From c017b4345604365c93bb205b36d108b0c5aff6f1 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 24 Apr 2020 15:12:57 +0200 Subject: [PATCH] Tinker linux5.4 (#632) * Migrate Tinker to linux 5.4 * Update bootloader --- buildroot-external/board/asus/hassos-hook.sh | 9 +- .../linux/0000-mali-r19p0-01rel0.patch | 82447 ---- ...midgard-r19p0-fixes-for-4.13-kernels.patch | 122 - ...ader-on-4.12-kernels-for-copy_-_user.patch | 36 - ...ages-calls-to-use-the-new-calling-pr.patch | 46 - ...evere-when-looking-for-the-IRQ-names.patch | 40 - ...mpatible-list-mainly-used-by-Rockchi.patch | 42 - ...-arm-Midgard-setup_timer-timer_setup.patch | 98 - ...Midgard-Replace-ACCESS_ONCE-by-READ_.patch | 35 - ...-midgard-Remove-sys_close-references.patch | 32 - ...rd-Adapt-to-the-new-mmap-call-checks.patch | 34 - ...gard-remove-rcu_read_lock-references.patch | 76 - ...8865-add-restart-handler-for-act8846.patch | 2 +- ...ing-Mali-Midgard-video-and-gpu-drive.patch | 39 - ...288-miqi-Enabling-the-Mali-GPU-node.patch} | 0 ...fix-the-regulator-s-voltage-range-o.patch} | 0 ...add-the-MiQi-board-s-fan-definition.patch} | 0 ...he-dependency-to-the-clk_mali-symbol.patch | 30 - .../1005-ASUS-Tinkerboard-Stupid-reboot.patch | 157 - ...TSI-rk3288-Add-missing-SPI2-pinctrl.patch} | 0 ...288-Adding-missing-EDP-power-domain.patch} | 0 ...k3288-Adding-missing-VOPB-registers.patch} | 0 ...rk3288-Fixed-the-SPDIF-node-address.patch} | 0 ...rk3288-tinker-Enabling-SDIO-and-Wifi.patch | 98 + ...tinker-Setup-the-Bluetooth-UART-pins.patch | 62 + ...tinker-Improving-the-CPU-max-voltage.patch | 28 + ...-tinker-Setting-up-the-SD-regulators.patch | 31 + ...88-tinker-Defined-the-I2C-interfaces.patch | 53 + ...88-tinker-Defining-the-SPI-interface.patch | 50 + ...288-tinker-Defining-SDMMC-properties.patch | 33 + ...k3288-Set-the-VPU-MMU-power-domains.patch} | 8 - ...support-for-dedicating-npll-to-a-vop.patch | 46 + ...dded-a-flag-to-disable-cache-flush-d.patch | 32 + .../1100-media-Add-JPEG_RAW-format.patch | 63 - ...ontrols-for-JPEG-quantization-tables.patch | 153 - ...all-known-operating-points-to-the-a.patch} | 0 ...-add-support-for-1800-MHz-operation-.patch | 41 - ...rockchip-miqi-add-turbo-mode-operati.patch | 170 - ...ci-rockchip-Handle-ASUS-Tinkerboard.patch} | 0 ...-ARM-DTSI-rk3288-Missing-GRF-handles.patch | 61 - ...ip-power-domain-export-idle-request.patch} | 40 +- ...verse-do-not-use-bulk-on-EP3-and-EP4.patch | 101 + ...port-for-Tinkerboard-s-SPI-interface.patch | 27 - ...88-Support-for-dedicating-NPLL-to-a.patch} | 84 +- ...3288-Adding-cells-addresses-and-size.patch | 56 - ...hip-better-clock-selection-logic-an.patch} | 42 +- ...88-tinker-Enabling-SDIO-Wireless-and.patch | 165 - ...port-for-Tinkerboard-s-SPI-interface.patch | 22 + ...tinker-Setup-the-Bluetooth-UART-pins.patch | 30 - ...88-tinker-Improving-the-CPU-max-volt.patch | 29 - ...88-tinker-Setting-up-the-SD-regulato.patch | 40 - ...88-tinker-Defined-the-I2C-interfaces.patch | 53 - ...inker-Add-the-MIPI-DSI-node.patch.disabled | 35 - ...288-tinker-Defining-SDMMC-properties.patch | 33 - ...-DTSI-rk3288-Define-the-VPU-services.patch | 107 - ...88-miqi-Enable-the-Video-encoding-MM.patch | 57 - ...inker-Enable-the-Video-encoding-MMU-.patch | 48 - ...firefly-Enable-the-Video-encoding-MM.patch | 49 - ...veyron-Enable-the-Video-encoding-MMU.patch | 48 - ...3288-Renamed-the-VPU-services-clocks.patch | 39 - ...-service-as-defined-in-the-V4L2-driv.patch | 43 - .../patches/linux/261_gpiomem_driver.patch | 395 + ...K3288-Tinkerboard-add-1.7_1.8Ghz_OPP.patch | 45 - .../ARM-DTSI-rk3288-add-usbphy-reset.patch | 31 - .../linux/RK3288-1.8GHz-and-boost.patch | 80 + ...et-when-waking-up-in-rk3288-platform.patch | 68 - ...oard-tinkerboard-enable-emmc-support.patch | 42 +- ...kerboard-support-older-eMMC-installs.patch | 665 - ...general-adjust-tinker-dts-hdmi-sound.patch | 10 +- .../general-fix-reboot-from-kwiboo.patch | 19 + ..._DMA_block_memory_allocation_to_2048.patch | 27 - .../patches/linux/remove-broken-dtb.patch | 22 + ...i-2001-01-rtl8188eu-kconfig-makefile.patch | 24 - .../linux/wifi-2002-02-rtl8188eu.patch | 315825 --------------- .../linux/xt-q8l-v10-add-device-tree.patch | 423 +- .../linux/xt-q8l-v10-add-dts-makefile.patch | 3 +- .../linux/xt-q8l-v10-remote-keymap.patch | 44 +- ...001-TLP-Modify-entrypoint-for-u-boot.patch | 23 + .../0017-Fix-HDMI-some-issues.patch.disabled | 115 - ...mic-enable-LDO2-vcc33_mipi-at-bootup.patch | 37 +- ...mode-when-TinkerBoard-is-connected-t.patch | 206 - ...-add-10ms-delay-after-re-enable-EMMC.patch | 25 - ...-fixed-enter-ums-mode-fail-sometimes.patch | 160 - .../uboot/0045-modify-UMS-name-of-uboot.patch | 32 - ...timeout-when-force-entering-UMS-mode.patch | 146 - .../patches/uboot/0050-USB-VID-PID.patch | 17 - .../uboot/100-tinker-s-eMMC-bootable.patch | 54 - ...nable-rockchip-video-driver.patch.disabled | 25 - buildroot-external/configs/tinker_defconfig | 9 +- 89 files changed, 1490 insertions(+), 402404 deletions(-) delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0000-mali-r19p0-01rel0.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0001-Mali-midgard-r19p0-fixes-for-4.13-kernels.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0002-Using-the-new-header-on-4.12-kernels-for-copy_-_user.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0003-Adapt-get_user_pages-calls-to-use-the-new-calling-pr.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0004-Don-t-be-TOO-severe-when-looking-for-the-IRQ-names.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0005-Added-the-new-compatible-list-mainly-used-by-Rockchi.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0006-gpu-arm-Midgard-setup_timer-timer_setup.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0007-drivers-gpu-Arm-Midgard-Replace-ACCESS_ONCE-by-READ_.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0008-gpu-arm-midgard-Remove-sys_close-references.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0009-GPU-ARM-Midgard-Adapt-to-the-new-mmap-call-checks.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/0010-GPU-Mali-Midgard-remove-rcu_read_lock-references.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/1001-drivers-Integrating-Mali-Midgard-video-and-gpu-drive.patch rename buildroot-external/board/asus/tinker/patches/linux/{2001-dts-rk3288-miqi-Enabling-the-Mali-GPU-node.patch => 1001-dts-rk3288-miqi-Enabling-the-Mali-GPU-node.patch} (100%) rename buildroot-external/board/asus/tinker/patches/linux/{2002-ARM-dts-rockchip-fix-the-regulator-s-voltage-range-o.patch => 1002-ARM-dts-rockchip-fix-the-regulator-s-voltage-range-o.patch} (100%) rename buildroot-external/board/asus/tinker/patches/linux/{2003-ARM-dts-rockchip-add-the-MiQi-board-s-fan-definition.patch => 1003-ARM-dts-rockchip-add-the-MiQi-board-s-fan-definition.patch} (100%) delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/1004-Remove-the-dependency-to-the-clk_mali-symbol.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/1005-ASUS-Tinkerboard-Stupid-reboot.patch rename buildroot-external/board/asus/tinker/patches/linux/{2007-RK3288-DTSI-rk3288-Add-missing-SPI2-pinctrl.patch => 1007-RK3288-DTSI-rk3288-Add-missing-SPI2-pinctrl.patch} (100%) rename buildroot-external/board/asus/tinker/patches/linux/{2010-ARM-DTSI-rk3288-Adding-missing-EDP-power-domain.patch => 1010-ARM-DTSI-rk3288-Adding-missing-EDP-power-domain.patch} (100%) rename buildroot-external/board/asus/tinker/patches/linux/{2011-ARM-DTSI-rk3288-Adding-missing-VOPB-registers.patch => 1011-ARM-DTSI-rk3288-Adding-missing-VOPB-registers.patch} (100%) rename buildroot-external/board/asus/tinker/patches/linux/{2012-ARM-DTSI-rk3288-Fixed-the-SPDIF-node-address.patch => 1012-ARM-DTSI-rk3288-Fixed-the-SPDIF-node-address.patch} (100%) create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1013-ARM-DTS-rk3288-tinker-Enabling-SDIO-and-Wifi.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1015-ARM-DTSI-rk3288-tinker-Improving-the-CPU-max-voltage.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1016-ARM-DTSI-rk3288-tinker-Setting-up-the-SD-regulators.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1018-ARM-DTS-rk3288-tinker-Defining-the-SPI-interface.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1019-ARM-DTSI-rk3288-tinker-Defining-SDMMC-properties.patch rename buildroot-external/board/asus/tinker/patches/linux/{2026-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch => 1020-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch} (88%) create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1023-dts-rk3288-support-for-dedicating-npll-to-a-vop.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/1024-arm-dts-veyron-Added-a-flag-to-disable-cache-flush-d.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/1100-media-Add-JPEG_RAW-format.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/1101-media-Add-controls-for-JPEG-quantization-tables.patch rename buildroot-external/board/asus/tinker/patches/linux/{1002-clk-rockchip-add-all-known-operating-points-to-the-a.patch => 2002-clk-rockchip-add-all-known-operating-points-to-the-a.patch} (100%) delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2004-ARM-dts-rockchip-add-support-for-1800-MHz-operation-.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2005-Readapt-ARM-dts-rockchip-miqi-add-turbo-mode-operati.patch rename buildroot-external/board/asus/tinker/patches/linux/{1005-drivers-mmc-dw-mci-rockchip-Handle-ASUS-Tinkerboard.patch => 2005-drivers-mmc-dw-mci-rockchip-Handle-ASUS-Tinkerboard.patch} (100%) delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2006-ARM-DTSI-rk3288-Missing-GRF-handles.patch rename buildroot-external/board/asus/tinker/patches/linux/{1006-soc-rockchip-power-domain-export-idle-request.patch => 2006-soc-rockchip-power-domain-export-idle-request.patch} (58%) create mode 100644 buildroot-external/board/asus/tinker/patches/linux/2007-drivers-wifi-ath9k-reverse-do-not-use-bulk-on-EP3-and-EP4.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2008-Added-support-for-Tinkerboard-s-SPI-interface.patch rename buildroot-external/board/asus/tinker/patches/linux/{1009-drivers-clk-rk3288-support-for-dedicating-NPLL-to-a-.patch => 2008-clk-rockchip-rk3288-Support-for-dedicating-NPLL-to-a.patch} (67%) delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2009-ARM-DTSI-rk3288-Adding-cells-addresses-and-size.patch rename buildroot-external/board/asus/tinker/patches/linux/{1010-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch => 2009-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch} (90%) delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2013-ARM-DTS-rk3288-tinker-Enabling-SDIO-Wireless-and.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/2013-spi-Added-support-for-Tinkerboard-s-SPI-interface.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2015-ARM-DTS-rk3288-tinker-Improving-the-CPU-max-volt.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2016-ARM-DTS-rk3288-tinker-Setting-up-the-SD-regulato.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Add-the-MIPI-DSI-node.patch.disabled delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Defining-SDMMC-properties.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2020-ARM-DTSI-rk3288-Define-the-VPU-services.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2021-ARM-DTS-rk3288-miqi-Enable-the-Video-encoding-MM.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2022-ARM-DTS-rk3288-tinker-Enable-the-Video-encoding-MMU-.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2023-ARM-DTSI-rk3288-firefly-Enable-the-Video-encoding-MM.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2024-ARM-DTSI-rk3288-veyron-Enable-the-Video-encoding-MMU.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2025-ARM-DTSI-rk3288-Renamed-the-VPU-services-clocks.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/2027-ARM-dtsi-The-VPU-service-as-defined-in-the-V4L2-driv.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/261_gpiomem_driver.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/3000_RK3288-Tinkerboard-add-1.7_1.8Ghz_OPP.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/ARM-DTSI-rk3288-add-usbphy-reset.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/RK3288-1.8GHz-and-boost.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/assert-phy-reset-when-waking-up-in-rk3288-platform.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-support-older-eMMC-installs.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/general-fix-reboot-from-kwiboo.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/general-increasing_DMA_block_memory_allocation_to_2048.patch create mode 100644 buildroot-external/board/asus/tinker/patches/linux/remove-broken-dtb.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/wifi-2001-01-rtl8188eu-kconfig-makefile.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/linux/wifi-2002-02-rtl8188eu.patch create mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0001-TLP-Modify-entrypoint-for-u-boot.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0017-Fix-HDMI-some-issues.patch.disabled delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0036-auto-enable-ums-mode-when-TinkerBoard-is-connected-t.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0037-add-10ms-delay-after-re-enable-EMMC.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0039-fixed-enter-ums-mode-fail-sometimes.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0045-modify-UMS-name-of-uboot.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0049-added-timeout-when-force-entering-UMS-mode.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/0050-USB-VID-PID.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/100-tinker-s-eMMC-bootable.patch delete mode 100644 buildroot-external/board/asus/tinker/patches/uboot/101-u-boot-0002-rockchip-tinker-enable-rockchip-video-driver.patch.disabled diff --git a/buildroot-external/board/asus/hassos-hook.sh b/buildroot-external/board/asus/hassos-hook.sh index 2d5b835a8..9582e5474 100755 --- a/buildroot-external/board/asus/hassos-hook.sh +++ b/buildroot-external/board/asus/hassos-hook.sh @@ -12,14 +12,15 @@ function hassos_pre_image() { echo "console=tty1" > "${BOOT_DATA}/cmdline.txt" # Create boot binary - rm -f "${BINARIES_DIR}/u-boot-spl-dtb.img" - mkimage -n rk3288 -T rksd -d "${BINARIES_DIR}/u-boot-spl-dtb.bin" "${BINARIES_DIR}/u-boot-spl-dtb.img" - cat "${BINARIES_DIR}/u-boot-dtb.bin" >> "${BINARIES_DIR}/u-boot-spl-dtb.img" + rm -f "${BINARIES_DIR}/idbloader.img" + mkimage -n rk3288 -T rksd -d "${BINARIES_DIR}/u-boot-tpl.bin" "${BINARIES_DIR}/idbloader.img" + cat "${BINARIES_DIR}/u-boot-spl.bin" >> "${BINARIES_DIR}/idbloader.img" # SPL create_spl_image - dd if="${BINARIES_DIR}/u-boot-spl-dtb.img" of="${SPL_IMG}" conv=notrunc bs=512 seek=64 + dd if="${BINARIES_DIR}/idbloader.img" of="${SPL_IMG}" conv=notrunc bs=512 seek=64 + dd if="${BINARIES_DIR}/u-boot-dtb.img" of="${SPL_IMG}" conv=notrunc bs=512 seek=12288 } diff --git a/buildroot-external/board/asus/tinker/patches/linux/0000-mali-r19p0-01rel0.patch b/buildroot-external/board/asus/tinker/patches/linux/0000-mali-r19p0-01rel0.patch deleted file mode 100644 index 6520dc74f..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0000-mali-r19p0-01rel0.patch +++ /dev/null @@ -1,82447 +0,0 @@ -diff --git a/drivers/base/ump/Kbuild b/drivers/base/ump/Kbuild -new file mode 100644 -index 0000000..2bbdba2 ---- /dev/null -+++ b/drivers/base/ump/Kbuild -@@ -0,0 +1,18 @@ -+# -+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+obj-y += src/ -+ -diff --git a/drivers/base/ump/Kconfig b/drivers/base/ump/Kconfig -new file mode 100644 -index 0000000..f7451e6 ---- /dev/null -+++ b/drivers/base/ump/Kconfig -@@ -0,0 +1,26 @@ -+# -+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+config UMP -+ tristate "Enable Unified Memory Provider (UMP) support" -+ default n -+ help -+ Enable this option to build support for the ARM UMP module. -+ UMP can be used by the Mali T6xx module to improve performance -+ by reducing the copying of data by sharing memory. -+ -+ To compile this driver as a module, choose M here: -+ this will generate one module, called ump. -diff --git a/drivers/base/ump/docs/Doxyfile b/drivers/base/ump/docs/Doxyfile -new file mode 100644 -index 0000000..fbec8eb ---- /dev/null -+++ b/drivers/base/ump/docs/Doxyfile -@@ -0,0 +1,125 @@ -+# -+# (C) COPYRIGHT 2011-2013 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+############################################################################## -+ -+# This file contains per-module Doxygen configuration. Please do not add -+# extra settings to this file without consulting all stakeholders, as they -+# may cause override project-wide settings. -+# -+# Additionally, when defining aliases, macros, sections etc, use the module -+# name as a prefix e.g. gles_my_alias. -+ -+############################################################################## -+ -+@INCLUDE = ../../bldsys/Doxyfile_common -+ -+# The INPUT tag can be used to specify the files and/or directories that contain -+# documented source files. You may enter file names like "myfile.cpp" or -+# directories like "/usr/src/myproject". Separate the files or directories -+# with spaces. -+ -+INPUT += ../../kernel/include/linux/ump-common.h ../../kernel/include/linux/ump.h -+ -+############################################################################## -+# Everything below here is optional, and in most cases not required -+############################################################################## -+ -+# This tag can be used to specify a number of aliases that acts -+# as commands in the documentation. An alias has the form "name=value". -+# For example adding "sideeffect=\par Side Effects:\n" will allow you to -+# put the command \sideeffect (or @sideeffect) in the documentation, which -+# will result in a user-defined paragraph with heading "Side Effects:". -+# You can put \n's in the value part of an alias to insert newlines. -+ -+ALIASES += -+ -+# The ENABLED_SECTIONS tag can be used to enable conditional -+# documentation sections, marked by \if sectionname ... \endif. -+ -+ENABLED_SECTIONS += -+ -+# If the value of the INPUT tag contains directories, you can use the -+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -+# and *.h) to filter out the source-files in the directories. If left -+# blank the following patterns are tested: -+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 -+ -+FILE_PATTERNS += -+ -+# The EXCLUDE tag can be used to specify files and/or directories that should -+# excluded from the INPUT source files. This way you can easily exclude a -+# subdirectory from a directory tree whose root is specified with the INPUT tag. -+ -+EXCLUDE += -+ -+# If the value of the INPUT tag contains directories, you can use the -+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -+# certain files from those directories. Note that the wildcards are matched -+# against the file with absolute path, so to exclude all test directories -+# for example use the pattern */test/* -+ -+EXCLUDE_PATTERNS += -+ -+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -+# (namespaces, classes, functions, etc.) that should be excluded from the -+# output. The symbol name can be a fully qualified name, a word, or if the -+# wildcard * is used, a substring. Examples: ANamespace, AClass, -+# AClass::ANamespace, ANamespace::*Test -+ -+EXCLUDE_SYMBOLS += -+ -+# The EXAMPLE_PATH tag can be used to specify one or more files or -+# directories that contain example code fragments that are included (see -+# the \include command). -+ -+EXAMPLE_PATH += ../../kernel/drivers/base/ump -+ -+# The IMAGE_PATH tag can be used to specify one or more files or -+# directories that contain image that are included in the documentation (see -+# the \image command). -+ -+IMAGE_PATH += -+ -+# The INCLUDE_PATH tag can be used to specify one or more directories that -+# contain include files that are not input files but should be processed by -+# the preprocessor. -+ -+INCLUDE_PATH += -+ -+# The PREDEFINED tag can be used to specify one or more macro names that -+# are defined before the preprocessor is started (similar to the -D option of -+# gcc). The argument of the tag is a list of macros of the form: name -+# or name=definition (no spaces). If the definition and the = are -+# omitted =1 is assumed. To prevent a macro definition from being -+# undefined via #undef or recursively expanded use the := operator -+# instead of the = operator. -+ -+PREDEFINED += -+ -+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -+# this tag can be used to specify a list of macro names that should be expanded. -+# The macro definition that is found in the sources will be used. -+# Use the PREDEFINED tag if you want to use a different macro definition. -+ -+EXPAND_AS_DEFINED += -+ -+# The DOTFILE_DIRS tag can be used to specify one or more directories that -+# contain dot files that are included in the documentation (see the -+# \dotfile command). -+ -+DOTFILE_DIRS += -diff --git a/drivers/base/ump/docs/sconscript b/drivers/base/ump/docs/sconscript -new file mode 100644 -index 0000000..521278d ---- /dev/null -+++ b/drivers/base/ump/docs/sconscript -@@ -0,0 +1,31 @@ -+# -+# (C) COPYRIGHT 2010-2011, 2013 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+Import('env') -+ -+doxygen_sources = [ -+ 'Doxyfile', -+ Glob('*.png'), -+ Glob('../*.h'), -+ Glob('../src/*.h') ] -+ -+if env['doc'] == '1': -+ doxygen_target = env.Command('doxygen/html/index.html', doxygen_sources, -+ ['cd ${SOURCE.dir} && doxygen']) -+ env.Clean(doxygen_target, './doxygen') -+ -+ Alias('doxygen', doxygen_target) -+ -diff --git a/drivers/base/ump/example_kernel_api.c b/drivers/base/ump/example_kernel_api.c -new file mode 100644 -index 0000000..858dd8b ---- /dev/null -+++ b/drivers/base/ump/example_kernel_api.c -@@ -0,0 +1,73 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+ -+#include -+#include -+ -+/* -+ * Example routine to display information about an UMP allocation -+ * The routine takes an secure_id which can come from a different kernel module -+ * or from a client application (i.e. an ioctl). -+ * It creates a ump handle from the secure id (which validates the secure id) -+ * and if successful dumps the physical memory information. -+ * It follows the API and pins the memory while "using" the physical memory. -+ * Finally it calls the release function to indicate it's finished with the handle. -+ * -+ * If the function can't look up the handle it fails with return value -1. -+ * If the testy succeeds then it return 0. -+ * */ -+ -+static int display_ump_memory_information(ump_secure_id secure_id) -+{ -+ const ump_dd_physical_block_64 * ump_blocks = NULL; -+ ump_dd_handle ump_mem; -+ uint64_t nr_blocks; -+ int i; -+ ump_alloc_flags flags; -+ -+ /* get a handle from the secure id */ -+ ump_mem = ump_dd_from_secure_id(secure_id); -+ -+ if (UMP_DD_INVALID_MEMORY_HANDLE == ump_mem) -+ { -+ /* invalid ID received */ -+ return -1; -+ } -+ -+ /* at this point we know we've added a reference to the ump allocation, so we must release it with ump_dd_release */ -+ -+ ump_dd_phys_blocks_get_64(ump_mem, &nr_blocks, &ump_blocks); -+ flags = ump_dd_allocation_flags_get(ump_mem); -+ -+ printf("UMP allocation with secure ID %u consists of %zd physical block(s):\n", secure_id, nr_blocks); -+ -+ for(i=0; i -+#include -+#include -+ -+/* -+ * Example routine to exercise the user space UMP api. -+ * This routine initializes the UMP api and allocates some CPU+device X memory. -+ * No usage hints are given, so the driver will use the default cacheability policy. -+ * With the allocation it creates a duplicate handle and plays with the reference count. -+ * Then it simulates interacting with a device and contains pseudo code for the device. -+ * -+ * If any error is detected correct cleanup will be performed and -1 will be returned. -+ * If successful then 0 will be returned. -+ */ -+ -+static int test_ump_user_api(void) -+{ -+ /* This is the size we try to allocate*/ -+ const size_t alloc_size = 4096; -+ -+ ump_handle h = UMP_INVALID_MEMORY_HANDLE; -+ ump_handle h_copy = UMP_INVALID_MEMORY_HANDLE; -+ ump_handle h_clone = UMP_INVALID_MEMORY_HANDLE; -+ -+ void * mapping = NULL; -+ -+ ump_result ump_api_res; -+ int result = -1; -+ -+ ump_secure_id id; -+ -+ size_t size_returned; -+ -+ ump_api_res = ump_open(); -+ if (UMP_OK != ump_api_res) -+ { -+ /* failed to open an ump session */ -+ /* early out */ -+ return -1; -+ } -+ -+ h = ump_allocate_64(alloc_size, UMP_PROT_CPU_RD | UMP_PROT_CPU_WR | UMP_PROT_X_RD | UMP_PROT_X_WR); -+ /* the refcount is now 1 */ -+ if (UMP_INVALID_MEMORY_HANDLE == h) -+ { -+ /* allocation failure */ -+ goto cleanup; -+ } -+ -+ /* this is how we could share this allocation with another process */ -+ -+ /* in process A: */ -+ id = ump_secure_id_get(h); -+ /* still ref count 1 */ -+ /* send the id to process B */ -+ -+ /* in process B: */ -+ /* receive the id from A */ -+ h_clone = ump_from_secure_id(id); -+ /* the ref count of the allocation is now 2 (one from each handle to it) */ -+ /* do something ... */ -+ /* release our clone */ -+ ump_release(h_clone); /* safe to call even if ump_from_secure_id failed */ -+ h_clone = UMP_INVALID_MEMORY_HANDLE; -+ -+ -+ /* a simple save-for-future-use logic inside the driver would just copy the handle (but add a ref manually too!) */ -+ /* -+ * void assign_memory_to_job(h) -+ * { -+ */ -+ h_copy = h; -+ ump_retain(h_copy); /* manual retain needed as we just assigned the handle, now 2 */ -+ /* -+ * } -+ * -+ * void job_completed(void) -+ * { -+ */ -+ ump_release(h_copy); /* normal handle release as if we got via an ump_allocate */ -+ h_copy = UMP_INVALID_MEMORY_HANDLE; -+ /* -+ * } -+ */ -+ -+ /* we're now back at ref count 1, and only h is a valid handle */ -+ /* enough handle duplication show-off, let's play with the contents instead */ -+ -+ mapping = ump_map(h, 0, alloc_size); -+ if (NULL == mapping) -+ { -+ /* mapping failure, either out of address space or some other error */ -+ goto cleanup; -+ } -+ -+ memset(mapping, 0, alloc_size); -+ -+ /* let's pretend we're going to start some hw device on this buffer and read the result afterwards */ -+ ump_cpu_msync_now(h, UMP_MSYNC_CLEAN, mapping, alloc_size); -+ /* -+ device cache invalidate -+ -+ memory barrier -+ -+ start device -+ -+ memory barrier -+ -+ wait for device -+ -+ memory barrier -+ -+ device cache clean -+ -+ memory barrier -+ */ -+ ump_cpu_msync_now(h, UMP_MSYNC_CLEAN_AND_INVALIDATE, mapping, alloc_size); -+ -+ /* we could now peek at the result produced by the hw device, which is now accessible via our mapping */ -+ -+ /* unmap the buffer when we're done with it */ -+ ump_unmap(h, mapping, alloc_size); -+ -+ result = 0; -+ -+cleanup: -+ ump_release(h); -+ h = UMP_INVALID_MEMORY_HANDLE; -+ -+ ump_close(); -+ -+ return result; -+} -+ -diff --git a/drivers/base/ump/sconscript b/drivers/base/ump/sconscript -new file mode 100644 -index 0000000..b4aa8b6 ---- /dev/null -+++ b/drivers/base/ump/sconscript -@@ -0,0 +1,21 @@ -+# -+# (C) COPYRIGHT 2010-2013 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+Import('env') -+ -+if Glob('src/sconscript') and int(env['ump']) == 1: -+ SConscript( 'src/sconscript' ) -+ SConscript( 'docs/sconscript' ) -+ -diff --git a/drivers/base/ump/src/Kbuild b/drivers/base/ump/src/Kbuild -new file mode 100644 -index 0000000..de6d307 ---- /dev/null -+++ b/drivers/base/ump/src/Kbuild -@@ -0,0 +1,50 @@ -+# -+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+# Paths required for build -+UMP_PATH = $(src)/../.. -+UMP_DEVICEDRV_PATH = $(src)/. -+ -+# Set up defaults if not defined by the user -+MALI_UNIT_TEST ?= 0 -+ -+SRC :=\ -+ common/ump_kernel_core.c \ -+ common/ump_kernel_descriptor_mapping.c \ -+ linux/ump_kernel_linux.c \ -+ linux/ump_kernel_linux_mem.c -+ -+UNIT_TEST_DEFINES= -+ifeq ($(MALI_UNIT_TEST), 1) -+ MALI_DEBUG ?= 1 -+ -+ UNIT_TEST_DEFINES = -DMALI_UNIT_TEST=1 \ -+ -DMALI_DEBUG=$(MALI_DEBUG) -+endif -+ -+# Use our defines when compiling -+ccflags-y += -I$(UMP_PATH) -I$(UMP_DEVICEDRV_PATH) $(UNIT_TEST_DEFINES) -+ -+ -+# Tell the Linux build system from which .o file to create the kernel module -+obj-$(CONFIG_UMP) += ump.o -+ifeq ($(CONFIG_ION),y) -+ccflags-y += -I$(srctree)/drivers/staging/android/ion -I$(srctree)/include/linux -+obj-$(CONFIG_UMP) += imports/ion/ump_kernel_import_ion.o -+endif -+ -+# Tell the Linux build system to enable building of our .c files -+ump-y := $(SRC:.c=.o) -diff --git a/drivers/base/ump/src/Makefile b/drivers/base/ump/src/Makefile -new file mode 100644 -index 0000000..45428ad ---- /dev/null -+++ b/drivers/base/ump/src/Makefile -@@ -0,0 +1,81 @@ -+# -+# (C) COPYRIGHT 2008-2014 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+ifneq ($(KBUILD_EXTMOD),) -+include $(KBUILD_EXTMOD)/Makefile.common -+else -+include ./Makefile.common -+endif -+ -+# default to building for the host -+ARCH ?= $(shell uname -m) -+ -+# linux build system integration -+RELATIVE_ROOT=../../../../.. -+ROOT = $(CURDIR)/$(RELATIVE_ROOT) -+ -+EXTRA_CFLAGS=-I$(CURDIR)/../../../../include -+ -+ifeq ($(MALI_UNIT_TEST),1) -+ EXTRA_CFLAGS += -DMALI_UNIT_TEST=$(MALI_UNIT_TEST) -+endif -+ -+# Get any user defined KDIR- or maybe even a hardcoded KDIR -+-include KDIR_CONFIGURATION -+ -+# Define host system directory -+KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build -+ -+CONFIG ?= $(ARCH) -+ -+# default cpu to select -+CPU ?= $(shell uname -m) -+ -+# look up KDIR based om CPU selection -+KDIR ?= $(KDIR-$(CPU)) -+ -+ifeq ($(KDIR),) -+$(error No KDIR found for platform $(CPU)) -+endif -+ -+# Validate selected config -+ifneq ($(shell [ -d arch-$(CONFIG) ] && [ -f arch-$(CONFIG)/config.h ] && echo "OK"), OK) -+$(warning Current directory is $(shell pwd)) -+$(error No configuration found for config $(CONFIG). Check that arch-$(CONFIG)/config.h exists) -+else -+# Link arch to the selected arch-config directory -+$(shell [ -L arch ] && rm arch) -+$(shell ln -sf arch-$(CONFIG) arch) -+$(shell touch arch/config.h) -+endif -+ -+EXTRA_SYMBOLS= -+ -+ifeq ($(MALI_UNIT_TEST),1) -+ KBASE_PATH=$(ROOT)/kernel/drivers/gpu/arm/midgard -+ EXTRA_SYMBOLS+=$(KBASE_PATH)/tests/internal/src/kernel_assert_module/linux/Module.symvers -+endif -+KDS_PATH=$(ROOT)/kernel/drivers/base/kds -+EXTRA_SYMBOLS+=$(KDS_PATH)/Module.symvers -+ -+all: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) EXTRA_CFLAGS="$(EXTRA_CFLAGS) $(SCONS_CFLAGS)" CONFIG_UMP=m KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" modules -+ -+kernelrelease: -+ $(MAKE) -C $(KDIR) KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" kernelrelease -+ -+clean: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean -diff --git a/drivers/base/ump/src/Makefile.common b/drivers/base/ump/src/Makefile.common -new file mode 100644 -index 0000000..f29a4c1 ---- /dev/null -+++ b/drivers/base/ump/src/Makefile.common -@@ -0,0 +1,19 @@ -+# -+# (C) COPYRIGHT 2008-2010, 2013 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+SRC = $(UMP_FILE_PREFIX)/common/ump_kernel_core.c \ -+ $(UMP_FILE_PREFIX)/common/ump_kernel_descriptor_mapping.c -+ -diff --git a/drivers/base/ump/src/arch-arm/config.h b/drivers/base/ump/src/arch-arm/config.h -new file mode 100644 -index 0000000..152d98f ---- /dev/null -+++ b/drivers/base/ump/src/arch-arm/config.h -@@ -0,0 +1,27 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2009, 2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef __ARCH_CONFIG_H__ -+#define __ARCH_CONFIG_H__ -+ -+#define ARCH_UMP_BACKEND_DEFAULT 1 -+#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x00000000 -+#define ARCH_UMP_MEMORY_SIZE_DEFAULT 32UL * 1024UL * 1024UL -+ -+#endif /* __ARCH_CONFIG_H__ */ -diff --git a/drivers/base/ump/src/arch-arm64/config.h b/drivers/base/ump/src/arch-arm64/config.h -new file mode 100644 -index 0000000..cfb14ca ---- /dev/null -+++ b/drivers/base/ump/src/arch-arm64/config.h -@@ -0,0 +1,27 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2009, 2013-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef __ARCH_CONFIG_H__ -+#define __ARCH_CONFIG_H__ -+ -+#define ARCH_UMP_BACKEND_DEFAULT 1 -+#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x00000000 -+#define ARCH_UMP_MEMORY_SIZE_DEFAULT 32UL * 1024UL * 1024UL -+ -+#endif /* __ARCH_CONFIG_H__ */ -diff --git a/drivers/base/ump/src/common/ump_kernel_core.c b/drivers/base/ump/src/common/ump_kernel_core.c -new file mode 100644 -index 0000000..07aa077 ---- /dev/null -+++ b/drivers/base/ump/src/common/ump_kernel_core.c -@@ -0,0 +1,756 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* module headers */ -+#include -+#include -+ -+/* local headers */ -+#include -+#include -+#include -+#include -+ -+#define UMP_FLAGS_RANGE ((UMP_PROT_SHAREABLE<<1) - 1u) -+ -+static umpp_device device; -+ -+ump_result umpp_core_constructor(void) -+{ -+ mutex_init(&device.secure_id_map_lock); -+ device.secure_id_map = umpp_descriptor_mapping_create(UMP_EXPECTED_IDS, UMP_MAX_IDS); -+ if (NULL != device.secure_id_map) -+ { -+ if (UMP_OK == umpp_device_initialize()) -+ { -+ return UMP_OK; -+ } -+ umpp_descriptor_mapping_destroy(device.secure_id_map); -+ } -+ mutex_destroy(&device.secure_id_map_lock); -+ -+ return UMP_ERROR; -+} -+ -+void umpp_core_destructor(void) -+{ -+ umpp_device_terminate(); -+ umpp_descriptor_mapping_destroy(device.secure_id_map); -+ mutex_destroy(&device.secure_id_map_lock); -+} -+ -+umpp_session *umpp_core_session_start(void) -+{ -+ umpp_session * session; -+ -+ session = kzalloc(sizeof(*session), GFP_KERNEL); -+ if (NULL != session) -+ { -+ mutex_init(&session->session_lock); -+ -+ INIT_LIST_HEAD(&session->memory_usage); -+ -+ /* try to create import client session, not a failure if they fail to initialize */ -+ umpp_import_handlers_init(session); -+ } -+ -+ return session; -+} -+ -+void umpp_core_session_end(umpp_session *session) -+{ -+ umpp_session_memory_usage * usage, *_usage; -+ UMP_ASSERT(session); -+ -+ list_for_each_entry_safe(usage, _usage, &session->memory_usage, link) -+ { -+ printk(KERN_WARNING "UMP: Memory usage cleanup, releasing secure ID %d\n", ump_dd_secure_id_get(usage->mem)); -+ ump_dd_release(usage->mem); -+ kfree(usage); -+ -+ } -+ -+ /* we should now not hold any imported memory objects, -+ * detatch all import handlers */ -+ umpp_import_handlers_term(session); -+ -+ mutex_destroy(&session->session_lock); -+ kfree(session); -+} -+ -+ump_dd_handle ump_dd_allocate_64(uint64_t size, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data) -+{ -+ umpp_allocation * alloc; -+ int i; -+ -+ UMP_ASSERT(size); -+ -+ if (flags & (~UMP_FLAGS_RANGE)) -+ { -+ printk(KERN_WARNING "UMP: allocation flags out of allowed bits range\n"); -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+ } -+ -+ if( ( flags & (UMP_PROT_CPU_RD | UMP_PROT_W_RD | UMP_PROT_X_RD | UMP_PROT_Y_RD | UMP_PROT_Z_RD ) ) == 0 || -+ ( flags & (UMP_PROT_CPU_WR | UMP_PROT_W_WR | UMP_PROT_X_WR | UMP_PROT_Y_WR | UMP_PROT_Z_WR )) == 0 ) -+ { -+ printk(KERN_WARNING "UMP: allocation flags should have at least one read and one write permission bit set\n"); -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+ } -+ -+ /*check permission flags to be set if hit flags are set too*/ -+ for (i = UMP_DEVICE_CPU_SHIFT; i<=UMP_DEVICE_Z_SHIFT; i+=4) -+ { -+ if (flags & (UMP_HINT_DEVICE_RD<flags = flags; -+ alloc->filter_func = filter_func; -+ alloc->final_release_func = final_release_func; -+ alloc->callback_data = callback_data; -+ alloc->size = size; -+ -+ mutex_init(&alloc->map_list_lock); -+ INIT_LIST_HEAD(&alloc->map_list); -+ atomic_set(&alloc->refcount, 1); -+ -+#ifdef CONFIG_KDS -+ kds_resource_init(&alloc->kds_res); -+#endif -+ -+ if (!(alloc->flags & UMP_PROT_SHAREABLE)) -+ { -+ alloc->owner = get_current()->pid; -+ } -+ -+ if (0 != umpp_phys_commit(alloc)) -+ { -+ goto out2; -+ } -+ -+ /* all set up, allocate an ID for it */ -+ -+ mutex_lock(&device.secure_id_map_lock); -+ alloc->id = umpp_descriptor_mapping_allocate(device.secure_id_map, (void*)alloc); -+ mutex_unlock(&device.secure_id_map_lock); -+ -+ if ((int)alloc->id == 0) -+ { -+ /* failed to allocate a secure_id */ -+ goto out3; -+ } -+ -+ return alloc; -+ -+out3: -+ umpp_phys_free(alloc); -+out2: -+ kfree(alloc); -+out1: -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+} -+ -+uint64_t ump_dd_size_get_64(const ump_dd_handle mem) -+{ -+ umpp_allocation * alloc; -+ -+ UMP_ASSERT(mem); -+ -+ alloc = (umpp_allocation*)mem; -+ -+ return alloc->size; -+} -+ -+/* -+ * UMP v1 API -+ */ -+unsigned long ump_dd_size_get(ump_dd_handle mem) -+{ -+ umpp_allocation * alloc; -+ -+ UMP_ASSERT(mem); -+ -+ alloc = (umpp_allocation*)mem; -+ -+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE); -+ UMP_ASSERT(alloc->size <= UMP_UINT32_MAX); -+ -+ return (unsigned long)alloc->size; -+} -+ -+ump_secure_id ump_dd_secure_id_get(const ump_dd_handle mem) -+{ -+ umpp_allocation * alloc; -+ -+ UMP_ASSERT(mem); -+ -+ alloc = (umpp_allocation*)mem; -+ -+ return alloc->id; -+} -+ -+#ifdef CONFIG_KDS -+struct kds_resource * ump_dd_kds_resource_get(const ump_dd_handle mem) -+{ -+ umpp_allocation * alloc; -+ -+ UMP_ASSERT(mem); -+ -+ alloc = (umpp_allocation*)mem; -+ -+ return &alloc->kds_res; -+} -+#endif -+ -+ump_alloc_flags ump_dd_allocation_flags_get(const ump_dd_handle mem) -+{ -+ const umpp_allocation * alloc; -+ -+ UMP_ASSERT(mem); -+ alloc = (const umpp_allocation *)mem; -+ -+ return alloc->flags; -+} -+ -+ump_dd_handle ump_dd_from_secure_id(ump_secure_id secure_id) -+{ -+ umpp_allocation * alloc = UMP_DD_INVALID_MEMORY_HANDLE; -+ -+ mutex_lock(&device.secure_id_map_lock); -+ -+ if (0 == umpp_descriptor_mapping_lookup(device.secure_id_map, secure_id, (void**)&alloc)) -+ { -+ if (NULL != alloc->filter_func) -+ { -+ if (!alloc->filter_func(secure_id, alloc, alloc->callback_data)) -+ { -+ alloc = UMP_DD_INVALID_MEMORY_HANDLE; /* the filter denied access */ -+ } -+ } -+ -+ /* check permission to access it */ -+ if ((UMP_DD_INVALID_MEMORY_HANDLE != alloc) && !(alloc->flags & UMP_PROT_SHAREABLE)) -+ { -+ if (alloc->owner != get_current()->pid) -+ { -+ alloc = UMP_DD_INVALID_MEMORY_HANDLE; /*no rights for the current process*/ -+ } -+ } -+ -+ if (UMP_DD_INVALID_MEMORY_HANDLE != alloc) -+ { -+ if( ump_dd_retain(alloc) != UMP_DD_SUCCESS) -+ { -+ alloc = UMP_DD_INVALID_MEMORY_HANDLE; -+ } -+ } -+ } -+ mutex_unlock(&device.secure_id_map_lock); -+ -+ return alloc; -+} -+ -+/* -+ * UMP v1 API -+ */ -+ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id) -+{ -+ return ump_dd_from_secure_id(secure_id); -+} -+ -+int ump_dd_retain(ump_dd_handle mem) -+{ -+ umpp_allocation * alloc; -+ -+ UMP_ASSERT(mem); -+ -+ alloc = (umpp_allocation*)mem; -+ -+ /* check for overflow */ -+ while(1) -+ { -+ int refcnt = atomic_read(&alloc->refcount); -+ if (refcnt + 1 > 0) -+ { -+ if(atomic_cmpxchg(&alloc->refcount, refcnt, refcnt + 1) == refcnt) -+ { -+ return 0; -+ } -+ } -+ else -+ { -+ return -EBUSY; -+ } -+ } -+} -+ -+/* -+ * UMP v1 API -+ */ -+void ump_dd_reference_add(ump_dd_handle mem) -+{ -+ ump_dd_retain(mem); -+} -+ -+ -+void ump_dd_release(ump_dd_handle mem) -+{ -+ umpp_allocation * alloc; -+ uint32_t new_cnt; -+ -+ UMP_ASSERT(mem); -+ -+ alloc = (umpp_allocation*)mem; -+ -+ /* secure the id for lookup while releasing */ -+ mutex_lock(&device.secure_id_map_lock); -+ -+ /* do the actual release */ -+ new_cnt = atomic_sub_return(1, &alloc->refcount); -+ if (0 == new_cnt) -+ { -+ /* remove from the table as this was the last ref */ -+ umpp_descriptor_mapping_remove(device.secure_id_map, alloc->id); -+ } -+ -+ /* release the lock as early as possible */ -+ mutex_unlock(&device.secure_id_map_lock); -+ -+ if (0 != new_cnt) -+ { -+ /* exit if still have refs */ -+ return; -+ } -+ -+ UMP_ASSERT(list_empty(&alloc->map_list)); -+ -+#ifdef CONFIG_KDS -+ if (kds_resource_term(&alloc->kds_res)) -+ { -+ printk(KERN_ERR "ump_dd_release: kds_resource_term failed," -+ "unable to release UMP allocation\n"); -+ return; -+ } -+#endif -+ /* cleanup */ -+ if (NULL != alloc->final_release_func) -+ { -+ alloc->final_release_func(alloc, alloc->callback_data); -+ } -+ -+ if (0 == (alloc->management_flags & UMP_MGMT_EXTERNAL)) -+ { -+ umpp_phys_free(alloc); -+ } -+ else -+ { -+ kfree(alloc->block_array); -+ } -+ -+ mutex_destroy(&alloc->map_list_lock); -+ -+ kfree(alloc); -+} -+ -+/* -+ * UMP v1 API -+ */ -+void ump_dd_reference_release(ump_dd_handle mem) -+{ -+ ump_dd_release(mem); -+} -+ -+void ump_dd_phys_blocks_get_64(const ump_dd_handle mem, uint64_t * const pCount, const ump_dd_physical_block_64 ** const pArray) -+{ -+ const umpp_allocation * alloc; -+ UMP_ASSERT(pCount); -+ UMP_ASSERT(pArray); -+ UMP_ASSERT(mem); -+ alloc = (const umpp_allocation *)mem; -+ *pCount = alloc->blocksCount; -+ *pArray = alloc->block_array; -+} -+ -+/* -+ * UMP v1 API -+ */ -+ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle mem, ump_dd_physical_block * const blocks, unsigned long num_blocks) -+{ -+ const umpp_allocation * alloc; -+ unsigned long i; -+ UMP_ASSERT(mem); -+ UMP_ASSERT(blocks); -+ UMP_ASSERT(num_blocks); -+ -+ alloc = (const umpp_allocation *)mem; -+ -+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE); -+ -+ if((uint64_t)num_blocks != alloc->blocksCount) -+ { -+ return UMP_DD_INVALID; -+ } -+ -+ for( i = 0; i < num_blocks; i++) -+ { -+ UMP_ASSERT(alloc->block_array[i].addr <= UMP_UINT32_MAX); -+ UMP_ASSERT(alloc->block_array[i].size <= UMP_UINT32_MAX); -+ -+ blocks[i].addr = (unsigned long)alloc->block_array[i].addr; -+ blocks[i].size = (unsigned long)alloc->block_array[i].size; -+ } -+ -+ return UMP_DD_SUCCESS; -+} -+/* -+ * UMP v1 API -+ */ -+ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle mem, unsigned long index, ump_dd_physical_block * const block) -+{ -+ const umpp_allocation * alloc; -+ UMP_ASSERT(mem); -+ UMP_ASSERT(block); -+ alloc = (const umpp_allocation *)mem; -+ -+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE); -+ -+ UMP_ASSERT(alloc->block_array[index].addr <= UMP_UINT32_MAX); -+ UMP_ASSERT(alloc->block_array[index].size <= UMP_UINT32_MAX); -+ -+ block->addr = (unsigned long)alloc->block_array[index].addr; -+ block->size = (unsigned long)alloc->block_array[index].size; -+ -+ return UMP_DD_SUCCESS; -+} -+ -+/* -+ * UMP v1 API -+ */ -+unsigned long ump_dd_phys_block_count_get(ump_dd_handle mem) -+{ -+ const umpp_allocation * alloc; -+ UMP_ASSERT(mem); -+ alloc = (const umpp_allocation *)mem; -+ -+ UMP_ASSERT(alloc->flags & UMP_CONSTRAINT_32BIT_ADDRESSABLE); -+ UMP_ASSERT(alloc->blocksCount <= UMP_UINT32_MAX); -+ -+ return (unsigned long)alloc->blocksCount; -+} -+ -+umpp_cpu_mapping * umpp_dd_find_enclosing_mapping(umpp_allocation * alloc, void *uaddr, size_t size) -+{ -+ umpp_cpu_mapping *map; -+ -+ void *target_first = uaddr; -+ void *target_last = (void*)((uintptr_t)uaddr - 1 + size); -+ -+ if (target_last < target_first) /* wrapped */ -+ { -+ return NULL; -+ } -+ -+ mutex_lock(&alloc->map_list_lock); -+ list_for_each_entry(map, &alloc->map_list, link) -+ { -+ if ( map->vaddr_start <= target_first && -+ (void*)((uintptr_t)map->vaddr_start + (map->nr_pages << PAGE_SHIFT) - 1) >= target_last) -+ { -+ goto out; -+ } -+ } -+ map = NULL; -+out: -+ mutex_unlock(&alloc->map_list_lock); -+ -+ return map; -+} -+ -+void umpp_dd_add_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * map) -+{ -+ UMP_ASSERT(alloc); -+ UMP_ASSERT(map); -+ mutex_lock(&alloc->map_list_lock); -+ list_add(&map->link, &alloc->map_list); -+ mutex_unlock(&alloc->map_list_lock); -+} -+ -+void umpp_dd_remove_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * target) -+{ -+ umpp_cpu_mapping * map; -+ -+ UMP_ASSERT(alloc); -+ UMP_ASSERT(target); -+ -+ mutex_lock(&alloc->map_list_lock); -+ list_for_each_entry(map, &alloc->map_list, link) -+ { -+ if (map == target) -+ { -+ list_del(&target->link); -+ kfree(target); -+ mutex_unlock(&alloc->map_list_lock); -+ return; -+ } -+ } -+ -+ /* not found, error */ -+ UMP_ASSERT(0); -+} -+ -+int umpp_dd_find_start_block(const umpp_allocation * alloc, uint64_t offset, uint64_t * const block_index, uint64_t * const block_internal_offset) -+{ -+ uint64_t i; -+ -+ for (i = 0 ; i < alloc->blocksCount; i++) -+ { -+ if (offset < alloc->block_array[i].size) -+ { -+ /* found the block_array element containing this offset */ -+ *block_index = i; -+ *block_internal_offset = offset; -+ return 0; -+ } -+ offset -= alloc->block_array[i].size; -+ } -+ -+ return -ENXIO; -+} -+ -+void umpp_dd_cpu_msync_now(ump_dd_handle mem, ump_cpu_msync_op op, void * address, size_t size) -+{ -+ umpp_allocation * alloc; -+ void *vaddr; -+ umpp_cpu_mapping * mapping; -+ uint64_t virt_page_off; /* offset of given address from beginning of the virtual mapping */ -+ uint64_t phys_page_off; /* offset of the virtual mapping from the beginning of the physical buffer */ -+ uint64_t page_count; /* number of pages to sync */ -+ uint64_t i; -+ uint64_t block_idx; -+ uint64_t block_offset; -+ uint64_t paddr; -+ -+ UMP_ASSERT((UMP_MSYNC_CLEAN == op) || (UMP_MSYNC_CLEAN_AND_INVALIDATE == op)); -+ -+ alloc = (umpp_allocation*)mem; -+ vaddr = (void*)(uintptr_t)address; -+ -+ if((alloc->flags & UMP_CONSTRAINT_UNCACHED) != 0) -+ { -+ /* mapping is not cached */ -+ return; -+ } -+ -+ mapping = umpp_dd_find_enclosing_mapping(alloc, vaddr, size); -+ if (NULL == mapping) -+ { -+ printk(KERN_WARNING "UMP: Illegal cache sync address %lx\n", (uintptr_t)vaddr); -+ return; /* invalid pointer or size causes out-of-bounds */ -+ } -+ -+ /* we already know that address + size don't wrap around as umpp_dd_find_enclosing_mapping didn't fail */ -+ page_count = ((((((uintptr_t)address + size - 1) & PAGE_MASK) - ((uintptr_t)address & PAGE_MASK))) >> PAGE_SHIFT) + 1; -+ virt_page_off = (vaddr - mapping->vaddr_start) >> PAGE_SHIFT; -+ phys_page_off = mapping->page_off; -+ -+ if (umpp_dd_find_start_block(alloc, (virt_page_off + phys_page_off) << PAGE_SHIFT, &block_idx, &block_offset)) -+ { -+ /* should not fail as a valid mapping was found, so the phys mem must exists */ -+ printk(KERN_WARNING "UMP: Unable to find physical start block with offset %llx\n", virt_page_off + phys_page_off); -+ UMP_ASSERT(0); -+ return; -+ } -+ -+ paddr = alloc->block_array[block_idx].addr + block_offset + (((uintptr_t)vaddr) & ((1u << PAGE_SHIFT)-1)); -+ -+ for (i = 0; i < page_count; i++) -+ { -+ size_t offset = ((uintptr_t)vaddr) & ((1u << PAGE_SHIFT)-1); -+ size_t sz = min((size_t)PAGE_SIZE - offset, size); -+ -+ /* check if we've overrrun the current block, if so move to the next block */ -+ if (paddr >= (alloc->block_array[block_idx].addr + alloc->block_array[block_idx].size)) -+ { -+ block_idx++; -+ UMP_ASSERT(block_idx < alloc->blocksCount); -+ paddr = alloc->block_array[block_idx].addr; -+ } -+ -+ if (UMP_MSYNC_CLEAN == op) -+ { -+ ump_sync_to_memory(paddr, vaddr, sz); -+ } -+ else /* (UMP_MSYNC_CLEAN_AND_INVALIDATE == op) already validated on entry */ -+ { -+ ump_sync_to_cpu(paddr, vaddr, sz); -+ } -+ -+ /* advance to next page */ -+ vaddr = (void*)((uintptr_t)vaddr + sz); -+ size -= sz; -+ paddr += sz; -+ } -+} -+ -+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_create_from_phys_blocks_64(const ump_dd_physical_block_64 * blocks, uint64_t num_blocks, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data) -+{ -+ uint64_t size = 0; -+ uint64_t i; -+ umpp_allocation * alloc; -+ -+ UMP_ASSERT(blocks); -+ UMP_ASSERT(num_blocks); -+ -+ for (i = 0; i < num_blocks; i++) -+ { -+ size += blocks[i].size; -+ } -+ UMP_ASSERT(size); -+ -+ if (flags & (~UMP_FLAGS_RANGE)) -+ { -+ printk(KERN_WARNING "UMP: allocation flags out of allowed bits range\n"); -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+ } -+ -+ if( ( flags & (UMP_PROT_CPU_RD | UMP_PROT_W_RD | UMP_PROT_X_RD | UMP_PROT_Y_RD | UMP_PROT_Z_RD -+ | UMP_PROT_CPU_WR | UMP_PROT_W_WR | UMP_PROT_X_WR | UMP_PROT_Y_WR | UMP_PROT_Z_WR )) == 0 ) -+ { -+ printk(KERN_WARNING "UMP: allocation flags should have at least one read or write permission bit set\n"); -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+ } -+ -+ /*check permission flags to be set if hit flags are set too*/ -+ for (i = UMP_DEVICE_CPU_SHIFT; i<=UMP_DEVICE_Z_SHIFT; i+=4) -+ { -+ if (flags & (UMP_HINT_DEVICE_RD<block_array = kzalloc(sizeof(ump_dd_physical_block_64) * num_blocks,__GFP_HARDWALL | GFP_KERNEL); -+ if (NULL == alloc->block_array) -+ { -+ goto out2; -+ } -+ -+ memcpy(alloc->block_array, blocks, sizeof(ump_dd_physical_block_64) * num_blocks); -+ -+#ifdef CONFIG_KDS -+ kds_resource_init(&alloc->kds_res); -+#endif -+ alloc->size = size; -+ alloc->blocksCount = num_blocks; -+ alloc->flags = flags; -+ alloc->filter_func = filter_func; -+ alloc->final_release_func = final_release_func; -+ alloc->callback_data = callback_data; -+ -+ if (!(alloc->flags & UMP_PROT_SHAREABLE)) -+ { -+ alloc->owner = get_current()->pid; -+ } -+ -+ mutex_init(&alloc->map_list_lock); -+ INIT_LIST_HEAD(&alloc->map_list); -+ atomic_set(&alloc->refcount, 1); -+ -+ /* all set up, allocate an ID */ -+ -+ mutex_lock(&device.secure_id_map_lock); -+ alloc->id = umpp_descriptor_mapping_allocate(device.secure_id_map, (void*)alloc); -+ mutex_unlock(&device.secure_id_map_lock); -+ -+ if ((int)alloc->id == 0) -+ { -+ /* failed to allocate a secure_id */ -+ goto out3; -+ } -+ -+ alloc->management_flags |= UMP_MGMT_EXTERNAL; -+ -+ return alloc; -+ -+out3: -+ kfree(alloc->block_array); -+out2: -+ kfree(alloc); -+out1: -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+} -+ -+ -+/* -+ * UMP v1 API -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks) -+{ -+ ump_dd_handle mem; -+ ump_dd_physical_block_64 *block_64_array; -+ ump_alloc_flags flags = UMP_V1_API_DEFAULT_ALLOCATION_FLAGS; -+ unsigned long i; -+ -+ UMP_ASSERT(blocks); -+ UMP_ASSERT(num_blocks); -+ -+ block_64_array = kzalloc(num_blocks * sizeof(*block_64_array), __GFP_HARDWALL | GFP_KERNEL); -+ -+ if(block_64_array == NULL) -+ { -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+ } -+ -+ /* copy physical blocks */ -+ for( i = 0; i < num_blocks; i++) -+ { -+ block_64_array[i].addr = blocks[i].addr; -+ block_64_array[i].size = blocks[i].size; -+ } -+ -+ mem = ump_dd_create_from_phys_blocks_64(block_64_array, num_blocks, flags, NULL, NULL, NULL); -+ -+ kfree(block_64_array); -+ -+ return mem; -+ -+} -diff --git a/drivers/base/ump/src/common/ump_kernel_core.h b/drivers/base/ump/src/common/ump_kernel_core.h -new file mode 100644 -index 0000000..8cb424d ---- /dev/null -+++ b/drivers/base/ump/src/common/ump_kernel_core.h -@@ -0,0 +1,228 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _UMP_KERNEL_CORE_H_ -+#define _UMP_KERNEL_CORE_H_ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_KDS -+#include -+#endif -+#include -+#include -+ -+/* forward decl */ -+struct umpp_session; -+ -+/** -+ * UMP handle metadata. -+ * Tracks various data about a handle not of any use to user space -+ */ -+typedef enum -+{ -+ UMP_MGMT_EXTERNAL = (1ul << 0) /**< Handle created via the ump_dd_create_from_phys_blocks interface */ -+ /* (1ul << 31) not to be used */ -+} umpp_management_flags; -+ -+/** -+ * Structure tracking the single global UMP device. -+ * Holds global data like the ID map -+ */ -+typedef struct umpp_device -+{ -+ struct mutex secure_id_map_lock; /**< Lock protecting access to the map */ -+ umpp_descriptor_mapping * secure_id_map; /**< Map of all known secure IDs on the system */ -+} umpp_device; -+ -+/** -+ * Structure tracking all memory allocations of a UMP allocation. -+ * Tracks info about an mapping so we can verify cache maintenace -+ * operations and help in the unmap cleanup. -+ */ -+typedef struct umpp_cpu_mapping -+{ -+ struct list_head link; /**< link to list of mappings for an allocation */ -+ void *vaddr_start; /**< CPU VA start of the mapping */ -+ size_t nr_pages; /**< Size (in pages) of the mapping */ -+ uint64_t page_off; /**< Offset (in pages) from start of the allocation where the mapping starts */ -+ ump_dd_handle handle; /**< Which handle this mapping is linked to */ -+ struct umpp_session * session; /**< Which session created the mapping */ -+} umpp_cpu_mapping; -+ -+/** -+ * Structure tracking UMP allocation. -+ * Represent a memory allocation with its ID. -+ * Tracks all needed meta-data about an allocation. -+ * */ -+typedef struct umpp_allocation -+{ -+ ump_secure_id id; /**< Secure ID of the allocation */ -+ atomic_t refcount; /**< Usage count */ -+ -+ ump_alloc_flags flags; /**< Flags for all supported devices */ -+ uint32_t management_flags; /**< Managment flags tracking */ -+ -+ pid_t owner; /**< The process ID owning the memory if not sharable */ -+ -+ ump_dd_security_filter filter_func; /**< Hook to verify use, called during retains from new clients */ -+ ump_dd_final_release_callback final_release_func; /**< Hook called when the last reference is removed */ -+ void* callback_data; /**< Additional data given to release hook */ -+ -+ uint64_t size; /**< Size (in bytes) of the allocation */ -+ uint64_t blocksCount; /**< Number of physsical blocks the allocation is built up of */ -+ ump_dd_physical_block_64 * block_array; /**< Array, one entry per block, describing block start and length */ -+ -+ struct mutex map_list_lock; /**< Lock protecting the map_list */ -+ struct list_head map_list; /**< Tracks all CPU VA mappings of this allocation */ -+ -+#ifdef CONFIG_KDS -+ struct kds_resource kds_res; /**< The KDS resource controlling access to this allocation */ -+#endif -+ -+ void * backendData; /**< Physical memory backend meta-data */ -+} umpp_allocation; -+ -+/** -+ * Structure tracking use of UMP memory by a session. -+ * Tracks the use of an allocation by a session so session termination can clean up any outstanding references. -+ * Also protects agains non-matched release calls from user space. -+ */ -+typedef struct umpp_session_memory_usage -+{ -+ ump_secure_id id; /**< ID being used. For quick look-up */ -+ ump_dd_handle mem; /**< Handle being used. */ -+ -+ /** -+ * Track how many times has the process retained this handle in the kernel. -+ * This should usually just be 1(allocated or resolved) or 2(mapped), -+ * but could be more if someone is playing with the low-level API -+ * */ -+ atomic_t process_usage_count; -+ -+ struct list_head link; /**< link to other usage trackers for a session */ -+} umpp_session_memory_usage; -+ -+/** -+ * Structure representing a session/client. -+ * Tracks the UMP allocations being used by this client. -+ */ -+typedef struct umpp_session -+{ -+ struct mutex session_lock; /**< Lock for memory usage manipulation */ -+ struct list_head memory_usage; /**< list of memory currently being used by the this session */ -+ void* import_handler_data[UMPP_EXTERNAL_MEM_COUNT]; /**< Import modules per-session data pointer */ -+} umpp_session; -+ -+/** -+ * UMP core setup. -+ * Called by any OS specific startup function to initialize the common part. -+ * @return UMP_OK if core initialized correctly, any other value for errors -+ */ -+ump_result umpp_core_constructor(void); -+ -+/** -+ * UMP core teardown. -+ * Called by any OS specific unload function to clean up the common part. -+ */ -+void umpp_core_destructor(void); -+ -+/** -+ * UMP session start. -+ * Called by any OS specific session handler when a new session is detected -+ * @return Non-NULL if a matching core session could be set up. NULL on failure -+ */ -+umpp_session *umpp_core_session_start(void); -+ -+/** -+ * UMP session end. -+ * Called by any OS specific session handler when a session is ended/terminated. -+ * @param session The core session object returned by ump_core_session_start -+ */ -+void umpp_core_session_end(umpp_session *session); -+ -+/** -+ * Find a mapping object (if any) for this allocation. -+ * Called by any function needing to identify a mapping from a user virtual address. -+ * Verifies that the whole range to be within a mapping object. -+ * @param alloc The UMP allocation to find a matching mapping object of -+ * @param uaddr User mapping address to find the mapping object for -+ * @param size Length of the mapping -+ * @return NULL on error (no match found), pointer to mapping object if match found -+ */ -+umpp_cpu_mapping * umpp_dd_find_enclosing_mapping(umpp_allocation * alloc, void* uaddr, size_t size); -+ -+/** -+ * Register a new mapping of an allocation. -+ * Called by functions creating a new mapping of an allocation, typically OS specific handlers. -+ * @param alloc The allocation object which has been mapped -+ * @param map Info about the mapping -+ */ -+void umpp_dd_add_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * map); -+ -+/** -+ * Remove and free mapping object from an allocation. -+ * @param alloc The allocation object to remove the mapping info from -+ * @param target The mapping object to remove -+ */ -+void umpp_dd_remove_cpu_mapping(umpp_allocation * alloc, umpp_cpu_mapping * target); -+ -+/** -+ * Helper to find a block in the blockArray which holds a given byte offset. -+ * @param alloc The allocation object to find the block in -+ * @param offset Offset (in bytes) from allocation start to find the block of -+ * @param[out] block_index Pointer to the index of the block matching -+ * @param[out] block_internal_offset Offset within the returned block of the searched offset -+ * @return 0 if a matching block was found, any other value for error -+ */ -+int umpp_dd_find_start_block(const umpp_allocation * alloc, uint64_t offset, uint64_t * const block_index, uint64_t * const block_internal_offset); -+ -+/** -+ * Cache maintenance helper. -+ * Performs the requested cache operation on the given handle. -+ * @param mem Allocation handle -+ * @param op Cache maintenance operation to perform -+ * @param address User mapping at which to do the operation -+ * @param size Length (in bytes) of the range to do the operation on -+ */ -+void umpp_dd_cpu_msync_now(ump_dd_handle mem, ump_cpu_msync_op op, void * address, size_t size); -+ -+/** -+ * Import module session early init. -+ * Calls session_begin on all installed import modules. -+ * @param session The core session object to initialized the import handler for -+ * */ -+void umpp_import_handlers_init(umpp_session * session); -+ -+/** -+ * Import module session cleanup. -+ * Calls session_end on all import modules bound to the session. -+ * @param session The core session object to initialized the import handler for -+ */ -+void umpp_import_handlers_term(umpp_session * session); -+ -+#endif /* _UMP_KERNEL_CORE_H_ */ -+ -diff --git a/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.c b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.c -new file mode 100644 -index 0000000..c5b0d74 ---- /dev/null -+++ b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.c -@@ -0,0 +1,162 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+ -+#include -+#include -+ -+#define MALI_PAD_INT(x) (((x) + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1)) -+ -+/** -+ * Allocate a descriptor table capable of holding 'count' mappings -+ * @param count Number of mappings in the table -+ * @return Pointer to a new table, NULL on error -+ */ -+static umpp_descriptor_table * descriptor_table_alloc(unsigned int count); -+ -+/** -+ * Free a descriptor table -+ * @param table The table to free -+ */ -+static void descriptor_table_free(umpp_descriptor_table * table); -+ -+umpp_descriptor_mapping * umpp_descriptor_mapping_create(unsigned int init_entries, unsigned int max_entries) -+{ -+ umpp_descriptor_mapping * map = kzalloc(sizeof(umpp_descriptor_mapping), GFP_KERNEL); -+ -+ init_entries = MALI_PAD_INT(init_entries); -+ max_entries = MALI_PAD_INT(max_entries); -+ -+ if (NULL != map) -+ { -+ map->table = descriptor_table_alloc(init_entries); -+ if (NULL != map->table) -+ { -+ init_rwsem( &map->lock); -+ set_bit(0, map->table->usage); -+ map->max_nr_mappings_allowed = max_entries; -+ map->current_nr_mappings = init_entries; -+ return map; -+ -+ descriptor_table_free(map->table); -+ } -+ kfree(map); -+ } -+ return NULL; -+} -+ -+void umpp_descriptor_mapping_destroy(umpp_descriptor_mapping * map) -+{ -+ UMP_ASSERT(NULL != map); -+ descriptor_table_free(map->table); -+ kfree(map); -+} -+ -+unsigned int umpp_descriptor_mapping_allocate(umpp_descriptor_mapping * map, void * target) -+{ -+ int descriptor = 0; -+ UMP_ASSERT(NULL != map); -+ down_write( &map->lock); -+ descriptor = find_first_zero_bit(map->table->usage, map->current_nr_mappings); -+ if (descriptor == map->current_nr_mappings) -+ { -+ /* no free descriptor, try to expand the table */ -+ umpp_descriptor_table * new_table; -+ umpp_descriptor_table * old_table = map->table; -+ int nr_mappings_new = map->current_nr_mappings + BITS_PER_LONG; -+ -+ if (map->current_nr_mappings >= map->max_nr_mappings_allowed) -+ { -+ descriptor = 0; -+ goto unlock_and_exit; -+ } -+ -+ new_table = descriptor_table_alloc(nr_mappings_new); -+ if (NULL == new_table) -+ { -+ descriptor = 0; -+ goto unlock_and_exit; -+ } -+ -+ memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG); -+ memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*)); -+ -+ map->table = new_table; -+ map->current_nr_mappings = nr_mappings_new; -+ descriptor_table_free(old_table); -+ } -+ -+ /* we have found a valid descriptor, set the value and usage bit */ -+ set_bit(descriptor, map->table->usage); -+ map->table->mappings[descriptor] = target; -+ -+unlock_and_exit: -+ up_write(&map->lock); -+ return descriptor; -+} -+ -+int umpp_descriptor_mapping_lookup(umpp_descriptor_mapping * map, unsigned int descriptor, void** const target) -+{ -+ int result = -EINVAL; -+ UMP_ASSERT(map); -+ UMP_ASSERT(target); -+ down_read(&map->lock); -+ if ( (descriptor > 0) && (descriptor < map->current_nr_mappings) && test_bit(descriptor, map->table->usage) ) -+ { -+ *target = map->table->mappings[descriptor]; -+ result = 0; -+ } -+ /* keep target untouched if the descriptor was not found */ -+ up_read(&map->lock); -+ return result; -+} -+ -+void umpp_descriptor_mapping_remove(umpp_descriptor_mapping * map, unsigned int descriptor) -+{ -+ UMP_ASSERT(map); -+ down_write(&map->lock); -+ if ( (descriptor > 0) && (descriptor < map->current_nr_mappings) && test_bit(descriptor, map->table->usage) ) -+ { -+ map->table->mappings[descriptor] = NULL; -+ clear_bit(descriptor, map->table->usage); -+ } -+ up_write(&map->lock); -+} -+ -+static umpp_descriptor_table * descriptor_table_alloc(unsigned int count) -+{ -+ umpp_descriptor_table * table; -+ -+ table = kzalloc(sizeof(umpp_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG) + (sizeof(void*) * count), __GFP_HARDWALL | GFP_KERNEL ); -+ -+ if (NULL != table) -+ { -+ table->usage = (unsigned long*)((u8*)table + sizeof(umpp_descriptor_table)); -+ table->mappings = (void**)((u8*)table + sizeof(umpp_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG)); -+ } -+ -+ return table; -+} -+ -+static void descriptor_table_free(umpp_descriptor_table * table) -+{ -+ UMP_ASSERT(table); -+ kfree(table); -+} -+ -diff --git a/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.h b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.h -new file mode 100644 -index 0000000..d06c145 ---- /dev/null -+++ b/drivers/base/ump/src/common/ump_kernel_descriptor_mapping.h -@@ -0,0 +1,94 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file ump_kernel_descriptor_mapping.h -+ */ -+ -+#ifndef _UMP_KERNEL_DESCRIPTOR_MAPPING_H_ -+#define _UMP_KERNEL_DESCRIPTOR_MAPPING_H_ -+ -+#include -+#include -+/** -+ * The actual descriptor mapping table, never directly accessed by clients -+ */ -+typedef struct umpp_descriptor_table -+{ -+ /* keep as a unsigned long to rely on the OS's bitops support */ -+ unsigned long * usage; /**< Pointer to bitpattern indicating if a descriptor is valid/used(1) or not(0) */ -+ void** mappings; /**< Array of the pointers the descriptors map to */ -+} umpp_descriptor_table; -+ -+/** -+ * The descriptor mapping object -+ * Provides a separate namespace where we can map an integer to a pointer -+ */ -+typedef struct umpp_descriptor_mapping -+{ -+ struct rw_semaphore lock; /**< Lock protecting access to the mapping object */ -+ unsigned int max_nr_mappings_allowed; /**< Max number of mappings to support in this namespace */ -+ unsigned int current_nr_mappings; /**< Current number of possible mappings */ -+ umpp_descriptor_table * table; /**< Pointer to the current mapping table */ -+} umpp_descriptor_mapping; -+ -+/** -+ * Create a descriptor mapping object. -+ * Create a descriptor mapping capable of holding init_entries growable to max_entries. -+ * ID 0 is reserved so the number of available entries will be max - 1. -+ * @param init_entries Number of entries to preallocate memory for -+ * @param max_entries Number of entries to max support -+ * @return Pointer to a descriptor mapping object, NULL on failure -+ */ -+umpp_descriptor_mapping * umpp_descriptor_mapping_create(unsigned int init_entries, unsigned int max_entries); -+ -+/** -+ * Destroy a descriptor mapping object -+ * @param[in] map The map to free -+ */ -+void umpp_descriptor_mapping_destroy(umpp_descriptor_mapping * map); -+ -+/** -+ * Allocate a new mapping entry (descriptor ID) -+ * Allocates a new entry in the map. -+ * @param[in] map The map to allocate a new entry in -+ * @param[in] target The value to map to -+ * @return The descriptor allocated, ID 0 on failure. -+ */ -+unsigned int umpp_descriptor_mapping_allocate(umpp_descriptor_mapping * map, void * target); -+ -+/** -+ * Get the value mapped to by a descriptor ID -+ * @param[in] map The map to lookup the descriptor id in -+ * @param[in] descriptor The descriptor ID to lookup -+ * @param[out] target Pointer to a pointer which will receive the stored value -+ * -+ * @return 0 on success lookup, -EINVAL on lookup failure. -+ */ -+int umpp_descriptor_mapping_lookup(umpp_descriptor_mapping * map, unsigned int descriptor, void** const target); -+ -+/** -+ * Free the descriptor ID -+ * For the descriptor to be reused it has to be freed -+ * @param[in] map The map to free the descriptor from -+ * @param descriptor The descriptor ID to free -+ */ -+void umpp_descriptor_mapping_remove(umpp_descriptor_mapping * map, unsigned int descriptor); -+ -+#endif /* _UMP_KERNEL_DESCRIPTOR_MAPPING_H_ */ -diff --git a/drivers/base/ump/src/common/ump_kernel_priv.h b/drivers/base/ump/src/common/ump_kernel_priv.h -new file mode 100644 -index 0000000..38b6f1b ---- /dev/null -+++ b/drivers/base/ump/src/common/ump_kernel_priv.h -@@ -0,0 +1,80 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _UMP_KERNEL_PRIV_H_ -+#define _UMP_KERNEL_PRIV_H_ -+ -+#ifdef __KERNEL__ -+#include -+#include -+#include -+#include -+#endif -+ -+ -+#define UMP_EXPECTED_IDS 64 -+#define UMP_MAX_IDS 32768 -+ -+#ifdef __KERNEL__ -+#define UMP_ASSERT(expr) \ -+ if (!(expr)) { \ -+ printk(KERN_ERR "UMP: Assertion failed! %s,%s,%s,line=%d\n",\ -+ #expr,__FILE__,__func__,__LINE__); \ -+ BUG(); \ -+ } -+ -+static inline void ump_sync_to_memory(uint64_t paddr, void* vaddr, size_t sz) -+{ -+#ifdef CONFIG_ARM -+ __cpuc_flush_dcache_area(vaddr, sz); -+ outer_flush_range(paddr, paddr+sz); -+#elif defined(CONFIG_ARM64) -+ /*TODO (MID64-46): There's no other suitable cache flush function for ARM64 */ -+ flush_cache_all(); -+#elif defined(CONFIG_X86) -+ struct scatterlist scl = {0, }; -+ sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz, -+ paddr & (PAGE_SIZE -1 )); -+ dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_TO_DEVICE); -+ mb(); /* for outer_sync (if needed) */ -+#else -+#error Implement cache maintenance for your architecture here -+#endif -+} -+ -+static inline void ump_sync_to_cpu(uint64_t paddr, void* vaddr, size_t sz) -+{ -+#ifdef CONFIG_ARM -+ __cpuc_flush_dcache_area(vaddr, sz); -+ outer_flush_range(paddr, paddr+sz); -+#elif defined(CONFIG_ARM64) -+ /* TODO (MID64-46): There's no other suitable cache flush function for ARM64 */ -+ flush_cache_all(); -+#elif defined(CONFIG_X86) -+ struct scatterlist scl = {0, }; -+ sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz, -+ paddr & (PAGE_SIZE -1 )); -+ dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_FROM_DEVICE); -+#else -+#error Implement cache maintenance for your architecture here -+#endif -+} -+#endif /* __KERNEL__*/ -+#endif /* _UMP_KERNEL_PRIV_H_ */ -+ -diff --git a/drivers/base/ump/src/imports/ion/Makefile b/drivers/base/ump/src/imports/ion/Makefile -new file mode 100644 -index 0000000..ef74b27 ---- /dev/null -+++ b/drivers/base/ump/src/imports/ion/Makefile -@@ -0,0 +1,53 @@ -+# -+# (C) COPYRIGHT 2011, 2013 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+ -+# default to building for the host -+ARCH ?= $(shell uname -m) -+ -+# linux build system integration -+ -+ifneq ($(KERNELRELEASE),) -+# Inside the kernel build system -+ -+EXTRA_CFLAGS += -I$(KBUILD_EXTMOD) -I$(KBUILD_EXTMOD)/../../../../.. -+KBUILD_EXTRA_SYMBOLS += "$(KBUILD_EXTMOD)/../../Module.symvers" -+ -+SRC += ump_kernel_import_ion.c -+ -+MODULE:=ump_ion_import.ko -+ -+obj-m := $(MODULE:.ko=.o) -+$(MODULE:.ko=-y) := $(SRC:.c=.o) -+$(MODULE:.ko=-objs) := $(SRC:.c=.o) -+ -+else -+# Outside the kernel build system -+# -+# -+ -+ifeq ($(KDIR),) -+$(error Must specify KDIR to point to the kernel to target)) -+endif -+ -+all: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) -+ -+clean: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean -+ -+endif -+ -diff --git a/drivers/base/ump/src/imports/ion/sconscript b/drivers/base/ump/src/imports/ion/sconscript -new file mode 100644 -index 0000000..cff24c8 ---- /dev/null -+++ b/drivers/base/ump/src/imports/ion/sconscript -@@ -0,0 +1,49 @@ -+# -+# (C) COPYRIGHT 2010-2013, 2016 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+import os -+Import('env') -+ -+# Clone the environment so changes don't affect other build files -+env_ion = env.Clone() -+ -+if env_ion['ump_ion'] != '1': -+ Return() -+ -+# Source files required for UMP. -+ion_src = [Glob('#kernel/drivers/base/ump/src/imports/ion/*.c')] -+ -+# Note: cleaning via the Linux kernel build system does not yet work -+if env_ion.GetOption('clean') : -+ makeAction=Action("cd ${SOURCE.dir} && make clean", '$MAKECOMSTR') -+else: -+ makeAction=Action("cd ${SOURCE.dir} && make PLATFORM=${platform} && cp ump_ion_import.ko $STATIC_LIB_PATH/ump_ion_import.ko", '$MAKECOMSTR') -+# The target is ump_import_ion.ko, built from the source in ion_src, via the action makeAction -+# ump_import_ion.ko will be copied to $STATIC_LIB_PATH after being built by the standard Linux -+# kernel build system, after which it can be installed to the directory specified if -+# "libs_install" is set; this is done by LibTarget. -+cmd = env_ion.Command('$STATIC_LIB_PATH/ump_ion_import.ko', ion_src, [makeAction]) -+ -+# Until we fathom out how the invoke the Linux build system to clean, we can use Clean -+# to remove generated files. -+ -+patterns = ['*.mod.c', '*.o', '*.ko', '*.a', '.*.cmd', 'modules.order', '.tmp_versions', 'Module.symvers'] -+ -+for p in patterns: -+ Clean(cmd, Glob('#kernel/drivers/base/ump/src/imports/ion/%s' % p)) -+ -+env_ion.Depends('$STATIC_LIB_PATH/ump_ion_import.ko', '$STATIC_LIB_PATH/ump.ko') -+env_ion.KernelObjTarget('ump', cmd) -diff --git a/drivers/base/ump/src/imports/ion/ump_kernel_import_ion.c b/drivers/base/ump/src/imports/ion/ump_kernel_import_ion.c -new file mode 100644 -index 0000000..12b2e32 ---- /dev/null -+++ b/drivers/base/ump/src/imports/ion/ump_kernel_import_ion.c -@@ -0,0 +1,204 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+#include "ion.h" -+#include -+#include -+#include -+ -+struct ion_wrapping_info -+{ -+ struct ion_client * ion_client; -+ struct ion_handle * ion_handle; -+ int num_phys_blocks; -+ struct scatterlist * sglist; -+}; -+ -+static struct ion_device * ion_device_get(void) -+{ -+ /* < Customer to provide implementation > -+ * Return a pointer to the global ion_device on the system -+ */ -+ return NULL; -+} -+ -+static int import_ion_client_create(void** const custom_session_data) -+{ -+ struct ion_client ** ion_client; -+ -+ ion_client = (struct ion_client**)custom_session_data; -+ -+ *ion_client = ion_client_create(ion_device_get(), "ump"); -+ -+ return PTR_RET(*ion_client); -+} -+ -+ -+static void import_ion_client_destroy(void* custom_session_data) -+{ -+ struct ion_client * ion_client; -+ -+ ion_client = (struct ion_client*)custom_session_data; -+ BUG_ON(!ion_client); -+ -+ ion_client_destroy(ion_client); -+} -+ -+ -+static void import_ion_final_release_callback(const ump_dd_handle handle, void * info) -+{ -+ struct ion_wrapping_info * ion_info; -+ -+ BUG_ON(!info); -+ -+ (void)handle; -+ ion_info = (struct ion_wrapping_info*)info; -+ -+ dma_unmap_sg(NULL, ion_info->sglist, ion_info->num_phys_blocks, DMA_BIDIRECTIONAL); -+ -+ ion_free(ion_info->ion_client, ion_info->ion_handle); -+ kfree(ion_info); -+ module_put(THIS_MODULE); -+} -+ -+static ump_dd_handle import_ion_import(void * custom_session_data, void * pfd, ump_alloc_flags flags) -+{ -+ int fd; -+ ump_dd_handle ump_handle; -+ struct scatterlist * sg; -+ int num_dma_blocks; -+ ump_dd_physical_block_64 * phys_blocks; -+ unsigned long i; -+ struct sg_table * sgt; -+ -+ struct ion_wrapping_info * ion_info; -+ -+ BUG_ON(!custom_session_data); -+ BUG_ON(!pfd); -+ -+ ion_info = kzalloc(GFP_KERNEL, sizeof(*ion_info)); -+ if (NULL == ion_info) -+ { -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+ } -+ -+ ion_info->ion_client = (struct ion_client*)custom_session_data; -+ -+ if (get_user(fd, (int*)pfd)) -+ { -+ goto out; -+ } -+ -+ ion_info->ion_handle = ion_import_dma_buf(ion_info->ion_client, fd); -+ -+ if (IS_ERR_OR_NULL(ion_info->ion_handle)) -+ { -+ goto out; -+ } -+ -+ sgt = ion_sg_table(ion_info->ion_client, ion_info->ion_handle); -+ if (IS_ERR_OR_NULL(sgt)) -+ { -+ goto ion_dma_map_failed; -+ } -+ -+ ion_info->sglist = sgt->sgl; -+ -+ sg = ion_info->sglist; -+ while (sg) -+ { -+ ion_info->num_phys_blocks++; -+ sg = sg_next(sg); -+ } -+ -+ num_dma_blocks = dma_map_sg(NULL, ion_info->sglist, ion_info->num_phys_blocks, DMA_BIDIRECTIONAL); -+ -+ if (0 == num_dma_blocks) -+ { -+ goto linux_dma_map_failed; -+ } -+ -+ phys_blocks = vmalloc(num_dma_blocks * sizeof(*phys_blocks)); -+ if (NULL == phys_blocks) -+ { -+ goto vmalloc_failed; -+ } -+ -+ for_each_sg(ion_info->sglist, sg, num_dma_blocks, i) -+ { -+ phys_blocks[i].addr = sg_phys(sg); -+ phys_blocks[i].size = sg_dma_len(sg); -+ } -+ -+ ump_handle = ump_dd_create_from_phys_blocks_64(phys_blocks, num_dma_blocks, flags, NULL, import_ion_final_release_callback, ion_info); -+ -+ vfree(phys_blocks); -+ -+ if (ump_handle != UMP_DD_INVALID_MEMORY_HANDLE) -+ { -+ /* -+ * As we have a final release callback installed -+ * we must keep the module locked until -+ * the callback has been triggered -+ * */ -+ __module_get(THIS_MODULE); -+ return ump_handle; -+ } -+ -+ /* failed*/ -+vmalloc_failed: -+ dma_unmap_sg(NULL, ion_info->sglist, ion_info->num_phys_blocks, DMA_BIDIRECTIONAL); -+linux_dma_map_failed: -+ion_dma_map_failed: -+ ion_free(ion_info->ion_client, ion_info->ion_handle); -+out: -+ kfree(ion_info); -+ return UMP_DD_INVALID_MEMORY_HANDLE; -+} -+ -+struct ump_import_handler import_handler_ion = -+{ -+ .linux_module = THIS_MODULE, -+ .session_begin = import_ion_client_create, -+ .session_end = import_ion_client_destroy, -+ .import = import_ion_import -+}; -+ -+static int __init import_ion_initialize_module(void) -+{ -+ /* register with UMP */ -+ return ump_import_module_register(UMP_EXTERNAL_MEM_TYPE_ION, &import_handler_ion); -+} -+ -+static void __exit import_ion_cleanup_module(void) -+{ -+ /* unregister import handler */ -+ ump_import_module_unregister(UMP_EXTERNAL_MEM_TYPE_ION); -+} -+ -+/* Setup init and exit functions for this module */ -+module_init(import_ion_initialize_module); -+module_exit(import_ion_cleanup_module); -+ -+/* And some module information */ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("ARM Ltd."); -+MODULE_VERSION("1.0"); -diff --git a/drivers/base/ump/src/imports/sconscript b/drivers/base/ump/src/imports/sconscript -new file mode 100644 -index 0000000..8f50683 ---- /dev/null -+++ b/drivers/base/ump/src/imports/sconscript -@@ -0,0 +1,25 @@ -+# -+# (C) COPYRIGHT 2011-2013 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+import os, sys -+Import('env') -+ -+import_modules = [ os.path.join( path, 'sconscript' ) for path in sorted(os.listdir( os.getcwd() )) ] -+ -+for m in import_modules: -+ if os.path.exists(m): -+ SConscript( m, variant_dir=os.path.join( env['BUILD_DIR_PATH'], os.path.dirname(m) ), duplicate=0 ) -+ -diff --git a/drivers/base/ump/src/linux/ump_kernel_linux.c b/drivers/base/ump/src/linux/ump_kernel_linux.c -new file mode 100644 -index 0000000..d6c3c53 ---- /dev/null -+++ b/drivers/base/ump/src/linux/ump_kernel_linux.c -@@ -0,0 +1,831 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+ -+#include /* copy_*_user */ -+#include -+#include /* kernel module definitions */ -+#include /* file system operations */ -+#include /* character device definitions */ -+#include /* request_mem_region */ -+#include /* class registration support */ -+ -+#include -+ -+#include "ump_kernel_linux_mem.h" -+#include -+ -+ -+struct ump_linux_device -+{ -+ struct cdev cdev; -+ struct class * ump_class; -+}; -+ -+/* Name of the UMP device driver */ -+static char ump_dev_name[] = "ump"; /* should be const, but the functions we call requires non-cost */ -+ -+/* Module parameter to control log level */ -+int ump_debug_level = 2; -+module_param(ump_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */ -+MODULE_PARM_DESC(ump_debug_level, "Higher number, more dmesg output"); -+ -+/* By default the module uses any available major, but it's possible to set it at load time to a specific number */ -+int ump_major = 0; -+module_param(ump_major, int, S_IRUGO); /* r--r--r-- */ -+MODULE_PARM_DESC(ump_major, "Device major number"); -+ -+#define UMP_REV_STRING "1.0" -+ -+char * ump_revision = UMP_REV_STRING; -+module_param(ump_revision, charp, S_IRUGO); /* r--r--r-- */ -+MODULE_PARM_DESC(ump_revision, "Revision info"); -+ -+static int umpp_linux_open(struct inode *inode, struct file *filp); -+static int umpp_linux_release(struct inode *inode, struct file *filp); -+#ifdef HAVE_UNLOCKED_IOCTL -+static long umpp_linux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -+#else -+static int umpp_linux_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -+#endif -+ -+/* This variable defines the file operations this UMP device driver offers */ -+static struct file_operations ump_fops = -+{ -+ .owner = THIS_MODULE, -+ .open = umpp_linux_open, -+ .release = umpp_linux_release, -+#ifdef HAVE_UNLOCKED_IOCTL -+ .unlocked_ioctl = umpp_linux_ioctl, -+#else -+ .ioctl = umpp_linux_ioctl, -+#endif -+ .compat_ioctl = umpp_linux_ioctl, -+ .mmap = umpp_linux_mmap -+}; -+ -+/* import module handling */ -+DEFINE_MUTEX(import_list_lock); -+struct ump_import_handler * import_handlers[UMPP_EXTERNAL_MEM_COUNT]; -+ -+/* The global variable containing the global device data */ -+static struct ump_linux_device ump_linux_device; -+ -+#define DBG_MSG(level, ...) do { \ -+if ((level) <= ump_debug_level)\ -+{\ -+printk(KERN_DEBUG "UMP<" #level ">:\n" __VA_ARGS__);\ -+} \ -+} while (0) -+ -+#define MSG_ERR(...) do{ \ -+printk(KERN_ERR "UMP: ERR: %s\n %s()%4d\n", __FILE__, __func__ , __LINE__) ; \ -+printk(KERN_ERR __VA_ARGS__); \ -+printk(KERN_ERR "\n"); \ -+} while(0) -+ -+#define MSG(...) do{ \ -+printk(KERN_INFO "UMP: " __VA_ARGS__);\ -+} while (0) -+ -+/* -+ * This function is called by Linux to initialize this module. -+ * All we do is initialize the UMP device driver. -+ */ -+static int __init umpp_linux_initialize_module(void) -+{ -+ ump_result err; -+ -+ err = umpp_core_constructor(); -+ if (UMP_OK != err) -+ { -+ MSG_ERR("UMP device driver init failed\n"); -+ return -ENOTTY; -+ } -+ -+ MSG("UMP device driver %s loaded\n", UMP_REV_STRING); -+ return 0; -+} -+ -+ -+ -+/* -+ * This function is called by Linux to unload/terminate/exit/cleanup this module. -+ * All we do is terminate the UMP device driver. -+ */ -+static void __exit umpp_linux_cleanup_module(void) -+{ -+ DBG_MSG(2, "Unloading UMP device driver\n"); -+ umpp_core_destructor(); -+ DBG_MSG(2, "Module unloaded\n"); -+} -+ -+ -+ -+/* -+ * Initialize the UMP device driver. -+ */ -+ump_result umpp_device_initialize(void) -+{ -+ int err; -+ dev_t dev = 0; -+ -+ if (0 == ump_major) -+ { -+ /* auto select a major */ -+ err = alloc_chrdev_region(&dev, 0, 1, ump_dev_name); -+ ump_major = MAJOR(dev); -+ } -+ else -+ { -+ /* use load time defined major number */ -+ dev = MKDEV(ump_major, 0); -+ err = register_chrdev_region(dev, 1, ump_dev_name); -+ } -+ -+ if (0 == err) -+ { -+ memset(&ump_linux_device, 0, sizeof(ump_linux_device)); -+ -+ /* initialize our char dev data */ -+ cdev_init(&ump_linux_device.cdev, &ump_fops); -+ ump_linux_device.cdev.owner = THIS_MODULE; -+ ump_linux_device.cdev.ops = &ump_fops; -+ -+ /* register char dev with the kernel */ -+ err = cdev_add(&ump_linux_device.cdev, dev, 1/*count*/); -+ if (0 == err) -+ { -+ -+ ump_linux_device.ump_class = class_create(THIS_MODULE, ump_dev_name); -+ if (IS_ERR(ump_linux_device.ump_class)) -+ { -+ err = PTR_ERR(ump_linux_device.ump_class); -+ } -+ else -+ { -+ struct device * mdev; -+ mdev = device_create(ump_linux_device.ump_class, NULL, dev, NULL, ump_dev_name); -+ if (!IS_ERR(mdev)) -+ { -+ return UMP_OK; -+ } -+ -+ err = PTR_ERR(mdev); -+ class_destroy(ump_linux_device.ump_class); -+ } -+ cdev_del(&ump_linux_device.cdev); -+ } -+ -+ unregister_chrdev_region(dev, 1); -+ } -+ -+ return UMP_ERROR; -+} -+ -+ -+ -+/* -+ * Terminate the UMP device driver -+ */ -+void umpp_device_terminate(void) -+{ -+ dev_t dev = MKDEV(ump_major, 0); -+ -+ device_destroy(ump_linux_device.ump_class, dev); -+ class_destroy(ump_linux_device.ump_class); -+ -+ /* unregister char device */ -+ cdev_del(&ump_linux_device.cdev); -+ -+ /* free major */ -+ unregister_chrdev_region(dev, 1); -+} -+ -+ -+static int umpp_linux_open(struct inode *inode, struct file *filp) -+{ -+ umpp_session *session; -+ -+ session = umpp_core_session_start(); -+ if (NULL == session) -+ { -+ return -EFAULT; -+ } -+ -+ filp->private_data = session; -+ -+ return 0; -+} -+ -+static int umpp_linux_release(struct inode *inode, struct file *filp) -+{ -+ umpp_session *session; -+ -+ session = filp->private_data; -+ -+ umpp_core_session_end(session); -+ -+ filp->private_data = NULL; -+ -+ return 0; -+} -+ -+/**************************/ -+/*ioctl specific functions*/ -+/**************************/ -+static int do_ump_dd_allocate(umpp_session * session, ump_k_allocate * params) -+{ -+ ump_dd_handle new_allocation; -+ new_allocation = ump_dd_allocate_64(params->size, params->alloc_flags, NULL, NULL, NULL); -+ -+ if (UMP_DD_INVALID_MEMORY_HANDLE != new_allocation) -+ { -+ umpp_session_memory_usage * tracker; -+ -+ tracker = kmalloc(sizeof(*tracker), GFP_KERNEL | __GFP_HARDWALL); -+ if (NULL != tracker) -+ { -+ /* update the return struct with the new ID */ -+ params->secure_id = ump_dd_secure_id_get(new_allocation); -+ -+ tracker->mem = new_allocation; -+ tracker->id = params->secure_id; -+ atomic_set(&tracker->process_usage_count, 1); -+ -+ /* link it into the session in-use list */ -+ mutex_lock(&session->session_lock); -+ list_add(&tracker->link, &session->memory_usage); -+ mutex_unlock(&session->session_lock); -+ -+ return 0; -+ } -+ ump_dd_release(new_allocation); -+ } -+ -+ printk(KERN_WARNING "UMP: Allocation FAILED\n"); -+ return -ENOMEM; -+} -+ -+static int do_ump_dd_retain(umpp_session * session, ump_k_retain * params) -+{ -+ umpp_session_memory_usage * it; -+ -+ mutex_lock(&session->session_lock); -+ -+ /* try to find it on the session usage list */ -+ list_for_each_entry(it, &session->memory_usage, link) -+ { -+ if (it->id == params->secure_id) -+ { -+ /* found to already be in use */ -+ /* check for overflow */ -+ while(1) -+ { -+ int refcnt = atomic_read(&it->process_usage_count); -+ if (refcnt + 1 > 0) -+ { -+ /* add a process local ref */ -+ if(atomic_cmpxchg(&it->process_usage_count, refcnt, refcnt + 1) == refcnt) -+ { -+ mutex_unlock(&session->session_lock); -+ return 0; -+ } -+ } -+ else -+ { -+ /* maximum usage cap reached */ -+ mutex_unlock(&session->session_lock); -+ return -EBUSY; -+ } -+ } -+ } -+ } -+ /* try to look it up globally */ -+ -+ it = kmalloc(sizeof(*it), GFP_KERNEL); -+ -+ if (NULL != it) -+ { -+ it->mem = ump_dd_from_secure_id(params->secure_id); -+ if (UMP_DD_INVALID_MEMORY_HANDLE != it->mem) -+ { -+ /* found, add it to the session usage list */ -+ it->id = params->secure_id; -+ atomic_set(&it->process_usage_count, 1); -+ list_add(&it->link, &session->memory_usage); -+ } -+ else -+ { -+ /* not found */ -+ kfree(it); -+ it = NULL; -+ } -+ } -+ -+ mutex_unlock(&session->session_lock); -+ -+ return (NULL != it) ? 0 : -ENODEV; -+} -+ -+ -+static int do_ump_dd_release(umpp_session * session, ump_k_release * params) -+{ -+ umpp_session_memory_usage * it; -+ int result = -ENODEV; -+ -+ mutex_lock(&session->session_lock); -+ -+ /* only do a release if found on the session list */ -+ list_for_each_entry(it, &session->memory_usage, link) -+ { -+ if (it->id == params->secure_id) -+ { -+ /* found, a valid call */ -+ result = 0; -+ -+ if (0 == atomic_sub_return(1, &it->process_usage_count)) -+ { -+ /* last ref in this process remove from the usage list and remove the underlying ref */ -+ list_del(&it->link); -+ ump_dd_release(it->mem); -+ kfree(it); -+ } -+ -+ break; -+ } -+ } -+ mutex_unlock(&session->session_lock); -+ -+ return result; -+} -+ -+static int do_ump_dd_sizequery(umpp_session * session, ump_k_sizequery * params) -+{ -+ umpp_session_memory_usage * it; -+ int result = -ENODEV; -+ -+ mutex_lock(&session->session_lock); -+ -+ /* only valid if found on the session list */ -+ list_for_each_entry(it, &session->memory_usage, link) -+ { -+ if (it->id == params->secure_id) -+ { -+ /* found, a valid call */ -+ params->size = ump_dd_size_get_64(it->mem); -+ result = 0; -+ break; -+ } -+ -+ } -+ mutex_unlock(&session->session_lock); -+ -+ return result; -+} -+ -+static int do_ump_dd_allocation_flags_get(umpp_session * session, ump_k_allocation_flags * params) -+{ -+ umpp_session_memory_usage * it; -+ int result = -ENODEV; -+ -+ mutex_lock(&session->session_lock); -+ -+ /* only valid if found on the session list */ -+ list_for_each_entry(it, &session->memory_usage, link) -+ { -+ if (it->id == params->secure_id) -+ { -+ /* found, a valid call */ -+ params->alloc_flags = ump_dd_allocation_flags_get(it->mem); -+ result = 0; -+ break; -+ } -+ -+ } -+ mutex_unlock(&session->session_lock); -+ -+ return result; -+} -+ -+static int do_ump_dd_msync_now(umpp_session * session, ump_k_msync * params) -+{ -+ umpp_session_memory_usage * it; -+ int result = -ENODEV; -+ -+ mutex_lock(&session->session_lock); -+ -+ /* only valid if found on the session list */ -+ list_for_each_entry(it, &session->memory_usage, link) -+ { -+ if (it->id == params->secure_id) -+ { -+ /* found, do the cache op */ -+#ifdef CONFIG_COMPAT -+ if (is_compat_task()) -+ { -+ umpp_dd_cpu_msync_now(it->mem, params->cache_operation, compat_ptr(params->mapped_ptr.compat_value), params->size); -+ result = 0; -+ } -+ else -+ { -+#endif -+ umpp_dd_cpu_msync_now(it->mem, params->cache_operation, params->mapped_ptr.value, params->size); -+ result = 0; -+#ifdef CONFIG_COMPAT -+ } -+#endif -+ break; -+ } -+ } -+ mutex_unlock(&session->session_lock); -+ -+ return result; -+} -+ -+ -+void umpp_import_handlers_init(umpp_session * session) -+{ -+ int i; -+ mutex_lock(&import_list_lock); -+ for ( i = 1; i < UMPP_EXTERNAL_MEM_COUNT; i++ ) -+ { -+ if (import_handlers[i]) -+ { -+ import_handlers[i]->session_begin(&session->import_handler_data[i]); -+ /* It is OK if session_begin returned an error. -+ * We won't do any import calls if so */ -+ } -+ } -+ mutex_unlock(&import_list_lock); -+} -+ -+void umpp_import_handlers_term(umpp_session * session) -+{ -+ int i; -+ mutex_lock(&import_list_lock); -+ for ( i = 1; i < UMPP_EXTERNAL_MEM_COUNT; i++ ) -+ { -+ /* only call if session_begin succeeded */ -+ if (session->import_handler_data[i] != NULL) -+ { -+ /* if session_beging succeeded the handler -+ * should not have unregistered with us */ -+ BUG_ON(!import_handlers[i]); -+ import_handlers[i]->session_end(session->import_handler_data[i]); -+ session->import_handler_data[i] = NULL; -+ } -+ } -+ mutex_unlock(&import_list_lock); -+} -+ -+int ump_import_module_register(enum ump_external_memory_type type, struct ump_import_handler * handler) -+{ -+ int res = -EEXIST; -+ -+ /* validate input */ -+ BUG_ON(type == 0 || type >= UMPP_EXTERNAL_MEM_COUNT); -+ BUG_ON(!handler); -+ BUG_ON(!handler->linux_module); -+ BUG_ON(!handler->session_begin); -+ BUG_ON(!handler->session_end); -+ BUG_ON(!handler->import); -+ -+ mutex_lock(&import_list_lock); -+ -+ if (!import_handlers[type]) -+ { -+ import_handlers[type] = handler; -+ res = 0; -+ } -+ -+ mutex_unlock(&import_list_lock); -+ -+ return res; -+} -+ -+void ump_import_module_unregister(enum ump_external_memory_type type) -+{ -+ BUG_ON(type == 0 || type >= UMPP_EXTERNAL_MEM_COUNT); -+ -+ mutex_lock(&import_list_lock); -+ /* an error to call this if ump_import_module_register didn't succeed */ -+ BUG_ON(!import_handlers[type]); -+ import_handlers[type] = NULL; -+ mutex_unlock(&import_list_lock); -+} -+ -+static struct ump_import_handler * import_handler_get(unsigned int type_id) -+{ -+ enum ump_external_memory_type type; -+ struct ump_import_handler * handler; -+ -+ /* validate and convert input */ -+ /* handle bad data here, not just BUG_ON */ -+ if (type_id == 0 || type_id >= UMPP_EXTERNAL_MEM_COUNT) -+ return NULL; -+ -+ type = (enum ump_external_memory_type)type_id; -+ -+ /* find the handler */ -+ mutex_lock(&import_list_lock); -+ -+ handler = import_handlers[type]; -+ -+ if (handler) -+ { -+ if (!try_module_get(handler->linux_module)) -+ { -+ handler = NULL; -+ } -+ } -+ -+ mutex_unlock(&import_list_lock); -+ -+ return handler; -+} -+ -+static void import_handler_put(struct ump_import_handler * handler) -+{ -+ module_put(handler->linux_module); -+} -+ -+static int do_ump_dd_import(umpp_session * session, ump_k_import * params) -+{ -+ ump_dd_handle new_allocation = UMP_DD_INVALID_MEMORY_HANDLE; -+ struct ump_import_handler * handler; -+ -+ handler = import_handler_get(params->type); -+ -+ if (handler) -+ { -+ /* try late binding if not already bound */ -+ if (!session->import_handler_data[params->type]) -+ { -+ handler->session_begin(&session->import_handler_data[params->type]); -+ } -+ -+ /* do we have a bound session? */ -+ if (session->import_handler_data[params->type]) -+ { -+ new_allocation = handler->import( session->import_handler_data[params->type], -+ params->phandle.value, -+ params->alloc_flags); -+ } -+ -+ /* done with the handler */ -+ import_handler_put(handler); -+ } -+ -+ /* did the import succeed? */ -+ if (UMP_DD_INVALID_MEMORY_HANDLE != new_allocation) -+ { -+ umpp_session_memory_usage * tracker; -+ -+ tracker = kmalloc(sizeof(*tracker), GFP_KERNEL | __GFP_HARDWALL); -+ if (NULL != tracker) -+ { -+ /* update the return struct with the new ID */ -+ params->secure_id = ump_dd_secure_id_get(new_allocation); -+ -+ tracker->mem = new_allocation; -+ tracker->id = params->secure_id; -+ atomic_set(&tracker->process_usage_count, 1); -+ -+ /* link it into the session in-use list */ -+ mutex_lock(&session->session_lock); -+ list_add(&tracker->link, &session->memory_usage); -+ mutex_unlock(&session->session_lock); -+ -+ return 0; -+ } -+ ump_dd_release(new_allocation); -+ } -+ -+ return -ENOMEM; -+ -+} -+ -+#ifdef HAVE_UNLOCKED_IOCTL -+static long umpp_linux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -+#else -+static int umpp_linux_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+#endif -+{ -+ int ret; -+ uint64_t msg[(UMP_CALL_MAX_SIZE+7)>>3]; /* alignment fixup */ -+ uint32_t size = _IOC_SIZE(cmd); -+ struct umpp_session *session = filp->private_data; -+ -+#ifndef HAVE_UNLOCKED_IOCTL -+ (void)inode; /* unused arg */ -+#endif -+ -+ /* -+ * extract the type and number bitfields, and don't decode -+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() -+ */ -+ if (_IOC_TYPE(cmd) != UMP_IOC_MAGIC) -+ { -+ return -ENOTTY; -+ -+ } -+ if (_IOC_NR(cmd) > UMP_IOC_MAXNR) -+ { -+ return -ENOTTY; -+ } -+ -+ switch(cmd) -+ { -+ case UMP_FUNC_ALLOCATE: -+ if (size != sizeof(ump_k_allocate)) -+ { -+ return -ENOTTY; -+ } -+ if (copy_from_user(&msg, (void __user *)arg, size)) -+ { -+ return -EFAULT; -+ } -+ ret = do_ump_dd_allocate(session, (ump_k_allocate *)&msg); -+ if (ret) -+ { -+ return ret; -+ } -+ if (copy_to_user((void *)arg, &msg, size)) -+ { -+ return -EFAULT; -+ } -+ return 0; -+ case UMP_FUNC_SIZEQUERY: -+ if (size != sizeof(ump_k_sizequery)) -+ { -+ return -ENOTTY; -+ } -+ if (copy_from_user(&msg, (void __user *)arg, size)) -+ { -+ return -EFAULT; -+ } -+ ret = do_ump_dd_sizequery(session,(ump_k_sizequery*) &msg); -+ if (ret) -+ { -+ return ret; -+ } -+ if (copy_to_user((void *)arg, &msg, size)) -+ { -+ return -EFAULT; -+ } -+ return 0; -+ case UMP_FUNC_MSYNC: -+ if (size != sizeof(ump_k_msync)) -+ { -+ return -ENOTTY; -+ } -+ if (copy_from_user(&msg, (void __user *)arg, size)) -+ { -+ return -EFAULT; -+ } -+ ret = do_ump_dd_msync_now(session,(ump_k_msync*) &msg); -+ if (ret) -+ { -+ return ret; -+ } -+ if (copy_to_user((void *)arg, &msg, size)) -+ { -+ return -EFAULT; -+ } -+ return 0; -+ case UMP_FUNC_IMPORT: -+ if (size != sizeof(ump_k_import)) -+ { -+ return -ENOTTY; -+ } -+ if (copy_from_user(&msg, (void __user*)arg, size)) -+ { -+ return -EFAULT; -+ } -+ ret = do_ump_dd_import(session, (ump_k_import*) &msg); -+ if (ret) -+ { -+ return ret; -+ } -+ if (copy_to_user((void *)arg, &msg, size)) -+ { -+ return -EFAULT; -+ } -+ return 0; -+ /* used only by v1 API */ -+ case UMP_FUNC_ALLOCATION_FLAGS_GET: -+ if (size != sizeof(ump_k_allocation_flags)) -+ { -+ return -ENOTTY; -+ } -+ if (copy_from_user(&msg, (void __user *)arg, size)) -+ { -+ return -EFAULT; -+ } -+ ret = do_ump_dd_allocation_flags_get(session,(ump_k_allocation_flags*) &msg); -+ if (ret) -+ { -+ return ret; -+ } -+ if (copy_to_user((void *)arg, &msg, size)) -+ { -+ return -EFAULT; -+ } -+ return 0; -+ case UMP_FUNC_RETAIN: -+ if (size != sizeof(ump_k_retain)) -+ { -+ return -ENOTTY; -+ } -+ if (copy_from_user(&msg, (void __user *)arg, size)) -+ { -+ return -EFAULT; -+ } -+ ret = do_ump_dd_retain(session,(ump_k_retain*) &msg); -+ if (ret) -+ { -+ return ret; -+ } -+ return 0; -+ case UMP_FUNC_RELEASE: -+ if (size != sizeof(ump_k_release)) -+ { -+ return -ENOTTY; -+ } -+ if (copy_from_user(&msg, (void __user *)arg, size)) -+ { -+ return -EFAULT; -+ } -+ ret = do_ump_dd_release(session,(ump_k_release*) &msg); -+ if (ret) -+ { -+ return ret; -+ } -+ return 0; -+ default: -+ /* not ours */ -+ return -ENOTTY; -+ } -+ /*redundant below*/ -+ return -ENOTTY; -+} -+ -+ -+/* Export UMP kernel space API functions */ -+EXPORT_SYMBOL(ump_dd_allocate_64); -+EXPORT_SYMBOL(ump_dd_allocation_flags_get); -+EXPORT_SYMBOL(ump_dd_secure_id_get); -+EXPORT_SYMBOL(ump_dd_from_secure_id); -+EXPORT_SYMBOL(ump_dd_phys_blocks_get_64); -+EXPORT_SYMBOL(ump_dd_size_get_64); -+EXPORT_SYMBOL(ump_dd_retain); -+EXPORT_SYMBOL(ump_dd_release); -+EXPORT_SYMBOL(ump_dd_create_from_phys_blocks_64); -+#ifdef CONFIG_KDS -+EXPORT_SYMBOL(ump_dd_kds_resource_get); -+#endif -+ -+/* import API */ -+EXPORT_SYMBOL(ump_import_module_register); -+EXPORT_SYMBOL(ump_import_module_unregister); -+ -+ -+ -+/* V1 API */ -+EXPORT_SYMBOL(ump_dd_handle_create_from_secure_id); -+EXPORT_SYMBOL(ump_dd_phys_block_count_get); -+EXPORT_SYMBOL(ump_dd_phys_block_get); -+EXPORT_SYMBOL(ump_dd_phys_blocks_get); -+EXPORT_SYMBOL(ump_dd_size_get); -+EXPORT_SYMBOL(ump_dd_reference_add); -+EXPORT_SYMBOL(ump_dd_reference_release); -+EXPORT_SYMBOL(ump_dd_handle_create_from_phys_blocks); -+ -+ -+/* Setup init and exit functions for this module */ -+module_init(umpp_linux_initialize_module); -+module_exit(umpp_linux_cleanup_module); -+ -+/* And some module informatio */ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("ARM Ltd."); -+MODULE_VERSION(UMP_REV_STRING); -diff --git a/drivers/base/ump/src/linux/ump_kernel_linux_mem.c b/drivers/base/ump/src/linux/ump_kernel_linux_mem.c -new file mode 100644 -index 0000000..9186dd0 ---- /dev/null -+++ b/drivers/base/ump/src/linux/ump_kernel_linux_mem.c -@@ -0,0 +1,250 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013, 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+ -+#include -+#include /* kernel module definitions */ -+#include /* file system operations */ -+#include /* character device definitions */ -+#include /* request_mem_region */ -+#include /* memory mananger definitions */ -+#include -+#include /*kmap*/ -+ -+#include /* is_compat_task */ -+ -+#include -+#include -+#include -+ -+static void umpp_vm_close(struct vm_area_struct *vma) -+{ -+ umpp_cpu_mapping * mapping; -+ umpp_session * session; -+ ump_dd_handle handle; -+ -+ mapping = (umpp_cpu_mapping*)vma->vm_private_data; -+ UMP_ASSERT(mapping); -+ -+ session = mapping->session; -+ handle = mapping->handle; -+ -+ umpp_dd_remove_cpu_mapping(mapping->handle, mapping); /* will free the mapping object */ -+ ump_dd_release(handle); -+} -+ -+ -+static const struct vm_operations_struct umpp_vm_ops = { -+ .close = umpp_vm_close -+}; -+ -+int umpp_phys_commit(umpp_allocation * alloc) -+{ -+ uint64_t i; -+ -+ /* round up to a page boundary */ -+ alloc->size = (alloc->size + PAGE_SIZE - 1) & ~((uint64_t)PAGE_SIZE-1) ; -+ /* calculate number of pages */ -+ alloc->blocksCount = alloc->size >> PAGE_SHIFT; -+ -+ if( (sizeof(ump_dd_physical_block_64) * alloc->blocksCount) > ((size_t)-1)) -+ { -+ printk(KERN_WARNING "UMP: umpp_phys_commit - trying to allocate more than possible\n"); -+ return -ENOMEM; -+ } -+ -+ alloc->block_array = kmalloc(sizeof(ump_dd_physical_block_64) * alloc->blocksCount, __GFP_HARDWALL | GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN); -+ if (NULL == alloc->block_array) -+ { -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < alloc->blocksCount; i++) -+ { -+ void * mp; -+ struct page * page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY | __GFP_NOWARN | __GFP_COLD); -+ if (NULL == page) -+ { -+ break; -+ } -+ -+ alloc->block_array[i].addr = PFN_PHYS(page_to_pfn(page)); -+ alloc->block_array[i].size = PAGE_SIZE; -+ -+ mp = kmap(page); -+ if (NULL == mp) -+ { -+ __free_page(page); -+ break; -+ } -+ -+ memset(mp, 0x00, PAGE_SIZE); /* instead of __GFP_ZERO, so we can do cache maintenance */ -+ ump_sync_to_memory(PFN_PHYS(page_to_pfn(page)), mp, PAGE_SIZE); -+ kunmap(page); -+ } -+ -+ if (i == alloc->blocksCount) -+ { -+ return 0; -+ } -+ else -+ { -+ uint64_t j; -+ for (j = 0; j < i; j++) -+ { -+ struct page * page; -+ page = pfn_to_page(alloc->block_array[j].addr >> PAGE_SHIFT); -+ __free_page(page); -+ } -+ -+ kfree(alloc->block_array); -+ -+ return -ENOMEM; -+ } -+} -+ -+void umpp_phys_free(umpp_allocation * alloc) -+{ -+ uint64_t i; -+ -+ for (i = 0; i < alloc->blocksCount; i++) -+ { -+ __free_page(pfn_to_page(alloc->block_array[i].addr >> PAGE_SHIFT)); -+ } -+ -+ kfree(alloc->block_array); -+} -+ -+int umpp_linux_mmap(struct file * filp, struct vm_area_struct * vma) -+{ -+ ump_secure_id id; -+ ump_dd_handle h; -+ size_t offset; -+ int err = -EINVAL; -+ size_t length = vma->vm_end - vma->vm_start; -+ -+ umpp_cpu_mapping * map = NULL; -+ umpp_session *session = filp->private_data; -+ -+ if ( 0 == length ) -+ { -+ return -EINVAL; -+ } -+ -+ map = kzalloc(sizeof(*map), GFP_KERNEL); -+ if (NULL == map) -+ { -+ WARN_ON(1); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ /* unpack our arg */ -+#if defined CONFIG_64BIT && CONFIG_64BIT -+ if (is_compat_task()) -+ { -+#endif -+ id = vma->vm_pgoff >> UMP_LINUX_OFFSET_BITS_32; -+ offset = vma->vm_pgoff & UMP_LINUX_OFFSET_MASK_32; -+#if defined CONFIG_64BIT && CONFIG_64BIT -+ } -+ else -+ { -+ id = vma->vm_pgoff >> UMP_LINUX_OFFSET_BITS_64; -+ offset = vma->vm_pgoff & UMP_LINUX_OFFSET_MASK_64; -+ } -+#endif -+ -+ h = ump_dd_from_secure_id(id); -+ if (UMP_DD_INVALID_MEMORY_HANDLE != h) -+ { -+ uint64_t i; -+ uint64_t block_idx; -+ uint64_t block_offset; -+ uint64_t paddr; -+ umpp_allocation * alloc; -+ uint64_t last_byte; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)) -+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_IO | VM_MIXEDMAP | VM_DONTDUMP; -+#else -+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_IO | VM_MIXEDMAP; -+#endif -+ vma->vm_ops = &umpp_vm_ops; -+ vma->vm_private_data = map; -+ -+ alloc = (umpp_allocation*)h; -+ -+ if( (alloc->flags & UMP_CONSTRAINT_UNCACHED) != 0) -+ { -+ /* cache disabled flag set, disable caching for cpu mappings */ -+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); -+ } -+ -+ last_byte = length + (offset << PAGE_SHIFT) - 1; -+ if (last_byte >= alloc->size || last_byte < (offset << PAGE_SHIFT)) -+ { -+ goto err_out; -+ } -+ -+ if (umpp_dd_find_start_block(alloc, offset << PAGE_SHIFT, &block_idx, &block_offset)) -+ { -+ goto err_out; -+ } -+ -+ paddr = alloc->block_array[block_idx].addr + block_offset; -+ -+ for (i = 0; i < (length >> PAGE_SHIFT); i++) -+ { -+ /* check if we've overrrun the current block, if so move to the next block */ -+ if (paddr >= (alloc->block_array[block_idx].addr + alloc->block_array[block_idx].size)) -+ { -+ block_idx++; -+ UMP_ASSERT(block_idx < alloc->blocksCount); -+ paddr = alloc->block_array[block_idx].addr; -+ } -+ -+ err = vm_insert_mixed(vma, vma->vm_start + (i << PAGE_SHIFT), paddr >> PAGE_SHIFT); -+ paddr += PAGE_SIZE; -+ } -+ -+ map->vaddr_start = (void*)vma->vm_start; -+ map->nr_pages = length >> PAGE_SHIFT; -+ map->page_off = offset; -+ map->handle = h; -+ map->session = session; -+ -+ umpp_dd_add_cpu_mapping(h, map); -+ -+ return 0; -+ -+ err_out: -+ -+ ump_dd_release(h); -+ } -+ -+ kfree(map); -+ -+out: -+ -+ return err; -+} -+ -diff --git a/drivers/base/ump/src/linux/ump_kernel_linux_mem.h b/drivers/base/ump/src/linux/ump_kernel_linux_mem.h -new file mode 100644 -index 0000000..4fbf3b2 ---- /dev/null -+++ b/drivers/base/ump/src/linux/ump_kernel_linux_mem.h -@@ -0,0 +1,26 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2011, 2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _UMP_KERNEL_LINUX_MEM_H_ -+#define _UMP_KERNEL_LINUX_MEM_H_ -+ -+ -+int umpp_linux_mmap(struct file * filp, struct vm_area_struct * vma); -+ -+#endif /* _UMP_KERNEL_LINUX_MEM_H_ */ -diff --git a/drivers/base/ump/src/sconscript b/drivers/base/ump/src/sconscript -new file mode 100644 -index 0000000..b34d499 ---- /dev/null -+++ b/drivers/base/ump/src/sconscript -@@ -0,0 +1,46 @@ -+# -+# (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+Import('env') -+ -+# Clone the environment so changes don't affect other build files -+env_ump = env.Clone() -+ -+# Source files required for UMP. -+ump_src = [ -+ Glob('common/*.c'), -+ Glob('imports/*/*.c'), -+ Glob('linux/*.c'), -+] -+ -+make_args = env_ump.kernel_get_config_defines(ret_list = True) + [ -+ 'PLATFORM=%s' % env_ump['platform'], -+ 'MALI_UNIT_TEST=%s' % env_ump['unit'], -+] -+ -+mod = env_ump.BuildKernelModule('$STATIC_LIB_PATH/ump.ko', ump_src, -+ make_args = make_args) -+env_ump.KernelObjTarget('ump', mod) -+ -+# Add a dependency on kds.ko only when the build is not Android -+# Android uses sync_pt instead of Midgard KDS to achieve KDS functionality -+# Only necessary when KDS is not built into the kernel. -+# -+if env_ump['os'] != 'android': -+ if not env_ump.KernelConfigEnabled('CONFIG_KDS'): -+ env_ump.Depends(mod, '$STATIC_LIB_PATH/kds.ko') -+ -+SConscript( 'imports/sconscript' ) -+ -diff --git a/drivers/base/ump/src/ump_arch.h b/drivers/base/ump/src/ump_arch.h -new file mode 100644 -index 0000000..2303d56 ---- /dev/null -+++ b/drivers/base/ump/src/ump_arch.h -@@ -0,0 +1,42 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2011, 2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _UMP_ARCH_H_ -+#define _UMP_ARCH_H_ -+ -+#include -+ -+/** -+ * Device specific setup. -+ * Called by the UMP core code to to host OS/device specific setup. -+ * Typical use case is device node creation for talking to user space. -+ * @return UMP_OK on success, any other value on failure -+ */ -+extern ump_result umpp_device_initialize(void); -+ -+/** -+ * Device specific teardown. -+ * Undo any things done by ump_device_initialize. -+ */ -+extern void umpp_device_terminate(void); -+ -+extern int umpp_phys_commit(umpp_allocation * alloc); -+extern void umpp_phys_free(umpp_allocation * alloc); -+ -+#endif /* _UMP_ARCH_H_ */ -diff --git a/drivers/base/ump/ump_ref_drv.h b/drivers/base/ump/ump_ref_drv.h -new file mode 100644 -index 0000000..9a265fe ---- /dev/null -+++ b/drivers/base/ump/ump_ref_drv.h -@@ -0,0 +1,33 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file ump_ref_drv.h -+ * -+ * This file contains the link to user space part of the UMP API for usage by MALI 400 gralloc. -+ * -+ */ -+ -+#ifndef _UMP_REF_DRV_H_ -+#define _UMP_REF_DRV_H_ -+ -+#include -+ -+ -+#endif /* _UMP_REF_DRV_H_ */ -diff --git a/drivers/gpu/arm/midgard/Kbuild b/drivers/gpu/arm/midgard/Kbuild -new file mode 100644 -index 0000000..8da1e5e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/Kbuild -@@ -0,0 +1,218 @@ -+# -+# (C) COPYRIGHT 2012-2016, 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+# Driver version string which is returned to userspace via an ioctl -+MALI_RELEASE_NAME ?= "r19p0-01rel0" -+ -+# Paths required for build -+KBASE_PATH = $(src) -+KBASE_PLATFORM_PATH = $(KBASE_PATH)/platform_dummy -+UMP_PATH = $(src)/../../../base -+ -+ifeq ($(CONFIG_MALI_ERROR_INJECTION),y) -+MALI_ERROR_INJECT_ON = 1 -+endif -+ -+# Set up defaults if not defined by build system -+MALI_CUSTOMER_RELEASE ?= 1 -+MALI_UNIT_TEST ?= 0 -+MALI_KERNEL_TEST_API ?= 0 -+MALI_ERROR_INJECT_ON ?= 0 -+MALI_MOCK_TEST ?= 0 -+MALI_COVERAGE ?= 0 -+MALI_INSTRUMENTATION_LEVEL ?= 0 -+# This workaround is for what seems to be a compiler bug we observed in -+# GCC 4.7 on AOSP 4.3. The bug caused an intermittent failure compiling -+# the "_Pragma" syntax, where an error message is returned: -+# -+# "internal compiler error: unspellable token PRAGMA" -+# -+# This regression has thus far only been seen on the GCC 4.7 compiler bundled -+# with AOSP 4.3.0. So this makefile, intended for in-tree kernel builds -+# which are not known to be used with AOSP, is hardcoded to disable the -+# workaround, i.e. set the define to 0. -+MALI_GCC_WORKAROUND_MIDCOM_4598 ?= 0 -+ -+# Set up our defines, which will be passed to gcc -+DEFINES = \ -+ -DMALI_CUSTOMER_RELEASE=$(MALI_CUSTOMER_RELEASE) \ -+ -DMALI_KERNEL_TEST_API=$(MALI_KERNEL_TEST_API) \ -+ -DMALI_UNIT_TEST=$(MALI_UNIT_TEST) \ -+ -DMALI_ERROR_INJECT_ON=$(MALI_ERROR_INJECT_ON) \ -+ -DMALI_MOCK_TEST=$(MALI_MOCK_TEST) \ -+ -DMALI_COVERAGE=$(MALI_COVERAGE) \ -+ -DMALI_INSTRUMENTATION_LEVEL=$(MALI_INSTRUMENTATION_LEVEL) \ -+ -DMALI_RELEASE_NAME=\"$(MALI_RELEASE_NAME)\" \ -+ -DMALI_GCC_WORKAROUND_MIDCOM_4598=$(MALI_GCC_WORKAROUND_MIDCOM_4598) -+ -+ifeq ($(KBUILD_EXTMOD),) -+# in-tree -+DEFINES +=-DMALI_KBASE_THIRDPARTY_PATH=../../$(src)/platform/$(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME) -+else -+# out-of-tree -+DEFINES +=-DMALI_KBASE_THIRDPARTY_PATH=$(src)/platform/$(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME) -+endif -+ -+DEFINES += -I$(srctree)/drivers/staging/android -+ -+# Use our defines when compiling -+ccflags-y += $(DEFINES) -I$(KBASE_PATH) -I$(KBASE_PLATFORM_PATH) -I$(UMP_PATH) -I$(srctree)/include/linux -+subdir-ccflags-y += $(DEFINES) -I$(KBASE_PATH) -I$(KBASE_PLATFORM_PATH) -I$(OSK_PATH) -I$(UMP_PATH) -I$(srctree)/include/linux -+ -+SRC := \ -+ mali_kbase_device.c \ -+ mali_kbase_cache_policy.c \ -+ mali_kbase_mem.c \ -+ mali_kbase_mmu.c \ -+ mali_kbase_ctx_sched.c \ -+ mali_kbase_jd.c \ -+ mali_kbase_jd_debugfs.c \ -+ mali_kbase_jm.c \ -+ mali_kbase_gpuprops.c \ -+ mali_kbase_js.c \ -+ mali_kbase_js_ctx_attr.c \ -+ mali_kbase_event.c \ -+ mali_kbase_context.c \ -+ mali_kbase_pm.c \ -+ mali_kbase_config.c \ -+ mali_kbase_vinstr.c \ -+ mali_kbase_softjobs.c \ -+ mali_kbase_10969_workaround.c \ -+ mali_kbase_hw.c \ -+ mali_kbase_utility.c \ -+ mali_kbase_debug.c \ -+ mali_kbase_trace_timeline.c \ -+ mali_kbase_gpu_memory_debugfs.c \ -+ mali_kbase_mem_linux.c \ -+ mali_kbase_core_linux.c \ -+ mali_kbase_replay.c \ -+ mali_kbase_mem_profile_debugfs.c \ -+ mali_kbase_mmu_mode_lpae.c \ -+ mali_kbase_mmu_mode_aarch64.c \ -+ mali_kbase_disjoint_events.c \ -+ mali_kbase_gator_api.c \ -+ mali_kbase_debug_mem_view.c \ -+ mali_kbase_debug_job_fault.c \ -+ mali_kbase_smc.c \ -+ mali_kbase_mem_pool.c \ -+ mali_kbase_mem_pool_debugfs.c \ -+ mali_kbase_tlstream.c \ -+ mali_kbase_strings.c \ -+ mali_kbase_as_fault_debugfs.c \ -+ mali_kbase_regs_history_debugfs.c -+ -+ -+ -+ -+ifeq ($(MALI_UNIT_TEST),1) -+ SRC += mali_kbase_tlstream_test.c -+endif -+ -+ifeq ($(MALI_CUSTOMER_RELEASE),0) -+ SRC += mali_kbase_regs_dump_debugfs.c -+endif -+ -+ -+ccflags-y += -I$(KBASE_PATH) -+ -+ifeq ($(CONFIG_MALI_PLATFORM_FAKE),y) -+ SRC += mali_kbase_platform_fake.c -+ -+ ifeq ($(CONFIG_MALI_PLATFORM_VEXPRESS),y) -+ SRC += platform/vexpress/mali_kbase_config_vexpress.c \ -+ platform/vexpress/mali_kbase_cpu_vexpress.c -+ ccflags-y += -I$(src)/platform/vexpress -+ endif -+ -+ ifeq ($(CONFIG_MALI_PLATFORM_RTSM_VE),y) -+ SRC += platform/rtsm_ve/mali_kbase_config_vexpress.c -+ ccflags-y += -I$(src)/platform/rtsm_ve -+ endif -+ -+ ifeq ($(CONFIG_MALI_PLATFORM_VEXPRESS_1XV7_A57),y) -+ SRC += platform/vexpress_1xv7_a57/mali_kbase_config_vexpress.c -+ ccflags-y += -I$(src)/platform/vexpress_1xv7_a57 -+ endif -+ -+ ifeq ($(CONFIG_MALI_PLATFORM_VEXPRESS_6XVIRTEX7_10MHZ),y) -+ SRC += platform/vexpress_6xvirtex7_10mhz/mali_kbase_config_vexpress.c \ -+ platform/vexpress_6xvirtex7_10mhz/mali_kbase_cpu_vexpress.c -+ ccflags-y += -I$(src)/platform/vexpress_6xvirtex7_10mhz -+ endif -+endif # CONFIG_MALI_PLATFORM_FAKE=y -+ -+# Tell the Linux build system from which .o file to create the kernel module -+obj-$(CONFIG_MALI_MIDGARD) += mali_kbase.o -+ -+# Tell the Linux build system to enable building of our .c files -+mali_kbase-y := $(SRC:.c=.o) -+ -+ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY),y) -+ # Kconfig passes in the name with quotes for in-tree builds - remove them. -+ platform_name := $(shell echo $(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME)) -+ MALI_PLATFORM_THIRDPARTY_DIR := platform/$(platform_name) -+ ccflags-y += -I$(src)/$(MALI_PLATFORM_THIRDPARTY_DIR) -+ include $(src)/$(MALI_PLATFORM_THIRDPARTY_DIR)/Kbuild -+endif -+ -+ifeq ($(CONFIG_MALI_DEVFREQ),y) -+ ifeq ($(CONFIG_DEVFREQ_THERMAL),y) -+ include $(src)/ipa/Kbuild -+ endif -+endif -+ -+mali_kbase-$(CONFIG_MALI_DMA_FENCE) += \ -+ mali_kbase_dma_fence.o \ -+ mali_kbase_fence.o -+mali_kbase-$(CONFIG_SYNC) += \ -+ mali_kbase_sync_android.o \ -+ mali_kbase_sync_common.o -+mali_kbase-$(CONFIG_SYNC_FILE) += \ -+ mali_kbase_sync_file.o \ -+ mali_kbase_sync_common.o \ -+ mali_kbase_fence.o -+ -+MALI_BACKEND_PATH ?= backend -+CONFIG_MALI_BACKEND ?= gpu -+CONFIG_MALI_BACKEND_REAL ?= $(CONFIG_MALI_BACKEND) -+ -+ifeq ($(MALI_MOCK_TEST),1) -+ifeq ($(CONFIG_MALI_BACKEND_REAL),gpu) -+# Test functionality -+mali_kbase-y += tests/internal/src/mock/mali_kbase_pm_driver_mock.o -+endif -+endif -+ -+include $(src)/$(MALI_BACKEND_PATH)/$(CONFIG_MALI_BACKEND_REAL)/Kbuild -+mali_kbase-y += $(BACKEND:.c=.o) -+ -+ -+ccflags-y += -I$(src)/$(MALI_BACKEND_PATH)/$(CONFIG_MALI_BACKEND_REAL) -+subdir-ccflags-y += -I$(src)/$(MALI_BACKEND_PATH)/$(CONFIG_MALI_BACKEND_REAL) -+ -+# Default to devicetree platform if neither a fake platform or a thirdparty -+# platform is configured. -+ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY)$(CONFIG_MALI_PLATFORM_FAKE),) -+CONFIG_MALI_PLATFORM_DEVICETREE := y -+endif -+ -+mali_kbase-$(CONFIG_MALI_PLATFORM_DEVICETREE) += \ -+ platform/devicetree/mali_kbase_runtime_pm.o \ -+ platform/devicetree/mali_kbase_config_devicetree.o -+ccflags-$(CONFIG_MALI_PLATFORM_DEVICETREE) += -I$(src)/platform/devicetree -+ -+# For kutf and mali_kutf_irq_latency_test -+obj-$(CONFIG_MALI_KUTF) += tests/ -diff --git a/drivers/gpu/arm/midgard/Kconfig b/drivers/gpu/arm/midgard/Kconfig -new file mode 100644 -index 0000000..af91dd7 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/Kconfig -@@ -0,0 +1,258 @@ -+# -+# (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+menuconfig MALI_MIDGARD -+ tristate "Mali Midgard series support" -+ select GPU_TRACEPOINTS if ANDROID -+ default n -+ help -+ Enable this option to build support for a ARM Mali Midgard GPU. -+ -+ To compile this driver as a module, choose M here: -+ this will generate a single module, called mali_kbase. -+ -+config MALI_GATOR_SUPPORT -+ bool "Streamline support via Gator" -+ depends on MALI_MIDGARD -+ default n -+ help -+ Adds diagnostic support for use with the ARM Streamline Performance Analyzer. -+ You will need the Gator device driver already loaded before loading this driver when enabling -+ Streamline debug support. -+ This is a legacy interface required by older versions of Streamline. -+ -+config MALI_MIDGARD_DVFS -+ bool "Enable legacy DVFS" -+ depends on MALI_MIDGARD && !MALI_DEVFREQ && !MALI_PLATFORM_DEVICETREE -+ default n -+ help -+ Choose this option to enable legacy DVFS in the Mali Midgard DDK. -+ -+config MALI_MIDGARD_ENABLE_TRACE -+ bool "Enable kbase tracing" -+ depends on MALI_MIDGARD -+ default n -+ help -+ Enables tracing in kbase. Trace log available through -+ the "mali_trace" debugfs file, when the CONFIG_DEBUG_FS is enabled -+ -+config MALI_DEVFREQ -+ bool "devfreq support for Mali" -+ depends on MALI_MIDGARD && PM_DEVFREQ -+ help -+ Support devfreq for Mali. -+ -+ Using the devfreq framework and, by default, the simpleondemand -+ governor, the frequency of Mali will be dynamically selected from the -+ available OPPs. -+ -+config MALI_DMA_FENCE -+ bool "DMA_BUF fence support for Mali" -+ depends on MALI_MIDGARD && !KDS -+ default n -+ help -+ Support DMA_BUF fences for Mali. -+ -+ This option should only be enabled if KDS is not present and -+ the Linux Kernel has built in support for DMA_BUF fences. -+ -+# MALI_EXPERT configuration options -+ -+menuconfig MALI_EXPERT -+ depends on MALI_MIDGARD -+ bool "Enable Expert Settings" -+ default n -+ help -+ Enabling this option and modifying the default settings may produce a driver with performance or -+ other limitations. -+ -+config MALI_CORESTACK -+ bool "Support controlling power to the GPU core stack" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ Enabling this feature on supported GPUs will let the driver powering -+ on/off the GPU core stack independently without involving the Power -+ Domain Controller. This should only be enabled on platforms which -+ integration of the PDC to the Mali GPU is known to be problematic. -+ This feature is currently only supported on t-Six and t-HEx GPUs. -+ -+ If unsure, say N. -+ -+config MALI_PRFCNT_SET_SECONDARY -+ bool "Use secondary set of performance counters" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ Select this option to use secondary set of performance counters. Kernel -+ features that depend on an access to the primary set of counters may -+ become unavailable. Enabling this option will prevent power management -+ from working optimally and may cause instrumentation tools to return -+ bogus results. -+ -+ If unsure, say N. -+ -+config MALI_PLATFORM_FAKE -+ bool "Enable fake platform device support" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ When you start to work with the Mali Midgard series device driver the platform-specific code of -+ the Linux kernel for your platform may not be complete. In this situation the kernel device driver -+ supports creating the platform device outside of the Linux platform-specific code. -+ Enable this option if would like to use a platform device configuration from within the device driver. -+ -+choice -+ prompt "Platform configuration" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default MALI_PLATFORM_DEVICETREE -+ help -+ Select the SOC platform that contains a Mali Midgard GPU -+ -+config MALI_PLATFORM_DEVICETREE -+ bool "Device Tree platform" -+ depends on OF -+ help -+ Select this option to use Device Tree with the Mali driver. -+ -+ When using this option the Mali driver will get the details of the -+ GPU hardware from the Device Tree. This means that the same driver -+ binary can run on multiple platforms as long as all the GPU hardware -+ details are described in the device tree. -+ -+ Device Tree is the recommended method for the Mali driver platform -+ integration. -+ -+config MALI_PLATFORM_VEXPRESS -+ depends on ARCH_VEXPRESS && (ARCH_VEXPRESS_CA9X4 || ARCH_VEXPRESS_CA15X4) -+ bool "Versatile Express" -+config MALI_PLATFORM_VEXPRESS_VIRTEX7_40MHZ -+ depends on ARCH_VEXPRESS && (ARCH_VEXPRESS_CA9X4 || ARCH_VEXPRESS_CA15X4) -+ bool "Versatile Express w/Virtex7 @ 40Mhz" -+config MALI_PLATFORM_GOLDFISH -+ depends on ARCH_GOLDFISH -+ bool "Android Goldfish virtual CPU" -+config MALI_PLATFORM_PBX -+ depends on ARCH_REALVIEW && REALVIEW_EB_A9MP && MACH_REALVIEW_PBX -+ bool "Realview PBX-A9" -+config MALI_PLATFORM_THIRDPARTY -+ bool "Third Party Platform" -+endchoice -+ -+config MALI_PLATFORM_THIRDPARTY_NAME -+ depends on MALI_MIDGARD && MALI_PLATFORM_THIRDPARTY && MALI_EXPERT -+ string "Third party platform name" -+ help -+ Enter the name of a third party platform that is supported. The third part configuration -+ file must be in midgard/config/tpip/mali_kbase_config_xxx.c where xxx is the name -+ specified here. -+ -+config MALI_DEBUG -+ bool "Debug build" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ Select this option for increased checking and reporting of errors. -+ -+config MALI_FENCE_DEBUG -+ bool "Debug sync fence usage" -+ depends on MALI_MIDGARD && MALI_EXPERT && (SYNC || SYNC_FILE) -+ default y if MALI_DEBUG -+ help -+ Select this option to enable additional checking and reporting on the -+ use of sync fences in the Mali driver. -+ -+ This will add a 3s timeout to all sync fence waits in the Mali -+ driver, so that when work for Mali has been waiting on a sync fence -+ for a long time a debug message will be printed, detailing what fence -+ is causing the block, and which dependent Mali atoms are blocked as a -+ result of this. -+ -+ The timeout can be changed at runtime through the js_soft_timeout -+ device attribute, where the timeout is specified in milliseconds. -+ -+config MALI_NO_MALI -+ bool "No Mali" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ This can be used to test the driver in a simulated environment -+ whereby the hardware is not physically present. If the hardware is physically -+ present it will not be used. This can be used to test the majority of the -+ driver without needing actual hardware or for software benchmarking. -+ All calls to the simulated hardware will complete immediately as if the hardware -+ completed the task. -+ -+config MALI_ERROR_INJECT -+ bool "Error injection" -+ depends on MALI_MIDGARD && MALI_EXPERT && MALI_NO_MALI -+ default n -+ help -+ Enables insertion of errors to test module failure and recovery mechanisms. -+ -+config MALI_TRACE_TIMELINE -+ bool "Timeline tracing" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ Enables timeline tracing through the kernel tracepoint system. -+ -+config MALI_SYSTEM_TRACE -+ bool "Enable system event tracing support" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ Choose this option to enable system trace events for each -+ kbase event. This is typically used for debugging but has -+ minimal overhead when not in use. Enable only if you know what -+ you are doing. -+ -+config MALI_GPU_MMU_AARCH64 -+ bool "Use AArch64 page tables" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ Use AArch64 format page tables for the GPU instead of LPAE-style. -+ The two formats have the same functionality and performance but a -+ future GPU may deprecate or remove the legacy LPAE-style format. -+ -+ The LPAE-style format is supported on all Midgard and current Bifrost -+ GPUs. Enabling AArch64 format restricts the driver to only supporting -+ Bifrost GPUs. -+ -+ If in doubt, say N. -+ -+config MALI_2MB_ALLOC -+ bool "Attempt to allocate 2MB pages" -+ depends on MALI_MIDGARD && MALI_EXPERT -+ default n -+ help -+ Rather than allocating all GPU memory page-by-page, attempt to -+ allocate 2MB pages from the kernel. This reduces TLB pressure and -+ helps to prevent memory fragmentation. -+ -+ If in doubt, say N -+ -+config MALI_PWRSOFT_765 -+ bool "PWRSOFT-765 ticket" -+ default n -+ help -+ PWRSOFT-765 fixes devfreq cooling devices issues. However, they are -+ not merged in mainline kernel yet. So this define helps to guard those -+ parts of the code. -+ -+source "drivers/gpu/arm/midgard/platform/Kconfig" -+source "drivers/gpu/arm/midgard/tests/Kconfig" -diff --git a/drivers/gpu/arm/midgard/Makefile b/drivers/gpu/arm/midgard/Makefile -new file mode 100644 -index 0000000..9aa242c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/Makefile -@@ -0,0 +1,42 @@ -+# -+# (C) COPYRIGHT 2010-2016, 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+KDIR ?= /lib/modules/$(shell uname -r)/build -+ -+BUSLOG_PATH_RELATIVE = $(CURDIR)/../../../.. -+UMP_PATH_RELATIVE = $(CURDIR)/../../../base/ump -+KBASE_PATH_RELATIVE = $(CURDIR) -+KDS_PATH_RELATIVE = $(CURDIR)/../../../.. -+EXTRA_SYMBOLS = $(UMP_PATH_RELATIVE)/src/Module.symvers -+ -+ifeq ($(MALI_UNIT_TEST), 1) -+ EXTRA_SYMBOLS += $(KBASE_PATH_RELATIVE)/tests/internal/src/kernel_assert_module/linux/Module.symvers -+endif -+ -+ifeq ($(MALI_BUS_LOG), 1) -+#Add bus logger symbols -+EXTRA_SYMBOLS += $(BUSLOG_PATH_RELATIVE)/drivers/base/bus_logger/Module.symvers -+endif -+ -+# GPL driver supports KDS -+EXTRA_SYMBOLS += $(KDS_PATH_RELATIVE)/drivers/base/kds/Module.symvers -+ -+# we get the symbols from modules using KBUILD_EXTRA_SYMBOLS to prevent warnings about unknown functions -+all: -+ $(MAKE) -C $(KDIR) M=$(CURDIR) EXTRA_CFLAGS="-I$(CURDIR)/../../../../include -I$(CURDIR)/../../../../tests/include $(SCONS_CFLAGS)" $(SCONS_CONFIGS) KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" modules -+ -+clean: -+ $(MAKE) -C $(KDIR) M=$(CURDIR) clean -diff --git a/drivers/gpu/arm/midgard/Makefile.kbase b/drivers/gpu/arm/midgard/Makefile.kbase -new file mode 100644 -index 0000000..2bef9c2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/Makefile.kbase -@@ -0,0 +1,17 @@ -+# -+# (C) COPYRIGHT 2010 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+EXTRA_CFLAGS += -I$(ROOT) -I$(KBASE_PATH) -I$(OSK_PATH)/src/linux/include -I$(KBASE_PATH)/platform_$(PLATFORM) -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/Kbuild b/drivers/gpu/arm/midgard/backend/gpu/Kbuild -new file mode 100644 -index 0000000..5f700e9 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/Kbuild -@@ -0,0 +1,60 @@ -+# -+# (C) COPYRIGHT 2014,2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+BACKEND += \ -+ backend/gpu/mali_kbase_cache_policy_backend.c \ -+ backend/gpu/mali_kbase_device_hw.c \ -+ backend/gpu/mali_kbase_gpu.c \ -+ backend/gpu/mali_kbase_gpuprops_backend.c \ -+ backend/gpu/mali_kbase_debug_job_fault_backend.c \ -+ backend/gpu/mali_kbase_irq_linux.c \ -+ backend/gpu/mali_kbase_instr_backend.c \ -+ backend/gpu/mali_kbase_jm_as.c \ -+ backend/gpu/mali_kbase_jm_hw.c \ -+ backend/gpu/mali_kbase_jm_rb.c \ -+ backend/gpu/mali_kbase_js_affinity.c \ -+ backend/gpu/mali_kbase_js_backend.c \ -+ backend/gpu/mali_kbase_mmu_hw_direct.c \ -+ backend/gpu/mali_kbase_pm_backend.c \ -+ backend/gpu/mali_kbase_pm_driver.c \ -+ backend/gpu/mali_kbase_pm_metrics.c \ -+ backend/gpu/mali_kbase_pm_ca.c \ -+ backend/gpu/mali_kbase_pm_ca_fixed.c \ -+ backend/gpu/mali_kbase_pm_always_on.c \ -+ backend/gpu/mali_kbase_pm_coarse_demand.c \ -+ backend/gpu/mali_kbase_pm_demand.c \ -+ backend/gpu/mali_kbase_pm_policy.c \ -+ backend/gpu/mali_kbase_time.c -+ -+ifeq ($(MALI_CUSTOMER_RELEASE),0) -+BACKEND += \ -+ backend/gpu/mali_kbase_pm_ca_random.c \ -+ backend/gpu/mali_kbase_pm_demand_always_powered.c \ -+ backend/gpu/mali_kbase_pm_fast_start.c -+endif -+ -+ifeq ($(CONFIG_MALI_DEVFREQ),y) -+BACKEND += \ -+ backend/gpu/mali_kbase_devfreq.c \ -+ backend/gpu/mali_kbase_pm_ca_devfreq.c -+endif -+ -+ifeq ($(CONFIG_MALI_NO_MALI),y) -+ # Dummy model -+ BACKEND += backend/gpu/mali_kbase_model_dummy.c -+ BACKEND += backend/gpu/mali_kbase_model_linux.c -+ # HW error simulation -+ BACKEND += backend/gpu/mali_kbase_model_error_generator.c -+endif -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_backend_config.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_backend_config.h -new file mode 100644 -index 0000000..c8ae87e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_backend_config.h -@@ -0,0 +1,29 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Backend specific configuration -+ */ -+ -+#ifndef _KBASE_BACKEND_CONFIG_H_ -+#define _KBASE_BACKEND_CONFIG_H_ -+ -+/* Enable GPU reset API */ -+#define KBASE_GPU_RESET_EN 1 -+ -+#endif /* _KBASE_BACKEND_CONFIG_H_ */ -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_cache_policy_backend.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_cache_policy_backend.c -new file mode 100644 -index 0000000..fef9a2c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_cache_policy_backend.c -@@ -0,0 +1,29 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include "backend/gpu/mali_kbase_cache_policy_backend.h" -+#include -+ -+void kbase_cache_set_coherency_mode(struct kbase_device *kbdev, -+ u32 mode) -+{ -+ kbdev->current_gpu_coherency_mode = mode; -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_COHERENCY_REG)) -+ kbase_reg_write(kbdev, COHERENCY_ENABLE, mode, NULL); -+} -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_cache_policy_backend.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_cache_policy_backend.h -new file mode 100644 -index 0000000..fe98691 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_cache_policy_backend.h -@@ -0,0 +1,34 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+#ifndef _KBASE_CACHE_POLICY_BACKEND_H_ -+#define _KBASE_CACHE_POLICY_BACKEND_H_ -+ -+#include "mali_kbase.h" -+#include "mali_base_kernel.h" -+ -+/** -+ * kbase_cache_set_coherency_mode() - Sets the system coherency mode -+ * in the GPU. -+ * @kbdev: Device pointer -+ * @mode: Coherency mode. COHERENCY_ACE/ACE_LITE -+ */ -+void kbase_cache_set_coherency_mode(struct kbase_device *kbdev, -+ u32 mode); -+ -+#endif /* _KBASE_CACHE_POLICY_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_debug_job_fault_backend.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_debug_job_fault_backend.c -new file mode 100644 -index 0000000..7851ea6 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_debug_job_fault_backend.c -@@ -0,0 +1,157 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include "mali_kbase_debug_job_fault.h" -+ -+#ifdef CONFIG_DEBUG_FS -+ -+/*GPU_CONTROL_REG(r)*/ -+static int gpu_control_reg_snapshot[] = { -+ GPU_ID, -+ SHADER_READY_LO, -+ SHADER_READY_HI, -+ TILER_READY_LO, -+ TILER_READY_HI, -+ L2_READY_LO, -+ L2_READY_HI -+}; -+ -+/* JOB_CONTROL_REG(r) */ -+static int job_control_reg_snapshot[] = { -+ JOB_IRQ_MASK, -+ JOB_IRQ_STATUS -+}; -+ -+/* JOB_SLOT_REG(n,r) */ -+static int job_slot_reg_snapshot[] = { -+ JS_HEAD_LO, -+ JS_HEAD_HI, -+ JS_TAIL_LO, -+ JS_TAIL_HI, -+ JS_AFFINITY_LO, -+ JS_AFFINITY_HI, -+ JS_CONFIG, -+ JS_STATUS, -+ JS_HEAD_NEXT_LO, -+ JS_HEAD_NEXT_HI, -+ JS_AFFINITY_NEXT_LO, -+ JS_AFFINITY_NEXT_HI, -+ JS_CONFIG_NEXT -+}; -+ -+/*MMU_REG(r)*/ -+static int mmu_reg_snapshot[] = { -+ MMU_IRQ_MASK, -+ MMU_IRQ_STATUS -+}; -+ -+/* MMU_AS_REG(n,r) */ -+static int as_reg_snapshot[] = { -+ AS_TRANSTAB_LO, -+ AS_TRANSTAB_HI, -+ AS_MEMATTR_LO, -+ AS_MEMATTR_HI, -+ AS_FAULTSTATUS, -+ AS_FAULTADDRESS_LO, -+ AS_FAULTADDRESS_HI, -+ AS_STATUS -+}; -+ -+bool kbase_debug_job_fault_reg_snapshot_init(struct kbase_context *kctx, -+ int reg_range) -+{ -+ int i, j; -+ int offset = 0; -+ int slot_number; -+ int as_number; -+ -+ if (kctx->reg_dump == NULL) -+ return false; -+ -+ slot_number = kctx->kbdev->gpu_props.num_job_slots; -+ as_number = kctx->kbdev->gpu_props.num_address_spaces; -+ -+ /* get the GPU control registers*/ -+ for (i = 0; i < sizeof(gpu_control_reg_snapshot)/4; i++) { -+ kctx->reg_dump[offset] = -+ GPU_CONTROL_REG(gpu_control_reg_snapshot[i]); -+ offset += 2; -+ } -+ -+ /* get the Job control registers*/ -+ for (i = 0; i < sizeof(job_control_reg_snapshot)/4; i++) { -+ kctx->reg_dump[offset] = -+ JOB_CONTROL_REG(job_control_reg_snapshot[i]); -+ offset += 2; -+ } -+ -+ /* get the Job Slot registers*/ -+ for (j = 0; j < slot_number; j++) { -+ for (i = 0; i < sizeof(job_slot_reg_snapshot)/4; i++) { -+ kctx->reg_dump[offset] = -+ JOB_SLOT_REG(j, job_slot_reg_snapshot[i]); -+ offset += 2; -+ } -+ } -+ -+ /* get the MMU registers*/ -+ for (i = 0; i < sizeof(mmu_reg_snapshot)/4; i++) { -+ kctx->reg_dump[offset] = MMU_REG(mmu_reg_snapshot[i]); -+ offset += 2; -+ } -+ -+ /* get the Address space registers*/ -+ for (j = 0; j < as_number; j++) { -+ for (i = 0; i < sizeof(as_reg_snapshot)/4; i++) { -+ kctx->reg_dump[offset] = -+ MMU_AS_REG(j, as_reg_snapshot[i]); -+ offset += 2; -+ } -+ } -+ -+ WARN_ON(offset >= (reg_range*2/4)); -+ -+ /* set the termination flag*/ -+ kctx->reg_dump[offset] = REGISTER_DUMP_TERMINATION_FLAG; -+ kctx->reg_dump[offset + 1] = REGISTER_DUMP_TERMINATION_FLAG; -+ -+ dev_dbg(kctx->kbdev->dev, "kbase_job_fault_reg_snapshot_init:%d\n", -+ offset); -+ -+ return true; -+} -+ -+bool kbase_job_fault_get_reg_snapshot(struct kbase_context *kctx) -+{ -+ int offset = 0; -+ -+ if (kctx->reg_dump == NULL) -+ return false; -+ -+ while (kctx->reg_dump[offset] != REGISTER_DUMP_TERMINATION_FLAG) { -+ kctx->reg_dump[offset+1] = -+ kbase_reg_read(kctx->kbdev, -+ kctx->reg_dump[offset], NULL); -+ offset += 2; -+ } -+ return true; -+} -+ -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c -new file mode 100644 -index 0000000..e280322 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c -@@ -0,0 +1,413 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#ifdef CONFIG_DEVFREQ_THERMAL -+#include -+#endif -+ -+#include -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) -+#include -+#else /* Linux >= 3.13 */ -+/* In 3.13 the OPP include header file, types, and functions were all -+ * renamed. Use the old filename for the include, and define the new names to -+ * the old, when an old kernel is detected. -+ */ -+#include -+#define dev_pm_opp opp -+#define dev_pm_opp_get_voltage opp_get_voltage -+#define dev_pm_opp_get_opp_count opp_get_opp_count -+#define dev_pm_opp_find_freq_ceil opp_find_freq_ceil -+#define dev_pm_opp_find_freq_floor opp_find_freq_floor -+#endif /* Linux >= 3.13 */ -+ -+/** -+ * opp_translate - Translate nominal OPP frequency from devicetree into real -+ * frequency and core mask -+ * @kbdev: Device pointer -+ * @freq: Nominal frequency -+ * @core_mask: Pointer to u64 to store core mask to -+ * -+ * Return: Real target frequency -+ * -+ * This function will only perform translation if an operating-points-v2-mali -+ * table is present in devicetree. If one is not present then it will return an -+ * untranslated frequency and all cores enabled. -+ */ -+static unsigned long opp_translate(struct kbase_device *kbdev, -+ unsigned long freq, u64 *core_mask) -+{ -+ int i; -+ -+ for (i = 0; i < kbdev->num_opps; i++) { -+ if (kbdev->opp_table[i].opp_freq == freq) { -+ *core_mask = kbdev->opp_table[i].core_mask; -+ return kbdev->opp_table[i].real_freq; -+ } -+ } -+ -+ /* Failed to find OPP - return all cores enabled & nominal frequency */ -+ *core_mask = kbdev->gpu_props.props.raw_props.shader_present; -+ -+ return freq; -+} -+ -+static int -+kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags) -+{ -+ struct kbase_device *kbdev = dev_get_drvdata(dev); -+ struct dev_pm_opp *opp; -+ unsigned long nominal_freq; -+ unsigned long freq = 0; -+ unsigned long voltage; -+ int err; -+ u64 core_mask; -+ -+ freq = *target_freq; -+ -+ rcu_read_lock(); -+ opp = devfreq_recommended_opp(dev, &freq, flags); -+ voltage = dev_pm_opp_get_voltage(opp); -+ rcu_read_unlock(); -+ if (IS_ERR_OR_NULL(opp)) { -+ dev_err(dev, "Failed to get opp (%ld)\n", PTR_ERR(opp)); -+ return PTR_ERR(opp); -+ } -+ -+ nominal_freq = freq; -+ -+ /* -+ * Only update if there is a change of frequency -+ */ -+ if (kbdev->current_nominal_freq == nominal_freq) { -+ *target_freq = nominal_freq; -+ return 0; -+ } -+ -+ freq = opp_translate(kbdev, nominal_freq, &core_mask); -+#ifdef CONFIG_REGULATOR -+ if (kbdev->regulator && kbdev->current_voltage != voltage -+ && kbdev->current_freq < freq) { -+ err = regulator_set_voltage(kbdev->regulator, voltage, voltage); -+ if (err) { -+ dev_err(dev, "Failed to increase voltage (%d)\n", err); -+ return err; -+ } -+ } -+#endif -+ -+ err = clk_set_rate(kbdev->clock, freq); -+ if (err) { -+ dev_err(dev, "Failed to set clock %lu (target %lu)\n", -+ freq, *target_freq); -+ return err; -+ } -+ -+#ifdef CONFIG_REGULATOR -+ if (kbdev->regulator && kbdev->current_voltage != voltage -+ && kbdev->current_freq > freq) { -+ err = regulator_set_voltage(kbdev->regulator, voltage, voltage); -+ if (err) { -+ dev_err(dev, "Failed to decrease voltage (%d)\n", err); -+ return err; -+ } -+ } -+#endif -+ -+ if (kbdev->pm.backend.ca_current_policy->id == -+ KBASE_PM_CA_POLICY_ID_DEVFREQ) -+ kbase_devfreq_set_core_mask(kbdev, core_mask); -+ -+ *target_freq = nominal_freq; -+ kbdev->current_voltage = voltage; -+ kbdev->current_nominal_freq = nominal_freq; -+ kbdev->current_freq = freq; -+ kbdev->current_core_mask = core_mask; -+ -+ KBASE_TLSTREAM_AUX_DEVFREQ_TARGET((u64)nominal_freq); -+ -+ kbase_pm_reset_dvfs_utilisation(kbdev); -+ -+ return err; -+} -+ -+static int -+kbase_devfreq_cur_freq(struct device *dev, unsigned long *freq) -+{ -+ struct kbase_device *kbdev = dev_get_drvdata(dev); -+ -+ *freq = kbdev->current_nominal_freq; -+ -+ return 0; -+} -+ -+static int -+kbase_devfreq_status(struct device *dev, struct devfreq_dev_status *stat) -+{ -+ struct kbase_device *kbdev = dev_get_drvdata(dev); -+ -+ stat->current_frequency = kbdev->current_nominal_freq; -+ -+ kbase_pm_get_dvfs_utilisation(kbdev, -+ &stat->total_time, &stat->busy_time); -+ -+ stat->private_data = NULL; -+ -+ return 0; -+} -+ -+static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev, -+ struct devfreq_dev_profile *dp) -+{ -+ int count; -+ int i = 0; -+ unsigned long freq; -+ struct dev_pm_opp *opp; -+ -+ rcu_read_lock(); -+ count = dev_pm_opp_get_opp_count(kbdev->dev); -+ if (count < 0) { -+ rcu_read_unlock(); -+ return count; -+ } -+ rcu_read_unlock(); -+ -+ dp->freq_table = kmalloc_array(count, sizeof(dp->freq_table[0]), -+ GFP_KERNEL); -+ if (!dp->freq_table) -+ return -ENOMEM; -+ -+ rcu_read_lock(); -+ for (i = 0, freq = ULONG_MAX; i < count; i++, freq--) { -+ opp = dev_pm_opp_find_freq_floor(kbdev->dev, &freq); -+ if (IS_ERR(opp)) -+ break; -+ -+ dp->freq_table[i] = freq; -+ } -+ rcu_read_unlock(); -+ -+ if (count != i) -+ dev_warn(kbdev->dev, "Unable to enumerate all OPPs (%d!=%d\n", -+ count, i); -+ -+ dp->max_state = i; -+ -+ return 0; -+} -+ -+static void kbase_devfreq_term_freq_table(struct kbase_device *kbdev) -+{ -+ struct devfreq_dev_profile *dp = kbdev->devfreq->profile; -+ -+ kfree(dp->freq_table); -+} -+ -+static void kbase_devfreq_exit(struct device *dev) -+{ -+ struct kbase_device *kbdev = dev_get_drvdata(dev); -+ -+ kbase_devfreq_term_freq_table(kbdev); -+} -+ -+static int kbase_devfreq_init_core_mask_table(struct kbase_device *kbdev) -+{ -+ struct device_node *opp_node = of_parse_phandle(kbdev->dev->of_node, -+ "operating-points-v2", 0); -+ struct device_node *node; -+ int i = 0; -+ int count; -+ -+ if (!opp_node) -+ return 0; -+ if (!of_device_is_compatible(opp_node, "operating-points-v2-mali")) -+ return 0; -+ -+ count = dev_pm_opp_get_opp_count(kbdev->dev); -+ kbdev->opp_table = kmalloc_array(count, -+ sizeof(struct kbase_devfreq_opp), GFP_KERNEL); -+ if (!kbdev->opp_table) -+ return -ENOMEM; -+ -+ for_each_available_child_of_node(opp_node, node) { -+ u64 core_mask; -+ u64 opp_freq, real_freq; -+ const void *core_count_p; -+ -+ if (of_property_read_u64(node, "opp-hz", &opp_freq)) { -+ dev_warn(kbdev->dev, "OPP is missing required opp-hz property\n"); -+ continue; -+ } -+ if (of_property_read_u64(node, "opp-hz-real", &real_freq)) -+ real_freq = opp_freq; -+ if (of_property_read_u64(node, "opp-core-mask", &core_mask)) -+ core_mask = -+ kbdev->gpu_props.props.raw_props.shader_present; -+ core_count_p = of_get_property(node, "opp-core-count", NULL); -+ if (core_count_p) { -+ u64 remaining_core_mask = -+ kbdev->gpu_props.props.raw_props.shader_present; -+ int core_count = be32_to_cpup(core_count_p); -+ -+ core_mask = 0; -+ -+ for (; core_count > 0; core_count--) { -+ int core = ffs(remaining_core_mask); -+ -+ if (!core) { -+ dev_err(kbdev->dev, "OPP has more cores than GPU\n"); -+ return -ENODEV; -+ } -+ -+ core_mask |= (1ull << (core-1)); -+ remaining_core_mask &= ~(1ull << (core-1)); -+ } -+ } -+ -+ if (!core_mask) { -+ dev_err(kbdev->dev, "OPP has invalid core mask of 0\n"); -+ return -ENODEV; -+ } -+ -+ kbdev->opp_table[i].opp_freq = opp_freq; -+ kbdev->opp_table[i].real_freq = real_freq; -+ kbdev->opp_table[i].core_mask = core_mask; -+ -+ dev_info(kbdev->dev, "OPP %d : opp_freq=%llu real_freq=%llu core_mask=%llx\n", -+ i, opp_freq, real_freq, core_mask); -+ -+ i++; -+ } -+ -+ kbdev->num_opps = i; -+ -+ return 0; -+} -+ -+int kbase_devfreq_init(struct kbase_device *kbdev) -+{ -+ struct devfreq_dev_profile *dp; -+ int err; -+ -+ if (!kbdev->clock) { -+ dev_err(kbdev->dev, "Clock not available for devfreq\n"); -+ return -ENODEV; -+ } -+ -+ kbdev->current_freq = clk_get_rate(kbdev->clock); -+ kbdev->current_nominal_freq = kbdev->current_freq; -+ -+ dp = &kbdev->devfreq_profile; -+ -+ dp->initial_freq = kbdev->current_freq; -+ dp->polling_ms = 100; -+ dp->target = kbase_devfreq_target; -+ dp->get_dev_status = kbase_devfreq_status; -+ dp->get_cur_freq = kbase_devfreq_cur_freq; -+ dp->exit = kbase_devfreq_exit; -+ -+ if (kbase_devfreq_init_freq_table(kbdev, dp)) -+ return -EFAULT; -+ -+ err = kbase_devfreq_init_core_mask_table(kbdev); -+ if (err) -+ return err; -+ -+ kbdev->devfreq = devfreq_add_device(kbdev->dev, dp, -+ "simple_ondemand", NULL); -+ if (IS_ERR(kbdev->devfreq)) { -+ kbase_devfreq_term_freq_table(kbdev); -+ return PTR_ERR(kbdev->devfreq); -+ } -+ -+ /* devfreq_add_device only copies a few of kbdev->dev's fields, so -+ * set drvdata explicitly so IPA models can access kbdev. */ -+ dev_set_drvdata(&kbdev->devfreq->dev, kbdev); -+ -+ err = devfreq_register_opp_notifier(kbdev->dev, kbdev->devfreq); -+ if (err) { -+ dev_err(kbdev->dev, -+ "Failed to register OPP notifier (%d)\n", err); -+ goto opp_notifier_failed; -+ } -+ -+#ifdef CONFIG_DEVFREQ_THERMAL -+ err = kbase_ipa_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "IPA initialization failed\n"); -+ goto cooling_failed; -+ } -+ -+ kbdev->devfreq_cooling = of_devfreq_cooling_register_power( -+ kbdev->dev->of_node, -+ kbdev->devfreq, -+ &kbase_ipa_power_model_ops); -+ if (IS_ERR_OR_NULL(kbdev->devfreq_cooling)) { -+ err = PTR_ERR(kbdev->devfreq_cooling); -+ dev_err(kbdev->dev, -+ "Failed to register cooling device (%d)\n", -+ err); -+ goto cooling_failed; -+ } -+#endif -+ -+ return 0; -+ -+#ifdef CONFIG_DEVFREQ_THERMAL -+cooling_failed: -+ devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq); -+#endif /* CONFIG_DEVFREQ_THERMAL */ -+opp_notifier_failed: -+ if (devfreq_remove_device(kbdev->devfreq)) -+ dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err); -+ else -+ kbdev->devfreq = NULL; -+ -+ return err; -+} -+ -+void kbase_devfreq_term(struct kbase_device *kbdev) -+{ -+ int err; -+ -+ dev_dbg(kbdev->dev, "Term Mali devfreq\n"); -+ -+#ifdef CONFIG_DEVFREQ_THERMAL -+ if (kbdev->devfreq_cooling) -+ devfreq_cooling_unregister(kbdev->devfreq_cooling); -+ -+ kbase_ipa_term(kbdev); -+#endif -+ -+ devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq); -+ -+ err = devfreq_remove_device(kbdev->devfreq); -+ if (err) -+ dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err); -+ else -+ kbdev->devfreq = NULL; -+ -+ kfree(kbdev->opp_table); -+} -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.h -new file mode 100644 -index 0000000..c0bf8b1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.h -@@ -0,0 +1,24 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _BASE_DEVFREQ_H_ -+#define _BASE_DEVFREQ_H_ -+ -+int kbase_devfreq_init(struct kbase_device *kbdev); -+void kbase_devfreq_term(struct kbase_device *kbdev); -+ -+#endif /* _BASE_DEVFREQ_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_device_hw.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_device_hw.c -new file mode 100644 -index 0000000..dcdf15c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_device_hw.c -@@ -0,0 +1,255 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * -+ */ -+#include -+#include -+#include -+ -+#include -+ -+#if !defined(CONFIG_MALI_NO_MALI) -+ -+ -+#ifdef CONFIG_DEBUG_FS -+ -+ -+int kbase_io_history_resize(struct kbase_io_history *h, u16 new_size) -+{ -+ struct kbase_io_access *old_buf; -+ struct kbase_io_access *new_buf; -+ unsigned long flags; -+ -+ if (!new_size) -+ goto out_err; /* The new size must not be 0 */ -+ -+ new_buf = vmalloc(new_size * sizeof(*h->buf)); -+ if (!new_buf) -+ goto out_err; -+ -+ spin_lock_irqsave(&h->lock, flags); -+ -+ old_buf = h->buf; -+ -+ /* Note: we won't bother with copying the old data over. The dumping -+ * logic wouldn't work properly as it relies on 'count' both as a -+ * counter and as an index to the buffer which would have changed with -+ * the new array. This is a corner case that we don't need to support. -+ */ -+ h->count = 0; -+ h->size = new_size; -+ h->buf = new_buf; -+ -+ spin_unlock_irqrestore(&h->lock, flags); -+ -+ vfree(old_buf); -+ -+ return 0; -+ -+out_err: -+ return -1; -+} -+ -+ -+int kbase_io_history_init(struct kbase_io_history *h, u16 n) -+{ -+ h->enabled = false; -+ spin_lock_init(&h->lock); -+ h->count = 0; -+ h->size = 0; -+ h->buf = NULL; -+ if (kbase_io_history_resize(h, n)) -+ return -1; -+ -+ return 0; -+} -+ -+ -+void kbase_io_history_term(struct kbase_io_history *h) -+{ -+ vfree(h->buf); -+ h->buf = NULL; -+} -+ -+ -+/* kbase_io_history_add - add new entry to the register access history -+ * -+ * @h: Pointer to the history data structure -+ * @addr: Register address -+ * @value: The value that is either read from or written to the register -+ * @write: 1 if it's a register write, 0 if it's a read -+ */ -+static void kbase_io_history_add(struct kbase_io_history *h, -+ void __iomem const *addr, u32 value, u8 write) -+{ -+ struct kbase_io_access *io; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&h->lock, flags); -+ -+ io = &h->buf[h->count % h->size]; -+ io->addr = (uintptr_t)addr | write; -+ io->value = value; -+ ++h->count; -+ /* If count overflows, move the index by the buffer size so the entire -+ * buffer will still be dumped later */ -+ if (unlikely(!h->count)) -+ h->count = h->size; -+ -+ spin_unlock_irqrestore(&h->lock, flags); -+} -+ -+ -+void kbase_io_history_dump(struct kbase_device *kbdev) -+{ -+ struct kbase_io_history *const h = &kbdev->io_history; -+ u16 i; -+ size_t iters; -+ unsigned long flags; -+ -+ if (!unlikely(h->enabled)) -+ return; -+ -+ spin_lock_irqsave(&h->lock, flags); -+ -+ dev_err(kbdev->dev, "Register IO History:"); -+ iters = (h->size > h->count) ? h->count : h->size; -+ dev_err(kbdev->dev, "Last %zu register accesses of %zu total:\n", iters, -+ h->count); -+ for (i = 0; i < iters; ++i) { -+ struct kbase_io_access *io = -+ &h->buf[(h->count - iters + i) % h->size]; -+ char const access = (io->addr & 1) ? 'w' : 'r'; -+ -+ dev_err(kbdev->dev, "%6i: %c: reg 0x%p val %08x\n", i, access, -+ (void *)(io->addr & ~0x1), io->value); -+ } -+ -+ spin_unlock_irqrestore(&h->lock, flags); -+} -+ -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+ -+void kbase_reg_write(struct kbase_device *kbdev, u16 offset, u32 value, -+ struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered); -+ KBASE_DEBUG_ASSERT(kctx == NULL || kctx->as_nr != KBASEP_AS_NR_INVALID); -+ KBASE_DEBUG_ASSERT(kbdev->dev != NULL); -+ -+ writel(value, kbdev->reg + offset); -+ -+#ifdef CONFIG_DEBUG_FS -+ if (unlikely(kbdev->io_history.enabled)) -+ kbase_io_history_add(&kbdev->io_history, kbdev->reg + offset, -+ value, 1); -+#endif /* CONFIG_DEBUG_FS */ -+ dev_dbg(kbdev->dev, "w: reg %04x val %08x", offset, value); -+ -+ if (kctx && kctx->jctx.tb) -+ kbase_device_trace_register_access(kctx, REG_WRITE, offset, -+ value); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_reg_write); -+ -+u32 kbase_reg_read(struct kbase_device *kbdev, u16 offset, -+ struct kbase_context *kctx) -+{ -+ u32 val; -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered); -+ KBASE_DEBUG_ASSERT(kctx == NULL || kctx->as_nr != KBASEP_AS_NR_INVALID); -+ KBASE_DEBUG_ASSERT(kbdev->dev != NULL); -+ -+ val = readl(kbdev->reg + offset); -+ -+#ifdef CONFIG_DEBUG_FS -+ if (unlikely(kbdev->io_history.enabled)) -+ kbase_io_history_add(&kbdev->io_history, kbdev->reg + offset, -+ val, 0); -+#endif /* CONFIG_DEBUG_FS */ -+ dev_dbg(kbdev->dev, "r: reg %04x val %08x", offset, val); -+ -+ if (kctx && kctx->jctx.tb) -+ kbase_device_trace_register_access(kctx, REG_READ, offset, val); -+ return val; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_reg_read); -+#endif /* !defined(CONFIG_MALI_NO_MALI) */ -+ -+/** -+ * kbase_report_gpu_fault - Report a GPU fault. -+ * @kbdev: Kbase device pointer -+ * @multiple: Zero if only GPU_FAULT was raised, non-zero if MULTIPLE_GPU_FAULTS -+ * was also set -+ * -+ * This function is called from the interrupt handler when a GPU fault occurs. -+ * It reports the details of the fault using dev_warn(). -+ */ -+static void kbase_report_gpu_fault(struct kbase_device *kbdev, int multiple) -+{ -+ u32 status; -+ u64 address; -+ -+ status = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTSTATUS), NULL); -+ address = (u64) kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(GPU_FAULTADDRESS_HI), NULL) << 32; -+ address |= kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(GPU_FAULTADDRESS_LO), NULL); -+ -+ dev_warn(kbdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx", -+ status & 0xFF, -+ kbase_exception_name(kbdev, status), -+ address); -+ if (multiple) -+ dev_warn(kbdev->dev, "There were multiple GPU faults - some have not been reported\n"); -+} -+ -+void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val) -+{ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ, NULL, NULL, 0u, val); -+ if (val & GPU_FAULT) -+ kbase_report_gpu_fault(kbdev, val & MULTIPLE_GPU_FAULTS); -+ -+ if (val & RESET_COMPLETED) -+ kbase_pm_reset_done(kbdev); -+ -+ if (val & PRFCNT_SAMPLE_COMPLETED) -+ kbase_instr_hwcnt_sample_done(kbdev); -+ -+ if (val & CLEAN_CACHES_COMPLETED) -+ kbase_clean_caches_done(kbdev); -+ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, NULL, 0u, val); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), val, NULL); -+ -+ /* kbase_pm_check_transitions must be called after the IRQ has been -+ * cleared. This is because it might trigger further power transitions -+ * and we don't want to miss the interrupt raised to notify us that -+ * these further transitions have finished. -+ */ -+ if (val & POWER_CHANGED_ALL) -+ kbase_pm_power_changed(kbdev); -+ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ_DONE, NULL, NULL, 0u, val); -+} -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_device_internal.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_device_internal.h -new file mode 100644 -index 0000000..5b20445 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_device_internal.h -@@ -0,0 +1,67 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Backend-specific HW access device APIs -+ */ -+ -+#ifndef _KBASE_DEVICE_INTERNAL_H_ -+#define _KBASE_DEVICE_INTERNAL_H_ -+ -+/** -+ * kbase_reg_write - write to GPU register -+ * @kbdev: Kbase device pointer -+ * @offset: Offset of register -+ * @value: Value to write -+ * @kctx: Kbase context pointer. May be NULL -+ * -+ * Caller must ensure the GPU is powered (@kbdev->pm.gpu_powered != false). If -+ * @kctx is not NULL then the caller must ensure it is scheduled (@kctx->as_nr -+ * != KBASEP_AS_NR_INVALID). -+ */ -+void kbase_reg_write(struct kbase_device *kbdev, u16 offset, u32 value, -+ struct kbase_context *kctx); -+ -+/** -+ * kbase_reg_read - read from GPU register -+ * @kbdev: Kbase device pointer -+ * @offset: Offset of register -+ * @kctx: Kbase context pointer. May be NULL -+ * -+ * Caller must ensure the GPU is powered (@kbdev->pm.gpu_powered != false). If -+ * @kctx is not NULL then the caller must ensure it is scheduled (@kctx->as_nr -+ * != KBASEP_AS_NR_INVALID). -+ * -+ * Return: Value in desired register -+ */ -+u32 kbase_reg_read(struct kbase_device *kbdev, u16 offset, -+ struct kbase_context *kctx); -+ -+ -+/** -+ * kbase_gpu_interrupt - GPU interrupt handler -+ * @kbdev: Kbase device pointer -+ * @val: The value of the GPU IRQ status register which triggered the call -+ * -+ * This function is called from the interrupt handler when a GPU irq is to be -+ * handled. -+ */ -+void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val); -+ -+#endif /* _KBASE_DEVICE_INTERNAL_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_gpu.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_gpu.c -new file mode 100644 -index 0000000..d578fd7 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_gpu.c -@@ -0,0 +1,123 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Register-based HW access backend APIs -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+int kbase_backend_early_init(struct kbase_device *kbdev) -+{ -+ int err; -+ -+ err = kbasep_platform_device_init(kbdev); -+ if (err) -+ return err; -+ -+ /* Ensure we can access the GPU registers */ -+ kbase_pm_register_access_enable(kbdev); -+ -+ /* Find out GPU properties based on the GPU feature registers */ -+ kbase_gpuprops_set(kbdev); -+ -+ /* We're done accessing the GPU registers for now. */ -+ kbase_pm_register_access_disable(kbdev); -+ -+ err = kbase_hwaccess_pm_init(kbdev); -+ if (err) -+ goto fail_pm; -+ -+ err = kbase_install_interrupts(kbdev); -+ if (err) -+ goto fail_interrupts; -+ -+ return 0; -+ -+fail_interrupts: -+ kbase_hwaccess_pm_term(kbdev); -+fail_pm: -+ kbasep_platform_device_term(kbdev); -+ -+ return err; -+} -+ -+void kbase_backend_early_term(struct kbase_device *kbdev) -+{ -+ kbase_release_interrupts(kbdev); -+ kbase_hwaccess_pm_term(kbdev); -+ kbasep_platform_device_term(kbdev); -+} -+ -+int kbase_backend_late_init(struct kbase_device *kbdev) -+{ -+ int err; -+ -+ err = kbase_hwaccess_pm_powerup(kbdev, PM_HW_ISSUES_DETECT); -+ if (err) -+ return err; -+ -+ err = kbase_backend_timer_init(kbdev); -+ if (err) -+ goto fail_timer; -+ -+#ifdef CONFIG_MALI_DEBUG -+#ifndef CONFIG_MALI_NO_MALI -+ if (kbasep_common_test_interrupt_handlers(kbdev) != 0) { -+ dev_err(kbdev->dev, "Interrupt assigment check failed.\n"); -+ err = -EINVAL; -+ goto fail_interrupt_test; -+ } -+#endif /* !CONFIG_MALI_NO_MALI */ -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ err = kbase_job_slot_init(kbdev); -+ if (err) -+ goto fail_job_slot; -+ -+ init_waitqueue_head(&kbdev->hwaccess.backend.reset_wait); -+ -+ return 0; -+ -+fail_job_slot: -+ -+#ifdef CONFIG_MALI_DEBUG -+#ifndef CONFIG_MALI_NO_MALI -+fail_interrupt_test: -+#endif /* !CONFIG_MALI_NO_MALI */ -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ kbase_backend_timer_term(kbdev); -+fail_timer: -+ kbase_hwaccess_pm_halt(kbdev); -+ -+ return err; -+} -+ -+void kbase_backend_late_term(struct kbase_device *kbdev) -+{ -+ kbase_job_slot_halt(kbdev); -+ kbase_job_slot_term(kbdev); -+ kbase_backend_timer_term(kbdev); -+ kbase_hwaccess_pm_halt(kbdev); -+} -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_gpuprops_backend.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_gpuprops_backend.c -new file mode 100644 -index 0000000..b395325 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_gpuprops_backend.c -@@ -0,0 +1,110 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Base kernel property query backend APIs -+ */ -+ -+#include -+#include -+#include -+#include -+ -+void kbase_backend_gpuprops_get(struct kbase_device *kbdev, -+ struct kbase_gpuprops_regdump *regdump) -+{ -+ int i; -+ -+ /* Fill regdump with the content of the relevant registers */ -+ regdump->gpu_id = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID), NULL); -+ -+ regdump->l2_features = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(L2_FEATURES), NULL); -+ regdump->suspend_size = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(SUSPEND_SIZE), NULL); -+ regdump->tiler_features = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TILER_FEATURES), NULL); -+ regdump->mem_features = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(MEM_FEATURES), NULL); -+ regdump->mmu_features = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(MMU_FEATURES), NULL); -+ regdump->as_present = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(AS_PRESENT), NULL); -+ regdump->js_present = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(JS_PRESENT), NULL); -+ -+ for (i = 0; i < GPU_MAX_JOB_SLOTS; i++) -+ regdump->js_features[i] = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(JS_FEATURES_REG(i)), NULL); -+ -+ for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++) -+ regdump->texture_features[i] = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TEXTURE_FEATURES_REG(i)), NULL); -+ -+ regdump->thread_max_threads = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(THREAD_MAX_THREADS), NULL); -+ regdump->thread_max_workgroup_size = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(THREAD_MAX_WORKGROUP_SIZE), -+ NULL); -+ regdump->thread_max_barrier_size = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(THREAD_MAX_BARRIER_SIZE), NULL); -+ regdump->thread_features = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(THREAD_FEATURES), NULL); -+ -+ regdump->shader_present_lo = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(SHADER_PRESENT_LO), NULL); -+ regdump->shader_present_hi = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(SHADER_PRESENT_HI), NULL); -+ -+ regdump->tiler_present_lo = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TILER_PRESENT_LO), NULL); -+ regdump->tiler_present_hi = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TILER_PRESENT_HI), NULL); -+ -+ regdump->l2_present_lo = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(L2_PRESENT_LO), NULL); -+ regdump->l2_present_hi = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(L2_PRESENT_HI), NULL); -+ -+ regdump->stack_present_lo = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(STACK_PRESENT_LO), NULL); -+ regdump->stack_present_hi = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(STACK_PRESENT_HI), NULL); -+} -+ -+void kbase_backend_gpuprops_get_features(struct kbase_device *kbdev, -+ struct kbase_gpuprops_regdump *regdump) -+{ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_COHERENCY_REG)) { -+ /* Ensure we can access the GPU registers */ -+ kbase_pm_register_access_enable(kbdev); -+ -+ regdump->coherency_features = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(COHERENCY_FEATURES), NULL); -+ -+ /* We're done accessing the GPU registers for now. */ -+ kbase_pm_register_access_disable(kbdev); -+ } else { -+ /* Pre COHERENCY_FEATURES we only supported ACE_LITE */ -+ regdump->coherency_features = -+ COHERENCY_FEATURE_BIT(COHERENCY_NONE) | -+ COHERENCY_FEATURE_BIT(COHERENCY_ACE_LITE); -+ } -+} -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_backend.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_backend.c -new file mode 100644 -index 0000000..7ad309e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_backend.c -@@ -0,0 +1,492 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * GPU backend instrumentation APIs. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * kbasep_instr_hwcnt_cacheclean - Issue Cache Clean & Invalidate command to -+ * hardware -+ * -+ * @kbdev: Kbase device -+ */ -+static void kbasep_instr_hwcnt_cacheclean(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ unsigned long pm_flags; -+ u32 irq_mask; -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state == -+ KBASE_INSTR_STATE_REQUEST_CLEAN); -+ -+ /* Enable interrupt */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, pm_flags); -+ irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), NULL); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), -+ irq_mask | CLEAN_CACHES_COMPLETED, NULL); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, pm_flags); -+ -+ /* clean&invalidate the caches so we're sure the mmu tables for the dump -+ * buffer is valid */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, NULL, 0u, 0); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_CLEAN_INV_CACHES, NULL); -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_CLEANING; -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+} -+ -+int kbase_instr_hwcnt_enable_internal(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ struct kbase_uk_hwcnt_setup *setup) -+{ -+ unsigned long flags, pm_flags; -+ int err = -EINVAL; -+ u32 irq_mask; -+ int ret; -+ u64 shader_cores_needed; -+ u32 prfcnt_config; -+ -+ shader_cores_needed = kbase_pm_get_present_cores(kbdev, -+ KBASE_PM_CORE_SHADER); -+ -+ /* alignment failure */ -+ if ((setup->dump_buffer == 0ULL) || (setup->dump_buffer & (2048 - 1))) -+ goto out_err; -+ -+ /* Override core availability policy to ensure all cores are available -+ */ -+ kbase_pm_ca_instr_enable(kbdev); -+ -+ /* Request the cores early on synchronously - we'll release them on any -+ * errors (e.g. instrumentation already active) */ -+ kbase_pm_request_cores_sync(kbdev, true, shader_cores_needed); -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ if (kbdev->hwcnt.backend.state != KBASE_INSTR_STATE_DISABLED) { -+ /* Instrumentation is already enabled */ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ goto out_unrequest_cores; -+ } -+ -+ /* Enable interrupt */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, pm_flags); -+ irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), NULL); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask | -+ PRFCNT_SAMPLE_COMPLETED, NULL); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, pm_flags); -+ -+ /* In use, this context is the owner */ -+ kbdev->hwcnt.kctx = kctx; -+ /* Remember the dump address so we can reprogram it later */ -+ kbdev->hwcnt.addr = setup->dump_buffer; -+ -+ /* Request the clean */ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_REQUEST_CLEAN; -+ kbdev->hwcnt.backend.triggered = 0; -+ /* Clean&invalidate the caches so we're sure the mmu tables for the dump -+ * buffer is valid */ -+ ret = queue_work(kbdev->hwcnt.backend.cache_clean_wq, -+ &kbdev->hwcnt.backend.cache_clean_work); -+ KBASE_DEBUG_ASSERT(ret); -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ -+ /* Wait for cacheclean to complete */ -+ wait_event(kbdev->hwcnt.backend.wait, -+ kbdev->hwcnt.backend.triggered != 0); -+ -+ KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state == -+ KBASE_INSTR_STATE_IDLE); -+ -+ kbase_pm_request_l2_caches(kbdev); -+ -+ /* Configure */ -+ prfcnt_config = kctx->as_nr << PRFCNT_CONFIG_AS_SHIFT; -+#ifdef CONFIG_MALI_PRFCNT_SET_SECONDARY -+ { -+ u32 gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ u32 product_id = (gpu_id & GPU_ID_VERSION_PRODUCT_ID) -+ >> GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ int arch_v6 = GPU_ID_IS_NEW_FORMAT(product_id); -+ -+ if (arch_v6) -+ prfcnt_config |= 1 << PRFCNT_CONFIG_SETSELECT_SHIFT; -+ } -+#endif -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), -+ prfcnt_config | PRFCNT_CONFIG_MODE_OFF, kctx); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), -+ setup->dump_buffer & 0xFFFFFFFF, kctx); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), -+ setup->dump_buffer >> 32, kctx); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_JM_EN), -+ setup->jm_bm, kctx); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_SHADER_EN), -+ setup->shader_bm, kctx); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_MMU_L2_EN), -+ setup->mmu_l2_bm, kctx); -+ /* Due to PRLAM-8186 we need to disable the Tiler before we enable the -+ * HW counter dump. */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8186)) -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), 0, -+ kctx); -+ else -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), -+ setup->tiler_bm, kctx); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), -+ prfcnt_config | PRFCNT_CONFIG_MODE_MANUAL, kctx); -+ -+ /* If HW has PRLAM-8186 we can now re-enable the tiler HW counters dump -+ */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8186)) -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), -+ setup->tiler_bm, kctx); -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE; -+ kbdev->hwcnt.backend.triggered = 1; -+ wake_up(&kbdev->hwcnt.backend.wait); -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ -+ err = 0; -+ -+ dev_dbg(kbdev->dev, "HW counters dumping set-up for context %p", kctx); -+ return err; -+ out_unrequest_cores: -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_pm_unrequest_cores(kbdev, true, shader_cores_needed); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ out_err: -+ return err; -+} -+ -+int kbase_instr_hwcnt_disable_internal(struct kbase_context *kctx) -+{ -+ unsigned long flags, pm_flags; -+ int err = -EINVAL; -+ u32 irq_mask; -+ struct kbase_device *kbdev = kctx->kbdev; -+ -+ while (1) { -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_DISABLED) { -+ /* Instrumentation is not enabled */ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ goto out; -+ } -+ -+ if (kbdev->hwcnt.kctx != kctx) { -+ /* Instrumentation has been setup for another context */ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ goto out; -+ } -+ -+ if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_IDLE) -+ break; -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ -+ /* Ongoing dump/setup - wait for its completion */ -+ wait_event(kbdev->hwcnt.backend.wait, -+ kbdev->hwcnt.backend.triggered != 0); -+ } -+ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_DISABLED; -+ kbdev->hwcnt.backend.triggered = 0; -+ -+ /* Disable interrupt */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, pm_flags); -+ irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), NULL); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), -+ irq_mask & ~PRFCNT_SAMPLE_COMPLETED, NULL); -+ -+ /* Disable the counters */ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), 0, kctx); -+ -+ kbdev->hwcnt.kctx = NULL; -+ kbdev->hwcnt.addr = 0ULL; -+ -+ kbase_pm_ca_instr_disable(kbdev); -+ -+ kbase_pm_unrequest_cores(kbdev, true, -+ kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER)); -+ -+ kbase_pm_release_l2_caches(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, pm_flags); -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ -+ dev_dbg(kbdev->dev, "HW counters dumping disabled for context %p", -+ kctx); -+ -+ err = 0; -+ -+ out: -+ return err; -+} -+ -+int kbase_instr_hwcnt_request_dump(struct kbase_context *kctx) -+{ -+ unsigned long flags; -+ int err = -EINVAL; -+ struct kbase_device *kbdev = kctx->kbdev; -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ if (kbdev->hwcnt.kctx != kctx) { -+ /* The instrumentation has been setup for another context */ -+ goto unlock; -+ } -+ -+ if (kbdev->hwcnt.backend.state != KBASE_INSTR_STATE_IDLE) { -+ /* HW counters are disabled or another dump is ongoing, or we're -+ * resetting */ -+ goto unlock; -+ } -+ -+ kbdev->hwcnt.backend.triggered = 0; -+ -+ /* Mark that we're dumping - the PF handler can signal that we faulted -+ */ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_DUMPING; -+ -+ /* Reconfigure the dump address */ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), -+ kbdev->hwcnt.addr & 0xFFFFFFFF, NULL); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), -+ kbdev->hwcnt.addr >> 32, NULL); -+ -+ /* Start dumping */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_PRFCNT_SAMPLE, NULL, NULL, -+ kbdev->hwcnt.addr, 0); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_PRFCNT_SAMPLE, kctx); -+ -+ dev_dbg(kbdev->dev, "HW counters dumping done for context %p", kctx); -+ -+ err = 0; -+ -+ unlock: -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ return err; -+} -+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_request_dump); -+ -+bool kbase_instr_hwcnt_dump_complete(struct kbase_context *kctx, -+ bool * const success) -+{ -+ unsigned long flags; -+ bool complete = false; -+ struct kbase_device *kbdev = kctx->kbdev; -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_IDLE) { -+ *success = true; -+ complete = true; -+ } else if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_FAULT) { -+ *success = false; -+ complete = true; -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE; -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ -+ return complete; -+} -+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_complete); -+ -+void kbasep_cache_clean_worker(struct work_struct *data) -+{ -+ struct kbase_device *kbdev; -+ unsigned long flags; -+ -+ kbdev = container_of(data, struct kbase_device, -+ hwcnt.backend.cache_clean_work); -+ -+ mutex_lock(&kbdev->cacheclean_lock); -+ kbasep_instr_hwcnt_cacheclean(kbdev); -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ /* Wait for our condition, and any reset to complete */ -+ while (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_CLEANING) { -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ wait_event(kbdev->hwcnt.backend.cache_clean_wait, -+ kbdev->hwcnt.backend.state != -+ KBASE_INSTR_STATE_CLEANING); -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ } -+ KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state == -+ KBASE_INSTR_STATE_CLEANED); -+ -+ /* All finished and idle */ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE; -+ kbdev->hwcnt.backend.triggered = 1; -+ wake_up(&kbdev->hwcnt.backend.wait); -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ mutex_unlock(&kbdev->cacheclean_lock); -+} -+ -+void kbase_instr_hwcnt_sample_done(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_FAULT) { -+ kbdev->hwcnt.backend.triggered = 1; -+ wake_up(&kbdev->hwcnt.backend.wait); -+ } else if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_DUMPING) { -+ int ret; -+ /* Always clean and invalidate the cache after a successful dump -+ */ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_REQUEST_CLEAN; -+ ret = queue_work(kbdev->hwcnt.backend.cache_clean_wq, -+ &kbdev->hwcnt.backend.cache_clean_work); -+ KBASE_DEBUG_ASSERT(ret); -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+} -+ -+void kbase_clean_caches_done(struct kbase_device *kbdev) -+{ -+ u32 irq_mask; -+ -+ if (kbdev->hwcnt.backend.state != KBASE_INSTR_STATE_DISABLED) { -+ unsigned long flags; -+ unsigned long pm_flags; -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ /* Disable interrupt */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, pm_flags); -+ irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), -+ NULL); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), -+ irq_mask & ~CLEAN_CACHES_COMPLETED, NULL); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, pm_flags); -+ -+ /* Wakeup... */ -+ if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_CLEANING) { -+ /* Only wake if we weren't resetting */ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_CLEANED; -+ wake_up(&kbdev->hwcnt.backend.cache_clean_wait); -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ } -+} -+ -+int kbase_instr_hwcnt_wait_for_dump(struct kbase_context *kctx) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ unsigned long flags; -+ int err; -+ -+ /* Wait for dump & cacheclean to complete */ -+ wait_event(kbdev->hwcnt.backend.wait, -+ kbdev->hwcnt.backend.triggered != 0); -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_FAULT) { -+ err = -EINVAL; -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE; -+ } else { -+ /* Dump done */ -+ KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state == -+ KBASE_INSTR_STATE_IDLE); -+ err = 0; -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ -+ return err; -+} -+ -+int kbase_instr_hwcnt_clear(struct kbase_context *kctx) -+{ -+ unsigned long flags; -+ int err = -EINVAL; -+ struct kbase_device *kbdev = kctx->kbdev; -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ -+ /* Check it's the context previously set up and we're not already -+ * dumping */ -+ if (kbdev->hwcnt.kctx != kctx || kbdev->hwcnt.backend.state != -+ KBASE_INSTR_STATE_IDLE) -+ goto out; -+ -+ /* Clear the counters */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_PRFCNT_CLEAR, NULL, NULL, 0u, 0); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_PRFCNT_CLEAR, kctx); -+ -+ err = 0; -+ -+out: -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ return err; -+} -+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_clear); -+ -+int kbase_instr_backend_init(struct kbase_device *kbdev) -+{ -+ int ret = 0; -+ -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_DISABLED; -+ -+ init_waitqueue_head(&kbdev->hwcnt.backend.wait); -+ init_waitqueue_head(&kbdev->hwcnt.backend.cache_clean_wait); -+ INIT_WORK(&kbdev->hwcnt.backend.cache_clean_work, -+ kbasep_cache_clean_worker); -+ kbdev->hwcnt.backend.triggered = 0; -+ -+ kbdev->hwcnt.backend.cache_clean_wq = -+ alloc_workqueue("Mali cache cleaning workqueue", 0, 1); -+ if (NULL == kbdev->hwcnt.backend.cache_clean_wq) -+ ret = -EINVAL; -+ -+ return ret; -+} -+ -+void kbase_instr_backend_term(struct kbase_device *kbdev) -+{ -+ destroy_workqueue(kbdev->hwcnt.backend.cache_clean_wq); -+} -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_defs.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_defs.h -new file mode 100644 -index 0000000..4794672 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_defs.h -@@ -0,0 +1,58 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Backend-specific instrumentation definitions -+ */ -+ -+#ifndef _KBASE_INSTR_DEFS_H_ -+#define _KBASE_INSTR_DEFS_H_ -+ -+/* -+ * Instrumentation State Machine States -+ */ -+enum kbase_instr_state { -+ /* State where instrumentation is not active */ -+ KBASE_INSTR_STATE_DISABLED = 0, -+ /* State machine is active and ready for a command. */ -+ KBASE_INSTR_STATE_IDLE, -+ /* Hardware is currently dumping a frame. */ -+ KBASE_INSTR_STATE_DUMPING, -+ /* We've requested a clean to occur on a workqueue */ -+ KBASE_INSTR_STATE_REQUEST_CLEAN, -+ /* Hardware is currently cleaning and invalidating caches. */ -+ KBASE_INSTR_STATE_CLEANING, -+ /* Cache clean completed, and either a) a dump is complete, or -+ * b) instrumentation can now be setup. */ -+ KBASE_INSTR_STATE_CLEANED, -+ /* An error has occured during DUMPING (page fault). */ -+ KBASE_INSTR_STATE_FAULT -+}; -+ -+/* Structure used for instrumentation and HW counters dumping */ -+struct kbase_instr_backend { -+ wait_queue_head_t wait; -+ int triggered; -+ -+ enum kbase_instr_state state; -+ wait_queue_head_t cache_clean_wait; -+ struct workqueue_struct *cache_clean_wq; -+ struct work_struct cache_clean_work; -+}; -+ -+#endif /* _KBASE_INSTR_DEFS_H_ */ -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_internal.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_internal.h -new file mode 100644 -index 0000000..e96aeae ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_instr_internal.h -@@ -0,0 +1,45 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Backend-specific HW access instrumentation APIs -+ */ -+ -+#ifndef _KBASE_INSTR_INTERNAL_H_ -+#define _KBASE_INSTR_INTERNAL_H_ -+ -+/** -+ * kbasep_cache_clean_worker() - Workqueue for handling cache cleaning -+ * @data: a &struct work_struct -+ */ -+void kbasep_cache_clean_worker(struct work_struct *data); -+ -+/** -+ * kbase_clean_caches_done() - Cache clean interrupt received -+ * @kbdev: Kbase device -+ */ -+void kbase_clean_caches_done(struct kbase_device *kbdev); -+ -+/** -+ * kbase_instr_hwcnt_sample_done() - Dump complete interrupt received -+ * @kbdev: Kbase device -+ */ -+void kbase_instr_hwcnt_sample_done(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_INSTR_INTERNAL_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_irq_internal.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_irq_internal.h -new file mode 100644 -index 0000000..8781561 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_irq_internal.h -@@ -0,0 +1,39 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Backend specific IRQ APIs -+ */ -+ -+#ifndef _KBASE_IRQ_INTERNAL_H_ -+#define _KBASE_IRQ_INTERNAL_H_ -+ -+int kbase_install_interrupts(struct kbase_device *kbdev); -+ -+void kbase_release_interrupts(struct kbase_device *kbdev); -+ -+/** -+ * kbase_synchronize_irqs - Ensure that all IRQ handlers have completed -+ * execution -+ * @kbdev: The kbase device -+ */ -+void kbase_synchronize_irqs(struct kbase_device *kbdev); -+ -+int kbasep_common_test_interrupt_handlers( -+ struct kbase_device * const kbdev); -+ -+#endif /* _KBASE_IRQ_INTERNAL_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_irq_linux.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_irq_linux.c -new file mode 100644 -index 0000000..8416b80 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_irq_linux.c -@@ -0,0 +1,469 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+ -+#include -+ -+#if !defined(CONFIG_MALI_NO_MALI) -+ -+/* GPU IRQ Tags */ -+#define JOB_IRQ_TAG 0 -+#define MMU_IRQ_TAG 1 -+#define GPU_IRQ_TAG 2 -+ -+static void *kbase_tag(void *ptr, u32 tag) -+{ -+ return (void *)(((uintptr_t) ptr) | tag); -+} -+ -+static void *kbase_untag(void *ptr) -+{ -+ return (void *)(((uintptr_t) ptr) & ~3); -+} -+ -+static irqreturn_t kbase_job_irq_handler(int irq, void *data) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev = kbase_untag(data); -+ u32 val; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!kbdev->pm.backend.gpu_powered) { -+ /* GPU is turned off - IRQ is not for us */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, -+ flags); -+ return IRQ_NONE; -+ } -+ -+ val = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_STATUS), NULL); -+ -+#ifdef CONFIG_MALI_DEBUG -+ if (!kbdev->pm.backend.driver_ready_for_irqs) -+ dev_warn(kbdev->dev, "%s: irq %d irqstatus 0x%x before driver is ready\n", -+ __func__, irq, val); -+#endif /* CONFIG_MALI_DEBUG */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!val) -+ return IRQ_NONE; -+ -+ dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val); -+ -+ kbase_job_done(kbdev, val); -+ -+ return IRQ_HANDLED; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_job_irq_handler); -+ -+static irqreturn_t kbase_mmu_irq_handler(int irq, void *data) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev = kbase_untag(data); -+ u32 val; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!kbdev->pm.backend.gpu_powered) { -+ /* GPU is turned off - IRQ is not for us */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, -+ flags); -+ return IRQ_NONE; -+ } -+ -+ atomic_inc(&kbdev->faults_pending); -+ -+ val = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_STATUS), NULL); -+ -+#ifdef CONFIG_MALI_DEBUG -+ if (!kbdev->pm.backend.driver_ready_for_irqs) -+ dev_warn(kbdev->dev, "%s: irq %d irqstatus 0x%x before driver is ready\n", -+ __func__, irq, val); -+#endif /* CONFIG_MALI_DEBUG */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!val) { -+ atomic_dec(&kbdev->faults_pending); -+ return IRQ_NONE; -+ } -+ -+ dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val); -+ -+ kbase_mmu_interrupt(kbdev, val); -+ -+ atomic_dec(&kbdev->faults_pending); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t kbase_gpu_irq_handler(int irq, void *data) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev = kbase_untag(data); -+ u32 val; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!kbdev->pm.backend.gpu_powered) { -+ /* GPU is turned off - IRQ is not for us */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, -+ flags); -+ return IRQ_NONE; -+ } -+ -+ val = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_STATUS), NULL); -+ -+#ifdef CONFIG_MALI_DEBUG -+ if (!kbdev->pm.backend.driver_ready_for_irqs) -+ dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x before driver is ready\n", -+ __func__, irq, val); -+#endif /* CONFIG_MALI_DEBUG */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!val) -+ return IRQ_NONE; -+ -+ dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val); -+ -+ kbase_gpu_interrupt(kbdev, val); -+ -+ return IRQ_HANDLED; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_gpu_irq_handler); -+ -+static irq_handler_t kbase_handler_table[] = { -+ [JOB_IRQ_TAG] = kbase_job_irq_handler, -+ [MMU_IRQ_TAG] = kbase_mmu_irq_handler, -+ [GPU_IRQ_TAG] = kbase_gpu_irq_handler, -+}; -+ -+#ifdef CONFIG_MALI_DEBUG -+#define JOB_IRQ_HANDLER JOB_IRQ_TAG -+#define MMU_IRQ_HANDLER MMU_IRQ_TAG -+#define GPU_IRQ_HANDLER GPU_IRQ_TAG -+ -+/** -+ * kbase_set_custom_irq_handler - Set a custom IRQ handler -+ * @kbdev: Device for which the handler is to be registered -+ * @custom_handler: Handler to be registered -+ * @irq_type: Interrupt type -+ * -+ * Registers given interrupt handler for requested interrupt type -+ * In the case where irq handler is not specified, the default handler shall be -+ * registered -+ * -+ * Return: 0 case success, error code otherwise -+ */ -+int kbase_set_custom_irq_handler(struct kbase_device *kbdev, -+ irq_handler_t custom_handler, -+ int irq_type) -+{ -+ int result = 0; -+ irq_handler_t requested_irq_handler = NULL; -+ -+ KBASE_DEBUG_ASSERT((JOB_IRQ_HANDLER <= irq_type) && -+ (GPU_IRQ_HANDLER >= irq_type)); -+ -+ /* Release previous handler */ -+ if (kbdev->irqs[irq_type].irq) -+ free_irq(kbdev->irqs[irq_type].irq, kbase_tag(kbdev, irq_type)); -+ -+ requested_irq_handler = (NULL != custom_handler) ? custom_handler : -+ kbase_handler_table[irq_type]; -+ -+ if (0 != request_irq(kbdev->irqs[irq_type].irq, -+ requested_irq_handler, -+ kbdev->irqs[irq_type].flags | IRQF_SHARED, -+ dev_name(kbdev->dev), kbase_tag(kbdev, irq_type))) { -+ result = -EINVAL; -+ dev_err(kbdev->dev, "Can't request interrupt %d (index %d)\n", -+ kbdev->irqs[irq_type].irq, irq_type); -+#ifdef CONFIG_SPARSE_IRQ -+ dev_err(kbdev->dev, "You have CONFIG_SPARSE_IRQ support enabled - is the interrupt number correct for this configuration?\n"); -+#endif /* CONFIG_SPARSE_IRQ */ -+ } -+ -+ return result; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_set_custom_irq_handler); -+ -+/* test correct interrupt assigment and reception by cpu */ -+struct kbasep_irq_test { -+ struct hrtimer timer; -+ wait_queue_head_t wait; -+ int triggered; -+ u32 timeout; -+}; -+ -+static struct kbasep_irq_test kbasep_irq_test_data; -+ -+#define IRQ_TEST_TIMEOUT 500 -+ -+static irqreturn_t kbase_job_irq_test_handler(int irq, void *data) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev = kbase_untag(data); -+ u32 val; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!kbdev->pm.backend.gpu_powered) { -+ /* GPU is turned off - IRQ is not for us */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, -+ flags); -+ return IRQ_NONE; -+ } -+ -+ val = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_STATUS), NULL); -+ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!val) -+ return IRQ_NONE; -+ -+ dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val); -+ -+ kbasep_irq_test_data.triggered = 1; -+ wake_up(&kbasep_irq_test_data.wait); -+ -+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), val, NULL); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t kbase_mmu_irq_test_handler(int irq, void *data) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev = kbase_untag(data); -+ u32 val; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!kbdev->pm.backend.gpu_powered) { -+ /* GPU is turned off - IRQ is not for us */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, -+ flags); -+ return IRQ_NONE; -+ } -+ -+ val = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_STATUS), NULL); -+ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (!val) -+ return IRQ_NONE; -+ -+ dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val); -+ -+ kbasep_irq_test_data.triggered = 1; -+ wake_up(&kbasep_irq_test_data.wait); -+ -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), val, NULL); -+ -+ return IRQ_HANDLED; -+} -+ -+static enum hrtimer_restart kbasep_test_interrupt_timeout(struct hrtimer *timer) -+{ -+ struct kbasep_irq_test *test_data = container_of(timer, -+ struct kbasep_irq_test, timer); -+ -+ test_data->timeout = 1; -+ test_data->triggered = 1; -+ wake_up(&test_data->wait); -+ return HRTIMER_NORESTART; -+} -+ -+static int kbasep_common_test_interrupt( -+ struct kbase_device * const kbdev, u32 tag) -+{ -+ int err = 0; -+ irq_handler_t test_handler; -+ -+ u32 old_mask_val; -+ u16 mask_offset; -+ u16 rawstat_offset; -+ -+ switch (tag) { -+ case JOB_IRQ_TAG: -+ test_handler = kbase_job_irq_test_handler; -+ rawstat_offset = JOB_CONTROL_REG(JOB_IRQ_RAWSTAT); -+ mask_offset = JOB_CONTROL_REG(JOB_IRQ_MASK); -+ break; -+ case MMU_IRQ_TAG: -+ test_handler = kbase_mmu_irq_test_handler; -+ rawstat_offset = MMU_REG(MMU_IRQ_RAWSTAT); -+ mask_offset = MMU_REG(MMU_IRQ_MASK); -+ break; -+ case GPU_IRQ_TAG: -+ /* already tested by pm_driver - bail out */ -+ default: -+ return 0; -+ } -+ -+ /* store old mask */ -+ old_mask_val = kbase_reg_read(kbdev, mask_offset, NULL); -+ /* mask interrupts */ -+ kbase_reg_write(kbdev, mask_offset, 0x0, NULL); -+ -+ if (kbdev->irqs[tag].irq) { -+ /* release original handler and install test handler */ -+ if (kbase_set_custom_irq_handler(kbdev, test_handler, tag) != 0) { -+ err = -EINVAL; -+ } else { -+ kbasep_irq_test_data.timeout = 0; -+ hrtimer_init(&kbasep_irq_test_data.timer, -+ CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ kbasep_irq_test_data.timer.function = -+ kbasep_test_interrupt_timeout; -+ -+ /* trigger interrupt */ -+ kbase_reg_write(kbdev, mask_offset, 0x1, NULL); -+ kbase_reg_write(kbdev, rawstat_offset, 0x1, NULL); -+ -+ hrtimer_start(&kbasep_irq_test_data.timer, -+ HR_TIMER_DELAY_MSEC(IRQ_TEST_TIMEOUT), -+ HRTIMER_MODE_REL); -+ -+ wait_event(kbasep_irq_test_data.wait, -+ kbasep_irq_test_data.triggered != 0); -+ -+ if (kbasep_irq_test_data.timeout != 0) { -+ dev_err(kbdev->dev, "Interrupt %d (index %d) didn't reach CPU.\n", -+ kbdev->irqs[tag].irq, tag); -+ err = -EINVAL; -+ } else { -+ dev_dbg(kbdev->dev, "Interrupt %d (index %d) reached CPU.\n", -+ kbdev->irqs[tag].irq, tag); -+ } -+ -+ hrtimer_cancel(&kbasep_irq_test_data.timer); -+ kbasep_irq_test_data.triggered = 0; -+ -+ /* mask interrupts */ -+ kbase_reg_write(kbdev, mask_offset, 0x0, NULL); -+ -+ /* release test handler */ -+ free_irq(kbdev->irqs[tag].irq, kbase_tag(kbdev, tag)); -+ } -+ -+ /* restore original interrupt */ -+ if (request_irq(kbdev->irqs[tag].irq, kbase_handler_table[tag], -+ kbdev->irqs[tag].flags | IRQF_SHARED, -+ dev_name(kbdev->dev), kbase_tag(kbdev, tag))) { -+ dev_err(kbdev->dev, "Can't restore original interrupt %d (index %d)\n", -+ kbdev->irqs[tag].irq, tag); -+ err = -EINVAL; -+ } -+ } -+ /* restore old mask */ -+ kbase_reg_write(kbdev, mask_offset, old_mask_val, NULL); -+ -+ return err; -+} -+ -+int kbasep_common_test_interrupt_handlers( -+ struct kbase_device * const kbdev) -+{ -+ int err; -+ -+ init_waitqueue_head(&kbasep_irq_test_data.wait); -+ kbasep_irq_test_data.triggered = 0; -+ -+ /* A suspend won't happen during startup/insmod */ -+ kbase_pm_context_active(kbdev); -+ -+ err = kbasep_common_test_interrupt(kbdev, JOB_IRQ_TAG); -+ if (err) { -+ dev_err(kbdev->dev, "Interrupt JOB_IRQ didn't reach CPU. Check interrupt assignments.\n"); -+ goto out; -+ } -+ -+ err = kbasep_common_test_interrupt(kbdev, MMU_IRQ_TAG); -+ if (err) { -+ dev_err(kbdev->dev, "Interrupt MMU_IRQ didn't reach CPU. Check interrupt assignments.\n"); -+ goto out; -+ } -+ -+ dev_dbg(kbdev->dev, "Interrupts are correctly assigned.\n"); -+ -+ out: -+ kbase_pm_context_idle(kbdev); -+ -+ return err; -+} -+#endif /* CONFIG_MALI_DEBUG */ -+ -+int kbase_install_interrupts(struct kbase_device *kbdev) -+{ -+ u32 nr = ARRAY_SIZE(kbase_handler_table); -+ int err; -+ u32 i; -+ -+ for (i = 0; i < nr; i++) { -+ err = request_irq(kbdev->irqs[i].irq, kbase_handler_table[i], -+ kbdev->irqs[i].flags | IRQF_SHARED, -+ dev_name(kbdev->dev), -+ kbase_tag(kbdev, i)); -+ if (err) { -+ dev_err(kbdev->dev, "Can't request interrupt %d (index %d)\n", -+ kbdev->irqs[i].irq, i); -+#ifdef CONFIG_SPARSE_IRQ -+ dev_err(kbdev->dev, "You have CONFIG_SPARSE_IRQ support enabled - is the interrupt number correct for this configuration?\n"); -+#endif /* CONFIG_SPARSE_IRQ */ -+ goto release; -+ } -+ } -+ -+ return 0; -+ -+ release: -+ while (i-- > 0) -+ free_irq(kbdev->irqs[i].irq, kbase_tag(kbdev, i)); -+ -+ return err; -+} -+ -+void kbase_release_interrupts(struct kbase_device *kbdev) -+{ -+ u32 nr = ARRAY_SIZE(kbase_handler_table); -+ u32 i; -+ -+ for (i = 0; i < nr; i++) { -+ if (kbdev->irqs[i].irq) -+ free_irq(kbdev->irqs[i].irq, kbase_tag(kbdev, i)); -+ } -+} -+ -+void kbase_synchronize_irqs(struct kbase_device *kbdev) -+{ -+ u32 nr = ARRAY_SIZE(kbase_handler_table); -+ u32 i; -+ -+ for (i = 0; i < nr; i++) { -+ if (kbdev->irqs[i].irq) -+ synchronize_irq(kbdev->irqs[i].irq); -+ } -+} -+ -+#endif /* !defined(CONFIG_MALI_NO_MALI) */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c -new file mode 100644 -index 0000000..c660c80 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_as.c -@@ -0,0 +1,235 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Register backend context / address space management -+ */ -+ -+#include -+#include -+#include -+ -+/** -+ * assign_and_activate_kctx_addr_space - Assign an AS to a context -+ * @kbdev: Kbase device -+ * @kctx: Kbase context -+ * @current_as: Address Space to assign -+ * -+ * Assign an Address Space (AS) to a context, and add the context to the Policy. -+ * -+ * This includes -+ * setting up the global runpool_irq structure and the context on the AS, -+ * Activating the MMU on the AS, -+ * Allowing jobs to be submitted on the AS. -+ * -+ * Context: -+ * kbasep_js_kctx_info.jsctx_mutex held, -+ * kbasep_js_device_data.runpool_mutex held, -+ * AS transaction mutex held, -+ * Runpool IRQ lock held -+ */ -+static void assign_and_activate_kctx_addr_space(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ struct kbase_as *current_as) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ -+ lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ lockdep_assert_held(&js_devdata->runpool_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ /* Attribute handling */ -+ kbasep_js_ctx_attr_runpool_retain_ctx(kbdev, kctx); -+ -+ /* Allow it to run jobs */ -+ kbasep_js_set_submit_allowed(js_devdata, kctx); -+ -+ kbase_js_runpool_inc_context_count(kbdev, kctx); -+} -+ -+bool kbase_backend_use_ctx_sched(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ int i; -+ -+ if (kbdev->hwaccess.active_kctx == kctx) { -+ /* Context is already active */ -+ return true; -+ } -+ -+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++) { -+ if (kbdev->as_to_kctx[i] == kctx) { -+ /* Context already has ASID - mark as active */ -+ return true; -+ } -+ } -+ -+ /* Context does not have address space assigned */ -+ return false; -+} -+ -+void kbase_backend_release_ctx_irq(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ int as_nr = kctx->as_nr; -+ -+ if (as_nr == KBASEP_AS_NR_INVALID) { -+ WARN(1, "Attempting to release context without ASID\n"); -+ return; -+ } -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (atomic_read(&kctx->refcount) != 1) { -+ WARN(1, "Attempting to release active ASID\n"); -+ return; -+ } -+ -+ kbasep_js_clear_submit_allowed(&kbdev->js_data, kctx); -+ -+ kbase_ctx_sched_release_ctx(kctx); -+ kbase_js_runpool_dec_context_count(kbdev, kctx); -+} -+ -+void kbase_backend_release_ctx_noirq(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+} -+ -+int kbase_backend_find_and_release_free_address_space( -+ struct kbase_device *kbdev, struct kbase_context *kctx) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ unsigned long flags; -+ int i; -+ -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_lock(&js_devdata->runpool_mutex); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++) { -+ struct kbasep_js_kctx_info *as_js_kctx_info; -+ struct kbase_context *as_kctx; -+ -+ as_kctx = kbdev->as_to_kctx[i]; -+ as_js_kctx_info = &as_kctx->jctx.sched_info; -+ -+ /* Don't release privileged or active contexts, or contexts with -+ * jobs running. -+ * Note that a context will have at least 1 reference (which -+ * was previously taken by kbasep_js_schedule_ctx()) until -+ * descheduled. -+ */ -+ if (as_kctx && !kbase_ctx_flag(as_kctx, KCTX_PRIVILEGED) && -+ atomic_read(&as_kctx->refcount) == 1) { -+ if (!kbasep_js_runpool_retain_ctx_nolock(kbdev, -+ as_kctx)) { -+ WARN(1, "Failed to retain active context\n"); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, -+ flags); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ return KBASEP_AS_NR_INVALID; -+ } -+ -+ kbasep_js_clear_submit_allowed(js_devdata, as_kctx); -+ -+ /* Drop and retake locks to take the jsctx_mutex on the -+ * context we're about to release without violating lock -+ * ordering -+ */ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ -+ /* Release context from address space */ -+ mutex_lock(&as_js_kctx_info->ctx.jsctx_mutex); -+ mutex_lock(&js_devdata->runpool_mutex); -+ -+ kbasep_js_runpool_release_ctx_nolock(kbdev, as_kctx); -+ -+ if (!kbase_ctx_flag(as_kctx, KCTX_SCHEDULED)) { -+ kbasep_js_runpool_requeue_or_kill_ctx(kbdev, -+ as_kctx, -+ true); -+ -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&as_js_kctx_info->ctx.jsctx_mutex); -+ -+ return i; -+ } -+ -+ /* Context was retained while locks were dropped, -+ * continue looking for free AS */ -+ -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&as_js_kctx_info->ctx.jsctx_mutex); -+ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_lock(&js_devdata->runpool_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ } -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ return KBASEP_AS_NR_INVALID; -+} -+ -+bool kbase_backend_use_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int as_nr) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbase_as *new_address_space = NULL; -+ -+ js_devdata = &kbdev->js_data; -+ -+ if (kbdev->hwaccess.active_kctx == kctx) { -+ WARN(1, "Context is already scheduled in\n"); -+ return false; -+ } -+ -+ new_address_space = &kbdev->as[as_nr]; -+ -+ lockdep_assert_held(&js_devdata->runpool_mutex); -+ lockdep_assert_held(&kbdev->mmu_hw_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ assign_and_activate_kctx_addr_space(kbdev, kctx, new_address_space); -+ -+ if (kbase_ctx_flag(kctx, KCTX_PRIVILEGED)) { -+ /* We need to retain it to keep the corresponding address space -+ */ -+ kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx); -+ } -+ -+ return true; -+} -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_defs.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_defs.h -new file mode 100644 -index 0000000..08a7400 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_defs.h -@@ -0,0 +1,123 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Register-based HW access backend specific definitions -+ */ -+ -+#ifndef _KBASE_HWACCESS_GPU_DEFS_H_ -+#define _KBASE_HWACCESS_GPU_DEFS_H_ -+ -+/* SLOT_RB_SIZE must be < 256 */ -+#define SLOT_RB_SIZE 2 -+#define SLOT_RB_MASK (SLOT_RB_SIZE - 1) -+ -+/** -+ * struct rb_entry - Ringbuffer entry -+ * @katom: Atom associated with this entry -+ */ -+struct rb_entry { -+ struct kbase_jd_atom *katom; -+}; -+ -+/** -+ * struct slot_rb - Slot ringbuffer -+ * @entries: Ringbuffer entries -+ * @last_context: The last context to submit a job on this slot -+ * @read_idx: Current read index of buffer -+ * @write_idx: Current write index of buffer -+ * @job_chain_flag: Flag used to implement jobchain disambiguation -+ */ -+struct slot_rb { -+ struct rb_entry entries[SLOT_RB_SIZE]; -+ -+ struct kbase_context *last_context; -+ -+ u8 read_idx; -+ u8 write_idx; -+ -+ u8 job_chain_flag; -+}; -+ -+/** -+ * struct kbase_backend_data - GPU backend specific data for HW access layer -+ * @slot_rb: Slot ringbuffers -+ * @rmu_workaround_flag: When PRLAM-8987 is present, this flag determines -+ * whether slots 0/1 or slot 2 are currently being -+ * pulled from -+ * @scheduling_timer: The timer tick used for rescheduling jobs -+ * @timer_running: Is the timer running? The runpool_mutex must be -+ * held whilst modifying this. -+ * @suspend_timer: Is the timer suspended? Set when a suspend -+ * occurs and cleared on resume. The runpool_mutex -+ * must be held whilst modifying this. -+ * @reset_gpu: Set to a KBASE_RESET_xxx value (see comments) -+ * @reset_workq: Work queue for performing the reset -+ * @reset_work: Work item for performing the reset -+ * @reset_wait: Wait event signalled when the reset is complete -+ * @reset_timer: Timeout for soft-stops before the reset -+ * @timeouts_updated: Have timeout values just been updated? -+ * -+ * The hwaccess_lock (a spinlock) must be held when accessing this structure -+ */ -+struct kbase_backend_data { -+ struct slot_rb slot_rb[BASE_JM_MAX_NR_SLOTS]; -+ -+ bool rmu_workaround_flag; -+ -+ struct hrtimer scheduling_timer; -+ -+ bool timer_running; -+ bool suspend_timer; -+ -+ atomic_t reset_gpu; -+ -+/* The GPU reset isn't pending */ -+#define KBASE_RESET_GPU_NOT_PENDING 0 -+/* kbase_prepare_to_reset_gpu has been called */ -+#define KBASE_RESET_GPU_PREPARED 1 -+/* kbase_reset_gpu has been called - the reset will now definitely happen -+ * within the timeout period */ -+#define KBASE_RESET_GPU_COMMITTED 2 -+/* The GPU reset process is currently occuring (timeout has expired or -+ * kbasep_try_reset_gpu_early was called) */ -+#define KBASE_RESET_GPU_HAPPENING 3 -+/* Reset the GPU silently, used when resetting the GPU as part of normal -+ * behavior (e.g. when exiting protected mode). */ -+#define KBASE_RESET_GPU_SILENT 4 -+ struct workqueue_struct *reset_workq; -+ struct work_struct reset_work; -+ wait_queue_head_t reset_wait; -+ struct hrtimer reset_timer; -+ -+ bool timeouts_updated; -+}; -+ -+/** -+ * struct kbase_jd_atom_backend - GPU backend specific katom data -+ */ -+struct kbase_jd_atom_backend { -+}; -+ -+/** -+ * struct kbase_context_backend - GPU backend specific context data -+ */ -+struct kbase_context_backend { -+}; -+ -+#endif /* _KBASE_HWACCESS_GPU_DEFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_hw.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_hw.c -new file mode 100644 -index 0000000..92c36d1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_hw.c -@@ -0,0 +1,1514 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Base kernel job manager APIs -+ */ -+ -+#include -+#include -+#include -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+#include -+#endif -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define beenthere(kctx, f, a...) \ -+ dev_dbg(kctx->kbdev->dev, "%s:" f, __func__, ##a) -+ -+#if KBASE_GPU_RESET_EN -+static void kbasep_try_reset_gpu_early(struct kbase_device *kbdev); -+static void kbasep_reset_timeout_worker(struct work_struct *data); -+static enum hrtimer_restart kbasep_reset_timer_callback(struct hrtimer *timer); -+#endif /* KBASE_GPU_RESET_EN */ -+ -+static inline int kbasep_jm_is_js_free(struct kbase_device *kbdev, int js, -+ struct kbase_context *kctx) -+{ -+ return !kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT), kctx); -+} -+ -+void kbase_job_hw_submit(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, -+ int js) -+{ -+ struct kbase_context *kctx; -+ u32 cfg; -+ u64 jc_head = katom->jc; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ KBASE_DEBUG_ASSERT(katom); -+ -+ kctx = katom->kctx; -+ -+ /* Command register must be available */ -+ KBASE_DEBUG_ASSERT(kbasep_jm_is_js_free(kbdev, js, kctx)); -+ /* Affinity is not violating */ -+ kbase_js_debug_log_current_affinities(kbdev); -+ KBASE_DEBUG_ASSERT(!kbase_js_affinity_would_violate(kbdev, js, -+ katom->affinity)); -+ -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_HEAD_NEXT_LO), -+ jc_head & 0xFFFFFFFF, kctx); -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_HEAD_NEXT_HI), -+ jc_head >> 32, kctx); -+ -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_AFFINITY_NEXT_LO), -+ katom->affinity & 0xFFFFFFFF, kctx); -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_AFFINITY_NEXT_HI), -+ katom->affinity >> 32, kctx); -+ -+ /* start MMU, medium priority, cache clean/flush on end, clean/flush on -+ * start */ -+ cfg = kctx->as_nr; -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_FLUSH_REDUCTION) && -+ !(kbdev->serialize_jobs & KBASE_SERIALIZE_RESET)) -+ cfg |= JS_CONFIG_ENABLE_FLUSH_REDUCTION; -+ -+ if (0 != (katom->core_req & BASE_JD_REQ_SKIP_CACHE_START)) -+ cfg |= JS_CONFIG_START_FLUSH_NO_ACTION; -+ else -+ cfg |= JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE; -+ -+ if (0 != (katom->core_req & BASE_JD_REQ_SKIP_CACHE_END) && -+ !(kbdev->serialize_jobs & KBASE_SERIALIZE_RESET)) -+ cfg |= JS_CONFIG_END_FLUSH_NO_ACTION; -+ else -+ cfg |= JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE; -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10649)) -+ cfg |= JS_CONFIG_START_MMU; -+ -+ cfg |= JS_CONFIG_THREAD_PRI(8); -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE) && -+ (katom->atom_flags & KBASE_KATOM_FLAG_PROTECTED)) -+ cfg |= JS_CONFIG_DISABLE_DESCRIPTOR_WR_BK; -+ -+ if (kbase_hw_has_feature(kbdev, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION)) { -+ if (!kbdev->hwaccess.backend.slot_rb[js].job_chain_flag) { -+ cfg |= JS_CONFIG_JOB_CHAIN_FLAG; -+ katom->atom_flags |= KBASE_KATOM_FLAGS_JOBCHAIN; -+ kbdev->hwaccess.backend.slot_rb[js].job_chain_flag = -+ true; -+ } else { -+ katom->atom_flags &= ~KBASE_KATOM_FLAGS_JOBCHAIN; -+ kbdev->hwaccess.backend.slot_rb[js].job_chain_flag = -+ false; -+ } -+ } -+ -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_CONFIG_NEXT), cfg, kctx); -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_FLUSH_REDUCTION)) -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_FLUSH_ID_NEXT), -+ katom->flush_id, kctx); -+ -+ /* Write an approximate start timestamp. -+ * It's approximate because there might be a job in the HEAD register. -+ */ -+ katom->start_timestamp = ktime_get(); -+ -+ /* GO ! */ -+ dev_dbg(kbdev->dev, "JS: Submitting atom %p from ctx %p to js[%d] with head=0x%llx, affinity=0x%llx", -+ katom, kctx, js, jc_head, katom->affinity); -+ -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, JM_SUBMIT, kctx, katom, jc_head, js, -+ (u32) katom->affinity); -+ -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_job_slots_event( -+ GATOR_MAKE_EVENT(GATOR_JOB_SLOT_START, js), -+ kctx, kbase_jd_atom_id(kctx, katom)); -+#endif -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_CONFIG(katom, jc_head, -+ katom->affinity, cfg); -+ KBASE_TLSTREAM_TL_RET_CTX_LPU( -+ kctx, -+ &kbdev->gpu_props.props.raw_props.js_features[ -+ katom->slot_nr]); -+ KBASE_TLSTREAM_TL_RET_ATOM_AS(katom, &kbdev->as[kctx->as_nr]); -+ KBASE_TLSTREAM_TL_RET_ATOM_LPU( -+ katom, -+ &kbdev->gpu_props.props.raw_props.js_features[js], -+ "ctx_nr,atom_nr"); -+#ifdef CONFIG_GPU_TRACEPOINTS -+ if (!kbase_backend_nr_atoms_submitted(kbdev, js)) { -+ /* If this is the only job on the slot, trace it as starting */ -+ char js_string[16]; -+ -+ trace_gpu_sched_switch( -+ kbasep_make_job_slot_string(js, js_string, -+ sizeof(js_string)), -+ ktime_to_ns(katom->start_timestamp), -+ (u32)katom->kctx->id, 0, katom->work_id); -+ kbdev->hwaccess.backend.slot_rb[js].last_context = katom->kctx; -+ } -+#endif -+ kbase_timeline_job_slot_submit(kbdev, kctx, katom, js); -+ -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT), -+ JS_COMMAND_START, katom->kctx); -+} -+ -+/** -+ * kbasep_job_slot_update_head_start_timestamp - Update timestamp -+ * @kbdev: kbase device -+ * @js: job slot -+ * @end_timestamp: timestamp -+ * -+ * Update the start_timestamp of the job currently in the HEAD, based on the -+ * fact that we got an IRQ for the previous set of completed jobs. -+ * -+ * The estimate also takes into account the time the job was submitted, to -+ * work out the best estimate (which might still result in an over-estimate to -+ * the calculated time spent) -+ */ -+static void kbasep_job_slot_update_head_start_timestamp( -+ struct kbase_device *kbdev, -+ int js, -+ ktime_t end_timestamp) -+{ -+ if (kbase_backend_nr_atoms_on_slot(kbdev, js) > 0) { -+ struct kbase_jd_atom *katom; -+ ktime_t timestamp_diff; -+ /* The atom in the HEAD */ -+ katom = kbase_gpu_inspect(kbdev, js, 0); -+ -+ KBASE_DEBUG_ASSERT(katom != NULL); -+ -+ timestamp_diff = ktime_sub(end_timestamp, -+ katom->start_timestamp); -+ if (ktime_to_ns(timestamp_diff) >= 0) { -+ /* Only update the timestamp if it's a better estimate -+ * than what's currently stored. This is because our -+ * estimate that accounts for the throttle time may be -+ * too much of an overestimate */ -+ katom->start_timestamp = end_timestamp; -+ } -+ } -+} -+ -+/** -+ * kbasep_trace_tl_event_lpu_softstop - Call event_lpu_softstop timeline -+ * tracepoint -+ * @kbdev: kbase device -+ * @js: job slot -+ * -+ * Make a tracepoint call to the instrumentation module informing that -+ * softstop happened on given lpu (job slot). -+ */ -+static void kbasep_trace_tl_event_lpu_softstop(struct kbase_device *kbdev, -+ int js) -+{ -+ KBASE_TLSTREAM_TL_EVENT_LPU_SOFTSTOP( -+ &kbdev->gpu_props.props.raw_props.js_features[js]); -+} -+ -+void kbase_job_done(struct kbase_device *kbdev, u32 done) -+{ -+ unsigned long flags; -+ int i; -+ u32 count = 0; -+ ktime_t end_timestamp = ktime_get(); -+ struct kbasep_js_device_data *js_devdata; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ js_devdata = &kbdev->js_data; -+ -+ KBASE_TRACE_ADD(kbdev, JM_IRQ, NULL, NULL, 0, done); -+ -+ memset(&kbdev->slot_submit_count_irq[0], 0, -+ sizeof(kbdev->slot_submit_count_irq)); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ while (done) { -+ u32 failed = done >> 16; -+ -+ /* treat failed slots as finished slots */ -+ u32 finished = (done & 0xFFFF) | failed; -+ -+ /* Note: This is inherently unfair, as we always check -+ * for lower numbered interrupts before the higher -+ * numbered ones.*/ -+ i = ffs(finished) - 1; -+ KBASE_DEBUG_ASSERT(i >= 0); -+ -+ do { -+ int nr_done; -+ u32 active; -+ u32 completion_code = BASE_JD_EVENT_DONE;/* assume OK */ -+ u64 job_tail = 0; -+ -+ if (failed & (1u << i)) { -+ /* read out the job slot status code if the job -+ * slot reported failure */ -+ completion_code = kbase_reg_read(kbdev, -+ JOB_SLOT_REG(i, JS_STATUS), NULL); -+ -+ switch (completion_code) { -+ case BASE_JD_EVENT_STOPPED: -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_job_slots_event( -+ GATOR_MAKE_EVENT( -+ GATOR_JOB_SLOT_SOFT_STOPPED, i), -+ NULL, 0); -+#endif -+ -+ kbasep_trace_tl_event_lpu_softstop( -+ kbdev, i); -+ -+ /* Soft-stopped job - read the value of -+ * JS_TAIL so that the job chain can -+ * be resumed */ -+ job_tail = (u64)kbase_reg_read(kbdev, -+ JOB_SLOT_REG(i, JS_TAIL_LO), -+ NULL) | -+ ((u64)kbase_reg_read(kbdev, -+ JOB_SLOT_REG(i, JS_TAIL_HI), -+ NULL) << 32); -+ break; -+ case BASE_JD_EVENT_NOT_STARTED: -+ /* PRLAM-10673 can cause a TERMINATED -+ * job to come back as NOT_STARTED, but -+ * the error interrupt helps us detect -+ * it */ -+ completion_code = -+ BASE_JD_EVENT_TERMINATED; -+ /* fall through */ -+ default: -+ dev_warn(kbdev->dev, "error detected from slot %d, job status 0x%08x (%s)", -+ i, completion_code, -+ kbase_exception_name -+ (kbdev, -+ completion_code)); -+ } -+ -+ kbase_gpu_irq_evict(kbdev, i); -+ } -+ -+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), -+ done & ((1 << i) | (1 << (i + 16))), -+ NULL); -+ active = kbase_reg_read(kbdev, -+ JOB_CONTROL_REG(JOB_IRQ_JS_STATE), -+ NULL); -+ -+ if (((active >> i) & 1) == 0 && -+ (((done >> (i + 16)) & 1) == 0)) { -+ /* There is a potential race we must work -+ * around: -+ * -+ * 1. A job slot has a job in both current and -+ * next registers -+ * 2. The job in current completes -+ * successfully, the IRQ handler reads -+ * RAWSTAT and calls this function with the -+ * relevant bit set in "done" -+ * 3. The job in the next registers becomes the -+ * current job on the GPU -+ * 4. Sometime before the JOB_IRQ_CLEAR line -+ * above the job on the GPU _fails_ -+ * 5. The IRQ_CLEAR clears the done bit but not -+ * the failed bit. This atomically sets -+ * JOB_IRQ_JS_STATE. However since both jobs -+ * have now completed the relevant bits for -+ * the slot are set to 0. -+ * -+ * If we now did nothing then we'd incorrectly -+ * assume that _both_ jobs had completed -+ * successfully (since we haven't yet observed -+ * the fail bit being set in RAWSTAT). -+ * -+ * So at this point if there are no active jobs -+ * left we check to see if RAWSTAT has a failure -+ * bit set for the job slot. If it does we know -+ * that there has been a new failure that we -+ * didn't previously know about, so we make sure -+ * that we record this in active (but we wait -+ * for the next loop to deal with it). -+ * -+ * If we were handling a job failure (i.e. done -+ * has the relevant high bit set) then we know -+ * that the value read back from -+ * JOB_IRQ_JS_STATE is the correct number of -+ * remaining jobs because the failed job will -+ * have prevented any futher jobs from starting -+ * execution. -+ */ -+ u32 rawstat = kbase_reg_read(kbdev, -+ JOB_CONTROL_REG(JOB_IRQ_RAWSTAT), NULL); -+ -+ if ((rawstat >> (i + 16)) & 1) { -+ /* There is a failed job that we've -+ * missed - add it back to active */ -+ active |= (1u << i); -+ } -+ } -+ -+ dev_dbg(kbdev->dev, "Job ended with status 0x%08X\n", -+ completion_code); -+ -+ nr_done = kbase_backend_nr_atoms_submitted(kbdev, i); -+ nr_done -= (active >> i) & 1; -+ nr_done -= (active >> (i + 16)) & 1; -+ -+ if (nr_done <= 0) { -+ dev_warn(kbdev->dev, "Spurious interrupt on slot %d", -+ i); -+ -+ goto spurious; -+ } -+ -+ count += nr_done; -+ -+ while (nr_done) { -+ if (nr_done == 1) { -+ kbase_gpu_complete_hw(kbdev, i, -+ completion_code, -+ job_tail, -+ &end_timestamp); -+ kbase_jm_try_kick_all(kbdev); -+ } else { -+ /* More than one job has completed. -+ * Since this is not the last job being -+ * reported this time it must have -+ * passed. This is because the hardware -+ * will not allow further jobs in a job -+ * slot to complete until the failed job -+ * is cleared from the IRQ status. -+ */ -+ kbase_gpu_complete_hw(kbdev, i, -+ BASE_JD_EVENT_DONE, -+ 0, -+ &end_timestamp); -+ } -+ nr_done--; -+ } -+ spurious: -+ done = kbase_reg_read(kbdev, -+ JOB_CONTROL_REG(JOB_IRQ_RAWSTAT), NULL); -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10883)) { -+ /* Workaround for missing interrupt caused by -+ * PRLAM-10883 */ -+ if (((active >> i) & 1) && (0 == -+ kbase_reg_read(kbdev, -+ JOB_SLOT_REG(i, -+ JS_STATUS), NULL))) { -+ /* Force job slot to be processed again -+ */ -+ done |= (1u << i); -+ } -+ } -+ -+ failed = done >> 16; -+ finished = (done & 0xFFFF) | failed; -+ if (done) -+ end_timestamp = ktime_get(); -+ } while (finished & (1 << i)); -+ -+ kbasep_job_slot_update_head_start_timestamp(kbdev, i, -+ end_timestamp); -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+#if KBASE_GPU_RESET_EN -+ if (atomic_read(&kbdev->hwaccess.backend.reset_gpu) == -+ KBASE_RESET_GPU_COMMITTED) { -+ /* If we're trying to reset the GPU then we might be able to do -+ * it early (without waiting for a timeout) because some jobs -+ * have completed -+ */ -+ kbasep_try_reset_gpu_early(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ KBASE_TRACE_ADD(kbdev, JM_IRQ_END, NULL, NULL, 0, count); -+} -+KBASE_EXPORT_TEST_API(kbase_job_done); -+ -+static bool kbasep_soft_stop_allowed(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ bool soft_stops_allowed = true; -+ -+ if (kbase_jd_katom_is_protected(katom)) { -+ soft_stops_allowed = false; -+ } else if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408)) { -+ if ((katom->core_req & BASE_JD_REQ_T) != 0) -+ soft_stops_allowed = false; -+ } -+ return soft_stops_allowed; -+} -+ -+static bool kbasep_hard_stop_allowed(struct kbase_device *kbdev, -+ base_jd_core_req core_reqs) -+{ -+ bool hard_stops_allowed = true; -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8394)) { -+ if ((core_reqs & BASE_JD_REQ_T) != 0) -+ hard_stops_allowed = false; -+ } -+ return hard_stops_allowed; -+} -+ -+void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev, -+ int js, -+ u32 action, -+ base_jd_core_req core_reqs, -+ struct kbase_jd_atom *target_katom) -+{ -+ struct kbase_context *kctx = target_katom->kctx; -+#if KBASE_TRACE_ENABLE -+ u32 status_reg_before; -+ u64 job_in_head_before; -+ u32 status_reg_after; -+ -+ KBASE_DEBUG_ASSERT(!(action & (~JS_COMMAND_MASK))); -+ -+ /* Check the head pointer */ -+ job_in_head_before = ((u64) kbase_reg_read(kbdev, -+ JOB_SLOT_REG(js, JS_HEAD_LO), NULL)) -+ | (((u64) kbase_reg_read(kbdev, -+ JOB_SLOT_REG(js, JS_HEAD_HI), NULL)) -+ << 32); -+ status_reg_before = kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_STATUS), -+ NULL); -+#endif -+ -+ if (action == JS_COMMAND_SOFT_STOP) { -+ bool soft_stop_allowed = kbasep_soft_stop_allowed(kbdev, -+ target_katom); -+ -+ if (!soft_stop_allowed) { -+#ifdef CONFIG_MALI_DEBUG -+ dev_dbg(kbdev->dev, -+ "Attempt made to soft-stop a job that cannot be soft-stopped. core_reqs = 0x%X", -+ (unsigned int)core_reqs); -+#endif /* CONFIG_MALI_DEBUG */ -+ return; -+ } -+ -+ /* We are about to issue a soft stop, so mark the atom as having -+ * been soft stopped */ -+ target_katom->atom_flags |= KBASE_KATOM_FLAG_BEEN_SOFT_STOPPPED; -+ -+ /* Mark the point where we issue the soft-stop command */ -+ KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_ISSUE(target_katom); -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316)) { -+ int i; -+ -+ for (i = 0; -+ i < kbase_backend_nr_atoms_submitted(kbdev, js); -+ i++) { -+ struct kbase_jd_atom *katom; -+ -+ katom = kbase_gpu_inspect(kbdev, js, i); -+ -+ KBASE_DEBUG_ASSERT(katom); -+ -+ /* For HW_ISSUE_8316, only 'bad' jobs attacking -+ * the system can cause this issue: normally, -+ * all memory should be allocated in multiples -+ * of 4 pages, and growable memory should be -+ * changed size in multiples of 4 pages. -+ * -+ * Whilst such 'bad' jobs can be cleared by a -+ * GPU reset, the locking up of a uTLB entry -+ * caused by the bad job could also stall other -+ * ASs, meaning that other ASs' jobs don't -+ * complete in the 'grace' period before the -+ * reset. We don't want to lose other ASs' jobs -+ * when they would normally complete fine, so we -+ * must 'poke' the MMU regularly to help other -+ * ASs complete */ -+ kbase_as_poking_timer_retain_atom( -+ kbdev, katom->kctx, katom); -+ } -+ } -+ -+ if (kbase_hw_has_feature( -+ kbdev, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION)) { -+ action = (target_katom->atom_flags & -+ KBASE_KATOM_FLAGS_JOBCHAIN) ? -+ JS_COMMAND_SOFT_STOP_1 : -+ JS_COMMAND_SOFT_STOP_0; -+ } -+ } else if (action == JS_COMMAND_HARD_STOP) { -+ bool hard_stop_allowed = kbasep_hard_stop_allowed(kbdev, -+ core_reqs); -+ -+ if (!hard_stop_allowed) { -+ /* Jobs can be hard-stopped for the following reasons: -+ * * CFS decides the job has been running too long (and -+ * soft-stop has not occurred). In this case the GPU -+ * will be reset by CFS if the job remains on the -+ * GPU. -+ * -+ * * The context is destroyed, kbase_jd_zap_context -+ * will attempt to hard-stop the job. However it also -+ * has a watchdog which will cause the GPU to be -+ * reset if the job remains on the GPU. -+ * -+ * * An (unhandled) MMU fault occurred. As long as -+ * BASE_HW_ISSUE_8245 is defined then the GPU will be -+ * reset. -+ * -+ * All three cases result in the GPU being reset if the -+ * hard-stop fails, so it is safe to just return and -+ * ignore the hard-stop request. -+ */ -+ dev_warn(kbdev->dev, -+ "Attempt made to hard-stop a job that cannot be hard-stopped. core_reqs = 0x%X", -+ (unsigned int)core_reqs); -+ return; -+ } -+ target_katom->atom_flags |= KBASE_KATOM_FLAG_BEEN_HARD_STOPPED; -+ -+ if (kbase_hw_has_feature( -+ kbdev, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION)) { -+ action = (target_katom->atom_flags & -+ KBASE_KATOM_FLAGS_JOBCHAIN) ? -+ JS_COMMAND_HARD_STOP_1 : -+ JS_COMMAND_HARD_STOP_0; -+ } -+ } -+ -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_COMMAND), action, kctx); -+ -+#if KBASE_TRACE_ENABLE -+ status_reg_after = kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_STATUS), -+ NULL); -+ if (status_reg_after == BASE_JD_EVENT_ACTIVE) { -+ struct kbase_jd_atom *head; -+ struct kbase_context *head_kctx; -+ -+ head = kbase_gpu_inspect(kbdev, js, 0); -+ head_kctx = head->kctx; -+ -+ if (status_reg_before == BASE_JD_EVENT_ACTIVE) -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, head_kctx, -+ head, job_in_head_before, js); -+ else -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL, -+ 0, js); -+ -+ switch (action) { -+ case JS_COMMAND_SOFT_STOP: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP, head_kctx, -+ head, head->jc, js); -+ break; -+ case JS_COMMAND_SOFT_STOP_0: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_0, head_kctx, -+ head, head->jc, js); -+ break; -+ case JS_COMMAND_SOFT_STOP_1: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_1, head_kctx, -+ head, head->jc, js); -+ break; -+ case JS_COMMAND_HARD_STOP: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP, head_kctx, -+ head, head->jc, js); -+ break; -+ case JS_COMMAND_HARD_STOP_0: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_0, head_kctx, -+ head, head->jc, js); -+ break; -+ case JS_COMMAND_HARD_STOP_1: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_1, head_kctx, -+ head, head->jc, js); -+ break; -+ default: -+ BUG(); -+ break; -+ } -+ } else { -+ if (status_reg_before == BASE_JD_EVENT_ACTIVE) -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL, -+ job_in_head_before, js); -+ else -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL, -+ 0, js); -+ -+ switch (action) { -+ case JS_COMMAND_SOFT_STOP: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP, NULL, NULL, 0, -+ js); -+ break; -+ case JS_COMMAND_SOFT_STOP_0: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_0, NULL, NULL, -+ 0, js); -+ break; -+ case JS_COMMAND_SOFT_STOP_1: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_1, NULL, NULL, -+ 0, js); -+ break; -+ case JS_COMMAND_HARD_STOP: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP, NULL, NULL, 0, -+ js); -+ break; -+ case JS_COMMAND_HARD_STOP_0: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_0, NULL, NULL, -+ 0, js); -+ break; -+ case JS_COMMAND_HARD_STOP_1: -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_1, NULL, NULL, -+ 0, js); -+ break; -+ default: -+ BUG(); -+ break; -+ } -+ } -+#endif -+} -+ -+void kbase_backend_jm_kill_jobs_from_kctx(struct kbase_context *kctx) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev; -+ struct kbasep_js_device_data *js_devdata; -+ int i; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ kbdev = kctx->kbdev; -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ js_devdata = &kbdev->js_data; -+ -+ /* Cancel any remaining running jobs for this kctx */ -+ mutex_lock(&kctx->jctx.lock); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* Invalidate all jobs in context, to prevent re-submitting */ -+ for (i = 0; i < BASE_JD_ATOM_COUNT; i++) { -+ if (!work_pending(&kctx->jctx.atoms[i].work)) -+ kctx->jctx.atoms[i].event_code = -+ BASE_JD_EVENT_JOB_CANCELLED; -+ } -+ -+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++) -+ kbase_job_slot_hardstop(kctx, i, NULL); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kctx->jctx.lock); -+} -+ -+void kbase_job_slot_ctx_priority_check_locked(struct kbase_context *kctx, -+ struct kbase_jd_atom *target_katom) -+{ -+ struct kbase_device *kbdev; -+ int js = target_katom->slot_nr; -+ int priority = target_katom->sched_priority; -+ int i; -+ bool stop_sent = false; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ kbdev = kctx->kbdev; -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ for (i = 0; i < kbase_backend_nr_atoms_on_slot(kbdev, js); i++) { -+ struct kbase_jd_atom *katom; -+ -+ katom = kbase_gpu_inspect(kbdev, js, i); -+ if (!katom) -+ continue; -+ -+ if (katom->kctx != kctx) -+ continue; -+ -+ if (katom->sched_priority > priority) { -+ if (!stop_sent) -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_PRIORITY_CHANGE( -+ target_katom); -+ -+ kbase_job_slot_softstop(kbdev, js, katom); -+ stop_sent = true; -+ } -+ } -+} -+ -+struct zap_reset_data { -+ /* The stages are: -+ * 1. The timer has never been called -+ * 2. The zap has timed out, all slots are soft-stopped - the GPU reset -+ * will happen. The GPU has been reset when -+ * kbdev->hwaccess.backend.reset_waitq is signalled -+ * -+ * (-1 - The timer has been cancelled) -+ */ -+ int stage; -+ struct kbase_device *kbdev; -+ struct hrtimer timer; -+ spinlock_t lock; /* protects updates to stage member */ -+}; -+ -+static enum hrtimer_restart zap_timeout_callback(struct hrtimer *timer) -+{ -+ struct zap_reset_data *reset_data = container_of(timer, -+ struct zap_reset_data, timer); -+ struct kbase_device *kbdev = reset_data->kbdev; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&reset_data->lock, flags); -+ -+ if (reset_data->stage == -1) -+ goto out; -+ -+#if KBASE_GPU_RESET_EN -+ if (kbase_prepare_to_reset_gpu(kbdev)) { -+ dev_err(kbdev->dev, "Issueing GPU soft-reset because jobs failed to be killed (within %d ms) as part of context termination (e.g. process exit)\n", -+ ZAP_TIMEOUT); -+ kbase_reset_gpu(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ reset_data->stage = 2; -+ -+ out: -+ spin_unlock_irqrestore(&reset_data->lock, flags); -+ -+ return HRTIMER_NORESTART; -+} -+ -+void kbase_jm_wait_for_zero_jobs(struct kbase_context *kctx) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ struct zap_reset_data reset_data; -+ unsigned long flags; -+ -+ hrtimer_init_on_stack(&reset_data.timer, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ reset_data.timer.function = zap_timeout_callback; -+ -+ spin_lock_init(&reset_data.lock); -+ -+ reset_data.kbdev = kbdev; -+ reset_data.stage = 1; -+ -+ hrtimer_start(&reset_data.timer, HR_TIMER_DELAY_MSEC(ZAP_TIMEOUT), -+ HRTIMER_MODE_REL); -+ -+ /* Wait for all jobs to finish, and for the context to be not-scheduled -+ * (due to kbase_job_zap_context(), we also guarentee it's not in the JS -+ * policy queue either */ -+ wait_event(kctx->jctx.zero_jobs_wait, kctx->jctx.job_nr == 0); -+ wait_event(kctx->jctx.sched_info.ctx.is_scheduled_wait, -+ !kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ spin_lock_irqsave(&reset_data.lock, flags); -+ if (reset_data.stage == 1) { -+ /* The timer hasn't run yet - so cancel it */ -+ reset_data.stage = -1; -+ } -+ spin_unlock_irqrestore(&reset_data.lock, flags); -+ -+ hrtimer_cancel(&reset_data.timer); -+ -+ if (reset_data.stage == 2) { -+ /* The reset has already started. -+ * Wait for the reset to complete -+ */ -+ wait_event(kbdev->hwaccess.backend.reset_wait, -+ atomic_read(&kbdev->hwaccess.backend.reset_gpu) -+ == KBASE_RESET_GPU_NOT_PENDING); -+ } -+ destroy_hrtimer_on_stack(&reset_data.timer); -+ -+ dev_dbg(kbdev->dev, "Zap: Finished Context %p", kctx); -+ -+ /* Ensure that the signallers of the waitqs have finished */ -+ mutex_lock(&kctx->jctx.lock); -+ mutex_lock(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ mutex_unlock(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ mutex_unlock(&kctx->jctx.lock); -+} -+ -+u32 kbase_backend_get_current_flush_id(struct kbase_device *kbdev) -+{ -+ u32 flush_id = 0; -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_FLUSH_REDUCTION)) { -+ mutex_lock(&kbdev->pm.lock); -+ if (kbdev->pm.backend.gpu_powered) -+ flush_id = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(LATEST_FLUSH), NULL); -+ mutex_unlock(&kbdev->pm.lock); -+ } -+ -+ return flush_id; -+} -+ -+int kbase_job_slot_init(struct kbase_device *kbdev) -+{ -+#if KBASE_GPU_RESET_EN -+ kbdev->hwaccess.backend.reset_workq = alloc_workqueue( -+ "Mali reset workqueue", 0, 1); -+ if (NULL == kbdev->hwaccess.backend.reset_workq) -+ return -EINVAL; -+ -+ KBASE_DEBUG_ASSERT(0 == -+ object_is_on_stack(&kbdev->hwaccess.backend.reset_work)); -+ INIT_WORK(&kbdev->hwaccess.backend.reset_work, -+ kbasep_reset_timeout_worker); -+ -+ hrtimer_init(&kbdev->hwaccess.backend.reset_timer, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ kbdev->hwaccess.backend.reset_timer.function = -+ kbasep_reset_timer_callback; -+#endif -+ -+ return 0; -+} -+KBASE_EXPORT_TEST_API(kbase_job_slot_init); -+ -+void kbase_job_slot_halt(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+void kbase_job_slot_term(struct kbase_device *kbdev) -+{ -+#if KBASE_GPU_RESET_EN -+ destroy_workqueue(kbdev->hwaccess.backend.reset_workq); -+#endif -+} -+KBASE_EXPORT_TEST_API(kbase_job_slot_term); -+ -+#if KBASE_GPU_RESET_EN -+/** -+ * kbasep_check_for_afbc_on_slot() - Check whether AFBC is in use on this slot -+ * @kbdev: kbase device pointer -+ * @kctx: context to check against -+ * @js: slot to check -+ * @target_katom: An atom to check, or NULL if all atoms from @kctx on -+ * slot @js should be checked -+ * -+ * This checks are based upon parameters that would normally be passed to -+ * kbase_job_slot_hardstop(). -+ * -+ * In the event of @target_katom being NULL, this will check the last jobs that -+ * are likely to be running on the slot to see if a) they belong to kctx, and -+ * so would be stopped, and b) whether they have AFBC -+ * -+ * In that case, It's guaranteed that a job currently executing on the HW with -+ * AFBC will be detected. However, this is a conservative check because it also -+ * detects jobs that have just completed too. -+ * -+ * Return: true when hard-stop _might_ stop an afbc atom, else false. -+ */ -+static bool kbasep_check_for_afbc_on_slot(struct kbase_device *kbdev, -+ struct kbase_context *kctx, int js, -+ struct kbase_jd_atom *target_katom) -+{ -+ bool ret = false; -+ int i; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ /* When we have an atom the decision can be made straight away. */ -+ if (target_katom) -+ return !!(target_katom->core_req & BASE_JD_REQ_FS_AFBC); -+ -+ /* Otherwise, we must chweck the hardware to see if it has atoms from -+ * this context with AFBC. */ -+ for (i = 0; i < kbase_backend_nr_atoms_on_slot(kbdev, js); i++) { -+ struct kbase_jd_atom *katom; -+ -+ katom = kbase_gpu_inspect(kbdev, js, i); -+ if (!katom) -+ continue; -+ -+ /* Ignore atoms from other contexts, they won't be stopped when -+ * we use this for checking if we should hard-stop them */ -+ if (katom->kctx != kctx) -+ continue; -+ -+ /* An atom on this slot and this context: check for AFBC */ -+ if (katom->core_req & BASE_JD_REQ_FS_AFBC) { -+ ret = true; -+ break; -+ } -+ } -+ -+ return ret; -+} -+#endif /* KBASE_GPU_RESET_EN */ -+ -+/** -+ * kbase_job_slot_softstop_swflags - Soft-stop a job with flags -+ * @kbdev: The kbase device -+ * @js: The job slot to soft-stop -+ * @target_katom: The job that should be soft-stopped (or NULL for any job) -+ * @sw_flags: Flags to pass in about the soft-stop -+ * -+ * Context: -+ * The job slot lock must be held when calling this function. -+ * The job slot must not already be in the process of being soft-stopped. -+ * -+ * Soft-stop the specified job slot, with extra information about the stop -+ * -+ * Where possible any job in the next register is evicted before the soft-stop. -+ */ -+void kbase_job_slot_softstop_swflags(struct kbase_device *kbdev, int js, -+ struct kbase_jd_atom *target_katom, u32 sw_flags) -+{ -+ KBASE_DEBUG_ASSERT(!(sw_flags & JS_COMMAND_MASK)); -+ kbase_backend_soft_hard_stop_slot(kbdev, NULL, js, target_katom, -+ JS_COMMAND_SOFT_STOP | sw_flags); -+} -+ -+/** -+ * kbase_job_slot_softstop - Soft-stop the specified job slot -+ * @kbdev: The kbase device -+ * @js: The job slot to soft-stop -+ * @target_katom: The job that should be soft-stopped (or NULL for any job) -+ * Context: -+ * The job slot lock must be held when calling this function. -+ * The job slot must not already be in the process of being soft-stopped. -+ * -+ * Where possible any job in the next register is evicted before the soft-stop. -+ */ -+void kbase_job_slot_softstop(struct kbase_device *kbdev, int js, -+ struct kbase_jd_atom *target_katom) -+{ -+ kbase_job_slot_softstop_swflags(kbdev, js, target_katom, 0u); -+} -+ -+/** -+ * kbase_job_slot_hardstop - Hard-stop the specified job slot -+ * @kctx: The kbase context that contains the job(s) that should -+ * be hard-stopped -+ * @js: The job slot to hard-stop -+ * @target_katom: The job that should be hard-stopped (or NULL for all -+ * jobs from the context) -+ * Context: -+ * The job slot lock must be held when calling this function. -+ */ -+void kbase_job_slot_hardstop(struct kbase_context *kctx, int js, -+ struct kbase_jd_atom *target_katom) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ bool stopped; -+#if KBASE_GPU_RESET_EN -+ /* We make the check for AFBC before evicting/stopping atoms. Note -+ * that no other thread can modify the slots whilst we have the -+ * hwaccess_lock. */ -+ int needs_workaround_for_afbc = -+ kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_T76X_3542) -+ && kbasep_check_for_afbc_on_slot(kbdev, kctx, js, -+ target_katom); -+#endif -+ -+ stopped = kbase_backend_soft_hard_stop_slot(kbdev, kctx, js, -+ target_katom, -+ JS_COMMAND_HARD_STOP); -+#if KBASE_GPU_RESET_EN -+ if (stopped && (kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_8401) || -+ kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_9510) || -+ needs_workaround_for_afbc)) { -+ /* MIDBASE-2916 if a fragment job with AFBC encoding is -+ * hardstopped, ensure to do a soft reset also in order to -+ * clear the GPU status. -+ * Workaround for HW issue 8401 has an issue,so after -+ * hard-stopping just reset the GPU. This will ensure that the -+ * jobs leave the GPU.*/ -+ if (kbase_prepare_to_reset_gpu_locked(kbdev)) { -+ dev_err(kbdev->dev, "Issueing GPU soft-reset after hard stopping due to hardware issue"); -+ kbase_reset_gpu_locked(kbdev); -+ } -+ } -+#endif -+} -+ -+/** -+ * kbase_job_check_enter_disjoint - potentiall enter disjoint mode -+ * @kbdev: kbase device -+ * @action: the event which has occurred -+ * @core_reqs: core requirements of the atom -+ * @target_katom: the atom which is being affected -+ * -+ * For a certain soft/hard-stop action, work out whether to enter disjoint -+ * state. -+ * -+ * This does not register multiple disjoint events if the atom has already -+ * started a disjoint period -+ * -+ * @core_reqs can be supplied as 0 if the atom had not started on the hardware -+ * (and so a 'real' soft/hard-stop was not required, but it still interrupted -+ * flow, perhaps on another context) -+ * -+ * kbase_job_check_leave_disjoint() should be used to end the disjoint -+ * state when the soft/hard-stop action is complete -+ */ -+void kbase_job_check_enter_disjoint(struct kbase_device *kbdev, u32 action, -+ base_jd_core_req core_reqs, struct kbase_jd_atom *target_katom) -+{ -+ u32 hw_action = action & JS_COMMAND_MASK; -+ -+ /* For hard-stop, don't enter if hard-stop not allowed */ -+ if (hw_action == JS_COMMAND_HARD_STOP && -+ !kbasep_hard_stop_allowed(kbdev, core_reqs)) -+ return; -+ -+ /* For soft-stop, don't enter if soft-stop not allowed, or isn't -+ * causing disjoint */ -+ if (hw_action == JS_COMMAND_SOFT_STOP && -+ !(kbasep_soft_stop_allowed(kbdev, target_katom) && -+ (action & JS_COMMAND_SW_CAUSES_DISJOINT))) -+ return; -+ -+ /* Nothing to do if already logged disjoint state on this atom */ -+ if (target_katom->atom_flags & KBASE_KATOM_FLAG_IN_DISJOINT) -+ return; -+ -+ target_katom->atom_flags |= KBASE_KATOM_FLAG_IN_DISJOINT; -+ kbase_disjoint_state_up(kbdev); -+} -+ -+/** -+ * kbase_job_check_enter_disjoint - potentially leave disjoint state -+ * @kbdev: kbase device -+ * @target_katom: atom which is finishing -+ * -+ * Work out whether to leave disjoint state when finishing an atom that was -+ * originated by kbase_job_check_enter_disjoint(). -+ */ -+void kbase_job_check_leave_disjoint(struct kbase_device *kbdev, -+ struct kbase_jd_atom *target_katom) -+{ -+ if (target_katom->atom_flags & KBASE_KATOM_FLAG_IN_DISJOINT) { -+ target_katom->atom_flags &= ~KBASE_KATOM_FLAG_IN_DISJOINT; -+ kbase_disjoint_state_down(kbdev); -+ } -+} -+ -+ -+#if KBASE_GPU_RESET_EN -+static void kbase_debug_dump_registers(struct kbase_device *kbdev) -+{ -+ int i; -+ -+ kbase_io_history_dump(kbdev); -+ -+ dev_err(kbdev->dev, "Register state:"); -+ dev_err(kbdev->dev, " GPU_IRQ_RAWSTAT=0x%08x GPU_STATUS=0x%08x", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_STATUS), NULL)); -+ dev_err(kbdev->dev, " JOB_IRQ_RAWSTAT=0x%08x JOB_IRQ_JS_STATE=0x%08x", -+ kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_RAWSTAT), NULL), -+ kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_JS_STATE), NULL)); -+ for (i = 0; i < 3; i++) { -+ dev_err(kbdev->dev, " JS%d_STATUS=0x%08x JS%d_HEAD_LO=0x%08x", -+ i, kbase_reg_read(kbdev, JOB_SLOT_REG(i, JS_STATUS), -+ NULL), -+ i, kbase_reg_read(kbdev, JOB_SLOT_REG(i, JS_HEAD_LO), -+ NULL)); -+ } -+ dev_err(kbdev->dev, " MMU_IRQ_RAWSTAT=0x%08x GPU_FAULTSTATUS=0x%08x", -+ kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_RAWSTAT), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTSTATUS), NULL)); -+ dev_err(kbdev->dev, " GPU_IRQ_MASK=0x%08x JOB_IRQ_MASK=0x%08x MMU_IRQ_MASK=0x%08x", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), NULL), -+ kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), NULL), -+ kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), NULL)); -+ dev_err(kbdev->dev, " PWR_OVERRIDE0=0x%08x PWR_OVERRIDE1=0x%08x", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(PWR_OVERRIDE0), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(PWR_OVERRIDE1), NULL)); -+ dev_err(kbdev->dev, " SHADER_CONFIG=0x%08x L2_MMU_CONFIG=0x%08x", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(SHADER_CONFIG), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(L2_MMU_CONFIG), NULL)); -+ dev_err(kbdev->dev, " TILER_CONFIG=0x%08x JM_CONFIG=0x%08x", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(TILER_CONFIG), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG(JM_CONFIG), NULL)); -+} -+ -+static void kbasep_reset_timeout_worker(struct work_struct *data) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev; -+ ktime_t end_timestamp = ktime_get(); -+ struct kbasep_js_device_data *js_devdata; -+ bool try_schedule = false; -+ bool silent = false; -+ u32 max_loops = KBASE_CLEAN_CACHE_MAX_LOOPS; -+ -+ KBASE_DEBUG_ASSERT(data); -+ -+ kbdev = container_of(data, struct kbase_device, -+ hwaccess.backend.reset_work); -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ js_devdata = &kbdev->js_data; -+ -+ if (atomic_read(&kbdev->hwaccess.backend.reset_gpu) == -+ KBASE_RESET_GPU_SILENT) -+ silent = true; -+ -+ KBASE_TRACE_ADD(kbdev, JM_BEGIN_RESET_WORKER, NULL, NULL, 0u, 0); -+ -+ /* Suspend vinstr. -+ * This call will block until vinstr is suspended. */ -+ kbase_vinstr_suspend(kbdev->vinstr_ctx); -+ -+ /* Make sure the timer has completed - this cannot be done from -+ * interrupt context, so this cannot be done within -+ * kbasep_try_reset_gpu_early. */ -+ hrtimer_cancel(&kbdev->hwaccess.backend.reset_timer); -+ -+ if (kbase_pm_context_active_handle_suspend(kbdev, -+ KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) { -+ /* This would re-activate the GPU. Since it's already idle, -+ * there's no need to reset it */ -+ atomic_set(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_NOT_PENDING); -+ kbase_disjoint_state_down(kbdev); -+ wake_up(&kbdev->hwaccess.backend.reset_wait); -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+ return; -+ } -+ -+ KBASE_DEBUG_ASSERT(kbdev->irq_reset_flush == false); -+ -+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags); -+ spin_lock(&kbdev->hwaccess_lock); -+ spin_lock(&kbdev->mmu_mask_change); -+ /* We're about to flush out the IRQs and their bottom half's */ -+ kbdev->irq_reset_flush = true; -+ -+ /* Disable IRQ to avoid IRQ handlers to kick in after releasing the -+ * spinlock; this also clears any outstanding interrupts */ -+ kbase_pm_disable_interrupts_nolock(kbdev); -+ -+ spin_unlock(&kbdev->mmu_mask_change); -+ spin_unlock(&kbdev->hwaccess_lock); -+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags); -+ -+ /* Ensure that any IRQ handlers have finished -+ * Must be done without any locks IRQ handlers will take */ -+ kbase_synchronize_irqs(kbdev); -+ -+ /* Flush out any in-flight work items */ -+ kbase_flush_mmu_wqs(kbdev); -+ -+ /* The flush has completed so reset the active indicator */ -+ kbdev->irq_reset_flush = false; -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_TMIX_8463)) { -+ /* Ensure that L2 is not transitioning when we send the reset -+ * command */ -+ while (--max_loops && kbase_pm_get_trans_cores(kbdev, -+ KBASE_PM_CORE_L2)) -+ ; -+ -+ WARN(!max_loops, "L2 power transition timed out while trying to reset\n"); -+ } -+ -+ mutex_lock(&kbdev->pm.lock); -+ /* We hold the pm lock, so there ought to be a current policy */ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.pm_current_policy); -+ -+ /* All slot have been soft-stopped and we've waited -+ * SOFT_STOP_RESET_TIMEOUT for the slots to clear, at this point we -+ * assume that anything that is still left on the GPU is stuck there and -+ * we'll kill it when we reset the GPU */ -+ -+ if (!silent) -+ dev_err(kbdev->dev, "Resetting GPU (allowing up to %d ms)", -+ RESET_TIMEOUT); -+ -+ /* Output the state of some interesting registers to help in the -+ * debugging of GPU resets */ -+ if (!silent) -+ kbase_debug_dump_registers(kbdev); -+ -+ /* Complete any jobs that were still on the GPU */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbdev->protected_mode = false; -+ kbase_backend_reset(kbdev, &end_timestamp); -+ kbase_pm_metrics_update(kbdev, NULL); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ /* Reset the GPU */ -+ kbase_pm_init_hw(kbdev, 0); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_ctx_sched_restore_all_as(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ kbase_pm_enable_interrupts(kbdev); -+ -+ atomic_set(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_NOT_PENDING); -+ -+ kbase_disjoint_state_down(kbdev); -+ -+ wake_up(&kbdev->hwaccess.backend.reset_wait); -+ if (!silent) -+ dev_err(kbdev->dev, "Reset complete"); -+ -+ if (js_devdata->nr_contexts_pullable > 0 && !kbdev->poweroff_pending) -+ try_schedule = true; -+ -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ mutex_lock(&kbdev->pm.lock); -+ -+ /* Find out what cores are required now */ -+ kbase_pm_update_cores_state(kbdev); -+ -+ /* Synchronously request and wait for those cores, because if -+ * instrumentation is enabled it would need them immediately. */ -+ kbase_pm_check_transitions_sync(kbdev); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ -+ /* Try submitting some jobs to restart processing */ -+ if (try_schedule) { -+ KBASE_TRACE_ADD(kbdev, JM_SUBMIT_AFTER_RESET, NULL, NULL, 0u, -+ 0); -+ kbase_js_sched_all(kbdev); -+ } -+ -+ /* Process any pending slot updates */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_backend_slot_update(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ kbase_pm_context_idle(kbdev); -+ -+ /* Release vinstr */ -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+ -+ KBASE_TRACE_ADD(kbdev, JM_END_RESET_WORKER, NULL, NULL, 0u, 0); -+} -+ -+static enum hrtimer_restart kbasep_reset_timer_callback(struct hrtimer *timer) -+{ -+ struct kbase_device *kbdev = container_of(timer, struct kbase_device, -+ hwaccess.backend.reset_timer); -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ /* Reset still pending? */ -+ if (atomic_cmpxchg(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_COMMITTED, KBASE_RESET_GPU_HAPPENING) == -+ KBASE_RESET_GPU_COMMITTED) -+ queue_work(kbdev->hwaccess.backend.reset_workq, -+ &kbdev->hwaccess.backend.reset_work); -+ -+ return HRTIMER_NORESTART; -+} -+ -+/* -+ * If all jobs are evicted from the GPU then we can reset the GPU -+ * immediately instead of waiting for the timeout to elapse -+ */ -+ -+static void kbasep_try_reset_gpu_early_locked(struct kbase_device *kbdev) -+{ -+ int i; -+ int pending_jobs = 0; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ /* Count the number of jobs */ -+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++) -+ pending_jobs += kbase_backend_nr_atoms_submitted(kbdev, i); -+ -+ if (pending_jobs > 0) { -+ /* There are still jobs on the GPU - wait */ -+ return; -+ } -+ -+ /* To prevent getting incorrect registers when dumping failed job, -+ * skip early reset. -+ */ -+ if (kbdev->job_fault_debug != false) -+ return; -+ -+ /* Check that the reset has been committed to (i.e. kbase_reset_gpu has -+ * been called), and that no other thread beat this thread to starting -+ * the reset */ -+ if (atomic_cmpxchg(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_COMMITTED, KBASE_RESET_GPU_HAPPENING) != -+ KBASE_RESET_GPU_COMMITTED) { -+ /* Reset has already occurred */ -+ return; -+ } -+ -+ queue_work(kbdev->hwaccess.backend.reset_workq, -+ &kbdev->hwaccess.backend.reset_work); -+} -+ -+static void kbasep_try_reset_gpu_early(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbasep_try_reset_gpu_early_locked(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+/** -+ * kbase_prepare_to_reset_gpu_locked - Prepare for resetting the GPU -+ * @kbdev: kbase device -+ * -+ * This function just soft-stops all the slots to ensure that as many jobs as -+ * possible are saved. -+ * -+ * Return: -+ * The function returns a boolean which should be interpreted as follows: -+ * true - Prepared for reset, kbase_reset_gpu_locked should be called. -+ * false - Another thread is performing a reset, kbase_reset_gpu should -+ * not be called. -+ */ -+bool kbase_prepare_to_reset_gpu_locked(struct kbase_device *kbdev) -+{ -+ int i; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ if (atomic_cmpxchg(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_NOT_PENDING, -+ KBASE_RESET_GPU_PREPARED) != -+ KBASE_RESET_GPU_NOT_PENDING) { -+ /* Some other thread is already resetting the GPU */ -+ return false; -+ } -+ -+ kbase_disjoint_state_up(kbdev); -+ -+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++) -+ kbase_job_slot_softstop(kbdev, i, NULL); -+ -+ return true; -+} -+ -+bool kbase_prepare_to_reset_gpu(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ bool ret; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ ret = kbase_prepare_to_reset_gpu_locked(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return ret; -+} -+KBASE_EXPORT_TEST_API(kbase_prepare_to_reset_gpu); -+ -+/* -+ * This function should be called after kbase_prepare_to_reset_gpu if it -+ * returns true. It should never be called without a corresponding call to -+ * kbase_prepare_to_reset_gpu. -+ * -+ * After this function is called (or not called if kbase_prepare_to_reset_gpu -+ * returned false), the caller should wait for -+ * kbdev->hwaccess.backend.reset_waitq to be signalled to know when the reset -+ * has completed. -+ */ -+void kbase_reset_gpu(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ /* Note this is an assert/atomic_set because it is a software issue for -+ * a race to be occuring here */ -+ KBASE_DEBUG_ASSERT(atomic_read(&kbdev->hwaccess.backend.reset_gpu) == -+ KBASE_RESET_GPU_PREPARED); -+ atomic_set(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_COMMITTED); -+ -+ dev_err(kbdev->dev, "Preparing to soft-reset GPU: Waiting (upto %d ms) for all jobs to complete soft-stop\n", -+ kbdev->reset_timeout_ms); -+ -+ hrtimer_start(&kbdev->hwaccess.backend.reset_timer, -+ HR_TIMER_DELAY_MSEC(kbdev->reset_timeout_ms), -+ HRTIMER_MODE_REL); -+ -+ /* Try resetting early */ -+ kbasep_try_reset_gpu_early(kbdev); -+} -+KBASE_EXPORT_TEST_API(kbase_reset_gpu); -+ -+void kbase_reset_gpu_locked(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ /* Note this is an assert/atomic_set because it is a software issue for -+ * a race to be occuring here */ -+ KBASE_DEBUG_ASSERT(atomic_read(&kbdev->hwaccess.backend.reset_gpu) == -+ KBASE_RESET_GPU_PREPARED); -+ atomic_set(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_COMMITTED); -+ -+ dev_err(kbdev->dev, "Preparing to soft-reset GPU: Waiting (upto %d ms) for all jobs to complete soft-stop\n", -+ kbdev->reset_timeout_ms); -+ hrtimer_start(&kbdev->hwaccess.backend.reset_timer, -+ HR_TIMER_DELAY_MSEC(kbdev->reset_timeout_ms), -+ HRTIMER_MODE_REL); -+ -+ /* Try resetting early */ -+ kbasep_try_reset_gpu_early_locked(kbdev); -+} -+ -+void kbase_reset_gpu_silent(struct kbase_device *kbdev) -+{ -+ if (atomic_cmpxchg(&kbdev->hwaccess.backend.reset_gpu, -+ KBASE_RESET_GPU_NOT_PENDING, -+ KBASE_RESET_GPU_SILENT) != -+ KBASE_RESET_GPU_NOT_PENDING) { -+ /* Some other thread is already resetting the GPU */ -+ return; -+ } -+ -+ kbase_disjoint_state_up(kbdev); -+ -+ queue_work(kbdev->hwaccess.backend.reset_workq, -+ &kbdev->hwaccess.backend.reset_work); -+} -+ -+bool kbase_reset_gpu_active(struct kbase_device *kbdev) -+{ -+ if (atomic_read(&kbdev->hwaccess.backend.reset_gpu) == -+ KBASE_RESET_GPU_NOT_PENDING) -+ return false; -+ -+ return true; -+} -+#endif /* KBASE_GPU_RESET_EN */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_internal.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_internal.h -new file mode 100644 -index 0000000..1f382b3 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_internal.h -@@ -0,0 +1,164 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Job Manager backend-specific low-level APIs. -+ */ -+ -+#ifndef _KBASE_JM_HWACCESS_H_ -+#define _KBASE_JM_HWACCESS_H_ -+ -+#include -+#include -+#include -+ -+#include -+ -+/** -+ * kbase_job_submit_nolock() - Submit a job to a certain job-slot -+ * @kbdev: Device pointer -+ * @katom: Atom to submit -+ * @js: Job slot to submit on -+ * -+ * The caller must check kbasep_jm_is_submit_slots_free() != false before -+ * calling this. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must hold the hwaccess_lock -+ */ -+void kbase_job_submit_nolock(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, int js); -+ -+/** -+ * kbase_job_done_slot() - Complete the head job on a particular job-slot -+ * @kbdev: Device pointer -+ * @s: Job slot -+ * @completion_code: Completion code of job reported by GPU -+ * @job_tail: Job tail address reported by GPU -+ * @end_timestamp: Timestamp of job completion -+ */ -+void kbase_job_done_slot(struct kbase_device *kbdev, int s, u32 completion_code, -+ u64 job_tail, ktime_t *end_timestamp); -+ -+#ifdef CONFIG_GPU_TRACEPOINTS -+static inline char *kbasep_make_job_slot_string(int js, char *js_string, -+ size_t js_size) -+{ -+ snprintf(js_string, js_size, "job_slot_%i", js); -+ return js_string; -+} -+#endif -+ -+/** -+ * kbase_job_hw_submit() - Submit a job to the GPU -+ * @kbdev: Device pointer -+ * @katom: Atom to submit -+ * @js: Job slot to submit on -+ * -+ * The caller must check kbasep_jm_is_submit_slots_free() != false before -+ * calling this. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must hold the hwaccess_lock -+ */ -+void kbase_job_hw_submit(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, -+ int js); -+ -+/** -+ * kbasep_job_slot_soft_or_hard_stop_do_action() - Perform a soft or hard stop -+ * on the specified atom -+ * @kbdev: Device pointer -+ * @js: Job slot to stop on -+ * @action: The action to perform, either JSn_COMMAND_HARD_STOP or -+ * JSn_COMMAND_SOFT_STOP -+ * @core_reqs: Core requirements of atom to stop -+ * @target_katom: Atom to stop -+ * -+ * The following locking conditions are made on the caller: -+ * - it must hold the hwaccess_lock -+ */ -+void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev, -+ int js, -+ u32 action, -+ base_jd_core_req core_reqs, -+ struct kbase_jd_atom *target_katom); -+ -+/** -+ * kbase_backend_soft_hard_stop_slot() - Soft or hard stop jobs on a given job -+ * slot belonging to a given context. -+ * @kbdev: Device pointer -+ * @kctx: Context pointer. May be NULL -+ * @katom: Specific atom to stop. May be NULL -+ * @js: Job slot to hard stop -+ * @action: The action to perform, either JSn_COMMAND_HARD_STOP or -+ * JSn_COMMAND_SOFT_STOP -+ * -+ * If no context is provided then all jobs on the slot will be soft or hard -+ * stopped. -+ * -+ * If a katom is provided then only that specific atom will be stopped. In this -+ * case the kctx parameter is ignored. -+ * -+ * Jobs that are on the slot but are not yet on the GPU will be unpulled and -+ * returned to the job scheduler. -+ * -+ * Return: true if an atom was stopped, false otherwise -+ */ -+bool kbase_backend_soft_hard_stop_slot(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js, -+ struct kbase_jd_atom *katom, -+ u32 action); -+ -+/** -+ * kbase_job_slot_init - Initialise job slot framework -+ * @kbdev: Device pointer -+ * -+ * Called on driver initialisation -+ * -+ * Return: 0 on success -+ */ -+int kbase_job_slot_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_job_slot_halt - Halt the job slot framework -+ * @kbdev: Device pointer -+ * -+ * Should prevent any further job slot processing -+ */ -+void kbase_job_slot_halt(struct kbase_device *kbdev); -+ -+/** -+ * kbase_job_slot_term - Terminate job slot framework -+ * @kbdev: Device pointer -+ * -+ * Called on driver termination -+ */ -+void kbase_job_slot_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_gpu_cacheclean - Cause a GPU cache clean & flush -+ * @kbdev: Device pointer -+ * -+ * Caller must not be in IRQ context -+ */ -+void kbase_gpu_cacheclean(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_JM_HWACCESS_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_rb.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_rb.c -new file mode 100644 -index 0000000..a41e7b5 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_rb.c -@@ -0,0 +1,1947 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Register-based HW access backend specific APIs -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Return whether the specified ringbuffer is empty. HW access lock must be -+ * held */ -+#define SLOT_RB_EMPTY(rb) (rb->write_idx == rb->read_idx) -+/* Return number of atoms currently in the specified ringbuffer. HW access lock -+ * must be held */ -+#define SLOT_RB_ENTRIES(rb) (int)(s8)(rb->write_idx - rb->read_idx) -+ -+static void kbase_gpu_release_atom(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, -+ ktime_t *end_timestamp); -+ -+/** -+ * kbase_gpu_enqueue_atom - Enqueue an atom in the HW access ringbuffer -+ * @kbdev: Device pointer -+ * @katom: Atom to enqueue -+ * -+ * Context: Caller must hold the HW access lock -+ */ -+static void kbase_gpu_enqueue_atom(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ struct slot_rb *rb = &kbdev->hwaccess.backend.slot_rb[katom->slot_nr]; -+ -+ WARN_ON(SLOT_RB_ENTRIES(rb) >= SLOT_RB_SIZE); -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ rb->entries[rb->write_idx & SLOT_RB_MASK].katom = katom; -+ rb->write_idx++; -+ -+ katom->gpu_rb_state = KBASE_ATOM_GPU_RB_WAITING_BLOCKED; -+} -+ -+/** -+ * kbase_gpu_dequeue_atom - Remove an atom from the HW access ringbuffer, once -+ * it has been completed -+ * @kbdev: Device pointer -+ * @js: Job slot to remove atom from -+ * @end_timestamp: Pointer to timestamp of atom completion. May be NULL, in -+ * which case current time will be used. -+ * -+ * Context: Caller must hold the HW access lock -+ * -+ * Return: Atom removed from ringbuffer -+ */ -+static struct kbase_jd_atom *kbase_gpu_dequeue_atom(struct kbase_device *kbdev, -+ int js, -+ ktime_t *end_timestamp) -+{ -+ struct slot_rb *rb = &kbdev->hwaccess.backend.slot_rb[js]; -+ struct kbase_jd_atom *katom; -+ -+ if (SLOT_RB_EMPTY(rb)) { -+ WARN(1, "GPU ringbuffer unexpectedly empty\n"); -+ return NULL; -+ } -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ katom = rb->entries[rb->read_idx & SLOT_RB_MASK].katom; -+ -+ kbase_gpu_release_atom(kbdev, katom, end_timestamp); -+ -+ rb->read_idx++; -+ -+ katom->gpu_rb_state = KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB; -+ -+ kbase_js_debug_log_current_affinities(kbdev); -+ -+ return katom; -+} -+ -+struct kbase_jd_atom *kbase_gpu_inspect(struct kbase_device *kbdev, int js, -+ int idx) -+{ -+ struct slot_rb *rb = &kbdev->hwaccess.backend.slot_rb[js]; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if ((SLOT_RB_ENTRIES(rb) - 1) < idx) -+ return NULL; /* idx out of range */ -+ -+ return rb->entries[(rb->read_idx + idx) & SLOT_RB_MASK].katom; -+} -+ -+struct kbase_jd_atom *kbase_backend_inspect_head(struct kbase_device *kbdev, -+ int js) -+{ -+ return kbase_gpu_inspect(kbdev, js, 0); -+} -+ -+struct kbase_jd_atom *kbase_backend_inspect_tail(struct kbase_device *kbdev, -+ int js) -+{ -+ struct slot_rb *rb = &kbdev->hwaccess.backend.slot_rb[js]; -+ -+ if (SLOT_RB_EMPTY(rb)) -+ return NULL; -+ -+ return rb->entries[(rb->write_idx - 1) & SLOT_RB_MASK].katom; -+} -+ -+/** -+ * kbase_gpu_atoms_submitted - Inspect whether a slot has any atoms currently -+ * on the GPU -+ * @kbdev: Device pointer -+ * @js: Job slot to inspect -+ * -+ * Return: true if there are atoms on the GPU for slot js, -+ * false otherwise -+ */ -+static bool kbase_gpu_atoms_submitted(struct kbase_device *kbdev, int js) -+{ -+ int i; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ for (i = 0; i < SLOT_RB_SIZE; i++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, i); -+ -+ if (!katom) -+ return false; -+ if (katom->gpu_rb_state == KBASE_ATOM_GPU_RB_SUBMITTED || -+ katom->gpu_rb_state == KBASE_ATOM_GPU_RB_READY) -+ return true; -+ } -+ -+ return false; -+} -+ -+/** -+ * kbase_gpu_atoms_submitted_any() - Inspect whether there are any atoms -+ * currently on the GPU -+ * @kbdev: Device pointer -+ * -+ * Return: true if there are any atoms on the GPU, false otherwise -+ */ -+static bool kbase_gpu_atoms_submitted_any(struct kbase_device *kbdev) -+{ -+ int js; -+ int i; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ for (i = 0; i < SLOT_RB_SIZE; i++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, i); -+ -+ if (katom && katom->gpu_rb_state == KBASE_ATOM_GPU_RB_SUBMITTED) -+ return true; -+ } -+ } -+ return false; -+} -+ -+int kbase_backend_nr_atoms_submitted(struct kbase_device *kbdev, int js) -+{ -+ int nr = 0; -+ int i; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ for (i = 0; i < SLOT_RB_SIZE; i++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, i); -+ -+ if (katom && (katom->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_SUBMITTED)) -+ nr++; -+ } -+ -+ return nr; -+} -+ -+int kbase_backend_nr_atoms_on_slot(struct kbase_device *kbdev, int js) -+{ -+ int nr = 0; -+ int i; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ for (i = 0; i < SLOT_RB_SIZE; i++) { -+ if (kbase_gpu_inspect(kbdev, js, i)) -+ nr++; -+ } -+ -+ return nr; -+} -+ -+static int kbase_gpu_nr_atoms_on_slot_min(struct kbase_device *kbdev, int js, -+ enum kbase_atom_gpu_rb_state min_rb_state) -+{ -+ int nr = 0; -+ int i; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ for (i = 0; i < SLOT_RB_SIZE; i++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, i); -+ -+ if (katom && (katom->gpu_rb_state >= min_rb_state)) -+ nr++; -+ } -+ -+ return nr; -+} -+ -+/** -+ * check_secure_atom - Check if the given atom is in the given secure state and -+ * has a ringbuffer state of at least -+ * KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION -+ * @katom: Atom pointer -+ * @secure: Desired secure state -+ * -+ * Return: true if atom is in the given state, false otherwise -+ */ -+static bool check_secure_atom(struct kbase_jd_atom *katom, bool secure) -+{ -+ if (katom->gpu_rb_state >= -+ KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION && -+ ((kbase_jd_katom_is_protected(katom) && secure) || -+ (!kbase_jd_katom_is_protected(katom) && !secure))) -+ return true; -+ -+ return false; -+} -+ -+/** -+ * kbase_gpu_check_secure_atoms - Check if there are any atoms in the given -+ * secure state in the ringbuffers of at least -+ * state -+ * KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE -+ * @kbdev: Device pointer -+ * @secure: Desired secure state -+ * -+ * Return: true if any atoms are in the given state, false otherwise -+ */ -+static bool kbase_gpu_check_secure_atoms(struct kbase_device *kbdev, -+ bool secure) -+{ -+ int js, i; -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ for (i = 0; i < SLOT_RB_SIZE; i++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, -+ js, i); -+ -+ if (katom) { -+ if (check_secure_atom(katom, secure)) -+ return true; -+ } -+ } -+ } -+ -+ return false; -+} -+ -+int kbase_backend_slot_free(struct kbase_device *kbdev, int js) -+{ -+ if (atomic_read(&kbdev->hwaccess.backend.reset_gpu) != -+ KBASE_RESET_GPU_NOT_PENDING) { -+ /* The GPU is being reset - so prevent submission */ -+ return 0; -+ } -+ -+ return SLOT_RB_SIZE - kbase_backend_nr_atoms_on_slot(kbdev, js); -+} -+ -+ -+static void kbasep_js_job_check_deref_cores(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom); -+ -+static bool kbasep_js_job_check_ref_cores(struct kbase_device *kbdev, -+ int js, -+ struct kbase_jd_atom *katom) -+{ -+ /* The most recently checked affinity. Having this at this scope allows -+ * us to guarantee that we've checked the affinity in this function -+ * call. -+ */ -+ u64 recently_chosen_affinity = 0; -+ bool chosen_affinity = false; -+ bool retry; -+ -+ do { -+ retry = false; -+ -+ /* NOTE: The following uses a number of FALLTHROUGHs to optimize -+ * the calls to this function. Ending of the function is -+ * indicated by BREAK OUT */ -+ switch (katom->coreref_state) { -+ /* State when job is first attempted to be run */ -+ case KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED: -+ KBASE_DEBUG_ASSERT(katom->affinity == 0); -+ -+ /* Compute affinity */ -+ if (false == kbase_js_choose_affinity( -+ &recently_chosen_affinity, kbdev, katom, -+ js)) { -+ /* No cores are currently available */ -+ /* *** BREAK OUT: No state transition *** */ -+ break; -+ } -+ -+ chosen_affinity = true; -+ -+ /* Request the cores */ -+ kbase_pm_request_cores(kbdev, -+ katom->core_req & BASE_JD_REQ_T, -+ recently_chosen_affinity); -+ -+ katom->affinity = recently_chosen_affinity; -+ -+ /* Proceed to next state */ -+ katom->coreref_state = -+ KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES: -+ { -+ enum kbase_pm_cores_ready cores_ready; -+ -+ KBASE_DEBUG_ASSERT(katom->affinity != 0 || -+ (katom->core_req & BASE_JD_REQ_T)); -+ -+ cores_ready = kbase_pm_register_inuse_cores( -+ kbdev, -+ katom->core_req & BASE_JD_REQ_T, -+ katom->affinity); -+ if (cores_ready == KBASE_NEW_AFFINITY) { -+ /* Affinity no longer valid - return to -+ * previous state */ -+ kbasep_js_job_check_deref_cores(kbdev, -+ katom); -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, -+ JS_CORE_REF_REGISTER_INUSE_FAILED, -+ katom->kctx, katom, -+ katom->jc, js, -+ (u32) katom->affinity); -+ /* *** BREAK OUT: Return to previous -+ * state, retry *** */ -+ retry = true; -+ break; -+ } -+ if (cores_ready == KBASE_CORES_NOT_READY) { -+ /* Stay in this state and return, to -+ * retry at this state later */ -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, -+ JS_CORE_REF_REGISTER_INUSE_FAILED, -+ katom->kctx, katom, -+ katom->jc, js, -+ (u32) katom->affinity); -+ /* *** BREAK OUT: No state transition -+ * *** */ -+ break; -+ } -+ /* Proceed to next state */ -+ katom->coreref_state = -+ KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY; -+ } -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY: -+ KBASE_DEBUG_ASSERT(katom->affinity != 0 || -+ (katom->core_req & BASE_JD_REQ_T)); -+ -+ /* Optimize out choosing the affinity twice in the same -+ * function call */ -+ if (chosen_affinity == false) { -+ /* See if the affinity changed since a previous -+ * call. */ -+ if (false == kbase_js_choose_affinity( -+ &recently_chosen_affinity, -+ kbdev, katom, js)) { -+ /* No cores are currently available */ -+ kbasep_js_job_check_deref_cores(kbdev, -+ katom); -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, -+ JS_CORE_REF_REQUEST_ON_RECHECK_FAILED, -+ katom->kctx, katom, -+ katom->jc, js, -+ (u32) recently_chosen_affinity); -+ /* *** BREAK OUT: Transition to lower -+ * state *** */ -+ break; -+ } -+ chosen_affinity = true; -+ } -+ -+ /* Now see if this requires a different set of cores */ -+ if (recently_chosen_affinity != katom->affinity) { -+ enum kbase_pm_cores_ready cores_ready; -+ -+ kbase_pm_request_cores(kbdev, -+ katom->core_req & BASE_JD_REQ_T, -+ recently_chosen_affinity); -+ -+ /* Register new cores whilst we still hold the -+ * old ones, to minimize power transitions */ -+ cores_ready = -+ kbase_pm_register_inuse_cores(kbdev, -+ katom->core_req & BASE_JD_REQ_T, -+ recently_chosen_affinity); -+ kbasep_js_job_check_deref_cores(kbdev, katom); -+ -+ /* Fixup the state that was reduced by -+ * deref_cores: */ -+ katom->coreref_state = -+ KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY; -+ katom->affinity = recently_chosen_affinity; -+ if (cores_ready == KBASE_NEW_AFFINITY) { -+ /* Affinity no longer valid - return to -+ * previous state */ -+ katom->coreref_state = -+ KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES; -+ -+ kbasep_js_job_check_deref_cores(kbdev, -+ katom); -+ -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, -+ JS_CORE_REF_REGISTER_INUSE_FAILED, -+ katom->kctx, katom, -+ katom->jc, js, -+ (u32) katom->affinity); -+ /* *** BREAK OUT: Return to previous -+ * state, retry *** */ -+ retry = true; -+ break; -+ } -+ /* Now might be waiting for powerup again, with -+ * a new affinity */ -+ if (cores_ready == KBASE_CORES_NOT_READY) { -+ /* Return to previous state */ -+ katom->coreref_state = -+ KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES; -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, -+ JS_CORE_REF_REGISTER_ON_RECHECK_FAILED, -+ katom->kctx, katom, -+ katom->jc, js, -+ (u32) katom->affinity); -+ /* *** BREAK OUT: Transition to lower -+ * state *** */ -+ break; -+ } -+ } -+ /* Proceed to next state */ -+ katom->coreref_state = -+ KBASE_ATOM_COREREF_STATE_CHECK_AFFINITY_VIOLATIONS; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ case KBASE_ATOM_COREREF_STATE_CHECK_AFFINITY_VIOLATIONS: -+ KBASE_DEBUG_ASSERT(katom->affinity != 0 || -+ (katom->core_req & BASE_JD_REQ_T)); -+ KBASE_DEBUG_ASSERT(katom->affinity == -+ recently_chosen_affinity); -+ -+ /* Note: this is where the caller must've taken the -+ * hwaccess_lock */ -+ -+ /* Check for affinity violations - if there are any, -+ * then we just ask the caller to requeue and try again -+ * later */ -+ if (kbase_js_affinity_would_violate(kbdev, js, -+ katom->affinity) != false) { -+ /* Return to previous state */ -+ katom->coreref_state = -+ KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY; -+ /* *** BREAK OUT: Transition to lower state *** -+ */ -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, -+ JS_CORE_REF_AFFINITY_WOULD_VIOLATE, -+ katom->kctx, katom, katom->jc, js, -+ (u32) katom->affinity); -+ break; -+ } -+ -+ /* No affinity violations would result, so the cores are -+ * ready */ -+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_READY; -+ /* *** BREAK OUT: Cores Ready *** */ -+ break; -+ -+ default: -+ KBASE_DEBUG_ASSERT_MSG(false, -+ "Unhandled kbase_atom_coreref_state %d", -+ katom->coreref_state); -+ break; -+ } -+ } while (retry != false); -+ -+ return (katom->coreref_state == KBASE_ATOM_COREREF_STATE_READY); -+} -+ -+static void kbasep_js_job_check_deref_cores(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(katom != NULL); -+ -+ switch (katom->coreref_state) { -+ case KBASE_ATOM_COREREF_STATE_READY: -+ /* State where atom was submitted to the HW - just proceed to -+ * power-down */ -+ KBASE_DEBUG_ASSERT(katom->affinity != 0 || -+ (katom->core_req & BASE_JD_REQ_T)); -+ -+ /* *** FALLTHROUGH *** */ -+ -+ case KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY: -+ /* State where cores were registered */ -+ KBASE_DEBUG_ASSERT(katom->affinity != 0 || -+ (katom->core_req & BASE_JD_REQ_T)); -+ kbase_pm_release_cores(kbdev, katom->core_req & BASE_JD_REQ_T, -+ katom->affinity); -+ -+ break; -+ -+ case KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES: -+ /* State where cores were requested, but not registered */ -+ KBASE_DEBUG_ASSERT(katom->affinity != 0 || -+ (katom->core_req & BASE_JD_REQ_T)); -+ kbase_pm_unrequest_cores(kbdev, katom->core_req & BASE_JD_REQ_T, -+ katom->affinity); -+ break; -+ -+ case KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED: -+ /* Initial state - nothing required */ -+ KBASE_DEBUG_ASSERT(katom->affinity == 0); -+ break; -+ -+ default: -+ KBASE_DEBUG_ASSERT_MSG(false, -+ "Unhandled coreref_state: %d", -+ katom->coreref_state); -+ break; -+ } -+ -+ katom->affinity = 0; -+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED; -+} -+ -+static void kbasep_js_job_check_deref_cores_nokatom(struct kbase_device *kbdev, -+ base_jd_core_req core_req, u64 affinity, -+ enum kbase_atom_coreref_state coreref_state) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ switch (coreref_state) { -+ case KBASE_ATOM_COREREF_STATE_READY: -+ /* State where atom was submitted to the HW - just proceed to -+ * power-down */ -+ KBASE_DEBUG_ASSERT(affinity != 0 || -+ (core_req & BASE_JD_REQ_T)); -+ -+ /* *** FALLTHROUGH *** */ -+ -+ case KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY: -+ /* State where cores were registered */ -+ KBASE_DEBUG_ASSERT(affinity != 0 || -+ (core_req & BASE_JD_REQ_T)); -+ kbase_pm_release_cores(kbdev, core_req & BASE_JD_REQ_T, -+ affinity); -+ -+ break; -+ -+ case KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES: -+ /* State where cores were requested, but not registered */ -+ KBASE_DEBUG_ASSERT(affinity != 0 || -+ (core_req & BASE_JD_REQ_T)); -+ kbase_pm_unrequest_cores(kbdev, core_req & BASE_JD_REQ_T, -+ affinity); -+ break; -+ -+ case KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED: -+ /* Initial state - nothing required */ -+ KBASE_DEBUG_ASSERT(affinity == 0); -+ break; -+ -+ default: -+ KBASE_DEBUG_ASSERT_MSG(false, -+ "Unhandled coreref_state: %d", -+ coreref_state); -+ break; -+ } -+} -+ -+static void kbase_gpu_release_atom(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, -+ ktime_t *end_timestamp) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ -+ switch (katom->gpu_rb_state) { -+ case KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB: -+ /* Should be impossible */ -+ WARN(1, "Attempting to release atom not in ringbuffer\n"); -+ break; -+ -+ case KBASE_ATOM_GPU_RB_SUBMITTED: -+ /* Inform power management at start/finish of atom so it can -+ * update its GPU utilisation metrics. Mark atom as not -+ * submitted beforehand. */ -+ katom->gpu_rb_state = KBASE_ATOM_GPU_RB_READY; -+ kbase_pm_metrics_update(kbdev, end_timestamp); -+ -+ if (katom->core_req & BASE_JD_REQ_PERMON) -+ kbase_pm_release_gpu_cycle_counter_nolock(kbdev); -+ /* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */ -+ -+ KBASE_TLSTREAM_TL_NRET_ATOM_LPU(katom, -+ &kbdev->gpu_props.props.raw_props.js_features -+ [katom->slot_nr]); -+ KBASE_TLSTREAM_TL_NRET_ATOM_AS(katom, &kbdev->as[kctx->as_nr]); -+ KBASE_TLSTREAM_TL_NRET_CTX_LPU(kctx, -+ &kbdev->gpu_props.props.raw_props.js_features -+ [katom->slot_nr]); -+ -+ case KBASE_ATOM_GPU_RB_READY: -+ /* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_AFFINITY: -+ kbase_js_affinity_release_slot_cores(kbdev, katom->slot_nr, -+ katom->affinity); -+ /* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE: -+ break; -+ -+ case KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION: -+ if (katom->protected_state.enter != -+ KBASE_ATOM_ENTER_PROTECTED_CHECK || -+ katom->protected_state.exit != -+ KBASE_ATOM_EXIT_PROTECTED_CHECK) -+ kbdev->protected_mode_transition = false; -+ -+ if (kbase_jd_katom_is_protected(katom) && -+ (katom->protected_state.enter == -+ KBASE_ATOM_ENTER_PROTECTED_IDLE_L2)) { -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+ -+ /* Go back to configured model for IPA */ -+ kbase_ipa_model_use_configured_locked(kbdev); -+ } -+ -+ -+ /* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV: -+ /* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_BLOCKED: -+ /* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_RETURN_TO_JS: -+ break; -+ } -+ -+ katom->gpu_rb_state = KBASE_ATOM_GPU_RB_WAITING_BLOCKED; -+ katom->protected_state.exit = KBASE_ATOM_EXIT_PROTECTED_CHECK; -+} -+ -+static void kbase_gpu_mark_atom_for_return(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ kbase_gpu_release_atom(kbdev, katom, NULL); -+ katom->gpu_rb_state = KBASE_ATOM_GPU_RB_RETURN_TO_JS; -+} -+ -+static inline bool kbase_gpu_rmu_workaround(struct kbase_device *kbdev, int js) -+{ -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ bool slot_busy[3]; -+ -+ if (!kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987)) -+ return true; -+ slot_busy[0] = kbase_gpu_nr_atoms_on_slot_min(kbdev, 0, -+ KBASE_ATOM_GPU_RB_WAITING_AFFINITY); -+ slot_busy[1] = kbase_gpu_nr_atoms_on_slot_min(kbdev, 1, -+ KBASE_ATOM_GPU_RB_WAITING_AFFINITY); -+ slot_busy[2] = kbase_gpu_nr_atoms_on_slot_min(kbdev, 2, -+ KBASE_ATOM_GPU_RB_WAITING_AFFINITY); -+ -+ if ((js == 2 && !(slot_busy[0] || slot_busy[1])) || -+ (js != 2 && !slot_busy[2])) -+ return true; -+ -+ /* Don't submit slot 2 atom while GPU has jobs on slots 0/1 */ -+ if (js == 2 && (kbase_gpu_atoms_submitted(kbdev, 0) || -+ kbase_gpu_atoms_submitted(kbdev, 1) || -+ backend->rmu_workaround_flag)) -+ return false; -+ -+ /* Don't submit slot 0/1 atom while GPU has jobs on slot 2 */ -+ if (js != 2 && (kbase_gpu_atoms_submitted(kbdev, 2) || -+ !backend->rmu_workaround_flag)) -+ return false; -+ -+ backend->rmu_workaround_flag = !backend->rmu_workaround_flag; -+ -+ return true; -+} -+ -+/** -+ * other_slots_busy - Determine if any job slots other than @js are currently -+ * running atoms -+ * @kbdev: Device pointer -+ * @js: Job slot -+ * -+ * Return: true if any slots other than @js are busy, false otherwise -+ */ -+static inline bool other_slots_busy(struct kbase_device *kbdev, int js) -+{ -+ int slot; -+ -+ for (slot = 0; slot < kbdev->gpu_props.num_job_slots; slot++) { -+ if (slot == js) -+ continue; -+ -+ if (kbase_gpu_nr_atoms_on_slot_min(kbdev, slot, -+ KBASE_ATOM_GPU_RB_SUBMITTED)) -+ return true; -+ } -+ -+ return false; -+} -+ -+static inline bool kbase_gpu_in_protected_mode(struct kbase_device *kbdev) -+{ -+ return kbdev->protected_mode; -+} -+ -+static int kbase_gpu_protected_mode_enter(struct kbase_device *kbdev) -+{ -+ int err = -EINVAL; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ WARN_ONCE(!kbdev->protected_ops, -+ "Cannot enter protected mode: protected callbacks not specified.\n"); -+ -+ /* -+ * When entering into protected mode, we must ensure that the -+ * GPU is not operating in coherent mode as well. This is to -+ * ensure that no protected memory can be leaked. -+ */ -+ if (kbdev->system_coherency == COHERENCY_ACE) -+ kbase_cache_set_coherency_mode(kbdev, COHERENCY_ACE_LITE); -+ -+ if (kbdev->protected_ops) { -+ /* Switch GPU to protected mode */ -+ err = kbdev->protected_ops->protected_mode_enable( -+ kbdev->protected_dev); -+ -+ if (err) -+ dev_warn(kbdev->dev, "Failed to enable protected mode: %d\n", -+ err); -+ else -+ kbdev->protected_mode = true; -+ } -+ -+ return err; -+} -+ -+static int kbase_gpu_protected_mode_reset(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ WARN_ONCE(!kbdev->protected_ops, -+ "Cannot exit protected mode: protected callbacks not specified.\n"); -+ -+ if (!kbdev->protected_ops) -+ return -EINVAL; -+ -+ /* The protected mode disable callback will be called as part of reset -+ */ -+ kbase_reset_gpu_silent(kbdev); -+ -+ return 0; -+} -+ -+static int kbase_jm_enter_protected_mode(struct kbase_device *kbdev, -+ struct kbase_jd_atom **katom, int idx, int js) -+{ -+ int err = 0; -+ -+ switch (katom[idx]->protected_state.enter) { -+ case KBASE_ATOM_ENTER_PROTECTED_CHECK: -+ KBASE_TLSTREAM_AUX_PROTECTED_ENTER_START(kbdev); -+ /* The checks in KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV -+ * should ensure that we are not already transitiong, and that -+ * there are no atoms currently on the GPU. */ -+ WARN_ON(kbdev->protected_mode_transition); -+ WARN_ON(kbase_gpu_atoms_submitted_any(kbdev)); -+ -+ kbdev->protected_mode_transition = true; -+ katom[idx]->protected_state.enter = -+ KBASE_ATOM_ENTER_PROTECTED_VINSTR; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_ENTER_PROTECTED_VINSTR: -+ if (kbase_vinstr_try_suspend(kbdev->vinstr_ctx) < 0) { -+ /* -+ * We can't switch now because -+ * the vinstr core state switch -+ * is not done yet. -+ */ -+ return -EAGAIN; -+ } -+ -+ /* Use generic model for IPA in protected mode */ -+ kbase_ipa_model_use_fallback_locked(kbdev); -+ -+ /* Once reaching this point GPU must be -+ * switched to protected mode or vinstr -+ * re-enabled. */ -+ -+ /* -+ * Not in correct mode, begin protected mode switch. -+ * Entering protected mode requires us to power down the L2, -+ * and drop out of fully coherent mode. -+ */ -+ katom[idx]->protected_state.enter = -+ KBASE_ATOM_ENTER_PROTECTED_IDLE_L2; -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_ENTER_PROTECTED_IDLE_L2: -+ /* Avoid unnecessary waiting on non-ACE platforms. */ -+ if (kbdev->current_gpu_coherency_mode == COHERENCY_ACE) { -+ if (kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_L2) || -+ kbase_pm_get_trans_cores(kbdev, KBASE_PM_CORE_L2)) { -+ /* -+ * The L2 is still powered, wait for all the users to -+ * finish with it before doing the actual reset. -+ */ -+ return -EAGAIN; -+ } -+ } -+ -+ katom[idx]->protected_state.enter = -+ KBASE_ATOM_ENTER_PROTECTED_FINISHED; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_ENTER_PROTECTED_FINISHED: -+ -+ /* No jobs running, so we can switch GPU mode right now. */ -+ err = kbase_gpu_protected_mode_enter(kbdev); -+ -+ /* -+ * Regardless of result, we are no longer transitioning -+ * the GPU. -+ */ -+ kbdev->protected_mode_transition = false; -+ KBASE_TLSTREAM_AUX_PROTECTED_ENTER_END(kbdev); -+ if (err) { -+ /* -+ * Failed to switch into protected mode, resume -+ * vinstr core and fail atom. -+ */ -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+ katom[idx]->event_code = BASE_JD_EVENT_JOB_INVALID; -+ kbase_gpu_mark_atom_for_return(kbdev, katom[idx]); -+ /* Only return if head atom or previous atom -+ * already removed - as atoms must be returned -+ * in order. */ -+ if (idx == 0 || katom[0]->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB) { -+ kbase_gpu_dequeue_atom(kbdev, js, NULL); -+ kbase_jm_return_atom_to_js(kbdev, katom[idx]); -+ } -+ -+ /* Go back to configured model for IPA */ -+ kbase_ipa_model_use_configured_locked(kbdev); -+ -+ return -EINVAL; -+ } -+ -+ /* Protected mode sanity checks. */ -+ KBASE_DEBUG_ASSERT_MSG( -+ kbase_jd_katom_is_protected(katom[idx]) == -+ kbase_gpu_in_protected_mode(kbdev), -+ "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", -+ kbase_jd_katom_is_protected(katom[idx]), -+ kbase_gpu_in_protected_mode(kbdev)); -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_READY; -+ } -+ -+ return 0; -+} -+ -+static int kbase_jm_exit_protected_mode(struct kbase_device *kbdev, -+ struct kbase_jd_atom **katom, int idx, int js) -+{ -+ int err = 0; -+ -+ -+ switch (katom[idx]->protected_state.exit) { -+ case KBASE_ATOM_EXIT_PROTECTED_CHECK: -+ KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_START(kbdev); -+ /* The checks in KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV -+ * should ensure that we are not already transitiong, and that -+ * there are no atoms currently on the GPU. */ -+ WARN_ON(kbdev->protected_mode_transition); -+ WARN_ON(kbase_gpu_atoms_submitted_any(kbdev)); -+ -+ /* -+ * Exiting protected mode requires a reset, but first the L2 -+ * needs to be powered down to ensure it's not active when the -+ * reset is issued. -+ */ -+ katom[idx]->protected_state.exit = -+ KBASE_ATOM_EXIT_PROTECTED_IDLE_L2; -+ -+ kbdev->protected_mode_transition = true; -+ kbase_pm_update_cores_state_nolock(kbdev); -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ case KBASE_ATOM_EXIT_PROTECTED_IDLE_L2: -+ if (kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_L2) || -+ kbase_pm_get_trans_cores(kbdev, KBASE_PM_CORE_L2)) { -+ /* -+ * The L2 is still powered, wait for all the users to -+ * finish with it before doing the actual reset. -+ */ -+ return -EAGAIN; -+ } -+ katom[idx]->protected_state.exit = -+ KBASE_ATOM_EXIT_PROTECTED_RESET; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_EXIT_PROTECTED_RESET: -+ /* Issue the reset to the GPU */ -+ err = kbase_gpu_protected_mode_reset(kbdev); -+ -+ if (err) { -+ kbdev->protected_mode_transition = false; -+ -+ /* Failed to exit protected mode, fail atom */ -+ katom[idx]->event_code = BASE_JD_EVENT_JOB_INVALID; -+ kbase_gpu_mark_atom_for_return(kbdev, katom[idx]); -+ /* Only return if head atom or previous atom -+ * already removed - as atoms must be returned -+ * in order */ -+ if (idx == 0 || katom[0]->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB) { -+ kbase_gpu_dequeue_atom(kbdev, js, NULL); -+ kbase_jm_return_atom_to_js(kbdev, katom[idx]); -+ } -+ -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+ -+ /* Use generic model for IPA in protected mode */ -+ kbase_ipa_model_use_fallback_locked(kbdev); -+ -+ return -EINVAL; -+ } -+ -+ katom[idx]->protected_state.exit = -+ KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT: -+ /* A GPU reset is issued when exiting protected mode. Once the -+ * reset is done all atoms' state will also be reset. For this -+ * reason, if the atom is still in this state we can safely -+ * say that the reset has not completed i.e., we have not -+ * finished exiting protected mode yet. -+ */ -+ return -EAGAIN; -+ } -+ -+ return 0; -+} -+ -+void kbase_backend_slot_update(struct kbase_device *kbdev) -+{ -+ int js; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ struct kbase_jd_atom *katom[2]; -+ int idx; -+ -+ katom[0] = kbase_gpu_inspect(kbdev, js, 0); -+ katom[1] = kbase_gpu_inspect(kbdev, js, 1); -+ WARN_ON(katom[1] && !katom[0]); -+ -+ for (idx = 0; idx < SLOT_RB_SIZE; idx++) { -+ bool cores_ready; -+ int ret; -+ -+ if (!katom[idx]) -+ continue; -+ -+ switch (katom[idx]->gpu_rb_state) { -+ case KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB: -+ /* Should be impossible */ -+ WARN(1, "Attempting to update atom not in ringbuffer\n"); -+ break; -+ -+ case KBASE_ATOM_GPU_RB_WAITING_BLOCKED: -+ if (katom[idx]->atom_flags & -+ KBASE_KATOM_FLAG_X_DEP_BLOCKED) -+ break; -+ -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV: -+ if (kbase_gpu_check_secure_atoms(kbdev, -+ !kbase_jd_katom_is_protected( -+ katom[idx]))) -+ break; -+ -+ if ((idx == 1) && (kbase_jd_katom_is_protected( -+ katom[0]) != -+ kbase_jd_katom_is_protected( -+ katom[1]))) -+ break; -+ -+ if (kbdev->protected_mode_transition) -+ break; -+ -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION: -+ -+ /* -+ * Exiting protected mode must be done before -+ * the references on the cores are taken as -+ * a power down the L2 is required which -+ * can't happen after the references for this -+ * atom are taken. -+ */ -+ -+ if (!kbase_gpu_in_protected_mode(kbdev) && -+ kbase_jd_katom_is_protected(katom[idx])) { -+ /* Atom needs to transition into protected mode. */ -+ ret = kbase_jm_enter_protected_mode(kbdev, -+ katom, idx, js); -+ if (ret) -+ break; -+ } else if (kbase_gpu_in_protected_mode(kbdev) && -+ !kbase_jd_katom_is_protected(katom[idx])) { -+ /* Atom needs to transition out of protected mode. */ -+ ret = kbase_jm_exit_protected_mode(kbdev, -+ katom, idx, js); -+ if (ret) -+ break; -+ } -+ katom[idx]->protected_state.exit = -+ KBASE_ATOM_EXIT_PROTECTED_CHECK; -+ -+ /* Atom needs no protected mode transition. */ -+ -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE: -+ if (katom[idx]->will_fail_event_code) { -+ kbase_gpu_mark_atom_for_return(kbdev, -+ katom[idx]); -+ /* Set EVENT_DONE so this atom will be -+ completed, not unpulled. */ -+ katom[idx]->event_code = -+ BASE_JD_EVENT_DONE; -+ /* Only return if head atom or previous -+ * atom already removed - as atoms must -+ * be returned in order. */ -+ if (idx == 0 || katom[0]->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB) { -+ kbase_gpu_dequeue_atom(kbdev, js, NULL); -+ kbase_jm_return_atom_to_js(kbdev, katom[idx]); -+ } -+ break; -+ } -+ -+ cores_ready = -+ kbasep_js_job_check_ref_cores(kbdev, js, -+ katom[idx]); -+ -+ if (katom[idx]->event_code == -+ BASE_JD_EVENT_PM_EVENT) { -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_RETURN_TO_JS; -+ break; -+ } -+ -+ if (!cores_ready) -+ break; -+ -+ kbase_js_affinity_retain_slot_cores(kbdev, js, -+ katom[idx]->affinity); -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_WAITING_AFFINITY; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_WAITING_AFFINITY: -+ if (!kbase_gpu_rmu_workaround(kbdev, js)) -+ break; -+ -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_READY; -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_READY: -+ -+ if (idx == 1) { -+ /* Only submit if head atom or previous -+ * atom already submitted */ -+ if ((katom[0]->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_SUBMITTED && -+ katom[0]->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB)) -+ break; -+ -+ /* If intra-slot serialization in use -+ * then don't submit atom to NEXT slot -+ */ -+ if (kbdev->serialize_jobs & -+ KBASE_SERIALIZE_INTRA_SLOT) -+ break; -+ } -+ -+ /* If inter-slot serialization in use then don't -+ * submit atom if any other slots are in use */ -+ if ((kbdev->serialize_jobs & -+ KBASE_SERIALIZE_INTER_SLOT) && -+ other_slots_busy(kbdev, js)) -+ break; -+ -+ if ((kbdev->serialize_jobs & -+ KBASE_SERIALIZE_RESET) && -+ kbase_reset_gpu_active(kbdev)) -+ break; -+ -+ /* Check if this job needs the cycle counter -+ * enabled before submission */ -+ if (katom[idx]->core_req & BASE_JD_REQ_PERMON) -+ kbase_pm_request_gpu_cycle_counter_l2_is_on( -+ kbdev); -+ -+ kbase_job_hw_submit(kbdev, katom[idx], js); -+ katom[idx]->gpu_rb_state = -+ KBASE_ATOM_GPU_RB_SUBMITTED; -+ -+ /* Inform power management at start/finish of -+ * atom so it can update its GPU utilisation -+ * metrics. */ -+ kbase_pm_metrics_update(kbdev, -+ &katom[idx]->start_timestamp); -+ -+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */ -+ -+ case KBASE_ATOM_GPU_RB_SUBMITTED: -+ /* Atom submitted to HW, nothing else to do */ -+ break; -+ -+ case KBASE_ATOM_GPU_RB_RETURN_TO_JS: -+ /* Only return if head atom or previous atom -+ * already removed - as atoms must be returned -+ * in order */ -+ if (idx == 0 || katom[0]->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB) { -+ kbase_gpu_dequeue_atom(kbdev, js, NULL); -+ kbase_jm_return_atom_to_js(kbdev, -+ katom[idx]); -+ } -+ break; -+ } -+ } -+ } -+ -+ /* Warn if PRLAM-8987 affinity restrictions are violated */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987)) -+ WARN_ON((kbase_gpu_atoms_submitted(kbdev, 0) || -+ kbase_gpu_atoms_submitted(kbdev, 1)) && -+ kbase_gpu_atoms_submitted(kbdev, 2)); -+} -+ -+ -+void kbase_backend_run_atom(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ kbase_gpu_enqueue_atom(kbdev, katom); -+ kbase_backend_slot_update(kbdev); -+} -+ -+#define HAS_DEP(katom) (katom->pre_dep || katom->atom_flags & \ -+ (KBASE_KATOM_FLAG_X_DEP_BLOCKED | KBASE_KATOM_FLAG_FAIL_BLOCKER)) -+ -+bool kbase_gpu_irq_evict(struct kbase_device *kbdev, int js) -+{ -+ struct kbase_jd_atom *katom; -+ struct kbase_jd_atom *next_katom; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ katom = kbase_gpu_inspect(kbdev, js, 0); -+ next_katom = kbase_gpu_inspect(kbdev, js, 1); -+ -+ if (next_katom && katom->kctx == next_katom->kctx && -+ next_katom->gpu_rb_state == KBASE_ATOM_GPU_RB_SUBMITTED && -+ HAS_DEP(next_katom) && -+ (kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_HEAD_NEXT_LO), NULL) -+ != 0 || -+ kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_HEAD_NEXT_HI), NULL) -+ != 0)) { -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT), -+ JS_COMMAND_NOP, NULL); -+ next_katom->gpu_rb_state = KBASE_ATOM_GPU_RB_READY; -+ -+ KBASE_TLSTREAM_TL_NRET_ATOM_LPU(katom, -+ &kbdev->gpu_props.props.raw_props.js_features -+ [katom->slot_nr]); -+ KBASE_TLSTREAM_TL_NRET_ATOM_AS(katom, &kbdev->as -+ [katom->kctx->as_nr]); -+ KBASE_TLSTREAM_TL_NRET_CTX_LPU(katom->kctx, -+ &kbdev->gpu_props.props.raw_props.js_features -+ [katom->slot_nr]); -+ -+ return true; -+ } -+ -+ return false; -+} -+ -+void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js, -+ u32 completion_code, -+ u64 job_tail, -+ ktime_t *end_timestamp) -+{ -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, 0); -+ struct kbase_context *kctx = katom->kctx; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ /* -+ * When a hard-stop is followed close after a soft-stop, the completion -+ * code may be set to STOPPED, even though the job is terminated -+ */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_TMIX_8438)) { -+ if (completion_code == BASE_JD_EVENT_STOPPED && -+ (katom->atom_flags & -+ KBASE_KATOM_FLAG_BEEN_HARD_STOPPED)) { -+ completion_code = BASE_JD_EVENT_TERMINATED; -+ } -+ } -+ -+ if ((kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_6787) || (katom->core_req & -+ BASE_JD_REQ_SKIP_CACHE_END)) && -+ completion_code != BASE_JD_EVENT_DONE && -+ !(completion_code & BASE_JD_SW_EVENT)) { -+ /* When a job chain fails, on a T60x or when -+ * BASE_JD_REQ_SKIP_CACHE_END is set, the GPU cache is not -+ * flushed. To prevent future evictions causing possible memory -+ * corruption we need to flush the cache manually before any -+ * affected memory gets reused. */ -+ katom->need_cache_flush_cores_retained = katom->affinity; -+ kbase_pm_request_cores(kbdev, false, katom->affinity); -+ } else if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10676)) { -+ if (kbdev->gpu_props.num_core_groups > 1 && -+ !(katom->affinity & -+ kbdev->gpu_props.props.coherency_info.group[0].core_mask -+ ) && -+ (katom->affinity & -+ kbdev->gpu_props.props.coherency_info.group[1].core_mask -+ )) { -+ dev_info(kbdev->dev, "JD: Flushing cache due to PRLAM-10676\n"); -+ katom->need_cache_flush_cores_retained = -+ katom->affinity; -+ kbase_pm_request_cores(kbdev, false, -+ katom->affinity); -+ } -+ } -+ -+ katom = kbase_gpu_dequeue_atom(kbdev, js, end_timestamp); -+ kbase_timeline_job_slot_done(kbdev, katom->kctx, katom, js, 0); -+ -+ if (completion_code == BASE_JD_EVENT_STOPPED) { -+ struct kbase_jd_atom *next_katom = kbase_gpu_inspect(kbdev, js, -+ 0); -+ -+ /* -+ * Dequeue next atom from ringbuffers on same slot if required. -+ * This atom will already have been removed from the NEXT -+ * registers by kbase_gpu_soft_hard_stop_slot(), to ensure that -+ * the atoms on this slot are returned in the correct order. -+ */ -+ if (next_katom && katom->kctx == next_katom->kctx && -+ next_katom->sched_priority == -+ katom->sched_priority) { -+ kbase_gpu_dequeue_atom(kbdev, js, end_timestamp); -+ kbase_jm_return_atom_to_js(kbdev, next_katom); -+ } -+ } else if (completion_code != BASE_JD_EVENT_DONE) { -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ int i; -+ -+#if KBASE_TRACE_DUMP_ON_JOB_SLOT_ERROR != 0 -+ KBASE_TRACE_DUMP(kbdev); -+#endif -+ kbasep_js_clear_submit_allowed(js_devdata, katom->kctx); -+ -+ /* -+ * Remove all atoms on the same context from ringbuffers. This -+ * will not remove atoms that are already on the GPU, as these -+ * are guaranteed not to have fail dependencies on the failed -+ * atom. -+ */ -+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++) { -+ struct kbase_jd_atom *katom_idx0 = -+ kbase_gpu_inspect(kbdev, i, 0); -+ struct kbase_jd_atom *katom_idx1 = -+ kbase_gpu_inspect(kbdev, i, 1); -+ -+ if (katom_idx0 && katom_idx0->kctx == katom->kctx && -+ HAS_DEP(katom_idx0) && -+ katom_idx0->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_SUBMITTED) { -+ /* Dequeue katom_idx0 from ringbuffer */ -+ kbase_gpu_dequeue_atom(kbdev, i, end_timestamp); -+ -+ if (katom_idx1 && -+ katom_idx1->kctx == katom->kctx -+ && HAS_DEP(katom_idx1) && -+ katom_idx0->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_SUBMITTED) { -+ /* Dequeue katom_idx1 from ringbuffer */ -+ kbase_gpu_dequeue_atom(kbdev, i, -+ end_timestamp); -+ -+ katom_idx1->event_code = -+ BASE_JD_EVENT_STOPPED; -+ kbase_jm_return_atom_to_js(kbdev, -+ katom_idx1); -+ } -+ katom_idx0->event_code = BASE_JD_EVENT_STOPPED; -+ kbase_jm_return_atom_to_js(kbdev, katom_idx0); -+ -+ } else if (katom_idx1 && -+ katom_idx1->kctx == katom->kctx && -+ HAS_DEP(katom_idx1) && -+ katom_idx1->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_SUBMITTED) { -+ /* Can not dequeue this atom yet - will be -+ * dequeued when atom at idx0 completes */ -+ katom_idx1->event_code = BASE_JD_EVENT_STOPPED; -+ kbase_gpu_mark_atom_for_return(kbdev, -+ katom_idx1); -+ } -+ } -+ } -+ -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, JM_JOB_DONE, kctx, katom, katom->jc, -+ js, completion_code); -+ -+ if (job_tail != 0 && job_tail != katom->jc) { -+ bool was_updated = (job_tail != katom->jc); -+ -+ /* Some of the job has been executed, so we update the job chain -+ * address to where we should resume from */ -+ katom->jc = job_tail; -+ if (was_updated) -+ KBASE_TRACE_ADD_SLOT(kbdev, JM_UPDATE_HEAD, katom->kctx, -+ katom, job_tail, js); -+ } -+ -+ /* Only update the event code for jobs that weren't cancelled */ -+ if (katom->event_code != BASE_JD_EVENT_JOB_CANCELLED) -+ katom->event_code = (base_jd_event_code)completion_code; -+ -+ kbase_device_trace_register_access(kctx, REG_WRITE, -+ JOB_CONTROL_REG(JOB_IRQ_CLEAR), -+ 1 << js); -+ -+ /* Complete the job, and start new ones -+ * -+ * Also defer remaining work onto the workqueue: -+ * - Re-queue Soft-stopped jobs -+ * - For any other jobs, queue the job back into the dependency system -+ * - Schedule out the parent context if necessary, and schedule a new -+ * one in. -+ */ -+#ifdef CONFIG_GPU_TRACEPOINTS -+ { -+ /* The atom in the HEAD */ -+ struct kbase_jd_atom *next_katom = kbase_gpu_inspect(kbdev, js, -+ 0); -+ -+ if (next_katom && next_katom->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_SUBMITTED) { -+ char js_string[16]; -+ -+ trace_gpu_sched_switch(kbasep_make_job_slot_string(js, -+ js_string, -+ sizeof(js_string)), -+ ktime_to_ns(*end_timestamp), -+ (u32)next_katom->kctx->id, 0, -+ next_katom->work_id); -+ kbdev->hwaccess.backend.slot_rb[js].last_context = -+ next_katom->kctx; -+ } else { -+ char js_string[16]; -+ -+ trace_gpu_sched_switch(kbasep_make_job_slot_string(js, -+ js_string, -+ sizeof(js_string)), -+ ktime_to_ns(ktime_get()), 0, 0, -+ 0); -+ kbdev->hwaccess.backend.slot_rb[js].last_context = 0; -+ } -+ } -+#endif -+ -+ if (kbdev->serialize_jobs & KBASE_SERIALIZE_RESET) -+ kbase_reset_gpu_silent(kbdev); -+ -+ if (completion_code == BASE_JD_EVENT_STOPPED) -+ katom = kbase_jm_return_atom_to_js(kbdev, katom); -+ else -+ katom = kbase_jm_complete(kbdev, katom, end_timestamp); -+ -+ if (katom) { -+ /* Cross-slot dependency has now become runnable. Try to submit -+ * it. */ -+ -+ /* Check if there are lower priority jobs to soft stop */ -+ kbase_job_slot_ctx_priority_check_locked(kctx, katom); -+ -+ kbase_jm_try_kick(kbdev, 1 << katom->slot_nr); -+ } -+ -+ /* Job completion may have unblocked other atoms. Try to update all job -+ * slots */ -+ kbase_backend_slot_update(kbdev); -+} -+ -+void kbase_backend_reset(struct kbase_device *kbdev, ktime_t *end_timestamp) -+{ -+ int js; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ /* Reset should always take the GPU out of protected mode */ -+ WARN_ON(kbase_gpu_in_protected_mode(kbdev)); -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ int atom_idx = 0; -+ int idx; -+ -+ for (idx = 0; idx < SLOT_RB_SIZE; idx++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, -+ js, atom_idx); -+ bool keep_in_jm_rb = false; -+ -+ if (!katom) -+ break; -+ if (katom->protected_state.exit == -+ KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT) -+ { -+ KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_END(kbdev); -+ -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+ -+ /* protected mode sanity checks */ -+ KBASE_DEBUG_ASSERT_MSG( -+ kbase_jd_katom_is_protected(katom) == kbase_gpu_in_protected_mode(kbdev), -+ "Protected mode of atom (%d) doesn't match protected mode of GPU (%d)", -+ kbase_jd_katom_is_protected(katom), kbase_gpu_in_protected_mode(kbdev)); -+ KBASE_DEBUG_ASSERT_MSG( -+ (kbase_jd_katom_is_protected(katom) && js == 0) || -+ !kbase_jd_katom_is_protected(katom), -+ "Protected atom on JS%d not supported", js); -+ } -+ if (katom->gpu_rb_state < KBASE_ATOM_GPU_RB_SUBMITTED) -+ keep_in_jm_rb = true; -+ -+ kbase_gpu_release_atom(kbdev, katom, NULL); -+ -+ /* -+ * If the atom wasn't on HW when the reset was issued -+ * then leave it in the RB and next time we're kicked -+ * it will be processed again from the starting state. -+ */ -+ if (keep_in_jm_rb) { -+ kbasep_js_job_check_deref_cores(kbdev, katom); -+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED; -+ katom->affinity = 0; -+ katom->protected_state.exit = KBASE_ATOM_EXIT_PROTECTED_CHECK; -+ /* As the atom was not removed, increment the -+ * index so that we read the correct atom in the -+ * next iteration. */ -+ atom_idx++; -+ continue; -+ } -+ -+ /* -+ * The atom was on the HW when the reset was issued -+ * all we can do is fail the atom. -+ */ -+ kbase_gpu_dequeue_atom(kbdev, js, NULL); -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ kbase_jm_complete(kbdev, katom, end_timestamp); -+ } -+ } -+ -+ kbdev->protected_mode_transition = false; -+} -+ -+static inline void kbase_gpu_stop_atom(struct kbase_device *kbdev, -+ int js, -+ struct kbase_jd_atom *katom, -+ u32 action) -+{ -+ u32 hw_action = action & JS_COMMAND_MASK; -+ -+ kbase_job_check_enter_disjoint(kbdev, action, katom->core_req, katom); -+ kbasep_job_slot_soft_or_hard_stop_do_action(kbdev, js, hw_action, -+ katom->core_req, katom); -+ katom->kctx->blocked_js[js][katom->sched_priority] = true; -+} -+ -+static inline void kbase_gpu_remove_atom(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, -+ u32 action, -+ bool disjoint) -+{ -+ katom->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT; -+ kbase_gpu_mark_atom_for_return(kbdev, katom); -+ katom->kctx->blocked_js[katom->slot_nr][katom->sched_priority] = true; -+ -+ if (disjoint) -+ kbase_job_check_enter_disjoint(kbdev, action, katom->core_req, -+ katom); -+} -+ -+static int should_stop_x_dep_slot(struct kbase_jd_atom *katom) -+{ -+ if (katom->x_post_dep) { -+ struct kbase_jd_atom *dep_atom = katom->x_post_dep; -+ -+ if (dep_atom->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB && -+ dep_atom->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_RETURN_TO_JS) -+ return dep_atom->slot_nr; -+ } -+ return -1; -+} -+ -+static void kbase_job_evicted(struct kbase_jd_atom *katom) -+{ -+ kbase_timeline_job_slot_done(katom->kctx->kbdev, katom->kctx, katom, -+ katom->slot_nr, KBASE_JS_ATOM_DONE_EVICTED_FROM_NEXT); -+} -+ -+bool kbase_backend_soft_hard_stop_slot(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js, -+ struct kbase_jd_atom *katom, -+ u32 action) -+{ -+ struct kbase_jd_atom *katom_idx0; -+ struct kbase_jd_atom *katom_idx1; -+ -+ bool katom_idx0_valid, katom_idx1_valid; -+ -+ bool ret = false; -+ -+ int stop_x_dep_idx0 = -1, stop_x_dep_idx1 = -1; -+ int prio_idx0 = 0, prio_idx1 = 0; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ katom_idx0 = kbase_gpu_inspect(kbdev, js, 0); -+ katom_idx1 = kbase_gpu_inspect(kbdev, js, 1); -+ -+ if (katom_idx0) -+ prio_idx0 = katom_idx0->sched_priority; -+ if (katom_idx1) -+ prio_idx1 = katom_idx1->sched_priority; -+ -+ if (katom) { -+ katom_idx0_valid = (katom_idx0 == katom); -+ /* If idx0 is to be removed and idx1 is on the same context, -+ * then idx1 must also be removed otherwise the atoms might be -+ * returned out of order */ -+ if (katom_idx1) -+ katom_idx1_valid = (katom_idx1 == katom) || -+ (katom_idx0_valid && -+ (katom_idx0->kctx == -+ katom_idx1->kctx)); -+ else -+ katom_idx1_valid = false; -+ } else { -+ katom_idx0_valid = (katom_idx0 && -+ (!kctx || katom_idx0->kctx == kctx)); -+ katom_idx1_valid = (katom_idx1 && -+ (!kctx || katom_idx1->kctx == kctx) && -+ prio_idx0 == prio_idx1); -+ } -+ -+ if (katom_idx0_valid) -+ stop_x_dep_idx0 = should_stop_x_dep_slot(katom_idx0); -+ if (katom_idx1_valid) -+ stop_x_dep_idx1 = should_stop_x_dep_slot(katom_idx1); -+ -+ if (katom_idx0_valid) { -+ if (katom_idx0->gpu_rb_state != KBASE_ATOM_GPU_RB_SUBMITTED) { -+ /* Simple case - just dequeue and return */ -+ kbase_gpu_dequeue_atom(kbdev, js, NULL); -+ if (katom_idx1_valid) { -+ kbase_gpu_dequeue_atom(kbdev, js, NULL); -+ katom_idx1->event_code = -+ BASE_JD_EVENT_REMOVED_FROM_NEXT; -+ kbase_jm_return_atom_to_js(kbdev, katom_idx1); -+ katom_idx1->kctx->blocked_js[js][prio_idx1] = -+ true; -+ } -+ -+ katom_idx0->event_code = -+ BASE_JD_EVENT_REMOVED_FROM_NEXT; -+ kbase_jm_return_atom_to_js(kbdev, katom_idx0); -+ katom_idx0->kctx->blocked_js[js][prio_idx0] = true; -+ } else { -+ /* katom_idx0 is on GPU */ -+ if (katom_idx1 && katom_idx1->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_SUBMITTED) { -+ /* katom_idx0 and katom_idx1 are on GPU */ -+ -+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, -+ JS_COMMAND_NEXT), NULL) == 0) { -+ /* idx0 has already completed - stop -+ * idx1 if needed*/ -+ if (katom_idx1_valid) { -+ kbase_gpu_stop_atom(kbdev, js, -+ katom_idx1, -+ action); -+ ret = true; -+ } -+ } else { -+ /* idx1 is in NEXT registers - attempt -+ * to remove */ -+ kbase_reg_write(kbdev, -+ JOB_SLOT_REG(js, -+ JS_COMMAND_NEXT), -+ JS_COMMAND_NOP, NULL); -+ -+ if (kbase_reg_read(kbdev, -+ JOB_SLOT_REG(js, -+ JS_HEAD_NEXT_LO), NULL) -+ != 0 || -+ kbase_reg_read(kbdev, -+ JOB_SLOT_REG(js, -+ JS_HEAD_NEXT_HI), NULL) -+ != 0) { -+ /* idx1 removed successfully, -+ * will be handled in IRQ */ -+ kbase_job_evicted(katom_idx1); -+ kbase_gpu_remove_atom(kbdev, -+ katom_idx1, -+ action, true); -+ stop_x_dep_idx1 = -+ should_stop_x_dep_slot(katom_idx1); -+ -+ /* stop idx0 if still on GPU */ -+ kbase_gpu_stop_atom(kbdev, js, -+ katom_idx0, -+ action); -+ ret = true; -+ } else if (katom_idx1_valid) { -+ /* idx0 has already completed, -+ * stop idx1 if needed */ -+ kbase_gpu_stop_atom(kbdev, js, -+ katom_idx1, -+ action); -+ ret = true; -+ } -+ } -+ } else if (katom_idx1_valid) { -+ /* idx1 not on GPU but must be dequeued*/ -+ -+ /* idx1 will be handled in IRQ */ -+ kbase_gpu_remove_atom(kbdev, katom_idx1, action, -+ false); -+ /* stop idx0 */ -+ /* This will be repeated for anything removed -+ * from the next registers, since their normal -+ * flow was also interrupted, and this function -+ * might not enter disjoint state e.g. if we -+ * don't actually do a hard stop on the head -+ * atom */ -+ kbase_gpu_stop_atom(kbdev, js, katom_idx0, -+ action); -+ ret = true; -+ } else { -+ /* no atom in idx1 */ -+ /* just stop idx0 */ -+ kbase_gpu_stop_atom(kbdev, js, katom_idx0, -+ action); -+ ret = true; -+ } -+ } -+ } else if (katom_idx1_valid) { -+ if (katom_idx1->gpu_rb_state != KBASE_ATOM_GPU_RB_SUBMITTED) { -+ /* Mark for return */ -+ /* idx1 will be returned once idx0 completes */ -+ kbase_gpu_remove_atom(kbdev, katom_idx1, action, -+ false); -+ } else { -+ /* idx1 is on GPU */ -+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, -+ JS_COMMAND_NEXT), NULL) == 0) { -+ /* idx0 has already completed - stop idx1 */ -+ kbase_gpu_stop_atom(kbdev, js, katom_idx1, -+ action); -+ ret = true; -+ } else { -+ /* idx1 is in NEXT registers - attempt to -+ * remove */ -+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, -+ JS_COMMAND_NEXT), -+ JS_COMMAND_NOP, NULL); -+ -+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, -+ JS_HEAD_NEXT_LO), NULL) != 0 || -+ kbase_reg_read(kbdev, JOB_SLOT_REG(js, -+ JS_HEAD_NEXT_HI), NULL) != 0) { -+ /* idx1 removed successfully, will be -+ * handled in IRQ once idx0 completes */ -+ kbase_job_evicted(katom_idx1); -+ kbase_gpu_remove_atom(kbdev, katom_idx1, -+ action, -+ false); -+ } else { -+ /* idx0 has already completed - stop -+ * idx1 */ -+ kbase_gpu_stop_atom(kbdev, js, -+ katom_idx1, -+ action); -+ ret = true; -+ } -+ } -+ } -+ } -+ -+ -+ if (stop_x_dep_idx0 != -1) -+ kbase_backend_soft_hard_stop_slot(kbdev, kctx, stop_x_dep_idx0, -+ NULL, action); -+ -+ if (stop_x_dep_idx1 != -1) -+ kbase_backend_soft_hard_stop_slot(kbdev, kctx, stop_x_dep_idx1, -+ NULL, action); -+ -+ return ret; -+} -+ -+void kbase_gpu_cacheclean(struct kbase_device *kbdev) -+{ -+ /* Limit the number of loops to avoid a hang if the interrupt is missed -+ */ -+ u32 max_loops = KBASE_CLEAN_CACHE_MAX_LOOPS; -+ -+ mutex_lock(&kbdev->cacheclean_lock); -+ -+ /* use GPU_COMMAND completion solution */ -+ /* clean & invalidate the caches */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, NULL, 0u, 0); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_CLEAN_INV_CACHES, NULL); -+ -+ /* wait for cache flush to complete before continuing */ -+ while (--max_loops && -+ (kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), NULL) & -+ CLEAN_CACHES_COMPLETED) == 0) -+ ; -+ -+ /* clear the CLEAN_CACHES_COMPLETED irq */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, NULL, 0u, -+ CLEAN_CACHES_COMPLETED); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), -+ CLEAN_CACHES_COMPLETED, NULL); -+ KBASE_DEBUG_ASSERT_MSG(kbdev->hwcnt.backend.state != -+ KBASE_INSTR_STATE_CLEANING, -+ "Instrumentation code was cleaning caches, but Job Management code cleared their IRQ - Instrumentation code will now hang."); -+ -+ mutex_unlock(&kbdev->cacheclean_lock); -+} -+ -+void kbase_backend_cacheclean(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ if (katom->need_cache_flush_cores_retained) { -+ unsigned long flags; -+ -+ kbase_gpu_cacheclean(kbdev); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_pm_unrequest_cores(kbdev, false, -+ katom->need_cache_flush_cores_retained); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ katom->need_cache_flush_cores_retained = 0; -+ } -+} -+ -+void kbase_backend_complete_wq(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ /* -+ * If cache flush required due to HW workaround then perform the flush -+ * now -+ */ -+ kbase_backend_cacheclean(kbdev, katom); -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10969) && -+ (katom->core_req & BASE_JD_REQ_FS) && -+ katom->event_code == BASE_JD_EVENT_TILE_RANGE_FAULT && -+ (katom->atom_flags & KBASE_KATOM_FLAG_BEEN_SOFT_STOPPPED) && -+ !(katom->atom_flags & KBASE_KATOM_FLAGS_RERUN)) { -+ dev_dbg(kbdev->dev, "Soft-stopped fragment shader job got a TILE_RANGE_FAULT. Possible HW issue, trying SW workaround\n"); -+ if (kbasep_10969_workaround_clamp_coordinates(katom)) { -+ /* The job had a TILE_RANGE_FAULT after was soft-stopped -+ * Due to an HW issue we try to execute the job again. -+ */ -+ dev_dbg(kbdev->dev, -+ "Clamping has been executed, try to rerun the job\n" -+ ); -+ katom->event_code = BASE_JD_EVENT_STOPPED; -+ katom->atom_flags |= KBASE_KATOM_FLAGS_RERUN; -+ } -+ } -+ -+ /* Clear the coreref_state now - while check_deref_cores() may not have -+ * been called yet, the caller will have taken a copy of this field. If -+ * this is not done, then if the atom is re-scheduled (following a soft -+ * stop) then the core reference would not be retaken. */ -+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED; -+ katom->affinity = 0; -+} -+ -+void kbase_backend_complete_wq_post_sched(struct kbase_device *kbdev, -+ base_jd_core_req core_req, u64 affinity, -+ enum kbase_atom_coreref_state coreref_state) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbasep_js_job_check_deref_cores_nokatom(kbdev, core_req, affinity, -+ coreref_state); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ if (!kbdev->pm.active_count) { -+ mutex_lock(&kbdev->js_data.runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ kbase_pm_update_active(kbdev); -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&kbdev->js_data.runpool_mutex); -+ } -+} -+ -+void kbase_gpu_dump_slots(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ int js; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ dev_info(kbdev->dev, "kbase_gpu_dump_slots:\n"); -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ int idx; -+ -+ for (idx = 0; idx < SLOT_RB_SIZE; idx++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, -+ js, -+ idx); -+ -+ if (katom) -+ dev_info(kbdev->dev, -+ " js%d idx%d : katom=%p gpu_rb_state=%d\n", -+ js, idx, katom, katom->gpu_rb_state); -+ else -+ dev_info(kbdev->dev, " js%d idx%d : empty\n", -+ js, idx); -+ } -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+ -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_rb.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_rb.h -new file mode 100644 -index 0000000..1e0e05a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_jm_rb.h -@@ -0,0 +1,76 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Register-based HW access backend specific APIs -+ */ -+ -+#ifndef _KBASE_HWACCESS_GPU_H_ -+#define _KBASE_HWACCESS_GPU_H_ -+ -+#include -+ -+/** -+ * kbase_gpu_irq_evict - Evict an atom from a NEXT slot -+ * -+ * @kbdev: Device pointer -+ * @js: Job slot to evict from -+ * -+ * Evict the atom in the NEXT slot for the specified job slot. This function is -+ * called from the job complete IRQ handler when the previous job has failed. -+ * -+ * Return: true if job evicted from NEXT registers, false otherwise -+ */ -+bool kbase_gpu_irq_evict(struct kbase_device *kbdev, int js); -+ -+/** -+ * kbase_gpu_complete_hw - Complete an atom on job slot js -+ * -+ * @kbdev: Device pointer -+ * @js: Job slot that has completed -+ * @completion_code: Event code from job that has completed -+ * @job_tail: The tail address from the hardware if the job has partially -+ * completed -+ * @end_timestamp: Time of completion -+ */ -+void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js, -+ u32 completion_code, -+ u64 job_tail, -+ ktime_t *end_timestamp); -+ -+/** -+ * kbase_gpu_inspect - Inspect the contents of the HW access ringbuffer -+ * -+ * @kbdev: Device pointer -+ * @js: Job slot to inspect -+ * @idx: Index into ringbuffer. 0 is the job currently running on -+ * the slot, 1 is the job waiting, all other values are invalid. -+ * Return: The atom at that position in the ringbuffer -+ * or NULL if no atom present -+ */ -+struct kbase_jd_atom *kbase_gpu_inspect(struct kbase_device *kbdev, int js, -+ int idx); -+ -+/** -+ * kbase_gpu_dump_slots - Print the contents of the slot ringbuffers -+ * -+ * @kbdev: Device pointer -+ */ -+void kbase_gpu_dump_slots(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_HWACCESS_GPU_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_affinity.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_affinity.c -new file mode 100644 -index 0000000..54d8ddd ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_affinity.c -@@ -0,0 +1,303 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Base kernel affinity manager APIs -+ */ -+ -+#include -+#include "mali_kbase_js_affinity.h" -+#include "mali_kbase_hw.h" -+ -+#include -+ -+ -+bool kbase_js_can_run_job_on_slot_no_lock(struct kbase_device *kbdev, -+ int js) -+{ -+ /* -+ * Here are the reasons for using job slot 2: -+ * - BASE_HW_ISSUE_8987 (which is entirely used for that purpose) -+ * - In absence of the above, then: -+ * - Atoms with BASE_JD_REQ_COHERENT_GROUP -+ * - But, only when there aren't contexts with -+ * KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES, because the atoms that run on -+ * all cores on slot 1 could be blocked by those using a coherent group -+ * on slot 2 -+ * - And, only when you actually have 2 or more coregroups - if you -+ * only have 1 coregroup, then having jobs for slot 2 implies they'd -+ * also be for slot 1, meaning you'll get interference from them. Jobs -+ * able to run on slot 2 could also block jobs that can only run on -+ * slot 1 (tiler jobs) -+ */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987)) -+ return true; -+ -+ if (js != 2) -+ return true; -+ -+ /* Only deal with js==2 now: */ -+ if (kbdev->gpu_props.num_core_groups > 1) { -+ /* Only use slot 2 in the 2+ coregroup case */ -+ if (kbasep_js_ctx_attr_is_attr_on_runpool(kbdev, -+ KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES) == -+ false) { -+ /* ...But only when we *don't* have atoms that run on -+ * all cores */ -+ -+ /* No specific check for BASE_JD_REQ_COHERENT_GROUP -+ * atoms - the policy will sort that out */ -+ return true; -+ } -+ } -+ -+ /* Above checks failed mean we shouldn't use slot 2 */ -+ return false; -+} -+ -+/* -+ * As long as it has been decided to have a deeper modification of -+ * what job scheduler, power manager and affinity manager will -+ * implement, this function is just an intermediate step that -+ * assumes: -+ * - all working cores will be powered on when this is called. -+ * - largest current configuration is 2 core groups. -+ * - It has been decided not to have hardcoded values so the low -+ * and high cores in a core split will be evently distributed. -+ * - Odd combinations of core requirements have been filtered out -+ * and do not get to this function (e.g. CS+T+NSS is not -+ * supported here). -+ * - This function is frequently called and can be optimized, -+ * (see notes in loops), but as the functionallity will likely -+ * be modified, optimization has not been addressed. -+*/ -+bool kbase_js_choose_affinity(u64 * const affinity, -+ struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, int js) -+{ -+ base_jd_core_req core_req = katom->core_req; -+ unsigned int num_core_groups = kbdev->gpu_props.num_core_groups; -+ u64 core_availability_mask; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ core_availability_mask = kbase_pm_ca_get_core_mask(kbdev); -+ -+ /* -+ * If no cores are currently available (core availability policy is -+ * transitioning) then fail. -+ */ -+ if (0 == core_availability_mask) { -+ *affinity = 0; -+ return false; -+ } -+ -+ KBASE_DEBUG_ASSERT(js >= 0); -+ -+ if ((core_req & (BASE_JD_REQ_FS | BASE_JD_REQ_CS | BASE_JD_REQ_T)) == -+ BASE_JD_REQ_T) { -+ /* If the hardware supports XAFFINITY then we'll only enable -+ * the tiler (which is the default so this is a no-op), -+ * otherwise enable shader core 0. */ -+ if (!kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_XAFFINITY)) -+ *affinity = 1; -+ else -+ *affinity = 0; -+ -+ return true; -+ } -+ -+ if (1 == kbdev->gpu_props.num_cores) { -+ /* trivial case only one core, nothing to do */ -+ *affinity = core_availability_mask & -+ kbdev->pm.debug_core_mask[js]; -+ } else { -+ if ((core_req & (BASE_JD_REQ_COHERENT_GROUP | -+ BASE_JD_REQ_SPECIFIC_COHERENT_GROUP))) { -+ if (js == 0 || num_core_groups == 1) { -+ /* js[0] and single-core-group systems just get -+ * the first core group */ -+ *affinity = -+ kbdev->gpu_props.props.coherency_info.group[0].core_mask -+ & core_availability_mask & -+ kbdev->pm.debug_core_mask[js]; -+ } else { -+ /* js[1], js[2] use core groups 0, 1 for -+ * dual-core-group systems */ -+ u32 core_group_idx = ((u32) js) - 1; -+ -+ KBASE_DEBUG_ASSERT(core_group_idx < -+ num_core_groups); -+ *affinity = -+ kbdev->gpu_props.props.coherency_info.group[core_group_idx].core_mask -+ & core_availability_mask & -+ kbdev->pm.debug_core_mask[js]; -+ -+ /* If the job is specifically targeting core -+ * group 1 and the core availability policy is -+ * keeping that core group off, then fail */ -+ if (*affinity == 0 && core_group_idx == 1 && -+ kbdev->pm.backend.cg1_disabled -+ == true) -+ katom->event_code = -+ BASE_JD_EVENT_PM_EVENT; -+ } -+ } else { -+ /* All cores are available when no core split is -+ * required */ -+ *affinity = core_availability_mask & -+ kbdev->pm.debug_core_mask[js]; -+ } -+ } -+ -+ /* -+ * If no cores are currently available in the desired core group(s) -+ * (core availability policy is transitioning) then fail. -+ */ -+ if (*affinity == 0) -+ return false; -+ -+ /* Enable core 0 if tiler required for hardware without XAFFINITY -+ * support (notes above) */ -+ if (core_req & BASE_JD_REQ_T) { -+ if (!kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_XAFFINITY)) -+ *affinity = *affinity | 1; -+ } -+ -+ return true; -+} -+ -+static inline bool kbase_js_affinity_is_violating( -+ struct kbase_device *kbdev, -+ u64 *affinities) -+{ -+ /* This implementation checks whether the two slots involved in Generic -+ * thread creation have intersecting affinity. This is due to micro- -+ * architectural issues where a job in slot A targetting cores used by -+ * slot B could prevent the job in slot B from making progress until the -+ * job in slot A has completed. -+ */ -+ u64 affinity_set_left; -+ u64 affinity_set_right; -+ u64 intersection; -+ -+ KBASE_DEBUG_ASSERT(affinities != NULL); -+ -+ affinity_set_left = affinities[1]; -+ -+ affinity_set_right = affinities[2]; -+ -+ /* A violation occurs when any bit in the left_set is also in the -+ * right_set */ -+ intersection = affinity_set_left & affinity_set_right; -+ -+ return (bool) (intersection != (u64) 0u); -+} -+ -+bool kbase_js_affinity_would_violate(struct kbase_device *kbdev, int js, -+ u64 affinity) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ u64 new_affinities[BASE_JM_MAX_NR_SLOTS]; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(js < BASE_JM_MAX_NR_SLOTS); -+ js_devdata = &kbdev->js_data; -+ -+ memcpy(new_affinities, js_devdata->runpool_irq.slot_affinities, -+ sizeof(js_devdata->runpool_irq.slot_affinities)); -+ -+ new_affinities[js] |= affinity; -+ -+ return kbase_js_affinity_is_violating(kbdev, new_affinities); -+} -+ -+void kbase_js_affinity_retain_slot_cores(struct kbase_device *kbdev, int js, -+ u64 affinity) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ u64 cores; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(js < BASE_JM_MAX_NR_SLOTS); -+ js_devdata = &kbdev->js_data; -+ -+ KBASE_DEBUG_ASSERT(kbase_js_affinity_would_violate(kbdev, js, affinity) -+ == false); -+ -+ cores = affinity; -+ while (cores) { -+ int bitnum = fls64(cores) - 1; -+ u64 bit = 1ULL << bitnum; -+ s8 cnt; -+ -+ cnt = -+ ++(js_devdata->runpool_irq.slot_affinity_refcount[js][bitnum]); -+ -+ if (cnt == 1) -+ js_devdata->runpool_irq.slot_affinities[js] |= bit; -+ -+ cores &= ~bit; -+ } -+} -+ -+void kbase_js_affinity_release_slot_cores(struct kbase_device *kbdev, int js, -+ u64 affinity) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ u64 cores; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(js < BASE_JM_MAX_NR_SLOTS); -+ js_devdata = &kbdev->js_data; -+ -+ cores = affinity; -+ while (cores) { -+ int bitnum = fls64(cores) - 1; -+ u64 bit = 1ULL << bitnum; -+ s8 cnt; -+ -+ KBASE_DEBUG_ASSERT( -+ js_devdata->runpool_irq.slot_affinity_refcount[js][bitnum] > 0); -+ -+ cnt = -+ --(js_devdata->runpool_irq.slot_affinity_refcount[js][bitnum]); -+ -+ if (0 == cnt) -+ js_devdata->runpool_irq.slot_affinities[js] &= ~bit; -+ -+ cores &= ~bit; -+ } -+} -+ -+#if KBASE_TRACE_ENABLE -+void kbase_js_debug_log_current_affinities(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ int slot_nr; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ js_devdata = &kbdev->js_data; -+ -+ for (slot_nr = 0; slot_nr < 3; ++slot_nr) -+ KBASE_TRACE_ADD_SLOT_INFO(kbdev, JS_AFFINITY_CURRENT, NULL, -+ NULL, 0u, slot_nr, -+ (u32) js_devdata->runpool_irq.slot_affinities[slot_nr]); -+} -+#endif /* KBASE_TRACE_ENABLE */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_affinity.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_affinity.h -new file mode 100644 -index 0000000..35d9781 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_affinity.h -@@ -0,0 +1,129 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Affinity Manager internal APIs. -+ */ -+ -+#ifndef _KBASE_JS_AFFINITY_H_ -+#define _KBASE_JS_AFFINITY_H_ -+ -+/** -+ * kbase_js_can_run_job_on_slot_no_lock - Decide whether it is possible to -+ * submit a job to a particular job slot in the current status -+ * -+ * @kbdev: The kbase device structure of the device -+ * @js: Job slot number to check for allowance -+ * -+ * Will check if submitting to the given job slot is allowed in the current -+ * status. For example using job slot 2 while in soft-stoppable state and only -+ * having 1 coregroup is not allowed by the policy. This function should be -+ * called prior to submitting a job to a slot to make sure policy rules are not -+ * violated. -+ * -+ * The following locking conditions are made on the caller -+ * - it must hold hwaccess_lock -+ */ -+bool kbase_js_can_run_job_on_slot_no_lock(struct kbase_device *kbdev, int js); -+ -+/** -+ * kbase_js_choose_affinity - Compute affinity for a given job. -+ * -+ * @affinity: Affinity bitmap computed -+ * @kbdev: The kbase device structure of the device -+ * @katom: Job chain of which affinity is going to be found -+ * @js: Slot the job chain is being submitted -+ * -+ * Currently assumes an all-on/all-off power management policy. -+ * Also assumes there is at least one core with tiler available. -+ * -+ * Returns true if a valid affinity was chosen, false if -+ * no cores were available. -+ */ -+bool kbase_js_choose_affinity(u64 * const affinity, -+ struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, -+ int js); -+ -+/** -+ * kbase_js_affinity_would_violate - Determine whether a proposed affinity on -+ * job slot @js would cause a violation of affinity restrictions. -+ * -+ * @kbdev: Kbase device structure -+ * @js: The job slot to test -+ * @affinity: The affinity mask to test -+ * -+ * The following locks must be held by the caller -+ * - hwaccess_lock -+ * -+ * Return: true if the affinity would violate the restrictions -+ */ -+bool kbase_js_affinity_would_violate(struct kbase_device *kbdev, int js, -+ u64 affinity); -+ -+/** -+ * kbase_js_affinity_retain_slot_cores - Affinity tracking: retain cores used by -+ * a slot -+ * -+ * @kbdev: Kbase device structure -+ * @js: The job slot retaining the cores -+ * @affinity: The cores to retain -+ * -+ * The following locks must be held by the caller -+ * - hwaccess_lock -+ */ -+void kbase_js_affinity_retain_slot_cores(struct kbase_device *kbdev, int js, -+ u64 affinity); -+ -+/** -+ * kbase_js_affinity_release_slot_cores - Affinity tracking: release cores used -+ * by a slot -+ * -+ * @kbdev: Kbase device structure -+ * @js: Job slot -+ * @affinity: Bit mask of core to be released -+ * -+ * Cores must be released as soon as a job is dequeued from a slot's 'submit -+ * slots', and before another job is submitted to those slots. Otherwise, the -+ * refcount could exceed the maximum number submittable to a slot, -+ * %BASE_JM_SUBMIT_SLOTS. -+ * -+ * The following locks must be held by the caller -+ * - hwaccess_lock -+ */ -+void kbase_js_affinity_release_slot_cores(struct kbase_device *kbdev, int js, -+ u64 affinity); -+ -+/** -+ * kbase_js_debug_log_current_affinities - log the current affinities -+ * -+ * @kbdev: Kbase device structure -+ * -+ * Output to the Trace log the current tracked affinities on all slots -+ */ -+#if KBASE_TRACE_ENABLE -+void kbase_js_debug_log_current_affinities(struct kbase_device *kbdev); -+#else /* KBASE_TRACE_ENABLE */ -+static inline void -+kbase_js_debug_log_current_affinities(struct kbase_device *kbdev) -+{ -+} -+#endif /* KBASE_TRACE_ENABLE */ -+ -+#endif /* _KBASE_JS_AFFINITY_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_backend.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_backend.c -new file mode 100644 -index 0000000..a8c1af2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_backend.c -@@ -0,0 +1,356 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Register-based HW access backend specific job scheduler APIs -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * Define for when dumping is enabled. -+ * This should not be based on the instrumentation level as whether dumping is -+ * enabled for a particular level is down to the integrator. However this is -+ * being used for now as otherwise the cinstr headers would be needed. -+ */ -+#define CINSTR_DUMPING_ENABLED (2 == MALI_INSTRUMENTATION_LEVEL) -+ -+/* -+ * Hold the runpool_mutex for this -+ */ -+static inline bool timer_callback_should_run(struct kbase_device *kbdev) -+{ -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ s8 nr_running_ctxs; -+ -+ lockdep_assert_held(&kbdev->js_data.runpool_mutex); -+ -+ /* Timer must stop if we are suspending */ -+ if (backend->suspend_timer) -+ return false; -+ -+ /* nr_contexts_pullable is updated with the runpool_mutex. However, the -+ * locking in the caller gives us a barrier that ensures -+ * nr_contexts_pullable is up-to-date for reading */ -+ nr_running_ctxs = atomic_read(&kbdev->js_data.nr_contexts_runnable); -+ -+#ifdef CONFIG_MALI_DEBUG -+ if (kbdev->js_data.softstop_always) { -+ /* Debug support for allowing soft-stop on a single context */ -+ return true; -+ } -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9435)) { -+ /* Timeouts would have to be 4x longer (due to micro- -+ * architectural design) to support OpenCL conformance tests, so -+ * only run the timer when there's: -+ * - 2 or more CL contexts -+ * - 1 or more GLES contexts -+ * -+ * NOTE: We will treat a context that has both Compute and Non- -+ * Compute jobs will be treated as an OpenCL context (hence, we -+ * don't check KBASEP_JS_CTX_ATTR_NON_COMPUTE). -+ */ -+ { -+ s8 nr_compute_ctxs = -+ kbasep_js_ctx_attr_count_on_runpool(kbdev, -+ KBASEP_JS_CTX_ATTR_COMPUTE); -+ s8 nr_noncompute_ctxs = nr_running_ctxs - -+ nr_compute_ctxs; -+ -+ return (bool) (nr_compute_ctxs >= 2 || -+ nr_noncompute_ctxs > 0); -+ } -+ } else { -+ /* Run the timer callback whenever you have at least 1 context -+ */ -+ return (bool) (nr_running_ctxs > 0); -+ } -+} -+ -+static enum hrtimer_restart timer_callback(struct hrtimer *timer) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev; -+ struct kbasep_js_device_data *js_devdata; -+ struct kbase_backend_data *backend; -+ int s; -+ bool reset_needed = false; -+ -+ KBASE_DEBUG_ASSERT(timer != NULL); -+ -+ backend = container_of(timer, struct kbase_backend_data, -+ scheduling_timer); -+ kbdev = container_of(backend, struct kbase_device, hwaccess.backend); -+ js_devdata = &kbdev->js_data; -+ -+ /* Loop through the slots */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ for (s = 0; s < kbdev->gpu_props.num_job_slots; s++) { -+ struct kbase_jd_atom *atom = NULL; -+ -+ if (kbase_backend_nr_atoms_on_slot(kbdev, s) > 0) { -+ atom = kbase_gpu_inspect(kbdev, s, 0); -+ KBASE_DEBUG_ASSERT(atom != NULL); -+ } -+ -+ if (atom != NULL) { -+ /* The current version of the model doesn't support -+ * Soft-Stop */ -+ if (!kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_5736)) { -+ u32 ticks = atom->ticks++; -+ -+#if !CINSTR_DUMPING_ENABLED -+ u32 soft_stop_ticks, hard_stop_ticks, -+ gpu_reset_ticks; -+ if (atom->core_req & BASE_JD_REQ_ONLY_COMPUTE) { -+ soft_stop_ticks = -+ js_devdata->soft_stop_ticks_cl; -+ hard_stop_ticks = -+ js_devdata->hard_stop_ticks_cl; -+ gpu_reset_ticks = -+ js_devdata->gpu_reset_ticks_cl; -+ } else { -+ soft_stop_ticks = -+ js_devdata->soft_stop_ticks; -+ hard_stop_ticks = -+ js_devdata->hard_stop_ticks_ss; -+ gpu_reset_ticks = -+ js_devdata->gpu_reset_ticks_ss; -+ } -+ -+ /* If timeouts have been changed then ensure -+ * that atom tick count is not greater than the -+ * new soft_stop timeout. This ensures that -+ * atoms do not miss any of the timeouts due to -+ * races between this worker and the thread -+ * changing the timeouts. */ -+ if (backend->timeouts_updated && -+ ticks > soft_stop_ticks) -+ ticks = atom->ticks = soft_stop_ticks; -+ -+ /* Job is Soft-Stoppable */ -+ if (ticks == soft_stop_ticks) { -+ int disjoint_threshold = -+ KBASE_DISJOINT_STATE_INTERLEAVED_CONTEXT_COUNT_THRESHOLD; -+ u32 softstop_flags = 0u; -+ /* Job has been scheduled for at least -+ * js_devdata->soft_stop_ticks ticks. -+ * Soft stop the slot so we can run -+ * other jobs. -+ */ -+ dev_dbg(kbdev->dev, "Soft-stop"); -+#if !KBASE_DISABLE_SCHEDULING_SOFT_STOPS -+ /* nr_user_contexts_running is updated -+ * with the runpool_mutex, but we can't -+ * take that here. -+ * -+ * However, if it's about to be -+ * increased then the new context can't -+ * run any jobs until they take the -+ * hwaccess_lock, so it's OK to observe -+ * the older value. -+ * -+ * Similarly, if it's about to be -+ * decreased, the last job from another -+ * context has already finished, so it's -+ * not too bad that we observe the older -+ * value and register a disjoint event -+ * when we try soft-stopping */ -+ if (js_devdata->nr_user_contexts_running -+ >= disjoint_threshold) -+ softstop_flags |= -+ JS_COMMAND_SW_CAUSES_DISJOINT; -+ -+ kbase_job_slot_softstop_swflags(kbdev, -+ s, atom, softstop_flags); -+#endif -+ } else if (ticks == hard_stop_ticks) { -+ /* Job has been scheduled for at least -+ * js_devdata->hard_stop_ticks_ss ticks. -+ * It should have been soft-stopped by -+ * now. Hard stop the slot. -+ */ -+#if !KBASE_DISABLE_SCHEDULING_HARD_STOPS -+ int ms = -+ js_devdata->scheduling_period_ns -+ / 1000000u; -+ dev_warn(kbdev->dev, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)", -+ (unsigned long)ticks, -+ (unsigned long)ms); -+ kbase_job_slot_hardstop(atom->kctx, s, -+ atom); -+#endif -+ } else if (ticks == gpu_reset_ticks) { -+ /* Job has been scheduled for at least -+ * js_devdata->gpu_reset_ticks_ss ticks. -+ * It should have left the GPU by now. -+ * Signal that the GPU needs to be -+ * reset. -+ */ -+ reset_needed = true; -+ } -+#else /* !CINSTR_DUMPING_ENABLED */ -+ /* NOTE: During CINSTR_DUMPING_ENABLED, we use -+ * the alternate timeouts, which makes the hard- -+ * stop and GPU reset timeout much longer. We -+ * also ensure that we don't soft-stop at all. -+ */ -+ if (ticks == js_devdata->soft_stop_ticks) { -+ /* Job has been scheduled for at least -+ * js_devdata->soft_stop_ticks. We do -+ * not soft-stop during -+ * CINSTR_DUMPING_ENABLED, however. -+ */ -+ dev_dbg(kbdev->dev, "Soft-stop"); -+ } else if (ticks == -+ js_devdata->hard_stop_ticks_dumping) { -+ /* Job has been scheduled for at least -+ * js_devdata->hard_stop_ticks_dumping -+ * ticks. Hard stop the slot. -+ */ -+#if !KBASE_DISABLE_SCHEDULING_HARD_STOPS -+ int ms = -+ js_devdata->scheduling_period_ns -+ / 1000000u; -+ dev_warn(kbdev->dev, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)", -+ (unsigned long)ticks, -+ (unsigned long)ms); -+ kbase_job_slot_hardstop(atom->kctx, s, -+ atom); -+#endif -+ } else if (ticks == -+ js_devdata->gpu_reset_ticks_dumping) { -+ /* Job has been scheduled for at least -+ * js_devdata->gpu_reset_ticks_dumping -+ * ticks. It should have left the GPU by -+ * now. Signal that the GPU needs to be -+ * reset. -+ */ -+ reset_needed = true; -+ } -+#endif /* !CINSTR_DUMPING_ENABLED */ -+ } -+ } -+ } -+#if KBASE_GPU_RESET_EN -+ if (reset_needed) { -+ dev_err(kbdev->dev, "JS: Job has been on the GPU for too long (JS_RESET_TICKS_SS/DUMPING timeout hit). Issueing GPU soft-reset to resolve."); -+ -+ if (kbase_prepare_to_reset_gpu_locked(kbdev)) -+ kbase_reset_gpu_locked(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ /* the timer is re-issued if there is contexts in the run-pool */ -+ -+ if (backend->timer_running) -+ hrtimer_start(&backend->scheduling_timer, -+ HR_TIMER_DELAY_NSEC(js_devdata->scheduling_period_ns), -+ HRTIMER_MODE_REL); -+ -+ backend->timeouts_updated = false; -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return HRTIMER_NORESTART; -+} -+ -+void kbase_backend_ctx_count_changed(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ unsigned long flags; -+ -+ lockdep_assert_held(&js_devdata->runpool_mutex); -+ -+ if (!timer_callback_should_run(kbdev)) { -+ /* Take spinlock to force synchronisation with timer */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ backend->timer_running = false; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ /* From now on, return value of timer_callback_should_run() will -+ * also cause the timer to not requeue itself. Its return value -+ * cannot change, because it depends on variables updated with -+ * the runpool_mutex held, which the caller of this must also -+ * hold */ -+ hrtimer_cancel(&backend->scheduling_timer); -+ } -+ -+ if (timer_callback_should_run(kbdev) && !backend->timer_running) { -+ /* Take spinlock to force synchronisation with timer */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ backend->timer_running = true; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ hrtimer_start(&backend->scheduling_timer, -+ HR_TIMER_DELAY_NSEC(js_devdata->scheduling_period_ns), -+ HRTIMER_MODE_REL); -+ -+ KBASE_TRACE_ADD(kbdev, JS_POLICY_TIMER_START, NULL, NULL, 0u, -+ 0u); -+ } -+} -+ -+int kbase_backend_timer_init(struct kbase_device *kbdev) -+{ -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ -+ hrtimer_init(&backend->scheduling_timer, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ backend->scheduling_timer.function = timer_callback; -+ -+ backend->timer_running = false; -+ -+ return 0; -+} -+ -+void kbase_backend_timer_term(struct kbase_device *kbdev) -+{ -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ -+ hrtimer_cancel(&backend->scheduling_timer); -+} -+ -+void kbase_backend_timer_suspend(struct kbase_device *kbdev) -+{ -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ -+ backend->suspend_timer = true; -+ -+ kbase_backend_ctx_count_changed(kbdev); -+} -+ -+void kbase_backend_timer_resume(struct kbase_device *kbdev) -+{ -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ -+ backend->suspend_timer = false; -+ -+ kbase_backend_ctx_count_changed(kbdev); -+} -+ -+void kbase_backend_timeouts_changed(struct kbase_device *kbdev) -+{ -+ struct kbase_backend_data *backend = &kbdev->hwaccess.backend; -+ -+ backend->timeouts_updated = true; -+} -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_internal.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_internal.h -new file mode 100644 -index 0000000..3f53779 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_js_internal.h -@@ -0,0 +1,69 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Register-based HW access backend specific job scheduler APIs -+ */ -+ -+#ifndef _KBASE_JS_BACKEND_H_ -+#define _KBASE_JS_BACKEND_H_ -+ -+/** -+ * kbase_backend_timer_init() - Initialise the JS scheduling timer -+ * @kbdev: Device pointer -+ * -+ * This function should be called at driver initialisation -+ * -+ * Return: 0 on success -+ */ -+int kbase_backend_timer_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_timer_term() - Terminate the JS scheduling timer -+ * @kbdev: Device pointer -+ * -+ * This function should be called at driver termination -+ */ -+void kbase_backend_timer_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_timer_suspend - Suspend is happening, stop the JS scheduling -+ * timer -+ * @kbdev: Device pointer -+ * -+ * This function should be called on suspend, after the active count has reached -+ * zero. This is required as the timer may have been started on job submission -+ * to the job scheduler, but before jobs are submitted to the GPU. -+ * -+ * Caller must hold runpool_mutex. -+ */ -+void kbase_backend_timer_suspend(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_timer_resume - Resume is happening, re-evaluate the JS -+ * scheduling timer -+ * @kbdev: Device pointer -+ * -+ * This function should be called on resume. Note that is is not guaranteed to -+ * re-start the timer, only evalute whether it should be re-started. -+ * -+ * Caller must hold runpool_mutex. -+ */ -+void kbase_backend_timer_resume(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_JS_BACKEND_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_mmu_hw_direct.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_mmu_hw_direct.c -new file mode 100644 -index 0000000..aa1817c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_mmu_hw_direct.c -@@ -0,0 +1,401 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static inline u64 lock_region(struct kbase_device *kbdev, u64 pfn, -+ u32 num_pages) -+{ -+ u64 region; -+ -+ /* can't lock a zero sized range */ -+ KBASE_DEBUG_ASSERT(num_pages); -+ -+ region = pfn << PAGE_SHIFT; -+ /* -+ * fls returns (given the ASSERT above): -+ * 1 .. 32 -+ * -+ * 10 + fls(num_pages) -+ * results in the range (11 .. 42) -+ */ -+ -+ /* gracefully handle num_pages being zero */ -+ if (0 == num_pages) { -+ region |= 11; -+ } else { -+ u8 region_width; -+ -+ region_width = 10 + fls(num_pages); -+ if (num_pages != (1ul << (region_width - 11))) { -+ /* not pow2, so must go up to the next pow2 */ -+ region_width += 1; -+ } -+ KBASE_DEBUG_ASSERT(region_width <= KBASE_LOCK_REGION_MAX_SIZE); -+ KBASE_DEBUG_ASSERT(region_width >= KBASE_LOCK_REGION_MIN_SIZE); -+ region |= region_width; -+ } -+ -+ return region; -+} -+ -+static int wait_ready(struct kbase_device *kbdev, -+ unsigned int as_nr, struct kbase_context *kctx) -+{ -+ unsigned int max_loops = KBASE_AS_INACTIVE_MAX_LOOPS; -+ u32 val = kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS), kctx); -+ -+ /* Wait for the MMU status to indicate there is no active command, in -+ * case one is pending. Do not log remaining register accesses. */ -+ while (--max_loops && (val & AS_STATUS_AS_ACTIVE)) -+ val = kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS), NULL); -+ -+ if (max_loops == 0) { -+ dev_err(kbdev->dev, "AS_ACTIVE bit stuck\n"); -+ return -1; -+ } -+ -+ /* If waiting in loop was performed, log last read value. */ -+ if (KBASE_AS_INACTIVE_MAX_LOOPS - 1 > max_loops) -+ kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS), kctx); -+ -+ return 0; -+} -+ -+static int write_cmd(struct kbase_device *kbdev, int as_nr, u32 cmd, -+ struct kbase_context *kctx) -+{ -+ int status; -+ -+ /* write AS_COMMAND when MMU is ready to accept another command */ -+ status = wait_ready(kbdev, as_nr, kctx); -+ if (status == 0) -+ kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_COMMAND), cmd, -+ kctx); -+ -+ return status; -+} -+ -+static void validate_protected_page_fault(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ /* GPUs which support (native) protected mode shall not report page -+ * fault addresses unless it has protected debug mode and protected -+ * debug mode is turned on */ -+ u32 protected_debug_mode = 0; -+ -+ if (!kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE)) -+ return; -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_DEBUG_MODE)) { -+ protected_debug_mode = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(GPU_STATUS), -+ kctx) & GPU_DBGEN; -+ } -+ -+ if (!protected_debug_mode) { -+ /* fault_addr should never be reported in protected mode. -+ * However, we just continue by printing an error message */ -+ dev_err(kbdev->dev, "Fault address reported in protected mode\n"); -+ } -+} -+ -+void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat) -+{ -+ const int num_as = 16; -+ const int busfault_shift = MMU_PAGE_FAULT_FLAGS; -+ const int pf_shift = 0; -+ const unsigned long as_bit_mask = (1UL << num_as) - 1; -+ unsigned long flags; -+ u32 new_mask; -+ u32 tmp; -+ -+ /* bus faults */ -+ u32 bf_bits = (irq_stat >> busfault_shift) & as_bit_mask; -+ /* page faults (note: Ignore ASes with both pf and bf) */ -+ u32 pf_bits = ((irq_stat >> pf_shift) & as_bit_mask) & ~bf_bits; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ -+ /* remember current mask */ -+ spin_lock_irqsave(&kbdev->mmu_mask_change, flags); -+ new_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), NULL); -+ /* mask interrupts for now */ -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0, NULL); -+ spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags); -+ -+ while (bf_bits | pf_bits) { -+ struct kbase_as *as; -+ int as_no; -+ struct kbase_context *kctx; -+ -+ /* -+ * the while logic ensures we have a bit set, no need to check -+ * for not-found here -+ */ -+ as_no = ffs(bf_bits | pf_bits) - 1; -+ as = &kbdev->as[as_no]; -+ -+ /* -+ * Refcount the kctx ASAP - it shouldn't disappear anyway, since -+ * Bus/Page faults _should_ only occur whilst jobs are running, -+ * and a job causing the Bus/Page fault shouldn't complete until -+ * the MMU is updated -+ */ -+ kctx = kbasep_js_runpool_lookup_ctx(kbdev, as_no); -+ -+ -+ /* find faulting address */ -+ as->fault_addr = kbase_reg_read(kbdev, -+ MMU_AS_REG(as_no, -+ AS_FAULTADDRESS_HI), -+ kctx); -+ as->fault_addr <<= 32; -+ as->fault_addr |= kbase_reg_read(kbdev, -+ MMU_AS_REG(as_no, -+ AS_FAULTADDRESS_LO), -+ kctx); -+ -+ /* Mark the fault protected or not */ -+ as->protected_mode = kbdev->protected_mode; -+ -+ if (kbdev->protected_mode && as->fault_addr) -+ { -+ /* check if address reporting is allowed */ -+ validate_protected_page_fault(kbdev, kctx); -+ } -+ -+ /* report the fault to debugfs */ -+ kbase_as_fault_debugfs_new(kbdev, as_no); -+ -+ /* record the fault status */ -+ as->fault_status = kbase_reg_read(kbdev, -+ MMU_AS_REG(as_no, -+ AS_FAULTSTATUS), -+ kctx); -+ -+ /* find the fault type */ -+ as->fault_type = (bf_bits & (1 << as_no)) ? -+ KBASE_MMU_FAULT_TYPE_BUS : -+ KBASE_MMU_FAULT_TYPE_PAGE; -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) { -+ as->fault_extra_addr = kbase_reg_read(kbdev, -+ MMU_AS_REG(as_no, AS_FAULTEXTRA_HI), -+ kctx); -+ as->fault_extra_addr <<= 32; -+ as->fault_extra_addr |= kbase_reg_read(kbdev, -+ MMU_AS_REG(as_no, AS_FAULTEXTRA_LO), -+ kctx); -+ } -+ -+ if (kbase_as_has_bus_fault(as)) { -+ /* Mark bus fault as handled. -+ * Note that a bus fault is processed first in case -+ * where both a bus fault and page fault occur. -+ */ -+ bf_bits &= ~(1UL << as_no); -+ -+ /* remove the queued BF (and PF) from the mask */ -+ new_mask &= ~(MMU_BUS_ERROR(as_no) | -+ MMU_PAGE_FAULT(as_no)); -+ } else { -+ /* Mark page fault as handled */ -+ pf_bits &= ~(1UL << as_no); -+ -+ /* remove the queued PF from the mask */ -+ new_mask &= ~MMU_PAGE_FAULT(as_no); -+ } -+ -+ /* Process the interrupt for this address space */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_mmu_interrupt_process(kbdev, kctx, as); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ } -+ -+ /* reenable interrupts */ -+ spin_lock_irqsave(&kbdev->mmu_mask_change, flags); -+ tmp = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), NULL); -+ new_mask |= tmp; -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), new_mask, NULL); -+ spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags); -+} -+ -+void kbase_mmu_hw_configure(struct kbase_device *kbdev, struct kbase_as *as, -+ struct kbase_context *kctx) -+{ -+ struct kbase_mmu_setup *current_setup = &as->current_setup; -+ u32 transcfg = 0; -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) { -+ transcfg = current_setup->transcfg & 0xFFFFFFFFUL; -+ -+ /* Set flag AS_TRANSCFG_PTW_MEMATTR_WRITE_BACK */ -+ /* Clear PTW_MEMATTR bits */ -+ transcfg &= ~AS_TRANSCFG_PTW_MEMATTR_MASK; -+ /* Enable correct PTW_MEMATTR bits */ -+ transcfg |= AS_TRANSCFG_PTW_MEMATTR_WRITE_BACK; -+ -+ if (kbdev->system_coherency == COHERENCY_ACE) { -+ /* Set flag AS_TRANSCFG_PTW_SH_OS (outer shareable) */ -+ /* Clear PTW_SH bits */ -+ transcfg = (transcfg & ~AS_TRANSCFG_PTW_SH_MASK); -+ /* Enable correct PTW_SH bits */ -+ transcfg = (transcfg | AS_TRANSCFG_PTW_SH_OS); -+ } -+ -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSCFG_LO), -+ transcfg, kctx); -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSCFG_HI), -+ (current_setup->transcfg >> 32) & 0xFFFFFFFFUL, -+ kctx); -+ } else { -+ if (kbdev->system_coherency == COHERENCY_ACE) -+ current_setup->transtab |= AS_TRANSTAB_LPAE_SHARE_OUTER; -+ } -+ -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSTAB_LO), -+ current_setup->transtab & 0xFFFFFFFFUL, kctx); -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSTAB_HI), -+ (current_setup->transtab >> 32) & 0xFFFFFFFFUL, kctx); -+ -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_MEMATTR_LO), -+ current_setup->memattr & 0xFFFFFFFFUL, kctx); -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_MEMATTR_HI), -+ (current_setup->memattr >> 32) & 0xFFFFFFFFUL, kctx); -+ -+ KBASE_TLSTREAM_TL_ATTRIB_AS_CONFIG(as, -+ current_setup->transtab, -+ current_setup->memattr, -+ transcfg); -+ -+ write_cmd(kbdev, as->number, AS_COMMAND_UPDATE, kctx); -+} -+ -+int kbase_mmu_hw_do_operation(struct kbase_device *kbdev, struct kbase_as *as, -+ struct kbase_context *kctx, u64 vpfn, u32 nr, u32 op, -+ unsigned int handling_irq) -+{ -+ int ret; -+ -+ lockdep_assert_held(&kbdev->mmu_hw_mutex); -+ -+ if (op == AS_COMMAND_UNLOCK) { -+ /* Unlock doesn't require a lock first */ -+ ret = write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK, kctx); -+ } else { -+ u64 lock_addr = lock_region(kbdev, vpfn, nr); -+ -+ /* Lock the region that needs to be updated */ -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_LO), -+ lock_addr & 0xFFFFFFFFUL, kctx); -+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_HI), -+ (lock_addr >> 32) & 0xFFFFFFFFUL, kctx); -+ write_cmd(kbdev, as->number, AS_COMMAND_LOCK, kctx); -+ -+ /* Run the MMU operation */ -+ write_cmd(kbdev, as->number, op, kctx); -+ -+ /* Wait for the flush to complete */ -+ ret = wait_ready(kbdev, as->number, kctx); -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9630)) { -+ /* Issue an UNLOCK command to ensure that valid page -+ tables are re-read by the GPU after an update. -+ Note that, the FLUSH command should perform all the -+ actions necessary, however the bus logs show that if -+ multiple page faults occur within an 8 page region -+ the MMU does not always re-read the updated page -+ table entries for later faults or is only partially -+ read, it subsequently raises the page fault IRQ for -+ the same addresses, the unlock ensures that the MMU -+ cache is flushed, so updates can be re-read. As the -+ region is now unlocked we need to issue 2 UNLOCK -+ commands in order to flush the MMU/uTLB, -+ see PRLAM-8812. -+ */ -+ write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK, kctx); -+ write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK, kctx); -+ } -+ } -+ -+ return ret; -+} -+ -+void kbase_mmu_hw_clear_fault(struct kbase_device *kbdev, struct kbase_as *as, -+ struct kbase_context *kctx, enum kbase_mmu_fault_type type) -+{ -+ unsigned long flags; -+ u32 pf_bf_mask; -+ -+ spin_lock_irqsave(&kbdev->mmu_mask_change, flags); -+ -+ /* -+ * A reset is in-flight and we're flushing the IRQ + bottom half -+ * so don't update anything as it could race with the reset code. -+ */ -+ if (kbdev->irq_reset_flush) -+ goto unlock; -+ -+ /* Clear the page (and bus fault IRQ as well in case one occurred) */ -+ pf_bf_mask = MMU_PAGE_FAULT(as->number); -+ if (type == KBASE_MMU_FAULT_TYPE_BUS || -+ type == KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED) -+ pf_bf_mask |= MMU_BUS_ERROR(as->number); -+ -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), pf_bf_mask, kctx); -+ -+unlock: -+ spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags); -+} -+ -+void kbase_mmu_hw_enable_fault(struct kbase_device *kbdev, struct kbase_as *as, -+ struct kbase_context *kctx, enum kbase_mmu_fault_type type) -+{ -+ unsigned long flags; -+ u32 irq_mask; -+ -+ /* Enable the page fault IRQ (and bus fault IRQ as well in case one -+ * occurred) */ -+ spin_lock_irqsave(&kbdev->mmu_mask_change, flags); -+ -+ /* -+ * A reset is in-flight and we're flushing the IRQ + bottom half -+ * so don't update anything as it could race with the reset code. -+ */ -+ if (kbdev->irq_reset_flush) -+ goto unlock; -+ -+ irq_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), kctx) | -+ MMU_PAGE_FAULT(as->number); -+ -+ if (type == KBASE_MMU_FAULT_TYPE_BUS || -+ type == KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED) -+ irq_mask |= MMU_BUS_ERROR(as->number); -+ -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), irq_mask, kctx); -+ -+unlock: -+ spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags); -+} -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_mmu_hw_direct.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_mmu_hw_direct.h -new file mode 100644 -index 0000000..c02253c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_mmu_hw_direct.h -@@ -0,0 +1,42 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Interface file for the direct implementation for MMU hardware access -+ * -+ * Direct MMU hardware interface -+ * -+ * This module provides the interface(s) that are required by the direct -+ * register access implementation of the MMU hardware interface -+ */ -+ -+#ifndef _MALI_KBASE_MMU_HW_DIRECT_H_ -+#define _MALI_KBASE_MMU_HW_DIRECT_H_ -+ -+#include -+ -+/** -+ * kbase_mmu_interrupt - Process an MMU interrupt. -+ * -+ * Process the MMU interrupt that was reported by the &kbase_device. -+ * -+ * @kbdev: kbase context to clear the fault from. -+ * @irq_stat: Value of the MMU_IRQ_STATUS register -+ */ -+void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat); -+ -+#endif /* _MALI_KBASE_MMU_HW_DIRECT_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_always_on.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_always_on.c -new file mode 100644 -index 0000000..0614348 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_always_on.c -@@ -0,0 +1,63 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * "Always on" power management policy -+ */ -+ -+#include -+#include -+ -+static u64 always_on_get_core_mask(struct kbase_device *kbdev) -+{ -+ return kbdev->gpu_props.props.raw_props.shader_present; -+} -+ -+static bool always_on_get_core_active(struct kbase_device *kbdev) -+{ -+ return true; -+} -+ -+static void always_on_init(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+static void always_on_term(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+/* -+ * The struct kbase_pm_policy structure for the demand power policy. -+ * -+ * This is the static structure that defines the demand power policy's callback -+ * and name. -+ */ -+const struct kbase_pm_policy kbase_pm_always_on_policy_ops = { -+ "always_on", /* name */ -+ always_on_init, /* init */ -+ always_on_term, /* term */ -+ always_on_get_core_mask, /* get_core_mask */ -+ always_on_get_core_active, /* get_core_active */ -+ 0u, /* flags */ -+ KBASE_PM_POLICY_ID_ALWAYS_ON, /* id */ -+}; -+ -+KBASE_EXPORT_TEST_API(kbase_pm_always_on_policy_ops); -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_always_on.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_always_on.h -new file mode 100644 -index 0000000..f9d244b ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_always_on.h -@@ -0,0 +1,77 @@ -+ -+/* -+ * -+ * (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * "Always on" power management policy -+ */ -+ -+#ifndef MALI_KBASE_PM_ALWAYS_ON_H -+#define MALI_KBASE_PM_ALWAYS_ON_H -+ -+/** -+ * DOC: -+ * The "Always on" power management policy has the following -+ * characteristics: -+ * -+ * - When KBase indicates that the GPU will be powered up, but we don't yet -+ * know which Job Chains are to be run: -+ * All Shader Cores are powered up, regardless of whether or not they will -+ * be needed later. -+ * -+ * - When KBase indicates that a set of Shader Cores are needed to submit the -+ * currently queued Job Chains: -+ * All Shader Cores are kept powered, regardless of whether or not they will -+ * be needed -+ * -+ * - When KBase indicates that the GPU need not be powered: -+ * The Shader Cores are kept powered, regardless of whether or not they will -+ * be needed. The GPU itself is also kept powered, even though it is not -+ * needed. -+ * -+ * This policy is automatically overridden during system suspend: the desired -+ * core state is ignored, and the cores are forced off regardless of what the -+ * policy requests. After resuming from suspend, new changes to the desired -+ * core state made by the policy are honored. -+ * -+ * Note: -+ * -+ * - KBase indicates the GPU will be powered up when it has a User Process that -+ * has just started to submit Job Chains. -+ * -+ * - KBase indicates the GPU need not be powered when all the Job Chains from -+ * User Processes have finished, and it is waiting for a User Process to -+ * submit some more Job Chains. -+ */ -+ -+/** -+ * struct kbasep_pm_policy_always_on - Private struct for policy instance data -+ * @dummy: unused dummy variable -+ * -+ * This contains data that is private to the particular power policy that is -+ * active. -+ */ -+struct kbasep_pm_policy_always_on { -+ int dummy; -+}; -+ -+extern const struct kbase_pm_policy kbase_pm_always_on_policy_ops; -+ -+#endif /* MALI_KBASE_PM_ALWAYS_ON_H */ -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_backend.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_backend.c -new file mode 100644 -index 0000000..c88b80a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_backend.c -@@ -0,0 +1,478 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * GPU backend implementation of base kernel power management APIs -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+static void kbase_pm_gpu_poweroff_wait_wq(struct work_struct *data); -+ -+void kbase_pm_register_access_enable(struct kbase_device *kbdev) -+{ -+ struct kbase_pm_callback_conf *callbacks; -+ -+ callbacks = (struct kbase_pm_callback_conf *)POWER_MANAGEMENT_CALLBACKS; -+ -+ if (callbacks) -+ callbacks->power_on_callback(kbdev); -+ -+ kbdev->pm.backend.gpu_powered = true; -+} -+ -+void kbase_pm_register_access_disable(struct kbase_device *kbdev) -+{ -+ struct kbase_pm_callback_conf *callbacks; -+ -+ callbacks = (struct kbase_pm_callback_conf *)POWER_MANAGEMENT_CALLBACKS; -+ -+ if (callbacks) -+ callbacks->power_off_callback(kbdev); -+ -+ kbdev->pm.backend.gpu_powered = false; -+} -+ -+int kbase_hwaccess_pm_init(struct kbase_device *kbdev) -+{ -+ int ret = 0; -+ struct kbase_pm_callback_conf *callbacks; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ mutex_init(&kbdev->pm.lock); -+ -+ kbdev->pm.backend.gpu_poweroff_wait_wq = alloc_workqueue("kbase_pm_poweroff_wait", -+ WQ_HIGHPRI | WQ_UNBOUND, 1); -+ if (!kbdev->pm.backend.gpu_poweroff_wait_wq) -+ return -ENOMEM; -+ -+ INIT_WORK(&kbdev->pm.backend.gpu_poweroff_wait_work, -+ kbase_pm_gpu_poweroff_wait_wq); -+ -+ kbdev->pm.backend.gpu_powered = false; -+ kbdev->pm.suspending = false; -+#ifdef CONFIG_MALI_DEBUG -+ kbdev->pm.backend.driver_ready_for_irqs = false; -+#endif /* CONFIG_MALI_DEBUG */ -+ kbdev->pm.backend.gpu_in_desired_state = true; -+ init_waitqueue_head(&kbdev->pm.backend.gpu_in_desired_state_wait); -+ -+ callbacks = (struct kbase_pm_callback_conf *)POWER_MANAGEMENT_CALLBACKS; -+ if (callbacks) { -+ kbdev->pm.backend.callback_power_on = -+ callbacks->power_on_callback; -+ kbdev->pm.backend.callback_power_off = -+ callbacks->power_off_callback; -+ kbdev->pm.backend.callback_power_suspend = -+ callbacks->power_suspend_callback; -+ kbdev->pm.backend.callback_power_resume = -+ callbacks->power_resume_callback; -+ kbdev->pm.callback_power_runtime_init = -+ callbacks->power_runtime_init_callback; -+ kbdev->pm.callback_power_runtime_term = -+ callbacks->power_runtime_term_callback; -+ kbdev->pm.backend.callback_power_runtime_on = -+ callbacks->power_runtime_on_callback; -+ kbdev->pm.backend.callback_power_runtime_off = -+ callbacks->power_runtime_off_callback; -+ kbdev->pm.backend.callback_power_runtime_idle = -+ callbacks->power_runtime_idle_callback; -+ } else { -+ kbdev->pm.backend.callback_power_on = NULL; -+ kbdev->pm.backend.callback_power_off = NULL; -+ kbdev->pm.backend.callback_power_suspend = NULL; -+ kbdev->pm.backend.callback_power_resume = NULL; -+ kbdev->pm.callback_power_runtime_init = NULL; -+ kbdev->pm.callback_power_runtime_term = NULL; -+ kbdev->pm.backend.callback_power_runtime_on = NULL; -+ kbdev->pm.backend.callback_power_runtime_off = NULL; -+ kbdev->pm.backend.callback_power_runtime_idle = NULL; -+ } -+ -+ /* Initialise the metrics subsystem */ -+ ret = kbasep_pm_metrics_init(kbdev); -+ if (ret) -+ return ret; -+ -+ init_waitqueue_head(&kbdev->pm.backend.l2_powered_wait); -+ kbdev->pm.backend.l2_powered = 0; -+ -+ init_waitqueue_head(&kbdev->pm.backend.reset_done_wait); -+ kbdev->pm.backend.reset_done = false; -+ -+ init_waitqueue_head(&kbdev->pm.zero_active_count_wait); -+ kbdev->pm.active_count = 0; -+ -+ spin_lock_init(&kbdev->pm.backend.gpu_cycle_counter_requests_lock); -+ spin_lock_init(&kbdev->pm.backend.gpu_powered_lock); -+ -+ init_waitqueue_head(&kbdev->pm.backend.poweroff_wait); -+ -+ if (kbase_pm_ca_init(kbdev) != 0) -+ goto workq_fail; -+ -+ if (kbase_pm_policy_init(kbdev) != 0) -+ goto pm_policy_fail; -+ -+ return 0; -+ -+pm_policy_fail: -+ kbase_pm_ca_term(kbdev); -+workq_fail: -+ kbasep_pm_metrics_term(kbdev); -+ return -EINVAL; -+} -+ -+void kbase_pm_do_poweron(struct kbase_device *kbdev, bool is_resume) -+{ -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ /* Turn clocks and interrupts on - no-op if we haven't done a previous -+ * kbase_pm_clock_off() */ -+ kbase_pm_clock_on(kbdev, is_resume); -+ -+ /* Update core status as required by the policy */ -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_PM_DO_POWERON_START); -+ kbase_pm_update_cores_state(kbdev); -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_PM_DO_POWERON_END); -+ -+ /* NOTE: We don't wait to reach the desired state, since running atoms -+ * will wait for that state to be reached anyway */ -+} -+ -+static void kbase_pm_gpu_poweroff_wait_wq(struct work_struct *data) -+{ -+ struct kbase_device *kbdev = container_of(data, struct kbase_device, -+ pm.backend.gpu_poweroff_wait_work); -+ struct kbase_pm_device_data *pm = &kbdev->pm; -+ struct kbase_pm_backend_data *backend = &pm->backend; -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ unsigned long flags; -+ -+#if !PLATFORM_POWER_DOWN_ONLY -+ /* Wait for power transitions to complete. We do this with no locks held -+ * so that we don't deadlock with any pending workqueues */ -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_PM_DO_POWEROFF_START); -+ kbase_pm_check_transitions_sync(kbdev); -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_PM_DO_POWEROFF_END); -+#endif /* !PLATFORM_POWER_DOWN_ONLY */ -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ -+#if PLATFORM_POWER_DOWN_ONLY -+ if (kbdev->pm.backend.gpu_powered) { -+ if (kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_L2)) { -+ /* If L2 cache is powered then we must flush it before -+ * we power off the GPU. Normally this would have been -+ * handled when the L2 was powered off. */ -+ kbase_gpu_cacheclean(kbdev); -+ } -+ } -+#endif /* PLATFORM_POWER_DOWN_ONLY */ -+ -+ if (!backend->poweron_required) { -+#if !PLATFORM_POWER_DOWN_ONLY -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ WARN_ON(kbdev->l2_available_bitmap || -+ kbdev->shader_available_bitmap || -+ kbdev->tiler_available_bitmap); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+#endif /* !PLATFORM_POWER_DOWN_ONLY */ -+ -+ /* Consume any change-state events */ -+ kbase_timeline_pm_check_handle_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED); -+ -+ /* Disable interrupts and turn the clock off */ -+ if (!kbase_pm_clock_off(kbdev, backend->poweroff_is_suspend)) { -+ /* -+ * Page/bus faults are pending, must drop locks to -+ * process. Interrupts are disabled so no more faults -+ * should be generated at this point. -+ */ -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ kbase_flush_mmu_wqs(kbdev); -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ -+ /* Turn off clock now that fault have been handled. We -+ * dropped locks so poweron_required may have changed - -+ * power back on if this is the case.*/ -+ if (backend->poweron_required) -+ kbase_pm_clock_on(kbdev, false); -+ else -+ WARN_ON(!kbase_pm_clock_off(kbdev, -+ backend->poweroff_is_suspend)); -+ } -+ } -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ backend->poweroff_wait_in_progress = false; -+ if (backend->poweron_required) { -+ backend->poweron_required = false; -+ kbase_pm_update_cores_state_nolock(kbdev); -+ kbase_backend_slot_update(kbdev); -+ } -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ wake_up(&kbdev->pm.backend.poweroff_wait); -+} -+ -+void kbase_pm_do_poweroff(struct kbase_device *kbdev, bool is_suspend) -+{ -+ unsigned long flags; -+ -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ if (!kbdev->pm.backend.poweroff_wait_in_progress) { -+ /* Force all cores off */ -+ kbdev->pm.backend.desired_shader_state = 0; -+ kbdev->pm.backend.desired_tiler_state = 0; -+ -+ /* Force all cores to be unavailable, in the situation where -+ * transitions are in progress for some cores but not others, -+ * and kbase_pm_check_transitions_nolock can not immediately -+ * power off the cores */ -+ kbdev->shader_available_bitmap = 0; -+ kbdev->tiler_available_bitmap = 0; -+ kbdev->l2_available_bitmap = 0; -+ -+ kbdev->pm.backend.poweroff_wait_in_progress = true; -+ kbdev->pm.backend.poweroff_is_suspend = is_suspend; -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ /*Kick off wq here. Callers will have to wait*/ -+ queue_work(kbdev->pm.backend.gpu_poweroff_wait_wq, -+ &kbdev->pm.backend.gpu_poweroff_wait_work); -+ } else { -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ } -+} -+ -+static bool is_poweroff_in_progress(struct kbase_device *kbdev) -+{ -+ bool ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ ret = (kbdev->pm.backend.poweroff_wait_in_progress == false); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return ret; -+} -+ -+void kbase_pm_wait_for_poweroff_complete(struct kbase_device *kbdev) -+{ -+ wait_event_killable(kbdev->pm.backend.poweroff_wait, -+ is_poweroff_in_progress(kbdev)); -+} -+ -+int kbase_hwaccess_pm_powerup(struct kbase_device *kbdev, -+ unsigned int flags) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ unsigned long irq_flags; -+ int ret; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ -+ /* A suspend won't happen during startup/insmod */ -+ KBASE_DEBUG_ASSERT(!kbase_pm_is_suspending(kbdev)); -+ -+ /* Power up the GPU, don't enable IRQs as we are not ready to receive -+ * them. */ -+ ret = kbase_pm_init_hw(kbdev, flags); -+ if (ret) { -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ return ret; -+ } -+ -+ kbasep_pm_init_core_use_bitmaps(kbdev); -+ -+ kbdev->pm.debug_core_mask_all = kbdev->pm.debug_core_mask[0] = -+ kbdev->pm.debug_core_mask[1] = -+ kbdev->pm.debug_core_mask[2] = -+ kbdev->gpu_props.props.raw_props.shader_present; -+ -+ /* Pretend the GPU is active to prevent a power policy turning the GPU -+ * cores off */ -+ kbdev->pm.active_count = 1; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ irq_flags); -+ /* Ensure cycle counter is off */ -+ kbdev->pm.backend.gpu_cycle_counter_requests = 0; -+ spin_unlock_irqrestore( -+ &kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ irq_flags); -+ -+ /* We are ready to receive IRQ's now as power policy is set up, so -+ * enable them now. */ -+#ifdef CONFIG_MALI_DEBUG -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, irq_flags); -+ kbdev->pm.backend.driver_ready_for_irqs = true; -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, irq_flags); -+#endif -+ kbase_pm_enable_interrupts(kbdev); -+ -+ /* Turn on the GPU and any cores needed by the policy */ -+ kbase_pm_do_poweron(kbdev, false); -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ /* Idle the GPU and/or cores, if the policy wants it to */ -+ kbase_pm_context_idle(kbdev); -+ -+ return 0; -+} -+ -+void kbase_hwaccess_pm_halt(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ mutex_lock(&kbdev->pm.lock); -+ kbase_pm_cancel_deferred_poweroff(kbdev); -+ kbase_pm_do_poweroff(kbdev, false); -+ mutex_unlock(&kbdev->pm.lock); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_hwaccess_pm_halt); -+ -+void kbase_hwaccess_pm_term(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kbdev->pm.active_count == 0); -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests == 0); -+ -+ /* Free any resources the policy allocated */ -+ kbase_pm_policy_term(kbdev); -+ kbase_pm_ca_term(kbdev); -+ -+ /* Shut down the metrics subsystem */ -+ kbasep_pm_metrics_term(kbdev); -+ -+ destroy_workqueue(kbdev->pm.backend.gpu_poweroff_wait_wq); -+} -+ -+void kbase_pm_power_changed(struct kbase_device *kbdev) -+{ -+ bool cores_are_available; -+ unsigned long flags; -+ -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_GPU_INTERRUPT_START); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ cores_are_available = kbase_pm_check_transitions_nolock(kbdev); -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_GPU_INTERRUPT_END); -+ -+ if (cores_are_available) { -+ /* Log timelining information that a change in state has -+ * completed */ -+ kbase_timeline_pm_handle_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED); -+ -+ kbase_backend_slot_update(kbdev); -+ } -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+void kbase_pm_set_debug_core_mask(struct kbase_device *kbdev, -+ u64 new_core_mask_js0, u64 new_core_mask_js1, -+ u64 new_core_mask_js2) -+{ -+ kbdev->pm.debug_core_mask[0] = new_core_mask_js0; -+ kbdev->pm.debug_core_mask[1] = new_core_mask_js1; -+ kbdev->pm.debug_core_mask[2] = new_core_mask_js2; -+ kbdev->pm.debug_core_mask_all = new_core_mask_js0 | new_core_mask_js1 | -+ new_core_mask_js2; -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+} -+ -+void kbase_hwaccess_pm_gpu_active(struct kbase_device *kbdev) -+{ -+ kbase_pm_update_active(kbdev); -+} -+ -+void kbase_hwaccess_pm_gpu_idle(struct kbase_device *kbdev) -+{ -+ kbase_pm_update_active(kbdev); -+} -+ -+void kbase_hwaccess_pm_suspend(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ -+ /* Force power off the GPU and all cores (regardless of policy), only -+ * after the PM active count reaches zero (otherwise, we risk turning it -+ * off prematurely) */ -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ -+ kbase_pm_cancel_deferred_poweroff(kbdev); -+ kbase_pm_do_poweroff(kbdev, true); -+ -+ kbase_backend_timer_suspend(kbdev); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ kbase_pm_wait_for_poweroff_complete(kbdev); -+} -+ -+void kbase_hwaccess_pm_resume(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ -+ kbdev->pm.suspending = false; -+ kbase_pm_do_poweron(kbdev, true); -+ -+ kbase_backend_timer_resume(kbdev); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+} -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca.c -new file mode 100644 -index 0000000..85890f1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca.c -@@ -0,0 +1,182 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Base kernel core availability APIs -+ */ -+ -+#include -+#include -+#include -+ -+static const struct kbase_pm_ca_policy *const policy_list[] = { -+ &kbase_pm_ca_fixed_policy_ops, -+#ifdef CONFIG_MALI_DEVFREQ -+ &kbase_pm_ca_devfreq_policy_ops, -+#endif -+#if !MALI_CUSTOMER_RELEASE -+ &kbase_pm_ca_random_policy_ops -+#endif -+}; -+ -+/** -+ * POLICY_COUNT - The number of policies available in the system. -+ * -+ * This is derived from the number of functions listed in policy_list. -+ */ -+#define POLICY_COUNT (sizeof(policy_list)/sizeof(*policy_list)) -+ -+int kbase_pm_ca_init(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ kbdev->pm.backend.ca_current_policy = policy_list[0]; -+ -+ kbdev->pm.backend.ca_current_policy->init(kbdev); -+ -+ return 0; -+} -+ -+void kbase_pm_ca_term(struct kbase_device *kbdev) -+{ -+ kbdev->pm.backend.ca_current_policy->term(kbdev); -+} -+ -+int kbase_pm_ca_list_policies(const struct kbase_pm_ca_policy * const **list) -+{ -+ if (!list) -+ return POLICY_COUNT; -+ -+ *list = policy_list; -+ -+ return POLICY_COUNT; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_ca_list_policies); -+ -+const struct kbase_pm_ca_policy -+*kbase_pm_ca_get_policy(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ return kbdev->pm.backend.ca_current_policy; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_ca_get_policy); -+ -+void kbase_pm_ca_set_policy(struct kbase_device *kbdev, -+ const struct kbase_pm_ca_policy *new_policy) -+{ -+ const struct kbase_pm_ca_policy *old_policy; -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(new_policy != NULL); -+ -+ KBASE_TRACE_ADD(kbdev, PM_CA_SET_POLICY, NULL, NULL, 0u, -+ new_policy->id); -+ -+ /* During a policy change we pretend the GPU is active */ -+ /* A suspend won't happen here, because we're in a syscall from a -+ * userspace thread */ -+ kbase_pm_context_active(kbdev); -+ -+ mutex_lock(&kbdev->pm.lock); -+ -+ /* Remove the policy to prevent IRQ handlers from working on it */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ old_policy = kbdev->pm.backend.ca_current_policy; -+ kbdev->pm.backend.ca_current_policy = NULL; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ if (old_policy->term) -+ old_policy->term(kbdev); -+ -+ if (new_policy->init) -+ new_policy->init(kbdev); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbdev->pm.backend.ca_current_policy = new_policy; -+ -+ /* If any core power state changes were previously attempted, but -+ * couldn't be made because the policy was changing (current_policy was -+ * NULL), then re-try them here. */ -+ kbase_pm_update_cores_state_nolock(kbdev); -+ -+ kbdev->pm.backend.ca_current_policy->update_core_status(kbdev, -+ kbdev->shader_ready_bitmap, -+ kbdev->shader_transitioning_bitmap); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ -+ /* Now the policy change is finished, we release our fake context active -+ * reference */ -+ kbase_pm_context_idle(kbdev); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_ca_set_policy); -+ -+u64 kbase_pm_ca_get_core_mask(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ /* All cores must be enabled when instrumentation is in use */ -+ if (kbdev->pm.backend.instr_enabled) -+ return kbdev->gpu_props.props.raw_props.shader_present & -+ kbdev->pm.debug_core_mask_all; -+ -+ if (kbdev->pm.backend.ca_current_policy == NULL) -+ return kbdev->gpu_props.props.raw_props.shader_present & -+ kbdev->pm.debug_core_mask_all; -+ -+ return kbdev->pm.backend.ca_current_policy->get_core_mask(kbdev) & -+ kbdev->pm.debug_core_mask_all; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_ca_get_core_mask); -+ -+void kbase_pm_ca_update_core_status(struct kbase_device *kbdev, u64 cores_ready, -+ u64 cores_transitioning) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (kbdev->pm.backend.ca_current_policy != NULL) -+ kbdev->pm.backend.ca_current_policy->update_core_status(kbdev, -+ cores_ready, -+ cores_transitioning); -+} -+ -+void kbase_pm_ca_instr_enable(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbdev->pm.backend.instr_enabled = true; -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+void kbase_pm_ca_instr_disable(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ kbdev->pm.backend.instr_enabled = false; -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+} -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca.h -new file mode 100644 -index 0000000..ee9e751 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca.h -@@ -0,0 +1,92 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Base kernel core availability APIs -+ */ -+ -+#ifndef _KBASE_PM_CA_H_ -+#define _KBASE_PM_CA_H_ -+ -+/** -+ * kbase_pm_ca_init - Initialize core availability framework -+ * -+ * Must be called before calling any other core availability function -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Return: 0 if the core availability framework was successfully initialized, -+ * -errno otherwise -+ */ -+int kbase_pm_ca_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_ca_term - Terminate core availability framework -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_ca_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_ca_get_core_mask - Get currently available shaders core mask -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Returns a mask of the currently available shader cores. -+ * Calls into the core availability policy -+ * -+ * Return: The bit mask of available cores -+ */ -+u64 kbase_pm_ca_get_core_mask(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_ca_update_core_status - Update core status -+ * -+ * @kbdev: The kbase device structure for the device (must be -+ * a valid pointer) -+ * @cores_ready: The bit mask of cores ready for job submission -+ * @cores_transitioning: The bit mask of cores that are transitioning power -+ * state -+ * -+ * Update core availability policy with current core power status -+ * -+ * Calls into the core availability policy -+ */ -+void kbase_pm_ca_update_core_status(struct kbase_device *kbdev, u64 cores_ready, -+ u64 cores_transitioning); -+ -+/** -+ * kbase_pm_ca_instr_enable - Enable override for instrumentation -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * This overrides the output of the core availability policy, ensuring that all -+ * cores are available -+ */ -+void kbase_pm_ca_instr_enable(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_ca_instr_disable - Disable override for instrumentation -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * This disables any previously enabled override, and resumes normal policy -+ * functionality -+ */ -+void kbase_pm_ca_instr_disable(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_PM_CA_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_devfreq.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_devfreq.c -new file mode 100644 -index 0000000..66bf660 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_devfreq.c -@@ -0,0 +1,129 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * A core availability policy implementing core mask selection from devfreq OPPs -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+void kbase_devfreq_set_core_mask(struct kbase_device *kbdev, u64 core_mask) -+{ -+ struct kbasep_pm_ca_policy_devfreq *data = -+ &kbdev->pm.backend.ca_policy_data.devfreq; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ data->cores_desired = core_mask; -+ -+ /* Disable any cores that are now unwanted */ -+ data->cores_enabled &= data->cores_desired; -+ -+ kbdev->pm.backend.ca_in_transition = true; -+ -+ /* If there are no cores to be powered off then power on desired cores -+ */ -+ if (!(data->cores_used & ~data->cores_desired)) { -+ data->cores_enabled = data->cores_desired; -+ kbdev->pm.backend.ca_in_transition = false; -+ } -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ dev_dbg(kbdev->dev, "Devfreq policy : new core mask=%llX %llX\n", -+ data->cores_desired, data->cores_enabled); -+} -+ -+static void devfreq_init(struct kbase_device *kbdev) -+{ -+ struct kbasep_pm_ca_policy_devfreq *data = -+ &kbdev->pm.backend.ca_policy_data.devfreq; -+ -+ if (kbdev->current_core_mask) { -+ data->cores_enabled = kbdev->current_core_mask; -+ data->cores_desired = kbdev->current_core_mask; -+ } else { -+ data->cores_enabled = -+ kbdev->gpu_props.props.raw_props.shader_present; -+ data->cores_desired = -+ kbdev->gpu_props.props.raw_props.shader_present; -+ } -+ data->cores_used = 0; -+ kbdev->pm.backend.ca_in_transition = false; -+} -+ -+static void devfreq_term(struct kbase_device *kbdev) -+{ -+} -+ -+static u64 devfreq_get_core_mask(struct kbase_device *kbdev) -+{ -+ return kbdev->pm.backend.ca_policy_data.devfreq.cores_enabled; -+} -+ -+static void devfreq_update_core_status(struct kbase_device *kbdev, -+ u64 cores_ready, -+ u64 cores_transitioning) -+{ -+ struct kbasep_pm_ca_policy_devfreq *data = -+ &kbdev->pm.backend.ca_policy_data.devfreq; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ data->cores_used = cores_ready | cores_transitioning; -+ -+ /* If in desired state then clear transition flag */ -+ if (data->cores_enabled == data->cores_desired) -+ kbdev->pm.backend.ca_in_transition = false; -+ -+ /* If all undesired cores are now off then power on desired cores. -+ * The direct comparison against cores_enabled limits potential -+ * recursion to one level */ -+ if (!(data->cores_used & ~data->cores_desired) && -+ data->cores_enabled != data->cores_desired) { -+ data->cores_enabled = data->cores_desired; -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+ -+ kbdev->pm.backend.ca_in_transition = false; -+ } -+} -+ -+/* -+ * The struct kbase_pm_ca_policy structure for the devfreq core availability -+ * policy. -+ * -+ * This is the static structure that defines the devfreq core availability power -+ * policy's callback and name. -+ */ -+const struct kbase_pm_ca_policy kbase_pm_ca_devfreq_policy_ops = { -+ "devfreq", /* name */ -+ devfreq_init, /* init */ -+ devfreq_term, /* term */ -+ devfreq_get_core_mask, /* get_core_mask */ -+ devfreq_update_core_status, /* update_core_status */ -+ 0u, /* flags */ -+ KBASE_PM_CA_POLICY_ID_DEVFREQ, /* id */ -+}; -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_devfreq.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_devfreq.h -new file mode 100644 -index 0000000..7ab3cd4 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_devfreq.h -@@ -0,0 +1,55 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * A core availability policy for use with devfreq, where core masks are -+ * associated with OPPs. -+ */ -+ -+#ifndef MALI_KBASE_PM_CA_DEVFREQ_H -+#define MALI_KBASE_PM_CA_DEVFREQ_H -+ -+/** -+ * struct kbasep_pm_ca_policy_devfreq - Private structure for devfreq ca policy -+ * -+ * This contains data that is private to the devfreq core availability -+ * policy. -+ * -+ * @cores_desired: Cores that the policy wants to be available -+ * @cores_enabled: Cores that the policy is currently returning as available -+ * @cores_used: Cores currently powered or transitioning -+ */ -+struct kbasep_pm_ca_policy_devfreq { -+ u64 cores_desired; -+ u64 cores_enabled; -+ u64 cores_used; -+}; -+ -+extern const struct kbase_pm_ca_policy kbase_pm_ca_devfreq_policy_ops; -+ -+/** -+ * kbase_devfreq_set_core_mask - Set core mask for policy to use -+ * @kbdev: Device pointer -+ * @core_mask: New core mask -+ * -+ * The new core mask will have immediate effect if the GPU is powered, or will -+ * take effect when it is next powered on. -+ */ -+void kbase_devfreq_set_core_mask(struct kbase_device *kbdev, u64 core_mask); -+ -+#endif /* MALI_KBASE_PM_CA_DEVFREQ_H */ -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_fixed.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_fixed.c -new file mode 100644 -index 0000000..864612d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_fixed.c -@@ -0,0 +1,65 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * A power policy implementing fixed core availability -+ */ -+ -+#include -+#include -+ -+static void fixed_init(struct kbase_device *kbdev) -+{ -+ kbdev->pm.backend.ca_in_transition = false; -+} -+ -+static void fixed_term(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+static u64 fixed_get_core_mask(struct kbase_device *kbdev) -+{ -+ return kbdev->gpu_props.props.raw_props.shader_present; -+} -+ -+static void fixed_update_core_status(struct kbase_device *kbdev, -+ u64 cores_ready, -+ u64 cores_transitioning) -+{ -+ CSTD_UNUSED(kbdev); -+ CSTD_UNUSED(cores_ready); -+ CSTD_UNUSED(cores_transitioning); -+} -+ -+/* -+ * The struct kbase_pm_policy structure for the fixed power policy. -+ * -+ * This is the static structure that defines the fixed power policy's callback -+ * and name. -+ */ -+const struct kbase_pm_ca_policy kbase_pm_ca_fixed_policy_ops = { -+ "fixed", /* name */ -+ fixed_init, /* init */ -+ fixed_term, /* term */ -+ fixed_get_core_mask, /* get_core_mask */ -+ fixed_update_core_status, /* update_core_status */ -+ 0u, /* flags */ -+ KBASE_PM_CA_POLICY_ID_FIXED, /* id */ -+}; -+ -+KBASE_EXPORT_TEST_API(kbase_pm_ca_fixed_policy_ops); -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_fixed.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_fixed.h -new file mode 100644 -index 0000000..a763155 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_ca_fixed.h -@@ -0,0 +1,40 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * A power policy implementing fixed core availability -+ */ -+ -+#ifndef MALI_KBASE_PM_CA_FIXED_H -+#define MALI_KBASE_PM_CA_FIXED_H -+ -+/** -+ * struct kbasep_pm_ca_policy_fixed - Private structure for policy instance data -+ * -+ * @dummy: Dummy member - no state is needed -+ * -+ * This contains data that is private to the particular power policy that is -+ * active. -+ */ -+struct kbasep_pm_ca_policy_fixed { -+ int dummy; -+}; -+ -+extern const struct kbase_pm_ca_policy kbase_pm_ca_fixed_policy_ops; -+ -+#endif /* MALI_KBASE_PM_CA_FIXED_H */ -+ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_coarse_demand.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_coarse_demand.c -new file mode 100644 -index 0000000..f891fa2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_coarse_demand.c -@@ -0,0 +1,70 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * "Coarse Demand" power management policy -+ */ -+ -+#include -+#include -+ -+static u64 coarse_demand_get_core_mask(struct kbase_device *kbdev) -+{ -+ if (kbdev->pm.active_count == 0) -+ return 0; -+ -+ return kbdev->gpu_props.props.raw_props.shader_present; -+} -+ -+static bool coarse_demand_get_core_active(struct kbase_device *kbdev) -+{ -+ if (0 == kbdev->pm.active_count && !(kbdev->shader_needed_bitmap | -+ kbdev->shader_inuse_bitmap) && !kbdev->tiler_needed_cnt -+ && !kbdev->tiler_inuse_cnt) -+ return false; -+ -+ return true; -+} -+ -+static void coarse_demand_init(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+static void coarse_demand_term(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+/* The struct kbase_pm_policy structure for the demand power policy. -+ * -+ * This is the static structure that defines the demand power policy's callback -+ * and name. -+ */ -+const struct kbase_pm_policy kbase_pm_coarse_demand_policy_ops = { -+ "coarse_demand", /* name */ -+ coarse_demand_init, /* init */ -+ coarse_demand_term, /* term */ -+ coarse_demand_get_core_mask, /* get_core_mask */ -+ coarse_demand_get_core_active, /* get_core_active */ -+ 0u, /* flags */ -+ KBASE_PM_POLICY_ID_COARSE_DEMAND, /* id */ -+}; -+ -+KBASE_EXPORT_TEST_API(kbase_pm_coarse_demand_policy_ops); -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_coarse_demand.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_coarse_demand.h -new file mode 100644 -index 0000000..749d305 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_coarse_demand.h -@@ -0,0 +1,64 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * "Coarse Demand" power management policy -+ */ -+ -+#ifndef MALI_KBASE_PM_COARSE_DEMAND_H -+#define MALI_KBASE_PM_COARSE_DEMAND_H -+ -+/** -+ * DOC: -+ * The "Coarse" demand power management policy has the following -+ * characteristics: -+ * - When KBase indicates that the GPU will be powered up, but we don't yet -+ * know which Job Chains are to be run: -+ * - All Shader Cores are powered up, regardless of whether or not they will -+ * be needed later. -+ * - When KBase indicates that a set of Shader Cores are needed to submit the -+ * currently queued Job Chains: -+ * - All Shader Cores are kept powered, regardless of whether or not they will -+ * be needed -+ * - When KBase indicates that the GPU need not be powered: -+ * - The Shader Cores are powered off, and the GPU itself is powered off too. -+ * -+ * @note: -+ * - KBase indicates the GPU will be powered up when it has a User Process that -+ * has just started to submit Job Chains. -+ * - KBase indicates the GPU need not be powered when all the Job Chains from -+ * User Processes have finished, and it is waiting for a User Process to -+ * submit some more Job Chains. -+ */ -+ -+/** -+ * struct kbasep_pm_policy_coarse_demand - Private structure for coarse demand -+ * policy -+ * -+ * This contains data that is private to the coarse demand power policy. -+ * -+ * @dummy: Dummy member - no state needed -+ */ -+struct kbasep_pm_policy_coarse_demand { -+ int dummy; -+}; -+ -+extern const struct kbase_pm_policy kbase_pm_coarse_demand_policy_ops; -+ -+#endif /* MALI_KBASE_PM_COARSE_DEMAND_H */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_defs.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_defs.h -new file mode 100644 -index 0000000..352744e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_defs.h -@@ -0,0 +1,519 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Backend-specific Power Manager definitions -+ */ -+ -+#ifndef _KBASE_PM_HWACCESS_DEFS_H_ -+#define _KBASE_PM_HWACCESS_DEFS_H_ -+ -+#include "mali_kbase_pm_ca_fixed.h" -+#include "mali_kbase_pm_ca_devfreq.h" -+#if !MALI_CUSTOMER_RELEASE -+#include "mali_kbase_pm_ca_random.h" -+#endif -+ -+#include "mali_kbase_pm_always_on.h" -+#include "mali_kbase_pm_coarse_demand.h" -+#include "mali_kbase_pm_demand.h" -+#if !MALI_CUSTOMER_RELEASE -+#include "mali_kbase_pm_demand_always_powered.h" -+#include "mali_kbase_pm_fast_start.h" -+#endif -+ -+/* Forward definition - see mali_kbase.h */ -+struct kbase_device; -+struct kbase_jd_atom; -+ -+/** -+ * enum kbase_pm_core_type - The types of core in a GPU. -+ * -+ * These enumerated values are used in calls to -+ * - kbase_pm_get_present_cores() -+ * - kbase_pm_get_active_cores() -+ * - kbase_pm_get_trans_cores() -+ * - kbase_pm_get_ready_cores(). -+ * -+ * They specify which type of core should be acted on. These values are set in -+ * a manner that allows core_type_to_reg() function to be simpler and more -+ * efficient. -+ * -+ * @KBASE_PM_CORE_L2: The L2 cache -+ * @KBASE_PM_CORE_SHADER: Shader cores -+ * @KBASE_PM_CORE_TILER: Tiler cores -+ * @KBASE_PM_CORE_STACK: Core stacks -+ */ -+enum kbase_pm_core_type { -+ KBASE_PM_CORE_L2 = L2_PRESENT_LO, -+ KBASE_PM_CORE_SHADER = SHADER_PRESENT_LO, -+ KBASE_PM_CORE_TILER = TILER_PRESENT_LO, -+ KBASE_PM_CORE_STACK = STACK_PRESENT_LO -+}; -+ -+/** -+ * struct kbasep_pm_metrics_data - Metrics data collected for use by the power -+ * management framework. -+ * -+ * @time_period_start: time at which busy/idle measurements started -+ * @time_busy: number of ns the GPU was busy executing jobs since the -+ * @time_period_start timestamp. -+ * @time_idle: number of ns since time_period_start the GPU was not executing -+ * jobs since the @time_period_start timestamp. -+ * @prev_busy: busy time in ns of previous time period. -+ * Updated when metrics are reset. -+ * @prev_idle: idle time in ns of previous time period -+ * Updated when metrics are reset. -+ * @gpu_active: true when the GPU is executing jobs. false when -+ * not. Updated when the job scheduler informs us a job in submitted -+ * or removed from a GPU slot. -+ * @busy_cl: number of ns the GPU was busy executing CL jobs. Note that -+ * if two CL jobs were active for 400ns, this value would be updated -+ * with 800. -+ * @busy_gl: number of ns the GPU was busy executing GL jobs. Note that -+ * if two GL jobs were active for 400ns, this value would be updated -+ * with 800. -+ * @active_cl_ctx: number of CL jobs active on the GPU. Array is per-device. -+ * @active_gl_ctx: number of GL jobs active on the GPU. Array is per-slot. As -+ * GL jobs never run on slot 2 this slot is not recorded. -+ * @lock: spinlock protecting the kbasep_pm_metrics_data structure -+ * @timer: timer to regularly make DVFS decisions based on the power -+ * management metrics. -+ * @timer_active: boolean indicating @timer is running -+ * @platform_data: pointer to data controlled by platform specific code -+ * @kbdev: pointer to kbase device for which metrics are collected -+ * -+ */ -+struct kbasep_pm_metrics_data { -+ ktime_t time_period_start; -+ u32 time_busy; -+ u32 time_idle; -+ u32 prev_busy; -+ u32 prev_idle; -+ bool gpu_active; -+ u32 busy_cl[2]; -+ u32 busy_gl; -+ u32 active_cl_ctx[2]; -+ u32 active_gl_ctx[2]; /* GL jobs can only run on 2 of the 3 job slots */ -+ spinlock_t lock; -+ -+#ifdef CONFIG_MALI_MIDGARD_DVFS -+ struct hrtimer timer; -+ bool timer_active; -+#endif -+ -+ void *platform_data; -+ struct kbase_device *kbdev; -+}; -+ -+union kbase_pm_policy_data { -+ struct kbasep_pm_policy_always_on always_on; -+ struct kbasep_pm_policy_coarse_demand coarse_demand; -+ struct kbasep_pm_policy_demand demand; -+#if !MALI_CUSTOMER_RELEASE -+ struct kbasep_pm_policy_demand_always_powered demand_always_powered; -+ struct kbasep_pm_policy_fast_start fast_start; -+#endif -+}; -+ -+union kbase_pm_ca_policy_data { -+ struct kbasep_pm_ca_policy_fixed fixed; -+ struct kbasep_pm_ca_policy_devfreq devfreq; -+#if !MALI_CUSTOMER_RELEASE -+ struct kbasep_pm_ca_policy_random random; -+#endif -+}; -+ -+/** -+ * struct kbase_pm_backend_data - Data stored per device for power management. -+ * -+ * This structure contains data for the power management framework. There is one -+ * instance of this structure per device in the system. -+ * -+ * @ca_current_policy: The policy that is currently actively controlling core -+ * availability. -+ * @pm_current_policy: The policy that is currently actively controlling the -+ * power state. -+ * @ca_policy_data: Private data for current CA policy -+ * @pm_policy_data: Private data for current PM policy -+ * @ca_in_transition: Flag indicating when core availability policy is -+ * transitioning cores. The core availability policy must -+ * set this when a change in core availability is occurring. -+ * power_change_lock must be held when accessing this. -+ * @reset_done: Flag when a reset is complete -+ * @reset_done_wait: Wait queue to wait for changes to @reset_done -+ * @l2_powered_wait: Wait queue for whether the l2 cache has been powered as -+ * requested -+ * @l2_powered: State indicating whether all the l2 caches are powered. -+ * Non-zero indicates they're *all* powered -+ * Zero indicates that some (or all) are not powered -+ * @gpu_cycle_counter_requests: The reference count of active gpu cycle counter -+ * users -+ * @gpu_cycle_counter_requests_lock: Lock to protect @gpu_cycle_counter_requests -+ * @desired_shader_state: A bit mask identifying the shader cores that the -+ * power policy would like to be on. The current state -+ * of the cores may be different, but there should be -+ * transitions in progress that will eventually achieve -+ * this state (assuming that the policy doesn't change -+ * its mind in the mean time). -+ * @powering_on_shader_state: A bit mask indicating which shader cores are -+ * currently in a power-on transition -+ * @desired_tiler_state: A bit mask identifying the tiler cores that the power -+ * policy would like to be on. See @desired_shader_state -+ * @powering_on_tiler_state: A bit mask indicating which tiler core are -+ * currently in a power-on transition -+ * @powering_on_l2_state: A bit mask indicating which l2-caches are currently -+ * in a power-on transition -+ * @powering_on_stack_state: A bit mask indicating which core stacks are -+ * currently in a power-on transition -+ * @gpu_in_desired_state: This flag is set if the GPU is powered as requested -+ * by the desired_xxx_state variables -+ * @gpu_in_desired_state_wait: Wait queue set when @gpu_in_desired_state != 0 -+ * @gpu_powered: Set to true when the GPU is powered and register -+ * accesses are possible, false otherwise -+ * @instr_enabled: Set to true when instrumentation is enabled, -+ * false otherwise -+ * @cg1_disabled: Set if the policy wants to keep the second core group -+ * powered off -+ * @driver_ready_for_irqs: Debug state indicating whether sufficient -+ * initialization of the driver has occurred to handle -+ * IRQs -+ * @gpu_powered_lock: Spinlock that must be held when writing @gpu_powered or -+ * accessing @driver_ready_for_irqs -+ * @metrics: Structure to hold metrics for the GPU -+ * @gpu_poweroff_pending: number of poweroff timer ticks until the GPU is -+ * powered off -+ * @shader_poweroff_pending_time: number of poweroff timer ticks until shaders -+ * and/or timers are powered off -+ * @gpu_poweroff_timer: Timer for powering off GPU -+ * @gpu_poweroff_wq: Workqueue to power off GPU on when timer fires -+ * @gpu_poweroff_work: Workitem used on @gpu_poweroff_wq -+ * @shader_poweroff_pending: Bit mask of shaders to be powered off on next -+ * timer callback -+ * @tiler_poweroff_pending: Bit mask of tilers to be powered off on next timer -+ * callback -+ * @poweroff_timer_needed: true if the poweroff timer is currently required, -+ * false otherwise -+ * @poweroff_timer_running: true if the poweroff timer is currently running, -+ * false otherwise -+ * power_change_lock should be held when accessing, -+ * unless there is no way the timer can be running (eg -+ * hrtimer_cancel() was called immediately before) -+ * @poweroff_wait_in_progress: true if a wait for GPU power off is in progress. -+ * hwaccess_lock must be held when accessing -+ * @poweron_required: true if a GPU power on is required. Should only be set -+ * when poweroff_wait_in_progress is true, and therefore the -+ * GPU can not immediately be powered on. pm.lock must be -+ * held when accessing -+ * @poweroff_is_suspend: true if the GPU is being powered off due to a suspend -+ * request. pm.lock must be held when accessing -+ * @gpu_poweroff_wait_wq: workqueue for waiting for GPU to power off -+ * @gpu_poweroff_wait_work: work item for use with @gpu_poweroff_wait_wq -+ * @poweroff_wait: waitqueue for waiting for @gpu_poweroff_wait_work to complete -+ * @callback_power_on: Callback when the GPU needs to be turned on. See -+ * &struct kbase_pm_callback_conf -+ * @callback_power_off: Callback when the GPU may be turned off. See -+ * &struct kbase_pm_callback_conf -+ * @callback_power_suspend: Callback when a suspend occurs and the GPU needs to -+ * be turned off. See &struct kbase_pm_callback_conf -+ * @callback_power_resume: Callback when a resume occurs and the GPU needs to -+ * be turned on. See &struct kbase_pm_callback_conf -+ * @callback_power_runtime_on: Callback when the GPU needs to be turned on. See -+ * &struct kbase_pm_callback_conf -+ * @callback_power_runtime_off: Callback when the GPU may be turned off. See -+ * &struct kbase_pm_callback_conf -+ * @callback_power_runtime_idle: Optional callback when the GPU may be idle. See -+ * &struct kbase_pm_callback_conf -+ * -+ * Note: -+ * During an IRQ, @ca_current_policy or @pm_current_policy can be NULL when the -+ * policy is being changed with kbase_pm_ca_set_policy() or -+ * kbase_pm_set_policy(). The change is protected under -+ * kbase_device.pm.power_change_lock. Direct access to this -+ * from IRQ context must therefore check for NULL. If NULL, then -+ * kbase_pm_ca_set_policy() or kbase_pm_set_policy() will re-issue the policy -+ * functions that would have been done under IRQ. -+ */ -+struct kbase_pm_backend_data { -+ const struct kbase_pm_ca_policy *ca_current_policy; -+ const struct kbase_pm_policy *pm_current_policy; -+ union kbase_pm_ca_policy_data ca_policy_data; -+ union kbase_pm_policy_data pm_policy_data; -+ bool ca_in_transition; -+ bool reset_done; -+ wait_queue_head_t reset_done_wait; -+ wait_queue_head_t l2_powered_wait; -+ int l2_powered; -+ int gpu_cycle_counter_requests; -+ spinlock_t gpu_cycle_counter_requests_lock; -+ -+ u64 desired_shader_state; -+ u64 powering_on_shader_state; -+ u64 desired_tiler_state; -+ u64 powering_on_tiler_state; -+ u64 powering_on_l2_state; -+#ifdef CONFIG_MALI_CORESTACK -+ u64 powering_on_stack_state; -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+ bool gpu_in_desired_state; -+ wait_queue_head_t gpu_in_desired_state_wait; -+ -+ bool gpu_powered; -+ -+ bool instr_enabled; -+ -+ bool cg1_disabled; -+ -+#ifdef CONFIG_MALI_DEBUG -+ bool driver_ready_for_irqs; -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ spinlock_t gpu_powered_lock; -+ -+ -+ struct kbasep_pm_metrics_data metrics; -+ -+ int gpu_poweroff_pending; -+ int shader_poweroff_pending_time; -+ -+ struct hrtimer gpu_poweroff_timer; -+ struct workqueue_struct *gpu_poweroff_wq; -+ struct work_struct gpu_poweroff_work; -+ -+ u64 shader_poweroff_pending; -+ u64 tiler_poweroff_pending; -+ -+ bool poweroff_timer_needed; -+ bool poweroff_timer_running; -+ -+ bool poweroff_wait_in_progress; -+ bool poweron_required; -+ bool poweroff_is_suspend; -+ -+ struct workqueue_struct *gpu_poweroff_wait_wq; -+ struct work_struct gpu_poweroff_wait_work; -+ -+ wait_queue_head_t poweroff_wait; -+ -+ int (*callback_power_on)(struct kbase_device *kbdev); -+ void (*callback_power_off)(struct kbase_device *kbdev); -+ void (*callback_power_suspend)(struct kbase_device *kbdev); -+ void (*callback_power_resume)(struct kbase_device *kbdev); -+ int (*callback_power_runtime_on)(struct kbase_device *kbdev); -+ void (*callback_power_runtime_off)(struct kbase_device *kbdev); -+ int (*callback_power_runtime_idle)(struct kbase_device *kbdev); -+}; -+ -+ -+/* List of policy IDs */ -+enum kbase_pm_policy_id { -+ KBASE_PM_POLICY_ID_DEMAND = 1, -+ KBASE_PM_POLICY_ID_ALWAYS_ON, -+ KBASE_PM_POLICY_ID_COARSE_DEMAND, -+#if !MALI_CUSTOMER_RELEASE -+ KBASE_PM_POLICY_ID_DEMAND_ALWAYS_POWERED, -+ KBASE_PM_POLICY_ID_FAST_START -+#endif -+}; -+ -+typedef u32 kbase_pm_policy_flags; -+ -+/** -+ * struct kbase_pm_policy - Power policy structure. -+ * -+ * Each power policy exposes a (static) instance of this structure which -+ * contains function pointers to the policy's methods. -+ * -+ * @name: The name of this policy -+ * @init: Function called when the policy is selected -+ * @term: Function called when the policy is unselected -+ * @get_core_mask: Function called to get the current shader core mask -+ * @get_core_active: Function called to get the current overall GPU power -+ * state -+ * @flags: Field indicating flags for this policy -+ * @id: Field indicating an ID for this policy. This is not -+ * necessarily the same as its index in the list returned -+ * by kbase_pm_list_policies(). -+ * It is used purely for debugging. -+ */ -+struct kbase_pm_policy { -+ char *name; -+ -+ /** -+ * Function called when the policy is selected -+ * -+ * This should initialize the kbdev->pm.pm_policy_data structure. It -+ * should not attempt to make any changes to hardware state. -+ * -+ * It is undefined what state the cores are in when the function is -+ * called. -+ * -+ * @kbdev: The kbase device structure for the device (must be a -+ * valid pointer) -+ */ -+ void (*init)(struct kbase_device *kbdev); -+ -+ /** -+ * Function called when the policy is unselected. -+ * -+ * @kbdev: The kbase device structure for the device (must be a -+ * valid pointer) -+ */ -+ void (*term)(struct kbase_device *kbdev); -+ -+ /** -+ * Function called to get the current shader core mask -+ * -+ * The returned mask should meet or exceed (kbdev->shader_needed_bitmap -+ * | kbdev->shader_inuse_bitmap). -+ * -+ * @kbdev: The kbase device structure for the device (must be a -+ * valid pointer) -+ * -+ * Return: The mask of shader cores to be powered -+ */ -+ u64 (*get_core_mask)(struct kbase_device *kbdev); -+ -+ /** -+ * Function called to get the current overall GPU power state -+ * -+ * This function should consider the state of kbdev->pm.active_count. If -+ * this count is greater than 0 then there is at least one active -+ * context on the device and the GPU should be powered. If it is equal -+ * to 0 then there are no active contexts and the GPU could be powered -+ * off if desired. -+ * -+ * @kbdev: The kbase device structure for the device (must be a -+ * valid pointer) -+ * -+ * Return: true if the GPU should be powered, false otherwise -+ */ -+ bool (*get_core_active)(struct kbase_device *kbdev); -+ -+ kbase_pm_policy_flags flags; -+ enum kbase_pm_policy_id id; -+}; -+ -+ -+enum kbase_pm_ca_policy_id { -+ KBASE_PM_CA_POLICY_ID_FIXED = 1, -+ KBASE_PM_CA_POLICY_ID_DEVFREQ, -+ KBASE_PM_CA_POLICY_ID_RANDOM -+}; -+ -+typedef u32 kbase_pm_ca_policy_flags; -+ -+/** -+ * Maximum length of a CA policy names -+ */ -+#define KBASE_PM_CA_MAX_POLICY_NAME_LEN 15 -+ -+/** -+ * struct kbase_pm_ca_policy - Core availability policy structure. -+ * -+ * Each core availability policy exposes a (static) instance of this structure -+ * which contains function pointers to the policy's methods. -+ * -+ * @name: The name of this policy -+ * @init: Function called when the policy is selected -+ * @term: Function called when the policy is unselected -+ * @get_core_mask: Function called to get the current shader core -+ * availability mask -+ * @update_core_status: Function called to update the current core status -+ * @flags: Field indicating flags for this policy -+ * @id: Field indicating an ID for this policy. This is not -+ * necessarily the same as its index in the list returned -+ * by kbase_pm_list_policies(). -+ * It is used purely for debugging. -+ */ -+struct kbase_pm_ca_policy { -+ char name[KBASE_PM_CA_MAX_POLICY_NAME_LEN + 1]; -+ -+ /** -+ * Function called when the policy is selected -+ * -+ * This should initialize the kbdev->pm.ca_policy_data structure. It -+ * should not attempt to make any changes to hardware state. -+ * -+ * It is undefined what state the cores are in when the function is -+ * called. -+ * -+ * @kbdev The kbase device structure for the device (must be a -+ * valid pointer) -+ */ -+ void (*init)(struct kbase_device *kbdev); -+ -+ /** -+ * Function called when the policy is unselected. -+ * -+ * @kbdev The kbase device structure for the device (must be a -+ * valid pointer) -+ */ -+ void (*term)(struct kbase_device *kbdev); -+ -+ /** -+ * Function called to get the current shader core availability mask -+ * -+ * When a change in core availability is occurring, the policy must set -+ * kbdev->pm.ca_in_transition to true. This is to indicate that -+ * reporting changes in power state cannot be optimized out, even if -+ * kbdev->pm.desired_shader_state remains unchanged. This must be done -+ * by any functions internal to the Core Availability Policy that change -+ * the return value of kbase_pm_ca_policy::get_core_mask. -+ * -+ * @kbdev The kbase device structure for the device (must be a -+ * valid pointer) -+ * -+ * Return: The current core availability mask -+ */ -+ u64 (*get_core_mask)(struct kbase_device *kbdev); -+ -+ /** -+ * Function called to update the current core status -+ * -+ * If none of the cores in core group 0 are ready or transitioning, then -+ * the policy must ensure that the next call to get_core_mask does not -+ * return 0 for all cores in core group 0. It is an error to disable -+ * core group 0 through the core availability policy. -+ * -+ * When a change in core availability has finished, the policy must set -+ * kbdev->pm.ca_in_transition to false. This is to indicate that -+ * changes in power state can once again be optimized out when -+ * kbdev->pm.desired_shader_state is unchanged. -+ * -+ * @kbdev: The kbase device structure for the device -+ * (must be a valid pointer) -+ * @cores_ready: The mask of cores currently powered and -+ * ready to run jobs -+ * @cores_transitioning: The mask of cores currently transitioning -+ * power state -+ */ -+ void (*update_core_status)(struct kbase_device *kbdev, u64 cores_ready, -+ u64 cores_transitioning); -+ -+ kbase_pm_ca_policy_flags flags; -+ -+ /** -+ * Field indicating an ID for this policy. This is not necessarily the -+ * same as its index in the list returned by kbase_pm_list_policies(). -+ * It is used purely for debugging. -+ */ -+ enum kbase_pm_ca_policy_id id; -+}; -+ -+#endif /* _KBASE_PM_HWACCESS_DEFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_demand.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_demand.c -new file mode 100644 -index 0000000..81322fd ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_demand.c -@@ -0,0 +1,73 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * A simple demand based power management policy -+ */ -+ -+#include -+#include -+ -+static u64 demand_get_core_mask(struct kbase_device *kbdev) -+{ -+ u64 desired = kbdev->shader_needed_bitmap | kbdev->shader_inuse_bitmap; -+ -+ if (0 == kbdev->pm.active_count) -+ return 0; -+ -+ return desired; -+} -+ -+static bool demand_get_core_active(struct kbase_device *kbdev) -+{ -+ if (0 == kbdev->pm.active_count && !(kbdev->shader_needed_bitmap | -+ kbdev->shader_inuse_bitmap) && !kbdev->tiler_needed_cnt -+ && !kbdev->tiler_inuse_cnt) -+ return false; -+ -+ return true; -+} -+ -+static void demand_init(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+static void demand_term(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+/* -+ * The struct kbase_pm_policy structure for the demand power policy. -+ * -+ * This is the static structure that defines the demand power policy's callback -+ * and name. -+ */ -+const struct kbase_pm_policy kbase_pm_demand_policy_ops = { -+ "demand", /* name */ -+ demand_init, /* init */ -+ demand_term, /* term */ -+ demand_get_core_mask, /* get_core_mask */ -+ demand_get_core_active, /* get_core_active */ -+ 0u, /* flags */ -+ KBASE_PM_POLICY_ID_DEMAND, /* id */ -+}; -+ -+KBASE_EXPORT_TEST_API(kbase_pm_demand_policy_ops); -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_demand.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_demand.h -new file mode 100644 -index 0000000..c0c84b6 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_demand.h -@@ -0,0 +1,64 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * A simple demand based power management policy -+ */ -+ -+#ifndef MALI_KBASE_PM_DEMAND_H -+#define MALI_KBASE_PM_DEMAND_H -+ -+/** -+ * DOC: Demand power management policy -+ * -+ * The demand power management policy has the following characteristics: -+ * - When KBase indicates that the GPU will be powered up, but we don't yet -+ * know which Job Chains are to be run: -+ * - The Shader Cores are not powered up -+ * -+ * - When KBase indicates that a set of Shader Cores are needed to submit the -+ * currently queued Job Chains: -+ * - Only those Shader Cores are powered up -+ * -+ * - When KBase indicates that the GPU need not be powered: -+ * - The Shader Cores are powered off, and the GPU itself is powered off too. -+ * -+ * Note: -+ * - KBase indicates the GPU will be powered up when it has a User Process that -+ * has just started to submit Job Chains. -+ * -+ * - KBase indicates the GPU need not be powered when all the Job Chains from -+ * User Processes have finished, and it is waiting for a User Process to -+ * submit some more Job Chains. -+ */ -+ -+/** -+ * struct kbasep_pm_policy_demand - Private structure for policy instance data -+ * -+ * @dummy: No state is needed, a dummy variable -+ * -+ * This contains data that is private to the demand power policy. -+ */ -+struct kbasep_pm_policy_demand { -+ int dummy; -+}; -+ -+extern const struct kbase_pm_policy kbase_pm_demand_policy_ops; -+ -+#endif /* MALI_KBASE_PM_DEMAND_H */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_driver.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_driver.c -new file mode 100644 -index 0000000..ed19a8a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_driver.c -@@ -0,0 +1,1671 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Base kernel Power Management hardware control -+ */ -+ -+#include -+#include -+#include -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+#include -+#endif -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#if MALI_MOCK_TEST -+#define MOCKABLE(function) function##_original -+#else -+#define MOCKABLE(function) function -+#endif /* MALI_MOCK_TEST */ -+ -+/** -+ * enum kbasep_pm_action - Actions that can be performed on a core. -+ * -+ * This enumeration is private to the file. Its values are set to allow -+ * core_type_to_reg() function, which decodes this enumeration, to be simpler -+ * and more efficient. -+ * -+ * @ACTION_PRESENT: The cores that are present -+ * @ACTION_READY: The cores that are ready -+ * @ACTION_PWRON: Power on the cores specified -+ * @ACTION_PWROFF: Power off the cores specified -+ * @ACTION_PWRTRANS: The cores that are transitioning -+ * @ACTION_PWRACTIVE: The cores that are active -+ */ -+enum kbasep_pm_action { -+ ACTION_PRESENT = 0, -+ ACTION_READY = (SHADER_READY_LO - SHADER_PRESENT_LO), -+ ACTION_PWRON = (SHADER_PWRON_LO - SHADER_PRESENT_LO), -+ ACTION_PWROFF = (SHADER_PWROFF_LO - SHADER_PRESENT_LO), -+ ACTION_PWRTRANS = (SHADER_PWRTRANS_LO - SHADER_PRESENT_LO), -+ ACTION_PWRACTIVE = (SHADER_PWRACTIVE_LO - SHADER_PRESENT_LO) -+}; -+ -+static u64 kbase_pm_get_state( -+ struct kbase_device *kbdev, -+ enum kbase_pm_core_type core_type, -+ enum kbasep_pm_action action); -+ -+/** -+ * core_type_to_reg - Decode a core type and action to a register. -+ * -+ * Given a core type (defined by kbase_pm_core_type) and an action (defined -+ * by kbasep_pm_action) this function will return the register offset that -+ * will perform the action on the core type. The register returned is the _LO -+ * register and an offset must be applied to use the _HI register. -+ * -+ * @core_type: The type of core -+ * @action: The type of action -+ * -+ * Return: The register offset of the _LO register that performs an action of -+ * type @action on a core of type @core_type. -+ */ -+static u32 core_type_to_reg(enum kbase_pm_core_type core_type, -+ enum kbasep_pm_action action) -+{ -+#ifdef CONFIG_MALI_CORESTACK -+ if (core_type == KBASE_PM_CORE_STACK) { -+ switch (action) { -+ case ACTION_PRESENT: -+ return STACK_PRESENT_LO; -+ case ACTION_READY: -+ return STACK_READY_LO; -+ case ACTION_PWRON: -+ return STACK_PWRON_LO; -+ case ACTION_PWROFF: -+ return STACK_PWROFF_LO; -+ case ACTION_PWRTRANS: -+ return STACK_PWRTRANS_LO; -+ default: -+ BUG(); -+ } -+ } -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+ return (u32)core_type + (u32)action; -+} -+ -+#ifdef CONFIG_ARM64 -+static void mali_cci_flush_l2(struct kbase_device *kbdev) -+{ -+ const u32 mask = CLEAN_CACHES_COMPLETED | RESET_COMPLETED; -+ u32 loops = KBASE_CLEAN_CACHE_MAX_LOOPS; -+ u32 raw; -+ -+ /* -+ * Note that we don't take the cache flush mutex here since -+ * we expect to be the last user of the L2, all other L2 users -+ * would have dropped their references, to initiate L2 power -+ * down, L2 power down being the only valid place for this -+ * to be called from. -+ */ -+ -+ kbase_reg_write(kbdev, -+ GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_CLEAN_INV_CACHES, -+ NULL); -+ -+ raw = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), -+ NULL); -+ -+ /* Wait for cache flush to complete before continuing, exit on -+ * gpu resets or loop expiry. */ -+ while (((raw & mask) == 0) && --loops) { -+ raw = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), -+ NULL); -+ } -+} -+#endif -+ -+/** -+ * kbase_pm_invoke - Invokes an action on a core set -+ * -+ * This function performs the action given by @action on a set of cores of a -+ * type given by @core_type. It is a static function used by -+ * kbase_pm_transition_core_type() -+ * -+ * @kbdev: The kbase device structure of the device -+ * @core_type: The type of core that the action should be performed on -+ * @cores: A bit mask of cores to perform the action on (low 32 bits) -+ * @action: The action to perform on the cores -+ */ -+static void kbase_pm_invoke(struct kbase_device *kbdev, -+ enum kbase_pm_core_type core_type, -+ u64 cores, -+ enum kbasep_pm_action action) -+{ -+ u32 reg; -+ u32 lo = cores & 0xFFFFFFFF; -+ u32 hi = (cores >> 32) & 0xFFFFFFFF; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ reg = core_type_to_reg(core_type, action); -+ -+ KBASE_DEBUG_ASSERT(reg); -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ if (cores) { -+ if (action == ACTION_PWRON) -+ kbase_trace_mali_pm_power_on(core_type, cores); -+ else if (action == ACTION_PWROFF) -+ kbase_trace_mali_pm_power_off(core_type, cores); -+ } -+#endif -+ -+ if (cores) { -+ u64 state = kbase_pm_get_state(kbdev, core_type, ACTION_READY); -+ -+ if (action == ACTION_PWRON) -+ state |= cores; -+ else if (action == ACTION_PWROFF) -+ state &= ~cores; -+ KBASE_TLSTREAM_AUX_PM_STATE(core_type, state); -+ } -+ -+ /* Tracing */ -+ if (cores) { -+ if (action == ACTION_PWRON) -+ switch (core_type) { -+ case KBASE_PM_CORE_SHADER: -+ KBASE_TRACE_ADD(kbdev, PM_PWRON, NULL, NULL, 0u, -+ lo); -+ break; -+ case KBASE_PM_CORE_TILER: -+ KBASE_TRACE_ADD(kbdev, PM_PWRON_TILER, NULL, -+ NULL, 0u, lo); -+ break; -+ case KBASE_PM_CORE_L2: -+ KBASE_TRACE_ADD(kbdev, PM_PWRON_L2, NULL, NULL, -+ 0u, lo); -+ break; -+ default: -+ break; -+ } -+ else if (action == ACTION_PWROFF) -+ switch (core_type) { -+ case KBASE_PM_CORE_SHADER: -+ KBASE_TRACE_ADD(kbdev, PM_PWROFF, NULL, NULL, -+ 0u, lo); -+ break; -+ case KBASE_PM_CORE_TILER: -+ KBASE_TRACE_ADD(kbdev, PM_PWROFF_TILER, NULL, -+ NULL, 0u, lo); -+ break; -+ case KBASE_PM_CORE_L2: -+ KBASE_TRACE_ADD(kbdev, PM_PWROFF_L2, NULL, NULL, -+ 0u, lo); -+ /* disable snoops before L2 is turned off */ -+ kbase_pm_cache_snoop_disable(kbdev); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ if (lo != 0) -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(reg), lo, NULL); -+ -+ if (hi != 0) -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(reg + 4), hi, NULL); -+} -+ -+/** -+ * kbase_pm_get_state - Get information about a core set -+ * -+ * This function gets information (chosen by @action) about a set of cores of -+ * a type given by @core_type. It is a static function used by -+ * kbase_pm_get_active_cores(), kbase_pm_get_trans_cores() and -+ * kbase_pm_get_ready_cores(). -+ * -+ * @kbdev: The kbase device structure of the device -+ * @core_type: The type of core that the should be queried -+ * @action: The property of the cores to query -+ * -+ * Return: A bit mask specifying the state of the cores -+ */ -+static u64 kbase_pm_get_state(struct kbase_device *kbdev, -+ enum kbase_pm_core_type core_type, -+ enum kbasep_pm_action action) -+{ -+ u32 reg; -+ u32 lo, hi; -+ -+ reg = core_type_to_reg(core_type, action); -+ -+ KBASE_DEBUG_ASSERT(reg); -+ -+ lo = kbase_reg_read(kbdev, GPU_CONTROL_REG(reg), NULL); -+ hi = kbase_reg_read(kbdev, GPU_CONTROL_REG(reg + 4), NULL); -+ -+ return (((u64) hi) << 32) | ((u64) lo); -+} -+ -+void kbasep_pm_init_core_use_bitmaps(struct kbase_device *kbdev) -+{ -+ kbdev->shader_inuse_bitmap = 0; -+ kbdev->shader_needed_bitmap = 0; -+ kbdev->shader_available_bitmap = 0; -+ kbdev->tiler_available_bitmap = 0; -+ kbdev->l2_users_count = 0; -+ kbdev->l2_available_bitmap = 0; -+ kbdev->tiler_needed_cnt = 0; -+ kbdev->tiler_inuse_cnt = 0; -+ -+ memset(kbdev->shader_needed_cnt, 0, sizeof(kbdev->shader_needed_cnt)); -+} -+ -+/** -+ * kbase_pm_get_present_cores - Get the cores that are present -+ * -+ * @kbdev: Kbase device -+ * @type: The type of cores to query -+ * -+ * Return: Bitmask of the cores that are present -+ */ -+u64 kbase_pm_get_present_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ switch (type) { -+ case KBASE_PM_CORE_L2: -+ return kbdev->gpu_props.props.raw_props.l2_present; -+ case KBASE_PM_CORE_SHADER: -+ return kbdev->gpu_props.props.raw_props.shader_present; -+ case KBASE_PM_CORE_TILER: -+ return kbdev->gpu_props.props.raw_props.tiler_present; -+#ifdef CONFIG_MALI_CORESTACK -+ case KBASE_PM_CORE_STACK: -+ return kbdev->gpu_props.props.raw_props.stack_present; -+#endif /* CONFIG_MALI_CORESTACK */ -+ default: -+ break; -+ } -+ KBASE_DEBUG_ASSERT(0); -+ -+ return 0; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_get_present_cores); -+ -+/** -+ * kbase_pm_get_active_cores - Get the cores that are "active" -+ * (busy processing work) -+ * -+ * @kbdev: Kbase device -+ * @type: The type of cores to query -+ * -+ * Return: Bitmask of cores that are active -+ */ -+u64 kbase_pm_get_active_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type) -+{ -+ return kbase_pm_get_state(kbdev, type, ACTION_PWRACTIVE); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_get_active_cores); -+ -+/** -+ * kbase_pm_get_trans_cores - Get the cores that are transitioning between -+ * power states -+ * -+ * @kbdev: Kbase device -+ * @type: The type of cores to query -+ * -+ * Return: Bitmask of cores that are transitioning -+ */ -+u64 kbase_pm_get_trans_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type) -+{ -+ return kbase_pm_get_state(kbdev, type, ACTION_PWRTRANS); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_get_trans_cores); -+ -+/** -+ * kbase_pm_get_ready_cores - Get the cores that are powered on -+ * -+ * @kbdev: Kbase device -+ * @type: The type of cores to query -+ * -+ * Return: Bitmask of cores that are ready (powered on) -+ */ -+u64 kbase_pm_get_ready_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type) -+{ -+ u64 result; -+ -+ result = kbase_pm_get_state(kbdev, type, ACTION_READY); -+ -+ switch (type) { -+ case KBASE_PM_CORE_SHADER: -+ KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED, NULL, NULL, 0u, -+ (u32) result); -+ break; -+ case KBASE_PM_CORE_TILER: -+ KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED_TILER, NULL, NULL, 0u, -+ (u32) result); -+ break; -+ case KBASE_PM_CORE_L2: -+ KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED_L2, NULL, NULL, 0u, -+ (u32) result); -+ break; -+ default: -+ break; -+ } -+ -+ return result; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_get_ready_cores); -+ -+/** -+ * kbase_pm_transition_core_type - Perform power transitions for a particular -+ * core type. -+ * -+ * This function will perform any available power transitions to make the actual -+ * hardware state closer to the desired state. If a core is currently -+ * transitioning then changes to the power state of that call cannot be made -+ * until the transition has finished. Cores which are not present in the -+ * hardware are ignored if they are specified in the desired_state bitmask, -+ * however the return value will always be 0 in this case. -+ * -+ * @kbdev: The kbase device -+ * @type: The core type to perform transitions for -+ * @desired_state: A bit mask of the desired state of the cores -+ * @in_use: A bit mask of the cores that are currently running -+ * jobs. These cores have to be kept powered up because -+ * there are jobs running (or about to run) on them. -+ * @available: Receives a bit mask of the cores that the job -+ * scheduler can use to submit jobs to. May be NULL if -+ * this is not needed. -+ * @powering_on: Bit mask to update with cores that are -+ * transitioning to a power-on state. -+ * -+ * Return: true if the desired state has been reached, false otherwise -+ */ -+static bool kbase_pm_transition_core_type(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type, -+ u64 desired_state, -+ u64 in_use, -+ u64 * const available, -+ u64 *powering_on) -+{ -+ u64 present; -+ u64 ready; -+ u64 trans; -+ u64 powerup; -+ u64 powerdown; -+ u64 powering_on_trans; -+ u64 desired_state_in_use; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ /* Get current state */ -+ present = kbase_pm_get_present_cores(kbdev, type); -+ trans = kbase_pm_get_trans_cores(kbdev, type); -+ ready = kbase_pm_get_ready_cores(kbdev, type); -+ /* mask off ready from trans in case transitions finished between the -+ * register reads */ -+ trans &= ~ready; -+ -+ if (trans) /* Do not progress if any cores are transitioning */ -+ return false; -+ -+ powering_on_trans = trans & *powering_on; -+ *powering_on = powering_on_trans; -+ -+ if (available != NULL) -+ *available = (ready | powering_on_trans) & desired_state; -+ -+ /* Update desired state to include the in-use cores. These have to be -+ * kept powered up because there are jobs running or about to run on -+ * these cores -+ */ -+ desired_state_in_use = desired_state | in_use; -+ -+ /* Update state of whether l2 caches are powered */ -+ if (type == KBASE_PM_CORE_L2) { -+ if ((ready == present) && (desired_state_in_use == ready) && -+ (trans == 0)) { -+ /* All are ready, none will be turned off, and none are -+ * transitioning */ -+ kbdev->pm.backend.l2_powered = 1; -+ /* -+ * Ensure snoops are enabled after L2 is powered up, -+ * note that kbase keeps track of the snoop state, so -+ * safe to repeatedly call. -+ */ -+ kbase_pm_cache_snoop_enable(kbdev); -+ if (kbdev->l2_users_count > 0) { -+ /* Notify any registered l2 cache users -+ * (optimized out when no users waiting) */ -+ wake_up(&kbdev->pm.backend.l2_powered_wait); -+ } -+ } else -+ kbdev->pm.backend.l2_powered = 0; -+ } -+ -+ if (desired_state == ready && (trans == 0)) -+ return true; -+ -+ /* Restrict the cores to those that are actually present */ -+ powerup = desired_state_in_use & present; -+ powerdown = (~desired_state_in_use) & present; -+ -+ /* Restrict to cores that are not already in the desired state */ -+ powerup &= ~ready; -+ powerdown &= ready; -+ -+ /* Don't transition any cores that are already transitioning, except for -+ * Mali cores that support the following case: -+ * -+ * If the SHADER_PWRON or TILER_PWRON registers are written to turn on -+ * a core that is currently transitioning to power off, then this is -+ * remembered and the shader core is automatically powered up again once -+ * the original transition completes. Once the automatic power on is -+ * complete any job scheduled on the shader core should start. -+ */ -+ powerdown &= ~trans; -+ -+ if (kbase_hw_has_feature(kbdev, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS)) -+ if (KBASE_PM_CORE_SHADER == type || KBASE_PM_CORE_TILER == type) -+ trans = powering_on_trans; /* for exception cases, only -+ * mask off cores in power on -+ * transitions */ -+ -+ powerup &= ~trans; -+ -+ /* Perform transitions if any */ -+ kbase_pm_invoke(kbdev, type, powerup, ACTION_PWRON); -+#if !PLATFORM_POWER_DOWN_ONLY -+ kbase_pm_invoke(kbdev, type, powerdown, ACTION_PWROFF); -+#endif -+ -+ /* Recalculate cores transitioning on, and re-evaluate our state */ -+ powering_on_trans |= powerup; -+ *powering_on = powering_on_trans; -+ if (available != NULL) -+ *available = (ready | powering_on_trans) & desired_state; -+ -+ return false; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_transition_core_type); -+ -+/** -+ * get_desired_cache_status - Determine which caches should be on for a -+ * particular core state -+ * -+ * This function takes a bit mask of the present caches and the cores (or -+ * caches) that are attached to the caches that will be powered. It then -+ * computes which caches should be turned on to allow the cores requested to be -+ * powered up. -+ * -+ * @present: The bit mask of present caches -+ * @cores_powered: A bit mask of cores (or L2 caches) that are desired to -+ * be powered -+ * @tilers_powered: The bit mask of tilers that are desired to be powered -+ * -+ * Return: A bit mask of the caches that should be turned on -+ */ -+static u64 get_desired_cache_status(u64 present, u64 cores_powered, -+ u64 tilers_powered) -+{ -+ u64 desired = 0; -+ -+ while (present) { -+ /* Find out which is the highest set bit */ -+ u64 bit = fls64(present) - 1; -+ u64 bit_mask = 1ull << bit; -+ /* Create a mask which has all bits from 'bit' upwards set */ -+ -+ u64 mask = ~(bit_mask - 1); -+ -+ /* If there are any cores powered at this bit or above (that -+ * haven't previously been processed) then we need this core on -+ */ -+ if (cores_powered & mask) -+ desired |= bit_mask; -+ -+ /* Remove bits from cores_powered and present */ -+ cores_powered &= ~mask; -+ present &= ~bit_mask; -+ } -+ -+ /* Power up the required L2(s) for the tiler */ -+ if (tilers_powered) -+ desired |= 1; -+ -+ return desired; -+} -+ -+KBASE_EXPORT_TEST_API(get_desired_cache_status); -+ -+#ifdef CONFIG_MALI_CORESTACK -+u64 kbase_pm_core_stack_mask(u64 cores) -+{ -+ u64 stack_mask = 0; -+ size_t const MAX_CORE_ID = 31; -+ size_t const NUM_CORES_PER_STACK = 4; -+ size_t i; -+ -+ for (i = 0; i <= MAX_CORE_ID; ++i) { -+ if (test_bit(i, (unsigned long *)&cores)) { -+ /* Every core which ID >= 16 is filled to stacks 4-7 -+ * instead of 0-3 */ -+ size_t const stack_num = (i > 16) ? -+ (i % NUM_CORES_PER_STACK) + 4 : -+ (i % NUM_CORES_PER_STACK); -+ set_bit(stack_num, (unsigned long *)&stack_mask); -+ } -+ } -+ -+ return stack_mask; -+} -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+bool -+MOCKABLE(kbase_pm_check_transitions_nolock) (struct kbase_device *kbdev) -+{ -+ bool cores_are_available = false; -+ bool in_desired_state = true; -+ u64 desired_l2_state; -+#ifdef CONFIG_MALI_CORESTACK -+ u64 desired_stack_state; -+ u64 stacks_powered; -+#endif /* CONFIG_MALI_CORESTACK */ -+ u64 cores_powered; -+ u64 tilers_powered; -+ u64 tiler_available_bitmap; -+ u64 tiler_transitioning_bitmap; -+ u64 shader_available_bitmap; -+ u64 shader_ready_bitmap; -+ u64 shader_transitioning_bitmap; -+ u64 l2_available_bitmap; -+ u64 prev_l2_available_bitmap; -+ u64 l2_inuse_bitmap; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ spin_lock(&kbdev->pm.backend.gpu_powered_lock); -+ if (kbdev->pm.backend.gpu_powered == false) { -+ spin_unlock(&kbdev->pm.backend.gpu_powered_lock); -+ if (kbdev->pm.backend.desired_shader_state == 0 && -+ kbdev->pm.backend.desired_tiler_state == 0) -+ return true; -+ return false; -+ } -+ -+ /* Trace that a change-state is being requested, and that it took -+ * (effectively) no time to start it. This is useful for counting how -+ * many state changes occurred, in a way that's backwards-compatible -+ * with processing the trace data */ -+ kbase_timeline_pm_send_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_CHANGE_GPU_STATE); -+ kbase_timeline_pm_handle_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_CHANGE_GPU_STATE); -+ -+ /* If any cores are already powered then, we must keep the caches on */ -+ shader_transitioning_bitmap = kbase_pm_get_trans_cores(kbdev, -+ KBASE_PM_CORE_SHADER); -+ cores_powered = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_SHADER); -+ cores_powered |= kbdev->pm.backend.desired_shader_state; -+ -+#ifdef CONFIG_MALI_CORESTACK -+ /* Work out which core stacks want to be powered */ -+ desired_stack_state = kbase_pm_core_stack_mask(cores_powered); -+ stacks_powered = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_STACK) | -+ desired_stack_state; -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+ /* Work out which tilers want to be powered */ -+ tiler_transitioning_bitmap = kbase_pm_get_trans_cores(kbdev, -+ KBASE_PM_CORE_TILER); -+ tilers_powered = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_TILER); -+ tilers_powered |= kbdev->pm.backend.desired_tiler_state; -+ -+ /* If there are l2 cache users registered, keep all l2s powered even if -+ * all other cores are off. */ -+ if (kbdev->l2_users_count > 0) -+ cores_powered |= kbdev->gpu_props.props.raw_props.l2_present; -+ -+ desired_l2_state = get_desired_cache_status( -+ kbdev->gpu_props.props.raw_props.l2_present, -+ cores_powered, tilers_powered); -+ -+ l2_inuse_bitmap = get_desired_cache_status( -+ kbdev->gpu_props.props.raw_props.l2_present, -+ cores_powered | shader_transitioning_bitmap, -+ tilers_powered | tiler_transitioning_bitmap); -+ -+#ifdef CONFIG_MALI_CORESTACK -+ if (stacks_powered) -+ desired_l2_state |= 1; -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+ /* If any l2 cache is on, then enable l2 #0, for use by job manager */ -+ if (0 != desired_l2_state) -+ desired_l2_state |= 1; -+ -+ prev_l2_available_bitmap = kbdev->l2_available_bitmap; -+ in_desired_state &= kbase_pm_transition_core_type(kbdev, -+ KBASE_PM_CORE_L2, desired_l2_state, l2_inuse_bitmap, -+ &l2_available_bitmap, -+ &kbdev->pm.backend.powering_on_l2_state); -+ -+ if (kbdev->l2_available_bitmap != l2_available_bitmap) -+ KBASE_TIMELINE_POWER_L2(kbdev, l2_available_bitmap); -+ -+ kbdev->l2_available_bitmap = l2_available_bitmap; -+ -+ -+#ifdef CONFIG_MALI_CORESTACK -+ if (in_desired_state) { -+ in_desired_state &= kbase_pm_transition_core_type(kbdev, -+ KBASE_PM_CORE_STACK, desired_stack_state, 0, -+ &kbdev->stack_available_bitmap, -+ &kbdev->pm.backend.powering_on_stack_state); -+ } -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+ if (in_desired_state) { -+ in_desired_state &= kbase_pm_transition_core_type(kbdev, -+ KBASE_PM_CORE_TILER, -+ kbdev->pm.backend.desired_tiler_state, -+ 0, &tiler_available_bitmap, -+ &kbdev->pm.backend.powering_on_tiler_state); -+ in_desired_state &= kbase_pm_transition_core_type(kbdev, -+ KBASE_PM_CORE_SHADER, -+ kbdev->pm.backend.desired_shader_state, -+ kbdev->shader_inuse_bitmap, -+ &shader_available_bitmap, -+ &kbdev->pm.backend.powering_on_shader_state); -+ -+ if (kbdev->shader_available_bitmap != shader_available_bitmap) { -+ KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL, -+ NULL, 0u, -+ (u32) shader_available_bitmap); -+ KBASE_TIMELINE_POWER_SHADER(kbdev, -+ shader_available_bitmap); -+ } -+ -+ kbdev->shader_available_bitmap = shader_available_bitmap; -+ -+ if (kbdev->tiler_available_bitmap != tiler_available_bitmap) { -+ KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER, -+ NULL, NULL, 0u, -+ (u32) tiler_available_bitmap); -+ KBASE_TIMELINE_POWER_TILER(kbdev, -+ tiler_available_bitmap); -+ } -+ -+ kbdev->tiler_available_bitmap = tiler_available_bitmap; -+ -+ } else if ((l2_available_bitmap & -+ kbdev->gpu_props.props.raw_props.tiler_present) != -+ kbdev->gpu_props.props.raw_props.tiler_present) { -+ tiler_available_bitmap = 0; -+ -+ if (kbdev->tiler_available_bitmap != tiler_available_bitmap) -+ KBASE_TIMELINE_POWER_TILER(kbdev, -+ tiler_available_bitmap); -+ -+ kbdev->tiler_available_bitmap = tiler_available_bitmap; -+ } -+ -+ /* State updated for slow-path waiters */ -+ kbdev->pm.backend.gpu_in_desired_state = in_desired_state; -+ -+ shader_ready_bitmap = kbase_pm_get_ready_cores(kbdev, -+ KBASE_PM_CORE_SHADER); -+ shader_transitioning_bitmap = kbase_pm_get_trans_cores(kbdev, -+ KBASE_PM_CORE_SHADER); -+ -+ /* Determine whether the cores are now available (even if the set of -+ * available cores is empty). Note that they can be available even if -+ * we've not finished transitioning to the desired state */ -+ if ((kbdev->shader_available_bitmap & -+ kbdev->pm.backend.desired_shader_state) -+ == kbdev->pm.backend.desired_shader_state && -+ (kbdev->tiler_available_bitmap & -+ kbdev->pm.backend.desired_tiler_state) -+ == kbdev->pm.backend.desired_tiler_state) { -+ cores_are_available = true; -+ -+ KBASE_TRACE_ADD(kbdev, PM_CORES_AVAILABLE, NULL, NULL, 0u, -+ (u32)(kbdev->shader_available_bitmap & -+ kbdev->pm.backend.desired_shader_state)); -+ KBASE_TRACE_ADD(kbdev, PM_CORES_AVAILABLE_TILER, NULL, NULL, 0u, -+ (u32)(kbdev->tiler_available_bitmap & -+ kbdev->pm.backend.desired_tiler_state)); -+ -+ /* Log timelining information about handling events that power -+ * up cores, to match up either with immediate submission either -+ * because cores already available, or from PM IRQ */ -+ if (!in_desired_state) -+ kbase_timeline_pm_send_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED); -+ } -+ -+ if (in_desired_state) { -+ KBASE_DEBUG_ASSERT(cores_are_available); -+ -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_pm_status(KBASE_PM_CORE_L2, -+ kbase_pm_get_ready_cores(kbdev, -+ KBASE_PM_CORE_L2)); -+ kbase_trace_mali_pm_status(KBASE_PM_CORE_SHADER, -+ kbase_pm_get_ready_cores(kbdev, -+ KBASE_PM_CORE_SHADER)); -+ kbase_trace_mali_pm_status(KBASE_PM_CORE_TILER, -+ kbase_pm_get_ready_cores(kbdev, -+ KBASE_PM_CORE_TILER)); -+#ifdef CONFIG_MALI_CORESTACK -+ kbase_trace_mali_pm_status(KBASE_PM_CORE_STACK, -+ kbase_pm_get_ready_cores(kbdev, -+ KBASE_PM_CORE_STACK)); -+#endif /* CONFIG_MALI_CORESTACK */ -+#endif -+ -+ KBASE_TLSTREAM_AUX_PM_STATE( -+ KBASE_PM_CORE_L2, -+ kbase_pm_get_ready_cores( -+ kbdev, KBASE_PM_CORE_L2)); -+ KBASE_TLSTREAM_AUX_PM_STATE( -+ KBASE_PM_CORE_SHADER, -+ kbase_pm_get_ready_cores( -+ kbdev, KBASE_PM_CORE_SHADER)); -+ KBASE_TLSTREAM_AUX_PM_STATE( -+ KBASE_PM_CORE_TILER, -+ kbase_pm_get_ready_cores( -+ kbdev, -+ KBASE_PM_CORE_TILER)); -+#ifdef CONFIG_MALI_CORESTACK -+ KBASE_TLSTREAM_AUX_PM_STATE( -+ KBASE_PM_CORE_STACK, -+ kbase_pm_get_ready_cores( -+ kbdev, -+ KBASE_PM_CORE_STACK)); -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+ KBASE_TRACE_ADD(kbdev, PM_DESIRED_REACHED, NULL, NULL, -+ kbdev->pm.backend.gpu_in_desired_state, -+ (u32)kbdev->pm.backend.desired_shader_state); -+ KBASE_TRACE_ADD(kbdev, PM_DESIRED_REACHED_TILER, NULL, NULL, 0u, -+ (u32)kbdev->pm.backend.desired_tiler_state); -+ -+ /* Log timelining information for synchronous waiters */ -+ kbase_timeline_pm_send_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED); -+ /* Wake slow-path waiters. Job scheduler does not use this. */ -+ KBASE_TRACE_ADD(kbdev, PM_WAKE_WAITERS, NULL, NULL, 0u, 0); -+ -+ wake_up(&kbdev->pm.backend.gpu_in_desired_state_wait); -+ } -+ -+ spin_unlock(&kbdev->pm.backend.gpu_powered_lock); -+ -+ /* kbase_pm_ca_update_core_status can cause one-level recursion into -+ * this function, so it must only be called once all changes to kbdev -+ * have been committed, and after the gpu_powered_lock has been -+ * dropped. */ -+ if (kbdev->shader_ready_bitmap != shader_ready_bitmap || -+ kbdev->shader_transitioning_bitmap != shader_transitioning_bitmap) { -+ kbdev->shader_ready_bitmap = shader_ready_bitmap; -+ kbdev->shader_transitioning_bitmap = -+ shader_transitioning_bitmap; -+ -+ kbase_pm_ca_update_core_status(kbdev, shader_ready_bitmap, -+ shader_transitioning_bitmap); -+ } -+ -+ /* The core availability policy is not allowed to keep core group 0 -+ * turned off (unless it was changing the l2 power state) */ -+ if (!((shader_ready_bitmap | shader_transitioning_bitmap) & -+ kbdev->gpu_props.props.coherency_info.group[0].core_mask) && -+ (prev_l2_available_bitmap == desired_l2_state) && -+ !(kbase_pm_ca_get_core_mask(kbdev) & -+ kbdev->gpu_props.props.coherency_info.group[0].core_mask)) -+ BUG(); -+ -+ /* The core availability policy is allowed to keep core group 1 off, -+ * but all jobs specifically targeting CG1 must fail */ -+ if (!((shader_ready_bitmap | shader_transitioning_bitmap) & -+ kbdev->gpu_props.props.coherency_info.group[1].core_mask) && -+ !(kbase_pm_ca_get_core_mask(kbdev) & -+ kbdev->gpu_props.props.coherency_info.group[1].core_mask)) -+ kbdev->pm.backend.cg1_disabled = true; -+ else -+ kbdev->pm.backend.cg1_disabled = false; -+ -+ return cores_are_available; -+} -+KBASE_EXPORT_TEST_API(kbase_pm_check_transitions_nolock); -+ -+/* Timeout for kbase_pm_check_transitions_sync when wait_event_killable has -+ * aborted due to a fatal signal. If the time spent waiting has exceeded this -+ * threshold then there is most likely a hardware issue. */ -+#define PM_TIMEOUT (5*HZ) /* 5s */ -+ -+void kbase_pm_check_transitions_sync(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ unsigned long timeout; -+ bool cores_are_available; -+ int ret; -+ -+ /* Force the transition to be checked and reported - the cores may be -+ * 'available' (for job submission) but not fully powered up. */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ cores_are_available = kbase_pm_check_transitions_nolock(kbdev); -+ -+ /* Don't need 'cores_are_available', because we don't return anything */ -+ CSTD_UNUSED(cores_are_available); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ timeout = jiffies + PM_TIMEOUT; -+ -+ /* Wait for cores */ -+ ret = wait_event_killable(kbdev->pm.backend.gpu_in_desired_state_wait, -+ kbdev->pm.backend.gpu_in_desired_state); -+ -+ if (ret < 0 && time_after(jiffies, timeout)) { -+ dev_err(kbdev->dev, "Power transition timed out unexpectedly\n"); -+ dev_err(kbdev->dev, "Desired state :\n"); -+ dev_err(kbdev->dev, "\tShader=%016llx\n", -+ kbdev->pm.backend.desired_shader_state); -+ dev_err(kbdev->dev, "\tTiler =%016llx\n", -+ kbdev->pm.backend.desired_tiler_state); -+ dev_err(kbdev->dev, "Current state :\n"); -+ dev_err(kbdev->dev, "\tShader=%08x%08x\n", -+ kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(SHADER_READY_HI), NULL), -+ kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(SHADER_READY_LO), -+ NULL)); -+ dev_err(kbdev->dev, "\tTiler =%08x%08x\n", -+ kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TILER_READY_HI), NULL), -+ kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TILER_READY_LO), NULL)); -+ dev_err(kbdev->dev, "\tL2 =%08x%08x\n", -+ kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(L2_READY_HI), NULL), -+ kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(L2_READY_LO), NULL)); -+ dev_err(kbdev->dev, "Cores transitioning :\n"); -+ dev_err(kbdev->dev, "\tShader=%08x%08x\n", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG( -+ SHADER_PWRTRANS_HI), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG( -+ SHADER_PWRTRANS_LO), NULL)); -+ dev_err(kbdev->dev, "\tTiler =%08x%08x\n", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG( -+ TILER_PWRTRANS_HI), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG( -+ TILER_PWRTRANS_LO), NULL)); -+ dev_err(kbdev->dev, "\tL2 =%08x%08x\n", -+ kbase_reg_read(kbdev, GPU_CONTROL_REG( -+ L2_PWRTRANS_HI), NULL), -+ kbase_reg_read(kbdev, GPU_CONTROL_REG( -+ L2_PWRTRANS_LO), NULL)); -+#if KBASE_GPU_RESET_EN -+ dev_err(kbdev->dev, "Sending reset to GPU - all running jobs will be lost\n"); -+ if (kbase_prepare_to_reset_gpu(kbdev)) -+ kbase_reset_gpu(kbdev); -+#endif /* KBASE_GPU_RESET_EN */ -+ } else { -+ /* Log timelining information that a change in state has -+ * completed */ -+ kbase_timeline_pm_handle_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED); -+ } -+} -+KBASE_EXPORT_TEST_API(kbase_pm_check_transitions_sync); -+ -+void kbase_pm_enable_interrupts(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ /* -+ * Clear all interrupts, -+ * and unmask them all. -+ */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), GPU_IRQ_REG_ALL, -+ NULL); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), GPU_IRQ_REG_ALL, -+ NULL); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), 0xFFFFFFFF, -+ NULL); -+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), 0xFFFFFFFF, NULL); -+ -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), 0xFFFFFFFF, NULL); -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0xFFFFFFFF, NULL); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_enable_interrupts); -+ -+void kbase_pm_disable_interrupts_nolock(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ /* -+ * Mask all interrupts, -+ * and clear them all. -+ */ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), 0, NULL); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), GPU_IRQ_REG_ALL, -+ NULL); -+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), 0, NULL); -+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), 0xFFFFFFFF, -+ NULL); -+ -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0, NULL); -+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), 0xFFFFFFFF, NULL); -+} -+ -+void kbase_pm_disable_interrupts(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_pm_disable_interrupts_nolock(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_disable_interrupts); -+ -+ -+/* -+ * pmu layout: -+ * 0x0000: PMU TAG (RO) (0xCAFECAFE) -+ * 0x0004: PMU VERSION ID (RO) (0x00000000) -+ * 0x0008: CLOCK ENABLE (RW) (31:1 SBZ, 0 CLOCK STATE) -+ */ -+void kbase_pm_clock_on(struct kbase_device *kbdev, bool is_resume) -+{ -+ bool reset_required = is_resume; -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ lockdep_assert_held(&js_devdata->runpool_mutex); -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ if (kbdev->pm.backend.gpu_powered) { -+ /* Already turned on */ -+ if (kbdev->poweroff_pending) -+ kbase_pm_enable_interrupts(kbdev); -+ kbdev->poweroff_pending = false; -+ KBASE_DEBUG_ASSERT(!is_resume); -+ return; -+ } -+ -+ kbdev->poweroff_pending = false; -+ -+ KBASE_TRACE_ADD(kbdev, PM_GPU_ON, NULL, NULL, 0u, 0u); -+ -+ if (is_resume && kbdev->pm.backend.callback_power_resume) { -+ kbdev->pm.backend.callback_power_resume(kbdev); -+ return; -+ } else if (kbdev->pm.backend.callback_power_on) { -+ kbdev->pm.backend.callback_power_on(kbdev); -+ /* If your platform properly keeps the GPU state you may use the -+ * return value of the callback_power_on function to -+ * conditionally reset the GPU on power up. Currently we are -+ * conservative and always reset the GPU. */ -+ reset_required = true; -+ } -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags); -+ kbdev->pm.backend.gpu_powered = true; -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (reset_required) { -+ /* GPU state was lost, reset GPU to ensure it is in a -+ * consistent state */ -+ kbase_pm_init_hw(kbdev, PM_ENABLE_IRQS); -+ } -+ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_ctx_sched_restore_all_as(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ /* Lastly, enable the interrupts */ -+ kbase_pm_enable_interrupts(kbdev); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_clock_on); -+ -+bool kbase_pm_clock_off(struct kbase_device *kbdev, bool is_suspend) -+{ -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ /* ASSERT that the cores should now be unavailable. No lock needed. */ -+ KBASE_DEBUG_ASSERT(kbdev->shader_available_bitmap == 0u); -+ -+ kbdev->poweroff_pending = true; -+ -+ if (!kbdev->pm.backend.gpu_powered) { -+ /* Already turned off */ -+ if (is_suspend && kbdev->pm.backend.callback_power_suspend) -+ kbdev->pm.backend.callback_power_suspend(kbdev); -+ return true; -+ } -+ -+ KBASE_TRACE_ADD(kbdev, PM_GPU_OFF, NULL, NULL, 0u, 0u); -+ -+ /* Disable interrupts. This also clears any outstanding interrupts */ -+ kbase_pm_disable_interrupts(kbdev); -+ /* Ensure that any IRQ handlers have finished */ -+ kbase_synchronize_irqs(kbdev); -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (atomic_read(&kbdev->faults_pending)) { -+ /* Page/bus faults are still being processed. The GPU can not -+ * be powered off until they have completed */ -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, -+ flags); -+ return false; -+ } -+ -+ kbase_pm_cache_snoop_disable(kbdev); -+ -+ /* The GPU power may be turned off from this point */ -+ kbdev->pm.backend.gpu_powered = false; -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags); -+ -+ if (is_suspend && kbdev->pm.backend.callback_power_suspend) -+ kbdev->pm.backend.callback_power_suspend(kbdev); -+ else if (kbdev->pm.backend.callback_power_off) -+ kbdev->pm.backend.callback_power_off(kbdev); -+ return true; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_clock_off); -+ -+struct kbasep_reset_timeout_data { -+ struct hrtimer timer; -+ bool timed_out; -+ struct kbase_device *kbdev; -+}; -+ -+void kbase_pm_reset_done(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ kbdev->pm.backend.reset_done = true; -+ wake_up(&kbdev->pm.backend.reset_done_wait); -+} -+ -+/** -+ * kbase_pm_wait_for_reset - Wait for a reset to happen -+ * -+ * Wait for the %RESET_COMPLETED IRQ to occur, then reset the waiting state. -+ * -+ * @kbdev: Kbase device -+ */ -+static void kbase_pm_wait_for_reset(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ wait_event(kbdev->pm.backend.reset_done_wait, -+ (kbdev->pm.backend.reset_done)); -+ kbdev->pm.backend.reset_done = false; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_reset_done); -+ -+static enum hrtimer_restart kbasep_reset_timeout(struct hrtimer *timer) -+{ -+ struct kbasep_reset_timeout_data *rtdata = -+ container_of(timer, struct kbasep_reset_timeout_data, timer); -+ -+ rtdata->timed_out = 1; -+ -+ /* Set the wait queue to wake up kbase_pm_init_hw even though the reset -+ * hasn't completed */ -+ kbase_pm_reset_done(rtdata->kbdev); -+ -+ return HRTIMER_NORESTART; -+} -+ -+static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev) -+{ -+ struct device_node *np = kbdev->dev->of_node; -+ u32 jm_values[4]; -+ const u32 gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ const u32 prod_id = (gpu_id & GPU_ID_VERSION_PRODUCT_ID) >> -+ GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ const u32 major = (gpu_id & GPU_ID_VERSION_MAJOR) >> -+ GPU_ID_VERSION_MAJOR_SHIFT; -+ -+ kbdev->hw_quirks_sc = 0; -+ -+ /* Needed due to MIDBASE-1494: LS_PAUSEBUFFER_DISABLE. See PRLAM-8443. -+ * and needed due to MIDGLES-3539. See PRLAM-11035 */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8443) || -+ kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_11035)) -+ kbdev->hw_quirks_sc |= SC_LS_PAUSEBUFFER_DISABLE; -+ -+ /* Needed due to MIDBASE-2054: SDC_DISABLE_OQ_DISCARD. See PRLAM-10327. -+ */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10327)) -+ kbdev->hw_quirks_sc |= SC_SDC_DISABLE_OQ_DISCARD; -+ -+#ifdef CONFIG_MALI_PRFCNT_SET_SECONDARY -+ /* Enable alternative hardware counter selection if configured. */ -+ if (!GPU_ID_IS_NEW_FORMAT(prod_id)) -+ kbdev->hw_quirks_sc |= SC_ALT_COUNTERS; -+#endif -+ -+ /* Needed due to MIDBASE-2795. ENABLE_TEXGRD_FLAGS. See PRLAM-10797. */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10797)) -+ kbdev->hw_quirks_sc |= SC_ENABLE_TEXGRD_FLAGS; -+ -+ if (!kbase_hw_has_issue(kbdev, GPUCORE_1619)) { -+ if (prod_id < 0x750 || prod_id == 0x6956) /* T60x, T62x, T72x */ -+ kbdev->hw_quirks_sc |= SC_LS_ATTR_CHECK_DISABLE; -+ else if (prod_id >= 0x750 && prod_id <= 0x880) /* T76x, T8xx */ -+ kbdev->hw_quirks_sc |= SC_LS_ALLOW_ATTR_TYPES; -+ } -+ -+ if (!kbdev->hw_quirks_sc) -+ kbdev->hw_quirks_sc = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(SHADER_CONFIG), NULL); -+ -+ kbdev->hw_quirks_tiler = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TILER_CONFIG), NULL); -+ -+ /* Set tiler clock gate override if required */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_T76X_3953)) -+ kbdev->hw_quirks_tiler |= TC_CLOCK_GATE_OVERRIDE; -+ -+ /* Limit the GPU bus bandwidth if the platform needs this. */ -+ kbdev->hw_quirks_mmu = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(L2_MMU_CONFIG), NULL); -+ -+ /* Limit read ID width for AXI */ -+ kbdev->hw_quirks_mmu &= ~(L2_MMU_CONFIG_LIMIT_EXTERNAL_READS); -+ kbdev->hw_quirks_mmu |= (DEFAULT_ARID_LIMIT & 0x3) << -+ L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT; -+ -+ /* Limit write ID width for AXI */ -+ kbdev->hw_quirks_mmu &= ~(L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES); -+ kbdev->hw_quirks_mmu |= (DEFAULT_AWID_LIMIT & 0x3) << -+ L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT; -+ -+ if (kbdev->system_coherency == COHERENCY_ACE) { -+ /* Allow memory configuration disparity to be ignored, we -+ * optimize the use of shared memory and thus we expect -+ * some disparity in the memory configuration */ -+ kbdev->hw_quirks_mmu |= L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY; -+ } -+ -+ kbdev->hw_quirks_jm = 0; -+ /* Only for T86x/T88x-based products after r2p0 */ -+ if (prod_id >= 0x860 && prod_id <= 0x880 && major >= 2) { -+ -+ if (of_property_read_u32_array(np, -+ "jm_config", -+ &jm_values[0], -+ ARRAY_SIZE(jm_values))) { -+ /* Entry not in device tree, use defaults */ -+ jm_values[0] = 0; -+ jm_values[1] = 0; -+ jm_values[2] = 0; -+ jm_values[3] = JM_MAX_JOB_THROTTLE_LIMIT; -+ } -+ -+ /* Limit throttle limit to 6 bits*/ -+ if (jm_values[3] > JM_MAX_JOB_THROTTLE_LIMIT) { -+ dev_dbg(kbdev->dev, "JOB_THROTTLE_LIMIT supplied in device tree is too large. Limiting to MAX (63)."); -+ jm_values[3] = JM_MAX_JOB_THROTTLE_LIMIT; -+ } -+ -+ /* Aggregate to one integer. */ -+ kbdev->hw_quirks_jm |= (jm_values[0] ? -+ JM_TIMESTAMP_OVERRIDE : 0); -+ kbdev->hw_quirks_jm |= (jm_values[1] ? -+ JM_CLOCK_GATE_OVERRIDE : 0); -+ kbdev->hw_quirks_jm |= (jm_values[2] ? -+ JM_JOB_THROTTLE_ENABLE : 0); -+ kbdev->hw_quirks_jm |= (jm_values[3] << -+ JM_JOB_THROTTLE_LIMIT_SHIFT); -+ -+ } else if (GPU_ID_IS_NEW_FORMAT(prod_id) && -+ (GPU_ID2_MODEL_MATCH_VALUE(prod_id) == -+ GPU_ID2_PRODUCT_TMIX)) { -+ /* Only for tMIx */ -+ u32 coherency_features; -+ -+ coherency_features = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(COHERENCY_FEATURES), NULL); -+ -+ /* (COHERENCY_ACE_LITE | COHERENCY_ACE) was incorrectly -+ * documented for tMIx so force correct value here. -+ */ -+ if (coherency_features == -+ COHERENCY_FEATURE_BIT(COHERENCY_ACE)) { -+ kbdev->hw_quirks_jm |= -+ (COHERENCY_ACE_LITE | COHERENCY_ACE) << -+ JM_FORCE_COHERENCY_FEATURES_SHIFT; -+ } -+ } -+ -+ if (!kbdev->hw_quirks_jm) -+ kbdev->hw_quirks_jm = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(JM_CONFIG), NULL); -+ -+#ifdef CONFIG_MALI_CORESTACK -+#define MANUAL_POWER_CONTROL ((u32)(1 << 8)) -+ kbdev->hw_quirks_jm |= MANUAL_POWER_CONTROL; -+#endif /* CONFIG_MALI_CORESTACK */ -+} -+ -+static void kbase_pm_hw_issues_apply(struct kbase_device *kbdev) -+{ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(SHADER_CONFIG), -+ kbdev->hw_quirks_sc, NULL); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(TILER_CONFIG), -+ kbdev->hw_quirks_tiler, NULL); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(L2_MMU_CONFIG), -+ kbdev->hw_quirks_mmu, NULL); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(JM_CONFIG), -+ kbdev->hw_quirks_jm, NULL); -+ -+} -+ -+void kbase_pm_cache_snoop_enable(struct kbase_device *kbdev) -+{ -+ if ((kbdev->current_gpu_coherency_mode == COHERENCY_ACE) && -+ !kbdev->cci_snoop_enabled) { -+#ifdef CONFIG_ARM64 -+ if (kbdev->snoop_enable_smc != 0) -+ kbase_invoke_smc_fid(kbdev->snoop_enable_smc, 0, 0, 0); -+#endif /* CONFIG_ARM64 */ -+ dev_dbg(kbdev->dev, "MALI - CCI Snoops - Enabled\n"); -+ kbdev->cci_snoop_enabled = true; -+ } -+} -+ -+void kbase_pm_cache_snoop_disable(struct kbase_device *kbdev) -+{ -+ if (kbdev->cci_snoop_enabled) { -+#ifdef CONFIG_ARM64 -+ if (kbdev->snoop_disable_smc != 0) { -+ mali_cci_flush_l2(kbdev); -+ kbase_invoke_smc_fid(kbdev->snoop_disable_smc, 0, 0, 0); -+ } -+#endif /* CONFIG_ARM64 */ -+ dev_dbg(kbdev->dev, "MALI - CCI Snoops Disabled\n"); -+ kbdev->cci_snoop_enabled = false; -+ } -+} -+ -+static int kbase_pm_do_reset(struct kbase_device *kbdev) -+{ -+ struct kbasep_reset_timeout_data rtdata; -+ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_SOFT_RESET, NULL, NULL, 0u, 0); -+ -+ KBASE_TLSTREAM_JD_GPU_SOFT_RESET(kbdev); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_SOFT_RESET, NULL); -+ -+ /* Unmask the reset complete interrupt only */ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), RESET_COMPLETED, -+ NULL); -+ -+ /* Initialize a structure for tracking the status of the reset */ -+ rtdata.kbdev = kbdev; -+ rtdata.timed_out = 0; -+ -+ /* Create a timer to use as a timeout on the reset */ -+ hrtimer_init_on_stack(&rtdata.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ rtdata.timer.function = kbasep_reset_timeout; -+ -+ hrtimer_start(&rtdata.timer, HR_TIMER_DELAY_MSEC(RESET_TIMEOUT), -+ HRTIMER_MODE_REL); -+ -+ /* Wait for the RESET_COMPLETED interrupt to be raised */ -+ kbase_pm_wait_for_reset(kbdev); -+ -+ if (rtdata.timed_out == 0) { -+ /* GPU has been reset */ -+ hrtimer_cancel(&rtdata.timer); -+ destroy_hrtimer_on_stack(&rtdata.timer); -+ return 0; -+ } -+ -+ /* No interrupt has been received - check if the RAWSTAT register says -+ * the reset has completed */ -+ if (kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), NULL) & -+ RESET_COMPLETED) { -+ /* The interrupt is set in the RAWSTAT; this suggests that the -+ * interrupts are not getting to the CPU */ -+ dev_err(kbdev->dev, "Reset interrupt didn't reach CPU. Check interrupt assignments.\n"); -+ /* If interrupts aren't working we can't continue. */ -+ destroy_hrtimer_on_stack(&rtdata.timer); -+ return -EINVAL; -+ } -+ -+ /* The GPU doesn't seem to be responding to the reset so try a hard -+ * reset */ -+ dev_err(kbdev->dev, "Failed to soft-reset GPU (timed out after %d ms), now attempting a hard reset\n", -+ RESET_TIMEOUT); -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0); -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_HARD_RESET, NULL); -+ -+ /* Restart the timer to wait for the hard reset to complete */ -+ rtdata.timed_out = 0; -+ -+ hrtimer_start(&rtdata.timer, HR_TIMER_DELAY_MSEC(RESET_TIMEOUT), -+ HRTIMER_MODE_REL); -+ -+ /* Wait for the RESET_COMPLETED interrupt to be raised */ -+ kbase_pm_wait_for_reset(kbdev); -+ -+ if (rtdata.timed_out == 0) { -+ /* GPU has been reset */ -+ hrtimer_cancel(&rtdata.timer); -+ destroy_hrtimer_on_stack(&rtdata.timer); -+ return 0; -+ } -+ -+ destroy_hrtimer_on_stack(&rtdata.timer); -+ -+ dev_err(kbdev->dev, "Failed to hard-reset the GPU (timed out after %d ms)\n", -+ RESET_TIMEOUT); -+ -+ return -EINVAL; -+} -+ -+static int kbasep_protected_mode_enable(struct protected_mode_device *pdev) -+{ -+ struct kbase_device *kbdev = pdev->data; -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_SET_PROTECTED_MODE, NULL); -+ return 0; -+} -+ -+static int kbasep_protected_mode_disable(struct protected_mode_device *pdev) -+{ -+ struct kbase_device *kbdev = pdev->data; -+ -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ return kbase_pm_do_reset(kbdev); -+} -+ -+struct protected_mode_ops kbase_native_protected_ops = { -+ .protected_mode_enable = kbasep_protected_mode_enable, -+ .protected_mode_disable = kbasep_protected_mode_disable -+}; -+ -+int kbase_pm_init_hw(struct kbase_device *kbdev, unsigned int flags) -+{ -+ unsigned long irq_flags; -+ int err; -+ bool resume_vinstr = false; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ /* Ensure the clock is on before attempting to access the hardware */ -+ if (!kbdev->pm.backend.gpu_powered) { -+ if (kbdev->pm.backend.callback_power_on) -+ kbdev->pm.backend.callback_power_on(kbdev); -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, -+ irq_flags); -+ kbdev->pm.backend.gpu_powered = true; -+ spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, -+ irq_flags); -+ } -+ -+ /* Ensure interrupts are off to begin with, this also clears any -+ * outstanding interrupts */ -+ kbase_pm_disable_interrupts(kbdev); -+ /* Ensure cache snoops are disabled before reset. */ -+ kbase_pm_cache_snoop_disable(kbdev); -+ /* Prepare for the soft-reset */ -+ kbdev->pm.backend.reset_done = false; -+ -+ /* The cores should be made unavailable due to the reset */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags); -+ if (kbdev->shader_available_bitmap != 0u) -+ KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL, -+ NULL, 0u, (u32)0u); -+ if (kbdev->tiler_available_bitmap != 0u) -+ KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER, -+ NULL, NULL, 0u, (u32)0u); -+ kbdev->shader_available_bitmap = 0u; -+ kbdev->tiler_available_bitmap = 0u; -+ kbdev->l2_available_bitmap = 0u; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags); -+ -+ /* Soft reset the GPU */ -+ if (kbdev->protected_mode_support) -+ err = kbdev->protected_ops->protected_mode_disable( -+ kbdev->protected_dev); -+ else -+ err = kbase_pm_do_reset(kbdev); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags); -+ if (kbdev->protected_mode) -+ resume_vinstr = true; -+ kbdev->protected_mode = false; -+ kbase_ipa_model_use_configured_locked(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags); -+ -+ if (err) -+ goto exit; -+ -+ if (flags & PM_HW_ISSUES_DETECT) -+ kbase_pm_hw_issues_detect(kbdev); -+ -+ kbase_pm_hw_issues_apply(kbdev); -+ kbase_cache_set_coherency_mode(kbdev, kbdev->system_coherency); -+ -+ /* Sanity check protected mode was left after reset */ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE)) { -+ u32 gpu_status = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(GPU_STATUS), NULL); -+ -+ WARN_ON(gpu_status & GPU_STATUS_PROTECTED_MODE_ACTIVE); -+ } -+ -+ /* If cycle counter was in use re-enable it, enable_irqs will only be -+ * false when called from kbase_pm_powerup */ -+ if (kbdev->pm.backend.gpu_cycle_counter_requests && -+ (flags & PM_ENABLE_IRQS)) { -+ /* enable interrupts as the L2 may have to be powered on */ -+ kbase_pm_enable_interrupts(kbdev); -+ kbase_pm_request_l2_caches(kbdev); -+ -+ /* Re-enable the counters if we need to */ -+ spin_lock_irqsave( -+ &kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ irq_flags); -+ if (kbdev->pm.backend.gpu_cycle_counter_requests) -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_CYCLE_COUNT_START, NULL); -+ spin_unlock_irqrestore( -+ &kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ irq_flags); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags); -+ kbase_pm_release_l2_caches(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags); -+ -+ kbase_pm_disable_interrupts(kbdev); -+ } -+ -+ if (flags & PM_ENABLE_IRQS) -+ kbase_pm_enable_interrupts(kbdev); -+ -+exit: -+ /* If GPU is leaving protected mode resume vinstr operation. */ -+ if (kbdev->vinstr_ctx && resume_vinstr) -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+ -+ return err; -+} -+ -+/** -+ * kbase_pm_request_gpu_cycle_counter_do_request - Request cycle counters -+ * -+ * Increase the count of cycle counter users and turn the cycle counters on if -+ * they were previously off -+ * -+ * This function is designed to be called by -+ * kbase_pm_request_gpu_cycle_counter() or -+ * kbase_pm_request_gpu_cycle_counter_l2_is_on() only -+ * -+ * When this function is called the l2 cache must be on and the l2 cache users -+ * count must have been incremented by a call to ( -+ * kbase_pm_request_l2_caches() or kbase_pm_request_l2_caches_l2_on() ) -+ * -+ * @kbdev: The kbase device structure of the device -+ */ -+static void -+kbase_pm_request_gpu_cycle_counter_do_request(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ flags); -+ -+ ++kbdev->pm.backend.gpu_cycle_counter_requests; -+ -+ if (1 == kbdev->pm.backend.gpu_cycle_counter_requests) -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_CYCLE_COUNT_START, NULL); -+ -+ spin_unlock_irqrestore( -+ &kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ flags); -+} -+ -+void kbase_pm_request_gpu_cycle_counter(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered); -+ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests < -+ INT_MAX); -+ -+ kbase_pm_request_l2_caches(kbdev); -+ -+ kbase_pm_request_gpu_cycle_counter_do_request(kbdev); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_request_gpu_cycle_counter); -+ -+void kbase_pm_request_gpu_cycle_counter_l2_is_on(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered); -+ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests < -+ INT_MAX); -+ -+ kbase_pm_request_l2_caches_l2_is_on(kbdev); -+ -+ kbase_pm_request_gpu_cycle_counter_do_request(kbdev); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_request_gpu_cycle_counter_l2_is_on); -+ -+void kbase_pm_release_gpu_cycle_counter_nolock(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ spin_lock_irqsave(&kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ flags); -+ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests > 0); -+ -+ --kbdev->pm.backend.gpu_cycle_counter_requests; -+ -+ if (0 == kbdev->pm.backend.gpu_cycle_counter_requests) -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), -+ GPU_COMMAND_CYCLE_COUNT_STOP, NULL); -+ -+ spin_unlock_irqrestore( -+ &kbdev->pm.backend.gpu_cycle_counter_requests_lock, -+ flags); -+ -+ kbase_pm_release_l2_caches(kbdev); -+} -+ -+void kbase_pm_release_gpu_cycle_counter(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ kbase_pm_release_gpu_cycle_counter_nolock(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_release_gpu_cycle_counter); -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_internal.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_internal.h -new file mode 100644 -index 0000000..6804f45 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_internal.h -@@ -0,0 +1,548 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Power management API definitions used internally by GPU backend -+ */ -+ -+#ifndef _KBASE_BACKEND_PM_INTERNAL_H_ -+#define _KBASE_BACKEND_PM_INTERNAL_H_ -+ -+#include -+ -+#include "mali_kbase_pm_ca.h" -+#include "mali_kbase_pm_policy.h" -+ -+ -+/** -+ * kbase_pm_dev_idle - The GPU is idle. -+ * -+ * The OS may choose to turn off idle devices -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_dev_idle(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_dev_activate - The GPU is active. -+ * -+ * The OS should avoid opportunistically turning off the GPU while it is active -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_dev_activate(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_get_present_cores - Get details of the cores that are present in -+ * the device. -+ * -+ * This function can be called by the active power policy to return a bitmask of -+ * the cores (of a specified type) present in the GPU device and also a count of -+ * the number of cores. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid -+ * pointer) -+ * @type: The type of core (see the enum kbase_pm_core_type enumeration) -+ * -+ * Return: The bit mask of cores present -+ */ -+u64 kbase_pm_get_present_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type); -+ -+/** -+ * kbase_pm_get_active_cores - Get details of the cores that are currently -+ * active in the device. -+ * -+ * This function can be called by the active power policy to return a bitmask of -+ * the cores (of a specified type) that are actively processing work (i.e. -+ * turned on *and* busy). -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * @type: The type of core (see the enum kbase_pm_core_type enumeration) -+ * -+ * Return: The bit mask of active cores -+ */ -+u64 kbase_pm_get_active_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type); -+ -+/** -+ * kbase_pm_get_trans_cores - Get details of the cores that are currently -+ * transitioning between power states. -+ * -+ * This function can be called by the active power policy to return a bitmask of -+ * the cores (of a specified type) that are currently transitioning between -+ * power states. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * @type: The type of core (see the enum kbase_pm_core_type enumeration) -+ * -+ * Return: The bit mask of transitioning cores -+ */ -+u64 kbase_pm_get_trans_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type); -+ -+/** -+ * kbase_pm_get_ready_cores - Get details of the cores that are currently -+ * powered and ready for jobs. -+ * -+ * This function can be called by the active power policy to return a bitmask of -+ * the cores (of a specified type) that are powered and ready for jobs (they may -+ * or may not be currently executing jobs). -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * @type: The type of core (see the enum kbase_pm_core_type enumeration) -+ * -+ * Return: The bit mask of ready cores -+ */ -+u64 kbase_pm_get_ready_cores(struct kbase_device *kbdev, -+ enum kbase_pm_core_type type); -+ -+/** -+ * kbase_pm_clock_on - Turn the clock for the device on, and enable device -+ * interrupts. -+ * -+ * This function can be used by a power policy to turn the clock for the GPU on. -+ * It should be modified during integration to perform the necessary actions to -+ * ensure that the GPU is fully powered and clocked. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid -+ * pointer) -+ * @is_resume: true if clock on due to resume after suspend, false otherwise -+ */ -+void kbase_pm_clock_on(struct kbase_device *kbdev, bool is_resume); -+ -+/** -+ * kbase_pm_clock_off - Disable device interrupts, and turn the clock for the -+ * device off. -+ * -+ * This function can be used by a power policy to turn the clock for the GPU -+ * off. It should be modified during integration to perform the necessary -+ * actions to turn the clock off (if this is possible in the integration). -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid -+ * pointer) -+ * @is_suspend: true if clock off due to suspend, false otherwise -+ * -+ * Return: true if clock was turned off, or -+ * false if clock can not be turned off due to pending page/bus fault -+ * workers. Caller must flush MMU workqueues and retry -+ */ -+bool kbase_pm_clock_off(struct kbase_device *kbdev, bool is_suspend); -+ -+/** -+ * kbase_pm_enable_interrupts - Enable interrupts on the device. -+ * -+ * Interrupts are also enabled after a call to kbase_pm_clock_on(). -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_enable_interrupts(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_disable_interrupts - Disable interrupts on the device. -+ * -+ * This prevents delivery of Power Management interrupts to the CPU so that -+ * kbase_pm_check_transitions_nolock() will not be called from the IRQ handler -+ * until kbase_pm_enable_interrupts() or kbase_pm_clock_on() is called. -+ * -+ * Interrupts are also disabled after a call to kbase_pm_clock_off(). -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_disable_interrupts(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_disable_interrupts_nolock - Version of kbase_pm_disable_interrupts() -+ * that does not take the hwaccess_lock -+ * -+ * Caller must hold the hwaccess_lock. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_disable_interrupts_nolock(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_init_hw - Initialize the hardware. -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * @flags: Flags specifying the type of PM init -+ * -+ * This function checks the GPU ID register to ensure that the GPU is supported -+ * by the driver and performs a reset on the device so that it is in a known -+ * state before the device is used. -+ * -+ * Return: 0 if the device is supported and successfully reset. -+ */ -+int kbase_pm_init_hw(struct kbase_device *kbdev, unsigned int flags); -+ -+/** -+ * kbase_pm_reset_done - The GPU has been reset successfully. -+ * -+ * This function must be called by the GPU interrupt handler when the -+ * RESET_COMPLETED bit is set. It signals to the power management initialization -+ * code that the GPU has been successfully reset. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_reset_done(struct kbase_device *kbdev); -+ -+ -+/** -+ * kbase_pm_check_transitions_nolock - Check if there are any power transitions -+ * to make, and if so start them. -+ * -+ * This function will check the desired_xx_state members of -+ * struct kbase_pm_device_data and the actual status of the hardware to see if -+ * any power transitions can be made at this time to make the hardware state -+ * closer to the state desired by the power policy. -+ * -+ * The return value can be used to check whether all the desired cores are -+ * available, and so whether it's worth submitting a job (e.g. from a Power -+ * Management IRQ). -+ * -+ * Note that this still returns true when desired_xx_state has no -+ * cores. That is: of the no cores desired, none were *un*available. In -+ * this case, the caller may still need to try submitting jobs. This is because -+ * the Core Availability Policy might have taken us to an intermediate state -+ * where no cores are powered, before powering on more cores (e.g. for core -+ * rotation) -+ * -+ * The caller must hold kbase_device.pm.power_change_lock -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Return: non-zero when all desired cores are available. That is, -+ * it's worthwhile for the caller to submit a job. -+ * false otherwise -+ */ -+bool kbase_pm_check_transitions_nolock(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_check_transitions_sync - Synchronous and locking variant of -+ * kbase_pm_check_transitions_nolock() -+ * -+ * On returning, the desired state at the time of the call will have been met. -+ * -+ * There is nothing to stop the core being switched off by calls to -+ * kbase_pm_release_cores() or kbase_pm_unrequest_cores(). Therefore, the -+ * caller must have already made a call to -+ * kbase_pm_request_cores()/kbase_pm_request_cores_sync() previously. -+ * -+ * The usual use-case for this is to ensure cores are 'READY' after performing -+ * a GPU Reset. -+ * -+ * Unlike kbase_pm_check_transitions_nolock(), the caller must not hold -+ * kbase_device.pm.power_change_lock, because this function will take that -+ * lock itself. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_check_transitions_sync(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_update_cores_state_nolock - Variant of kbase_pm_update_cores_state() -+ * where the caller must hold -+ * kbase_device.pm.power_change_lock -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_update_cores_state_nolock(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_update_cores_state - Update the desired state of shader cores from -+ * the Power Policy, and begin any power -+ * transitions. -+ * -+ * This function will update the desired_xx_state members of -+ * struct kbase_pm_device_data by calling into the current Power Policy. It will -+ * then begin power transitions to make the hardware acheive the desired shader -+ * core state. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_update_cores_state(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_cancel_deferred_poweroff - Cancel any pending requests to power off -+ * the GPU and/or shader cores. -+ * -+ * This should be called by any functions which directly power off the GPU. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_cancel_deferred_poweroff(struct kbase_device *kbdev); -+ -+/** -+ * kbasep_pm_init_core_use_bitmaps - Initialise data tracking the required -+ * and used cores. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbasep_pm_init_core_use_bitmaps(struct kbase_device *kbdev); -+ -+/** -+ * kbasep_pm_metrics_init - Initialize the metrics gathering framework. -+ * -+ * This must be called before other metric gathering APIs are called. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Return: 0 on success, error code on error -+ */ -+int kbasep_pm_metrics_init(struct kbase_device *kbdev); -+ -+/** -+ * kbasep_pm_metrics_term - Terminate the metrics gathering framework. -+ * -+ * This must be called when metric gathering is no longer required. It is an -+ * error to call any metrics gathering function (other than -+ * kbasep_pm_metrics_init()) after calling this function. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbasep_pm_metrics_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_report_vsync - Function to be called by the frame buffer driver to -+ * update the vsync metric. -+ * -+ * This function should be called by the frame buffer driver to update whether -+ * the system is hitting the vsync target or not. buffer_updated should be true -+ * if the vsync corresponded with a new frame being displayed, otherwise it -+ * should be false. This function does not need to be called every vsync, but -+ * only when the value of @buffer_updated differs from a previous call. -+ * -+ * @kbdev: The kbase device structure for the device (must be a -+ * valid pointer) -+ * @buffer_updated: True if the buffer has been updated on this VSync, -+ * false otherwise -+ */ -+void kbase_pm_report_vsync(struct kbase_device *kbdev, int buffer_updated); -+ -+/** -+ * kbase_pm_get_dvfs_action - Determine whether the DVFS system should change -+ * the clock speed of the GPU. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * This function should be called regularly by the DVFS system to check whether -+ * the clock speed of the GPU needs updating. -+ */ -+void kbase_pm_get_dvfs_action(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_request_gpu_cycle_counter - Mark that the GPU cycle counter is -+ * needed -+ * -+ * If the caller is the first caller then the GPU cycle counters will be enabled -+ * along with the l2 cache -+ * -+ * The GPU must be powered when calling this function (i.e. -+ * kbase_pm_context_active() must have been called). -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_request_gpu_cycle_counter(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_request_gpu_cycle_counter_l2_is_on - Mark GPU cycle counter is -+ * needed (l2 cache already on) -+ * -+ * This is a version of the above function -+ * (kbase_pm_request_gpu_cycle_counter()) suitable for being called when the -+ * l2 cache is known to be on and assured to be on until the subsequent call of -+ * kbase_pm_release_gpu_cycle_counter() such as when a job is submitted. It does -+ * not sleep and can be called from atomic functions. -+ * -+ * The GPU must be powered when calling this function (i.e. -+ * kbase_pm_context_active() must have been called) and the l2 cache must be -+ * powered on. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_request_gpu_cycle_counter_l2_is_on(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_release_gpu_cycle_counter - Mark that the GPU cycle counter is no -+ * longer in use -+ * -+ * If the caller is the last caller then the GPU cycle counters will be -+ * disabled. A request must have been made before a call to this. -+ * -+ * Caller must not hold the hwaccess_lock, as it will be taken in this function. -+ * If the caller is already holding this lock then -+ * kbase_pm_release_gpu_cycle_counter_nolock() must be used instead. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_release_gpu_cycle_counter(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_release_gpu_cycle_counter_nolock - Version of kbase_pm_release_gpu_cycle_counter() -+ * that does not take hwaccess_lock -+ * -+ * Caller must hold the hwaccess_lock. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_release_gpu_cycle_counter_nolock(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_wait_for_poweroff_complete - Wait for the poweroff workqueue to -+ * complete -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_wait_for_poweroff_complete(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_register_access_enable - Enable access to GPU registers -+ * -+ * Enables access to the GPU registers before power management has powered up -+ * the GPU with kbase_pm_powerup(). -+ * -+ * Access to registers should be done using kbase_os_reg_read()/write() at this -+ * stage, not kbase_reg_read()/write(). -+ * -+ * This results in the power management callbacks provided in the driver -+ * configuration to get called to turn on power and/or clocks to the GPU. See -+ * kbase_pm_callback_conf. -+ * -+ * This should only be used before power management is powered up with -+ * kbase_pm_powerup() -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_register_access_enable(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_register_access_disable - Disable early register access -+ * -+ * Disables access to the GPU registers enabled earlier by a call to -+ * kbase_pm_register_access_enable(). -+ * -+ * This results in the power management callbacks provided in the driver -+ * configuration to get called to turn off power and/or clocks to the GPU. See -+ * kbase_pm_callback_conf -+ * -+ * This should only be used before power management is powered up with -+ * kbase_pm_powerup() -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_register_access_disable(struct kbase_device *kbdev); -+ -+/* NOTE: kbase_pm_is_suspending is in mali_kbase.h, because it is an inline -+ * function */ -+ -+/** -+ * kbase_pm_metrics_is_active - Check if the power management metrics -+ * collection is active. -+ * -+ * Note that this returns if the power management metrics collection was -+ * active at the time of calling, it is possible that after the call the metrics -+ * collection enable may have changed state. -+ * -+ * The caller must handle the consequence that the state may have changed. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * Return: true if metrics collection was active else false. -+ */ -+bool kbase_pm_metrics_is_active(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_do_poweron - Power on the GPU, and any cores that are requested. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid -+ * pointer) -+ * @is_resume: true if power on due to resume after suspend, -+ * false otherwise -+ */ -+void kbase_pm_do_poweron(struct kbase_device *kbdev, bool is_resume); -+ -+/** -+ * kbase_pm_do_poweroff - Power off the GPU, and any cores that have been -+ * requested. -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid -+ * pointer) -+ * @is_suspend: true if power off due to suspend, -+ * false otherwise -+ */ -+void kbase_pm_do_poweroff(struct kbase_device *kbdev, bool is_suspend); -+ -+#if defined(CONFIG_MALI_DEVFREQ) || defined(CONFIG_MALI_MIDGARD_DVFS) -+void kbase_pm_get_dvfs_utilisation(struct kbase_device *kbdev, -+ unsigned long *total, unsigned long *busy); -+void kbase_pm_reset_dvfs_utilisation(struct kbase_device *kbdev); -+#endif /* defined(CONFIG_MALI_DEVFREQ) || defined(CONFIG_MALI_MIDGARD_DVFS) */ -+ -+#ifdef CONFIG_MALI_MIDGARD_DVFS -+ -+/** -+ * kbase_platform_dvfs_event - Report utilisation to DVFS code -+ * -+ * Function provided by platform specific code when DVFS is enabled to allow -+ * the power management metrics system to report utilisation. -+ * -+ * @kbdev: The kbase device structure for the device (must be a -+ * valid pointer) -+ * @utilisation: The current calculated utilisation by the metrics system. -+ * @util_gl_share: The current calculated gl share of utilisation. -+ * @util_cl_share: The current calculated cl share of utilisation per core -+ * group. -+ * Return: Returns 0 on failure and non zero on success. -+ */ -+ -+int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation, -+ u32 util_gl_share, u32 util_cl_share[2]); -+#endif -+ -+void kbase_pm_power_changed(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_metrics_update - Inform the metrics system that an atom is either -+ * about to be run or has just completed. -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * @now: Pointer to the timestamp of the change, or NULL to use current time -+ * -+ * Caller must hold hwaccess_lock -+ */ -+void kbase_pm_metrics_update(struct kbase_device *kbdev, -+ ktime_t *now); -+ -+/** -+ * kbase_pm_cache_snoop_enable - Allow CPU snoops on the GPU -+ * If the GPU does not have coherency this is a no-op -+ * @kbdev: Device pointer -+ * -+ * This function should be called after L2 power up. -+ */ -+ -+void kbase_pm_cache_snoop_enable(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_cache_snoop_disable - Prevent CPU snoops on the GPU -+ * If the GPU does not have coherency this is a no-op -+ * @kbdev: Device pointer -+ * -+ * This function should be called before L2 power off. -+ */ -+void kbase_pm_cache_snoop_disable(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_BACKEND_PM_INTERNAL_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_metrics.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_metrics.c -new file mode 100644 -index 0000000..024248c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_metrics.c -@@ -0,0 +1,401 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Metrics for power management -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/* When VSync is being hit aim for utilisation between 70-90% */ -+#define KBASE_PM_VSYNC_MIN_UTILISATION 70 -+#define KBASE_PM_VSYNC_MAX_UTILISATION 90 -+/* Otherwise aim for 10-40% */ -+#define KBASE_PM_NO_VSYNC_MIN_UTILISATION 10 -+#define KBASE_PM_NO_VSYNC_MAX_UTILISATION 40 -+ -+/* Shift used for kbasep_pm_metrics_data.time_busy/idle - units of (1 << 8) ns -+ * This gives a maximum period between samples of 2^(32+8)/100 ns = slightly -+ * under 11s. Exceeding this will cause overflow */ -+#define KBASE_PM_TIME_SHIFT 8 -+ -+/* Maximum time between sampling of utilization data, without resetting the -+ * counters. */ -+#define MALI_UTILIZATION_MAX_PERIOD 100000 /* ns = 100ms */ -+ -+#ifdef CONFIG_MALI_MIDGARD_DVFS -+static enum hrtimer_restart dvfs_callback(struct hrtimer *timer) -+{ -+ unsigned long flags; -+ struct kbasep_pm_metrics_data *metrics; -+ -+ KBASE_DEBUG_ASSERT(timer != NULL); -+ -+ metrics = container_of(timer, struct kbasep_pm_metrics_data, timer); -+ kbase_pm_get_dvfs_action(metrics->kbdev); -+ -+ spin_lock_irqsave(&metrics->lock, flags); -+ -+ if (metrics->timer_active) -+ hrtimer_start(timer, -+ HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period), -+ HRTIMER_MODE_REL); -+ -+ spin_unlock_irqrestore(&metrics->lock, flags); -+ -+ return HRTIMER_NORESTART; -+} -+#endif /* CONFIG_MALI_MIDGARD_DVFS */ -+ -+int kbasep_pm_metrics_init(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ kbdev->pm.backend.metrics.kbdev = kbdev; -+ -+ kbdev->pm.backend.metrics.time_period_start = ktime_get(); -+ kbdev->pm.backend.metrics.time_busy = 0; -+ kbdev->pm.backend.metrics.time_idle = 0; -+ kbdev->pm.backend.metrics.prev_busy = 0; -+ kbdev->pm.backend.metrics.prev_idle = 0; -+ kbdev->pm.backend.metrics.gpu_active = false; -+ kbdev->pm.backend.metrics.active_cl_ctx[0] = 0; -+ kbdev->pm.backend.metrics.active_cl_ctx[1] = 0; -+ kbdev->pm.backend.metrics.active_gl_ctx[0] = 0; -+ kbdev->pm.backend.metrics.active_gl_ctx[1] = 0; -+ kbdev->pm.backend.metrics.busy_cl[0] = 0; -+ kbdev->pm.backend.metrics.busy_cl[1] = 0; -+ kbdev->pm.backend.metrics.busy_gl = 0; -+ -+ spin_lock_init(&kbdev->pm.backend.metrics.lock); -+ -+#ifdef CONFIG_MALI_MIDGARD_DVFS -+ kbdev->pm.backend.metrics.timer_active = true; -+ hrtimer_init(&kbdev->pm.backend.metrics.timer, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL); -+ kbdev->pm.backend.metrics.timer.function = dvfs_callback; -+ -+ hrtimer_start(&kbdev->pm.backend.metrics.timer, -+ HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period), -+ HRTIMER_MODE_REL); -+#endif /* CONFIG_MALI_MIDGARD_DVFS */ -+ -+ return 0; -+} -+ -+KBASE_EXPORT_TEST_API(kbasep_pm_metrics_init); -+ -+void kbasep_pm_metrics_term(struct kbase_device *kbdev) -+{ -+#ifdef CONFIG_MALI_MIDGARD_DVFS -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); -+ kbdev->pm.backend.metrics.timer_active = false; -+ spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); -+ -+ hrtimer_cancel(&kbdev->pm.backend.metrics.timer); -+#endif /* CONFIG_MALI_MIDGARD_DVFS */ -+} -+ -+KBASE_EXPORT_TEST_API(kbasep_pm_metrics_term); -+ -+/* caller needs to hold kbdev->pm.backend.metrics.lock before calling this -+ * function -+ */ -+static void kbase_pm_get_dvfs_utilisation_calc(struct kbase_device *kbdev, -+ ktime_t now) -+{ -+ ktime_t diff; -+ -+ lockdep_assert_held(&kbdev->pm.backend.metrics.lock); -+ -+ diff = ktime_sub(now, kbdev->pm.backend.metrics.time_period_start); -+ if (ktime_to_ns(diff) < 0) -+ return; -+ -+ if (kbdev->pm.backend.metrics.gpu_active) { -+ u32 ns_time = (u32) (ktime_to_ns(diff) >> KBASE_PM_TIME_SHIFT); -+ -+ kbdev->pm.backend.metrics.time_busy += ns_time; -+ if (kbdev->pm.backend.metrics.active_cl_ctx[0]) -+ kbdev->pm.backend.metrics.busy_cl[0] += ns_time; -+ if (kbdev->pm.backend.metrics.active_cl_ctx[1]) -+ kbdev->pm.backend.metrics.busy_cl[1] += ns_time; -+ if (kbdev->pm.backend.metrics.active_gl_ctx[0]) -+ kbdev->pm.backend.metrics.busy_gl += ns_time; -+ if (kbdev->pm.backend.metrics.active_gl_ctx[1]) -+ kbdev->pm.backend.metrics.busy_gl += ns_time; -+ } else { -+ kbdev->pm.backend.metrics.time_idle += (u32) (ktime_to_ns(diff) -+ >> KBASE_PM_TIME_SHIFT); -+ } -+ -+ kbdev->pm.backend.metrics.time_period_start = now; -+} -+ -+#if defined(CONFIG_MALI_DEVFREQ) || defined(CONFIG_MALI_MIDGARD_DVFS) -+/* Caller needs to hold kbdev->pm.backend.metrics.lock before calling this -+ * function. -+ */ -+static void kbase_pm_reset_dvfs_utilisation_unlocked(struct kbase_device *kbdev, -+ ktime_t now) -+{ -+ /* Store previous value */ -+ kbdev->pm.backend.metrics.prev_idle = -+ kbdev->pm.backend.metrics.time_idle; -+ kbdev->pm.backend.metrics.prev_busy = -+ kbdev->pm.backend.metrics.time_busy; -+ -+ /* Reset current values */ -+ kbdev->pm.backend.metrics.time_period_start = now; -+ kbdev->pm.backend.metrics.time_idle = 0; -+ kbdev->pm.backend.metrics.time_busy = 0; -+ kbdev->pm.backend.metrics.busy_cl[0] = 0; -+ kbdev->pm.backend.metrics.busy_cl[1] = 0; -+ kbdev->pm.backend.metrics.busy_gl = 0; -+} -+ -+void kbase_pm_reset_dvfs_utilisation(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); -+ kbase_pm_reset_dvfs_utilisation_unlocked(kbdev, ktime_get()); -+ spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); -+} -+ -+void kbase_pm_get_dvfs_utilisation(struct kbase_device *kbdev, -+ unsigned long *total_out, unsigned long *busy_out) -+{ -+ ktime_t now = ktime_get(); -+ unsigned long flags, busy, total; -+ -+ spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); -+ kbase_pm_get_dvfs_utilisation_calc(kbdev, now); -+ -+ busy = kbdev->pm.backend.metrics.time_busy; -+ total = busy + kbdev->pm.backend.metrics.time_idle; -+ -+ /* Reset stats if older than MALI_UTILIZATION_MAX_PERIOD (default -+ * 100ms) */ -+ if (total >= MALI_UTILIZATION_MAX_PERIOD) { -+ kbase_pm_reset_dvfs_utilisation_unlocked(kbdev, now); -+ } else if (total < (MALI_UTILIZATION_MAX_PERIOD / 2)) { -+ total += kbdev->pm.backend.metrics.prev_idle + -+ kbdev->pm.backend.metrics.prev_busy; -+ busy += kbdev->pm.backend.metrics.prev_busy; -+ } -+ -+ *total_out = total; -+ *busy_out = busy; -+ spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); -+} -+#endif -+ -+#ifdef CONFIG_MALI_MIDGARD_DVFS -+ -+/* caller needs to hold kbdev->pm.backend.metrics.lock before calling this -+ * function -+ */ -+int kbase_pm_get_dvfs_utilisation_old(struct kbase_device *kbdev, -+ int *util_gl_share, -+ int util_cl_share[2], -+ ktime_t now) -+{ -+ int utilisation; -+ int busy; -+ -+ kbase_pm_get_dvfs_utilisation_calc(kbdev, now); -+ -+ if (kbdev->pm.backend.metrics.time_idle + -+ kbdev->pm.backend.metrics.time_busy == 0) { -+ /* No data - so we return NOP */ -+ utilisation = -1; -+ if (util_gl_share) -+ *util_gl_share = -1; -+ if (util_cl_share) { -+ util_cl_share[0] = -1; -+ util_cl_share[1] = -1; -+ } -+ goto out; -+ } -+ -+ utilisation = (100 * kbdev->pm.backend.metrics.time_busy) / -+ (kbdev->pm.backend.metrics.time_idle + -+ kbdev->pm.backend.metrics.time_busy); -+ -+ busy = kbdev->pm.backend.metrics.busy_gl + -+ kbdev->pm.backend.metrics.busy_cl[0] + -+ kbdev->pm.backend.metrics.busy_cl[1]; -+ -+ if (busy != 0) { -+ if (util_gl_share) -+ *util_gl_share = -+ (100 * kbdev->pm.backend.metrics.busy_gl) / -+ busy; -+ if (util_cl_share) { -+ util_cl_share[0] = -+ (100 * kbdev->pm.backend.metrics.busy_cl[0]) / -+ busy; -+ util_cl_share[1] = -+ (100 * kbdev->pm.backend.metrics.busy_cl[1]) / -+ busy; -+ } -+ } else { -+ if (util_gl_share) -+ *util_gl_share = -1; -+ if (util_cl_share) { -+ util_cl_share[0] = -1; -+ util_cl_share[1] = -1; -+ } -+ } -+ -+out: -+ return utilisation; -+} -+ -+void kbase_pm_get_dvfs_action(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ int utilisation, util_gl_share; -+ int util_cl_share[2]; -+ ktime_t now; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); -+ -+ now = ktime_get(); -+ -+ utilisation = kbase_pm_get_dvfs_utilisation_old(kbdev, &util_gl_share, -+ util_cl_share, now); -+ -+ if (utilisation < 0 || util_gl_share < 0 || util_cl_share[0] < 0 || -+ util_cl_share[1] < 0) { -+ utilisation = 0; -+ util_gl_share = 0; -+ util_cl_share[0] = 0; -+ util_cl_share[1] = 0; -+ goto out; -+ } -+ -+out: -+#ifdef CONFIG_MALI_MIDGARD_DVFS -+ kbase_platform_dvfs_event(kbdev, utilisation, util_gl_share, -+ util_cl_share); -+#endif /*CONFIG_MALI_MIDGARD_DVFS */ -+ -+ kbase_pm_reset_dvfs_utilisation_unlocked(kbdev, now); -+ -+ spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); -+} -+ -+bool kbase_pm_metrics_is_active(struct kbase_device *kbdev) -+{ -+ bool isactive; -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); -+ isactive = kbdev->pm.backend.metrics.timer_active; -+ spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); -+ -+ return isactive; -+} -+KBASE_EXPORT_TEST_API(kbase_pm_metrics_is_active); -+ -+#endif /* CONFIG_MALI_MIDGARD_DVFS */ -+ -+/** -+ * kbase_pm_metrics_active_calc - Update PM active counts based on currently -+ * running atoms -+ * @kbdev: Device pointer -+ * -+ * The caller must hold kbdev->pm.backend.metrics.lock -+ */ -+static void kbase_pm_metrics_active_calc(struct kbase_device *kbdev) -+{ -+ int js; -+ -+ lockdep_assert_held(&kbdev->pm.backend.metrics.lock); -+ -+ kbdev->pm.backend.metrics.active_gl_ctx[0] = 0; -+ kbdev->pm.backend.metrics.active_gl_ctx[1] = 0; -+ kbdev->pm.backend.metrics.active_cl_ctx[0] = 0; -+ kbdev->pm.backend.metrics.active_cl_ctx[1] = 0; -+ kbdev->pm.backend.metrics.gpu_active = false; -+ -+ for (js = 0; js < BASE_JM_MAX_NR_SLOTS; js++) { -+ struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, 0); -+ -+ /* Head atom may have just completed, so if it isn't running -+ * then try the next atom */ -+ if (katom && katom->gpu_rb_state != KBASE_ATOM_GPU_RB_SUBMITTED) -+ katom = kbase_gpu_inspect(kbdev, js, 1); -+ -+ if (katom && katom->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_SUBMITTED) { -+ if (katom->core_req & BASE_JD_REQ_ONLY_COMPUTE) { -+ int device_nr = (katom->core_req & -+ BASE_JD_REQ_SPECIFIC_COHERENT_GROUP) -+ ? katom->device_nr : 0; -+ if (!WARN_ON(device_nr >= 2)) -+ kbdev->pm.backend.metrics. -+ active_cl_ctx[device_nr] = 1; -+ } else { -+ /* Slot 2 should not be running non-compute -+ * atoms */ -+ if (!WARN_ON(js >= 2)) -+ kbdev->pm.backend.metrics. -+ active_gl_ctx[js] = 1; -+ } -+ kbdev->pm.backend.metrics.gpu_active = true; -+ } -+ } -+} -+ -+/* called when job is submitted to or removed from a GPU slot */ -+void kbase_pm_metrics_update(struct kbase_device *kbdev, ktime_t *timestamp) -+{ -+ unsigned long flags; -+ ktime_t now; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags); -+ -+ if (!timestamp) { -+ now = ktime_get(); -+ timestamp = &now; -+ } -+ -+ /* Track how long CL and/or GL jobs have been busy for */ -+ kbase_pm_get_dvfs_utilisation_calc(kbdev, *timestamp); -+ -+ kbase_pm_metrics_active_calc(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags); -+} -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_policy.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_policy.c -new file mode 100644 -index 0000000..075f020 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_policy.c -@@ -0,0 +1,973 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Power policy API implementations -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static const struct kbase_pm_policy *const policy_list[] = { -+#ifdef CONFIG_MALI_NO_MALI -+ &kbase_pm_always_on_policy_ops, -+ &kbase_pm_demand_policy_ops, -+ &kbase_pm_coarse_demand_policy_ops, -+#if !MALI_CUSTOMER_RELEASE -+ &kbase_pm_demand_always_powered_policy_ops, -+ &kbase_pm_fast_start_policy_ops, -+#endif -+#else /* CONFIG_MALI_NO_MALI */ -+#if !PLATFORM_POWER_DOWN_ONLY -+ &kbase_pm_demand_policy_ops, -+#endif /* !PLATFORM_POWER_DOWN_ONLY */ -+ &kbase_pm_coarse_demand_policy_ops, -+ &kbase_pm_always_on_policy_ops, -+#if !MALI_CUSTOMER_RELEASE -+#if !PLATFORM_POWER_DOWN_ONLY -+ &kbase_pm_demand_always_powered_policy_ops, -+ &kbase_pm_fast_start_policy_ops, -+#endif /* !PLATFORM_POWER_DOWN_ONLY */ -+#endif -+#endif /* CONFIG_MALI_NO_MALI */ -+}; -+ -+/* The number of policies available in the system. -+ * This is derived from the number of functions listed in policy_get_functions. -+ */ -+#define POLICY_COUNT (sizeof(policy_list)/sizeof(*policy_list)) -+ -+ -+/* Function IDs for looking up Timeline Trace codes in -+ * kbase_pm_change_state_trace_code */ -+enum kbase_pm_func_id { -+ KBASE_PM_FUNC_ID_REQUEST_CORES_START, -+ KBASE_PM_FUNC_ID_REQUEST_CORES_END, -+ KBASE_PM_FUNC_ID_RELEASE_CORES_START, -+ KBASE_PM_FUNC_ID_RELEASE_CORES_END, -+ /* Note: kbase_pm_unrequest_cores() is on the slow path, and we neither -+ * expect to hit it nor tend to hit it very much anyway. We can detect -+ * whether we need more instrumentation by a difference between -+ * PM_CHECKTRANS events and PM_SEND/HANDLE_EVENT. */ -+ -+ /* Must be the last */ -+ KBASE_PM_FUNC_ID_COUNT -+}; -+ -+ -+/* State changes during request/unrequest/release-ing cores */ -+enum { -+ KBASE_PM_CHANGE_STATE_SHADER = (1u << 0), -+ KBASE_PM_CHANGE_STATE_TILER = (1u << 1), -+ -+ /* These two must be last */ -+ KBASE_PM_CHANGE_STATE_MASK = (KBASE_PM_CHANGE_STATE_TILER | -+ KBASE_PM_CHANGE_STATE_SHADER), -+ KBASE_PM_CHANGE_STATE_COUNT = KBASE_PM_CHANGE_STATE_MASK + 1 -+}; -+typedef u32 kbase_pm_change_state; -+ -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+/* Timeline Trace code lookups for each function */ -+static u32 kbase_pm_change_state_trace_code[KBASE_PM_FUNC_ID_COUNT] -+ [KBASE_PM_CHANGE_STATE_COUNT] = { -+ /* kbase_pm_request_cores */ -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_START][0] = 0, -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_START][KBASE_PM_CHANGE_STATE_SHADER] = -+ SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_START, -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_START][KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_TILER_START, -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_START][KBASE_PM_CHANGE_STATE_SHADER | -+ KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_TILER_START, -+ -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_END][0] = 0, -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_END][KBASE_PM_CHANGE_STATE_SHADER] = -+ SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_END, -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_END][KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_TILER_END, -+ [KBASE_PM_FUNC_ID_REQUEST_CORES_END][KBASE_PM_CHANGE_STATE_SHADER | -+ KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_TILER_END, -+ -+ /* kbase_pm_release_cores */ -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_START][0] = 0, -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_START][KBASE_PM_CHANGE_STATE_SHADER] = -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_START, -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_START][KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_TILER_START, -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_START][KBASE_PM_CHANGE_STATE_SHADER | -+ KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_TILER_START, -+ -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_END][0] = 0, -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_END][KBASE_PM_CHANGE_STATE_SHADER] = -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_END, -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_END][KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_TILER_END, -+ [KBASE_PM_FUNC_ID_RELEASE_CORES_END][KBASE_PM_CHANGE_STATE_SHADER | -+ KBASE_PM_CHANGE_STATE_TILER] = -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_TILER_END -+}; -+ -+static inline void kbase_timeline_pm_cores_func(struct kbase_device *kbdev, -+ enum kbase_pm_func_id func_id, -+ kbase_pm_change_state state) -+{ -+ int trace_code; -+ -+ KBASE_DEBUG_ASSERT(func_id >= 0 && func_id < KBASE_PM_FUNC_ID_COUNT); -+ KBASE_DEBUG_ASSERT(state != 0 && (state & KBASE_PM_CHANGE_STATE_MASK) == -+ state); -+ -+ trace_code = kbase_pm_change_state_trace_code[func_id][state]; -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, trace_code); -+} -+ -+#else /* CONFIG_MALI_TRACE_TIMELINE */ -+static inline void kbase_timeline_pm_cores_func(struct kbase_device *kbdev, -+ enum kbase_pm_func_id func_id, kbase_pm_change_state state) -+{ -+} -+ -+#endif /* CONFIG_MALI_TRACE_TIMELINE */ -+ -+/** -+ * kbasep_pm_do_poweroff_cores - Process a poweroff request and power down any -+ * requested shader cores -+ * @kbdev: Device pointer -+ */ -+static void kbasep_pm_do_poweroff_cores(struct kbase_device *kbdev) -+{ -+ u64 prev_shader_state = kbdev->pm.backend.desired_shader_state; -+ u64 prev_tiler_state = kbdev->pm.backend.desired_tiler_state; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ kbdev->pm.backend.desired_shader_state &= -+ ~kbdev->pm.backend.shader_poweroff_pending; -+ kbdev->pm.backend.desired_tiler_state &= -+ ~kbdev->pm.backend.tiler_poweroff_pending; -+ -+ kbdev->pm.backend.shader_poweroff_pending = 0; -+ kbdev->pm.backend.tiler_poweroff_pending = 0; -+ -+ if (prev_shader_state != kbdev->pm.backend.desired_shader_state || -+ prev_tiler_state != -+ kbdev->pm.backend.desired_tiler_state || -+ kbdev->pm.backend.ca_in_transition) { -+ bool cores_are_available; -+ -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_START); -+ cores_are_available = kbase_pm_check_transitions_nolock(kbdev); -+ KBASE_TIMELINE_PM_CHECKTRANS(kbdev, -+ SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_END); -+ -+ /* Don't need 'cores_are_available', -+ * because we don't return anything */ -+ CSTD_UNUSED(cores_are_available); -+ } -+} -+ -+static enum hrtimer_restart -+kbasep_pm_do_gpu_poweroff_callback(struct hrtimer *timer) -+{ -+ struct kbase_device *kbdev; -+ unsigned long flags; -+ -+ kbdev = container_of(timer, struct kbase_device, -+ pm.backend.gpu_poweroff_timer); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* It is safe for this call to do nothing if the work item is already -+ * queued. The worker function will read the must up-to-date state of -+ * kbdev->pm.backend.gpu_poweroff_pending under lock. -+ * -+ * If a state change occurs while the worker function is processing, -+ * this call will succeed as a work item can be requeued once it has -+ * started processing. -+ */ -+ if (kbdev->pm.backend.gpu_poweroff_pending) -+ queue_work(kbdev->pm.backend.gpu_poweroff_wq, -+ &kbdev->pm.backend.gpu_poweroff_work); -+ -+ if (kbdev->pm.backend.shader_poweroff_pending || -+ kbdev->pm.backend.tiler_poweroff_pending) { -+ kbdev->pm.backend.shader_poweroff_pending_time--; -+ -+ KBASE_DEBUG_ASSERT( -+ kbdev->pm.backend.shader_poweroff_pending_time -+ >= 0); -+ -+ if (!kbdev->pm.backend.shader_poweroff_pending_time) -+ kbasep_pm_do_poweroff_cores(kbdev); -+ } -+ -+ if (kbdev->pm.backend.poweroff_timer_needed) { -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ hrtimer_add_expires(timer, kbdev->pm.gpu_poweroff_time); -+ -+ return HRTIMER_RESTART; -+ } -+ -+ kbdev->pm.backend.poweroff_timer_running = false; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return HRTIMER_NORESTART; -+} -+ -+static void kbasep_pm_do_gpu_poweroff_wq(struct work_struct *data) -+{ -+ unsigned long flags; -+ struct kbase_device *kbdev; -+ bool do_poweroff = false; -+ -+ kbdev = container_of(data, struct kbase_device, -+ pm.backend.gpu_poweroff_work); -+ -+ mutex_lock(&kbdev->pm.lock); -+ -+ if (kbdev->pm.backend.gpu_poweroff_pending == 0) { -+ mutex_unlock(&kbdev->pm.lock); -+ return; -+ } -+ -+ kbdev->pm.backend.gpu_poweroff_pending--; -+ -+ if (kbdev->pm.backend.gpu_poweroff_pending > 0) { -+ mutex_unlock(&kbdev->pm.lock); -+ return; -+ } -+ -+ KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_poweroff_pending == 0); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* Only power off the GPU if a request is still pending */ -+ if (!kbdev->pm.backend.pm_current_policy->get_core_active(kbdev)) -+ do_poweroff = true; -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ if (do_poweroff) { -+ kbdev->pm.backend.poweroff_timer_needed = false; -+ hrtimer_cancel(&kbdev->pm.backend.gpu_poweroff_timer); -+ kbdev->pm.backend.poweroff_timer_running = false; -+ -+ /* Power off the GPU */ -+ kbase_pm_do_poweroff(kbdev, false); -+ } -+ -+ mutex_unlock(&kbdev->pm.lock); -+} -+ -+int kbase_pm_policy_init(struct kbase_device *kbdev) -+{ -+ struct workqueue_struct *wq; -+ -+ wq = alloc_workqueue("kbase_pm_do_poweroff", -+ WQ_HIGHPRI | WQ_UNBOUND, 1); -+ if (!wq) -+ return -ENOMEM; -+ -+ kbdev->pm.backend.gpu_poweroff_wq = wq; -+ INIT_WORK(&kbdev->pm.backend.gpu_poweroff_work, -+ kbasep_pm_do_gpu_poweroff_wq); -+ hrtimer_init(&kbdev->pm.backend.gpu_poweroff_timer, -+ CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ kbdev->pm.backend.gpu_poweroff_timer.function = -+ kbasep_pm_do_gpu_poweroff_callback; -+ kbdev->pm.backend.pm_current_policy = policy_list[0]; -+ kbdev->pm.backend.pm_current_policy->init(kbdev); -+ kbdev->pm.gpu_poweroff_time = -+ HR_TIMER_DELAY_NSEC(DEFAULT_PM_GPU_POWEROFF_TICK_NS); -+ kbdev->pm.poweroff_shader_ticks = DEFAULT_PM_POWEROFF_TICK_SHADER; -+ kbdev->pm.poweroff_gpu_ticks = DEFAULT_PM_POWEROFF_TICK_GPU; -+ -+ return 0; -+} -+ -+void kbase_pm_policy_term(struct kbase_device *kbdev) -+{ -+ kbdev->pm.backend.pm_current_policy->term(kbdev); -+ destroy_workqueue(kbdev->pm.backend.gpu_poweroff_wq); -+} -+ -+void kbase_pm_cancel_deferred_poweroff(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ lockdep_assert_held(&kbdev->pm.lock); -+ -+ kbdev->pm.backend.poweroff_timer_needed = false; -+ hrtimer_cancel(&kbdev->pm.backend.gpu_poweroff_timer); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbdev->pm.backend.poweroff_timer_running = false; -+ -+ /* If wq is already running but is held off by pm.lock, make sure it has -+ * no effect */ -+ kbdev->pm.backend.gpu_poweroff_pending = 0; -+ -+ kbdev->pm.backend.shader_poweroff_pending = 0; -+ kbdev->pm.backend.tiler_poweroff_pending = 0; -+ kbdev->pm.backend.shader_poweroff_pending_time = 0; -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+void kbase_pm_update_active(struct kbase_device *kbdev) -+{ -+ struct kbase_pm_device_data *pm = &kbdev->pm; -+ struct kbase_pm_backend_data *backend = &pm->backend; -+ unsigned long flags; -+ bool active; -+ -+ lockdep_assert_held(&pm->lock); -+ -+ /* pm_current_policy will never be NULL while pm.lock is held */ -+ KBASE_DEBUG_ASSERT(backend->pm_current_policy); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ active = backend->pm_current_policy->get_core_active(kbdev); -+ -+ if (active) { -+ if (backend->gpu_poweroff_pending) { -+ /* Cancel any pending power off request */ -+ backend->gpu_poweroff_pending = 0; -+ -+ /* If a request was pending then the GPU was still -+ * powered, so no need to continue */ -+ if (!kbdev->poweroff_pending) { -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, -+ flags); -+ return; -+ } -+ } -+ -+ if (!backend->poweroff_timer_running && !backend->gpu_powered && -+ (pm->poweroff_gpu_ticks || -+ pm->poweroff_shader_ticks)) { -+ backend->poweroff_timer_needed = true; -+ backend->poweroff_timer_running = true; -+ hrtimer_start(&backend->gpu_poweroff_timer, -+ pm->gpu_poweroff_time, -+ HRTIMER_MODE_REL); -+ } -+ -+ /* Power on the GPU and any cores requested by the policy */ -+ if (pm->backend.poweroff_wait_in_progress) { -+ pm->backend.poweron_required = true; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ } else { -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ kbase_pm_do_poweron(kbdev, false); -+ } -+ } else { -+ /* It is an error for the power policy to power off the GPU -+ * when there are contexts active */ -+ KBASE_DEBUG_ASSERT(pm->active_count == 0); -+ -+ if (backend->shader_poweroff_pending || -+ backend->tiler_poweroff_pending) { -+ backend->shader_poweroff_pending = 0; -+ backend->tiler_poweroff_pending = 0; -+ backend->shader_poweroff_pending_time = 0; -+ } -+ -+ /* Request power off */ -+ if (pm->backend.gpu_powered) { -+ if (pm->poweroff_gpu_ticks) { -+ backend->gpu_poweroff_pending = -+ pm->poweroff_gpu_ticks; -+ backend->poweroff_timer_needed = true; -+ if (!backend->poweroff_timer_running) { -+ /* Start timer if not running (eg if -+ * power policy has been changed from -+ * always_on to something else). This -+ * will ensure the GPU is actually -+ * powered off */ -+ backend->poweroff_timer_running -+ = true; -+ hrtimer_start( -+ &backend->gpu_poweroff_timer, -+ pm->gpu_poweroff_time, -+ HRTIMER_MODE_REL); -+ } -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, -+ flags); -+ } else { -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, -+ flags); -+ -+ /* Power off the GPU immediately */ -+ kbase_pm_do_poweroff(kbdev, false); -+ } -+ } else { -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ } -+ } -+} -+ -+void kbase_pm_update_cores_state_nolock(struct kbase_device *kbdev) -+{ -+ u64 desired_bitmap; -+ u64 desired_tiler_bitmap; -+ bool cores_are_available; -+ bool do_poweroff = false; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (kbdev->pm.backend.pm_current_policy == NULL) -+ return; -+ if (kbdev->pm.backend.poweroff_wait_in_progress) -+ return; -+ -+ if (kbdev->protected_mode_transition && !kbdev->shader_needed_bitmap && -+ !kbdev->shader_inuse_bitmap && !kbdev->tiler_needed_cnt -+ && !kbdev->tiler_inuse_cnt) { -+ /* We are trying to change in/out of protected mode - force all -+ * cores off so that the L2 powers down */ -+ desired_bitmap = 0; -+ desired_tiler_bitmap = 0; -+ } else { -+ desired_bitmap = -+ kbdev->pm.backend.pm_current_policy->get_core_mask(kbdev); -+ desired_bitmap &= kbase_pm_ca_get_core_mask(kbdev); -+ -+ if (kbdev->tiler_needed_cnt > 0 || kbdev->tiler_inuse_cnt > 0) -+ desired_tiler_bitmap = 1; -+ else -+ desired_tiler_bitmap = 0; -+ -+ if (!kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_XAFFINITY)) { -+ /* Unless XAFFINITY is supported, enable core 0 if tiler -+ * required, regardless of core availability */ -+ if (kbdev->tiler_needed_cnt > 0 || -+ kbdev->tiler_inuse_cnt > 0) -+ desired_bitmap |= 1; -+ } -+ } -+ -+ if (kbdev->pm.backend.desired_shader_state != desired_bitmap) -+ KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_DESIRED, NULL, NULL, 0u, -+ (u32)desired_bitmap); -+ /* Are any cores being powered on? */ -+ if (~kbdev->pm.backend.desired_shader_state & desired_bitmap || -+ ~kbdev->pm.backend.desired_tiler_state & desired_tiler_bitmap || -+ kbdev->pm.backend.ca_in_transition) { -+ /* Check if we are powering off any cores before updating shader -+ * state */ -+ if (kbdev->pm.backend.desired_shader_state & ~desired_bitmap || -+ kbdev->pm.backend.desired_tiler_state & -+ ~desired_tiler_bitmap) { -+ /* Start timer to power off cores */ -+ kbdev->pm.backend.shader_poweroff_pending |= -+ (kbdev->pm.backend.desired_shader_state & -+ ~desired_bitmap); -+ kbdev->pm.backend.tiler_poweroff_pending |= -+ (kbdev->pm.backend.desired_tiler_state & -+ ~desired_tiler_bitmap); -+ -+ if (kbdev->pm.poweroff_shader_ticks && -+ !kbdev->protected_mode_transition) -+ kbdev->pm.backend.shader_poweroff_pending_time = -+ kbdev->pm.poweroff_shader_ticks; -+ else -+ do_poweroff = true; -+ } -+ -+ kbdev->pm.backend.desired_shader_state = desired_bitmap; -+ kbdev->pm.backend.desired_tiler_state = desired_tiler_bitmap; -+ -+ /* If any cores are being powered on, transition immediately */ -+ cores_are_available = kbase_pm_check_transitions_nolock(kbdev); -+ } else if (kbdev->pm.backend.desired_shader_state & ~desired_bitmap || -+ kbdev->pm.backend.desired_tiler_state & -+ ~desired_tiler_bitmap) { -+ /* Start timer to power off cores */ -+ kbdev->pm.backend.shader_poweroff_pending |= -+ (kbdev->pm.backend.desired_shader_state & -+ ~desired_bitmap); -+ kbdev->pm.backend.tiler_poweroff_pending |= -+ (kbdev->pm.backend.desired_tiler_state & -+ ~desired_tiler_bitmap); -+ if (kbdev->pm.poweroff_shader_ticks && -+ !kbdev->protected_mode_transition) -+ kbdev->pm.backend.shader_poweroff_pending_time = -+ kbdev->pm.poweroff_shader_ticks; -+ else -+ kbasep_pm_do_poweroff_cores(kbdev); -+ } else if (kbdev->pm.active_count == 0 && desired_bitmap != 0 && -+ desired_tiler_bitmap != 0 && -+ kbdev->pm.backend.poweroff_timer_needed) { -+ /* If power policy is keeping cores on despite there being no -+ * active contexts then disable poweroff timer as it isn't -+ * required. -+ * Only reset poweroff_timer_needed if we're not in the middle -+ * of the power off callback */ -+ kbdev->pm.backend.poweroff_timer_needed = false; -+ } -+ -+ /* Ensure timer does not power off wanted cores and make sure to power -+ * off unwanted cores */ -+ if (kbdev->pm.backend.shader_poweroff_pending || -+ kbdev->pm.backend.tiler_poweroff_pending) { -+ kbdev->pm.backend.shader_poweroff_pending &= -+ ~(kbdev->pm.backend.desired_shader_state & -+ desired_bitmap); -+ kbdev->pm.backend.tiler_poweroff_pending &= -+ ~(kbdev->pm.backend.desired_tiler_state & -+ desired_tiler_bitmap); -+ -+ if (!kbdev->pm.backend.shader_poweroff_pending && -+ !kbdev->pm.backend.tiler_poweroff_pending) -+ kbdev->pm.backend.shader_poweroff_pending_time = 0; -+ } -+ -+ /* Shader poweroff is deferred to the end of the function, to eliminate -+ * issues caused by the core availability policy recursing into this -+ * function */ -+ if (do_poweroff) -+ kbasep_pm_do_poweroff_cores(kbdev); -+ -+ /* Don't need 'cores_are_available', because we don't return anything */ -+ CSTD_UNUSED(cores_are_available); -+} -+ -+void kbase_pm_update_cores_state(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+int kbase_pm_list_policies(const struct kbase_pm_policy * const **list) -+{ -+ if (!list) -+ return POLICY_COUNT; -+ -+ *list = policy_list; -+ -+ return POLICY_COUNT; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_list_policies); -+ -+const struct kbase_pm_policy *kbase_pm_get_policy(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ return kbdev->pm.backend.pm_current_policy; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_get_policy); -+ -+void kbase_pm_set_policy(struct kbase_device *kbdev, -+ const struct kbase_pm_policy *new_policy) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ const struct kbase_pm_policy *old_policy; -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(new_policy != NULL); -+ -+ KBASE_TRACE_ADD(kbdev, PM_SET_POLICY, NULL, NULL, 0u, new_policy->id); -+ -+ /* During a policy change we pretend the GPU is active */ -+ /* A suspend won't happen here, because we're in a syscall from a -+ * userspace thread */ -+ kbase_pm_context_active(kbdev); -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ -+ /* Remove the policy to prevent IRQ handlers from working on it */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ old_policy = kbdev->pm.backend.pm_current_policy; -+ kbdev->pm.backend.pm_current_policy = NULL; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ KBASE_TRACE_ADD(kbdev, PM_CURRENT_POLICY_TERM, NULL, NULL, 0u, -+ old_policy->id); -+ if (old_policy->term) -+ old_policy->term(kbdev); -+ -+ KBASE_TRACE_ADD(kbdev, PM_CURRENT_POLICY_INIT, NULL, NULL, 0u, -+ new_policy->id); -+ if (new_policy->init) -+ new_policy->init(kbdev); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbdev->pm.backend.pm_current_policy = new_policy; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ /* If any core power state changes were previously attempted, but -+ * couldn't be made because the policy was changing (current_policy was -+ * NULL), then re-try them here. */ -+ kbase_pm_update_active(kbdev); -+ kbase_pm_update_cores_state(kbdev); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ /* Now the policy change is finished, we release our fake context active -+ * reference */ -+ kbase_pm_context_idle(kbdev); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_set_policy); -+ -+/* Check whether a state change has finished, and trace it as completed */ -+static void -+kbase_pm_trace_check_and_finish_state_change(struct kbase_device *kbdev) -+{ -+ if ((kbdev->shader_available_bitmap & -+ kbdev->pm.backend.desired_shader_state) -+ == kbdev->pm.backend.desired_shader_state && -+ (kbdev->tiler_available_bitmap & -+ kbdev->pm.backend.desired_tiler_state) -+ == kbdev->pm.backend.desired_tiler_state) -+ kbase_timeline_pm_check_handle_event(kbdev, -+ KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED); -+} -+ -+void kbase_pm_request_cores(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores) -+{ -+ u64 cores; -+ -+ kbase_pm_change_state change_gpu_state = 0u; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ cores = shader_cores; -+ while (cores) { -+ int bitnum = fls64(cores) - 1; -+ u64 bit = 1ULL << bitnum; -+ -+ /* It should be almost impossible for this to overflow. It would -+ * require 2^32 atoms to request a particular core, which would -+ * require 2^24 contexts to submit. This would require an amount -+ * of memory that is impossible on a 32-bit system and extremely -+ * unlikely on a 64-bit system. */ -+ int cnt = ++kbdev->shader_needed_cnt[bitnum]; -+ -+ if (1 == cnt) { -+ kbdev->shader_needed_bitmap |= bit; -+ change_gpu_state |= KBASE_PM_CHANGE_STATE_SHADER; -+ } -+ -+ cores &= ~bit; -+ } -+ -+ if (tiler_required) { -+ int cnt = ++kbdev->tiler_needed_cnt; -+ -+ if (1 == cnt) -+ change_gpu_state |= KBASE_PM_CHANGE_STATE_TILER; -+ -+ KBASE_DEBUG_ASSERT(kbdev->tiler_needed_cnt != 0); -+ } -+ -+ if (change_gpu_state) { -+ KBASE_TRACE_ADD(kbdev, PM_REQUEST_CHANGE_SHADER_NEEDED, NULL, -+ NULL, 0u, (u32) kbdev->shader_needed_bitmap); -+ -+ kbase_timeline_pm_cores_func(kbdev, -+ KBASE_PM_FUNC_ID_REQUEST_CORES_START, -+ change_gpu_state); -+ kbase_pm_update_cores_state_nolock(kbdev); -+ kbase_timeline_pm_cores_func(kbdev, -+ KBASE_PM_FUNC_ID_REQUEST_CORES_END, -+ change_gpu_state); -+ } -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_request_cores); -+ -+void kbase_pm_unrequest_cores(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores) -+{ -+ kbase_pm_change_state change_gpu_state = 0u; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ while (shader_cores) { -+ int bitnum = fls64(shader_cores) - 1; -+ u64 bit = 1ULL << bitnum; -+ int cnt; -+ -+ KBASE_DEBUG_ASSERT(kbdev->shader_needed_cnt[bitnum] > 0); -+ -+ cnt = --kbdev->shader_needed_cnt[bitnum]; -+ -+ if (0 == cnt) { -+ kbdev->shader_needed_bitmap &= ~bit; -+ -+ change_gpu_state |= KBASE_PM_CHANGE_STATE_SHADER; -+ } -+ -+ shader_cores &= ~bit; -+ } -+ -+ if (tiler_required) { -+ int cnt; -+ -+ KBASE_DEBUG_ASSERT(kbdev->tiler_needed_cnt > 0); -+ -+ cnt = --kbdev->tiler_needed_cnt; -+ -+ if (0 == cnt) -+ change_gpu_state |= KBASE_PM_CHANGE_STATE_TILER; -+ } -+ -+ if (change_gpu_state) { -+ KBASE_TRACE_ADD(kbdev, PM_UNREQUEST_CHANGE_SHADER_NEEDED, NULL, -+ NULL, 0u, (u32) kbdev->shader_needed_bitmap); -+ -+ kbase_pm_update_cores_state_nolock(kbdev); -+ -+ /* Trace that any state change effectively completes immediately -+ * - no-one will wait on the state change */ -+ kbase_pm_trace_check_and_finish_state_change(kbdev); -+ } -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_unrequest_cores); -+ -+enum kbase_pm_cores_ready -+kbase_pm_register_inuse_cores(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores) -+{ -+ u64 prev_shader_needed; /* Just for tracing */ -+ u64 prev_shader_inuse; /* Just for tracing */ -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ prev_shader_needed = kbdev->shader_needed_bitmap; -+ prev_shader_inuse = kbdev->shader_inuse_bitmap; -+ -+ /* If desired_shader_state does not contain the requested cores, then -+ * power management is not attempting to powering those cores (most -+ * likely due to core availability policy) and a new job affinity must -+ * be chosen */ -+ if ((kbdev->pm.backend.desired_shader_state & shader_cores) != -+ shader_cores) { -+ return (kbdev->pm.backend.poweroff_wait_in_progress || -+ kbdev->pm.backend.pm_current_policy == NULL) ? -+ KBASE_CORES_NOT_READY : KBASE_NEW_AFFINITY; -+ } -+ -+ if ((kbdev->shader_available_bitmap & shader_cores) != shader_cores || -+ (tiler_required && !kbdev->tiler_available_bitmap)) { -+ /* Trace ongoing core transition */ -+ kbase_timeline_pm_l2_transition_start(kbdev); -+ return KBASE_CORES_NOT_READY; -+ } -+ -+ /* If we started to trace a state change, then trace it has being -+ * finished by now, at the very latest */ -+ kbase_pm_trace_check_and_finish_state_change(kbdev); -+ /* Trace core transition done */ -+ kbase_timeline_pm_l2_transition_done(kbdev); -+ -+ while (shader_cores) { -+ int bitnum = fls64(shader_cores) - 1; -+ u64 bit = 1ULL << bitnum; -+ int cnt; -+ -+ KBASE_DEBUG_ASSERT(kbdev->shader_needed_cnt[bitnum] > 0); -+ -+ cnt = --kbdev->shader_needed_cnt[bitnum]; -+ -+ if (0 == cnt) -+ kbdev->shader_needed_bitmap &= ~bit; -+ -+ /* shader_inuse_cnt should not overflow because there can only -+ * be a very limited number of jobs on the h/w at one time */ -+ -+ kbdev->shader_inuse_cnt[bitnum]++; -+ kbdev->shader_inuse_bitmap |= bit; -+ -+ shader_cores &= ~bit; -+ } -+ -+ if (tiler_required) { -+ KBASE_DEBUG_ASSERT(kbdev->tiler_needed_cnt > 0); -+ -+ --kbdev->tiler_needed_cnt; -+ -+ kbdev->tiler_inuse_cnt++; -+ -+ KBASE_DEBUG_ASSERT(kbdev->tiler_inuse_cnt != 0); -+ } -+ -+ if (prev_shader_needed != kbdev->shader_needed_bitmap) -+ KBASE_TRACE_ADD(kbdev, PM_REGISTER_CHANGE_SHADER_NEEDED, NULL, -+ NULL, 0u, (u32) kbdev->shader_needed_bitmap); -+ -+ if (prev_shader_inuse != kbdev->shader_inuse_bitmap) -+ KBASE_TRACE_ADD(kbdev, PM_REGISTER_CHANGE_SHADER_INUSE, NULL, -+ NULL, 0u, (u32) kbdev->shader_inuse_bitmap); -+ -+ return KBASE_CORES_READY; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_register_inuse_cores); -+ -+void kbase_pm_release_cores(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores) -+{ -+ kbase_pm_change_state change_gpu_state = 0u; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ while (shader_cores) { -+ int bitnum = fls64(shader_cores) - 1; -+ u64 bit = 1ULL << bitnum; -+ int cnt; -+ -+ KBASE_DEBUG_ASSERT(kbdev->shader_inuse_cnt[bitnum] > 0); -+ -+ cnt = --kbdev->shader_inuse_cnt[bitnum]; -+ -+ if (0 == cnt) { -+ kbdev->shader_inuse_bitmap &= ~bit; -+ change_gpu_state |= KBASE_PM_CHANGE_STATE_SHADER; -+ } -+ -+ shader_cores &= ~bit; -+ } -+ -+ if (tiler_required) { -+ int cnt; -+ -+ KBASE_DEBUG_ASSERT(kbdev->tiler_inuse_cnt > 0); -+ -+ cnt = --kbdev->tiler_inuse_cnt; -+ -+ if (0 == cnt) -+ change_gpu_state |= KBASE_PM_CHANGE_STATE_TILER; -+ } -+ -+ if (change_gpu_state) { -+ KBASE_TRACE_ADD(kbdev, PM_RELEASE_CHANGE_SHADER_INUSE, NULL, -+ NULL, 0u, (u32) kbdev->shader_inuse_bitmap); -+ -+ kbase_timeline_pm_cores_func(kbdev, -+ KBASE_PM_FUNC_ID_RELEASE_CORES_START, -+ change_gpu_state); -+ kbase_pm_update_cores_state_nolock(kbdev); -+ kbase_timeline_pm_cores_func(kbdev, -+ KBASE_PM_FUNC_ID_RELEASE_CORES_END, -+ change_gpu_state); -+ -+ /* Trace that any state change completed immediately */ -+ kbase_pm_trace_check_and_finish_state_change(kbdev); -+ } -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_release_cores); -+ -+void kbase_pm_request_cores_sync(struct kbase_device *kbdev, -+ bool tiler_required, -+ u64 shader_cores) -+{ -+ unsigned long flags; -+ -+ kbase_pm_wait_for_poweroff_complete(kbdev); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_pm_request_cores(kbdev, tiler_required, shader_cores); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ kbase_pm_check_transitions_sync(kbdev); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_request_cores_sync); -+ -+void kbase_pm_request_l2_caches(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ u32 prior_l2_users_count; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ prior_l2_users_count = kbdev->l2_users_count++; -+ -+ KBASE_DEBUG_ASSERT(kbdev->l2_users_count != 0); -+ -+ /* if the GPU is reset while the l2 is on, l2 will be off but -+ * prior_l2_users_count will be > 0. l2_available_bitmap will have been -+ * set to 0 though by kbase_pm_init_hw */ -+ if (!prior_l2_users_count || !kbdev->l2_available_bitmap) -+ kbase_pm_check_transitions_nolock(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ wait_event(kbdev->pm.backend.l2_powered_wait, -+ kbdev->pm.backend.l2_powered == 1); -+ -+ /* Trace that any state change completed immediately */ -+ kbase_pm_trace_check_and_finish_state_change(kbdev); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_request_l2_caches); -+ -+void kbase_pm_request_l2_caches_l2_is_on(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ kbdev->l2_users_count++; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_request_l2_caches_l2_is_on); -+ -+void kbase_pm_release_l2_caches(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ KBASE_DEBUG_ASSERT(kbdev->l2_users_count > 0); -+ -+ --kbdev->l2_users_count; -+ -+ if (!kbdev->l2_users_count) { -+ kbase_pm_check_transitions_nolock(kbdev); -+ /* Trace that any state change completed immediately */ -+ kbase_pm_trace_check_and_finish_state_change(kbdev); -+ } -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_release_l2_caches); -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_policy.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_policy.h -new file mode 100644 -index 0000000..611a90e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_pm_policy.h -@@ -0,0 +1,227 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Power policy API definitions -+ */ -+ -+#ifndef _KBASE_PM_POLICY_H_ -+#define _KBASE_PM_POLICY_H_ -+ -+/** -+ * kbase_pm_policy_init - Initialize power policy framework -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Must be called before calling any other policy function -+ * -+ * Return: 0 if the power policy framework was successfully -+ * initialized, -errno otherwise. -+ */ -+int kbase_pm_policy_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_policy_term - Terminate power policy framework -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_policy_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_update_active - Update the active power state of the GPU -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Calls into the current power policy -+ */ -+void kbase_pm_update_active(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_update_cores - Update the desired core state of the GPU -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Calls into the current power policy -+ */ -+void kbase_pm_update_cores(struct kbase_device *kbdev); -+ -+ -+enum kbase_pm_cores_ready { -+ KBASE_CORES_NOT_READY = 0, -+ KBASE_NEW_AFFINITY = 1, -+ KBASE_CORES_READY = 2 -+}; -+ -+ -+/** -+ * kbase_pm_request_cores_sync - Synchronous variant of kbase_pm_request_cores() -+ * -+ * @kbdev: The kbase device structure for the device -+ * @tiler_required: true if the tiler is required, false otherwise -+ * @shader_cores: A bitmask of shader cores which are necessary for the job -+ * -+ * When this function returns, the @shader_cores will be in the READY state. -+ * -+ * This is safe variant of kbase_pm_check_transitions_sync(): it handles the -+ * work of ensuring the requested cores will remain powered until a matching -+ * call to kbase_pm_unrequest_cores()/kbase_pm_release_cores() (as appropriate) -+ * is made. -+ */ -+void kbase_pm_request_cores_sync(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores); -+ -+/** -+ * kbase_pm_request_cores - Mark one or more cores as being required -+ * for jobs to be submitted -+ * -+ * @kbdev: The kbase device structure for the device -+ * @tiler_required: true if the tiler is required, false otherwise -+ * @shader_cores: A bitmask of shader cores which are necessary for the job -+ * -+ * This function is called by the job scheduler to mark one or more cores as -+ * being required to submit jobs that are ready to run. -+ * -+ * The cores requested are reference counted and a subsequent call to -+ * kbase_pm_register_inuse_cores() or kbase_pm_unrequest_cores() should be -+ * made to dereference the cores as being 'needed'. -+ * -+ * The active power policy will meet or exceed the requirements of the -+ * requested cores in the system. Any core transitions needed will be begun -+ * immediately, but they might not complete/the cores might not be available -+ * until a Power Management IRQ. -+ * -+ * Return: 0 if the cores were successfully requested, or -errno otherwise. -+ */ -+void kbase_pm_request_cores(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores); -+ -+/** -+ * kbase_pm_unrequest_cores - Unmark one or more cores as being required for -+ * jobs to be submitted. -+ * -+ * @kbdev: The kbase device structure for the device -+ * @tiler_required: true if the tiler is required, false otherwise -+ * @shader_cores: A bitmask of shader cores (as given to -+ * kbase_pm_request_cores() ) -+ * -+ * This function undoes the effect of kbase_pm_request_cores(). It should be -+ * used when a job is not going to be submitted to the hardware (e.g. the job is -+ * cancelled before it is enqueued). -+ * -+ * The active power policy will meet or exceed the requirements of the -+ * requested cores in the system. Any core transitions needed will be begun -+ * immediately, but they might not complete until a Power Management IRQ. -+ * -+ * The policy may use this as an indication that it can power down cores. -+ */ -+void kbase_pm_unrequest_cores(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores); -+ -+/** -+ * kbase_pm_register_inuse_cores - Register a set of cores as in use by a job -+ * -+ * @kbdev: The kbase device structure for the device -+ * @tiler_required: true if the tiler is required, false otherwise -+ * @shader_cores: A bitmask of shader cores (as given to -+ * kbase_pm_request_cores() ) -+ * -+ * This function should be called after kbase_pm_request_cores() when the job -+ * is about to be submitted to the hardware. It will check that the necessary -+ * cores are available and if so update the 'needed' and 'inuse' bitmasks to -+ * reflect that the job is now committed to being run. -+ * -+ * If the necessary cores are not currently available then the function will -+ * return %KBASE_CORES_NOT_READY and have no effect. -+ * -+ * Return: %KBASE_CORES_NOT_READY if the cores are not immediately ready, -+ * -+ * %KBASE_NEW_AFFINITY if the affinity requested is not allowed, -+ * -+ * %KBASE_CORES_READY if the cores requested are already available -+ */ -+enum kbase_pm_cores_ready kbase_pm_register_inuse_cores( -+ struct kbase_device *kbdev, -+ bool tiler_required, -+ u64 shader_cores); -+ -+/** -+ * kbase_pm_release_cores - Release cores after a job has run -+ * -+ * @kbdev: The kbase device structure for the device -+ * @tiler_required: true if the tiler is required, false otherwise -+ * @shader_cores: A bitmask of shader cores (as given to -+ * kbase_pm_register_inuse_cores() ) -+ * -+ * This function should be called when a job has finished running on the -+ * hardware. A call to kbase_pm_register_inuse_cores() must have previously -+ * occurred. The reference counts of the specified cores will be decremented -+ * which may cause the bitmask of 'inuse' cores to be reduced. The power policy -+ * may then turn off any cores which are no longer 'inuse'. -+ */ -+void kbase_pm_release_cores(struct kbase_device *kbdev, -+ bool tiler_required, u64 shader_cores); -+ -+/** -+ * kbase_pm_request_l2_caches - Request l2 caches -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Request the use of l2 caches for all core groups, power up, wait and prevent -+ * the power manager from powering down the l2 caches. -+ * -+ * This tells the power management that the caches should be powered up, and -+ * they should remain powered, irrespective of the usage of shader cores. This -+ * does not return until the l2 caches are powered up. -+ * -+ * The caller must call kbase_pm_release_l2_caches() when they are finished -+ * to allow normal power management of the l2 caches to resume. -+ * -+ * This should only be used when power management is active. -+ */ -+void kbase_pm_request_l2_caches(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_request_l2_caches_l2_is_on - Request l2 caches but don't power on -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Increment the count of l2 users but do not attempt to power on the l2 -+ * -+ * It is the callers responsibility to ensure that the l2 is already powered up -+ * and to eventually call kbase_pm_release_l2_caches() -+ */ -+void kbase_pm_request_l2_caches_l2_is_on(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_request_l2_caches - Release l2 caches -+ * -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * -+ * Release the use of l2 caches for all core groups and allow the power manager -+ * to power them down when necessary. -+ * -+ * This tells the power management that the caches can be powered down if -+ * necessary, with respect to the usage of shader cores. -+ * -+ * The caller must have called kbase_pm_request_l2_caches() prior to a call -+ * to this. -+ * -+ * This should only be used when power management is active. -+ */ -+void kbase_pm_release_l2_caches(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_PM_POLICY_H_ */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_time.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_time.c -new file mode 100644 -index 0000000..d992989 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_time.c -@@ -0,0 +1,103 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+ -+void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter, -+ u64 *system_time, struct timespec *ts) -+{ -+ u32 hi1, hi2; -+ -+ kbase_pm_request_gpu_cycle_counter(kbdev); -+ -+ /* Read hi, lo, hi to ensure that overflow from lo to hi is handled -+ * correctly */ -+ do { -+ hi1 = kbase_reg_read(kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), -+ NULL); -+ *cycle_counter = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL); -+ hi2 = kbase_reg_read(kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), -+ NULL); -+ *cycle_counter |= (((u64) hi1) << 32); -+ } while (hi1 != hi2); -+ -+ /* Read hi, lo, hi to ensure that overflow from lo to hi is handled -+ * correctly */ -+ do { -+ hi1 = kbase_reg_read(kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), -+ NULL); -+ *system_time = kbase_reg_read(kbdev, -+ GPU_CONTROL_REG(TIMESTAMP_LO), NULL); -+ hi2 = kbase_reg_read(kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), -+ NULL); -+ *system_time |= (((u64) hi1) << 32); -+ } while (hi1 != hi2); -+ -+ /* Record the CPU's idea of current time */ -+ getrawmonotonic(ts); -+ -+ kbase_pm_release_gpu_cycle_counter(kbdev); -+} -+ -+/** -+ * kbase_wait_write_flush - Wait for GPU write flush -+ * @kctx: Context pointer -+ * -+ * Wait 1000 GPU clock cycles. This delay is known to give the GPU time to flush -+ * its write buffer. -+ * -+ * Only in use for BASE_HW_ISSUE_6367 -+ * -+ * Note : If GPU resets occur then the counters are reset to zero, the delay may -+ * not be as expected. -+ */ -+#ifndef CONFIG_MALI_NO_MALI -+void kbase_wait_write_flush(struct kbase_context *kctx) -+{ -+ u32 base_count = 0; -+ -+ /* -+ * The caller must be holding onto the kctx or the call is from -+ * userspace. -+ */ -+ kbase_pm_context_active(kctx->kbdev); -+ kbase_pm_request_gpu_cycle_counter(kctx->kbdev); -+ -+ while (true) { -+ u32 new_count; -+ -+ new_count = kbase_reg_read(kctx->kbdev, -+ GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL); -+ /* First time around, just store the count. */ -+ if (base_count == 0) { -+ base_count = new_count; -+ continue; -+ } -+ -+ /* No need to handle wrapping, unsigned maths works for this. */ -+ if ((new_count - base_count) > 1000) -+ break; -+ } -+ -+ kbase_pm_release_gpu_cycle_counter(kctx->kbdev); -+ kbase_pm_context_idle(kctx->kbdev); -+} -+#endif /* CONFIG_MALI_NO_MALI */ -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_time.h b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_time.h -new file mode 100644 -index 0000000..35088ab ---- /dev/null -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_time.h -@@ -0,0 +1,52 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_BACKEND_TIME_H_ -+#define _KBASE_BACKEND_TIME_H_ -+ -+/** -+ * kbase_backend_get_gpu_time() - Get current GPU time -+ * @kbdev: Device pointer -+ * @cycle_counter: Pointer to u64 to store cycle counter in -+ * @system_time: Pointer to u64 to store system time in -+ * @ts: Pointer to struct timespec to store current monotonic -+ * time in -+ */ -+void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter, -+ u64 *system_time, struct timespec *ts); -+ -+/** -+ * kbase_wait_write_flush() - Wait for GPU write flush -+ * @kctx: Context pointer -+ * -+ * Wait 1000 GPU clock cycles. This delay is known to give the GPU time to flush -+ * its write buffer. -+ * -+ * If GPU resets occur then the counters are reset to zero, the delay may not be -+ * as expected. -+ * -+ * This function is only in use for BASE_HW_ISSUE_6367 -+ */ -+#ifdef CONFIG_MALI_NO_MALI -+static inline void kbase_wait_write_flush(struct kbase_context *kctx) -+{ -+} -+#else -+void kbase_wait_write_flush(struct kbase_context *kctx); -+#endif -+ -+#endif /* _KBASE_BACKEND_TIME_H_ */ -diff --git a/drivers/gpu/arm/midgard/docs/Doxyfile b/drivers/gpu/arm/midgard/docs/Doxyfile -new file mode 100644 -index 0000000..35ff2f1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/docs/Doxyfile -@@ -0,0 +1,126 @@ -+# -+# (C) COPYRIGHT 2011-2013, 2015 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+############################################################################## -+ -+# This file contains per-module Doxygen configuration. Please do not add -+# extra settings to this file without consulting all stakeholders, as they -+# may cause override project-wide settings. -+# -+# Additionally, when defining aliases, macros, sections etc, use the module -+# name as a prefix e.g. gles_my_alias. -+ -+############################################################################## -+ -+@INCLUDE = ../../bldsys/Doxyfile_common -+ -+# The INPUT tag can be used to specify the files and/or directories that contain -+# documented source files. You may enter file names like "myfile.cpp" or -+# directories like "/usr/src/myproject". Separate the files or directories -+# with spaces. -+ -+INPUT += ../../kernel/drivers/gpu/arm/midgard/ -+ -+############################################################################## -+# Everything below here is optional, and in most cases not required -+############################################################################## -+ -+# This tag can be used to specify a number of aliases that acts -+# as commands in the documentation. An alias has the form "name=value". -+# For example adding "sideeffect=\par Side Effects:\n" will allow you to -+# put the command \sideeffect (or @sideeffect) in the documentation, which -+# will result in a user-defined paragraph with heading "Side Effects:". -+# You can put \n's in the value part of an alias to insert newlines. -+ -+ALIASES += -+ -+# The ENABLED_SECTIONS tag can be used to enable conditional -+# documentation sections, marked by \if sectionname ... \endif. -+ -+ENABLED_SECTIONS += -+ -+# If the value of the INPUT tag contains directories, you can use the -+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -+# and *.h) to filter out the source-files in the directories. If left -+# blank the following patterns are tested: -+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 -+ -+FILE_PATTERNS += -+ -+# The EXCLUDE tag can be used to specify files and/or directories that should -+# excluded from the INPUT source files. This way you can easily exclude a -+# subdirectory from a directory tree whose root is specified with the INPUT tag. -+EXCLUDE += ../../kernel/drivers/gpu/arm/midgard/platform ../../kernel/drivers/gpu/arm/midgard/platform_dummy ../../kernel/drivers/gpu/arm/midgard/scripts ../../kernel/drivers/gpu/arm/midgard/tests ../../kernel/drivers/gpu/arm/midgard/Makefile ../../kernel/drivers/gpu/arm/midgard/Makefile.kbase ../../kernel/drivers/gpu/arm/midgard/Kbuild ../../kernel/drivers/gpu/arm/midgard/Kconfig ../../kernel/drivers/gpu/arm/midgard/sconscript ../../kernel/drivers/gpu/arm/midgard/docs ../../kernel/drivers/gpu/arm/midgard/pm_test_script.sh ../../kernel/drivers/gpu/arm/midgard/mali_uk.h ../../kernel/drivers/gpu/arm/midgard/Makefile -+ -+ -+# If the value of the INPUT tag contains directories, you can use the -+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -+# certain files from those directories. Note that the wildcards are matched -+# against the file with absolute path, so to exclude all test directories -+# for example use the pattern */test/* -+ -+EXCLUDE_PATTERNS += -+ -+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -+# (namespaces, classes, functions, etc.) that should be excluded from the -+# output. The symbol name can be a fully qualified name, a word, or if the -+# wildcard * is used, a substring. Examples: ANamespace, AClass, -+# AClass::ANamespace, ANamespace::*Test -+ -+EXCLUDE_SYMBOLS += -+ -+# The EXAMPLE_PATH tag can be used to specify one or more files or -+# directories that contain example code fragments that are included (see -+# the \include command). -+ -+EXAMPLE_PATH += -+ -+# The IMAGE_PATH tag can be used to specify one or more files or -+# directories that contain image that are included in the documentation (see -+# the \image command). -+ -+IMAGE_PATH += -+ -+# The INCLUDE_PATH tag can be used to specify one or more directories that -+# contain include files that are not input files but should be processed by -+# the preprocessor. -+ -+INCLUDE_PATH += -+ -+# The PREDEFINED tag can be used to specify one or more macro names that -+# are defined before the preprocessor is started (similar to the -D option of -+# gcc). The argument of the tag is a list of macros of the form: name -+# or name=definition (no spaces). If the definition and the = are -+# omitted =1 is assumed. To prevent a macro definition from being -+# undefined via #undef or recursively expanded use the := operator -+# instead of the = operator. -+ -+PREDEFINED += -+ -+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -+# this tag can be used to specify a list of macro names that should be expanded. -+# The macro definition that is found in the sources will be used. -+# Use the PREDEFINED tag if you want to use a different macro definition. -+ -+EXPAND_AS_DEFINED += -+ -+# The DOTFILE_DIRS tag can be used to specify one or more directories that -+# contain dot files that are included in the documentation (see the -+# \dotfile command). -+ -+DOTFILE_DIRS += ../../kernel/drivers/gpu/arm/midgard/docs -+ -diff --git a/drivers/gpu/arm/midgard/docs/policy_operation_diagram.dot b/drivers/gpu/arm/midgard/docs/policy_operation_diagram.dot -new file mode 100644 -index 0000000..7ae05c2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/docs/policy_operation_diagram.dot -@@ -0,0 +1,112 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+digraph policy_objects_diagram { -+ rankdir=LR; -+ size="12,8"; -+ compound=true; -+ -+ node [ shape = box ]; -+ -+ subgraph cluster_policy_queues { -+ low_queue [ shape=record label = "LowP | {ctx_lo | ... | ctx_i | ... | ctx_hi}" ]; -+ queues_middle_sep [ label="" shape=plaintext width=0 height=0 ]; -+ -+ rt_queue [ shape=record label = "RT | {ctx_lo | ... | ctx_j | ... | ctx_hi}" ]; -+ -+ label = "Policy's Queue(s)"; -+ } -+ -+ call_enqueue [ shape=plaintext label="enqueue_ctx()" ]; -+ -+ { -+ rank=same; -+ ordering=out; -+ call_dequeue [ shape=plaintext label="dequeue_head_ctx()\n+ runpool_add_ctx()" ]; -+ call_ctxfinish [ shape=plaintext label="runpool_remove_ctx()" ]; -+ -+ call_ctxdone [ shape=plaintext label="don't requeue;\n/* ctx has no more jobs */" ]; -+ } -+ -+ subgraph cluster_runpool { -+ -+ as0 [ width=2 height = 0.25 label="AS0: Job_1, ..., Job_n" ]; -+ as1 [ width=2 height = 0.25 label="AS1: Job_1, ..., Job_m" ]; -+ as2 [ width=2 height = 0.25 label="AS2: Job_1, ..., Job_p" ]; -+ as3 [ width=2 height = 0.25 label="AS3: Job_1, ..., Job_q" ]; -+ -+ label = "Policy's Run Pool"; -+ } -+ -+ { -+ rank=same; -+ call_jdequeue [ shape=plaintext label="dequeue_job()" ]; -+ sstop_dotfixup [ shape=plaintext label="" width=0 height=0 ]; -+ } -+ -+ { -+ rank=same; -+ ordering=out; -+ sstop [ shape=ellipse label="SS-Timer expires" ] -+ jobslots [ shape=record label="Jobslots: | <0>js[0] | <1>js[1] | <2>js[2]" ]; -+ -+ irq [ label="IRQ" shape=ellipse ]; -+ -+ job_finish [ shape=plaintext label="don't requeue;\n/* job done */" ]; -+ } -+ -+ hstop [ shape=ellipse label="HS-Timer expires" ] -+ -+ /* -+ * Edges -+ */ -+ -+ call_enqueue -> queues_middle_sep [ lhead=cluster_policy_queues ]; -+ -+ low_queue:qr -> call_dequeue:w; -+ rt_queue:qr -> call_dequeue:w; -+ -+ call_dequeue -> as1 [lhead=cluster_runpool]; -+ -+ as1->call_jdequeue [ltail=cluster_runpool]; -+ call_jdequeue->jobslots:0; -+ call_jdequeue->sstop_dotfixup [ arrowhead=none]; -+ sstop_dotfixup->sstop [label="Spawn SS-Timer"]; -+ sstop->jobslots [label="SoftStop"]; -+ sstop->hstop [label="Spawn HS-Timer"]; -+ hstop->jobslots:ne [label="HardStop"]; -+ -+ -+ as3->call_ctxfinish:ne [ ltail=cluster_runpool ]; -+ call_ctxfinish:sw->rt_queue:qm [ lhead=cluster_policy_queues label="enqueue_ctx()\n/* ctx still has jobs */" ]; -+ -+ call_ctxfinish->call_ctxdone [constraint=false]; -+ -+ call_ctxdone->call_enqueue [weight=0.1 labeldistance=20.0 labelangle=0.0 taillabel="Job submitted to the ctx" style=dotted constraint=false]; -+ -+ -+ { -+ jobslots->irq [constraint=false]; -+ -+ irq->job_finish [constraint=false]; -+ } -+ -+ irq->as2 [lhead=cluster_runpool label="requeue_job()\n/* timeslice expired */" ]; -+ -+} -diff --git a/drivers/gpu/arm/midgard/docs/policy_overview.dot b/drivers/gpu/arm/midgard/docs/policy_overview.dot -new file mode 100644 -index 0000000..159b993 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/docs/policy_overview.dot -@@ -0,0 +1,63 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+digraph policy_objects_diagram { -+ rankdir=LR -+ size="6,6" -+ compound=true; -+ -+ node [ shape = box ]; -+ -+ call_enqueue [ shape=plaintext label="enqueue ctx" ]; -+ -+ -+ policy_queue [ label="Policy's Queue" ]; -+ -+ { -+ rank=same; -+ runpool [ label="Policy's Run Pool" ]; -+ -+ ctx_finish [ label="ctx finished" ]; -+ } -+ -+ { -+ rank=same; -+ jobslots [ shape=record label="Jobslots: | <0>js[0] | <1>js[1] | <2>js[2]" ]; -+ -+ job_finish [ label="Job finished" ]; -+ } -+ -+ -+ -+ /* -+ * Edges -+ */ -+ -+ call_enqueue -> policy_queue; -+ -+ policy_queue->runpool [label="dequeue ctx" weight=0.1]; -+ runpool->policy_queue [label="requeue ctx" weight=0.1]; -+ -+ runpool->ctx_finish [ style=dotted ]; -+ -+ runpool->jobslots [label="dequeue job" weight=0.1]; -+ jobslots->runpool [label="requeue job" weight=0.1]; -+ -+ jobslots->job_finish [ style=dotted ]; -+} -diff --git a/drivers/gpu/arm/midgard/ipa/Kbuild b/drivers/gpu/arm/midgard/ipa/Kbuild -new file mode 100644 -index 0000000..8e37f40 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/Kbuild -@@ -0,0 +1,27 @@ -+# -+# (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+mali_kbase-y += \ -+ ipa/mali_kbase_ipa_simple.o \ -+ ipa/mali_kbase_ipa.o -+ -+mali_kbase-$(CONFIG_DEBUG_FS) += ipa/mali_kbase_ipa_debugfs.o -+ -+ifneq ($(wildcard $(src)/ipa/mali_kbase_ipa_vinstr_g71.c),) -+ mali_kbase-y += \ -+ ipa/mali_kbase_ipa_vinstr_g71.o \ -+ ipa/mali_kbase_ipa_vinstr_common.o -+ -+endif -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa.c b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa.c -new file mode 100644 -index 0000000..4319893 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa.c -@@ -0,0 +1,584 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+#include -+#include -+#include -+#include "mali_kbase.h" -+#include "mali_kbase_ipa.h" -+#include "mali_kbase_ipa_debugfs.h" -+#include "mali_kbase_ipa_simple.h" -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -+#include -+#else -+#include -+#define dev_pm_opp_find_freq_exact opp_find_freq_exact -+#define dev_pm_opp_get_voltage opp_get_voltage -+#define dev_pm_opp opp -+#endif -+ -+#define KBASE_IPA_FALLBACK_MODEL_NAME "mali-simple-power-model" -+#define KBASE_IPA_G71_MODEL_NAME "mali-g71-power-model" -+ -+static struct kbase_ipa_model_ops *kbase_ipa_all_model_ops[] = { -+ &kbase_simple_ipa_model_ops, -+ &kbase_g71_ipa_model_ops -+}; -+ -+int kbase_ipa_model_recalculate(struct kbase_ipa_model *model) -+{ -+ int err = 0; -+ -+ lockdep_assert_held(&model->kbdev->ipa.lock); -+ -+ if (model->ops->recalculate) { -+ err = model->ops->recalculate(model); -+ if (err) { -+ dev_err(model->kbdev->dev, -+ "recalculation of power model %s returned error %d\n", -+ model->ops->name, err); -+ } -+ } -+ -+ return err; -+} -+ -+static struct kbase_ipa_model_ops *kbase_ipa_model_ops_find(struct kbase_device *kbdev, -+ const char *name) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(kbase_ipa_all_model_ops); ++i) { -+ struct kbase_ipa_model_ops *ops = kbase_ipa_all_model_ops[i]; -+ -+ if (!strcmp(ops->name, name)) -+ return ops; -+ } -+ -+ dev_err(kbdev->dev, "power model \'%s\' not found\n", name); -+ -+ return NULL; -+} -+ -+void kbase_ipa_model_use_fallback_locked(struct kbase_device *kbdev) -+{ -+ atomic_set(&kbdev->ipa_use_configured_model, false); -+} -+ -+void kbase_ipa_model_use_configured_locked(struct kbase_device *kbdev) -+{ -+ atomic_set(&kbdev->ipa_use_configured_model, true); -+} -+ -+const char *kbase_ipa_model_name_from_id(u32 gpu_id) -+{ -+ const u32 prod_id = (gpu_id & GPU_ID_VERSION_PRODUCT_ID) >> -+ GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ -+ if (GPU_ID_IS_NEW_FORMAT(prod_id)) { -+ switch (GPU_ID2_MODEL_MATCH_VALUE(prod_id)) { -+ case GPU_ID2_PRODUCT_TMIX: -+ return KBASE_IPA_G71_MODEL_NAME; -+ default: -+ return KBASE_IPA_FALLBACK_MODEL_NAME; -+ } -+ } -+ -+ return KBASE_IPA_FALLBACK_MODEL_NAME; -+} -+ -+static struct device_node *get_model_dt_node(struct kbase_ipa_model *model) -+{ -+ struct device_node *model_dt_node; -+ char compat_string[64]; -+ -+ snprintf(compat_string, sizeof(compat_string), "arm,%s", -+ model->ops->name); -+ -+ model_dt_node = of_find_compatible_node(model->kbdev->dev->of_node, -+ NULL, compat_string); -+ if (!model_dt_node && !model->missing_dt_node_warning) { -+ dev_warn(model->kbdev->dev, -+ "Couldn't find power_model DT node matching \'%s\'\n", -+ compat_string); -+ model->missing_dt_node_warning = true; -+ } -+ -+ return model_dt_node; -+} -+ -+int kbase_ipa_model_add_param_s32(struct kbase_ipa_model *model, -+ const char *name, s32 *addr, -+ size_t num_elems, bool dt_required) -+{ -+ int err, i; -+ struct device_node *model_dt_node = get_model_dt_node(model); -+ char *origin; -+ -+ err = of_property_read_u32_array(model_dt_node, name, addr, num_elems); -+ -+ if (err && dt_required) { -+ memset(addr, 0, sizeof(s32) * num_elems); -+ dev_warn(model->kbdev->dev, -+ "Error %d, no DT entry: %s.%s = %zu*[0]\n", -+ err, model->ops->name, name, num_elems); -+ origin = "zero"; -+ } else if (err && !dt_required) { -+ origin = "default"; -+ } else /* !err */ { -+ origin = "DT"; -+ } -+ -+ /* Create a unique debugfs entry for each element */ -+ for (i = 0; i < num_elems; ++i) { -+ char elem_name[32]; -+ -+ if (num_elems == 1) -+ snprintf(elem_name, sizeof(elem_name), "%s", name); -+ else -+ snprintf(elem_name, sizeof(elem_name), "%s.%d", -+ name, i); -+ -+ dev_dbg(model->kbdev->dev, "%s.%s = %d (%s)\n", -+ model->ops->name, elem_name, addr[i], origin); -+ -+ err = kbase_ipa_model_param_add(model, elem_name, -+ &addr[i], sizeof(s32), -+ PARAM_TYPE_S32); -+ if (err) -+ goto exit; -+ } -+exit: -+ return err; -+} -+ -+int kbase_ipa_model_add_param_string(struct kbase_ipa_model *model, -+ const char *name, char *addr, -+ size_t size, bool dt_required) -+{ -+ int err; -+ struct device_node *model_dt_node = get_model_dt_node(model); -+ const char *string_prop_value; -+ char *origin; -+ -+ err = of_property_read_string(model_dt_node, name, -+ &string_prop_value); -+ if (err && dt_required) { -+ strncpy(addr, "", size - 1); -+ dev_warn(model->kbdev->dev, -+ "Error %d, no DT entry: %s.%s = \'%s\'\n", -+ err, model->ops->name, name, addr); -+ err = 0; -+ origin = "zero"; -+ } else if (err && !dt_required) { -+ origin = "default"; -+ } else /* !err */ { -+ strncpy(addr, string_prop_value, size - 1); -+ origin = "DT"; -+ } -+ -+ addr[size - 1] = '\0'; -+ -+ dev_dbg(model->kbdev->dev, "%s.%s = \'%s\' (%s)\n", -+ model->ops->name, name, string_prop_value, origin); -+ -+ err = kbase_ipa_model_param_add(model, name, addr, size, -+ PARAM_TYPE_STRING); -+ -+ return err; -+} -+ -+void kbase_ipa_term_model(struct kbase_ipa_model *model) -+{ -+ if (!model) -+ return; -+ -+ lockdep_assert_held(&model->kbdev->ipa.lock); -+ -+ if (model->ops->term) -+ model->ops->term(model); -+ -+ kbase_ipa_model_param_free_all(model); -+ -+ kfree(model); -+} -+KBASE_EXPORT_TEST_API(kbase_ipa_term_model); -+ -+struct kbase_ipa_model *kbase_ipa_init_model(struct kbase_device *kbdev, -+ struct kbase_ipa_model_ops *ops) -+{ -+ struct kbase_ipa_model *model; -+ int err; -+ -+ lockdep_assert_held(&kbdev->ipa.lock); -+ -+ if (!ops || !ops->name) -+ return NULL; -+ -+ model = kzalloc(sizeof(struct kbase_ipa_model), GFP_KERNEL); -+ if (!model) -+ return NULL; -+ -+ model->kbdev = kbdev; -+ model->ops = ops; -+ INIT_LIST_HEAD(&model->params); -+ -+ err = model->ops->init(model); -+ if (err) { -+ dev_err(kbdev->dev, -+ "init of power model \'%s\' returned error %d\n", -+ ops->name, err); -+ goto term_model; -+ } -+ -+ err = kbase_ipa_model_recalculate(model); -+ if (err) -+ goto term_model; -+ -+ return model; -+ -+term_model: -+ kbase_ipa_term_model(model); -+ return NULL; -+} -+KBASE_EXPORT_TEST_API(kbase_ipa_init_model); -+ -+static void kbase_ipa_term_locked(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->ipa.lock); -+ -+ /* Clean up the models */ -+ if (kbdev->ipa.configured_model != kbdev->ipa.fallback_model) -+ kbase_ipa_term_model(kbdev->ipa.configured_model); -+ kbase_ipa_term_model(kbdev->ipa.fallback_model); -+ -+ kbdev->ipa.configured_model = NULL; -+ kbdev->ipa.fallback_model = NULL; -+} -+ -+int kbase_ipa_init(struct kbase_device *kbdev) -+{ -+ -+ const char *model_name; -+ struct kbase_ipa_model_ops *ops; -+ struct kbase_ipa_model *default_model = NULL; -+ int err; -+ -+ mutex_init(&kbdev->ipa.lock); -+ /* -+ * Lock during init to avoid warnings from lockdep_assert_held (there -+ * shouldn't be any concurrent access yet). -+ */ -+ mutex_lock(&kbdev->ipa.lock); -+ -+ /* The simple IPA model must *always* be present.*/ -+ ops = kbase_ipa_model_ops_find(kbdev, KBASE_IPA_FALLBACK_MODEL_NAME); -+ -+ if (!ops->do_utilization_scaling_in_framework) { -+ dev_err(kbdev->dev, -+ "Fallback IPA model %s should not account for utilization\n", -+ ops->name); -+ err = -EINVAL; -+ goto end; -+ } -+ -+ default_model = kbase_ipa_init_model(kbdev, ops); -+ if (!default_model) { -+ err = -EINVAL; -+ goto end; -+ } -+ -+ kbdev->ipa.fallback_model = default_model; -+ err = of_property_read_string(kbdev->dev->of_node, -+ "ipa-model", -+ &model_name); -+ if (err) { -+ /* Attempt to load a match from GPU-ID */ -+ u32 gpu_id; -+ -+ gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ model_name = kbase_ipa_model_name_from_id(gpu_id); -+ dev_dbg(kbdev->dev, -+ "Inferring model from GPU ID 0x%x: \'%s\'\n", -+ gpu_id, model_name); -+ err = 0; -+ } else { -+ dev_dbg(kbdev->dev, -+ "Using ipa-model parameter from DT: \'%s\'\n", -+ model_name); -+ } -+ -+ if (strcmp(KBASE_IPA_FALLBACK_MODEL_NAME, model_name) != 0) { -+ ops = kbase_ipa_model_ops_find(kbdev, model_name); -+ kbdev->ipa.configured_model = kbase_ipa_init_model(kbdev, ops); -+ if (!kbdev->ipa.configured_model) { -+ err = -EINVAL; -+ goto end; -+ } -+ } else { -+ kbdev->ipa.configured_model = default_model; -+ } -+ -+ kbase_ipa_model_use_configured_locked(kbdev); -+ -+end: -+ if (err) -+ kbase_ipa_term_locked(kbdev); -+ else -+ dev_info(kbdev->dev, -+ "Using configured power model %s, and fallback %s\n", -+ kbdev->ipa.configured_model->ops->name, -+ kbdev->ipa.fallback_model->ops->name); -+ -+ mutex_unlock(&kbdev->ipa.lock); -+ return err; -+} -+KBASE_EXPORT_TEST_API(kbase_ipa_init); -+ -+void kbase_ipa_term(struct kbase_device *kbdev) -+{ -+ mutex_lock(&kbdev->ipa.lock); -+ kbase_ipa_term_locked(kbdev); -+ mutex_unlock(&kbdev->ipa.lock); -+} -+KBASE_EXPORT_TEST_API(kbase_ipa_term); -+ -+/** -+ * kbase_scale_dynamic_power() - Scale a dynamic power coefficient to an OPP -+ * @c: Dynamic model coefficient, in pW/(Hz V^2). Should be in range -+ * 0 < c < 2^26 to prevent overflow. -+ * @freq: Frequency, in Hz. Range: 2^23 < freq < 2^30 (~8MHz to ~1GHz) -+ * @voltage: Voltage, in mV. Range: 2^9 < voltage < 2^13 (~0.5V to ~8V) -+ * -+ * Keep a record of the approximate range of each value at every stage of the -+ * calculation, to ensure we don't overflow. This makes heavy use of the -+ * approximations 1000 = 2^10 and 1000000 = 2^20, but does the actual -+ * calculations in decimal for increased accuracy. -+ * -+ * Return: Power consumption, in mW. Range: 0 < p < 2^13 (0W to ~8W) -+ */ -+static u32 kbase_scale_dynamic_power(const u32 c, const u32 freq, -+ const u32 voltage) -+{ -+ /* Range: 2^8 < v2 < 2^16 m(V^2) */ -+ const u32 v2 = (voltage * voltage) / 1000; -+ -+ /* Range: 2^3 < f_MHz < 2^10 MHz */ -+ const u32 f_MHz = freq / 1000000; -+ -+ /* Range: 2^11 < v2f_big < 2^26 kHz V^2 */ -+ const u32 v2f_big = v2 * f_MHz; -+ -+ /* Range: 2^1 < v2f < 2^16 MHz V^2 */ -+ const u32 v2f = v2f_big / 1000; -+ -+ /* Range (working backwards from next line): 0 < v2fc < 2^23 uW. -+ * Must be < 2^42 to avoid overflowing the return value. */ -+ const u64 v2fc = (u64) c * (u64) v2f; -+ -+ /* Range: 0 < v2fc / 1000 < 2^13 mW */ -+ return v2fc / 1000; -+} -+ -+/** -+ * kbase_scale_static_power() - Scale a static power coefficient to an OPP -+ * @c: Static model coefficient, in uW/V^3. Should be in range -+ * 0 < c < 2^32 to prevent overflow. -+ * @voltage: Voltage, in mV. Range: 2^9 < voltage < 2^13 (~0.5V to ~8V) -+ * -+ * Return: Power consumption, in mW. Range: 0 < p < 2^13 (0W to ~8W) -+ */ -+u32 kbase_scale_static_power(const u32 c, const u32 voltage) -+{ -+ /* Range: 2^8 < v2 < 2^16 m(V^2) */ -+ const u32 v2 = (voltage * voltage) / 1000; -+ -+ /* Range: 2^17 < v3_big < 2^29 m(V^2) mV */ -+ const u32 v3_big = v2 * voltage; -+ -+ /* Range: 2^7 < v3 < 2^19 m(V^3) */ -+ const u32 v3 = v3_big / 1000; -+ -+ /* -+ * Range (working backwards from next line): 0 < v3c_big < 2^33 nW. -+ * The result should be < 2^52 to avoid overflowing the return value. -+ */ -+ const u64 v3c_big = (u64) c * (u64) v3; -+ -+ /* Range: 0 < v3c_big / 1000000 < 2^13 mW */ -+ return v3c_big / 1000000; -+} -+ -+static struct kbase_ipa_model *get_current_model(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->ipa.lock); -+ -+ if (atomic_read(&kbdev->ipa_use_configured_model)) -+ return kbdev->ipa.configured_model; -+ else -+ return kbdev->ipa.fallback_model; -+} -+ -+static u32 get_static_power_locked(struct kbase_device *kbdev, -+ struct kbase_ipa_model *model, -+ unsigned long voltage) -+{ -+ u32 power = 0; -+ int err; -+ u32 power_coeff; -+ -+ lockdep_assert_held(&model->kbdev->ipa.lock); -+ -+ if (!model->ops->get_static_coeff) -+ model = kbdev->ipa.fallback_model; -+ -+ if (model->ops->get_static_coeff) { -+ err = model->ops->get_static_coeff(model, &power_coeff); -+ if (!err) -+ power = kbase_scale_static_power(power_coeff, -+ (u32) voltage); -+ } -+ -+ return power; -+} -+ -+#ifdef CONFIG_MALI_PWRSOFT_765 -+static unsigned long kbase_get_static_power(struct devfreq *df, -+ unsigned long voltage) -+#else -+static unsigned long kbase_get_static_power(unsigned long voltage) -+#endif -+{ -+ struct kbase_ipa_model *model; -+ u32 power = 0; -+#ifdef CONFIG_MALI_PWRSOFT_765 -+ struct kbase_device *kbdev = dev_get_drvdata(&df->dev); -+#else -+ struct kbase_device *kbdev = kbase_find_device(-1); -+#endif -+ -+ mutex_lock(&kbdev->ipa.lock); -+ -+ model = get_current_model(kbdev); -+ power = get_static_power_locked(kbdev, model, voltage); -+ -+ mutex_unlock(&kbdev->ipa.lock); -+ -+#ifndef CONFIG_MALI_PWRSOFT_765 -+ kbase_release_device(kbdev); -+#endif -+ -+ return power; -+} -+ -+#ifdef CONFIG_MALI_PWRSOFT_765 -+static unsigned long kbase_get_dynamic_power(struct devfreq *df, -+ unsigned long freq, -+ unsigned long voltage) -+#else -+static unsigned long kbase_get_dynamic_power(unsigned long freq, -+ unsigned long voltage) -+#endif -+{ -+ struct kbase_ipa_model *model; -+ u32 power_coeff = 0, power = 0; -+ int err = 0; -+#ifdef CONFIG_MALI_PWRSOFT_765 -+ struct kbase_device *kbdev = dev_get_drvdata(&df->dev); -+#else -+ struct kbase_device *kbdev = kbase_find_device(-1); -+#endif -+ -+ mutex_lock(&kbdev->ipa.lock); -+ -+ model = kbdev->ipa.fallback_model; -+ -+ err = model->ops->get_dynamic_coeff(model, &power_coeff, freq); -+ -+ if (!err) -+ power = kbase_scale_dynamic_power(power_coeff, freq, voltage); -+ else -+ dev_err_ratelimited(kbdev->dev, -+ "Model %s returned error code %d\n", -+ model->ops->name, err); -+ -+ mutex_unlock(&kbdev->ipa.lock); -+ -+#ifndef CONFIG_MALI_PWRSOFT_765 -+ kbase_release_device(kbdev); -+#endif -+ -+ return power; -+} -+ -+int kbase_get_real_power(struct devfreq *df, u32 *power, -+ unsigned long freq, -+ unsigned long voltage) -+{ -+ struct kbase_ipa_model *model; -+ u32 power_coeff = 0; -+ int err = 0; -+ struct kbase_device *kbdev = dev_get_drvdata(&df->dev); -+ -+ mutex_lock(&kbdev->ipa.lock); -+ -+ model = get_current_model(kbdev); -+ -+ err = model->ops->get_dynamic_coeff(model, &power_coeff, freq); -+ -+ /* If we switch to protected model between get_current_model() and -+ * get_dynamic_coeff(), counter reading could fail. If that happens -+ * (unlikely, but possible), revert to the fallback model. */ -+ if (err && model != kbdev->ipa.fallback_model) { -+ model = kbdev->ipa.fallback_model; -+ err = model->ops->get_dynamic_coeff(model, &power_coeff, freq); -+ } -+ -+ if (err) -+ goto exit_unlock; -+ -+ *power = kbase_scale_dynamic_power(power_coeff, freq, voltage); -+ -+ if (model->ops->do_utilization_scaling_in_framework) { -+ struct devfreq_dev_status *status = &df->last_status; -+ unsigned long total_time = max(status->total_time, 1ul); -+ u64 busy_time = min(status->busy_time, total_time); -+ -+ *power = ((u64) *power * (u64) busy_time) / total_time; -+ } -+ -+ *power += get_static_power_locked(kbdev, model, voltage); -+ -+exit_unlock: -+ mutex_unlock(&kbdev->ipa.lock); -+ -+ return err; -+} -+KBASE_EXPORT_TEST_API(kbase_get_real_power); -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) -+struct devfreq_cooling_ops kbase_ipa_power_model_ops = { -+#else -+struct devfreq_cooling_power kbase_ipa_power_model_ops = { -+#endif -+ .get_static_power = &kbase_get_static_power, -+ .get_dynamic_power = &kbase_get_dynamic_power, -+#ifdef CONFIG_MALI_PWRSOFT_765 -+ .get_real_power = &kbase_get_real_power, -+#endif -+}; -+KBASE_EXPORT_TEST_API(kbase_ipa_power_model_ops); -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa.h b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa.h -new file mode 100644 -index 0000000..469f33c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa.h -@@ -0,0 +1,165 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_IPA_H_ -+#define _KBASE_IPA_H_ -+ -+#if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_DEVFREQ_THERMAL) -+ -+struct devfreq; -+ -+struct kbase_ipa_model { -+ struct list_head link; -+ struct kbase_device *kbdev; -+ void *model_data; -+ struct kbase_ipa_model_ops *ops; -+ struct list_head params; -+ bool missing_dt_node_warning; -+}; -+ -+/** -+ * kbase_ipa_model_add_param_s32 - Add an integer model parameter -+ * @model: pointer to IPA model -+ * @name: name of corresponding debugfs entry -+ * @addr: address where the value is stored -+ * @num_elems: number of elements (1 if not an array) -+ * @dt_required: if false, a corresponding devicetree entry is not required, -+ * and the current value will be used. If true, a warning is -+ * output and the data is zeroed -+ * -+ * Return: 0 on success, or an error code -+ */ -+int kbase_ipa_model_add_param_s32(struct kbase_ipa_model *model, -+ const char *name, s32 *addr, -+ size_t num_elems, bool dt_required); -+ -+/** -+ * kbase_ipa_model_add_param_string - Add a string model parameter -+ * @model: pointer to IPA model -+ * @name: name of corresponding debugfs entry -+ * @addr: address where the value is stored -+ * @size: size, in bytes, of the value storage (so the maximum string -+ * length is size - 1) -+ * @dt_required: if false, a corresponding devicetree entry is not required, -+ * and the current value will be used. If true, a warning is -+ * output and the data is zeroed -+ * -+ * Return: 0 on success, or an error code -+ */ -+int kbase_ipa_model_add_param_string(struct kbase_ipa_model *model, -+ const char *name, char *addr, -+ size_t size, bool dt_required); -+ -+struct kbase_ipa_model_ops { -+ char *name; -+ /* The init, recalculate and term ops on the default model are always -+ * called. However, all the other models are only invoked if the model -+ * is selected in the device tree. Otherwise they are never -+ * initialized. Additional resources can be acquired by models in -+ * init(), however they must be terminated in the term(). -+ */ -+ int (*init)(struct kbase_ipa_model *model); -+ /* Called immediately after init(), or when a parameter is changed, so -+ * that any coefficients derived from model parameters can be -+ * recalculated. */ -+ int (*recalculate)(struct kbase_ipa_model *model); -+ void (*term)(struct kbase_ipa_model *model); -+ /* -+ * get_dynamic_coeff() - calculate dynamic power coefficient -+ * @model: pointer to model -+ * @coeffp: pointer to return value location -+ * @current_freq: frequency the GPU has been running at for the -+ * previous sampling period. -+ * -+ * Calculate a dynamic power coefficient, with units pW/(Hz V^2), which -+ * is then scaled by the IPA framework according to the current OPP's -+ * frequency and voltage. -+ * -+ * Return: 0 on success, or an error code. -+ */ -+ int (*get_dynamic_coeff)(struct kbase_ipa_model *model, u32 *coeffp, -+ u32 current_freq); -+ /* -+ * get_static_coeff() - calculate static power coefficient -+ * @model: pointer to model -+ * @coeffp: pointer to return value location -+ * -+ * Calculate a static power coefficient, with units uW/(V^3), which is -+ * scaled by the IPA framework according to the current OPP's voltage. -+ * -+ * Return: 0 on success, or an error code. -+ */ -+ int (*get_static_coeff)(struct kbase_ipa_model *model, u32 *coeffp); -+ /* If false, the model's get_dynamic_coeff() method accounts for how -+ * long the GPU was active over the sample period. If true, the -+ * framework will scale the calculated power according to the -+ * utilization stats recorded by devfreq in get_real_power(). */ -+ bool do_utilization_scaling_in_framework; -+}; -+ -+/* Models can be registered only in the platform's platform_init_func call */ -+int kbase_ipa_model_ops_register(struct kbase_device *kbdev, -+ struct kbase_ipa_model_ops *new_model_ops); -+struct kbase_ipa_model *kbase_ipa_get_model(struct kbase_device *kbdev, -+ const char *name); -+ -+int kbase_ipa_init(struct kbase_device *kbdev); -+void kbase_ipa_term(struct kbase_device *kbdev); -+void kbase_ipa_model_use_fallback_locked(struct kbase_device *kbdev); -+void kbase_ipa_model_use_configured_locked(struct kbase_device *kbdev); -+int kbase_ipa_model_recalculate(struct kbase_ipa_model *model); -+struct kbase_ipa_model *kbase_ipa_init_model(struct kbase_device *kbdev, -+ struct kbase_ipa_model_ops *ops); -+void kbase_ipa_term_model(struct kbase_ipa_model *model); -+ -+extern struct kbase_ipa_model_ops kbase_g71_ipa_model_ops; -+ -+#if MALI_UNIT_TEST -+/** -+ * kbase_get_real_power() - get the real power consumption of the GPU -+ * @df: dynamic voltage and frequency scaling information for the GPU. -+ * @power: where to store the power consumption, in mW. -+ * @freq: a frequency, in HZ. -+ * @voltage: a voltage, in mV. -+ * -+ * This function is only exposed for use by unit tests. The returned value -+ * incorporates both static and dynamic power consumption. -+ * -+ * Return: 0 on success, or an error code. -+ */ -+int kbase_get_real_power(struct devfreq *df, u32 *power, -+ unsigned long freq, -+ unsigned long voltage); -+#endif /* MALI_UNIT_TEST */ -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) -+extern struct devfreq_cooling_ops kbase_ipa_power_model_ops; -+#else -+extern struct devfreq_cooling_power kbase_ipa_power_model_ops; -+#endif -+ -+#else /* !(defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_DEVFREQ_THERMAL)) */ -+ -+static inline void kbase_ipa_model_use_fallback_locked(struct kbase_device *kbdev) -+{ } -+ -+static inline void kbase_ipa_model_use_configured_locked(struct kbase_device *kbdev) -+{ } -+ -+#endif /* (defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_DEVFREQ_THERMAL)) */ -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_debugfs.c b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_debugfs.c -new file mode 100644 -index 0000000..eafc140 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_debugfs.c -@@ -0,0 +1,219 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+ -+#include "mali_kbase.h" -+#include "mali_kbase_ipa.h" -+#include "mali_kbase_ipa_debugfs.h" -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) -+#define DEFINE_DEBUGFS_ATTRIBUTE DEFINE_SIMPLE_ATTRIBUTE -+#endif -+ -+struct kbase_ipa_model_param { -+ char *name; -+ union { -+ void *voidp; -+ s32 *s32p; -+ char *str; -+ } addr; -+ size_t size; -+ enum kbase_ipa_model_param_type type; -+ struct kbase_ipa_model *model; -+ struct list_head link; -+}; -+ -+static int param_int_get(void *data, u64 *val) -+{ -+ struct kbase_ipa_model_param *param = data; -+ -+ mutex_lock(¶m->model->kbdev->ipa.lock); -+ *(s64 *) val = *param->addr.s32p; -+ mutex_unlock(¶m->model->kbdev->ipa.lock); -+ -+ return 0; -+} -+ -+static int param_int_set(void *data, u64 val) -+{ -+ struct kbase_ipa_model_param *param = data; -+ struct kbase_ipa_model *model = param->model; -+ s64 sval = (s64) val; -+ int err = 0; -+ -+ if (sval < S32_MIN || sval > S32_MAX) -+ return -ERANGE; -+ -+ mutex_lock(¶m->model->kbdev->ipa.lock); -+ *param->addr.s32p = val; -+ err = kbase_ipa_model_recalculate(model); -+ mutex_unlock(¶m->model->kbdev->ipa.lock); -+ -+ return err; -+} -+ -+DEFINE_DEBUGFS_ATTRIBUTE(fops_s32, param_int_get, param_int_set, "%lld\n"); -+ -+static ssize_t param_string_get(struct file *file, char __user *user_buf, -+ size_t count, loff_t *ppos) -+{ -+ struct kbase_ipa_model_param *param = file->private_data; -+ ssize_t ret; -+ size_t len; -+ -+ mutex_lock(¶m->model->kbdev->ipa.lock); -+ len = strnlen(param->addr.str, param->size - 1) + 1; -+ ret = simple_read_from_buffer(user_buf, count, ppos, -+ param->addr.str, len); -+ mutex_unlock(¶m->model->kbdev->ipa.lock); -+ -+ return ret; -+} -+ -+static ssize_t param_string_set(struct file *file, const char __user *user_buf, -+ size_t count, loff_t *ppos) -+{ -+ struct kbase_ipa_model_param *param = file->private_data; -+ struct kbase_ipa_model *model = param->model; -+ ssize_t ret = count; -+ size_t buf_size; -+ int err; -+ -+ mutex_lock(&model->kbdev->ipa.lock); -+ -+ if (count > param->size) { -+ ret = -EINVAL; -+ goto end; -+ } -+ -+ buf_size = min(param->size - 1, count); -+ if (copy_from_user(param->addr.str, user_buf, buf_size)) { -+ ret = -EFAULT; -+ goto end; -+ } -+ -+ param->addr.str[buf_size] = '\0'; -+ -+ err = kbase_ipa_model_recalculate(model); -+ if (err < 0) -+ ret = err; -+ -+end: -+ mutex_unlock(&model->kbdev->ipa.lock); -+ -+ return ret; -+} -+ -+static const struct file_operations fops_string = { -+ .read = param_string_get, -+ .write = param_string_set, -+ .open = simple_open, -+ .llseek = default_llseek, -+}; -+ -+int kbase_ipa_model_param_add(struct kbase_ipa_model *model, const char *name, -+ void *addr, size_t size, -+ enum kbase_ipa_model_param_type type) -+{ -+ struct kbase_ipa_model_param *param; -+ -+ param = kzalloc(sizeof(*param), GFP_KERNEL); -+ -+ if (!param) -+ return -ENOMEM; -+ -+ /* 'name' is stack-allocated for array elements, so copy it into -+ * heap-allocated storage */ -+ param->name = kstrdup(name, GFP_KERNEL); -+ param->addr.voidp = addr; -+ param->size = size; -+ param->type = type; -+ param->model = model; -+ -+ list_add(¶m->link, &model->params); -+ -+ return 0; -+} -+ -+void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model) -+{ -+ struct kbase_ipa_model_param *param_p, *param_n; -+ -+ list_for_each_entry_safe(param_p, param_n, &model->params, link) { -+ list_del(¶m_p->link); -+ kfree(param_p->name); -+ kfree(param_p); -+ } -+} -+ -+static void kbase_ipa_model_debugfs_init(struct kbase_ipa_model *model) -+{ -+ struct list_head *it; -+ struct dentry *dir; -+ -+ lockdep_assert_held(&model->kbdev->ipa.lock); -+ -+ dir = debugfs_create_dir(model->ops->name, -+ model->kbdev->mali_debugfs_directory); -+ -+ if (!dir) { -+ dev_err(model->kbdev->dev, -+ "Couldn't create mali debugfs %s directory", -+ model->ops->name); -+ return; -+ } -+ -+ list_for_each(it, &model->params) { -+ struct kbase_ipa_model_param *param = -+ list_entry(it, -+ struct kbase_ipa_model_param, -+ link); -+ const struct file_operations *fops = NULL; -+ -+ switch (param->type) { -+ case PARAM_TYPE_S32: -+ fops = &fops_s32; -+ break; -+ case PARAM_TYPE_STRING: -+ fops = &fops_string; -+ break; -+ } -+ -+ if (unlikely(!fops)) { -+ dev_err(model->kbdev->dev, -+ "Type not set for %s parameter %s\n", -+ model->ops->name, param->name); -+ } else { -+ debugfs_create_file(param->name, S_IRUGO | S_IWUSR, -+ dir, param, fops); -+ } -+ } -+} -+ -+void kbase_ipa_debugfs_init(struct kbase_device *kbdev) -+{ -+ mutex_lock(&kbdev->ipa.lock); -+ -+ if (kbdev->ipa.configured_model != kbdev->ipa.fallback_model) -+ kbase_ipa_model_debugfs_init(kbdev->ipa.configured_model); -+ kbase_ipa_model_debugfs_init(kbdev->ipa.fallback_model); -+ -+ mutex_unlock(&kbdev->ipa.lock); -+} -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_debugfs.h b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_debugfs.h -new file mode 100644 -index 0000000..ec06e20 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_debugfs.h -@@ -0,0 +1,49 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_IPA_DEBUGFS_H_ -+#define _KBASE_IPA_DEBUGFS_H_ -+ -+enum kbase_ipa_model_param_type { -+ PARAM_TYPE_S32 = 1, -+ PARAM_TYPE_STRING, -+}; -+ -+#ifdef CONFIG_DEBUG_FS -+ -+void kbase_ipa_debugfs_init(struct kbase_device *kbdev); -+int kbase_ipa_model_param_add(struct kbase_ipa_model *model, const char *name, -+ void *addr, size_t size, -+ enum kbase_ipa_model_param_type type); -+void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model); -+ -+#else /* CONFIG_DEBUG_FS */ -+ -+static inline int kbase_ipa_model_param_add(struct kbase_ipa_model *model, -+ const char *name, void *addr, -+ size_t size, -+ enum kbase_ipa_model_param_type type) -+{ -+ return 0; -+} -+ -+static inline void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model) -+{ } -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+#endif /* _KBASE_IPA_DEBUGFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_simple.c b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_simple.c -new file mode 100644 -index 0000000..dd65d33 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_simple.c -@@ -0,0 +1,325 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#ifdef CONFIG_DEVFREQ_THERMAL -+#include -+#endif -+#include -+#include -+#include -+ -+#include "mali_kbase.h" -+#include "mali_kbase_defs.h" -+#include "mali_kbase_ipa_simple.h" -+ -+#if MALI_UNIT_TEST -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) -+static unsigned long dummy_temp; -+ -+static int kbase_simple_power_model_get_dummy_temp( -+ struct thermal_zone_device *tz, -+ unsigned long *temp) -+{ -+ *temp = ACCESS_ONCE(dummy_temp); -+ return 0; -+} -+ -+#else -+static int dummy_temp; -+ -+static int kbase_simple_power_model_get_dummy_temp( -+ struct thermal_zone_device *tz, -+ int *dummy_temp) -+{ -+ *temp = ACCESS_ONCE(dummy_temp); -+ return 0; -+} -+#endif -+ -+/* Intercept calls to the kernel function using a macro */ -+#ifdef thermal_zone_get_temp -+#undef thermal_zone_get_temp -+#endif -+#define thermal_zone_get_temp(tz, temp) \ -+ kbase_simple_power_model_get_dummy_temp(tz, temp) -+ -+void kbase_simple_power_model_set_dummy_temp(int temp) -+{ -+ ACCESS_ONCE(dummy_temp) = temp; -+} -+KBASE_EXPORT_TEST_API(kbase_simple_power_model_set_dummy_temp); -+ -+#endif /* MALI_UNIT_TEST */ -+ -+/* -+ * This model is primarily designed for the Juno platform. It may not be -+ * suitable for other platforms. The additional resources in this model -+ * should preferably be minimal, as this model is rarely used when a dynamic -+ * model is available. -+ */ -+ -+/** -+ * struct kbase_ipa_model_simple_data - IPA context per device -+ * @dynamic_coefficient: dynamic coefficient of the model -+ * @static_coefficient: static coefficient of the model -+ * @ts: Thermal scaling coefficients of the model -+ * @tz_name: Thermal zone name -+ * @gpu_tz: thermal zone device -+ * @poll_temperature_thread: Handle for temperature polling thread -+ * @current_temperature: Most recent value of polled temperature -+ * @temperature_poll_interval_ms: How often temperature should be checked, in ms -+ */ -+ -+struct kbase_ipa_model_simple_data { -+ u32 dynamic_coefficient; -+ u32 static_coefficient; -+ s32 ts[4]; -+ char tz_name[16]; -+ struct thermal_zone_device *gpu_tz; -+ struct task_struct *poll_temperature_thread; -+ int current_temperature; -+ int temperature_poll_interval_ms; -+}; -+#define FALLBACK_STATIC_TEMPERATURE 55000 -+ -+/** -+ * calculate_temp_scaling_factor() - Calculate temperature scaling coefficient -+ * @ts: Signed coefficients, in order t^0 to t^3, with units Deg^-N -+ * @t: Temperature, in mDeg C. Range: -2^17 < t < 2^17 -+ * -+ * Scale the temperature according to a cubic polynomial whose coefficients are -+ * provided in the device tree. The result is used to scale the static power -+ * coefficient, where 1000000 means no change. -+ * -+ * Return: Temperature scaling factor. Range 0 <= ret <= 10,000,000. -+ */ -+static u32 calculate_temp_scaling_factor(s32 ts[4], s64 t) -+{ -+ /* Range: -2^24 < t2 < 2^24 m(Deg^2) */ -+ const s64 t2 = (t * t) / 1000; -+ -+ /* Range: -2^31 < t3 < 2^31 m(Deg^3) */ -+ const s64 t3 = (t * t2) / 1000; -+ -+ /* -+ * Sum the parts. t^[1-3] are in m(Deg^N), but the coefficients are in -+ * Deg^-N, so we need to multiply the last coefficient by 1000. -+ * Range: -2^63 < res_big < 2^63 -+ */ -+ const s64 res_big = ts[3] * t3 /* +/- 2^62 */ -+ + ts[2] * t2 /* +/- 2^55 */ -+ + ts[1] * t /* +/- 2^48 */ -+ + ts[0] * 1000; /* +/- 2^41 */ -+ -+ /* Range: -2^60 < res_unclamped < 2^60 */ -+ s64 res_unclamped = res_big / 1000; -+ -+ /* Clamp to range of 0x to 10x the static power */ -+ return clamp(res_unclamped, (s64) 0, (s64) 10000000); -+} -+ -+/* We can't call thermal_zone_get_temp() directly in model_static_coeff(), -+ * because we don't know if tz->lock is held in the same thread. So poll it in -+ * a separate thread to get around this. */ -+static int poll_temperature(void *data) -+{ -+ struct kbase_ipa_model_simple_data *model_data = -+ (struct kbase_ipa_model_simple_data *) data; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) -+ unsigned long temp; -+#else -+ int temp; -+#endif -+ -+ while (!kthread_should_stop()) { -+ struct thermal_zone_device *tz = ACCESS_ONCE(model_data->gpu_tz); -+ -+ if (tz) { -+ int ret; -+ -+ ret = thermal_zone_get_temp(tz, &temp); -+ if (ret) { -+ pr_warn_ratelimited("Error reading temperature for gpu thermal zone: %d\n", -+ ret); -+ temp = FALLBACK_STATIC_TEMPERATURE; -+ } -+ } else { -+ temp = FALLBACK_STATIC_TEMPERATURE; -+ } -+ -+ ACCESS_ONCE(model_data->current_temperature) = temp; -+ -+ msleep_interruptible(ACCESS_ONCE(model_data->temperature_poll_interval_ms)); -+ } -+ -+ return 0; -+} -+ -+static int model_static_coeff(struct kbase_ipa_model *model, u32 *coeffp) -+{ -+ u32 temp_scaling_factor; -+ struct kbase_ipa_model_simple_data *model_data = -+ (struct kbase_ipa_model_simple_data *) model->model_data; -+ u64 coeff_big; -+ int temp; -+ -+ temp = ACCESS_ONCE(model_data->current_temperature); -+ -+ /* Range: 0 <= temp_scaling_factor < 2^24 */ -+ temp_scaling_factor = calculate_temp_scaling_factor(model_data->ts, -+ temp); -+ -+ /* -+ * Range: 0 <= coeff_big < 2^52 to avoid overflowing *coeffp. This -+ * means static_coefficient must be in range -+ * 0 <= static_coefficient < 2^28. -+ */ -+ coeff_big = (u64) model_data->static_coefficient * (u64) temp_scaling_factor; -+ *coeffp = coeff_big / 1000000; -+ -+ return 0; -+} -+ -+static int model_dynamic_coeff(struct kbase_ipa_model *model, u32 *coeffp, -+ u32 current_freq) -+{ -+ struct kbase_ipa_model_simple_data *model_data = -+ (struct kbase_ipa_model_simple_data *) model->model_data; -+ -+ *coeffp = model_data->dynamic_coefficient; -+ -+ return 0; -+} -+ -+static int add_params(struct kbase_ipa_model *model) -+{ -+ int err = 0; -+ struct kbase_ipa_model_simple_data *model_data = -+ (struct kbase_ipa_model_simple_data *)model->model_data; -+ -+ err = kbase_ipa_model_add_param_s32(model, "static-coefficient", -+ &model_data->static_coefficient, -+ 1, true); -+ if (err) -+ goto end; -+ -+ err = kbase_ipa_model_add_param_s32(model, "dynamic-coefficient", -+ &model_data->dynamic_coefficient, -+ 1, true); -+ if (err) -+ goto end; -+ -+ err = kbase_ipa_model_add_param_s32(model, "ts", -+ model_data->ts, 4, true); -+ if (err) -+ goto end; -+ -+ err = kbase_ipa_model_add_param_string(model, "thermal-zone", -+ model_data->tz_name, -+ sizeof(model_data->tz_name), true); -+ if (err) -+ goto end; -+ -+ model_data->temperature_poll_interval_ms = 200; -+ err = kbase_ipa_model_add_param_s32(model, "temp-poll-interval-ms", -+ &model_data->temperature_poll_interval_ms, -+ 1, false); -+ -+end: -+ return err; -+} -+ -+static int kbase_simple_power_model_init(struct kbase_ipa_model *model) -+{ -+ int err; -+ struct kbase_ipa_model_simple_data *model_data; -+ -+ model_data = kzalloc(sizeof(struct kbase_ipa_model_simple_data), -+ GFP_KERNEL); -+ if (!model_data) { -+ err = -ENOMEM; -+ goto exit; -+ } -+ -+ model->model_data = (void *) model_data; -+ -+ model_data->current_temperature = FALLBACK_STATIC_TEMPERATURE; -+ model_data->poll_temperature_thread = kthread_run(poll_temperature, -+ (void *) model_data, -+ "mali-simple-power-model-temp-poll"); -+ if (!model_data->poll_temperature_thread) { -+ err = -ENOMEM; -+ goto exit; -+ } -+ -+ err = add_params(model); -+ -+exit: -+ if (err) { -+ if (model_data->poll_temperature_thread) -+ kthread_stop(model_data->poll_temperature_thread); -+ kfree(model_data); -+ } -+ -+ return err; -+} -+ -+static int kbase_simple_power_model_recalculate(struct kbase_ipa_model *model) -+{ -+ struct kbase_ipa_model_simple_data *model_data = -+ (struct kbase_ipa_model_simple_data *)model->model_data; -+ struct thermal_zone_device *tz; -+ -+ if (!strnlen(model_data->tz_name, sizeof(model_data->tz_name))) { -+ tz = NULL; -+ } else { -+ tz = thermal_zone_get_zone_by_name(model_data->tz_name); -+ -+ if (IS_ERR_OR_NULL(tz)) { -+ pr_warn_ratelimited("Error %ld getting thermal zone \'%s\', not yet ready?\n", -+ PTR_ERR(tz), model_data->tz_name); -+ tz = NULL; -+ return -EPROBE_DEFER; -+ } -+ } -+ -+ ACCESS_ONCE(model_data->gpu_tz) = tz; -+ -+ return 0; -+} -+ -+static void kbase_simple_power_model_term(struct kbase_ipa_model *model) -+{ -+ struct kbase_ipa_model_simple_data *model_data = -+ (struct kbase_ipa_model_simple_data *)model->model_data; -+ -+ kthread_stop(model_data->poll_temperature_thread); -+ -+ kfree(model_data); -+} -+ -+struct kbase_ipa_model_ops kbase_simple_ipa_model_ops = { -+ .name = "mali-simple-power-model", -+ .init = &kbase_simple_power_model_init, -+ .recalculate = &kbase_simple_power_model_recalculate, -+ .term = &kbase_simple_power_model_term, -+ .get_dynamic_coeff = &model_dynamic_coeff, -+ .get_static_coeff = &model_static_coeff, -+ .do_utilization_scaling_in_framework = true, -+}; -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_simple.h b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_simple.h -new file mode 100644 -index 0000000..e78d617 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_simple.h -@@ -0,0 +1,40 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_IPA_SIMPLE_H_ -+#define _KBASE_IPA_SIMPLE_H_ -+ -+#if defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_DEVFREQ_THERMAL) -+ -+extern struct kbase_ipa_model_ops kbase_simple_ipa_model_ops; -+ -+#if MALI_UNIT_TEST -+/** -+ * kbase_simple_power_model_set_dummy_temp() - set a dummy temperature value -+ * @temp: Temperature of the thermal zone, in millidegrees celsius. -+ * -+ * This is only intended for use in unit tests, to ensure that the temperature -+ * values used by the simple power model are predictable. Deterministic -+ * behavior is necessary to allow validation of the static power values -+ * computed by this model. -+ */ -+void kbase_simple_power_model_set_dummy_temp(int temp); -+#endif /* MALI_UNIT_TEST */ -+ -+#endif /* (defined(CONFIG_MALI_DEVFREQ) && defined(CONFIG_DEVFREQ_THERMAL)) */ -+ -+#endif /* _KBASE_IPA_SIMPLE_H_ */ -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_common.c b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_common.c -new file mode 100644 -index 0000000..d3964d0 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_common.c -@@ -0,0 +1,217 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include "mali_kbase_ipa_vinstr_common.h" -+ -+#if MALI_UNIT_TEST -+static ktime_t dummy_time; -+ -+/* Intercept calls to the kernel function using a macro */ -+#ifdef ktime_get -+#undef ktime_get -+#endif -+#define ktime_get() (ACCESS_ONCE(dummy_time)) -+ -+void kbase_ipa_set_dummy_time(ktime_t t) -+{ -+ ACCESS_ONCE(dummy_time) = t; -+} -+KBASE_EXPORT_TEST_API(kbase_ipa_set_dummy_time); -+ -+#endif /* MALI_UNIT_TEST */ -+ -+/** -+ * read_hwcnt() - read a counter value -+ * @model_data: pointer to model data -+ * @offset: offset, in bytes, into vinstr buffer -+ * -+ * Return: A 32-bit counter value. Range: 0 < value < 2^27 (worst case would be -+ * incrementing every cycle over a ~100ms sample period at a high frequency, -+ * e.g. 1 GHz: 2^30 * 0.1seconds ~= 2^27. -+ */ -+static inline u32 kbase_ipa_read_hwcnt( -+ struct kbase_ipa_model_vinstr_data *model_data, -+ u32 offset) -+{ -+ u8 *p = model_data->vinstr_buffer; -+ -+ return *(u32 *)&p[offset]; -+} -+ -+static inline s64 kbase_ipa_add_saturate(s64 a, s64 b) -+{ -+ if (S64_MAX - a < b) -+ return S64_MAX; -+ return a + b; -+} -+ -+s64 kbase_ipa_sum_all_shader_cores( -+ struct kbase_ipa_model_vinstr_data *model_data, -+ s32 coeff, u32 counter) -+{ -+ struct kbase_device *kbdev = model_data->kbdev; -+ u64 core_mask; -+ u32 base = 0; -+ s64 ret = 0; -+ -+ core_mask = kbdev->gpu_props.props.coherency_info.group[0].core_mask; -+ while (core_mask != 0ull) { -+ if ((core_mask & 1ull) != 0ull) { -+ /* 0 < counter_value < 2^27 */ -+ u32 counter_value = kbase_ipa_read_hwcnt(model_data, -+ base + counter); -+ -+ /* 0 < ret < 2^27 * max_num_cores = 2^32 */ -+ ret = kbase_ipa_add_saturate(ret, counter_value); -+ } -+ base += KBASE_IPA_NR_BYTES_PER_BLOCK; -+ core_mask >>= 1; -+ } -+ -+ /* Range: -2^54 < ret < 2^54 */ -+ ret *= coeff; -+ -+ return ret / 1000000; -+} -+ -+s64 kbase_ipa_single_counter( -+ struct kbase_ipa_model_vinstr_data *model_data, -+ s32 coeff, u32 counter) -+{ -+ /* Range: 0 < counter_value < 2^27 */ -+ const u32 counter_value = kbase_ipa_read_hwcnt(model_data, counter); -+ -+ /* Range: -2^49 < ret < 2^49 */ -+ const s64 multiplied = (s64) counter_value * (s64) coeff; -+ -+ /* Range: -2^29 < return < 2^29 */ -+ return multiplied / 1000000; -+} -+ -+int kbase_ipa_attach_vinstr(struct kbase_ipa_model_vinstr_data *model_data) -+{ -+ struct kbase_device *kbdev = model_data->kbdev; -+ struct kbase_uk_hwcnt_reader_setup setup; -+ size_t dump_size; -+ -+ dump_size = kbase_vinstr_dump_size(kbdev); -+ model_data->vinstr_buffer = kzalloc(dump_size, GFP_KERNEL); -+ if (!model_data->vinstr_buffer) { -+ dev_err(kbdev->dev, "Failed to allocate IPA dump buffer"); -+ return -1; -+ } -+ -+ setup.jm_bm = ~0u; -+ setup.shader_bm = ~0u; -+ setup.tiler_bm = ~0u; -+ setup.mmu_l2_bm = ~0u; -+ model_data->vinstr_cli = kbase_vinstr_hwcnt_kernel_setup(kbdev->vinstr_ctx, -+ &setup, model_data->vinstr_buffer); -+ if (!model_data->vinstr_cli) { -+ dev_err(kbdev->dev, "Failed to register IPA with vinstr core"); -+ kfree(model_data->vinstr_buffer); -+ model_data->vinstr_buffer = NULL; -+ return -1; -+ } -+ -+ model_data->last_sample_read_time = ktime_get(); -+ kbase_vinstr_hwc_clear(model_data->vinstr_cli); -+ -+ return 0; -+} -+ -+void kbase_ipa_detach_vinstr(struct kbase_ipa_model_vinstr_data *model_data) -+{ -+ if (model_data->vinstr_cli) -+ kbase_vinstr_detach_client(model_data->vinstr_cli); -+ model_data->vinstr_cli = NULL; -+ kfree(model_data->vinstr_buffer); -+ model_data->vinstr_buffer = NULL; -+} -+ -+int kbase_ipa_vinstr_dynamic_coeff(struct kbase_ipa_model *model, u32 *coeffp, -+ u32 current_freq) -+{ -+ struct kbase_ipa_model_vinstr_data *model_data = -+ (struct kbase_ipa_model_vinstr_data *)model->model_data; -+ s64 energy = 0; -+ size_t i; -+ ktime_t now = ktime_get(); -+ ktime_t time_since_last_sample = -+ ktime_sub(now, model_data->last_sample_read_time); -+ /* Range: 2^0 < time_since_last_sample_ms < 2^10 (1-1000ms) */ -+ s64 time_since_last_sample_ms = ktime_to_ms(time_since_last_sample); -+ u64 coeff = 0; -+ u64 num_cycles; -+ int err = 0; -+ -+ err = kbase_vinstr_hwc_dump(model_data->vinstr_cli, -+ BASE_HWCNT_READER_EVENT_MANUAL); -+ if (err) -+ goto err0; -+ -+ model_data->last_sample_read_time = now; -+ -+ /* Range of 'energy' is +/- 2^34 * number of IPA groups, so around -+ * -2^38 < energy < 2^38 */ -+ for (i = 0; i < model_data->groups_def_num; i++) { -+ const struct kbase_ipa_group *group = &model_data->groups_def[i]; -+ s32 coeff, group_energy; -+ -+ coeff = model_data->group_values[i]; -+ group_energy = group->op(model_data, coeff, group->counter); -+ -+ energy = kbase_ipa_add_saturate(energy, group_energy); -+ } -+ -+ /* Range: 0 <= coeff < 2^38 */ -+ if (energy > 0) -+ coeff = energy; -+ -+ /* Scale by user-specified factor and divide by 1000. But actually -+ * cancel the division out, because we want the num_cycles in KHz and -+ * don't want to lose precision. */ -+ -+ /* Range: 0 < coeff < 2^53 */ -+ coeff = coeff * model_data->scaling_factor; -+ -+ if (time_since_last_sample_ms == 0) { -+ time_since_last_sample_ms = 1; -+ } else if (time_since_last_sample_ms < 0) { -+ err = -ERANGE; -+ goto err0; -+ } -+ -+ /* Range: 2^20 < num_cycles < 2^40 mCycles */ -+ num_cycles = (u64) current_freq * (u64) time_since_last_sample_ms; -+ /* Range: 2^10 < num_cycles < 2^30 Cycles */ -+ num_cycles /= 1000000; -+ -+ /* num_cycles should never be 0 in _normal_ usage (because we expect -+ * frequencies on the order of MHz and >10ms polling intervals), but -+ * protect against divide-by-zero anyway. */ -+ if (num_cycles == 0) -+ num_cycles = 1; -+ -+ /* Range: 0 < coeff < 2^43 */ -+ coeff = div_u64(coeff, num_cycles); -+ -+err0: -+ /* Clamp to a sensible range - 2^16 gives about 14W at 400MHz/750mV */ -+ *coeffp = clamp(coeff, (u64) 0, (u64) 1 << 16); -+ return err; -+} -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_common.h b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_common.h -new file mode 100644 -index 0000000..25b36c8 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_common.h -@@ -0,0 +1,161 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_IPA_VINSTR_COMMON_H_ -+#define _KBASE_IPA_VINSTR_COMMON_H_ -+ -+#include "mali_kbase.h" -+ -+/* Maximum length for the name of an IPA group. */ -+#define KBASE_IPA_MAX_GROUP_NAME_LEN 15 -+ -+/* Maximum number of IPA groups for an IPA model. */ -+#define KBASE_IPA_MAX_GROUP_DEF_NUM 16 -+ -+/* Number of bytes per hardware counter in a vinstr_buffer. */ -+#define KBASE_IPA_NR_BYTES_PER_CNT 4 -+ -+/* Number of hardware counters per block in a vinstr_buffer. */ -+#define KBASE_IPA_NR_CNT_PER_BLOCK 64 -+ -+/* Number of bytes per block in a vinstr_buffer. */ -+#define KBASE_IPA_NR_BYTES_PER_BLOCK \ -+ (KBASE_IPA_NR_CNT_PER_BLOCK * KBASE_IPA_NR_BYTES_PER_CNT) -+ -+ -+ -+/** -+ * struct kbase_ipa_model_vinstr_data - IPA context per device -+ * @kbdev: pointer to kbase device -+ * @groups_def: Array of IPA groups. -+ * @groups_def_num: Number of elements in the array of IPA groups. -+ * @vinstr_cli: vinstr client handle -+ * @vinstr_buffer: buffer to dump hardware counters onto -+ * @last_sample_read_time: timestamp of last vinstr buffer read -+ * @scaling_factor: user-specified power scaling factor. This is -+ * interpreted as a fraction where the denominator is -+ * 1000. Range approx 0.0-32.0: -+ * 0 < scaling_factor < 2^15 -+ */ -+struct kbase_ipa_model_vinstr_data { -+ struct kbase_device *kbdev; -+ s32 group_values[KBASE_IPA_MAX_GROUP_DEF_NUM]; -+ const struct kbase_ipa_group *groups_def; -+ size_t groups_def_num; -+ struct kbase_vinstr_client *vinstr_cli; -+ void *vinstr_buffer; -+ ktime_t last_sample_read_time; -+ s32 scaling_factor; -+}; -+ -+/** -+ * struct ipa_group - represents a single IPA group -+ * @name: name of the IPA group -+ * @default_value: default value of coefficient for IPA group. -+ * Coefficients are interpreted as fractions where the -+ * denominator is 1000000. -+ * @op: which operation to be performed on the counter values -+ * @counter: counter used to calculate energy for IPA group -+ */ -+struct kbase_ipa_group { -+ char name[KBASE_IPA_MAX_GROUP_NAME_LEN + 1]; -+ s32 default_value; -+ s64 (*op)(struct kbase_ipa_model_vinstr_data *, s32, u32); -+ u32 counter; -+}; -+ -+/* -+ * sum_all_shader_cores() - sum a counter over all cores -+ * @model_data pointer to model data -+ * @coeff model coefficient. Unity is ~2^20, so range approx -+ * +/- 4.0: -2^22 < coeff < 2^22 -+ -+ * Calculate energy estimation based on hardware counter `counter' -+ * across all shader cores. -+ * -+ * Return: Sum of counter values. Range: -2^34 < ret < 2^34 -+ */ -+s64 kbase_ipa_sum_all_shader_cores( -+ struct kbase_ipa_model_vinstr_data *model_data, -+ s32 coeff, u32 counter); -+ -+/* -+ * sum_single_counter() - sum a single counter -+ * @model_data pointer to model data -+ * @coeff model coefficient. Unity is ~2^20, so range approx -+ * +/- 4.0: -2^22 < coeff < 2^22 -+ -+ * Calculate energy estimation based on hardware counter `counter'. -+ * -+ * Return: Counter value. Range: -2^34 < ret < 2^34 -+ */ -+s64 kbase_ipa_single_counter( -+ struct kbase_ipa_model_vinstr_data *model_data, -+ s32 coeff, u32 counter); -+ -+/* -+ * attach_vinstr() - attach a vinstr_buffer to an IPA model. -+ * @model_data pointer to model data -+ * -+ * Attach a vinstr_buffer to an IPA model. The vinstr_buffer -+ * allows access to the hardware counters used to calculate -+ * energy consumption. -+ * -+ * Return: 0 on success, or an error code. -+ */ -+int kbase_ipa_attach_vinstr(struct kbase_ipa_model_vinstr_data *model_data); -+ -+/* -+ * detach_vinstr() - detach a vinstr_buffer from an IPA model. -+ * @model_data pointer to model data -+ * -+ * Detach a vinstr_buffer from an IPA model. -+ */ -+void kbase_ipa_detach_vinstr(struct kbase_ipa_model_vinstr_data *model_data); -+ -+/** -+ * kbase_ipa_vinstr_dynamic_coeff() - calculate dynamic power based on HW counters -+ * @model: pointer to instantiated model -+ * @coeffp: pointer to location where calculated power, in -+ * pW/(Hz V^2), is stored. -+ * @current_freq: frequency the GPU has been running at over the sample -+ * period. In Hz. Range: 10 MHz < 1GHz, -+ * 2^20 < current_freq < 2^30 -+ * -+ * This is a GPU-agnostic implementation of the get_dynamic_coeff() -+ * function of an IPA model. It relies on the model being populated -+ * with GPU-specific attributes at initialization time. -+ * -+ * Return: 0 on success, or an error code. -+ */ -+int kbase_ipa_vinstr_dynamic_coeff(struct kbase_ipa_model *model, u32 *coeffp, -+ u32 current_freq); -+ -+#if MALI_UNIT_TEST -+/** -+ * kbase_ipa_set_dummy_time() - set a dummy monotonic time value -+ * @t: a monotonic time value -+ * -+ * This is only intended for use in unit tests, to ensure that the kernel time -+ * values used by a power model are predictable. Deterministic behavior is -+ * necessary to allow validation of the dynamic power values computed by the -+ * model. -+ */ -+void kbase_ipa_set_dummy_time(ktime_t t); -+#endif /* MALI_UNIT_TEST */ -+ -+#endif /* _KBASE_IPA_VINSTR_COMMON_H_ */ -diff --git a/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_g71.c b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_g71.c -new file mode 100644 -index 0000000..14241a0 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/ipa/mali_kbase_ipa_vinstr_g71.c -@@ -0,0 +1,128 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+#include -+ -+#include "mali_kbase_ipa_vinstr_common.h" -+#include "mali_kbase.h" -+ -+ -+#define JM_BASE (0 * KBASE_IPA_NR_BYTES_PER_BLOCK) -+#define TILER_BASE (1 * KBASE_IPA_NR_BYTES_PER_BLOCK) -+#define MMU_BASE (2 * KBASE_IPA_NR_BYTES_PER_BLOCK) -+#define SC0_BASE (3 * KBASE_IPA_NR_BYTES_PER_BLOCK) -+ -+#define GPU_ACTIVE (JM_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 6) -+#define TILER_ACTIVE (TILER_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 45) -+#define L2_ANY_LOOKUP (MMU_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 25) -+#define FRAG_ACTIVE (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 4) -+#define EXEC_CORE_ACTIVE (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 26) -+#define EXEC_INSTR_COUNT (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 28) -+#define TEX_COORD_ISSUE (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 40) -+#define VARY_SLOT_32 (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 50) -+#define VARY_SLOT_16 (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 51) -+#define BEATS_RD_LSC (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 56) -+#define BEATS_WR_LSC (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 61) -+#define BEATS_WR_TIB (SC0_BASE + KBASE_IPA_NR_BYTES_PER_CNT * 62) -+ -+static const struct kbase_ipa_group ipa_groups_def[] = { -+ { -+ .name = "l2_access", -+ .default_value = 526300, -+ .op = kbase_ipa_single_counter, -+ .counter = L2_ANY_LOOKUP, -+ }, -+ { -+ .name = "exec_instr_count", -+ .default_value = 301100, -+ .op = kbase_ipa_sum_all_shader_cores, -+ .counter = EXEC_INSTR_COUNT, -+ }, -+ { -+ .name = "tex_issue", -+ .default_value = 197400, -+ .op = kbase_ipa_sum_all_shader_cores, -+ .counter = TEX_COORD_ISSUE, -+ }, -+ { -+ .name = "tile_wb", -+ .default_value = -156400, -+ .op = kbase_ipa_sum_all_shader_cores, -+ .counter = BEATS_WR_TIB, -+ }, -+ { -+ .name = "gpu_active", -+ .default_value = 115800, -+ .op = kbase_ipa_single_counter, -+ .counter = GPU_ACTIVE, -+ }, -+}; -+ -+static int kbase_g71_power_model_init(struct kbase_ipa_model *model) -+{ -+ int i, err = 0; -+ struct kbase_ipa_model_vinstr_data *model_data; -+ -+ model_data = kzalloc(sizeof(*model_data), GFP_KERNEL); -+ if (!model_data) -+ return -EINVAL; -+ -+ model_data->kbdev = model->kbdev; -+ model_data->groups_def = ipa_groups_def; -+ BUILD_BUG_ON(ARRAY_SIZE(ipa_groups_def) > KBASE_IPA_MAX_GROUP_DEF_NUM); -+ model_data->groups_def_num = ARRAY_SIZE(ipa_groups_def); -+ -+ model->model_data = (void *) model_data; -+ -+ for (i = 0; i < ARRAY_SIZE(ipa_groups_def); ++i) { -+ const struct kbase_ipa_group *group = &ipa_groups_def[i]; -+ -+ model_data->group_values[i] = group->default_value; -+ err = kbase_ipa_model_add_param_s32(model, group->name, -+ &model_data->group_values[i], -+ 1, false); -+ if (err) -+ break; -+ } -+ -+ model_data->scaling_factor = 15000; -+ err = kbase_ipa_model_add_param_s32(model, "scale", -+ &model_data->scaling_factor, -+ 1, false); -+ -+ err = kbase_ipa_attach_vinstr(model_data); -+ -+ return err; -+} -+ -+static void kbase_g71_power_model_term(struct kbase_ipa_model *model) -+{ -+ struct kbase_ipa_model_vinstr_data *model_data = -+ (struct kbase_ipa_model_vinstr_data *)model->model_data; -+ -+ kbase_ipa_detach_vinstr(model_data); -+ kfree(model_data); -+} -+ -+ -+struct kbase_ipa_model_ops kbase_g71_ipa_model_ops = { -+ .name = "mali-g71-power-model", -+ .init = kbase_g71_power_model_init, -+ .term = kbase_g71_power_model_term, -+ .get_dynamic_coeff = kbase_ipa_vinstr_dynamic_coeff, -+ .do_utilization_scaling_in_framework = false, -+}; -+KBASE_EXPORT_TEST_API(kbase_g71_ipa_model_ops); -diff --git a/drivers/gpu/arm/midgard/mali_base_hwconfig_features.h b/drivers/gpu/arm/midgard/mali_base_hwconfig_features.h -new file mode 100644 -index 0000000..bead0ab ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_base_hwconfig_features.h -@@ -0,0 +1,368 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* AUTOMATICALLY GENERATED FILE. If you want to amend the issues/features, -+ * please update base/tools/hwconfig_generator/hwc_{issues,features}.py -+ * For more information see base/tools/hwconfig_generator/README -+ */ -+ -+#ifndef _BASE_HWCONFIG_FEATURES_H_ -+#define _BASE_HWCONFIG_FEATURES_H_ -+ -+enum base_hw_feature { -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_OPTIMIZED_COVERAGE_MASK, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4, -+ BASE_HW_FEATURE_IMAGES_IN_FRAGMENT_SHADERS, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_V4, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, -+ BASE_HW_FEATURE_AARCH64_MMU, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_generic[] = { -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_t60x[] = { -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_V4, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_t62x[] = { -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_V4, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_t72x[] = { -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_OPTIMIZED_COVERAGE_MASK, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_V4, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_t76x[] = { -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_tFxx[] = { -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_t83x[] = { -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_t82x[] = { -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_tMIx[] = { -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_tHEx[] = { -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_tSIx[] = { -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_END -+}; -+ -+static const enum base_hw_feature base_hw_features_tDVx[] = { -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_END -+}; -+ -+ -+#ifdef MALI_INCLUDE_TGOX -+static const enum base_hw_feature base_hw_features_tGOx[] = { -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_AARCH64_MMU, -+ BASE_HW_FEATURE_END -+}; -+ -+#endif /* MALI_INCLUDE_TGOX */ -+ -+#ifdef MALI_INCLUDE_TKAX -+static const enum base_hw_feature base_hw_features_tKAx[] = { -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_END -+}; -+ -+#endif /* MALI_INCLUDE_TKAX */ -+ -+#ifdef MALI_INCLUDE_TTRX -+static const enum base_hw_feature base_hw_features_tTRx[] = { -+ BASE_HW_FEATURE_33BIT_VA, -+ BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION, -+ BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS, -+ BASE_HW_FEATURE_XAFFINITY, -+ BASE_HW_FEATURE_WARPING, -+ BASE_HW_FEATURE_INTERPIPE_REG_ALIASING, -+ BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS, -+ BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, -+ BASE_HW_FEATURE_BRNDOUT_CC, -+ BASE_HW_FEATURE_BRNDOUT_KILL, -+ BASE_HW_FEATURE_LD_ST_LEA_TEX, -+ BASE_HW_FEATURE_LD_ST_TILEBUFFER, -+ BASE_HW_FEATURE_LINEAR_FILTER_FLOAT, -+ BASE_HW_FEATURE_MRT, -+ BASE_HW_FEATURE_MSAA_16X, -+ BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE, -+ BASE_HW_FEATURE_OUT_OF_ORDER_EXEC, -+ BASE_HW_FEATURE_T7XX_PAIRING_RULES, -+ BASE_HW_FEATURE_TEST4_DATUM_MODE, -+ BASE_HW_FEATURE_FLUSH_REDUCTION, -+ BASE_HW_FEATURE_PROTECTED_MODE, -+ BASE_HW_FEATURE_PROTECTED_DEBUG_MODE, -+ BASE_HW_FEATURE_COHERENCY_REG, -+ BASE_HW_FEATURE_END -+}; -+ -+#endif /* MALI_INCLUDE_TTRX */ -+ -+#endif /* _BASE_HWCONFIG_FEATURES_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_base_hwconfig_issues.h b/drivers/gpu/arm/midgard/mali_base_hwconfig_issues.h -new file mode 100644 -index 0000000..d068aaf ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_base_hwconfig_issues.h -@@ -0,0 +1,1134 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* AUTOMATICALLY GENERATED FILE. If you want to amend the issues/features, -+ * please update base/tools/hwconfig_generator/hwc_{issues,features}.py -+ * For more information see base/tools/hwconfig_generator/README -+ */ -+ -+#ifndef _BASE_HWCONFIG_ISSUES_H_ -+#define _BASE_HWCONFIG_ISSUES_H_ -+ -+enum base_hw_issue { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_6367, -+ BASE_HW_ISSUE_6398, -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_6787, -+ BASE_HW_ISSUE_7027, -+ BASE_HW_ISSUE_7144, -+ BASE_HW_ISSUE_7304, -+ BASE_HW_ISSUE_8073, -+ BASE_HW_ISSUE_8186, -+ BASE_HW_ISSUE_8215, -+ BASE_HW_ISSUE_8245, -+ BASE_HW_ISSUE_8250, -+ BASE_HW_ISSUE_8260, -+ BASE_HW_ISSUE_8280, -+ BASE_HW_ISSUE_8316, -+ BASE_HW_ISSUE_8381, -+ BASE_HW_ISSUE_8394, -+ BASE_HW_ISSUE_8401, -+ BASE_HW_ISSUE_8408, -+ BASE_HW_ISSUE_8443, -+ BASE_HW_ISSUE_8456, -+ BASE_HW_ISSUE_8564, -+ BASE_HW_ISSUE_8634, -+ BASE_HW_ISSUE_8778, -+ BASE_HW_ISSUE_8791, -+ BASE_HW_ISSUE_8833, -+ BASE_HW_ISSUE_8879, -+ BASE_HW_ISSUE_8896, -+ BASE_HW_ISSUE_8975, -+ BASE_HW_ISSUE_8986, -+ BASE_HW_ISSUE_8987, -+ BASE_HW_ISSUE_9010, -+ BASE_HW_ISSUE_9418, -+ BASE_HW_ISSUE_9423, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_9510, -+ BASE_HW_ISSUE_9566, -+ BASE_HW_ISSUE_9630, -+ BASE_HW_ISSUE_10127, -+ BASE_HW_ISSUE_10327, -+ BASE_HW_ISSUE_10410, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10487, -+ BASE_HW_ISSUE_10607, -+ BASE_HW_ISSUE_10632, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10676, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10797, -+ BASE_HW_ISSUE_10817, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_10959, -+ BASE_HW_ISSUE_10969, -+ BASE_HW_ISSUE_10984, -+ BASE_HW_ISSUE_10995, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11035, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_26, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3542, -+ BASE_HW_ISSUE_T76X_3556, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_7940, -+ BASE_HW_ISSUE_TMIX_8042, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TMIX_8138, -+ BASE_HW_ISSUE_TMIX_8206, -+ BASE_HW_ISSUE_TMIX_8343, -+ BASE_HW_ISSUE_TMIX_8463, -+ BASE_HW_ISSUE_TMIX_8456, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_generic[] = { -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t60x_r0p0_15dev0[] = { -+ BASE_HW_ISSUE_6367, -+ BASE_HW_ISSUE_6398, -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_6787, -+ BASE_HW_ISSUE_7027, -+ BASE_HW_ISSUE_7144, -+ BASE_HW_ISSUE_7304, -+ BASE_HW_ISSUE_8073, -+ BASE_HW_ISSUE_8186, -+ BASE_HW_ISSUE_8215, -+ BASE_HW_ISSUE_8245, -+ BASE_HW_ISSUE_8250, -+ BASE_HW_ISSUE_8260, -+ BASE_HW_ISSUE_8280, -+ BASE_HW_ISSUE_8316, -+ BASE_HW_ISSUE_8381, -+ BASE_HW_ISSUE_8394, -+ BASE_HW_ISSUE_8401, -+ BASE_HW_ISSUE_8408, -+ BASE_HW_ISSUE_8443, -+ BASE_HW_ISSUE_8456, -+ BASE_HW_ISSUE_8564, -+ BASE_HW_ISSUE_8634, -+ BASE_HW_ISSUE_8778, -+ BASE_HW_ISSUE_8791, -+ BASE_HW_ISSUE_8833, -+ BASE_HW_ISSUE_8896, -+ BASE_HW_ISSUE_8975, -+ BASE_HW_ISSUE_8986, -+ BASE_HW_ISSUE_8987, -+ BASE_HW_ISSUE_9010, -+ BASE_HW_ISSUE_9418, -+ BASE_HW_ISSUE_9423, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_9510, -+ BASE_HW_ISSUE_9566, -+ BASE_HW_ISSUE_9630, -+ BASE_HW_ISSUE_10410, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10487, -+ BASE_HW_ISSUE_10607, -+ BASE_HW_ISSUE_10632, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10676, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_10969, -+ BASE_HW_ISSUE_10984, -+ BASE_HW_ISSUE_10995, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11035, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_3964, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t60x_r0p0_eac[] = { -+ BASE_HW_ISSUE_6367, -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_6787, -+ BASE_HW_ISSUE_7027, -+ BASE_HW_ISSUE_7304, -+ BASE_HW_ISSUE_8408, -+ BASE_HW_ISSUE_8564, -+ BASE_HW_ISSUE_8778, -+ BASE_HW_ISSUE_8975, -+ BASE_HW_ISSUE_9010, -+ BASE_HW_ISSUE_9418, -+ BASE_HW_ISSUE_9423, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_9510, -+ BASE_HW_ISSUE_10410, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10487, -+ BASE_HW_ISSUE_10607, -+ BASE_HW_ISSUE_10632, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10676, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_10969, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11035, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t60x_r0p1[] = { -+ BASE_HW_ISSUE_6367, -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_6787, -+ BASE_HW_ISSUE_7027, -+ BASE_HW_ISSUE_7304, -+ BASE_HW_ISSUE_8408, -+ BASE_HW_ISSUE_8564, -+ BASE_HW_ISSUE_8778, -+ BASE_HW_ISSUE_8975, -+ BASE_HW_ISSUE_9010, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_9510, -+ BASE_HW_ISSUE_10410, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10487, -+ BASE_HW_ISSUE_10607, -+ BASE_HW_ISSUE_10632, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10676, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11035, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t62x_r0p1[] = { -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10127, -+ BASE_HW_ISSUE_10327, -+ BASE_HW_ISSUE_10410, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10487, -+ BASE_HW_ISSUE_10607, -+ BASE_HW_ISSUE_10632, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10676, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10817, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_10959, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11035, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t62x_r1p0[] = { -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_10959, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t62x_r1p1[] = { -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_10959, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t76x_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_26, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3542, -+ BASE_HW_ISSUE_T76X_3556, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t76x_r0p1[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_26, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3542, -+ BASE_HW_ISSUE_T76X_3556, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t76x_r0p1_50rel0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_26, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3542, -+ BASE_HW_ISSUE_T76X_3556, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t76x_r0p2[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_26, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3542, -+ BASE_HW_ISSUE_T76X_3556, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t76x_r0p3[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_26, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3542, -+ BASE_HW_ISSUE_T76X_3556, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t76x_r1p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t72x_r0p0[] = { -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10797, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t72x_r1p0[] = { -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10797, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t72x_r1p1[] = { -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10684, -+ BASE_HW_ISSUE_10797, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_t72x[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10471, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10797, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_t76x[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_t60x[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_8778, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_t62x[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_6402, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10472, -+ BASE_HW_ISSUE_10649, -+ BASE_HW_ISSUE_10931, -+ BASE_HW_ISSUE_11012, -+ BASE_HW_ISSUE_11020, -+ BASE_HW_ISSUE_11024, -+ BASE_HW_ISSUE_11042, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3964, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tFRx_r0p1[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tFRx_r0p2[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tFRx_r1p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tFRx_r2p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_tFRx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t86x_r0p2[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t86x_r1p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t86x_r2p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3966, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_t86x[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t83x_r0p1[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t83x_r1p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_t83x[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t82x_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3964, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t82x_r0p1[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_1909, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_t82x_r1p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10821, -+ BASE_HW_ISSUE_10883, -+ BASE_HW_ISSUE_10946, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T720_1386, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_T76X_3960, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_t82x[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_11051, -+ BASE_HW_ISSUE_T76X_1963, -+ BASE_HW_ISSUE_T76X_3086, -+ BASE_HW_ISSUE_T76X_3700, -+ BASE_HW_ISSUE_T76X_3793, -+ BASE_HW_ISSUE_T76X_3979, -+ BASE_HW_ISSUE_TMIX_7891, -+ GPUCORE_1619, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tMIx_r0p0_05dev0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_T76X_3953, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8042, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TMIX_8138, -+ BASE_HW_ISSUE_TMIX_8206, -+ BASE_HW_ISSUE_TMIX_8343, -+ BASE_HW_ISSUE_TMIX_8463, -+ BASE_HW_ISSUE_TMIX_8456, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tMIx_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_11054, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_7940, -+ BASE_HW_ISSUE_TMIX_8042, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TMIX_8138, -+ BASE_HW_ISSUE_TMIX_8206, -+ BASE_HW_ISSUE_TMIX_8343, -+ BASE_HW_ISSUE_TMIX_8463, -+ BASE_HW_ISSUE_TMIX_8456, -+ BASE_HW_ISSUE_TMIX_8438, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_tMIx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_7940, -+ BASE_HW_ISSUE_TMIX_8042, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TMIX_8138, -+ BASE_HW_ISSUE_TMIX_8206, -+ BASE_HW_ISSUE_TMIX_8343, -+ BASE_HW_ISSUE_TMIX_8456, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tHEx_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8042, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tHEx_r0p1[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_10682, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8042, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_tHEx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_7891, -+ BASE_HW_ISSUE_TMIX_8042, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tSIx_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tSIx_r0p1[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tSIx_r1p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_tSIx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_tDVx_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+static const enum base_hw_issue base_hw_issues_model_tDVx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+ -+ -+#ifdef MALI_INCLUDE_TGOX -+static const enum base_hw_issue base_hw_issues_tGOx_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+#endif /* MALI_INCLUDE_TGOX */ -+ -+#ifdef MALI_INCLUDE_TGOX -+static const enum base_hw_issue base_hw_issues_model_tGOx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+#endif /* MALI_INCLUDE_TGOX */ -+ -+#ifdef MALI_INCLUDE_TKAX -+static const enum base_hw_issue base_hw_issues_tKAx_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+#endif /* MALI_INCLUDE_TKAX */ -+ -+#ifdef MALI_INCLUDE_TKAX -+static const enum base_hw_issue base_hw_issues_model_tKAx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+#endif /* MALI_INCLUDE_TKAX */ -+ -+#ifdef MALI_INCLUDE_TTRX -+static const enum base_hw_issue base_hw_issues_tTRx_r0p0[] = { -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+#endif /* MALI_INCLUDE_TTRX */ -+ -+#ifdef MALI_INCLUDE_TTRX -+static const enum base_hw_issue base_hw_issues_model_tTRx[] = { -+ BASE_HW_ISSUE_5736, -+ BASE_HW_ISSUE_9435, -+ BASE_HW_ISSUE_TMIX_8133, -+ BASE_HW_ISSUE_TSIX_1116, -+ BASE_HW_ISSUE_END -+}; -+ -+#endif /* MALI_INCLUDE_TTRX */ -+ -+#endif /* _BASE_HWCONFIG_ISSUES_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_base_kernel.h b/drivers/gpu/arm/midgard/mali_base_kernel.h -new file mode 100644 -index 0000000..998d097 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_base_kernel.h -@@ -0,0 +1,1818 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Base structures shared with the kernel. -+ */ -+ -+#ifndef _BASE_KERNEL_H_ -+#define _BASE_KERNEL_H_ -+ -+/* Support UK10_2 IOCTLS */ -+#define BASE_LEGACY_UK10_2_SUPPORT 1 -+ -+/* Support UK10_4 IOCTLS */ -+#define BASE_LEGACY_UK10_4_SUPPORT 1 -+ -+typedef struct base_mem_handle { -+ struct { -+ u64 handle; -+ } basep; -+} base_mem_handle; -+ -+#include "mali_base_mem_priv.h" -+#include "mali_kbase_profiling_gator_api.h" -+#include "mali_midg_coherency.h" -+#include "mali_kbase_gpu_id.h" -+ -+/* -+ * Dependency stuff, keep it private for now. May want to expose it if -+ * we decide to make the number of semaphores a configurable -+ * option. -+ */ -+#define BASE_JD_ATOM_COUNT 256 -+ -+#define BASEP_JD_SEM_PER_WORD_LOG2 5 -+#define BASEP_JD_SEM_PER_WORD (1 << BASEP_JD_SEM_PER_WORD_LOG2) -+#define BASEP_JD_SEM_WORD_NR(x) ((x) >> BASEP_JD_SEM_PER_WORD_LOG2) -+#define BASEP_JD_SEM_MASK_IN_WORD(x) (1 << ((x) & (BASEP_JD_SEM_PER_WORD - 1))) -+#define BASEP_JD_SEM_ARRAY_SIZE BASEP_JD_SEM_WORD_NR(BASE_JD_ATOM_COUNT) -+ -+/* Set/reset values for a software event */ -+#define BASE_JD_SOFT_EVENT_SET ((unsigned char)1) -+#define BASE_JD_SOFT_EVENT_RESET ((unsigned char)0) -+ -+#define BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS 3 -+ -+#define BASE_MAX_COHERENT_GROUPS 16 -+ -+#if defined CDBG_ASSERT -+#define LOCAL_ASSERT CDBG_ASSERT -+#elif defined KBASE_DEBUG_ASSERT -+#define LOCAL_ASSERT KBASE_DEBUG_ASSERT -+#else -+#error assert macro not defined! -+#endif -+ -+#if defined PAGE_MASK -+#define LOCAL_PAGE_LSB ~PAGE_MASK -+#else -+#include -+ -+#if defined OSU_CONFIG_CPU_PAGE_SIZE_LOG2 -+#define LOCAL_PAGE_LSB ((1ul << OSU_CONFIG_CPU_PAGE_SIZE_LOG2) - 1) -+#else -+#error Failed to find page size -+#endif -+#endif -+ -+/** -+ * @addtogroup base_user_api User-side Base APIs -+ * @{ -+ */ -+ -+/** -+ * @addtogroup base_user_api_memory User-side Base Memory APIs -+ * @{ -+ */ -+ -+/** -+ * typedef base_mem_alloc_flags - Memory allocation, access/hint flags. -+ * -+ * A combination of MEM_PROT/MEM_HINT flags must be passed to each allocator -+ * in order to determine the best cache policy. Some combinations are -+ * of course invalid (e.g. MEM_PROT_CPU_WR | MEM_HINT_CPU_RD), -+ * which defines a write-only region on the CPU side, which is -+ * heavily read by the CPU... -+ * Other flags are only meaningful to a particular allocator. -+ * More flags can be added to this list, as long as they don't clash -+ * (see BASE_MEM_FLAGS_NR_BITS for the number of the first free bit). -+ */ -+typedef u32 base_mem_alloc_flags; -+ -+/* Memory allocation, access/hint flags. -+ * -+ * See base_mem_alloc_flags. -+ */ -+ -+/* IN */ -+/* Read access CPU side -+ */ -+#define BASE_MEM_PROT_CPU_RD ((base_mem_alloc_flags)1 << 0) -+ -+/* Write access CPU side -+ */ -+#define BASE_MEM_PROT_CPU_WR ((base_mem_alloc_flags)1 << 1) -+ -+/* Read access GPU side -+ */ -+#define BASE_MEM_PROT_GPU_RD ((base_mem_alloc_flags)1 << 2) -+ -+/* Write access GPU side -+ */ -+#define BASE_MEM_PROT_GPU_WR ((base_mem_alloc_flags)1 << 3) -+ -+/* Execute allowed on the GPU side -+ */ -+#define BASE_MEM_PROT_GPU_EX ((base_mem_alloc_flags)1 << 4) -+ -+ /* BASE_MEM_HINT flags have been removed, but their values are reserved -+ * for backwards compatibility with older user-space drivers. The values -+ * can be re-used once support for r5p0 user-space drivers is removed, -+ * presumably in r7p0. -+ * -+ * RESERVED: (1U << 5) -+ * RESERVED: (1U << 6) -+ * RESERVED: (1U << 7) -+ * RESERVED: (1U << 8) -+ */ -+ -+/* Grow backing store on GPU Page Fault -+ */ -+#define BASE_MEM_GROW_ON_GPF ((base_mem_alloc_flags)1 << 9) -+ -+/* Page coherence Outer shareable, if available -+ */ -+#define BASE_MEM_COHERENT_SYSTEM ((base_mem_alloc_flags)1 << 10) -+ -+/* Page coherence Inner shareable -+ */ -+#define BASE_MEM_COHERENT_LOCAL ((base_mem_alloc_flags)1 << 11) -+ -+/* Should be cached on the CPU -+ */ -+#define BASE_MEM_CACHED_CPU ((base_mem_alloc_flags)1 << 12) -+ -+/* IN/OUT */ -+/* Must have same VA on both the GPU and the CPU -+ */ -+#define BASE_MEM_SAME_VA ((base_mem_alloc_flags)1 << 13) -+ -+/* OUT */ -+/* Must call mmap to acquire a GPU address for the alloc -+ */ -+#define BASE_MEM_NEED_MMAP ((base_mem_alloc_flags)1 << 14) -+ -+/* IN */ -+/* Page coherence Outer shareable, required. -+ */ -+#define BASE_MEM_COHERENT_SYSTEM_REQUIRED ((base_mem_alloc_flags)1 << 15) -+ -+/* Secure memory -+ */ -+#define BASE_MEM_SECURE ((base_mem_alloc_flags)1 << 16) -+ -+/* Not needed physical memory -+ */ -+#define BASE_MEM_DONT_NEED ((base_mem_alloc_flags)1 << 17) -+ -+/* Must use shared CPU/GPU zone (SAME_VA zone) but doesn't require the -+ * addresses to be the same -+ */ -+#define BASE_MEM_IMPORT_SHARED ((base_mem_alloc_flags)1 << 18) -+ -+/* Number of bits used as flags for base memory management -+ * -+ * Must be kept in sync with the base_mem_alloc_flags flags -+ */ -+#define BASE_MEM_FLAGS_NR_BITS 19 -+ -+/* A mask for all output bits, excluding IN/OUT bits. -+ */ -+#define BASE_MEM_FLAGS_OUTPUT_MASK BASE_MEM_NEED_MMAP -+ -+/* A mask for all input bits, including IN/OUT bits. -+ */ -+#define BASE_MEM_FLAGS_INPUT_MASK \ -+ (((1 << BASE_MEM_FLAGS_NR_BITS) - 1) & ~BASE_MEM_FLAGS_OUTPUT_MASK) -+ -+/* A mask for all the flags which are modifiable via the base_mem_set_flags -+ * interface. -+ */ -+#define BASE_MEM_FLAGS_MODIFIABLE \ -+ (BASE_MEM_DONT_NEED | BASE_MEM_COHERENT_SYSTEM | \ -+ BASE_MEM_COHERENT_LOCAL) -+ -+/** -+ * enum base_mem_import_type - Memory types supported by @a base_mem_import -+ * -+ * @BASE_MEM_IMPORT_TYPE_INVALID: Invalid type -+ * @BASE_MEM_IMPORT_TYPE_UMP: UMP import. Handle type is ump_secure_id. -+ * @BASE_MEM_IMPORT_TYPE_UMM: UMM import. Handle type is a file descriptor (int) -+ * @BASE_MEM_IMPORT_TYPE_USER_BUFFER: User buffer import. Handle is a -+ * base_mem_import_user_buffer -+ * -+ * Each type defines what the supported handle type is. -+ * -+ * If any new type is added here ARM must be contacted -+ * to allocate a numeric value for it. -+ * Do not just add a new type without synchronizing with ARM -+ * as future releases from ARM might include other new types -+ * which could clash with your custom types. -+ */ -+typedef enum base_mem_import_type { -+ BASE_MEM_IMPORT_TYPE_INVALID = 0, -+ BASE_MEM_IMPORT_TYPE_UMP = 1, -+ BASE_MEM_IMPORT_TYPE_UMM = 2, -+ BASE_MEM_IMPORT_TYPE_USER_BUFFER = 3 -+} base_mem_import_type; -+ -+/** -+ * struct base_mem_import_user_buffer - Handle of an imported user buffer -+ * -+ * @ptr: address of imported user buffer -+ * @length: length of imported user buffer in bytes -+ * -+ * This structure is used to represent a handle of an imported user buffer. -+ */ -+ -+struct base_mem_import_user_buffer { -+ u64 ptr; -+ u64 length; -+}; -+ -+/** -+ * @brief Invalid memory handle. -+ * -+ * Return value from functions returning @ref base_mem_handle on error. -+ * -+ * @warning @ref base_mem_handle_new_invalid must be used instead of this macro -+ * in C++ code or other situations where compound literals cannot be used. -+ */ -+#define BASE_MEM_INVALID_HANDLE ((base_mem_handle) { {BASEP_MEM_INVALID_HANDLE} }) -+ -+/** -+ * @brief Special write-alloc memory handle. -+ * -+ * A special handle is used to represent a region where a special page is mapped -+ * with a write-alloc cache setup, typically used when the write result of the -+ * GPU isn't needed, but the GPU must write anyway. -+ * -+ * @warning @ref base_mem_handle_new_write_alloc must be used instead of this macro -+ * in C++ code or other situations where compound literals cannot be used. -+ */ -+#define BASE_MEM_WRITE_ALLOC_PAGES_HANDLE ((base_mem_handle) { {BASEP_MEM_WRITE_ALLOC_PAGES_HANDLE} }) -+ -+#define BASEP_MEM_INVALID_HANDLE (0ull << 12) -+#define BASE_MEM_MMU_DUMP_HANDLE (1ull << 12) -+#define BASE_MEM_TRACE_BUFFER_HANDLE (2ull << 12) -+#define BASE_MEM_MAP_TRACKING_HANDLE (3ull << 12) -+#define BASEP_MEM_WRITE_ALLOC_PAGES_HANDLE (4ull << 12) -+/* reserved handles ..-64< for future special handles */ -+#define BASE_MEM_COOKIE_BASE (64ul << 12) -+#define BASE_MEM_FIRST_FREE_ADDRESS ((BITS_PER_LONG << 12) + \ -+ BASE_MEM_COOKIE_BASE) -+ -+/* Mask to detect 4GB boundary alignment */ -+#define BASE_MEM_MASK_4GB 0xfffff000UL -+ -+ -+/* Bit mask of cookies used for for memory allocation setup */ -+#define KBASE_COOKIE_MASK ~1UL /* bit 0 is reserved */ -+ -+ -+/** -+ * @brief Result codes of changing the size of the backing store allocated to a tmem region -+ */ -+typedef enum base_backing_threshold_status { -+ BASE_BACKING_THRESHOLD_OK = 0, /**< Resize successful */ -+ BASE_BACKING_THRESHOLD_ERROR_OOM = -2, /**< Increase failed due to an out-of-memory condition */ -+ BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS = -4 /**< Invalid arguments (not tmem, illegal size request, etc.) */ -+} base_backing_threshold_status; -+ -+/** -+ * @addtogroup base_user_api_memory_defered User-side Base Defered Memory Coherency APIs -+ * @{ -+ */ -+ -+/** -+ * @brief a basic memory operation (sync-set). -+ * -+ * The content of this structure is private, and should only be used -+ * by the accessors. -+ */ -+typedef struct base_syncset { -+ struct basep_syncset basep_sset; -+} base_syncset; -+ -+/** @} end group base_user_api_memory_defered */ -+ -+/** -+ * Handle to represent imported memory object. -+ * Simple opague handle to imported memory, can't be used -+ * with anything but base_external_resource_init to bind to an atom. -+ */ -+typedef struct base_import_handle { -+ struct { -+ u64 handle; -+ } basep; -+} base_import_handle; -+ -+/** @} end group base_user_api_memory */ -+ -+/** -+ * @addtogroup base_user_api_job_dispatch User-side Base Job Dispatcher APIs -+ * @{ -+ */ -+ -+typedef int platform_fence_type; -+#define INVALID_PLATFORM_FENCE ((platform_fence_type)-1) -+ -+/** -+ * Base stream handle. -+ * -+ * References an underlying base stream object. -+ */ -+typedef struct base_stream { -+ struct { -+ int fd; -+ } basep; -+} base_stream; -+ -+/** -+ * Base fence handle. -+ * -+ * References an underlying base fence object. -+ */ -+typedef struct base_fence { -+ struct { -+ int fd; -+ int stream_fd; -+ } basep; -+} base_fence; -+ -+/** -+ * @brief Per-job data -+ * -+ * This structure is used to store per-job data, and is completely unused -+ * by the Base driver. It can be used to store things such as callback -+ * function pointer, data to handle job completion. It is guaranteed to be -+ * untouched by the Base driver. -+ */ -+typedef struct base_jd_udata { -+ u64 blob[2]; /**< per-job data array */ -+} base_jd_udata; -+ -+/** -+ * @brief Memory aliasing info -+ * -+ * Describes a memory handle to be aliased. -+ * A subset of the handle can be chosen for aliasing, given an offset and a -+ * length. -+ * A special handle BASE_MEM_WRITE_ALLOC_PAGES_HANDLE is used to represent a -+ * region where a special page is mapped with a write-alloc cache setup, -+ * typically used when the write result of the GPU isn't needed, but the GPU -+ * must write anyway. -+ * -+ * Offset and length are specified in pages. -+ * Offset must be within the size of the handle. -+ * Offset+length must not overrun the size of the handle. -+ * -+ * @handle Handle to alias, can be BASE_MEM_WRITE_ALLOC_PAGES_HANDLE -+ * @offset Offset within the handle to start aliasing from, in pages. -+ * Not used with BASE_MEM_WRITE_ALLOC_PAGES_HANDLE. -+ * @length Length to alias, in pages. For BASE_MEM_WRITE_ALLOC_PAGES_HANDLE -+ * specifies the number of times the special page is needed. -+ */ -+struct base_mem_aliasing_info { -+ base_mem_handle handle; -+ u64 offset; -+ u64 length; -+}; -+ -+/** -+ * struct base_jit_alloc_info - Structure which describes a JIT allocation -+ * request. -+ * @gpu_alloc_addr: The GPU virtual address to write the JIT -+ * allocated GPU virtual address to. -+ * @va_pages: The minimum number of virtual pages required. -+ * @commit_pages: The minimum number of physical pages which -+ * should back the allocation. -+ * @extent: Granularity of physical pages to grow the -+ * allocation by during a fault. -+ * @id: Unique ID provided by the caller, this is used -+ * to pair allocation and free requests. -+ * Zero is not a valid value. -+ */ -+struct base_jit_alloc_info { -+ u64 gpu_alloc_addr; -+ u64 va_pages; -+ u64 commit_pages; -+ u64 extent; -+ u8 id; -+}; -+ -+/** -+ * @brief Job dependency type. -+ * -+ * A flags field will be inserted into the atom structure to specify whether a dependency is a data or -+ * ordering dependency (by putting it before/after 'core_req' in the structure it should be possible to add without -+ * changing the structure size). -+ * When the flag is set for a particular dependency to signal that it is an ordering only dependency then -+ * errors will not be propagated. -+ */ -+typedef u8 base_jd_dep_type; -+ -+ -+#define BASE_JD_DEP_TYPE_INVALID (0) /**< Invalid dependency */ -+#define BASE_JD_DEP_TYPE_DATA (1U << 0) /**< Data dependency */ -+#define BASE_JD_DEP_TYPE_ORDER (1U << 1) /**< Order dependency */ -+ -+/** -+ * @brief Job chain hardware requirements. -+ * -+ * A job chain must specify what GPU features it needs to allow the -+ * driver to schedule the job correctly. By not specifying the -+ * correct settings can/will cause an early job termination. Multiple -+ * values can be ORed together to specify multiple requirements. -+ * Special case is ::BASE_JD_REQ_DEP, which is used to express complex -+ * dependencies, and that doesn't execute anything on the hardware. -+ */ -+typedef u32 base_jd_core_req; -+ -+/* Requirements that come from the HW */ -+ -+/** -+ * No requirement, dependency only -+ */ -+#define BASE_JD_REQ_DEP ((base_jd_core_req)0) -+ -+/** -+ * Requires fragment shaders -+ */ -+#define BASE_JD_REQ_FS ((base_jd_core_req)1 << 0) -+ -+/** -+ * Requires compute shaders -+ * This covers any of the following Midgard Job types: -+ * - Vertex Shader Job -+ * - Geometry Shader Job -+ * - An actual Compute Shader Job -+ * -+ * Compare this with @ref BASE_JD_REQ_ONLY_COMPUTE, which specifies that the -+ * job is specifically just the "Compute Shader" job type, and not the "Vertex -+ * Shader" nor the "Geometry Shader" job type. -+ */ -+#define BASE_JD_REQ_CS ((base_jd_core_req)1 << 1) -+#define BASE_JD_REQ_T ((base_jd_core_req)1 << 2) /**< Requires tiling */ -+#define BASE_JD_REQ_CF ((base_jd_core_req)1 << 3) /**< Requires cache flushes */ -+#define BASE_JD_REQ_V ((base_jd_core_req)1 << 4) /**< Requires value writeback */ -+ -+/* SW-only requirements - the HW does not expose these as part of the job slot capabilities */ -+ -+/* Requires fragment job with AFBC encoding */ -+#define BASE_JD_REQ_FS_AFBC ((base_jd_core_req)1 << 13) -+ -+/** -+ * SW-only requirement: coalesce completion events. -+ * If this bit is set then completion of this atom will not cause an event to -+ * be sent to userspace, whether successful or not; completion events will be -+ * deferred until an atom completes which does not have this bit set. -+ * -+ * This bit may not be used in combination with BASE_JD_REQ_EXTERNAL_RESOURCES. -+ */ -+#define BASE_JD_REQ_EVENT_COALESCE ((base_jd_core_req)1 << 5) -+ -+/** -+ * SW Only requirement: the job chain requires a coherent core group. We don't -+ * mind which coherent core group is used. -+ */ -+#define BASE_JD_REQ_COHERENT_GROUP ((base_jd_core_req)1 << 6) -+ -+/** -+ * SW Only requirement: The performance counters should be enabled only when -+ * they are needed, to reduce power consumption. -+ */ -+ -+#define BASE_JD_REQ_PERMON ((base_jd_core_req)1 << 7) -+ -+/** -+ * SW Only requirement: External resources are referenced by this atom. -+ * When external resources are referenced no syncsets can be bundled with the atom -+ * but should instead be part of a NULL jobs inserted into the dependency tree. -+ * The first pre_dep object must be configured for the external resouces to use, -+ * the second pre_dep object can be used to create other dependencies. -+ * -+ * This bit may not be used in combination with BASE_JD_REQ_EVENT_COALESCE. -+ */ -+#define BASE_JD_REQ_EXTERNAL_RESOURCES ((base_jd_core_req)1 << 8) -+ -+/** -+ * SW Only requirement: Software defined job. Jobs with this bit set will not be submitted -+ * to the hardware but will cause some action to happen within the driver -+ */ -+#define BASE_JD_REQ_SOFT_JOB ((base_jd_core_req)1 << 9) -+ -+#define BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME (BASE_JD_REQ_SOFT_JOB | 0x1) -+#define BASE_JD_REQ_SOFT_FENCE_TRIGGER (BASE_JD_REQ_SOFT_JOB | 0x2) -+#define BASE_JD_REQ_SOFT_FENCE_WAIT (BASE_JD_REQ_SOFT_JOB | 0x3) -+ -+/** -+ * SW Only requirement : Replay job. -+ * -+ * If the preceding job fails, the replay job will cause the jobs specified in -+ * the list of base_jd_replay_payload pointed to by the jc pointer to be -+ * replayed. -+ * -+ * A replay job will only cause jobs to be replayed up to BASEP_JD_REPLAY_LIMIT -+ * times. If a job fails more than BASEP_JD_REPLAY_LIMIT times then the replay -+ * job is failed, as well as any following dependencies. -+ * -+ * The replayed jobs will require a number of atom IDs. If there are not enough -+ * free atom IDs then the replay job will fail. -+ * -+ * If the preceding job does not fail, then the replay job is returned as -+ * completed. -+ * -+ * The replayed jobs will never be returned to userspace. The preceding failed -+ * job will be returned to userspace as failed; the status of this job should -+ * be ignored. Completion should be determined by the status of the replay soft -+ * job. -+ * -+ * In order for the jobs to be replayed, the job headers will have to be -+ * modified. The Status field will be reset to NOT_STARTED. If the Job Type -+ * field indicates a Vertex Shader Job then it will be changed to Null Job. -+ * -+ * The replayed jobs have the following assumptions : -+ * -+ * - No external resources. Any required external resources will be held by the -+ * replay atom. -+ * - Pre-dependencies are created based on job order. -+ * - Atom numbers are automatically assigned. -+ * - device_nr is set to 0. This is not relevant as -+ * BASE_JD_REQ_SPECIFIC_COHERENT_GROUP should not be set. -+ * - Priority is inherited from the replay job. -+ */ -+#define BASE_JD_REQ_SOFT_REPLAY (BASE_JD_REQ_SOFT_JOB | 0x4) -+/** -+ * SW only requirement: event wait/trigger job. -+ * -+ * - BASE_JD_REQ_SOFT_EVENT_WAIT: this job will block until the event is set. -+ * - BASE_JD_REQ_SOFT_EVENT_SET: this job sets the event, thus unblocks the -+ * other waiting jobs. It completes immediately. -+ * - BASE_JD_REQ_SOFT_EVENT_RESET: this job resets the event, making it -+ * possible for other jobs to wait upon. It completes immediately. -+ */ -+#define BASE_JD_REQ_SOFT_EVENT_WAIT (BASE_JD_REQ_SOFT_JOB | 0x5) -+#define BASE_JD_REQ_SOFT_EVENT_SET (BASE_JD_REQ_SOFT_JOB | 0x6) -+#define BASE_JD_REQ_SOFT_EVENT_RESET (BASE_JD_REQ_SOFT_JOB | 0x7) -+ -+#define BASE_JD_REQ_SOFT_DEBUG_COPY (BASE_JD_REQ_SOFT_JOB | 0x8) -+ -+/** -+ * SW only requirement: Just In Time allocation -+ * -+ * This job requests a JIT allocation based on the request in the -+ * @base_jit_alloc_info structure which is passed via the jc element of -+ * the atom. -+ * -+ * It should be noted that the id entry in @base_jit_alloc_info must not -+ * be reused until it has been released via @BASE_JD_REQ_SOFT_JIT_FREE. -+ * -+ * Should this soft job fail it is expected that a @BASE_JD_REQ_SOFT_JIT_FREE -+ * soft job to free the JIT allocation is still made. -+ * -+ * The job will complete immediately. -+ */ -+#define BASE_JD_REQ_SOFT_JIT_ALLOC (BASE_JD_REQ_SOFT_JOB | 0x9) -+/** -+ * SW only requirement: Just In Time free -+ * -+ * This job requests a JIT allocation created by @BASE_JD_REQ_SOFT_JIT_ALLOC -+ * to be freed. The ID of the JIT allocation is passed via the jc element of -+ * the atom. -+ * -+ * The job will complete immediately. -+ */ -+#define BASE_JD_REQ_SOFT_JIT_FREE (BASE_JD_REQ_SOFT_JOB | 0xa) -+ -+/** -+ * SW only requirement: Map external resource -+ * -+ * This job requests external resource(s) are mapped once the dependencies -+ * of the job have been satisfied. The list of external resources are -+ * passed via the jc element of the atom which is a pointer to a -+ * @base_external_resource_list. -+ */ -+#define BASE_JD_REQ_SOFT_EXT_RES_MAP (BASE_JD_REQ_SOFT_JOB | 0xb) -+/** -+ * SW only requirement: Unmap external resource -+ * -+ * This job requests external resource(s) are unmapped once the dependencies -+ * of the job has been satisfied. The list of external resources are -+ * passed via the jc element of the atom which is a pointer to a -+ * @base_external_resource_list. -+ */ -+#define BASE_JD_REQ_SOFT_EXT_RES_UNMAP (BASE_JD_REQ_SOFT_JOB | 0xc) -+ -+/** -+ * HW Requirement: Requires Compute shaders (but not Vertex or Geometry Shaders) -+ * -+ * This indicates that the Job Chain contains Midgard Jobs of the 'Compute Shaders' type. -+ * -+ * In contrast to @ref BASE_JD_REQ_CS, this does \b not indicate that the Job -+ * Chain contains 'Geometry Shader' or 'Vertex Shader' jobs. -+ */ -+#define BASE_JD_REQ_ONLY_COMPUTE ((base_jd_core_req)1 << 10) -+ -+/** -+ * HW Requirement: Use the base_jd_atom::device_nr field to specify a -+ * particular core group -+ * -+ * If both @ref BASE_JD_REQ_COHERENT_GROUP and this flag are set, this flag takes priority -+ * -+ * This is only guaranteed to work for @ref BASE_JD_REQ_ONLY_COMPUTE atoms. -+ * -+ * If the core availability policy is keeping the required core group turned off, then -+ * the job will fail with a @ref BASE_JD_EVENT_PM_EVENT error code. -+ */ -+#define BASE_JD_REQ_SPECIFIC_COHERENT_GROUP ((base_jd_core_req)1 << 11) -+ -+/** -+ * SW Flag: If this bit is set then the successful completion of this atom -+ * will not cause an event to be sent to userspace -+ */ -+#define BASE_JD_REQ_EVENT_ONLY_ON_FAILURE ((base_jd_core_req)1 << 12) -+ -+/** -+ * SW Flag: If this bit is set then completion of this atom will not cause an -+ * event to be sent to userspace, whether successful or not. -+ */ -+#define BASEP_JD_REQ_EVENT_NEVER ((base_jd_core_req)1 << 14) -+ -+/** -+ * SW Flag: Skip GPU cache clean and invalidation before starting a GPU job. -+ * -+ * If this bit is set then the GPU's cache will not be cleaned and invalidated -+ * until a GPU job starts which does not have this bit set or a job completes -+ * which does not have the @ref BASE_JD_REQ_SKIP_CACHE_END bit set. Do not use if -+ * the CPU may have written to memory addressed by the job since the last job -+ * without this bit set was submitted. -+ */ -+#define BASE_JD_REQ_SKIP_CACHE_START ((base_jd_core_req)1 << 15) -+ -+/** -+ * SW Flag: Skip GPU cache clean and invalidation after a GPU job completes. -+ * -+ * If this bit is set then the GPU's cache will not be cleaned and invalidated -+ * until a GPU job completes which does not have this bit set or a job starts -+ * which does not have the @ref BASE_JD_REQ_SKIP_CACHE_START bti set. Do not use if -+ * the CPU may read from or partially overwrite memory addressed by the job -+ * before the next job without this bit set completes. -+ */ -+#define BASE_JD_REQ_SKIP_CACHE_END ((base_jd_core_req)1 << 16) -+ -+/** -+ * These requirement bits are currently unused in base_jd_core_req -+ */ -+#define BASEP_JD_REQ_RESERVED \ -+ (~(BASE_JD_REQ_ATOM_TYPE | BASE_JD_REQ_EXTERNAL_RESOURCES | \ -+ BASE_JD_REQ_EVENT_ONLY_ON_FAILURE | BASEP_JD_REQ_EVENT_NEVER | \ -+ BASE_JD_REQ_EVENT_COALESCE | \ -+ BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP | \ -+ BASE_JD_REQ_FS_AFBC | BASE_JD_REQ_PERMON | \ -+ BASE_JD_REQ_SKIP_CACHE_START | BASE_JD_REQ_SKIP_CACHE_END)) -+ -+/** -+ * Mask of all bits in base_jd_core_req that control the type of the atom. -+ * -+ * This allows dependency only atoms to have flags set -+ */ -+#define BASE_JD_REQ_ATOM_TYPE \ -+ (BASE_JD_REQ_FS | BASE_JD_REQ_CS | BASE_JD_REQ_T | BASE_JD_REQ_CF | \ -+ BASE_JD_REQ_V | BASE_JD_REQ_SOFT_JOB | BASE_JD_REQ_ONLY_COMPUTE) -+ -+/** -+ * Mask of all bits in base_jd_core_req that control the type of a soft job. -+ */ -+#define BASE_JD_REQ_SOFT_JOB_TYPE (BASE_JD_REQ_SOFT_JOB | 0x1f) -+ -+/* -+ * Returns non-zero value if core requirements passed define a soft job or -+ * a dependency only job. -+ */ -+#define BASE_JD_REQ_SOFT_JOB_OR_DEP(core_req) \ -+ ((core_req & BASE_JD_REQ_SOFT_JOB) || \ -+ (core_req & BASE_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_DEP) -+ -+/** -+ * @brief States to model state machine processed by kbasep_js_job_check_ref_cores(), which -+ * handles retaining cores for power management and affinity management. -+ * -+ * The state @ref KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY prevents an attack -+ * where lots of atoms could be submitted before powerup, and each has an -+ * affinity chosen that causes other atoms to have an affinity -+ * violation. Whilst the affinity was not causing violations at the time it -+ * was chosen, it could cause violations thereafter. For example, 1000 jobs -+ * could have had their affinity chosen during the powerup time, so any of -+ * those 1000 jobs could cause an affinity violation later on. -+ * -+ * The attack would otherwise occur because other atoms/contexts have to wait for: -+ * -# the currently running atoms (which are causing the violation) to -+ * finish -+ * -# and, the atoms that had their affinity chosen during powerup to -+ * finish. These are run preferentially because they don't cause a -+ * violation, but instead continue to cause the violation in others. -+ * -# or, the attacker is scheduled out (which might not happen for just 2 -+ * contexts) -+ * -+ * By re-choosing the affinity (which is designed to avoid violations at the -+ * time it's chosen), we break condition (2) of the wait, which minimizes the -+ * problem to just waiting for current jobs to finish (which can be bounded if -+ * the Job Scheduling Policy has a timer). -+ */ -+enum kbase_atom_coreref_state { -+ /** Starting state: No affinity chosen, and cores must be requested. kbase_jd_atom::affinity==0 */ -+ KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED, -+ /** Cores requested, but waiting for them to be powered. Requested cores given by kbase_jd_atom::affinity */ -+ KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES, -+ /** Cores given by kbase_jd_atom::affinity are powered, but affinity might be out-of-date, so must recheck */ -+ KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY, -+ /** Cores given by kbase_jd_atom::affinity are powered, and affinity is up-to-date, but must check for violations */ -+ KBASE_ATOM_COREREF_STATE_CHECK_AFFINITY_VIOLATIONS, -+ /** Cores are powered, kbase_jd_atom::affinity up-to-date, no affinity violations: atom can be submitted to HW */ -+ KBASE_ATOM_COREREF_STATE_READY -+}; -+ -+/* -+ * Base Atom priority -+ * -+ * Only certain priority levels are actually implemented, as specified by the -+ * BASE_JD_PRIO_<...> definitions below. It is undefined to use a priority -+ * level that is not one of those defined below. -+ * -+ * Priority levels only affect scheduling between atoms of the same type within -+ * a base context, and only after the atoms have had dependencies resolved. -+ * Fragment atoms does not affect non-frament atoms with lower priorities, and -+ * the other way around. For example, a low priority atom that has had its -+ * dependencies resolved might run before a higher priority atom that has not -+ * had its dependencies resolved. -+ * -+ * The scheduling between base contexts/processes and between atoms from -+ * different base contexts/processes is unaffected by atom priority. -+ * -+ * The atoms are scheduled as follows with respect to their priorities: -+ * - Let atoms 'X' and 'Y' be for the same job slot who have dependencies -+ * resolved, and atom 'X' has a higher priority than atom 'Y' -+ * - If atom 'Y' is currently running on the HW, then it is interrupted to -+ * allow atom 'X' to run soon after -+ * - If instead neither atom 'Y' nor atom 'X' are running, then when choosing -+ * the next atom to run, atom 'X' will always be chosen instead of atom 'Y' -+ * - Any two atoms that have the same priority could run in any order with -+ * respect to each other. That is, there is no ordering constraint between -+ * atoms of the same priority. -+ */ -+typedef u8 base_jd_prio; -+ -+/* Medium atom priority. This is a priority higher than BASE_JD_PRIO_LOW */ -+#define BASE_JD_PRIO_MEDIUM ((base_jd_prio)0) -+/* High atom priority. This is a priority higher than BASE_JD_PRIO_MEDIUM and -+ * BASE_JD_PRIO_LOW */ -+#define BASE_JD_PRIO_HIGH ((base_jd_prio)1) -+/* Low atom priority. */ -+#define BASE_JD_PRIO_LOW ((base_jd_prio)2) -+ -+/* Count of the number of priority levels. This itself is not a valid -+ * base_jd_prio setting */ -+#define BASE_JD_NR_PRIO_LEVELS 3 -+ -+enum kbase_jd_atom_state { -+ /** Atom is not used */ -+ KBASE_JD_ATOM_STATE_UNUSED, -+ /** Atom is queued in JD */ -+ KBASE_JD_ATOM_STATE_QUEUED, -+ /** Atom has been given to JS (is runnable/running) */ -+ KBASE_JD_ATOM_STATE_IN_JS, -+ /** Atom has been completed, but not yet handed back to job dispatcher -+ * for dependency resolution */ -+ KBASE_JD_ATOM_STATE_HW_COMPLETED, -+ /** Atom has been completed, but not yet handed back to userspace */ -+ KBASE_JD_ATOM_STATE_COMPLETED -+}; -+ -+typedef u8 base_atom_id; /**< Type big enough to store an atom number in */ -+ -+struct base_dependency { -+ base_atom_id atom_id; /**< An atom number */ -+ base_jd_dep_type dependency_type; /**< Dependency type */ -+}; -+ -+/* This structure has changed since UK 10.2 for which base_jd_core_req was a u16 value. -+ * In order to keep the size of the structure same, padding field has been adjusted -+ * accordingly and core_req field of a u32 type (to which UK 10.3 base_jd_core_req defines) -+ * is added at the end of the structure. Place in the structure previously occupied by u16 core_req -+ * is kept but renamed to compat_core_req and as such it can be used in ioctl call for job submission -+ * as long as UK 10.2 legacy is supported. Once when this support ends, this field can be left -+ * for possible future use. */ -+typedef struct base_jd_atom_v2 { -+ u64 jc; /**< job-chain GPU address */ -+ struct base_jd_udata udata; /**< user data */ -+ u64 extres_list; /**< list of external resources */ -+ u16 nr_extres; /**< nr of external resources */ -+ u16 compat_core_req; /**< core requirements which correspond to the legacy support for UK 10.2 */ -+ struct base_dependency pre_dep[2]; /**< pre-dependencies, one need to use SETTER function to assign this field, -+ this is done in order to reduce possibility of improper assigment of a dependency field */ -+ base_atom_id atom_number; /**< unique number to identify the atom */ -+ base_jd_prio prio; /**< Atom priority. Refer to @ref base_jd_prio for more details */ -+ u8 device_nr; /**< coregroup when BASE_JD_REQ_SPECIFIC_COHERENT_GROUP specified */ -+ u8 padding[1]; -+ base_jd_core_req core_req; /**< core requirements */ -+} base_jd_atom_v2; -+ -+typedef enum base_external_resource_access { -+ BASE_EXT_RES_ACCESS_SHARED, -+ BASE_EXT_RES_ACCESS_EXCLUSIVE -+} base_external_resource_access; -+ -+typedef struct base_external_resource { -+ u64 ext_resource; -+} base_external_resource; -+ -+ -+/** -+ * The maximum number of external resources which can be mapped/unmapped -+ * in a single request. -+ */ -+#define BASE_EXT_RES_COUNT_MAX 10 -+ -+/** -+ * struct base_external_resource_list - Structure which describes a list of -+ * external resources. -+ * @count: The number of resources. -+ * @ext_res: Array of external resources which is -+ * sized at allocation time. -+ */ -+struct base_external_resource_list { -+ u64 count; -+ struct base_external_resource ext_res[1]; -+}; -+ -+struct base_jd_debug_copy_buffer { -+ u64 address; -+ u64 size; -+ struct base_external_resource extres; -+}; -+ -+/** -+ * @brief Setter for a dependency structure -+ * -+ * @param[in] dep The kbase jd atom dependency to be initialized. -+ * @param id The atom_id to be assigned. -+ * @param dep_type The dep_type to be assigned. -+ * -+ */ -+static inline void base_jd_atom_dep_set(struct base_dependency *dep, -+ base_atom_id id, base_jd_dep_type dep_type) -+{ -+ LOCAL_ASSERT(dep != NULL); -+ -+ /* -+ * make sure we don't set not allowed combinations -+ * of atom_id/dependency_type. -+ */ -+ LOCAL_ASSERT((id == 0 && dep_type == BASE_JD_DEP_TYPE_INVALID) || -+ (id > 0 && dep_type != BASE_JD_DEP_TYPE_INVALID)); -+ -+ dep->atom_id = id; -+ dep->dependency_type = dep_type; -+} -+ -+/** -+ * @brief Make a copy of a dependency structure -+ * -+ * @param[in,out] dep The kbase jd atom dependency to be written. -+ * @param[in] from The dependency to make a copy from. -+ * -+ */ -+static inline void base_jd_atom_dep_copy(struct base_dependency *dep, -+ const struct base_dependency *from) -+{ -+ LOCAL_ASSERT(dep != NULL); -+ -+ base_jd_atom_dep_set(dep, from->atom_id, from->dependency_type); -+} -+ -+/** -+ * @brief Soft-atom fence trigger setup. -+ * -+ * Sets up an atom to be a SW-only atom signaling a fence -+ * when it reaches the run state. -+ * -+ * Using the existing base dependency system the fence can -+ * be set to trigger when a GPU job has finished. -+ * -+ * The base fence object must not be terminated until the atom -+ * has been submitted to @a base_jd_submit and @a base_jd_submit has returned. -+ * -+ * @a fence must be a valid fence set up with @a base_fence_init. -+ * Calling this function with a uninitialized fence results in undefined behavior. -+ * -+ * @param[out] atom A pre-allocated atom to configure as a fence trigger SW atom -+ * @param[in] fence The base fence object to trigger. -+ */ -+static inline void base_jd_fence_trigger_setup_v2(struct base_jd_atom_v2 *atom, struct base_fence *fence) -+{ -+ LOCAL_ASSERT(atom); -+ LOCAL_ASSERT(fence); -+ LOCAL_ASSERT(fence->basep.fd == INVALID_PLATFORM_FENCE); -+ LOCAL_ASSERT(fence->basep.stream_fd >= 0); -+ atom->jc = (uintptr_t) fence; -+ atom->core_req = BASE_JD_REQ_SOFT_FENCE_TRIGGER; -+} -+ -+/** -+ * @brief Soft-atom fence wait setup. -+ * -+ * Sets up an atom to be a SW-only atom waiting on a fence. -+ * When the fence becomes triggered the atom becomes runnable -+ * and completes immediately. -+ * -+ * Using the existing base dependency system the fence can -+ * be set to block a GPU job until it has been triggered. -+ * -+ * The base fence object must not be terminated until the atom -+ * has been submitted to @a base_jd_submit and @a base_jd_submit has returned. -+ * -+ * @a fence must be a valid fence set up with @a base_fence_init or @a base_fence_import. -+ * Calling this function with a uninitialized fence results in undefined behavior. -+ * -+ * @param[out] atom A pre-allocated atom to configure as a fence wait SW atom -+ * @param[in] fence The base fence object to wait on -+ */ -+static inline void base_jd_fence_wait_setup_v2(struct base_jd_atom_v2 *atom, struct base_fence *fence) -+{ -+ LOCAL_ASSERT(atom); -+ LOCAL_ASSERT(fence); -+ LOCAL_ASSERT(fence->basep.fd >= 0); -+ atom->jc = (uintptr_t) fence; -+ atom->core_req = BASE_JD_REQ_SOFT_FENCE_WAIT; -+} -+ -+/** -+ * @brief External resource info initialization. -+ * -+ * Sets up an external resource object to reference -+ * a memory allocation and the type of access requested. -+ * -+ * @param[in] res The resource object to initialize -+ * @param handle The handle to the imported memory object, must be -+ * obtained by calling @ref base_mem_as_import_handle(). -+ * @param access The type of access requested -+ */ -+static inline void base_external_resource_init(struct base_external_resource *res, struct base_import_handle handle, base_external_resource_access access) -+{ -+ u64 address; -+ -+ address = handle.basep.handle; -+ -+ LOCAL_ASSERT(res != NULL); -+ LOCAL_ASSERT(0 == (address & LOCAL_PAGE_LSB)); -+ LOCAL_ASSERT(access == BASE_EXT_RES_ACCESS_SHARED || access == BASE_EXT_RES_ACCESS_EXCLUSIVE); -+ -+ res->ext_resource = address | (access & LOCAL_PAGE_LSB); -+} -+ -+/** -+ * @brief Job chain event code bits -+ * Defines the bits used to create ::base_jd_event_code -+ */ -+enum { -+ BASE_JD_SW_EVENT_KERNEL = (1u << 15), /**< Kernel side event */ -+ BASE_JD_SW_EVENT = (1u << 14), /**< SW defined event */ -+ BASE_JD_SW_EVENT_SUCCESS = (1u << 13), /**< Event idicates success (SW events only) */ -+ BASE_JD_SW_EVENT_JOB = (0u << 11), /**< Job related event */ -+ BASE_JD_SW_EVENT_BAG = (1u << 11), /**< Bag related event */ -+ BASE_JD_SW_EVENT_INFO = (2u << 11), /**< Misc/info event */ -+ BASE_JD_SW_EVENT_RESERVED = (3u << 11), /**< Reserved event type */ -+ BASE_JD_SW_EVENT_TYPE_MASK = (3u << 11) /**< Mask to extract the type from an event code */ -+}; -+ -+/** -+ * @brief Job chain event codes -+ * -+ * HW and low-level SW events are represented by event codes. -+ * The status of jobs which succeeded are also represented by -+ * an event code (see ::BASE_JD_EVENT_DONE). -+ * Events are usually reported as part of a ::base_jd_event. -+ * -+ * The event codes are encoded in the following way: -+ * @li 10:0 - subtype -+ * @li 12:11 - type -+ * @li 13 - SW success (only valid if the SW bit is set) -+ * @li 14 - SW event (HW event if not set) -+ * @li 15 - Kernel event (should never be seen in userspace) -+ * -+ * Events are split up into ranges as follows: -+ * - BASE_JD_EVENT_RANGE_\_START -+ * - BASE_JD_EVENT_RANGE_\_END -+ * -+ * \a code is in \'s range when: -+ * - BASE_JD_EVENT_RANGE_\_START <= code < BASE_JD_EVENT_RANGE_\_END -+ * -+ * Ranges can be asserted for adjacency by testing that the END of the previous -+ * is equal to the START of the next. This is useful for optimizing some tests -+ * for range. -+ * -+ * A limitation is that the last member of this enum must explicitly be handled -+ * (with an assert-unreachable statement) in switch statements that use -+ * variables of this type. Otherwise, the compiler warns that we have not -+ * handled that enum value. -+ */ -+typedef enum base_jd_event_code { -+ /* HW defined exceptions */ -+ -+ /** Start of HW Non-fault status codes -+ * -+ * @note Obscurely, BASE_JD_EVENT_TERMINATED indicates a real fault, -+ * because the job was hard-stopped -+ */ -+ BASE_JD_EVENT_RANGE_HW_NONFAULT_START = 0, -+ -+ /* non-fatal exceptions */ -+ BASE_JD_EVENT_NOT_STARTED = 0x00, /**< Can't be seen by userspace, treated as 'previous job done' */ -+ BASE_JD_EVENT_DONE = 0x01, -+ BASE_JD_EVENT_STOPPED = 0x03, /**< Can't be seen by userspace, becomes TERMINATED, DONE or JOB_CANCELLED */ -+ BASE_JD_EVENT_TERMINATED = 0x04, /**< This is actually a fault status code - the job was hard stopped */ -+ BASE_JD_EVENT_ACTIVE = 0x08, /**< Can't be seen by userspace, jobs only returned on complete/fail/cancel */ -+ -+ /** End of HW Non-fault status codes -+ * -+ * @note Obscurely, BASE_JD_EVENT_TERMINATED indicates a real fault, -+ * because the job was hard-stopped -+ */ -+ BASE_JD_EVENT_RANGE_HW_NONFAULT_END = 0x40, -+ -+ /** Start of HW fault and SW Error status codes */ -+ BASE_JD_EVENT_RANGE_HW_FAULT_OR_SW_ERROR_START = 0x40, -+ -+ /* job exceptions */ -+ BASE_JD_EVENT_JOB_CONFIG_FAULT = 0x40, -+ BASE_JD_EVENT_JOB_POWER_FAULT = 0x41, -+ BASE_JD_EVENT_JOB_READ_FAULT = 0x42, -+ BASE_JD_EVENT_JOB_WRITE_FAULT = 0x43, -+ BASE_JD_EVENT_JOB_AFFINITY_FAULT = 0x44, -+ BASE_JD_EVENT_JOB_BUS_FAULT = 0x48, -+ BASE_JD_EVENT_INSTR_INVALID_PC = 0x50, -+ BASE_JD_EVENT_INSTR_INVALID_ENC = 0x51, -+ BASE_JD_EVENT_INSTR_TYPE_MISMATCH = 0x52, -+ BASE_JD_EVENT_INSTR_OPERAND_FAULT = 0x53, -+ BASE_JD_EVENT_INSTR_TLS_FAULT = 0x54, -+ BASE_JD_EVENT_INSTR_BARRIER_FAULT = 0x55, -+ BASE_JD_EVENT_INSTR_ALIGN_FAULT = 0x56, -+ BASE_JD_EVENT_DATA_INVALID_FAULT = 0x58, -+ BASE_JD_EVENT_TILE_RANGE_FAULT = 0x59, -+ BASE_JD_EVENT_STATE_FAULT = 0x5A, -+ BASE_JD_EVENT_OUT_OF_MEMORY = 0x60, -+ BASE_JD_EVENT_UNKNOWN = 0x7F, -+ -+ /* GPU exceptions */ -+ BASE_JD_EVENT_DELAYED_BUS_FAULT = 0x80, -+ BASE_JD_EVENT_SHAREABILITY_FAULT = 0x88, -+ -+ /* MMU exceptions */ -+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL1 = 0xC1, -+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL2 = 0xC2, -+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL3 = 0xC3, -+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL4 = 0xC4, -+ BASE_JD_EVENT_PERMISSION_FAULT = 0xC8, -+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL1 = 0xD1, -+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL2 = 0xD2, -+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL3 = 0xD3, -+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL4 = 0xD4, -+ BASE_JD_EVENT_ACCESS_FLAG = 0xD8, -+ -+ /* SW defined exceptions */ -+ BASE_JD_EVENT_MEM_GROWTH_FAILED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x000, -+ BASE_JD_EVENT_TIMED_OUT = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x001, -+ BASE_JD_EVENT_JOB_CANCELLED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x002, -+ BASE_JD_EVENT_JOB_INVALID = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x003, -+ BASE_JD_EVENT_PM_EVENT = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x004, -+ BASE_JD_EVENT_FORCE_REPLAY = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x005, -+ -+ BASE_JD_EVENT_BAG_INVALID = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_BAG | 0x003, -+ -+ /** End of HW fault and SW Error status codes */ -+ BASE_JD_EVENT_RANGE_HW_FAULT_OR_SW_ERROR_END = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_RESERVED | 0x3FF, -+ -+ /** Start of SW Success status codes */ -+ BASE_JD_EVENT_RANGE_SW_SUCCESS_START = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | 0x000, -+ -+ BASE_JD_EVENT_PROGRESS_REPORT = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_JOB | 0x000, -+ BASE_JD_EVENT_BAG_DONE = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_BAG | 0x000, -+ BASE_JD_EVENT_DRV_TERMINATED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_INFO | 0x000, -+ -+ /** End of SW Success status codes */ -+ BASE_JD_EVENT_RANGE_SW_SUCCESS_END = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_RESERVED | 0x3FF, -+ -+ /** Start of Kernel-only status codes. Such codes are never returned to user-space */ -+ BASE_JD_EVENT_RANGE_KERNEL_ONLY_START = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_KERNEL | 0x000, -+ BASE_JD_EVENT_REMOVED_FROM_NEXT = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_KERNEL | BASE_JD_SW_EVENT_JOB | 0x000, -+ -+ /** End of Kernel-only status codes. */ -+ BASE_JD_EVENT_RANGE_KERNEL_ONLY_END = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_KERNEL | BASE_JD_SW_EVENT_RESERVED | 0x3FF -+} base_jd_event_code; -+ -+/** -+ * @brief Event reporting structure -+ * -+ * This structure is used by the kernel driver to report information -+ * about GPU events. The can either be HW-specific events or low-level -+ * SW events, such as job-chain completion. -+ * -+ * The event code contains an event type field which can be extracted -+ * by ANDing with ::BASE_JD_SW_EVENT_TYPE_MASK. -+ * -+ * Based on the event type base_jd_event::data holds: -+ * @li ::BASE_JD_SW_EVENT_JOB : the offset in the ring-buffer for the completed -+ * job-chain -+ * @li ::BASE_JD_SW_EVENT_BAG : The address of the ::base_jd_bag that has -+ * been completed (ie all contained job-chains have been completed). -+ * @li ::BASE_JD_SW_EVENT_INFO : base_jd_event::data not used -+ */ -+typedef struct base_jd_event_v2 { -+ base_jd_event_code event_code; /**< event code */ -+ base_atom_id atom_number; /**< the atom number that has completed */ -+ struct base_jd_udata udata; /**< user data */ -+} base_jd_event_v2; -+ -+/** -+ * Padding required to ensure that the @ref struct base_dump_cpu_gpu_counters structure fills -+ * a full cache line. -+ */ -+ -+#define BASE_CPU_GPU_CACHE_LINE_PADDING (36) -+ -+ -+/** -+ * @brief Structure for BASE_JD_REQ_SOFT_DUMP_CPU_GPU_COUNTERS jobs. -+ * -+ * This structure is stored into the memory pointed to by the @c jc field of @ref base_jd_atom. -+ * -+ * This structure must be padded to ensure that it will occupy whole cache lines. This is to avoid -+ * cases where access to pages containing the structure is shared between cached and un-cached -+ * memory regions, which would cause memory corruption. Here we set the structure size to be 64 bytes -+ * which is the cache line for ARM A15 processors. -+ */ -+ -+typedef struct base_dump_cpu_gpu_counters { -+ u64 system_time; -+ u64 cycle_counter; -+ u64 sec; -+ u32 usec; -+ u8 padding[BASE_CPU_GPU_CACHE_LINE_PADDING]; -+} base_dump_cpu_gpu_counters; -+ -+ -+ -+/** @} end group base_user_api_job_dispatch */ -+ -+#define GPU_MAX_JOB_SLOTS 16 -+ -+/** -+ * @page page_base_user_api_gpuprops User-side Base GPU Property Query API -+ * -+ * The User-side Base GPU Property Query API encapsulates two -+ * sub-modules: -+ * -+ * - @ref base_user_api_gpuprops_dyn "Dynamic GPU Properties" -+ * - @ref base_plat_config_gpuprops "Base Platform Config GPU Properties" -+ * -+ * There is a related third module outside of Base, which is owned by the MIDG -+ * module: -+ * - @ref gpu_props_static "Midgard Compile-time GPU Properties" -+ * -+ * Base only deals with properties that vary between different Midgard -+ * implementations - the Dynamic GPU properties and the Platform Config -+ * properties. -+ * -+ * For properties that are constant for the Midgard Architecture, refer to the -+ * MIDG module. However, we will discuss their relevance here just to -+ * provide background information. -+ * -+ * @section sec_base_user_api_gpuprops_about About the GPU Properties in Base and MIDG modules -+ * -+ * The compile-time properties (Platform Config, Midgard Compile-time -+ * properties) are exposed as pre-processor macros. -+ * -+ * Complementing the compile-time properties are the Dynamic GPU -+ * Properties, which act as a conduit for the Midgard Configuration -+ * Discovery. -+ * -+ * In general, the dynamic properties are present to verify that the platform -+ * has been configured correctly with the right set of Platform Config -+ * Compile-time Properties. -+ * -+ * As a consistent guide across the entire DDK, the choice for dynamic or -+ * compile-time should consider the following, in order: -+ * -# Can the code be written so that it doesn't need to know the -+ * implementation limits at all? -+ * -# If you need the limits, get the information from the Dynamic Property -+ * lookup. This should be done once as you fetch the context, and then cached -+ * as part of the context data structure, so it's cheap to access. -+ * -# If there's a clear and arguable inefficiency in using Dynamic Properties, -+ * then use a Compile-Time Property (Platform Config, or Midgard Compile-time -+ * property). Examples of where this might be sensible follow: -+ * - Part of a critical inner-loop -+ * - Frequent re-use throughout the driver, causing significant extra load -+ * instructions or control flow that would be worthwhile optimizing out. -+ * -+ * We cannot provide an exhaustive set of examples, neither can we provide a -+ * rule for every possible situation. Use common sense, and think about: what -+ * the rest of the driver will be doing; how the compiler might represent the -+ * value if it is a compile-time constant; whether an OEM shipping multiple -+ * devices would benefit much more from a single DDK binary, instead of -+ * insignificant micro-optimizations. -+ * -+ * @section sec_base_user_api_gpuprops_dyn Dynamic GPU Properties -+ * -+ * Dynamic GPU properties are presented in two sets: -+ * -# the commonly used properties in @ref base_gpu_props, which have been -+ * unpacked from GPU register bitfields. -+ * -# The full set of raw, unprocessed properties in @ref gpu_raw_gpu_props -+ * (also a member of @ref base_gpu_props). All of these are presented in -+ * the packed form, as presented by the GPU registers themselves. -+ * -+ * @usecase The raw properties in @ref gpu_raw_gpu_props are necessary to -+ * allow a user of the Mali Tools (e.g. PAT) to determine "Why is this device -+ * behaving differently?". In this case, all information about the -+ * configuration is potentially useful, but it does not need to be processed -+ * by the driver. Instead, the raw registers can be processed by the Mali -+ * Tools software on the host PC. -+ * -+ * The properties returned extend the Midgard Configuration Discovery -+ * registers. For example, GPU clock speed is not specified in the Midgard -+ * Architecture, but is necessary for OpenCL's clGetDeviceInfo() function. -+ * -+ * The GPU properties are obtained by a call to -+ * _mali_base_get_gpu_props(). This simply returns a pointer to a const -+ * base_gpu_props structure. It is constant for the life of a base -+ * context. Multiple calls to _mali_base_get_gpu_props() to a base context -+ * return the same pointer to a constant structure. This avoids cache pollution -+ * of the common data. -+ * -+ * This pointer must not be freed, because it does not point to the start of a -+ * region allocated by the memory allocator; instead, just close the @ref -+ * base_context. -+ * -+ * -+ * @section sec_base_user_api_gpuprops_config Platform Config Compile-time Properties -+ * -+ * The Platform Config File sets up gpu properties that are specific to a -+ * certain platform. Properties that are 'Implementation Defined' in the -+ * Midgard Architecture spec are placed here. -+ * -+ * @note Reference configurations are provided for Midgard Implementations, such as -+ * the Mali-T600 family. The customer need not repeat this information, and can select one of -+ * these reference configurations. For example, VA_BITS, PA_BITS and the -+ * maximum number of samples per pixel might vary between Midgard Implementations, but -+ * \b not for platforms using the Mali-T604. This information is placed in -+ * the reference configuration files. -+ * -+ * The System Integrator creates the following structure: -+ * - platform_XYZ -+ * - platform_XYZ/plat -+ * - platform_XYZ/plat/plat_config.h -+ * -+ * They then edit plat_config.h, using the example plat_config.h files as a -+ * guide. -+ * -+ * At the very least, the customer must set @ref CONFIG_GPU_CORE_TYPE, and will -+ * receive a helpful \#error message if they do not do this correctly. This -+ * selects the Reference Configuration for the Midgard Implementation. The rationale -+ * behind this decision (against asking the customer to write \#include -+ * in their plat_config.h) is as follows: -+ * - This mechanism 'looks' like a regular config file (such as Linux's -+ * .config) -+ * - It is difficult to get wrong in a way that will produce strange build -+ * errors: -+ * - They need not know where the mali_t600.h, other_midg_gpu.h etc. files are stored - and -+ * so they won't accidentally pick another file with 'mali_t600' in its name -+ * - When the build doesn't work, the System Integrator may think the DDK is -+ * doesn't work, and attempt to fix it themselves: -+ * - For the @ref CONFIG_GPU_CORE_TYPE mechanism, the only way to get past the -+ * error is to set @ref CONFIG_GPU_CORE_TYPE, and this is what the \#error tells -+ * you. -+ * - For a \#include mechanism, checks must still be made elsewhere, which the -+ * System Integrator may try working around by setting \#defines (such as -+ * VA_BITS) themselves in their plat_config.h. In the worst case, they may -+ * set the prevention-mechanism \#define of -+ * "A_CORRECT_MIDGARD_CORE_WAS_CHOSEN". -+ * - In this case, they would believe they are on the right track, because -+ * the build progresses with their fix, but with errors elsewhere. -+ * -+ * However, there is nothing to prevent the customer using \#include to organize -+ * their own configurations files hierarchically. -+ * -+ * The mechanism for the header file processing is as follows: -+ * -+ * @dot -+ digraph plat_config_mechanism { -+ rankdir=BT -+ size="6,6" -+ -+ "mali_base.h"; -+ "gpu/mali_gpu.h"; -+ -+ node [ shape=box ]; -+ { -+ rank = same; ordering = out; -+ -+ "gpu/mali_gpu_props.h"; -+ "base/midg_gpus/mali_t600.h"; -+ "base/midg_gpus/other_midg_gpu.h"; -+ } -+ { rank = same; "plat/plat_config.h"; } -+ { -+ rank = same; -+ "gpu/mali_gpu.h" [ shape=box ]; -+ gpu_chooser [ label="" style="invisible" width=0 height=0 fixedsize=true ]; -+ select_gpu [ label="Mali-T600 | Other\n(select_gpu.h)" shape=polygon,sides=4,distortion=0.25 width=3.3 height=0.99 fixedsize=true ] ; -+ } -+ node [ shape=box ]; -+ { rank = same; "plat/plat_config.h"; } -+ { rank = same; "mali_base.h"; } -+ -+ "mali_base.h" -> "gpu/mali_gpu.h" -> "gpu/mali_gpu_props.h"; -+ "mali_base.h" -> "plat/plat_config.h" ; -+ "mali_base.h" -> select_gpu ; -+ -+ "plat/plat_config.h" -> gpu_chooser [style="dotted,bold" dir=none weight=4] ; -+ gpu_chooser -> select_gpu [style="dotted,bold"] ; -+ -+ select_gpu -> "base/midg_gpus/mali_t600.h" ; -+ select_gpu -> "base/midg_gpus/other_midg_gpu.h" ; -+ } -+ @enddot -+ * -+ * -+ * @section sec_base_user_api_gpuprops_kernel Kernel Operation -+ * -+ * During Base Context Create time, user-side makes a single kernel call: -+ * - A call to fill user memory with GPU information structures -+ * -+ * The kernel-side will fill the provided the entire processed @ref base_gpu_props -+ * structure, because this information is required in both -+ * user and kernel side; it does not make sense to decode it twice. -+ * -+ * Coherency groups must be derived from the bitmasks, but this can be done -+ * kernel side, and just once at kernel startup: Coherency groups must already -+ * be known kernel-side, to support chains that specify a 'Only Coherent Group' -+ * SW requirement, or 'Only Coherent Group with Tiler' SW requirement. -+ * -+ * @section sec_base_user_api_gpuprops_cocalc Coherency Group calculation -+ * Creation of the coherent group data is done at device-driver startup, and so -+ * is one-time. This will most likely involve a loop with CLZ, shifting, and -+ * bit clearing on the L2_PRESENT mask, depending on whether the -+ * system is L2 Coherent. The number of shader cores is done by a -+ * population count, since faulty cores may be disabled during production, -+ * producing a non-contiguous mask. -+ * -+ * The memory requirements for this algorithm can be determined either by a u64 -+ * population count on the L2_PRESENT mask (a LUT helper already is -+ * required for the above), or simple assumption that there can be no more than -+ * 16 coherent groups, since core groups are typically 4 cores. -+ */ -+ -+/** -+ * @addtogroup base_user_api_gpuprops User-side Base GPU Property Query APIs -+ * @{ -+ */ -+ -+/** -+ * @addtogroup base_user_api_gpuprops_dyn Dynamic HW Properties -+ * @{ -+ */ -+ -+#define BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS 3 -+ -+#define BASE_MAX_COHERENT_GROUPS 16 -+ -+struct mali_base_gpu_core_props { -+ /** -+ * Product specific value. -+ */ -+ u32 product_id; -+ -+ /** -+ * Status of the GPU release. -+ * No defined values, but starts at 0 and increases by one for each -+ * release status (alpha, beta, EAC, etc.). -+ * 4 bit values (0-15). -+ */ -+ u16 version_status; -+ -+ /** -+ * Minor release number of the GPU. "P" part of an "RnPn" release number. -+ * 8 bit values (0-255). -+ */ -+ u16 minor_revision; -+ -+ /** -+ * Major release number of the GPU. "R" part of an "RnPn" release number. -+ * 4 bit values (0-15). -+ */ -+ u16 major_revision; -+ -+ u16 padding; -+ -+ /** -+ * This property is deprecated since it has not contained the real current -+ * value of GPU clock speed. It is kept here only for backwards compatibility. -+ * For the new ioctl interface, it is ignored and is treated as a padding -+ * to keep the structure of the same size and retain the placement of its -+ * members. -+ */ -+ u32 gpu_speed_mhz; -+ -+ /** -+ * @usecase GPU clock max/min speed is required for computing best/worst case -+ * in tasks as job scheduling ant irq_throttling. (It is not specified in the -+ * Midgard Architecture). -+ * Also, GPU clock max speed is used for OpenCL's clGetDeviceInfo() function. -+ */ -+ u32 gpu_freq_khz_max; -+ u32 gpu_freq_khz_min; -+ -+ /** -+ * Size of the shader program counter, in bits. -+ */ -+ u32 log2_program_counter_size; -+ -+ /** -+ * TEXTURE_FEATURES_x registers, as exposed by the GPU. This is a -+ * bitpattern where a set bit indicates that the format is supported. -+ * -+ * Before using a texture format, it is recommended that the corresponding -+ * bit be checked. -+ */ -+ u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS]; -+ -+ /** -+ * Theoretical maximum memory available to the GPU. It is unlikely that a -+ * client will be able to allocate all of this memory for their own -+ * purposes, but this at least provides an upper bound on the memory -+ * available to the GPU. -+ * -+ * This is required for OpenCL's clGetDeviceInfo() call when -+ * CL_DEVICE_GLOBAL_MEM_SIZE is requested, for OpenCL GPU devices. The -+ * client will not be expecting to allocate anywhere near this value. -+ */ -+ u64 gpu_available_memory_size; -+}; -+ -+/** -+ * -+ * More information is possible - but associativity and bus width are not -+ * required by upper-level apis. -+ */ -+struct mali_base_gpu_l2_cache_props { -+ u8 log2_line_size; -+ u8 log2_cache_size; -+ u8 num_l2_slices; /* Number of L2C slices. 1 or higher */ -+ u8 padding[5]; -+}; -+ -+struct mali_base_gpu_tiler_props { -+ u32 bin_size_bytes; /* Max is 4*2^15 */ -+ u32 max_active_levels; /* Max is 2^15 */ -+}; -+ -+/** -+ * GPU threading system details. -+ */ -+struct mali_base_gpu_thread_props { -+ u32 max_threads; /* Max. number of threads per core */ -+ u32 max_workgroup_size; /* Max. number of threads per workgroup */ -+ u32 max_barrier_size; /* Max. number of threads that can synchronize on a simple barrier */ -+ u16 max_registers; /* Total size [1..65535] of the register file available per core. */ -+ u8 max_task_queue; /* Max. tasks [1..255] which may be sent to a core before it becomes blocked. */ -+ u8 max_thread_group_split; /* Max. allowed value [1..15] of the Thread Group Split field. */ -+ u8 impl_tech; /* 0 = Not specified, 1 = Silicon, 2 = FPGA, 3 = SW Model/Emulation */ -+ u8 padding[7]; -+}; -+ -+/** -+ * @brief descriptor for a coherent group -+ * -+ * \c core_mask exposes all cores in that coherent group, and \c num_cores -+ * provides a cached population-count for that mask. -+ * -+ * @note Whilst all cores are exposed in the mask, not all may be available to -+ * the application, depending on the Kernel Power policy. -+ * -+ * @note if u64s must be 8-byte aligned, then this structure has 32-bits of wastage. -+ */ -+struct mali_base_gpu_coherent_group { -+ u64 core_mask; /**< Core restriction mask required for the group */ -+ u16 num_cores; /**< Number of cores in the group */ -+ u16 padding[3]; -+}; -+ -+/** -+ * @brief Coherency group information -+ * -+ * Note that the sizes of the members could be reduced. However, the \c group -+ * member might be 8-byte aligned to ensure the u64 core_mask is 8-byte -+ * aligned, thus leading to wastage if the other members sizes were reduced. -+ * -+ * The groups are sorted by core mask. The core masks are non-repeating and do -+ * not intersect. -+ */ -+struct mali_base_gpu_coherent_group_info { -+ u32 num_groups; -+ -+ /** -+ * Number of core groups (coherent or not) in the GPU. Equivalent to the number of L2 Caches. -+ * -+ * The GPU Counter dumping writes 2048 bytes per core group, regardless of -+ * whether the core groups are coherent or not. Hence this member is needed -+ * to calculate how much memory is required for dumping. -+ * -+ * @note Do not use it to work out how many valid elements are in the -+ * group[] member. Use num_groups instead. -+ */ -+ u32 num_core_groups; -+ -+ /** -+ * Coherency features of the memory, accessed by @ref gpu_mem_features -+ * methods -+ */ -+ u32 coherency; -+ -+ u32 padding; -+ -+ /** -+ * Descriptors of coherent groups -+ */ -+ struct mali_base_gpu_coherent_group group[BASE_MAX_COHERENT_GROUPS]; -+}; -+ -+/** -+ * A complete description of the GPU's Hardware Configuration Discovery -+ * registers. -+ * -+ * The information is presented inefficiently for access. For frequent access, -+ * the values should be better expressed in an unpacked form in the -+ * base_gpu_props structure. -+ * -+ * @usecase The raw properties in @ref gpu_raw_gpu_props are necessary to -+ * allow a user of the Mali Tools (e.g. PAT) to determine "Why is this device -+ * behaving differently?". In this case, all information about the -+ * configuration is potentially useful, but it does not need to be processed -+ * by the driver. Instead, the raw registers can be processed by the Mali -+ * Tools software on the host PC. -+ * -+ */ -+struct gpu_raw_gpu_props { -+ u64 shader_present; -+ u64 tiler_present; -+ u64 l2_present; -+ u64 stack_present; -+ -+ u32 l2_features; -+ u32 suspend_size; /* API 8.2+ */ -+ u32 mem_features; -+ u32 mmu_features; -+ -+ u32 as_present; -+ -+ u32 js_present; -+ u32 js_features[GPU_MAX_JOB_SLOTS]; -+ u32 tiler_features; -+ u32 texture_features[3]; -+ -+ u32 gpu_id; -+ -+ u32 thread_max_threads; -+ u32 thread_max_workgroup_size; -+ u32 thread_max_barrier_size; -+ u32 thread_features; -+ -+ /* -+ * Note: This is the _selected_ coherency mode rather than the -+ * available modes as exposed in the coherency_features register. -+ */ -+ u32 coherency_mode; -+}; -+ -+/** -+ * Return structure for _mali_base_get_gpu_props(). -+ * -+ * NOTE: the raw_props member in this data structure contains the register -+ * values from which the value of the other members are derived. The derived -+ * members exist to allow for efficient access and/or shielding the details -+ * of the layout of the registers. -+ * -+ */ -+typedef struct mali_base_gpu_props { -+ struct mali_base_gpu_core_props core_props; -+ struct mali_base_gpu_l2_cache_props l2_props; -+ u64 unused_1; /* keep for backwards compatibility */ -+ struct mali_base_gpu_tiler_props tiler_props; -+ struct mali_base_gpu_thread_props thread_props; -+ -+ /** This member is large, likely to be 128 bytes */ -+ struct gpu_raw_gpu_props raw_props; -+ -+ /** This must be last member of the structure */ -+ struct mali_base_gpu_coherent_group_info coherency_info; -+} base_gpu_props; -+ -+/** @} end group base_user_api_gpuprops_dyn */ -+ -+/** @} end group base_user_api_gpuprops */ -+ -+/** -+ * @addtogroup base_user_api_core User-side Base core APIs -+ * @{ -+ */ -+ -+/** -+ * \enum base_context_create_flags -+ * -+ * Flags to pass to ::base_context_init. -+ * Flags can be ORed together to enable multiple things. -+ * -+ * These share the same space as BASEP_CONTEXT_FLAG_*, and so must -+ * not collide with them. -+ */ -+enum base_context_create_flags { -+ /** No flags set */ -+ BASE_CONTEXT_CREATE_FLAG_NONE = 0, -+ -+ /** Base context is embedded in a cctx object (flag used for CINSTR software counter macros) */ -+ BASE_CONTEXT_CCTX_EMBEDDED = (1u << 0), -+ -+ /** Base context is a 'System Monitor' context for Hardware counters. -+ * -+ * One important side effect of this is that job submission is disabled. */ -+ BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED = (1u << 1) -+}; -+ -+/** -+ * Bitpattern describing the ::base_context_create_flags that can be passed to base_context_init() -+ */ -+#define BASE_CONTEXT_CREATE_ALLOWED_FLAGS \ -+ (((u32)BASE_CONTEXT_CCTX_EMBEDDED) | \ -+ ((u32)BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED)) -+ -+/** -+ * Bitpattern describing the ::base_context_create_flags that can be passed to the kernel -+ */ -+#define BASE_CONTEXT_CREATE_KERNEL_FLAGS \ -+ ((u32)BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) -+ -+/* -+ * Private flags used on the base context -+ * -+ * These start at bit 31, and run down to zero. -+ * -+ * They share the same space as @ref base_context_create_flags, and so must -+ * not collide with them. -+ */ -+/** Private flag tracking whether job descriptor dumping is disabled */ -+#define BASEP_CONTEXT_FLAG_JOB_DUMP_DISABLED ((u32)(1 << 31)) -+ -+/** @} end group base_user_api_core */ -+ -+/** @} end group base_user_api */ -+ -+/** -+ * @addtogroup base_plat_config_gpuprops Base Platform Config GPU Properties -+ * @{ -+ * -+ * C Pre-processor macros are exposed here to do with Platform -+ * Config. -+ * -+ * These include: -+ * - GPU Properties that are constant on a particular Midgard Family -+ * Implementation e.g. Maximum samples per pixel on Mali-T600. -+ * - General platform config for the GPU, such as the GPU major and minor -+ * revison. -+ */ -+ -+/** @} end group base_plat_config_gpuprops */ -+ -+/** -+ * @addtogroup base_api Base APIs -+ * @{ -+ */ -+ -+/** -+ * @brief The payload for a replay job. This must be in GPU memory. -+ */ -+typedef struct base_jd_replay_payload { -+ /** -+ * Pointer to the first entry in the base_jd_replay_jc list. These -+ * will be replayed in @b reverse order (so that extra ones can be added -+ * to the head in future soft jobs without affecting this soft job) -+ */ -+ u64 tiler_jc_list; -+ -+ /** -+ * Pointer to the fragment job chain. -+ */ -+ u64 fragment_jc; -+ -+ /** -+ * Pointer to the tiler heap free FBD field to be modified. -+ */ -+ u64 tiler_heap_free; -+ -+ /** -+ * Hierarchy mask for the replayed fragment jobs. May be zero. -+ */ -+ u16 fragment_hierarchy_mask; -+ -+ /** -+ * Hierarchy mask for the replayed tiler jobs. May be zero. -+ */ -+ u16 tiler_hierarchy_mask; -+ -+ /** -+ * Default weight to be used for hierarchy levels not in the original -+ * mask. -+ */ -+ u32 hierarchy_default_weight; -+ -+ /** -+ * Core requirements for the tiler job chain -+ */ -+ base_jd_core_req tiler_core_req; -+ -+ /** -+ * Core requirements for the fragment job chain -+ */ -+ base_jd_core_req fragment_core_req; -+} base_jd_replay_payload; -+ -+#ifdef BASE_LEGACY_UK10_2_SUPPORT -+typedef struct base_jd_replay_payload_uk10_2 { -+ u64 tiler_jc_list; -+ u64 fragment_jc; -+ u64 tiler_heap_free; -+ u16 fragment_hierarchy_mask; -+ u16 tiler_hierarchy_mask; -+ u32 hierarchy_default_weight; -+ u16 tiler_core_req; -+ u16 fragment_core_req; -+ u8 padding[4]; -+} base_jd_replay_payload_uk10_2; -+#endif /* BASE_LEGACY_UK10_2_SUPPORT */ -+ -+/** -+ * @brief An entry in the linked list of job chains to be replayed. This must -+ * be in GPU memory. -+ */ -+typedef struct base_jd_replay_jc { -+ /** -+ * Pointer to next entry in the list. A setting of NULL indicates the -+ * end of the list. -+ */ -+ u64 next; -+ -+ /** -+ * Pointer to the job chain. -+ */ -+ u64 jc; -+ -+} base_jd_replay_jc; -+ -+/* Maximum number of jobs allowed in a fragment chain in the payload of a -+ * replay job */ -+#define BASE_JD_REPLAY_F_CHAIN_JOB_LIMIT 256 -+ -+/** @} end group base_api */ -+ -+typedef struct base_profiling_controls { -+ u32 profiling_controls[FBDUMP_CONTROL_MAX]; -+} base_profiling_controls; -+ -+/* Enable additional tracepoints for latency measurements (TL_ATOM_READY, -+ * TL_ATOM_DONE, TL_ATOM_PRIO_CHANGE, TL_ATOM_EVENT_POST) */ -+#define BASE_TLSTREAM_ENABLE_LATENCY_TRACEPOINTS (1 << 0) -+ -+/* Indicate that job dumping is enabled. This could affect certain timers -+ * to account for the performance impact. */ -+#define BASE_TLSTREAM_JOB_DUMPING_ENABLED (1 << 1) -+ -+#define BASE_TLSTREAM_FLAGS_MASK (BASE_TLSTREAM_ENABLE_LATENCY_TRACEPOINTS | \ -+ BASE_TLSTREAM_JOB_DUMPING_ENABLED) -+ -+#endif /* _BASE_KERNEL_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_base_mem_priv.h b/drivers/gpu/arm/midgard/mali_base_mem_priv.h -new file mode 100644 -index 0000000..4a98a72 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_base_mem_priv.h -@@ -0,0 +1,52 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _BASE_MEM_PRIV_H_ -+#define _BASE_MEM_PRIV_H_ -+ -+#define BASE_SYNCSET_OP_MSYNC (1U << 0) -+#define BASE_SYNCSET_OP_CSYNC (1U << 1) -+ -+/* -+ * This structure describe a basic memory coherency operation. -+ * It can either be: -+ * @li a sync from CPU to Memory: -+ * - type = ::BASE_SYNCSET_OP_MSYNC -+ * - mem_handle = a handle to the memory object on which the operation -+ * is taking place -+ * - user_addr = the address of the range to be synced -+ * - size = the amount of data to be synced, in bytes -+ * - offset is ignored. -+ * @li a sync from Memory to CPU: -+ * - type = ::BASE_SYNCSET_OP_CSYNC -+ * - mem_handle = a handle to the memory object on which the operation -+ * is taking place -+ * - user_addr = the address of the range to be synced -+ * - size = the amount of data to be synced, in bytes. -+ * - offset is ignored. -+ */ -+struct basep_syncset { -+ base_mem_handle mem_handle; -+ u64 user_addr; -+ u64 size; -+ u8 type; -+ u8 padding[7]; -+}; -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_base_vendor_specific_func.h b/drivers/gpu/arm/midgard/mali_base_vendor_specific_func.h -new file mode 100644 -index 0000000..be454a2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_base_vendor_specific_func.h -@@ -0,0 +1,24 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010, 2012-2013, 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+#ifndef _BASE_VENDOR_SPEC_FUNC_H_ -+#define _BASE_VENDOR_SPEC_FUNC_H_ -+ -+int kbase_get_vendor_specific_cpu_clock_speed(u32 * const); -+ -+#endif /*_BASE_VENDOR_SPEC_FUNC_H_*/ -diff --git a/drivers/gpu/arm/midgard/mali_kbase.h b/drivers/gpu/arm/midgard/mali_kbase.h -new file mode 100644 -index 0000000..d77f186 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase.h -@@ -0,0 +1,613 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KBASE_H_ -+#define _KBASE_H_ -+ -+#include -+ -+#include -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mali_base_kernel.h" -+#include -+#include -+ -+/* -+ * Include mali_kbase_defs.h first as this provides types needed by other local -+ * header files. -+ */ -+#include "mali_kbase_defs.h" -+ -+#include "mali_kbase_context.h" -+#include "mali_kbase_strings.h" -+#include "mali_kbase_mem_lowlevel.h" -+#include "mali_kbase_trace_timeline.h" -+#include "mali_kbase_js.h" -+#include "mali_kbase_mem.h" -+#include "mali_kbase_utility.h" -+#include "mali_kbase_gpu_memory_debugfs.h" -+#include "mali_kbase_mem_profile_debugfs.h" -+#include "mali_kbase_debug_job_fault.h" -+#include "mali_kbase_jd_debugfs.h" -+#include "mali_kbase_gpuprops.h" -+#include "mali_kbase_jm.h" -+#include "mali_kbase_vinstr.h" -+ -+#include "ipa/mali_kbase_ipa.h" -+ -+#ifdef CONFIG_GPU_TRACEPOINTS -+#include -+#endif -+ -+#ifndef u64_to_user_ptr -+/* Introduced in Linux v4.6 */ -+#define u64_to_user_ptr(x) ((void __user *)(uintptr_t)x) -+#endif -+ -+/* -+ * Kernel-side Base (KBase) APIs -+ */ -+ -+struct kbase_device *kbase_device_alloc(void); -+/* -+* note: configuration attributes member of kbdev needs to have -+* been setup before calling kbase_device_init -+*/ -+ -+/* -+* API to acquire device list semaphore and return pointer -+* to the device list head -+*/ -+const struct list_head *kbase_dev_list_get(void); -+/* API to release the device list semaphore */ -+void kbase_dev_list_put(const struct list_head *dev_list); -+ -+int kbase_device_init(struct kbase_device * const kbdev); -+void kbase_device_term(struct kbase_device *kbdev); -+void kbase_device_free(struct kbase_device *kbdev); -+int kbase_device_has_feature(struct kbase_device *kbdev, u32 feature); -+ -+/* Needed for gator integration and for reporting vsync information */ -+struct kbase_device *kbase_find_device(int minor); -+void kbase_release_device(struct kbase_device *kbdev); -+ -+void kbase_set_profiling_control(struct kbase_device *kbdev, u32 control, u32 value); -+ -+struct kbase_context * -+kbase_create_context(struct kbase_device *kbdev, bool is_compat); -+void kbase_destroy_context(struct kbase_context *kctx); -+ -+int kbase_jd_init(struct kbase_context *kctx); -+void kbase_jd_exit(struct kbase_context *kctx); -+ -+/** -+ * kbase_jd_submit - Submit atoms to the job dispatcher -+ * -+ * @kctx: The kbase context to submit to -+ * @user_addr: The address in user space of the struct base_jd_atom_v2 array -+ * @nr_atoms: The number of atoms in the array -+ * @stride: sizeof(struct base_jd_atom_v2) -+ * @uk6_atom: true if the atoms are legacy atoms (struct base_jd_atom_v2_uk6) -+ * -+ * Return: 0 on success or error code -+ */ -+int kbase_jd_submit(struct kbase_context *kctx, -+ void __user *user_addr, u32 nr_atoms, u32 stride, -+ bool uk6_atom); -+ -+/** -+ * kbase_jd_done_worker - Handle a job completion -+ * @data: a &struct work_struct -+ * -+ * This function requeues the job from the runpool (if it was soft-stopped or -+ * removed from NEXT registers). -+ * -+ * Removes it from the system if it finished/failed/was cancelled. -+ * -+ * Resolves dependencies to add dependent jobs to the context, potentially -+ * starting them if necessary (which may add more references to the context) -+ * -+ * Releases the reference to the context from the no-longer-running job. -+ * -+ * Handles retrying submission outside of IRQ context if it failed from within -+ * IRQ context. -+ */ -+void kbase_jd_done_worker(struct work_struct *data); -+ -+void kbase_jd_done(struct kbase_jd_atom *katom, int slot_nr, ktime_t *end_timestamp, -+ kbasep_js_atom_done_code done_code); -+void kbase_jd_cancel(struct kbase_device *kbdev, struct kbase_jd_atom *katom); -+void kbase_jd_zap_context(struct kbase_context *kctx); -+bool jd_done_nolock(struct kbase_jd_atom *katom, -+ struct list_head *completed_jobs_ctx); -+void kbase_jd_free_external_resources(struct kbase_jd_atom *katom); -+bool jd_submit_atom(struct kbase_context *kctx, -+ const struct base_jd_atom_v2 *user_atom, -+ struct kbase_jd_atom *katom); -+void kbase_jd_dep_clear_locked(struct kbase_jd_atom *katom); -+ -+void kbase_job_done(struct kbase_device *kbdev, u32 done); -+ -+/** -+ * kbase_job_slot_ctx_priority_check_locked(): - Check for lower priority atoms -+ * and soft stop them -+ * @kctx: Pointer to context to check. -+ * @katom: Pointer to priority atom. -+ * -+ * Atoms from @kctx on the same job slot as @katom, which have lower priority -+ * than @katom will be soft stopped and put back in the queue, so that atoms -+ * with higher priority can run. -+ * -+ * The hwaccess_lock must be held when calling this function. -+ */ -+void kbase_job_slot_ctx_priority_check_locked(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom); -+ -+void kbase_job_slot_softstop(struct kbase_device *kbdev, int js, -+ struct kbase_jd_atom *target_katom); -+void kbase_job_slot_softstop_swflags(struct kbase_device *kbdev, int js, -+ struct kbase_jd_atom *target_katom, u32 sw_flags); -+void kbase_job_slot_hardstop(struct kbase_context *kctx, int js, -+ struct kbase_jd_atom *target_katom); -+void kbase_job_check_enter_disjoint(struct kbase_device *kbdev, u32 action, -+ base_jd_core_req core_reqs, struct kbase_jd_atom *target_katom); -+void kbase_job_check_leave_disjoint(struct kbase_device *kbdev, -+ struct kbase_jd_atom *target_katom); -+ -+void kbase_event_post(struct kbase_context *ctx, struct kbase_jd_atom *event); -+int kbase_event_dequeue(struct kbase_context *ctx, struct base_jd_event_v2 *uevent); -+int kbase_event_pending(struct kbase_context *ctx); -+int kbase_event_init(struct kbase_context *kctx); -+void kbase_event_close(struct kbase_context *kctx); -+void kbase_event_cleanup(struct kbase_context *kctx); -+void kbase_event_wakeup(struct kbase_context *kctx); -+ -+int kbase_process_soft_job(struct kbase_jd_atom *katom); -+int kbase_prepare_soft_job(struct kbase_jd_atom *katom); -+void kbase_finish_soft_job(struct kbase_jd_atom *katom); -+void kbase_cancel_soft_job(struct kbase_jd_atom *katom); -+void kbase_resume_suspended_soft_jobs(struct kbase_device *kbdev); -+void kbasep_remove_waiting_soft_job(struct kbase_jd_atom *katom); -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+void kbase_soft_event_wait_callback(struct kbase_jd_atom *katom); -+#endif -+int kbase_soft_event_update(struct kbase_context *kctx, -+ u64 event, -+ unsigned char new_status); -+ -+bool kbase_replay_process(struct kbase_jd_atom *katom); -+ -+void kbasep_soft_job_timeout_worker(unsigned long data); -+void kbasep_complete_triggered_soft_events(struct kbase_context *kctx, u64 evt); -+ -+/* api used internally for register access. Contains validation and tracing */ -+void kbase_device_trace_register_access(struct kbase_context *kctx, enum kbase_reg_access_type type, u16 reg_offset, u32 reg_value); -+int kbase_device_trace_buffer_install( -+ struct kbase_context *kctx, u32 *tb, size_t size); -+void kbase_device_trace_buffer_uninstall(struct kbase_context *kctx); -+ -+/* api to be ported per OS, only need to do the raw register access */ -+void kbase_os_reg_write(struct kbase_device *kbdev, u16 offset, u32 value); -+u32 kbase_os_reg_read(struct kbase_device *kbdev, u16 offset); -+ -+void kbasep_as_do_poke(struct work_struct *work); -+ -+/** Returns the name associated with a Mali exception code -+ * -+ * This function is called from the interrupt handler when a GPU fault occurs. -+ * It reports the details of the fault using KBASE_DEBUG_PRINT_WARN. -+ * -+ * @param[in] kbdev The kbase device that the GPU fault occurred from. -+ * @param[in] exception_code exception code -+ * @return name associated with the exception code -+ */ -+const char *kbase_exception_name(struct kbase_device *kbdev, -+ u32 exception_code); -+ -+/** -+ * Check whether a system suspend is in progress, or has already been suspended -+ * -+ * The caller should ensure that either kbdev->pm.active_count_lock is held, or -+ * a dmb was executed recently (to ensure the value is most -+ * up-to-date). However, without a lock the value could change afterwards. -+ * -+ * @return false if a suspend is not in progress -+ * @return !=false otherwise -+ */ -+static inline bool kbase_pm_is_suspending(struct kbase_device *kbdev) -+{ -+ return kbdev->pm.suspending; -+} -+ -+/** -+ * Return the atom's ID, as was originally supplied by userspace in -+ * base_jd_atom_v2::atom_number -+ */ -+static inline int kbase_jd_atom_id(struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ int result; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(katom); -+ KBASE_DEBUG_ASSERT(katom->kctx == kctx); -+ -+ result = katom - &kctx->jctx.atoms[0]; -+ KBASE_DEBUG_ASSERT(result >= 0 && result <= BASE_JD_ATOM_COUNT); -+ return result; -+} -+ -+/** -+ * kbase_jd_atom_from_id - Return the atom structure for the given atom ID -+ * @kctx: Context pointer -+ * @id: ID of atom to retrieve -+ * -+ * Return: Pointer to struct kbase_jd_atom associated with the supplied ID -+ */ -+static inline struct kbase_jd_atom *kbase_jd_atom_from_id( -+ struct kbase_context *kctx, int id) -+{ -+ return &kctx->jctx.atoms[id]; -+} -+ -+/** -+ * Initialize the disjoint state -+ * -+ * The disjoint event count and state are both set to zero. -+ * -+ * Disjoint functions usage: -+ * -+ * The disjoint event count should be incremented whenever a disjoint event occurs. -+ * -+ * There are several cases which are regarded as disjoint behavior. Rather than just increment -+ * the counter during disjoint events we also increment the counter when jobs may be affected -+ * by what the GPU is currently doing. To facilitate this we have the concept of disjoint state. -+ * -+ * Disjoint state is entered during GPU reset and for the entire time that an atom is replaying -+ * (as part of the replay workaround). Increasing the disjoint state also increases the count of -+ * disjoint events. -+ * -+ * The disjoint state is then used to increase the count of disjoint events during job submission -+ * and job completion. Any atom submitted or completed while the disjoint state is greater than -+ * zero is regarded as a disjoint event. -+ * -+ * The disjoint event counter is also incremented immediately whenever a job is soft stopped -+ * and during context creation. -+ * -+ * @param kbdev The kbase device -+ */ -+void kbase_disjoint_init(struct kbase_device *kbdev); -+ -+/** -+ * Increase the count of disjoint events -+ * called when a disjoint event has happened -+ * -+ * @param kbdev The kbase device -+ */ -+void kbase_disjoint_event(struct kbase_device *kbdev); -+ -+/** -+ * Increase the count of disjoint events only if the GPU is in a disjoint state -+ * -+ * This should be called when something happens which could be disjoint if the GPU -+ * is in a disjoint state. The state refcount keeps track of this. -+ * -+ * @param kbdev The kbase device -+ */ -+void kbase_disjoint_event_potential(struct kbase_device *kbdev); -+ -+/** -+ * Returns the count of disjoint events -+ * -+ * @param kbdev The kbase device -+ * @return the count of disjoint events -+ */ -+u32 kbase_disjoint_event_get(struct kbase_device *kbdev); -+ -+/** -+ * Increment the refcount state indicating that the GPU is in a disjoint state. -+ * -+ * Also Increment the disjoint event count (calls @ref kbase_disjoint_event) -+ * eventually after the disjoint state has completed @ref kbase_disjoint_state_down -+ * should be called -+ * -+ * @param kbdev The kbase device -+ */ -+void kbase_disjoint_state_up(struct kbase_device *kbdev); -+ -+/** -+ * Decrement the refcount state -+ * -+ * Also Increment the disjoint event count (calls @ref kbase_disjoint_event) -+ * -+ * Called after @ref kbase_disjoint_state_up once the disjoint state is over -+ * -+ * @param kbdev The kbase device -+ */ -+void kbase_disjoint_state_down(struct kbase_device *kbdev); -+ -+/** -+ * If a job is soft stopped and the number of contexts is >= this value -+ * it is reported as a disjoint event -+ */ -+#define KBASE_DISJOINT_STATE_INTERLEAVED_CONTEXT_COUNT_THRESHOLD 2 -+ -+#if !defined(UINT64_MAX) -+ #define UINT64_MAX ((uint64_t)0xFFFFFFFFFFFFFFFFULL) -+#endif -+ -+#if KBASE_TRACE_ENABLE -+void kbasep_trace_debugfs_init(struct kbase_device *kbdev); -+ -+#ifndef CONFIG_MALI_SYSTEM_TRACE -+/** Add trace values about a job-slot -+ * -+ * @note Any functions called through this macro will still be evaluated in -+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any -+ * functions called to get the parameters supplied to this macro must: -+ * - be static or static inline -+ * - must just return 0 and have no other statements present in the body. -+ */ -+#define KBASE_TRACE_ADD_SLOT(kbdev, code, ctx, katom, gpu_addr, jobslot) \ -+ kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \ -+ KBASE_TRACE_FLAG_JOBSLOT, 0, jobslot, 0) -+ -+/** Add trace values about a job-slot, with info -+ * -+ * @note Any functions called through this macro will still be evaluated in -+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any -+ * functions called to get the parameters supplied to this macro must: -+ * - be static or static inline -+ * - must just return 0 and have no other statements present in the body. -+ */ -+#define KBASE_TRACE_ADD_SLOT_INFO(kbdev, code, ctx, katom, gpu_addr, jobslot, info_val) \ -+ kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \ -+ KBASE_TRACE_FLAG_JOBSLOT, 0, jobslot, info_val) -+ -+/** Add trace values about a ctx refcount -+ * -+ * @note Any functions called through this macro will still be evaluated in -+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any -+ * functions called to get the parameters supplied to this macro must: -+ * - be static or static inline -+ * - must just return 0 and have no other statements present in the body. -+ */ -+#define KBASE_TRACE_ADD_REFCOUNT(kbdev, code, ctx, katom, gpu_addr, refcount) \ -+ kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \ -+ KBASE_TRACE_FLAG_REFCOUNT, refcount, 0, 0) -+/** Add trace values about a ctx refcount, and info -+ * -+ * @note Any functions called through this macro will still be evaluated in -+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any -+ * functions called to get the parameters supplied to this macro must: -+ * - be static or static inline -+ * - must just return 0 and have no other statements present in the body. -+ */ -+#define KBASE_TRACE_ADD_REFCOUNT_INFO(kbdev, code, ctx, katom, gpu_addr, refcount, info_val) \ -+ kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \ -+ KBASE_TRACE_FLAG_REFCOUNT, refcount, 0, info_val) -+ -+/** Add trace values (no slot or refcount) -+ * -+ * @note Any functions called through this macro will still be evaluated in -+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any -+ * functions called to get the parameters supplied to this macro must: -+ * - be static or static inline -+ * - must just return 0 and have no other statements present in the body. -+ */ -+#define KBASE_TRACE_ADD(kbdev, code, ctx, katom, gpu_addr, info_val) \ -+ kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \ -+ 0, 0, 0, info_val) -+ -+/** Clear the trace */ -+#define KBASE_TRACE_CLEAR(kbdev) \ -+ kbasep_trace_clear(kbdev) -+ -+/** Dump the slot trace */ -+#define KBASE_TRACE_DUMP(kbdev) \ -+ kbasep_trace_dump(kbdev) -+ -+/** PRIVATE - do not use directly. Use KBASE_TRACE_ADD() instead */ -+void kbasep_trace_add(struct kbase_device *kbdev, enum kbase_trace_code code, void *ctx, struct kbase_jd_atom *katom, u64 gpu_addr, u8 flags, int refcount, int jobslot, unsigned long info_val); -+/** PRIVATE - do not use directly. Use KBASE_TRACE_CLEAR() instead */ -+void kbasep_trace_clear(struct kbase_device *kbdev); -+#else /* #ifndef CONFIG_MALI_SYSTEM_TRACE */ -+/* Dispatch kbase trace events as system trace events */ -+#include -+#define KBASE_TRACE_ADD_SLOT(kbdev, code, ctx, katom, gpu_addr, jobslot)\ -+ trace_mali_##code(jobslot, 0) -+ -+#define KBASE_TRACE_ADD_SLOT_INFO(kbdev, code, ctx, katom, gpu_addr, jobslot, info_val)\ -+ trace_mali_##code(jobslot, info_val) -+ -+#define KBASE_TRACE_ADD_REFCOUNT(kbdev, code, ctx, katom, gpu_addr, refcount)\ -+ trace_mali_##code(refcount, 0) -+ -+#define KBASE_TRACE_ADD_REFCOUNT_INFO(kbdev, code, ctx, katom, gpu_addr, refcount, info_val)\ -+ trace_mali_##code(refcount, info_val) -+ -+#define KBASE_TRACE_ADD(kbdev, code, ctx, katom, gpu_addr, info_val)\ -+ trace_mali_##code(gpu_addr, info_val) -+ -+#define KBASE_TRACE_CLEAR(kbdev)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(0);\ -+ } while (0) -+#define KBASE_TRACE_DUMP(kbdev)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(0);\ -+ } while (0) -+ -+#endif /* #ifndef CONFIG_MALI_SYSTEM_TRACE */ -+#else -+#define KBASE_TRACE_ADD_SLOT(kbdev, code, ctx, katom, gpu_addr, jobslot)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(code);\ -+ CSTD_UNUSED(ctx);\ -+ CSTD_UNUSED(katom);\ -+ CSTD_UNUSED(gpu_addr);\ -+ CSTD_UNUSED(jobslot);\ -+ } while (0) -+ -+#define KBASE_TRACE_ADD_SLOT_INFO(kbdev, code, ctx, katom, gpu_addr, jobslot, info_val)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(code);\ -+ CSTD_UNUSED(ctx);\ -+ CSTD_UNUSED(katom);\ -+ CSTD_UNUSED(gpu_addr);\ -+ CSTD_UNUSED(jobslot);\ -+ CSTD_UNUSED(info_val);\ -+ CSTD_NOP(0);\ -+ } while (0) -+ -+#define KBASE_TRACE_ADD_REFCOUNT(kbdev, code, ctx, katom, gpu_addr, refcount)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(code);\ -+ CSTD_UNUSED(ctx);\ -+ CSTD_UNUSED(katom);\ -+ CSTD_UNUSED(gpu_addr);\ -+ CSTD_UNUSED(refcount);\ -+ CSTD_NOP(0);\ -+ } while (0) -+ -+#define KBASE_TRACE_ADD_REFCOUNT_INFO(kbdev, code, ctx, katom, gpu_addr, refcount, info_val)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(code);\ -+ CSTD_UNUSED(ctx);\ -+ CSTD_UNUSED(katom);\ -+ CSTD_UNUSED(gpu_addr);\ -+ CSTD_UNUSED(info_val);\ -+ CSTD_NOP(0);\ -+ } while (0) -+ -+#define KBASE_TRACE_ADD(kbdev, code, subcode, ctx, katom, val)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(code);\ -+ CSTD_UNUSED(subcode);\ -+ CSTD_UNUSED(ctx);\ -+ CSTD_UNUSED(katom);\ -+ CSTD_UNUSED(val);\ -+ CSTD_NOP(0);\ -+ } while (0) -+ -+#define KBASE_TRACE_CLEAR(kbdev)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(0);\ -+ } while (0) -+#define KBASE_TRACE_DUMP(kbdev)\ -+ do {\ -+ CSTD_UNUSED(kbdev);\ -+ CSTD_NOP(0);\ -+ } while (0) -+#endif /* KBASE_TRACE_ENABLE */ -+/** PRIVATE - do not use directly. Use KBASE_TRACE_DUMP() instead */ -+void kbasep_trace_dump(struct kbase_device *kbdev); -+ -+#ifdef CONFIG_MALI_DEBUG -+/** -+ * kbase_set_driver_inactive - Force driver to go inactive -+ * @kbdev: Device pointer -+ * @inactive: true if driver should go inactive, false otherwise -+ * -+ * Forcing the driver inactive will cause all future IOCTLs to wait until the -+ * driver is made active again. This is intended solely for the use of tests -+ * which require that no jobs are running while the test executes. -+ */ -+void kbase_set_driver_inactive(struct kbase_device *kbdev, bool inactive); -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ -+#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_MALI_NO_MALI) -+ -+/* kbase_io_history_init - initialize data struct for register access history -+ * -+ * @kbdev The register history to initialize -+ * @n The number of register accesses that the buffer could hold -+ * -+ * @return 0 if successfully initialized, failure otherwise -+ */ -+int kbase_io_history_init(struct kbase_io_history *h, u16 n); -+ -+/* kbase_io_history_term - uninit all resources for the register access history -+ * -+ * @h The register history to terminate -+ */ -+void kbase_io_history_term(struct kbase_io_history *h); -+ -+/* kbase_io_history_dump - print the register history to the kernel ring buffer -+ * -+ * @kbdev Pointer to kbase_device containing the register history to dump -+ */ -+void kbase_io_history_dump(struct kbase_device *kbdev); -+ -+/** -+ * kbase_io_history_resize - resize the register access history buffer. -+ * -+ * @h: Pointer to a valid register history to resize -+ * @new_size: Number of accesses the buffer could hold -+ * -+ * A successful resize will clear all recent register accesses. -+ * If resizing fails for any reason (e.g., could not allocate memory, invalid -+ * buffer size) then the original buffer will be kept intact. -+ * -+ * @return 0 if the buffer was resized, failure otherwise -+ */ -+int kbase_io_history_resize(struct kbase_io_history *h, u16 new_size); -+ -+#else /* CONFIG_DEBUG_FS */ -+ -+#define kbase_io_history_init(...) ((int)0) -+ -+#define kbase_io_history_term CSTD_NOP -+ -+#define kbase_io_history_dump CSTD_NOP -+ -+#define kbase_io_history_resize CSTD_NOP -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+ -+#endif -+ -+ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_10969_workaround.c b/drivers/gpu/arm/midgard/mali_kbase_10969_workaround.c -new file mode 100644 -index 0000000..6b3559d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_10969_workaround.c -@@ -0,0 +1,210 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2015,2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+#include -+#include -+#include -+ -+/* This function is used to solve an HW issue with single iterator GPUs. -+ * If a fragment job is soft-stopped on the edge of its bounding box, can happen that the -+ * restart index is out of bounds and the rerun causes a tile range fault. If this happens -+ * we try to clamp the restart index to a correct value and rerun the job. -+ */ -+/* Mask of X and Y coordinates for the coordinates words in the descriptors*/ -+#define X_COORDINATE_MASK 0x00000FFF -+#define Y_COORDINATE_MASK 0x0FFF0000 -+/* Max number of words needed from the fragment shader job descriptor */ -+#define JOB_HEADER_SIZE_IN_WORDS 10 -+#define JOB_HEADER_SIZE (JOB_HEADER_SIZE_IN_WORDS*sizeof(u32)) -+ -+/* Word 0: Status Word */ -+#define JOB_DESC_STATUS_WORD 0 -+/* Word 1: Restart Index */ -+#define JOB_DESC_RESTART_INDEX_WORD 1 -+/* Word 2: Fault address low word */ -+#define JOB_DESC_FAULT_ADDR_LOW_WORD 2 -+/* Word 8: Minimum Tile Coordinates */ -+#define FRAG_JOB_DESC_MIN_TILE_COORD_WORD 8 -+/* Word 9: Maximum Tile Coordinates */ -+#define FRAG_JOB_DESC_MAX_TILE_COORD_WORD 9 -+ -+int kbasep_10969_workaround_clamp_coordinates(struct kbase_jd_atom *katom) -+{ -+ struct device *dev = katom->kctx->kbdev->dev; -+ u32 clamped = 0; -+ struct kbase_va_region *region; -+ struct tagged_addr *page_array; -+ u64 page_index; -+ u32 offset = katom->jc & (~PAGE_MASK); -+ u32 *page_1 = NULL; -+ u32 *page_2 = NULL; -+ u32 job_header[JOB_HEADER_SIZE_IN_WORDS]; -+ void *dst = job_header; -+ u32 minX, minY, maxX, maxY; -+ u32 restartX, restartY; -+ struct page *p; -+ u32 copy_size; -+ -+ dev_warn(dev, "Called TILE_RANGE_FAULT workaround clamping function.\n"); -+ if (!(katom->core_req & BASE_JD_REQ_FS)) -+ return 0; -+ -+ kbase_gpu_vm_lock(katom->kctx); -+ region = kbase_region_tracker_find_region_enclosing_address(katom->kctx, -+ katom->jc); -+ if (!region || (region->flags & KBASE_REG_FREE)) -+ goto out_unlock; -+ -+ page_array = kbase_get_cpu_phy_pages(region); -+ if (!page_array) -+ goto out_unlock; -+ -+ page_index = (katom->jc >> PAGE_SHIFT) - region->start_pfn; -+ -+ p = phys_to_page(as_phys_addr_t(page_array[page_index])); -+ -+ /* we need the first 10 words of the fragment shader job descriptor. -+ * We need to check that the offset + 10 words is less that the page -+ * size otherwise we need to load the next page. -+ * page_size_overflow will be equal to 0 in case the whole descriptor -+ * is within the page > 0 otherwise. -+ */ -+ copy_size = MIN(PAGE_SIZE - offset, JOB_HEADER_SIZE); -+ -+ page_1 = kmap_atomic(p); -+ -+ /* page_1 is a u32 pointer, offset is expressed in bytes */ -+ page_1 += offset>>2; -+ -+ kbase_sync_single_for_cpu(katom->kctx->kbdev, -+ kbase_dma_addr(p) + offset, -+ copy_size, DMA_BIDIRECTIONAL); -+ -+ memcpy(dst, page_1, copy_size); -+ -+ /* The data needed overflows page the dimension, -+ * need to map the subsequent page */ -+ if (copy_size < JOB_HEADER_SIZE) { -+ p = phys_to_page(as_phys_addr_t(page_array[page_index + 1])); -+ page_2 = kmap_atomic(p); -+ -+ kbase_sync_single_for_cpu(katom->kctx->kbdev, -+ kbase_dma_addr(p), -+ JOB_HEADER_SIZE - copy_size, DMA_BIDIRECTIONAL); -+ -+ memcpy(dst + copy_size, page_2, JOB_HEADER_SIZE - copy_size); -+ } -+ -+ /* We managed to correctly map one or two pages (in case of overflow) */ -+ /* Get Bounding Box data and restart index from fault address low word */ -+ minX = job_header[FRAG_JOB_DESC_MIN_TILE_COORD_WORD] & X_COORDINATE_MASK; -+ minY = job_header[FRAG_JOB_DESC_MIN_TILE_COORD_WORD] & Y_COORDINATE_MASK; -+ maxX = job_header[FRAG_JOB_DESC_MAX_TILE_COORD_WORD] & X_COORDINATE_MASK; -+ maxY = job_header[FRAG_JOB_DESC_MAX_TILE_COORD_WORD] & Y_COORDINATE_MASK; -+ restartX = job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] & X_COORDINATE_MASK; -+ restartY = job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] & Y_COORDINATE_MASK; -+ -+ dev_warn(dev, "Before Clamping:\n" -+ "Jobstatus: %08x\n" -+ "restartIdx: %08x\n" -+ "Fault_addr_low: %08x\n" -+ "minCoordsX: %08x minCoordsY: %08x\n" -+ "maxCoordsX: %08x maxCoordsY: %08x\n", -+ job_header[JOB_DESC_STATUS_WORD], -+ job_header[JOB_DESC_RESTART_INDEX_WORD], -+ job_header[JOB_DESC_FAULT_ADDR_LOW_WORD], -+ minX, minY, -+ maxX, maxY); -+ -+ /* Set the restart index to the one which generated the fault*/ -+ job_header[JOB_DESC_RESTART_INDEX_WORD] = -+ job_header[JOB_DESC_FAULT_ADDR_LOW_WORD]; -+ -+ if (restartX < minX) { -+ job_header[JOB_DESC_RESTART_INDEX_WORD] = (minX) | restartY; -+ dev_warn(dev, -+ "Clamping restart X index to minimum. %08x clamped to %08x\n", -+ restartX, minX); -+ clamped = 1; -+ } -+ if (restartY < minY) { -+ job_header[JOB_DESC_RESTART_INDEX_WORD] = (minY) | restartX; -+ dev_warn(dev, -+ "Clamping restart Y index to minimum. %08x clamped to %08x\n", -+ restartY, minY); -+ clamped = 1; -+ } -+ if (restartX > maxX) { -+ job_header[JOB_DESC_RESTART_INDEX_WORD] = (maxX) | restartY; -+ dev_warn(dev, -+ "Clamping restart X index to maximum. %08x clamped to %08x\n", -+ restartX, maxX); -+ clamped = 1; -+ } -+ if (restartY > maxY) { -+ job_header[JOB_DESC_RESTART_INDEX_WORD] = (maxY) | restartX; -+ dev_warn(dev, -+ "Clamping restart Y index to maximum. %08x clamped to %08x\n", -+ restartY, maxY); -+ clamped = 1; -+ } -+ -+ if (clamped) { -+ /* Reset the fault address low word -+ * and set the job status to STOPPED */ -+ job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] = 0x0; -+ job_header[JOB_DESC_STATUS_WORD] = BASE_JD_EVENT_STOPPED; -+ dev_warn(dev, "After Clamping:\n" -+ "Jobstatus: %08x\n" -+ "restartIdx: %08x\n" -+ "Fault_addr_low: %08x\n" -+ "minCoordsX: %08x minCoordsY: %08x\n" -+ "maxCoordsX: %08x maxCoordsY: %08x\n", -+ job_header[JOB_DESC_STATUS_WORD], -+ job_header[JOB_DESC_RESTART_INDEX_WORD], -+ job_header[JOB_DESC_FAULT_ADDR_LOW_WORD], -+ minX, minY, -+ maxX, maxY); -+ -+ /* Flush CPU cache to update memory for future GPU reads*/ -+ memcpy(page_1, dst, copy_size); -+ p = phys_to_page(as_phys_addr_t(page_array[page_index])); -+ -+ kbase_sync_single_for_device(katom->kctx->kbdev, -+ kbase_dma_addr(p) + offset, -+ copy_size, DMA_TO_DEVICE); -+ -+ if (copy_size < JOB_HEADER_SIZE) { -+ memcpy(page_2, dst + copy_size, -+ JOB_HEADER_SIZE - copy_size); -+ p = phys_to_page(as_phys_addr_t(page_array[page_index + -+ 1])); -+ -+ kbase_sync_single_for_device(katom->kctx->kbdev, -+ kbase_dma_addr(p), -+ JOB_HEADER_SIZE - copy_size, -+ DMA_TO_DEVICE); -+ } -+ } -+ if (copy_size < JOB_HEADER_SIZE) -+ kunmap_atomic(page_2); -+ -+ kunmap_atomic(page_1); -+ -+out_unlock: -+ kbase_gpu_vm_unlock(katom->kctx); -+ return clamped; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_10969_workaround.h b/drivers/gpu/arm/midgard/mali_kbase_10969_workaround.h -new file mode 100644 -index 0000000..099a298 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_10969_workaround.h -@@ -0,0 +1,23 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_10969_WORKAROUND_ -+#define _KBASE_10969_WORKAROUND_ -+ -+int kbasep_10969_workaround_clamp_coordinates(struct kbase_jd_atom *katom); -+ -+#endif /* _KBASE_10969_WORKAROUND_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_as_fault_debugfs.c b/drivers/gpu/arm/midgard/mali_kbase_as_fault_debugfs.c -new file mode 100644 -index 0000000..f910fe9 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_as_fault_debugfs.c -@@ -0,0 +1,102 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+ -+#include -+#include -+ -+#ifdef CONFIG_DEBUG_FS -+#ifdef CONFIG_MALI_DEBUG -+ -+static int kbase_as_fault_read(struct seq_file *sfile, void *data) -+{ -+ uintptr_t as_no = (uintptr_t) sfile->private; -+ -+ struct list_head *entry; -+ const struct list_head *kbdev_list; -+ struct kbase_device *kbdev = NULL; -+ -+ kbdev_list = kbase_dev_list_get(); -+ -+ list_for_each(entry, kbdev_list) { -+ kbdev = list_entry(entry, struct kbase_device, entry); -+ -+ if(kbdev->debugfs_as_read_bitmap & (1ULL << as_no)) { -+ -+ /* don't show this one again until another fault occors */ -+ kbdev->debugfs_as_read_bitmap &= ~(1ULL << as_no); -+ -+ /* output the last page fault addr */ -+ seq_printf(sfile, "%llu\n", (u64) kbdev->as[as_no].fault_addr); -+ } -+ -+ } -+ -+ kbase_dev_list_put(kbdev_list); -+ -+ return 0; -+} -+ -+static int kbase_as_fault_debugfs_open(struct inode *in, struct file *file) -+{ -+ return single_open(file, kbase_as_fault_read , in->i_private); -+} -+ -+static const struct file_operations as_fault_fops = { -+ .open = kbase_as_fault_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+#endif /* CONFIG_MALI_DEBUG */ -+#endif /* CONFIG_DEBUG_FS */ -+ -+/* -+ * Initialize debugfs entry for each address space -+ */ -+void kbase_as_fault_debugfs_init(struct kbase_device *kbdev) -+{ -+#ifdef CONFIG_DEBUG_FS -+#ifdef CONFIG_MALI_DEBUG -+ uint i; -+ char as_name[64]; -+ struct dentry *debugfs_directory; -+ -+ kbdev->debugfs_as_read_bitmap = 0ULL; -+ -+ KBASE_DEBUG_ASSERT(kbdev->nr_hw_address_spaces); -+ KBASE_DEBUG_ASSERT(sizeof(kbdev->as[0].fault_addr) == sizeof(u64)); -+ -+ debugfs_directory = debugfs_create_dir("address_spaces", -+ kbdev->mali_debugfs_directory); -+ -+ if(debugfs_directory) { -+ for(i = 0; i < kbdev->nr_hw_address_spaces; i++) { -+ snprintf(as_name, ARRAY_SIZE(as_name), "as%u", i); -+ debugfs_create_file(as_name, S_IRUGO, -+ debugfs_directory, (void*) ((uintptr_t) i), &as_fault_fops); -+ } -+ } -+ else -+ dev_warn(kbdev->dev, "unable to create address_spaces debugfs directory"); -+ -+#endif /* CONFIG_MALI_DEBUG */ -+#endif /* CONFIG_DEBUG_FS */ -+ return; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_as_fault_debugfs.h b/drivers/gpu/arm/midgard/mali_kbase_as_fault_debugfs.h -new file mode 100644 -index 0000000..3ed2248 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_as_fault_debugfs.h -@@ -0,0 +1,45 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_AS_FAULT_DEBUG_FS_H -+#define _KBASE_AS_FAULT_DEBUG_FS_H -+ -+/** -+ * kbase_as_fault_debugfs_init() - Add debugfs files for reporting page faults -+ * -+ * @kbdev: Pointer to kbase_device -+ */ -+void kbase_as_fault_debugfs_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_as_fault_debugfs_new() - make the last fault available on debugfs -+ * -+ * @kbdev: Pointer to kbase_device -+ * @as_no: The address space the fault occurred on -+ */ -+static inline void -+kbase_as_fault_debugfs_new(struct kbase_device *kbdev, int as_no) -+{ -+#ifdef CONFIG_DEBUG_FS -+#ifdef CONFIG_MALI_DEBUG -+ kbdev->debugfs_as_read_bitmap |= (1ULL << as_no); -+#endif /* CONFIG_DEBUG_FS */ -+#endif /* CONFIG_MALI_DEBUG */ -+ return; -+} -+ -+#endif /*_KBASE_AS_FAULT_DEBUG_FS_H*/ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_cache_policy.c b/drivers/gpu/arm/midgard/mali_kbase_cache_policy.c -new file mode 100644 -index 0000000..1d11de6 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_cache_policy.c -@@ -0,0 +1,54 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Cache Policy API. -+ */ -+ -+#include "mali_kbase_cache_policy.h" -+ -+/* -+ * The output flags should be a combination of the following values: -+ * KBASE_REG_CPU_CACHED: CPU cache should be enabled. -+ */ -+u32 kbase_cache_enabled(u32 flags, u32 nr_pages) -+{ -+ u32 cache_flags = 0; -+ -+ CSTD_UNUSED(nr_pages); -+ -+ if (flags & BASE_MEM_CACHED_CPU) -+ cache_flags |= KBASE_REG_CPU_CACHED; -+ -+ return cache_flags; -+} -+ -+ -+void kbase_sync_single_for_device(struct kbase_device *kbdev, dma_addr_t handle, -+ size_t size, enum dma_data_direction dir) -+{ -+ dma_sync_single_for_device(kbdev->dev, handle, size, dir); -+} -+ -+ -+void kbase_sync_single_for_cpu(struct kbase_device *kbdev, dma_addr_t handle, -+ size_t size, enum dma_data_direction dir) -+{ -+ dma_sync_single_for_cpu(kbdev->dev, handle, size, dir); -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_cache_policy.h b/drivers/gpu/arm/midgard/mali_kbase_cache_policy.h -new file mode 100644 -index 0000000..0c18bdb ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_cache_policy.h -@@ -0,0 +1,45 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2013, 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Cache Policy API. -+ */ -+ -+#ifndef _KBASE_CACHE_POLICY_H_ -+#define _KBASE_CACHE_POLICY_H_ -+ -+#include "mali_kbase.h" -+#include "mali_base_kernel.h" -+ -+/** -+ * kbase_cache_enabled - Choose the cache policy for a specific region -+ * @flags: flags describing attributes of the region -+ * @nr_pages: total number of pages (backed or not) for the region -+ * -+ * Tells whether the CPU and GPU caches should be enabled or not for a specific -+ * region. -+ * This function can be modified to customize the cache policy depending on the -+ * flags and size of the region. -+ * -+ * Return: a combination of %KBASE_REG_CPU_CACHED and %KBASE_REG_GPU_CACHED -+ * depending on the cache policy -+ */ -+u32 kbase_cache_enabled(u32 flags, u32 nr_pages); -+ -+#endif /* _KBASE_CACHE_POLICY_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_config.c b/drivers/gpu/arm/midgard/mali_kbase_config.c -new file mode 100644 -index 0000000..fb615ae ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_config.c -@@ -0,0 +1,51 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+#include -+ -+int kbasep_platform_device_init(struct kbase_device *kbdev) -+{ -+ struct kbase_platform_funcs_conf *platform_funcs_p; -+ -+ platform_funcs_p = (struct kbase_platform_funcs_conf *)PLATFORM_FUNCS; -+ if (platform_funcs_p && platform_funcs_p->platform_init_func) -+ return platform_funcs_p->platform_init_func(kbdev); -+ -+ return 0; -+} -+ -+void kbasep_platform_device_term(struct kbase_device *kbdev) -+{ -+ struct kbase_platform_funcs_conf *platform_funcs_p; -+ -+ platform_funcs_p = (struct kbase_platform_funcs_conf *)PLATFORM_FUNCS; -+ if (platform_funcs_p && platform_funcs_p->platform_term_func) -+ platform_funcs_p->platform_term_func(kbdev); -+} -+ -+int kbase_cpuprops_get_default_clock_speed(u32 * const clock_speed) -+{ -+ KBASE_DEBUG_ASSERT(NULL != clock_speed); -+ -+ *clock_speed = 100; -+ return 0; -+} -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_config.h b/drivers/gpu/arm/midgard/mali_kbase_config.h -new file mode 100644 -index 0000000..356d52b ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_config.h -@@ -0,0 +1,345 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_config.h -+ * Configuration API and Attributes for KBase -+ */ -+ -+#ifndef _KBASE_CONFIG_H_ -+#define _KBASE_CONFIG_H_ -+ -+#include -+ -+#include -+#include -+ -+/** -+ * @addtogroup base_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup base_kbase_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup kbase_config Configuration API and Attributes -+ * @{ -+ */ -+ -+#include -+ -+/* Forward declaration of struct kbase_device */ -+struct kbase_device; -+ -+/** -+ * kbase_platform_funcs_conf - Specifies platform init/term function pointers -+ * -+ * Specifies the functions pointers for platform specific initialization and -+ * termination. By default no functions are required. No additional platform -+ * specific control is necessary. -+ */ -+struct kbase_platform_funcs_conf { -+ /** -+ * platform_init_func - platform specific init function pointer -+ * @kbdev - kbase_device pointer -+ * -+ * Returns 0 on success, negative error code otherwise. -+ * -+ * Function pointer for platform specific initialization or NULL if no -+ * initialization function is required. At the point this the GPU is -+ * not active and its power and clocks are in unknown (platform specific -+ * state) as kbase doesn't yet have control of power and clocks. -+ * -+ * The platform specific private pointer kbase_device::platform_context -+ * can be accessed (and possibly initialized) in here. -+ */ -+ int (*platform_init_func)(struct kbase_device *kbdev); -+ /** -+ * platform_term_func - platform specific termination function pointer -+ * @kbdev - kbase_device pointer -+ * -+ * Function pointer for platform specific termination or NULL if no -+ * termination function is required. At the point this the GPU will be -+ * idle but still powered and clocked. -+ * -+ * The platform specific private pointer kbase_device::platform_context -+ * can be accessed (and possibly terminated) in here. -+ */ -+ void (*platform_term_func)(struct kbase_device *kbdev); -+}; -+ -+/* -+ * @brief Specifies the callbacks for power management -+ * -+ * By default no callbacks will be made and the GPU must not be powered off. -+ */ -+struct kbase_pm_callback_conf { -+ /** Callback for when the GPU is idle and the power to it can be switched off. -+ * -+ * The system integrator can decide whether to either do nothing, just switch off -+ * the clocks to the GPU, or to completely power down the GPU. -+ * The platform specific private pointer kbase_device::platform_context can be accessed and modified in here. It is the -+ * platform \em callbacks responsibility to initialize and terminate this pointer if used (see @ref kbase_platform_funcs_conf). -+ */ -+ void (*power_off_callback)(struct kbase_device *kbdev); -+ -+ /** Callback for when the GPU is about to become active and power must be supplied. -+ * -+ * This function must not return until the GPU is powered and clocked sufficiently for register access to -+ * succeed. The return value specifies whether the GPU was powered down since the call to power_off_callback. -+ * If the GPU state has been lost then this function must return 1, otherwise it should return 0. -+ * The platform specific private pointer kbase_device::platform_context can be accessed and modified in here. It is the -+ * platform \em callbacks responsibility to initialize and terminate this pointer if used (see @ref kbase_platform_funcs_conf). -+ * -+ * The return value of the first call to this function is ignored. -+ * -+ * @return 1 if the GPU state may have been lost, 0 otherwise. -+ */ -+ int (*power_on_callback)(struct kbase_device *kbdev); -+ -+ /** Callback for when the system is requesting a suspend and GPU power -+ * must be switched off. -+ * -+ * Note that if this callback is present, then this may be called -+ * without a preceding call to power_off_callback. Therefore this -+ * callback must be able to take any action that might otherwise happen -+ * in power_off_callback. -+ * -+ * The platform specific private pointer kbase_device::platform_context -+ * can be accessed and modified in here. It is the platform \em -+ * callbacks responsibility to initialize and terminate this pointer if -+ * used (see @ref kbase_platform_funcs_conf). -+ */ -+ void (*power_suspend_callback)(struct kbase_device *kbdev); -+ -+ /** Callback for when the system is resuming from a suspend and GPU -+ * power must be switched on. -+ * -+ * Note that if this callback is present, then this may be called -+ * without a following call to power_on_callback. Therefore this -+ * callback must be able to take any action that might otherwise happen -+ * in power_on_callback. -+ * -+ * The platform specific private pointer kbase_device::platform_context -+ * can be accessed and modified in here. It is the platform \em -+ * callbacks responsibility to initialize and terminate this pointer if -+ * used (see @ref kbase_platform_funcs_conf). -+ */ -+ void (*power_resume_callback)(struct kbase_device *kbdev); -+ -+ /** Callback for handling runtime power management initialization. -+ * -+ * The runtime power management callbacks @ref power_runtime_off_callback and @ref power_runtime_on_callback -+ * will become active from calls made to the OS from within this function. -+ * The runtime calls can be triggered by calls from @ref power_off_callback and @ref power_on_callback. -+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature. -+ * -+ * @return 0 on success, else int error code. -+ */ -+ int (*power_runtime_init_callback)(struct kbase_device *kbdev); -+ -+ /** Callback for handling runtime power management termination. -+ * -+ * The runtime power management callbacks @ref power_runtime_off_callback and @ref power_runtime_on_callback -+ * should no longer be called by the OS on completion of this function. -+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature. -+ */ -+ void (*power_runtime_term_callback)(struct kbase_device *kbdev); -+ -+ /** Callback for runtime power-off power management callback -+ * -+ * For linux this callback will be called by the kernel runtime_suspend callback. -+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature. -+ * -+ * @return 0 on success, else OS error code. -+ */ -+ void (*power_runtime_off_callback)(struct kbase_device *kbdev); -+ -+ /** Callback for runtime power-on power management callback -+ * -+ * For linux this callback will be called by the kernel runtime_resume callback. -+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature. -+ */ -+ int (*power_runtime_on_callback)(struct kbase_device *kbdev); -+ -+ /* -+ * Optional callback for checking if GPU can be suspended when idle -+ * -+ * This callback will be called by the runtime power management core -+ * when the reference count goes to 0 to provide notification that the -+ * GPU now seems idle. -+ * -+ * If this callback finds that the GPU can't be powered off, or handles -+ * suspend by powering off directly or queueing up a power off, a -+ * non-zero value must be returned to prevent the runtime PM core from -+ * also triggering a suspend. -+ * -+ * Returning 0 will cause the runtime PM core to conduct a regular -+ * autosuspend. -+ * -+ * This callback is optional and if not provided regular autosuspend -+ * will be triggered. -+ * -+ * Note: The Linux kernel must have CONFIG_PM_RUNTIME enabled to use -+ * this feature. -+ * -+ * Return 0 if GPU can be suspended, positive value if it can not be -+ * suspeneded by runtime PM, else OS error code -+ */ -+ int (*power_runtime_idle_callback)(struct kbase_device *kbdev); -+}; -+ -+/** -+ * kbase_cpuprops_get_default_clock_speed - default for CPU_SPEED_FUNC -+ * @clock_speed - see kbase_cpu_clk_speed_func for details on the parameters -+ * -+ * Returns 0 on success, negative error code otherwise. -+ * -+ * Default implementation of CPU_SPEED_FUNC. This function sets clock_speed -+ * to 100, so will be an underestimate for any real system. -+ */ -+int kbase_cpuprops_get_default_clock_speed(u32 * const clock_speed); -+ -+/** -+ * kbase_cpu_clk_speed_func - Type of the function pointer for CPU_SPEED_FUNC -+ * @param clock_speed - pointer to store the current CPU clock speed in MHz -+ * -+ * Returns 0 on success, otherwise negative error code. -+ * -+ * This is mainly used to implement OpenCL's clGetDeviceInfo(). -+ */ -+typedef int (*kbase_cpu_clk_speed_func) (u32 *clock_speed); -+ -+/** -+ * kbase_gpu_clk_speed_func - Type of the function pointer for GPU_SPEED_FUNC -+ * @param clock_speed - pointer to store the current GPU clock speed in MHz -+ * -+ * Returns 0 on success, otherwise negative error code. -+ * When an error is returned the caller assumes maximum GPU speed stored in -+ * gpu_freq_khz_max. -+ * -+ * If the system timer is not available then this function is required -+ * for the OpenCL queue profiling to return correct timing information. -+ * -+ */ -+typedef int (*kbase_gpu_clk_speed_func) (u32 *clock_speed); -+ -+#ifdef CONFIG_OF -+struct kbase_platform_config { -+}; -+#else -+ -+/* -+ * @brief Specifies start and end of I/O memory region. -+ */ -+struct kbase_io_memory_region { -+ u64 start; -+ u64 end; -+}; -+ -+/* -+ * @brief Specifies I/O related resources like IRQs and memory region for I/O operations. -+ */ -+struct kbase_io_resources { -+ u32 job_irq_number; -+ u32 mmu_irq_number; -+ u32 gpu_irq_number; -+ struct kbase_io_memory_region io_memory_region; -+}; -+ -+struct kbase_platform_config { -+ const struct kbase_io_resources *io_resources; -+}; -+ -+#endif /* CONFIG_OF */ -+ -+/** -+ * @brief Gets the pointer to platform config. -+ * -+ * @return Pointer to the platform config -+ */ -+struct kbase_platform_config *kbase_get_platform_config(void); -+ -+/** -+ * kbasep_platform_device_init: - Platform specific call to initialize hardware -+ * @kbdev: kbase device pointer -+ * -+ * Function calls a platform defined routine if specified in the configuration -+ * attributes. The routine can initialize any hardware and context state that -+ * is required for the GPU block to function. -+ * -+ * Return: 0 if no errors have been found in the config. -+ * Negative error code otherwise. -+ */ -+int kbasep_platform_device_init(struct kbase_device *kbdev); -+ -+/** -+ * kbasep_platform_device_term - Platform specific call to terminate hardware -+ * @kbdev: Kbase device pointer -+ * -+ * Function calls a platform defined routine if specified in the configuration -+ * attributes. The routine can destroy any platform specific context state and -+ * shut down any hardware functionality that are outside of the Power Management -+ * callbacks. -+ * -+ */ -+void kbasep_platform_device_term(struct kbase_device *kbdev); -+ -+ -+/** -+ * kbase_platform_early_init - Early initialisation of the platform code -+ * -+ * This function will be called when the module is loaded to perform any -+ * early initialisation required by the platform code. Such as reading -+ * platform specific device tree entries for the GPU. -+ * -+ * Return: 0 for success, any other fail causes module initialisation to fail -+ */ -+int kbase_platform_early_init(void); -+ -+#ifndef CONFIG_OF -+#ifdef CONFIG_MALI_PLATFORM_FAKE -+/** -+ * kbase_platform_fake_register - Register a platform device for the GPU -+ * -+ * This can be used to register a platform device on systems where device tree -+ * is not enabled and the platform initialisation code in the kernel doesn't -+ * create the GPU device. Where possible device tree should be used instead. -+ * -+ * Return: 0 for success, any other fail causes module initialisation to fail -+ */ -+int kbase_platform_fake_register(void); -+ -+/** -+ * kbase_platform_fake_unregister - Unregister a fake platform device -+ * -+ * Unregister the platform device created with kbase_platform_fake_register() -+ */ -+void kbase_platform_fake_unregister(void); -+#endif -+#endif -+ -+ /** @} *//* end group kbase_config */ -+ /** @} *//* end group base_kbase_api */ -+ /** @} *//* end group base_api */ -+ -+#endif /* _KBASE_CONFIG_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h b/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h -new file mode 100644 -index 0000000..69079e7 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_config_defaults.h -@@ -0,0 +1,226 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @file mali_kbase_config_defaults.h -+ * -+ * Default values for configuration settings -+ * -+ */ -+ -+#ifndef _KBASE_CONFIG_DEFAULTS_H_ -+#define _KBASE_CONFIG_DEFAULTS_H_ -+ -+/* Include mandatory definitions per platform */ -+#include -+ -+/** -+* Boolean indicating whether the driver is configured to be secure at -+* a potential loss of performance. -+* -+* This currently affects only r0p0-15dev0 HW and earlier. -+* -+* On r0p0-15dev0 HW and earlier, there are tradeoffs between security and -+* performance: -+* -+* - When this is set to true, the driver remains fully secure, -+* but potentially loses performance compared with setting this to -+* false. -+* - When set to false, the driver is open to certain security -+* attacks. -+* -+* From r0p0-00rel0 and onwards, there is no security loss by setting -+* this to false, and no performance loss by setting it to -+* true. -+*/ -+#define DEFAULT_SECURE_BUT_LOSS_OF_PERFORMANCE false -+ -+enum { -+ /** -+ * Use unrestricted Address ID width on the AXI bus. -+ */ -+ KBASE_AID_32 = 0x0, -+ -+ /** -+ * Restrict GPU to a half of maximum Address ID count. -+ * This will reduce performance, but reduce bus load due to GPU. -+ */ -+ KBASE_AID_16 = 0x3, -+ -+ /** -+ * Restrict GPU to a quarter of maximum Address ID count. -+ * This will reduce performance, but reduce bus load due to GPU. -+ */ -+ KBASE_AID_8 = 0x2, -+ -+ /** -+ * Restrict GPU to an eighth of maximum Address ID count. -+ * This will reduce performance, but reduce bus load due to GPU. -+ */ -+ KBASE_AID_4 = 0x1 -+}; -+ -+/** -+ * Default setting for read Address ID limiting on AXI bus. -+ * -+ * Attached value: u32 register value -+ * KBASE_AID_32 - use the full 32 IDs (5 ID bits) -+ * KBASE_AID_16 - use 16 IDs (4 ID bits) -+ * KBASE_AID_8 - use 8 IDs (3 ID bits) -+ * KBASE_AID_4 - use 4 IDs (2 ID bits) -+ * Default value: KBASE_AID_32 (no limit). Note hardware implementation -+ * may limit to a lower value. -+ */ -+#define DEFAULT_ARID_LIMIT KBASE_AID_32 -+ -+/** -+ * Default setting for write Address ID limiting on AXI. -+ * -+ * Attached value: u32 register value -+ * KBASE_AID_32 - use the full 32 IDs (5 ID bits) -+ * KBASE_AID_16 - use 16 IDs (4 ID bits) -+ * KBASE_AID_8 - use 8 IDs (3 ID bits) -+ * KBASE_AID_4 - use 4 IDs (2 ID bits) -+ * Default value: KBASE_AID_32 (no limit). Note hardware implementation -+ * may limit to a lower value. -+ */ -+#define DEFAULT_AWID_LIMIT KBASE_AID_32 -+ -+/** -+ * Default UMP device mapping. A UMP_DEVICE__SHIFT value which -+ * defines which UMP device this GPU should be mapped to. -+ */ -+#define DEFAULT_UMP_GPU_DEVICE_SHIFT UMP_DEVICE_Z_SHIFT -+ -+/* -+ * Default period for DVFS sampling -+ */ -+#define DEFAULT_PM_DVFS_PERIOD 100 /* 100ms */ -+ -+/* -+ * Power Management poweroff tick granuality. This is in nanoseconds to -+ * allow HR timer support. -+ * -+ * On each scheduling tick, the power manager core may decide to: -+ * -# Power off one or more shader cores -+ * -# Power off the entire GPU -+ */ -+#define DEFAULT_PM_GPU_POWEROFF_TICK_NS (400000) /* 400us */ -+ -+/* -+ * Power Manager number of ticks before shader cores are powered off -+ */ -+#define DEFAULT_PM_POWEROFF_TICK_SHADER (2) /* 400-800us */ -+ -+/* -+ * Power Manager number of ticks before GPU is powered off -+ */ -+#define DEFAULT_PM_POWEROFF_TICK_GPU (2) /* 400-800us */ -+ -+/* -+ * Default scheduling tick granuality -+ */ -+#define DEFAULT_JS_SCHEDULING_PERIOD_NS (100000000u) /* 100ms */ -+ -+/* -+ * Default minimum number of scheduling ticks before jobs are soft-stopped. -+ * -+ * This defines the time-slice for a job (which may be different from that of a -+ * context) -+ */ -+#define DEFAULT_JS_SOFT_STOP_TICKS (1) /* 100ms-200ms */ -+ -+/* -+ * Default minimum number of scheduling ticks before CL jobs are soft-stopped. -+ */ -+#define DEFAULT_JS_SOFT_STOP_TICKS_CL (1) /* 100ms-200ms */ -+ -+/* -+ * Default minimum number of scheduling ticks before jobs are hard-stopped -+ */ -+#define DEFAULT_JS_HARD_STOP_TICKS_SS (50) /* 5s */ -+#define DEFAULT_JS_HARD_STOP_TICKS_SS_8408 (300) /* 30s */ -+ -+/* -+ * Default minimum number of scheduling ticks before CL jobs are hard-stopped. -+ */ -+#define DEFAULT_JS_HARD_STOP_TICKS_CL (50) /* 5s */ -+ -+/* -+ * Default minimum number of scheduling ticks before jobs are hard-stopped -+ * during dumping -+ */ -+#define DEFAULT_JS_HARD_STOP_TICKS_DUMPING (15000) /* 1500s */ -+ -+/* -+ * Default timeout for some software jobs, after which the software event wait -+ * jobs will be cancelled. -+ */ -+#define DEFAULT_JS_SOFT_JOB_TIMEOUT (3000) /* 3s */ -+ -+/* -+ * Default minimum number of scheduling ticks before the GPU is reset to clear a -+ * "stuck" job -+ */ -+#define DEFAULT_JS_RESET_TICKS_SS (55) /* 5.5s */ -+#define DEFAULT_JS_RESET_TICKS_SS_8408 (450) /* 45s */ -+ -+/* -+ * Default minimum number of scheduling ticks before the GPU is reset to clear a -+ * "stuck" CL job. -+ */ -+#define DEFAULT_JS_RESET_TICKS_CL (55) /* 5.5s */ -+ -+/* -+ * Default minimum number of scheduling ticks before the GPU is reset to clear a -+ * "stuck" job during dumping. -+ */ -+#define DEFAULT_JS_RESET_TICKS_DUMPING (15020) /* 1502s */ -+ -+/* -+ * Default number of milliseconds given for other jobs on the GPU to be -+ * soft-stopped when the GPU needs to be reset. -+ */ -+#define DEFAULT_RESET_TIMEOUT_MS (3000) /* 3s */ -+ -+/* -+ * Default timeslice that a context is scheduled in for, in nanoseconds. -+ * -+ * When a context has used up this amount of time across its jobs, it is -+ * scheduled out to let another run. -+ * -+ * @note the resolution is nanoseconds (ns) here, because that's the format -+ * often used by the OS. -+ */ -+#define DEFAULT_JS_CTX_TIMESLICE_NS (50000000) /* 50ms */ -+ -+/* -+ * Perform GPU power down using only platform specific code, skipping DDK power -+ * management. -+ * -+ * If this is non-zero then kbase will avoid powering down shader cores, the -+ * tiler, and the L2 cache, instead just powering down the entire GPU through -+ * platform specific code. This may be required for certain platform -+ * integrations. -+ * -+ * Note that as this prevents kbase from powering down shader cores, this limits -+ * the available power policies to coarse_demand and always_on. -+ */ -+#define PLATFORM_POWER_DOWN_ONLY (0) -+ -+#endif /* _KBASE_CONFIG_DEFAULTS_H_ */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_context.c b/drivers/gpu/arm/midgard/mali_kbase_context.c -new file mode 100644 -index 0000000..ad20e61 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_context.c -@@ -0,0 +1,362 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Base kernel context APIs -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * kbase_create_context() - Create a kernel base context. -+ * @kbdev: Kbase device -+ * @is_compat: Force creation of a 32-bit context -+ * -+ * Allocate and init a kernel base context. -+ * -+ * Return: new kbase context -+ */ -+struct kbase_context * -+kbase_create_context(struct kbase_device *kbdev, bool is_compat) -+{ -+ struct kbase_context *kctx; -+ int err; -+ struct page *p; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ /* zero-inited as lot of code assume it's zero'ed out on create */ -+ kctx = vzalloc(sizeof(*kctx)); -+ -+ if (!kctx) -+ goto out; -+ -+ /* creating a context is considered a disjoint event */ -+ kbase_disjoint_event(kbdev); -+ -+ kctx->kbdev = kbdev; -+ kctx->as_nr = KBASEP_AS_NR_INVALID; -+ atomic_set(&kctx->refcount, 0); -+ if (is_compat) -+ kbase_ctx_flag_set(kctx, KCTX_COMPAT); -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+ kctx->timeline.owner_tgid = task_tgid_nr(current); -+#endif -+ atomic_set(&kctx->setup_complete, 0); -+ atomic_set(&kctx->setup_in_progress, 0); -+ spin_lock_init(&kctx->mm_update_lock); -+ kctx->process_mm = NULL; -+ atomic_set(&kctx->nonmapped_pages, 0); -+ kctx->slots_pullable = 0; -+ kctx->tgid = current->tgid; -+ kctx->pid = current->pid; -+ -+ err = kbase_mem_pool_init(&kctx->mem_pool, -+ kbdev->mem_pool_max_size_default, -+ KBASE_MEM_POOL_4KB_PAGE_TABLE_ORDER, -+ kctx->kbdev, -+ &kbdev->mem_pool); -+ if (err) -+ goto free_kctx; -+ -+ err = kbase_mem_pool_init(&kctx->lp_mem_pool, -+ (kbdev->mem_pool_max_size_default >> 9), -+ KBASE_MEM_POOL_2MB_PAGE_TABLE_ORDER, -+ kctx->kbdev, -+ &kbdev->lp_mem_pool); -+ if (err) -+ goto free_mem_pool; -+ -+ err = kbase_mem_evictable_init(kctx); -+ if (err) -+ goto free_both_pools; -+ -+ atomic_set(&kctx->used_pages, 0); -+ -+ err = kbase_jd_init(kctx); -+ if (err) -+ goto deinit_evictable; -+ -+ err = kbasep_js_kctx_init(kctx); -+ if (err) -+ goto free_jd; /* safe to call kbasep_js_kctx_term in this case */ -+ -+ err = kbase_event_init(kctx); -+ if (err) -+ goto free_jd; -+ -+ atomic_set(&kctx->drain_pending, 0); -+ -+ mutex_init(&kctx->reg_lock); -+ -+ mutex_init(&kctx->mem_partials_lock); -+ INIT_LIST_HEAD(&kctx->mem_partials); -+ -+ INIT_LIST_HEAD(&kctx->waiting_soft_jobs); -+ spin_lock_init(&kctx->waiting_soft_jobs_lock); -+#ifdef CONFIG_KDS -+ INIT_LIST_HEAD(&kctx->waiting_kds_resource); -+#endif -+ err = kbase_dma_fence_init(kctx); -+ if (err) -+ goto free_event; -+ -+ err = kbase_mmu_init(kctx); -+ if (err) -+ goto term_dma_fence; -+ -+ do { -+ err = kbase_mem_pool_grow(&kctx->mem_pool, -+ MIDGARD_MMU_BOTTOMLEVEL); -+ if (err) -+ goto pgd_no_mem; -+ -+ mutex_lock(&kctx->mmu_lock); -+ kctx->pgd = kbase_mmu_alloc_pgd(kctx); -+ mutex_unlock(&kctx->mmu_lock); -+ } while (!kctx->pgd); -+ -+ p = kbase_mem_alloc_page(&kctx->mem_pool); -+ if (!p) -+ goto no_sink_page; -+ kctx->aliasing_sink_page = as_tagged(page_to_phys(p)); -+ -+ init_waitqueue_head(&kctx->event_queue); -+ -+ kctx->cookies = KBASE_COOKIE_MASK; -+ -+ /* Make sure page 0 is not used... */ -+ err = kbase_region_tracker_init(kctx); -+ if (err) -+ goto no_region_tracker; -+ -+ err = kbase_sticky_resource_init(kctx); -+ if (err) -+ goto no_sticky; -+ -+ err = kbase_jit_init(kctx); -+ if (err) -+ goto no_jit; -+#ifdef CONFIG_GPU_TRACEPOINTS -+ atomic_set(&kctx->jctx.work_id, 0); -+#endif -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+ atomic_set(&kctx->timeline.jd_atoms_in_flight, 0); -+#endif -+ -+ kctx->id = atomic_add_return(1, &(kbdev->ctx_num)) - 1; -+ -+ mutex_init(&kctx->vinstr_cli_lock); -+ -+ setup_timer(&kctx->soft_job_timeout, -+ kbasep_soft_job_timeout_worker, -+ (uintptr_t)kctx); -+ -+ return kctx; -+ -+no_jit: -+ kbase_gpu_vm_lock(kctx); -+ kbase_sticky_resource_term(kctx); -+ kbase_gpu_vm_unlock(kctx); -+no_sticky: -+ kbase_region_tracker_term(kctx); -+no_region_tracker: -+ kbase_mem_pool_free(&kctx->mem_pool, p, false); -+no_sink_page: -+ /* VM lock needed for the call to kbase_mmu_free_pgd */ -+ kbase_gpu_vm_lock(kctx); -+ kbase_mmu_free_pgd(kctx); -+ kbase_gpu_vm_unlock(kctx); -+pgd_no_mem: -+ kbase_mmu_term(kctx); -+term_dma_fence: -+ kbase_dma_fence_term(kctx); -+free_event: -+ kbase_event_cleanup(kctx); -+free_jd: -+ /* Safe to call this one even when didn't initialize (assuming kctx was sufficiently zeroed) */ -+ kbasep_js_kctx_term(kctx); -+ kbase_jd_exit(kctx); -+deinit_evictable: -+ kbase_mem_evictable_deinit(kctx); -+free_both_pools: -+ kbase_mem_pool_term(&kctx->lp_mem_pool); -+free_mem_pool: -+ kbase_mem_pool_term(&kctx->mem_pool); -+free_kctx: -+ vfree(kctx); -+out: -+ return NULL; -+} -+KBASE_EXPORT_SYMBOL(kbase_create_context); -+ -+static void kbase_reg_pending_dtor(struct kbase_va_region *reg) -+{ -+ dev_dbg(reg->kctx->kbdev->dev, "Freeing pending unmapped region\n"); -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+ kfree(reg); -+} -+ -+/** -+ * kbase_destroy_context - Destroy a kernel base context. -+ * @kctx: Context to destroy -+ * -+ * Calls kbase_destroy_os_context() to free OS specific structures. -+ * Will release all outstanding regions. -+ */ -+void kbase_destroy_context(struct kbase_context *kctx) -+{ -+ struct kbase_device *kbdev; -+ int pages; -+ unsigned long pending_regions_to_clean; -+ unsigned long flags; -+ struct page *p; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ -+ kbdev = kctx->kbdev; -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ -+ KBASE_TRACE_ADD(kbdev, CORE_CTX_DESTROY, kctx, NULL, 0u, 0u); -+ -+ /* Ensure the core is powered up for the destroy process */ -+ /* A suspend won't happen here, because we're in a syscall from a userspace -+ * thread. */ -+ kbase_pm_context_active(kbdev); -+ -+ kbase_jd_zap_context(kctx); -+ -+#ifdef CONFIG_DEBUG_FS -+ /* Removing the rest of the debugfs entries here as we want to keep the -+ * atom debugfs interface alive until all atoms have completed. This -+ * is useful for debugging hung contexts. */ -+ debugfs_remove_recursive(kctx->kctx_dentry); -+#endif -+ -+ kbase_event_cleanup(kctx); -+ -+ /* -+ * JIT must be terminated before the code below as it must be called -+ * without the region lock being held. -+ * The code above ensures no new JIT allocations can be made by -+ * by the time we get to this point of context tear down. -+ */ -+ kbase_jit_term(kctx); -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ kbase_sticky_resource_term(kctx); -+ -+ /* MMU is disabled as part of scheduling out the context */ -+ kbase_mmu_free_pgd(kctx); -+ -+ /* drop the aliasing sink page now that it can't be mapped anymore */ -+ p = phys_to_page(as_phys_addr_t(kctx->aliasing_sink_page)); -+ kbase_mem_pool_free(&kctx->mem_pool, p, false); -+ -+ /* free pending region setups */ -+ pending_regions_to_clean = (~kctx->cookies) & KBASE_COOKIE_MASK; -+ while (pending_regions_to_clean) { -+ unsigned int cookie = __ffs(pending_regions_to_clean); -+ -+ BUG_ON(!kctx->pending_regions[cookie]); -+ -+ kbase_reg_pending_dtor(kctx->pending_regions[cookie]); -+ -+ kctx->pending_regions[cookie] = NULL; -+ pending_regions_to_clean &= ~(1UL << cookie); -+ } -+ -+ kbase_region_tracker_term(kctx); -+ kbase_gpu_vm_unlock(kctx); -+ -+ /* Safe to call this one even when didn't initialize (assuming kctx was sufficiently zeroed) */ -+ kbasep_js_kctx_term(kctx); -+ -+ kbase_jd_exit(kctx); -+ -+ kbase_pm_context_idle(kbdev); -+ -+ kbase_dma_fence_term(kctx); -+ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, flags); -+ kbase_ctx_sched_remove_ctx(kctx); -+ spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ kbase_mmu_term(kctx); -+ -+ pages = atomic_read(&kctx->used_pages); -+ if (pages != 0) -+ dev_warn(kbdev->dev, "%s: %d pages in use!\n", __func__, pages); -+ -+ kbase_mem_evictable_deinit(kctx); -+ kbase_mem_pool_term(&kctx->mem_pool); -+ kbase_mem_pool_term(&kctx->lp_mem_pool); -+ WARN_ON(atomic_read(&kctx->nonmapped_pages) != 0); -+ -+ vfree(kctx); -+} -+KBASE_EXPORT_SYMBOL(kbase_destroy_context); -+ -+/** -+ * kbase_context_set_create_flags - Set creation flags on a context -+ * @kctx: Kbase context -+ * @flags: Flags to set -+ * -+ * Return: 0 on success -+ */ -+int kbase_context_set_create_flags(struct kbase_context *kctx, u32 flags) -+{ -+ int err = 0; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ unsigned long irq_flags; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ /* Validate flags */ -+ if (flags != (flags & BASE_CONTEXT_CREATE_KERNEL_FLAGS)) { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, irq_flags); -+ -+ /* Translate the flags */ -+ if ((flags & BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) == 0) -+ kbase_ctx_flag_clear(kctx, KCTX_SUBMIT_DISABLED); -+ -+ /* Latch the initial attributes into the Job Scheduler */ -+ kbasep_js_ctx_attr_set_initial_attrs(kctx->kbdev, kctx); -+ -+ spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, irq_flags); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ out: -+ return err; -+} -+KBASE_EXPORT_SYMBOL(kbase_context_set_create_flags); -diff --git a/drivers/gpu/arm/midgard/mali_kbase_context.h b/drivers/gpu/arm/midgard/mali_kbase_context.h -new file mode 100644 -index 0000000..a3f5bb0 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_context.h -@@ -0,0 +1,90 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_CONTEXT_H_ -+#define _KBASE_CONTEXT_H_ -+ -+#include -+ -+ -+int kbase_context_set_create_flags(struct kbase_context *kctx, u32 flags); -+ -+/** -+ * kbase_ctx_flag - Check if @flag is set on @kctx -+ * @kctx: Pointer to kbase context to check -+ * @flag: Flag to check -+ * -+ * Return: true if @flag is set on @kctx, false if not. -+ */ -+static inline bool kbase_ctx_flag(struct kbase_context *kctx, -+ enum kbase_context_flags flag) -+{ -+ return atomic_read(&kctx->flags) & flag; -+} -+ -+/** -+ * kbase_ctx_flag_clear - Clear @flag on @kctx -+ * @kctx: Pointer to kbase context -+ * @flag: Flag to clear -+ * -+ * Clear the @flag on @kctx. This is done atomically, so other flags being -+ * cleared or set at the same time will be safe. -+ * -+ * Some flags have locking requirements, check the documentation for the -+ * respective flags. -+ */ -+static inline void kbase_ctx_flag_clear(struct kbase_context *kctx, -+ enum kbase_context_flags flag) -+{ -+#if KERNEL_VERSION(4, 3, 0) > LINUX_VERSION_CODE -+ /* -+ * Earlier kernel versions doesn't have atomic_andnot() or -+ * atomic_and(). atomic_clear_mask() was only available on some -+ * architectures and removed on arm in v3.13 on arm and arm64. -+ * -+ * Use a compare-exchange loop to clear the flag on pre 4.3 kernels, -+ * when atomic_andnot() becomes available. -+ */ -+ int old, new; -+ -+ do { -+ old = atomic_read(&kctx->flags); -+ new = old & ~flag; -+ -+ } while (atomic_cmpxchg(&kctx->flags, old, new) != old); -+#else -+ atomic_andnot(flag, &kctx->flags); -+#endif -+} -+ -+/** -+ * kbase_ctx_flag_set - Set @flag on @kctx -+ * @kctx: Pointer to kbase context -+ * @flag: Flag to clear -+ * -+ * Set the @flag on @kctx. This is done atomically, so other flags being -+ * cleared or set at the same time will be safe. -+ * -+ * Some flags have locking requirements, check the documentation for the -+ * respective flags. -+ */ -+static inline void kbase_ctx_flag_set(struct kbase_context *kctx, -+ enum kbase_context_flags flag) -+{ -+ atomic_or(flag, &kctx->flags); -+} -+#endif /* _KBASE_CONTEXT_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -new file mode 100644 -index 0000000..0cccb0b ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -@@ -0,0 +1,4867 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef CONFIG_MALI_DEVFREQ -+#include -+#include -+#ifdef CONFIG_DEVFREQ_THERMAL -+#include -+#endif /* CONFIG_DEVFREQ_THERMAL */ -+#endif /* CONFIG_MALI_DEVFREQ */ -+#ifdef CONFIG_MALI_NO_MALI -+#include "mali_kbase_model_linux.h" -+#endif /* CONFIG_MALI_NO_MALI */ -+#include "mali_kbase_mem_profile_debugfs_buf_size.h" -+#include "mali_kbase_debug_mem_view.h" -+#include "mali_kbase_mem.h" -+#include "mali_kbase_mem_pool_debugfs.h" -+#if !MALI_CUSTOMER_RELEASE -+#include "mali_kbase_regs_dump_debugfs.h" -+#endif /* !MALI_CUSTOMER_RELEASE */ -+#include "mali_kbase_regs_history_debugfs.h" -+#include -+#include -+#include -+#include -+#include "mali_kbase_ioctl.h" -+ -+#ifdef CONFIG_KDS -+#include -+#include -+#endif /* CONFIG_KDS */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* is_compat_task */ -+#include -+#include -+#include -+#include -+#ifdef CONFIG_MALI_PLATFORM_FAKE -+#include -+#endif /*CONFIG_MALI_PLATFORM_FAKE */ -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+#include -+#endif /* CONFIG_SYNC || CONFIG_SYNC_FILE */ -+#include -+#include -+ -+#include -+ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) -+#include -+#else -+#include -+#endif -+ -+#include -+ -+#include -+ -+/* GPU IRQ Tags */ -+#define JOB_IRQ_TAG 0 -+#define MMU_IRQ_TAG 1 -+#define GPU_IRQ_TAG 2 -+ -+#if MALI_UNIT_TEST -+static struct kbase_exported_test_data shared_kernel_test_data; -+EXPORT_SYMBOL(shared_kernel_test_data); -+#endif /* MALI_UNIT_TEST */ -+ -+static int kbase_dev_nr; -+ -+static DEFINE_MUTEX(kbase_dev_list_lock); -+static LIST_HEAD(kbase_dev_list); -+ -+#define KERNEL_SIDE_DDK_VERSION_STRING "K:" MALI_RELEASE_NAME "(GPL)" -+static inline void __compile_time_asserts(void) -+{ -+ CSTD_COMPILE_TIME_ASSERT(sizeof(KERNEL_SIDE_DDK_VERSION_STRING) <= KBASE_GET_VERSION_BUFFER_SIZE); -+} -+ -+static int kbase_api_handshake(struct kbase_context *kctx, -+ struct kbase_ioctl_version_check *version) -+{ -+ switch (version->major) { -+ case BASE_UK_VERSION_MAJOR: -+ /* set minor to be the lowest common */ -+ version->minor = min_t(int, BASE_UK_VERSION_MINOR, -+ (int)version->minor); -+ break; -+ default: -+ /* We return our actual version regardless if it -+ * matches the version returned by userspace - -+ * userspace can bail if it can't handle this -+ * version */ -+ version->major = BASE_UK_VERSION_MAJOR; -+ version->minor = BASE_UK_VERSION_MINOR; -+ break; -+ } -+ -+ /* save the proposed version number for later use */ -+ kctx->api_version = KBASE_API_VERSION(version->major, version->minor); -+ -+ return 0; -+} -+ -+/** -+ * enum mali_error - Mali error codes shared with userspace -+ * -+ * This is subset of those common Mali errors that can be returned to userspace. -+ * Values of matching user and kernel space enumerators MUST be the same. -+ * MALI_ERROR_NONE is guaranteed to be 0. -+ * -+ * @MALI_ERROR_NONE: Success -+ * @MALI_ERROR_OUT_OF_GPU_MEMORY: Not used in the kernel driver -+ * @MALI_ERROR_OUT_OF_MEMORY: Memory allocation failure -+ * @MALI_ERROR_FUNCTION_FAILED: Generic error code -+ */ -+enum mali_error { -+ MALI_ERROR_NONE = 0, -+ MALI_ERROR_OUT_OF_GPU_MEMORY, -+ MALI_ERROR_OUT_OF_MEMORY, -+ MALI_ERROR_FUNCTION_FAILED, -+}; -+ -+enum { -+ inited_mem = (1u << 0), -+ inited_js = (1u << 1), -+ inited_pm_runtime_init = (1u << 2), -+#ifdef CONFIG_MALI_DEVFREQ -+ inited_devfreq = (1u << 3), -+#endif /* CONFIG_MALI_DEVFREQ */ -+ inited_tlstream = (1u << 4), -+ inited_backend_early = (1u << 5), -+ inited_backend_late = (1u << 6), -+ inited_device = (1u << 7), -+ inited_vinstr = (1u << 8), -+ -+ inited_job_fault = (1u << 10), -+ inited_sysfs_group = (1u << 11), -+ inited_misc_register = (1u << 12), -+ inited_get_device = (1u << 13), -+ inited_dev_list = (1u << 14), -+ inited_debugfs = (1u << 15), -+ inited_gpu_device = (1u << 16), -+ inited_registers_map = (1u << 17), -+ inited_io_history = (1u << 18), -+ inited_power_control = (1u << 19), -+ inited_buslogger = (1u << 20), -+ inited_protected = (1u << 21), -+ inited_ctx_sched = (1u << 22) -+}; -+ -+ -+#ifdef CONFIG_MALI_DEBUG -+#define INACTIVE_WAIT_MS (5000) -+ -+void kbase_set_driver_inactive(struct kbase_device *kbdev, bool inactive) -+{ -+ kbdev->driver_inactive = inactive; -+ wake_up(&kbdev->driver_inactive_wait); -+ -+ /* Wait for any running IOCTLs to complete */ -+ if (inactive) -+ msleep(INACTIVE_WAIT_MS); -+} -+KBASE_EXPORT_TEST_API(kbase_set_driver_inactive); -+#endif /* CONFIG_MALI_DEBUG */ -+ -+/** -+ * kbase_legacy_dispatch - UKK dispatch function -+ * -+ * This is the dispatch function for the legacy UKK ioctl interface. No new -+ * ioctls should be added to this function, see kbase_ioctl instead. -+ * -+ * @kctx: The kernel context structure -+ * @args: Pointer to the data structure passed from/to user space -+ * @args_size: Size of the data structure -+ */ -+static int kbase_legacy_dispatch(struct kbase_context *kctx, -+ void * const args, u32 args_size) -+{ -+ struct kbase_device *kbdev; -+ union uk_header *ukh = args; -+ u32 id; -+ int ret = 0; -+ -+ KBASE_DEBUG_ASSERT(ukh != NULL); -+ -+ kbdev = kctx->kbdev; -+ id = ukh->id; -+ ukh->ret = MALI_ERROR_NONE; /* Be optimistic */ -+ -+#ifdef CONFIG_MALI_DEBUG -+ wait_event(kbdev->driver_inactive_wait, -+ kbdev->driver_inactive == false); -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ if (UKP_FUNC_ID_CHECK_VERSION == id) { -+ struct uku_version_check_args *version_check; -+ struct kbase_ioctl_version_check version; -+ -+ if (args_size != sizeof(struct uku_version_check_args)) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ return 0; -+ } -+ version_check = (struct uku_version_check_args *)args; -+ version.minor = version_check->minor; -+ version.major = version_check->major; -+ -+ kbase_api_handshake(kctx, &version); -+ -+ version_check->minor = version.minor; -+ version_check->major = version.major; -+ ukh->ret = MALI_ERROR_NONE; -+ return 0; -+ } -+ -+ /* block calls until version handshake */ -+ if (kctx->api_version == 0) -+ return -EINVAL; -+ -+ if (!atomic_read(&kctx->setup_complete)) { -+ struct kbase_uk_set_flags *kbase_set_flags; -+ -+ /* setup pending, try to signal that we'll do the setup, -+ * if setup was already in progress, err this call -+ */ -+ if (atomic_cmpxchg(&kctx->setup_in_progress, 0, 1) != 0) -+ return -EINVAL; -+ -+ /* if unexpected call, will stay stuck in setup mode -+ * (is it the only call we accept?) -+ */ -+ if (id != KBASE_FUNC_SET_FLAGS) -+ return -EINVAL; -+ -+ kbase_set_flags = (struct kbase_uk_set_flags *)args; -+ -+ /* if not matching the expected call, stay in setup mode */ -+ if (sizeof(*kbase_set_flags) != args_size) -+ goto bad_size; -+ -+ /* if bad flags, will stay stuck in setup mode */ -+ if (kbase_context_set_create_flags(kctx, -+ kbase_set_flags->create_flags) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ -+ atomic_set(&kctx->setup_complete, 1); -+ return 0; -+ } -+ -+ /* setup complete, perform normal operation */ -+ switch (id) { -+ case KBASE_FUNC_MEM_JIT_INIT: -+ { -+ struct kbase_uk_mem_jit_init *jit_init = args; -+ -+ if (sizeof(*jit_init) != args_size) -+ goto bad_size; -+ -+ if (kbase_region_tracker_init_jit(kctx, -+ jit_init->va_pages)) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ case KBASE_FUNC_MEM_ALLOC: -+ { -+ struct kbase_uk_mem_alloc *mem = args; -+ struct kbase_va_region *reg; -+ -+ if (sizeof(*mem) != args_size) -+ goto bad_size; -+ -+#if defined(CONFIG_64BIT) -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+ /* force SAME_VA if a 64-bit client */ -+ mem->flags |= BASE_MEM_SAME_VA; -+ } -+#endif -+ -+ reg = kbase_mem_alloc(kctx, mem->va_pages, -+ mem->commit_pages, mem->extent, -+ &mem->flags, &mem->gpu_va); -+ mem->va_alignment = 0; -+ -+ if (!reg) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ case KBASE_FUNC_MEM_IMPORT: { -+ struct kbase_uk_mem_import *mem_import = args; -+ void __user *phandle; -+ -+ if (sizeof(*mem_import) != args_size) -+ goto bad_size; -+#ifdef CONFIG_COMPAT -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ phandle = compat_ptr(mem_import->phandle); -+ else -+#endif -+ phandle = u64_to_user_ptr(mem_import->phandle); -+ -+ if (mem_import->type == BASE_MEM_IMPORT_TYPE_INVALID) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ -+ if (kbase_mem_import(kctx, -+ (enum base_mem_import_type) -+ mem_import->type, -+ phandle, -+ 0, -+ &mem_import->gpu_va, -+ &mem_import->va_pages, -+ &mem_import->flags)) { -+ mem_import->type = BASE_MEM_IMPORT_TYPE_INVALID; -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ } -+ break; -+ } -+ case KBASE_FUNC_MEM_ALIAS: { -+ struct kbase_uk_mem_alias *alias = args; -+ struct base_mem_aliasing_info __user *user_ai; -+ struct base_mem_aliasing_info *ai; -+ -+ if (sizeof(*alias) != args_size) -+ goto bad_size; -+ -+ if (alias->nents > 2048) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ if (!alias->nents) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ -+#ifdef CONFIG_COMPAT -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ user_ai = compat_ptr(alias->ai); -+ else -+#endif -+ user_ai = u64_to_user_ptr(alias->ai); -+ -+ ai = vmalloc(sizeof(*ai) * alias->nents); -+ -+ if (!ai) { -+ ukh->ret = MALI_ERROR_OUT_OF_MEMORY; -+ break; -+ } -+ -+ if (copy_from_user(ai, user_ai, -+ sizeof(*ai) * alias->nents)) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ goto copy_failed; -+ } -+ -+ alias->gpu_va = kbase_mem_alias(kctx, &alias->flags, -+ alias->stride, -+ alias->nents, ai, -+ &alias->va_pages); -+ if (!alias->gpu_va) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ goto no_alias; -+ } -+no_alias: -+copy_failed: -+ vfree(ai); -+ break; -+ } -+ case KBASE_FUNC_MEM_COMMIT: -+ { -+ struct kbase_uk_mem_commit *commit = args; -+ int ret; -+ -+ if (sizeof(*commit) != args_size) -+ goto bad_size; -+ -+ ret = kbase_mem_commit(kctx, commit->gpu_addr, -+ commit->pages); -+ -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ commit->result_subcode = -+ BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS; -+ -+ if (ret == 0) { -+ ukh->ret = MALI_ERROR_NONE; -+ commit->result_subcode = -+ BASE_BACKING_THRESHOLD_OK; -+ } else if (ret == -ENOMEM) { -+ commit->result_subcode = -+ BASE_BACKING_THRESHOLD_ERROR_OOM; -+ } -+ -+ break; -+ } -+ -+ case KBASE_FUNC_MEM_QUERY: -+ { -+ struct kbase_uk_mem_query *query = args; -+ -+ if (sizeof(*query) != args_size) -+ goto bad_size; -+ -+ if (kbase_mem_query(kctx, query->gpu_addr, -+ query->query, &query->value) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ else -+ ukh->ret = MALI_ERROR_NONE; -+ break; -+ } -+ break; -+ -+ case KBASE_FUNC_MEM_FLAGS_CHANGE: -+ { -+ struct kbase_uk_mem_flags_change *fc = args; -+ -+ if (sizeof(*fc) != args_size) -+ goto bad_size; -+ -+ if (kbase_mem_flags_change(kctx, fc->gpu_va, -+ fc->flags, fc->mask) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ -+ break; -+ } -+ case KBASE_FUNC_MEM_FREE: -+ { -+ struct kbase_uk_mem_free *mem = args; -+ -+ if (sizeof(*mem) != args_size) -+ goto bad_size; -+ -+ if (kbase_mem_free(kctx, mem->gpu_addr) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ -+ case KBASE_FUNC_JOB_SUBMIT: -+ { -+ struct kbase_uk_job_submit *job = args; -+ -+ if (sizeof(*job) != args_size) -+ goto bad_size; -+ -+ if (kbase_jd_submit(kctx, u64_to_user_ptr(job->addr), -+ job->nr_atoms, -+ job->stride, -+ false) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ -+ case KBASE_FUNC_SYNC: -+ { -+ struct kbase_uk_sync_now *sn = args; -+ -+ if (sizeof(*sn) != args_size) -+ goto bad_size; -+ -+ if (kbase_sync_now(kctx, &sn->sset.basep_sset) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ -+ case KBASE_FUNC_DISJOINT_QUERY: -+ { -+ struct kbase_uk_disjoint_query *dquery = args; -+ -+ if (sizeof(*dquery) != args_size) -+ goto bad_size; -+ -+ /* Get the disjointness counter value. */ -+ dquery->counter = kbase_disjoint_event_get(kctx->kbdev); -+ break; -+ } -+ -+ case KBASE_FUNC_POST_TERM: -+ { -+ kbase_event_close(kctx); -+ break; -+ } -+ -+ case KBASE_FUNC_HWCNT_SETUP: -+ { -+ struct kbase_uk_hwcnt_setup *setup = args; -+ -+ if (sizeof(*setup) != args_size) -+ goto bad_size; -+ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ if (kbase_vinstr_legacy_hwc_setup(kbdev->vinstr_ctx, -+ &kctx->vinstr_cli, setup) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ break; -+ } -+ -+ case KBASE_FUNC_HWCNT_DUMP: -+ { -+ /* args ignored */ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ if (kbase_vinstr_hwc_dump(kctx->vinstr_cli, -+ BASE_HWCNT_READER_EVENT_MANUAL) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ break; -+ } -+ -+ case KBASE_FUNC_HWCNT_CLEAR: -+ { -+ /* args ignored */ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ if (kbase_vinstr_hwc_clear(kctx->vinstr_cli) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ break; -+ } -+ -+ case KBASE_FUNC_HWCNT_READER_SETUP: -+ { -+ struct kbase_uk_hwcnt_reader_setup *setup = args; -+ -+ if (sizeof(*setup) != args_size) -+ goto bad_size; -+ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ if (kbase_vinstr_hwcnt_reader_setup(kbdev->vinstr_ctx, -+ setup) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ break; -+ } -+ -+ case KBASE_FUNC_GPU_PROPS_REG_DUMP: -+ { -+ struct kbase_uk_gpuprops *setup = args; -+ -+ if (sizeof(*setup) != args_size) -+ goto bad_size; -+ -+ if (kbase_gpuprops_uk_get_props(kctx, setup) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ case KBASE_FUNC_FIND_CPU_OFFSET: -+ { -+ struct kbase_uk_find_cpu_offset *find = args; -+ -+ if (sizeof(*find) != args_size) -+ goto bad_size; -+ -+ if (find->gpu_addr & ~PAGE_MASK) { -+ dev_warn(kbdev->dev, "kbase_legacy_dispatch case KBASE_FUNC_FIND_CPU_OFFSET: find->gpu_addr: passed parameter is invalid"); -+ goto out_bad; -+ } -+ -+ if (find->size > SIZE_MAX || find->cpu_addr > ULONG_MAX) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ } else { -+ int err; -+ -+ err = kbasep_find_enclosing_cpu_mapping_offset( -+ kctx, -+ find->cpu_addr, -+ find->size, -+ &find->offset); -+ -+ if (err) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ } -+ break; -+ } -+ case KBASE_FUNC_GET_VERSION: -+ { -+ struct kbase_uk_get_ddk_version *get_version = (struct kbase_uk_get_ddk_version *)args; -+ -+ if (sizeof(*get_version) != args_size) -+ goto bad_size; -+ -+ /* version buffer size check is made in compile time assert */ -+ memcpy(get_version->version_buffer, KERNEL_SIDE_DDK_VERSION_STRING, sizeof(KERNEL_SIDE_DDK_VERSION_STRING)); -+ get_version->version_string_size = sizeof(KERNEL_SIDE_DDK_VERSION_STRING); -+ break; -+ } -+ -+ case KBASE_FUNC_STREAM_CREATE: -+ { -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ struct kbase_uk_stream_create *screate = (struct kbase_uk_stream_create *)args; -+ -+ if (sizeof(*screate) != args_size) -+ goto bad_size; -+ -+ if (strnlen(screate->name, sizeof(screate->name)) >= sizeof(screate->name)) { -+ /* not NULL terminated */ -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ break; -+ } -+ -+ if (kbase_sync_fence_stream_create(screate->name, -+ &screate->fd) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ else -+ ukh->ret = MALI_ERROR_NONE; -+#else /* CONFIG_SYNC || CONFIG_SYNC_FILE */ -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+#endif /* CONFIG_SYNC || CONFIG_SYNC_FILE */ -+ break; -+ } -+ case KBASE_FUNC_FENCE_VALIDATE: -+ { -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ struct kbase_uk_fence_validate *fence_validate = (struct kbase_uk_fence_validate *)args; -+ -+ if (sizeof(*fence_validate) != args_size) -+ goto bad_size; -+ -+ if (kbase_sync_fence_validate(fence_validate->fd) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ else -+ ukh->ret = MALI_ERROR_NONE; -+#endif /* CONFIG_SYNC || CONFIG_SYNC_FILE */ -+ break; -+ } -+ -+ case KBASE_FUNC_SET_TEST_DATA: -+ { -+#if MALI_UNIT_TEST -+ struct kbase_uk_set_test_data *set_data = args; -+ -+ shared_kernel_test_data = set_data->test_data; -+ shared_kernel_test_data.kctx = (uintptr_t)kctx; -+ shared_kernel_test_data.mm = (uintptr_t)current->mm; -+ ukh->ret = MALI_ERROR_NONE; -+#endif /* MALI_UNIT_TEST */ -+ break; -+ } -+ -+ case KBASE_FUNC_INJECT_ERROR: -+ { -+#ifdef CONFIG_MALI_ERROR_INJECT -+ unsigned long flags; -+ struct kbase_error_params params = ((struct kbase_uk_error_params *)args)->params; -+ -+ /*mutex lock */ -+ spin_lock_irqsave(&kbdev->reg_op_lock, flags); -+ if (job_atom_inject_error(¶ms) != 0) -+ ukh->ret = MALI_ERROR_OUT_OF_MEMORY; -+ else -+ ukh->ret = MALI_ERROR_NONE; -+ spin_unlock_irqrestore(&kbdev->reg_op_lock, flags); -+ /*mutex unlock */ -+#endif /* CONFIG_MALI_ERROR_INJECT */ -+ break; -+ } -+ -+ case KBASE_FUNC_MODEL_CONTROL: -+ { -+#ifdef CONFIG_MALI_NO_MALI -+ unsigned long flags; -+ struct kbase_model_control_params params = -+ ((struct kbase_uk_model_control_params *)args)->params; -+ -+ /*mutex lock */ -+ spin_lock_irqsave(&kbdev->reg_op_lock, flags); -+ if (gpu_model_control(kbdev->model, ¶ms) != 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ else -+ ukh->ret = MALI_ERROR_NONE; -+ spin_unlock_irqrestore(&kbdev->reg_op_lock, flags); -+ /*mutex unlock */ -+#endif /* CONFIG_MALI_NO_MALI */ -+ break; -+ } -+ -+ case KBASE_FUNC_GET_PROFILING_CONTROLS: -+ { -+ struct kbase_uk_profiling_controls *controls = -+ (struct kbase_uk_profiling_controls *)args; -+ u32 i; -+ -+ if (sizeof(*controls) != args_size) -+ goto bad_size; -+ -+ for (i = FBDUMP_CONTROL_MIN; i < FBDUMP_CONTROL_MAX; i++) -+ controls->profiling_controls[i] = -+ kbdev->kbase_profiling_controls[i]; -+ -+ break; -+ } -+ -+ /* used only for testing purposes; these controls are to be set by gator through gator API */ -+ case KBASE_FUNC_SET_PROFILING_CONTROLS: -+ { -+ struct kbase_uk_profiling_controls *controls = -+ (struct kbase_uk_profiling_controls *)args; -+ u32 i; -+ -+ if (sizeof(*controls) != args_size) -+ goto bad_size; -+ -+ for (i = FBDUMP_CONTROL_MIN; i < FBDUMP_CONTROL_MAX; i++) -+ _mali_profiling_control(i, controls->profiling_controls[i]); -+ -+ break; -+ } -+ -+ case KBASE_FUNC_DEBUGFS_MEM_PROFILE_ADD: -+ { -+ struct kbase_uk_debugfs_mem_profile_add *add_data = -+ (struct kbase_uk_debugfs_mem_profile_add *)args; -+ char *buf; -+ char __user *user_buf; -+ -+ if (sizeof(*add_data) != args_size) -+ goto bad_size; -+ -+ if (add_data->len > KBASE_MEM_PROFILE_MAX_BUF_SIZE) { -+ dev_err(kbdev->dev, "buffer too big\n"); -+ goto out_bad; -+ } -+ -+#ifdef CONFIG_COMPAT -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ user_buf = compat_ptr(add_data->buf); -+ else -+#endif -+ user_buf = u64_to_user_ptr(add_data->buf); -+ -+ buf = kmalloc(add_data->len, GFP_KERNEL); -+ if (ZERO_OR_NULL_PTR(buf)) -+ goto out_bad; -+ -+ if (0 != copy_from_user(buf, user_buf, add_data->len)) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ kfree(buf); -+ goto out_bad; -+ } -+ -+ if (kbasep_mem_profile_debugfs_insert(kctx, buf, -+ add_data->len)) { -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ goto out_bad; -+ } -+ -+ break; -+ } -+ -+#ifdef CONFIG_MALI_NO_MALI -+ case KBASE_FUNC_SET_PRFCNT_VALUES: -+ { -+ -+ struct kbase_uk_prfcnt_values *params = -+ ((struct kbase_uk_prfcnt_values *)args); -+ gpu_model_set_dummy_prfcnt_sample(params->data, -+ params->size); -+ -+ break; -+ } -+#endif /* CONFIG_MALI_NO_MALI */ -+#ifdef BASE_LEGACY_UK10_4_SUPPORT -+ case KBASE_FUNC_TLSTREAM_ACQUIRE_V10_4: -+ { -+ struct kbase_uk_tlstream_acquire_v10_4 *tlstream_acquire -+ = args; -+ int ret; -+ -+ if (sizeof(*tlstream_acquire) != args_size) -+ goto bad_size; -+ -+ ret = kbase_tlstream_acquire( -+ kctx, 0); -+ if (ret < 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ else -+ tlstream_acquire->fd = ret; -+ break; -+ } -+#endif /* BASE_LEGACY_UK10_4_SUPPORT */ -+ case KBASE_FUNC_TLSTREAM_ACQUIRE: -+ { -+ struct kbase_uk_tlstream_acquire *tlstream_acquire = -+ args; -+ int ret; -+ -+ if (sizeof(*tlstream_acquire) != args_size) -+ goto bad_size; -+ -+ if (tlstream_acquire->flags & ~BASE_TLSTREAM_FLAGS_MASK) -+ goto out_bad; -+ -+ ret = kbase_tlstream_acquire( -+ kctx, tlstream_acquire->flags); -+ if (ret < 0) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ else -+ tlstream_acquire->fd = ret; -+ break; -+ } -+ case KBASE_FUNC_TLSTREAM_FLUSH: -+ { -+ struct kbase_uk_tlstream_flush *tlstream_flush = -+ args; -+ -+ if (sizeof(*tlstream_flush) != args_size) -+ goto bad_size; -+ -+ kbase_tlstream_flush_streams(); -+ break; -+ } -+#if MALI_UNIT_TEST -+ case KBASE_FUNC_TLSTREAM_TEST: -+ { -+ struct kbase_uk_tlstream_test *tlstream_test = args; -+ -+ if (sizeof(*tlstream_test) != args_size) -+ goto bad_size; -+ -+ kbase_tlstream_test( -+ tlstream_test->tpw_count, -+ tlstream_test->msg_delay, -+ tlstream_test->msg_count, -+ tlstream_test->aux_msg); -+ break; -+ } -+ case KBASE_FUNC_TLSTREAM_STATS: -+ { -+ struct kbase_uk_tlstream_stats *tlstream_stats = args; -+ -+ if (sizeof(*tlstream_stats) != args_size) -+ goto bad_size; -+ -+ kbase_tlstream_stats( -+ &tlstream_stats->bytes_collected, -+ &tlstream_stats->bytes_generated); -+ break; -+ } -+#endif /* MALI_UNIT_TEST */ -+ -+ case KBASE_FUNC_GET_CONTEXT_ID: -+ { -+ struct kbase_uk_context_id *info = args; -+ -+ info->id = kctx->id; -+ break; -+ } -+ -+ case KBASE_FUNC_SOFT_EVENT_UPDATE: -+ { -+ struct kbase_uk_soft_event_update *update = args; -+ -+ if (sizeof(*update) != args_size) -+ goto bad_size; -+ -+ if (((update->new_status != BASE_JD_SOFT_EVENT_SET) && -+ (update->new_status != BASE_JD_SOFT_EVENT_RESET)) || -+ (update->flags != 0)) -+ goto out_bad; -+ -+ if (kbase_soft_event_update(kctx, update->evt, -+ update->new_status)) -+ ukh->ret = MALI_ERROR_FUNCTION_FAILED; -+ -+ break; -+ } -+ -+ default: -+ dev_err(kbdev->dev, "unknown ioctl %u\n", id); -+ goto out_bad; -+ } -+ -+ return ret; -+ -+ bad_size: -+ dev_err(kbdev->dev, "Wrong syscall size (%d) for %08x\n", args_size, id); -+ out_bad: -+ return -EINVAL; -+} -+ -+static struct kbase_device *to_kbase_device(struct device *dev) -+{ -+ return dev_get_drvdata(dev); -+} -+ -+static int assign_irqs(struct platform_device *pdev) -+{ -+ struct kbase_device *kbdev = to_kbase_device(&pdev->dev); -+ int i; -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ /* 3 IRQ resources */ -+ for (i = 0; i < 3; i++) { -+ struct resource *irq_res; -+ int irqtag; -+ -+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, i); -+ if (!irq_res) { -+ dev_err(kbdev->dev, "No IRQ resource at index %d\n", i); -+ return -ENOENT; -+ } -+ -+#ifdef CONFIG_OF -+ if (!strncmp(irq_res->name, "JOB", 4)) { -+ irqtag = JOB_IRQ_TAG; -+ } else if (!strncmp(irq_res->name, "MMU", 4)) { -+ irqtag = MMU_IRQ_TAG; -+ } else if (!strncmp(irq_res->name, "GPU", 4)) { -+ irqtag = GPU_IRQ_TAG; -+ } else { -+ dev_err(&pdev->dev, "Invalid irq res name: '%s'\n", -+ irq_res->name); -+ return -EINVAL; -+ } -+#else -+ irqtag = i; -+#endif /* CONFIG_OF */ -+ kbdev->irqs[irqtag].irq = irq_res->start; -+ kbdev->irqs[irqtag].flags = irq_res->flags & IRQF_TRIGGER_MASK; -+ } -+ -+ return 0; -+} -+ -+/* -+ * API to acquire device list mutex and -+ * return pointer to the device list head -+ */ -+const struct list_head *kbase_dev_list_get(void) -+{ -+ mutex_lock(&kbase_dev_list_lock); -+ return &kbase_dev_list; -+} -+KBASE_EXPORT_TEST_API(kbase_dev_list_get); -+ -+/* API to release the device list mutex */ -+void kbase_dev_list_put(const struct list_head *dev_list) -+{ -+ mutex_unlock(&kbase_dev_list_lock); -+} -+KBASE_EXPORT_TEST_API(kbase_dev_list_put); -+ -+/* Find a particular kbase device (as specified by minor number), or find the "first" device if -1 is specified */ -+struct kbase_device *kbase_find_device(int minor) -+{ -+ struct kbase_device *kbdev = NULL; -+ struct list_head *entry; -+ const struct list_head *dev_list = kbase_dev_list_get(); -+ -+ list_for_each(entry, dev_list) { -+ struct kbase_device *tmp; -+ -+ tmp = list_entry(entry, struct kbase_device, entry); -+ if (tmp->mdev.minor == minor || minor == -1) { -+ kbdev = tmp; -+ get_device(kbdev->dev); -+ break; -+ } -+ } -+ kbase_dev_list_put(dev_list); -+ -+ return kbdev; -+} -+EXPORT_SYMBOL(kbase_find_device); -+ -+void kbase_release_device(struct kbase_device *kbdev) -+{ -+ put_device(kbdev->dev); -+} -+EXPORT_SYMBOL(kbase_release_device); -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) && \ -+ !(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 28) && \ -+ LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)) -+/* -+ * Older versions, before v4.6, of the kernel doesn't have -+ * kstrtobool_from_user(), except longterm 4.4.y which had it added in 4.4.28 -+ */ -+static int kstrtobool_from_user(const char __user *s, size_t count, bool *res) -+{ -+ char buf[32]; -+ -+ count = min(sizeof(buf), count); -+ -+ if (copy_from_user(buf, s, count)) -+ return -EFAULT; -+ buf[count] = '\0'; -+ -+ return strtobool(buf, res); -+} -+#endif -+ -+static ssize_t write_ctx_infinite_cache(struct file *f, const char __user *ubuf, size_t size, loff_t *off) -+{ -+ struct kbase_context *kctx = f->private_data; -+ int err; -+ bool value; -+ -+ err = kstrtobool_from_user(ubuf, size, &value); -+ if (err) -+ return err; -+ -+ if (value) -+ kbase_ctx_flag_set(kctx, KCTX_INFINITE_CACHE); -+ else -+ kbase_ctx_flag_clear(kctx, KCTX_INFINITE_CACHE); -+ -+ return size; -+} -+ -+static ssize_t read_ctx_infinite_cache(struct file *f, char __user *ubuf, size_t size, loff_t *off) -+{ -+ struct kbase_context *kctx = f->private_data; -+ char buf[32]; -+ int count; -+ bool value; -+ -+ value = kbase_ctx_flag(kctx, KCTX_INFINITE_CACHE); -+ -+ count = scnprintf(buf, sizeof(buf), "%s\n", value ? "Y" : "N"); -+ -+ return simple_read_from_buffer(ubuf, size, off, buf, count); -+} -+ -+static const struct file_operations kbase_infinite_cache_fops = { -+ .open = simple_open, -+ .write = write_ctx_infinite_cache, -+ .read = read_ctx_infinite_cache, -+}; -+ -+static int kbase_open(struct inode *inode, struct file *filp) -+{ -+ struct kbase_device *kbdev = NULL; -+ struct kbase_context *kctx; -+ int ret = 0; -+#ifdef CONFIG_DEBUG_FS -+ char kctx_name[64]; -+#endif -+ -+ kbdev = kbase_find_device(iminor(inode)); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ kctx = kbase_create_context(kbdev, is_compat_task()); -+ if (!kctx) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ init_waitqueue_head(&kctx->event_queue); -+ filp->private_data = kctx; -+ kctx->filp = filp; -+ -+ if (kbdev->infinite_cache_active_default) -+ kbase_ctx_flag_set(kctx, KCTX_INFINITE_CACHE); -+ -+#ifdef CONFIG_DEBUG_FS -+ snprintf(kctx_name, 64, "%d_%d", kctx->tgid, kctx->id); -+ -+ kctx->kctx_dentry = debugfs_create_dir(kctx_name, -+ kbdev->debugfs_ctx_directory); -+ -+ if (IS_ERR_OR_NULL(kctx->kctx_dentry)) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ debugfs_create_file("infinite_cache", 0644, kctx->kctx_dentry, -+ kctx, &kbase_infinite_cache_fops); -+ -+ mutex_init(&kctx->mem_profile_lock); -+ -+ kbasep_jd_debugfs_ctx_init(kctx); -+ kbase_debug_mem_view_init(filp); -+ -+ kbase_debug_job_fault_context_init(kctx); -+ -+ kbase_mem_pool_debugfs_init(kctx->kctx_dentry, &kctx->mem_pool); -+ -+ kbase_jit_debugfs_init(kctx); -+#endif /* CONFIG_DEBUG_FS */ -+ -+ dev_dbg(kbdev->dev, "created base context\n"); -+ -+ { -+ struct kbasep_kctx_list_element *element; -+ -+ element = kzalloc(sizeof(*element), GFP_KERNEL); -+ if (element) { -+ mutex_lock(&kbdev->kctx_list_lock); -+ element->kctx = kctx; -+ list_add(&element->link, &kbdev->kctx_list); -+ KBASE_TLSTREAM_TL_NEW_CTX( -+ element->kctx, -+ (u32)(element->kctx->id), -+ (u32)(element->kctx->tgid)); -+ mutex_unlock(&kbdev->kctx_list_lock); -+ } else { -+ /* we don't treat this as a fail - just warn about it */ -+ dev_warn(kbdev->dev, "couldn't add kctx to kctx_list\n"); -+ } -+ } -+ return 0; -+ -+ out: -+ kbase_release_device(kbdev); -+ return ret; -+} -+ -+static int kbase_release(struct inode *inode, struct file *filp) -+{ -+ struct kbase_context *kctx = filp->private_data; -+ struct kbase_device *kbdev = kctx->kbdev; -+ struct kbasep_kctx_list_element *element, *tmp; -+ bool found_element = false; -+ -+ KBASE_TLSTREAM_TL_DEL_CTX(kctx); -+ -+#ifdef CONFIG_DEBUG_FS -+ kbasep_mem_profile_debugfs_remove(kctx); -+ kbase_debug_job_fault_context_term(kctx); -+#endif -+ -+ mutex_lock(&kbdev->kctx_list_lock); -+ list_for_each_entry_safe(element, tmp, &kbdev->kctx_list, link) { -+ if (element->kctx == kctx) { -+ list_del(&element->link); -+ kfree(element); -+ found_element = true; -+ } -+ } -+ mutex_unlock(&kbdev->kctx_list_lock); -+ if (!found_element) -+ dev_warn(kbdev->dev, "kctx not in kctx_list\n"); -+ -+ filp->private_data = NULL; -+ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ /* If this client was performing hwcnt dumping and did not explicitly -+ * detach itself, remove it from the vinstr core now */ -+ if (kctx->vinstr_cli) { -+ struct kbase_uk_hwcnt_setup setup; -+ -+ setup.dump_buffer = 0llu; -+ kbase_vinstr_legacy_hwc_setup( -+ kbdev->vinstr_ctx, &kctx->vinstr_cli, &setup); -+ } -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ -+ kbase_destroy_context(kctx); -+ -+ dev_dbg(kbdev->dev, "deleted base context\n"); -+ kbase_release_device(kbdev); -+ return 0; -+} -+ -+#define CALL_MAX_SIZE 536 -+ -+static long kbase_legacy_ioctl(struct file *filp, unsigned int cmd, -+ unsigned long arg) -+{ -+ u64 msg[(CALL_MAX_SIZE + 7) >> 3] = { 0xdeadbeefdeadbeefull }; /* alignment fixup */ -+ u32 size = _IOC_SIZE(cmd); -+ struct kbase_context *kctx = filp->private_data; -+ -+ if (size > CALL_MAX_SIZE) -+ return -ENOTTY; -+ -+ if (0 != copy_from_user(&msg, (void __user *)arg, size)) { -+ dev_err(kctx->kbdev->dev, "failed to copy ioctl argument into kernel space\n"); -+ return -EFAULT; -+ } -+ -+ if (kbase_legacy_dispatch(kctx, &msg, size) != 0) -+ return -EFAULT; -+ -+ if (0 != copy_to_user((void __user *)arg, &msg, size)) { -+ dev_err(kctx->kbdev->dev, "failed to copy results of UK call back to user space\n"); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+static int kbase_api_set_flags(struct kbase_context *kctx, -+ struct kbase_ioctl_set_flags *flags) -+{ -+ int err; -+ -+ /* setup pending, try to signal that we'll do the setup, -+ * if setup was already in progress, err this call -+ */ -+ if (atomic_cmpxchg(&kctx->setup_in_progress, 0, 1) != 0) -+ return -EINVAL; -+ -+ err = kbase_context_set_create_flags(kctx, flags->create_flags); -+ /* if bad flags, will stay stuck in setup mode */ -+ if (err) -+ return err; -+ -+ atomic_set(&kctx->setup_complete, 1); -+ return 0; -+} -+ -+static int kbase_api_job_submit(struct kbase_context *kctx, -+ struct kbase_ioctl_job_submit *submit) -+{ -+ return kbase_jd_submit(kctx, u64_to_user_ptr(submit->addr), -+ submit->nr_atoms, -+ submit->stride, false); -+} -+ -+static int kbase_api_get_gpuprops(struct kbase_context *kctx, -+ struct kbase_ioctl_get_gpuprops *get_props) -+{ -+ struct kbase_gpu_props *kprops = &kctx->kbdev->gpu_props; -+ int err; -+ -+ if (get_props->flags != 0) { -+ dev_err(kctx->kbdev->dev, "Unsupported flags to get_gpuprops"); -+ return -EINVAL; -+ } -+ -+ if (get_props->size == 0) -+ return kprops->prop_buffer_size; -+ if (get_props->size < kprops->prop_buffer_size) -+ return -EINVAL; -+ -+ err = copy_to_user(u64_to_user_ptr(get_props->buffer), -+ kprops->prop_buffer, -+ kprops->prop_buffer_size); -+ if (err) -+ return -EFAULT; -+ return kprops->prop_buffer_size; -+} -+ -+static int kbase_api_post_term(struct kbase_context *kctx) -+{ -+ kbase_event_close(kctx); -+ return 0; -+} -+ -+static int kbase_api_mem_alloc(struct kbase_context *kctx, -+ union kbase_ioctl_mem_alloc *alloc) -+{ -+ struct kbase_va_region *reg; -+ u64 flags = alloc->in.flags; -+ u64 gpu_va; -+ -+#if defined(CONFIG_64BIT) -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+ /* force SAME_VA if a 64-bit client */ -+ flags |= BASE_MEM_SAME_VA; -+ } -+#endif -+ -+ reg = kbase_mem_alloc(kctx, alloc->in.va_pages, -+ alloc->in.commit_pages, -+ alloc->in.extent, -+ &flags, &gpu_va); -+ -+ if (!reg) -+ return -ENOMEM; -+ -+ alloc->out.flags = flags; -+ alloc->out.gpu_va = gpu_va; -+ -+ return 0; -+} -+ -+static int kbase_api_mem_query(struct kbase_context *kctx, -+ union kbase_ioctl_mem_query *query) -+{ -+ return kbase_mem_query(kctx, query->in.gpu_addr, -+ query->in.query, &query->out.value); -+} -+ -+static int kbase_api_mem_free(struct kbase_context *kctx, -+ struct kbase_ioctl_mem_free *free) -+{ -+ return kbase_mem_free(kctx, free->gpu_addr); -+} -+ -+static int kbase_api_hwcnt_reader_setup(struct kbase_context *kctx, -+ struct kbase_ioctl_hwcnt_reader_setup *setup) -+{ -+ int ret; -+ struct kbase_uk_hwcnt_reader_setup args = { -+ .buffer_count = setup->buffer_count, -+ .jm_bm = setup->jm_bm, -+ .shader_bm = setup->shader_bm, -+ .tiler_bm = setup->tiler_bm, -+ .mmu_l2_bm = setup->mmu_l2_bm -+ }; -+ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ ret = kbase_vinstr_hwcnt_reader_setup(kctx->kbdev->vinstr_ctx, &args); -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ -+ if (ret) -+ return ret; -+ return args.fd; -+} -+ -+static int kbase_api_hwcnt_enable(struct kbase_context *kctx, -+ struct kbase_ioctl_hwcnt_enable *enable) -+{ -+ int ret; -+ struct kbase_uk_hwcnt_setup args = { -+ .dump_buffer = enable->dump_buffer, -+ .jm_bm = enable->jm_bm, -+ .shader_bm = enable->shader_bm, -+ .tiler_bm = enable->tiler_bm, -+ .mmu_l2_bm = enable->mmu_l2_bm -+ }; -+ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ ret = kbase_vinstr_legacy_hwc_setup(kctx->kbdev->vinstr_ctx, -+ &kctx->vinstr_cli, &args); -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ -+ return ret; -+} -+ -+static int kbase_api_hwcnt_dump(struct kbase_context *kctx) -+{ -+ int ret; -+ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ ret = kbase_vinstr_hwc_dump(kctx->vinstr_cli, -+ BASE_HWCNT_READER_EVENT_MANUAL); -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ -+ return ret; -+} -+ -+static int kbase_api_hwcnt_clear(struct kbase_context *kctx) -+{ -+ int ret; -+ -+ mutex_lock(&kctx->vinstr_cli_lock); -+ ret = kbase_vinstr_hwc_clear(kctx->vinstr_cli); -+ mutex_unlock(&kctx->vinstr_cli_lock); -+ -+ return ret; -+} -+ -+static int kbase_api_disjoint_query(struct kbase_context *kctx, -+ struct kbase_ioctl_disjoint_query *query) -+{ -+ query->counter = kbase_disjoint_event_get(kctx->kbdev); -+ -+ return 0; -+} -+ -+static int kbase_api_get_ddk_version(struct kbase_context *kctx, -+ struct kbase_ioctl_get_ddk_version *version) -+{ -+ int ret; -+ int len = sizeof(KERNEL_SIDE_DDK_VERSION_STRING); -+ -+ if (version->version_buffer == 0) -+ return len; -+ -+ if (version->size < len) -+ return -EOVERFLOW; -+ -+ ret = copy_to_user(u64_to_user_ptr(version->version_buffer), -+ KERNEL_SIDE_DDK_VERSION_STRING, -+ sizeof(KERNEL_SIDE_DDK_VERSION_STRING)); -+ -+ if (ret) -+ return -EFAULT; -+ -+ return len; -+} -+ -+static int kbase_api_mem_jit_init(struct kbase_context *kctx, -+ struct kbase_ioctl_mem_jit_init *jit_init) -+{ -+ return kbase_region_tracker_init_jit(kctx, jit_init->va_pages); -+} -+ -+static int kbase_api_mem_sync(struct kbase_context *kctx, -+ struct kbase_ioctl_mem_sync *sync) -+{ -+ struct basep_syncset sset = { -+ .mem_handle.basep.handle = sync->handle, -+ .user_addr = sync->user_addr, -+ .size = sync->size, -+ .type = sync->type -+ }; -+ -+ return kbase_sync_now(kctx, &sset); -+} -+ -+static int kbase_api_mem_find_cpu_offset(struct kbase_context *kctx, -+ union kbase_ioctl_mem_find_cpu_offset *find) -+{ -+ return kbasep_find_enclosing_cpu_mapping_offset( -+ kctx, -+ find->in.cpu_addr, -+ find->in.size, -+ &find->out.offset); -+} -+ -+static int kbase_api_get_context_id(struct kbase_context *kctx, -+ struct kbase_ioctl_get_context_id *info) -+{ -+ info->id = kctx->id; -+ -+ return 0; -+} -+ -+static int kbase_api_tlstream_acquire(struct kbase_context *kctx, -+ struct kbase_ioctl_tlstream_acquire *acquire) -+{ -+ return kbase_tlstream_acquire(kctx, acquire->flags); -+} -+ -+static int kbase_api_tlstream_flush(struct kbase_context *kctx) -+{ -+ kbase_tlstream_flush_streams(); -+ -+ return 0; -+} -+ -+static int kbase_api_mem_commit(struct kbase_context *kctx, -+ struct kbase_ioctl_mem_commit *commit) -+{ -+ return kbase_mem_commit(kctx, commit->gpu_addr, commit->pages); -+} -+ -+static int kbase_api_mem_alias(struct kbase_context *kctx, -+ union kbase_ioctl_mem_alias *alias) -+{ -+ struct base_mem_aliasing_info *ai; -+ u64 flags; -+ int err; -+ -+ if (alias->in.nents == 0 || alias->in.nents > 2048) -+ return -EINVAL; -+ -+ ai = vmalloc(sizeof(*ai) * alias->in.nents); -+ if (!ai) -+ return -ENOMEM; -+ -+ err = copy_from_user(ai, -+ u64_to_user_ptr(alias->in.aliasing_info), -+ sizeof(*ai) * alias->in.nents); -+ if (err) { -+ vfree(ai); -+ return -EFAULT; -+ } -+ -+ flags = alias->in.flags; -+ -+ alias->out.gpu_va = kbase_mem_alias(kctx, &flags, -+ alias->in.stride, alias->in.nents, -+ ai, &alias->out.va_pages); -+ -+ alias->out.flags = flags; -+ -+ vfree(ai); -+ -+ if (alias->out.gpu_va == 0) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+static int kbase_api_mem_import(struct kbase_context *kctx, -+ union kbase_ioctl_mem_import *import) -+{ -+ int ret; -+ u64 flags = import->in.flags; -+ -+ ret = kbase_mem_import(kctx, -+ import->in.type, -+ u64_to_user_ptr(import->in.phandle), -+ import->in.padding, -+ &import->out.gpu_va, -+ &import->out.va_pages, -+ &flags); -+ -+ import->out.flags = flags; -+ -+ return ret; -+} -+ -+static int kbase_api_mem_flags_change(struct kbase_context *kctx, -+ struct kbase_ioctl_mem_flags_change *change) -+{ -+ return kbase_mem_flags_change(kctx, change->gpu_va, -+ change->flags, change->mask); -+} -+ -+static int kbase_api_stream_create(struct kbase_context *kctx, -+ struct kbase_ioctl_stream_create *stream) -+{ -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ int fd, ret; -+ -+ /* Name must be NULL-terminated and padded with NULLs, so check last -+ * character is NULL -+ */ -+ if (stream->name[sizeof(stream->name)-1] != 0) -+ return -EINVAL; -+ -+ ret = kbase_sync_fence_stream_create(stream->name, &fd); -+ -+ if (ret) -+ return ret; -+ return fd; -+#else -+ return -ENOENT; -+#endif -+} -+ -+static int kbase_api_fence_validate(struct kbase_context *kctx, -+ struct kbase_ioctl_fence_validate *validate) -+{ -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ return kbase_sync_fence_validate(validate->fd); -+#else -+ return -ENOENT; -+#endif -+} -+ -+static int kbase_api_get_profiling_controls(struct kbase_context *kctx, -+ struct kbase_ioctl_get_profiling_controls *controls) -+{ -+ int ret; -+ -+ if (controls->count > (FBDUMP_CONTROL_MAX - FBDUMP_CONTROL_MIN)) -+ return -EINVAL; -+ -+ ret = copy_to_user(u64_to_user_ptr(controls->buffer), -+ &kctx->kbdev->kbase_profiling_controls[ -+ FBDUMP_CONTROL_MIN], -+ controls->count * sizeof(u32)); -+ -+ if (ret) -+ return -EFAULT; -+ return 0; -+} -+ -+static int kbase_api_mem_profile_add(struct kbase_context *kctx, -+ struct kbase_ioctl_mem_profile_add *data) -+{ -+ char *buf; -+ int err; -+ -+ if (data->len > KBASE_MEM_PROFILE_MAX_BUF_SIZE) { -+ dev_err(kctx->kbdev->dev, "mem_profile_add: buffer too big\n"); -+ return -EINVAL; -+ } -+ -+ buf = kmalloc(data->len, GFP_KERNEL); -+ if (ZERO_OR_NULL_PTR(buf)) -+ return -ENOMEM; -+ -+ err = copy_from_user(buf, u64_to_user_ptr(data->buffer), -+ data->len); -+ if (err) { -+ kfree(buf); -+ return -EFAULT; -+ } -+ -+ return kbasep_mem_profile_debugfs_insert(kctx, buf, data->len); -+} -+ -+static int kbase_api_soft_event_update(struct kbase_context *kctx, -+ struct kbase_ioctl_soft_event_update *update) -+{ -+ if (update->flags != 0) -+ return -EINVAL; -+ -+ return kbase_soft_event_update(kctx, update->event, update->new_status); -+} -+ -+#if MALI_UNIT_TEST -+static int kbase_api_tlstream_test(struct kbase_context *kctx, -+ struct kbase_ioctl_tlstream_test *test) -+{ -+ kbase_tlstream_test( -+ test->tpw_count, -+ test->msg_delay, -+ test->msg_count, -+ test->aux_msg); -+ -+ return 0; -+} -+ -+static int kbase_api_tlstream_stats(struct kbase_context *kctx, -+ struct kbase_ioctl_tlstream_stats *stats) -+{ -+ kbase_tlstream_stats( -+ &stats->bytes_collected, -+ &stats->bytes_generated); -+ -+ return 0; -+} -+#endif /* MALI_UNIT_TEST */ -+ -+#define KBASE_HANDLE_IOCTL(cmd, function) \ -+ case cmd: \ -+ do { \ -+ BUILD_BUG_ON(_IOC_DIR(cmd) != _IOC_NONE); \ -+ return function(kctx); \ -+ } while (0) -+ -+#define KBASE_HANDLE_IOCTL_IN(cmd, function, type) \ -+ case cmd: \ -+ do { \ -+ type param; \ -+ int err; \ -+ BUILD_BUG_ON(_IOC_DIR(cmd) != _IOC_WRITE); \ -+ BUILD_BUG_ON(sizeof(param) != _IOC_SIZE(cmd)); \ -+ err = copy_from_user(¶m, uarg, sizeof(param)); \ -+ if (err) \ -+ return -EFAULT; \ -+ return function(kctx, ¶m); \ -+ } while (0) -+ -+#define KBASE_HANDLE_IOCTL_OUT(cmd, function, type) \ -+ case cmd: \ -+ do { \ -+ type param; \ -+ int ret, err; \ -+ BUILD_BUG_ON(_IOC_DIR(cmd) != _IOC_READ); \ -+ BUILD_BUG_ON(sizeof(param) != _IOC_SIZE(cmd)); \ -+ ret = function(kctx, ¶m); \ -+ err = copy_to_user(uarg, ¶m, sizeof(param)); \ -+ if (err) \ -+ return -EFAULT; \ -+ return ret; \ -+ } while (0) -+ -+#define KBASE_HANDLE_IOCTL_INOUT(cmd, function, type) \ -+ case cmd: \ -+ do { \ -+ type param; \ -+ int ret, err; \ -+ BUILD_BUG_ON(_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ)); \ -+ BUILD_BUG_ON(sizeof(param) != _IOC_SIZE(cmd)); \ -+ err = copy_from_user(¶m, uarg, sizeof(param)); \ -+ if (err) \ -+ return -EFAULT; \ -+ ret = function(kctx, ¶m); \ -+ err = copy_to_user(uarg, ¶m, sizeof(param)); \ -+ if (err) \ -+ return -EFAULT; \ -+ return ret; \ -+ } while (0) -+ -+static long kbase_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ struct kbase_context *kctx = filp->private_data; -+ struct kbase_device *kbdev = kctx->kbdev; -+ void __user *uarg = (void __user *)arg; -+ -+ /* The UK ioctl values overflow the cmd field causing the type to be -+ * incremented -+ */ -+ if (_IOC_TYPE(cmd) == LINUX_UK_BASE_MAGIC+2) -+ return kbase_legacy_ioctl(filp, cmd, arg); -+ -+ /* The UK version check IOCTL doesn't overflow the cmd field, so is -+ * handled separately here -+ */ -+ if (cmd == _IOC(_IOC_READ|_IOC_WRITE, LINUX_UK_BASE_MAGIC, -+ UKP_FUNC_ID_CHECK_VERSION, -+ sizeof(struct uku_version_check_args))) -+ return kbase_legacy_ioctl(filp, cmd, arg); -+ -+ /* Only these ioctls are available until setup is complete */ -+ switch (cmd) { -+ KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_VERSION_CHECK, -+ kbase_api_handshake, -+ struct kbase_ioctl_version_check); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_SET_FLAGS, -+ kbase_api_set_flags, -+ struct kbase_ioctl_set_flags); -+ } -+ -+ /* Block call until version handshake and setup is complete */ -+ if (kctx->api_version == 0 || !atomic_read(&kctx->setup_complete)) -+ return -EINVAL; -+ -+ /* Normal ioctls */ -+ switch (cmd) { -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_JOB_SUBMIT, -+ kbase_api_job_submit, -+ struct kbase_ioctl_job_submit); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_GET_GPUPROPS, -+ kbase_api_get_gpuprops, -+ struct kbase_ioctl_get_gpuprops); -+ KBASE_HANDLE_IOCTL(KBASE_IOCTL_POST_TERM, -+ kbase_api_post_term); -+ KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_MEM_ALLOC, -+ kbase_api_mem_alloc, -+ union kbase_ioctl_mem_alloc); -+ KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_MEM_QUERY, -+ kbase_api_mem_query, -+ union kbase_ioctl_mem_query); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_FREE, -+ kbase_api_mem_free, -+ struct kbase_ioctl_mem_free); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_HWCNT_READER_SETUP, -+ kbase_api_hwcnt_reader_setup, -+ struct kbase_ioctl_hwcnt_reader_setup); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_HWCNT_ENABLE, -+ kbase_api_hwcnt_enable, -+ struct kbase_ioctl_hwcnt_enable); -+ KBASE_HANDLE_IOCTL(KBASE_IOCTL_HWCNT_DUMP, -+ kbase_api_hwcnt_dump); -+ KBASE_HANDLE_IOCTL(KBASE_IOCTL_HWCNT_CLEAR, -+ kbase_api_hwcnt_clear); -+ KBASE_HANDLE_IOCTL_OUT(KBASE_IOCTL_DISJOINT_QUERY, -+ kbase_api_disjoint_query, -+ struct kbase_ioctl_disjoint_query); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_GET_DDK_VERSION, -+ kbase_api_get_ddk_version, -+ struct kbase_ioctl_get_ddk_version); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_JIT_INIT, -+ kbase_api_mem_jit_init, -+ struct kbase_ioctl_mem_jit_init); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_SYNC, -+ kbase_api_mem_sync, -+ struct kbase_ioctl_mem_sync); -+ KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_MEM_FIND_CPU_OFFSET, -+ kbase_api_mem_find_cpu_offset, -+ union kbase_ioctl_mem_find_cpu_offset); -+ KBASE_HANDLE_IOCTL_OUT(KBASE_IOCTL_GET_CONTEXT_ID, -+ kbase_api_get_context_id, -+ struct kbase_ioctl_get_context_id); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_TLSTREAM_ACQUIRE, -+ kbase_api_tlstream_acquire, -+ struct kbase_ioctl_tlstream_acquire); -+ KBASE_HANDLE_IOCTL(KBASE_IOCTL_TLSTREAM_FLUSH, -+ kbase_api_tlstream_flush); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_COMMIT, -+ kbase_api_mem_commit, -+ struct kbase_ioctl_mem_commit); -+ KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_MEM_ALIAS, -+ kbase_api_mem_alias, -+ union kbase_ioctl_mem_alias); -+ KBASE_HANDLE_IOCTL_INOUT(KBASE_IOCTL_MEM_IMPORT, -+ kbase_api_mem_import, -+ union kbase_ioctl_mem_import); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_FLAGS_CHANGE, -+ kbase_api_mem_flags_change, -+ struct kbase_ioctl_mem_flags_change); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_STREAM_CREATE, -+ kbase_api_stream_create, -+ struct kbase_ioctl_stream_create); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_FENCE_VALIDATE, -+ kbase_api_fence_validate, -+ struct kbase_ioctl_fence_validate); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_GET_PROFILING_CONTROLS, -+ kbase_api_get_profiling_controls, -+ struct kbase_ioctl_get_profiling_controls); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_MEM_PROFILE_ADD, -+ kbase_api_mem_profile_add, -+ struct kbase_ioctl_mem_profile_add); -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_SOFT_EVENT_UPDATE, -+ kbase_api_soft_event_update, -+ struct kbase_ioctl_soft_event_update); -+ -+#if MALI_UNIT_TEST -+ KBASE_HANDLE_IOCTL_IN(KBASE_IOCTL_TLSTREAM_TEST, -+ kbase_api_tlstream_test, -+ struct kbase_ioctl_tlstream_test); -+ KBASE_HANDLE_IOCTL_OUT(KBASE_IOCTL_TLSTREAM_STATS, -+ kbase_api_tlstream_stats, -+ struct kbase_ioctl_tlstream_stats); -+#endif -+ } -+ -+ dev_warn(kbdev->dev, "Unknown ioctl 0x%x nr:%d", cmd, _IOC_NR(cmd)); -+ -+ return -ENOIOCTLCMD; -+} -+ -+static ssize_t kbase_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) -+{ -+ struct kbase_context *kctx = filp->private_data; -+ struct base_jd_event_v2 uevent; -+ int out_count = 0; -+ -+ if (count < sizeof(uevent)) -+ return -ENOBUFS; -+ -+ do { -+ while (kbase_event_dequeue(kctx, &uevent)) { -+ if (out_count > 0) -+ goto out; -+ -+ if (filp->f_flags & O_NONBLOCK) -+ return -EAGAIN; -+ -+ if (wait_event_interruptible(kctx->event_queue, -+ kbase_event_pending(kctx)) != 0) -+ return -ERESTARTSYS; -+ } -+ if (uevent.event_code == BASE_JD_EVENT_DRV_TERMINATED) { -+ if (out_count == 0) -+ return -EPIPE; -+ goto out; -+ } -+ -+ if (copy_to_user(buf, &uevent, sizeof(uevent)) != 0) -+ return -EFAULT; -+ -+ buf += sizeof(uevent); -+ out_count++; -+ count -= sizeof(uevent); -+ } while (count >= sizeof(uevent)); -+ -+ out: -+ return out_count * sizeof(uevent); -+} -+ -+static unsigned int kbase_poll(struct file *filp, poll_table *wait) -+{ -+ struct kbase_context *kctx = filp->private_data; -+ -+ poll_wait(filp, &kctx->event_queue, wait); -+ if (kbase_event_pending(kctx)) -+ return POLLIN | POLLRDNORM; -+ -+ return 0; -+} -+ -+void kbase_event_wakeup(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+ wake_up_interruptible(&kctx->event_queue); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_event_wakeup); -+ -+static int kbase_check_flags(int flags) -+{ -+ /* Enforce that the driver keeps the O_CLOEXEC flag so that execve() always -+ * closes the file descriptor in a child process. -+ */ -+ if (0 == (flags & O_CLOEXEC)) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+ -+/** -+ * align_and_check - Align the specified pointer to the provided alignment and -+ * check that it is still in range. -+ * @gap_end: Highest possible start address for allocation (end of gap in -+ * address space) -+ * @gap_start: Start address of current memory area / gap in address space -+ * @info: vm_unmapped_area_info structure passed to caller, containing -+ * alignment, length and limits for the allocation -+ * @is_shader_code: True if the allocation is for shader code (which has -+ * additional alignment requirements) -+ * -+ * Return: true if gap_end is now aligned correctly and is still in range, -+ * false otherwise -+ */ -+static bool align_and_check(unsigned long *gap_end, unsigned long gap_start, -+ struct vm_unmapped_area_info *info, bool is_shader_code) -+{ -+ /* Compute highest gap address at the desired alignment */ -+ (*gap_end) -= info->length; -+ (*gap_end) -= (*gap_end - info->align_offset) & info->align_mask; -+ -+ if (is_shader_code) { -+ /* Check for 4GB boundary */ -+ if (0 == (*gap_end & BASE_MEM_MASK_4GB)) -+ (*gap_end) -= (info->align_offset ? info->align_offset : -+ info->length); -+ if (0 == ((*gap_end + info->length) & BASE_MEM_MASK_4GB)) -+ (*gap_end) -= (info->align_offset ? info->align_offset : -+ info->length); -+ -+ if (!(*gap_end & BASE_MEM_MASK_4GB) || !((*gap_end + -+ info->length) & BASE_MEM_MASK_4GB)) -+ return false; -+ } -+ -+ -+ if ((*gap_end < info->low_limit) || (*gap_end < gap_start)) -+ return false; -+ -+ -+ return true; -+} -+ -+/* The following function is taken from the kernel and just -+ * renamed. As it's not exported to modules we must copy-paste it here. -+ */ -+ -+static unsigned long kbase_unmapped_area_topdown(struct vm_unmapped_area_info -+ *info, bool is_shader_code) -+{ -+ struct mm_struct *mm = current->mm; -+ struct vm_area_struct *vma; -+ unsigned long length, low_limit, high_limit, gap_start, gap_end; -+ -+ /* Adjust search length to account for worst case alignment overhead */ -+ length = info->length + info->align_mask; -+ if (length < info->length) -+ return -ENOMEM; -+ -+ /* -+ * Adjust search limits by the desired length. -+ * See implementation comment at top of unmapped_area(). -+ */ -+ gap_end = info->high_limit; -+ if (gap_end < length) -+ return -ENOMEM; -+ high_limit = gap_end - length; -+ -+ if (info->low_limit > high_limit) -+ return -ENOMEM; -+ low_limit = info->low_limit + length; -+ -+ /* Check highest gap, which does not precede any rbtree node */ -+ gap_start = mm->highest_vm_end; -+ if (gap_start <= high_limit) { -+ if (align_and_check(&gap_end, gap_start, info, is_shader_code)) -+ return gap_end; -+ } -+ -+ /* Check if rbtree root looks promising */ -+ if (RB_EMPTY_ROOT(&mm->mm_rb)) -+ return -ENOMEM; -+ vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb); -+ if (vma->rb_subtree_gap < length) -+ return -ENOMEM; -+ -+ while (true) { -+ /* Visit right subtree if it looks promising */ -+ gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; -+ if (gap_start <= high_limit && vma->vm_rb.rb_right) { -+ struct vm_area_struct *right = -+ rb_entry(vma->vm_rb.rb_right, -+ struct vm_area_struct, vm_rb); -+ if (right->rb_subtree_gap >= length) { -+ vma = right; -+ continue; -+ } -+ } -+ -+check_current: -+ /* Check if current node has a suitable gap */ -+ gap_end = vma->vm_start; -+ if (gap_end < low_limit) -+ return -ENOMEM; -+ if (gap_start <= high_limit && gap_end - gap_start >= length) { -+ /* We found a suitable gap. Clip it with the original -+ * high_limit. */ -+ if (gap_end > info->high_limit) -+ gap_end = info->high_limit; -+ -+ if (align_and_check(&gap_end, gap_start, info, -+ is_shader_code)) -+ return gap_end; -+ } -+ -+ /* Visit left subtree if it looks promising */ -+ if (vma->vm_rb.rb_left) { -+ struct vm_area_struct *left = -+ rb_entry(vma->vm_rb.rb_left, -+ struct vm_area_struct, vm_rb); -+ if (left->rb_subtree_gap >= length) { -+ vma = left; -+ continue; -+ } -+ } -+ -+ /* Go back up the rbtree to find next candidate node */ -+ while (true) { -+ struct rb_node *prev = &vma->vm_rb; -+ if (!rb_parent(prev)) -+ return -ENOMEM; -+ vma = rb_entry(rb_parent(prev), -+ struct vm_area_struct, vm_rb); -+ if (prev == vma->vm_rb.rb_right) { -+ gap_start = vma->vm_prev ? -+ vma->vm_prev->vm_end : 0; -+ goto check_current; -+ } -+ } -+ } -+ -+ return -ENOMEM; -+} -+ -+static unsigned long kbase_get_unmapped_area(struct file *filp, -+ const unsigned long addr, const unsigned long len, -+ const unsigned long pgoff, const unsigned long flags) -+{ -+ /* based on get_unmapped_area, but simplified slightly due to that some -+ * values are known in advance */ -+ struct kbase_context *kctx = filp->private_data; -+ struct mm_struct *mm = current->mm; -+ struct vm_unmapped_area_info info; -+ unsigned long align_offset = 0; -+ unsigned long align_mask = 0; -+ unsigned long high_limit = mm->mmap_base; -+ unsigned long low_limit = PAGE_SIZE; -+ int cpu_va_bits = BITS_PER_LONG; -+ int gpu_pc_bits = -+ kctx->kbdev->gpu_props.props.core_props.log2_program_counter_size; -+ bool is_shader_code = false; -+ unsigned long ret; -+ -+ /* err on fixed address */ -+ if ((flags & MAP_FIXED) || addr) -+ return -EINVAL; -+ -+#ifdef CONFIG_64BIT -+ /* too big? */ -+ if (len > TASK_SIZE - SZ_2M) -+ return -ENOMEM; -+ -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+ -+ if (kbase_hw_has_feature(kctx->kbdev, -+ BASE_HW_FEATURE_33BIT_VA)) { -+ high_limit = kctx->same_va_end << PAGE_SHIFT; -+ } else { -+ high_limit = min_t(unsigned long, mm->mmap_base, -+ (kctx->same_va_end << PAGE_SHIFT)); -+ if (len >= SZ_2M) { -+ align_offset = SZ_2M; -+ align_mask = SZ_2M - 1; -+ } -+ } -+ -+ low_limit = SZ_2M; -+ } else { -+ cpu_va_bits = 32; -+ } -+#endif /* CONFIG_64BIT */ -+ if ((PFN_DOWN(BASE_MEM_COOKIE_BASE) <= pgoff) && -+ (PFN_DOWN(BASE_MEM_FIRST_FREE_ADDRESS) > pgoff)) { -+ int cookie = pgoff - PFN_DOWN(BASE_MEM_COOKIE_BASE); -+ -+ if (!kctx->pending_regions[cookie]) -+ return -EINVAL; -+ -+ if (!(kctx->pending_regions[cookie]->flags & -+ KBASE_REG_GPU_NX)) { -+ if (cpu_va_bits > gpu_pc_bits) { -+ align_offset = 1ULL << gpu_pc_bits; -+ align_mask = align_offset - 1; -+ is_shader_code = true; -+ } -+ } -+#ifndef CONFIG_64BIT -+ } else { -+ return current->mm->get_unmapped_area(filp, addr, len, pgoff, -+ flags); -+#endif -+ } -+ -+ info.flags = 0; -+ info.length = len; -+ info.low_limit = low_limit; -+ info.high_limit = high_limit; -+ info.align_offset = align_offset; -+ info.align_mask = align_mask; -+ -+ ret = kbase_unmapped_area_topdown(&info, is_shader_code); -+ -+ if (IS_ERR_VALUE(ret) && high_limit == mm->mmap_base && -+ high_limit < (kctx->same_va_end << PAGE_SHIFT)) { -+ /* Retry above mmap_base */ -+ info.low_limit = mm->mmap_base; -+ info.high_limit = min_t(u64, TASK_SIZE, -+ (kctx->same_va_end << PAGE_SHIFT)); -+ -+ ret = kbase_unmapped_area_topdown(&info, is_shader_code); -+ } -+ -+ return ret; -+} -+ -+static const struct file_operations kbase_fops = { -+ .owner = THIS_MODULE, -+ .open = kbase_open, -+ .release = kbase_release, -+ .read = kbase_read, -+ .poll = kbase_poll, -+ .unlocked_ioctl = kbase_ioctl, -+ .compat_ioctl = kbase_ioctl, -+ .mmap = kbase_mmap, -+ .check_flags = kbase_check_flags, -+ .get_unmapped_area = kbase_get_unmapped_area, -+}; -+ -+#ifndef CONFIG_MALI_NO_MALI -+void kbase_os_reg_write(struct kbase_device *kbdev, u16 offset, u32 value) -+{ -+ writel(value, kbdev->reg + offset); -+} -+ -+u32 kbase_os_reg_read(struct kbase_device *kbdev, u16 offset) -+{ -+ return readl(kbdev->reg + offset); -+} -+#endif /* !CONFIG_MALI_NO_MALI */ -+ -+/** -+ * show_policy - Show callback for the power_policy sysfs file. -+ * -+ * This function is called to get the contents of the power_policy sysfs -+ * file. This is a list of the available policies with the currently active one -+ * surrounded by square brackets. -+ * -+ * @dev: The device this sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The output buffer for the sysfs file contents -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_policy(struct device *dev, struct device_attribute *attr, char *const buf) -+{ -+ struct kbase_device *kbdev; -+ const struct kbase_pm_policy *current_policy; -+ const struct kbase_pm_policy *const *policy_list; -+ int policy_count; -+ int i; -+ ssize_t ret = 0; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ current_policy = kbase_pm_get_policy(kbdev); -+ -+ policy_count = kbase_pm_list_policies(&policy_list); -+ -+ for (i = 0; i < policy_count && ret < PAGE_SIZE; i++) { -+ if (policy_list[i] == current_policy) -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "[%s] ", policy_list[i]->name); -+ else -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s ", policy_list[i]->name); -+ } -+ -+ if (ret < PAGE_SIZE - 1) { -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); -+ } else { -+ buf[PAGE_SIZE - 2] = '\n'; -+ buf[PAGE_SIZE - 1] = '\0'; -+ ret = PAGE_SIZE - 1; -+ } -+ -+ return ret; -+} -+ -+/** -+ * set_policy - Store callback for the power_policy sysfs file. -+ * -+ * This function is called when the power_policy sysfs file is written to. -+ * It matches the requested policy against the available policies and if a -+ * matching policy is found calls kbase_pm_set_policy() to change the -+ * policy. -+ * -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_policy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ const struct kbase_pm_policy *new_policy = NULL; -+ const struct kbase_pm_policy *const *policy_list; -+ int policy_count; -+ int i; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ policy_count = kbase_pm_list_policies(&policy_list); -+ -+ for (i = 0; i < policy_count; i++) { -+ if (sysfs_streq(policy_list[i]->name, buf)) { -+ new_policy = policy_list[i]; -+ break; -+ } -+ } -+ -+ if (!new_policy) { -+ dev_err(dev, "power_policy: policy not found\n"); -+ return -EINVAL; -+ } -+ -+ kbase_pm_set_policy(kbdev, new_policy); -+ -+ return count; -+} -+ -+/* -+ * The sysfs file power_policy. -+ * -+ * This is used for obtaining information about the available policies, -+ * determining which policy is currently active, and changing the active -+ * policy. -+ */ -+static DEVICE_ATTR(power_policy, S_IRUGO | S_IWUSR, show_policy, set_policy); -+ -+/** -+ * show_ca_policy - Show callback for the core_availability_policy sysfs file. -+ * -+ * This function is called to get the contents of the core_availability_policy -+ * sysfs file. This is a list of the available policies with the currently -+ * active one surrounded by square brackets. -+ * -+ * @dev: The device this sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The output buffer for the sysfs file contents -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_ca_policy(struct device *dev, struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ const struct kbase_pm_ca_policy *current_policy; -+ const struct kbase_pm_ca_policy *const *policy_list; -+ int policy_count; -+ int i; -+ ssize_t ret = 0; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ current_policy = kbase_pm_ca_get_policy(kbdev); -+ -+ policy_count = kbase_pm_ca_list_policies(&policy_list); -+ -+ for (i = 0; i < policy_count && ret < PAGE_SIZE; i++) { -+ if (policy_list[i] == current_policy) -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "[%s] ", policy_list[i]->name); -+ else -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s ", policy_list[i]->name); -+ } -+ -+ if (ret < PAGE_SIZE - 1) { -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); -+ } else { -+ buf[PAGE_SIZE - 2] = '\n'; -+ buf[PAGE_SIZE - 1] = '\0'; -+ ret = PAGE_SIZE - 1; -+ } -+ -+ return ret; -+} -+ -+/** -+ * set_ca_policy - Store callback for the core_availability_policy sysfs file. -+ * -+ * This function is called when the core_availability_policy sysfs file is -+ * written to. It matches the requested policy against the available policies -+ * and if a matching policy is found calls kbase_pm_set_policy() to change -+ * the policy. -+ * -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_ca_policy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ const struct kbase_pm_ca_policy *new_policy = NULL; -+ const struct kbase_pm_ca_policy *const *policy_list; -+ int policy_count; -+ int i; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ policy_count = kbase_pm_ca_list_policies(&policy_list); -+ -+ for (i = 0; i < policy_count; i++) { -+ if (sysfs_streq(policy_list[i]->name, buf)) { -+ new_policy = policy_list[i]; -+ break; -+ } -+ } -+ -+ if (!new_policy) { -+ dev_err(dev, "core_availability_policy: policy not found\n"); -+ return -EINVAL; -+ } -+ -+ kbase_pm_ca_set_policy(kbdev, new_policy); -+ -+ return count; -+} -+ -+/* -+ * The sysfs file core_availability_policy -+ * -+ * This is used for obtaining information about the available policies, -+ * determining which policy is currently active, and changing the active -+ * policy. -+ */ -+static DEVICE_ATTR(core_availability_policy, S_IRUGO | S_IWUSR, show_ca_policy, set_ca_policy); -+ -+/* -+ * show_core_mask - Show callback for the core_mask sysfs file. -+ * -+ * This function is called to get the contents of the core_mask sysfs file. -+ * -+ * @dev: The device this sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The output buffer for the sysfs file contents -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_core_mask(struct device *dev, struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret = 0; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, -+ "Current core mask (JS0) : 0x%llX\n", -+ kbdev->pm.debug_core_mask[0]); -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, -+ "Current core mask (JS1) : 0x%llX\n", -+ kbdev->pm.debug_core_mask[1]); -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, -+ "Current core mask (JS2) : 0x%llX\n", -+ kbdev->pm.debug_core_mask[2]); -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, -+ "Available core mask : 0x%llX\n", -+ kbdev->gpu_props.props.raw_props.shader_present); -+ -+ return ret; -+} -+ -+/** -+ * set_core_mask - Store callback for the core_mask sysfs file. -+ * -+ * This function is called when the core_mask sysfs file is written to. -+ * -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_core_mask(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ u64 new_core_mask[3]; -+ int items; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ items = sscanf(buf, "%llx %llx %llx", -+ &new_core_mask[0], &new_core_mask[1], -+ &new_core_mask[2]); -+ -+ if (items == 1) -+ new_core_mask[1] = new_core_mask[2] = new_core_mask[0]; -+ -+ if (items == 1 || items == 3) { -+ u64 shader_present = -+ kbdev->gpu_props.props.raw_props.shader_present; -+ u64 group0_core_mask = -+ kbdev->gpu_props.props.coherency_info.group[0]. -+ core_mask; -+ -+ if ((new_core_mask[0] & shader_present) != new_core_mask[0] || -+ !(new_core_mask[0] & group0_core_mask) || -+ (new_core_mask[1] & shader_present) != -+ new_core_mask[1] || -+ !(new_core_mask[1] & group0_core_mask) || -+ (new_core_mask[2] & shader_present) != -+ new_core_mask[2] || -+ !(new_core_mask[2] & group0_core_mask)) { -+ dev_err(dev, "power_policy: invalid core specification\n"); -+ return -EINVAL; -+ } -+ -+ if (kbdev->pm.debug_core_mask[0] != new_core_mask[0] || -+ kbdev->pm.debug_core_mask[1] != -+ new_core_mask[1] || -+ kbdev->pm.debug_core_mask[2] != -+ new_core_mask[2]) { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ kbase_pm_set_debug_core_mask(kbdev, new_core_mask[0], -+ new_core_mask[1], new_core_mask[2]); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ } -+ -+ return count; -+ } -+ -+ dev_err(kbdev->dev, "Couldn't process set_core_mask write operation.\n" -+ "Use format \n" -+ "or \n"); -+ return -EINVAL; -+} -+ -+/* -+ * The sysfs file core_mask. -+ * -+ * This is used to restrict shader core availability for debugging purposes. -+ * Reading it will show the current core mask and the mask of cores available. -+ * Writing to it will set the current core mask. -+ */ -+static DEVICE_ATTR(core_mask, S_IRUGO | S_IWUSR, show_core_mask, set_core_mask); -+ -+/** -+ * set_soft_job_timeout - Store callback for the soft_job_timeout sysfs -+ * file. -+ * -+ * @dev: The device this sysfs file is for. -+ * @attr: The attributes of the sysfs file. -+ * @buf: The value written to the sysfs file. -+ * @count: The number of bytes written to the sysfs file. -+ * -+ * This allows setting the timeout for software jobs. Waiting soft event wait -+ * jobs will be cancelled after this period expires, while soft fence wait jobs -+ * will print debug information if the fence debug feature is enabled. -+ * -+ * This is expressed in milliseconds. -+ * -+ * Return: count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_soft_job_timeout(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int soft_job_timeout_ms; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ if ((kstrtoint(buf, 0, &soft_job_timeout_ms) != 0) || -+ (soft_job_timeout_ms <= 0)) -+ return -EINVAL; -+ -+ atomic_set(&kbdev->js_data.soft_job_timeout_ms, -+ soft_job_timeout_ms); -+ -+ return count; -+} -+ -+/** -+ * show_soft_job_timeout - Show callback for the soft_job_timeout sysfs -+ * file. -+ * -+ * This will return the timeout for the software jobs. -+ * -+ * @dev: The device this sysfs file is for. -+ * @attr: The attributes of the sysfs file. -+ * @buf: The output buffer for the sysfs file contents. -+ * -+ * Return: The number of bytes output to buf. -+ */ -+static ssize_t show_soft_job_timeout(struct device *dev, -+ struct device_attribute *attr, -+ char * const buf) -+{ -+ struct kbase_device *kbdev; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ return scnprintf(buf, PAGE_SIZE, "%i\n", -+ atomic_read(&kbdev->js_data.soft_job_timeout_ms)); -+} -+ -+static DEVICE_ATTR(soft_job_timeout, S_IRUGO | S_IWUSR, -+ show_soft_job_timeout, set_soft_job_timeout); -+ -+static u32 timeout_ms_to_ticks(struct kbase_device *kbdev, long timeout_ms, -+ int default_ticks, u32 old_ticks) -+{ -+ if (timeout_ms > 0) { -+ u64 ticks = timeout_ms * 1000000ULL; -+ do_div(ticks, kbdev->js_data.scheduling_period_ns); -+ if (!ticks) -+ return 1; -+ return ticks; -+ } else if (timeout_ms < 0) { -+ return default_ticks; -+ } else { -+ return old_ticks; -+ } -+} -+ -+/** -+ * set_js_timeouts - Store callback for the js_timeouts sysfs file. -+ * -+ * This function is called to get the contents of the js_timeouts sysfs -+ * file. This file contains five values separated by whitespace. The values -+ * are basically the same as %JS_SOFT_STOP_TICKS, %JS_HARD_STOP_TICKS_SS, -+ * %JS_HARD_STOP_TICKS_DUMPING, %JS_RESET_TICKS_SS, %JS_RESET_TICKS_DUMPING -+ * configuration values (in that order), with the difference that the js_timeout -+ * values are expressed in MILLISECONDS. -+ * -+ * The js_timeouts sysfile file allows the current values in -+ * use by the job scheduler to get override. Note that a value needs to -+ * be other than 0 for it to override the current job scheduler value. -+ * -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_js_timeouts(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int items; -+ long js_soft_stop_ms; -+ long js_soft_stop_ms_cl; -+ long js_hard_stop_ms_ss; -+ long js_hard_stop_ms_cl; -+ long js_hard_stop_ms_dumping; -+ long js_reset_ms_ss; -+ long js_reset_ms_cl; -+ long js_reset_ms_dumping; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ items = sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld %ld", -+ &js_soft_stop_ms, &js_soft_stop_ms_cl, -+ &js_hard_stop_ms_ss, &js_hard_stop_ms_cl, -+ &js_hard_stop_ms_dumping, &js_reset_ms_ss, -+ &js_reset_ms_cl, &js_reset_ms_dumping); -+ -+ if (items == 8) { -+ struct kbasep_js_device_data *js_data = &kbdev->js_data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+#define UPDATE_TIMEOUT(ticks_name, ms_name, default) do {\ -+ js_data->ticks_name = timeout_ms_to_ticks(kbdev, ms_name, \ -+ default, js_data->ticks_name); \ -+ dev_dbg(kbdev->dev, "Overriding " #ticks_name \ -+ " with %lu ticks (%lu ms)\n", \ -+ (unsigned long)js_data->ticks_name, \ -+ ms_name); \ -+ } while (0) -+ -+ UPDATE_TIMEOUT(soft_stop_ticks, js_soft_stop_ms, -+ DEFAULT_JS_SOFT_STOP_TICKS); -+ UPDATE_TIMEOUT(soft_stop_ticks_cl, js_soft_stop_ms_cl, -+ DEFAULT_JS_SOFT_STOP_TICKS_CL); -+ UPDATE_TIMEOUT(hard_stop_ticks_ss, js_hard_stop_ms_ss, -+ kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408) ? -+ DEFAULT_JS_HARD_STOP_TICKS_SS_8408 : -+ DEFAULT_JS_HARD_STOP_TICKS_SS); -+ UPDATE_TIMEOUT(hard_stop_ticks_cl, js_hard_stop_ms_cl, -+ DEFAULT_JS_HARD_STOP_TICKS_CL); -+ UPDATE_TIMEOUT(hard_stop_ticks_dumping, -+ js_hard_stop_ms_dumping, -+ DEFAULT_JS_HARD_STOP_TICKS_DUMPING); -+ UPDATE_TIMEOUT(gpu_reset_ticks_ss, js_reset_ms_ss, -+ kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408) ? -+ DEFAULT_JS_RESET_TICKS_SS_8408 : -+ DEFAULT_JS_RESET_TICKS_SS); -+ UPDATE_TIMEOUT(gpu_reset_ticks_cl, js_reset_ms_cl, -+ DEFAULT_JS_RESET_TICKS_CL); -+ UPDATE_TIMEOUT(gpu_reset_ticks_dumping, js_reset_ms_dumping, -+ DEFAULT_JS_RESET_TICKS_DUMPING); -+ -+ kbase_js_set_timeouts(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return count; -+ } -+ -+ dev_err(kbdev->dev, "Couldn't process js_timeouts write operation.\n" -+ "Use format \n" -+ "Write 0 for no change, -1 to restore default timeout\n"); -+ return -EINVAL; -+} -+ -+static unsigned long get_js_timeout_in_ms( -+ u32 scheduling_period_ns, -+ u32 ticks) -+{ -+ u64 ms = (u64)ticks * scheduling_period_ns; -+ -+ do_div(ms, 1000000UL); -+ return ms; -+} -+ -+/** -+ * show_js_timeouts - Show callback for the js_timeouts sysfs file. -+ * -+ * This function is called to get the contents of the js_timeouts sysfs -+ * file. It returns the last set values written to the js_timeouts sysfs file. -+ * If the file didn't get written yet, the values will be current setting in -+ * use. -+ * @dev: The device this sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The output buffer for the sysfs file contents -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_js_timeouts(struct device *dev, struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ unsigned long js_soft_stop_ms; -+ unsigned long js_soft_stop_ms_cl; -+ unsigned long js_hard_stop_ms_ss; -+ unsigned long js_hard_stop_ms_cl; -+ unsigned long js_hard_stop_ms_dumping; -+ unsigned long js_reset_ms_ss; -+ unsigned long js_reset_ms_cl; -+ unsigned long js_reset_ms_dumping; -+ u32 scheduling_period_ns; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ scheduling_period_ns = kbdev->js_data.scheduling_period_ns; -+ -+#define GET_TIMEOUT(name) get_js_timeout_in_ms(\ -+ scheduling_period_ns, \ -+ kbdev->js_data.name) -+ -+ js_soft_stop_ms = GET_TIMEOUT(soft_stop_ticks); -+ js_soft_stop_ms_cl = GET_TIMEOUT(soft_stop_ticks_cl); -+ js_hard_stop_ms_ss = GET_TIMEOUT(hard_stop_ticks_ss); -+ js_hard_stop_ms_cl = GET_TIMEOUT(hard_stop_ticks_cl); -+ js_hard_stop_ms_dumping = GET_TIMEOUT(hard_stop_ticks_dumping); -+ js_reset_ms_ss = GET_TIMEOUT(gpu_reset_ticks_ss); -+ js_reset_ms_cl = GET_TIMEOUT(gpu_reset_ticks_cl); -+ js_reset_ms_dumping = GET_TIMEOUT(gpu_reset_ticks_dumping); -+ -+#undef GET_TIMEOUT -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%lu %lu %lu %lu %lu %lu %lu %lu\n", -+ js_soft_stop_ms, js_soft_stop_ms_cl, -+ js_hard_stop_ms_ss, js_hard_stop_ms_cl, -+ js_hard_stop_ms_dumping, js_reset_ms_ss, -+ js_reset_ms_cl, js_reset_ms_dumping); -+ -+ if (ret >= PAGE_SIZE) { -+ buf[PAGE_SIZE - 2] = '\n'; -+ buf[PAGE_SIZE - 1] = '\0'; -+ ret = PAGE_SIZE - 1; -+ } -+ -+ return ret; -+} -+ -+/* -+ * The sysfs file js_timeouts. -+ * -+ * This is used to override the current job scheduler values for -+ * JS_STOP_STOP_TICKS_SS -+ * JS_STOP_STOP_TICKS_CL -+ * JS_HARD_STOP_TICKS_SS -+ * JS_HARD_STOP_TICKS_CL -+ * JS_HARD_STOP_TICKS_DUMPING -+ * JS_RESET_TICKS_SS -+ * JS_RESET_TICKS_CL -+ * JS_RESET_TICKS_DUMPING. -+ */ -+static DEVICE_ATTR(js_timeouts, S_IRUGO | S_IWUSR, show_js_timeouts, set_js_timeouts); -+ -+static u32 get_new_js_timeout( -+ u32 old_period, -+ u32 old_ticks, -+ u32 new_scheduling_period_ns) -+{ -+ u64 ticks = (u64)old_period * (u64)old_ticks; -+ do_div(ticks, new_scheduling_period_ns); -+ return ticks?ticks:1; -+} -+ -+/** -+ * set_js_scheduling_period - Store callback for the js_scheduling_period sysfs -+ * file -+ * @dev: The device the sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * This function is called when the js_scheduling_period sysfs file is written -+ * to. It checks the data written, and if valid updates the js_scheduling_period -+ * value -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_js_scheduling_period(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int ret; -+ unsigned int js_scheduling_period; -+ u32 new_scheduling_period_ns; -+ u32 old_period; -+ struct kbasep_js_device_data *js_data; -+ unsigned long flags; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ js_data = &kbdev->js_data; -+ -+ ret = kstrtouint(buf, 0, &js_scheduling_period); -+ if (ret || !js_scheduling_period) { -+ dev_err(kbdev->dev, "Couldn't process js_scheduling_period write operation.\n" -+ "Use format \n"); -+ return -EINVAL; -+ } -+ -+ new_scheduling_period_ns = js_scheduling_period * 1000000; -+ -+ /* Update scheduling timeouts */ -+ mutex_lock(&js_data->runpool_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* If no contexts have been scheduled since js_timeouts was last written -+ * to, the new timeouts might not have been latched yet. So check if an -+ * update is pending and use the new values if necessary. */ -+ -+ /* Use previous 'new' scheduling period as a base if present. */ -+ old_period = js_data->scheduling_period_ns; -+ -+#define SET_TIMEOUT(name) \ -+ (js_data->name = get_new_js_timeout(\ -+ old_period, \ -+ kbdev->js_data.name, \ -+ new_scheduling_period_ns)) -+ -+ SET_TIMEOUT(soft_stop_ticks); -+ SET_TIMEOUT(soft_stop_ticks_cl); -+ SET_TIMEOUT(hard_stop_ticks_ss); -+ SET_TIMEOUT(hard_stop_ticks_cl); -+ SET_TIMEOUT(hard_stop_ticks_dumping); -+ SET_TIMEOUT(gpu_reset_ticks_ss); -+ SET_TIMEOUT(gpu_reset_ticks_cl); -+ SET_TIMEOUT(gpu_reset_ticks_dumping); -+ -+#undef SET_TIMEOUT -+ -+ js_data->scheduling_period_ns = new_scheduling_period_ns; -+ -+ kbase_js_set_timeouts(kbdev); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&js_data->runpool_mutex); -+ -+ dev_dbg(kbdev->dev, "JS scheduling period: %dms\n", -+ js_scheduling_period); -+ -+ return count; -+} -+ -+/** -+ * show_js_scheduling_period - Show callback for the js_scheduling_period sysfs -+ * entry. -+ * @dev: The device this sysfs file is for. -+ * @attr: The attributes of the sysfs file. -+ * @buf: The output buffer to receive the GPU information. -+ * -+ * This function is called to get the current period used for the JS scheduling -+ * period. -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_js_scheduling_period(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ u32 period; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ period = kbdev->js_data.scheduling_period_ns; -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%d\n", -+ period / 1000000); -+ -+ return ret; -+} -+ -+static DEVICE_ATTR(js_scheduling_period, S_IRUGO | S_IWUSR, -+ show_js_scheduling_period, set_js_scheduling_period); -+ -+#if !MALI_CUSTOMER_RELEASE -+/** -+ * set_force_replay - Store callback for the force_replay sysfs file. -+ * -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_force_replay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ if (!strncmp("limit=", buf, MIN(6, count))) { -+ int force_replay_limit; -+ int items = sscanf(buf, "limit=%u", &force_replay_limit); -+ -+ if (items == 1) { -+ kbdev->force_replay_random = false; -+ kbdev->force_replay_limit = force_replay_limit; -+ kbdev->force_replay_count = 0; -+ -+ return count; -+ } -+ } else if (!strncmp("random_limit", buf, MIN(12, count))) { -+ kbdev->force_replay_random = true; -+ kbdev->force_replay_count = 0; -+ -+ return count; -+ } else if (!strncmp("norandom_limit", buf, MIN(14, count))) { -+ kbdev->force_replay_random = false; -+ kbdev->force_replay_limit = KBASEP_FORCE_REPLAY_DISABLED; -+ kbdev->force_replay_count = 0; -+ -+ return count; -+ } else if (!strncmp("core_req=", buf, MIN(9, count))) { -+ unsigned int core_req; -+ int items = sscanf(buf, "core_req=%x", &core_req); -+ -+ if (items == 1) { -+ kbdev->force_replay_core_req = (base_jd_core_req)core_req; -+ -+ return count; -+ } -+ } -+ dev_err(kbdev->dev, "Couldn't process force_replay write operation.\nPossible settings: limit=, random_limit, norandom_limit, core_req=\n"); -+ return -EINVAL; -+} -+ -+/** -+ * show_force_replay - Show callback for the force_replay sysfs file. -+ * -+ * This function is called to get the contents of the force_replay sysfs -+ * file. It returns the last set value written to the force_replay sysfs file. -+ * If the file didn't get written yet, the values will be 0. -+ * -+ * @dev: The device this sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The output buffer for the sysfs file contents -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_force_replay(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ if (kbdev->force_replay_random) -+ ret = scnprintf(buf, PAGE_SIZE, -+ "limit=0\nrandom_limit\ncore_req=%x\n", -+ kbdev->force_replay_core_req); -+ else -+ ret = scnprintf(buf, PAGE_SIZE, -+ "limit=%u\nnorandom_limit\ncore_req=%x\n", -+ kbdev->force_replay_limit, -+ kbdev->force_replay_core_req); -+ -+ if (ret >= PAGE_SIZE) { -+ buf[PAGE_SIZE - 2] = '\n'; -+ buf[PAGE_SIZE - 1] = '\0'; -+ ret = PAGE_SIZE - 1; -+ } -+ -+ return ret; -+} -+ -+/* -+ * The sysfs file force_replay. -+ */ -+static DEVICE_ATTR(force_replay, S_IRUGO | S_IWUSR, show_force_replay, -+ set_force_replay); -+#endif /* !MALI_CUSTOMER_RELEASE */ -+ -+#ifdef CONFIG_MALI_DEBUG -+static ssize_t set_js_softstop_always(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int ret; -+ int softstop_always; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = kstrtoint(buf, 0, &softstop_always); -+ if (ret || ((softstop_always != 0) && (softstop_always != 1))) { -+ dev_err(kbdev->dev, "Couldn't process js_softstop_always write operation.\n" -+ "Use format \n"); -+ return -EINVAL; -+ } -+ -+ kbdev->js_data.softstop_always = (bool) softstop_always; -+ dev_dbg(kbdev->dev, "Support for softstop on a single context: %s\n", -+ (kbdev->js_data.softstop_always) ? -+ "Enabled" : "Disabled"); -+ return count; -+} -+ -+static ssize_t show_js_softstop_always(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%d\n", kbdev->js_data.softstop_always); -+ -+ if (ret >= PAGE_SIZE) { -+ buf[PAGE_SIZE - 2] = '\n'; -+ buf[PAGE_SIZE - 1] = '\0'; -+ ret = PAGE_SIZE - 1; -+ } -+ -+ return ret; -+} -+ -+/* -+ * By default, soft-stops are disabled when only a single context is present. -+ * The ability to enable soft-stop when only a single context is present can be -+ * used for debug and unit-testing purposes. -+ * (see CL t6xx_stress_1 unit-test as an example whereby this feature is used.) -+ */ -+static DEVICE_ATTR(js_softstop_always, S_IRUGO | S_IWUSR, show_js_softstop_always, set_js_softstop_always); -+#endif /* CONFIG_MALI_DEBUG */ -+ -+#ifdef CONFIG_MALI_DEBUG -+typedef void (kbasep_debug_command_func) (struct kbase_device *); -+ -+enum kbasep_debug_command_code { -+ KBASEP_DEBUG_COMMAND_DUMPTRACE, -+ -+ /* This must be the last enum */ -+ KBASEP_DEBUG_COMMAND_COUNT -+}; -+ -+struct kbasep_debug_command { -+ char *str; -+ kbasep_debug_command_func *func; -+}; -+ -+/* Debug commands supported by the driver */ -+static const struct kbasep_debug_command debug_commands[] = { -+ { -+ .str = "dumptrace", -+ .func = &kbasep_trace_dump, -+ } -+}; -+ -+/** -+ * show_debug - Show callback for the debug_command sysfs file. -+ * -+ * This function is called to get the contents of the debug_command sysfs -+ * file. This is a list of the available debug commands, separated by newlines. -+ * -+ * @dev: The device this sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The output buffer for the sysfs file contents -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_debug(struct device *dev, struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ int i; -+ ssize_t ret = 0; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ for (i = 0; i < KBASEP_DEBUG_COMMAND_COUNT && ret < PAGE_SIZE; i++) -+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s\n", debug_commands[i].str); -+ -+ if (ret >= PAGE_SIZE) { -+ buf[PAGE_SIZE - 2] = '\n'; -+ buf[PAGE_SIZE - 1] = '\0'; -+ ret = PAGE_SIZE - 1; -+ } -+ -+ return ret; -+} -+ -+/** -+ * issue_debug - Store callback for the debug_command sysfs file. -+ * -+ * This function is called when the debug_command sysfs file is written to. -+ * It matches the requested command against the available commands, and if -+ * a matching command is found calls the associated function from -+ * @debug_commands to issue the command. -+ * -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t issue_debug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int i; -+ -+ kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ for (i = 0; i < KBASEP_DEBUG_COMMAND_COUNT; i++) { -+ if (sysfs_streq(debug_commands[i].str, buf)) { -+ debug_commands[i].func(kbdev); -+ return count; -+ } -+ } -+ -+ /* Debug Command not found */ -+ dev_err(dev, "debug_command: command not known\n"); -+ return -EINVAL; -+} -+ -+/* The sysfs file debug_command. -+ * -+ * This is used to issue general debug commands to the device driver. -+ * Reading it will produce a list of debug commands, separated by newlines. -+ * Writing to it with one of those commands will issue said command. -+ */ -+static DEVICE_ATTR(debug_command, S_IRUGO | S_IWUSR, show_debug, issue_debug); -+#endif /* CONFIG_MALI_DEBUG */ -+ -+/** -+ * kbase_show_gpuinfo - Show callback for the gpuinfo sysfs entry. -+ * @dev: The device this sysfs file is for. -+ * @attr: The attributes of the sysfs file. -+ * @buf: The output buffer to receive the GPU information. -+ * -+ * This function is called to get a description of the present Mali -+ * GPU via the gpuinfo sysfs entry. This includes the GPU family, the -+ * number of cores, the hardware version and the raw product id. For -+ * example -+ * -+ * Mali-T60x MP4 r0p0 0x6956 -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t kbase_show_gpuinfo(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ static const struct gpu_product_id_name { -+ unsigned id; -+ char *name; -+ } gpu_product_id_names[] = { -+ { .id = GPU_ID_PI_T60X, .name = "Mali-T60x" }, -+ { .id = GPU_ID_PI_T62X, .name = "Mali-T62x" }, -+ { .id = GPU_ID_PI_T72X, .name = "Mali-T72x" }, -+ { .id = GPU_ID_PI_T76X, .name = "Mali-T76x" }, -+ { .id = GPU_ID_PI_T82X, .name = "Mali-T82x" }, -+ { .id = GPU_ID_PI_T83X, .name = "Mali-T83x" }, -+ { .id = GPU_ID_PI_T86X, .name = "Mali-T86x" }, -+ { .id = GPU_ID_PI_TFRX, .name = "Mali-T88x" }, -+ { .id = GPU_ID2_PRODUCT_TMIX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, -+ .name = "Mali-G71" }, -+ { .id = GPU_ID2_PRODUCT_THEX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, -+ .name = "Mali-THEx" }, -+ { .id = GPU_ID2_PRODUCT_TSIX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, -+ .name = "Mali-G51" }, -+ }; -+ const char *product_name = "(Unknown Mali GPU)"; -+ struct kbase_device *kbdev; -+ u32 gpu_id; -+ unsigned product_id, product_id_mask; -+ unsigned i; -+ bool is_new_format; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ product_id = gpu_id >> GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ is_new_format = GPU_ID_IS_NEW_FORMAT(product_id); -+ product_id_mask = -+ (is_new_format ? -+ GPU_ID2_PRODUCT_MODEL : -+ GPU_ID_VERSION_PRODUCT_ID) >> -+ GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ -+ for (i = 0; i < ARRAY_SIZE(gpu_product_id_names); ++i) { -+ const struct gpu_product_id_name *p = &gpu_product_id_names[i]; -+ -+ if ((GPU_ID_IS_NEW_FORMAT(p->id) == is_new_format) && -+ (p->id & product_id_mask) == -+ (product_id & product_id_mask)) { -+ product_name = p->name; -+ break; -+ } -+ } -+ -+ return scnprintf(buf, PAGE_SIZE, "%s %d cores r%dp%d 0x%04X\n", -+ product_name, kbdev->gpu_props.num_cores, -+ (gpu_id & GPU_ID_VERSION_MAJOR) >> GPU_ID_VERSION_MAJOR_SHIFT, -+ (gpu_id & GPU_ID_VERSION_MINOR) >> GPU_ID_VERSION_MINOR_SHIFT, -+ product_id); -+} -+static DEVICE_ATTR(gpuinfo, S_IRUGO, kbase_show_gpuinfo, NULL); -+ -+/** -+ * set_dvfs_period - Store callback for the dvfs_period sysfs file. -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * This function is called when the dvfs_period sysfs file is written to. It -+ * checks the data written, and if valid updates the DVFS period variable, -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_dvfs_period(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int ret; -+ int dvfs_period; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = kstrtoint(buf, 0, &dvfs_period); -+ if (ret || dvfs_period <= 0) { -+ dev_err(kbdev->dev, "Couldn't process dvfs_period write operation.\n" -+ "Use format \n"); -+ return -EINVAL; -+ } -+ -+ kbdev->pm.dvfs_period = dvfs_period; -+ dev_dbg(kbdev->dev, "DVFS period: %dms\n", dvfs_period); -+ -+ return count; -+} -+ -+/** -+ * show_dvfs_period - Show callback for the dvfs_period sysfs entry. -+ * @dev: The device this sysfs file is for. -+ * @attr: The attributes of the sysfs file. -+ * @buf: The output buffer to receive the GPU information. -+ * -+ * This function is called to get the current period used for the DVFS sample -+ * timer. -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_dvfs_period(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%d\n", kbdev->pm.dvfs_period); -+ -+ return ret; -+} -+ -+static DEVICE_ATTR(dvfs_period, S_IRUGO | S_IWUSR, show_dvfs_period, -+ set_dvfs_period); -+ -+/** -+ * set_pm_poweroff - Store callback for the pm_poweroff sysfs file. -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * This function is called when the pm_poweroff sysfs file is written to. -+ * -+ * This file contains three values separated by whitespace. The values -+ * are gpu_poweroff_time (the period of the poweroff timer, in ns), -+ * poweroff_shader_ticks (the number of poweroff timer ticks before an idle -+ * shader is powered off), and poweroff_gpu_ticks (the number of poweroff timer -+ * ticks before the GPU is powered off), in that order. -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_pm_poweroff(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int items; -+ s64 gpu_poweroff_time; -+ int poweroff_shader_ticks, poweroff_gpu_ticks; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ items = sscanf(buf, "%llu %u %u", &gpu_poweroff_time, -+ &poweroff_shader_ticks, -+ &poweroff_gpu_ticks); -+ if (items != 3) { -+ dev_err(kbdev->dev, "Couldn't process pm_poweroff write operation.\n" -+ "Use format \n"); -+ return -EINVAL; -+ } -+ -+ kbdev->pm.gpu_poweroff_time = HR_TIMER_DELAY_NSEC(gpu_poweroff_time); -+ kbdev->pm.poweroff_shader_ticks = poweroff_shader_ticks; -+ kbdev->pm.poweroff_gpu_ticks = poweroff_gpu_ticks; -+ -+ return count; -+} -+ -+/** -+ * show_pm_poweroff - Show callback for the pm_poweroff sysfs entry. -+ * @dev: The device this sysfs file is for. -+ * @attr: The attributes of the sysfs file. -+ * @buf: The output buffer to receive the GPU information. -+ * -+ * This function is called to get the current period used for the DVFS sample -+ * timer. -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_pm_poweroff(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%llu %u %u\n", -+ ktime_to_ns(kbdev->pm.gpu_poweroff_time), -+ kbdev->pm.poweroff_shader_ticks, -+ kbdev->pm.poweroff_gpu_ticks); -+ -+ return ret; -+} -+ -+static DEVICE_ATTR(pm_poweroff, S_IRUGO | S_IWUSR, show_pm_poweroff, -+ set_pm_poweroff); -+ -+/** -+ * set_reset_timeout - Store callback for the reset_timeout sysfs file. -+ * @dev: The device with sysfs file is for -+ * @attr: The attributes of the sysfs file -+ * @buf: The value written to the sysfs file -+ * @count: The number of bytes written to the sysfs file -+ * -+ * This function is called when the reset_timeout sysfs file is written to. It -+ * checks the data written, and if valid updates the reset timeout. -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t set_reset_timeout(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ int ret; -+ int reset_timeout; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = kstrtoint(buf, 0, &reset_timeout); -+ if (ret || reset_timeout <= 0) { -+ dev_err(kbdev->dev, "Couldn't process reset_timeout write operation.\n" -+ "Use format \n"); -+ return -EINVAL; -+ } -+ -+ kbdev->reset_timeout_ms = reset_timeout; -+ dev_dbg(kbdev->dev, "Reset timeout: %dms\n", reset_timeout); -+ -+ return count; -+} -+ -+/** -+ * show_reset_timeout - Show callback for the reset_timeout sysfs entry. -+ * @dev: The device this sysfs file is for. -+ * @attr: The attributes of the sysfs file. -+ * @buf: The output buffer to receive the GPU information. -+ * -+ * This function is called to get the current reset timeout. -+ * -+ * Return: The number of bytes output to @buf. -+ */ -+static ssize_t show_reset_timeout(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%d\n", kbdev->reset_timeout_ms); -+ -+ return ret; -+} -+ -+static DEVICE_ATTR(reset_timeout, S_IRUGO | S_IWUSR, show_reset_timeout, -+ set_reset_timeout); -+ -+ -+ -+static ssize_t show_mem_pool_size(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%zu\n", -+ kbase_mem_pool_size(&kbdev->mem_pool)); -+ -+ return ret; -+} -+ -+static ssize_t set_mem_pool_size(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ size_t new_size; -+ int err; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ err = kstrtoul(buf, 0, (unsigned long *)&new_size); -+ if (err) -+ return err; -+ -+ kbase_mem_pool_trim(&kbdev->mem_pool, new_size); -+ -+ return count; -+} -+ -+static DEVICE_ATTR(mem_pool_size, S_IRUGO | S_IWUSR, show_mem_pool_size, -+ set_mem_pool_size); -+ -+static ssize_t show_mem_pool_max_size(struct device *dev, -+ struct device_attribute *attr, char * const buf) -+{ -+ struct kbase_device *kbdev; -+ ssize_t ret; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ ret = scnprintf(buf, PAGE_SIZE, "%zu\n", -+ kbase_mem_pool_max_size(&kbdev->mem_pool)); -+ -+ return ret; -+} -+ -+static ssize_t set_mem_pool_max_size(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct kbase_device *kbdev; -+ size_t new_max_size; -+ int err; -+ -+ kbdev = to_kbase_device(dev); -+ if (!kbdev) -+ return -ENODEV; -+ -+ err = kstrtoul(buf, 0, (unsigned long *)&new_max_size); -+ if (err) -+ return -EINVAL; -+ -+ kbase_mem_pool_set_max_size(&kbdev->mem_pool, new_max_size); -+ -+ return count; -+} -+ -+static DEVICE_ATTR(mem_pool_max_size, S_IRUGO | S_IWUSR, show_mem_pool_max_size, -+ set_mem_pool_max_size); -+ -+#ifdef CONFIG_DEBUG_FS -+ -+/* Number of entries in serialize_jobs_settings[] */ -+#define NR_SERIALIZE_JOBS_SETTINGS 5 -+/* Maximum string length in serialize_jobs_settings[].name */ -+#define MAX_SERIALIZE_JOBS_NAME_LEN 16 -+ -+static struct -+{ -+ char *name; -+ u8 setting; -+} serialize_jobs_settings[NR_SERIALIZE_JOBS_SETTINGS] = { -+ {"none", 0}, -+ {"intra-slot", KBASE_SERIALIZE_INTRA_SLOT}, -+ {"inter-slot", KBASE_SERIALIZE_INTER_SLOT}, -+ {"full", KBASE_SERIALIZE_INTRA_SLOT | KBASE_SERIALIZE_INTER_SLOT}, -+ {"full-reset", KBASE_SERIALIZE_INTRA_SLOT | KBASE_SERIALIZE_INTER_SLOT | -+ KBASE_SERIALIZE_RESET} -+}; -+ -+/** -+ * kbasep_serialize_jobs_seq_show - Show callback for the serialize_jobs debugfs -+ * file -+ * @sfile: seq_file pointer -+ * @data: Private callback data -+ * -+ * This function is called to get the contents of the serialize_jobs debugfs -+ * file. This is a list of the available settings with the currently active one -+ * surrounded by square brackets. -+ * -+ * Return: 0 on success, or an error code on error -+ */ -+static int kbasep_serialize_jobs_seq_show(struct seq_file *sfile, void *data) -+{ -+ struct kbase_device *kbdev = sfile->private; -+ int i; -+ -+ CSTD_UNUSED(data); -+ -+ for (i = 0; i < NR_SERIALIZE_JOBS_SETTINGS; i++) { -+ if (kbdev->serialize_jobs == serialize_jobs_settings[i].setting) -+ seq_printf(sfile, "[%s] ", -+ serialize_jobs_settings[i].name); -+ else -+ seq_printf(sfile, "%s ", -+ serialize_jobs_settings[i].name); -+ } -+ -+ seq_puts(sfile, "\n"); -+ -+ return 0; -+} -+ -+/** -+ * kbasep_serialize_jobs_debugfs_write - Store callback for the serialize_jobs -+ * debugfs file. -+ * @file: File pointer -+ * @ubuf: User buffer containing data to store -+ * @count: Number of bytes in user buffer -+ * @ppos: File position -+ * -+ * This function is called when the serialize_jobs debugfs file is written to. -+ * It matches the requested setting against the available settings and if a -+ * matching setting is found updates kbdev->serialize_jobs. -+ * -+ * Return: @count if the function succeeded. An error code on failure. -+ */ -+static ssize_t kbasep_serialize_jobs_debugfs_write(struct file *file, -+ const char __user *ubuf, size_t count, loff_t *ppos) -+{ -+ struct seq_file *s = file->private_data; -+ struct kbase_device *kbdev = s->private; -+ char buf[MAX_SERIALIZE_JOBS_NAME_LEN]; -+ int i; -+ bool valid = false; -+ -+ CSTD_UNUSED(ppos); -+ -+ count = min_t(size_t, sizeof(buf) - 1, count); -+ if (copy_from_user(buf, ubuf, count)) -+ return -EFAULT; -+ -+ buf[count] = 0; -+ -+ for (i = 0; i < NR_SERIALIZE_JOBS_SETTINGS; i++) { -+ if (sysfs_streq(serialize_jobs_settings[i].name, buf)) { -+ kbdev->serialize_jobs = -+ serialize_jobs_settings[i].setting; -+ valid = true; -+ break; -+ } -+ } -+ -+ if (!valid) { -+ dev_err(kbdev->dev, "serialize_jobs: invalid setting\n"); -+ return -EINVAL; -+ } -+ -+ return count; -+} -+ -+/** -+ * kbasep_serialize_jobs_debugfs_open - Open callback for the serialize_jobs -+ * debugfs file -+ * @in: inode pointer -+ * @file: file pointer -+ * -+ * Return: Zero on success, error code on failure -+ */ -+static int kbasep_serialize_jobs_debugfs_open(struct inode *in, -+ struct file *file) -+{ -+ return single_open(file, kbasep_serialize_jobs_seq_show, in->i_private); -+} -+ -+static const struct file_operations kbasep_serialize_jobs_debugfs_fops = { -+ .open = kbasep_serialize_jobs_debugfs_open, -+ .read = seq_read, -+ .write = kbasep_serialize_jobs_debugfs_write, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+static int kbasep_protected_mode_init(struct kbase_device *kbdev) -+{ -+#ifdef CONFIG_OF -+ struct device_node *protected_node; -+ struct platform_device *pdev; -+ struct protected_mode_device *protected_dev; -+#endif -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE)) { -+ /* Use native protected ops */ -+ kbdev->protected_dev = kzalloc(sizeof(*kbdev->protected_dev), -+ GFP_KERNEL); -+ if (!kbdev->protected_dev) -+ return -ENOMEM; -+ kbdev->protected_dev->data = kbdev; -+ kbdev->protected_ops = &kbase_native_protected_ops; -+ kbdev->protected_mode_support = true; -+ return 0; -+ } -+ -+ kbdev->protected_mode_support = false; -+ -+#ifdef CONFIG_OF -+ protected_node = of_parse_phandle(kbdev->dev->of_node, -+ "protected-mode-switcher", 0); -+ -+ if (!protected_node) -+ protected_node = of_parse_phandle(kbdev->dev->of_node, -+ "secure-mode-switcher", 0); -+ -+ if (!protected_node) { -+ /* If protected_node cannot be looked up then we assume -+ * protected mode is not supported on this platform. */ -+ dev_info(kbdev->dev, "Protected mode not available\n"); -+ return 0; -+ } -+ -+ pdev = of_find_device_by_node(protected_node); -+ if (!pdev) -+ return -EINVAL; -+ -+ protected_dev = platform_get_drvdata(pdev); -+ if (!protected_dev) -+ return -EPROBE_DEFER; -+ -+ kbdev->protected_ops = &protected_dev->ops; -+ kbdev->protected_dev = protected_dev; -+ -+ if (kbdev->protected_ops) { -+ int err; -+ -+ /* Make sure protected mode is disabled on startup */ -+ mutex_lock(&kbdev->pm.lock); -+ err = kbdev->protected_ops->protected_mode_disable( -+ kbdev->protected_dev); -+ mutex_unlock(&kbdev->pm.lock); -+ -+ /* protected_mode_disable() returns -EINVAL if not supported */ -+ kbdev->protected_mode_support = (err != -EINVAL); -+ } -+#endif -+ return 0; -+} -+ -+static void kbasep_protected_mode_term(struct kbase_device *kbdev) -+{ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE)) -+ kfree(kbdev->protected_dev); -+} -+ -+#ifdef CONFIG_MALI_NO_MALI -+static int kbase_common_reg_map(struct kbase_device *kbdev) -+{ -+ return 0; -+} -+static void kbase_common_reg_unmap(struct kbase_device * const kbdev) -+{ -+} -+#else /* CONFIG_MALI_NO_MALI */ -+static int kbase_common_reg_map(struct kbase_device *kbdev) -+{ -+ int err = -ENOMEM; -+ -+ if (!request_mem_region(kbdev->reg_start, kbdev->reg_size, dev_name(kbdev->dev))) { -+ dev_err(kbdev->dev, "Register window unavailable\n"); -+ err = -EIO; -+ goto out_region; -+ } -+ -+ kbdev->reg = ioremap(kbdev->reg_start, kbdev->reg_size); -+ if (!kbdev->reg) { -+ dev_err(kbdev->dev, "Can't remap register window\n"); -+ err = -EINVAL; -+ goto out_ioremap; -+ } -+ -+ return 0; -+ -+ out_ioremap: -+ release_mem_region(kbdev->reg_start, kbdev->reg_size); -+ out_region: -+ return err; -+} -+ -+static void kbase_common_reg_unmap(struct kbase_device * const kbdev) -+{ -+ if (kbdev->reg) { -+ iounmap(kbdev->reg); -+ release_mem_region(kbdev->reg_start, kbdev->reg_size); -+ kbdev->reg = NULL; -+ kbdev->reg_start = 0; -+ kbdev->reg_size = 0; -+ } -+} -+#endif /* CONFIG_MALI_NO_MALI */ -+ -+static int registers_map(struct kbase_device * const kbdev) -+{ -+ -+ /* the first memory resource is the physical address of the GPU -+ * registers */ -+ struct platform_device *pdev = to_platform_device(kbdev->dev); -+ struct resource *reg_res; -+ int err; -+ -+ reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!reg_res) { -+ dev_err(kbdev->dev, "Invalid register resource\n"); -+ return -ENOENT; -+ } -+ -+ kbdev->reg_start = reg_res->start; -+ kbdev->reg_size = resource_size(reg_res); -+ -+ err = kbase_common_reg_map(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Failed to map registers\n"); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static void registers_unmap(struct kbase_device *kbdev) -+{ -+ kbase_common_reg_unmap(kbdev); -+} -+ -+static int power_control_init(struct platform_device *pdev) -+{ -+ struct kbase_device *kbdev = to_kbase_device(&pdev->dev); -+ int err = 0; -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) && defined(CONFIG_OF) \ -+ && defined(CONFIG_REGULATOR) -+ kbdev->regulator = regulator_get_optional(kbdev->dev, "mali"); -+ if (IS_ERR_OR_NULL(kbdev->regulator)) { -+ err = PTR_ERR(kbdev->regulator); -+ kbdev->regulator = NULL; -+ if (err == -EPROBE_DEFER) { -+ dev_err(&pdev->dev, "Failed to get regulator\n"); -+ return err; -+ } -+ dev_info(kbdev->dev, -+ "Continuing without Mali regulator control\n"); -+ /* Allow probe to continue without regulator */ -+ } -+#endif /* LINUX_VERSION_CODE >= 3, 12, 0 */ -+ -+ kbdev->clock = clk_get(kbdev->dev, "clk_mali"); -+ if (IS_ERR_OR_NULL(kbdev->clock)) { -+ err = PTR_ERR(kbdev->clock); -+ kbdev->clock = NULL; -+ if (err == -EPROBE_DEFER) { -+ dev_err(&pdev->dev, "Failed to get clock\n"); -+ goto fail; -+ } -+ dev_info(kbdev->dev, "Continuing without Mali clock control\n"); -+ /* Allow probe to continue without clock. */ -+ } else { -+ err = clk_prepare_enable(kbdev->clock); -+ if (err) { -+ dev_err(kbdev->dev, -+ "Failed to prepare and enable clock (%d)\n", -+ err); -+ goto fail; -+ } -+ } -+ -+#if defined(CONFIG_OF) && defined(CONFIG_PM_OPP) -+ /* Register the OPPs if they are available in device tree */ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) \ -+ || defined(LSK_OPPV2_BACKPORT) -+ err = dev_pm_opp_of_add_table(kbdev->dev); -+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -+ err = of_init_opp_table(kbdev->dev); -+#else -+ err = 0; -+#endif /* LINUX_VERSION_CODE */ -+ if (err) -+ dev_dbg(kbdev->dev, "OPP table not found\n"); -+#endif /* CONFIG_OF && CONFIG_PM_OPP */ -+ -+ return 0; -+ -+fail: -+ -+if (kbdev->clock != NULL) { -+ clk_put(kbdev->clock); -+ kbdev->clock = NULL; -+} -+ -+#ifdef CONFIG_REGULATOR -+ if (NULL != kbdev->regulator) { -+ regulator_put(kbdev->regulator); -+ kbdev->regulator = NULL; -+ } -+#endif -+ -+ return err; -+} -+ -+static void power_control_term(struct kbase_device *kbdev) -+{ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || \ -+ defined(LSK_OPPV2_BACKPORT) -+ dev_pm_opp_of_remove_table(kbdev->dev); -+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) -+ of_free_opp_table(kbdev->dev); -+#endif -+ -+ if (kbdev->clock) { -+ clk_disable_unprepare(kbdev->clock); -+ clk_put(kbdev->clock); -+ kbdev->clock = NULL; -+ } -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) && defined(CONFIG_OF) \ -+ && defined(CONFIG_REGULATOR) -+ if (kbdev->regulator) { -+ regulator_put(kbdev->regulator); -+ kbdev->regulator = NULL; -+ } -+#endif /* LINUX_VERSION_CODE >= 3, 12, 0 */ -+} -+ -+#ifdef CONFIG_DEBUG_FS -+ -+#if KBASE_GPU_RESET_EN -+#include -+ -+static void trigger_quirks_reload(struct kbase_device *kbdev) -+{ -+ kbase_pm_context_active(kbdev); -+ if (kbase_prepare_to_reset_gpu(kbdev)) -+ kbase_reset_gpu(kbdev); -+ kbase_pm_context_idle(kbdev); -+} -+ -+#define MAKE_QUIRK_ACCESSORS(type) \ -+static int type##_quirks_set(void *data, u64 val) \ -+{ \ -+ struct kbase_device *kbdev; \ -+ kbdev = (struct kbase_device *)data; \ -+ kbdev->hw_quirks_##type = (u32)val; \ -+ trigger_quirks_reload(kbdev); \ -+ return 0;\ -+} \ -+\ -+static int type##_quirks_get(void *data, u64 *val) \ -+{ \ -+ struct kbase_device *kbdev;\ -+ kbdev = (struct kbase_device *)data;\ -+ *val = kbdev->hw_quirks_##type;\ -+ return 0;\ -+} \ -+DEFINE_SIMPLE_ATTRIBUTE(fops_##type##_quirks, type##_quirks_get,\ -+ type##_quirks_set, "%llu\n") -+ -+MAKE_QUIRK_ACCESSORS(sc); -+MAKE_QUIRK_ACCESSORS(tiler); -+MAKE_QUIRK_ACCESSORS(mmu); -+MAKE_QUIRK_ACCESSORS(jm); -+ -+#endif /* KBASE_GPU_RESET_EN */ -+ -+/** -+ * debugfs_protected_debug_mode_read - "protected_debug_mode" debugfs read -+ * @file: File object to read is for -+ * @buf: User buffer to populate with data -+ * @len: Length of user buffer -+ * @ppos: Offset within file object -+ * -+ * Retrieves the current status of protected debug mode -+ * (0 = disabled, 1 = enabled) -+ * -+ * Return: Number of bytes added to user buffer -+ */ -+static ssize_t debugfs_protected_debug_mode_read(struct file *file, -+ char __user *buf, size_t len, loff_t *ppos) -+{ -+ struct kbase_device *kbdev = (struct kbase_device *)file->private_data; -+ u32 gpu_status; -+ ssize_t ret_val; -+ -+ kbase_pm_context_active(kbdev); -+ gpu_status = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_STATUS), NULL); -+ kbase_pm_context_idle(kbdev); -+ -+ if (gpu_status & GPU_DBGEN) -+ ret_val = simple_read_from_buffer(buf, len, ppos, "1\n", 2); -+ else -+ ret_val = simple_read_from_buffer(buf, len, ppos, "0\n", 2); -+ -+ return ret_val; -+} -+ -+/* -+ * struct fops_protected_debug_mode - "protected_debug_mode" debugfs fops -+ * -+ * Contains the file operations for the "protected_debug_mode" debugfs file -+ */ -+static const struct file_operations fops_protected_debug_mode = { -+ .open = simple_open, -+ .read = debugfs_protected_debug_mode_read, -+ .llseek = default_llseek, -+}; -+ -+static int kbase_device_debugfs_init(struct kbase_device *kbdev) -+{ -+ struct dentry *debugfs_ctx_defaults_directory; -+ int err; -+ -+ kbdev->mali_debugfs_directory = debugfs_create_dir(kbdev->devname, -+ NULL); -+ if (!kbdev->mali_debugfs_directory) { -+ dev_err(kbdev->dev, "Couldn't create mali debugfs directory\n"); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ kbdev->debugfs_ctx_directory = debugfs_create_dir("ctx", -+ kbdev->mali_debugfs_directory); -+ if (!kbdev->debugfs_ctx_directory) { -+ dev_err(kbdev->dev, "Couldn't create mali debugfs ctx directory\n"); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ debugfs_ctx_defaults_directory = debugfs_create_dir("defaults", -+ kbdev->debugfs_ctx_directory); -+ if (!debugfs_ctx_defaults_directory) { -+ dev_err(kbdev->dev, "Couldn't create mali debugfs ctx defaults directory\n"); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+#if !MALI_CUSTOMER_RELEASE -+ kbasep_regs_dump_debugfs_init(kbdev); -+#endif /* !MALI_CUSTOMER_RELEASE */ -+ kbasep_regs_history_debugfs_init(kbdev); -+ -+ kbase_debug_job_fault_debugfs_init(kbdev); -+ kbasep_gpu_memory_debugfs_init(kbdev); -+ kbase_as_fault_debugfs_init(kbdev); -+#if KBASE_GPU_RESET_EN -+ /* fops_* variables created by invocations of macro -+ * MAKE_QUIRK_ACCESSORS() above. */ -+ debugfs_create_file("quirks_sc", 0644, -+ kbdev->mali_debugfs_directory, kbdev, -+ &fops_sc_quirks); -+ debugfs_create_file("quirks_tiler", 0644, -+ kbdev->mali_debugfs_directory, kbdev, -+ &fops_tiler_quirks); -+ debugfs_create_file("quirks_mmu", 0644, -+ kbdev->mali_debugfs_directory, kbdev, -+ &fops_mmu_quirks); -+ debugfs_create_file("quirks_jm", 0644, -+ kbdev->mali_debugfs_directory, kbdev, -+ &fops_jm_quirks); -+#endif /* KBASE_GPU_RESET_EN */ -+ -+ debugfs_create_bool("infinite_cache", 0644, -+ debugfs_ctx_defaults_directory, -+ &kbdev->infinite_cache_active_default); -+ -+ debugfs_create_size_t("mem_pool_max_size", 0644, -+ debugfs_ctx_defaults_directory, -+ &kbdev->mem_pool_max_size_default); -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_DEBUG_MODE)) { -+ debugfs_create_file("protected_debug_mode", S_IRUGO, -+ kbdev->mali_debugfs_directory, kbdev, -+ &fops_protected_debug_mode); -+ } -+ -+#if KBASE_TRACE_ENABLE -+ kbasep_trace_debugfs_init(kbdev); -+#endif /* KBASE_TRACE_ENABLE */ -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+ kbasep_trace_timeline_debugfs_init(kbdev); -+#endif /* CONFIG_MALI_TRACE_TIMELINE */ -+ -+#ifdef CONFIG_MALI_DEVFREQ -+#ifdef CONFIG_DEVFREQ_THERMAL -+ if (kbdev->inited_subsys & inited_devfreq) -+ kbase_ipa_debugfs_init(kbdev); -+#endif /* CONFIG_DEVFREQ_THERMAL */ -+#endif /* CONFIG_MALI_DEVFREQ */ -+ -+#ifdef CONFIG_DEBUG_FS -+ debugfs_create_file("serialize_jobs", S_IRUGO | S_IWUSR, -+ kbdev->mali_debugfs_directory, kbdev, -+ &kbasep_serialize_jobs_debugfs_fops); -+#endif /* CONFIG_DEBUG_FS */ -+ -+ return 0; -+ -+out: -+ debugfs_remove_recursive(kbdev->mali_debugfs_directory); -+ return err; -+} -+ -+static void kbase_device_debugfs_term(struct kbase_device *kbdev) -+{ -+ debugfs_remove_recursive(kbdev->mali_debugfs_directory); -+} -+ -+#else /* CONFIG_DEBUG_FS */ -+static inline int kbase_device_debugfs_init(struct kbase_device *kbdev) -+{ -+ return 0; -+} -+ -+static inline void kbase_device_debugfs_term(struct kbase_device *kbdev) { } -+#endif /* CONFIG_DEBUG_FS */ -+ -+static void kbase_device_coherency_init(struct kbase_device *kbdev, -+ unsigned prod_id) -+{ -+#ifdef CONFIG_OF -+ u32 supported_coherency_bitmap = -+ kbdev->gpu_props.props.raw_props.coherency_mode; -+ const void *coherency_override_dts; -+ u32 override_coherency; -+ -+ /* Only for tMIx : -+ * (COHERENCY_ACE_LITE | COHERENCY_ACE) was incorrectly -+ * documented for tMIx so force correct value here. -+ */ -+ if (GPU_ID_IS_NEW_FORMAT(prod_id) && -+ (GPU_ID2_MODEL_MATCH_VALUE(prod_id) == -+ GPU_ID2_PRODUCT_TMIX)) -+ if (supported_coherency_bitmap == -+ COHERENCY_FEATURE_BIT(COHERENCY_ACE)) -+ supported_coherency_bitmap |= -+ COHERENCY_FEATURE_BIT(COHERENCY_ACE_LITE); -+ -+#endif /* CONFIG_OF */ -+ -+ kbdev->system_coherency = COHERENCY_NONE; -+ -+ /* device tree may override the coherency */ -+#ifdef CONFIG_OF -+ coherency_override_dts = of_get_property(kbdev->dev->of_node, -+ "system-coherency", -+ NULL); -+ if (coherency_override_dts) { -+ -+ override_coherency = be32_to_cpup(coherency_override_dts); -+ -+ if ((override_coherency <= COHERENCY_NONE) && -+ (supported_coherency_bitmap & -+ COHERENCY_FEATURE_BIT(override_coherency))) { -+ -+ kbdev->system_coherency = override_coherency; -+ -+ dev_info(kbdev->dev, -+ "Using coherency mode %u set from dtb", -+ override_coherency); -+ } else -+ dev_warn(kbdev->dev, -+ "Ignoring unsupported coherency mode %u set from dtb", -+ override_coherency); -+ } -+ -+#endif /* CONFIG_OF */ -+ -+ kbdev->gpu_props.props.raw_props.coherency_mode = -+ kbdev->system_coherency; -+} -+ -+#ifdef CONFIG_MALI_FPGA_BUS_LOGGER -+ -+/* Callback used by the kbase bus logger client, to initiate a GPU reset -+ * when the bus log is restarted. GPU reset is used as reference point -+ * in HW bus log analyses. -+ */ -+static void kbase_logging_started_cb(void *data) -+{ -+ struct kbase_device *kbdev = (struct kbase_device *)data; -+ -+ if (kbase_prepare_to_reset_gpu(kbdev)) -+ kbase_reset_gpu(kbdev); -+ dev_info(kbdev->dev, "KBASE - Bus logger restarted\n"); -+} -+#endif -+ -+static struct attribute *kbase_attrs[] = { -+#ifdef CONFIG_MALI_DEBUG -+ &dev_attr_debug_command.attr, -+ &dev_attr_js_softstop_always.attr, -+#endif -+#if !MALI_CUSTOMER_RELEASE -+ &dev_attr_force_replay.attr, -+#endif -+ &dev_attr_js_timeouts.attr, -+ &dev_attr_soft_job_timeout.attr, -+ &dev_attr_gpuinfo.attr, -+ &dev_attr_dvfs_period.attr, -+ &dev_attr_pm_poweroff.attr, -+ &dev_attr_reset_timeout.attr, -+ &dev_attr_js_scheduling_period.attr, -+ &dev_attr_power_policy.attr, -+ &dev_attr_core_availability_policy.attr, -+ &dev_attr_core_mask.attr, -+ &dev_attr_mem_pool_size.attr, -+ &dev_attr_mem_pool_max_size.attr, -+ NULL -+}; -+ -+static const struct attribute_group kbase_attr_group = { -+ .attrs = kbase_attrs, -+}; -+ -+static int kbase_platform_device_remove(struct platform_device *pdev) -+{ -+ struct kbase_device *kbdev = to_kbase_device(&pdev->dev); -+ const struct list_head *dev_list; -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ kfree(kbdev->gpu_props.prop_buffer); -+ -+#ifdef CONFIG_MALI_FPGA_BUS_LOGGER -+ if (kbdev->inited_subsys & inited_buslogger) { -+ bl_core_client_unregister(kbdev->buslogger); -+ kbdev->inited_subsys &= ~inited_buslogger; -+ } -+#endif -+ -+ -+ if (kbdev->inited_subsys & inited_dev_list) { -+ dev_list = kbase_dev_list_get(); -+ list_del(&kbdev->entry); -+ kbase_dev_list_put(dev_list); -+ kbdev->inited_subsys &= ~inited_dev_list; -+ } -+ -+ if (kbdev->inited_subsys & inited_misc_register) { -+ misc_deregister(&kbdev->mdev); -+ kbdev->inited_subsys &= ~inited_misc_register; -+ } -+ -+ if (kbdev->inited_subsys & inited_sysfs_group) { -+ sysfs_remove_group(&kbdev->dev->kobj, &kbase_attr_group); -+ kbdev->inited_subsys &= ~inited_sysfs_group; -+ } -+ -+ if (kbdev->inited_subsys & inited_get_device) { -+ put_device(kbdev->dev); -+ kbdev->inited_subsys &= ~inited_get_device; -+ } -+ -+ if (kbdev->inited_subsys & inited_debugfs) { -+ kbase_device_debugfs_term(kbdev); -+ kbdev->inited_subsys &= ~inited_debugfs; -+ } -+ -+ if (kbdev->inited_subsys & inited_job_fault) { -+ kbase_debug_job_fault_dev_term(kbdev); -+ kbdev->inited_subsys &= ~inited_job_fault; -+ } -+ if (kbdev->inited_subsys & inited_vinstr) { -+ kbase_vinstr_term(kbdev->vinstr_ctx); -+ kbdev->inited_subsys &= ~inited_vinstr; -+ } -+ -+#ifdef CONFIG_MALI_DEVFREQ -+ if (kbdev->inited_subsys & inited_devfreq) { -+ kbase_devfreq_term(kbdev); -+ kbdev->inited_subsys &= ~inited_devfreq; -+ } -+#endif -+ -+ if (kbdev->inited_subsys & inited_backend_late) { -+ kbase_backend_late_term(kbdev); -+ kbdev->inited_subsys &= ~inited_backend_late; -+ } -+ -+ if (kbdev->inited_subsys & inited_tlstream) { -+ kbase_tlstream_term(); -+ kbdev->inited_subsys &= ~inited_tlstream; -+ } -+ -+ /* Bring job and mem sys to a halt before we continue termination */ -+ -+ if (kbdev->inited_subsys & inited_js) -+ kbasep_js_devdata_halt(kbdev); -+ -+ if (kbdev->inited_subsys & inited_mem) -+ kbase_mem_halt(kbdev); -+ -+ if (kbdev->inited_subsys & inited_protected) { -+ kbasep_protected_mode_term(kbdev); -+ kbdev->inited_subsys &= ~inited_protected; -+ } -+ -+ if (kbdev->inited_subsys & inited_js) { -+ kbasep_js_devdata_term(kbdev); -+ kbdev->inited_subsys &= ~inited_js; -+ } -+ -+ if (kbdev->inited_subsys & inited_mem) { -+ kbase_mem_term(kbdev); -+ kbdev->inited_subsys &= ~inited_mem; -+ } -+ -+ if (kbdev->inited_subsys & inited_pm_runtime_init) { -+ kbdev->pm.callback_power_runtime_term(kbdev); -+ kbdev->inited_subsys &= ~inited_pm_runtime_init; -+ } -+ -+ if (kbdev->inited_subsys & inited_ctx_sched) { -+ kbase_ctx_sched_term(kbdev); -+ kbdev->inited_subsys &= ~inited_ctx_sched; -+ } -+ -+ if (kbdev->inited_subsys & inited_device) { -+ kbase_device_term(kbdev); -+ kbdev->inited_subsys &= ~inited_device; -+ } -+ -+ if (kbdev->inited_subsys & inited_backend_early) { -+ kbase_backend_early_term(kbdev); -+ kbdev->inited_subsys &= ~inited_backend_early; -+ } -+ -+ if (kbdev->inited_subsys & inited_io_history) { -+ kbase_io_history_term(&kbdev->io_history); -+ kbdev->inited_subsys &= ~inited_io_history; -+ } -+ -+ if (kbdev->inited_subsys & inited_power_control) { -+ power_control_term(kbdev); -+ kbdev->inited_subsys &= ~inited_power_control; -+ } -+ -+ if (kbdev->inited_subsys & inited_registers_map) { -+ registers_unmap(kbdev); -+ kbdev->inited_subsys &= ~inited_registers_map; -+ } -+ -+#ifdef CONFIG_MALI_NO_MALI -+ if (kbdev->inited_subsys & inited_gpu_device) { -+ gpu_device_destroy(kbdev); -+ kbdev->inited_subsys &= ~inited_gpu_device; -+ } -+#endif /* CONFIG_MALI_NO_MALI */ -+ -+ if (kbdev->inited_subsys != 0) -+ dev_err(kbdev->dev, "Missing sub system termination\n"); -+ -+ kbase_device_free(kbdev); -+ -+ return 0; -+} -+ -+ -+/* Number of register accesses for the buffer that we allocate during -+ * initialization time. The buffer size can be changed later via debugfs. */ -+#define KBASEP_DEFAULT_REGISTER_HISTORY_SIZE ((u16)512) -+ -+static int kbase_platform_device_probe(struct platform_device *pdev) -+{ -+ struct kbase_device *kbdev; -+ struct mali_base_gpu_core_props *core_props; -+ u32 gpu_id; -+ unsigned prod_id; -+ const struct list_head *dev_list; -+ int err = 0; -+ -+#ifdef CONFIG_OF -+ err = kbase_platform_early_init(); -+ if (err) { -+ dev_err(&pdev->dev, "Early platform initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+#endif -+ kbdev = kbase_device_alloc(); -+ if (!kbdev) { -+ dev_err(&pdev->dev, "Allocate device failed\n"); -+ kbase_platform_device_remove(pdev); -+ return -ENOMEM; -+ } -+ -+ kbdev->dev = &pdev->dev; -+ dev_set_drvdata(kbdev->dev, kbdev); -+ -+#ifdef CONFIG_MALI_NO_MALI -+ err = gpu_device_create(kbdev); -+ if (err) { -+ dev_err(&pdev->dev, "Dummy model initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_gpu_device; -+#endif /* CONFIG_MALI_NO_MALI */ -+ -+ err = assign_irqs(pdev); -+ if (err) { -+ dev_err(&pdev->dev, "IRQ search failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ -+ err = registers_map(kbdev); -+ if (err) { -+ dev_err(&pdev->dev, "Register map failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_registers_map; -+ -+ err = power_control_init(pdev); -+ if (err) { -+ dev_err(&pdev->dev, "Power control initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_power_control; -+ -+ err = kbase_io_history_init(&kbdev->io_history, -+ KBASEP_DEFAULT_REGISTER_HISTORY_SIZE); -+ if (err) { -+ dev_err(&pdev->dev, "Register access history initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return -ENOMEM; -+ } -+ kbdev->inited_subsys |= inited_io_history; -+ -+ err = kbase_backend_early_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Early backend initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_backend_early; -+ -+ scnprintf(kbdev->devname, DEVNAME_SIZE, "%s%d", kbase_drv_name, -+ kbase_dev_nr); -+ -+ kbase_disjoint_init(kbdev); -+ -+ /* obtain min/max configured gpu frequencies */ -+ core_props = &(kbdev->gpu_props.props.core_props); -+ core_props->gpu_freq_khz_min = GPU_FREQ_KHZ_MIN; -+ core_props->gpu_freq_khz_max = GPU_FREQ_KHZ_MAX; -+ -+ err = kbase_device_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Device initialization failed (%d)\n", err); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_device; -+ -+ err = kbase_ctx_sched_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Context scheduler initialization failed (%d)\n", -+ err); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_ctx_sched; -+ -+ if (kbdev->pm.callback_power_runtime_init) { -+ err = kbdev->pm.callback_power_runtime_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, -+ "Runtime PM initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_pm_runtime_init; -+ } -+ -+ err = kbase_mem_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Memory subsystem initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_mem; -+ -+ gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ gpu_id &= GPU_ID_VERSION_PRODUCT_ID; -+ prod_id = gpu_id >> GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ -+ kbase_device_coherency_init(kbdev, prod_id); -+ -+ err = kbasep_protected_mode_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Protected mode subsystem initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_protected; -+ -+ dev_list = kbase_dev_list_get(); -+ list_add(&kbdev->entry, &kbase_dev_list); -+ kbase_dev_list_put(dev_list); -+ kbdev->inited_subsys |= inited_dev_list; -+ -+ err = kbasep_js_devdata_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Job JS devdata initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_js; -+ -+ err = kbase_tlstream_init(); -+ if (err) { -+ dev_err(kbdev->dev, "Timeline stream initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_tlstream; -+ -+ err = kbase_backend_late_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Late backend initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_backend_late; -+ -+ /* Initialize the kctx list. This is used by vinstr. */ -+ mutex_init(&kbdev->kctx_list_lock); -+ INIT_LIST_HEAD(&kbdev->kctx_list); -+ -+ kbdev->vinstr_ctx = kbase_vinstr_init(kbdev); -+ if (!kbdev->vinstr_ctx) { -+ dev_err(kbdev->dev, -+ "Virtual instrumentation initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return -EINVAL; -+ } -+ kbdev->inited_subsys |= inited_vinstr; -+ -+#ifdef CONFIG_MALI_DEVFREQ -+ /* Devfreq uses vinstr, so must be initialized after it. */ -+ err = kbase_devfreq_init(kbdev); -+ if (!err) -+ kbdev->inited_subsys |= inited_devfreq; -+ else -+ dev_err(kbdev->dev, "Continuing without devfreq\n"); -+#endif /* CONFIG_MALI_DEVFREQ */ -+ -+ err = kbase_debug_job_fault_dev_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "Job fault debug initialization failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_job_fault; -+ -+ err = kbase_device_debugfs_init(kbdev); -+ if (err) { -+ dev_err(kbdev->dev, "DebugFS initialization failed"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_debugfs; -+ -+ kbdev->mdev.minor = MISC_DYNAMIC_MINOR; -+ kbdev->mdev.name = kbdev->devname; -+ kbdev->mdev.fops = &kbase_fops; -+ kbdev->mdev.parent = get_device(kbdev->dev); -+ kbdev->inited_subsys |= inited_get_device; -+ -+ /* This needs to happen before registering the device with misc_register(), -+ * otherwise it causes a race condition between registering the device and a -+ * uevent event being generated for userspace, causing udev rules to run -+ * which might expect certain sysfs attributes present. As a result of the -+ * race condition we avoid, some Mali sysfs entries may have appeared to -+ * udev to not exist. -+ -+ * For more information, see -+ * https://www.kernel.org/doc/Documentation/driver-model/device.txt, the -+ * paragraph that starts with "Word of warning", currently the second-last -+ * paragraph. -+ */ -+ err = sysfs_create_group(&kbdev->dev->kobj, &kbase_attr_group); -+ if (err) { -+ dev_err(&pdev->dev, "SysFS group creation failed\n"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_sysfs_group; -+ -+ err = misc_register(&kbdev->mdev); -+ if (err) { -+ dev_err(kbdev->dev, "Misc device registration failed for %s\n", -+ kbdev->devname); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ kbdev->inited_subsys |= inited_misc_register; -+ -+ -+#ifdef CONFIG_MALI_FPGA_BUS_LOGGER -+ err = bl_core_client_register(kbdev->devname, -+ kbase_logging_started_cb, -+ kbdev, &kbdev->buslogger, -+ THIS_MODULE, NULL); -+ if (err == 0) { -+ kbdev->inited_subsys |= inited_buslogger; -+ bl_core_set_threshold(kbdev->buslogger, 1024*1024*1024); -+ } else { -+ dev_warn(kbdev->dev, "Bus log client registration failed\n"); -+ err = 0; -+ } -+#endif -+ -+ err = kbase_gpuprops_populate_user_buffer(kbdev); -+ if (err) { -+ dev_err(&pdev->dev, "GPU property population failed"); -+ kbase_platform_device_remove(pdev); -+ return err; -+ } -+ -+ dev_info(kbdev->dev, -+ "Probed as %s\n", dev_name(kbdev->mdev.this_device)); -+ -+ kbase_dev_nr++; -+ -+ return err; -+} -+ -+#undef KBASEP_DEFAULT_REGISTER_HISTORY_SIZE -+ -+/** -+ * kbase_device_suspend - Suspend callback from the OS. -+ * -+ * This is called by Linux when the device should suspend. -+ * -+ * @dev: The device to suspend -+ * -+ * Return: A standard Linux error code -+ */ -+static int kbase_device_suspend(struct device *dev) -+{ -+ struct kbase_device *kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+#if defined(CONFIG_MALI_DEVFREQ) && \ -+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -+ if (kbdev->inited_subsys & inited_devfreq) -+ devfreq_suspend_device(kbdev->devfreq); -+#endif -+ -+ kbase_pm_suspend(kbdev); -+ return 0; -+} -+ -+/** -+ * kbase_device_resume - Resume callback from the OS. -+ * -+ * This is called by Linux when the device should resume from suspension. -+ * -+ * @dev: The device to resume -+ * -+ * Return: A standard Linux error code -+ */ -+static int kbase_device_resume(struct device *dev) -+{ -+ struct kbase_device *kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ kbase_pm_resume(kbdev); -+ -+#if defined(CONFIG_MALI_DEVFREQ) && \ -+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -+ if (kbdev->inited_subsys & inited_devfreq) -+ devfreq_resume_device(kbdev->devfreq); -+#endif -+ return 0; -+} -+ -+/** -+ * kbase_device_runtime_suspend - Runtime suspend callback from the OS. -+ * -+ * This is called by Linux when the device should prepare for a condition in -+ * which it will not be able to communicate with the CPU(s) and RAM due to -+ * power management. -+ * -+ * @dev: The device to suspend -+ * -+ * Return: A standard Linux error code -+ */ -+#ifdef KBASE_PM_RUNTIME -+static int kbase_device_runtime_suspend(struct device *dev) -+{ -+ struct kbase_device *kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+#if defined(CONFIG_MALI_DEVFREQ) && \ -+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -+ if (kbdev->inited_subsys & inited_devfreq) -+ devfreq_suspend_device(kbdev->devfreq); -+#endif -+ -+ if (kbdev->pm.backend.callback_power_runtime_off) { -+ kbdev->pm.backend.callback_power_runtime_off(kbdev); -+ dev_dbg(dev, "runtime suspend\n"); -+ } -+ return 0; -+} -+#endif /* KBASE_PM_RUNTIME */ -+ -+/** -+ * kbase_device_runtime_resume - Runtime resume callback from the OS. -+ * -+ * This is called by Linux when the device should go into a fully active state. -+ * -+ * @dev: The device to suspend -+ * -+ * Return: A standard Linux error code -+ */ -+ -+#ifdef KBASE_PM_RUNTIME -+static int kbase_device_runtime_resume(struct device *dev) -+{ -+ int ret = 0; -+ struct kbase_device *kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ if (kbdev->pm.backend.callback_power_runtime_on) { -+ ret = kbdev->pm.backend.callback_power_runtime_on(kbdev); -+ dev_dbg(dev, "runtime resume\n"); -+ } -+ -+#if defined(CONFIG_MALI_DEVFREQ) && \ -+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) -+ if (kbdev->inited_subsys & inited_devfreq) -+ devfreq_resume_device(kbdev->devfreq); -+#endif -+ -+ return ret; -+} -+#endif /* KBASE_PM_RUNTIME */ -+ -+ -+#ifdef KBASE_PM_RUNTIME -+/** -+ * kbase_device_runtime_idle - Runtime idle callback from the OS. -+ * @dev: The device to suspend -+ * -+ * This is called by Linux when the device appears to be inactive and it might -+ * be placed into a low power state. -+ * -+ * Return: 0 if device can be suspended, non-zero to avoid runtime autosuspend, -+ * otherwise a standard Linux error code -+ */ -+static int kbase_device_runtime_idle(struct device *dev) -+{ -+ struct kbase_device *kbdev = to_kbase_device(dev); -+ -+ if (!kbdev) -+ return -ENODEV; -+ -+ /* Use platform specific implementation if it exists. */ -+ if (kbdev->pm.backend.callback_power_runtime_idle) -+ return kbdev->pm.backend.callback_power_runtime_idle(kbdev); -+ -+ return 0; -+} -+#endif /* KBASE_PM_RUNTIME */ -+ -+/* The power management operations for the platform driver. -+ */ -+static const struct dev_pm_ops kbase_pm_ops = { -+ .suspend = kbase_device_suspend, -+ .resume = kbase_device_resume, -+#ifdef KBASE_PM_RUNTIME -+ .runtime_suspend = kbase_device_runtime_suspend, -+ .runtime_resume = kbase_device_runtime_resume, -+ .runtime_idle = kbase_device_runtime_idle, -+#endif /* KBASE_PM_RUNTIME */ -+}; -+ -+#ifdef CONFIG_OF -+static const struct of_device_id kbase_dt_ids[] = { -+ { .compatible = "arm,malit6xx" }, -+ { .compatible = "arm,mali-midgard" }, -+ { /* sentinel */ } -+}; -+MODULE_DEVICE_TABLE(of, kbase_dt_ids); -+#endif -+ -+static struct platform_driver kbase_platform_driver = { -+ .probe = kbase_platform_device_probe, -+ .remove = kbase_platform_device_remove, -+ .driver = { -+ .name = kbase_drv_name, -+ .owner = THIS_MODULE, -+ .pm = &kbase_pm_ops, -+ .of_match_table = of_match_ptr(kbase_dt_ids), -+ }, -+}; -+ -+/* -+ * The driver will not provide a shortcut to create the Mali platform device -+ * anymore when using Device Tree. -+ */ -+#ifdef CONFIG_OF -+module_platform_driver(kbase_platform_driver); -+#else -+ -+static int __init kbase_driver_init(void) -+{ -+ int ret; -+ -+ ret = kbase_platform_early_init(); -+ if (ret) -+ return ret; -+ -+#ifdef CONFIG_MALI_PLATFORM_FAKE -+ ret = kbase_platform_fake_register(); -+ if (ret) -+ return ret; -+#endif -+ ret = platform_driver_register(&kbase_platform_driver); -+#ifdef CONFIG_MALI_PLATFORM_FAKE -+ if (ret) -+ kbase_platform_fake_unregister(); -+#endif -+ return ret; -+} -+ -+static void __exit kbase_driver_exit(void) -+{ -+ platform_driver_unregister(&kbase_platform_driver); -+#ifdef CONFIG_MALI_PLATFORM_FAKE -+ kbase_platform_fake_unregister(); -+#endif -+} -+ -+module_init(kbase_driver_init); -+module_exit(kbase_driver_exit); -+ -+#endif /* CONFIG_OF */ -+ -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(MALI_RELEASE_NAME " (UK version " \ -+ __stringify(BASE_UK_VERSION_MAJOR) "." \ -+ __stringify(BASE_UK_VERSION_MINOR) ")"); -+ -+#if defined(CONFIG_MALI_GATOR_SUPPORT) || defined(CONFIG_MALI_SYSTEM_TRACE) -+#define CREATE_TRACE_POINTS -+#endif -+ -+#ifdef CONFIG_MALI_GATOR_SUPPORT -+/* Create the trace points (otherwise we just get code to call a tracepoint) */ -+#include "mali_linux_trace.h" -+ -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_job_slots_event); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_pm_status); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_pm_power_on); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_pm_power_off); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_page_fault_insert_pages); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_mmu_as_in_use); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_mmu_as_released); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_total_alloc_pages_change); -+ -+void kbase_trace_mali_pm_status(u32 event, u64 value) -+{ -+ trace_mali_pm_status(event, value); -+} -+ -+void kbase_trace_mali_pm_power_off(u32 event, u64 value) -+{ -+ trace_mali_pm_power_off(event, value); -+} -+ -+void kbase_trace_mali_pm_power_on(u32 event, u64 value) -+{ -+ trace_mali_pm_power_on(event, value); -+} -+ -+void kbase_trace_mali_job_slots_event(u32 event, const struct kbase_context *kctx, u8 atom_id) -+{ -+ trace_mali_job_slots_event(event, (kctx != NULL ? kctx->tgid : 0), (kctx != NULL ? kctx->pid : 0), atom_id); -+} -+ -+void kbase_trace_mali_page_fault_insert_pages(int event, u32 value) -+{ -+ trace_mali_page_fault_insert_pages(event, value); -+} -+ -+void kbase_trace_mali_mmu_as_in_use(int event) -+{ -+ trace_mali_mmu_as_in_use(event); -+} -+ -+void kbase_trace_mali_mmu_as_released(int event) -+{ -+ trace_mali_mmu_as_released(event); -+} -+ -+void kbase_trace_mali_total_alloc_pages_change(long long int event) -+{ -+ trace_mali_total_alloc_pages_change(event); -+} -+#endif /* CONFIG_MALI_GATOR_SUPPORT */ -+#ifdef CONFIG_MALI_SYSTEM_TRACE -+#include "mali_linux_kbase_trace.h" -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_ctx_sched.c b/drivers/gpu/arm/midgard/mali_kbase_ctx_sched.c -new file mode 100644 -index 0000000..e2f7baa ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_ctx_sched.c -@@ -0,0 +1,203 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+ -+#include "mali_kbase_ctx_sched.h" -+ -+int kbase_ctx_sched_init(struct kbase_device *kbdev) -+{ -+ int as_present = (1U << kbdev->nr_hw_address_spaces) - 1; -+ -+ /* These two must be recalculated if nr_hw_address_spaces changes -+ * (e.g. for HW workarounds) */ -+ kbdev->nr_user_address_spaces = kbdev->nr_hw_address_spaces; -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987)) { -+ bool use_workaround; -+ -+ use_workaround = DEFAULT_SECURE_BUT_LOSS_OF_PERFORMANCE; -+ if (use_workaround) { -+ dev_dbg(kbdev->dev, "GPU has HW ISSUE 8987, and driver configured for security workaround: 1 address space only"); -+ kbdev->nr_user_address_spaces = 1; -+ } -+ } -+ -+ kbdev->as_free = as_present; /* All ASs initially free */ -+ -+ memset(kbdev->as_to_kctx, 0, sizeof(kbdev->as_to_kctx)); -+ -+ return 0; -+} -+ -+void kbase_ctx_sched_term(struct kbase_device *kbdev) -+{ -+ s8 i; -+ -+ /* Sanity checks */ -+ for (i = 0; i != kbdev->nr_hw_address_spaces; ++i) { -+ WARN_ON(kbdev->as_to_kctx[i] != NULL); -+ WARN_ON(!(kbdev->as_free & (1u << i))); -+ } -+} -+ -+/* kbasep_ctx_sched_find_as_for_ctx - Find a free address space -+ * -+ * @kbdev: The context for which to find a free address space -+ * -+ * Return: A valid AS if successful, otherwise KBASEP_AS_NR_INVALID -+ * -+ * This function returns an address space available for use. It would prefer -+ * returning an AS that has been previously assigned to the context to -+ * avoid having to reprogram the MMU. -+ */ -+static int kbasep_ctx_sched_find_as_for_ctx(struct kbase_context *kctx) -+{ -+ struct kbase_device *const kbdev = kctx->kbdev; -+ int free_as; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ /* First check if the previously assigned AS is available */ -+ if ((kctx->as_nr != KBASEP_AS_NR_INVALID) && -+ (kbdev->as_free & (1u << kctx->as_nr))) -+ return kctx->as_nr; -+ -+ /* The previously assigned AS was taken, we'll be returning any free -+ * AS at this point. -+ */ -+ free_as = ffs(kbdev->as_free) - 1; -+ if (free_as >= 0 && free_as < kbdev->nr_hw_address_spaces) -+ return free_as; -+ -+ return KBASEP_AS_NR_INVALID; -+} -+ -+int kbase_ctx_sched_retain_ctx(struct kbase_context *kctx) -+{ -+ struct kbase_device *const kbdev = kctx->kbdev; -+ -+ lockdep_assert_held(&kbdev->mmu_hw_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ WARN_ON(!kbdev->pm.backend.gpu_powered); -+ -+ if (atomic_inc_return(&kctx->refcount) == 1) { -+ int const free_as = kbasep_ctx_sched_find_as_for_ctx(kctx); -+ -+ if (free_as != KBASEP_AS_NR_INVALID) { -+ kbdev->as_free &= ~(1u << free_as); -+ /* Only program the MMU if the context has not been -+ * assigned the same address space before. -+ */ -+ if (free_as != kctx->as_nr) { -+ struct kbase_context *const prev_kctx = -+ kbdev->as_to_kctx[free_as]; -+ -+ if (prev_kctx) { -+ WARN_ON(atomic_read(&prev_kctx->refcount) != 0); -+ kbase_mmu_disable(prev_kctx); -+ prev_kctx->as_nr = KBASEP_AS_NR_INVALID; -+ } -+ -+ kctx->as_nr = free_as; -+ kbdev->as_to_kctx[free_as] = kctx; -+ kbase_mmu_update(kctx); -+ } -+ } else { -+ atomic_dec(&kctx->refcount); -+ -+ /* Failed to find an available address space, we must -+ * be returning an error at this point. -+ */ -+ WARN_ON(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ } -+ } -+ -+ return kctx->as_nr; -+} -+ -+void kbase_ctx_sched_retain_ctx_refcount(struct kbase_context *kctx) -+{ -+ struct kbase_device *const kbdev = kctx->kbdev; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ WARN_ON(atomic_read(&kctx->refcount) == 0); -+ WARN_ON(kctx->as_nr == KBASEP_AS_NR_INVALID); -+ WARN_ON(kbdev->as_to_kctx[kctx->as_nr] != kctx); -+ -+ atomic_inc(&kctx->refcount); -+} -+ -+void kbase_ctx_sched_release_ctx(struct kbase_context *kctx) -+{ -+ struct kbase_device *const kbdev = kctx->kbdev; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (atomic_dec_return(&kctx->refcount) == 0) -+ kbdev->as_free |= (1u << kctx->as_nr); -+} -+ -+void kbase_ctx_sched_remove_ctx(struct kbase_context *kctx) -+{ -+ struct kbase_device *const kbdev = kctx->kbdev; -+ -+ lockdep_assert_held(&kbdev->mmu_hw_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ WARN_ON(atomic_read(&kctx->refcount) != 0); -+ -+ if (kctx->as_nr != KBASEP_AS_NR_INVALID) { -+ if (kbdev->pm.backend.gpu_powered) -+ kbase_mmu_disable(kctx); -+ -+ kbdev->as_to_kctx[kctx->as_nr] = NULL; -+ kctx->as_nr = KBASEP_AS_NR_INVALID; -+ } -+} -+ -+void kbase_ctx_sched_restore_all_as(struct kbase_device *kbdev) -+{ -+ s8 i; -+ -+ lockdep_assert_held(&kbdev->mmu_hw_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ WARN_ON(!kbdev->pm.backend.gpu_powered); -+ -+ for (i = 0; i != kbdev->nr_hw_address_spaces; ++i) { -+ struct kbase_context *kctx; -+ -+ kctx = kbdev->as_to_kctx[i]; -+ if (kctx) { -+ if (atomic_read(&kctx->refcount)) { -+ WARN_ON(kctx->as_nr != i); -+ -+ kbase_mmu_update(kctx); -+ } else { -+ /* This context might have been assigned an -+ * AS before, clear it. -+ */ -+ kbdev->as_to_kctx[kctx->as_nr] = NULL; -+ kctx->as_nr = KBASEP_AS_NR_INVALID; -+ } -+ } else { -+ kbase_mmu_disable_as(kbdev, i); -+ } -+ } -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_ctx_sched.h b/drivers/gpu/arm/midgard/mali_kbase_ctx_sched.h -new file mode 100644 -index 0000000..e551525 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_ctx_sched.h -@@ -0,0 +1,131 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_CTX_SCHED_H_ -+#define _KBASE_CTX_SCHED_H_ -+ -+#include -+ -+/* The Context Scheduler manages address space assignment and reference -+ * counting to kbase_context. The interface has been designed to minimise -+ * interactions between the Job Scheduler and Power Management/MMU to support -+ * both the existing Job Scheduler and Command Stream Frontend interface. -+ * -+ * The initial implementation of the Context Scheduler does not schedule -+ * contexts. Instead it relies on the Job Scheduler/CSF to make decisions of -+ * when to schedule/evict contexts if address spaces are starved. In the -+ * future, once an interface between the CS and JS/CSF have been devised to -+ * provide enough information about how each context is consuming GPU resources, -+ * those decisions can be made in the CS itself, thereby reducing duplicated -+ * code. -+ */ -+ -+/* base_ctx_sched_init - Initialise the context scheduler -+ * -+ * @kbdev: The device for which the context scheduler needs to be -+ * initialised -+ * -+ * Return: 0 for success, otherwise failure -+ * -+ * This must be called during device initilisation. The number of hardware -+ * address spaces must already be established before calling this function. -+ */ -+int kbase_ctx_sched_init(struct kbase_device *kbdev); -+ -+/* base_ctx_sched_term - Terminate the context scheduler -+ * -+ * @kbdev: The device for which the context scheduler needs to be -+ * terminated -+ * -+ * This must be called during device termination after all contexts have been -+ * destroyed. -+ */ -+void kbase_ctx_sched_term(struct kbase_device *kbdev); -+ -+/* kbase_ctx_sched_retain_ctx - Retain a reference to the @ref kbase_context -+ * -+ * @kctx: The context to which to retain a reference -+ * -+ * Return: The address space that the context has been assigned to or -+ * KBASEP_AS_NR_INVALID if no address space was available. -+ * -+ * This function should be called whenever an address space should be assigned -+ * to a context and programmed onto the MMU. It should typically be called -+ * when jobs are ready to be submitted to the GPU. -+ * -+ * It can be called as many times as necessary. The address space will be -+ * assigned to the context for as long as there is a reference to said context. -+ * -+ * The kbase_device::mmu_hw_mutex and kbase_device::hwaccess_lock locks must be -+ * held whilst calling this function. -+ */ -+int kbase_ctx_sched_retain_ctx(struct kbase_context *kctx); -+ -+/* kbase_ctx_sched_retain_ctx_refcount -+ * -+ * @kctx: The context to which to retain a reference -+ * -+ * This function only retains a reference to the context. It must be called -+ * only when the context already has a reference. -+ * -+ * This is typically called inside an atomic session where we know the context -+ * is already scheduled in but want to take an extra reference to ensure that -+ * it doesn't get descheduled. -+ * -+ * The kbase_device::hwaccess_lock must be held whilst calling this function -+ */ -+void kbase_ctx_sched_retain_ctx_refcount(struct kbase_context *kctx); -+ -+/* kbase_ctx_sched_release_ctx - Release a reference to the @ref kbase_context -+ * -+ * @kctx: The context from which to release a reference -+ * -+ * This function should be called whenever an address space could be unassigned -+ * from a context. When there are no more references to said context, the -+ * address space previously assigned to this context shall be reassigned to -+ * other contexts as needed. -+ * -+ * The kbase_device::hwaccess_lock must be held whilst calling this function -+ */ -+void kbase_ctx_sched_release_ctx(struct kbase_context *kctx); -+ -+/* kbase_ctx_sched_remove_ctx - Unassign previously assigned address space -+ * -+ * @kctx: The context to be removed -+ * -+ * This function should be called when a context is being destroyed. The -+ * context must no longer have any reference. If it has been assigned an -+ * address space before then the AS will be unprogrammed. -+ * -+ * The kbase_device::mmu_hw_mutex and kbase_device::hwaccess_lock locks must be -+ * held whilst calling this function. -+ */ -+void kbase_ctx_sched_remove_ctx(struct kbase_context *kctx); -+ -+/* kbase_ctx_sched_restore_all_as - Reprogram all address spaces -+ * -+ * @kbdev: The device for which address spaces to be reprogrammed -+ * -+ * This function shall reprogram all address spaces previously assigned to -+ * contexts. It can be used after the GPU is reset. -+ * -+ * The kbase_device::mmu_hw_mutex and kbase_device::hwaccess_lock locks must be -+ * held whilst calling this function. -+ */ -+void kbase_ctx_sched_restore_all_as(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_CTX_SCHED_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_debug.c b/drivers/gpu/arm/midgard/mali_kbase_debug.c -new file mode 100644 -index 0000000..fb57ac2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_debug.c -@@ -0,0 +1,39 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+ -+static struct kbasep_debug_assert_cb kbasep_debug_assert_registered_cb = { -+ NULL, -+ NULL -+}; -+ -+void kbase_debug_assert_register_hook(kbase_debug_assert_hook *func, void *param) -+{ -+ kbasep_debug_assert_registered_cb.func = func; -+ kbasep_debug_assert_registered_cb.param = param; -+} -+ -+void kbasep_debug_assert_call_hook(void) -+{ -+ if (kbasep_debug_assert_registered_cb.func != NULL) -+ kbasep_debug_assert_registered_cb.func(kbasep_debug_assert_registered_cb.param); -+} -+KBASE_EXPORT_SYMBOL(kbasep_debug_assert_call_hook); -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_debug.h b/drivers/gpu/arm/midgard/mali_kbase_debug.h -new file mode 100644 -index 0000000..5fff289 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_debug.h -@@ -0,0 +1,164 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KBASE_DEBUG_H -+#define _KBASE_DEBUG_H -+ -+#include -+ -+/** @brief If equals to 0, a trace containing the file, line, and function will be displayed before each message. */ -+#define KBASE_DEBUG_SKIP_TRACE 0 -+ -+/** @brief If different from 0, the trace will only contain the file and line. */ -+#define KBASE_DEBUG_SKIP_FUNCTION_NAME 0 -+ -+/** @brief Disable the asserts tests if set to 1. Default is to disable the asserts in release. */ -+#ifndef KBASE_DEBUG_DISABLE_ASSERTS -+#ifdef CONFIG_MALI_DEBUG -+#define KBASE_DEBUG_DISABLE_ASSERTS 0 -+#else -+#define KBASE_DEBUG_DISABLE_ASSERTS 1 -+#endif -+#endif /* KBASE_DEBUG_DISABLE_ASSERTS */ -+ -+/** Function type that is called on an KBASE_DEBUG_ASSERT() or KBASE_DEBUG_ASSERT_MSG() */ -+typedef void (kbase_debug_assert_hook) (void *); -+ -+struct kbasep_debug_assert_cb { -+ kbase_debug_assert_hook *func; -+ void *param; -+}; -+ -+/** -+ * @def KBASEP_DEBUG_PRINT_TRACE -+ * @brief Private macro containing the format of the trace to display before every message -+ * @sa KBASE_DEBUG_SKIP_TRACE, KBASE_DEBUG_SKIP_FUNCTION_NAME -+ */ -+#if !KBASE_DEBUG_SKIP_TRACE -+#define KBASEP_DEBUG_PRINT_TRACE \ -+ "In file: " __FILE__ " line: " CSTD_STR2(__LINE__) -+#if !KBASE_DEBUG_SKIP_FUNCTION_NAME -+#define KBASEP_DEBUG_PRINT_FUNCTION __func__ -+#else -+#define KBASEP_DEBUG_PRINT_FUNCTION "" -+#endif -+#else -+#define KBASEP_DEBUG_PRINT_TRACE "" -+#endif -+ -+/** -+ * @def KBASEP_DEBUG_ASSERT_OUT(trace, function, ...) -+ * @brief (Private) system printing function associated to the @see KBASE_DEBUG_ASSERT_MSG event. -+ * @param trace location in the code from where the message is printed -+ * @param function function from where the message is printed -+ * @param ... Format string followed by format arguments. -+ * @note function parameter cannot be concatenated with other strings -+ */ -+/* Select the correct system output function*/ -+#ifdef CONFIG_MALI_DEBUG -+#define KBASEP_DEBUG_ASSERT_OUT(trace, function, ...)\ -+ do { \ -+ pr_err("Mali: %s function:%s ", trace, function);\ -+ pr_err(__VA_ARGS__);\ -+ pr_err("\n");\ -+ } while (false) -+#else -+#define KBASEP_DEBUG_ASSERT_OUT(trace, function, ...) CSTD_NOP() -+#endif -+ -+#ifdef CONFIG_MALI_DEBUG -+#define KBASE_CALL_ASSERT_HOOK() kbasep_debug_assert_call_hook() -+#else -+#define KBASE_CALL_ASSERT_HOOK() CSTD_NOP() -+#endif -+ -+/** -+ * @def KBASE_DEBUG_ASSERT(expr) -+ * @brief Calls @see KBASE_PRINT_ASSERT and prints the expression @a expr if @a expr is false -+ * -+ * @note This macro does nothing if the flag @see KBASE_DEBUG_DISABLE_ASSERTS is set to 1 -+ * -+ * @param expr Boolean expression -+ */ -+#define KBASE_DEBUG_ASSERT(expr) \ -+ KBASE_DEBUG_ASSERT_MSG(expr, #expr) -+ -+#if KBASE_DEBUG_DISABLE_ASSERTS -+#define KBASE_DEBUG_ASSERT_MSG(expr, ...) CSTD_NOP() -+#else -+ /** -+ * @def KBASE_DEBUG_ASSERT_MSG(expr, ...) -+ * @brief Calls @see KBASEP_DEBUG_ASSERT_OUT and prints the given message if @a expr is false -+ * -+ * @note This macro does nothing if the flag @see KBASE_DEBUG_DISABLE_ASSERTS is set to 1 -+ * -+ * @param expr Boolean expression -+ * @param ... Message to display when @a expr is false, as a format string followed by format arguments. -+ */ -+#define KBASE_DEBUG_ASSERT_MSG(expr, ...) \ -+ do { \ -+ if (!(expr)) { \ -+ KBASEP_DEBUG_ASSERT_OUT(KBASEP_DEBUG_PRINT_TRACE, KBASEP_DEBUG_PRINT_FUNCTION, __VA_ARGS__);\ -+ KBASE_CALL_ASSERT_HOOK();\ -+ BUG();\ -+ } \ -+ } while (false) -+#endif /* KBASE_DEBUG_DISABLE_ASSERTS */ -+ -+/** -+ * @def KBASE_DEBUG_CODE( X ) -+ * @brief Executes the code inside the macro only in debug mode -+ * -+ * @param X Code to compile only in debug mode. -+ */ -+#ifdef CONFIG_MALI_DEBUG -+#define KBASE_DEBUG_CODE(X) X -+#else -+#define KBASE_DEBUG_CODE(X) CSTD_NOP() -+#endif /* CONFIG_MALI_DEBUG */ -+ -+/** @} */ -+ -+/** -+ * @brief Register a function to call on ASSERT -+ * -+ * Such functions will \b only be called during Debug mode, and for debugging -+ * features \b only. Do not rely on them to be called in general use. -+ * -+ * To disable the hook, supply NULL to \a func. -+ * -+ * @note This function is not thread-safe, and should only be used to -+ * register/deregister once in the module's lifetime. -+ * -+ * @param[in] func the function to call when an assert is triggered. -+ * @param[in] param the parameter to pass to \a func when calling it -+ */ -+void kbase_debug_assert_register_hook(kbase_debug_assert_hook *func, void *param); -+ -+/** -+ * @brief Call a debug assert hook previously registered with kbase_debug_assert_register_hook() -+ * -+ * @note This function is not thread-safe with respect to multiple threads -+ * registering functions and parameters with -+ * kbase_debug_assert_register_hook(). Otherwise, thread safety is the -+ * responsibility of the registered hook. -+ */ -+void kbasep_debug_assert_call_hook(void); -+ -+#endif /* _KBASE_DEBUG_H */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_debug_job_fault.c b/drivers/gpu/arm/midgard/mali_kbase_debug_job_fault.c -new file mode 100644 -index 0000000..f29430d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_debug_job_fault.c -@@ -0,0 +1,499 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+ -+#ifdef CONFIG_DEBUG_FS -+ -+static bool kbase_is_job_fault_event_pending(struct kbase_device *kbdev) -+{ -+ struct list_head *event_list = &kbdev->job_fault_event_list; -+ unsigned long flags; -+ bool ret; -+ -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ ret = !list_empty(event_list); -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ -+ return ret; -+} -+ -+static bool kbase_ctx_has_no_event_pending(struct kbase_context *kctx) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ struct list_head *event_list = &kctx->kbdev->job_fault_event_list; -+ struct base_job_fault_event *event; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ if (list_empty(event_list)) { -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ return true; -+ } -+ list_for_each_entry(event, event_list, head) { -+ if (event->katom->kctx == kctx) { -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, -+ flags); -+ return false; -+ } -+ } -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ return true; -+} -+ -+/* wait until the fault happen and copy the event */ -+static int kbase_job_fault_event_wait(struct kbase_device *kbdev, -+ struct base_job_fault_event *event) -+{ -+ struct list_head *event_list = &kbdev->job_fault_event_list; -+ struct base_job_fault_event *event_in; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ if (list_empty(event_list)) { -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ if (wait_event_interruptible(kbdev->job_fault_wq, -+ kbase_is_job_fault_event_pending(kbdev))) -+ return -ERESTARTSYS; -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ } -+ -+ event_in = list_entry(event_list->next, -+ struct base_job_fault_event, head); -+ event->event_code = event_in->event_code; -+ event->katom = event_in->katom; -+ -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ -+ return 0; -+ -+} -+ -+/* remove the event from the queue */ -+static struct base_job_fault_event *kbase_job_fault_event_dequeue( -+ struct kbase_device *kbdev, struct list_head *event_list) -+{ -+ struct base_job_fault_event *event; -+ -+ event = list_entry(event_list->next, -+ struct base_job_fault_event, head); -+ list_del(event_list->next); -+ -+ return event; -+ -+} -+ -+/* Remove all the following atoms after the failed atom in the same context -+ * Call the postponed bottom half of job done. -+ * Then, this context could be rescheduled. -+ */ -+static void kbase_job_fault_resume_event_cleanup(struct kbase_context *kctx) -+{ -+ struct list_head *event_list = &kctx->job_fault_resume_event_list; -+ -+ while (!list_empty(event_list)) { -+ struct base_job_fault_event *event; -+ -+ event = kbase_job_fault_event_dequeue(kctx->kbdev, -+ &kctx->job_fault_resume_event_list); -+ kbase_jd_done_worker(&event->katom->work); -+ } -+ -+} -+ -+/* Remove all the failed atoms that belong to different contexts -+ * Resume all the contexts that were suspend due to failed job -+ */ -+static void kbase_job_fault_event_cleanup(struct kbase_device *kbdev) -+{ -+ struct list_head *event_list = &kbdev->job_fault_event_list; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ while (!list_empty(event_list)) { -+ kbase_job_fault_event_dequeue(kbdev, event_list); -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ wake_up(&kbdev->job_fault_resume_wq); -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ } -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+} -+ -+static void kbase_job_fault_resume_worker(struct work_struct *data) -+{ -+ struct base_job_fault_event *event = container_of(data, -+ struct base_job_fault_event, job_fault_work); -+ struct kbase_context *kctx; -+ struct kbase_jd_atom *katom; -+ -+ katom = event->katom; -+ kctx = katom->kctx; -+ -+ dev_info(kctx->kbdev->dev, "Job dumping wait\n"); -+ -+ /* When it was waked up, it need to check if queue is empty or the -+ * failed atom belongs to different context. If yes, wake up. Both -+ * of them mean the failed job has been dumped. Please note, it -+ * should never happen that the job_fault_event_list has the two -+ * atoms belong to the same context. -+ */ -+ wait_event(kctx->kbdev->job_fault_resume_wq, -+ kbase_ctx_has_no_event_pending(kctx)); -+ -+ atomic_set(&kctx->job_fault_count, 0); -+ kbase_jd_done_worker(&katom->work); -+ -+ /* In case the following atoms were scheduled during failed job dump -+ * the job_done_worker was held. We need to rerun it after the dump -+ * was finished -+ */ -+ kbase_job_fault_resume_event_cleanup(kctx); -+ -+ dev_info(kctx->kbdev->dev, "Job dumping finish, resume scheduler\n"); -+} -+ -+static struct base_job_fault_event *kbase_job_fault_event_queue( -+ struct list_head *event_list, -+ struct kbase_jd_atom *atom, -+ u32 completion_code) -+{ -+ struct base_job_fault_event *event; -+ -+ event = &atom->fault_event; -+ -+ event->katom = atom; -+ event->event_code = completion_code; -+ -+ list_add_tail(&event->head, event_list); -+ -+ return event; -+ -+} -+ -+static void kbase_job_fault_event_post(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, u32 completion_code) -+{ -+ struct base_job_fault_event *event; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ event = kbase_job_fault_event_queue(&kbdev->job_fault_event_list, -+ katom, completion_code); -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ -+ wake_up_interruptible(&kbdev->job_fault_wq); -+ -+ INIT_WORK(&event->job_fault_work, kbase_job_fault_resume_worker); -+ queue_work(kbdev->job_fault_resume_workq, &event->job_fault_work); -+ -+ dev_info(katom->kctx->kbdev->dev, "Job fault happen, start dump: %d_%d", -+ katom->kctx->tgid, katom->kctx->id); -+ -+} -+ -+/* -+ * This function will process the job fault -+ * Get the register copy -+ * Send the failed job dump event -+ * Create a Wait queue to wait until the job dump finish -+ */ -+ -+bool kbase_debug_job_fault_process(struct kbase_jd_atom *katom, -+ u32 completion_code) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ -+ /* Check if dumping is in the process -+ * only one atom of each context can be dumped at the same time -+ * If the atom belongs to different context, it can be dumped -+ */ -+ if (atomic_read(&kctx->job_fault_count) > 0) { -+ kbase_job_fault_event_queue( -+ &kctx->job_fault_resume_event_list, -+ katom, completion_code); -+ dev_info(kctx->kbdev->dev, "queue:%d\n", -+ kbase_jd_atom_id(kctx, katom)); -+ return true; -+ } -+ -+ if (kctx->kbdev->job_fault_debug == true) { -+ -+ if (completion_code != BASE_JD_EVENT_DONE) { -+ -+ if (kbase_job_fault_get_reg_snapshot(kctx) == false) { -+ dev_warn(kctx->kbdev->dev, "get reg dump failed\n"); -+ return false; -+ } -+ -+ kbase_job_fault_event_post(kctx->kbdev, katom, -+ completion_code); -+ atomic_inc(&kctx->job_fault_count); -+ dev_info(kctx->kbdev->dev, "post:%d\n", -+ kbase_jd_atom_id(kctx, katom)); -+ return true; -+ -+ } -+ } -+ return false; -+ -+} -+ -+static int debug_job_fault_show(struct seq_file *m, void *v) -+{ -+ struct kbase_device *kbdev = m->private; -+ struct base_job_fault_event *event = (struct base_job_fault_event *)v; -+ struct kbase_context *kctx = event->katom->kctx; -+ int i; -+ -+ dev_info(kbdev->dev, "debug job fault seq show:%d_%d, %d", -+ kctx->tgid, kctx->id, event->reg_offset); -+ -+ if (kctx->reg_dump == NULL) { -+ dev_warn(kbdev->dev, "reg dump is NULL"); -+ return -1; -+ } -+ -+ if (kctx->reg_dump[event->reg_offset] == -+ REGISTER_DUMP_TERMINATION_FLAG) { -+ /* Return the error here to stop the read. And the -+ * following next() will not be called. The stop can -+ * get the real event resource and release it -+ */ -+ return -1; -+ } -+ -+ if (event->reg_offset == 0) -+ seq_printf(m, "%d_%d\n", kctx->tgid, kctx->id); -+ -+ for (i = 0; i < 50; i++) { -+ if (kctx->reg_dump[event->reg_offset] == -+ REGISTER_DUMP_TERMINATION_FLAG) { -+ break; -+ } -+ seq_printf(m, "%08x: %08x\n", -+ kctx->reg_dump[event->reg_offset], -+ kctx->reg_dump[1+event->reg_offset]); -+ event->reg_offset += 2; -+ -+ } -+ -+ -+ return 0; -+} -+static void *debug_job_fault_next(struct seq_file *m, void *v, loff_t *pos) -+{ -+ struct kbase_device *kbdev = m->private; -+ struct base_job_fault_event *event = (struct base_job_fault_event *)v; -+ -+ dev_info(kbdev->dev, "debug job fault seq next:%d, %d", -+ event->reg_offset, (int)*pos); -+ -+ return event; -+} -+ -+static void *debug_job_fault_start(struct seq_file *m, loff_t *pos) -+{ -+ struct kbase_device *kbdev = m->private; -+ struct base_job_fault_event *event; -+ -+ dev_info(kbdev->dev, "fault job seq start:%d", (int)*pos); -+ -+ /* The condition is trick here. It needs make sure the -+ * fault hasn't happened and the dumping hasn't been started, -+ * or the dumping has finished -+ */ -+ if (*pos == 0) { -+ event = kmalloc(sizeof(*event), GFP_KERNEL); -+ if (!event) -+ return NULL; -+ event->reg_offset = 0; -+ if (kbase_job_fault_event_wait(kbdev, event)) { -+ kfree(event); -+ return NULL; -+ } -+ -+ /* The cache flush workaround is called in bottom half of -+ * job done but we delayed it. Now we should clean cache -+ * earlier. Then the GPU memory dump should be correct. -+ */ -+ kbase_backend_cacheclean(kbdev, event->katom); -+ } else -+ return NULL; -+ -+ return event; -+} -+ -+static void debug_job_fault_stop(struct seq_file *m, void *v) -+{ -+ struct kbase_device *kbdev = m->private; -+ -+ /* here we wake up the kbase_jd_done_worker after stop, it needs -+ * get the memory dump before the register dump in debug daemon, -+ * otherwise, the memory dump may be incorrect. -+ */ -+ -+ if (v != NULL) { -+ kfree(v); -+ dev_info(kbdev->dev, "debug job fault seq stop stage 1"); -+ -+ } else { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->job_fault_event_lock, flags); -+ if (!list_empty(&kbdev->job_fault_event_list)) { -+ kbase_job_fault_event_dequeue(kbdev, -+ &kbdev->job_fault_event_list); -+ wake_up(&kbdev->job_fault_resume_wq); -+ } -+ spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags); -+ dev_info(kbdev->dev, "debug job fault seq stop stage 2"); -+ } -+ -+} -+ -+static const struct seq_operations ops = { -+ .start = debug_job_fault_start, -+ .next = debug_job_fault_next, -+ .stop = debug_job_fault_stop, -+ .show = debug_job_fault_show, -+}; -+ -+static int debug_job_fault_open(struct inode *in, struct file *file) -+{ -+ struct kbase_device *kbdev = in->i_private; -+ -+ seq_open(file, &ops); -+ -+ ((struct seq_file *)file->private_data)->private = kbdev; -+ dev_info(kbdev->dev, "debug job fault seq open"); -+ -+ kbdev->job_fault_debug = true; -+ -+ return 0; -+ -+} -+ -+static int debug_job_fault_release(struct inode *in, struct file *file) -+{ -+ struct kbase_device *kbdev = in->i_private; -+ -+ seq_release(in, file); -+ -+ kbdev->job_fault_debug = false; -+ -+ /* Clean the unprocessed job fault. After that, all the suspended -+ * contexts could be rescheduled. -+ */ -+ kbase_job_fault_event_cleanup(kbdev); -+ -+ dev_info(kbdev->dev, "debug job fault seq close"); -+ -+ return 0; -+} -+ -+static const struct file_operations kbasep_debug_job_fault_fops = { -+ .open = debug_job_fault_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = debug_job_fault_release, -+}; -+ -+/* -+ * Initialize debugfs entry for job fault dump -+ */ -+void kbase_debug_job_fault_debugfs_init(struct kbase_device *kbdev) -+{ -+ debugfs_create_file("job_fault", S_IRUGO, -+ kbdev->mali_debugfs_directory, kbdev, -+ &kbasep_debug_job_fault_fops); -+} -+ -+ -+int kbase_debug_job_fault_dev_init(struct kbase_device *kbdev) -+{ -+ -+ INIT_LIST_HEAD(&kbdev->job_fault_event_list); -+ -+ init_waitqueue_head(&(kbdev->job_fault_wq)); -+ init_waitqueue_head(&(kbdev->job_fault_resume_wq)); -+ spin_lock_init(&kbdev->job_fault_event_lock); -+ -+ kbdev->job_fault_resume_workq = alloc_workqueue( -+ "kbase_job_fault_resume_work_queue", WQ_MEM_RECLAIM, 1); -+ if (!kbdev->job_fault_resume_workq) -+ return -ENOMEM; -+ -+ kbdev->job_fault_debug = false; -+ -+ return 0; -+} -+ -+/* -+ * Release the relevant resource per device -+ */ -+void kbase_debug_job_fault_dev_term(struct kbase_device *kbdev) -+{ -+ destroy_workqueue(kbdev->job_fault_resume_workq); -+} -+ -+ -+/* -+ * Initialize the relevant data structure per context -+ */ -+void kbase_debug_job_fault_context_init(struct kbase_context *kctx) -+{ -+ -+ /* We need allocate double size register range -+ * Because this memory will keep the register address and value -+ */ -+ kctx->reg_dump = vmalloc(0x4000 * 2); -+ if (kctx->reg_dump == NULL) -+ return; -+ -+ if (kbase_debug_job_fault_reg_snapshot_init(kctx, 0x4000) == false) { -+ vfree(kctx->reg_dump); -+ kctx->reg_dump = NULL; -+ } -+ INIT_LIST_HEAD(&kctx->job_fault_resume_event_list); -+ atomic_set(&kctx->job_fault_count, 0); -+ -+} -+ -+/* -+ * release the relevant resource per context -+ */ -+void kbase_debug_job_fault_context_term(struct kbase_context *kctx) -+{ -+ vfree(kctx->reg_dump); -+} -+ -+#else /* CONFIG_DEBUG_FS */ -+ -+int kbase_debug_job_fault_dev_init(struct kbase_device *kbdev) -+{ -+ kbdev->job_fault_debug = false; -+ -+ return 0; -+} -+ -+void kbase_debug_job_fault_dev_term(struct kbase_device *kbdev) -+{ -+} -+ -+#endif /* CONFIG_DEBUG_FS */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_debug_job_fault.h b/drivers/gpu/arm/midgard/mali_kbase_debug_job_fault.h -new file mode 100644 -index 0000000..a2bf898 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_debug_job_fault.h -@@ -0,0 +1,96 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_DEBUG_JOB_FAULT_H -+#define _KBASE_DEBUG_JOB_FAULT_H -+ -+#include -+#include -+ -+#define REGISTER_DUMP_TERMINATION_FLAG 0xFFFFFFFF -+ -+/** -+ * kbase_debug_job_fault_dev_init - Create the fault event wait queue -+ * per device and initialize the required lists. -+ * @kbdev: Device pointer -+ * -+ * Return: Zero on success or a negative error code. -+ */ -+int kbase_debug_job_fault_dev_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_debug_job_fault_debugfs_init - Initialize job fault debug sysfs -+ * @kbdev: Device pointer -+ */ -+void kbase_debug_job_fault_debugfs_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_debug_job_fault_dev_term - Clean up resources created in -+ * kbase_debug_job_fault_dev_init. -+ * @kbdev: Device pointer -+ */ -+void kbase_debug_job_fault_dev_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_debug_job_fault_context_init - Initialize the relevant -+ * data structure per context -+ * @kctx: KBase context pointer -+ */ -+void kbase_debug_job_fault_context_init(struct kbase_context *kctx); -+ -+/** -+ * kbase_debug_job_fault_context_term - Release the relevant -+ * resource per context -+ * @kctx: KBase context pointer -+ */ -+void kbase_debug_job_fault_context_term(struct kbase_context *kctx); -+ -+/** -+ * kbase_debug_job_fault_process - Process the failed job. -+ * It will send a event and wake up the job fault waiting queue -+ * Then create a work queue to wait for job dump finish -+ * This function should be called in the interrupt handler and before -+ * jd_done that make sure the jd_done_worker will be delayed until the -+ * job dump finish -+ * @katom: The failed atom pointer -+ * @completion_code: the job status -+ * @return true if dump is going on -+ */ -+bool kbase_debug_job_fault_process(struct kbase_jd_atom *katom, -+ u32 completion_code); -+ -+ -+/** -+ * kbase_debug_job_fault_reg_snapshot_init - Set the interested registers -+ * address during the job fault process, the relevant registers will -+ * be saved when a job fault happen -+ * @kctx: KBase context pointer -+ * @reg_range: Maximum register address space -+ * @return true if initializing successfully -+ */ -+bool kbase_debug_job_fault_reg_snapshot_init(struct kbase_context *kctx, -+ int reg_range); -+ -+/** -+ * kbase_job_fault_get_reg_snapshot - Read the interested registers for -+ * failed job dump -+ * @kctx: KBase context pointer -+ * @return true if getting registers successfully -+ */ -+bool kbase_job_fault_get_reg_snapshot(struct kbase_context *kctx); -+ -+#endif /*_KBASE_DEBUG_JOB_FAULT_H*/ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_debug_mem_view.c b/drivers/gpu/arm/midgard/mali_kbase_debug_mem_view.c -new file mode 100644 -index 0000000..aa27156 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_debug_mem_view.c -@@ -0,0 +1,306 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Debugfs interface to dump the memory visible to the GPU -+ */ -+ -+#include "mali_kbase_debug_mem_view.h" -+#include "mali_kbase.h" -+ -+#include -+#include -+ -+#ifdef CONFIG_DEBUG_FS -+ -+struct debug_mem_mapping { -+ struct list_head node; -+ -+ struct kbase_mem_phy_alloc *alloc; -+ unsigned long flags; -+ -+ u64 start_pfn; -+ size_t nr_pages; -+}; -+ -+struct debug_mem_data { -+ struct list_head mapping_list; -+ struct kbase_context *kctx; -+}; -+ -+struct debug_mem_seq_off { -+ struct list_head *lh; -+ size_t offset; -+}; -+ -+static void *debug_mem_start(struct seq_file *m, loff_t *_pos) -+{ -+ struct debug_mem_data *mem_data = m->private; -+ struct debug_mem_seq_off *data; -+ struct debug_mem_mapping *map; -+ loff_t pos = *_pos; -+ -+ list_for_each_entry(map, &mem_data->mapping_list, node) { -+ if (pos >= map->nr_pages) { -+ pos -= map->nr_pages; -+ } else { -+ data = kmalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return NULL; -+ data->lh = &map->node; -+ data->offset = pos; -+ return data; -+ } -+ } -+ -+ /* Beyond the end */ -+ return NULL; -+} -+ -+static void debug_mem_stop(struct seq_file *m, void *v) -+{ -+ kfree(v); -+} -+ -+static void *debug_mem_next(struct seq_file *m, void *v, loff_t *pos) -+{ -+ struct debug_mem_data *mem_data = m->private; -+ struct debug_mem_seq_off *data = v; -+ struct debug_mem_mapping *map; -+ -+ map = list_entry(data->lh, struct debug_mem_mapping, node); -+ -+ if (data->offset < map->nr_pages - 1) { -+ data->offset++; -+ ++*pos; -+ return data; -+ } -+ -+ if (list_is_last(data->lh, &mem_data->mapping_list)) { -+ kfree(data); -+ return NULL; -+ } -+ -+ data->lh = data->lh->next; -+ data->offset = 0; -+ ++*pos; -+ -+ return data; -+} -+ -+static int debug_mem_show(struct seq_file *m, void *v) -+{ -+ struct debug_mem_data *mem_data = m->private; -+ struct debug_mem_seq_off *data = v; -+ struct debug_mem_mapping *map; -+ int i, j; -+ struct page *page; -+ uint32_t *mapping; -+ pgprot_t prot = PAGE_KERNEL; -+ -+ map = list_entry(data->lh, struct debug_mem_mapping, node); -+ -+ kbase_gpu_vm_lock(mem_data->kctx); -+ -+ if (data->offset >= map->alloc->nents) { -+ seq_printf(m, "%016llx: Unbacked page\n\n", (map->start_pfn + -+ data->offset) << PAGE_SHIFT); -+ goto out; -+ } -+ -+ if (!(map->flags & KBASE_REG_CPU_CACHED)) -+ prot = pgprot_writecombine(prot); -+ -+ page = phys_to_page(as_phys_addr_t(map->alloc->pages[data->offset])); -+ mapping = vmap(&page, 1, VM_MAP, prot); -+ if (!mapping) -+ goto out; -+ -+ for (i = 0; i < PAGE_SIZE; i += 4*sizeof(*mapping)) { -+ seq_printf(m, "%016llx:", i + ((map->start_pfn + -+ data->offset) << PAGE_SHIFT)); -+ -+ for (j = 0; j < 4*sizeof(*mapping); j += sizeof(*mapping)) -+ seq_printf(m, " %08x", mapping[(i+j)/sizeof(*mapping)]); -+ seq_putc(m, '\n'); -+ } -+ -+ vunmap(mapping); -+ -+ seq_putc(m, '\n'); -+ -+out: -+ kbase_gpu_vm_unlock(mem_data->kctx); -+ return 0; -+} -+ -+static const struct seq_operations ops = { -+ .start = debug_mem_start, -+ .next = debug_mem_next, -+ .stop = debug_mem_stop, -+ .show = debug_mem_show, -+}; -+ -+static int debug_mem_zone_open(struct rb_root *rbtree, -+ struct debug_mem_data *mem_data) -+{ -+ int ret = 0; -+ struct rb_node *p; -+ struct kbase_va_region *reg; -+ struct debug_mem_mapping *mapping; -+ -+ for (p = rb_first(rbtree); p; p = rb_next(p)) { -+ reg = rb_entry(p, struct kbase_va_region, rblink); -+ -+ if (reg->gpu_alloc == NULL) -+ /* Empty region - ignore */ -+ continue; -+ -+ mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); -+ if (!mapping) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ mapping->alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); -+ mapping->start_pfn = reg->start_pfn; -+ mapping->nr_pages = reg->nr_pages; -+ mapping->flags = reg->flags; -+ list_add_tail(&mapping->node, &mem_data->mapping_list); -+ } -+ -+out: -+ return ret; -+} -+ -+static int debug_mem_open(struct inode *i, struct file *file) -+{ -+ struct file *kctx_file = i->i_private; -+ struct kbase_context *kctx = kctx_file->private_data; -+ struct debug_mem_data *mem_data; -+ int ret; -+ -+ ret = seq_open(file, &ops); -+ if (ret) -+ return ret; -+ -+ mem_data = kmalloc(sizeof(*mem_data), GFP_KERNEL); -+ if (!mem_data) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ mem_data->kctx = kctx; -+ -+ INIT_LIST_HEAD(&mem_data->mapping_list); -+ -+ get_file(kctx_file); -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ ret = debug_mem_zone_open(&kctx->reg_rbtree_same, mem_data); -+ if (0 != ret) { -+ kbase_gpu_vm_unlock(kctx); -+ goto out; -+ } -+ -+ ret = debug_mem_zone_open(&kctx->reg_rbtree_exec, mem_data); -+ if (0 != ret) { -+ kbase_gpu_vm_unlock(kctx); -+ goto out; -+ } -+ -+ ret = debug_mem_zone_open(&kctx->reg_rbtree_custom, mem_data); -+ if (0 != ret) { -+ kbase_gpu_vm_unlock(kctx); -+ goto out; -+ } -+ -+ kbase_gpu_vm_unlock(kctx); -+ -+ ((struct seq_file *)file->private_data)->private = mem_data; -+ -+ return 0; -+ -+out: -+ if (mem_data) { -+ while (!list_empty(&mem_data->mapping_list)) { -+ struct debug_mem_mapping *mapping; -+ -+ mapping = list_first_entry(&mem_data->mapping_list, -+ struct debug_mem_mapping, node); -+ kbase_mem_phy_alloc_put(mapping->alloc); -+ list_del(&mapping->node); -+ kfree(mapping); -+ } -+ fput(kctx_file); -+ kfree(mem_data); -+ } -+ seq_release(i, file); -+ return ret; -+} -+ -+static int debug_mem_release(struct inode *inode, struct file *file) -+{ -+ struct file *kctx_file = inode->i_private; -+ struct seq_file *sfile = file->private_data; -+ struct debug_mem_data *mem_data = sfile->private; -+ struct debug_mem_mapping *mapping; -+ -+ seq_release(inode, file); -+ -+ while (!list_empty(&mem_data->mapping_list)) { -+ mapping = list_first_entry(&mem_data->mapping_list, -+ struct debug_mem_mapping, node); -+ kbase_mem_phy_alloc_put(mapping->alloc); -+ list_del(&mapping->node); -+ kfree(mapping); -+ } -+ -+ kfree(mem_data); -+ -+ fput(kctx_file); -+ -+ return 0; -+} -+ -+static const struct file_operations kbase_debug_mem_view_fops = { -+ .open = debug_mem_open, -+ .release = debug_mem_release, -+ .read = seq_read, -+ .llseek = seq_lseek -+}; -+ -+/** -+ * kbase_debug_mem_view_init - Initialise the mem_view sysfs file -+ * @kctx_file: The /dev/mali0 file instance for the context -+ * -+ * This function creates a "mem_view" file which can be used to get a view of -+ * the context's memory as the GPU sees it (i.e. using the GPU's page tables). -+ * -+ * The file is cleaned up by a call to debugfs_remove_recursive() deleting the -+ * parent directory. -+ */ -+void kbase_debug_mem_view_init(struct file *kctx_file) -+{ -+ struct kbase_context *kctx = kctx_file->private_data; -+ -+ debugfs_create_file("mem_view", S_IRUGO, kctx->kctx_dentry, kctx_file, -+ &kbase_debug_mem_view_fops); -+} -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_debug_mem_view.h b/drivers/gpu/arm/midgard/mali_kbase_debug_mem_view.h -new file mode 100644 -index 0000000..20ab51a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_debug_mem_view.h -@@ -0,0 +1,25 @@ -+/* -+ * -+ * (C) COPYRIGHT 2013-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_DEBUG_MEM_VIEW_H -+#define _KBASE_DEBUG_MEM_VIEW_H -+ -+#include -+ -+void kbase_debug_mem_view_init(struct file *kctx_file); -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_defs.h b/drivers/gpu/arm/midgard/mali_kbase_defs.h -new file mode 100644 -index 0000000..047ea41 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_defs.h -@@ -0,0 +1,1616 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_defs.h -+ * -+ * Defintions (types, defines, etcs) common to Kbase. They are placed here to -+ * allow the hierarchy of header files to work. -+ */ -+ -+#ifndef _KBASE_DEFS_H_ -+#define _KBASE_DEFS_H_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_MALI_FPGA_BUS_LOGGER -+#include -+#endif -+ -+ -+#ifdef CONFIG_KDS -+#include -+#endif /* CONFIG_KDS */ -+ -+#if defined(CONFIG_SYNC) -+#include -+#else -+#include "mali_kbase_fence_defs.h" -+#endif -+ -+#ifdef CONFIG_DEBUG_FS -+#include -+#endif /* CONFIG_DEBUG_FS */ -+ -+#ifdef CONFIG_MALI_DEVFREQ -+#include -+#endif /* CONFIG_MALI_DEVFREQ */ -+ -+#include -+#include -+ -+#if defined(CONFIG_PM_RUNTIME) || \ -+ (defined(CONFIG_PM) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) -+#define KBASE_PM_RUNTIME 1 -+#endif -+ -+/** Enable SW tracing when set */ -+#ifdef CONFIG_MALI_MIDGARD_ENABLE_TRACE -+#define KBASE_TRACE_ENABLE 1 -+#endif -+ -+#ifndef KBASE_TRACE_ENABLE -+#ifdef CONFIG_MALI_DEBUG -+#define KBASE_TRACE_ENABLE 1 -+#else -+#define KBASE_TRACE_ENABLE 0 -+#endif /* CONFIG_MALI_DEBUG */ -+#endif /* KBASE_TRACE_ENABLE */ -+ -+/** Dump Job slot trace on error (only active if KBASE_TRACE_ENABLE != 0) */ -+#define KBASE_TRACE_DUMP_ON_JOB_SLOT_ERROR 1 -+ -+/** -+ * Number of milliseconds before resetting the GPU when a job cannot be "zapped" from the hardware. -+ * Note that the time is actually ZAP_TIMEOUT+SOFT_STOP_RESET_TIMEOUT between the context zap starting and the GPU -+ * actually being reset to give other contexts time for their jobs to be soft-stopped and removed from the hardware -+ * before resetting. -+ */ -+#define ZAP_TIMEOUT 1000 -+ -+/** Number of milliseconds before we time out on a GPU soft/hard reset */ -+#define RESET_TIMEOUT 500 -+ -+/** -+ * Prevent soft-stops from occuring in scheduling situations -+ * -+ * This is not due to HW issues, but when scheduling is desired to be more predictable. -+ * -+ * Therefore, soft stop may still be disabled due to HW issues. -+ * -+ * @note Soft stop will still be used for non-scheduling purposes e.g. when terminating a context. -+ * -+ * @note if not in use, define this value to 0 instead of \#undef'ing it -+ */ -+#define KBASE_DISABLE_SCHEDULING_SOFT_STOPS 0 -+ -+/** -+ * Prevent hard-stops from occuring in scheduling situations -+ * -+ * This is not due to HW issues, but when scheduling is desired to be more predictable. -+ * -+ * @note Hard stop will still be used for non-scheduling purposes e.g. when terminating a context. -+ * -+ * @note if not in use, define this value to 0 instead of \#undef'ing it -+ */ -+#define KBASE_DISABLE_SCHEDULING_HARD_STOPS 0 -+ -+/** -+ * The maximum number of Job Slots to support in the Hardware. -+ * -+ * You can optimize this down if your target devices will only ever support a -+ * small number of job slots. -+ */ -+#define BASE_JM_MAX_NR_SLOTS 3 -+ -+/** -+ * The maximum number of Address Spaces to support in the Hardware. -+ * -+ * You can optimize this down if your target devices will only ever support a -+ * small number of Address Spaces -+ */ -+#define BASE_MAX_NR_AS 16 -+ -+/* mmu */ -+#define MIDGARD_MMU_VA_BITS 48 -+ -+#define MIDGARD_MMU_LEVEL(x) (x) -+ -+#if MIDGARD_MMU_VA_BITS > 39 -+#define MIDGARD_MMU_TOPLEVEL MIDGARD_MMU_LEVEL(0) -+#else -+#define MIDGARD_MMU_TOPLEVEL MIDGARD_MMU_LEVEL(1) -+#endif -+ -+#define MIDGARD_MMU_BOTTOMLEVEL MIDGARD_MMU_LEVEL(3) -+ -+#define GROWABLE_FLAGS_REQUIRED (KBASE_REG_PF_GROW | KBASE_REG_GPU_WR) -+ -+/** setting in kbase_context::as_nr that indicates it's invalid */ -+#define KBASEP_AS_NR_INVALID (-1) -+ -+#define KBASE_LOCK_REGION_MAX_SIZE (63) -+#define KBASE_LOCK_REGION_MIN_SIZE (11) -+ -+#define KBASE_TRACE_SIZE_LOG2 8 /* 256 entries */ -+#define KBASE_TRACE_SIZE (1 << KBASE_TRACE_SIZE_LOG2) -+#define KBASE_TRACE_MASK ((1 << KBASE_TRACE_SIZE_LOG2)-1) -+ -+#include "mali_kbase_js_defs.h" -+#include "mali_kbase_hwaccess_defs.h" -+ -+#define KBASEP_FORCE_REPLAY_DISABLED 0 -+ -+/* Maximum force replay limit when randomization is enabled */ -+#define KBASEP_FORCE_REPLAY_RANDOM_LIMIT 16 -+ -+/** Atom has been previously soft-stoppped */ -+#define KBASE_KATOM_FLAG_BEEN_SOFT_STOPPPED (1<<1) -+/** Atom has been previously retried to execute */ -+#define KBASE_KATOM_FLAGS_RERUN (1<<2) -+#define KBASE_KATOM_FLAGS_JOBCHAIN (1<<3) -+/** Atom has been previously hard-stopped. */ -+#define KBASE_KATOM_FLAG_BEEN_HARD_STOPPED (1<<4) -+/** Atom has caused us to enter disjoint state */ -+#define KBASE_KATOM_FLAG_IN_DISJOINT (1<<5) -+/* Atom blocked on cross-slot dependency */ -+#define KBASE_KATOM_FLAG_X_DEP_BLOCKED (1<<7) -+/* Atom has fail dependency on cross-slot dependency */ -+#define KBASE_KATOM_FLAG_FAIL_BLOCKER (1<<8) -+/* Atom is currently in the list of atoms blocked on cross-slot dependencies */ -+#define KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST (1<<9) -+/* Atom is currently holding a context reference */ -+#define KBASE_KATOM_FLAG_HOLDING_CTX_REF (1<<10) -+/* Atom requires GPU to be in protected mode */ -+#define KBASE_KATOM_FLAG_PROTECTED (1<<11) -+/* Atom has been stored in runnable_tree */ -+#define KBASE_KATOM_FLAG_JSCTX_IN_TREE (1<<12) -+ -+/* SW related flags about types of JS_COMMAND action -+ * NOTE: These must be masked off by JS_COMMAND_MASK */ -+ -+/** This command causes a disjoint event */ -+#define JS_COMMAND_SW_CAUSES_DISJOINT 0x100 -+ -+/** Bitmask of all SW related flags */ -+#define JS_COMMAND_SW_BITS (JS_COMMAND_SW_CAUSES_DISJOINT) -+ -+#if (JS_COMMAND_SW_BITS & JS_COMMAND_MASK) -+#error JS_COMMAND_SW_BITS not masked off by JS_COMMAND_MASK. Must update JS_COMMAND_SW_<..> bitmasks -+#endif -+ -+/** Soft-stop command that causes a Disjoint event. This of course isn't -+ * entirely masked off by JS_COMMAND_MASK */ -+#define JS_COMMAND_SOFT_STOP_WITH_SW_DISJOINT \ -+ (JS_COMMAND_SW_CAUSES_DISJOINT | JS_COMMAND_SOFT_STOP) -+ -+#define KBASEP_ATOM_ID_INVALID BASE_JD_ATOM_COUNT -+ -+/* Serialize atoms within a slot (ie only one atom per job slot) */ -+#define KBASE_SERIALIZE_INTRA_SLOT (1 << 0) -+/* Serialize atoms between slots (ie only one job slot running at any time) */ -+#define KBASE_SERIALIZE_INTER_SLOT (1 << 1) -+/* Reset the GPU after each atom completion */ -+#define KBASE_SERIALIZE_RESET (1 << 2) -+ -+#ifdef CONFIG_DEBUG_FS -+struct base_job_fault_event { -+ -+ u32 event_code; -+ struct kbase_jd_atom *katom; -+ struct work_struct job_fault_work; -+ struct list_head head; -+ int reg_offset; -+}; -+ -+#endif -+ -+struct kbase_jd_atom_dependency { -+ struct kbase_jd_atom *atom; -+ u8 dep_type; -+}; -+ -+/** -+ * struct kbase_io_access - holds information about 1 register access -+ * -+ * @addr: first bit indicates r/w (r=0, w=1) -+ * @value: value written or read -+ */ -+struct kbase_io_access { -+ uintptr_t addr; -+ u32 value; -+}; -+ -+/** -+ * struct kbase_io_history - keeps track of all recent register accesses -+ * -+ * @enabled: true if register accesses are recorded, false otherwise -+ * @lock: spinlock protecting kbase_io_access array -+ * @count: number of registers read/written -+ * @size: number of elements in kbase_io_access array -+ * @buf: array of kbase_io_access -+ */ -+struct kbase_io_history { -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) -+ bool enabled; -+#else -+ u32 enabled; -+#endif -+ -+ spinlock_t lock; -+ size_t count; -+ u16 size; -+ struct kbase_io_access *buf; -+}; -+ -+/** -+ * @brief The function retrieves a read-only reference to the atom field from -+ * the kbase_jd_atom_dependency structure -+ * -+ * @param[in] dep kbase jd atom dependency. -+ * -+ * @return readonly reference to dependent ATOM. -+ */ -+static inline const struct kbase_jd_atom * kbase_jd_katom_dep_atom(const struct kbase_jd_atom_dependency *dep) -+{ -+ LOCAL_ASSERT(dep != NULL); -+ -+ return (const struct kbase_jd_atom *)(dep->atom); -+} -+ -+/** -+ * @brief The function retrieves a read-only reference to the dependency type field from -+ * the kbase_jd_atom_dependency structure -+ * -+ * @param[in] dep kbase jd atom dependency. -+ * -+ * @return A dependency type value. -+ */ -+static inline u8 kbase_jd_katom_dep_type(const struct kbase_jd_atom_dependency *dep) -+{ -+ LOCAL_ASSERT(dep != NULL); -+ -+ return dep->dep_type; -+} -+ -+/** -+ * @brief Setter macro for dep_atom array entry in kbase_jd_atom -+ * -+ * @param[in] dep The kbase jd atom dependency. -+ * @param[in] a The ATOM to be set as a dependency. -+ * @param type The ATOM dependency type to be set. -+ * -+ */ -+static inline void kbase_jd_katom_dep_set(const struct kbase_jd_atom_dependency *const_dep, -+ struct kbase_jd_atom *a, u8 type) -+{ -+ struct kbase_jd_atom_dependency *dep; -+ -+ LOCAL_ASSERT(const_dep != NULL); -+ -+ dep = (struct kbase_jd_atom_dependency *)const_dep; -+ -+ dep->atom = a; -+ dep->dep_type = type; -+} -+ -+/** -+ * @brief Setter macro for dep_atom array entry in kbase_jd_atom -+ * -+ * @param[in] dep The kbase jd atom dependency to be cleared. -+ * -+ */ -+static inline void kbase_jd_katom_dep_clear(const struct kbase_jd_atom_dependency *const_dep) -+{ -+ struct kbase_jd_atom_dependency *dep; -+ -+ LOCAL_ASSERT(const_dep != NULL); -+ -+ dep = (struct kbase_jd_atom_dependency *)const_dep; -+ -+ dep->atom = NULL; -+ dep->dep_type = BASE_JD_DEP_TYPE_INVALID; -+} -+ -+enum kbase_atom_gpu_rb_state { -+ /* Atom is not currently present in slot ringbuffer */ -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB, -+ /* Atom is in slot ringbuffer but is blocked on a previous atom */ -+ KBASE_ATOM_GPU_RB_WAITING_BLOCKED, -+ /* Atom is in slot ringbuffer but is waiting for a previous protected -+ * mode transition to complete */ -+ KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV, -+ /* Atom is in slot ringbuffer but is waiting for proected mode -+ * transition */ -+ KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION, -+ /* Atom is in slot ringbuffer but is waiting for cores to become -+ * available */ -+ KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE, -+ /* Atom is in slot ringbuffer but is blocked on affinity */ -+ KBASE_ATOM_GPU_RB_WAITING_AFFINITY, -+ /* Atom is in slot ringbuffer and ready to run */ -+ KBASE_ATOM_GPU_RB_READY, -+ /* Atom is in slot ringbuffer and has been submitted to the GPU */ -+ KBASE_ATOM_GPU_RB_SUBMITTED, -+ /* Atom must be returned to JS as soon as it reaches the head of the -+ * ringbuffer due to a previous failure */ -+ KBASE_ATOM_GPU_RB_RETURN_TO_JS = -1 -+}; -+ -+enum kbase_atom_enter_protected_state { -+ /* -+ * Starting state: -+ * Check if a transition into protected mode is required. -+ * -+ * NOTE: The integer value of this must -+ * match KBASE_ATOM_EXIT_PROTECTED_CHECK. -+ */ -+ KBASE_ATOM_ENTER_PROTECTED_CHECK = 0, -+ /* Wait for vinstr to suspend. */ -+ KBASE_ATOM_ENTER_PROTECTED_VINSTR, -+ /* Wait for the L2 to become idle in preparation for -+ * the coherency change. */ -+ KBASE_ATOM_ENTER_PROTECTED_IDLE_L2, -+ /* End state; -+ * Prepare coherency change. */ -+ KBASE_ATOM_ENTER_PROTECTED_FINISHED, -+}; -+ -+enum kbase_atom_exit_protected_state { -+ /* -+ * Starting state: -+ * Check if a transition out of protected mode is required. -+ * -+ * NOTE: The integer value of this must -+ * match KBASE_ATOM_ENTER_PROTECTED_CHECK. -+ */ -+ KBASE_ATOM_EXIT_PROTECTED_CHECK = 0, -+ /* Wait for the L2 to become idle in preparation -+ * for the reset. */ -+ KBASE_ATOM_EXIT_PROTECTED_IDLE_L2, -+ /* Issue the protected reset. */ -+ KBASE_ATOM_EXIT_PROTECTED_RESET, -+ /* End state; -+ * Wait for the reset to complete. */ -+ KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT, -+}; -+ -+struct kbase_ext_res { -+ u64 gpu_address; -+ struct kbase_mem_phy_alloc *alloc; -+}; -+ -+struct kbase_jd_atom { -+ struct work_struct work; -+ ktime_t start_timestamp; -+ -+ struct base_jd_udata udata; -+ struct kbase_context *kctx; -+ -+ struct list_head dep_head[2]; -+ struct list_head dep_item[2]; -+ const struct kbase_jd_atom_dependency dep[2]; -+ /* List head used during job dispatch job_done processing - as -+ * dependencies may not be entirely resolved at this point, we need to -+ * use a separate list head. */ -+ struct list_head jd_item; -+ /* true if atom's jd_item is currently on a list. Prevents atom being -+ * processed twice. */ -+ bool in_jd_list; -+ -+ u16 nr_extres; -+ struct kbase_ext_res *extres; -+ -+ u32 device_nr; -+ u64 affinity; -+ u64 jc; -+ enum kbase_atom_coreref_state coreref_state; -+#ifdef CONFIG_KDS -+ struct list_head node; -+ struct kds_resource_set *kds_rset; -+ bool kds_dep_satisfied; -+#endif /* CONFIG_KDS */ -+#if defined(CONFIG_SYNC) -+ /* Stores either an input or output fence, depending on soft-job type */ -+ struct sync_fence *fence; -+ struct sync_fence_waiter sync_waiter; -+#endif /* CONFIG_SYNC */ -+#if defined(CONFIG_MALI_DMA_FENCE) || defined(CONFIG_SYNC_FILE) -+ struct { -+ /* Use the functions/API defined in mali_kbase_fence.h to -+ * when working with this sub struct */ -+#if defined(CONFIG_SYNC_FILE) -+ /* Input fence */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence_in; -+#else -+ struct dma_fence *fence_in; -+#endif -+#endif -+ /* This points to the dma-buf output fence for this atom. If -+ * this is NULL then there is no fence for this atom and the -+ * following fields related to dma_fence may have invalid data. -+ * -+ * The context and seqno fields contain the details for this -+ * fence. -+ * -+ * This fence is signaled when the katom is completed, -+ * regardless of the event_code of the katom (signal also on -+ * failure). -+ */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence; -+#else -+ struct dma_fence *fence; -+#endif -+ /* The dma-buf fence context number for this atom. A unique -+ * context number is allocated to each katom in the context on -+ * context creation. -+ */ -+ unsigned int context; -+ /* The dma-buf fence sequence number for this atom. This is -+ * increased every time this katom uses dma-buf fence. -+ */ -+ atomic_t seqno; -+ /* This contains a list of all callbacks set up to wait on -+ * other fences. This atom must be held back from JS until all -+ * these callbacks have been called and dep_count have reached -+ * 0. The initial value of dep_count must be equal to the -+ * number of callbacks on this list. -+ * -+ * This list is protected by jctx.lock. Callbacks are added to -+ * this list when the atom is built and the wait are set up. -+ * All the callbacks then stay on the list until all callbacks -+ * have been called and the atom is queued, or cancelled, and -+ * then all callbacks are taken off the list and freed. -+ */ -+ struct list_head callbacks; -+ /* Atomic counter of number of outstandind dma-buf fence -+ * dependencies for this atom. When dep_count reaches 0 the -+ * atom may be queued. -+ * -+ * The special value "-1" may only be set after the count -+ * reaches 0, while holding jctx.lock. This indicates that the -+ * atom has been handled, either queued in JS or cancelled. -+ * -+ * If anyone but the dma-fence worker sets this to -1 they must -+ * ensure that any potentially queued worker must have -+ * completed before allowing the atom to be marked as unused. -+ * This can be done by flushing the fence work queue: -+ * kctx->dma_fence.wq. -+ */ -+ atomic_t dep_count; -+ } dma_fence; -+#endif /* CONFIG_MALI_DMA_FENCE || CONFIG_SYNC_FILE*/ -+ -+ /* Note: refer to kbasep_js_atom_retained_state, which will take a copy of some of the following members */ -+ enum base_jd_event_code event_code; -+ base_jd_core_req core_req; /**< core requirements */ -+ /** Job Slot to retry submitting to if submission from IRQ handler failed -+ * -+ * NOTE: see if this can be unified into the another member e.g. the event */ -+ int retry_submit_on_slot; -+ -+ u32 ticks; -+ /* JS atom priority with respect to other atoms on its kctx. */ -+ int sched_priority; -+ -+ int poking; /* BASE_HW_ISSUE_8316 */ -+ -+ wait_queue_head_t completed; -+ enum kbase_jd_atom_state status; -+#ifdef CONFIG_GPU_TRACEPOINTS -+ int work_id; -+#endif -+ /* Assigned after atom is completed. Used to check whether PRLAM-10676 workaround should be applied */ -+ int slot_nr; -+ -+ u32 atom_flags; -+ -+ /* Number of times this atom has been retried. Used by replay soft job. -+ */ -+ int retry_count; -+ -+ enum kbase_atom_gpu_rb_state gpu_rb_state; -+ -+ u64 need_cache_flush_cores_retained; -+ -+ atomic_t blocked; -+ -+ /* Pointer to atom that this atom has same-slot dependency on */ -+ struct kbase_jd_atom *pre_dep; -+ /* Pointer to atom that has same-slot dependency on this atom */ -+ struct kbase_jd_atom *post_dep; -+ -+ /* Pointer to atom that this atom has cross-slot dependency on */ -+ struct kbase_jd_atom *x_pre_dep; -+ /* Pointer to atom that has cross-slot dependency on this atom */ -+ struct kbase_jd_atom *x_post_dep; -+ -+ /* The GPU's flush count recorded at the time of submission, used for -+ * the cache flush optimisation */ -+ u32 flush_id; -+ -+ struct kbase_jd_atom_backend backend; -+#ifdef CONFIG_DEBUG_FS -+ struct base_job_fault_event fault_event; -+#endif -+ -+ /* List head used for three different purposes: -+ * 1. Overflow list for JS ring buffers. If an atom is ready to run, -+ * but there is no room in the JS ring buffer, then the atom is put -+ * on the ring buffer's overflow list using this list node. -+ * 2. List of waiting soft jobs. -+ */ -+ struct list_head queue; -+ -+ /* Used to keep track of all JIT free/alloc jobs in submission order -+ */ -+ struct list_head jit_node; -+ bool jit_blocked; -+ -+ /* If non-zero, this indicates that the atom will fail with the set -+ * event_code when the atom is processed. */ -+ enum base_jd_event_code will_fail_event_code; -+ -+ /* Atoms will only ever be transitioning into, or out of -+ * protected mode so we do not need two separate fields. -+ */ -+ union { -+ enum kbase_atom_enter_protected_state enter; -+ enum kbase_atom_exit_protected_state exit; -+ } protected_state; -+ -+ struct rb_node runnable_tree_node; -+ -+ /* 'Age' of atom relative to other atoms in the context. */ -+ u32 age; -+}; -+ -+static inline bool kbase_jd_katom_is_protected(const struct kbase_jd_atom *katom) -+{ -+ return (bool)(katom->atom_flags & KBASE_KATOM_FLAG_PROTECTED); -+} -+ -+/* -+ * Theory of operations: -+ * -+ * Atom objects are statically allocated within the context structure. -+ * -+ * Each atom is the head of two lists, one for the "left" set of dependencies, one for the "right" set. -+ */ -+ -+#define KBASE_JD_DEP_QUEUE_SIZE 256 -+ -+struct kbase_jd_context { -+ struct mutex lock; -+ struct kbasep_js_kctx_info sched_info; -+ struct kbase_jd_atom atoms[BASE_JD_ATOM_COUNT]; -+ -+ /** Tracks all job-dispatch jobs. This includes those not tracked by -+ * the scheduler: 'not ready to run' and 'dependency-only' jobs. */ -+ u32 job_nr; -+ -+ /** Waitq that reflects whether there are no jobs (including SW-only -+ * dependency jobs). This is set when no jobs are present on the ctx, -+ * and clear when there are jobs. -+ * -+ * @note: Job Dispatcher knows about more jobs than the Job Scheduler: -+ * the Job Scheduler is unaware of jobs that are blocked on dependencies, -+ * and SW-only dependency jobs. -+ * -+ * This waitq can be waited upon to find out when the context jobs are all -+ * done/cancelled (including those that might've been blocked on -+ * dependencies) - and so, whether it can be terminated. However, it should -+ * only be terminated once it is not present in the run-pool (see -+ * kbasep_js_kctx_info::ctx::is_scheduled). -+ * -+ * Since the waitq is only set under kbase_jd_context::lock, -+ * the waiter should also briefly obtain and drop kbase_jd_context::lock to -+ * guarentee that the setter has completed its work on the kbase_context -+ * -+ * This must be updated atomically with: -+ * - kbase_jd_context::job_nr */ -+ wait_queue_head_t zero_jobs_wait; -+ -+ /** Job Done workqueue. */ -+ struct workqueue_struct *job_done_wq; -+ -+ spinlock_t tb_lock; -+ u32 *tb; -+ size_t tb_wrap_offset; -+ -+#ifdef CONFIG_KDS -+ struct kds_callback kds_cb; -+#endif /* CONFIG_KDS */ -+#ifdef CONFIG_GPU_TRACEPOINTS -+ atomic_t work_id; -+#endif -+}; -+ -+struct kbase_device_info { -+ u32 features; -+}; -+ -+/** Poking state for BASE_HW_ISSUE_8316 */ -+enum { -+ KBASE_AS_POKE_STATE_IN_FLIGHT = 1<<0, -+ KBASE_AS_POKE_STATE_KILLING_POKE = 1<<1 -+}; -+ -+/** Poking state for BASE_HW_ISSUE_8316 */ -+typedef u32 kbase_as_poke_state; -+ -+struct kbase_mmu_setup { -+ u64 transtab; -+ u64 memattr; -+ u64 transcfg; -+}; -+ -+/** -+ * Important: Our code makes assumptions that a struct kbase_as structure is always at -+ * kbase_device->as[number]. This is used to recover the containing -+ * struct kbase_device from a struct kbase_as structure. -+ * -+ * Therefore, struct kbase_as structures must not be allocated anywhere else. -+ */ -+struct kbase_as { -+ int number; -+ -+ struct workqueue_struct *pf_wq; -+ struct work_struct work_pagefault; -+ struct work_struct work_busfault; -+ enum kbase_mmu_fault_type fault_type; -+ bool protected_mode; -+ u32 fault_status; -+ u64 fault_addr; -+ u64 fault_extra_addr; -+ -+ struct kbase_mmu_setup current_setup; -+ -+ /* BASE_HW_ISSUE_8316 */ -+ struct workqueue_struct *poke_wq; -+ struct work_struct poke_work; -+ /** Protected by hwaccess_lock */ -+ int poke_refcount; -+ /** Protected by hwaccess_lock */ -+ kbase_as_poke_state poke_state; -+ struct hrtimer poke_timer; -+}; -+ -+static inline int kbase_as_has_bus_fault(struct kbase_as *as) -+{ -+ return as->fault_type == KBASE_MMU_FAULT_TYPE_BUS; -+} -+ -+static inline int kbase_as_has_page_fault(struct kbase_as *as) -+{ -+ return as->fault_type == KBASE_MMU_FAULT_TYPE_PAGE; -+} -+ -+struct kbasep_mem_device { -+ atomic_t used_pages; /* Tracks usage of OS shared memory. Updated -+ when OS memory is allocated/freed. */ -+ -+}; -+ -+#define KBASE_TRACE_CODE(X) KBASE_TRACE_CODE_ ## X -+ -+enum kbase_trace_code { -+ /* IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE -+ * THIS MUST BE USED AT THE START OF THE ENUM */ -+#define KBASE_TRACE_CODE_MAKE_CODE(X) KBASE_TRACE_CODE(X) -+#include "mali_kbase_trace_defs.h" -+#undef KBASE_TRACE_CODE_MAKE_CODE -+ /* Comma on its own, to extend the list */ -+ , -+ /* Must be the last in the enum */ -+ KBASE_TRACE_CODE_COUNT -+}; -+ -+#define KBASE_TRACE_FLAG_REFCOUNT (((u8)1) << 0) -+#define KBASE_TRACE_FLAG_JOBSLOT (((u8)1) << 1) -+ -+struct kbase_trace { -+ struct timespec timestamp; -+ u32 thread_id; -+ u32 cpu; -+ void *ctx; -+ bool katom; -+ int atom_number; -+ u64 atom_udata[2]; -+ u64 gpu_addr; -+ unsigned long info_val; -+ u8 code; -+ u8 jobslot; -+ u8 refcount; -+ u8 flags; -+}; -+ -+/** Event IDs for the power management framework. -+ * -+ * Any of these events might be missed, so they should not be relied upon to -+ * find the precise state of the GPU at a particular time in the -+ * trace. Overall, we should get a high percentage of these events for -+ * statisical purposes, and so a few missing should not be a problem */ -+enum kbase_timeline_pm_event { -+ /* helper for tests */ -+ KBASEP_TIMELINE_PM_EVENT_FIRST, -+ -+ /** Event reserved for backwards compatibility with 'init' events */ -+ KBASE_TIMELINE_PM_EVENT_RESERVED_0 = KBASEP_TIMELINE_PM_EVENT_FIRST, -+ -+ /** The power state of the device has changed. -+ * -+ * Specifically, the device has reached a desired or available state. -+ */ -+ KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED, -+ -+ /** The GPU is becoming active. -+ * -+ * This event is sent when the first context is about to use the GPU. -+ */ -+ KBASE_TIMELINE_PM_EVENT_GPU_ACTIVE, -+ -+ /** The GPU is becoming idle. -+ * -+ * This event is sent when the last context has finished using the GPU. -+ */ -+ KBASE_TIMELINE_PM_EVENT_GPU_IDLE, -+ -+ /** Event reserved for backwards compatibility with 'policy_change' -+ * events */ -+ KBASE_TIMELINE_PM_EVENT_RESERVED_4, -+ -+ /** Event reserved for backwards compatibility with 'system_suspend' -+ * events */ -+ KBASE_TIMELINE_PM_EVENT_RESERVED_5, -+ -+ /** Event reserved for backwards compatibility with 'system_resume' -+ * events */ -+ KBASE_TIMELINE_PM_EVENT_RESERVED_6, -+ -+ /** The job scheduler is requesting to power up/down cores. -+ * -+ * This event is sent when: -+ * - powered down cores are needed to complete a job -+ * - powered up cores are not needed anymore -+ */ -+ KBASE_TIMELINE_PM_EVENT_CHANGE_GPU_STATE, -+ -+ KBASEP_TIMELINE_PM_EVENT_LAST = KBASE_TIMELINE_PM_EVENT_CHANGE_GPU_STATE, -+}; -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+struct kbase_trace_kctx_timeline { -+ atomic_t jd_atoms_in_flight; -+ u32 owner_tgid; -+}; -+ -+struct kbase_trace_kbdev_timeline { -+ /* Note: strictly speaking, not needed, because it's in sync with -+ * kbase_device::jm_slots[]::submitted_nr -+ * -+ * But it's kept as an example of how to add global timeline tracking -+ * information -+ * -+ * The caller must hold hwaccess_lock when accessing this */ -+ u8 slot_atoms_submitted[BASE_JM_MAX_NR_SLOTS]; -+ -+ /* Last UID for each PM event */ -+ atomic_t pm_event_uid[KBASEP_TIMELINE_PM_EVENT_LAST+1]; -+ /* Counter for generating PM event UIDs */ -+ atomic_t pm_event_uid_counter; -+ /* -+ * L2 transition state - true indicates that the transition is ongoing -+ * Expected to be protected by hwaccess_lock */ -+ bool l2_transitioning; -+}; -+#endif /* CONFIG_MALI_TRACE_TIMELINE */ -+ -+ -+struct kbasep_kctx_list_element { -+ struct list_head link; -+ struct kbase_context *kctx; -+}; -+ -+/** -+ * Data stored per device for power management. -+ * -+ * This structure contains data for the power management framework. There is one -+ * instance of this structure per device in the system. -+ */ -+struct kbase_pm_device_data { -+ /** -+ * The lock protecting Power Management structures accessed outside of -+ * IRQ. -+ * -+ * This lock must also be held whenever the GPU is being powered on or -+ * off. -+ */ -+ struct mutex lock; -+ -+ /** The reference count of active contexts on this device. */ -+ int active_count; -+ /** Flag indicating suspending/suspended */ -+ bool suspending; -+ /* Wait queue set when active_count == 0 */ -+ wait_queue_head_t zero_active_count_wait; -+ -+ /** -+ * Bit masks identifying the available shader cores that are specified -+ * via sysfs. One mask per job slot. -+ */ -+ u64 debug_core_mask[BASE_JM_MAX_NR_SLOTS]; -+ u64 debug_core_mask_all; -+ -+ /** -+ * Callback for initializing the runtime power management. -+ * -+ * @param kbdev The kbase device -+ * -+ * @return 0 on success, else error code -+ */ -+ int (*callback_power_runtime_init)(struct kbase_device *kbdev); -+ -+ /** -+ * Callback for terminating the runtime power management. -+ * -+ * @param kbdev The kbase device -+ */ -+ void (*callback_power_runtime_term)(struct kbase_device *kbdev); -+ -+ /* Time in milliseconds between each dvfs sample */ -+ u32 dvfs_period; -+ -+ /* Period of GPU poweroff timer */ -+ ktime_t gpu_poweroff_time; -+ -+ /* Number of ticks of GPU poweroff timer before shader is powered off */ -+ int poweroff_shader_ticks; -+ -+ /* Number of ticks of GPU poweroff timer before GPU is powered off */ -+ int poweroff_gpu_ticks; -+ -+ struct kbase_pm_backend_data backend; -+}; -+ -+/** -+ * struct kbase_mem_pool - Page based memory pool for kctx/kbdev -+ * @kbdev: Kbase device where memory is used -+ * @cur_size: Number of free pages currently in the pool (may exceed @max_size -+ * in some corner cases) -+ * @max_size: Maximum number of free pages in the pool -+ * @order: order = 0 refers to a pool of 4 KB pages -+ * order = 9 refers to a pool of 2 MB pages (2^9 * 4KB = 2 MB) -+ * @pool_lock: Lock protecting the pool - must be held when modifying @cur_size -+ * and @page_list -+ * @page_list: List of free pages in the pool -+ * @reclaim: Shrinker for kernel reclaim of free pages -+ * @next_pool: Pointer to next pool where pages can be allocated when this pool -+ * is empty. Pages will spill over to the next pool when this pool -+ * is full. Can be NULL if there is no next pool. -+ */ -+struct kbase_mem_pool { -+ struct kbase_device *kbdev; -+ size_t cur_size; -+ size_t max_size; -+ size_t order; -+ spinlock_t pool_lock; -+ struct list_head page_list; -+ struct shrinker reclaim; -+ -+ struct kbase_mem_pool *next_pool; -+}; -+ -+/** -+ * struct kbase_devfreq_opp - Lookup table for converting between nominal OPP -+ * frequency, and real frequency and core mask -+ * @opp_freq: Nominal OPP frequency -+ * @real_freq: Real GPU frequency -+ * @core_mask: Shader core mask -+ */ -+struct kbase_devfreq_opp { -+ u64 opp_freq; -+ u64 real_freq; -+ u64 core_mask; -+}; -+ -+#define DEVNAME_SIZE 16 -+ -+struct kbase_device { -+ s8 slot_submit_count_irq[BASE_JM_MAX_NR_SLOTS]; -+ -+ u32 hw_quirks_sc; -+ u32 hw_quirks_tiler; -+ u32 hw_quirks_mmu; -+ u32 hw_quirks_jm; -+ -+ struct list_head entry; -+ struct device *dev; -+ struct miscdevice mdev; -+ u64 reg_start; -+ size_t reg_size; -+ void __iomem *reg; -+ -+ struct { -+ int irq; -+ int flags; -+ } irqs[3]; -+ -+ struct clk *clock; -+#ifdef CONFIG_REGULATOR -+ struct regulator *regulator; -+#endif -+ char devname[DEVNAME_SIZE]; -+ -+#ifdef CONFIG_MALI_NO_MALI -+ void *model; -+ struct kmem_cache *irq_slab; -+ struct workqueue_struct *irq_workq; -+ atomic_t serving_job_irq; -+ atomic_t serving_gpu_irq; -+ atomic_t serving_mmu_irq; -+ spinlock_t reg_op_lock; -+#endif /* CONFIG_MALI_NO_MALI */ -+ -+ struct kbase_pm_device_data pm; -+ struct kbasep_js_device_data js_data; -+ struct kbase_mem_pool mem_pool; -+ struct kbase_mem_pool lp_mem_pool; -+ struct kbasep_mem_device memdev; -+ struct kbase_mmu_mode const *mmu_mode; -+ -+ struct kbase_as as[BASE_MAX_NR_AS]; -+ /* The below variables (as_free and as_to_kctx) are managed by the -+ * Context Scheduler. The kbasep_js_device_data::runpool_irq::lock must -+ * be held whilst accessing these. -+ */ -+ u16 as_free; /* Bitpattern of free Address Spaces */ -+ /* Mapping from active Address Spaces to kbase_context */ -+ struct kbase_context *as_to_kctx[BASE_MAX_NR_AS]; -+ -+ -+ spinlock_t mmu_mask_change; -+ -+ struct kbase_gpu_props gpu_props; -+ -+ /** List of SW workarounds for HW issues */ -+ unsigned long hw_issues_mask[(BASE_HW_ISSUE_END + BITS_PER_LONG - 1) / BITS_PER_LONG]; -+ /** List of features available */ -+ unsigned long hw_features_mask[(BASE_HW_FEATURE_END + BITS_PER_LONG - 1) / BITS_PER_LONG]; -+ -+ /* Bitmaps of cores that are currently in use (running jobs). -+ * These should be kept up to date by the job scheduler. -+ * -+ * pm.power_change_lock should be held when accessing these members. -+ * -+ * kbase_pm_check_transitions_nolock() should be called when bits are -+ * cleared to update the power management system and allow transitions to -+ * occur. */ -+ u64 shader_inuse_bitmap; -+ -+ /* Refcount for cores in use */ -+ u32 shader_inuse_cnt[64]; -+ -+ /* Bitmaps of cores the JS needs for jobs ready to run */ -+ u64 shader_needed_bitmap; -+ -+ /* Refcount for cores needed */ -+ u32 shader_needed_cnt[64]; -+ -+ u32 tiler_inuse_cnt; -+ -+ u32 tiler_needed_cnt; -+ -+ /* struct for keeping track of the disjoint information -+ * -+ * The state is > 0 if the GPU is in a disjoint state. Otherwise 0 -+ * The count is the number of disjoint events that have occurred on the GPU -+ */ -+ struct { -+ atomic_t count; -+ atomic_t state; -+ } disjoint_event; -+ -+ /* Refcount for tracking users of the l2 cache, e.g. when using hardware counter instrumentation. */ -+ u32 l2_users_count; -+ -+ /* Bitmaps of cores that are currently available (powered up and the power policy is happy for jobs to be -+ * submitted to these cores. These are updated by the power management code. The job scheduler should avoid -+ * submitting new jobs to any cores that are not marked as available. -+ * -+ * pm.power_change_lock should be held when accessing these members. -+ */ -+ u64 shader_available_bitmap; -+ u64 tiler_available_bitmap; -+ u64 l2_available_bitmap; -+ u64 stack_available_bitmap; -+ -+ u64 shader_ready_bitmap; -+ u64 shader_transitioning_bitmap; -+ -+ s8 nr_hw_address_spaces; /**< Number of address spaces in the GPU (constant after driver initialisation) */ -+ s8 nr_user_address_spaces; /**< Number of address spaces available to user contexts */ -+ -+ /* Structure used for instrumentation and HW counters dumping */ -+ struct kbase_hwcnt { -+ /* The lock should be used when accessing any of the following members */ -+ spinlock_t lock; -+ -+ struct kbase_context *kctx; -+ u64 addr; -+ -+ struct kbase_instr_backend backend; -+ } hwcnt; -+ -+ struct kbase_vinstr_context *vinstr_ctx; -+ -+#if KBASE_TRACE_ENABLE -+ spinlock_t trace_lock; -+ u16 trace_first_out; -+ u16 trace_next_in; -+ struct kbase_trace *trace_rbuf; -+#endif -+ -+ u32 reset_timeout_ms; -+ -+ struct mutex cacheclean_lock; -+ -+ /* Platform specific private data to be accessed by mali_kbase_config_xxx.c only */ -+ void *platform_context; -+ -+ /* List of kbase_contexts created */ -+ struct list_head kctx_list; -+ struct mutex kctx_list_lock; -+ -+#ifdef CONFIG_MALI_DEVFREQ -+ struct devfreq_dev_profile devfreq_profile; -+ struct devfreq *devfreq; -+ unsigned long current_freq; -+ unsigned long current_nominal_freq; -+ unsigned long current_voltage; -+ u64 current_core_mask; -+ struct kbase_devfreq_opp *opp_table; -+ int num_opps; -+#ifdef CONFIG_DEVFREQ_THERMAL -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) -+ struct devfreq_cooling_device *devfreq_cooling; -+#else -+ struct thermal_cooling_device *devfreq_cooling; -+#endif -+ /* Current IPA model - true for configured model, false for fallback */ -+ atomic_t ipa_use_configured_model; -+ struct { -+ /* Access to this struct must be with ipa.lock held */ -+ struct mutex lock; -+ struct kbase_ipa_model *configured_model; -+ struct kbase_ipa_model *fallback_model; -+ } ipa; -+#endif /* CONFIG_DEVFREQ_THERMAL */ -+#endif /* CONFIG_MALI_DEVFREQ */ -+ -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+ struct kbase_trace_kbdev_timeline timeline; -+#endif -+ -+ /* -+ * Control for enabling job dump on failure, set when control debugfs -+ * is opened. -+ */ -+ bool job_fault_debug; -+ -+#ifdef CONFIG_DEBUG_FS -+ /* directory for debugfs entries */ -+ struct dentry *mali_debugfs_directory; -+ /* Root directory for per context entry */ -+ struct dentry *debugfs_ctx_directory; -+ -+#ifdef CONFIG_MALI_DEBUG -+ /* bit for each as, set if there is new data to report */ -+ u64 debugfs_as_read_bitmap; -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ /* failed job dump, used for separate debug process */ -+ wait_queue_head_t job_fault_wq; -+ wait_queue_head_t job_fault_resume_wq; -+ struct workqueue_struct *job_fault_resume_workq; -+ struct list_head job_fault_event_list; -+ spinlock_t job_fault_event_lock; -+ struct kbase_context *kctx_fault; -+ -+#if !MALI_CUSTOMER_RELEASE -+ /* Per-device data for register dumping interface */ -+ struct { -+ u16 reg_offset; /* Offset of a GPU_CONTROL register to be -+ dumped upon request */ -+ } regs_dump_debugfs_data; -+#endif /* !MALI_CUSTOMER_RELEASE */ -+#endif /* CONFIG_DEBUG_FS */ -+ -+ /* fbdump profiling controls set by gator */ -+ u32 kbase_profiling_controls[FBDUMP_CONTROL_MAX]; -+ -+ -+#if MALI_CUSTOMER_RELEASE == 0 -+ /* Number of jobs that are run before a job is forced to fail and -+ * replay. May be KBASEP_FORCE_REPLAY_DISABLED, to disable forced -+ * failures. */ -+ int force_replay_limit; -+ /* Count of jobs between forced failures. Incremented on each job. A -+ * job is forced to fail once this is greater than or equal to -+ * force_replay_limit. */ -+ int force_replay_count; -+ /* Core requirement for jobs to be failed and replayed. May be zero. */ -+ base_jd_core_req force_replay_core_req; -+ /* true if force_replay_limit should be randomized. The random -+ * value will be in the range of 1 - KBASEP_FORCE_REPLAY_RANDOM_LIMIT. -+ */ -+ bool force_replay_random; -+#endif -+ -+ /* Total number of created contexts */ -+ atomic_t ctx_num; -+ -+#ifdef CONFIG_DEBUG_FS -+ /* Holds the most recent register accesses */ -+ struct kbase_io_history io_history; -+#endif /* CONFIG_DEBUG_FS */ -+ -+ struct kbase_hwaccess_data hwaccess; -+ -+ /* Count of page/bus faults waiting for workqueues to process */ -+ atomic_t faults_pending; -+ -+ /* true if GPU is powered off or power off operation is in progress */ -+ bool poweroff_pending; -+ -+ -+ /* defaults for new context created for this device */ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) -+ bool infinite_cache_active_default; -+#else -+ u32 infinite_cache_active_default; -+#endif -+ size_t mem_pool_max_size_default; -+ -+ /* current gpu coherency mode */ -+ u32 current_gpu_coherency_mode; -+ /* system coherency mode */ -+ u32 system_coherency; -+ /* Flag to track when cci snoops have been enabled on the interface */ -+ bool cci_snoop_enabled; -+ -+ /* SMC function IDs to call into Trusted firmware to enable/disable -+ * cache snooping. Value of 0 indicates that they are not used -+ */ -+ u32 snoop_enable_smc; -+ u32 snoop_disable_smc; -+ -+ /* Protected mode operations */ -+ struct protected_mode_ops *protected_ops; -+ -+ /* Protected device attached to this kbase device */ -+ struct protected_mode_device *protected_dev; -+ -+ /* -+ * true when GPU is put into protected mode -+ */ -+ bool protected_mode; -+ -+ /* -+ * true when GPU is transitioning into or out of protected mode -+ */ -+ bool protected_mode_transition; -+ -+ /* -+ * true if protected mode is supported -+ */ -+ bool protected_mode_support; -+ -+ -+#ifdef CONFIG_MALI_DEBUG -+ wait_queue_head_t driver_inactive_wait; -+ bool driver_inactive; -+#endif /* CONFIG_MALI_DEBUG */ -+ -+#ifdef CONFIG_MALI_FPGA_BUS_LOGGER -+ /* -+ * Bus logger integration. -+ */ -+ struct bus_logger_client *buslogger; -+#endif -+ /* Boolean indicating if an IRQ flush during reset is in progress. */ -+ bool irq_reset_flush; -+ -+ /* list of inited sub systems. Used during terminate/error recovery */ -+ u32 inited_subsys; -+ -+ spinlock_t hwaccess_lock; -+ -+ /* Protects access to MMU operations */ -+ struct mutex mmu_hw_mutex; -+ -+ /* Current serialization mode. See KBASE_SERIALIZE_* for details */ -+ u8 serialize_jobs; -+}; -+ -+/** -+ * struct jsctx_queue - JS context atom queue -+ * @runnable_tree: Root of RB-tree containing currently runnable atoms on this -+ * job slot. -+ * @x_dep_head: Head item of the linked list of atoms blocked on cross-slot -+ * dependencies. Atoms on this list will be moved to the -+ * runnable_tree when the blocking atom completes. -+ * -+ * hwaccess_lock must be held when accessing this structure. -+ */ -+struct jsctx_queue { -+ struct rb_root runnable_tree; -+ struct list_head x_dep_head; -+}; -+ -+ -+#define KBASE_API_VERSION(major, minor) ((((major) & 0xFFF) << 20) | \ -+ (((minor) & 0xFFF) << 8) | \ -+ ((0 & 0xFF) << 0)) -+ -+/** -+ * enum kbase_context_flags - Flags for kbase contexts -+ * -+ * @KCTX_COMPAT: Set when the context process is a compat process, 32-bit -+ * process on a 64-bit kernel. -+ * -+ * @KCTX_RUNNABLE_REF: Set when context is counted in -+ * kbdev->js_data.nr_contexts_runnable. Must hold queue_mutex when accessing. -+ * -+ * @KCTX_ACTIVE: Set when the context is active. -+ * -+ * @KCTX_PULLED: Set when last kick() caused atoms to be pulled from this -+ * context. -+ * -+ * @KCTX_MEM_PROFILE_INITIALIZED: Set when the context's memory profile has been -+ * initialized. -+ * -+ * @KCTX_INFINITE_CACHE: Set when infinite cache is to be enabled for new -+ * allocations. Existing allocations will not change. -+ * -+ * @KCTX_SUBMIT_DISABLED: Set to prevent context from submitting any jobs. -+ * -+ * @KCTX_PRIVILEGED:Set if the context uses an address space and should be kept -+ * scheduled in. -+ * -+ * @KCTX_SCHEDULED: Set when the context is scheduled on the Run Pool. -+ * This is only ever updated whilst the jsctx_mutex is held. -+ * -+ * @KCTX_DYING: Set when the context process is in the process of being evicted. -+ * -+ * @KCTX_NO_IMPLICIT_SYNC: Set when explicit Android fences are in use on this -+ * context, to disable use of implicit dma-buf fences. This is used to avoid -+ * potential synchronization deadlocks. -+ * -+ * All members need to be separate bits. This enum is intended for use in a -+ * bitmask where multiple values get OR-ed together. -+ */ -+enum kbase_context_flags { -+ KCTX_COMPAT = 1U << 0, -+ KCTX_RUNNABLE_REF = 1U << 1, -+ KCTX_ACTIVE = 1U << 2, -+ KCTX_PULLED = 1U << 3, -+ KCTX_MEM_PROFILE_INITIALIZED = 1U << 4, -+ KCTX_INFINITE_CACHE = 1U << 5, -+ KCTX_SUBMIT_DISABLED = 1U << 6, -+ KCTX_PRIVILEGED = 1U << 7, -+ KCTX_SCHEDULED = 1U << 8, -+ KCTX_DYING = 1U << 9, -+ KCTX_NO_IMPLICIT_SYNC = 1U << 10, -+}; -+ -+struct kbase_sub_alloc { -+ struct list_head link; -+ struct page *page; -+ DECLARE_BITMAP(sub_pages, SZ_2M / SZ_4K); -+}; -+ -+struct kbase_context { -+ struct file *filp; -+ struct kbase_device *kbdev; -+ int id; /* System wide unique id */ -+ unsigned long api_version; -+ phys_addr_t pgd; -+ struct list_head event_list; -+ struct list_head event_coalesce_list; -+ struct mutex event_mutex; -+ atomic_t event_closed; -+ struct workqueue_struct *event_workq; -+ atomic_t event_count; -+ int event_coalesce_count; -+ -+ atomic_t flags; -+ -+ atomic_t setup_complete; -+ atomic_t setup_in_progress; -+ -+ u64 *mmu_teardown_pages; -+ -+ struct tagged_addr aliasing_sink_page; -+ -+ struct mutex mem_partials_lock; -+ struct list_head mem_partials; -+ -+ struct mutex mmu_lock; -+ struct mutex reg_lock; /* To be converted to a rwlock? */ -+ struct rb_root reg_rbtree_same; /* RB tree of GPU (live) regions, -+ * SAME_VA zone */ -+ struct rb_root reg_rbtree_exec; /* RB tree of GPU (live) regions, -+ * EXEC zone */ -+ struct rb_root reg_rbtree_custom; /* RB tree of GPU (live) regions, -+ * CUSTOM_VA zone */ -+ -+ unsigned long cookies; -+ struct kbase_va_region *pending_regions[BITS_PER_LONG]; -+ -+ wait_queue_head_t event_queue; -+ pid_t tgid; -+ pid_t pid; -+ -+ struct kbase_jd_context jctx; -+ atomic_t used_pages; -+ atomic_t nonmapped_pages; -+ -+ struct kbase_mem_pool mem_pool; -+ struct kbase_mem_pool lp_mem_pool; -+ -+ struct shrinker reclaim; -+ struct list_head evict_list; -+ -+ struct list_head waiting_soft_jobs; -+ spinlock_t waiting_soft_jobs_lock; -+#ifdef CONFIG_KDS -+ struct list_head waiting_kds_resource; -+#endif -+#ifdef CONFIG_MALI_DMA_FENCE -+ struct { -+ struct list_head waiting_resource; -+ struct workqueue_struct *wq; -+ } dma_fence; -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ /** This is effectively part of the Run Pool, because it only has a valid -+ * setting (!=KBASEP_AS_NR_INVALID) whilst the context is scheduled in -+ * -+ * The hwaccess_lock must be held whilst accessing this. -+ * -+ * If the context relating to this as_nr is required, you must use -+ * kbasep_js_runpool_retain_ctx() to ensure that the context doesn't disappear -+ * whilst you're using it. Alternatively, just hold the hwaccess_lock -+ * to ensure the context doesn't disappear (but this has restrictions on what other locks -+ * you can take whilst doing this) */ -+ int as_nr; -+ -+ /* Keeps track of the number of users of this context. A user can be a -+ * job that is available for execution, instrumentation needing to 'pin' -+ * a context for counter collection, etc. If the refcount reaches 0 then -+ * this context is considered inactive and the previously programmed -+ * AS might be cleared at any point. -+ */ -+ atomic_t refcount; -+ -+ /* NOTE: -+ * -+ * Flags are in jctx.sched_info.ctx.flags -+ * Mutable flags *must* be accessed under jctx.sched_info.ctx.jsctx_mutex -+ * -+ * All other flags must be added there */ -+ spinlock_t mm_update_lock; -+ struct mm_struct *process_mm; -+ /* End of the SAME_VA zone */ -+ u64 same_va_end; -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+ struct kbase_trace_kctx_timeline timeline; -+#endif -+#ifdef CONFIG_DEBUG_FS -+ /* Content of mem_profile file */ -+ char *mem_profile_data; -+ /* Size of @c mem_profile_data */ -+ size_t mem_profile_size; -+ /* Mutex guarding memory profile state */ -+ struct mutex mem_profile_lock; -+ /* Memory profile directory under debugfs */ -+ struct dentry *kctx_dentry; -+ -+ /* for job fault debug */ -+ unsigned int *reg_dump; -+ atomic_t job_fault_count; -+ /* This list will keep the following atoms during the dump -+ * in the same context -+ */ -+ struct list_head job_fault_resume_event_list; -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+ struct jsctx_queue jsctx_queue -+ [KBASE_JS_ATOM_SCHED_PRIO_COUNT][BASE_JM_MAX_NR_SLOTS]; -+ -+ /* Number of atoms currently pulled from this context */ -+ atomic_t atoms_pulled; -+ /* Number of atoms currently pulled from this context, per slot */ -+ atomic_t atoms_pulled_slot[BASE_JM_MAX_NR_SLOTS]; -+ /* Number of atoms currently pulled from this context, per slot and -+ * priority. Hold hwaccess_lock when accessing */ -+ int atoms_pulled_slot_pri[BASE_JM_MAX_NR_SLOTS][ -+ KBASE_JS_ATOM_SCHED_PRIO_COUNT]; -+ -+ /* true if slot is blocked on the given priority. This will be set on a -+ * soft-stop */ -+ bool blocked_js[BASE_JM_MAX_NR_SLOTS][KBASE_JS_ATOM_SCHED_PRIO_COUNT]; -+ -+ /* Bitmask of slots that can be pulled from */ -+ u32 slots_pullable; -+ -+ /* Backend specific data */ -+ struct kbase_context_backend backend; -+ -+ /* Work structure used for deferred ASID assignment */ -+ struct work_struct work; -+ -+ /* Only one userspace vinstr client per kbase context */ -+ struct kbase_vinstr_client *vinstr_cli; -+ struct mutex vinstr_cli_lock; -+ -+ /* List of completed jobs waiting for events to be posted */ -+ struct list_head completed_jobs; -+ /* Number of work items currently pending on job_done_wq */ -+ atomic_t work_count; -+ -+ /* Waiting soft-jobs will fail when this timer expires */ -+ struct timer_list soft_job_timeout; -+ -+ /* JIT allocation management */ -+ struct kbase_va_region *jit_alloc[256]; -+ struct list_head jit_active_head; -+ struct list_head jit_pool_head; -+ struct list_head jit_destroy_head; -+ struct mutex jit_evict_lock; -+ struct work_struct jit_work; -+ -+ /* A list of the JIT soft-jobs in submission order -+ * (protected by kbase_jd_context.lock) -+ */ -+ struct list_head jit_atoms_head; -+ /* A list of pending JIT alloc soft-jobs (using the 'queue' list_head) -+ * (protected by kbase_jd_context.lock) -+ */ -+ struct list_head jit_pending_alloc; -+ -+ /* External sticky resource management */ -+ struct list_head ext_res_meta_head; -+ -+ /* Used to record that a drain was requested from atomic context */ -+ atomic_t drain_pending; -+ -+ /* Current age count, used to determine age for newly submitted atoms */ -+ u32 age_count; -+}; -+ -+/** -+ * struct kbase_ctx_ext_res_meta - Structure which binds an external resource -+ * to a @kbase_context. -+ * @ext_res_node: List head for adding the metadata to a -+ * @kbase_context. -+ * @alloc: The physical memory allocation structure -+ * which is mapped. -+ * @gpu_addr: The GPU virtual address the resource is -+ * mapped to. -+ * -+ * External resources can be mapped into multiple contexts as well as the same -+ * context multiple times. -+ * As kbase_va_region itself isn't refcounted we can't attach our extra -+ * information to it as it could be removed under our feet leaving external -+ * resources pinned. -+ * This metadata structure binds a single external resource to a single -+ * context, ensuring that per context mapping is tracked separately so it can -+ * be overridden when needed and abuses by the application (freeing the resource -+ * multiple times) don't effect the refcount of the physical allocation. -+ */ -+struct kbase_ctx_ext_res_meta { -+ struct list_head ext_res_node; -+ struct kbase_mem_phy_alloc *alloc; -+ u64 gpu_addr; -+}; -+ -+enum kbase_reg_access_type { -+ REG_READ, -+ REG_WRITE -+}; -+ -+enum kbase_share_attr_bits { -+ /* (1ULL << 8) bit is reserved */ -+ SHARE_BOTH_BITS = (2ULL << 8), /* inner and outer shareable coherency */ -+ SHARE_INNER_BITS = (3ULL << 8) /* inner shareable coherency */ -+}; -+ -+/** -+ * kbase_device_is_cpu_coherent - Returns if the device is CPU coherent. -+ * @kbdev: kbase device -+ * -+ * Return: true if the device access are coherent, false if not. -+ */ -+static inline bool kbase_device_is_cpu_coherent(struct kbase_device *kbdev) -+{ -+ if ((kbdev->system_coherency == COHERENCY_ACE_LITE) || -+ (kbdev->system_coherency == COHERENCY_ACE)) -+ return true; -+ -+ return false; -+} -+ -+/* Conversion helpers for setting up high resolution timers */ -+#define HR_TIMER_DELAY_MSEC(x) (ns_to_ktime(((u64)(x))*1000000U)) -+#define HR_TIMER_DELAY_NSEC(x) (ns_to_ktime(x)) -+ -+/* Maximum number of loops polling the GPU for a cache flush before we assume it must have completed */ -+#define KBASE_CLEAN_CACHE_MAX_LOOPS 100000 -+/* Maximum number of loops polling the GPU for an AS command to complete before we assume the GPU has hung */ -+#define KBASE_AS_INACTIVE_MAX_LOOPS 100000 -+ -+/* Maximum number of times a job can be replayed */ -+#define BASEP_JD_REPLAY_LIMIT 15 -+ -+/* JobDescriptorHeader - taken from the architecture specifications, the layout -+ * is currently identical for all GPU archs. */ -+struct job_descriptor_header { -+ u32 exception_status; -+ u32 first_incomplete_task; -+ u64 fault_pointer; -+ u8 job_descriptor_size : 1; -+ u8 job_type : 7; -+ u8 job_barrier : 1; -+ u8 _reserved_01 : 1; -+ u8 _reserved_1 : 1; -+ u8 _reserved_02 : 1; -+ u8 _reserved_03 : 1; -+ u8 _reserved_2 : 1; -+ u8 _reserved_04 : 1; -+ u8 _reserved_05 : 1; -+ u16 job_index; -+ u16 job_dependency_index_1; -+ u16 job_dependency_index_2; -+ union { -+ u64 _64; -+ u32 _32; -+ } next_job; -+}; -+ -+#endif /* _KBASE_DEFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_device.c b/drivers/gpu/arm/midgard/mali_kbase_device.c -new file mode 100644 -index 0000000..d635fcc ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_device.c -@@ -0,0 +1,674 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Base kernel device APIs -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* NOTE: Magic - 0x45435254 (TRCE in ASCII). -+ * Supports tracing feature provided in the base module. -+ * Please keep it in sync with the value of base module. -+ */ -+#define TRACE_BUFFER_HEADER_SPECIAL 0x45435254 -+ -+#if KBASE_TRACE_ENABLE -+static const char *kbasep_trace_code_string[] = { -+ /* IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE -+ * THIS MUST BE USED AT THE START OF THE ARRAY */ -+#define KBASE_TRACE_CODE_MAKE_CODE(X) # X -+#include "mali_kbase_trace_defs.h" -+#undef KBASE_TRACE_CODE_MAKE_CODE -+}; -+#endif -+ -+#define DEBUG_MESSAGE_SIZE 256 -+ -+static int kbasep_trace_init(struct kbase_device *kbdev); -+static void kbasep_trace_term(struct kbase_device *kbdev); -+static void kbasep_trace_hook_wrapper(void *param); -+ -+struct kbase_device *kbase_device_alloc(void) -+{ -+ return kzalloc(sizeof(struct kbase_device), GFP_KERNEL); -+} -+ -+static int kbase_device_as_init(struct kbase_device *kbdev, int i) -+{ -+ const char format[] = "mali_mmu%d"; -+ char name[sizeof(format)]; -+ const char poke_format[] = "mali_mmu%d_poker"; -+ char poke_name[sizeof(poke_format)]; -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316)) -+ snprintf(poke_name, sizeof(poke_name), poke_format, i); -+ -+ snprintf(name, sizeof(name), format, i); -+ -+ kbdev->as[i].number = i; -+ kbdev->as[i].fault_addr = 0ULL; -+ -+ kbdev->as[i].pf_wq = alloc_workqueue(name, 0, 1); -+ if (!kbdev->as[i].pf_wq) -+ return -EINVAL; -+ -+ INIT_WORK(&kbdev->as[i].work_pagefault, page_fault_worker); -+ INIT_WORK(&kbdev->as[i].work_busfault, bus_fault_worker); -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316)) { -+ struct hrtimer *poke_timer = &kbdev->as[i].poke_timer; -+ struct work_struct *poke_work = &kbdev->as[i].poke_work; -+ -+ kbdev->as[i].poke_wq = alloc_workqueue(poke_name, 0, 1); -+ if (!kbdev->as[i].poke_wq) { -+ destroy_workqueue(kbdev->as[i].pf_wq); -+ return -EINVAL; -+ } -+ KBASE_DEBUG_ASSERT(!object_is_on_stack(poke_work)); -+ INIT_WORK(poke_work, kbasep_as_do_poke); -+ -+ hrtimer_init(poke_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ -+ poke_timer->function = kbasep_as_poke_timer_callback; -+ -+ kbdev->as[i].poke_refcount = 0; -+ kbdev->as[i].poke_state = 0u; -+ } -+ -+ return 0; -+} -+ -+static void kbase_device_as_term(struct kbase_device *kbdev, int i) -+{ -+ destroy_workqueue(kbdev->as[i].pf_wq); -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316)) -+ destroy_workqueue(kbdev->as[i].poke_wq); -+} -+ -+static int kbase_device_all_as_init(struct kbase_device *kbdev) -+{ -+ int i, err; -+ -+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++) { -+ err = kbase_device_as_init(kbdev, i); -+ if (err) -+ goto free_workqs; -+ } -+ -+ return 0; -+ -+free_workqs: -+ for (; i > 0; i--) -+ kbase_device_as_term(kbdev, i); -+ -+ return err; -+} -+ -+static void kbase_device_all_as_term(struct kbase_device *kbdev) -+{ -+ int i; -+ -+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++) -+ kbase_device_as_term(kbdev, i); -+} -+ -+int kbase_device_init(struct kbase_device * const kbdev) -+{ -+ int i, err; -+#ifdef CONFIG_ARM64 -+ struct device_node *np = NULL; -+#endif /* CONFIG_ARM64 */ -+ -+ spin_lock_init(&kbdev->mmu_mask_change); -+ mutex_init(&kbdev->mmu_hw_mutex); -+#ifdef CONFIG_ARM64 -+ kbdev->cci_snoop_enabled = false; -+ np = kbdev->dev->of_node; -+ if (np != NULL) { -+ if (of_property_read_u32(np, "snoop_enable_smc", -+ &kbdev->snoop_enable_smc)) -+ kbdev->snoop_enable_smc = 0; -+ if (of_property_read_u32(np, "snoop_disable_smc", -+ &kbdev->snoop_disable_smc)) -+ kbdev->snoop_disable_smc = 0; -+ /* Either both or none of the calls should be provided. */ -+ if (!((kbdev->snoop_disable_smc == 0 -+ && kbdev->snoop_enable_smc == 0) -+ || (kbdev->snoop_disable_smc != 0 -+ && kbdev->snoop_enable_smc != 0))) { -+ WARN_ON(1); -+ err = -EINVAL; -+ goto fail; -+ } -+ } -+#endif /* CONFIG_ARM64 */ -+ /* Get the list of workarounds for issues on the current HW -+ * (identified by the GPU_ID register) -+ */ -+ err = kbase_hw_set_issues_mask(kbdev); -+ if (err) -+ goto fail; -+ -+ /* Set the list of features available on the current HW -+ * (identified by the GPU_ID register) -+ */ -+ kbase_hw_set_features_mask(kbdev); -+ -+ kbase_gpuprops_set_features(kbdev); -+ -+ /* On Linux 4.0+, dma coherency is determined from device tree */ -+#if defined(CONFIG_ARM64) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) -+ set_dma_ops(kbdev->dev, &noncoherent_swiotlb_dma_ops); -+#endif -+ -+ /* Workaround a pre-3.13 Linux issue, where dma_mask is NULL when our -+ * device structure was created by device-tree -+ */ -+ if (!kbdev->dev->dma_mask) -+ kbdev->dev->dma_mask = &kbdev->dev->coherent_dma_mask; -+ -+ err = dma_set_mask(kbdev->dev, -+ DMA_BIT_MASK(kbdev->gpu_props.mmu.pa_bits)); -+ if (err) -+ goto dma_set_mask_failed; -+ -+ err = dma_set_coherent_mask(kbdev->dev, -+ DMA_BIT_MASK(kbdev->gpu_props.mmu.pa_bits)); -+ if (err) -+ goto dma_set_mask_failed; -+ -+ kbdev->nr_hw_address_spaces = kbdev->gpu_props.num_address_spaces; -+ -+ err = kbase_device_all_as_init(kbdev); -+ if (err) -+ goto as_init_failed; -+ -+ spin_lock_init(&kbdev->hwcnt.lock); -+ -+ err = kbasep_trace_init(kbdev); -+ if (err) -+ goto term_as; -+ -+ mutex_init(&kbdev->cacheclean_lock); -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+ for (i = 0; i < BASE_JM_MAX_NR_SLOTS; ++i) -+ kbdev->timeline.slot_atoms_submitted[i] = 0; -+ -+ for (i = 0; i <= KBASEP_TIMELINE_PM_EVENT_LAST; ++i) -+ atomic_set(&kbdev->timeline.pm_event_uid[i], 0); -+#endif /* CONFIG_MALI_TRACE_TIMELINE */ -+ -+ /* fbdump profiling controls set to 0 - fbdump not enabled until changed by gator */ -+ for (i = 0; i < FBDUMP_CONTROL_MAX; i++) -+ kbdev->kbase_profiling_controls[i] = 0; -+ -+ kbase_debug_assert_register_hook(&kbasep_trace_hook_wrapper, kbdev); -+ -+ atomic_set(&kbdev->ctx_num, 0); -+ -+ err = kbase_instr_backend_init(kbdev); -+ if (err) -+ goto term_trace; -+ -+ kbdev->pm.dvfs_period = DEFAULT_PM_DVFS_PERIOD; -+ -+ kbdev->reset_timeout_ms = DEFAULT_RESET_TIMEOUT_MS; -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ kbdev->mmu_mode = kbase_mmu_mode_get_aarch64(); -+ else -+ kbdev->mmu_mode = kbase_mmu_mode_get_lpae(); -+ -+#ifdef CONFIG_MALI_DEBUG -+ init_waitqueue_head(&kbdev->driver_inactive_wait); -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ return 0; -+term_trace: -+ kbasep_trace_term(kbdev); -+term_as: -+ kbase_device_all_as_term(kbdev); -+as_init_failed: -+dma_set_mask_failed: -+fail: -+ return err; -+} -+ -+void kbase_device_term(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+#if KBASE_TRACE_ENABLE -+ kbase_debug_assert_register_hook(NULL, NULL); -+#endif -+ -+ kbase_instr_backend_term(kbdev); -+ -+ kbasep_trace_term(kbdev); -+ -+ kbase_device_all_as_term(kbdev); -+} -+ -+void kbase_device_free(struct kbase_device *kbdev) -+{ -+ kfree(kbdev); -+} -+ -+int kbase_device_trace_buffer_install( -+ struct kbase_context *kctx, u32 *tb, size_t size) -+{ -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(tb); -+ -+ /* Interface uses 16-bit value to track last accessed entry. Each entry -+ * is composed of two 32-bit words. -+ * This limits the size that can be handled without an overflow. */ -+ if (0xFFFF * (2 * sizeof(u32)) < size) -+ return -EINVAL; -+ -+ /* set up the header */ -+ /* magic number in the first 4 bytes */ -+ tb[0] = TRACE_BUFFER_HEADER_SPECIAL; -+ /* Store (write offset = 0, wrap counter = 0, transaction active = no) -+ * write offset 0 means never written. -+ * Offsets 1 to (wrap_offset - 1) used to store values when trace started -+ */ -+ tb[1] = 0; -+ -+ /* install trace buffer */ -+ spin_lock_irqsave(&kctx->jctx.tb_lock, flags); -+ kctx->jctx.tb_wrap_offset = size / 8; -+ kctx->jctx.tb = tb; -+ spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags); -+ -+ return 0; -+} -+ -+void kbase_device_trace_buffer_uninstall(struct kbase_context *kctx) -+{ -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ spin_lock_irqsave(&kctx->jctx.tb_lock, flags); -+ kctx->jctx.tb = NULL; -+ kctx->jctx.tb_wrap_offset = 0; -+ spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags); -+} -+ -+void kbase_device_trace_register_access(struct kbase_context *kctx, enum kbase_reg_access_type type, u16 reg_offset, u32 reg_value) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kctx->jctx.tb_lock, flags); -+ if (kctx->jctx.tb) { -+ u16 wrap_count; -+ u16 write_offset; -+ u32 *tb = kctx->jctx.tb; -+ u32 header_word; -+ -+ header_word = tb[1]; -+ KBASE_DEBUG_ASSERT(0 == (header_word & 0x1)); -+ -+ wrap_count = (header_word >> 1) & 0x7FFF; -+ write_offset = (header_word >> 16) & 0xFFFF; -+ -+ /* mark as transaction in progress */ -+ tb[1] |= 0x1; -+ mb(); -+ -+ /* calculate new offset */ -+ write_offset++; -+ if (write_offset == kctx->jctx.tb_wrap_offset) { -+ /* wrap */ -+ write_offset = 1; -+ wrap_count++; -+ wrap_count &= 0x7FFF; /* 15bit wrap counter */ -+ } -+ -+ /* store the trace entry at the selected offset */ -+ tb[write_offset * 2 + 0] = (reg_offset & ~0x3) | ((type == REG_WRITE) ? 0x1 : 0x0); -+ tb[write_offset * 2 + 1] = reg_value; -+ mb(); -+ -+ /* new header word */ -+ header_word = (write_offset << 16) | (wrap_count << 1) | 0x0; /* transaction complete */ -+ tb[1] = header_word; -+ } -+ spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags); -+} -+ -+/* -+ * Device trace functions -+ */ -+#if KBASE_TRACE_ENABLE -+ -+static int kbasep_trace_init(struct kbase_device *kbdev) -+{ -+ struct kbase_trace *rbuf; -+ -+ rbuf = kmalloc_array(KBASE_TRACE_SIZE, sizeof(*rbuf), GFP_KERNEL); -+ -+ if (!rbuf) -+ return -EINVAL; -+ -+ kbdev->trace_rbuf = rbuf; -+ spin_lock_init(&kbdev->trace_lock); -+ return 0; -+} -+ -+static void kbasep_trace_term(struct kbase_device *kbdev) -+{ -+ kfree(kbdev->trace_rbuf); -+} -+ -+static void kbasep_trace_format_msg(struct kbase_trace *trace_msg, char *buffer, int len) -+{ -+ s32 written = 0; -+ -+ /* Initial part of message */ -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), "%d.%.6d,%d,%d,%s,%p,", (int)trace_msg->timestamp.tv_sec, (int)(trace_msg->timestamp.tv_nsec / 1000), trace_msg->thread_id, trace_msg->cpu, kbasep_trace_code_string[trace_msg->code], trace_msg->ctx), 0); -+ -+ if (trace_msg->katom) -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), "atom %d (ud: 0x%llx 0x%llx)", trace_msg->atom_number, trace_msg->atom_udata[0], trace_msg->atom_udata[1]), 0); -+ -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), ",%.8llx,", trace_msg->gpu_addr), 0); -+ -+ /* NOTE: Could add function callbacks to handle different message types */ -+ /* Jobslot present */ -+ if (trace_msg->flags & KBASE_TRACE_FLAG_JOBSLOT) -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), "%d", trace_msg->jobslot), 0); -+ -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), ","), 0); -+ -+ /* Refcount present */ -+ if (trace_msg->flags & KBASE_TRACE_FLAG_REFCOUNT) -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), "%d", trace_msg->refcount), 0); -+ -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), ","), 0); -+ -+ /* Rest of message */ -+ written += MAX(snprintf(buffer + written, MAX(len - written, 0), "0x%.8lx", trace_msg->info_val), 0); -+} -+ -+static void kbasep_trace_dump_msg(struct kbase_device *kbdev, struct kbase_trace *trace_msg) -+{ -+ char buffer[DEBUG_MESSAGE_SIZE]; -+ -+ kbasep_trace_format_msg(trace_msg, buffer, DEBUG_MESSAGE_SIZE); -+ dev_dbg(kbdev->dev, "%s", buffer); -+} -+ -+void kbasep_trace_add(struct kbase_device *kbdev, enum kbase_trace_code code, void *ctx, struct kbase_jd_atom *katom, u64 gpu_addr, u8 flags, int refcount, int jobslot, unsigned long info_val) -+{ -+ unsigned long irqflags; -+ struct kbase_trace *trace_msg; -+ -+ spin_lock_irqsave(&kbdev->trace_lock, irqflags); -+ -+ trace_msg = &kbdev->trace_rbuf[kbdev->trace_next_in]; -+ -+ /* Fill the message */ -+ trace_msg->thread_id = task_pid_nr(current); -+ trace_msg->cpu = task_cpu(current); -+ -+ getnstimeofday(&trace_msg->timestamp); -+ -+ trace_msg->code = code; -+ trace_msg->ctx = ctx; -+ -+ if (NULL == katom) { -+ trace_msg->katom = false; -+ } else { -+ trace_msg->katom = true; -+ trace_msg->atom_number = kbase_jd_atom_id(katom->kctx, katom); -+ trace_msg->atom_udata[0] = katom->udata.blob[0]; -+ trace_msg->atom_udata[1] = katom->udata.blob[1]; -+ } -+ -+ trace_msg->gpu_addr = gpu_addr; -+ trace_msg->jobslot = jobslot; -+ trace_msg->refcount = MIN((unsigned int)refcount, 0xFF); -+ trace_msg->info_val = info_val; -+ trace_msg->flags = flags; -+ -+ /* Update the ringbuffer indices */ -+ kbdev->trace_next_in = (kbdev->trace_next_in + 1) & KBASE_TRACE_MASK; -+ if (kbdev->trace_next_in == kbdev->trace_first_out) -+ kbdev->trace_first_out = (kbdev->trace_first_out + 1) & KBASE_TRACE_MASK; -+ -+ /* Done */ -+ -+ spin_unlock_irqrestore(&kbdev->trace_lock, irqflags); -+} -+ -+void kbasep_trace_clear(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->trace_lock, flags); -+ kbdev->trace_first_out = kbdev->trace_next_in; -+ spin_unlock_irqrestore(&kbdev->trace_lock, flags); -+} -+ -+void kbasep_trace_dump(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ u32 start; -+ u32 end; -+ -+ dev_dbg(kbdev->dev, "Dumping trace:\nsecs,nthread,cpu,code,ctx,katom,gpu_addr,jobslot,refcount,info_val"); -+ spin_lock_irqsave(&kbdev->trace_lock, flags); -+ start = kbdev->trace_first_out; -+ end = kbdev->trace_next_in; -+ -+ while (start != end) { -+ struct kbase_trace *trace_msg = &kbdev->trace_rbuf[start]; -+ -+ kbasep_trace_dump_msg(kbdev, trace_msg); -+ -+ start = (start + 1) & KBASE_TRACE_MASK; -+ } -+ dev_dbg(kbdev->dev, "TRACE_END"); -+ -+ spin_unlock_irqrestore(&kbdev->trace_lock, flags); -+ -+ KBASE_TRACE_CLEAR(kbdev); -+} -+ -+static void kbasep_trace_hook_wrapper(void *param) -+{ -+ struct kbase_device *kbdev = (struct kbase_device *)param; -+ -+ kbasep_trace_dump(kbdev); -+} -+ -+#ifdef CONFIG_DEBUG_FS -+struct trace_seq_state { -+ struct kbase_trace trace_buf[KBASE_TRACE_SIZE]; -+ u32 start; -+ u32 end; -+}; -+ -+static void *kbasep_trace_seq_start(struct seq_file *s, loff_t *pos) -+{ -+ struct trace_seq_state *state = s->private; -+ int i; -+ -+ if (*pos > KBASE_TRACE_SIZE) -+ return NULL; -+ i = state->start + *pos; -+ if ((state->end >= state->start && i >= state->end) || -+ i >= state->end + KBASE_TRACE_SIZE) -+ return NULL; -+ -+ i &= KBASE_TRACE_MASK; -+ -+ return &state->trace_buf[i]; -+} -+ -+static void kbasep_trace_seq_stop(struct seq_file *s, void *data) -+{ -+} -+ -+static void *kbasep_trace_seq_next(struct seq_file *s, void *data, loff_t *pos) -+{ -+ struct trace_seq_state *state = s->private; -+ int i; -+ -+ (*pos)++; -+ -+ i = (state->start + *pos) & KBASE_TRACE_MASK; -+ if (i == state->end) -+ return NULL; -+ -+ return &state->trace_buf[i]; -+} -+ -+static int kbasep_trace_seq_show(struct seq_file *s, void *data) -+{ -+ struct kbase_trace *trace_msg = data; -+ char buffer[DEBUG_MESSAGE_SIZE]; -+ -+ kbasep_trace_format_msg(trace_msg, buffer, DEBUG_MESSAGE_SIZE); -+ seq_printf(s, "%s\n", buffer); -+ return 0; -+} -+ -+static const struct seq_operations kbasep_trace_seq_ops = { -+ .start = kbasep_trace_seq_start, -+ .next = kbasep_trace_seq_next, -+ .stop = kbasep_trace_seq_stop, -+ .show = kbasep_trace_seq_show, -+}; -+ -+static int kbasep_trace_debugfs_open(struct inode *inode, struct file *file) -+{ -+ struct kbase_device *kbdev = inode->i_private; -+ unsigned long flags; -+ -+ struct trace_seq_state *state; -+ -+ state = __seq_open_private(file, &kbasep_trace_seq_ops, sizeof(*state)); -+ if (!state) -+ return -ENOMEM; -+ -+ spin_lock_irqsave(&kbdev->trace_lock, flags); -+ state->start = kbdev->trace_first_out; -+ state->end = kbdev->trace_next_in; -+ memcpy(state->trace_buf, kbdev->trace_rbuf, sizeof(state->trace_buf)); -+ spin_unlock_irqrestore(&kbdev->trace_lock, flags); -+ -+ return 0; -+} -+ -+static const struct file_operations kbasep_trace_debugfs_fops = { -+ .open = kbasep_trace_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release_private, -+}; -+ -+void kbasep_trace_debugfs_init(struct kbase_device *kbdev) -+{ -+ debugfs_create_file("mali_trace", S_IRUGO, -+ kbdev->mali_debugfs_directory, kbdev, -+ &kbasep_trace_debugfs_fops); -+} -+ -+#else -+void kbasep_trace_debugfs_init(struct kbase_device *kbdev) -+{ -+} -+#endif /* CONFIG_DEBUG_FS */ -+ -+#else /* KBASE_TRACE_ENABLE */ -+static int kbasep_trace_init(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+ return 0; -+} -+ -+static void kbasep_trace_term(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+static void kbasep_trace_hook_wrapper(void *param) -+{ -+ CSTD_UNUSED(param); -+} -+ -+void kbasep_trace_dump(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+#endif /* KBASE_TRACE_ENABLE */ -+ -+void kbase_set_profiling_control(struct kbase_device *kbdev, u32 control, u32 value) -+{ -+ switch (control) { -+ case FBDUMP_CONTROL_ENABLE: -+ /* fall through */ -+ case FBDUMP_CONTROL_RATE: -+ /* fall through */ -+ case SW_COUNTER_ENABLE: -+ /* fall through */ -+ case FBDUMP_CONTROL_RESIZE_FACTOR: -+ kbdev->kbase_profiling_controls[control] = value; -+ break; -+ default: -+ dev_err(kbdev->dev, "Profiling control %d not found\n", control); -+ break; -+ } -+} -+ -+/* -+ * Called by gator to control the production of -+ * profiling information at runtime -+ * */ -+ -+void _mali_profiling_control(u32 action, u32 value) -+{ -+ struct kbase_device *kbdev = NULL; -+ -+ /* find the first i.e. call with -1 */ -+ kbdev = kbase_find_device(-1); -+ -+ if (NULL != kbdev) -+ kbase_set_profiling_control(kbdev, action, value); -+} -+KBASE_EXPORT_SYMBOL(_mali_profiling_control); -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_disjoint_events.c b/drivers/gpu/arm/midgard/mali_kbase_disjoint_events.c -new file mode 100644 -index 0000000..f70bccc ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_disjoint_events.c -@@ -0,0 +1,76 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Base kernel disjoint events helper functions -+ */ -+ -+#include -+ -+void kbase_disjoint_init(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ atomic_set(&kbdev->disjoint_event.count, 0); -+ atomic_set(&kbdev->disjoint_event.state, 0); -+} -+ -+/* increment the disjoint event count */ -+void kbase_disjoint_event(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ atomic_inc(&kbdev->disjoint_event.count); -+} -+ -+/* increment the state and the event counter */ -+void kbase_disjoint_state_up(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ atomic_inc(&kbdev->disjoint_event.state); -+ -+ kbase_disjoint_event(kbdev); -+} -+ -+/* decrement the state */ -+void kbase_disjoint_state_down(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(atomic_read(&kbdev->disjoint_event.state) > 0); -+ -+ kbase_disjoint_event(kbdev); -+ -+ atomic_dec(&kbdev->disjoint_event.state); -+} -+ -+/* increments the count only if the state is > 0 */ -+void kbase_disjoint_event_potential(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ if (atomic_read(&kbdev->disjoint_event.state)) -+ kbase_disjoint_event(kbdev); -+} -+ -+u32 kbase_disjoint_event_get(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ return atomic_read(&kbdev->disjoint_event.count); -+} -+KBASE_EXPORT_TEST_API(kbase_disjoint_event_get); -diff --git a/drivers/gpu/arm/midgard/mali_kbase_dma_fence.c b/drivers/gpu/arm/midgard/mali_kbase_dma_fence.c -new file mode 100644 -index 0000000..9197743 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_dma_fence.c -@@ -0,0 +1,449 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* Include mali_kbase_dma_fence.h before checking for CONFIG_MALI_DMA_FENCE as -+ * it will be set there. -+ */ -+#include "mali_kbase_dma_fence.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+static void -+kbase_dma_fence_work(struct work_struct *pwork); -+ -+static void -+kbase_dma_fence_waiters_add(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ -+ list_add_tail(&katom->queue, &kctx->dma_fence.waiting_resource); -+} -+ -+static void -+kbase_dma_fence_waiters_remove(struct kbase_jd_atom *katom) -+{ -+ list_del(&katom->queue); -+} -+ -+static int -+kbase_dma_fence_lock_reservations(struct kbase_dma_fence_resv_info *info, -+ struct ww_acquire_ctx *ctx) -+{ -+ struct reservation_object *content_res = NULL; -+ unsigned int content_res_idx = 0; -+ unsigned int r; -+ int err = 0; -+ -+ ww_acquire_init(ctx, &reservation_ww_class); -+ -+retry: -+ for (r = 0; r < info->dma_fence_resv_count; r++) { -+ if (info->resv_objs[r] == content_res) { -+ content_res = NULL; -+ continue; -+ } -+ -+ err = ww_mutex_lock(&info->resv_objs[r]->lock, ctx); -+ if (err) -+ goto error; -+ } -+ -+ ww_acquire_done(ctx); -+ return err; -+ -+error: -+ content_res_idx = r; -+ -+ /* Unlock the locked one ones */ -+ while (r--) -+ ww_mutex_unlock(&info->resv_objs[r]->lock); -+ -+ if (content_res) -+ ww_mutex_unlock(&content_res->lock); -+ -+ /* If we deadlock try with lock_slow and retry */ -+ if (err == -EDEADLK) { -+ content_res = info->resv_objs[content_res_idx]; -+ ww_mutex_lock_slow(&content_res->lock, ctx); -+ goto retry; -+ } -+ -+ /* If we are here the function failed */ -+ ww_acquire_fini(ctx); -+ return err; -+} -+ -+static void -+kbase_dma_fence_unlock_reservations(struct kbase_dma_fence_resv_info *info, -+ struct ww_acquire_ctx *ctx) -+{ -+ unsigned int r; -+ -+ for (r = 0; r < info->dma_fence_resv_count; r++) -+ ww_mutex_unlock(&info->resv_objs[r]->lock); -+ ww_acquire_fini(ctx); -+} -+ -+/** -+ * kbase_dma_fence_queue_work() - Queue work to handle @katom -+ * @katom: Pointer to atom for which to queue work -+ * -+ * Queue kbase_dma_fence_work() for @katom to clean up the fence callbacks and -+ * submit the atom. -+ */ -+static void -+kbase_dma_fence_queue_work(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ bool ret; -+ -+ INIT_WORK(&katom->work, kbase_dma_fence_work); -+ ret = queue_work(kctx->dma_fence.wq, &katom->work); -+ /* Warn if work was already queued, that should not happen. */ -+ WARN_ON(!ret); -+} -+ -+/** -+ * kbase_dma_fence_cancel_atom() - Cancels waiting on an atom -+ * @katom: Katom to cancel -+ * -+ * Locking: katom->dma_fence.callbacks list assumes jctx.lock is held. -+ */ -+static void -+kbase_dma_fence_cancel_atom(struct kbase_jd_atom *katom) -+{ -+ lockdep_assert_held(&katom->kctx->jctx.lock); -+ -+ /* Cancel callbacks and clean up. */ -+ kbase_fence_free_callbacks(katom); -+ -+ /* Mark the atom as handled in case all fences signaled just before -+ * canceling the callbacks and the worker was queued. -+ */ -+ kbase_fence_dep_count_set(katom, -1); -+ -+ /* Prevent job_done_nolock from being called twice on an atom when -+ * there is a race between job completion and cancellation. -+ */ -+ -+ if (katom->status == KBASE_JD_ATOM_STATE_QUEUED) { -+ /* Wait was cancelled - zap the atom */ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ if (jd_done_nolock(katom, NULL)) -+ kbase_js_sched_all(katom->kctx->kbdev); -+ } -+} -+ -+/** -+ * kbase_dma_fence_work() - Worker thread called when a fence is signaled -+ * @pwork: work_struct containing a pointer to a katom -+ * -+ * This function will clean and mark all dependencies as satisfied -+ */ -+static void -+kbase_dma_fence_work(struct work_struct *pwork) -+{ -+ struct kbase_jd_atom *katom; -+ struct kbase_jd_context *ctx; -+ -+ katom = container_of(pwork, struct kbase_jd_atom, work); -+ ctx = &katom->kctx->jctx; -+ -+ mutex_lock(&ctx->lock); -+ if (kbase_fence_dep_count_read(katom) != 0) -+ goto out; -+ -+ kbase_fence_dep_count_set(katom, -1); -+ -+ /* Remove atom from list of dma-fence waiting atoms. */ -+ kbase_dma_fence_waiters_remove(katom); -+ /* Cleanup callbacks. */ -+ kbase_fence_free_callbacks(katom); -+ /* -+ * Queue atom on GPU, unless it has already completed due to a failing -+ * dependency. Run jd_done_nolock() on the katom if it is completed. -+ */ -+ if (unlikely(katom->status == KBASE_JD_ATOM_STATE_COMPLETED)) -+ jd_done_nolock(katom, NULL); -+ else -+ kbase_jd_dep_clear_locked(katom); -+ -+out: -+ mutex_unlock(&ctx->lock); -+} -+ -+static void -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+kbase_dma_fence_cb(struct fence *fence, struct fence_cb *cb) -+#else -+kbase_dma_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb) -+#endif -+{ -+ struct kbase_fence_cb *kcb = container_of(cb, -+ struct kbase_fence_cb, -+ fence_cb); -+ struct kbase_jd_atom *katom = kcb->katom; -+ -+ /* If the atom is zapped dep_count will be forced to a negative number -+ * preventing this callback from ever scheduling work. Which in turn -+ * would reschedule the atom. -+ */ -+ -+ if (kbase_fence_dep_count_dec_and_test(katom)) -+ kbase_dma_fence_queue_work(katom); -+} -+ -+static int -+kbase_dma_fence_add_reservation_callback(struct kbase_jd_atom *katom, -+ struct reservation_object *resv, -+ bool exclusive) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *excl_fence = NULL; -+ struct fence **shared_fences = NULL; -+#else -+ struct dma_fence *excl_fence = NULL; -+ struct dma_fence **shared_fences = NULL; -+#endif -+ unsigned int shared_count = 0; -+ int err, i; -+ -+ err = reservation_object_get_fences_rcu(resv, -+ &excl_fence, -+ &shared_count, -+ &shared_fences); -+ if (err) -+ return err; -+ -+ if (excl_fence) { -+ err = kbase_fence_add_callback(katom, -+ excl_fence, -+ kbase_dma_fence_cb); -+ -+ /* Release our reference, taken by reservation_object_get_fences_rcu(), -+ * to the fence. We have set up our callback (if that was possible), -+ * and it's the fence's owner is responsible for singling the fence -+ * before allowing it to disappear. -+ */ -+ dma_fence_put(excl_fence); -+ -+ if (err) -+ goto out; -+ } -+ -+ if (exclusive) { -+ for (i = 0; i < shared_count; i++) { -+ err = kbase_fence_add_callback(katom, -+ shared_fences[i], -+ kbase_dma_fence_cb); -+ if (err) -+ goto out; -+ } -+ } -+ -+ /* Release all our references to the shared fences, taken by -+ * reservation_object_get_fences_rcu(). We have set up our callback (if -+ * that was possible), and it's the fence's owner is responsible for -+ * signaling the fence before allowing it to disappear. -+ */ -+out: -+ for (i = 0; i < shared_count; i++) -+ dma_fence_put(shared_fences[i]); -+ kfree(shared_fences); -+ -+ if (err) { -+ /* -+ * On error, cancel and clean up all callbacks that was set up -+ * before the error. -+ */ -+ kbase_fence_free_callbacks(katom); -+ } -+ -+ return err; -+} -+ -+void kbase_dma_fence_add_reservation(struct reservation_object *resv, -+ struct kbase_dma_fence_resv_info *info, -+ bool exclusive) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < info->dma_fence_resv_count; i++) { -+ /* Duplicate resource, ignore */ -+ if (info->resv_objs[i] == resv) -+ return; -+ } -+ -+ info->resv_objs[info->dma_fence_resv_count] = resv; -+ if (exclusive) -+ set_bit(info->dma_fence_resv_count, -+ info->dma_fence_excl_bitmap); -+ (info->dma_fence_resv_count)++; -+} -+ -+int kbase_dma_fence_wait(struct kbase_jd_atom *katom, -+ struct kbase_dma_fence_resv_info *info) -+{ -+ int err, i; -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence; -+#else -+ struct dma_fence *fence; -+#endif -+ struct ww_acquire_ctx ww_ctx; -+ -+ lockdep_assert_held(&katom->kctx->jctx.lock); -+ -+ fence = kbase_fence_out_new(katom); -+ if (!fence) { -+ err = -ENOMEM; -+ dev_err(katom->kctx->kbdev->dev, -+ "Error %d creating fence.\n", err); -+ return err; -+ } -+ -+ kbase_fence_dep_count_set(katom, 1); -+ -+ err = kbase_dma_fence_lock_reservations(info, &ww_ctx); -+ if (err) { -+ dev_err(katom->kctx->kbdev->dev, -+ "Error %d locking reservations.\n", err); -+ kbase_fence_dep_count_set(katom, -1); -+ kbase_fence_out_remove(katom); -+ return err; -+ } -+ -+ for (i = 0; i < info->dma_fence_resv_count; i++) { -+ struct reservation_object *obj = info->resv_objs[i]; -+ -+ if (!test_bit(i, info->dma_fence_excl_bitmap)) { -+ err = reservation_object_reserve_shared(obj); -+ if (err) { -+ dev_err(katom->kctx->kbdev->dev, -+ "Error %d reserving space for shared fence.\n", err); -+ goto end; -+ } -+ -+ err = kbase_dma_fence_add_reservation_callback(katom, obj, false); -+ if (err) { -+ dev_err(katom->kctx->kbdev->dev, -+ "Error %d adding reservation to callback.\n", err); -+ goto end; -+ } -+ -+ reservation_object_add_shared_fence(obj, fence); -+ } else { -+ err = kbase_dma_fence_add_reservation_callback(katom, obj, true); -+ if (err) { -+ dev_err(katom->kctx->kbdev->dev, -+ "Error %d adding reservation to callback.\n", err); -+ goto end; -+ } -+ -+ reservation_object_add_excl_fence(obj, fence); -+ } -+ } -+ -+end: -+ kbase_dma_fence_unlock_reservations(info, &ww_ctx); -+ -+ if (likely(!err)) { -+ /* Test if the callbacks are already triggered */ -+ if (kbase_fence_dep_count_dec_and_test(katom)) { -+ kbase_fence_dep_count_set(katom, -1); -+ kbase_fence_free_callbacks(katom); -+ } else { -+ /* Add katom to the list of dma-buf fence waiting atoms -+ * only if it is still waiting. -+ */ -+ kbase_dma_fence_waiters_add(katom); -+ } -+ } else { -+ /* There was an error, cancel callbacks, set dep_count to -1 to -+ * indicate that the atom has been handled (the caller will -+ * kill it for us), signal the fence, free callbacks and the -+ * fence. -+ */ -+ kbase_fence_free_callbacks(katom); -+ kbase_fence_dep_count_set(katom, -1); -+ kbase_dma_fence_signal(katom); -+ } -+ -+ return err; -+} -+ -+void kbase_dma_fence_cancel_all_atoms(struct kbase_context *kctx) -+{ -+ struct list_head *list = &kctx->dma_fence.waiting_resource; -+ -+ while (!list_empty(list)) { -+ struct kbase_jd_atom *katom; -+ -+ katom = list_first_entry(list, struct kbase_jd_atom, queue); -+ kbase_dma_fence_waiters_remove(katom); -+ kbase_dma_fence_cancel_atom(katom); -+ } -+} -+ -+void kbase_dma_fence_cancel_callbacks(struct kbase_jd_atom *katom) -+{ -+ /* Cancel callbacks and clean up. */ -+ if (kbase_fence_free_callbacks(katom)) -+ kbase_dma_fence_queue_work(katom); -+} -+ -+void kbase_dma_fence_signal(struct kbase_jd_atom *katom) -+{ -+ if (!katom->dma_fence.fence) -+ return; -+ -+ /* Signal the atom's fence. */ -+ dma_fence_signal(katom->dma_fence.fence); -+ -+ kbase_fence_out_remove(katom); -+ -+ kbase_fence_free_callbacks(katom); -+} -+ -+void kbase_dma_fence_term(struct kbase_context *kctx) -+{ -+ destroy_workqueue(kctx->dma_fence.wq); -+ kctx->dma_fence.wq = NULL; -+} -+ -+int kbase_dma_fence_init(struct kbase_context *kctx) -+{ -+ INIT_LIST_HEAD(&kctx->dma_fence.waiting_resource); -+ -+ kctx->dma_fence.wq = alloc_workqueue("mali-fence-%d", -+ WQ_UNBOUND, 1, kctx->pid); -+ if (!kctx->dma_fence.wq) -+ return -ENOMEM; -+ -+ return 0; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_dma_fence.h b/drivers/gpu/arm/midgard/mali_kbase_dma_fence.h -new file mode 100644 -index 0000000..c9ab403 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_dma_fence.h -@@ -0,0 +1,131 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_DMA_FENCE_H_ -+#define _KBASE_DMA_FENCE_H_ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ -+#include -+#include -+#include -+ -+ -+/* Forward declaration from mali_kbase_defs.h */ -+struct kbase_jd_atom; -+struct kbase_context; -+ -+/** -+ * struct kbase_dma_fence_resv_info - Structure with list of reservation objects -+ * @resv_objs: Array of reservation objects to attach the -+ * new fence to. -+ * @dma_fence_resv_count: Number of reservation objects in the array. -+ * @dma_fence_excl_bitmap: Specifies which resv_obj are exclusive. -+ * -+ * This is used by some functions to pass around a collection of data about -+ * reservation objects. -+ */ -+struct kbase_dma_fence_resv_info { -+ struct reservation_object **resv_objs; -+ unsigned int dma_fence_resv_count; -+ unsigned long *dma_fence_excl_bitmap; -+}; -+ -+/** -+ * kbase_dma_fence_add_reservation() - Adds a resv to the array of resv_objs -+ * @resv: Reservation object to add to the array. -+ * @info: Pointer to struct with current reservation info -+ * @exclusive: Boolean indicating if exclusive access is needed -+ * -+ * The function adds a new reservation_object to an existing array of -+ * reservation_objects. At the same time keeps track of which objects require -+ * exclusive access in dma_fence_excl_bitmap. -+ */ -+void kbase_dma_fence_add_reservation(struct reservation_object *resv, -+ struct kbase_dma_fence_resv_info *info, -+ bool exclusive); -+ -+/** -+ * kbase_dma_fence_wait() - Creates a new fence and attaches it to the resv_objs -+ * @katom: Katom with the external dependency. -+ * @info: Pointer to struct with current reservation info -+ * -+ * Return: An error code or 0 if succeeds -+ */ -+int kbase_dma_fence_wait(struct kbase_jd_atom *katom, -+ struct kbase_dma_fence_resv_info *info); -+ -+/** -+ * kbase_dma_fence_cancel_ctx() - Cancel all dma-fences blocked atoms on kctx -+ * @kctx: Pointer to kbase context -+ * -+ * This function will cancel and clean up all katoms on @kctx that is waiting -+ * on dma-buf fences. -+ * -+ * Locking: jctx.lock needs to be held when calling this function. -+ */ -+void kbase_dma_fence_cancel_all_atoms(struct kbase_context *kctx); -+ -+/** -+ * kbase_dma_fence_cancel_callbacks() - Cancel only callbacks on katom -+ * @katom: Pointer to katom whose callbacks are to be canceled -+ * -+ * This function cancels all dma-buf fence callbacks on @katom, but does not -+ * cancel the katom itself. -+ * -+ * The caller is responsible for ensuring that jd_done_nolock is called on -+ * @katom. -+ * -+ * Locking: jctx.lock must be held when calling this function. -+ */ -+void kbase_dma_fence_cancel_callbacks(struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_dma_fence_signal() - Signal katom's fence and clean up after wait -+ * @katom: Pointer to katom to signal and clean up -+ * -+ * This function will signal the @katom's fence, if it has one, and clean up -+ * the callback data from the katom's wait on earlier fences. -+ * -+ * Locking: jctx.lock must be held while calling this function. -+ */ -+void kbase_dma_fence_signal(struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_dma_fence_term() - Terminate Mali dma-fence context -+ * @kctx: kbase context to terminate -+ */ -+void kbase_dma_fence_term(struct kbase_context *kctx); -+ -+/** -+ * kbase_dma_fence_init() - Initialize Mali dma-fence context -+ * @kctx: kbase context to initialize -+ */ -+int kbase_dma_fence_init(struct kbase_context *kctx); -+ -+ -+#else /* CONFIG_MALI_DMA_FENCE */ -+/* Dummy functions for when dma-buf fence isn't enabled. */ -+ -+static inline int kbase_dma_fence_init(struct kbase_context *kctx) -+{ -+ return 0; -+} -+ -+static inline void kbase_dma_fence_term(struct kbase_context *kctx) {} -+#endif /* CONFIG_MALI_DMA_FENCE */ -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_event.c b/drivers/gpu/arm/midgard/mali_kbase_event.c -new file mode 100644 -index 0000000..1881486 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_event.c -@@ -0,0 +1,259 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+#include -+ -+static struct base_jd_udata kbase_event_process(struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ struct base_jd_udata data; -+ -+ lockdep_assert_held(&kctx->jctx.lock); -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(katom != NULL); -+ KBASE_DEBUG_ASSERT(katom->status == KBASE_JD_ATOM_STATE_COMPLETED); -+ -+ data = katom->udata; -+ -+ KBASE_TIMELINE_ATOMS_IN_FLIGHT(kctx, atomic_sub_return(1, &kctx->timeline.jd_atoms_in_flight)); -+ -+ KBASE_TLSTREAM_TL_NRET_ATOM_CTX(katom, kctx); -+ KBASE_TLSTREAM_TL_DEL_ATOM(katom); -+ -+ katom->status = KBASE_JD_ATOM_STATE_UNUSED; -+ -+ wake_up(&katom->completed); -+ -+ return data; -+} -+ -+int kbase_event_pending(struct kbase_context *ctx) -+{ -+ KBASE_DEBUG_ASSERT(ctx); -+ -+ return (atomic_read(&ctx->event_count) != 0) || -+ (atomic_read(&ctx->event_closed) != 0); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_event_pending); -+ -+int kbase_event_dequeue(struct kbase_context *ctx, struct base_jd_event_v2 *uevent) -+{ -+ struct kbase_jd_atom *atom; -+ -+ KBASE_DEBUG_ASSERT(ctx); -+ -+ mutex_lock(&ctx->event_mutex); -+ -+ if (list_empty(&ctx->event_list)) { -+ if (!atomic_read(&ctx->event_closed)) { -+ mutex_unlock(&ctx->event_mutex); -+ return -1; -+ } -+ -+ /* generate the BASE_JD_EVENT_DRV_TERMINATED message on the fly */ -+ mutex_unlock(&ctx->event_mutex); -+ uevent->event_code = BASE_JD_EVENT_DRV_TERMINATED; -+ memset(&uevent->udata, 0, sizeof(uevent->udata)); -+ dev_dbg(ctx->kbdev->dev, -+ "event system closed, returning BASE_JD_EVENT_DRV_TERMINATED(0x%X)\n", -+ BASE_JD_EVENT_DRV_TERMINATED); -+ return 0; -+ } -+ -+ /* normal event processing */ -+ atomic_dec(&ctx->event_count); -+ atom = list_entry(ctx->event_list.next, struct kbase_jd_atom, dep_item[0]); -+ list_del(ctx->event_list.next); -+ -+ mutex_unlock(&ctx->event_mutex); -+ -+ dev_dbg(ctx->kbdev->dev, "event dequeuing %p\n", (void *)atom); -+ uevent->event_code = atom->event_code; -+ uevent->atom_number = (atom - ctx->jctx.atoms); -+ -+ if (atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) -+ kbase_jd_free_external_resources(atom); -+ -+ mutex_lock(&ctx->jctx.lock); -+ uevent->udata = kbase_event_process(ctx, atom); -+ mutex_unlock(&ctx->jctx.lock); -+ -+ return 0; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_event_dequeue); -+ -+/** -+ * kbase_event_process_noreport_worker - Worker for processing atoms that do not -+ * return an event but do have external -+ * resources -+ * @data: Work structure -+ */ -+static void kbase_event_process_noreport_worker(struct work_struct *data) -+{ -+ struct kbase_jd_atom *katom = container_of(data, struct kbase_jd_atom, -+ work); -+ struct kbase_context *kctx = katom->kctx; -+ -+ if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) -+ kbase_jd_free_external_resources(katom); -+ -+ mutex_lock(&kctx->jctx.lock); -+ kbase_event_process(kctx, katom); -+ mutex_unlock(&kctx->jctx.lock); -+} -+ -+/** -+ * kbase_event_process_noreport - Process atoms that do not return an event -+ * @kctx: Context pointer -+ * @katom: Atom to be processed -+ * -+ * Atoms that do not have external resources will be processed immediately. -+ * Atoms that do have external resources will be processed on a workqueue, in -+ * order to avoid locking issues. -+ */ -+static void kbase_event_process_noreport(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom) -+{ -+ if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) { -+ INIT_WORK(&katom->work, kbase_event_process_noreport_worker); -+ queue_work(kctx->event_workq, &katom->work); -+ } else { -+ kbase_event_process(kctx, katom); -+ } -+} -+ -+/** -+ * kbase_event_coalesce - Move pending events to the main event list -+ * @kctx: Context pointer -+ * -+ * kctx->event_list and kctx->event_coalesce_count must be protected -+ * by a lock unless this is the last thread using them -+ * (and we're about to terminate the lock). -+ * -+ * Return: The number of pending events moved to the main event list -+ */ -+static int kbase_event_coalesce(struct kbase_context *kctx) -+{ -+ const int event_count = kctx->event_coalesce_count; -+ -+ /* Join the list of pending events onto the tail of the main list -+ and reset it */ -+ list_splice_tail_init(&kctx->event_coalesce_list, &kctx->event_list); -+ kctx->event_coalesce_count = 0; -+ -+ /* Return the number of events moved */ -+ return event_count; -+} -+ -+void kbase_event_post(struct kbase_context *ctx, struct kbase_jd_atom *atom) -+{ -+ if (atom->core_req & BASE_JD_REQ_EVENT_ONLY_ON_FAILURE) { -+ if (atom->event_code == BASE_JD_EVENT_DONE) { -+ /* Don't report the event */ -+ kbase_event_process_noreport(ctx, atom); -+ return; -+ } -+ } -+ -+ if (atom->core_req & BASEP_JD_REQ_EVENT_NEVER) { -+ /* Don't report the event */ -+ kbase_event_process_noreport(ctx, atom); -+ return; -+ } -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(atom, TL_ATOM_STATE_POSTED); -+ if (atom->core_req & BASE_JD_REQ_EVENT_COALESCE) { -+ /* Don't report the event until other event(s) have completed */ -+ mutex_lock(&ctx->event_mutex); -+ list_add_tail(&atom->dep_item[0], &ctx->event_coalesce_list); -+ ++ctx->event_coalesce_count; -+ mutex_unlock(&ctx->event_mutex); -+ } else { -+ /* Report the event and any pending events now */ -+ int event_count = 1; -+ -+ mutex_lock(&ctx->event_mutex); -+ event_count += kbase_event_coalesce(ctx); -+ list_add_tail(&atom->dep_item[0], &ctx->event_list); -+ atomic_add(event_count, &ctx->event_count); -+ mutex_unlock(&ctx->event_mutex); -+ -+ kbase_event_wakeup(ctx); -+ } -+} -+KBASE_EXPORT_TEST_API(kbase_event_post); -+ -+void kbase_event_close(struct kbase_context *kctx) -+{ -+ mutex_lock(&kctx->event_mutex); -+ atomic_set(&kctx->event_closed, true); -+ mutex_unlock(&kctx->event_mutex); -+ kbase_event_wakeup(kctx); -+} -+ -+int kbase_event_init(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+ INIT_LIST_HEAD(&kctx->event_list); -+ INIT_LIST_HEAD(&kctx->event_coalesce_list); -+ mutex_init(&kctx->event_mutex); -+ atomic_set(&kctx->event_count, 0); -+ kctx->event_coalesce_count = 0; -+ atomic_set(&kctx->event_closed, false); -+ kctx->event_workq = alloc_workqueue("kbase_event", WQ_MEM_RECLAIM, 1); -+ -+ if (NULL == kctx->event_workq) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_event_init); -+ -+void kbase_event_cleanup(struct kbase_context *kctx) -+{ -+ int event_count; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(kctx->event_workq); -+ -+ flush_workqueue(kctx->event_workq); -+ destroy_workqueue(kctx->event_workq); -+ -+ /* We use kbase_event_dequeue to remove the remaining events as that -+ * deals with all the cleanup needed for the atoms. -+ * -+ * Note: use of kctx->event_list without a lock is safe because this must be the last -+ * thread using it (because we're about to terminate the lock) -+ */ -+ event_count = kbase_event_coalesce(kctx); -+ atomic_add(event_count, &kctx->event_count); -+ -+ while (!list_empty(&kctx->event_list)) { -+ struct base_jd_event_v2 event; -+ -+ kbase_event_dequeue(kctx, &event); -+ } -+} -+ -+KBASE_EXPORT_TEST_API(kbase_event_cleanup); -diff --git a/drivers/gpu/arm/midgard/mali_kbase_fence.c b/drivers/gpu/arm/midgard/mali_kbase_fence.c -new file mode 100644 -index 0000000..fcb3733 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_fence.c -@@ -0,0 +1,196 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Spin lock protecting all Mali fences as fence->lock. */ -+static DEFINE_SPINLOCK(kbase_fence_lock); -+ -+static const char * -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+kbase_fence_get_driver_name(struct fence *fence) -+#else -+kbase_fence_get_driver_name(struct dma_fence *fence) -+#endif -+{ -+ return kbase_drv_name; -+} -+ -+static const char * -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+kbase_fence_get_timeline_name(struct fence *fence) -+#else -+kbase_fence_get_timeline_name(struct dma_fence *fence) -+#endif -+{ -+ return kbase_timeline_name; -+} -+ -+static bool -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+kbase_fence_enable_signaling(struct fence *fence) -+#else -+kbase_fence_enable_signaling(struct dma_fence *fence) -+#endif -+{ -+ return true; -+} -+ -+static void -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+kbase_fence_fence_value_str(struct fence *fence, char *str, int size) -+#else -+kbase_fence_fence_value_str(struct dma_fence *fence, char *str, int size) -+#endif -+{ -+ snprintf(str, size, "%u", fence->seqno); -+} -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+const struct fence_ops kbase_fence_ops = { -+ .wait = fence_default_wait, -+#else -+const struct dma_fence_ops kbase_fence_ops = { -+ .wait = dma_fence_default_wait, -+#endif -+ .get_driver_name = kbase_fence_get_driver_name, -+ .get_timeline_name = kbase_fence_get_timeline_name, -+ .enable_signaling = kbase_fence_enable_signaling, -+ .fence_value_str = kbase_fence_fence_value_str -+}; -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+struct fence * -+kbase_fence_out_new(struct kbase_jd_atom *katom) -+#else -+struct dma_fence * -+kbase_fence_out_new(struct kbase_jd_atom *katom) -+#endif -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence; -+#else -+ struct dma_fence *fence; -+#endif -+ -+ WARN_ON(katom->dma_fence.fence); -+ -+ fence = kzalloc(sizeof(*fence), GFP_KERNEL); -+ if (!fence) -+ return NULL; -+ -+ dma_fence_init(fence, -+ &kbase_fence_ops, -+ &kbase_fence_lock, -+ katom->dma_fence.context, -+ atomic_inc_return(&katom->dma_fence.seqno)); -+ -+ katom->dma_fence.fence = fence; -+ -+ return fence; -+} -+ -+bool -+kbase_fence_free_callbacks(struct kbase_jd_atom *katom) -+{ -+ struct kbase_fence_cb *cb, *tmp; -+ bool res = false; -+ -+ lockdep_assert_held(&katom->kctx->jctx.lock); -+ -+ /* Clean up and free callbacks. */ -+ list_for_each_entry_safe(cb, tmp, &katom->dma_fence.callbacks, node) { -+ bool ret; -+ -+ /* Cancel callbacks that hasn't been called yet. */ -+ ret = dma_fence_remove_callback(cb->fence, &cb->fence_cb); -+ if (ret) { -+ int ret; -+ -+ /* Fence had not signaled, clean up after -+ * canceling. -+ */ -+ ret = atomic_dec_return(&katom->dma_fence.dep_count); -+ -+ if (unlikely(ret == 0)) -+ res = true; -+ } -+ -+ /* -+ * Release the reference taken in -+ * kbase_fence_add_callback(). -+ */ -+ dma_fence_put(cb->fence); -+ list_del(&cb->node); -+ kfree(cb); -+ } -+ -+ return res; -+} -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+int -+kbase_fence_add_callback(struct kbase_jd_atom *katom, -+ struct fence *fence, -+ fence_func_t callback) -+#else -+int -+kbase_fence_add_callback(struct kbase_jd_atom *katom, -+ struct dma_fence *fence, -+ dma_fence_func_t callback) -+#endif -+{ -+ int err = 0; -+ struct kbase_fence_cb *kbase_fence_cb; -+ -+ if (!fence) -+ return -EINVAL; -+ -+ kbase_fence_cb = kmalloc(sizeof(*kbase_fence_cb), GFP_KERNEL); -+ if (!kbase_fence_cb) -+ return -ENOMEM; -+ -+ kbase_fence_cb->fence = fence; -+ kbase_fence_cb->katom = katom; -+ INIT_LIST_HEAD(&kbase_fence_cb->node); -+ -+ err = dma_fence_add_callback(fence, &kbase_fence_cb->fence_cb, -+ callback); -+ if (err == -ENOENT) { -+ /* Fence signaled, clear the error and return */ -+ err = 0; -+ kfree(kbase_fence_cb); -+ } else if (err) { -+ kfree(kbase_fence_cb); -+ } else { -+ /* -+ * Get reference to fence that will be kept until callback gets -+ * cleaned up in kbase_fence_free_callbacks(). -+ */ -+ dma_fence_get(fence); -+ atomic_inc(&katom->dma_fence.dep_count); -+ /* Add callback to katom's list of callbacks */ -+ list_add(&kbase_fence_cb->node, &katom->dma_fence.callbacks); -+ } -+ -+ return err; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_fence.h b/drivers/gpu/arm/midgard/mali_kbase_fence.h -new file mode 100644 -index 0000000..8d39299 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_fence.h -@@ -0,0 +1,266 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_FENCE_H_ -+#define _KBASE_FENCE_H_ -+ -+/* -+ * mali_kbase_fence.[hc] has common fence code used by both -+ * - CONFIG_MALI_DMA_FENCE - implicit DMA fences -+ * - CONFIG_SYNC_FILE - explicit fences beginning with 4.9 kernel -+ */ -+ -+#if defined(CONFIG_MALI_DMA_FENCE) || defined(CONFIG_SYNC_FILE) -+ -+#include -+#include "mali_kbase_fence_defs.h" -+#include "mali_kbase.h" -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+extern const struct fence_ops kbase_fence_ops; -+#else -+extern const struct dma_fence_ops kbase_fence_ops; -+#endif -+ -+/** -+* struct kbase_fence_cb - Mali dma-fence callback data struct -+* @fence_cb: Callback function -+* @katom: Pointer to katom that is waiting on this callback -+* @fence: Pointer to the fence object on which this callback is waiting -+* @node: List head for linking this callback to the katom -+*/ -+struct kbase_fence_cb { -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence_cb fence_cb; -+ struct fence *fence; -+#else -+ struct dma_fence_cb fence_cb; -+ struct dma_fence *fence; -+#endif -+ struct kbase_jd_atom *katom; -+ struct list_head node; -+}; -+ -+/** -+ * kbase_fence_out_new() - Creates a new output fence and puts it on the atom -+ * @katom: Atom to create an output fence for -+ * -+ * return: A new fence object on success, NULL on failure. -+ */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+struct fence *kbase_fence_out_new(struct kbase_jd_atom *katom); -+#else -+struct dma_fence *kbase_fence_out_new(struct kbase_jd_atom *katom); -+#endif -+ -+#if defined(CONFIG_SYNC_FILE) -+/** -+ * kbase_fence_fence_in_set() - Assign input fence to atom -+ * @katom: Atom to assign input fence to -+ * @fence: Input fence to assign to atom -+ * -+ * This function will take ownership of one fence reference! -+ */ -+#define kbase_fence_fence_in_set(katom, fence) \ -+ do { \ -+ WARN_ON((katom)->dma_fence.fence_in); \ -+ (katom)->dma_fence.fence_in = fence; \ -+ } while (0) -+#endif -+ -+/** -+ * kbase_fence_out_remove() - Removes the output fence from atom -+ * @katom: Atom to remove output fence for -+ * -+ * This will also release the reference to this fence which the atom keeps -+ */ -+static inline void kbase_fence_out_remove(struct kbase_jd_atom *katom) -+{ -+ if (katom->dma_fence.fence) { -+ dma_fence_put(katom->dma_fence.fence); -+ katom->dma_fence.fence = NULL; -+ } -+} -+ -+#if defined(CONFIG_SYNC_FILE) -+/** -+ * kbase_fence_out_remove() - Removes the input fence from atom -+ * @katom: Atom to remove input fence for -+ * -+ * This will also release the reference to this fence which the atom keeps -+ */ -+static inline void kbase_fence_in_remove(struct kbase_jd_atom *katom) -+{ -+ if (katom->dma_fence.fence_in) { -+ dma_fence_put(katom->dma_fence.fence_in); -+ katom->dma_fence.fence_in = NULL; -+ } -+} -+#endif -+ -+/** -+ * kbase_fence_out_is_ours() - Check if atom has a valid fence created by us -+ * @katom: Atom to check output fence for -+ * -+ * Return: true if fence exists and is valid, otherwise false -+ */ -+static inline bool kbase_fence_out_is_ours(struct kbase_jd_atom *katom) -+{ -+ return katom->dma_fence.fence && -+ katom->dma_fence.fence->ops == &kbase_fence_ops; -+} -+ -+/** -+ * kbase_fence_out_signal() - Signal output fence of atom -+ * @katom: Atom to signal output fence for -+ * @status: Status to signal with (0 for success, < 0 for error) -+ * -+ * Return: 0 on success, < 0 on error -+ */ -+static inline int kbase_fence_out_signal(struct kbase_jd_atom *katom, -+ int status) -+{ -+ katom->dma_fence.fence->status = status; -+ return dma_fence_signal(katom->dma_fence.fence); -+} -+ -+/** -+ * kbase_fence_add_callback() - Add callback on @fence to block @katom -+ * @katom: Pointer to katom that will be blocked by @fence -+ * @fence: Pointer to fence on which to set up the callback -+ * @callback: Pointer to function to be called when fence is signaled -+ * -+ * Caller needs to hold a reference to @fence when calling this function, and -+ * the caller is responsible for releasing that reference. An additional -+ * reference to @fence will be taken when the callback was successfully set up -+ * and @fence needs to be kept valid until the callback has been called and -+ * cleanup have been done. -+ * -+ * Return: 0 on success: fence was either already signaled, or callback was -+ * set up. Negative error code is returned on error. -+ */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+int kbase_fence_add_callback(struct kbase_jd_atom *katom, -+ struct fence *fence, -+ fence_func_t callback); -+#else -+int kbase_fence_add_callback(struct kbase_jd_atom *katom, -+ struct dma_fence *fence, -+ dma_fence_func_t callback); -+#endif -+ -+/** -+ * kbase_fence_dep_count_set() - Set dep_count value on atom to specified value -+ * @katom: Atom to set dep_count for -+ * @val: value to set dep_count to -+ * -+ * The dep_count is available to the users of this module so that they can -+ * synchronize completion of the wait with cancellation and adding of more -+ * callbacks. For instance, a user could do the following: -+ * -+ * dep_count set to 1 -+ * callback #1 added, dep_count is increased to 2 -+ * callback #1 happens, dep_count decremented to 1 -+ * since dep_count > 0, no completion is done -+ * callback #2 is added, dep_count is increased to 2 -+ * dep_count decremented to 1 -+ * callback #2 happens, dep_count decremented to 0 -+ * since dep_count now is zero, completion executes -+ * -+ * The dep_count can also be used to make sure that the completion only -+ * executes once. This is typically done by setting dep_count to -1 for the -+ * thread that takes on this responsibility. -+ */ -+static inline void -+kbase_fence_dep_count_set(struct kbase_jd_atom *katom, int val) -+{ -+ atomic_set(&katom->dma_fence.dep_count, val); -+} -+ -+/** -+ * kbase_fence_dep_count_dec_and_test() - Decrements dep_count -+ * @katom: Atom to decrement dep_count for -+ * -+ * See @kbase_fence_dep_count_set for general description about dep_count -+ * -+ * Return: true if value was decremented to zero, otherwise false -+ */ -+static inline bool -+kbase_fence_dep_count_dec_and_test(struct kbase_jd_atom *katom) -+{ -+ return atomic_dec_and_test(&katom->dma_fence.dep_count); -+} -+ -+/** -+ * kbase_fence_dep_count_read() - Returns the current dep_count value -+ * @katom: Pointer to katom -+ * -+ * See @kbase_fence_dep_count_set for general description about dep_count -+ * -+ * Return: The current dep_count value -+ */ -+static inline int kbase_fence_dep_count_read(struct kbase_jd_atom *katom) -+{ -+ return atomic_read(&katom->dma_fence.dep_count); -+} -+ -+/** -+ * kbase_fence_free_callbacks() - Free dma-fence callbacks on a katom -+ * @katom: Pointer to katom -+ * -+ * This function will free all fence callbacks on the katom's list of -+ * callbacks. Callbacks that have not yet been called, because their fence -+ * hasn't yet signaled, will first be removed from the fence. -+ * -+ * Locking: katom->dma_fence.callbacks list assumes jctx.lock is held. -+ * -+ * Return: true if dep_count reached 0, otherwise false. -+ */ -+bool kbase_fence_free_callbacks(struct kbase_jd_atom *katom); -+ -+#if defined(CONFIG_SYNC_FILE) -+/** -+ * kbase_fence_in_get() - Retrieve input fence for atom. -+ * @katom: Atom to get input fence from -+ * -+ * A ref will be taken for the fence, so use @kbase_fence_put() to release it -+ * -+ * Return: The fence, or NULL if there is no input fence for atom -+ */ -+#define kbase_fence_in_get(katom) dma_fence_get((katom)->dma_fence.fence_in) -+#endif -+ -+/** -+ * kbase_fence_out_get() - Retrieve output fence for atom. -+ * @katom: Atom to get output fence from -+ * -+ * A ref will be taken for the fence, so use @kbase_fence_put() to release it -+ * -+ * Return: The fence, or NULL if there is no output fence for atom -+ */ -+#define kbase_fence_out_get(katom) dma_fence_get((katom)->dma_fence.fence) -+ -+/** -+ * kbase_fence_put() - Releases a reference to a fence -+ * @fence: Fence to release reference for. -+ */ -+#define kbase_fence_put(fence) dma_fence_put(fence) -+ -+ -+#endif /* CONFIG_MALI_DMA_FENCE || defined(CONFIG_SYNC_FILE */ -+ -+#endif /* _KBASE_FENCE_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_fence_defs.h b/drivers/gpu/arm/midgard/mali_kbase_fence_defs.h -new file mode 100644 -index 0000000..fa2c6df ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_fence_defs.h -@@ -0,0 +1,51 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_FENCE_DEFS_H_ -+#define _KBASE_FENCE_DEFS_H_ -+ -+/* -+ * There was a big rename in the 4.10 kernel (fence* -> dma_fence*) -+ * This file hides the compatibility issues with this for the rest the driver -+ */ -+ -+#if defined(CONFIG_MALI_DMA_FENCE) || defined(CONFIG_SYNC_FILE) -+ -+#include -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ -+#include -+ -+#define dma_fence_context_alloc(a) fence_context_alloc(a) -+#define dma_fence_init(a, b, c, d, e) fence_init(a, b, c, d, e) -+#define dma_fence_get(a) fence_get(a) -+#define dma_fence_put(a) fence_put(a) -+#define dma_fence_signal(a) fence_signal(a) -+#define dma_fence_is_signaled(a) fence_is_signaled(a) -+#define dma_fence_add_callback(a, b, c) fence_add_callback(a, b, c) -+#define dma_fence_remove_callback(a, b) fence_remove_callback(a, b) -+ -+#else -+ -+#include -+ -+#endif /* < 4.10.0 */ -+ -+#endif /* CONFIG_MALI_DMA_FENCE || CONFIG_SYNC_FILE */ -+ -+#endif /* _KBASE_FENCE_DEFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gator.h b/drivers/gpu/arm/midgard/mali_kbase_gator.h -new file mode 100644 -index 0000000..ce65b55 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gator.h -@@ -0,0 +1,45 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* NB taken from gator */ -+/* -+ * List of possible actions to be controlled by DS-5 Streamline. -+ * The following numbers are used by gator to control the frame buffer dumping -+ * and s/w counter reporting. We cannot use the enums in mali_uk_types.h because -+ * they are unknown inside gator. -+ */ -+#ifndef _KBASE_GATOR_H_ -+#define _KBASE_GATOR_H_ -+ -+#ifdef CONFIG_MALI_GATOR_SUPPORT -+#define GATOR_MAKE_EVENT(type, number) (((type) << 24) | ((number) << 16)) -+#define GATOR_JOB_SLOT_START 1 -+#define GATOR_JOB_SLOT_STOP 2 -+#define GATOR_JOB_SLOT_SOFT_STOPPED 3 -+ -+void kbase_trace_mali_job_slots_event(u32 event, const struct kbase_context *kctx, u8 atom_id); -+void kbase_trace_mali_pm_status(u32 event, u64 value); -+void kbase_trace_mali_pm_power_off(u32 event, u64 value); -+void kbase_trace_mali_pm_power_on(u32 event, u64 value); -+void kbase_trace_mali_page_fault_insert_pages(int event, u32 value); -+void kbase_trace_mali_mmu_as_in_use(int event); -+void kbase_trace_mali_mmu_as_released(int event); -+void kbase_trace_mali_total_alloc_pages_change(long long int event); -+ -+#endif /* CONFIG_MALI_GATOR_SUPPORT */ -+ -+#endif /* _KBASE_GATOR_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gator_api.c b/drivers/gpu/arm/midgard/mali_kbase_gator_api.c -new file mode 100644 -index 0000000..860e101 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gator_api.c -@@ -0,0 +1,334 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include "mali_kbase.h" -+#include "mali_kbase_hw.h" -+#include "mali_kbase_mem_linux.h" -+#include "mali_kbase_gator_api.h" -+#include "mali_kbase_gator_hwcnt_names.h" -+ -+#define MALI_MAX_CORES_PER_GROUP 4 -+#define MALI_MAX_NUM_BLOCKS_PER_GROUP 8 -+#define MALI_COUNTERS_PER_BLOCK 64 -+#define MALI_BYTES_PER_COUNTER 4 -+ -+struct kbase_gator_hwcnt_handles { -+ struct kbase_device *kbdev; -+ struct kbase_vinstr_client *vinstr_cli; -+ void *vinstr_buffer; -+ struct work_struct dump_work; -+ int dump_complete; -+ spinlock_t dump_lock; -+}; -+ -+static void dump_worker(struct work_struct *work); -+ -+const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters) -+{ -+ const char * const *hardware_counters; -+ struct kbase_device *kbdev; -+ uint32_t product_id; -+ uint32_t count; -+ -+ if (!total_counters) -+ return NULL; -+ -+ /* Get the first device - it doesn't matter in this case */ -+ kbdev = kbase_find_device(-1); -+ if (!kbdev) -+ return NULL; -+ -+ product_id = kbdev->gpu_props.props.core_props.product_id; -+ -+ if (GPU_ID_IS_NEW_FORMAT(product_id)) { -+ switch (GPU_ID2_MODEL_MATCH_VALUE(product_id)) { -+ case GPU_ID2_PRODUCT_TMIX: -+ hardware_counters = hardware_counters_mali_tMIx; -+ count = ARRAY_SIZE(hardware_counters_mali_tMIx); -+ break; -+ case GPU_ID2_PRODUCT_THEX: -+ hardware_counters = hardware_counters_mali_tHEx; -+ count = ARRAY_SIZE(hardware_counters_mali_tHEx); -+ break; -+ case GPU_ID2_PRODUCT_TSIX: -+ hardware_counters = hardware_counters_mali_tSIx; -+ count = ARRAY_SIZE(hardware_counters_mali_tSIx); -+ break; -+ default: -+ hardware_counters = NULL; -+ count = 0; -+ dev_err(kbdev->dev, "Unrecognized product ID: %u\n", -+ product_id); -+ break; -+ } -+ } else { -+ switch (product_id) { -+ /* If we are using a Mali-T60x device */ -+ case GPU_ID_PI_T60X: -+ hardware_counters = hardware_counters_mali_t60x; -+ count = ARRAY_SIZE(hardware_counters_mali_t60x); -+ break; -+ /* If we are using a Mali-T62x device */ -+ case GPU_ID_PI_T62X: -+ hardware_counters = hardware_counters_mali_t62x; -+ count = ARRAY_SIZE(hardware_counters_mali_t62x); -+ break; -+ /* If we are using a Mali-T72x device */ -+ case GPU_ID_PI_T72X: -+ hardware_counters = hardware_counters_mali_t72x; -+ count = ARRAY_SIZE(hardware_counters_mali_t72x); -+ break; -+ /* If we are using a Mali-T76x device */ -+ case GPU_ID_PI_T76X: -+ hardware_counters = hardware_counters_mali_t76x; -+ count = ARRAY_SIZE(hardware_counters_mali_t76x); -+ break; -+ /* If we are using a Mali-T82x device */ -+ case GPU_ID_PI_T82X: -+ hardware_counters = hardware_counters_mali_t82x; -+ count = ARRAY_SIZE(hardware_counters_mali_t82x); -+ break; -+ /* If we are using a Mali-T83x device */ -+ case GPU_ID_PI_T83X: -+ hardware_counters = hardware_counters_mali_t83x; -+ count = ARRAY_SIZE(hardware_counters_mali_t83x); -+ break; -+ /* If we are using a Mali-T86x device */ -+ case GPU_ID_PI_T86X: -+ hardware_counters = hardware_counters_mali_t86x; -+ count = ARRAY_SIZE(hardware_counters_mali_t86x); -+ break; -+ /* If we are using a Mali-T88x device */ -+ case GPU_ID_PI_TFRX: -+ hardware_counters = hardware_counters_mali_t88x; -+ count = ARRAY_SIZE(hardware_counters_mali_t88x); -+ break; -+ default: -+ hardware_counters = NULL; -+ count = 0; -+ dev_err(kbdev->dev, "Unrecognized product ID: %u\n", -+ product_id); -+ break; -+ } -+ } -+ -+ /* Release the kbdev reference. */ -+ kbase_release_device(kbdev); -+ -+ *total_counters = count; -+ -+ /* If we return a string array take a reference on the module (or fail). */ -+ if (hardware_counters && !try_module_get(THIS_MODULE)) -+ return NULL; -+ -+ return hardware_counters; -+} -+KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init_names); -+ -+void kbase_gator_hwcnt_term_names(void) -+{ -+ /* Release the module reference. */ -+ module_put(THIS_MODULE); -+} -+KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term_names); -+ -+struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info) -+{ -+ struct kbase_gator_hwcnt_handles *hand; -+ struct kbase_uk_hwcnt_reader_setup setup; -+ uint32_t dump_size = 0, i = 0; -+ -+ if (!in_out_info) -+ return NULL; -+ -+ hand = kzalloc(sizeof(*hand), GFP_KERNEL); -+ if (!hand) -+ return NULL; -+ -+ INIT_WORK(&hand->dump_work, dump_worker); -+ spin_lock_init(&hand->dump_lock); -+ -+ /* Get the first device */ -+ hand->kbdev = kbase_find_device(-1); -+ if (!hand->kbdev) -+ goto free_hand; -+ -+ dump_size = kbase_vinstr_dump_size(hand->kbdev); -+ hand->vinstr_buffer = kzalloc(dump_size, GFP_KERNEL); -+ if (!hand->vinstr_buffer) -+ goto release_device; -+ in_out_info->kernel_dump_buffer = hand->vinstr_buffer; -+ -+ in_out_info->nr_cores = hand->kbdev->gpu_props.num_cores; -+ in_out_info->nr_core_groups = hand->kbdev->gpu_props.num_core_groups; -+ in_out_info->gpu_id = hand->kbdev->gpu_props.props.core_props.product_id; -+ -+ /* If we are using a v4 device (Mali-T6xx or Mali-T72x) */ -+ if (kbase_hw_has_feature(hand->kbdev, BASE_HW_FEATURE_V4)) { -+ uint32_t cg, j; -+ uint64_t core_mask; -+ -+ /* There are 8 hardware counters blocks per core group */ -+ in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) * -+ MALI_MAX_NUM_BLOCKS_PER_GROUP * -+ in_out_info->nr_core_groups, GFP_KERNEL); -+ -+ if (!in_out_info->hwc_layout) -+ goto free_vinstr_buffer; -+ -+ dump_size = in_out_info->nr_core_groups * -+ MALI_MAX_NUM_BLOCKS_PER_GROUP * -+ MALI_COUNTERS_PER_BLOCK * -+ MALI_BYTES_PER_COUNTER; -+ -+ for (cg = 0; cg < in_out_info->nr_core_groups; cg++) { -+ core_mask = hand->kbdev->gpu_props.props.coherency_info.group[cg].core_mask; -+ -+ for (j = 0; j < MALI_MAX_CORES_PER_GROUP; j++) { -+ if (core_mask & (1u << j)) -+ in_out_info->hwc_layout[i++] = SHADER_BLOCK; -+ else -+ in_out_info->hwc_layout[i++] = RESERVED_BLOCK; -+ } -+ -+ in_out_info->hwc_layout[i++] = TILER_BLOCK; -+ in_out_info->hwc_layout[i++] = MMU_L2_BLOCK; -+ -+ in_out_info->hwc_layout[i++] = RESERVED_BLOCK; -+ -+ if (0 == cg) -+ in_out_info->hwc_layout[i++] = JM_BLOCK; -+ else -+ in_out_info->hwc_layout[i++] = RESERVED_BLOCK; -+ } -+ /* If we are using any other device */ -+ } else { -+ uint32_t nr_l2, nr_sc_bits, j; -+ uint64_t core_mask; -+ -+ nr_l2 = hand->kbdev->gpu_props.props.l2_props.num_l2_slices; -+ -+ core_mask = hand->kbdev->gpu_props.props.coherency_info.group[0].core_mask; -+ -+ nr_sc_bits = fls64(core_mask); -+ -+ /* The job manager and tiler sets of counters -+ * are always present */ -+ in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) * (2 + nr_sc_bits + nr_l2), GFP_KERNEL); -+ -+ if (!in_out_info->hwc_layout) -+ goto free_vinstr_buffer; -+ -+ dump_size = (2 + nr_sc_bits + nr_l2) * MALI_COUNTERS_PER_BLOCK * MALI_BYTES_PER_COUNTER; -+ -+ in_out_info->hwc_layout[i++] = JM_BLOCK; -+ in_out_info->hwc_layout[i++] = TILER_BLOCK; -+ -+ for (j = 0; j < nr_l2; j++) -+ in_out_info->hwc_layout[i++] = MMU_L2_BLOCK; -+ -+ while (core_mask != 0ull) { -+ if ((core_mask & 1ull) != 0ull) -+ in_out_info->hwc_layout[i++] = SHADER_BLOCK; -+ else -+ in_out_info->hwc_layout[i++] = RESERVED_BLOCK; -+ core_mask >>= 1; -+ } -+ } -+ -+ in_out_info->nr_hwc_blocks = i; -+ in_out_info->size = dump_size; -+ -+ setup.jm_bm = in_out_info->bitmask[0]; -+ setup.tiler_bm = in_out_info->bitmask[1]; -+ setup.shader_bm = in_out_info->bitmask[2]; -+ setup.mmu_l2_bm = in_out_info->bitmask[3]; -+ hand->vinstr_cli = kbase_vinstr_hwcnt_kernel_setup(hand->kbdev->vinstr_ctx, -+ &setup, hand->vinstr_buffer); -+ if (!hand->vinstr_cli) { -+ dev_err(hand->kbdev->dev, "Failed to register gator with vinstr core"); -+ goto free_layout; -+ } -+ -+ return hand; -+ -+free_layout: -+ kfree(in_out_info->hwc_layout); -+ -+free_vinstr_buffer: -+ kfree(hand->vinstr_buffer); -+ -+release_device: -+ kbase_release_device(hand->kbdev); -+ -+free_hand: -+ kfree(hand); -+ return NULL; -+} -+KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init); -+ -+void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles) -+{ -+ if (in_out_info) -+ kfree(in_out_info->hwc_layout); -+ -+ if (opaque_handles) { -+ cancel_work_sync(&opaque_handles->dump_work); -+ kbase_vinstr_detach_client(opaque_handles->vinstr_cli); -+ kfree(opaque_handles->vinstr_buffer); -+ kbase_release_device(opaque_handles->kbdev); -+ kfree(opaque_handles); -+ } -+} -+KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term); -+ -+static void dump_worker(struct work_struct *work) -+{ -+ struct kbase_gator_hwcnt_handles *hand; -+ -+ hand = container_of(work, struct kbase_gator_hwcnt_handles, dump_work); -+ if (!kbase_vinstr_hwc_dump(hand->vinstr_cli, -+ BASE_HWCNT_READER_EVENT_MANUAL)) { -+ spin_lock_bh(&hand->dump_lock); -+ hand->dump_complete = 1; -+ spin_unlock_bh(&hand->dump_lock); -+ } else { -+ schedule_work(&hand->dump_work); -+ } -+} -+ -+uint32_t kbase_gator_instr_hwcnt_dump_complete( -+ struct kbase_gator_hwcnt_handles *opaque_handles, -+ uint32_t * const success) -+{ -+ -+ if (opaque_handles && success) { -+ *success = opaque_handles->dump_complete; -+ opaque_handles->dump_complete = 0; -+ return *success; -+ } -+ return 0; -+} -+KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_complete); -+ -+uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles) -+{ -+ if (opaque_handles) -+ schedule_work(&opaque_handles->dump_work); -+ return 0; -+} -+KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_irq); -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gator_api.h b/drivers/gpu/arm/midgard/mali_kbase_gator_api.h -new file mode 100644 -index 0000000..ef9ac0f ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gator_api.h -@@ -0,0 +1,219 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_GATOR_API_H_ -+#define _KBASE_GATOR_API_H_ -+ -+/** -+ * @brief This file describes the API used by Gator to fetch hardware counters. -+ */ -+ -+/* This define is used by the gator kernel module compile to select which DDK -+ * API calling convention to use. If not defined (legacy DDK) gator assumes -+ * version 1. The version to DDK release mapping is: -+ * Version 1 API: DDK versions r1px, r2px -+ * Version 2 API: DDK versions r3px, r4px -+ * Version 3 API: DDK version r5p0 and newer -+ * -+ * API Usage -+ * ========= -+ * -+ * 1] Call kbase_gator_hwcnt_init_names() to return the list of short counter -+ * names for the GPU present in this device. -+ * -+ * 2] Create a kbase_gator_hwcnt_info structure and set the counter enables for -+ * the counters you want enabled. The enables can all be set for simplicity in -+ * most use cases, but disabling some will let you minimize bandwidth impact. -+ * -+ * 3] Call kbase_gator_hwcnt_init() using the above structure, to create a -+ * counter context. On successful return the DDK will have populated the -+ * structure with a variety of useful information. -+ * -+ * 4] Call kbase_gator_hwcnt_dump_irq() to queue a non-blocking request for a -+ * counter dump. If this returns a non-zero value the request has been queued, -+ * otherwise the driver has been unable to do so (typically because of another -+ * user of the instrumentation exists concurrently). -+ * -+ * 5] Call kbase_gator_hwcnt_dump_complete() to test whether the previously -+ * requested dump has been succesful. If this returns non-zero the counter dump -+ * has resolved, but the value of *success must also be tested as the dump -+ * may have not been successful. If it returns zero the counter dump was -+ * abandoned due to the device being busy (typically because of another -+ * user of the instrumentation exists concurrently). -+ * -+ * 6] Process the counters stored in the buffer pointed to by ... -+ * -+ * kbase_gator_hwcnt_info->kernel_dump_buffer -+ * -+ * In pseudo code you can find all of the counters via this approach: -+ * -+ * -+ * hwcnt_info # pointer to kbase_gator_hwcnt_info structure -+ * hwcnt_name # pointer to name list -+ * -+ * u32 * hwcnt_data = (u32*)hwcnt_info->kernel_dump_buffer -+ * -+ * # Iterate over each 64-counter block in this GPU configuration -+ * for( i = 0; i < hwcnt_info->nr_hwc_blocks; i++) { -+ * hwc_type type = hwcnt_info->hwc_layout[i]; -+ * -+ * # Skip reserved type blocks - they contain no counters at all -+ * if( type == RESERVED_BLOCK ) { -+ * continue; -+ * } -+ * -+ * size_t name_offset = type * 64; -+ * size_t data_offset = i * 64; -+ * -+ * # Iterate over the names of the counters in this block type -+ * for( j = 0; j < 64; j++) { -+ * const char * name = hwcnt_name[name_offset+j]; -+ * -+ * # Skip empty name strings - there is no counter here -+ * if( name[0] == '\0' ) { -+ * continue; -+ * } -+ * -+ * u32 data = hwcnt_data[data_offset+j]; -+ * -+ * printk( "COUNTER: %s DATA: %u\n", name, data ); -+ * } -+ * } -+ * -+ * -+ * Note that in most implementations you typically want to either SUM or -+ * AVERAGE multiple instances of the same counter if, for example, you have -+ * multiple shader cores or multiple L2 caches. The most sensible view for -+ * analysis is to AVERAGE shader core counters, but SUM L2 cache and MMU -+ * counters. -+ * -+ * 7] Goto 4, repeating until you want to stop collecting counters. -+ * -+ * 8] Release the dump resources by calling kbase_gator_hwcnt_term(). -+ * -+ * 9] Release the name table resources by calling -+ * kbase_gator_hwcnt_term_names(). This function must only be called if -+ * init_names() returned a non-NULL value. -+ **/ -+ -+#define MALI_DDK_GATOR_API_VERSION 3 -+ -+enum hwc_type { -+ JM_BLOCK = 0, -+ TILER_BLOCK, -+ SHADER_BLOCK, -+ MMU_L2_BLOCK, -+ RESERVED_BLOCK -+}; -+ -+struct kbase_gator_hwcnt_info { -+ /* Passed from Gator to kbase */ -+ -+ /* the bitmask of enabled hardware counters for each counter block */ -+ uint16_t bitmask[4]; -+ -+ /* Passed from kbase to Gator */ -+ -+ /* ptr to counter dump memory */ -+ void *kernel_dump_buffer; -+ -+ /* size of counter dump memory */ -+ uint32_t size; -+ -+ /* the ID of the Mali device */ -+ uint32_t gpu_id; -+ -+ /* the number of shader cores in the GPU */ -+ uint32_t nr_cores; -+ -+ /* the number of core groups */ -+ uint32_t nr_core_groups; -+ -+ /* the memory layout of the performance counters */ -+ enum hwc_type *hwc_layout; -+ -+ /* the total number of hardware couter blocks */ -+ uint32_t nr_hwc_blocks; -+}; -+ -+/** -+ * @brief Opaque block of Mali data which Gator needs to return to the API later. -+ */ -+struct kbase_gator_hwcnt_handles; -+ -+/** -+ * @brief Initialize the resources Gator needs for performance profiling. -+ * -+ * @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the Mali -+ * specific information that will be returned to Gator. On entry Gator must have populated the -+ * 'bitmask' field with the counters it wishes to enable for each class of counter block. -+ * Each entry in the array corresponds to a single counter class based on the "hwc_type" -+ * enumeration, and each bit corresponds to an enable for 4 sequential counters (LSB enables -+ * the first 4 counters in the block, and so on). See the GPU counter array as returned by -+ * kbase_gator_hwcnt_get_names() for the index values of each counter for the curernt GPU. -+ * -+ * @return Pointer to an opaque handle block on success, NULL on error. -+ */ -+extern struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info); -+ -+/** -+ * @brief Free all resources once Gator has finished using performance counters. -+ * -+ * @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the -+ * Mali specific information that will be returned to Gator. -+ * @param opaque_handles A wrapper structure for kbase structures. -+ */ -+extern void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles); -+ -+/** -+ * @brief Poll whether a counter dump is successful. -+ * -+ * @param opaque_handles A wrapper structure for kbase structures. -+ * @param[out] success Non-zero on success, zero on failure. -+ * -+ * @return Zero if the dump is still pending, non-zero if the dump has completed. Note that a -+ * completed dump may not have dumped succesfully, so the caller must test for both -+ * a completed and successful dump before processing counters. -+ */ -+extern uint32_t kbase_gator_instr_hwcnt_dump_complete(struct kbase_gator_hwcnt_handles *opaque_handles, uint32_t * const success); -+ -+/** -+ * @brief Request the generation of a new counter dump. -+ * -+ * @param opaque_handles A wrapper structure for kbase structures. -+ * -+ * @return Zero if the hardware device is busy and cannot handle the request, non-zero otherwise. -+ */ -+extern uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles); -+ -+/** -+ * @brief This function is used to fetch the names table based on the Mali device in use. -+ * -+ * @param[out] total_counters The total number of counters short names in the Mali devices' list. -+ * -+ * @return Pointer to an array of strings of length *total_counters. -+ */ -+extern const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters); -+ -+/** -+ * @brief This function is used to terminate the use of the names table. -+ * -+ * This function must only be called if the initial call to kbase_gator_hwcnt_init_names returned a non-NULL value. -+ */ -+extern void kbase_gator_hwcnt_term_names(void); -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names.h b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names.h -new file mode 100644 -index 0000000..cad19b6 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names.h -@@ -0,0 +1,2170 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_GATOR_HWCNT_NAMES_H_ -+#define _KBASE_GATOR_HWCNT_NAMES_H_ -+ -+/* -+ * "Short names" for hardware counters used by Streamline. Counters names are -+ * stored in accordance with their memory layout in the binary counter block -+ * emitted by the Mali GPU. Each "master" in the GPU emits a fixed-size block -+ * of 64 counters, and each GPU implements the same set of "masters" although -+ * the counters each master exposes within its block of 64 may vary. -+ * -+ * Counters which are an empty string are simply "holes" in the counter memory -+ * where no counter exists. -+ */ -+ -+static const char * const hardware_counters_mali_t60x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T60x_MESSAGES_SENT", -+ "T60x_MESSAGES_RECEIVED", -+ "T60x_GPU_ACTIVE", -+ "T60x_IRQ_ACTIVE", -+ "T60x_JS0_JOBS", -+ "T60x_JS0_TASKS", -+ "T60x_JS0_ACTIVE", -+ "", -+ "T60x_JS0_WAIT_READ", -+ "T60x_JS0_WAIT_ISSUE", -+ "T60x_JS0_WAIT_DEPEND", -+ "T60x_JS0_WAIT_FINISH", -+ "T60x_JS1_JOBS", -+ "T60x_JS1_TASKS", -+ "T60x_JS1_ACTIVE", -+ "", -+ "T60x_JS1_WAIT_READ", -+ "T60x_JS1_WAIT_ISSUE", -+ "T60x_JS1_WAIT_DEPEND", -+ "T60x_JS1_WAIT_FINISH", -+ "T60x_JS2_JOBS", -+ "T60x_JS2_TASKS", -+ "T60x_JS2_ACTIVE", -+ "", -+ "T60x_JS2_WAIT_READ", -+ "T60x_JS2_WAIT_ISSUE", -+ "T60x_JS2_WAIT_DEPEND", -+ "T60x_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T60x_TI_JOBS_PROCESSED", -+ "T60x_TI_TRIANGLES", -+ "T60x_TI_QUADS", -+ "T60x_TI_POLYGONS", -+ "T60x_TI_POINTS", -+ "T60x_TI_LINES", -+ "T60x_TI_VCACHE_HIT", -+ "T60x_TI_VCACHE_MISS", -+ "T60x_TI_FRONT_FACING", -+ "T60x_TI_BACK_FACING", -+ "T60x_TI_PRIM_VISIBLE", -+ "T60x_TI_PRIM_CULLED", -+ "T60x_TI_PRIM_CLIPPED", -+ "T60x_TI_LEVEL0", -+ "T60x_TI_LEVEL1", -+ "T60x_TI_LEVEL2", -+ "T60x_TI_LEVEL3", -+ "T60x_TI_LEVEL4", -+ "T60x_TI_LEVEL5", -+ "T60x_TI_LEVEL6", -+ "T60x_TI_LEVEL7", -+ "T60x_TI_COMMAND_1", -+ "T60x_TI_COMMAND_2", -+ "T60x_TI_COMMAND_3", -+ "T60x_TI_COMMAND_4", -+ "T60x_TI_COMMAND_4_7", -+ "T60x_TI_COMMAND_8_15", -+ "T60x_TI_COMMAND_16_63", -+ "T60x_TI_COMMAND_64", -+ "T60x_TI_COMPRESS_IN", -+ "T60x_TI_COMPRESS_OUT", -+ "T60x_TI_COMPRESS_FLUSH", -+ "T60x_TI_TIMESTAMPS", -+ "T60x_TI_PCACHE_HIT", -+ "T60x_TI_PCACHE_MISS", -+ "T60x_TI_PCACHE_LINE", -+ "T60x_TI_PCACHE_STALL", -+ "T60x_TI_WRBUF_HIT", -+ "T60x_TI_WRBUF_MISS", -+ "T60x_TI_WRBUF_LINE", -+ "T60x_TI_WRBUF_PARTIAL", -+ "T60x_TI_WRBUF_STALL", -+ "T60x_TI_ACTIVE", -+ "T60x_TI_LOADING_DESC", -+ "T60x_TI_INDEX_WAIT", -+ "T60x_TI_INDEX_RANGE_WAIT", -+ "T60x_TI_VERTEX_WAIT", -+ "T60x_TI_PCACHE_WAIT", -+ "T60x_TI_WRBUF_WAIT", -+ "T60x_TI_BUS_READ", -+ "T60x_TI_BUS_WRITE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T60x_TI_UTLB_STALL", -+ "T60x_TI_UTLB_REPLAY_MISS", -+ "T60x_TI_UTLB_REPLAY_FULL", -+ "T60x_TI_UTLB_NEW_MISS", -+ "T60x_TI_UTLB_HIT", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "T60x_FRAG_ACTIVE", -+ "T60x_FRAG_PRIMITIVES", -+ "T60x_FRAG_PRIMITIVES_DROPPED", -+ "T60x_FRAG_CYCLES_DESC", -+ "T60x_FRAG_CYCLES_PLR", -+ "T60x_FRAG_CYCLES_VERT", -+ "T60x_FRAG_CYCLES_TRISETUP", -+ "T60x_FRAG_CYCLES_RAST", -+ "T60x_FRAG_THREADS", -+ "T60x_FRAG_DUMMY_THREADS", -+ "T60x_FRAG_QUADS_RAST", -+ "T60x_FRAG_QUADS_EZS_TEST", -+ "T60x_FRAG_QUADS_EZS_KILLED", -+ "T60x_FRAG_THREADS_LZS_TEST", -+ "T60x_FRAG_THREADS_LZS_KILLED", -+ "T60x_FRAG_CYCLES_NO_TILE", -+ "T60x_FRAG_NUM_TILES", -+ "T60x_FRAG_TRANS_ELIM", -+ "T60x_COMPUTE_ACTIVE", -+ "T60x_COMPUTE_TASKS", -+ "T60x_COMPUTE_THREADS", -+ "T60x_COMPUTE_CYCLES_DESC", -+ "T60x_TRIPIPE_ACTIVE", -+ "T60x_ARITH_WORDS", -+ "T60x_ARITH_CYCLES_REG", -+ "T60x_ARITH_CYCLES_L0", -+ "T60x_ARITH_FRAG_DEPEND", -+ "T60x_LS_WORDS", -+ "T60x_LS_ISSUES", -+ "T60x_LS_RESTARTS", -+ "T60x_LS_REISSUES_MISS", -+ "T60x_LS_REISSUES_VD", -+ "T60x_LS_REISSUE_ATTRIB_MISS", -+ "T60x_LS_NO_WB", -+ "T60x_TEX_WORDS", -+ "T60x_TEX_BUBBLES", -+ "T60x_TEX_WORDS_L0", -+ "T60x_TEX_WORDS_DESC", -+ "T60x_TEX_ISSUES", -+ "T60x_TEX_RECIRC_FMISS", -+ "T60x_TEX_RECIRC_DESC", -+ "T60x_TEX_RECIRC_MULTI", -+ "T60x_TEX_RECIRC_PMISS", -+ "T60x_TEX_RECIRC_CONF", -+ "T60x_LSC_READ_HITS", -+ "T60x_LSC_READ_MISSES", -+ "T60x_LSC_WRITE_HITS", -+ "T60x_LSC_WRITE_MISSES", -+ "T60x_LSC_ATOMIC_HITS", -+ "T60x_LSC_ATOMIC_MISSES", -+ "T60x_LSC_LINE_FETCHES", -+ "T60x_LSC_DIRTY_LINE", -+ "T60x_LSC_SNOOPS", -+ "T60x_AXI_TLB_STALL", -+ "T60x_AXI_TLB_MISS", -+ "T60x_AXI_TLB_TRANSACTION", -+ "T60x_LS_TLB_MISS", -+ "T60x_LS_TLB_HIT", -+ "T60x_AXI_BEATS_READ", -+ "T60x_AXI_BEATS_WRITTEN", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T60x_MMU_HIT", -+ "T60x_MMU_NEW_MISS", -+ "T60x_MMU_REPLAY_FULL", -+ "T60x_MMU_REPLAY_MISS", -+ "T60x_MMU_TABLE_WALK", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T60x_UTLB_HIT", -+ "T60x_UTLB_NEW_MISS", -+ "T60x_UTLB_REPLAY_FULL", -+ "T60x_UTLB_REPLAY_MISS", -+ "T60x_UTLB_STALL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T60x_L2_EXT_WRITE_BEATS", -+ "T60x_L2_EXT_READ_BEATS", -+ "T60x_L2_ANY_LOOKUP", -+ "T60x_L2_READ_LOOKUP", -+ "T60x_L2_SREAD_LOOKUP", -+ "T60x_L2_READ_REPLAY", -+ "T60x_L2_READ_SNOOP", -+ "T60x_L2_READ_HIT", -+ "T60x_L2_CLEAN_MISS", -+ "T60x_L2_WRITE_LOOKUP", -+ "T60x_L2_SWRITE_LOOKUP", -+ "T60x_L2_WRITE_REPLAY", -+ "T60x_L2_WRITE_SNOOP", -+ "T60x_L2_WRITE_HIT", -+ "T60x_L2_EXT_READ_FULL", -+ "T60x_L2_EXT_READ_HALF", -+ "T60x_L2_EXT_WRITE_FULL", -+ "T60x_L2_EXT_WRITE_HALF", -+ "T60x_L2_EXT_READ", -+ "T60x_L2_EXT_READ_LINE", -+ "T60x_L2_EXT_WRITE", -+ "T60x_L2_EXT_WRITE_LINE", -+ "T60x_L2_EXT_WRITE_SMALL", -+ "T60x_L2_EXT_BARRIER", -+ "T60x_L2_EXT_AR_STALL", -+ "T60x_L2_EXT_R_BUF_FULL", -+ "T60x_L2_EXT_RD_BUF_FULL", -+ "T60x_L2_EXT_R_RAW", -+ "T60x_L2_EXT_W_STALL", -+ "T60x_L2_EXT_W_BUF_FULL", -+ "T60x_L2_EXT_R_W_HAZARD", -+ "T60x_L2_TAG_HAZARD", -+ "T60x_L2_SNOOP_FULL", -+ "T60x_L2_REPLAY_FULL" -+}; -+static const char * const hardware_counters_mali_t62x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T62x_MESSAGES_SENT", -+ "T62x_MESSAGES_RECEIVED", -+ "T62x_GPU_ACTIVE", -+ "T62x_IRQ_ACTIVE", -+ "T62x_JS0_JOBS", -+ "T62x_JS0_TASKS", -+ "T62x_JS0_ACTIVE", -+ "", -+ "T62x_JS0_WAIT_READ", -+ "T62x_JS0_WAIT_ISSUE", -+ "T62x_JS0_WAIT_DEPEND", -+ "T62x_JS0_WAIT_FINISH", -+ "T62x_JS1_JOBS", -+ "T62x_JS1_TASKS", -+ "T62x_JS1_ACTIVE", -+ "", -+ "T62x_JS1_WAIT_READ", -+ "T62x_JS1_WAIT_ISSUE", -+ "T62x_JS1_WAIT_DEPEND", -+ "T62x_JS1_WAIT_FINISH", -+ "T62x_JS2_JOBS", -+ "T62x_JS2_TASKS", -+ "T62x_JS2_ACTIVE", -+ "", -+ "T62x_JS2_WAIT_READ", -+ "T62x_JS2_WAIT_ISSUE", -+ "T62x_JS2_WAIT_DEPEND", -+ "T62x_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T62x_TI_JOBS_PROCESSED", -+ "T62x_TI_TRIANGLES", -+ "T62x_TI_QUADS", -+ "T62x_TI_POLYGONS", -+ "T62x_TI_POINTS", -+ "T62x_TI_LINES", -+ "T62x_TI_VCACHE_HIT", -+ "T62x_TI_VCACHE_MISS", -+ "T62x_TI_FRONT_FACING", -+ "T62x_TI_BACK_FACING", -+ "T62x_TI_PRIM_VISIBLE", -+ "T62x_TI_PRIM_CULLED", -+ "T62x_TI_PRIM_CLIPPED", -+ "T62x_TI_LEVEL0", -+ "T62x_TI_LEVEL1", -+ "T62x_TI_LEVEL2", -+ "T62x_TI_LEVEL3", -+ "T62x_TI_LEVEL4", -+ "T62x_TI_LEVEL5", -+ "T62x_TI_LEVEL6", -+ "T62x_TI_LEVEL7", -+ "T62x_TI_COMMAND_1", -+ "T62x_TI_COMMAND_2", -+ "T62x_TI_COMMAND_3", -+ "T62x_TI_COMMAND_4", -+ "T62x_TI_COMMAND_5_7", -+ "T62x_TI_COMMAND_8_15", -+ "T62x_TI_COMMAND_16_63", -+ "T62x_TI_COMMAND_64", -+ "T62x_TI_COMPRESS_IN", -+ "T62x_TI_COMPRESS_OUT", -+ "T62x_TI_COMPRESS_FLUSH", -+ "T62x_TI_TIMESTAMPS", -+ "T62x_TI_PCACHE_HIT", -+ "T62x_TI_PCACHE_MISS", -+ "T62x_TI_PCACHE_LINE", -+ "T62x_TI_PCACHE_STALL", -+ "T62x_TI_WRBUF_HIT", -+ "T62x_TI_WRBUF_MISS", -+ "T62x_TI_WRBUF_LINE", -+ "T62x_TI_WRBUF_PARTIAL", -+ "T62x_TI_WRBUF_STALL", -+ "T62x_TI_ACTIVE", -+ "T62x_TI_LOADING_DESC", -+ "T62x_TI_INDEX_WAIT", -+ "T62x_TI_INDEX_RANGE_WAIT", -+ "T62x_TI_VERTEX_WAIT", -+ "T62x_TI_PCACHE_WAIT", -+ "T62x_TI_WRBUF_WAIT", -+ "T62x_TI_BUS_READ", -+ "T62x_TI_BUS_WRITE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T62x_TI_UTLB_STALL", -+ "T62x_TI_UTLB_REPLAY_MISS", -+ "T62x_TI_UTLB_REPLAY_FULL", -+ "T62x_TI_UTLB_NEW_MISS", -+ "T62x_TI_UTLB_HIT", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "T62x_SHADER_CORE_ACTIVE", -+ "T62x_FRAG_ACTIVE", -+ "T62x_FRAG_PRIMITIVES", -+ "T62x_FRAG_PRIMITIVES_DROPPED", -+ "T62x_FRAG_CYCLES_DESC", -+ "T62x_FRAG_CYCLES_FPKQ_ACTIVE", -+ "T62x_FRAG_CYCLES_VERT", -+ "T62x_FRAG_CYCLES_TRISETUP", -+ "T62x_FRAG_CYCLES_EZS_ACTIVE", -+ "T62x_FRAG_THREADS", -+ "T62x_FRAG_DUMMY_THREADS", -+ "T62x_FRAG_QUADS_RAST", -+ "T62x_FRAG_QUADS_EZS_TEST", -+ "T62x_FRAG_QUADS_EZS_KILLED", -+ "T62x_FRAG_THREADS_LZS_TEST", -+ "T62x_FRAG_THREADS_LZS_KILLED", -+ "T62x_FRAG_CYCLES_NO_TILE", -+ "T62x_FRAG_NUM_TILES", -+ "T62x_FRAG_TRANS_ELIM", -+ "T62x_COMPUTE_ACTIVE", -+ "T62x_COMPUTE_TASKS", -+ "T62x_COMPUTE_THREADS", -+ "T62x_COMPUTE_CYCLES_DESC", -+ "T62x_TRIPIPE_ACTIVE", -+ "T62x_ARITH_WORDS", -+ "T62x_ARITH_CYCLES_REG", -+ "T62x_ARITH_CYCLES_L0", -+ "T62x_ARITH_FRAG_DEPEND", -+ "T62x_LS_WORDS", -+ "T62x_LS_ISSUES", -+ "T62x_LS_RESTARTS", -+ "T62x_LS_REISSUES_MISS", -+ "T62x_LS_REISSUES_VD", -+ "T62x_LS_REISSUE_ATTRIB_MISS", -+ "T62x_LS_NO_WB", -+ "T62x_TEX_WORDS", -+ "T62x_TEX_BUBBLES", -+ "T62x_TEX_WORDS_L0", -+ "T62x_TEX_WORDS_DESC", -+ "T62x_TEX_ISSUES", -+ "T62x_TEX_RECIRC_FMISS", -+ "T62x_TEX_RECIRC_DESC", -+ "T62x_TEX_RECIRC_MULTI", -+ "T62x_TEX_RECIRC_PMISS", -+ "T62x_TEX_RECIRC_CONF", -+ "T62x_LSC_READ_HITS", -+ "T62x_LSC_READ_MISSES", -+ "T62x_LSC_WRITE_HITS", -+ "T62x_LSC_WRITE_MISSES", -+ "T62x_LSC_ATOMIC_HITS", -+ "T62x_LSC_ATOMIC_MISSES", -+ "T62x_LSC_LINE_FETCHES", -+ "T62x_LSC_DIRTY_LINE", -+ "T62x_LSC_SNOOPS", -+ "T62x_AXI_TLB_STALL", -+ "T62x_AXI_TLB_MISS", -+ "T62x_AXI_TLB_TRANSACTION", -+ "T62x_LS_TLB_MISS", -+ "T62x_LS_TLB_HIT", -+ "T62x_AXI_BEATS_READ", -+ "T62x_AXI_BEATS_WRITTEN", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T62x_MMU_HIT", -+ "T62x_MMU_NEW_MISS", -+ "T62x_MMU_REPLAY_FULL", -+ "T62x_MMU_REPLAY_MISS", -+ "T62x_MMU_TABLE_WALK", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T62x_UTLB_HIT", -+ "T62x_UTLB_NEW_MISS", -+ "T62x_UTLB_REPLAY_FULL", -+ "T62x_UTLB_REPLAY_MISS", -+ "T62x_UTLB_STALL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T62x_L2_EXT_WRITE_BEATS", -+ "T62x_L2_EXT_READ_BEATS", -+ "T62x_L2_ANY_LOOKUP", -+ "T62x_L2_READ_LOOKUP", -+ "T62x_L2_SREAD_LOOKUP", -+ "T62x_L2_READ_REPLAY", -+ "T62x_L2_READ_SNOOP", -+ "T62x_L2_READ_HIT", -+ "T62x_L2_CLEAN_MISS", -+ "T62x_L2_WRITE_LOOKUP", -+ "T62x_L2_SWRITE_LOOKUP", -+ "T62x_L2_WRITE_REPLAY", -+ "T62x_L2_WRITE_SNOOP", -+ "T62x_L2_WRITE_HIT", -+ "T62x_L2_EXT_READ_FULL", -+ "T62x_L2_EXT_READ_HALF", -+ "T62x_L2_EXT_WRITE_FULL", -+ "T62x_L2_EXT_WRITE_HALF", -+ "T62x_L2_EXT_READ", -+ "T62x_L2_EXT_READ_LINE", -+ "T62x_L2_EXT_WRITE", -+ "T62x_L2_EXT_WRITE_LINE", -+ "T62x_L2_EXT_WRITE_SMALL", -+ "T62x_L2_EXT_BARRIER", -+ "T62x_L2_EXT_AR_STALL", -+ "T62x_L2_EXT_R_BUF_FULL", -+ "T62x_L2_EXT_RD_BUF_FULL", -+ "T62x_L2_EXT_R_RAW", -+ "T62x_L2_EXT_W_STALL", -+ "T62x_L2_EXT_W_BUF_FULL", -+ "T62x_L2_EXT_R_W_HAZARD", -+ "T62x_L2_TAG_HAZARD", -+ "T62x_L2_SNOOP_FULL", -+ "T62x_L2_REPLAY_FULL" -+}; -+ -+static const char * const hardware_counters_mali_t72x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T72x_GPU_ACTIVE", -+ "T72x_IRQ_ACTIVE", -+ "T72x_JS0_JOBS", -+ "T72x_JS0_TASKS", -+ "T72x_JS0_ACTIVE", -+ "T72x_JS1_JOBS", -+ "T72x_JS1_TASKS", -+ "T72x_JS1_ACTIVE", -+ "T72x_JS2_JOBS", -+ "T72x_JS2_TASKS", -+ "T72x_JS2_ACTIVE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T72x_TI_JOBS_PROCESSED", -+ "T72x_TI_TRIANGLES", -+ "T72x_TI_QUADS", -+ "T72x_TI_POLYGONS", -+ "T72x_TI_POINTS", -+ "T72x_TI_LINES", -+ "T72x_TI_FRONT_FACING", -+ "T72x_TI_BACK_FACING", -+ "T72x_TI_PRIM_VISIBLE", -+ "T72x_TI_PRIM_CULLED", -+ "T72x_TI_PRIM_CLIPPED", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T72x_TI_ACTIVE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "T72x_FRAG_ACTIVE", -+ "T72x_FRAG_PRIMITIVES", -+ "T72x_FRAG_PRIMITIVES_DROPPED", -+ "T72x_FRAG_THREADS", -+ "T72x_FRAG_DUMMY_THREADS", -+ "T72x_FRAG_QUADS_RAST", -+ "T72x_FRAG_QUADS_EZS_TEST", -+ "T72x_FRAG_QUADS_EZS_KILLED", -+ "T72x_FRAG_THREADS_LZS_TEST", -+ "T72x_FRAG_THREADS_LZS_KILLED", -+ "T72x_FRAG_CYCLES_NO_TILE", -+ "T72x_FRAG_NUM_TILES", -+ "T72x_FRAG_TRANS_ELIM", -+ "T72x_COMPUTE_ACTIVE", -+ "T72x_COMPUTE_TASKS", -+ "T72x_COMPUTE_THREADS", -+ "T72x_TRIPIPE_ACTIVE", -+ "T72x_ARITH_WORDS", -+ "T72x_ARITH_CYCLES_REG", -+ "T72x_LS_WORDS", -+ "T72x_LS_ISSUES", -+ "T72x_LS_RESTARTS", -+ "T72x_LS_REISSUES_MISS", -+ "T72x_TEX_WORDS", -+ "T72x_TEX_BUBBLES", -+ "T72x_TEX_ISSUES", -+ "T72x_LSC_READ_HITS", -+ "T72x_LSC_READ_MISSES", -+ "T72x_LSC_WRITE_HITS", -+ "T72x_LSC_WRITE_MISSES", -+ "T72x_LSC_ATOMIC_HITS", -+ "T72x_LSC_ATOMIC_MISSES", -+ "T72x_LSC_LINE_FETCHES", -+ "T72x_LSC_DIRTY_LINE", -+ "T72x_LSC_SNOOPS", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T72x_L2_EXT_WRITE_BEAT", -+ "T72x_L2_EXT_READ_BEAT", -+ "T72x_L2_READ_SNOOP", -+ "T72x_L2_READ_HIT", -+ "T72x_L2_WRITE_SNOOP", -+ "T72x_L2_WRITE_HIT", -+ "T72x_L2_EXT_WRITE_SMALL", -+ "T72x_L2_EXT_BARRIER", -+ "T72x_L2_EXT_AR_STALL", -+ "T72x_L2_EXT_W_STALL", -+ "T72x_L2_SNOOP_FULL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "" -+}; -+ -+static const char * const hardware_counters_mali_t76x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T76x_MESSAGES_SENT", -+ "T76x_MESSAGES_RECEIVED", -+ "T76x_GPU_ACTIVE", -+ "T76x_IRQ_ACTIVE", -+ "T76x_JS0_JOBS", -+ "T76x_JS0_TASKS", -+ "T76x_JS0_ACTIVE", -+ "", -+ "T76x_JS0_WAIT_READ", -+ "T76x_JS0_WAIT_ISSUE", -+ "T76x_JS0_WAIT_DEPEND", -+ "T76x_JS0_WAIT_FINISH", -+ "T76x_JS1_JOBS", -+ "T76x_JS1_TASKS", -+ "T76x_JS1_ACTIVE", -+ "", -+ "T76x_JS1_WAIT_READ", -+ "T76x_JS1_WAIT_ISSUE", -+ "T76x_JS1_WAIT_DEPEND", -+ "T76x_JS1_WAIT_FINISH", -+ "T76x_JS2_JOBS", -+ "T76x_JS2_TASKS", -+ "T76x_JS2_ACTIVE", -+ "", -+ "T76x_JS2_WAIT_READ", -+ "T76x_JS2_WAIT_ISSUE", -+ "T76x_JS2_WAIT_DEPEND", -+ "T76x_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T76x_TI_JOBS_PROCESSED", -+ "T76x_TI_TRIANGLES", -+ "T76x_TI_QUADS", -+ "T76x_TI_POLYGONS", -+ "T76x_TI_POINTS", -+ "T76x_TI_LINES", -+ "T76x_TI_VCACHE_HIT", -+ "T76x_TI_VCACHE_MISS", -+ "T76x_TI_FRONT_FACING", -+ "T76x_TI_BACK_FACING", -+ "T76x_TI_PRIM_VISIBLE", -+ "T76x_TI_PRIM_CULLED", -+ "T76x_TI_PRIM_CLIPPED", -+ "T76x_TI_LEVEL0", -+ "T76x_TI_LEVEL1", -+ "T76x_TI_LEVEL2", -+ "T76x_TI_LEVEL3", -+ "T76x_TI_LEVEL4", -+ "T76x_TI_LEVEL5", -+ "T76x_TI_LEVEL6", -+ "T76x_TI_LEVEL7", -+ "T76x_TI_COMMAND_1", -+ "T76x_TI_COMMAND_2", -+ "T76x_TI_COMMAND_3", -+ "T76x_TI_COMMAND_4", -+ "T76x_TI_COMMAND_5_7", -+ "T76x_TI_COMMAND_8_15", -+ "T76x_TI_COMMAND_16_63", -+ "T76x_TI_COMMAND_64", -+ "T76x_TI_COMPRESS_IN", -+ "T76x_TI_COMPRESS_OUT", -+ "T76x_TI_COMPRESS_FLUSH", -+ "T76x_TI_TIMESTAMPS", -+ "T76x_TI_PCACHE_HIT", -+ "T76x_TI_PCACHE_MISS", -+ "T76x_TI_PCACHE_LINE", -+ "T76x_TI_PCACHE_STALL", -+ "T76x_TI_WRBUF_HIT", -+ "T76x_TI_WRBUF_MISS", -+ "T76x_TI_WRBUF_LINE", -+ "T76x_TI_WRBUF_PARTIAL", -+ "T76x_TI_WRBUF_STALL", -+ "T76x_TI_ACTIVE", -+ "T76x_TI_LOADING_DESC", -+ "T76x_TI_INDEX_WAIT", -+ "T76x_TI_INDEX_RANGE_WAIT", -+ "T76x_TI_VERTEX_WAIT", -+ "T76x_TI_PCACHE_WAIT", -+ "T76x_TI_WRBUF_WAIT", -+ "T76x_TI_BUS_READ", -+ "T76x_TI_BUS_WRITE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T76x_TI_UTLB_HIT", -+ "T76x_TI_UTLB_NEW_MISS", -+ "T76x_TI_UTLB_REPLAY_FULL", -+ "T76x_TI_UTLB_REPLAY_MISS", -+ "T76x_TI_UTLB_STALL", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "T76x_FRAG_ACTIVE", -+ "T76x_FRAG_PRIMITIVES", -+ "T76x_FRAG_PRIMITIVES_DROPPED", -+ "T76x_FRAG_CYCLES_DESC", -+ "T76x_FRAG_CYCLES_FPKQ_ACTIVE", -+ "T76x_FRAG_CYCLES_VERT", -+ "T76x_FRAG_CYCLES_TRISETUP", -+ "T76x_FRAG_CYCLES_EZS_ACTIVE", -+ "T76x_FRAG_THREADS", -+ "T76x_FRAG_DUMMY_THREADS", -+ "T76x_FRAG_QUADS_RAST", -+ "T76x_FRAG_QUADS_EZS_TEST", -+ "T76x_FRAG_QUADS_EZS_KILLED", -+ "T76x_FRAG_THREADS_LZS_TEST", -+ "T76x_FRAG_THREADS_LZS_KILLED", -+ "T76x_FRAG_CYCLES_NO_TILE", -+ "T76x_FRAG_NUM_TILES", -+ "T76x_FRAG_TRANS_ELIM", -+ "T76x_COMPUTE_ACTIVE", -+ "T76x_COMPUTE_TASKS", -+ "T76x_COMPUTE_THREADS", -+ "T76x_COMPUTE_CYCLES_DESC", -+ "T76x_TRIPIPE_ACTIVE", -+ "T76x_ARITH_WORDS", -+ "T76x_ARITH_CYCLES_REG", -+ "T76x_ARITH_CYCLES_L0", -+ "T76x_ARITH_FRAG_DEPEND", -+ "T76x_LS_WORDS", -+ "T76x_LS_ISSUES", -+ "T76x_LS_REISSUE_ATTR", -+ "T76x_LS_REISSUES_VARY", -+ "T76x_LS_VARY_RV_MISS", -+ "T76x_LS_VARY_RV_HIT", -+ "T76x_LS_NO_UNPARK", -+ "T76x_TEX_WORDS", -+ "T76x_TEX_BUBBLES", -+ "T76x_TEX_WORDS_L0", -+ "T76x_TEX_WORDS_DESC", -+ "T76x_TEX_ISSUES", -+ "T76x_TEX_RECIRC_FMISS", -+ "T76x_TEX_RECIRC_DESC", -+ "T76x_TEX_RECIRC_MULTI", -+ "T76x_TEX_RECIRC_PMISS", -+ "T76x_TEX_RECIRC_CONF", -+ "T76x_LSC_READ_HITS", -+ "T76x_LSC_READ_OP", -+ "T76x_LSC_WRITE_HITS", -+ "T76x_LSC_WRITE_OP", -+ "T76x_LSC_ATOMIC_HITS", -+ "T76x_LSC_ATOMIC_OP", -+ "T76x_LSC_LINE_FETCHES", -+ "T76x_LSC_DIRTY_LINE", -+ "T76x_LSC_SNOOPS", -+ "T76x_AXI_TLB_STALL", -+ "T76x_AXI_TLB_MISS", -+ "T76x_AXI_TLB_TRANSACTION", -+ "T76x_LS_TLB_MISS", -+ "T76x_LS_TLB_HIT", -+ "T76x_AXI_BEATS_READ", -+ "T76x_AXI_BEATS_WRITTEN", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T76x_MMU_HIT", -+ "T76x_MMU_NEW_MISS", -+ "T76x_MMU_REPLAY_FULL", -+ "T76x_MMU_REPLAY_MISS", -+ "T76x_MMU_TABLE_WALK", -+ "T76x_MMU_REQUESTS", -+ "", -+ "", -+ "T76x_UTLB_HIT", -+ "T76x_UTLB_NEW_MISS", -+ "T76x_UTLB_REPLAY_FULL", -+ "T76x_UTLB_REPLAY_MISS", -+ "T76x_UTLB_STALL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T76x_L2_EXT_WRITE_BEATS", -+ "T76x_L2_EXT_READ_BEATS", -+ "T76x_L2_ANY_LOOKUP", -+ "T76x_L2_READ_LOOKUP", -+ "T76x_L2_SREAD_LOOKUP", -+ "T76x_L2_READ_REPLAY", -+ "T76x_L2_READ_SNOOP", -+ "T76x_L2_READ_HIT", -+ "T76x_L2_CLEAN_MISS", -+ "T76x_L2_WRITE_LOOKUP", -+ "T76x_L2_SWRITE_LOOKUP", -+ "T76x_L2_WRITE_REPLAY", -+ "T76x_L2_WRITE_SNOOP", -+ "T76x_L2_WRITE_HIT", -+ "T76x_L2_EXT_READ_FULL", -+ "", -+ "T76x_L2_EXT_WRITE_FULL", -+ "T76x_L2_EXT_R_W_HAZARD", -+ "T76x_L2_EXT_READ", -+ "T76x_L2_EXT_READ_LINE", -+ "T76x_L2_EXT_WRITE", -+ "T76x_L2_EXT_WRITE_LINE", -+ "T76x_L2_EXT_WRITE_SMALL", -+ "T76x_L2_EXT_BARRIER", -+ "T76x_L2_EXT_AR_STALL", -+ "T76x_L2_EXT_R_BUF_FULL", -+ "T76x_L2_EXT_RD_BUF_FULL", -+ "T76x_L2_EXT_R_RAW", -+ "T76x_L2_EXT_W_STALL", -+ "T76x_L2_EXT_W_BUF_FULL", -+ "T76x_L2_EXT_R_BUF_FULL", -+ "T76x_L2_TAG_HAZARD", -+ "T76x_L2_SNOOP_FULL", -+ "T76x_L2_REPLAY_FULL" -+}; -+ -+static const char * const hardware_counters_mali_t82x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T82x_MESSAGES_SENT", -+ "T82x_MESSAGES_RECEIVED", -+ "T82x_GPU_ACTIVE", -+ "T82x_IRQ_ACTIVE", -+ "T82x_JS0_JOBS", -+ "T82x_JS0_TASKS", -+ "T82x_JS0_ACTIVE", -+ "", -+ "T82x_JS0_WAIT_READ", -+ "T82x_JS0_WAIT_ISSUE", -+ "T82x_JS0_WAIT_DEPEND", -+ "T82x_JS0_WAIT_FINISH", -+ "T82x_JS1_JOBS", -+ "T82x_JS1_TASKS", -+ "T82x_JS1_ACTIVE", -+ "", -+ "T82x_JS1_WAIT_READ", -+ "T82x_JS1_WAIT_ISSUE", -+ "T82x_JS1_WAIT_DEPEND", -+ "T82x_JS1_WAIT_FINISH", -+ "T82x_JS2_JOBS", -+ "T82x_JS2_TASKS", -+ "T82x_JS2_ACTIVE", -+ "", -+ "T82x_JS2_WAIT_READ", -+ "T82x_JS2_WAIT_ISSUE", -+ "T82x_JS2_WAIT_DEPEND", -+ "T82x_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T82x_TI_JOBS_PROCESSED", -+ "T82x_TI_TRIANGLES", -+ "T82x_TI_QUADS", -+ "T82x_TI_POLYGONS", -+ "T82x_TI_POINTS", -+ "T82x_TI_LINES", -+ "T82x_TI_FRONT_FACING", -+ "T82x_TI_BACK_FACING", -+ "T82x_TI_PRIM_VISIBLE", -+ "T82x_TI_PRIM_CULLED", -+ "T82x_TI_PRIM_CLIPPED", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T82x_TI_ACTIVE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "T82x_FRAG_ACTIVE", -+ "T82x_FRAG_PRIMITIVES", -+ "T82x_FRAG_PRIMITIVES_DROPPED", -+ "T82x_FRAG_CYCLES_DESC", -+ "T82x_FRAG_CYCLES_FPKQ_ACTIVE", -+ "T82x_FRAG_CYCLES_VERT", -+ "T82x_FRAG_CYCLES_TRISETUP", -+ "T82x_FRAG_CYCLES_EZS_ACTIVE", -+ "T82x_FRAG_THREADS", -+ "T82x_FRAG_DUMMY_THREADS", -+ "T82x_FRAG_QUADS_RAST", -+ "T82x_FRAG_QUADS_EZS_TEST", -+ "T82x_FRAG_QUADS_EZS_KILLED", -+ "T82x_FRAG_THREADS_LZS_TEST", -+ "T82x_FRAG_THREADS_LZS_KILLED", -+ "T82x_FRAG_CYCLES_NO_TILE", -+ "T82x_FRAG_NUM_TILES", -+ "T82x_FRAG_TRANS_ELIM", -+ "T82x_COMPUTE_ACTIVE", -+ "T82x_COMPUTE_TASKS", -+ "T82x_COMPUTE_THREADS", -+ "T82x_COMPUTE_CYCLES_DESC", -+ "T82x_TRIPIPE_ACTIVE", -+ "T82x_ARITH_WORDS", -+ "T82x_ARITH_CYCLES_REG", -+ "T82x_ARITH_CYCLES_L0", -+ "T82x_ARITH_FRAG_DEPEND", -+ "T82x_LS_WORDS", -+ "T82x_LS_ISSUES", -+ "T82x_LS_REISSUE_ATTR", -+ "T82x_LS_REISSUES_VARY", -+ "T82x_LS_VARY_RV_MISS", -+ "T82x_LS_VARY_RV_HIT", -+ "T82x_LS_NO_UNPARK", -+ "T82x_TEX_WORDS", -+ "T82x_TEX_BUBBLES", -+ "T82x_TEX_WORDS_L0", -+ "T82x_TEX_WORDS_DESC", -+ "T82x_TEX_ISSUES", -+ "T82x_TEX_RECIRC_FMISS", -+ "T82x_TEX_RECIRC_DESC", -+ "T82x_TEX_RECIRC_MULTI", -+ "T82x_TEX_RECIRC_PMISS", -+ "T82x_TEX_RECIRC_CONF", -+ "T82x_LSC_READ_HITS", -+ "T82x_LSC_READ_OP", -+ "T82x_LSC_WRITE_HITS", -+ "T82x_LSC_WRITE_OP", -+ "T82x_LSC_ATOMIC_HITS", -+ "T82x_LSC_ATOMIC_OP", -+ "T82x_LSC_LINE_FETCHES", -+ "T82x_LSC_DIRTY_LINE", -+ "T82x_LSC_SNOOPS", -+ "T82x_AXI_TLB_STALL", -+ "T82x_AXI_TLB_MISS", -+ "T82x_AXI_TLB_TRANSACTION", -+ "T82x_LS_TLB_MISS", -+ "T82x_LS_TLB_HIT", -+ "T82x_AXI_BEATS_READ", -+ "T82x_AXI_BEATS_WRITTEN", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T82x_MMU_HIT", -+ "T82x_MMU_NEW_MISS", -+ "T82x_MMU_REPLAY_FULL", -+ "T82x_MMU_REPLAY_MISS", -+ "T82x_MMU_TABLE_WALK", -+ "T82x_MMU_REQUESTS", -+ "", -+ "", -+ "T82x_UTLB_HIT", -+ "T82x_UTLB_NEW_MISS", -+ "T82x_UTLB_REPLAY_FULL", -+ "T82x_UTLB_REPLAY_MISS", -+ "T82x_UTLB_STALL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T82x_L2_EXT_WRITE_BEATS", -+ "T82x_L2_EXT_READ_BEATS", -+ "T82x_L2_ANY_LOOKUP", -+ "T82x_L2_READ_LOOKUP", -+ "T82x_L2_SREAD_LOOKUP", -+ "T82x_L2_READ_REPLAY", -+ "T82x_L2_READ_SNOOP", -+ "T82x_L2_READ_HIT", -+ "T82x_L2_CLEAN_MISS", -+ "T82x_L2_WRITE_LOOKUP", -+ "T82x_L2_SWRITE_LOOKUP", -+ "T82x_L2_WRITE_REPLAY", -+ "T82x_L2_WRITE_SNOOP", -+ "T82x_L2_WRITE_HIT", -+ "T82x_L2_EXT_READ_FULL", -+ "", -+ "T82x_L2_EXT_WRITE_FULL", -+ "T82x_L2_EXT_R_W_HAZARD", -+ "T82x_L2_EXT_READ", -+ "T82x_L2_EXT_READ_LINE", -+ "T82x_L2_EXT_WRITE", -+ "T82x_L2_EXT_WRITE_LINE", -+ "T82x_L2_EXT_WRITE_SMALL", -+ "T82x_L2_EXT_BARRIER", -+ "T82x_L2_EXT_AR_STALL", -+ "T82x_L2_EXT_R_BUF_FULL", -+ "T82x_L2_EXT_RD_BUF_FULL", -+ "T82x_L2_EXT_R_RAW", -+ "T82x_L2_EXT_W_STALL", -+ "T82x_L2_EXT_W_BUF_FULL", -+ "T82x_L2_EXT_R_BUF_FULL", -+ "T82x_L2_TAG_HAZARD", -+ "T82x_L2_SNOOP_FULL", -+ "T82x_L2_REPLAY_FULL" -+}; -+ -+static const char * const hardware_counters_mali_t83x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T83x_MESSAGES_SENT", -+ "T83x_MESSAGES_RECEIVED", -+ "T83x_GPU_ACTIVE", -+ "T83x_IRQ_ACTIVE", -+ "T83x_JS0_JOBS", -+ "T83x_JS0_TASKS", -+ "T83x_JS0_ACTIVE", -+ "", -+ "T83x_JS0_WAIT_READ", -+ "T83x_JS0_WAIT_ISSUE", -+ "T83x_JS0_WAIT_DEPEND", -+ "T83x_JS0_WAIT_FINISH", -+ "T83x_JS1_JOBS", -+ "T83x_JS1_TASKS", -+ "T83x_JS1_ACTIVE", -+ "", -+ "T83x_JS1_WAIT_READ", -+ "T83x_JS1_WAIT_ISSUE", -+ "T83x_JS1_WAIT_DEPEND", -+ "T83x_JS1_WAIT_FINISH", -+ "T83x_JS2_JOBS", -+ "T83x_JS2_TASKS", -+ "T83x_JS2_ACTIVE", -+ "", -+ "T83x_JS2_WAIT_READ", -+ "T83x_JS2_WAIT_ISSUE", -+ "T83x_JS2_WAIT_DEPEND", -+ "T83x_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T83x_TI_JOBS_PROCESSED", -+ "T83x_TI_TRIANGLES", -+ "T83x_TI_QUADS", -+ "T83x_TI_POLYGONS", -+ "T83x_TI_POINTS", -+ "T83x_TI_LINES", -+ "T83x_TI_FRONT_FACING", -+ "T83x_TI_BACK_FACING", -+ "T83x_TI_PRIM_VISIBLE", -+ "T83x_TI_PRIM_CULLED", -+ "T83x_TI_PRIM_CLIPPED", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T83x_TI_ACTIVE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "T83x_FRAG_ACTIVE", -+ "T83x_FRAG_PRIMITIVES", -+ "T83x_FRAG_PRIMITIVES_DROPPED", -+ "T83x_FRAG_CYCLES_DESC", -+ "T83x_FRAG_CYCLES_FPKQ_ACTIVE", -+ "T83x_FRAG_CYCLES_VERT", -+ "T83x_FRAG_CYCLES_TRISETUP", -+ "T83x_FRAG_CYCLES_EZS_ACTIVE", -+ "T83x_FRAG_THREADS", -+ "T83x_FRAG_DUMMY_THREADS", -+ "T83x_FRAG_QUADS_RAST", -+ "T83x_FRAG_QUADS_EZS_TEST", -+ "T83x_FRAG_QUADS_EZS_KILLED", -+ "T83x_FRAG_THREADS_LZS_TEST", -+ "T83x_FRAG_THREADS_LZS_KILLED", -+ "T83x_FRAG_CYCLES_NO_TILE", -+ "T83x_FRAG_NUM_TILES", -+ "T83x_FRAG_TRANS_ELIM", -+ "T83x_COMPUTE_ACTIVE", -+ "T83x_COMPUTE_TASKS", -+ "T83x_COMPUTE_THREADS", -+ "T83x_COMPUTE_CYCLES_DESC", -+ "T83x_TRIPIPE_ACTIVE", -+ "T83x_ARITH_WORDS", -+ "T83x_ARITH_CYCLES_REG", -+ "T83x_ARITH_CYCLES_L0", -+ "T83x_ARITH_FRAG_DEPEND", -+ "T83x_LS_WORDS", -+ "T83x_LS_ISSUES", -+ "T83x_LS_REISSUE_ATTR", -+ "T83x_LS_REISSUES_VARY", -+ "T83x_LS_VARY_RV_MISS", -+ "T83x_LS_VARY_RV_HIT", -+ "T83x_LS_NO_UNPARK", -+ "T83x_TEX_WORDS", -+ "T83x_TEX_BUBBLES", -+ "T83x_TEX_WORDS_L0", -+ "T83x_TEX_WORDS_DESC", -+ "T83x_TEX_ISSUES", -+ "T83x_TEX_RECIRC_FMISS", -+ "T83x_TEX_RECIRC_DESC", -+ "T83x_TEX_RECIRC_MULTI", -+ "T83x_TEX_RECIRC_PMISS", -+ "T83x_TEX_RECIRC_CONF", -+ "T83x_LSC_READ_HITS", -+ "T83x_LSC_READ_OP", -+ "T83x_LSC_WRITE_HITS", -+ "T83x_LSC_WRITE_OP", -+ "T83x_LSC_ATOMIC_HITS", -+ "T83x_LSC_ATOMIC_OP", -+ "T83x_LSC_LINE_FETCHES", -+ "T83x_LSC_DIRTY_LINE", -+ "T83x_LSC_SNOOPS", -+ "T83x_AXI_TLB_STALL", -+ "T83x_AXI_TLB_MISS", -+ "T83x_AXI_TLB_TRANSACTION", -+ "T83x_LS_TLB_MISS", -+ "T83x_LS_TLB_HIT", -+ "T83x_AXI_BEATS_READ", -+ "T83x_AXI_BEATS_WRITTEN", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T83x_MMU_HIT", -+ "T83x_MMU_NEW_MISS", -+ "T83x_MMU_REPLAY_FULL", -+ "T83x_MMU_REPLAY_MISS", -+ "T83x_MMU_TABLE_WALK", -+ "T83x_MMU_REQUESTS", -+ "", -+ "", -+ "T83x_UTLB_HIT", -+ "T83x_UTLB_NEW_MISS", -+ "T83x_UTLB_REPLAY_FULL", -+ "T83x_UTLB_REPLAY_MISS", -+ "T83x_UTLB_STALL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T83x_L2_EXT_WRITE_BEATS", -+ "T83x_L2_EXT_READ_BEATS", -+ "T83x_L2_ANY_LOOKUP", -+ "T83x_L2_READ_LOOKUP", -+ "T83x_L2_SREAD_LOOKUP", -+ "T83x_L2_READ_REPLAY", -+ "T83x_L2_READ_SNOOP", -+ "T83x_L2_READ_HIT", -+ "T83x_L2_CLEAN_MISS", -+ "T83x_L2_WRITE_LOOKUP", -+ "T83x_L2_SWRITE_LOOKUP", -+ "T83x_L2_WRITE_REPLAY", -+ "T83x_L2_WRITE_SNOOP", -+ "T83x_L2_WRITE_HIT", -+ "T83x_L2_EXT_READ_FULL", -+ "", -+ "T83x_L2_EXT_WRITE_FULL", -+ "T83x_L2_EXT_R_W_HAZARD", -+ "T83x_L2_EXT_READ", -+ "T83x_L2_EXT_READ_LINE", -+ "T83x_L2_EXT_WRITE", -+ "T83x_L2_EXT_WRITE_LINE", -+ "T83x_L2_EXT_WRITE_SMALL", -+ "T83x_L2_EXT_BARRIER", -+ "T83x_L2_EXT_AR_STALL", -+ "T83x_L2_EXT_R_BUF_FULL", -+ "T83x_L2_EXT_RD_BUF_FULL", -+ "T83x_L2_EXT_R_RAW", -+ "T83x_L2_EXT_W_STALL", -+ "T83x_L2_EXT_W_BUF_FULL", -+ "T83x_L2_EXT_R_BUF_FULL", -+ "T83x_L2_TAG_HAZARD", -+ "T83x_L2_SNOOP_FULL", -+ "T83x_L2_REPLAY_FULL" -+}; -+ -+static const char * const hardware_counters_mali_t86x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T86x_MESSAGES_SENT", -+ "T86x_MESSAGES_RECEIVED", -+ "T86x_GPU_ACTIVE", -+ "T86x_IRQ_ACTIVE", -+ "T86x_JS0_JOBS", -+ "T86x_JS0_TASKS", -+ "T86x_JS0_ACTIVE", -+ "", -+ "T86x_JS0_WAIT_READ", -+ "T86x_JS0_WAIT_ISSUE", -+ "T86x_JS0_WAIT_DEPEND", -+ "T86x_JS0_WAIT_FINISH", -+ "T86x_JS1_JOBS", -+ "T86x_JS1_TASKS", -+ "T86x_JS1_ACTIVE", -+ "", -+ "T86x_JS1_WAIT_READ", -+ "T86x_JS1_WAIT_ISSUE", -+ "T86x_JS1_WAIT_DEPEND", -+ "T86x_JS1_WAIT_FINISH", -+ "T86x_JS2_JOBS", -+ "T86x_JS2_TASKS", -+ "T86x_JS2_ACTIVE", -+ "", -+ "T86x_JS2_WAIT_READ", -+ "T86x_JS2_WAIT_ISSUE", -+ "T86x_JS2_WAIT_DEPEND", -+ "T86x_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T86x_TI_JOBS_PROCESSED", -+ "T86x_TI_TRIANGLES", -+ "T86x_TI_QUADS", -+ "T86x_TI_POLYGONS", -+ "T86x_TI_POINTS", -+ "T86x_TI_LINES", -+ "T86x_TI_VCACHE_HIT", -+ "T86x_TI_VCACHE_MISS", -+ "T86x_TI_FRONT_FACING", -+ "T86x_TI_BACK_FACING", -+ "T86x_TI_PRIM_VISIBLE", -+ "T86x_TI_PRIM_CULLED", -+ "T86x_TI_PRIM_CLIPPED", -+ "T86x_TI_LEVEL0", -+ "T86x_TI_LEVEL1", -+ "T86x_TI_LEVEL2", -+ "T86x_TI_LEVEL3", -+ "T86x_TI_LEVEL4", -+ "T86x_TI_LEVEL5", -+ "T86x_TI_LEVEL6", -+ "T86x_TI_LEVEL7", -+ "T86x_TI_COMMAND_1", -+ "T86x_TI_COMMAND_2", -+ "T86x_TI_COMMAND_3", -+ "T86x_TI_COMMAND_4", -+ "T86x_TI_COMMAND_5_7", -+ "T86x_TI_COMMAND_8_15", -+ "T86x_TI_COMMAND_16_63", -+ "T86x_TI_COMMAND_64", -+ "T86x_TI_COMPRESS_IN", -+ "T86x_TI_COMPRESS_OUT", -+ "T86x_TI_COMPRESS_FLUSH", -+ "T86x_TI_TIMESTAMPS", -+ "T86x_TI_PCACHE_HIT", -+ "T86x_TI_PCACHE_MISS", -+ "T86x_TI_PCACHE_LINE", -+ "T86x_TI_PCACHE_STALL", -+ "T86x_TI_WRBUF_HIT", -+ "T86x_TI_WRBUF_MISS", -+ "T86x_TI_WRBUF_LINE", -+ "T86x_TI_WRBUF_PARTIAL", -+ "T86x_TI_WRBUF_STALL", -+ "T86x_TI_ACTIVE", -+ "T86x_TI_LOADING_DESC", -+ "T86x_TI_INDEX_WAIT", -+ "T86x_TI_INDEX_RANGE_WAIT", -+ "T86x_TI_VERTEX_WAIT", -+ "T86x_TI_PCACHE_WAIT", -+ "T86x_TI_WRBUF_WAIT", -+ "T86x_TI_BUS_READ", -+ "T86x_TI_BUS_WRITE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T86x_TI_UTLB_HIT", -+ "T86x_TI_UTLB_NEW_MISS", -+ "T86x_TI_UTLB_REPLAY_FULL", -+ "T86x_TI_UTLB_REPLAY_MISS", -+ "T86x_TI_UTLB_STALL", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "T86x_FRAG_ACTIVE", -+ "T86x_FRAG_PRIMITIVES", -+ "T86x_FRAG_PRIMITIVES_DROPPED", -+ "T86x_FRAG_CYCLES_DESC", -+ "T86x_FRAG_CYCLES_FPKQ_ACTIVE", -+ "T86x_FRAG_CYCLES_VERT", -+ "T86x_FRAG_CYCLES_TRISETUP", -+ "T86x_FRAG_CYCLES_EZS_ACTIVE", -+ "T86x_FRAG_THREADS", -+ "T86x_FRAG_DUMMY_THREADS", -+ "T86x_FRAG_QUADS_RAST", -+ "T86x_FRAG_QUADS_EZS_TEST", -+ "T86x_FRAG_QUADS_EZS_KILLED", -+ "T86x_FRAG_THREADS_LZS_TEST", -+ "T86x_FRAG_THREADS_LZS_KILLED", -+ "T86x_FRAG_CYCLES_NO_TILE", -+ "T86x_FRAG_NUM_TILES", -+ "T86x_FRAG_TRANS_ELIM", -+ "T86x_COMPUTE_ACTIVE", -+ "T86x_COMPUTE_TASKS", -+ "T86x_COMPUTE_THREADS", -+ "T86x_COMPUTE_CYCLES_DESC", -+ "T86x_TRIPIPE_ACTIVE", -+ "T86x_ARITH_WORDS", -+ "T86x_ARITH_CYCLES_REG", -+ "T86x_ARITH_CYCLES_L0", -+ "T86x_ARITH_FRAG_DEPEND", -+ "T86x_LS_WORDS", -+ "T86x_LS_ISSUES", -+ "T86x_LS_REISSUE_ATTR", -+ "T86x_LS_REISSUES_VARY", -+ "T86x_LS_VARY_RV_MISS", -+ "T86x_LS_VARY_RV_HIT", -+ "T86x_LS_NO_UNPARK", -+ "T86x_TEX_WORDS", -+ "T86x_TEX_BUBBLES", -+ "T86x_TEX_WORDS_L0", -+ "T86x_TEX_WORDS_DESC", -+ "T86x_TEX_ISSUES", -+ "T86x_TEX_RECIRC_FMISS", -+ "T86x_TEX_RECIRC_DESC", -+ "T86x_TEX_RECIRC_MULTI", -+ "T86x_TEX_RECIRC_PMISS", -+ "T86x_TEX_RECIRC_CONF", -+ "T86x_LSC_READ_HITS", -+ "T86x_LSC_READ_OP", -+ "T86x_LSC_WRITE_HITS", -+ "T86x_LSC_WRITE_OP", -+ "T86x_LSC_ATOMIC_HITS", -+ "T86x_LSC_ATOMIC_OP", -+ "T86x_LSC_LINE_FETCHES", -+ "T86x_LSC_DIRTY_LINE", -+ "T86x_LSC_SNOOPS", -+ "T86x_AXI_TLB_STALL", -+ "T86x_AXI_TLB_MISS", -+ "T86x_AXI_TLB_TRANSACTION", -+ "T86x_LS_TLB_MISS", -+ "T86x_LS_TLB_HIT", -+ "T86x_AXI_BEATS_READ", -+ "T86x_AXI_BEATS_WRITTEN", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T86x_MMU_HIT", -+ "T86x_MMU_NEW_MISS", -+ "T86x_MMU_REPLAY_FULL", -+ "T86x_MMU_REPLAY_MISS", -+ "T86x_MMU_TABLE_WALK", -+ "T86x_MMU_REQUESTS", -+ "", -+ "", -+ "T86x_UTLB_HIT", -+ "T86x_UTLB_NEW_MISS", -+ "T86x_UTLB_REPLAY_FULL", -+ "T86x_UTLB_REPLAY_MISS", -+ "T86x_UTLB_STALL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T86x_L2_EXT_WRITE_BEATS", -+ "T86x_L2_EXT_READ_BEATS", -+ "T86x_L2_ANY_LOOKUP", -+ "T86x_L2_READ_LOOKUP", -+ "T86x_L2_SREAD_LOOKUP", -+ "T86x_L2_READ_REPLAY", -+ "T86x_L2_READ_SNOOP", -+ "T86x_L2_READ_HIT", -+ "T86x_L2_CLEAN_MISS", -+ "T86x_L2_WRITE_LOOKUP", -+ "T86x_L2_SWRITE_LOOKUP", -+ "T86x_L2_WRITE_REPLAY", -+ "T86x_L2_WRITE_SNOOP", -+ "T86x_L2_WRITE_HIT", -+ "T86x_L2_EXT_READ_FULL", -+ "", -+ "T86x_L2_EXT_WRITE_FULL", -+ "T86x_L2_EXT_R_W_HAZARD", -+ "T86x_L2_EXT_READ", -+ "T86x_L2_EXT_READ_LINE", -+ "T86x_L2_EXT_WRITE", -+ "T86x_L2_EXT_WRITE_LINE", -+ "T86x_L2_EXT_WRITE_SMALL", -+ "T86x_L2_EXT_BARRIER", -+ "T86x_L2_EXT_AR_STALL", -+ "T86x_L2_EXT_R_BUF_FULL", -+ "T86x_L2_EXT_RD_BUF_FULL", -+ "T86x_L2_EXT_R_RAW", -+ "T86x_L2_EXT_W_STALL", -+ "T86x_L2_EXT_W_BUF_FULL", -+ "T86x_L2_EXT_R_BUF_FULL", -+ "T86x_L2_TAG_HAZARD", -+ "T86x_L2_SNOOP_FULL", -+ "T86x_L2_REPLAY_FULL" -+}; -+ -+static const char * const hardware_counters_mali_t88x[] = { -+ /* Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "T88x_MESSAGES_SENT", -+ "T88x_MESSAGES_RECEIVED", -+ "T88x_GPU_ACTIVE", -+ "T88x_IRQ_ACTIVE", -+ "T88x_JS0_JOBS", -+ "T88x_JS0_TASKS", -+ "T88x_JS0_ACTIVE", -+ "", -+ "T88x_JS0_WAIT_READ", -+ "T88x_JS0_WAIT_ISSUE", -+ "T88x_JS0_WAIT_DEPEND", -+ "T88x_JS0_WAIT_FINISH", -+ "T88x_JS1_JOBS", -+ "T88x_JS1_TASKS", -+ "T88x_JS1_ACTIVE", -+ "", -+ "T88x_JS1_WAIT_READ", -+ "T88x_JS1_WAIT_ISSUE", -+ "T88x_JS1_WAIT_DEPEND", -+ "T88x_JS1_WAIT_FINISH", -+ "T88x_JS2_JOBS", -+ "T88x_JS2_TASKS", -+ "T88x_JS2_ACTIVE", -+ "", -+ "T88x_JS2_WAIT_READ", -+ "T88x_JS2_WAIT_ISSUE", -+ "T88x_JS2_WAIT_DEPEND", -+ "T88x_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /*Tiler */ -+ "", -+ "", -+ "", -+ "T88x_TI_JOBS_PROCESSED", -+ "T88x_TI_TRIANGLES", -+ "T88x_TI_QUADS", -+ "T88x_TI_POLYGONS", -+ "T88x_TI_POINTS", -+ "T88x_TI_LINES", -+ "T88x_TI_VCACHE_HIT", -+ "T88x_TI_VCACHE_MISS", -+ "T88x_TI_FRONT_FACING", -+ "T88x_TI_BACK_FACING", -+ "T88x_TI_PRIM_VISIBLE", -+ "T88x_TI_PRIM_CULLED", -+ "T88x_TI_PRIM_CLIPPED", -+ "T88x_TI_LEVEL0", -+ "T88x_TI_LEVEL1", -+ "T88x_TI_LEVEL2", -+ "T88x_TI_LEVEL3", -+ "T88x_TI_LEVEL4", -+ "T88x_TI_LEVEL5", -+ "T88x_TI_LEVEL6", -+ "T88x_TI_LEVEL7", -+ "T88x_TI_COMMAND_1", -+ "T88x_TI_COMMAND_2", -+ "T88x_TI_COMMAND_3", -+ "T88x_TI_COMMAND_4", -+ "T88x_TI_COMMAND_5_7", -+ "T88x_TI_COMMAND_8_15", -+ "T88x_TI_COMMAND_16_63", -+ "T88x_TI_COMMAND_64", -+ "T88x_TI_COMPRESS_IN", -+ "T88x_TI_COMPRESS_OUT", -+ "T88x_TI_COMPRESS_FLUSH", -+ "T88x_TI_TIMESTAMPS", -+ "T88x_TI_PCACHE_HIT", -+ "T88x_TI_PCACHE_MISS", -+ "T88x_TI_PCACHE_LINE", -+ "T88x_TI_PCACHE_STALL", -+ "T88x_TI_WRBUF_HIT", -+ "T88x_TI_WRBUF_MISS", -+ "T88x_TI_WRBUF_LINE", -+ "T88x_TI_WRBUF_PARTIAL", -+ "T88x_TI_WRBUF_STALL", -+ "T88x_TI_ACTIVE", -+ "T88x_TI_LOADING_DESC", -+ "T88x_TI_INDEX_WAIT", -+ "T88x_TI_INDEX_RANGE_WAIT", -+ "T88x_TI_VERTEX_WAIT", -+ "T88x_TI_PCACHE_WAIT", -+ "T88x_TI_WRBUF_WAIT", -+ "T88x_TI_BUS_READ", -+ "T88x_TI_BUS_WRITE", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T88x_TI_UTLB_HIT", -+ "T88x_TI_UTLB_NEW_MISS", -+ "T88x_TI_UTLB_REPLAY_FULL", -+ "T88x_TI_UTLB_REPLAY_MISS", -+ "T88x_TI_UTLB_STALL", -+ -+ /* Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "T88x_FRAG_ACTIVE", -+ "T88x_FRAG_PRIMITIVES", -+ "T88x_FRAG_PRIMITIVES_DROPPED", -+ "T88x_FRAG_CYCLES_DESC", -+ "T88x_FRAG_CYCLES_FPKQ_ACTIVE", -+ "T88x_FRAG_CYCLES_VERT", -+ "T88x_FRAG_CYCLES_TRISETUP", -+ "T88x_FRAG_CYCLES_EZS_ACTIVE", -+ "T88x_FRAG_THREADS", -+ "T88x_FRAG_DUMMY_THREADS", -+ "T88x_FRAG_QUADS_RAST", -+ "T88x_FRAG_QUADS_EZS_TEST", -+ "T88x_FRAG_QUADS_EZS_KILLED", -+ "T88x_FRAG_THREADS_LZS_TEST", -+ "T88x_FRAG_THREADS_LZS_KILLED", -+ "T88x_FRAG_CYCLES_NO_TILE", -+ "T88x_FRAG_NUM_TILES", -+ "T88x_FRAG_TRANS_ELIM", -+ "T88x_COMPUTE_ACTIVE", -+ "T88x_COMPUTE_TASKS", -+ "T88x_COMPUTE_THREADS", -+ "T88x_COMPUTE_CYCLES_DESC", -+ "T88x_TRIPIPE_ACTIVE", -+ "T88x_ARITH_WORDS", -+ "T88x_ARITH_CYCLES_REG", -+ "T88x_ARITH_CYCLES_L0", -+ "T88x_ARITH_FRAG_DEPEND", -+ "T88x_LS_WORDS", -+ "T88x_LS_ISSUES", -+ "T88x_LS_REISSUE_ATTR", -+ "T88x_LS_REISSUES_VARY", -+ "T88x_LS_VARY_RV_MISS", -+ "T88x_LS_VARY_RV_HIT", -+ "T88x_LS_NO_UNPARK", -+ "T88x_TEX_WORDS", -+ "T88x_TEX_BUBBLES", -+ "T88x_TEX_WORDS_L0", -+ "T88x_TEX_WORDS_DESC", -+ "T88x_TEX_ISSUES", -+ "T88x_TEX_RECIRC_FMISS", -+ "T88x_TEX_RECIRC_DESC", -+ "T88x_TEX_RECIRC_MULTI", -+ "T88x_TEX_RECIRC_PMISS", -+ "T88x_TEX_RECIRC_CONF", -+ "T88x_LSC_READ_HITS", -+ "T88x_LSC_READ_OP", -+ "T88x_LSC_WRITE_HITS", -+ "T88x_LSC_WRITE_OP", -+ "T88x_LSC_ATOMIC_HITS", -+ "T88x_LSC_ATOMIC_OP", -+ "T88x_LSC_LINE_FETCHES", -+ "T88x_LSC_DIRTY_LINE", -+ "T88x_LSC_SNOOPS", -+ "T88x_AXI_TLB_STALL", -+ "T88x_AXI_TLB_MISS", -+ "T88x_AXI_TLB_TRANSACTION", -+ "T88x_LS_TLB_MISS", -+ "T88x_LS_TLB_HIT", -+ "T88x_AXI_BEATS_READ", -+ "T88x_AXI_BEATS_WRITTEN", -+ -+ /*L2 and MMU */ -+ "", -+ "", -+ "", -+ "", -+ "T88x_MMU_HIT", -+ "T88x_MMU_NEW_MISS", -+ "T88x_MMU_REPLAY_FULL", -+ "T88x_MMU_REPLAY_MISS", -+ "T88x_MMU_TABLE_WALK", -+ "T88x_MMU_REQUESTS", -+ "", -+ "", -+ "T88x_UTLB_HIT", -+ "T88x_UTLB_NEW_MISS", -+ "T88x_UTLB_REPLAY_FULL", -+ "T88x_UTLB_REPLAY_MISS", -+ "T88x_UTLB_STALL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "T88x_L2_EXT_WRITE_BEATS", -+ "T88x_L2_EXT_READ_BEATS", -+ "T88x_L2_ANY_LOOKUP", -+ "T88x_L2_READ_LOOKUP", -+ "T88x_L2_SREAD_LOOKUP", -+ "T88x_L2_READ_REPLAY", -+ "T88x_L2_READ_SNOOP", -+ "T88x_L2_READ_HIT", -+ "T88x_L2_CLEAN_MISS", -+ "T88x_L2_WRITE_LOOKUP", -+ "T88x_L2_SWRITE_LOOKUP", -+ "T88x_L2_WRITE_REPLAY", -+ "T88x_L2_WRITE_SNOOP", -+ "T88x_L2_WRITE_HIT", -+ "T88x_L2_EXT_READ_FULL", -+ "", -+ "T88x_L2_EXT_WRITE_FULL", -+ "T88x_L2_EXT_R_W_HAZARD", -+ "T88x_L2_EXT_READ", -+ "T88x_L2_EXT_READ_LINE", -+ "T88x_L2_EXT_WRITE", -+ "T88x_L2_EXT_WRITE_LINE", -+ "T88x_L2_EXT_WRITE_SMALL", -+ "T88x_L2_EXT_BARRIER", -+ "T88x_L2_EXT_AR_STALL", -+ "T88x_L2_EXT_R_BUF_FULL", -+ "T88x_L2_EXT_RD_BUF_FULL", -+ "T88x_L2_EXT_R_RAW", -+ "T88x_L2_EXT_W_STALL", -+ "T88x_L2_EXT_W_BUF_FULL", -+ "T88x_L2_EXT_R_BUF_FULL", -+ "T88x_L2_TAG_HAZARD", -+ "T88x_L2_SNOOP_FULL", -+ "T88x_L2_REPLAY_FULL" -+}; -+ -+#include "mali_kbase_gator_hwcnt_names_tmix.h" -+ -+#include "mali_kbase_gator_hwcnt_names_thex.h" -+ -+#include "mali_kbase_gator_hwcnt_names_tsix.h" -+ -+ -+#ifdef MALI_INCLUDE_TKAX -+#include "mali_kbase_gator_hwcnt_names_tkax.h" -+#endif /* MALI_INCLUDE_TKAX */ -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_thex.h b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_thex.h -new file mode 100644 -index 0000000..15fd4ef ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_thex.h -@@ -0,0 +1,291 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * This header was autogenerated, it should not be edited. -+ */ -+ -+#ifndef _KBASE_GATOR_HWCNT_NAMES_THEX_H_ -+#define _KBASE_GATOR_HWCNT_NAMES_THEX_H_ -+ -+static const char * const hardware_counters_mali_tHEx[] = { -+ /* Performance counters for the Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "THEx_MESSAGES_SENT", -+ "THEx_MESSAGES_RECEIVED", -+ "THEx_GPU_ACTIVE", -+ "THEx_IRQ_ACTIVE", -+ "THEx_JS0_JOBS", -+ "THEx_JS0_TASKS", -+ "THEx_JS0_ACTIVE", -+ "", -+ "THEx_JS0_WAIT_READ", -+ "THEx_JS0_WAIT_ISSUE", -+ "THEx_JS0_WAIT_DEPEND", -+ "THEx_JS0_WAIT_FINISH", -+ "THEx_JS1_JOBS", -+ "THEx_JS1_TASKS", -+ "THEx_JS1_ACTIVE", -+ "", -+ "THEx_JS1_WAIT_READ", -+ "THEx_JS1_WAIT_ISSUE", -+ "THEx_JS1_WAIT_DEPEND", -+ "THEx_JS1_WAIT_FINISH", -+ "THEx_JS2_JOBS", -+ "THEx_JS2_TASKS", -+ "THEx_JS2_ACTIVE", -+ "", -+ "THEx_JS2_WAIT_READ", -+ "THEx_JS2_WAIT_ISSUE", -+ "THEx_JS2_WAIT_DEPEND", -+ "THEx_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /* Performance counters for the Tiler */ -+ "", -+ "", -+ "", -+ "", -+ "THEx_TILER_ACTIVE", -+ "THEx_JOBS_PROCESSED", -+ "THEx_TRIANGLES", -+ "THEx_LINES", -+ "THEx_POINTS", -+ "THEx_FRONT_FACING", -+ "THEx_BACK_FACING", -+ "THEx_PRIM_VISIBLE", -+ "THEx_PRIM_CULLED", -+ "THEx_PRIM_CLIPPED", -+ "THEx_PRIM_SAT_CULLED", -+ "THEx_BIN_ALLOC_INIT", -+ "THEx_BIN_ALLOC_OVERFLOW", -+ "THEx_BUS_READ", -+ "", -+ "THEx_BUS_WRITE", -+ "THEx_LOADING_DESC", -+ "THEx_IDVS_POS_SHAD_REQ", -+ "THEx_IDVS_POS_SHAD_WAIT", -+ "THEx_IDVS_POS_SHAD_STALL", -+ "THEx_IDVS_POS_FIFO_FULL", -+ "THEx_PREFETCH_STALL", -+ "THEx_VCACHE_HIT", -+ "THEx_VCACHE_MISS", -+ "THEx_VCACHE_LINE_WAIT", -+ "THEx_VFETCH_POS_READ_WAIT", -+ "THEx_VFETCH_VERTEX_WAIT", -+ "THEx_VFETCH_STALL", -+ "THEx_PRIMASSY_STALL", -+ "THEx_BBOX_GEN_STALL", -+ "THEx_IDVS_VBU_HIT", -+ "THEx_IDVS_VBU_MISS", -+ "THEx_IDVS_VBU_LINE_DEALLOCATE", -+ "THEx_IDVS_VAR_SHAD_REQ", -+ "THEx_IDVS_VAR_SHAD_STALL", -+ "THEx_BINNER_STALL", -+ "THEx_ITER_STALL", -+ "THEx_COMPRESS_MISS", -+ "THEx_COMPRESS_STALL", -+ "THEx_PCACHE_HIT", -+ "THEx_PCACHE_MISS", -+ "THEx_PCACHE_MISS_STALL", -+ "THEx_PCACHE_EVICT_STALL", -+ "THEx_PMGR_PTR_WR_STALL", -+ "THEx_PMGR_PTR_RD_STALL", -+ "THEx_PMGR_CMD_WR_STALL", -+ "THEx_WRBUF_ACTIVE", -+ "THEx_WRBUF_HIT", -+ "THEx_WRBUF_MISS", -+ "THEx_WRBUF_NO_FREE_LINE_STALL", -+ "THEx_WRBUF_NO_AXI_ID_STALL", -+ "THEx_WRBUF_AXI_STALL", -+ "", -+ "", -+ "", -+ "THEx_UTLB_TRANS", -+ "THEx_UTLB_TRANS_HIT", -+ "THEx_UTLB_TRANS_STALL", -+ "THEx_UTLB_TRANS_MISS_DELAY", -+ "THEx_UTLB_MMU_REQ", -+ -+ /* Performance counters for the Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "THEx_FRAG_ACTIVE", -+ "THEx_FRAG_PRIMITIVES", -+ "THEx_FRAG_PRIM_RAST", -+ "THEx_FRAG_FPK_ACTIVE", -+ "THEx_FRAG_STARVING", -+ "THEx_FRAG_WARPS", -+ "THEx_FRAG_PARTIAL_WARPS", -+ "THEx_FRAG_QUADS_RAST", -+ "THEx_FRAG_QUADS_EZS_TEST", -+ "THEx_FRAG_QUADS_EZS_UPDATE", -+ "THEx_FRAG_QUADS_EZS_KILL", -+ "THEx_FRAG_LZS_TEST", -+ "THEx_FRAG_LZS_KILL", -+ "", -+ "THEx_FRAG_PTILES", -+ "THEx_FRAG_TRANS_ELIM", -+ "THEx_QUAD_FPK_KILLER", -+ "", -+ "THEx_COMPUTE_ACTIVE", -+ "THEx_COMPUTE_TASKS", -+ "THEx_COMPUTE_WARPS", -+ "THEx_COMPUTE_STARVING", -+ "THEx_EXEC_CORE_ACTIVE", -+ "THEx_EXEC_ACTIVE", -+ "THEx_EXEC_INSTR_COUNT", -+ "THEx_EXEC_INSTR_DIVERGED", -+ "THEx_EXEC_INSTR_STARVING", -+ "THEx_ARITH_INSTR_SINGLE_FMA", -+ "THEx_ARITH_INSTR_DOUBLE", -+ "THEx_ARITH_INSTR_MSG", -+ "THEx_ARITH_INSTR_MSG_ONLY", -+ "THEx_TEX_INSTR", -+ "THEx_TEX_INSTR_MIPMAP", -+ "THEx_TEX_INSTR_COMPRESSED", -+ "THEx_TEX_INSTR_3D", -+ "THEx_TEX_INSTR_TRILINEAR", -+ "THEx_TEX_COORD_ISSUE", -+ "THEx_TEX_COORD_STALL", -+ "THEx_TEX_STARVE_CACHE", -+ "THEx_TEX_STARVE_FILTER", -+ "THEx_LS_MEM_READ_FULL", -+ "THEx_LS_MEM_READ_SHORT", -+ "THEx_LS_MEM_WRITE_FULL", -+ "THEx_LS_MEM_WRITE_SHORT", -+ "THEx_LS_MEM_ATOMIC", -+ "THEx_VARY_INSTR", -+ "THEx_VARY_SLOT_32", -+ "THEx_VARY_SLOT_16", -+ "THEx_ATTR_INSTR", -+ "THEx_ARITH_INSTR_FP_MUL", -+ "THEx_BEATS_RD_FTC", -+ "THEx_BEATS_RD_FTC_EXT", -+ "THEx_BEATS_RD_LSC", -+ "THEx_BEATS_RD_LSC_EXT", -+ "THEx_BEATS_RD_TEX", -+ "THEx_BEATS_RD_TEX_EXT", -+ "THEx_BEATS_RD_OTHER", -+ "THEx_BEATS_WR_LSC", -+ "THEx_BEATS_WR_TIB", -+ "", -+ -+ /* Performance counters for the Memory System */ -+ "", -+ "", -+ "", -+ "", -+ "THEx_MMU_REQUESTS", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "THEx_L2_RD_MSG_IN", -+ "THEx_L2_RD_MSG_IN_STALL", -+ "THEx_L2_WR_MSG_IN", -+ "THEx_L2_WR_MSG_IN_STALL", -+ "THEx_L2_SNP_MSG_IN", -+ "THEx_L2_SNP_MSG_IN_STALL", -+ "THEx_L2_RD_MSG_OUT", -+ "THEx_L2_RD_MSG_OUT_STALL", -+ "THEx_L2_WR_MSG_OUT", -+ "THEx_L2_ANY_LOOKUP", -+ "THEx_L2_READ_LOOKUP", -+ "THEx_L2_WRITE_LOOKUP", -+ "THEx_L2_EXT_SNOOP_LOOKUP", -+ "THEx_L2_EXT_READ", -+ "THEx_L2_EXT_READ_NOSNP", -+ "THEx_L2_EXT_READ_UNIQUE", -+ "THEx_L2_EXT_READ_BEATS", -+ "THEx_L2_EXT_AR_STALL", -+ "THEx_L2_EXT_AR_CNT_Q1", -+ "THEx_L2_EXT_AR_CNT_Q2", -+ "THEx_L2_EXT_AR_CNT_Q3", -+ "THEx_L2_EXT_RRESP_0_127", -+ "THEx_L2_EXT_RRESP_128_191", -+ "THEx_L2_EXT_RRESP_192_255", -+ "THEx_L2_EXT_RRESP_256_319", -+ "THEx_L2_EXT_RRESP_320_383", -+ "THEx_L2_EXT_WRITE", -+ "THEx_L2_EXT_WRITE_NOSNP_FULL", -+ "THEx_L2_EXT_WRITE_NOSNP_PTL", -+ "THEx_L2_EXT_WRITE_SNP_FULL", -+ "THEx_L2_EXT_WRITE_SNP_PTL", -+ "THEx_L2_EXT_WRITE_BEATS", -+ "THEx_L2_EXT_W_STALL", -+ "THEx_L2_EXT_AW_CNT_Q1", -+ "THEx_L2_EXT_AW_CNT_Q2", -+ "THEx_L2_EXT_AW_CNT_Q3", -+ "THEx_L2_EXT_SNOOP", -+ "THEx_L2_EXT_SNOOP_STALL", -+ "THEx_L2_EXT_SNOOP_RESP_CLEAN", -+ "THEx_L2_EXT_SNOOP_RESP_DATA", -+ "THEx_L2_EXT_SNOOP_INTERNAL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+}; -+ -+#endif /* _KBASE_GATOR_HWCNT_NAMES_THEX_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_tmix.h b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_tmix.h -new file mode 100644 -index 0000000..8a215f7 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_tmix.h -@@ -0,0 +1,291 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * This header was autogenerated, it should not be edited. -+ */ -+ -+#ifndef _KBASE_GATOR_HWCNT_NAMES_TMIX_H_ -+#define _KBASE_GATOR_HWCNT_NAMES_TMIX_H_ -+ -+static const char * const hardware_counters_mali_tMIx[] = { -+ /* Performance counters for the Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "TMIx_MESSAGES_SENT", -+ "TMIx_MESSAGES_RECEIVED", -+ "TMIx_GPU_ACTIVE", -+ "TMIx_IRQ_ACTIVE", -+ "TMIx_JS0_JOBS", -+ "TMIx_JS0_TASKS", -+ "TMIx_JS0_ACTIVE", -+ "", -+ "TMIx_JS0_WAIT_READ", -+ "TMIx_JS0_WAIT_ISSUE", -+ "TMIx_JS0_WAIT_DEPEND", -+ "TMIx_JS0_WAIT_FINISH", -+ "TMIx_JS1_JOBS", -+ "TMIx_JS1_TASKS", -+ "TMIx_JS1_ACTIVE", -+ "", -+ "TMIx_JS1_WAIT_READ", -+ "TMIx_JS1_WAIT_ISSUE", -+ "TMIx_JS1_WAIT_DEPEND", -+ "TMIx_JS1_WAIT_FINISH", -+ "TMIx_JS2_JOBS", -+ "TMIx_JS2_TASKS", -+ "TMIx_JS2_ACTIVE", -+ "", -+ "TMIx_JS2_WAIT_READ", -+ "TMIx_JS2_WAIT_ISSUE", -+ "TMIx_JS2_WAIT_DEPEND", -+ "TMIx_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /* Performance counters for the Tiler */ -+ "", -+ "", -+ "", -+ "", -+ "TMIx_TILER_ACTIVE", -+ "TMIx_JOBS_PROCESSED", -+ "TMIx_TRIANGLES", -+ "TMIx_LINES", -+ "TMIx_POINTS", -+ "TMIx_FRONT_FACING", -+ "TMIx_BACK_FACING", -+ "TMIx_PRIM_VISIBLE", -+ "TMIx_PRIM_CULLED", -+ "TMIx_PRIM_CLIPPED", -+ "TMIx_PRIM_SAT_CULLED", -+ "TMIx_BIN_ALLOC_INIT", -+ "TMIx_BIN_ALLOC_OVERFLOW", -+ "TMIx_BUS_READ", -+ "", -+ "TMIx_BUS_WRITE", -+ "TMIx_LOADING_DESC", -+ "TMIx_IDVS_POS_SHAD_REQ", -+ "TMIx_IDVS_POS_SHAD_WAIT", -+ "TMIx_IDVS_POS_SHAD_STALL", -+ "TMIx_IDVS_POS_FIFO_FULL", -+ "TMIx_PREFETCH_STALL", -+ "TMIx_VCACHE_HIT", -+ "TMIx_VCACHE_MISS", -+ "TMIx_VCACHE_LINE_WAIT", -+ "TMIx_VFETCH_POS_READ_WAIT", -+ "TMIx_VFETCH_VERTEX_WAIT", -+ "TMIx_VFETCH_STALL", -+ "TMIx_PRIMASSY_STALL", -+ "TMIx_BBOX_GEN_STALL", -+ "TMIx_IDVS_VBU_HIT", -+ "TMIx_IDVS_VBU_MISS", -+ "TMIx_IDVS_VBU_LINE_DEALLOCATE", -+ "TMIx_IDVS_VAR_SHAD_REQ", -+ "TMIx_IDVS_VAR_SHAD_STALL", -+ "TMIx_BINNER_STALL", -+ "TMIx_ITER_STALL", -+ "TMIx_COMPRESS_MISS", -+ "TMIx_COMPRESS_STALL", -+ "TMIx_PCACHE_HIT", -+ "TMIx_PCACHE_MISS", -+ "TMIx_PCACHE_MISS_STALL", -+ "TMIx_PCACHE_EVICT_STALL", -+ "TMIx_PMGR_PTR_WR_STALL", -+ "TMIx_PMGR_PTR_RD_STALL", -+ "TMIx_PMGR_CMD_WR_STALL", -+ "TMIx_WRBUF_ACTIVE", -+ "TMIx_WRBUF_HIT", -+ "TMIx_WRBUF_MISS", -+ "TMIx_WRBUF_NO_FREE_LINE_STALL", -+ "TMIx_WRBUF_NO_AXI_ID_STALL", -+ "TMIx_WRBUF_AXI_STALL", -+ "", -+ "", -+ "", -+ "TMIx_UTLB_TRANS", -+ "TMIx_UTLB_TRANS_HIT", -+ "TMIx_UTLB_TRANS_STALL", -+ "TMIx_UTLB_TRANS_MISS_DELAY", -+ "TMIx_UTLB_MMU_REQ", -+ -+ /* Performance counters for the Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "TMIx_FRAG_ACTIVE", -+ "TMIx_FRAG_PRIMITIVES", -+ "TMIx_FRAG_PRIM_RAST", -+ "TMIx_FRAG_FPK_ACTIVE", -+ "TMIx_FRAG_STARVING", -+ "TMIx_FRAG_WARPS", -+ "TMIx_FRAG_PARTIAL_WARPS", -+ "TMIx_FRAG_QUADS_RAST", -+ "TMIx_FRAG_QUADS_EZS_TEST", -+ "TMIx_FRAG_QUADS_EZS_UPDATE", -+ "TMIx_FRAG_QUADS_EZS_KILL", -+ "TMIx_FRAG_LZS_TEST", -+ "TMIx_FRAG_LZS_KILL", -+ "", -+ "TMIx_FRAG_PTILES", -+ "TMIx_FRAG_TRANS_ELIM", -+ "TMIx_QUAD_FPK_KILLER", -+ "", -+ "TMIx_COMPUTE_ACTIVE", -+ "TMIx_COMPUTE_TASKS", -+ "TMIx_COMPUTE_WARPS", -+ "TMIx_COMPUTE_STARVING", -+ "TMIx_EXEC_CORE_ACTIVE", -+ "TMIx_EXEC_ACTIVE", -+ "TMIx_EXEC_INSTR_COUNT", -+ "TMIx_EXEC_INSTR_DIVERGED", -+ "TMIx_EXEC_INSTR_STARVING", -+ "TMIx_ARITH_INSTR_SINGLE_FMA", -+ "TMIx_ARITH_INSTR_DOUBLE", -+ "TMIx_ARITH_INSTR_MSG", -+ "TMIx_ARITH_INSTR_MSG_ONLY", -+ "TMIx_TEX_INSTR", -+ "TMIx_TEX_INSTR_MIPMAP", -+ "TMIx_TEX_INSTR_COMPRESSED", -+ "TMIx_TEX_INSTR_3D", -+ "TMIx_TEX_INSTR_TRILINEAR", -+ "TMIx_TEX_COORD_ISSUE", -+ "TMIx_TEX_COORD_STALL", -+ "TMIx_TEX_STARVE_CACHE", -+ "TMIx_TEX_STARVE_FILTER", -+ "TMIx_LS_MEM_READ_FULL", -+ "TMIx_LS_MEM_READ_SHORT", -+ "TMIx_LS_MEM_WRITE_FULL", -+ "TMIx_LS_MEM_WRITE_SHORT", -+ "TMIx_LS_MEM_ATOMIC", -+ "TMIx_VARY_INSTR", -+ "TMIx_VARY_SLOT_32", -+ "TMIx_VARY_SLOT_16", -+ "TMIx_ATTR_INSTR", -+ "TMIx_ARITH_INSTR_FP_MUL", -+ "TMIx_BEATS_RD_FTC", -+ "TMIx_BEATS_RD_FTC_EXT", -+ "TMIx_BEATS_RD_LSC", -+ "TMIx_BEATS_RD_LSC_EXT", -+ "TMIx_BEATS_RD_TEX", -+ "TMIx_BEATS_RD_TEX_EXT", -+ "TMIx_BEATS_RD_OTHER", -+ "TMIx_BEATS_WR_LSC", -+ "TMIx_BEATS_WR_TIB", -+ "", -+ -+ /* Performance counters for the Memory System */ -+ "", -+ "", -+ "", -+ "", -+ "TMIx_MMU_REQUESTS", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "TMIx_L2_RD_MSG_IN", -+ "TMIx_L2_RD_MSG_IN_STALL", -+ "TMIx_L2_WR_MSG_IN", -+ "TMIx_L2_WR_MSG_IN_STALL", -+ "TMIx_L2_SNP_MSG_IN", -+ "TMIx_L2_SNP_MSG_IN_STALL", -+ "TMIx_L2_RD_MSG_OUT", -+ "TMIx_L2_RD_MSG_OUT_STALL", -+ "TMIx_L2_WR_MSG_OUT", -+ "TMIx_L2_ANY_LOOKUP", -+ "TMIx_L2_READ_LOOKUP", -+ "TMIx_L2_WRITE_LOOKUP", -+ "TMIx_L2_EXT_SNOOP_LOOKUP", -+ "TMIx_L2_EXT_READ", -+ "TMIx_L2_EXT_READ_NOSNP", -+ "TMIx_L2_EXT_READ_UNIQUE", -+ "TMIx_L2_EXT_READ_BEATS", -+ "TMIx_L2_EXT_AR_STALL", -+ "TMIx_L2_EXT_AR_CNT_Q1", -+ "TMIx_L2_EXT_AR_CNT_Q2", -+ "TMIx_L2_EXT_AR_CNT_Q3", -+ "TMIx_L2_EXT_RRESP_0_127", -+ "TMIx_L2_EXT_RRESP_128_191", -+ "TMIx_L2_EXT_RRESP_192_255", -+ "TMIx_L2_EXT_RRESP_256_319", -+ "TMIx_L2_EXT_RRESP_320_383", -+ "TMIx_L2_EXT_WRITE", -+ "TMIx_L2_EXT_WRITE_NOSNP_FULL", -+ "TMIx_L2_EXT_WRITE_NOSNP_PTL", -+ "TMIx_L2_EXT_WRITE_SNP_FULL", -+ "TMIx_L2_EXT_WRITE_SNP_PTL", -+ "TMIx_L2_EXT_WRITE_BEATS", -+ "TMIx_L2_EXT_W_STALL", -+ "TMIx_L2_EXT_AW_CNT_Q1", -+ "TMIx_L2_EXT_AW_CNT_Q2", -+ "TMIx_L2_EXT_AW_CNT_Q3", -+ "TMIx_L2_EXT_SNOOP", -+ "TMIx_L2_EXT_SNOOP_STALL", -+ "TMIx_L2_EXT_SNOOP_RESP_CLEAN", -+ "TMIx_L2_EXT_SNOOP_RESP_DATA", -+ "TMIx_L2_EXT_SNOOP_INTERNAL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+}; -+ -+#endif /* _KBASE_GATOR_HWCNT_NAMES_TMIX_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_tsix.h b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_tsix.h -new file mode 100644 -index 0000000..fb6a143 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gator_hwcnt_names_tsix.h -@@ -0,0 +1,291 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * This header was autogenerated, it should not be edited. -+ */ -+ -+#ifndef _KBASE_GATOR_HWCNT_NAMES_TSIX_H_ -+#define _KBASE_GATOR_HWCNT_NAMES_TSIX_H_ -+ -+static const char * const hardware_counters_mali_tSIx[] = { -+ /* Performance counters for the Job Manager */ -+ "", -+ "", -+ "", -+ "", -+ "TSIx_MESSAGES_SENT", -+ "TSIx_MESSAGES_RECEIVED", -+ "TSIx_GPU_ACTIVE", -+ "TSIx_IRQ_ACTIVE", -+ "TSIx_JS0_JOBS", -+ "TSIx_JS0_TASKS", -+ "TSIx_JS0_ACTIVE", -+ "", -+ "TSIx_JS0_WAIT_READ", -+ "TSIx_JS0_WAIT_ISSUE", -+ "TSIx_JS0_WAIT_DEPEND", -+ "TSIx_JS0_WAIT_FINISH", -+ "TSIx_JS1_JOBS", -+ "TSIx_JS1_TASKS", -+ "TSIx_JS1_ACTIVE", -+ "", -+ "TSIx_JS1_WAIT_READ", -+ "TSIx_JS1_WAIT_ISSUE", -+ "TSIx_JS1_WAIT_DEPEND", -+ "TSIx_JS1_WAIT_FINISH", -+ "TSIx_JS2_JOBS", -+ "TSIx_JS2_TASKS", -+ "TSIx_JS2_ACTIVE", -+ "", -+ "TSIx_JS2_WAIT_READ", -+ "TSIx_JS2_WAIT_ISSUE", -+ "TSIx_JS2_WAIT_DEPEND", -+ "TSIx_JS2_WAIT_FINISH", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ -+ /* Performance counters for the Tiler */ -+ "", -+ "", -+ "", -+ "", -+ "TSIx_TILER_ACTIVE", -+ "TSIx_JOBS_PROCESSED", -+ "TSIx_TRIANGLES", -+ "TSIx_LINES", -+ "TSIx_POINTS", -+ "TSIx_FRONT_FACING", -+ "TSIx_BACK_FACING", -+ "TSIx_PRIM_VISIBLE", -+ "TSIx_PRIM_CULLED", -+ "TSIx_PRIM_CLIPPED", -+ "TSIx_PRIM_SAT_CULLED", -+ "TSIx_BIN_ALLOC_INIT", -+ "TSIx_BIN_ALLOC_OVERFLOW", -+ "TSIx_BUS_READ", -+ "", -+ "TSIx_BUS_WRITE", -+ "TSIx_LOADING_DESC", -+ "TSIx_IDVS_POS_SHAD_REQ", -+ "TSIx_IDVS_POS_SHAD_WAIT", -+ "TSIx_IDVS_POS_SHAD_STALL", -+ "TSIx_IDVS_POS_FIFO_FULL", -+ "TSIx_PREFETCH_STALL", -+ "TSIx_VCACHE_HIT", -+ "TSIx_VCACHE_MISS", -+ "TSIx_VCACHE_LINE_WAIT", -+ "TSIx_VFETCH_POS_READ_WAIT", -+ "TSIx_VFETCH_VERTEX_WAIT", -+ "TSIx_VFETCH_STALL", -+ "TSIx_PRIMASSY_STALL", -+ "TSIx_BBOX_GEN_STALL", -+ "TSIx_IDVS_VBU_HIT", -+ "TSIx_IDVS_VBU_MISS", -+ "TSIx_IDVS_VBU_LINE_DEALLOCATE", -+ "TSIx_IDVS_VAR_SHAD_REQ", -+ "TSIx_IDVS_VAR_SHAD_STALL", -+ "TSIx_BINNER_STALL", -+ "TSIx_ITER_STALL", -+ "TSIx_COMPRESS_MISS", -+ "TSIx_COMPRESS_STALL", -+ "TSIx_PCACHE_HIT", -+ "TSIx_PCACHE_MISS", -+ "TSIx_PCACHE_MISS_STALL", -+ "TSIx_PCACHE_EVICT_STALL", -+ "TSIx_PMGR_PTR_WR_STALL", -+ "TSIx_PMGR_PTR_RD_STALL", -+ "TSIx_PMGR_CMD_WR_STALL", -+ "TSIx_WRBUF_ACTIVE", -+ "TSIx_WRBUF_HIT", -+ "TSIx_WRBUF_MISS", -+ "TSIx_WRBUF_NO_FREE_LINE_STALL", -+ "TSIx_WRBUF_NO_AXI_ID_STALL", -+ "TSIx_WRBUF_AXI_STALL", -+ "", -+ "", -+ "", -+ "TSIx_UTLB_TRANS", -+ "TSIx_UTLB_TRANS_HIT", -+ "TSIx_UTLB_TRANS_STALL", -+ "TSIx_UTLB_TRANS_MISS_DELAY", -+ "TSIx_UTLB_MMU_REQ", -+ -+ /* Performance counters for the Shader Core */ -+ "", -+ "", -+ "", -+ "", -+ "TSIx_FRAG_ACTIVE", -+ "TSIx_FRAG_PRIMITIVES", -+ "TSIx_FRAG_PRIM_RAST", -+ "TSIx_FRAG_FPK_ACTIVE", -+ "TSIx_FRAG_STARVING", -+ "TSIx_FRAG_WARPS", -+ "TSIx_FRAG_PARTIAL_WARPS", -+ "TSIx_FRAG_QUADS_RAST", -+ "TSIx_FRAG_QUADS_EZS_TEST", -+ "TSIx_FRAG_QUADS_EZS_UPDATE", -+ "TSIx_FRAG_QUADS_EZS_KILL", -+ "TSIx_FRAG_LZS_TEST", -+ "TSIx_FRAG_LZS_KILL", -+ "", -+ "TSIx_FRAG_PTILES", -+ "TSIx_FRAG_TRANS_ELIM", -+ "TSIx_QUAD_FPK_KILLER", -+ "", -+ "TSIx_COMPUTE_ACTIVE", -+ "TSIx_COMPUTE_TASKS", -+ "TSIx_COMPUTE_WARPS", -+ "TSIx_COMPUTE_STARVING", -+ "TSIx_EXEC_CORE_ACTIVE", -+ "TSIx_EXEC_ACTIVE", -+ "TSIx_EXEC_INSTR_COUNT", -+ "TSIx_EXEC_INSTR_DIVERGED", -+ "TSIx_EXEC_INSTR_STARVING", -+ "TSIx_ARITH_INSTR_SINGLE_FMA", -+ "TSIx_ARITH_INSTR_DOUBLE", -+ "TSIx_ARITH_INSTR_MSG", -+ "TSIx_ARITH_INSTR_MSG_ONLY", -+ "TSIx_TEX_MSGI_NUM_QUADS", -+ "TSIx_TEX_DFCH_NUM_PASSES", -+ "TSIx_TEX_DFCH_NUM_PASSES_MISS", -+ "TSIx_TEX_DFCH_NUM_PASSES_MIP_MAP", -+ "TSIx_TEX_TIDX_NUM_SPLIT_MIP_MAP", -+ "TSIx_TEX_TFCH_NUM_LINES_FETCHED", -+ "TSIx_TEX_TFCH_NUM_LINES_FETCHED_BLOCK", -+ "TSIx_TEX_TFCH_NUM_OPERATIONS", -+ "TSIx_TEX_FILT_NUM_OPERATIONS", -+ "TSIx_LS_MEM_READ_FULL", -+ "TSIx_LS_MEM_READ_SHORT", -+ "TSIx_LS_MEM_WRITE_FULL", -+ "TSIx_LS_MEM_WRITE_SHORT", -+ "TSIx_LS_MEM_ATOMIC", -+ "TSIx_VARY_INSTR", -+ "TSIx_VARY_SLOT_32", -+ "TSIx_VARY_SLOT_16", -+ "TSIx_ATTR_INSTR", -+ "TSIx_ARITH_INSTR_FP_MUL", -+ "TSIx_BEATS_RD_FTC", -+ "TSIx_BEATS_RD_FTC_EXT", -+ "TSIx_BEATS_RD_LSC", -+ "TSIx_BEATS_RD_LSC_EXT", -+ "TSIx_BEATS_RD_TEX", -+ "TSIx_BEATS_RD_TEX_EXT", -+ "TSIx_BEATS_RD_OTHER", -+ "TSIx_BEATS_WR_LSC", -+ "TSIx_BEATS_WR_TIB", -+ "", -+ -+ /* Performance counters for the Memory System */ -+ "", -+ "", -+ "", -+ "", -+ "TSIx_MMU_REQUESTS", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "TSIx_L2_RD_MSG_IN", -+ "TSIx_L2_RD_MSG_IN_STALL", -+ "TSIx_L2_WR_MSG_IN", -+ "TSIx_L2_WR_MSG_IN_STALL", -+ "TSIx_L2_SNP_MSG_IN", -+ "TSIx_L2_SNP_MSG_IN_STALL", -+ "TSIx_L2_RD_MSG_OUT", -+ "TSIx_L2_RD_MSG_OUT_STALL", -+ "TSIx_L2_WR_MSG_OUT", -+ "TSIx_L2_ANY_LOOKUP", -+ "TSIx_L2_READ_LOOKUP", -+ "TSIx_L2_WRITE_LOOKUP", -+ "TSIx_L2_EXT_SNOOP_LOOKUP", -+ "TSIx_L2_EXT_READ", -+ "TSIx_L2_EXT_READ_NOSNP", -+ "TSIx_L2_EXT_READ_UNIQUE", -+ "TSIx_L2_EXT_READ_BEATS", -+ "TSIx_L2_EXT_AR_STALL", -+ "TSIx_L2_EXT_AR_CNT_Q1", -+ "TSIx_L2_EXT_AR_CNT_Q2", -+ "TSIx_L2_EXT_AR_CNT_Q3", -+ "TSIx_L2_EXT_RRESP_0_127", -+ "TSIx_L2_EXT_RRESP_128_191", -+ "TSIx_L2_EXT_RRESP_192_255", -+ "TSIx_L2_EXT_RRESP_256_319", -+ "TSIx_L2_EXT_RRESP_320_383", -+ "TSIx_L2_EXT_WRITE", -+ "TSIx_L2_EXT_WRITE_NOSNP_FULL", -+ "TSIx_L2_EXT_WRITE_NOSNP_PTL", -+ "TSIx_L2_EXT_WRITE_SNP_FULL", -+ "TSIx_L2_EXT_WRITE_SNP_PTL", -+ "TSIx_L2_EXT_WRITE_BEATS", -+ "TSIx_L2_EXT_W_STALL", -+ "TSIx_L2_EXT_AW_CNT_Q1", -+ "TSIx_L2_EXT_AW_CNT_Q2", -+ "TSIx_L2_EXT_AW_CNT_Q3", -+ "TSIx_L2_EXT_SNOOP", -+ "TSIx_L2_EXT_SNOOP_STALL", -+ "TSIx_L2_EXT_SNOOP_RESP_CLEAN", -+ "TSIx_L2_EXT_SNOOP_RESP_DATA", -+ "TSIx_L2_EXT_SNOOP_INTERNAL", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+}; -+ -+#endif /* _KBASE_GATOR_HWCNT_NAMES_TSIX_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gpu_id.h b/drivers/gpu/arm/midgard/mali_kbase_gpu_id.h -new file mode 100644 -index 0000000..9763f96 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gpu_id.h -@@ -0,0 +1,129 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+#ifndef _KBASE_GPU_ID_H_ -+#define _KBASE_GPU_ID_H_ -+ -+/* GPU_ID register */ -+#define GPU_ID_VERSION_STATUS_SHIFT 0 -+#define GPU_ID_VERSION_MINOR_SHIFT 4 -+#define GPU_ID_VERSION_MAJOR_SHIFT 12 -+#define GPU_ID_VERSION_PRODUCT_ID_SHIFT 16 -+#define GPU_ID_VERSION_STATUS (0xF << GPU_ID_VERSION_STATUS_SHIFT) -+#define GPU_ID_VERSION_MINOR (0xFF << GPU_ID_VERSION_MINOR_SHIFT) -+#define GPU_ID_VERSION_MAJOR (0xF << GPU_ID_VERSION_MAJOR_SHIFT) -+#define GPU_ID_VERSION_PRODUCT_ID (0xFFFF << GPU_ID_VERSION_PRODUCT_ID_SHIFT) -+ -+/* Values for GPU_ID_VERSION_PRODUCT_ID bitfield */ -+#define GPU_ID_PI_T60X 0x6956 -+#define GPU_ID_PI_T62X 0x0620 -+#define GPU_ID_PI_T76X 0x0750 -+#define GPU_ID_PI_T72X 0x0720 -+#define GPU_ID_PI_TFRX 0x0880 -+#define GPU_ID_PI_T86X 0x0860 -+#define GPU_ID_PI_T82X 0x0820 -+#define GPU_ID_PI_T83X 0x0830 -+ -+/* New GPU ID format when PRODUCT_ID is >= 0x1000 (and not 0x6956) */ -+#define GPU_ID_PI_NEW_FORMAT_START 0x1000 -+#define GPU_ID_IS_NEW_FORMAT(product_id) ((product_id) != GPU_ID_PI_T60X && \ -+ (product_id) >= \ -+ GPU_ID_PI_NEW_FORMAT_START) -+ -+#define GPU_ID2_VERSION_STATUS_SHIFT 0 -+#define GPU_ID2_VERSION_MINOR_SHIFT 4 -+#define GPU_ID2_VERSION_MAJOR_SHIFT 12 -+#define GPU_ID2_PRODUCT_MAJOR_SHIFT 16 -+#define GPU_ID2_ARCH_REV_SHIFT 20 -+#define GPU_ID2_ARCH_MINOR_SHIFT 24 -+#define GPU_ID2_ARCH_MAJOR_SHIFT 28 -+#define GPU_ID2_VERSION_STATUS (0xF << GPU_ID2_VERSION_STATUS_SHIFT) -+#define GPU_ID2_VERSION_MINOR (0xFF << GPU_ID2_VERSION_MINOR_SHIFT) -+#define GPU_ID2_VERSION_MAJOR (0xF << GPU_ID2_VERSION_MAJOR_SHIFT) -+#define GPU_ID2_PRODUCT_MAJOR (0xF << GPU_ID2_PRODUCT_MAJOR_SHIFT) -+#define GPU_ID2_ARCH_REV (0xF << GPU_ID2_ARCH_REV_SHIFT) -+#define GPU_ID2_ARCH_MINOR (0xF << GPU_ID2_ARCH_MINOR_SHIFT) -+#define GPU_ID2_ARCH_MAJOR (0xF << GPU_ID2_ARCH_MAJOR_SHIFT) -+#define GPU_ID2_PRODUCT_MODEL (GPU_ID2_ARCH_MAJOR | GPU_ID2_PRODUCT_MAJOR) -+#define GPU_ID2_VERSION (GPU_ID2_VERSION_MAJOR | \ -+ GPU_ID2_VERSION_MINOR | \ -+ GPU_ID2_VERSION_STATUS) -+ -+/* Helper macro to create a partial GPU_ID (new format) that defines -+ a product ignoring its version. */ -+#define GPU_ID2_PRODUCT_MAKE(arch_major, arch_minor, arch_rev, product_major) \ -+ (((arch_major) << GPU_ID2_ARCH_MAJOR_SHIFT) | \ -+ ((arch_minor) << GPU_ID2_ARCH_MINOR_SHIFT) | \ -+ ((arch_rev) << GPU_ID2_ARCH_REV_SHIFT) | \ -+ ((product_major) << GPU_ID2_PRODUCT_MAJOR_SHIFT)) -+ -+/* Helper macro to create a partial GPU_ID (new format) that specifies the -+ revision (major, minor, status) of a product */ -+#define GPU_ID2_VERSION_MAKE(version_major, version_minor, version_status) \ -+ (((version_major) << GPU_ID2_VERSION_MAJOR_SHIFT) | \ -+ ((version_minor) << GPU_ID2_VERSION_MINOR_SHIFT) | \ -+ ((version_status) << GPU_ID2_VERSION_STATUS_SHIFT)) -+ -+/* Helper macro to create a complete GPU_ID (new format) */ -+#define GPU_ID2_MAKE(arch_major, arch_minor, arch_rev, product_major, \ -+ version_major, version_minor, version_status) \ -+ (GPU_ID2_PRODUCT_MAKE(arch_major, arch_minor, arch_rev, \ -+ product_major) | \ -+ GPU_ID2_VERSION_MAKE(version_major, version_minor, \ -+ version_status)) -+ -+/* Helper macro to create a partial GPU_ID (new format) that identifies -+ a particular GPU model by its arch_major and product_major. */ -+#define GPU_ID2_MODEL_MAKE(arch_major, product_major) \ -+ (((arch_major) << GPU_ID2_ARCH_MAJOR_SHIFT) | \ -+ ((product_major) << GPU_ID2_PRODUCT_MAJOR_SHIFT)) -+ -+/* Strip off the non-relevant bits from a product_id value and make it suitable -+ for comparison against the GPU_ID2_PRODUCT_xxx values which identify a GPU -+ model. */ -+#define GPU_ID2_MODEL_MATCH_VALUE(product_id) \ -+ (((product_id) << GPU_ID2_PRODUCT_MAJOR_SHIFT) & \ -+ GPU_ID2_PRODUCT_MODEL) -+ -+#define GPU_ID2_PRODUCT_TMIX GPU_ID2_MODEL_MAKE(6u, 0) -+#define GPU_ID2_PRODUCT_THEX GPU_ID2_MODEL_MAKE(6u, 1) -+#define GPU_ID2_PRODUCT_TSIX GPU_ID2_MODEL_MAKE(7u, 0) -+#ifdef MALI_INCLUDE_TDVX -+#define GPU_ID2_PRODUCT_TDVX GPU_ID2_MODEL_MAKE(7u, 3) -+#endif /* MALI_INCLUDE_TDVX */ -+#ifdef MALI_INCLUDE_TGOX -+#define GPU_ID2_PRODUCT_TGOX GPU_ID2_MODEL_MAKE(7u, 2) -+#endif /* MALI_INCLUDE_TGOX */ -+#ifdef MALI_INCLUDE_TKAX -+#define GPU_ID2_PRODUCT_TKAX GPU_ID2_MODEL_MAKE(9u, 0) -+#endif /* MALI_INCLUDE_TKAX */ -+#ifdef MALI_INCLUDE_TTRX -+#define GPU_ID2_PRODUCT_TTRX GPU_ID2_MODEL_MAKE(10u, 0) -+#endif /* MALI_INCLUDE_TTRX */ -+ -+/* Values for GPU_ID_VERSION_STATUS field for PRODUCT_ID GPU_ID_PI_T60X */ -+#define GPU_ID_S_15DEV0 0x1 -+#define GPU_ID_S_EAC 0x2 -+ -+/* Helper macro to create a GPU_ID assuming valid values for id, major, -+ minor, status */ -+#define GPU_ID_MAKE(id, major, minor, status) \ -+ (((id) << GPU_ID_VERSION_PRODUCT_ID_SHIFT) | \ -+ ((major) << GPU_ID_VERSION_MAJOR_SHIFT) | \ -+ ((minor) << GPU_ID_VERSION_MINOR_SHIFT) | \ -+ ((status) << GPU_ID_VERSION_STATUS_SHIFT)) -+ -+#endif /* _KBASE_GPU_ID_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gpu_memory_debugfs.c b/drivers/gpu/arm/midgard/mali_kbase_gpu_memory_debugfs.c -new file mode 100644 -index 0000000..6df0a1c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gpu_memory_debugfs.c -@@ -0,0 +1,97 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+ -+#ifdef CONFIG_DEBUG_FS -+/** Show callback for the @c gpu_memory debugfs file. -+ * -+ * This function is called to get the contents of the @c gpu_memory debugfs -+ * file. This is a report of current gpu memory usage. -+ * -+ * @param sfile The debugfs entry -+ * @param data Data associated with the entry -+ * -+ * @return 0 if successfully prints data in debugfs entry file -+ * -1 if it encountered an error -+ */ -+ -+static int kbasep_gpu_memory_seq_show(struct seq_file *sfile, void *data) -+{ -+ struct list_head *entry; -+ const struct list_head *kbdev_list; -+ -+ kbdev_list = kbase_dev_list_get(); -+ list_for_each(entry, kbdev_list) { -+ struct kbase_device *kbdev = NULL; -+ struct kbasep_kctx_list_element *element; -+ -+ kbdev = list_entry(entry, struct kbase_device, entry); -+ /* output the total memory usage and cap for this device */ -+ seq_printf(sfile, "%-16s %10u\n", -+ kbdev->devname, -+ atomic_read(&(kbdev->memdev.used_pages))); -+ mutex_lock(&kbdev->kctx_list_lock); -+ list_for_each_entry(element, &kbdev->kctx_list, link) { -+ /* output the memory usage and cap for each kctx -+ * opened on this device */ -+ seq_printf(sfile, " %s-0x%p %10u\n", -+ "kctx", -+ element->kctx, -+ atomic_read(&(element->kctx->used_pages))); -+ } -+ mutex_unlock(&kbdev->kctx_list_lock); -+ } -+ kbase_dev_list_put(kbdev_list); -+ return 0; -+} -+ -+/* -+ * File operations related to debugfs entry for gpu_memory -+ */ -+static int kbasep_gpu_memory_debugfs_open(struct inode *in, struct file *file) -+{ -+ return single_open(file, kbasep_gpu_memory_seq_show , NULL); -+} -+ -+static const struct file_operations kbasep_gpu_memory_debugfs_fops = { -+ .open = kbasep_gpu_memory_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+/* -+ * Initialize debugfs entry for gpu_memory -+ */ -+void kbasep_gpu_memory_debugfs_init(struct kbase_device *kbdev) -+{ -+ debugfs_create_file("gpu_memory", S_IRUGO, -+ kbdev->mali_debugfs_directory, NULL, -+ &kbasep_gpu_memory_debugfs_fops); -+ return; -+} -+ -+#else -+/* -+ * Stub functions for when debugfs is disabled -+ */ -+void kbasep_gpu_memory_debugfs_init(struct kbase_device *kbdev) -+{ -+ return; -+} -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gpu_memory_debugfs.h b/drivers/gpu/arm/midgard/mali_kbase_gpu_memory_debugfs.h -new file mode 100644 -index 0000000..7045693 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gpu_memory_debugfs.h -@@ -0,0 +1,37 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2014, 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_gpu_memory_debugfs.h -+ * Header file for gpu_memory entry in debugfs -+ * -+ */ -+ -+#ifndef _KBASE_GPU_MEMORY_DEBUGFS_H -+#define _KBASE_GPU_MEMORY_DEBUGFS_H -+ -+#include -+#include -+ -+/** -+ * @brief Initialize gpu_memory debugfs entry -+ */ -+void kbasep_gpu_memory_debugfs_init(struct kbase_device *kbdev); -+ -+#endif /*_KBASE_GPU_MEMORY_DEBUGFS_H*/ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gpuprops.c b/drivers/gpu/arm/midgard/mali_kbase_gpuprops.c -new file mode 100644 -index 0000000..baf3c49 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gpuprops.c -@@ -0,0 +1,514 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Base kernel property query APIs -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "mali_kbase_ioctl.h" -+#include -+ -+/** -+ * KBASE_UBFX32 - Extracts bits from a 32-bit bitfield. -+ * @value: The value from which to extract bits. -+ * @offset: The first bit to extract (0 being the LSB). -+ * @size: The number of bits to extract. -+ * -+ * Context: @offset + @size <= 32. -+ * -+ * Return: Bits [@offset, @offset + @size) from @value. -+ */ -+/* from mali_cdsb.h */ -+#define KBASE_UBFX32(value, offset, size) \ -+ (((u32)(value) >> (u32)(offset)) & (u32)((1ULL << (u32)(size)) - 1)) -+ -+int kbase_gpuprops_uk_get_props(struct kbase_context *kctx, struct kbase_uk_gpuprops * const kbase_props) -+{ -+ kbase_gpu_clk_speed_func get_gpu_speed_mhz; -+ u32 gpu_speed_mhz; -+ int rc = 1; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(NULL != kbase_props); -+ -+ /* Current GPU speed is requested from the system integrator via the GPU_SPEED_FUNC function. -+ * If that function fails, or the function is not provided by the system integrator, we report the maximum -+ * GPU speed as specified by GPU_FREQ_KHZ_MAX. -+ */ -+ get_gpu_speed_mhz = (kbase_gpu_clk_speed_func) GPU_SPEED_FUNC; -+ if (get_gpu_speed_mhz != NULL) { -+ rc = get_gpu_speed_mhz(&gpu_speed_mhz); -+#ifdef CONFIG_MALI_DEBUG -+ /* Issue a warning message when the reported GPU speed falls outside the min/max range */ -+ if (rc == 0) { -+ u32 gpu_speed_khz = gpu_speed_mhz * 1000; -+ -+ if (gpu_speed_khz < kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_min || -+ gpu_speed_khz > kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max) -+ dev_warn(kctx->kbdev->dev, "GPU Speed is outside of min/max range (got %lu Khz, min %lu Khz, max %lu Khz)\n", -+ (unsigned long)gpu_speed_khz, -+ (unsigned long)kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_min, -+ (unsigned long)kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max); -+ } -+#endif /* CONFIG_MALI_DEBUG */ -+ } -+ if (kctx->kbdev->clock) { -+ gpu_speed_mhz = clk_get_rate(kctx->kbdev->clock) / 1000000; -+ rc = 0; -+ } -+ if (rc != 0) -+ gpu_speed_mhz = kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max / 1000; -+ -+ kctx->kbdev->gpu_props.props.core_props.gpu_speed_mhz = gpu_speed_mhz; -+ -+ memcpy(&kbase_props->props, &kctx->kbdev->gpu_props.props, sizeof(kbase_props->props)); -+ -+ /* Before API 8.2 they expect L3 cache info here, which was always 0 */ -+ if (kctx->api_version < KBASE_API_VERSION(8, 2)) -+ kbase_props->props.raw_props.suspend_size = 0; -+ -+ return 0; -+} -+ -+static void kbase_gpuprops_construct_coherent_groups(base_gpu_props * const props) -+{ -+ struct mali_base_gpu_coherent_group *current_group; -+ u64 group_present; -+ u64 group_mask; -+ u64 first_set, first_set_prev; -+ u32 num_groups = 0; -+ -+ KBASE_DEBUG_ASSERT(NULL != props); -+ -+ props->coherency_info.coherency = props->raw_props.mem_features; -+ props->coherency_info.num_core_groups = hweight64(props->raw_props.l2_present); -+ -+ if (props->coherency_info.coherency & GROUPS_L2_COHERENT) { -+ /* Group is l2 coherent */ -+ group_present = props->raw_props.l2_present; -+ } else { -+ /* Group is l1 coherent */ -+ group_present = props->raw_props.shader_present; -+ } -+ -+ /* -+ * The coherent group mask can be computed from the l2 present -+ * register. -+ * -+ * For the coherent group n: -+ * group_mask[n] = (first_set[n] - 1) & ~(first_set[n-1] - 1) -+ * where first_set is group_present with only its nth set-bit kept -+ * (i.e. the position from where a new group starts). -+ * -+ * For instance if the groups are l2 coherent and l2_present=0x0..01111: -+ * The first mask is: -+ * group_mask[1] = (first_set[1] - 1) & ~(first_set[0] - 1) -+ * = (0x0..010 - 1) & ~(0x0..01 - 1) -+ * = 0x0..00f -+ * The second mask is: -+ * group_mask[2] = (first_set[2] - 1) & ~(first_set[1] - 1) -+ * = (0x0..100 - 1) & ~(0x0..010 - 1) -+ * = 0x0..0f0 -+ * And so on until all the bits from group_present have been cleared -+ * (i.e. there is no group left). -+ */ -+ -+ current_group = props->coherency_info.group; -+ first_set = group_present & ~(group_present - 1); -+ -+ while (group_present != 0 && num_groups < BASE_MAX_COHERENT_GROUPS) { -+ group_present -= first_set; /* Clear the current group bit */ -+ first_set_prev = first_set; -+ -+ first_set = group_present & ~(group_present - 1); -+ group_mask = (first_set - 1) & ~(first_set_prev - 1); -+ -+ /* Populate the coherent_group structure for each group */ -+ current_group->core_mask = group_mask & props->raw_props.shader_present; -+ current_group->num_cores = hweight64(current_group->core_mask); -+ -+ num_groups++; -+ current_group++; -+ } -+ -+ if (group_present != 0) -+ pr_warn("Too many coherent groups (keeping only %d groups).\n", BASE_MAX_COHERENT_GROUPS); -+ -+ props->coherency_info.num_groups = num_groups; -+} -+ -+/** -+ * kbase_gpuprops_get_props - Get the GPU configuration -+ * @gpu_props: The &base_gpu_props structure -+ * @kbdev: The &struct kbase_device structure for the device -+ * -+ * Fill the &base_gpu_props structure with values from the GPU configuration -+ * registers. Only the raw properties are filled in this function -+ */ -+static void kbase_gpuprops_get_props(base_gpu_props * const gpu_props, struct kbase_device *kbdev) -+{ -+ struct kbase_gpuprops_regdump regdump; -+ int i; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ KBASE_DEBUG_ASSERT(NULL != gpu_props); -+ -+ /* Dump relevant registers */ -+ kbase_backend_gpuprops_get(kbdev, ®dump); -+ -+ gpu_props->raw_props.gpu_id = regdump.gpu_id; -+ gpu_props->raw_props.tiler_features = regdump.tiler_features; -+ gpu_props->raw_props.mem_features = regdump.mem_features; -+ gpu_props->raw_props.mmu_features = regdump.mmu_features; -+ gpu_props->raw_props.l2_features = regdump.l2_features; -+ gpu_props->raw_props.suspend_size = regdump.suspend_size; -+ -+ gpu_props->raw_props.as_present = regdump.as_present; -+ gpu_props->raw_props.js_present = regdump.js_present; -+ gpu_props->raw_props.shader_present = -+ ((u64) regdump.shader_present_hi << 32) + -+ regdump.shader_present_lo; -+ gpu_props->raw_props.tiler_present = -+ ((u64) regdump.tiler_present_hi << 32) + -+ regdump.tiler_present_lo; -+ gpu_props->raw_props.l2_present = -+ ((u64) regdump.l2_present_hi << 32) + -+ regdump.l2_present_lo; -+#ifdef CONFIG_MALI_CORESTACK -+ gpu_props->raw_props.stack_present = -+ ((u64) regdump.stack_present_hi << 32) + -+ regdump.stack_present_lo; -+#else /* CONFIG_MALI_CORESTACK */ -+ gpu_props->raw_props.stack_present = 0; -+#endif /* CONFIG_MALI_CORESTACK */ -+ -+ for (i = 0; i < GPU_MAX_JOB_SLOTS; i++) -+ gpu_props->raw_props.js_features[i] = regdump.js_features[i]; -+ -+ for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++) -+ gpu_props->raw_props.texture_features[i] = regdump.texture_features[i]; -+ -+ gpu_props->raw_props.thread_max_barrier_size = regdump.thread_max_barrier_size; -+ gpu_props->raw_props.thread_max_threads = regdump.thread_max_threads; -+ gpu_props->raw_props.thread_max_workgroup_size = regdump.thread_max_workgroup_size; -+ gpu_props->raw_props.thread_features = regdump.thread_features; -+} -+ -+void kbase_gpuprops_update_core_props_gpu_id(base_gpu_props * const gpu_props) -+{ -+ gpu_props->core_props.version_status = -+ KBASE_UBFX32(gpu_props->raw_props.gpu_id, 0U, 4); -+ gpu_props->core_props.minor_revision = -+ KBASE_UBFX32(gpu_props->raw_props.gpu_id, 4U, 8); -+ gpu_props->core_props.major_revision = -+ KBASE_UBFX32(gpu_props->raw_props.gpu_id, 12U, 4); -+ gpu_props->core_props.product_id = -+ KBASE_UBFX32(gpu_props->raw_props.gpu_id, 16U, 16); -+} -+ -+/** -+ * kbase_gpuprops_calculate_props - Calculate the derived properties -+ * @gpu_props: The &base_gpu_props structure -+ * @kbdev: The &struct kbase_device structure for the device -+ * -+ * Fill the &base_gpu_props structure with values derived from the GPU -+ * configuration registers -+ */ -+static void kbase_gpuprops_calculate_props(base_gpu_props * const gpu_props, struct kbase_device *kbdev) -+{ -+ int i; -+ -+ /* Populate the base_gpu_props structure */ -+ kbase_gpuprops_update_core_props_gpu_id(gpu_props); -+ gpu_props->core_props.log2_program_counter_size = KBASE_GPU_PC_SIZE_LOG2; -+ gpu_props->core_props.gpu_available_memory_size = totalram_pages << PAGE_SHIFT; -+ -+ for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++) -+ gpu_props->core_props.texture_features[i] = gpu_props->raw_props.texture_features[i]; -+ -+ gpu_props->l2_props.log2_line_size = KBASE_UBFX32(gpu_props->raw_props.l2_features, 0U, 8); -+ gpu_props->l2_props.log2_cache_size = KBASE_UBFX32(gpu_props->raw_props.l2_features, 16U, 8); -+ -+ /* Field with number of l2 slices is added to MEM_FEATURES register -+ * since t76x. Below code assumes that for older GPU reserved bits will -+ * be read as zero. */ -+ gpu_props->l2_props.num_l2_slices = -+ KBASE_UBFX32(gpu_props->raw_props.mem_features, 8U, 4) + 1; -+ -+ gpu_props->tiler_props.bin_size_bytes = 1 << KBASE_UBFX32(gpu_props->raw_props.tiler_features, 0U, 6); -+ gpu_props->tiler_props.max_active_levels = KBASE_UBFX32(gpu_props->raw_props.tiler_features, 8U, 4); -+ -+ if (gpu_props->raw_props.thread_max_threads == 0) -+ gpu_props->thread_props.max_threads = THREAD_MT_DEFAULT; -+ else -+ gpu_props->thread_props.max_threads = gpu_props->raw_props.thread_max_threads; -+ -+ if (gpu_props->raw_props.thread_max_workgroup_size == 0) -+ gpu_props->thread_props.max_workgroup_size = THREAD_MWS_DEFAULT; -+ else -+ gpu_props->thread_props.max_workgroup_size = gpu_props->raw_props.thread_max_workgroup_size; -+ -+ if (gpu_props->raw_props.thread_max_barrier_size == 0) -+ gpu_props->thread_props.max_barrier_size = THREAD_MBS_DEFAULT; -+ else -+ gpu_props->thread_props.max_barrier_size = gpu_props->raw_props.thread_max_barrier_size; -+ -+ gpu_props->thread_props.max_registers = KBASE_UBFX32(gpu_props->raw_props.thread_features, 0U, 16); -+ gpu_props->thread_props.max_task_queue = KBASE_UBFX32(gpu_props->raw_props.thread_features, 16U, 8); -+ gpu_props->thread_props.max_thread_group_split = KBASE_UBFX32(gpu_props->raw_props.thread_features, 24U, 6); -+ gpu_props->thread_props.impl_tech = KBASE_UBFX32(gpu_props->raw_props.thread_features, 30U, 2); -+ -+ /* If values are not specified, then use defaults */ -+ if (gpu_props->thread_props.max_registers == 0) { -+ gpu_props->thread_props.max_registers = THREAD_MR_DEFAULT; -+ gpu_props->thread_props.max_task_queue = THREAD_MTQ_DEFAULT; -+ gpu_props->thread_props.max_thread_group_split = THREAD_MTGS_DEFAULT; -+ } -+ /* Initialize the coherent_group structure for each group */ -+ kbase_gpuprops_construct_coherent_groups(gpu_props); -+} -+ -+void kbase_gpuprops_set(struct kbase_device *kbdev) -+{ -+ struct kbase_gpu_props *gpu_props; -+ struct gpu_raw_gpu_props *raw; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ gpu_props = &kbdev->gpu_props; -+ raw = &gpu_props->props.raw_props; -+ -+ /* Initialize the base_gpu_props structure from the hardware */ -+ kbase_gpuprops_get_props(&gpu_props->props, kbdev); -+ -+ /* Populate the derived properties */ -+ kbase_gpuprops_calculate_props(&gpu_props->props, kbdev); -+ -+ /* Populate kbase-only fields */ -+ gpu_props->l2_props.associativity = KBASE_UBFX32(raw->l2_features, 8U, 8); -+ gpu_props->l2_props.external_bus_width = KBASE_UBFX32(raw->l2_features, 24U, 8); -+ -+ gpu_props->mem.core_group = KBASE_UBFX32(raw->mem_features, 0U, 1); -+ -+ gpu_props->mmu.va_bits = KBASE_UBFX32(raw->mmu_features, 0U, 8); -+ gpu_props->mmu.pa_bits = KBASE_UBFX32(raw->mmu_features, 8U, 8); -+ -+ gpu_props->num_cores = hweight64(raw->shader_present); -+ gpu_props->num_core_groups = hweight64(raw->l2_present); -+ gpu_props->num_address_spaces = hweight32(raw->as_present); -+ gpu_props->num_job_slots = hweight32(raw->js_present); -+} -+ -+void kbase_gpuprops_set_features(struct kbase_device *kbdev) -+{ -+ base_gpu_props *gpu_props; -+ struct kbase_gpuprops_regdump regdump; -+ -+ gpu_props = &kbdev->gpu_props.props; -+ -+ /* Dump relevant registers */ -+ kbase_backend_gpuprops_get_features(kbdev, ®dump); -+ -+ /* -+ * Copy the raw value from the register, later this will get turned -+ * into the selected coherency mode. -+ * Additionally, add non-coherent mode, as this is always supported. -+ */ -+ gpu_props->raw_props.coherency_mode = regdump.coherency_features | -+ COHERENCY_FEATURE_BIT(COHERENCY_NONE); -+} -+ -+static struct { -+ u32 type; -+ size_t offset; -+ int size; -+} gpu_property_mapping[] = { -+#define PROP(name, member) \ -+ {KBASE_GPUPROP_ ## name, offsetof(struct mali_base_gpu_props, member), \ -+ sizeof(((struct mali_base_gpu_props *)0)->member)} -+ PROP(PRODUCT_ID, core_props.product_id), -+ PROP(VERSION_STATUS, core_props.version_status), -+ PROP(MINOR_REVISION, core_props.minor_revision), -+ PROP(MAJOR_REVISION, core_props.major_revision), -+ PROP(GPU_SPEED_MHZ, core_props.gpu_speed_mhz), -+ PROP(GPU_FREQ_KHZ_MAX, core_props.gpu_freq_khz_max), -+ PROP(GPU_FREQ_KHZ_MIN, core_props.gpu_freq_khz_min), -+ PROP(LOG2_PROGRAM_COUNTER_SIZE, core_props.log2_program_counter_size), -+ PROP(TEXTURE_FEATURES_0, core_props.texture_features[0]), -+ PROP(TEXTURE_FEATURES_1, core_props.texture_features[1]), -+ PROP(TEXTURE_FEATURES_2, core_props.texture_features[2]), -+ PROP(GPU_AVAILABLE_MEMORY_SIZE, core_props.gpu_available_memory_size), -+ -+ PROP(L2_LOG2_LINE_SIZE, l2_props.log2_line_size), -+ PROP(L2_LOG2_CACHE_SIZE, l2_props.log2_cache_size), -+ PROP(L2_NUM_L2_SLICES, l2_props.num_l2_slices), -+ -+ PROP(TILER_BIN_SIZE_BYTES, tiler_props.bin_size_bytes), -+ PROP(TILER_MAX_ACTIVE_LEVELS, tiler_props.max_active_levels), -+ -+ PROP(MAX_THREADS, thread_props.max_threads), -+ PROP(MAX_WORKGROUP_SIZE, thread_props.max_workgroup_size), -+ PROP(MAX_BARRIER_SIZE, thread_props.max_barrier_size), -+ PROP(MAX_REGISTERS, thread_props.max_registers), -+ PROP(MAX_TASK_QUEUE, thread_props.max_task_queue), -+ PROP(MAX_THREAD_GROUP_SPLIT, thread_props.max_thread_group_split), -+ PROP(IMPL_TECH, thread_props.impl_tech), -+ -+ PROP(RAW_SHADER_PRESENT, raw_props.shader_present), -+ PROP(RAW_TILER_PRESENT, raw_props.tiler_present), -+ PROP(RAW_L2_PRESENT, raw_props.l2_present), -+ PROP(RAW_STACK_PRESENT, raw_props.stack_present), -+ PROP(RAW_L2_FEATURES, raw_props.l2_features), -+ PROP(RAW_SUSPEND_SIZE, raw_props.suspend_size), -+ PROP(RAW_MEM_FEATURES, raw_props.mem_features), -+ PROP(RAW_MMU_FEATURES, raw_props.mmu_features), -+ PROP(RAW_AS_PRESENT, raw_props.as_present), -+ PROP(RAW_JS_PRESENT, raw_props.js_present), -+ PROP(RAW_JS_FEATURES_0, raw_props.js_features[0]), -+ PROP(RAW_JS_FEATURES_1, raw_props.js_features[1]), -+ PROP(RAW_JS_FEATURES_2, raw_props.js_features[2]), -+ PROP(RAW_JS_FEATURES_3, raw_props.js_features[3]), -+ PROP(RAW_JS_FEATURES_4, raw_props.js_features[4]), -+ PROP(RAW_JS_FEATURES_5, raw_props.js_features[5]), -+ PROP(RAW_JS_FEATURES_6, raw_props.js_features[6]), -+ PROP(RAW_JS_FEATURES_7, raw_props.js_features[7]), -+ PROP(RAW_JS_FEATURES_8, raw_props.js_features[8]), -+ PROP(RAW_JS_FEATURES_9, raw_props.js_features[9]), -+ PROP(RAW_JS_FEATURES_10, raw_props.js_features[10]), -+ PROP(RAW_JS_FEATURES_11, raw_props.js_features[11]), -+ PROP(RAW_JS_FEATURES_12, raw_props.js_features[12]), -+ PROP(RAW_JS_FEATURES_13, raw_props.js_features[13]), -+ PROP(RAW_JS_FEATURES_14, raw_props.js_features[14]), -+ PROP(RAW_JS_FEATURES_15, raw_props.js_features[15]), -+ PROP(RAW_TILER_FEATURES, raw_props.tiler_features), -+ PROP(RAW_TEXTURE_FEATURES_0, raw_props.texture_features[0]), -+ PROP(RAW_TEXTURE_FEATURES_1, raw_props.texture_features[1]), -+ PROP(RAW_TEXTURE_FEATURES_2, raw_props.texture_features[2]), -+ PROP(RAW_GPU_ID, raw_props.gpu_id), -+ PROP(RAW_THREAD_MAX_THREADS, raw_props.thread_max_threads), -+ PROP(RAW_THREAD_MAX_WORKGROUP_SIZE, -+ raw_props.thread_max_workgroup_size), -+ PROP(RAW_THREAD_MAX_BARRIER_SIZE, raw_props.thread_max_barrier_size), -+ PROP(RAW_THREAD_FEATURES, raw_props.thread_features), -+ PROP(RAW_COHERENCY_MODE, raw_props.coherency_mode), -+ -+ PROP(COHERENCY_NUM_GROUPS, coherency_info.num_groups), -+ PROP(COHERENCY_NUM_CORE_GROUPS, coherency_info.num_core_groups), -+ PROP(COHERENCY_COHERENCY, coherency_info.coherency), -+ PROP(COHERENCY_GROUP_0, coherency_info.group[0].core_mask), -+ PROP(COHERENCY_GROUP_1, coherency_info.group[1].core_mask), -+ PROP(COHERENCY_GROUP_2, coherency_info.group[2].core_mask), -+ PROP(COHERENCY_GROUP_3, coherency_info.group[3].core_mask), -+ PROP(COHERENCY_GROUP_4, coherency_info.group[4].core_mask), -+ PROP(COHERENCY_GROUP_5, coherency_info.group[5].core_mask), -+ PROP(COHERENCY_GROUP_6, coherency_info.group[6].core_mask), -+ PROP(COHERENCY_GROUP_7, coherency_info.group[7].core_mask), -+ PROP(COHERENCY_GROUP_8, coherency_info.group[8].core_mask), -+ PROP(COHERENCY_GROUP_9, coherency_info.group[9].core_mask), -+ PROP(COHERENCY_GROUP_10, coherency_info.group[10].core_mask), -+ PROP(COHERENCY_GROUP_11, coherency_info.group[11].core_mask), -+ PROP(COHERENCY_GROUP_12, coherency_info.group[12].core_mask), -+ PROP(COHERENCY_GROUP_13, coherency_info.group[13].core_mask), -+ PROP(COHERENCY_GROUP_14, coherency_info.group[14].core_mask), -+ PROP(COHERENCY_GROUP_15, coherency_info.group[15].core_mask), -+ -+#undef PROP -+}; -+ -+int kbase_gpuprops_populate_user_buffer(struct kbase_device *kbdev) -+{ -+ struct kbase_gpu_props *kprops = &kbdev->gpu_props; -+ struct mali_base_gpu_props *props = &kprops->props; -+ u32 count = ARRAY_SIZE(gpu_property_mapping); -+ u32 i; -+ u32 size = 0; -+ u8 *p; -+ -+ for (i = 0; i < count; i++) { -+ /* 4 bytes for the ID, and the size of the property */ -+ size += 4 + gpu_property_mapping[i].size; -+ } -+ -+ kprops->prop_buffer_size = size; -+ kprops->prop_buffer = kmalloc(size, GFP_KERNEL); -+ -+ if (!kprops->prop_buffer) { -+ kprops->prop_buffer_size = 0; -+ return -ENOMEM; -+ } -+ -+ p = kprops->prop_buffer; -+ -+#define WRITE_U8(v) (*p++ = (v) & 0xFF) -+#define WRITE_U16(v) do { WRITE_U8(v); WRITE_U8((v) >> 8); } while (0) -+#define WRITE_U32(v) do { WRITE_U16(v); WRITE_U16((v) >> 16); } while (0) -+#define WRITE_U64(v) do { WRITE_U32(v); WRITE_U32((v) >> 32); } while (0) -+ -+ for (i = 0; i < count; i++) { -+ u32 type = gpu_property_mapping[i].type; -+ u8 type_size; -+ void *field = ((u8 *)props) + gpu_property_mapping[i].offset; -+ -+ switch (gpu_property_mapping[i].size) { -+ case 1: -+ type_size = KBASE_GPUPROP_VALUE_SIZE_U8; -+ break; -+ case 2: -+ type_size = KBASE_GPUPROP_VALUE_SIZE_U16; -+ break; -+ case 4: -+ type_size = KBASE_GPUPROP_VALUE_SIZE_U32; -+ break; -+ case 8: -+ type_size = KBASE_GPUPROP_VALUE_SIZE_U64; -+ break; -+ default: -+ dev_err(kbdev->dev, -+ "Invalid gpu_property_mapping type=%d size=%d", -+ type, gpu_property_mapping[i].size); -+ return -EINVAL; -+ } -+ -+ WRITE_U32((type<<2) | type_size); -+ -+ switch (type_size) { -+ case KBASE_GPUPROP_VALUE_SIZE_U8: -+ WRITE_U8(*((u8 *)field)); -+ break; -+ case KBASE_GPUPROP_VALUE_SIZE_U16: -+ WRITE_U16(*((u16 *)field)); -+ break; -+ case KBASE_GPUPROP_VALUE_SIZE_U32: -+ WRITE_U32(*((u32 *)field)); -+ break; -+ case KBASE_GPUPROP_VALUE_SIZE_U64: -+ WRITE_U64(*((u64 *)field)); -+ break; -+ default: /* Cannot be reached */ -+ WARN_ON(1); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gpuprops.h b/drivers/gpu/arm/midgard/mali_kbase_gpuprops.h -new file mode 100644 -index 0000000..57b3eaf ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gpuprops.h -@@ -0,0 +1,84 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2015,2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_gpuprops.h -+ * Base kernel property query APIs -+ */ -+ -+#ifndef _KBASE_GPUPROPS_H_ -+#define _KBASE_GPUPROPS_H_ -+ -+#include "mali_kbase_gpuprops_types.h" -+ -+/* Forward definition - see mali_kbase.h */ -+struct kbase_device; -+ -+/** -+ * @brief Set up Kbase GPU properties. -+ * -+ * Set up Kbase GPU properties with information from the GPU registers -+ * -+ * @param kbdev The struct kbase_device structure for the device -+ */ -+void kbase_gpuprops_set(struct kbase_device *kbdev); -+ -+/** -+ * kbase_gpuprops_set_features - Set up Kbase GPU properties -+ * @kbdev: Device pointer -+ * -+ * This function sets up GPU properties that are dependent on the hardware -+ * features bitmask. This function must be preceeded by a call to -+ * kbase_hw_set_features_mask(). -+ */ -+void kbase_gpuprops_set_features(struct kbase_device *kbdev); -+ -+/** -+ * @brief Provide GPU properties to userside through UKU call. -+ * -+ * Fill the struct kbase_uk_gpuprops with values from GPU configuration registers. -+ * -+ * @param kctx The struct kbase_context structure -+ * @param kbase_props A copy of the struct kbase_uk_gpuprops structure from userspace -+ * -+ * @return 0 on success. Any other value indicates failure. -+ */ -+int kbase_gpuprops_uk_get_props(struct kbase_context *kctx, struct kbase_uk_gpuprops * const kbase_props); -+ -+/** -+ * kbase_gpuprops_populate_user_buffer - Populate the GPU properties buffer -+ * @kbdev: The kbase device -+ * -+ * Fills kbdev->gpu_props->prop_buffer with the GPU properties for user -+ * space to read. -+ */ -+int kbase_gpuprops_populate_user_buffer(struct kbase_device *kbdev); -+ -+/** -+ * kbase_gpuprops_update_core_props_gpu_id - break down gpu id value -+ * @gpu_props: the &base_gpu_props structure -+ * -+ * Break down gpu_id value stored in base_gpu_props::raw_props.gpu_id into -+ * separate fields (version_status, minor_revision, major_revision, product_id) -+ * stored in base_gpu_props::core_props. -+ */ -+void kbase_gpuprops_update_core_props_gpu_id(base_gpu_props * const gpu_props); -+ -+ -+#endif /* _KBASE_GPUPROPS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_gpuprops_types.h b/drivers/gpu/arm/midgard/mali_kbase_gpuprops_types.h -new file mode 100644 -index 0000000..10794fc ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_gpuprops_types.h -@@ -0,0 +1,92 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_gpuprops_types.h -+ * Base kernel property query APIs -+ */ -+ -+#ifndef _KBASE_GPUPROPS_TYPES_H_ -+#define _KBASE_GPUPROPS_TYPES_H_ -+ -+#include "mali_base_kernel.h" -+ -+#define KBASE_GPU_SPEED_MHZ 123 -+#define KBASE_GPU_PC_SIZE_LOG2 24U -+ -+struct kbase_gpuprops_regdump { -+ u32 gpu_id; -+ u32 l2_features; -+ u32 suspend_size; /* API 8.2+ */ -+ u32 tiler_features; -+ u32 mem_features; -+ u32 mmu_features; -+ u32 as_present; -+ u32 js_present; -+ u32 thread_max_threads; -+ u32 thread_max_workgroup_size; -+ u32 thread_max_barrier_size; -+ u32 thread_features; -+ u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS]; -+ u32 js_features[GPU_MAX_JOB_SLOTS]; -+ u32 shader_present_lo; -+ u32 shader_present_hi; -+ u32 tiler_present_lo; -+ u32 tiler_present_hi; -+ u32 l2_present_lo; -+ u32 l2_present_hi; -+ u32 stack_present_lo; -+ u32 stack_present_hi; -+ u32 coherency_features; -+}; -+ -+struct kbase_gpu_cache_props { -+ u8 associativity; -+ u8 external_bus_width; -+}; -+ -+struct kbase_gpu_mem_props { -+ u8 core_group; -+}; -+ -+struct kbase_gpu_mmu_props { -+ u8 va_bits; -+ u8 pa_bits; -+}; -+ -+struct kbase_gpu_props { -+ /* kernel-only properties */ -+ u8 num_cores; -+ u8 num_core_groups; -+ u8 num_address_spaces; -+ u8 num_job_slots; -+ -+ struct kbase_gpu_cache_props l2_props; -+ -+ struct kbase_gpu_mem_props mem; -+ struct kbase_gpu_mmu_props mmu; -+ -+ /* Properties shared with userspace */ -+ base_gpu_props props; -+ -+ u32 prop_buffer_size; -+ void *prop_buffer; -+}; -+ -+#endif /* _KBASE_GPUPROPS_TYPES_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hw.c b/drivers/gpu/arm/midgard/mali_kbase_hw.c -new file mode 100644 -index 0000000..bacb32f ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hw.c -@@ -0,0 +1,492 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Run-time work-arounds helpers -+ */ -+ -+#include -+#include -+#include -+#include "mali_kbase.h" -+#include "mali_kbase_hw.h" -+ -+void kbase_hw_set_features_mask(struct kbase_device *kbdev) -+{ -+ const enum base_hw_feature *features; -+ u32 gpu_id; -+ u32 product_id; -+ -+ gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ product_id = gpu_id & GPU_ID_VERSION_PRODUCT_ID; -+ product_id >>= GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ -+ if (GPU_ID_IS_NEW_FORMAT(product_id)) { -+ switch (gpu_id & GPU_ID2_PRODUCT_MODEL) { -+ case GPU_ID2_PRODUCT_TMIX: -+ features = base_hw_features_tMIx; -+ break; -+ case GPU_ID2_PRODUCT_THEX: -+ features = base_hw_features_tHEx; -+ break; -+ case GPU_ID2_PRODUCT_TSIX: -+ features = base_hw_features_tSIx; -+ break; -+#ifdef MALI_INCLUDE_TDVX -+ case GPU_ID2_PRODUCT_TDVX: -+ features = base_hw_features_tDVx; -+ break; -+#endif /* MALI_INCLUDE_TDVX */ -+#ifdef MALI_INCLUDE_TGOX -+ case GPU_ID2_PRODUCT_TGOX: -+ features = base_hw_features_tGOx; -+ break; -+#endif /* MALI_INCLUDE_TGOX */ -+#ifdef MALI_INCLUDE_TKAX -+ case GPU_ID2_PRODUCT_TKAX: -+ features = base_hw_features_tKAx; -+ break; -+#endif /* MALI_INCLUDE_TKAX */ -+#ifdef MALI_INCLUDE_TTRX -+ case GPU_ID2_PRODUCT_TTRX: -+ features = base_hw_features_tTRx; -+ break; -+#endif /* MALI_INCLUDE_TTRX */ -+ default: -+ features = base_hw_features_generic; -+ break; -+ } -+ } else { -+ switch (product_id) { -+ case GPU_ID_PI_TFRX: -+ /* FALLTHROUGH */ -+ case GPU_ID_PI_T86X: -+ features = base_hw_features_tFxx; -+ break; -+ case GPU_ID_PI_T83X: -+ features = base_hw_features_t83x; -+ break; -+ case GPU_ID_PI_T82X: -+ features = base_hw_features_t82x; -+ break; -+ case GPU_ID_PI_T76X: -+ features = base_hw_features_t76x; -+ break; -+ case GPU_ID_PI_T72X: -+ features = base_hw_features_t72x; -+ break; -+ case GPU_ID_PI_T62X: -+ features = base_hw_features_t62x; -+ break; -+ case GPU_ID_PI_T60X: -+ features = base_hw_features_t60x; -+ break; -+ default: -+ features = base_hw_features_generic; -+ break; -+ } -+ } -+ -+ for (; *features != BASE_HW_FEATURE_END; features++) -+ set_bit(*features, &kbdev->hw_features_mask[0]); -+} -+ -+/** -+ * kbase_hw_get_issues_for_new_id - Get the hardware issues for a new GPU ID -+ * @kbdev: Device pointer -+ * -+ * Return: pointer to an array of hardware issues, terminated by -+ * BASE_HW_ISSUE_END. -+ * -+ * This function can only be used on new-format GPU IDs, i.e. those for which -+ * GPU_ID_IS_NEW_FORMAT evaluates as true. The GPU ID is read from the @kbdev. -+ * -+ * In debugging versions of the driver, unknown versions of a known GPU will -+ * be treated as the most recent known version not later than the actual -+ * version. In such circumstances, the GPU ID in @kbdev will also be replaced -+ * with the most recent known version. -+ * -+ * Note: The GPU configuration must have been read by kbase_gpuprops_get_props() -+ * before calling this function. -+ */ -+static const enum base_hw_issue *kbase_hw_get_issues_for_new_id( -+ struct kbase_device *kbdev) -+{ -+ const enum base_hw_issue *issues = NULL; -+ -+ struct base_hw_product { -+ u32 product_model; -+ struct { -+ u32 version; -+ const enum base_hw_issue *issues; -+ } map[7]; -+ }; -+ -+ static const struct base_hw_product base_hw_products[] = { -+ {GPU_ID2_PRODUCT_TMIX, -+ {{GPU_ID2_VERSION_MAKE(0, 0, 1), -+ base_hw_issues_tMIx_r0p0_05dev0}, -+ {GPU_ID2_VERSION_MAKE(0, 0, 2), base_hw_issues_tMIx_r0p0}, -+ {U32_MAX /* sentinel value */, NULL} } }, -+ -+ {GPU_ID2_PRODUCT_THEX, -+ {{GPU_ID2_VERSION_MAKE(0, 0, 0), base_hw_issues_tHEx_r0p0}, -+ {GPU_ID2_VERSION_MAKE(0, 0, 1), base_hw_issues_tHEx_r0p0}, -+ {GPU_ID2_VERSION_MAKE(0, 1, 0), base_hw_issues_tHEx_r0p1}, -+ {U32_MAX, NULL} } }, -+ -+ {GPU_ID2_PRODUCT_TSIX, -+ {{GPU_ID2_VERSION_MAKE(0, 0, 0), base_hw_issues_tSIx_r0p0}, -+ {GPU_ID2_VERSION_MAKE(0, 0, 1), base_hw_issues_tSIx_r0p0}, -+ {GPU_ID2_VERSION_MAKE(0, 1, 0), base_hw_issues_tSIx_r0p1}, -+ {GPU_ID2_VERSION_MAKE(1, 0, 0), base_hw_issues_tSIx_r1p0}, -+ {U32_MAX, NULL} } }, -+ -+#ifdef MALI_INCLUDE_TDVX -+ {GPU_ID2_PRODUCT_TDVX, -+ {{GPU_ID2_VERSION_MAKE(0, 0, 0), base_hw_issues_tDVx_r0p0}, -+ {U32_MAX, NULL} } }, -+#endif /* MALI_INCLUDE_TDVX */ -+ -+ -+#ifdef MALI_INCLUDE_TGOX -+ {GPU_ID2_PRODUCT_TGOX, -+ {{GPU_ID2_VERSION_MAKE(0, 0, 0), base_hw_issues_tGOx_r0p0}, -+ {U32_MAX, NULL} } }, -+#endif /* MALI_INCLUDE_TGOX */ -+ -+#ifdef MALI_INCLUDE_TKAX -+ {GPU_ID2_PRODUCT_TKAX, -+ {{GPU_ID2_VERSION_MAKE(0, 0, 0), base_hw_issues_tKAx_r0p0}, -+ {U32_MAX, NULL} } }, -+#endif /* MALI_INCLUDE_TKAX */ -+ -+#ifdef MALI_INCLUDE_TTRX -+ {GPU_ID2_PRODUCT_TTRX, -+ {{GPU_ID2_VERSION_MAKE(0, 0, 0), base_hw_issues_tTRx_r0p0}, -+ {U32_MAX, NULL} } }, -+#endif /* MALI_INCLUDE_TTRX */ -+ }; -+ -+ u32 gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ const u32 product_model = gpu_id & GPU_ID2_PRODUCT_MODEL; -+ const struct base_hw_product *product = NULL; -+ size_t p; -+ -+ /* Stop when we reach the end of the products array. */ -+ for (p = 0; p < ARRAY_SIZE(base_hw_products); ++p) { -+ if (product_model == base_hw_products[p].product_model) { -+ product = &base_hw_products[p]; -+ break; -+ } -+ } -+ -+ if (product != NULL) { -+ /* Found a matching product. */ -+ const u32 version = gpu_id & GPU_ID2_VERSION; -+#if !MALI_CUSTOMER_RELEASE -+ u32 fallback_version = 0; -+ const enum base_hw_issue *fallback_issues = NULL; -+#endif -+ size_t v; -+ -+ /* Stop when we reach the end of the map. */ -+ for (v = 0; product->map[v].version != U32_MAX; ++v) { -+ -+ if (version == product->map[v].version) { -+ /* Exact match so stop. */ -+ issues = product->map[v].issues; -+ break; -+ } -+ -+#if !MALI_CUSTOMER_RELEASE -+ /* Check whether this is a candidate for most recent -+ known version not later than the actual -+ version. */ -+ if ((version > product->map[v].version) && -+ (product->map[v].version >= fallback_version)) { -+ fallback_version = product->map[v].version; -+ fallback_issues = product->map[v].issues; -+ } -+#endif -+ } -+ -+#if !MALI_CUSTOMER_RELEASE -+ if ((issues == NULL) && (fallback_issues != NULL)) { -+ /* Fall back to the issue set of the most recent known -+ version not later than the actual version. */ -+ issues = fallback_issues; -+ -+ dev_info(kbdev->dev, -+ "r%dp%d status %d is unknown; treating as r%dp%d status %d", -+ (gpu_id & GPU_ID2_VERSION_MAJOR) >> -+ GPU_ID2_VERSION_MAJOR_SHIFT, -+ (gpu_id & GPU_ID2_VERSION_MINOR) >> -+ GPU_ID2_VERSION_MINOR_SHIFT, -+ (gpu_id & GPU_ID2_VERSION_STATUS) >> -+ GPU_ID2_VERSION_STATUS_SHIFT, -+ (fallback_version & GPU_ID2_VERSION_MAJOR) >> -+ GPU_ID2_VERSION_MAJOR_SHIFT, -+ (fallback_version & GPU_ID2_VERSION_MINOR) >> -+ GPU_ID2_VERSION_MINOR_SHIFT, -+ (fallback_version & GPU_ID2_VERSION_STATUS) >> -+ GPU_ID2_VERSION_STATUS_SHIFT); -+ -+ gpu_id &= ~GPU_ID2_VERSION; -+ gpu_id |= fallback_version; -+ kbdev->gpu_props.props.raw_props.gpu_id = gpu_id; -+ -+ kbase_gpuprops_update_core_props_gpu_id( -+ &kbdev->gpu_props.props); -+ } -+#endif -+ } -+ return issues; -+} -+ -+int kbase_hw_set_issues_mask(struct kbase_device *kbdev) -+{ -+ const enum base_hw_issue *issues; -+ u32 gpu_id; -+ u32 product_id; -+ u32 impl_tech; -+ -+ gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+ product_id = gpu_id & GPU_ID_VERSION_PRODUCT_ID; -+ product_id >>= GPU_ID_VERSION_PRODUCT_ID_SHIFT; -+ impl_tech = kbdev->gpu_props.props.thread_props.impl_tech; -+ -+ if (impl_tech != IMPLEMENTATION_MODEL) { -+ if (GPU_ID_IS_NEW_FORMAT(product_id)) { -+ issues = kbase_hw_get_issues_for_new_id(kbdev); -+ if (issues == NULL) { -+ dev_err(kbdev->dev, -+ "Unknown GPU ID %x", gpu_id); -+ return -EINVAL; -+ } -+ -+#if !MALI_CUSTOMER_RELEASE -+ /* The GPU ID might have been replaced with the last -+ known version of the same GPU. */ -+ gpu_id = kbdev->gpu_props.props.raw_props.gpu_id; -+#endif -+ -+ } else { -+ switch (gpu_id) { -+ case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 0, GPU_ID_S_15DEV0): -+ issues = base_hw_issues_t60x_r0p0_15dev0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 0, GPU_ID_S_EAC): -+ issues = base_hw_issues_t60x_r0p0_eac; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 1, 0): -+ issues = base_hw_issues_t60x_r0p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T62X, 0, 1, 0): -+ issues = base_hw_issues_t62x_r0p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T62X, 1, 0, 0): -+ case GPU_ID_MAKE(GPU_ID_PI_T62X, 1, 0, 1): -+ issues = base_hw_issues_t62x_r1p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T62X, 1, 1, 0): -+ issues = base_hw_issues_t62x_r1p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 0, 1): -+ issues = base_hw_issues_t76x_r0p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 1, 1): -+ issues = base_hw_issues_t76x_r0p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 1, 9): -+ issues = base_hw_issues_t76x_r0p1_50rel0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 2, 1): -+ issues = base_hw_issues_t76x_r0p2; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 3, 1): -+ issues = base_hw_issues_t76x_r0p3; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T76X, 1, 0, 0): -+ issues = base_hw_issues_t76x_r1p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T72X, 0, 0, 0): -+ case GPU_ID_MAKE(GPU_ID_PI_T72X, 0, 0, 1): -+ case GPU_ID_MAKE(GPU_ID_PI_T72X, 0, 0, 2): -+ issues = base_hw_issues_t72x_r0p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T72X, 1, 0, 0): -+ issues = base_hw_issues_t72x_r1p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T72X, 1, 1, 0): -+ issues = base_hw_issues_t72x_r1p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_TFRX, 0, 1, 2): -+ issues = base_hw_issues_tFRx_r0p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_TFRX, 0, 2, 0): -+ issues = base_hw_issues_tFRx_r0p2; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_TFRX, 1, 0, 0): -+ case GPU_ID_MAKE(GPU_ID_PI_TFRX, 1, 0, 8): -+ issues = base_hw_issues_tFRx_r1p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_TFRX, 2, 0, 0): -+ issues = base_hw_issues_tFRx_r2p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T86X, 0, 2, 0): -+ issues = base_hw_issues_t86x_r0p2; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T86X, 1, 0, 0): -+ case GPU_ID_MAKE(GPU_ID_PI_T86X, 1, 0, 8): -+ issues = base_hw_issues_t86x_r1p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T86X, 2, 0, 0): -+ issues = base_hw_issues_t86x_r2p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T83X, 0, 1, 0): -+ issues = base_hw_issues_t83x_r0p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T83X, 1, 0, 0): -+ case GPU_ID_MAKE(GPU_ID_PI_T83X, 1, 0, 8): -+ issues = base_hw_issues_t83x_r1p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T82X, 0, 0, 0): -+ issues = base_hw_issues_t82x_r0p0; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T82X, 0, 1, 0): -+ issues = base_hw_issues_t82x_r0p1; -+ break; -+ case GPU_ID_MAKE(GPU_ID_PI_T82X, 1, 0, 0): -+ case GPU_ID_MAKE(GPU_ID_PI_T82X, 1, 0, 8): -+ issues = base_hw_issues_t82x_r1p0; -+ break; -+ default: -+ dev_err(kbdev->dev, -+ "Unknown GPU ID %x", gpu_id); -+ return -EINVAL; -+ } -+ } -+ } else { -+ /* Software model */ -+ if (GPU_ID_IS_NEW_FORMAT(product_id)) { -+ switch (gpu_id & GPU_ID2_PRODUCT_MODEL) { -+ case GPU_ID2_PRODUCT_TMIX: -+ issues = base_hw_issues_model_tMIx; -+ break; -+ case GPU_ID2_PRODUCT_THEX: -+ issues = base_hw_issues_model_tHEx; -+ break; -+ case GPU_ID2_PRODUCT_TSIX: -+ issues = base_hw_issues_model_tSIx; -+ break; -+#ifdef MALI_INCLUDE_TDVX -+ case GPU_ID2_PRODUCT_TDVX: -+ issues = base_hw_issues_model_tDVx; -+ break; -+#endif /* MALI_INCLUDE_TNOX */ -+#ifdef MALI_INCLUDE_TGOX -+ case GPU_ID2_PRODUCT_TGOX: -+ issues = base_hw_issues_model_tGOx; -+ break; -+#endif /* MALI_INCLUDE_TGOX */ -+#ifdef MALI_INCLUDE_TKAX -+ case GPU_ID2_PRODUCT_TKAX: -+ issues = base_hw_issues_model_tKAx; -+ break; -+#endif /* MALI_INCLUDE_TKAX */ -+#ifdef MALI_INCLUDE_TTRX -+ case GPU_ID2_PRODUCT_TTRX: -+ issues = base_hw_issues_model_tTRx; -+ break; -+#endif /* MALI_INCLUDE_TTRX */ -+ default: -+ dev_err(kbdev->dev, -+ "Unknown GPU ID %x", gpu_id); -+ return -EINVAL; -+ } -+ } else { -+ switch (product_id) { -+ case GPU_ID_PI_T60X: -+ issues = base_hw_issues_model_t60x; -+ break; -+ case GPU_ID_PI_T62X: -+ issues = base_hw_issues_model_t62x; -+ break; -+ case GPU_ID_PI_T72X: -+ issues = base_hw_issues_model_t72x; -+ break; -+ case GPU_ID_PI_T76X: -+ issues = base_hw_issues_model_t76x; -+ break; -+ case GPU_ID_PI_TFRX: -+ issues = base_hw_issues_model_tFRx; -+ break; -+ case GPU_ID_PI_T86X: -+ issues = base_hw_issues_model_t86x; -+ break; -+ case GPU_ID_PI_T83X: -+ issues = base_hw_issues_model_t83x; -+ break; -+ case GPU_ID_PI_T82X: -+ issues = base_hw_issues_model_t82x; -+ break; -+ default: -+ dev_err(kbdev->dev, "Unknown GPU ID %x", -+ gpu_id); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ if (GPU_ID_IS_NEW_FORMAT(product_id)) { -+ dev_info(kbdev->dev, -+ "GPU identified as 0x%x arch %d.%d.%d r%dp%d status %d", -+ (gpu_id & GPU_ID2_PRODUCT_MAJOR) >> -+ GPU_ID2_PRODUCT_MAJOR_SHIFT, -+ (gpu_id & GPU_ID2_ARCH_MAJOR) >> -+ GPU_ID2_ARCH_MAJOR_SHIFT, -+ (gpu_id & GPU_ID2_ARCH_MINOR) >> -+ GPU_ID2_ARCH_MINOR_SHIFT, -+ (gpu_id & GPU_ID2_ARCH_REV) >> -+ GPU_ID2_ARCH_REV_SHIFT, -+ (gpu_id & GPU_ID2_VERSION_MAJOR) >> -+ GPU_ID2_VERSION_MAJOR_SHIFT, -+ (gpu_id & GPU_ID2_VERSION_MINOR) >> -+ GPU_ID2_VERSION_MINOR_SHIFT, -+ (gpu_id & GPU_ID2_VERSION_STATUS) >> -+ GPU_ID2_VERSION_STATUS_SHIFT); -+ } else { -+ dev_info(kbdev->dev, -+ "GPU identified as 0x%04x r%dp%d status %d", -+ (gpu_id & GPU_ID_VERSION_PRODUCT_ID) >> -+ GPU_ID_VERSION_PRODUCT_ID_SHIFT, -+ (gpu_id & GPU_ID_VERSION_MAJOR) >> -+ GPU_ID_VERSION_MAJOR_SHIFT, -+ (gpu_id & GPU_ID_VERSION_MINOR) >> -+ GPU_ID_VERSION_MINOR_SHIFT, -+ (gpu_id & GPU_ID_VERSION_STATUS) >> -+ GPU_ID_VERSION_STATUS_SHIFT); -+ } -+ -+ for (; *issues != BASE_HW_ISSUE_END; issues++) -+ set_bit(*issues, &kbdev->hw_issues_mask[0]); -+ -+ return 0; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hw.h b/drivers/gpu/arm/midgard/mali_kbase_hw.h -new file mode 100644 -index 0000000..754250c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hw.h -@@ -0,0 +1,65 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file -+ * Run-time work-arounds helpers -+ */ -+ -+#ifndef _KBASE_HW_H_ -+#define _KBASE_HW_H_ -+ -+#include "mali_kbase_defs.h" -+ -+/** -+ * @brief Tell whether a work-around should be enabled -+ */ -+#define kbase_hw_has_issue(kbdev, issue)\ -+ test_bit(issue, &(kbdev)->hw_issues_mask[0]) -+ -+/** -+ * @brief Tell whether a feature is supported -+ */ -+#define kbase_hw_has_feature(kbdev, feature)\ -+ test_bit(feature, &(kbdev)->hw_features_mask[0]) -+ -+/** -+ * kbase_hw_set_issues_mask - Set the hardware issues mask based on the GPU ID -+ * @kbdev: Device pointer -+ * -+ * Return: 0 if the GPU ID was recognized, otherwise -EINVAL. -+ * -+ * The GPU ID is read from the @kbdev. -+ * -+ * In debugging versions of the driver, unknown versions of a known GPU with a -+ * new-format ID will be treated as the most recent known version not later -+ * than the actual version. In such circumstances, the GPU ID in @kbdev will -+ * also be replaced with the most recent known version. -+ * -+ * Note: The GPU configuration must have been read by -+ * kbase_gpuprops_get_props() before calling this function. -+ */ -+int kbase_hw_set_issues_mask(struct kbase_device *kbdev); -+ -+/** -+ * @brief Set the features mask depending on the GPU ID -+ */ -+void kbase_hw_set_features_mask(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_HW_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwaccess_backend.h b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_backend.h -new file mode 100644 -index 0000000..b09be99 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_backend.h -@@ -0,0 +1,54 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * HW access backend common APIs -+ */ -+ -+#ifndef _KBASE_HWACCESS_BACKEND_H_ -+#define _KBASE_HWACCESS_BACKEND_H_ -+ -+/** -+ * kbase_backend_early_init - Perform any backend-specific initialization. -+ * @kbdev: Device pointer -+ * -+ * Return: 0 on success, or an error code on failure. -+ */ -+int kbase_backend_early_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_late_init - Perform any backend-specific initialization. -+ * @kbdev: Device pointer -+ * -+ * Return: 0 on success, or an error code on failure. -+ */ -+int kbase_backend_late_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_early_term - Perform any backend-specific termination. -+ * @kbdev: Device pointer -+ */ -+void kbase_backend_early_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_late_term - Perform any backend-specific termination. -+ * @kbdev: Device pointer -+ */ -+void kbase_backend_late_term(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_HWACCESS_BACKEND_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwaccess_defs.h b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_defs.h -new file mode 100644 -index 0000000..0acf297 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_defs.h -@@ -0,0 +1,36 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_hwaccess_gpu_defs.h -+ * HW access common definitions -+ */ -+ -+#ifndef _KBASE_HWACCESS_DEFS_H_ -+#define _KBASE_HWACCESS_DEFS_H_ -+ -+#include -+ -+/* The hwaccess_lock (a spinlock) must be held when accessing this structure */ -+struct kbase_hwaccess_data { -+ struct kbase_context *active_kctx; -+ -+ struct kbase_backend_data backend; -+}; -+ -+#endif /* _KBASE_HWACCESS_DEFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwaccess_gpuprops.h b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_gpuprops.h -new file mode 100644 -index 0000000..cf8a813 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_gpuprops.h -@@ -0,0 +1,47 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/** -+ * Base kernel property query backend APIs -+ */ -+ -+#ifndef _KBASE_HWACCESS_GPUPROPS_H_ -+#define _KBASE_HWACCESS_GPUPROPS_H_ -+ -+/** -+ * kbase_backend_gpuprops_get() - Fill @regdump with GPU properties read from -+ * GPU -+ * @kbdev: Device pointer -+ * @regdump: Pointer to struct kbase_gpuprops_regdump structure -+ */ -+void kbase_backend_gpuprops_get(struct kbase_device *kbdev, -+ struct kbase_gpuprops_regdump *regdump); -+ -+/** -+ * kbase_backend_gpuprops_get - Fill @regdump with GPU properties read from GPU -+ * @kbdev: Device pointer -+ * @regdump: Pointer to struct kbase_gpuprops_regdump structure -+ * -+ * This function reads GPU properties that are dependent on the hardware -+ * features bitmask -+ */ -+void kbase_backend_gpuprops_get_features(struct kbase_device *kbdev, -+ struct kbase_gpuprops_regdump *regdump); -+ -+ -+#endif /* _KBASE_HWACCESS_GPUPROPS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwaccess_instr.h b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_instr.h -new file mode 100644 -index 0000000..5de2b75 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_instr.h -@@ -0,0 +1,116 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * HW Access instrumentation common APIs -+ */ -+ -+#ifndef _KBASE_HWACCESS_INSTR_H_ -+#define _KBASE_HWACCESS_INSTR_H_ -+ -+#include -+ -+/** -+ * kbase_instr_hwcnt_enable_internal - Enable HW counters collection -+ * @kbdev: Kbase device -+ * @kctx: Kbase context -+ * @setup: HW counter setup parameters -+ * -+ * Context: might sleep, waiting for reset to complete -+ * -+ * Return: 0 on success -+ */ -+int kbase_instr_hwcnt_enable_internal(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ struct kbase_uk_hwcnt_setup *setup); -+ -+/** -+ * kbase_instr_hwcnt_disable_internal - Disable HW counters collection -+ * @kctx: Kbase context -+ * -+ * Context: might sleep, waiting for an ongoing dump to complete -+ * -+ * Return: 0 on success -+ */ -+int kbase_instr_hwcnt_disable_internal(struct kbase_context *kctx); -+ -+/** -+ * kbase_instr_hwcnt_request_dump() - Request HW counter dump from GPU -+ * @kctx: Kbase context -+ * -+ * Caller must either wait for kbase_instr_hwcnt_dump_complete() to return true, -+ * of call kbase_instr_hwcnt_wait_for_dump(). -+ * -+ * Return: 0 on success -+ */ -+int kbase_instr_hwcnt_request_dump(struct kbase_context *kctx); -+ -+/** -+ * kbase_instr_hwcnt_wait_for_dump() - Wait until pending HW counter dump has -+ * completed. -+ * @kctx: Kbase context -+ * -+ * Context: will sleep, waiting for dump to complete -+ * -+ * Return: 0 on success -+ */ -+int kbase_instr_hwcnt_wait_for_dump(struct kbase_context *kctx); -+ -+/** -+ * kbase_instr_hwcnt_dump_complete - Tell whether the HW counters dump has -+ * completed -+ * @kctx: Kbase context -+ * @success: Set to true if successful -+ * -+ * Context: does not sleep. -+ * -+ * Return: true if the dump is complete -+ */ -+bool kbase_instr_hwcnt_dump_complete(struct kbase_context *kctx, -+ bool * const success); -+ -+/** -+ * kbase_instr_hwcnt_clear() - Clear HW counters -+ * @kctx: Kbase context -+ * -+ * Context: might sleep, waiting for reset to complete -+ * -+ * Return: 0 on success -+ */ -+int kbase_instr_hwcnt_clear(struct kbase_context *kctx); -+ -+/** -+ * kbase_instr_backend_init() - Initialise the instrumentation backend -+ * @kbdev: Kbase device -+ * -+ * This function should be called during driver initialization. -+ * -+ * Return: 0 on success -+ */ -+int kbase_instr_backend_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_instr_backend_init() - Terminate the instrumentation backend -+ * @kbdev: Kbase device -+ * -+ * This function should be called during driver termination. -+ */ -+void kbase_instr_backend_term(struct kbase_device *kbdev); -+ -+#endif /* _KBASE_HWACCESS_INSTR_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwaccess_jm.h b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_jm.h -new file mode 100644 -index 0000000..750fda2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_jm.h -@@ -0,0 +1,381 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * HW access job manager common APIs -+ */ -+ -+#ifndef _KBASE_HWACCESS_JM_H_ -+#define _KBASE_HWACCESS_JM_H_ -+ -+/** -+ * kbase_backend_run_atom() - Run an atom on the GPU -+ * @kbdev: Device pointer -+ * @atom: Atom to run -+ * -+ * Caller must hold the HW access lock -+ */ -+void kbase_backend_run_atom(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_backend_slot_update - Update state based on slot ringbuffers -+ * -+ * @kbdev: Device pointer -+ * -+ * Inspect the jobs in the slot ringbuffers and update state. -+ * -+ * This will cause jobs to be submitted to hardware if they are unblocked -+ */ -+void kbase_backend_slot_update(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_find_and_release_free_address_space() - Release a free AS -+ * @kbdev: Device pointer -+ * @kctx: Context pointer -+ * -+ * This function can evict an idle context from the runpool, freeing up the -+ * address space it was using. -+ * -+ * The address space is marked as in use. The caller must either assign a -+ * context using kbase_gpu_use_ctx(), or release it using -+ * kbase_ctx_sched_release() -+ * -+ * Return: Number of free address space, or KBASEP_AS_NR_INVALID if none -+ * available -+ */ -+int kbase_backend_find_and_release_free_address_space( -+ struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * kbase_backend_use_ctx() - Activate a currently unscheduled context, using the -+ * provided address space. -+ * @kbdev: Device pointer -+ * @kctx: Context pointer. May be NULL -+ * @as_nr: Free address space to use -+ * -+ * kbase_gpu_next_job() will pull atoms from the active context. -+ * -+ * Return: true if successful, false if ASID not assigned. -+ */ -+bool kbase_backend_use_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int as_nr); -+ -+/** -+ * kbase_backend_use_ctx_sched() - Activate a context. -+ * @kbdev: Device pointer -+ * @kctx: Context pointer -+ * -+ * kbase_gpu_next_job() will pull atoms from the active context. -+ * -+ * The context must already be scheduled and assigned to an address space. If -+ * the context is not scheduled, then kbase_gpu_use_ctx() should be used -+ * instead. -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: true if context is now active, false otherwise (ie if context does -+ * not have an address space assigned) -+ */ -+bool kbase_backend_use_ctx_sched(struct kbase_device *kbdev, -+ struct kbase_context *kctx); -+ -+/** -+ * kbase_backend_release_ctx_irq - Release a context from the GPU. This will -+ * de-assign the assigned address space. -+ * @kbdev: Device pointer -+ * @kctx: Context pointer -+ * -+ * Caller must hold kbase_device->mmu_hw_mutex and hwaccess_lock -+ */ -+void kbase_backend_release_ctx_irq(struct kbase_device *kbdev, -+ struct kbase_context *kctx); -+ -+/** -+ * kbase_backend_release_ctx_noirq - Release a context from the GPU. This will -+ * de-assign the assigned address space. -+ * @kbdev: Device pointer -+ * @kctx: Context pointer -+ * -+ * Caller must hold kbase_device->mmu_hw_mutex -+ * -+ * This function must perform any operations that could not be performed in IRQ -+ * context by kbase_backend_release_ctx_irq(). -+ */ -+void kbase_backend_release_ctx_noirq(struct kbase_device *kbdev, -+ struct kbase_context *kctx); -+ -+/** -+ * kbase_backend_cacheclean - Perform a cache clean if the given atom requires -+ * one -+ * @kbdev: Device pointer -+ * @katom: Pointer to the failed atom -+ * -+ * On some GPUs, the GPU cache must be cleaned following a failed atom. This -+ * function performs a clean if it is required by @katom. -+ */ -+void kbase_backend_cacheclean(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom); -+ -+ -+/** -+ * kbase_backend_complete_wq() - Perform backend-specific actions required on -+ * completing an atom. -+ * @kbdev: Device pointer -+ * @katom: Pointer to the atom to complete -+ * -+ * This function should only be called from kbase_jd_done_worker() or -+ * js_return_worker(). -+ * -+ * Return: true if atom has completed, false if atom should be re-submitted -+ */ -+void kbase_backend_complete_wq(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_backend_complete_wq_post_sched - Perform backend-specific actions -+ * required on completing an atom, after -+ * any scheduling has taken place. -+ * @kbdev: Device pointer -+ * @core_req: Core requirements of atom -+ * @affinity: Affinity of atom -+ * @coreref_state: Coreref state of atom -+ * -+ * This function should only be called from kbase_jd_done_worker() or -+ * js_return_worker(). -+ */ -+void kbase_backend_complete_wq_post_sched(struct kbase_device *kbdev, -+ base_jd_core_req core_req, u64 affinity, -+ enum kbase_atom_coreref_state coreref_state); -+ -+/** -+ * kbase_backend_reset() - The GPU is being reset. Cancel all jobs on the GPU -+ * and remove any others from the ringbuffers. -+ * @kbdev: Device pointer -+ * @end_timestamp: Timestamp of reset -+ */ -+void kbase_backend_reset(struct kbase_device *kbdev, ktime_t *end_timestamp); -+ -+/** -+ * kbase_backend_inspect_head() - Return the atom currently at the head of slot -+ * @js -+ * @kbdev: Device pointer -+ * @js: Job slot to inspect -+ * -+ * Return : Atom currently at the head of slot @js, or NULL -+ */ -+struct kbase_jd_atom *kbase_backend_inspect_head(struct kbase_device *kbdev, -+ int js); -+ -+/** -+ * kbase_backend_inspect_tail - Return the atom currently at the tail of slot -+ * @js -+ * @kbdev: Device pointer -+ * @js: Job slot to inspect -+ * -+ * Return : Atom currently at the head of slot @js, or NULL -+ */ -+struct kbase_jd_atom *kbase_backend_inspect_tail(struct kbase_device *kbdev, -+ int js); -+ -+/** -+ * kbase_backend_nr_atoms_on_slot() - Return the number of atoms currently on a -+ * slot. -+ * @kbdev: Device pointer -+ * @js: Job slot to inspect -+ * -+ * Return : Number of atoms currently on slot -+ */ -+int kbase_backend_nr_atoms_on_slot(struct kbase_device *kbdev, int js); -+ -+/** -+ * kbase_backend_nr_atoms_submitted() - Return the number of atoms on a slot -+ * that are currently on the GPU. -+ * @kbdev: Device pointer -+ * @js: Job slot to inspect -+ * -+ * Return : Number of atoms currently on slot @js that are currently on the GPU. -+ */ -+int kbase_backend_nr_atoms_submitted(struct kbase_device *kbdev, int js); -+ -+/** -+ * kbase_backend_ctx_count_changed() - Number of contexts ready to submit jobs -+ * has changed. -+ * @kbdev: Device pointer -+ * -+ * Perform any required backend-specific actions (eg starting/stopping -+ * scheduling timers). -+ */ -+void kbase_backend_ctx_count_changed(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_timeouts_changed() - Job Scheduler timeouts have changed. -+ * @kbdev: Device pointer -+ * -+ * Perform any required backend-specific actions (eg updating timeouts of -+ * currently running atoms). -+ */ -+void kbase_backend_timeouts_changed(struct kbase_device *kbdev); -+ -+/** -+ * kbase_backend_slot_free() - Return the number of jobs that can be currently -+ * submitted to slot @js. -+ * @kbdev: Device pointer -+ * @js: Job slot to inspect -+ * -+ * Return : Number of jobs that can be submitted. -+ */ -+int kbase_backend_slot_free(struct kbase_device *kbdev, int js); -+ -+/** -+ * kbase_job_check_enter_disjoint - potentially leave disjoint state -+ * @kbdev: kbase device -+ * @target_katom: atom which is finishing -+ * -+ * Work out whether to leave disjoint state when finishing an atom that was -+ * originated by kbase_job_check_enter_disjoint(). -+ */ -+void kbase_job_check_leave_disjoint(struct kbase_device *kbdev, -+ struct kbase_jd_atom *target_katom); -+ -+/** -+ * kbase_backend_jm_kill_jobs_from_kctx - Kill all jobs that are currently -+ * running from a context -+ * @kctx: Context pointer -+ * -+ * This is used in response to a page fault to remove all jobs from the faulting -+ * context from the hardware. -+ */ -+void kbase_backend_jm_kill_jobs_from_kctx(struct kbase_context *kctx); -+ -+/** -+ * kbase_jm_wait_for_zero_jobs - Wait for context to have zero jobs running, and -+ * to be descheduled. -+ * @kctx: Context pointer -+ * -+ * This should be called following kbase_js_zap_context(), to ensure the context -+ * can be safely destroyed. -+ */ -+void kbase_jm_wait_for_zero_jobs(struct kbase_context *kctx); -+ -+/** -+ * kbase_backend_get_current_flush_id - Return the current flush ID -+ * -+ * @kbdev: Device pointer -+ * -+ * Return: the current flush ID to be recorded for each job chain -+ */ -+u32 kbase_backend_get_current_flush_id(struct kbase_device *kbdev); -+ -+#if KBASE_GPU_RESET_EN -+/** -+ * kbase_prepare_to_reset_gpu - Prepare for resetting the GPU. -+ * @kbdev: Device pointer -+ * -+ * This function just soft-stops all the slots to ensure that as many jobs as -+ * possible are saved. -+ * -+ * Return: a boolean which should be interpreted as follows: -+ * - true - Prepared for reset, kbase_reset_gpu should be called. -+ * - false - Another thread is performing a reset, kbase_reset_gpu should -+ * not be called. -+ */ -+bool kbase_prepare_to_reset_gpu(struct kbase_device *kbdev); -+ -+/** -+ * kbase_reset_gpu - Reset the GPU -+ * @kbdev: Device pointer -+ * -+ * This function should be called after kbase_prepare_to_reset_gpu if it returns -+ * true. It should never be called without a corresponding call to -+ * kbase_prepare_to_reset_gpu. -+ * -+ * After this function is called (or not called if kbase_prepare_to_reset_gpu -+ * returned false), the caller should wait for kbdev->reset_waitq to be -+ * signalled to know when the reset has completed. -+ */ -+void kbase_reset_gpu(struct kbase_device *kbdev); -+ -+/** -+ * kbase_prepare_to_reset_gpu_locked - Prepare for resetting the GPU. -+ * @kbdev: Device pointer -+ * -+ * This function just soft-stops all the slots to ensure that as many jobs as -+ * possible are saved. -+ * -+ * Return: a boolean which should be interpreted as follows: -+ * - true - Prepared for reset, kbase_reset_gpu should be called. -+ * - false - Another thread is performing a reset, kbase_reset_gpu should -+ * not be called. -+ */ -+bool kbase_prepare_to_reset_gpu_locked(struct kbase_device *kbdev); -+ -+/** -+ * kbase_reset_gpu_locked - Reset the GPU -+ * @kbdev: Device pointer -+ * -+ * This function should be called after kbase_prepare_to_reset_gpu if it -+ * returns true. It should never be called without a corresponding call to -+ * kbase_prepare_to_reset_gpu. -+ * -+ * After this function is called (or not called if kbase_prepare_to_reset_gpu -+ * returned false), the caller should wait for kbdev->reset_waitq to be -+ * signalled to know when the reset has completed. -+ */ -+void kbase_reset_gpu_locked(struct kbase_device *kbdev); -+ -+/** -+ * kbase_reset_gpu_silent - Reset the GPU silently -+ * @kbdev: Device pointer -+ * -+ * Reset the GPU without trying to cancel jobs and don't emit messages into -+ * the kernel log while doing the reset. -+ * -+ * This function should be used in cases where we are doing a controlled reset -+ * of the GPU as part of normal processing (e.g. exiting protected mode) where -+ * the driver will have ensured the scheduler has been idled and all other -+ * users of the GPU (e.g. instrumentation) have been suspended. -+ */ -+void kbase_reset_gpu_silent(struct kbase_device *kbdev); -+ -+/** -+ * kbase_reset_gpu_active - Reports if the GPU is being reset -+ * @kbdev: Device pointer -+ * -+ * Return: True if the GPU is in the process of being reset. -+ */ -+bool kbase_reset_gpu_active(struct kbase_device *kbdev); -+#endif -+ -+/** -+ * kbase_job_slot_hardstop - Hard-stop the specified job slot -+ * @kctx: The kbase context that contains the job(s) that should -+ * be hard-stopped -+ * @js: The job slot to hard-stop -+ * @target_katom: The job that should be hard-stopped (or NULL for all -+ * jobs from the context) -+ * Context: -+ * The job slot lock must be held when calling this function. -+ */ -+void kbase_job_slot_hardstop(struct kbase_context *kctx, int js, -+ struct kbase_jd_atom *target_katom); -+ -+extern struct protected_mode_ops kbase_native_protected_ops; -+ -+#endif /* _KBASE_HWACCESS_JM_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwaccess_pm.h b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_pm.h -new file mode 100644 -index 0000000..71c7d49 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_pm.h -@@ -0,0 +1,209 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_hwaccess_pm.h -+ * HW access power manager common APIs -+ */ -+ -+#ifndef _KBASE_HWACCESS_PM_H_ -+#define _KBASE_HWACCESS_PM_H_ -+ -+#include -+#include -+ -+#include -+ -+/* Forward definition - see mali_kbase.h */ -+struct kbase_device; -+ -+/* Functions common to all HW access backends */ -+ -+/** -+ * Initialize the power management framework. -+ * -+ * Must be called before any other power management function -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ * -+ * @return 0 if the power management framework was successfully -+ * initialized. -+ */ -+int kbase_hwaccess_pm_init(struct kbase_device *kbdev); -+ -+/** -+ * Terminate the power management framework. -+ * -+ * No power management functions may be called after this (except -+ * @ref kbase_pm_init) -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ */ -+void kbase_hwaccess_pm_term(struct kbase_device *kbdev); -+ -+/** -+ * kbase_hwaccess_pm_powerup - Power up the GPU. -+ * @kbdev: The kbase device structure for the device (must be a valid pointer) -+ * @flags: Flags to pass on to kbase_pm_init_hw -+ * -+ * Power up GPU after all modules have been initialized and interrupt handlers -+ * installed. -+ * -+ * Return: 0 if powerup was successful. -+ */ -+int kbase_hwaccess_pm_powerup(struct kbase_device *kbdev, -+ unsigned int flags); -+ -+/** -+ * Halt the power management framework. -+ * -+ * Should ensure that no new interrupts are generated, but allow any currently -+ * running interrupt handlers to complete successfully. The GPU is forced off by -+ * the time this function returns, regardless of whether or not the active power -+ * policy asks for the GPU to be powered off. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ */ -+void kbase_hwaccess_pm_halt(struct kbase_device *kbdev); -+ -+/** -+ * Perform any backend-specific actions to suspend the GPU -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ */ -+void kbase_hwaccess_pm_suspend(struct kbase_device *kbdev); -+ -+/** -+ * Perform any backend-specific actions to resume the GPU from a suspend -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ */ -+void kbase_hwaccess_pm_resume(struct kbase_device *kbdev); -+ -+/** -+ * Perform any required actions for activating the GPU. Called when the first -+ * context goes active. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ */ -+void kbase_hwaccess_pm_gpu_active(struct kbase_device *kbdev); -+ -+/** -+ * Perform any required actions for idling the GPU. Called when the last -+ * context goes idle. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ */ -+void kbase_hwaccess_pm_gpu_idle(struct kbase_device *kbdev); -+ -+ -+/** -+ * Set the debug core mask. -+ * -+ * This determines which cores the power manager is allowed to use. -+ * -+ * @param kbdev The kbase device structure for the device (must be a -+ * valid pointer) -+ * @param new_core_mask_js0 The core mask to use for job slot 0 -+ * @param new_core_mask_js0 The core mask to use for job slot 1 -+ * @param new_core_mask_js0 The core mask to use for job slot 2 -+ */ -+void kbase_pm_set_debug_core_mask(struct kbase_device *kbdev, -+ u64 new_core_mask_js0, u64 new_core_mask_js1, -+ u64 new_core_mask_js2); -+ -+ -+/** -+ * Get the current policy. -+ * -+ * Returns the policy that is currently active. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ * -+ * @return The current policy -+ */ -+const struct kbase_pm_ca_policy -+*kbase_pm_ca_get_policy(struct kbase_device *kbdev); -+ -+/** -+ * Change the policy to the one specified. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ * @param policy The policy to change to (valid pointer returned from -+ * @ref kbase_pm_ca_list_policies) -+ */ -+void kbase_pm_ca_set_policy(struct kbase_device *kbdev, -+ const struct kbase_pm_ca_policy *policy); -+ -+/** -+ * Retrieve a static list of the available policies. -+ * -+ * @param[out] policies An array pointer to take the list of policies. This may -+ * be NULL. The contents of this array must not be -+ * modified. -+ * -+ * @return The number of policies -+ */ -+int -+kbase_pm_ca_list_policies(const struct kbase_pm_ca_policy * const **policies); -+ -+ -+/** -+ * Get the current policy. -+ * -+ * Returns the policy that is currently active. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ * -+ * @return The current policy -+ */ -+const struct kbase_pm_policy *kbase_pm_get_policy(struct kbase_device *kbdev); -+ -+/** -+ * Change the policy to the one specified. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid -+ * pointer) -+ * @param policy The policy to change to (valid pointer returned from -+ * @ref kbase_pm_list_policies) -+ */ -+void kbase_pm_set_policy(struct kbase_device *kbdev, -+ const struct kbase_pm_policy *policy); -+ -+/** -+ * Retrieve a static list of the available policies. -+ * -+ * @param[out] policies An array pointer to take the list of policies. This may -+ * be NULL. The contents of this array must not be -+ * modified. -+ * -+ * @return The number of policies -+ */ -+int kbase_pm_list_policies(const struct kbase_pm_policy * const **policies); -+ -+#endif /* _KBASE_HWACCESS_PM_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwaccess_time.h b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_time.h -new file mode 100644 -index 0000000..89d26ea ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwaccess_time.h -@@ -0,0 +1,53 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/** -+ * -+ */ -+ -+#ifndef _KBASE_BACKEND_TIME_H_ -+#define _KBASE_BACKEND_TIME_H_ -+ -+/** -+ * kbase_backend_get_gpu_time() - Get current GPU time -+ * @kbdev: Device pointer -+ * @cycle_counter: Pointer to u64 to store cycle counter in -+ * @system_time: Pointer to u64 to store system time in -+ * @ts: Pointer to struct timespec to store current monotonic -+ * time in -+ */ -+void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter, -+ u64 *system_time, struct timespec *ts); -+ -+/** -+ * kbase_wait_write_flush() - Wait for GPU write flush -+ * @kctx: Context pointer -+ * -+ * Wait 1000 GPU clock cycles. This delay is known to give the GPU time to flush -+ * its write buffer. -+ * -+ * If GPU resets occur then the counters are reset to zero, the delay may not be -+ * as expected. -+ * -+ * This function is only in use for BASE_HW_ISSUE_6367 -+ */ -+#ifndef CONFIG_MALI_NO_MALI -+void kbase_wait_write_flush(struct kbase_context *kctx); -+#endif -+ -+#endif /* _KBASE_BACKEND_TIME_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_hwcnt_reader.h b/drivers/gpu/arm/midgard/mali_kbase_hwcnt_reader.h -new file mode 100644 -index 0000000..cf7bf1b ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_hwcnt_reader.h -@@ -0,0 +1,66 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_HWCNT_READER_H_ -+#define _KBASE_HWCNT_READER_H_ -+ -+/* The ids of ioctl commands. */ -+#define KBASE_HWCNT_READER 0xBE -+#define KBASE_HWCNT_READER_GET_HWVER _IOR(KBASE_HWCNT_READER, 0x00, u32) -+#define KBASE_HWCNT_READER_GET_BUFFER_SIZE _IOR(KBASE_HWCNT_READER, 0x01, u32) -+#define KBASE_HWCNT_READER_DUMP _IOW(KBASE_HWCNT_READER, 0x10, u32) -+#define KBASE_HWCNT_READER_CLEAR _IOW(KBASE_HWCNT_READER, 0x11, u32) -+#define KBASE_HWCNT_READER_GET_BUFFER _IOR(KBASE_HWCNT_READER, 0x20,\ -+ struct kbase_hwcnt_reader_metadata) -+#define KBASE_HWCNT_READER_PUT_BUFFER _IOW(KBASE_HWCNT_READER, 0x21,\ -+ struct kbase_hwcnt_reader_metadata) -+#define KBASE_HWCNT_READER_SET_INTERVAL _IOW(KBASE_HWCNT_READER, 0x30, u32) -+#define KBASE_HWCNT_READER_ENABLE_EVENT _IOW(KBASE_HWCNT_READER, 0x40, u32) -+#define KBASE_HWCNT_READER_DISABLE_EVENT _IOW(KBASE_HWCNT_READER, 0x41, u32) -+#define KBASE_HWCNT_READER_GET_API_VERSION _IOW(KBASE_HWCNT_READER, 0xFF, u32) -+ -+/** -+ * struct kbase_hwcnt_reader_metadata - hwcnt reader sample buffer metadata -+ * @timestamp: time when sample was collected -+ * @event_id: id of an event that triggered sample collection -+ * @buffer_idx: position in sampling area where sample buffer was stored -+ */ -+struct kbase_hwcnt_reader_metadata { -+ u64 timestamp; -+ u32 event_id; -+ u32 buffer_idx; -+}; -+ -+/** -+ * enum base_hwcnt_reader_event - hwcnt dumping events -+ * @BASE_HWCNT_READER_EVENT_MANUAL: manual request for dump -+ * @BASE_HWCNT_READER_EVENT_PERIODIC: periodic dump -+ * @BASE_HWCNT_READER_EVENT_PREJOB: prejob dump request -+ * @BASE_HWCNT_READER_EVENT_POSTJOB: postjob dump request -+ * @BASE_HWCNT_READER_EVENT_COUNT: number of supported events -+ */ -+enum base_hwcnt_reader_event { -+ BASE_HWCNT_READER_EVENT_MANUAL, -+ BASE_HWCNT_READER_EVENT_PERIODIC, -+ BASE_HWCNT_READER_EVENT_PREJOB, -+ BASE_HWCNT_READER_EVENT_POSTJOB, -+ -+ BASE_HWCNT_READER_EVENT_COUNT -+}; -+ -+#endif /* _KBASE_HWCNT_READER_H_ */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_ioctl.h b/drivers/gpu/arm/midgard/mali_kbase_ioctl.h -new file mode 100644 -index 0000000..3957cd1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_ioctl.h -@@ -0,0 +1,658 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_IOCTL_H_ -+#define _KBASE_IOCTL_H_ -+ -+#ifdef __cpluscplus -+extern "C" { -+#endif -+ -+#include -+ -+#define KBASE_IOCTL_TYPE 0x80 -+ -+#ifdef ANDROID -+/* Android's definition of ioctl is incorrect, specifying the type argument as -+ * 'int'. This creates a warning when using _IOWR (as the top bit is set). Work -+ * round this by redefining _IOC to include a case to 'int'. -+ */ -+#undef _IOC -+#define _IOC(dir, type, nr, size) \ -+ ((int)(((dir) << _IOC_DIRSHIFT) | ((type) << _IOC_TYPESHIFT) | \ -+ ((nr) << _IOC_NRSHIFT) | ((size) << _IOC_SIZESHIFT))) -+#endif -+ -+/** -+ * struct kbase_ioctl_version_check - Check version compatibility with kernel -+ * -+ * @major: Major version number -+ * @minor: Minor version number -+ */ -+struct kbase_ioctl_version_check { -+ __u16 major; -+ __u16 minor; -+}; -+ -+#define KBASE_IOCTL_VERSION_CHECK \ -+ _IOWR(KBASE_IOCTL_TYPE, 0, struct kbase_ioctl_version_check) -+ -+/** -+ * struct kbase_ioctl_set_flags - Set kernel context creation flags -+ * -+ * @create_flags: Flags - see base_context_create_flags -+ */ -+struct kbase_ioctl_set_flags { -+ __u32 create_flags; -+}; -+ -+#define KBASE_IOCTL_SET_FLAGS \ -+ _IOW(KBASE_IOCTL_TYPE, 1, struct kbase_ioctl_set_flags) -+ -+/** -+ * struct kbase_ioctl_job_submit - Submit jobs/atoms to the kernel -+ * -+ * @addr: Memory address of an array of struct base_jd_atom_v2 -+ * @nr_atoms: Number of entries in the array -+ * @stride: sizeof(struct base_jd_atom_v2) -+ */ -+struct kbase_ioctl_job_submit { -+ __u64 addr; -+ __u32 nr_atoms; -+ __u32 stride; -+}; -+ -+#define KBASE_IOCTL_JOB_SUBMIT \ -+ _IOW(KBASE_IOCTL_TYPE, 2, struct kbase_ioctl_job_submit) -+ -+/** -+ * struct kbase_ioctl_get_gpuprops - Read GPU properties from the kernel -+ * -+ * @buffer: Pointer to the buffer to store properties into -+ * @size: Size of the buffer -+ * @flags: Flags - must be zero for now -+ * -+ * The ioctl will return the number of bytes stored into @buffer or an error -+ * on failure (e.g. @size is too small). If @size is specified as 0 then no -+ * data will be written but the return value will be the number of bytes needed -+ * for all the properties. -+ * -+ * @flags may be used in the future to request a different format for the -+ * buffer. With @flags == 0 the following format is used. -+ * -+ * The buffer will be filled with pairs of values, a u32 key identifying the -+ * property followed by the value. The size of the value is identified using -+ * the bottom bits of the key. The value then immediately followed the key and -+ * is tightly packed (there is no padding). All keys and values are -+ * little-endian. -+ * -+ * 00 = u8 -+ * 01 = u16 -+ * 10 = u32 -+ * 11 = u64 -+ */ -+struct kbase_ioctl_get_gpuprops { -+ __u64 buffer; -+ __u32 size; -+ __u32 flags; -+}; -+ -+#define KBASE_IOCTL_GET_GPUPROPS \ -+ _IOW(KBASE_IOCTL_TYPE, 3, struct kbase_ioctl_get_gpuprops) -+ -+#define KBASE_IOCTL_POST_TERM \ -+ _IO(KBASE_IOCTL_TYPE, 4) -+ -+/** -+ * union kbase_ioctl_mem_alloc - Allocate memory on the GPU -+ * -+ * @va_pages: The number of pages of virtual address space to reserve -+ * @commit_pages: The number of physical pages to allocate -+ * @extent: The number of extra pages to allocate on each GPU fault which grows -+ * the region -+ * @flags: Flags -+ * @gpu_va: The GPU virtual address which is allocated -+ * -+ * @in: Input parameters -+ * @out: Output parameters -+ */ -+union kbase_ioctl_mem_alloc { -+ struct { -+ __u64 va_pages; -+ __u64 commit_pages; -+ __u64 extent; -+ __u64 flags; -+ } in; -+ struct { -+ __u64 flags; -+ __u64 gpu_va; -+ } out; -+}; -+ -+#define KBASE_IOCTL_MEM_ALLOC \ -+ _IOWR(KBASE_IOCTL_TYPE, 5, union kbase_ioctl_mem_alloc) -+ -+/** -+ * struct kbase_ioctl_mem_query - Query properties of a GPU memory region -+ * @gpu_addr: A GPU address contained within the region -+ * @query: The type of query -+ * @value: The result of the query -+ * -+ * Use a %KBASE_MEM_QUERY_xxx flag as input for @query. -+ * -+ * @in: Input parameters -+ * @out: Output parameters -+ */ -+union kbase_ioctl_mem_query { -+ struct { -+ __u64 gpu_addr; -+ __u64 query; -+ } in; -+ struct { -+ __u64 value; -+ } out; -+}; -+ -+#define KBASE_IOCTL_MEM_QUERY \ -+ _IOWR(KBASE_IOCTL_TYPE, 6, union kbase_ioctl_mem_query) -+ -+#define KBASE_MEM_QUERY_COMMIT_SIZE 1 -+#define KBASE_MEM_QUERY_VA_SIZE 2 -+#define KBASE_MEM_QUERY_FLAGS 3 -+ -+/** -+ * struct kbase_ioctl_mem_free - Free a memory region -+ * @gpu_addr: Handle to the region to free -+ */ -+struct kbase_ioctl_mem_free { -+ __u64 gpu_addr; -+}; -+ -+#define KBASE_IOCTL_MEM_FREE \ -+ _IOW(KBASE_IOCTL_TYPE, 7, struct kbase_ioctl_mem_free) -+ -+/** -+ * struct kbase_ioctl_hwcnt_reader_setup - Setup HWC dumper/reader -+ * @buffer_count: requested number of dumping buffers -+ * @jm_bm: counters selection bitmask (JM) -+ * @shader_bm: counters selection bitmask (Shader) -+ * @tiler_bm: counters selection bitmask (Tiler) -+ * @mmu_l2_bm: counters selection bitmask (MMU_L2) -+ * -+ * A fd is returned from the ioctl if successful, or a negative value on error -+ */ -+struct kbase_ioctl_hwcnt_reader_setup { -+ __u32 buffer_count; -+ __u32 jm_bm; -+ __u32 shader_bm; -+ __u32 tiler_bm; -+ __u32 mmu_l2_bm; -+}; -+ -+#define KBASE_IOCTL_HWCNT_READER_SETUP \ -+ _IOW(KBASE_IOCTL_TYPE, 8, struct kbase_ioctl_hwcnt_reader_setup) -+ -+/** -+ * struct kbase_ioctl_hwcnt_enable - Enable hardware counter collection -+ * @dump_buffer: GPU address to write counters to -+ * @jm_bm: counters selection bitmask (JM) -+ * @shader_bm: counters selection bitmask (Shader) -+ * @tiler_bm: counters selection bitmask (Tiler) -+ * @mmu_l2_bm: counters selection bitmask (MMU_L2) -+ */ -+struct kbase_ioctl_hwcnt_enable { -+ __u64 dump_buffer; -+ __u32 jm_bm; -+ __u32 shader_bm; -+ __u32 tiler_bm; -+ __u32 mmu_l2_bm; -+}; -+ -+#define KBASE_IOCTL_HWCNT_ENABLE \ -+ _IOW(KBASE_IOCTL_TYPE, 9, struct kbase_ioctl_hwcnt_enable) -+ -+#define KBASE_IOCTL_HWCNT_DUMP \ -+ _IO(KBASE_IOCTL_TYPE, 10) -+ -+#define KBASE_IOCTL_HWCNT_CLEAR \ -+ _IO(KBASE_IOCTL_TYPE, 11) -+ -+/** -+ * struct kbase_ioctl_disjoint_query - Query the disjoint counter -+ * @counter: A counter of disjoint events in the kernel -+ */ -+struct kbase_ioctl_disjoint_query { -+ __u32 counter; -+}; -+ -+#define KBASE_IOCTL_DISJOINT_QUERY \ -+ _IOR(KBASE_IOCTL_TYPE, 12, struct kbase_ioctl_disjoint_query) -+ -+/** -+ * struct kbase_ioctl_get_ddk_version - Query the kernel version -+ * @version_buffer: Buffer to receive the kernel version string -+ * @size: Size of the buffer -+ * -+ * The ioctl will return the number of bytes written into version_buffer -+ * (which includes a NULL byte) or a negative error code -+ */ -+struct kbase_ioctl_get_ddk_version { -+ __u64 version_buffer; -+ __u32 size; -+}; -+ -+#define KBASE_IOCTL_GET_DDK_VERSION \ -+ _IOW(KBASE_IOCTL_TYPE, 13, struct kbase_ioctl_get_ddk_version) -+ -+/** -+ * struct kbase_ioctl_mem_jit_init - Initialise the JIT memory allocator -+ * -+ * @va_pages: Number of VA pages to reserve for JIT -+ * -+ * Note that depending on the VA size of the application and GPU, the value -+ * specified in @va_pages may be ignored. -+ */ -+struct kbase_ioctl_mem_jit_init { -+ __u64 va_pages; -+}; -+ -+#define KBASE_IOCTL_MEM_JIT_INIT \ -+ _IOW(KBASE_IOCTL_TYPE, 14, struct kbase_ioctl_mem_jit_init) -+ -+/** -+ * struct kbase_ioctl_mem_sync - Perform cache maintenance on memory -+ * -+ * @handle: GPU memory handle (GPU VA) -+ * @user_addr: The address where it is mapped in user space -+ * @size: The number of bytes to synchronise -+ * @type: The direction to synchronise: 0 is sync to memory (clean), -+ * 1 is sync from memory (invalidate). Use the BASE_SYNCSET_OP_xxx constants. -+ * @padding: Padding to round up to a multiple of 8 bytes, must be zero -+ */ -+struct kbase_ioctl_mem_sync { -+ __u64 handle; -+ __u64 user_addr; -+ __u64 size; -+ __u8 type; -+ __u8 padding[7]; -+}; -+ -+#define KBASE_IOCTL_MEM_SYNC \ -+ _IOW(KBASE_IOCTL_TYPE, 15, struct kbase_ioctl_mem_sync) -+ -+/** -+ * union kbase_ioctl_mem_find_cpu_offset - Find the offset of a CPU pointer -+ * -+ * @gpu_addr: The GPU address of the memory region -+ * @cpu_addr: The CPU address to locate -+ * @size: A size in bytes to validate is contained within the region -+ * @offset: The offset from the start of the memory region to @cpu_addr -+ * -+ * @in: Input parameters -+ * @out: Output parameters -+ */ -+union kbase_ioctl_mem_find_cpu_offset { -+ struct { -+ __u64 gpu_addr; -+ __u64 cpu_addr; -+ __u64 size; -+ } in; -+ struct { -+ __u64 offset; -+ } out; -+}; -+ -+#define KBASE_IOCTL_MEM_FIND_CPU_OFFSET \ -+ _IOWR(KBASE_IOCTL_TYPE, 16, union kbase_ioctl_mem_find_cpu_offset) -+ -+/** -+ * struct kbase_ioctl_get_context_id - Get the kernel context ID -+ * -+ * @id: The kernel context ID -+ */ -+struct kbase_ioctl_get_context_id { -+ int id; /* This should really be __u32, but see GPUCORE-10048 */ -+}; -+ -+#define KBASE_IOCTL_GET_CONTEXT_ID \ -+ _IOR(KBASE_IOCTL_TYPE, 17, struct kbase_ioctl_get_context_id) -+ -+/** -+ * struct kbase_ioctl_tlstream_acquire - Acquire a tlstream fd -+ * -+ * @flags: Flags -+ * -+ * The ioctl returns a file descriptor when successful -+ */ -+struct kbase_ioctl_tlstream_acquire { -+ __u32 flags; -+}; -+ -+#define KBASE_IOCTL_TLSTREAM_ACQUIRE \ -+ _IOW(KBASE_IOCTL_TYPE, 18, struct kbase_ioctl_tlstream_acquire) -+ -+#define KBASE_IOCTL_TLSTREAM_FLUSH \ -+ _IO(KBASE_IOCTL_TYPE, 19) -+ -+/** -+ * struct kbase_ioctl_mem_commit - Change the amount of memory backing a region -+ * -+ * @gpu_addr: The memory region to modify -+ * @pages: The number of physical pages that should be present -+ * -+ * The ioctl may return on the following error codes or 0 for success: -+ * -ENOMEM: Out of memory -+ * -EINVAL: Invalid arguments -+ */ -+struct kbase_ioctl_mem_commit { -+ __u64 gpu_addr; -+ __u64 pages; -+}; -+ -+#define KBASE_IOCTL_MEM_COMMIT \ -+ _IOW(KBASE_IOCTL_TYPE, 20, struct kbase_ioctl_mem_commit) -+ -+/** -+ * union kbase_ioctl_mem_alias - Create an alias of memory regions -+ * @flags: Flags, see BASE_MEM_xxx -+ * @stride: Bytes between start of each memory region -+ * @nents: The number of regions to pack together into the alias -+ * @aliasing_info: Pointer to an array of struct base_mem_aliasing_info -+ * @gpu_va: Address of the new alias -+ * @va_pages: Size of the new alias -+ * -+ * @in: Input parameters -+ * @out: Output parameters -+ */ -+union kbase_ioctl_mem_alias { -+ struct { -+ __u64 flags; -+ __u64 stride; -+ __u64 nents; -+ __u64 aliasing_info; -+ } in; -+ struct { -+ __u64 flags; -+ __u64 gpu_va; -+ __u64 va_pages; -+ } out; -+}; -+ -+#define KBASE_IOCTL_MEM_ALIAS \ -+ _IOWR(KBASE_IOCTL_TYPE, 21, union kbase_ioctl_mem_alias) -+ -+/** -+ * union kbase_ioctl_mem_import - Import memory for use by the GPU -+ * @flags: Flags, see BASE_MEM_xxx -+ * @phandle: Handle to the external memory -+ * @type: Type of external memory, see base_mem_import_type -+ * @padding: Amount of extra VA pages to append to the imported buffer -+ * @gpu_va: Address of the new alias -+ * @va_pages: Size of the new alias -+ * -+ * @in: Input parameters -+ * @out: Output parameters -+ */ -+union kbase_ioctl_mem_import { -+ struct { -+ __u64 flags; -+ __u64 phandle; -+ __u32 type; -+ __u32 padding; -+ } in; -+ struct { -+ __u64 flags; -+ __u64 gpu_va; -+ __u64 va_pages; -+ } out; -+}; -+ -+#define KBASE_IOCTL_MEM_IMPORT \ -+ _IOWR(KBASE_IOCTL_TYPE, 22, union kbase_ioctl_mem_import) -+ -+/** -+ * struct kbase_ioctl_mem_flags_change - Change the flags for a memory region -+ * @gpu_va: The GPU region to modify -+ * @flags: The new flags to set -+ * @mask: Mask of the flags to modify -+ */ -+struct kbase_ioctl_mem_flags_change { -+ __u64 gpu_va; -+ __u64 flags; -+ __u64 mask; -+}; -+ -+#define KBASE_IOCTL_MEM_FLAGS_CHANGE \ -+ _IOW(KBASE_IOCTL_TYPE, 23, struct kbase_ioctl_mem_flags_change) -+ -+/** -+ * struct kbase_ioctl_stream_create - Create a synchronisation stream -+ * @name: A name to identify this stream. Must be NULL-terminated. -+ * -+ * Note that this is also called a "timeline", but is named stream to avoid -+ * confusion with other uses of the word. -+ * -+ * Unused bytes in @name (after the first NULL byte) must be also be NULL bytes. -+ * -+ * The ioctl returns a file descriptor. -+ */ -+struct kbase_ioctl_stream_create { -+ char name[32]; -+}; -+ -+#define KBASE_IOCTL_STREAM_CREATE \ -+ _IOW(KBASE_IOCTL_TYPE, 24, struct kbase_ioctl_stream_create) -+ -+/** -+ * struct kbase_ioctl_fence_validate - Validate a fd refers to a fence -+ * @fd: The file descriptor to validate -+ */ -+struct kbase_ioctl_fence_validate { -+ int fd; -+}; -+ -+#define KBASE_IOCTL_FENCE_VALIDATE \ -+ _IOW(KBASE_IOCTL_TYPE, 25, struct kbase_ioctl_fence_validate) -+ -+/** -+ * struct kbase_ioctl_get_profiling_controls - Get the profiling controls -+ * @count: The size of @buffer in u32 words -+ * @buffer: The buffer to receive the profiling controls -+ */ -+struct kbase_ioctl_get_profiling_controls { -+ __u64 buffer; -+ __u32 count; -+}; -+ -+#define KBASE_IOCTL_GET_PROFILING_CONTROLS \ -+ _IOW(KBASE_IOCTL_TYPE, 26, struct kbase_ioctl_get_profiling_controls) -+ -+/** -+ * struct kbase_ioctl_mem_profile_add - Provide profiling information to kernel -+ * @buffer: Pointer to the information -+ * @len: Length -+ * @padding: Padding -+ * -+ * The data provided is accessible through a debugfs file -+ */ -+struct kbase_ioctl_mem_profile_add { -+ __u64 buffer; -+ __u32 len; -+ __u32 padding; -+}; -+ -+#define KBASE_IOCTL_MEM_PROFILE_ADD \ -+ _IOW(KBASE_IOCTL_TYPE, 27, struct kbase_ioctl_mem_profile_add) -+ -+/** -+ * struct kbase_ioctl_soft_event_update - Update the status of a soft-event -+ * @event: GPU address of the event which has been updated -+ * @new_status: The new status to set -+ * @flags: Flags for future expansion -+ */ -+struct kbase_ioctl_soft_event_update { -+ __u64 event; -+ __u32 new_status; -+ __u32 flags; -+}; -+ -+#define KBASE_IOCTL_SOFT_EVENT_UPDATE \ -+ _IOW(KBASE_IOCTL_TYPE, 28, struct kbase_ioctl_soft_event_update) -+ -+/* IOCTLs 29-32 are reserved */ -+ -+/*************** -+ * test ioctls * -+ ***************/ -+#if MALI_UNIT_TEST -+/* These ioctls are purely for test purposes and are not used in the production -+ * driver, they therefore may change without notice -+ */ -+ -+#define KBASE_IOCTL_TEST_TYPE (KBASE_IOCTL_TYPE + 1) -+ -+/** -+ * struct kbase_ioctl_tlstream_test - Start a timeline stream test -+ * -+ * @tpw_count: number of trace point writers in each context -+ * @msg_delay: time delay between tracepoints from one writer in milliseconds -+ * @msg_count: number of trace points written by one writer -+ * @aux_msg: if non-zero aux messages will be included -+ */ -+struct kbase_ioctl_tlstream_test { -+ __u32 tpw_count; -+ __u32 msg_delay; -+ __u32 msg_count; -+ __u32 aux_msg; -+}; -+ -+#define KBASE_IOCTL_TLSTREAM_TEST \ -+ _IOW(KBASE_IOCTL_TEST_TYPE, 1, struct kbase_ioctl_tlstream_test) -+ -+/** -+ * struct kbase_ioctl_tlstream_stats - Read tlstream stats for test purposes -+ * @bytes_collected: number of bytes read by user -+ * @bytes_generated: number of bytes generated by tracepoints -+ */ -+struct kbase_ioctl_tlstream_stats { -+ __u32 bytes_collected; -+ __u32 bytes_generated; -+}; -+ -+#define KBASE_IOCTL_TLSTREAM_STATS \ -+ _IOR(KBASE_IOCTL_TEST_TYPE, 2, struct kbase_ioctl_tlstream_stats) -+ -+#endif -+ -+/********************************** -+ * Definitions for GPU properties * -+ **********************************/ -+#define KBASE_GPUPROP_VALUE_SIZE_U8 (0x0) -+#define KBASE_GPUPROP_VALUE_SIZE_U16 (0x1) -+#define KBASE_GPUPROP_VALUE_SIZE_U32 (0x2) -+#define KBASE_GPUPROP_VALUE_SIZE_U64 (0x3) -+ -+#define KBASE_GPUPROP_PRODUCT_ID 1 -+#define KBASE_GPUPROP_VERSION_STATUS 2 -+#define KBASE_GPUPROP_MINOR_REVISION 3 -+#define KBASE_GPUPROP_MAJOR_REVISION 4 -+#define KBASE_GPUPROP_GPU_SPEED_MHZ 5 -+#define KBASE_GPUPROP_GPU_FREQ_KHZ_MAX 6 -+#define KBASE_GPUPROP_GPU_FREQ_KHZ_MIN 7 -+#define KBASE_GPUPROP_LOG2_PROGRAM_COUNTER_SIZE 8 -+#define KBASE_GPUPROP_TEXTURE_FEATURES_0 9 -+#define KBASE_GPUPROP_TEXTURE_FEATURES_1 10 -+#define KBASE_GPUPROP_TEXTURE_FEATURES_2 11 -+#define KBASE_GPUPROP_GPU_AVAILABLE_MEMORY_SIZE 12 -+ -+#define KBASE_GPUPROP_L2_LOG2_LINE_SIZE 13 -+#define KBASE_GPUPROP_L2_LOG2_CACHE_SIZE 14 -+#define KBASE_GPUPROP_L2_NUM_L2_SLICES 15 -+ -+#define KBASE_GPUPROP_TILER_BIN_SIZE_BYTES 16 -+#define KBASE_GPUPROP_TILER_MAX_ACTIVE_LEVELS 17 -+ -+#define KBASE_GPUPROP_MAX_THREADS 18 -+#define KBASE_GPUPROP_MAX_WORKGROUP_SIZE 19 -+#define KBASE_GPUPROP_MAX_BARRIER_SIZE 20 -+#define KBASE_GPUPROP_MAX_REGISTERS 21 -+#define KBASE_GPUPROP_MAX_TASK_QUEUE 22 -+#define KBASE_GPUPROP_MAX_THREAD_GROUP_SPLIT 23 -+#define KBASE_GPUPROP_IMPL_TECH 24 -+ -+#define KBASE_GPUPROP_RAW_SHADER_PRESENT 25 -+#define KBASE_GPUPROP_RAW_TILER_PRESENT 26 -+#define KBASE_GPUPROP_RAW_L2_PRESENT 27 -+#define KBASE_GPUPROP_RAW_STACK_PRESENT 28 -+#define KBASE_GPUPROP_RAW_L2_FEATURES 29 -+#define KBASE_GPUPROP_RAW_SUSPEND_SIZE 30 -+#define KBASE_GPUPROP_RAW_MEM_FEATURES 31 -+#define KBASE_GPUPROP_RAW_MMU_FEATURES 32 -+#define KBASE_GPUPROP_RAW_AS_PRESENT 33 -+#define KBASE_GPUPROP_RAW_JS_PRESENT 34 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_0 35 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_1 36 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_2 37 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_3 38 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_4 39 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_5 40 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_6 41 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_7 42 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_8 43 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_9 44 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_10 45 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_11 46 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_12 47 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_13 48 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_14 49 -+#define KBASE_GPUPROP_RAW_JS_FEATURES_15 50 -+#define KBASE_GPUPROP_RAW_TILER_FEATURES 51 -+#define KBASE_GPUPROP_RAW_TEXTURE_FEATURES_0 52 -+#define KBASE_GPUPROP_RAW_TEXTURE_FEATURES_1 53 -+#define KBASE_GPUPROP_RAW_TEXTURE_FEATURES_2 54 -+#define KBASE_GPUPROP_RAW_GPU_ID 55 -+#define KBASE_GPUPROP_RAW_THREAD_MAX_THREADS 56 -+#define KBASE_GPUPROP_RAW_THREAD_MAX_WORKGROUP_SIZE 57 -+#define KBASE_GPUPROP_RAW_THREAD_MAX_BARRIER_SIZE 58 -+#define KBASE_GPUPROP_RAW_THREAD_FEATURES 59 -+#define KBASE_GPUPROP_RAW_COHERENCY_MODE 60 -+ -+#define KBASE_GPUPROP_COHERENCY_NUM_GROUPS 61 -+#define KBASE_GPUPROP_COHERENCY_NUM_CORE_GROUPS 62 -+#define KBASE_GPUPROP_COHERENCY_COHERENCY 63 -+#define KBASE_GPUPROP_COHERENCY_GROUP_0 64 -+#define KBASE_GPUPROP_COHERENCY_GROUP_1 65 -+#define KBASE_GPUPROP_COHERENCY_GROUP_2 66 -+#define KBASE_GPUPROP_COHERENCY_GROUP_3 67 -+#define KBASE_GPUPROP_COHERENCY_GROUP_4 68 -+#define KBASE_GPUPROP_COHERENCY_GROUP_5 69 -+#define KBASE_GPUPROP_COHERENCY_GROUP_6 70 -+#define KBASE_GPUPROP_COHERENCY_GROUP_7 71 -+#define KBASE_GPUPROP_COHERENCY_GROUP_8 72 -+#define KBASE_GPUPROP_COHERENCY_GROUP_9 73 -+#define KBASE_GPUPROP_COHERENCY_GROUP_10 74 -+#define KBASE_GPUPROP_COHERENCY_GROUP_11 75 -+#define KBASE_GPUPROP_COHERENCY_GROUP_12 76 -+#define KBASE_GPUPROP_COHERENCY_GROUP_13 77 -+#define KBASE_GPUPROP_COHERENCY_GROUP_14 78 -+#define KBASE_GPUPROP_COHERENCY_GROUP_15 79 -+ -+#ifdef __cpluscplus -+} -+#endif -+ -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_jd.c b/drivers/gpu/arm/midgard/mali_kbase_jd.c -new file mode 100644 -index 0000000..15ed061 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_jd.c -@@ -0,0 +1,1847 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#if defined(CONFIG_DMA_SHARED_BUFFER) -+#include -+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */ -+#ifdef CONFIG_COMPAT -+#include -+#endif -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "mali_kbase_dma_fence.h" -+ -+#define beenthere(kctx, f, a...) dev_dbg(kctx->kbdev->dev, "%s:" f, __func__, ##a) -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) -+/* random32 was renamed to prandom_u32 in 3.8 */ -+#define prandom_u32 random32 -+#endif -+ -+/* Return whether katom will run on the GPU or not. Currently only soft jobs and -+ * dependency-only atoms do not run on the GPU */ -+#define IS_GPU_ATOM(katom) (!((katom->core_req & BASE_JD_REQ_SOFT_JOB) || \ -+ ((katom->core_req & BASE_JD_REQ_ATOM_TYPE) == \ -+ BASE_JD_REQ_DEP))) -+/* -+ * This is the kernel side of the API. Only entry points are: -+ * - kbase_jd_submit(): Called from userspace to submit a single bag -+ * - kbase_jd_done(): Called from interrupt context to track the -+ * completion of a job. -+ * Callouts: -+ * - to the job manager (enqueue a job) -+ * - to the event subsystem (signals the completion/failure of bag/job-chains). -+ */ -+ -+static void __user * -+get_compat_pointer(struct kbase_context *kctx, const u64 p) -+{ -+#ifdef CONFIG_COMPAT -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ return compat_ptr(p); -+#endif -+ return u64_to_user_ptr(p); -+} -+ -+/* Runs an atom, either by handing to the JS or by immediately running it in the case of soft-jobs -+ * -+ * Returns whether the JS needs a reschedule. -+ * -+ * Note that the caller must also check the atom status and -+ * if it is KBASE_JD_ATOM_STATE_COMPLETED must call jd_done_nolock -+ */ -+static int jd_run_atom(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ -+ KBASE_DEBUG_ASSERT(katom->status != KBASE_JD_ATOM_STATE_UNUSED); -+ -+ if ((katom->core_req & BASE_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_DEP) { -+ /* Dependency only atom */ -+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED; -+ return 0; -+ } else if (katom->core_req & BASE_JD_REQ_SOFT_JOB) { -+ /* Soft-job */ -+ if (katom->will_fail_event_code) { -+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED; -+ return 0; -+ } -+ if ((katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) -+ == BASE_JD_REQ_SOFT_REPLAY) { -+ if (!kbase_replay_process(katom)) -+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED; -+ } else if (kbase_process_soft_job(katom) == 0) { -+ kbase_finish_soft_job(katom); -+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED; -+ } -+ return 0; -+ } -+ -+ katom->status = KBASE_JD_ATOM_STATE_IN_JS; -+ /* Queue an action about whether we should try scheduling a context */ -+ return kbasep_js_add_job(kctx, katom); -+} -+ -+#if defined(CONFIG_KDS) || defined(CONFIG_MALI_DMA_FENCE) -+void kbase_jd_dep_clear_locked(struct kbase_jd_atom *katom) -+{ -+ struct kbase_device *kbdev; -+ -+ KBASE_DEBUG_ASSERT(katom); -+ kbdev = katom->kctx->kbdev; -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ /* Check whether the atom's other dependencies were already met. If -+ * katom is a GPU atom then the job scheduler may be able to represent -+ * the dependencies, hence we may attempt to submit it before they are -+ * met. Other atoms must have had both dependencies resolved. -+ */ -+ if (IS_GPU_ATOM(katom) || -+ (!kbase_jd_katom_dep_atom(&katom->dep[0]) && -+ !kbase_jd_katom_dep_atom(&katom->dep[1]))) { -+ /* katom dep complete, attempt to run it */ -+ bool resched = false; -+ -+ resched = jd_run_atom(katom); -+ -+ if (katom->status == KBASE_JD_ATOM_STATE_COMPLETED) { -+ /* The atom has already finished */ -+ resched |= jd_done_nolock(katom, NULL); -+ } -+ -+ if (resched) -+ kbase_js_sched_all(kbdev); -+ } -+} -+#endif -+ -+#ifdef CONFIG_KDS -+ -+/* Add the katom to the kds waiting list. -+ * Atoms must be added to the waiting list after a successful call to kds_async_waitall. -+ * The caller must hold the kbase_jd_context.lock */ -+ -+static void kbase_jd_kds_waiters_add(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx; -+ -+ KBASE_DEBUG_ASSERT(katom); -+ -+ kctx = katom->kctx; -+ -+ list_add_tail(&katom->node, &kctx->waiting_kds_resource); -+} -+ -+/* Remove the katom from the kds waiting list. -+ * Atoms must be removed from the waiting list before a call to kds_resource_set_release_sync. -+ * The supplied katom must first have been added to the list with a call to kbase_jd_kds_waiters_add. -+ * The caller must hold the kbase_jd_context.lock */ -+ -+static void kbase_jd_kds_waiters_remove(struct kbase_jd_atom *katom) -+{ -+ KBASE_DEBUG_ASSERT(katom); -+ list_del(&katom->node); -+} -+ -+static void kds_dep_clear(void *callback_parameter, void *callback_extra_parameter) -+{ -+ struct kbase_jd_atom *katom; -+ struct kbase_jd_context *ctx; -+ -+ katom = (struct kbase_jd_atom *)callback_parameter; -+ KBASE_DEBUG_ASSERT(katom); -+ -+ ctx = &katom->kctx->jctx; -+ -+ /* If KDS resource has already been satisfied (e.g. due to zapping) -+ * do nothing. -+ */ -+ mutex_lock(&ctx->lock); -+ if (!katom->kds_dep_satisfied) { -+ katom->kds_dep_satisfied = true; -+ kbase_jd_dep_clear_locked(katom); -+ } -+ mutex_unlock(&ctx->lock); -+} -+ -+static void kbase_cancel_kds_wait_job(struct kbase_jd_atom *katom) -+{ -+ KBASE_DEBUG_ASSERT(katom); -+ -+ /* Prevent job_done_nolock from being called twice on an atom when -+ * there is a race between job completion and cancellation */ -+ -+ if (katom->status == KBASE_JD_ATOM_STATE_QUEUED) { -+ /* Wait was cancelled - zap the atom */ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ if (jd_done_nolock(katom, NULL)) -+ kbase_js_sched_all(katom->kctx->kbdev); -+ } -+} -+#endif /* CONFIG_KDS */ -+ -+void kbase_jd_free_external_resources(struct kbase_jd_atom *katom) -+{ -+#ifdef CONFIG_KDS -+ if (katom->kds_rset) { -+ struct kbase_jd_context *jctx = &katom->kctx->jctx; -+ -+ /* -+ * As the atom is no longer waiting, remove it from -+ * the waiting list. -+ */ -+ -+ mutex_lock(&jctx->lock); -+ kbase_jd_kds_waiters_remove(katom); -+ mutex_unlock(&jctx->lock); -+ -+ /* Release the kds resource or cancel if zapping */ -+ kds_resource_set_release_sync(&katom->kds_rset); -+ } -+#endif /* CONFIG_KDS */ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ /* Flush dma-fence workqueue to ensure that any callbacks that may have -+ * been queued are done before continuing. -+ * Any successfully completed atom would have had all it's callbacks -+ * completed before the atom was run, so only flush for failed atoms. -+ */ -+ if (katom->event_code != BASE_JD_EVENT_DONE) -+ flush_workqueue(katom->kctx->dma_fence.wq); -+#endif /* CONFIG_MALI_DMA_FENCE */ -+} -+ -+static void kbase_jd_post_external_resources(struct kbase_jd_atom *katom) -+{ -+ KBASE_DEBUG_ASSERT(katom); -+ KBASE_DEBUG_ASSERT(katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES); -+ -+#ifdef CONFIG_KDS -+ /* Prevent the KDS resource from triggering the atom in case of zapping */ -+ if (katom->kds_rset) -+ katom->kds_dep_satisfied = true; -+#endif /* CONFIG_KDS */ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ kbase_dma_fence_signal(katom); -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ -+ kbase_gpu_vm_lock(katom->kctx); -+ /* only roll back if extres is non-NULL */ -+ if (katom->extres) { -+ u32 res_no; -+ -+ res_no = katom->nr_extres; -+ while (res_no-- > 0) { -+ struct kbase_mem_phy_alloc *alloc = katom->extres[res_no].alloc; -+ struct kbase_va_region *reg; -+ -+ reg = kbase_region_tracker_find_region_base_address( -+ katom->kctx, -+ katom->extres[res_no].gpu_address); -+ kbase_unmap_external_resource(katom->kctx, reg, alloc); -+ } -+ kfree(katom->extres); -+ katom->extres = NULL; -+ } -+ kbase_gpu_vm_unlock(katom->kctx); -+} -+ -+/* -+ * Set up external resources needed by this job. -+ * -+ * jctx.lock must be held when this is called. -+ */ -+ -+static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const struct base_jd_atom_v2 *user_atom) -+{ -+ int err_ret_val = -EINVAL; -+ u32 res_no; -+#ifdef CONFIG_KDS -+ u32 kds_res_count = 0; -+ struct kds_resource **kds_resources = NULL; -+ unsigned long *kds_access_bitmap = NULL; -+#endif /* CONFIG_KDS */ -+#ifdef CONFIG_MALI_DMA_FENCE -+ struct kbase_dma_fence_resv_info info = { -+ .dma_fence_resv_count = 0, -+ }; -+#ifdef CONFIG_SYNC -+ /* -+ * When both dma-buf fence and Android native sync is enabled, we -+ * disable dma-buf fence for contexts that are using Android native -+ * fences. -+ */ -+ const bool implicit_sync = !kbase_ctx_flag(katom->kctx, -+ KCTX_NO_IMPLICIT_SYNC); -+#else /* CONFIG_SYNC */ -+ const bool implicit_sync = true; -+#endif /* CONFIG_SYNC */ -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ struct base_external_resource *input_extres; -+ -+ KBASE_DEBUG_ASSERT(katom); -+ KBASE_DEBUG_ASSERT(katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES); -+ -+ /* no resources encoded, early out */ -+ if (!katom->nr_extres) -+ return -EINVAL; -+ -+ katom->extres = kmalloc_array(katom->nr_extres, sizeof(*katom->extres), GFP_KERNEL); -+ if (NULL == katom->extres) { -+ err_ret_val = -ENOMEM; -+ goto early_err_out; -+ } -+ -+ /* copy user buffer to the end of our real buffer. -+ * Make sure the struct sizes haven't changed in a way -+ * we don't support */ -+ BUILD_BUG_ON(sizeof(*input_extres) > sizeof(*katom->extres)); -+ input_extres = (struct base_external_resource *) -+ (((unsigned char *)katom->extres) + -+ (sizeof(*katom->extres) - sizeof(*input_extres)) * -+ katom->nr_extres); -+ -+ if (copy_from_user(input_extres, -+ get_compat_pointer(katom->kctx, user_atom->extres_list), -+ sizeof(*input_extres) * katom->nr_extres) != 0) { -+ err_ret_val = -EINVAL; -+ goto early_err_out; -+ } -+#ifdef CONFIG_KDS -+ /* assume we have to wait for all */ -+ KBASE_DEBUG_ASSERT(0 != katom->nr_extres); -+ kds_resources = kmalloc_array(katom->nr_extres, sizeof(struct kds_resource *), GFP_KERNEL); -+ -+ if (!kds_resources) { -+ err_ret_val = -ENOMEM; -+ goto early_err_out; -+ } -+ -+ KBASE_DEBUG_ASSERT(0 != katom->nr_extres); -+ kds_access_bitmap = kcalloc(BITS_TO_LONGS(katom->nr_extres), -+ sizeof(unsigned long), -+ GFP_KERNEL); -+ if (!kds_access_bitmap) { -+ err_ret_val = -ENOMEM; -+ goto early_err_out; -+ } -+#endif /* CONFIG_KDS */ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ if (implicit_sync) { -+ info.resv_objs = kmalloc_array(katom->nr_extres, -+ sizeof(struct reservation_object *), -+ GFP_KERNEL); -+ if (!info.resv_objs) { -+ err_ret_val = -ENOMEM; -+ goto early_err_out; -+ } -+ -+ info.dma_fence_excl_bitmap = -+ kcalloc(BITS_TO_LONGS(katom->nr_extres), -+ sizeof(unsigned long), GFP_KERNEL); -+ if (!info.dma_fence_excl_bitmap) { -+ err_ret_val = -ENOMEM; -+ goto early_err_out; -+ } -+ } -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ -+ /* Take the processes mmap lock */ -+ down_read(¤t->mm->mmap_sem); -+ -+ /* need to keep the GPU VM locked while we set up UMM buffers */ -+ kbase_gpu_vm_lock(katom->kctx); -+ for (res_no = 0; res_no < katom->nr_extres; res_no++) { -+ struct base_external_resource *res; -+ struct kbase_va_region *reg; -+ struct kbase_mem_phy_alloc *alloc; -+ bool exclusive; -+ -+ res = &input_extres[res_no]; -+ exclusive = (res->ext_resource & BASE_EXT_RES_ACCESS_EXCLUSIVE) -+ ? true : false; -+ reg = kbase_region_tracker_find_region_enclosing_address( -+ katom->kctx, -+ res->ext_resource & ~BASE_EXT_RES_ACCESS_EXCLUSIVE); -+ /* did we find a matching region object? */ -+ if (NULL == reg || (reg->flags & KBASE_REG_FREE)) { -+ /* roll back */ -+ goto failed_loop; -+ } -+ -+ if (!(katom->core_req & BASE_JD_REQ_SOFT_JOB) && -+ (reg->flags & KBASE_REG_SECURE)) { -+ katom->atom_flags |= KBASE_KATOM_FLAG_PROTECTED; -+ } -+ -+ alloc = kbase_map_external_resource(katom->kctx, reg, -+ current->mm -+#ifdef CONFIG_KDS -+ , &kds_res_count, kds_resources, -+ kds_access_bitmap, exclusive -+#endif -+ ); -+ if (!alloc) { -+ err_ret_val = -EINVAL; -+ goto failed_loop; -+ } -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ if (implicit_sync && -+ reg->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM) { -+ struct reservation_object *resv; -+ -+ resv = reg->gpu_alloc->imported.umm.dma_buf->resv; -+ if (resv) -+ kbase_dma_fence_add_reservation(resv, &info, -+ exclusive); -+ } -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ -+ /* finish with updating out array with the data we found */ -+ /* NOTE: It is important that this is the last thing we do (or -+ * at least not before the first write) as we overwrite elements -+ * as we loop and could be overwriting ourself, so no writes -+ * until the last read for an element. -+ * */ -+ katom->extres[res_no].gpu_address = reg->start_pfn << PAGE_SHIFT; /* save the start_pfn (as an address, not pfn) to use fast lookup later */ -+ katom->extres[res_no].alloc = alloc; -+ } -+ /* successfully parsed the extres array */ -+ /* drop the vm lock before we call into kds */ -+ kbase_gpu_vm_unlock(katom->kctx); -+ -+ /* Release the processes mmap lock */ -+ up_read(¤t->mm->mmap_sem); -+ -+#ifdef CONFIG_KDS -+ if (kds_res_count) { -+ int wait_failed; -+ -+ /* We have resources to wait for with kds */ -+ katom->kds_dep_satisfied = false; -+ -+ wait_failed = kds_async_waitall(&katom->kds_rset, -+ &katom->kctx->jctx.kds_cb, katom, NULL, -+ kds_res_count, kds_access_bitmap, -+ kds_resources); -+ -+ if (wait_failed) -+ goto failed_kds_setup; -+ else -+ kbase_jd_kds_waiters_add(katom); -+ } else { -+ /* Nothing to wait for, so kds dep met */ -+ katom->kds_dep_satisfied = true; -+ } -+ kfree(kds_resources); -+ kfree(kds_access_bitmap); -+#endif /* CONFIG_KDS */ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ if (implicit_sync) { -+ if (info.dma_fence_resv_count) { -+ int ret; -+ -+ ret = kbase_dma_fence_wait(katom, &info); -+ if (ret < 0) -+ goto failed_dma_fence_setup; -+ } -+ -+ kfree(info.resv_objs); -+ kfree(info.dma_fence_excl_bitmap); -+ } -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ -+ /* all done OK */ -+ return 0; -+ -+/* error handling section */ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+failed_dma_fence_setup: -+#ifdef CONFIG_KDS -+ /* If we are here, dma_fence setup failed but KDS didn't. -+ * Revert KDS setup if any. -+ */ -+ if (kds_res_count) { -+ mutex_unlock(&katom->kctx->jctx.lock); -+ kds_resource_set_release_sync(&katom->kds_rset); -+ mutex_lock(&katom->kctx->jctx.lock); -+ -+ kbase_jd_kds_waiters_remove(katom); -+ katom->kds_dep_satisfied = true; -+ } -+#endif /* CONFIG_KDS */ -+#endif /* CONFIG_MALI_DMA_FENCE */ -+#ifdef CONFIG_KDS -+failed_kds_setup: -+#endif -+#if defined(CONFIG_KDS) || defined(CONFIG_MALI_DMA_FENCE) -+ /* Lock the processes mmap lock */ -+ down_read(¤t->mm->mmap_sem); -+ -+ /* lock before we unmap */ -+ kbase_gpu_vm_lock(katom->kctx); -+#endif -+ -+ failed_loop: -+ /* undo the loop work */ -+ while (res_no-- > 0) { -+ struct kbase_mem_phy_alloc *alloc = katom->extres[res_no].alloc; -+ -+ kbase_unmap_external_resource(katom->kctx, NULL, alloc); -+ } -+ kbase_gpu_vm_unlock(katom->kctx); -+ -+ /* Release the processes mmap lock */ -+ up_read(¤t->mm->mmap_sem); -+ -+ early_err_out: -+ kfree(katom->extres); -+ katom->extres = NULL; -+#ifdef CONFIG_KDS -+ kfree(kds_resources); -+ kfree(kds_access_bitmap); -+#endif /* CONFIG_KDS */ -+#ifdef CONFIG_MALI_DMA_FENCE -+ if (implicit_sync) { -+ kfree(info.resv_objs); -+ kfree(info.dma_fence_excl_bitmap); -+ } -+#endif -+ return err_ret_val; -+} -+ -+static inline void jd_resolve_dep(struct list_head *out_list, -+ struct kbase_jd_atom *katom, -+ u8 d, bool ctx_is_dying) -+{ -+ u8 other_d = !d; -+ -+ while (!list_empty(&katom->dep_head[d])) { -+ struct kbase_jd_atom *dep_atom; -+ struct kbase_jd_atom *other_dep_atom; -+ u8 dep_type; -+ -+ dep_atom = list_entry(katom->dep_head[d].next, -+ struct kbase_jd_atom, dep_item[d]); -+ list_del(katom->dep_head[d].next); -+ -+ dep_type = kbase_jd_katom_dep_type(&dep_atom->dep[d]); -+ kbase_jd_katom_dep_clear(&dep_atom->dep[d]); -+ -+ if (katom->event_code != BASE_JD_EVENT_DONE && -+ (dep_type != BASE_JD_DEP_TYPE_ORDER)) { -+#ifdef CONFIG_KDS -+ if (!dep_atom->kds_dep_satisfied) { -+ /* Just set kds_dep_satisfied to true. If the callback happens after this then it will early out and -+ * do nothing. If the callback doesn't happen then kbase_jd_post_external_resources will clean up -+ */ -+ dep_atom->kds_dep_satisfied = true; -+ } -+#endif -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ kbase_dma_fence_cancel_callbacks(dep_atom); -+#endif -+ -+ dep_atom->event_code = katom->event_code; -+ KBASE_DEBUG_ASSERT(dep_atom->status != -+ KBASE_JD_ATOM_STATE_UNUSED); -+ -+ if ((dep_atom->core_req & BASE_JD_REQ_SOFT_REPLAY) -+ != BASE_JD_REQ_SOFT_REPLAY) { -+ dep_atom->will_fail_event_code = -+ dep_atom->event_code; -+ } else { -+ dep_atom->status = -+ KBASE_JD_ATOM_STATE_COMPLETED; -+ } -+ } -+ other_dep_atom = (struct kbase_jd_atom *) -+ kbase_jd_katom_dep_atom(&dep_atom->dep[other_d]); -+ -+ if (!dep_atom->in_jd_list && (!other_dep_atom || -+ (IS_GPU_ATOM(dep_atom) && !ctx_is_dying && -+ !dep_atom->will_fail_event_code && -+ !other_dep_atom->will_fail_event_code))) { -+ bool dep_satisfied = true; -+#ifdef CONFIG_MALI_DMA_FENCE -+ int dep_count; -+ -+ dep_count = kbase_fence_dep_count_read(dep_atom); -+ if (likely(dep_count == -1)) { -+ dep_satisfied = true; -+ } else { -+ /* -+ * There are either still active callbacks, or -+ * all fences for this @dep_atom has signaled, -+ * but the worker that will queue the atom has -+ * not yet run. -+ * -+ * Wait for the fences to signal and the fence -+ * worker to run and handle @dep_atom. If -+ * @dep_atom was completed due to error on -+ * @katom, then the fence worker will pick up -+ * the complete status and error code set on -+ * @dep_atom above. -+ */ -+ dep_satisfied = false; -+ } -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ -+#ifdef CONFIG_KDS -+ dep_satisfied = dep_satisfied && dep_atom->kds_dep_satisfied; -+#endif -+ -+ if (dep_satisfied) { -+ dep_atom->in_jd_list = true; -+ list_add_tail(&dep_atom->jd_item, out_list); -+ } -+ } -+ } -+} -+ -+KBASE_EXPORT_TEST_API(jd_resolve_dep); -+ -+#if MALI_CUSTOMER_RELEASE == 0 -+static void jd_force_failure(struct kbase_device *kbdev, struct kbase_jd_atom *katom) -+{ -+ kbdev->force_replay_count++; -+ -+ if (kbdev->force_replay_count >= kbdev->force_replay_limit) { -+ kbdev->force_replay_count = 0; -+ katom->event_code = BASE_JD_EVENT_FORCE_REPLAY; -+ -+ if (kbdev->force_replay_random) -+ kbdev->force_replay_limit = -+ (prandom_u32() % KBASEP_FORCE_REPLAY_RANDOM_LIMIT) + 1; -+ -+ dev_info(kbdev->dev, "force_replay : promoting to error\n"); -+ } -+} -+ -+/** Test to see if atom should be forced to fail. -+ * -+ * This function will check if an atom has a replay job as a dependent. If so -+ * then it will be considered for forced failure. */ -+static void jd_check_force_failure(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ struct kbase_device *kbdev = kctx->kbdev; -+ int i; -+ -+ if ((kbdev->force_replay_limit == KBASEP_FORCE_REPLAY_DISABLED) || -+ (katom->core_req & BASEP_JD_REQ_EVENT_NEVER)) -+ return; -+ -+ for (i = 1; i < BASE_JD_ATOM_COUNT; i++) { -+ if (kbase_jd_katom_dep_atom(&kctx->jctx.atoms[i].dep[0]) == katom || -+ kbase_jd_katom_dep_atom(&kctx->jctx.atoms[i].dep[1]) == katom) { -+ struct kbase_jd_atom *dep_atom = &kctx->jctx.atoms[i]; -+ -+ if ((dep_atom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) == -+ BASE_JD_REQ_SOFT_REPLAY && -+ (dep_atom->core_req & kbdev->force_replay_core_req) -+ == kbdev->force_replay_core_req) { -+ jd_force_failure(kbdev, katom); -+ return; -+ } -+ } -+ } -+} -+#endif -+ -+/** -+ * is_dep_valid - Validate that a dependency is valid for early dependency -+ * submission -+ * @katom: Dependency atom to validate -+ * -+ * A dependency is valid if any of the following are true : -+ * - It does not exist (a non-existent dependency does not block submission) -+ * - It is in the job scheduler -+ * - It has completed, does not have a failure event code, and has not been -+ * marked to fail in the future -+ * -+ * Return: true if valid, false otherwise -+ */ -+static bool is_dep_valid(struct kbase_jd_atom *katom) -+{ -+ /* If there's no dependency then this is 'valid' from the perspective of -+ * early dependency submission */ -+ if (!katom) -+ return true; -+ -+ /* Dependency must have reached the job scheduler */ -+ if (katom->status < KBASE_JD_ATOM_STATE_IN_JS) -+ return false; -+ -+ /* If dependency has completed and has failed or will fail then it is -+ * not valid */ -+ if (katom->status >= KBASE_JD_ATOM_STATE_HW_COMPLETED && -+ (katom->event_code != BASE_JD_EVENT_DONE || -+ katom->will_fail_event_code)) -+ return false; -+ -+ return true; -+} -+ -+static void jd_try_submitting_deps(struct list_head *out_list, -+ struct kbase_jd_atom *node) -+{ -+ int i; -+ -+ for (i = 0; i < 2; i++) { -+ struct list_head *pos; -+ -+ list_for_each(pos, &node->dep_head[i]) { -+ struct kbase_jd_atom *dep_atom = list_entry(pos, -+ struct kbase_jd_atom, dep_item[i]); -+ -+ if (IS_GPU_ATOM(dep_atom) && !dep_atom->in_jd_list) { -+ /*Check if atom deps look sane*/ -+ bool dep0_valid = is_dep_valid( -+ dep_atom->dep[0].atom); -+ bool dep1_valid = is_dep_valid( -+ dep_atom->dep[1].atom); -+ bool dep_satisfied = true; -+#ifdef CONFIG_MALI_DMA_FENCE -+ int dep_count; -+ -+ dep_count = kbase_fence_dep_count_read( -+ dep_atom); -+ if (likely(dep_count == -1)) { -+ dep_satisfied = true; -+ } else { -+ /* -+ * There are either still active callbacks, or -+ * all fences for this @dep_atom has signaled, -+ * but the worker that will queue the atom has -+ * not yet run. -+ * -+ * Wait for the fences to signal and the fence -+ * worker to run and handle @dep_atom. If -+ * @dep_atom was completed due to error on -+ * @katom, then the fence worker will pick up -+ * the complete status and error code set on -+ * @dep_atom above. -+ */ -+ dep_satisfied = false; -+ } -+#endif /* CONFIG_MALI_DMA_FENCE */ -+#ifdef CONFIG_KDS -+ dep_satisfied = dep_satisfied && -+ dep_atom->kds_dep_satisfied; -+#endif -+ -+ if (dep0_valid && dep1_valid && dep_satisfied) { -+ dep_atom->in_jd_list = true; -+ list_add(&dep_atom->jd_item, out_list); -+ } -+ } -+ } -+ } -+} -+ -+/* -+ * Perform the necessary handling of an atom that has finished running -+ * on the GPU. -+ * -+ * Note that if this is a soft-job that has had kbase_prepare_soft_job called on it then the caller -+ * is responsible for calling kbase_finish_soft_job *before* calling this function. -+ * -+ * The caller must hold the kbase_jd_context.lock. -+ */ -+bool jd_done_nolock(struct kbase_jd_atom *katom, -+ struct list_head *completed_jobs_ctx) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ struct kbase_device *kbdev = kctx->kbdev; -+ struct list_head completed_jobs; -+ struct list_head runnable_jobs; -+ bool need_to_try_schedule_context = false; -+ int i; -+ -+ INIT_LIST_HEAD(&completed_jobs); -+ INIT_LIST_HEAD(&runnable_jobs); -+ -+ KBASE_DEBUG_ASSERT(katom->status != KBASE_JD_ATOM_STATE_UNUSED); -+ -+#if MALI_CUSTOMER_RELEASE == 0 -+ jd_check_force_failure(katom); -+#endif -+ -+ /* This is needed in case an atom is failed due to being invalid, this -+ * can happen *before* the jobs that the atom depends on have completed */ -+ for (i = 0; i < 2; i++) { -+ if (kbase_jd_katom_dep_atom(&katom->dep[i])) { -+ list_del(&katom->dep_item[i]); -+ kbase_jd_katom_dep_clear(&katom->dep[i]); -+ } -+ } -+ -+ /* With PRLAM-10817 or PRLAM-10959 the last tile of a fragment job being soft-stopped can fail with -+ * BASE_JD_EVENT_TILE_RANGE_FAULT. -+ * -+ * So here if the fragment job failed with TILE_RANGE_FAULT and it has been soft-stopped, then we promote the -+ * error code to BASE_JD_EVENT_DONE -+ */ -+ -+ if ((kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10817) || kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10959)) && -+ katom->event_code == BASE_JD_EVENT_TILE_RANGE_FAULT) { -+ if ((katom->core_req & BASE_JD_REQ_FS) && (katom->atom_flags & KBASE_KATOM_FLAG_BEEN_SOFT_STOPPPED)) { -+ /* Promote the failure to job done */ -+ katom->event_code = BASE_JD_EVENT_DONE; -+ katom->atom_flags = katom->atom_flags & (~KBASE_KATOM_FLAG_BEEN_SOFT_STOPPPED); -+ } -+ } -+ -+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED; -+ list_add_tail(&katom->jd_item, &completed_jobs); -+ -+ while (!list_empty(&completed_jobs)) { -+ katom = list_entry(completed_jobs.prev, struct kbase_jd_atom, jd_item); -+ list_del(completed_jobs.prev); -+ KBASE_DEBUG_ASSERT(katom->status == KBASE_JD_ATOM_STATE_COMPLETED); -+ -+ for (i = 0; i < 2; i++) -+ jd_resolve_dep(&runnable_jobs, katom, i, -+ kbase_ctx_flag(kctx, KCTX_DYING)); -+ -+ if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) -+ kbase_jd_post_external_resources(katom); -+ -+ while (!list_empty(&runnable_jobs)) { -+ struct kbase_jd_atom *node; -+ -+ node = list_entry(runnable_jobs.next, -+ struct kbase_jd_atom, jd_item); -+ list_del(runnable_jobs.next); -+ node->in_jd_list = false; -+ -+ KBASE_DEBUG_ASSERT(node->status != KBASE_JD_ATOM_STATE_UNUSED); -+ -+ if (node->status != KBASE_JD_ATOM_STATE_COMPLETED && -+ !kbase_ctx_flag(kctx, KCTX_DYING)) { -+ need_to_try_schedule_context |= jd_run_atom(node); -+ } else { -+ node->event_code = katom->event_code; -+ -+ if ((node->core_req & -+ BASE_JD_REQ_SOFT_JOB_TYPE) == -+ BASE_JD_REQ_SOFT_REPLAY) { -+ if (kbase_replay_process(node)) -+ /* Don't complete this atom */ -+ continue; -+ } else if (node->core_req & -+ BASE_JD_REQ_SOFT_JOB) { -+ /* If this is a fence wait soft job -+ * then remove it from the list of sync -+ * waiters. -+ */ -+ if (BASE_JD_REQ_SOFT_FENCE_WAIT == node->core_req) -+ kbasep_remove_waiting_soft_job(node); -+ -+ kbase_finish_soft_job(node); -+ } -+ node->status = KBASE_JD_ATOM_STATE_COMPLETED; -+ } -+ -+ if (node->status == KBASE_JD_ATOM_STATE_COMPLETED) { -+ list_add_tail(&node->jd_item, &completed_jobs); -+ } else if (node->status == KBASE_JD_ATOM_STATE_IN_JS && -+ !node->will_fail_event_code) { -+ /* Node successfully submitted, try submitting -+ * dependencies as they may now be representable -+ * in JS */ -+ jd_try_submitting_deps(&runnable_jobs, node); -+ } -+ } -+ -+ /* Register a completed job as a disjoint event when the GPU -+ * is in a disjoint state (ie. being reset or replaying jobs). -+ */ -+ kbase_disjoint_event_potential(kctx->kbdev); -+ if (completed_jobs_ctx) -+ list_add_tail(&katom->jd_item, completed_jobs_ctx); -+ else -+ kbase_event_post(kctx, katom); -+ -+ /* Decrement and check the TOTAL number of jobs. This includes -+ * those not tracked by the scheduler: 'not ready to run' and -+ * 'dependency-only' jobs. */ -+ if (--kctx->jctx.job_nr == 0) -+ wake_up(&kctx->jctx.zero_jobs_wait); /* All events are safely queued now, and we can signal any waiter -+ * that we've got no more jobs (so we can be safely terminated) */ -+ } -+ -+ return need_to_try_schedule_context; -+} -+ -+KBASE_EXPORT_TEST_API(jd_done_nolock); -+ -+#ifdef CONFIG_GPU_TRACEPOINTS -+enum { -+ CORE_REQ_DEP_ONLY, -+ CORE_REQ_SOFT, -+ CORE_REQ_COMPUTE, -+ CORE_REQ_FRAGMENT, -+ CORE_REQ_VERTEX, -+ CORE_REQ_TILER, -+ CORE_REQ_FRAGMENT_VERTEX, -+ CORE_REQ_FRAGMENT_VERTEX_TILER, -+ CORE_REQ_FRAGMENT_TILER, -+ CORE_REQ_VERTEX_TILER, -+ CORE_REQ_UNKNOWN -+}; -+static const char * const core_req_strings[] = { -+ "Dependency Only Job", -+ "Soft Job", -+ "Compute Shader Job", -+ "Fragment Shader Job", -+ "Vertex/Geometry Shader Job", -+ "Tiler Job", -+ "Fragment Shader + Vertex/Geometry Shader Job", -+ "Fragment Shader + Vertex/Geometry Shader Job + Tiler Job", -+ "Fragment Shader + Tiler Job", -+ "Vertex/Geometry Shader Job + Tiler Job", -+ "Unknown Job" -+}; -+static const char *kbasep_map_core_reqs_to_string(base_jd_core_req core_req) -+{ -+ if (core_req & BASE_JD_REQ_SOFT_JOB) -+ return core_req_strings[CORE_REQ_SOFT]; -+ if (core_req & BASE_JD_REQ_ONLY_COMPUTE) -+ return core_req_strings[CORE_REQ_COMPUTE]; -+ switch (core_req & (BASE_JD_REQ_FS | BASE_JD_REQ_CS | BASE_JD_REQ_T)) { -+ case BASE_JD_REQ_DEP: -+ return core_req_strings[CORE_REQ_DEP_ONLY]; -+ case BASE_JD_REQ_FS: -+ return core_req_strings[CORE_REQ_FRAGMENT]; -+ case BASE_JD_REQ_CS: -+ return core_req_strings[CORE_REQ_VERTEX]; -+ case BASE_JD_REQ_T: -+ return core_req_strings[CORE_REQ_TILER]; -+ case (BASE_JD_REQ_FS | BASE_JD_REQ_CS): -+ return core_req_strings[CORE_REQ_FRAGMENT_VERTEX]; -+ case (BASE_JD_REQ_FS | BASE_JD_REQ_T): -+ return core_req_strings[CORE_REQ_FRAGMENT_TILER]; -+ case (BASE_JD_REQ_CS | BASE_JD_REQ_T): -+ return core_req_strings[CORE_REQ_VERTEX_TILER]; -+ case (BASE_JD_REQ_FS | BASE_JD_REQ_CS | BASE_JD_REQ_T): -+ return core_req_strings[CORE_REQ_FRAGMENT_VERTEX_TILER]; -+ } -+ return core_req_strings[CORE_REQ_UNKNOWN]; -+} -+#endif -+ -+bool jd_submit_atom(struct kbase_context *kctx, const struct base_jd_atom_v2 *user_atom, struct kbase_jd_atom *katom) -+{ -+ struct kbase_jd_context *jctx = &kctx->jctx; -+ int queued = 0; -+ int i; -+ int sched_prio; -+ bool ret; -+ bool will_fail = false; -+ -+ /* Update the TOTAL number of jobs. This includes those not tracked by -+ * the scheduler: 'not ready to run' and 'dependency-only' jobs. */ -+ jctx->job_nr++; -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) -+ katom->start_timestamp.tv64 = 0; -+#else -+ katom->start_timestamp = 0; -+#endif -+ katom->udata = user_atom->udata; -+ katom->kctx = kctx; -+ katom->nr_extres = user_atom->nr_extres; -+ katom->extres = NULL; -+ katom->device_nr = user_atom->device_nr; -+ katom->affinity = 0; -+ katom->jc = user_atom->jc; -+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED; -+ katom->core_req = user_atom->core_req; -+ katom->atom_flags = 0; -+ katom->retry_count = 0; -+ katom->need_cache_flush_cores_retained = 0; -+ katom->pre_dep = NULL; -+ katom->post_dep = NULL; -+ katom->x_pre_dep = NULL; -+ katom->x_post_dep = NULL; -+ katom->will_fail_event_code = BASE_JD_EVENT_NOT_STARTED; -+ -+ /* Implicitly sets katom->protected_state.enter as well. */ -+ katom->protected_state.exit = KBASE_ATOM_EXIT_PROTECTED_CHECK; -+ -+ katom->age = kctx->age_count++; -+ -+ INIT_LIST_HEAD(&katom->jd_item); -+#ifdef CONFIG_KDS -+ /* Start by assuming that the KDS dependencies are satisfied, -+ * kbase_jd_pre_external_resources will correct this if there are dependencies */ -+ katom->kds_dep_satisfied = true; -+ katom->kds_rset = NULL; -+#endif /* CONFIG_KDS */ -+#ifdef CONFIG_MALI_DMA_FENCE -+ kbase_fence_dep_count_set(katom, -1); -+#endif -+ -+ /* Don't do anything if there is a mess up with dependencies. -+ This is done in a separate cycle to check both the dependencies at ones, otherwise -+ it will be extra complexity to deal with 1st dependency ( just added to the list ) -+ if only the 2nd one has invalid config. -+ */ -+ for (i = 0; i < 2; i++) { -+ int dep_atom_number = user_atom->pre_dep[i].atom_id; -+ base_jd_dep_type dep_atom_type = user_atom->pre_dep[i].dependency_type; -+ -+ if (dep_atom_number) { -+ if (dep_atom_type != BASE_JD_DEP_TYPE_ORDER && -+ dep_atom_type != BASE_JD_DEP_TYPE_DATA) { -+ katom->event_code = BASE_JD_EVENT_JOB_CONFIG_FAULT; -+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED; -+ -+ /* Wrong dependency setup. Atom will be sent -+ * back to user space. Do not record any -+ * dependencies. */ -+ KBASE_TLSTREAM_TL_NEW_ATOM( -+ katom, -+ kbase_jd_atom_id(kctx, katom)); -+ KBASE_TLSTREAM_TL_RET_ATOM_CTX( -+ katom, kctx); -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(katom, -+ TL_ATOM_STATE_IDLE); -+ -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ } -+ } -+ -+ /* Add dependencies */ -+ for (i = 0; i < 2; i++) { -+ int dep_atom_number = user_atom->pre_dep[i].atom_id; -+ base_jd_dep_type dep_atom_type; -+ struct kbase_jd_atom *dep_atom = &jctx->atoms[dep_atom_number]; -+ -+ dep_atom_type = user_atom->pre_dep[i].dependency_type; -+ kbase_jd_katom_dep_clear(&katom->dep[i]); -+ -+ if (!dep_atom_number) -+ continue; -+ -+ if (dep_atom->status == KBASE_JD_ATOM_STATE_UNUSED || -+ dep_atom->status == KBASE_JD_ATOM_STATE_COMPLETED) { -+ -+ if (dep_atom->event_code == BASE_JD_EVENT_DONE) -+ continue; -+ /* don't stop this atom if it has an order dependency -+ * only to the failed one, try to submit it through -+ * the normal path -+ */ -+ if (dep_atom_type == BASE_JD_DEP_TYPE_ORDER && -+ dep_atom->event_code > BASE_JD_EVENT_ACTIVE) { -+ continue; -+ } -+ -+ /* Atom has completed, propagate the error code if any */ -+ katom->event_code = dep_atom->event_code; -+ katom->status = KBASE_JD_ATOM_STATE_QUEUED; -+ -+ /* This atom is going through soft replay or -+ * will be sent back to user space. Do not record any -+ * dependencies. */ -+ KBASE_TLSTREAM_TL_NEW_ATOM( -+ katom, -+ kbase_jd_atom_id(kctx, katom)); -+ KBASE_TLSTREAM_TL_RET_ATOM_CTX(katom, kctx); -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(katom, -+ TL_ATOM_STATE_IDLE); -+ -+ if ((katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) -+ == BASE_JD_REQ_SOFT_REPLAY) { -+ if (kbase_replay_process(katom)) { -+ ret = false; -+ goto out; -+ } -+ } -+ will_fail = true; -+ -+ } else { -+ /* Atom is in progress, add this atom to the list */ -+ list_add_tail(&katom->dep_item[i], &dep_atom->dep_head[i]); -+ kbase_jd_katom_dep_set(&katom->dep[i], dep_atom, dep_atom_type); -+ queued = 1; -+ } -+ } -+ -+ if (will_fail) { -+ if (!queued) { -+ ret = jd_done_nolock(katom, NULL); -+ -+ goto out; -+ } else { -+ katom->will_fail_event_code = katom->event_code; -+ ret = false; -+ -+ goto out; -+ } -+ } else { -+ /* These must occur after the above loop to ensure that an atom -+ * that depends on a previous atom with the same number behaves -+ * as expected */ -+ katom->event_code = BASE_JD_EVENT_DONE; -+ katom->status = KBASE_JD_ATOM_STATE_QUEUED; -+ } -+ -+ /* For invalid priority, be most lenient and choose the default */ -+ sched_prio = kbasep_js_atom_prio_to_sched_prio(user_atom->prio); -+ if (sched_prio == KBASE_JS_ATOM_SCHED_PRIO_INVALID) -+ sched_prio = KBASE_JS_ATOM_SCHED_PRIO_DEFAULT; -+ katom->sched_priority = sched_prio; -+ -+ /* Create a new atom recording all dependencies it was set up with. */ -+ KBASE_TLSTREAM_TL_NEW_ATOM( -+ katom, -+ kbase_jd_atom_id(kctx, katom)); -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(katom, TL_ATOM_STATE_IDLE); -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_PRIORITY(katom, katom->sched_priority); -+ KBASE_TLSTREAM_TL_RET_ATOM_CTX(katom, kctx); -+ for (i = 0; i < 2; i++) -+ if (BASE_JD_DEP_TYPE_INVALID != kbase_jd_katom_dep_type( -+ &katom->dep[i])) { -+ KBASE_TLSTREAM_TL_DEP_ATOM_ATOM( -+ (void *)kbase_jd_katom_dep_atom( -+ &katom->dep[i]), -+ (void *)katom); -+ } else if (BASE_JD_DEP_TYPE_INVALID != -+ user_atom->pre_dep[i].dependency_type) { -+ /* Resolved dependency. */ -+ int dep_atom_number = -+ user_atom->pre_dep[i].atom_id; -+ struct kbase_jd_atom *dep_atom = -+ &jctx->atoms[dep_atom_number]; -+ -+ KBASE_TLSTREAM_TL_RDEP_ATOM_ATOM( -+ (void *)dep_atom, -+ (void *)katom); -+ } -+ -+ /* Reject atoms with job chain = NULL, as these cause issues with soft-stop */ -+ if (!katom->jc && (katom->core_req & BASE_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP) { -+ dev_warn(kctx->kbdev->dev, "Rejecting atom with jc = NULL"); -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ -+ /* Reject atoms with an invalid device_nr */ -+ if ((katom->core_req & BASE_JD_REQ_SPECIFIC_COHERENT_GROUP) && -+ (katom->device_nr >= kctx->kbdev->gpu_props.num_core_groups)) { -+ dev_warn(kctx->kbdev->dev, -+ "Rejecting atom with invalid device_nr %d", -+ katom->device_nr); -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ -+ /* Reject atoms with invalid core requirements */ -+ if ((katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) && -+ (katom->core_req & BASE_JD_REQ_EVENT_COALESCE)) { -+ dev_warn(kctx->kbdev->dev, -+ "Rejecting atom with invalid core requirements"); -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ katom->core_req &= ~BASE_JD_REQ_EVENT_COALESCE; -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ -+ if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) { -+ /* handle what we need to do to access the external resources */ -+ if (kbase_jd_pre_external_resources(katom, user_atom) != 0) { -+ /* setup failed (no access, bad resource, unknown resource types, etc.) */ -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ } -+ -+ /* Validate the atom. Function will return error if the atom is -+ * malformed. -+ * -+ * Soft-jobs never enter the job scheduler but have their own initialize method. -+ * -+ * If either fail then we immediately complete the atom with an error. -+ */ -+ if ((katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0) { -+ if (!kbase_js_is_atom_valid(kctx->kbdev, katom)) { -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ } else { -+ /* Soft-job */ -+ if (kbase_prepare_soft_job(katom) != 0) { -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ } -+ -+#ifdef CONFIG_GPU_TRACEPOINTS -+ katom->work_id = atomic_inc_return(&jctx->work_id); -+ trace_gpu_job_enqueue((u32)kctx->id, katom->work_id, -+ kbasep_map_core_reqs_to_string(katom->core_req)); -+#endif -+ -+ if (queued && !IS_GPU_ATOM(katom)) { -+ ret = false; -+ goto out; -+ } -+#ifdef CONFIG_KDS -+ if (!katom->kds_dep_satisfied) { -+ /* Queue atom due to KDS dependency */ -+ ret = false; -+ goto out; -+ } -+#endif /* CONFIG_KDS */ -+ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ if (kbase_fence_dep_count_read(katom) != -1) { -+ ret = false; -+ goto out; -+ } -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ -+ if ((katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) -+ == BASE_JD_REQ_SOFT_REPLAY) { -+ if (kbase_replay_process(katom)) -+ ret = false; -+ else -+ ret = jd_done_nolock(katom, NULL); -+ -+ goto out; -+ } else if (katom->core_req & BASE_JD_REQ_SOFT_JOB) { -+ if (kbase_process_soft_job(katom) == 0) { -+ kbase_finish_soft_job(katom); -+ ret = jd_done_nolock(katom, NULL); -+ goto out; -+ } -+ -+ ret = false; -+ } else if ((katom->core_req & BASE_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP) { -+ katom->status = KBASE_JD_ATOM_STATE_IN_JS; -+ ret = kbasep_js_add_job(kctx, katom); -+ /* If job was cancelled then resolve immediately */ -+ if (katom->event_code == BASE_JD_EVENT_JOB_CANCELLED) -+ ret = jd_done_nolock(katom, NULL); -+ } else { -+ /* This is a pure dependency. Resolve it immediately */ -+ ret = jd_done_nolock(katom, NULL); -+ } -+ -+ out: -+ return ret; -+} -+ -+int kbase_jd_submit(struct kbase_context *kctx, -+ void __user *user_addr, u32 nr_atoms, u32 stride, -+ bool uk6_atom) -+{ -+ struct kbase_jd_context *jctx = &kctx->jctx; -+ int err = 0; -+ int i; -+ bool need_to_try_schedule_context = false; -+ struct kbase_device *kbdev; -+ u32 latest_flush; -+ -+ /* -+ * kbase_jd_submit isn't expected to fail and so all errors with the -+ * jobs are reported by immediately failing them (through event system) -+ */ -+ kbdev = kctx->kbdev; -+ -+ beenthere(kctx, "%s", "Enter"); -+ -+ if (kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { -+ dev_err(kbdev->dev, "Attempt to submit to a context that has SUBMIT_DISABLED set on it"); -+ return -EINVAL; -+ } -+ -+ if (stride != sizeof(base_jd_atom_v2)) { -+ dev_err(kbdev->dev, "Stride passed to job_submit doesn't match kernel"); -+ return -EINVAL; -+ } -+ -+ KBASE_TIMELINE_ATOMS_IN_FLIGHT(kctx, atomic_add_return(nr_atoms, -+ &kctx->timeline.jd_atoms_in_flight)); -+ -+ /* All atoms submitted in this call have the same flush ID */ -+ latest_flush = kbase_backend_get_current_flush_id(kbdev); -+ -+ for (i = 0; i < nr_atoms; i++) { -+ struct base_jd_atom_v2 user_atom; -+ struct kbase_jd_atom *katom; -+ -+ if (copy_from_user(&user_atom, user_addr, -+ sizeof(user_atom)) != 0) { -+ err = -EINVAL; -+ KBASE_TIMELINE_ATOMS_IN_FLIGHT(kctx, -+ atomic_sub_return(nr_atoms - i, -+ &kctx->timeline.jd_atoms_in_flight)); -+ break; -+ } -+ -+#ifdef BASE_LEGACY_UK10_2_SUPPORT -+ if (KBASE_API_VERSION(10, 3) > kctx->api_version) -+ user_atom.core_req = (u32)(user_atom.compat_core_req -+ & 0x7fff); -+#endif /* BASE_LEGACY_UK10_2_SUPPORT */ -+ -+ user_addr = (void __user *)((uintptr_t) user_addr + stride); -+ -+ mutex_lock(&jctx->lock); -+#ifndef compiletime_assert -+#define compiletime_assert_defined -+#define compiletime_assert(x, msg) do { switch (0) { case 0: case (x):; } } \ -+while (false) -+#endif -+ compiletime_assert((1 << (8*sizeof(user_atom.atom_number))) == -+ BASE_JD_ATOM_COUNT, -+ "BASE_JD_ATOM_COUNT and base_atom_id type out of sync"); -+ compiletime_assert(sizeof(user_atom.pre_dep[0].atom_id) == -+ sizeof(user_atom.atom_number), -+ "BASE_JD_ATOM_COUNT and base_atom_id type out of sync"); -+#ifdef compiletime_assert_defined -+#undef compiletime_assert -+#undef compiletime_assert_defined -+#endif -+ katom = &jctx->atoms[user_atom.atom_number]; -+ -+ /* Record the flush ID for the cache flush optimisation */ -+ katom->flush_id = latest_flush; -+ -+ while (katom->status != KBASE_JD_ATOM_STATE_UNUSED) { -+ /* Atom number is already in use, wait for the atom to -+ * complete -+ */ -+ mutex_unlock(&jctx->lock); -+ -+ /* This thread will wait for the atom to complete. Due -+ * to thread scheduling we are not sure that the other -+ * thread that owns the atom will also schedule the -+ * context, so we force the scheduler to be active and -+ * hence eventually schedule this context at some point -+ * later. -+ */ -+ kbase_js_sched_all(kbdev); -+ -+ if (wait_event_killable(katom->completed, -+ katom->status == -+ KBASE_JD_ATOM_STATE_UNUSED) != 0) { -+ /* We're being killed so the result code -+ * doesn't really matter -+ */ -+ return 0; -+ } -+ mutex_lock(&jctx->lock); -+ } -+ -+ need_to_try_schedule_context |= -+ jd_submit_atom(kctx, &user_atom, katom); -+ -+ /* Register a completed job as a disjoint event when the GPU is in a disjoint state -+ * (ie. being reset or replaying jobs). -+ */ -+ kbase_disjoint_event_potential(kbdev); -+ -+ mutex_unlock(&jctx->lock); -+ } -+ -+ if (need_to_try_schedule_context) -+ kbase_js_sched_all(kbdev); -+ -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_jd_submit); -+ -+void kbase_jd_done_worker(struct work_struct *data) -+{ -+ struct kbase_jd_atom *katom = container_of(data, struct kbase_jd_atom, work); -+ struct kbase_jd_context *jctx; -+ struct kbase_context *kctx; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ struct kbase_device *kbdev; -+ struct kbasep_js_device_data *js_devdata; -+ u64 cache_jc = katom->jc; -+ struct kbasep_js_atom_retained_state katom_retained_state; -+ bool context_idle; -+ base_jd_core_req core_req = katom->core_req; -+ u64 affinity = katom->affinity; -+ enum kbase_atom_coreref_state coreref_state = katom->coreref_state; -+ -+ /* Soft jobs should never reach this function */ -+ KBASE_DEBUG_ASSERT((katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0); -+ -+ kctx = katom->kctx; -+ jctx = &kctx->jctx; -+ kbdev = kctx->kbdev; -+ js_kctx_info = &kctx->jctx.sched_info; -+ js_devdata = &kbdev->js_data; -+ -+ KBASE_TRACE_ADD(kbdev, JD_DONE_WORKER, kctx, katom, katom->jc, 0); -+ -+ kbase_backend_complete_wq(kbdev, katom); -+ -+ /* -+ * Begin transaction on JD context and JS context -+ */ -+ mutex_lock(&jctx->lock); -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(katom, TL_ATOM_STATE_DONE); -+ mutex_lock(&js_devdata->queue_mutex); -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ /* This worker only gets called on contexts that are scheduled *in*. This is -+ * because it only happens in response to an IRQ from a job that was -+ * running. -+ */ -+ KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ if (katom->event_code == BASE_JD_EVENT_STOPPED) { -+ /* Atom has been promoted to stopped */ -+ unsigned long flags; -+ -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ katom->status = KBASE_JD_ATOM_STATE_IN_JS; -+ kbase_js_unpull(kctx, katom); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&jctx->lock); -+ -+ return; -+ } -+ -+ if (katom->event_code != BASE_JD_EVENT_DONE) -+ dev_err(kbdev->dev, -+ "t6xx: GPU fault 0x%02lx from job slot %d\n", -+ (unsigned long)katom->event_code, -+ katom->slot_nr); -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316)) -+ kbase_as_poking_timer_release_atom(kbdev, kctx, katom); -+ -+ /* Retain state before the katom disappears */ -+ kbasep_js_atom_retained_state_copy(&katom_retained_state, katom); -+ -+ context_idle = kbase_js_complete_atom_wq(kctx, katom); -+ -+ KBASE_DEBUG_ASSERT(kbasep_js_has_atom_finished(&katom_retained_state)); -+ -+ kbasep_js_remove_job(kbdev, kctx, katom); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ katom->atom_flags &= ~KBASE_KATOM_FLAG_HOLDING_CTX_REF; -+ /* jd_done_nolock() requires the jsctx_mutex lock to be dropped */ -+ jd_done_nolock(katom, &kctx->completed_jobs); -+ -+ /* katom may have been freed now, do not use! */ -+ -+ if (context_idle) { -+ unsigned long flags; -+ -+ context_idle = false; -+ mutex_lock(&js_devdata->queue_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* If kbase_sched() has scheduled this context back in then -+ * KCTX_ACTIVE will have been set after we marked it as -+ * inactive, and another pm reference will have been taken, so -+ * drop our reference. But do not call kbase_jm_idle_ctx(), as -+ * the context is active and fast-starting is allowed. -+ * -+ * If an atom has been fast-started then kctx->atoms_pulled will -+ * be non-zero but KCTX_ACTIVE will still be false (as the -+ * previous pm reference has been inherited). Do NOT drop our -+ * reference, as it has been re-used, and leave the context as -+ * active. -+ * -+ * If no new atoms have been started then KCTX_ACTIVE will still -+ * be false and atoms_pulled will be zero, so drop the reference -+ * and call kbase_jm_idle_ctx(). -+ * -+ * As the checks are done under both the queue_mutex and -+ * hwaccess_lock is should be impossible for this to race -+ * with the scheduler code. -+ */ -+ if (kbase_ctx_flag(kctx, KCTX_ACTIVE) || -+ !atomic_read(&kctx->atoms_pulled)) { -+ /* Calling kbase_jm_idle_ctx() here will ensure that -+ * atoms are not fast-started when we drop the -+ * hwaccess_lock. This is not performed if -+ * KCTX_ACTIVE is set as in that case another pm -+ * reference has been taken and a fast-start would be -+ * valid. -+ */ -+ if (!kbase_ctx_flag(kctx, KCTX_ACTIVE)) -+ kbase_jm_idle_ctx(kbdev, kctx); -+ context_idle = true; -+ } else { -+ kbase_ctx_flag_set(kctx, KCTX_ACTIVE); -+ } -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&js_devdata->queue_mutex); -+ } -+ -+ /* -+ * Transaction complete -+ */ -+ mutex_unlock(&jctx->lock); -+ -+ /* Job is now no longer running, so can now safely release the context -+ * reference, and handle any actions that were logged against the atom's retained state */ -+ -+ kbasep_js_runpool_release_ctx_and_katom_retained_state(kbdev, kctx, &katom_retained_state); -+ -+ kbase_js_sched_all(kbdev); -+ -+ if (!atomic_dec_return(&kctx->work_count)) { -+ /* If worker now idle then post all events that jd_done_nolock() -+ * has queued */ -+ mutex_lock(&jctx->lock); -+ while (!list_empty(&kctx->completed_jobs)) { -+ struct kbase_jd_atom *atom = list_entry( -+ kctx->completed_jobs.next, -+ struct kbase_jd_atom, jd_item); -+ list_del(kctx->completed_jobs.next); -+ -+ kbase_event_post(kctx, atom); -+ } -+ mutex_unlock(&jctx->lock); -+ } -+ -+ kbase_backend_complete_wq_post_sched(kbdev, core_req, affinity, -+ coreref_state); -+ -+ if (context_idle) -+ kbase_pm_context_idle(kbdev); -+ -+ KBASE_TRACE_ADD(kbdev, JD_DONE_WORKER_END, kctx, NULL, cache_jc, 0); -+} -+ -+/** -+ * jd_cancel_worker - Work queue job cancel function. -+ * @data: a &struct work_struct -+ * -+ * Only called as part of 'Zapping' a context (which occurs on termination). -+ * Operates serially with the kbase_jd_done_worker() on the work queue. -+ * -+ * This can only be called on contexts that aren't scheduled. -+ * -+ * We don't need to release most of the resources that would occur on -+ * kbase_jd_done() or kbase_jd_done_worker(), because the atoms here must not be -+ * running (by virtue of only being called on contexts that aren't -+ * scheduled). -+ */ -+static void jd_cancel_worker(struct work_struct *data) -+{ -+ struct kbase_jd_atom *katom = container_of(data, struct kbase_jd_atom, work); -+ struct kbase_jd_context *jctx; -+ struct kbase_context *kctx; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ bool need_to_try_schedule_context; -+ bool attr_state_changed; -+ struct kbase_device *kbdev; -+ -+ /* Soft jobs should never reach this function */ -+ KBASE_DEBUG_ASSERT((katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0); -+ -+ kctx = katom->kctx; -+ kbdev = kctx->kbdev; -+ jctx = &kctx->jctx; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ KBASE_TRACE_ADD(kbdev, JD_CANCEL_WORKER, kctx, katom, katom->jc, 0); -+ -+ /* This only gets called on contexts that are scheduled out. Hence, we must -+ * make sure we don't de-ref the number of running jobs (there aren't -+ * any), nor must we try to schedule out the context (it's already -+ * scheduled out). -+ */ -+ KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ /* Scheduler: Remove the job from the system */ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ attr_state_changed = kbasep_js_remove_cancelled_job(kbdev, kctx, katom); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ mutex_lock(&jctx->lock); -+ -+ need_to_try_schedule_context = jd_done_nolock(katom, NULL); -+ /* Because we're zapping, we're not adding any more jobs to this ctx, so no need to -+ * schedule the context. There's also no need for the jsctx_mutex to have been taken -+ * around this too. */ -+ KBASE_DEBUG_ASSERT(!need_to_try_schedule_context); -+ -+ /* katom may have been freed now, do not use! */ -+ mutex_unlock(&jctx->lock); -+ -+ if (attr_state_changed) -+ kbase_js_sched_all(kbdev); -+} -+ -+/** -+ * kbase_jd_done - Complete a job that has been removed from the Hardware -+ * @katom: atom which has been completed -+ * @slot_nr: slot the atom was on -+ * @end_timestamp: completion time -+ * @done_code: completion code -+ * -+ * This must be used whenever a job has been removed from the Hardware, e.g.: -+ * An IRQ indicates that the job finished (for both error and 'done' codes), or -+ * the job was evicted from the JS_HEAD_NEXT registers during a Soft/Hard stop. -+ * -+ * Some work is carried out immediately, and the rest is deferred onto a -+ * workqueue -+ * -+ * Context: -+ * This can be called safely from atomic context. -+ * The caller must hold kbdev->hwaccess_lock -+ */ -+void kbase_jd_done(struct kbase_jd_atom *katom, int slot_nr, -+ ktime_t *end_timestamp, kbasep_js_atom_done_code done_code) -+{ -+ struct kbase_context *kctx; -+ struct kbase_device *kbdev; -+ -+ KBASE_DEBUG_ASSERT(katom); -+ kctx = katom->kctx; -+ KBASE_DEBUG_ASSERT(kctx); -+ kbdev = kctx->kbdev; -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ if (done_code & KBASE_JS_ATOM_DONE_EVICTED_FROM_NEXT) -+ katom->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT; -+ -+ KBASE_TRACE_ADD(kbdev, JD_DONE, kctx, katom, katom->jc, 0); -+ -+ kbase_job_check_leave_disjoint(kbdev, katom); -+ -+ katom->slot_nr = slot_nr; -+ -+ atomic_inc(&kctx->work_count); -+ -+#ifdef CONFIG_DEBUG_FS -+ /* a failed job happened and is waiting for dumping*/ -+ if (!katom->will_fail_event_code && -+ kbase_debug_job_fault_process(katom, katom->event_code)) -+ return; -+#endif -+ -+ WARN_ON(work_pending(&katom->work)); -+ KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&katom->work)); -+ INIT_WORK(&katom->work, kbase_jd_done_worker); -+ queue_work(kctx->jctx.job_done_wq, &katom->work); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_jd_done); -+ -+void kbase_jd_cancel(struct kbase_device *kbdev, struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx; -+ -+ KBASE_DEBUG_ASSERT(NULL != kbdev); -+ KBASE_DEBUG_ASSERT(NULL != katom); -+ kctx = katom->kctx; -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ -+ KBASE_TRACE_ADD(kbdev, JD_CANCEL, kctx, katom, katom->jc, 0); -+ -+ /* This should only be done from a context that is not scheduled */ -+ KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ WARN_ON(work_pending(&katom->work)); -+ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ -+ KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&katom->work)); -+ INIT_WORK(&katom->work, jd_cancel_worker); -+ queue_work(kctx->jctx.job_done_wq, &katom->work); -+} -+ -+ -+void kbase_jd_zap_context(struct kbase_context *kctx) -+{ -+ struct kbase_jd_atom *katom; -+ struct list_head *entry, *tmp; -+ struct kbase_device *kbdev; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+ kbdev = kctx->kbdev; -+ -+ KBASE_TRACE_ADD(kbdev, JD_ZAP_CONTEXT, kctx, NULL, 0u, 0u); -+ -+ kbase_js_zap_context(kctx); -+ -+ mutex_lock(&kctx->jctx.lock); -+ -+ /* -+ * While holding the struct kbase_jd_context lock clean up jobs which are known to kbase but are -+ * queued outside the job scheduler. -+ */ -+ -+ del_timer_sync(&kctx->soft_job_timeout); -+ list_for_each_safe(entry, tmp, &kctx->waiting_soft_jobs) { -+ katom = list_entry(entry, struct kbase_jd_atom, queue); -+ kbase_cancel_soft_job(katom); -+ } -+ -+ -+#ifdef CONFIG_KDS -+ -+ /* For each job waiting on a kds resource, cancel the wait and force the job to -+ * complete early, this is done so that we don't leave jobs outstanding waiting -+ * on kds resources which may never be released when contexts are zapped, resulting -+ * in a hang. -+ * -+ * Note that we can safely iterate over the list as the struct kbase_jd_context lock is held, -+ * this prevents items being removed when calling job_done_nolock in kbase_cancel_kds_wait_job. -+ */ -+ -+ list_for_each(entry, &kctx->waiting_kds_resource) { -+ katom = list_entry(entry, struct kbase_jd_atom, node); -+ -+ kbase_cancel_kds_wait_job(katom); -+ } -+#endif -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ kbase_dma_fence_cancel_all_atoms(kctx); -+#endif -+ -+ mutex_unlock(&kctx->jctx.lock); -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ /* Flush dma-fence workqueue to ensure that any callbacks that may have -+ * been queued are done before continuing. -+ */ -+ flush_workqueue(kctx->dma_fence.wq); -+#endif -+ -+ kbase_jm_wait_for_zero_jobs(kctx); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_jd_zap_context); -+ -+int kbase_jd_init(struct kbase_context *kctx) -+{ -+ int i; -+ int mali_err = 0; -+#ifdef CONFIG_KDS -+ int err; -+#endif /* CONFIG_KDS */ -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+ kctx->jctx.job_done_wq = alloc_workqueue("mali_jd", -+ WQ_HIGHPRI | WQ_UNBOUND, 1); -+ if (NULL == kctx->jctx.job_done_wq) { -+ mali_err = -ENOMEM; -+ goto out1; -+ } -+ -+ for (i = 0; i < BASE_JD_ATOM_COUNT; i++) { -+ init_waitqueue_head(&kctx->jctx.atoms[i].completed); -+ -+ INIT_LIST_HEAD(&kctx->jctx.atoms[i].dep_head[0]); -+ INIT_LIST_HEAD(&kctx->jctx.atoms[i].dep_head[1]); -+ -+ /* Catch userspace attempting to use an atom which doesn't exist as a pre-dependency */ -+ kctx->jctx.atoms[i].event_code = BASE_JD_EVENT_JOB_INVALID; -+ kctx->jctx.atoms[i].status = KBASE_JD_ATOM_STATE_UNUSED; -+ -+#if defined(CONFIG_MALI_DMA_FENCE) || defined(CONFIG_SYNC_FILE) -+ kctx->jctx.atoms[i].dma_fence.context = -+ dma_fence_context_alloc(1); -+ atomic_set(&kctx->jctx.atoms[i].dma_fence.seqno, 0); -+ INIT_LIST_HEAD(&kctx->jctx.atoms[i].dma_fence.callbacks); -+#endif -+ } -+ -+ mutex_init(&kctx->jctx.lock); -+ -+ init_waitqueue_head(&kctx->jctx.zero_jobs_wait); -+ -+ spin_lock_init(&kctx->jctx.tb_lock); -+ -+#ifdef CONFIG_KDS -+ err = kds_callback_init(&kctx->jctx.kds_cb, 0, kds_dep_clear); -+ if (0 != err) { -+ mali_err = -EINVAL; -+ goto out2; -+ } -+#endif /* CONFIG_KDS */ -+ -+ kctx->jctx.job_nr = 0; -+ INIT_LIST_HEAD(&kctx->completed_jobs); -+ atomic_set(&kctx->work_count, 0); -+ -+ return 0; -+ -+#ifdef CONFIG_KDS -+ out2: -+ destroy_workqueue(kctx->jctx.job_done_wq); -+#endif /* CONFIG_KDS */ -+ out1: -+ return mali_err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_jd_init); -+ -+void kbase_jd_exit(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+#ifdef CONFIG_KDS -+ kds_callback_term(&kctx->jctx.kds_cb); -+#endif /* CONFIG_KDS */ -+ /* Work queue is emptied by this */ -+ destroy_workqueue(kctx->jctx.job_done_wq); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_jd_exit); -diff --git a/drivers/gpu/arm/midgard/mali_kbase_jd_debugfs.c b/drivers/gpu/arm/midgard/mali_kbase_jd_debugfs.c -new file mode 100644 -index 0000000..c8b37c4 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_jd_debugfs.c -@@ -0,0 +1,235 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifdef CONFIG_DEBUG_FS -+ -+#include -+#include -+#include -+#include -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+#include -+#endif -+ -+struct kbase_jd_debugfs_depinfo { -+ u8 id; -+ char type; -+}; -+ -+static void kbase_jd_debugfs_fence_info(struct kbase_jd_atom *atom, -+ struct seq_file *sfile) -+{ -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ struct kbase_sync_fence_info info; -+ int res; -+ -+ switch (atom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) { -+ case BASE_JD_REQ_SOFT_FENCE_TRIGGER: -+ res = kbase_sync_fence_out_info_get(atom, &info); -+ if (0 == res) { -+ seq_printf(sfile, "Sa([%p]%d) ", -+ info.fence, info.status); -+ break; -+ } -+ case BASE_JD_REQ_SOFT_FENCE_WAIT: -+ res = kbase_sync_fence_in_info_get(atom, &info); -+ if (0 == res) { -+ seq_printf(sfile, "Wa([%p]%d) ", -+ info.fence, info.status); -+ break; -+ } -+ default: -+ break; -+ } -+#endif /* CONFIG_SYNC || CONFIG_SYNC_FILE */ -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ if (atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) { -+ struct kbase_fence_cb *cb; -+ -+ if (atom->dma_fence.fence) { -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence = atom->dma_fence.fence; -+#else -+ struct dma_fence *fence = atom->dma_fence.fence; -+#endif -+ -+ seq_printf(sfile, -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) -+ "Sd(%u#%u: %s) ", -+#else -+ "Sd(%llu#%u: %s) ", -+#endif -+ fence->context, -+ fence->seqno, -+ dma_fence_is_signaled(fence) ? -+ "signaled" : "active"); -+ } -+ -+ list_for_each_entry(cb, &atom->dma_fence.callbacks, -+ node) { -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence = cb->fence; -+#else -+ struct dma_fence *fence = cb->fence; -+#endif -+ -+ seq_printf(sfile, -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) -+ "Wd(%u#%u: %s) ", -+#else -+ "Wd(%llu#%u: %s) ", -+#endif -+ fence->context, -+ fence->seqno, -+ dma_fence_is_signaled(fence) ? -+ "signaled" : "active"); -+ } -+ } -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ -+} -+ -+static void kbasep_jd_debugfs_atom_deps( -+ struct kbase_jd_debugfs_depinfo *deps, -+ struct kbase_jd_atom *atom) -+{ -+ struct kbase_context *kctx = atom->kctx; -+ int i; -+ -+ for (i = 0; i < 2; i++) { -+ deps[i].id = (unsigned)(atom->dep[i].atom ? -+ kbase_jd_atom_id(kctx, atom->dep[i].atom) : 0); -+ -+ switch (atom->dep[i].dep_type) { -+ case BASE_JD_DEP_TYPE_INVALID: -+ deps[i].type = ' '; -+ break; -+ case BASE_JD_DEP_TYPE_DATA: -+ deps[i].type = 'D'; -+ break; -+ case BASE_JD_DEP_TYPE_ORDER: -+ deps[i].type = '>'; -+ break; -+ default: -+ deps[i].type = '?'; -+ break; -+ } -+ } -+} -+/** -+ * kbasep_jd_debugfs_atoms_show - Show callback for the JD atoms debugfs file. -+ * @sfile: The debugfs entry -+ * @data: Data associated with the entry -+ * -+ * This function is called to get the contents of the JD atoms debugfs file. -+ * This is a report of all atoms managed by kbase_jd_context.atoms -+ * -+ * Return: 0 if successfully prints data in debugfs entry file, failure -+ * otherwise -+ */ -+static int kbasep_jd_debugfs_atoms_show(struct seq_file *sfile, void *data) -+{ -+ struct kbase_context *kctx = sfile->private; -+ struct kbase_jd_atom *atoms; -+ unsigned long irq_flags; -+ int i; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ /* Print version */ -+ seq_printf(sfile, "v%u\n", MALI_JD_DEBUGFS_VERSION); -+ -+ /* Print U/K API version */ -+ seq_printf(sfile, "ukv%u.%u\n", BASE_UK_VERSION_MAJOR, -+ BASE_UK_VERSION_MINOR); -+ -+ /* Print table heading */ -+ seq_puts(sfile, " ID, Core req, St, CR, Predeps, Start time, Additional info...\n"); -+ -+ atoms = kctx->jctx.atoms; -+ /* General atom states */ -+ mutex_lock(&kctx->jctx.lock); -+ /* JS-related states */ -+ spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, irq_flags); -+ for (i = 0; i != BASE_JD_ATOM_COUNT; ++i) { -+ struct kbase_jd_atom *atom = &atoms[i]; -+ s64 start_timestamp = 0; -+ struct kbase_jd_debugfs_depinfo deps[2]; -+ -+ if (atom->status == KBASE_JD_ATOM_STATE_UNUSED) -+ continue; -+ -+ /* start_timestamp is cleared as soon as the atom leaves UNUSED state -+ * and set before a job is submitted to the h/w, a non-zero value means -+ * it is valid */ -+ if (ktime_to_ns(atom->start_timestamp)) -+ start_timestamp = ktime_to_ns( -+ ktime_sub(ktime_get(), atom->start_timestamp)); -+ -+ kbasep_jd_debugfs_atom_deps(deps, atom); -+ -+ seq_printf(sfile, -+ "%3u, %8x, %2u, %2u, %c%3u %c%3u, %20lld, ", -+ i, atom->core_req, atom->status, -+ atom->coreref_state, -+ deps[0].type, deps[0].id, -+ deps[1].type, deps[1].id, -+ start_timestamp); -+ -+ -+ kbase_jd_debugfs_fence_info(atom, sfile); -+ -+ seq_puts(sfile, "\n"); -+ } -+ spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, irq_flags); -+ mutex_unlock(&kctx->jctx.lock); -+ -+ return 0; -+} -+ -+ -+/** -+ * kbasep_jd_debugfs_atoms_open - open operation for atom debugfs file -+ * @in: &struct inode pointer -+ * @file: &struct file pointer -+ * -+ * Return: file descriptor -+ */ -+static int kbasep_jd_debugfs_atoms_open(struct inode *in, struct file *file) -+{ -+ return single_open(file, kbasep_jd_debugfs_atoms_show, in->i_private); -+} -+ -+static const struct file_operations kbasep_jd_debugfs_atoms_fops = { -+ .open = kbasep_jd_debugfs_atoms_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+void kbasep_jd_debugfs_ctx_init(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ /* Expose all atoms */ -+ debugfs_create_file("atoms", S_IRUGO, kctx->kctx_dentry, kctx, -+ &kbasep_jd_debugfs_atoms_fops); -+ -+} -+ -+#endif /* CONFIG_DEBUG_FS */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_jd_debugfs.h b/drivers/gpu/arm/midgard/mali_kbase_jd_debugfs.h -new file mode 100644 -index 0000000..0935f1d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_jd_debugfs.h -@@ -0,0 +1,39 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @file mali_kbase_jd_debugfs.h -+ * Header file for job dispatcher-related entries in debugfs -+ */ -+ -+#ifndef _KBASE_JD_DEBUGFS_H -+#define _KBASE_JD_DEBUGFS_H -+ -+#include -+ -+#include -+ -+#define MALI_JD_DEBUGFS_VERSION 2 -+ -+/** -+ * kbasep_jd_debugfs_ctx_init() - Add debugfs entries for JD system -+ * -+ * @kctx Pointer to kbase_context -+ */ -+void kbasep_jd_debugfs_ctx_init(struct kbase_context *kctx); -+ -+#endif /*_KBASE_JD_DEBUGFS_H*/ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_jm.c b/drivers/gpu/arm/midgard/mali_kbase_jm.c -new file mode 100644 -index 0000000..0c5c6a6 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_jm.c -@@ -0,0 +1,131 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * HW access job manager common APIs -+ */ -+ -+#include -+#include "mali_kbase_hwaccess_jm.h" -+#include "mali_kbase_jm.h" -+ -+/** -+ * kbase_jm_next_job() - Attempt to run the next @nr_jobs_to_submit jobs on slot -+ * @js on the active context. -+ * @kbdev: Device pointer -+ * @js: Job slot to run on -+ * @nr_jobs_to_submit: Number of jobs to attempt to submit -+ * -+ * Return: true if slot can still be submitted on, false if slot is now full. -+ */ -+static bool kbase_jm_next_job(struct kbase_device *kbdev, int js, -+ int nr_jobs_to_submit) -+{ -+ struct kbase_context *kctx; -+ int i; -+ -+ kctx = kbdev->hwaccess.active_kctx; -+ -+ if (!kctx) -+ return true; -+ -+ for (i = 0; i < nr_jobs_to_submit; i++) { -+ struct kbase_jd_atom *katom = kbase_js_pull(kctx, js); -+ -+ if (!katom) -+ return true; /* Context has no jobs on this slot */ -+ -+ kbase_backend_run_atom(kbdev, katom); -+ } -+ -+ return false; /* Slot ringbuffer should now be full */ -+} -+ -+u32 kbase_jm_kick(struct kbase_device *kbdev, u32 js_mask) -+{ -+ u32 ret_mask = 0; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ while (js_mask) { -+ int js = ffs(js_mask) - 1; -+ int nr_jobs_to_submit = kbase_backend_slot_free(kbdev, js); -+ -+ if (kbase_jm_next_job(kbdev, js, nr_jobs_to_submit)) -+ ret_mask |= (1 << js); -+ -+ js_mask &= ~(1 << js); -+ } -+ -+ return ret_mask; -+} -+ -+void kbase_jm_try_kick(struct kbase_device *kbdev, u32 js_mask) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (!down_trylock(&js_devdata->schedule_sem)) { -+ kbase_jm_kick(kbdev, js_mask); -+ up(&js_devdata->schedule_sem); -+ } -+} -+ -+void kbase_jm_try_kick_all(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (!down_trylock(&js_devdata->schedule_sem)) { -+ kbase_jm_kick_all(kbdev); -+ up(&js_devdata->schedule_sem); -+ } -+} -+ -+void kbase_jm_idle_ctx(struct kbase_device *kbdev, struct kbase_context *kctx) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (kbdev->hwaccess.active_kctx == kctx) -+ kbdev->hwaccess.active_kctx = NULL; -+} -+ -+struct kbase_jd_atom *kbase_jm_return_atom_to_js(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (katom->event_code != BASE_JD_EVENT_STOPPED && -+ katom->event_code != BASE_JD_EVENT_REMOVED_FROM_NEXT) { -+ return kbase_js_complete_atom(katom, NULL); -+ } else { -+ kbase_js_unpull(katom->kctx, katom); -+ return NULL; -+ } -+} -+ -+struct kbase_jd_atom *kbase_jm_complete(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, ktime_t *end_timestamp) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ return kbase_js_complete_atom(katom, end_timestamp); -+} -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_jm.h b/drivers/gpu/arm/midgard/mali_kbase_jm.h -new file mode 100644 -index 0000000..a74ee24 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_jm.h -@@ -0,0 +1,110 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+/* -+ * Job manager common APIs -+ */ -+ -+#ifndef _KBASE_JM_H_ -+#define _KBASE_JM_H_ -+ -+/** -+ * kbase_jm_kick() - Indicate that there are jobs ready to run. -+ * @kbdev: Device pointer -+ * @js_mask: Mask of the job slots that can be pulled from. -+ * -+ * Caller must hold the hwaccess_lock and schedule_sem semaphore -+ * -+ * Return: Mask of the job slots that can still be submitted to. -+ */ -+u32 kbase_jm_kick(struct kbase_device *kbdev, u32 js_mask); -+ -+/** -+ * kbase_jm_kick_all() - Indicate that there are jobs ready to run on all job -+ * slots. -+ * @kbdev: Device pointer -+ * -+ * Caller must hold the hwaccess_lock and schedule_sem semaphore -+ * -+ * Return: Mask of the job slots that can still be submitted to. -+ */ -+static inline u32 kbase_jm_kick_all(struct kbase_device *kbdev) -+{ -+ return kbase_jm_kick(kbdev, (1 << kbdev->gpu_props.num_job_slots) - 1); -+} -+ -+/** -+ * kbase_jm_try_kick - Attempt to call kbase_jm_kick -+ * @kbdev: Device pointer -+ * @js_mask: Mask of the job slots that can be pulled from -+ * Context: Caller must hold hwaccess_lock -+ * -+ * If schedule_sem can be immediately obtained then this function will call -+ * kbase_jm_kick() otherwise it will do nothing. -+ */ -+void kbase_jm_try_kick(struct kbase_device *kbdev, u32 js_mask); -+ -+/** -+ * kbase_jm_try_kick_all() - Attempt to call kbase_jm_kick_all -+ * @kbdev: Device pointer -+ * Context: Caller must hold hwaccess_lock -+ * -+ * If schedule_sem can be immediately obtained then this function will call -+ * kbase_jm_kick_all() otherwise it will do nothing. -+ */ -+void kbase_jm_try_kick_all(struct kbase_device *kbdev); -+ -+/** -+ * kbase_jm_idle_ctx() - Mark a context as idle. -+ * @kbdev: Device pointer -+ * @kctx: Context to mark as idle -+ * -+ * No more atoms will be pulled from this context until it is marked as active -+ * by kbase_js_use_ctx(). -+ * -+ * The context should have no atoms currently pulled from it -+ * (kctx->atoms_pulled == 0). -+ * -+ * Caller must hold the hwaccess_lock -+ */ -+void kbase_jm_idle_ctx(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * kbase_jm_return_atom_to_js() - Return an atom to the job scheduler that has -+ * been soft-stopped or will fail due to a -+ * dependency -+ * @kbdev: Device pointer -+ * @katom: Atom that has been stopped or will be failed -+ * -+ * Return: Atom that has now been unblocked and can now be run, or NULL if none -+ */ -+struct kbase_jd_atom *kbase_jm_return_atom_to_js(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_jm_complete() - Complete an atom -+ * @kbdev: Device pointer -+ * @katom: Atom that has completed -+ * @end_timestamp: Timestamp of atom completion -+ * -+ * Return: Atom that has now been unblocked and can now be run, or NULL if none -+ */ -+struct kbase_jd_atom *kbase_jm_complete(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom, ktime_t *end_timestamp); -+ -+#endif /* _KBASE_JM_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_js.c b/drivers/gpu/arm/midgard/mali_kbase_js.c -new file mode 100644 -index 0000000..2be32d6 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_js.c -@@ -0,0 +1,2819 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* -+ * Job Scheduler Implementation -+ */ -+#include -+#include -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+#include -+#endif -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "mali_kbase_jm.h" -+#include "mali_kbase_hwaccess_jm.h" -+ -+/* -+ * Private types -+ */ -+ -+/* Bitpattern indicating the result of releasing a context */ -+enum { -+ /* The context was descheduled - caller should try scheduling in a new -+ * one to keep the runpool full */ -+ KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED = (1u << 0), -+ /* Ctx attributes were changed - caller should try scheduling all -+ * contexts */ -+ KBASEP_JS_RELEASE_RESULT_SCHED_ALL = (1u << 1) -+}; -+ -+typedef u32 kbasep_js_release_result; -+ -+const int kbasep_js_atom_priority_to_relative[BASE_JD_NR_PRIO_LEVELS] = { -+ KBASE_JS_ATOM_SCHED_PRIO_MED, /* BASE_JD_PRIO_MEDIUM */ -+ KBASE_JS_ATOM_SCHED_PRIO_HIGH, /* BASE_JD_PRIO_HIGH */ -+ KBASE_JS_ATOM_SCHED_PRIO_LOW /* BASE_JD_PRIO_LOW */ -+}; -+ -+const base_jd_prio -+kbasep_js_relative_priority_to_atom[KBASE_JS_ATOM_SCHED_PRIO_COUNT] = { -+ BASE_JD_PRIO_HIGH, /* KBASE_JS_ATOM_SCHED_PRIO_HIGH */ -+ BASE_JD_PRIO_MEDIUM, /* KBASE_JS_ATOM_SCHED_PRIO_MED */ -+ BASE_JD_PRIO_LOW /* KBASE_JS_ATOM_SCHED_PRIO_LOW */ -+}; -+ -+ -+/* -+ * Private function prototypes -+ */ -+static kbasep_js_release_result kbasep_js_runpool_release_ctx_internal( -+ struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbasep_js_atom_retained_state *katom_retained_state); -+ -+static int kbase_js_get_slot(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom); -+ -+static void kbase_js_foreach_ctx_job(struct kbase_context *kctx, -+ kbasep_js_ctx_job_cb callback); -+ -+/* Helper for trace subcodes */ -+#if KBASE_TRACE_ENABLE -+static int kbasep_js_trace_get_refcnt(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ return atomic_read(&kctx->refcount); -+} -+#else /* KBASE_TRACE_ENABLE */ -+static int kbasep_js_trace_get_refcnt(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ CSTD_UNUSED(kbdev); -+ CSTD_UNUSED(kctx); -+ return 0; -+} -+#endif /* KBASE_TRACE_ENABLE */ -+ -+/* -+ * Private functions -+ */ -+ -+/** -+ * core_reqs_from_jsn_features - Convert JSn_FEATURES to core requirements -+ * @features: JSn_FEATURE register value -+ * -+ * Given a JSn_FEATURE register value returns the core requirements that match -+ * -+ * Return: Core requirement bit mask -+ */ -+static base_jd_core_req core_reqs_from_jsn_features(u16 features) -+{ -+ base_jd_core_req core_req = 0u; -+ -+ if ((features & JS_FEATURE_SET_VALUE_JOB) != 0) -+ core_req |= BASE_JD_REQ_V; -+ -+ if ((features & JS_FEATURE_CACHE_FLUSH_JOB) != 0) -+ core_req |= BASE_JD_REQ_CF; -+ -+ if ((features & JS_FEATURE_COMPUTE_JOB) != 0) -+ core_req |= BASE_JD_REQ_CS; -+ -+ if ((features & JS_FEATURE_TILER_JOB) != 0) -+ core_req |= BASE_JD_REQ_T; -+ -+ if ((features & JS_FEATURE_FRAGMENT_JOB) != 0) -+ core_req |= BASE_JD_REQ_FS; -+ -+ return core_req; -+} -+ -+static void kbase_js_sync_timers(struct kbase_device *kbdev) -+{ -+ mutex_lock(&kbdev->js_data.runpool_mutex); -+ kbase_backend_ctx_count_changed(kbdev); -+ mutex_unlock(&kbdev->js_data.runpool_mutex); -+} -+ -+/* Hold the mmu_hw_mutex and hwaccess_lock for this */ -+bool kbasep_js_runpool_retain_ctx_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ bool result = false; -+ int as_nr; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ js_devdata = &kbdev->js_data; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ as_nr = kctx->as_nr; -+ if (atomic_read(&kctx->refcount) > 0) { -+ KBASE_DEBUG_ASSERT(as_nr >= 0); -+ -+ kbase_ctx_sched_retain_ctx_refcount(kctx); -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, JS_RETAIN_CTX_NOLOCK, kctx, -+ NULL, 0u, atomic_read(&kctx->refcount)); -+ result = true; -+ } -+ -+ return result; -+} -+ -+/** -+ * jsctx_rb_none_to_pull_prio(): - Check if there are no pullable atoms -+ * @kctx: Pointer to kbase context with ring buffer. -+ * @js: Job slot id to check. -+ * @prio: Priority to check. -+ * -+ * Return true if there are no atoms to pull. There may be running atoms in the -+ * ring buffer even if there are no atoms to pull. It is also possible for the -+ * ring buffer to be full (with running atoms) when this functions returns -+ * true. -+ * -+ * Return: true if there are no atoms to pull, false otherwise. -+ */ -+static inline bool -+jsctx_rb_none_to_pull_prio(struct kbase_context *kctx, int js, int prio) -+{ -+ struct jsctx_queue *rb = &kctx->jsctx_queue[prio][js]; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ return RB_EMPTY_ROOT(&rb->runnable_tree); -+} -+ -+/** -+ * jsctx_rb_none_to_pull(): - Check if all priority ring buffers have no -+ * pullable atoms -+ * @kctx: Pointer to kbase context with ring buffer. -+ * @js: Job slot id to check. -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: true if the ring buffers for all priorities have no pullable atoms, -+ * false otherwise. -+ */ -+static inline bool -+jsctx_rb_none_to_pull(struct kbase_context *kctx, int js) -+{ -+ int prio; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ for (prio = 0; prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++) { -+ if (!jsctx_rb_none_to_pull_prio(kctx, js, prio)) -+ return false; -+ } -+ -+ return true; -+} -+ -+/** -+ * jsctx_queue_foreach_prio(): - Execute callback for each entry in the queue. -+ * @kctx: Pointer to kbase context with the queue. -+ * @js: Job slot id to iterate. -+ * @prio: Priority id to iterate. -+ * @callback: Function pointer to callback. -+ * -+ * Iterate over a queue and invoke @callback for each entry in the queue, and -+ * remove the entry from the queue. -+ * -+ * If entries are added to the queue while this is running those entries may, or -+ * may not be covered. To ensure that all entries in the buffer have been -+ * enumerated when this function returns jsctx->lock must be held when calling -+ * this function. -+ * -+ * The HW access lock must always be held when calling this function. -+ */ -+static void -+jsctx_queue_foreach_prio(struct kbase_context *kctx, int js, int prio, -+ kbasep_js_ctx_job_cb callback) -+{ -+ struct jsctx_queue *queue = &kctx->jsctx_queue[prio][js]; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ while (!RB_EMPTY_ROOT(&queue->runnable_tree)) { -+ struct rb_node *node = rb_first(&queue->runnable_tree); -+ struct kbase_jd_atom *entry = rb_entry(node, -+ struct kbase_jd_atom, runnable_tree_node); -+ -+ rb_erase(node, &queue->runnable_tree); -+ callback(kctx->kbdev, entry); -+ } -+ -+ while (!list_empty(&queue->x_dep_head)) { -+ struct kbase_jd_atom *entry = list_entry(queue->x_dep_head.next, -+ struct kbase_jd_atom, queue); -+ -+ list_del(queue->x_dep_head.next); -+ -+ callback(kctx->kbdev, entry); -+ } -+} -+ -+/** -+ * jsctx_queue_foreach(): - Execute callback for each entry in every queue -+ * @kctx: Pointer to kbase context with queue. -+ * @js: Job slot id to iterate. -+ * @callback: Function pointer to callback. -+ * -+ * Iterate over all the different priorities, and for each call -+ * jsctx_queue_foreach_prio() to iterate over the queue and invoke @callback -+ * for each entry, and remove the entry from the queue. -+ */ -+static inline void -+jsctx_queue_foreach(struct kbase_context *kctx, int js, -+ kbasep_js_ctx_job_cb callback) -+{ -+ int prio; -+ -+ for (prio = 0; prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++) -+ jsctx_queue_foreach_prio(kctx, js, prio, callback); -+} -+ -+/** -+ * jsctx_rb_peek_prio(): - Check buffer and get next atom -+ * @kctx: Pointer to kbase context with ring buffer. -+ * @js: Job slot id to check. -+ * @prio: Priority id to check. -+ * -+ * Check the ring buffer for the specified @js and @prio and return a pointer to -+ * the next atom, unless the ring buffer is empty. -+ * -+ * Return: Pointer to next atom in buffer, or NULL if there is no atom. -+ */ -+static inline struct kbase_jd_atom * -+jsctx_rb_peek_prio(struct kbase_context *kctx, int js, int prio) -+{ -+ struct jsctx_queue *rb = &kctx->jsctx_queue[prio][js]; -+ struct rb_node *node; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ node = rb_first(&rb->runnable_tree); -+ if (!node) -+ return NULL; -+ -+ return rb_entry(node, struct kbase_jd_atom, runnable_tree_node); -+} -+ -+/** -+ * jsctx_rb_peek(): - Check all priority buffers and get next atom -+ * @kctx: Pointer to kbase context with ring buffer. -+ * @js: Job slot id to check. -+ * -+ * Check the ring buffers for all priorities, starting from -+ * KBASE_JS_ATOM_SCHED_PRIO_HIGH, for the specified @js and @prio and return a -+ * pointer to the next atom, unless all the priority's ring buffers are empty. -+ * -+ * Caller must hold the hwaccess_lock. -+ * -+ * Return: Pointer to next atom in buffer, or NULL if there is no atom. -+ */ -+static inline struct kbase_jd_atom * -+jsctx_rb_peek(struct kbase_context *kctx, int js) -+{ -+ int prio; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ for (prio = 0; prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++) { -+ struct kbase_jd_atom *katom; -+ -+ katom = jsctx_rb_peek_prio(kctx, js, prio); -+ if (katom) -+ return katom; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * jsctx_rb_pull(): - Mark atom in list as running -+ * @kctx: Pointer to kbase context with ring buffer. -+ * @katom: Pointer to katom to pull. -+ * -+ * Mark an atom previously obtained from jsctx_rb_peek() as running. -+ * -+ * @katom must currently be at the head of the ring buffer. -+ */ -+static inline void -+jsctx_rb_pull(struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ int prio = katom->sched_priority; -+ int js = katom->slot_nr; -+ struct jsctx_queue *rb = &kctx->jsctx_queue[prio][js]; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ /* Atoms must be pulled in the correct order. */ -+ WARN_ON(katom != jsctx_rb_peek_prio(kctx, js, prio)); -+ -+ rb_erase(&katom->runnable_tree_node, &rb->runnable_tree); -+} -+ -+#define LESS_THAN_WRAP(a, b) ((s32)(a - b) < 0) -+ -+static void -+jsctx_tree_add(struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ int prio = katom->sched_priority; -+ int js = katom->slot_nr; -+ struct jsctx_queue *queue = &kctx->jsctx_queue[prio][js]; -+ struct rb_node **new = &(queue->runnable_tree.rb_node), *parent = NULL; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ while (*new) { -+ struct kbase_jd_atom *entry = container_of(*new, -+ struct kbase_jd_atom, runnable_tree_node); -+ -+ parent = *new; -+ if (LESS_THAN_WRAP(katom->age, entry->age)) -+ new = &((*new)->rb_left); -+ else -+ new = &((*new)->rb_right); -+ } -+ -+ /* Add new node and rebalance tree. */ -+ rb_link_node(&katom->runnable_tree_node, parent, new); -+ rb_insert_color(&katom->runnable_tree_node, &queue->runnable_tree); -+} -+ -+/** -+ * jsctx_rb_unpull(): - Undo marking of atom in list as running -+ * @kctx: Pointer to kbase context with ring buffer. -+ * @katom: Pointer to katom to unpull. -+ * -+ * Undo jsctx_rb_pull() and put @katom back in the queue. -+ * -+ * jsctx_rb_unpull() must be called on atoms in the same order the atoms were -+ * pulled. -+ */ -+static inline void -+jsctx_rb_unpull(struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ jsctx_tree_add(kctx, katom); -+} -+ -+static bool kbase_js_ctx_pullable(struct kbase_context *kctx, -+ int js, -+ bool is_scheduled); -+static bool kbase_js_ctx_list_add_pullable_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js); -+static bool kbase_js_ctx_list_add_unpullable_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js); -+ -+/* -+ * Functions private to KBase ('Protected' functions) -+ */ -+int kbasep_js_devdata_init(struct kbase_device * const kbdev) -+{ -+ struct kbasep_js_device_data *jsdd; -+ int i; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ jsdd = &kbdev->js_data; -+ -+#ifdef CONFIG_MALI_DEBUG -+ /* Soft-stop will be disabled on a single context by default unless -+ * softstop_always is set */ -+ jsdd->softstop_always = false; -+#endif /* CONFIG_MALI_DEBUG */ -+ jsdd->nr_all_contexts_running = 0; -+ jsdd->nr_user_contexts_running = 0; -+ jsdd->nr_contexts_pullable = 0; -+ atomic_set(&jsdd->nr_contexts_runnable, 0); -+ /* No ctx allowed to submit */ -+ jsdd->runpool_irq.submit_allowed = 0u; -+ memset(jsdd->runpool_irq.ctx_attr_ref_count, 0, -+ sizeof(jsdd->runpool_irq.ctx_attr_ref_count)); -+ memset(jsdd->runpool_irq.slot_affinities, 0, -+ sizeof(jsdd->runpool_irq.slot_affinities)); -+ memset(jsdd->runpool_irq.slot_affinity_refcount, 0, -+ sizeof(jsdd->runpool_irq.slot_affinity_refcount)); -+ INIT_LIST_HEAD(&jsdd->suspended_soft_jobs_list); -+ -+ /* Config attributes */ -+ jsdd->scheduling_period_ns = DEFAULT_JS_SCHEDULING_PERIOD_NS; -+ jsdd->soft_stop_ticks = DEFAULT_JS_SOFT_STOP_TICKS; -+ jsdd->soft_stop_ticks_cl = DEFAULT_JS_SOFT_STOP_TICKS_CL; -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408)) -+ jsdd->hard_stop_ticks_ss = DEFAULT_JS_HARD_STOP_TICKS_SS_8408; -+ else -+ jsdd->hard_stop_ticks_ss = DEFAULT_JS_HARD_STOP_TICKS_SS; -+ jsdd->hard_stop_ticks_cl = DEFAULT_JS_HARD_STOP_TICKS_CL; -+ jsdd->hard_stop_ticks_dumping = DEFAULT_JS_HARD_STOP_TICKS_DUMPING; -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408)) -+ jsdd->gpu_reset_ticks_ss = DEFAULT_JS_RESET_TICKS_SS_8408; -+ else -+ jsdd->gpu_reset_ticks_ss = DEFAULT_JS_RESET_TICKS_SS; -+ jsdd->gpu_reset_ticks_cl = DEFAULT_JS_RESET_TICKS_CL; -+ jsdd->gpu_reset_ticks_dumping = DEFAULT_JS_RESET_TICKS_DUMPING; -+ jsdd->ctx_timeslice_ns = DEFAULT_JS_CTX_TIMESLICE_NS; -+ atomic_set(&jsdd->soft_job_timeout_ms, DEFAULT_JS_SOFT_JOB_TIMEOUT); -+ -+ dev_dbg(kbdev->dev, "JS Config Attribs: "); -+ dev_dbg(kbdev->dev, "\tscheduling_period_ns:%u", -+ jsdd->scheduling_period_ns); -+ dev_dbg(kbdev->dev, "\tsoft_stop_ticks:%u", -+ jsdd->soft_stop_ticks); -+ dev_dbg(kbdev->dev, "\tsoft_stop_ticks_cl:%u", -+ jsdd->soft_stop_ticks_cl); -+ dev_dbg(kbdev->dev, "\thard_stop_ticks_ss:%u", -+ jsdd->hard_stop_ticks_ss); -+ dev_dbg(kbdev->dev, "\thard_stop_ticks_cl:%u", -+ jsdd->hard_stop_ticks_cl); -+ dev_dbg(kbdev->dev, "\thard_stop_ticks_dumping:%u", -+ jsdd->hard_stop_ticks_dumping); -+ dev_dbg(kbdev->dev, "\tgpu_reset_ticks_ss:%u", -+ jsdd->gpu_reset_ticks_ss); -+ dev_dbg(kbdev->dev, "\tgpu_reset_ticks_cl:%u", -+ jsdd->gpu_reset_ticks_cl); -+ dev_dbg(kbdev->dev, "\tgpu_reset_ticks_dumping:%u", -+ jsdd->gpu_reset_ticks_dumping); -+ dev_dbg(kbdev->dev, "\tctx_timeslice_ns:%u", -+ jsdd->ctx_timeslice_ns); -+ dev_dbg(kbdev->dev, "\tsoft_job_timeout:%i", -+ atomic_read(&jsdd->soft_job_timeout_ms)); -+ -+ if (!(jsdd->soft_stop_ticks < jsdd->hard_stop_ticks_ss && -+ jsdd->hard_stop_ticks_ss < jsdd->gpu_reset_ticks_ss && -+ jsdd->soft_stop_ticks < jsdd->hard_stop_ticks_dumping && -+ jsdd->hard_stop_ticks_dumping < -+ jsdd->gpu_reset_ticks_dumping)) { -+ dev_err(kbdev->dev, "Job scheduler timeouts invalid; soft/hard/reset tick counts should be in increasing order\n"); -+ return -EINVAL; -+ } -+ -+#if KBASE_DISABLE_SCHEDULING_SOFT_STOPS -+ dev_dbg(kbdev->dev, "Job Scheduling Soft-stops disabled, ignoring value for soft_stop_ticks==%u at %uns per tick. Other soft-stops may still occur.", -+ jsdd->soft_stop_ticks, -+ jsdd->scheduling_period_ns); -+#endif -+#if KBASE_DISABLE_SCHEDULING_HARD_STOPS -+ dev_dbg(kbdev->dev, "Job Scheduling Hard-stops disabled, ignoring values for hard_stop_ticks_ss==%d and hard_stop_ticks_dumping==%u at %uns per tick. Other hard-stops may still occur.", -+ jsdd->hard_stop_ticks_ss, -+ jsdd->hard_stop_ticks_dumping, -+ jsdd->scheduling_period_ns); -+#endif -+#if KBASE_DISABLE_SCHEDULING_SOFT_STOPS && KBASE_DISABLE_SCHEDULING_HARD_STOPS -+ dev_dbg(kbdev->dev, "Note: The JS tick timer (if coded) will still be run, but do nothing."); -+#endif -+ -+ for (i = 0; i < kbdev->gpu_props.num_job_slots; ++i) -+ jsdd->js_reqs[i] = core_reqs_from_jsn_features( -+ kbdev->gpu_props.props.raw_props.js_features[i]); -+ -+ /* On error, we could continue on: providing none of the below resources -+ * rely on the ones above */ -+ -+ mutex_init(&jsdd->runpool_mutex); -+ mutex_init(&jsdd->queue_mutex); -+ spin_lock_init(&kbdev->hwaccess_lock); -+ sema_init(&jsdd->schedule_sem, 1); -+ -+ for (i = 0; i < kbdev->gpu_props.num_job_slots; ++i) { -+ INIT_LIST_HEAD(&jsdd->ctx_list_pullable[i]); -+ INIT_LIST_HEAD(&jsdd->ctx_list_unpullable[i]); -+ } -+ -+ return 0; -+} -+ -+void kbasep_js_devdata_halt(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+void kbasep_js_devdata_term(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ s8 zero_ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_COUNT] = { 0, }; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ js_devdata = &kbdev->js_data; -+ -+ /* The caller must de-register all contexts before calling this -+ */ -+ KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running == 0); -+ KBASE_DEBUG_ASSERT(memcmp( -+ js_devdata->runpool_irq.ctx_attr_ref_count, -+ zero_ctx_attr_ref_count, -+ sizeof(zero_ctx_attr_ref_count)) == 0); -+ CSTD_UNUSED(zero_ctx_attr_ref_count); -+} -+ -+int kbasep_js_kctx_init(struct kbase_context * const kctx) -+{ -+ struct kbase_device *kbdev; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ int i, j; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ kbdev = kctx->kbdev; -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ for (i = 0; i < BASE_JM_MAX_NR_SLOTS; ++i) -+ INIT_LIST_HEAD(&kctx->jctx.sched_info.ctx.ctx_list_entry[i]); -+ -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ js_kctx_info->ctx.nr_jobs = 0; -+ kbase_ctx_flag_clear(kctx, KCTX_SCHEDULED); -+ kbase_ctx_flag_clear(kctx, KCTX_DYING); -+ memset(js_kctx_info->ctx.ctx_attr_ref_count, 0, -+ sizeof(js_kctx_info->ctx.ctx_attr_ref_count)); -+ -+ /* Initially, the context is disabled from submission until the create -+ * flags are set */ -+ kbase_ctx_flag_set(kctx, KCTX_SUBMIT_DISABLED); -+ -+ /* On error, we could continue on: providing none of the below resources -+ * rely on the ones above */ -+ mutex_init(&js_kctx_info->ctx.jsctx_mutex); -+ -+ init_waitqueue_head(&js_kctx_info->ctx.is_scheduled_wait); -+ -+ for (i = 0; i < KBASE_JS_ATOM_SCHED_PRIO_COUNT; i++) { -+ for (j = 0; j < BASE_JM_MAX_NR_SLOTS; j++) { -+ INIT_LIST_HEAD(&kctx->jsctx_queue[i][j].x_dep_head); -+ kctx->jsctx_queue[i][j].runnable_tree = RB_ROOT; -+ } -+ } -+ -+ return 0; -+} -+ -+void kbasep_js_kctx_term(struct kbase_context *kctx) -+{ -+ struct kbase_device *kbdev; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ int js; -+ bool update_ctx_count = false; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ kbdev = kctx->kbdev; -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ /* The caller must de-register all jobs before calling this */ -+ KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ KBASE_DEBUG_ASSERT(js_kctx_info->ctx.nr_jobs == 0); -+ -+ mutex_lock(&kbdev->js_data.queue_mutex); -+ mutex_lock(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) -+ list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]); -+ -+ if (kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)) { -+ WARN_ON(atomic_read(&kbdev->js_data.nr_contexts_runnable) <= 0); -+ atomic_dec(&kbdev->js_data.nr_contexts_runnable); -+ update_ctx_count = true; -+ kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF); -+ } -+ -+ mutex_unlock(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ mutex_unlock(&kbdev->js_data.queue_mutex); -+ -+ if (update_ctx_count) { -+ mutex_lock(&kbdev->js_data.runpool_mutex); -+ kbase_backend_ctx_count_changed(kbdev); -+ mutex_unlock(&kbdev->js_data.runpool_mutex); -+ } -+} -+ -+/** -+ * kbase_js_ctx_list_add_pullable_nolock - Variant of -+ * kbase_jd_ctx_list_add_pullable() -+ * where the caller must hold -+ * hwaccess_lock -+ * @kbdev: Device pointer -+ * @kctx: Context to add to queue -+ * @js: Job slot to use -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: true if caller should call kbase_backend_ctx_count_changed() -+ */ -+static bool kbase_js_ctx_list_add_pullable_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js) -+{ -+ bool ret = false; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (!list_empty(&kctx->jctx.sched_info.ctx.ctx_list_entry[js])) -+ list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]); -+ -+ list_add_tail(&kctx->jctx.sched_info.ctx.ctx_list_entry[js], -+ &kbdev->js_data.ctx_list_pullable[js]); -+ -+ if (!kctx->slots_pullable) { -+ kbdev->js_data.nr_contexts_pullable++; -+ ret = true; -+ if (!atomic_read(&kctx->atoms_pulled)) { -+ WARN_ON(kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)); -+ kbase_ctx_flag_set(kctx, KCTX_RUNNABLE_REF); -+ atomic_inc(&kbdev->js_data.nr_contexts_runnable); -+ } -+ } -+ kctx->slots_pullable |= (1 << js); -+ -+ return ret; -+} -+ -+/** -+ * kbase_js_ctx_list_add_pullable_head_nolock - Variant of -+ * kbase_js_ctx_list_add_pullable_head() -+ * where the caller must hold -+ * hwaccess_lock -+ * @kbdev: Device pointer -+ * @kctx: Context to add to queue -+ * @js: Job slot to use -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: true if caller should call kbase_backend_ctx_count_changed() -+ */ -+static bool kbase_js_ctx_list_add_pullable_head_nolock( -+ struct kbase_device *kbdev, struct kbase_context *kctx, int js) -+{ -+ bool ret = false; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (!list_empty(&kctx->jctx.sched_info.ctx.ctx_list_entry[js])) -+ list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]); -+ -+ list_add(&kctx->jctx.sched_info.ctx.ctx_list_entry[js], -+ &kbdev->js_data.ctx_list_pullable[js]); -+ -+ if (!kctx->slots_pullable) { -+ kbdev->js_data.nr_contexts_pullable++; -+ ret = true; -+ if (!atomic_read(&kctx->atoms_pulled)) { -+ WARN_ON(kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)); -+ kbase_ctx_flag_set(kctx, KCTX_RUNNABLE_REF); -+ atomic_inc(&kbdev->js_data.nr_contexts_runnable); -+ } -+ } -+ kctx->slots_pullable |= (1 << js); -+ -+ return ret; -+} -+ -+/** -+ * kbase_js_ctx_list_add_pullable_head - Add context to the head of the -+ * per-slot pullable context queue -+ * @kbdev: Device pointer -+ * @kctx: Context to add to queue -+ * @js: Job slot to use -+ * -+ * If the context is on either the pullable or unpullable queues, then it is -+ * removed before being added to the head. -+ * -+ * This function should be used when a context has been scheduled, but no jobs -+ * can currently be pulled from it. -+ * -+ * Return: true if caller should call kbase_backend_ctx_count_changed() -+ */ -+static bool kbase_js_ctx_list_add_pullable_head(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js) -+{ -+ bool ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ ret = kbase_js_ctx_list_add_pullable_head_nolock(kbdev, kctx, js); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return ret; -+} -+ -+/** -+ * kbase_js_ctx_list_add_unpullable_nolock - Add context to the tail of the -+ * per-slot unpullable context queue -+ * @kbdev: Device pointer -+ * @kctx: Context to add to queue -+ * @js: Job slot to use -+ * -+ * The context must already be on the per-slot pullable queue. It will be -+ * removed from the pullable queue before being added to the unpullable queue. -+ * -+ * This function should be used when a context has been pulled from, and there -+ * are no jobs remaining on the specified slot. -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: true if caller should call kbase_backend_ctx_count_changed() -+ */ -+static bool kbase_js_ctx_list_add_unpullable_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js) -+{ -+ bool ret = false; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ list_move_tail(&kctx->jctx.sched_info.ctx.ctx_list_entry[js], -+ &kbdev->js_data.ctx_list_unpullable[js]); -+ -+ if (kctx->slots_pullable == (1 << js)) { -+ kbdev->js_data.nr_contexts_pullable--; -+ ret = true; -+ if (!atomic_read(&kctx->atoms_pulled)) { -+ WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)); -+ kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF); -+ atomic_dec(&kbdev->js_data.nr_contexts_runnable); -+ } -+ } -+ kctx->slots_pullable &= ~(1 << js); -+ -+ return ret; -+} -+ -+/** -+ * kbase_js_ctx_list_remove_nolock - Remove context from the per-slot pullable -+ * or unpullable context queues -+ * @kbdev: Device pointer -+ * @kctx: Context to remove from queue -+ * @js: Job slot to use -+ * -+ * The context must already be on one of the queues. -+ * -+ * This function should be used when a context has no jobs on the GPU, and no -+ * jobs remaining for the specified slot. -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: true if caller should call kbase_backend_ctx_count_changed() -+ */ -+static bool kbase_js_ctx_list_remove_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ int js) -+{ -+ bool ret = false; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ WARN_ON(list_empty(&kctx->jctx.sched_info.ctx.ctx_list_entry[js])); -+ -+ list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]); -+ -+ if (kctx->slots_pullable == (1 << js)) { -+ kbdev->js_data.nr_contexts_pullable--; -+ ret = true; -+ if (!atomic_read(&kctx->atoms_pulled)) { -+ WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)); -+ kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF); -+ atomic_dec(&kbdev->js_data.nr_contexts_runnable); -+ } -+ } -+ kctx->slots_pullable &= ~(1 << js); -+ -+ return ret; -+} -+ -+/** -+ * kbase_js_ctx_list_pop_head_nolock - Variant of kbase_js_ctx_list_pop_head() -+ * where the caller must hold -+ * hwaccess_lock -+ * @kbdev: Device pointer -+ * @js: Job slot to use -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: Context to use for specified slot. -+ * NULL if no contexts present for specified slot -+ */ -+static struct kbase_context *kbase_js_ctx_list_pop_head_nolock( -+ struct kbase_device *kbdev, -+ int js) -+{ -+ struct kbase_context *kctx; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (list_empty(&kbdev->js_data.ctx_list_pullable[js])) -+ return NULL; -+ -+ kctx = list_entry(kbdev->js_data.ctx_list_pullable[js].next, -+ struct kbase_context, -+ jctx.sched_info.ctx.ctx_list_entry[js]); -+ -+ list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]); -+ -+ return kctx; -+} -+ -+/** -+ * kbase_js_ctx_list_pop_head - Pop the head context off the per-slot pullable -+ * queue. -+ * @kbdev: Device pointer -+ * @js: Job slot to use -+ * -+ * Return: Context to use for specified slot. -+ * NULL if no contexts present for specified slot -+ */ -+static struct kbase_context *kbase_js_ctx_list_pop_head( -+ struct kbase_device *kbdev, int js) -+{ -+ struct kbase_context *kctx; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kctx = kbase_js_ctx_list_pop_head_nolock(kbdev, js); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return kctx; -+} -+ -+/** -+ * kbase_js_ctx_pullable - Return if a context can be pulled from on the -+ * specified slot -+ * @kctx: Context pointer -+ * @js: Job slot to use -+ * @is_scheduled: true if the context is currently scheduled -+ * -+ * Caller must hold hwaccess_lock -+ * -+ * Return: true if context can be pulled from on specified slot -+ * false otherwise -+ */ -+static bool kbase_js_ctx_pullable(struct kbase_context *kctx, int js, -+ bool is_scheduled) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbase_jd_atom *katom; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ js_devdata = &kctx->kbdev->js_data; -+ -+ if (is_scheduled) { -+ if (!kbasep_js_is_submit_allowed(js_devdata, kctx)) -+ return false; -+ } -+ katom = jsctx_rb_peek(kctx, js); -+ if (!katom) -+ return false; /* No pullable atoms */ -+ if (kctx->blocked_js[js][katom->sched_priority]) -+ return false; -+ if (atomic_read(&katom->blocked)) -+ return false; /* next atom blocked */ -+ if (katom->atom_flags & KBASE_KATOM_FLAG_X_DEP_BLOCKED) { -+ if (katom->x_pre_dep->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB || -+ katom->x_pre_dep->will_fail_event_code) -+ return false; -+ if ((katom->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER) && -+ kbase_backend_nr_atoms_on_slot(kctx->kbdev, js)) -+ return false; -+ } -+ -+ return true; -+} -+ -+static bool kbase_js_dep_validate(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ bool ret = true; -+ bool has_dep = false, has_x_dep = false; -+ int js = kbase_js_get_slot(kbdev, katom); -+ int prio = katom->sched_priority; -+ int i; -+ -+ for (i = 0; i < 2; i++) { -+ struct kbase_jd_atom *dep_atom = katom->dep[i].atom; -+ -+ if (dep_atom) { -+ int dep_js = kbase_js_get_slot(kbdev, dep_atom); -+ int dep_prio = dep_atom->sched_priority; -+ -+ /* Dependent atom must already have been submitted */ -+ if (!(dep_atom->atom_flags & -+ KBASE_KATOM_FLAG_JSCTX_IN_TREE)) { -+ ret = false; -+ break; -+ } -+ -+ /* Dependencies with different priorities can't -+ be represented in the ringbuffer */ -+ if (prio != dep_prio) { -+ ret = false; -+ break; -+ } -+ -+ if (js == dep_js) { -+ /* Only one same-slot dependency can be -+ * represented in the ringbuffer */ -+ if (has_dep) { -+ ret = false; -+ break; -+ } -+ /* Each dependee atom can only have one -+ * same-slot dependency */ -+ if (dep_atom->post_dep) { -+ ret = false; -+ break; -+ } -+ has_dep = true; -+ } else { -+ /* Only one cross-slot dependency can be -+ * represented in the ringbuffer */ -+ if (has_x_dep) { -+ ret = false; -+ break; -+ } -+ /* Each dependee atom can only have one -+ * cross-slot dependency */ -+ if (dep_atom->x_post_dep) { -+ ret = false; -+ break; -+ } -+ /* The dependee atom can not already be in the -+ * HW access ringbuffer */ -+ if (dep_atom->gpu_rb_state != -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB) { -+ ret = false; -+ break; -+ } -+ /* The dependee atom can not already have -+ * completed */ -+ if (dep_atom->status != -+ KBASE_JD_ATOM_STATE_IN_JS) { -+ ret = false; -+ break; -+ } -+ /* Cross-slot dependencies must not violate -+ * PRLAM-8987 affinity restrictions */ -+ if (kbase_hw_has_issue(kbdev, -+ BASE_HW_ISSUE_8987) && -+ (js == 2 || dep_js == 2)) { -+ ret = false; -+ break; -+ } -+ has_x_dep = true; -+ } -+ -+ /* Dependency can be represented in ringbuffers */ -+ } -+ } -+ -+ /* If dependencies can be represented by ringbuffer then clear them from -+ * atom structure */ -+ if (ret) { -+ for (i = 0; i < 2; i++) { -+ struct kbase_jd_atom *dep_atom = katom->dep[i].atom; -+ -+ if (dep_atom) { -+ int dep_js = kbase_js_get_slot(kbdev, dep_atom); -+ -+ if ((js != dep_js) && -+ (dep_atom->status != -+ KBASE_JD_ATOM_STATE_COMPLETED) -+ && (dep_atom->status != -+ KBASE_JD_ATOM_STATE_HW_COMPLETED) -+ && (dep_atom->status != -+ KBASE_JD_ATOM_STATE_UNUSED)) { -+ -+ katom->atom_flags |= -+ KBASE_KATOM_FLAG_X_DEP_BLOCKED; -+ katom->x_pre_dep = dep_atom; -+ dep_atom->x_post_dep = katom; -+ if (kbase_jd_katom_dep_type( -+ &katom->dep[i]) == -+ BASE_JD_DEP_TYPE_DATA) -+ katom->atom_flags |= -+ KBASE_KATOM_FLAG_FAIL_BLOCKER; -+ } -+ if ((kbase_jd_katom_dep_type(&katom->dep[i]) -+ == BASE_JD_DEP_TYPE_DATA) && -+ (js == dep_js)) { -+ katom->pre_dep = dep_atom; -+ dep_atom->post_dep = katom; -+ } -+ -+ list_del(&katom->dep_item[i]); -+ kbase_jd_katom_dep_clear(&katom->dep[i]); -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+bool kbasep_js_add_job(struct kbase_context *kctx, -+ struct kbase_jd_atom *atom) -+{ -+ unsigned long flags; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ struct kbase_device *kbdev; -+ struct kbasep_js_device_data *js_devdata; -+ -+ bool enqueue_required = false; -+ bool timer_sync = false; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(atom != NULL); -+ lockdep_assert_held(&kctx->jctx.lock); -+ -+ kbdev = kctx->kbdev; -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ mutex_lock(&js_devdata->queue_mutex); -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ /* -+ * Begin Runpool transaction -+ */ -+ mutex_lock(&js_devdata->runpool_mutex); -+ -+ /* Refcount ctx.nr_jobs */ -+ KBASE_DEBUG_ASSERT(js_kctx_info->ctx.nr_jobs < U32_MAX); -+ ++(js_kctx_info->ctx.nr_jobs); -+ -+ /* Setup any scheduling information */ -+ kbasep_js_clear_job_retry_submit(atom); -+ -+ /* Lock for state available during IRQ */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ if (!kbase_js_dep_validate(kctx, atom)) { -+ /* Dependencies could not be represented */ -+ --(js_kctx_info->ctx.nr_jobs); -+ -+ /* Setting atom status back to queued as it still has unresolved -+ * dependencies */ -+ atom->status = KBASE_JD_ATOM_STATE_QUEUED; -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ goto out_unlock; -+ } -+ -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(atom, TL_ATOM_STATE_READY); -+ KBASE_TIMELINE_ATOM_READY(kctx, kbase_jd_atom_id(kctx, atom)); -+ -+ enqueue_required = kbase_js_dep_resolved_submit(kctx, atom); -+ -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, JS_ADD_JOB, kctx, atom, atom->jc, -+ kbasep_js_trace_get_refcnt(kbdev, kctx)); -+ -+ /* Context Attribute Refcounting */ -+ kbasep_js_ctx_attr_ctx_retain_atom(kbdev, kctx, atom); -+ -+ if (enqueue_required) { -+ if (kbase_js_ctx_pullable(kctx, atom->slot_nr, false)) -+ timer_sync = kbase_js_ctx_list_add_pullable_nolock( -+ kbdev, kctx, atom->slot_nr); -+ else -+ timer_sync = kbase_js_ctx_list_add_unpullable_nolock( -+ kbdev, kctx, atom->slot_nr); -+ } -+ /* If this context is active and the atom is the first on its slot, -+ * kick the job manager to attempt to fast-start the atom */ -+ if (enqueue_required && kctx == kbdev->hwaccess.active_kctx) -+ kbase_jm_try_kick(kbdev, 1 << atom->slot_nr); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ if (timer_sync) -+ kbase_backend_ctx_count_changed(kbdev); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ /* End runpool transaction */ -+ -+ if (!kbase_ctx_flag(kctx, KCTX_SCHEDULED)) { -+ if (kbase_ctx_flag(kctx, KCTX_DYING)) { -+ /* A job got added while/after kbase_job_zap_context() -+ * was called on a non-scheduled context (e.g. KDS -+ * dependency resolved). Kill that job by killing the -+ * context. */ -+ kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx, -+ false); -+ } else if (js_kctx_info->ctx.nr_jobs == 1) { -+ /* Handle Refcount going from 0 to 1: schedule the -+ * context on the Queue */ -+ KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ dev_dbg(kbdev->dev, "JS: Enqueue Context %p", kctx); -+ -+ /* Queue was updated - caller must try to -+ * schedule the head context */ -+ WARN_ON(!enqueue_required); -+ } -+ } -+out_unlock: -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ mutex_unlock(&js_devdata->queue_mutex); -+ -+ return enqueue_required; -+} -+ -+void kbasep_js_remove_job(struct kbase_device *kbdev, -+ struct kbase_context *kctx, struct kbase_jd_atom *atom) -+{ -+ struct kbasep_js_kctx_info *js_kctx_info; -+ struct kbasep_js_device_data *js_devdata; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(atom != NULL); -+ -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, JS_REMOVE_JOB, kctx, atom, atom->jc, -+ kbasep_js_trace_get_refcnt(kbdev, kctx)); -+ -+ /* De-refcount ctx.nr_jobs */ -+ KBASE_DEBUG_ASSERT(js_kctx_info->ctx.nr_jobs > 0); -+ --(js_kctx_info->ctx.nr_jobs); -+} -+ -+bool kbasep_js_remove_cancelled_job(struct kbase_device *kbdev, -+ struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ unsigned long flags; -+ struct kbasep_js_atom_retained_state katom_retained_state; -+ struct kbasep_js_device_data *js_devdata; -+ bool attr_state_changed; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(katom != NULL); -+ -+ js_devdata = &kbdev->js_data; -+ -+ kbasep_js_atom_retained_state_copy(&katom_retained_state, katom); -+ kbasep_js_remove_job(kbdev, kctx, katom); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* The atom has 'finished' (will not be re-run), so no need to call -+ * kbasep_js_has_atom_finished(). -+ * -+ * This is because it returns false for soft-stopped atoms, but we -+ * want to override that, because we're cancelling an atom regardless of -+ * whether it was soft-stopped or not */ -+ attr_state_changed = kbasep_js_ctx_attr_ctx_release_atom(kbdev, kctx, -+ &katom_retained_state); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return attr_state_changed; -+} -+ -+bool kbasep_js_runpool_retain_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ unsigned long flags; -+ struct kbasep_js_device_data *js_devdata; -+ bool result; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ js_devdata = &kbdev->js_data; -+ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ result = kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ return result; -+} -+ -+struct kbase_context *kbasep_js_runpool_lookup_ctx(struct kbase_device *kbdev, -+ int as_nr) -+{ -+ unsigned long flags; -+ struct kbasep_js_device_data *js_devdata; -+ struct kbase_context *found_kctx = NULL; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(0 <= as_nr && as_nr < BASE_MAX_NR_AS); -+ js_devdata = &kbdev->js_data; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ found_kctx = kbdev->as_to_kctx[as_nr]; -+ -+ if (found_kctx != NULL) -+ kbase_ctx_sched_retain_ctx_refcount(found_kctx); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return found_kctx; -+} -+ -+/** -+ * kbasep_js_release_result - Try running more jobs after releasing a context -+ * and/or atom -+ * -+ * @kbdev: The kbase_device to operate on -+ * @kctx: The kbase_context to operate on -+ * @katom_retained_state: Retained state from the atom -+ * @runpool_ctx_attr_change: True if the runpool context attributes have changed -+ * -+ * This collates a set of actions that must happen whilst hwaccess_lock is held. -+ * -+ * This includes running more jobs when: -+ * - The previously released kctx caused a ctx attribute change, -+ * - The released atom caused a ctx attribute change, -+ * - Slots were previously blocked due to affinity restrictions, -+ * - Submission during IRQ handling failed. -+ * -+ * Return: %KBASEP_JS_RELEASE_RESULT_SCHED_ALL if context attributes were -+ * changed. The caller should try scheduling all contexts -+ */ -+static kbasep_js_release_result kbasep_js_run_jobs_after_ctx_and_atom_release( -+ struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ struct kbasep_js_atom_retained_state *katom_retained_state, -+ bool runpool_ctx_attr_change) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ kbasep_js_release_result result = 0; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(katom_retained_state != NULL); -+ js_devdata = &kbdev->js_data; -+ -+ lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ lockdep_assert_held(&js_devdata->runpool_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (js_devdata->nr_user_contexts_running != 0) { -+ bool retry_submit = false; -+ int retry_jobslot = 0; -+ -+ if (katom_retained_state) -+ retry_submit = kbasep_js_get_atom_retry_submit_slot( -+ katom_retained_state, &retry_jobslot); -+ -+ if (runpool_ctx_attr_change || retry_submit) { -+ /* A change in runpool ctx attributes might mean we can -+ * run more jobs than before */ -+ result = KBASEP_JS_RELEASE_RESULT_SCHED_ALL; -+ -+ KBASE_TRACE_ADD_SLOT(kbdev, JD_DONE_TRY_RUN_NEXT_JOB, -+ kctx, NULL, 0u, retry_jobslot); -+ } -+ } -+ return result; -+} -+ -+/* -+ * Internal function to release the reference on a ctx and an atom's "retained -+ * state", only taking the runpool and as transaction mutexes -+ * -+ * This also starts more jobs running in the case of an ctx-attribute state -+ * change -+ * -+ * This does none of the followup actions for scheduling: -+ * - It does not schedule in a new context -+ * - It does not requeue or handle dying contexts -+ * -+ * For those tasks, just call kbasep_js_runpool_release_ctx() instead -+ * -+ * Requires: -+ * - Context is scheduled in, and kctx->as_nr matches kctx_as_nr -+ * - Context has a non-zero refcount -+ * - Caller holds js_kctx_info->ctx.jsctx_mutex -+ * - Caller holds js_devdata->runpool_mutex -+ */ -+static kbasep_js_release_result kbasep_js_runpool_release_ctx_internal( -+ struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ struct kbasep_js_atom_retained_state *katom_retained_state) -+{ -+ unsigned long flags; -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ -+ kbasep_js_release_result release_result = 0u; -+ bool runpool_ctx_attr_change = false; -+ int kctx_as_nr; -+ int new_ref_count; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ js_kctx_info = &kctx->jctx.sched_info; -+ js_devdata = &kbdev->js_data; -+ -+ /* Ensure context really is scheduled in */ -+ KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ kctx_as_nr = kctx->as_nr; -+ KBASE_DEBUG_ASSERT(kctx_as_nr != KBASEP_AS_NR_INVALID); -+ KBASE_DEBUG_ASSERT(atomic_read(&kctx->refcount) > 0); -+ -+ /* -+ * Transaction begins on AS and runpool_irq -+ * -+ * Assert about out calling contract -+ */ -+ mutex_lock(&kbdev->pm.lock); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ KBASE_DEBUG_ASSERT(kctx_as_nr == kctx->as_nr); -+ KBASE_DEBUG_ASSERT(atomic_read(&kctx->refcount) > 0); -+ -+ /* Update refcount */ -+ kbase_ctx_sched_release_ctx(kctx); -+ new_ref_count = atomic_read(&kctx->refcount); -+ -+ /* Release the atom if it finished (i.e. wasn't soft-stopped) */ -+ if (kbasep_js_has_atom_finished(katom_retained_state)) -+ runpool_ctx_attr_change |= kbasep_js_ctx_attr_ctx_release_atom( -+ kbdev, kctx, katom_retained_state); -+ -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, JS_RELEASE_CTX, kctx, NULL, 0u, -+ new_ref_count); -+ -+ if (new_ref_count == 2 && kbase_ctx_flag(kctx, KCTX_PRIVILEGED) && -+ !kbase_pm_is_suspending(kbdev)) { -+ /* Context is kept scheduled into an address space even when -+ * there are no jobs, in this case we have to handle the -+ * situation where all jobs have been evicted from the GPU and -+ * submission is disabled. -+ * -+ * At this point we re-enable submission to allow further jobs -+ * to be executed -+ */ -+ kbasep_js_set_submit_allowed(js_devdata, kctx); -+ } -+ -+ /* Make a set of checks to see if the context should be scheduled out. -+ * Note that there'll always be at least 1 reference to the context -+ * which was previously acquired by kbasep_js_schedule_ctx(). */ -+ if (new_ref_count == 1 && -+ (!kbasep_js_is_submit_allowed(js_devdata, kctx) || -+ kbdev->pm.suspending)) { -+ int num_slots = kbdev->gpu_props.num_job_slots; -+ int slot; -+ -+ /* Last reference, and we've been told to remove this context -+ * from the Run Pool */ -+ dev_dbg(kbdev->dev, "JS: RunPool Remove Context %p because refcount=%d, jobs=%d, allowed=%d", -+ kctx, new_ref_count, js_kctx_info->ctx.nr_jobs, -+ kbasep_js_is_submit_allowed(js_devdata, kctx)); -+ -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_mmu_as_released(kctx->as_nr); -+#endif -+ KBASE_TLSTREAM_TL_NRET_AS_CTX(&kbdev->as[kctx->as_nr], kctx); -+ -+ kbase_backend_release_ctx_irq(kbdev, kctx); -+ -+ if (kbdev->hwaccess.active_kctx == kctx) -+ kbdev->hwaccess.active_kctx = NULL; -+ -+ /* Ctx Attribute handling -+ * -+ * Releasing atoms attributes must either happen before this, or -+ * after the KCTX_SHEDULED flag is changed, otherwise we -+ * double-decount the attributes -+ */ -+ runpool_ctx_attr_change |= -+ kbasep_js_ctx_attr_runpool_release_ctx(kbdev, kctx); -+ -+ /* Releasing the context and katom retained state can allow -+ * more jobs to run */ -+ release_result |= -+ kbasep_js_run_jobs_after_ctx_and_atom_release(kbdev, -+ kctx, katom_retained_state, -+ runpool_ctx_attr_change); -+ -+ /* -+ * Transaction ends on AS and runpool_irq: -+ * -+ * By this point, the AS-related data is now clear and ready -+ * for re-use. -+ * -+ * Since releases only occur once for each previous successful -+ * retain, and no more retains are allowed on this context, no -+ * other thread will be operating in this -+ * code whilst we are -+ */ -+ -+ /* Recalculate pullable status for all slots */ -+ for (slot = 0; slot < num_slots; slot++) { -+ if (kbase_js_ctx_pullable(kctx, slot, false)) -+ kbase_js_ctx_list_add_pullable_nolock(kbdev, -+ kctx, slot); -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ kbase_backend_release_ctx_noirq(kbdev, kctx); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ -+ /* Note: Don't reuse kctx_as_nr now */ -+ -+ /* Synchronize with any timers */ -+ kbase_backend_ctx_count_changed(kbdev); -+ -+ /* update book-keeping info */ -+ kbase_ctx_flag_clear(kctx, KCTX_SCHEDULED); -+ /* Signal any waiter that the context is not scheduled, so is -+ * safe for termination - once the jsctx_mutex is also dropped, -+ * and jobs have finished. */ -+ wake_up(&js_kctx_info->ctx.is_scheduled_wait); -+ -+ /* Queue an action to occur after we've dropped the lock */ -+ release_result |= KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED | -+ KBASEP_JS_RELEASE_RESULT_SCHED_ALL; -+ } else { -+ kbasep_js_run_jobs_after_ctx_and_atom_release(kbdev, kctx, -+ katom_retained_state, runpool_ctx_attr_change); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->pm.lock); -+ } -+ -+ return release_result; -+} -+ -+void kbasep_js_runpool_release_ctx_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_atom_retained_state katom_retained_state; -+ -+ /* Setup a dummy katom_retained_state */ -+ kbasep_js_atom_retained_state_init_invalid(&katom_retained_state); -+ -+ kbasep_js_runpool_release_ctx_internal(kbdev, kctx, -+ &katom_retained_state); -+} -+ -+void kbasep_js_runpool_requeue_or_kill_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx, bool has_pm_ref) -+{ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ /* This is called if and only if you've you've detached the context from -+ * the Runpool Queue, and not added it back to the Runpool -+ */ -+ KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ if (kbase_ctx_flag(kctx, KCTX_DYING)) { -+ /* Dying: don't requeue, but kill all jobs on the context. This -+ * happens asynchronously */ -+ dev_dbg(kbdev->dev, -+ "JS: ** Killing Context %p on RunPool Remove **", kctx); -+ kbase_js_foreach_ctx_job(kctx, &kbase_jd_cancel); -+ } -+} -+ -+void kbasep_js_runpool_release_ctx_and_katom_retained_state( -+ struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbasep_js_atom_retained_state *katom_retained_state) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ kbasep_js_release_result release_result; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ js_kctx_info = &kctx->jctx.sched_info; -+ js_devdata = &kbdev->js_data; -+ -+ mutex_lock(&js_devdata->queue_mutex); -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_lock(&js_devdata->runpool_mutex); -+ -+ release_result = kbasep_js_runpool_release_ctx_internal(kbdev, kctx, -+ katom_retained_state); -+ -+ /* Drop the runpool mutex to allow requeing kctx */ -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ if ((release_result & KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED) != 0u) -+ kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx, true); -+ -+ /* Drop the jsctx_mutex to allow scheduling in a new context */ -+ -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ -+ if (release_result & KBASEP_JS_RELEASE_RESULT_SCHED_ALL) -+ kbase_js_sched_all(kbdev); -+} -+ -+void kbasep_js_runpool_release_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_atom_retained_state katom_retained_state; -+ -+ kbasep_js_atom_retained_state_init_invalid(&katom_retained_state); -+ -+ kbasep_js_runpool_release_ctx_and_katom_retained_state(kbdev, kctx, -+ &katom_retained_state); -+} -+ -+/* Variant of kbasep_js_runpool_release_ctx() that doesn't call into -+ * kbase_js_sched_all() */ -+static void kbasep_js_runpool_release_ctx_no_schedule( -+ struct kbase_device *kbdev, struct kbase_context *kctx) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ kbasep_js_release_result release_result; -+ struct kbasep_js_atom_retained_state katom_retained_state_struct; -+ struct kbasep_js_atom_retained_state *katom_retained_state = -+ &katom_retained_state_struct; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ js_kctx_info = &kctx->jctx.sched_info; -+ js_devdata = &kbdev->js_data; -+ kbasep_js_atom_retained_state_init_invalid(katom_retained_state); -+ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_lock(&js_devdata->runpool_mutex); -+ -+ release_result = kbasep_js_runpool_release_ctx_internal(kbdev, kctx, -+ katom_retained_state); -+ -+ /* Drop the runpool mutex to allow requeing kctx */ -+ mutex_unlock(&js_devdata->runpool_mutex); -+ if ((release_result & KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED) != 0u) -+ kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx, true); -+ -+ /* Drop the jsctx_mutex to allow scheduling in a new context */ -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ /* NOTE: could return release_result if the caller would like to know -+ * whether it should schedule a new context, but currently no callers do -+ */ -+} -+ -+void kbase_js_set_timeouts(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ kbase_backend_timeouts_changed(kbdev); -+} -+ -+static bool kbasep_js_schedule_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ unsigned long flags; -+ bool kctx_suspended = false; -+ int as_nr; -+ -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ /* Pick available address space for this context */ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ as_nr = kbase_ctx_sched_retain_ctx(kctx); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ if (as_nr == KBASEP_AS_NR_INVALID) { -+ as_nr = kbase_backend_find_and_release_free_address_space( -+ kbdev, kctx); -+ if (as_nr != KBASEP_AS_NR_INVALID) { -+ /* Attempt to retain the context again, this should -+ * succeed */ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ as_nr = kbase_ctx_sched_retain_ctx(kctx); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ WARN_ON(as_nr == KBASEP_AS_NR_INVALID); -+ } -+ } -+ if (as_nr == KBASEP_AS_NR_INVALID) -+ return false; /* No address spaces currently available */ -+ -+ /* -+ * Atomic transaction on the Context and Run Pool begins -+ */ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* Check to see if context is dying due to kbase_job_zap_context() */ -+ if (kbase_ctx_flag(kctx, KCTX_DYING)) { -+ /* Roll back the transaction so far and return */ -+ kbase_ctx_sched_release_ctx(kctx); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ return false; -+ } -+ -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, JS_TRY_SCHEDULE_HEAD_CTX, kctx, NULL, -+ 0u, -+ kbasep_js_trace_get_refcnt(kbdev, kctx)); -+ -+ kbase_ctx_flag_set(kctx, KCTX_SCHEDULED); -+ -+ /* Assign context to previously chosen address space */ -+ if (!kbase_backend_use_ctx(kbdev, kctx, as_nr)) { -+ /* Roll back the transaction so far and return */ -+ kbase_ctx_sched_release_ctx(kctx); -+ kbase_ctx_flag_clear(kctx, KCTX_SCHEDULED); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ return false; -+ } -+ -+ kbdev->hwaccess.active_kctx = kctx; -+ -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_mmu_as_in_use(kctx->as_nr); -+#endif -+ KBASE_TLSTREAM_TL_RET_AS_CTX(&kbdev->as[kctx->as_nr], kctx); -+ -+ /* Cause any future waiter-on-termination to wait until the context is -+ * descheduled */ -+ wake_up(&js_kctx_info->ctx.is_scheduled_wait); -+ -+ /* Re-check for suspending: a suspend could've occurred, and all the -+ * contexts could've been removed from the runpool before we took this -+ * lock. In this case, we don't want to allow this context to run jobs, -+ * we just want it out immediately. -+ * -+ * The DMB required to read the suspend flag was issued recently as part -+ * of the hwaccess_lock locking. If a suspend occurs *after* that lock -+ * was taken (i.e. this condition doesn't execute), then the -+ * kbasep_js_suspend() code will cleanup this context instead (by virtue -+ * of it being called strictly after the suspend flag is set, and will -+ * wait for this lock to drop) */ -+ if (kbase_pm_is_suspending(kbdev)) { -+ /* Cause it to leave at some later point */ -+ bool retained; -+ -+ retained = kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx); -+ KBASE_DEBUG_ASSERT(retained); -+ -+ kbasep_js_clear_submit_allowed(js_devdata, kctx); -+ kctx_suspended = true; -+ } -+ -+ /* Transaction complete */ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ /* Synchronize with any timers */ -+ kbase_backend_ctx_count_changed(kbdev); -+ -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ /* Note: after this point, the context could potentially get scheduled -+ * out immediately */ -+ -+ if (kctx_suspended) { -+ /* Finishing forcing out the context due to a suspend. Use a -+ * variant of kbasep_js_runpool_release_ctx() that doesn't -+ * schedule a new context, to prevent a risk of recursion back -+ * into this function */ -+ kbasep_js_runpool_release_ctx_no_schedule(kbdev, kctx); -+ return false; -+ } -+ return true; -+} -+ -+static bool kbase_js_use_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ if (kbase_ctx_flag(kctx, KCTX_SCHEDULED) && -+ kbase_backend_use_ctx_sched(kbdev, kctx)) { -+ /* Context already has ASID - mark as active */ -+ kbdev->hwaccess.active_kctx = kctx; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ return true; /* Context already scheduled */ -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ return kbasep_js_schedule_ctx(kbdev, kctx); -+} -+ -+void kbasep_js_schedule_privileged_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_kctx_info *js_kctx_info; -+ struct kbasep_js_device_data *js_devdata; -+ bool is_scheduled; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ /* This must never be attempted whilst suspending - i.e. it should only -+ * happen in response to a syscall from a user-space thread */ -+ BUG_ON(kbase_pm_is_suspending(kbdev)); -+ -+ mutex_lock(&js_devdata->queue_mutex); -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ /* Mark the context as privileged */ -+ kbase_ctx_flag_set(kctx, KCTX_PRIVILEGED); -+ -+ is_scheduled = kbase_ctx_flag(kctx, KCTX_SCHEDULED); -+ if (!is_scheduled) { -+ /* Add the context to the pullable list */ -+ if (kbase_js_ctx_list_add_pullable_head(kbdev, kctx, 0)) -+ kbase_js_sync_timers(kbdev); -+ -+ /* Fast-starting requires the jsctx_mutex to be dropped, -+ * because it works on multiple ctxs */ -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ -+ /* Try to schedule the context in */ -+ kbase_js_sched_all(kbdev); -+ -+ /* Wait for the context to be scheduled in */ -+ wait_event(kctx->jctx.sched_info.ctx.is_scheduled_wait, -+ kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ } else { -+ /* Already scheduled in - We need to retain it to keep the -+ * corresponding address space */ -+ kbasep_js_runpool_retain_ctx(kbdev, kctx); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ } -+} -+KBASE_EXPORT_TEST_API(kbasep_js_schedule_privileged_ctx); -+ -+void kbasep_js_release_privileged_ctx(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_kctx_info *js_kctx_info; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ /* We don't need to use the address space anymore */ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ kbase_ctx_flag_clear(kctx, KCTX_PRIVILEGED); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ /* Release the context - it will be scheduled out */ -+ kbasep_js_runpool_release_ctx(kbdev, kctx); -+ -+ kbase_js_sched_all(kbdev); -+} -+KBASE_EXPORT_TEST_API(kbasep_js_release_privileged_ctx); -+ -+void kbasep_js_suspend(struct kbase_device *kbdev) -+{ -+ unsigned long flags; -+ struct kbasep_js_device_data *js_devdata; -+ int i; -+ u16 retained = 0u; -+ int nr_privileged_ctx = 0; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ KBASE_DEBUG_ASSERT(kbase_pm_is_suspending(kbdev)); -+ js_devdata = &kbdev->js_data; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* Prevent all contexts from submitting */ -+ js_devdata->runpool_irq.submit_allowed = 0; -+ -+ /* Retain each of the contexts, so we can cause it to leave even if it -+ * had no refcount to begin with */ -+ for (i = BASE_MAX_NR_AS - 1; i >= 0; --i) { -+ struct kbase_context *kctx = kbdev->as_to_kctx[i]; -+ -+ retained = retained << 1; -+ -+ if (kctx) { -+ kbase_ctx_sched_retain_ctx_refcount(kctx); -+ retained |= 1u; -+ /* We can only cope with up to 1 privileged context - -+ * the instrumented context. It'll be suspended by -+ * disabling instrumentation */ -+ if (kbase_ctx_flag(kctx, KCTX_PRIVILEGED)) { -+ ++nr_privileged_ctx; -+ WARN_ON(nr_privileged_ctx != 1); -+ } -+ } -+ } -+ CSTD_UNUSED(nr_privileged_ctx); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ /* De-ref the previous retain to ensure each context gets pulled out -+ * sometime later. */ -+ for (i = 0; -+ i < BASE_MAX_NR_AS; -+ ++i, retained = retained >> 1) { -+ struct kbase_context *kctx = kbdev->as_to_kctx[i]; -+ -+ if (retained & 1u) -+ kbasep_js_runpool_release_ctx(kbdev, kctx); -+ } -+ -+ /* Caller must wait for all Power Manager active references to be -+ * dropped */ -+} -+ -+void kbasep_js_resume(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ int js; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ js_devdata = &kbdev->js_data; -+ KBASE_DEBUG_ASSERT(!kbase_pm_is_suspending(kbdev)); -+ -+ mutex_lock(&js_devdata->queue_mutex); -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ struct kbase_context *kctx, *n; -+ -+ list_for_each_entry_safe(kctx, n, -+ &kbdev->js_data.ctx_list_unpullable[js], -+ jctx.sched_info.ctx.ctx_list_entry[js]) { -+ struct kbasep_js_kctx_info *js_kctx_info; -+ unsigned long flags; -+ bool timer_sync = false; -+ -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_lock(&js_devdata->runpool_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ if (!kbase_ctx_flag(kctx, KCTX_SCHEDULED) && -+ kbase_js_ctx_pullable(kctx, js, false)) -+ timer_sync = -+ kbase_js_ctx_list_add_pullable_nolock( -+ kbdev, kctx, js); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ if (timer_sync) -+ kbase_backend_ctx_count_changed(kbdev); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ } -+ } -+ mutex_unlock(&js_devdata->queue_mutex); -+ -+ /* Restart atom processing */ -+ kbase_js_sched_all(kbdev); -+ -+ /* JS Resume complete */ -+} -+ -+bool kbase_js_is_atom_valid(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ if ((katom->core_req & BASE_JD_REQ_FS) && -+ (katom->core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | -+ BASE_JD_REQ_T))) -+ return false; -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987) && -+ (katom->core_req & BASE_JD_REQ_ONLY_COMPUTE) && -+ (katom->core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_T))) -+ return false; -+ -+ return true; -+} -+ -+static int kbase_js_get_slot(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom) -+{ -+ if (katom->core_req & BASE_JD_REQ_FS) -+ return 0; -+ -+ if (katom->core_req & BASE_JD_REQ_ONLY_COMPUTE) { -+ if (katom->device_nr == 1 && -+ kbdev->gpu_props.num_core_groups == 2) -+ return 2; -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987)) -+ return 2; -+ } -+ -+ return 1; -+} -+ -+bool kbase_js_dep_resolved_submit(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom) -+{ -+ bool enqueue_required; -+ -+ katom->slot_nr = kbase_js_get_slot(kctx->kbdev, katom); -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ lockdep_assert_held(&kctx->jctx.lock); -+ -+ /* If slot will transition from unpullable to pullable then add to -+ * pullable list */ -+ if (jsctx_rb_none_to_pull(kctx, katom->slot_nr)) { -+ enqueue_required = true; -+ } else { -+ enqueue_required = false; -+ } -+ if ((katom->atom_flags & KBASE_KATOM_FLAG_X_DEP_BLOCKED) || -+ (katom->pre_dep && (katom->pre_dep->atom_flags & -+ KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST))) { -+ int prio = katom->sched_priority; -+ int js = katom->slot_nr; -+ struct jsctx_queue *queue = &kctx->jsctx_queue[prio][js]; -+ -+ list_add_tail(&katom->queue, &queue->x_dep_head); -+ katom->atom_flags |= KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST; -+ enqueue_required = false; -+ } else { -+ /* Check if there are lower priority jobs to soft stop */ -+ kbase_job_slot_ctx_priority_check_locked(kctx, katom); -+ -+ /* Add atom to ring buffer. */ -+ jsctx_tree_add(kctx, katom); -+ katom->atom_flags |= KBASE_KATOM_FLAG_JSCTX_IN_TREE; -+ } -+ -+ return enqueue_required; -+} -+ -+/** -+ * kbase_js_move_to_tree - Move atom (and any dependent atoms) to the -+ * runnable_tree, ready for execution -+ * @katom: Atom to submit -+ * -+ * It is assumed that @katom does not have KBASE_KATOM_FLAG_X_DEP_BLOCKED set, -+ * but is still present in the x_dep list. If @katom has a same-slot dependent -+ * atom then that atom (and any dependents) will also be moved. -+ */ -+static void kbase_js_move_to_tree(struct kbase_jd_atom *katom) -+{ -+ lockdep_assert_held(&katom->kctx->kbdev->hwaccess_lock); -+ -+ while (katom) { -+ WARN_ON(!(katom->atom_flags & -+ KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST)); -+ -+ if (!(katom->atom_flags & KBASE_KATOM_FLAG_X_DEP_BLOCKED)) { -+ list_del(&katom->queue); -+ katom->atom_flags &= -+ ~KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST; -+ jsctx_tree_add(katom->kctx, katom); -+ katom->atom_flags |= KBASE_KATOM_FLAG_JSCTX_IN_TREE; -+ } else { -+ break; -+ } -+ -+ katom = katom->post_dep; -+ } -+} -+ -+ -+/** -+ * kbase_js_evict_deps - Evict dependencies of a failed atom. -+ * @kctx: Context pointer -+ * @katom: Pointer to the atom that has failed. -+ * @js: The job slot the katom was run on. -+ * @prio: Priority of the katom. -+ * -+ * Remove all post dependencies of an atom from the context ringbuffers. -+ * -+ * The original atom's event_code will be propogated to all dependent atoms. -+ * -+ * Context: Caller must hold the HW access lock -+ */ -+static void kbase_js_evict_deps(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom, int js, int prio) -+{ -+ struct kbase_jd_atom *x_dep = katom->x_post_dep; -+ struct kbase_jd_atom *next_katom = katom->post_dep; -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ if (next_katom) { -+ KBASE_DEBUG_ASSERT(next_katom->status != -+ KBASE_JD_ATOM_STATE_HW_COMPLETED); -+ next_katom->will_fail_event_code = katom->event_code; -+ -+ } -+ -+ /* Has cross slot depenency. */ -+ if (x_dep && (x_dep->atom_flags & (KBASE_KATOM_FLAG_JSCTX_IN_TREE | -+ KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST))) { -+ /* Remove dependency.*/ -+ x_dep->atom_flags &= ~KBASE_KATOM_FLAG_X_DEP_BLOCKED; -+ -+ /* Fail if it had a data dependency. */ -+ if (x_dep->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER) { -+ x_dep->will_fail_event_code = katom->event_code; -+ } -+ if (x_dep->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST) -+ kbase_js_move_to_tree(x_dep); -+ } -+} -+ -+struct kbase_jd_atom *kbase_js_pull(struct kbase_context *kctx, int js) -+{ -+ struct kbase_jd_atom *katom; -+ struct kbasep_js_device_data *js_devdata; -+ struct kbase_device *kbdev; -+ int pulled; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+ kbdev = kctx->kbdev; -+ -+ js_devdata = &kbdev->js_data; -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (!kbasep_js_is_submit_allowed(js_devdata, kctx)) -+ return NULL; -+ if (kbase_pm_is_suspending(kbdev)) -+ return NULL; -+ -+ katom = jsctx_rb_peek(kctx, js); -+ if (!katom) -+ return NULL; -+ if (kctx->blocked_js[js][katom->sched_priority]) -+ return NULL; -+ if (atomic_read(&katom->blocked)) -+ return NULL; -+ -+ /* Due to ordering restrictions when unpulling atoms on failure, we do -+ * not allow multiple runs of fail-dep atoms from the same context to be -+ * present on the same slot */ -+ if (katom->pre_dep && atomic_read(&kctx->atoms_pulled_slot[js])) { -+ struct kbase_jd_atom *prev_atom = -+ kbase_backend_inspect_tail(kbdev, js); -+ -+ if (prev_atom && prev_atom->kctx != kctx) -+ return NULL; -+ } -+ -+ if (katom->atom_flags & KBASE_KATOM_FLAG_X_DEP_BLOCKED) { -+ if (katom->x_pre_dep->gpu_rb_state == -+ KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB || -+ katom->x_pre_dep->will_fail_event_code) -+ return NULL; -+ if ((katom->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER) && -+ kbase_backend_nr_atoms_on_slot(kbdev, js)) -+ return NULL; -+ } -+ -+ kbase_ctx_flag_set(kctx, KCTX_PULLED); -+ -+ pulled = atomic_inc_return(&kctx->atoms_pulled); -+ if (pulled == 1 && !kctx->slots_pullable) { -+ WARN_ON(kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)); -+ kbase_ctx_flag_set(kctx, KCTX_RUNNABLE_REF); -+ atomic_inc(&kbdev->js_data.nr_contexts_runnable); -+ } -+ atomic_inc(&kctx->atoms_pulled_slot[katom->slot_nr]); -+ kctx->atoms_pulled_slot_pri[katom->slot_nr][katom->sched_priority]++; -+ jsctx_rb_pull(kctx, katom); -+ -+ kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx); -+ -+ katom->atom_flags |= KBASE_KATOM_FLAG_HOLDING_CTX_REF; -+ -+ katom->ticks = 0; -+ -+ return katom; -+} -+ -+ -+static void js_return_worker(struct work_struct *data) -+{ -+ struct kbase_jd_atom *katom = container_of(data, struct kbase_jd_atom, -+ work); -+ struct kbase_context *kctx = katom->kctx; -+ struct kbase_device *kbdev = kctx->kbdev; -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ struct kbasep_js_kctx_info *js_kctx_info = &kctx->jctx.sched_info; -+ struct kbasep_js_atom_retained_state retained_state; -+ int js = katom->slot_nr; -+ int prio = katom->sched_priority; -+ bool timer_sync = false; -+ bool context_idle = false; -+ unsigned long flags; -+ base_jd_core_req core_req = katom->core_req; -+ u64 affinity = katom->affinity; -+ enum kbase_atom_coreref_state coreref_state = katom->coreref_state; -+ -+ KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_EX(katom); -+ -+ kbase_backend_complete_wq(kbdev, katom); -+ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316)) -+ kbase_as_poking_timer_release_atom(kbdev, kctx, katom); -+ -+ kbasep_js_atom_retained_state_copy(&retained_state, katom); -+ -+ mutex_lock(&js_devdata->queue_mutex); -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ -+ atomic_dec(&kctx->atoms_pulled); -+ atomic_dec(&kctx->atoms_pulled_slot[js]); -+ -+ atomic_dec(&katom->blocked); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ kctx->atoms_pulled_slot_pri[js][katom->sched_priority]--; -+ -+ if (!atomic_read(&kctx->atoms_pulled_slot[js]) && -+ jsctx_rb_none_to_pull(kctx, js)) -+ timer_sync |= kbase_js_ctx_list_remove_nolock(kbdev, kctx, js); -+ -+ /* If this slot has been blocked due to soft-stopped atoms, and all -+ * atoms have now been processed, then unblock the slot */ -+ if (!kctx->atoms_pulled_slot_pri[js][prio] && -+ kctx->blocked_js[js][prio]) { -+ kctx->blocked_js[js][prio] = false; -+ -+ /* Only mark the slot as pullable if the context is not idle - -+ * that case is handled below */ -+ if (atomic_read(&kctx->atoms_pulled) && -+ kbase_js_ctx_pullable(kctx, js, true)) -+ timer_sync |= kbase_js_ctx_list_add_pullable_nolock( -+ kbdev, kctx, js); -+ } -+ -+ if (!atomic_read(&kctx->atoms_pulled)) { -+ if (!kctx->slots_pullable) { -+ WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)); -+ kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF); -+ atomic_dec(&kbdev->js_data.nr_contexts_runnable); -+ timer_sync = true; -+ } -+ -+ if (kctx->as_nr != KBASEP_AS_NR_INVALID && -+ !kbase_ctx_flag(kctx, KCTX_DYING)) { -+ int num_slots = kbdev->gpu_props.num_job_slots; -+ int slot; -+ -+ if (!kbasep_js_is_submit_allowed(js_devdata, kctx)) -+ kbasep_js_set_submit_allowed(js_devdata, kctx); -+ -+ for (slot = 0; slot < num_slots; slot++) { -+ if (kbase_js_ctx_pullable(kctx, slot, true)) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_nolock( -+ kbdev, kctx, slot); -+ } -+ } -+ -+ kbase_jm_idle_ctx(kbdev, kctx); -+ -+ context_idle = true; -+ } -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ if (context_idle) { -+ WARN_ON(!kbase_ctx_flag(kctx, KCTX_ACTIVE)); -+ kbase_ctx_flag_clear(kctx, KCTX_ACTIVE); -+ kbase_pm_context_idle(kbdev); -+ } -+ -+ if (timer_sync) -+ kbase_js_sync_timers(kbdev); -+ -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ -+ katom->atom_flags &= ~KBASE_KATOM_FLAG_HOLDING_CTX_REF; -+ kbasep_js_runpool_release_ctx_and_katom_retained_state(kbdev, kctx, -+ &retained_state); -+ -+ kbase_js_sched_all(kbdev); -+ -+ kbase_backend_complete_wq_post_sched(kbdev, core_req, affinity, -+ coreref_state); -+} -+ -+void kbase_js_unpull(struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ jsctx_rb_unpull(kctx, katom); -+ -+ WARN_ON(work_pending(&katom->work)); -+ -+ /* Block re-submission until workqueue has run */ -+ atomic_inc(&katom->blocked); -+ -+ kbase_job_check_leave_disjoint(kctx->kbdev, katom); -+ -+ KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&katom->work)); -+ INIT_WORK(&katom->work, js_return_worker); -+ queue_work(kctx->jctx.job_done_wq, &katom->work); -+} -+ -+bool kbase_js_complete_atom_wq(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom) -+{ -+ struct kbasep_js_kctx_info *js_kctx_info; -+ struct kbasep_js_device_data *js_devdata; -+ struct kbase_device *kbdev; -+ unsigned long flags; -+ bool timer_sync = false; -+ int atom_slot; -+ bool context_idle = false; -+ int prio = katom->sched_priority; -+ -+ kbdev = kctx->kbdev; -+ atom_slot = katom->slot_nr; -+ -+ js_kctx_info = &kctx->jctx.sched_info; -+ js_devdata = &kbdev->js_data; -+ -+ lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex); -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ if (katom->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_TREE) { -+ context_idle = !atomic_dec_return(&kctx->atoms_pulled); -+ atomic_dec(&kctx->atoms_pulled_slot[atom_slot]); -+ kctx->atoms_pulled_slot_pri[atom_slot][prio]--; -+ -+ if (!atomic_read(&kctx->atoms_pulled) && -+ !kctx->slots_pullable) { -+ WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)); -+ kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF); -+ atomic_dec(&kbdev->js_data.nr_contexts_runnable); -+ timer_sync = true; -+ } -+ -+ /* If this slot has been blocked due to soft-stopped atoms, and -+ * all atoms have now been processed, then unblock the slot */ -+ if (!kctx->atoms_pulled_slot_pri[atom_slot][prio] -+ && kctx->blocked_js[atom_slot][prio]) { -+ kctx->blocked_js[atom_slot][prio] = false; -+ if (kbase_js_ctx_pullable(kctx, atom_slot, true)) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_nolock( -+ kbdev, kctx, atom_slot); -+ } -+ } -+ WARN_ON(!(katom->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_TREE)); -+ -+ if (!atomic_read(&kctx->atoms_pulled_slot[atom_slot]) && -+ jsctx_rb_none_to_pull(kctx, atom_slot)) { -+ if (!list_empty( -+ &kctx->jctx.sched_info.ctx.ctx_list_entry[atom_slot])) -+ timer_sync |= kbase_js_ctx_list_remove_nolock( -+ kctx->kbdev, kctx, atom_slot); -+ } -+ -+ /* -+ * If submission is disabled on this context (most likely due to an -+ * atom failure) and there are now no atoms left in the system then -+ * re-enable submission so that context can be scheduled again. -+ */ -+ if (!kbasep_js_is_submit_allowed(js_devdata, kctx) && -+ !atomic_read(&kctx->atoms_pulled) && -+ !kbase_ctx_flag(kctx, KCTX_DYING)) { -+ int js; -+ -+ kbasep_js_set_submit_allowed(js_devdata, kctx); -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ if (kbase_js_ctx_pullable(kctx, js, true)) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_nolock( -+ kbdev, kctx, js); -+ } -+ } else if (katom->x_post_dep && -+ kbasep_js_is_submit_allowed(js_devdata, kctx)) { -+ int js; -+ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ if (kbase_js_ctx_pullable(kctx, js, true)) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_nolock( -+ kbdev, kctx, js); -+ } -+ } -+ -+ /* Mark context as inactive. The pm reference will be dropped later in -+ * jd_done_worker(). -+ */ -+ if (context_idle) -+ kbase_ctx_flag_clear(kctx, KCTX_ACTIVE); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ if (timer_sync) -+ kbase_backend_ctx_count_changed(kbdev); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ return context_idle; -+} -+ -+struct kbase_jd_atom *kbase_js_complete_atom(struct kbase_jd_atom *katom, -+ ktime_t *end_timestamp) -+{ -+ u64 microseconds_spent = 0; -+ struct kbase_device *kbdev; -+ struct kbase_context *kctx = katom->kctx; -+ struct kbase_jd_atom *x_dep = katom->x_post_dep; -+ -+ kbdev = kctx->kbdev; -+ -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ if (katom->will_fail_event_code) -+ katom->event_code = katom->will_fail_event_code; -+ -+ katom->status = KBASE_JD_ATOM_STATE_HW_COMPLETED; -+ -+ if (katom->event_code != BASE_JD_EVENT_DONE) { -+ kbase_js_evict_deps(kctx, katom, katom->slot_nr, -+ katom->sched_priority); -+ } -+ -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_job_slots_event(GATOR_MAKE_EVENT(GATOR_JOB_SLOT_STOP, -+ katom->slot_nr), NULL, 0); -+#endif -+ -+ /* Calculate the job's time used */ -+ if (end_timestamp != NULL) { -+ /* Only calculating it for jobs that really run on the HW (e.g. -+ * removed from next jobs never actually ran, so really did take -+ * zero time) */ -+ ktime_t tick_diff = ktime_sub(*end_timestamp, -+ katom->start_timestamp); -+ -+ microseconds_spent = ktime_to_ns(tick_diff); -+ -+ do_div(microseconds_spent, 1000); -+ -+ /* Round up time spent to the minimum timer resolution */ -+ if (microseconds_spent < KBASEP_JS_TICK_RESOLUTION_US) -+ microseconds_spent = KBASEP_JS_TICK_RESOLUTION_US; -+ } -+ -+ -+ kbase_jd_done(katom, katom->slot_nr, end_timestamp, 0); -+ -+ /* Unblock cross dependency if present */ -+ if (x_dep && (katom->event_code == BASE_JD_EVENT_DONE || -+ !(x_dep->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER)) && -+ (x_dep->atom_flags & KBASE_KATOM_FLAG_X_DEP_BLOCKED)) { -+ bool was_pullable = kbase_js_ctx_pullable(kctx, x_dep->slot_nr, -+ false); -+ x_dep->atom_flags &= ~KBASE_KATOM_FLAG_X_DEP_BLOCKED; -+ kbase_js_move_to_tree(x_dep); -+ if (!was_pullable && kbase_js_ctx_pullable(kctx, x_dep->slot_nr, -+ false)) -+ kbase_js_ctx_list_add_pullable_nolock(kbdev, kctx, -+ x_dep->slot_nr); -+ -+ if (x_dep->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_TREE) -+ return x_dep; -+ } -+ -+ return NULL; -+} -+ -+void kbase_js_sched(struct kbase_device *kbdev, int js_mask) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbase_context *last_active; -+ bool timer_sync = false; -+ bool ctx_waiting = false; -+ -+ js_devdata = &kbdev->js_data; -+ -+ down(&js_devdata->schedule_sem); -+ mutex_lock(&js_devdata->queue_mutex); -+ -+ last_active = kbdev->hwaccess.active_kctx; -+ -+ while (js_mask) { -+ int js; -+ -+ js = ffs(js_mask) - 1; -+ -+ while (1) { -+ struct kbase_context *kctx; -+ unsigned long flags; -+ bool context_idle = false; -+ -+ kctx = kbase_js_ctx_list_pop_head(kbdev, js); -+ -+ if (!kctx) { -+ js_mask &= ~(1 << js); -+ break; /* No contexts on pullable list */ -+ } -+ -+ if (!kbase_ctx_flag(kctx, KCTX_ACTIVE)) { -+ context_idle = true; -+ -+ if (kbase_pm_context_active_handle_suspend( -+ kbdev, -+ KBASE_PM_SUSPEND_HANDLER_DONT_INCREASE)) { -+ /* Suspend pending - return context to -+ * queue and stop scheduling */ -+ mutex_lock( -+ &kctx->jctx.sched_info.ctx.jsctx_mutex); -+ if (kbase_js_ctx_list_add_pullable_head( -+ kctx->kbdev, kctx, js)) -+ kbase_js_sync_timers(kbdev); -+ mutex_unlock( -+ &kctx->jctx.sched_info.ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ up(&js_devdata->schedule_sem); -+ return; -+ } -+ kbase_ctx_flag_set(kctx, KCTX_ACTIVE); -+ } -+ -+ if (!kbase_js_use_ctx(kbdev, kctx)) { -+ mutex_lock( -+ &kctx->jctx.sched_info.ctx.jsctx_mutex); -+ /* Context can not be used at this time */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ if (kbase_js_ctx_pullable(kctx, js, false) -+ || kbase_ctx_flag(kctx, KCTX_PRIVILEGED)) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_head_nolock( -+ kctx->kbdev, kctx, js); -+ else -+ timer_sync |= -+ kbase_js_ctx_list_add_unpullable_nolock( -+ kctx->kbdev, kctx, js); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, -+ flags); -+ mutex_unlock( -+ &kctx->jctx.sched_info.ctx.jsctx_mutex); -+ if (context_idle) { -+ WARN_ON(!kbase_ctx_flag(kctx, KCTX_ACTIVE)); -+ kbase_ctx_flag_clear(kctx, KCTX_ACTIVE); -+ kbase_pm_context_idle(kbdev); -+ } -+ -+ /* No more jobs can be submitted on this slot */ -+ js_mask &= ~(1 << js); -+ break; -+ } -+ mutex_lock(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ kbase_ctx_flag_clear(kctx, KCTX_PULLED); -+ -+ if (!kbase_jm_kick(kbdev, 1 << js)) -+ /* No more jobs can be submitted on this slot */ -+ js_mask &= ~(1 << js); -+ -+ if (!kbase_ctx_flag(kctx, KCTX_PULLED)) { -+ bool pullable = kbase_js_ctx_pullable(kctx, js, -+ true); -+ -+ /* Failed to pull jobs - push to head of list. -+ * Unless this context is already 'active', in -+ * which case it's effectively already scheduled -+ * so push it to the back of the list. */ -+ if (pullable && kctx == last_active) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_nolock( -+ kctx->kbdev, -+ kctx, js); -+ else if (pullable) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_head_nolock( -+ kctx->kbdev, -+ kctx, js); -+ else -+ timer_sync |= -+ kbase_js_ctx_list_add_unpullable_nolock( -+ kctx->kbdev, -+ kctx, js); -+ -+ /* If this context is not the active context, -+ * but the active context is pullable on this -+ * slot, then we need to remove the active -+ * marker to prevent it from submitting atoms in -+ * the IRQ handler, which would prevent this -+ * context from making progress. */ -+ if (last_active && kctx != last_active && -+ kbase_js_ctx_pullable( -+ last_active, js, true)) -+ ctx_waiting = true; -+ -+ if (context_idle) { -+ kbase_jm_idle_ctx(kbdev, kctx); -+ spin_unlock_irqrestore( -+ &kbdev->hwaccess_lock, -+ flags); -+ WARN_ON(!kbase_ctx_flag(kctx, KCTX_ACTIVE)); -+ kbase_ctx_flag_clear(kctx, KCTX_ACTIVE); -+ kbase_pm_context_idle(kbdev); -+ } else { -+ spin_unlock_irqrestore( -+ &kbdev->hwaccess_lock, -+ flags); -+ } -+ mutex_unlock( -+ &kctx->jctx.sched_info.ctx.jsctx_mutex); -+ -+ js_mask &= ~(1 << js); -+ break; /* Could not run atoms on this slot */ -+ } -+ -+ /* Push to back of list */ -+ if (kbase_js_ctx_pullable(kctx, js, true)) -+ timer_sync |= -+ kbase_js_ctx_list_add_pullable_nolock( -+ kctx->kbdev, kctx, js); -+ else -+ timer_sync |= -+ kbase_js_ctx_list_add_unpullable_nolock( -+ kctx->kbdev, kctx, js); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&kctx->jctx.sched_info.ctx.jsctx_mutex); -+ } -+ } -+ -+ if (timer_sync) -+ kbase_js_sync_timers(kbdev); -+ -+ if (kbdev->hwaccess.active_kctx == last_active && ctx_waiting) -+ kbdev->hwaccess.active_kctx = NULL; -+ -+ mutex_unlock(&js_devdata->queue_mutex); -+ up(&js_devdata->schedule_sem); -+} -+ -+void kbase_js_zap_context(struct kbase_context *kctx) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ struct kbasep_js_kctx_info *js_kctx_info = &kctx->jctx.sched_info; -+ int js; -+ -+ /* -+ * Critical assumption: No more submission is possible outside of the -+ * workqueue. This is because the OS *must* prevent U/K calls (IOCTLs) -+ * whilst the struct kbase_context is terminating. -+ */ -+ -+ /* First, atomically do the following: -+ * - mark the context as dying -+ * - try to evict it from the queue */ -+ mutex_lock(&kctx->jctx.lock); -+ mutex_lock(&js_devdata->queue_mutex); -+ mutex_lock(&js_kctx_info->ctx.jsctx_mutex); -+ kbase_ctx_flag_set(kctx, KCTX_DYING); -+ -+ dev_dbg(kbdev->dev, "Zap: Try Evict Ctx %p", kctx); -+ -+ /* -+ * At this point we know: -+ * - If eviction succeeded, it was in the queue, but now no -+ * longer is -+ * - We must cancel the jobs here. No Power Manager active reference to -+ * release. -+ * - This happens asynchronously - kbase_jd_zap_context() will wait for -+ * those jobs to be killed. -+ * - If eviction failed, then it wasn't in the queue. It is one -+ * of the following: -+ * - a. it didn't have any jobs, and so is not in the Queue or -+ * the Run Pool (not scheduled) -+ * - Hence, no more work required to cancel jobs. No Power Manager -+ * active reference to release. -+ * - b. it was in the middle of a scheduling transaction (and thus must -+ * have at least 1 job). This can happen from a syscall or a -+ * kernel thread. We still hold the jsctx_mutex, and so the thread -+ * must be waiting inside kbasep_js_try_schedule_head_ctx(), -+ * before checking whether the runpool is full. That thread will -+ * continue after we drop the mutex, and will notice the context -+ * is dying. It will rollback the transaction, killing all jobs at -+ * the same time. kbase_jd_zap_context() will wait for those jobs -+ * to be killed. -+ * - Hence, no more work required to cancel jobs, or to release the -+ * Power Manager active reference. -+ * - c. it is scheduled, and may or may not be running jobs -+ * - We must cause it to leave the runpool by stopping it from -+ * submitting any more jobs. When it finally does leave, -+ * kbasep_js_runpool_requeue_or_kill_ctx() will kill all remaining jobs -+ * (because it is dying), release the Power Manager active reference, -+ * and will not requeue the context in the queue. -+ * kbase_jd_zap_context() will wait for those jobs to be killed. -+ * - Hence, work required just to make it leave the runpool. Cancelling -+ * jobs and releasing the Power manager active reference will be -+ * handled when it leaves the runpool. -+ */ -+ if (!kbase_ctx_flag(kctx, KCTX_SCHEDULED)) { -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) { -+ if (!list_empty( -+ &kctx->jctx.sched_info.ctx.ctx_list_entry[js])) -+ list_del_init( -+ &kctx->jctx.sched_info.ctx.ctx_list_entry[js]); -+ } -+ -+ /* The following events require us to kill off remaining jobs -+ * and update PM book-keeping: -+ * - we evicted it correctly (it must have jobs to be in the -+ * Queue) -+ * -+ * These events need no action, but take this path anyway: -+ * - Case a: it didn't have any jobs, and was never in the Queue -+ * - Case b: scheduling transaction will be partially rolled- -+ * back (this already cancels the jobs) -+ */ -+ -+ KBASE_TRACE_ADD(kbdev, JM_ZAP_NON_SCHEDULED, kctx, NULL, 0u, -+ kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ dev_dbg(kbdev->dev, "Zap: Ctx %p scheduled=0", kctx); -+ -+ /* Only cancel jobs when we evicted from the -+ * queue. No Power Manager active reference was held. -+ * -+ * Having is_dying set ensures that this kills, and -+ * doesn't requeue */ -+ kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx, false); -+ -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ mutex_unlock(&kctx->jctx.lock); -+ } else { -+ unsigned long flags; -+ bool was_retained; -+ -+ /* Case c: didn't evict, but it is scheduled - it's in the Run -+ * Pool */ -+ KBASE_TRACE_ADD(kbdev, JM_ZAP_SCHEDULED, kctx, NULL, 0u, -+ kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ dev_dbg(kbdev->dev, "Zap: Ctx %p is in RunPool", kctx); -+ -+ /* Disable the ctx from submitting any more jobs */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ kbasep_js_clear_submit_allowed(js_devdata, kctx); -+ -+ /* Retain and (later) release the context whilst it is is now -+ * disallowed from submitting jobs - ensures that someone -+ * somewhere will be removing the context later on */ -+ was_retained = kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx); -+ -+ /* Since it's scheduled and we have the jsctx_mutex, it must be -+ * retained successfully */ -+ KBASE_DEBUG_ASSERT(was_retained); -+ -+ dev_dbg(kbdev->dev, "Zap: Ctx %p Kill Any Running jobs", kctx); -+ -+ /* Cancel any remaining running jobs for this kctx - if any. -+ * Submit is disallowed which takes effect immediately, so no -+ * more new jobs will appear after we do this. */ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) -+ kbase_job_slot_hardstop(kctx, js, NULL); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ mutex_unlock(&js_kctx_info->ctx.jsctx_mutex); -+ mutex_unlock(&js_devdata->queue_mutex); -+ mutex_unlock(&kctx->jctx.lock); -+ -+ dev_dbg(kbdev->dev, "Zap: Ctx %p Release (may or may not schedule out immediately)", -+ kctx); -+ -+ kbasep_js_runpool_release_ctx(kbdev, kctx); -+ } -+ -+ KBASE_TRACE_ADD(kbdev, JM_ZAP_DONE, kctx, NULL, 0u, 0u); -+ -+ /* After this, you must wait on both the -+ * kbase_jd_context::zero_jobs_wait and the -+ * kbasep_js_kctx_info::ctx::is_scheduled_waitq - to wait for the jobs -+ * to be destroyed, and the context to be de-scheduled (if it was on the -+ * runpool). -+ * -+ * kbase_jd_zap_context() will do this. */ -+} -+ -+static inline int trace_get_refcnt(struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ return atomic_read(&kctx->refcount); -+} -+ -+/** -+ * kbase_js_foreach_ctx_job(): - Call a function on all jobs in context -+ * @kctx: Pointer to context. -+ * @callback: Pointer to function to call for each job. -+ * -+ * Call a function on all jobs belonging to a non-queued, non-running -+ * context, and detach the jobs from the context as it goes. -+ * -+ * Due to the locks that might be held at the time of the call, the callback -+ * may need to defer work on a workqueue to complete its actions (e.g. when -+ * cancelling jobs) -+ * -+ * Atoms will be removed from the queue, so this must only be called when -+ * cancelling jobs (which occurs as part of context destruction). -+ * -+ * The locking conditions on the caller are as follows: -+ * - it will be holding kbasep_js_kctx_info::ctx::jsctx_mutex. -+ */ -+static void kbase_js_foreach_ctx_job(struct kbase_context *kctx, -+ kbasep_js_ctx_job_cb callback) -+{ -+ struct kbase_device *kbdev; -+ unsigned long flags; -+ u32 js; -+ -+ kbdev = kctx->kbdev; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, JS_POLICY_FOREACH_CTX_JOBS, kctx, NULL, -+ 0u, trace_get_refcnt(kbdev, kctx)); -+ -+ /* Invoke callback on jobs on each slot in turn */ -+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) -+ jsctx_queue_foreach(kctx, js, callback); -+ -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_js.h b/drivers/gpu/arm/midgard/mali_kbase_js.h -new file mode 100644 -index 0000000..ddada8e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_js.h -@@ -0,0 +1,925 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_js.h -+ * Job Scheduler APIs. -+ */ -+ -+#ifndef _KBASE_JS_H_ -+#define _KBASE_JS_H_ -+ -+#include "mali_kbase_js_defs.h" -+#include "mali_kbase_context.h" -+#include "mali_kbase_defs.h" -+#include "mali_kbase_debug.h" -+ -+#include "mali_kbase_js_ctx_attr.h" -+ -+/** -+ * @addtogroup base_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup base_kbase_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup kbase_js Job Scheduler Internal APIs -+ * @{ -+ * -+ * These APIs are Internal to KBase. -+ */ -+ -+/** -+ * @brief Initialize the Job Scheduler -+ * -+ * The struct kbasep_js_device_data sub-structure of \a kbdev must be zero -+ * initialized before passing to the kbasep_js_devdata_init() function. This is -+ * to give efficient error path code. -+ */ -+int kbasep_js_devdata_init(struct kbase_device * const kbdev); -+ -+/** -+ * @brief Halt the Job Scheduler. -+ * -+ * It is safe to call this on \a kbdev even if it the kbasep_js_device_data -+ * sub-structure was never initialized/failed initialization, to give efficient -+ * error-path code. -+ * -+ * For this to work, the struct kbasep_js_device_data sub-structure of \a kbdev must -+ * be zero initialized before passing to the kbasep_js_devdata_init() -+ * function. This is to give efficient error path code. -+ * -+ * It is a Programming Error to call this whilst there are still kbase_context -+ * structures registered with this scheduler. -+ * -+ */ -+void kbasep_js_devdata_halt(struct kbase_device *kbdev); -+ -+/** -+ * @brief Terminate the Job Scheduler -+ * -+ * It is safe to call this on \a kbdev even if it the kbasep_js_device_data -+ * sub-structure was never initialized/failed initialization, to give efficient -+ * error-path code. -+ * -+ * For this to work, the struct kbasep_js_device_data sub-structure of \a kbdev must -+ * be zero initialized before passing to the kbasep_js_devdata_init() -+ * function. This is to give efficient error path code. -+ * -+ * It is a Programming Error to call this whilst there are still kbase_context -+ * structures registered with this scheduler. -+ */ -+void kbasep_js_devdata_term(struct kbase_device *kbdev); -+ -+/** -+ * @brief Initialize the Scheduling Component of a struct kbase_context on the Job Scheduler. -+ * -+ * This effectively registers a struct kbase_context with a Job Scheduler. -+ * -+ * It does not register any jobs owned by the struct kbase_context with the scheduler. -+ * Those must be separately registered by kbasep_js_add_job(). -+ * -+ * The struct kbase_context must be zero intitialized before passing to the -+ * kbase_js_init() function. This is to give efficient error path code. -+ */ -+int kbasep_js_kctx_init(struct kbase_context * const kctx); -+ -+/** -+ * @brief Terminate the Scheduling Component of a struct kbase_context on the Job Scheduler -+ * -+ * This effectively de-registers a struct kbase_context from its Job Scheduler -+ * -+ * It is safe to call this on a struct kbase_context that has never had or failed -+ * initialization of its jctx.sched_info member, to give efficient error-path -+ * code. -+ * -+ * For this to work, the struct kbase_context must be zero intitialized before passing -+ * to the kbase_js_init() function. -+ * -+ * It is a Programming Error to call this whilst there are still jobs -+ * registered with this context. -+ */ -+void kbasep_js_kctx_term(struct kbase_context *kctx); -+ -+/** -+ * @brief Add a job chain to the Job Scheduler, and take necessary actions to -+ * schedule the context/run the job. -+ * -+ * This atomically does the following: -+ * - Update the numbers of jobs information -+ * - Add the job to the run pool if necessary (part of init_job) -+ * -+ * Once this is done, then an appropriate action is taken: -+ * - If the ctx is scheduled, it attempts to start the next job (which might be -+ * this added job) -+ * - Otherwise, and if this is the first job on the context, it enqueues it on -+ * the Policy Queue -+ * -+ * The Policy's Queue can be updated by this in the following ways: -+ * - In the above case that this is the first job on the context -+ * - If the context is high priority and the context is not scheduled, then it -+ * could cause the Policy to schedule out a low-priority context, allowing -+ * this context to be scheduled in. -+ * -+ * If the context is already scheduled on the RunPool, then adding a job to it -+ * is guarenteed not to update the Policy Queue. And so, the caller is -+ * guarenteed to not need to try scheduling a context from the Run Pool - it -+ * can safely assert that the result is false. -+ * -+ * It is a programming error to have more than U32_MAX jobs in flight at a time. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * - it must \em not hold hwaccess_lock (as this will be obtained internally) -+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be -+ * obtained internally) -+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (again, it's used internally). -+ * -+ * @return true indicates that the Policy Queue was updated, and so the -+ * caller will need to try scheduling a context onto the Run Pool. -+ * @return false indicates that no updates were made to the Policy Queue, -+ * so no further action is required from the caller. This is \b always returned -+ * when the context is currently scheduled. -+ */ -+bool kbasep_js_add_job(struct kbase_context *kctx, struct kbase_jd_atom *atom); -+ -+/** -+ * @brief Remove a job chain from the Job Scheduler, except for its 'retained state'. -+ * -+ * Completely removing a job requires several calls: -+ * - kbasep_js_copy_atom_retained_state(), to capture the 'retained state' of -+ * the atom -+ * - kbasep_js_remove_job(), to partially remove the atom from the Job Scheduler -+ * - kbasep_js_runpool_release_ctx_and_katom_retained_state(), to release the -+ * remaining state held as part of the job having been run. -+ * -+ * In the common case of atoms completing normally, this set of actions is more optimal for spinlock purposes than having kbasep_js_remove_job() handle all of the actions. -+ * -+ * In the case of cancelling atoms, it is easier to call kbasep_js_remove_cancelled_job(), which handles all the necessary actions. -+ * -+ * It is a programming error to call this when: -+ * - \a atom is not a job belonging to kctx. -+ * - \a atom has already been removed from the Job Scheduler. -+ * - \a atom is still in the runpool -+ * -+ * Do not use this for removing jobs being killed by kbase_jd_cancel() - use -+ * kbasep_js_remove_cancelled_job() instead. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must hold kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * -+ */ -+void kbasep_js_remove_job(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *atom); -+ -+/** -+ * @brief Completely remove a job chain from the Job Scheduler, in the case -+ * where the job chain was cancelled. -+ * -+ * This is a variant of kbasep_js_remove_job() that takes care of removing all -+ * of the retained state too. This is generally useful for cancelled atoms, -+ * which need not be handled in an optimal way. -+ * -+ * It is a programming error to call this when: -+ * - \a atom is not a job belonging to kctx. -+ * - \a atom has already been removed from the Job Scheduler. -+ * - \a atom is still in the runpool: -+ * - it is not being killed with kbasep_jd_cancel() -+ * -+ * The following locking conditions are made on the caller: -+ * - it must hold kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * - it must \em not hold the hwaccess_lock, (as this will be obtained -+ * internally) -+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this could be -+ * obtained internally) -+ * -+ * @return true indicates that ctx attributes have changed and the caller -+ * should call kbase_js_sched_all() to try to run more jobs -+ * @return false otherwise -+ */ -+bool kbasep_js_remove_cancelled_job(struct kbase_device *kbdev, -+ struct kbase_context *kctx, -+ struct kbase_jd_atom *katom); -+ -+/** -+ * @brief Refcount a context as being busy, preventing it from being scheduled -+ * out. -+ * -+ * @note This function can safely be called from IRQ context. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must \em not hold mmu_hw_mutex and hwaccess_lock, because they will be -+ * used internally. -+ * -+ * @return value != false if the retain succeeded, and the context will not be scheduled out. -+ * @return false if the retain failed (because the context is being/has been scheduled out). -+ */ -+bool kbasep_js_runpool_retain_ctx(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * @brief Refcount a context as being busy, preventing it from being scheduled -+ * out. -+ * -+ * @note This function can safely be called from IRQ context. -+ * -+ * The following locks must be held by the caller: -+ * - mmu_hw_mutex, hwaccess_lock -+ * -+ * @return value != false if the retain succeeded, and the context will not be scheduled out. -+ * @return false if the retain failed (because the context is being/has been scheduled out). -+ */ -+bool kbasep_js_runpool_retain_ctx_nolock(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * @brief Lookup a context in the Run Pool based upon its current address space -+ * and ensure that is stays scheduled in. -+ * -+ * The context is refcounted as being busy to prevent it from scheduling -+ * out. It must be released with kbasep_js_runpool_release_ctx() when it is no -+ * longer required to stay scheduled in. -+ * -+ * @note This function can safely be called from IRQ context. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must \em not hold the hwaccess_lock, because it will be used internally. -+ * If the hwaccess_lock is already held, then the caller should use -+ * kbasep_js_runpool_lookup_ctx_nolock() instead. -+ * -+ * @return a valid struct kbase_context on success, which has been refcounted as being busy. -+ * @return NULL on failure, indicating that no context was found in \a as_nr -+ */ -+struct kbase_context *kbasep_js_runpool_lookup_ctx(struct kbase_device *kbdev, int as_nr); -+ -+/** -+ * @brief Handling the requeuing/killing of a context that was evicted from the -+ * policy queue or runpool. -+ * -+ * This should be used whenever handing off a context that has been evicted -+ * from the policy queue or the runpool: -+ * - If the context is not dying and has jobs, it gets re-added to the policy -+ * queue -+ * - Otherwise, it is not added -+ * -+ * In addition, if the context is dying the jobs are killed asynchronously. -+ * -+ * In all cases, the Power Manager active reference is released -+ * (kbase_pm_context_idle()) whenever the has_pm_ref parameter is true. \a -+ * has_pm_ref must be set to false whenever the context was not previously in -+ * the runpool and does not hold a Power Manager active refcount. Note that -+ * contexts in a rollback of kbasep_js_try_schedule_head_ctx() might have an -+ * active refcount even though they weren't in the runpool. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must hold kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (as this will be -+ * obtained internally) -+ */ -+void kbasep_js_runpool_requeue_or_kill_ctx(struct kbase_device *kbdev, struct kbase_context *kctx, bool has_pm_ref); -+ -+/** -+ * @brief Release a refcount of a context being busy, allowing it to be -+ * scheduled out. -+ * -+ * When the refcount reaches zero and the context \em might be scheduled out -+ * (depending on whether the Scheudling Policy has deemed it so, or if it has run -+ * out of jobs). -+ * -+ * If the context does get scheduled out, then The following actions will be -+ * taken as part of deschduling a context: -+ * - For the context being descheduled: -+ * - If the context is in the processing of dying (all the jobs are being -+ * removed from it), then descheduling also kills off any jobs remaining in the -+ * context. -+ * - If the context is not dying, and any jobs remain after descheduling the -+ * context then it is re-enqueued to the Policy's Queue. -+ * - Otherwise, the context is still known to the scheduler, but remains absent -+ * from the Policy Queue until a job is next added to it. -+ * - In all descheduling cases, the Power Manager active reference (obtained -+ * during kbasep_js_try_schedule_head_ctx()) is released (kbase_pm_context_idle()). -+ * -+ * Whilst the context is being descheduled, this also handles actions that -+ * cause more atoms to be run: -+ * - Attempt submitting atoms when the Context Attributes on the Runpool have -+ * changed. This is because the context being scheduled out could mean that -+ * there are more opportunities to run atoms. -+ * - Attempt submitting to a slot that was previously blocked due to affinity -+ * restrictions. This is usually only necessary when releasing a context -+ * happens as part of completing a previous job, but is harmless nonetheless. -+ * - Attempt scheduling in a new context (if one is available), and if necessary, -+ * running a job from that new context. -+ * -+ * Unlike retaining a context in the runpool, this function \b cannot be called -+ * from IRQ context. -+ * -+ * It is a programming error to call this on a \a kctx that is not currently -+ * scheduled, or that already has a zero refcount. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must \em not hold the hwaccess_lock, because it will be used internally. -+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be -+ * obtained internally) -+ * - it must \em not hold the kbase_device::mmu_hw_mutex (as this will be -+ * obtained internally) -+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (as this will be -+ * obtained internally) -+ * -+ */ -+void kbasep_js_runpool_release_ctx(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * @brief Variant of kbasep_js_runpool_release_ctx() that handles additional -+ * actions from completing an atom. -+ * -+ * This is usually called as part of completing an atom and releasing the -+ * refcount on the context held by the atom. -+ * -+ * Therefore, the extra actions carried out are part of handling actions queued -+ * on a completed atom, namely: -+ * - Releasing the atom's context attributes -+ * - Retrying the submission on a particular slot, because we couldn't submit -+ * on that slot from an IRQ handler. -+ * -+ * The locking conditions of this function are the same as those for -+ * kbasep_js_runpool_release_ctx() -+ */ -+void kbasep_js_runpool_release_ctx_and_katom_retained_state(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbasep_js_atom_retained_state *katom_retained_state); -+ -+/** -+ * @brief Variant of kbase_js_runpool_release_ctx() that assumes that -+ * kbasep_js_device_data::runpool_mutex and -+ * kbasep_js_kctx_info::ctx::jsctx_mutex are held by the caller, and does not -+ * attempt to schedule new contexts. -+ */ -+void kbasep_js_runpool_release_ctx_nolock(struct kbase_device *kbdev, -+ struct kbase_context *kctx); -+ -+/** -+ * @brief Schedule in a privileged context -+ * -+ * This schedules a context in regardless of the context priority. -+ * If the runpool is full, a context will be forced out of the runpool and the function will wait -+ * for the new context to be scheduled in. -+ * The context will be kept scheduled in (and the corresponding address space reserved) until -+ * kbasep_js_release_privileged_ctx is called). -+ * -+ * The following locking conditions are made on the caller: -+ * - it must \em not hold the hwaccess_lock, because it will be used internally. -+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be -+ * obtained internally) -+ * - it must \em not hold the kbase_device::mmu_hw_mutex (as this will be -+ * obtained internally) -+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (again, it's used internally). -+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex, because it will -+ * be used internally. -+ * -+ */ -+void kbasep_js_schedule_privileged_ctx(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * @brief Release a privileged context, allowing it to be scheduled out. -+ * -+ * See kbasep_js_runpool_release_ctx for potential side effects. -+ * -+ * The following locking conditions are made on the caller: -+ * - it must \em not hold the hwaccess_lock, because it will be used internally. -+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be -+ * obtained internally) -+ * - it must \em not hold the kbase_device::mmu_hw_mutex (as this will be -+ * obtained internally) -+ * -+ */ -+void kbasep_js_release_privileged_ctx(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * @brief Try to submit the next job on each slot -+ * -+ * The following locks may be used: -+ * - kbasep_js_device_data::runpool_mutex -+ * - hwaccess_lock -+ */ -+void kbase_js_try_run_jobs(struct kbase_device *kbdev); -+ -+/** -+ * @brief Suspend the job scheduler during a Power Management Suspend event. -+ * -+ * Causes all contexts to be removed from the runpool, and prevents any -+ * contexts from (re)entering the runpool. -+ * -+ * This does not handle suspending the one privileged context: the caller must -+ * instead do this by by suspending the GPU HW Counter Instrumentation. -+ * -+ * This will eventually cause all Power Management active references held by -+ * contexts on the runpool to be released, without running any more atoms. -+ * -+ * The caller must then wait for all Power Mangement active refcount to become -+ * zero before completing the suspend. -+ * -+ * The emptying mechanism may take some time to complete, since it can wait for -+ * jobs to complete naturally instead of forcing them to end quickly. However, -+ * this is bounded by the Job Scheduler's Job Timeouts. Hence, this -+ * function is guaranteed to complete in a finite time. -+ */ -+void kbasep_js_suspend(struct kbase_device *kbdev); -+ -+/** -+ * @brief Resume the Job Scheduler after a Power Management Resume event. -+ * -+ * This restores the actions from kbasep_js_suspend(): -+ * - Schedules contexts back into the runpool -+ * - Resumes running atoms on the GPU -+ */ -+void kbasep_js_resume(struct kbase_device *kbdev); -+ -+/** -+ * @brief Submit an atom to the job scheduler. -+ * -+ * The atom is enqueued on the context's ringbuffer. The caller must have -+ * ensured that all dependencies can be represented in the ringbuffer. -+ * -+ * Caller must hold jctx->lock -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] atom Pointer to the atom to submit -+ * -+ * @return Whether the context requires to be enqueued. */ -+bool kbase_js_dep_resolved_submit(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom); -+ -+/** -+ * jsctx_ll_flush_to_rb() - Pushes atoms from the linked list to ringbuffer. -+ * @kctx: Context Pointer -+ * @prio: Priority (specifies the queue together with js). -+ * @js: Job slot (specifies the queue together with prio). -+ * -+ * Pushes all possible atoms from the linked list to the ringbuffer. -+ * Number of atoms are limited to free space in the ringbuffer and -+ * number of available atoms in the linked list. -+ * -+ */ -+void jsctx_ll_flush_to_rb(struct kbase_context *kctx, int prio, int js); -+/** -+ * @brief Pull an atom from a context in the job scheduler for execution. -+ * -+ * The atom will not be removed from the ringbuffer at this stage. -+ * -+ * The HW access lock must be held when calling this function. -+ * -+ * @param[in] kctx Context to pull from -+ * @param[in] js Job slot to pull from -+ * @return Pointer to an atom, or NULL if there are no atoms for this -+ * slot that can be currently run. -+ */ -+struct kbase_jd_atom *kbase_js_pull(struct kbase_context *kctx, int js); -+ -+/** -+ * @brief Return an atom to the job scheduler ringbuffer. -+ * -+ * An atom is 'unpulled' if execution is stopped but intended to be returned to -+ * later. The most common reason for this is that the atom has been -+ * soft-stopped. -+ * -+ * Note that if multiple atoms are to be 'unpulled', they must be returned in -+ * the reverse order to which they were originally pulled. It is a programming -+ * error to return atoms in any other order. -+ * -+ * The HW access lock must be held when calling this function. -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] atom Pointer to the atom to unpull -+ */ -+void kbase_js_unpull(struct kbase_context *kctx, struct kbase_jd_atom *katom); -+ -+/** -+ * @brief Complete an atom from jd_done_worker(), removing it from the job -+ * scheduler ringbuffer. -+ * -+ * If the atom failed then all dependee atoms marked for failure propagation -+ * will also fail. -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] katom Pointer to the atom to complete -+ * @return true if the context is now idle (no jobs pulled) -+ * false otherwise -+ */ -+bool kbase_js_complete_atom_wq(struct kbase_context *kctx, -+ struct kbase_jd_atom *katom); -+ -+/** -+ * @brief Complete an atom. -+ * -+ * Most of the work required to complete an atom will be performed by -+ * jd_done_worker(). -+ * -+ * The HW access lock must be held when calling this function. -+ * -+ * @param[in] katom Pointer to the atom to complete -+ * @param[in] end_timestamp The time that the atom completed (may be NULL) -+ * -+ * Return: Atom that has now been unblocked and can now be run, or NULL if none -+ */ -+struct kbase_jd_atom *kbase_js_complete_atom(struct kbase_jd_atom *katom, -+ ktime_t *end_timestamp); -+ -+/** -+ * @brief Submit atoms from all available contexts. -+ * -+ * This will attempt to submit as many jobs as possible to the provided job -+ * slots. It will exit when either all job slots are full, or all contexts have -+ * been used. -+ * -+ * @param[in] kbdev Device pointer -+ * @param[in] js_mask Mask of job slots to submit to -+ */ -+void kbase_js_sched(struct kbase_device *kbdev, int js_mask); -+ -+/** -+ * kbase_jd_zap_context - Attempt to deschedule a context that is being -+ * destroyed -+ * @kctx: Context pointer -+ * -+ * This will attempt to remove a context from any internal job scheduler queues -+ * and perform any other actions to ensure a context will not be submitted -+ * from. -+ * -+ * If the context is currently scheduled, then the caller must wait for all -+ * pending jobs to complete before taking any further action. -+ */ -+void kbase_js_zap_context(struct kbase_context *kctx); -+ -+/** -+ * @brief Validate an atom -+ * -+ * This will determine whether the atom can be scheduled onto the GPU. Atoms -+ * with invalid combinations of core requirements will be rejected. -+ * -+ * @param[in] kbdev Device pointer -+ * @param[in] katom Atom to validate -+ * @return true if atom is valid -+ * false otherwise -+ */ -+bool kbase_js_is_atom_valid(struct kbase_device *kbdev, -+ struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_js_set_timeouts - update all JS timeouts with user specified data -+ * @kbdev: Device pointer -+ * -+ * Timeouts are specified through the 'js_timeouts' sysfs file. If a timeout is -+ * set to a positive number then that becomes the new value used, if a timeout -+ * is negative then the default is set. -+ */ -+void kbase_js_set_timeouts(struct kbase_device *kbdev); -+ -+/* -+ * Helpers follow -+ */ -+ -+/** -+ * @brief Check that a context is allowed to submit jobs on this policy -+ * -+ * The purpose of this abstraction is to hide the underlying data size, and wrap up -+ * the long repeated line of code. -+ * -+ * As with any bool, never test the return value with true. -+ * -+ * The caller must hold hwaccess_lock. -+ */ -+static inline bool kbasep_js_is_submit_allowed(struct kbasep_js_device_data *js_devdata, struct kbase_context *kctx) -+{ -+ u16 test_bit; -+ -+ /* Ensure context really is scheduled in */ -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ test_bit = (u16) (1u << kctx->as_nr); -+ -+ return (bool) (js_devdata->runpool_irq.submit_allowed & test_bit); -+} -+ -+/** -+ * @brief Allow a context to submit jobs on this policy -+ * -+ * The purpose of this abstraction is to hide the underlying data size, and wrap up -+ * the long repeated line of code. -+ * -+ * The caller must hold hwaccess_lock. -+ */ -+static inline void kbasep_js_set_submit_allowed(struct kbasep_js_device_data *js_devdata, struct kbase_context *kctx) -+{ -+ u16 set_bit; -+ -+ /* Ensure context really is scheduled in */ -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ set_bit = (u16) (1u << kctx->as_nr); -+ -+ dev_dbg(kctx->kbdev->dev, "JS: Setting Submit Allowed on %p (as=%d)", kctx, kctx->as_nr); -+ -+ js_devdata->runpool_irq.submit_allowed |= set_bit; -+} -+ -+/** -+ * @brief Prevent a context from submitting more jobs on this policy -+ * -+ * The purpose of this abstraction is to hide the underlying data size, and wrap up -+ * the long repeated line of code. -+ * -+ * The caller must hold hwaccess_lock. -+ */ -+static inline void kbasep_js_clear_submit_allowed(struct kbasep_js_device_data *js_devdata, struct kbase_context *kctx) -+{ -+ u16 clear_bit; -+ u16 clear_mask; -+ -+ /* Ensure context really is scheduled in */ -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ clear_bit = (u16) (1u << kctx->as_nr); -+ clear_mask = ~clear_bit; -+ -+ dev_dbg(kctx->kbdev->dev, "JS: Clearing Submit Allowed on %p (as=%d)", kctx, kctx->as_nr); -+ -+ js_devdata->runpool_irq.submit_allowed &= clear_mask; -+} -+ -+/** -+ * @brief Manage the 'retry_submit_on_slot' part of a kbase_jd_atom -+ */ -+static inline void kbasep_js_clear_job_retry_submit(struct kbase_jd_atom *atom) -+{ -+ atom->retry_submit_on_slot = KBASEP_JS_RETRY_SUBMIT_SLOT_INVALID; -+} -+ -+/** -+ * Mark a slot as requiring resubmission by carrying that information on a -+ * completing atom. -+ * -+ * @note This can ASSERT in debug builds if the submit slot has been set to -+ * something other than the current value for @a js. This is because you might -+ * be unintentionally stopping more jobs being submitted on the old submit -+ * slot, and that might cause a scheduling-hang. -+ * -+ * @note If you can guarantee that the atoms for the original slot will be -+ * submitted on some other slot, then call kbasep_js_clear_job_retry_submit() -+ * first to silence the ASSERT. -+ */ -+static inline void kbasep_js_set_job_retry_submit_slot(struct kbase_jd_atom *atom, int js) -+{ -+ KBASE_DEBUG_ASSERT(0 <= js && js <= BASE_JM_MAX_NR_SLOTS); -+ KBASE_DEBUG_ASSERT((atom->retry_submit_on_slot == -+ KBASEP_JS_RETRY_SUBMIT_SLOT_INVALID) -+ || (atom->retry_submit_on_slot == js)); -+ -+ atom->retry_submit_on_slot = js; -+} -+ -+/** -+ * Create an initial 'invalid' atom retained state, that requires no -+ * atom-related work to be done on releasing with -+ * kbasep_js_runpool_release_ctx_and_katom_retained_state() -+ */ -+static inline void kbasep_js_atom_retained_state_init_invalid(struct kbasep_js_atom_retained_state *retained_state) -+{ -+ retained_state->event_code = BASE_JD_EVENT_NOT_STARTED; -+ retained_state->core_req = KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID; -+ retained_state->retry_submit_on_slot = KBASEP_JS_RETRY_SUBMIT_SLOT_INVALID; -+} -+ -+/** -+ * Copy atom state that can be made available after jd_done_nolock() is called -+ * on that atom. -+ */ -+static inline void kbasep_js_atom_retained_state_copy(struct kbasep_js_atom_retained_state *retained_state, const struct kbase_jd_atom *katom) -+{ -+ retained_state->event_code = katom->event_code; -+ retained_state->core_req = katom->core_req; -+ retained_state->retry_submit_on_slot = katom->retry_submit_on_slot; -+ retained_state->sched_priority = katom->sched_priority; -+ retained_state->device_nr = katom->device_nr; -+} -+ -+/** -+ * @brief Determine whether an atom has finished (given its retained state), -+ * and so should be given back to userspace/removed from the system. -+ * -+ * Reasons for an atom not finishing include: -+ * - Being soft-stopped (and so, the atom should be resubmitted sometime later) -+ * -+ * @param[in] katom_retained_state the retained state of the atom to check -+ * @return false if the atom has not finished -+ * @return !=false if the atom has finished -+ */ -+static inline bool kbasep_js_has_atom_finished(const struct kbasep_js_atom_retained_state *katom_retained_state) -+{ -+ return (bool) (katom_retained_state->event_code != BASE_JD_EVENT_STOPPED && katom_retained_state->event_code != BASE_JD_EVENT_REMOVED_FROM_NEXT); -+} -+ -+/** -+ * @brief Determine whether a struct kbasep_js_atom_retained_state is valid -+ * -+ * An invalid struct kbasep_js_atom_retained_state is allowed, and indicates that the -+ * code should just ignore it. -+ * -+ * @param[in] katom_retained_state the atom's retained state to check -+ * @return false if the retained state is invalid, and can be ignored -+ * @return !=false if the retained state is valid -+ */ -+static inline bool kbasep_js_atom_retained_state_is_valid(const struct kbasep_js_atom_retained_state *katom_retained_state) -+{ -+ return (bool) (katom_retained_state->core_req != KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID); -+} -+ -+static inline bool kbasep_js_get_atom_retry_submit_slot(const struct kbasep_js_atom_retained_state *katom_retained_state, int *res) -+{ -+ int js = katom_retained_state->retry_submit_on_slot; -+ -+ *res = js; -+ return (bool) (js >= 0); -+} -+ -+/** -+ * @brief Variant of kbasep_js_runpool_lookup_ctx() that can be used when the -+ * context is guaranteed to be already previously retained. -+ * -+ * It is a programming error to supply the \a as_nr of a context that has not -+ * been previously retained/has a busy refcount of zero. The only exception is -+ * when there is no ctx in \a as_nr (NULL returned). -+ * -+ * The following locking conditions are made on the caller: -+ * - it must \em not hold the hwaccess_lock, because it will be used internally. -+ * -+ * @return a valid struct kbase_context on success, with a refcount that is guaranteed -+ * to be non-zero and unmodified by this function. -+ * @return NULL on failure, indicating that no context was found in \a as_nr -+ */ -+static inline struct kbase_context *kbasep_js_runpool_lookup_ctx_noretain(struct kbase_device *kbdev, int as_nr) -+{ -+ struct kbase_context *found_kctx; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(0 <= as_nr && as_nr < BASE_MAX_NR_AS); -+ -+ found_kctx = kbdev->as_to_kctx[as_nr]; -+ KBASE_DEBUG_ASSERT(found_kctx == NULL || -+ atomic_read(&found_kctx->refcount) > 0); -+ -+ return found_kctx; -+} -+ -+/* -+ * The following locking conditions are made on the caller: -+ * - The caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * - The caller must hold the kbasep_js_device_data::runpool_mutex -+ */ -+static inline void kbase_js_runpool_inc_context_count( -+ struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex); -+ lockdep_assert_held(&js_devdata->runpool_mutex); -+ -+ /* Track total contexts */ -+ KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running < S8_MAX); -+ ++(js_devdata->nr_all_contexts_running); -+ -+ if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { -+ /* Track contexts that can submit jobs */ -+ KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running < -+ S8_MAX); -+ ++(js_devdata->nr_user_contexts_running); -+ } -+} -+ -+/* -+ * The following locking conditions are made on the caller: -+ * - The caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex. -+ * - The caller must hold the kbasep_js_device_data::runpool_mutex -+ */ -+static inline void kbase_js_runpool_dec_context_count( -+ struct kbase_device *kbdev, -+ struct kbase_context *kctx) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex); -+ lockdep_assert_held(&js_devdata->runpool_mutex); -+ -+ /* Track total contexts */ -+ --(js_devdata->nr_all_contexts_running); -+ KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running >= 0); -+ -+ if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { -+ /* Track contexts that can submit jobs */ -+ --(js_devdata->nr_user_contexts_running); -+ KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running >= 0); -+ } -+} -+ -+ -+/** -+ * @brief Submit atoms from all available contexts to all job slots. -+ * -+ * This will attempt to submit as many jobs as possible. It will exit when -+ * either all job slots are full, or all contexts have been used. -+ * -+ * @param[in] kbdev Device pointer -+ */ -+static inline void kbase_js_sched_all(struct kbase_device *kbdev) -+{ -+ kbase_js_sched(kbdev, (1 << kbdev->gpu_props.num_job_slots) - 1); -+} -+ -+extern const int -+kbasep_js_atom_priority_to_relative[BASE_JD_NR_PRIO_LEVELS]; -+ -+extern const base_jd_prio -+kbasep_js_relative_priority_to_atom[KBASE_JS_ATOM_SCHED_PRIO_COUNT]; -+ -+/** -+ * kbasep_js_atom_prio_to_sched_prio(): - Convert atom priority (base_jd_prio) -+ * to relative ordering -+ * @atom_prio: Priority ID to translate. -+ * -+ * Atom priority values for @ref base_jd_prio cannot be compared directly to -+ * find out which are higher or lower. -+ * -+ * This function will convert base_jd_prio values for successively lower -+ * priorities into a monotonically increasing sequence. That is, the lower the -+ * base_jd_prio priority, the higher the value produced by this function. This -+ * is in accordance with how the rest of the kernel treates priority. -+ * -+ * The mapping is 1:1 and the size of the valid input range is the same as the -+ * size of the valid output range, i.e. -+ * KBASE_JS_ATOM_SCHED_PRIO_COUNT == BASE_JD_NR_PRIO_LEVELS -+ * -+ * Note This must be kept in sync with BASE_JD_PRIO_<...> definitions -+ * -+ * Return: On success: a value in the inclusive range -+ * 0..KBASE_JS_ATOM_SCHED_PRIO_COUNT-1. On failure: -+ * KBASE_JS_ATOM_SCHED_PRIO_INVALID -+ */ -+static inline int kbasep_js_atom_prio_to_sched_prio(base_jd_prio atom_prio) -+{ -+ if (atom_prio >= BASE_JD_NR_PRIO_LEVELS) -+ return KBASE_JS_ATOM_SCHED_PRIO_INVALID; -+ -+ return kbasep_js_atom_priority_to_relative[atom_prio]; -+} -+ -+static inline base_jd_prio kbasep_js_sched_prio_to_atom_prio(int sched_prio) -+{ -+ unsigned int prio_idx; -+ -+ KBASE_DEBUG_ASSERT(0 <= sched_prio -+ && sched_prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT); -+ -+ prio_idx = (unsigned int)sched_prio; -+ -+ return kbasep_js_relative_priority_to_atom[prio_idx]; -+} -+ -+ /** @} *//* end group kbase_js */ -+ /** @} *//* end group base_kbase_api */ -+ /** @} *//* end group base_api */ -+ -+#endif /* _KBASE_JS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_js_ctx_attr.c b/drivers/gpu/arm/midgard/mali_kbase_js_ctx_attr.c -new file mode 100644 -index 0000000..321506a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_js_ctx_attr.c -@@ -0,0 +1,301 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+#include -+#include -+ -+/* -+ * Private functions follow -+ */ -+ -+/** -+ * @brief Check whether a ctx has a certain attribute, and if so, retain that -+ * attribute on the runpool. -+ * -+ * Requires: -+ * - jsctx mutex -+ * - runpool_irq spinlock -+ * - ctx is scheduled on the runpool -+ * -+ * @return true indicates a change in ctx attributes state of the runpool. -+ * In this state, the scheduler might be able to submit more jobs than -+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock() -+ * or similar is called sometime later. -+ * @return false indicates no change in ctx attributes state of the runpool. -+ */ -+static bool kbasep_js_ctx_attr_runpool_retain_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ bool runpool_state_changed = false; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT); -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, attribute) != false) { -+ KBASE_DEBUG_ASSERT(js_devdata->runpool_irq.ctx_attr_ref_count[attribute] < S8_MAX); -+ ++(js_devdata->runpool_irq.ctx_attr_ref_count[attribute]); -+ -+ if (js_devdata->runpool_irq.ctx_attr_ref_count[attribute] == 1) { -+ /* First refcount indicates a state change */ -+ runpool_state_changed = true; -+ KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_ON_RUNPOOL, kctx, NULL, 0u, attribute); -+ } -+ } -+ -+ return runpool_state_changed; -+} -+ -+/** -+ * @brief Check whether a ctx has a certain attribute, and if so, release that -+ * attribute on the runpool. -+ * -+ * Requires: -+ * - jsctx mutex -+ * - runpool_irq spinlock -+ * - ctx is scheduled on the runpool -+ * -+ * @return true indicates a change in ctx attributes state of the runpool. -+ * In this state, the scheduler might be able to submit more jobs than -+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock() -+ * or similar is called sometime later. -+ * @return false indicates no change in ctx attributes state of the runpool. -+ */ -+static bool kbasep_js_ctx_attr_runpool_release_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ struct kbasep_js_kctx_info *js_kctx_info; -+ bool runpool_state_changed = false; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT); -+ js_devdata = &kbdev->js_data; -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); -+ -+ if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, attribute) != false) { -+ KBASE_DEBUG_ASSERT(js_devdata->runpool_irq.ctx_attr_ref_count[attribute] > 0); -+ --(js_devdata->runpool_irq.ctx_attr_ref_count[attribute]); -+ -+ if (js_devdata->runpool_irq.ctx_attr_ref_count[attribute] == 0) { -+ /* Last de-refcount indicates a state change */ -+ runpool_state_changed = true; -+ KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_OFF_RUNPOOL, kctx, NULL, 0u, attribute); -+ } -+ } -+ -+ return runpool_state_changed; -+} -+ -+/** -+ * @brief Retain a certain attribute on a ctx, also retaining it on the runpool -+ * if the context is scheduled. -+ * -+ * Requires: -+ * - jsctx mutex -+ * - If the context is scheduled, then runpool_irq spinlock must also be held -+ * -+ * @return true indicates a change in ctx attributes state of the runpool. -+ * This may allow the scheduler to submit more jobs than previously. -+ * @return false indicates no change in ctx attributes state of the runpool. -+ */ -+static bool kbasep_js_ctx_attr_ctx_retain_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute) -+{ -+ struct kbasep_js_kctx_info *js_kctx_info; -+ bool runpool_state_changed = false; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT); -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex); -+ KBASE_DEBUG_ASSERT(js_kctx_info->ctx.ctx_attr_ref_count[attribute] < U32_MAX); -+ -+ ++(js_kctx_info->ctx.ctx_attr_ref_count[attribute]); -+ -+ if (kbase_ctx_flag(kctx, KCTX_SCHEDULED) && js_kctx_info->ctx.ctx_attr_ref_count[attribute] == 1) { -+ /* Only ref-count the attribute on the runpool for the first time this contexts sees this attribute */ -+ KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_ON_CTX, kctx, NULL, 0u, attribute); -+ runpool_state_changed = kbasep_js_ctx_attr_runpool_retain_attr(kbdev, kctx, attribute); -+ } -+ -+ return runpool_state_changed; -+} -+ -+/* -+ * @brief Release a certain attribute on a ctx, also releasing it from the runpool -+ * if the context is scheduled. -+ * -+ * Requires: -+ * - jsctx mutex -+ * - If the context is scheduled, then runpool_irq spinlock must also be held -+ * -+ * @return true indicates a change in ctx attributes state of the runpool. -+ * This may allow the scheduler to submit more jobs than previously. -+ * @return false indicates no change in ctx attributes state of the runpool. -+ */ -+static bool kbasep_js_ctx_attr_ctx_release_attr(struct kbase_device *kbdev, struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute) -+{ -+ struct kbasep_js_kctx_info *js_kctx_info; -+ bool runpool_state_changed = false; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT); -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex); -+ KBASE_DEBUG_ASSERT(js_kctx_info->ctx.ctx_attr_ref_count[attribute] > 0); -+ -+ if (kbase_ctx_flag(kctx, KCTX_SCHEDULED) && js_kctx_info->ctx.ctx_attr_ref_count[attribute] == 1) { -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ /* Only de-ref-count the attribute on the runpool when this is the last ctx-reference to it */ -+ runpool_state_changed = kbasep_js_ctx_attr_runpool_release_attr(kbdev, kctx, attribute); -+ KBASE_TRACE_ADD(kbdev, JS_CTX_ATTR_NOW_OFF_CTX, kctx, NULL, 0u, attribute); -+ } -+ -+ /* De-ref must happen afterwards, because kbasep_js_ctx_attr_runpool_release() needs to check it too */ -+ --(js_kctx_info->ctx.ctx_attr_ref_count[attribute]); -+ -+ return runpool_state_changed; -+} -+ -+/* -+ * More commonly used public functions -+ */ -+ -+void kbasep_js_ctx_attr_set_initial_attrs(struct kbase_device *kbdev, struct kbase_context *kctx) -+{ -+ bool runpool_state_changed = false; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ if (kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { -+ /* This context never submits, so don't track any scheduling attributes */ -+ return; -+ } -+ -+ /* Transfer attributes held in the context flags for contexts that have submit enabled */ -+ -+ /* ... More attributes can be added here ... */ -+ -+ /* The context should not have been scheduled yet, so ASSERT if this caused -+ * runpool state changes (note that other threads *can't* affect the value -+ * of runpool_state_changed, due to how it's calculated) */ -+ KBASE_DEBUG_ASSERT(runpool_state_changed == false); -+ CSTD_UNUSED(runpool_state_changed); -+} -+ -+void kbasep_js_ctx_attr_runpool_retain_ctx(struct kbase_device *kbdev, struct kbase_context *kctx) -+{ -+ bool runpool_state_changed; -+ int i; -+ -+ /* Retain any existing attributes */ -+ for (i = 0; i < KBASEP_JS_CTX_ATTR_COUNT; ++i) { -+ if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, (enum kbasep_js_ctx_attr) i) != false) { -+ /* The context is being scheduled in, so update the runpool with the new attributes */ -+ runpool_state_changed = kbasep_js_ctx_attr_runpool_retain_attr(kbdev, kctx, (enum kbasep_js_ctx_attr) i); -+ -+ /* We don't need to know about state changed, because retaining a -+ * context occurs on scheduling it, and that itself will also try -+ * to run new atoms */ -+ CSTD_UNUSED(runpool_state_changed); -+ } -+ } -+} -+ -+bool kbasep_js_ctx_attr_runpool_release_ctx(struct kbase_device *kbdev, struct kbase_context *kctx) -+{ -+ bool runpool_state_changed = false; -+ int i; -+ -+ /* Release any existing attributes */ -+ for (i = 0; i < KBASEP_JS_CTX_ATTR_COUNT; ++i) { -+ if (kbasep_js_ctx_attr_is_attr_on_ctx(kctx, (enum kbasep_js_ctx_attr) i) != false) { -+ /* The context is being scheduled out, so update the runpool on the removed attributes */ -+ runpool_state_changed |= kbasep_js_ctx_attr_runpool_release_attr(kbdev, kctx, (enum kbasep_js_ctx_attr) i); -+ } -+ } -+ -+ return runpool_state_changed; -+} -+ -+void kbasep_js_ctx_attr_ctx_retain_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ bool runpool_state_changed = false; -+ base_jd_core_req core_req; -+ -+ KBASE_DEBUG_ASSERT(katom); -+ core_req = katom->core_req; -+ -+ if (core_req & BASE_JD_REQ_ONLY_COMPUTE) -+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE); -+ else -+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_NON_COMPUTE); -+ -+ if ((core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T)) != 0 && (core_req & (BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)) == 0) { -+ /* Atom that can run on slot1 or slot2, and can use all cores */ -+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES); -+ } -+ -+ /* We don't need to know about state changed, because retaining an -+ * atom occurs on adding it, and that itself will also try to run -+ * new atoms */ -+ CSTD_UNUSED(runpool_state_changed); -+} -+ -+bool kbasep_js_ctx_attr_ctx_release_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbasep_js_atom_retained_state *katom_retained_state) -+{ -+ bool runpool_state_changed = false; -+ base_jd_core_req core_req; -+ -+ KBASE_DEBUG_ASSERT(katom_retained_state); -+ core_req = katom_retained_state->core_req; -+ -+ /* No-op for invalid atoms */ -+ if (kbasep_js_atom_retained_state_is_valid(katom_retained_state) == false) -+ return false; -+ -+ if (core_req & BASE_JD_REQ_ONLY_COMPUTE) -+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE); -+ else -+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_NON_COMPUTE); -+ -+ if ((core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T)) != 0 && (core_req & (BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)) == 0) { -+ /* Atom that can run on slot1 or slot2, and can use all cores */ -+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr(kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES); -+ } -+ -+ return runpool_state_changed; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_js_ctx_attr.h b/drivers/gpu/arm/midgard/mali_kbase_js_ctx_attr.h -new file mode 100644 -index 0000000..ce91833 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_js_ctx_attr.h -@@ -0,0 +1,158 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_js_ctx_attr.h -+ * Job Scheduler Context Attribute APIs -+ */ -+ -+#ifndef _KBASE_JS_CTX_ATTR_H_ -+#define _KBASE_JS_CTX_ATTR_H_ -+ -+/** -+ * @addtogroup base_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup base_kbase_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup kbase_js -+ * @{ -+ */ -+ -+/** -+ * Set the initial attributes of a context (when context create flags are set) -+ * -+ * Requires: -+ * - Hold the jsctx_mutex -+ */ -+void kbasep_js_ctx_attr_set_initial_attrs(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * Retain all attributes of a context -+ * -+ * This occurs on scheduling in the context on the runpool (but after -+ * is_scheduled is set) -+ * -+ * Requires: -+ * - jsctx mutex -+ * - runpool_irq spinlock -+ * - ctx->is_scheduled is true -+ */ -+void kbasep_js_ctx_attr_runpool_retain_ctx(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * Release all attributes of a context -+ * -+ * This occurs on scheduling out the context from the runpool (but before -+ * is_scheduled is cleared) -+ * -+ * Requires: -+ * - jsctx mutex -+ * - runpool_irq spinlock -+ * - ctx->is_scheduled is true -+ * -+ * @return true indicates a change in ctx attributes state of the runpool. -+ * In this state, the scheduler might be able to submit more jobs than -+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock() -+ * or similar is called sometime later. -+ * @return false indicates no change in ctx attributes state of the runpool. -+ */ -+bool kbasep_js_ctx_attr_runpool_release_ctx(struct kbase_device *kbdev, struct kbase_context *kctx); -+ -+/** -+ * Retain all attributes of an atom -+ * -+ * This occurs on adding an atom to a context -+ * -+ * Requires: -+ * - jsctx mutex -+ * - If the context is scheduled, then runpool_irq spinlock must also be held -+ */ -+void kbasep_js_ctx_attr_ctx_retain_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom); -+ -+/** -+ * Release all attributes of an atom, given its retained state. -+ * -+ * This occurs after (permanently) removing an atom from a context -+ * -+ * Requires: -+ * - jsctx mutex -+ * - If the context is scheduled, then runpool_irq spinlock must also be held -+ * -+ * This is a no-op when \a katom_retained_state is invalid. -+ * -+ * @return true indicates a change in ctx attributes state of the runpool. -+ * In this state, the scheduler might be able to submit more jobs than -+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock() -+ * or similar is called sometime later. -+ * @return false indicates no change in ctx attributes state of the runpool. -+ */ -+bool kbasep_js_ctx_attr_ctx_release_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbasep_js_atom_retained_state *katom_retained_state); -+ -+/** -+ * Requires: -+ * - runpool_irq spinlock -+ */ -+static inline s8 kbasep_js_ctx_attr_count_on_runpool(struct kbase_device *kbdev, enum kbasep_js_ctx_attr attribute) -+{ -+ struct kbasep_js_device_data *js_devdata; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT); -+ js_devdata = &kbdev->js_data; -+ -+ return js_devdata->runpool_irq.ctx_attr_ref_count[attribute]; -+} -+ -+/** -+ * Requires: -+ * - runpool_irq spinlock -+ */ -+static inline bool kbasep_js_ctx_attr_is_attr_on_runpool(struct kbase_device *kbdev, enum kbasep_js_ctx_attr attribute) -+{ -+ /* In general, attributes are 'on' when they have a non-zero refcount (note: the refcount will never be < 0) */ -+ return (bool) kbasep_js_ctx_attr_count_on_runpool(kbdev, attribute); -+} -+ -+/** -+ * Requires: -+ * - jsctx mutex -+ */ -+static inline bool kbasep_js_ctx_attr_is_attr_on_ctx(struct kbase_context *kctx, enum kbasep_js_ctx_attr attribute) -+{ -+ struct kbasep_js_kctx_info *js_kctx_info; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(attribute < KBASEP_JS_CTX_ATTR_COUNT); -+ js_kctx_info = &kctx->jctx.sched_info; -+ -+ /* In general, attributes are 'on' when they have a refcount (which should never be < 0) */ -+ return (bool) (js_kctx_info->ctx.ctx_attr_ref_count[attribute]); -+} -+ -+ /** @} *//* end group kbase_js */ -+ /** @} *//* end group base_kbase_api */ -+ /** @} *//* end group base_api */ -+ -+#endif /* _KBASE_JS_DEFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_js_defs.h b/drivers/gpu/arm/midgard/mali_kbase_js_defs.h -new file mode 100644 -index 0000000..ba8b644 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_js_defs.h -@@ -0,0 +1,386 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_js.h -+ * Job Scheduler Type Definitions -+ */ -+ -+#ifndef _KBASE_JS_DEFS_H_ -+#define _KBASE_JS_DEFS_H_ -+ -+/** -+ * @addtogroup base_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup base_kbase_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup kbase_js -+ * @{ -+ */ -+/* Forward decls */ -+struct kbase_device; -+struct kbase_jd_atom; -+ -+ -+typedef u32 kbase_context_flags; -+ -+struct kbasep_atom_req { -+ base_jd_core_req core_req; -+ kbase_context_flags ctx_req; -+ u32 device_nr; -+}; -+ -+/** Callback function run on all of a context's jobs registered with the Job -+ * Scheduler */ -+typedef void (*kbasep_js_ctx_job_cb)(struct kbase_device *kbdev, struct kbase_jd_atom *katom); -+ -+/** -+ * @brief Maximum number of jobs that can be submitted to a job slot whilst -+ * inside the IRQ handler. -+ * -+ * This is important because GPU NULL jobs can complete whilst the IRQ handler -+ * is running. Otherwise, it potentially allows an unlimited number of GPU NULL -+ * jobs to be submitted inside the IRQ handler, which increases IRQ latency. -+ */ -+#define KBASE_JS_MAX_JOB_SUBMIT_PER_SLOT_PER_IRQ 2 -+ -+/** -+ * @brief Context attributes -+ * -+ * Each context attribute can be thought of as a boolean value that caches some -+ * state information about either the runpool, or the context: -+ * - In the case of the runpool, it is a cache of "Do any contexts owned by -+ * the runpool have attribute X?" -+ * - In the case of a context, it is a cache of "Do any atoms owned by the -+ * context have attribute X?" -+ * -+ * The boolean value of the context attributes often affect scheduling -+ * decisions, such as affinities to use and job slots to use. -+ * -+ * To accomodate changes of state in the context, each attribute is refcounted -+ * in the context, and in the runpool for all running contexts. Specifically: -+ * - The runpool holds a refcount of how many contexts in the runpool have this -+ * attribute. -+ * - The context holds a refcount of how many atoms have this attribute. -+ */ -+enum kbasep_js_ctx_attr { -+ /** Attribute indicating a context that contains Compute jobs. That is, -+ * the context has jobs of type @ref BASE_JD_REQ_ONLY_COMPUTE -+ * -+ * @note A context can be both 'Compute' and 'Non Compute' if it contains -+ * both types of jobs. -+ */ -+ KBASEP_JS_CTX_ATTR_COMPUTE, -+ -+ /** Attribute indicating a context that contains Non-Compute jobs. That is, -+ * the context has some jobs that are \b not of type @ref -+ * BASE_JD_REQ_ONLY_COMPUTE. -+ * -+ * @note A context can be both 'Compute' and 'Non Compute' if it contains -+ * both types of jobs. -+ */ -+ KBASEP_JS_CTX_ATTR_NON_COMPUTE, -+ -+ /** Attribute indicating that a context contains compute-job atoms that -+ * aren't restricted to a coherent group, and can run on all cores. -+ * -+ * Specifically, this is when the atom's \a core_req satisfy: -+ * - (\a core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T) // uses slot 1 or slot 2 -+ * - && !(\a core_req & BASE_JD_REQ_COHERENT_GROUP) // not restricted to coherent groups -+ * -+ * Such atoms could be blocked from running if one of the coherent groups -+ * is being used by another job slot, so tracking this context attribute -+ * allows us to prevent such situations. -+ * -+ * @note This doesn't take into account the 1-coregroup case, where all -+ * compute atoms would effectively be able to run on 'all cores', but -+ * contexts will still not always get marked with this attribute. Instead, -+ * it is the caller's responsibility to take into account the number of -+ * coregroups when interpreting this attribute. -+ * -+ * @note Whilst Tiler atoms are normally combined with -+ * BASE_JD_REQ_COHERENT_GROUP, it is possible to send such atoms without -+ * BASE_JD_REQ_COHERENT_GROUP set. This is an unlikely case, but it's easy -+ * enough to handle anyway. -+ */ -+ KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES, -+ -+ /** Must be the last in the enum */ -+ KBASEP_JS_CTX_ATTR_COUNT -+}; -+ -+enum { -+ /** Bit indicating that new atom should be started because this atom completed */ -+ KBASE_JS_ATOM_DONE_START_NEW_ATOMS = (1u << 0), -+ /** Bit indicating that the atom was evicted from the JS_NEXT registers */ -+ KBASE_JS_ATOM_DONE_EVICTED_FROM_NEXT = (1u << 1) -+}; -+ -+/** Combination of KBASE_JS_ATOM_DONE_<...> bits */ -+typedef u32 kbasep_js_atom_done_code; -+ -+/** -+ * @brief KBase Device Data Job Scheduler sub-structure -+ * -+ * This encapsulates the current context of the Job Scheduler on a particular -+ * device. This context is global to the device, and is not tied to any -+ * particular struct kbase_context running on the device. -+ * -+ * nr_contexts_running and as_free are optimized for packing together (by making -+ * them smaller types than u32). The operations on them should rarely involve -+ * masking. The use of signed types for arithmetic indicates to the compiler that -+ * the value will not rollover (which would be undefined behavior), and so under -+ * the Total License model, it is free to make optimizations based on that (i.e. -+ * to remove masking). -+ */ -+struct kbasep_js_device_data { -+ /* Sub-structure to collect together Job Scheduling data used in IRQ -+ * context. The hwaccess_lock must be held when accessing. */ -+ struct runpool_irq { -+ /** Bitvector indicating whether a currently scheduled context is allowed to submit jobs. -+ * When bit 'N' is set in this, it indicates whether the context bound to address space -+ * 'N' is allowed to submit jobs. -+ */ -+ u16 submit_allowed; -+ -+ /** Context Attributes: -+ * Each is large enough to hold a refcount of the number of contexts -+ * that can fit into the runpool. This is currently BASE_MAX_NR_AS -+ * -+ * Note that when BASE_MAX_NR_AS==16 we need 5 bits (not 4) to store -+ * the refcount. Hence, it's not worthwhile reducing this to -+ * bit-manipulation on u32s to save space (where in contrast, 4 bit -+ * sub-fields would be easy to do and would save space). -+ * -+ * Whilst this must not become negative, the sign bit is used for: -+ * - error detection in debug builds -+ * - Optimization: it is undefined for a signed int to overflow, and so -+ * the compiler can optimize for that never happening (thus, no masking -+ * is required on updating the variable) */ -+ s8 ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_COUNT]; -+ -+ /* -+ * Affinity management and tracking -+ */ -+ /** Bitvector to aid affinity checking. Element 'n' bit 'i' indicates -+ * that slot 'n' is using core i (i.e. slot_affinity_refcount[n][i] > 0) */ -+ u64 slot_affinities[BASE_JM_MAX_NR_SLOTS]; -+ /** Refcount for each core owned by each slot. Used to generate the -+ * slot_affinities array of bitvectors -+ * -+ * The value of the refcount will not exceed BASE_JM_SUBMIT_SLOTS, -+ * because it is refcounted only when a job is definitely about to be -+ * submitted to a slot, and is de-refcounted immediately after a job -+ * finishes */ -+ s8 slot_affinity_refcount[BASE_JM_MAX_NR_SLOTS][64]; -+ } runpool_irq; -+ -+ /** -+ * Run Pool mutex, for managing contexts within the runpool. -+ * Unless otherwise specified, you must hold this lock whilst accessing any -+ * members that follow -+ * -+ * In addition, this is used to access: -+ * - the kbasep_js_kctx_info::runpool substructure -+ */ -+ struct mutex runpool_mutex; -+ -+ /** -+ * Queue Lock, used to access the Policy's queue of contexts independently -+ * of the Run Pool. -+ * -+ * Of course, you don't need the Run Pool lock to access this. -+ */ -+ struct mutex queue_mutex; -+ -+ /** -+ * Scheduling semaphore. This must be held when calling -+ * kbase_jm_kick() -+ */ -+ struct semaphore schedule_sem; -+ -+ /** -+ * List of contexts that can currently be pulled from -+ */ -+ struct list_head ctx_list_pullable[BASE_JM_MAX_NR_SLOTS]; -+ /** -+ * List of contexts that can not currently be pulled from, but have -+ * jobs currently running. -+ */ -+ struct list_head ctx_list_unpullable[BASE_JM_MAX_NR_SLOTS]; -+ -+ /** Number of currently scheduled user contexts (excluding ones that are not submitting jobs) */ -+ s8 nr_user_contexts_running; -+ /** Number of currently scheduled contexts (including ones that are not submitting jobs) */ -+ s8 nr_all_contexts_running; -+ -+ /** Core Requirements to match up with base_js_atom's core_req memeber -+ * @note This is a write-once member, and so no locking is required to read */ -+ base_jd_core_req js_reqs[BASE_JM_MAX_NR_SLOTS]; -+ -+ u32 scheduling_period_ns; /*< Value for JS_SCHEDULING_PERIOD_NS */ -+ u32 soft_stop_ticks; /*< Value for JS_SOFT_STOP_TICKS */ -+ u32 soft_stop_ticks_cl; /*< Value for JS_SOFT_STOP_TICKS_CL */ -+ u32 hard_stop_ticks_ss; /*< Value for JS_HARD_STOP_TICKS_SS */ -+ u32 hard_stop_ticks_cl; /*< Value for JS_HARD_STOP_TICKS_CL */ -+ u32 hard_stop_ticks_dumping; /*< Value for JS_HARD_STOP_TICKS_DUMPING */ -+ u32 gpu_reset_ticks_ss; /*< Value for JS_RESET_TICKS_SS */ -+ u32 gpu_reset_ticks_cl; /*< Value for JS_RESET_TICKS_CL */ -+ u32 gpu_reset_ticks_dumping; /*< Value for JS_RESET_TICKS_DUMPING */ -+ u32 ctx_timeslice_ns; /**< Value for JS_CTX_TIMESLICE_NS */ -+ -+ /**< Value for JS_SOFT_JOB_TIMEOUT */ -+ atomic_t soft_job_timeout_ms; -+ -+ /** List of suspended soft jobs */ -+ struct list_head suspended_soft_jobs_list; -+ -+#ifdef CONFIG_MALI_DEBUG -+ /* Support soft-stop on a single context */ -+ bool softstop_always; -+#endif /* CONFIG_MALI_DEBUG */ -+ -+ /** The initalized-flag is placed at the end, to avoid cache-pollution (we should -+ * only be using this during init/term paths). -+ * @note This is a write-once member, and so no locking is required to read */ -+ int init_status; -+ -+ /* Number of contexts that can currently be pulled from */ -+ u32 nr_contexts_pullable; -+ -+ /* Number of contexts that can either be pulled from or are currently -+ * running */ -+ atomic_t nr_contexts_runnable; -+}; -+ -+/** -+ * @brief KBase Context Job Scheduling information structure -+ * -+ * This is a substructure in the struct kbase_context that encapsulates all the -+ * scheduling information. -+ */ -+struct kbasep_js_kctx_info { -+ -+ /** -+ * Job Scheduler Context information sub-structure. These members are -+ * accessed regardless of whether the context is: -+ * - In the Policy's Run Pool -+ * - In the Policy's Queue -+ * - Not queued nor in the Run Pool. -+ * -+ * You must obtain the jsctx_mutex before accessing any other members of -+ * this substructure. -+ * -+ * You may not access any of these members from IRQ context. -+ */ -+ struct kbase_jsctx { -+ struct mutex jsctx_mutex; /**< Job Scheduler Context lock */ -+ -+ /** Number of jobs ready to run - does \em not include the jobs waiting in -+ * the dispatcher, and dependency-only jobs. See kbase_jd_context::job_nr -+ * for such jobs*/ -+ u32 nr_jobs; -+ -+ /** Context Attributes: -+ * Each is large enough to hold a refcount of the number of atoms on -+ * the context. **/ -+ u32 ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_COUNT]; -+ -+ /** -+ * Wait queue to wait for KCTX_SHEDULED flag state changes. -+ * */ -+ wait_queue_head_t is_scheduled_wait; -+ -+ /** Link implementing JS queues. Context can be present on one -+ * list per job slot -+ */ -+ struct list_head ctx_list_entry[BASE_JM_MAX_NR_SLOTS]; -+ } ctx; -+ -+ /* The initalized-flag is placed at the end, to avoid cache-pollution (we should -+ * only be using this during init/term paths) */ -+ int init_status; -+}; -+ -+/** Subset of atom state that can be available after jd_done_nolock() is called -+ * on that atom. A copy must be taken via kbasep_js_atom_retained_state_copy(), -+ * because the original atom could disappear. */ -+struct kbasep_js_atom_retained_state { -+ /** Event code - to determine whether the atom has finished */ -+ enum base_jd_event_code event_code; -+ /** core requirements */ -+ base_jd_core_req core_req; -+ /* priority */ -+ int sched_priority; -+ /** Job Slot to retry submitting to if submission from IRQ handler failed */ -+ int retry_submit_on_slot; -+ /* Core group atom was executed on */ -+ u32 device_nr; -+ -+}; -+ -+/** -+ * Value signifying 'no retry on a slot required' for: -+ * - kbase_js_atom_retained_state::retry_submit_on_slot -+ * - kbase_jd_atom::retry_submit_on_slot -+ */ -+#define KBASEP_JS_RETRY_SUBMIT_SLOT_INVALID (-1) -+ -+/** -+ * base_jd_core_req value signifying 'invalid' for a kbase_jd_atom_retained_state. -+ * -+ * @see kbase_atom_retained_state_is_valid() -+ */ -+#define KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID BASE_JD_REQ_DEP -+ -+/** -+ * @brief The JS timer resolution, in microseconds -+ * -+ * Any non-zero difference in time will be at least this size. -+ */ -+#define KBASEP_JS_TICK_RESOLUTION_US 1 -+ -+/* -+ * Internal atom priority defines for kbase_jd_atom::sched_prio -+ */ -+enum { -+ KBASE_JS_ATOM_SCHED_PRIO_HIGH = 0, -+ KBASE_JS_ATOM_SCHED_PRIO_MED, -+ KBASE_JS_ATOM_SCHED_PRIO_LOW, -+ KBASE_JS_ATOM_SCHED_PRIO_COUNT, -+}; -+ -+/* Invalid priority for kbase_jd_atom::sched_prio */ -+#define KBASE_JS_ATOM_SCHED_PRIO_INVALID -1 -+ -+/* Default priority in the case of contexts with no atoms, or being lenient -+ * about invalid priorities from userspace */ -+#define KBASE_JS_ATOM_SCHED_PRIO_DEFAULT KBASE_JS_ATOM_SCHED_PRIO_MED -+ -+ /** @} *//* end group kbase_js */ -+ /** @} *//* end group base_kbase_api */ -+ /** @} *//* end group base_api */ -+ -+#endif /* _KBASE_JS_DEFS_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_linux.h b/drivers/gpu/arm/midgard/mali_kbase_linux.h -new file mode 100644 -index 0000000..6d1e61f ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_linux.h -@@ -0,0 +1,43 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_linux.h -+ * Base kernel APIs, Linux implementation. -+ */ -+ -+#ifndef _KBASE_LINUX_H_ -+#define _KBASE_LINUX_H_ -+ -+/* All things that are needed for the Linux port. */ -+#include -+#include -+#include -+#include -+#include -+ -+#if (defined(MALI_KERNEL_TEST_API) && (1 == MALI_KERNEL_TEST_API)) -+ #define KBASE_EXPORT_TEST_API(func) EXPORT_SYMBOL(func) -+#else -+ #define KBASE_EXPORT_TEST_API(func) -+#endif -+ -+#define KBASE_EXPORT_SYMBOL(func) EXPORT_SYMBOL(func) -+ -+#endif /* _KBASE_LINUX_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem.c b/drivers/gpu/arm/midgard/mali_kbase_mem.c -new file mode 100644 -index 0000000..6fefffe ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem.c -@@ -0,0 +1,2869 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_mem.c -+ * Base kernel memory APIs -+ */ -+#ifdef CONFIG_DMA_SHARED_BUFFER -+#include -+#endif /* CONFIG_DMA_SHARED_BUFFER */ -+#ifdef CONFIG_UMP -+#include -+#endif /* CONFIG_UMP */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* This function finds out which RB tree the given GPU VA region belongs to -+ * based on the region zone */ -+static struct rb_root *kbase_reg_flags_to_rbtree(struct kbase_context *kctx, -+ struct kbase_va_region *reg) -+{ -+ struct rb_root *rbtree = NULL; -+ -+ switch (reg->flags & KBASE_REG_ZONE_MASK) { -+ case KBASE_REG_ZONE_CUSTOM_VA: -+ rbtree = &kctx->reg_rbtree_custom; -+ break; -+ case KBASE_REG_ZONE_EXEC: -+ rbtree = &kctx->reg_rbtree_exec; -+ break; -+ case KBASE_REG_ZONE_SAME_VA: -+ rbtree = &kctx->reg_rbtree_same; -+ /* fall through */ -+ default: -+ rbtree = &kctx->reg_rbtree_same; -+ break; -+ } -+ -+ return rbtree; -+} -+ -+/* This function finds out which RB tree the given pfn from the GPU VA belongs -+ * to based on the memory zone the pfn refers to */ -+static struct rb_root *kbase_gpu_va_to_rbtree(struct kbase_context *kctx, -+ u64 gpu_pfn) -+{ -+ struct rb_root *rbtree = NULL; -+ -+#ifdef CONFIG_64BIT -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+#endif /* CONFIG_64BIT */ -+ if (gpu_pfn >= KBASE_REG_ZONE_CUSTOM_VA_BASE) -+ rbtree = &kctx->reg_rbtree_custom; -+ else if (gpu_pfn >= KBASE_REG_ZONE_EXEC_BASE) -+ rbtree = &kctx->reg_rbtree_exec; -+ else -+ rbtree = &kctx->reg_rbtree_same; -+#ifdef CONFIG_64BIT -+ } else { -+ if (gpu_pfn >= kctx->same_va_end) -+ rbtree = &kctx->reg_rbtree_custom; -+ else -+ rbtree = &kctx->reg_rbtree_same; -+ } -+#endif /* CONFIG_64BIT */ -+ -+ return rbtree; -+} -+ -+/* This function inserts a region into the tree. */ -+static void kbase_region_tracker_insert(struct kbase_context *kctx, -+ struct kbase_va_region *new_reg) -+{ -+ u64 start_pfn = new_reg->start_pfn; -+ struct rb_node **link = NULL; -+ struct rb_node *parent = NULL; -+ struct rb_root *rbtree = NULL; -+ -+ rbtree = kbase_reg_flags_to_rbtree(kctx, new_reg); -+ -+ link = &(rbtree->rb_node); -+ /* Find the right place in the tree using tree search */ -+ while (*link) { -+ struct kbase_va_region *old_reg; -+ -+ parent = *link; -+ old_reg = rb_entry(parent, struct kbase_va_region, rblink); -+ -+ /* RBTree requires no duplicate entries. */ -+ KBASE_DEBUG_ASSERT(old_reg->start_pfn != start_pfn); -+ -+ if (old_reg->start_pfn > start_pfn) -+ link = &(*link)->rb_left; -+ else -+ link = &(*link)->rb_right; -+ } -+ -+ /* Put the new node there, and rebalance tree */ -+ rb_link_node(&(new_reg->rblink), parent, link); -+ -+ rb_insert_color(&(new_reg->rblink), rbtree); -+} -+ -+/* Find allocated region enclosing free range. */ -+static struct kbase_va_region *kbase_region_tracker_find_region_enclosing_range_free( -+ struct kbase_context *kctx, u64 start_pfn, size_t nr_pages) -+{ -+ struct rb_node *rbnode = NULL; -+ struct kbase_va_region *reg = NULL; -+ struct rb_root *rbtree = NULL; -+ -+ u64 end_pfn = start_pfn + nr_pages; -+ -+ rbtree = kbase_gpu_va_to_rbtree(kctx, start_pfn); -+ -+ rbnode = rbtree->rb_node; -+ -+ while (rbnode) { -+ u64 tmp_start_pfn, tmp_end_pfn; -+ -+ reg = rb_entry(rbnode, struct kbase_va_region, rblink); -+ tmp_start_pfn = reg->start_pfn; -+ tmp_end_pfn = reg->start_pfn + reg->nr_pages; -+ -+ /* If start is lower than this, go left. */ -+ if (start_pfn < tmp_start_pfn) -+ rbnode = rbnode->rb_left; -+ /* If end is higher than this, then go right. */ -+ else if (end_pfn > tmp_end_pfn) -+ rbnode = rbnode->rb_right; -+ else /* Enclosing */ -+ return reg; -+ } -+ -+ return NULL; -+} -+ -+/* Find region enclosing given address. */ -+struct kbase_va_region *kbase_region_tracker_find_region_enclosing_address(struct kbase_context *kctx, u64 gpu_addr) -+{ -+ struct rb_node *rbnode; -+ struct kbase_va_region *reg; -+ u64 gpu_pfn = gpu_addr >> PAGE_SHIFT; -+ struct rb_root *rbtree = NULL; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ rbtree = kbase_gpu_va_to_rbtree(kctx, gpu_pfn); -+ -+ rbnode = rbtree->rb_node; -+ -+ while (rbnode) { -+ u64 tmp_start_pfn, tmp_end_pfn; -+ -+ reg = rb_entry(rbnode, struct kbase_va_region, rblink); -+ tmp_start_pfn = reg->start_pfn; -+ tmp_end_pfn = reg->start_pfn + reg->nr_pages; -+ -+ /* If start is lower than this, go left. */ -+ if (gpu_pfn < tmp_start_pfn) -+ rbnode = rbnode->rb_left; -+ /* If end is higher than this, then go right. */ -+ else if (gpu_pfn >= tmp_end_pfn) -+ rbnode = rbnode->rb_right; -+ else /* Enclosing */ -+ return reg; -+ } -+ -+ return NULL; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_region_tracker_find_region_enclosing_address); -+ -+/* Find region with given base address */ -+struct kbase_va_region *kbase_region_tracker_find_region_base_address(struct kbase_context *kctx, u64 gpu_addr) -+{ -+ u64 gpu_pfn = gpu_addr >> PAGE_SHIFT; -+ struct rb_node *rbnode = NULL; -+ struct kbase_va_region *reg = NULL; -+ struct rb_root *rbtree = NULL; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ rbtree = kbase_gpu_va_to_rbtree(kctx, gpu_pfn); -+ -+ rbnode = rbtree->rb_node; -+ -+ while (rbnode) { -+ reg = rb_entry(rbnode, struct kbase_va_region, rblink); -+ if (reg->start_pfn > gpu_pfn) -+ rbnode = rbnode->rb_left; -+ else if (reg->start_pfn < gpu_pfn) -+ rbnode = rbnode->rb_right; -+ else -+ return reg; -+ -+ } -+ -+ return NULL; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_region_tracker_find_region_base_address); -+ -+/* Find region meeting given requirements */ -+static struct kbase_va_region *kbase_region_tracker_find_region_meeting_reqs(struct kbase_context *kctx, struct kbase_va_region *reg_reqs, size_t nr_pages, size_t align) -+{ -+ struct rb_node *rbnode = NULL; -+ struct kbase_va_region *reg = NULL; -+ struct rb_root *rbtree = NULL; -+ -+ /* Note that this search is a linear search, as we do not have a target -+ address in mind, so does not benefit from the rbtree search */ -+ -+ rbtree = kbase_reg_flags_to_rbtree(kctx, reg_reqs); -+ -+ rbnode = rb_first(rbtree); -+ -+ while (rbnode) { -+ reg = rb_entry(rbnode, struct kbase_va_region, rblink); -+ if ((reg->nr_pages >= nr_pages) && -+ (reg->flags & KBASE_REG_FREE)) { -+ /* Check alignment */ -+ u64 start_pfn = (reg->start_pfn + align - 1) & ~(align - 1); -+ -+ if ((start_pfn >= reg->start_pfn) && -+ (start_pfn <= (reg->start_pfn + reg->nr_pages - 1)) && -+ ((start_pfn + nr_pages - 1) <= (reg->start_pfn + reg->nr_pages - 1))) -+ return reg; -+ } -+ rbnode = rb_next(rbnode); -+ } -+ -+ return NULL; -+} -+ -+/** -+ * @brief Remove a region object from the global list. -+ * -+ * The region reg is removed, possibly by merging with other free and -+ * compatible adjacent regions. It must be called with the context -+ * region lock held. The associated memory is not released (see -+ * kbase_free_alloced_region). Internal use only. -+ */ -+static int kbase_remove_va_region(struct kbase_context *kctx, struct kbase_va_region *reg) -+{ -+ struct rb_node *rbprev; -+ struct kbase_va_region *prev = NULL; -+ struct rb_node *rbnext; -+ struct kbase_va_region *next = NULL; -+ struct rb_root *reg_rbtree = NULL; -+ -+ int merged_front = 0; -+ int merged_back = 0; -+ int err = 0; -+ -+ reg_rbtree = kbase_reg_flags_to_rbtree(kctx, reg); -+ -+ /* Try to merge with the previous block first */ -+ rbprev = rb_prev(&(reg->rblink)); -+ if (rbprev) { -+ prev = rb_entry(rbprev, struct kbase_va_region, rblink); -+ if (prev->flags & KBASE_REG_FREE) { -+ /* We're compatible with the previous VMA, -+ * merge with it */ -+ WARN_ON((prev->flags & KBASE_REG_ZONE_MASK) != -+ (reg->flags & KBASE_REG_ZONE_MASK)); -+ prev->nr_pages += reg->nr_pages; -+ rb_erase(&(reg->rblink), reg_rbtree); -+ reg = prev; -+ merged_front = 1; -+ } -+ } -+ -+ /* Try to merge with the next block second */ -+ /* Note we do the lookup here as the tree may have been rebalanced. */ -+ rbnext = rb_next(&(reg->rblink)); -+ if (rbnext) { -+ /* We're compatible with the next VMA, merge with it */ -+ next = rb_entry(rbnext, struct kbase_va_region, rblink); -+ if (next->flags & KBASE_REG_FREE) { -+ WARN_ON((next->flags & KBASE_REG_ZONE_MASK) != -+ (reg->flags & KBASE_REG_ZONE_MASK)); -+ next->start_pfn = reg->start_pfn; -+ next->nr_pages += reg->nr_pages; -+ rb_erase(&(reg->rblink), reg_rbtree); -+ merged_back = 1; -+ if (merged_front) { -+ /* We already merged with prev, free it */ -+ kbase_free_alloced_region(reg); -+ } -+ } -+ } -+ -+ /* If we failed to merge then we need to add a new block */ -+ if (!(merged_front || merged_back)) { -+ /* -+ * We didn't merge anything. Add a new free -+ * placeholder and remove the original one. -+ */ -+ struct kbase_va_region *free_reg; -+ -+ free_reg = kbase_alloc_free_region(kctx, reg->start_pfn, reg->nr_pages, reg->flags & KBASE_REG_ZONE_MASK); -+ if (!free_reg) { -+ err = -ENOMEM; -+ goto out; -+ } -+ rb_replace_node(&(reg->rblink), &(free_reg->rblink), reg_rbtree); -+ } -+ -+ out: -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_remove_va_region); -+ -+/** -+ * @brief Insert a VA region to the list, replacing the current at_reg. -+ */ -+static int kbase_insert_va_region_nolock(struct kbase_context *kctx, struct kbase_va_region *new_reg, struct kbase_va_region *at_reg, u64 start_pfn, size_t nr_pages) -+{ -+ struct rb_root *reg_rbtree = NULL; -+ int err = 0; -+ -+ reg_rbtree = kbase_reg_flags_to_rbtree(kctx, at_reg); -+ -+ /* Must be a free region */ -+ KBASE_DEBUG_ASSERT((at_reg->flags & KBASE_REG_FREE) != 0); -+ /* start_pfn should be contained within at_reg */ -+ KBASE_DEBUG_ASSERT((start_pfn >= at_reg->start_pfn) && (start_pfn < at_reg->start_pfn + at_reg->nr_pages)); -+ /* at least nr_pages from start_pfn should be contained within at_reg */ -+ KBASE_DEBUG_ASSERT(start_pfn + nr_pages <= at_reg->start_pfn + at_reg->nr_pages); -+ -+ new_reg->start_pfn = start_pfn; -+ new_reg->nr_pages = nr_pages; -+ -+ /* Regions are a whole use, so swap and delete old one. */ -+ if (at_reg->start_pfn == start_pfn && at_reg->nr_pages == nr_pages) { -+ rb_replace_node(&(at_reg->rblink), &(new_reg->rblink), -+ reg_rbtree); -+ kbase_free_alloced_region(at_reg); -+ } -+ /* New region replaces the start of the old one, so insert before. */ -+ else if (at_reg->start_pfn == start_pfn) { -+ at_reg->start_pfn += nr_pages; -+ KBASE_DEBUG_ASSERT(at_reg->nr_pages >= nr_pages); -+ at_reg->nr_pages -= nr_pages; -+ -+ kbase_region_tracker_insert(kctx, new_reg); -+ } -+ /* New region replaces the end of the old one, so insert after. */ -+ else if ((at_reg->start_pfn + at_reg->nr_pages) == (start_pfn + nr_pages)) { -+ at_reg->nr_pages -= nr_pages; -+ -+ kbase_region_tracker_insert(kctx, new_reg); -+ } -+ /* New region splits the old one, so insert and create new */ -+ else { -+ struct kbase_va_region *new_front_reg; -+ -+ new_front_reg = kbase_alloc_free_region(kctx, -+ at_reg->start_pfn, -+ start_pfn - at_reg->start_pfn, -+ at_reg->flags & KBASE_REG_ZONE_MASK); -+ -+ if (new_front_reg) { -+ at_reg->nr_pages -= nr_pages + new_front_reg->nr_pages; -+ at_reg->start_pfn = start_pfn + nr_pages; -+ -+ kbase_region_tracker_insert(kctx, new_front_reg); -+ kbase_region_tracker_insert(kctx, new_reg); -+ } else { -+ err = -ENOMEM; -+ } -+ } -+ -+ return err; -+} -+ -+/** -+ * @brief Add a VA region to the list. -+ */ -+int kbase_add_va_region(struct kbase_context *kctx, -+ struct kbase_va_region *reg, u64 addr, -+ size_t nr_pages, size_t align) -+{ -+ struct kbase_va_region *tmp; -+ u64 gpu_pfn = addr >> PAGE_SHIFT; -+ int err = 0; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(NULL != reg); -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ if (!align) -+ align = 1; -+ -+ /* must be a power of 2 */ -+ KBASE_DEBUG_ASSERT((align & (align - 1)) == 0); -+ KBASE_DEBUG_ASSERT(nr_pages > 0); -+ -+ /* Path 1: Map a specific address. Find the enclosing region, which *must* be free. */ -+ if (gpu_pfn) { -+ struct device *dev = kctx->kbdev->dev; -+ -+ KBASE_DEBUG_ASSERT(!(gpu_pfn & (align - 1))); -+ -+ tmp = kbase_region_tracker_find_region_enclosing_range_free(kctx, gpu_pfn, nr_pages); -+ if (!tmp) { -+ dev_warn(dev, "Enclosing region not found: 0x%08llx gpu_pfn, %zu nr_pages", gpu_pfn, nr_pages); -+ err = -ENOMEM; -+ goto exit; -+ } -+ if (!(tmp->flags & KBASE_REG_FREE)) { -+ dev_warn(dev, "Zone mismatch: %lu != %lu", tmp->flags & KBASE_REG_ZONE_MASK, reg->flags & KBASE_REG_ZONE_MASK); -+ dev_warn(dev, "!(tmp->flags & KBASE_REG_FREE): tmp->start_pfn=0x%llx tmp->flags=0x%lx tmp->nr_pages=0x%zx gpu_pfn=0x%llx nr_pages=0x%zx\n", tmp->start_pfn, tmp->flags, tmp->nr_pages, gpu_pfn, nr_pages); -+ dev_warn(dev, "in function %s (%p, %p, 0x%llx, 0x%zx, 0x%zx)\n", __func__, kctx, reg, addr, nr_pages, align); -+ err = -ENOMEM; -+ goto exit; -+ } -+ -+ err = kbase_insert_va_region_nolock(kctx, reg, tmp, gpu_pfn, nr_pages); -+ if (err) { -+ dev_warn(dev, "Failed to insert va region"); -+ err = -ENOMEM; -+ goto exit; -+ } -+ -+ goto exit; -+ } -+ -+ /* Path 2: Map any free address which meets the requirements. */ -+ { -+ u64 start_pfn; -+ -+ /* -+ * Depending on the zone the allocation request is for -+ * we might need to retry it. -+ */ -+ do { -+ tmp = kbase_region_tracker_find_region_meeting_reqs( -+ kctx, reg, nr_pages, align); -+ if (tmp) { -+ start_pfn = (tmp->start_pfn + align - 1) & -+ ~(align - 1); -+ err = kbase_insert_va_region_nolock(kctx, reg, -+ tmp, start_pfn, nr_pages); -+ break; -+ } -+ -+ /* -+ * If the allocation is not from the same zone as JIT -+ * then don't retry, we're out of VA and there is -+ * nothing which can be done about it. -+ */ -+ if ((reg->flags & KBASE_REG_ZONE_MASK) != -+ KBASE_REG_ZONE_CUSTOM_VA) -+ break; -+ } while (kbase_jit_evict(kctx)); -+ -+ if (!tmp) -+ err = -ENOMEM; -+ } -+ -+ exit: -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_add_va_region); -+ -+/** -+ * @brief Initialize the internal region tracker data structure. -+ */ -+static void kbase_region_tracker_ds_init(struct kbase_context *kctx, -+ struct kbase_va_region *same_va_reg, -+ struct kbase_va_region *exec_reg, -+ struct kbase_va_region *custom_va_reg) -+{ -+ kctx->reg_rbtree_same = RB_ROOT; -+ kbase_region_tracker_insert(kctx, same_va_reg); -+ -+ /* Although exec and custom_va_reg don't always exist, -+ * initialize unconditionally because of the mem_view debugfs -+ * implementation which relies on these being empty */ -+ kctx->reg_rbtree_exec = RB_ROOT; -+ kctx->reg_rbtree_custom = RB_ROOT; -+ -+ if (exec_reg) -+ kbase_region_tracker_insert(kctx, exec_reg); -+ if (custom_va_reg) -+ kbase_region_tracker_insert(kctx, custom_va_reg); -+} -+ -+static void kbase_region_tracker_erase_rbtree(struct rb_root *rbtree) -+{ -+ struct rb_node *rbnode; -+ struct kbase_va_region *reg; -+ -+ do { -+ rbnode = rb_first(rbtree); -+ if (rbnode) { -+ rb_erase(rbnode, rbtree); -+ reg = rb_entry(rbnode, struct kbase_va_region, rblink); -+ kbase_free_alloced_region(reg); -+ } -+ } while (rbnode); -+} -+ -+void kbase_region_tracker_term(struct kbase_context *kctx) -+{ -+ kbase_region_tracker_erase_rbtree(&kctx->reg_rbtree_same); -+ kbase_region_tracker_erase_rbtree(&kctx->reg_rbtree_exec); -+ kbase_region_tracker_erase_rbtree(&kctx->reg_rbtree_custom); -+} -+ -+/** -+ * Initialize the region tracker data structure. -+ */ -+int kbase_region_tracker_init(struct kbase_context *kctx) -+{ -+ struct kbase_va_region *same_va_reg; -+ struct kbase_va_region *exec_reg = NULL; -+ struct kbase_va_region *custom_va_reg = NULL; -+ size_t same_va_bits = sizeof(void *) * BITS_PER_BYTE; -+ u64 custom_va_size = KBASE_REG_ZONE_CUSTOM_VA_SIZE; -+ u64 gpu_va_limit = (1ULL << kctx->kbdev->gpu_props.mmu.va_bits) >> PAGE_SHIFT; -+ u64 same_va_pages; -+ int err; -+ -+ /* Take the lock as kbase_free_alloced_region requires it */ -+ kbase_gpu_vm_lock(kctx); -+ -+#if defined(CONFIG_ARM64) -+ same_va_bits = VA_BITS; -+#elif defined(CONFIG_X86_64) -+ same_va_bits = 47; -+#elif defined(CONFIG_64BIT) -+#error Unsupported 64-bit architecture -+#endif -+ -+#ifdef CONFIG_64BIT -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ same_va_bits = 32; -+ else if (kbase_hw_has_feature(kctx->kbdev, BASE_HW_FEATURE_33BIT_VA)) -+ same_va_bits = 33; -+#endif -+ -+ if (kctx->kbdev->gpu_props.mmu.va_bits < same_va_bits) { -+ err = -EINVAL; -+ goto fail_unlock; -+ } -+ -+ same_va_pages = (1ULL << (same_va_bits - PAGE_SHIFT)) - 1; -+ /* all have SAME_VA */ -+ same_va_reg = kbase_alloc_free_region(kctx, 1, -+ same_va_pages, -+ KBASE_REG_ZONE_SAME_VA); -+ -+ if (!same_va_reg) { -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+#ifdef CONFIG_64BIT -+ /* 32-bit clients have exec and custom VA zones */ -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+#endif -+ if (gpu_va_limit <= KBASE_REG_ZONE_CUSTOM_VA_BASE) { -+ err = -EINVAL; -+ goto fail_free_same_va; -+ } -+ /* If the current size of TMEM is out of range of the -+ * virtual address space addressable by the MMU then -+ * we should shrink it to fit -+ */ -+ if ((KBASE_REG_ZONE_CUSTOM_VA_BASE + KBASE_REG_ZONE_CUSTOM_VA_SIZE) >= gpu_va_limit) -+ custom_va_size = gpu_va_limit - KBASE_REG_ZONE_CUSTOM_VA_BASE; -+ -+ exec_reg = kbase_alloc_free_region(kctx, -+ KBASE_REG_ZONE_EXEC_BASE, -+ KBASE_REG_ZONE_EXEC_SIZE, -+ KBASE_REG_ZONE_EXEC); -+ -+ if (!exec_reg) { -+ err = -ENOMEM; -+ goto fail_free_same_va; -+ } -+ -+ custom_va_reg = kbase_alloc_free_region(kctx, -+ KBASE_REG_ZONE_CUSTOM_VA_BASE, -+ custom_va_size, KBASE_REG_ZONE_CUSTOM_VA); -+ -+ if (!custom_va_reg) { -+ err = -ENOMEM; -+ goto fail_free_exec; -+ } -+#ifdef CONFIG_64BIT -+ } -+#endif -+ -+ kbase_region_tracker_ds_init(kctx, same_va_reg, exec_reg, custom_va_reg); -+ -+ kctx->same_va_end = same_va_pages + 1; -+ -+ kbase_gpu_vm_unlock(kctx); -+ return 0; -+ -+fail_free_exec: -+ kbase_free_alloced_region(exec_reg); -+fail_free_same_va: -+ kbase_free_alloced_region(same_va_reg); -+fail_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ return err; -+} -+ -+int kbase_region_tracker_init_jit(struct kbase_context *kctx, u64 jit_va_pages) -+{ -+#ifdef CONFIG_64BIT -+ struct kbase_va_region *same_va; -+ struct kbase_va_region *custom_va_reg; -+ u64 same_va_bits; -+ u64 total_va_size; -+ int err; -+ -+ /* -+ * Nothing to do for 32-bit clients, JIT uses the existing -+ * custom VA zone. -+ */ -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ return 0; -+ -+#if defined(CONFIG_ARM64) -+ same_va_bits = VA_BITS; -+#elif defined(CONFIG_X86_64) -+ same_va_bits = 47; -+#elif defined(CONFIG_64BIT) -+#error Unsupported 64-bit architecture -+#endif -+ -+ if (kbase_hw_has_feature(kctx->kbdev, BASE_HW_FEATURE_33BIT_VA)) -+ same_va_bits = 33; -+ -+ total_va_size = (1ULL << (same_va_bits - PAGE_SHIFT)) - 1; -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ /* -+ * Modify the same VA free region after creation. Be careful to ensure -+ * that allocations haven't been made as they could cause an overlap -+ * to happen with existing same VA allocations and the custom VA zone. -+ */ -+ same_va = kbase_region_tracker_find_region_base_address(kctx, -+ PAGE_SIZE); -+ if (!same_va) { -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+ /* The region flag or region size has changed since creation so bail. */ -+ if ((!(same_va->flags & KBASE_REG_FREE)) || -+ (same_va->nr_pages != total_va_size)) { -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+ if (same_va->nr_pages < jit_va_pages || -+ kctx->same_va_end < jit_va_pages) { -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+ /* It's safe to adjust the same VA zone now */ -+ same_va->nr_pages -= jit_va_pages; -+ kctx->same_va_end -= jit_va_pages; -+ -+ /* -+ * Create a custom VA zone at the end of the VA for allocations which -+ * JIT can use so it doesn't have to allocate VA from the kernel. -+ */ -+ custom_va_reg = kbase_alloc_free_region(kctx, -+ kctx->same_va_end, -+ jit_va_pages, -+ KBASE_REG_ZONE_CUSTOM_VA); -+ -+ if (!custom_va_reg) { -+ /* -+ * The context will be destroyed if we fail here so no point -+ * reverting the change we made to same_va. -+ */ -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+ kbase_region_tracker_insert(kctx, custom_va_reg); -+ -+ kbase_gpu_vm_unlock(kctx); -+ return 0; -+ -+fail_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ return err; -+#else -+ return 0; -+#endif -+} -+ -+int kbase_mem_init(struct kbase_device *kbdev) -+{ -+ struct kbasep_mem_device *memdev; -+ int ret; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ memdev = &kbdev->memdev; -+ kbdev->mem_pool_max_size_default = KBASE_MEM_POOL_MAX_SIZE_KCTX; -+ -+ /* Initialize memory usage */ -+ atomic_set(&memdev->used_pages, 0); -+ -+ ret = kbase_mem_pool_init(&kbdev->mem_pool, -+ KBASE_MEM_POOL_MAX_SIZE_KBDEV, -+ KBASE_MEM_POOL_4KB_PAGE_TABLE_ORDER, -+ kbdev, -+ NULL); -+ if (ret) -+ return ret; -+ -+ ret = kbase_mem_pool_init(&kbdev->lp_mem_pool, -+ (KBASE_MEM_POOL_MAX_SIZE_KBDEV >> 9), -+ KBASE_MEM_POOL_2MB_PAGE_TABLE_ORDER, -+ kbdev, -+ NULL); -+ if (ret) -+ kbase_mem_pool_term(&kbdev->mem_pool); -+ -+ return ret; -+} -+ -+void kbase_mem_halt(struct kbase_device *kbdev) -+{ -+ CSTD_UNUSED(kbdev); -+} -+ -+void kbase_mem_term(struct kbase_device *kbdev) -+{ -+ struct kbasep_mem_device *memdev; -+ int pages; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ memdev = &kbdev->memdev; -+ -+ pages = atomic_read(&memdev->used_pages); -+ if (pages != 0) -+ dev_warn(kbdev->dev, "%s: %d pages in use!\n", __func__, pages); -+ -+ kbase_mem_pool_term(&kbdev->mem_pool); -+ kbase_mem_pool_term(&kbdev->lp_mem_pool); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mem_term); -+ -+ -+ -+ -+/** -+ * @brief Allocate a free region object. -+ * -+ * The allocated object is not part of any list yet, and is flagged as -+ * KBASE_REG_FREE. No mapping is allocated yet. -+ * -+ * zone is KBASE_REG_ZONE_CUSTOM_VA, KBASE_REG_ZONE_SAME_VA, or KBASE_REG_ZONE_EXEC -+ * -+ */ -+struct kbase_va_region *kbase_alloc_free_region(struct kbase_context *kctx, u64 start_pfn, size_t nr_pages, int zone) -+{ -+ struct kbase_va_region *new_reg; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ /* zone argument should only contain zone related region flags */ -+ KBASE_DEBUG_ASSERT((zone & ~KBASE_REG_ZONE_MASK) == 0); -+ KBASE_DEBUG_ASSERT(nr_pages > 0); -+ /* 64-bit address range is the max */ -+ KBASE_DEBUG_ASSERT(start_pfn + nr_pages <= (U64_MAX / PAGE_SIZE)); -+ -+ new_reg = kzalloc(sizeof(*new_reg), GFP_KERNEL); -+ -+ if (!new_reg) -+ return NULL; -+ -+ new_reg->cpu_alloc = NULL; /* no alloc bound yet */ -+ new_reg->gpu_alloc = NULL; /* no alloc bound yet */ -+ new_reg->kctx = kctx; -+ new_reg->flags = zone | KBASE_REG_FREE; -+ -+ new_reg->flags |= KBASE_REG_GROWABLE; -+ -+ new_reg->start_pfn = start_pfn; -+ new_reg->nr_pages = nr_pages; -+ -+ return new_reg; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_alloc_free_region); -+ -+/** -+ * @brief Free a region object. -+ * -+ * The described region must be freed of any mapping. -+ * -+ * If the region is not flagged as KBASE_REG_FREE, the region's -+ * alloc object will be released. -+ * It is a bug if no alloc object exists for non-free regions. -+ * -+ */ -+void kbase_free_alloced_region(struct kbase_va_region *reg) -+{ -+ if (!(reg->flags & KBASE_REG_FREE)) { -+ /* -+ * The physical allocation should have been removed from the -+ * eviction list before this function is called. However, in the -+ * case of abnormal process termination or the app leaking the -+ * memory kbase_mem_free_region is not called so it can still be -+ * on the list at termination time of the region tracker. -+ */ -+ if (!list_empty(®->gpu_alloc->evict_node)) { -+ /* -+ * Unlink the physical allocation before unmaking it -+ * evictable so that the allocation isn't grown back to -+ * its last backed size as we're going to unmap it -+ * anyway. -+ */ -+ reg->cpu_alloc->reg = NULL; -+ if (reg->cpu_alloc != reg->gpu_alloc) -+ reg->gpu_alloc->reg = NULL; -+ -+ /* -+ * If a region has been made evictable then we must -+ * unmake it before trying to free it. -+ * If the memory hasn't been reclaimed it will be -+ * unmapped and freed below, if it has been reclaimed -+ * then the operations below are no-ops. -+ */ -+ if (reg->flags & KBASE_REG_DONT_NEED) { -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc->type == -+ KBASE_MEM_TYPE_NATIVE); -+ kbase_mem_evictable_unmake(reg->gpu_alloc); -+ } -+ } -+ -+ /* -+ * Remove the region from the sticky resource metadata -+ * list should it be there. -+ */ -+ kbase_sticky_resource_release(reg->kctx, NULL, -+ reg->start_pfn << PAGE_SHIFT); -+ -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+ /* To detect use-after-free in debug builds */ -+ KBASE_DEBUG_CODE(reg->flags |= KBASE_REG_FREE); -+ } -+ kfree(reg); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_free_alloced_region); -+ -+int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, u64 addr, size_t nr_pages, size_t align) -+{ -+ int err; -+ size_t i = 0; -+ unsigned long attr; -+ unsigned long mask = ~KBASE_REG_MEMATTR_MASK; -+ -+ if ((kctx->kbdev->system_coherency == COHERENCY_ACE) && -+ (reg->flags & KBASE_REG_SHARE_BOTH)) -+ attr = KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_OUTER_WA); -+ else -+ attr = KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_WRITE_ALLOC); -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(NULL != reg); -+ -+ err = kbase_add_va_region(kctx, reg, addr, nr_pages, align); -+ if (err) -+ return err; -+ -+ if (reg->gpu_alloc->type == KBASE_MEM_TYPE_ALIAS) { -+ u64 stride; -+ struct kbase_mem_phy_alloc *alloc; -+ -+ alloc = reg->gpu_alloc; -+ stride = alloc->imported.alias.stride; -+ KBASE_DEBUG_ASSERT(alloc->imported.alias.aliased); -+ for (i = 0; i < alloc->imported.alias.nents; i++) { -+ if (alloc->imported.alias.aliased[i].alloc) { -+ err = kbase_mmu_insert_pages(kctx, -+ reg->start_pfn + (i * stride), -+ alloc->imported.alias.aliased[i].alloc->pages + alloc->imported.alias.aliased[i].offset, -+ alloc->imported.alias.aliased[i].length, -+ reg->flags); -+ if (err) -+ goto bad_insert; -+ -+ kbase_mem_phy_alloc_gpu_mapped(alloc->imported.alias.aliased[i].alloc); -+ } else { -+ err = kbase_mmu_insert_single_page(kctx, -+ reg->start_pfn + i * stride, -+ kctx->aliasing_sink_page, -+ alloc->imported.alias.aliased[i].length, -+ (reg->flags & mask) | attr); -+ -+ if (err) -+ goto bad_insert; -+ } -+ } -+ } else { -+ err = kbase_mmu_insert_pages(kctx, reg->start_pfn, -+ kbase_get_gpu_phy_pages(reg), -+ kbase_reg_current_backed_size(reg), -+ reg->flags); -+ if (err) -+ goto bad_insert; -+ kbase_mem_phy_alloc_gpu_mapped(reg->gpu_alloc); -+ } -+ -+ return err; -+ -+bad_insert: -+ if (reg->gpu_alloc->type == KBASE_MEM_TYPE_ALIAS) { -+ u64 stride; -+ -+ stride = reg->gpu_alloc->imported.alias.stride; -+ KBASE_DEBUG_ASSERT(reg->gpu_alloc->imported.alias.aliased); -+ while (i--) -+ if (reg->gpu_alloc->imported.alias.aliased[i].alloc) { -+ kbase_mmu_teardown_pages(kctx, reg->start_pfn + (i * stride), reg->gpu_alloc->imported.alias.aliased[i].length); -+ kbase_mem_phy_alloc_gpu_unmapped(reg->gpu_alloc->imported.alias.aliased[i].alloc); -+ } -+ } -+ -+ kbase_remove_va_region(kctx, reg); -+ -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_gpu_mmap); -+ -+static void kbase_jd_user_buf_unmap(struct kbase_context *kctx, -+ struct kbase_mem_phy_alloc *alloc, bool writeable); -+ -+int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg) -+{ -+ int err; -+ -+ if (reg->start_pfn == 0) -+ return 0; -+ -+ if (reg->gpu_alloc && reg->gpu_alloc->type == KBASE_MEM_TYPE_ALIAS) { -+ size_t i; -+ -+ err = kbase_mmu_teardown_pages(kctx, reg->start_pfn, reg->nr_pages); -+ KBASE_DEBUG_ASSERT(reg->gpu_alloc->imported.alias.aliased); -+ for (i = 0; i < reg->gpu_alloc->imported.alias.nents; i++) -+ if (reg->gpu_alloc->imported.alias.aliased[i].alloc) -+ kbase_mem_phy_alloc_gpu_unmapped(reg->gpu_alloc->imported.alias.aliased[i].alloc); -+ } else { -+ err = kbase_mmu_teardown_pages(kctx, reg->start_pfn, kbase_reg_current_backed_size(reg)); -+ kbase_mem_phy_alloc_gpu_unmapped(reg->gpu_alloc); -+ } -+ -+ if (reg->gpu_alloc && reg->gpu_alloc->type == -+ KBASE_MEM_TYPE_IMPORTED_USER_BUF) { -+ struct kbase_alloc_import_user_buf *user_buf = -+ ®->gpu_alloc->imported.user_buf; -+ -+ if (user_buf->current_mapping_usage_count & PINNED_ON_IMPORT) { -+ user_buf->current_mapping_usage_count &= -+ ~PINNED_ON_IMPORT; -+ -+ kbase_jd_user_buf_unmap(kctx, reg->gpu_alloc, -+ (reg->flags & KBASE_REG_GPU_WR)); -+ } -+ } -+ -+ if (err) -+ return err; -+ -+ err = kbase_remove_va_region(kctx, reg); -+ return err; -+} -+ -+static struct kbase_cpu_mapping *kbasep_find_enclosing_cpu_mapping( -+ struct kbase_context *kctx, -+ unsigned long uaddr, size_t size, u64 *offset) -+{ -+ struct vm_area_struct *vma; -+ struct kbase_cpu_mapping *map; -+ unsigned long vm_pgoff_in_region; -+ unsigned long vm_off_in_region; -+ unsigned long map_start; -+ size_t map_size; -+ -+ lockdep_assert_held(¤t->mm->mmap_sem); -+ -+ if ((uintptr_t) uaddr + size < (uintptr_t) uaddr) /* overflow check */ -+ return NULL; -+ -+ vma = find_vma_intersection(current->mm, uaddr, uaddr+size); -+ -+ if (!vma || vma->vm_start > uaddr) -+ return NULL; -+ if (vma->vm_ops != &kbase_vm_ops) -+ /* Not ours! */ -+ return NULL; -+ -+ map = vma->vm_private_data; -+ -+ if (map->kctx != kctx) -+ /* Not from this context! */ -+ return NULL; -+ -+ vm_pgoff_in_region = vma->vm_pgoff - map->region->start_pfn; -+ vm_off_in_region = vm_pgoff_in_region << PAGE_SHIFT; -+ map_start = vma->vm_start - vm_off_in_region; -+ map_size = map->region->nr_pages << PAGE_SHIFT; -+ -+ if ((uaddr + size) > (map_start + map_size)) -+ /* Not within the CPU mapping */ -+ return NULL; -+ -+ *offset = (uaddr - vma->vm_start) + vm_off_in_region; -+ -+ return map; -+} -+ -+int kbasep_find_enclosing_cpu_mapping_offset( -+ struct kbase_context *kctx, -+ unsigned long uaddr, size_t size, u64 *offset) -+{ -+ struct kbase_cpu_mapping *map; -+ -+ kbase_os_mem_map_lock(kctx); -+ -+ map = kbasep_find_enclosing_cpu_mapping(kctx, uaddr, size, offset); -+ -+ kbase_os_mem_map_unlock(kctx); -+ -+ if (!map) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+KBASE_EXPORT_TEST_API(kbasep_find_enclosing_cpu_mapping_offset); -+ -+void kbase_sync_single(struct kbase_context *kctx, -+ struct tagged_addr t_cpu_pa, struct tagged_addr t_gpu_pa, -+ off_t offset, size_t size, enum kbase_sync_type sync_fn) -+{ -+ struct page *cpu_page; -+ phys_addr_t cpu_pa = as_phys_addr_t(t_cpu_pa); -+ phys_addr_t gpu_pa = as_phys_addr_t(t_gpu_pa); -+ -+ cpu_page = pfn_to_page(PFN_DOWN(cpu_pa)); -+ -+ if (likely(cpu_pa == gpu_pa)) { -+ dma_addr_t dma_addr; -+ -+ BUG_ON(!cpu_page); -+ BUG_ON(offset + size > PAGE_SIZE); -+ -+ dma_addr = kbase_dma_addr(cpu_page) + offset; -+ if (sync_fn == KBASE_SYNC_TO_CPU) -+ dma_sync_single_for_cpu(kctx->kbdev->dev, dma_addr, -+ size, DMA_BIDIRECTIONAL); -+ else if (sync_fn == KBASE_SYNC_TO_DEVICE) -+ dma_sync_single_for_device(kctx->kbdev->dev, dma_addr, -+ size, DMA_BIDIRECTIONAL); -+ } else { -+ void *src = NULL; -+ void *dst = NULL; -+ struct page *gpu_page; -+ -+ if (WARN(!gpu_pa, "No GPU PA found for infinite cache op")) -+ return; -+ -+ gpu_page = pfn_to_page(PFN_DOWN(gpu_pa)); -+ -+ if (sync_fn == KBASE_SYNC_TO_DEVICE) { -+ src = ((unsigned char *)kmap(cpu_page)) + offset; -+ dst = ((unsigned char *)kmap(gpu_page)) + offset; -+ } else if (sync_fn == KBASE_SYNC_TO_CPU) { -+ dma_sync_single_for_cpu(kctx->kbdev->dev, -+ kbase_dma_addr(gpu_page) + offset, -+ size, DMA_BIDIRECTIONAL); -+ src = ((unsigned char *)kmap(gpu_page)) + offset; -+ dst = ((unsigned char *)kmap(cpu_page)) + offset; -+ } -+ memcpy(dst, src, size); -+ kunmap(gpu_page); -+ kunmap(cpu_page); -+ if (sync_fn == KBASE_SYNC_TO_DEVICE) -+ dma_sync_single_for_device(kctx->kbdev->dev, -+ kbase_dma_addr(gpu_page) + offset, -+ size, DMA_BIDIRECTIONAL); -+ } -+} -+ -+static int kbase_do_syncset(struct kbase_context *kctx, -+ struct basep_syncset *sset, enum kbase_sync_type sync_fn) -+{ -+ int err = 0; -+ struct kbase_va_region *reg; -+ struct kbase_cpu_mapping *map; -+ unsigned long start; -+ size_t size; -+ struct tagged_addr *cpu_pa; -+ struct tagged_addr *gpu_pa; -+ u64 page_off, page_count; -+ u64 i; -+ u64 offset; -+ -+ kbase_os_mem_map_lock(kctx); -+ kbase_gpu_vm_lock(kctx); -+ -+ /* find the region where the virtual address is contained */ -+ reg = kbase_region_tracker_find_region_enclosing_address(kctx, -+ sset->mem_handle.basep.handle); -+ if (!reg) { -+ dev_warn(kctx->kbdev->dev, "Can't find region at VA 0x%016llX", -+ sset->mem_handle.basep.handle); -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ -+ if (!(reg->flags & KBASE_REG_CPU_CACHED) || -+ kbase_mem_is_imported(reg->gpu_alloc->type)) -+ goto out_unlock; -+ -+ start = (uintptr_t)sset->user_addr; -+ size = (size_t)sset->size; -+ -+ map = kbasep_find_enclosing_cpu_mapping(kctx, start, size, &offset); -+ if (!map) { -+ dev_warn(kctx->kbdev->dev, "Can't find CPU mapping 0x%016lX for VA 0x%016llX", -+ start, sset->mem_handle.basep.handle); -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ -+ page_off = offset >> PAGE_SHIFT; -+ offset &= ~PAGE_MASK; -+ page_count = (size + offset + (PAGE_SIZE - 1)) >> PAGE_SHIFT; -+ cpu_pa = kbase_get_cpu_phy_pages(reg); -+ gpu_pa = kbase_get_gpu_phy_pages(reg); -+ -+ if (page_off > reg->nr_pages || -+ page_off + page_count > reg->nr_pages) { -+ /* Sync overflows the region */ -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ -+ /* Sync first page */ -+ if (as_phys_addr_t(cpu_pa[page_off])) { -+ size_t sz = MIN(((size_t) PAGE_SIZE - offset), size); -+ -+ kbase_sync_single(kctx, cpu_pa[page_off], gpu_pa[page_off], -+ offset, sz, sync_fn); -+ } -+ -+ /* Sync middle pages (if any) */ -+ for (i = 1; page_count > 2 && i < page_count - 1; i++) { -+ /* we grow upwards, so bail on first non-present page */ -+ if (!as_phys_addr_t(cpu_pa[page_off + i])) -+ break; -+ -+ kbase_sync_single(kctx, cpu_pa[page_off + i], -+ gpu_pa[page_off + i], 0, PAGE_SIZE, sync_fn); -+ } -+ -+ /* Sync last page (if any) */ -+ if (page_count > 1 && -+ as_phys_addr_t(cpu_pa[page_off + page_count - 1])) { -+ size_t sz = ((start + size - 1) & ~PAGE_MASK) + 1; -+ -+ kbase_sync_single(kctx, cpu_pa[page_off + page_count - 1], -+ gpu_pa[page_off + page_count - 1], 0, sz, -+ sync_fn); -+ } -+ -+out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ kbase_os_mem_map_unlock(kctx); -+ return err; -+} -+ -+int kbase_sync_now(struct kbase_context *kctx, struct basep_syncset *sset) -+{ -+ int err = -EINVAL; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(sset != NULL); -+ -+ if (sset->mem_handle.basep.handle & ~PAGE_MASK) { -+ dev_warn(kctx->kbdev->dev, -+ "mem_handle: passed parameter is invalid"); -+ return -EINVAL; -+ } -+ -+ switch (sset->type) { -+ case BASE_SYNCSET_OP_MSYNC: -+ err = kbase_do_syncset(kctx, sset, KBASE_SYNC_TO_DEVICE); -+ break; -+ -+ case BASE_SYNCSET_OP_CSYNC: -+ err = kbase_do_syncset(kctx, sset, KBASE_SYNC_TO_CPU); -+ break; -+ -+ default: -+ dev_warn(kctx->kbdev->dev, "Unknown msync op %d\n", sset->type); -+ break; -+ } -+ -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_sync_now); -+ -+/* vm lock must be held */ -+int kbase_mem_free_region(struct kbase_context *kctx, struct kbase_va_region *reg) -+{ -+ int err; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(NULL != reg); -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* -+ * Unlink the physical allocation before unmaking it evictable so -+ * that the allocation isn't grown back to its last backed size -+ * as we're going to unmap it anyway. -+ */ -+ reg->cpu_alloc->reg = NULL; -+ if (reg->cpu_alloc != reg->gpu_alloc) -+ reg->gpu_alloc->reg = NULL; -+ -+ /* -+ * If a region has been made evictable then we must unmake it -+ * before trying to free it. -+ * If the memory hasn't been reclaimed it will be unmapped and freed -+ * below, if it has been reclaimed then the operations below are no-ops. -+ */ -+ if (reg->flags & KBASE_REG_DONT_NEED) { -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc->type == -+ KBASE_MEM_TYPE_NATIVE); -+ kbase_mem_evictable_unmake(reg->gpu_alloc); -+ } -+ -+ err = kbase_gpu_munmap(kctx, reg); -+ if (err) { -+ dev_warn(reg->kctx->kbdev->dev, "Could not unmap from the GPU...\n"); -+ goto out; -+ } -+ -+ /* This will also free the physical pages */ -+ kbase_free_alloced_region(reg); -+ -+ out: -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mem_free_region); -+ -+/** -+ * @brief Free the region from the GPU and unregister it. -+ * -+ * This function implements the free operation on a memory segment. -+ * It will loudly fail if called with outstanding mappings. -+ */ -+int kbase_mem_free(struct kbase_context *kctx, u64 gpu_addr) -+{ -+ int err = 0; -+ struct kbase_va_region *reg; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ -+ if ((gpu_addr & ~PAGE_MASK) && (gpu_addr >= PAGE_SIZE)) { -+ dev_warn(kctx->kbdev->dev, "kbase_mem_free: gpu_addr parameter is invalid"); -+ return -EINVAL; -+ } -+ -+ if (0 == gpu_addr) { -+ dev_warn(kctx->kbdev->dev, "gpu_addr 0 is reserved for the ringbuffer and it's an error to try to free it using kbase_mem_free\n"); -+ return -EINVAL; -+ } -+ kbase_gpu_vm_lock(kctx); -+ -+ if (gpu_addr >= BASE_MEM_COOKIE_BASE && -+ gpu_addr < BASE_MEM_FIRST_FREE_ADDRESS) { -+ int cookie = PFN_DOWN(gpu_addr - BASE_MEM_COOKIE_BASE); -+ -+ reg = kctx->pending_regions[cookie]; -+ if (!reg) { -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ -+ /* ask to unlink the cookie as we'll free it */ -+ -+ kctx->pending_regions[cookie] = NULL; -+ kctx->cookies |= (1UL << cookie); -+ -+ kbase_free_alloced_region(reg); -+ } else { -+ /* A real GPU va */ -+ /* Validate the region */ -+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr); -+ if (!reg || (reg->flags & KBASE_REG_FREE)) { -+ dev_warn(kctx->kbdev->dev, "kbase_mem_free called with nonexistent gpu_addr 0x%llX", -+ gpu_addr); -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ -+ if ((reg->flags & KBASE_REG_ZONE_MASK) == KBASE_REG_ZONE_SAME_VA) { -+ /* SAME_VA must be freed through munmap */ -+ dev_warn(kctx->kbdev->dev, "%s called on SAME_VA memory 0x%llX", __func__, -+ gpu_addr); -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ err = kbase_mem_free_region(kctx, reg); -+ } -+ -+ out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mem_free); -+ -+int kbase_update_region_flags(struct kbase_context *kctx, -+ struct kbase_va_region *reg, unsigned long flags) -+{ -+ KBASE_DEBUG_ASSERT(NULL != reg); -+ KBASE_DEBUG_ASSERT((flags & ~((1ul << BASE_MEM_FLAGS_NR_BITS) - 1)) == 0); -+ -+ reg->flags |= kbase_cache_enabled(flags, reg->nr_pages); -+ /* all memory is now growable */ -+ reg->flags |= KBASE_REG_GROWABLE; -+ -+ if (flags & BASE_MEM_GROW_ON_GPF) -+ reg->flags |= KBASE_REG_PF_GROW; -+ -+ if (flags & BASE_MEM_PROT_CPU_WR) -+ reg->flags |= KBASE_REG_CPU_WR; -+ -+ if (flags & BASE_MEM_PROT_CPU_RD) -+ reg->flags |= KBASE_REG_CPU_RD; -+ -+ if (flags & BASE_MEM_PROT_GPU_WR) -+ reg->flags |= KBASE_REG_GPU_WR; -+ -+ if (flags & BASE_MEM_PROT_GPU_RD) -+ reg->flags |= KBASE_REG_GPU_RD; -+ -+ if (0 == (flags & BASE_MEM_PROT_GPU_EX)) -+ reg->flags |= KBASE_REG_GPU_NX; -+ -+ if (!kbase_device_is_cpu_coherent(kctx->kbdev)) { -+ if (flags & BASE_MEM_COHERENT_SYSTEM_REQUIRED) -+ return -EINVAL; -+ } else if (flags & (BASE_MEM_COHERENT_SYSTEM | -+ BASE_MEM_COHERENT_SYSTEM_REQUIRED)) { -+ reg->flags |= KBASE_REG_SHARE_BOTH; -+ } -+ -+ if (!(reg->flags & KBASE_REG_SHARE_BOTH) && -+ flags & BASE_MEM_COHERENT_LOCAL) { -+ reg->flags |= KBASE_REG_SHARE_IN; -+ } -+ -+ /* Set up default MEMATTR usage */ -+ if (kctx->kbdev->system_coherency == COHERENCY_ACE && -+ (reg->flags & KBASE_REG_SHARE_BOTH)) { -+ reg->flags |= -+ KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_DEFAULT_ACE); -+ } else { -+ reg->flags |= -+ KBASE_REG_MEMATTR_INDEX(AS_MEMATTR_INDEX_DEFAULT); -+ } -+ -+ return 0; -+} -+ -+int kbase_alloc_phy_pages_helper( -+ struct kbase_mem_phy_alloc *alloc, -+ size_t nr_pages_requested) -+{ -+ int new_page_count __maybe_unused; -+ size_t old_page_count = alloc->nents; -+ size_t nr_left = nr_pages_requested; -+ int res; -+ struct kbase_context *kctx; -+ struct tagged_addr *tp; -+ -+ KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_NATIVE); -+ KBASE_DEBUG_ASSERT(alloc->imported.kctx); -+ -+ kctx = alloc->imported.kctx; -+ -+ if (nr_pages_requested == 0) -+ goto done; /*nothing to do*/ -+ -+ new_page_count = kbase_atomic_add_pages( -+ nr_pages_requested, &kctx->used_pages); -+ kbase_atomic_add_pages(nr_pages_requested, -+ &kctx->kbdev->memdev.used_pages); -+ -+ /* Increase mm counters before we allocate pages so that this -+ * allocation is visible to the OOM killer */ -+ kbase_process_page_usage_inc(kctx, nr_pages_requested); -+ -+ tp = alloc->pages + old_page_count; -+ -+#ifdef CONFIG_MALI_2MB_ALLOC -+ /* Check if we have enough pages requested so we can allocate a large -+ * page (512 * 4KB = 2MB ) -+ */ -+ if (nr_left >= (SZ_2M / SZ_4K)) { -+ int nr_lp = nr_left / (SZ_2M / SZ_4K); -+ -+ res = kbase_mem_pool_alloc_pages(&kctx->lp_mem_pool, -+ nr_lp * (SZ_2M / SZ_4K), -+ tp, -+ true); -+ -+ if (res > 0) { -+ nr_left -= res; -+ tp += res; -+ } -+ -+ if (nr_left) { -+ struct kbase_sub_alloc *sa, *temp_sa; -+ -+ mutex_lock(&kctx->mem_partials_lock); -+ -+ list_for_each_entry_safe(sa, temp_sa, -+ &kctx->mem_partials, link) { -+ int pidx = 0; -+ -+ while (nr_left) { -+ pidx = find_next_zero_bit(sa->sub_pages, -+ SZ_2M / SZ_4K, -+ pidx); -+ bitmap_set(sa->sub_pages, pidx, 1); -+ *tp++ = as_tagged_tag(page_to_phys(sa->page + -+ pidx), -+ FROM_PARTIAL); -+ nr_left--; -+ -+ if (bitmap_full(sa->sub_pages, SZ_2M / SZ_4K)) { -+ /* unlink from partial list when full */ -+ list_del_init(&sa->link); -+ break; -+ } -+ } -+ } -+ mutex_unlock(&kctx->mem_partials_lock); -+ } -+ -+ /* only if we actually have a chunk left <512. If more it indicates -+ * that we couldn't allocate a 2MB above, so no point to retry here. -+ */ -+ if (nr_left > 0 && nr_left < (SZ_2M / SZ_4K)) { -+ /* create a new partial and suballocate the rest from it */ -+ struct page *np = NULL; -+ -+ do { -+ int err = kbase_mem_pool_grow(&kctx->lp_mem_pool, 1); -+ -+ if (err) -+ break; -+ np = kbase_mem_pool_alloc(&kctx->lp_mem_pool); -+ } while (!np); -+ -+ if (np) { -+ int i; -+ struct kbase_sub_alloc *sa; -+ struct page *p; -+ -+ sa = kmalloc(sizeof(*sa), GFP_KERNEL); -+ if (!sa) { -+ kbase_mem_pool_free(&kctx->lp_mem_pool, np, false); -+ goto no_new_partial; -+ } -+ -+ /* store pointers back to the control struct */ -+ np->lru.next = (void *)sa; -+ for (p = np; p < np + SZ_2M / SZ_4K; p++) -+ p->lru.prev = (void *)np; -+ INIT_LIST_HEAD(&sa->link); -+ bitmap_zero(sa->sub_pages, SZ_2M / SZ_4K); -+ sa->page = np; -+ -+ for (i = 0; i < nr_left; i++) -+ *tp++ = as_tagged_tag(page_to_phys(np + i), FROM_PARTIAL); -+ -+ bitmap_set(sa->sub_pages, 0, nr_left); -+ nr_left = 0; -+ -+ /* expose for later use */ -+ mutex_lock(&kctx->mem_partials_lock); -+ list_add(&sa->link, &kctx->mem_partials); -+ mutex_unlock(&kctx->mem_partials_lock); -+ } -+ } -+ } -+no_new_partial: -+#endif -+ -+ if (nr_left) { -+ res = kbase_mem_pool_alloc_pages(&kctx->mem_pool, -+ nr_left, -+ tp, -+ false); -+ if (res <= 0) -+ goto alloc_failed; -+ } -+ -+ /* -+ * Request a zone cache update, this scans only the new pages an -+ * appends their information to the zone cache. if the update -+ * fails then clear the cache so we fall-back to doing things -+ * page by page. -+ */ -+ if (kbase_zone_cache_update(alloc, old_page_count) != 0) -+ kbase_zone_cache_clear(alloc); -+ -+ KBASE_TLSTREAM_AUX_PAGESALLOC( -+ (u32)kctx->id, -+ (u64)new_page_count); -+ -+ alloc->nents += nr_pages_requested; -+done: -+ return 0; -+ -+alloc_failed: -+ /* rollback needed if got one or more 2MB but failed later */ -+ if (nr_left != nr_pages_requested) -+ kbase_mem_pool_free_pages(&kctx->lp_mem_pool, -+ nr_pages_requested - nr_left, -+ alloc->pages + old_page_count, -+ false, -+ false); -+ -+ kbase_process_page_usage_dec(kctx, nr_pages_requested); -+ kbase_atomic_sub_pages(nr_pages_requested, &kctx->used_pages); -+ kbase_atomic_sub_pages(nr_pages_requested, -+ &kctx->kbdev->memdev.used_pages); -+ -+ return -ENOMEM; -+} -+ -+static void free_partial(struct kbase_context *kctx, struct tagged_addr tp) -+{ -+ struct page *p, *head_page; -+ struct kbase_sub_alloc *sa; -+ -+ p = phys_to_page(as_phys_addr_t(tp)); -+ head_page = (struct page *)p->lru.prev; -+ sa = (struct kbase_sub_alloc *)head_page->lru.next; -+ mutex_lock(&kctx->mem_partials_lock); -+ clear_bit(p - head_page, sa->sub_pages); -+ if (bitmap_empty(sa->sub_pages, SZ_2M / SZ_4K)) { -+ list_del(&sa->link); -+ kbase_mem_pool_free(&kctx->lp_mem_pool, head_page, true); -+ kfree(sa); -+ } else if (bitmap_weight(sa->sub_pages, SZ_2M / SZ_4K) == -+ SZ_2M / SZ_4K - 1) { -+ /* expose the partial again */ -+ list_add(&sa->link, &kctx->mem_partials); -+ } -+ mutex_unlock(&kctx->mem_partials_lock); -+} -+ -+int kbase_free_phy_pages_helper( -+ struct kbase_mem_phy_alloc *alloc, -+ size_t nr_pages_to_free) -+{ -+ struct kbase_context *kctx = alloc->imported.kctx; -+ bool syncback; -+ bool reclaimed = (alloc->evicted != 0); -+ struct tagged_addr *start_free; -+ int new_page_count __maybe_unused; -+ size_t freed = 0; -+ -+ KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_NATIVE); -+ KBASE_DEBUG_ASSERT(alloc->imported.kctx); -+ KBASE_DEBUG_ASSERT(alloc->nents >= nr_pages_to_free); -+ -+ /* early out if nothing to do */ -+ if (0 == nr_pages_to_free) -+ return 0; -+ -+ start_free = alloc->pages + alloc->nents - nr_pages_to_free; -+ -+ syncback = alloc->properties & KBASE_MEM_PHY_ALLOC_ACCESSED_CACHED; -+ -+ /* pad start_free to a valid start location */ -+ while (nr_pages_to_free && is_huge(*start_free) && -+ !is_huge_head(*start_free)) { -+ nr_pages_to_free--; -+ start_free++; -+ } -+ -+ /* -+ * Clear the zone cache, we don't expect JIT allocations to be -+ * shrunk in parts so there is no point trying to optimize for that -+ * by scanning for the changes caused by freeing this memory and -+ * updating the existing cache entries. -+ */ -+ kbase_zone_cache_clear(alloc); -+ -+ -+ while (nr_pages_to_free) { -+ if (is_huge_head(*start_free)) { -+ /* This is a 2MB entry, so free all the 512 pages that -+ * it points to -+ */ -+ kbase_mem_pool_free_pages(&kctx->lp_mem_pool, -+ 512, -+ start_free, -+ syncback, -+ reclaimed); -+ nr_pages_to_free -= 512; -+ start_free += 512; -+ freed += 512; -+ } else if (is_partial(*start_free)) { -+ free_partial(kctx, *start_free); -+ nr_pages_to_free--; -+ start_free++; -+ freed++; -+ } else { -+ struct tagged_addr *local_end_free; -+ -+ local_end_free = start_free; -+ while (nr_pages_to_free && -+ !is_huge(*local_end_free) && -+ !is_partial(*local_end_free)) { -+ local_end_free++; -+ nr_pages_to_free--; -+ } -+ kbase_mem_pool_free_pages(&kctx->mem_pool, -+ local_end_free - start_free, -+ start_free, -+ syncback, -+ reclaimed); -+ freed += local_end_free - start_free; -+ start_free += local_end_free - start_free; -+ } -+ } -+ -+ alloc->nents -= freed; -+ -+ /* -+ * If the allocation was not evicted (i.e. evicted == 0) then -+ * the page accounting needs to be done. -+ */ -+ if (!reclaimed) { -+ kbase_process_page_usage_dec(kctx, freed); -+ new_page_count = kbase_atomic_sub_pages(freed, -+ &kctx->used_pages); -+ kbase_atomic_sub_pages(freed, -+ &kctx->kbdev->memdev.used_pages); -+ -+ KBASE_TLSTREAM_AUX_PAGESALLOC( -+ (u32)kctx->id, -+ (u64)new_page_count); -+ } -+ -+ return 0; -+} -+ -+void kbase_mem_kref_free(struct kref *kref) -+{ -+ struct kbase_mem_phy_alloc *alloc; -+ -+ alloc = container_of(kref, struct kbase_mem_phy_alloc, kref); -+ -+ switch (alloc->type) { -+ case KBASE_MEM_TYPE_NATIVE: { -+ WARN_ON(!alloc->imported.kctx); -+ /* -+ * The physical allocation must have been removed from the -+ * eviction list before trying to free it. -+ */ -+ WARN_ON(!list_empty(&alloc->evict_node)); -+ kbase_free_phy_pages_helper(alloc, alloc->nents); -+ break; -+ } -+ case KBASE_MEM_TYPE_ALIAS: { -+ /* just call put on the underlying phy allocs */ -+ size_t i; -+ struct kbase_aliased *aliased; -+ -+ aliased = alloc->imported.alias.aliased; -+ if (aliased) { -+ for (i = 0; i < alloc->imported.alias.nents; i++) -+ if (aliased[i].alloc) -+ kbase_mem_phy_alloc_put(aliased[i].alloc); -+ vfree(aliased); -+ } -+ break; -+ } -+ case KBASE_MEM_TYPE_RAW: -+ /* raw pages, external cleanup */ -+ break; -+ #ifdef CONFIG_UMP -+ case KBASE_MEM_TYPE_IMPORTED_UMP: -+ ump_dd_release(alloc->imported.ump_handle); -+ break; -+#endif -+#ifdef CONFIG_DMA_SHARED_BUFFER -+ case KBASE_MEM_TYPE_IMPORTED_UMM: -+ dma_buf_detach(alloc->imported.umm.dma_buf, -+ alloc->imported.umm.dma_attachment); -+ dma_buf_put(alloc->imported.umm.dma_buf); -+ break; -+#endif -+ case KBASE_MEM_TYPE_IMPORTED_USER_BUF: -+ if (alloc->imported.user_buf.mm) -+ mmdrop(alloc->imported.user_buf.mm); -+ kfree(alloc->imported.user_buf.pages); -+ break; -+ case KBASE_MEM_TYPE_TB:{ -+ void *tb; -+ -+ tb = alloc->imported.kctx->jctx.tb; -+ kbase_device_trace_buffer_uninstall(alloc->imported.kctx); -+ vfree(tb); -+ break; -+ } -+ default: -+ WARN(1, "Unexecpted free of type %d\n", alloc->type); -+ break; -+ } -+ -+ /* Free based on allocation type */ -+ if (alloc->properties & KBASE_MEM_PHY_ALLOC_LARGE) -+ vfree(alloc); -+ else -+ kfree(alloc); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mem_kref_free); -+ -+int kbase_alloc_phy_pages(struct kbase_va_region *reg, size_t vsize, size_t size) -+{ -+ KBASE_DEBUG_ASSERT(NULL != reg); -+ KBASE_DEBUG_ASSERT(vsize > 0); -+ -+ /* validate user provided arguments */ -+ if (size > vsize || vsize > reg->nr_pages) -+ goto out_term; -+ -+ /* Prevent vsize*sizeof from wrapping around. -+ * For instance, if vsize is 2**29+1, we'll allocate 1 byte and the alloc won't fail. -+ */ -+ if ((size_t) vsize > ((size_t) -1 / sizeof(*reg->cpu_alloc->pages))) -+ goto out_term; -+ -+ KBASE_DEBUG_ASSERT(0 != vsize); -+ -+ if (kbase_alloc_phy_pages_helper(reg->cpu_alloc, size) != 0) -+ goto out_term; -+ -+ reg->cpu_alloc->reg = reg; -+ if (reg->cpu_alloc != reg->gpu_alloc) { -+ if (kbase_alloc_phy_pages_helper(reg->gpu_alloc, size) != 0) -+ goto out_rollback; -+ reg->gpu_alloc->reg = reg; -+ } -+ -+ return 0; -+ -+out_rollback: -+ kbase_free_phy_pages_helper(reg->cpu_alloc, size); -+out_term: -+ return -1; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_alloc_phy_pages); -+ -+bool kbase_check_alloc_flags(unsigned long flags) -+{ -+ /* Only known input flags should be set. */ -+ if (flags & ~BASE_MEM_FLAGS_INPUT_MASK) -+ return false; -+ -+ /* At least one flag should be set */ -+ if (flags == 0) -+ return false; -+ -+ /* Either the GPU or CPU must be reading from the allocated memory */ -+ if ((flags & (BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_GPU_RD)) == 0) -+ return false; -+ -+ /* Either the GPU or CPU must be writing to the allocated memory */ -+ if ((flags & (BASE_MEM_PROT_CPU_WR | BASE_MEM_PROT_GPU_WR)) == 0) -+ return false; -+ -+ /* GPU cannot be writing to GPU executable memory and cannot grow the memory on page fault. */ -+ if ((flags & BASE_MEM_PROT_GPU_EX) && (flags & (BASE_MEM_PROT_GPU_WR | BASE_MEM_GROW_ON_GPF))) -+ return false; -+ -+ /* GPU should have at least read or write access otherwise there is no -+ reason for allocating. */ -+ if ((flags & (BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR)) == 0) -+ return false; -+ -+ /* BASE_MEM_IMPORT_SHARED is only valid for imported memory */ -+ if ((flags & BASE_MEM_IMPORT_SHARED) == BASE_MEM_IMPORT_SHARED) -+ return false; -+ -+ return true; -+} -+ -+bool kbase_check_import_flags(unsigned long flags) -+{ -+ /* Only known input flags should be set. */ -+ if (flags & ~BASE_MEM_FLAGS_INPUT_MASK) -+ return false; -+ -+ /* At least one flag should be set */ -+ if (flags == 0) -+ return false; -+ -+ /* Imported memory cannot be GPU executable */ -+ if (flags & BASE_MEM_PROT_GPU_EX) -+ return false; -+ -+ /* Imported memory cannot grow on page fault */ -+ if (flags & BASE_MEM_GROW_ON_GPF) -+ return false; -+ -+ /* GPU should have at least read or write access otherwise there is no -+ reason for importing. */ -+ if ((flags & (BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR)) == 0) -+ return false; -+ -+ /* Secure memory cannot be read by the CPU */ -+ if ((flags & BASE_MEM_SECURE) && (flags & BASE_MEM_PROT_CPU_RD)) -+ return false; -+ -+ return true; -+} -+ -+/** -+ * @brief Acquire the per-context region list lock -+ */ -+void kbase_gpu_vm_lock(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ mutex_lock(&kctx->reg_lock); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_gpu_vm_lock); -+ -+/** -+ * @brief Release the per-context region list lock -+ */ -+void kbase_gpu_vm_unlock(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ mutex_unlock(&kctx->reg_lock); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_gpu_vm_unlock); -+ -+#ifdef CONFIG_DEBUG_FS -+struct kbase_jit_debugfs_data { -+ int (*func)(struct kbase_jit_debugfs_data *); -+ struct mutex lock; -+ struct kbase_context *kctx; -+ u64 active_value; -+ u64 pool_value; -+ u64 destroy_value; -+ char buffer[50]; -+}; -+ -+static int kbase_jit_debugfs_common_open(struct inode *inode, -+ struct file *file, int (*func)(struct kbase_jit_debugfs_data *)) -+{ -+ struct kbase_jit_debugfs_data *data; -+ -+ data = kzalloc(sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ data->func = func; -+ mutex_init(&data->lock); -+ data->kctx = (struct kbase_context *) inode->i_private; -+ -+ file->private_data = data; -+ -+ return nonseekable_open(inode, file); -+} -+ -+static ssize_t kbase_jit_debugfs_common_read(struct file *file, -+ char __user *buf, size_t len, loff_t *ppos) -+{ -+ struct kbase_jit_debugfs_data *data; -+ size_t size; -+ int ret; -+ -+ data = (struct kbase_jit_debugfs_data *) file->private_data; -+ mutex_lock(&data->lock); -+ -+ if (*ppos) { -+ size = strnlen(data->buffer, sizeof(data->buffer)); -+ } else { -+ if (!data->func) { -+ ret = -EACCES; -+ goto out_unlock; -+ } -+ -+ if (data->func(data)) { -+ ret = -EACCES; -+ goto out_unlock; -+ } -+ -+ size = scnprintf(data->buffer, sizeof(data->buffer), -+ "%llu,%llu,%llu", data->active_value, -+ data->pool_value, data->destroy_value); -+ } -+ -+ ret = simple_read_from_buffer(buf, len, ppos, data->buffer, size); -+ -+out_unlock: -+ mutex_unlock(&data->lock); -+ return ret; -+} -+ -+static int kbase_jit_debugfs_common_release(struct inode *inode, -+ struct file *file) -+{ -+ kfree(file->private_data); -+ return 0; -+} -+ -+#define KBASE_JIT_DEBUGFS_DECLARE(__fops, __func) \ -+static int __fops ## _open(struct inode *inode, struct file *file) \ -+{ \ -+ return kbase_jit_debugfs_common_open(inode, file, __func); \ -+} \ -+static const struct file_operations __fops = { \ -+ .owner = THIS_MODULE, \ -+ .open = __fops ## _open, \ -+ .release = kbase_jit_debugfs_common_release, \ -+ .read = kbase_jit_debugfs_common_read, \ -+ .write = NULL, \ -+ .llseek = generic_file_llseek, \ -+} -+ -+static int kbase_jit_debugfs_count_get(struct kbase_jit_debugfs_data *data) -+{ -+ struct kbase_context *kctx = data->kctx; -+ struct list_head *tmp; -+ -+ mutex_lock(&kctx->jit_evict_lock); -+ list_for_each(tmp, &kctx->jit_active_head) { -+ data->active_value++; -+ } -+ -+ list_for_each(tmp, &kctx->jit_pool_head) { -+ data->pool_value++; -+ } -+ -+ list_for_each(tmp, &kctx->jit_destroy_head) { -+ data->destroy_value++; -+ } -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ return 0; -+} -+KBASE_JIT_DEBUGFS_DECLARE(kbase_jit_debugfs_count_fops, -+ kbase_jit_debugfs_count_get); -+ -+static int kbase_jit_debugfs_vm_get(struct kbase_jit_debugfs_data *data) -+{ -+ struct kbase_context *kctx = data->kctx; -+ struct kbase_va_region *reg; -+ -+ mutex_lock(&kctx->jit_evict_lock); -+ list_for_each_entry(reg, &kctx->jit_active_head, jit_node) { -+ data->active_value += reg->nr_pages; -+ } -+ -+ list_for_each_entry(reg, &kctx->jit_pool_head, jit_node) { -+ data->pool_value += reg->nr_pages; -+ } -+ -+ list_for_each_entry(reg, &kctx->jit_destroy_head, jit_node) { -+ data->destroy_value += reg->nr_pages; -+ } -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ return 0; -+} -+KBASE_JIT_DEBUGFS_DECLARE(kbase_jit_debugfs_vm_fops, -+ kbase_jit_debugfs_vm_get); -+ -+static int kbase_jit_debugfs_phys_get(struct kbase_jit_debugfs_data *data) -+{ -+ struct kbase_context *kctx = data->kctx; -+ struct kbase_va_region *reg; -+ -+ mutex_lock(&kctx->jit_evict_lock); -+ list_for_each_entry(reg, &kctx->jit_active_head, jit_node) { -+ data->active_value += reg->gpu_alloc->nents; -+ } -+ -+ list_for_each_entry(reg, &kctx->jit_pool_head, jit_node) { -+ data->pool_value += reg->gpu_alloc->nents; -+ } -+ -+ list_for_each_entry(reg, &kctx->jit_destroy_head, jit_node) { -+ data->destroy_value += reg->gpu_alloc->nents; -+ } -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ return 0; -+} -+KBASE_JIT_DEBUGFS_DECLARE(kbase_jit_debugfs_phys_fops, -+ kbase_jit_debugfs_phys_get); -+ -+void kbase_jit_debugfs_init(struct kbase_context *kctx) -+{ -+ /* Debugfs entry for getting the number of JIT allocations. */ -+ debugfs_create_file("mem_jit_count", S_IRUGO, kctx->kctx_dentry, -+ kctx, &kbase_jit_debugfs_count_fops); -+ -+ /* -+ * Debugfs entry for getting the total number of virtual pages -+ * used by JIT allocations. -+ */ -+ debugfs_create_file("mem_jit_vm", S_IRUGO, kctx->kctx_dentry, -+ kctx, &kbase_jit_debugfs_vm_fops); -+ -+ /* -+ * Debugfs entry for getting the number of physical pages used -+ * by JIT allocations. -+ */ -+ debugfs_create_file("mem_jit_phys", S_IRUGO, kctx->kctx_dentry, -+ kctx, &kbase_jit_debugfs_phys_fops); -+} -+#endif /* CONFIG_DEBUG_FS */ -+ -+/** -+ * kbase_jit_destroy_worker - Deferred worker which frees JIT allocations -+ * @work: Work item -+ * -+ * This function does the work of freeing JIT allocations whose physical -+ * backing has been released. -+ */ -+static void kbase_jit_destroy_worker(struct work_struct *work) -+{ -+ struct kbase_context *kctx; -+ struct kbase_va_region *reg; -+ -+ kctx = container_of(work, struct kbase_context, jit_work); -+ do { -+ mutex_lock(&kctx->jit_evict_lock); -+ if (list_empty(&kctx->jit_destroy_head)) { -+ mutex_unlock(&kctx->jit_evict_lock); -+ break; -+ } -+ -+ reg = list_first_entry(&kctx->jit_destroy_head, -+ struct kbase_va_region, jit_node); -+ -+ list_del(®->jit_node); -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ kbase_gpu_vm_lock(kctx); -+ kbase_mem_free_region(kctx, reg); -+ kbase_gpu_vm_unlock(kctx); -+ } while (1); -+} -+ -+int kbase_jit_init(struct kbase_context *kctx) -+{ -+ INIT_LIST_HEAD(&kctx->jit_active_head); -+ INIT_LIST_HEAD(&kctx->jit_pool_head); -+ INIT_LIST_HEAD(&kctx->jit_destroy_head); -+ INIT_WORK(&kctx->jit_work, kbase_jit_destroy_worker); -+ -+ INIT_LIST_HEAD(&kctx->jit_pending_alloc); -+ INIT_LIST_HEAD(&kctx->jit_atoms_head); -+ -+ return 0; -+} -+ -+struct kbase_va_region *kbase_jit_allocate(struct kbase_context *kctx, -+ struct base_jit_alloc_info *info) -+{ -+ struct kbase_va_region *reg = NULL; -+ struct kbase_va_region *walker; -+ struct kbase_va_region *temp; -+ size_t current_diff = SIZE_MAX; -+ -+ int ret; -+ -+ mutex_lock(&kctx->jit_evict_lock); -+ /* -+ * Scan the pool for an existing allocation which meets our -+ * requirements and remove it. -+ */ -+ list_for_each_entry_safe(walker, temp, &kctx->jit_pool_head, jit_node) { -+ -+ if (walker->nr_pages >= info->va_pages) { -+ size_t min_size, max_size, diff; -+ -+ /* -+ * The JIT allocations VA requirements have been -+ * meet, it's suitable but other allocations -+ * might be a better fit. -+ */ -+ min_size = min_t(size_t, walker->gpu_alloc->nents, -+ info->commit_pages); -+ max_size = max_t(size_t, walker->gpu_alloc->nents, -+ info->commit_pages); -+ diff = max_size - min_size; -+ -+ if (current_diff > diff) { -+ current_diff = diff; -+ reg = walker; -+ } -+ -+ /* The allocation is an exact match, stop looking */ -+ if (current_diff == 0) -+ break; -+ } -+ } -+ -+ if (reg) { -+ /* -+ * Remove the found region from the pool and add it to the -+ * active list. -+ */ -+ list_move(®->jit_node, &kctx->jit_active_head); -+ -+ /* -+ * Remove the allocation from the eviction list as it's no -+ * longer eligible for eviction. This must be done before -+ * dropping the jit_evict_lock -+ */ -+ list_del_init(®->gpu_alloc->evict_node); -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ /* Make the physical backing no longer reclaimable */ -+ if (!kbase_mem_evictable_unmake(reg->gpu_alloc)) -+ goto update_failed; -+ -+ /* Grow the backing if required */ -+ if (reg->gpu_alloc->nents < info->commit_pages) { -+ size_t delta; -+ size_t old_size = reg->gpu_alloc->nents; -+ -+ /* Allocate some more pages */ -+ delta = info->commit_pages - reg->gpu_alloc->nents; -+ if (kbase_alloc_phy_pages_helper(reg->gpu_alloc, delta) -+ != 0) -+ goto update_failed; -+ -+ if (reg->cpu_alloc != reg->gpu_alloc) { -+ if (kbase_alloc_phy_pages_helper( -+ reg->cpu_alloc, delta) != 0) { -+ kbase_free_phy_pages_helper( -+ reg->gpu_alloc, delta); -+ goto update_failed; -+ } -+ } -+ -+ ret = kbase_mem_grow_gpu_mapping(kctx, reg, -+ info->commit_pages, old_size); -+ /* -+ * The grow failed so put the allocation back in the -+ * pool and return failure. -+ */ -+ if (ret) -+ goto update_failed; -+ } -+ kbase_gpu_vm_unlock(kctx); -+ } else { -+ /* No suitable JIT allocation was found so create a new one */ -+ u64 flags = BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_GPU_RD | -+ BASE_MEM_PROT_GPU_WR | BASE_MEM_GROW_ON_GPF | -+ BASE_MEM_COHERENT_LOCAL; -+ u64 gpu_addr; -+ -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ reg = kbase_mem_alloc(kctx, info->va_pages, info->commit_pages, -+ info->extent, &flags, &gpu_addr); -+ if (!reg) -+ goto out_unlocked; -+ -+ mutex_lock(&kctx->jit_evict_lock); -+ list_add(®->jit_node, &kctx->jit_active_head); -+ mutex_unlock(&kctx->jit_evict_lock); -+ } -+ -+ return reg; -+ -+update_failed: -+ /* -+ * An update to an allocation from the pool failed, chances -+ * are slim a new allocation would fair any better so return -+ * the allocation to the pool and return the function with failure. -+ */ -+ kbase_gpu_vm_unlock(kctx); -+ mutex_lock(&kctx->jit_evict_lock); -+ list_move(®->jit_node, &kctx->jit_pool_head); -+ mutex_unlock(&kctx->jit_evict_lock); -+out_unlocked: -+ return NULL; -+} -+ -+void kbase_jit_free(struct kbase_context *kctx, struct kbase_va_region *reg) -+{ -+ /* The physical backing of memory in the pool is always reclaimable */ -+ kbase_gpu_vm_lock(kctx); -+ kbase_mem_evictable_make(reg->gpu_alloc); -+ kbase_gpu_vm_unlock(kctx); -+ -+ mutex_lock(&kctx->jit_evict_lock); -+ list_move(®->jit_node, &kctx->jit_pool_head); -+ mutex_unlock(&kctx->jit_evict_lock); -+} -+ -+void kbase_jit_backing_lost(struct kbase_va_region *reg) -+{ -+ struct kbase_context *kctx = reg->kctx; -+ -+ lockdep_assert_held(&kctx->jit_evict_lock); -+ -+ /* -+ * JIT allocations will always be on a list, if the region -+ * is not on a list then it's not a JIT allocation. -+ */ -+ if (list_empty(®->jit_node)) -+ return; -+ -+ /* -+ * Freeing the allocation requires locks we might not be able -+ * to take now, so move the allocation to the free list and kick -+ * the worker which will do the freeing. -+ */ -+ list_move(®->jit_node, &kctx->jit_destroy_head); -+ -+ schedule_work(&kctx->jit_work); -+} -+ -+bool kbase_jit_evict(struct kbase_context *kctx) -+{ -+ struct kbase_va_region *reg = NULL; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* Free the oldest allocation from the pool */ -+ mutex_lock(&kctx->jit_evict_lock); -+ if (!list_empty(&kctx->jit_pool_head)) { -+ reg = list_entry(kctx->jit_pool_head.prev, -+ struct kbase_va_region, jit_node); -+ list_del(®->jit_node); -+ } -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ if (reg) -+ kbase_mem_free_region(kctx, reg); -+ -+ return (reg != NULL); -+} -+ -+void kbase_jit_term(struct kbase_context *kctx) -+{ -+ struct kbase_va_region *walker; -+ -+ /* Free all allocations for this context */ -+ -+ /* -+ * Flush the freeing of allocations whose backing has been freed -+ * (i.e. everything in jit_destroy_head). -+ */ -+ cancel_work_sync(&kctx->jit_work); -+ -+ kbase_gpu_vm_lock(kctx); -+ mutex_lock(&kctx->jit_evict_lock); -+ /* Free all allocations from the pool */ -+ while (!list_empty(&kctx->jit_pool_head)) { -+ walker = list_first_entry(&kctx->jit_pool_head, -+ struct kbase_va_region, jit_node); -+ list_del(&walker->jit_node); -+ mutex_unlock(&kctx->jit_evict_lock); -+ kbase_mem_free_region(kctx, walker); -+ mutex_lock(&kctx->jit_evict_lock); -+ } -+ -+ /* Free all allocations from active list */ -+ while (!list_empty(&kctx->jit_active_head)) { -+ walker = list_first_entry(&kctx->jit_active_head, -+ struct kbase_va_region, jit_node); -+ list_del(&walker->jit_node); -+ mutex_unlock(&kctx->jit_evict_lock); -+ kbase_mem_free_region(kctx, walker); -+ mutex_lock(&kctx->jit_evict_lock); -+ } -+ mutex_unlock(&kctx->jit_evict_lock); -+ kbase_gpu_vm_unlock(kctx); -+} -+ -+static int kbase_jd_user_buf_map(struct kbase_context *kctx, -+ struct kbase_va_region *reg) -+{ -+ long pinned_pages; -+ struct kbase_mem_phy_alloc *alloc; -+ struct page **pages; -+ struct tagged_addr *pa; -+ long i; -+ int err = -ENOMEM; -+ unsigned long address; -+ struct mm_struct *mm; -+ struct device *dev; -+ unsigned long offset; -+ unsigned long local_size; -+ -+ alloc = reg->gpu_alloc; -+ pa = kbase_get_gpu_phy_pages(reg); -+ address = alloc->imported.user_buf.address; -+ mm = alloc->imported.user_buf.mm; -+ -+ KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_IMPORTED_USER_BUF); -+ -+ pages = alloc->imported.user_buf.pages; -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) -+ pinned_pages = get_user_pages(NULL, mm, -+ address, -+ alloc->imported.user_buf.nr_pages, -+ reg->flags & KBASE_REG_GPU_WR, -+ 0, pages, NULL); -+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) -+ pinned_pages = get_user_pages_remote(NULL, mm, -+ address, -+ alloc->imported.user_buf.nr_pages, -+ reg->flags & KBASE_REG_GPU_WR, -+ 0, pages, NULL); -+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) -+ pinned_pages = get_user_pages_remote(NULL, mm, -+ address, -+ alloc->imported.user_buf.nr_pages, -+ reg->flags & KBASE_REG_GPU_WR ? FOLL_WRITE : 0, -+ pages, NULL); -+#else -+ pinned_pages = get_user_pages_remote(NULL, mm, -+ address, -+ alloc->imported.user_buf.nr_pages, -+ reg->flags & KBASE_REG_GPU_WR ? FOLL_WRITE : 0, -+ pages, NULL, NULL); -+#endif -+ -+ if (pinned_pages <= 0) -+ return pinned_pages; -+ -+ if (pinned_pages != alloc->imported.user_buf.nr_pages) { -+ for (i = 0; i < pinned_pages; i++) -+ put_page(pages[i]); -+ return -ENOMEM; -+ } -+ -+ dev = kctx->kbdev->dev; -+ offset = address & ~PAGE_MASK; -+ local_size = alloc->imported.user_buf.size; -+ -+ for (i = 0; i < pinned_pages; i++) { -+ dma_addr_t dma_addr; -+ unsigned long min; -+ -+ min = MIN(PAGE_SIZE - offset, local_size); -+ dma_addr = dma_map_page(dev, pages[i], -+ offset, min, -+ DMA_BIDIRECTIONAL); -+ if (dma_mapping_error(dev, dma_addr)) -+ goto unwind; -+ -+ alloc->imported.user_buf.dma_addrs[i] = dma_addr; -+ pa[i] = as_tagged(page_to_phys(pages[i])); -+ -+ local_size -= min; -+ offset = 0; -+ } -+ -+ alloc->nents = pinned_pages; -+ -+ err = kbase_mmu_insert_pages(kctx, reg->start_pfn, pa, -+ kbase_reg_current_backed_size(reg), -+ reg->flags); -+ if (err == 0) -+ return 0; -+ -+ alloc->nents = 0; -+ /* fall down */ -+unwind: -+ while (i--) { -+ dma_unmap_page(kctx->kbdev->dev, -+ alloc->imported.user_buf.dma_addrs[i], -+ PAGE_SIZE, DMA_BIDIRECTIONAL); -+ } -+ -+ while (++i < pinned_pages) { -+ put_page(pages[i]); -+ pages[i] = NULL; -+ } -+ -+ return err; -+} -+ -+static void kbase_jd_user_buf_unmap(struct kbase_context *kctx, -+ struct kbase_mem_phy_alloc *alloc, bool writeable) -+{ -+ long i; -+ struct page **pages; -+ unsigned long size = alloc->imported.user_buf.size; -+ -+ KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_IMPORTED_USER_BUF); -+ pages = alloc->imported.user_buf.pages; -+ for (i = 0; i < alloc->imported.user_buf.nr_pages; i++) { -+ unsigned long local_size; -+ dma_addr_t dma_addr = alloc->imported.user_buf.dma_addrs[i]; -+ -+ local_size = MIN(size, PAGE_SIZE - (dma_addr & ~PAGE_MASK)); -+ dma_unmap_page(kctx->kbdev->dev, dma_addr, local_size, -+ DMA_BIDIRECTIONAL); -+ if (writeable) -+ set_page_dirty_lock(pages[i]); -+ put_page(pages[i]); -+ pages[i] = NULL; -+ -+ size -= local_size; -+ } -+ alloc->nents = 0; -+} -+ -+#ifdef CONFIG_DMA_SHARED_BUFFER -+static int kbase_jd_umm_map(struct kbase_context *kctx, -+ struct kbase_va_region *reg) -+{ -+ struct sg_table *sgt; -+ struct scatterlist *s; -+ int i; -+ struct tagged_addr *pa; -+ int err; -+ size_t count = 0; -+ struct kbase_mem_phy_alloc *alloc; -+ -+ alloc = reg->gpu_alloc; -+ -+ KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM); -+ KBASE_DEBUG_ASSERT(NULL == alloc->imported.umm.sgt); -+ sgt = dma_buf_map_attachment(alloc->imported.umm.dma_attachment, -+ DMA_BIDIRECTIONAL); -+ -+ if (IS_ERR_OR_NULL(sgt)) -+ return -EINVAL; -+ -+ /* save for later */ -+ alloc->imported.umm.sgt = sgt; -+ -+ pa = kbase_get_gpu_phy_pages(reg); -+ KBASE_DEBUG_ASSERT(pa); -+ -+ for_each_sg(sgt->sgl, s, sgt->nents, i) { -+ int j; -+ size_t pages = PFN_UP(sg_dma_len(s)); -+ -+ WARN_ONCE(sg_dma_len(s) & (PAGE_SIZE-1), -+ "sg_dma_len(s)=%u is not a multiple of PAGE_SIZE\n", -+ sg_dma_len(s)); -+ -+ WARN_ONCE(sg_dma_address(s) & (PAGE_SIZE-1), -+ "sg_dma_address(s)=%llx is not aligned to PAGE_SIZE\n", -+ (unsigned long long) sg_dma_address(s)); -+ -+ for (j = 0; (j < pages) && (count < reg->nr_pages); j++, -+ count++) -+ *pa++ = as_tagged(sg_dma_address(s) + -+ (j << PAGE_SHIFT)); -+ WARN_ONCE(j < pages, -+ "sg list from dma_buf_map_attachment > dma_buf->size=%zu\n", -+ alloc->imported.umm.dma_buf->size); -+ } -+ -+ if (!(reg->flags & KBASE_REG_IMPORT_PAD) && -+ WARN_ONCE(count < reg->nr_pages, -+ "sg list from dma_buf_map_attachment < dma_buf->size=%zu\n", -+ alloc->imported.umm.dma_buf->size)) { -+ err = -EINVAL; -+ goto err_unmap_attachment; -+ } -+ -+ /* Update nents as we now have pages to map */ -+ alloc->nents = reg->nr_pages; -+ -+ err = kbase_mmu_insert_pages(kctx, reg->start_pfn, -+ kbase_get_gpu_phy_pages(reg), -+ count, -+ reg->flags | KBASE_REG_GPU_WR | KBASE_REG_GPU_RD); -+ if (err) -+ goto err_unmap_attachment; -+ -+ if (reg->flags & KBASE_REG_IMPORT_PAD) { -+ err = kbase_mmu_insert_single_page(kctx, -+ reg->start_pfn + count, -+ kctx->aliasing_sink_page, -+ reg->nr_pages - count, -+ (reg->flags | KBASE_REG_GPU_RD) & -+ ~KBASE_REG_GPU_WR); -+ if (err) -+ goto err_teardown_orig_pages; -+ } -+ -+ return 0; -+ -+err_teardown_orig_pages: -+ kbase_mmu_teardown_pages(kctx, reg->start_pfn, count); -+err_unmap_attachment: -+ dma_buf_unmap_attachment(alloc->imported.umm.dma_attachment, -+ alloc->imported.umm.sgt, DMA_BIDIRECTIONAL); -+ alloc->imported.umm.sgt = NULL; -+ -+ return err; -+} -+ -+static void kbase_jd_umm_unmap(struct kbase_context *kctx, -+ struct kbase_mem_phy_alloc *alloc) -+{ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(alloc); -+ KBASE_DEBUG_ASSERT(alloc->imported.umm.dma_attachment); -+ KBASE_DEBUG_ASSERT(alloc->imported.umm.sgt); -+ dma_buf_unmap_attachment(alloc->imported.umm.dma_attachment, -+ alloc->imported.umm.sgt, DMA_BIDIRECTIONAL); -+ alloc->imported.umm.sgt = NULL; -+ alloc->nents = 0; -+} -+#endif /* CONFIG_DMA_SHARED_BUFFER */ -+ -+#if (defined(CONFIG_KDS) && defined(CONFIG_UMP)) \ -+ || defined(CONFIG_DMA_SHARED_BUFFER_USES_KDS) -+static void add_kds_resource(struct kds_resource *kds_res, -+ struct kds_resource **kds_resources, u32 *kds_res_count, -+ unsigned long *kds_access_bitmap, bool exclusive) -+{ -+ u32 i; -+ -+ for (i = 0; i < *kds_res_count; i++) { -+ /* Duplicate resource, ignore */ -+ if (kds_resources[i] == kds_res) -+ return; -+ } -+ -+ kds_resources[*kds_res_count] = kds_res; -+ if (exclusive) -+ set_bit(*kds_res_count, kds_access_bitmap); -+ (*kds_res_count)++; -+} -+#endif -+ -+struct kbase_mem_phy_alloc *kbase_map_external_resource( -+ struct kbase_context *kctx, struct kbase_va_region *reg, -+ struct mm_struct *locked_mm -+#ifdef CONFIG_KDS -+ , u32 *kds_res_count, struct kds_resource **kds_resources, -+ unsigned long *kds_access_bitmap, bool exclusive -+#endif -+ ) -+{ -+ int err; -+ -+ /* decide what needs to happen for this resource */ -+ switch (reg->gpu_alloc->type) { -+ case KBASE_MEM_TYPE_IMPORTED_USER_BUF: { -+ if (reg->gpu_alloc->imported.user_buf.mm != locked_mm) -+ goto exit; -+ -+ reg->gpu_alloc->imported.user_buf.current_mapping_usage_count++; -+ if (1 == reg->gpu_alloc->imported.user_buf.current_mapping_usage_count) { -+ err = kbase_jd_user_buf_map(kctx, reg); -+ if (err) { -+ reg->gpu_alloc->imported.user_buf.current_mapping_usage_count--; -+ goto exit; -+ } -+ } -+ } -+ break; -+ case KBASE_MEM_TYPE_IMPORTED_UMP: { -+#if defined(CONFIG_KDS) && defined(CONFIG_UMP) -+ if (kds_res_count) { -+ struct kds_resource *kds_res; -+ -+ kds_res = ump_dd_kds_resource_get( -+ reg->gpu_alloc->imported.ump_handle); -+ if (kds_res) -+ add_kds_resource(kds_res, kds_resources, -+ kds_res_count, -+ kds_access_bitmap, exclusive); -+ } -+#endif /*defined(CONFIG_KDS) && defined(CONFIG_UMP) */ -+ break; -+ } -+#ifdef CONFIG_DMA_SHARED_BUFFER -+ case KBASE_MEM_TYPE_IMPORTED_UMM: { -+#ifdef CONFIG_DMA_SHARED_BUFFER_USES_KDS -+ if (kds_res_count) { -+ struct kds_resource *kds_res; -+ -+ kds_res = get_dma_buf_kds_resource( -+ reg->gpu_alloc->imported.umm.dma_buf); -+ if (kds_res) -+ add_kds_resource(kds_res, kds_resources, -+ kds_res_count, -+ kds_access_bitmap, exclusive); -+ } -+#endif -+ reg->gpu_alloc->imported.umm.current_mapping_usage_count++; -+ if (1 == reg->gpu_alloc->imported.umm.current_mapping_usage_count) { -+ err = kbase_jd_umm_map(kctx, reg); -+ if (err) { -+ reg->gpu_alloc->imported.umm.current_mapping_usage_count--; -+ goto exit; -+ } -+ } -+ break; -+ } -+#endif -+ default: -+ goto exit; -+ } -+ -+ return kbase_mem_phy_alloc_get(reg->gpu_alloc); -+exit: -+ return NULL; -+} -+ -+void kbase_unmap_external_resource(struct kbase_context *kctx, -+ struct kbase_va_region *reg, struct kbase_mem_phy_alloc *alloc) -+{ -+ switch (alloc->type) { -+#ifdef CONFIG_DMA_SHARED_BUFFER -+ case KBASE_MEM_TYPE_IMPORTED_UMM: { -+ alloc->imported.umm.current_mapping_usage_count--; -+ -+ if (0 == alloc->imported.umm.current_mapping_usage_count) { -+ if (reg && reg->gpu_alloc == alloc) { -+ int err; -+ -+ err = kbase_mmu_teardown_pages( -+ kctx, -+ reg->start_pfn, -+ alloc->nents); -+ WARN_ON(err); -+ } -+ -+ kbase_jd_umm_unmap(kctx, alloc); -+ } -+ } -+ break; -+#endif /* CONFIG_DMA_SHARED_BUFFER */ -+ case KBASE_MEM_TYPE_IMPORTED_USER_BUF: { -+ alloc->imported.user_buf.current_mapping_usage_count--; -+ -+ if (0 == alloc->imported.user_buf.current_mapping_usage_count) { -+ bool writeable = true; -+ -+ if (reg && reg->gpu_alloc == alloc) -+ kbase_mmu_teardown_pages( -+ kctx, -+ reg->start_pfn, -+ kbase_reg_current_backed_size(reg)); -+ -+ if (reg && ((reg->flags & KBASE_REG_GPU_WR) == 0)) -+ writeable = false; -+ -+ kbase_jd_user_buf_unmap(kctx, alloc, writeable); -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ kbase_mem_phy_alloc_put(alloc); -+} -+ -+struct kbase_ctx_ext_res_meta *kbase_sticky_resource_acquire( -+ struct kbase_context *kctx, u64 gpu_addr) -+{ -+ struct kbase_ctx_ext_res_meta *meta = NULL; -+ struct kbase_ctx_ext_res_meta *walker; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* -+ * Walk the per context external resource metadata list for the -+ * metadata which matches the region which is being acquired. -+ */ -+ list_for_each_entry(walker, &kctx->ext_res_meta_head, ext_res_node) { -+ if (walker->gpu_addr == gpu_addr) { -+ meta = walker; -+ break; -+ } -+ } -+ -+ /* No metadata exists so create one. */ -+ if (!meta) { -+ struct kbase_va_region *reg; -+ -+ /* Find the region */ -+ reg = kbase_region_tracker_find_region_enclosing_address( -+ kctx, gpu_addr); -+ if (NULL == reg || (reg->flags & KBASE_REG_FREE)) -+ goto failed; -+ -+ /* Allocate the metadata object */ -+ meta = kzalloc(sizeof(*meta), GFP_KERNEL); -+ if (!meta) -+ goto failed; -+ -+ /* -+ * Fill in the metadata object and acquire a reference -+ * for the physical resource. -+ */ -+ meta->alloc = kbase_map_external_resource(kctx, reg, NULL -+#ifdef CONFIG_KDS -+ , NULL, NULL, -+ NULL, false -+#endif -+ ); -+ -+ if (!meta->alloc) -+ goto fail_map; -+ -+ meta->gpu_addr = reg->start_pfn << PAGE_SHIFT; -+ -+ list_add(&meta->ext_res_node, &kctx->ext_res_meta_head); -+ } -+ -+ return meta; -+ -+fail_map: -+ kfree(meta); -+failed: -+ return NULL; -+} -+ -+bool kbase_sticky_resource_release(struct kbase_context *kctx, -+ struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr) -+{ -+ struct kbase_ctx_ext_res_meta *walker; -+ struct kbase_va_region *reg; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* Search of the metadata if one isn't provided. */ -+ if (!meta) { -+ /* -+ * Walk the per context external resource metadata list for the -+ * metadata which matches the region which is being released. -+ */ -+ list_for_each_entry(walker, &kctx->ext_res_meta_head, -+ ext_res_node) { -+ if (walker->gpu_addr == gpu_addr) { -+ meta = walker; -+ break; -+ } -+ } -+ } -+ -+ /* No metadata so just return. */ -+ if (!meta) -+ return false; -+ -+ /* Drop the physical memory reference and free the metadata. */ -+ reg = kbase_region_tracker_find_region_enclosing_address( -+ kctx, -+ meta->gpu_addr); -+ -+ kbase_unmap_external_resource(kctx, reg, meta->alloc); -+ list_del(&meta->ext_res_node); -+ kfree(meta); -+ -+ return true; -+} -+ -+int kbase_sticky_resource_init(struct kbase_context *kctx) -+{ -+ INIT_LIST_HEAD(&kctx->ext_res_meta_head); -+ -+ return 0; -+} -+ -+void kbase_sticky_resource_term(struct kbase_context *kctx) -+{ -+ struct kbase_ctx_ext_res_meta *walker; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* -+ * Free any sticky resources which haven't been unmapped. -+ * -+ * Note: -+ * We don't care about refcounts at this point as no future -+ * references to the meta data will be made. -+ * Region termination would find these if we didn't free them -+ * here, but it's more efficient if we do the clean up here. -+ */ -+ while (!list_empty(&kctx->ext_res_meta_head)) { -+ walker = list_first_entry(&kctx->ext_res_meta_head, -+ struct kbase_ctx_ext_res_meta, ext_res_node); -+ -+ kbase_sticky_resource_release(kctx, walker, 0); -+ } -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem.h b/drivers/gpu/arm/midgard/mali_kbase_mem.h -new file mode 100644 -index 0000000..e9a8d5d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem.h -@@ -0,0 +1,1138 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_mem.h -+ * Base kernel memory APIs -+ */ -+ -+#ifndef _KBASE_MEM_H_ -+#define _KBASE_MEM_H_ -+ -+#ifndef _KBASE_H_ -+#error "Don't include this file directly, use mali_kbase.h instead" -+#endif -+ -+#include -+#ifdef CONFIG_KDS -+#include -+#endif /* CONFIG_KDS */ -+#ifdef CONFIG_UMP -+#include -+#endif /* CONFIG_UMP */ -+#include "mali_base_kernel.h" -+#include -+#include "mali_kbase_pm.h" -+#include "mali_kbase_defs.h" -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+#include "mali_kbase_gator.h" -+#endif -+/* Required for kbase_mem_evictable_unmake */ -+#include "mali_kbase_mem_linux.h" -+ -+/* Part of the workaround for uTLB invalid pages is to ensure we grow/shrink tmem by 4 pages at a time */ -+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_8316 (2) /* round to 4 pages */ -+ -+/* Part of the workaround for PRLAM-9630 requires us to grow/shrink memory by 8 pages. -+The MMU reads in 8 page table entries from memory at a time, if we have more than one page fault within the same 8 pages and -+page tables are updated accordingly, the MMU does not re-read the page table entries from memory for the subsequent page table -+updates and generates duplicate page faults as the page table information used by the MMU is not valid. */ -+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_9630 (3) /* round to 8 pages */ -+ -+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2 (0) /* round to 1 page */ -+ -+/* This must always be a power of 2 */ -+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2) -+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_8316 (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_8316) -+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_9630 (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_9630) -+/** -+ * A CPU mapping -+ */ -+struct kbase_cpu_mapping { -+ struct list_head mappings_list; -+ struct kbase_mem_phy_alloc *alloc; -+ struct kbase_context *kctx; -+ struct kbase_va_region *region; -+ int count; -+ int free_on_close; -+}; -+ -+enum kbase_memory_type { -+ KBASE_MEM_TYPE_NATIVE, -+ KBASE_MEM_TYPE_IMPORTED_UMP, -+ KBASE_MEM_TYPE_IMPORTED_UMM, -+ KBASE_MEM_TYPE_IMPORTED_USER_BUF, -+ KBASE_MEM_TYPE_ALIAS, -+ KBASE_MEM_TYPE_TB, -+ KBASE_MEM_TYPE_RAW -+}; -+ -+/* internal structure, mirroring base_mem_aliasing_info, -+ * but with alloc instead of a gpu va (handle) */ -+struct kbase_aliased { -+ struct kbase_mem_phy_alloc *alloc; /* NULL for special, non-NULL for native */ -+ u64 offset; /* in pages */ -+ u64 length; /* in pages */ -+}; -+ -+/** -+ * @brief Physical pages tracking object properties -+ */ -+#define KBASE_MEM_PHY_ALLOC_ACCESSED_CACHED (1ul << 0) -+#define KBASE_MEM_PHY_ALLOC_LARGE (1ul << 1) -+ -+/* physical pages tracking object. -+ * Set up to track N pages. -+ * N not stored here, the creator holds that info. -+ * This object only tracks how many elements are actually valid (present). -+ * Changing of nents or *pages should only happen if the kbase_mem_phy_alloc is not -+ * shared with another region or client. CPU mappings are OK to exist when changing, as -+ * long as the tracked mappings objects are updated as part of the change. -+ */ -+struct kbase_mem_phy_alloc { -+ struct kref kref; /* number of users of this alloc */ -+ atomic_t gpu_mappings; -+ size_t nents; /* 0..N */ -+ struct tagged_addr *pages; /* N elements, only 0..nents are valid */ -+ -+ /* kbase_cpu_mappings */ -+ struct list_head mappings; -+ -+ /* Node used to store this allocation on the eviction list */ -+ struct list_head evict_node; -+ /* Physical backing size when the pages where evicted */ -+ size_t evicted; -+ /* -+ * Back reference to the region structure which created this -+ * allocation, or NULL if it has been freed. -+ */ -+ struct kbase_va_region *reg; -+ -+ /* type of buffer */ -+ enum kbase_memory_type type; -+ -+ unsigned long properties; -+ -+ struct list_head zone_cache; -+ -+ /* member in union valid based on @a type */ -+ union { -+#ifdef CONFIG_UMP -+ ump_dd_handle ump_handle; -+#endif /* CONFIG_UMP */ -+#if defined(CONFIG_DMA_SHARED_BUFFER) -+ struct { -+ struct dma_buf *dma_buf; -+ struct dma_buf_attachment *dma_attachment; -+ unsigned int current_mapping_usage_count; -+ struct sg_table *sgt; -+ } umm; -+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */ -+ struct { -+ u64 stride; -+ size_t nents; -+ struct kbase_aliased *aliased; -+ } alias; -+ /* Used by type = (KBASE_MEM_TYPE_NATIVE, KBASE_MEM_TYPE_TB) */ -+ struct kbase_context *kctx; -+ struct kbase_alloc_import_user_buf { -+ unsigned long address; -+ unsigned long size; -+ unsigned long nr_pages; -+ struct page **pages; -+ /* top bit (1<<31) of current_mapping_usage_count -+ * specifies that this import was pinned on import -+ * See PINNED_ON_IMPORT -+ */ -+ u32 current_mapping_usage_count; -+ struct mm_struct *mm; -+ dma_addr_t *dma_addrs; -+ } user_buf; -+ } imported; -+}; -+ -+/* The top bit of kbase_alloc_import_user_buf::current_mapping_usage_count is -+ * used to signify that a buffer was pinned when it was imported. Since the -+ * reference count is limited by the number of atoms that can be submitted at -+ * once there should be no danger of overflowing into this bit. -+ * Stealing the top bit also has the benefit that -+ * current_mapping_usage_count != 0 if and only if the buffer is mapped. -+ */ -+#define PINNED_ON_IMPORT (1<<31) -+ -+static inline void kbase_mem_phy_alloc_gpu_mapped(struct kbase_mem_phy_alloc *alloc) -+{ -+ KBASE_DEBUG_ASSERT(alloc); -+ /* we only track mappings of NATIVE buffers */ -+ if (alloc->type == KBASE_MEM_TYPE_NATIVE) -+ atomic_inc(&alloc->gpu_mappings); -+} -+ -+static inline void kbase_mem_phy_alloc_gpu_unmapped(struct kbase_mem_phy_alloc *alloc) -+{ -+ KBASE_DEBUG_ASSERT(alloc); -+ /* we only track mappings of NATIVE buffers */ -+ if (alloc->type == KBASE_MEM_TYPE_NATIVE) -+ if (0 > atomic_dec_return(&alloc->gpu_mappings)) { -+ pr_err("Mismatched %s:\n", __func__); -+ dump_stack(); -+ } -+} -+ -+/** -+ * kbase_mem_is_imported - Indicate whether a memory type is imported -+ * -+ * @type: the memory type -+ * -+ * Return: true if the memory type is imported, false otherwise -+ */ -+static inline bool kbase_mem_is_imported(enum kbase_memory_type type) -+{ -+ return (type == KBASE_MEM_TYPE_IMPORTED_UMP) || -+ (type == KBASE_MEM_TYPE_IMPORTED_UMM) || -+ (type == KBASE_MEM_TYPE_IMPORTED_USER_BUF); -+} -+ -+void kbase_mem_kref_free(struct kref *kref); -+ -+int kbase_mem_init(struct kbase_device *kbdev); -+void kbase_mem_halt(struct kbase_device *kbdev); -+void kbase_mem_term(struct kbase_device *kbdev); -+ -+static inline struct kbase_mem_phy_alloc *kbase_mem_phy_alloc_get(struct kbase_mem_phy_alloc *alloc) -+{ -+ kref_get(&alloc->kref); -+ return alloc; -+} -+ -+static inline struct kbase_mem_phy_alloc *kbase_mem_phy_alloc_put(struct kbase_mem_phy_alloc *alloc) -+{ -+ kref_put(&alloc->kref, kbase_mem_kref_free); -+ return NULL; -+} -+ -+/** -+ * A GPU memory region, and attributes for CPU mappings. -+ */ -+struct kbase_va_region { -+ struct rb_node rblink; -+ struct list_head link; -+ -+ struct kbase_context *kctx; /* Backlink to base context */ -+ -+ u64 start_pfn; /* The PFN in GPU space */ -+ size_t nr_pages; -+ -+/* Free region */ -+#define KBASE_REG_FREE (1ul << 0) -+/* CPU write access */ -+#define KBASE_REG_CPU_WR (1ul << 1) -+/* GPU write access */ -+#define KBASE_REG_GPU_WR (1ul << 2) -+/* No eXecute flag */ -+#define KBASE_REG_GPU_NX (1ul << 3) -+/* Is CPU cached? */ -+#define KBASE_REG_CPU_CACHED (1ul << 4) -+/* Is GPU cached? */ -+#define KBASE_REG_GPU_CACHED (1ul << 5) -+ -+#define KBASE_REG_GROWABLE (1ul << 6) -+/* Can grow on pf? */ -+#define KBASE_REG_PF_GROW (1ul << 7) -+ -+/* VA managed by us */ -+#define KBASE_REG_CUSTOM_VA (1ul << 8) -+ -+/* inner shareable coherency */ -+#define KBASE_REG_SHARE_IN (1ul << 9) -+/* inner & outer shareable coherency */ -+#define KBASE_REG_SHARE_BOTH (1ul << 10) -+ -+/* Space for 4 different zones */ -+#define KBASE_REG_ZONE_MASK (3ul << 11) -+#define KBASE_REG_ZONE(x) (((x) & 3) << 11) -+ -+/* GPU read access */ -+#define KBASE_REG_GPU_RD (1ul<<13) -+/* CPU read access */ -+#define KBASE_REG_CPU_RD (1ul<<14) -+ -+/* Index of chosen MEMATTR for this region (0..7) */ -+#define KBASE_REG_MEMATTR_MASK (7ul << 16) -+#define KBASE_REG_MEMATTR_INDEX(x) (((x) & 7) << 16) -+#define KBASE_REG_MEMATTR_VALUE(x) (((x) & KBASE_REG_MEMATTR_MASK) >> 16) -+ -+#define KBASE_REG_SECURE (1ul << 19) -+ -+#define KBASE_REG_DONT_NEED (1ul << 20) -+ -+/* Imported buffer is padded? */ -+#define KBASE_REG_IMPORT_PAD (1ul << 21) -+ -+#define KBASE_REG_ZONE_SAME_VA KBASE_REG_ZONE(0) -+ -+/* only used with 32-bit clients */ -+/* -+ * On a 32bit platform, custom VA should be wired from (4GB + shader region) -+ * to the VA limit of the GPU. Unfortunately, the Linux mmap() interface -+ * limits us to 2^32 pages (2^44 bytes, see mmap64 man page for reference). -+ * So we put the default limit to the maximum possible on Linux and shrink -+ * it down, if required by the GPU, during initialization. -+ */ -+ -+/* -+ * Dedicated 16MB region for shader code: -+ * VA range 0x101000000-0x102000000 -+ */ -+#define KBASE_REG_ZONE_EXEC KBASE_REG_ZONE(1) -+#define KBASE_REG_ZONE_EXEC_BASE (0x101000000ULL >> PAGE_SHIFT) -+#define KBASE_REG_ZONE_EXEC_SIZE ((16ULL * 1024 * 1024) >> PAGE_SHIFT) -+ -+#define KBASE_REG_ZONE_CUSTOM_VA KBASE_REG_ZONE(2) -+#define KBASE_REG_ZONE_CUSTOM_VA_BASE (KBASE_REG_ZONE_EXEC_BASE + KBASE_REG_ZONE_EXEC_SIZE) /* Starting after KBASE_REG_ZONE_EXEC */ -+#define KBASE_REG_ZONE_CUSTOM_VA_SIZE (((1ULL << 44) >> PAGE_SHIFT) - KBASE_REG_ZONE_CUSTOM_VA_BASE) -+/* end 32-bit clients only */ -+ -+ unsigned long flags; -+ -+ size_t extent; /* nr of pages alloc'd on PF */ -+ -+ struct kbase_mem_phy_alloc *cpu_alloc; /* the one alloc object we mmap to the CPU when mapping this region */ -+ struct kbase_mem_phy_alloc *gpu_alloc; /* the one alloc object we mmap to the GPU when mapping this region */ -+ -+ /* non-NULL if this memory object is a kds_resource */ -+ struct kds_resource *kds_res; -+ -+ /* List head used to store the region in the JIT allocation pool */ -+ struct list_head jit_node; -+}; -+ -+/* Common functions */ -+static inline struct tagged_addr *kbase_get_cpu_phy_pages( -+ struct kbase_va_region *reg) -+{ -+ KBASE_DEBUG_ASSERT(reg); -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->gpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc->nents == reg->gpu_alloc->nents); -+ -+ return reg->cpu_alloc->pages; -+} -+ -+static inline struct tagged_addr *kbase_get_gpu_phy_pages( -+ struct kbase_va_region *reg) -+{ -+ KBASE_DEBUG_ASSERT(reg); -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->gpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc->nents == reg->gpu_alloc->nents); -+ -+ return reg->gpu_alloc->pages; -+} -+ -+static inline size_t kbase_reg_current_backed_size(struct kbase_va_region *reg) -+{ -+ KBASE_DEBUG_ASSERT(reg); -+ /* if no alloc object the backed size naturally is 0 */ -+ if (!reg->cpu_alloc) -+ return 0; -+ -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->gpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc->nents == reg->gpu_alloc->nents); -+ -+ return reg->cpu_alloc->nents; -+} -+ -+#define KBASE_MEM_PHY_ALLOC_LARGE_THRESHOLD ((size_t)(4*1024)) /* size above which vmalloc is used over kmalloc */ -+ -+static inline struct kbase_mem_phy_alloc *kbase_alloc_create(size_t nr_pages, enum kbase_memory_type type) -+{ -+ struct kbase_mem_phy_alloc *alloc; -+ size_t alloc_size = sizeof(*alloc) + sizeof(*alloc->pages) * nr_pages; -+ size_t per_page_size = sizeof(*alloc->pages); -+ -+ /* Imported pages may have page private data already in use */ -+ if (type == KBASE_MEM_TYPE_IMPORTED_USER_BUF) { -+ alloc_size += nr_pages * -+ sizeof(*alloc->imported.user_buf.dma_addrs); -+ per_page_size += sizeof(*alloc->imported.user_buf.dma_addrs); -+ } -+ -+ /* -+ * Prevent nr_pages*per_page_size + sizeof(*alloc) from -+ * wrapping around. -+ */ -+ if (nr_pages > ((((size_t) -1) - sizeof(*alloc)) -+ / per_page_size)) -+ return ERR_PTR(-ENOMEM); -+ -+ /* Allocate based on the size to reduce internal fragmentation of vmem */ -+ if (alloc_size > KBASE_MEM_PHY_ALLOC_LARGE_THRESHOLD) -+ alloc = vzalloc(alloc_size); -+ else -+ alloc = kzalloc(alloc_size, GFP_KERNEL); -+ -+ if (!alloc) -+ return ERR_PTR(-ENOMEM); -+ -+ /* Store allocation method */ -+ if (alloc_size > KBASE_MEM_PHY_ALLOC_LARGE_THRESHOLD) -+ alloc->properties |= KBASE_MEM_PHY_ALLOC_LARGE; -+ -+ kref_init(&alloc->kref); -+ atomic_set(&alloc->gpu_mappings, 0); -+ alloc->nents = 0; -+ alloc->pages = (void *)(alloc + 1); -+ INIT_LIST_HEAD(&alloc->mappings); -+ alloc->type = type; -+ INIT_LIST_HEAD(&alloc->zone_cache); -+ -+ if (type == KBASE_MEM_TYPE_IMPORTED_USER_BUF) -+ alloc->imported.user_buf.dma_addrs = -+ (void *) (alloc->pages + nr_pages); -+ -+ return alloc; -+} -+ -+static inline int kbase_reg_prepare_native(struct kbase_va_region *reg, -+ struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(reg); -+ KBASE_DEBUG_ASSERT(!reg->cpu_alloc); -+ KBASE_DEBUG_ASSERT(!reg->gpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->flags & KBASE_REG_FREE); -+ -+ reg->cpu_alloc = kbase_alloc_create(reg->nr_pages, -+ KBASE_MEM_TYPE_NATIVE); -+ if (IS_ERR(reg->cpu_alloc)) -+ return PTR_ERR(reg->cpu_alloc); -+ else if (!reg->cpu_alloc) -+ return -ENOMEM; -+ reg->cpu_alloc->imported.kctx = kctx; -+ INIT_LIST_HEAD(®->cpu_alloc->evict_node); -+ if (kbase_ctx_flag(kctx, KCTX_INFINITE_CACHE) -+ && (reg->flags & KBASE_REG_CPU_CACHED)) { -+ reg->gpu_alloc = kbase_alloc_create(reg->nr_pages, -+ KBASE_MEM_TYPE_NATIVE); -+ reg->gpu_alloc->imported.kctx = kctx; -+ INIT_LIST_HEAD(®->gpu_alloc->evict_node); -+ } else { -+ reg->gpu_alloc = kbase_mem_phy_alloc_get(reg->cpu_alloc); -+ } -+ -+ INIT_LIST_HEAD(®->jit_node); -+ reg->flags &= ~KBASE_REG_FREE; -+ return 0; -+} -+ -+static inline int kbase_atomic_add_pages(int num_pages, atomic_t *used_pages) -+{ -+ int new_val = atomic_add_return(num_pages, used_pages); -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_total_alloc_pages_change((long long int)new_val); -+#endif -+ return new_val; -+} -+ -+static inline int kbase_atomic_sub_pages(int num_pages, atomic_t *used_pages) -+{ -+ int new_val = atomic_sub_return(num_pages, used_pages); -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_total_alloc_pages_change((long long int)new_val); -+#endif -+ return new_val; -+} -+ -+/* -+ * Max size for kbdev memory pool (in pages) -+ */ -+#define KBASE_MEM_POOL_MAX_SIZE_KBDEV (SZ_64M >> PAGE_SHIFT) -+ -+/* -+ * Max size for kctx memory pool (in pages) -+ */ -+#define KBASE_MEM_POOL_MAX_SIZE_KCTX (SZ_64M >> PAGE_SHIFT) -+ -+/* -+ * The order required for a 2MB page allocation (2^order * 4KB = 2MB) -+ */ -+#define KBASE_MEM_POOL_2MB_PAGE_TABLE_ORDER 9 -+ -+/* -+ * The order required for a 4KB page allocation -+ */ -+#define KBASE_MEM_POOL_4KB_PAGE_TABLE_ORDER 0 -+ -+/** -+ * kbase_mem_pool_init - Create a memory pool for a kbase device -+ * @pool: Memory pool to initialize -+ * @max_size: Maximum number of free pages the pool can hold -+ * @order: Page order for physical page size (order=0=>4kB, order=9=>2MB) -+ * @kbdev: Kbase device where memory is used -+ * @next_pool: Pointer to the next pool or NULL. -+ * -+ * Allocations from @pool are in whole pages. Each @pool has a free list where -+ * pages can be quickly allocated from. The free list is initially empty and -+ * filled whenever pages are freed back to the pool. The number of free pages -+ * in the pool will in general not exceed @max_size, but the pool may in -+ * certain corner cases grow above @max_size. -+ * -+ * If @next_pool is not NULL, we will allocate from @next_pool before going to -+ * the kernel allocator. Similarily pages can spill over to @next_pool when -+ * @pool is full. Pages are zeroed before they spill over to another pool, to -+ * prevent leaking information between applications. -+ * -+ * A shrinker is registered so that Linux mm can reclaim pages from the pool as -+ * needed. -+ * -+ * Return: 0 on success, negative -errno on error -+ */ -+int kbase_mem_pool_init(struct kbase_mem_pool *pool, -+ size_t max_size, -+ size_t order, -+ struct kbase_device *kbdev, -+ struct kbase_mem_pool *next_pool); -+ -+/** -+ * kbase_mem_pool_term - Destroy a memory pool -+ * @pool: Memory pool to destroy -+ * -+ * Pages in the pool will spill over to @next_pool (if available) or freed to -+ * the kernel. -+ */ -+void kbase_mem_pool_term(struct kbase_mem_pool *pool); -+ -+/** -+ * kbase_mem_pool_alloc - Allocate a page from memory pool -+ * @pool: Memory pool to allocate from -+ * -+ * Allocations from the pool are made as follows: -+ * 1. If there are free pages in the pool, allocate a page from @pool. -+ * 2. Otherwise, if @next_pool is not NULL and has free pages, allocate a page -+ * from @next_pool. -+ * 3. Return NULL if no memory in the pool -+ * -+ * Return: Pointer to allocated page, or NULL if allocation failed. -+ */ -+struct page *kbase_mem_pool_alloc(struct kbase_mem_pool *pool); -+ -+/** -+ * kbase_mem_pool_free - Free a page to memory pool -+ * @pool: Memory pool where page should be freed -+ * @page: Page to free to the pool -+ * @dirty: Whether some of the page may be dirty in the cache. -+ * -+ * Pages are freed to the pool as follows: -+ * 1. If @pool is not full, add @page to @pool. -+ * 2. Otherwise, if @next_pool is not NULL and not full, add @page to -+ * @next_pool. -+ * 3. Finally, free @page to the kernel. -+ */ -+void kbase_mem_pool_free(struct kbase_mem_pool *pool, struct page *page, -+ bool dirty); -+ -+/** -+ * kbase_mem_pool_alloc_pages - Allocate pages from memory pool -+ * @pool: Memory pool to allocate from -+ * @nr_pages: Number of pages to allocate -+ * @pages: Pointer to array where the physical address of the allocated -+ * pages will be stored. -+ * @partial_allowed: If fewer pages allocated is allowed -+ * -+ * Like kbase_mem_pool_alloc() but optimized for allocating many pages. -+ * -+ * Return: -+ * On success number of pages allocated (could be less than nr_pages if -+ * partial_allowed). -+ * On error an error code. -+ */ -+int kbase_mem_pool_alloc_pages(struct kbase_mem_pool *pool, size_t nr_pages, -+ struct tagged_addr *pages, bool partial_allowed); -+ -+/** -+ * kbase_mem_pool_free_pages - Free pages to memory pool -+ * @pool: Memory pool where pages should be freed -+ * @nr_pages: Number of pages to free -+ * @pages: Pointer to array holding the physical addresses of the pages to -+ * free. -+ * @dirty: Whether any pages may be dirty in the cache. -+ * @reclaimed: Whether the pages where reclaimable and thus should bypass -+ * the pool and go straight to the kernel. -+ * -+ * Like kbase_mem_pool_free() but optimized for freeing many pages. -+ */ -+void kbase_mem_pool_free_pages(struct kbase_mem_pool *pool, size_t nr_pages, -+ struct tagged_addr *pages, bool dirty, bool reclaimed); -+ -+/** -+ * kbase_mem_pool_size - Get number of free pages in memory pool -+ * @pool: Memory pool to inspect -+ * -+ * Note: the size of the pool may in certain corner cases exceed @max_size! -+ * -+ * Return: Number of free pages in the pool -+ */ -+static inline size_t kbase_mem_pool_size(struct kbase_mem_pool *pool) -+{ -+ return ACCESS_ONCE(pool->cur_size); -+} -+ -+/** -+ * kbase_mem_pool_max_size - Get maximum number of free pages in memory pool -+ * @pool: Memory pool to inspect -+ * -+ * Return: Maximum number of free pages in the pool -+ */ -+static inline size_t kbase_mem_pool_max_size(struct kbase_mem_pool *pool) -+{ -+ return pool->max_size; -+} -+ -+ -+/** -+ * kbase_mem_pool_set_max_size - Set maximum number of free pages in memory pool -+ * @pool: Memory pool to inspect -+ * @max_size: Maximum number of free pages the pool can hold -+ * -+ * If @max_size is reduced, the pool will be shrunk to adhere to the new limit. -+ * For details see kbase_mem_pool_shrink(). -+ */ -+void kbase_mem_pool_set_max_size(struct kbase_mem_pool *pool, size_t max_size); -+ -+/** -+ * kbase_mem_pool_grow - Grow the pool -+ * @pool: Memory pool to grow -+ * @nr_to_grow: Number of pages to add to the pool -+ * -+ * Adds @nr_to_grow pages to the pool. Note that this may cause the pool to -+ * become larger than the maximum size specified. -+ * -+ * Returns: 0 on success, -ENOMEM if unable to allocate sufficent pages -+ */ -+int kbase_mem_pool_grow(struct kbase_mem_pool *pool, size_t nr_to_grow); -+ -+/** -+ * kbase_mem_pool_trim - Grow or shrink the pool to a new size -+ * @pool: Memory pool to trim -+ * @new_size: New number of pages in the pool -+ * -+ * If @new_size > @cur_size, fill the pool with new pages from the kernel, but -+ * not above the max_size for the pool. -+ * If @new_size < @cur_size, shrink the pool by freeing pages to the kernel. -+ */ -+void kbase_mem_pool_trim(struct kbase_mem_pool *pool, size_t new_size); -+ -+/** -+ * kbase_mem_alloc_page - Allocate a new page for a device -+ * @pool: Memory pool to allocate a page from -+ * -+ * Most uses should use kbase_mem_pool_alloc to allocate a page. However that -+ * function can fail in the event the pool is empty. -+ * -+ * Return: A new page or NULL if no memory -+ */ -+struct page *kbase_mem_alloc_page(struct kbase_mem_pool *pool); -+ -+int kbase_region_tracker_init(struct kbase_context *kctx); -+int kbase_region_tracker_init_jit(struct kbase_context *kctx, u64 jit_va_pages); -+void kbase_region_tracker_term(struct kbase_context *kctx); -+ -+struct kbase_va_region *kbase_region_tracker_find_region_enclosing_address(struct kbase_context *kctx, u64 gpu_addr); -+ -+/** -+ * @brief Check that a pointer is actually a valid region. -+ * -+ * Must be called with context lock held. -+ */ -+struct kbase_va_region *kbase_region_tracker_find_region_base_address(struct kbase_context *kctx, u64 gpu_addr); -+ -+struct kbase_va_region *kbase_alloc_free_region(struct kbase_context *kctx, u64 start_pfn, size_t nr_pages, int zone); -+void kbase_free_alloced_region(struct kbase_va_region *reg); -+int kbase_add_va_region(struct kbase_context *kctx, struct kbase_va_region *reg, u64 addr, size_t nr_pages, size_t align); -+ -+bool kbase_check_alloc_flags(unsigned long flags); -+bool kbase_check_import_flags(unsigned long flags); -+ -+/** -+ * kbase_update_region_flags - Convert user space flags to kernel region flags -+ * -+ * @kctx: kbase context -+ * @reg: The region to update the flags on -+ * @flags: The flags passed from user space -+ * -+ * The user space flag BASE_MEM_COHERENT_SYSTEM_REQUIRED will be rejected and -+ * this function will fail if the system does not support system coherency. -+ * -+ * Return: 0 if successful, -EINVAL if the flags are not supported -+ */ -+int kbase_update_region_flags(struct kbase_context *kctx, -+ struct kbase_va_region *reg, unsigned long flags); -+ -+void kbase_gpu_vm_lock(struct kbase_context *kctx); -+void kbase_gpu_vm_unlock(struct kbase_context *kctx); -+ -+int kbase_alloc_phy_pages(struct kbase_va_region *reg, size_t vsize, size_t size); -+ -+int kbase_mmu_init(struct kbase_context *kctx); -+void kbase_mmu_term(struct kbase_context *kctx); -+ -+phys_addr_t kbase_mmu_alloc_pgd(struct kbase_context *kctx); -+void kbase_mmu_free_pgd(struct kbase_context *kctx); -+int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, u64 vpfn, -+ struct tagged_addr *phys, size_t nr, -+ unsigned long flags); -+int kbase_mmu_insert_pages(struct kbase_context *kctx, u64 vpfn, -+ struct tagged_addr *phys, size_t nr, -+ unsigned long flags); -+int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, -+ struct tagged_addr phys, size_t nr, -+ unsigned long flags); -+ -+int kbase_mmu_teardown_pages(struct kbase_context *kctx, u64 vpfn, size_t nr); -+int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn, -+ struct tagged_addr *phys, size_t nr, -+ unsigned long flags); -+ -+/** -+ * @brief Register region and map it on the GPU. -+ * -+ * Call kbase_add_va_region() and map the region on the GPU. -+ */ -+int kbase_gpu_mmap(struct kbase_context *kctx, struct kbase_va_region *reg, u64 addr, size_t nr_pages, size_t align); -+ -+/** -+ * @brief Remove the region from the GPU and unregister it. -+ * -+ * Must be called with context lock held. -+ */ -+int kbase_gpu_munmap(struct kbase_context *kctx, struct kbase_va_region *reg); -+ -+/** -+ * The caller has the following locking conditions: -+ * - It must hold kbase_device->mmu_hw_mutex -+ * - It must hold the hwaccess_lock -+ */ -+void kbase_mmu_update(struct kbase_context *kctx); -+ -+/** -+ * kbase_mmu_disable() - Disable the MMU for a previously active kbase context. -+ * @kctx: Kbase context -+ * -+ * Disable and perform the required cache maintenance to remove the all -+ * data from provided kbase context from the GPU caches. -+ * -+ * The caller has the following locking conditions: -+ * - It must hold kbase_device->mmu_hw_mutex -+ * - It must hold the hwaccess_lock -+ */ -+void kbase_mmu_disable(struct kbase_context *kctx); -+ -+/** -+ * kbase_mmu_disable_as() - Set the MMU to unmapped mode for the specified -+ * address space. -+ * @kbdev: Kbase device -+ * @as_nr: The address space number to set to unmapped. -+ * -+ * This function must only be called during reset/power-up and it used to -+ * ensure the registers are in a known state. -+ * -+ * The caller must hold kbdev->mmu_hw_mutex. -+ */ -+void kbase_mmu_disable_as(struct kbase_device *kbdev, int as_nr); -+ -+void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat); -+ -+/** Dump the MMU tables to a buffer -+ * -+ * This function allocates a buffer (of @c nr_pages pages) to hold a dump of the MMU tables and fills it. If the -+ * buffer is too small then the return value will be NULL. -+ * -+ * The GPU vm lock must be held when calling this function. -+ * -+ * The buffer returned should be freed with @ref vfree when it is no longer required. -+ * -+ * @param[in] kctx The kbase context to dump -+ * @param[in] nr_pages The number of pages to allocate for the buffer. -+ * -+ * @return The address of the buffer containing the MMU dump or NULL on error (including if the @c nr_pages is too -+ * small) -+ */ -+void *kbase_mmu_dump(struct kbase_context *kctx, int nr_pages); -+ -+/** -+ * kbase_sync_now - Perform cache maintenance on a memory region -+ * -+ * @kctx: The kbase context of the region -+ * @sset: A syncset structure describing the region and direction of the -+ * synchronisation required -+ * -+ * Return: 0 on success or error code -+ */ -+int kbase_sync_now(struct kbase_context *kctx, struct basep_syncset *sset); -+void kbase_sync_single(struct kbase_context *kctx, struct tagged_addr cpu_pa, -+ struct tagged_addr gpu_pa, off_t offset, size_t size, -+ enum kbase_sync_type sync_fn); -+void kbase_pre_job_sync(struct kbase_context *kctx, struct base_syncset *syncsets, size_t nr); -+void kbase_post_job_sync(struct kbase_context *kctx, struct base_syncset *syncsets, size_t nr); -+ -+/* OS specific functions */ -+int kbase_mem_free(struct kbase_context *kctx, u64 gpu_addr); -+int kbase_mem_free_region(struct kbase_context *kctx, struct kbase_va_region *reg); -+void kbase_os_mem_map_lock(struct kbase_context *kctx); -+void kbase_os_mem_map_unlock(struct kbase_context *kctx); -+ -+/** -+ * @brief Update the memory allocation counters for the current process -+ * -+ * OS specific call to updates the current memory allocation counters for the current process with -+ * the supplied delta. -+ * -+ * @param[in] kctx The kbase context -+ * @param[in] pages The desired delta to apply to the memory usage counters. -+ */ -+ -+void kbasep_os_process_page_usage_update(struct kbase_context *kctx, int pages); -+ -+/** -+ * @brief Add to the memory allocation counters for the current process -+ * -+ * OS specific call to add to the current memory allocation counters for the current process by -+ * the supplied amount. -+ * -+ * @param[in] kctx The kernel base context used for the allocation. -+ * @param[in] pages The desired delta to apply to the memory usage counters. -+ */ -+ -+static inline void kbase_process_page_usage_inc(struct kbase_context *kctx, int pages) -+{ -+ kbasep_os_process_page_usage_update(kctx, pages); -+} -+ -+/** -+ * @brief Subtract from the memory allocation counters for the current process -+ * -+ * OS specific call to subtract from the current memory allocation counters for the current process by -+ * the supplied amount. -+ * -+ * @param[in] kctx The kernel base context used for the allocation. -+ * @param[in] pages The desired delta to apply to the memory usage counters. -+ */ -+ -+static inline void kbase_process_page_usage_dec(struct kbase_context *kctx, int pages) -+{ -+ kbasep_os_process_page_usage_update(kctx, 0 - pages); -+} -+ -+/** -+ * kbasep_find_enclosing_cpu_mapping_offset() - Find the offset of the CPU -+ * mapping of a memory allocation containing a given address range -+ * -+ * Searches for a CPU mapping of any part of any region that fully encloses the -+ * CPU virtual address range specified by @uaddr and @size. Returns a failure -+ * indication if only part of the address range lies within a CPU mapping. -+ * -+ * @kctx: The kernel base context used for the allocation. -+ * @uaddr: Start of the CPU virtual address range. -+ * @size: Size of the CPU virtual address range (in bytes). -+ * @offset: The offset from the start of the allocation to the specified CPU -+ * virtual address. -+ * -+ * Return: 0 if offset was obtained successfully. Error code otherwise. -+ */ -+int kbasep_find_enclosing_cpu_mapping_offset( -+ struct kbase_context *kctx, -+ unsigned long uaddr, size_t size, u64 *offset); -+ -+enum hrtimer_restart kbasep_as_poke_timer_callback(struct hrtimer *timer); -+void kbase_as_poking_timer_retain_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom); -+void kbase_as_poking_timer_release_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom); -+ -+/** -+* @brief Allocates physical pages. -+* -+* Allocates \a nr_pages_requested and updates the alloc object. -+* -+* @param[in] alloc allocation object to add pages to -+* @param[in] nr_pages_requested number of physical pages to allocate -+* -+* @return 0 if all pages have been successfully allocated. Error code otherwise -+*/ -+int kbase_alloc_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, size_t nr_pages_requested); -+ -+/** -+* @brief Free physical pages. -+* -+* Frees \a nr_pages and updates the alloc object. -+* -+* @param[in] alloc allocation object to free pages from -+* @param[in] nr_pages_to_free number of physical pages to free -+*/ -+int kbase_free_phy_pages_helper(struct kbase_mem_phy_alloc *alloc, size_t nr_pages_to_free); -+ -+static inline void kbase_set_dma_addr(struct page *p, dma_addr_t dma_addr) -+{ -+ SetPagePrivate(p); -+ if (sizeof(dma_addr_t) > sizeof(p->private)) { -+ /* on 32-bit ARM with LPAE dma_addr_t becomes larger, but the -+ * private field stays the same. So we have to be clever and -+ * use the fact that we only store DMA addresses of whole pages, -+ * so the low bits should be zero */ -+ KBASE_DEBUG_ASSERT(!(dma_addr & (PAGE_SIZE - 1))); -+ set_page_private(p, dma_addr >> PAGE_SHIFT); -+ } else { -+ set_page_private(p, dma_addr); -+ } -+} -+ -+static inline dma_addr_t kbase_dma_addr(struct page *p) -+{ -+ if (sizeof(dma_addr_t) > sizeof(p->private)) -+ return ((dma_addr_t)page_private(p)) << PAGE_SHIFT; -+ -+ return (dma_addr_t)page_private(p); -+} -+ -+static inline void kbase_clear_dma_addr(struct page *p) -+{ -+ ClearPagePrivate(p); -+} -+ -+/** -+* @brief Process a bus or page fault. -+* -+* This function will process a fault on a specific address space -+* -+* @param[in] kbdev The @ref kbase_device the fault happened on -+* @param[in] kctx The @ref kbase_context for the faulting address space if -+* one was found. -+* @param[in] as The address space that has the fault -+*/ -+void kbase_mmu_interrupt_process(struct kbase_device *kbdev, -+ struct kbase_context *kctx, struct kbase_as *as); -+ -+/** -+ * @brief Process a page fault. -+ * -+ * @param[in] data work_struct passed by queue_work() -+ */ -+void page_fault_worker(struct work_struct *data); -+ -+/** -+ * @brief Process a bus fault. -+ * -+ * @param[in] data work_struct passed by queue_work() -+ */ -+void bus_fault_worker(struct work_struct *data); -+ -+/** -+ * @brief Flush MMU workqueues. -+ * -+ * This function will cause any outstanding page or bus faults to be processed. -+ * It should be called prior to powering off the GPU. -+ * -+ * @param[in] kbdev Device pointer -+ */ -+void kbase_flush_mmu_wqs(struct kbase_device *kbdev); -+ -+/** -+ * kbase_sync_single_for_device - update physical memory and give GPU ownership -+ * @kbdev: Device pointer -+ * @handle: DMA address of region -+ * @size: Size of region to sync -+ * @dir: DMA data direction -+ */ -+ -+void kbase_sync_single_for_device(struct kbase_device *kbdev, dma_addr_t handle, -+ size_t size, enum dma_data_direction dir); -+ -+/** -+ * kbase_sync_single_for_cpu - update physical memory and give CPU ownership -+ * @kbdev: Device pointer -+ * @handle: DMA address of region -+ * @size: Size of region to sync -+ * @dir: DMA data direction -+ */ -+ -+void kbase_sync_single_for_cpu(struct kbase_device *kbdev, dma_addr_t handle, -+ size_t size, enum dma_data_direction dir); -+ -+#ifdef CONFIG_DEBUG_FS -+/** -+ * kbase_jit_debugfs_init - Add per context debugfs entry for JIT. -+ * @kctx: kbase context -+ */ -+void kbase_jit_debugfs_init(struct kbase_context *kctx); -+#endif /* CONFIG_DEBUG_FS */ -+ -+/** -+ * kbase_jit_init - Initialize the JIT memory pool management -+ * @kctx: kbase context -+ * -+ * Returns zero on success or negative error number on failure. -+ */ -+int kbase_jit_init(struct kbase_context *kctx); -+ -+/** -+ * kbase_jit_allocate - Allocate JIT memory -+ * @kctx: kbase context -+ * @info: JIT allocation information -+ * -+ * Return: JIT allocation on success or NULL on failure. -+ */ -+struct kbase_va_region *kbase_jit_allocate(struct kbase_context *kctx, -+ struct base_jit_alloc_info *info); -+ -+/** -+ * kbase_jit_free - Free a JIT allocation -+ * @kctx: kbase context -+ * @reg: JIT allocation -+ * -+ * Frees a JIT allocation and places it into the free pool for later reuse. -+ */ -+void kbase_jit_free(struct kbase_context *kctx, struct kbase_va_region *reg); -+ -+/** -+ * kbase_jit_backing_lost - Inform JIT that an allocation has lost backing -+ * @reg: JIT allocation -+ */ -+void kbase_jit_backing_lost(struct kbase_va_region *reg); -+ -+/** -+ * kbase_jit_evict - Evict a JIT allocation from the pool -+ * @kctx: kbase context -+ * -+ * Evict the least recently used JIT allocation from the pool. This can be -+ * required if normal VA allocations are failing due to VA exhaustion. -+ * -+ * Return: True if a JIT allocation was freed, false otherwise. -+ */ -+bool kbase_jit_evict(struct kbase_context *kctx); -+ -+/** -+ * kbase_jit_term - Terminate the JIT memory pool management -+ * @kctx: kbase context -+ */ -+void kbase_jit_term(struct kbase_context *kctx); -+ -+/** -+ * kbase_map_external_resource - Map an external resource to the GPU. -+ * @kctx: kbase context. -+ * @reg: The region to map. -+ * @locked_mm: The mm_struct which has been locked for this operation. -+ * @kds_res_count: The number of KDS resources. -+ * @kds_resources: Array of KDS resources. -+ * @kds_access_bitmap: Access bitmap for KDS. -+ * @exclusive: If the KDS resource requires exclusive access. -+ * -+ * Return: The physical allocation which backs the region on success or NULL -+ * on failure. -+ */ -+struct kbase_mem_phy_alloc *kbase_map_external_resource( -+ struct kbase_context *kctx, struct kbase_va_region *reg, -+ struct mm_struct *locked_mm -+#ifdef CONFIG_KDS -+ , u32 *kds_res_count, struct kds_resource **kds_resources, -+ unsigned long *kds_access_bitmap, bool exclusive -+#endif -+ ); -+ -+/** -+ * kbase_unmap_external_resource - Unmap an external resource from the GPU. -+ * @kctx: kbase context. -+ * @reg: The region to unmap or NULL if it has already been released. -+ * @alloc: The physical allocation being unmapped. -+ */ -+void kbase_unmap_external_resource(struct kbase_context *kctx, -+ struct kbase_va_region *reg, struct kbase_mem_phy_alloc *alloc); -+ -+/** -+ * kbase_sticky_resource_init - Initialize sticky resource management. -+ * @kctx: kbase context -+ * -+ * Returns zero on success or negative error number on failure. -+ */ -+int kbase_sticky_resource_init(struct kbase_context *kctx); -+ -+/** -+ * kbase_sticky_resource_acquire - Acquire a reference on a sticky resource. -+ * @kctx: kbase context. -+ * @gpu_addr: The GPU address of the external resource. -+ * -+ * Return: The metadata object which represents the binding between the -+ * external resource and the kbase context on success or NULL on failure. -+ */ -+struct kbase_ctx_ext_res_meta *kbase_sticky_resource_acquire( -+ struct kbase_context *kctx, u64 gpu_addr); -+ -+/** -+ * kbase_sticky_resource_release - Release a reference on a sticky resource. -+ * @kctx: kbase context. -+ * @meta: Binding metadata. -+ * @gpu_addr: GPU address of the external resource. -+ * -+ * If meta is NULL then gpu_addr will be used to scan the metadata list and -+ * find the matching metadata (if any), otherwise the provided meta will be -+ * used and gpu_addr will be ignored. -+ * -+ * Return: True if the release found the metadata and the reference was dropped. -+ */ -+bool kbase_sticky_resource_release(struct kbase_context *kctx, -+ struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr); -+ -+/** -+ * kbase_sticky_resource_term - Terminate sticky resource management. -+ * @kctx: kbase context -+ */ -+void kbase_sticky_resource_term(struct kbase_context *kctx); -+ -+/** -+ * kbase_zone_cache_update - Update the memory zone cache after new pages have -+ * been added. -+ * @alloc: The physical memory allocation to build the cache for. -+ * @start_offset: Offset to where the new pages start. -+ * -+ * Updates an existing memory zone cache, updating the counters for the -+ * various zones. -+ * If the memory allocation doesn't already have a zone cache assume that -+ * one isn't created and thus don't do anything. -+ * -+ * Return: Zero cache was updated, negative error code on error. -+ */ -+int kbase_zone_cache_update(struct kbase_mem_phy_alloc *alloc, -+ size_t start_offset); -+ -+/** -+ * kbase_zone_cache_build - Build the memory zone cache. -+ * @alloc: The physical memory allocation to build the cache for. -+ * -+ * Create a new zone cache for the provided physical memory allocation if -+ * one doesn't already exist, if one does exist then just return. -+ * -+ * Return: Zero if the zone cache was created, negative error code on error. -+ */ -+int kbase_zone_cache_build(struct kbase_mem_phy_alloc *alloc); -+ -+/** -+ * kbase_zone_cache_clear - Clear the memory zone cache. -+ * @alloc: The physical memory allocation to clear the cache on. -+ */ -+void kbase_zone_cache_clear(struct kbase_mem_phy_alloc *alloc); -+ -+#endif /* _KBASE_MEM_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c -new file mode 100644 -index 0000000..b1f2c46 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c -@@ -0,0 +1,2670 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_mem_linux.c -+ * Base kernel memory APIs, Linux implementation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) && \ -+ (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) -+#include -+#endif /* LINUX_VERSION_CODE >= 3.5.0 && < 4.8.0 */ -+#ifdef CONFIG_DMA_SHARED_BUFFER -+#include -+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+static int kbase_tracking_page_setup(struct kbase_context *kctx, struct vm_area_struct *vma); -+ -+/** -+ * kbase_mem_shrink_cpu_mapping - Shrink the CPU mapping(s) of an allocation -+ * @kctx: Context the region belongs to -+ * @reg: The GPU region -+ * @new_pages: The number of pages after the shrink -+ * @old_pages: The number of pages before the shrink -+ * -+ * Shrink (or completely remove) all CPU mappings which reference the shrunk -+ * part of the allocation. -+ * -+ * Note: Caller must be holding the processes mmap_sem lock. -+ */ -+static void kbase_mem_shrink_cpu_mapping(struct kbase_context *kctx, -+ struct kbase_va_region *reg, -+ u64 new_pages, u64 old_pages); -+ -+/** -+ * kbase_mem_shrink_gpu_mapping - Shrink the GPU mapping of an allocation -+ * @kctx: Context the region belongs to -+ * @reg: The GPU region or NULL if there isn't one -+ * @new_pages: The number of pages after the shrink -+ * @old_pages: The number of pages before the shrink -+ * -+ * Return: 0 on success, negative -errno on error -+ * -+ * Unmap the shrunk pages from the GPU mapping. Note that the size of the region -+ * itself is unmodified as we still need to reserve the VA, only the page tables -+ * will be modified by this function. -+ */ -+static int kbase_mem_shrink_gpu_mapping(struct kbase_context *kctx, -+ struct kbase_va_region *reg, -+ u64 new_pages, u64 old_pages); -+ -+struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, -+ u64 va_pages, u64 commit_pages, u64 extent, u64 *flags, -+ u64 *gpu_va) -+{ -+ int zone; -+ int gpu_pc_bits; -+ struct kbase_va_region *reg; -+ struct device *dev; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(flags); -+ KBASE_DEBUG_ASSERT(gpu_va); -+ -+ dev = kctx->kbdev->dev; -+ *gpu_va = 0; /* return 0 on failure */ -+ -+ gpu_pc_bits = kctx->kbdev->gpu_props.props.core_props.log2_program_counter_size; -+ -+ if (0 == va_pages) { -+ dev_warn(dev, "kbase_mem_alloc called with 0 va_pages!"); -+ goto bad_size; -+ } -+ -+ if (va_pages > (U64_MAX / PAGE_SIZE)) -+ /* 64-bit address range is the max */ -+ goto bad_size; -+ -+ if (!kbase_check_alloc_flags(*flags)) { -+ dev_warn(dev, -+ "kbase_mem_alloc called with bad flags (%llx)", -+ (unsigned long long)*flags); -+ goto bad_flags; -+ } -+ -+ if ((*flags & BASE_MEM_COHERENT_SYSTEM_REQUIRED) != 0 && -+ !kbase_device_is_cpu_coherent(kctx->kbdev)) { -+ dev_warn(dev, "kbase_mem_alloc call required coherent mem when unavailable"); -+ goto bad_flags; -+ } -+ if ((*flags & BASE_MEM_COHERENT_SYSTEM) != 0 && -+ !kbase_device_is_cpu_coherent(kctx->kbdev)) { -+ /* Remove COHERENT_SYSTEM flag if coherent mem is unavailable */ -+ *flags &= ~BASE_MEM_COHERENT_SYSTEM; -+ } -+ -+ /* Limit GPU executable allocs to GPU PC size */ -+ if ((*flags & BASE_MEM_PROT_GPU_EX) && -+ (va_pages > (1ULL << gpu_pc_bits >> PAGE_SHIFT))) -+ goto bad_ex_size; -+ -+ /* find out which VA zone to use */ -+ if (*flags & BASE_MEM_SAME_VA) -+ zone = KBASE_REG_ZONE_SAME_VA; -+ else if (*flags & BASE_MEM_PROT_GPU_EX) -+ zone = KBASE_REG_ZONE_EXEC; -+ else -+ zone = KBASE_REG_ZONE_CUSTOM_VA; -+ -+ reg = kbase_alloc_free_region(kctx, 0, va_pages, zone); -+ if (!reg) { -+ dev_err(dev, "Failed to allocate free region"); -+ goto no_region; -+ } -+ -+ if (kbase_update_region_flags(kctx, reg, *flags) != 0) -+ goto invalid_flags; -+ -+ if (kbase_reg_prepare_native(reg, kctx) != 0) { -+ dev_err(dev, "Failed to prepare region"); -+ goto prepare_failed; -+ } -+ -+ if (*flags & BASE_MEM_GROW_ON_GPF) -+ reg->extent = extent; -+ else -+ reg->extent = 0; -+ -+ if (kbase_alloc_phy_pages(reg, va_pages, commit_pages) != 0) { -+ dev_warn(dev, "Failed to allocate %lld pages (va_pages=%lld)", -+ (unsigned long long)commit_pages, -+ (unsigned long long)va_pages); -+ goto no_mem; -+ } -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ /* mmap needed to setup VA? */ -+ if (*flags & BASE_MEM_SAME_VA) { -+ unsigned long prot = PROT_NONE; -+ unsigned long va_size = va_pages << PAGE_SHIFT; -+ unsigned long va_map = va_size; -+ unsigned long cookie, cookie_nr; -+ unsigned long cpu_addr; -+ -+ /* Bind to a cookie */ -+ if (!kctx->cookies) { -+ dev_err(dev, "No cookies available for allocation!"); -+ kbase_gpu_vm_unlock(kctx); -+ goto no_cookie; -+ } -+ /* return a cookie */ -+ cookie_nr = __ffs(kctx->cookies); -+ kctx->cookies &= ~(1UL << cookie_nr); -+ BUG_ON(kctx->pending_regions[cookie_nr]); -+ kctx->pending_regions[cookie_nr] = reg; -+ -+ kbase_gpu_vm_unlock(kctx); -+ -+ /* relocate to correct base */ -+ cookie = cookie_nr + PFN_DOWN(BASE_MEM_COOKIE_BASE); -+ cookie <<= PAGE_SHIFT; -+ -+ /* -+ * 10.1-10.4 UKU userland relies on the kernel to call mmap. -+ * For all other versions we can just return the cookie -+ */ -+ if (kctx->api_version < KBASE_API_VERSION(10, 1) || -+ kctx->api_version > KBASE_API_VERSION(10, 4)) { -+ *gpu_va = (u64) cookie; -+ return reg; -+ } -+ if (*flags & BASE_MEM_PROT_CPU_RD) -+ prot |= PROT_READ; -+ if (*flags & BASE_MEM_PROT_CPU_WR) -+ prot |= PROT_WRITE; -+ -+ cpu_addr = vm_mmap(kctx->filp, 0, va_map, prot, -+ MAP_SHARED, cookie); -+ -+ if (IS_ERR_VALUE(cpu_addr)) { -+ kbase_gpu_vm_lock(kctx); -+ kctx->pending_regions[cookie_nr] = NULL; -+ kctx->cookies |= (1UL << cookie_nr); -+ kbase_gpu_vm_unlock(kctx); -+ goto no_mmap; -+ } -+ -+ *gpu_va = (u64) cpu_addr; -+ } else /* we control the VA */ { -+ if (kbase_gpu_mmap(kctx, reg, 0, va_pages, 1) != 0) { -+ dev_warn(dev, "Failed to map memory on GPU"); -+ kbase_gpu_vm_unlock(kctx); -+ goto no_mmap; -+ } -+ /* return real GPU VA */ -+ *gpu_va = reg->start_pfn << PAGE_SHIFT; -+ -+ kbase_gpu_vm_unlock(kctx); -+ } -+ -+ return reg; -+ -+no_mmap: -+no_cookie: -+no_mem: -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+invalid_flags: -+prepare_failed: -+ kfree(reg); -+no_region: -+bad_ex_size: -+bad_flags: -+bad_size: -+ return NULL; -+} -+KBASE_EXPORT_TEST_API(kbase_mem_alloc); -+ -+int kbase_mem_query(struct kbase_context *kctx, u64 gpu_addr, int query, u64 * const out) -+{ -+ struct kbase_va_region *reg; -+ int ret = -EINVAL; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(out); -+ -+ if (gpu_addr & ~PAGE_MASK) { -+ dev_warn(kctx->kbdev->dev, "mem_query: gpu_addr: passed parameter is invalid"); -+ return -EINVAL; -+ } -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ /* Validate the region */ -+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr); -+ if (!reg || (reg->flags & KBASE_REG_FREE)) -+ goto out_unlock; -+ -+ switch (query) { -+ case KBASE_MEM_QUERY_COMMIT_SIZE: -+ if (reg->cpu_alloc->type != KBASE_MEM_TYPE_ALIAS) { -+ *out = kbase_reg_current_backed_size(reg); -+ } else { -+ size_t i; -+ struct kbase_aliased *aliased; -+ *out = 0; -+ aliased = reg->cpu_alloc->imported.alias.aliased; -+ for (i = 0; i < reg->cpu_alloc->imported.alias.nents; i++) -+ *out += aliased[i].length; -+ } -+ break; -+ case KBASE_MEM_QUERY_VA_SIZE: -+ *out = reg->nr_pages; -+ break; -+ case KBASE_MEM_QUERY_FLAGS: -+ { -+ *out = 0; -+ if (KBASE_REG_CPU_WR & reg->flags) -+ *out |= BASE_MEM_PROT_CPU_WR; -+ if (KBASE_REG_CPU_RD & reg->flags) -+ *out |= BASE_MEM_PROT_CPU_RD; -+ if (KBASE_REG_CPU_CACHED & reg->flags) -+ *out |= BASE_MEM_CACHED_CPU; -+ if (KBASE_REG_GPU_WR & reg->flags) -+ *out |= BASE_MEM_PROT_GPU_WR; -+ if (KBASE_REG_GPU_RD & reg->flags) -+ *out |= BASE_MEM_PROT_GPU_RD; -+ if (!(KBASE_REG_GPU_NX & reg->flags)) -+ *out |= BASE_MEM_PROT_GPU_EX; -+ if (KBASE_REG_SHARE_BOTH & reg->flags) -+ *out |= BASE_MEM_COHERENT_SYSTEM; -+ if (KBASE_REG_SHARE_IN & reg->flags) -+ *out |= BASE_MEM_COHERENT_LOCAL; -+ break; -+ } -+ default: -+ *out = 0; -+ goto out_unlock; -+ } -+ -+ ret = 0; -+ -+out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ return ret; -+} -+ -+/** -+ * kbase_mem_evictable_reclaim_count_objects - Count number of pages in the -+ * Ephemeral memory eviction list. -+ * @s: Shrinker -+ * @sc: Shrinker control -+ * -+ * Return: Number of pages which can be freed. -+ */ -+static -+unsigned long kbase_mem_evictable_reclaim_count_objects(struct shrinker *s, -+ struct shrink_control *sc) -+{ -+ struct kbase_context *kctx; -+ struct kbase_mem_phy_alloc *alloc; -+ unsigned long pages = 0; -+ -+ kctx = container_of(s, struct kbase_context, reclaim); -+ -+ mutex_lock(&kctx->jit_evict_lock); -+ -+ list_for_each_entry(alloc, &kctx->evict_list, evict_node) -+ pages += alloc->nents; -+ -+ mutex_unlock(&kctx->jit_evict_lock); -+ return pages; -+} -+ -+/** -+ * kbase_mem_evictable_reclaim_scan_objects - Scan the Ephemeral memory eviction -+ * list for pages and try to reclaim them. -+ * @s: Shrinker -+ * @sc: Shrinker control -+ * -+ * Return: Number of pages freed (can be less then requested) or -1 if the -+ * shrinker failed to free pages in its pool. -+ * -+ * Note: -+ * This function accesses region structures without taking the region lock, -+ * this is required as the OOM killer can call the shrinker after the region -+ * lock has already been held. -+ * This is safe as we can guarantee that a region on the eviction list will -+ * not be freed (kbase_mem_free_region removes the allocation from the list -+ * before destroying it), or modified by other parts of the driver. -+ * The eviction list itself is guarded by the eviction lock and the MMU updates -+ * are protected by their own lock. -+ */ -+static -+unsigned long kbase_mem_evictable_reclaim_scan_objects(struct shrinker *s, -+ struct shrink_control *sc) -+{ -+ struct kbase_context *kctx; -+ struct kbase_mem_phy_alloc *alloc; -+ struct kbase_mem_phy_alloc *tmp; -+ unsigned long freed = 0; -+ -+ kctx = container_of(s, struct kbase_context, reclaim); -+ mutex_lock(&kctx->jit_evict_lock); -+ -+ list_for_each_entry_safe(alloc, tmp, &kctx->evict_list, evict_node) { -+ int err; -+ -+ err = kbase_mem_shrink_gpu_mapping(kctx, alloc->reg, -+ 0, alloc->nents); -+ if (err != 0) { -+ /* -+ * Failed to remove GPU mapping, tell the shrinker -+ * to stop trying to shrink our slab even though we -+ * have pages in it. -+ */ -+ freed = -1; -+ goto out_unlock; -+ } -+ -+ /* -+ * Update alloc->evicted before freeing the backing so the -+ * helper can determine that it needs to bypass the accounting -+ * and memory pool. -+ */ -+ alloc->evicted = alloc->nents; -+ -+ kbase_free_phy_pages_helper(alloc, alloc->evicted); -+ freed += alloc->evicted; -+ list_del_init(&alloc->evict_node); -+ -+ /* -+ * Inform the JIT allocator this region has lost backing -+ * as it might need to free the allocation. -+ */ -+ kbase_jit_backing_lost(alloc->reg); -+ -+ /* Enough pages have been freed so stop now */ -+ if (freed > sc->nr_to_scan) -+ break; -+ } -+out_unlock: -+ mutex_unlock(&kctx->jit_evict_lock); -+ -+ return freed; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) -+static int kbase_mem_evictable_reclaim_shrink(struct shrinker *s, -+ struct shrink_control *sc) -+{ -+ if (sc->nr_to_scan == 0) -+ return kbase_mem_evictable_reclaim_count_objects(s, sc); -+ -+ return kbase_mem_evictable_reclaim_scan_objects(s, sc); -+} -+#endif -+ -+int kbase_mem_evictable_init(struct kbase_context *kctx) -+{ -+ INIT_LIST_HEAD(&kctx->evict_list); -+ mutex_init(&kctx->jit_evict_lock); -+ -+ /* Register shrinker */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) -+ kctx->reclaim.shrink = kbase_mem_evictable_reclaim_shrink; -+#else -+ kctx->reclaim.count_objects = kbase_mem_evictable_reclaim_count_objects; -+ kctx->reclaim.scan_objects = kbase_mem_evictable_reclaim_scan_objects; -+#endif -+ kctx->reclaim.seeks = DEFAULT_SEEKS; -+ /* Kernel versions prior to 3.1 : -+ * struct shrinker does not define batch */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) -+ kctx->reclaim.batch = 0; -+#endif -+ register_shrinker(&kctx->reclaim); -+ return 0; -+} -+ -+void kbase_mem_evictable_deinit(struct kbase_context *kctx) -+{ -+ unregister_shrinker(&kctx->reclaim); -+} -+ -+struct kbase_mem_zone_cache_entry { -+ /* List head used to link the cache entry to the memory allocation. */ -+ struct list_head zone_node; -+ /* The zone the cacheline is for. */ -+ struct zone *zone; -+ /* The number of pages in the allocation which belong to this zone. */ -+ u64 count; -+}; -+ -+static bool kbase_zone_cache_builder(struct kbase_mem_phy_alloc *alloc, -+ size_t start_offset) -+{ -+ struct kbase_mem_zone_cache_entry *cache = NULL; -+ size_t i; -+ int ret = 0; -+ -+ for (i = start_offset; i < alloc->nents; i++) { -+ struct page *p = phys_to_page(as_phys_addr_t(alloc->pages[i])); -+ struct zone *zone = page_zone(p); -+ bool create = true; -+ -+ if (cache && (cache->zone == zone)) { -+ /* -+ * Fast path check as most of the time adjacent -+ * pages come from the same zone. -+ */ -+ create = false; -+ } else { -+ /* -+ * Slow path check, walk all the cache entries to see -+ * if we already know about this zone. -+ */ -+ list_for_each_entry(cache, &alloc->zone_cache, zone_node) { -+ if (cache->zone == zone) { -+ create = false; -+ break; -+ } -+ } -+ } -+ -+ /* This zone wasn't found in the cache, create an entry for it */ -+ if (create) { -+ cache = kmalloc(sizeof(*cache), GFP_KERNEL); -+ if (!cache) { -+ ret = -ENOMEM; -+ goto bail; -+ } -+ cache->zone = zone; -+ cache->count = 0; -+ list_add(&cache->zone_node, &alloc->zone_cache); -+ } -+ -+ cache->count++; -+ } -+ return 0; -+ -+bail: -+ return ret; -+} -+ -+int kbase_zone_cache_update(struct kbase_mem_phy_alloc *alloc, -+ size_t start_offset) -+{ -+ /* -+ * Bail if the zone cache is empty, only update the cache if it -+ * existed in the first place. -+ */ -+ if (list_empty(&alloc->zone_cache)) -+ return 0; -+ -+ return kbase_zone_cache_builder(alloc, start_offset); -+} -+ -+int kbase_zone_cache_build(struct kbase_mem_phy_alloc *alloc) -+{ -+ /* Bail if the zone cache already exists */ -+ if (!list_empty(&alloc->zone_cache)) -+ return 0; -+ -+ return kbase_zone_cache_builder(alloc, 0); -+} -+ -+void kbase_zone_cache_clear(struct kbase_mem_phy_alloc *alloc) -+{ -+ struct kbase_mem_zone_cache_entry *walker; -+ -+ while(!list_empty(&alloc->zone_cache)){ -+ walker = list_first_entry(&alloc->zone_cache, -+ struct kbase_mem_zone_cache_entry, zone_node); -+ list_del(&walker->zone_node); -+ kfree(walker); -+ } -+} -+ -+/** -+ * kbase_mem_evictable_mark_reclaim - Mark the pages as reclaimable. -+ * @alloc: The physical allocation -+ */ -+static void kbase_mem_evictable_mark_reclaim(struct kbase_mem_phy_alloc *alloc) -+{ -+ struct kbase_context *kctx = alloc->imported.kctx; -+ struct kbase_mem_zone_cache_entry *zone_cache; -+ int __maybe_unused new_page_count; -+ int err; -+ -+ /* Attempt to build a zone cache of tracking */ -+ err = kbase_zone_cache_build(alloc); -+ if (err == 0) { -+ /* Bulk update all the zones */ -+ list_for_each_entry(zone_cache, &alloc->zone_cache, zone_node) { -+ zone_page_state_add(zone_cache->count, -+ zone_cache->zone, NR_SLAB_RECLAIMABLE); -+ } -+ } else { -+ /* Fall-back to page by page updates */ -+ int i; -+ -+ for (i = 0; i < alloc->nents; i++) { -+ struct page *p; -+ struct zone *zone; -+ -+ p = phys_to_page(as_phys_addr_t(alloc->pages[i])); -+ zone = page_zone(p); -+ -+ zone_page_state_add(1, zone, NR_SLAB_RECLAIMABLE); -+ } -+ } -+ -+ kbase_process_page_usage_dec(kctx, alloc->nents); -+ new_page_count = kbase_atomic_sub_pages(alloc->nents, -+ &kctx->used_pages); -+ kbase_atomic_sub_pages(alloc->nents, &kctx->kbdev->memdev.used_pages); -+ -+ KBASE_TLSTREAM_AUX_PAGESALLOC( -+ (u32)kctx->id, -+ (u64)new_page_count); -+} -+ -+/** -+ * kbase_mem_evictable_unmark_reclaim - Mark the pages as no longer reclaimable. -+ * @alloc: The physical allocation -+ */ -+static -+void kbase_mem_evictable_unmark_reclaim(struct kbase_mem_phy_alloc *alloc) -+{ -+ struct kbase_context *kctx = alloc->imported.kctx; -+ struct kbase_mem_zone_cache_entry *zone_cache; -+ int __maybe_unused new_page_count; -+ int err; -+ -+ new_page_count = kbase_atomic_add_pages(alloc->nents, -+ &kctx->used_pages); -+ kbase_atomic_add_pages(alloc->nents, &kctx->kbdev->memdev.used_pages); -+ -+ /* Increase mm counters so that the allocation is accounted for -+ * against the process and thus is visible to the OOM killer, -+ * then remove it from the reclaimable accounting. */ -+ kbase_process_page_usage_inc(kctx, alloc->nents); -+ -+ /* Attempt to build a zone cache of tracking */ -+ err = kbase_zone_cache_build(alloc); -+ if (err == 0) { -+ /* Bulk update all the zones */ -+ list_for_each_entry(zone_cache, &alloc->zone_cache, zone_node) { -+ zone_page_state_add(-zone_cache->count, -+ zone_cache->zone, NR_SLAB_RECLAIMABLE); -+ } -+ } else { -+ /* Fall-back to page by page updates */ -+ int i; -+ -+ for (i = 0; i < alloc->nents; i++) { -+ struct page *p; -+ struct zone *zone; -+ -+ p = phys_to_page(as_phys_addr_t(alloc->pages[i])); -+ zone = page_zone(p); -+ zone_page_state_add(-1, zone, NR_SLAB_RECLAIMABLE); -+ } -+ } -+ -+ KBASE_TLSTREAM_AUX_PAGESALLOC( -+ (u32)kctx->id, -+ (u64)new_page_count); -+} -+ -+int kbase_mem_evictable_make(struct kbase_mem_phy_alloc *gpu_alloc) -+{ -+ struct kbase_context *kctx = gpu_alloc->imported.kctx; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* This alloction can't already be on a list. */ -+ WARN_ON(!list_empty(&gpu_alloc->evict_node)); -+ -+ kbase_mem_shrink_cpu_mapping(kctx, gpu_alloc->reg, -+ 0, gpu_alloc->nents); -+ -+ /* -+ * Add the allocation to the eviction list, after this point the shrink -+ * can reclaim it. -+ */ -+ mutex_lock(&kctx->jit_evict_lock); -+ list_add(&gpu_alloc->evict_node, &kctx->evict_list); -+ mutex_unlock(&kctx->jit_evict_lock); -+ kbase_mem_evictable_mark_reclaim(gpu_alloc); -+ -+ gpu_alloc->reg->flags |= KBASE_REG_DONT_NEED; -+ return 0; -+} -+ -+bool kbase_mem_evictable_unmake(struct kbase_mem_phy_alloc *gpu_alloc) -+{ -+ struct kbase_context *kctx = gpu_alloc->imported.kctx; -+ int err = 0; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* -+ * First remove the allocation from the eviction list as it's no -+ * longer eligible for eviction. -+ */ -+ list_del_init(&gpu_alloc->evict_node); -+ -+ if (gpu_alloc->evicted == 0) { -+ /* -+ * The backing is still present, update the VM stats as it's -+ * in use again. -+ */ -+ kbase_mem_evictable_unmark_reclaim(gpu_alloc); -+ } else { -+ /* If the region is still alive ... */ -+ if (gpu_alloc->reg) { -+ /* ... allocate replacement backing ... */ -+ err = kbase_alloc_phy_pages_helper(gpu_alloc, -+ gpu_alloc->evicted); -+ -+ /* -+ * ... and grow the mapping back to its -+ * pre-eviction size. -+ */ -+ if (!err) -+ err = kbase_mem_grow_gpu_mapping(kctx, -+ gpu_alloc->reg, -+ gpu_alloc->evicted, 0); -+ -+ gpu_alloc->evicted = 0; -+ } -+ } -+ -+ /* If the region is still alive remove the DONT_NEED attribute. */ -+ if (gpu_alloc->reg) -+ gpu_alloc->reg->flags &= ~KBASE_REG_DONT_NEED; -+ -+ return (err == 0); -+} -+ -+int kbase_mem_flags_change(struct kbase_context *kctx, u64 gpu_addr, unsigned int flags, unsigned int mask) -+{ -+ struct kbase_va_region *reg; -+ int ret = -EINVAL; -+ unsigned int real_flags = 0; -+ unsigned int prev_flags = 0; -+ bool prev_needed, new_needed; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+ if (!gpu_addr) -+ return -EINVAL; -+ -+ if ((gpu_addr & ~PAGE_MASK) && (gpu_addr >= PAGE_SIZE)) -+ return -EINVAL; -+ -+ /* nuke other bits */ -+ flags &= mask; -+ -+ /* check for only supported flags */ -+ if (flags & ~(BASE_MEM_FLAGS_MODIFIABLE)) -+ goto out; -+ -+ /* mask covers bits we don't support? */ -+ if (mask & ~(BASE_MEM_FLAGS_MODIFIABLE)) -+ goto out; -+ -+ /* convert flags */ -+ if (BASE_MEM_COHERENT_SYSTEM & flags) -+ real_flags |= KBASE_REG_SHARE_BOTH; -+ else if (BASE_MEM_COHERENT_LOCAL & flags) -+ real_flags |= KBASE_REG_SHARE_IN; -+ -+ /* now we can lock down the context, and find the region */ -+ down_write(¤t->mm->mmap_sem); -+ kbase_gpu_vm_lock(kctx); -+ -+ /* Validate the region */ -+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr); -+ if (!reg || (reg->flags & KBASE_REG_FREE)) -+ goto out_unlock; -+ -+ /* Is the region being transitioning between not needed and needed? */ -+ prev_needed = (KBASE_REG_DONT_NEED & reg->flags) == KBASE_REG_DONT_NEED; -+ new_needed = (BASE_MEM_DONT_NEED & flags) == BASE_MEM_DONT_NEED; -+ if (prev_needed != new_needed) { -+ /* Aliased allocations can't be made ephemeral */ -+ if (atomic_read(®->cpu_alloc->gpu_mappings) > 1) -+ goto out_unlock; -+ -+ if (new_needed) { -+ /* Only native allocations can be marked not needed */ -+ if (reg->cpu_alloc->type != KBASE_MEM_TYPE_NATIVE) { -+ ret = -EINVAL; -+ goto out_unlock; -+ } -+ ret = kbase_mem_evictable_make(reg->gpu_alloc); -+ if (ret) -+ goto out_unlock; -+ } else { -+ kbase_mem_evictable_unmake(reg->gpu_alloc); -+ } -+ } -+ -+ /* limit to imported memory */ -+ if ((reg->gpu_alloc->type != KBASE_MEM_TYPE_IMPORTED_UMP) && -+ (reg->gpu_alloc->type != KBASE_MEM_TYPE_IMPORTED_UMM)) -+ goto out_unlock; -+ -+ /* no change? */ -+ if (real_flags == (reg->flags & (KBASE_REG_SHARE_IN | KBASE_REG_SHARE_BOTH))) { -+ ret = 0; -+ goto out_unlock; -+ } -+ -+ /* save for roll back */ -+ prev_flags = reg->flags; -+ reg->flags &= ~(KBASE_REG_SHARE_IN | KBASE_REG_SHARE_BOTH); -+ reg->flags |= real_flags; -+ -+ /* Currently supporting only imported memory */ -+ switch (reg->gpu_alloc->type) { -+#ifdef CONFIG_UMP -+ case KBASE_MEM_TYPE_IMPORTED_UMP: -+ ret = kbase_mmu_update_pages(kctx, reg->start_pfn, kbase_get_cpu_phy_pages(reg), reg->gpu_alloc->nents, reg->flags); -+ break; -+#endif -+#ifdef CONFIG_DMA_SHARED_BUFFER -+ case KBASE_MEM_TYPE_IMPORTED_UMM: -+ /* Future use will use the new flags, existing mapping will NOT be updated -+ * as memory should not be in use by the GPU when updating the flags. -+ */ -+ ret = 0; -+ WARN_ON(reg->gpu_alloc->imported.umm.current_mapping_usage_count); -+ break; -+#endif -+ default: -+ break; -+ } -+ -+ /* roll back on error, i.e. not UMP */ -+ if (ret) -+ reg->flags = prev_flags; -+ -+out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ up_write(¤t->mm->mmap_sem); -+out: -+ return ret; -+} -+ -+#define KBASE_MEM_IMPORT_HAVE_PAGES (1UL << BASE_MEM_FLAGS_NR_BITS) -+ -+#ifdef CONFIG_UMP -+static struct kbase_va_region *kbase_mem_from_ump(struct kbase_context *kctx, ump_secure_id id, u64 *va_pages, u64 *flags) -+{ -+ struct kbase_va_region *reg; -+ ump_dd_handle umph; -+ u64 block_count; -+ const ump_dd_physical_block_64 *block_array; -+ u64 i, j; -+ int page = 0; -+ ump_alloc_flags ump_flags; -+ ump_alloc_flags cpu_flags; -+ ump_alloc_flags gpu_flags; -+ -+ if (*flags & BASE_MEM_SECURE) -+ goto bad_flags; -+ -+ umph = ump_dd_from_secure_id(id); -+ if (UMP_DD_INVALID_MEMORY_HANDLE == umph) -+ goto bad_id; -+ -+ ump_flags = ump_dd_allocation_flags_get(umph); -+ cpu_flags = (ump_flags >> UMP_DEVICE_CPU_SHIFT) & UMP_DEVICE_MASK; -+ gpu_flags = (ump_flags >> DEFAULT_UMP_GPU_DEVICE_SHIFT) & -+ UMP_DEVICE_MASK; -+ -+ *va_pages = ump_dd_size_get_64(umph); -+ *va_pages >>= PAGE_SHIFT; -+ -+ if (!*va_pages) -+ goto bad_size; -+ -+ if (*va_pages > (U64_MAX / PAGE_SIZE)) -+ /* 64-bit address range is the max */ -+ goto bad_size; -+ -+ if (*flags & BASE_MEM_SAME_VA) -+ reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_SAME_VA); -+ else -+ reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_CUSTOM_VA); -+ -+ if (!reg) -+ goto no_region; -+ -+ /* we've got pages to map now, and support SAME_VA */ -+ *flags |= KBASE_MEM_IMPORT_HAVE_PAGES; -+ -+ reg->gpu_alloc = kbase_alloc_create(*va_pages, KBASE_MEM_TYPE_IMPORTED_UMP); -+ if (IS_ERR_OR_NULL(reg->gpu_alloc)) -+ goto no_alloc_obj; -+ -+ reg->cpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); -+ -+ reg->gpu_alloc->imported.ump_handle = umph; -+ -+ reg->flags &= ~KBASE_REG_FREE; -+ reg->flags |= KBASE_REG_GPU_NX; /* UMP is always No eXecute */ -+ reg->flags &= ~KBASE_REG_GROWABLE; /* UMP cannot be grown */ -+ -+ /* Override import flags based on UMP flags */ -+ *flags &= ~(BASE_MEM_CACHED_CPU); -+ *flags &= ~(BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_CPU_WR); -+ *flags &= ~(BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR); -+ -+ if ((cpu_flags & (UMP_HINT_DEVICE_RD | UMP_HINT_DEVICE_WR)) == -+ (UMP_HINT_DEVICE_RD | UMP_HINT_DEVICE_WR)) { -+ reg->flags |= KBASE_REG_CPU_CACHED; -+ *flags |= BASE_MEM_CACHED_CPU; -+ } -+ -+ if (cpu_flags & UMP_PROT_CPU_WR) { -+ reg->flags |= KBASE_REG_CPU_WR; -+ *flags |= BASE_MEM_PROT_CPU_WR; -+ } -+ -+ if (cpu_flags & UMP_PROT_CPU_RD) { -+ reg->flags |= KBASE_REG_CPU_RD; -+ *flags |= BASE_MEM_PROT_CPU_RD; -+ } -+ -+ if ((gpu_flags & (UMP_HINT_DEVICE_RD | UMP_HINT_DEVICE_WR)) == -+ (UMP_HINT_DEVICE_RD | UMP_HINT_DEVICE_WR)) -+ reg->flags |= KBASE_REG_GPU_CACHED; -+ -+ if (gpu_flags & UMP_PROT_DEVICE_WR) { -+ reg->flags |= KBASE_REG_GPU_WR; -+ *flags |= BASE_MEM_PROT_GPU_WR; -+ } -+ -+ if (gpu_flags & UMP_PROT_DEVICE_RD) { -+ reg->flags |= KBASE_REG_GPU_RD; -+ *flags |= BASE_MEM_PROT_GPU_RD; -+ } -+ -+ /* ump phys block query */ -+ ump_dd_phys_blocks_get_64(umph, &block_count, &block_array); -+ -+ for (i = 0; i < block_count; i++) { -+ for (j = 0; j < (block_array[i].size >> PAGE_SHIFT); j++) { -+ struct tagged_addr tagged; -+ -+ tagged = as_tagged(block_array[i].addr + -+ (j << PAGE_SHIFT)); -+ reg->gpu_alloc->pages[page] = tagged; -+ page++; -+ } -+ } -+ reg->gpu_alloc->nents = *va_pages; -+ reg->extent = 0; -+ -+ return reg; -+ -+no_alloc_obj: -+ kfree(reg); -+no_region: -+bad_size: -+ ump_dd_release(umph); -+bad_id: -+bad_flags: -+ return NULL; -+} -+#endif /* CONFIG_UMP */ -+ -+#ifdef CONFIG_DMA_SHARED_BUFFER -+static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, -+ int fd, u64 *va_pages, u64 *flags, u32 padding) -+{ -+ struct kbase_va_region *reg; -+ struct dma_buf *dma_buf; -+ struct dma_buf_attachment *dma_attachment; -+ bool shared_zone = false; -+ -+ dma_buf = dma_buf_get(fd); -+ if (IS_ERR_OR_NULL(dma_buf)) -+ goto no_buf; -+ -+ dma_attachment = dma_buf_attach(dma_buf, kctx->kbdev->dev); -+ if (!dma_attachment) -+ goto no_attachment; -+ -+ *va_pages = (PAGE_ALIGN(dma_buf->size) >> PAGE_SHIFT) + padding; -+ if (!*va_pages) -+ goto bad_size; -+ -+ if (*va_pages > (U64_MAX / PAGE_SIZE)) -+ /* 64-bit address range is the max */ -+ goto bad_size; -+ -+ /* ignore SAME_VA */ -+ *flags &= ~BASE_MEM_SAME_VA; -+ -+ if (*flags & BASE_MEM_IMPORT_SHARED) -+ shared_zone = true; -+ -+#ifdef CONFIG_64BIT -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+ /* -+ * 64-bit tasks require us to reserve VA on the CPU that we use -+ * on the GPU. -+ */ -+ shared_zone = true; -+ } -+#endif -+ -+ if (shared_zone) { -+ *flags |= BASE_MEM_NEED_MMAP; -+ reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_SAME_VA); -+ } else { -+ reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_CUSTOM_VA); -+ } -+ -+ if (!reg) -+ goto no_region; -+ -+ reg->gpu_alloc = kbase_alloc_create(*va_pages, KBASE_MEM_TYPE_IMPORTED_UMM); -+ if (IS_ERR_OR_NULL(reg->gpu_alloc)) -+ goto no_alloc_obj; -+ -+ reg->cpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); -+ -+ /* No pages to map yet */ -+ reg->gpu_alloc->nents = 0; -+ -+ if (kbase_update_region_flags(kctx, reg, *flags) != 0) -+ goto invalid_flags; -+ -+ reg->flags &= ~KBASE_REG_FREE; -+ reg->flags |= KBASE_REG_GPU_NX; /* UMM is always No eXecute */ -+ reg->flags &= ~KBASE_REG_GROWABLE; /* UMM cannot be grown */ -+ reg->flags |= KBASE_REG_GPU_CACHED; -+ -+ if (*flags & BASE_MEM_SECURE) -+ reg->flags |= KBASE_REG_SECURE; -+ -+ if (padding) -+ reg->flags |= KBASE_REG_IMPORT_PAD; -+ -+ reg->gpu_alloc->type = KBASE_MEM_TYPE_IMPORTED_UMM; -+ reg->gpu_alloc->imported.umm.sgt = NULL; -+ reg->gpu_alloc->imported.umm.dma_buf = dma_buf; -+ reg->gpu_alloc->imported.umm.dma_attachment = dma_attachment; -+ reg->gpu_alloc->imported.umm.current_mapping_usage_count = 0; -+ reg->extent = 0; -+ -+ return reg; -+ -+invalid_flags: -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+no_alloc_obj: -+ kfree(reg); -+no_region: -+bad_size: -+ dma_buf_detach(dma_buf, dma_attachment); -+no_attachment: -+ dma_buf_put(dma_buf); -+no_buf: -+ return NULL; -+} -+#endif /* CONFIG_DMA_SHARED_BUFFER */ -+ -+static u32 kbase_get_cache_line_alignment(struct kbase_context *kctx) -+{ -+ u32 cpu_cache_line_size = cache_line_size(); -+ u32 gpu_cache_line_size = -+ (1UL << kctx->kbdev->gpu_props.props.l2_props.log2_line_size); -+ -+ return ((cpu_cache_line_size > gpu_cache_line_size) ? -+ cpu_cache_line_size : -+ gpu_cache_line_size); -+} -+ -+static struct kbase_va_region *kbase_mem_from_user_buffer( -+ struct kbase_context *kctx, unsigned long address, -+ unsigned long size, u64 *va_pages, u64 *flags) -+{ -+ long i; -+ struct kbase_va_region *reg; -+ long faulted_pages; -+ int zone = KBASE_REG_ZONE_CUSTOM_VA; -+ bool shared_zone = false; -+ u32 cache_line_alignment = kbase_get_cache_line_alignment(kctx); -+ struct kbase_alloc_import_user_buf *user_buf; -+ struct page **pages = NULL; -+ -+ if ((address & (cache_line_alignment - 1)) != 0 || -+ (size & (cache_line_alignment - 1)) != 0) { -+ /* Coherency must be enabled to handle partial cache lines */ -+ if (*flags & (BASE_MEM_COHERENT_SYSTEM | -+ BASE_MEM_COHERENT_SYSTEM_REQUIRED)) { -+ /* Force coherent system required flag, import will -+ * then fail if coherency isn't available -+ */ -+ *flags |= BASE_MEM_COHERENT_SYSTEM_REQUIRED; -+ } else { -+ dev_warn(kctx->kbdev->dev, -+ "User buffer is not cache line aligned and no coherency enabled\n"); -+ goto bad_size; -+ } -+ } -+ -+ *va_pages = (PAGE_ALIGN(address + size) >> PAGE_SHIFT) - -+ PFN_DOWN(address); -+ if (!*va_pages) -+ goto bad_size; -+ -+ if (*va_pages > (UINT64_MAX / PAGE_SIZE)) -+ /* 64-bit address range is the max */ -+ goto bad_size; -+ -+ /* SAME_VA generally not supported with imported memory (no known use cases) */ -+ *flags &= ~BASE_MEM_SAME_VA; -+ -+ if (*flags & BASE_MEM_IMPORT_SHARED) -+ shared_zone = true; -+ -+#ifdef CONFIG_64BIT -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+ /* -+ * 64-bit tasks require us to reserve VA on the CPU that we use -+ * on the GPU. -+ */ -+ shared_zone = true; -+ } -+#endif -+ -+ if (shared_zone) { -+ *flags |= BASE_MEM_NEED_MMAP; -+ zone = KBASE_REG_ZONE_SAME_VA; -+ } -+ -+ reg = kbase_alloc_free_region(kctx, 0, *va_pages, zone); -+ -+ if (!reg) -+ goto no_region; -+ -+ reg->gpu_alloc = kbase_alloc_create(*va_pages, -+ KBASE_MEM_TYPE_IMPORTED_USER_BUF); -+ if (IS_ERR_OR_NULL(reg->gpu_alloc)) -+ goto no_alloc_obj; -+ -+ reg->cpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); -+ -+ if (kbase_update_region_flags(kctx, reg, *flags) != 0) -+ goto invalid_flags; -+ -+ reg->flags &= ~KBASE_REG_FREE; -+ reg->flags |= KBASE_REG_GPU_NX; /* User-buffers are always No eXecute */ -+ reg->flags &= ~KBASE_REG_GROWABLE; /* Cannot be grown */ -+ -+ user_buf = ®->gpu_alloc->imported.user_buf; -+ -+ user_buf->size = size; -+ user_buf->address = address; -+ user_buf->nr_pages = *va_pages; -+ user_buf->mm = current->mm; -+ user_buf->pages = kmalloc_array(*va_pages, sizeof(struct page *), -+ GFP_KERNEL); -+ -+ if (!user_buf->pages) -+ goto no_page_array; -+ -+ /* If the region is coherent with the CPU then the memory is imported -+ * and mapped onto the GPU immediately. -+ * Otherwise get_user_pages is called as a sanity check, but with -+ * NULL as the pages argument which will fault the pages, but not -+ * pin them. The memory will then be pinned only around the jobs that -+ * specify the region as an external resource. -+ */ -+ if (reg->flags & KBASE_REG_SHARE_BOTH) { -+ pages = user_buf->pages; -+ *flags |= KBASE_MEM_IMPORT_HAVE_PAGES; -+ } -+ -+ down_read(¤t->mm->mmap_sem); -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) -+ faulted_pages = get_user_pages(current, current->mm, address, *va_pages, -+ reg->flags & KBASE_REG_GPU_WR, 0, pages, NULL); -+#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) -+ faulted_pages = get_user_pages(address, *va_pages, -+ reg->flags & KBASE_REG_GPU_WR, 0, pages, NULL); -+#else -+ faulted_pages = get_user_pages(address, *va_pages, -+ reg->flags & KBASE_REG_GPU_WR ? FOLL_WRITE : 0, -+ pages, NULL); -+#endif -+ -+ up_read(¤t->mm->mmap_sem); -+ -+ if (faulted_pages != *va_pages) -+ goto fault_mismatch; -+ -+ atomic_inc(¤t->mm->mm_count); -+ -+ reg->gpu_alloc->nents = 0; -+ reg->extent = 0; -+ -+ if (pages) { -+ struct device *dev = kctx->kbdev->dev; -+ unsigned long local_size = user_buf->size; -+ unsigned long offset = user_buf->address & ~PAGE_MASK; -+ struct tagged_addr *pa = kbase_get_gpu_phy_pages(reg); -+ -+ /* Top bit signifies that this was pinned on import */ -+ user_buf->current_mapping_usage_count |= PINNED_ON_IMPORT; -+ -+ for (i = 0; i < faulted_pages; i++) { -+ dma_addr_t dma_addr; -+ unsigned long min; -+ -+ min = MIN(PAGE_SIZE - offset, local_size); -+ dma_addr = dma_map_page(dev, pages[i], -+ offset, min, -+ DMA_BIDIRECTIONAL); -+ if (dma_mapping_error(dev, dma_addr)) -+ goto unwind_dma_map; -+ -+ user_buf->dma_addrs[i] = dma_addr; -+ pa[i] = as_tagged(page_to_phys(pages[i])); -+ -+ local_size -= min; -+ offset = 0; -+ } -+ -+ reg->gpu_alloc->nents = faulted_pages; -+ } -+ -+ return reg; -+ -+unwind_dma_map: -+ while (i--) { -+ dma_unmap_page(kctx->kbdev->dev, -+ user_buf->dma_addrs[i], -+ PAGE_SIZE, DMA_BIDIRECTIONAL); -+ } -+fault_mismatch: -+ if (pages) { -+ for (i = 0; i < faulted_pages; i++) -+ put_page(pages[i]); -+ } -+ kfree(user_buf->pages); -+no_page_array: -+invalid_flags: -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+no_alloc_obj: -+ kfree(reg); -+no_region: -+bad_size: -+ return NULL; -+ -+} -+ -+ -+u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, -+ u64 nents, struct base_mem_aliasing_info *ai, -+ u64 *num_pages) -+{ -+ struct kbase_va_region *reg; -+ u64 gpu_va; -+ size_t i; -+ bool coherent; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(flags); -+ KBASE_DEBUG_ASSERT(ai); -+ KBASE_DEBUG_ASSERT(num_pages); -+ -+ /* mask to only allowed flags */ -+ *flags &= (BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR | -+ BASE_MEM_COHERENT_SYSTEM | BASE_MEM_COHERENT_LOCAL | -+ BASE_MEM_COHERENT_SYSTEM_REQUIRED); -+ -+ if (!(*flags & (BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR))) { -+ dev_warn(kctx->kbdev->dev, -+ "kbase_mem_alias called with bad flags (%llx)", -+ (unsigned long long)*flags); -+ goto bad_flags; -+ } -+ coherent = (*flags & BASE_MEM_COHERENT_SYSTEM) != 0 || -+ (*flags & BASE_MEM_COHERENT_SYSTEM_REQUIRED) != 0; -+ -+ if (!stride) -+ goto bad_stride; -+ -+ if (!nents) -+ goto bad_nents; -+ -+ if ((nents * stride) > (U64_MAX / PAGE_SIZE)) -+ /* 64-bit address range is the max */ -+ goto bad_size; -+ -+ /* calculate the number of pages this alias will cover */ -+ *num_pages = nents * stride; -+ -+#ifdef CONFIG_64BIT -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+ /* 64-bit tasks must MMAP anyway, but not expose this address to -+ * clients */ -+ *flags |= BASE_MEM_NEED_MMAP; -+ reg = kbase_alloc_free_region(kctx, 0, *num_pages, -+ KBASE_REG_ZONE_SAME_VA); -+ } else { -+#else -+ if (1) { -+#endif -+ reg = kbase_alloc_free_region(kctx, 0, *num_pages, -+ KBASE_REG_ZONE_CUSTOM_VA); -+ } -+ -+ if (!reg) -+ goto no_reg; -+ -+ /* zero-sized page array, as we don't need one/can support one */ -+ reg->gpu_alloc = kbase_alloc_create(0, KBASE_MEM_TYPE_ALIAS); -+ if (IS_ERR_OR_NULL(reg->gpu_alloc)) -+ goto no_alloc_obj; -+ -+ reg->cpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); -+ -+ if (kbase_update_region_flags(kctx, reg, *flags) != 0) -+ goto invalid_flags; -+ -+ reg->gpu_alloc->imported.alias.nents = nents; -+ reg->gpu_alloc->imported.alias.stride = stride; -+ reg->gpu_alloc->imported.alias.aliased = vzalloc(sizeof(*reg->gpu_alloc->imported.alias.aliased) * nents); -+ if (!reg->gpu_alloc->imported.alias.aliased) -+ goto no_aliased_array; -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ /* validate and add src handles */ -+ for (i = 0; i < nents; i++) { -+ if (ai[i].handle.basep.handle < BASE_MEM_FIRST_FREE_ADDRESS) { -+ if (ai[i].handle.basep.handle != -+ BASEP_MEM_WRITE_ALLOC_PAGES_HANDLE) -+ goto bad_handle; /* unsupported magic handle */ -+ if (!ai[i].length) -+ goto bad_handle; /* must be > 0 */ -+ if (ai[i].length > stride) -+ goto bad_handle; /* can't be larger than the -+ stride */ -+ reg->gpu_alloc->imported.alias.aliased[i].length = ai[i].length; -+ } else { -+ struct kbase_va_region *aliasing_reg; -+ struct kbase_mem_phy_alloc *alloc; -+ -+ aliasing_reg = kbase_region_tracker_find_region_base_address( -+ kctx, -+ (ai[i].handle.basep.handle >> PAGE_SHIFT) << PAGE_SHIFT); -+ -+ /* validate found region */ -+ if (!aliasing_reg) -+ goto bad_handle; /* Not found */ -+ if (aliasing_reg->flags & KBASE_REG_FREE) -+ goto bad_handle; /* Free region */ -+ if (aliasing_reg->flags & KBASE_REG_DONT_NEED) -+ goto bad_handle; /* Ephemeral region */ -+ if (!aliasing_reg->gpu_alloc) -+ goto bad_handle; /* No alloc */ -+ if (aliasing_reg->gpu_alloc->type != KBASE_MEM_TYPE_NATIVE) -+ goto bad_handle; /* Not a native alloc */ -+ if (coherent != ((aliasing_reg->flags & KBASE_REG_SHARE_BOTH) != 0)) -+ goto bad_handle; -+ /* Non-coherent memory cannot alias -+ coherent memory, and vice versa.*/ -+ -+ /* check size against stride */ -+ if (!ai[i].length) -+ goto bad_handle; /* must be > 0 */ -+ if (ai[i].length > stride) -+ goto bad_handle; /* can't be larger than the -+ stride */ -+ -+ alloc = aliasing_reg->gpu_alloc; -+ -+ /* check against the alloc's size */ -+ if (ai[i].offset > alloc->nents) -+ goto bad_handle; /* beyond end */ -+ if (ai[i].offset + ai[i].length > alloc->nents) -+ goto bad_handle; /* beyond end */ -+ -+ reg->gpu_alloc->imported.alias.aliased[i].alloc = kbase_mem_phy_alloc_get(alloc); -+ reg->gpu_alloc->imported.alias.aliased[i].length = ai[i].length; -+ reg->gpu_alloc->imported.alias.aliased[i].offset = ai[i].offset; -+ } -+ } -+ -+#ifdef CONFIG_64BIT -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) { -+ /* Bind to a cookie */ -+ if (!kctx->cookies) { -+ dev_err(kctx->kbdev->dev, "No cookies available for allocation!"); -+ goto no_cookie; -+ } -+ /* return a cookie */ -+ gpu_va = __ffs(kctx->cookies); -+ kctx->cookies &= ~(1UL << gpu_va); -+ BUG_ON(kctx->pending_regions[gpu_va]); -+ kctx->pending_regions[gpu_va] = reg; -+ -+ /* relocate to correct base */ -+ gpu_va += PFN_DOWN(BASE_MEM_COOKIE_BASE); -+ gpu_va <<= PAGE_SHIFT; -+ } else /* we control the VA */ { -+#else -+ if (1) { -+#endif -+ if (kbase_gpu_mmap(kctx, reg, 0, *num_pages, 1) != 0) { -+ dev_warn(kctx->kbdev->dev, "Failed to map memory on GPU"); -+ goto no_mmap; -+ } -+ /* return real GPU VA */ -+ gpu_va = reg->start_pfn << PAGE_SHIFT; -+ } -+ -+ reg->flags &= ~KBASE_REG_FREE; -+ reg->flags &= ~KBASE_REG_GROWABLE; -+ -+ kbase_gpu_vm_unlock(kctx); -+ -+ return gpu_va; -+ -+#ifdef CONFIG_64BIT -+no_cookie: -+#endif -+no_mmap: -+bad_handle: -+ kbase_gpu_vm_unlock(kctx); -+no_aliased_array: -+invalid_flags: -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+no_alloc_obj: -+ kfree(reg); -+no_reg: -+bad_size: -+bad_nents: -+bad_stride: -+bad_flags: -+ return 0; -+} -+ -+int kbase_mem_import(struct kbase_context *kctx, enum base_mem_import_type type, -+ void __user *phandle, u32 padding, u64 *gpu_va, u64 *va_pages, -+ u64 *flags) -+{ -+ struct kbase_va_region *reg; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(gpu_va); -+ KBASE_DEBUG_ASSERT(va_pages); -+ KBASE_DEBUG_ASSERT(flags); -+ -+#ifdef CONFIG_64BIT -+ if (!kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ *flags |= BASE_MEM_SAME_VA; -+#endif -+ -+ if (!kbase_check_import_flags(*flags)) { -+ dev_warn(kctx->kbdev->dev, -+ "kbase_mem_import called with bad flags (%llx)", -+ (unsigned long long)*flags); -+ goto bad_flags; -+ } -+ -+ if ((*flags & BASE_MEM_COHERENT_SYSTEM_REQUIRED) != 0 && -+ !kbase_device_is_cpu_coherent(kctx->kbdev)) { -+ dev_warn(kctx->kbdev->dev, -+ "kbase_mem_import call required coherent mem when unavailable"); -+ goto bad_flags; -+ } -+ if ((*flags & BASE_MEM_COHERENT_SYSTEM) != 0 && -+ !kbase_device_is_cpu_coherent(kctx->kbdev)) { -+ /* Remove COHERENT_SYSTEM flag if coherent mem is unavailable */ -+ *flags &= ~BASE_MEM_COHERENT_SYSTEM; -+ } -+ -+ if ((padding != 0) && (type != BASE_MEM_IMPORT_TYPE_UMM)) { -+ dev_warn(kctx->kbdev->dev, -+ "padding is only supported for UMM"); -+ goto bad_flags; -+ } -+ -+ switch (type) { -+#ifdef CONFIG_UMP -+ case BASE_MEM_IMPORT_TYPE_UMP: { -+ ump_secure_id id; -+ -+ if (get_user(id, (ump_secure_id __user *)phandle)) -+ reg = NULL; -+ else -+ reg = kbase_mem_from_ump(kctx, id, va_pages, flags); -+ } -+ break; -+#endif /* CONFIG_UMP */ -+#ifdef CONFIG_DMA_SHARED_BUFFER -+ case BASE_MEM_IMPORT_TYPE_UMM: { -+ int fd; -+ -+ if (get_user(fd, (int __user *)phandle)) -+ reg = NULL; -+ else -+ reg = kbase_mem_from_umm(kctx, fd, va_pages, flags, -+ padding); -+ } -+ break; -+#endif /* CONFIG_DMA_SHARED_BUFFER */ -+ case BASE_MEM_IMPORT_TYPE_USER_BUFFER: { -+ struct base_mem_import_user_buffer user_buffer; -+ void __user *uptr; -+ -+ if (copy_from_user(&user_buffer, phandle, -+ sizeof(user_buffer))) { -+ reg = NULL; -+ } else { -+#ifdef CONFIG_COMPAT -+ if (kbase_ctx_flag(kctx, KCTX_COMPAT)) -+ uptr = compat_ptr(user_buffer.ptr); -+ else -+#endif -+ uptr = u64_to_user_ptr(user_buffer.ptr); -+ -+ reg = kbase_mem_from_user_buffer(kctx, -+ (unsigned long)uptr, user_buffer.length, -+ va_pages, flags); -+ } -+ break; -+ } -+ default: { -+ reg = NULL; -+ break; -+ } -+ } -+ -+ if (!reg) -+ goto no_reg; -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ /* mmap needed to setup VA? */ -+ if (*flags & (BASE_MEM_SAME_VA | BASE_MEM_NEED_MMAP)) { -+ /* Bind to a cookie */ -+ if (!kctx->cookies) -+ goto no_cookie; -+ /* return a cookie */ -+ *gpu_va = __ffs(kctx->cookies); -+ kctx->cookies &= ~(1UL << *gpu_va); -+ BUG_ON(kctx->pending_regions[*gpu_va]); -+ kctx->pending_regions[*gpu_va] = reg; -+ -+ /* relocate to correct base */ -+ *gpu_va += PFN_DOWN(BASE_MEM_COOKIE_BASE); -+ *gpu_va <<= PAGE_SHIFT; -+ -+ } else if (*flags & KBASE_MEM_IMPORT_HAVE_PAGES) { -+ /* we control the VA, mmap now to the GPU */ -+ if (kbase_gpu_mmap(kctx, reg, 0, *va_pages, 1) != 0) -+ goto no_gpu_va; -+ /* return real GPU VA */ -+ *gpu_va = reg->start_pfn << PAGE_SHIFT; -+ } else { -+ /* we control the VA, but nothing to mmap yet */ -+ if (kbase_add_va_region(kctx, reg, 0, *va_pages, 1) != 0) -+ goto no_gpu_va; -+ /* return real GPU VA */ -+ *gpu_va = reg->start_pfn << PAGE_SHIFT; -+ } -+ -+ /* clear out private flags */ -+ *flags &= ((1UL << BASE_MEM_FLAGS_NR_BITS) - 1); -+ -+ kbase_gpu_vm_unlock(kctx); -+ -+ return 0; -+ -+no_gpu_va: -+no_cookie: -+ kbase_gpu_vm_unlock(kctx); -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+ kfree(reg); -+no_reg: -+bad_flags: -+ *gpu_va = 0; -+ *va_pages = 0; -+ *flags = 0; -+ return -ENOMEM; -+} -+ -+int kbase_mem_grow_gpu_mapping(struct kbase_context *kctx, -+ struct kbase_va_region *reg, -+ u64 new_pages, u64 old_pages) -+{ -+ struct tagged_addr *phy_pages; -+ u64 delta = new_pages - old_pages; -+ int ret = 0; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ /* Map the new pages into the GPU */ -+ phy_pages = kbase_get_gpu_phy_pages(reg); -+ ret = kbase_mmu_insert_pages(kctx, reg->start_pfn + old_pages, -+ phy_pages + old_pages, delta, reg->flags); -+ -+ return ret; -+} -+ -+static void kbase_mem_shrink_cpu_mapping(struct kbase_context *kctx, -+ struct kbase_va_region *reg, -+ u64 new_pages, u64 old_pages) -+{ -+ u64 gpu_va_start = reg->start_pfn; -+ -+ if (new_pages == old_pages) -+ /* Nothing to do */ -+ return; -+ -+ unmap_mapping_range(kctx->filp->f_inode->i_mapping, -+ (gpu_va_start + new_pages)<start_pfn + new_pages, delta); -+ -+ return ret; -+} -+ -+int kbase_mem_commit(struct kbase_context *kctx, u64 gpu_addr, u64 new_pages) -+{ -+ u64 old_pages; -+ u64 delta; -+ int res = -EINVAL; -+ struct kbase_va_region *reg; -+ bool read_locked = false; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(gpu_addr != 0); -+ -+ if (gpu_addr & ~PAGE_MASK) { -+ dev_warn(kctx->kbdev->dev, "kbase:mem_commit: gpu_addr: passed parameter is invalid"); -+ return -EINVAL; -+ } -+ -+ down_write(¤t->mm->mmap_sem); -+ kbase_gpu_vm_lock(kctx); -+ -+ /* Validate the region */ -+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr); -+ if (!reg || (reg->flags & KBASE_REG_FREE)) -+ goto out_unlock; -+ -+ KBASE_DEBUG_ASSERT(reg->cpu_alloc); -+ KBASE_DEBUG_ASSERT(reg->gpu_alloc); -+ -+ if (reg->gpu_alloc->type != KBASE_MEM_TYPE_NATIVE) -+ goto out_unlock; -+ -+ if (0 == (reg->flags & KBASE_REG_GROWABLE)) -+ goto out_unlock; -+ -+ /* Would overflow the VA region */ -+ if (new_pages > reg->nr_pages) -+ goto out_unlock; -+ -+ /* can't be mapped more than once on the GPU */ -+ if (atomic_read(®->gpu_alloc->gpu_mappings) > 1) -+ goto out_unlock; -+ /* can't grow regions which are ephemeral */ -+ if (reg->flags & KBASE_REG_DONT_NEED) -+ goto out_unlock; -+ -+ if (new_pages == reg->gpu_alloc->nents) { -+ /* no change */ -+ res = 0; -+ goto out_unlock; -+ } -+ -+ old_pages = kbase_reg_current_backed_size(reg); -+ if (new_pages > old_pages) { -+ delta = new_pages - old_pages; -+ -+ /* -+ * No update to the mm so downgrade the writer lock to a read -+ * lock so other readers aren't blocked after this point. -+ */ -+ downgrade_write(¤t->mm->mmap_sem); -+ read_locked = true; -+ -+ /* Allocate some more pages */ -+ if (kbase_alloc_phy_pages_helper(reg->cpu_alloc, delta) != 0) { -+ res = -ENOMEM; -+ goto out_unlock; -+ } -+ if (reg->cpu_alloc != reg->gpu_alloc) { -+ if (kbase_alloc_phy_pages_helper( -+ reg->gpu_alloc, delta) != 0) { -+ res = -ENOMEM; -+ kbase_free_phy_pages_helper(reg->cpu_alloc, -+ delta); -+ goto out_unlock; -+ } -+ } -+ -+ /* No update required for CPU mappings, that's done on fault. */ -+ -+ /* Update GPU mapping. */ -+ res = kbase_mem_grow_gpu_mapping(kctx, reg, -+ new_pages, old_pages); -+ -+ /* On error free the new pages */ -+ if (res) { -+ kbase_free_phy_pages_helper(reg->cpu_alloc, delta); -+ if (reg->cpu_alloc != reg->gpu_alloc) -+ kbase_free_phy_pages_helper(reg->gpu_alloc, -+ delta); -+ res = -ENOMEM; -+ goto out_unlock; -+ } -+ } else { -+ delta = old_pages - new_pages; -+ -+ /* Update all CPU mapping(s) */ -+ kbase_mem_shrink_cpu_mapping(kctx, reg, -+ new_pages, old_pages); -+ -+ /* Update the GPU mapping */ -+ res = kbase_mem_shrink_gpu_mapping(kctx, reg, -+ new_pages, old_pages); -+ if (res) { -+ res = -ENOMEM; -+ goto out_unlock; -+ } -+ -+ kbase_free_phy_pages_helper(reg->cpu_alloc, delta); -+ if (reg->cpu_alloc != reg->gpu_alloc) -+ kbase_free_phy_pages_helper(reg->gpu_alloc, delta); -+ } -+ -+out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ if (read_locked) -+ up_read(¤t->mm->mmap_sem); -+ else -+ up_write(¤t->mm->mmap_sem); -+ -+ return res; -+} -+ -+static void kbase_cpu_vm_open(struct vm_area_struct *vma) -+{ -+ struct kbase_cpu_mapping *map = vma->vm_private_data; -+ -+ KBASE_DEBUG_ASSERT(map); -+ KBASE_DEBUG_ASSERT(map->count > 0); -+ /* non-atomic as we're under Linux' mm lock */ -+ map->count++; -+} -+ -+static void kbase_cpu_vm_close(struct vm_area_struct *vma) -+{ -+ struct kbase_cpu_mapping *map = vma->vm_private_data; -+ -+ KBASE_DEBUG_ASSERT(map); -+ KBASE_DEBUG_ASSERT(map->count > 0); -+ -+ /* non-atomic as we're under Linux' mm lock */ -+ if (--map->count) -+ return; -+ -+ KBASE_DEBUG_ASSERT(map->kctx); -+ KBASE_DEBUG_ASSERT(map->alloc); -+ -+ kbase_gpu_vm_lock(map->kctx); -+ -+ if (map->free_on_close) { -+ KBASE_DEBUG_ASSERT((map->region->flags & KBASE_REG_ZONE_MASK) == -+ KBASE_REG_ZONE_SAME_VA); -+ /* Avoid freeing memory on the process death which results in -+ * GPU Page Fault. Memory will be freed in kbase_destroy_context -+ */ -+ if (!(current->flags & PF_EXITING)) -+ kbase_mem_free_region(map->kctx, map->region); -+ } -+ -+ list_del(&map->mappings_list); -+ -+ kbase_gpu_vm_unlock(map->kctx); -+ -+ kbase_mem_phy_alloc_put(map->alloc); -+ kfree(map); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_cpu_vm_close); -+ -+ -+static int kbase_cpu_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -+{ -+ struct kbase_cpu_mapping *map = vma->vm_private_data; -+ pgoff_t rel_pgoff; -+ size_t i; -+ pgoff_t addr; -+ -+ KBASE_DEBUG_ASSERT(map); -+ KBASE_DEBUG_ASSERT(map->count > 0); -+ KBASE_DEBUG_ASSERT(map->kctx); -+ KBASE_DEBUG_ASSERT(map->alloc); -+ -+ rel_pgoff = vmf->pgoff - map->region->start_pfn; -+ -+ kbase_gpu_vm_lock(map->kctx); -+ if (rel_pgoff >= map->alloc->nents) -+ goto locked_bad_fault; -+ -+ /* Fault on access to DONT_NEED regions */ -+ if (map->alloc->reg && (map->alloc->reg->flags & KBASE_REG_DONT_NEED)) -+ goto locked_bad_fault; -+ -+ /* insert all valid pages from the fault location */ -+ i = rel_pgoff; -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ addr = (pgoff_t)((uintptr_t)vmf->virtual_address >> PAGE_SHIFT); -+#else -+ addr = (pgoff_t)(vmf->address >> PAGE_SHIFT); -+#endif -+ while (i < map->alloc->nents && (addr < vma->vm_end >> PAGE_SHIFT)) { -+ int ret = vm_insert_pfn(vma, addr << PAGE_SHIFT, -+ PFN_DOWN(as_phys_addr_t(map->alloc->pages[i]))); -+ if (ret < 0 && ret != -EBUSY) -+ goto locked_bad_fault; -+ -+ i++; addr++; -+ } -+ -+ kbase_gpu_vm_unlock(map->kctx); -+ /* we resolved it, nothing for VM to do */ -+ return VM_FAULT_NOPAGE; -+ -+locked_bad_fault: -+ kbase_gpu_vm_unlock(map->kctx); -+ return VM_FAULT_SIGBUS; -+} -+ -+const struct vm_operations_struct kbase_vm_ops = { -+ .open = kbase_cpu_vm_open, -+ .close = kbase_cpu_vm_close, -+ .fault = kbase_cpu_vm_fault -+}; -+ -+static int kbase_cpu_mmap(struct kbase_va_region *reg, struct vm_area_struct *vma, void *kaddr, size_t nr_pages, unsigned long aligned_offset, int free_on_close) -+{ -+ struct kbase_cpu_mapping *map; -+ struct tagged_addr *page_array; -+ int err = 0; -+ int i; -+ -+ map = kzalloc(sizeof(*map), GFP_KERNEL); -+ -+ if (!map) { -+ WARN_ON(1); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ /* -+ * VM_DONTCOPY - don't make this mapping available in fork'ed processes -+ * VM_DONTEXPAND - disable mremap on this region -+ * VM_IO - disables paging -+ * VM_DONTDUMP - Don't include in core dumps (3.7 only) -+ * VM_MIXEDMAP - Support mixing struct page*s and raw pfns. -+ * This is needed to support using the dedicated and -+ * the OS based memory backends together. -+ */ -+ /* -+ * This will need updating to propagate coherency flags -+ * See MIDBASE-1057 -+ */ -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -+ vma->vm_flags |= VM_DONTCOPY | VM_DONTDUMP | VM_DONTEXPAND | VM_IO; -+#else -+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_IO; -+#endif -+ vma->vm_ops = &kbase_vm_ops; -+ vma->vm_private_data = map; -+ -+ page_array = kbase_get_cpu_phy_pages(reg); -+ -+ if (!(reg->flags & KBASE_REG_CPU_CACHED) && -+ (reg->flags & (KBASE_REG_CPU_WR|KBASE_REG_CPU_RD))) { -+ /* We can't map vmalloc'd memory uncached. -+ * Other memory will have been returned from -+ * kbase_mem_pool which would be -+ * suitable for mapping uncached. -+ */ -+ BUG_ON(kaddr); -+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); -+ } -+ -+ if (!kaddr) { -+ unsigned long addr = vma->vm_start + aligned_offset; -+ u64 start_off = vma->vm_pgoff - reg->start_pfn + -+ (aligned_offset>>PAGE_SHIFT); -+ -+ vma->vm_flags |= VM_PFNMAP; -+ for (i = 0; i < nr_pages; i++) { -+ phys_addr_t phys; -+ -+ phys = as_phys_addr_t(page_array[i + start_off]); -+ err = vm_insert_pfn(vma, addr, PFN_DOWN(phys)); -+ if (WARN_ON(err)) -+ break; -+ -+ addr += PAGE_SIZE; -+ } -+ } else { -+ WARN_ON(aligned_offset); -+ /* MIXEDMAP so we can vfree the kaddr early and not track it after map time */ -+ vma->vm_flags |= VM_MIXEDMAP; -+ /* vmalloc remaping is easy... */ -+ err = remap_vmalloc_range(vma, kaddr, 0); -+ WARN_ON(err); -+ } -+ -+ if (err) { -+ kfree(map); -+ goto out; -+ } -+ -+ map->region = reg; -+ map->free_on_close = free_on_close; -+ map->kctx = reg->kctx; -+ map->alloc = kbase_mem_phy_alloc_get(reg->cpu_alloc); -+ map->count = 1; /* start with one ref */ -+ -+ if (reg->flags & KBASE_REG_CPU_CACHED) -+ map->alloc->properties |= KBASE_MEM_PHY_ALLOC_ACCESSED_CACHED; -+ -+ list_add(&map->mappings_list, &map->alloc->mappings); -+ -+ out: -+ return err; -+} -+ -+static int kbase_trace_buffer_mmap(struct kbase_context *kctx, struct vm_area_struct *vma, struct kbase_va_region **const reg, void **const kaddr) -+{ -+ struct kbase_va_region *new_reg; -+ u32 nr_pages; -+ size_t size; -+ int err = 0; -+ u32 *tb; -+ int owns_tb = 1; -+ -+ dev_dbg(kctx->kbdev->dev, "in %s\n", __func__); -+ size = (vma->vm_end - vma->vm_start); -+ nr_pages = size >> PAGE_SHIFT; -+ -+ if (!kctx->jctx.tb) { -+ KBASE_DEBUG_ASSERT(0 != size); -+ tb = vmalloc_user(size); -+ -+ if (NULL == tb) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ err = kbase_device_trace_buffer_install(kctx, tb, size); -+ if (err) { -+ vfree(tb); -+ goto out; -+ } -+ } else { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ *kaddr = kctx->jctx.tb; -+ -+ new_reg = kbase_alloc_free_region(kctx, 0, nr_pages, KBASE_REG_ZONE_SAME_VA); -+ if (!new_reg) { -+ err = -ENOMEM; -+ WARN_ON(1); -+ goto out_no_region; -+ } -+ -+ new_reg->cpu_alloc = kbase_alloc_create(0, KBASE_MEM_TYPE_TB); -+ if (IS_ERR_OR_NULL(new_reg->cpu_alloc)) { -+ err = -ENOMEM; -+ new_reg->cpu_alloc = NULL; -+ WARN_ON(1); -+ goto out_no_alloc; -+ } -+ -+ new_reg->gpu_alloc = kbase_mem_phy_alloc_get(new_reg->cpu_alloc); -+ -+ new_reg->cpu_alloc->imported.kctx = kctx; -+ new_reg->flags &= ~KBASE_REG_FREE; -+ new_reg->flags |= KBASE_REG_CPU_CACHED; -+ -+ /* alloc now owns the tb */ -+ owns_tb = 0; -+ -+ if (kbase_add_va_region(kctx, new_reg, vma->vm_start, nr_pages, 1) != 0) { -+ err = -ENOMEM; -+ WARN_ON(1); -+ goto out_no_va_region; -+ } -+ -+ *reg = new_reg; -+ -+ /* map read only, noexec */ -+ vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE | VM_EXEC | VM_MAYEXEC); -+ /* the rest of the flags is added by the cpu_mmap handler */ -+ -+ dev_dbg(kctx->kbdev->dev, "%s done\n", __func__); -+ return 0; -+ -+out_no_va_region: -+out_no_alloc: -+ kbase_free_alloced_region(new_reg); -+out_no_region: -+ if (owns_tb) { -+ kbase_device_trace_buffer_uninstall(kctx); -+ vfree(tb); -+ } -+out: -+ return err; -+} -+ -+static int kbase_mmu_dump_mmap(struct kbase_context *kctx, struct vm_area_struct *vma, struct kbase_va_region **const reg, void **const kmap_addr) -+{ -+ struct kbase_va_region *new_reg; -+ void *kaddr; -+ u32 nr_pages; -+ size_t size; -+ int err = 0; -+ -+ dev_dbg(kctx->kbdev->dev, "in kbase_mmu_dump_mmap\n"); -+ size = (vma->vm_end - vma->vm_start); -+ nr_pages = size >> PAGE_SHIFT; -+ -+ kaddr = kbase_mmu_dump(kctx, nr_pages); -+ -+ if (!kaddr) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ new_reg = kbase_alloc_free_region(kctx, 0, nr_pages, KBASE_REG_ZONE_SAME_VA); -+ if (!new_reg) { -+ err = -ENOMEM; -+ WARN_ON(1); -+ goto out; -+ } -+ -+ new_reg->cpu_alloc = kbase_alloc_create(0, KBASE_MEM_TYPE_RAW); -+ if (IS_ERR_OR_NULL(new_reg->cpu_alloc)) { -+ err = -ENOMEM; -+ new_reg->cpu_alloc = NULL; -+ WARN_ON(1); -+ goto out_no_alloc; -+ } -+ -+ new_reg->gpu_alloc = kbase_mem_phy_alloc_get(new_reg->cpu_alloc); -+ -+ new_reg->flags &= ~KBASE_REG_FREE; -+ new_reg->flags |= KBASE_REG_CPU_CACHED; -+ if (kbase_add_va_region(kctx, new_reg, vma->vm_start, nr_pages, 1) != 0) { -+ err = -ENOMEM; -+ WARN_ON(1); -+ goto out_va_region; -+ } -+ -+ *kmap_addr = kaddr; -+ *reg = new_reg; -+ -+ dev_dbg(kctx->kbdev->dev, "kbase_mmu_dump_mmap done\n"); -+ return 0; -+ -+out_no_alloc: -+out_va_region: -+ kbase_free_alloced_region(new_reg); -+out: -+ return err; -+} -+ -+ -+void kbase_os_mem_map_lock(struct kbase_context *kctx) -+{ -+ struct mm_struct *mm = current->mm; -+ (void)kctx; -+ down_read(&mm->mmap_sem); -+} -+ -+void kbase_os_mem_map_unlock(struct kbase_context *kctx) -+{ -+ struct mm_struct *mm = current->mm; -+ (void)kctx; -+ up_read(&mm->mmap_sem); -+} -+ -+static int kbasep_reg_mmap(struct kbase_context *kctx, -+ struct vm_area_struct *vma, -+ struct kbase_va_region **regm, -+ size_t *nr_pages, size_t *aligned_offset) -+ -+{ -+ int cookie = vma->vm_pgoff - PFN_DOWN(BASE_MEM_COOKIE_BASE); -+ struct kbase_va_region *reg; -+ int err = 0; -+ -+ *aligned_offset = 0; -+ -+ dev_dbg(kctx->kbdev->dev, "in kbasep_reg_mmap\n"); -+ -+ /* SAME_VA stuff, fetch the right region */ -+ reg = kctx->pending_regions[cookie]; -+ if (!reg) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ if ((reg->flags & KBASE_REG_GPU_NX) && (reg->nr_pages != *nr_pages)) { -+ /* incorrect mmap size */ -+ /* leave the cookie for a potential later -+ * mapping, or to be reclaimed later when the -+ * context is freed */ -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ if ((vma->vm_flags & VM_READ && !(reg->flags & KBASE_REG_CPU_RD)) || -+ (vma->vm_flags & VM_WRITE && !(reg->flags & KBASE_REG_CPU_WR))) { -+ /* VM flags inconsistent with region flags */ -+ err = -EPERM; -+ dev_err(kctx->kbdev->dev, "%s:%d inconsistent VM flags\n", -+ __FILE__, __LINE__); -+ goto out; -+ } -+ -+ /* adjust down nr_pages to what we have physically */ -+ *nr_pages = kbase_reg_current_backed_size(reg); -+ -+ if (kbase_gpu_mmap(kctx, reg, vma->vm_start + *aligned_offset, -+ reg->nr_pages, 1) != 0) { -+ dev_err(kctx->kbdev->dev, "%s:%d\n", __FILE__, __LINE__); -+ /* Unable to map in GPU space. */ -+ WARN_ON(1); -+ err = -ENOMEM; -+ goto out; -+ } -+ /* no need for the cookie anymore */ -+ kctx->pending_regions[cookie] = NULL; -+ kctx->cookies |= (1UL << cookie); -+ -+ /* -+ * Overwrite the offset with the region start_pfn, so we effectively -+ * map from offset 0 in the region. However subtract the aligned -+ * offset so that when user space trims the mapping the beginning of -+ * the trimmed VMA has the correct vm_pgoff; -+ */ -+ vma->vm_pgoff = reg->start_pfn - ((*aligned_offset)>>PAGE_SHIFT); -+out: -+ *regm = reg; -+ dev_dbg(kctx->kbdev->dev, "kbasep_reg_mmap done\n"); -+ -+ return err; -+} -+ -+int kbase_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct kbase_context *kctx = file->private_data; -+ struct kbase_va_region *reg = NULL; -+ void *kaddr = NULL; -+ size_t nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; -+ int err = 0; -+ int free_on_close = 0; -+ struct device *dev = kctx->kbdev->dev; -+ size_t aligned_offset = 0; -+ -+ dev_dbg(dev, "kbase_mmap\n"); -+ -+ /* strip away corresponding VM_MAY% flags to the VM_% flags requested */ -+ vma->vm_flags &= ~((vma->vm_flags & (VM_READ | VM_WRITE)) << 4); -+ -+ if (0 == nr_pages) { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ if (!(vma->vm_flags & VM_SHARED)) { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ if (vma->vm_pgoff == PFN_DOWN(BASE_MEM_MAP_TRACKING_HANDLE)) { -+ /* The non-mapped tracking helper page */ -+ err = kbase_tracking_page_setup(kctx, vma); -+ goto out_unlock; -+ } -+ -+ /* if not the MTP, verify that the MTP has been mapped */ -+ rcu_read_lock(); -+ /* catches both when the special page isn't present or -+ * when we've forked */ -+ if (rcu_dereference(kctx->process_mm) != current->mm) { -+ err = -EINVAL; -+ rcu_read_unlock(); -+ goto out_unlock; -+ } -+ rcu_read_unlock(); -+ -+ switch (vma->vm_pgoff) { -+ case PFN_DOWN(BASEP_MEM_INVALID_HANDLE): -+ case PFN_DOWN(BASEP_MEM_WRITE_ALLOC_PAGES_HANDLE): -+ /* Illegal handle for direct map */ -+ err = -EINVAL; -+ goto out_unlock; -+ case PFN_DOWN(BASE_MEM_TRACE_BUFFER_HANDLE): -+ err = kbase_trace_buffer_mmap(kctx, vma, ®, &kaddr); -+ if (0 != err) -+ goto out_unlock; -+ dev_dbg(dev, "kbase_trace_buffer_mmap ok\n"); -+ /* free the region on munmap */ -+ free_on_close = 1; -+ break; -+ case PFN_DOWN(BASE_MEM_MMU_DUMP_HANDLE): -+ /* MMU dump */ -+ err = kbase_mmu_dump_mmap(kctx, vma, ®, &kaddr); -+ if (0 != err) -+ goto out_unlock; -+ /* free the region on munmap */ -+ free_on_close = 1; -+ break; -+ case PFN_DOWN(BASE_MEM_COOKIE_BASE) ... -+ PFN_DOWN(BASE_MEM_FIRST_FREE_ADDRESS) - 1: { -+ err = kbasep_reg_mmap(kctx, vma, ®, &nr_pages, -+ &aligned_offset); -+ if (0 != err) -+ goto out_unlock; -+ /* free the region on munmap */ -+ free_on_close = 1; -+ break; -+ } -+ default: { -+ reg = kbase_region_tracker_find_region_enclosing_address(kctx, -+ (u64)vma->vm_pgoff << PAGE_SHIFT); -+ -+ if (reg && !(reg->flags & KBASE_REG_FREE)) { -+ /* will this mapping overflow the size of the region? */ -+ if (nr_pages > (reg->nr_pages - -+ (vma->vm_pgoff - reg->start_pfn))) { -+ err = -ENOMEM; -+ goto out_unlock; -+ } -+ -+ if ((vma->vm_flags & VM_READ && -+ !(reg->flags & KBASE_REG_CPU_RD)) || -+ (vma->vm_flags & VM_WRITE && -+ !(reg->flags & KBASE_REG_CPU_WR))) { -+ /* VM flags inconsistent with region flags */ -+ err = -EPERM; -+ dev_err(dev, "%s:%d inconsistent VM flags\n", -+ __FILE__, __LINE__); -+ goto out_unlock; -+ } -+ -+#ifdef CONFIG_DMA_SHARED_BUFFER -+ if (KBASE_MEM_TYPE_IMPORTED_UMM == -+ reg->cpu_alloc->type) { -+ err = dma_buf_mmap( -+ reg->cpu_alloc->imported.umm.dma_buf, -+ vma, vma->vm_pgoff - reg->start_pfn); -+ goto out_unlock; -+ } -+#endif /* CONFIG_DMA_SHARED_BUFFER */ -+ -+ /* limit what we map to the amount currently backed */ -+ if (reg->cpu_alloc->nents < (vma->vm_pgoff - reg->start_pfn + nr_pages)) { -+ if ((vma->vm_pgoff - reg->start_pfn) >= reg->cpu_alloc->nents) -+ nr_pages = 0; -+ else -+ nr_pages = reg->cpu_alloc->nents - (vma->vm_pgoff - reg->start_pfn); -+ } -+ } else { -+ err = -ENOMEM; -+ goto out_unlock; -+ } -+ } /* default */ -+ } /* switch */ -+ -+ err = kbase_cpu_mmap(reg, vma, kaddr, nr_pages, aligned_offset, free_on_close); -+ -+ if (vma->vm_pgoff == PFN_DOWN(BASE_MEM_MMU_DUMP_HANDLE)) { -+ /* MMU dump - userspace should now have a reference on -+ * the pages, so we can now free the kernel mapping */ -+ vfree(kaddr); -+ } -+ -+out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+out: -+ if (err) -+ dev_err(dev, "mmap failed %d\n", err); -+ -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mmap); -+ -+static void kbasep_sync_mem_regions(struct kbase_context *kctx, -+ struct kbase_vmap_struct *map, enum kbase_sync_type dest) -+{ -+ size_t i; -+ off_t const offset = (uintptr_t)map->gpu_addr & ~PAGE_MASK; -+ size_t const page_count = PFN_UP(offset + map->size); -+ -+ /* Sync first page */ -+ size_t sz = MIN(((size_t) PAGE_SIZE - offset), map->size); -+ struct tagged_addr cpu_pa = map->cpu_pages[0]; -+ struct tagged_addr gpu_pa = map->gpu_pages[0]; -+ -+ kbase_sync_single(kctx, cpu_pa, gpu_pa, offset, sz, dest); -+ -+ /* Sync middle pages (if any) */ -+ for (i = 1; page_count > 2 && i < page_count - 1; i++) { -+ cpu_pa = map->cpu_pages[i]; -+ gpu_pa = map->gpu_pages[i]; -+ kbase_sync_single(kctx, cpu_pa, gpu_pa, 0, PAGE_SIZE, dest); -+ } -+ -+ /* Sync last page (if any) */ -+ if (page_count > 1) { -+ cpu_pa = map->cpu_pages[page_count - 1]; -+ gpu_pa = map->gpu_pages[page_count - 1]; -+ sz = ((offset + map->size - 1) & ~PAGE_MASK) + 1; -+ kbase_sync_single(kctx, cpu_pa, gpu_pa, 0, sz, dest); -+ } -+} -+ -+void *kbase_vmap_prot(struct kbase_context *kctx, u64 gpu_addr, size_t size, -+ unsigned long prot_request, struct kbase_vmap_struct *map) -+{ -+ struct kbase_va_region *reg; -+ unsigned long page_index; -+ unsigned int offset = gpu_addr & ~PAGE_MASK; -+ size_t page_count = PFN_UP(offset + size); -+ struct tagged_addr *page_array; -+ struct page **pages; -+ void *cpu_addr = NULL; -+ pgprot_t prot; -+ size_t i; -+ -+ if (!size || !map) -+ return NULL; -+ -+ /* check if page_count calculation will wrap */ -+ if (size > ((size_t)-1 / PAGE_SIZE)) -+ return NULL; -+ -+ kbase_gpu_vm_lock(kctx); -+ -+ reg = kbase_region_tracker_find_region_enclosing_address(kctx, gpu_addr); -+ if (!reg || (reg->flags & KBASE_REG_FREE)) -+ goto out_unlock; -+ -+ page_index = (gpu_addr >> PAGE_SHIFT) - reg->start_pfn; -+ -+ /* check if page_index + page_count will wrap */ -+ if (-1UL - page_count < page_index) -+ goto out_unlock; -+ -+ if (page_index + page_count > kbase_reg_current_backed_size(reg)) -+ goto out_unlock; -+ -+ if (reg->flags & KBASE_REG_DONT_NEED) -+ goto out_unlock; -+ -+ /* check access permissions can be satisfied -+ * Intended only for checking KBASE_REG_{CPU,GPU}_{RD,WR} */ -+ if ((reg->flags & prot_request) != prot_request) -+ goto out_unlock; -+ -+ page_array = kbase_get_cpu_phy_pages(reg); -+ if (!page_array) -+ goto out_unlock; -+ -+ pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL); -+ if (!pages) -+ goto out_unlock; -+ -+ for (i = 0; i < page_count; i++) -+ pages[i] = phys_to_page(as_phys_addr_t(page_array[page_index + -+ i])); -+ -+ prot = PAGE_KERNEL; -+ if (!(reg->flags & KBASE_REG_CPU_CACHED)) { -+ /* Map uncached */ -+ prot = pgprot_writecombine(prot); -+ } -+ /* Note: enforcing a RO prot_request onto prot is not done, since: -+ * - CPU-arch-specific integration required -+ * - kbase_vmap() requires no access checks to be made/enforced */ -+ -+ cpu_addr = vmap(pages, page_count, VM_MAP, prot); -+ -+ kfree(pages); -+ -+ if (!cpu_addr) -+ goto out_unlock; -+ -+ map->gpu_addr = gpu_addr; -+ map->cpu_alloc = kbase_mem_phy_alloc_get(reg->cpu_alloc); -+ map->cpu_pages = &kbase_get_cpu_phy_pages(reg)[page_index]; -+ map->gpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); -+ map->gpu_pages = &kbase_get_gpu_phy_pages(reg)[page_index]; -+ map->addr = (void *)((uintptr_t)cpu_addr + offset); -+ map->size = size; -+ map->sync_needed = ((reg->flags & KBASE_REG_CPU_CACHED) != 0) && -+ !kbase_mem_is_imported(map->gpu_alloc->type); -+ -+ if (map->sync_needed) -+ kbasep_sync_mem_regions(kctx, map, KBASE_SYNC_TO_CPU); -+ kbase_gpu_vm_unlock(kctx); -+ -+ return map->addr; -+ -+out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ return NULL; -+} -+ -+void *kbase_vmap(struct kbase_context *kctx, u64 gpu_addr, size_t size, -+ struct kbase_vmap_struct *map) -+{ -+ /* 0 is specified for prot_request to indicate no access checks should -+ * be made. -+ * -+ * As mentioned in kbase_vmap_prot() this means that a kernel-side -+ * CPU-RO mapping is not enforced to allow this to work */ -+ return kbase_vmap_prot(kctx, gpu_addr, size, 0u, map); -+} -+KBASE_EXPORT_TEST_API(kbase_vmap); -+ -+void kbase_vunmap(struct kbase_context *kctx, struct kbase_vmap_struct *map) -+{ -+ void *addr = (void *)((uintptr_t)map->addr & PAGE_MASK); -+ vunmap(addr); -+ -+ if (map->sync_needed) -+ kbasep_sync_mem_regions(kctx, map, KBASE_SYNC_TO_DEVICE); -+ map->gpu_addr = 0; -+ map->cpu_alloc = kbase_mem_phy_alloc_put(map->cpu_alloc); -+ map->gpu_alloc = kbase_mem_phy_alloc_put(map->gpu_alloc); -+ map->cpu_pages = NULL; -+ map->gpu_pages = NULL; -+ map->addr = NULL; -+ map->size = 0; -+ map->sync_needed = false; -+} -+KBASE_EXPORT_TEST_API(kbase_vunmap); -+ -+void kbasep_os_process_page_usage_update(struct kbase_context *kctx, int pages) -+{ -+ struct mm_struct *mm; -+ -+ rcu_read_lock(); -+ mm = rcu_dereference(kctx->process_mm); -+ if (mm) { -+ atomic_add(pages, &kctx->nonmapped_pages); -+#ifdef SPLIT_RSS_COUNTING -+ add_mm_counter(mm, MM_FILEPAGES, pages); -+#else -+ spin_lock(&mm->page_table_lock); -+ add_mm_counter(mm, MM_FILEPAGES, pages); -+ spin_unlock(&mm->page_table_lock); -+#endif -+ } -+ rcu_read_unlock(); -+} -+ -+static void kbasep_os_process_page_usage_drain(struct kbase_context *kctx) -+{ -+ int pages; -+ struct mm_struct *mm; -+ -+ spin_lock(&kctx->mm_update_lock); -+ mm = rcu_dereference_protected(kctx->process_mm, lockdep_is_held(&kctx->mm_update_lock)); -+ if (!mm) { -+ spin_unlock(&kctx->mm_update_lock); -+ return; -+ } -+ -+ rcu_assign_pointer(kctx->process_mm, NULL); -+ spin_unlock(&kctx->mm_update_lock); -+ synchronize_rcu(); -+ -+ pages = atomic_xchg(&kctx->nonmapped_pages, 0); -+#ifdef SPLIT_RSS_COUNTING -+ add_mm_counter(mm, MM_FILEPAGES, -pages); -+#else -+ spin_lock(&mm->page_table_lock); -+ add_mm_counter(mm, MM_FILEPAGES, -pages); -+ spin_unlock(&mm->page_table_lock); -+#endif -+} -+ -+static void kbase_special_vm_close(struct vm_area_struct *vma) -+{ -+ struct kbase_context *kctx; -+ -+ kctx = vma->vm_private_data; -+ kbasep_os_process_page_usage_drain(kctx); -+} -+ -+static const struct vm_operations_struct kbase_vm_special_ops = { -+ .close = kbase_special_vm_close, -+}; -+ -+static int kbase_tracking_page_setup(struct kbase_context *kctx, struct vm_area_struct *vma) -+{ -+ /* check that this is the only tracking page */ -+ spin_lock(&kctx->mm_update_lock); -+ if (rcu_dereference_protected(kctx->process_mm, lockdep_is_held(&kctx->mm_update_lock))) { -+ spin_unlock(&kctx->mm_update_lock); -+ return -EFAULT; -+ } -+ -+ rcu_assign_pointer(kctx->process_mm, current->mm); -+ -+ spin_unlock(&kctx->mm_update_lock); -+ -+ /* no real access */ -+ vma->vm_flags &= ~(VM_READ | VM_MAYREAD | VM_WRITE | VM_MAYWRITE | VM_EXEC | VM_MAYEXEC); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP | VM_IO; -+#else -+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_IO; -+#endif -+ vma->vm_ops = &kbase_vm_special_ops; -+ vma->vm_private_data = kctx; -+ -+ return 0; -+} -+void *kbase_va_alloc(struct kbase_context *kctx, u32 size, struct kbase_hwc_dma_mapping *handle) -+{ -+ int i; -+ int res; -+ void *va; -+ dma_addr_t dma_pa; -+ struct kbase_va_region *reg; -+ struct tagged_addr *page_array; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) -+ unsigned long attrs = DMA_ATTR_WRITE_COMBINE; -+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+ DEFINE_DMA_ATTRS(attrs); -+#endif -+ -+ u32 pages = ((size - 1) >> PAGE_SHIFT) + 1; -+ u32 flags = BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_CPU_WR | -+ BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR; -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(0 != size); -+ KBASE_DEBUG_ASSERT(0 != pages); -+ -+ if (size == 0) -+ goto err; -+ -+ /* All the alloc calls return zeroed memory */ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) -+ va = dma_alloc_attrs(kctx->kbdev->dev, size, &dma_pa, GFP_KERNEL, -+ attrs); -+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); -+ va = dma_alloc_attrs(kctx->kbdev->dev, size, &dma_pa, GFP_KERNEL, -+ &attrs); -+#else -+ va = dma_alloc_writecombine(kctx->kbdev->dev, size, &dma_pa, GFP_KERNEL); -+#endif -+ if (!va) -+ goto err; -+ -+ /* Store the state so we can free it later. */ -+ handle->cpu_va = va; -+ handle->dma_pa = dma_pa; -+ handle->size = size; -+ -+ -+ reg = kbase_alloc_free_region(kctx, 0, pages, KBASE_REG_ZONE_SAME_VA); -+ if (!reg) -+ goto no_reg; -+ -+ reg->flags &= ~KBASE_REG_FREE; -+ if (kbase_update_region_flags(kctx, reg, flags) != 0) -+ goto invalid_flags; -+ -+ reg->cpu_alloc = kbase_alloc_create(pages, KBASE_MEM_TYPE_RAW); -+ if (IS_ERR_OR_NULL(reg->cpu_alloc)) -+ goto no_alloc; -+ -+ reg->gpu_alloc = kbase_mem_phy_alloc_get(reg->cpu_alloc); -+ -+ page_array = kbase_get_cpu_phy_pages(reg); -+ -+ for (i = 0; i < pages; i++) -+ page_array[i] = as_tagged(dma_pa + (i << PAGE_SHIFT)); -+ -+ reg->cpu_alloc->nents = pages; -+ -+ kbase_gpu_vm_lock(kctx); -+ res = kbase_gpu_mmap(kctx, reg, (uintptr_t) va, pages, 1); -+ kbase_gpu_vm_unlock(kctx); -+ if (res) -+ goto no_mmap; -+ -+ return va; -+ -+no_mmap: -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+no_alloc: -+invalid_flags: -+ kfree(reg); -+no_reg: -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) -+ dma_free_attrs(kctx->kbdev->dev, size, va, dma_pa, attrs); -+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+ dma_free_attrs(kctx->kbdev->dev, size, va, dma_pa, &attrs); -+#else -+ dma_free_writecombine(kctx->kbdev->dev, size, va, dma_pa); -+#endif -+err: -+ return NULL; -+} -+KBASE_EXPORT_SYMBOL(kbase_va_alloc); -+ -+void kbase_va_free(struct kbase_context *kctx, struct kbase_hwc_dma_mapping *handle) -+{ -+ struct kbase_va_region *reg; -+ int err; -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) && \ -+ (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) -+ DEFINE_DMA_ATTRS(attrs); -+#endif -+ -+ KBASE_DEBUG_ASSERT(kctx != NULL); -+ KBASE_DEBUG_ASSERT(handle->cpu_va != NULL); -+ -+ kbase_gpu_vm_lock(kctx); -+ reg = kbase_region_tracker_find_region_base_address(kctx, (uintptr_t)handle->cpu_va); -+ KBASE_DEBUG_ASSERT(reg); -+ err = kbase_gpu_munmap(kctx, reg); -+ kbase_gpu_vm_unlock(kctx); -+ KBASE_DEBUG_ASSERT(!err); -+ -+ kbase_mem_phy_alloc_put(reg->cpu_alloc); -+ kbase_mem_phy_alloc_put(reg->gpu_alloc); -+ kfree(reg); -+ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) -+ dma_free_attrs(kctx->kbdev->dev, handle->size, -+ handle->cpu_va, handle->dma_pa, DMA_ATTR_WRITE_COMBINE); -+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); -+ dma_free_attrs(kctx->kbdev->dev, handle->size, -+ handle->cpu_va, handle->dma_pa, &attrs); -+#else -+ dma_free_writecombine(kctx->kbdev->dev, handle->size, -+ handle->cpu_va, handle->dma_pa); -+#endif -+} -+KBASE_EXPORT_SYMBOL(kbase_va_free); -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_linux.h b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.h -new file mode 100644 -index 0000000..db35f62 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.h -@@ -0,0 +1,240 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010, 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_mem_linux.h -+ * Base kernel memory APIs, Linux implementation. -+ */ -+ -+#ifndef _KBASE_MEM_LINUX_H_ -+#define _KBASE_MEM_LINUX_H_ -+ -+/** A HWC dump mapping */ -+struct kbase_hwc_dma_mapping { -+ void *cpu_va; -+ dma_addr_t dma_pa; -+ size_t size; -+}; -+ -+struct kbase_va_region *kbase_mem_alloc(struct kbase_context *kctx, -+ u64 va_pages, u64 commit_pages, u64 extent, u64 *flags, -+ u64 *gpu_va); -+int kbase_mem_query(struct kbase_context *kctx, u64 gpu_addr, int query, u64 *const pages); -+int kbase_mem_import(struct kbase_context *kctx, enum base_mem_import_type type, -+ void __user *phandle, u32 padding, u64 *gpu_va, u64 *va_pages, -+ u64 *flags); -+u64 kbase_mem_alias(struct kbase_context *kctx, u64 *flags, u64 stride, u64 nents, struct base_mem_aliasing_info *ai, u64 *num_pages); -+int kbase_mem_flags_change(struct kbase_context *kctx, u64 gpu_addr, unsigned int flags, unsigned int mask); -+ -+/** -+ * kbase_mem_commit - Change the physical backing size of a region -+ * -+ * @kctx: The kernel context -+ * @gpu_addr: Handle to the memory region -+ * @new_pages: Number of physical pages to back the region with -+ * -+ * Return: 0 on success or error code -+ */ -+int kbase_mem_commit(struct kbase_context *kctx, u64 gpu_addr, u64 new_pages); -+ -+int kbase_mmap(struct file *file, struct vm_area_struct *vma); -+ -+/** -+ * kbase_mem_evictable_init - Initialize the Ephemeral memory the eviction -+ * mechanism. -+ * @kctx: The kbase context to initialize. -+ * -+ * Return: Zero on success or -errno on failure. -+ */ -+int kbase_mem_evictable_init(struct kbase_context *kctx); -+ -+/** -+ * kbase_mem_evictable_deinit - De-initialize the Ephemeral memory eviction -+ * mechanism. -+ * @kctx: The kbase context to de-initialize. -+ */ -+void kbase_mem_evictable_deinit(struct kbase_context *kctx); -+ -+/** -+ * kbase_mem_grow_gpu_mapping - Grow the GPU mapping of an allocation -+ * @kctx: Context the region belongs to -+ * @reg: The GPU region -+ * @new_pages: The number of pages after the grow -+ * @old_pages: The number of pages before the grow -+ * -+ * Return: 0 on success, -errno on error. -+ * -+ * Expand the GPU mapping to encompass the new psychical pages which have -+ * been added to the allocation. -+ * -+ * Note: Caller must be holding the region lock. -+ */ -+int kbase_mem_grow_gpu_mapping(struct kbase_context *kctx, -+ struct kbase_va_region *reg, -+ u64 new_pages, u64 old_pages); -+ -+/** -+ * kbase_mem_evictable_make - Make a physical allocation eligible for eviction -+ * @gpu_alloc: The physical allocation to make evictable -+ * -+ * Return: 0 on success, -errno on error. -+ * -+ * Take the provided region and make all the physical pages within it -+ * reclaimable by the kernel, updating the per-process VM stats as well. -+ * Remove any CPU mappings (as these can't be removed in the shrinker callback -+ * as mmap_sem might already be taken) but leave the GPU mapping intact as -+ * and until the shrinker reclaims the allocation. -+ * -+ * Note: Must be called with the region lock of the containing context. -+ */ -+int kbase_mem_evictable_make(struct kbase_mem_phy_alloc *gpu_alloc); -+ -+/** -+ * kbase_mem_evictable_unmake - Remove a physical allocations eligibility for -+ * eviction. -+ * @alloc: The physical allocation to remove eviction eligibility from. -+ * -+ * Return: True if the allocation had its backing restored and false if -+ * it hasn't. -+ * -+ * Make the physical pages in the region no longer reclaimable and update the -+ * per-process stats, if the shrinker has already evicted the memory then -+ * re-allocate it if the region is still alive. -+ * -+ * Note: Must be called with the region lock of the containing context. -+ */ -+bool kbase_mem_evictable_unmake(struct kbase_mem_phy_alloc *alloc); -+ -+struct kbase_vmap_struct { -+ u64 gpu_addr; -+ struct kbase_mem_phy_alloc *cpu_alloc; -+ struct kbase_mem_phy_alloc *gpu_alloc; -+ struct tagged_addr *cpu_pages; -+ struct tagged_addr *gpu_pages; -+ void *addr; -+ size_t size; -+ bool sync_needed; -+}; -+ -+ -+/** -+ * kbase_vmap_prot - Map a GPU VA range into the kernel safely, only if the -+ * requested access permissions are supported -+ * @kctx: Context the VA range belongs to -+ * @gpu_addr: Start address of VA range -+ * @size: Size of VA range -+ * @prot_request: Flags indicating how the caller will then access the memory -+ * @map: Structure to be given to kbase_vunmap() on freeing -+ * -+ * Return: Kernel-accessible CPU pointer to the VA range, or NULL on error -+ * -+ * Map a GPU VA Range into the kernel. The VA range must be contained within a -+ * GPU memory region. Appropriate CPU cache-flushing operations are made as -+ * required, dependent on the CPU mapping for the memory region. -+ * -+ * This is safer than using kmap() on the pages directly, -+ * because the pages here are refcounted to prevent freeing (and hence reuse -+ * elsewhere in the system) until an kbase_vunmap() -+ * -+ * The flags in @prot_request should use KBASE_REG_{CPU,GPU}_{RD,WR}, to check -+ * whether the region should allow the intended access, and return an error if -+ * disallowed. This is essential for security of imported memory, particularly -+ * a user buf from SHM mapped into the process as RO. In that case, write -+ * access must be checked if the intention is for kernel to write to the -+ * memory. -+ * -+ * The checks are also there to help catch access errors on memory where -+ * security is not a concern: imported memory that is always RW, and memory -+ * that was allocated and owned by the process attached to @kctx. In this case, -+ * it helps to identify memory that was was mapped with the wrong access type. -+ * -+ * Note: KBASE_REG_GPU_{RD,WR} flags are currently supported for legacy cases -+ * where either the security of memory is solely dependent on those flags, or -+ * when userspace code was expecting only the GPU to access the memory (e.g. HW -+ * workarounds). -+ * -+ * All cache maintenance operations shall be ignored if the -+ * memory region has been imported. -+ * -+ */ -+void *kbase_vmap_prot(struct kbase_context *kctx, u64 gpu_addr, size_t size, -+ unsigned long prot_request, struct kbase_vmap_struct *map); -+ -+/** -+ * kbase_vmap - Map a GPU VA range into the kernel safely -+ * @kctx: Context the VA range belongs to -+ * @gpu_addr: Start address of VA range -+ * @size: Size of VA range -+ * @map: Structure to be given to kbase_vunmap() on freeing -+ * -+ * Return: Kernel-accessible CPU pointer to the VA range, or NULL on error -+ * -+ * Map a GPU VA Range into the kernel. The VA range must be contained within a -+ * GPU memory region. Appropriate CPU cache-flushing operations are made as -+ * required, dependent on the CPU mapping for the memory region. -+ * -+ * This is safer than using kmap() on the pages directly, -+ * because the pages here are refcounted to prevent freeing (and hence reuse -+ * elsewhere in the system) until an kbase_vunmap() -+ * -+ * kbase_vmap_prot() should be used in preference, since kbase_vmap() makes no -+ * checks to ensure the security of e.g. imported user bufs from RO SHM. -+ * -+ * Note: All cache maintenance operations shall be ignored if the memory region -+ * has been imported. -+ */ -+void *kbase_vmap(struct kbase_context *kctx, u64 gpu_addr, size_t size, -+ struct kbase_vmap_struct *map); -+ -+/** -+ * kbase_vunmap - Unmap a GPU VA range from the kernel -+ * @kctx: Context the VA range belongs to -+ * @map: Structure describing the mapping from the corresponding kbase_vmap() -+ * call -+ * -+ * Unmaps a GPU VA range from the kernel, given its @map structure obtained -+ * from kbase_vmap(). Appropriate CPU cache-flushing operations are made as -+ * required, dependent on the CPU mapping for the memory region. -+ * -+ * The reference taken on pages during kbase_vmap() is released. -+ * -+ * Note: All cache maintenance operations shall be ignored if the memory region -+ * has been imported. -+ */ -+void kbase_vunmap(struct kbase_context *kctx, struct kbase_vmap_struct *map); -+ -+/** @brief Allocate memory from kernel space and map it onto the GPU -+ * -+ * @param kctx The context used for the allocation/mapping -+ * @param size The size of the allocation in bytes -+ * @param handle An opaque structure used to contain the state needed to free the memory -+ * @return the VA for kernel space and GPU MMU -+ */ -+void *kbase_va_alloc(struct kbase_context *kctx, u32 size, struct kbase_hwc_dma_mapping *handle); -+ -+/** @brief Free/unmap memory allocated by kbase_va_alloc -+ * -+ * @param kctx The context used for the allocation/mapping -+ * @param handle An opaque structure returned by the kbase_va_alloc function. -+ */ -+void kbase_va_free(struct kbase_context *kctx, struct kbase_hwc_dma_mapping *handle); -+ -+extern const struct vm_operations_struct kbase_vm_ops; -+ -+#endif /* _KBASE_MEM_LINUX_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_lowlevel.h b/drivers/gpu/arm/midgard/mali_kbase_mem_lowlevel.h -new file mode 100644 -index 0000000..f4e8849 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_lowlevel.h -@@ -0,0 +1,89 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2014,2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KBASE_MEM_LOWLEVEL_H -+#define _KBASE_MEM_LOWLEVEL_H -+ -+#ifndef _KBASE_H_ -+#error "Don't include this file directly, use mali_kbase.h instead" -+#endif -+ -+#include -+ -+/** -+ * @brief Flags for kbase_phy_allocator_pages_alloc -+ */ -+#define KBASE_PHY_PAGES_FLAG_DEFAULT (0) /** Default allocation flag */ -+#define KBASE_PHY_PAGES_FLAG_CLEAR (1 << 0) /** Clear the pages after allocation */ -+#define KBASE_PHY_PAGES_FLAG_POISON (1 << 1) /** Fill the memory with a poison value */ -+ -+#define KBASE_PHY_PAGES_SUPPORTED_FLAGS (KBASE_PHY_PAGES_FLAG_DEFAULT|KBASE_PHY_PAGES_FLAG_CLEAR|KBASE_PHY_PAGES_FLAG_POISON) -+ -+#define KBASE_PHY_PAGES_POISON_VALUE 0xFD /** Value to fill the memory with when KBASE_PHY_PAGES_FLAG_POISON is set */ -+ -+enum kbase_sync_type { -+ KBASE_SYNC_TO_CPU, -+ KBASE_SYNC_TO_DEVICE -+}; -+ -+struct tagged_addr { phys_addr_t tagged_addr; }; -+ -+#define HUGE_PAGE (1u << 0) -+#define HUGE_HEAD (1u << 1) -+#define FROM_PARTIAL (1u << 2) -+ -+static inline phys_addr_t as_phys_addr_t(struct tagged_addr t) -+{ -+ return t.tagged_addr & PAGE_MASK; -+} -+ -+static inline struct tagged_addr as_tagged(phys_addr_t phys) -+{ -+ struct tagged_addr t; -+ -+ t.tagged_addr = phys & PAGE_MASK; -+ return t; -+} -+ -+static inline struct tagged_addr as_tagged_tag(phys_addr_t phys, int tag) -+{ -+ struct tagged_addr t; -+ -+ t.tagged_addr = (phys & PAGE_MASK) | (tag & ~PAGE_MASK); -+ return t; -+} -+ -+static inline bool is_huge(struct tagged_addr t) -+{ -+ return t.tagged_addr & HUGE_PAGE; -+} -+ -+static inline bool is_huge_head(struct tagged_addr t) -+{ -+ int mask = HUGE_HEAD | HUGE_PAGE; -+ -+ return mask == (t.tagged_addr & mask); -+} -+ -+static inline bool is_partial(struct tagged_addr t) -+{ -+ return t.tagged_addr & FROM_PARTIAL; -+} -+ -+#endif /* _KBASE_LOWLEVEL_H */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_pool.c b/drivers/gpu/arm/midgard/mali_kbase_mem_pool.c -new file mode 100644 -index 0000000..696730a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_pool.c -@@ -0,0 +1,651 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define pool_dbg(pool, format, ...) \ -+ dev_dbg(pool->kbdev->dev, "%s-pool [%zu/%zu]: " format, \ -+ (pool->next_pool) ? "kctx" : "kbdev", \ -+ kbase_mem_pool_size(pool), \ -+ kbase_mem_pool_max_size(pool), \ -+ ##__VA_ARGS__) -+ -+#define NOT_DIRTY false -+#define NOT_RECLAIMED false -+ -+static inline void kbase_mem_pool_lock(struct kbase_mem_pool *pool) -+{ -+ spin_lock(&pool->pool_lock); -+} -+ -+static inline void kbase_mem_pool_unlock(struct kbase_mem_pool *pool) -+{ -+ spin_unlock(&pool->pool_lock); -+} -+ -+static size_t kbase_mem_pool_capacity(struct kbase_mem_pool *pool) -+{ -+ ssize_t max_size = kbase_mem_pool_max_size(pool); -+ ssize_t cur_size = kbase_mem_pool_size(pool); -+ -+ return max(max_size - cur_size, (ssize_t)0); -+} -+ -+static bool kbase_mem_pool_is_full(struct kbase_mem_pool *pool) -+{ -+ return kbase_mem_pool_size(pool) >= kbase_mem_pool_max_size(pool); -+} -+ -+static bool kbase_mem_pool_is_empty(struct kbase_mem_pool *pool) -+{ -+ return kbase_mem_pool_size(pool) == 0; -+} -+ -+static void kbase_mem_pool_add_locked(struct kbase_mem_pool *pool, -+ struct page *p) -+{ -+ lockdep_assert_held(&pool->pool_lock); -+ -+ list_add(&p->lru, &pool->page_list); -+ pool->cur_size++; -+ -+ zone_page_state_add(1, page_zone(p), NR_SLAB_RECLAIMABLE); -+ -+ pool_dbg(pool, "added page\n"); -+} -+ -+static void kbase_mem_pool_add(struct kbase_mem_pool *pool, struct page *p) -+{ -+ kbase_mem_pool_lock(pool); -+ kbase_mem_pool_add_locked(pool, p); -+ kbase_mem_pool_unlock(pool); -+} -+ -+static void kbase_mem_pool_add_list_locked(struct kbase_mem_pool *pool, -+ struct list_head *page_list, size_t nr_pages) -+{ -+ struct page *p; -+ -+ lockdep_assert_held(&pool->pool_lock); -+ -+ list_for_each_entry(p, page_list, lru) { -+ zone_page_state_add(1, page_zone(p), NR_SLAB_RECLAIMABLE); -+ } -+ -+ list_splice(page_list, &pool->page_list); -+ pool->cur_size += nr_pages; -+ -+ pool_dbg(pool, "added %zu pages\n", nr_pages); -+} -+ -+static void kbase_mem_pool_add_list(struct kbase_mem_pool *pool, -+ struct list_head *page_list, size_t nr_pages) -+{ -+ kbase_mem_pool_lock(pool); -+ kbase_mem_pool_add_list_locked(pool, page_list, nr_pages); -+ kbase_mem_pool_unlock(pool); -+} -+ -+static struct page *kbase_mem_pool_remove_locked(struct kbase_mem_pool *pool) -+{ -+ struct page *p; -+ -+ lockdep_assert_held(&pool->pool_lock); -+ -+ if (kbase_mem_pool_is_empty(pool)) -+ return NULL; -+ -+ p = list_first_entry(&pool->page_list, struct page, lru); -+ list_del_init(&p->lru); -+ pool->cur_size--; -+ -+ zone_page_state_add(-1, page_zone(p), NR_SLAB_RECLAIMABLE); -+ -+ pool_dbg(pool, "removed page\n"); -+ -+ return p; -+} -+ -+static struct page *kbase_mem_pool_remove(struct kbase_mem_pool *pool) -+{ -+ struct page *p; -+ -+ kbase_mem_pool_lock(pool); -+ p = kbase_mem_pool_remove_locked(pool); -+ kbase_mem_pool_unlock(pool); -+ -+ return p; -+} -+ -+static void kbase_mem_pool_sync_page(struct kbase_mem_pool *pool, -+ struct page *p) -+{ -+ struct device *dev = pool->kbdev->dev; -+ dma_sync_single_for_device(dev, kbase_dma_addr(p), -+ (PAGE_SIZE << pool->order), DMA_BIDIRECTIONAL); -+} -+ -+static void kbase_mem_pool_zero_page(struct kbase_mem_pool *pool, -+ struct page *p) -+{ -+ int i; -+ -+ for (i = 0; i < (1U << pool->order); i++) -+ clear_highpage(p+i); -+ -+ kbase_mem_pool_sync_page(pool, p); -+} -+ -+static void kbase_mem_pool_spill(struct kbase_mem_pool *next_pool, -+ struct page *p) -+{ -+ /* Zero page before spilling */ -+ kbase_mem_pool_zero_page(next_pool, p); -+ -+ kbase_mem_pool_add(next_pool, p); -+} -+ -+struct page *kbase_mem_alloc_page(struct kbase_mem_pool *pool) -+{ -+ struct page *p; -+ gfp_t gfp; -+ struct device *dev = pool->kbdev->dev; -+ dma_addr_t dma_addr; -+ int i; -+ -+#if defined(CONFIG_ARM) && !defined(CONFIG_HAVE_DMA_ATTRS) && \ -+ LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) -+ /* DMA cache sync fails for HIGHMEM before 3.5 on ARM */ -+ gfp = GFP_USER | __GFP_ZERO; -+#else -+ gfp = GFP_HIGHUSER | __GFP_ZERO; -+#endif -+ -+ if (current->flags & PF_KTHREAD) { -+ /* Don't trigger OOM killer from kernel threads, e.g. when -+ * growing memory on GPU page fault */ -+ gfp |= __GFP_NORETRY; -+ } -+ -+ /* don't warn on higer order failures */ -+ if (pool->order) -+ gfp |= __GFP_NOWARN; -+ -+ p = alloc_pages(gfp, pool->order); -+ if (!p) -+ return NULL; -+ -+ dma_addr = dma_map_page(dev, p, 0, (PAGE_SIZE << pool->order), -+ DMA_BIDIRECTIONAL); -+ if (dma_mapping_error(dev, dma_addr)) { -+ __free_pages(p, pool->order); -+ return NULL; -+ } -+ -+ WARN_ON(dma_addr != page_to_phys(p)); -+ for (i = 0; i < (1u << pool->order); i++) -+ kbase_set_dma_addr(p+i, dma_addr + PAGE_SIZE * i); -+ -+ return p; -+} -+ -+static void kbase_mem_pool_free_page(struct kbase_mem_pool *pool, -+ struct page *p) -+{ -+ struct device *dev = pool->kbdev->dev; -+ dma_addr_t dma_addr = kbase_dma_addr(p); -+ int i; -+ -+ dma_unmap_page(dev, dma_addr, (PAGE_SIZE << pool->order), -+ DMA_BIDIRECTIONAL); -+ for (i = 0; i < (1u << pool->order); i++) -+ kbase_clear_dma_addr(p+i); -+ __free_pages(p, pool->order); -+ -+ pool_dbg(pool, "freed page to kernel\n"); -+} -+ -+static size_t kbase_mem_pool_shrink_locked(struct kbase_mem_pool *pool, -+ size_t nr_to_shrink) -+{ -+ struct page *p; -+ size_t i; -+ -+ lockdep_assert_held(&pool->pool_lock); -+ -+ for (i = 0; i < nr_to_shrink && !kbase_mem_pool_is_empty(pool); i++) { -+ p = kbase_mem_pool_remove_locked(pool); -+ kbase_mem_pool_free_page(pool, p); -+ } -+ -+ return i; -+} -+ -+static size_t kbase_mem_pool_shrink(struct kbase_mem_pool *pool, -+ size_t nr_to_shrink) -+{ -+ size_t nr_freed; -+ -+ kbase_mem_pool_lock(pool); -+ nr_freed = kbase_mem_pool_shrink_locked(pool, nr_to_shrink); -+ kbase_mem_pool_unlock(pool); -+ -+ return nr_freed; -+} -+ -+int kbase_mem_pool_grow(struct kbase_mem_pool *pool, -+ size_t nr_to_grow) -+{ -+ struct page *p; -+ size_t i; -+ -+ for (i = 0; i < nr_to_grow; i++) { -+ p = kbase_mem_alloc_page(pool); -+ if (!p) -+ return -ENOMEM; -+ kbase_mem_pool_add(pool, p); -+ } -+ -+ return 0; -+} -+ -+void kbase_mem_pool_trim(struct kbase_mem_pool *pool, size_t new_size) -+{ -+ size_t cur_size; -+ int err = 0; -+ -+ cur_size = kbase_mem_pool_size(pool); -+ -+ if (new_size > pool->max_size) -+ new_size = pool->max_size; -+ -+ if (new_size < cur_size) -+ kbase_mem_pool_shrink(pool, cur_size - new_size); -+ else if (new_size > cur_size) -+ err = kbase_mem_pool_grow(pool, new_size - cur_size); -+ -+ if (err) { -+ size_t grown_size = kbase_mem_pool_size(pool); -+ -+ dev_warn(pool->kbdev->dev, -+ "Mem pool not grown to the required size of %zu bytes, grown for additional %zu bytes instead!\n", -+ (new_size - cur_size), (grown_size - cur_size)); -+ } -+} -+ -+void kbase_mem_pool_set_max_size(struct kbase_mem_pool *pool, size_t max_size) -+{ -+ size_t cur_size; -+ size_t nr_to_shrink; -+ -+ kbase_mem_pool_lock(pool); -+ -+ pool->max_size = max_size; -+ -+ cur_size = kbase_mem_pool_size(pool); -+ if (max_size < cur_size) { -+ nr_to_shrink = cur_size - max_size; -+ kbase_mem_pool_shrink_locked(pool, nr_to_shrink); -+ } -+ -+ kbase_mem_pool_unlock(pool); -+} -+ -+ -+static unsigned long kbase_mem_pool_reclaim_count_objects(struct shrinker *s, -+ struct shrink_control *sc) -+{ -+ struct kbase_mem_pool *pool; -+ -+ pool = container_of(s, struct kbase_mem_pool, reclaim); -+ pool_dbg(pool, "reclaim count: %zu\n", kbase_mem_pool_size(pool)); -+ return kbase_mem_pool_size(pool); -+} -+ -+static unsigned long kbase_mem_pool_reclaim_scan_objects(struct shrinker *s, -+ struct shrink_control *sc) -+{ -+ struct kbase_mem_pool *pool; -+ unsigned long freed; -+ -+ pool = container_of(s, struct kbase_mem_pool, reclaim); -+ -+ pool_dbg(pool, "reclaim scan %ld:\n", sc->nr_to_scan); -+ -+ freed = kbase_mem_pool_shrink(pool, sc->nr_to_scan); -+ -+ pool_dbg(pool, "reclaim freed %ld pages\n", freed); -+ -+ return freed; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) -+static int kbase_mem_pool_reclaim_shrink(struct shrinker *s, -+ struct shrink_control *sc) -+{ -+ if (sc->nr_to_scan == 0) -+ return kbase_mem_pool_reclaim_count_objects(s, sc); -+ -+ return kbase_mem_pool_reclaim_scan_objects(s, sc); -+} -+#endif -+ -+int kbase_mem_pool_init(struct kbase_mem_pool *pool, -+ size_t max_size, -+ size_t order, -+ struct kbase_device *kbdev, -+ struct kbase_mem_pool *next_pool) -+{ -+ pool->cur_size = 0; -+ pool->max_size = max_size; -+ pool->order = order; -+ pool->kbdev = kbdev; -+ pool->next_pool = next_pool; -+ -+ spin_lock_init(&pool->pool_lock); -+ INIT_LIST_HEAD(&pool->page_list); -+ -+ /* Register shrinker */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) -+ pool->reclaim.shrink = kbase_mem_pool_reclaim_shrink; -+#else -+ pool->reclaim.count_objects = kbase_mem_pool_reclaim_count_objects; -+ pool->reclaim.scan_objects = kbase_mem_pool_reclaim_scan_objects; -+#endif -+ pool->reclaim.seeks = DEFAULT_SEEKS; -+ /* Kernel versions prior to 3.1 : -+ * struct shrinker does not define batch */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) -+ pool->reclaim.batch = 0; -+#endif -+ register_shrinker(&pool->reclaim); -+ -+ pool_dbg(pool, "initialized\n"); -+ -+ return 0; -+} -+ -+void kbase_mem_pool_term(struct kbase_mem_pool *pool) -+{ -+ struct kbase_mem_pool *next_pool = pool->next_pool; -+ struct page *p; -+ size_t nr_to_spill = 0; -+ LIST_HEAD(spill_list); -+ int i; -+ -+ pool_dbg(pool, "terminate()\n"); -+ -+ unregister_shrinker(&pool->reclaim); -+ -+ kbase_mem_pool_lock(pool); -+ pool->max_size = 0; -+ -+ if (next_pool && !kbase_mem_pool_is_full(next_pool)) { -+ /* Spill to next pool (may overspill) */ -+ nr_to_spill = kbase_mem_pool_capacity(next_pool); -+ nr_to_spill = min(kbase_mem_pool_size(pool), nr_to_spill); -+ -+ /* Zero pages first without holding the next_pool lock */ -+ for (i = 0; i < nr_to_spill; i++) { -+ p = kbase_mem_pool_remove_locked(pool); -+ kbase_mem_pool_zero_page(pool, p); -+ list_add(&p->lru, &spill_list); -+ } -+ } -+ -+ while (!kbase_mem_pool_is_empty(pool)) { -+ /* Free remaining pages to kernel */ -+ p = kbase_mem_pool_remove_locked(pool); -+ kbase_mem_pool_free_page(pool, p); -+ } -+ -+ kbase_mem_pool_unlock(pool); -+ -+ if (next_pool && nr_to_spill) { -+ /* Add new page list to next_pool */ -+ kbase_mem_pool_add_list(next_pool, &spill_list, nr_to_spill); -+ -+ pool_dbg(pool, "terminate() spilled %zu pages\n", nr_to_spill); -+ } -+ -+ pool_dbg(pool, "terminated\n"); -+} -+ -+struct page *kbase_mem_pool_alloc(struct kbase_mem_pool *pool) -+{ -+ struct page *p; -+ -+ do { -+ pool_dbg(pool, "alloc()\n"); -+ p = kbase_mem_pool_remove(pool); -+ -+ if (p) -+ return p; -+ -+ pool = pool->next_pool; -+ } while (pool); -+ -+ return NULL; -+} -+ -+void kbase_mem_pool_free(struct kbase_mem_pool *pool, struct page *p, -+ bool dirty) -+{ -+ struct kbase_mem_pool *next_pool = pool->next_pool; -+ -+ pool_dbg(pool, "free()\n"); -+ -+ if (!kbase_mem_pool_is_full(pool)) { -+ /* Add to our own pool */ -+ if (dirty) -+ kbase_mem_pool_sync_page(pool, p); -+ -+ kbase_mem_pool_add(pool, p); -+ } else if (next_pool && !kbase_mem_pool_is_full(next_pool)) { -+ /* Spill to next pool */ -+ kbase_mem_pool_spill(next_pool, p); -+ } else { -+ /* Free page */ -+ kbase_mem_pool_free_page(pool, p); -+ } -+} -+ -+int kbase_mem_pool_alloc_pages(struct kbase_mem_pool *pool, size_t nr_4k_pages, -+ struct tagged_addr *pages, bool partial_allowed) -+{ -+ struct page *p; -+ size_t nr_from_pool; -+ size_t i = 0; -+ int err = -ENOMEM; -+ size_t nr_pages_internal; -+ -+ nr_pages_internal = nr_4k_pages / (1u << (pool->order)); -+ -+ if (nr_pages_internal * (1u << pool->order) != nr_4k_pages) -+ return -EINVAL; -+ -+ pool_dbg(pool, "alloc_pages(4k=%zu):\n", nr_4k_pages); -+ pool_dbg(pool, "alloc_pages(internal=%zu):\n", nr_pages_internal); -+ -+ /* Get pages from this pool */ -+ kbase_mem_pool_lock(pool); -+ nr_from_pool = min(nr_pages_internal, kbase_mem_pool_size(pool)); -+ while (nr_from_pool--) { -+ int j; -+ p = kbase_mem_pool_remove_locked(pool); -+ if (pool->order) { -+ pages[i++] = as_tagged_tag(page_to_phys(p), -+ HUGE_HEAD | HUGE_PAGE); -+ for (j = 1; j < (1u << pool->order); j++) -+ pages[i++] = as_tagged_tag(page_to_phys(p) + -+ PAGE_SIZE * j, -+ HUGE_PAGE); -+ } else { -+ pages[i++] = as_tagged(page_to_phys(p)); -+ } -+ } -+ kbase_mem_pool_unlock(pool); -+ -+ if (i != nr_4k_pages && pool->next_pool) { -+ /* Allocate via next pool */ -+ err = kbase_mem_pool_alloc_pages(pool->next_pool, -+ nr_4k_pages - i, pages + i, partial_allowed); -+ -+ if (err < 0) -+ goto err_rollback; -+ -+ i += err; -+ } else { -+ /* Get any remaining pages from kernel */ -+ while (i != nr_4k_pages) { -+ p = kbase_mem_alloc_page(pool); -+ if (!p) { -+ if (partial_allowed) -+ goto done; -+ else -+ goto err_rollback; -+ } -+ -+ if (pool->order) { -+ int j; -+ -+ pages[i++] = as_tagged_tag(page_to_phys(p), -+ HUGE_PAGE | -+ HUGE_HEAD); -+ for (j = 1; j < (1u << pool->order); j++) { -+ phys_addr_t phys; -+ -+ phys = page_to_phys(p) + PAGE_SIZE * j; -+ pages[i++] = as_tagged_tag(phys, -+ HUGE_PAGE); -+ } -+ } else { -+ pages[i++] = as_tagged(page_to_phys(p)); -+ } -+ } -+ } -+ -+done: -+ pool_dbg(pool, "alloc_pages(%zu) done\n", i); -+ -+ return i; -+ -+err_rollback: -+ kbase_mem_pool_free_pages(pool, i, pages, NOT_DIRTY, NOT_RECLAIMED); -+ return err; -+} -+ -+static void kbase_mem_pool_add_array(struct kbase_mem_pool *pool, -+ size_t nr_pages, struct tagged_addr *pages, -+ bool zero, bool sync) -+{ -+ struct page *p; -+ size_t nr_to_pool = 0; -+ LIST_HEAD(new_page_list); -+ size_t i; -+ -+ if (!nr_pages) -+ return; -+ -+ pool_dbg(pool, "add_array(%zu, zero=%d, sync=%d):\n", -+ nr_pages, zero, sync); -+ -+ /* Zero/sync pages first without holding the pool lock */ -+ for (i = 0; i < nr_pages; i++) { -+ if (unlikely(!as_phys_addr_t(pages[i]))) -+ continue; -+ -+ if (is_huge_head(pages[i]) || !is_huge(pages[i])) { -+ p = phys_to_page(as_phys_addr_t(pages[i])); -+ if (zero) -+ kbase_mem_pool_zero_page(pool, p); -+ else if (sync) -+ kbase_mem_pool_sync_page(pool, p); -+ -+ list_add(&p->lru, &new_page_list); -+ nr_to_pool++; -+ } -+ pages[i] = as_tagged(0); -+ } -+ -+ /* Add new page list to pool */ -+ kbase_mem_pool_add_list(pool, &new_page_list, nr_to_pool); -+ -+ pool_dbg(pool, "add_array(%zu) added %zu pages\n", -+ nr_pages, nr_to_pool); -+} -+ -+void kbase_mem_pool_free_pages(struct kbase_mem_pool *pool, size_t nr_pages, -+ struct tagged_addr *pages, bool dirty, bool reclaimed) -+{ -+ struct kbase_mem_pool *next_pool = pool->next_pool; -+ struct page *p; -+ size_t nr_to_pool; -+ LIST_HEAD(to_pool_list); -+ size_t i = 0; -+ -+ pool_dbg(pool, "free_pages(%zu):\n", nr_pages); -+ -+ if (!reclaimed) { -+ /* Add to this pool */ -+ nr_to_pool = kbase_mem_pool_capacity(pool); -+ nr_to_pool = min(nr_pages, nr_to_pool); -+ -+ kbase_mem_pool_add_array(pool, nr_to_pool, pages, false, dirty); -+ -+ i += nr_to_pool; -+ -+ if (i != nr_pages && next_pool) { -+ /* Spill to next pool (may overspill) */ -+ nr_to_pool = kbase_mem_pool_capacity(next_pool); -+ nr_to_pool = min(nr_pages - i, nr_to_pool); -+ -+ kbase_mem_pool_add_array(next_pool, nr_to_pool, -+ pages + i, true, dirty); -+ i += nr_to_pool; -+ } -+ } -+ -+ /* Free any remaining pages to kernel */ -+ for (; i < nr_pages; i++) { -+ if (unlikely(!as_phys_addr_t(pages[i]))) -+ continue; -+ -+ if (is_huge(pages[i]) && !is_huge_head(pages[i])) { -+ pages[i] = as_tagged(0); -+ continue; -+ } -+ -+ p = phys_to_page(as_phys_addr_t(pages[i])); -+ -+ if (reclaimed) -+ zone_page_state_add(-1, page_zone(p), -+ NR_SLAB_RECLAIMABLE); -+ -+ kbase_mem_pool_free_page(pool, p); -+ pages[i] = as_tagged(0); -+ } -+ -+ pool_dbg(pool, "free_pages(%zu) done\n", nr_pages); -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_pool_debugfs.c b/drivers/gpu/arm/midgard/mali_kbase_mem_pool_debugfs.c -new file mode 100644 -index 0000000..585fba0 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_pool_debugfs.c -@@ -0,0 +1,81 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+ -+#include -+ -+#ifdef CONFIG_DEBUG_FS -+ -+static int kbase_mem_pool_debugfs_size_get(void *data, u64 *val) -+{ -+ struct kbase_mem_pool *pool = (struct kbase_mem_pool *)data; -+ -+ *val = kbase_mem_pool_size(pool); -+ -+ return 0; -+} -+ -+static int kbase_mem_pool_debugfs_size_set(void *data, u64 val) -+{ -+ struct kbase_mem_pool *pool = (struct kbase_mem_pool *)data; -+ -+ kbase_mem_pool_trim(pool, val); -+ -+ return 0; -+} -+ -+DEFINE_SIMPLE_ATTRIBUTE(kbase_mem_pool_debugfs_size_fops, -+ kbase_mem_pool_debugfs_size_get, -+ kbase_mem_pool_debugfs_size_set, -+ "%llu\n"); -+ -+static int kbase_mem_pool_debugfs_max_size_get(void *data, u64 *val) -+{ -+ struct kbase_mem_pool *pool = (struct kbase_mem_pool *)data; -+ -+ *val = kbase_mem_pool_max_size(pool); -+ -+ return 0; -+} -+ -+static int kbase_mem_pool_debugfs_max_size_set(void *data, u64 val) -+{ -+ struct kbase_mem_pool *pool = (struct kbase_mem_pool *)data; -+ -+ kbase_mem_pool_set_max_size(pool, val); -+ -+ return 0; -+} -+ -+DEFINE_SIMPLE_ATTRIBUTE(kbase_mem_pool_debugfs_max_size_fops, -+ kbase_mem_pool_debugfs_max_size_get, -+ kbase_mem_pool_debugfs_max_size_set, -+ "%llu\n"); -+ -+void kbase_mem_pool_debugfs_init(struct dentry *parent, -+ struct kbase_mem_pool *pool) -+{ -+ debugfs_create_file("mem_pool_size", S_IRUGO | S_IWUSR, parent, -+ pool, &kbase_mem_pool_debugfs_size_fops); -+ -+ debugfs_create_file("mem_pool_max_size", S_IRUGO | S_IWUSR, parent, -+ pool, &kbase_mem_pool_debugfs_max_size_fops); -+} -+ -+#endif /* CONFIG_DEBUG_FS */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_pool_debugfs.h b/drivers/gpu/arm/midgard/mali_kbase_mem_pool_debugfs.h -new file mode 100644 -index 0000000..1442854 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_pool_debugfs.h -@@ -0,0 +1,36 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_MEM_POOL_DEBUGFS_H -+#define _KBASE_MEM_POOL_DEBUGFS_H -+ -+#include -+ -+/** -+ * kbase_mem_pool_debugfs_init - add debugfs knobs for @pool -+ * @parent: Parent debugfs dentry -+ * @pool: Memory pool to control -+ * -+ * Adds two debugfs files under @parent: -+ * - mem_pool_size: get/set the current size of @pool -+ * - mem_pool_max_size: get/set the max size of @pool -+ */ -+void kbase_mem_pool_debugfs_init(struct dentry *parent, -+ struct kbase_mem_pool *pool); -+ -+#endif /*_KBASE_MEM_POOL_DEBUGFS_H*/ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs.c b/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs.c -new file mode 100644 -index 0000000..d58fd8d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs.c -@@ -0,0 +1,121 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+ -+#ifdef CONFIG_DEBUG_FS -+ -+/** Show callback for the @c mem_profile debugfs file. -+ * -+ * This function is called to get the contents of the @c mem_profile debugfs -+ * file. This is a report of current memory usage and distribution in userspace. -+ * -+ * @param sfile The debugfs entry -+ * @param data Data associated with the entry -+ * -+ * @return 0 if it successfully prints data in debugfs entry file, non-zero otherwise -+ */ -+static int kbasep_mem_profile_seq_show(struct seq_file *sfile, void *data) -+{ -+ struct kbase_context *kctx = sfile->private; -+ -+ mutex_lock(&kctx->mem_profile_lock); -+ -+ seq_write(sfile, kctx->mem_profile_data, kctx->mem_profile_size); -+ -+ seq_putc(sfile, '\n'); -+ -+ mutex_unlock(&kctx->mem_profile_lock); -+ -+ return 0; -+} -+ -+/* -+ * File operations related to debugfs entry for mem_profile -+ */ -+static int kbasep_mem_profile_debugfs_open(struct inode *in, struct file *file) -+{ -+ return single_open(file, kbasep_mem_profile_seq_show, in->i_private); -+} -+ -+static const struct file_operations kbasep_mem_profile_debugfs_fops = { -+ .open = kbasep_mem_profile_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+int kbasep_mem_profile_debugfs_insert(struct kbase_context *kctx, char *data, -+ size_t size) -+{ -+ int err = 0; -+ -+ mutex_lock(&kctx->mem_profile_lock); -+ -+ dev_dbg(kctx->kbdev->dev, "initialised: %d", -+ kbase_ctx_flag(kctx, KCTX_MEM_PROFILE_INITIALIZED)); -+ -+ if (!kbase_ctx_flag(kctx, KCTX_MEM_PROFILE_INITIALIZED)) { -+ if (!debugfs_create_file("mem_profile", S_IRUGO, -+ kctx->kctx_dentry, kctx, -+ &kbasep_mem_profile_debugfs_fops)) { -+ err = -EAGAIN; -+ } else { -+ kbase_ctx_flag_set(kctx, -+ KCTX_MEM_PROFILE_INITIALIZED); -+ } -+ } -+ -+ if (kbase_ctx_flag(kctx, KCTX_MEM_PROFILE_INITIALIZED)) { -+ kfree(kctx->mem_profile_data); -+ kctx->mem_profile_data = data; -+ kctx->mem_profile_size = size; -+ } else { -+ kfree(data); -+ } -+ -+ dev_dbg(kctx->kbdev->dev, "returning: %d, initialised: %d", -+ err, kbase_ctx_flag(kctx, KCTX_MEM_PROFILE_INITIALIZED)); -+ -+ mutex_unlock(&kctx->mem_profile_lock); -+ -+ return err; -+} -+ -+void kbasep_mem_profile_debugfs_remove(struct kbase_context *kctx) -+{ -+ mutex_lock(&kctx->mem_profile_lock); -+ -+ dev_dbg(kctx->kbdev->dev, "initialised: %d", -+ kbase_ctx_flag(kctx, KCTX_MEM_PROFILE_INITIALIZED)); -+ -+ kfree(kctx->mem_profile_data); -+ kctx->mem_profile_data = NULL; -+ kctx->mem_profile_size = 0; -+ -+ mutex_unlock(&kctx->mem_profile_lock); -+} -+ -+#else /* CONFIG_DEBUG_FS */ -+ -+int kbasep_mem_profile_debugfs_insert(struct kbase_context *kctx, char *data, -+ size_t size) -+{ -+ kfree(data); -+ return 0; -+} -+#endif /* CONFIG_DEBUG_FS */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs.h b/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs.h -new file mode 100644 -index 0000000..a1dc2e0 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs.h -@@ -0,0 +1,59 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_mem_profile_debugfs.h -+ * Header file for mem profiles entries in debugfs -+ * -+ */ -+ -+#ifndef _KBASE_MEM_PROFILE_DEBUGFS_H -+#define _KBASE_MEM_PROFILE_DEBUGFS_H -+ -+#include -+#include -+ -+/** -+ * @brief Remove entry from Mali memory profile debugfs -+ */ -+void kbasep_mem_profile_debugfs_remove(struct kbase_context *kctx); -+ -+/** -+ * @brief Insert @p data to the debugfs file so it can be read by userspace -+ * -+ * The function takes ownership of @p data and frees it later when new data -+ * is inserted. -+ * -+ * If the debugfs entry corresponding to the @p kctx doesn't exist, -+ * an attempt will be made to create it. -+ * -+ * @param kctx The context whose debugfs file @p data should be inserted to -+ * @param data A NULL-terminated string to be inserted to the debugfs file, -+ * without the trailing new line character -+ * @param size The length of the @p data string -+ * @return 0 if @p data inserted correctly -+ * -EAGAIN in case of error -+ * @post @ref mem_profile_initialized will be set to @c true -+ * the first time this function succeeds. -+ */ -+int kbasep_mem_profile_debugfs_insert(struct kbase_context *kctx, char *data, -+ size_t size); -+ -+#endif /*_KBASE_MEM_PROFILE_DEBUGFS_H*/ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs_buf_size.h b/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs_buf_size.h -new file mode 100644 -index 0000000..82f0702 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_profile_debugfs_buf_size.h -@@ -0,0 +1,33 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @file mali_kbase_mem_profile_debugfs_buf_size.h -+ * Header file for the size of the buffer to accumulate the histogram report text in -+ */ -+ -+#ifndef _KBASE_MEM_PROFILE_DEBUGFS_BUF_SIZE_H_ -+#define _KBASE_MEM_PROFILE_DEBUGFS_BUF_SIZE_H_ -+ -+/** -+ * The size of the buffer to accumulate the histogram report text in -+ * @see @ref CCTXP_HIST_BUF_SIZE_MAX_LENGTH_REPORT -+ */ -+#define KBASE_MEM_PROFILE_MAX_BUF_SIZE ((size_t) (64 + ((80 + (56 * 64)) * 15) + 56)) -+ -+#endif /*_KBASE_MEM_PROFILE_DEBUGFS_BUF_SIZE_H_*/ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mmu.c b/drivers/gpu/arm/midgard/mali_kbase_mmu.c -new file mode 100644 -index 0000000..b3aa9e0 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mmu.c -@@ -0,0 +1,2141 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_mmu.c -+ * Base kernel MMU management. -+ */ -+ -+/* #define DEBUG 1 */ -+#include -+#include -+#include -+#include -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+#include -+#endif -+#include -+#include -+#include -+ -+#define beenthere(kctx, f, a...) dev_dbg(kctx->kbdev->dev, "%s:" f, __func__, ##a) -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define KBASE_MMU_PAGE_ENTRIES 512 -+ -+/** -+ * kbase_mmu_flush_invalidate() - Flush and invalidate the GPU caches. -+ * @kctx: The KBase context. -+ * @vpfn: The virtual page frame number to start the flush on. -+ * @nr: The number of pages to flush. -+ * @sync: Set if the operation should be synchronous or not. -+ * -+ * Issue a cache flush + invalidate to the GPU caches and invalidate the TLBs. -+ * -+ * If sync is not set then transactions still in flight when the flush is issued -+ * may use the old page tables and the data they write will not be written out -+ * to memory, this function returns after the flush has been issued but -+ * before all accesses which might effect the flushed region have completed. -+ * -+ * If sync is set then accesses in the flushed region will be drained -+ * before data is flush and invalidated through L1, L2 and into memory, -+ * after which point this function will return. -+ */ -+static void kbase_mmu_flush_invalidate(struct kbase_context *kctx, -+ u64 vpfn, size_t nr, bool sync); -+ -+/** -+ * kbase_mmu_sync_pgd - sync page directory to memory -+ * @kbdev: Device pointer. -+ * @handle: Address of DMA region. -+ * @size: Size of the region to sync. -+ * -+ * This should be called after each page directory update. -+ */ -+ -+static void kbase_mmu_sync_pgd(struct kbase_device *kbdev, -+ dma_addr_t handle, size_t size) -+{ -+ /* If page table is not coherent then ensure the gpu can read -+ * the pages from memory -+ */ -+ if (kbdev->system_coherency != COHERENCY_ACE) -+ dma_sync_single_for_device(kbdev->dev, handle, size, -+ DMA_TO_DEVICE); -+} -+ -+/* -+ * Definitions: -+ * - PGD: Page Directory. -+ * - PTE: Page Table Entry. A 64bit value pointing to the next -+ * level of translation -+ * - ATE: Address Transation Entry. A 64bit value pointing to -+ * a 4kB physical page. -+ */ -+ -+static void kbase_mmu_report_fault_and_kill(struct kbase_context *kctx, -+ struct kbase_as *as, const char *reason_str); -+ -+ -+static size_t make_multiple(size_t minimum, size_t multiple) -+{ -+ size_t remainder = minimum % multiple; -+ -+ if (remainder == 0) -+ return minimum; -+ -+ return minimum + multiple - remainder; -+} -+ -+void page_fault_worker(struct work_struct *data) -+{ -+ u64 fault_pfn; -+ u32 fault_status; -+ size_t new_pages; -+ size_t fault_rel_pfn; -+ struct kbase_as *faulting_as; -+ int as_no; -+ struct kbase_context *kctx; -+ struct kbase_device *kbdev; -+ struct kbase_va_region *region; -+ int err; -+ bool grown = false; -+ -+ faulting_as = container_of(data, struct kbase_as, work_pagefault); -+ fault_pfn = faulting_as->fault_addr >> PAGE_SHIFT; -+ as_no = faulting_as->number; -+ -+ kbdev = container_of(faulting_as, struct kbase_device, as[as_no]); -+ -+ /* Grab the context that was already refcounted in kbase_mmu_interrupt(). -+ * Therefore, it cannot be scheduled out of this AS until we explicitly release it -+ */ -+ kctx = kbasep_js_runpool_lookup_ctx_noretain(kbdev, as_no); -+ if (WARN_ON(!kctx)) { -+ atomic_dec(&kbdev->faults_pending); -+ return; -+ } -+ -+ KBASE_DEBUG_ASSERT(kctx->kbdev == kbdev); -+ -+ if (unlikely(faulting_as->protected_mode)) -+ { -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Protected mode fault"); -+ kbase_mmu_hw_clear_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE); -+ -+ goto fault_done; -+ } -+ -+ fault_status = faulting_as->fault_status; -+ switch (fault_status & AS_FAULTSTATUS_EXCEPTION_CODE_MASK) { -+ -+ case AS_FAULTSTATUS_EXCEPTION_CODE_TRANSLATION_FAULT: -+ /* need to check against the region to handle this one */ -+ break; -+ -+ case AS_FAULTSTATUS_EXCEPTION_CODE_PERMISSION_FAULT: -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Permission failure"); -+ goto fault_done; -+ -+ case AS_FAULTSTATUS_EXCEPTION_CODE_TRANSTAB_BUS_FAULT: -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Translation table bus fault"); -+ goto fault_done; -+ -+ case AS_FAULTSTATUS_EXCEPTION_CODE_ACCESS_FLAG: -+ /* nothing to do, but we don't expect this fault currently */ -+ dev_warn(kbdev->dev, "Access flag unexpectedly set"); -+ goto fault_done; -+ -+ case AS_FAULTSTATUS_EXCEPTION_CODE_ADDRESS_SIZE_FAULT: -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Address size fault"); -+ else -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Unknown fault code"); -+ goto fault_done; -+ -+ case AS_FAULTSTATUS_EXCEPTION_CODE_MEMORY_ATTRIBUTES_FAULT: -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Memory attributes fault"); -+ else -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Unknown fault code"); -+ goto fault_done; -+ -+ default: -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Unknown fault code"); -+ goto fault_done; -+ } -+ -+ /* so we have a translation fault, let's see if it is for growable -+ * memory */ -+ kbase_gpu_vm_lock(kctx); -+ -+ region = kbase_region_tracker_find_region_enclosing_address(kctx, -+ faulting_as->fault_addr); -+ if (!region || region->flags & KBASE_REG_FREE) { -+ kbase_gpu_vm_unlock(kctx); -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Memory is not mapped on the GPU"); -+ goto fault_done; -+ } -+ -+ if (region->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM) { -+ kbase_gpu_vm_unlock(kctx); -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "DMA-BUF is not mapped on the GPU"); -+ goto fault_done; -+ } -+ -+ if ((region->flags & GROWABLE_FLAGS_REQUIRED) -+ != GROWABLE_FLAGS_REQUIRED) { -+ kbase_gpu_vm_unlock(kctx); -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Memory is not growable"); -+ goto fault_done; -+ } -+ -+ if ((region->flags & KBASE_REG_DONT_NEED)) { -+ kbase_gpu_vm_unlock(kctx); -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Don't need memory can't be grown"); -+ goto fault_done; -+ } -+ -+ /* find the size we need to grow it by */ -+ /* we know the result fit in a size_t due to kbase_region_tracker_find_region_enclosing_address -+ * validating the fault_adress to be within a size_t from the start_pfn */ -+ fault_rel_pfn = fault_pfn - region->start_pfn; -+ -+ if (fault_rel_pfn < kbase_reg_current_backed_size(region)) { -+ dev_dbg(kbdev->dev, "Page fault @ 0x%llx in allocated region 0x%llx-0x%llx of growable TMEM: Ignoring", -+ faulting_as->fault_addr, region->start_pfn, -+ region->start_pfn + -+ kbase_reg_current_backed_size(region)); -+ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ -+ kbase_mmu_hw_clear_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE); -+ /* [1] in case another page fault occurred while we were -+ * handling the (duplicate) page fault we need to ensure we -+ * don't loose the other page fault as result of us clearing -+ * the MMU IRQ. Therefore, after we clear the MMU IRQ we send -+ * an UNLOCK command that will retry any stalled memory -+ * transaction (which should cause the other page fault to be -+ * raised again). -+ */ -+ kbase_mmu_hw_do_operation(kbdev, faulting_as, NULL, 0, 0, -+ AS_COMMAND_UNLOCK, 1); -+ -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ kbase_mmu_hw_enable_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE); -+ kbase_gpu_vm_unlock(kctx); -+ -+ goto fault_done; -+ } -+ -+ new_pages = make_multiple(fault_rel_pfn - -+ kbase_reg_current_backed_size(region) + 1, -+ region->extent); -+ -+ /* cap to max vsize */ -+ if (new_pages + kbase_reg_current_backed_size(region) > -+ region->nr_pages) -+ new_pages = region->nr_pages - -+ kbase_reg_current_backed_size(region); -+ -+ if (0 == new_pages) { -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ -+ /* Duplicate of a fault we've already handled, nothing to do */ -+ kbase_mmu_hw_clear_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE); -+ /* See comment [1] about UNLOCK usage */ -+ kbase_mmu_hw_do_operation(kbdev, faulting_as, NULL, 0, 0, -+ AS_COMMAND_UNLOCK, 1); -+ -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ -+ kbase_mmu_hw_enable_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE); -+ kbase_gpu_vm_unlock(kctx); -+ goto fault_done; -+ } -+ -+ if (kbase_alloc_phy_pages_helper(region->gpu_alloc, new_pages) == 0) { -+ if (region->gpu_alloc != region->cpu_alloc) { -+ if (kbase_alloc_phy_pages_helper( -+ region->cpu_alloc, new_pages) == 0) { -+ grown = true; -+ } else { -+ kbase_free_phy_pages_helper(region->gpu_alloc, -+ new_pages); -+ } -+ } else { -+ grown = true; -+ } -+ } -+ -+ -+ if (grown) { -+ u64 pfn_offset; -+ u32 op; -+ -+ /* alloc success */ -+ KBASE_DEBUG_ASSERT(kbase_reg_current_backed_size(region) <= region->nr_pages); -+ -+ /* set up the new pages */ -+ pfn_offset = kbase_reg_current_backed_size(region) - new_pages; -+ /* -+ * Note: -+ * Issuing an MMU operation will unlock the MMU and cause the -+ * translation to be replayed. If the page insertion fails then -+ * rather then trying to continue the context should be killed -+ * so the no_flush version of insert_pages is used which allows -+ * us to unlock the MMU as we see fit. -+ */ -+ err = kbase_mmu_insert_pages_no_flush(kctx, -+ region->start_pfn + pfn_offset, -+ &kbase_get_gpu_phy_pages(region)[pfn_offset], -+ new_pages, region->flags); -+ if (err) { -+ kbase_free_phy_pages_helper(region->gpu_alloc, new_pages); -+ if (region->gpu_alloc != region->cpu_alloc) -+ kbase_free_phy_pages_helper(region->cpu_alloc, -+ new_pages); -+ kbase_gpu_vm_unlock(kctx); -+ /* The locked VA region will be unlocked and the cache invalidated in here */ -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Page table update failure"); -+ goto fault_done; -+ } -+#if defined(CONFIG_MALI_GATOR_SUPPORT) -+ kbase_trace_mali_page_fault_insert_pages(as_no, new_pages); -+#endif -+ KBASE_TLSTREAM_AUX_PAGEFAULT(kctx->id, (u64)new_pages); -+ -+ /* AS transaction begin */ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ -+ /* flush L2 and unlock the VA (resumes the MMU) */ -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_6367)) -+ op = AS_COMMAND_FLUSH; -+ else -+ op = AS_COMMAND_FLUSH_PT; -+ -+ /* clear MMU interrupt - this needs to be done after updating -+ * the page tables but before issuing a FLUSH command. The -+ * FLUSH cmd has a side effect that it restarts stalled memory -+ * transactions in other address spaces which may cause -+ * another fault to occur. If we didn't clear the interrupt at -+ * this stage a new IRQ might not be raised when the GPU finds -+ * a MMU IRQ is already pending. -+ */ -+ kbase_mmu_hw_clear_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE); -+ -+ kbase_mmu_hw_do_operation(kbdev, faulting_as, kctx, -+ faulting_as->fault_addr >> PAGE_SHIFT, -+ new_pages, -+ op, 1); -+ -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ /* AS transaction end */ -+ -+ /* reenable this in the mask */ -+ kbase_mmu_hw_enable_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE); -+ kbase_gpu_vm_unlock(kctx); -+ } else { -+ /* failed to extend, handle as a normal PF */ -+ kbase_gpu_vm_unlock(kctx); -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Page allocation failure"); -+ } -+ -+fault_done: -+ /* -+ * By this point, the fault was handled in some way, -+ * so release the ctx refcount -+ */ -+ kbasep_js_runpool_release_ctx(kbdev, kctx); -+ -+ atomic_dec(&kbdev->faults_pending); -+} -+ -+phys_addr_t kbase_mmu_alloc_pgd(struct kbase_context *kctx) -+{ -+ u64 *page; -+ int i; -+ struct page *p; -+ int new_page_count __maybe_unused; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ new_page_count = kbase_atomic_add_pages(1, &kctx->used_pages); -+ kbase_atomic_add_pages(1, &kctx->kbdev->memdev.used_pages); -+ -+ p = kbase_mem_pool_alloc(&kctx->mem_pool); -+ if (!p) -+ goto sub_pages; -+ -+ KBASE_TLSTREAM_AUX_PAGESALLOC( -+ (u32)kctx->id, -+ (u64)new_page_count); -+ -+ page = kmap(p); -+ if (NULL == page) -+ goto alloc_free; -+ -+ kbase_process_page_usage_inc(kctx, 1); -+ -+ for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) -+ kctx->kbdev->mmu_mode->entry_invalidate(&page[i]); -+ -+ kbase_mmu_sync_pgd(kctx->kbdev, kbase_dma_addr(p), PAGE_SIZE); -+ -+ kunmap(p); -+ return page_to_phys(p); -+ -+alloc_free: -+ kbase_mem_pool_free(&kctx->mem_pool, p, false); -+sub_pages: -+ kbase_atomic_sub_pages(1, &kctx->used_pages); -+ kbase_atomic_sub_pages(1, &kctx->kbdev->memdev.used_pages); -+ -+ return 0; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mmu_alloc_pgd); -+ -+/* Given PGD PFN for level N, return PGD PFN for level N+1, allocating the -+ * new table from the pool if needed and possible -+ */ -+static int mmu_get_next_pgd(struct kbase_context *kctx, -+ phys_addr_t *pgd, u64 vpfn, int level) -+{ -+ u64 *page; -+ phys_addr_t target_pgd; -+ struct page *p; -+ -+ KBASE_DEBUG_ASSERT(*pgd); -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ -+ lockdep_assert_held(&kctx->mmu_lock); -+ -+ /* -+ * Architecture spec defines level-0 as being the top-most. -+ * This is a bit unfortunate here, but we keep the same convention. -+ */ -+ vpfn >>= (3 - level) * 9; -+ vpfn &= 0x1FF; -+ -+ p = pfn_to_page(PFN_DOWN(*pgd)); -+ page = kmap(p); -+ if (NULL == page) { -+ dev_warn(kctx->kbdev->dev, "mmu_get_next_pgd: kmap failure\n"); -+ return -EINVAL; -+ } -+ -+ target_pgd = kctx->kbdev->mmu_mode->pte_to_phy_addr(page[vpfn]); -+ -+ if (!target_pgd) { -+ target_pgd = kbase_mmu_alloc_pgd(kctx); -+ if (!target_pgd) { -+ dev_dbg(kctx->kbdev->dev, "mmu_get_next_pgd: kbase_mmu_alloc_pgd failure\n"); -+ kunmap(p); -+ return -ENOMEM; -+ } -+ -+ kctx->kbdev->mmu_mode->entry_set_pte(&page[vpfn], target_pgd); -+ -+ kbase_mmu_sync_pgd(kctx->kbdev, kbase_dma_addr(p), PAGE_SIZE); -+ /* Rely on the caller to update the address space flags. */ -+ } -+ -+ kunmap(p); -+ *pgd = target_pgd; -+ -+ return 0; -+} -+ -+/* -+ * Returns the PGD for the specified level of translation -+ */ -+static int mmu_get_pgd_at_level(struct kbase_context *kctx, -+ u64 vpfn, -+ unsigned int level, -+ phys_addr_t *out_pgd) -+{ -+ phys_addr_t pgd; -+ int l; -+ -+ lockdep_assert_held(&kctx->mmu_lock); -+ pgd = kctx->pgd; -+ -+ for (l = MIDGARD_MMU_TOPLEVEL; l < level; l++) { -+ int err = mmu_get_next_pgd(kctx, &pgd, vpfn, l); -+ /* Handle failure condition */ -+ if (err) { -+ dev_dbg(kctx->kbdev->dev, -+ "%s: mmu_get_next_pgd failure at level %d\n", -+ __func__, l); -+ return err; -+ } -+ } -+ -+ *out_pgd = pgd; -+ -+ return 0; -+} -+ -+#define mmu_get_bottom_pgd(kctx, vpfn, out_pgd) \ -+ mmu_get_pgd_at_level((kctx), (vpfn), MIDGARD_MMU_BOTTOMLEVEL, (out_pgd)) -+ -+ -+static void mmu_insert_pages_failure_recovery(struct kbase_context *kctx, -+ u64 from_vpfn, u64 to_vpfn) -+{ -+ phys_addr_t pgd; -+ u64 vpfn = from_vpfn; -+ struct kbase_mmu_mode const *mmu_mode; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(0 != vpfn); -+ /* 64-bit address range is the max */ -+ KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE)); -+ KBASE_DEBUG_ASSERT(from_vpfn <= to_vpfn); -+ -+ lockdep_assert_held(&kctx->mmu_lock); -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ mmu_mode = kctx->kbdev->mmu_mode; -+ -+ while (vpfn < to_vpfn) { -+ unsigned int i; -+ unsigned int idx = vpfn & 0x1FF; -+ unsigned int count = KBASE_MMU_PAGE_ENTRIES - idx; -+ unsigned int pcount = 0; -+ unsigned int left = to_vpfn - vpfn; -+ unsigned int level; -+ u64 *page; -+ -+ if (count > left) -+ count = left; -+ -+ /* need to check if this is a 2MB page or a 4kB */ -+ pgd = kctx->pgd; -+ -+ for (level = MIDGARD_MMU_TOPLEVEL; -+ level <= MIDGARD_MMU_BOTTOMLEVEL; level++) { -+ idx = (vpfn >> ((3 - level) * 9)) & 0x1FF; -+ page = kmap(phys_to_page(pgd)); -+ if (mmu_mode->ate_is_valid(page[idx], level)) -+ break; /* keep the mapping */ -+ kunmap(phys_to_page(pgd)); -+ pgd = mmu_mode->pte_to_phy_addr(page[idx]); -+ } -+ -+ switch (level) { -+ case MIDGARD_MMU_LEVEL(2): -+ /* remap to single entry to update */ -+ pcount = 1; -+ break; -+ case MIDGARD_MMU_BOTTOMLEVEL: -+ /* page count is the same as the logical count */ -+ pcount = count; -+ break; -+ default: -+ dev_warn(kctx->kbdev->dev, "%sNo support for ATEs at level %d\n", -+ __func__, level); -+ goto next; -+ } -+ -+ /* Invalidate the entries we added */ -+ for (i = 0; i < pcount; i++) -+ mmu_mode->entry_invalidate(&page[idx + i]); -+ -+ kbase_mmu_sync_pgd(kctx->kbdev, -+ kbase_dma_addr(phys_to_page(pgd)) + 8 * idx, -+ 8 * pcount); -+ kunmap(phys_to_page(pgd)); -+ -+next: -+ vpfn += count; -+ } -+} -+ -+/* -+ * Map the single page 'phys' 'nr' of times, starting at GPU PFN 'vpfn' -+ */ -+int kbase_mmu_insert_single_page(struct kbase_context *kctx, u64 vpfn, -+ struct tagged_addr phys, size_t nr, -+ unsigned long flags) -+{ -+ phys_addr_t pgd; -+ u64 *pgd_page; -+ /* In case the insert_single_page only partially completes we need to be -+ * able to recover */ -+ bool recover_required = false; -+ u64 recover_vpfn = vpfn; -+ size_t recover_count = 0; -+ size_t remain = nr; -+ int err; -+ struct kbase_mmu_mode const *mmu_mode; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(0 != vpfn); -+ /* 64-bit address range is the max */ -+ KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE)); -+ -+ mmu_mode = kctx->kbdev->mmu_mode; -+ -+ /* Early out if there is nothing to do */ -+ if (nr == 0) -+ return 0; -+ -+ mutex_lock(&kctx->mmu_lock); -+ -+ while (remain) { -+ unsigned int i; -+ unsigned int index = vpfn & 0x1FF; -+ unsigned int count = KBASE_MMU_PAGE_ENTRIES - index; -+ struct page *p; -+ -+ if (count > remain) -+ count = remain; -+ -+ /* -+ * Repeatedly calling mmu_get_bottom_pte() is clearly -+ * suboptimal. We don't have to re-parse the whole tree -+ * each time (just cache the l0-l2 sequence). -+ * On the other hand, it's only a gain when we map more than -+ * 256 pages at once (on average). Do we really care? -+ */ -+ do { -+ err = mmu_get_bottom_pgd(kctx, vpfn, &pgd); -+ if (err != -ENOMEM) -+ break; -+ /* Fill the memory pool with enough pages for -+ * the page walk to succeed -+ */ -+ mutex_unlock(&kctx->mmu_lock); -+ err = kbase_mem_pool_grow(&kctx->mem_pool, -+ MIDGARD_MMU_BOTTOMLEVEL); -+ mutex_lock(&kctx->mmu_lock); -+ } while (!err); -+ if (err) { -+ dev_warn(kctx->kbdev->dev, "kbase_mmu_insert_pages: mmu_get_bottom_pgd failure\n"); -+ if (recover_required) { -+ /* Invalidate the pages we have partially -+ * completed */ -+ mmu_insert_pages_failure_recovery(kctx, -+ recover_vpfn, -+ recover_vpfn + -+ recover_count -+ ); -+ } -+ goto fail_unlock; -+ } -+ -+ p = pfn_to_page(PFN_DOWN(pgd)); -+ pgd_page = kmap(p); -+ if (!pgd_page) { -+ dev_warn(kctx->kbdev->dev, "kbase_mmu_insert_pages: kmap failure\n"); -+ if (recover_required) { -+ /* Invalidate the pages we have partially -+ * completed */ -+ mmu_insert_pages_failure_recovery(kctx, -+ recover_vpfn, -+ recover_vpfn + -+ recover_count -+ ); -+ } -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+ for (i = 0; i < count; i++) { -+ unsigned int ofs = index + i; -+ -+ /* Fail if the current page is a valid ATE entry */ -+ KBASE_DEBUG_ASSERT(0 == (pgd_page[ofs] & 1UL)); -+ -+ mmu_mode->entry_set_ate(&pgd_page[ofs], -+ phys, flags, -+ MIDGARD_MMU_BOTTOMLEVEL); -+ } -+ -+ vpfn += count; -+ remain -= count; -+ -+ kbase_mmu_sync_pgd(kctx->kbdev, -+ kbase_dma_addr(p) + (index * sizeof(u64)), -+ count * sizeof(u64)); -+ -+ kunmap(p); -+ /* We have started modifying the page table. -+ * If further pages need inserting and fail we need to undo what -+ * has already taken place */ -+ recover_required = true; -+ recover_count += count; -+ } -+ mutex_unlock(&kctx->mmu_lock); -+ kbase_mmu_flush_invalidate(kctx, vpfn, nr, false); -+ return 0; -+ -+fail_unlock: -+ mutex_unlock(&kctx->mmu_lock); -+ kbase_mmu_flush_invalidate(kctx, vpfn, nr, false); -+ return err; -+} -+ -+static inline void cleanup_empty_pte(struct kbase_context *kctx, u64 *pte) -+{ -+ phys_addr_t tmp_pgd; -+ struct page *tmp_p; -+ -+ tmp_pgd = kctx->kbdev->mmu_mode->pte_to_phy_addr(*pte); -+ tmp_p = phys_to_page(tmp_pgd); -+ kbase_mem_pool_free(&kctx->mem_pool, tmp_p, false); -+ kbase_process_page_usage_dec(kctx, 1); -+ kbase_atomic_sub_pages(1, &kctx->used_pages); -+ kbase_atomic_sub_pages(1, &kctx->kbdev->memdev.used_pages); -+} -+ -+int kbase_mmu_insert_pages_no_flush(struct kbase_context *kctx, -+ const u64 start_vpfn, -+ struct tagged_addr *phys, size_t nr, -+ unsigned long flags) -+{ -+ phys_addr_t pgd; -+ u64 *pgd_page; -+ u64 insert_vpfn = start_vpfn; -+ size_t remain = nr; -+ int err; -+ struct kbase_mmu_mode const *mmu_mode; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(start_vpfn); -+ /* 64-bit address range is the max */ -+ KBASE_DEBUG_ASSERT(start_vpfn <= (U64_MAX / PAGE_SIZE)); -+ -+ mmu_mode = kctx->kbdev->mmu_mode; -+ -+ /* Early out if there is nothing to do */ -+ if (nr == 0) -+ return 0; -+ -+ mutex_lock(&kctx->mmu_lock); -+ -+ while (remain) { -+ unsigned int i; -+ unsigned int vindex = insert_vpfn & 0x1FF; -+ unsigned int count = KBASE_MMU_PAGE_ENTRIES - vindex; -+ struct page *p; -+ unsigned int cur_level; -+ -+ if (count > remain) -+ count = remain; -+ -+ if (!vindex && is_huge_head(*phys)) -+ cur_level = MIDGARD_MMU_LEVEL(2); -+ else -+ cur_level = MIDGARD_MMU_BOTTOMLEVEL; -+ -+ /* -+ * Repeatedly calling mmu_get_pgd_at_level() is clearly -+ * suboptimal. We don't have to re-parse the whole tree -+ * each time (just cache the l0-l2 sequence). -+ * On the other hand, it's only a gain when we map more than -+ * 256 pages at once (on average). Do we really care? -+ */ -+ do { -+ err = mmu_get_pgd_at_level(kctx, insert_vpfn, cur_level, -+ &pgd); -+ if (err != -ENOMEM) -+ break; -+ /* Fill the memory pool with enough pages for -+ * the page walk to succeed -+ */ -+ mutex_unlock(&kctx->mmu_lock); -+ err = kbase_mem_pool_grow(&kctx->mem_pool, -+ cur_level); -+ mutex_lock(&kctx->mmu_lock); -+ } while (!err); -+ -+ if (err) { -+ dev_warn(kctx->kbdev->dev, -+ "%s: mmu_get_bottom_pgd failure\n", __func__); -+ if (insert_vpfn != start_vpfn) { -+ /* Invalidate the pages we have partially -+ * completed */ -+ mmu_insert_pages_failure_recovery(kctx, -+ start_vpfn, -+ insert_vpfn); -+ } -+ goto fail_unlock; -+ } -+ -+ p = pfn_to_page(PFN_DOWN(pgd)); -+ pgd_page = kmap(p); -+ if (!pgd_page) { -+ dev_warn(kctx->kbdev->dev, "%s: kmap failure\n", -+ __func__); -+ if (insert_vpfn != start_vpfn) { -+ /* Invalidate the pages we have partially -+ * completed */ -+ mmu_insert_pages_failure_recovery(kctx, -+ start_vpfn, -+ insert_vpfn); -+ } -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+ if (cur_level == MIDGARD_MMU_LEVEL(2)) { -+ unsigned int level_index = (insert_vpfn >> 9) & 0x1FF; -+ u64 *target = &pgd_page[level_index]; -+ -+ if (mmu_mode->pte_is_valid(*target)) -+ cleanup_empty_pte(kctx, target); -+ mmu_mode->entry_set_ate(target, *phys, flags, -+ cur_level); -+ } else { -+ for (i = 0; i < count; i++) { -+ unsigned int ofs = vindex + i; -+ u64 *target = &pgd_page[ofs]; -+ -+ /* Fail if the current page is a valid ATE entry -+ */ -+ KBASE_DEBUG_ASSERT(0 == (*target & 1UL)); -+ -+ kctx->kbdev->mmu_mode->entry_set_ate(target, -+ phys[i], flags, cur_level); -+ } -+ } -+ -+ phys += count; -+ insert_vpfn += count; -+ remain -= count; -+ -+ kbase_mmu_sync_pgd(kctx->kbdev, -+ kbase_dma_addr(p) + (vindex * sizeof(u64)), -+ count * sizeof(u64)); -+ -+ kunmap(p); -+ } -+ -+ mutex_unlock(&kctx->mmu_lock); -+ return 0; -+ -+fail_unlock: -+ mutex_unlock(&kctx->mmu_lock); -+ return err; -+} -+ -+/* -+ * Map 'nr' pages pointed to by 'phys' at GPU PFN 'vpfn' -+ */ -+int kbase_mmu_insert_pages(struct kbase_context *kctx, u64 vpfn, -+ struct tagged_addr *phys, size_t nr, -+ unsigned long flags) -+{ -+ int err; -+ -+ err = kbase_mmu_insert_pages_no_flush(kctx, vpfn, phys, nr, flags); -+ kbase_mmu_flush_invalidate(kctx, vpfn, nr, false); -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mmu_insert_pages); -+ -+/** -+ * kbase_mmu_flush_invalidate_noretain() - Flush and invalidate the GPU caches -+ * without retaining the kbase context. -+ * @kctx: The KBase context. -+ * @vpfn: The virtual page frame number to start the flush on. -+ * @nr: The number of pages to flush. -+ * @sync: Set if the operation should be synchronous or not. -+ * -+ * As per kbase_mmu_flush_invalidate but doesn't retain the kctx or do any -+ * other locking. -+ */ -+static void kbase_mmu_flush_invalidate_noretain(struct kbase_context *kctx, -+ u64 vpfn, size_t nr, bool sync) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ int err; -+ u32 op; -+ -+ /* Early out if there is nothing to do */ -+ if (nr == 0) -+ return; -+ -+ if (sync) -+ op = AS_COMMAND_FLUSH_MEM; -+ else -+ op = AS_COMMAND_FLUSH_PT; -+ -+ err = kbase_mmu_hw_do_operation(kbdev, -+ &kbdev->as[kctx->as_nr], -+ kctx, vpfn, nr, op, 0); -+#if KBASE_GPU_RESET_EN -+ if (err) { -+ /* Flush failed to complete, assume the -+ * GPU has hung and perform a reset to -+ * recover */ -+ dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issuing GPU soft-reset to recover\n"); -+ -+ if (kbase_prepare_to_reset_gpu_locked(kbdev)) -+ kbase_reset_gpu_locked(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ -+#ifndef CONFIG_MALI_NO_MALI -+ /* -+ * As this function could be called in interrupt context the sync -+ * request can't block. Instead log the request and the next flush -+ * request will pick it up. -+ */ -+ if ((!err) && sync && -+ kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_6367)) -+ atomic_set(&kctx->drain_pending, 1); -+#endif /* !CONFIG_MALI_NO_MALI */ -+} -+ -+static void kbase_mmu_flush_invalidate(struct kbase_context *kctx, -+ u64 vpfn, size_t nr, bool sync) -+{ -+ struct kbase_device *kbdev; -+ bool ctx_is_in_runpool; -+#ifndef CONFIG_MALI_NO_MALI -+ bool drain_pending = false; -+ -+ if (atomic_xchg(&kctx->drain_pending, 0)) -+ drain_pending = true; -+#endif /* !CONFIG_MALI_NO_MALI */ -+ -+ /* Early out if there is nothing to do */ -+ if (nr == 0) -+ return; -+ -+ kbdev = kctx->kbdev; -+ mutex_lock(&kbdev->js_data.queue_mutex); -+ ctx_is_in_runpool = kbasep_js_runpool_retain_ctx(kbdev, kctx); -+ mutex_unlock(&kbdev->js_data.queue_mutex); -+ -+ if (ctx_is_in_runpool) { -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ -+ if (!kbase_pm_context_active_handle_suspend(kbdev, -+ KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) { -+ int err; -+ u32 op; -+ -+ /* AS transaction begin */ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ -+ if (sync) -+ op = AS_COMMAND_FLUSH_MEM; -+ else -+ op = AS_COMMAND_FLUSH_PT; -+ -+ err = kbase_mmu_hw_do_operation(kbdev, -+ &kbdev->as[kctx->as_nr], -+ kctx, vpfn, nr, op, 0); -+ -+#if KBASE_GPU_RESET_EN -+ if (err) { -+ /* Flush failed to complete, assume the -+ * GPU has hung and perform a reset to -+ * recover */ -+ dev_err(kbdev->dev, "Flush for GPU page table update did not complete. Issueing GPU soft-reset to recover\n"); -+ -+ if (kbase_prepare_to_reset_gpu(kbdev)) -+ kbase_reset_gpu(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ /* AS transaction end */ -+ -+#ifndef CONFIG_MALI_NO_MALI -+ /* -+ * The transaction lock must be dropped before here -+ * as kbase_wait_write_flush could take it if -+ * the GPU was powered down (static analysis doesn't -+ * know this can't happen). -+ */ -+ drain_pending |= (!err) && sync && -+ kbase_hw_has_issue(kctx->kbdev, -+ BASE_HW_ISSUE_6367); -+ if (drain_pending) { -+ /* Wait for GPU to flush write buffer */ -+ kbase_wait_write_flush(kctx); -+ } -+#endif /* !CONFIG_MALI_NO_MALI */ -+ -+ kbase_pm_context_idle(kbdev); -+ } -+ kbasep_js_runpool_release_ctx(kbdev, kctx); -+ } -+} -+ -+void kbase_mmu_update(struct kbase_context *kctx) -+{ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ lockdep_assert_held(&kctx->kbdev->mmu_hw_mutex); -+ /* ASSERT that the context has a valid as_nr, which is only the case -+ * when it's scheduled in. -+ * -+ * as_nr won't change because the caller has the hwaccess_lock */ -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ -+ kctx->kbdev->mmu_mode->update(kctx); -+} -+KBASE_EXPORT_TEST_API(kbase_mmu_update); -+ -+void kbase_mmu_disable_as(struct kbase_device *kbdev, int as_nr) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ lockdep_assert_held(&kbdev->mmu_hw_mutex); -+ -+ kbdev->mmu_mode->disable_as(kbdev, as_nr); -+} -+ -+void kbase_mmu_disable(struct kbase_context *kctx) -+{ -+ /* ASSERT that the context has a valid as_nr, which is only the case -+ * when it's scheduled in. -+ * -+ * as_nr won't change because the caller has the hwaccess_lock */ -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ -+ lockdep_assert_held(&kctx->kbdev->hwaccess_lock); -+ -+ /* -+ * The address space is being disabled, drain all knowledge of it out -+ * from the caches as pages and page tables might be freed after this. -+ * -+ * The job scheduler code will already be holding the locks and context -+ * so just do the flush. -+ */ -+ kbase_mmu_flush_invalidate_noretain(kctx, 0, ~0, true); -+ -+ kctx->kbdev->mmu_mode->disable_as(kctx->kbdev, kctx->as_nr); -+} -+KBASE_EXPORT_TEST_API(kbase_mmu_disable); -+ -+/* -+ * We actually only discard the ATE, and not the page table -+ * pages. There is a potential DoS here, as we'll leak memory by -+ * having PTEs that are potentially unused. Will require physical -+ * page accounting, so MMU pages are part of the process allocation. -+ * -+ * IMPORTANT: This uses kbasep_js_runpool_release_ctx() when the context is -+ * currently scheduled into the runpool, and so potentially uses a lot of locks. -+ * These locks must be taken in the correct order with respect to others -+ * already held by the caller. Refer to kbasep_js_runpool_release_ctx() for more -+ * information. -+ */ -+int kbase_mmu_teardown_pages(struct kbase_context *kctx, u64 vpfn, size_t nr) -+{ -+ phys_addr_t pgd; -+ size_t requested_nr = nr; -+ struct kbase_mmu_mode const *mmu_mode; -+ int err = -EFAULT; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ beenthere(kctx, "kctx %p vpfn %lx nr %zd", (void *)kctx, (unsigned long)vpfn, nr); -+ -+ if (0 == nr) { -+ /* early out if nothing to do */ -+ return 0; -+ } -+ -+ mutex_lock(&kctx->mmu_lock); -+ -+ mmu_mode = kctx->kbdev->mmu_mode; -+ -+ while (nr) { -+ unsigned int i; -+ unsigned int index = vpfn & 0x1FF; -+ unsigned int count = KBASE_MMU_PAGE_ENTRIES - index; -+ unsigned int pcount; -+ unsigned int level; -+ u64 *page; -+ -+ if (count > nr) -+ count = nr; -+ -+ /* need to check if this is a 2MB or a 4kB page */ -+ pgd = kctx->pgd; -+ -+ for (level = MIDGARD_MMU_TOPLEVEL; -+ level <= MIDGARD_MMU_BOTTOMLEVEL; level++) { -+ phys_addr_t next_pgd; -+ -+ index = (vpfn >> ((3 - level) * 9)) & 0x1FF; -+ page = kmap(phys_to_page(pgd)); -+ if (mmu_mode->ate_is_valid(page[index], level)) -+ break; /* keep the mapping */ -+ else if (!mmu_mode->pte_is_valid(page[index])) { -+ /* nothing here, advance */ -+ switch (level) { -+ case MIDGARD_MMU_LEVEL(0): -+ count = 134217728; -+ break; -+ case MIDGARD_MMU_LEVEL(1): -+ count = 262144; -+ break; -+ case MIDGARD_MMU_LEVEL(2): -+ count = 512; -+ break; -+ case MIDGARD_MMU_LEVEL(3): -+ count = 1; -+ break; -+ } -+ if (count > nr) -+ count = nr; -+ goto next; -+ } -+ next_pgd = mmu_mode->pte_to_phy_addr(page[index]); -+ kunmap(phys_to_page(pgd)); -+ pgd = next_pgd; -+ } -+ -+ switch (level) { -+ case MIDGARD_MMU_LEVEL(0): -+ case MIDGARD_MMU_LEVEL(1): -+ dev_warn(kctx->kbdev->dev, -+ "%s: No support for ATEs at level %d\n", -+ __func__, level); -+ kunmap(phys_to_page(pgd)); -+ goto out; -+ case MIDGARD_MMU_LEVEL(2): -+ /* can only teardown if count >= 512 */ -+ if (count >= 512) { -+ pcount = 1; -+ } else { -+ dev_warn(kctx->kbdev->dev, -+ "%s: limiting teardown as it tries to do a partial 2MB teardown, need 512, but have %d to tear down\n", -+ __func__, count); -+ pcount = 0; -+ } -+ break; -+ case MIDGARD_MMU_BOTTOMLEVEL: -+ /* page count is the same as the logical count */ -+ pcount = count; -+ break; -+ default: -+ dev_err(kctx->kbdev->dev, -+ "%s: found non-mapped memory, early out\n", -+ __func__); -+ vpfn += count; -+ nr -= count; -+ continue; -+ } -+ -+ /* Invalidate the entries we added */ -+ for (i = 0; i < pcount; i++) -+ mmu_mode->entry_invalidate(&page[index + i]); -+ -+ kbase_mmu_sync_pgd(kctx->kbdev, -+ kbase_dma_addr(phys_to_page(pgd)) + -+ 8 * index, 8*pcount); -+ -+next: -+ kunmap(phys_to_page(pgd)); -+ vpfn += count; -+ nr -= count; -+ } -+ err = 0; -+out: -+ mutex_unlock(&kctx->mmu_lock); -+ kbase_mmu_flush_invalidate(kctx, vpfn, requested_nr, true); -+ return err; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mmu_teardown_pages); -+ -+/** -+ * Update the entries for specified number of pages pointed to by 'phys' at GPU PFN 'vpfn'. -+ * This call is being triggered as a response to the changes of the mem attributes -+ * -+ * @pre : The caller is responsible for validating the memory attributes -+ * -+ * IMPORTANT: This uses kbasep_js_runpool_release_ctx() when the context is -+ * currently scheduled into the runpool, and so potentially uses a lot of locks. -+ * These locks must be taken in the correct order with respect to others -+ * already held by the caller. Refer to kbasep_js_runpool_release_ctx() for more -+ * information. -+ */ -+int kbase_mmu_update_pages(struct kbase_context *kctx, u64 vpfn, -+ struct tagged_addr *phys, size_t nr, -+ unsigned long flags) -+{ -+ phys_addr_t pgd; -+ u64 *pgd_page; -+ size_t requested_nr = nr; -+ struct kbase_mmu_mode const *mmu_mode; -+ int err; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(0 != vpfn); -+ KBASE_DEBUG_ASSERT(vpfn <= (U64_MAX / PAGE_SIZE)); -+ -+ /* Early out if there is nothing to do */ -+ if (nr == 0) -+ return 0; -+ -+ mutex_lock(&kctx->mmu_lock); -+ -+ mmu_mode = kctx->kbdev->mmu_mode; -+ -+ dev_warn(kctx->kbdev->dev, "kbase_mmu_update_pages(): updating page share flags on GPU PFN 0x%llx from phys %p, %zu pages", -+ vpfn, phys, nr); -+ -+ while (nr) { -+ unsigned int i; -+ unsigned int index = vpfn & 0x1FF; -+ size_t count = KBASE_MMU_PAGE_ENTRIES - index; -+ struct page *p; -+ -+ if (count > nr) -+ count = nr; -+ -+ do { -+ err = mmu_get_bottom_pgd(kctx, vpfn, &pgd); -+ if (err != -ENOMEM) -+ break; -+ /* Fill the memory pool with enough pages for -+ * the page walk to succeed -+ */ -+ mutex_unlock(&kctx->mmu_lock); -+ err = kbase_mem_pool_grow(&kctx->mem_pool, -+ MIDGARD_MMU_BOTTOMLEVEL); -+ mutex_lock(&kctx->mmu_lock); -+ } while (!err); -+ if (err) { -+ dev_warn(kctx->kbdev->dev, -+ "mmu_get_bottom_pgd failure\n"); -+ goto fail_unlock; -+ } -+ -+ p = pfn_to_page(PFN_DOWN(pgd)); -+ pgd_page = kmap(p); -+ if (!pgd_page) { -+ dev_warn(kctx->kbdev->dev, "kmap failure\n"); -+ err = -ENOMEM; -+ goto fail_unlock; -+ } -+ -+ for (i = 0; i < count; i++) -+ mmu_mode->entry_set_ate(&pgd_page[index + i], phys[i], -+ flags, MIDGARD_MMU_BOTTOMLEVEL); -+ -+ phys += count; -+ vpfn += count; -+ nr -= count; -+ -+ kbase_mmu_sync_pgd(kctx->kbdev, -+ kbase_dma_addr(p) + (index * sizeof(u64)), -+ count * sizeof(u64)); -+ -+ kunmap(pfn_to_page(PFN_DOWN(pgd))); -+ } -+ -+ mutex_unlock(&kctx->mmu_lock); -+ kbase_mmu_flush_invalidate(kctx, vpfn, requested_nr, true); -+ return 0; -+ -+fail_unlock: -+ mutex_unlock(&kctx->mmu_lock); -+ kbase_mmu_flush_invalidate(kctx, vpfn, requested_nr, true); -+ return err; -+} -+ -+static void mmu_teardown_level(struct kbase_context *kctx, phys_addr_t pgd, -+ int level, u64 *pgd_page_buffer) -+{ -+ phys_addr_t target_pgd; -+ struct page *p; -+ u64 *pgd_page; -+ int i; -+ struct kbase_mmu_mode const *mmu_mode; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ lockdep_assert_held(&kctx->mmu_lock); -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ pgd_page = kmap_atomic(pfn_to_page(PFN_DOWN(pgd))); -+ /* kmap_atomic should NEVER fail. */ -+ KBASE_DEBUG_ASSERT(NULL != pgd_page); -+ /* Copy the page to our preallocated buffer so that we can minimize -+ * kmap_atomic usage */ -+ memcpy(pgd_page_buffer, pgd_page, PAGE_SIZE); -+ kunmap_atomic(pgd_page); -+ pgd_page = pgd_page_buffer; -+ -+ mmu_mode = kctx->kbdev->mmu_mode; -+ -+ for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) { -+ target_pgd = mmu_mode->pte_to_phy_addr(pgd_page[i]); -+ -+ if (target_pgd) { -+ if (mmu_mode->pte_is_valid(pgd_page[i])) { -+ mmu_teardown_level(kctx, -+ target_pgd, -+ level + 1, -+ pgd_page_buffer + -+ (PAGE_SIZE / sizeof(u64))); -+ } -+ } -+ } -+ -+ p = pfn_to_page(PFN_DOWN(pgd)); -+ kbase_mem_pool_free(&kctx->mem_pool, p, true); -+ kbase_process_page_usage_dec(kctx, 1); -+ kbase_atomic_sub_pages(1, &kctx->used_pages); -+ kbase_atomic_sub_pages(1, &kctx->kbdev->memdev.used_pages); -+} -+ -+int kbase_mmu_init(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(NULL == kctx->mmu_teardown_pages); -+ -+ mutex_init(&kctx->mmu_lock); -+ -+ /* Preallocate MMU depth of four pages for mmu_teardown_level to use */ -+ kctx->mmu_teardown_pages = kmalloc(PAGE_SIZE * 4, GFP_KERNEL); -+ -+ if (NULL == kctx->mmu_teardown_pages) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+void kbase_mmu_term(struct kbase_context *kctx) -+{ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(NULL != kctx->mmu_teardown_pages); -+ -+ kfree(kctx->mmu_teardown_pages); -+ kctx->mmu_teardown_pages = NULL; -+} -+ -+void kbase_mmu_free_pgd(struct kbase_context *kctx) -+{ -+ int new_page_count = 0; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ KBASE_DEBUG_ASSERT(NULL != kctx->mmu_teardown_pages); -+ -+ mutex_lock(&kctx->mmu_lock); -+ mmu_teardown_level(kctx, kctx->pgd, MIDGARD_MMU_TOPLEVEL, -+ kctx->mmu_teardown_pages); -+ mutex_unlock(&kctx->mmu_lock); -+ -+ KBASE_TLSTREAM_AUX_PAGESALLOC( -+ (u32)kctx->id, -+ (u64)new_page_count); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_mmu_free_pgd); -+ -+static size_t kbasep_mmu_dump_level(struct kbase_context *kctx, phys_addr_t pgd, int level, char ** const buffer, size_t *size_left) -+{ -+ phys_addr_t target_pgd; -+ u64 *pgd_page; -+ int i; -+ size_t size = KBASE_MMU_PAGE_ENTRIES * sizeof(u64) + sizeof(u64); -+ size_t dump_size; -+ struct kbase_mmu_mode const *mmu_mode; -+ -+ KBASE_DEBUG_ASSERT(NULL != kctx); -+ lockdep_assert_held(&kctx->mmu_lock); -+ -+ mmu_mode = kctx->kbdev->mmu_mode; -+ -+ pgd_page = kmap(pfn_to_page(PFN_DOWN(pgd))); -+ if (!pgd_page) { -+ dev_warn(kctx->kbdev->dev, "kbasep_mmu_dump_level: kmap failure\n"); -+ return 0; -+ } -+ -+ if (*size_left >= size) { -+ /* A modified physical address that contains the page table level */ -+ u64 m_pgd = pgd | level; -+ -+ /* Put the modified physical address in the output buffer */ -+ memcpy(*buffer, &m_pgd, sizeof(m_pgd)); -+ *buffer += sizeof(m_pgd); -+ -+ /* Followed by the page table itself */ -+ memcpy(*buffer, pgd_page, sizeof(u64) * KBASE_MMU_PAGE_ENTRIES); -+ *buffer += sizeof(u64) * KBASE_MMU_PAGE_ENTRIES; -+ -+ *size_left -= size; -+ } -+ -+ if (level < MIDGARD_MMU_BOTTOMLEVEL) { -+ for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) { -+ if (mmu_mode->pte_is_valid(pgd_page[i])) { -+ target_pgd = mmu_mode->pte_to_phy_addr( -+ pgd_page[i]); -+ -+ dump_size = kbasep_mmu_dump_level(kctx, -+ target_pgd, level + 1, -+ buffer, size_left); -+ if (!dump_size) { -+ kunmap(pfn_to_page(PFN_DOWN(pgd))); -+ return 0; -+ } -+ size += dump_size; -+ } -+ } -+ } -+ -+ kunmap(pfn_to_page(PFN_DOWN(pgd))); -+ -+ return size; -+} -+ -+void *kbase_mmu_dump(struct kbase_context *kctx, int nr_pages) -+{ -+ void *kaddr; -+ size_t size_left; -+ -+ KBASE_DEBUG_ASSERT(kctx); -+ -+ if (0 == nr_pages) { -+ /* can't dump in a 0 sized buffer, early out */ -+ return NULL; -+ } -+ -+ size_left = nr_pages * PAGE_SIZE; -+ -+ KBASE_DEBUG_ASSERT(0 != size_left); -+ kaddr = vmalloc_user(size_left); -+ -+ mutex_lock(&kctx->mmu_lock); -+ -+ if (kaddr) { -+ u64 end_marker = 0xFFULL; -+ char *buffer; -+ char *mmu_dump_buffer; -+ u64 config[3]; -+ size_t size; -+ -+ buffer = (char *)kaddr; -+ mmu_dump_buffer = buffer; -+ -+ if (kctx->api_version >= KBASE_API_VERSION(8, 4)) { -+ struct kbase_mmu_setup as_setup; -+ -+ kctx->kbdev->mmu_mode->get_as_setup(kctx, &as_setup); -+ config[0] = as_setup.transtab; -+ config[1] = as_setup.memattr; -+ config[2] = as_setup.transcfg; -+ memcpy(buffer, &config, sizeof(config)); -+ mmu_dump_buffer += sizeof(config); -+ size_left -= sizeof(config); -+ } -+ -+ -+ -+ size = kbasep_mmu_dump_level(kctx, -+ kctx->pgd, -+ MIDGARD_MMU_TOPLEVEL, -+ &mmu_dump_buffer, -+ &size_left); -+ -+ if (!size) -+ goto fail_free; -+ -+ /* Add on the size for the end marker */ -+ size += sizeof(u64); -+ /* Add on the size for the config */ -+ if (kctx->api_version >= KBASE_API_VERSION(8, 4)) -+ size += sizeof(config); -+ -+ -+ if (size > nr_pages * PAGE_SIZE || size_left < sizeof(u64)) { -+ /* The buffer isn't big enough - free the memory and return failure */ -+ goto fail_free; -+ } -+ -+ /* Add the end marker */ -+ memcpy(mmu_dump_buffer, &end_marker, sizeof(u64)); -+ } -+ -+ mutex_unlock(&kctx->mmu_lock); -+ return kaddr; -+ -+fail_free: -+ vfree(kaddr); -+ mutex_unlock(&kctx->mmu_lock); -+ return NULL; -+} -+KBASE_EXPORT_TEST_API(kbase_mmu_dump); -+ -+void bus_fault_worker(struct work_struct *data) -+{ -+ struct kbase_as *faulting_as; -+ int as_no; -+ struct kbase_context *kctx; -+ struct kbase_device *kbdev; -+#if KBASE_GPU_RESET_EN -+ bool reset_status = false; -+#endif /* KBASE_GPU_RESET_EN */ -+ -+ faulting_as = container_of(data, struct kbase_as, work_busfault); -+ -+ as_no = faulting_as->number; -+ -+ kbdev = container_of(faulting_as, struct kbase_device, as[as_no]); -+ -+ /* Grab the context that was already refcounted in kbase_mmu_interrupt(). -+ * Therefore, it cannot be scheduled out of this AS until we explicitly release it -+ */ -+ kctx = kbasep_js_runpool_lookup_ctx_noretain(kbdev, as_no); -+ if (WARN_ON(!kctx)) { -+ atomic_dec(&kbdev->faults_pending); -+ return; -+ } -+ -+ if (unlikely(faulting_as->protected_mode)) -+ { -+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, -+ "Permission failure"); -+ kbase_mmu_hw_clear_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED); -+ kbasep_js_runpool_release_ctx(kbdev, kctx); -+ atomic_dec(&kbdev->faults_pending); -+ return; -+ -+ } -+ -+#if KBASE_GPU_RESET_EN -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245)) { -+ /* Due to H/W issue 8245 we need to reset the GPU after using UNMAPPED mode. -+ * We start the reset before switching to UNMAPPED to ensure that unrelated jobs -+ * are evicted from the GPU before the switch. -+ */ -+ dev_err(kbdev->dev, "GPU bus error occurred. For this GPU version we now soft-reset as part of bus error recovery\n"); -+ reset_status = kbase_prepare_to_reset_gpu(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ /* NOTE: If GPU already powered off for suspend, we don't need to switch to unmapped */ -+ if (!kbase_pm_context_active_handle_suspend(kbdev, KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE)) { -+ unsigned long flags; -+ -+ /* switch to UNMAPPED mode, will abort all jobs and stop any hw counter dumping */ -+ /* AS transaction begin */ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ -+ /* Set the MMU into unmapped mode */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_mmu_disable(kctx); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ /* AS transaction end */ -+ -+ kbase_mmu_hw_clear_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED); -+ kbase_mmu_hw_enable_fault(kbdev, faulting_as, kctx, -+ KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED); -+ -+ kbase_pm_context_idle(kbdev); -+ } -+ -+#if KBASE_GPU_RESET_EN -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245) && reset_status) -+ kbase_reset_gpu(kbdev); -+#endif /* KBASE_GPU_RESET_EN */ -+ -+ kbasep_js_runpool_release_ctx(kbdev, kctx); -+ -+ atomic_dec(&kbdev->faults_pending); -+} -+ -+const char *kbase_exception_name(struct kbase_device *kbdev, u32 exception_code) -+{ -+ const char *e; -+ -+ switch (exception_code) { -+ /* Non-Fault Status code */ -+ case 0x00: -+ e = "NOT_STARTED/IDLE/OK"; -+ break; -+ case 0x01: -+ e = "DONE"; -+ break; -+ case 0x02: -+ e = "INTERRUPTED"; -+ break; -+ case 0x03: -+ e = "STOPPED"; -+ break; -+ case 0x04: -+ e = "TERMINATED"; -+ break; -+ case 0x08: -+ e = "ACTIVE"; -+ break; -+ /* Job exceptions */ -+ case 0x40: -+ e = "JOB_CONFIG_FAULT"; -+ break; -+ case 0x41: -+ e = "JOB_POWER_FAULT"; -+ break; -+ case 0x42: -+ e = "JOB_READ_FAULT"; -+ break; -+ case 0x43: -+ e = "JOB_WRITE_FAULT"; -+ break; -+ case 0x44: -+ e = "JOB_AFFINITY_FAULT"; -+ break; -+ case 0x48: -+ e = "JOB_BUS_FAULT"; -+ break; -+ case 0x50: -+ e = "INSTR_INVALID_PC"; -+ break; -+ case 0x51: -+ e = "INSTR_INVALID_ENC"; -+ break; -+ case 0x52: -+ e = "INSTR_TYPE_MISMATCH"; -+ break; -+ case 0x53: -+ e = "INSTR_OPERAND_FAULT"; -+ break; -+ case 0x54: -+ e = "INSTR_TLS_FAULT"; -+ break; -+ case 0x55: -+ e = "INSTR_BARRIER_FAULT"; -+ break; -+ case 0x56: -+ e = "INSTR_ALIGN_FAULT"; -+ break; -+ case 0x58: -+ e = "DATA_INVALID_FAULT"; -+ break; -+ case 0x59: -+ e = "TILE_RANGE_FAULT"; -+ break; -+ case 0x5A: -+ e = "ADDR_RANGE_FAULT"; -+ break; -+ case 0x60: -+ e = "OUT_OF_MEMORY"; -+ break; -+ /* GPU exceptions */ -+ case 0x80: -+ e = "DELAYED_BUS_FAULT"; -+ break; -+ case 0x88: -+ e = "SHAREABILITY_FAULT"; -+ break; -+ /* MMU exceptions */ -+ case 0xC0: -+ case 0xC1: -+ case 0xC2: -+ case 0xC3: -+ case 0xC4: -+ case 0xC5: -+ case 0xC6: -+ case 0xC7: -+ e = "TRANSLATION_FAULT"; -+ break; -+ case 0xC8: -+ e = "PERMISSION_FAULT"; -+ break; -+ case 0xC9: -+ case 0xCA: -+ case 0xCB: -+ case 0xCC: -+ case 0xCD: -+ case 0xCE: -+ case 0xCF: -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ e = "PERMISSION_FAULT"; -+ else -+ e = "UNKNOWN"; -+ break; -+ case 0xD0: -+ case 0xD1: -+ case 0xD2: -+ case 0xD3: -+ case 0xD4: -+ case 0xD5: -+ case 0xD6: -+ case 0xD7: -+ e = "TRANSTAB_BUS_FAULT"; -+ break; -+ case 0xD8: -+ e = "ACCESS_FLAG"; -+ break; -+ case 0xD9: -+ case 0xDA: -+ case 0xDB: -+ case 0xDC: -+ case 0xDD: -+ case 0xDE: -+ case 0xDF: -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ e = "ACCESS_FLAG"; -+ else -+ e = "UNKNOWN"; -+ break; -+ case 0xE0: -+ case 0xE1: -+ case 0xE2: -+ case 0xE3: -+ case 0xE4: -+ case 0xE5: -+ case 0xE6: -+ case 0xE7: -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ e = "ADDRESS_SIZE_FAULT"; -+ else -+ e = "UNKNOWN"; -+ break; -+ case 0xE8: -+ case 0xE9: -+ case 0xEA: -+ case 0xEB: -+ case 0xEC: -+ case 0xED: -+ case 0xEE: -+ case 0xEF: -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ e = "MEMORY_ATTRIBUTES_FAULT"; -+ else -+ e = "UNKNOWN"; -+ break; -+ default: -+ e = "UNKNOWN"; -+ break; -+ }; -+ -+ return e; -+} -+ -+static const char *access_type_name(struct kbase_device *kbdev, -+ u32 fault_status) -+{ -+ switch (fault_status & AS_FAULTSTATUS_ACCESS_TYPE_MASK) { -+ case AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC: -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ return "ATOMIC"; -+ else -+ return "UNKNOWN"; -+ case AS_FAULTSTATUS_ACCESS_TYPE_READ: -+ return "READ"; -+ case AS_FAULTSTATUS_ACCESS_TYPE_WRITE: -+ return "WRITE"; -+ case AS_FAULTSTATUS_ACCESS_TYPE_EX: -+ return "EXECUTE"; -+ default: -+ WARN_ON(1); -+ return NULL; -+ } -+} -+ -+/** -+ * The caller must ensure it's retained the ctx to prevent it from being scheduled out whilst it's being worked on. -+ */ -+static void kbase_mmu_report_fault_and_kill(struct kbase_context *kctx, -+ struct kbase_as *as, const char *reason_str) -+{ -+ unsigned long flags; -+ int exception_type; -+ int access_type; -+ int source_id; -+ int as_no; -+ struct kbase_device *kbdev; -+ struct kbasep_js_device_data *js_devdata; -+ -+#if KBASE_GPU_RESET_EN -+ bool reset_status = false; -+#endif -+ -+ as_no = as->number; -+ kbdev = kctx->kbdev; -+ js_devdata = &kbdev->js_data; -+ -+ /* ASSERT that the context won't leave the runpool */ -+ KBASE_DEBUG_ASSERT(atomic_read(&kctx->refcount) > 0); -+ -+ /* decode the fault status */ -+ exception_type = as->fault_status & 0xFF; -+ access_type = (as->fault_status >> 8) & 0x3; -+ source_id = (as->fault_status >> 16); -+ -+ /* terminal fault, print info about the fault */ -+ dev_err(kbdev->dev, -+ "Unhandled Page fault in AS%d at VA 0x%016llX\n" -+ "Reason: %s\n" -+ "raw fault status: 0x%X\n" -+ "decoded fault status: %s\n" -+ "exception type 0x%X: %s\n" -+ "access type 0x%X: %s\n" -+ "source id 0x%X\n" -+ "pid: %d\n", -+ as_no, as->fault_addr, -+ reason_str, -+ as->fault_status, -+ (as->fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"), -+ exception_type, kbase_exception_name(kbdev, exception_type), -+ access_type, access_type_name(kbdev, as->fault_status), -+ source_id, -+ kctx->pid); -+ -+ /* hardware counters dump fault handling */ -+ if ((kbdev->hwcnt.kctx) && (kbdev->hwcnt.kctx->as_nr == as_no) && -+ (kbdev->hwcnt.backend.state == -+ KBASE_INSTR_STATE_DUMPING)) { -+ unsigned int num_core_groups = kbdev->gpu_props.num_core_groups; -+ -+ if ((as->fault_addr >= kbdev->hwcnt.addr) && -+ (as->fault_addr < (kbdev->hwcnt.addr + -+ (num_core_groups * 2048)))) -+ kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_FAULT; -+ } -+ -+ /* Stop the kctx from submitting more jobs and cause it to be scheduled -+ * out/rescheduled - this will occur on releasing the context's refcount */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbasep_js_clear_submit_allowed(js_devdata, kctx); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ /* Kill any running jobs from the context. Submit is disallowed, so no more jobs from this -+ * context can appear in the job slots from this point on */ -+ kbase_backend_jm_kill_jobs_from_kctx(kctx); -+ /* AS transaction begin */ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+#if KBASE_GPU_RESET_EN -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245)) { -+ /* Due to H/W issue 8245 we need to reset the GPU after using UNMAPPED mode. -+ * We start the reset before switching to UNMAPPED to ensure that unrelated jobs -+ * are evicted from the GPU before the switch. -+ */ -+ dev_err(kbdev->dev, "Unhandled page fault. For this GPU version we now soft-reset the GPU as part of page fault recovery."); -+ reset_status = kbase_prepare_to_reset_gpu(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ /* switch to UNMAPPED mode, will abort all jobs and stop any hw counter dumping */ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_mmu_disable(kctx); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ /* AS transaction end */ -+ /* Clear down the fault */ -+ kbase_mmu_hw_clear_fault(kbdev, as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE_UNEXPECTED); -+ kbase_mmu_hw_enable_fault(kbdev, as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE_UNEXPECTED); -+ -+#if KBASE_GPU_RESET_EN -+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245) && reset_status) -+ kbase_reset_gpu(kbdev); -+#endif /* KBASE_GPU_RESET_EN */ -+} -+ -+void kbasep_as_do_poke(struct work_struct *work) -+{ -+ struct kbase_as *as; -+ struct kbase_device *kbdev; -+ struct kbase_context *kctx; -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(work); -+ as = container_of(work, struct kbase_as, poke_work); -+ kbdev = container_of(as, struct kbase_device, as[as->number]); -+ KBASE_DEBUG_ASSERT(as->poke_state & KBASE_AS_POKE_STATE_IN_FLIGHT); -+ -+ /* GPU power will already be active by virtue of the caller holding a JS -+ * reference on the address space, and will not release it until this worker -+ * has finished */ -+ -+ /* Further to the comment above, we know that while this function is running -+ * the AS will not be released as before the atom is released this workqueue -+ * is flushed (in kbase_as_poking_timer_release_atom) -+ */ -+ kctx = kbasep_js_runpool_lookup_ctx_noretain(kbdev, as->number); -+ -+ /* AS transaction begin */ -+ mutex_lock(&kbdev->mmu_hw_mutex); -+ /* Force a uTLB invalidate */ -+ kbase_mmu_hw_do_operation(kbdev, as, kctx, 0, 0, -+ AS_COMMAND_UNLOCK, 0); -+ mutex_unlock(&kbdev->mmu_hw_mutex); -+ /* AS transaction end */ -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ if (as->poke_refcount && -+ !(as->poke_state & KBASE_AS_POKE_STATE_KILLING_POKE)) { -+ /* Only queue up the timer if we need it, and we're not trying to kill it */ -+ hrtimer_start(&as->poke_timer, HR_TIMER_DELAY_MSEC(5), HRTIMER_MODE_REL); -+ } -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+} -+ -+enum hrtimer_restart kbasep_as_poke_timer_callback(struct hrtimer *timer) -+{ -+ struct kbase_as *as; -+ int queue_work_ret; -+ -+ KBASE_DEBUG_ASSERT(NULL != timer); -+ as = container_of(timer, struct kbase_as, poke_timer); -+ KBASE_DEBUG_ASSERT(as->poke_state & KBASE_AS_POKE_STATE_IN_FLIGHT); -+ -+ queue_work_ret = queue_work(as->poke_wq, &as->poke_work); -+ KBASE_DEBUG_ASSERT(queue_work_ret); -+ return HRTIMER_NORESTART; -+} -+ -+/** -+ * Retain the poking timer on an atom's context (if the atom hasn't already -+ * done so), and start the timer (if it's not already started). -+ * -+ * This must only be called on a context that's scheduled in, and an atom -+ * that's running on the GPU. -+ * -+ * The caller must hold hwaccess_lock -+ * -+ * This can be called safely from atomic context -+ */ -+void kbase_as_poking_timer_retain_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ struct kbase_as *as; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(katom); -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (katom->poking) -+ return; -+ -+ katom->poking = 1; -+ -+ /* It's safe to work on the as/as_nr without an explicit reference, -+ * because the caller holds the hwaccess_lock, and the atom itself -+ * was also running and had already taken a reference */ -+ as = &kbdev->as[kctx->as_nr]; -+ -+ if (++(as->poke_refcount) == 1) { -+ /* First refcount for poke needed: check if not already in flight */ -+ if (!as->poke_state) { -+ /* need to start poking */ -+ as->poke_state |= KBASE_AS_POKE_STATE_IN_FLIGHT; -+ queue_work(as->poke_wq, &as->poke_work); -+ } -+ } -+} -+ -+/** -+ * If an atom holds a poking timer, release it and wait for it to finish -+ * -+ * This must only be called on a context that's scheduled in, and an atom -+ * that still has a JS reference on the context -+ * -+ * This must \b not be called from atomic context, since it can sleep. -+ */ -+void kbase_as_poking_timer_release_atom(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom) -+{ -+ struct kbase_as *as; -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ KBASE_DEBUG_ASSERT(kctx); -+ KBASE_DEBUG_ASSERT(katom); -+ KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); -+ -+ if (!katom->poking) -+ return; -+ -+ as = &kbdev->as[kctx->as_nr]; -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ KBASE_DEBUG_ASSERT(as->poke_refcount > 0); -+ KBASE_DEBUG_ASSERT(as->poke_state & KBASE_AS_POKE_STATE_IN_FLIGHT); -+ -+ if (--(as->poke_refcount) == 0) { -+ as->poke_state |= KBASE_AS_POKE_STATE_KILLING_POKE; -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ hrtimer_cancel(&as->poke_timer); -+ flush_workqueue(as->poke_wq); -+ -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ -+ /* Re-check whether it's still needed */ -+ if (as->poke_refcount) { -+ int queue_work_ret; -+ /* Poking still needed: -+ * - Another retain will not be starting the timer or queueing work, -+ * because it's still marked as in-flight -+ * - The hrtimer has finished, and has not started a new timer or -+ * queued work because it's been marked as killing -+ * -+ * So whatever happens now, just queue the work again */ -+ as->poke_state &= ~((kbase_as_poke_state)KBASE_AS_POKE_STATE_KILLING_POKE); -+ queue_work_ret = queue_work(as->poke_wq, &as->poke_work); -+ KBASE_DEBUG_ASSERT(queue_work_ret); -+ } else { -+ /* It isn't - so mark it as not in flight, and not killing */ -+ as->poke_state = 0u; -+ -+ /* The poke associated with the atom has now finished. If this is -+ * also the last atom on the context, then we can guarentee no more -+ * pokes (and thus no more poking register accesses) will occur on -+ * the context until new atoms are run */ -+ } -+ } -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ -+ katom->poking = 0; -+} -+ -+void kbase_mmu_interrupt_process(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_as *as) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (!kctx) { -+ dev_warn(kbdev->dev, "%s in AS%d at 0x%016llx with no context present! Suprious IRQ or SW Design Error?\n", -+ kbase_as_has_bus_fault(as) ? "Bus error" : "Page fault", -+ as->number, as->fault_addr); -+ -+ /* Since no ctx was found, the MMU must be disabled. */ -+ WARN_ON(as->current_setup.transtab); -+ -+ if (kbase_as_has_bus_fault(as)) { -+ kbase_mmu_hw_clear_fault(kbdev, as, kctx, -+ KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED); -+ kbase_mmu_hw_enable_fault(kbdev, as, kctx, -+ KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED); -+ } else if (kbase_as_has_page_fault(as)) { -+ kbase_mmu_hw_clear_fault(kbdev, as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE_UNEXPECTED); -+ kbase_mmu_hw_enable_fault(kbdev, as, kctx, -+ KBASE_MMU_FAULT_TYPE_PAGE_UNEXPECTED); -+ } -+ -+#if KBASE_GPU_RESET_EN -+ if (kbase_as_has_bus_fault(as) && -+ kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245)) { -+ bool reset_status; -+ /* -+ * Reset the GPU, like in bus_fault_worker, in case an -+ * earlier error hasn't been properly cleared by this -+ * point. -+ */ -+ dev_err(kbdev->dev, "GPU bus error occurred. For this GPU version we now soft-reset as part of bus error recovery\n"); -+ reset_status = kbase_prepare_to_reset_gpu_locked(kbdev); -+ if (reset_status) -+ kbase_reset_gpu_locked(kbdev); -+ } -+#endif /* KBASE_GPU_RESET_EN */ -+ -+ return; -+ } -+ -+ if (kbase_as_has_bus_fault(as)) { -+ /* -+ * hw counters dumping in progress, signal the -+ * other thread that it failed -+ */ -+ if ((kbdev->hwcnt.kctx == kctx) && -+ (kbdev->hwcnt.backend.state == -+ KBASE_INSTR_STATE_DUMPING)) -+ kbdev->hwcnt.backend.state = -+ KBASE_INSTR_STATE_FAULT; -+ -+ /* -+ * Stop the kctx from submitting more jobs and cause it -+ * to be scheduled out/rescheduled when all references -+ * to it are released -+ */ -+ kbasep_js_clear_submit_allowed(js_devdata, kctx); -+ -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU)) -+ dev_warn(kbdev->dev, -+ "Bus error in AS%d at VA=0x%016llx, IPA=0x%016llx\n", -+ as->number, as->fault_addr, -+ as->fault_extra_addr); -+ else -+ dev_warn(kbdev->dev, "Bus error in AS%d at 0x%016llx\n", -+ as->number, as->fault_addr); -+ -+ /* -+ * We need to switch to UNMAPPED mode - but we do this in a -+ * worker so that we can sleep -+ */ -+ KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&as->work_busfault)); -+ WARN_ON(work_pending(&as->work_busfault)); -+ queue_work(as->pf_wq, &as->work_busfault); -+ atomic_inc(&kbdev->faults_pending); -+ } else { -+ KBASE_DEBUG_ASSERT(0 == object_is_on_stack(&as->work_pagefault)); -+ WARN_ON(work_pending(&as->work_pagefault)); -+ queue_work(as->pf_wq, &as->work_pagefault); -+ atomic_inc(&kbdev->faults_pending); -+ } -+} -+ -+void kbase_flush_mmu_wqs(struct kbase_device *kbdev) -+{ -+ int i; -+ -+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++) { -+ struct kbase_as *as = &kbdev->as[i]; -+ -+ flush_workqueue(as->pf_wq); -+ } -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mmu_hw.h b/drivers/gpu/arm/midgard/mali_kbase_mmu_hw.h -new file mode 100644 -index 0000000..986e959 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mmu_hw.h -@@ -0,0 +1,123 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @file -+ * Interface file for accessing MMU hardware functionality -+ */ -+ -+/** -+ * @page mali_kbase_mmu_hw_page MMU hardware interface -+ * -+ * @section mali_kbase_mmu_hw_intro_sec Introduction -+ * This module provides an abstraction for accessing the functionality provided -+ * by the midgard MMU and thus allows all MMU HW access to be contained within -+ * one common place and allows for different backends (implementations) to -+ * be provided. -+ */ -+ -+#ifndef _MALI_KBASE_MMU_HW_H_ -+#define _MALI_KBASE_MMU_HW_H_ -+ -+/* Forward declarations */ -+struct kbase_device; -+struct kbase_as; -+struct kbase_context; -+ -+/** -+ * @addtogroup base_kbase_api -+ * @{ -+ */ -+ -+/** -+ * @addtogroup mali_kbase_mmu_hw MMU access APIs -+ * @{ -+ */ -+ -+/** @brief MMU fault type descriptor. -+ */ -+enum kbase_mmu_fault_type { -+ KBASE_MMU_FAULT_TYPE_UNKNOWN = 0, -+ KBASE_MMU_FAULT_TYPE_PAGE, -+ KBASE_MMU_FAULT_TYPE_BUS, -+ KBASE_MMU_FAULT_TYPE_PAGE_UNEXPECTED, -+ KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED -+}; -+ -+/** @brief Configure an address space for use. -+ * -+ * Configure the MMU using the address space details setup in the -+ * @ref kbase_context structure. -+ * -+ * @param[in] kbdev kbase device to configure. -+ * @param[in] as address space to configure. -+ * @param[in] kctx kbase context to configure. -+ */ -+void kbase_mmu_hw_configure(struct kbase_device *kbdev, -+ struct kbase_as *as, struct kbase_context *kctx); -+ -+/** @brief Issue an operation to the MMU. -+ * -+ * Issue an operation (MMU invalidate, MMU flush, etc) on the address space that -+ * is associated with the provided @ref kbase_context over the specified range -+ * -+ * @param[in] kbdev kbase device to issue the MMU operation on. -+ * @param[in] as address space to issue the MMU operation on. -+ * @param[in] kctx kbase context to issue the MMU operation on. -+ * @param[in] vpfn MMU Virtual Page Frame Number to start the -+ * operation on. -+ * @param[in] nr Number of pages to work on. -+ * @param[in] type Operation type (written to ASn_COMMAND). -+ * @param[in] handling_irq Is this operation being called during the handling -+ * of an interrupt? -+ * -+ * @return Zero if the operation was successful, non-zero otherwise. -+ */ -+int kbase_mmu_hw_do_operation(struct kbase_device *kbdev, struct kbase_as *as, -+ struct kbase_context *kctx, u64 vpfn, u32 nr, u32 type, -+ unsigned int handling_irq); -+ -+/** @brief Clear a fault that has been previously reported by the MMU. -+ * -+ * Clear a bus error or page fault that has been reported by the MMU. -+ * -+ * @param[in] kbdev kbase device to clear the fault from. -+ * @param[in] as address space to clear the fault from. -+ * @param[in] kctx kbase context to clear the fault from or NULL. -+ * @param[in] type The type of fault that needs to be cleared. -+ */ -+void kbase_mmu_hw_clear_fault(struct kbase_device *kbdev, struct kbase_as *as, -+ struct kbase_context *kctx, enum kbase_mmu_fault_type type); -+ -+/** @brief Enable fault that has been previously reported by the MMU. -+ * -+ * After a page fault or bus error has been reported by the MMU these -+ * will be disabled. After these are handled this function needs to be -+ * called to enable the page fault or bus error fault again. -+ * -+ * @param[in] kbdev kbase device to again enable the fault from. -+ * @param[in] as address space to again enable the fault from. -+ * @param[in] kctx kbase context to again enable the fault from. -+ * @param[in] type The type of fault that needs to be enabled again. -+ */ -+void kbase_mmu_hw_enable_fault(struct kbase_device *kbdev, struct kbase_as *as, -+ struct kbase_context *kctx, enum kbase_mmu_fault_type type); -+ -+/** @} *//* end group mali_kbase_mmu_hw */ -+/** @} *//* end group base_kbase_api */ -+ -+#endif /* _MALI_KBASE_MMU_HW_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mmu_mode.h b/drivers/gpu/arm/midgard/mali_kbase_mmu_mode.h -new file mode 100644 -index 0000000..a2c3862 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mmu_mode.h -@@ -0,0 +1,49 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015,2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _MALI_KBASE_MMU_MODE_ -+#define _MALI_KBASE_MMU_MODE_ -+ -+#include -+#include -+ -+/* Forward declarations */ -+struct kbase_context; -+struct kbase_device; -+struct kbase_as; -+struct kbase_mmu_setup; -+ -+struct kbase_mmu_mode { -+ void (*update)(struct kbase_context *kctx); -+ void (*get_as_setup)(struct kbase_context *kctx, -+ struct kbase_mmu_setup * const setup); -+ void (*disable_as)(struct kbase_device *kbdev, int as_nr); -+ phys_addr_t (*pte_to_phy_addr)(u64 entry); -+ int (*ate_is_valid)(u64 ate, unsigned int level); -+ int (*pte_is_valid)(u64 pte); -+ void (*entry_set_ate)(u64 *entry, struct tagged_addr phy, -+ unsigned long flags, unsigned int level); -+ void (*entry_set_pte)(u64 *entry, phys_addr_t phy); -+ void (*entry_invalidate)(u64 *entry); -+}; -+ -+struct kbase_mmu_mode const *kbase_mmu_mode_get_lpae(void); -+struct kbase_mmu_mode const *kbase_mmu_mode_get_aarch64(void); -+ -+#endif /* _MALI_KBASE_MMU_MODE_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mmu_mode_aarch64.c b/drivers/gpu/arm/midgard/mali_kbase_mmu_mode_aarch64.c -new file mode 100644 -index 0000000..eccb33a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mmu_mode_aarch64.c -@@ -0,0 +1,212 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2014, 2016-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include "mali_kbase_mmu_mode.h" -+ -+#include "mali_kbase.h" -+#include "mali_midg_regmap.h" -+ -+#define ENTRY_TYPE_MASK 3ULL -+/* For valid ATEs bit 1 = ((level == 3) ? 1 : 0). -+ * Valid ATE entries at level 3 are flagged with the value 3. -+ * Valid ATE entries at level 0-2 are flagged with the value 1. -+ */ -+#define ENTRY_IS_ATE_L3 3ULL -+#define ENTRY_IS_ATE_L02 1ULL -+#define ENTRY_IS_INVAL 2ULL -+#define ENTRY_IS_PTE 3ULL -+ -+#define ENTRY_ATTR_BITS (7ULL << 2) /* bits 4:2 */ -+#define ENTRY_ACCESS_RW (1ULL << 6) /* bits 6:7 */ -+#define ENTRY_ACCESS_RO (3ULL << 6) -+#define ENTRY_SHARE_BITS (3ULL << 8) /* bits 9:8 */ -+#define ENTRY_ACCESS_BIT (1ULL << 10) -+#define ENTRY_NX_BIT (1ULL << 54) -+ -+/* Helper Function to perform assignment of page table entries, to -+ * ensure the use of strd, which is required on LPAE systems. -+ */ -+static inline void page_table_entry_set(u64 *pte, u64 phy) -+{ -+#ifdef CONFIG_64BIT -+ *pte = phy; -+#elif defined(CONFIG_ARM) -+ /* -+ * In order to prevent the compiler keeping cached copies of -+ * memory, we have to explicitly say that we have updated memory. -+ * -+ * Note: We could manually move the data ourselves into R0 and -+ * R1 by specifying register variables that are explicitly -+ * given registers assignments, the down side of this is that -+ * we have to assume cpu endianness. To avoid this we can use -+ * the ldrd to read the data from memory into R0 and R1 which -+ * will respect the cpu endianness, we then use strd to make -+ * the 64 bit assignment to the page table entry. -+ */ -+ asm volatile("ldrd r0, r1, [%[ptemp]]\n\t" -+ "strd r0, r1, [%[pte]]\n\t" -+ : "=m" (*pte) -+ : [ptemp] "r" (&phy), [pte] "r" (pte), "m" (phy) -+ : "r0", "r1"); -+#else -+#error "64-bit atomic write must be implemented for your architecture" -+#endif -+} -+ -+static void mmu_get_as_setup(struct kbase_context *kctx, -+ struct kbase_mmu_setup * const setup) -+{ -+ /* Set up the required caching policies at the correct indices -+ * in the memattr register. -+ */ -+ setup->memattr = -+ (AS_MEMATTR_IMPL_DEF_CACHE_POLICY << -+ (AS_MEMATTR_INDEX_IMPL_DEF_CACHE_POLICY * 8)) | -+ (AS_MEMATTR_FORCE_TO_CACHE_ALL << -+ (AS_MEMATTR_INDEX_FORCE_TO_CACHE_ALL * 8)) | -+ (AS_MEMATTR_WRITE_ALLOC << -+ (AS_MEMATTR_INDEX_WRITE_ALLOC * 8)) | -+ (AS_MEMATTR_AARCH64_OUTER_IMPL_DEF << -+ (AS_MEMATTR_INDEX_OUTER_IMPL_DEF * 8)) | -+ (AS_MEMATTR_AARCH64_OUTER_WA << -+ (AS_MEMATTR_INDEX_OUTER_WA * 8)); -+ -+ setup->transtab = (u64)kctx->pgd & AS_TRANSTAB_BASE_MASK; -+ setup->transcfg = AS_TRANSCFG_ADRMODE_AARCH64_4K; -+} -+ -+static void mmu_update(struct kbase_context *kctx) -+{ -+ struct kbase_device * const kbdev = kctx->kbdev; -+ struct kbase_as * const as = &kbdev->as[kctx->as_nr]; -+ struct kbase_mmu_setup * const current_setup = &as->current_setup; -+ -+ mmu_get_as_setup(kctx, current_setup); -+ -+ /* Apply the address space setting */ -+ kbase_mmu_hw_configure(kbdev, as, kctx); -+} -+ -+static void mmu_disable_as(struct kbase_device *kbdev, int as_nr) -+{ -+ struct kbase_as * const as = &kbdev->as[as_nr]; -+ struct kbase_mmu_setup * const current_setup = &as->current_setup; -+ -+ current_setup->transtab = 0ULL; -+ current_setup->transcfg = AS_TRANSCFG_ADRMODE_UNMAPPED; -+ -+ /* Apply the address space setting */ -+ kbase_mmu_hw_configure(kbdev, as, NULL); -+} -+ -+static phys_addr_t pte_to_phy_addr(u64 entry) -+{ -+ if (!(entry & 1)) -+ return 0; -+ -+ return entry & ~0xFFF; -+} -+ -+static int ate_is_valid(u64 ate, unsigned int level) -+{ -+ if (level == MIDGARD_MMU_BOTTOMLEVEL) -+ return ((ate & ENTRY_TYPE_MASK) == ENTRY_IS_ATE_L3); -+ else -+ return ((ate & ENTRY_TYPE_MASK) == ENTRY_IS_ATE_L02); -+} -+ -+static int pte_is_valid(u64 pte) -+{ -+ return ((pte & ENTRY_TYPE_MASK) == ENTRY_IS_PTE); -+} -+ -+/* -+ * Map KBASE_REG flags to MMU flags -+ */ -+static u64 get_mmu_flags(unsigned long flags) -+{ -+ u64 mmu_flags; -+ -+ /* store mem_attr index as 4:2 (macro called ensures 3 bits already) */ -+ mmu_flags = KBASE_REG_MEMATTR_VALUE(flags) << 2; -+ -+ /* Set access flags - note that AArch64 stage 1 does not support -+ * write-only access, so we use read/write instead -+ */ -+ if (flags & KBASE_REG_GPU_WR) -+ mmu_flags |= ENTRY_ACCESS_RW; -+ else if (flags & KBASE_REG_GPU_RD) -+ mmu_flags |= ENTRY_ACCESS_RO; -+ -+ /* nx if requested */ -+ mmu_flags |= (flags & KBASE_REG_GPU_NX) ? ENTRY_NX_BIT : 0; -+ -+ if (flags & KBASE_REG_SHARE_BOTH) { -+ /* inner and outer shareable */ -+ mmu_flags |= SHARE_BOTH_BITS; -+ } else if (flags & KBASE_REG_SHARE_IN) { -+ /* inner shareable coherency */ -+ mmu_flags |= SHARE_INNER_BITS; -+ } -+ -+ return mmu_flags; -+} -+ -+static void entry_set_ate(u64 *entry, -+ struct tagged_addr phy, -+ unsigned long flags, -+ unsigned int level) -+{ -+ if (level == MIDGARD_MMU_BOTTOMLEVEL) -+ page_table_entry_set(entry, as_phys_addr_t(phy) | -+ get_mmu_flags(flags) | -+ ENTRY_ACCESS_BIT | ENTRY_IS_ATE_L3); -+ else -+ page_table_entry_set(entry, as_phys_addr_t(phy) | -+ get_mmu_flags(flags) | -+ ENTRY_ACCESS_BIT | ENTRY_IS_ATE_L02); -+} -+ -+static void entry_set_pte(u64 *entry, phys_addr_t phy) -+{ -+ page_table_entry_set(entry, (phy & PAGE_MASK) | -+ ENTRY_ACCESS_BIT | ENTRY_IS_PTE); -+} -+ -+static void entry_invalidate(u64 *entry) -+{ -+ page_table_entry_set(entry, ENTRY_IS_INVAL); -+} -+ -+static struct kbase_mmu_mode const aarch64_mode = { -+ .update = mmu_update, -+ .get_as_setup = mmu_get_as_setup, -+ .disable_as = mmu_disable_as, -+ .pte_to_phy_addr = pte_to_phy_addr, -+ .ate_is_valid = ate_is_valid, -+ .pte_is_valid = pte_is_valid, -+ .entry_set_ate = entry_set_ate, -+ .entry_set_pte = entry_set_pte, -+ .entry_invalidate = entry_invalidate -+}; -+ -+struct kbase_mmu_mode const *kbase_mmu_mode_get_aarch64(void) -+{ -+ return &aarch64_mode; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mmu_mode_lpae.c b/drivers/gpu/arm/midgard/mali_kbase_mmu_mode_lpae.c -new file mode 100644 -index 0000000..5500127 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_mmu_mode_lpae.c -@@ -0,0 +1,200 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include "mali_kbase_mmu_mode.h" -+ -+#include "mali_kbase.h" -+#include "mali_midg_regmap.h" -+ -+#define ENTRY_TYPE_MASK 3ULL -+#define ENTRY_IS_ATE 1ULL -+#define ENTRY_IS_INVAL 2ULL -+#define ENTRY_IS_PTE 3ULL -+ -+#define ENTRY_ATTR_BITS (7ULL << 2) /* bits 4:2 */ -+#define ENTRY_RD_BIT (1ULL << 6) -+#define ENTRY_WR_BIT (1ULL << 7) -+#define ENTRY_SHARE_BITS (3ULL << 8) /* bits 9:8 */ -+#define ENTRY_ACCESS_BIT (1ULL << 10) -+#define ENTRY_NX_BIT (1ULL << 54) -+ -+#define ENTRY_FLAGS_MASK (ENTRY_ATTR_BITS | ENTRY_RD_BIT | ENTRY_WR_BIT | \ -+ ENTRY_SHARE_BITS | ENTRY_ACCESS_BIT | ENTRY_NX_BIT) -+ -+/* Helper Function to perform assignment of page table entries, to -+ * ensure the use of strd, which is required on LPAE systems. -+ */ -+static inline void page_table_entry_set(u64 *pte, u64 phy) -+{ -+#ifdef CONFIG_64BIT -+ *pte = phy; -+#elif defined(CONFIG_ARM) -+ /* -+ * In order to prevent the compiler keeping cached copies of -+ * memory, we have to explicitly say that we have updated -+ * memory. -+ * -+ * Note: We could manually move the data ourselves into R0 and -+ * R1 by specifying register variables that are explicitly -+ * given registers assignments, the down side of this is that -+ * we have to assume cpu endianness. To avoid this we can use -+ * the ldrd to read the data from memory into R0 and R1 which -+ * will respect the cpu endianness, we then use strd to make -+ * the 64 bit assignment to the page table entry. -+ */ -+ asm volatile("ldrd r0, r1, [%[ptemp]]\n\t" -+ "strd r0, r1, [%[pte]]\n\t" -+ : "=m" (*pte) -+ : [ptemp] "r" (&phy), [pte] "r" (pte), "m" (phy) -+ : "r0", "r1"); -+#else -+#error "64-bit atomic write must be implemented for your architecture" -+#endif -+} -+ -+static void mmu_get_as_setup(struct kbase_context *kctx, -+ struct kbase_mmu_setup * const setup) -+{ -+ /* Set up the required caching policies at the correct indices -+ * in the memattr register. */ -+ setup->memattr = -+ (AS_MEMATTR_LPAE_IMPL_DEF_CACHE_POLICY << -+ (AS_MEMATTR_INDEX_IMPL_DEF_CACHE_POLICY * 8)) | -+ (AS_MEMATTR_LPAE_FORCE_TO_CACHE_ALL << -+ (AS_MEMATTR_INDEX_FORCE_TO_CACHE_ALL * 8)) | -+ (AS_MEMATTR_LPAE_WRITE_ALLOC << -+ (AS_MEMATTR_INDEX_WRITE_ALLOC * 8)) | -+ (AS_MEMATTR_LPAE_OUTER_IMPL_DEF << -+ (AS_MEMATTR_INDEX_OUTER_IMPL_DEF * 8)) | -+ (AS_MEMATTR_LPAE_OUTER_WA << -+ (AS_MEMATTR_INDEX_OUTER_WA * 8)) | -+ 0; /* The other indices are unused for now */ -+ -+ setup->transtab = ((u64)kctx->pgd & -+ ((0xFFFFFFFFULL << 32) | AS_TRANSTAB_LPAE_ADDR_SPACE_MASK)) | -+ AS_TRANSTAB_LPAE_ADRMODE_TABLE | -+ AS_TRANSTAB_LPAE_READ_INNER; -+ -+ setup->transcfg = 0; -+} -+ -+static void mmu_update(struct kbase_context *kctx) -+{ -+ struct kbase_device * const kbdev = kctx->kbdev; -+ struct kbase_as * const as = &kbdev->as[kctx->as_nr]; -+ struct kbase_mmu_setup * const current_setup = &as->current_setup; -+ -+ mmu_get_as_setup(kctx, current_setup); -+ -+ /* Apply the address space setting */ -+ kbase_mmu_hw_configure(kbdev, as, kctx); -+} -+ -+static void mmu_disable_as(struct kbase_device *kbdev, int as_nr) -+{ -+ struct kbase_as * const as = &kbdev->as[as_nr]; -+ struct kbase_mmu_setup * const current_setup = &as->current_setup; -+ -+ current_setup->transtab = AS_TRANSTAB_LPAE_ADRMODE_UNMAPPED; -+ -+ /* Apply the address space setting */ -+ kbase_mmu_hw_configure(kbdev, as, NULL); -+} -+ -+static phys_addr_t pte_to_phy_addr(u64 entry) -+{ -+ if (!(entry & 1)) -+ return 0; -+ -+ return entry & ~0xFFF; -+} -+ -+static int ate_is_valid(u64 ate, unsigned int level) -+{ -+ return ((ate & ENTRY_TYPE_MASK) == ENTRY_IS_ATE); -+} -+ -+static int pte_is_valid(u64 pte) -+{ -+ return ((pte & ENTRY_TYPE_MASK) == ENTRY_IS_PTE); -+} -+ -+/* -+ * Map KBASE_REG flags to MMU flags -+ */ -+static u64 get_mmu_flags(unsigned long flags) -+{ -+ u64 mmu_flags; -+ -+ /* store mem_attr index as 4:2 (macro called ensures 3 bits already) */ -+ mmu_flags = KBASE_REG_MEMATTR_VALUE(flags) << 2; -+ -+ /* write perm if requested */ -+ mmu_flags |= (flags & KBASE_REG_GPU_WR) ? ENTRY_WR_BIT : 0; -+ /* read perm if requested */ -+ mmu_flags |= (flags & KBASE_REG_GPU_RD) ? ENTRY_RD_BIT : 0; -+ /* nx if requested */ -+ mmu_flags |= (flags & KBASE_REG_GPU_NX) ? ENTRY_NX_BIT : 0; -+ -+ if (flags & KBASE_REG_SHARE_BOTH) { -+ /* inner and outer shareable */ -+ mmu_flags |= SHARE_BOTH_BITS; -+ } else if (flags & KBASE_REG_SHARE_IN) { -+ /* inner shareable coherency */ -+ mmu_flags |= SHARE_INNER_BITS; -+ } -+ -+ return mmu_flags; -+} -+ -+static void entry_set_ate(u64 *entry, -+ struct tagged_addr phy, -+ unsigned long flags, -+ unsigned int level) -+{ -+ page_table_entry_set(entry, as_phys_addr_t(phy) | get_mmu_flags(flags) | -+ ENTRY_IS_ATE); -+} -+ -+static void entry_set_pte(u64 *entry, phys_addr_t phy) -+{ -+ page_table_entry_set(entry, (phy & ~0xFFF) | ENTRY_IS_PTE); -+} -+ -+static void entry_invalidate(u64 *entry) -+{ -+ page_table_entry_set(entry, ENTRY_IS_INVAL); -+} -+ -+static struct kbase_mmu_mode const lpae_mode = { -+ .update = mmu_update, -+ .get_as_setup = mmu_get_as_setup, -+ .disable_as = mmu_disable_as, -+ .pte_to_phy_addr = pte_to_phy_addr, -+ .ate_is_valid = ate_is_valid, -+ .pte_is_valid = pte_is_valid, -+ .entry_set_ate = entry_set_ate, -+ .entry_set_pte = entry_set_pte, -+ .entry_invalidate = entry_invalidate -+}; -+ -+struct kbase_mmu_mode const *kbase_mmu_mode_get_lpae(void) -+{ -+ return &lpae_mode; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_platform_fake.c b/drivers/gpu/arm/midgard/mali_kbase_platform_fake.c -new file mode 100644 -index 0000000..1a44957 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_platform_fake.c -@@ -0,0 +1,124 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2014, 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifdef CONFIG_MALI_PLATFORM_FAKE -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* -+ * This file is included only for type definitions and functions belonging to -+ * specific platform folders. Do not add dependencies with symbols that are -+ * defined somewhere else. -+ */ -+#include -+ -+#define PLATFORM_CONFIG_RESOURCE_COUNT 4 -+#define PLATFORM_CONFIG_IRQ_RES_COUNT 3 -+ -+static struct platform_device *mali_device; -+ -+#ifndef CONFIG_OF -+/** -+ * @brief Convert data in struct kbase_io_resources struct to Linux-specific resources -+ * -+ * Function converts data in struct kbase_io_resources struct to an array of Linux resource structures. Note that function -+ * assumes that size of linux_resource array is at least PLATFORM_CONFIG_RESOURCE_COUNT. -+ * Resources are put in fixed order: I/O memory region, job IRQ, MMU IRQ, GPU IRQ. -+ * -+ * @param[in] io_resource Input IO resource data -+ * @param[out] linux_resources Pointer to output array of Linux resource structures -+ */ -+static void kbasep_config_parse_io_resources(const struct kbase_io_resources *io_resources, struct resource *const linux_resources) -+{ -+ if (!io_resources || !linux_resources) { -+ pr_err("%s: couldn't find proper resources\n", __func__); -+ return; -+ } -+ -+ memset(linux_resources, 0, PLATFORM_CONFIG_RESOURCE_COUNT * sizeof(struct resource)); -+ -+ linux_resources[0].start = io_resources->io_memory_region.start; -+ linux_resources[0].end = io_resources->io_memory_region.end; -+ linux_resources[0].flags = IORESOURCE_MEM; -+ -+ linux_resources[1].start = io_resources->job_irq_number; -+ linux_resources[1].end = io_resources->job_irq_number; -+ linux_resources[1].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL; -+ -+ linux_resources[2].start = io_resources->mmu_irq_number; -+ linux_resources[2].end = io_resources->mmu_irq_number; -+ linux_resources[2].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL; -+ -+ linux_resources[3].start = io_resources->gpu_irq_number; -+ linux_resources[3].end = io_resources->gpu_irq_number; -+ linux_resources[3].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL; -+} -+#endif /* CONFIG_OF */ -+ -+int kbase_platform_fake_register(void) -+{ -+ struct kbase_platform_config *config; -+#ifndef CONFIG_OF -+ struct resource resources[PLATFORM_CONFIG_RESOURCE_COUNT]; -+#endif -+ int err; -+ -+ config = kbase_get_platform_config(); /* declared in midgard/mali_kbase_config.h but defined in platform folder */ -+ if (config == NULL) { -+ pr_err("%s: couldn't get platform config\n", __func__); -+ return -ENODEV; -+ } -+ -+ mali_device = platform_device_alloc("mali", 0); -+ if (mali_device == NULL) -+ return -ENOMEM; -+ -+#ifndef CONFIG_OF -+ kbasep_config_parse_io_resources(config->io_resources, resources); -+ err = platform_device_add_resources(mali_device, resources, PLATFORM_CONFIG_RESOURCE_COUNT); -+ if (err) { -+ platform_device_put(mali_device); -+ mali_device = NULL; -+ return err; -+ } -+#endif /* CONFIG_OF */ -+ -+ err = platform_device_add(mali_device); -+ if (err) { -+ platform_device_unregister(mali_device); -+ mali_device = NULL; -+ return err; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(kbase_platform_fake_register); -+ -+void kbase_platform_fake_unregister(void) -+{ -+ if (mali_device) -+ platform_device_unregister(mali_device); -+} -+EXPORT_SYMBOL(kbase_platform_fake_unregister); -+ -+#endif /* CONFIG_MALI_PLATFORM_FAKE */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_pm.c b/drivers/gpu/arm/midgard/mali_kbase_pm.c -new file mode 100644 -index 0000000..97d5434 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_pm.c -@@ -0,0 +1,205 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_pm.c -+ * Base kernel power management APIs -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+int kbase_pm_powerup(struct kbase_device *kbdev, unsigned int flags) -+{ -+ return kbase_hwaccess_pm_powerup(kbdev, flags); -+} -+ -+void kbase_pm_halt(struct kbase_device *kbdev) -+{ -+ kbase_hwaccess_pm_halt(kbdev); -+} -+ -+void kbase_pm_context_active(struct kbase_device *kbdev) -+{ -+ (void)kbase_pm_context_active_handle_suspend(kbdev, KBASE_PM_SUSPEND_HANDLER_NOT_POSSIBLE); -+} -+ -+int kbase_pm_context_active_handle_suspend(struct kbase_device *kbdev, enum kbase_pm_suspend_handler suspend_handler) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ int c; -+ int old_count; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ /* Trace timeline information about how long it took to handle the decision -+ * to powerup. Sometimes the event might be missed due to reading the count -+ * outside of mutex, but this is necessary to get the trace timing -+ * correct. */ -+ old_count = kbdev->pm.active_count; -+ if (old_count == 0) -+ kbase_timeline_pm_send_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_ACTIVE); -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ if (kbase_pm_is_suspending(kbdev)) { -+ switch (suspend_handler) { -+ case KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE: -+ if (kbdev->pm.active_count != 0) -+ break; -+ /* FALLTHROUGH */ -+ case KBASE_PM_SUSPEND_HANDLER_DONT_INCREASE: -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ if (old_count == 0) -+ kbase_timeline_pm_handle_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_ACTIVE); -+ return 1; -+ -+ case KBASE_PM_SUSPEND_HANDLER_NOT_POSSIBLE: -+ /* FALLTHROUGH */ -+ default: -+ KBASE_DEBUG_ASSERT_MSG(false, "unreachable"); -+ break; -+ } -+ } -+ c = ++kbdev->pm.active_count; -+ KBASE_TIMELINE_CONTEXT_ACTIVE(kbdev, c); -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, PM_CONTEXT_ACTIVE, NULL, NULL, 0u, c); -+ -+ /* Trace the event being handled */ -+ if (old_count == 0) -+ kbase_timeline_pm_handle_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_ACTIVE); -+ -+ if (c == 1) -+ /* First context active: Power on the GPU and any cores requested by -+ * the policy */ -+ kbase_hwaccess_pm_gpu_active(kbdev); -+ -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ return 0; -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_context_active); -+ -+void kbase_pm_context_idle(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ int c; -+ int old_count; -+ -+ KBASE_DEBUG_ASSERT(kbdev != NULL); -+ -+ /* Trace timeline information about how long it took to handle the decision -+ * to powerdown. Sometimes the event might be missed due to reading the -+ * count outside of mutex, but this is necessary to get the trace timing -+ * correct. */ -+ old_count = kbdev->pm.active_count; -+ if (old_count == 0) -+ kbase_timeline_pm_send_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_IDLE); -+ -+ mutex_lock(&js_devdata->runpool_mutex); -+ mutex_lock(&kbdev->pm.lock); -+ -+ c = --kbdev->pm.active_count; -+ KBASE_TIMELINE_CONTEXT_ACTIVE(kbdev, c); -+ KBASE_TRACE_ADD_REFCOUNT(kbdev, PM_CONTEXT_IDLE, NULL, NULL, 0u, c); -+ -+ KBASE_DEBUG_ASSERT(c >= 0); -+ -+ /* Trace the event being handled */ -+ if (old_count == 0) -+ kbase_timeline_pm_handle_event(kbdev, KBASE_TIMELINE_PM_EVENT_GPU_IDLE); -+ -+ if (c == 0) { -+ /* Last context has gone idle */ -+ kbase_hwaccess_pm_gpu_idle(kbdev); -+ -+ /* Wake up anyone waiting for this to become 0 (e.g. suspend). The -+ * waiters must synchronize with us by locking the pm.lock after -+ * waiting */ -+ wake_up(&kbdev->pm.zero_active_count_wait); -+ } -+ -+ mutex_unlock(&kbdev->pm.lock); -+ mutex_unlock(&js_devdata->runpool_mutex); -+} -+ -+KBASE_EXPORT_TEST_API(kbase_pm_context_idle); -+ -+void kbase_pm_suspend(struct kbase_device *kbdev) -+{ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ /* Suspend vinstr. -+ * This call will block until vinstr is suspended. */ -+ kbase_vinstr_suspend(kbdev->vinstr_ctx); -+ -+ mutex_lock(&kbdev->pm.lock); -+ KBASE_DEBUG_ASSERT(!kbase_pm_is_suspending(kbdev)); -+ kbdev->pm.suspending = true; -+ mutex_unlock(&kbdev->pm.lock); -+ -+ /* From now on, the active count will drop towards zero. Sometimes, it'll -+ * go up briefly before going down again. However, once it reaches zero it -+ * will stay there - guaranteeing that we've idled all pm references */ -+ -+ /* Suspend job scheduler and associated components, so that it releases all -+ * the PM active count references */ -+ kbasep_js_suspend(kbdev); -+ -+ /* Wait for the active count to reach zero. This is not the same as -+ * waiting for a power down, since not all policies power down when this -+ * reaches zero. */ -+ wait_event(kbdev->pm.zero_active_count_wait, kbdev->pm.active_count == 0); -+ -+ /* NOTE: We synchronize with anything that was just finishing a -+ * kbase_pm_context_idle() call by locking the pm.lock below */ -+ -+ kbase_hwaccess_pm_suspend(kbdev); -+} -+ -+void kbase_pm_resume(struct kbase_device *kbdev) -+{ -+ /* MUST happen before any pm_context_active calls occur */ -+ kbase_hwaccess_pm_resume(kbdev); -+ -+ /* Initial active call, to power on the GPU/cores if needed */ -+ kbase_pm_context_active(kbdev); -+ -+ /* Resume any blocked atoms (which may cause contexts to be scheduled in -+ * and dependent atoms to run) */ -+ kbase_resume_suspended_soft_jobs(kbdev); -+ -+ /* Resume the Job Scheduler and associated components, and start running -+ * atoms */ -+ kbasep_js_resume(kbdev); -+ -+ /* Matching idle call, to power off the GPU/cores if we didn't actually -+ * need it and the policy doesn't want it on */ -+ kbase_pm_context_idle(kbdev); -+ -+ /* Resume vinstr operation */ -+ kbase_vinstr_resume(kbdev->vinstr_ctx); -+} -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_pm.h b/drivers/gpu/arm/midgard/mali_kbase_pm.h -new file mode 100644 -index 0000000..37fa247 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_pm.h -@@ -0,0 +1,171 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_kbase_pm.h -+ * Power management API definitions -+ */ -+ -+#ifndef _KBASE_PM_H_ -+#define _KBASE_PM_H_ -+ -+#include "mali_kbase_hwaccess_pm.h" -+ -+#define PM_ENABLE_IRQS 0x01 -+#define PM_HW_ISSUES_DETECT 0x02 -+ -+ -+/** Initialize the power management framework. -+ * -+ * Must be called before any other power management function -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ * -+ * @return 0 if the power management framework was successfully initialized. -+ */ -+int kbase_pm_init(struct kbase_device *kbdev); -+ -+/** Power up GPU after all modules have been initialized and interrupt handlers installed. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ * -+ * @param flags Flags to pass on to kbase_pm_init_hw -+ * -+ * @return 0 if powerup was successful. -+ */ -+int kbase_pm_powerup(struct kbase_device *kbdev, unsigned int flags); -+ -+/** -+ * Halt the power management framework. -+ * Should ensure that no new interrupts are generated, -+ * but allow any currently running interrupt handlers to complete successfully. -+ * The GPU is forced off by the time this function returns, regardless of -+ * whether or not the active power policy asks for the GPU to be powered off. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_halt(struct kbase_device *kbdev); -+ -+/** Terminate the power management framework. -+ * -+ * No power management functions may be called after this -+ * (except @ref kbase_pm_init) -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_term(struct kbase_device *kbdev); -+ -+/** Increment the count of active contexts. -+ * -+ * This function should be called when a context is about to submit a job. It informs the active power policy that the -+ * GPU is going to be in use shortly and the policy is expected to start turning on the GPU. -+ * -+ * This function will block until the GPU is available. -+ * -+ * This function ASSERTS if a suspend is occuring/has occurred whilst this is -+ * in use. Use kbase_pm_contect_active_unless_suspending() instead. -+ * -+ * @note a Suspend is only visible to Kernel threads; user-space threads in a -+ * syscall cannot witness a suspend, because they are frozen before the suspend -+ * begins. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_context_active(struct kbase_device *kbdev); -+ -+ -+/** Handler codes for doing kbase_pm_context_active_handle_suspend() */ -+enum kbase_pm_suspend_handler { -+ /** A suspend is not expected/not possible - this is the same as -+ * kbase_pm_context_active() */ -+ KBASE_PM_SUSPEND_HANDLER_NOT_POSSIBLE, -+ /** If we're suspending, fail and don't increase the active count */ -+ KBASE_PM_SUSPEND_HANDLER_DONT_INCREASE, -+ /** If we're suspending, succeed and allow the active count to increase iff -+ * it didn't go from 0->1 (i.e., we didn't re-activate the GPU). -+ * -+ * This should only be used when there is a bounded time on the activation -+ * (e.g. guarantee it's going to be idled very soon after) */ -+ KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE -+}; -+ -+/** Suspend 'safe' variant of kbase_pm_context_active() -+ * -+ * If a suspend is in progress, this allows for various different ways of -+ * handling the suspend. Refer to @ref enum kbase_pm_suspend_handler for details. -+ * -+ * We returns a status code indicating whether we're allowed to keep the GPU -+ * active during the suspend, depending on the handler code. If the status code -+ * indicates a failure, the caller must abort whatever operation it was -+ * attempting, and potentially queue it up for after the OS has resumed. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ * @param suspend_handler The handler code for how to handle a suspend that might occur -+ * @return zero Indicates success -+ * @return non-zero Indicates failure due to the system being suspending/suspended. -+ */ -+int kbase_pm_context_active_handle_suspend(struct kbase_device *kbdev, enum kbase_pm_suspend_handler suspend_handler); -+ -+/** Decrement the reference count of active contexts. -+ * -+ * This function should be called when a context becomes idle. After this call the GPU may be turned off by the power -+ * policy so the calling code should ensure that it does not access the GPU's registers. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_context_idle(struct kbase_device *kbdev); -+ -+/** -+ * Suspend the GPU and prevent any further register accesses to it from Kernel -+ * threads. -+ * -+ * This is called in response to an OS suspend event, and calls into the various -+ * kbase components to complete the suspend. -+ * -+ * @note the mechanisms used here rely on all user-space threads being frozen -+ * by the OS before we suspend. Otherwise, an IOCTL could occur that powers up -+ * the GPU e.g. via atom submission. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_suspend(struct kbase_device *kbdev); -+ -+/** -+ * Resume the GPU, allow register accesses to it, and resume running atoms on -+ * the GPU. -+ * -+ * This is called in response to an OS resume event, and calls into the various -+ * kbase components to complete the resume. -+ * -+ * @param kbdev The kbase device structure for the device (must be a valid pointer) -+ */ -+void kbase_pm_resume(struct kbase_device *kbdev); -+ -+/** -+ * kbase_pm_vsync_callback - vsync callback -+ * -+ * @buffer_updated: 1 if a new frame was displayed, 0 otherwise -+ * @data: Pointer to the kbase device as returned by kbase_find_device() -+ * -+ * Callback function used to notify the power management code that a vsync has -+ * occurred on the display. -+ */ -+void kbase_pm_vsync_callback(int buffer_updated, void *data); -+ -+#endif /* _KBASE_PM_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_profiling_gator_api.h b/drivers/gpu/arm/midgard/mali_kbase_profiling_gator_api.h -new file mode 100644 -index 0000000..7fb674e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_profiling_gator_api.h -@@ -0,0 +1,40 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010, 2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @file mali_kbase_profiling_gator_api.h -+ * Model interface -+ */ -+ -+#ifndef _KBASE_PROFILING_GATOR_API_H_ -+#define _KBASE_PROFILING_GATOR_API_H_ -+ -+/* -+ * List of possible actions to be controlled by Streamline. -+ * The following numbers are used by gator to control -+ * the frame buffer dumping and s/w counter reporting. -+ */ -+#define FBDUMP_CONTROL_ENABLE (1) -+#define FBDUMP_CONTROL_RATE (2) -+#define SW_COUNTER_ENABLE (3) -+#define FBDUMP_CONTROL_RESIZE_FACTOR (4) -+#define FBDUMP_CONTROL_MAX (5) -+#define FBDUMP_CONTROL_MIN FBDUMP_CONTROL_ENABLE -+ -+void _mali_profiling_control(u32 action, u32 value); -+ -+#endif /* _KBASE_PROFILING_GATOR_API */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_regs_history_debugfs.c b/drivers/gpu/arm/midgard/mali_kbase_regs_history_debugfs.c -new file mode 100644 -index 0000000..c970650 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_regs_history_debugfs.c -@@ -0,0 +1,130 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include "mali_kbase.h" -+ -+#include "mali_kbase_regs_history_debugfs.h" -+ -+#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_MALI_NO_MALI) -+ -+#include -+ -+ -+static int regs_history_size_get(void *data, u64 *val) -+{ -+ struct kbase_io_history *const h = data; -+ -+ *val = h->size; -+ -+ return 0; -+} -+ -+static int regs_history_size_set(void *data, u64 val) -+{ -+ struct kbase_io_history *const h = data; -+ -+ return kbase_io_history_resize(h, (u16)val); -+} -+ -+ -+DEFINE_SIMPLE_ATTRIBUTE(regs_history_size_fops, -+ regs_history_size_get, -+ regs_history_size_set, -+ "%llu\n"); -+ -+ -+/** -+ * regs_history_show - show callback for the register access history file. -+ * -+ * @sfile: The debugfs entry -+ * @data: Data associated with the entry -+ * -+ * This function is called to dump all recent accesses to the GPU registers. -+ * -+ * @return 0 if successfully prints data in debugfs entry file, failure -+ * otherwise -+ */ -+static int regs_history_show(struct seq_file *sfile, void *data) -+{ -+ struct kbase_io_history *const h = sfile->private; -+ u16 i; -+ size_t iters; -+ unsigned long flags; -+ -+ if (!h->enabled) { -+ seq_puts(sfile, "The register access history is disabled\n"); -+ goto out; -+ } -+ -+ spin_lock_irqsave(&h->lock, flags); -+ -+ iters = (h->size > h->count) ? h->count : h->size; -+ seq_printf(sfile, "Last %zu register accesses of %zu total:\n", iters, -+ h->count); -+ for (i = 0; i < iters; ++i) { -+ struct kbase_io_access *io = -+ &h->buf[(h->count - iters + i) % h->size]; -+ char const access = (io->addr & 1) ? 'w' : 'r'; -+ -+ seq_printf(sfile, "%6i: %c: reg 0x%p val %08x\n", i, access, -+ (void *)(io->addr & ~0x1), io->value); -+ } -+ -+ spin_unlock_irqrestore(&h->lock, flags); -+ -+out: -+ return 0; -+} -+ -+ -+/** -+ * regs_history_open - open operation for regs_history debugfs file -+ * -+ * @in: &struct inode pointer -+ * @file: &struct file pointer -+ * -+ * @return file descriptor -+ */ -+static int regs_history_open(struct inode *in, struct file *file) -+{ -+ return single_open(file, ®s_history_show, in->i_private); -+} -+ -+ -+static const struct file_operations regs_history_fops = { -+ .open = ®s_history_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+ -+void kbasep_regs_history_debugfs_init(struct kbase_device *kbdev) -+{ -+ debugfs_create_bool("regs_history_enabled", S_IRUGO | S_IWUSR, -+ kbdev->mali_debugfs_directory, -+ &kbdev->io_history.enabled); -+ debugfs_create_file("regs_history_size", S_IRUGO | S_IWUSR, -+ kbdev->mali_debugfs_directory, -+ &kbdev->io_history, ®s_history_size_fops); -+ debugfs_create_file("regs_history", S_IRUGO, -+ kbdev->mali_debugfs_directory, &kbdev->io_history, -+ ®s_history_fops); -+} -+ -+ -+#endif /* CONFIG_DEBUG_FS */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_regs_history_debugfs.h b/drivers/gpu/arm/midgard/mali_kbase_regs_history_debugfs.h -new file mode 100644 -index 0000000..f108370 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_regs_history_debugfs.h -@@ -0,0 +1,50 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * Header file for register access history support via debugfs -+ * -+ * This interface is made available via /sys/kernel/debug/mali#/regs_history*. -+ * -+ * Usage: -+ * - regs_history_enabled: whether recording of register accesses is enabled. -+ * Write 'y' to enable, 'n' to disable. -+ * - regs_history_size: size of the register history buffer, must be > 0 -+ * - regs_history: return the information about last accesses to the registers. -+ */ -+ -+#ifndef _KBASE_REGS_HISTORY_DEBUGFS_H -+#define _KBASE_REGS_HISTORY_DEBUGFS_H -+ -+struct kbase_device; -+ -+#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_MALI_NO_MALI) -+ -+/** -+ * kbasep_regs_history_debugfs_init - add debugfs entries for register history -+ * -+ * @kbdev: Pointer to kbase_device containing the register history -+ */ -+void kbasep_regs_history_debugfs_init(struct kbase_device *kbdev); -+ -+#else /* CONFIG_DEBUG_FS */ -+ -+#define kbasep_regs_history_debugfs_init CSTD_NOP -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+#endif /*_KBASE_REGS_HISTORY_DEBUGFS_H*/ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_replay.c b/drivers/gpu/arm/midgard/mali_kbase_replay.c -new file mode 100644 -index 0000000..2f8eccf ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_replay.c -@@ -0,0 +1,1166 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @file mali_kbase_replay.c -+ * Replay soft job handlers -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define JOB_NOT_STARTED 0 -+#define JOB_TYPE_NULL (1) -+#define JOB_TYPE_VERTEX (5) -+#define JOB_TYPE_TILER (7) -+#define JOB_TYPE_FUSED (8) -+#define JOB_TYPE_FRAGMENT (9) -+ -+#define JOB_HEADER_32_FBD_OFFSET (31*4) -+#define JOB_HEADER_64_FBD_OFFSET (44*4) -+ -+#define FBD_POINTER_MASK (~0x3f) -+ -+#define SFBD_TILER_OFFSET (48*4) -+ -+#define MFBD_TILER_OFFSET (14*4) -+ -+#define FBD_HIERARCHY_WEIGHTS 8 -+#define FBD_HIERARCHY_MASK_MASK 0x1fff -+ -+#define FBD_TYPE 1 -+ -+#define HIERARCHY_WEIGHTS 13 -+ -+#define JOB_HEADER_ID_MAX 0xffff -+ -+#define JOB_SOURCE_ID(status) (((status) >> 16) & 0xFFFF) -+#define JOB_POLYGON_LIST (0x03) -+ -+struct fragment_job { -+ struct job_descriptor_header header; -+ -+ u32 x[2]; -+ union { -+ u64 _64; -+ u32 _32; -+ } fragment_fbd; -+}; -+ -+static void dump_job_head(struct kbase_context *kctx, char *head_str, -+ struct job_descriptor_header *job) -+{ -+#ifdef CONFIG_MALI_DEBUG -+ dev_dbg(kctx->kbdev->dev, "%s\n", head_str); -+ dev_dbg(kctx->kbdev->dev, -+ "addr = %p\n" -+ "exception_status = %x (Source ID: 0x%x Access: 0x%x Exception: 0x%x)\n" -+ "first_incomplete_task = %x\n" -+ "fault_pointer = %llx\n" -+ "job_descriptor_size = %x\n" -+ "job_type = %x\n" -+ "job_barrier = %x\n" -+ "_reserved_01 = %x\n" -+ "_reserved_02 = %x\n" -+ "_reserved_03 = %x\n" -+ "_reserved_04/05 = %x,%x\n" -+ "job_index = %x\n" -+ "dependencies = %x,%x\n", -+ job, job->exception_status, -+ JOB_SOURCE_ID(job->exception_status), -+ (job->exception_status >> 8) & 0x3, -+ job->exception_status & 0xFF, -+ job->first_incomplete_task, -+ job->fault_pointer, job->job_descriptor_size, -+ job->job_type, job->job_barrier, job->_reserved_01, -+ job->_reserved_02, job->_reserved_03, -+ job->_reserved_04, job->_reserved_05, -+ job->job_index, -+ job->job_dependency_index_1, -+ job->job_dependency_index_2); -+ -+ if (job->job_descriptor_size) -+ dev_dbg(kctx->kbdev->dev, "next = %llx\n", -+ job->next_job._64); -+ else -+ dev_dbg(kctx->kbdev->dev, "next = %x\n", -+ job->next_job._32); -+#endif -+} -+ -+static int kbasep_replay_reset_sfbd(struct kbase_context *kctx, -+ u64 fbd_address, u64 tiler_heap_free, -+ u16 hierarchy_mask, u32 default_weight) -+{ -+ struct { -+ u32 padding_1[1]; -+ u32 flags; -+ u64 padding_2[2]; -+ u64 heap_free_address; -+ u32 padding[8]; -+ u32 weights[FBD_HIERARCHY_WEIGHTS]; -+ } *fbd_tiler; -+ struct kbase_vmap_struct map; -+ -+ dev_dbg(kctx->kbdev->dev, "fbd_address: %llx\n", fbd_address); -+ -+ fbd_tiler = kbase_vmap(kctx, fbd_address + SFBD_TILER_OFFSET, -+ sizeof(*fbd_tiler), &map); -+ if (!fbd_tiler) { -+ dev_err(kctx->kbdev->dev, "kbasep_replay_reset_fbd: failed to map fbd\n"); -+ return -EINVAL; -+ } -+ -+#ifdef CONFIG_MALI_DEBUG -+ dev_dbg(kctx->kbdev->dev, -+ "FBD tiler:\n" -+ "flags = %x\n" -+ "heap_free_address = %llx\n", -+ fbd_tiler->flags, fbd_tiler->heap_free_address); -+#endif -+ if (hierarchy_mask) { -+ u32 weights[HIERARCHY_WEIGHTS]; -+ u16 old_hierarchy_mask = fbd_tiler->flags & -+ FBD_HIERARCHY_MASK_MASK; -+ int i, j = 0; -+ -+ for (i = 0; i < HIERARCHY_WEIGHTS; i++) { -+ if (old_hierarchy_mask & (1 << i)) { -+ KBASE_DEBUG_ASSERT(j < FBD_HIERARCHY_WEIGHTS); -+ weights[i] = fbd_tiler->weights[j++]; -+ } else { -+ weights[i] = default_weight; -+ } -+ } -+ -+ -+ dev_dbg(kctx->kbdev->dev, "Old hierarchy mask=%x New hierarchy mask=%x\n", -+ old_hierarchy_mask, hierarchy_mask); -+ -+ for (i = 0; i < HIERARCHY_WEIGHTS; i++) -+ dev_dbg(kctx->kbdev->dev, " Hierarchy weight %02d: %08x\n", -+ i, weights[i]); -+ -+ j = 0; -+ -+ for (i = 0; i < HIERARCHY_WEIGHTS; i++) { -+ if (hierarchy_mask & (1 << i)) { -+ KBASE_DEBUG_ASSERT(j < FBD_HIERARCHY_WEIGHTS); -+ -+ dev_dbg(kctx->kbdev->dev, " Writing hierarchy level %02d (%08x) to %d\n", -+ i, weights[i], j); -+ -+ fbd_tiler->weights[j++] = weights[i]; -+ } -+ } -+ -+ for (; j < FBD_HIERARCHY_WEIGHTS; j++) -+ fbd_tiler->weights[j] = 0; -+ -+ fbd_tiler->flags = hierarchy_mask | (1 << 16); -+ } -+ -+ fbd_tiler->heap_free_address = tiler_heap_free; -+ -+ dev_dbg(kctx->kbdev->dev, "heap_free_address=%llx flags=%x\n", -+ fbd_tiler->heap_free_address, fbd_tiler->flags); -+ -+ kbase_vunmap(kctx, &map); -+ -+ return 0; -+} -+ -+static int kbasep_replay_reset_mfbd(struct kbase_context *kctx, -+ u64 fbd_address, u64 tiler_heap_free, -+ u16 hierarchy_mask, u32 default_weight) -+{ -+ struct kbase_vmap_struct map; -+ struct { -+ u32 padding_0; -+ u32 flags; -+ u64 padding_1[2]; -+ u64 heap_free_address; -+ u64 padding_2; -+ u32 weights[FBD_HIERARCHY_WEIGHTS]; -+ } *fbd_tiler; -+ -+ dev_dbg(kctx->kbdev->dev, "fbd_address: %llx\n", fbd_address); -+ -+ fbd_tiler = kbase_vmap(kctx, fbd_address + MFBD_TILER_OFFSET, -+ sizeof(*fbd_tiler), &map); -+ if (!fbd_tiler) { -+ dev_err(kctx->kbdev->dev, -+ "kbasep_replay_reset_fbd: failed to map fbd\n"); -+ return -EINVAL; -+ } -+ -+#ifdef CONFIG_MALI_DEBUG -+ dev_dbg(kctx->kbdev->dev, "FBD tiler:\n" -+ "flags = %x\n" -+ "heap_free_address = %llx\n", -+ fbd_tiler->flags, -+ fbd_tiler->heap_free_address); -+#endif -+ if (hierarchy_mask) { -+ u32 weights[HIERARCHY_WEIGHTS]; -+ u16 old_hierarchy_mask = (fbd_tiler->flags) & -+ FBD_HIERARCHY_MASK_MASK; -+ int i, j = 0; -+ -+ for (i = 0; i < HIERARCHY_WEIGHTS; i++) { -+ if (old_hierarchy_mask & (1 << i)) { -+ KBASE_DEBUG_ASSERT(j < FBD_HIERARCHY_WEIGHTS); -+ weights[i] = fbd_tiler->weights[j++]; -+ } else { -+ weights[i] = default_weight; -+ } -+ } -+ -+ -+ dev_dbg(kctx->kbdev->dev, "Old hierarchy mask=%x New hierarchy mask=%x\n", -+ old_hierarchy_mask, hierarchy_mask); -+ -+ for (i = 0; i < HIERARCHY_WEIGHTS; i++) -+ dev_dbg(kctx->kbdev->dev, " Hierarchy weight %02d: %08x\n", -+ i, weights[i]); -+ -+ j = 0; -+ -+ for (i = 0; i < HIERARCHY_WEIGHTS; i++) { -+ if (hierarchy_mask & (1 << i)) { -+ KBASE_DEBUG_ASSERT(j < FBD_HIERARCHY_WEIGHTS); -+ -+ dev_dbg(kctx->kbdev->dev, -+ " Writing hierarchy level %02d (%08x) to %d\n", -+ i, weights[i], j); -+ -+ fbd_tiler->weights[j++] = weights[i]; -+ } -+ } -+ -+ for (; j < FBD_HIERARCHY_WEIGHTS; j++) -+ fbd_tiler->weights[j] = 0; -+ -+ fbd_tiler->flags = hierarchy_mask | (1 << 16); -+ } -+ -+ fbd_tiler->heap_free_address = tiler_heap_free; -+ -+ kbase_vunmap(kctx, &map); -+ -+ return 0; -+} -+ -+/** -+ * @brief Reset the status of an FBD pointed to by a tiler job -+ * -+ * This performs two functions : -+ * - Set the hierarchy mask -+ * - Reset the tiler free heap address -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] job_header Address of job header to reset. -+ * @param[in] tiler_heap_free The value to reset Tiler Heap Free to -+ * @param[in] hierarchy_mask The hierarchy mask to use -+ * @param[in] default_weight Default hierarchy weight to write when no other -+ * weight is given in the FBD -+ * @param[in] job_64 true if this job is using 64-bit -+ * descriptors -+ * -+ * @return 0 on success, error code on failure -+ */ -+static int kbasep_replay_reset_tiler_job(struct kbase_context *kctx, -+ u64 job_header, u64 tiler_heap_free, -+ u16 hierarchy_mask, u32 default_weight, bool job_64) -+{ -+ struct kbase_vmap_struct map; -+ u64 fbd_address; -+ -+ if (job_64) { -+ u64 *job_ext; -+ -+ job_ext = kbase_vmap(kctx, -+ job_header + JOB_HEADER_64_FBD_OFFSET, -+ sizeof(*job_ext), &map); -+ -+ if (!job_ext) { -+ dev_err(kctx->kbdev->dev, "kbasep_replay_reset_tiler_job: failed to map jc\n"); -+ return -EINVAL; -+ } -+ -+ fbd_address = *job_ext; -+ -+ kbase_vunmap(kctx, &map); -+ } else { -+ u32 *job_ext; -+ -+ job_ext = kbase_vmap(kctx, -+ job_header + JOB_HEADER_32_FBD_OFFSET, -+ sizeof(*job_ext), &map); -+ -+ if (!job_ext) { -+ dev_err(kctx->kbdev->dev, "kbasep_replay_reset_tiler_job: failed to map jc\n"); -+ return -EINVAL; -+ } -+ -+ fbd_address = *job_ext; -+ -+ kbase_vunmap(kctx, &map); -+ } -+ -+ if (fbd_address & FBD_TYPE) { -+ return kbasep_replay_reset_mfbd(kctx, -+ fbd_address & FBD_POINTER_MASK, -+ tiler_heap_free, -+ hierarchy_mask, -+ default_weight); -+ } else { -+ return kbasep_replay_reset_sfbd(kctx, -+ fbd_address & FBD_POINTER_MASK, -+ tiler_heap_free, -+ hierarchy_mask, -+ default_weight); -+ } -+} -+ -+/** -+ * @brief Reset the status of a job -+ * -+ * This performs the following functions : -+ * -+ * - Reset the Job Status field of each job to NOT_STARTED. -+ * - Set the Job Type field of any Vertex Jobs to Null Job. -+ * - For any jobs using an FBD, set the Tiler Heap Free field to the value of -+ * the tiler_heap_free parameter, and set the hierarchy level mask to the -+ * hier_mask parameter. -+ * - Offset HW dependencies by the hw_job_id_offset parameter -+ * - Set the Perform Job Barrier flag if this job is the first in the chain -+ * - Read the address of the next job header -+ * -+ * @param[in] kctx Context pointer -+ * @param[in,out] job_header Address of job header to reset. Set to address -+ * of next job header on exit. -+ * @param[in] prev_jc Previous job chain to link to, if this job is -+ * the last in the chain. -+ * @param[in] hw_job_id_offset Offset for HW job IDs -+ * @param[in] tiler_heap_free The value to reset Tiler Heap Free to -+ * @param[in] hierarchy_mask The hierarchy mask to use -+ * @param[in] default_weight Default hierarchy weight to write when no other -+ * weight is given in the FBD -+ * @param[in] first_in_chain true if this job is the first in the chain -+ * @param[in] fragment_chain true if this job is in the fragment chain -+ * -+ * @return 0 on success, error code on failure -+ */ -+static int kbasep_replay_reset_job(struct kbase_context *kctx, -+ u64 *job_header, u64 prev_jc, -+ u64 tiler_heap_free, u16 hierarchy_mask, -+ u32 default_weight, u16 hw_job_id_offset, -+ bool first_in_chain, bool fragment_chain) -+{ -+ struct fragment_job *frag_job; -+ struct job_descriptor_header *job; -+ u64 new_job_header; -+ struct kbase_vmap_struct map; -+ -+ frag_job = kbase_vmap(kctx, *job_header, sizeof(*frag_job), &map); -+ if (!frag_job) { -+ dev_err(kctx->kbdev->dev, -+ "kbasep_replay_parse_jc: failed to map jc\n"); -+ return -EINVAL; -+ } -+ job = &frag_job->header; -+ -+ dump_job_head(kctx, "Job header:", job); -+ -+ if (job->exception_status == JOB_NOT_STARTED && !fragment_chain) { -+ dev_err(kctx->kbdev->dev, "Job already not started\n"); -+ goto out_unmap; -+ } -+ job->exception_status = JOB_NOT_STARTED; -+ -+ if (job->job_type == JOB_TYPE_VERTEX) -+ job->job_type = JOB_TYPE_NULL; -+ -+ if (job->job_type == JOB_TYPE_FUSED) { -+ dev_err(kctx->kbdev->dev, "Fused jobs can not be replayed\n"); -+ goto out_unmap; -+ } -+ -+ if (first_in_chain) -+ job->job_barrier = 1; -+ -+ if ((job->job_dependency_index_1 + hw_job_id_offset) > -+ JOB_HEADER_ID_MAX || -+ (job->job_dependency_index_2 + hw_job_id_offset) > -+ JOB_HEADER_ID_MAX || -+ (job->job_index + hw_job_id_offset) > JOB_HEADER_ID_MAX) { -+ dev_err(kctx->kbdev->dev, -+ "Job indicies/dependencies out of valid range\n"); -+ goto out_unmap; -+ } -+ -+ if (job->job_dependency_index_1) -+ job->job_dependency_index_1 += hw_job_id_offset; -+ if (job->job_dependency_index_2) -+ job->job_dependency_index_2 += hw_job_id_offset; -+ -+ job->job_index += hw_job_id_offset; -+ -+ if (job->job_descriptor_size) { -+ new_job_header = job->next_job._64; -+ if (!job->next_job._64) -+ job->next_job._64 = prev_jc; -+ } else { -+ new_job_header = job->next_job._32; -+ if (!job->next_job._32) -+ job->next_job._32 = prev_jc; -+ } -+ dump_job_head(kctx, "Updated to:", job); -+ -+ if (job->job_type == JOB_TYPE_TILER) { -+ bool job_64 = job->job_descriptor_size != 0; -+ -+ if (kbasep_replay_reset_tiler_job(kctx, *job_header, -+ tiler_heap_free, hierarchy_mask, -+ default_weight, job_64) != 0) -+ goto out_unmap; -+ -+ } else if (job->job_type == JOB_TYPE_FRAGMENT) { -+ u64 fbd_address; -+ -+ if (job->job_descriptor_size) -+ fbd_address = frag_job->fragment_fbd._64; -+ else -+ fbd_address = (u64)frag_job->fragment_fbd._32; -+ -+ if (fbd_address & FBD_TYPE) { -+ if (kbasep_replay_reset_mfbd(kctx, -+ fbd_address & FBD_POINTER_MASK, -+ tiler_heap_free, -+ hierarchy_mask, -+ default_weight) != 0) -+ goto out_unmap; -+ } else { -+ if (kbasep_replay_reset_sfbd(kctx, -+ fbd_address & FBD_POINTER_MASK, -+ tiler_heap_free, -+ hierarchy_mask, -+ default_weight) != 0) -+ goto out_unmap; -+ } -+ } -+ -+ kbase_vunmap(kctx, &map); -+ -+ *job_header = new_job_header; -+ -+ return 0; -+ -+out_unmap: -+ kbase_vunmap(kctx, &map); -+ return -EINVAL; -+} -+ -+/** -+ * @brief Find the highest job ID in a job chain -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] jc Job chain start address -+ * @param[out] hw_job_id Highest job ID in chain -+ * -+ * @return 0 on success, error code on failure -+ */ -+static int kbasep_replay_find_hw_job_id(struct kbase_context *kctx, -+ u64 jc, u16 *hw_job_id) -+{ -+ while (jc) { -+ struct job_descriptor_header *job; -+ struct kbase_vmap_struct map; -+ -+ dev_dbg(kctx->kbdev->dev, -+ "kbasep_replay_find_hw_job_id: parsing jc=%llx\n", jc); -+ -+ job = kbase_vmap(kctx, jc, sizeof(*job), &map); -+ if (!job) { -+ dev_err(kctx->kbdev->dev, "failed to map jc\n"); -+ -+ return -EINVAL; -+ } -+ -+ if (job->job_index > *hw_job_id) -+ *hw_job_id = job->job_index; -+ -+ if (job->job_descriptor_size) -+ jc = job->next_job._64; -+ else -+ jc = job->next_job._32; -+ -+ kbase_vunmap(kctx, &map); -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief Reset the status of a number of jobs -+ * -+ * This function walks the provided job chain, and calls -+ * kbasep_replay_reset_job for each job. It also links the job chain to the -+ * provided previous job chain. -+ * -+ * The function will fail if any of the jobs passed already have status of -+ * NOT_STARTED. -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] jc Job chain to be processed -+ * @param[in] prev_jc Job chain to be added to. May be NULL -+ * @param[in] tiler_heap_free The value to reset Tiler Heap Free to -+ * @param[in] hierarchy_mask The hierarchy mask to use -+ * @param[in] default_weight Default hierarchy weight to write when no other -+ * weight is given in the FBD -+ * @param[in] hw_job_id_offset Offset for HW job IDs -+ * @param[in] fragment_chain true if this chain is the fragment chain -+ * -+ * @return 0 on success, error code otherwise -+ */ -+static int kbasep_replay_parse_jc(struct kbase_context *kctx, -+ u64 jc, u64 prev_jc, -+ u64 tiler_heap_free, u16 hierarchy_mask, -+ u32 default_weight, u16 hw_job_id_offset, -+ bool fragment_chain) -+{ -+ bool first_in_chain = true; -+ int nr_jobs = 0; -+ -+ dev_dbg(kctx->kbdev->dev, "kbasep_replay_parse_jc: jc=%llx hw_job_id=%x\n", -+ jc, hw_job_id_offset); -+ -+ while (jc) { -+ dev_dbg(kctx->kbdev->dev, "kbasep_replay_parse_jc: parsing jc=%llx\n", jc); -+ -+ if (kbasep_replay_reset_job(kctx, &jc, prev_jc, -+ tiler_heap_free, hierarchy_mask, -+ default_weight, hw_job_id_offset, -+ first_in_chain, fragment_chain) != 0) -+ return -EINVAL; -+ -+ first_in_chain = false; -+ -+ nr_jobs++; -+ if (fragment_chain && -+ nr_jobs >= BASE_JD_REPLAY_F_CHAIN_JOB_LIMIT) { -+ dev_err(kctx->kbdev->dev, -+ "Exceeded maximum number of jobs in fragment chain\n"); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief Reset the status of a replay job, and set up dependencies -+ * -+ * This performs the actions to allow the replay job to be re-run following -+ * completion of the passed dependency. -+ * -+ * @param[in] katom The atom to be reset -+ * @param[in] dep_atom The dependency to be attached to the atom -+ */ -+static void kbasep_replay_reset_softjob(struct kbase_jd_atom *katom, -+ struct kbase_jd_atom *dep_atom) -+{ -+ katom->status = KBASE_JD_ATOM_STATE_QUEUED; -+ kbase_jd_katom_dep_set(&katom->dep[0], dep_atom, BASE_JD_DEP_TYPE_DATA); -+ list_add_tail(&katom->dep_item[0], &dep_atom->dep_head[0]); -+} -+ -+/** -+ * @brief Allocate an unused katom -+ * -+ * This will search the provided context for an unused katom, and will mark it -+ * as KBASE_JD_ATOM_STATE_QUEUED. -+ * -+ * If no atoms are available then the function will fail. -+ * -+ * @param[in] kctx Context pointer -+ * @return An atom ID, or -1 on failure -+ */ -+static int kbasep_allocate_katom(struct kbase_context *kctx) -+{ -+ struct kbase_jd_context *jctx = &kctx->jctx; -+ int i; -+ -+ for (i = BASE_JD_ATOM_COUNT-1; i > 0; i--) { -+ if (jctx->atoms[i].status == KBASE_JD_ATOM_STATE_UNUSED) { -+ jctx->atoms[i].status = KBASE_JD_ATOM_STATE_QUEUED; -+ dev_dbg(kctx->kbdev->dev, -+ "kbasep_allocate_katom: Allocated atom %d\n", -+ i); -+ return i; -+ } -+ } -+ -+ return -1; -+} -+ -+/** -+ * @brief Release a katom -+ * -+ * This will mark the provided atom as available, and remove any dependencies. -+ * -+ * For use on error path. -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] atom_id ID of atom to release -+ */ -+static void kbasep_release_katom(struct kbase_context *kctx, int atom_id) -+{ -+ struct kbase_jd_context *jctx = &kctx->jctx; -+ -+ dev_dbg(kctx->kbdev->dev, "kbasep_release_katom: Released atom %d\n", -+ atom_id); -+ -+ while (!list_empty(&jctx->atoms[atom_id].dep_head[0])) -+ list_del(jctx->atoms[atom_id].dep_head[0].next); -+ -+ while (!list_empty(&jctx->atoms[atom_id].dep_head[1])) -+ list_del(jctx->atoms[atom_id].dep_head[1].next); -+ -+ jctx->atoms[atom_id].status = KBASE_JD_ATOM_STATE_UNUSED; -+} -+ -+static void kbasep_replay_create_atom(struct kbase_context *kctx, -+ struct base_jd_atom_v2 *atom, -+ int atom_nr, -+ base_jd_prio prio) -+{ -+ atom->nr_extres = 0; -+ atom->extres_list = 0; -+ atom->device_nr = 0; -+ atom->prio = prio; -+ atom->atom_number = atom_nr; -+ -+ base_jd_atom_dep_set(&atom->pre_dep[0], 0 , BASE_JD_DEP_TYPE_INVALID); -+ base_jd_atom_dep_set(&atom->pre_dep[1], 0 , BASE_JD_DEP_TYPE_INVALID); -+ -+ atom->udata.blob[0] = 0; -+ atom->udata.blob[1] = 0; -+} -+ -+/** -+ * @brief Create two atoms for the purpose of replaying jobs -+ * -+ * Two atoms are allocated and created. The jc pointer is not set at this -+ * stage. The second atom has a dependency on the first. The remaining fields -+ * are set up as follows : -+ * -+ * - No external resources. Any required external resources will be held by the -+ * replay atom. -+ * - device_nr is set to 0. This is not relevant as -+ * BASE_JD_REQ_SPECIFIC_COHERENT_GROUP should not be set. -+ * - Priority is inherited from the replay job. -+ * -+ * @param[out] t_atom Atom to use for tiler jobs -+ * @param[out] f_atom Atom to use for fragment jobs -+ * @param[in] prio Priority of new atom (inherited from replay soft -+ * job) -+ * @return 0 on success, error code on failure -+ */ -+static int kbasep_replay_create_atoms(struct kbase_context *kctx, -+ struct base_jd_atom_v2 *t_atom, -+ struct base_jd_atom_v2 *f_atom, -+ base_jd_prio prio) -+{ -+ int t_atom_nr, f_atom_nr; -+ -+ t_atom_nr = kbasep_allocate_katom(kctx); -+ if (t_atom_nr < 0) { -+ dev_err(kctx->kbdev->dev, "Failed to allocate katom\n"); -+ return -EINVAL; -+ } -+ -+ f_atom_nr = kbasep_allocate_katom(kctx); -+ if (f_atom_nr < 0) { -+ dev_err(kctx->kbdev->dev, "Failed to allocate katom\n"); -+ kbasep_release_katom(kctx, t_atom_nr); -+ return -EINVAL; -+ } -+ -+ kbasep_replay_create_atom(kctx, t_atom, t_atom_nr, prio); -+ kbasep_replay_create_atom(kctx, f_atom, f_atom_nr, prio); -+ -+ base_jd_atom_dep_set(&f_atom->pre_dep[0], t_atom_nr , BASE_JD_DEP_TYPE_DATA); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_MALI_DEBUG -+static void payload_dump(struct kbase_context *kctx, base_jd_replay_payload *payload) -+{ -+ u64 next; -+ -+ dev_dbg(kctx->kbdev->dev, "Tiler jc list :\n"); -+ next = payload->tiler_jc_list; -+ -+ while (next) { -+ struct kbase_vmap_struct map; -+ base_jd_replay_jc *jc_struct; -+ -+ jc_struct = kbase_vmap(kctx, next, sizeof(*jc_struct), &map); -+ -+ if (!jc_struct) -+ return; -+ -+ dev_dbg(kctx->kbdev->dev, "* jc_struct=%p jc=%llx next=%llx\n", -+ jc_struct, jc_struct->jc, jc_struct->next); -+ -+ next = jc_struct->next; -+ -+ kbase_vunmap(kctx, &map); -+ } -+} -+#endif -+ -+/** -+ * @brief Parse a base_jd_replay_payload provided by userspace -+ * -+ * This will read the payload from userspace, and parse the job chains. -+ * -+ * @param[in] kctx Context pointer -+ * @param[in] replay_atom Replay soft job atom -+ * @param[in] t_atom Atom to use for tiler jobs -+ * @param[in] f_atom Atom to use for fragment jobs -+ * @return 0 on success, error code on failure -+ */ -+static int kbasep_replay_parse_payload(struct kbase_context *kctx, -+ struct kbase_jd_atom *replay_atom, -+ struct base_jd_atom_v2 *t_atom, -+ struct base_jd_atom_v2 *f_atom) -+{ -+ base_jd_replay_payload *payload = NULL; -+ u64 next; -+ u64 prev_jc = 0; -+ u16 hw_job_id_offset = 0; -+ int ret = -EINVAL; -+ struct kbase_vmap_struct map; -+ -+ dev_dbg(kctx->kbdev->dev, "kbasep_replay_parse_payload: replay_atom->jc = %llx sizeof(payload) = %zu\n", -+ replay_atom->jc, sizeof(payload)); -+ -+ payload = kbase_vmap(kctx, replay_atom->jc, sizeof(*payload), &map); -+ if (!payload) { -+ dev_err(kctx->kbdev->dev, "kbasep_replay_parse_payload: failed to map payload into kernel space\n"); -+ return -EINVAL; -+ } -+ -+#ifdef BASE_LEGACY_UK10_2_SUPPORT -+ if (KBASE_API_VERSION(10, 3) > replay_atom->kctx->api_version) { -+ base_jd_replay_payload_uk10_2 *payload_uk10_2; -+ u16 tiler_core_req; -+ u16 fragment_core_req; -+ -+ payload_uk10_2 = (base_jd_replay_payload_uk10_2 *) payload; -+ memcpy(&tiler_core_req, &payload_uk10_2->tiler_core_req, -+ sizeof(tiler_core_req)); -+ memcpy(&fragment_core_req, &payload_uk10_2->fragment_core_req, -+ sizeof(fragment_core_req)); -+ payload->tiler_core_req = (u32)(tiler_core_req & 0x7fff); -+ payload->fragment_core_req = (u32)(fragment_core_req & 0x7fff); -+ } -+#endif /* BASE_LEGACY_UK10_2_SUPPORT */ -+ -+#ifdef CONFIG_MALI_DEBUG -+ dev_dbg(kctx->kbdev->dev, "kbasep_replay_parse_payload: payload=%p\n", payload); -+ dev_dbg(kctx->kbdev->dev, "Payload structure:\n" -+ "tiler_jc_list = %llx\n" -+ "fragment_jc = %llx\n" -+ "tiler_heap_free = %llx\n" -+ "fragment_hierarchy_mask = %x\n" -+ "tiler_hierarchy_mask = %x\n" -+ "hierarchy_default_weight = %x\n" -+ "tiler_core_req = %x\n" -+ "fragment_core_req = %x\n", -+ payload->tiler_jc_list, -+ payload->fragment_jc, -+ payload->tiler_heap_free, -+ payload->fragment_hierarchy_mask, -+ payload->tiler_hierarchy_mask, -+ payload->hierarchy_default_weight, -+ payload->tiler_core_req, -+ payload->fragment_core_req); -+ payload_dump(kctx, payload); -+#endif -+ t_atom->core_req = payload->tiler_core_req | BASEP_JD_REQ_EVENT_NEVER; -+ f_atom->core_req = payload->fragment_core_req | BASEP_JD_REQ_EVENT_NEVER; -+ -+ /* Sanity check core requirements*/ -+ if ((t_atom->core_req & BASE_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_T || -+ (f_atom->core_req & BASE_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_FS || -+ t_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES || -+ f_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) { -+ -+ int t_atom_type = t_atom->core_req & BASE_JD_REQ_ATOM_TYPE & ~BASE_JD_REQ_COHERENT_GROUP; -+ int f_atom_type = f_atom->core_req & BASE_JD_REQ_ATOM_TYPE & ~BASE_JD_REQ_COHERENT_GROUP & ~BASE_JD_REQ_FS_AFBC; -+ int t_has_ex_res = t_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES; -+ int f_has_ex_res = f_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES; -+ -+ if (t_atom_type != BASE_JD_REQ_T) { -+ dev_err(kctx->kbdev->dev, "Invalid core requirement: Tiler atom not a tiler job. Was: 0x%x\n Expected: 0x%x", -+ t_atom_type, BASE_JD_REQ_T); -+ } -+ if (f_atom_type != BASE_JD_REQ_FS) { -+ dev_err(kctx->kbdev->dev, "Invalid core requirement: Fragment shader atom not a fragment shader. Was 0x%x Expected: 0x%x\n", -+ f_atom_type, BASE_JD_REQ_FS); -+ } -+ if (t_has_ex_res) { -+ dev_err(kctx->kbdev->dev, "Invalid core requirement: Tiler atom has external resources.\n"); -+ } -+ if (f_has_ex_res) { -+ dev_err(kctx->kbdev->dev, "Invalid core requirement: Fragment shader atom has external resources.\n"); -+ } -+ -+ goto out; -+ } -+ -+ /* Process tiler job chains */ -+ next = payload->tiler_jc_list; -+ if (!next) { -+ dev_err(kctx->kbdev->dev, "Invalid tiler JC list\n"); -+ goto out; -+ } -+ -+ while (next) { -+ base_jd_replay_jc *jc_struct; -+ struct kbase_vmap_struct jc_map; -+ u64 jc; -+ -+ jc_struct = kbase_vmap(kctx, next, sizeof(*jc_struct), &jc_map); -+ -+ if (!jc_struct) { -+ dev_err(kctx->kbdev->dev, "Failed to map jc struct\n"); -+ goto out; -+ } -+ -+ jc = jc_struct->jc; -+ next = jc_struct->next; -+ if (next) -+ jc_struct->jc = 0; -+ -+ kbase_vunmap(kctx, &jc_map); -+ -+ if (jc) { -+ u16 max_hw_job_id = 0; -+ -+ if (kbasep_replay_find_hw_job_id(kctx, jc, -+ &max_hw_job_id) != 0) -+ goto out; -+ -+ if (kbasep_replay_parse_jc(kctx, jc, prev_jc, -+ payload->tiler_heap_free, -+ payload->tiler_hierarchy_mask, -+ payload->hierarchy_default_weight, -+ hw_job_id_offset, false) != 0) { -+ goto out; -+ } -+ -+ hw_job_id_offset += max_hw_job_id; -+ -+ prev_jc = jc; -+ } -+ } -+ t_atom->jc = prev_jc; -+ -+ /* Process fragment job chain */ -+ f_atom->jc = payload->fragment_jc; -+ if (kbasep_replay_parse_jc(kctx, payload->fragment_jc, 0, -+ payload->tiler_heap_free, -+ payload->fragment_hierarchy_mask, -+ payload->hierarchy_default_weight, 0, -+ true) != 0) { -+ goto out; -+ } -+ -+ if (!t_atom->jc || !f_atom->jc) { -+ dev_err(kctx->kbdev->dev, "Invalid payload\n"); -+ goto out; -+ } -+ -+ dev_dbg(kctx->kbdev->dev, "t_atom->jc=%llx f_atom->jc=%llx\n", -+ t_atom->jc, f_atom->jc); -+ ret = 0; -+ -+out: -+ kbase_vunmap(kctx, &map); -+ -+ return ret; -+} -+ -+static void kbase_replay_process_worker(struct work_struct *data) -+{ -+ struct kbase_jd_atom *katom; -+ struct kbase_context *kctx; -+ struct kbase_jd_context *jctx; -+ bool need_to_try_schedule_context = false; -+ -+ struct base_jd_atom_v2 t_atom, f_atom; -+ struct kbase_jd_atom *t_katom, *f_katom; -+ base_jd_prio atom_prio; -+ -+ katom = container_of(data, struct kbase_jd_atom, work); -+ kctx = katom->kctx; -+ jctx = &kctx->jctx; -+ -+ mutex_lock(&jctx->lock); -+ -+ atom_prio = kbasep_js_sched_prio_to_atom_prio(katom->sched_priority); -+ -+ if (kbasep_replay_create_atoms( -+ kctx, &t_atom, &f_atom, atom_prio) != 0) { -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ goto out; -+ } -+ -+ t_katom = &jctx->atoms[t_atom.atom_number]; -+ f_katom = &jctx->atoms[f_atom.atom_number]; -+ -+ if (kbasep_replay_parse_payload(kctx, katom, &t_atom, &f_atom) != 0) { -+ kbasep_release_katom(kctx, t_atom.atom_number); -+ kbasep_release_katom(kctx, f_atom.atom_number); -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ goto out; -+ } -+ -+ kbasep_replay_reset_softjob(katom, f_katom); -+ -+ need_to_try_schedule_context |= jd_submit_atom(kctx, &t_atom, t_katom); -+ if (t_katom->event_code == BASE_JD_EVENT_JOB_INVALID) { -+ dev_err(kctx->kbdev->dev, "Replay failed to submit atom\n"); -+ kbasep_release_katom(kctx, f_atom.atom_number); -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ goto out; -+ } -+ need_to_try_schedule_context |= jd_submit_atom(kctx, &f_atom, f_katom); -+ if (f_katom->event_code == BASE_JD_EVENT_JOB_INVALID) { -+ dev_err(kctx->kbdev->dev, "Replay failed to submit atom\n"); -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ goto out; -+ } -+ -+ katom->event_code = BASE_JD_EVENT_DONE; -+ -+out: -+ if (katom->event_code != BASE_JD_EVENT_DONE) { -+ kbase_disjoint_state_down(kctx->kbdev); -+ -+ need_to_try_schedule_context |= jd_done_nolock(katom, NULL); -+ } -+ -+ if (need_to_try_schedule_context) -+ kbase_js_sched_all(kctx->kbdev); -+ -+ mutex_unlock(&jctx->lock); -+} -+ -+/** -+ * @brief Check job replay fault -+ * -+ * This will read the job payload, checks fault type and source, then decides -+ * whether replay is required. -+ * -+ * @param[in] katom The atom to be processed -+ * @return true (success) if replay required or false on failure. -+ */ -+static bool kbase_replay_fault_check(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ struct device *dev = kctx->kbdev->dev; -+ base_jd_replay_payload *payload; -+ u64 job_header; -+ u64 job_loop_detect; -+ struct job_descriptor_header *job; -+ struct kbase_vmap_struct job_map; -+ struct kbase_vmap_struct map; -+ bool err = false; -+ -+ /* Replay job if fault is of type BASE_JD_EVENT_JOB_WRITE_FAULT or -+ * if force_replay is enabled. -+ */ -+ if (BASE_JD_EVENT_TERMINATED == katom->event_code) { -+ return false; -+ } else if (BASE_JD_EVENT_JOB_WRITE_FAULT == katom->event_code) { -+ return true; -+ } else if (BASE_JD_EVENT_FORCE_REPLAY == katom->event_code) { -+ katom->event_code = BASE_JD_EVENT_DATA_INVALID_FAULT; -+ return true; -+ } else if (BASE_JD_EVENT_DATA_INVALID_FAULT != katom->event_code) { -+ /* No replay for faults of type other than -+ * BASE_JD_EVENT_DATA_INVALID_FAULT. -+ */ -+ return false; -+ } -+ -+ /* Job fault is BASE_JD_EVENT_DATA_INVALID_FAULT, now scan fragment jc -+ * to find out whether the source of exception is POLYGON_LIST. Replay -+ * is required if the source of fault is POLYGON_LIST. -+ */ -+ payload = kbase_vmap(kctx, katom->jc, sizeof(*payload), &map); -+ if (!payload) { -+ dev_err(dev, "kbase_replay_fault_check: failed to map payload.\n"); -+ return false; -+ } -+ -+#ifdef CONFIG_MALI_DEBUG -+ dev_dbg(dev, "kbase_replay_fault_check: payload=%p\n", payload); -+ dev_dbg(dev, "\nPayload structure:\n" -+ "fragment_jc = 0x%llx\n" -+ "fragment_hierarchy_mask = 0x%x\n" -+ "fragment_core_req = 0x%x\n", -+ payload->fragment_jc, -+ payload->fragment_hierarchy_mask, -+ payload->fragment_core_req); -+#endif -+ /* Process fragment job chain */ -+ job_header = (u64) payload->fragment_jc; -+ job_loop_detect = job_header; -+ while (job_header) { -+ job = kbase_vmap(kctx, job_header, sizeof(*job), &job_map); -+ if (!job) { -+ dev_err(dev, "failed to map jc\n"); -+ /* unmap payload*/ -+ kbase_vunmap(kctx, &map); -+ return false; -+ } -+ -+ -+ dump_job_head(kctx, "\njob_head structure:\n", job); -+ -+ /* Replay only when the polygon list reader caused the -+ * DATA_INVALID_FAULT */ -+ if ((BASE_JD_EVENT_DATA_INVALID_FAULT == katom->event_code) && -+ (JOB_POLYGON_LIST == JOB_SOURCE_ID(job->exception_status))) { -+ err = true; -+ kbase_vunmap(kctx, &job_map); -+ break; -+ } -+ -+ /* Move on to next fragment job in the list */ -+ if (job->job_descriptor_size) -+ job_header = job->next_job._64; -+ else -+ job_header = job->next_job._32; -+ -+ kbase_vunmap(kctx, &job_map); -+ -+ /* Job chain loop detected */ -+ if (job_header == job_loop_detect) -+ break; -+ } -+ -+ /* unmap payload*/ -+ kbase_vunmap(kctx, &map); -+ -+ return err; -+} -+ -+ -+/** -+ * @brief Process a replay job -+ * -+ * Called from kbase_process_soft_job. -+ * -+ * On exit, if the job has completed, katom->event_code will have been updated. -+ * If the job has not completed, and is replaying jobs, then the atom status -+ * will have been reset to KBASE_JD_ATOM_STATE_QUEUED. -+ * -+ * @param[in] katom The atom to be processed -+ * @return false if the atom has completed -+ * true if the atom is replaying jobs -+ */ -+bool kbase_replay_process(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ struct kbase_device *kbdev = kctx->kbdev; -+ -+ /* Don't replay this atom if these issues are not present in the -+ * hardware */ -+ if (!kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_11020) && -+ !kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_11024)) { -+ dev_dbg(kbdev->dev, "Hardware does not need replay workaround"); -+ -+ /* Signal failure to userspace */ -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ -+ return false; -+ } -+ -+ if (katom->event_code == BASE_JD_EVENT_DONE) { -+ dev_dbg(kbdev->dev, "Previous job succeeded - not replaying\n"); -+ -+ if (katom->retry_count) -+ kbase_disjoint_state_down(kbdev); -+ -+ return false; -+ } -+ -+ if (kbase_ctx_flag(kctx, KCTX_DYING)) { -+ dev_dbg(kbdev->dev, "Not replaying; context is dying\n"); -+ -+ if (katom->retry_count) -+ kbase_disjoint_state_down(kbdev); -+ -+ return false; -+ } -+ -+ /* Check job exception type and source before replaying. */ -+ if (!kbase_replay_fault_check(katom)) { -+ dev_dbg(kbdev->dev, -+ "Replay cancelled on event %x\n", katom->event_code); -+ /* katom->event_code is already set to the failure code of the -+ * previous job. -+ */ -+ return false; -+ } -+ -+ dev_warn(kbdev->dev, "Replaying jobs retry=%d\n", -+ katom->retry_count); -+ -+ katom->retry_count++; -+ -+ if (katom->retry_count > BASEP_JD_REPLAY_LIMIT) { -+ dev_err(kbdev->dev, "Replay exceeded limit - failing jobs\n"); -+ -+ kbase_disjoint_state_down(kbdev); -+ -+ /* katom->event_code is already set to the failure code of the -+ previous job */ -+ return false; -+ } -+ -+ /* only enter the disjoint state once for the whole time while the replay is ongoing */ -+ if (katom->retry_count == 1) -+ kbase_disjoint_state_up(kbdev); -+ -+ INIT_WORK(&katom->work, kbase_replay_process_worker); -+ queue_work(kctx->event_workq, &katom->work); -+ -+ return true; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_smc.c b/drivers/gpu/arm/midgard/mali_kbase_smc.c -new file mode 100644 -index 0000000..43175c8 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_smc.c -@@ -0,0 +1,74 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifdef CONFIG_ARM64 -+ -+#include -+#include -+ -+#include -+ -+static noinline u64 invoke_smc_fid(u64 function_id, -+ u64 arg0, u64 arg1, u64 arg2) -+{ -+ register u64 x0 asm("x0") = function_id; -+ register u64 x1 asm("x1") = arg0; -+ register u64 x2 asm("x2") = arg1; -+ register u64 x3 asm("x3") = arg2; -+ -+ asm volatile( -+ __asmeq("%0", "x0") -+ __asmeq("%1", "x1") -+ __asmeq("%2", "x2") -+ __asmeq("%3", "x3") -+ "smc #0\n" -+ : "+r" (x0) -+ : "r" (x1), "r" (x2), "r" (x3)); -+ -+ return x0; -+} -+ -+u64 kbase_invoke_smc_fid(u32 fid, u64 arg0, u64 arg1, u64 arg2) -+{ -+ /* Is fast call (bit 31 set) */ -+ KBASE_DEBUG_ASSERT(fid & ~SMC_FAST_CALL); -+ /* bits 16-23 must be zero for fast calls */ -+ KBASE_DEBUG_ASSERT((fid & (0xFF << 16)) == 0); -+ -+ return invoke_smc_fid(fid, arg0, arg1, arg2); -+} -+ -+u64 kbase_invoke_smc(u32 oen, u16 function_number, bool smc64, -+ u64 arg0, u64 arg1, u64 arg2) -+{ -+ u32 fid = 0; -+ -+ /* Only the six bits allowed should be used. */ -+ KBASE_DEBUG_ASSERT((oen & ~SMC_OEN_MASK) == 0); -+ -+ fid |= SMC_FAST_CALL; /* Bit 31: Fast call */ -+ if (smc64) -+ fid |= SMC_64; /* Bit 30: 1=SMC64, 0=SMC32 */ -+ fid |= oen; /* Bit 29:24: OEN */ -+ /* Bit 23:16: Must be zero for fast calls */ -+ fid |= (function_number); /* Bit 15:0: function number */ -+ -+ return kbase_invoke_smc_fid(fid, arg0, arg1, arg2); -+} -+ -+#endif /* CONFIG_ARM64 */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_smc.h b/drivers/gpu/arm/midgard/mali_kbase_smc.h -new file mode 100644 -index 0000000..9bff3d2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_smc.h -@@ -0,0 +1,67 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KBASE_SMC_H_ -+#define _KBASE_SMC_H_ -+ -+#ifdef CONFIG_ARM64 -+ -+#include -+ -+#define SMC_FAST_CALL (1 << 31) -+#define SMC_64 (1 << 30) -+ -+#define SMC_OEN_OFFSET 24 -+#define SMC_OEN_MASK (0x3F << SMC_OEN_OFFSET) /* 6 bits */ -+#define SMC_OEN_SIP (2 << SMC_OEN_OFFSET) -+#define SMC_OEN_STD (4 << SMC_OEN_OFFSET) -+ -+ -+/** -+ * kbase_invoke_smc_fid - Perform a secure monitor call -+ * @fid: The SMC function to call, see SMC Calling convention. -+ * @arg0: First argument to the SMC. -+ * @arg1: Second argument to the SMC. -+ * @arg2: Third argument to the SMC. -+ * -+ * See SMC Calling Convention for details. -+ * -+ * Return: the return value from the SMC. -+ */ -+u64 kbase_invoke_smc_fid(u32 fid, u64 arg0, u64 arg1, u64 arg2); -+ -+/** -+ * kbase_invoke_smc_fid - Perform a secure monitor call -+ * @oen: Owning Entity number (SIP, STD etc). -+ * @function_number: The function number within the OEN. -+ * @smc64: use SMC64 calling convention instead of SMC32. -+ * @arg0: First argument to the SMC. -+ * @arg1: Second argument to the SMC. -+ * @arg2: Third argument to the SMC. -+ * -+ * See SMC Calling Convention for details. -+ * -+ * Return: the return value from the SMC call. -+ */ -+u64 kbase_invoke_smc(u32 oen, u16 function_number, bool smc64, -+ u64 arg0, u64 arg1, u64 arg2); -+ -+#endif /* CONFIG_ARM64 */ -+ -+#endif /* _KBASE_SMC_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_softjobs.c b/drivers/gpu/arm/midgard/mali_kbase_softjobs.c -new file mode 100644 -index 0000000..29e76a9 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_softjobs.c -@@ -0,0 +1,1512 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+ -+#if defined(CONFIG_DMA_SHARED_BUFFER) -+#include -+#include -+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */ -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+#include -+#endif -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Mask to check cache alignment of data structures */ -+#define KBASE_CACHE_ALIGNMENT_MASK ((1<kctx; -+ unsigned long lflags; -+ -+ spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags); -+ list_add_tail(&katom->queue, &kctx->waiting_soft_jobs); -+ spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags); -+} -+ -+void kbasep_remove_waiting_soft_job(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ unsigned long lflags; -+ -+ spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags); -+ list_del(&katom->queue); -+ spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags); -+} -+ -+static void kbasep_add_waiting_with_timeout(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ -+ /* Record the start time of this atom so we could cancel it at -+ * the right time. -+ */ -+ katom->start_timestamp = ktime_get(); -+ -+ /* Add the atom to the waiting list before the timer is -+ * (re)started to make sure that it gets processed. -+ */ -+ kbasep_add_waiting_soft_job(katom); -+ -+ /* Schedule timeout of this atom after a period if it is not active */ -+ if (!timer_pending(&kctx->soft_job_timeout)) { -+ int timeout_ms = atomic_read( -+ &kctx->kbdev->js_data.soft_job_timeout_ms); -+ mod_timer(&kctx->soft_job_timeout, -+ jiffies + msecs_to_jiffies(timeout_ms)); -+ } -+} -+ -+static int kbasep_read_soft_event_status( -+ struct kbase_context *kctx, u64 evt, unsigned char *status) -+{ -+ unsigned char *mapped_evt; -+ struct kbase_vmap_struct map; -+ -+ mapped_evt = kbase_vmap(kctx, evt, sizeof(*mapped_evt), &map); -+ if (!mapped_evt) -+ return -EFAULT; -+ -+ *status = *mapped_evt; -+ -+ kbase_vunmap(kctx, &map); -+ -+ return 0; -+} -+ -+static int kbasep_write_soft_event_status( -+ struct kbase_context *kctx, u64 evt, unsigned char new_status) -+{ -+ unsigned char *mapped_evt; -+ struct kbase_vmap_struct map; -+ -+ if ((new_status != BASE_JD_SOFT_EVENT_SET) && -+ (new_status != BASE_JD_SOFT_EVENT_RESET)) -+ return -EINVAL; -+ -+ mapped_evt = kbase_vmap(kctx, evt, sizeof(*mapped_evt), &map); -+ if (!mapped_evt) -+ return -EFAULT; -+ -+ *mapped_evt = new_status; -+ -+ kbase_vunmap(kctx, &map); -+ -+ return 0; -+} -+ -+static int kbase_dump_cpu_gpu_time(struct kbase_jd_atom *katom) -+{ -+ struct kbase_vmap_struct map; -+ void *user_result; -+ struct timespec ts; -+ struct base_dump_cpu_gpu_counters data; -+ u64 system_time; -+ u64 cycle_counter; -+ u64 jc = katom->jc; -+ struct kbase_context *kctx = katom->kctx; -+ int pm_active_err; -+ -+ memset(&data, 0, sizeof(data)); -+ -+ /* Take the PM active reference as late as possible - otherwise, it could -+ * delay suspend until we process the atom (which may be at the end of a -+ * long chain of dependencies */ -+ pm_active_err = kbase_pm_context_active_handle_suspend(kctx->kbdev, KBASE_PM_SUSPEND_HANDLER_DONT_REACTIVATE); -+ if (pm_active_err) { -+ struct kbasep_js_device_data *js_devdata = &kctx->kbdev->js_data; -+ -+ /* We're suspended - queue this on the list of suspended jobs -+ * Use dep_item[1], because dep_item[0] was previously in use -+ * for 'waiting_soft_jobs'. -+ */ -+ mutex_lock(&js_devdata->runpool_mutex); -+ list_add_tail(&katom->dep_item[1], &js_devdata->suspended_soft_jobs_list); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ /* Also adding this to the list of waiting soft job */ -+ kbasep_add_waiting_soft_job(katom); -+ -+ return pm_active_err; -+ } -+ -+ kbase_backend_get_gpu_time(kctx->kbdev, &cycle_counter, &system_time, -+ &ts); -+ -+ kbase_pm_context_idle(kctx->kbdev); -+ -+ data.sec = ts.tv_sec; -+ data.usec = ts.tv_nsec / 1000; -+ data.system_time = system_time; -+ data.cycle_counter = cycle_counter; -+ -+ /* Assume this atom will be cancelled until we know otherwise */ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ -+ /* GPU_WR access is checked on the range for returning the result to -+ * userspace for the following reasons: -+ * - security, this is currently how imported user bufs are checked. -+ * - userspace ddk guaranteed to assume region was mapped as GPU_WR */ -+ user_result = kbase_vmap_prot(kctx, jc, sizeof(data), KBASE_REG_GPU_WR, &map); -+ if (!user_result) -+ return 0; -+ -+ memcpy(user_result, &data, sizeof(data)); -+ -+ kbase_vunmap(kctx, &map); -+ -+ /* Atom was fine - mark it as done */ -+ katom->event_code = BASE_JD_EVENT_DONE; -+ -+ return 0; -+} -+ -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+/* Called by the explicit fence mechanism when a fence wait has completed */ -+void kbase_soft_event_wait_callback(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ -+ mutex_lock(&kctx->jctx.lock); -+ kbasep_remove_waiting_soft_job(katom); -+ kbase_finish_soft_job(katom); -+ if (jd_done_nolock(katom, NULL)) -+ kbase_js_sched_all(kctx->kbdev); -+ mutex_unlock(&kctx->jctx.lock); -+} -+#endif -+ -+static void kbasep_soft_event_complete_job(struct work_struct *work) -+{ -+ struct kbase_jd_atom *katom = container_of(work, struct kbase_jd_atom, -+ work); -+ struct kbase_context *kctx = katom->kctx; -+ int resched; -+ -+ mutex_lock(&kctx->jctx.lock); -+ resched = jd_done_nolock(katom, NULL); -+ mutex_unlock(&kctx->jctx.lock); -+ -+ if (resched) -+ kbase_js_sched_all(kctx->kbdev); -+} -+ -+void kbasep_complete_triggered_soft_events(struct kbase_context *kctx, u64 evt) -+{ -+ int cancel_timer = 1; -+ struct list_head *entry, *tmp; -+ unsigned long lflags; -+ -+ spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags); -+ list_for_each_safe(entry, tmp, &kctx->waiting_soft_jobs) { -+ struct kbase_jd_atom *katom = list_entry( -+ entry, struct kbase_jd_atom, queue); -+ -+ switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) { -+ case BASE_JD_REQ_SOFT_EVENT_WAIT: -+ if (katom->jc == evt) { -+ list_del(&katom->queue); -+ -+ katom->event_code = BASE_JD_EVENT_DONE; -+ INIT_WORK(&katom->work, -+ kbasep_soft_event_complete_job); -+ queue_work(kctx->jctx.job_done_wq, -+ &katom->work); -+ } else { -+ /* There are still other waiting jobs, we cannot -+ * cancel the timer yet. -+ */ -+ cancel_timer = 0; -+ } -+ break; -+#ifdef CONFIG_MALI_FENCE_DEBUG -+ case BASE_JD_REQ_SOFT_FENCE_WAIT: -+ /* Keep the timer running if fence debug is enabled and -+ * there are waiting fence jobs. -+ */ -+ cancel_timer = 0; -+ break; -+#endif -+ } -+ } -+ -+ if (cancel_timer) -+ del_timer(&kctx->soft_job_timeout); -+ spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags); -+} -+ -+#ifdef CONFIG_MALI_FENCE_DEBUG -+static void kbase_fence_debug_check_atom(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ struct device *dev = kctx->kbdev->dev; -+ int i; -+ -+ for (i = 0; i < 2; i++) { -+ struct kbase_jd_atom *dep; -+ -+ list_for_each_entry(dep, &katom->dep_head[i], dep_item[i]) { -+ if (dep->status == KBASE_JD_ATOM_STATE_UNUSED || -+ dep->status == KBASE_JD_ATOM_STATE_COMPLETED) -+ continue; -+ -+ if ((dep->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) -+ == BASE_JD_REQ_SOFT_FENCE_TRIGGER) { -+ /* Found blocked trigger fence. */ -+ struct kbase_sync_fence_info info; -+ -+ if (!kbase_sync_fence_in_info_get(dep, &info)) { -+ dev_warn(dev, -+ "\tVictim trigger atom %d fence [%p] %s: %s\n", -+ kbase_jd_atom_id(kctx, dep), -+ info.fence, -+ info.name, -+ kbase_sync_status_string(info.status)); -+ } -+ } -+ -+ kbase_fence_debug_check_atom(dep); -+ } -+ } -+} -+ -+static void kbase_fence_debug_wait_timeout(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ struct device *dev = katom->kctx->kbdev->dev; -+ int timeout_ms = atomic_read(&kctx->kbdev->js_data.soft_job_timeout_ms); -+ unsigned long lflags; -+ struct kbase_sync_fence_info info; -+ -+ spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags); -+ -+ if (kbase_sync_fence_in_info_get(katom, &info)) { -+ /* Fence must have signaled just after timeout. */ -+ spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags); -+ return; -+ } -+ -+ dev_warn(dev, "ctx %d_%d: Atom %d still waiting for fence [%p] after %dms\n", -+ kctx->tgid, kctx->id, -+ kbase_jd_atom_id(kctx, katom), -+ info.fence, timeout_ms); -+ dev_warn(dev, "\tGuilty fence [%p] %s: %s\n", -+ info.fence, info.name, -+ kbase_sync_status_string(info.status)); -+ -+ /* Search for blocked trigger atoms */ -+ kbase_fence_debug_check_atom(katom); -+ -+ spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags); -+ -+ kbase_sync_fence_in_dump(katom); -+} -+ -+struct kbase_fence_debug_work { -+ struct kbase_jd_atom *katom; -+ struct work_struct work; -+}; -+ -+static void kbase_fence_debug_wait_timeout_worker(struct work_struct *work) -+{ -+ struct kbase_fence_debug_work *w = container_of(work, -+ struct kbase_fence_debug_work, work); -+ struct kbase_jd_atom *katom = w->katom; -+ struct kbase_context *kctx = katom->kctx; -+ -+ mutex_lock(&kctx->jctx.lock); -+ kbase_fence_debug_wait_timeout(katom); -+ mutex_unlock(&kctx->jctx.lock); -+ -+ kfree(w); -+} -+ -+static void kbase_fence_debug_timeout(struct kbase_jd_atom *katom) -+{ -+ struct kbase_fence_debug_work *work; -+ struct kbase_context *kctx = katom->kctx; -+ -+ /* Enqueue fence debug worker. Use job_done_wq to get -+ * debug print ordered with job completion. -+ */ -+ work = kzalloc(sizeof(struct kbase_fence_debug_work), GFP_ATOMIC); -+ /* Ignore allocation failure. */ -+ if (work) { -+ work->katom = katom; -+ INIT_WORK(&work->work, kbase_fence_debug_wait_timeout_worker); -+ queue_work(kctx->jctx.job_done_wq, &work->work); -+ } -+} -+#endif /* CONFIG_MALI_FENCE_DEBUG */ -+ -+void kbasep_soft_job_timeout_worker(unsigned long data) -+{ -+ struct kbase_context *kctx = (struct kbase_context *)data; -+ u32 timeout_ms = (u32)atomic_read( -+ &kctx->kbdev->js_data.soft_job_timeout_ms); -+ struct timer_list *timer = &kctx->soft_job_timeout; -+ ktime_t cur_time = ktime_get(); -+ bool restarting = false; -+ unsigned long lflags; -+ struct list_head *entry, *tmp; -+ -+ spin_lock_irqsave(&kctx->waiting_soft_jobs_lock, lflags); -+ list_for_each_safe(entry, tmp, &kctx->waiting_soft_jobs) { -+ struct kbase_jd_atom *katom = list_entry(entry, -+ struct kbase_jd_atom, queue); -+ s64 elapsed_time = ktime_to_ms(ktime_sub(cur_time, -+ katom->start_timestamp)); -+ -+ if (elapsed_time < (s64)timeout_ms) { -+ restarting = true; -+ continue; -+ } -+ -+ switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) { -+ case BASE_JD_REQ_SOFT_EVENT_WAIT: -+ /* Take it out of the list to ensure that it -+ * will be cancelled in all cases -+ */ -+ list_del(&katom->queue); -+ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ INIT_WORK(&katom->work, kbasep_soft_event_complete_job); -+ queue_work(kctx->jctx.job_done_wq, &katom->work); -+ break; -+#ifdef CONFIG_MALI_FENCE_DEBUG -+ case BASE_JD_REQ_SOFT_FENCE_WAIT: -+ kbase_fence_debug_timeout(katom); -+ break; -+#endif -+ } -+ } -+ -+ if (restarting) -+ mod_timer(timer, jiffies + msecs_to_jiffies(timeout_ms)); -+ spin_unlock_irqrestore(&kctx->waiting_soft_jobs_lock, lflags); -+} -+ -+static int kbasep_soft_event_wait(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ unsigned char status; -+ -+ /* The status of this soft-job is stored in jc */ -+ if (kbasep_read_soft_event_status(kctx, katom->jc, &status)) { -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ return 0; -+ } -+ -+ if (status == BASE_JD_SOFT_EVENT_SET) -+ return 0; /* Event already set, nothing to do */ -+ -+ kbasep_add_waiting_with_timeout(katom); -+ -+ return 1; -+} -+ -+static void kbasep_soft_event_update_locked(struct kbase_jd_atom *katom, -+ unsigned char new_status) -+{ -+ /* Complete jobs waiting on the same event */ -+ struct kbase_context *kctx = katom->kctx; -+ -+ if (kbasep_write_soft_event_status(kctx, katom->jc, new_status) != 0) { -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ return; -+ } -+ -+ if (new_status == BASE_JD_SOFT_EVENT_SET) -+ kbasep_complete_triggered_soft_events(kctx, katom->jc); -+} -+ -+/** -+ * kbase_soft_event_update() - Update soft event state -+ * @kctx: Pointer to context -+ * @event: Event to update -+ * @new_status: New status value of event -+ * -+ * Update the event, and wake up any atoms waiting for the event. -+ * -+ * Return: 0 on success, a negative error code on failure. -+ */ -+int kbase_soft_event_update(struct kbase_context *kctx, -+ u64 event, -+ unsigned char new_status) -+{ -+ int err = 0; -+ -+ mutex_lock(&kctx->jctx.lock); -+ -+ if (kbasep_write_soft_event_status(kctx, event, new_status)) { -+ err = -ENOENT; -+ goto out; -+ } -+ -+ if (new_status == BASE_JD_SOFT_EVENT_SET) -+ kbasep_complete_triggered_soft_events(kctx, event); -+ -+out: -+ mutex_unlock(&kctx->jctx.lock); -+ -+ return err; -+} -+ -+static void kbasep_soft_event_cancel_job(struct kbase_jd_atom *katom) -+{ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ if (jd_done_nolock(katom, NULL)) -+ kbase_js_sched_all(katom->kctx->kbdev); -+} -+ -+struct kbase_debug_copy_buffer { -+ size_t size; -+ struct page **pages; -+ int nr_pages; -+ size_t offset; -+ struct kbase_mem_phy_alloc *gpu_alloc; -+ -+ struct page **extres_pages; -+ int nr_extres_pages; -+}; -+ -+static inline void free_user_buffer(struct kbase_debug_copy_buffer *buffer) -+{ -+ struct page **pages = buffer->extres_pages; -+ int nr_pages = buffer->nr_extres_pages; -+ -+ if (pages) { -+ int i; -+ -+ for (i = 0; i < nr_pages; i++) { -+ struct page *pg = pages[i]; -+ -+ if (pg) -+ put_page(pg); -+ } -+ kfree(pages); -+ } -+} -+ -+static void kbase_debug_copy_finish(struct kbase_jd_atom *katom) -+{ -+ struct kbase_debug_copy_buffer *buffers = -+ (struct kbase_debug_copy_buffer *)(uintptr_t)katom->jc; -+ unsigned int i; -+ unsigned int nr = katom->nr_extres; -+ -+ if (!buffers) -+ return; -+ -+ kbase_gpu_vm_lock(katom->kctx); -+ for (i = 0; i < nr; i++) { -+ int p; -+ struct kbase_mem_phy_alloc *gpu_alloc = buffers[i].gpu_alloc; -+ -+ if (!buffers[i].pages) -+ break; -+ for (p = 0; p < buffers[i].nr_pages; p++) { -+ struct page *pg = buffers[i].pages[p]; -+ -+ if (pg) -+ put_page(pg); -+ } -+ kfree(buffers[i].pages); -+ if (gpu_alloc) { -+ switch (gpu_alloc->type) { -+ case KBASE_MEM_TYPE_IMPORTED_USER_BUF: -+ { -+ free_user_buffer(&buffers[i]); -+ break; -+ } -+ default: -+ /* Nothing to be done. */ -+ break; -+ } -+ kbase_mem_phy_alloc_put(gpu_alloc); -+ } -+ } -+ kbase_gpu_vm_unlock(katom->kctx); -+ kfree(buffers); -+ -+ katom->jc = 0; -+} -+ -+static int kbase_debug_copy_prepare(struct kbase_jd_atom *katom) -+{ -+ struct kbase_debug_copy_buffer *buffers; -+ struct base_jd_debug_copy_buffer *user_buffers = NULL; -+ unsigned int i; -+ unsigned int nr = katom->nr_extres; -+ int ret = 0; -+ void __user *user_structs = (void __user *)(uintptr_t)katom->jc; -+ -+ if (!user_structs) -+ return -EINVAL; -+ -+ buffers = kcalloc(nr, sizeof(*buffers), GFP_KERNEL); -+ if (!buffers) { -+ ret = -ENOMEM; -+ katom->jc = 0; -+ goto out_cleanup; -+ } -+ katom->jc = (u64)(uintptr_t)buffers; -+ -+ user_buffers = kmalloc_array(nr, sizeof(*user_buffers), GFP_KERNEL); -+ -+ if (!user_buffers) { -+ ret = -ENOMEM; -+ goto out_cleanup; -+ } -+ -+ ret = copy_from_user(user_buffers, user_structs, -+ sizeof(*user_buffers)*nr); -+ if (ret) { -+ ret = -EFAULT; -+ goto out_cleanup; -+ } -+ -+ for (i = 0; i < nr; i++) { -+ u64 addr = user_buffers[i].address; -+ u64 page_addr = addr & PAGE_MASK; -+ u64 end_page_addr = addr + user_buffers[i].size - 1; -+ u64 last_page_addr = end_page_addr & PAGE_MASK; -+ int nr_pages = (last_page_addr-page_addr)/PAGE_SIZE+1; -+ int pinned_pages; -+ struct kbase_va_region *reg; -+ struct base_external_resource user_extres; -+ -+ if (!addr) -+ continue; -+ -+ buffers[i].nr_pages = nr_pages; -+ buffers[i].offset = addr & ~PAGE_MASK; -+ if (buffers[i].offset >= PAGE_SIZE) { -+ ret = -EINVAL; -+ goto out_cleanup; -+ } -+ buffers[i].size = user_buffers[i].size; -+ -+ buffers[i].pages = kcalloc(nr_pages, sizeof(struct page *), -+ GFP_KERNEL); -+ if (!buffers[i].pages) { -+ ret = -ENOMEM; -+ goto out_cleanup; -+ } -+ -+ pinned_pages = get_user_pages_fast(page_addr, -+ nr_pages, -+ 1, /* Write */ -+ buffers[i].pages); -+ if (pinned_pages < 0) { -+ ret = pinned_pages; -+ goto out_cleanup; -+ } -+ if (pinned_pages != nr_pages) { -+ ret = -EINVAL; -+ goto out_cleanup; -+ } -+ -+ user_extres = user_buffers[i].extres; -+ if (user_extres.ext_resource == 0ULL) { -+ ret = -EINVAL; -+ goto out_cleanup; -+ } -+ -+ kbase_gpu_vm_lock(katom->kctx); -+ reg = kbase_region_tracker_find_region_enclosing_address( -+ katom->kctx, user_extres.ext_resource & -+ ~BASE_EXT_RES_ACCESS_EXCLUSIVE); -+ -+ if (NULL == reg || NULL == reg->gpu_alloc || -+ (reg->flags & KBASE_REG_FREE)) { -+ ret = -EINVAL; -+ goto out_unlock; -+ } -+ -+ buffers[i].gpu_alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc); -+ buffers[i].nr_extres_pages = reg->nr_pages; -+ -+ if (reg->nr_pages*PAGE_SIZE != buffers[i].size) -+ dev_warn(katom->kctx->kbdev->dev, "Copy buffer is not of same size as the external resource to copy.\n"); -+ -+ switch (reg->gpu_alloc->type) { -+ case KBASE_MEM_TYPE_IMPORTED_USER_BUF: -+ { -+ struct kbase_mem_phy_alloc *alloc = reg->gpu_alloc; -+ unsigned long nr_pages = -+ alloc->imported.user_buf.nr_pages; -+ -+ if (alloc->imported.user_buf.mm != current->mm) { -+ ret = -EINVAL; -+ goto out_unlock; -+ } -+ buffers[i].extres_pages = kcalloc(nr_pages, -+ sizeof(struct page *), GFP_KERNEL); -+ if (!buffers[i].extres_pages) { -+ ret = -ENOMEM; -+ goto out_unlock; -+ } -+ -+ ret = get_user_pages_fast( -+ alloc->imported.user_buf.address, -+ nr_pages, 0, -+ buffers[i].extres_pages); -+ if (ret != nr_pages) -+ goto out_unlock; -+ ret = 0; -+ break; -+ } -+ case KBASE_MEM_TYPE_IMPORTED_UMP: -+ { -+ dev_warn(katom->kctx->kbdev->dev, -+ "UMP is not supported for debug_copy jobs\n"); -+ ret = -EINVAL; -+ goto out_unlock; -+ } -+ default: -+ /* Nothing to be done. */ -+ break; -+ } -+ kbase_gpu_vm_unlock(katom->kctx); -+ } -+ kfree(user_buffers); -+ -+ return ret; -+ -+out_unlock: -+ kbase_gpu_vm_unlock(katom->kctx); -+ -+out_cleanup: -+ kfree(buffers); -+ kfree(user_buffers); -+ -+ /* Frees allocated memory for kbase_debug_copy_job struct, including -+ * members, and sets jc to 0 */ -+ kbase_debug_copy_finish(katom); -+ return ret; -+} -+ -+static void kbase_mem_copy_from_extres_page(struct kbase_context *kctx, -+ void *extres_page, struct page **pages, unsigned int nr_pages, -+ unsigned int *target_page_nr, size_t offset, size_t *to_copy) -+{ -+ void *target_page = kmap(pages[*target_page_nr]); -+ size_t chunk = PAGE_SIZE-offset; -+ -+ lockdep_assert_held(&kctx->reg_lock); -+ -+ if (!target_page) { -+ *target_page_nr += 1; -+ dev_warn(kctx->kbdev->dev, "kmap failed in debug_copy job."); -+ return; -+ } -+ -+ chunk = min(chunk, *to_copy); -+ -+ memcpy(target_page + offset, extres_page, chunk); -+ *to_copy -= chunk; -+ -+ kunmap(pages[*target_page_nr]); -+ -+ *target_page_nr += 1; -+ if (*target_page_nr >= nr_pages) -+ return; -+ -+ target_page = kmap(pages[*target_page_nr]); -+ if (!target_page) { -+ *target_page_nr += 1; -+ dev_warn(kctx->kbdev->dev, "kmap failed in debug_copy job."); -+ return; -+ } -+ -+ KBASE_DEBUG_ASSERT(target_page); -+ -+ chunk = min(offset, *to_copy); -+ memcpy(target_page, extres_page + PAGE_SIZE-offset, chunk); -+ *to_copy -= chunk; -+ -+ kunmap(pages[*target_page_nr]); -+} -+ -+static int kbase_mem_copy_from_extres(struct kbase_context *kctx, -+ struct kbase_debug_copy_buffer *buf_data) -+{ -+ unsigned int i; -+ unsigned int target_page_nr = 0; -+ struct page **pages = buf_data->pages; -+ u64 offset = buf_data->offset; -+ size_t extres_size = buf_data->nr_extres_pages*PAGE_SIZE; -+ size_t to_copy = min(extres_size, buf_data->size); -+ struct kbase_mem_phy_alloc *gpu_alloc = buf_data->gpu_alloc; -+ int ret = 0; -+ -+ KBASE_DEBUG_ASSERT(pages != NULL); -+ -+ kbase_gpu_vm_lock(kctx); -+ if (!gpu_alloc) { -+ ret = -EINVAL; -+ goto out_unlock; -+ } -+ -+ switch (gpu_alloc->type) { -+ case KBASE_MEM_TYPE_IMPORTED_USER_BUF: -+ { -+ for (i = 0; i < buf_data->nr_extres_pages; i++) { -+ struct page *pg = buf_data->extres_pages[i]; -+ void *extres_page = kmap(pg); -+ -+ if (extres_page) -+ kbase_mem_copy_from_extres_page(kctx, -+ extres_page, pages, -+ buf_data->nr_pages, -+ &target_page_nr, -+ offset, &to_copy); -+ -+ kunmap(pg); -+ if (target_page_nr >= buf_data->nr_pages) -+ break; -+ } -+ break; -+ } -+ break; -+#ifdef CONFIG_DMA_SHARED_BUFFER -+ case KBASE_MEM_TYPE_IMPORTED_UMM: { -+ struct dma_buf *dma_buf = gpu_alloc->imported.umm.dma_buf; -+ -+ KBASE_DEBUG_ASSERT(dma_buf != NULL); -+ KBASE_DEBUG_ASSERT(dma_buf->size == -+ buf_data->nr_extres_pages * PAGE_SIZE); -+ -+ ret = dma_buf_begin_cpu_access(dma_buf, -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) && !defined(CONFIG_CHROMEOS) -+ 0, buf_data->nr_extres_pages*PAGE_SIZE, -+#endif -+ DMA_FROM_DEVICE); -+ if (ret) -+ goto out_unlock; -+ -+ for (i = 0; i < buf_data->nr_extres_pages; i++) { -+ -+ void *extres_page = dma_buf_kmap(dma_buf, i); -+ -+ if (extres_page) -+ kbase_mem_copy_from_extres_page(kctx, -+ extres_page, pages, -+ buf_data->nr_pages, -+ &target_page_nr, -+ offset, &to_copy); -+ -+ dma_buf_kunmap(dma_buf, i, extres_page); -+ if (target_page_nr >= buf_data->nr_pages) -+ break; -+ } -+ dma_buf_end_cpu_access(dma_buf, -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) && !defined(CONFIG_CHROMEOS) -+ 0, buf_data->nr_extres_pages*PAGE_SIZE, -+#endif -+ DMA_FROM_DEVICE); -+ break; -+ } -+#endif -+ default: -+ ret = -EINVAL; -+ } -+out_unlock: -+ kbase_gpu_vm_unlock(kctx); -+ return ret; -+ -+} -+ -+static int kbase_debug_copy(struct kbase_jd_atom *katom) -+{ -+ struct kbase_debug_copy_buffer *buffers = -+ (struct kbase_debug_copy_buffer *)(uintptr_t)katom->jc; -+ unsigned int i; -+ -+ for (i = 0; i < katom->nr_extres; i++) { -+ int res = kbase_mem_copy_from_extres(katom->kctx, &buffers[i]); -+ -+ if (res) -+ return res; -+ } -+ -+ return 0; -+} -+ -+static int kbase_jit_allocate_prepare(struct kbase_jd_atom *katom) -+{ -+ __user void *data = (__user void *)(uintptr_t) katom->jc; -+ struct base_jit_alloc_info *info; -+ struct kbase_context *kctx = katom->kctx; -+ int ret; -+ -+ /* Fail the job if there is no info structure */ -+ if (!data) { -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ /* Copy the information for safe access and future storage */ -+ info = kzalloc(sizeof(*info), GFP_KERNEL); -+ if (!info) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ if (copy_from_user(info, data, sizeof(*info)) != 0) { -+ ret = -EINVAL; -+ goto free_info; -+ } -+ -+ /* If the ID is zero then fail the job */ -+ if (info->id == 0) { -+ ret = -EINVAL; -+ goto free_info; -+ } -+ -+ /* Sanity check that the PA fits within the VA */ -+ if (info->va_pages < info->commit_pages) { -+ ret = -EINVAL; -+ goto free_info; -+ } -+ -+ /* Ensure the GPU address is correctly aligned */ -+ if ((info->gpu_alloc_addr & 0x7) != 0) { -+ ret = -EINVAL; -+ goto free_info; -+ } -+ -+ /* Replace the user pointer with our kernel allocated info structure */ -+ katom->jc = (u64)(uintptr_t) info; -+ katom->jit_blocked = false; -+ -+ lockdep_assert_held(&kctx->jctx.lock); -+ list_add_tail(&katom->jit_node, &kctx->jit_atoms_head); -+ -+ /* -+ * Note: -+ * The provided info->gpu_alloc_addr isn't validated here as -+ * userland can cache allocations which means that even -+ * though the region is valid it doesn't represent the -+ * same thing it used to. -+ * -+ * Complete validation of va_pages, commit_pages and extent -+ * isn't done here as it will be done during the call to -+ * kbase_mem_alloc. -+ */ -+ return 0; -+ -+free_info: -+ kfree(info); -+fail: -+ katom->jc = 0; -+ return ret; -+} -+ -+static u8 kbase_jit_free_get_id(struct kbase_jd_atom *katom) -+{ -+ if (WARN_ON(katom->core_req != BASE_JD_REQ_SOFT_JIT_FREE)) -+ return 0; -+ -+ return (u8) katom->jc; -+} -+ -+static int kbase_jit_allocate_process(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ struct base_jit_alloc_info *info; -+ struct kbase_va_region *reg; -+ struct kbase_vmap_struct mapping; -+ u64 *ptr, new_addr; -+ -+ if (katom->jit_blocked) { -+ list_del(&katom->queue); -+ katom->jit_blocked = false; -+ } -+ -+ info = (struct base_jit_alloc_info *) (uintptr_t) katom->jc; -+ -+ /* The JIT ID is still in use so fail the allocation */ -+ if (kctx->jit_alloc[info->id]) { -+ katom->event_code = BASE_JD_EVENT_MEM_GROWTH_FAILED; -+ return 0; -+ } -+ -+ /* Create a JIT allocation */ -+ reg = kbase_jit_allocate(kctx, info); -+ if (!reg) { -+ struct kbase_jd_atom *jit_atom; -+ bool can_block = false; -+ -+ lockdep_assert_held(&kctx->jctx.lock); -+ -+ jit_atom = list_first_entry(&kctx->jit_atoms_head, -+ struct kbase_jd_atom, jit_node); -+ -+ list_for_each_entry(jit_atom, &kctx->jit_atoms_head, jit_node) { -+ if (jit_atom == katom) -+ break; -+ if (jit_atom->core_req == BASE_JD_REQ_SOFT_JIT_FREE) { -+ u8 free_id = kbase_jit_free_get_id(jit_atom); -+ -+ if (free_id && kctx->jit_alloc[free_id]) { -+ /* A JIT free which is active and -+ * submitted before this atom -+ */ -+ can_block = true; -+ break; -+ } -+ } -+ } -+ -+ if (!can_block) { -+ /* Mark the allocation so we know it's in use even if -+ * the allocation itself fails. -+ */ -+ kctx->jit_alloc[info->id] = -+ (struct kbase_va_region *) -1; -+ -+ katom->event_code = BASE_JD_EVENT_MEM_GROWTH_FAILED; -+ return 0; -+ } -+ -+ /* There are pending frees for an active allocation -+ * so we should wait to see whether they free the memory. -+ * Add to the beginning of the list to ensure that the atom is -+ * processed only once in kbase_jit_free_finish -+ */ -+ list_add(&katom->queue, &kctx->jit_pending_alloc); -+ katom->jit_blocked = true; -+ -+ return 1; -+ } -+ -+ /* -+ * Write the address of the JIT allocation to the user provided -+ * GPU allocation. -+ */ -+ ptr = kbase_vmap(kctx, info->gpu_alloc_addr, sizeof(*ptr), -+ &mapping); -+ if (!ptr) { -+ /* -+ * Leave the allocation "live" as the JIT free jit will be -+ * submitted anyway. -+ */ -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ return 0; -+ } -+ -+ new_addr = reg->start_pfn << PAGE_SHIFT; -+ *ptr = new_addr; -+ KBASE_TLSTREAM_TL_ATTRIB_ATOM_JIT( -+ katom, info->gpu_alloc_addr, new_addr); -+ kbase_vunmap(kctx, &mapping); -+ -+ katom->event_code = BASE_JD_EVENT_DONE; -+ -+ /* -+ * Bind it to the user provided ID. Do this last so we can check for -+ * the JIT free racing this JIT alloc job. -+ */ -+ kctx->jit_alloc[info->id] = reg; -+ -+ return 0; -+} -+ -+static void kbase_jit_allocate_finish(struct kbase_jd_atom *katom) -+{ -+ struct base_jit_alloc_info *info; -+ -+ lockdep_assert_held(&katom->kctx->jctx.lock); -+ -+ /* Remove atom from jit_atoms_head list */ -+ list_del(&katom->jit_node); -+ -+ if (katom->jit_blocked) { -+ list_del(&katom->queue); -+ katom->jit_blocked = false; -+ } -+ -+ info = (struct base_jit_alloc_info *) (uintptr_t) katom->jc; -+ /* Free the info structure */ -+ kfree(info); -+} -+ -+static int kbase_jit_free_prepare(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ -+ lockdep_assert_held(&kctx->jctx.lock); -+ list_add_tail(&katom->jit_node, &kctx->jit_atoms_head); -+ -+ return 0; -+} -+ -+static void kbase_jit_free_process(struct kbase_jd_atom *katom) -+{ -+ struct kbase_context *kctx = katom->kctx; -+ u8 id = kbase_jit_free_get_id(katom); -+ -+ /* -+ * If the ID is zero or it is not in use yet then fail the job. -+ */ -+ if ((id == 0) || (kctx->jit_alloc[id] == NULL)) { -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ return; -+ } -+ -+ /* -+ * If the ID is valid but the allocation request failed still succeed -+ * this soft job but don't try and free the allocation. -+ */ -+ if (kctx->jit_alloc[id] != (struct kbase_va_region *) -1) -+ kbase_jit_free(kctx, kctx->jit_alloc[id]); -+ -+ kctx->jit_alloc[id] = NULL; -+} -+ -+static void kbasep_jit_free_finish_worker(struct work_struct *work) -+{ -+ struct kbase_jd_atom *katom = container_of(work, struct kbase_jd_atom, -+ work); -+ struct kbase_context *kctx = katom->kctx; -+ int resched; -+ -+ mutex_lock(&kctx->jctx.lock); -+ kbase_finish_soft_job(katom); -+ resched = jd_done_nolock(katom, NULL); -+ mutex_unlock(&kctx->jctx.lock); -+ -+ if (resched) -+ kbase_js_sched_all(kctx->kbdev); -+} -+ -+static void kbase_jit_free_finish(struct kbase_jd_atom *katom) -+{ -+ struct list_head *i, *tmp; -+ struct kbase_context *kctx = katom->kctx; -+ -+ lockdep_assert_held(&kctx->jctx.lock); -+ /* Remove this atom from the kctx->jit_atoms_head list */ -+ list_del(&katom->jit_node); -+ -+ list_for_each_safe(i, tmp, &kctx->jit_pending_alloc) { -+ struct kbase_jd_atom *pending_atom = list_entry(i, -+ struct kbase_jd_atom, queue); -+ if (kbase_jit_allocate_process(pending_atom) == 0) { -+ /* Atom has completed */ -+ INIT_WORK(&pending_atom->work, -+ kbasep_jit_free_finish_worker); -+ queue_work(kctx->jctx.job_done_wq, &pending_atom->work); -+ } -+ } -+} -+ -+static int kbase_ext_res_prepare(struct kbase_jd_atom *katom) -+{ -+ __user struct base_external_resource_list *user_ext_res; -+ struct base_external_resource_list *ext_res; -+ u64 count = 0; -+ size_t copy_size; -+ int ret; -+ -+ user_ext_res = (__user struct base_external_resource_list *) -+ (uintptr_t) katom->jc; -+ -+ /* Fail the job if there is no info structure */ -+ if (!user_ext_res) { -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ if (copy_from_user(&count, &user_ext_res->count, sizeof(u64)) != 0) { -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ /* Is the number of external resources in range? */ -+ if (!count || count > BASE_EXT_RES_COUNT_MAX) { -+ ret = -EINVAL; -+ goto fail; -+ } -+ -+ /* Copy the information for safe access and future storage */ -+ copy_size = sizeof(*ext_res); -+ copy_size += sizeof(struct base_external_resource) * (count - 1); -+ ext_res = kzalloc(copy_size, GFP_KERNEL); -+ if (!ext_res) { -+ ret = -ENOMEM; -+ goto fail; -+ } -+ -+ if (copy_from_user(ext_res, user_ext_res, copy_size) != 0) { -+ ret = -EINVAL; -+ goto free_info; -+ } -+ -+ /* -+ * Overwrite the count with the first value incase it was changed -+ * after the fact. -+ */ -+ ext_res->count = count; -+ -+ /* -+ * Replace the user pointer with our kernel allocated -+ * ext_res structure. -+ */ -+ katom->jc = (u64)(uintptr_t) ext_res; -+ -+ return 0; -+ -+free_info: -+ kfree(ext_res); -+fail: -+ return ret; -+} -+ -+static void kbase_ext_res_process(struct kbase_jd_atom *katom, bool map) -+{ -+ struct base_external_resource_list *ext_res; -+ int i; -+ bool failed = false; -+ -+ ext_res = (struct base_external_resource_list *) (uintptr_t) katom->jc; -+ if (!ext_res) -+ goto failed_jc; -+ -+ kbase_gpu_vm_lock(katom->kctx); -+ -+ for (i = 0; i < ext_res->count; i++) { -+ u64 gpu_addr; -+ -+ gpu_addr = ext_res->ext_res[i].ext_resource & -+ ~BASE_EXT_RES_ACCESS_EXCLUSIVE; -+ if (map) { -+ if (!kbase_sticky_resource_acquire(katom->kctx, -+ gpu_addr)) -+ goto failed_loop; -+ } else -+ if (!kbase_sticky_resource_release(katom->kctx, NULL, -+ gpu_addr)) -+ failed = true; -+ } -+ -+ /* -+ * In the case of unmap we continue unmapping other resources in the -+ * case of failure but will always report failure if _any_ unmap -+ * request fails. -+ */ -+ if (failed) -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ else -+ katom->event_code = BASE_JD_EVENT_DONE; -+ -+ kbase_gpu_vm_unlock(katom->kctx); -+ -+ return; -+ -+failed_loop: -+ while (--i > 0) { -+ u64 gpu_addr; -+ -+ gpu_addr = ext_res->ext_res[i].ext_resource & -+ ~BASE_EXT_RES_ACCESS_EXCLUSIVE; -+ -+ kbase_sticky_resource_release(katom->kctx, NULL, gpu_addr); -+ } -+ -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ kbase_gpu_vm_unlock(katom->kctx); -+ -+failed_jc: -+ return; -+} -+ -+static void kbase_ext_res_finish(struct kbase_jd_atom *katom) -+{ -+ struct base_external_resource_list *ext_res; -+ -+ ext_res = (struct base_external_resource_list *) (uintptr_t) katom->jc; -+ /* Free the info structure */ -+ kfree(ext_res); -+} -+ -+int kbase_process_soft_job(struct kbase_jd_atom *katom) -+{ -+ switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) { -+ case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME: -+ return kbase_dump_cpu_gpu_time(katom); -+ -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ case BASE_JD_REQ_SOFT_FENCE_TRIGGER: -+ katom->event_code = kbase_sync_fence_out_trigger(katom, -+ katom->event_code == BASE_JD_EVENT_DONE ? -+ 0 : -EFAULT); -+ break; -+ case BASE_JD_REQ_SOFT_FENCE_WAIT: -+ { -+ int ret = kbase_sync_fence_in_wait(katom); -+ -+ if (ret == 1) { -+#ifdef CONFIG_MALI_FENCE_DEBUG -+ kbasep_add_waiting_with_timeout(katom); -+#else -+ kbasep_add_waiting_soft_job(katom); -+#endif -+ } -+ return ret; -+ } -+#endif -+ -+ case BASE_JD_REQ_SOFT_REPLAY: -+ return kbase_replay_process(katom); -+ case BASE_JD_REQ_SOFT_EVENT_WAIT: -+ return kbasep_soft_event_wait(katom); -+ case BASE_JD_REQ_SOFT_EVENT_SET: -+ kbasep_soft_event_update_locked(katom, BASE_JD_SOFT_EVENT_SET); -+ break; -+ case BASE_JD_REQ_SOFT_EVENT_RESET: -+ kbasep_soft_event_update_locked(katom, BASE_JD_SOFT_EVENT_RESET); -+ break; -+ case BASE_JD_REQ_SOFT_DEBUG_COPY: -+ { -+ int res = kbase_debug_copy(katom); -+ -+ if (res) -+ katom->event_code = BASE_JD_EVENT_JOB_INVALID; -+ break; -+ } -+ case BASE_JD_REQ_SOFT_JIT_ALLOC: -+ return kbase_jit_allocate_process(katom); -+ case BASE_JD_REQ_SOFT_JIT_FREE: -+ kbase_jit_free_process(katom); -+ break; -+ case BASE_JD_REQ_SOFT_EXT_RES_MAP: -+ kbase_ext_res_process(katom, true); -+ break; -+ case BASE_JD_REQ_SOFT_EXT_RES_UNMAP: -+ kbase_ext_res_process(katom, false); -+ break; -+ } -+ -+ /* Atom is complete */ -+ return 0; -+} -+ -+void kbase_cancel_soft_job(struct kbase_jd_atom *katom) -+{ -+ switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) { -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ case BASE_JD_REQ_SOFT_FENCE_WAIT: -+ kbase_sync_fence_in_cancel_wait(katom); -+ break; -+#endif -+ case BASE_JD_REQ_SOFT_EVENT_WAIT: -+ kbasep_soft_event_cancel_job(katom); -+ break; -+ default: -+ /* This soft-job doesn't support cancellation! */ -+ KBASE_DEBUG_ASSERT(0); -+ } -+} -+ -+int kbase_prepare_soft_job(struct kbase_jd_atom *katom) -+{ -+ switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) { -+ case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME: -+ { -+ if (0 != (katom->jc & KBASE_CACHE_ALIGNMENT_MASK)) -+ return -EINVAL; -+ } -+ break; -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ case BASE_JD_REQ_SOFT_FENCE_TRIGGER: -+ { -+ struct base_fence fence; -+ int fd; -+ -+ if (0 != copy_from_user(&fence, (__user void *)(uintptr_t) katom->jc, sizeof(fence))) -+ return -EINVAL; -+ -+ fd = kbase_sync_fence_out_create(katom, -+ fence.basep.stream_fd); -+ if (fd < 0) -+ return -EINVAL; -+ -+ fence.basep.fd = fd; -+ if (0 != copy_to_user((__user void *)(uintptr_t) katom->jc, &fence, sizeof(fence))) { -+ kbase_sync_fence_out_remove(katom); -+ kbase_sync_fence_close_fd(fd); -+ fence.basep.fd = -EINVAL; -+ return -EINVAL; -+ } -+ } -+ break; -+ case BASE_JD_REQ_SOFT_FENCE_WAIT: -+ { -+ struct base_fence fence; -+ int ret; -+ -+ if (0 != copy_from_user(&fence, (__user void *)(uintptr_t) katom->jc, sizeof(fence))) -+ return -EINVAL; -+ -+ /* Get a reference to the fence object */ -+ ret = kbase_sync_fence_in_from_fd(katom, -+ fence.basep.fd); -+ if (ret < 0) -+ return ret; -+ -+#ifdef CONFIG_MALI_DMA_FENCE -+ /* -+ * Set KCTX_NO_IMPLICIT_FENCE in the context the first -+ * time a soft fence wait job is observed. This will -+ * prevent the implicit dma-buf fence to conflict with -+ * the Android native sync fences. -+ */ -+ if (!kbase_ctx_flag(katom->kctx, KCTX_NO_IMPLICIT_SYNC)) -+ kbase_ctx_flag_set(katom->kctx, KCTX_NO_IMPLICIT_SYNC); -+#endif /* CONFIG_MALI_DMA_FENCE */ -+ } -+ break; -+#endif /* CONFIG_SYNC || CONFIG_SYNC_FILE */ -+ case BASE_JD_REQ_SOFT_JIT_ALLOC: -+ return kbase_jit_allocate_prepare(katom); -+ case BASE_JD_REQ_SOFT_REPLAY: -+ break; -+ case BASE_JD_REQ_SOFT_JIT_FREE: -+ return kbase_jit_free_prepare(katom); -+ case BASE_JD_REQ_SOFT_EVENT_WAIT: -+ case BASE_JD_REQ_SOFT_EVENT_SET: -+ case BASE_JD_REQ_SOFT_EVENT_RESET: -+ if (katom->jc == 0) -+ return -EINVAL; -+ break; -+ case BASE_JD_REQ_SOFT_DEBUG_COPY: -+ return kbase_debug_copy_prepare(katom); -+ case BASE_JD_REQ_SOFT_EXT_RES_MAP: -+ return kbase_ext_res_prepare(katom); -+ case BASE_JD_REQ_SOFT_EXT_RES_UNMAP: -+ return kbase_ext_res_prepare(katom); -+ default: -+ /* Unsupported soft-job */ -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+void kbase_finish_soft_job(struct kbase_jd_atom *katom) -+{ -+ switch (katom->core_req & BASE_JD_REQ_SOFT_JOB_TYPE) { -+ case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME: -+ /* Nothing to do */ -+ break; -+#if defined(CONFIG_SYNC) || defined(CONFIG_SYNC_FILE) -+ case BASE_JD_REQ_SOFT_FENCE_TRIGGER: -+ /* If fence has not yet been signaled, do it now */ -+ kbase_sync_fence_out_trigger(katom, katom->event_code == -+ BASE_JD_EVENT_DONE ? 0 : -EFAULT); -+ break; -+ case BASE_JD_REQ_SOFT_FENCE_WAIT: -+ /* Release katom's reference to fence object */ -+ kbase_sync_fence_in_remove(katom); -+ break; -+#endif /* CONFIG_SYNC || CONFIG_SYNC_FILE */ -+ case BASE_JD_REQ_SOFT_DEBUG_COPY: -+ kbase_debug_copy_finish(katom); -+ break; -+ case BASE_JD_REQ_SOFT_JIT_ALLOC: -+ kbase_jit_allocate_finish(katom); -+ break; -+ case BASE_JD_REQ_SOFT_EXT_RES_MAP: -+ kbase_ext_res_finish(katom); -+ break; -+ case BASE_JD_REQ_SOFT_EXT_RES_UNMAP: -+ kbase_ext_res_finish(katom); -+ break; -+ case BASE_JD_REQ_SOFT_JIT_FREE: -+ kbase_jit_free_finish(katom); -+ break; -+ } -+} -+ -+void kbase_resume_suspended_soft_jobs(struct kbase_device *kbdev) -+{ -+ LIST_HEAD(local_suspended_soft_jobs); -+ struct kbase_jd_atom *tmp_iter; -+ struct kbase_jd_atom *katom_iter; -+ struct kbasep_js_device_data *js_devdata; -+ bool resched = false; -+ -+ KBASE_DEBUG_ASSERT(kbdev); -+ -+ js_devdata = &kbdev->js_data; -+ -+ /* Move out the entire list */ -+ mutex_lock(&js_devdata->runpool_mutex); -+ list_splice_init(&js_devdata->suspended_soft_jobs_list, -+ &local_suspended_soft_jobs); -+ mutex_unlock(&js_devdata->runpool_mutex); -+ -+ /* -+ * Each atom must be detached from the list and ran separately - -+ * it could be re-added to the old list, but this is unlikely -+ */ -+ list_for_each_entry_safe(katom_iter, tmp_iter, -+ &local_suspended_soft_jobs, dep_item[1]) { -+ struct kbase_context *kctx = katom_iter->kctx; -+ -+ mutex_lock(&kctx->jctx.lock); -+ -+ /* Remove from the global list */ -+ list_del(&katom_iter->dep_item[1]); -+ /* Remove from the context's list of waiting soft jobs */ -+ kbasep_remove_waiting_soft_job(katom_iter); -+ -+ if (kbase_process_soft_job(katom_iter) == 0) { -+ kbase_finish_soft_job(katom_iter); -+ resched |= jd_done_nolock(katom_iter, NULL); -+ } else { -+ KBASE_DEBUG_ASSERT((katom_iter->core_req & -+ BASE_JD_REQ_SOFT_JOB_TYPE) -+ != BASE_JD_REQ_SOFT_REPLAY); -+ } -+ -+ mutex_unlock(&kctx->jctx.lock); -+ } -+ -+ if (resched) -+ kbase_js_sched_all(kbdev); -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_strings.c b/drivers/gpu/arm/midgard/mali_kbase_strings.c -new file mode 100644 -index 0000000..c98762c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_strings.c -@@ -0,0 +1,23 @@ -+ /* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+#include "mali_kbase_strings.h" -+ -+#define KBASE_DRV_NAME "mali" -+#define KBASE_TIMELINE_NAME KBASE_DRV_NAME ".timeline" -+ -+const char kbase_drv_name[] = KBASE_DRV_NAME; -+const char kbase_timeline_name[] = KBASE_TIMELINE_NAME; -diff --git a/drivers/gpu/arm/midgard/mali_kbase_strings.h b/drivers/gpu/arm/midgard/mali_kbase_strings.h -new file mode 100644 -index 0000000..41b8fdb ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_strings.h -@@ -0,0 +1,19 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+extern const char kbase_drv_name[]; -+extern const char kbase_timeline_name[]; -diff --git a/drivers/gpu/arm/midgard/mali_kbase_sync.h b/drivers/gpu/arm/midgard/mali_kbase_sync.h -new file mode 100644 -index 0000000..de72147 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_sync.h -@@ -0,0 +1,203 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @file mali_kbase_sync.h -+ * -+ * This file contains our internal "API" for explicit fences. -+ * It hides the implementation details of the actual explicit fence mechanism -+ * used (Android fences or sync file with DMA fences). -+ */ -+ -+#ifndef MALI_KBASE_SYNC_H -+#define MALI_KBASE_SYNC_H -+ -+#include -+#ifdef CONFIG_SYNC -+#include -+#endif -+#ifdef CONFIG_SYNC_FILE -+#include "mali_kbase_fence_defs.h" -+#include -+#endif -+ -+#include "mali_kbase.h" -+ -+/** -+ * struct kbase_sync_fence_info - Information about a fence -+ * @fence: Pointer to fence (type is void*, as underlaying struct can differ) -+ * @name: The name given to this fence when it was created -+ * @status: < 0 means error, 0 means active, 1 means signaled -+ * -+ * Use kbase_sync_fence_in_info_get() or kbase_sync_fence_out_info_get() -+ * to get the information. -+ */ -+struct kbase_sync_fence_info { -+ void *fence; -+ char name[32]; -+ int status; -+}; -+ -+/** -+ * kbase_sync_fence_stream_create() - Create a stream object -+ * @name: Name of stream (only used to ease debugging/visualization) -+ * @out_fd: A file descriptor representing the created stream object -+ * -+ * Can map down to a timeline implementation in some implementations. -+ * Exposed as a file descriptor. -+ * Life-time controlled via the file descriptor: -+ * - dup to add a ref -+ * - close to remove a ref -+ * -+ * return: 0 on success, < 0 on error -+ */ -+int kbase_sync_fence_stream_create(const char *name, int *const out_fd); -+ -+/** -+ * kbase_sync_fence_out_create Create an explicit output fence to specified atom -+ * @katom: Atom to assign the new explicit fence to -+ * @stream_fd: File descriptor for stream object to create fence on -+ * -+ * return: Valid file descriptor to fence or < 0 on error -+ */ -+int kbase_sync_fence_out_create(struct kbase_jd_atom *katom, int stream_fd); -+ -+/** -+ * kbase_sync_fence_in_from_fd() Assigns an existing fence to specified atom -+ * @katom: Atom to assign the existing explicit fence to -+ * @fd: File descriptor to an existing fence -+ * -+ * Assigns an explicit input fence to atom. -+ * This can later be waited for by calling @kbase_sync_fence_in_wait -+ * -+ * return: 0 on success, < 0 on error -+ */ -+int kbase_sync_fence_in_from_fd(struct kbase_jd_atom *katom, int fd); -+ -+/** -+ * kbase_sync_fence_validate() - Validate a fd to be a valid fence -+ * @fd: File descriptor to check -+ * -+ * This function is only usable to catch unintentional user errors early, -+ * it does not stop malicious code changing the fd after this function returns. -+ * -+ * return 0: if fd is for a valid fence, < 0 if invalid -+ */ -+int kbase_sync_fence_validate(int fd); -+ -+/** -+ * kbase_sync_fence_out_trigger - Signal explicit output fence attached on katom -+ * @katom: Atom with an explicit fence to signal -+ * @result: < 0 means signal with error, 0 >= indicates success -+ * -+ * Signal output fence attached on katom and remove the fence from the atom. -+ * -+ * return: The "next" event code for atom, typically JOB_CANCELLED or EVENT_DONE -+ */ -+enum base_jd_event_code -+kbase_sync_fence_out_trigger(struct kbase_jd_atom *katom, int result); -+ -+/** -+ * kbase_sync_fence_in_wait() - Wait for explicit input fence to be signaled -+ * @katom: Atom with explicit fence to wait for -+ * -+ * If the fence is already signaled, then 0 is returned, and the caller must -+ * continue processing of the katom. -+ * -+ * If the fence isn't already signaled, then this kbase_sync framework will -+ * take responsibility to continue the processing once the fence is signaled. -+ * -+ * return: 0 if already signaled, otherwise 1 -+ */ -+int kbase_sync_fence_in_wait(struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_sync_fence_in_cancel_wait() - Cancel explicit input fence waits -+ * @katom: Atom to cancel wait for -+ * -+ * This function is fully responsible for continuing processing of this atom -+ * (remove_waiting_soft_job + finish_soft_job + jd_done + js_sched_all) -+ */ -+void kbase_sync_fence_in_cancel_wait(struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_sync_fence_in_remove() - Remove the input fence from the katom -+ * @katom: Atom to remove explicit input fence for -+ * -+ * This will also release the corresponding reference. -+ */ -+void kbase_sync_fence_in_remove(struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_sync_fence_out_remove() - Remove the output fence from the katom -+ * @katom: Atom to remove explicit output fence for -+ * -+ * This will also release the corresponding reference. -+ */ -+void kbase_sync_fence_out_remove(struct kbase_jd_atom *katom); -+ -+/** -+ * kbase_sync_fence_close_fd() - Close a file descriptor representing a fence -+ * @fd: File descriptor to close -+ */ -+static inline void kbase_sync_fence_close_fd(int fd) -+{ -+ sys_close(fd); -+} -+ -+/** -+ * kbase_sync_fence_in_info_get() - Retrieves information about input fence -+ * @katom: Atom to get fence information from -+ * @info: Struct to be filled with fence information -+ * -+ * return: 0 on success, < 0 on error -+ */ -+int kbase_sync_fence_in_info_get(struct kbase_jd_atom *katom, -+ struct kbase_sync_fence_info *info); -+ -+/** -+ * kbase_sync_fence_out_info_get() - Retrieves information about output fence -+ * @katom: Atom to get fence information from -+ * @info: Struct to be filled with fence information -+ * -+ * return: 0 on success, < 0 on error -+ */ -+int kbase_sync_fence_out_info_get(struct kbase_jd_atom *katom, -+ struct kbase_sync_fence_info *info); -+ -+/** -+ * kbase_sync_status_string() - Get string matching @status -+ * @status: Value of fence status. -+ * -+ * return: Pointer to string describing @status. -+ */ -+const char *kbase_sync_status_string(int status); -+ -+/* -+ * Internal worker used to continue processing of atom. -+ */ -+void kbase_sync_fence_wait_worker(struct work_struct *data); -+ -+#ifdef CONFIG_MALI_FENCE_DEBUG -+/** -+ * kbase_sync_fence_in_dump() Trigger a debug dump of atoms input fence state -+ * @katom: Atom to trigger fence debug dump for -+ */ -+void kbase_sync_fence_in_dump(struct kbase_jd_atom *katom); -+#endif -+ -+#endif /* MALI_KBASE_SYNC_H */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_sync_android.c b/drivers/gpu/arm/midgard/mali_kbase_sync_android.c -new file mode 100644 -index 0000000..d7349dc ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_sync_android.c -@@ -0,0 +1,537 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Code for supporting explicit Android fences (CONFIG_SYNC) -+ * Known to be good for kernels 4.5 and earlier. -+ * Replaced with CONFIG_SYNC_FILE for 4.9 and later kernels -+ * (see mali_kbase_sync_file.c) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sync.h" -+#include -+#include -+ -+struct mali_sync_timeline { -+ struct sync_timeline timeline; -+ atomic_t counter; -+ atomic_t signaled; -+}; -+ -+struct mali_sync_pt { -+ struct sync_pt pt; -+ int order; -+ int result; -+}; -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) -+/* For backwards compatibility with kernels before 3.17. After 3.17 -+ * sync_pt_parent is included in the kernel. */ -+static inline struct sync_timeline *sync_pt_parent(struct sync_pt *pt) -+{ -+ return pt->parent; -+} -+#endif -+ -+static struct mali_sync_timeline *to_mali_sync_timeline( -+ struct sync_timeline *timeline) -+{ -+ return container_of(timeline, struct mali_sync_timeline, timeline); -+} -+ -+static struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt) -+{ -+ return container_of(pt, struct mali_sync_pt, pt); -+} -+ -+static struct sync_pt *timeline_dup(struct sync_pt *pt) -+{ -+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt); -+ struct mali_sync_pt *new_mpt; -+ struct sync_pt *new_pt = sync_pt_create(sync_pt_parent(pt), -+ sizeof(struct mali_sync_pt)); -+ -+ if (!new_pt) -+ return NULL; -+ -+ new_mpt = to_mali_sync_pt(new_pt); -+ new_mpt->order = mpt->order; -+ new_mpt->result = mpt->result; -+ -+ return new_pt; -+} -+ -+static int timeline_has_signaled(struct sync_pt *pt) -+{ -+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt); -+ struct mali_sync_timeline *mtl = to_mali_sync_timeline( -+ sync_pt_parent(pt)); -+ int result = mpt->result; -+ -+ int diff = atomic_read(&mtl->signaled) - mpt->order; -+ -+ if (diff >= 0) -+ return (result < 0) ? result : 1; -+ -+ return 0; -+} -+ -+static int timeline_compare(struct sync_pt *a, struct sync_pt *b) -+{ -+ struct mali_sync_pt *ma = container_of(a, struct mali_sync_pt, pt); -+ struct mali_sync_pt *mb = container_of(b, struct mali_sync_pt, pt); -+ -+ int diff = ma->order - mb->order; -+ -+ if (diff == 0) -+ return 0; -+ -+ return (diff < 0) ? -1 : 1; -+} -+ -+static void timeline_value_str(struct sync_timeline *timeline, char *str, -+ int size) -+{ -+ struct mali_sync_timeline *mtl = to_mali_sync_timeline(timeline); -+ -+ snprintf(str, size, "%d", atomic_read(&mtl->signaled)); -+} -+ -+static void pt_value_str(struct sync_pt *pt, char *str, int size) -+{ -+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt); -+ -+ snprintf(str, size, "%d(%d)", mpt->order, mpt->result); -+} -+ -+static struct sync_timeline_ops mali_timeline_ops = { -+ .driver_name = "Mali", -+ .dup = timeline_dup, -+ .has_signaled = timeline_has_signaled, -+ .compare = timeline_compare, -+ .timeline_value_str = timeline_value_str, -+ .pt_value_str = pt_value_str, -+}; -+ -+/* Allocates a timeline for Mali -+ * -+ * One timeline should be allocated per API context. -+ */ -+static struct sync_timeline *mali_sync_timeline_alloc(const char *name) -+{ -+ struct sync_timeline *tl; -+ struct mali_sync_timeline *mtl; -+ -+ tl = sync_timeline_create(&mali_timeline_ops, -+ sizeof(struct mali_sync_timeline), name); -+ if (!tl) -+ return NULL; -+ -+ /* Set the counter in our private struct */ -+ mtl = to_mali_sync_timeline(tl); -+ atomic_set(&mtl->counter, 0); -+ atomic_set(&mtl->signaled, 0); -+ -+ return tl; -+} -+ -+static int kbase_stream_close(struct inode *inode, struct file *file) -+{ -+ struct sync_timeline *tl; -+ -+ tl = (struct sync_timeline *)file->private_data; -+ sync_timeline_destroy(tl); -+ return 0; -+} -+ -+static const struct file_operations stream_fops = { -+ .owner = THIS_MODULE, -+ .release = kbase_stream_close, -+}; -+ -+int kbase_sync_fence_stream_create(const char *name, int *const out_fd) -+{ -+ struct sync_timeline *tl; -+ -+ if (!out_fd) -+ return -EINVAL; -+ -+ tl = mali_sync_timeline_alloc(name); -+ if (!tl) -+ return -EINVAL; -+ -+ *out_fd = anon_inode_getfd(name, &stream_fops, tl, O_RDONLY|O_CLOEXEC); -+ -+ if (*out_fd < 0) { -+ sync_timeline_destroy(tl); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* Allocates a sync point within the timeline. -+ * -+ * The timeline must be the one allocated by kbase_sync_timeline_alloc -+ * -+ * Sync points must be triggered in *exactly* the same order as they are -+ * allocated. -+ */ -+static struct sync_pt *kbase_sync_pt_alloc(struct sync_timeline *parent) -+{ -+ struct sync_pt *pt = sync_pt_create(parent, -+ sizeof(struct mali_sync_pt)); -+ struct mali_sync_timeline *mtl = to_mali_sync_timeline(parent); -+ struct mali_sync_pt *mpt; -+ -+ if (!pt) -+ return NULL; -+ -+ mpt = to_mali_sync_pt(pt); -+ mpt->order = atomic_inc_return(&mtl->counter); -+ mpt->result = 0; -+ -+ return pt; -+} -+ -+int kbase_sync_fence_out_create(struct kbase_jd_atom *katom, int tl_fd) -+{ -+ struct sync_timeline *tl; -+ struct sync_pt *pt; -+ struct sync_fence *fence; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) -+ struct files_struct *files; -+ struct fdtable *fdt; -+#endif -+ int fd; -+ struct file *tl_file; -+ -+ tl_file = fget(tl_fd); -+ if (tl_file == NULL) -+ return -EBADF; -+ -+ if (tl_file->f_op != &stream_fops) { -+ fd = -EBADF; -+ goto out; -+ } -+ -+ tl = tl_file->private_data; -+ -+ pt = kbase_sync_pt_alloc(tl); -+ if (!pt) { -+ fd = -EFAULT; -+ goto out; -+ } -+ -+ fence = sync_fence_create("mali_fence", pt); -+ if (!fence) { -+ sync_pt_free(pt); -+ fd = -EFAULT; -+ goto out; -+ } -+ -+ /* from here the fence owns the sync_pt */ -+ -+ /* create a fd representing the fence */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) -+ fd = get_unused_fd_flags(O_RDWR | O_CLOEXEC); -+ if (fd < 0) { -+ sync_fence_put(fence); -+ goto out; -+ } -+#else -+ fd = get_unused_fd(); -+ if (fd < 0) { -+ sync_fence_put(fence); -+ goto out; -+ } -+ -+ files = current->files; -+ spin_lock(&files->file_lock); -+ fdt = files_fdtable(files); -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) -+ __set_close_on_exec(fd, fdt); -+#else -+ FD_SET(fd, fdt->close_on_exec); -+#endif -+ spin_unlock(&files->file_lock); -+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) */ -+ -+ /* bind fence to the new fd */ -+ sync_fence_install(fence, fd); -+ -+ katom->fence = sync_fence_fdget(fd); -+ if (katom->fence == NULL) { -+ /* The only way the fence can be NULL is if userspace closed it -+ * for us, so we don't need to clear it up */ -+ fd = -EINVAL; -+ goto out; -+ } -+ -+out: -+ fput(tl_file); -+ -+ return fd; -+} -+ -+int kbase_sync_fence_in_from_fd(struct kbase_jd_atom *katom, int fd) -+{ -+ katom->fence = sync_fence_fdget(fd); -+ return katom->fence ? 0 : -ENOENT; -+} -+ -+int kbase_sync_fence_validate(int fd) -+{ -+ struct sync_fence *fence; -+ -+ fence = sync_fence_fdget(fd); -+ if (!fence) -+ return -EINVAL; -+ -+ sync_fence_put(fence); -+ return 0; -+} -+ -+/* Returns true if the specified timeline is allocated by Mali */ -+static int kbase_sync_timeline_is_ours(struct sync_timeline *timeline) -+{ -+ return timeline->ops == &mali_timeline_ops; -+} -+ -+/* Signals a particular sync point -+ * -+ * Sync points must be triggered in *exactly* the same order as they are -+ * allocated. -+ * -+ * If they are signaled in the wrong order then a message will be printed in -+ * debug builds and otherwise attempts to signal order sync_pts will be ignored. -+ * -+ * result can be negative to indicate error, any other value is interpreted as -+ * success. -+ */ -+static void kbase_sync_signal_pt(struct sync_pt *pt, int result) -+{ -+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt); -+ struct mali_sync_timeline *mtl = to_mali_sync_timeline( -+ sync_pt_parent(pt)); -+ int signaled; -+ int diff; -+ -+ mpt->result = result; -+ -+ do { -+ signaled = atomic_read(&mtl->signaled); -+ -+ diff = signaled - mpt->order; -+ -+ if (diff > 0) { -+ /* The timeline is already at or ahead of this point. -+ * This should not happen unless userspace has been -+ * signaling fences out of order, so warn but don't -+ * violate the sync_pt API. -+ * The warning is only in debug builds to prevent -+ * a malicious user being able to spam dmesg. -+ */ -+#ifdef CONFIG_MALI_DEBUG -+ pr_err("Fences were triggered in a different order to allocation!"); -+#endif /* CONFIG_MALI_DEBUG */ -+ return; -+ } -+ } while (atomic_cmpxchg(&mtl->signaled, -+ signaled, mpt->order) != signaled); -+} -+ -+enum base_jd_event_code -+kbase_sync_fence_out_trigger(struct kbase_jd_atom *katom, int result) -+{ -+ struct sync_pt *pt; -+ struct sync_timeline *timeline; -+ -+ if (!katom->fence) -+ return BASE_JD_EVENT_JOB_CANCELLED; -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) -+ if (!list_is_singular(&katom->fence->pt_list_head)) { -+#else -+ if (katom->fence->num_fences != 1) { -+#endif -+ /* Not exactly one item in the list - so it didn't (directly) -+ * come from us */ -+ return BASE_JD_EVENT_JOB_CANCELLED; -+ } -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) -+ pt = list_first_entry(&katom->fence->pt_list_head, -+ struct sync_pt, pt_list); -+#else -+ pt = container_of(katom->fence->cbs[0].sync_pt, struct sync_pt, base); -+#endif -+ timeline = sync_pt_parent(pt); -+ -+ if (!kbase_sync_timeline_is_ours(timeline)) { -+ /* Fence has a sync_pt which isn't ours! */ -+ return BASE_JD_EVENT_JOB_CANCELLED; -+ } -+ -+ kbase_sync_signal_pt(pt, result); -+ -+ sync_timeline_signal(timeline); -+ -+ kbase_sync_fence_out_remove(katom); -+ -+ return (result < 0) ? BASE_JD_EVENT_JOB_CANCELLED : BASE_JD_EVENT_DONE; -+} -+ -+static inline int kbase_fence_get_status(struct sync_fence *fence) -+{ -+ if (!fence) -+ return -ENOENT; -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) -+ return fence->status; -+#else -+ return atomic_read(&fence->status); -+#endif -+} -+ -+static void kbase_fence_wait_callback(struct sync_fence *fence, -+ struct sync_fence_waiter *waiter) -+{ -+ struct kbase_jd_atom *katom = container_of(waiter, -+ struct kbase_jd_atom, sync_waiter); -+ struct kbase_context *kctx = katom->kctx; -+ -+ /* Propagate the fence status to the atom. -+ * If negative then cancel this atom and its dependencies. -+ */ -+ if (kbase_fence_get_status(fence) < 0) -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ -+ /* To prevent a potential deadlock we schedule the work onto the -+ * job_done_wq workqueue -+ * -+ * The issue is that we may signal the timeline while holding -+ * kctx->jctx.lock and the callbacks are run synchronously from -+ * sync_timeline_signal. So we simply defer the work. -+ */ -+ -+ INIT_WORK(&katom->work, kbase_sync_fence_wait_worker); -+ queue_work(kctx->jctx.job_done_wq, &katom->work); -+} -+ -+int kbase_sync_fence_in_wait(struct kbase_jd_atom *katom) -+{ -+ int ret; -+ -+ sync_fence_waiter_init(&katom->sync_waiter, kbase_fence_wait_callback); -+ -+ ret = sync_fence_wait_async(katom->fence, &katom->sync_waiter); -+ -+ if (ret == 1) { -+ /* Already signaled */ -+ return 0; -+ } -+ -+ if (ret < 0) { -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ /* We should cause the dependent jobs in the bag to be failed, -+ * to do this we schedule the work queue to complete this job */ -+ INIT_WORK(&katom->work, kbase_sync_fence_wait_worker); -+ queue_work(katom->kctx->jctx.job_done_wq, &katom->work); -+ } -+ -+ return 1; -+} -+ -+void kbase_sync_fence_in_cancel_wait(struct kbase_jd_atom *katom) -+{ -+ if (sync_fence_cancel_async(katom->fence, &katom->sync_waiter) != 0) { -+ /* The wait wasn't cancelled - leave the cleanup for -+ * kbase_fence_wait_callback */ -+ return; -+ } -+ -+ /* Wait was cancelled - zap the atoms */ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ -+ kbasep_remove_waiting_soft_job(katom); -+ kbase_finish_soft_job(katom); -+ -+ if (jd_done_nolock(katom, NULL)) -+ kbase_js_sched_all(katom->kctx->kbdev); -+} -+ -+void kbase_sync_fence_out_remove(struct kbase_jd_atom *katom) -+{ -+ if (katom->fence) { -+ sync_fence_put(katom->fence); -+ katom->fence = NULL; -+ } -+} -+ -+void kbase_sync_fence_in_remove(struct kbase_jd_atom *katom) -+{ -+ if (katom->fence) { -+ sync_fence_put(katom->fence); -+ katom->fence = NULL; -+ } -+} -+ -+int kbase_sync_fence_in_info_get(struct kbase_jd_atom *katom, -+ struct kbase_sync_fence_info *info) -+{ -+ if (!katom->fence) -+ return -ENOENT; -+ -+ info->fence = katom->fence; -+ info->status = kbase_fence_get_status(katom->fence); -+ strlcpy(info->name, katom->fence->name, sizeof(info->name)); -+ -+ return 0; -+} -+ -+int kbase_sync_fence_out_info_get(struct kbase_jd_atom *katom, -+ struct kbase_sync_fence_info *info) -+{ -+ if (!katom->fence) -+ return -ENOENT; -+ -+ info->fence = katom->fence; -+ info->status = kbase_fence_get_status(katom->fence); -+ strlcpy(info->name, katom->fence->name, sizeof(info->name)); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_MALI_FENCE_DEBUG -+void kbase_sync_fence_in_dump(struct kbase_jd_atom *katom) -+{ -+ /* Dump out the full state of all the Android sync fences. -+ * The function sync_dump() isn't exported to modules, so force -+ * sync_fence_wait() to time out to trigger sync_dump(). -+ */ -+ if (katom->fence) -+ sync_fence_wait(katom->fence, 1); -+} -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_sync_common.c b/drivers/gpu/arm/midgard/mali_kbase_sync_common.c -new file mode 100644 -index 0000000..457def2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_sync_common.c -@@ -0,0 +1,43 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * @file mali_kbase_sync_common.c -+ * -+ * Common code for our explicit fence functionality -+ */ -+ -+#include -+#include "mali_kbase.h" -+ -+void kbase_sync_fence_wait_worker(struct work_struct *data) -+{ -+ struct kbase_jd_atom *katom; -+ -+ katom = container_of(data, struct kbase_jd_atom, work); -+ kbase_soft_event_wait_callback(katom); -+} -+ -+const char *kbase_sync_status_string(int status) -+{ -+ if (status == 0) -+ return "signaled"; -+ else if (status > 0) -+ return "active"; -+ else -+ return "error"; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_sync_file.c b/drivers/gpu/arm/midgard/mali_kbase_sync_file.c -new file mode 100644 -index 0000000..4e1621c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_sync_file.c -@@ -0,0 +1,339 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* -+ * Code for supporting explicit Linux fences (CONFIG_SYNC_FILE) -+ * Introduced in kernel 4.9. -+ * Android explicit fences (CONFIG_SYNC) can be used for older kernels -+ * (see mali_kbase_sync_android.c) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "mali_kbase_fence_defs.h" -+#include "mali_kbase_sync.h" -+#include "mali_kbase_fence.h" -+#include "mali_kbase.h" -+ -+static const struct file_operations stream_fops = { -+ .owner = THIS_MODULE -+}; -+ -+int kbase_sync_fence_stream_create(const char *name, int *const out_fd) -+{ -+ if (!out_fd) -+ return -EINVAL; -+ -+ *out_fd = anon_inode_getfd(name, &stream_fops, NULL, -+ O_RDONLY | O_CLOEXEC); -+ if (*out_fd < 0) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+int kbase_sync_fence_out_create(struct kbase_jd_atom *katom, int stream_fd) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence; -+#else -+ struct dma_fence *fence; -+#endif -+ struct sync_file *sync_file; -+ int fd; -+ -+ fence = kbase_fence_out_new(katom); -+ if (!fence) -+ return -ENOMEM; -+ -+ /* Take an extra reference to the fence on behalf of the katom. -+ * This is needed because sync_file_create() will take ownership of -+ * one of these refs */ -+ dma_fence_get(fence); -+ -+ /* create a sync_file fd representing the fence */ -+ sync_file = sync_file_create(fence); -+ if (!sync_file) { -+ dma_fence_put(fence); -+ kbase_fence_out_remove(katom); -+ return -ENOMEM; -+ } -+ -+ fd = get_unused_fd_flags(O_CLOEXEC); -+ if (fd < 0) { -+ fput(sync_file->file); -+ kbase_fence_out_remove(katom); -+ return fd; -+ } -+ -+ fd_install(fd, sync_file->file); -+ -+ return fd; -+} -+ -+int kbase_sync_fence_in_from_fd(struct kbase_jd_atom *katom, int fd) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence = sync_file_get_fence(fd); -+#else -+ struct dma_fence *fence = sync_file_get_fence(fd); -+#endif -+ -+ if (!fence) -+ return -ENOENT; -+ -+ kbase_fence_fence_in_set(katom, fence); -+ -+ return 0; -+} -+ -+int kbase_sync_fence_validate(int fd) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence = sync_file_get_fence(fd); -+#else -+ struct dma_fence *fence = sync_file_get_fence(fd); -+#endif -+ -+ if (!fence) -+ return -EINVAL; -+ -+ dma_fence_put(fence); -+ -+ return 0; /* valid */ -+} -+ -+enum base_jd_event_code -+kbase_sync_fence_out_trigger(struct kbase_jd_atom *katom, int result) -+{ -+ int res; -+ -+ if (!kbase_fence_out_is_ours(katom)) { -+ /* Not our fence */ -+ return BASE_JD_EVENT_JOB_CANCELLED; -+ } -+ -+ res = kbase_fence_out_signal(katom, result); -+ if (unlikely(res < 0)) { -+ dev_warn(katom->kctx->kbdev->dev, -+ "fence_signal() failed with %d\n", res); -+ } -+ -+ kbase_sync_fence_out_remove(katom); -+ -+ return (result != 0) ? BASE_JD_EVENT_JOB_CANCELLED : BASE_JD_EVENT_DONE; -+} -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+static void kbase_fence_wait_callback(struct fence *fence, -+ struct fence_cb *cb) -+#else -+static void kbase_fence_wait_callback(struct dma_fence *fence, -+ struct dma_fence_cb *cb) -+#endif -+{ -+ struct kbase_fence_cb *kcb = container_of(cb, -+ struct kbase_fence_cb, -+ fence_cb); -+ struct kbase_jd_atom *katom = kcb->katom; -+ struct kbase_context *kctx = katom->kctx; -+ -+ /* Cancel atom if fence is erroneous */ -+ if (dma_fence_is_signaled(kcb->fence) && kcb->fence->status < 0) -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ -+ if (kbase_fence_dep_count_dec_and_test(katom)) { -+ /* We take responsibility of handling this */ -+ kbase_fence_dep_count_set(katom, -1); -+ -+ /* To prevent a potential deadlock we schedule the work onto the -+ * job_done_wq workqueue -+ * -+ * The issue is that we may signal the timeline while holding -+ * kctx->jctx.lock and the callbacks are run synchronously from -+ * sync_timeline_signal. So we simply defer the work. -+ */ -+ INIT_WORK(&katom->work, kbase_sync_fence_wait_worker); -+ queue_work(kctx->jctx.job_done_wq, &katom->work); -+ } -+} -+ -+int kbase_sync_fence_in_wait(struct kbase_jd_atom *katom) -+{ -+ int err; -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence; -+#else -+ struct dma_fence *fence; -+#endif -+ -+ fence = kbase_fence_in_get(katom); -+ if (!fence) -+ return 0; /* no input fence to wait for, good to go! */ -+ -+ kbase_fence_dep_count_set(katom, 1); -+ -+ err = kbase_fence_add_callback(katom, fence, kbase_fence_wait_callback); -+ -+ kbase_fence_put(fence); -+ -+ if (likely(!err)) { -+ /* Test if the callbacks are already triggered */ -+ if (kbase_fence_dep_count_dec_and_test(katom)) { -+ kbase_fence_free_callbacks(katom); -+ kbase_fence_dep_count_set(katom, -1); -+ return 0; /* Already signaled, good to go right now */ -+ } -+ -+ /* Callback installed, so we just need to wait for it... */ -+ } else { -+ /* Failure */ -+ kbase_fence_free_callbacks(katom); -+ kbase_fence_dep_count_set(katom, -1); -+ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ -+ /* We should cause the dependent jobs in the bag to be failed, -+ * to do this we schedule the work queue to complete this job */ -+ -+ INIT_WORK(&katom->work, kbase_sync_fence_wait_worker); -+ queue_work(katom->kctx->jctx.job_done_wq, &katom->work); -+ } -+ -+ return 1; /* completion to be done later by callback/worker */ -+} -+ -+void kbase_sync_fence_in_cancel_wait(struct kbase_jd_atom *katom) -+{ -+ if (!kbase_fence_free_callbacks(katom)) { -+ /* The wait wasn't cancelled - -+ * leave the cleanup for kbase_fence_wait_callback */ -+ return; -+ } -+ -+ /* Take responsibility of completion */ -+ kbase_fence_dep_count_set(katom, -1); -+ -+ /* Wait was cancelled - zap the atoms */ -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+ -+ kbasep_remove_waiting_soft_job(katom); -+ kbase_finish_soft_job(katom); -+ -+ if (jd_done_nolock(katom, NULL)) -+ kbase_js_sched_all(katom->kctx->kbdev); -+} -+ -+void kbase_sync_fence_out_remove(struct kbase_jd_atom *katom) -+{ -+ kbase_fence_out_remove(katom); -+} -+ -+void kbase_sync_fence_in_remove(struct kbase_jd_atom *katom) -+{ -+ kbase_fence_free_callbacks(katom); -+ kbase_fence_in_remove(katom); -+} -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+static void kbase_sync_fence_info_get(struct fence *fence, -+ struct kbase_sync_fence_info *info) -+#else -+static void kbase_sync_fence_info_get(struct dma_fence *fence, -+ struct kbase_sync_fence_info *info) -+#endif -+{ -+ info->fence = fence; -+ -+ /* translate into CONFIG_SYNC status: -+ * < 0 : error -+ * 0 : active -+ * 1 : signaled -+ */ -+ if (dma_fence_is_signaled(fence)) { -+ if (fence->status < 0) -+ info->status = fence->status; /* signaled with error */ -+ else -+ info->status = 1; /* signaled with success */ -+ } else { -+ info->status = 0; /* still active (unsignaled) */ -+ } -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) -+ scnprintf(info->name, sizeof(info->name), "%u#%u", -+ fence->context, fence->seqno); -+#else -+ scnprintf(info->name, sizeof(info->name), "%llu#%u", -+ fence->context, fence->seqno); -+#endif -+} -+ -+int kbase_sync_fence_in_info_get(struct kbase_jd_atom *katom, -+ struct kbase_sync_fence_info *info) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence; -+#else -+ struct dma_fence *fence; -+#endif -+ -+ fence = kbase_fence_in_get(katom); -+ if (!fence) -+ return -ENOENT; -+ -+ kbase_sync_fence_info_get(fence, info); -+ -+ kbase_fence_put(fence); -+ -+ return 0; -+} -+ -+int kbase_sync_fence_out_info_get(struct kbase_jd_atom *katom, -+ struct kbase_sync_fence_info *info) -+{ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) -+ struct fence *fence; -+#else -+ struct dma_fence *fence; -+#endif -+ -+ fence = kbase_fence_out_get(katom); -+ if (!fence) -+ return -ENOENT; -+ -+ kbase_sync_fence_info_get(fence, info); -+ -+ kbase_fence_put(fence); -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_MALI_FENCE_DEBUG -+void kbase_sync_fence_in_dump(struct kbase_jd_atom *katom) -+{ -+ /* Not implemented */ -+} -+#endif -diff --git a/drivers/gpu/arm/midgard/mali_kbase_tlstream.c b/drivers/gpu/arm/midgard/mali_kbase_tlstream.c -new file mode 100644 -index 0000000..c952993 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_tlstream.c -@@ -0,0 +1,2572 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/*****************************************************************************/ -+ -+/* The version of swtrace protocol used in timeline stream. */ -+#define SWTRACE_VERSION 3 -+ -+/* The maximum expected length of string in tracepoint descriptor. */ -+#define STRLEN_MAX 64 /* bytes */ -+ -+/* The number of nanoseconds in a second. */ -+#define NSECS_IN_SEC 1000000000ull /* ns */ -+ -+/* The period of autoflush checker execution in milliseconds. */ -+#define AUTOFLUSH_INTERVAL 1000 /* ms */ -+ -+/* The maximum size of a single packet used by timeline. */ -+#define PACKET_SIZE 4096 /* bytes */ -+ -+/* The number of packets used by one timeline stream. */ -+#define PACKET_COUNT 16 -+ -+/* The number of bytes reserved for packet header. -+ * These value must be defined according to MIPE documentation. */ -+#define PACKET_HEADER_SIZE 8 /* bytes */ -+ -+/* The number of bytes reserved for packet sequence number. -+ * These value must be defined according to MIPE documentation. */ -+#define PACKET_NUMBER_SIZE 4 /* bytes */ -+ -+/* Packet header - first word. -+ * These values must be defined according to MIPE documentation. */ -+#define PACKET_STREAMID_POS 0 -+#define PACKET_STREAMID_LEN 8 -+#define PACKET_RSVD1_POS (PACKET_STREAMID_POS + PACKET_STREAMID_LEN) -+#define PACKET_RSVD1_LEN 8 -+#define PACKET_TYPE_POS (PACKET_RSVD1_POS + PACKET_RSVD1_LEN) -+#define PACKET_TYPE_LEN 3 -+#define PACKET_CLASS_POS (PACKET_TYPE_POS + PACKET_TYPE_LEN) -+#define PACKET_CLASS_LEN 7 -+#define PACKET_FAMILY_POS (PACKET_CLASS_POS + PACKET_CLASS_LEN) -+#define PACKET_FAMILY_LEN 6 -+ -+/* Packet header - second word -+ * These values must be defined according to MIPE documentation. */ -+#define PACKET_LENGTH_POS 0 -+#define PACKET_LENGTH_LEN 24 -+#define PACKET_SEQBIT_POS (PACKET_LENGTH_POS + PACKET_LENGTH_LEN) -+#define PACKET_SEQBIT_LEN 1 -+#define PACKET_RSVD2_POS (PACKET_SEQBIT_POS + PACKET_SEQBIT_LEN) -+#define PACKET_RSVD2_LEN 7 -+ -+/* Types of streams generated by timeline. -+ * Order is significant! Header streams must precede respective body streams. */ -+enum tl_stream_type { -+ TL_STREAM_TYPE_OBJ_HEADER, -+ TL_STREAM_TYPE_OBJ_SUMMARY, -+ TL_STREAM_TYPE_OBJ, -+ TL_STREAM_TYPE_AUX_HEADER, -+ TL_STREAM_TYPE_AUX, -+ -+ TL_STREAM_TYPE_COUNT -+}; -+ -+/* Timeline packet family ids. -+ * Values are significant! Check MIPE documentation. */ -+enum tl_packet_family { -+ TL_PACKET_FAMILY_CTRL = 0, /* control packets */ -+ TL_PACKET_FAMILY_TL = 1, /* timeline packets */ -+ -+ TL_PACKET_FAMILY_COUNT -+}; -+ -+/* Packet classes used in timeline streams. -+ * Values are significant! Check MIPE documentation. */ -+enum tl_packet_class { -+ TL_PACKET_CLASS_OBJ = 0, /* timeline objects packet */ -+ TL_PACKET_CLASS_AUX = 1, /* auxiliary events packet */ -+}; -+ -+/* Packet types used in timeline streams. -+ * Values are significant! Check MIPE documentation. */ -+enum tl_packet_type { -+ TL_PACKET_TYPE_HEADER = 0, /* stream's header/directory */ -+ TL_PACKET_TYPE_BODY = 1, /* stream's body */ -+ TL_PACKET_TYPE_SUMMARY = 2, /* stream's summary */ -+}; -+ -+/* Message ids of trace events that are recorded in the timeline stream. */ -+enum tl_msg_id_obj { -+ /* Timeline object events. */ -+ KBASE_TL_NEW_CTX, -+ KBASE_TL_NEW_GPU, -+ KBASE_TL_NEW_LPU, -+ KBASE_TL_NEW_ATOM, -+ KBASE_TL_NEW_AS, -+ KBASE_TL_DEL_CTX, -+ KBASE_TL_DEL_ATOM, -+ KBASE_TL_LIFELINK_LPU_GPU, -+ KBASE_TL_LIFELINK_AS_GPU, -+ KBASE_TL_RET_CTX_LPU, -+ KBASE_TL_RET_ATOM_CTX, -+ KBASE_TL_RET_ATOM_LPU, -+ KBASE_TL_NRET_CTX_LPU, -+ KBASE_TL_NRET_ATOM_CTX, -+ KBASE_TL_NRET_ATOM_LPU, -+ KBASE_TL_RET_AS_CTX, -+ KBASE_TL_NRET_AS_CTX, -+ KBASE_TL_RET_ATOM_AS, -+ KBASE_TL_NRET_ATOM_AS, -+ KBASE_TL_DEP_ATOM_ATOM, -+ KBASE_TL_NDEP_ATOM_ATOM, -+ KBASE_TL_RDEP_ATOM_ATOM, -+ KBASE_TL_ATTRIB_ATOM_CONFIG, -+ KBASE_TL_ATTRIB_ATOM_PRIORITY, -+ KBASE_TL_ATTRIB_ATOM_STATE, -+ KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE, -+ KBASE_TL_ATTRIB_ATOM_JIT, -+ KBASE_TL_ATTRIB_AS_CONFIG, -+ KBASE_TL_EVENT_LPU_SOFTSTOP, -+ KBASE_TL_EVENT_ATOM_SOFTSTOP_EX, -+ KBASE_TL_EVENT_ATOM_SOFTSTOP_ISSUE, -+ -+ /* Job dump specific events. */ -+ KBASE_JD_GPU_SOFT_RESET -+}; -+ -+/* Message ids of trace events that are recorded in the auxiliary stream. */ -+enum tl_msg_id_aux { -+ KBASE_AUX_PM_STATE, -+ KBASE_AUX_PAGEFAULT, -+ KBASE_AUX_PAGESALLOC, -+ KBASE_AUX_DEVFREQ_TARGET, -+ KBASE_AUX_PROTECTED_ENTER_START, -+ KBASE_AUX_PROTECTED_ENTER_END, -+ KBASE_AUX_PROTECTED_LEAVE_START, -+ KBASE_AUX_PROTECTED_LEAVE_END -+}; -+ -+/*****************************************************************************/ -+ -+/** -+ * struct tl_stream - timeline stream structure -+ * @lock: message order lock -+ * @buffer: array of buffers -+ * @wbi: write buffer index -+ * @rbi: read buffer index -+ * @numbered: if non-zero stream's packets are sequentially numbered -+ * @autoflush_counter: counter tracking stream's autoflush state -+ * -+ * This structure holds information needed to construct proper packets in the -+ * timeline stream. Each message in sequence must bear timestamp that is greater -+ * to one in previous message in the same stream. For this reason lock is held -+ * throughout the process of message creation. Each stream contains set of -+ * buffers. Each buffer will hold one MIPE packet. In case there is no free -+ * space required to store incoming message the oldest buffer is discarded. -+ * Each packet in timeline body stream has sequence number embedded (this value -+ * must increment monotonically and is used by packets receiver to discover -+ * buffer overflows. -+ * Autoflush counter is set to negative number when there is no data pending -+ * for flush and it is set to zero on every update of the buffer. Autoflush -+ * timer will increment the counter by one on every expiry. In case there will -+ * be no activity on the buffer during two consecutive timer expiries, stream -+ * buffer will be flushed. -+ */ -+struct tl_stream { -+ spinlock_t lock; -+ -+ struct { -+ atomic_t size; /* number of bytes in buffer */ -+ char data[PACKET_SIZE]; /* buffer's data */ -+ } buffer[PACKET_COUNT]; -+ -+ atomic_t wbi; -+ atomic_t rbi; -+ -+ int numbered; -+ atomic_t autoflush_counter; -+}; -+ -+/** -+ * struct tp_desc - tracepoint message descriptor structure -+ * @id: tracepoint ID identifying message in stream -+ * @id_str: human readable version of tracepoint ID -+ * @name: tracepoint description -+ * @arg_types: tracepoint's arguments types declaration -+ * @arg_names: comma separated list of tracepoint's arguments names -+ */ -+struct tp_desc { -+ u32 id; -+ const char *id_str; -+ const char *name; -+ const char *arg_types; -+ const char *arg_names; -+}; -+ -+/*****************************************************************************/ -+ -+/* Configuration of timeline streams generated by kernel. -+ * Kernel emit only streams containing either timeline object events or -+ * auxiliary events. All streams have stream id value of 1 (as opposed to user -+ * space streams that have value of 0). */ -+static const struct { -+ enum tl_packet_family pkt_family; -+ enum tl_packet_class pkt_class; -+ enum tl_packet_type pkt_type; -+ unsigned int stream_id; -+} tl_stream_cfg[TL_STREAM_TYPE_COUNT] = { -+ {TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_OBJ, TL_PACKET_TYPE_HEADER, 1}, -+ {TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_OBJ, TL_PACKET_TYPE_SUMMARY, 1}, -+ {TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_OBJ, TL_PACKET_TYPE_BODY, 1}, -+ {TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_AUX, TL_PACKET_TYPE_HEADER, 1}, -+ {TL_PACKET_FAMILY_TL, TL_PACKET_CLASS_AUX, TL_PACKET_TYPE_BODY, 1} -+}; -+ -+/* The timeline streams generated by kernel. */ -+static struct tl_stream *tl_stream[TL_STREAM_TYPE_COUNT]; -+ -+/* Autoflush timer. */ -+static struct timer_list autoflush_timer; -+ -+/* If non-zero autoflush timer is active. */ -+static atomic_t autoflush_timer_active; -+ -+/* Reader lock. Only one reader is allowed to have access to the timeline -+ * streams at any given time. */ -+static DEFINE_MUTEX(tl_reader_lock); -+ -+/* Timeline stream event queue. */ -+static DECLARE_WAIT_QUEUE_HEAD(tl_event_queue); -+ -+/* The timeline stream file operations functions. */ -+static ssize_t kbasep_tlstream_read( -+ struct file *filp, -+ char __user *buffer, -+ size_t size, -+ loff_t *f_pos); -+static unsigned int kbasep_tlstream_poll(struct file *filp, poll_table *wait); -+static int kbasep_tlstream_release(struct inode *inode, struct file *filp); -+ -+/* The timeline stream file operations structure. */ -+static const struct file_operations kbasep_tlstream_fops = { -+ .release = kbasep_tlstream_release, -+ .read = kbasep_tlstream_read, -+ .poll = kbasep_tlstream_poll, -+}; -+ -+/* Descriptors of timeline messages transmitted in object events stream. */ -+static const struct tp_desc tp_desc_obj[] = { -+ { -+ KBASE_TL_NEW_CTX, -+ __stringify(KBASE_TL_NEW_CTX), -+ "object ctx is created", -+ "@pII", -+ "ctx,ctx_nr,tgid" -+ }, -+ { -+ KBASE_TL_NEW_GPU, -+ __stringify(KBASE_TL_NEW_GPU), -+ "object gpu is created", -+ "@pII", -+ "gpu,gpu_id,core_count" -+ }, -+ { -+ KBASE_TL_NEW_LPU, -+ __stringify(KBASE_TL_NEW_LPU), -+ "object lpu is created", -+ "@pII", -+ "lpu,lpu_nr,lpu_fn" -+ }, -+ { -+ KBASE_TL_NEW_ATOM, -+ __stringify(KBASE_TL_NEW_ATOM), -+ "object atom is created", -+ "@pI", -+ "atom,atom_nr" -+ }, -+ { -+ KBASE_TL_NEW_AS, -+ __stringify(KBASE_TL_NEW_AS), -+ "address space object is created", -+ "@pI", -+ "address_space,as_nr" -+ }, -+ { -+ KBASE_TL_DEL_CTX, -+ __stringify(KBASE_TL_DEL_CTX), -+ "context is destroyed", -+ "@p", -+ "ctx" -+ }, -+ { -+ KBASE_TL_DEL_ATOM, -+ __stringify(KBASE_TL_DEL_ATOM), -+ "atom is destroyed", -+ "@p", -+ "atom" -+ }, -+ { -+ KBASE_TL_LIFELINK_LPU_GPU, -+ __stringify(KBASE_TL_LIFELINK_LPU_GPU), -+ "lpu is deleted with gpu", -+ "@pp", -+ "lpu,gpu" -+ }, -+ { -+ KBASE_TL_LIFELINK_AS_GPU, -+ __stringify(KBASE_TL_LIFELINK_AS_GPU), -+ "address space is deleted with gpu", -+ "@pp", -+ "address_space,gpu" -+ }, -+ { -+ KBASE_TL_RET_CTX_LPU, -+ __stringify(KBASE_TL_RET_CTX_LPU), -+ "context is retained by lpu", -+ "@pp", -+ "ctx,lpu" -+ }, -+ { -+ KBASE_TL_RET_ATOM_CTX, -+ __stringify(KBASE_TL_RET_ATOM_CTX), -+ "atom is retained by context", -+ "@pp", -+ "atom,ctx" -+ }, -+ { -+ KBASE_TL_RET_ATOM_LPU, -+ __stringify(KBASE_TL_RET_ATOM_LPU), -+ "atom is retained by lpu", -+ "@pps", -+ "atom,lpu,attrib_match_list" -+ }, -+ { -+ KBASE_TL_NRET_CTX_LPU, -+ __stringify(KBASE_TL_NRET_CTX_LPU), -+ "context is released by lpu", -+ "@pp", -+ "ctx,lpu" -+ }, -+ { -+ KBASE_TL_NRET_ATOM_CTX, -+ __stringify(KBASE_TL_NRET_ATOM_CTX), -+ "atom is released by context", -+ "@pp", -+ "atom,ctx" -+ }, -+ { -+ KBASE_TL_NRET_ATOM_LPU, -+ __stringify(KBASE_TL_NRET_ATOM_LPU), -+ "atom is released by lpu", -+ "@pp", -+ "atom,lpu" -+ }, -+ { -+ KBASE_TL_RET_AS_CTX, -+ __stringify(KBASE_TL_RET_AS_CTX), -+ "address space is retained by context", -+ "@pp", -+ "address_space,ctx" -+ }, -+ { -+ KBASE_TL_NRET_AS_CTX, -+ __stringify(KBASE_TL_NRET_AS_CTX), -+ "address space is released by context", -+ "@pp", -+ "address_space,ctx" -+ }, -+ { -+ KBASE_TL_RET_ATOM_AS, -+ __stringify(KBASE_TL_RET_ATOM_AS), -+ "atom is retained by address space", -+ "@pp", -+ "atom,address_space" -+ }, -+ { -+ KBASE_TL_NRET_ATOM_AS, -+ __stringify(KBASE_TL_NRET_ATOM_AS), -+ "atom is released by address space", -+ "@pp", -+ "atom,address_space" -+ }, -+ { -+ KBASE_TL_DEP_ATOM_ATOM, -+ __stringify(KBASE_TL_DEP_ATOM_ATOM), -+ "atom2 depends on atom1", -+ "@pp", -+ "atom1,atom2" -+ }, -+ { -+ KBASE_TL_NDEP_ATOM_ATOM, -+ __stringify(KBASE_TL_NDEP_ATOM_ATOM), -+ "atom2 no longer depends on atom1", -+ "@pp", -+ "atom1,atom2" -+ }, -+ { -+ KBASE_TL_RDEP_ATOM_ATOM, -+ __stringify(KBASE_TL_RDEP_ATOM_ATOM), -+ "resolved dependecy of atom2 depending on atom1", -+ "@pp", -+ "atom1,atom2" -+ }, -+ { -+ KBASE_TL_ATTRIB_ATOM_CONFIG, -+ __stringify(KBASE_TL_ATTRIB_ATOM_CONFIG), -+ "atom job slot attributes", -+ "@pLLI", -+ "atom,descriptor,affinity,config" -+ }, -+ { -+ KBASE_TL_ATTRIB_ATOM_PRIORITY, -+ __stringify(KBASE_TL_ATTRIB_ATOM_PRIORITY), -+ "atom priority", -+ "@pI", -+ "atom,prio" -+ }, -+ { -+ KBASE_TL_ATTRIB_ATOM_STATE, -+ __stringify(KBASE_TL_ATTRIB_ATOM_STATE), -+ "atom state", -+ "@pI", -+ "atom,state" -+ }, -+ { -+ KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE, -+ __stringify(KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE), -+ "atom caused priority change", -+ "@p", -+ "atom" -+ }, -+ { -+ KBASE_TL_ATTRIB_ATOM_JIT, -+ __stringify(KBASE_TL_ATTRIB_ATOM_JIT), -+ "jit done for atom", -+ "@pLL", -+ "atom,edit_addr,new_addr" -+ }, -+ { -+ KBASE_TL_ATTRIB_AS_CONFIG, -+ __stringify(KBASE_TL_ATTRIB_AS_CONFIG), -+ "address space attributes", -+ "@pLLL", -+ "address_space,transtab,memattr,transcfg" -+ }, -+ { -+ KBASE_TL_EVENT_LPU_SOFTSTOP, -+ __stringify(KBASE_TL_EVENT_LPU_SOFTSTOP), -+ "softstop event on given lpu", -+ "@p", -+ "lpu" -+ }, -+ { -+ KBASE_TL_EVENT_ATOM_SOFTSTOP_EX, -+ __stringify(KBASE_TL_EVENT_ATOM_SOFTSTOP_EX), -+ "atom softstopped", -+ "@p", -+ "atom" -+ }, -+ { -+ KBASE_TL_EVENT_ATOM_SOFTSTOP_ISSUE, -+ __stringify(KBASE_TL_EVENT_SOFTSTOP_ISSUE), -+ "atom softstop issued", -+ "@p", -+ "atom" -+ }, -+ { -+ KBASE_JD_GPU_SOFT_RESET, -+ __stringify(KBASE_JD_GPU_SOFT_RESET), -+ "gpu soft reset", -+ "@p", -+ "gpu" -+ }, -+}; -+ -+/* Descriptors of timeline messages transmitted in auxiliary events stream. */ -+static const struct tp_desc tp_desc_aux[] = { -+ { -+ KBASE_AUX_PM_STATE, -+ __stringify(KBASE_AUX_PM_STATE), -+ "PM state", -+ "@IL", -+ "core_type,core_state_bitset" -+ }, -+ { -+ KBASE_AUX_PAGEFAULT, -+ __stringify(KBASE_AUX_PAGEFAULT), -+ "Page fault", -+ "@IL", -+ "ctx_nr,page_cnt_change" -+ }, -+ { -+ KBASE_AUX_PAGESALLOC, -+ __stringify(KBASE_AUX_PAGESALLOC), -+ "Total alloc pages change", -+ "@IL", -+ "ctx_nr,page_cnt" -+ }, -+ { -+ KBASE_AUX_DEVFREQ_TARGET, -+ __stringify(KBASE_AUX_DEVFREQ_TARGET), -+ "New device frequency target", -+ "@L", -+ "target_freq" -+ }, -+ { -+ KBASE_AUX_PROTECTED_ENTER_START, -+ __stringify(KBASE_AUX_PROTECTED_ENTER_START), -+ "enter protected mode start", -+ "@p", -+ "gpu" -+ }, -+ { -+ KBASE_AUX_PROTECTED_ENTER_END, -+ __stringify(KBASE_AUX_PROTECTED_ENTER_END), -+ "enter protected mode end", -+ "@p", -+ "gpu" -+ }, -+ { -+ KBASE_AUX_PROTECTED_LEAVE_START, -+ __stringify(KBASE_AUX_PROTECTED_LEAVE_START), -+ "leave protected mode start", -+ "@p", -+ "gpu" -+ }, -+ { -+ KBASE_AUX_PROTECTED_LEAVE_END, -+ __stringify(KBASE_AUX_PROTECTED_LEAVE_END), -+ "leave protected mode end", -+ "@p", -+ "gpu" -+ } -+}; -+ -+#if MALI_UNIT_TEST -+/* Number of bytes read by user. */ -+static atomic_t tlstream_bytes_collected = {0}; -+ -+/* Number of bytes generated by tracepoint messages. */ -+static atomic_t tlstream_bytes_generated = {0}; -+#endif /* MALI_UNIT_TEST */ -+ -+/*****************************************************************************/ -+ -+/* Indicator of whether the timeline stream file descriptor is used. */ -+atomic_t kbase_tlstream_enabled = {0}; -+ -+/*****************************************************************************/ -+ -+/** -+ * kbasep_tlstream_get_timestamp - return timestamp -+ * -+ * Function returns timestamp value based on raw monotonic timer. Value will -+ * wrap around zero in case of overflow. -+ * Return: timestamp value -+ */ -+static u64 kbasep_tlstream_get_timestamp(void) -+{ -+ struct timespec ts; -+ u64 timestamp; -+ -+ getrawmonotonic(&ts); -+ timestamp = (u64)ts.tv_sec * NSECS_IN_SEC + ts.tv_nsec; -+ return timestamp; -+} -+ -+/** -+ * kbasep_tlstream_write_bytes - write data to message buffer -+ * @buffer: buffer where data will be written -+ * @pos: position in the buffer where to place data -+ * @bytes: pointer to buffer holding data -+ * @len: length of data to be written -+ * -+ * Return: updated position in the buffer -+ */ -+static size_t kbasep_tlstream_write_bytes( -+ char *buffer, -+ size_t pos, -+ const void *bytes, -+ size_t len) -+{ -+ KBASE_DEBUG_ASSERT(buffer); -+ KBASE_DEBUG_ASSERT(bytes); -+ -+ memcpy(&buffer[pos], bytes, len); -+ -+ return pos + len; -+} -+ -+/** -+ * kbasep_tlstream_write_string - write string to message buffer -+ * @buffer: buffer where data will be written -+ * @pos: position in the buffer where to place data -+ * @string: pointer to buffer holding the source string -+ * @max_write_size: number of bytes that can be stored in buffer -+ * -+ * Return: updated position in the buffer -+ */ -+static size_t kbasep_tlstream_write_string( -+ char *buffer, -+ size_t pos, -+ const char *string, -+ size_t max_write_size) -+{ -+ u32 string_len; -+ -+ KBASE_DEBUG_ASSERT(buffer); -+ KBASE_DEBUG_ASSERT(string); -+ /* Timeline string consists of at least string length and nul -+ * terminator. */ -+ KBASE_DEBUG_ASSERT(max_write_size >= sizeof(string_len) + sizeof(char)); -+ max_write_size -= sizeof(string_len); -+ -+ string_len = strlcpy( -+ &buffer[pos + sizeof(string_len)], -+ string, -+ max_write_size); -+ string_len += sizeof(char); -+ -+ /* Make sure that the source string fit into the buffer. */ -+ KBASE_DEBUG_ASSERT(string_len <= max_write_size); -+ -+ /* Update string length. */ -+ memcpy(&buffer[pos], &string_len, sizeof(string_len)); -+ -+ return pos + sizeof(string_len) + string_len; -+} -+ -+/** -+ * kbasep_tlstream_write_timestamp - write timestamp to message buffer -+ * @buffer: buffer where data will be written -+ * @pos: position in the buffer where to place data -+ * -+ * Return: updated position in the buffer -+ */ -+static size_t kbasep_tlstream_write_timestamp(void *buffer, size_t pos) -+{ -+ u64 timestamp = kbasep_tlstream_get_timestamp(); -+ -+ return kbasep_tlstream_write_bytes( -+ buffer, pos, -+ ×tamp, sizeof(timestamp)); -+} -+ -+/** -+ * kbasep_tlstream_put_bits - put bits in a word -+ * @word: pointer to the words being modified -+ * @value: value that shall be written to given position -+ * @bitpos: position where value shall be written (in bits) -+ * @bitlen: length of value (in bits) -+ */ -+static void kbasep_tlstream_put_bits( -+ u32 *word, -+ u32 value, -+ unsigned int bitpos, -+ unsigned int bitlen) -+{ -+ const u32 mask = ((1 << bitlen) - 1) << bitpos; -+ -+ KBASE_DEBUG_ASSERT(word); -+ KBASE_DEBUG_ASSERT((0 != bitlen) && (32 >= bitlen)); -+ KBASE_DEBUG_ASSERT((bitpos + bitlen) <= 32); -+ -+ *word &= ~mask; -+ *word |= ((value << bitpos) & mask); -+} -+ -+/** -+ * kbasep_tlstream_packet_header_setup - setup the packet header -+ * @buffer: pointer to the buffer -+ * @pkt_family: packet's family -+ * @pkt_type: packet's type -+ * @pkt_class: packet's class -+ * @stream_id: stream id -+ * @numbered: non-zero if this stream is numbered -+ * -+ * Function sets up immutable part of packet header in the given buffer. -+ */ -+static void kbasep_tlstream_packet_header_setup( -+ char *buffer, -+ enum tl_packet_family pkt_family, -+ enum tl_packet_class pkt_class, -+ enum tl_packet_type pkt_type, -+ unsigned int stream_id, -+ int numbered) -+{ -+ u32 word0 = 0; -+ u32 word1 = 0; -+ -+ KBASE_DEBUG_ASSERT(buffer); -+ KBASE_DEBUG_ASSERT(pkt_family == TL_PACKET_FAMILY_TL); -+ KBASE_DEBUG_ASSERT( -+ (pkt_type == TL_PACKET_TYPE_HEADER) || -+ (pkt_type == TL_PACKET_TYPE_SUMMARY) || -+ (pkt_type == TL_PACKET_TYPE_BODY)); -+ KBASE_DEBUG_ASSERT( -+ (pkt_class == TL_PACKET_CLASS_OBJ) || -+ (pkt_class == TL_PACKET_CLASS_AUX)); -+ -+ kbasep_tlstream_put_bits( -+ &word0, pkt_family, -+ PACKET_FAMILY_POS, PACKET_FAMILY_LEN); -+ kbasep_tlstream_put_bits( -+ &word0, pkt_class, -+ PACKET_CLASS_POS, PACKET_CLASS_LEN); -+ kbasep_tlstream_put_bits( -+ &word0, pkt_type, -+ PACKET_TYPE_POS, PACKET_TYPE_LEN); -+ kbasep_tlstream_put_bits( -+ &word0, stream_id, -+ PACKET_STREAMID_POS, PACKET_STREAMID_LEN); -+ -+ if (numbered) -+ kbasep_tlstream_put_bits( -+ &word1, 1, -+ PACKET_SEQBIT_POS, PACKET_SEQBIT_LEN); -+ -+ memcpy(&buffer[0], &word0, sizeof(word0)); -+ memcpy(&buffer[sizeof(word0)], &word1, sizeof(word1)); -+} -+ -+/** -+ * kbasep_tlstream_packet_header_update - update the packet header -+ * @buffer: pointer to the buffer -+ * @data_size: amount of data carried in this packet -+ * -+ * Function updates mutable part of packet header in the given buffer. -+ * Note that value of data_size must not including size of the header. -+ */ -+static void kbasep_tlstream_packet_header_update( -+ char *buffer, -+ size_t data_size) -+{ -+ u32 word0; -+ u32 word1; -+ -+ KBASE_DEBUG_ASSERT(buffer); -+ CSTD_UNUSED(word0); -+ -+ memcpy(&word1, &buffer[sizeof(word0)], sizeof(word1)); -+ -+ kbasep_tlstream_put_bits( -+ &word1, data_size, -+ PACKET_LENGTH_POS, PACKET_LENGTH_LEN); -+ -+ memcpy(&buffer[sizeof(word0)], &word1, sizeof(word1)); -+} -+ -+/** -+ * kbasep_tlstream_packet_number_update - update the packet number -+ * @buffer: pointer to the buffer -+ * @counter: value of packet counter for this packet's stream -+ * -+ * Function updates packet number embedded within the packet placed in the -+ * given buffer. -+ */ -+static void kbasep_tlstream_packet_number_update(char *buffer, u32 counter) -+{ -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ memcpy(&buffer[PACKET_HEADER_SIZE], &counter, sizeof(counter)); -+} -+ -+/** -+ * kbasep_timeline_stream_reset - reset stream -+ * @stream: pointer to the stream structure -+ * -+ * Function discards all pending messages and resets packet counters. -+ */ -+static void kbasep_timeline_stream_reset(struct tl_stream *stream) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < PACKET_COUNT; i++) { -+ if (stream->numbered) -+ atomic_set( -+ &stream->buffer[i].size, -+ PACKET_HEADER_SIZE + -+ PACKET_NUMBER_SIZE); -+ else -+ atomic_set(&stream->buffer[i].size, PACKET_HEADER_SIZE); -+ } -+ -+ atomic_set(&stream->wbi, 0); -+ atomic_set(&stream->rbi, 0); -+} -+ -+/** -+ * kbasep_timeline_stream_init - initialize timeline stream -+ * @stream: pointer to the stream structure -+ * @stream_type: stream type -+ */ -+static void kbasep_timeline_stream_init( -+ struct tl_stream *stream, -+ enum tl_stream_type stream_type) -+{ -+ unsigned int i; -+ -+ KBASE_DEBUG_ASSERT(stream); -+ KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type); -+ -+ spin_lock_init(&stream->lock); -+ -+ /* All packets carrying tracepoints shall be numbered. */ -+ if (TL_PACKET_TYPE_BODY == tl_stream_cfg[stream_type].pkt_type) -+ stream->numbered = 1; -+ else -+ stream->numbered = 0; -+ -+ for (i = 0; i < PACKET_COUNT; i++) -+ kbasep_tlstream_packet_header_setup( -+ stream->buffer[i].data, -+ tl_stream_cfg[stream_type].pkt_family, -+ tl_stream_cfg[stream_type].pkt_class, -+ tl_stream_cfg[stream_type].pkt_type, -+ tl_stream_cfg[stream_type].stream_id, -+ stream->numbered); -+ -+ kbasep_timeline_stream_reset(tl_stream[stream_type]); -+} -+ -+/** -+ * kbasep_timeline_stream_term - terminate timeline stream -+ * @stream: pointer to the stream structure -+ */ -+static void kbasep_timeline_stream_term(struct tl_stream *stream) -+{ -+ KBASE_DEBUG_ASSERT(stream); -+} -+ -+/** -+ * kbasep_tlstream_msgbuf_submit - submit packet to the user space -+ * @stream: pointer to the stream structure -+ * @wb_idx_raw: write buffer index -+ * @wb_size: length of data stored in current buffer -+ * -+ * Function updates currently written buffer with packet header. Then write -+ * index is incremented and buffer is handled to user space. Parameters -+ * of new buffer are returned using provided arguments. -+ * -+ * Return: length of data in new buffer -+ * -+ * Warning: User must update the stream structure with returned value. -+ */ -+static size_t kbasep_tlstream_msgbuf_submit( -+ struct tl_stream *stream, -+ unsigned int wb_idx_raw, -+ unsigned int wb_size) -+{ -+ unsigned int rb_idx_raw = atomic_read(&stream->rbi); -+ unsigned int wb_idx = wb_idx_raw % PACKET_COUNT; -+ -+ /* Set stream as flushed. */ -+ atomic_set(&stream->autoflush_counter, -1); -+ -+ kbasep_tlstream_packet_header_update( -+ stream->buffer[wb_idx].data, -+ wb_size - PACKET_HEADER_SIZE); -+ -+ if (stream->numbered) -+ kbasep_tlstream_packet_number_update( -+ stream->buffer[wb_idx].data, -+ wb_idx_raw); -+ -+ /* Increasing write buffer index will expose this packet to the reader. -+ * As stream->lock is not taken on reader side we must make sure memory -+ * is updated correctly before this will happen. */ -+ smp_wmb(); -+ wb_idx_raw++; -+ atomic_set(&stream->wbi, wb_idx_raw); -+ -+ /* Inform user that packets are ready for reading. */ -+ wake_up_interruptible(&tl_event_queue); -+ -+ /* Detect and mark overflow in this stream. */ -+ if (PACKET_COUNT == wb_idx_raw - rb_idx_raw) { -+ /* Reader side depends on this increment to correctly handle -+ * overflows. The value shall be updated only if it was not -+ * modified by the reader. The data holding buffer will not be -+ * updated before stream->lock is released, however size of the -+ * buffer will. Make sure this increment is globally visible -+ * before information about selected write buffer size. */ -+ atomic_cmpxchg(&stream->rbi, rb_idx_raw, rb_idx_raw + 1); -+ } -+ -+ wb_size = PACKET_HEADER_SIZE; -+ if (stream->numbered) -+ wb_size += PACKET_NUMBER_SIZE; -+ -+ return wb_size; -+} -+ -+/** -+ * kbasep_tlstream_msgbuf_acquire - lock selected stream and reserves buffer -+ * @stream_type: type of the stream that shall be locked -+ * @msg_size: message size -+ * @flags: pointer to store flags passed back on stream release -+ * -+ * Function will lock the stream and reserve the number of bytes requested -+ * in msg_size for the user. -+ * -+ * Return: pointer to the buffer where message can be stored -+ * -+ * Warning: Stream must be released with kbasep_tlstream_msgbuf_release(). -+ * Only atomic operations are allowed while stream is locked -+ * (i.e. do not use any operation that may sleep). -+ */ -+static char *kbasep_tlstream_msgbuf_acquire( -+ enum tl_stream_type stream_type, -+ size_t msg_size, -+ unsigned long *flags) __acquires(&stream->lock) -+{ -+ struct tl_stream *stream; -+ unsigned int wb_idx_raw; -+ unsigned int wb_idx; -+ size_t wb_size; -+ -+ KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type); -+ KBASE_DEBUG_ASSERT( -+ PACKET_SIZE - PACKET_HEADER_SIZE - PACKET_NUMBER_SIZE >= -+ msg_size); -+ -+ stream = tl_stream[stream_type]; -+ -+ spin_lock_irqsave(&stream->lock, *flags); -+ -+ wb_idx_raw = atomic_read(&stream->wbi); -+ wb_idx = wb_idx_raw % PACKET_COUNT; -+ wb_size = atomic_read(&stream->buffer[wb_idx].size); -+ -+ /* Select next buffer if data will not fit into current one. */ -+ if (PACKET_SIZE < wb_size + msg_size) { -+ wb_size = kbasep_tlstream_msgbuf_submit( -+ stream, wb_idx_raw, wb_size); -+ wb_idx = (wb_idx_raw + 1) % PACKET_COUNT; -+ } -+ -+ /* Reserve space in selected buffer. */ -+ atomic_set(&stream->buffer[wb_idx].size, wb_size + msg_size); -+ -+#if MALI_UNIT_TEST -+ atomic_add(msg_size, &tlstream_bytes_generated); -+#endif /* MALI_UNIT_TEST */ -+ -+ return &stream->buffer[wb_idx].data[wb_size]; -+} -+ -+/** -+ * kbasep_tlstream_msgbuf_release - unlock selected stream -+ * @stream_type: type of the stream that shall be locked -+ * @flags: value obtained during stream acquire -+ * -+ * Function releases stream that has been previously locked with a call to -+ * kbasep_tlstream_msgbuf_acquire(). -+ */ -+static void kbasep_tlstream_msgbuf_release( -+ enum tl_stream_type stream_type, -+ unsigned long flags) __releases(&stream->lock) -+{ -+ struct tl_stream *stream; -+ -+ KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type); -+ -+ stream = tl_stream[stream_type]; -+ -+ /* Mark stream as containing unflushed data. */ -+ atomic_set(&stream->autoflush_counter, 0); -+ -+ spin_unlock_irqrestore(&stream->lock, flags); -+} -+ -+/*****************************************************************************/ -+ -+/** -+ * kbasep_tlstream_flush_stream - flush stream -+ * @stype: type of stream to be flushed -+ * -+ * Flush pending data in timeline stream. -+ */ -+static void kbasep_tlstream_flush_stream(enum tl_stream_type stype) -+{ -+ struct tl_stream *stream = tl_stream[stype]; -+ unsigned long flags; -+ unsigned int wb_idx_raw; -+ unsigned int wb_idx; -+ size_t wb_size; -+ size_t min_size = PACKET_HEADER_SIZE; -+ -+ if (stream->numbered) -+ min_size += PACKET_NUMBER_SIZE; -+ -+ spin_lock_irqsave(&stream->lock, flags); -+ -+ wb_idx_raw = atomic_read(&stream->wbi); -+ wb_idx = wb_idx_raw % PACKET_COUNT; -+ wb_size = atomic_read(&stream->buffer[wb_idx].size); -+ -+ if (wb_size > min_size) { -+ wb_size = kbasep_tlstream_msgbuf_submit( -+ stream, wb_idx_raw, wb_size); -+ wb_idx = (wb_idx_raw + 1) % PACKET_COUNT; -+ atomic_set(&stream->buffer[wb_idx].size, wb_size); -+ } -+ spin_unlock_irqrestore(&stream->lock, flags); -+} -+ -+/** -+ * kbasep_tlstream_autoflush_timer_callback - autoflush timer callback -+ * @data: unused -+ * -+ * Timer is executed periodically to check if any of the stream contains -+ * buffer ready to be submitted to user space. -+ */ -+static void kbasep_tlstream_autoflush_timer_callback(unsigned long data) -+{ -+ enum tl_stream_type stype; -+ int rcode; -+ -+ CSTD_UNUSED(data); -+ -+ for (stype = 0; stype < TL_STREAM_TYPE_COUNT; stype++) { -+ struct tl_stream *stream = tl_stream[stype]; -+ unsigned long flags; -+ unsigned int wb_idx_raw; -+ unsigned int wb_idx; -+ size_t wb_size; -+ size_t min_size = PACKET_HEADER_SIZE; -+ -+ int af_cnt = atomic_read(&stream->autoflush_counter); -+ -+ /* Check if stream contain unflushed data. */ -+ if (0 > af_cnt) -+ continue; -+ -+ /* Check if stream should be flushed now. */ -+ if (af_cnt != atomic_cmpxchg( -+ &stream->autoflush_counter, -+ af_cnt, -+ af_cnt + 1)) -+ continue; -+ if (!af_cnt) -+ continue; -+ -+ /* Autoflush this stream. */ -+ if (stream->numbered) -+ min_size += PACKET_NUMBER_SIZE; -+ -+ spin_lock_irqsave(&stream->lock, flags); -+ -+ wb_idx_raw = atomic_read(&stream->wbi); -+ wb_idx = wb_idx_raw % PACKET_COUNT; -+ wb_size = atomic_read(&stream->buffer[wb_idx].size); -+ -+ if (wb_size > min_size) { -+ wb_size = kbasep_tlstream_msgbuf_submit( -+ stream, wb_idx_raw, wb_size); -+ wb_idx = (wb_idx_raw + 1) % PACKET_COUNT; -+ atomic_set(&stream->buffer[wb_idx].size, -+ wb_size); -+ } -+ spin_unlock_irqrestore(&stream->lock, flags); -+ } -+ -+ if (atomic_read(&autoflush_timer_active)) -+ rcode = mod_timer( -+ &autoflush_timer, -+ jiffies + msecs_to_jiffies(AUTOFLUSH_INTERVAL)); -+ CSTD_UNUSED(rcode); -+} -+ -+/** -+ * kbasep_tlstream_packet_pending - check timeline streams for pending packets -+ * @stype: pointer to variable where stream type will be placed -+ * @rb_idx_raw: pointer to variable where read buffer index will be placed -+ * -+ * Function checks all streams for pending packets. It will stop as soon as -+ * packet ready to be submitted to user space is detected. Variables under -+ * pointers, passed as the parameters to this function will be updated with -+ * values pointing to right stream and buffer. -+ * -+ * Return: non-zero if any of timeline streams has at last one packet ready -+ */ -+static int kbasep_tlstream_packet_pending( -+ enum tl_stream_type *stype, -+ unsigned int *rb_idx_raw) -+{ -+ int pending = 0; -+ -+ KBASE_DEBUG_ASSERT(stype); -+ KBASE_DEBUG_ASSERT(rb_idx_raw); -+ -+ for ( -+ *stype = 0; -+ (*stype < TL_STREAM_TYPE_COUNT) && !pending; -+ (*stype)++) { -+ if (NULL != tl_stream[*stype]) { -+ *rb_idx_raw = atomic_read(&tl_stream[*stype]->rbi); -+ /* Read buffer index may be updated by writer in case of -+ * overflow. Read and write buffer indexes must be -+ * loaded in correct order. */ -+ smp_rmb(); -+ if (atomic_read(&tl_stream[*stype]->wbi) != *rb_idx_raw) -+ pending = 1; -+ } -+ } -+ (*stype)--; -+ -+ return pending; -+} -+ -+/** -+ * kbasep_tlstream_read - copy data from streams to buffer provided by user -+ * @filp: pointer to file structure (unused) -+ * @buffer: pointer to the buffer provided by user -+ * @size: maximum amount of data that can be stored in the buffer -+ * @f_pos: pointer to file offset (unused) -+ * -+ * Return: number of bytes stored in the buffer -+ */ -+static ssize_t kbasep_tlstream_read( -+ struct file *filp, -+ char __user *buffer, -+ size_t size, -+ loff_t *f_pos) -+{ -+ ssize_t copy_len = 0; -+ -+ KBASE_DEBUG_ASSERT(filp); -+ KBASE_DEBUG_ASSERT(f_pos); -+ -+ if (!buffer) -+ return -EINVAL; -+ -+ if ((0 > *f_pos) || (PACKET_SIZE > size)) -+ return -EINVAL; -+ -+ mutex_lock(&tl_reader_lock); -+ -+ while (copy_len < size) { -+ enum tl_stream_type stype; -+ unsigned int rb_idx_raw = 0; -+ unsigned int rb_idx; -+ size_t rb_size; -+ -+ /* If we don't have any data yet, wait for packet to be -+ * submitted. If we already read some packets and there is no -+ * packet pending return back to user. */ -+ if (0 < copy_len) { -+ if (!kbasep_tlstream_packet_pending( -+ &stype, -+ &rb_idx_raw)) -+ break; -+ } else { -+ if (wait_event_interruptible( -+ tl_event_queue, -+ kbasep_tlstream_packet_pending( -+ &stype, -+ &rb_idx_raw))) { -+ copy_len = -ERESTARTSYS; -+ break; -+ } -+ } -+ -+ /* Check if this packet fits into the user buffer. -+ * If so copy its content. */ -+ rb_idx = rb_idx_raw % PACKET_COUNT; -+ rb_size = atomic_read(&tl_stream[stype]->buffer[rb_idx].size); -+ if (rb_size > size - copy_len) -+ break; -+ if (copy_to_user( -+ &buffer[copy_len], -+ tl_stream[stype]->buffer[rb_idx].data, -+ rb_size)) { -+ copy_len = -EFAULT; -+ break; -+ } -+ -+ /* If the rbi still points to the packet we just processed -+ * then there was no overflow so we add the copied size to -+ * copy_len and move rbi on to the next packet -+ */ -+ smp_rmb(); -+ if (atomic_read(&tl_stream[stype]->rbi) == rb_idx_raw) { -+ copy_len += rb_size; -+ atomic_inc(&tl_stream[stype]->rbi); -+ -+#if MALI_UNIT_TEST -+ atomic_add(rb_size, &tlstream_bytes_collected); -+#endif /* MALI_UNIT_TEST */ -+ } -+ } -+ -+ mutex_unlock(&tl_reader_lock); -+ -+ return copy_len; -+} -+ -+/** -+ * kbasep_tlstream_poll - poll timeline stream for packets -+ * @filp: pointer to file structure -+ * @wait: pointer to poll table -+ * Return: POLLIN if data can be read without blocking, otherwise zero -+ */ -+static unsigned int kbasep_tlstream_poll(struct file *filp, poll_table *wait) -+{ -+ enum tl_stream_type stream_type; -+ unsigned int rb_idx; -+ -+ KBASE_DEBUG_ASSERT(filp); -+ KBASE_DEBUG_ASSERT(wait); -+ -+ poll_wait(filp, &tl_event_queue, wait); -+ if (kbasep_tlstream_packet_pending(&stream_type, &rb_idx)) -+ return POLLIN; -+ return 0; -+} -+ -+/** -+ * kbasep_tlstream_release - release timeline stream descriptor -+ * @inode: pointer to inode structure -+ * @filp: pointer to file structure -+ * -+ * Return always return zero -+ */ -+static int kbasep_tlstream_release(struct inode *inode, struct file *filp) -+{ -+ KBASE_DEBUG_ASSERT(inode); -+ KBASE_DEBUG_ASSERT(filp); -+ CSTD_UNUSED(inode); -+ CSTD_UNUSED(filp); -+ -+ /* Stop autoflush timer before releasing access to streams. */ -+ atomic_set(&autoflush_timer_active, 0); -+ del_timer_sync(&autoflush_timer); -+ -+ atomic_set(&kbase_tlstream_enabled, 0); -+ return 0; -+} -+ -+/** -+ * kbasep_tlstream_timeline_header - prepare timeline header stream packet -+ * @stream_type: type of the stream that will carry header data -+ * @tp_desc: pointer to array with tracepoint descriptors -+ * @tp_count: number of descriptors in the given array -+ * -+ * Functions fills in information about tracepoints stored in body stream -+ * associated with this header stream. -+ */ -+static void kbasep_tlstream_timeline_header( -+ enum tl_stream_type stream_type, -+ const struct tp_desc *tp_desc, -+ u32 tp_count) -+{ -+ const u8 tv = SWTRACE_VERSION; /* protocol version */ -+ const u8 ps = sizeof(void *); /* pointer size */ -+ size_t msg_size = sizeof(tv) + sizeof(ps) + sizeof(tp_count); -+ char *buffer; -+ size_t pos = 0; -+ unsigned long flags; -+ unsigned int i; -+ -+ KBASE_DEBUG_ASSERT(TL_STREAM_TYPE_COUNT > stream_type); -+ KBASE_DEBUG_ASSERT(tp_desc); -+ -+ /* Calculate the size of the timeline message. */ -+ for (i = 0; i < tp_count; i++) { -+ msg_size += sizeof(tp_desc[i].id); -+ msg_size += -+ strnlen(tp_desc[i].id_str, STRLEN_MAX) + -+ sizeof(char) + sizeof(u32); -+ msg_size += -+ strnlen(tp_desc[i].name, STRLEN_MAX) + -+ sizeof(char) + sizeof(u32); -+ msg_size += -+ strnlen(tp_desc[i].arg_types, STRLEN_MAX) + -+ sizeof(char) + sizeof(u32); -+ msg_size += -+ strnlen(tp_desc[i].arg_names, STRLEN_MAX) + -+ sizeof(char) + sizeof(u32); -+ } -+ -+ KBASE_DEBUG_ASSERT(PACKET_SIZE - PACKET_HEADER_SIZE >= msg_size); -+ -+ buffer = kbasep_tlstream_msgbuf_acquire(stream_type, msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &tv, sizeof(tv)); -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &ps, sizeof(ps)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &tp_count, sizeof(tp_count)); -+ -+ for (i = 0; i < tp_count; i++) { -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, -+ &tp_desc[i].id, sizeof(tp_desc[i].id)); -+ pos = kbasep_tlstream_write_string( -+ buffer, pos, -+ tp_desc[i].id_str, msg_size - pos); -+ pos = kbasep_tlstream_write_string( -+ buffer, pos, -+ tp_desc[i].name, msg_size - pos); -+ pos = kbasep_tlstream_write_string( -+ buffer, pos, -+ tp_desc[i].arg_types, msg_size - pos); -+ pos = kbasep_tlstream_write_string( -+ buffer, pos, -+ tp_desc[i].arg_names, msg_size - pos); -+ } -+ -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(stream_type, flags); -+ -+ /* We don't expect any more data to be read in this stream. -+ * As header stream must be read before its associated body stream, -+ * make this packet visible to the user straightaway. */ -+ kbasep_tlstream_flush_stream(stream_type); -+} -+ -+/*****************************************************************************/ -+ -+int kbase_tlstream_init(void) -+{ -+ enum tl_stream_type i; -+ -+ /* Prepare stream structures. */ -+ for (i = 0; i < TL_STREAM_TYPE_COUNT; i++) { -+ tl_stream[i] = kmalloc(sizeof(**tl_stream), GFP_KERNEL); -+ if (!tl_stream[i]) -+ break; -+ kbasep_timeline_stream_init(tl_stream[i], i); -+ } -+ if (TL_STREAM_TYPE_COUNT > i) { -+ for (; i > 0; i--) { -+ kbasep_timeline_stream_term(tl_stream[i - 1]); -+ kfree(tl_stream[i - 1]); -+ } -+ return -ENOMEM; -+ } -+ -+ /* Initialize autoflush timer. */ -+ atomic_set(&autoflush_timer_active, 0); -+ setup_timer(&autoflush_timer, -+ kbasep_tlstream_autoflush_timer_callback, -+ 0); -+ -+ return 0; -+} -+ -+void kbase_tlstream_term(void) -+{ -+ enum tl_stream_type i; -+ -+ for (i = 0; i < TL_STREAM_TYPE_COUNT; i++) { -+ kbasep_timeline_stream_term(tl_stream[i]); -+ kfree(tl_stream[i]); -+ } -+} -+ -+static void kbase_create_timeline_objects(struct kbase_context *kctx) -+{ -+ struct kbase_device *kbdev = kctx->kbdev; -+ unsigned int lpu_id; -+ unsigned int as_nr; -+ struct kbasep_kctx_list_element *element; -+ -+ /* Create LPU objects. */ -+ for (lpu_id = 0; lpu_id < kbdev->gpu_props.num_job_slots; lpu_id++) { -+ u32 *lpu = -+ &kbdev->gpu_props.props.raw_props.js_features[lpu_id]; -+ KBASE_TLSTREAM_TL_SUMMARY_NEW_LPU(lpu, lpu_id, *lpu); -+ } -+ -+ /* Create Address Space objects. */ -+ for (as_nr = 0; as_nr < kbdev->nr_hw_address_spaces; as_nr++) -+ KBASE_TLSTREAM_TL_SUMMARY_NEW_AS(&kbdev->as[as_nr], as_nr); -+ -+ /* Create GPU object and make it retain all LPUs and address spaces. */ -+ KBASE_TLSTREAM_TL_SUMMARY_NEW_GPU( -+ kbdev, -+ kbdev->gpu_props.props.raw_props.gpu_id, -+ kbdev->gpu_props.num_cores); -+ -+ for (lpu_id = 0; lpu_id < kbdev->gpu_props.num_job_slots; lpu_id++) { -+ void *lpu = -+ &kbdev->gpu_props.props.raw_props.js_features[lpu_id]; -+ KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_LPU_GPU(lpu, kbdev); -+ } -+ for (as_nr = 0; as_nr < kbdev->nr_hw_address_spaces; as_nr++) -+ KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_AS_GPU( -+ &kbdev->as[as_nr], -+ kbdev); -+ -+ /* Create object for each known context. */ -+ mutex_lock(&kbdev->kctx_list_lock); -+ list_for_each_entry(element, &kbdev->kctx_list, link) { -+ KBASE_TLSTREAM_TL_SUMMARY_NEW_CTX( -+ element->kctx, -+ (u32)(element->kctx->id), -+ (u32)(element->kctx->tgid)); -+ } -+ /* Before releasing the lock, reset body stream buffers. -+ * This will prevent context creation message to be directed to both -+ * summary and body stream. -+ */ -+ kbase_tlstream_reset_body_streams(); -+ mutex_unlock(&kbdev->kctx_list_lock); -+ /* Static object are placed into summary packet that needs to be -+ * transmitted first. Flush all streams to make it available to -+ * user space. -+ */ -+ kbase_tlstream_flush_streams(); -+} -+ -+int kbase_tlstream_acquire(struct kbase_context *kctx, u32 flags) -+{ -+ int ret; -+ u32 tlstream_enabled = TLSTREAM_ENABLED | flags; -+ -+ if (0 == atomic_cmpxchg(&kbase_tlstream_enabled, 0, tlstream_enabled)) { -+ int rcode; -+ -+ ret = anon_inode_getfd( -+ "[mali_tlstream]", -+ &kbasep_tlstream_fops, -+ kctx, -+ O_RDONLY | O_CLOEXEC); -+ if (ret < 0) { -+ atomic_set(&kbase_tlstream_enabled, 0); -+ return ret; -+ } -+ -+ /* Reset and initialize header streams. */ -+ kbasep_timeline_stream_reset( -+ tl_stream[TL_STREAM_TYPE_OBJ_HEADER]); -+ kbasep_timeline_stream_reset( -+ tl_stream[TL_STREAM_TYPE_OBJ_SUMMARY]); -+ kbasep_timeline_stream_reset( -+ tl_stream[TL_STREAM_TYPE_AUX_HEADER]); -+ kbasep_tlstream_timeline_header( -+ TL_STREAM_TYPE_OBJ_HEADER, -+ tp_desc_obj, -+ ARRAY_SIZE(tp_desc_obj)); -+ kbasep_tlstream_timeline_header( -+ TL_STREAM_TYPE_AUX_HEADER, -+ tp_desc_aux, -+ ARRAY_SIZE(tp_desc_aux)); -+ -+ /* Start autoflush timer. */ -+ atomic_set(&autoflush_timer_active, 1); -+ rcode = mod_timer( -+ &autoflush_timer, -+ jiffies + msecs_to_jiffies(AUTOFLUSH_INTERVAL)); -+ CSTD_UNUSED(rcode); -+ -+ /* If job dumping is enabled, readjust the software event's -+ * timeout as the default value of 3 seconds is often -+ * insufficient. */ -+ if (flags & BASE_TLSTREAM_JOB_DUMPING_ENABLED) { -+ dev_info(kctx->kbdev->dev, -+ "Job dumping is enabled, readjusting the software event's timeout\n"); -+ atomic_set(&kctx->kbdev->js_data.soft_job_timeout_ms, -+ 1800000); -+ } -+ -+ /* Summary stream was cleared during acquire. -+ * Create static timeline objects that will be -+ * read by client. -+ */ -+ kbase_create_timeline_objects(kctx); -+ -+ } else { -+ ret = -EBUSY; -+ } -+ -+ return ret; -+} -+ -+void kbase_tlstream_flush_streams(void) -+{ -+ enum tl_stream_type stype; -+ -+ for (stype = 0; stype < TL_STREAM_TYPE_COUNT; stype++) -+ kbasep_tlstream_flush_stream(stype); -+} -+ -+void kbase_tlstream_reset_body_streams(void) -+{ -+ kbasep_timeline_stream_reset( -+ tl_stream[TL_STREAM_TYPE_OBJ]); -+ kbasep_timeline_stream_reset( -+ tl_stream[TL_STREAM_TYPE_AUX]); -+} -+ -+#if MALI_UNIT_TEST -+void kbase_tlstream_stats(u32 *bytes_collected, u32 *bytes_generated) -+{ -+ KBASE_DEBUG_ASSERT(bytes_collected); -+ KBASE_DEBUG_ASSERT(bytes_generated); -+ *bytes_collected = atomic_read(&tlstream_bytes_collected); -+ *bytes_generated = atomic_read(&tlstream_bytes_generated); -+} -+#endif /* MALI_UNIT_TEST */ -+ -+/*****************************************************************************/ -+ -+void __kbase_tlstream_tl_summary_new_ctx(void *context, u32 nr, u32 tgid) -+{ -+ const u32 msg_id = KBASE_TL_NEW_CTX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(nr) + -+ sizeof(tgid); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ_SUMMARY, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &context, sizeof(context)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &nr, sizeof(nr)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &tgid, sizeof(tgid)); -+ -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags); -+} -+ -+void __kbase_tlstream_tl_summary_new_gpu(void *gpu, u32 id, u32 core_count) -+{ -+ const u32 msg_id = KBASE_TL_NEW_GPU; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(gpu) + sizeof(id) + -+ sizeof(core_count); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ_SUMMARY, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &id, sizeof(id)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &core_count, sizeof(core_count)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags); -+} -+ -+void __kbase_tlstream_tl_summary_new_lpu(void *lpu, u32 nr, u32 fn) -+{ -+ const u32 msg_id = KBASE_TL_NEW_LPU; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(lpu) + sizeof(nr) + -+ sizeof(fn); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ_SUMMARY, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &lpu, sizeof(lpu)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &nr, sizeof(nr)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &fn, sizeof(fn)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags); -+} -+ -+void __kbase_tlstream_tl_summary_lifelink_lpu_gpu(void *lpu, void *gpu) -+{ -+ const u32 msg_id = KBASE_TL_LIFELINK_LPU_GPU; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(lpu) + sizeof(gpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ_SUMMARY, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &lpu, sizeof(lpu)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags); -+} -+ -+void __kbase_tlstream_tl_summary_new_as(void *as, u32 nr) -+{ -+ const u32 msg_id = KBASE_TL_NEW_AS; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(nr); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ_SUMMARY, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &as, sizeof(as)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &nr, sizeof(nr)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags); -+} -+ -+void __kbase_tlstream_tl_summary_lifelink_as_gpu(void *as, void *gpu) -+{ -+ const u32 msg_id = KBASE_TL_LIFELINK_AS_GPU; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(gpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ_SUMMARY, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &as, sizeof(as)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ_SUMMARY, flags); -+} -+ -+/*****************************************************************************/ -+ -+void __kbase_tlstream_tl_new_ctx(void *context, u32 nr, u32 tgid) -+{ -+ const u32 msg_id = KBASE_TL_NEW_CTX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(nr) + -+ sizeof(tgid); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &context, sizeof(context)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &nr, sizeof(nr)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &tgid, sizeof(tgid)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_new_atom(void *atom, u32 nr) -+{ -+ const u32 msg_id = KBASE_TL_NEW_ATOM; -+ const size_t msg_size = sizeof(msg_id) + sizeof(u64) + sizeof(atom) + -+ sizeof(nr); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &nr, sizeof(nr)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_del_ctx(void *context) -+{ -+ const u32 msg_id = KBASE_TL_DEL_CTX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(context); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &context, sizeof(context)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_del_atom(void *atom) -+{ -+ const u32 msg_id = KBASE_TL_DEL_ATOM; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_ret_ctx_lpu(void *context, void *lpu) -+{ -+ const u32 msg_id = KBASE_TL_RET_CTX_LPU; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(lpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &context, sizeof(context)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &lpu, sizeof(lpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_ret_atom_ctx(void *atom, void *context) -+{ -+ const u32 msg_id = KBASE_TL_RET_ATOM_CTX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(context); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &context, sizeof(context)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_ret_atom_lpu( -+ void *atom, void *lpu, const char *attrib_match_list) -+{ -+ const u32 msg_id = KBASE_TL_RET_ATOM_LPU; -+ const size_t msg_s0 = sizeof(u32) + sizeof(char) + -+ strnlen(attrib_match_list, STRLEN_MAX); -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + -+ sizeof(atom) + sizeof(lpu) + msg_s0; -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &lpu, sizeof(lpu)); -+ pos = kbasep_tlstream_write_string( -+ buffer, pos, attrib_match_list, msg_s0); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_nret_ctx_lpu(void *context, void *lpu) -+{ -+ const u32 msg_id = KBASE_TL_NRET_CTX_LPU; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(context) + sizeof(lpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &context, sizeof(context)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &lpu, sizeof(lpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_nret_atom_ctx(void *atom, void *context) -+{ -+ const u32 msg_id = KBASE_TL_NRET_ATOM_CTX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(context); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &context, sizeof(context)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_dep_atom_atom(void *atom1, void *atom2) -+{ -+ const u32 msg_id = KBASE_TL_DEP_ATOM_ATOM; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom1, sizeof(atom1)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom2, sizeof(atom2)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_ndep_atom_atom(void *atom1, void *atom2) -+{ -+ const u32 msg_id = KBASE_TL_NDEP_ATOM_ATOM; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom1, sizeof(atom1)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom2, sizeof(atom2)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_rdep_atom_atom(void *atom1, void *atom2) -+{ -+ const u32 msg_id = KBASE_TL_RDEP_ATOM_ATOM; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom1, sizeof(atom1)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom2, sizeof(atom2)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_nret_atom_lpu(void *atom, void *lpu) -+{ -+ const u32 msg_id = KBASE_TL_NRET_ATOM_LPU; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(lpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &lpu, sizeof(lpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_ret_as_ctx(void *as, void *ctx) -+{ -+ const u32 msg_id = KBASE_TL_RET_AS_CTX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(ctx); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &as, sizeof(as)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &ctx, sizeof(ctx)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_nret_as_ctx(void *as, void *ctx) -+{ -+ const u32 msg_id = KBASE_TL_NRET_AS_CTX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(as) + sizeof(ctx); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &as, sizeof(as)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &ctx, sizeof(ctx)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_ret_atom_as(void *atom, void *as) -+{ -+ const u32 msg_id = KBASE_TL_RET_ATOM_AS; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(as); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &as, sizeof(as)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_nret_atom_as(void *atom, void *as) -+{ -+ const u32 msg_id = KBASE_TL_NRET_ATOM_AS; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(as); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &as, sizeof(as)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_attrib_atom_config( -+ void *atom, u64 jd, u64 affinity, u32 config) -+{ -+ const u32 msg_id = KBASE_TL_ATTRIB_ATOM_CONFIG; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + -+ sizeof(jd) + sizeof(affinity) + sizeof(config); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &jd, sizeof(jd)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &affinity, sizeof(affinity)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &config, sizeof(config)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_attrib_atom_priority(void *atom, u32 prio) -+{ -+ const u32 msg_id = KBASE_TL_ATTRIB_ATOM_PRIORITY; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(prio); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &prio, sizeof(prio)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_attrib_atom_state(void *atom, u32 state) -+{ -+ const u32 msg_id = KBASE_TL_ATTRIB_ATOM_STATE; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) + sizeof(state); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &state, sizeof(state)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_attrib_atom_priority_change(void *atom) -+{ -+ const u32 msg_id = KBASE_TL_ATTRIB_ATOM_PRIORITY_CHANGE; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_attrib_atom_jit( -+ void *atom, u64 edit_addr, u64 new_addr) -+{ -+ const u32 msg_id = KBASE_TL_ATTRIB_ATOM_JIT; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom) -+ + sizeof(edit_addr) + sizeof(new_addr); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &edit_addr, sizeof(edit_addr)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &new_addr, sizeof(new_addr)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_attrib_as_config( -+ void *as, u64 transtab, u64 memattr, u64 transcfg) -+{ -+ const u32 msg_id = KBASE_TL_ATTRIB_AS_CONFIG; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(as) + -+ sizeof(transtab) + sizeof(memattr) + sizeof(transcfg); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &as, sizeof(as)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &transtab, sizeof(transtab)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &memattr, sizeof(memattr)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &transcfg, sizeof(transcfg)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_event_lpu_softstop(void *lpu) -+{ -+ const u32 msg_id = KBASE_TL_EVENT_LPU_SOFTSTOP; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(lpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &lpu, sizeof(lpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_event_atom_softstop_ex(void *atom) -+{ -+ const u32 msg_id = KBASE_TL_EVENT_ATOM_SOFTSTOP_EX; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_tl_event_atom_softstop_issue(void *atom) -+{ -+ const u32 msg_id = KBASE_TL_EVENT_ATOM_SOFTSTOP_ISSUE; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(atom); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &atom, sizeof(atom)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+void __kbase_tlstream_jd_gpu_soft_reset(void *gpu) -+{ -+ const u32 msg_id = KBASE_JD_GPU_SOFT_RESET; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(gpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_OBJ, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags); -+} -+ -+/*****************************************************************************/ -+ -+void __kbase_tlstream_aux_pm_state(u32 core_type, u64 state) -+{ -+ const u32 msg_id = KBASE_AUX_PM_STATE; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(core_type) + -+ sizeof(state); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &core_type, sizeof(core_type)); -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &state, sizeof(state)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -+ -+void __kbase_tlstream_aux_pagefault(u32 ctx_nr, u64 page_count_change) -+{ -+ const u32 msg_id = KBASE_AUX_PAGEFAULT; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(ctx_nr) + -+ sizeof(page_count_change); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &ctx_nr, sizeof(ctx_nr)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, -+ &page_count_change, sizeof(page_count_change)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -+ -+void __kbase_tlstream_aux_pagesalloc(u32 ctx_nr, u64 page_count) -+{ -+ const u32 msg_id = KBASE_AUX_PAGESALLOC; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(ctx_nr) + -+ sizeof(page_count); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &ctx_nr, sizeof(ctx_nr)); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &page_count, sizeof(page_count)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -+ -+void __kbase_tlstream_aux_devfreq_target(u64 target_freq) -+{ -+ const u32 msg_id = KBASE_AUX_DEVFREQ_TARGET; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(target_freq); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &target_freq, sizeof(target_freq)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -+ -+void __kbase_tlstream_aux_protected_enter_start(void *gpu) -+{ -+ const u32 msg_id = KBASE_AUX_PROTECTED_ENTER_START; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(gpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -+void __kbase_tlstream_aux_protected_enter_end(void *gpu) -+{ -+ const u32 msg_id = KBASE_AUX_PROTECTED_ENTER_END; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(gpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -+ -+void __kbase_tlstream_aux_protected_leave_start(void *gpu) -+{ -+ const u32 msg_id = KBASE_AUX_PROTECTED_LEAVE_START; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(gpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -+void __kbase_tlstream_aux_protected_leave_end(void *gpu) -+{ -+ const u32 msg_id = KBASE_AUX_PROTECTED_LEAVE_END; -+ const size_t msg_size = -+ sizeof(msg_id) + sizeof(u64) + sizeof(gpu); -+ unsigned long flags; -+ char *buffer; -+ size_t pos = 0; -+ -+ buffer = kbasep_tlstream_msgbuf_acquire( -+ TL_STREAM_TYPE_AUX, -+ msg_size, &flags); -+ KBASE_DEBUG_ASSERT(buffer); -+ -+ pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id)); -+ pos = kbasep_tlstream_write_timestamp(buffer, pos); -+ pos = kbasep_tlstream_write_bytes( -+ buffer, pos, &gpu, sizeof(gpu)); -+ KBASE_DEBUG_ASSERT(msg_size == pos); -+ -+ kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_AUX, flags); -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_tlstream.h b/drivers/gpu/arm/midgard/mali_kbase_tlstream.h -new file mode 100644 -index 0000000..c0a1117 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_tlstream.h -@@ -0,0 +1,623 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#if !defined(_KBASE_TLSTREAM_H) -+#define _KBASE_TLSTREAM_H -+ -+#include -+ -+/*****************************************************************************/ -+ -+/** -+ * kbase_tlstream_init - initialize timeline infrastructure in kernel -+ * Return: zero on success, negative number on error -+ */ -+int kbase_tlstream_init(void); -+ -+/** -+ * kbase_tlstream_term - terminate timeline infrastructure in kernel -+ * -+ * Timeline need have to been previously enabled with kbase_tlstream_init(). -+ */ -+void kbase_tlstream_term(void); -+ -+/** -+ * kbase_tlstream_acquire - acquire timeline stream file descriptor -+ * @kctx: kernel common context -+ * @flags: timeline stream flags -+ * -+ * This descriptor is meant to be used by userspace timeline to gain access to -+ * kernel timeline stream. This stream is later broadcasted by user space to the -+ * timeline client. -+ * Only one entity can own the descriptor at any given time. Descriptor shall be -+ * closed if unused. If descriptor cannot be obtained (i.e. when it is already -+ * being used) return will be a negative value. -+ * -+ * Return: file descriptor on success, negative number on error -+ */ -+int kbase_tlstream_acquire(struct kbase_context *kctx, u32 flags); -+ -+/** -+ * kbase_tlstream_flush_streams - flush timeline streams. -+ * -+ * Function will flush pending data in all timeline streams. -+ */ -+void kbase_tlstream_flush_streams(void); -+ -+/** -+ * kbase_tlstream_reset_body_streams - reset timeline body streams. -+ * -+ * Function will discard pending data in all timeline body streams. -+ */ -+void kbase_tlstream_reset_body_streams(void); -+ -+#if MALI_UNIT_TEST -+/** -+ * kbase_tlstream_test - start timeline stream data generator -+ * @tpw_count: number of trace point writers in each context -+ * @msg_delay: time delay in milliseconds between trace points written by one -+ * writer -+ * @msg_count: number of trace points written by one writer -+ * @aux_msg: if non-zero aux messages will be included -+ * -+ * This test starts a requested number of asynchronous writers in both IRQ and -+ * thread context. Each writer will generate required number of test -+ * tracepoints (tracepoints with embedded information about writer that -+ * should be verified by user space reader). Tracepoints will be emitted in -+ * all timeline body streams. If aux_msg is non-zero writer will also -+ * generate not testable tracepoints (tracepoints without information about -+ * writer). These tracepoints are used to check correctness of remaining -+ * timeline message generating functions. Writer will wait requested time -+ * between generating another set of messages. This call blocks until all -+ * writers finish. -+ */ -+void kbase_tlstream_test( -+ unsigned int tpw_count, -+ unsigned int msg_delay, -+ unsigned int msg_count, -+ int aux_msg); -+ -+/** -+ * kbase_tlstream_stats - read timeline stream statistics -+ * @bytes_collected: will hold number of bytes read by the user -+ * @bytes_generated: will hold number of bytes generated by trace points -+ */ -+void kbase_tlstream_stats(u32 *bytes_collected, u32 *bytes_generated); -+#endif /* MALI_UNIT_TEST */ -+ -+/*****************************************************************************/ -+ -+#define TL_ATOM_STATE_IDLE 0 -+#define TL_ATOM_STATE_READY 1 -+#define TL_ATOM_STATE_DONE 2 -+#define TL_ATOM_STATE_POSTED 3 -+ -+void __kbase_tlstream_tl_summary_new_ctx(void *context, u32 nr, u32 tgid); -+void __kbase_tlstream_tl_summary_new_gpu(void *gpu, u32 id, u32 core_count); -+void __kbase_tlstream_tl_summary_new_lpu(void *lpu, u32 nr, u32 fn); -+void __kbase_tlstream_tl_summary_lifelink_lpu_gpu(void *lpu, void *gpu); -+void __kbase_tlstream_tl_summary_new_as(void *as, u32 nr); -+void __kbase_tlstream_tl_summary_lifelink_as_gpu(void *as, void *gpu); -+void __kbase_tlstream_tl_new_ctx(void *context, u32 nr, u32 tgid); -+void __kbase_tlstream_tl_new_atom(void *atom, u32 nr); -+void __kbase_tlstream_tl_del_ctx(void *context); -+void __kbase_tlstream_tl_del_atom(void *atom); -+void __kbase_tlstream_tl_ret_ctx_lpu(void *context, void *lpu); -+void __kbase_tlstream_tl_ret_atom_ctx(void *atom, void *context); -+void __kbase_tlstream_tl_ret_atom_lpu( -+ void *atom, void *lpu, const char *attrib_match_list); -+void __kbase_tlstream_tl_nret_ctx_lpu(void *context, void *lpu); -+void __kbase_tlstream_tl_nret_atom_ctx(void *atom, void *context); -+void __kbase_tlstream_tl_nret_atom_lpu(void *atom, void *lpu); -+void __kbase_tlstream_tl_ret_as_ctx(void *as, void *ctx); -+void __kbase_tlstream_tl_nret_as_ctx(void *as, void *ctx); -+void __kbase_tlstream_tl_ret_atom_as(void *atom, void *as); -+void __kbase_tlstream_tl_nret_atom_as(void *atom, void *as); -+void __kbase_tlstream_tl_dep_atom_atom(void *atom1, void *atom2); -+void __kbase_tlstream_tl_ndep_atom_atom(void *atom1, void *atom2); -+void __kbase_tlstream_tl_rdep_atom_atom(void *atom1, void *atom2); -+void __kbase_tlstream_tl_attrib_atom_config( -+ void *atom, u64 jd, u64 affinity, u32 config); -+void __kbase_tlstream_tl_attrib_atom_priority(void *atom, u32 prio); -+void __kbase_tlstream_tl_attrib_atom_state(void *atom, u32 state); -+void __kbase_tlstream_tl_attrib_atom_priority_change(void *atom); -+void __kbase_tlstream_tl_attrib_atom_jit( -+ void *atom, u64 edit_addr, u64 new_addr); -+void __kbase_tlstream_tl_attrib_as_config( -+ void *as, u64 transtab, u64 memattr, u64 transcfg); -+void __kbase_tlstream_tl_event_atom_softstop_ex(void *atom); -+void __kbase_tlstream_tl_event_lpu_softstop(void *lpu); -+void __kbase_tlstream_tl_event_atom_softstop_issue(void *atom); -+void __kbase_tlstream_jd_gpu_soft_reset(void *gpu); -+void __kbase_tlstream_aux_pm_state(u32 core_type, u64 state); -+void __kbase_tlstream_aux_pagefault(u32 ctx_nr, u64 page_count_change); -+void __kbase_tlstream_aux_pagesalloc(u32 ctx_nr, u64 page_count); -+void __kbase_tlstream_aux_devfreq_target(u64 target_freq); -+void __kbase_tlstream_aux_protected_enter_start(void *gpu); -+void __kbase_tlstream_aux_protected_enter_end(void *gpu); -+void __kbase_tlstream_aux_protected_leave_start(void *gpu); -+void __kbase_tlstream_aux_protected_leave_end(void *gpu); -+ -+#define TLSTREAM_ENABLED (1 << 31) -+ -+extern atomic_t kbase_tlstream_enabled; -+ -+#define __TRACE_IF_ENABLED(trace_name, ...) \ -+ do { \ -+ int enabled = atomic_read(&kbase_tlstream_enabled); \ -+ if (enabled & TLSTREAM_ENABLED) \ -+ __kbase_tlstream_##trace_name(__VA_ARGS__); \ -+ } while (0) -+ -+#define __TRACE_IF_ENABLED_LATENCY(trace_name, ...) \ -+ do { \ -+ int enabled = atomic_read(&kbase_tlstream_enabled); \ -+ if (enabled & BASE_TLSTREAM_ENABLE_LATENCY_TRACEPOINTS) \ -+ __kbase_tlstream_##trace_name(__VA_ARGS__); \ -+ } while (0) -+ -+#define __TRACE_IF_ENABLED_JD(trace_name, ...) \ -+ do { \ -+ int enabled = atomic_read(&kbase_tlstream_enabled); \ -+ if (enabled & BASE_TLSTREAM_JOB_DUMPING_ENABLED) \ -+ __kbase_tlstream_##trace_name(__VA_ARGS__); \ -+ } while (0) -+ -+/*****************************************************************************/ -+ -+/** -+ * KBASE_TLSTREAM_TL_SUMMARY_NEW_CTX - create context object in timeline -+ * summary -+ * @context: name of the context object -+ * @nr: context number -+ * @tgid: thread Group Id -+ * -+ * Function emits a timeline message informing about context creation. Context -+ * is created with context number (its attribute), that can be used to link -+ * kbase context with userspace context. -+ * This message is directed to timeline summary stream. -+ */ -+#define KBASE_TLSTREAM_TL_SUMMARY_NEW_CTX(context, nr, tgid) \ -+ __TRACE_IF_ENABLED(tl_summary_new_ctx, context, nr, tgid) -+ -+/** -+ * KBASE_TLSTREAM_TL_SUMMARY_NEW_GPU - create GPU object in timeline summary -+ * @gpu: name of the GPU object -+ * @id: id value of this GPU -+ * @core_count: number of cores this GPU hosts -+ * -+ * Function emits a timeline message informing about GPU creation. GPU is -+ * created with two attributes: id and core count. -+ * This message is directed to timeline summary stream. -+ */ -+#define KBASE_TLSTREAM_TL_SUMMARY_NEW_GPU(gpu, id, core_count) \ -+ __TRACE_IF_ENABLED(tl_summary_new_gpu, gpu, id, core_count) -+ -+/** -+ * KBASE_TLSTREAM_TL_SUMMARY_NEW_LPU - create LPU object in timeline summary -+ * @lpu: name of the Logical Processing Unit object -+ * @nr: sequential number assigned to this LPU -+ * @fn: property describing this LPU's functional abilities -+ * -+ * Function emits a timeline message informing about LPU creation. LPU is -+ * created with two attributes: number linking this LPU with GPU's job slot -+ * and function bearing information about this LPU abilities. -+ * This message is directed to timeline summary stream. -+ */ -+#define KBASE_TLSTREAM_TL_SUMMARY_NEW_LPU(lpu, nr, fn) \ -+ __TRACE_IF_ENABLED(tl_summary_new_lpu, lpu, nr, fn) -+ -+/** -+ * KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_LPU_GPU - lifelink LPU object to GPU -+ * @lpu: name of the Logical Processing Unit object -+ * @gpu: name of the GPU object -+ * -+ * Function emits a timeline message informing that LPU object shall be deleted -+ * along with GPU object. -+ * This message is directed to timeline summary stream. -+ */ -+#define KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_LPU_GPU(lpu, gpu) \ -+ __TRACE_IF_ENABLED(tl_summary_lifelink_lpu_gpu, lpu, gpu) -+ -+/** -+ * KBASE_TLSTREAM_TL_SUMMARY_NEW_AS - create address space object in timeline summary -+ * @as: name of the address space object -+ * @nr: sequential number assigned to this address space -+ * -+ * Function emits a timeline message informing about address space creation. -+ * Address space is created with one attribute: number identifying this -+ * address space. -+ * This message is directed to timeline summary stream. -+ */ -+#define KBASE_TLSTREAM_TL_SUMMARY_NEW_AS(as, nr) \ -+ __TRACE_IF_ENABLED(tl_summary_new_as, as, nr) -+ -+/** -+ * KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_AS_GPU - lifelink address space object to GPU -+ * @as: name of the address space object -+ * @gpu: name of the GPU object -+ * -+ * Function emits a timeline message informing that address space object -+ * shall be deleted along with GPU object. -+ * This message is directed to timeline summary stream. -+ */ -+#define KBASE_TLSTREAM_TL_SUMMARY_LIFELINK_AS_GPU(as, gpu) \ -+ __TRACE_IF_ENABLED(tl_summary_lifelink_as_gpu, as, gpu) -+ -+/** -+ * KBASE_TLSTREAM_TL_NEW_CTX - create context object in timeline -+ * @context: name of the context object -+ * @nr: context number -+ * @tgid: thread Group Id -+ * -+ * Function emits a timeline message informing about context creation. Context -+ * is created with context number (its attribute), that can be used to link -+ * kbase context with userspace context. -+ */ -+#define KBASE_TLSTREAM_TL_NEW_CTX(context, nr, tgid) \ -+ __TRACE_IF_ENABLED(tl_new_ctx, context, nr, tgid) -+ -+/** -+ * KBASE_TLSTREAM_TL_NEW_ATOM - create atom object in timeline -+ * @atom: name of the atom object -+ * @nr: sequential number assigned to this atom -+ * -+ * Function emits a timeline message informing about atom creation. Atom is -+ * created with atom number (its attribute) that links it with actual work -+ * bucket id understood by hardware. -+ */ -+#define KBASE_TLSTREAM_TL_NEW_ATOM(atom, nr) \ -+ __TRACE_IF_ENABLED(tl_new_atom, atom, nr) -+ -+/** -+ * KBASE_TLSTREAM_TL_DEL_CTX - destroy context object in timeline -+ * @context: name of the context object -+ * -+ * Function emits a timeline message informing that context object ceased to -+ * exist. -+ */ -+#define KBASE_TLSTREAM_TL_DEL_CTX(context) \ -+ __TRACE_IF_ENABLED(tl_del_ctx, context) -+ -+/** -+ * KBASE_TLSTREAM_TL_DEL_ATOM - destroy atom object in timeline -+ * @atom: name of the atom object -+ * -+ * Function emits a timeline message informing that atom object ceased to -+ * exist. -+ */ -+#define KBASE_TLSTREAM_TL_DEL_ATOM(atom) \ -+ __TRACE_IF_ENABLED(tl_del_atom, atom) -+ -+/** -+ * KBASE_TLSTREAM_TL_RET_CTX_LPU - retain context by LPU -+ * @context: name of the context object -+ * @lpu: name of the Logical Processing Unit object -+ * -+ * Function emits a timeline message informing that context is being held -+ * by LPU and must not be deleted unless it is released. -+ */ -+#define KBASE_TLSTREAM_TL_RET_CTX_LPU(context, lpu) \ -+ __TRACE_IF_ENABLED(tl_ret_ctx_lpu, context, lpu) -+ -+/** -+ * KBASE_TLSTREAM_TL_RET_ATOM_CTX - retain atom by context -+ * @atom: name of the atom object -+ * @context: name of the context object -+ * -+ * Function emits a timeline message informing that atom object is being held -+ * by context and must not be deleted unless it is released. -+ */ -+#define KBASE_TLSTREAM_TL_RET_ATOM_CTX(atom, context) \ -+ __TRACE_IF_ENABLED(tl_ret_atom_ctx, atom, context) -+ -+/** -+ * KBASE_TLSTREAM_TL_RET_ATOM_LPU - retain atom by LPU -+ * @atom: name of the atom object -+ * @lpu: name of the Logical Processing Unit object -+ * @attrib_match_list: list containing match operator attributes -+ * -+ * Function emits a timeline message informing that atom object is being held -+ * by LPU and must not be deleted unless it is released. -+ */ -+#define KBASE_TLSTREAM_TL_RET_ATOM_LPU(atom, lpu, attrib_match_list) \ -+ __TRACE_IF_ENABLED(tl_ret_atom_lpu, atom, lpu, attrib_match_list) -+ -+/** -+ * KBASE_TLSTREAM_TL_NRET_CTX_LPU - release context by LPU -+ * @context: name of the context object -+ * @lpu: name of the Logical Processing Unit object -+ * -+ * Function emits a timeline message informing that context is being released -+ * by LPU object. -+ */ -+#define KBASE_TLSTREAM_TL_NRET_CTX_LPU(context, lpu) \ -+ __TRACE_IF_ENABLED(tl_nret_ctx_lpu, context, lpu) -+ -+/** -+ * KBASE_TLSTREAM_TL_NRET_ATOM_CTX - release atom by context -+ * @atom: name of the atom object -+ * @context: name of the context object -+ * -+ * Function emits a timeline message informing that atom object is being -+ * released by context. -+ */ -+#define KBASE_TLSTREAM_TL_NRET_ATOM_CTX(atom, context) \ -+ __TRACE_IF_ENABLED(tl_nret_atom_ctx, atom, context) -+ -+/** -+ * KBASE_TLSTREAM_TL_NRET_ATOM_LPU - release atom by LPU -+ * @atom: name of the atom object -+ * @lpu: name of the Logical Processing Unit object -+ * -+ * Function emits a timeline message informing that atom object is being -+ * released by LPU. -+ */ -+#define KBASE_TLSTREAM_TL_NRET_ATOM_LPU(atom, lpu) \ -+ __TRACE_IF_ENABLED(tl_nret_atom_lpu, atom, lpu) -+ -+/** -+ * KBASE_TLSTREAM_TL_RET_AS_CTX - lifelink address space object to context -+ * @as: name of the address space object -+ * @ctx: name of the context object -+ * -+ * Function emits a timeline message informing that address space object -+ * is being held by the context object. -+ */ -+#define KBASE_TLSTREAM_TL_RET_AS_CTX(as, ctx) \ -+ __TRACE_IF_ENABLED(tl_ret_as_ctx, as, ctx) -+ -+/** -+ * KBASE_TLSTREAM_TL_NRET_AS_CTX - release address space by context -+ * @as: name of the address space object -+ * @ctx: name of the context object -+ * -+ * Function emits a timeline message informing that address space object -+ * is being released by atom. -+ */ -+#define KBASE_TLSTREAM_TL_NRET_AS_CTX(as, ctx) \ -+ __TRACE_IF_ENABLED(tl_nret_as_ctx, as, ctx) -+ -+/** -+ * KBASE_TLSTREAM_TL_RET_ATOM_AS - retain atom by address space -+ * @atom: name of the atom object -+ * @as: name of the address space object -+ * -+ * Function emits a timeline message informing that atom object is being held -+ * by address space and must not be deleted unless it is released. -+ */ -+#define KBASE_TLSTREAM_TL_RET_ATOM_AS(atom, as) \ -+ __TRACE_IF_ENABLED(tl_ret_atom_as, atom, as) -+ -+/** -+ * KBASE_TLSTREAM_TL_NRET_ATOM_AS - release atom by address space -+ * @atom: name of the atom object -+ * @as: name of the address space object -+ * -+ * Function emits a timeline message informing that atom object is being -+ * released by address space. -+ */ -+#define KBASE_TLSTREAM_TL_NRET_ATOM_AS(atom, as) \ -+ __TRACE_IF_ENABLED(tl_nret_atom_as, atom, as) -+ -+/** -+ * KBASE_TLSTREAM_TL_DEP_ATOM_ATOM - parent atom depends on child atom -+ * @atom1: name of the child atom object -+ * @atom2: name of the parent atom object that depends on child atom -+ * -+ * Function emits a timeline message informing that parent atom waits for -+ * child atom object to be completed before start its execution. -+ */ -+#define KBASE_TLSTREAM_TL_DEP_ATOM_ATOM(atom1, atom2) \ -+ __TRACE_IF_ENABLED(tl_dep_atom_atom, atom1, atom2) -+ -+/** -+ * KBASE_TLSTREAM_TL_NDEP_ATOM_ATOM - dependency between atoms resolved -+ * @atom1: name of the child atom object -+ * @atom2: name of the parent atom object that depended on child atom -+ * -+ * Function emits a timeline message informing that parent atom execution -+ * dependency on child atom has been resolved. -+ */ -+#define KBASE_TLSTREAM_TL_NDEP_ATOM_ATOM(atom1, atom2) \ -+ __TRACE_IF_ENABLED(tl_ndep_atom_atom, atom1, atom2) -+ -+/** -+ * KBASE_TLSTREAM_TL_RDEP_ATOM_ATOM - information about already resolved dependency between atoms -+ * @atom1: name of the child atom object -+ * @atom2: name of the parent atom object that depended on child atom -+ * -+ * Function emits a timeline message informing that parent atom execution -+ * dependency on child atom has been resolved. -+ */ -+#define KBASE_TLSTREAM_TL_RDEP_ATOM_ATOM(atom1, atom2) \ -+ __TRACE_IF_ENABLED(tl_rdep_atom_atom, atom1, atom2) -+ -+/** -+ * KBASE_TLSTREAM_TL_ATTRIB_ATOM_CONFIG - atom job slot attributes -+ * @atom: name of the atom object -+ * @jd: job descriptor address -+ * @affinity: job affinity -+ * @config: job config -+ * -+ * Function emits a timeline message containing atom attributes. -+ */ -+#define KBASE_TLSTREAM_TL_ATTRIB_ATOM_CONFIG(atom, jd, affinity, config) \ -+ __TRACE_IF_ENABLED(tl_attrib_atom_config, atom, jd, affinity, config) -+ -+/** -+ * KBASE_TLSTREAM_TL_ATTRIB_ATOM_PRIORITY - atom priority -+ * @atom: name of the atom object -+ * @prio: atom priority -+ * -+ * Function emits a timeline message containing atom priority. -+ */ -+#define KBASE_TLSTREAM_TL_ATTRIB_ATOM_PRIORITY(atom, prio) \ -+ __TRACE_IF_ENABLED_LATENCY(tl_attrib_atom_priority, atom, prio) -+ -+/** -+ * KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE - atom state -+ * @atom: name of the atom object -+ * @state: atom state -+ * -+ * Function emits a timeline message containing atom state. -+ */ -+#define KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(atom, state) \ -+ __TRACE_IF_ENABLED_LATENCY(tl_attrib_atom_state, atom, state) -+ -+/** -+ * KBASE_TLSTREAM_TL_ATTRIB_ATOM_PRIORITY_CHANGE - atom caused priority change -+ * @atom: name of the atom object -+ * -+ * Function emits a timeline message signalling priority change -+ */ -+#define KBASE_TLSTREAM_TL_ATTRIB_ATOM_PRIORITY_CHANGE(atom) \ -+ __TRACE_IF_ENABLED_LATENCY(tl_attrib_atom_priority_change, atom) -+ -+/** -+ * KBASE_TLSTREAM_TL_ATTRIB_ATOM_JIT - jit happened on atom -+ * @atom: atom identifier -+ * @edit_addr: address edited by jit -+ * @new_addr: address placed into the edited location -+ */ -+#define KBASE_TLSTREAM_TL_ATTRIB_ATOM_JIT(atom, edit_addr, new_addr) \ -+ __TRACE_IF_ENABLED_JD(tl_attrib_atom_jit, atom, edit_addr, new_addr) -+ -+/** -+ * KBASE_TLSTREAM_TL_ATTRIB_AS_CONFIG - address space attributes -+ * @as: assigned address space -+ * @transtab: configuration of the TRANSTAB register -+ * @memattr: configuration of the MEMATTR register -+ * @transcfg: configuration of the TRANSCFG register (or zero if not present) -+ * -+ * Function emits a timeline message containing address space attributes. -+ */ -+#define KBASE_TLSTREAM_TL_ATTRIB_AS_CONFIG(as, transtab, memattr, transcfg) \ -+ __TRACE_IF_ENABLED(tl_attrib_as_config, as, transtab, memattr, transcfg) -+ -+/** -+ * KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_ex -+ * @atom: atom identifier -+ */ -+#define KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_EX(atom) \ -+ __TRACE_IF_ENABLED(tl_event_atom_softstop_ex, atom) -+ -+/** -+ * KBASE_TLSTREAM_TL_EVENT_LPU_softstop -+ * @lpu: name of the LPU object -+ */ -+#define KBASE_TLSTREAM_TL_EVENT_LPU_SOFTSTOP(lpu) \ -+ __TRACE_IF_ENABLED(tl_event_lpu_softstop, lpu) -+ -+/** -+ * KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_issue -+ * @atom: atom identifier -+ */ -+#define KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_ISSUE(atom) \ -+ __TRACE_IF_ENABLED(tl_event_atom_softstop_issue, atom) -+ -+/** -+ * KBASE_TLSTREAM_JD_GPU_SOFT_RESET - The GPU is being soft reset -+ * @gpu: name of the GPU object -+ * -+ * This imperative tracepoint is specific to job dumping. -+ * Function emits a timeline message indicating GPU soft reset. -+ */ -+#define KBASE_TLSTREAM_JD_GPU_SOFT_RESET(gpu) \ -+ __TRACE_IF_ENABLED(jd_gpu_soft_reset, gpu) -+ -+ -+/** -+ * KBASE_TLSTREAM_AUX_PM_STATE - timeline message: power management state -+ * @core_type: core type (shader, tiler, l2 cache, l3 cache) -+ * @state: 64bits bitmask reporting power state of the cores (1-ON, 0-OFF) -+ */ -+#define KBASE_TLSTREAM_AUX_PM_STATE(core_type, state) \ -+ __TRACE_IF_ENABLED(aux_pm_state, core_type, state) -+ -+/** -+ * KBASE_TLSTREAM_AUX_PAGEFAULT - timeline message: MMU page fault event -+ * resulting in new pages being mapped -+ * @ctx_nr: kernel context number -+ * @page_count_change: number of pages to be added -+ */ -+#define KBASE_TLSTREAM_AUX_PAGEFAULT(ctx_nr, page_count_change) \ -+ __TRACE_IF_ENABLED(aux_pagefault, ctx_nr, page_count_change) -+ -+/** -+ * KBASE_TLSTREAM_AUX_PAGESALLOC - timeline message: total number of allocated -+ * pages is changed -+ * @ctx_nr: kernel context number -+ * @page_count: number of pages used by the context -+ */ -+#define KBASE_TLSTREAM_AUX_PAGESALLOC(ctx_nr, page_count) \ -+ __TRACE_IF_ENABLED(aux_pagesalloc, ctx_nr, page_count) -+ -+/** -+ * KBASE_TLSTREAM_AUX_DEVFREQ_TARGET - timeline message: new target DVFS -+ * frequency -+ * @target_freq: new target frequency -+ */ -+#define KBASE_TLSTREAM_AUX_DEVFREQ_TARGET(target_freq) \ -+ __TRACE_IF_ENABLED(aux_devfreq_target, target_freq) -+ -+/** -+ * KBASE_TLSTREAM_AUX_PROTECTED_ENTER_START - The GPU has started transitioning -+ * to protected mode -+ * @gpu: name of the GPU object -+ * -+ * Function emits a timeline message indicating the GPU is starting to -+ * transition to protected mode. -+ */ -+#define KBASE_TLSTREAM_AUX_PROTECTED_ENTER_START(gpu) \ -+ __TRACE_IF_ENABLED_LATENCY(aux_protected_enter_start, gpu) -+ -+/** -+ * KBASE_TLSTREAM_AUX_PROTECTED_ENTER_END - The GPU has finished transitioning -+ * to protected mode -+ * @gpu: name of the GPU object -+ * -+ * Function emits a timeline message indicating the GPU has finished -+ * transitioning to protected mode. -+ */ -+#define KBASE_TLSTREAM_AUX_PROTECTED_ENTER_END(gpu) \ -+ __TRACE_IF_ENABLED_LATENCY(aux_protected_enter_end, gpu) -+ -+/** -+ * KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_START - The GPU has started transitioning -+ * to non-protected mode -+ * @gpu: name of the GPU object -+ * -+ * Function emits a timeline message indicating the GPU is starting to -+ * transition to non-protected mode. -+ */ -+#define KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_START(gpu) \ -+ __TRACE_IF_ENABLED_LATENCY(aux_protected_leave_start, gpu) -+ -+/** -+ * KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_END - The GPU has finished transitioning -+ * to non-protected mode -+ * @gpu: name of the GPU object -+ * -+ * Function emits a timeline message indicating the GPU has finished -+ * transitioning to non-protected mode. -+ */ -+#define KBASE_TLSTREAM_AUX_PROTECTED_LEAVE_END(gpu) \ -+ __TRACE_IF_ENABLED_LATENCY(aux_protected_leave_end, gpu) -+ -+#endif /* _KBASE_TLSTREAM_H */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_trace_defs.h b/drivers/gpu/arm/midgard/mali_kbase_trace_defs.h -new file mode 100644 -index 0000000..e2e0544 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_trace_defs.h -@@ -0,0 +1,264 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* ***** IMPORTANT: THIS IS NOT A NORMAL HEADER FILE ***** -+ * ***** DO NOT INCLUDE DIRECTLY ***** -+ * ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */ -+ -+/* -+ * The purpose of this header file is just to contain a list of trace code idenitifers -+ * -+ * Each identifier is wrapped in a macro, so that its string form and enum form can be created -+ * -+ * Each macro is separated with a comma, to allow insertion into an array initializer or enum definition block. -+ * -+ * This allows automatic creation of an enum and a corresponding array of strings -+ * -+ * Before #including, the includer MUST #define KBASE_TRACE_CODE_MAKE_CODE. -+ * After #including, the includer MUST #under KBASE_TRACE_CODE_MAKE_CODE. -+ * -+ * e.g.: -+ * #define KBASE_TRACE_CODE( X ) KBASE_TRACE_CODE_ ## X -+ * typedef enum -+ * { -+ * #define KBASE_TRACE_CODE_MAKE_CODE( X ) KBASE_TRACE_CODE( X ) -+ * #include "mali_kbase_trace_defs.h" -+ * #undef KBASE_TRACE_CODE_MAKE_CODE -+ * } kbase_trace_code; -+ * -+ * IMPORTANT: THIS FILE MUST NOT BE USED FOR ANY OTHER PURPOSE OTHER THAN THE ABOVE -+ * -+ * -+ * The use of the macro here is: -+ * - KBASE_TRACE_CODE_MAKE_CODE( X ) -+ * -+ * Which produces: -+ * - For an enum, KBASE_TRACE_CODE_X -+ * - For a string, "X" -+ * -+ * -+ * For example: -+ * - KBASE_TRACE_CODE_MAKE_CODE( JM_JOB_COMPLETE ) expands to: -+ * - KBASE_TRACE_CODE_JM_JOB_COMPLETE for the enum -+ * - "JM_JOB_COMPLETE" for the string -+ * - To use it to trace an event, do: -+ * - KBASE_TRACE_ADD( kbdev, JM_JOB_COMPLETE, subcode, kctx, uatom, val ); -+ */ -+ -+#if 0 /* Dummy section to avoid breaking formatting */ -+int dummy_array[] = { -+#endif -+ -+/* -+ * Core events -+ */ -+ /* no info_val, no gpu_addr, no atom */ -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_CTX_DESTROY), -+ /* no info_val, no gpu_addr, no atom */ -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_CTX_HWINSTR_TERM), -+ /* info_val == GPU_IRQ_STATUS register */ -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_IRQ), -+ /* info_val == bits cleared */ -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_IRQ_CLEAR), -+ /* info_val == GPU_IRQ_STATUS register */ -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_IRQ_DONE), -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_SOFT_RESET), -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_HARD_RESET), -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_PRFCNT_CLEAR), -+ /* GPU addr==dump address */ -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_PRFCNT_SAMPLE), -+ KBASE_TRACE_CODE_MAKE_CODE(CORE_GPU_CLEAN_INV_CACHES), -+/* -+ * Job Slot management events -+ */ -+ /* info_val==irq rawstat at start */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_IRQ), -+ /* info_val==jobs processed */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_IRQ_END), -+/* In the following: -+ * -+ * - ctx is set if a corresponding job found (NULL otherwise, e.g. some soft-stop cases) -+ * - uatom==kernel-side mapped uatom address (for correlation with user-side) -+ */ -+ /* info_val==exit code; gpu_addr==chain gpuaddr */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_JOB_DONE), -+ /* gpu_addr==JS_HEAD_NEXT written, info_val==lower 32 bits of affinity */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_SUBMIT), -+ /* gpu_addr is as follows: -+ * - If JS_STATUS active after soft-stop, val==gpu addr written to -+ * JS_HEAD on submit -+ * - otherwise gpu_addr==0 */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_SOFTSTOP), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_SOFTSTOP_0), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_SOFTSTOP_1), -+ /* gpu_addr==JS_HEAD read */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_HARDSTOP), -+ /* gpu_addr==JS_HEAD read */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_HARDSTOP_0), -+ /* gpu_addr==JS_HEAD read */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_HARDSTOP_1), -+ /* gpu_addr==JS_TAIL read */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_UPDATE_HEAD), -+/* gpu_addr is as follows: -+ * - If JS_STATUS active before soft-stop, val==JS_HEAD -+ * - otherwise gpu_addr==0 -+ */ -+ /* gpu_addr==JS_HEAD read */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_CHECK_HEAD), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_FLUSH_WORKQS), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_FLUSH_WORKQS_DONE), -+ /* info_val == is_scheduled */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_ZAP_NON_SCHEDULED), -+ /* info_val == is_scheduled */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_ZAP_SCHEDULED), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_ZAP_DONE), -+ /* info_val == nr jobs submitted */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_SLOT_SOFT_OR_HARD_STOP), -+ /* gpu_addr==JS_HEAD_NEXT last written */ -+ KBASE_TRACE_CODE_MAKE_CODE(JM_SLOT_EVICT), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_SUBMIT_AFTER_RESET), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_BEGIN_RESET_WORKER), -+ KBASE_TRACE_CODE_MAKE_CODE(JM_END_RESET_WORKER), -+/* -+ * Job dispatch events -+ */ -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JD_DONE), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JD_DONE_WORKER), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JD_DONE_WORKER_END), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JD_DONE_TRY_RUN_NEXT_JOB), -+ /* gpu_addr==0, info_val==0, uatom==0 */ -+ KBASE_TRACE_CODE_MAKE_CODE(JD_ZAP_CONTEXT), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JD_CANCEL), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JD_CANCEL_WORKER), -+/* -+ * Scheduler Core events -+ */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_RETAIN_CTX_NOLOCK), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_ADD_JOB), -+ /* gpu_addr==last value written/would be written to JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_REMOVE_JOB), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_RETAIN_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_RELEASE_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_TRY_SCHEDULE_HEAD_CTX), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_JOB_DONE_TRY_RUN_NEXT_JOB), -+ /* gpu_addr==value to write into JS_HEAD */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_JOB_DONE_RETRY_NEEDED), -+ /* kctx is the one being evicted, info_val == kctx to put in */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_FAST_START_EVICTS_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_AFFINITY_SUBMIT_TO_BLOCKED), -+ /* info_val == lower 32 bits of affinity */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_AFFINITY_CURRENT), -+ /* info_val == lower 32 bits of affinity */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CORE_REF_REQUEST_CORES_FAILED), -+ /* info_val == lower 32 bits of affinity */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CORE_REF_REGISTER_INUSE_FAILED), -+ /* info_val == lower 32 bits of rechecked affinity */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CORE_REF_REQUEST_ON_RECHECK_FAILED), -+ /* info_val == lower 32 bits of rechecked affinity */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CORE_REF_REGISTER_ON_RECHECK_FAILED), -+ /* info_val == lower 32 bits of affinity */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CORE_REF_AFFINITY_WOULD_VIOLATE), -+ /* info_val == the ctx attribute now on ctx */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_ON_CTX), -+ /* info_val == the ctx attribute now on runpool */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_ON_RUNPOOL), -+ /* info_val == the ctx attribute now off ctx */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_OFF_CTX), -+ /* info_val == the ctx attribute now off runpool */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_OFF_RUNPOOL), -+/* -+ * Scheduler Policy events -+ */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_INIT_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_TERM_CTX), -+ /* info_val == whether it was evicted */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_TRY_EVICT_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_FOREACH_CTX_JOBS), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_ENQUEUE_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_DEQUEUE_HEAD_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_RUNPOOL_ADD_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_RUNPOOL_REMOVE_CTX), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_DEQUEUE_JOB), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_DEQUEUE_JOB_IRQ), -+ /* gpu_addr==JS_HEAD to write if the job were run */ -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_ENQUEUE_JOB), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_TIMER_START), -+ KBASE_TRACE_CODE_MAKE_CODE(JS_POLICY_TIMER_END), -+/* -+ * Power Management Events -+ */ -+ KBASE_TRACE_CODE_MAKE_CODE(PM_JOB_SUBMIT_AFTER_POWERING_UP), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_JOB_SUBMIT_AFTER_POWERED_UP), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_PWRON), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_PWRON_TILER), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_PWRON_L2), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_PWROFF), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_PWROFF_TILER), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_PWROFF_L2), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_POWERED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_POWERED_TILER), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_POWERED_L2), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_DESIRED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_DESIRED_TILER), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_AVAILABLE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_AVAILABLE_TILER), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_AVAILABLE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CORES_AVAILABLE_TILER), -+ /* PM_DESIRED_REACHED: gpu_addr == pm.gpu_in_desired_state */ -+ KBASE_TRACE_CODE_MAKE_CODE(PM_DESIRED_REACHED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_DESIRED_REACHED_TILER), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_REGISTER_CHANGE_SHADER_INUSE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_REGISTER_CHANGE_TILER_INUSE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_REGISTER_CHANGE_SHADER_NEEDED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_REGISTER_CHANGE_TILER_NEEDED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_RELEASE_CHANGE_SHADER_INUSE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_RELEASE_CHANGE_TILER_INUSE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_UNREQUEST_CHANGE_SHADER_NEEDED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_UNREQUEST_CHANGE_TILER_NEEDED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_REQUEST_CHANGE_SHADER_NEEDED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_REQUEST_CHANGE_TILER_NEEDED), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_WAKE_WAITERS), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CONTEXT_ACTIVE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CONTEXT_IDLE), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_GPU_ON), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_GPU_OFF), -+ /* info_val == policy number, or -1 for "Already changing" */ -+ KBASE_TRACE_CODE_MAKE_CODE(PM_SET_POLICY), -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CA_SET_POLICY), -+ /* info_val == policy number */ -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CURRENT_POLICY_INIT), -+ /* info_val == policy number */ -+ KBASE_TRACE_CODE_MAKE_CODE(PM_CURRENT_POLICY_TERM), -+/* Unused code just to make it easier to not have a comma at the end. -+ * All other codes MUST come before this */ -+ KBASE_TRACE_CODE_MAKE_CODE(DUMMY) -+ -+#if 0 /* Dummy section to avoid breaking formatting */ -+}; -+#endif -+ -+/* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_trace_timeline.c b/drivers/gpu/arm/midgard/mali_kbase_trace_timeline.c -new file mode 100644 -index 0000000..5830e87 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_trace_timeline.c -@@ -0,0 +1,236 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+#include -+ -+#define CREATE_TRACE_POINTS -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+#include "mali_timeline.h" -+ -+#include -+#include -+ -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_atoms_in_flight); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_atom); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_gpu_slot_active); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_gpu_slot_action); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_gpu_power_active); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_l2_power_active); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_pm_event); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_slot_atom); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_pm_checktrans); -+EXPORT_TRACEPOINT_SYMBOL_GPL(mali_timeline_context_active); -+ -+struct kbase_trace_timeline_desc { -+ char *enum_str; -+ char *desc; -+ char *format; -+ char *format_desc; -+}; -+ -+static struct kbase_trace_timeline_desc kbase_trace_timeline_desc_table[] = { -+ #define KBASE_TIMELINE_TRACE_CODE(enum_val, desc, format, format_desc) { #enum_val, desc, format, format_desc } -+ #include "mali_kbase_trace_timeline_defs.h" -+ #undef KBASE_TIMELINE_TRACE_CODE -+}; -+ -+#define KBASE_NR_TRACE_CODES ARRAY_SIZE(kbase_trace_timeline_desc_table) -+ -+static void *kbasep_trace_timeline_seq_start(struct seq_file *s, loff_t *pos) -+{ -+ if (*pos >= KBASE_NR_TRACE_CODES) -+ return NULL; -+ -+ return &kbase_trace_timeline_desc_table[*pos]; -+} -+ -+static void kbasep_trace_timeline_seq_stop(struct seq_file *s, void *data) -+{ -+} -+ -+static void *kbasep_trace_timeline_seq_next(struct seq_file *s, void *data, loff_t *pos) -+{ -+ (*pos)++; -+ -+ if (*pos == KBASE_NR_TRACE_CODES) -+ return NULL; -+ -+ return &kbase_trace_timeline_desc_table[*pos]; -+} -+ -+static int kbasep_trace_timeline_seq_show(struct seq_file *s, void *data) -+{ -+ struct kbase_trace_timeline_desc *trace_desc = data; -+ -+ seq_printf(s, "%s#%s#%s#%s\n", trace_desc->enum_str, trace_desc->desc, trace_desc->format, trace_desc->format_desc); -+ return 0; -+} -+ -+ -+static const struct seq_operations kbasep_trace_timeline_seq_ops = { -+ .start = kbasep_trace_timeline_seq_start, -+ .next = kbasep_trace_timeline_seq_next, -+ .stop = kbasep_trace_timeline_seq_stop, -+ .show = kbasep_trace_timeline_seq_show, -+}; -+ -+static int kbasep_trace_timeline_debugfs_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &kbasep_trace_timeline_seq_ops); -+} -+ -+static const struct file_operations kbasep_trace_timeline_debugfs_fops = { -+ .open = kbasep_trace_timeline_debugfs_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+#ifdef CONFIG_DEBUG_FS -+ -+void kbasep_trace_timeline_debugfs_init(struct kbase_device *kbdev) -+{ -+ debugfs_create_file("mali_timeline_defs", -+ S_IRUGO, kbdev->mali_debugfs_directory, NULL, -+ &kbasep_trace_timeline_debugfs_fops); -+} -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+void kbase_timeline_job_slot_submit(struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbase_jd_atom *katom, int js) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (kbdev->timeline.slot_atoms_submitted[js] > 0) { -+ KBASE_TIMELINE_JOB_START_NEXT(kctx, js, 1); -+ } else { -+ base_atom_id atom_number = kbase_jd_atom_id(kctx, katom); -+ -+ KBASE_TIMELINE_JOB_START_HEAD(kctx, js, 1); -+ KBASE_TIMELINE_JOB_START(kctx, js, atom_number); -+ } -+ ++kbdev->timeline.slot_atoms_submitted[js]; -+ -+ KBASE_TIMELINE_ATOMS_SUBMITTED(kctx, js, kbdev->timeline.slot_atoms_submitted[js]); -+} -+ -+void kbase_timeline_job_slot_done(struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbase_jd_atom *katom, int js, -+ kbasep_js_atom_done_code done_code) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ -+ if (done_code & KBASE_JS_ATOM_DONE_EVICTED_FROM_NEXT) { -+ KBASE_TIMELINE_JOB_START_NEXT(kctx, js, 0); -+ } else { -+ /* Job finished in JS_HEAD */ -+ base_atom_id atom_number = kbase_jd_atom_id(kctx, katom); -+ -+ KBASE_TIMELINE_JOB_START_HEAD(kctx, js, 0); -+ KBASE_TIMELINE_JOB_STOP(kctx, js, atom_number); -+ -+ /* see if we need to trace the job in JS_NEXT moving to JS_HEAD */ -+ if (kbase_backend_nr_atoms_submitted(kbdev, js)) { -+ struct kbase_jd_atom *next_katom; -+ struct kbase_context *next_kctx; -+ -+ /* Peek the next atom - note that the atom in JS_HEAD will already -+ * have been dequeued */ -+ next_katom = kbase_backend_inspect_head(kbdev, js); -+ WARN_ON(!next_katom); -+ next_kctx = next_katom->kctx; -+ KBASE_TIMELINE_JOB_START_NEXT(next_kctx, js, 0); -+ KBASE_TIMELINE_JOB_START_HEAD(next_kctx, js, 1); -+ KBASE_TIMELINE_JOB_START(next_kctx, js, kbase_jd_atom_id(next_kctx, next_katom)); -+ } -+ } -+ -+ --kbdev->timeline.slot_atoms_submitted[js]; -+ -+ KBASE_TIMELINE_ATOMS_SUBMITTED(kctx, js, kbdev->timeline.slot_atoms_submitted[js]); -+} -+ -+void kbase_timeline_pm_send_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event_sent) -+{ -+ int uid = 0; -+ int old_uid; -+ -+ /* If a producer already exists for the event, try to use their UID (multiple-producers) */ -+ uid = atomic_read(&kbdev->timeline.pm_event_uid[event_sent]); -+ old_uid = uid; -+ -+ /* Get a new non-zero UID if we don't have one yet */ -+ while (!uid) -+ uid = atomic_inc_return(&kbdev->timeline.pm_event_uid_counter); -+ -+ /* Try to use this UID */ -+ if (old_uid != atomic_cmpxchg(&kbdev->timeline.pm_event_uid[event_sent], old_uid, uid)) -+ /* If it changed, raced with another producer: we've lost this UID */ -+ uid = 0; -+ -+ KBASE_TIMELINE_PM_SEND_EVENT(kbdev, event_sent, uid); -+} -+ -+void kbase_timeline_pm_check_handle_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event) -+{ -+ int uid = atomic_read(&kbdev->timeline.pm_event_uid[event]); -+ -+ if (uid != 0) { -+ if (uid != atomic_cmpxchg(&kbdev->timeline.pm_event_uid[event], uid, 0)) -+ /* If it changed, raced with another consumer: we've lost this UID */ -+ uid = 0; -+ -+ KBASE_TIMELINE_PM_HANDLE_EVENT(kbdev, event, uid); -+ } -+} -+ -+void kbase_timeline_pm_handle_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event) -+{ -+ int uid = atomic_read(&kbdev->timeline.pm_event_uid[event]); -+ -+ if (uid != atomic_cmpxchg(&kbdev->timeline.pm_event_uid[event], uid, 0)) -+ /* If it changed, raced with another consumer: we've lost this UID */ -+ uid = 0; -+ -+ KBASE_TIMELINE_PM_HANDLE_EVENT(kbdev, event, uid); -+} -+ -+void kbase_timeline_pm_l2_transition_start(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ /* Simply log the start of the transition */ -+ kbdev->timeline.l2_transitioning = true; -+ KBASE_TIMELINE_POWERING_L2(kbdev); -+} -+ -+void kbase_timeline_pm_l2_transition_done(struct kbase_device *kbdev) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+ /* Simply log the end of the transition */ -+ if (kbdev->timeline.l2_transitioning) { -+ kbdev->timeline.l2_transitioning = false; -+ KBASE_TIMELINE_POWERED_L2(kbdev); -+ } -+} -+ -+#endif /* CONFIG_MALI_TRACE_TIMELINE */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_trace_timeline.h b/drivers/gpu/arm/midgard/mali_kbase_trace_timeline.h -new file mode 100644 -index 0000000..619072f ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_trace_timeline.h -@@ -0,0 +1,363 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#if !defined(_KBASE_TRACE_TIMELINE_H) -+#define _KBASE_TRACE_TIMELINE_H -+ -+#ifdef CONFIG_MALI_TRACE_TIMELINE -+ -+enum kbase_trace_timeline_code { -+ #define KBASE_TIMELINE_TRACE_CODE(enum_val, desc, format, format_desc) enum_val -+ #include "mali_kbase_trace_timeline_defs.h" -+ #undef KBASE_TIMELINE_TRACE_CODE -+}; -+ -+#ifdef CONFIG_DEBUG_FS -+ -+/** Initialize Timeline DebugFS entries */ -+void kbasep_trace_timeline_debugfs_init(struct kbase_device *kbdev); -+ -+#else /* CONFIG_DEBUG_FS */ -+ -+#define kbasep_trace_timeline_debugfs_init CSTD_NOP -+ -+#endif /* CONFIG_DEBUG_FS */ -+ -+/* mali_timeline.h defines kernel tracepoints used by the KBASE_TIMELINE -+ * functions. -+ * Output is timestamped by either sched_clock() (default), local_clock(), or -+ * cpu_clock(), depending on /sys/kernel/debug/tracing/trace_clock */ -+#include "mali_timeline.h" -+ -+/* Trace number of atoms in flight for kctx (atoms either not completed, or in -+ process of being returned to user */ -+#define KBASE_TIMELINE_ATOMS_IN_FLIGHT(kctx, count) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_atoms_in_flight(ts.tv_sec, ts.tv_nsec, \ -+ (int)kctx->timeline.owner_tgid, \ -+ count); \ -+ } while (0) -+ -+/* Trace atom_id being Ready to Run */ -+#define KBASE_TIMELINE_ATOM_READY(kctx, atom_id) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_atom(ts.tv_sec, ts.tv_nsec, \ -+ CTX_FLOW_ATOM_READY, \ -+ (int)kctx->timeline.owner_tgid, \ -+ atom_id); \ -+ } while (0) -+ -+/* Trace number of atoms submitted to job slot js -+ * -+ * NOTE: This uses a different tracepoint to the head/next/soft-stop actions, -+ * so that those actions can be filtered out separately from this -+ * -+ * This is because this is more useful, as we can use it to calculate general -+ * utilization easily and accurately */ -+#define KBASE_TIMELINE_ATOMS_SUBMITTED(kctx, js, count) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_slot_active(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_SLOT_ACTIVE, \ -+ (int)kctx->timeline.owner_tgid, \ -+ js, count); \ -+ } while (0) -+ -+ -+/* Trace atoms present in JS_NEXT */ -+#define KBASE_TIMELINE_JOB_START_NEXT(kctx, js, count) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_slot_action(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_SLOT_NEXT, \ -+ (int)kctx->timeline.owner_tgid, \ -+ js, count); \ -+ } while (0) -+ -+/* Trace atoms present in JS_HEAD */ -+#define KBASE_TIMELINE_JOB_START_HEAD(kctx, js, count) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_slot_action(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_SLOT_HEAD, \ -+ (int)kctx->timeline.owner_tgid, \ -+ js, count); \ -+ } while (0) -+ -+/* Trace that a soft stop/evict from next is being attempted on a slot */ -+#define KBASE_TIMELINE_TRY_SOFT_STOP(kctx, js, count) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_slot_action(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_SLOT_STOPPING, \ -+ (kctx) ? (int)kctx->timeline.owner_tgid : 0, \ -+ js, count); \ -+ } while (0) -+ -+ -+ -+/* Trace state of overall GPU power */ -+#define KBASE_TIMELINE_GPU_POWER(kbdev, active) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_power_active(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_POWER_ACTIVE, active); \ -+ } while (0) -+ -+/* Trace state of tiler power */ -+#define KBASE_TIMELINE_POWER_TILER(kbdev, bitmap) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_power_active(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_POWER_TILER_ACTIVE, \ -+ hweight64(bitmap)); \ -+ } while (0) -+ -+/* Trace number of shaders currently powered */ -+#define KBASE_TIMELINE_POWER_SHADER(kbdev, bitmap) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_power_active(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_POWER_SHADER_ACTIVE, \ -+ hweight64(bitmap)); \ -+ } while (0) -+ -+/* Trace state of L2 power */ -+#define KBASE_TIMELINE_POWER_L2(kbdev, bitmap) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_gpu_power_active(ts.tv_sec, ts.tv_nsec, \ -+ SW_SET_GPU_POWER_L2_ACTIVE, \ -+ hweight64(bitmap)); \ -+ } while (0) -+ -+/* Trace state of L2 cache*/ -+#define KBASE_TIMELINE_POWERING_L2(kbdev) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_l2_power_active(ts.tv_sec, ts.tv_nsec, \ -+ SW_FLOW_GPU_POWER_L2_POWERING, \ -+ 1); \ -+ } while (0) -+ -+#define KBASE_TIMELINE_POWERED_L2(kbdev) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_l2_power_active(ts.tv_sec, ts.tv_nsec, \ -+ SW_FLOW_GPU_POWER_L2_ACTIVE, \ -+ 1); \ -+ } while (0) -+ -+/* Trace kbase_pm_send_event message send */ -+#define KBASE_TIMELINE_PM_SEND_EVENT(kbdev, event_type, pm_event_id) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_pm_event(ts.tv_sec, ts.tv_nsec, \ -+ SW_FLOW_PM_SEND_EVENT, \ -+ event_type, pm_event_id); \ -+ } while (0) -+ -+/* Trace kbase_pm_worker message receive */ -+#define KBASE_TIMELINE_PM_HANDLE_EVENT(kbdev, event_type, pm_event_id) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_pm_event(ts.tv_sec, ts.tv_nsec, \ -+ SW_FLOW_PM_HANDLE_EVENT, \ -+ event_type, pm_event_id); \ -+ } while (0) -+ -+ -+/* Trace atom_id starting in JS_HEAD */ -+#define KBASE_TIMELINE_JOB_START(kctx, js, _consumerof_atom_number) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_slot_atom(ts.tv_sec, ts.tv_nsec, \ -+ HW_START_GPU_JOB_CHAIN_SW_APPROX, \ -+ (int)kctx->timeline.owner_tgid, \ -+ js, _consumerof_atom_number); \ -+ } while (0) -+ -+/* Trace atom_id stopping on JS_HEAD */ -+#define KBASE_TIMELINE_JOB_STOP(kctx, js, _producerof_atom_number_completed) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_slot_atom(ts.tv_sec, ts.tv_nsec, \ -+ HW_STOP_GPU_JOB_CHAIN_SW_APPROX, \ -+ (int)kctx->timeline.owner_tgid, \ -+ js, _producerof_atom_number_completed); \ -+ } while (0) -+ -+/** Trace beginning/end of a call to kbase_pm_check_transitions_nolock from a -+ * certin caller */ -+#define KBASE_TIMELINE_PM_CHECKTRANS(kbdev, trace_code) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_pm_checktrans(ts.tv_sec, ts.tv_nsec, \ -+ trace_code, 1); \ -+ } while (0) -+ -+/* Trace number of contexts active */ -+#define KBASE_TIMELINE_CONTEXT_ACTIVE(kbdev, count) \ -+ do { \ -+ struct timespec ts; \ -+ getrawmonotonic(&ts); \ -+ trace_mali_timeline_context_active(ts.tv_sec, ts.tv_nsec, \ -+ count); \ -+ } while (0) -+ -+/* NOTE: kbase_timeline_pm_cores_func() is in mali_kbase_pm_policy.c */ -+ -+/** -+ * Trace that an atom is starting on a job slot -+ * -+ * The caller must be holding hwaccess_lock -+ */ -+void kbase_timeline_job_slot_submit(struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbase_jd_atom *katom, int js); -+ -+/** -+ * Trace that an atom has done on a job slot -+ * -+ * 'Done' in this sense can occur either because: -+ * - the atom in JS_HEAD finished -+ * - the atom in JS_NEXT was evicted -+ * -+ * Whether the atom finished or was evicted is passed in @a done_code -+ * -+ * It is assumed that the atom has already been removed from the submit slot, -+ * with either: -+ * - kbasep_jm_dequeue_submit_slot() -+ * - kbasep_jm_dequeue_tail_submit_slot() -+ * -+ * The caller must be holding hwaccess_lock -+ */ -+void kbase_timeline_job_slot_done(struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbase_jd_atom *katom, int js, -+ kbasep_js_atom_done_code done_code); -+ -+ -+/** Trace a pm event starting */ -+void kbase_timeline_pm_send_event(struct kbase_device *kbdev, -+ enum kbase_timeline_pm_event event_sent); -+ -+/** Trace a pm event finishing */ -+void kbase_timeline_pm_check_handle_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event); -+ -+/** Check whether a pm event was present, and if so trace finishing it */ -+void kbase_timeline_pm_handle_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event); -+ -+/** Trace L2 power-up start */ -+void kbase_timeline_pm_l2_transition_start(struct kbase_device *kbdev); -+ -+/** Trace L2 power-up done */ -+void kbase_timeline_pm_l2_transition_done(struct kbase_device *kbdev); -+ -+#else -+ -+#define KBASE_TIMELINE_ATOMS_IN_FLIGHT(kctx, count) CSTD_NOP() -+ -+#define KBASE_TIMELINE_ATOM_READY(kctx, atom_id) CSTD_NOP() -+ -+#define KBASE_TIMELINE_ATOMS_SUBMITTED(kctx, js, count) CSTD_NOP() -+ -+#define KBASE_TIMELINE_JOB_START_NEXT(kctx, js, count) CSTD_NOP() -+ -+#define KBASE_TIMELINE_JOB_START_HEAD(kctx, js, count) CSTD_NOP() -+ -+#define KBASE_TIMELINE_TRY_SOFT_STOP(kctx, js, count) CSTD_NOP() -+ -+#define KBASE_TIMELINE_GPU_POWER(kbdev, active) CSTD_NOP() -+ -+#define KBASE_TIMELINE_POWER_TILER(kbdev, bitmap) CSTD_NOP() -+ -+#define KBASE_TIMELINE_POWER_SHADER(kbdev, bitmap) CSTD_NOP() -+ -+#define KBASE_TIMELINE_POWER_L2(kbdev, active) CSTD_NOP() -+ -+#define KBASE_TIMELINE_POWERING_L2(kbdev) CSTD_NOP() -+ -+#define KBASE_TIMELINE_POWERED_L2(kbdev) CSTD_NOP() -+ -+#define KBASE_TIMELINE_PM_SEND_EVENT(kbdev, event_type, pm_event_id) CSTD_NOP() -+ -+#define KBASE_TIMELINE_PM_HANDLE_EVENT(kbdev, event_type, pm_event_id) CSTD_NOP() -+ -+#define KBASE_TIMELINE_JOB_START(kctx, js, _consumerof_atom_number) CSTD_NOP() -+ -+#define KBASE_TIMELINE_JOB_STOP(kctx, js, _producerof_atom_number_completed) CSTD_NOP() -+ -+#define KBASE_TIMELINE_PM_CHECKTRANS(kbdev, trace_code) CSTD_NOP() -+ -+#define KBASE_TIMELINE_CONTEXT_ACTIVE(kbdev, count) CSTD_NOP() -+ -+static inline void kbase_timeline_job_slot_submit(struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbase_jd_atom *katom, int js) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+} -+ -+static inline void kbase_timeline_job_slot_done(struct kbase_device *kbdev, struct kbase_context *kctx, -+ struct kbase_jd_atom *katom, int js, -+ kbasep_js_atom_done_code done_code) -+{ -+ lockdep_assert_held(&kbdev->hwaccess_lock); -+} -+ -+static inline void kbase_timeline_pm_send_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event_sent) -+{ -+} -+ -+static inline void kbase_timeline_pm_check_handle_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event) -+{ -+} -+ -+static inline void kbase_timeline_pm_handle_event(struct kbase_device *kbdev, enum kbase_timeline_pm_event event) -+{ -+} -+ -+static inline void kbase_timeline_pm_l2_transition_start(struct kbase_device *kbdev) -+{ -+} -+ -+static inline void kbase_timeline_pm_l2_transition_done(struct kbase_device *kbdev) -+{ -+} -+#endif /* CONFIG_MALI_TRACE_TIMELINE */ -+ -+#endif /* _KBASE_TRACE_TIMELINE_H */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_trace_timeline_defs.h b/drivers/gpu/arm/midgard/mali_kbase_trace_timeline_defs.h -new file mode 100644 -index 0000000..156a95a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_trace_timeline_defs.h -@@ -0,0 +1,140 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/* ***** IMPORTANT: THIS IS NOT A NORMAL HEADER FILE ***** -+ * ***** DO NOT INCLUDE DIRECTLY ***** -+ * ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */ -+ -+/* -+ * Conventions on Event Names: -+ * -+ * - The prefix determines something about how the timeline should be -+ * displayed, and is split up into various parts, separated by underscores: -+ * - 'SW' and 'HW' as the first part will be used to determine whether a -+ * timeline is to do with Software or Hardware - effectively, separate -+ * 'channels' for Software and Hardware -+ * - 'START', 'STOP', 'ENTER', 'LEAVE' can be used in the second part, and -+ * signify related pairs of events - these are optional. -+ * - 'FLOW' indicates a generic event, which can use dependencies -+ * - This gives events such as: -+ * - 'SW_ENTER_FOO' -+ * - 'SW_LEAVE_FOO' -+ * - 'SW_FLOW_BAR_1' -+ * - 'SW_FLOW_BAR_2' -+ * - 'HW_START_BAZ' -+ * - 'HW_STOP_BAZ' -+ * - And an unadorned HW event: -+ * - 'HW_BAZ_FROZBOZ' -+ */ -+ -+/* -+ * Conventions on parameter names: -+ * - anything with 'instance' in the name will have a separate timeline based -+ * on that instances. -+ * - underscored-prefixed parameters will by hidden by default on timelines -+ * -+ * Hence: -+ * - Different job slots have their own 'instance', based on the instance value -+ * - Per-context info (e.g. atoms on a context) have their own 'instance' -+ * (i.e. each context should be on a different timeline) -+ * -+ * Note that globally-shared resources can be tagged with a tgid, but we don't -+ * want an instance per context: -+ * - There's no point having separate Job Slot timelines for each context, that -+ * would be confusing - there's only really 3 job slots! -+ * - There's no point having separate Shader-powered timelines for each -+ * context, that would be confusing - all shader cores (whether it be 4, 8, -+ * etc) are shared in the system. -+ */ -+ -+ /* -+ * CTX events -+ */ -+ /* Separate timelines for each context 'instance'*/ -+ KBASE_TIMELINE_TRACE_CODE(CTX_SET_NR_ATOMS_IN_FLIGHT, "CTX: Atoms in flight", "%d,%d", "_instance_tgid,_value_number_of_atoms"), -+ KBASE_TIMELINE_TRACE_CODE(CTX_FLOW_ATOM_READY, "CTX: Atoms Ready to Run", "%d,%d,%d", "_instance_tgid,_consumerof_atom_number,_producerof_atom_number_ready"), -+ -+ /* -+ * SW Events -+ */ -+ /* Separate timelines for each slot 'instance' */ -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_SLOT_ACTIVE, "SW: GPU slot active", "%d,%d,%d", "_tgid,_instance_slot,_value_number_of_atoms"), -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_SLOT_NEXT, "SW: GPU atom in NEXT", "%d,%d,%d", "_tgid,_instance_slot,_value_is_an_atom_in_next"), -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_SLOT_HEAD, "SW: GPU atom in HEAD", "%d,%d,%d", "_tgid,_instance_slot,_value_is_an_atom_in_head"), -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_SLOT_STOPPING, "SW: Try Soft-Stop on GPU slot", "%d,%d,%d", "_tgid,_instance_slot,_value_is_slot_stopping"), -+ /* Shader and overall power is shared - can't have separate instances of -+ * it, just tagging with the context */ -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_POWER_ACTIVE, "SW: GPU power active", "%d,%d", "_tgid,_value_is_power_active"), -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_POWER_TILER_ACTIVE, "SW: GPU tiler powered", "%d,%d", "_tgid,_value_number_of_tilers"), -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_POWER_SHADER_ACTIVE, "SW: GPU shaders powered", "%d,%d", "_tgid,_value_number_of_shaders"), -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_GPU_POWER_L2_ACTIVE, "SW: GPU L2 powered", "%d,%d", "_tgid,_value_number_of_l2"), -+ -+ /* SW Power event messaging. _event_type is one from the kbase_pm_event enum */ -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_SEND_EVENT, "SW: PM Send Event", "%d,%d,%d", "_tgid,_event_type,_writerof_pm_event_id"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_HANDLE_EVENT, "SW: PM Handle Event", "%d,%d,%d", "_tgid,_event_type,_finalconsumerof_pm_event_id"), -+ /* SW L2 power events */ -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_GPU_POWER_L2_POWERING, "SW: GPU L2 powering", "%d,%d", "_tgid,_writerof_l2_transitioning"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_GPU_POWER_L2_ACTIVE, "SW: GPU L2 powering done", "%d,%d", "_tgid,_finalconsumerof_l2_transitioning"), -+ -+ KBASE_TIMELINE_TRACE_CODE(SW_SET_CONTEXT_ACTIVE, "SW: Context Active", "%d,%d", "_tgid,_value_active"), -+ -+ /* -+ * BEGIN: Significant SW Functions that call kbase_pm_check_transitions_nolock() -+ */ -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_DO_POWEROFF_START, "SW: PM CheckTrans from kbase_pm_do_poweroff", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_do_poweroff"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_DO_POWEROFF_END, "SW: PM CheckTrans from kbase_pm_do_poweroff", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_do_poweroff"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_DO_POWERON_START, "SW: PM CheckTrans from kbase_pm_do_poweron", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_do_poweron"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_DO_POWERON_END, "SW: PM CheckTrans from kbase_pm_do_poweron", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_do_poweron"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_GPU_INTERRUPT_START, "SW: PM CheckTrans from kbase_gpu_interrupt", "%d,%d", "_tgid,_writerof_pm_checktrans_gpu_interrupt"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_GPU_INTERRUPT_END, "SW: PM CheckTrans from kbase_gpu_interrupt", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_gpu_interrupt"), -+ -+ /* -+ * Significant Indirect callers of kbase_pm_check_transitions_nolock() -+ */ -+ /* kbase_pm_request_cores */ -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_START, "SW: PM CheckTrans from kbase_pm_request_cores(shader)", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_request_cores_shader"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_END, "SW: PM CheckTrans from kbase_pm_request_cores(shader)", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_request_cores_shader"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_TILER_START, "SW: PM CheckTrans from kbase_pm_request_cores(tiler)", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_request_cores_tiler"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_TILER_END, "SW: PM CheckTrans from kbase_pm_request_cores(tiler)", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_request_cores_tiler"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_TILER_START, "SW: PM CheckTrans from kbase_pm_request_cores(shader+tiler)", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_request_cores_shader_tiler"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_TILER_END, "SW: PM CheckTrans from kbase_pm_request_cores(shader+tiler)", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_request_cores_shader_tiler"), -+ /* kbase_pm_release_cores */ -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_START, "SW: PM CheckTrans from kbase_pm_release_cores(shader)", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_release_cores_shader"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_END, "SW: PM CheckTrans from kbase_pm_release_cores(shader)", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_release_cores_shader"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_TILER_START, "SW: PM CheckTrans from kbase_pm_release_cores(tiler)", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_release_cores_tiler"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_TILER_END, "SW: PM CheckTrans from kbase_pm_release_cores(tiler)", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_release_cores_tiler"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_TILER_START, "SW: PM CheckTrans from kbase_pm_release_cores(shader+tiler)", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_release_cores_shader_tiler"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_TILER_END, "SW: PM CheckTrans from kbase_pm_release_cores(shader+tiler)", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_release_cores_shader_tiler"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_START, "SW: PM CheckTrans from kbasep_pm_do_shader_poweroff_callback", "%d,%d", "_tgid,_writerof_pm_checktrans_pm_do_shader_poweroff_callback"), -+ KBASE_TIMELINE_TRACE_CODE(SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_END, "SW: PM CheckTrans from kbasep_pm_do_shader_poweroff_callback", "%d,%d", "_tgid,_finalconsumerof_pm_checktrans_pm_do_shader_poweroff_callback"), -+ /* -+ * END: SW Functions that call kbase_pm_check_transitions_nolock() -+ */ -+ -+ /* -+ * HW Events -+ */ -+ KBASE_TIMELINE_TRACE_CODE(HW_MMU_FAULT, -+"HW: MMU Fault", "%d,%d,%d", "_tgid,fault_type,fault_stage,asid"), -+ KBASE_TIMELINE_TRACE_CODE(HW_START_GPU_JOB_CHAIN_SW_APPROX, -+"HW: Job Chain start (SW approximated)", "%d,%d,%d", -+"_tgid,job_slot,_consumerof_atom_number_ready"), -+ KBASE_TIMELINE_TRACE_CODE(HW_STOP_GPU_JOB_CHAIN_SW_APPROX, -+"HW: Job Chain stop (SW approximated)", "%d,%d,%d", -+"_tgid,job_slot,_producerof_atom_number_completed") -diff --git a/drivers/gpu/arm/midgard/mali_kbase_uku.h b/drivers/gpu/arm/midgard/mali_kbase_uku.h -new file mode 100644 -index 0000000..2a69da7 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_uku.h -@@ -0,0 +1,532 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KBASE_UKU_H_ -+#define _KBASE_UKU_H_ -+ -+#include "mali_uk.h" -+#include "mali_base_kernel.h" -+ -+/* This file needs to support being included from kernel and userside (which use different defines) */ -+#if defined(CONFIG_MALI_ERROR_INJECT) || MALI_ERROR_INJECT_ON -+#define SUPPORT_MALI_ERROR_INJECT -+#endif /* defined(CONFIG_MALI_ERROR_INJECT) || MALI_ERROR_INJECT_ON */ -+#if defined(CONFIG_MALI_NO_MALI) -+#define SUPPORT_MALI_NO_MALI -+#elif defined(MALI_NO_MALI) -+#if MALI_NO_MALI -+#define SUPPORT_MALI_NO_MALI -+#endif -+#endif -+ -+#if defined(SUPPORT_MALI_NO_MALI) || defined(SUPPORT_MALI_ERROR_INJECT) -+#include "backend/gpu/mali_kbase_model_dummy.h" -+#endif -+ -+#include "mali_kbase_gpuprops_types.h" -+ -+/* -+ * 10.1: -+ * - Do mmap in kernel for SAME_VA memory allocations rather then -+ * calling back into the kernel as a 2nd stage of the allocation request. -+ * -+ * 10.2: -+ * - Add KBASE_FUNC_MEM_JIT_INIT which allows clients to request a custom VA -+ * region for use with JIT (ignored on 32-bit platforms) -+ * -+ * 10.3: -+ * - base_jd_core_req typedef-ed to u32 (instead of to u16) -+ * - two flags added: BASE_JD_REQ_SKIP_CACHE_STAT / _END -+ * -+ * 10.4: -+ * - Removed KBASE_FUNC_EXT_BUFFER_LOCK used only in internal tests -+ * -+ * 10.5: -+ * - Reverted to performing mmap in user space so that tools like valgrind work. -+ * -+ * 10.6: -+ * - Add flags input variable to KBASE_FUNC_TLSTREAM_ACQUIRE -+ */ -+#define BASE_UK_VERSION_MAJOR 10 -+#define BASE_UK_VERSION_MINOR 6 -+ -+#define LINUX_UK_BASE_MAGIC 0x80 -+ -+struct kbase_uk_mem_alloc { -+ union uk_header header; -+ /* IN */ -+ u64 va_pages; -+ u64 commit_pages; -+ u64 extent; -+ /* IN/OUT */ -+ u64 flags; -+ /* OUT */ -+ u64 gpu_va; -+ u16 va_alignment; -+ u8 padding[6]; -+}; -+ -+struct kbase_uk_mem_free { -+ union uk_header header; -+ /* IN */ -+ u64 gpu_addr; -+ /* OUT */ -+}; -+ -+struct kbase_uk_mem_alias { -+ union uk_header header; -+ /* IN/OUT */ -+ u64 flags; -+ /* IN */ -+ u64 stride; -+ u64 nents; -+ u64 ai; -+ /* OUT */ -+ u64 gpu_va; -+ u64 va_pages; -+}; -+ -+struct kbase_uk_mem_import { -+ union uk_header header; -+ /* IN */ -+ u64 phandle; -+ u32 type; -+ u32 padding; -+ /* IN/OUT */ -+ u64 flags; -+ /* OUT */ -+ u64 gpu_va; -+ u64 va_pages; -+}; -+ -+struct kbase_uk_mem_flags_change { -+ union uk_header header; -+ /* IN */ -+ u64 gpu_va; -+ u64 flags; -+ u64 mask; -+}; -+ -+struct kbase_uk_job_submit { -+ union uk_header header; -+ /* IN */ -+ u64 addr; -+ u32 nr_atoms; -+ u32 stride; /* bytes between atoms, i.e. sizeof(base_jd_atom_v2) */ -+ /* OUT */ -+}; -+ -+struct kbase_uk_post_term { -+ union uk_header header; -+}; -+ -+struct kbase_uk_sync_now { -+ union uk_header header; -+ -+ /* IN */ -+ struct base_syncset sset; -+ -+ /* OUT */ -+}; -+ -+struct kbase_uk_hwcnt_setup { -+ union uk_header header; -+ -+ /* IN */ -+ u64 dump_buffer; -+ u32 jm_bm; -+ u32 shader_bm; -+ u32 tiler_bm; -+ u32 unused_1; /* keep for backwards compatibility */ -+ u32 mmu_l2_bm; -+ u32 padding; -+ /* OUT */ -+}; -+ -+/** -+ * struct kbase_uk_hwcnt_reader_setup - User/Kernel space data exchange structure -+ * @header: UK structure header -+ * @buffer_count: requested number of dumping buffers -+ * @jm_bm: counters selection bitmask (JM) -+ * @shader_bm: counters selection bitmask (Shader) -+ * @tiler_bm: counters selection bitmask (Tiler) -+ * @mmu_l2_bm: counters selection bitmask (MMU_L2) -+ * @fd: dumping notification file descriptor -+ * -+ * This structure sets up HWC dumper/reader for this context. -+ * Multiple instances can be created for single context. -+ */ -+struct kbase_uk_hwcnt_reader_setup { -+ union uk_header header; -+ -+ /* IN */ -+ u32 buffer_count; -+ u32 jm_bm; -+ u32 shader_bm; -+ u32 tiler_bm; -+ u32 mmu_l2_bm; -+ -+ /* OUT */ -+ s32 fd; -+}; -+ -+struct kbase_uk_hwcnt_dump { -+ union uk_header header; -+}; -+ -+struct kbase_uk_hwcnt_clear { -+ union uk_header header; -+}; -+ -+struct kbase_uk_fence_validate { -+ union uk_header header; -+ /* IN */ -+ s32 fd; -+ u32 padding; -+ /* OUT */ -+}; -+ -+struct kbase_uk_stream_create { -+ union uk_header header; -+ /* IN */ -+ char name[32]; -+ /* OUT */ -+ s32 fd; -+ u32 padding; -+}; -+ -+struct kbase_uk_gpuprops { -+ union uk_header header; -+ -+ /* IN */ -+ struct mali_base_gpu_props props; -+ /* OUT */ -+}; -+ -+struct kbase_uk_mem_query { -+ union uk_header header; -+ /* IN */ -+ u64 gpu_addr; -+#define KBASE_MEM_QUERY_COMMIT_SIZE 1 -+#define KBASE_MEM_QUERY_VA_SIZE 2 -+#define KBASE_MEM_QUERY_FLAGS 3 -+ u64 query; -+ /* OUT */ -+ u64 value; -+}; -+ -+struct kbase_uk_mem_commit { -+ union uk_header header; -+ /* IN */ -+ u64 gpu_addr; -+ u64 pages; -+ /* OUT */ -+ u32 result_subcode; -+ u32 padding; -+}; -+ -+struct kbase_uk_find_cpu_offset { -+ union uk_header header; -+ /* IN */ -+ u64 gpu_addr; -+ u64 cpu_addr; -+ u64 size; -+ /* OUT */ -+ u64 offset; -+}; -+ -+#define KBASE_GET_VERSION_BUFFER_SIZE 64 -+struct kbase_uk_get_ddk_version { -+ union uk_header header; -+ /* OUT */ -+ char version_buffer[KBASE_GET_VERSION_BUFFER_SIZE]; -+ u32 version_string_size; -+ u32 padding; -+}; -+ -+struct kbase_uk_disjoint_query { -+ union uk_header header; -+ /* OUT */ -+ u32 counter; -+ u32 padding; -+}; -+ -+struct kbase_uk_set_flags { -+ union uk_header header; -+ /* IN */ -+ u32 create_flags; -+ u32 padding; -+}; -+ -+#if MALI_UNIT_TEST -+#define TEST_ADDR_COUNT 4 -+#define KBASE_TEST_BUFFER_SIZE 128 -+struct kbase_exported_test_data { -+ u64 test_addr[TEST_ADDR_COUNT]; /**< memory address */ -+ u32 test_addr_pages[TEST_ADDR_COUNT]; /**< memory size in pages */ -+ u64 kctx; /**< base context created by process */ -+ u64 mm; /**< pointer to process address space */ -+ u8 buffer1[KBASE_TEST_BUFFER_SIZE]; /**< unit test defined parameter */ -+ u8 buffer2[KBASE_TEST_BUFFER_SIZE]; /**< unit test defined parameter */ -+}; -+ -+struct kbase_uk_set_test_data { -+ union uk_header header; -+ /* IN */ -+ struct kbase_exported_test_data test_data; -+}; -+ -+#endif /* MALI_UNIT_TEST */ -+ -+#ifdef SUPPORT_MALI_ERROR_INJECT -+struct kbase_uk_error_params { -+ union uk_header header; -+ /* IN */ -+ struct kbase_error_params params; -+}; -+#endif /* SUPPORT_MALI_ERROR_INJECT */ -+ -+#ifdef SUPPORT_MALI_NO_MALI -+struct kbase_uk_model_control_params { -+ union uk_header header; -+ /* IN */ -+ struct kbase_model_control_params params; -+}; -+#endif /* SUPPORT_MALI_NO_MALI */ -+ -+struct kbase_uk_profiling_controls { -+ union uk_header header; -+ u32 profiling_controls[FBDUMP_CONTROL_MAX]; -+}; -+ -+struct kbase_uk_debugfs_mem_profile_add { -+ union uk_header header; -+ u32 len; -+ u32 padding; -+ u64 buf; -+}; -+ -+struct kbase_uk_context_id { -+ union uk_header header; -+ /* OUT */ -+ int id; -+}; -+ -+/** -+ * struct kbase_uk_tlstream_acquire - User/Kernel space data exchange structure -+ * @header: UK structure header -+ * @flags: timeline stream flags -+ * @fd: timeline stream file descriptor -+ * -+ * This structure is used when performing a call to acquire kernel side timeline -+ * stream file descriptor. -+ */ -+struct kbase_uk_tlstream_acquire { -+ union uk_header header; -+ /* IN */ -+ u32 flags; -+ /* OUT */ -+ s32 fd; -+}; -+ -+/** -+ * struct kbase_uk_tlstream_acquire_v10_4 - User/Kernel space data exchange -+ * structure -+ * @header: UK structure header -+ * @fd: timeline stream file descriptor -+ * -+ * This structure is used when performing a call to acquire kernel side timeline -+ * stream file descriptor. -+ */ -+struct kbase_uk_tlstream_acquire_v10_4 { -+ union uk_header header; -+ /* IN */ -+ /* OUT */ -+ s32 fd; -+}; -+ -+/** -+ * struct kbase_uk_tlstream_flush - User/Kernel space data exchange structure -+ * @header: UK structure header -+ * -+ * This structure is used when performing a call to flush kernel side -+ * timeline streams. -+ */ -+struct kbase_uk_tlstream_flush { -+ union uk_header header; -+ /* IN */ -+ /* OUT */ -+}; -+ -+#if MALI_UNIT_TEST -+/** -+ * struct kbase_uk_tlstream_test - User/Kernel space data exchange structure -+ * @header: UK structure header -+ * @tpw_count: number of trace point writers in each context -+ * @msg_delay: time delay between tracepoints from one writer in milliseconds -+ * @msg_count: number of trace points written by one writer -+ * @aux_msg: if non-zero aux messages will be included -+ * -+ * This structure is used when performing a call to start timeline stream test -+ * embedded in kernel. -+ */ -+struct kbase_uk_tlstream_test { -+ union uk_header header; -+ /* IN */ -+ u32 tpw_count; -+ u32 msg_delay; -+ u32 msg_count; -+ u32 aux_msg; -+ /* OUT */ -+}; -+ -+/** -+ * struct kbase_uk_tlstream_stats - User/Kernel space data exchange structure -+ * @header: UK structure header -+ * @bytes_collected: number of bytes read by user -+ * @bytes_generated: number of bytes generated by tracepoints -+ * -+ * This structure is used when performing a call to obtain timeline stream -+ * statistics. -+ */ -+struct kbase_uk_tlstream_stats { -+ union uk_header header; /**< UK structure header. */ -+ /* IN */ -+ /* OUT */ -+ u32 bytes_collected; -+ u32 bytes_generated; -+}; -+#endif /* MALI_UNIT_TEST */ -+ -+/** -+ * struct struct kbase_uk_prfcnt_value for the KBASE_FUNC_SET_PRFCNT_VALUES ioctl -+ * @header: UK structure header -+ * @data: Counter samples for the dummy model -+ * @size:............Size of the counter sample data -+ */ -+struct kbase_uk_prfcnt_values { -+ union uk_header header; -+ /* IN */ -+ u32 *data; -+ u32 size; -+}; -+ -+/** -+ * struct kbase_uk_soft_event_update - User/Kernel space data exchange structure -+ * @header: UK structure header -+ * @evt: the GPU address containing the event -+ * @new_status: the new event status, must be either BASE_JD_SOFT_EVENT_SET or -+ * BASE_JD_SOFT_EVENT_RESET -+ * @flags: reserved for future uses, must be set to 0 -+ * -+ * This structure is used to update the status of a software event. If the -+ * event's status is set to BASE_JD_SOFT_EVENT_SET, any job currently waiting -+ * on this event will complete. -+ */ -+struct kbase_uk_soft_event_update { -+ union uk_header header; -+ /* IN */ -+ u64 evt; -+ u32 new_status; -+ u32 flags; -+}; -+ -+/** -+ * struct kbase_uk_mem_jit_init - User/Kernel space data exchange structure -+ * @header: UK structure header -+ * @va_pages: Number of virtual pages required for JIT -+ * -+ * This structure is used when requesting initialization of JIT. -+ */ -+struct kbase_uk_mem_jit_init { -+ union uk_header header; -+ /* IN */ -+ u64 va_pages; -+}; -+ -+enum kbase_uk_function_id { -+ KBASE_FUNC_MEM_ALLOC = (UK_FUNC_ID + 0), -+ KBASE_FUNC_MEM_IMPORT = (UK_FUNC_ID + 1), -+ KBASE_FUNC_MEM_COMMIT = (UK_FUNC_ID + 2), -+ KBASE_FUNC_MEM_QUERY = (UK_FUNC_ID + 3), -+ KBASE_FUNC_MEM_FREE = (UK_FUNC_ID + 4), -+ KBASE_FUNC_MEM_FLAGS_CHANGE = (UK_FUNC_ID + 5), -+ KBASE_FUNC_MEM_ALIAS = (UK_FUNC_ID + 6), -+ -+ /* UK_FUNC_ID + 7 not in use since BASE_LEGACY_UK6_SUPPORT dropped */ -+ -+ KBASE_FUNC_SYNC = (UK_FUNC_ID + 8), -+ -+ KBASE_FUNC_POST_TERM = (UK_FUNC_ID + 9), -+ -+ KBASE_FUNC_HWCNT_SETUP = (UK_FUNC_ID + 10), -+ KBASE_FUNC_HWCNT_DUMP = (UK_FUNC_ID + 11), -+ KBASE_FUNC_HWCNT_CLEAR = (UK_FUNC_ID + 12), -+ -+ KBASE_FUNC_GPU_PROPS_REG_DUMP = (UK_FUNC_ID + 14), -+ -+ KBASE_FUNC_FIND_CPU_OFFSET = (UK_FUNC_ID + 15), -+ -+ KBASE_FUNC_GET_VERSION = (UK_FUNC_ID + 16), -+ KBASE_FUNC_SET_FLAGS = (UK_FUNC_ID + 18), -+ -+ KBASE_FUNC_SET_TEST_DATA = (UK_FUNC_ID + 19), -+ KBASE_FUNC_INJECT_ERROR = (UK_FUNC_ID + 20), -+ KBASE_FUNC_MODEL_CONTROL = (UK_FUNC_ID + 21), -+ -+ /* UK_FUNC_ID + 22 not in use since BASE_LEGACY_UK8_SUPPORT dropped */ -+ -+ KBASE_FUNC_FENCE_VALIDATE = (UK_FUNC_ID + 23), -+ KBASE_FUNC_STREAM_CREATE = (UK_FUNC_ID + 24), -+ KBASE_FUNC_GET_PROFILING_CONTROLS = (UK_FUNC_ID + 25), -+ KBASE_FUNC_SET_PROFILING_CONTROLS = (UK_FUNC_ID + 26), -+ /* to be used only for testing -+ * purposes, otherwise these controls -+ * are set through gator API */ -+ -+ KBASE_FUNC_DEBUGFS_MEM_PROFILE_ADD = (UK_FUNC_ID + 27), -+ KBASE_FUNC_JOB_SUBMIT = (UK_FUNC_ID + 28), -+ KBASE_FUNC_DISJOINT_QUERY = (UK_FUNC_ID + 29), -+ -+ KBASE_FUNC_GET_CONTEXT_ID = (UK_FUNC_ID + 31), -+ -+ KBASE_FUNC_TLSTREAM_ACQUIRE_V10_4 = (UK_FUNC_ID + 32), -+#if MALI_UNIT_TEST -+ KBASE_FUNC_TLSTREAM_TEST = (UK_FUNC_ID + 33), -+ KBASE_FUNC_TLSTREAM_STATS = (UK_FUNC_ID + 34), -+#endif /* MALI_UNIT_TEST */ -+ KBASE_FUNC_TLSTREAM_FLUSH = (UK_FUNC_ID + 35), -+ -+ KBASE_FUNC_HWCNT_READER_SETUP = (UK_FUNC_ID + 36), -+ -+#ifdef SUPPORT_MALI_NO_MALI -+ KBASE_FUNC_SET_PRFCNT_VALUES = (UK_FUNC_ID + 37), -+#endif -+ -+ KBASE_FUNC_SOFT_EVENT_UPDATE = (UK_FUNC_ID + 38), -+ -+ KBASE_FUNC_MEM_JIT_INIT = (UK_FUNC_ID + 39), -+ -+ KBASE_FUNC_TLSTREAM_ACQUIRE = (UK_FUNC_ID + 40), -+ -+ KBASE_FUNC_MAX -+}; -+ -+#endif /* _KBASE_UKU_H_ */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_utility.c b/drivers/gpu/arm/midgard/mali_kbase_utility.c -new file mode 100644 -index 0000000..be474ff ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_utility.c -@@ -0,0 +1,33 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2013, 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+ -+bool kbasep_list_member_of(const struct list_head *base, struct list_head *entry) -+{ -+ struct list_head *pos = base->next; -+ -+ while (pos != base) { -+ if (pos == entry) -+ return true; -+ -+ pos = pos->next; -+ } -+ return false; -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_utility.h b/drivers/gpu/arm/midgard/mali_kbase_utility.h -new file mode 100644 -index 0000000..fd7252d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_utility.h -@@ -0,0 +1,37 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2013, 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KBASE_UTILITY_H -+#define _KBASE_UTILITY_H -+ -+#ifndef _KBASE_H_ -+#error "Don't include this file directly, use mali_kbase.h instead" -+#endif -+ -+/** Test whether the given list entry is a member of the given list. -+ * -+ * @param base The head of the list to be tested -+ * @param entry The list entry to be tested -+ * -+ * @return true if entry is a member of base -+ * false otherwise -+ */ -+bool kbasep_list_member_of(const struct list_head *base, struct list_head *entry); -+ -+#endif /* _KBASE_UTILITY_H */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_vinstr.c b/drivers/gpu/arm/midgard/mali_kbase_vinstr.c -new file mode 100644 -index 0000000..165841d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_vinstr.c -@@ -0,0 +1,2076 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/*****************************************************************************/ -+ -+/* Hwcnt reader API version */ -+#define HWCNT_READER_API 1 -+ -+/* The number of nanoseconds in a second. */ -+#define NSECS_IN_SEC 1000000000ull /* ns */ -+ -+/* The time resolution of dumping service. */ -+#define DUMPING_RESOLUTION 500000ull /* ns */ -+ -+/* The maximal supported number of dumping buffers. */ -+#define MAX_BUFFER_COUNT 32 -+ -+/* Size and number of hw counters blocks. */ -+#define NR_CNT_BLOCKS_PER_GROUP 8 -+#define NR_CNT_PER_BLOCK 64 -+#define NR_BYTES_PER_CNT 4 -+#define NR_BYTES_PER_HDR 16 -+#define PRFCNT_EN_MASK_OFFSET 0x8 -+ -+/*****************************************************************************/ -+ -+enum { -+ SHADER_HWCNT_BM, -+ TILER_HWCNT_BM, -+ MMU_L2_HWCNT_BM, -+ JM_HWCNT_BM -+}; -+ -+enum vinstr_state { -+ VINSTR_IDLE, -+ VINSTR_DUMPING, -+ VINSTR_SUSPENDING, -+ VINSTR_SUSPENDED, -+ VINSTR_RESUMING -+}; -+ -+/** -+ * struct kbase_vinstr_context - vinstr context per device -+ * @lock: protects the entire vinstr context -+ * @kbdev: pointer to kbase device -+ * @kctx: pointer to kbase context -+ * @vmap: vinstr vmap for mapping hwcnt dump buffer -+ * @gpu_va: GPU hwcnt dump buffer address -+ * @cpu_va: the CPU side mapping of the hwcnt dump buffer -+ * @dump_size: size of the dump buffer in bytes -+ * @bitmap: current set of counters monitored, not always in sync -+ * with hardware -+ * @reprogram: when true, reprogram hwcnt block with the new set of -+ * counters -+ * @state: vinstr state -+ * @state_lock: protects information about vinstr state -+ * @suspend_waitq: notification queue to trigger state re-validation -+ * @suspend_cnt: reference counter of vinstr's suspend state -+ * @suspend_work: worker to execute on entering suspended state -+ * @resume_work: worker to execute on leaving suspended state -+ * @nclients: number of attached clients, pending or otherwise -+ * @waiting_clients: head of list of clients being periodically sampled -+ * @idle_clients: head of list of clients being idle -+ * @suspended_clients: head of list of clients being suspended -+ * @thread: periodic sampling thread -+ * @waitq: notification queue of sampling thread -+ * @request_pending: request for action for sampling thread -+ * @clients_present: when true, we have at least one client -+ * Note: this variable is in sync. with nclients and is -+ * present to preserve simplicity. Protected by state_lock. -+ */ -+struct kbase_vinstr_context { -+ struct mutex lock; -+ struct kbase_device *kbdev; -+ struct kbase_context *kctx; -+ -+ struct kbase_vmap_struct vmap; -+ u64 gpu_va; -+ void *cpu_va; -+ size_t dump_size; -+ u32 bitmap[4]; -+ bool reprogram; -+ -+ enum vinstr_state state; -+ struct spinlock state_lock; -+ wait_queue_head_t suspend_waitq; -+ unsigned int suspend_cnt; -+ struct work_struct suspend_work; -+ struct work_struct resume_work; -+ -+ u32 nclients; -+ struct list_head waiting_clients; -+ struct list_head idle_clients; -+ struct list_head suspended_clients; -+ -+ struct task_struct *thread; -+ wait_queue_head_t waitq; -+ atomic_t request_pending; -+ -+ bool clients_present; -+}; -+ -+/** -+ * struct kbase_vinstr_client - a vinstr client attached to a vinstr context -+ * @vinstr_ctx: vinstr context client is attached to -+ * @list: node used to attach this client to list in vinstr context -+ * @buffer_count: number of buffers this client is using -+ * @event_mask: events this client reacts to -+ * @dump_size: size of one dump buffer in bytes -+ * @bitmap: bitmap request for JM, TILER, SHADER and MMU counters -+ * @legacy_buffer: userspace hwcnt dump buffer (legacy interface) -+ * @kernel_buffer: kernel hwcnt dump buffer (kernel client interface) -+ * @accum_buffer: temporary accumulation buffer for preserving counters -+ * @dump_time: next time this clients shall request hwcnt dump -+ * @dump_interval: interval between periodic hwcnt dumps -+ * @dump_buffers: kernel hwcnt dump buffers allocated by this client -+ * @dump_buffers_meta: metadata of dump buffers -+ * @meta_idx: index of metadata being accessed by userspace -+ * @read_idx: index of buffer read by userspace -+ * @write_idx: index of buffer being written by dumping service -+ * @waitq: client's notification queue -+ * @pending: when true, client has attached but hwcnt not yet updated -+ */ -+struct kbase_vinstr_client { -+ struct kbase_vinstr_context *vinstr_ctx; -+ struct list_head list; -+ unsigned int buffer_count; -+ u32 event_mask; -+ size_t dump_size; -+ u32 bitmap[4]; -+ void __user *legacy_buffer; -+ void *kernel_buffer; -+ void *accum_buffer; -+ u64 dump_time; -+ u32 dump_interval; -+ char *dump_buffers; -+ struct kbase_hwcnt_reader_metadata *dump_buffers_meta; -+ atomic_t meta_idx; -+ atomic_t read_idx; -+ atomic_t write_idx; -+ wait_queue_head_t waitq; -+ bool pending; -+}; -+ -+/** -+ * struct kbasep_vinstr_wake_up_timer - vinstr service thread wake up timer -+ * @hrtimer: high resolution timer -+ * @vinstr_ctx: vinstr context -+ */ -+struct kbasep_vinstr_wake_up_timer { -+ struct hrtimer hrtimer; -+ struct kbase_vinstr_context *vinstr_ctx; -+}; -+ -+/*****************************************************************************/ -+ -+static int kbasep_vinstr_service_task(void *data); -+ -+static unsigned int kbasep_vinstr_hwcnt_reader_poll( -+ struct file *filp, -+ poll_table *wait); -+static long kbasep_vinstr_hwcnt_reader_ioctl( -+ struct file *filp, -+ unsigned int cmd, -+ unsigned long arg); -+static int kbasep_vinstr_hwcnt_reader_mmap( -+ struct file *filp, -+ struct vm_area_struct *vma); -+static int kbasep_vinstr_hwcnt_reader_release( -+ struct inode *inode, -+ struct file *filp); -+ -+/* The timeline stream file operations structure. */ -+static const struct file_operations vinstr_client_fops = { -+ .poll = kbasep_vinstr_hwcnt_reader_poll, -+ .unlocked_ioctl = kbasep_vinstr_hwcnt_reader_ioctl, -+ .compat_ioctl = kbasep_vinstr_hwcnt_reader_ioctl, -+ .mmap = kbasep_vinstr_hwcnt_reader_mmap, -+ .release = kbasep_vinstr_hwcnt_reader_release, -+}; -+ -+/*****************************************************************************/ -+ -+static int enable_hwcnt(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_context *kctx = vinstr_ctx->kctx; -+ struct kbase_device *kbdev = kctx->kbdev; -+ struct kbase_uk_hwcnt_setup setup; -+ int err; -+ -+ setup.dump_buffer = vinstr_ctx->gpu_va; -+ setup.jm_bm = vinstr_ctx->bitmap[JM_HWCNT_BM]; -+ setup.tiler_bm = vinstr_ctx->bitmap[TILER_HWCNT_BM]; -+ setup.shader_bm = vinstr_ctx->bitmap[SHADER_HWCNT_BM]; -+ setup.mmu_l2_bm = vinstr_ctx->bitmap[MMU_L2_HWCNT_BM]; -+ -+ /* Mark the context as active so the GPU is kept turned on */ -+ /* A suspend won't happen here, because we're in a syscall from a -+ * userspace thread. */ -+ kbase_pm_context_active(kbdev); -+ -+ /* Schedule the context in */ -+ kbasep_js_schedule_privileged_ctx(kbdev, kctx); -+ err = kbase_instr_hwcnt_enable_internal(kbdev, kctx, &setup); -+ if (err) { -+ /* Release the context. This had its own Power Manager Active -+ * reference */ -+ kbasep_js_release_privileged_ctx(kbdev, kctx); -+ -+ /* Also release our Power Manager Active reference */ -+ kbase_pm_context_idle(kbdev); -+ } -+ -+ return err; -+} -+ -+static void disable_hwcnt(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_context *kctx = vinstr_ctx->kctx; -+ struct kbase_device *kbdev = kctx->kbdev; -+ int err; -+ -+ err = kbase_instr_hwcnt_disable_internal(kctx); -+ if (err) { -+ dev_warn(kbdev->dev, "Failed to disable HW counters (ctx:%p)", -+ kctx); -+ return; -+ } -+ -+ /* Release the context. This had its own Power Manager Active reference. */ -+ kbasep_js_release_privileged_ctx(kbdev, kctx); -+ -+ /* Also release our Power Manager Active reference. */ -+ kbase_pm_context_idle(kbdev); -+ -+ dev_dbg(kbdev->dev, "HW counters dumping disabled for context %p", kctx); -+} -+ -+static int reprogram_hwcnt(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ disable_hwcnt(vinstr_ctx); -+ return enable_hwcnt(vinstr_ctx); -+} -+ -+static void hwcnt_bitmap_set(u32 dst[4], u32 src[4]) -+{ -+ dst[JM_HWCNT_BM] = src[JM_HWCNT_BM]; -+ dst[TILER_HWCNT_BM] = src[TILER_HWCNT_BM]; -+ dst[SHADER_HWCNT_BM] = src[SHADER_HWCNT_BM]; -+ dst[MMU_L2_HWCNT_BM] = src[MMU_L2_HWCNT_BM]; -+} -+ -+static void hwcnt_bitmap_union(u32 dst[4], u32 src[4]) -+{ -+ dst[JM_HWCNT_BM] |= src[JM_HWCNT_BM]; -+ dst[TILER_HWCNT_BM] |= src[TILER_HWCNT_BM]; -+ dst[SHADER_HWCNT_BM] |= src[SHADER_HWCNT_BM]; -+ dst[MMU_L2_HWCNT_BM] |= src[MMU_L2_HWCNT_BM]; -+} -+ -+size_t kbase_vinstr_dump_size(struct kbase_device *kbdev) -+{ -+ size_t dump_size; -+ -+#ifndef CONFIG_MALI_NO_MALI -+ if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_V4)) { -+ u32 nr_cg; -+ -+ nr_cg = kbdev->gpu_props.num_core_groups; -+ dump_size = nr_cg * NR_CNT_BLOCKS_PER_GROUP * -+ NR_CNT_PER_BLOCK * -+ NR_BYTES_PER_CNT; -+ } else -+#endif /* CONFIG_MALI_NO_MALI */ -+ { -+ /* assume v5 for now */ -+ base_gpu_props *props = &kbdev->gpu_props.props; -+ u32 nr_l2 = props->l2_props.num_l2_slices; -+ u64 core_mask = props->coherency_info.group[0].core_mask; -+ u32 nr_blocks = fls64(core_mask); -+ -+ /* JM and tiler counter blocks are always present */ -+ dump_size = (2 + nr_l2 + nr_blocks) * -+ NR_CNT_PER_BLOCK * -+ NR_BYTES_PER_CNT; -+ } -+ return dump_size; -+} -+KBASE_EXPORT_TEST_API(kbase_vinstr_dump_size); -+ -+static size_t kbasep_vinstr_dump_size_ctx( -+ struct kbase_vinstr_context *vinstr_ctx) -+{ -+ return kbase_vinstr_dump_size(vinstr_ctx->kctx->kbdev); -+} -+ -+static int kbasep_vinstr_map_kernel_dump_buffer( -+ struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_va_region *reg; -+ struct kbase_context *kctx = vinstr_ctx->kctx; -+ u64 flags, nr_pages; -+ -+ flags = BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_GPU_WR; -+ vinstr_ctx->dump_size = kbasep_vinstr_dump_size_ctx(vinstr_ctx); -+ nr_pages = PFN_UP(vinstr_ctx->dump_size); -+ -+ reg = kbase_mem_alloc(kctx, nr_pages, nr_pages, 0, &flags, -+ &vinstr_ctx->gpu_va); -+ if (!reg) -+ return -ENOMEM; -+ -+ vinstr_ctx->cpu_va = kbase_vmap( -+ kctx, -+ vinstr_ctx->gpu_va, -+ vinstr_ctx->dump_size, -+ &vinstr_ctx->vmap); -+ if (!vinstr_ctx->cpu_va) { -+ kbase_mem_free(kctx, vinstr_ctx->gpu_va); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static void kbasep_vinstr_unmap_kernel_dump_buffer( -+ struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_context *kctx = vinstr_ctx->kctx; -+ -+ kbase_vunmap(kctx, &vinstr_ctx->vmap); -+ kbase_mem_free(kctx, vinstr_ctx->gpu_va); -+} -+ -+/** -+ * kbasep_vinstr_create_kctx - create kernel context for vinstr -+ * @vinstr_ctx: vinstr context -+ * Return: zero on success -+ */ -+static int kbasep_vinstr_create_kctx(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_device *kbdev = vinstr_ctx->kbdev; -+ struct kbasep_kctx_list_element *element; -+ unsigned long flags; -+ bool enable_backend = false; -+ int err; -+ -+ vinstr_ctx->kctx = kbase_create_context(vinstr_ctx->kbdev, true); -+ if (!vinstr_ctx->kctx) -+ return -ENOMEM; -+ -+ /* Map the master kernel dump buffer. The HW dumps the counters -+ * into this memory region. */ -+ err = kbasep_vinstr_map_kernel_dump_buffer(vinstr_ctx); -+ if (err) { -+ kbase_destroy_context(vinstr_ctx->kctx); -+ vinstr_ctx->kctx = NULL; -+ return err; -+ } -+ -+ /* Add kernel context to list of contexts associated with device. */ -+ element = kzalloc(sizeof(*element), GFP_KERNEL); -+ if (element) { -+ element->kctx = vinstr_ctx->kctx; -+ mutex_lock(&kbdev->kctx_list_lock); -+ list_add(&element->link, &kbdev->kctx_list); -+ -+ /* Inform timeline client about new context. -+ * Do this while holding the lock to avoid tracepoint -+ * being created in both body and summary stream. */ -+ KBASE_TLSTREAM_TL_NEW_CTX( -+ vinstr_ctx->kctx, -+ (u32)(vinstr_ctx->kctx->id), -+ (u32)(vinstr_ctx->kctx->tgid)); -+ -+ mutex_unlock(&kbdev->kctx_list_lock); -+ } else { -+ /* Don't treat this as a fail - just warn about it. */ -+ dev_warn(kbdev->dev, -+ "couldn't add kctx to kctx_list\n"); -+ } -+ -+ /* Don't enable hardware counters if vinstr is suspended. -+ * Note that vinstr resume code is run under vinstr context lock, -+ * lower layer will be enabled as needed on resume. */ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ if (VINSTR_IDLE == vinstr_ctx->state) -+ enable_backend = true; -+ vinstr_ctx->clients_present = true; -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ if (enable_backend) -+ err = enable_hwcnt(vinstr_ctx); -+ -+ if (err) { -+ kbasep_vinstr_unmap_kernel_dump_buffer(vinstr_ctx); -+ kbase_destroy_context(vinstr_ctx->kctx); -+ if (element) { -+ mutex_lock(&kbdev->kctx_list_lock); -+ list_del(&element->link); -+ kfree(element); -+ mutex_unlock(&kbdev->kctx_list_lock); -+ } -+ KBASE_TLSTREAM_TL_DEL_CTX(vinstr_ctx->kctx); -+ vinstr_ctx->kctx = NULL; -+ return err; -+ } -+ -+ vinstr_ctx->thread = kthread_run( -+ kbasep_vinstr_service_task, -+ vinstr_ctx, -+ "mali_vinstr_service"); -+ if (IS_ERR(vinstr_ctx->thread)) { -+ disable_hwcnt(vinstr_ctx); -+ kbasep_vinstr_unmap_kernel_dump_buffer(vinstr_ctx); -+ kbase_destroy_context(vinstr_ctx->kctx); -+ if (element) { -+ mutex_lock(&kbdev->kctx_list_lock); -+ list_del(&element->link); -+ kfree(element); -+ mutex_unlock(&kbdev->kctx_list_lock); -+ } -+ KBASE_TLSTREAM_TL_DEL_CTX(vinstr_ctx->kctx); -+ vinstr_ctx->kctx = NULL; -+ return -EFAULT; -+ } -+ -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_destroy_kctx - destroy vinstr's kernel context -+ * @vinstr_ctx: vinstr context -+ */ -+static void kbasep_vinstr_destroy_kctx(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_device *kbdev = vinstr_ctx->kbdev; -+ struct kbasep_kctx_list_element *element; -+ struct kbasep_kctx_list_element *tmp; -+ bool found = false; -+ unsigned long flags; -+ -+ /* Release hw counters dumping resources. */ -+ vinstr_ctx->thread = NULL; -+ disable_hwcnt(vinstr_ctx); -+ kbasep_vinstr_unmap_kernel_dump_buffer(vinstr_ctx); -+ kbase_destroy_context(vinstr_ctx->kctx); -+ -+ /* Simplify state transitions by specifying that we have no clients. */ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ vinstr_ctx->clients_present = false; -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ -+ /* Remove kernel context from the device's contexts list. */ -+ mutex_lock(&kbdev->kctx_list_lock); -+ list_for_each_entry_safe(element, tmp, &kbdev->kctx_list, link) { -+ if (element->kctx == vinstr_ctx->kctx) { -+ list_del(&element->link); -+ kfree(element); -+ found = true; -+ } -+ } -+ mutex_unlock(&kbdev->kctx_list_lock); -+ -+ if (!found) -+ dev_warn(kbdev->dev, "kctx not in kctx_list\n"); -+ -+ /* Inform timeline client about context destruction. */ -+ KBASE_TLSTREAM_TL_DEL_CTX(vinstr_ctx->kctx); -+ -+ vinstr_ctx->kctx = NULL; -+} -+ -+/** -+ * kbasep_vinstr_attach_client - Attach a client to the vinstr core -+ * @vinstr_ctx: vinstr context -+ * @buffer_count: requested number of dump buffers -+ * @bitmap: bitmaps describing which counters should be enabled -+ * @argp: pointer where notification descriptor shall be stored -+ * @kernel_buffer: pointer to kernel side buffer -+ * -+ * Return: vinstr opaque client handle or NULL on failure -+ */ -+static struct kbase_vinstr_client *kbasep_vinstr_attach_client( -+ struct kbase_vinstr_context *vinstr_ctx, u32 buffer_count, -+ u32 bitmap[4], void *argp, void *kernel_buffer) -+{ -+ struct task_struct *thread = NULL; -+ struct kbase_vinstr_client *cli; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ if (buffer_count > MAX_BUFFER_COUNT -+ || (buffer_count & (buffer_count - 1))) -+ return NULL; -+ -+ cli = kzalloc(sizeof(*cli), GFP_KERNEL); -+ if (!cli) -+ return NULL; -+ -+ cli->vinstr_ctx = vinstr_ctx; -+ cli->buffer_count = buffer_count; -+ cli->event_mask = -+ (1 << BASE_HWCNT_READER_EVENT_MANUAL) | -+ (1 << BASE_HWCNT_READER_EVENT_PERIODIC); -+ cli->pending = true; -+ -+ hwcnt_bitmap_set(cli->bitmap, bitmap); -+ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ hwcnt_bitmap_union(vinstr_ctx->bitmap, cli->bitmap); -+ vinstr_ctx->reprogram = true; -+ -+ /* If this is the first client, create the vinstr kbase -+ * context. This context is permanently resident until the -+ * last client exits. */ -+ if (!vinstr_ctx->nclients) { -+ hwcnt_bitmap_set(vinstr_ctx->bitmap, cli->bitmap); -+ if (kbasep_vinstr_create_kctx(vinstr_ctx) < 0) -+ goto error; -+ -+ vinstr_ctx->reprogram = false; -+ cli->pending = false; -+ } -+ -+ /* The GPU resets the counter block every time there is a request -+ * to dump it. We need a per client kernel buffer for accumulating -+ * the counters. */ -+ cli->dump_size = kbasep_vinstr_dump_size_ctx(vinstr_ctx); -+ cli->accum_buffer = kzalloc(cli->dump_size, GFP_KERNEL); -+ if (!cli->accum_buffer) -+ goto error; -+ -+ /* Prepare buffers. */ -+ if (cli->buffer_count) { -+ int *fd = (int *)argp; -+ size_t tmp; -+ -+ /* Allocate area for buffers metadata storage. */ -+ tmp = sizeof(struct kbase_hwcnt_reader_metadata) * -+ cli->buffer_count; -+ cli->dump_buffers_meta = kmalloc(tmp, GFP_KERNEL); -+ if (!cli->dump_buffers_meta) -+ goto error; -+ -+ /* Allocate required number of dumping buffers. */ -+ cli->dump_buffers = (char *)__get_free_pages( -+ GFP_KERNEL | __GFP_ZERO, -+ get_order(cli->dump_size * cli->buffer_count)); -+ if (!cli->dump_buffers) -+ goto error; -+ -+ /* Create descriptor for user-kernel data exchange. */ -+ *fd = anon_inode_getfd( -+ "[mali_vinstr_desc]", -+ &vinstr_client_fops, -+ cli, -+ O_RDONLY | O_CLOEXEC); -+ if (0 > *fd) -+ goto error; -+ } else if (kernel_buffer) { -+ cli->kernel_buffer = kernel_buffer; -+ } else { -+ cli->legacy_buffer = (void __user *)argp; -+ } -+ -+ atomic_set(&cli->read_idx, 0); -+ atomic_set(&cli->meta_idx, 0); -+ atomic_set(&cli->write_idx, 0); -+ init_waitqueue_head(&cli->waitq); -+ -+ vinstr_ctx->nclients++; -+ list_add(&cli->list, &vinstr_ctx->idle_clients); -+ -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ return cli; -+ -+error: -+ kfree(cli->dump_buffers_meta); -+ if (cli->dump_buffers) -+ free_pages( -+ (unsigned long)cli->dump_buffers, -+ get_order(cli->dump_size * cli->buffer_count)); -+ kfree(cli->accum_buffer); -+ if (!vinstr_ctx->nclients && vinstr_ctx->kctx) { -+ thread = vinstr_ctx->thread; -+ kbasep_vinstr_destroy_kctx(vinstr_ctx); -+ } -+ kfree(cli); -+ -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ /* Thread must be stopped after lock is released. */ -+ if (thread) -+ kthread_stop(thread); -+ -+ return NULL; -+} -+ -+void kbase_vinstr_detach_client(struct kbase_vinstr_client *cli) -+{ -+ struct kbase_vinstr_context *vinstr_ctx; -+ struct kbase_vinstr_client *iter, *tmp; -+ struct task_struct *thread = NULL; -+ u32 zerobitmap[4] = { 0 }; -+ int cli_found = 0; -+ -+ KBASE_DEBUG_ASSERT(cli); -+ vinstr_ctx = cli->vinstr_ctx; -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ list_for_each_entry_safe(iter, tmp, &vinstr_ctx->idle_clients, list) { -+ if (iter == cli) { -+ vinstr_ctx->reprogram = true; -+ cli_found = 1; -+ list_del(&iter->list); -+ break; -+ } -+ } -+ if (!cli_found) { -+ list_for_each_entry_safe( -+ iter, tmp, &vinstr_ctx->waiting_clients, list) { -+ if (iter == cli) { -+ vinstr_ctx->reprogram = true; -+ cli_found = 1; -+ list_del(&iter->list); -+ break; -+ } -+ } -+ } -+ KBASE_DEBUG_ASSERT(cli_found); -+ -+ kfree(cli->dump_buffers_meta); -+ free_pages( -+ (unsigned long)cli->dump_buffers, -+ get_order(cli->dump_size * cli->buffer_count)); -+ kfree(cli->accum_buffer); -+ kfree(cli); -+ -+ vinstr_ctx->nclients--; -+ if (!vinstr_ctx->nclients) { -+ thread = vinstr_ctx->thread; -+ kbasep_vinstr_destroy_kctx(vinstr_ctx); -+ } -+ -+ /* Rebuild context bitmap now that the client has detached */ -+ hwcnt_bitmap_set(vinstr_ctx->bitmap, zerobitmap); -+ list_for_each_entry(iter, &vinstr_ctx->idle_clients, list) -+ hwcnt_bitmap_union(vinstr_ctx->bitmap, iter->bitmap); -+ list_for_each_entry(iter, &vinstr_ctx->waiting_clients, list) -+ hwcnt_bitmap_union(vinstr_ctx->bitmap, iter->bitmap); -+ -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ /* Thread must be stopped after lock is released. */ -+ if (thread) -+ kthread_stop(thread); -+} -+KBASE_EXPORT_TEST_API(kbase_vinstr_detach_client); -+ -+/* Accumulate counters in the dump buffer */ -+static void accum_dump_buffer(void *dst, void *src, size_t dump_size) -+{ -+ size_t block_size = NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT; -+ u32 *d = dst; -+ u32 *s = src; -+ size_t i, j; -+ -+ for (i = 0; i < dump_size; i += block_size) { -+ /* skip over the header block */ -+ d += NR_BYTES_PER_HDR / sizeof(u32); -+ s += NR_BYTES_PER_HDR / sizeof(u32); -+ for (j = 0; j < (block_size - NR_BYTES_PER_HDR) / sizeof(u32); j++) { -+ /* saturate result if addition would result in wraparound */ -+ if (U32_MAX - *d < *s) -+ *d = U32_MAX; -+ else -+ *d += *s; -+ d++; -+ s++; -+ } -+ } -+} -+ -+/* This is the Midgard v4 patch function. It copies the headers for each -+ * of the defined blocks from the master kernel buffer and then patches up -+ * the performance counter enable mask for each of the blocks to exclude -+ * counters that were not requested by the client. */ -+static void patch_dump_buffer_hdr_v4( -+ struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_vinstr_client *cli) -+{ -+ u32 *mask; -+ u8 *dst = cli->accum_buffer; -+ u8 *src = vinstr_ctx->cpu_va; -+ u32 nr_cg = vinstr_ctx->kctx->kbdev->gpu_props.num_core_groups; -+ size_t i, group_size, group; -+ enum { -+ SC0_BASE = 0 * NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT, -+ SC1_BASE = 1 * NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT, -+ SC2_BASE = 2 * NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT, -+ SC3_BASE = 3 * NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT, -+ TILER_BASE = 4 * NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT, -+ MMU_L2_BASE = 5 * NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT, -+ JM_BASE = 7 * NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT -+ }; -+ -+ group_size = NR_CNT_BLOCKS_PER_GROUP * -+ NR_CNT_PER_BLOCK * -+ NR_BYTES_PER_CNT; -+ for (i = 0; i < nr_cg; i++) { -+ group = i * group_size; -+ /* copy shader core headers */ -+ memcpy(&dst[group + SC0_BASE], &src[group + SC0_BASE], -+ NR_BYTES_PER_HDR); -+ memcpy(&dst[group + SC1_BASE], &src[group + SC1_BASE], -+ NR_BYTES_PER_HDR); -+ memcpy(&dst[group + SC2_BASE], &src[group + SC2_BASE], -+ NR_BYTES_PER_HDR); -+ memcpy(&dst[group + SC3_BASE], &src[group + SC3_BASE], -+ NR_BYTES_PER_HDR); -+ -+ /* copy tiler header */ -+ memcpy(&dst[group + TILER_BASE], &src[group + TILER_BASE], -+ NR_BYTES_PER_HDR); -+ -+ /* copy mmu header */ -+ memcpy(&dst[group + MMU_L2_BASE], &src[group + MMU_L2_BASE], -+ NR_BYTES_PER_HDR); -+ -+ /* copy job manager header */ -+ memcpy(&dst[group + JM_BASE], &src[group + JM_BASE], -+ NR_BYTES_PER_HDR); -+ -+ /* patch the shader core enable mask */ -+ mask = (u32 *)&dst[group + SC0_BASE + PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[SHADER_HWCNT_BM]; -+ mask = (u32 *)&dst[group + SC1_BASE + PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[SHADER_HWCNT_BM]; -+ mask = (u32 *)&dst[group + SC2_BASE + PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[SHADER_HWCNT_BM]; -+ mask = (u32 *)&dst[group + SC3_BASE + PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[SHADER_HWCNT_BM]; -+ -+ /* patch the tiler core enable mask */ -+ mask = (u32 *)&dst[group + TILER_BASE + PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[TILER_HWCNT_BM]; -+ -+ /* patch the mmu core enable mask */ -+ mask = (u32 *)&dst[group + MMU_L2_BASE + PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[MMU_L2_HWCNT_BM]; -+ -+ /* patch the job manager enable mask */ -+ mask = (u32 *)&dst[group + JM_BASE + PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[JM_HWCNT_BM]; -+ } -+} -+ -+/* This is the Midgard v5 patch function. It copies the headers for each -+ * of the defined blocks from the master kernel buffer and then patches up -+ * the performance counter enable mask for each of the blocks to exclude -+ * counters that were not requested by the client. */ -+static void patch_dump_buffer_hdr_v5( -+ struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_vinstr_client *cli) -+{ -+ struct kbase_device *kbdev = vinstr_ctx->kctx->kbdev; -+ u32 i, nr_l2; -+ u64 core_mask; -+ u32 *mask; -+ u8 *dst = cli->accum_buffer; -+ u8 *src = vinstr_ctx->cpu_va; -+ size_t block_size = NR_CNT_PER_BLOCK * NR_BYTES_PER_CNT; -+ -+ /* copy and patch job manager header */ -+ memcpy(dst, src, NR_BYTES_PER_HDR); -+ mask = (u32 *)&dst[PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[JM_HWCNT_BM]; -+ dst += block_size; -+ src += block_size; -+ -+ /* copy and patch tiler header */ -+ memcpy(dst, src, NR_BYTES_PER_HDR); -+ mask = (u32 *)&dst[PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[TILER_HWCNT_BM]; -+ dst += block_size; -+ src += block_size; -+ -+ /* copy and patch MMU/L2C headers */ -+ nr_l2 = kbdev->gpu_props.props.l2_props.num_l2_slices; -+ for (i = 0; i < nr_l2; i++) { -+ memcpy(dst, src, NR_BYTES_PER_HDR); -+ mask = (u32 *)&dst[PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[MMU_L2_HWCNT_BM]; -+ dst += block_size; -+ src += block_size; -+ } -+ -+ /* copy and patch shader core headers */ -+ core_mask = kbdev->gpu_props.props.coherency_info.group[0].core_mask; -+ while (0ull != core_mask) { -+ memcpy(dst, src, NR_BYTES_PER_HDR); -+ if (0ull != (core_mask & 1ull)) { -+ /* if block is not reserved update header */ -+ mask = (u32 *)&dst[PRFCNT_EN_MASK_OFFSET]; -+ *mask &= cli->bitmap[SHADER_HWCNT_BM]; -+ } -+ dst += block_size; -+ src += block_size; -+ -+ core_mask >>= 1; -+ } -+} -+ -+/** -+ * accum_clients - accumulate dumped hw counters for all known clients -+ * @vinstr_ctx: vinstr context -+ */ -+static void accum_clients(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_vinstr_client *iter; -+ int v4 = 0; -+ -+#ifndef CONFIG_MALI_NO_MALI -+ v4 = kbase_hw_has_feature(vinstr_ctx->kbdev, BASE_HW_FEATURE_V4); -+#endif -+ -+ list_for_each_entry(iter, &vinstr_ctx->idle_clients, list) { -+ /* Don't bother accumulating clients whose hwcnt requests -+ * have not yet been honoured. */ -+ if (iter->pending) -+ continue; -+ if (v4) -+ patch_dump_buffer_hdr_v4(vinstr_ctx, iter); -+ else -+ patch_dump_buffer_hdr_v5(vinstr_ctx, iter); -+ accum_dump_buffer( -+ iter->accum_buffer, -+ vinstr_ctx->cpu_va, -+ iter->dump_size); -+ } -+ list_for_each_entry(iter, &vinstr_ctx->waiting_clients, list) { -+ /* Don't bother accumulating clients whose hwcnt requests -+ * have not yet been honoured. */ -+ if (iter->pending) -+ continue; -+ if (v4) -+ patch_dump_buffer_hdr_v4(vinstr_ctx, iter); -+ else -+ patch_dump_buffer_hdr_v5(vinstr_ctx, iter); -+ accum_dump_buffer( -+ iter->accum_buffer, -+ vinstr_ctx->cpu_va, -+ iter->dump_size); -+ } -+} -+ -+/*****************************************************************************/ -+ -+/** -+ * kbasep_vinstr_get_timestamp - return timestamp -+ * -+ * Function returns timestamp value based on raw monotonic timer. Value will -+ * wrap around zero in case of overflow. -+ * -+ * Return: timestamp value -+ */ -+static u64 kbasep_vinstr_get_timestamp(void) -+{ -+ struct timespec ts; -+ -+ getrawmonotonic(&ts); -+ return (u64)ts.tv_sec * NSECS_IN_SEC + ts.tv_nsec; -+} -+ -+/** -+ * kbasep_vinstr_add_dump_request - register client's dumping request -+ * @cli: requesting client -+ * @waiting_clients: list of pending dumping requests -+ */ -+static void kbasep_vinstr_add_dump_request( -+ struct kbase_vinstr_client *cli, -+ struct list_head *waiting_clients) -+{ -+ struct kbase_vinstr_client *tmp; -+ -+ if (list_empty(waiting_clients)) { -+ list_add(&cli->list, waiting_clients); -+ return; -+ } -+ list_for_each_entry(tmp, waiting_clients, list) { -+ if (tmp->dump_time > cli->dump_time) { -+ list_add_tail(&cli->list, &tmp->list); -+ return; -+ } -+ } -+ list_add_tail(&cli->list, waiting_clients); -+} -+ -+/** -+ * kbasep_vinstr_collect_and_accumulate - collect hw counters via low level -+ * dump and accumulate them for known -+ * clients -+ * @vinstr_ctx: vinstr context -+ * @timestamp: pointer where collection timestamp will be recorded -+ * -+ * Return: zero on success -+ */ -+static int kbasep_vinstr_collect_and_accumulate( -+ struct kbase_vinstr_context *vinstr_ctx, u64 *timestamp) -+{ -+ unsigned long flags; -+ int rcode; -+ -+#ifdef CONFIG_MALI_NO_MALI -+ /* The dummy model needs the CPU mapping. */ -+ gpu_model_set_dummy_prfcnt_base_cpu(vinstr_ctx->cpu_va); -+#endif -+ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ if (VINSTR_IDLE != vinstr_ctx->state) { -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ return -EAGAIN; -+ } else { -+ vinstr_ctx->state = VINSTR_DUMPING; -+ } -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ -+ /* Request HW counters dump. -+ * Disable preemption to make dump timestamp more accurate. */ -+ preempt_disable(); -+ *timestamp = kbasep_vinstr_get_timestamp(); -+ rcode = kbase_instr_hwcnt_request_dump(vinstr_ctx->kctx); -+ preempt_enable(); -+ -+ if (!rcode) -+ rcode = kbase_instr_hwcnt_wait_for_dump(vinstr_ctx->kctx); -+ WARN_ON(rcode); -+ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ switch (vinstr_ctx->state) -+ { -+ case VINSTR_SUSPENDING: -+ schedule_work(&vinstr_ctx->suspend_work); -+ break; -+ case VINSTR_DUMPING: -+ vinstr_ctx->state = VINSTR_IDLE; -+ wake_up_all(&vinstr_ctx->suspend_waitq); -+ break; -+ default: -+ break; -+ } -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ -+ /* Accumulate values of collected counters. */ -+ if (!rcode) -+ accum_clients(vinstr_ctx); -+ -+ return rcode; -+} -+ -+/** -+ * kbasep_vinstr_fill_dump_buffer - copy accumulated counters to empty kernel -+ * buffer -+ * @cli: requesting client -+ * @timestamp: timestamp when counters were collected -+ * @event_id: id of event that caused triggered counters collection -+ * -+ * Return: zero on success -+ */ -+static int kbasep_vinstr_fill_dump_buffer( -+ struct kbase_vinstr_client *cli, u64 timestamp, -+ enum base_hwcnt_reader_event event_id) -+{ -+ unsigned int write_idx = atomic_read(&cli->write_idx); -+ unsigned int read_idx = atomic_read(&cli->read_idx); -+ -+ struct kbase_hwcnt_reader_metadata *meta; -+ void *buffer; -+ -+ /* Check if there is a place to copy HWC block into. */ -+ if (write_idx - read_idx == cli->buffer_count) -+ return -1; -+ write_idx %= cli->buffer_count; -+ -+ /* Fill in dump buffer and its metadata. */ -+ buffer = &cli->dump_buffers[write_idx * cli->dump_size]; -+ meta = &cli->dump_buffers_meta[write_idx]; -+ meta->timestamp = timestamp; -+ meta->event_id = event_id; -+ meta->buffer_idx = write_idx; -+ memcpy(buffer, cli->accum_buffer, cli->dump_size); -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_fill_dump_buffer_legacy - copy accumulated counters to buffer -+ * allocated in userspace -+ * @cli: requesting client -+ * -+ * Return: zero on success -+ * -+ * This is part of legacy ioctl interface. -+ */ -+static int kbasep_vinstr_fill_dump_buffer_legacy( -+ struct kbase_vinstr_client *cli) -+{ -+ void __user *buffer = cli->legacy_buffer; -+ int rcode; -+ -+ /* Copy data to user buffer. */ -+ rcode = copy_to_user(buffer, cli->accum_buffer, cli->dump_size); -+ if (rcode) { -+ pr_warn("error while copying buffer to user\n"); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_fill_dump_buffer_kernel - copy accumulated counters to buffer -+ * allocated in kernel space -+ * @cli: requesting client -+ * -+ * Return: zero on success -+ * -+ * This is part of the kernel client interface. -+ */ -+static int kbasep_vinstr_fill_dump_buffer_kernel( -+ struct kbase_vinstr_client *cli) -+{ -+ memcpy(cli->kernel_buffer, cli->accum_buffer, cli->dump_size); -+ -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_reprogram - reprogram hwcnt set collected by inst -+ * @vinstr_ctx: vinstr context -+ */ -+static void kbasep_vinstr_reprogram( -+ struct kbase_vinstr_context *vinstr_ctx) -+{ -+ unsigned long flags; -+ bool suspended = false; -+ -+ /* Don't enable hardware counters if vinstr is suspended. */ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ if (VINSTR_IDLE != vinstr_ctx->state) -+ suspended = true; -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ if (suspended) -+ return; -+ -+ /* Change to suspended state is done while holding vinstr context -+ * lock. Below code will then no re-enable the instrumentation. */ -+ -+ if (vinstr_ctx->reprogram) { -+ struct kbase_vinstr_client *iter; -+ -+ if (!reprogram_hwcnt(vinstr_ctx)) { -+ vinstr_ctx->reprogram = false; -+ list_for_each_entry( -+ iter, -+ &vinstr_ctx->idle_clients, -+ list) -+ iter->pending = false; -+ list_for_each_entry( -+ iter, -+ &vinstr_ctx->waiting_clients, -+ list) -+ iter->pending = false; -+ } -+ } -+} -+ -+/** -+ * kbasep_vinstr_update_client - copy accumulated counters to user readable -+ * buffer and notify the user -+ * @cli: requesting client -+ * @timestamp: timestamp when counters were collected -+ * @event_id: id of event that caused triggered counters collection -+ * -+ * Return: zero on success -+ */ -+static int kbasep_vinstr_update_client( -+ struct kbase_vinstr_client *cli, u64 timestamp, -+ enum base_hwcnt_reader_event event_id) -+{ -+ int rcode = 0; -+ -+ /* Copy collected counters to user readable buffer. */ -+ if (cli->buffer_count) -+ rcode = kbasep_vinstr_fill_dump_buffer( -+ cli, timestamp, event_id); -+ else if (cli->kernel_buffer) -+ rcode = kbasep_vinstr_fill_dump_buffer_kernel(cli); -+ else -+ rcode = kbasep_vinstr_fill_dump_buffer_legacy(cli); -+ -+ if (rcode) -+ goto exit; -+ -+ -+ /* Notify client. Make sure all changes to memory are visible. */ -+ wmb(); -+ atomic_inc(&cli->write_idx); -+ wake_up_interruptible(&cli->waitq); -+ -+ /* Prepare for next request. */ -+ memset(cli->accum_buffer, 0, cli->dump_size); -+ -+exit: -+ return rcode; -+} -+ -+/** -+ * kbasep_vinstr_wake_up_callback - vinstr wake up timer wake up function -+ * -+ * @hrtimer: high resolution timer -+ * -+ * Return: High resolution timer restart enum. -+ */ -+static enum hrtimer_restart kbasep_vinstr_wake_up_callback( -+ struct hrtimer *hrtimer) -+{ -+ struct kbasep_vinstr_wake_up_timer *timer = -+ container_of( -+ hrtimer, -+ struct kbasep_vinstr_wake_up_timer, -+ hrtimer); -+ -+ KBASE_DEBUG_ASSERT(timer); -+ -+ atomic_set(&timer->vinstr_ctx->request_pending, 1); -+ wake_up_all(&timer->vinstr_ctx->waitq); -+ -+ return HRTIMER_NORESTART; -+} -+ -+/** -+ * kbasep_vinstr_service_task - HWC dumping service thread -+ * -+ * @data: Pointer to vinstr context structure. -+ * -+ * Return: 0 on success; -ENOMEM if timer allocation fails -+ */ -+static int kbasep_vinstr_service_task(void *data) -+{ -+ struct kbase_vinstr_context *vinstr_ctx = data; -+ struct kbasep_vinstr_wake_up_timer *timer; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ timer = kmalloc(sizeof(*timer), GFP_KERNEL); -+ -+ if (!timer) { -+ dev_warn(vinstr_ctx->kbdev->dev, "Timer allocation failed!\n"); -+ return -ENOMEM; -+ } -+ -+ hrtimer_init(&timer->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ -+ timer->hrtimer.function = kbasep_vinstr_wake_up_callback; -+ timer->vinstr_ctx = vinstr_ctx; -+ -+ while (!kthread_should_stop()) { -+ struct kbase_vinstr_client *cli = NULL; -+ struct kbase_vinstr_client *tmp; -+ int rcode; -+ -+ u64 timestamp = kbasep_vinstr_get_timestamp(); -+ u64 dump_time = 0; -+ struct list_head expired_requests; -+ -+ /* Hold lock while performing operations on lists of clients. */ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ /* Closing thread must not interact with client requests. */ -+ if (current == vinstr_ctx->thread) { -+ atomic_set(&vinstr_ctx->request_pending, 0); -+ -+ if (!list_empty(&vinstr_ctx->waiting_clients)) { -+ cli = list_first_entry( -+ &vinstr_ctx->waiting_clients, -+ struct kbase_vinstr_client, -+ list); -+ dump_time = cli->dump_time; -+ } -+ } -+ -+ if (!cli || ((s64)timestamp - (s64)dump_time < 0ll)) { -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ /* Sleep until next dumping event or service request. */ -+ if (cli) { -+ u64 diff = dump_time - timestamp; -+ -+ hrtimer_start( -+ &timer->hrtimer, -+ ns_to_ktime(diff), -+ HRTIMER_MODE_REL); -+ } -+ wait_event( -+ vinstr_ctx->waitq, -+ atomic_read( -+ &vinstr_ctx->request_pending) || -+ kthread_should_stop()); -+ hrtimer_cancel(&timer->hrtimer); -+ continue; -+ } -+ -+ rcode = kbasep_vinstr_collect_and_accumulate(vinstr_ctx, -+ ×tamp); -+ -+ INIT_LIST_HEAD(&expired_requests); -+ -+ /* Find all expired requests. */ -+ list_for_each_entry_safe( -+ cli, -+ tmp, -+ &vinstr_ctx->waiting_clients, -+ list) { -+ s64 tdiff = -+ (s64)(timestamp + DUMPING_RESOLUTION) - -+ (s64)cli->dump_time; -+ if (tdiff >= 0ll) { -+ list_del(&cli->list); -+ list_add(&cli->list, &expired_requests); -+ } else { -+ break; -+ } -+ } -+ -+ /* Fill data for each request found. */ -+ list_for_each_entry_safe(cli, tmp, &expired_requests, list) { -+ /* Ensure that legacy buffer will not be used from -+ * this kthread context. */ -+ BUG_ON(0 == cli->buffer_count); -+ /* Expect only periodically sampled clients. */ -+ BUG_ON(0 == cli->dump_interval); -+ -+ if (!rcode) -+ kbasep_vinstr_update_client( -+ cli, -+ timestamp, -+ BASE_HWCNT_READER_EVENT_PERIODIC); -+ -+ /* Set new dumping time. Drop missed probing times. */ -+ do { -+ cli->dump_time += cli->dump_interval; -+ } while (cli->dump_time < timestamp); -+ -+ list_del(&cli->list); -+ kbasep_vinstr_add_dump_request( -+ cli, -+ &vinstr_ctx->waiting_clients); -+ } -+ -+ /* Reprogram counters set if required. */ -+ kbasep_vinstr_reprogram(vinstr_ctx); -+ -+ mutex_unlock(&vinstr_ctx->lock); -+ } -+ -+ kfree(timer); -+ -+ return 0; -+} -+ -+/*****************************************************************************/ -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_buffer_ready - check if client has ready buffers -+ * @cli: pointer to vinstr client structure -+ * -+ * Return: non-zero if client has at least one dumping buffer filled that was -+ * not notified to user yet -+ */ -+static int kbasep_vinstr_hwcnt_reader_buffer_ready( -+ struct kbase_vinstr_client *cli) -+{ -+ KBASE_DEBUG_ASSERT(cli); -+ return atomic_read(&cli->write_idx) != atomic_read(&cli->meta_idx); -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_ioctl_get_buffer - hwcnt reader's ioctl command -+ * @cli: pointer to vinstr client structure -+ * @buffer: pointer to userspace buffer -+ * @size: size of buffer -+ * -+ * Return: zero on success -+ */ -+static long kbasep_vinstr_hwcnt_reader_ioctl_get_buffer( -+ struct kbase_vinstr_client *cli, void __user *buffer, -+ size_t size) -+{ -+ unsigned int meta_idx = atomic_read(&cli->meta_idx); -+ unsigned int idx = meta_idx % cli->buffer_count; -+ -+ struct kbase_hwcnt_reader_metadata *meta = &cli->dump_buffers_meta[idx]; -+ -+ /* Metadata sanity check. */ -+ KBASE_DEBUG_ASSERT(idx == meta->buffer_idx); -+ -+ if (sizeof(struct kbase_hwcnt_reader_metadata) != size) -+ return -EINVAL; -+ -+ /* Check if there is any buffer available. */ -+ if (atomic_read(&cli->write_idx) == meta_idx) -+ return -EAGAIN; -+ -+ /* Check if previously taken buffer was put back. */ -+ if (atomic_read(&cli->read_idx) != meta_idx) -+ return -EBUSY; -+ -+ /* Copy next available buffer's metadata to user. */ -+ if (copy_to_user(buffer, meta, size)) -+ return -EFAULT; -+ -+ atomic_inc(&cli->meta_idx); -+ -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_ioctl_put_buffer - hwcnt reader's ioctl command -+ * @cli: pointer to vinstr client structure -+ * @buffer: pointer to userspace buffer -+ * @size: size of buffer -+ * -+ * Return: zero on success -+ */ -+static long kbasep_vinstr_hwcnt_reader_ioctl_put_buffer( -+ struct kbase_vinstr_client *cli, void __user *buffer, -+ size_t size) -+{ -+ unsigned int read_idx = atomic_read(&cli->read_idx); -+ unsigned int idx = read_idx % cli->buffer_count; -+ -+ struct kbase_hwcnt_reader_metadata meta; -+ -+ if (sizeof(struct kbase_hwcnt_reader_metadata) != size) -+ return -EINVAL; -+ -+ /* Check if any buffer was taken. */ -+ if (atomic_read(&cli->meta_idx) == read_idx) -+ return -EPERM; -+ -+ /* Check if correct buffer is put back. */ -+ if (copy_from_user(&meta, buffer, size)) -+ return -EFAULT; -+ if (idx != meta.buffer_idx) -+ return -EINVAL; -+ -+ atomic_inc(&cli->read_idx); -+ -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_ioctl_set_interval - hwcnt reader's ioctl command -+ * @cli: pointer to vinstr client structure -+ * @interval: periodic dumping interval (disable periodic dumping if zero) -+ * -+ * Return: zero on success -+ */ -+static long kbasep_vinstr_hwcnt_reader_ioctl_set_interval( -+ struct kbase_vinstr_client *cli, u32 interval) -+{ -+ struct kbase_vinstr_context *vinstr_ctx = cli->vinstr_ctx; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ list_del(&cli->list); -+ -+ cli->dump_interval = interval; -+ -+ /* If interval is non-zero, enable periodic dumping for this client. */ -+ if (cli->dump_interval) { -+ if (DUMPING_RESOLUTION > cli->dump_interval) -+ cli->dump_interval = DUMPING_RESOLUTION; -+ cli->dump_time = -+ kbasep_vinstr_get_timestamp() + cli->dump_interval; -+ -+ kbasep_vinstr_add_dump_request( -+ cli, &vinstr_ctx->waiting_clients); -+ -+ atomic_set(&vinstr_ctx->request_pending, 1); -+ wake_up_all(&vinstr_ctx->waitq); -+ } else { -+ list_add(&cli->list, &vinstr_ctx->idle_clients); -+ } -+ -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_event_mask - return event mask for event id -+ * @event_id: id of event -+ * Return: event_mask or zero if event is not supported or maskable -+ */ -+static u32 kbasep_vinstr_hwcnt_reader_event_mask( -+ enum base_hwcnt_reader_event event_id) -+{ -+ u32 event_mask = 0; -+ -+ switch (event_id) { -+ case BASE_HWCNT_READER_EVENT_PREJOB: -+ case BASE_HWCNT_READER_EVENT_POSTJOB: -+ /* These event are maskable. */ -+ event_mask = (1 << event_id); -+ break; -+ -+ case BASE_HWCNT_READER_EVENT_MANUAL: -+ case BASE_HWCNT_READER_EVENT_PERIODIC: -+ /* These event are non-maskable. */ -+ default: -+ /* These event are not supported. */ -+ break; -+ } -+ -+ return event_mask; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_ioctl_enable_event - hwcnt reader's ioctl command -+ * @cli: pointer to vinstr client structure -+ * @event_id: id of event to enable -+ * -+ * Return: zero on success -+ */ -+static long kbasep_vinstr_hwcnt_reader_ioctl_enable_event( -+ struct kbase_vinstr_client *cli, -+ enum base_hwcnt_reader_event event_id) -+{ -+ struct kbase_vinstr_context *vinstr_ctx = cli->vinstr_ctx; -+ u32 event_mask; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ event_mask = kbasep_vinstr_hwcnt_reader_event_mask(event_id); -+ if (!event_mask) -+ return -EINVAL; -+ -+ mutex_lock(&vinstr_ctx->lock); -+ cli->event_mask |= event_mask; -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_ioctl_disable_event - hwcnt reader's ioctl command -+ * @cli: pointer to vinstr client structure -+ * @event_id: id of event to disable -+ * -+ * Return: zero on success -+ */ -+static long kbasep_vinstr_hwcnt_reader_ioctl_disable_event( -+ struct kbase_vinstr_client *cli, -+ enum base_hwcnt_reader_event event_id) -+{ -+ struct kbase_vinstr_context *vinstr_ctx = cli->vinstr_ctx; -+ u32 event_mask; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ event_mask = kbasep_vinstr_hwcnt_reader_event_mask(event_id); -+ if (!event_mask) -+ return -EINVAL; -+ -+ mutex_lock(&vinstr_ctx->lock); -+ cli->event_mask &= ~event_mask; -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_ioctl_get_hwver - hwcnt reader's ioctl command -+ * @cli: pointer to vinstr client structure -+ * @hwver: pointer to user buffer where hw version will be stored -+ * -+ * Return: zero on success -+ */ -+static long kbasep_vinstr_hwcnt_reader_ioctl_get_hwver( -+ struct kbase_vinstr_client *cli, u32 __user *hwver) -+{ -+#ifndef CONFIG_MALI_NO_MALI -+ struct kbase_vinstr_context *vinstr_ctx = cli->vinstr_ctx; -+#endif -+ -+ u32 ver = 5; -+ -+#ifndef CONFIG_MALI_NO_MALI -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ if (kbase_hw_has_feature(vinstr_ctx->kbdev, BASE_HW_FEATURE_V4)) -+ ver = 4; -+#endif -+ -+ return put_user(ver, hwver); -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_ioctl - hwcnt reader's ioctl -+ * @filp: pointer to file structure -+ * @cmd: user command -+ * @arg: command's argument -+ * -+ * Return: zero on success -+ */ -+static long kbasep_vinstr_hwcnt_reader_ioctl(struct file *filp, -+ unsigned int cmd, unsigned long arg) -+{ -+ long rcode = 0; -+ struct kbase_vinstr_client *cli; -+ -+ KBASE_DEBUG_ASSERT(filp); -+ -+ cli = filp->private_data; -+ KBASE_DEBUG_ASSERT(cli); -+ -+ if (unlikely(KBASE_HWCNT_READER != _IOC_TYPE(cmd))) -+ return -EINVAL; -+ -+ switch (cmd) { -+ case KBASE_HWCNT_READER_GET_API_VERSION: -+ rcode = put_user(HWCNT_READER_API, (u32 __user *)arg); -+ break; -+ case KBASE_HWCNT_READER_GET_HWVER: -+ rcode = kbasep_vinstr_hwcnt_reader_ioctl_get_hwver( -+ cli, (u32 __user *)arg); -+ break; -+ case KBASE_HWCNT_READER_GET_BUFFER_SIZE: -+ KBASE_DEBUG_ASSERT(cli->vinstr_ctx); -+ rcode = put_user( -+ (u32)cli->vinstr_ctx->dump_size, -+ (u32 __user *)arg); -+ break; -+ case KBASE_HWCNT_READER_DUMP: -+ rcode = kbase_vinstr_hwc_dump( -+ cli, BASE_HWCNT_READER_EVENT_MANUAL); -+ break; -+ case KBASE_HWCNT_READER_CLEAR: -+ rcode = kbase_vinstr_hwc_clear(cli); -+ break; -+ case KBASE_HWCNT_READER_GET_BUFFER: -+ rcode = kbasep_vinstr_hwcnt_reader_ioctl_get_buffer( -+ cli, (void __user *)arg, _IOC_SIZE(cmd)); -+ break; -+ case KBASE_HWCNT_READER_PUT_BUFFER: -+ rcode = kbasep_vinstr_hwcnt_reader_ioctl_put_buffer( -+ cli, (void __user *)arg, _IOC_SIZE(cmd)); -+ break; -+ case KBASE_HWCNT_READER_SET_INTERVAL: -+ rcode = kbasep_vinstr_hwcnt_reader_ioctl_set_interval( -+ cli, (u32)arg); -+ break; -+ case KBASE_HWCNT_READER_ENABLE_EVENT: -+ rcode = kbasep_vinstr_hwcnt_reader_ioctl_enable_event( -+ cli, (enum base_hwcnt_reader_event)arg); -+ break; -+ case KBASE_HWCNT_READER_DISABLE_EVENT: -+ rcode = kbasep_vinstr_hwcnt_reader_ioctl_disable_event( -+ cli, (enum base_hwcnt_reader_event)arg); -+ break; -+ default: -+ rcode = -EINVAL; -+ break; -+ } -+ -+ return rcode; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_poll - hwcnt reader's poll -+ * @filp: pointer to file structure -+ * @wait: pointer to poll table -+ * Return: POLLIN if data can be read without blocking, otherwise zero -+ */ -+static unsigned int kbasep_vinstr_hwcnt_reader_poll(struct file *filp, -+ poll_table *wait) -+{ -+ struct kbase_vinstr_client *cli; -+ -+ KBASE_DEBUG_ASSERT(filp); -+ KBASE_DEBUG_ASSERT(wait); -+ -+ cli = filp->private_data; -+ KBASE_DEBUG_ASSERT(cli); -+ -+ poll_wait(filp, &cli->waitq, wait); -+ if (kbasep_vinstr_hwcnt_reader_buffer_ready(cli)) -+ return POLLIN; -+ return 0; -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_mmap - hwcnt reader's mmap -+ * @filp: pointer to file structure -+ * @vma: pointer to vma structure -+ * Return: zero on success -+ */ -+static int kbasep_vinstr_hwcnt_reader_mmap(struct file *filp, -+ struct vm_area_struct *vma) -+{ -+ struct kbase_vinstr_client *cli; -+ unsigned long size, addr, pfn, offset; -+ unsigned long vm_size = vma->vm_end - vma->vm_start; -+ -+ KBASE_DEBUG_ASSERT(filp); -+ KBASE_DEBUG_ASSERT(vma); -+ -+ cli = filp->private_data; -+ KBASE_DEBUG_ASSERT(cli); -+ -+ size = cli->buffer_count * cli->dump_size; -+ -+ if (vma->vm_pgoff > (size >> PAGE_SHIFT)) -+ return -EINVAL; -+ -+ offset = vma->vm_pgoff << PAGE_SHIFT; -+ if (vm_size > size - offset) -+ return -EINVAL; -+ -+ addr = __pa((unsigned long)cli->dump_buffers + offset); -+ pfn = addr >> PAGE_SHIFT; -+ -+ return remap_pfn_range( -+ vma, -+ vma->vm_start, -+ pfn, -+ vm_size, -+ vma->vm_page_prot); -+} -+ -+/** -+ * kbasep_vinstr_hwcnt_reader_release - hwcnt reader's release -+ * @inode: pointer to inode structure -+ * @filp: pointer to file structure -+ * Return always return zero -+ */ -+static int kbasep_vinstr_hwcnt_reader_release(struct inode *inode, -+ struct file *filp) -+{ -+ struct kbase_vinstr_client *cli; -+ -+ KBASE_DEBUG_ASSERT(inode); -+ KBASE_DEBUG_ASSERT(filp); -+ -+ cli = filp->private_data; -+ KBASE_DEBUG_ASSERT(cli); -+ -+ kbase_vinstr_detach_client(cli); -+ return 0; -+} -+ -+/*****************************************************************************/ -+ -+/** -+ * kbasep_vinstr_kick_scheduler - trigger scheduler cycle -+ * @kbdev: pointer to kbase device structure -+ */ -+static void kbasep_vinstr_kick_scheduler(struct kbase_device *kbdev) -+{ -+ struct kbasep_js_device_data *js_devdata = &kbdev->js_data; -+ unsigned long flags; -+ -+ down(&js_devdata->schedule_sem); -+ spin_lock_irqsave(&kbdev->hwaccess_lock, flags); -+ kbase_backend_slot_update(kbdev); -+ spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); -+ up(&js_devdata->schedule_sem); -+} -+ -+/** -+ * kbasep_vinstr_suspend_worker - worker suspending vinstr module -+ * @data: pointer to work structure -+ */ -+static void kbasep_vinstr_suspend_worker(struct work_struct *data) -+{ -+ struct kbase_vinstr_context *vinstr_ctx; -+ unsigned long flags; -+ -+ vinstr_ctx = container_of(data, struct kbase_vinstr_context, -+ suspend_work); -+ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ if (vinstr_ctx->kctx) -+ disable_hwcnt(vinstr_ctx); -+ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ vinstr_ctx->state = VINSTR_SUSPENDED; -+ wake_up_all(&vinstr_ctx->suspend_waitq); -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ /* Kick GPU scheduler to allow entering protected mode. -+ * This must happen after vinstr was suspended. */ -+ kbasep_vinstr_kick_scheduler(vinstr_ctx->kbdev); -+} -+ -+/** -+ * kbasep_vinstr_suspend_worker - worker resuming vinstr module -+ * @data: pointer to work structure -+ */ -+static void kbasep_vinstr_resume_worker(struct work_struct *data) -+{ -+ struct kbase_vinstr_context *vinstr_ctx; -+ unsigned long flags; -+ -+ vinstr_ctx = container_of(data, struct kbase_vinstr_context, -+ resume_work); -+ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ if (vinstr_ctx->kctx) -+ enable_hwcnt(vinstr_ctx); -+ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ vinstr_ctx->state = VINSTR_IDLE; -+ wake_up_all(&vinstr_ctx->suspend_waitq); -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ /* Kick GPU scheduler to allow entering protected mode. -+ * Note that scheduler state machine might requested re-entry to -+ * protected mode before vinstr was resumed. -+ * This must happen after vinstr was release. */ -+ kbasep_vinstr_kick_scheduler(vinstr_ctx->kbdev); -+} -+ -+/*****************************************************************************/ -+ -+struct kbase_vinstr_context *kbase_vinstr_init(struct kbase_device *kbdev) -+{ -+ struct kbase_vinstr_context *vinstr_ctx; -+ -+ vinstr_ctx = kzalloc(sizeof(*vinstr_ctx), GFP_KERNEL); -+ if (!vinstr_ctx) -+ return NULL; -+ -+ INIT_LIST_HEAD(&vinstr_ctx->idle_clients); -+ INIT_LIST_HEAD(&vinstr_ctx->waiting_clients); -+ mutex_init(&vinstr_ctx->lock); -+ spin_lock_init(&vinstr_ctx->state_lock); -+ vinstr_ctx->kbdev = kbdev; -+ vinstr_ctx->thread = NULL; -+ vinstr_ctx->state = VINSTR_IDLE; -+ vinstr_ctx->suspend_cnt = 0; -+ INIT_WORK(&vinstr_ctx->suspend_work, kbasep_vinstr_suspend_worker); -+ INIT_WORK(&vinstr_ctx->resume_work, kbasep_vinstr_resume_worker); -+ init_waitqueue_head(&vinstr_ctx->suspend_waitq); -+ -+ atomic_set(&vinstr_ctx->request_pending, 0); -+ init_waitqueue_head(&vinstr_ctx->waitq); -+ -+ return vinstr_ctx; -+} -+ -+void kbase_vinstr_term(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ struct kbase_vinstr_client *cli; -+ -+ /* Stop service thread first. */ -+ if (vinstr_ctx->thread) -+ kthread_stop(vinstr_ctx->thread); -+ -+ /* Wait for workers. */ -+ flush_work(&vinstr_ctx->suspend_work); -+ flush_work(&vinstr_ctx->resume_work); -+ -+ while (1) { -+ struct list_head *list = &vinstr_ctx->idle_clients; -+ -+ if (list_empty(list)) { -+ list = &vinstr_ctx->waiting_clients; -+ if (list_empty(list)) -+ break; -+ } -+ -+ cli = list_first_entry(list, struct kbase_vinstr_client, list); -+ list_del(&cli->list); -+ kfree(cli->accum_buffer); -+ kfree(cli); -+ vinstr_ctx->nclients--; -+ } -+ KBASE_DEBUG_ASSERT(!vinstr_ctx->nclients); -+ if (vinstr_ctx->kctx) -+ kbasep_vinstr_destroy_kctx(vinstr_ctx); -+ kfree(vinstr_ctx); -+} -+ -+int kbase_vinstr_hwcnt_reader_setup(struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_uk_hwcnt_reader_setup *setup) -+{ -+ struct kbase_vinstr_client *cli; -+ u32 bitmap[4]; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ KBASE_DEBUG_ASSERT(setup); -+ KBASE_DEBUG_ASSERT(setup->buffer_count); -+ -+ bitmap[SHADER_HWCNT_BM] = setup->shader_bm; -+ bitmap[TILER_HWCNT_BM] = setup->tiler_bm; -+ bitmap[MMU_L2_HWCNT_BM] = setup->mmu_l2_bm; -+ bitmap[JM_HWCNT_BM] = setup->jm_bm; -+ -+ cli = kbasep_vinstr_attach_client( -+ vinstr_ctx, -+ setup->buffer_count, -+ bitmap, -+ &setup->fd, -+ NULL); -+ -+ if (!cli) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+int kbase_vinstr_legacy_hwc_setup( -+ struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_vinstr_client **cli, -+ struct kbase_uk_hwcnt_setup *setup) -+{ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ KBASE_DEBUG_ASSERT(setup); -+ KBASE_DEBUG_ASSERT(cli); -+ -+ if (setup->dump_buffer) { -+ u32 bitmap[4]; -+ -+ bitmap[SHADER_HWCNT_BM] = setup->shader_bm; -+ bitmap[TILER_HWCNT_BM] = setup->tiler_bm; -+ bitmap[MMU_L2_HWCNT_BM] = setup->mmu_l2_bm; -+ bitmap[JM_HWCNT_BM] = setup->jm_bm; -+ -+ if (*cli) -+ return -EBUSY; -+ -+ *cli = kbasep_vinstr_attach_client( -+ vinstr_ctx, -+ 0, -+ bitmap, -+ (void *)(long)setup->dump_buffer, -+ NULL); -+ -+ if (!(*cli)) -+ return -ENOMEM; -+ } else { -+ if (!*cli) -+ return -EINVAL; -+ -+ kbase_vinstr_detach_client(*cli); -+ *cli = NULL; -+ } -+ -+ return 0; -+} -+ -+struct kbase_vinstr_client *kbase_vinstr_hwcnt_kernel_setup( -+ struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_uk_hwcnt_reader_setup *setup, -+ void *kernel_buffer) -+{ -+ u32 bitmap[4]; -+ -+ if (!vinstr_ctx || !setup || !kernel_buffer) -+ return NULL; -+ -+ bitmap[SHADER_HWCNT_BM] = setup->shader_bm; -+ bitmap[TILER_HWCNT_BM] = setup->tiler_bm; -+ bitmap[MMU_L2_HWCNT_BM] = setup->mmu_l2_bm; -+ bitmap[JM_HWCNT_BM] = setup->jm_bm; -+ -+ return kbasep_vinstr_attach_client( -+ vinstr_ctx, -+ 0, -+ bitmap, -+ NULL, -+ kernel_buffer); -+} -+KBASE_EXPORT_TEST_API(kbase_vinstr_hwcnt_kernel_setup); -+ -+int kbase_vinstr_hwc_dump(struct kbase_vinstr_client *cli, -+ enum base_hwcnt_reader_event event_id) -+{ -+ int rcode = 0; -+ struct kbase_vinstr_context *vinstr_ctx; -+ u64 timestamp; -+ u32 event_mask; -+ -+ if (!cli) -+ return -EINVAL; -+ -+ vinstr_ctx = cli->vinstr_ctx; -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ KBASE_DEBUG_ASSERT(event_id < BASE_HWCNT_READER_EVENT_COUNT); -+ event_mask = 1 << event_id; -+ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ if (event_mask & cli->event_mask) { -+ rcode = kbasep_vinstr_collect_and_accumulate( -+ vinstr_ctx, -+ ×tamp); -+ if (rcode) -+ goto exit; -+ -+ rcode = kbasep_vinstr_update_client(cli, timestamp, event_id); -+ if (rcode) -+ goto exit; -+ -+ kbasep_vinstr_reprogram(vinstr_ctx); -+ } -+ -+exit: -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ return rcode; -+} -+KBASE_EXPORT_TEST_API(kbase_vinstr_hwc_dump); -+ -+int kbase_vinstr_hwc_clear(struct kbase_vinstr_client *cli) -+{ -+ struct kbase_vinstr_context *vinstr_ctx; -+ int rcode; -+ u64 unused; -+ -+ if (!cli) -+ return -EINVAL; -+ -+ vinstr_ctx = cli->vinstr_ctx; -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ mutex_lock(&vinstr_ctx->lock); -+ -+ rcode = kbasep_vinstr_collect_and_accumulate(vinstr_ctx, &unused); -+ if (rcode) -+ goto exit; -+ rcode = kbase_instr_hwcnt_clear(vinstr_ctx->kctx); -+ if (rcode) -+ goto exit; -+ memset(cli->accum_buffer, 0, cli->dump_size); -+ -+ kbasep_vinstr_reprogram(vinstr_ctx); -+ -+exit: -+ mutex_unlock(&vinstr_ctx->lock); -+ -+ return rcode; -+} -+ -+int kbase_vinstr_try_suspend(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ unsigned long flags; -+ int ret = -EAGAIN; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ switch (vinstr_ctx->state) { -+ case VINSTR_SUSPENDED: -+ vinstr_ctx->suspend_cnt++; -+ /* overflow shall not happen */ -+ BUG_ON(0 == vinstr_ctx->suspend_cnt); -+ ret = 0; -+ break; -+ -+ case VINSTR_IDLE: -+ if (vinstr_ctx->clients_present) { -+ vinstr_ctx->state = VINSTR_SUSPENDING; -+ schedule_work(&vinstr_ctx->suspend_work); -+ } else { -+ vinstr_ctx->state = VINSTR_SUSPENDED; -+ -+ vinstr_ctx->suspend_cnt++; -+ /* overflow shall not happen */ -+ WARN_ON(0 == vinstr_ctx->suspend_cnt); -+ ret = 0; -+ } -+ break; -+ -+ case VINSTR_DUMPING: -+ vinstr_ctx->state = VINSTR_SUSPENDING; -+ break; -+ -+ case VINSTR_SUSPENDING: -+ /* fall through */ -+ case VINSTR_RESUMING: -+ break; -+ -+ default: -+ BUG(); -+ break; -+ } -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+ -+ return ret; -+} -+ -+void kbase_vinstr_suspend(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ wait_event(vinstr_ctx->suspend_waitq, -+ (0 == kbase_vinstr_try_suspend(vinstr_ctx))); -+} -+ -+void kbase_vinstr_resume(struct kbase_vinstr_context *vinstr_ctx) -+{ -+ unsigned long flags; -+ -+ KBASE_DEBUG_ASSERT(vinstr_ctx); -+ -+ spin_lock_irqsave(&vinstr_ctx->state_lock, flags); -+ BUG_ON(VINSTR_SUSPENDING == vinstr_ctx->state); -+ if (VINSTR_SUSPENDED == vinstr_ctx->state) { -+ BUG_ON(0 == vinstr_ctx->suspend_cnt); -+ vinstr_ctx->suspend_cnt--; -+ if (0 == vinstr_ctx->suspend_cnt) { -+ if (vinstr_ctx->clients_present) { -+ vinstr_ctx->state = VINSTR_RESUMING; -+ schedule_work(&vinstr_ctx->resume_work); -+ } else { -+ vinstr_ctx->state = VINSTR_IDLE; -+ } -+ } -+ } -+ spin_unlock_irqrestore(&vinstr_ctx->state_lock, flags); -+} -diff --git a/drivers/gpu/arm/midgard/mali_kbase_vinstr.h b/drivers/gpu/arm/midgard/mali_kbase_vinstr.h -new file mode 100644 -index 0000000..6207d25 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_kbase_vinstr.h -@@ -0,0 +1,155 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KBASE_VINSTR_H_ -+#define _KBASE_VINSTR_H_ -+ -+#include -+#include -+ -+/*****************************************************************************/ -+ -+struct kbase_vinstr_context; -+struct kbase_vinstr_client; -+ -+/*****************************************************************************/ -+ -+/** -+ * kbase_vinstr_init() - initialize the vinstr core -+ * @kbdev: kbase device -+ * -+ * Return: pointer to the vinstr context on success or NULL on failure -+ */ -+struct kbase_vinstr_context *kbase_vinstr_init(struct kbase_device *kbdev); -+ -+/** -+ * kbase_vinstr_term() - terminate the vinstr core -+ * @vinstr_ctx: vinstr context -+ */ -+void kbase_vinstr_term(struct kbase_vinstr_context *vinstr_ctx); -+ -+/** -+ * kbase_vinstr_hwcnt_reader_setup - configure hw counters reader -+ * @vinstr_ctx: vinstr context -+ * @setup: reader's configuration -+ * -+ * Return: zero on success -+ */ -+int kbase_vinstr_hwcnt_reader_setup( -+ struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_uk_hwcnt_reader_setup *setup); -+ -+/** -+ * kbase_vinstr_legacy_hwc_setup - configure hw counters for dumping -+ * @vinstr_ctx: vinstr context -+ * @cli: pointer where to store pointer to new vinstr client structure -+ * @setup: hwc configuration -+ * -+ * Return: zero on success -+ */ -+int kbase_vinstr_legacy_hwc_setup( -+ struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_vinstr_client **cli, -+ struct kbase_uk_hwcnt_setup *setup); -+ -+/** -+ * kbase_vinstr_hwcnt_kernel_setup - configure hw counters for kernel side -+ * client -+ * @vinstr_ctx: vinstr context -+ * @setup: reader's configuration -+ * @kernel_buffer: pointer to dump buffer -+ * -+ * setup->buffer_count and setup->fd are not used for kernel side clients. -+ * -+ * Return: pointer to client structure, or NULL on failure -+ */ -+struct kbase_vinstr_client *kbase_vinstr_hwcnt_kernel_setup( -+ struct kbase_vinstr_context *vinstr_ctx, -+ struct kbase_uk_hwcnt_reader_setup *setup, -+ void *kernel_buffer); -+ -+/** -+ * kbase_vinstr_hwc_dump - issue counter dump for vinstr client -+ * @cli: pointer to vinstr client -+ * @event_id: id of event that triggered hwcnt dump -+ * -+ * Return: zero on success -+ */ -+int kbase_vinstr_hwc_dump( -+ struct kbase_vinstr_client *cli, -+ enum base_hwcnt_reader_event event_id); -+ -+/** -+ * kbase_vinstr_hwc_clear - performs a reset of the hardware counters for -+ * a given kbase context -+ * @cli: pointer to vinstr client -+ * -+ * Return: zero on success -+ */ -+int kbase_vinstr_hwc_clear(struct kbase_vinstr_client *cli); -+ -+/** -+ * kbase_vinstr_try_suspend - try suspending operation of a given vinstr context -+ * @vinstr_ctx: vinstr context -+ * -+ * Return: 0 on success, or negative if state change is in progress -+ * -+ * Warning: This API call is non-generic. It is meant to be used only by -+ * job scheduler state machine. -+ * -+ * Function initiates vinstr switch to suspended state. Once it was called -+ * vinstr enters suspending state. If function return non-zero value, it -+ * indicates that state switch is not complete and function must be called -+ * again. On state switch vinstr will trigger job scheduler state machine -+ * cycle. -+ */ -+int kbase_vinstr_try_suspend(struct kbase_vinstr_context *vinstr_ctx); -+ -+/** -+ * kbase_vinstr_suspend - suspends operation of a given vinstr context -+ * @vinstr_ctx: vinstr context -+ * -+ * Function initiates vinstr switch to suspended state. Then it blocks until -+ * operation is completed. -+ */ -+void kbase_vinstr_suspend(struct kbase_vinstr_context *vinstr_ctx); -+ -+/** -+ * kbase_vinstr_resume - resumes operation of a given vinstr context -+ * @vinstr_ctx: vinstr context -+ * -+ * Function can be called only if it was preceded by a successful call -+ * to kbase_vinstr_suspend. -+ */ -+void kbase_vinstr_resume(struct kbase_vinstr_context *vinstr_ctx); -+ -+/** -+ * kbase_vinstr_dump_size - Return required size of dump buffer -+ * @kbdev: device pointer -+ * -+ * Return : buffer size in bytes -+ */ -+size_t kbase_vinstr_dump_size(struct kbase_device *kbdev); -+ -+/** -+ * kbase_vinstr_detach_client - Detach a client from the vinstr core -+ * @cli: pointer to vinstr client -+ */ -+void kbase_vinstr_detach_client(struct kbase_vinstr_client *cli); -+ -+#endif /* _KBASE_VINSTR_H_ */ -+ -diff --git a/drivers/gpu/arm/midgard/mali_linux_kbase_trace.h b/drivers/gpu/arm/midgard/mali_linux_kbase_trace.h -new file mode 100644 -index 0000000..5d6b402 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_linux_kbase_trace.h -@@ -0,0 +1,201 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+#if !defined(_TRACE_MALI_KBASE_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _TRACE_MALI_KBASE_H -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM mali -+ -+#include -+ -+DECLARE_EVENT_CLASS(mali_slot_template, -+ TP_PROTO(int jobslot, unsigned int info_val), -+ TP_ARGS(jobslot, info_val), -+ TP_STRUCT__entry( -+ __field(unsigned int, jobslot) -+ __field(unsigned int, info_val) -+ ), -+ TP_fast_assign( -+ __entry->jobslot = jobslot; -+ __entry->info_val = info_val; -+ ), -+ TP_printk("jobslot=%u info=%u", __entry->jobslot, __entry->info_val) -+); -+ -+#define DEFINE_MALI_SLOT_EVENT(name) \ -+DEFINE_EVENT(mali_slot_template, mali_##name, \ -+ TP_PROTO(int jobslot, unsigned int info_val), \ -+ TP_ARGS(jobslot, info_val)) -+DEFINE_MALI_SLOT_EVENT(JM_SUBMIT); -+DEFINE_MALI_SLOT_EVENT(JM_JOB_DONE); -+DEFINE_MALI_SLOT_EVENT(JM_UPDATE_HEAD); -+DEFINE_MALI_SLOT_EVENT(JM_CHECK_HEAD); -+DEFINE_MALI_SLOT_EVENT(JM_SOFTSTOP); -+DEFINE_MALI_SLOT_EVENT(JM_SOFTSTOP_0); -+DEFINE_MALI_SLOT_EVENT(JM_SOFTSTOP_1); -+DEFINE_MALI_SLOT_EVENT(JM_HARDSTOP); -+DEFINE_MALI_SLOT_EVENT(JM_HARDSTOP_0); -+DEFINE_MALI_SLOT_EVENT(JM_HARDSTOP_1); -+DEFINE_MALI_SLOT_EVENT(JM_SLOT_SOFT_OR_HARD_STOP); -+DEFINE_MALI_SLOT_EVENT(JM_SLOT_EVICT); -+DEFINE_MALI_SLOT_EVENT(JM_BEGIN_RESET_WORKER); -+DEFINE_MALI_SLOT_EVENT(JM_END_RESET_WORKER); -+DEFINE_MALI_SLOT_EVENT(JS_CORE_REF_REGISTER_ON_RECHECK_FAILED); -+DEFINE_MALI_SLOT_EVENT(JS_AFFINITY_SUBMIT_TO_BLOCKED); -+DEFINE_MALI_SLOT_EVENT(JS_AFFINITY_CURRENT); -+DEFINE_MALI_SLOT_EVENT(JD_DONE_TRY_RUN_NEXT_JOB); -+DEFINE_MALI_SLOT_EVENT(JS_CORE_REF_REQUEST_CORES_FAILED); -+DEFINE_MALI_SLOT_EVENT(JS_CORE_REF_REGISTER_INUSE_FAILED); -+DEFINE_MALI_SLOT_EVENT(JS_CORE_REF_REQUEST_ON_RECHECK_FAILED); -+DEFINE_MALI_SLOT_EVENT(JS_CORE_REF_AFFINITY_WOULD_VIOLATE); -+DEFINE_MALI_SLOT_EVENT(JS_JOB_DONE_TRY_RUN_NEXT_JOB); -+DEFINE_MALI_SLOT_EVENT(JS_JOB_DONE_RETRY_NEEDED); -+DEFINE_MALI_SLOT_EVENT(JS_POLICY_DEQUEUE_JOB); -+DEFINE_MALI_SLOT_EVENT(JS_POLICY_DEQUEUE_JOB_IRQ); -+#undef DEFINE_MALI_SLOT_EVENT -+ -+DECLARE_EVENT_CLASS(mali_refcount_template, -+ TP_PROTO(int refcount, unsigned int info_val), -+ TP_ARGS(refcount, info_val), -+ TP_STRUCT__entry( -+ __field(unsigned int, refcount) -+ __field(unsigned int, info_val) -+ ), -+ TP_fast_assign( -+ __entry->refcount = refcount; -+ __entry->info_val = info_val; -+ ), -+ TP_printk("refcount=%u info=%u", __entry->refcount, __entry->info_val) -+); -+ -+#define DEFINE_MALI_REFCOUNT_EVENT(name) \ -+DEFINE_EVENT(mali_refcount_template, mali_##name, \ -+ TP_PROTO(int refcount, unsigned int info_val), \ -+ TP_ARGS(refcount, info_val)) -+DEFINE_MALI_REFCOUNT_EVENT(JS_RETAIN_CTX_NOLOCK); -+DEFINE_MALI_REFCOUNT_EVENT(JS_ADD_JOB); -+DEFINE_MALI_REFCOUNT_EVENT(JS_REMOVE_JOB); -+DEFINE_MALI_REFCOUNT_EVENT(JS_RETAIN_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_RELEASE_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_TRY_SCHEDULE_HEAD_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_INIT_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_TERM_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_ENQUEUE_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_DEQUEUE_HEAD_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_TRY_EVICT_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_RUNPOOL_ADD_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_RUNPOOL_REMOVE_CTX); -+DEFINE_MALI_REFCOUNT_EVENT(JS_POLICY_FOREACH_CTX_JOBS); -+DEFINE_MALI_REFCOUNT_EVENT(PM_CONTEXT_ACTIVE); -+DEFINE_MALI_REFCOUNT_EVENT(PM_CONTEXT_IDLE); -+#undef DEFINE_MALI_REFCOUNT_EVENT -+ -+DECLARE_EVENT_CLASS(mali_add_template, -+ TP_PROTO(int gpu_addr, unsigned int info_val), -+ TP_ARGS(gpu_addr, info_val), -+ TP_STRUCT__entry( -+ __field(unsigned int, gpu_addr) -+ __field(unsigned int, info_val) -+ ), -+ TP_fast_assign( -+ __entry->gpu_addr = gpu_addr; -+ __entry->info_val = info_val; -+ ), -+ TP_printk("gpu_addr=%u info=%u", __entry->gpu_addr, __entry->info_val) -+); -+ -+#define DEFINE_MALI_ADD_EVENT(name) \ -+DEFINE_EVENT(mali_add_template, mali_##name, \ -+ TP_PROTO(int gpu_addr, unsigned int info_val), \ -+ TP_ARGS(gpu_addr, info_val)) -+DEFINE_MALI_ADD_EVENT(CORE_CTX_DESTROY); -+DEFINE_MALI_ADD_EVENT(CORE_CTX_HWINSTR_TERM); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_IRQ); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_IRQ_CLEAR); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_IRQ_DONE); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_SOFT_RESET); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_HARD_RESET); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_PRFCNT_SAMPLE); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_PRFCNT_CLEAR); -+DEFINE_MALI_ADD_EVENT(CORE_GPU_CLEAN_INV_CACHES); -+DEFINE_MALI_ADD_EVENT(JD_DONE_WORKER); -+DEFINE_MALI_ADD_EVENT(JD_DONE_WORKER_END); -+DEFINE_MALI_ADD_EVENT(JD_CANCEL_WORKER); -+DEFINE_MALI_ADD_EVENT(JD_DONE); -+DEFINE_MALI_ADD_EVENT(JD_CANCEL); -+DEFINE_MALI_ADD_EVENT(JD_ZAP_CONTEXT); -+DEFINE_MALI_ADD_EVENT(JM_IRQ); -+DEFINE_MALI_ADD_EVENT(JM_IRQ_END); -+DEFINE_MALI_ADD_EVENT(JM_FLUSH_WORKQS); -+DEFINE_MALI_ADD_EVENT(JM_FLUSH_WORKQS_DONE); -+DEFINE_MALI_ADD_EVENT(JM_ZAP_NON_SCHEDULED); -+DEFINE_MALI_ADD_EVENT(JM_ZAP_SCHEDULED); -+DEFINE_MALI_ADD_EVENT(JM_ZAP_DONE); -+DEFINE_MALI_ADD_EVENT(JM_SUBMIT_AFTER_RESET); -+DEFINE_MALI_ADD_EVENT(JM_JOB_COMPLETE); -+DEFINE_MALI_ADD_EVENT(JS_FAST_START_EVICTS_CTX); -+DEFINE_MALI_ADD_EVENT(JS_CTX_ATTR_NOW_ON_RUNPOOL); -+DEFINE_MALI_ADD_EVENT(JS_CTX_ATTR_NOW_OFF_RUNPOOL); -+DEFINE_MALI_ADD_EVENT(JS_CTX_ATTR_NOW_ON_CTX); -+DEFINE_MALI_ADD_EVENT(JS_CTX_ATTR_NOW_OFF_CTX); -+DEFINE_MALI_ADD_EVENT(JS_POLICY_TIMER_END); -+DEFINE_MALI_ADD_EVENT(JS_POLICY_TIMER_START); -+DEFINE_MALI_ADD_EVENT(JS_POLICY_ENQUEUE_JOB); -+DEFINE_MALI_ADD_EVENT(PM_CORES_CHANGE_DESIRED); -+DEFINE_MALI_ADD_EVENT(PM_JOB_SUBMIT_AFTER_POWERING_UP); -+DEFINE_MALI_ADD_EVENT(PM_JOB_SUBMIT_AFTER_POWERED_UP); -+DEFINE_MALI_ADD_EVENT(PM_PWRON); -+DEFINE_MALI_ADD_EVENT(PM_PWRON_TILER); -+DEFINE_MALI_ADD_EVENT(PM_PWRON_L2); -+DEFINE_MALI_ADD_EVENT(PM_PWROFF); -+DEFINE_MALI_ADD_EVENT(PM_PWROFF_TILER); -+DEFINE_MALI_ADD_EVENT(PM_PWROFF_L2); -+DEFINE_MALI_ADD_EVENT(PM_CORES_POWERED); -+DEFINE_MALI_ADD_EVENT(PM_CORES_POWERED_TILER); -+DEFINE_MALI_ADD_EVENT(PM_CORES_POWERED_L2); -+DEFINE_MALI_ADD_EVENT(PM_DESIRED_REACHED); -+DEFINE_MALI_ADD_EVENT(PM_DESIRED_REACHED_TILER); -+DEFINE_MALI_ADD_EVENT(PM_UNREQUEST_CHANGE_SHADER_NEEDED); -+DEFINE_MALI_ADD_EVENT(PM_REQUEST_CHANGE_SHADER_NEEDED); -+DEFINE_MALI_ADD_EVENT(PM_REGISTER_CHANGE_SHADER_NEEDED); -+DEFINE_MALI_ADD_EVENT(PM_REGISTER_CHANGE_SHADER_INUSE); -+DEFINE_MALI_ADD_EVENT(PM_RELEASE_CHANGE_SHADER_INUSE); -+DEFINE_MALI_ADD_EVENT(PM_CORES_AVAILABLE); -+DEFINE_MALI_ADD_EVENT(PM_CORES_AVAILABLE_TILER); -+DEFINE_MALI_ADD_EVENT(PM_CORES_CHANGE_AVAILABLE); -+DEFINE_MALI_ADD_EVENT(PM_CORES_CHANGE_AVAILABLE_TILER); -+DEFINE_MALI_ADD_EVENT(PM_GPU_ON); -+DEFINE_MALI_ADD_EVENT(PM_GPU_OFF); -+DEFINE_MALI_ADD_EVENT(PM_SET_POLICY); -+DEFINE_MALI_ADD_EVENT(PM_CURRENT_POLICY_INIT); -+DEFINE_MALI_ADD_EVENT(PM_CURRENT_POLICY_TERM); -+DEFINE_MALI_ADD_EVENT(PM_CA_SET_POLICY); -+DEFINE_MALI_ADD_EVENT(PM_WAKE_WAITERS); -+#undef DEFINE_MALI_ADD_EVENT -+ -+#endif /* _TRACE_MALI_KBASE_H */ -+ -+#undef TRACE_INCLUDE_PATH -+#undef linux -+#define TRACE_INCLUDE_PATH . -+#undef TRACE_INCLUDE_FILE -+#define TRACE_INCLUDE_FILE mali_linux_kbase_trace -+ -+/* This part must be outside protection */ -+#include -diff --git a/drivers/gpu/arm/midgard/mali_linux_trace.h b/drivers/gpu/arm/midgard/mali_linux_trace.h -new file mode 100644 -index 0000000..2be06a5 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_linux_trace.h -@@ -0,0 +1,189 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#if !defined(_TRACE_MALI_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _TRACE_MALI_H -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM mali -+#define TRACE_INCLUDE_FILE mali_linux_trace -+ -+#include -+ -+#define MALI_JOB_SLOTS_EVENT_CHANGED -+ -+/** -+ * mali_job_slots_event - called from mali_kbase_core_linux.c -+ * @event_id: ORed together bitfields representing a type of event, made with the GATOR_MAKE_EVENT() macro. -+ */ -+TRACE_EVENT(mali_job_slots_event, -+ TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid, -+ unsigned char job_id), -+ TP_ARGS(event_id, tgid, pid, job_id), -+ TP_STRUCT__entry( -+ __field(unsigned int, event_id) -+ __field(unsigned int, tgid) -+ __field(unsigned int, pid) -+ __field(unsigned char, job_id) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ __entry->tgid = tgid; -+ __entry->pid = pid; -+ __entry->job_id = job_id; -+ ), -+ TP_printk("event=%u tgid=%u pid=%u job_id=%u", -+ __entry->event_id, __entry->tgid, __entry->pid, __entry->job_id) -+); -+ -+/** -+ * mali_pm_status - Called by mali_kbase_pm_driver.c -+ * @event_id: core type (shader, tiler, l2 cache) -+ * @value: 64bits bitmask reporting either power status of the cores (1-ON, 0-OFF) -+ */ -+TRACE_EVENT(mali_pm_status, -+ TP_PROTO(unsigned int event_id, unsigned long long value), -+ TP_ARGS(event_id, value), -+ TP_STRUCT__entry( -+ __field(unsigned int, event_id) -+ __field(unsigned long long, value) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ __entry->value = value; -+ ), -+ TP_printk("event %u = %llu", __entry->event_id, __entry->value) -+); -+ -+/** -+ * mali_pm_power_on - Called by mali_kbase_pm_driver.c -+ * @event_id: core type (shader, tiler, l2 cache) -+ * @value: 64bits bitmask reporting the cores to power up -+ */ -+TRACE_EVENT(mali_pm_power_on, -+ TP_PROTO(unsigned int event_id, unsigned long long value), -+ TP_ARGS(event_id, value), -+ TP_STRUCT__entry( -+ __field(unsigned int, event_id) -+ __field(unsigned long long, value) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ __entry->value = value; -+ ), -+ TP_printk("event %u = %llu", __entry->event_id, __entry->value) -+); -+ -+/** -+ * mali_pm_power_off - Called by mali_kbase_pm_driver.c -+ * @event_id: core type (shader, tiler, l2 cache) -+ * @value: 64bits bitmask reporting the cores to power down -+ */ -+TRACE_EVENT(mali_pm_power_off, -+ TP_PROTO(unsigned int event_id, unsigned long long value), -+ TP_ARGS(event_id, value), -+ TP_STRUCT__entry( -+ __field(unsigned int, event_id) -+ __field(unsigned long long, value) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ __entry->value = value; -+ ), -+ TP_printk("event %u = %llu", __entry->event_id, __entry->value) -+); -+ -+/** -+ * mali_page_fault_insert_pages - Called by page_fault_worker() -+ * it reports an MMU page fault resulting in new pages being mapped. -+ * @event_id: MMU address space number. -+ * @value: number of newly allocated pages -+ */ -+TRACE_EVENT(mali_page_fault_insert_pages, -+ TP_PROTO(int event_id, unsigned long value), -+ TP_ARGS(event_id, value), -+ TP_STRUCT__entry( -+ __field(int, event_id) -+ __field(unsigned long, value) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ __entry->value = value; -+ ), -+ TP_printk("event %d = %lu", __entry->event_id, __entry->value) -+); -+ -+/** -+ * mali_mmu_as_in_use - Called by assign_and_activate_kctx_addr_space() -+ * it reports that a certain MMU address space is in use now. -+ * @event_id: MMU address space number. -+ */ -+TRACE_EVENT(mali_mmu_as_in_use, -+ TP_PROTO(int event_id), -+ TP_ARGS(event_id), -+ TP_STRUCT__entry( -+ __field(int, event_id) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ ), -+ TP_printk("event=%d", __entry->event_id) -+); -+ -+/** -+ * mali_mmu_as_released - Called by kbasep_js_runpool_release_ctx_internal() -+ * it reports that a certain MMU address space has been released now. -+ * @event_id: MMU address space number. -+ */ -+TRACE_EVENT(mali_mmu_as_released, -+ TP_PROTO(int event_id), -+ TP_ARGS(event_id), -+ TP_STRUCT__entry( -+ __field(int, event_id) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ ), -+ TP_printk("event=%d", __entry->event_id) -+); -+ -+/** -+ * mali_total_alloc_pages_change - Called by kbase_atomic_add_pages() -+ * and by kbase_atomic_sub_pages() -+ * it reports that the total number of allocated pages is changed. -+ * @event_id: number of pages to be added or subtracted (according to the sign). -+ */ -+TRACE_EVENT(mali_total_alloc_pages_change, -+ TP_PROTO(long long int event_id), -+ TP_ARGS(event_id), -+ TP_STRUCT__entry( -+ __field(long long int, event_id) -+ ), -+ TP_fast_assign( -+ __entry->event_id = event_id; -+ ), -+ TP_printk("event=%lld", __entry->event_id) -+); -+ -+#endif /* _TRACE_MALI_H */ -+ -+#undef TRACE_INCLUDE_PATH -+#undef linux -+#define TRACE_INCLUDE_PATH . -+ -+/* This part must be outside protection */ -+#include -diff --git a/drivers/gpu/arm/midgard/mali_malisw.h b/drivers/gpu/arm/midgard/mali_malisw.h -new file mode 100644 -index 0000000..9945293 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_malisw.h -@@ -0,0 +1,131 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * Kernel-wide include for common macros and types. -+ */ -+ -+#ifndef _MALISW_H_ -+#define _MALISW_H_ -+ -+#include -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) -+#define U8_MAX ((u8)~0U) -+#define S8_MAX ((s8)(U8_MAX>>1)) -+#define S8_MIN ((s8)(-S8_MAX - 1)) -+#define U16_MAX ((u16)~0U) -+#define S16_MAX ((s16)(U16_MAX>>1)) -+#define S16_MIN ((s16)(-S16_MAX - 1)) -+#define U32_MAX ((u32)~0U) -+#define S32_MAX ((s32)(U32_MAX>>1)) -+#define S32_MIN ((s32)(-S32_MAX - 1)) -+#define U64_MAX ((u64)~0ULL) -+#define S64_MAX ((s64)(U64_MAX>>1)) -+#define S64_MIN ((s64)(-S64_MAX - 1)) -+#endif /* LINUX_VERSION_CODE */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) -+#define SIZE_MAX (~(size_t)0) -+#endif /* LINUX_VERSION_CODE */ -+ -+/** -+ * MIN - Return the lesser of two values. -+ * -+ * As a macro it may evaluate its arguments more than once. -+ * Refer to MAX macro for more details -+ */ -+#define MIN(x, y) ((x) < (y) ? (x) : (y)) -+ -+/** -+ * MAX - Return the greater of two values. -+ * -+ * As a macro it may evaluate its arguments more than once. -+ * If called on the same two arguments as MIN it is guaranteed to return -+ * the one that MIN didn't return. This is significant for types where not -+ * all values are comparable e.g. NaNs in floating-point types. But if you want -+ * to retrieve the min and max of two values, consider using a conditional swap -+ * instead. -+ */ -+#define MAX(x, y) ((x) < (y) ? (y) : (x)) -+ -+/** -+ * @hideinitializer -+ * Function-like macro for suppressing unused variable warnings. Where possible -+ * such variables should be removed; this macro is present for cases where we -+ * much support API backwards compatibility. -+ */ -+#define CSTD_UNUSED(x) ((void)(x)) -+ -+/** -+ * @hideinitializer -+ * Function-like macro for use where "no behavior" is desired. This is useful -+ * when compile time macros turn a function-like macro in to a no-op, but -+ * where having no statement is otherwise invalid. -+ */ -+#define CSTD_NOP(...) ((void)#__VA_ARGS__) -+ -+/** -+ * Function-like macro for converting a pointer in to a u64 for storing into -+ * an external data structure. This is commonly used when pairing a 32-bit -+ * CPU with a 64-bit peripheral, such as a Midgard GPU. C's type promotion -+ * is complex and a straight cast does not work reliably as pointers are -+ * often considered as signed. -+ */ -+#define PTR_TO_U64(x) ((uint64_t)((uintptr_t)(x))) -+ -+/** -+ * @hideinitializer -+ * Function-like macro for stringizing a single level macro. -+ * @code -+ * #define MY_MACRO 32 -+ * CSTD_STR1( MY_MACRO ) -+ * > "MY_MACRO" -+ * @endcode -+ */ -+#define CSTD_STR1(x) #x -+ -+/** -+ * @hideinitializer -+ * Function-like macro for stringizing a macro's value. This should not be used -+ * if the macro is defined in a way which may have no value; use the -+ * alternative @c CSTD_STR2N macro should be used instead. -+ * @code -+ * #define MY_MACRO 32 -+ * CSTD_STR2( MY_MACRO ) -+ * > "32" -+ * @endcode -+ */ -+#define CSTD_STR2(x) CSTD_STR1(x) -+ -+/** -+ * Specify an assertion value which is evaluated at compile time. Recommended -+ * usage is specification of a @c static @c INLINE function containing all of -+ * the assertions thus: -+ * -+ * @code -+ * static INLINE [module]_compile_time_assertions( void ) -+ * { -+ * COMPILE_TIME_ASSERT( sizeof(uintptr_t) == sizeof(intptr_t) ); -+ * } -+ * @endcode -+ * -+ * @note Use @c static not @c STATIC. We never want to turn off this @c static -+ * specification for testing purposes. -+ */ -+#define CSTD_COMPILE_TIME_ASSERT(expr) \ -+ do { switch (0) { case 0: case (expr):; } } while (false) -+ -+#endif /* _MALISW_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_midg_coherency.h b/drivers/gpu/arm/midgard/mali_midg_coherency.h -new file mode 100644 -index 0000000..a509cbd ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_midg_coherency.h -@@ -0,0 +1,26 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _MIDG_COHERENCY_H_ -+#define _MIDG_COHERENCY_H_ -+ -+#define COHERENCY_ACE_LITE 0 -+#define COHERENCY_ACE 1 -+#define COHERENCY_NONE 31 -+#define COHERENCY_FEATURE_BIT(x) (1 << (x)) -+ -+#endif /* _MIDG_COHERENCY_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_midg_regmap.h b/drivers/gpu/arm/midgard/mali_midg_regmap.h -new file mode 100644 -index 0000000..7d7b7bc ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_midg_regmap.h -@@ -0,0 +1,611 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _MIDGARD_REGMAP_H_ -+#define _MIDGARD_REGMAP_H_ -+ -+#include "mali_midg_coherency.h" -+#include "mali_kbase_gpu_id.h" -+ -+/* -+ * Begin Register Offsets -+ */ -+ -+#define GPU_CONTROL_BASE 0x0000 -+#define GPU_CONTROL_REG(r) (GPU_CONTROL_BASE + (r)) -+#define GPU_ID 0x000 /* (RO) GPU and revision identifier */ -+#define L2_FEATURES 0x004 /* (RO) Level 2 cache features */ -+#define SUSPEND_SIZE 0x008 /* (RO) Fixed-function suspend buffer -+ size */ -+#define TILER_FEATURES 0x00C /* (RO) Tiler Features */ -+#define MEM_FEATURES 0x010 /* (RO) Memory system features */ -+#define MMU_FEATURES 0x014 /* (RO) MMU features */ -+#define AS_PRESENT 0x018 /* (RO) Address space slots present */ -+#define JS_PRESENT 0x01C /* (RO) Job slots present */ -+#define GPU_IRQ_RAWSTAT 0x020 /* (RW) */ -+#define GPU_IRQ_CLEAR 0x024 /* (WO) */ -+#define GPU_IRQ_MASK 0x028 /* (RW) */ -+#define GPU_IRQ_STATUS 0x02C /* (RO) */ -+ -+/* IRQ flags */ -+#define GPU_FAULT (1 << 0) /* A GPU Fault has occurred */ -+#define MULTIPLE_GPU_FAULTS (1 << 7) /* More than one GPU Fault occurred. */ -+#define RESET_COMPLETED (1 << 8) /* Set when a reset has completed. Intended to use with SOFT_RESET -+ commands which may take time. */ -+#define POWER_CHANGED_SINGLE (1 << 9) /* Set when a single core has finished powering up or down. */ -+#define POWER_CHANGED_ALL (1 << 10) /* Set when all cores have finished powering up or down -+ and the power manager is idle. */ -+ -+#define PRFCNT_SAMPLE_COMPLETED (1 << 16) /* Set when a performance count sample has completed. */ -+#define CLEAN_CACHES_COMPLETED (1 << 17) /* Set when a cache clean operation has completed. */ -+ -+#define GPU_IRQ_REG_ALL (GPU_FAULT | MULTIPLE_GPU_FAULTS | RESET_COMPLETED \ -+ | POWER_CHANGED_ALL | PRFCNT_SAMPLE_COMPLETED) -+ -+#define GPU_COMMAND 0x030 /* (WO) */ -+#define GPU_STATUS 0x034 /* (RO) */ -+#define LATEST_FLUSH 0x038 /* (RO) */ -+ -+#define GROUPS_L2_COHERENT (1 << 0) /* Cores groups are l2 coherent */ -+#define GPU_DBGEN (1 << 8) /* DBGEN wire status */ -+ -+#define GPU_FAULTSTATUS 0x03C /* (RO) GPU exception type and fault status */ -+#define GPU_FAULTADDRESS_LO 0x040 /* (RO) GPU exception fault address, low word */ -+#define GPU_FAULTADDRESS_HI 0x044 /* (RO) GPU exception fault address, high word */ -+ -+#define PWR_KEY 0x050 /* (WO) Power manager key register */ -+#define PWR_OVERRIDE0 0x054 /* (RW) Power manager override settings */ -+#define PWR_OVERRIDE1 0x058 /* (RW) Power manager override settings */ -+ -+#define PRFCNT_BASE_LO 0x060 /* (RW) Performance counter memory region base address, low word */ -+#define PRFCNT_BASE_HI 0x064 /* (RW) Performance counter memory region base address, high word */ -+#define PRFCNT_CONFIG 0x068 /* (RW) Performance counter configuration */ -+#define PRFCNT_JM_EN 0x06C /* (RW) Performance counter enable flags for Job Manager */ -+#define PRFCNT_SHADER_EN 0x070 /* (RW) Performance counter enable flags for shader cores */ -+#define PRFCNT_TILER_EN 0x074 /* (RW) Performance counter enable flags for tiler */ -+#define PRFCNT_MMU_L2_EN 0x07C /* (RW) Performance counter enable flags for MMU/L2 cache */ -+ -+#define CYCLE_COUNT_LO 0x090 /* (RO) Cycle counter, low word */ -+#define CYCLE_COUNT_HI 0x094 /* (RO) Cycle counter, high word */ -+#define TIMESTAMP_LO 0x098 /* (RO) Global time stamp counter, low word */ -+#define TIMESTAMP_HI 0x09C /* (RO) Global time stamp counter, high word */ -+ -+#define THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ -+#define THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ -+#define THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ -+#define THREAD_FEATURES 0x0AC /* (RO) Thread features */ -+ -+#define TEXTURE_FEATURES_0 0x0B0 /* (RO) Support flags for indexed texture formats 0..31 */ -+#define TEXTURE_FEATURES_1 0x0B4 /* (RO) Support flags for indexed texture formats 32..63 */ -+#define TEXTURE_FEATURES_2 0x0B8 /* (RO) Support flags for indexed texture formats 64..95 */ -+ -+#define TEXTURE_FEATURES_REG(n) GPU_CONTROL_REG(TEXTURE_FEATURES_0 + ((n) << 2)) -+ -+#define JS0_FEATURES 0x0C0 /* (RO) Features of job slot 0 */ -+#define JS1_FEATURES 0x0C4 /* (RO) Features of job slot 1 */ -+#define JS2_FEATURES 0x0C8 /* (RO) Features of job slot 2 */ -+#define JS3_FEATURES 0x0CC /* (RO) Features of job slot 3 */ -+#define JS4_FEATURES 0x0D0 /* (RO) Features of job slot 4 */ -+#define JS5_FEATURES 0x0D4 /* (RO) Features of job slot 5 */ -+#define JS6_FEATURES 0x0D8 /* (RO) Features of job slot 6 */ -+#define JS7_FEATURES 0x0DC /* (RO) Features of job slot 7 */ -+#define JS8_FEATURES 0x0E0 /* (RO) Features of job slot 8 */ -+#define JS9_FEATURES 0x0E4 /* (RO) Features of job slot 9 */ -+#define JS10_FEATURES 0x0E8 /* (RO) Features of job slot 10 */ -+#define JS11_FEATURES 0x0EC /* (RO) Features of job slot 11 */ -+#define JS12_FEATURES 0x0F0 /* (RO) Features of job slot 12 */ -+#define JS13_FEATURES 0x0F4 /* (RO) Features of job slot 13 */ -+#define JS14_FEATURES 0x0F8 /* (RO) Features of job slot 14 */ -+#define JS15_FEATURES 0x0FC /* (RO) Features of job slot 15 */ -+ -+#define JS_FEATURES_REG(n) GPU_CONTROL_REG(JS0_FEATURES + ((n) << 2)) -+ -+#define SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */ -+#define SHADER_PRESENT_HI 0x104 /* (RO) Shader core present bitmap, high word */ -+ -+#define TILER_PRESENT_LO 0x110 /* (RO) Tiler core present bitmap, low word */ -+#define TILER_PRESENT_HI 0x114 /* (RO) Tiler core present bitmap, high word */ -+ -+#define L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */ -+#define L2_PRESENT_HI 0x124 /* (RO) Level 2 cache present bitmap, high word */ -+ -+#define STACK_PRESENT_LO 0xE00 /* (RO) Core stack present bitmap, low word */ -+#define STACK_PRESENT_HI 0xE04 /* (RO) Core stack present bitmap, high word */ -+ -+ -+#define SHADER_READY_LO 0x140 /* (RO) Shader core ready bitmap, low word */ -+#define SHADER_READY_HI 0x144 /* (RO) Shader core ready bitmap, high word */ -+ -+#define TILER_READY_LO 0x150 /* (RO) Tiler core ready bitmap, low word */ -+#define TILER_READY_HI 0x154 /* (RO) Tiler core ready bitmap, high word */ -+ -+#define L2_READY_LO 0x160 /* (RO) Level 2 cache ready bitmap, low word */ -+#define L2_READY_HI 0x164 /* (RO) Level 2 cache ready bitmap, high word */ -+ -+#define STACK_READY_LO 0xE10 /* (RO) Core stack ready bitmap, low word */ -+#define STACK_READY_HI 0xE14 /* (RO) Core stack ready bitmap, high word */ -+ -+ -+#define SHADER_PWRON_LO 0x180 /* (WO) Shader core power on bitmap, low word */ -+#define SHADER_PWRON_HI 0x184 /* (WO) Shader core power on bitmap, high word */ -+ -+#define TILER_PWRON_LO 0x190 /* (WO) Tiler core power on bitmap, low word */ -+#define TILER_PWRON_HI 0x194 /* (WO) Tiler core power on bitmap, high word */ -+ -+#define L2_PWRON_LO 0x1A0 /* (WO) Level 2 cache power on bitmap, low word */ -+#define L2_PWRON_HI 0x1A4 /* (WO) Level 2 cache power on bitmap, high word */ -+ -+#define STACK_PWRON_LO 0xE20 /* (RO) Core stack power on bitmap, low word */ -+#define STACK_PWRON_HI 0xE24 /* (RO) Core stack power on bitmap, high word */ -+ -+ -+#define SHADER_PWROFF_LO 0x1C0 /* (WO) Shader core power off bitmap, low word */ -+#define SHADER_PWROFF_HI 0x1C4 /* (WO) Shader core power off bitmap, high word */ -+ -+#define TILER_PWROFF_LO 0x1D0 /* (WO) Tiler core power off bitmap, low word */ -+#define TILER_PWROFF_HI 0x1D4 /* (WO) Tiler core power off bitmap, high word */ -+ -+#define L2_PWROFF_LO 0x1E0 /* (WO) Level 2 cache power off bitmap, low word */ -+#define L2_PWROFF_HI 0x1E4 /* (WO) Level 2 cache power off bitmap, high word */ -+ -+#define STACK_PWROFF_LO 0xE30 /* (RO) Core stack power off bitmap, low word */ -+#define STACK_PRWOFF_HI 0xE34 /* (RO) Core stack power off bitmap, high word */ -+ -+ -+#define SHADER_PWRTRANS_LO 0x200 /* (RO) Shader core power transition bitmap, low word */ -+#define SHADER_PWRTRANS_HI 0x204 /* (RO) Shader core power transition bitmap, high word */ -+ -+#define TILER_PWRTRANS_LO 0x210 /* (RO) Tiler core power transition bitmap, low word */ -+#define TILER_PWRTRANS_HI 0x214 /* (RO) Tiler core power transition bitmap, high word */ -+ -+#define L2_PWRTRANS_LO 0x220 /* (RO) Level 2 cache power transition bitmap, low word */ -+#define L2_PWRTRANS_HI 0x224 /* (RO) Level 2 cache power transition bitmap, high word */ -+ -+#define STACK_PWRTRANS_LO 0xE40 /* (RO) Core stack power transition bitmap, low word */ -+#define STACK_PRWTRANS_HI 0xE44 /* (RO) Core stack power transition bitmap, high word */ -+ -+ -+#define SHADER_PWRACTIVE_LO 0x240 /* (RO) Shader core active bitmap, low word */ -+#define SHADER_PWRACTIVE_HI 0x244 /* (RO) Shader core active bitmap, high word */ -+ -+#define TILER_PWRACTIVE_LO 0x250 /* (RO) Tiler core active bitmap, low word */ -+#define TILER_PWRACTIVE_HI 0x254 /* (RO) Tiler core active bitmap, high word */ -+ -+#define L2_PWRACTIVE_LO 0x260 /* (RO) Level 2 cache active bitmap, low word */ -+#define L2_PWRACTIVE_HI 0x264 /* (RO) Level 2 cache active bitmap, high word */ -+ -+#define COHERENCY_FEATURES 0x300 /* (RO) Coherency features present */ -+#define COHERENCY_ENABLE 0x304 /* (RW) Coherency enable */ -+ -+#define JM_CONFIG 0xF00 /* (RW) Job Manager configuration register (Implementation specific register) */ -+#define SHADER_CONFIG 0xF04 /* (RW) Shader core configuration settings (Implementation specific register) */ -+#define TILER_CONFIG 0xF08 /* (RW) Tiler core configuration settings (Implementation specific register) */ -+#define L2_MMU_CONFIG 0xF0C /* (RW) Configuration of the L2 cache and MMU (Implementation specific register) */ -+ -+#define JOB_CONTROL_BASE 0x1000 -+ -+#define JOB_CONTROL_REG(r) (JOB_CONTROL_BASE + (r)) -+ -+#define JOB_IRQ_RAWSTAT 0x000 /* Raw interrupt status register */ -+#define JOB_IRQ_CLEAR 0x004 /* Interrupt clear register */ -+#define JOB_IRQ_MASK 0x008 /* Interrupt mask register */ -+#define JOB_IRQ_STATUS 0x00C /* Interrupt status register */ -+#define JOB_IRQ_JS_STATE 0x010 /* status==active and _next == busy snapshot from last JOB_IRQ_CLEAR */ -+#define JOB_IRQ_THROTTLE 0x014 /* cycles to delay delivering an interrupt externally. The JOB_IRQ_STATUS is NOT affected by this, just the delivery of the interrupt. */ -+ -+#define JOB_SLOT0 0x800 /* Configuration registers for job slot 0 */ -+#define JOB_SLOT1 0x880 /* Configuration registers for job slot 1 */ -+#define JOB_SLOT2 0x900 /* Configuration registers for job slot 2 */ -+#define JOB_SLOT3 0x980 /* Configuration registers for job slot 3 */ -+#define JOB_SLOT4 0xA00 /* Configuration registers for job slot 4 */ -+#define JOB_SLOT5 0xA80 /* Configuration registers for job slot 5 */ -+#define JOB_SLOT6 0xB00 /* Configuration registers for job slot 6 */ -+#define JOB_SLOT7 0xB80 /* Configuration registers for job slot 7 */ -+#define JOB_SLOT8 0xC00 /* Configuration registers for job slot 8 */ -+#define JOB_SLOT9 0xC80 /* Configuration registers for job slot 9 */ -+#define JOB_SLOT10 0xD00 /* Configuration registers for job slot 10 */ -+#define JOB_SLOT11 0xD80 /* Configuration registers for job slot 11 */ -+#define JOB_SLOT12 0xE00 /* Configuration registers for job slot 12 */ -+#define JOB_SLOT13 0xE80 /* Configuration registers for job slot 13 */ -+#define JOB_SLOT14 0xF00 /* Configuration registers for job slot 14 */ -+#define JOB_SLOT15 0xF80 /* Configuration registers for job slot 15 */ -+ -+#define JOB_SLOT_REG(n, r) (JOB_CONTROL_REG(JOB_SLOT0 + ((n) << 7)) + (r)) -+ -+#define JS_HEAD_LO 0x00 /* (RO) Job queue head pointer for job slot n, low word */ -+#define JS_HEAD_HI 0x04 /* (RO) Job queue head pointer for job slot n, high word */ -+#define JS_TAIL_LO 0x08 /* (RO) Job queue tail pointer for job slot n, low word */ -+#define JS_TAIL_HI 0x0C /* (RO) Job queue tail pointer for job slot n, high word */ -+#define JS_AFFINITY_LO 0x10 /* (RO) Core affinity mask for job slot n, low word */ -+#define JS_AFFINITY_HI 0x14 /* (RO) Core affinity mask for job slot n, high word */ -+#define JS_CONFIG 0x18 /* (RO) Configuration settings for job slot n */ -+#define JS_XAFFINITY 0x1C /* (RO) Extended affinity mask for job -+ slot n */ -+ -+#define JS_COMMAND 0x20 /* (WO) Command register for job slot n */ -+#define JS_STATUS 0x24 /* (RO) Status register for job slot n */ -+ -+#define JS_HEAD_NEXT_LO 0x40 /* (RW) Next job queue head pointer for job slot n, low word */ -+#define JS_HEAD_NEXT_HI 0x44 /* (RW) Next job queue head pointer for job slot n, high word */ -+ -+#define JS_AFFINITY_NEXT_LO 0x50 /* (RW) Next core affinity mask for job slot n, low word */ -+#define JS_AFFINITY_NEXT_HI 0x54 /* (RW) Next core affinity mask for job slot n, high word */ -+#define JS_CONFIG_NEXT 0x58 /* (RW) Next configuration settings for job slot n */ -+#define JS_XAFFINITY_NEXT 0x5C /* (RW) Next extended affinity mask for -+ job slot n */ -+ -+#define JS_COMMAND_NEXT 0x60 /* (RW) Next command register for job slot n */ -+ -+#define JS_FLUSH_ID_NEXT 0x70 /* (RW) Next job slot n cache flush ID */ -+ -+#define MEMORY_MANAGEMENT_BASE 0x2000 -+#define MMU_REG(r) (MEMORY_MANAGEMENT_BASE + (r)) -+ -+#define MMU_IRQ_RAWSTAT 0x000 /* (RW) Raw interrupt status register */ -+#define MMU_IRQ_CLEAR 0x004 /* (WO) Interrupt clear register */ -+#define MMU_IRQ_MASK 0x008 /* (RW) Interrupt mask register */ -+#define MMU_IRQ_STATUS 0x00C /* (RO) Interrupt status register */ -+ -+#define MMU_AS0 0x400 /* Configuration registers for address space 0 */ -+#define MMU_AS1 0x440 /* Configuration registers for address space 1 */ -+#define MMU_AS2 0x480 /* Configuration registers for address space 2 */ -+#define MMU_AS3 0x4C0 /* Configuration registers for address space 3 */ -+#define MMU_AS4 0x500 /* Configuration registers for address space 4 */ -+#define MMU_AS5 0x540 /* Configuration registers for address space 5 */ -+#define MMU_AS6 0x580 /* Configuration registers for address space 6 */ -+#define MMU_AS7 0x5C0 /* Configuration registers for address space 7 */ -+#define MMU_AS8 0x600 /* Configuration registers for address space 8 */ -+#define MMU_AS9 0x640 /* Configuration registers for address space 9 */ -+#define MMU_AS10 0x680 /* Configuration registers for address space 10 */ -+#define MMU_AS11 0x6C0 /* Configuration registers for address space 11 */ -+#define MMU_AS12 0x700 /* Configuration registers for address space 12 */ -+#define MMU_AS13 0x740 /* Configuration registers for address space 13 */ -+#define MMU_AS14 0x780 /* Configuration registers for address space 14 */ -+#define MMU_AS15 0x7C0 /* Configuration registers for address space 15 */ -+ -+#define MMU_AS_REG(n, r) (MMU_REG(MMU_AS0 + ((n) << 6)) + (r)) -+ -+#define AS_TRANSTAB_LO 0x00 /* (RW) Translation Table Base Address for address space n, low word */ -+#define AS_TRANSTAB_HI 0x04 /* (RW) Translation Table Base Address for address space n, high word */ -+#define AS_MEMATTR_LO 0x08 /* (RW) Memory attributes for address space n, low word. */ -+#define AS_MEMATTR_HI 0x0C /* (RW) Memory attributes for address space n, high word. */ -+#define AS_LOCKADDR_LO 0x10 /* (RW) Lock region address for address space n, low word */ -+#define AS_LOCKADDR_HI 0x14 /* (RW) Lock region address for address space n, high word */ -+#define AS_COMMAND 0x18 /* (WO) MMU command register for address space n */ -+#define AS_FAULTSTATUS 0x1C /* (RO) MMU fault status register for address space n */ -+#define AS_FAULTADDRESS_LO 0x20 /* (RO) Fault Address for address space n, low word */ -+#define AS_FAULTADDRESS_HI 0x24 /* (RO) Fault Address for address space n, high word */ -+#define AS_STATUS 0x28 /* (RO) Status flags for address space n */ -+ -+ -+/* (RW) Translation table configuration for address space n, low word */ -+#define AS_TRANSCFG_LO 0x30 -+/* (RW) Translation table configuration for address space n, high word */ -+#define AS_TRANSCFG_HI 0x34 -+/* (RO) Secondary fault address for address space n, low word */ -+#define AS_FAULTEXTRA_LO 0x38 -+/* (RO) Secondary fault address for address space n, high word */ -+#define AS_FAULTEXTRA_HI 0x3C -+ -+/* End Register Offsets */ -+ -+/* -+ * MMU_IRQ_RAWSTAT register values. Values are valid also for -+ MMU_IRQ_CLEAR, MMU_IRQ_MASK, MMU_IRQ_STATUS registers. -+ */ -+ -+#define MMU_PAGE_FAULT_FLAGS 16 -+ -+/* Macros returning a bitmask to retrieve page fault or bus error flags from -+ * MMU registers */ -+#define MMU_PAGE_FAULT(n) (1UL << (n)) -+#define MMU_BUS_ERROR(n) (1UL << ((n) + MMU_PAGE_FAULT_FLAGS)) -+ -+/* -+ * Begin LPAE MMU TRANSTAB register values -+ */ -+#define AS_TRANSTAB_LPAE_ADDR_SPACE_MASK 0xfffff000 -+#define AS_TRANSTAB_LPAE_ADRMODE_UNMAPPED (0u << 0) -+#define AS_TRANSTAB_LPAE_ADRMODE_IDENTITY (1u << 1) -+#define AS_TRANSTAB_LPAE_ADRMODE_TABLE (3u << 0) -+#define AS_TRANSTAB_LPAE_READ_INNER (1u << 2) -+#define AS_TRANSTAB_LPAE_SHARE_OUTER (1u << 4) -+ -+#define AS_TRANSTAB_LPAE_ADRMODE_MASK 0x00000003 -+ -+/* -+ * Begin AARCH64 MMU TRANSTAB register values -+ */ -+#define MMU_HW_OUTA_BITS 40 -+#define AS_TRANSTAB_BASE_MASK ((1ULL << MMU_HW_OUTA_BITS) - (1ULL << 4)) -+ -+/* -+ * Begin MMU STATUS register values -+ */ -+#define AS_STATUS_AS_ACTIVE 0x01 -+ -+#define AS_FAULTSTATUS_EXCEPTION_CODE_MASK (0x7<<3) -+#define AS_FAULTSTATUS_EXCEPTION_CODE_TRANSLATION_FAULT (0x0<<3) -+#define AS_FAULTSTATUS_EXCEPTION_CODE_PERMISSION_FAULT (0x1<<3) -+#define AS_FAULTSTATUS_EXCEPTION_CODE_TRANSTAB_BUS_FAULT (0x2<<3) -+#define AS_FAULTSTATUS_EXCEPTION_CODE_ACCESS_FLAG (0x3<<3) -+ -+#define AS_FAULTSTATUS_EXCEPTION_CODE_ADDRESS_SIZE_FAULT (0x4<<3) -+#define AS_FAULTSTATUS_EXCEPTION_CODE_MEMORY_ATTRIBUTES_FAULT (0x5<<3) -+ -+#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3<<8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0<<8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1<<8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2<<8) -+#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3<<8) -+ -+/* -+ * Begin MMU TRANSCFG register values -+ */ -+ -+#define AS_TRANSCFG_ADRMODE_LEGACY 0 -+#define AS_TRANSCFG_ADRMODE_UNMAPPED 1 -+#define AS_TRANSCFG_ADRMODE_IDENTITY 2 -+#define AS_TRANSCFG_ADRMODE_AARCH64_4K 6 -+#define AS_TRANSCFG_ADRMODE_AARCH64_64K 8 -+ -+#define AS_TRANSCFG_ADRMODE_MASK 0xF -+ -+ -+/* -+ * Begin TRANSCFG register values -+ */ -+#define AS_TRANSCFG_PTW_MEMATTR_MASK (3 << 24) -+#define AS_TRANSCFG_PTW_MEMATTR_NON_CACHEABLE (1 << 24) -+#define AS_TRANSCFG_PTW_MEMATTR_WRITE_BACK (2 << 24) -+ -+#define AS_TRANSCFG_PTW_SH_MASK ((3 << 28)) -+#define AS_TRANSCFG_PTW_SH_OS (2 << 28) -+#define AS_TRANSCFG_PTW_SH_IS (3 << 28) -+ -+/* -+ * Begin Command Values -+ */ -+ -+/* JS_COMMAND register commands */ -+#define JS_COMMAND_NOP 0x00 /* NOP Operation. Writing this value is ignored */ -+#define JS_COMMAND_START 0x01 /* Start processing a job chain. Writing this value is ignored */ -+#define JS_COMMAND_SOFT_STOP 0x02 /* Gently stop processing a job chain */ -+#define JS_COMMAND_HARD_STOP 0x03 /* Rudely stop processing a job chain */ -+#define JS_COMMAND_SOFT_STOP_0 0x04 /* Execute SOFT_STOP if JOB_CHAIN_FLAG is 0 */ -+#define JS_COMMAND_HARD_STOP_0 0x05 /* Execute HARD_STOP if JOB_CHAIN_FLAG is 0 */ -+#define JS_COMMAND_SOFT_STOP_1 0x06 /* Execute SOFT_STOP if JOB_CHAIN_FLAG is 1 */ -+#define JS_COMMAND_HARD_STOP_1 0x07 /* Execute HARD_STOP if JOB_CHAIN_FLAG is 1 */ -+ -+#define JS_COMMAND_MASK 0x07 /* Mask of bits currently in use by the HW */ -+ -+/* AS_COMMAND register commands */ -+#define AS_COMMAND_NOP 0x00 /* NOP Operation */ -+#define AS_COMMAND_UPDATE 0x01 /* Broadcasts the values in AS_TRANSTAB and ASn_MEMATTR to all MMUs */ -+#define AS_COMMAND_LOCK 0x02 /* Issue a lock region command to all MMUs */ -+#define AS_COMMAND_UNLOCK 0x03 /* Issue a flush region command to all MMUs */ -+#define AS_COMMAND_FLUSH 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs -+ (deprecated - only for use with T60x) */ -+#define AS_COMMAND_FLUSH_PT 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs */ -+#define AS_COMMAND_FLUSH_MEM 0x05 /* Wait for memory accesses to complete, flush all the L1s cache then -+ flush all L2 caches then issue a flush region command to all MMUs */ -+ -+/* Possible values of JS_CONFIG and JS_CONFIG_NEXT registers */ -+#define JS_CONFIG_START_FLUSH_NO_ACTION (0u << 0) -+#define JS_CONFIG_START_FLUSH_CLEAN (1u << 8) -+#define JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE (3u << 8) -+#define JS_CONFIG_START_MMU (1u << 10) -+#define JS_CONFIG_JOB_CHAIN_FLAG (1u << 11) -+#define JS_CONFIG_END_FLUSH_NO_ACTION JS_CONFIG_START_FLUSH_NO_ACTION -+#define JS_CONFIG_END_FLUSH_CLEAN (1u << 12) -+#define JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE (3u << 12) -+#define JS_CONFIG_ENABLE_FLUSH_REDUCTION (1u << 14) -+#define JS_CONFIG_DISABLE_DESCRIPTOR_WR_BK (1u << 15) -+#define JS_CONFIG_THREAD_PRI(n) ((n) << 16) -+ -+/* JS_XAFFINITY register values */ -+#define JS_XAFFINITY_XAFFINITY_ENABLE (1u << 0) -+#define JS_XAFFINITY_TILER_ENABLE (1u << 8) -+#define JS_XAFFINITY_CACHE_ENABLE (1u << 16) -+ -+/* JS_STATUS register values */ -+ -+/* NOTE: Please keep this values in sync with enum base_jd_event_code in mali_base_kernel.h. -+ * The values are separated to avoid dependency of userspace and kernel code. -+ */ -+ -+/* Group of values representing the job status insead a particular fault */ -+#define JS_STATUS_NO_EXCEPTION_BASE 0x00 -+#define JS_STATUS_INTERRUPTED (JS_STATUS_NO_EXCEPTION_BASE + 0x02) /* 0x02 means INTERRUPTED */ -+#define JS_STATUS_STOPPED (JS_STATUS_NO_EXCEPTION_BASE + 0x03) /* 0x03 means STOPPED */ -+#define JS_STATUS_TERMINATED (JS_STATUS_NO_EXCEPTION_BASE + 0x04) /* 0x04 means TERMINATED */ -+ -+/* General fault values */ -+#define JS_STATUS_FAULT_BASE 0x40 -+#define JS_STATUS_CONFIG_FAULT (JS_STATUS_FAULT_BASE) /* 0x40 means CONFIG FAULT */ -+#define JS_STATUS_POWER_FAULT (JS_STATUS_FAULT_BASE + 0x01) /* 0x41 means POWER FAULT */ -+#define JS_STATUS_READ_FAULT (JS_STATUS_FAULT_BASE + 0x02) /* 0x42 means READ FAULT */ -+#define JS_STATUS_WRITE_FAULT (JS_STATUS_FAULT_BASE + 0x03) /* 0x43 means WRITE FAULT */ -+#define JS_STATUS_AFFINITY_FAULT (JS_STATUS_FAULT_BASE + 0x04) /* 0x44 means AFFINITY FAULT */ -+#define JS_STATUS_BUS_FAULT (JS_STATUS_FAULT_BASE + 0x08) /* 0x48 means BUS FAULT */ -+ -+/* Instruction or data faults */ -+#define JS_STATUS_INSTRUCTION_FAULT_BASE 0x50 -+#define JS_STATUS_INSTR_INVALID_PC (JS_STATUS_INSTRUCTION_FAULT_BASE) /* 0x50 means INSTR INVALID PC */ -+#define JS_STATUS_INSTR_INVALID_ENC (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x01) /* 0x51 means INSTR INVALID ENC */ -+#define JS_STATUS_INSTR_TYPE_MISMATCH (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x02) /* 0x52 means INSTR TYPE MISMATCH */ -+#define JS_STATUS_INSTR_OPERAND_FAULT (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x03) /* 0x53 means INSTR OPERAND FAULT */ -+#define JS_STATUS_INSTR_TLS_FAULT (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x04) /* 0x54 means INSTR TLS FAULT */ -+#define JS_STATUS_INSTR_BARRIER_FAULT (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x05) /* 0x55 means INSTR BARRIER FAULT */ -+#define JS_STATUS_INSTR_ALIGN_FAULT (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x06) /* 0x56 means INSTR ALIGN FAULT */ -+/* NOTE: No fault with 0x57 code defined in spec. */ -+#define JS_STATUS_DATA_INVALID_FAULT (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x08) /* 0x58 means DATA INVALID FAULT */ -+#define JS_STATUS_TILE_RANGE_FAULT (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x09) /* 0x59 means TILE RANGE FAULT */ -+#define JS_STATUS_ADDRESS_RANGE_FAULT (JS_STATUS_INSTRUCTION_FAULT_BASE + 0x0A) /* 0x5A means ADDRESS RANGE FAULT */ -+ -+/* Other faults */ -+#define JS_STATUS_MEMORY_FAULT_BASE 0x60 -+#define JS_STATUS_OUT_OF_MEMORY (JS_STATUS_MEMORY_FAULT_BASE) /* 0x60 means OUT OF MEMORY */ -+#define JS_STATUS_UNKNOWN 0x7F /* 0x7F means UNKNOWN */ -+ -+/* GPU_COMMAND values */ -+#define GPU_COMMAND_NOP 0x00 /* No operation, nothing happens */ -+#define GPU_COMMAND_SOFT_RESET 0x01 /* Stop all external bus interfaces, and then reset the entire GPU. */ -+#define GPU_COMMAND_HARD_RESET 0x02 /* Immediately reset the entire GPU. */ -+#define GPU_COMMAND_PRFCNT_CLEAR 0x03 /* Clear all performance counters, setting them all to zero. */ -+#define GPU_COMMAND_PRFCNT_SAMPLE 0x04 /* Sample all performance counters, writing them out to memory */ -+#define GPU_COMMAND_CYCLE_COUNT_START 0x05 /* Starts the cycle counter, and system timestamp propagation */ -+#define GPU_COMMAND_CYCLE_COUNT_STOP 0x06 /* Stops the cycle counter, and system timestamp propagation */ -+#define GPU_COMMAND_CLEAN_CACHES 0x07 /* Clean all caches */ -+#define GPU_COMMAND_CLEAN_INV_CACHES 0x08 /* Clean and invalidate all caches */ -+#define GPU_COMMAND_SET_PROTECTED_MODE 0x09 /* Places the GPU in protected mode */ -+ -+/* End Command Values */ -+ -+/* GPU_STATUS values */ -+#define GPU_STATUS_PRFCNT_ACTIVE (1 << 2) /* Set if the performance counters are active. */ -+#define GPU_STATUS_PROTECTED_MODE_ACTIVE (1 << 7) /* Set if protected mode is active */ -+ -+/* PRFCNT_CONFIG register values */ -+#define PRFCNT_CONFIG_MODE_SHIFT 0 /* Counter mode position. */ -+#define PRFCNT_CONFIG_AS_SHIFT 4 /* Address space bitmap position. */ -+#define PRFCNT_CONFIG_SETSELECT_SHIFT 8 /* Set select position. */ -+ -+#define PRFCNT_CONFIG_MODE_OFF 0 /* The performance counters are disabled. */ -+#define PRFCNT_CONFIG_MODE_MANUAL 1 /* The performance counters are enabled, but are only written out when a PRFCNT_SAMPLE command is issued using the GPU_COMMAND register. */ -+#define PRFCNT_CONFIG_MODE_TILE 2 /* The performance counters are enabled, and are written out each time a tile finishes rendering. */ -+ -+/* AS_MEMATTR values: */ -+/* Use GPU implementation-defined caching policy. */ -+#define AS_MEMATTR_IMPL_DEF_CACHE_POLICY 0x88ull -+/* The attribute set to force all resources to be cached. */ -+#define AS_MEMATTR_FORCE_TO_CACHE_ALL 0x8Full -+/* Inner write-alloc cache setup, no outer caching */ -+#define AS_MEMATTR_WRITE_ALLOC 0x8Dull -+ -+/* Set to implementation defined, outer caching */ -+#define AS_MEMATTR_AARCH64_OUTER_IMPL_DEF 0x88ull -+/* Set to write back memory, outer caching */ -+#define AS_MEMATTR_AARCH64_OUTER_WA 0x8Dull -+ -+/* Use GPU implementation-defined caching policy. */ -+#define AS_MEMATTR_LPAE_IMPL_DEF_CACHE_POLICY 0x48ull -+/* The attribute set to force all resources to be cached. */ -+#define AS_MEMATTR_LPAE_FORCE_TO_CACHE_ALL 0x4Full -+/* Inner write-alloc cache setup, no outer caching */ -+#define AS_MEMATTR_LPAE_WRITE_ALLOC 0x4Dull -+/* Set to implementation defined, outer caching */ -+#define AS_MEMATTR_LPAE_OUTER_IMPL_DEF 0x88ull -+/* Set to write back memory, outer caching */ -+#define AS_MEMATTR_LPAE_OUTER_WA 0x8Dull -+ -+/* Symbol for default MEMATTR to use */ -+ -+/* Default is - HW implementation defined caching */ -+#define AS_MEMATTR_INDEX_DEFAULT 0 -+#define AS_MEMATTR_INDEX_DEFAULT_ACE 3 -+ -+/* HW implementation defined caching */ -+#define AS_MEMATTR_INDEX_IMPL_DEF_CACHE_POLICY 0 -+/* Force cache on */ -+#define AS_MEMATTR_INDEX_FORCE_TO_CACHE_ALL 1 -+/* Write-alloc */ -+#define AS_MEMATTR_INDEX_WRITE_ALLOC 2 -+/* Outer coherent, inner implementation defined policy */ -+#define AS_MEMATTR_INDEX_OUTER_IMPL_DEF 3 -+/* Outer coherent, write alloc inner */ -+#define AS_MEMATTR_INDEX_OUTER_WA 4 -+ -+/* JS_FEATURES register */ -+ -+#define JS_FEATURE_NULL_JOB (1u << 1) -+#define JS_FEATURE_SET_VALUE_JOB (1u << 2) -+#define JS_FEATURE_CACHE_FLUSH_JOB (1u << 3) -+#define JS_FEATURE_COMPUTE_JOB (1u << 4) -+#define JS_FEATURE_VERTEX_JOB (1u << 5) -+#define JS_FEATURE_GEOMETRY_JOB (1u << 6) -+#define JS_FEATURE_TILER_JOB (1u << 7) -+#define JS_FEATURE_FUSED_JOB (1u << 8) -+#define JS_FEATURE_FRAGMENT_JOB (1u << 9) -+ -+/* End JS_FEATURES register */ -+ -+/* L2_MMU_CONFIG register */ -+#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT (23) -+#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY (0x1 << L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT (24) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_OCTANT (0x1 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_QUARTER (0x2 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_HALF (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) -+ -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT (26) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_OCTANT (0x1 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_QUARTER (0x2 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_HALF (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) -+/* End L2_MMU_CONFIG register */ -+ -+/* THREAD_* registers */ -+ -+/* THREAD_FEATURES IMPLEMENTATION_TECHNOLOGY values */ -+#define IMPLEMENTATION_UNSPECIFIED 0 -+#define IMPLEMENTATION_SILICON 1 -+#define IMPLEMENTATION_FPGA 2 -+#define IMPLEMENTATION_MODEL 3 -+ -+/* Default values when registers are not supported by the implemented hardware */ -+#define THREAD_MT_DEFAULT 256 -+#define THREAD_MWS_DEFAULT 256 -+#define THREAD_MBS_DEFAULT 256 -+#define THREAD_MR_DEFAULT 1024 -+#define THREAD_MTQ_DEFAULT 4 -+#define THREAD_MTGS_DEFAULT 10 -+ -+/* End THREAD_* registers */ -+ -+/* SHADER_CONFIG register */ -+ -+#define SC_ALT_COUNTERS (1ul << 3) -+#define SC_OVERRIDE_FWD_PIXEL_KILL (1ul << 4) -+#define SC_SDC_DISABLE_OQ_DISCARD (1ul << 6) -+#define SC_LS_ALLOW_ATTR_TYPES (1ul << 16) -+#define SC_LS_PAUSEBUFFER_DISABLE (1ul << 16) -+#define SC_LS_ATTR_CHECK_DISABLE (1ul << 18) -+#define SC_ENABLE_TEXGRD_FLAGS (1ul << 25) -+/* End SHADER_CONFIG register */ -+ -+/* TILER_CONFIG register */ -+ -+#define TC_CLOCK_GATE_OVERRIDE (1ul << 0) -+ -+/* End TILER_CONFIG register */ -+ -+/* JM_CONFIG register */ -+ -+#define JM_TIMESTAMP_OVERRIDE (1ul << 0) -+#define JM_CLOCK_GATE_OVERRIDE (1ul << 1) -+#define JM_JOB_THROTTLE_ENABLE (1ul << 2) -+#define JM_JOB_THROTTLE_LIMIT_SHIFT (3) -+#define JM_MAX_JOB_THROTTLE_LIMIT (0x3F) -+#define JM_FORCE_COHERENCY_FEATURES_SHIFT (2) -+#define JM_IDVS_GROUP_SIZE_SHIFT (16) -+#define JM_MAX_IDVS_GROUP_SIZE (0x3F) -+/* End JM_CONFIG register */ -+ -+ -+#endif /* _MIDGARD_REGMAP_H_ */ -diff --git a/drivers/gpu/arm/midgard/mali_timeline.h b/drivers/gpu/arm/midgard/mali_timeline.h -new file mode 100644 -index 0000000..bd5f661 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_timeline.h -@@ -0,0 +1,396 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM mali_timeline -+ -+#if !defined(_MALI_TIMELINE_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _MALI_TIMELINE_H -+ -+#include -+ -+TRACE_EVENT(mali_timeline_atoms_in_flight, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int tgid, -+ int count), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ tgid, -+ count), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, tgid) -+ __field(int, count) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->tgid = tgid; -+ __entry->count = count; -+ ), -+ -+ TP_printk("%i,%i.%.9i,%i,%i", CTX_SET_NR_ATOMS_IN_FLIGHT, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->tgid, -+ __entry->count) -+); -+ -+ -+TRACE_EVENT(mali_timeline_atom, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int event_type, -+ int tgid, -+ int atom_id), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ event_type, -+ tgid, -+ atom_id), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, event_type) -+ __field(int, tgid) -+ __field(int, atom_id) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->event_type = event_type; -+ __entry->tgid = tgid; -+ __entry->atom_id = atom_id; -+ ), -+ -+ TP_printk("%i,%i.%.9i,%i,%i,%i", __entry->event_type, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->tgid, -+ __entry->atom_id, -+ __entry->atom_id) -+); -+ -+TRACE_EVENT(mali_timeline_gpu_slot_active, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int event_type, -+ int tgid, -+ int js, -+ int count), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ event_type, -+ tgid, -+ js, -+ count), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, event_type) -+ __field(int, tgid) -+ __field(int, js) -+ __field(int, count) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->event_type = event_type; -+ __entry->tgid = tgid; -+ __entry->js = js; -+ __entry->count = count; -+ ), -+ -+ TP_printk("%i,%i.%.9i,%i,%i,%i", __entry->event_type, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->tgid, -+ __entry->js, -+ __entry->count) -+); -+ -+TRACE_EVENT(mali_timeline_gpu_slot_action, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int event_type, -+ int tgid, -+ int js, -+ int count), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ event_type, -+ tgid, -+ js, -+ count), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, event_type) -+ __field(int, tgid) -+ __field(int, js) -+ __field(int, count) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->event_type = event_type; -+ __entry->tgid = tgid; -+ __entry->js = js; -+ __entry->count = count; -+ ), -+ -+ TP_printk("%i,%i.%.9i,%i,%i,%i", __entry->event_type, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->tgid, -+ __entry->js, -+ __entry->count) -+); -+ -+TRACE_EVENT(mali_timeline_gpu_power_active, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int event_type, -+ int active), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ event_type, -+ active), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, event_type) -+ __field(int, active) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->event_type = event_type; -+ __entry->active = active; -+ ), -+ -+ TP_printk("%i,%i.%.9i,0,%i", __entry->event_type, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->active) -+ -+); -+ -+TRACE_EVENT(mali_timeline_l2_power_active, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int event_type, -+ int state), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ event_type, -+ state), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, event_type) -+ __field(int, state) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->event_type = event_type; -+ __entry->state = state; -+ ), -+ -+ TP_printk("%i,%i.%.9i,0,%i", __entry->event_type, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->state) -+ -+); -+TRACE_EVENT(mali_timeline_pm_event, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int event_type, -+ int pm_event_type, -+ unsigned int pm_event_id), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ event_type, -+ pm_event_type, -+ pm_event_id), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, event_type) -+ __field(int, pm_event_type) -+ __field(unsigned int, pm_event_id) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->event_type = event_type; -+ __entry->pm_event_type = pm_event_type; -+ __entry->pm_event_id = pm_event_id; -+ ), -+ -+ TP_printk("%i,%i.%.9i,0,%i,%u", __entry->event_type, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->pm_event_type, __entry->pm_event_id) -+ -+); -+ -+TRACE_EVENT(mali_timeline_slot_atom, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int event_type, -+ int tgid, -+ int js, -+ int atom_id), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ event_type, -+ tgid, -+ js, -+ atom_id), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, event_type) -+ __field(int, tgid) -+ __field(int, js) -+ __field(int, atom_id) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->event_type = event_type; -+ __entry->tgid = tgid; -+ __entry->js = js; -+ __entry->atom_id = atom_id; -+ ), -+ -+ TP_printk("%i,%i.%.9i,%i,%i,%i", __entry->event_type, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->tgid, -+ __entry->js, -+ __entry->atom_id) -+); -+ -+TRACE_EVENT(mali_timeline_pm_checktrans, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int trans_code, -+ int trans_id), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ trans_code, -+ trans_id), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, trans_code) -+ __field(int, trans_id) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->trans_code = trans_code; -+ __entry->trans_id = trans_id; -+ ), -+ -+ TP_printk("%i,%i.%.9i,0,%i", __entry->trans_code, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->trans_id) -+ -+); -+ -+TRACE_EVENT(mali_timeline_context_active, -+ -+ TP_PROTO(u64 ts_sec, -+ u32 ts_nsec, -+ int count), -+ -+ TP_ARGS(ts_sec, -+ ts_nsec, -+ count), -+ -+ TP_STRUCT__entry( -+ __field(u64, ts_sec) -+ __field(u32, ts_nsec) -+ __field(int, count) -+ ), -+ -+ TP_fast_assign( -+ __entry->ts_sec = ts_sec; -+ __entry->ts_nsec = ts_nsec; -+ __entry->count = count; -+ ), -+ -+ TP_printk("%i,%i.%.9i,0,%i", SW_SET_CONTEXT_ACTIVE, -+ (int)__entry->ts_sec, -+ (int)__entry->ts_nsec, -+ __entry->count) -+); -+ -+#endif /* _MALI_TIMELINE_H */ -+ -+#undef TRACE_INCLUDE_PATH -+#define TRACE_INCLUDE_PATH . -+ -+/* This part must be outside protection */ -+#include -+ -diff --git a/drivers/gpu/arm/midgard/mali_uk.h b/drivers/gpu/arm/midgard/mali_uk.h -new file mode 100644 -index 0000000..841d03f ---- /dev/null -+++ b/drivers/gpu/arm/midgard/mali_uk.h -@@ -0,0 +1,141 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010, 2012-2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file mali_uk.h -+ * Types and definitions that are common across OSs for both the user -+ * and kernel side of the User-Kernel interface. -+ */ -+ -+#ifndef _UK_H_ -+#define _UK_H_ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif /* __cplusplus */ -+ -+/** -+ * @addtogroup base_api -+ * @{ -+ */ -+ -+/** -+ * @defgroup uk_api User-Kernel Interface API -+ * -+ * The User-Kernel Interface abstracts the communication mechanism between the user and kernel-side code of device -+ * drivers developed as part of the Midgard DDK. Currently that includes the Base driver and the UMP driver. -+ * -+ * It exposes an OS independent API to user-side code (UKU) which routes functions calls to an OS-independent -+ * kernel-side API (UKK) via an OS-specific communication mechanism. -+ * -+ * This API is internal to the Midgard DDK and is not exposed to any applications. -+ * -+ * @{ -+ */ -+ -+/** -+ * These are identifiers for kernel-side drivers implementing a UK interface, aka UKK clients. The -+ * UK module maps this to an OS specific device name, e.g. "gpu_base" -> "GPU0:". Specify this -+ * identifier to select a UKK client to the uku_open() function. -+ * -+ * When a new UKK client driver is created a new identifier needs to be added to the uk_client_id -+ * enumeration and the uku_open() implemenation for the various OS ports need to be updated to -+ * provide a mapping of the identifier to the OS specific device name. -+ * -+ */ -+enum uk_client_id { -+ /** -+ * Value used to identify the Base driver UK client. -+ */ -+ UK_CLIENT_MALI_T600_BASE, -+ -+ /** The number of uk clients supported. This must be the last member of the enum */ -+ UK_CLIENT_COUNT -+}; -+ -+/** -+ * Each function callable through the UK interface has a unique number. -+ * Functions provided by UK clients start from number UK_FUNC_ID. -+ * Numbers below UK_FUNC_ID are used for internal UK functions. -+ */ -+enum uk_func { -+ UKP_FUNC_ID_CHECK_VERSION, /**< UKK Core internal function */ -+ /** -+ * Each UK client numbers the functions they provide starting from -+ * number UK_FUNC_ID. This number is then eventually assigned to the -+ * id field of the union uk_header structure when preparing to make a -+ * UK call. See your UK client for a list of their function numbers. -+ */ -+ UK_FUNC_ID = 512 -+}; -+ -+/** -+ * Arguments for a UK call are stored in a structure. This structure consists -+ * of a fixed size header and a payload. The header carries a 32-bit number -+ * identifying the UK function to be called (see uk_func). When the UKK client -+ * receives this header and executed the requested UK function, it will use -+ * the same header to store the result of the function in the form of a -+ * int return code. The size of this structure is such that the -+ * first member of the payload following the header can be accessed efficiently -+ * on a 32 and 64-bit kernel and the structure has the same size regardless -+ * of a 32 or 64-bit kernel. The uk_kernel_size_type type should be defined -+ * accordingly in the OS specific mali_uk_os.h header file. -+ */ -+union uk_header { -+ /** -+ * 32-bit number identifying the UK function to be called. -+ * Also see uk_func. -+ */ -+ u32 id; -+ /** -+ * The int return code returned by the called UK function. -+ * See the specification of the particular UK function you are -+ * calling for the meaning of the error codes returned. All -+ * UK functions return 0 on success. -+ */ -+ u32 ret; -+ /* -+ * Used to ensure 64-bit alignment of this union. Do not remove. -+ * This field is used for padding and does not need to be initialized. -+ */ -+ u64 sizer; -+}; -+ -+/** -+ * This structure carries a 16-bit major and minor number and is sent along with an internal UK call -+ * used during uku_open to identify the versions of the UK module in use by the user-side and kernel-side. -+ */ -+struct uku_version_check_args { -+ union uk_header header; -+ /**< UK call header */ -+ u16 major; -+ /**< This field carries the user-side major version on input and the kernel-side major version on output */ -+ u16 minor; -+ /**< This field carries the user-side minor version on input and the kernel-side minor version on output. */ -+ u8 padding[4]; -+}; -+ -+/** @} end group uk_api */ -+ -+/** @} *//* end group base_api */ -+ -+#ifdef __cplusplus -+} -+#endif /* __cplusplus */ -+#endif /* _UK_H_ */ -diff --git a/drivers/gpu/arm/midgard/platform/Kconfig b/drivers/gpu/arm/midgard/platform/Kconfig -new file mode 100644 -index 0000000..8fb4e91 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/Kconfig -@@ -0,0 +1,24 @@ -+# -+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+ -+# Add your platform specific Kconfig file here -+# -+# "drivers/gpu/arm/midgard/platform/xxx/Kconfig" -+# -+# Where xxx is the platform name is the name set in MALI_PLATFORM_THIRDPARTY_NAME -+# -+ -diff --git a/drivers/gpu/arm/midgard/platform/devicetree/Kbuild b/drivers/gpu/arm/midgard/platform/devicetree/Kbuild -new file mode 100644 -index 0000000..e888a42 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/devicetree/Kbuild -@@ -0,0 +1,18 @@ -+# -+# (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+mali_kbase-y += \ -+ $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_devicetree.o \ -+ $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_runtime_pm.o -diff --git a/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_config_devicetree.c b/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_config_devicetree.c -new file mode 100644 -index 0000000..b2a7c93 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_config_devicetree.c -@@ -0,0 +1,31 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+ -+int kbase_platform_early_init(void) -+{ -+ /* Nothing needed at this stage */ -+ return 0; -+} -+ -+static struct kbase_platform_config dummy_platform_config; -+ -+struct kbase_platform_config *kbase_get_platform_config(void) -+{ -+ return &dummy_platform_config; -+} -diff --git a/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_config_platform.h b/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_config_platform.h -new file mode 100644 -index 0000000..2ceca34 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_config_platform.h -@@ -0,0 +1,80 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * Maximum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MAX (5000) -+/** -+ * Minimum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MIN (5000) -+ -+/** -+ * CPU_SPEED_FUNC - A pointer to a function that calculates the CPU clock -+ * -+ * CPU clock speed of the platform is in MHz - see kbase_cpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_cpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define CPU_SPEED_FUNC (NULL) -+ -+/** -+ * GPU_SPEED_FUNC - A pointer to a function that calculates the GPU clock -+ * -+ * GPU clock speed of the platform in MHz - see kbase_gpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_gpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define GPU_SPEED_FUNC (NULL) -+ -+/** -+ * Power management configuration -+ * -+ * Attached value: pointer to @ref kbase_pm_callback_conf -+ * Default value: See @ref kbase_pm_callback_conf -+ */ -+#define POWER_MANAGEMENT_CALLBACKS (&pm_callbacks) -+ -+/** -+ * Platform specific configuration functions -+ * -+ * Attached value: pointer to @ref kbase_platform_funcs_conf -+ * Default value: See @ref kbase_platform_funcs_conf -+ */ -+#define PLATFORM_FUNCS (NULL) -+ -+extern struct kbase_pm_callback_conf pm_callbacks; -+ -+/** -+ * Autosuspend delay -+ * -+ * The delay time (in milliseconds) to be used for autosuspend -+ */ -+#define AUTO_SUSPEND_DELAY (100) -diff --git a/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_runtime_pm.c b/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_runtime_pm.c -new file mode 100644 -index 0000000..50cfb2c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_runtime_pm.c -@@ -0,0 +1,122 @@ -+/* -+ * -+ * (C) COPYRIGHT 2015, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include "mali_kbase_config_platform.h" -+ -+static int pm_callback_power_on(struct kbase_device *kbdev) -+{ -+ int ret = 1; /* Assume GPU has been powered off */ -+ int error; -+ -+ dev_dbg(kbdev->dev, "pm_callback_power_on %p\n", -+ (void *)kbdev->dev->pm_domain); -+ -+ error = pm_runtime_get_sync(kbdev->dev); -+ if (error == 1) { -+ /* -+ * Let core know that the chip has not been -+ * powered off, so we can save on re-initialization. -+ */ -+ ret = 0; -+ } -+ -+ dev_dbg(kbdev->dev, "pm_runtime_get_sync returned %d\n", error); -+ -+ return ret; -+} -+ -+static void pm_callback_power_off(struct kbase_device *kbdev) -+{ -+ dev_dbg(kbdev->dev, "pm_callback_power_off\n"); -+ -+ pm_runtime_mark_last_busy(kbdev->dev); -+ pm_runtime_put_autosuspend(kbdev->dev); -+} -+ -+int kbase_device_runtime_init(struct kbase_device *kbdev) -+{ -+ int ret = 0; -+ -+ dev_dbg(kbdev->dev, "kbase_device_runtime_init\n"); -+ -+ pm_runtime_set_autosuspend_delay(kbdev->dev, AUTO_SUSPEND_DELAY); -+ pm_runtime_use_autosuspend(kbdev->dev); -+ -+ pm_runtime_set_active(kbdev->dev); -+ pm_runtime_enable(kbdev->dev); -+ -+ if (!pm_runtime_enabled(kbdev->dev)) { -+ dev_warn(kbdev->dev, "pm_runtime not enabled"); -+ ret = -ENOSYS; -+ } -+ -+ return ret; -+} -+ -+void kbase_device_runtime_disable(struct kbase_device *kbdev) -+{ -+ dev_dbg(kbdev->dev, "kbase_device_runtime_disable\n"); -+ pm_runtime_disable(kbdev->dev); -+} -+ -+static int pm_callback_runtime_on(struct kbase_device *kbdev) -+{ -+ dev_dbg(kbdev->dev, "pm_callback_runtime_on\n"); -+ -+ return 0; -+} -+ -+static void pm_callback_runtime_off(struct kbase_device *kbdev) -+{ -+ dev_dbg(kbdev->dev, "pm_callback_runtime_off\n"); -+} -+ -+static void pm_callback_resume(struct kbase_device *kbdev) -+{ -+ int ret = pm_callback_runtime_on(kbdev); -+ -+ WARN_ON(ret); -+} -+ -+static void pm_callback_suspend(struct kbase_device *kbdev) -+{ -+ pm_callback_runtime_off(kbdev); -+} -+ -+struct kbase_pm_callback_conf pm_callbacks = { -+ .power_on_callback = pm_callback_power_on, -+ .power_off_callback = pm_callback_power_off, -+ .power_suspend_callback = pm_callback_suspend, -+ .power_resume_callback = pm_callback_resume, -+#ifdef KBASE_PM_RUNTIME -+ .power_runtime_init_callback = kbase_device_runtime_init, -+ .power_runtime_term_callback = kbase_device_runtime_disable, -+ .power_runtime_on_callback = pm_callback_runtime_on, -+ .power_runtime_off_callback = pm_callback_runtime_off, -+#else /* KBASE_PM_RUNTIME */ -+ .power_runtime_init_callback = NULL, -+ .power_runtime_term_callback = NULL, -+ .power_runtime_on_callback = NULL, -+ .power_runtime_off_callback = NULL, -+#endif /* KBASE_PM_RUNTIME */ -+}; -+ -+ -diff --git a/drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h b/drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h -new file mode 100644 -index 0000000..7cb3be7 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/mali_kbase_platform_common.h -@@ -0,0 +1,26 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * @brief Entry point to transfer control to a platform for early initialization -+ * -+ * This function is called early on in the initialization during execution of -+ * @ref kbase_driver_init. -+ * -+ * @return Zero to indicate success non-zero for failure. -+ */ -+int kbase_platform_early_init(void); -diff --git a/drivers/gpu/arm/midgard/platform/mali_kbase_platform_fake.h b/drivers/gpu/arm/midgard/platform/mali_kbase_platform_fake.h -new file mode 100644 -index 0000000..01f9dfc ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/mali_kbase_platform_fake.h -@@ -0,0 +1,38 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifdef CONFIG_MALI_PLATFORM_FAKE -+ -+/** -+ * kbase_platform_fake_register - Entry point for fake platform registration -+ * -+ * This function is called early on in the initialization during execution of -+ * kbase_driver_init. -+ * -+ * Return: 0 to indicate success, non-zero for failure. -+ */ -+int kbase_platform_fake_register(void); -+ -+/** -+ * kbase_platform_fake_unregister - Entry point for fake platform unregistration -+ * -+ * This function is called in the termination during execution of -+ * kbase_driver_exit. -+ */ -+void kbase_platform_fake_unregister(void); -+ -+#endif /* CONFIG_MALI_PLATFORM_FAKE */ -diff --git a/drivers/gpu/arm/midgard/platform/vexpress/Kbuild b/drivers/gpu/arm/midgard/platform/vexpress/Kbuild -new file mode 100644 -index 0000000..1caa293 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress/Kbuild -@@ -0,0 +1,18 @@ -+# -+# (C) COPYRIGHT 2012-2013, 2016 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+mali_kbase-y += \ -+ $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_vexpress.o \ -+ $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_cpu_vexpress.o -diff --git a/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_config_platform.h b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_config_platform.h -new file mode 100644 -index 0000000..02835f1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_config_platform.h -@@ -0,0 +1,75 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include "mali_kbase_cpu_vexpress.h" -+ -+/** -+ * Maximum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MAX kbase_get_platform_max_freq() -+/** -+ * Minimum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MIN kbase_get_platform_min_freq() -+ -+/** -+ * CPU_SPEED_FUNC - A pointer to a function that calculates the CPU clock -+ * -+ * CPU clock speed of the platform is in MHz - see kbase_cpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_cpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define CPU_SPEED_FUNC (&kbase_get_vexpress_cpu_clock_speed) -+ -+/** -+ * GPU_SPEED_FUNC - A pointer to a function that calculates the GPU clock -+ * -+ * GPU clock speed of the platform in MHz - see kbase_gpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_gpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define GPU_SPEED_FUNC (NULL) -+ -+/** -+ * Power management configuration -+ * -+ * Attached value: pointer to @ref kbase_pm_callback_conf -+ * Default value: See @ref kbase_pm_callback_conf -+ */ -+#define POWER_MANAGEMENT_CALLBACKS (&pm_callbacks) -+ -+/** -+ * Platform specific configuration functions -+ * -+ * Attached value: pointer to @ref kbase_platform_funcs_conf -+ * Default value: See @ref kbase_platform_funcs_conf -+ */ -+#define PLATFORM_FUNCS (NULL) -+ -+extern struct kbase_pm_callback_conf pm_callbacks; -diff --git a/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_config_vexpress.c b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_config_vexpress.c -new file mode 100644 -index 0000000..15ce2bc ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_config_vexpress.c -@@ -0,0 +1,85 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include "mali_kbase_cpu_vexpress.h" -+#include "mali_kbase_config_platform.h" -+ -+#define HARD_RESET_AT_POWER_OFF 0 -+ -+#ifndef CONFIG_OF -+static struct kbase_io_resources io_resources = { -+ .job_irq_number = 68, -+ .mmu_irq_number = 69, -+ .gpu_irq_number = 70, -+ .io_memory_region = { -+ .start = 0xFC010000, -+ .end = 0xFC010000 + (4096 * 4) - 1 -+ } -+}; -+#endif /* CONFIG_OF */ -+ -+static int pm_callback_power_on(struct kbase_device *kbdev) -+{ -+ /* Nothing is needed on VExpress, but we may have destroyed GPU state (if the below HARD_RESET code is active) */ -+ return 1; -+} -+ -+static void pm_callback_power_off(struct kbase_device *kbdev) -+{ -+#if HARD_RESET_AT_POWER_OFF -+ /* Cause a GPU hard reset to test whether we have actually idled the GPU -+ * and that we properly reconfigure the GPU on power up. -+ * Usually this would be dangerous, but if the GPU is working correctly it should -+ * be completely safe as the GPU should not be active at this point. -+ * However this is disabled normally because it will most likely interfere with -+ * bus logging etc. -+ */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0); -+ kbase_os_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_HARD_RESET); -+#endif -+} -+ -+struct kbase_pm_callback_conf pm_callbacks = { -+ .power_on_callback = pm_callback_power_on, -+ .power_off_callback = pm_callback_power_off, -+ .power_suspend_callback = NULL, -+ .power_resume_callback = NULL -+}; -+ -+static struct kbase_platform_config versatile_platform_config = { -+#ifndef CONFIG_OF -+ .io_resources = &io_resources -+#endif -+}; -+ -+struct kbase_platform_config *kbase_get_platform_config(void) -+{ -+ return &versatile_platform_config; -+} -+ -+ -+int kbase_platform_early_init(void) -+{ -+ /* Nothing needed at this stage */ -+ return 0; -+} -diff --git a/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c -new file mode 100644 -index 0000000..4665f98 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.c -@@ -0,0 +1,279 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include "mali_kbase_cpu_vexpress.h" -+ -+#define HZ_IN_MHZ (1000000) -+ -+#define CORETILE_EXPRESS_A9X4_SCC_START (0x100E2000) -+#define MOTHERBOARD_SYS_CFG_START (0x10000000) -+#define SYS_CFGDATA_OFFSET (0x000000A0) -+#define SYS_CFGCTRL_OFFSET (0x000000A4) -+#define SYS_CFGSTAT_OFFSET (0x000000A8) -+ -+#define SYS_CFGCTRL_START_BIT_VALUE (1 << 31) -+#define READ_REG_BIT_VALUE (0 << 30) -+#define DCC_DEFAULT_BIT_VALUE (0 << 26) -+#define SYS_CFG_OSC_FUNC_BIT_VALUE (1 << 20) -+#define SITE_DEFAULT_BIT_VALUE (1 << 16) -+#define BOARD_STACK_POS_DEFAULT_BIT_VALUE (0 << 12) -+#define DEVICE_DEFAULT_BIT_VALUE (2 << 0) -+#define SYS_CFG_COMPLETE_BIT_VALUE (1 << 0) -+#define SYS_CFG_ERROR_BIT_VALUE (1 << 1) -+ -+#define FEED_REG_BIT_MASK (0x0F) -+#define FCLK_PA_DIVIDE_BIT_SHIFT (0x03) -+#define FCLK_PB_DIVIDE_BIT_SHIFT (0x07) -+#define FCLK_PC_DIVIDE_BIT_SHIFT (0x0B) -+#define AXICLK_PA_DIVIDE_BIT_SHIFT (0x0F) -+#define AXICLK_PB_DIVIDE_BIT_SHIFT (0x13) -+ -+/* the following three values used for reading -+ * HBI value of the LogicTile daughterboard */ -+#define VE_MOTHERBOARD_PERIPHERALS_SMB_CS7 (0x10000000) -+#define VE_SYS_PROC_ID1_OFFSET (0x00000088) -+#define VE_LOGIC_TILE_HBI_MASK (0x00000FFF) -+ -+#define IS_SINGLE_BIT_SET(val, pos) (val&(1<> -+ FCLK_PA_DIVIDE_BIT_SHIFT); -+ /* CFGRW0[10:7] */ -+ pb_divide = ((reg_val & (FEED_REG_BIT_MASK << -+ FCLK_PB_DIVIDE_BIT_SHIFT)) >> -+ FCLK_PB_DIVIDE_BIT_SHIFT); -+ *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide + 1); -+ } else if (IS_SINGLE_BIT_SET(reg_val, 1)) { -+ /* CFGRW0[1] - CLKOC */ -+ /* CFGRW0[6:3] */ -+ pa_divide = ((reg_val & (FEED_REG_BIT_MASK << -+ FCLK_PA_DIVIDE_BIT_SHIFT)) >> -+ FCLK_PA_DIVIDE_BIT_SHIFT); -+ /* CFGRW0[14:11] */ -+ pc_divide = ((reg_val & (FEED_REG_BIT_MASK << -+ FCLK_PC_DIVIDE_BIT_SHIFT)) >> -+ FCLK_PC_DIVIDE_BIT_SHIFT); -+ *cpu_clock = osc2_value * (pa_divide + 1) / (pc_divide + 1); -+ } else if (IS_SINGLE_BIT_SET(reg_val, 2)) { -+ /* CFGRW0[2] - FACLK */ -+ /* CFGRW0[18:15] */ -+ pa_divide = ((reg_val & (FEED_REG_BIT_MASK << -+ AXICLK_PA_DIVIDE_BIT_SHIFT)) >> -+ AXICLK_PA_DIVIDE_BIT_SHIFT); -+ /* CFGRW0[22:19] */ -+ pb_divide = ((reg_val & (FEED_REG_BIT_MASK << -+ AXICLK_PB_DIVIDE_BIT_SHIFT)) >> -+ AXICLK_PB_DIVIDE_BIT_SHIFT); -+ *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide + 1); -+ } else { -+ err = -EIO; -+ } -+ -+set_reg_error: -+ongoing_request: -+ raw_spin_unlock(&syscfg_lock); -+ *cpu_clock /= HZ_IN_MHZ; -+ -+ if (!err) -+ cpu_clock_speed = *cpu_clock; -+ -+ iounmap(scc_reg); -+ -+scc_reg_map_failed: -+ iounmap(syscfg_reg); -+ -+syscfg_reg_map_failed: -+ -+ return err; -+} -+ -+/** -+ * kbase_get_platform_logic_tile_type - determines which LogicTile type -+ * is used by Versatile Express -+ * -+ * When platform_config build parameter is specified as vexpress, i.e., -+ * platform_config=vexpress, GPU frequency may vary dependent on the -+ * particular platform. The GPU frequency depends on the LogicTile type. -+ * -+ * This function determines which LogicTile type is used by the platform by -+ * reading the HBI value of the daughterboard which holds the LogicTile: -+ * -+ * 0x217 HBI0217 Virtex-6 -+ * 0x192 HBI0192 Virtex-5 -+ * 0x247 HBI0247 Virtex-7 -+ * -+ * Return: HBI value of the logic tile daughterboard, zero if not accessible -+ */ -+static u32 kbase_get_platform_logic_tile_type(void) -+{ -+ void __iomem *syscfg_reg = NULL; -+ u32 sys_procid1 = 0; -+ -+ syscfg_reg = ioremap(VE_MOTHERBOARD_PERIPHERALS_SMB_CS7 + VE_SYS_PROC_ID1_OFFSET, 4); -+ if (NULL != syscfg_reg) { -+ sys_procid1 = readl(syscfg_reg); -+ iounmap(syscfg_reg); -+ } -+ -+ return sys_procid1 & VE_LOGIC_TILE_HBI_MASK; -+} -+ -+u32 kbase_get_platform_min_freq(void) -+{ -+ u32 ve_logic_tile = kbase_get_platform_logic_tile_type(); -+ -+ switch (ve_logic_tile) { -+ case 0x217: -+ /* Virtex 6, HBI0217 */ -+ return VE_VIRTEX6_GPU_FREQ_MIN; -+ case 0x247: -+ /* Virtex 7, HBI0247 */ -+ return VE_VIRTEX7_GPU_FREQ_MIN; -+ default: -+ /* all other logic tiles, i.e., Virtex 5 HBI0192 -+ * or unsuccessful reading from the platform - -+ * fall back to some default value */ -+ return VE_DEFAULT_GPU_FREQ_MIN; -+ } -+} -+ -+u32 kbase_get_platform_max_freq(void) -+{ -+ u32 ve_logic_tile = kbase_get_platform_logic_tile_type(); -+ -+ switch (ve_logic_tile) { -+ case 0x217: -+ /* Virtex 6, HBI0217 */ -+ return VE_VIRTEX6_GPU_FREQ_MAX; -+ case 0x247: -+ /* Virtex 7, HBI0247 */ -+ return VE_VIRTEX7_GPU_FREQ_MAX; -+ default: -+ /* all other logic tiles, i.e., Virtex 5 HBI0192 -+ * or unsuccessful reading from the platform - -+ * fall back to some default value */ -+ return VE_DEFAULT_GPU_FREQ_MAX; -+ } -+} -diff --git a/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.h b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.h -new file mode 100644 -index 0000000..da86569 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress/mali_kbase_cpu_vexpress.h -@@ -0,0 +1,38 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2013, 2015-2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KBASE_CPU_VEXPRESS_H_ -+#define _KBASE_CPU_VEXPRESS_H_ -+ -+/** -+ * Versatile Express implementation of @ref kbase_cpu_clk_speed_func. -+ */ -+int kbase_get_vexpress_cpu_clock_speed(u32 *cpu_clock); -+ -+/** -+ * Get the minimum GPU frequency for the attached logic tile -+ */ -+u32 kbase_get_platform_min_freq(void); -+ -+/** -+ * Get the maximum GPU frequency for the attached logic tile -+ */ -+u32 kbase_get_platform_max_freq(void); -+ -+#endif /* _KBASE_CPU_VEXPRESS_H_ */ -diff --git a/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/Kbuild b/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/Kbuild -new file mode 100644 -index 0000000..7efe8fa ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/Kbuild -@@ -0,0 +1,16 @@ -+# -+# (C) COPYRIGHT 2013-2014, 2016 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+mali_kbase-y += $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_vexpress.o -diff --git a/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/mali_kbase_config_platform.h b/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/mali_kbase_config_platform.h -new file mode 100644 -index 0000000..0efbf39 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/mali_kbase_config_platform.h -@@ -0,0 +1,73 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/** -+ * Maximum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MAX 5000 -+/** -+ * Minimum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MIN 5000 -+ -+/** -+ * CPU_SPEED_FUNC - A pointer to a function that calculates the CPU clock -+ * -+ * CPU clock speed of the platform is in MHz - see kbase_cpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_cpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define CPU_SPEED_FUNC (&kbase_cpuprops_get_default_clock_speed) -+ -+/** -+ * GPU_SPEED_FUNC - A pointer to a function that calculates the GPU clock -+ * -+ * GPU clock speed of the platform in MHz - see kbase_gpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_gpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define GPU_SPEED_FUNC (NULL) -+ -+/** -+ * Power management configuration -+ * -+ * Attached value: pointer to @ref kbase_pm_callback_conf -+ * Default value: See @ref kbase_pm_callback_conf -+ */ -+#define POWER_MANAGEMENT_CALLBACKS (&pm_callbacks) -+ -+/** -+ * Platform specific configuration functions -+ * -+ * Attached value: pointer to @ref kbase_platform_funcs_conf -+ * Default value: See @ref kbase_platform_funcs_conf -+ */ -+#define PLATFORM_FUNCS (NULL) -+ -+extern struct kbase_pm_callback_conf pm_callbacks; -diff --git a/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/mali_kbase_config_vexpress.c b/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/mali_kbase_config_vexpress.c -new file mode 100644 -index 0000000..3ff0930 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress_1xv7_a57/mali_kbase_config_vexpress.c -@@ -0,0 +1,79 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+#include -+ -+#define HARD_RESET_AT_POWER_OFF 0 -+ -+#ifndef CONFIG_OF -+static struct kbase_io_resources io_resources = { -+ .job_irq_number = 68, -+ .mmu_irq_number = 69, -+ .gpu_irq_number = 70, -+ .io_memory_region = { -+ .start = 0x2f010000, -+ .end = 0x2f010000 + (4096 * 4) - 1} -+}; -+#endif -+ -+static int pm_callback_power_on(struct kbase_device *kbdev) -+{ -+ /* Nothing is needed on VExpress, but we may have destroyed GPU state (if the below HARD_RESET code is active) */ -+ return 1; -+} -+ -+static void pm_callback_power_off(struct kbase_device *kbdev) -+{ -+#if HARD_RESET_AT_POWER_OFF -+ /* Cause a GPU hard reset to test whether we have actually idled the GPU -+ * and that we properly reconfigure the GPU on power up. -+ * Usually this would be dangerous, but if the GPU is working correctly it should -+ * be completely safe as the GPU should not be active at this point. -+ * However this is disabled normally because it will most likely interfere with -+ * bus logging etc. -+ */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0); -+ kbase_os_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_HARD_RESET); -+#endif -+} -+ -+struct kbase_pm_callback_conf pm_callbacks = { -+ .power_on_callback = pm_callback_power_on, -+ .power_off_callback = pm_callback_power_off, -+ .power_suspend_callback = NULL, -+ .power_resume_callback = NULL -+}; -+ -+static struct kbase_platform_config versatile_platform_config = { -+#ifndef CONFIG_OF -+ .io_resources = &io_resources -+#endif -+}; -+ -+struct kbase_platform_config *kbase_get_platform_config(void) -+{ -+ return &versatile_platform_config; -+} -+ -+int kbase_platform_early_init(void) -+{ -+ /* Nothing needed at this stage */ -+ return 0; -+} -diff --git a/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/Kbuild b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/Kbuild -new file mode 100644 -index 0000000..1caa293 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/Kbuild -@@ -0,0 +1,18 @@ -+# -+# (C) COPYRIGHT 2012-2013, 2016 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+mali_kbase-y += \ -+ $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_config_vexpress.o \ -+ $(MALI_PLATFORM_THIRDPARTY_DIR)/mali_kbase_cpu_vexpress.o -diff --git a/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_config_platform.h b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_config_platform.h -new file mode 100644 -index 0000000..dbdf21e ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_config_platform.h -@@ -0,0 +1,75 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include "mali_kbase_cpu_vexpress.h" -+ -+/** -+ * Maximum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MAX 10000 -+/** -+ * Minimum frequency GPU will be clocked at. Given in kHz. -+ * This must be specified as there is no default value. -+ * -+ * Attached value: number in kHz -+ * Default value: NA -+ */ -+#define GPU_FREQ_KHZ_MIN 10000 -+ -+/** -+ * CPU_SPEED_FUNC - A pointer to a function that calculates the CPU clock -+ * -+ * CPU clock speed of the platform is in MHz - see kbase_cpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_cpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define CPU_SPEED_FUNC (&kbase_get_vexpress_cpu_clock_speed) -+ -+/** -+ * GPU_SPEED_FUNC - A pointer to a function that calculates the GPU clock -+ * -+ * GPU clock speed of the platform in MHz - see kbase_gpu_clk_speed_func -+ * for the function prototype. -+ * -+ * Attached value: A kbase_gpu_clk_speed_func. -+ * Default Value: NA -+ */ -+#define GPU_SPEED_FUNC (NULL) -+ -+/** -+ * Power management configuration -+ * -+ * Attached value: pointer to @ref kbase_pm_callback_conf -+ * Default value: See @ref kbase_pm_callback_conf -+ */ -+#define POWER_MANAGEMENT_CALLBACKS (&pm_callbacks) -+ -+/** -+ * Platform specific configuration functions -+ * -+ * Attached value: pointer to @ref kbase_platform_funcs_conf -+ * Default value: See @ref kbase_platform_funcs_conf -+ */ -+#define PLATFORM_FUNCS (NULL) -+ -+extern struct kbase_pm_callback_conf pm_callbacks; -diff --git a/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_config_vexpress.c b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_config_vexpress.c -new file mode 100644 -index 0000000..76ffe4a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_config_vexpress.c -@@ -0,0 +1,83 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2014 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+#include -+#include -+#include "mali_kbase_cpu_vexpress.h" -+ -+#define HARD_RESET_AT_POWER_OFF 0 -+ -+#ifndef CONFIG_OF -+static struct kbase_io_resources io_resources = { -+ .job_irq_number = 75, -+ .mmu_irq_number = 76, -+ .gpu_irq_number = 77, -+ .io_memory_region = { -+ .start = 0x2F000000, -+ .end = 0x2F000000 + (4096 * 4) - 1} -+}; -+#endif -+ -+static int pm_callback_power_on(struct kbase_device *kbdev) -+{ -+ /* Nothing is needed on VExpress, but we may have destroyed GPU state (if the below HARD_RESET code is active) */ -+ return 1; -+} -+ -+static void pm_callback_power_off(struct kbase_device *kbdev) -+{ -+#if HARD_RESET_AT_POWER_OFF -+ /* Cause a GPU hard reset to test whether we have actually idled the GPU -+ * and that we properly reconfigure the GPU on power up. -+ * Usually this would be dangerous, but if the GPU is working correctly it should -+ * be completely safe as the GPU should not be active at this point. -+ * However this is disabled normally because it will most likely interfere with -+ * bus logging etc. -+ */ -+ KBASE_TRACE_ADD(kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0); -+ kbase_os_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_HARD_RESET); -+#endif -+} -+ -+struct kbase_pm_callback_conf pm_callbacks = { -+ .power_on_callback = pm_callback_power_on, -+ .power_off_callback = pm_callback_power_off, -+ .power_suspend_callback = NULL, -+ .power_resume_callback = NULL -+}; -+ -+static struct kbase_platform_config versatile_platform_config = { -+#ifndef CONFIG_OF -+ .io_resources = &io_resources -+#endif -+}; -+ -+struct kbase_platform_config *kbase_get_platform_config(void) -+{ -+ return &versatile_platform_config; -+} -+ -+int kbase_platform_early_init(void) -+{ -+ /* Nothing needed at this stage */ -+ return 0; -+} -+ -diff --git a/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_cpu_vexpress.c b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_cpu_vexpress.c -new file mode 100644 -index 0000000..816dff4 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/platform/vexpress_6xvirtex7_10mhz/mali_kbase_cpu_vexpress.c -@@ -0,0 +1,71 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#include -+#include -+#include "mali_kbase_cpu_vexpress.h" -+ -+#define HZ_IN_MHZ (1000000) -+ -+#define CORETILE_EXPRESS_A9X4_SCC_START (0x100E2000) -+#define MOTHERBOARD_SYS_CFG_START (0x10000000) -+#define SYS_CFGDATA_OFFSET (0x000000A0) -+#define SYS_CFGCTRL_OFFSET (0x000000A4) -+#define SYS_CFGSTAT_OFFSET (0x000000A8) -+ -+#define SYS_CFGCTRL_START_BIT_VALUE (1 << 31) -+#define READ_REG_BIT_VALUE (0 << 30) -+#define DCC_DEFAULT_BIT_VALUE (0 << 26) -+#define SYS_CFG_OSC_FUNC_BIT_VALUE (1 << 20) -+#define SITE_DEFAULT_BIT_VALUE (1 << 16) -+#define BOARD_STACK_POS_DEFAULT_BIT_VALUE (0 << 12) -+#define DEVICE_DEFAULT_BIT_VALUE (2 << 0) -+#define SYS_CFG_COMPLETE_BIT_VALUE (1 << 0) -+#define SYS_CFG_ERROR_BIT_VALUE (1 << 1) -+ -+#define FEED_REG_BIT_MASK (0x0F) -+#define FCLK_PA_DIVIDE_BIT_SHIFT (0x03) -+#define FCLK_PB_DIVIDE_BIT_SHIFT (0x07) -+#define FCLK_PC_DIVIDE_BIT_SHIFT (0x0B) -+#define AXICLK_PA_DIVIDE_BIT_SHIFT (0x0F) -+#define AXICLK_PB_DIVIDE_BIT_SHIFT (0x13) -+ -+#define IS_SINGLE_BIT_SET(val, pos) (val&(1< -+ -+/** -+ * @addtogroup uk_api User-Kernel Interface API -+ * @{ -+ */ -+ -+/** -+ * @addtogroup uk_api_kernel UKK (Kernel side) -+ * @{ -+ */ -+ -+/** -+ * Internal OS specific data structure associated with each UKK session. Part -+ * of a ukk_session object. -+ */ -+typedef struct ukkp_session { -+ int dummy; /**< No internal OS specific data at this time */ -+} ukkp_session; -+ -+/** @} end group uk_api_kernel */ -+ -+/** @} end group uk_api */ -+ -+#endif /* _UKK_OS_H__ */ -diff --git a/drivers/gpu/arm/midgard/protected_mode_switcher.h b/drivers/gpu/arm/midgard/protected_mode_switcher.h -new file mode 100644 -index 0000000..5dc2f3b ---- /dev/null -+++ b/drivers/gpu/arm/midgard/protected_mode_switcher.h -@@ -0,0 +1,64 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _PROTECTED_MODE_SWITCH_H_ -+#define _PROTECTED_MODE_SWITCH_H_ -+ -+struct protected_mode_device; -+ -+/** -+ * struct protected_mode_ops - Callbacks for protected mode switch operations -+ * -+ * @protected_mode_enable: Callback to enable protected mode for device -+ * @protected_mode_disable: Callback to disable protected mode for device -+ */ -+struct protected_mode_ops { -+ /** -+ * protected_mode_enable() - Enable protected mode on device -+ * @dev: The struct device -+ * -+ * Return: 0 on success, non-zero on error -+ */ -+ int (*protected_mode_enable)( -+ struct protected_mode_device *protected_dev); -+ -+ /** -+ * protected_mode_disable() - Disable protected mode on device, and -+ * reset device -+ * @dev: The struct device -+ * -+ * Return: 0 on success, non-zero on error -+ */ -+ int (*protected_mode_disable)( -+ struct protected_mode_device *protected_dev); -+}; -+ -+/** -+ * struct protected_mode_device - Device structure for protected mode devices -+ * -+ * @ops - Callbacks associated with this device -+ * @data - Pointer to device private data -+ * -+ * This structure should be registered with the platform device using -+ * platform_set_drvdata(). -+ */ -+struct protected_mode_device { -+ struct protected_mode_ops ops; -+ void *data; -+}; -+ -+#endif /* _PROTECTED_MODE_SWITCH_H_ */ -diff --git a/drivers/gpu/arm/midgard/sconscript b/drivers/gpu/arm/midgard/sconscript -new file mode 100644 -index 0000000..ff23d7a ---- /dev/null -+++ b/drivers/gpu/arm/midgard/sconscript -@@ -0,0 +1,92 @@ -+# -+# (C) COPYRIGHT 2010-2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+import sys -+Import('env') -+ -+SConscript( 'tests/sconscript' ) -+ -+mock_test = 0 -+ -+# Fake platform is a transient solution for GPL drivers running in kernel that does not provide configuration via platform data. -+# For such kernels fake_platform_device should be set to 1. For kernels providing platform data fake_platform_device should be set to 0. -+if env['platform_config']=='devicetree' or env['platform_config']=='juno_soc': -+ fake_platform_device = 0 -+else: -+ fake_platform_device = 1 -+ -+# Source files required for kbase. -+kbase_src = [ -+ Glob('*.c'), -+ Glob('backend/*/*.c'), -+ Glob('internal/*/*.c'), -+ Glob('ipa/*.c') -+] -+ -+if env['platform_config']=='juno_soc': -+ kbase_src += [Glob('platform/devicetree/*.c')] -+else: -+ kbase_src += [Glob('platform/%s/*.c' % env['platform_config'])] -+ -+if Glob('#kernel/drivers/gpu/arm/midgard/tests/internal/src/mock') and env['unit'] == '1': -+ kbase_src += [Glob('#kernel/drivers/gpu/arm/midgard/tests/internal/src/mock/*.c')] -+ mock_test = 1 -+ -+# we need platform config for GPL version using fake platform -+if fake_platform_device==1: -+ # Check if we are compiling for PBX -+ if env.KernelConfigEnabled("CONFIG_MACH_REALVIEW_PBX") and \ -+ env["platform_config"] in {"vexpress", "vexpress_6xvirtex7_10mhz"}: -+ sys.stderr.write("WARNING: Building for a PBX kernel but with platform_config=vexpress*\n") -+ # if the file platform config file is in the tpip directory then use that, otherwise use the default config directory -+ if Glob('#kernel/drivers/gpu/arm/midgard/config/tpip/*%s.c' % (env['platform_config'])): -+ kbase_src += Glob('#kernel/drivers/gpu/arm/midgard/config/tpip/*%s.c' % (env['platform_config'])) -+ else: -+ kbase_src += Glob('#kernel/drivers/gpu/arm/midgard/config/*%s.c' % (env['platform_config'])) -+ -+make_args = env.kernel_get_config_defines(ret_list = True, -+ fake = fake_platform_device) + [ -+ 'PLATFORM=%s' % env['platform'], -+ 'MALI_ERROR_INJECT_ON=%s' % env['error_inject'], -+ 'MALI_KERNEL_TEST_API=%s' % env['debug'], -+ 'MALI_UNIT_TEST=%s' % env['unit'], -+ 'MALI_RELEASE_NAME=%s' % env['mali_release_name'], -+ 'MALI_MOCK_TEST=%s' % mock_test, -+ 'MALI_CUSTOMER_RELEASE=%s' % env['release'], -+ 'MALI_INSTRUMENTATION_LEVEL=%s' % env['instr'], -+ 'MALI_COVERAGE=%s' % env['coverage'], -+ 'MALI_BUS_LOG=%s' % env['buslog'] -+] -+ -+kbase = env.BuildKernelModule('$STATIC_LIB_PATH/mali_kbase.ko', kbase_src, -+ make_args = make_args) -+ -+# Add a dependency on kds.ko. -+# Only necessary when KDS is not built into the kernel. -+# -+if env['os'] != 'android': -+ if not env.KernelConfigEnabled("CONFIG_KDS"): -+ env.Depends(kbase, '$STATIC_LIB_PATH/kds.ko') -+ -+# need Module.symvers from ump.ko build -+if int(env['ump']) == 1: -+ env.Depends(kbase, '$STATIC_LIB_PATH/ump.ko') -+ -+if 'smc_protected_mode_switcher' in env: -+ env.Depends('$STATIC_LIB_PATH/mali_kbase.ko', '$STATIC_LIB_PATH/smc_protected_mode_switcher.ko') -+ -+env.KernelObjTarget('kbase', kbase) -+ -+env.AppendUnique(BASE=['cutils_linked_list']) -diff --git a/drivers/gpu/arm/midgard/tests/Kbuild b/drivers/gpu/arm/midgard/tests/Kbuild -new file mode 100644 -index 0000000..b4bed04 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/Kbuild -@@ -0,0 +1,17 @@ -+# -+# (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+obj-$(CONFIG_MALI_KUTF) += kutf/ -+obj-$(CONFIG_MALI_IRQ_LATENCY) += mali_kutf_irq_test/ -diff --git a/drivers/gpu/arm/midgard/tests/Kconfig b/drivers/gpu/arm/midgard/tests/Kconfig -new file mode 100644 -index 0000000..da0515c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/Kconfig -@@ -0,0 +1,17 @@ -+# -+# (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+source "drivers/gpu/arm/midgard/tests/kutf/Kconfig" -+source "drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Kconfig" -diff --git a/drivers/gpu/arm/midgard/tests/include/kutf/kutf_helpers.h b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_helpers.h -new file mode 100644 -index 0000000..3f1dfc2 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_helpers.h -@@ -0,0 +1,216 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KERNEL_UTF_HELPERS_H_ -+#define _KERNEL_UTF_HELPERS_H_ -+ -+/* kutf_helpers.h -+ * Test helper functions for the kernel UTF test infrastructure. -+ * -+ * This collection of helper functions are provided as 'stock' implementation -+ * helpers for certain features of kutf. Tests can implement common/boilerplate -+ * functionality using these, whilst still providing them the option of -+ * implementing completely custom functions themselves to use those kutf -+ * features. -+ */ -+ -+#include -+#include -+#include -+ -+/** -+ * enum kutf_helper_textbuf_flag - flags for textbufs -+ * @KUTF_HELPER_TEXTBUF_FLAG_DYING: Test is dying, textbuf should not allow -+ * writes, nor block on empty. -+ */ -+enum kutf_helper_textbuf_flag { -+ KUTF_HELPER_TEXTBUF_FLAG_DYING = (1u << 0), -+}; -+ -+/** -+ * struct kutf_helper_textbuf_line - Structure representing a line of text -+ * -+ * The string itself is stored immediately after this. -+ * -+ * @node: List node for the textbuf's textbuf_list -+ * @str_size: Length of the string buffer, including the \0 terminator -+ * @str: 'Flexible array' for the string representing the line -+ */ -+struct kutf_helper_textbuf_line { -+ struct list_head node; -+ int str_size; -+ char str[]; -+}; -+ -+/** -+ * struct kutf_helper_textbuf - Structure to representing sequential lines of -+ * text -+ * @lock: mutex to hold whilst accessing the structure -+ * @nr_user_clients: Number of userspace clients connected via an open() -+ * call -+ * @mempool: mempool for allocating lines -+ * @scratchpad: scratch area for receiving text of size max_line_size -+ * @used_bytes: number of valid bytes in the scratchpad -+ * @prev_pos: Previous position userspace has accessed -+ * @prev_line_pos: Previous start of line position userspace has accessed -+ * @textbuf_list: List head to store all the lines of text -+ * @max_line_size: Maximum size in memory allowed for a line of text -+ * @max_nr_lines: Maximum number of lines permitted in this textbuf -+ * @nr_lines: Number of entries in textbuf_list -+ * @flags: Flags indicating state of the textbuf, using values -+ * from enum kutf_helper_textbuf_flag -+ * @user_opened_wq: Waitq for when there's at least one userspace client -+ * connected to the textbuf via an open() call -+ * @not_full_wq: Waitq for when the textbuf can be enqueued into/can -+ * consume data from userspace -+ * @not_empty_wq: Waitq for when the textbuf can be dequeued from/can -+ * produce data for userspace -+ */ -+ -+struct kutf_helper_textbuf { -+ struct mutex lock; -+ int nr_user_clients; -+ struct kutf_mempool *mempool; -+ char *scratchpad; -+ int used_bytes; -+ loff_t prev_pos; -+ loff_t prev_line_pos; -+ struct list_head textbuf_list; -+ int max_line_size; -+ int max_nr_lines; -+ int nr_lines; -+ unsigned long flags; -+ wait_queue_head_t user_opened_wq; -+ wait_queue_head_t not_full_wq; -+ wait_queue_head_t not_empty_wq; -+ -+}; -+ -+/* stock callbacks for userspace to read from/write to the 'data' file as a -+ * textbuf */ -+extern struct kutf_userdata_ops kutf_helper_textbuf_userdata_ops; -+ -+/** -+ * kutf_helper_textbuf_init() - init a textbuf for use as a 'data' file -+ * consumer/producer -+ * @textbuf: textbuf to initialize -+ * @mempool: mempool to allocate from -+ * @max_line_size: maximum line size expected to/from userspace -+ * @max_nr_lines: maximum number of lines to expect to/from userspace -+ * -+ * Initialize a textbuf so that it can consume writes made to the 'data' file, -+ * and produce reads for userspace on the 'data' file. Tests may then read the -+ * lines written by userspace, or fill the buffer so it may be read back by -+ * userspace. -+ * -+ * The caller should write the @textbuf pointer into the kutf_context's -+ * userdata_producer_priv or userdata_consumer_priv member during fixture -+ * creation. -+ * -+ * Usually a test will have separate textbufs for userspace to write to and -+ * read from. Using the same one for both will echo back to the user what they -+ * are writing. -+ * -+ * Lines are understood as being separated by the '\n' character, but no '\n' -+ * characters will be observed by the test -+ * -+ * @max_line_size puts an upper bound on the size of lines in a textbuf, -+ * including the \0 terminator. Lines exceeding this will be truncated, -+ * effectively ignoring incoming data until the next '\n' -+ * -+ * Combining this with @max_nr_lines puts an upper bound on the size of the -+ * file read in -+ * -+ * Return: 0 on success, or negative value on error. -+ */ -+int kutf_helper_textbuf_init(struct kutf_helper_textbuf *textbuf, -+ struct kutf_mempool *mempool, int max_line_size, -+ int max_nr_lines); -+ -+/** -+ * kutf_helper_textbuf_wait_for_user() - wait for userspace to open the 'data' -+ * file -+ * @textbuf: textbuf to wait on -+ * -+ * This can be used to synchronize with userspace so that subsequent calls to -+ * kutf_helper_textbuf_dequeue() and kutf_helper_textbuf_enqueue() should -+ * succeed. -+ * -+ * Waiting is done on a timeout. -+ * -+ * There is of course no guarantee that userspace will keep the file open after -+ * this, but any error in the dequeue/enqueue functions afterwards can be -+ * treated as such rather than "we're still waiting for userspace to begin" -+ * -+ * Return: 0 if waited successfully, -ETIMEDOUT if we exceeded the -+ * timeout, or some other negative value if there was an -+ * error during waiting. -+ */ -+ -+int kutf_helper_textbuf_wait_for_user(struct kutf_helper_textbuf *textbuf); -+ -+ -+/** -+ * kutf_helper_textbuf_dequeue() - dequeue a line from a textbuf -+ * @textbuf: textbuf dequeue a line as a string from -+ * @str_size: pointer to storage to receive the size of the string, -+ * which includes the '\0' terminator, or NULL if not -+ * required -+ * -+ * Dequeue (remove) a line from the start of the textbuf as a string, and -+ * return it. -+ * -+ * If no lines are available, then this will block until a line has been -+ * submitted. If a userspace client is not connected and there are no remaining -+ * lines, then this function returns NULL instead. -+ * -+ * The memory for the string comes from the kutf_mempool given during -+ * initialization of the textbuf, and shares the same lifetime as it. -+ * -+ * Return: pointer to the next line of the textbuf. NULL indicated -+ * all userspace clients disconnected. An error value to be -+ * checked with IS_ERR() family of functions if a signal or -+ * some other error occurred -+ */ -+char *kutf_helper_textbuf_dequeue(struct kutf_helper_textbuf *textbuf, -+ int *str_size); -+ -+/** -+ * kutf_helper_textbuf_enqueue() - enqueue a line to a textbuf -+ * @textbuf: textbuf to enqueue a line as a string to -+ * @enqueue_str: pointer to the string to enqueue to the textbuf -+ * @buf_max_size: maximum size of the buffer holding @enqueue_str -+ * -+ * Enqueue (add) a line to the end of a textbuf as a string. -+ * -+ * The caller should avoid placing '\n' characters in their strings, as these -+ * will not be split into multiple lines. -+ * -+ * A copy of the string will be made into the textbuf, so @enqueue_str can be -+ * freed immediately after if.the caller wishes to do so. -+ * -+ * If the maximum amount of lines has been reached, then this will block until -+ * a line has been removed to make space. If a userspace client is not -+ * connected and there is no space available, then this function returns -+ * -EBUSY. -+ * -+ * Return: 0 on success, or negative value on error -+ */ -+int kutf_helper_textbuf_enqueue(struct kutf_helper_textbuf *textbuf, -+ char *enqueue_str, int buf_max_size); -+ -+#endif /* _KERNEL_UTF_HELPERS_H_ */ -diff --git a/drivers/gpu/arm/midgard/tests/include/kutf/kutf_helpers_user.h b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_helpers_user.h -new file mode 100644 -index 0000000..759bf71 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_helpers_user.h -@@ -0,0 +1,179 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KERNEL_UTF_HELPERS_USER_H_ -+#define _KERNEL_UTF_HELPERS_USER_H_ -+ -+/* kutf_helpers.h -+ * Test helper functions for the kernel UTF test infrastructure, whose -+ * implementation mirrors that of similar functions for kutf-userside -+ */ -+ -+#include -+#include -+ -+ -+#define KUTF_HELPER_MAX_VAL_NAME_LEN 255 -+ -+enum kutf_helper_valtype { -+ KUTF_HELPER_VALTYPE_INVALID, -+ KUTF_HELPER_VALTYPE_U64, -+ KUTF_HELPER_VALTYPE_STR, -+ -+ KUTF_HELPER_VALTYPE_COUNT /* Must be last */ -+}; -+ -+struct kutf_helper_named_val { -+ enum kutf_helper_valtype type; -+ char *val_name; -+ union { -+ u64 val_u64; -+ char *val_str; -+ } u; -+}; -+ -+/* Extra error values for certain helpers when we want to distinguish between -+ * Linux's own error values too. -+ * -+ * These can only be used on certain functions returning an int type that are -+ * documented as returning one of these potential values, they cannot be used -+ * from functions return a ptr type, since we can't decode it with PTR_ERR -+ * -+ * No negative values are used - Linux error codes should be used instead, and -+ * indicate a problem in accessing the data file itself (are generally -+ * unrecoverable) -+ * -+ * Positive values indicate correct access but invalid parsing (can be -+ * recovered from assuming data in the future is correct) */ -+enum kutf_helper_err { -+ /* No error - must be zero */ -+ KUTF_HELPER_ERR_NONE = 0, -+ /* Named value parsing encountered an invalid name */ -+ KUTF_HELPER_ERR_INVALID_NAME, -+ /* Named value parsing of string or u64 type encountered extra -+ * characters after the value (after the last digit for a u64 type or -+ * after the string end delimiter for string type) */ -+ KUTF_HELPER_ERR_CHARS_AFTER_VAL, -+ /* Named value parsing of string type couldn't find the string end -+ * delimiter. -+ * -+ * This cannot be encountered when the NAME="value" message exceeds the -+ * textbuf's maximum line length, because such messages are not checked -+ * for an end string delimiter */ -+ KUTF_HELPER_ERR_NO_END_DELIMITER, -+ /* Named value didn't parse as any of the known types */ -+ KUTF_HELPER_ERR_INVALID_VALUE, -+}; -+ -+ -+/* textbuf Send named NAME=value pair, u64 value -+ * -+ * NAME must match [A-Z0-9_]\+ and can be up to MAX_VAL_NAME_LEN characters long -+ * -+ * This is assuming the kernel-side test is using the 'textbuf' helpers -+ * -+ * Any failure will be logged on the suite's current test fixture -+ * -+ * Returns 0 on success, non-zero on failure -+ */ -+int kutf_helper_textbuf_send_named_u64(struct kutf_context *context, -+ struct kutf_helper_textbuf *textbuf, char *val_name, u64 val); -+ -+/* Get the maximum length of a string that can be represented as a particular -+ * NAME="value" pair without string-value truncation in the kernel's buffer -+ * -+ * Given val_name and the kernel buffer's size, this can be used to determine -+ * the maximum length of a string that can be sent as val_name="value" pair -+ * without having the string value truncated. Any string longer than this will -+ * be truncated at some point during communication to this size. -+ * -+ * The calculation is valid both for sending strings of val_str_len to kernel, -+ * and for receiving a string that was originally val_str_len from the kernel. -+ * -+ * It is assumed that valname is a valid name for -+ * kutf_test_helpers_textbuf_send_named_str(), and no checking will be made to -+ * ensure this. -+ * -+ * Returns the maximum string length that can be represented, or a negative -+ * value if the NAME="value" encoding itself wouldn't fit in kern_buf_sz -+ */ -+int kutf_helper_textbuf_max_str_len_for_kern(char *val_name, int kern_buf_sz); -+ -+/* textbuf Send named NAME="str" pair -+ * -+ * no escaping allowed in str. Any of the following characters will terminate -+ * the string: '"' '\\' '\n' -+ * -+ * NAME must match [A-Z0-9_]\+ and can be up to MAX_VAL_NAME_LEN characters long -+ * -+ * This is assuming the kernel-side test is using the 'textbuf' helpers -+ * -+ * Any failure will be logged on the suite's current test fixture -+ * -+ * Returns 0 on success, non-zero on failure */ -+int kutf_helper_textbuf_send_named_str(struct kutf_context *context, -+ struct kutf_helper_textbuf *textbuf, char *val_name, -+ char *val_str); -+ -+/* textbuf Receive named NAME=value pair -+ * -+ * This can receive u64 and string values - check named_val->type -+ * -+ * If you are not planning on dynamic handling of the named value's name and -+ * type, then kutf_test_helpers_textbuf_receive_check_val() is more useful as a -+ * convenience function. -+ * -+ * String members of named_val will come from memory allocated on the fixture's mempool -+ * -+ * Returns 0 on success. Negative value on failure to receive from the 'data' -+ * file, positive value indicates an enum kutf_helper_err value for correct -+ * reception of data but invalid parsing */ -+int kutf_helper_textbuf_receive_named_val(struct kutf_helper_named_val *named_val, -+ struct kutf_helper_textbuf *textbuf); -+ -+/* textbuf Receive and validate NAME=value pair -+ * -+ * As with kutf_test_helpers_textbuf_receive_named_val, but validate that the -+ * name and type are as expected, as a convenience for a common pattern found -+ * in tests. -+ * -+ * NOTE: this only returns an error value if there was actually a problem -+ * receiving data. -+ * -+ * NOTE: If the underlying data was received correctly, but: -+ * - isn't of the expected name -+ * - isn't the expected type -+ * - isn't correctly parsed for the type -+ * then the following happens: -+ * - failure result is recorded -+ * - named_val->type will be KUTF_HELPER_VALTYPE_INVALID -+ * - named_val->u will contain some default value that should be relatively -+ * harmless for the test, including being writable in the case of string -+ * values -+ * - return value will be 0 to indicate success -+ * -+ * The rationale behind this is that we'd prefer to continue the rest of the -+ * test with failures propagated, rather than hitting a timeout */ -+int kutf_helper_textbuf_receive_check_val(struct kutf_helper_named_val *named_val, -+ struct kutf_context *context, struct kutf_helper_textbuf *textbuf, -+ char *expect_val_name, enum kutf_helper_valtype expect_val_type); -+ -+/* Output a named value to kmsg */ -+void kutf_helper_output_named_val(struct kutf_helper_named_val *named_val); -+ -+ -+#endif /* _KERNEL_UTF_HELPERS_USER_H_ */ -diff --git a/drivers/gpu/arm/midgard/tests/include/kutf/kutf_mem.h b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_mem.h -new file mode 100644 -index 0000000..584c9dd ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_mem.h -@@ -0,0 +1,68 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KERNEL_UTF_MEM_H_ -+#define _KERNEL_UTF_MEM_H_ -+ -+/* kutf_mem.h -+ * Functions for management of memory pools in the kernel. -+ * -+ * This module implements a memory pool allocator, allowing a test -+ * implementation to allocate linked allocations which can then be freed by a -+ * single free which releases all of the resources held by the entire pool. -+ * -+ * Note that it is not possible to free single resources within the pool once -+ * allocated. -+ */ -+ -+#include -+#include -+ -+/** -+ * struct kutf_mempool - the memory pool context management structure -+ * @head: list head on which the allocations in this context are added to -+ * @lock: mutex for concurrent allocation from multiple threads -+ * -+ */ -+struct kutf_mempool { -+ struct list_head head; -+ struct mutex lock; -+}; -+ -+/** -+ * kutf_mempool_init() - Initialize a memory pool. -+ * @pool: Memory pool structure to initialize, provided by the user -+ * -+ * Return: zero on success -+ */ -+int kutf_mempool_init(struct kutf_mempool *pool); -+ -+/** -+ * kutf_mempool_alloc() - Allocate memory from a pool -+ * @pool: Memory pool to allocate from -+ * @size: Size of memory wanted in number of bytes -+ * -+ * Return: Pointer to memory on success, NULL on failure. -+ */ -+void *kutf_mempool_alloc(struct kutf_mempool *pool, size_t size); -+ -+/** -+ * kutf_mempool_destroy() - Destroy a memory pool, freeing all memory within it. -+ * @pool: The memory pool to free -+ */ -+void kutf_mempool_destroy(struct kutf_mempool *pool); -+#endif /* _KERNEL_UTF_MEM_H_ */ -diff --git a/drivers/gpu/arm/midgard/tests/include/kutf/kutf_resultset.h b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_resultset.h -new file mode 100644 -index 0000000..1cc85f1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_resultset.h -@@ -0,0 +1,121 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KERNEL_UTF_RESULTSET_H_ -+#define _KERNEL_UTF_RESULTSET_H_ -+ -+/* kutf_resultset.h -+ * Functions and structures for handling test results and result sets. -+ * -+ * This section of the kernel UTF contains structures and functions used for the -+ * management of Results and Result Sets. -+ */ -+ -+/** -+ * enum kutf_result_status - Status values for a single Test error. -+ * @KUTF_RESULT_BENCHMARK: Result is a meta-result containing benchmark -+ * results. -+ * @KUTF_RESULT_SKIP: The test was skipped. -+ * @KUTF_RESULT_UNKNOWN: The test has an unknown result. -+ * @KUTF_RESULT_PASS: The test result passed. -+ * @KUTF_RESULT_DEBUG: The test result passed, but raised a debug -+ * message. -+ * @KUTF_RESULT_INFO: The test result passed, but raised -+ * an informative message. -+ * @KUTF_RESULT_WARN: The test result passed, but raised a warning -+ * message. -+ * @KUTF_RESULT_FAIL: The test result failed with a non-fatal error. -+ * @KUTF_RESULT_FATAL: The test result failed with a fatal error. -+ * @KUTF_RESULT_ABORT: The test result failed due to a non-UTF -+ * assertion failure. -+ * @KUTF_RESULT_COUNT: The current number of possible status messages. -+ */ -+enum kutf_result_status { -+ KUTF_RESULT_BENCHMARK = -3, -+ KUTF_RESULT_SKIP = -2, -+ KUTF_RESULT_UNKNOWN = -1, -+ -+ KUTF_RESULT_PASS = 0, -+ KUTF_RESULT_DEBUG = 1, -+ KUTF_RESULT_INFO = 2, -+ KUTF_RESULT_WARN = 3, -+ KUTF_RESULT_FAIL = 4, -+ KUTF_RESULT_FATAL = 5, -+ KUTF_RESULT_ABORT = 6, -+ -+ KUTF_RESULT_COUNT -+}; -+ -+/* The maximum size of a kutf_result_status result when -+ * converted to a string -+ */ -+#define KUTF_ERROR_MAX_NAME_SIZE 21 -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+/** -+ * struct kutf_result - Represents a single test result. -+ * @node: Next result in the list of results. -+ * @status: The status summary (pass / warn / fail / etc). -+ * @message: A more verbose status message. -+ */ -+struct kutf_result { -+ struct list_head node; -+ enum kutf_result_status status; -+ const char *message; -+}; -+ -+/** -+ * kutf_create_result_set() - Create a new result set -+ * to which results can be added. -+ * -+ * Return: The created resultset. -+ */ -+struct kutf_result_set *kutf_create_result_set(void); -+ -+/** -+ * kutf_add_result() - Add a result to the end of an existing resultset. -+ * -+ * @mempool: The memory pool to allocate the result storage from. -+ * @set: The resultset to add the result to. -+ * @status: The result status to add. -+ * @message: The result message to add. -+ */ -+void kutf_add_result(struct kutf_mempool *mempool, struct kutf_result_set *set, -+ enum kutf_result_status status, const char *message); -+ -+/** -+ * kutf_remove_result() - Remove a result from the head of a resultset. -+ * @set: The resultset. -+ * -+ * Return: result or NULL if there are no further results in the resultset. -+ */ -+struct kutf_result *kutf_remove_result( -+ struct kutf_result_set *set); -+ -+/** -+ * kutf_destroy_result_set() - Free a previously created resultset. -+ * -+ * @results: The result set whose resources to free. -+ */ -+void kutf_destroy_result_set(struct kutf_result_set *results); -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _KERNEL_UTF_RESULTSET_H_ */ -diff --git a/drivers/gpu/arm/midgard/tests/include/kutf/kutf_suite.h b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_suite.h -new file mode 100644 -index 0000000..cba2b2d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_suite.h -@@ -0,0 +1,568 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KERNEL_UTF_SUITE_H_ -+#define _KERNEL_UTF_SUITE_H_ -+ -+/* kutf_suite.h -+ * Functions for management of test suites. -+ * -+ * This collection of data structures, macros, and functions are used to -+ * create Test Suites, Tests within those Test Suites, and Fixture variants -+ * of each test. -+ */ -+ -+#include -+ -+#include -+#include -+ -+/** -+ * Pseudo-flag indicating an absence of any specified test class. Note that -+ * tests should not be annotated with this constant as it is simply a zero -+ * value; tests without a more specific class must be marked with the flag -+ * KUTF_F_TEST_GENERIC. -+ */ -+#define KUTF_F_TEST_NONE ((unsigned int)(0)) -+ -+/** -+ * Class indicating this test is a smoke test. -+ * A given set of smoke tests should be quick to run, enabling rapid turn-around -+ * of "regress-on-commit" test runs. -+ */ -+#define KUTF_F_TEST_SMOKETEST ((unsigned int)(1 << 1)) -+ -+/** -+ * Class indicating this test is a performance test. -+ * These tests typically produce a performance metric, such as "time to run" or -+ * "frames per second", -+ */ -+#define KUTF_F_TEST_PERFORMANCE ((unsigned int)(1 << 2)) -+ -+/** -+ * Class indicating that this test is a deprecated test. -+ * These tests have typically been replaced by an alternative test which is -+ * more efficient, or has better coverage. -+ */ -+#define KUTF_F_TEST_DEPRECATED ((unsigned int)(1 << 3)) -+ -+/** -+ * Class indicating that this test is a known failure. -+ * These tests have typically been run and failed, but marking them as a known -+ * failure means it is easier to triage results. -+ * -+ * It is typically more convenient to triage known failures using the -+ * results database and web UI, as this means there is no need to modify the -+ * test code. -+ */ -+#define KUTF_F_TEST_EXPECTED_FAILURE ((unsigned int)(1 << 4)) -+ -+/** -+ * Class indicating that this test is a generic test, which is not a member of -+ * a more specific test class. Tests which are not created with a specific set -+ * of filter flags by the user are assigned this test class by default. -+ */ -+#define KUTF_F_TEST_GENERIC ((unsigned int)(1 << 5)) -+ -+/** -+ * Class indicating this test is a resource allocation failure test. -+ * A resource allocation failure test will test that an error code is -+ * correctly propagated when an allocation fails. -+ */ -+#define KUTF_F_TEST_RESFAIL ((unsigned int)(1 << 6)) -+ -+/** -+ * Additional flag indicating that this test is an expected failure when -+ * run in resource failure mode. These tests are never run when running -+ * the low resource mode. -+ */ -+#define KUTF_F_TEST_EXPECTED_FAILURE_RF ((unsigned int)(1 << 7)) -+ -+/** -+ * Flag reserved for user-defined filter zero. -+ */ -+#define KUTF_F_TEST_USER_0 ((unsigned int)(1 << 24)) -+ -+/** -+ * Flag reserved for user-defined filter one. -+ */ -+#define KUTF_F_TEST_USER_1 ((unsigned int)(1 << 25)) -+ -+/** -+ * Flag reserved for user-defined filter two. -+ */ -+#define KUTF_F_TEST_USER_2 ((unsigned int)(1 << 26)) -+ -+/** -+ * Flag reserved for user-defined filter three. -+ */ -+#define KUTF_F_TEST_USER_3 ((unsigned int)(1 << 27)) -+ -+/** -+ * Flag reserved for user-defined filter four. -+ */ -+#define KUTF_F_TEST_USER_4 ((unsigned int)(1 << 28)) -+ -+/** -+ * Flag reserved for user-defined filter five. -+ */ -+#define KUTF_F_TEST_USER_5 ((unsigned int)(1 << 29)) -+ -+/** -+ * Flag reserved for user-defined filter six. -+ */ -+#define KUTF_F_TEST_USER_6 ((unsigned int)(1 << 30)) -+ -+/** -+ * Flag reserved for user-defined filter seven. -+ */ -+#define KUTF_F_TEST_USER_7 ((unsigned int)(1 << 31)) -+ -+/** -+ * Pseudo-flag indicating that all test classes should be executed. -+ */ -+#define KUTF_F_TEST_ALL ((unsigned int)(0xFFFFFFFFU)) -+ -+/** -+ * union kutf_callback_data - Union used to store test callback data -+ * @ptr_value: pointer to the location where test callback data -+ * are stored -+ * @u32_value: a number which represents test callback data -+ */ -+union kutf_callback_data { -+ void *ptr_value; -+ u32 u32_value; -+}; -+ -+/** -+ * struct kutf_userdata_ops- Structure defining methods to exchange data -+ * with userspace via the 'data' file -+ * @open: Function used to notify when the 'data' file was opened -+ * @release: Function used to notify when the 'data' file was closed -+ * @notify_ended: Function used to notify when the test has ended. -+ * @consumer: Function used to consume writes from userspace -+ * @producer: Function used to produce data for userspace to read -+ * -+ * All ops can be NULL. -+ */ -+struct kutf_userdata_ops { -+ int (*open)(void *priv); -+ void (*release)(void *priv); -+ void (*notify_ended)(void *priv); -+ ssize_t (*consumer)(void *priv, const char __user *userbuf, -+ size_t userbuf_len, loff_t *ppos); -+ ssize_t (*producer)(void *priv, char __user *userbuf, -+ size_t userbuf_len, loff_t *ppos); -+}; -+ -+/** -+ * struct kutf_context - Structure representing a kernel test context -+ * @kref: Refcount for number of users of this context -+ * @suite: Convenience pointer to the suite this context -+ * is running -+ * @test_fix: The fixture that is being run in this context -+ * @fixture_pool: The memory pool used for the duration of -+ * the fixture/text context. -+ * @fixture: The user provided fixture structure. -+ * @fixture_index: The index (id) of the current fixture. -+ * @fixture_name: The name of the current fixture (or NULL if unnamed). -+ * @test_data: Any user private data associated with this test -+ * @result_set: All the results logged by this test context -+ * @status: The status of the currently running fixture. -+ * @expected_status: The expected status on exist of the currently -+ * running fixture. -+ * @userdata_consumer_priv: Parameter to pass into kutf_userdata_ops -+ * consumer function. Must not be NULL if a -+ * consumer function was specified -+ * @userdata_producer_priv: Parameter to pass into kutf_userdata_ops -+ * producer function. Must not be NULL if a -+ * producer function was specified -+ * @userdata_dentry: The debugfs file for userdata exchange -+ */ -+struct kutf_context { -+ struct kref kref; -+ struct kutf_suite *suite; -+ struct kutf_test_fixture *test_fix; -+ struct kutf_mempool fixture_pool; -+ void *fixture; -+ unsigned int fixture_index; -+ const char *fixture_name; -+ union kutf_callback_data test_data; -+ struct kutf_result_set *result_set; -+ enum kutf_result_status status; -+ enum kutf_result_status expected_status; -+ void *userdata_consumer_priv; -+ void *userdata_producer_priv; -+ struct dentry *userdata_dentry; -+}; -+ -+/** -+ * struct kutf_suite - Structure representing a kernel test suite -+ * @app: The application this suite belongs to. -+ * @name: The name of this suite. -+ * @suite_data: Any user private data associated with this -+ * suite. -+ * @create_fixture: Function used to create a new fixture instance -+ * @remove_fixture: Function used to destroy a new fixture instance -+ * @fixture_variants: The number of variants (must be at least 1). -+ * @suite_default_flags: Suite global filter flags which are set on -+ * all tests. -+ * @node: List node for suite_list -+ * @dir: The debugfs directory for this suite -+ * @test_list: List head to store all the tests which are -+ * part of this suite -+ */ -+struct kutf_suite { -+ struct kutf_application *app; -+ const char *name; -+ union kutf_callback_data suite_data; -+ void *(*create_fixture)(struct kutf_context *context); -+ void (*remove_fixture)(struct kutf_context *context); -+ unsigned int fixture_variants; -+ unsigned int suite_default_flags; -+ struct list_head node; -+ struct dentry *dir; -+ struct list_head test_list; -+}; -+ -+/* ============================================================================ -+ Application functions -+============================================================================ */ -+ -+/** -+ * kutf_create_application() - Create an in kernel test application. -+ * @name: The name of the test application. -+ * -+ * Return: pointer to the kutf_application on success or NULL -+ * on failure -+ */ -+struct kutf_application *kutf_create_application(const char *name); -+ -+/** -+ * kutf_destroy_application() - Destroy an in kernel test application. -+ * -+ * @app: The test application to destroy. -+ */ -+void kutf_destroy_application(struct kutf_application *app); -+ -+/* ============================================================================ -+ Suite functions -+============================================================================ */ -+ -+/** -+ * kutf_create_suite() - Create a kernel test suite. -+ * @app: The test application to create the suite in. -+ * @name: The name of the suite. -+ * @fixture_count: The number of fixtures to run over the test -+ * functions in this suite -+ * @create_fixture: Callback used to create a fixture. The returned value -+ * is stored in the fixture pointer in the context for -+ * use in the test functions. -+ * @remove_fixture: Callback used to remove a previously created fixture. -+ * -+ * Suite names must be unique. Should two suites with the same name be -+ * registered with the same application then this function will fail, if they -+ * are registered with different applications then the function will not detect -+ * this and the call will succeed. -+ * -+ * Return: pointer to the created kutf_suite on success or NULL -+ * on failure -+ */ -+struct kutf_suite *kutf_create_suite( -+ struct kutf_application *app, -+ const char *name, -+ unsigned int fixture_count, -+ void *(*create_fixture)(struct kutf_context *context), -+ void (*remove_fixture)(struct kutf_context *context)); -+ -+/** -+ * kutf_create_suite_with_filters() - Create a kernel test suite with user -+ * defined default filters. -+ * @app: The test application to create the suite in. -+ * @name: The name of the suite. -+ * @fixture_count: The number of fixtures to run over the test -+ * functions in this suite -+ * @create_fixture: Callback used to create a fixture. The returned value -+ * is stored in the fixture pointer in the context for -+ * use in the test functions. -+ * @remove_fixture: Callback used to remove a previously created fixture. -+ * @filters: Filters to apply to a test if it doesn't provide its own -+ * -+ * Suite names must be unique. Should two suites with the same name be -+ * registered with the same application then this function will fail, if they -+ * are registered with different applications then the function will not detect -+ * this and the call will succeed. -+ * -+ * Return: pointer to the created kutf_suite on success or NULL on failure -+ */ -+struct kutf_suite *kutf_create_suite_with_filters( -+ struct kutf_application *app, -+ const char *name, -+ unsigned int fixture_count, -+ void *(*create_fixture)(struct kutf_context *context), -+ void (*remove_fixture)(struct kutf_context *context), -+ unsigned int filters); -+ -+/** -+ * kutf_create_suite_with_filters_and_data() - Create a kernel test suite with -+ * user defined default filters. -+ * @app: The test application to create the suite in. -+ * @name: The name of the suite. -+ * @fixture_count: The number of fixtures to run over the test -+ * functions in this suite -+ * @create_fixture: Callback used to create a fixture. The returned value -+ * is stored in the fixture pointer in the context for -+ * use in the test functions. -+ * @remove_fixture: Callback used to remove a previously created fixture. -+ * @filters: Filters to apply to a test if it doesn't provide its own -+ * @suite_data: Suite specific callback data, provided during the -+ * running of the test in the kutf_context -+ * -+ * Return: pointer to the created kutf_suite on success or NULL -+ * on failure -+ */ -+struct kutf_suite *kutf_create_suite_with_filters_and_data( -+ struct kutf_application *app, -+ const char *name, -+ unsigned int fixture_count, -+ void *(*create_fixture)(struct kutf_context *context), -+ void (*remove_fixture)(struct kutf_context *context), -+ unsigned int filters, -+ union kutf_callback_data suite_data); -+ -+/** -+ * kutf_add_test() - Add a test to a kernel test suite. -+ * @suite: The suite to add the test to. -+ * @id: The ID of the test. -+ * @name: The name of the test. -+ * @execute: Callback to the test function to run. -+ * -+ * Note: As no filters are provided the test will use the suite filters instead -+ */ -+void kutf_add_test(struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context)); -+ -+/** -+ * kutf_add_test_with_filters() - Add a test to a kernel test suite with filters -+ * @suite: The suite to add the test to. -+ * @id: The ID of the test. -+ * @name: The name of the test. -+ * @execute: Callback to the test function to run. -+ * @filters: A set of filtering flags, assigning test categories. -+ */ -+void kutf_add_test_with_filters(struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context), -+ unsigned int filters); -+ -+/** -+ * kutf_add_test_with_filters_and_data() - Add a test to a kernel test suite -+ * with filters. -+ * @suite: The suite to add the test to. -+ * @id: The ID of the test. -+ * @name: The name of the test. -+ * @execute: Callback to the test function to run. -+ * @filters: A set of filtering flags, assigning test categories. -+ * @test_data: Test specific callback data, provided during the -+ * running of the test in the kutf_context -+ */ -+void kutf_add_test_with_filters_and_data( -+ struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context), -+ unsigned int filters, -+ union kutf_callback_data test_data); -+ -+/** -+ * kutf_add_test_with_filters_data_and_userdata() - Add a test to a kernel test suite with filters and setup for -+ * receiving data from userside -+ * @suite: The suite to add the test to. -+ * @id: The ID of the test. -+ * @name: The name of the test. -+ * @execute: Callback to the test function to run. -+ * @filters: A set of filtering flags, assigning test categories. -+ * @test_data: Test specific callback data, provided during the -+ * running of the test in the kutf_context -+ * @userdata_ops: Callbacks to use for sending and receiving data to -+ * userspace. A copy of the struct kutf_userdata_ops is -+ * taken. Each callback can be NULL. -+ * -+ */ -+void kutf_add_test_with_filters_data_and_userdata( -+ struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context), -+ unsigned int filters, -+ union kutf_callback_data test_data, -+ struct kutf_userdata_ops *userdata_ops); -+ -+ -+/* ============================================================================ -+ Test functions -+============================================================================ */ -+/** -+ * kutf_test_log_result_external() - Log a result which has been created -+ * externally into a in a standard form -+ * recognized by the log parser. -+ * @context: The test context the test is running in -+ * @message: The message for this result -+ * @new_status: The result status of this log message -+ */ -+void kutf_test_log_result_external( -+ struct kutf_context *context, -+ const char *message, -+ enum kutf_result_status new_status); -+ -+/** -+ * kutf_test_expect_abort() - Tell the kernel that you expect the current -+ * fixture to produce an abort. -+ * @context: The test context this test is running in. -+ */ -+void kutf_test_expect_abort(struct kutf_context *context); -+ -+/** -+ * kutf_test_expect_fatal() - Tell the kernel that you expect the current -+ * fixture to produce a fatal error. -+ * @context: The test context this test is running in. -+ */ -+void kutf_test_expect_fatal(struct kutf_context *context); -+ -+/** -+ * kutf_test_expect_fail() - Tell the kernel that you expect the current -+ * fixture to fail. -+ * @context: The test context this test is running in. -+ */ -+void kutf_test_expect_fail(struct kutf_context *context); -+ -+/** -+ * kutf_test_expect_warn() - Tell the kernel that you expect the current -+ * fixture to produce a warning. -+ * @context: The test context this test is running in. -+ */ -+void kutf_test_expect_warn(struct kutf_context *context); -+ -+/** -+ * kutf_test_expect_pass() - Tell the kernel that you expect the current -+ * fixture to pass. -+ * @context: The test context this test is running in. -+ */ -+void kutf_test_expect_pass(struct kutf_context *context); -+ -+/** -+ * kutf_test_skip() - Tell the kernel that the test should be skipped. -+ * @context: The test context this test is running in. -+ */ -+void kutf_test_skip(struct kutf_context *context); -+ -+/** -+ * kutf_test_skip_msg() - Tell the kernel that this test has been skipped, -+ * supplying a reason string. -+ * @context: The test context this test is running in. -+ * @message: A message string containing the reason for the skip. -+ * -+ * Note: The message must not be freed during the lifetime of the test run. -+ * This means it should either be a prebaked string, or if a dynamic string -+ * is required it must be created with kutf_dsprintf which will store -+ * the resultant string in a buffer who's lifetime is the same as the test run. -+ */ -+void kutf_test_skip_msg(struct kutf_context *context, const char *message); -+ -+/** -+ * kutf_test_pass() - Tell the kernel that this test has passed. -+ * @context: The test context this test is running in. -+ * @message: A message string containing the reason for the pass. -+ * -+ * Note: The message must not be freed during the lifetime of the test run. -+ * This means it should either be a pre-baked string, or if a dynamic string -+ * is required it must be created with kutf_dsprintf which will store -+ * the resultant string in a buffer who's lifetime is the same as the test run. -+ */ -+void kutf_test_pass(struct kutf_context *context, char const *message); -+ -+/** -+ * kutf_test_debug() - Send a debug message -+ * @context: The test context this test is running in. -+ * @message: A message string containing the debug information. -+ * -+ * Note: The message must not be freed during the lifetime of the test run. -+ * This means it should either be a pre-baked string, or if a dynamic string -+ * is required it must be created with kutf_dsprintf which will store -+ * the resultant string in a buffer who's lifetime is the same as the test run. -+ */ -+void kutf_test_debug(struct kutf_context *context, char const *message); -+ -+/** -+ * kutf_test_info() - Send an information message -+ * @context: The test context this test is running in. -+ * @message: A message string containing the information message. -+ * -+ * Note: The message must not be freed during the lifetime of the test run. -+ * This means it should either be a pre-baked string, or if a dynamic string -+ * is required it must be created with kutf_dsprintf which will store -+ * the resultant string in a buffer who's lifetime is the same as the test run. -+ */ -+void kutf_test_info(struct kutf_context *context, char const *message); -+ -+/** -+ * kutf_test_warn() - Send a warning message -+ * @context: The test context this test is running in. -+ * @message: A message string containing the warning message. -+ * -+ * Note: The message must not be freed during the lifetime of the test run. -+ * This means it should either be a pre-baked string, or if a dynamic string -+ * is required it must be created with kutf_dsprintf which will store -+ * the resultant string in a buffer who's lifetime is the same as the test run. -+ */ -+void kutf_test_warn(struct kutf_context *context, char const *message); -+ -+/** -+ * kutf_test_fail() - Tell the kernel that a test has failed -+ * @context: The test context this test is running in. -+ * @message: A message string containing the failure message. -+ * -+ * Note: The message must not be freed during the lifetime of the test run. -+ * This means it should either be a pre-baked string, or if a dynamic string -+ * is required it must be created with kutf_dsprintf which will store -+ * the resultant string in a buffer who's lifetime is the same as the test run. -+ */ -+void kutf_test_fail(struct kutf_context *context, char const *message); -+ -+/** -+ * kutf_test_fatal() - Tell the kernel that a test has triggered a fatal error -+ * @context: The test context this test is running in. -+ * @message: A message string containing the fatal error message. -+ * -+ * Note: The message must not be freed during the lifetime of the test run. -+ * This means it should either be a pre-baked string, or if a dynamic string -+ * is required it must be created with kutf_dsprintf which will store -+ * the resultant string in a buffer who's lifetime is the same as the test run. -+ */ -+void kutf_test_fatal(struct kutf_context *context, char const *message); -+ -+/** -+ * kutf_test_abort() - Tell the kernel that a test triggered an abort in the test -+ * -+ * @context: The test context this test is running in. -+ */ -+void kutf_test_abort(struct kutf_context *context); -+ -+#endif /* _KERNEL_UTF_SUITE_H_ */ -diff --git a/drivers/gpu/arm/midgard/tests/include/kutf/kutf_utils.h b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_utils.h -new file mode 100644 -index 0000000..c458c1f ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/include/kutf/kutf_utils.h -@@ -0,0 +1,55 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#ifndef _KERNEL_UTF_UTILS_H_ -+#define _KERNEL_UTF_UTILS_H_ -+ -+/* kutf_utils.h -+ * Utilities for the kernel UTF test infrastructure. -+ * -+ * This collection of library functions are provided for use by kernel UTF -+ * and users of kernel UTF which don't directly fit within the other -+ * code modules. -+ */ -+ -+#include -+ -+/** -+ * Maximum size of the message strings within kernel UTF, messages longer then -+ * this will be truncated. -+ */ -+#define KUTF_MAX_DSPRINTF_LEN 1024 -+ -+/** -+ * kutf_dsprintf() - dynamic sprintf -+ * @pool: memory pool to allocate from -+ * @fmt: The format string describing the string to document. -+ * @... The parameters to feed in to the format string. -+ * -+ * This function implements sprintf which dynamically allocates memory to store -+ * the string. The library will free the memory containing the string when the -+ * result set is cleared or destroyed. -+ * -+ * Note The returned string may be truncated to fit an internal temporary -+ * buffer, which is KUTF_MAX_DSPRINTF_LEN bytes in length. -+ * -+ * Return: Returns pointer to allocated string, or NULL on error. -+ */ -+const char *kutf_dsprintf(struct kutf_mempool *pool, -+ const char *fmt, ...); -+ -+#endif /* _KERNEL_UTF_UTILS_H_ */ -diff --git a/drivers/gpu/arm/midgard/tests/kutf/Kbuild b/drivers/gpu/arm/midgard/tests/kutf/Kbuild -new file mode 100644 -index 0000000..97f8005 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/Kbuild -@@ -0,0 +1,20 @@ -+# -+# (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ccflags-y += -I$(src)/../include -+ -+obj-$(CONFIG_MALI_KUTF) += kutf.o -+ -+kutf-y := kutf_mem.o kutf_resultset.o kutf_suite.o kutf_utils.o kutf_helpers.o kutf_helpers_user.o -diff --git a/drivers/gpu/arm/midgard/tests/kutf/Kconfig b/drivers/gpu/arm/midgard/tests/kutf/Kconfig -new file mode 100644 -index 0000000..6a87bdb ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/Kconfig -@@ -0,0 +1,22 @@ -+# -+# (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+config MALI_KUTF -+ tristate "Mali Kernel Unit Test Framework" -+ default m -+ help -+ Enables MALI testing framework. To compile it as a module, -+ choose M here - this will generate a single module called kutf. -diff --git a/drivers/gpu/arm/midgard/tests/kutf/Makefile b/drivers/gpu/arm/midgard/tests/kutf/Makefile -new file mode 100644 -index 0000000..010c92c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/Makefile -@@ -0,0 +1,29 @@ -+# -+# (C) COPYRIGHT 2014-2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+# linux build system bootstrap for out-of-tree module -+ -+# default to building for the host -+ARCH ?= $(shell uname -m) -+ -+ifeq ($(KDIR),) -+$(error Must specify KDIR to point to the kernel to target)) -+endif -+ -+all: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) $(SCONS_CONFIGS) EXTRA_CFLAGS=-I$(CURDIR)/../include modules -+ -+clean: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean -diff --git a/drivers/gpu/arm/midgard/tests/kutf/kutf_helpers.c b/drivers/gpu/arm/midgard/tests/kutf/kutf_helpers.c -new file mode 100644 -index 0000000..793d58c ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/kutf_helpers.c -@@ -0,0 +1,768 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* Kernel UTF test helpers */ -+#include -+ -+/* 10s timeout for user thread to open the 'data' file once the test is started */ -+#define USERDATA_WAIT_TIMEOUT_MS 10000 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+int kutf_helper_textbuf_init(struct kutf_helper_textbuf *textbuf, -+ struct kutf_mempool *mempool, int max_line_size, -+ int max_nr_lines) -+{ -+ textbuf->scratchpad = kutf_mempool_alloc(mempool, max_line_size); -+ -+ if (!textbuf->scratchpad) -+ return -ENOMEM; -+ -+ mutex_init(&textbuf->lock); -+ textbuf->nr_user_clients = 0; -+ textbuf->mempool = mempool; -+ textbuf->used_bytes = 0; -+ textbuf->prev_pos = 0; -+ textbuf->prev_line_pos = 0; -+ INIT_LIST_HEAD(&textbuf->textbuf_list); -+ textbuf->max_line_size = max_line_size; -+ textbuf->max_nr_lines = max_nr_lines; -+ textbuf->nr_lines = 0; -+ textbuf->flags = 0ul; -+ init_waitqueue_head(&textbuf->user_opened_wq); -+ init_waitqueue_head(&textbuf->not_full_wq); -+ init_waitqueue_head(&textbuf->not_empty_wq); -+ -+ return 0; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_init); -+ -+/** -+ * kutf_helper_textbuf_open() - Notify that userspace has opened the 'data' -+ * file for a textbuf -+ * -+ * @priv: private pointer from a kutf_userdata_exchange, which -+ * should be a pointer to a struct kutf_helper_textbuf -+ * -+ * Return: 0 on success, or negative value on error. -+ */ -+static int kutf_helper_textbuf_open(void *priv) -+{ -+ struct kutf_helper_textbuf *textbuf = priv; -+ int ret; -+ -+ ret = mutex_lock_interruptible(&textbuf->lock); -+ if (ret) -+ return -ERESTARTSYS; -+ -+ ++(textbuf->nr_user_clients); -+ wake_up(&textbuf->user_opened_wq); -+ -+ mutex_unlock(&textbuf->lock); -+ return ret; -+} -+ -+/** -+ * kutf_helper_textbuf_release() - Notify that userspace has closed the 'data' -+ * file for a textbuf -+ * -+ * @priv: private pointer from a kutf_userdata_exchange, which -+ * should be a pointer to a struct kutf_helper_textbuf -+ */ -+static void kutf_helper_textbuf_release(void *priv) -+{ -+ struct kutf_helper_textbuf *textbuf = priv; -+ -+ /* Shouldn't use interruptible variants here because if a signal is -+ * pending, we can't abort and restart the call */ -+ mutex_lock(&textbuf->lock); -+ -+ --(textbuf->nr_user_clients); -+ if (!textbuf->nr_user_clients) { -+ /* All clients disconnected, wakeup kernel-side waiters */ -+ wake_up(&textbuf->not_full_wq); -+ wake_up(&textbuf->not_empty_wq); -+ } -+ -+ mutex_unlock(&textbuf->lock); -+} -+ -+/** -+ * kutf_helper_textbuf_notify_test_ended() - Notify that the test has ended -+ * -+ * @priv: private pointer from a kutf_userdata_exchange, which -+ * should be a pointer to a struct kutf_helper_textbuf -+ * -+ * After this call, userspace should be allowed to finish remaining reads but -+ * not make new ones, and not be allowed to make new writes. -+ */ -+static void kutf_helper_textbuf_notify_test_ended(void *priv) -+{ -+ struct kutf_helper_textbuf *textbuf = priv; -+ -+ /* Shouldn't use interruptible variants here because if a signal is -+ * pending, we can't abort and restart the call */ -+ mutex_lock(&textbuf->lock); -+ -+ textbuf->flags |= KUTF_HELPER_TEXTBUF_FLAG_DYING; -+ -+ /* Consumers waiting due to being full should wake up and abort */ -+ wake_up(&textbuf->not_full_wq); -+ /* Producers waiting due to being empty should wake up and abort */ -+ wake_up(&textbuf->not_empty_wq); -+ -+ mutex_unlock(&textbuf->lock); -+} -+ -+/* Collect text in a textbuf scratchpad up to (but excluding) specified -+ * newline_off, and add it as a textbuf_line -+ * -+ * newline_off is permissible to be at the character after the end of the -+ * scratchpad (i.e. equal to textbuf->max_line_size), for handling when the -+ * line was longer than the size of the scratchpad. Nevertheless, the resulting -+ * size of the line is kept at textbuf->max_line_size, including the '\0' -+ * terminator. That is, the string length will be textbuf->max_line_size-1. -+ * -+ * Remaining characters strictly after newline_off are moved to the beginning -+ * of the scratchpad, to allow space for a longer line to be collected. This -+ * means the character specified at newline_off will be removed from/no longer -+ * be within the valid region of the scratchpad -+ * -+ * Returns number of bytes the scratchpad was shortened by, or an error -+ * otherwise -+ */ -+static size_t collect_line(struct kutf_helper_textbuf *textbuf, int newline_off) -+{ -+ /* '\n' terminator will be replaced as '\0' */ -+ int str_buf_size; -+ struct kutf_helper_textbuf_line *textbuf_line; -+ char *str_start; -+ int bytes_remain; -+ char *scratch = textbuf->scratchpad; -+ int nextline_off; -+ -+ str_buf_size = newline_off + 1; -+ if (str_buf_size > textbuf->max_line_size) -+ str_buf_size = textbuf->max_line_size; -+ -+ /* String is stored immediately after the line */ -+ textbuf_line = kutf_mempool_alloc(textbuf->mempool, str_buf_size + sizeof(struct kutf_helper_textbuf_line)); -+ if (!textbuf_line) -+ return -ENOMEM; -+ -+ str_start = &textbuf_line->str[0]; -+ -+ /* Copy in string, excluding the terminating '\n' character, replacing -+ * it with '\0' */ -+ strncpy(str_start, scratch, str_buf_size - 1); -+ str_start[str_buf_size-1] = '\0'; -+ textbuf_line->str_size = str_buf_size; -+ -+ /* Append to the textbuf */ -+ list_add_tail(&textbuf_line->node, &textbuf->textbuf_list); -+ ++(textbuf->nr_lines); -+ -+ /* Move the rest of the scratchpad to the start */ -+ nextline_off = newline_off + 1; -+ if (nextline_off > textbuf->used_bytes) -+ nextline_off = textbuf->used_bytes; -+ -+ bytes_remain = textbuf->used_bytes - nextline_off; -+ memmove(scratch, scratch + nextline_off, bytes_remain); -+ textbuf->used_bytes = bytes_remain; -+ -+ /* Wakeup anyone blocked on empty */ -+ wake_up(&textbuf->not_empty_wq); -+ -+ return nextline_off; -+} -+ -+/* Buffer size for truncating a string to its newline. -+ * Allocated on the stack, so keep it moderately small (within PAGE_SIZE) */ -+#define TRUNCATE_BUF_SZ 512 -+ -+/* Discard input from a userbuf up to a newline, then collect what was in the -+ * scratchpad into a new textbuf line */ -+static ssize_t collect_longline_truncate(struct kutf_helper_textbuf *textbuf, -+ const char __user *userbuf, size_t userbuf_len) -+{ -+ ssize_t bytes_processed = 0; -+ -+ while (userbuf_len > 0) { -+ int userbuf_copy_sz = userbuf_len; -+ size_t res; -+ char *newline_ptr; -+ char truncate_buf[TRUNCATE_BUF_SZ]; -+ -+ if (userbuf_len > TRUNCATE_BUF_SZ) -+ userbuf_copy_sz = TRUNCATE_BUF_SZ; -+ else -+ userbuf_copy_sz = (int)userbuf_len; -+ -+ /* copy what we can */ -+ res = copy_from_user(truncate_buf, userbuf, userbuf_copy_sz); -+ if (res == userbuf_copy_sz) -+ return -EFAULT; -+ userbuf_copy_sz -= res; -+ -+ /* Search for newline in what was copied */ -+ newline_ptr = strnchr(truncate_buf, userbuf_copy_sz, '\n'); -+ -+ if (newline_ptr) { -+ ssize_t sres; -+ /* Newline found: collect scratchpad and exit out */ -+ int newline_off = newline_ptr - truncate_buf; -+ -+ sres = collect_line(textbuf, textbuf->used_bytes); -+ if (sres < 0) -+ return sres; -+ -+ bytes_processed += newline_off + 1; -+ break; -+ } -+ -+ /* Newline not yet found: advance to the next part to copy */ -+ userbuf += userbuf_copy_sz; -+ userbuf_len -= userbuf_copy_sz; -+ bytes_processed += userbuf_copy_sz; -+ } -+ -+ return bytes_processed; -+} -+ -+/** -+ * kutf_helper_textbuf_consume() - 'data' file consumer function for writing to -+ * a textbuf -+ * @priv: private pointer from a kutf_userdata_exchange, which -+ * should be a pointer to a struct kutf_helper_textbuf to -+ * write into -+ * @userbuf: the userspace buffer to read from -+ * @userbuf_len: size of the userspace buffer -+ * @ppos: the current position in the buffer -+ * -+ * This consumer function is used as a write consumer for the 'data' file, -+ * receiving data that has been written to the 'data' file by userspace. It -+ * will read from the userspace buffer @userbuf and separates it into '\n' -+ * delimited lines for the textbuf pointed to by @priv . -+ * -+ * If there is insufficient space in textbuf, then it will block until there is -+ * space - for example, a kernel-side test calls -+ * kutf_helper_textbuf_dequeue(). Since this is expected to be called in the -+ * context of a syscall, the call can only be cancelled by sending an -+ * appropriate signal to the userspace process. -+ * -+ * The current position @ppos is advanced by the number of bytes successfully -+ * read. -+ * -+ * Return: the number of bytes read, or negative value on error. -+ */ -+static ssize_t kutf_helper_textbuf_consume(void *priv, -+ const char __user *userbuf, size_t userbuf_len, loff_t *ppos) -+{ -+ struct kutf_helper_textbuf *textbuf = priv; -+ int userbuf_copy_sz; -+ char *next_newline_ptr; -+ size_t bytes_processed = 0; -+ int newdata_off; -+ ssize_t ret; -+ -+ ret = mutex_lock_interruptible(&textbuf->lock); -+ if (ret) -+ return -ERESTARTSYS; -+ -+ /* Validate input */ -+ if (*ppos < 0) { -+ ret = -EINVAL; -+ goto out_unlock; -+ } -+ if (!userbuf_len) { -+ ret = 0; -+ goto out_unlock; -+ } -+ -+ while (textbuf->nr_lines >= textbuf->max_nr_lines && -+ !(textbuf->flags & KUTF_HELPER_TEXTBUF_FLAG_DYING)) { -+ /* Block on kernel-side dequeue making space available -+ * NOTE: should also handle O_NONBLOCK */ -+ mutex_unlock(&textbuf->lock); -+ ret = wait_event_interruptible(textbuf->not_full_wq, -+ (textbuf->nr_lines < textbuf->max_nr_lines || -+ (textbuf->flags & KUTF_HELPER_TEXTBUF_FLAG_DYING))); -+ if (ret) -+ return -ERESTARTSYS; -+ ret = mutex_lock_interruptible(&textbuf->lock); -+ if (ret) -+ return -ERESTARTSYS; -+ } -+ -+ if (textbuf->flags & KUTF_HELPER_TEXTBUF_FLAG_DYING) { -+ ret = -ENODEV; -+ goto out_unlock; -+ } -+ -+ if (textbuf->prev_pos != *ppos && textbuf->used_bytes) { -+ /* Seeking causes a new line to occur: -+ * Truncate what data was there into a textbuf-line, and reset -+ * the buffer */ -+ ret = collect_line(textbuf, textbuf->used_bytes); -+ if (ret < 0) -+ goto finish; -+ } else if (textbuf->used_bytes >= (textbuf->max_line_size - 1)) { -+ /* Line too long discard input until we find a '\n' */ -+ ret = collect_longline_truncate(textbuf, userbuf, userbuf_len); -+ -+ if (ret < 0) -+ goto finish; -+ -+ /* Update userbuf with how much was processed, which may be the -+ * entire buffer now */ -+ userbuf += ret; -+ userbuf_len -= ret; -+ bytes_processed += ret; -+ -+ /* If there's buffer remaining and we fault later (e.g. can't -+ * read or OOM) ensure ppos is updated */ -+ *ppos += ret; -+ -+ /* recheck in case entire buffer processed */ -+ if (!userbuf_len) -+ goto finish; -+ } -+ -+ /* An extra line may've been added, ensure we don't overfill */ -+ if (textbuf->nr_lines >= textbuf->max_nr_lines) -+ goto finish_noerr; -+ -+ userbuf_copy_sz = userbuf_len; -+ -+ /* Copy in as much as we can */ -+ if (userbuf_copy_sz > textbuf->max_line_size - textbuf->used_bytes) -+ userbuf_copy_sz = textbuf->max_line_size - textbuf->used_bytes; -+ -+ ret = copy_from_user(textbuf->scratchpad + textbuf->used_bytes, userbuf, userbuf_copy_sz); -+ if (ret == userbuf_copy_sz) { -+ ret = -EFAULT; -+ goto finish; -+ } -+ userbuf_copy_sz -= ret; -+ -+ newdata_off = textbuf->used_bytes; -+ textbuf->used_bytes += userbuf_copy_sz; -+ -+ while (textbuf->used_bytes && textbuf->nr_lines < textbuf->max_nr_lines) { -+ int new_bytes_remain = textbuf->used_bytes - newdata_off; -+ /* Find a new line - only the new part should be checked */ -+ next_newline_ptr = strnchr(textbuf->scratchpad + newdata_off, new_bytes_remain, '\n'); -+ -+ if (next_newline_ptr) { -+ int newline_off = next_newline_ptr - textbuf->scratchpad; -+ -+ /* if found, collect up to it, then memmove the rest */ -+ /* reset positions and see if we can fill any further */ -+ /* repeat until run out of data or line is filled */ -+ ret = collect_line(textbuf, newline_off); -+ -+ /* If filled up or OOM, rollback the remaining new -+ * data. Instead we'll try to grab it next time we're -+ * called */ -+ if (textbuf->nr_lines >= textbuf->max_nr_lines || ret < 0) -+ textbuf->used_bytes = newdata_off; -+ -+ if (ret < 0) -+ goto finish; -+ -+ /* Fix up ppos etc in case we'll be ending the loop */ -+ *ppos += ret - newdata_off; -+ bytes_processed += ret - newdata_off; -+ newdata_off = 0; -+ } else { -+ /* there's bytes left, but no new-line, so try to fill up next time */ -+ *ppos += new_bytes_remain; -+ bytes_processed += new_bytes_remain; -+ break; -+ } -+ } -+ -+finish_noerr: -+ ret = bytes_processed; -+finish: -+ textbuf->prev_pos = *ppos; -+out_unlock: -+ mutex_unlock(&textbuf->lock); -+ -+ return ret; -+} -+ -+/** -+ * kutf_helper_textbuf_produce() - 'data' file producer function for reading -+ * from a textbuf -+ * @priv: private pointer from a kutf_userdata_exchange, which -+ * should be a pointer to a struct kutf_helper_textbuf to -+ * read from -+ * @userbuf: the userspace buffer to write to -+ * @userbuf_len: size of the userspace buffer -+ * @ppos: the current position in the buffer -+ * -+ * This producer function is used as a read producer for the 'data' file, -+ * allowing userspace to read from the 'data' file. It will write to the -+ * userspace buffer @userbuf, taking lines from the textbuf pointed to by -+ * @priv, separating each line with '\n'. -+ * -+ * If there is no data in the textbuf, then it will block until some appears - -+ * for example, a kernel-side test calls kutf_helper_textbuf_enqueue(). Since -+ * this is expected to be called in the context of a syscall, the call can only -+ * be cancelled by sending an appropriate signal to the userspace process. -+ * -+ * The current position @ppos is advanced by the number of bytes successfully -+ * written. -+ * -+ * Return: the number of bytes written, or negative value on error -+ */ -+static ssize_t kutf_helper_textbuf_produce(void *priv, char __user *userbuf, -+ size_t userbuf_len, loff_t *ppos) -+{ -+ struct kutf_helper_textbuf *textbuf = priv; -+ loff_t pos_offset; -+ struct kutf_helper_textbuf_line *line = NULL; -+ int line_start_pos; -+ size_t bytes_processed = 0; -+ ssize_t ret; -+ int copy_length; -+ -+ ret = mutex_lock_interruptible(&textbuf->lock); -+ if (ret) -+ return -ERESTARTSYS; -+ -+ /* Validate input */ -+ if (*ppos < 0) { -+ ret = -EINVAL; -+ goto finish; -+ } -+ if (!userbuf_len) { -+ ret = 0; -+ goto finish; -+ } -+ -+ /* Seeking to before the beginning of the line will have the effect of -+ * resetting the position to the start of the current data, since we've -+ * already discarded previous data */ -+ if (*ppos < textbuf->prev_line_pos) -+ textbuf->prev_line_pos = *ppos; -+ -+ while (!line) { -+ int needs_wake = 0; -+ -+ pos_offset = *ppos - textbuf->prev_line_pos; -+ line_start_pos = 0; -+ -+ /* Find the line for the offset, emptying the textbuf as we go */ -+ while (!list_empty(&textbuf->textbuf_list)) { -+ int line_end_pos; -+ -+ line = list_first_entry(&textbuf->textbuf_list, struct kutf_helper_textbuf_line, node); -+ -+ /* str_size used in line_end_pos because lines implicitly have -+ * a '\n', but we count the '\0' string terminator as that */ -+ line_end_pos = line_start_pos + line->str_size; -+ -+ if (pos_offset < line_end_pos) -+ break; -+ -+ line_start_pos += line->str_size; -+ /* Only discard a line when we're sure it's finished -+ * with, to avoid awkward rollback conditions if we've -+ * had to block */ -+ list_del(&line->node); -+ --(textbuf->nr_lines); -+ line = NULL; -+ needs_wake = 1; -+ } -+ -+ /* Update the start of the line pos for next time we're called */ -+ textbuf->prev_line_pos += line_start_pos; -+ -+ /* If space was freed up, wake waiters */ -+ if (needs_wake) -+ wake_up(&textbuf->not_full_wq); -+; -+ if (!line) { -+ /* Only check before waiting, to ensure if the test -+ * does the last enqueue and immediately finishes, then -+ * we'll go back round the loop to receive the line -+ * instead of just dying straight away */ -+ if (textbuf->flags & KUTF_HELPER_TEXTBUF_FLAG_DYING) { -+ /* Indicate EOF rather than an error */ -+ ret = 0; -+ goto finish; -+ } -+ -+ /* No lines found, block for new ones -+ * NOTE: should also handle O_NONBLOCK */ -+ mutex_unlock(&textbuf->lock); -+ ret = wait_event_interruptible(textbuf->not_empty_wq, -+ (textbuf->nr_lines > 0 || -+ (textbuf->flags & KUTF_HELPER_TEXTBUF_FLAG_DYING))); -+ -+ /* signals here are not restartable */ -+ if (ret) -+ return ret; -+ ret = mutex_lock_interruptible(&textbuf->lock); -+ if (ret) -+ return ret; -+ } -+ -+ } -+ -+ -+ /* Find offset within the line, guaranteed to be within line->str_size */ -+ pos_offset -= line_start_pos; -+ -+ while (userbuf_len && line) { -+ /* Copy at most to the end of string, excluding terminator */ -+ copy_length = line->str_size - 1 - pos_offset; -+ if (copy_length > userbuf_len) -+ copy_length = userbuf_len; -+ -+ if (copy_length) { -+ ret = copy_to_user(userbuf, &line->str[pos_offset], copy_length); -+ if (ret == copy_length) { -+ ret = -EFAULT; -+ goto finish; -+ } -+ copy_length -= ret; -+ -+ userbuf += copy_length; -+ userbuf_len -= copy_length; -+ bytes_processed += copy_length; -+ *ppos += copy_length; -+ if (ret) -+ goto finish_noerr; -+ } -+ -+ /* Add terminator if one was needed */ -+ if (userbuf_len) { -+ copy_length = 1; -+ ret = copy_to_user(userbuf, "\n", copy_length); -+ if (ret == copy_length) { -+ ret = -EFAULT; -+ goto finish; -+ } -+ copy_length -= ret; -+ -+ userbuf += copy_length; -+ userbuf_len -= copy_length; -+ bytes_processed += copy_length; -+ *ppos += copy_length; -+ } else { -+ /* string wasn't completely copied this time - try to -+ * finish it next call */ -+ break; -+ } -+ -+ /* Line Completed - only now can safely delete it */ -+ textbuf->prev_line_pos += line->str_size; -+ list_del(&line->node); -+ --(textbuf->nr_lines); -+ line = NULL; -+ /* Space freed up, wake up waiters */ -+ wake_up(&textbuf->not_full_wq); -+ -+ /* Pick the next line */ -+ if (!list_empty(&textbuf->textbuf_list)) { -+ line = list_first_entry(&textbuf->textbuf_list, struct kutf_helper_textbuf_line, node); -+ pos_offset = 0; -+ } -+ /* if no more lines, we've copied at least some bytes, so only -+ * need to block on new lines the next time we're called */ -+ } -+ -+finish_noerr: -+ ret = bytes_processed; -+finish: -+ mutex_unlock(&textbuf->lock); -+ -+ return ret; -+} -+ -+int kutf_helper_textbuf_wait_for_user(struct kutf_helper_textbuf *textbuf) -+{ -+ int err; -+ unsigned long now; -+ unsigned long timeout_jiffies = msecs_to_jiffies(USERDATA_WAIT_TIMEOUT_MS); -+ unsigned long time_end; -+ int ret = 0; -+ -+ /* Mutex locking using non-interruptible variants, since a signal to -+ * the user process will generally have to wait until we finish the -+ * test, because we can't restart the test. The exception is where -+ * we're blocked on a waitq */ -+ mutex_lock(&textbuf->lock); -+ -+ now = jiffies; -+ time_end = now + timeout_jiffies; -+ -+ while (!textbuf->nr_user_clients && time_before_eq(now, time_end)) { -+ unsigned long time_to_wait = time_end - now; -+ /* No users yet, block or timeout */ -+ mutex_unlock(&textbuf->lock); -+ /* Use interruptible here - in case we block for a long time -+ * and want to kill the user process */ -+ err = wait_event_interruptible_timeout(textbuf->user_opened_wq, -+ (textbuf->nr_user_clients > 0), time_to_wait); -+ /* Any error is not restartable due to how kutf runs tests */ -+ if (err < 0) -+ return -EINTR; -+ mutex_lock(&textbuf->lock); -+ -+ now = jiffies; -+ } -+ if (!textbuf->nr_user_clients) -+ ret = -ETIMEDOUT; -+ -+ mutex_unlock(&textbuf->lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_wait_for_user); -+ -+char *kutf_helper_textbuf_dequeue(struct kutf_helper_textbuf *textbuf, -+ int *str_size) -+{ -+ struct kutf_helper_textbuf_line *line; -+ char *ret = NULL; -+ -+ /* Mutex locking using non-interruptible variants, since a signal to -+ * the user process will generally have to wait until we finish the -+ * test, because we can't restart the test. The exception is where -+ * we're blocked on a waitq */ -+ mutex_lock(&textbuf->lock); -+ -+ while (list_empty(&textbuf->textbuf_list)) { -+ int err; -+ -+ if (!textbuf->nr_user_clients) { -+ /* No user-side clients - error */ -+ goto out; -+ } -+ -+ /* No lines found, block for new ones from user-side consumer */ -+ mutex_unlock(&textbuf->lock); -+ /* Use interruptible here - in case we block for a long time -+ * and want to kill the user process */ -+ err = wait_event_interruptible(textbuf->not_empty_wq, -+ (textbuf->nr_lines > 0 || !textbuf->nr_user_clients)); -+ /* Any error is not restartable due to how kutf runs tests */ -+ if (err) -+ return ERR_PTR(-EINTR); -+ mutex_lock(&textbuf->lock); -+ } -+ -+ line = list_first_entry(&textbuf->textbuf_list, struct kutf_helper_textbuf_line, node); -+ list_del(&line->node); -+ --(textbuf->nr_lines); -+ /* Space freed up, wake up waiters */ -+ wake_up(&textbuf->not_full_wq); -+ -+ if (str_size) -+ *str_size = line->str_size; -+ -+ ret = &line->str[0]; -+ -+out: -+ mutex_unlock(&textbuf->lock); -+ return ret; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_dequeue); -+ -+int kutf_helper_textbuf_enqueue(struct kutf_helper_textbuf *textbuf, -+ char *enqueue_str, int buf_max_size) -+{ -+ struct kutf_helper_textbuf_line *textbuf_line; -+ int str_size = strnlen(enqueue_str, buf_max_size) + 1; -+ char *str_start; -+ int ret = 0; -+ -+ /* Mutex locking using non-interruptible variants, since a signal to -+ * the user process will generally have to wait until we finish the -+ * test, because we can't restart the test. The exception is where -+ * we're blocked on a waitq */ -+ mutex_lock(&textbuf->lock); -+ -+ if (str_size > textbuf->max_line_size) -+ str_size = textbuf->max_line_size; -+ -+ while (textbuf->nr_lines >= textbuf->max_nr_lines) { -+ if (!textbuf->nr_user_clients) { -+ /* No user-side clients - error */ -+ ret = -EBUSY; -+ goto out; -+ } -+ -+ /* Block on user-side producer making space available */ -+ mutex_unlock(&textbuf->lock); -+ /* Use interruptible here - in case we block for a long time -+ * and want to kill the user process */ -+ ret = wait_event_interruptible(textbuf->not_full_wq, -+ (textbuf->nr_lines < textbuf->max_nr_lines || !textbuf->nr_user_clients)); -+ /* Any error is not restartable due to how kutf runs tests */ -+ if (ret) -+ return -EINTR; -+ mutex_lock(&textbuf->lock); -+ } -+ -+ /* String is stored immediately after the line */ -+ textbuf_line = kutf_mempool_alloc(textbuf->mempool, str_size + sizeof(struct kutf_helper_textbuf_line)); -+ if (!textbuf_line) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ str_start = &textbuf_line->str[0]; -+ -+ /* Copy in string */ -+ strncpy(str_start, enqueue_str, str_size); -+ /* Enforce the '\0' termination */ -+ str_start[str_size-1] = '\0'; -+ textbuf_line->str_size = str_size; -+ -+ /* Append to the textbuf */ -+ list_add_tail(&textbuf_line->node, &textbuf->textbuf_list); -+ ++(textbuf->nr_lines); -+ -+ /* Wakeup anyone blocked on empty */ -+ wake_up(&textbuf->not_empty_wq); -+ -+out: -+ mutex_unlock(&textbuf->lock); -+ return ret; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_enqueue); -+ -+ -+struct kutf_userdata_ops kutf_helper_textbuf_userdata_ops = { -+ .open = kutf_helper_textbuf_open, -+ .release = kutf_helper_textbuf_release, -+ .notify_ended = kutf_helper_textbuf_notify_test_ended, -+ .consumer = kutf_helper_textbuf_consume, -+ .producer = kutf_helper_textbuf_produce, -+}; -+EXPORT_SYMBOL(kutf_helper_textbuf_userdata_ops); -diff --git a/drivers/gpu/arm/midgard/tests/kutf/kutf_helpers_user.c b/drivers/gpu/arm/midgard/tests/kutf/kutf_helpers_user.c -new file mode 100644 -index 0000000..5c34120 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/kutf_helpers_user.c -@@ -0,0 +1,462 @@ -+/* -+ * -+ * (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* Kernel UTF test helpers that mirror those for kutf-userside */ -+#include -+#include -+ -+#include -+#include -+ -+const char *valtype_names[] = { -+ "INVALID", -+ "U64", -+ "STR", -+}; -+ -+static const char *get_val_type_name(enum kutf_helper_valtype valtype) -+{ -+ /* enums can be signed or unsigned (implementation dependant), so -+ * enforce it to prevent: -+ * a) "<0 comparison on unsigned type" warning - if we did both upper -+ * and lower bound check -+ * b) incorrect range checking if it was a signed type - if we did -+ * upper bound check only */ -+ unsigned int type_idx = (unsigned int)valtype; -+ -+ if (type_idx >= (unsigned int)KUTF_HELPER_VALTYPE_COUNT) -+ type_idx = (unsigned int)KUTF_HELPER_VALTYPE_INVALID; -+ -+ return valtype_names[type_idx]; -+} -+ -+/* Check up to str_len chars of val_str to see if it's a valid value name: -+ * -+ * - Has between 1 and KUTF_HELPER_MAX_VAL_NAME_LEN characters before the \0 terminator -+ * - And, each char is in the character set [A-Z0-9_] */ -+static int validate_val_name(char *val_str, int str_len) -+{ -+ int i = 0; -+ -+ for (i = 0; str_len && i <= KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0'; ++i, --str_len) { -+ char val_chr = val_str[i]; -+ -+ if (val_chr >= 'A' && val_chr <= 'Z') -+ continue; -+ if (val_chr >= '0' && val_chr <= '9') -+ continue; -+ if (val_chr == '_') -+ continue; -+ -+ /* Character not in the set [A-Z0-9_] - report error */ -+ return 1; -+ } -+ -+ /* Names of 0 length are not valid */ -+ if (i == 0) -+ return 1; -+ /* Length greater than KUTF_HELPER_MAX_VAL_NAME_LEN not allowed */ -+ if (i > KUTF_HELPER_MAX_VAL_NAME_LEN || (i == KUTF_HELPER_MAX_VAL_NAME_LEN && val_str[i] != '\0')) -+ return 1; -+ -+ return 0; -+} -+ -+/* Find the length of the valid part of the string when it will be in quotes -+ * e.g. "str" -+ * -+ * That is, before any '\\', '\n' or '"' characters. This is so we don't have -+ * to escape the string */ -+static int find_quoted_string_valid_len(char *str) -+{ -+ char *ptr; -+ const char *check_chars = "\\\n\""; -+ -+ ptr = strpbrk(str, check_chars); -+ if (ptr) -+ return ptr-str; -+ -+ return strlen(str); -+} -+ -+#define MAX_U64_HEX_LEN 16 -+/* (Name size) + ("=0x" size) + (64-bit hex value size) + (terminator) */ -+#define NAMED_U64_VAL_BUF_SZ (KUTF_HELPER_MAX_VAL_NAME_LEN + 3 + MAX_U64_HEX_LEN + 1) -+ -+int kutf_helper_textbuf_send_named_u64(struct kutf_context *context, -+ struct kutf_helper_textbuf *textbuf, char *val_name, u64 val) -+{ -+ int ret = 1; -+ char msgbuf[NAMED_U64_VAL_BUF_SZ]; -+ const char *errmsg = NULL; -+ -+ if (validate_val_name(val_name, KUTF_HELPER_MAX_VAL_NAME_LEN + 1)) { -+ errmsg = kutf_dsprintf(&context->fixture_pool, -+ "Failed to send u64 value named '%s': Invalid value name", val_name); -+ goto out_err; -+ } -+ -+ ret = snprintf(msgbuf, NAMED_U64_VAL_BUF_SZ, "%s=0x%llx", val_name, val); -+ if (ret >= NAMED_U64_VAL_BUF_SZ || ret < 0) { -+ errmsg = kutf_dsprintf(&context->fixture_pool, -+ "Failed to send u64 value named '%s': snprintf() problem buffer size==%d ret=%d", -+ val_name, NAMED_U64_VAL_BUF_SZ, ret); -+ goto out_err; -+ } -+ msgbuf[NAMED_U64_VAL_BUF_SZ-1] = '\0'; -+ -+ ret = kutf_helper_textbuf_enqueue(textbuf, msgbuf, NAMED_U64_VAL_BUF_SZ); -+ if (ret) { -+ errmsg = kutf_dsprintf(&context->fixture_pool, -+ "Failed to send u64 value named '%s': send returned %d", -+ val_name, ret); -+ goto out_err; -+ } -+ -+ return ret; -+out_err: -+ kutf_test_fail(context, errmsg); -+ return ret; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_send_named_u64); -+ -+#define NAMED_VALUE_SEP "=" -+#define NAMED_STR_START_DELIM NAMED_VALUE_SEP "\"" -+#define NAMED_STR_END_DELIM "\"" -+ -+int kutf_helper_textbuf_max_str_len_for_kern(char *val_name, -+ int kern_buf_sz) -+{ -+ int val_name_len = strlen(val_name); -+ int start_delim_len = strlen(NAMED_STR_START_DELIM); -+ int max_msg_len = kern_buf_sz - 1; -+ int max_str_len; -+ -+ /* We do not include the end delimiter. Providing there is a line -+ * ending character when sending the message, the end delimiter can be -+ * truncated off safely to allow proper NAME="value" reception when -+ * value's length is too long */ -+ max_str_len = max_msg_len - val_name_len - start_delim_len; -+ -+ return max_str_len; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_max_str_len_for_kern); -+ -+int kutf_helper_textbuf_send_named_str(struct kutf_context *context, -+ struct kutf_helper_textbuf *textbuf, char *val_name, -+ char *val_str) -+{ -+ int val_str_len; -+ int str_buf_sz; -+ char *str_buf = NULL; -+ int ret = 1; -+ char *copy_ptr; -+ int val_name_len; -+ int start_delim_len = strlen(NAMED_STR_START_DELIM); -+ int end_delim_len = strlen(NAMED_STR_END_DELIM); -+ const char *errmsg = NULL; -+ -+ if (validate_val_name(val_name, KUTF_HELPER_MAX_VAL_NAME_LEN + 1)) { -+ errmsg = kutf_dsprintf(&context->fixture_pool, -+ "Failed to send u64 value named '%s': Invalid value name", val_name); -+ goto out_err; -+ } -+ val_name_len = strlen(val_name); -+ -+ val_str_len = find_quoted_string_valid_len(val_str); -+ -+ /* (name length) + ("=\"" length) + (val_str len) + ("\"" length) + terminator */ -+ str_buf_sz = val_name_len + start_delim_len + val_str_len + end_delim_len + 1; -+ -+ /* Using kmalloc() here instead of mempool since we know we need to free -+ * before we return */ -+ str_buf = kmalloc(str_buf_sz, GFP_KERNEL); -+ if (!str_buf) { -+ errmsg = kutf_dsprintf(&context->fixture_pool, -+ "Failed to send str value named '%s': kmalloc failed, str_buf_sz=%d", -+ val_name, str_buf_sz); -+ goto out_err; -+ } -+ copy_ptr = str_buf; -+ -+ /* Manually copy each string component instead of snprintf because -+ * val_str may need to end early, and less error path handling */ -+ -+ /* name */ -+ memcpy(copy_ptr, val_name, val_name_len); -+ copy_ptr += val_name_len; -+ -+ /* str start delimiter */ -+ memcpy(copy_ptr, NAMED_STR_START_DELIM, start_delim_len); -+ copy_ptr += start_delim_len; -+ -+ /* str value */ -+ memcpy(copy_ptr, val_str, val_str_len); -+ copy_ptr += val_str_len; -+ -+ /* str end delimiter */ -+ memcpy(copy_ptr, NAMED_STR_END_DELIM, end_delim_len); -+ copy_ptr += end_delim_len; -+ -+ /* Terminator */ -+ *copy_ptr = '\0'; -+ -+ ret = kutf_helper_textbuf_enqueue(textbuf, str_buf, str_buf_sz); -+ -+ if (ret) { -+ errmsg = kutf_dsprintf(&context->fixture_pool, -+ "Failed to send str value named '%s': send returned %d", -+ val_name, ret); -+ goto out_err; -+ } -+ -+ kfree(str_buf); -+ return ret; -+ -+out_err: -+ kutf_test_fail(context, errmsg); -+ kfree(str_buf); -+ return ret; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_send_named_str); -+ -+int kutf_helper_textbuf_receive_named_val(struct kutf_helper_named_val *named_val, -+ struct kutf_helper_textbuf *textbuf) -+{ -+ int recv_sz; -+ char *recv_str; -+ char *search_ptr; -+ char *name_str = NULL; -+ int name_len; -+ int strval_len; -+ enum kutf_helper_valtype type = KUTF_HELPER_VALTYPE_INVALID; -+ char *strval = NULL; -+ u64 u64val = 0; -+ int orig_recv_sz; -+ int err = KUTF_HELPER_ERR_INVALID_VALUE; -+ -+ recv_str = kutf_helper_textbuf_dequeue(textbuf, &recv_sz); -+ if (!recv_str) -+ return -EBUSY; -+ else if (IS_ERR(recv_str)) -+ return PTR_ERR(recv_str); -+ orig_recv_sz = recv_sz; -+ -+ /* Find the '=', grab the name and validate it */ -+ search_ptr = strnchr(recv_str, recv_sz, NAMED_VALUE_SEP[0]); -+ if (search_ptr) { -+ name_len = search_ptr - recv_str; -+ if (!validate_val_name(recv_str, name_len)) { -+ /* no need to reallocate - just modify string in place */ -+ name_str = recv_str; -+ name_str[name_len] = '\0'; -+ -+ /* Move until after the '=' */ -+ recv_str += (name_len + 1); -+ recv_sz -= (name_len + 1); -+ } -+ } -+ if (!name_str) { -+ pr_err("Invalid name part for recevied string '%s'\n", recv_str); -+ return KUTF_HELPER_ERR_INVALID_NAME; -+ } -+ -+ /* detect value type */ -+ if (*recv_str == NAMED_STR_START_DELIM[1]) { -+ /* string delimiter start*/ -+ ++recv_str; -+ --recv_sz; -+ -+ /* Find end of string */ -+ search_ptr = strnchr(recv_str, recv_sz, NAMED_STR_END_DELIM[0]); -+ if (search_ptr) { -+ strval_len = search_ptr - recv_str; -+ /* Validate the string to ensure it contains no quotes */ -+ if (strval_len == find_quoted_string_valid_len(recv_str)) { -+ /* no need to reallocate - just modify string in place */ -+ strval = recv_str; -+ strval[strval_len] = '\0'; -+ -+ /* Move until after the end delimiter */ -+ recv_str += (strval_len + 1); -+ recv_sz -= (strval_len + 1); -+ type = KUTF_HELPER_VALTYPE_STR; -+ } else { -+ pr_err("String value contains invalid characters in rest of received string '%s'\n", recv_str); -+ err = KUTF_HELPER_ERR_CHARS_AFTER_VAL; -+ } -+ } else if (orig_recv_sz == textbuf->max_line_size) { -+ /* No end-delimiter found, but the line is at -+ * the max line size. Assume that before -+ * truncation the line had a closing delimiter -+ * anyway */ -+ strval_len = strlen(recv_str); -+ /* Validate the string to ensure it contains no quotes */ -+ if (strval_len == find_quoted_string_valid_len(recv_str)) { -+ strval = recv_str; -+ -+ /* Move to the end of the string */ -+ recv_str += strval_len; -+ recv_sz -= strval_len; -+ type = KUTF_HELPER_VALTYPE_STR; -+ } else { -+ pr_err("String value contains invalid characters in rest of received string '%s'\n", recv_str); -+ err = KUTF_HELPER_ERR_CHARS_AFTER_VAL; -+ } -+ } else { -+ pr_err("End of string delimiter not found in rest of received string '%s'\n", recv_str); -+ err = KUTF_HELPER_ERR_NO_END_DELIMITER; -+ } -+ } else { -+ int err; -+ /* possibly a number value - strtoull will parse it */ -+ err = kstrtoull(recv_str, 0, &u64val); -+ /* unlike userspace can't get an end ptr, but if kstrtoull() -+ * reads characters after the number it'll report -EINVAL */ -+ if (!err) { -+ int len_remain = strnlen(recv_str, recv_sz); -+ -+ type = KUTF_HELPER_VALTYPE_U64; -+ recv_str += len_remain; -+ recv_sz -= len_remain; -+ } else { -+ /* special case: not a number, report as such */ -+ pr_err("Rest of received string was not a numeric value or quoted string value: '%s'\n", recv_str); -+ err = KUTF_HELPER_ERR_INVALID_VALUE; -+ } -+ } -+ -+ if (type == KUTF_HELPER_VALTYPE_INVALID) -+ return err; -+ -+ /* Any remaining characters - error */ -+ if (strnlen(recv_str, recv_sz) != 0) { -+ pr_err("Characters remain after value of type %s: '%s'\n", -+ get_val_type_name(type), recv_str); -+ return KUTF_HELPER_ERR_CHARS_AFTER_VAL; -+ } -+ -+ /* Success - write into the output structure */ -+ switch (type) { -+ case KUTF_HELPER_VALTYPE_U64: -+ named_val->u.val_u64 = u64val; -+ break; -+ case KUTF_HELPER_VALTYPE_STR: -+ named_val->u.val_str = strval; -+ break; -+ default: -+ pr_err("Unreachable, fix textbuf_receive_named_val\n"); -+ /* Coding error, report as though 'data' file failed */ -+ return -EINVAL; -+ } -+ -+ named_val->val_name = name_str; -+ named_val->type = type; -+ -+ return KUTF_HELPER_ERR_NONE; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_receive_named_val); -+ -+#define DUMMY_MSG "" -+int kutf_helper_textbuf_receive_check_val(struct kutf_helper_named_val *named_val, -+ struct kutf_context *context, struct kutf_helper_textbuf *textbuf, -+ char *expect_val_name, enum kutf_helper_valtype expect_val_type) -+{ -+ int err; -+ -+ err = kutf_helper_textbuf_receive_named_val(named_val, textbuf); -+ if (err < 0) { -+ const char *msg = kutf_dsprintf(&context->fixture_pool, -+ "Failed to receive value named '%s'", -+ expect_val_name); -+ kutf_test_fail(context, msg); -+ return err; -+ } else if (err > 0) { -+ const char *msg = kutf_dsprintf(&context->fixture_pool, -+ "Named-value parse error when expecting value named '%s'", -+ expect_val_name); -+ kutf_test_fail(context, msg); -+ goto out_fail_and_fixup; -+ } -+ -+ if (strcmp(named_val->val_name, expect_val_name) != 0) { -+ const char *msg = kutf_dsprintf(&context->fixture_pool, -+ "Expecting to receive value named '%s' but got '%s'", -+ expect_val_name, named_val->val_name); -+ kutf_test_fail(context, msg); -+ goto out_fail_and_fixup; -+ } -+ -+ -+ if (named_val->type != expect_val_type) { -+ const char *msg = kutf_dsprintf(&context->fixture_pool, -+ "Expecting value named '%s' to be of type %s but got %s", -+ expect_val_name, get_val_type_name(expect_val_type), -+ get_val_type_name(named_val->type)); -+ kutf_test_fail(context, msg); -+ goto out_fail_and_fixup; -+ } -+ -+ return err; -+ -+out_fail_and_fixup: -+ /* Produce a valid but incorrect value */ -+ switch (expect_val_type) { -+ case KUTF_HELPER_VALTYPE_U64: -+ named_val->u.val_u64 = 0ull; -+ break; -+ case KUTF_HELPER_VALTYPE_STR: -+ { -+ char *str = kutf_mempool_alloc(&context->fixture_pool, sizeof(DUMMY_MSG)); -+ -+ if (!str) -+ return -1; -+ -+ strcpy(str, DUMMY_MSG); -+ named_val->u.val_str = str; -+ break; -+ } -+ default: -+ break; -+ } -+ -+ /* Indicate that this is invalid */ -+ named_val->type = KUTF_HELPER_VALTYPE_INVALID; -+ -+ /* But at least allow the caller to continue in the test with failures */ -+ return 0; -+} -+EXPORT_SYMBOL(kutf_helper_textbuf_receive_check_val); -+ -+void kutf_helper_output_named_val(struct kutf_helper_named_val *named_val) -+{ -+ switch (named_val->type) { -+ case KUTF_HELPER_VALTYPE_U64: -+ pr_warn("%s=0x%llx\n", named_val->val_name, named_val->u.val_u64); -+ break; -+ case KUTF_HELPER_VALTYPE_STR: -+ pr_warn("%s=\"%s\"\n", named_val->val_name, named_val->u.val_str); -+ break; -+ case KUTF_HELPER_VALTYPE_INVALID: -+ pr_warn("%s is invalid\n", named_val->val_name); -+ break; -+ default: -+ pr_warn("%s has unknown type %d\n", named_val->val_name, named_val->type); -+ break; -+ } -+} -+EXPORT_SYMBOL(kutf_helper_output_named_val); -diff --git a/drivers/gpu/arm/midgard/tests/kutf/kutf_mem.c b/drivers/gpu/arm/midgard/tests/kutf/kutf_mem.c -new file mode 100644 -index 0000000..a75e15f ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/kutf_mem.c -@@ -0,0 +1,102 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* Kernel UTF memory management functions */ -+ -+#include -+#include -+ -+#include -+ -+ -+/** -+ * struct kutf_alloc_entry - Structure representing an allocation. -+ * @node: List node for use with kutf_mempool. -+ * @data: Data area of the allocation -+ */ -+struct kutf_alloc_entry { -+ struct list_head node; -+ u8 data[0]; -+}; -+ -+int kutf_mempool_init(struct kutf_mempool *pool) -+{ -+ if (!pool) { -+ pr_err("NULL pointer passed to %s\n", __func__); -+ return -1; -+ } -+ -+ INIT_LIST_HEAD(&pool->head); -+ mutex_init(&pool->lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(kutf_mempool_init); -+ -+void kutf_mempool_destroy(struct kutf_mempool *pool) -+{ -+ struct list_head *remove; -+ struct list_head *tmp; -+ -+ if (!pool) { -+ pr_err("NULL pointer passed to %s\n", __func__); -+ return; -+ } -+ -+ mutex_lock(&pool->lock); -+ list_for_each_safe(remove, tmp, &pool->head) { -+ struct kutf_alloc_entry *remove_alloc; -+ -+ remove_alloc = list_entry(remove, struct kutf_alloc_entry, node); -+ list_del(&remove_alloc->node); -+ kfree(remove_alloc); -+ } -+ mutex_unlock(&pool->lock); -+ -+} -+EXPORT_SYMBOL(kutf_mempool_destroy); -+ -+void *kutf_mempool_alloc(struct kutf_mempool *pool, size_t size) -+{ -+ struct kutf_alloc_entry *ret; -+ -+ if (!pool) { -+ pr_err("NULL pointer passed to %s\n", __func__); -+ goto fail_pool; -+ } -+ -+ mutex_lock(&pool->lock); -+ -+ ret = kmalloc(sizeof(*ret) + size, GFP_KERNEL); -+ if (!ret) { -+ pr_err("Failed to allocate memory\n"); -+ goto fail_alloc; -+ } -+ -+ INIT_LIST_HEAD(&ret->node); -+ list_add(&ret->node, &pool->head); -+ -+ mutex_unlock(&pool->lock); -+ -+ return &ret->data[0]; -+ -+fail_alloc: -+ mutex_unlock(&pool->lock); -+fail_pool: -+ return NULL; -+} -+EXPORT_SYMBOL(kutf_mempool_alloc); -diff --git a/drivers/gpu/arm/midgard/tests/kutf/kutf_resultset.c b/drivers/gpu/arm/midgard/tests/kutf/kutf_resultset.c -new file mode 100644 -index 0000000..5bd0496 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/kutf_resultset.c -@@ -0,0 +1,95 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* Kernel UTF result management functions */ -+ -+#include -+#include -+#include -+ -+#include -+ -+/** -+ * struct kutf_result_set - Represents a set of results. -+ * @results: Pointer to the linked list where the results are stored. -+ */ -+struct kutf_result_set { -+ struct list_head results; -+}; -+ -+struct kutf_result_set *kutf_create_result_set(void) -+{ -+ struct kutf_result_set *set; -+ -+ set = kmalloc(sizeof(*set), GFP_KERNEL); -+ if (!set) { -+ pr_err("Failed to allocate resultset"); -+ goto fail_alloc; -+ } -+ -+ INIT_LIST_HEAD(&set->results); -+ -+ return set; -+ -+fail_alloc: -+ return NULL; -+} -+ -+void kutf_add_result(struct kutf_mempool *mempool, -+ struct kutf_result_set *set, -+ enum kutf_result_status status, -+ const char *message) -+{ -+ /* Create the new result */ -+ struct kutf_result *new_result; -+ -+ BUG_ON(set == NULL); -+ -+ new_result = kutf_mempool_alloc(mempool, sizeof(*new_result)); -+ if (!new_result) { -+ pr_err("Result allocation failed\n"); -+ return; -+ } -+ -+ INIT_LIST_HEAD(&new_result->node); -+ new_result->status = status; -+ new_result->message = message; -+ -+ list_add_tail(&new_result->node, &set->results); -+} -+ -+void kutf_destroy_result_set(struct kutf_result_set *set) -+{ -+ if (!list_empty(&set->results)) -+ pr_err("kutf_destroy_result_set: Unread results from test\n"); -+ -+ kfree(set); -+} -+ -+struct kutf_result *kutf_remove_result(struct kutf_result_set *set) -+{ -+ if (!list_empty(&set->results)) { -+ struct kutf_result *ret; -+ -+ ret = list_first_entry(&set->results, struct kutf_result, node); -+ list_del(&ret->node); -+ return ret; -+ } -+ -+ return NULL; -+} -+ -diff --git a/drivers/gpu/arm/midgard/tests/kutf/kutf_suite.c b/drivers/gpu/arm/midgard/tests/kutf/kutf_suite.c -new file mode 100644 -index 0000000..ad30cc8 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/kutf_suite.c -@@ -0,0 +1,1398 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* Kernel UTF suite, test and fixture management including user to kernel -+ * interaction */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+ -+#if defined(CONFIG_DEBUG_FS) -+ -+/** -+ * struct kutf_application - Structure which represents kutf application -+ * @name: The name of this test application. -+ * @dir: The debugfs directory for this test -+ * @suite_list: List head to store all the suites which are part of this -+ * application -+ */ -+struct kutf_application { -+ const char *name; -+ struct dentry *dir; -+ struct list_head suite_list; -+}; -+ -+/** -+ * struct kutf_test_function - Structure which represents kutf test function -+ * @suite: Back reference to the suite this test function -+ * belongs to -+ * @filters: Filters that apply to this test function -+ * @test_id: Test ID -+ * @execute: Function to run for this test -+ * @test_data: Static data for this test -+ * @node: List node for test_list -+ * @variant_list: List head to store all the variants which can run on -+ * this function -+ * @dir: debugfs directory for this test function -+ * @userdata_ops: Callbacks to use for sending and receiving data to -+ * userspace. -+ */ -+struct kutf_test_function { -+ struct kutf_suite *suite; -+ unsigned int filters; -+ unsigned int test_id; -+ void (*execute)(struct kutf_context *context); -+ union kutf_callback_data test_data; -+ struct list_head node; -+ struct list_head variant_list; -+ struct dentry *dir; -+ struct kutf_userdata_ops userdata_ops; -+}; -+ -+/** -+ * struct kutf_test_fixture - Structure which holds information on the kutf -+ * test fixture -+ * @test_func: Test function this fixture belongs to -+ * @fixture_index: Index of this fixture -+ * @node: List node for variant_list -+ * @dir: debugfs directory for this test fixture -+ * @nr_running: Current count of user-clients running this fixture -+ */ -+struct kutf_test_fixture { -+ struct kutf_test_function *test_func; -+ unsigned int fixture_index; -+ struct list_head node; -+ struct dentry *dir; -+ atomic_t nr_running; -+}; -+ -+struct dentry *base_dir; -+ -+/** -+ * struct kutf_convert_table - Structure which keeps test results -+ * @result_name: Status of the test result -+ * @result: Status value for a single test -+ */ -+struct kutf_convert_table { -+ char result_name[50]; -+ enum kutf_result_status result; -+}; -+ -+struct kutf_convert_table kutf_convert[] = { -+#define ADD_UTF_RESULT(_name) \ -+{ \ -+ #_name, \ -+ _name, \ -+}, -+ADD_UTF_RESULT(KUTF_RESULT_BENCHMARK) -+ADD_UTF_RESULT(KUTF_RESULT_SKIP) -+ADD_UTF_RESULT(KUTF_RESULT_UNKNOWN) -+ADD_UTF_RESULT(KUTF_RESULT_PASS) -+ADD_UTF_RESULT(KUTF_RESULT_DEBUG) -+ADD_UTF_RESULT(KUTF_RESULT_INFO) -+ADD_UTF_RESULT(KUTF_RESULT_WARN) -+ADD_UTF_RESULT(KUTF_RESULT_FAIL) -+ADD_UTF_RESULT(KUTF_RESULT_FATAL) -+ADD_UTF_RESULT(KUTF_RESULT_ABORT) -+}; -+ -+#define UTF_CONVERT_SIZE (ARRAY_SIZE(kutf_convert)) -+ -+/** -+ * kutf_create_context() - Create a test context in which a specific fixture -+ * of an application will be run and its results -+ * reported back to the user -+ * @test_fix: Test fixture to be run. -+ * -+ * The context's refcount will be initialized to 1. -+ * -+ * Return: Returns the created test context on success or NULL on failure -+ */ -+static struct kutf_context *kutf_create_context( -+ struct kutf_test_fixture *test_fix); -+ -+/** -+ * kutf_destroy_context() - Destroy a previously created test context, only -+ * once its refcount has become zero -+ * @kref: pointer to kref member within the context -+ * -+ * This should only be used via a kref_put() call on the context's kref member -+ */ -+static void kutf_destroy_context(struct kref *kref); -+ -+/** -+ * kutf_context_get() - increment refcount on a context -+ * @context: the kutf context -+ * -+ * This must be used when the lifetime of the context might exceed that of the -+ * thread creating @context -+ */ -+static void kutf_context_get(struct kutf_context *context); -+ -+/** -+ * kutf_context_put() - decrement refcount on a context, destroying it when it -+ * reached zero -+ * @context: the kutf context -+ * -+ * This must be used only after a corresponding kutf_context_get() call on -+ * @context, and the caller no longer needs access to @context. -+ */ -+static void kutf_context_put(struct kutf_context *context); -+ -+/** -+ * kutf_set_result() - Set the test result against the specified test context -+ * @context: Test context -+ * @status: Result status -+ */ -+static void kutf_set_result(struct kutf_context *context, -+ enum kutf_result_status status); -+ -+/** -+ * kutf_set_expected_result() - Set the expected test result for the specified -+ * test context -+ * @context: Test context -+ * @expected_status: Expected result status -+ */ -+static void kutf_set_expected_result(struct kutf_context *context, -+ enum kutf_result_status expected_status); -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) -+/* Pre 3.4.0 kernels don't have the simple_open helper */ -+ -+/** -+ * simple_open() - Helper for file opening which stores the inode private data -+ * into the file private data -+ * @inode: File entry representation -+ * @file: A specific opening of the file -+ * -+ * Return: always 0; if inode private data do not exist, the file will not -+ * be assigned private data -+ */ -+static int simple_open(struct inode *inode, struct file *file) -+{ -+ if (inode->i_private) -+ file->private_data = inode->i_private; -+ return 0; -+} -+#endif -+ -+/** -+ * kutf_result_to_string() - Converts a KUTF result into a string -+ * @result_str: Output result string -+ * @result: Result status to convert -+ * -+ * Return: 1 if test result was successfully converted to string, 0 otherwise -+ */ -+static int kutf_result_to_string(char **result_str, -+ enum kutf_result_status result) -+{ -+ int i; -+ int ret = 0; -+ -+ for (i = 0; i < UTF_CONVERT_SIZE; i++) { -+ if (result == kutf_convert[i].result) { -+ *result_str = kutf_convert[i].result_name; -+ ret = 1; -+ } -+ } -+ return ret; -+} -+ -+/** -+ * kutf_debugfs_const_string_read() - Simple debugfs read callback which -+ * returns a constant string -+ * @file: Opened file to read from -+ * @buf: User buffer to write the data into -+ * @len: Amount of data to read -+ * @ppos: Offset into file to read from -+ * -+ * Return: On success, the number of bytes read and offset @ppos advanced by -+ * this number; on error, negative value -+ */ -+static ssize_t kutf_debugfs_const_string_read(struct file *file, -+ char __user *buf, size_t len, loff_t *ppos) -+{ -+ char *str = file->private_data; -+ -+ return simple_read_from_buffer(buf, len, ppos, str, strlen(str)); -+} -+ -+static const struct file_operations kutf_debugfs_const_string_ops = { -+ .owner = THIS_MODULE, -+ .open = simple_open, -+ .read = kutf_debugfs_const_string_read, -+ .llseek = default_llseek, -+}; -+ -+/** -+ * kutf_debugfs_data_open() Debugfs open callback for the "data" entry. -+ * @inode: inode of the opened file -+ * @file: Opened file to read from -+ * -+ * This function notifies the userdata callbacks that the userdata file has -+ * been opened, for tracking purposes. -+ * -+ * It is called on both the context's userdata_consumer_priv and -+ * userdata_producer_priv. -+ * -+ * This takes a refcount on the kutf_context -+ * -+ * Return: 0 on success -+ */ -+static int kutf_debugfs_data_open(struct inode *inode, struct file *file) -+{ -+ struct kutf_context *test_context = inode->i_private; -+ struct kutf_test_fixture *test_fix = test_context->test_fix; -+ struct kutf_test_function *test_func = test_fix->test_func; -+ int err; -+ -+ simple_open(inode, file); -+ -+ /* This is not an error */ -+ if (!test_func->userdata_ops.open) -+ goto out_no_ops; -+ -+ /* This is safe here - the 'data' file is only openable whilst the -+ * initial refcount is still present, and the initial refcount is only -+ * dropped strictly after the 'data' file is removed */ -+ kutf_context_get(test_context); -+ -+ if (test_context->userdata_consumer_priv) { -+ err = test_func->userdata_ops.open(test_context->userdata_consumer_priv); -+ if (err) -+ goto out_consumer_fail; -+ } -+ -+ if (test_context->userdata_producer_priv) { -+ err = test_func->userdata_ops.open(test_context->userdata_producer_priv); -+ if (err) -+ goto out_producer_fail; -+ } -+ -+out_no_ops: -+ return 0; -+ -+out_producer_fail: -+ if (test_func->userdata_ops.release && test_context->userdata_consumer_priv) -+ test_func->userdata_ops.release(test_context->userdata_consumer_priv); -+out_consumer_fail: -+ kutf_context_put(test_context); -+ -+ return err; -+} -+ -+ -+/** -+ * kutf_debugfs_data_read() Debugfs read callback for the "data" entry. -+ * @file: Opened file to read from -+ * @buf: User buffer to write the data into -+ * @len: Amount of data to read -+ * @ppos: Offset into file to read from -+ * -+ * This function allows user and kernel to exchange extra data necessary for -+ * the test fixture. -+ * -+ * The data is read from the first struct kutf_context running the fixture -+ * -+ * Return: Number of bytes read -+ */ -+static ssize_t kutf_debugfs_data_read(struct file *file, char __user *buf, -+ size_t len, loff_t *ppos) -+{ -+ struct kutf_context *test_context = file->private_data; -+ struct kutf_test_fixture *test_fix = test_context->test_fix; -+ struct kutf_test_function *test_func = test_fix->test_func; -+ ssize_t (*producer)(void *private, char __user *userbuf, -+ size_t userbuf_len, loff_t *ppos); -+ ssize_t count; -+ -+ producer = test_func->userdata_ops.producer; -+ /* Can only read if there's a producer callback */ -+ if (!producer) -+ return -ENODEV; -+ -+ count = producer(test_context->userdata_producer_priv, buf, len, ppos); -+ -+ return count; -+} -+ -+/** -+ * kutf_debugfs_data_write() Debugfs write callback for the "data" entry. -+ * @file: Opened file to write to -+ * @buf: User buffer to read the data from -+ * @len: Amount of data to write -+ * @ppos: Offset into file to write to -+ * -+ * This function allows user and kernel to exchange extra data necessary for -+ * the test fixture. -+ * -+ * The data is added to the first struct kutf_context running the fixture -+ * -+ * Return: Number of bytes written -+ */ -+static ssize_t kutf_debugfs_data_write(struct file *file, -+ const char __user *buf, size_t len, loff_t *ppos) -+{ -+ struct kutf_context *test_context = file->private_data; -+ struct kutf_test_fixture *test_fix = test_context->test_fix; -+ struct kutf_test_function *test_func = test_fix->test_func; -+ ssize_t (*consumer)(void *private, const char __user *userbuf, -+ size_t userbuf_len, loff_t *ppos); -+ ssize_t count; -+ -+ consumer = test_func->userdata_ops.consumer; -+ /* Can only write if there's a consumer callback */ -+ if (!consumer) -+ return -ENODEV; -+ -+ count = consumer(test_context->userdata_consumer_priv, buf, len, ppos); -+ -+ return count; -+} -+ -+ -+/** -+ * kutf_debugfs_data_release() - Debugfs release callback for the "data" entry. -+ * @inode: File entry representation -+ * @file: A specific opening of the file -+ * -+ * This function notifies the userdata callbacks that the userdata file has -+ * been closed, for tracking purposes. -+ * -+ * It is called on both the context's userdata_consumer_priv and -+ * userdata_producer_priv. -+ * -+ * It also drops the refcount on the kutf_context that was taken during -+ * kutf_debugfs_data_open() -+ */ -+static int kutf_debugfs_data_release(struct inode *inode, struct file *file) -+{ -+ struct kutf_context *test_context = file->private_data; -+ struct kutf_test_fixture *test_fix = test_context->test_fix; -+ struct kutf_test_function *test_func = test_fix->test_func; -+ -+ if (!test_func->userdata_ops.release) -+ return 0; -+ -+ if (test_context->userdata_consumer_priv) -+ test_func->userdata_ops.release(test_context->userdata_consumer_priv); -+ if (test_context->userdata_producer_priv) -+ test_func->userdata_ops.release(test_context->userdata_producer_priv); -+ -+ kutf_context_put(test_context); -+ -+ return 0; -+} -+ -+ -+static const struct file_operations kutf_debugfs_data_ops = { -+ .owner = THIS_MODULE, -+ .open = kutf_debugfs_data_open, -+ .read = kutf_debugfs_data_read, -+ .write = kutf_debugfs_data_write, -+ .release = kutf_debugfs_data_release, -+ .llseek = default_llseek, -+}; -+ -+/** -+ * userdata_init() - Initialize userspace data exchange for a test, if -+ * specified by that test -+ * @test_context: Test context -+ * -+ * Note that this allows new refcounts to be made on test_context by userspace -+ * threads opening the 'data' file. -+ * -+ * Return: 0 on success, negative value corresponding to error code in failure -+ * and kutf result will be set appropriately to indicate the error -+ */ -+static int userdata_init(struct kutf_context *test_context) -+{ -+ struct kutf_test_fixture *test_fix = test_context->test_fix; -+ struct kutf_test_function *test_func = test_fix->test_func; -+ int err = 0; -+ struct dentry *userdata_dentry; -+ -+ /* Valid to have neither a producer or consumer, which is the case for -+ * tests not requiring usersdata */ -+ if ((!test_func->userdata_ops.consumer) && (!test_func->userdata_ops.producer)) -+ return err; -+ -+ if (test_func->userdata_ops.consumer && !test_context->userdata_consumer_priv) { -+ kutf_test_fatal(test_context, -+ "incorrect test setup - userdata consumer provided without private data"); -+ return -EFAULT; -+ } -+ -+ if (test_func->userdata_ops.producer && !test_context->userdata_producer_priv) { -+ kutf_test_fatal(test_context, -+ "incorrect test setup - userdata producer provided without private data"); -+ return -EFAULT; -+ } -+ -+ userdata_dentry = debugfs_create_file("data", S_IROTH, test_fix->dir, -+ test_context, &kutf_debugfs_data_ops); -+ -+ if (!userdata_dentry) { -+ pr_err("Failed to create debugfs file \"data\" when running fixture\n"); -+ /* Not using Fatal (which stops other tests running), -+ * nor Abort (which indicates teardown should not be done) */ -+ kutf_test_fail(test_context, -+ "failed to create 'data' file for userside data exchange"); -+ -+ /* Error code is discarded by caller, but consistent with other -+ * debugfs_create_file failures */ -+ err = -EEXIST; -+ } else { -+ test_context->userdata_dentry = userdata_dentry; -+ } -+ -+ -+ return err; -+} -+ -+/** -+ * userdata_term() - Terminate userspace data exchange for a test, if specified -+ * by that test -+ * @test_context: Test context -+ * -+ * Note This also prevents new refcounts being made on @test_context by userspace -+ * threads opening the 'data' file for this test. Any existing open file descriptors -+ * to the 'data' file will still be safe to use by userspace. -+ */ -+static void userdata_term(struct kutf_context *test_context) -+{ -+ struct kutf_test_fixture *test_fix = test_context->test_fix; -+ struct kutf_test_function *test_func = test_fix->test_func; -+ void (*notify_ended)(void *priv) = test_func->userdata_ops.notify_ended; -+ -+ /* debugfs_remove() is safe when parameter is error or NULL */ -+ debugfs_remove(test_context->userdata_dentry); -+ -+ /* debugfs_remove() doesn't kill any currently open file descriptors on -+ * this file, and such fds are still safe to use providing test_context -+ * is properly refcounted */ -+ -+ if (notify_ended) { -+ if (test_context->userdata_consumer_priv) -+ notify_ended(test_context->userdata_consumer_priv); -+ if (test_context->userdata_producer_priv) -+ notify_ended(test_context->userdata_producer_priv); -+ } -+ -+} -+ -+/** -+ * kutf_add_explicit_result() - Check if an explicit result needs to be added -+ * @context: KUTF test context -+ */ -+static void kutf_add_explicit_result(struct kutf_context *context) -+{ -+ switch (context->expected_status) { -+ case KUTF_RESULT_UNKNOWN: -+ if (context->status == KUTF_RESULT_UNKNOWN) -+ kutf_test_pass(context, "(implicit pass)"); -+ break; -+ -+ case KUTF_RESULT_WARN: -+ if (context->status == KUTF_RESULT_WARN) -+ kutf_test_pass(context, -+ "Pass (expected warn occurred)"); -+ else if (context->status != KUTF_RESULT_SKIP) -+ kutf_test_fail(context, -+ "Fail (expected warn missing)"); -+ break; -+ -+ case KUTF_RESULT_FAIL: -+ if (context->status == KUTF_RESULT_FAIL) -+ kutf_test_pass(context, -+ "Pass (expected fail occurred)"); -+ else if (context->status != KUTF_RESULT_SKIP) { -+ /* Force the expected status so the fail gets logged */ -+ context->expected_status = KUTF_RESULT_PASS; -+ kutf_test_fail(context, -+ "Fail (expected fail missing)"); -+ } -+ break; -+ -+ case KUTF_RESULT_FATAL: -+ if (context->status == KUTF_RESULT_FATAL) -+ kutf_test_pass(context, -+ "Pass (expected fatal occurred)"); -+ else if (context->status != KUTF_RESULT_SKIP) -+ kutf_test_fail(context, -+ "Fail (expected fatal missing)"); -+ break; -+ -+ case KUTF_RESULT_ABORT: -+ if (context->status == KUTF_RESULT_ABORT) -+ kutf_test_pass(context, -+ "Pass (expected abort occurred)"); -+ else if (context->status != KUTF_RESULT_SKIP) -+ kutf_test_fail(context, -+ "Fail (expected abort missing)"); -+ break; -+ default: -+ break; -+ } -+} -+ -+/** -+ * kutf_debugfs_run_open() Debugfs open callback for the "run" entry. -+ * @inode: inode of the opened file -+ * @file: Opened file to read from -+ * -+ * This function retrieves the test fixture data that is associated with the -+ * opened file and works back to get the test, suite and application so -+ * it can then run the test that is associated with the file entry. -+ * -+ * Return: 0 on success -+ */ -+static int kutf_debugfs_run_open(struct inode *inode, struct file *file) -+{ -+ struct kutf_test_fixture *test_fix = inode->i_private; -+ struct kutf_test_function *test_func = test_fix->test_func; -+ struct kutf_suite *suite = test_func->suite; -+ struct kutf_context *test_context; -+ int err = 0; -+ -+ /* For the moment, only one user-client should be attempting to run -+ * this at a time. This simplifies how we lookup the kutf_context when -+ * using the 'data' file. -+ * Removing this restriction would require a rewrite of the mechanism -+ * of the 'data' file to pass data in, perhaps 'data' created here and -+ * based upon userspace thread's pid */ -+ if (atomic_inc_return(&test_fix->nr_running) != 1) { -+ err = -EBUSY; -+ goto finish; -+ } -+ -+ test_context = kutf_create_context(test_fix); -+ if (!test_context) { -+ err = -ENODEV; -+ goto finish; -+ } -+ -+ file->private_data = test_context; -+ -+ /* -+ * Call the create fixture function if required before the -+ * fixture is run -+ */ -+ if (suite->create_fixture) -+ test_context->fixture = suite->create_fixture(test_context); -+ -+ /* Only run the test if the fixture was created (if required) */ -+ if ((suite->create_fixture && test_context->fixture) || -+ (!suite->create_fixture)) { -+ int late_err; -+ /* Setup any userdata exchange */ -+ late_err = userdata_init(test_context); -+ -+ if (!late_err) -+ /* Run this fixture */ -+ test_func->execute(test_context); -+ -+ userdata_term(test_context); -+ -+ if (suite->remove_fixture) -+ suite->remove_fixture(test_context); -+ -+ kutf_add_explicit_result(test_context); -+ } -+ -+finish: -+ atomic_dec(&test_fix->nr_running); -+ return err; -+} -+ -+/** -+ * kutf_debugfs_run_read() - Debugfs read callback for the "run" entry. -+ * @file: Opened file to read from -+ * @buf: User buffer to write the data into -+ * @len: Amount of data to read -+ * @ppos: Offset into file to read from -+ * -+ * This function emits the results which where logged during the opening of -+ * the file kutf_debugfs_run_open. -+ * Results will be emitted one at a time, once all the results have been read -+ * 0 will be returned to indicate there is no more data. -+ * -+ * Return: Number of bytes read. -+ */ -+static ssize_t kutf_debugfs_run_read(struct file *file, char __user *buf, -+ size_t len, loff_t *ppos) -+{ -+ struct kutf_context *test_context = file->private_data; -+ struct kutf_result *res; -+ unsigned long bytes_not_copied; -+ ssize_t bytes_copied = 0; -+ -+ /* Note: This code assumes a result is read completely */ -+ res = kutf_remove_result(test_context->result_set); -+ if (res) { -+ char *kutf_str_ptr = NULL; -+ unsigned int kutf_str_len = 0; -+ unsigned int message_len = 0; -+ char separator = ':'; -+ char terminator = '\n'; -+ -+ kutf_result_to_string(&kutf_str_ptr, res->status); -+ if (kutf_str_ptr) -+ kutf_str_len = strlen(kutf_str_ptr); -+ -+ if (res->message) -+ message_len = strlen(res->message); -+ -+ if ((kutf_str_len + 1 + message_len + 1) > len) { -+ pr_err("Not enough space in user buffer for a single result"); -+ return 0; -+ } -+ -+ /* First copy the result string */ -+ if (kutf_str_ptr) { -+ bytes_not_copied = copy_to_user(&buf[0], kutf_str_ptr, -+ kutf_str_len); -+ bytes_copied += kutf_str_len - bytes_not_copied; -+ if (bytes_not_copied) -+ goto exit; -+ } -+ -+ /* Then the separator */ -+ bytes_not_copied = copy_to_user(&buf[bytes_copied], -+ &separator, 1); -+ bytes_copied += 1 - bytes_not_copied; -+ if (bytes_not_copied) -+ goto exit; -+ -+ /* Finally Next copy the result string */ -+ if (res->message) { -+ bytes_not_copied = copy_to_user(&buf[bytes_copied], -+ res->message, message_len); -+ bytes_copied += message_len - bytes_not_copied; -+ if (bytes_not_copied) -+ goto exit; -+ } -+ -+ /* Finally the terminator */ -+ bytes_not_copied = copy_to_user(&buf[bytes_copied], -+ &terminator, 1); -+ bytes_copied += 1 - bytes_not_copied; -+ } -+exit: -+ return bytes_copied; -+} -+ -+/** -+ * kutf_debugfs_run_release() - Debugfs release callback for the "run" entry. -+ * @inode: File entry representation -+ * @file: A specific opening of the file -+ * -+ * Release any resources that where created during the opening of the file -+ * -+ * Note that resources may not be released immediately, that might only happen -+ * later when other users of the kutf_context release their refcount. -+ * -+ * Return: 0 on success -+ */ -+static int kutf_debugfs_run_release(struct inode *inode, struct file *file) -+{ -+ struct kutf_context *test_context = file->private_data; -+ -+ kutf_context_put(test_context); -+ return 0; -+} -+ -+static const struct file_operations kutf_debugfs_run_ops = { -+ .owner = THIS_MODULE, -+ .open = kutf_debugfs_run_open, -+ .read = kutf_debugfs_run_read, -+ .release = kutf_debugfs_run_release, -+ .llseek = default_llseek, -+}; -+ -+/** -+ * create_fixture_variant() - Creates a fixture variant for the specified -+ * test function and index and the debugfs entries -+ * that represent it. -+ * @test_func: Test function -+ * @fixture_index: Fixture index -+ * -+ * Return: 0 on success, negative value corresponding to error code in failure -+ */ -+static int create_fixture_variant(struct kutf_test_function *test_func, -+ unsigned int fixture_index) -+{ -+ struct kutf_test_fixture *test_fix; -+ char name[11]; /* Enough to print the MAX_UINT32 + the null terminator */ -+ struct dentry *tmp; -+ int err; -+ -+ test_fix = kmalloc(sizeof(*test_fix), GFP_KERNEL); -+ if (!test_fix) { -+ pr_err("Failed to create debugfs directory when adding fixture\n"); -+ err = -ENOMEM; -+ goto fail_alloc; -+ } -+ -+ test_fix->test_func = test_func; -+ test_fix->fixture_index = fixture_index; -+ atomic_set(&test_fix->nr_running, 0); -+ -+ snprintf(name, sizeof(name), "%d", fixture_index); -+ test_fix->dir = debugfs_create_dir(name, test_func->dir); -+ if (!test_func->dir) { -+ pr_err("Failed to create debugfs directory when adding fixture\n"); -+ /* Might not be the right error, we don't get it passed back to us */ -+ err = -EEXIST; -+ goto fail_dir; -+ } -+ -+ tmp = debugfs_create_file("type", S_IROTH, test_fix->dir, "fixture\n", -+ &kutf_debugfs_const_string_ops); -+ if (!tmp) { -+ pr_err("Failed to create debugfs file \"type\" when adding fixture\n"); -+ /* Might not be the right error, we don't get it passed back to us */ -+ err = -EEXIST; -+ goto fail_file; -+ } -+ -+ tmp = debugfs_create_file("run", S_IROTH, test_fix->dir, test_fix, -+ &kutf_debugfs_run_ops); -+ if (!tmp) { -+ pr_err("Failed to create debugfs file \"run\" when adding fixture\n"); -+ /* Might not be the right error, we don't get it passed back to us */ -+ err = -EEXIST; -+ goto fail_file; -+ } -+ -+ list_add(&test_fix->node, &test_func->variant_list); -+ return 0; -+ -+fail_file: -+ debugfs_remove_recursive(test_fix->dir); -+fail_dir: -+ kfree(test_fix); -+fail_alloc: -+ return err; -+} -+ -+/** -+ * kutf_remove_test_variant() - Destroy a previously created fixture variant. -+ * @test_fix: Test fixture -+ */ -+static void kutf_remove_test_variant(struct kutf_test_fixture *test_fix) -+{ -+ debugfs_remove_recursive(test_fix->dir); -+ kfree(test_fix); -+} -+ -+void kutf_add_test_with_filters_data_and_userdata( -+ struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context), -+ unsigned int filters, -+ union kutf_callback_data test_data, -+ struct kutf_userdata_ops *userdata_ops) -+{ -+ struct kutf_test_function *test_func; -+ struct dentry *tmp; -+ unsigned int i; -+ -+ test_func = kmalloc(sizeof(*test_func), GFP_KERNEL); -+ if (!test_func) { -+ pr_err("Failed to allocate memory when adding test %s\n", name); -+ goto fail_alloc; -+ } -+ -+ INIT_LIST_HEAD(&test_func->variant_list); -+ -+ test_func->dir = debugfs_create_dir(name, suite->dir); -+ if (!test_func->dir) { -+ pr_err("Failed to create debugfs directory when adding test %s\n", name); -+ goto fail_dir; -+ } -+ -+ tmp = debugfs_create_file("type", S_IROTH, test_func->dir, "test\n", -+ &kutf_debugfs_const_string_ops); -+ if (!tmp) { -+ pr_err("Failed to create debugfs file \"type\" when adding test %s\n", name); -+ goto fail_file; -+ } -+ -+ test_func->filters = filters; -+ tmp = debugfs_create_x32("filters", S_IROTH, test_func->dir, -+ &test_func->filters); -+ if (!tmp) { -+ pr_err("Failed to create debugfs file \"filters\" when adding test %s\n", name); -+ goto fail_file; -+ } -+ -+ test_func->test_id = id; -+ tmp = debugfs_create_u32("test_id", S_IROTH, test_func->dir, -+ &test_func->test_id); -+ if (!tmp) { -+ pr_err("Failed to create debugfs file \"test_id\" when adding test %s\n", name); -+ goto fail_file; -+ } -+ -+ for (i = 0; i < suite->fixture_variants; i++) { -+ if (create_fixture_variant(test_func, i)) { -+ pr_err("Failed to create fixture %d when adding test %s\n", i, name); -+ goto fail_file; -+ } -+ } -+ -+ test_func->suite = suite; -+ test_func->execute = execute; -+ test_func->test_data = test_data; -+ memcpy(&test_func->userdata_ops, userdata_ops, sizeof(*userdata_ops)); -+ -+ list_add(&test_func->node, &suite->test_list); -+ return; -+ -+fail_file: -+ debugfs_remove_recursive(test_func->dir); -+fail_dir: -+ kfree(test_func); -+fail_alloc: -+ return; -+} -+EXPORT_SYMBOL(kutf_add_test_with_filters_data_and_userdata); -+ -+void kutf_add_test_with_filters_and_data( -+ struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context), -+ unsigned int filters, -+ union kutf_callback_data test_data) -+{ -+ struct kutf_userdata_ops userdata_ops = { -+ .open = NULL, -+ .release = NULL, -+ .consumer = NULL, -+ .producer = NULL, -+ }; -+ -+ kutf_add_test_with_filters_data_and_userdata(suite, id, name, execute, -+ filters, test_data, &userdata_ops); -+} -+ -+EXPORT_SYMBOL(kutf_add_test_with_filters_and_data); -+ -+void kutf_add_test_with_filters( -+ struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context), -+ unsigned int filters) -+{ -+ union kutf_callback_data data; -+ -+ data.ptr_value = NULL; -+ -+ kutf_add_test_with_filters_and_data(suite, -+ id, -+ name, -+ execute, -+ suite->suite_default_flags, -+ data); -+} -+EXPORT_SYMBOL(kutf_add_test_with_filters); -+ -+void kutf_add_test(struct kutf_suite *suite, -+ unsigned int id, -+ const char *name, -+ void (*execute)(struct kutf_context *context)) -+{ -+ union kutf_callback_data data; -+ -+ data.ptr_value = NULL; -+ -+ kutf_add_test_with_filters_and_data(suite, -+ id, -+ name, -+ execute, -+ suite->suite_default_flags, -+ data); -+} -+EXPORT_SYMBOL(kutf_add_test); -+ -+/** -+ * kutf_remove_test(): Remove a previously added test function. -+ * @test_func: Test function -+ */ -+static void kutf_remove_test(struct kutf_test_function *test_func) -+{ -+ struct list_head *pos; -+ struct list_head *tmp; -+ -+ list_for_each_safe(pos, tmp, &test_func->variant_list) { -+ struct kutf_test_fixture *test_fix; -+ -+ test_fix = list_entry(pos, struct kutf_test_fixture, node); -+ kutf_remove_test_variant(test_fix); -+ } -+ -+ list_del(&test_func->node); -+ debugfs_remove_recursive(test_func->dir); -+ kfree(test_func); -+} -+ -+struct kutf_suite *kutf_create_suite_with_filters_and_data( -+ struct kutf_application *app, -+ const char *name, -+ unsigned int fixture_count, -+ void *(*create_fixture)(struct kutf_context *context), -+ void (*remove_fixture)(struct kutf_context *context), -+ unsigned int filters, -+ union kutf_callback_data suite_data) -+{ -+ struct kutf_suite *suite; -+ struct dentry *tmp; -+ -+ suite = kmalloc(sizeof(*suite), GFP_KERNEL); -+ if (!suite) { -+ pr_err("Failed to allocate memory when creating suite %s\n", name); -+ goto fail_kmalloc; -+ } -+ -+ suite->dir = debugfs_create_dir(name, app->dir); -+ if (!suite->dir) { -+ pr_err("Failed to create debugfs directory when adding test %s\n", name); -+ goto fail_debugfs; -+ } -+ -+ tmp = debugfs_create_file("type", S_IROTH, suite->dir, "suite\n", -+ &kutf_debugfs_const_string_ops); -+ if (!tmp) { -+ pr_err("Failed to create debugfs file \"type\" when adding test %s\n", name); -+ goto fail_file; -+ } -+ -+ INIT_LIST_HEAD(&suite->test_list); -+ suite->app = app; -+ suite->name = name; -+ suite->fixture_variants = fixture_count; -+ suite->create_fixture = create_fixture; -+ suite->remove_fixture = remove_fixture; -+ suite->suite_default_flags = filters; -+ suite->suite_data = suite_data; -+ -+ list_add(&suite->node, &app->suite_list); -+ -+ return suite; -+ -+fail_file: -+ debugfs_remove_recursive(suite->dir); -+fail_debugfs: -+ kfree(suite); -+fail_kmalloc: -+ return NULL; -+} -+EXPORT_SYMBOL(kutf_create_suite_with_filters_and_data); -+ -+struct kutf_suite *kutf_create_suite_with_filters( -+ struct kutf_application *app, -+ const char *name, -+ unsigned int fixture_count, -+ void *(*create_fixture)(struct kutf_context *context), -+ void (*remove_fixture)(struct kutf_context *context), -+ unsigned int filters) -+{ -+ union kutf_callback_data data; -+ -+ data.ptr_value = NULL; -+ return kutf_create_suite_with_filters_and_data(app, -+ name, -+ fixture_count, -+ create_fixture, -+ remove_fixture, -+ filters, -+ data); -+} -+EXPORT_SYMBOL(kutf_create_suite_with_filters); -+ -+struct kutf_suite *kutf_create_suite( -+ struct kutf_application *app, -+ const char *name, -+ unsigned int fixture_count, -+ void *(*create_fixture)(struct kutf_context *context), -+ void (*remove_fixture)(struct kutf_context *context)) -+{ -+ union kutf_callback_data data; -+ -+ data.ptr_value = NULL; -+ return kutf_create_suite_with_filters_and_data(app, -+ name, -+ fixture_count, -+ create_fixture, -+ remove_fixture, -+ KUTF_F_TEST_GENERIC, -+ data); -+} -+EXPORT_SYMBOL(kutf_create_suite); -+ -+/** -+ * kutf_destroy_suite() - Destroy a previously added test suite. -+ * @suite: Test suite -+ */ -+static void kutf_destroy_suite(struct kutf_suite *suite) -+{ -+ struct list_head *pos; -+ struct list_head *tmp; -+ -+ list_for_each_safe(pos, tmp, &suite->test_list) { -+ struct kutf_test_function *test_func; -+ -+ test_func = list_entry(pos, struct kutf_test_function, node); -+ kutf_remove_test(test_func); -+ } -+ -+ list_del(&suite->node); -+ debugfs_remove_recursive(suite->dir); -+ kfree(suite); -+} -+ -+struct kutf_application *kutf_create_application(const char *name) -+{ -+ struct kutf_application *app; -+ struct dentry *tmp; -+ -+ app = kmalloc(sizeof(*app), GFP_KERNEL); -+ if (!app) { -+ pr_err("Failed to create allocate memory when creating application %s\n", name); -+ goto fail_kmalloc; -+ } -+ -+ app->dir = debugfs_create_dir(name, base_dir); -+ if (!app->dir) { -+ pr_err("Failed to create debugfs direcotry when creating application %s\n", name); -+ goto fail_debugfs; -+ } -+ -+ tmp = debugfs_create_file("type", S_IROTH, app->dir, "application\n", -+ &kutf_debugfs_const_string_ops); -+ if (!tmp) { -+ pr_err("Failed to create debugfs file \"type\" when creating application %s\n", name); -+ goto fail_file; -+ } -+ -+ INIT_LIST_HEAD(&app->suite_list); -+ app->name = name; -+ -+ return app; -+ -+fail_file: -+ debugfs_remove_recursive(app->dir); -+fail_debugfs: -+ kfree(app); -+fail_kmalloc: -+ return NULL; -+} -+EXPORT_SYMBOL(kutf_create_application); -+ -+void kutf_destroy_application(struct kutf_application *app) -+{ -+ struct list_head *pos; -+ struct list_head *tmp; -+ -+ list_for_each_safe(pos, tmp, &app->suite_list) { -+ struct kutf_suite *suite; -+ -+ suite = list_entry(pos, struct kutf_suite, node); -+ kutf_destroy_suite(suite); -+ } -+ -+ debugfs_remove_recursive(app->dir); -+ kfree(app); -+} -+EXPORT_SYMBOL(kutf_destroy_application); -+ -+static struct kutf_context *kutf_create_context( -+ struct kutf_test_fixture *test_fix) -+{ -+ struct kutf_context *new_context; -+ -+ new_context = kmalloc(sizeof(*new_context), GFP_KERNEL); -+ if (!new_context) { -+ pr_err("Failed to allocate test context"); -+ goto fail_alloc; -+ } -+ -+ new_context->result_set = kutf_create_result_set(); -+ if (!new_context->result_set) { -+ pr_err("Failed to create resultset"); -+ goto fail_result_set; -+ } -+ -+ new_context->test_fix = test_fix; -+ /* Save the pointer to the suite as the callbacks will require it */ -+ new_context->suite = test_fix->test_func->suite; -+ new_context->status = KUTF_RESULT_UNKNOWN; -+ new_context->expected_status = KUTF_RESULT_UNKNOWN; -+ -+ kutf_mempool_init(&new_context->fixture_pool); -+ new_context->fixture = NULL; -+ new_context->fixture_index = test_fix->fixture_index; -+ new_context->fixture_name = NULL; -+ new_context->test_data = test_fix->test_func->test_data; -+ new_context->userdata_consumer_priv = NULL; -+ new_context->userdata_producer_priv = NULL; -+ new_context->userdata_dentry = NULL; -+ -+ kref_init(&new_context->kref); -+ -+ return new_context; -+ -+fail_result_set: -+ kfree(new_context); -+fail_alloc: -+ return NULL; -+} -+ -+static void kutf_destroy_context(struct kref *kref) -+{ -+ struct kutf_context *context; -+ -+ context = container_of(kref, struct kutf_context, kref); -+ kutf_destroy_result_set(context->result_set); -+ kutf_mempool_destroy(&context->fixture_pool); -+ kfree(context); -+} -+ -+static void kutf_context_get(struct kutf_context *context) -+{ -+ kref_get(&context->kref); -+} -+ -+static void kutf_context_put(struct kutf_context *context) -+{ -+ kref_put(&context->kref, kutf_destroy_context); -+} -+ -+ -+static void kutf_set_result(struct kutf_context *context, -+ enum kutf_result_status status) -+{ -+ context->status = status; -+} -+ -+static void kutf_set_expected_result(struct kutf_context *context, -+ enum kutf_result_status expected_status) -+{ -+ context->expected_status = expected_status; -+} -+ -+/** -+ * kutf_test_log_result() - Log a result for the specified test context -+ * @context: Test context -+ * @message: Result string -+ * @new_status: Result status -+ */ -+static void kutf_test_log_result( -+ struct kutf_context *context, -+ const char *message, -+ enum kutf_result_status new_status) -+{ -+ if (context->status < new_status) -+ context->status = new_status; -+ -+ if (context->expected_status != new_status) -+ kutf_add_result(&context->fixture_pool, context->result_set, -+ new_status, message); -+} -+ -+void kutf_test_log_result_external( -+ struct kutf_context *context, -+ const char *message, -+ enum kutf_result_status new_status) -+{ -+ kutf_test_log_result(context, message, new_status); -+} -+EXPORT_SYMBOL(kutf_test_log_result_external); -+ -+void kutf_test_expect_abort(struct kutf_context *context) -+{ -+ kutf_set_expected_result(context, KUTF_RESULT_ABORT); -+} -+EXPORT_SYMBOL(kutf_test_expect_abort); -+ -+void kutf_test_expect_fatal(struct kutf_context *context) -+{ -+ kutf_set_expected_result(context, KUTF_RESULT_FATAL); -+} -+EXPORT_SYMBOL(kutf_test_expect_fatal); -+ -+void kutf_test_expect_fail(struct kutf_context *context) -+{ -+ kutf_set_expected_result(context, KUTF_RESULT_FAIL); -+} -+EXPORT_SYMBOL(kutf_test_expect_fail); -+ -+void kutf_test_expect_warn(struct kutf_context *context) -+{ -+ kutf_set_expected_result(context, KUTF_RESULT_WARN); -+} -+EXPORT_SYMBOL(kutf_test_expect_warn); -+ -+void kutf_test_expect_pass(struct kutf_context *context) -+{ -+ kutf_set_expected_result(context, KUTF_RESULT_PASS); -+} -+EXPORT_SYMBOL(kutf_test_expect_pass); -+ -+void kutf_test_skip(struct kutf_context *context) -+{ -+ kutf_set_result(context, KUTF_RESULT_SKIP); -+ kutf_set_expected_result(context, KUTF_RESULT_UNKNOWN); -+ -+ kutf_test_log_result(context, "Test skipped", KUTF_RESULT_SKIP); -+} -+EXPORT_SYMBOL(kutf_test_skip); -+ -+void kutf_test_skip_msg(struct kutf_context *context, const char *message) -+{ -+ kutf_set_result(context, KUTF_RESULT_SKIP); -+ kutf_set_expected_result(context, KUTF_RESULT_UNKNOWN); -+ -+ kutf_test_log_result(context, kutf_dsprintf(&context->fixture_pool, -+ "Test skipped: %s", message), KUTF_RESULT_SKIP); -+ kutf_test_log_result(context, "!!!Test skipped!!!", KUTF_RESULT_SKIP); -+} -+EXPORT_SYMBOL(kutf_test_skip_msg); -+ -+void kutf_test_debug(struct kutf_context *context, char const *message) -+{ -+ kutf_test_log_result(context, message, KUTF_RESULT_DEBUG); -+} -+EXPORT_SYMBOL(kutf_test_debug); -+ -+void kutf_test_pass(struct kutf_context *context, char const *message) -+{ -+ static const char explicit_message[] = "(explicit pass)"; -+ -+ if (!message) -+ message = explicit_message; -+ -+ kutf_test_log_result(context, message, KUTF_RESULT_PASS); -+} -+EXPORT_SYMBOL(kutf_test_pass); -+ -+void kutf_test_info(struct kutf_context *context, char const *message) -+{ -+ kutf_test_log_result(context, message, KUTF_RESULT_INFO); -+} -+EXPORT_SYMBOL(kutf_test_info); -+ -+void kutf_test_warn(struct kutf_context *context, char const *message) -+{ -+ kutf_test_log_result(context, message, KUTF_RESULT_WARN); -+} -+EXPORT_SYMBOL(kutf_test_warn); -+ -+void kutf_test_fail(struct kutf_context *context, char const *message) -+{ -+ kutf_test_log_result(context, message, KUTF_RESULT_FAIL); -+} -+EXPORT_SYMBOL(kutf_test_fail); -+ -+void kutf_test_fatal(struct kutf_context *context, char const *message) -+{ -+ kutf_test_log_result(context, message, KUTF_RESULT_FATAL); -+} -+EXPORT_SYMBOL(kutf_test_fatal); -+ -+void kutf_test_abort(struct kutf_context *context) -+{ -+ kutf_test_log_result(context, "", KUTF_RESULT_ABORT); -+} -+EXPORT_SYMBOL(kutf_test_abort); -+ -+/** -+ * init_kutf_core() - Module entry point. -+ * -+ * Create the base entry point in debugfs. -+ */ -+static int __init init_kutf_core(void) -+{ -+ int ret; -+ -+ base_dir = debugfs_create_dir("kutf_tests", NULL); -+ if (!base_dir) { -+ ret = -ENODEV; -+ goto exit_dir; -+ } -+ -+ return 0; -+ -+exit_dir: -+ return ret; -+} -+ -+/** -+ * exit_kutf_core() - Module exit point. -+ * -+ * Remove the base entry point in debugfs. -+ */ -+static void __exit exit_kutf_core(void) -+{ -+ debugfs_remove_recursive(base_dir); -+} -+ -+#else /* defined(CONFIG_DEBUG_FS) */ -+ -+/** -+ * init_kutf_core() - Module entry point. -+ * -+ * Stub for when build against a kernel without debugfs support -+ */ -+static int __init init_kutf_core(void) -+{ -+ pr_debug("KUTF requires a kernel with debug fs support"); -+ -+ return -ENODEV; -+} -+ -+/** -+ * exit_kutf_core() - Module exit point. -+ * -+ * Stub for when build against a kernel without debugfs support -+ */ -+static void __exit exit_kutf_core(void) -+{ -+} -+#endif /* defined(CONFIG_DEBUG_FS) */ -+ -+MODULE_LICENSE("GPL"); -+ -+module_init(init_kutf_core); -+module_exit(exit_kutf_core); -diff --git a/drivers/gpu/arm/midgard/tests/kutf/kutf_utils.c b/drivers/gpu/arm/midgard/tests/kutf/kutf_utils.c -new file mode 100644 -index 0000000..a429a2d ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/kutf_utils.c -@@ -0,0 +1,71 @@ -+/* -+ * -+ * (C) COPYRIGHT 2014, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+/* Kernel UTF utility functions */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+static char tmp_buffer[KUTF_MAX_DSPRINTF_LEN]; -+ -+DEFINE_MUTEX(buffer_lock); -+ -+const char *kutf_dsprintf(struct kutf_mempool *pool, -+ const char *fmt, ...) -+{ -+ va_list args; -+ int len; -+ int size; -+ void *buffer; -+ -+ mutex_lock(&buffer_lock); -+ va_start(args, fmt); -+ len = vsnprintf(tmp_buffer, sizeof(tmp_buffer), fmt, args); -+ va_end(args); -+ -+ if (len < 0) { -+ pr_err("kutf_dsprintf: Bad format dsprintf format %s\n", fmt); -+ goto fail_format; -+ } -+ -+ if (len >= sizeof(tmp_buffer)) { -+ pr_warn("kutf_dsprintf: Truncated dsprintf message %s\n", fmt); -+ size = sizeof(tmp_buffer); -+ } else { -+ size = len + 1; -+ } -+ -+ buffer = kutf_mempool_alloc(pool, size); -+ if (!buffer) -+ goto fail_alloc; -+ -+ memcpy(buffer, tmp_buffer, size); -+ mutex_unlock(&buffer_lock); -+ -+ return buffer; -+ -+fail_alloc: -+fail_format: -+ mutex_unlock(&buffer_lock); -+ return NULL; -+} -+EXPORT_SYMBOL(kutf_dsprintf); -diff --git a/drivers/gpu/arm/midgard/tests/kutf/sconscript b/drivers/gpu/arm/midgard/tests/kutf/sconscript -new file mode 100644 -index 0000000..d7f1124 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/kutf/sconscript -@@ -0,0 +1,21 @@ -+# -+# (C) COPYRIGHT 2014-2016, 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+Import('kutf_env') -+ -+make_args = kutf_env.kernel_get_config_defines(ret_list = True) -+ -+mod = kutf_env.BuildKernelModule('$STATIC_LIB_PATH/kutf.ko', Glob('*.c'), make_args = make_args) -+kutf_env.KernelObjTarget('kutf', mod) -diff --git a/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Kbuild b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Kbuild -new file mode 100644 -index 0000000..0cd9ceb ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Kbuild -@@ -0,0 +1,20 @@ -+# -+# (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ccflags-y += -I$(src)/../include -I$(src)/../../../ -I$(src)/../../ -I$(src)/../../backend/gpu -I$(srctree)/drivers/staging/android -+ -+obj-$(CONFIG_MALI_IRQ_LATENCY) += mali_kutf_irq_test.o -+ -+mali_kutf_irq_test-y := mali_kutf_irq_test_main.o -diff --git a/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Kconfig b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Kconfig -new file mode 100644 -index 0000000..f4553d3 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Kconfig -@@ -0,0 +1,23 @@ -+# -+# (C) COPYRIGHT 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+config MALI_IRQ_LATENCY -+ tristate "Mali GPU IRQ latency measurement" -+ depends on MALI_MIDGARD && MALI_DEBUG && MALI_KUTF -+ default m -+ help -+ This option will build a test module mali_kutf_irq_test that -+ can determine the latency of the Mali GPU IRQ on your system. -+ Choosing M here will generate a single module called mali_kutf_irq_test. -diff --git a/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Makefile b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Makefile -new file mode 100644 -index 0000000..4e94876 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Makefile -@@ -0,0 +1,51 @@ -+# -+# (C) COPYRIGHT 2015, 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+# linux build system bootstrap for out-of-tree module -+ -+# default to building for the host -+ARCH ?= $(shell uname -m) -+ -+ifeq ($(KDIR),) -+$(error Must specify KDIR to point to the kernel to target)) -+endif -+ -+TEST_CCFLAGS := \ -+ -DMALI_DEBUG=$(MALI_DEBUG) \ -+ -DMALI_BACKEND_KERNEL=$(MALI_BACKEND_KERNEL) \ -+ -DMALI_MODEL=$(MALI_MODEL) \ -+ -DMALI_NO_MALI=$(MALI_NO_MALI) \ -+ -DMALI_BASE_QA_LEAK=$(MALI_BASE_QA_LEAK) \ -+ -DMALI_BASE_QA_RESFAIL=$(MALI_BASE_QA_RESFAIL) \ -+ -DMALI_BASE_QA_USE_AFTER_FREE=$(MALI_BASE_QA_USE_AFTER_FREE) \ -+ -DMALI_UNIT_TEST=$(MALI_UNIT_TEST) \ -+ -DMALI_USE_UMP=$(MALI_USE_UMP) \ -+ -DMALI_ERROR_INJECT_ON=$(MALI_ERROR_INJECT_ON) \ -+ -DMALI_CUSTOMER_RELEASE=$(MALI_CUSTOMER_RELEASE) \ -+ $(SCONS_CFLAGS) \ -+ -I$(CURDIR)/../include \ -+ -I$(CURDIR)/../../../../../../include \ -+ -I$(CURDIR)/../../../ \ -+ -I$(CURDIR)/../../ \ -+ -I$(CURDIR)/../../backend/gpu \ -+ -I$(CURDIR)/ \ -+ -I$(srctree)/drivers/staging/android \ -+ -I$(srctree)/include/linux -+ -+all: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) $(SCONS_CONFIGS) EXTRA_CFLAGS="$(TEST_CCFLAGS)" KBUILD_EXTRA_SYMBOLS="$(CURDIR)/../kutf/Module.symvers $(CURDIR)/../../Module.symvers" modules -+ -+clean: -+ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean -diff --git a/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/mali_kutf_irq_test_main.c b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/mali_kutf_irq_test_main.c -new file mode 100644 -index 0000000..c9cc444 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/mali_kutf_irq_test_main.c -@@ -0,0 +1,269 @@ -+/* -+ * -+ * (C) COPYRIGHT 2016, 2017 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+#include -+#include -+#include -+ -+#include "mali_kbase.h" -+#include -+ -+#include -+#include -+ -+/* -+ * This file contains the code which is used for measuring interrupt latency -+ * of the Mali GPU IRQ. In particular, function mali_kutf_irq_latency() is -+ * used with this purpose and it is called within KUTF framework - a kernel -+ * unit test framework. The measured latency provided by this test should -+ * be representative for the latency of the Mali JOB/MMU IRQs as well. -+ */ -+ -+/* KUTF test application pointer for this test */ -+struct kutf_application *irq_app; -+ -+/** -+ * struct kutf_irq_fixture data - test fixture used by the test functions. -+ * @kbdev: kbase device for the GPU. -+ * -+ */ -+struct kutf_irq_fixture_data { -+ struct kbase_device *kbdev; -+}; -+ -+#define SEC_TO_NANO(s) ((s)*1000000000LL) -+ -+/* ID for the GPU IRQ */ -+#define GPU_IRQ_HANDLER 2 -+ -+#define NR_TEST_IRQS 1000000 -+ -+/* IRQ for the test to trigger. Currently MULTIPLE_GPU_FAULTS as we would not -+ * expect to see this in normal use (e.g., when Android is running). */ -+#define TEST_IRQ MULTIPLE_GPU_FAULTS -+ -+#define IRQ_TIMEOUT HZ -+ -+/* Kernel API for setting irq throttle hook callback and irq time in us*/ -+extern int kbase_set_custom_irq_handler(struct kbase_device *kbdev, -+ irq_handler_t custom_handler, -+ int irq_type); -+extern irqreturn_t kbase_gpu_irq_handler(int irq, void *data); -+ -+static DECLARE_WAIT_QUEUE_HEAD(wait); -+static bool triggered; -+static u64 irq_time; -+ -+static void *kbase_untag(void *ptr) -+{ -+ return (void *)(((uintptr_t) ptr) & ~3); -+} -+ -+/** -+ * kbase_gpu_irq_custom_handler - Custom IRQ throttle handler -+ * @irq: IRQ number -+ * @data: Data associated with this IRQ -+ * -+ * Return: state of the IRQ -+ */ -+static irqreturn_t kbase_gpu_irq_custom_handler(int irq, void *data) -+{ -+ struct kbase_device *kbdev = kbase_untag(data); -+ u32 val; -+ -+ val = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_STATUS), NULL); -+ if (val & TEST_IRQ) { -+ struct timespec tval; -+ -+ getnstimeofday(&tval); -+ irq_time = SEC_TO_NANO(tval.tv_sec) + (tval.tv_nsec); -+ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), val, -+ NULL); -+ -+ triggered = true; -+ wake_up(&wait); -+ -+ return IRQ_HANDLED; -+ } -+ -+ /* Trigger main irq handler */ -+ return kbase_gpu_irq_handler(irq, data); -+} -+ -+/** -+ * mali_kutf_irq_default_create_fixture() - Creates the fixture data required -+ * for all the tests in the irq suite. -+ * @context: KUTF context. -+ * -+ * Return: Fixture data created on success or NULL on failure -+ */ -+static void *mali_kutf_irq_default_create_fixture( -+ struct kutf_context *context) -+{ -+ struct kutf_irq_fixture_data *data; -+ -+ data = kutf_mempool_alloc(&context->fixture_pool, -+ sizeof(struct kutf_irq_fixture_data)); -+ -+ if (!data) -+ goto fail; -+ -+ /* Acquire the kbase device */ -+ data->kbdev = kbase_find_device(-1); -+ if (data->kbdev == NULL) { -+ kutf_test_fail(context, "Failed to find kbase device"); -+ goto fail; -+ } -+ -+ return data; -+ -+fail: -+ return NULL; -+} -+ -+/** -+ * mali_kutf_irq_default_remove_fixture() - Destroy fixture data previously -+ * created by mali_kutf_irq_default_create_fixture. -+ * -+ * @context: KUTF context. -+ */ -+static void mali_kutf_irq_default_remove_fixture( -+ struct kutf_context *context) -+{ -+ struct kutf_irq_fixture_data *data = context->fixture; -+ struct kbase_device *kbdev = data->kbdev; -+ -+ kbase_release_device(kbdev); -+} -+ -+/** -+ * mali_kutf_irq_latency() - measure GPU IRQ latency -+ * @context: kutf context within which to perform the test -+ * -+ * The test triggers IRQs manually, and measures the -+ * time between triggering the IRQ and the IRQ handler being executed. -+ * -+ * This is not a traditional test, in that the pass/fail status has little -+ * meaning (other than indicating that the IRQ handler executed at all). Instead -+ * the results are in the latencies provided with the test result. There is no -+ * meaningful pass/fail result that can be obtained here, instead the latencies -+ * are provided for manual analysis only. -+ */ -+static void mali_kutf_irq_latency(struct kutf_context *context) -+{ -+ struct kutf_irq_fixture_data *data = context->fixture; -+ struct kbase_device *kbdev = data->kbdev; -+ u64 min_time = U64_MAX, max_time = 0, average_time = 0; -+ int i; -+ bool test_failed = false; -+ -+ /* Force GPU to be powered */ -+ kbase_pm_context_active(kbdev); -+ -+ kbase_set_custom_irq_handler(kbdev, kbase_gpu_irq_custom_handler, -+ GPU_IRQ_HANDLER); -+ -+ for (i = 0; i < NR_TEST_IRQS; i++) { -+ struct timespec tval; -+ u64 start_time; -+ int ret; -+ -+ triggered = false; -+ getnstimeofday(&tval); -+ start_time = SEC_TO_NANO(tval.tv_sec) + (tval.tv_nsec); -+ -+ /* Trigger fake IRQ */ -+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), -+ TEST_IRQ, NULL); -+ -+ ret = wait_event_timeout(wait, triggered != false, IRQ_TIMEOUT); -+ -+ if (ret == 0) { -+ kutf_test_fail(context, "Timed out waiting for IRQ\n"); -+ test_failed = true; -+ break; -+ } -+ -+ if ((irq_time - start_time) < min_time) -+ min_time = irq_time - start_time; -+ if ((irq_time - start_time) > max_time) -+ max_time = irq_time - start_time; -+ average_time += irq_time - start_time; -+ -+ udelay(10); -+ } -+ -+ /* Go back to default handler */ -+ kbase_set_custom_irq_handler(kbdev, NULL, GPU_IRQ_HANDLER); -+ -+ kbase_pm_context_idle(kbdev); -+ -+ if (!test_failed) { -+ const char *results; -+ -+ do_div(average_time, NR_TEST_IRQS); -+ results = kutf_dsprintf(&context->fixture_pool, -+ "Min latency = %lldns, Max latency = %lldns, Average latency = %lldns\n", -+ min_time, max_time, average_time); -+ kutf_test_pass(context, results); -+ } -+} -+ -+/** -+ * Module entry point for this test. -+ */ -+int mali_kutf_irq_test_main_init(void) -+{ -+ struct kutf_suite *suite; -+ -+ irq_app = kutf_create_application("irq"); -+ -+ if (NULL == irq_app) { -+ pr_warn("Creation of test application failed!\n"); -+ return -ENOMEM; -+ } -+ -+ suite = kutf_create_suite(irq_app, "irq_default", -+ 1, mali_kutf_irq_default_create_fixture, -+ mali_kutf_irq_default_remove_fixture); -+ -+ if (NULL == suite) { -+ pr_warn("Creation of test suite failed!\n"); -+ kutf_destroy_application(irq_app); -+ return -ENOMEM; -+ } -+ -+ kutf_add_test(suite, 0x0, "irq_latency", -+ mali_kutf_irq_latency); -+ return 0; -+} -+ -+/** -+ * Module exit point for this test. -+ */ -+void mali_kutf_irq_test_main_exit(void) -+{ -+ kutf_destroy_application(irq_app); -+} -+ -+module_init(mali_kutf_irq_test_main_init); -+module_exit(mali_kutf_irq_test_main_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("ARM Ltd."); -+MODULE_VERSION("1.0"); -diff --git a/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/sconscript b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/sconscript -new file mode 100644 -index 0000000..ec837f1 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/sconscript -@@ -0,0 +1,30 @@ -+# -+# (C) COPYRIGHT 2015, 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+import os -+Import('env') -+ -+src = [Glob('#kernel/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/*.c'), Glob('#kernel/drivers/gpu/arm/midgard/tests/mali_kutf_irq_test/Makefile')] -+ -+if env.GetOption('clean') : -+ env.Execute(Action("make clean", '[CLEAN] mali_kutf_irq_test')) -+ cmd = env.Command('$STATIC_LIB_PATH/mali_kutf_irq_test.ko', src, []) -+ env.KernelObjTarget('mali_kutf_irq_test', cmd) -+else: -+ makeAction=Action("cd ${SOURCE.dir} && make MALI_DEBUG=${debug} MALI_BACKEND_KERNEL=1 MALI_ERROR_INJECT_ON=${error_inject} MALI_MODEL=${mali_model} MALI_NO_MALI=${no_mali} MALI_HW_VERSION=${hwver} MALI_UNIT_TEST=${unit} MALI_USE_UMP=${ump} MALI_CUSTOMER_RELEASE=${release} %s %s && ( ( [ -f mali_kutf_irq_test.ko ] && cp mali_kutf_irq_test.ko $STATIC_LIB_PATH/ ) || touch $STATIC_LIB_PATH/mali_kutf_irq_test.ko)" % (env.base_get_qa_settings(), env.kernel_get_config_defines()), '$MAKECOMSTR') -+ cmd = env.Command('$STATIC_LIB_PATH/mali_kutf_irq_test.ko', src, [makeAction]) -+ env.Depends('$STATIC_LIB_PATH/mali_kutf_irq_test.ko', '$STATIC_LIB_PATH/kutf.ko') -+ env.Depends('$STATIC_LIB_PATH/mali_kutf_irq_test.ko', '$STATIC_LIB_PATH/mali_kbase.ko') -+ env.KernelObjTarget('mali_kutf_irq_test', cmd) -diff --git a/drivers/gpu/arm/midgard/tests/sconscript b/drivers/gpu/arm/midgard/tests/sconscript -new file mode 100644 -index 0000000..0458411 ---- /dev/null -+++ b/drivers/gpu/arm/midgard/tests/sconscript -@@ -0,0 +1,38 @@ -+# -+# (C) COPYRIGHT 2010-2011, 2013, 2017 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+Import ('env') -+ -+kutf_env = env.Clone() -+kutf_env.Append(CPPPATH = '#kernel/drivers/gpu/arm/midgard/tests/include') -+Export('kutf_env') -+ -+if Glob('internal/sconscript'): -+ SConscript('internal/sconscript') -+ -+if kutf_env['debug'] == '1': -+ SConscript('kutf/sconscript') -+ SConscript('mali_kutf_irq_test/sconscript') -+ -+ if Glob('kutf_test/sconscript'): -+ SConscript('kutf_test/sconscript') -+ -+ if Glob('kutf_test_runner/sconscript'): -+ SConscript('kutf_test_runner/sconscript') -+ -+if env['unit'] == '1': -+ SConscript('mali_kutf_ipa_test/sconscript') -+ SConscript('mali_kutf_ipa_unit_test/sconscript') -+ SConscript('mali_kutf_vinstr_test/sconscript') -diff --git a/include/linux/kds.h b/include/linux/kds.h -new file mode 100644 -index 0000000..1346eda ---- /dev/null -+++ b/include/linux/kds.h -@@ -0,0 +1,173 @@ -+/* -+ * -+ * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _KDS_H_ -+#define _KDS_H_ -+ -+#include -+#include -+ -+#define KDS_WAIT_BLOCKING (ULONG_MAX) -+ -+struct kds_resource_set; -+ -+typedef void (*kds_callback_fn) (void *callback_parameter, void *callback_extra_parameter); -+ -+struct kds_callback -+{ -+ kds_callback_fn user_cb; /* real cb */ -+ int direct; /* do direct or queued call? */ -+ struct workqueue_struct *wq; -+}; -+ -+struct kds_link -+{ -+ struct kds_resource_set *parent; -+ struct list_head link; -+ unsigned long state; -+}; -+ -+struct kds_resource -+{ -+ struct kds_link waiters; -+}; -+ -+/* callback API */ -+ -+/* Initialize a callback object. -+ * -+ * Typically created per context or per hw resource. -+ * -+ * Callbacks can be performed directly if no nested locking can -+ * happen in the client. -+ * -+ * Nested locking can occur when a lock is held during the kds_async_waitall or -+ * kds_resource_set_release call. If the callback needs to take the same lock -+ * nested locking will happen. -+ * -+ * If nested locking could happen non-direct callbacks can be requested. -+ * Callbacks will then be called asynchronous to the triggering call. -+ */ -+int kds_callback_init(struct kds_callback *cb, int direct, kds_callback_fn user_cb); -+ -+/* Terminate the use of a callback object. -+ * -+ * If the callback object was set up as non-direct -+ * any pending callbacks will be flushed first. -+ * Note that to avoid a deadlock the lock callbacks needs -+ * can't be held when a callback object is terminated. -+ */ -+void kds_callback_term(struct kds_callback *cb); -+ -+ -+/* resource object API */ -+ -+/* initialize a resource handle for a shared resource */ -+void kds_resource_init(struct kds_resource * const resource); -+ -+/* -+ * Will return 0 on success. -+ * If the resource is being used or waited -EBUSY is returned. -+ * The caller should NOT try to terminate a resource that could still have clients. -+ * After the function returns the resource is no longer known by kds. -+ */ -+int kds_resource_term(struct kds_resource *resource); -+ -+/* Asynchronous wait for a set of resources. -+ * Callback will be called when all resources are available. -+ * If all the resources was available the callback will be called before kds_async_waitall returns. -+ * So one must not hold any locks the callback code-flow can take when calling kds_async_waitall. -+ * Caller considered to own/use the resources until \a kds_rset_release is called. -+ * exclusive_access_bitmap is a bitmap where a high bit means exclusive access while a low bit means shared access. -+ * Use the Linux __set_bit API, where the index of the buffer to control is used as the bit index. -+ * -+ * Standard Linux error return value. -+ */ -+int kds_async_waitall( -+ struct kds_resource_set ** const pprset, -+ struct kds_callback *cb, -+ void *callback_parameter, -+ void *callback_extra_parameter, -+ int number_resources, -+ unsigned long *exclusive_access_bitmap, -+ struct kds_resource **resource_list); -+ -+/* Synchronous wait for a set of resources. -+ * Function will return when one of these have happened: -+ * - all resources have been obtained -+ * - timeout lapsed while waiting -+ * - a signal was received while waiting -+ * -+ * To wait without a timeout, specify KDS_WAIT_BLOCKING for \a jifies_timeout, otherwise -+ * the timeout in jiffies. A zero timeout attempts to obtain all resources and returns -+ * immediately with a timeout if all resources could not be obtained. -+ * -+ * Caller considered to own/use the resources when the function returns. -+ * Caller must release the resources using \a kds_rset_release. -+ * -+ * Calling this function while holding already locked resources or other locking primitives is dangerous. -+ * One must if this is needed decide on a lock order of the resources and/or the other locking primitives -+ * and always take the resources/locking primitives in the specific order. -+ * -+ * Use the ERR_PTR framework to decode the return value. -+ * NULL = time out -+ * If IS_ERR then PTR_ERR gives: -+ * ERESTARTSYS = signal received, retry call after signal -+ * all other values = internal error, lock failed -+ * Other values = successful wait, now the owner, must call kds_resource_set_release -+ */ -+struct kds_resource_set *kds_waitall( -+ int number_resources, -+ unsigned long *exclusive_access_bitmap, -+ struct kds_resource **resource_list, -+ unsigned long jifies_timeout); -+ -+/* Release resources after use. -+ * Caller must handle that other async callbacks will trigger, -+ * so must avoid holding any locks a callback will take. -+ * -+ * The function takes a pointer to your poiner to handle a race -+ * between a cancelation and a completion. -+ * -+ * If the caller can't guarantee that a race can't occur then -+ * the passed in pointer must be the same in both call paths -+ * to allow kds to manage the potential race. -+ */ -+void kds_resource_set_release(struct kds_resource_set **pprset); -+ -+/* Release resources after use and wait callbacks to complete. -+ * Caller must handle that other async callbacks will trigger, -+ * so must avoid holding any locks a callback will take. -+ * -+ * The function takes a pointer to your poiner to handle a race -+ * between a cancelation and a completion. -+ * -+ * If the caller can't guarantee that a race can't occur then -+ * the passed in pointer must be the same in both call paths -+ * to allow kds to manage the potential race. -+ * -+ * This should be used to cancel waits which are pending on a kds -+ * resource. -+ * -+ * It is a bug to call this from atomic contexts and from within -+ * a kds callback that now owns the kds_rseource. -+ */ -+ -+void kds_resource_set_release_sync(struct kds_resource_set **pprset); -+#endif /* _KDS_H_ */ -diff --git a/include/linux/ump-common.h b/include/linux/ump-common.h -new file mode 100644 -index 0000000..0015bda ---- /dev/null -+++ b/include/linux/ump-common.h -@@ -0,0 +1,252 @@ -+/* -+ * -+ * (C) COPYRIGHT 2010-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file ump-common.h -+ * -+ * This file contains some common enum values used both in both the user and kernel space side of UMP. -+ */ -+ -+#ifndef _UMP_COMMON_H_ -+#define _UMP_COMMON_H_ -+ -+#ifdef __cplusplus -+extern "C" -+{ -+#endif -+ -+#ifdef __KERNEL__ -+#include -+#else -+#include -+#endif -+ -+#define UMP_UINT32_MAX (4294967295U) -+#define UMP_UINT64_MAX (18446744073709551615ULL) -+ -+#ifdef __GNUC__ -+ #define CHECK_RESULT __attribute__((__warn_unused_result__)) -+ #define INLINE __inline__ -+#else -+ #define CHECK_RESULT -+ #define INLINE __inline -+#endif -+ -+#ifndef STATIC -+ #define STATIC static -+#endif -+ -+/** -+ * Values to identify major and minor version of UMP -+ */ -+#define UMP_VERSION_MAJOR 2 -+#define UMP_VERSION_MINOR 0 -+ -+/** -+ * Typedef for a secure ID, a system wide identifier for UMP memory buffers. -+ */ -+typedef int32_t ump_secure_id; -+ -+/** -+ * Value to indicate an invalid secure Id. -+ */ -+#define UMP_INVALID_SECURE_ID ((ump_secure_id)0) -+ -+/** -+ * UMP error codes. -+ */ -+typedef enum -+{ -+ UMP_OK = 0, /**< indicates success */ -+ UMP_ERROR = 1 /**< indicates failure */ -+} ump_result; -+ -+/** -+ * Allocation flag bits. -+ * -+ * ump_allocate accepts zero or more flags to specify the type of memory to allocate and how to expose it to devices. -+ * -+ * For each supported device there are 4 flags to control access permissions and give usage characteristic hints to optimize the allocation/mapping. -+ * They are; -+ * @li @a UMP_PROT__RD read permission -+ * @li @a UMP_PROT__WR write permission -+ * @li @a UMP_HINT__RD read often -+ * @li @a UMP_HINT__WR written often -+ * -+ * 5 devices are currently supported, with a device being the CPU itself. -+ * The other 4 devices will be mapped to real devices per SoC design. -+ * They are just named W,X,Y,Z by UMP as it has no knowledge of their real names/identifiers. -+ * As an example device W could be a camera device while device Z could be an ARM GPU device, leaving X and Y unused. -+ * -+ * 2 additional flags control the allocation; -+ * @li @a UMP_CONSTRAINT_PHYSICALLY_LINEAR the allocation must be physical linear. Typical for devices without an MMU and no IOMMU to help it. -+ * @li @a UMP_PROT_SHAREABLE the allocation can be shared with other processes on the system. Without this flag the returned allocation won't be resolvable in other processes. -+ * -+ * All UMP allocation are growable unless they're @a UMP_PROT_SHAREABLE. -+ * The hint bits should be used to indicate the access pattern so the driver can select the most optimal memory type and cache settings based on the what the system supports. -+ */ -+typedef enum -+{ -+ /* Generic helpers */ -+ UMP_PROT_DEVICE_RD = (1u << 0), -+ UMP_PROT_DEVICE_WR = (1u << 1), -+ UMP_HINT_DEVICE_RD = (1u << 2), -+ UMP_HINT_DEVICE_WR = (1u << 3), -+ UMP_DEVICE_MASK = 0xF, -+ UMP_DEVICE_CPU_SHIFT = 0, -+ UMP_DEVICE_W_SHIFT = 4, -+ UMP_DEVICE_X_SHIFT = 8, -+ UMP_DEVICE_Y_SHIFT = 12, -+ UMP_DEVICE_Z_SHIFT = 16, -+ -+ /* CPU protection and hints. */ -+ UMP_PROT_CPU_RD = (1u << 0), -+ UMP_PROT_CPU_WR = (1u << 1), -+ UMP_HINT_CPU_RD = (1u << 2), -+ UMP_HINT_CPU_WR = (1u << 3), -+ -+ /* device W */ -+ UMP_PROT_W_RD = (1u << 4), -+ UMP_PROT_W_WR = (1u << 5), -+ UMP_HINT_W_RD = (1u << 6), -+ UMP_HINT_W_WR = (1u << 7), -+ -+ /* device X */ -+ UMP_PROT_X_RD = (1u << 8), -+ UMP_PROT_X_WR = (1u << 9), -+ UMP_HINT_X_RD = (1u << 10), -+ UMP_HINT_X_WR = (1u << 11), -+ -+ /* device Y */ -+ UMP_PROT_Y_RD = (1u << 12), -+ UMP_PROT_Y_WR = (1u << 13), -+ UMP_HINT_Y_RD = (1u << 14), -+ UMP_HINT_Y_WR = (1u << 15), -+ -+ /* device Z */ -+ UMP_PROT_Z_RD = (1u << 16), -+ UMP_PROT_Z_WR = (1u << 17), -+ UMP_HINT_Z_RD = (1u << 18), -+ UMP_HINT_Z_WR = (1u << 19), -+ -+ /* 20-26 reserved for future use */ -+ UMPP_ALLOCBITS_UNUSED = (0x7Fu << 20), -+ /** Allocations marked as @ UMP_CONSTRAINT_UNCACHED won't be mapped as cached by the cpu */ -+ UMP_CONSTRAINT_UNCACHED = (1u << 27), -+ /** Require 32-bit physically addressable memory */ -+ UMP_CONSTRAINT_32BIT_ADDRESSABLE = (1u << 28), -+ /** For devices without an MMU and with no IOMMU assistance. */ -+ UMP_CONSTRAINT_PHYSICALLY_LINEAR = (1u << 29), -+ /** Shareable must be set to allow the allocation to be used by other processes, the default is non-shared */ -+ UMP_PROT_SHAREABLE = (1u << 30) -+ /* (1u << 31) should not be used to ensure compiler portability */ -+} ump_allocation_bits; -+ -+/** -+ * ump_allocation_bits combination argument type. -+ * -+ * Type used to pass zero or more bits from the @ref ump_allocation_bits enum -+ */ -+typedef uint32_t ump_alloc_flags; -+ -+ -+/** -+ * Default allocation flags for UMP v1 compatible allocations. -+ */ -+#define UMP_V1_API_DEFAULT_ALLOCATION_FLAGS UMP_PROT_CPU_RD | UMP_PROT_CPU_WR | \ -+ UMP_PROT_W_RD | UMP_PROT_W_WR | \ -+ UMP_PROT_X_RD | UMP_PROT_X_WR | \ -+ UMP_PROT_Y_RD | UMP_PROT_Y_WR | \ -+ UMP_PROT_Z_RD | UMP_PROT_Z_WR | \ -+ UMP_PROT_SHAREABLE | \ -+ UMP_CONSTRAINT_32BIT_ADDRESSABLE -+ -+/** -+ * CPU cache sync operations. -+ * -+ * Cache synchronization operations to pass to @ref ump_cpu_msync_now -+ */ -+enum -+{ -+ /** -+ * Cleans any dirty cache lines to main memory, but the data will still be available in the cache. -+ * After a clean the contents of memory is considered to be "owned" by the device. -+ * */ -+ UMP_MSYNC_CLEAN = 1, -+ -+ /** Cleans any dirty cache lines to main memory and Ejects all lines from the cache. -+ * After an clean&invalidate the contents of memory is considered to be "owned" by the CPU. -+ * Any subsequent access will fetch data from main memory. -+ * -+ * @note Due to CPUs doing speculative prefetching a UMP_MSYNC_CLEAN_AND_INVALIDATE must be done before and after interacting with hardware. -+ * */ -+ UMP_MSYNC_CLEAN_AND_INVALIDATE -+ -+}; -+ -+typedef uint32_t ump_cpu_msync_op; -+ -+/** -+ * Memory import types supported. -+ * If new import types are added they will appear here. -+ * They must be added before UMPP_EXTERNAL_MEM_COUNT and -+ * must be assigned an explicit sequantial number. -+ * -+ * @li UMP_EXTERNAL_MEM_TYPE_ION - Import an ION allocation -+ * Takes a int* (pointer to a file descriptor) -+ * Another ION reference is taken which is released on the final ump_release -+ */ -+enum ump_external_memory_type -+{ -+ UMPP_EXTERNAL_MEM_TYPE_UNUSED = 0, /* reserve type 0 */ -+ UMP_EXTERNAL_MEM_TYPE_ION = 1, -+ UMPP_EXTERNAL_MEM_COUNT -+}; -+ -+/** @name UMP v1 API -+ * -+ *@{ -+ */ -+ -+/** -+ * Allocation constraints. -+ * -+ * Allocation flags to pass @ref ump_ref_drv_allocate -+ * -+ * UMP v1 API only. -+ */ -+typedef enum -+{ -+ /** the allocation is mapped as noncached. */ -+ UMP_REF_DRV_CONSTRAINT_NONE = 0, -+ /** not supported. */ -+ UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR = 1, -+ /** the allocation is mapped as cached by the cpu. */ -+ UMP_REF_DRV_CONSTRAINT_USE_CACHE = 4 -+} ump_alloc_constraints; -+ -+/* @} */ -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+ -+#endif /* _UMP_COMMON_H_ */ -diff --git a/include/linux/ump-import.h b/include/linux/ump-import.h -new file mode 100644 -index 0000000..89ce727 ---- /dev/null -+++ b/include/linux/ump-import.h -@@ -0,0 +1,99 @@ -+/* -+ * -+ * (C) COPYRIGHT 2011-2013 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _UMP_IMPORT_H_ -+#define _UMP_IMPORT_H_ -+ -+#include -+#include -+ -+/** -+ * UMP import module info. -+ * Contains information about the Linux module providing the import module, -+ * used to block unloading of the Linux module while imported memory exists. -+ * Lists the functions implementing the UMP import functions. -+ */ -+struct ump_import_handler -+{ -+ /** -+ * Linux module of the import handler -+ */ -+ struct module * linux_module; -+ -+ /** -+ * UMP session usage begin. -+ * -+ * Called when a UMP session first is bound to the handler. -+ * Typically used to set up any import module specific per-session data. -+ * The function returns a pointer to this data in the output pointer custom_session_data -+ * which will be passed to \a session_end and \a import. -+ * -+ * Note: custom_session_data must be set to non-NULL if successful. -+ * If no pointer is needed set it a magic value to validate instead. -+ * -+ * @param[out] custom_session_data Pointer to a generic pointer where any data can be stored -+ * @return 0 on success, error code if the session could not be initiated. -+ */ -+ int (*session_begin)(void ** custom_session_data); -+ -+ /** -+ * UMP session usage end. -+ * -+ * Called when a UMP session is no longer using the handler. -+ * Only called if @a session_begin returned OK. -+ * -+ * @param[in] custom_session_data The value set by the session_begin handler -+ */ -+ void (*session_end)(void * custom_session_data); -+ -+ /** -+ * Import request. -+ * -+ * Called when a client has asked to import a resource of the type the import module was installed for. -+ * Only called if @a session_begin returned OK. -+ * -+ * The requested flags must be verified to be valid to apply to the imported memory. -+ * If not valid return UMP_DD_INVALID_MEMORY_HANDLE. -+ * If the flags are found to be valid call \a ump_dd_create_from_phys_blocks_64 to create a handle. -+ * -+ * @param[in] custom_session_data The value set by the session_begin handler -+ * @param[in] phandle Pointer to the handle to import -+ * @param flags The requested UMPv2 flags to assign to the imported handle -+ * @return UMP_DD_INVALID_MEMORY_HANDLE if the import failed, a valid ump handle on success -+ */ -+ ump_dd_handle (*import)(void * custom_session_data, void * phandle, ump_alloc_flags flags); -+}; -+ -+/** -+ * Import module registration. -+ * Registers a ump_import_handler structure for a memory type. -+ * @param type Type of the memory to register a handler for -+ * @param[in] handler Handler strcture to install -+ * @return 0 on success, a Linux error code on failure -+ */ -+int ump_import_module_register(enum ump_external_memory_type type, struct ump_import_handler * handler); -+ -+/** -+ * Import module deregistration. -+ * Uninstalls the handler for the given memory type. -+ * @param type Type of the memory to unregister the handler for -+ */ -+void ump_import_module_unregister(enum ump_external_memory_type type); -+ -+#endif /* _UMP_IMPORT_H_ */ -diff --git a/include/linux/ump-ioctl.h b/include/linux/ump-ioctl.h -new file mode 100644 -index 0000000..caf4c0b ---- /dev/null -+++ b/include/linux/ump-ioctl.h -@@ -0,0 +1,152 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013, 2016 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+#ifndef _UMP_IOCTL_H_ -+#define _UMP_IOCTL_H_ -+ -+#include -+ -+/* -+ * The order and size of the members of these have been chosen so the structures look the same in 32-bit and 64-bit builds. -+ * If any changes are done build the ump_struct_size_checker test for 32-bit and 64-bit targets. Both must compile successfully to commit. -+ */ -+ -+/** 32/64-bit neutral way to represent pointers */ -+typedef union ump_pointer -+{ -+ void * value; /**< client should store their pointers here */ -+ uint32_t compat_value; /**< 64-bit kernels should fetch value here when handling 32-bit clients */ -+ uint64_t sizer; /**< Force 64-bit storage for all clients regardless */ -+} ump_pointer; -+ -+/** -+ * UMP allocation request. -+ * Used when performing ump_allocate -+ */ -+typedef struct ump_k_allocate -+{ -+ uint64_t size; /**< [in] Size in bytes to allocate */ -+ ump_secure_id secure_id; /**< [out] Secure ID of allocation on success */ -+ ump_alloc_flags alloc_flags; /**< [in] Flags to use when allocating */ -+} ump_k_allocate; -+ -+/** -+ * UMP size query request. -+ * Used when performing ump_size_get -+ */ -+typedef struct ump_k_sizequery -+{ -+ uint64_t size; /**< [out] Size of allocation */ -+ ump_secure_id secure_id; /**< [in] ID of allocation to query the size of */ -+ uint32_t padding; /* don't remove */ -+} ump_k_sizequery; -+ -+/** -+ * UMP cache synchronization request. -+ * Used when performing ump_cpu_msync_now -+ */ -+typedef struct ump_k_msync -+{ -+ ump_pointer mapped_ptr; /**< [in] CPU VA to perform cache operation on */ -+ ump_secure_id secure_id; /**< [in] ID of allocation to perform cache operation on */ -+ ump_cpu_msync_op cache_operation; /**< [in] Cache operation to perform */ -+ uint64_t size; /**< [in] Size in bytes of the range to synchronize */ -+} ump_k_msync; -+ -+/** -+ * UMP memory retain request. -+ * Used when performing ump_retain -+ */ -+typedef struct ump_k_retain -+{ -+ ump_secure_id secure_id; /**< [in] ID of allocation to retain a reference to */ -+ uint32_t padding; /* don't remove */ -+} ump_k_retain; -+ -+/** -+ * UMP memory release request. -+ * Used when performing ump_release -+ */ -+typedef struct ump_k_release -+{ -+ ump_secure_id secure_id; /**< [in] ID of allocation to release a reference to */ -+ uint32_t padding; /* don't remove */ -+} ump_k_release; -+ -+typedef struct ump_k_import -+{ -+ ump_pointer phandle; /**< [in] Pointer to handle to import */ -+ uint32_t type; /**< [in] Type of handle to import */ -+ ump_alloc_flags alloc_flags; /**< [in] Flags to assign to the imported memory */ -+ ump_secure_id secure_id; /**< [out] UMP ID representing the imported memory */ -+ uint32_t padding; /* don't remove */ -+} ump_k_import; -+ -+/** -+ * UMP allocation flags request. -+ * Used when performing umpp_get_allocation_flags -+ * -+ * used only by v1 API -+ */ -+typedef struct ump_k_allocation_flags -+{ -+ ump_secure_id secure_id; /**< [in] Secure ID of allocation on success */ -+ ump_alloc_flags alloc_flags; /**< [out] Flags to use when allocating */ -+} ump_k_allocation_flags; -+ -+#define UMP_CALL_MAX_SIZE 512 -+/* -+ * Ioctl definitions -+ */ -+ -+/* Use '~' as magic number */ -+ -+#define UMP_IOC_MAGIC '~' -+ -+#define UMP_FUNC_ALLOCATE _IOWR(UMP_IOC_MAGIC, 1, ump_k_allocate) -+#define UMP_FUNC_SIZEQUERY _IOWR(UMP_IOC_MAGIC, 2, ump_k_sizequery) -+#define UMP_FUNC_MSYNC _IOWR(UMP_IOC_MAGIC, 3, ump_k_msync) -+#define UMP_FUNC_RETAIN _IOW(UMP_IOC_MAGIC, 4, ump_k_retain) -+#define UMP_FUNC_RELEASE _IOW(UMP_IOC_MAGIC, 5, ump_k_release) -+#define UMP_FUNC_ALLOCATION_FLAGS_GET _IOWR(UMP_IOC_MAGIC, 6, ump_k_allocation_flags) -+#define UMP_FUNC_IMPORT _IOWR(UMP_IOC_MAGIC, 7, ump_k_import) -+ -+/*max ioctl sequential number*/ -+#define UMP_IOC_MAXNR 7 -+ -+/* 15 bits for the UMP ID (allowing 32768 IDs) */ -+#define UMP_LINUX_ID_BITS 15 -+#define UMP_LINUX_ID_MASK ((1ULL << UMP_LINUX_ID_BITS) - 1ULL) -+ -+/* 64-bit (really 52 bits) encoding: 15 bits for the ID, 37 bits for the offset */ -+#define UMP_LINUX_OFFSET_BITS_64 37 -+#define UMP_LINUX_OFFSET_MASK_64 ((1ULL << UMP_LINUX_OFFSET_BITS_64)-1) -+/* 32-bit encoding: 15 bits for the ID, 17 bits for the offset */ -+#define UMP_LINUX_OFFSET_BITS_32 17 -+#define UMP_LINUX_OFFSET_MASK_32 ((1ULL << UMP_LINUX_OFFSET_BITS_32)-1) -+ -+#if __SIZEOF_LONG__ == 8 -+#define UMP_LINUX_OFFSET_BITS UMP_LINUX_OFFSET_BITS_64 -+#define UMP_LINUX_OFFSET_MASK UMP_LINUX_OFFSET_MASK_64 -+#else -+#define UMP_LINUX_OFFSET_BITS UMP_LINUX_OFFSET_BITS_32 -+#define UMP_LINUX_OFFSET_MASK UMP_LINUX_OFFSET_MASK_32 -+#endif -+ -+#endif /* _UMP_IOCTL_H_ */ -diff --git a/include/linux/ump.h b/include/linux/ump.h -new file mode 100644 -index 0000000..16f9c39 ---- /dev/null -+++ b/include/linux/ump.h -@@ -0,0 +1,481 @@ -+/* -+ * -+ * (C) COPYRIGHT 2008-2013, 2015 ARM Limited. All rights reserved. -+ * -+ * This program is free software and is provided to you under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation, and any use by you of this program is subject to the terms -+ * of such GNU licence. -+ * -+ * A copy of the licence is included with the program, and can also be obtained -+ * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ * Boston, MA 02110-1301, USA. -+ * -+ */ -+ -+ -+ -+ -+ -+/** -+ * @file -+ * -+ * This file contains the kernel space part of the UMP API. -+ * -+ */ -+ -+#ifndef _UMP_KERNEL_INTERFACE_H_ -+#define _UMP_KERNEL_INTERFACE_H_ -+ -+/** -+ * @addtogroup ump_api -+ * @{ -+ */ -+ -+/** @defgroup ump_kernel_space_api UMP Kernel Space API -+ * @{ */ -+ -+/** -+ * External representation of a UMP handle in kernel space. -+ */ -+typedef void * ump_dd_handle; -+ -+#ifdef CONFIG_KDS -+#include -+#endif -+ -+#include -+ -+#define UMP_KERNEL_API_EXPORT -+ -+#if defined(__KERNEL__) -+#include -+#else -+#include -+#endif -+ -+#ifdef __cplusplus -+extern "C" -+{ -+#endif -+ -+/** -+ * Value to indicate an invalid UMP memory handle. -+ */ -+#define UMP_DD_INVALID_MEMORY_HANDLE ((ump_dd_handle)0) -+ -+/** -+ * Struct used to describe a physical block used by UMP memory -+ */ -+typedef struct ump_dd_physical_block_64 -+{ -+ uint64_t addr; /**< The physical address of the block */ -+ uint64_t size; /**< The length of the block, in bytes, typically page aligned */ -+} ump_dd_physical_block_64; -+ -+/** -+ * Security filter hook. -+ * -+ * Each allocation can have a security filter attached to it.@n -+ * The hook receives -+ * @li the secure ID -+ * @li a handle to the allocation -+ * @li the callback_data argument provided to @ref ump_dd_allocate_64 or @ref ump_dd_create_from_phys_blocks_64 -+ * -+ * The hook must return @a true to indicate that access to the handle is allowed or @n -+ * @a false to state that no access is permitted.@n -+ * This hook is guaranteed to be called in the context of the requesting process/address space. -+ * -+ * The arguments provided to the hook are; -+ * @li the secure ID -+ * @li handle to the allocation -+ * @li the callback_data set when registering the hook -+ * -+ * Return value; -+ * @li @a true to permit access -+ * @li @a false to deny access -+ */ -+typedef bool (*ump_dd_security_filter)(ump_secure_id, ump_dd_handle, void *); -+ -+/** -+ * Final release notify hook. -+ * -+ * Allocations can have a hook attached to them which is called when the last reference to the allocation is released. -+ * No reference count manipulation is allowed on the provided handle, just property querying (ID get, size get, phys block get). -+ * This is similar to finalizers in OO languages. -+ * -+ * The arguments provided to the hook are; -+ * * handle to the allocation -+ * * the callback_data set when registering the hook -+ */ -+typedef void (*ump_dd_final_release_callback)(const ump_dd_handle, void *); -+ -+/** -+ * Allocate a buffer. -+ * The lifetime of the allocation is controlled by a reference count. -+ * The reference count of the returned buffer is set to 1. -+ * The memory will be freed once the reference count reaches 0. -+ * Use @ref ump_dd_retain and @ref ump_dd_release to control the reference count. -+ * @param size Number of bytes to allocate. Will be padded up to a multiple of the page size. -+ * @param flags Bit-wise OR of zero or more of the allocation flag bits. -+ * @param[in] filter_func Pointer to a function which will be called when an allocation is required from a -+ * secure id before the allocation itself is returned to user-space. -+ * NULL permitted if no need for a callback. -+ * @param[in] final_release_func Pointer to a function which will be called when the last reference is removed, -+ * just before the allocation is freed. NULL permitted if no need for a callback. -+ * @param[in] callback_data An opaque pointer which will be provided to @a filter_func and @a final_release_func -+ * @return Handle to the new allocation, or @a UMP_DD_INVALID_MEMORY_HANDLE on allocation failure. -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_allocate_64(uint64_t size, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data); -+ -+ -+/** -+ * Allocation bits getter. -+ * Retrieves the allocation flags used when instantiating the given handle. -+ * Just a copy of the flag given to @ref ump_dd_allocate_64 and @ref ump_dd_create_from_phys_blocks_64 -+ * @param mem The handle retrieve the bits for -+ * @return The allocation bits used to instantiate the allocation -+ */ -+UMP_KERNEL_API_EXPORT ump_alloc_flags ump_dd_allocation_flags_get(const ump_dd_handle mem); -+ -+ -+/** -+ * Retrieves the secure ID for the specified UMP memory. -+ * -+ * This identifier is unique across the entire system, and uniquely identifies -+ * the specified UMP memory allocation. This identifier can later be used through the -+ * @ref ump_dd_from_secure_id or -+ * @ref ump_from_secure_id -+ * functions in order to access this UMP memory, for instance from another process (if shared of course). -+ * Unless the allocation was marked as shared the returned ID will only be resolvable in the same process as did the allocation. -+ * -+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE will result in undefined behavior. -+ * Debug builds will assert on this. -+ * -+ * @note There is a user space equivalent function called @ref ump_secure_id_get -+ * -+ * @see ump_dd_from_secure_id -+ * @see ump_from_secure_id -+ * @see ump_secure_id_get -+ * -+ * @param mem Handle to UMP memory. -+ * -+ * @return Returns the secure ID for the specified UMP memory. -+ */ -+UMP_KERNEL_API_EXPORT ump_secure_id ump_dd_secure_id_get(const ump_dd_handle mem); -+ -+#ifdef CONFIG_KDS -+/** -+ * Retrieve the KDS resource for the specified UMP memory. -+ * -+ * The KDS resource should be used to synchronize access to the UMP allocation. -+ * See the KDS API for how to do that. -+ * -+ * @param mem Handle to the UMP memory to query. -+ * @return Pointer to the KDS resource controlling access to the UMP memory. -+ */ -+UMP_KERNEL_API_EXPORT struct kds_resource * ump_dd_kds_resource_get(const ump_dd_handle mem); -+#endif -+ -+/** -+ * Retrieves a handle to allocated UMP memory. -+ * -+ * The usage of UMP memory is reference counted, so this will increment the reference -+ * count by one for the specified UMP memory. -+ * Use @ref ump_dd_release when there is no longer any -+ * use for the retrieved handle. -+ * -+ * If called on an non-shared allocation and this is a different process @a UMP_DD_INVALID_MEMORY_HANDLE will be returned. -+ * -+ * Calling on an @a UMP_INVALID_SECURE_ID will return @a UMP_DD_INVALID_MEMORY_HANDLE -+ * -+ * @note There is a user space equivalent function called @ref ump_from_secure_id -+ * -+ * @see ump_dd_release -+ * @see ump_from_secure_id -+ * -+ * @param secure_id The secure ID of the UMP memory to open, that can be retrieved using the @ref ump_secure_id_get function. -+ * -+ * @return @a UMP_DD_INVALID_MEMORY_HANDLE indicates failure, otherwise a valid handle is returned. -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_from_secure_id(ump_secure_id secure_id); -+ -+ -+/** -+ * Retrieves all physical memory block information for specified UMP memory. -+ * -+ * This function can be used by other device drivers in order to create MMU tables. -+ * This function will return a pointer to an array of @ref ump_dd_physical_block_64 in @a pArray and the number of array elements in @a pCount -+ * -+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE results in undefined behavior. -+ * Debug builds will assert on this. -+ * -+ * @param mem Handle to UMP memory. -+ * @param[out] pCount Pointer to where to store the number of items in the returned array -+ * @param[out] pArray Pointer to where to store a pointer to the physical blocks array -+ */ -+UMP_KERNEL_API_EXPORT void ump_dd_phys_blocks_get_64(const ump_dd_handle mem, uint64_t * const pCount, const ump_dd_physical_block_64 ** const pArray); -+ -+/** -+ * Retrieves the actual size of the specified UMP memory. -+ * -+ * The size is reported in bytes, and is typically page aligned. -+ * -+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE results in undefined behavior. -+ * Debug builds will assert on this. -+ * -+ * @note There is a user space equivalent function called @ref ump_size_get -+ * -+ * @see ump_size_get -+ * -+ * @param mem Handle to UMP memory. -+ * -+ * @return Returns the allocated size of the specified UMP memory, in bytes. -+ */ -+UMP_KERNEL_API_EXPORT uint64_t ump_dd_size_get_64(const ump_dd_handle mem); -+ -+ -+/** -+ * Adds an extra reference to the specified UMP memory allocation. -+ * -+ * The function @ref ump_dd_release must then be used -+ * to release each copy of the UMP memory handle. -+ * -+ * Calling on an @a UMP_DD_INVALID_MEMORY_HANDLE results in undefined behavior. -+ * Debug builds will assert on this. -+ * -+ * @note You are not required to call @ref ump_dd_retain -+ * for UMP handles returned from -+ * @ref ump_dd_from_secure_id, -+ * because these handles are already reference counted by this function. -+ * -+ * @note There is a user space equivalent function called @ref ump_retain -+ * -+ * @see ump_retain -+ * -+ * @param mem Handle to UMP memory. -+ * @return 0 indicates success, any other value indicates failure. -+ */ -+UMP_KERNEL_API_EXPORT int ump_dd_retain(ump_dd_handle mem); -+ -+ -+/** -+ * Releases a reference from the specified UMP memory. -+ * -+ * This function must be called once for every reference to the UMP memory handle. -+ * When the last reference is released, all resources associated with this UMP memory -+ * handle are freed. -+ * -+ * One can only call ump_release when matched with a successful ump_dd_retain, ump_dd_allocate_64 or ump_dd_from_secure_id -+ * If called on an @a UMP_DD_INVALID_MEMORY_HANDLE the function will early out. -+ * -+ * @note There is a user space equivalent function called @ref ump_release -+ * -+ * @see ump_release -+ * -+ * @param mem Handle to UMP memory. -+ */ -+UMP_KERNEL_API_EXPORT void ump_dd_release(ump_dd_handle mem); -+ -+/** -+ * Create an ump allocation handle based on externally managed memory. -+ * Used to wrap an existing allocation as an UMP memory handle. -+ * Once wrapped the memory acts just like a normal allocation coming from @ref ump_dd_allocate_64. -+ * The only exception is that the freed physical memory is not put into the pool of free memory, but instead considered returned to the caller once @a final_release_func returns. -+ * The blocks array will be copied, so no need to hold on to it after this function returns. -+ * @param[in] blocks Array of @ref ump_dd_physical_block_64 -+ * @param num_blocks Number of elements in the array pointed to by @a blocks -+ * @param flags Allocation flags to mark the handle with -+ * @param[in] filter_func Pointer to a function which will be called when an allocation is required from a secure id before the allocation itself is returned to user-space. -+ * NULL permitted if no need for a callback. -+ * @param[in] final_release_func Pointer to a function which will be called when the last reference is removed, just before the allocation is freed. NULL permitted if no need for a callback. -+ * @param[in] callback_data An opaque pointer which will be provided to @a filter_func and @a final_release_func -+ * @return Handle to the UMP allocation handle created, or @a UMP_DD_INVALID_MEMORY_HANDLE if no such handle could be created. -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_create_from_phys_blocks_64(const ump_dd_physical_block_64 * blocks, uint64_t num_blocks, ump_alloc_flags flags, ump_dd_security_filter filter_func, ump_dd_final_release_callback final_release_func, void* callback_data); -+ -+ -+/** @name UMP v1 API -+ * Functions provided to support compatibility with UMP v1 API -+ * -+ *@{ -+ */ -+ -+/** -+ * Value to indicate an invalid UMP memory handle. -+ */ -+#define UMP_DD_HANDLE_INVALID UMP_DD_INVALID_MEMORY_HANDLE -+ -+/** -+ * UMP error codes for kernel space. -+ */ -+typedef enum -+{ -+ UMP_DD_SUCCESS, /**< indicates success */ -+ UMP_DD_INVALID /**< indicates failure */ -+} ump_dd_status_code; -+ -+ -+/** -+ * Struct used to describe a physical block used by UMP memory -+ */ -+typedef struct ump_dd_physical_block -+{ -+ unsigned long addr; /**< The physical address of the block */ -+ unsigned long size; /**< The length of the block, typically page aligned */ -+} ump_dd_physical_block; -+ -+ -+/** -+ * Retrieves a handle to allocated UMP memory. -+ * -+ * The usage of UMP memory is reference counted, so this will increment the reference -+ * count by one for the specified UMP memory. -+ * Use @ref ump_dd_reference_release "ump_dd_reference_release" when there is no longer any -+ * use for the retrieved handle. -+ * -+ * @note There is a user space equivalent function called @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id" -+ * -+ * @see ump_dd_reference_release -+ * @see ump_handle_create_from_secure_id -+ * -+ * @param secure_id The secure ID of the UMP memory to open, that can be retrieved using the @ref ump_secure_id_get "ump_secure_id_get " function. -+ * -+ * @return UMP_INVALID_MEMORY_HANDLE indicates failure, otherwise a valid handle is returned. -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id); -+ -+ -+ -+/** -+ * Create an ump allocation handle based on externally managed memory. -+ * Used to wrap an existing allocation as an UMP memory handle. -+ * -+ * @param[in] blocks Array of @ref ump_dd_physical_block -+ * @param num_blocks Number of elements in the array pointed to by @a blocks -+ * -+ * @return Handle to the UMP allocation handle created, or @a UMP_DD_INVALID_MEMORY_HANDLE if no such handle could be created. -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks); -+ -+ -+/** -+ * Retrieves the number of physical blocks used by the specified UMP memory. -+ * -+ * This function retrieves the number of @ref ump_dd_physical_block "ump_dd_physical_block" structs needed -+ * to describe the physical memory layout of the given UMP memory. This can later be used when calling -+ * the functions @ref ump_dd_phys_blocks_get "ump_dd_phys_blocks_get" and -+ * @ref ump_dd_phys_block_get "ump_dd_phys_block_get". -+ * -+ * @see ump_dd_phys_blocks_get -+ * @see ump_dd_phys_block_get -+ * -+ * @param mem Handle to UMP memory. -+ * -+ * @return The number of ump_dd_physical_block structs required to describe the physical memory layout of the specified UMP memory. -+ */ -+UMP_KERNEL_API_EXPORT unsigned long ump_dd_phys_block_count_get(ump_dd_handle mem); -+ -+ -+/** -+ * Retrieves all physical memory block information for specified UMP memory. -+ * -+ * This function can be used by other device drivers in order to create MMU tables. -+ * -+ * @note This function will fail if the num_blocks parameter is either to large or to small. -+ * -+ * @see ump_dd_phys_block_get -+ * -+ * @param mem Handle to UMP memory. -+ * @param blocks An array of @ref ump_dd_physical_block "ump_dd_physical_block" structs that will receive the physical description. -+ * @param num_blocks The number of blocks to return in the blocks array. Use the function -+ * @ref ump_dd_phys_block_count_get "ump_dd_phys_block_count_get" first to determine the number of blocks required. -+ * -+ * @return UMP_DD_SUCCESS indicates success, UMP_DD_INVALID indicates failure. -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle mem, ump_dd_physical_block * const blocks, unsigned long num_blocks); -+ -+ -+/** -+ * Retrieves the physical memory block information for specified block for the specified UMP memory. -+ * -+ * This function can be used by other device drivers in order to create MMU tables. -+ * -+ * @note This function will return UMP_DD_INVALID if the specified index is out of range. -+ * -+ * @see ump_dd_phys_blocks_get -+ * -+ * @param mem Handle to UMP memory. -+ * @param index Which physical info block to retrieve. -+ * @param block Pointer to a @ref ump_dd_physical_block "ump_dd_physical_block" struct which will receive the requested information. -+ * -+ * @return UMP_DD_SUCCESS indicates success, UMP_DD_INVALID indicates failure. -+ */ -+UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle mem, unsigned long index, ump_dd_physical_block * const block); -+ -+ -+/** -+ * Retrieves the actual size of the specified UMP memory. -+ * -+ * The size is reported in bytes, and is typically page aligned. -+ * -+ * @note There is a user space equivalent function called @ref ump_size_get "ump_size_get" -+ * -+ * @see ump_size_get -+ * -+ * @param mem Handle to UMP memory. -+ * -+ * @return Returns the allocated size of the specified UMP memory, in bytes. -+ */ -+UMP_KERNEL_API_EXPORT unsigned long ump_dd_size_get(ump_dd_handle mem); -+ -+ -+/** -+ * Adds an extra reference to the specified UMP memory. -+ * -+ * This function adds an extra reference to the specified UMP memory. This function should -+ * be used every time a UMP memory handle is duplicated, that is, assigned to another ump_dd_handle -+ * variable. The function @ref ump_dd_reference_release "ump_dd_reference_release" must then be used -+ * to release each copy of the UMP memory handle. -+ * -+ * @note You are not required to call @ref ump_dd_reference_add "ump_dd_reference_add" -+ * for UMP handles returned from -+ * @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id", -+ * because these handles are already reference counted by this function. -+ * -+ * @note There is a user space equivalent function called @ref ump_reference_add "ump_reference_add" -+ * -+ * @see ump_reference_add -+ * -+ * @param mem Handle to UMP memory. -+ */ -+UMP_KERNEL_API_EXPORT void ump_dd_reference_add(ump_dd_handle mem); -+ -+ -+/** -+ * Releases a reference from the specified UMP memory. -+ * -+ * This function should be called once for every reference to the UMP memory handle. -+ * When the last reference is released, all resources associated with this UMP memory -+ * handle are freed. -+ * -+ * @note There is a user space equivalent function called @ref ump_reference_release "ump_reference_release" -+ * -+ * @see ump_reference_release -+ * -+ * @param mem Handle to UMP memory. -+ */ -+UMP_KERNEL_API_EXPORT void ump_dd_reference_release(ump_dd_handle mem); -+ -+/* @} */ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+ -+/** @} */ /* end group ump_kernel_space_api */ -+ -+/** @} */ /* end group ump_api */ -+ -+#endif /* _UMP_KERNEL_INTERFACE_H_ */ -diff --git a/drivers/gpu/arm/Kbuild b/drivers/gpu/arm/Kbuild -new file mode 100644 -index 0000000..19c7e9a ---- /dev/null -+++ b/drivers/gpu/arm/Kbuild -@@ -0,0 +1,17 @@ -+# -+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+obj-$(CONFIG_MALI_MIDGARD) += midgard/ -diff --git a/drivers/gpu/arm/Kconfig b/drivers/gpu/arm/Kconfig -new file mode 100644 -index 0000000..1f30eb5 ---- /dev/null -+++ b/drivers/gpu/arm/Kconfig -@@ -0,0 +1,19 @@ -+# -+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved. -+# -+# This program is free software and is provided to you under the terms of the -+# GNU General Public License version 2 as published by the Free Software -+# Foundation, and any use by you of this program is subject to the terms -+# of such GNU licence. -+# -+# A copy of the licence is included with the program, and can also be obtained -+# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+# Boston, MA 02110-1301, USA. -+# -+# -+ -+ -+ -+menu "ARM GPU Configuration" -+source "drivers/gpu/arm/midgard/Kconfig" -+endmenu diff --git a/buildroot-external/board/asus/tinker/patches/linux/0001-Mali-midgard-r19p0-fixes-for-4.13-kernels.patch b/buildroot-external/board/asus/tinker/patches/linux/0001-Mali-midgard-r19p0-fixes-for-4.13-kernels.patch deleted file mode 100644 index 918aad4e2..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0001-Mali-midgard-r19p0-fixes-for-4.13-kernels.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 7ba71967a2678e119bcd819ac92d08bd038e1879 Mon Sep 17 00:00:00 2001 -From: Myy -Date: Mon, 17 Jul 2017 18:34:33 +0000 -Subject: [PATCH 5/5] Mali midgard r19p0 fixes for 4.13 kernels - -Mostly due to DMA structure members renamed, and some signatures -modifications done during the development of Linux 4.11. - -* mm, fs: reduce fault, page_mkwrite, and pfn_mkwrite to take only vmf - 11bac80004499ea59f361ef2a5516c84b6eab675 - v4.11-rc1 - -* sched/headers: Move task->mm handling methods to - 68e21be2916b359fd8afb536c1911dc014cfd03e - v4.11-rc1 - -* sched/headers: Move task-stack related APIs from to - - f3ac60671954c8d413532627b1be13a76f394c49 - v4.11-rc1 - -* dma-fence: Introduce drm_fence_set_error() helper - a009e975da5c7d42a7f5eaadc54946eb5f76c9af - v4.11-rc1 - -Signed-off-by: Myy ---- - drivers/gpu/arm/midgard/mali_kbase.h | 4 ++++ - drivers/gpu/arm/midgard/mali_kbase_fence.h | 4 ++++ - drivers/gpu/arm/midgard/mali_kbase_mem_linux.c | 6 ++++++ - drivers/gpu/arm/midgard/mali_kbase_sync_file.c | 12 ++++++++++++ - 4 files changed, 26 insertions(+) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase.h b/drivers/gpu/arm/midgard/mali_kbase.h -index d77f186..5ee47c4 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase.h -+++ b/drivers/gpu/arm/midgard/mali_kbase.h -@@ -35,6 +35,10 @@ - #include - #include - #include -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -+#include -+#include -+#endif - #include - #include - #include -diff --git a/drivers/gpu/arm/midgard/mali_kbase_fence.h b/drivers/gpu/arm/midgard/mali_kbase_fence.h -index 8d39299..3c2e3a9 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_fence.h -+++ b/drivers/gpu/arm/midgard/mali_kbase_fence.h -@@ -134,7 +134,11 @@ static inline bool kbase_fence_out_is_ours(struct kbase_jd_atom *katom) - static inline int kbase_fence_out_signal(struct kbase_jd_atom *katom, - int status) - { -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) - katom->dma_fence.fence->status = status; -+#else -+ katom->dma_fence.fence->error = status; -+#endif - return dma_fence_signal(katom->dma_fence.fence); - } - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c -index b1f2c46..896aa35 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem_linux.c -@@ -1788,8 +1788,14 @@ static void kbase_cpu_vm_close(struct vm_area_struct *vma) - KBASE_EXPORT_TEST_API(kbase_cpu_vm_close); - - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) - static int kbase_cpu_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) - { -+#else -+static int kbase_cpu_vm_fault(struct vm_fault *vmf) -+{ -+ struct vm_area_struct *vma = vmf->vma; -+#endif - struct kbase_cpu_mapping *map = vma->vm_private_data; - pgoff_t rel_pgoff; - size_t i; -diff --git a/drivers/gpu/arm/midgard/mali_kbase_sync_file.c b/drivers/gpu/arm/midgard/mali_kbase_sync_file.c -index 4e1621c..d84a54e 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_sync_file.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_sync_file.c -@@ -161,8 +161,13 @@ static void kbase_fence_wait_callback(struct dma_fence *fence, - struct kbase_context *kctx = katom->kctx; - - /* Cancel atom if fence is erroneous */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) - if (dma_fence_is_signaled(kcb->fence) && kcb->fence->status < 0) - katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+#else -+ if (dma_fence_is_signaled(kcb->fence) && kcb->fence->error < 0) -+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED; -+#endif - - if (kbase_fence_dep_count_dec_and_test(katom)) { - /* We take responsibility of handling this */ -@@ -273,10 +278,17 @@ static void kbase_sync_fence_info_get(struct dma_fence *fence, - * 1 : signaled - */ - if (dma_fence_is_signaled(fence)) { -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) - if (fence->status < 0) - info->status = fence->status; /* signaled with error */ - else - info->status = 1; /* signaled with success */ -+#else -+ if (fence->error < 0) -+ info->status = fence->error; /* signaled with error */ -+ else -+ info->status = 1; /* signaled with success */ -+#endif - } else { - info->status = 0; /* still active (unsignaled) */ - } --- -2.10.2 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0002-Using-the-new-header-on-4.12-kernels-for-copy_-_user.patch b/buildroot-external/board/asus/tinker/patches/linux/0002-Using-the-new-header-on-4.12-kernels-for-copy_-_user.patch deleted file mode 100644 index 8a22b6d5d..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0002-Using-the-new-header-on-4.12-kernels-for-copy_-_user.patch +++ /dev/null @@ -1,36 +0,0 @@ -From f76c9c58669a3bba0456191431be558ab8054f50 Mon Sep 17 00:00:00 2001 -From: Myy -Date: Mon, 17 Jul 2017 11:43:00 +0000 -Subject: [PATCH 3/5] Using the new header on 4.12 kernels for copy_*_user - -These changes are due to : -* generic ...copy_..._user primitives - d597580d373774b1bdab84b3d26ff0b55162b916 - Version : 4.12-rc1 - -Signed-off-by: Myy ---- - drivers/base/ump/src/linux/ump_kernel_linux.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/drivers/base/ump/src/linux/ump_kernel_linux.c b/drivers/base/ump/src/linux/ump_kernel_linux.c -index d6c3c53..bb3a7f0 100644 ---- a/drivers/base/ump/src/linux/ump_kernel_linux.c -+++ b/drivers/base/ump/src/linux/ump_kernel_linux.c -@@ -20,7 +20,12 @@ - #include - #include - --#include /* copy_*_user */ -+#include -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0) -+#include /* copy_*_user */ -+#else -+#include /* copy_*_user */ -+#endif - #include - #include /* kernel module definitions */ - #include /* file system operations */ --- -2.10.2 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0003-Adapt-get_user_pages-calls-to-use-the-new-calling-pr.patch b/buildroot-external/board/asus/tinker/patches/linux/0003-Adapt-get_user_pages-calls-to-use-the-new-calling-pr.patch deleted file mode 100644 index d9f57ffd5..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0003-Adapt-get_user_pages-calls-to-use-the-new-calling-pr.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 63c110cdebc2c692964e1250c6f74f9e8c47c85d Mon Sep 17 00:00:00 2001 -From: Myy -Date: Tue, 10 Jan 2017 04:28:48 +0000 -Subject: [PATCH 4/5] Adapt get_user_pages calls to use the new calling - procedure - -These changes are due to this commit: -mm: replace get_user_pages_remote() write/force parameters with gup_flags -9beae1ea89305a9667ceaab6d0bf46a045ad71e7 -Kernel: 4.9.0-rc - -Signed-off-by: Myy ---- - drivers/base/ump/src/linux/ump_kernel_linux_mem.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/base/ump/src/linux/ump_kernel_linux_mem.c b/drivers/base/ump/src/linux/ump_kernel_linux_mem.c -index 9186dd0..def4c0e 100644 ---- a/drivers/base/ump/src/linux/ump_kernel_linux_mem.c -+++ b/drivers/base/ump/src/linux/ump_kernel_linux_mem.c -@@ -35,6 +35,10 @@ - #include - #include - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0)) -+#include -+#endif -+ - static void umpp_vm_close(struct vm_area_struct *vma) - { - umpp_cpu_mapping * mapping; -@@ -222,7 +226,11 @@ int umpp_linux_mmap(struct file * filp, struct vm_area_struct * vma) - paddr = alloc->block_array[block_idx].addr; - } - -+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4,4,0)) - err = vm_insert_mixed(vma, vma->vm_start + (i << PAGE_SHIFT), paddr >> PAGE_SHIFT); -+#else -+ err = vm_insert_mixed(vma, vma->vm_start + (i << PAGE_SHIFT), __pfn_to_pfn_t(paddr >> PAGE_SHIFT, PFN_DEV)); -+#endif - paddr += PAGE_SIZE; - } - --- -2.10.2 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0004-Don-t-be-TOO-severe-when-looking-for-the-IRQ-names.patch b/buildroot-external/board/asus/tinker/patches/linux/0004-Don-t-be-TOO-severe-when-looking-for-the-IRQ-names.patch deleted file mode 100644 index 114f4bbfa..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0004-Don-t-be-TOO-severe-when-looking-for-the-IRQ-names.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7c27055687c595e9f9eca484314f4fe3866a4260 Mon Sep 17 00:00:00 2001 -From: Myy -Date: Tue, 18 Jul 2017 17:35:16 +0000 -Subject: [PATCH 2/2] Don't be TOO severe when looking for the IRQ names - -Using strncmp with an all caps result in the driver being unable to -initialize itself when using the mainlined RK3288 DTS files, since they -define the IRQ names as "job", "mmu" and "gpu" instead of "JOB", "MMU" -and "GPU". - -strncmp calls have been replaced by strncasecmp calls in order to -avoid such issue. - -Signed-off-by: Myy ---- - drivers/gpu/arm/midgard/mali_kbase_core_linux.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -index 0cccb0b..9cc65d2 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -@@ -938,11 +938,11 @@ static int assign_irqs(struct platform_device *pdev) - } - - #ifdef CONFIG_OF -- if (!strncmp(irq_res->name, "JOB", 4)) { -+ if (!strncasecmp(irq_res->name, "JOB", 4)) { - irqtag = JOB_IRQ_TAG; -- } else if (!strncmp(irq_res->name, "MMU", 4)) { -+ } else if (!strncasecmp(irq_res->name, "MMU", 4)) { - irqtag = MMU_IRQ_TAG; -- } else if (!strncmp(irq_res->name, "GPU", 4)) { -+ } else if (!strncasecmp(irq_res->name, "GPU", 4)) { - irqtag = GPU_IRQ_TAG; - } else { - dev_err(&pdev->dev, "Invalid irq res name: '%s'\n", --- -2.10.2 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0005-Added-the-new-compatible-list-mainly-used-by-Rockchi.patch b/buildroot-external/board/asus/tinker/patches/linux/0005-Added-the-new-compatible-list-mainly-used-by-Rockchi.patch deleted file mode 100644 index 8515f76ec..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0005-Added-the-new-compatible-list-mainly-used-by-Rockchi.patch +++ /dev/null @@ -1,42 +0,0 @@ -From ef7689887c31d2b1336e14f2c089185e8f60a9f1 Mon Sep 17 00:00:00 2001 -From: Myy -Date: Mon, 7 Aug 2017 19:22:39 +0000 -Subject: [PATCH] Added the new "compatible" list, mainly used by Rockchip - -Because, you know, all the Mali Midgard GPU used to define the GPU -using the 'compatible = "arm,mali-midgard"' property, which worked fine. - -But it was removed. - -They replaced the "arm,mali-midgard" node by "arm,mali-tXXX" where XXX -is the GPU series, and added "arm,rk3288-mali" which is used by nothing. - -Which broke the Mali Midgard GPL kernel driver. - -This patch fixes this issue. - -Signed-off-by: Myy ---- - drivers/gpu/arm/midgard/mali_kbase_core_linux.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -index 27dcd9c1..cc4932a4 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -@@ -4742,6 +4742,12 @@ static const struct dev_pm_ops kbase_pm_ops = { - static const struct of_device_id kbase_dt_ids[] = { - { .compatible = "arm,malit6xx" }, - { .compatible = "arm,mali-midgard" }, -+ { .compatible = "arm,mali-t720" }, -+ { .compatible = "arm,mali-t760" }, -+ { .compatible = "arm,mali-t820" }, -+ { .compatible = "arm,mali-t830" }, -+ { .compatible = "arm,mali-t860" }, -+ { .compatible = "arm,mali-t880" }, - { /* sentinel */ } - }; - MODULE_DEVICE_TABLE(of, kbase_dt_ids); --- -2.13.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0006-gpu-arm-Midgard-setup_timer-timer_setup.patch b/buildroot-external/board/asus/tinker/patches/linux/0006-gpu-arm-Midgard-setup_timer-timer_setup.patch deleted file mode 100644 index 147591204..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0006-gpu-arm-Midgard-setup_timer-timer_setup.patch +++ /dev/null @@ -1,98 +0,0 @@ -From ee7f0a678fff8316ec0be973f1b3780a63f50942 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Mon, 11 Dec 2017 21:04:56 +0100 -Subject: [PATCH] gpu: arm: Midgard: setup_timer() -> timer_setup() - -This patch is due the changes provoked by series of commit ending -at 513ae785c63c30741e46f43960213d4ae5382ec0, and removing the -setup_timer macros. -The previous patches replaced made sure that timers were all set -up with setup_timer and replaced setup_timer calls by timer_setup -calls. - -This changed was introduced in the 4.15-rc1. - -Signed-off-by: Myy Miouyouyou ---- - drivers/gpu/arm/midgard/mali_kbase.h | 2 +- - drivers/gpu/arm/midgard/mali_kbase_context.c | 4 ++-- - drivers/gpu/arm/midgard/mali_kbase_softjobs.c | 4 ++-- - drivers/gpu/arm/midgard/mali_kbase_tlstream.c | 6 ++---- - 4 files changed, 7 insertions(+), 9 deletions(-) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase.h b/drivers/gpu/arm/midgard/mali_kbase.h -index a4ceab9e0..27bde3b71 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase.h -+++ b/drivers/gpu/arm/midgard/mali_kbase.h -@@ -213,7 +213,7 @@ int kbase_soft_event_update(struct kbase_context *kctx, - - bool kbase_replay_process(struct kbase_jd_atom *katom); - --void kbasep_soft_job_timeout_worker(unsigned long data); -+void kbasep_soft_job_timeout_worker(struct timer_list *t); - void kbasep_complete_triggered_soft_events(struct kbase_context *kctx, u64 evt); - - /* api used internally for register access. Contains validation and tracing */ -diff --git a/drivers/gpu/arm/midgard/mali_kbase_context.c b/drivers/gpu/arm/midgard/mali_kbase_context.c -index f43db48fd..589df768c 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_context.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_context.c -@@ -165,9 +165,9 @@ kbase_create_context(struct kbase_device *kbdev, bool is_compat) - - mutex_init(&kctx->vinstr_cli_lock); - -- setup_timer(&kctx->soft_job_timeout, -+ timer_setup(&kctx->soft_job_timeout, - kbasep_soft_job_timeout_worker, -- (uintptr_t)kctx); -+ 0); - - return kctx; - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_softjobs.c b/drivers/gpu/arm/midgard/mali_kbase_softjobs.c -index 127ada07f..019edf562 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_softjobs.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_softjobs.c -@@ -370,9 +370,9 @@ static void kbase_fence_debug_timeout(struct kbase_jd_atom *katom) - } - #endif /* CONFIG_MALI_FENCE_DEBUG */ - --void kbasep_soft_job_timeout_worker(unsigned long data) -+void kbasep_soft_job_timeout_worker(struct timer_list *t) - { -- struct kbase_context *kctx = (struct kbase_context *)data; -+ struct kbase_context *kctx = from_timer(kctx, t, soft_job_timeout); - u32 timeout_ms = (u32)atomic_read( - &kctx->kbdev->js_data.soft_job_timeout_ms); - struct timer_list *timer = &kctx->soft_job_timeout; -diff --git a/drivers/gpu/arm/midgard/mali_kbase_tlstream.c b/drivers/gpu/arm/midgard/mali_kbase_tlstream.c -index d01aa23b2..11d8b59c7 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_tlstream.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_tlstream.c -@@ -1042,13 +1042,11 @@ static void kbasep_tlstream_flush_stream(enum tl_stream_type stype) - * Timer is executed periodically to check if any of the stream contains - * buffer ready to be submitted to user space. - */ --static void kbasep_tlstream_autoflush_timer_callback(unsigned long data) -+static void kbasep_tlstream_autoflush_timer_callback(struct timer_list *unused) - { - enum tl_stream_type stype; - int rcode; - -- CSTD_UNUSED(data); -- - for (stype = 0; stype < TL_STREAM_TYPE_COUNT; stype++) { - struct tl_stream *stream = tl_stream[stype]; - unsigned long flags; -@@ -1371,7 +1369,7 @@ int kbase_tlstream_init(void) - - /* Initialize autoflush timer. */ - atomic_set(&autoflush_timer_active, 0); -- setup_timer(&autoflush_timer, -+ timer_setup(&autoflush_timer, - kbasep_tlstream_autoflush_timer_callback, - 0); - --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0007-drivers-gpu-Arm-Midgard-Replace-ACCESS_ONCE-by-READ_.patch b/buildroot-external/board/asus/tinker/patches/linux/0007-drivers-gpu-Arm-Midgard-Replace-ACCESS_ONCE-by-READ_.patch deleted file mode 100644 index 0cf8cea36..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0007-drivers-gpu-Arm-Midgard-Replace-ACCESS_ONCE-by-READ_.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 44a5ba2e969adfb64c84f294c16490194988dcc7 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Sun, 24 Dec 2017 19:30:12 +0100 -Subject: [PATCH] drivers: gpu: Arm: Midgard: Replace ACCESS_ONCE by READ_ONCE - -The ACCESS_ONCE macro has now been removed in the 4.15.0-rc4, -and every ACCESS_ONCE call has been replaced by either READ_ONCE or -WRITE_ONCE calls. -Since the Midgard GPU drivers are not mainlined, the change -needs to be applied manually. - -See commit b899a850431e2dd0943205a63a68573f3e312d0d and its parents, -for more informations. - -Signed-off-by: Myy Miouyouyou ---- - drivers/gpu/arm/midgard/mali_kbase_mem.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_mem.h b/drivers/gpu/arm/midgard/mali_kbase_mem.h -index e9a8d5dd6..eac685699 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_mem.h -+++ b/drivers/gpu/arm/midgard/mali_kbase_mem.h -@@ -591,7 +591,7 @@ void kbase_mem_pool_free_pages(struct kbase_mem_pool *pool, size_t nr_pages, - */ - static inline size_t kbase_mem_pool_size(struct kbase_mem_pool *pool) - { -- return ACCESS_ONCE(pool->cur_size); -+ return READ_ONCE(pool->cur_size); - } - - /** --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0008-gpu-arm-midgard-Remove-sys_close-references.patch b/buildroot-external/board/asus/tinker/patches/linux/0008-gpu-arm-midgard-Remove-sys_close-references.patch deleted file mode 100644 index bccce5d77..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0008-gpu-arm-midgard-Remove-sys_close-references.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 47e8aad9419ff8843a373c3e5aa2c9d261d8cd07 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Mon, 23 Apr 2018 20:54:13 +0200 -Subject: [PATCH] gpu: arm: midgard: Remove sys_close references - -sys_close is now replaced by ksys_close in an effort to remove -in-kernel system calls references. - -See 2ca2a09d6215fd9621aa3e2db7cc9428a61f2911 and -https://lkml.org/lkml/2018/3/25/93 for more details. - -Signed-off-by: Myy Miouyouyou ---- - drivers/gpu/arm/midgard/mali_kbase_sync.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_sync.h b/drivers/gpu/arm/midgard/mali_kbase_sync.h -index de72147d..33b58059 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_sync.h -+++ b/drivers/gpu/arm/midgard/mali_kbase_sync.h -@@ -156,7 +156,7 @@ void kbase_sync_fence_out_remove(struct kbase_jd_atom *katom); - */ - static inline void kbase_sync_fence_close_fd(int fd) - { -- sys_close(fd); -+ ksys_close(fd); - } - - /** --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0009-GPU-ARM-Midgard-Adapt-to-the-new-mmap-call-checks.patch b/buildroot-external/board/asus/tinker/patches/linux/0009-GPU-ARM-Midgard-Adapt-to-the-new-mmap-call-checks.patch deleted file mode 100644 index f5236bc16..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0009-GPU-ARM-Midgard-Adapt-to-the-new-mmap-call-checks.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 9812105eb6220863af05fc72591118f0a48e1c4e Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Mon, 21 May 2018 22:32:59 +0200 -Subject: [PATCH] GPU: ARM: Midgard: Adapt to the new mmap call checks. - -Now, I don't know if this driver is just one of these "buggy" drivers -Linus is talking about, or if this is just standard GPU procedure. - -Anyway, this patch is due to this change by Linus Torvalds : -https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=be83bbf806822b1b89e0a0f23cd87cddc409e429 - -And the fix is inspired by : -https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=76ef6b28ea4f81c3d511866a9b31392caa833126 - -Signed-off-by: Myy Miouyouyou ---- - drivers/gpu/arm/midgard/mali_kbase_core_linux.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -index cc4932a4ead7..89b4cca27cf1 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -@@ -1087,6 +1087,7 @@ static int kbase_open(struct inode *inode, struct file *filp) - - init_waitqueue_head(&kctx->event_queue); - filp->private_data = kctx; -+ filp->f_mode |= FMODE_UNSIGNED_OFFSET; - kctx->filp = filp; - - if (kbdev->infinite_cache_active_default) --- -2.17.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/0010-GPU-Mali-Midgard-remove-rcu_read_lock-references.patch b/buildroot-external/board/asus/tinker/patches/linux/0010-GPU-Mali-Midgard-remove-rcu_read_lock-references.patch deleted file mode 100644 index e3ab3f057..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/0010-GPU-Mali-Midgard-remove-rcu_read_lock-references.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 9bf91a052d8ceddfd5808547a51e167fb7463754 Mon Sep 17 00:00:00 2001 -From: "Miouyouyou (Myy)" -Date: Wed, 18 Jul 2018 19:59:21 +0200 -Subject: [PATCH] GPU: Mali: Midgard: remove rcu_read_lock references - -This patch is actually based on @mihailescu2m patch. -This removes references to rcu_read_lock when acquiring the OPP table, -as it is useless since. -See : -https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/base/power/opp/core.c?id=5b650b388844f26c61c70564865598836d05dcb3 - -The current rcu_read_lock actually generates some issues with recent -kernels. -See here : -https://community.arm.com/graphics/f/discussions/9207/midgard-r20p0-kernel-drivers-errors - -The patch has been recreated since it does not apply directly on r19p0 -sources (I guess the affected line numbers slightly differ...). - -@mihailescu2m patch for the Mali Midgard r20p0 kernel driver can be -acquired here : -https://github.com/mihailescu2m/linux/commit/bbe73c3c1143e5991bdcaee3afaecf5c31af0647 - -Signed-off-by: Miouyouyou (Myy) ---- - drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c | 7 +------ - 1 file changed, 1 insertion(+), 6 deletions(-) - -diff --git a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c -index e280322e..bf69d897 100644 ---- a/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c -+++ b/drivers/gpu/arm/midgard/backend/gpu/mali_kbase_devfreq.c -@@ -87,10 +87,9 @@ kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags) - - freq = *target_freq; - -- rcu_read_lock(); - opp = devfreq_recommended_opp(dev, &freq, flags); - voltage = dev_pm_opp_get_voltage(opp); -- rcu_read_unlock(); -+ - if (IS_ERR_OR_NULL(opp)) { - dev_err(dev, "Failed to get opp (%ld)\n", PTR_ERR(opp)); - return PTR_ERR(opp); -@@ -186,20 +185,17 @@ static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev, - unsigned long freq; - struct dev_pm_opp *opp; - -- rcu_read_lock(); - count = dev_pm_opp_get_opp_count(kbdev->dev); - if (count < 0) { - rcu_read_unlock(); - return count; - } -- rcu_read_unlock(); - - dp->freq_table = kmalloc_array(count, sizeof(dp->freq_table[0]), - GFP_KERNEL); - if (!dp->freq_table) - return -ENOMEM; - -- rcu_read_lock(); - for (i = 0, freq = ULONG_MAX; i < count; i++, freq--) { - opp = dev_pm_opp_find_freq_floor(kbdev->dev, &freq); - if (IS_ERR(opp)) -@@ -207,7 +203,6 @@ static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev, - - dp->freq_table[i] = freq; - } -- rcu_read_unlock(); - - if (count != i) - dev_warn(kbdev->dev, "Unable to enumerate all OPPs (%d!=%d\n", --- -2.16.4 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1-2-regulator-act8865-add-restart-handler-for-act8846.patch b/buildroot-external/board/asus/tinker/patches/linux/1-2-regulator-act8865-add-restart-handler-for-act8846.patch index 6d4982176..e1ca78624 100644 --- a/buildroot-external/board/asus/tinker/patches/linux/1-2-regulator-act8865-add-restart-handler-for-act8846.patch +++ b/buildroot-external/board/asus/tinker/patches/linux/1-2-regulator-act8865-add-restart-handler-for-act8846.patch @@ -9,9 +9,9 @@ index 2ff73d7..836d10b 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -27,6 +27,7 @@ - #include #include #include + #include +#include /* diff --git a/buildroot-external/board/asus/tinker/patches/linux/1001-drivers-Integrating-Mali-Midgard-video-and-gpu-drive.patch b/buildroot-external/board/asus/tinker/patches/linux/1001-drivers-Integrating-Mali-Midgard-video-and-gpu-drive.patch deleted file mode 100644 index 6c44e6542..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/1001-drivers-Integrating-Mali-Midgard-video-and-gpu-drive.patch +++ /dev/null @@ -1,39 +0,0 @@ -From fe85565d9ed8212cbda2148d4731418a36a8d088 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Mon, 11 Dec 2017 21:53:28 +0100 -Subject: [PATCH 1/3] drivers: Integrating Mali Midgard video and gpu drivers. - -I'm dropping the UMP drivers. They are not maintained. - -Signed-off-by: Myy Miouyouyou ---- - drivers/gpu/Makefile | 2 +- - drivers/video/Kconfig | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile -index e9ed439a5..66386b42a 100644 ---- a/drivers/gpu/Makefile -+++ b/drivers/gpu/Makefile -@@ -2,5 +2,5 @@ - # taken to initialize them in the correct order. Link order is the only way - # to ensure this currently. - obj-$(CONFIG_TEGRA_HOST1X) += host1x/ --obj-y += drm/ vga/ -+obj-y += drm/ vga/ arm/ - obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ -diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index 3c20af999..041e15f2c 100644 ---- a/drivers/video/Kconfig -+++ b/drivers/video/Kconfig -@@ -17,6 +17,7 @@ source "drivers/gpu/vga/Kconfig" - - source "drivers/gpu/host1x/Kconfig" - source "drivers/gpu/ipu-v3/Kconfig" -+source "drivers/gpu/arm/midgard/Kconfig" - - source "drivers/gpu/drm/Kconfig" - --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2001-dts-rk3288-miqi-Enabling-the-Mali-GPU-node.patch b/buildroot-external/board/asus/tinker/patches/linux/1001-dts-rk3288-miqi-Enabling-the-Mali-GPU-node.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/2001-dts-rk3288-miqi-Enabling-the-Mali-GPU-node.patch rename to buildroot-external/board/asus/tinker/patches/linux/1001-dts-rk3288-miqi-Enabling-the-Mali-GPU-node.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/2002-ARM-dts-rockchip-fix-the-regulator-s-voltage-range-o.patch b/buildroot-external/board/asus/tinker/patches/linux/1002-ARM-dts-rockchip-fix-the-regulator-s-voltage-range-o.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/2002-ARM-dts-rockchip-fix-the-regulator-s-voltage-range-o.patch rename to buildroot-external/board/asus/tinker/patches/linux/1002-ARM-dts-rockchip-fix-the-regulator-s-voltage-range-o.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/2003-ARM-dts-rockchip-add-the-MiQi-board-s-fan-definition.patch b/buildroot-external/board/asus/tinker/patches/linux/1003-ARM-dts-rockchip-add-the-MiQi-board-s-fan-definition.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/2003-ARM-dts-rockchip-add-the-MiQi-board-s-fan-definition.patch rename to buildroot-external/board/asus/tinker/patches/linux/1003-ARM-dts-rockchip-add-the-MiQi-board-s-fan-definition.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/1004-Remove-the-dependency-to-the-clk_mali-symbol.patch b/buildroot-external/board/asus/tinker/patches/linux/1004-Remove-the-dependency-to-the-clk_mali-symbol.patch deleted file mode 100644 index 882e4fdde..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/1004-Remove-the-dependency-to-the-clk_mali-symbol.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 239a5e3016b7f676bc3f56ea509ed172bf954001 Mon Sep 17 00:00:00 2001 -From: Myy -Date: Sat, 22 Jul 2017 04:07:36 +0000 -Subject: [PATCH] Remove the dependency to the clk_mali symbol. - -Inspired by @wzzy2 patch - -https://github.com/rockchip-linux/rockchip_forwardports/commit/359865c617129fe5fcc5530f4a88abcfaa6a5cb4 - -Signed-off-by: Myy ---- - drivers/gpu/arm/midgard/mali_kbase_core_linux.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -index 9cc65d2..27dcd9c 100644 ---- a/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -+++ b/drivers/gpu/arm/midgard/mali_kbase_core_linux.c -@@ -3793,7 +3793,7 @@ static int power_control_init(struct platform_device *pdev) - } - #endif /* LINUX_VERSION_CODE >= 3, 12, 0 */ - -- kbdev->clock = clk_get(kbdev->dev, "clk_mali"); -+ kbdev->clock = of_clk_get(kbdev->dev->of_node, 0); - if (IS_ERR_OR_NULL(kbdev->clock)) { - err = PTR_ERR(kbdev->clock); - kbdev->clock = NULL; --- -2.10.2 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1005-ASUS-Tinkerboard-Stupid-reboot.patch b/buildroot-external/board/asus/tinker/patches/linux/1005-ASUS-Tinkerboard-Stupid-reboot.patch deleted file mode 100644 index 7afe1d024..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/1005-ASUS-Tinkerboard-Stupid-reboot.patch +++ /dev/null @@ -1,157 +0,0 @@ -From bf9b932f6ae506baf5b79c8407089448ed77fc56 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Sun, 17 Dec 2017 16:15:03 +0100 -Subject: [PATCH] ASUS Tinkerboard: Stupid reboot patch - -This patch is ugly as shit and will be reworked when possible. - -Meanwhile, this fixes an issue with the ASUS Tinkerboard which -cannot reboot correctly. The issue is that the MMC hardware is -shutdown during the reboot phase and is not powered again after -the power cycle, leading to a dead board awaiting a hard power -cycle. - -Signed-off-by: Myy Miouyouyou ---- - drivers/mmc/host/dw_mmc-rockchip.c | 24 ++++++++++++++++++++++++ - drivers/mmc/host/dw_mmc.c | 28 ++++++++++++++++++++++++++++ - include/linux/reboot.h | 2 ++ - kernel/reboot.c | 1 + - 4 files changed, 55 insertions(+) - -diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c -index a3f1c2b30..52c13733f 100644 ---- a/drivers/mmc/host/dw_mmc-rockchip.c -+++ b/drivers/mmc/host/dw_mmc-rockchip.c -@@ -14,10 +14,12 @@ - #include - #include - #include -+#include // Stupid Tinkerboard Hack - #include - - #include "dw_mmc.h" - #include "dw_mmc-pltfm.h" -+#include "../core/core.h" // Stupid Tinkerboard Hack - - #define RK3288_CLKGEN_DIV 2 - -@@ -365,6 +367,27 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev) - return 0; - } - -+/* Stupid Tinkerboard Hack */ -+static void dw_mci_rockchip_platfm_shutdown(struct platform_device *pdev) -+{ -+ struct dw_mci *host = platform_get_drvdata(pdev); -+ struct mmc_host *mmc = host->slot->mmc; -+ int ret; -+ -+ if(of_machine_is_compatible("asus,rk3288-tinker")){ -+ -+ mmc_power_off(mmc); -+ -+ mdelay(20); -+ -+ if (!IS_ERR(mmc->supply.vmmc)) -+ ret = regulator_enable(mmc->supply.vmmc); -+ -+ if (!IS_ERR(mmc->supply.vqmmc)) -+ regulator_set_voltage(mmc->supply.vqmmc, 3000000, 3300000); -+ } -+} -+ - static int dw_mci_rockchip_remove(struct platform_device *pdev) - { - pm_runtime_get_sync(&pdev->dev); -@@ -385,6 +408,7 @@ static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = { - static struct platform_driver dw_mci_rockchip_pltfm_driver = { - .probe = dw_mci_rockchip_probe, - .remove = dw_mci_rockchip_remove, -+ .shutdown = dw_mci_rockchip_platfm_shutdown, // Stupid Tinkerboard Hack - .driver = { - .name = "dwmmc_rockchip", - .of_match_table = dw_mci_rockchip_match, -diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c -index 0aa39975f..70f7ce21b 100644 ---- a/drivers/mmc/host/dw_mmc.c -+++ b/drivers/mmc/host/dw_mmc.c -@@ -39,8 +39,10 @@ - #include - #include - #include -+#include // Stupid Tinkerboard Hack - - #include "dw_mmc.h" -+#include "../core/core.h" // Stupid Tinkerboard Hack - - /* Common flag combinations */ - #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ -@@ -2778,6 +2780,29 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) - return IRQ_HANDLED; - } - -+/* Stupid Tinkerboard Hack */ -+struct dw_mci *mSdhost; -+void setmmcEmergency() { -+ struct mmc_host *mmc; -+ int ret; -+ -+ printk(KERN_ERR "Emergency route taken.\n"); -+ if (of_machine_is_compatible("asus,rk3288-tinker")) { -+ mmc = mSdhost->slot->mmc; -+ -+ mmc_power_off(mmc); -+ -+ mdelay(20); -+ -+ if (!IS_ERR(mmc->supply.vmmc)) -+ ret = regulator_enable(mmc->supply.vmmc); -+ -+ if (!IS_ERR(mmc->supply.vqmmc)) -+ regulator_set_voltage(mmc->supply.vqmmc, 3000000, 3300000); -+ } -+} -+EXPORT_SYMBOL(setmmcEmergency); -+ - static int dw_mci_init_slot(struct dw_mci *host) - { - struct mmc_host *mmc; -@@ -2809,6 +2834,9 @@ static int dw_mci_init_slot(struct dw_mci *host) - mmc->f_max = freq[1]; - } - -+ /* Stupid Tinkerboard Hack */ -+ if (of_find_property(host->dev->of_node, "supports-sd", NULL)) -+ mSdhost = host; - /*if there are external regulators, get them*/ - ret = mmc_regulator_get_supply(mmc); - if (ret) -diff --git a/include/linux/reboot.h b/include/linux/reboot.h -index e63799a6e..057d3ce0c 100644 ---- a/include/linux/reboot.h -+++ b/include/linux/reboot.h -@@ -77,6 +77,8 @@ extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN]; - - extern void orderly_poweroff(bool force); - extern void orderly_reboot(void); -+/* Stupid Tinkerboard Hack */ -+extern void setmmcEmergency(void); - - /* - * Emergency restart, callable from an interrupt handler. -diff --git a/kernel/reboot.c b/kernel/reboot.c -index e4ced883d..c8e678ce6 100644 ---- a/kernel/reboot.c -+++ b/kernel/reboot.c -@@ -61,6 +61,7 @@ void (*pm_power_off_prepare)(void); - void emergency_restart(void) - { - kmsg_dump(KMSG_DUMP_EMERG); -+ setmmcEmergency(); // Stupid Tinkerboard Hack - machine_emergency_restart(); - } - EXPORT_SYMBOL_GPL(emergency_restart); --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2007-RK3288-DTSI-rk3288-Add-missing-SPI2-pinctrl.patch b/buildroot-external/board/asus/tinker/patches/linux/1007-RK3288-DTSI-rk3288-Add-missing-SPI2-pinctrl.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/2007-RK3288-DTSI-rk3288-Add-missing-SPI2-pinctrl.patch rename to buildroot-external/board/asus/tinker/patches/linux/1007-RK3288-DTSI-rk3288-Add-missing-SPI2-pinctrl.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/2010-ARM-DTSI-rk3288-Adding-missing-EDP-power-domain.patch b/buildroot-external/board/asus/tinker/patches/linux/1010-ARM-DTSI-rk3288-Adding-missing-EDP-power-domain.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/2010-ARM-DTSI-rk3288-Adding-missing-EDP-power-domain.patch rename to buildroot-external/board/asus/tinker/patches/linux/1010-ARM-DTSI-rk3288-Adding-missing-EDP-power-domain.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/2011-ARM-DTSI-rk3288-Adding-missing-VOPB-registers.patch b/buildroot-external/board/asus/tinker/patches/linux/1011-ARM-DTSI-rk3288-Adding-missing-VOPB-registers.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/2011-ARM-DTSI-rk3288-Adding-missing-VOPB-registers.patch rename to buildroot-external/board/asus/tinker/patches/linux/1011-ARM-DTSI-rk3288-Adding-missing-VOPB-registers.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/2012-ARM-DTSI-rk3288-Fixed-the-SPDIF-node-address.patch b/buildroot-external/board/asus/tinker/patches/linux/1012-ARM-DTSI-rk3288-Fixed-the-SPDIF-node-address.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/2012-ARM-DTSI-rk3288-Fixed-the-SPDIF-node-address.patch rename to buildroot-external/board/asus/tinker/patches/linux/1012-ARM-DTSI-rk3288-Fixed-the-SPDIF-node-address.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/1013-ARM-DTS-rk3288-tinker-Enabling-SDIO-and-Wifi.patch b/buildroot-external/board/asus/tinker/patches/linux/1013-ARM-DTS-rk3288-tinker-Enabling-SDIO-and-Wifi.patch new file mode 100644 index 000000000..18b6c9c0d --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1013-ARM-DTS-rk3288-tinker-Enabling-SDIO-and-Wifi.patch @@ -0,0 +1,98 @@ +From d5d5c53173c484a13cda62a537cbf75a5df4b0e4 Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 21:58:56 +0100 +Subject: [PATCH] ARM: DTS: rk3288-tinker: Enabling SDIO and Wifi + +Adding the appropriate nodes in order to exploit the WiFi capabilities +of the board. +Since these capabilities are provided through SDIO, and the SDIO +nodes were not defined, these were added too. + +These seems to depend on each other so they are added in one big +patch. + +Split if necessary. + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-tinker.dts | 62 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts +index 1e43527aa..d4df13bed 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dts ++++ b/arch/arm/boot/dts/rk3288-tinker.dts +@@ -6,8 +6,70 @@ + /dts-v1/; + + #include "rk3288-tinker.dtsi" ++#include + + / { + model = "Rockchip RK3288 Asus Tinker Board"; + compatible = "asus,rk3288-tinker", "rockchip,rk3288"; ++ ++ /* This is essential to get SDIO devices working. ++ The Wifi depends on SDIO ! */ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ clocks = <&rk808 RK808_CLKOUT1>; ++ clock-names = "ext_clock"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&chip_enable_h>, <&wifi_enable_h>; ++ ++ /* ++ * On the module itself this is one of these (depending ++ * on the actual card populated): ++ * - SDIO_RESET_L_WL_REG_ON ++ * - PDN (power down when low) ++ */ ++ reset-gpios = <&gpio4 28 GPIO_ACTIVE_LOW>, <&gpio4 27 GPIO_ACTIVE_LOW>; ++ }; ++ ++ wireless-wlan { ++ compatible = "wlan-platdata"; ++ rockchip,grf = <&grf>; ++ sdio_vref = <1800>; ++ status = "okay"; ++ wifi_chip_type = "8723bs"; ++ WIFI,host_wake_irq = <&gpio4 30 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&io_domains { ++ wifi-supply = <&vcc_18>; ++}; ++ ++&pinctrl { ++ sdio-pwrseq { ++ wifi_enable_h: wifienable-h { ++ rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ chip_enable_h: chip-enable-h { ++ rockchip,pins = <4 27 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++}; ++ ++&sdio0 { ++ bus-width = <4>; ++ cap-sd-highspeed; ++ cap-sdio-irq; ++ clock-frequency = <50000000>; ++ clock-freq-min-max = <200000 50000000>; ++ disable-wp; ++ keep-power-in-suspend; ++ mmc-pwrseq = <&sdio_pwrseq>; ++ non-removable; ++ num-slots = <1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>; ++ sd-uhs-sdr104; ++ status = "okay"; ++ supports-sdio; + }; +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch b/buildroot-external/board/asus/tinker/patches/linux/1014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch new file mode 100644 index 000000000..304936c64 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch @@ -0,0 +1,62 @@ +From 2c2e60256f2cbb2fce50a6317f85b1500efd1a6c Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 22:03:26 +0100 +Subject: [PATCH] ARM: DTS: rk3288-tinker: Setup the Bluetooth UART pins + +The most essential being the RTS pin, which is clearly needed to +upload the initial configuration into the Realtek Bluetooth +chip, and make the Bluetooth chip work. + +Now, the Bluetooth chip also needs 3 other GPIOS to be enabled. +I'll see how I do that through the DTS file in a near future. + +The 3 GPIOS being : +Bluetooth Reset : <&gpio4 29 GPIO_ACTIVE_HIGH> +Bluetooth Wake : <&gpio4 26 GPIO_ACTIVE_HIGH> +Bluetooth Wake_Host_IRQ : <&gpio4 31 GPIO_ACTIVE_HIGH> + +These are currently setup manually, through scripts. But it seems that +GPIO handling through /sys entries might not be possible in the long +term, the replacement being libgpio. +Anyway, if you're interesting in enabling the Bluetooth GPIO by hand, +here are the commands : + +cd /sys/class/gpio && +echo 146 > export && +echo 149 > export && +echo 151 > export && +echo high > gpio146/direction && +echo high > gpio149/direction && +echo high > gpio151/direction + +Resetting the chip is done like this : + +echo "Resetting the Bluetooth chip" +cd /sys/class/gpio/gpio149 && +echo 0 > value && +sleep 1 && +echo 1 > value && +sleep 1 + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-tinker.dts | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts +index d4df13bed..b92e59c1e 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dts ++++ b/arch/arm/boot/dts/rk3288-tinker.dts +@@ -73,3 +73,9 @@ + status = "okay"; + supports-sdio; + }; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>; ++}; ++ +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1015-ARM-DTSI-rk3288-tinker-Improving-the-CPU-max-voltage.patch b/buildroot-external/board/asus/tinker/patches/linux/1015-ARM-DTSI-rk3288-tinker-Improving-the-CPU-max-voltage.patch new file mode 100644 index 000000000..05b1179bc --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1015-ARM-DTSI-rk3288-tinker-Improving-the-CPU-max-voltage.patch @@ -0,0 +1,28 @@ +From ebc29962ac27264772a4227f5abd6900cb72fa79 Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 20:16:05 +0100 +Subject: [PATCH] ARM: DTSI: rk3288-tinker: Improving the CPU max voltage + +Taken from the various patches provided by @TonyMac32 . + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-tinker.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi +index aa107ee41..3da1c830f 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dtsi ++++ b/arch/arm/boot/dts/rk3288-tinker.dtsi +@@ -164,7 +164,7 @@ + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; +- regulator-max-microvolt = <1350000>; ++ regulator-max-microvolt = <1450000>; + regulator-name = "vdd_arm"; + regulator-ramp-delay = <6000>; + regulator-state-mem { +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1016-ARM-DTSI-rk3288-tinker-Setting-up-the-SD-regulators.patch b/buildroot-external/board/asus/tinker/patches/linux/1016-ARM-DTSI-rk3288-tinker-Setting-up-the-SD-regulators.patch new file mode 100644 index 000000000..220893706 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1016-ARM-DTSI-rk3288-tinker-Setting-up-the-SD-regulators.patch @@ -0,0 +1,31 @@ +From 3dacea70a8e434008f5b1f119a7f7da9aebc772c Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 20:18:58 +0100 +Subject: [PATCH] ARM: DTSI: rk3288-tinker: Setting up the SD regulators + +Some are needed and some are not. Playing with these parameters is +required to get reboot working on these boards. + +I still can't believe that these boards can't soft reset correctly. + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-tinker.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi +index 3da1c830f..dd1090728 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dtsi ++++ b/arch/arm/boot/dts/rk3288-tinker.dtsi +@@ -254,7 +254,8 @@ + }; + + vccio_sd: LDO_REG5 { ++ regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch b/buildroot-external/board/asus/tinker/patches/linux/1017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch new file mode 100644 index 000000000..b6d5ab7f6 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch @@ -0,0 +1,53 @@ +From a72e0749acad92df7b854e38e97e1dc7b4799abe Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 22:11:24 +0100 +Subject: [PATCH] ARM: DTS: rk3288-tinker: Defined the I2C interfaces + +And all the hardware behind. + +Taken from @TonyMac32, Butchered by @Miouyouyou . + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-tinker.dts | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts +index b92e59c1e..96d05fc6b 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dts ++++ b/arch/arm/boot/dts/rk3288-tinker.dts +@@ -40,6 +40,31 @@ + }; + }; + ++&i2c1 { ++ status = "okay"; ++}; ++ ++&i2c2 { ++ afc0:af-controller@0 { ++ status = "okay"; ++ compatible = "silicon touch,vm149C-v4l2-i2c-subdev"; ++ reg = <0x0 0x0c>; ++ }; ++ ++ eeprom:m24c08@50 { ++ compatible = "at,24c08"; ++ reg = <0x50>; ++ }; ++}; ++ ++&i2c3 { ++ status = "okay"; ++}; ++ ++&i2c4 { ++ status = "okay"; ++}; ++ + &io_domains { + wifi-supply = <&vcc_18>; + }; +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1018-ARM-DTS-rk3288-tinker-Defining-the-SPI-interface.patch b/buildroot-external/board/asus/tinker/patches/linux/1018-ARM-DTS-rk3288-tinker-Defining-the-SPI-interface.patch new file mode 100644 index 000000000..980b0a5e9 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1018-ARM-DTS-rk3288-tinker-Defining-the-SPI-interface.patch @@ -0,0 +1,50 @@ +From b24b8f83e150811ad54ee2a4843e44cd1421fafa Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 22:15:14 +0100 +Subject: [PATCH] ARM: DTS: rk3288-tinker: Defining the SPI interface + +Taken from, and tested by @TonyMac32 . + +Well, the original one was tested by him but I had to adapt the +registers definitions to the new 64-bits LPAE-compliant syntax. + +Therefore that *might* break, along with a few other patches. + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-tinker.dts | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts +index 96d05fc6b..17bfea298 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dts ++++ b/arch/arm/boot/dts/rk3288-tinker.dts +@@ -99,6 +99,25 @@ + supports-sdio; + }; + ++&spi2 { ++ max-freq = <50000000>; ++ status = "okay"; ++ ++ spidev@0 { ++ compatible = "rockchip,spi_tinker"; ++ reg = <0x0 0>; ++ spi-max-frequency = <50000000>; ++ spi-cpha = <1>; ++ }; ++ ++ spidev@1 { ++ compatible = "rockchip,spi_tinker"; ++ reg = <0x1>; ++ spi-max-frequency = <50000000>; ++ spi-cpha = <1>; ++ }; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>; +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1019-ARM-DTSI-rk3288-tinker-Defining-SDMMC-properties.patch b/buildroot-external/board/asus/tinker/patches/linux/1019-ARM-DTSI-rk3288-tinker-Defining-SDMMC-properties.patch new file mode 100644 index 000000000..318f5058a --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1019-ARM-DTSI-rk3288-tinker-Defining-SDMMC-properties.patch @@ -0,0 +1,33 @@ +From 487db7cefc9861fdaf30579c378a98f0360690ae Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 20:27:14 +0100 +Subject: [PATCH] ARM: DTSI: rk3288-tinker: Defining SDMMC properties + +I never knew if these properties were required to fix the dreaded +reboot issue... + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-tinker.dtsi | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi +index dd1090728..8edd6f681 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dtsi ++++ b/arch/arm/boot/dts/rk3288-tinker.dtsi +@@ -436,7 +436,12 @@ + disable-wp; /* wp not hooked up */ + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; ++ sd-uhs-sdr12; ++ sd-uhs-sdr25; ++ sd-uhs-sdr50; ++ sd-uhs-sdr104; + status = "okay"; ++ supports-sd; + vmmc-supply = <&vcc33_sd>; + vqmmc-supply = <&vccio_sd>; + }; +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/2026-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch b/buildroot-external/board/asus/tinker/patches/linux/1020-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch similarity index 88% rename from buildroot-external/board/asus/tinker/patches/linux/2026-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch rename to buildroot-external/board/asus/tinker/patches/linux/1020-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch index ad8eac7dc..1d2985708 100644 --- a/buildroot-external/board/asus/tinker/patches/linux/2026-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch +++ b/buildroot-external/board/asus/tinker/patches/linux/1020-ARM-DTSI-rk3288-Set-the-VPU-MMU-power-domains.patch @@ -35,14 +35,6 @@ diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 45ec4e89..46e1b8e2 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -1230,6 +1230,7 @@ - interrupt-names = "vpu_mmu"; - clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; - clock-names = "aclk", "iface"; -+ power-domains = <&power RK3288_PD_VIDEO>; - #iommu-cells = <0>; - status = "disabled"; - }; @@ -1262,6 +1263,7 @@ interrupt-names = "hevc_mmu"; clocks = <&cru ACLK_HEVC>, <&cru HCLK_HEVC>; diff --git a/buildroot-external/board/asus/tinker/patches/linux/1023-dts-rk3288-support-for-dedicating-npll-to-a-vop.patch b/buildroot-external/board/asus/tinker/patches/linux/1023-dts-rk3288-support-for-dedicating-npll-to-a-vop.patch new file mode 100644 index 000000000..3a4b8dc1f --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1023-dts-rk3288-support-for-dedicating-npll-to-a-vop.patch @@ -0,0 +1,46 @@ +From 4ab4f88649468dada5d609e1a6f8a71a7d5610c9 Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Sat, 29 Sep 2018 02:48:59 +0200 +Subject: [PATCH 4/6] dts: rk3288: support for dedicating npll to a vop + +This patch is taken from Urja Rannikko ( @urjaman ) patchset here : +https://github.com/urjaman/arch-c201/blob/master/linux-c201/0020-RK3288-HDMI-clock-hacks-combined.patch +https://www.spinics.net/lists/arm-kernel/msg673156.html + +The original description was : + + Add the VOP DCLKs to the assigned clocks list so their + parents can be set in the dts include files for + devices that do dedicate npll to a vop. + +https://www.spinics.net/lists/arm-kernel/msg673162.html + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288.dtsi | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index d23c7fa55..ff04aab5e 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -867,12 +867,14 @@ + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; +- assigned-clocks = <&cru PLL_GPLL>, <&cru PLL_CPLL>, ++ assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>, ++ <&cru PLL_GPLL>, <&cru PLL_CPLL>, + <&cru PLL_NPLL>, <&cru ACLK_CPU>, + <&cru HCLK_CPU>, <&cru PCLK_CPU>, + <&cru ACLK_PERI>, <&cru HCLK_PERI>, + <&cru PCLK_PERI>; +- assigned-clock-rates = <594000000>, <400000000>, ++ assigned-clock-rates = <0>, <0>, ++ <594000000>, <400000000>, + <500000000>, <300000000>, + <150000000>, <75000000>, + <300000000>, <150000000>, +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1024-arm-dts-veyron-Added-a-flag-to-disable-cache-flush-d.patch b/buildroot-external/board/asus/tinker/patches/linux/1024-arm-dts-veyron-Added-a-flag-to-disable-cache-flush-d.patch new file mode 100644 index 000000000..31f37e42f --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/1024-arm-dts-veyron-Added-a-flag-to-disable-cache-flush-d.patch @@ -0,0 +1,32 @@ +From 9177b30ab083dbda2bede3b3d61ef71ad4b1ffe0 Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Thu, 1 Nov 2018 21:31:26 +0100 +Subject: [PATCH 2/2] arm: dts: veyron: Added a flag to disable cache flush + during reset + +Flushing the MMC cache of ASUS Chromebooks during initialization or +"recovery" generates 10 minutes hangup, according to @SolidHal. + +This is an adaptation of @SolidHal, in order to pinpoint the fix to +Veyron Chromebooks, and avoiding issues other RK3288 boards. + +Signed-off-by: Miouyouyou (Myy) +--- + arch/arm/boot/dts/rk3288-veyron.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi +index 2075120cf..fa4951fd7 100644 +--- a/arch/arm/boot/dts/rk3288-veyron.dtsi ++++ b/arch/arm/boot/dts/rk3288-veyron.dtsi +@@ -123,6 +123,7 @@ + mmc-hs200-1_8v; + mmc-pwrseq = <&emmc_pwrseq>; + non-removable; ++ no-recovery-cache-flush; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + }; +-- +2.16.4 + diff --git a/buildroot-external/board/asus/tinker/patches/linux/1100-media-Add-JPEG_RAW-format.patch b/buildroot-external/board/asus/tinker/patches/linux/1100-media-Add-JPEG_RAW-format.patch deleted file mode 100644 index e29ad9085..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/1100-media-Add-JPEG_RAW-format.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 1680a655127a62e74cbcfb84782e04a9c55dcf81 Mon Sep 17 00:00:00 2001 -From: Shunqian Zheng -Date: Wed, 5 Sep 2018 19:00:09 -0300 -Subject: [PATCH 3/6] media: Add JPEG_RAW format - -Add V4L2_PIX_FMT_JPEG_RAW format that does not contain -JPEG header in the output frame. - -Signed-off-by: Shunqian Zheng -Signed-off-by: Ezequiel Garcia ---- - Documentation/media/uapi/v4l/pixfmt-compressed.rst | 9 +++++++++ - drivers/media/v4l2-core/v4l2-ioctl.c | 1 + - include/uapi/linux/videodev2.h | 1 + - 3 files changed, 11 insertions(+) - -diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst -index d382e7a5..4dffe400 100644 ---- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst -+++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst -@@ -23,6 +23,15 @@ Compressed Formats - - 'JPEG' - - TBD. See also :ref:`VIDIOC_G_JPEGCOMP `, - :ref:`VIDIOC_S_JPEGCOMP `. -+ * .. _V4L2-PIX-FMT-JPEG-RAW: -+ -+ - ``V4L2_PIX_FMT_JPEG_RAW`` -+ - 'Raw JPEG' -+ - Raw JPEG bitstream, containing a compressed payload. This format -+ contains an image scan, i.e. without any metadata or headers. -+ The user is expected to set the needed metadata such as -+ quantization and entropy encoding tables, via ``V4L2_CID_JPEG`` -+ controls, see :ref:`jpeg-control-id`. - * .. _V4L2-PIX-FMT-MPEG: - - - ``V4L2_PIX_FMT_MPEG`` -diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c -index 54afc9c7..0dcd95f4 100644 ---- a/drivers/media/v4l2-core/v4l2-ioctl.c -+++ b/drivers/media/v4l2-core/v4l2-ioctl.c -@@ -1301,6 +1301,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) - /* Max description length mask: descr = "0123456789012345678901234567890" */ - case V4L2_PIX_FMT_MJPEG: descr = "Motion-JPEG"; break; - case V4L2_PIX_FMT_JPEG: descr = "JFIF JPEG"; break; -+ case V4L2_PIX_FMT_JPEG_RAW: descr = "Raw JPEG"; break; - case V4L2_PIX_FMT_DV: descr = "1394"; break; - case V4L2_PIX_FMT_MPEG: descr = "MPEG-1/2/4"; break; - case V4L2_PIX_FMT_H264: descr = "H.264"; break; -diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h -index 5d1a3685..f271048c 100644 ---- a/include/uapi/linux/videodev2.h -+++ b/include/uapi/linux/videodev2.h -@@ -627,6 +627,7 @@ struct v4l2_pix_format { - /* compressed formats */ - #define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ - #define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG */ -+#define V4L2_PIX_FMT_JPEG_RAW v4l2_fourcc('J', 'P', 'G', 'R') /* JFIF JPEG RAW without headers */ - #define V4L2_PIX_FMT_DV v4l2_fourcc('d', 'v', 's', 'd') /* 1394 */ - #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */ - #define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */ --- -2.16.4 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1101-media-Add-controls-for-JPEG-quantization-tables.patch b/buildroot-external/board/asus/tinker/patches/linux/1101-media-Add-controls-for-JPEG-quantization-tables.patch deleted file mode 100644 index 7838c9b13..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/1101-media-Add-controls-for-JPEG-quantization-tables.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 82da876c36ccc7791d5b20e7ee8b50379f7b19aa Mon Sep 17 00:00:00 2001 -From: Shunqian Zheng -Date: Wed, 5 Sep 2018 19:00:10 -0300 -Subject: [PATCH 4/6] media: Add controls for JPEG quantization tables - -Add V4L2_CID_JPEG_QUANTIZATION compound control to allow userspace -configure the JPEG quantization tables. - -Signed-off-by: Shunqian Zheng -Signed-off-by: Ezequiel Garcia ---- - Documentation/media/uapi/v4l/extended-controls.rst | 31 ++++++++++++++++++++++ - Documentation/media/videodev2.h.rst.exceptions | 1 + - drivers/media/v4l2-core/v4l2-ctrls.c | 10 +++++++ - include/uapi/linux/v4l2-controls.h | 12 +++++++++ - include/uapi/linux/videodev2.h | 1 + - 5 files changed, 55 insertions(+) - -diff --git a/Documentation/media/uapi/v4l/extended-controls.rst b/Documentation/media/uapi/v4l/extended-controls.rst -index 9f7312bf..1335d27d 100644 ---- a/Documentation/media/uapi/v4l/extended-controls.rst -+++ b/Documentation/media/uapi/v4l/extended-controls.rst -@@ -3354,7 +3354,38 @@ JPEG Control IDs - Specify which JPEG markers are included in compressed stream. This - control is valid only for encoders. - -+.. _jpeg-quant-tables-control: - -+``V4L2_CID_JPEG_QUANTIZATION (struct)`` -+ Specifies the luma and chroma quantization matrices for encoding -+ or decoding a V4L2_PIX_FMT_JPEG_RAW format buffer. The :ref:`itu-t81` -+ specification allows 8-bit quantization coefficients for -+ baseline profile images, and 8-bit or 16-bit for extended profile -+ images. Supporting or not 16-bit precision coefficients is driver-specific. -+ Coefficients must be set in JPEG zigzag scan order. -+ -+ -+.. c:type:: struct v4l2_ctrl_jpeg_quantization -+ -+.. cssclass:: longtable -+ -+.. flat-table:: struct v4l2_ctrl_jpeg_quantization -+ :header-rows: 0 -+ :stub-columns: 0 -+ :widths: 1 1 2 -+ -+ * - __u8 -+ - ``precision`` -+ - Specifies the coefficient precision. User shall set 0 -+ for 8-bit, and 1 for 16-bit. -+ -+ * - __u16 -+ - ``luma_quantization_matrix[64]`` -+ - Sets the luma quantization table. -+ -+ * - __u16 -+ - ``chroma_quantization_matrix[64]`` -+ - Sets the chroma quantization table. - - .. flat-table:: - :header-rows: 0 -diff --git a/Documentation/media/videodev2.h.rst.exceptions b/Documentation/media/videodev2.h.rst.exceptions -index ca9f0edc..a0a38e92 100644 ---- a/Documentation/media/videodev2.h.rst.exceptions -+++ b/Documentation/media/videodev2.h.rst.exceptions -@@ -129,6 +129,7 @@ replace symbol V4L2_CTRL_TYPE_STRING :c:type:`v4l2_ctrl_type` - replace symbol V4L2_CTRL_TYPE_U16 :c:type:`v4l2_ctrl_type` - replace symbol V4L2_CTRL_TYPE_U32 :c:type:`v4l2_ctrl_type` - replace symbol V4L2_CTRL_TYPE_U8 :c:type:`v4l2_ctrl_type` -+replace symbol V4L2_CTRL_TYPE_JPEG_QUANTIZATION :c:type:`v4l2_ctrl_type` - - # V4L2 capability defines - replace define V4L2_CAP_VIDEO_CAPTURE device-capabilities -diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c -index 599c1cbf..305bd7a9 100644 ---- a/drivers/media/v4l2-core/v4l2-ctrls.c -+++ b/drivers/media/v4l2-core/v4l2-ctrls.c -@@ -999,6 +999,7 @@ const char *v4l2_ctrl_get_name(u32 id) - case V4L2_CID_JPEG_RESTART_INTERVAL: return "Restart Interval"; - case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality"; - case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers"; -+ case V4L2_CID_JPEG_QUANTIZATION: return "JPEG Quantization Tables"; - - /* Image source controls */ - /* Keep the order of the 'case's the same as in v4l2-controls.h! */ -@@ -1286,6 +1287,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, - case V4L2_CID_DETECT_MD_REGION_GRID: - *type = V4L2_CTRL_TYPE_U8; - break; -+ case V4L2_CID_JPEG_QUANTIZATION: -+ *type = V4L2_CTRL_TYPE_JPEG_QUANTIZATION; -+ break; - case V4L2_CID_DETECT_MD_THRESHOLD_GRID: - *type = V4L2_CTRL_TYPE_U16; - break; -@@ -1612,6 +1616,9 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, - return -ERANGE; - return 0; - -+ case V4L2_CTRL_TYPE_JPEG_QUANTIZATION: -+ return 0; -+ - default: - return -EINVAL; - } -@@ -2133,6 +2140,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, - case V4L2_CTRL_TYPE_U32: - elem_size = sizeof(u32); - break; -+ case V4L2_CTRL_TYPE_JPEG_QUANTIZATION: -+ elem_size = sizeof(struct v4l2_ctrl_jpeg_quantization); -+ break; - default: - if (type < V4L2_CTRL_COMPOUND_TYPES) - elem_size = sizeof(s32); -diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h -index e4ee10ee..856b3325 100644 ---- a/include/uapi/linux/v4l2-controls.h -+++ b/include/uapi/linux/v4l2-controls.h -@@ -987,6 +987,18 @@ enum v4l2_jpeg_chroma_subsampling { - #define V4L2_JPEG_ACTIVE_MARKER_DQT (1 << 17) - #define V4L2_JPEG_ACTIVE_MARKER_DHT (1 << 18) - -+#define V4L2_CID_JPEG_QUANTIZATION (V4L2_CID_JPEG_CLASS_BASE + 5) -+struct v4l2_ctrl_jpeg_quantization { -+ /* ITU-T.81 specifies two quantization coefficient precisions: -+ * 8-bit for baseline profile, -+ * 8-bit or 16-bit for extended profile. -+ * -+ * User shall set "precision" to 0 for 8-bit and 1 for 16-bit. -+ */ -+ __u8 precision; -+ __u16 luma_quantization_matrix[64]; -+ __u16 chroma_quantization_matrix[64]; -+}; - - /* Image source controls */ - #define V4L2_CID_IMAGE_SOURCE_CLASS_BASE (V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900) -diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h -index f271048c..e998d074 100644 ---- a/include/uapi/linux/videodev2.h -+++ b/include/uapi/linux/videodev2.h -@@ -1630,6 +1630,7 @@ enum v4l2_ctrl_type { - V4L2_CTRL_TYPE_U8 = 0x0100, - V4L2_CTRL_TYPE_U16 = 0x0101, - V4L2_CTRL_TYPE_U32 = 0x0102, -+ V4L2_CTRL_TYPE_JPEG_QUANTIZATION = 0x0103, - }; - - /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ --- -2.16.4 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1002-clk-rockchip-add-all-known-operating-points-to-the-a.patch b/buildroot-external/board/asus/tinker/patches/linux/2002-clk-rockchip-add-all-known-operating-points-to-the-a.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/1002-clk-rockchip-add-all-known-operating-points-to-the-a.patch rename to buildroot-external/board/asus/tinker/patches/linux/2002-clk-rockchip-add-all-known-operating-points-to-the-a.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/2004-ARM-dts-rockchip-add-support-for-1800-MHz-operation-.patch b/buildroot-external/board/asus/tinker/patches/linux/2004-ARM-dts-rockchip-add-support-for-1800-MHz-operation-.patch deleted file mode 100644 index f8276b950..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2004-ARM-dts-rockchip-add-support-for-1800-MHz-operation-.patch +++ /dev/null @@ -1,41 +0,0 @@ -From e7e092be197c51b4d222a3b4e6638318067b7e6a Mon Sep 17 00:00:00 2001 -From: Willy Tarreau -Date: Tue, 2 Aug 2016 08:20:53 +0200 -Subject: [PATCH 07/28] ARM: dts: rockchip: add support for 1800 MHz operation - on MiQi board - -This board happily supports 1800 MHz operations (and even more), so -let's enable it. - -Signed-off-by: Willy Tarreau -(cherry picked from commit a0b82a29e7873a81f49ac5f50be3df1c7d312a14) ---- - arch/arm/boot/dts/rk3288-miqi.dts | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index 0e383595..80603a3d 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -126,6 +126,18 @@ - - &cpu0 { - cpu0-supply = <&vdd_cpu>; -+ operating-points = < -+ /* KHz uV */ -+ 1800000 1400000 -+ 1704000 1350000 -+ 1608000 1300000 -+ 1512000 1250000 -+ 1416000 1200000 -+ 1200000 1100000 -+ 1008000 1050000 -+ 816000 1000000 -+ 600000 900000 -+ >; - }; - - &emmc { --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2005-Readapt-ARM-dts-rockchip-miqi-add-turbo-mode-operati.patch b/buildroot-external/board/asus/tinker/patches/linux/2005-Readapt-ARM-dts-rockchip-miqi-add-turbo-mode-operati.patch deleted file mode 100644 index 0c80cbbaa..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2005-Readapt-ARM-dts-rockchip-miqi-add-turbo-mode-operati.patch +++ /dev/null @@ -1,170 +0,0 @@ -From de9dcd5ecab0686022eee243464f35d2c7a34c97 Mon Sep 17 00:00:00 2001 -From: Myy -Date: Mon, 16 Jan 2017 12:44:56 +0000 -Subject: [PATCH 08/28] Readapt: ARM: dts: rockchip: miqi: add turbo-mode - operating points - -Readaptation of Willy Tarreau patch. - -Here's the original commit message: - -By switching to opp-v2 we can declare "turbo-mode" operating points -which are only enabled when /sys/devices/system/cpu/cpufreq/boost is -set. It is convenient because it allows to boot, set a safe powersave -governor, enable boost, limit scaling_max_freq to a safe value, then -change the governor to performance or ondemand, and the frequency can -then be manually adjusted by only touching scaling_max_freq. - -New values are 1896, 1920, 1992, 2016, 2040 MHz, 2064, 2088, 2112, -2136, 2160, 2184, 2208. MiQi boards work fine up to 2112 with a very -good power supply (5.2V/3A real) and a strong heatsink. Higher -frequencies may randomly work. At least 1992 is rock solid for hours -using "openssl speed -multi 4". The other ones have only been tested -for a few minutes. Frequencies of 1896 and 1920 MHz use 1.425V. -1992 MHz uses 1.45V. 2016, 2040 and 2064 use 1.475V. 2088 and above -use 1.500V. 2160, 2184 and 2208 cause the lowest frequency to be -picked. It's obvious that it's a sign issue somewhere in the kernel -but this one was not found yet. - -Signed-off-by: Myy ---- - arch/arm/boot/dts/rk3288-miqi.dts | 120 +++++++++++++++++++++++++++++++++----- - 1 file changed, 107 insertions(+), 13 deletions(-) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index 80603a3d..d7fde483 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -122,22 +122,116 @@ - regulator-always-on; - regulator-boot-on; - }; --}; - -+ -+ cpu0_opp_table: opp_table0 { -+ compatible = "operating-points-v2"; -+ opp-shared; -+ -+ opp@600000000 { -+ opp-hz = /bits/ 64 <600000000>; -+ opp-microvolt = <900000>; -+ }; -+ opp@816000000 { -+ opp-hz = /bits/ 64 <816000000>; -+ opp-microvolt = <1000000>; -+ }; -+ opp@1008000000 { -+ opp-hz = /bits/ 64 <1008000000>; -+ opp-microvolt = <1050000>; -+ }; -+ opp@1200000000 { -+ opp-hz = /bits/ 64 <1200000000>; -+ opp-microvolt = <1100000>; -+ }; -+ opp@1416000000 { -+ opp-hz = /bits/ 64 <1416000000>; -+ opp-microvolt = <1200000>; -+ }; -+ opp@1512000000 { -+ opp-hz = /bits/ 64 <1512000000>; -+ opp-microvolt = <1250000>; -+ }; -+ opp@1608000000 { -+ opp-hz = /bits/ 64 <1608000000>; -+ opp-microvolt = <1300000>; -+ }; -+ opp@1704000000 { -+ opp-hz = /bits/ 64 <1704000000>; -+ opp-microvolt = <1350000>; -+ }; -+ opp@1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <1400000>; -+ }; -+ /* boot-only frequencies below */ -+ opp@1896000000 { -+ opp-hz = /bits/ 64 <1896000000>; -+ opp-microvolt = <1425000>; -+ turbo-mode; -+ }; -+ opp@1920000000 { -+ opp-hz = /bits/ 64 <1920000000>; -+ opp-microvolt = <1425000>; -+ turbo-mode; -+ }; -+ opp@1992000000 { -+ opp-hz = /bits/ 64 <1992000000>; -+ opp-microvolt = <1450000>; -+ turbo-mode; -+ }; -+ opp@2016000000 { -+ opp-hz = /bits/ 64 <2016000000>; -+ opp-microvolt = <1475000>; -+ turbo-mode; -+ }; -+ opp@2040000000 { -+ opp-hz = /bits/ 64 <2040000000>; -+ opp-microvolt = <1475000>; -+ turbo-mode; -+ }; -+ opp@2064000000 { -+ opp-hz = /bits/ 64 <2064000000>; -+ opp-microvolt = <1475000>; -+ turbo-mode; -+ }; -+ opp@2088000000 { -+ opp-hz = /bits/ 64 <2088000000>; -+ opp-microvolt = <1500000>; -+ turbo-mode; -+ }; -+ opp@2112000000 { -+ opp-hz = /bits/ 64 <2112000000>; -+ opp-microvolt = <1500000>; -+ turbo-mode; -+ }; -+ opp@2136000000 { -+ opp-hz = /bits/ 64 <2136000000>; -+ opp-microvolt = <1500000>; -+ turbo-mode; -+ }; -+ opp@2160000000 { -+ opp-hz = /bits/ 64 <2160000000>; -+ opp-microvolt = <1500000>; -+ turbo-mode; -+ }; -+ opp@2184000000 { -+ opp-hz = /bits/ 64 <2184000000>; -+ opp-microvolt = <1500000>; -+ turbo-mode; -+ }; -+ opp@2208000000 { -+ opp-hz = /bits/ 64 <2208000000>; -+ opp-microvolt = <1500000>; -+ turbo-mode; -+ }; -+ }; -+}; -+ - &cpu0 { - cpu0-supply = <&vdd_cpu>; -- operating-points = < -- /* KHz uV */ -- 1800000 1400000 -- 1704000 1350000 -- 1608000 1300000 -- 1512000 1250000 -- 1416000 1200000 -- 1200000 1100000 -- 1008000 1050000 -- 816000 1000000 -- 600000 900000 -- >; -+ -+ operating-points-v2 = <&cpu0_opp_table>; - }; - - &emmc { --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1005-drivers-mmc-dw-mci-rockchip-Handle-ASUS-Tinkerboard.patch b/buildroot-external/board/asus/tinker/patches/linux/2005-drivers-mmc-dw-mci-rockchip-Handle-ASUS-Tinkerboard.patch similarity index 100% rename from buildroot-external/board/asus/tinker/patches/linux/1005-drivers-mmc-dw-mci-rockchip-Handle-ASUS-Tinkerboard.patch rename to buildroot-external/board/asus/tinker/patches/linux/2005-drivers-mmc-dw-mci-rockchip-Handle-ASUS-Tinkerboard.patch diff --git a/buildroot-external/board/asus/tinker/patches/linux/2006-ARM-DTSI-rk3288-Missing-GRF-handles.patch b/buildroot-external/board/asus/tinker/patches/linux/2006-ARM-DTSI-rk3288-Missing-GRF-handles.patch deleted file mode 100644 index 1014485f8..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2006-ARM-DTSI-rk3288-Missing-GRF-handles.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 771bcfe1735e42650b763e52a042a9fd98b2fa5b Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 21:20:43 +0200 -Subject: [PATCH 09/28] ARM: DTSI: rk3288.dtsi: Missing GRF handles - -Add missing GRF handles. - -This patch is taken from the patches provided by the ARMbian team. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288.dtsi | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi -index 356ed1e6..5b789528 100644 ---- a/arch/arm/boot/dts/rk3288.dtsi -+++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -547,6 +547,7 @@ - pinctrl-2 = <&otp_gpio>; - #thermal-sensor-cells = <1>; - rockchip,hw-tshut-temp = <95000>; -+ rockchip,grf = <&grf>; - status = "disabled"; - }; - -@@ -655,6 +656,7 @@ - pinctrl-0 = <&pwm0_pin>; - clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; -+ rockchip,grf = <&grf>; - status = "disabled"; - }; - -@@ -666,6 +668,7 @@ - pinctrl-0 = <&pwm1_pin>; - clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; -+ rockchip,grf = <&grf>; - status = "disabled"; - }; - -@@ -677,6 +680,7 @@ - pinctrl-0 = <&pwm2_pin>; - clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; -+ rockchip,grf = <&grf>; - status = "disabled"; - }; - -@@ -688,6 +692,7 @@ - pinctrl-0 = <&pwm3_pin>; - clocks = <&cru PCLK_PWM>; - clock-names = "pwm"; -+ rockchip,grf = <&grf>; - status = "disabled"; - }; - --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1006-soc-rockchip-power-domain-export-idle-request.patch b/buildroot-external/board/asus/tinker/patches/linux/2006-soc-rockchip-power-domain-export-idle-request.patch similarity index 58% rename from buildroot-external/board/asus/tinker/patches/linux/1006-soc-rockchip-power-domain-export-idle-request.patch rename to buildroot-external/board/asus/tinker/patches/linux/2006-soc-rockchip-power-domain-export-idle-request.patch index be15c3554..5db1e6227 100644 --- a/buildroot-external/board/asus/tinker/patches/linux/1006-soc-rockchip-power-domain-export-idle-request.patch +++ b/buildroot-external/board/asus/tinker/patches/linux/2006-soc-rockchip-power-domain-export-idle-request.patch @@ -1,32 +1,24 @@ -From 4ffe79de7272234408a9179aa4c403ee1b67a362 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 7 Dec 2017 21:27:52 +0100 -Subject: [PATCH] soc: rockchip: power-domain: export idle request +From e7b60b10cf3fd2f4374ab26c314383121c27fe82 Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Tue, 22 Jan 2019 21:24:37 +0100 +Subject: [PATCH] soc: rockchip: power-domain: export idle request for RKMPP -We need to put the power status of HEVC/RKVDEC IP into IDLE -unless we can't reset that IP or the SoC would crash down. -rockchip_pmu_idle_request(dev, true)---> enter idle -rockchip_pmu_idle_request(dev, false)---> exit idle +This function, and the added header, are required by the RKMPP driver, +provided by Randy Li. However, I can't attest that the provided code +is correct. -Only the video codec drivers of rockchip platform would -request this patch currently. - -I am not sure whether it is necessary to add a new function -at generic power domain. I want someone give me some advises -here. - -Signed-off-by: Myy Miouyouyou +Signed-off-by: Miouyouyou (Myy) --- drivers/soc/rockchip/pm_domains.c | 23 +++++++++++++++++++++++ - include/linux/rockchip_pmu.h | 15 +++++++++++++++ + include/soc/rockchip/pm_domains.h | 15 +++++++++++++++ 2 files changed, 38 insertions(+) - create mode 100644 include/linux/rockchip_pmu.h + create mode 100644 include/soc/rockchip/pm_domains.h diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c -index 40b75748..0006ed53 100644 +index 847c7c482..3e2e252cb 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c -@@ -180,6 +180,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, +@@ -199,6 +199,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, return 0; } @@ -56,11 +48,11 @@ index 40b75748..0006ed53 100644 static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) { int i; -diff --git a/include/linux/rockchip_pmu.h b/include/linux/rockchip_pmu.h +diff --git a/include/soc/rockchip/pm_domains.h b/include/soc/rockchip/pm_domains.h new file mode 100644 -index 00000000..720b3314 +index 000000000..720b3314e --- /dev/null -+++ b/include/linux/rockchip_pmu.h ++++ b/include/soc/rockchip/pm_domains.h @@ -0,0 +1,15 @@ +/* + * pm_domain.h - Definitions and headers related to device power domains. @@ -78,5 +70,5 @@ index 00000000..720b3314 + +#endif /* _LINUX_ROCKCHIP_PM_H */ -- -2.14.1 +2.16.4 diff --git a/buildroot-external/board/asus/tinker/patches/linux/2007-drivers-wifi-ath9k-reverse-do-not-use-bulk-on-EP3-and-EP4.patch b/buildroot-external/board/asus/tinker/patches/linux/2007-drivers-wifi-ath9k-reverse-do-not-use-bulk-on-EP3-and-EP4.patch new file mode 100644 index 000000000..551c18cc5 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/2007-drivers-wifi-ath9k-reverse-do-not-use-bulk-on-EP3-and-EP4.patch @@ -0,0 +1,101 @@ +FROM: Solidhal + +This patch reverses commit 2b721118b7821107757eb1d37af4b60e877b27e7, as can bee seen here: +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2b721118b7821107757eb1d37af4b60e877b27e7 + +This commit caused issues on veyron speedy with ath9k and dwc2 drivers. Any ath9k device (ar9271) +would intermittently work, most of the time ending in errors as can bee seen here: +https://github.com/SolidHal/PrawnOS/issues/38 +This commit fixes that issue. +This is only a temporary work around while a permenant fix is found, as this commit seems to only cause issues +with dwc2 + +diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c +--- b/drivers/net/wireless/ath/ath9k/hif_usb.c ++++ a/drivers/net/wireless/ath/ath9k/hif_usb.c +@@ -115,10 +115,10 @@ + cmd->skb = skb; + cmd->hif_dev = hif_dev; + ++ usb_fill_bulk_urb(urb, hif_dev->udev, ++ usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE), +- usb_fill_int_urb(urb, hif_dev->udev, +- usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE), + skb->data, skb->len, ++ hif_usb_regout_cb, cmd); +- hif_usb_regout_cb, cmd, 1); + + usb_anchor_urb(urb, &hif_dev->regout_submitted); + ret = usb_submit_urb(urb, GFP_KERNEL); +@@ -723,11 +723,11 @@ + return; + } + ++ usb_fill_bulk_urb(urb, hif_dev->udev, ++ usb_rcvbulkpipe(hif_dev->udev, +- usb_fill_int_urb(urb, hif_dev->udev, +- usb_rcvintpipe(hif_dev->udev, + USB_REG_IN_PIPE), + nskb->data, MAX_REG_IN_BUF_SIZE, ++ ath9k_hif_usb_reg_in_cb, nskb); +- ath9k_hif_usb_reg_in_cb, nskb, 1); + } + + resubmit: +@@ -909,11 +909,11 @@ + goto err_skb; + } + ++ usb_fill_bulk_urb(urb, hif_dev->udev, ++ usb_rcvbulkpipe(hif_dev->udev, +- usb_fill_int_urb(urb, hif_dev->udev, +- usb_rcvintpipe(hif_dev->udev, + USB_REG_IN_PIPE), + skb->data, MAX_REG_IN_BUF_SIZE, ++ ath9k_hif_usb_reg_in_cb, skb); +- ath9k_hif_usb_reg_in_cb, skb, 1); + + /* Anchor URB */ + usb_anchor_urb(urb, &hif_dev->reg_in_submitted); +@@ -1031,7 +1031,9 @@ + + static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) + { ++ struct usb_host_interface *alt = &hif_dev->interface->altsetting[0]; ++ struct usb_endpoint_descriptor *endp; ++ int ret, idx; +- int ret; + + ret = ath9k_hif_usb_download_fw(hif_dev); + if (ret) { +@@ -1041,6 +1043,20 @@ + return ret; + } + ++ /* On downloading the firmware to the target, the USB descriptor of EP4 ++ * is 'patched' to change the type of the endpoint to Bulk. This will ++ * bring down CPU usage during the scan period. ++ */ ++ for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) { ++ endp = &alt->endpoint[idx].desc; ++ if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_INT) { ++ endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK; ++ endp->bmAttributes |= USB_ENDPOINT_XFER_BULK; ++ endp->bInterval = 0; ++ } ++ } ++ + /* Alloc URBs */ + ret = ath9k_hif_usb_alloc_urbs(hif_dev); + if (ret) { +@@ -1252,7 +1268,7 @@ + if (!buf) + return; + ++ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE), +- ret = usb_interrupt_msg(udev, usb_sndintpipe(udev, USB_REG_OUT_PIPE), + buf, 4, NULL, USB_MSG_TIMEOUT); + if (ret) + dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n"); + diff --git a/buildroot-external/board/asus/tinker/patches/linux/2008-Added-support-for-Tinkerboard-s-SPI-interface.patch b/buildroot-external/board/asus/tinker/patches/linux/2008-Added-support-for-Tinkerboard-s-SPI-interface.patch deleted file mode 100644 index b20d17616..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2008-Added-support-for-Tinkerboard-s-SPI-interface.patch +++ /dev/null @@ -1,27 +0,0 @@ -From af8d73ec0df1dde1e2fe1674c5708d4c30385ba9 Mon Sep 17 00:00:00 2001 -From: Myy -Date: Mon, 5 Jun 2017 12:37:17 +0000 -Subject: [PATCH 11/28] Added support for Tinkerboard's SPI interface - -Imported from ARMbian - -Signed-off-by: Myy ---- - drivers/spi/spidev.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c -index cda10719..a6287475 100644 ---- a/drivers/spi/spidev.c -+++ b/drivers/spi/spidev.c -@@ -669,6 +669,7 @@ static const struct of_device_id spidev_dt_ids[] = { - { .compatible = "lineartechnology,ltc2488" }, - { .compatible = "ge,achc" }, - { .compatible = "semtech,sx1301" }, -+ { .compatible = "rockchip,spi_tinker" }, - {}, - }; - MODULE_DEVICE_TABLE(of, spidev_dt_ids); --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1009-drivers-clk-rk3288-support-for-dedicating-NPLL-to-a-.patch b/buildroot-external/board/asus/tinker/patches/linux/2008-clk-rockchip-rk3288-Support-for-dedicating-NPLL-to-a.patch similarity index 67% rename from buildroot-external/board/asus/tinker/patches/linux/1009-drivers-clk-rk3288-support-for-dedicating-NPLL-to-a-.patch rename to buildroot-external/board/asus/tinker/patches/linux/2008-clk-rockchip-rk3288-Support-for-dedicating-NPLL-to-a.patch index 11aa9525b..9e988f19c 100644 --- a/buildroot-external/board/asus/tinker/patches/linux/1009-drivers-clk-rk3288-support-for-dedicating-NPLL-to-a-.patch +++ b/buildroot-external/board/asus/tinker/patches/linux/2008-clk-rockchip-rk3288-Support-for-dedicating-NPLL-to-a.patch @@ -1,7 +1,7 @@ -From bc16cd0aa3cdaaff27b9bf2d3282ccfff81d8784 Mon Sep 17 00:00:00 2001 +From e03d074b8ec00718337e7373e991912f6b6f9a52 Mon Sep 17 00:00:00 2001 From: "Miouyouyou (Myy)" -Date: Sat, 29 Sep 2018 02:56:32 +0200 -Subject: [PATCH 5/6] drivers: clk-rk3288: support for dedicating NPLL to a VOP +Date: Mon, 5 Nov 2018 19:53:43 +0100 +Subject: [PATCH] clk: rockchip: rk3288: Support for dedicating NPLL to a VOP This patch is taken from Urja Rannikko ( @urjaman ) patchset here : https://github.com/urjaman/arch-c201/blob/master/linux-c201/0020-RK3288-HDMI-clock-hacks-combined.patch @@ -15,69 +15,21 @@ I have no clear idea how HDMI Neuronal PLL (and PLL in general) work, so I cannot comment on what it's doing and if it's a good idea in general. -The only thing I know from this patchset is that it works and have -resolved some purple line issue at the left of my HDMI screen, when -connected to MiQi or Tinkerboard devices. +Now, I still have to test if that patch does anything useful on +RK3288 boards. If it doesn't, I might just throw it away on next +versions. Signed-off-by: Miouyouyou (Myy) --- - drivers/clk/rockchip/clk-rk3288.c | 98 ++++++++++++++++++++++++++++++++------- + drivers/clk/rockchip/clk-rk3288.c | 68 ++++++++++++++++++++++++++++++++------- drivers/clk/rockchip/clk.h | 3 ++ - 2 files changed, 85 insertions(+), 16 deletions(-) + 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c -index fd2058f7d..b5b56169d 100644 +index 13b38cb89..0d8b99b6b 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c -@@ -83,22 +83,43 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = { - RK3066_PLL_RATE( 768000000, 1, 64, 2), - RK3066_PLL_RATE( 742500000, 8, 495, 2), - RK3066_PLL_RATE( 696000000, 1, 58, 2), -+ RK3066_PLL_RATE_NB(621000000, 1, 207, 8, 1), - RK3066_PLL_RATE( 600000000, 1, 50, 2), - RK3066_PLL_RATE_NB(594000000, 1, 198, 8, 1), - RK3066_PLL_RATE( 552000000, 1, 46, 2), - RK3066_PLL_RATE( 504000000, 1, 84, 4), - RK3066_PLL_RATE( 500000000, 3, 125, 2), - RK3066_PLL_RATE( 456000000, 1, 76, 4), -+ RK3066_PLL_RATE( 428000000, 1, 107, 6), - RK3066_PLL_RATE( 408000000, 1, 68, 4), - RK3066_PLL_RATE( 400000000, 3, 100, 2), -+ RK3066_PLL_RATE_NB( 394000000, 1, 197, 12, 1), - RK3066_PLL_RATE( 384000000, 2, 128, 4), - RK3066_PLL_RATE( 360000000, 1, 60, 4), -+ RK3066_PLL_RATE_NB( 356000000, 1, 178, 12, 1), -+ RK3066_PLL_RATE_NB( 324000000, 1, 189, 14, 1), - RK3066_PLL_RATE( 312000000, 1, 52, 4), -- RK3066_PLL_RATE( 300000000, 1, 50, 4), -- RK3066_PLL_RATE( 297000000, 2, 198, 8), -+ RK3066_PLL_RATE_NB( 308000000, 1, 154, 12, 1), -+ RK3066_PLL_RATE_NB( 303000000, 1, 202, 16, 1), -+ RK3066_PLL_RATE( 300000000, 1, 75, 6), -+ RK3066_PLL_RATE_NB( 297750000, 2, 397, 16, 1), -+ RK3066_PLL_RATE_NB( 293250000, 2, 391, 16, 1), -+ RK3066_PLL_RATE_NB( 292500000, 1, 195, 16, 1), -+ RK3066_PLL_RATE( 273600000, 1, 114, 10), -+ RK3066_PLL_RATE_NB( 273000000, 1, 182, 16, 1), -+ RK3066_PLL_RATE_NB( 270000000, 1, 180, 16, 1), -+ RK3066_PLL_RATE_NB( 266250000, 2, 355, 16, 1), -+ RK3066_PLL_RATE_NB( 256500000, 1, 171, 16, 1), - RK3066_PLL_RATE( 252000000, 1, 84, 8), -- RK3066_PLL_RATE( 216000000, 1, 72, 8), -- RK3066_PLL_RATE( 148500000, 2, 99, 8), -+ RK3066_PLL_RATE_NB( 250500000, 1, 167, 16, 1), -+ RK3066_PLL_RATE_NB( 243428571, 1, 142, 14, 1), -+ RK3066_PLL_RATE( 238000000, 1, 119, 12), -+ RK3066_PLL_RATE_NB( 219750000, 2, 293, 16, 1), -+ RK3066_PLL_RATE_NB( 216000000, 1, 144, 16, 1), -+ RK3066_PLL_RATE_NB( 213000000, 1, 142, 16, 1), -+ RK3066_PLL_RATE( 195428571, 1, 114, 14), -+ RK3066_PLL_RATE( 160000000, 1, 80, 12), -+ RK3066_PLL_RATE( 157500000, 1, 105, 16), - RK3066_PLL_RATE( 126000000, 1, 84, 16), - RK3066_PLL_RATE( 48000000, 1, 64, 32), - { /* sentinel */ }, -@@ -194,10 +215,14 @@ PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; +@@ -215,10 +215,13 @@ PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu" }; PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; @@ -88,14 +40,13 @@ index fd2058f7d..b5b56169d 100644 +PNAME_ED(mux_pll_src_cgn_pll_nonvop_p) = { "cpll", "gpll", "npll" }; +PNAME_ED(mux_pll_src_cgn_pll_vop0_p) = { "cpll", "gpll", "npll" }; +PNAME_ED(mux_pll_src_cgn_pll_vop1_p) = { "cpll", "gpll", "npll" }; -+ - PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usbphy480m_src" }; --PNAME(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "usbphy480m_src", "npll" }; + PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "unstable:usbphy480m_src" }; +-PNAME(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "unstable:usbphy480m_src", "npll" }; +PNAME_ED(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "usbphy480m_src", "npll" }; PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "xin24m" }; PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; -@@ -443,24 +468,24 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { +@@ -464,24 +467,24 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { RK3288_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(3), 4, GFLAGS), @@ -125,7 +76,7 @@ index fd2058f7d..b5b56169d 100644 RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS, RK3288_CLKGATE_CON(3), 15, GFLAGS), -@@ -469,16 +494,16 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { +@@ -490,16 +493,16 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0, RK3288_CLKGATE_CON(5), 11, GFLAGS), @@ -145,7 +96,7 @@ index fd2058f7d..b5b56169d 100644 RK3288_CLKSEL_CON(42), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(13), 15, GFLAGS), -@@ -552,7 +577,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { +@@ -573,7 +576,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "sclk_tspout", mux_tspout_p, 0, RK3288_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(4), 11, GFLAGS), @@ -154,15 +105,14 @@ index fd2058f7d..b5b56169d 100644 RK3288_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3288_CLKGATE_CON(4), 10, GFLAGS), -@@ -912,6 +937,7 @@ static void __init rk3288_clk_init(struct device_node *np) +@@ -933,5 +936,6 @@ static void __init rk3288_clk_init(struct device_node *np) { struct rockchip_clk_provider *ctx; - struct clk *clk; + s32 npll_vop = -1; rk3288_cru_base = of_iomap(np, 0); if (!rk3288_cru_base) { -@@ -919,6 +945,46 @@ static void __init rk3288_clk_init(struct device_node *np) +@@ -940,6 +944,46 @@ static void __init rk3288_clk_init(struct device_node *np) return; } diff --git a/buildroot-external/board/asus/tinker/patches/linux/2009-ARM-DTSI-rk3288-Adding-cells-addresses-and-size.patch b/buildroot-external/board/asus/tinker/patches/linux/2009-ARM-DTSI-rk3288-Adding-cells-addresses-and-size.patch deleted file mode 100644 index 6ab81139e..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2009-ARM-DTSI-rk3288-Adding-cells-addresses-and-size.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 7af8d2bf732cb3baab7d926ed8a7e061e7a09ad9 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 21:39:00 +0200 -Subject: [PATCH 13/28] ARM: DTSI: rk3288.dtsi: Adding cells addresses and - sizes of MMC nodes - -Imported from the Rockchip 4.4 patches. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288.dtsi | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi -index be985f02..14ef8202 100644 ---- a/arch/arm/boot/dts/rk3288.dtsi -+++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -236,6 +236,8 @@ - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; - reg = <0x0 0xff0c0000 0x0 0x4000>; - resets = <&cru SRST_MMC0>; - reset-names = "reset"; -@@ -250,6 +252,8 @@ - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; - reg = <0x0 0xff0d0000 0x0 0x4000>; - resets = <&cru SRST_SDIO0>; - reset-names = "reset"; -@@ -264,6 +268,8 @@ - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; - reg = <0x0 0xff0e0000 0x0 0x4000>; - resets = <&cru SRST_SDIO1>; - reset-names = "reset"; -@@ -278,6 +284,8 @@ - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - interrupts = ; -+ #address-cells = <1>; -+ #size-cells = <0>; - reg = <0x0 0xff0f0000 0x0 0x4000>; - resets = <&cru SRST_EMMC>; - reset-names = "reset"; --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/1010-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch b/buildroot-external/board/asus/tinker/patches/linux/2009-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch similarity index 90% rename from buildroot-external/board/asus/tinker/patches/linux/1010-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch rename to buildroot-external/board/asus/tinker/patches/linux/2009-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch index ea9b62231..afbc1be58 100644 --- a/buildroot-external/board/asus/tinker/patches/linux/1010-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch +++ b/buildroot-external/board/asus/tinker/patches/linux/2009-drm-dw_hdmi-rockchip-better-clock-selection-logic-an.patch @@ -42,17 +42,14 @@ frequencies easier, in case you have a very special HDMI screen. Signed-off-by: Miouyouyou (Myy) --- - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 269 ++++++++++++++++++---------- - 1 file changed, 175 insertions(+), 94 deletions(-) - diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -index 11309a2a4..740b0aeea 100644 +index cdc304d4c..91c7dc07b 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c -@@ -49,122 +49,141 @@ struct rockchip_hdmi { - struct clk *vpll_clk; +@@ -73,122 +73,141 @@ struct rockchip_hdmi { struct clk *grf_clk; struct dw_hdmi *hdmi; + struct phy *phy; + u32* rates; + u32 rates_cnt; }; @@ -273,7 +270,7 @@ index 11309a2a4..740b0aeea 100644 hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(hdmi->regmap)) { -@@ -192,26 +211,55 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) +@@ -216,26 +235,55 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return PTR_ERR(hdmi->grf_clk); } @@ -338,7 +335,7 @@ index 11309a2a4..740b0aeea 100644 } static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = { -@@ -227,7 +275,39 @@ dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, +@@ -251,7 +299,39 @@ dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { @@ -379,7 +376,7 @@ index 11309a2a4..740b0aeea 100644 } static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder, -@@ -280,6 +360,7 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, +@@ -307,6 +387,7 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder, } static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = { @@ -387,7 +384,15 @@ index 11309a2a4..740b0aeea 100644 .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup, .mode_set = dw_hdmi_rockchip_encoder_mode_set, .enable = dw_hdmi_rockchip_encoder_enable, -@@ -294,7 +375,6 @@ static struct rockchip_hdmi_chip_data rk3288_chip_data = { +@@ -406,7 +487,6 @@ static struct rockchip_hdmi_chip_data rk3228_chip_data = { + }; + + static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = { +- .mode_valid = dw_hdmi_rockchip_mode_valid, + .mpll_cfg = rockchip_mpll_cfg, + .cur_ctr = rockchip_cur_ctr, + .phy_config = rockchip_phy_config, +@@ -423,7 +503,6 @@ static struct rockchip_hdmi_chip_data rk3288_chip_data = { }; static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = { @@ -395,7 +400,15 @@ index 11309a2a4..740b0aeea 100644 .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config, -@@ -308,7 +388,6 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { +@@ -443,7 +522,6 @@ static struct rockchip_hdmi_chip_data rk3328_chip_data = { + }; + + static const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = { +- .mode_valid = dw_hdmi_rockchip_mode_valid, + .mpll_cfg = rockchip_mpll_cfg, + .cur_ctr = rockchip_cur_ctr, + .phy_config = rockchip_phy_config, +@@ -460,7 +538,6 @@ static struct rockchip_hdmi_chip_data rk3399_chip_data = { }; static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { @@ -403,7 +416,7 @@ index 11309a2a4..740b0aeea 100644 .mpll_cfg = rockchip_mpll_cfg, .cur_ctr = rockchip_cur_ctr, .phy_config = rockchip_phy_config, -@@ -387,6 +466,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, +@@ -558,6 +635,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, */ if (IS_ERR(hdmi->hdmi)) { ret = PTR_ERR(hdmi->hdmi); @@ -411,7 +424,7 @@ index 11309a2a4..740b0aeea 100644 drm_encoder_cleanup(encoder); clk_disable_unprepare(hdmi->vpll_clk); } -@@ -399,6 +479,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, +@@ -570,6 +648,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master, { struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); @@ -419,6 +432,3 @@ index 11309a2a4..740b0aeea 100644 dw_hdmi_unbind(hdmi->hdmi); clk_disable_unprepare(hdmi->vpll_clk); } --- -2.16.4 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2013-ARM-DTS-rk3288-tinker-Enabling-SDIO-Wireless-and.patch b/buildroot-external/board/asus/tinker/patches/linux/2013-ARM-DTS-rk3288-tinker-Enabling-SDIO-Wireless-and.patch deleted file mode 100644 index 58e842a13..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2013-ARM-DTS-rk3288-tinker-Enabling-SDIO-Wireless-and.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 2715f4a9ab5c169c546029a61eebb0bde6619b0e Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 22:12:48 +0200 -Subject: [PATCH 18/28] ARM: DTS: rk3288-tinker.dts: Enabling SDIO, Wireless - and Bluetooth - -Adding the appropriate nodes in order to exploit the WiFi capabilities -of the board. -Since these capabilities are provided through SDIO, and the SDIO -nodes were not defined, these were added too. - -These seems to depend on each other so they are added in one big -patch. - -Split if necessary. - -Bluetooth and uart0 (AKA Bluetooth UART) definitions were also added -in order to deal with all the wireless techs in one patch. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-tinker.dts | 82 ++++++++++++++++++++++++++++++++++++- - 1 file changed, 81 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 346b0d8b..c552fd95 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -44,6 +44,7 @@ - - #include "rk3288.dtsi" - #include -+#include - - / { - model = "Rockchip RK3288 Tinker Board"; -@@ -114,6 +115,24 @@ - }; - }; - -+ /* This is essential to get SDIO devices working. -+ The Wifi depends on SDIO ! */ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ clocks = <&rk808 RK808_CLKOUT1>; -+ clock-names = "ext_clock"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&chip_enable_h>, <&wifi_enable_h>; -+ -+ /* -+ * On the module itself this is one of these (depending -+ * on the actual card populated): -+ * - SDIO_RESET_L_WL_REG_ON -+ * - PDN (power down when low) -+ */ -+ reset-gpios = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>, <&gpio4 RK_PD3 GPIO_ACTIVE_LOW>; -+ }; -+ - vcc_sys: vsys-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_sys"; -@@ -134,6 +153,28 @@ - startup-delay-us = <100000>; - vin-supply = <&vcc_io>; - }; -+ -+ wireless-wlan { -+ compatible = "wlan-platdata"; -+ rockchip,grf = <&grf>; -+ wifi_chip_type = "8723bs"; -+ sdio_vref = <1800>; -+ WIFI,host_wake_irq = <&gpio4 30 GPIO_ACTIVE_HIGH>; -+ status = "okay"; -+ }; -+ -+ wireless-bluetooth { -+ compatible = "bluetooth-platdata"; -+ uart_rts_gpios = <&gpio4 19 GPIO_ACTIVE_LOW>; -+ pinctrl-names = "default","rts_gpio"; -+ pinctrl-0 = <&uart0_rts>; -+ pinctrl-1 = <&uart0_gpios>; -+ BT,reset_gpio = <&gpio4 29 GPIO_ACTIVE_HIGH>; -+ BT,wake_gpio = <&gpio4 26 GPIO_ACTIVE_HIGH>; -+ BT,wake_host_irq = <&gpio4 31 GPIO_ACTIVE_HIGH>; -+ status = "okay"; -+ }; -+ - }; - - &cpu0 { -@@ -373,10 +414,30 @@ - - &io_domains { - status = "okay"; -- -+ rockchip,grf = <&grf>; -+ wifi-supply = <&vcc_18>; - sdcard-supply = <&vccio_sd>; - }; - -+&sdio0 { -+ status = "okay"; -+ clock-frequency = <50000000>; -+ clock-freq-min-max = <200000 50000000>; -+ bus-width = <4>; -+ cap-sd-highspeed; -+ cap-sdio-irq; -+ disable-wp; -+ keep-power-in-suspend; -+ mmc-pwrseq = <&sdio_pwrseq>; -+ non-removable; -+ num-slots = <1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>; -+ sd-uhs-sdr104; -+ supports-sdio; -+ -+}; -+ - &pinctrl { - pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma { - drive-strength = <8>; -@@ -422,6 +483,16 @@ - }; - }; - -+ sdio-pwrseq { -+ wifi_enable_h: wifienable-h { -+ rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ chip_enable_h: chip-enable-h { -+ rockchip,pins = <4 27 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - sdmmc { - sdmmc_bus4: sdmmc-bus4 { - rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_8ma>, -@@ -453,6 +524,13 @@ - rockchip,pins = <7 8 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; -+ -+ wireless-bluetooth { -+ uart0_gpios: uart0-gpios { -+ rockchip,pins = <4 19 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ - }; - - &pwm0 { -@@ -485,6 +563,8 @@ - - &uart0 { - status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_xfer>, <&uart0_cts>; - }; - - &uart1 { --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2013-spi-Added-support-for-Tinkerboard-s-SPI-interface.patch b/buildroot-external/board/asus/tinker/patches/linux/2013-spi-Added-support-for-Tinkerboard-s-SPI-interface.patch new file mode 100644 index 000000000..8e0b23b57 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/2013-spi-Added-support-for-Tinkerboard-s-SPI-interface.patch @@ -0,0 +1,22 @@ +From d4d128324b8f8a9f5c441203d94703e41fa07df3 Mon Sep 17 00:00:00 2001 +From: "Miouyouyou (Myy)" +Date: Mon, 5 Nov 2018 19:57:56 +0100 +Subject: [PATCH] spi: Added support for Tinkerboard's SPI interface + +Imported from ARMbian + +Signed-off-by: Miouyouyou (Myy) +--- + +diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c +index 255786f2e..3a3f2e6fd 100644 +--- a/drivers/spi/spidev.c ++++ b/drivers/spi/spidev.c +@@ -665,6 +665,7 @@ static const struct of_device_id spidev_dt_ids[] = { + { .compatible = "lwn,bk4" }, + { .compatible = "dh,dhcom-board" }, + { .compatible = "menlo,m53cpld" }, ++ { .compatible = "rockchip,spi_tinker" }, + {}, + }; + MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/buildroot-external/board/asus/tinker/patches/linux/2014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch b/buildroot-external/board/asus/tinker/patches/linux/2014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch deleted file mode 100644 index 5f7dbd6f4..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2014-ARM-DTS-rk3288-tinker-Setup-the-Bluetooth-UART-pins.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 07b4af4..7755426 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -162,7 +162,7 @@ - WIFI,host_wake_irq = <&gpio4 30 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; -- -+/* - wireless-bluetooth { - compatible = "bluetooth-platdata"; - uart_rts_gpios = <&gpio4 19 GPIO_ACTIVE_LOW>; -@@ -174,6 +174,7 @@ - BT,wake_host_irq = <&gpio4 31 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; -+*/ - - }; - -@@ -620,7 +621,7 @@ - &uart0 { - status = "okay"; - pinctrl-names = "default"; -- pinctrl-0 = <&uart0_xfer>, <&uart0_cts>; -+ pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>; - }; - - &uart1 { diff --git a/buildroot-external/board/asus/tinker/patches/linux/2015-ARM-DTS-rk3288-tinker-Improving-the-CPU-max-volt.patch b/buildroot-external/board/asus/tinker/patches/linux/2015-ARM-DTS-rk3288-tinker-Improving-the-CPU-max-volt.patch deleted file mode 100644 index 21a176b52..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2015-ARM-DTS-rk3288-tinker-Improving-the-CPU-max-volt.patch +++ /dev/null @@ -1,29 +0,0 @@ -From d4775f623b25009039a8ef3f28332033c7766ecc Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 22:20:33 +0200 -Subject: [PATCH 19/28] ARM: DTS: rk3288-tinker.dts: Improving the CPU max - voltage - -Taken from the various patches provided by @TonyMac32 . - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-tinker.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index c552fd95..4ce94698 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -243,7 +243,7 @@ - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; -- regulator-max-microvolt = <1350000>; -+ regulator-max-microvolt = <1450000>; - regulator-name = "vdd_arm"; - regulator-ramp-delay = <6000>; - regulator-state-mem { --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2016-ARM-DTS-rk3288-tinker-Setting-up-the-SD-regulato.patch b/buildroot-external/board/asus/tinker/patches/linux/2016-ARM-DTS-rk3288-tinker-Setting-up-the-SD-regulato.patch deleted file mode 100644 index 4db124399..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2016-ARM-DTS-rk3288-tinker-Setting-up-the-SD-regulato.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 39e50ab508d8104a733771a8681908a66a300edd Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 22:25:03 +0200 -Subject: [PATCH 20/28] ARM: DTS: rk3288-tinker.dts: Setting up the SD - regulators - -Some are needed and some are not. Playing with these parameters is -required to get reboot working on these boards. - -I still can't believe that these boards can't soft reset correctly. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-tinker.dts | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 4ce94698..90c1a251 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -333,6 +333,8 @@ - }; - - vccio_sd: LDO_REG5 { -+ regulator-always-on; -+ regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vccio_sd"; -@@ -379,7 +381,6 @@ - }; - - vcc33_sd: SWITCH_REG1 { -- regulator-always-on; - regulator-boot-on; - regulator-name = "vcc33_sd"; - regulator-state-mem { --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch b/buildroot-external/board/asus/tinker/patches/linux/2017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch deleted file mode 100644 index e37783a13..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2017-ARM-DTS-rk3288-tinker-Defined-the-I2C-interfaces.patch +++ /dev/null @@ -1,53 +0,0 @@ -From b0a552add28bf4590b979abb3530b14b6811eec1 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 22:33:39 +0200 -Subject: [PATCH 21/28] ARM: DTS: rk3288-tinker.dts: Defined the I2C interfaces - -And all the hardware behind. - -Taken from, and tested by @TonyMac32 . - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-tinker.dts | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 90c1a251..67a3ce6f 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -400,8 +400,31 @@ - }; - }; - -+&i2c1 { -+ status = "okay"; -+}; -+ - &i2c2 { - status = "okay"; -+ -+ afc0:af-controller@0 { -+ status = "okay"; -+ compatible = "silicon touch,vm149C-v4l2-i2c-subdev"; -+ reg = <0x0c>; -+ }; -+ -+ eeprom:m24c08@50 { -+ compatible = "at,24c08"; -+ reg = <0x50>; -+ }; -+}; -+ -+&i2c3 { -+ status = "okay"; -+}; -+ -+&i2c4 { -+ status = "okay"; - }; - - &i2c5 { --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Add-the-MIPI-DSI-node.patch.disabled b/buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Add-the-MIPI-DSI-node.patch.disabled deleted file mode 100644 index 52519bb4a..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Add-the-MIPI-DSI-node.patch.disabled +++ /dev/null @@ -1,35 +0,0 @@ -From 8ca607f3fe77c80a3367d8363703d5dc1d6781d4 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 22:36:02 +0200 -Subject: [PATCH 22/28] ARM: DTS: rk3288-tinker.dts: Add the MIPI DSI node - -Taken from, and tested by @TonyMac32 . - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-tinker.dts | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 67a3ce6f..6f4c0843 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -443,6 +443,15 @@ - sdcard-supply = <&vccio_sd>; - }; - -+&mipi_dsi { -+ status = "okay"; -+ mipi_panel: mipi-panel { -+ compatible ="asus,tc358762"; -+ reg = <0x0 0>; -+ status = "okay"; -+ }; -+}; -+ - &sdio0 { - status = "okay"; - clock-frequency = <50000000>; --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Defining-SDMMC-properties.patch b/buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Defining-SDMMC-properties.patch deleted file mode 100644 index 19b96e668..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2019-ARM-DTS-rk3288-tinker-Defining-SDMMC-properties.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 58d72a1cc693c4c08391487476d0cd6d167a57cf Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Thu, 19 Oct 2017 22:48:36 +0200 -Subject: [PATCH 24/28] ARM: DTS: rk3288-tinker.dts: Defining SDMMC properties - -I never knew if these properties were required to fix the dreaded -reboot issue... - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-tinker.dts | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index f4b4525c..a0663425 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -601,7 +601,12 @@ - disable-wp; /* wp not hooked up */ - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; -+ sd-uhs-sdr12; -+ sd-uhs-sdr25; -+ sd-uhs-sdr50; -+ sd-uhs-sdr104; - status = "okay"; -+ supports-sd; - vmmc-supply = <&vcc33_sd>; - vqmmc-supply = <&vccio_sd>; - }; --- -2.11.0 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2020-ARM-DTSI-rk3288-Define-the-VPU-services.patch b/buildroot-external/board/asus/tinker/patches/linux/2020-ARM-DTSI-rk3288-Define-the-VPU-services.patch deleted file mode 100644 index cd10913db..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2020-ARM-DTSI-rk3288-Define-the-VPU-services.patch +++ /dev/null @@ -1,107 +0,0 @@ -From f4480cb8198085607c15e523b49aa21bc38cf62c Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Tue, 21 Nov 2017 21:47:33 +0100 -Subject: [PATCH 1/5] ARM: DTSI: rk3288.dtsi: Define the VPU services - -Still, you will need appropriate drivers to use them. - -Contrary to the previous versions of this patch, these services are : -* NOT enabled by default; -* MUST be activated in each individual DTS; - -I currently do not own enough RK3288 boards to ensure that the -VPU and HEVC MMU + services can be activated without issues. - -Still this patch does not generate issues like the previous one AND -still enable these services on boot, when activated properly in -individual DTS files. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288.dtsi | 63 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 63 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi -index 30b04257..bc3601ac 100644 ---- a/arch/arm/boot/dts/rk3288.dtsi -+++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -1182,6 +1182,27 @@ - status = "disabled"; - }; - -+ vpu_service: vpu-service@ff9a0000 { -+ compatible = "rockchip,vpu_service"; -+ reg = <0x0 0xff9a0000 0x0 0x800>; -+ interrupts = -+ , -+ ; -+ interrupt-names = "irq_enc", "irq_dec"; -+ clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; -+ clock-names = "aclk_vcodec", "hclk_vcodec"; -+ power-domains = <&power RK3288_PD_VIDEO>; -+ rockchip,grf = <&grf>; -+ resets = <&cru SRST_VCODEC_AXI>, <&cru SRST_VCODEC_AHB>; -+ reset-names = "video_a", "video_h"; -+ iommus = <&vpu_mmu>; -+ iommu_enabled = <1>; -+ dev_mode = <0>; -+ status = "disabled"; -+ /* 0 means ion, 1 means drm */ -+ allocator = <1>; -+ }; -+ - hevc_mmu: iommu@ff9c0440 { - compatible = "rockchip,iommu"; - reg = <0x0 0xff9c0440 0x0 0x40>, <0x0 0xff9c0480 0x0 0x40>; -@@ -1191,6 +1212,48 @@ - status = "disabled"; - }; - -+ hevc_service: hevc-service@ff9c0000 { -+ compatible = "rockchip,hevc_service"; -+ reg = <0x0 0xff9c0000 0x0 0x400>; -+ interrupts = ; -+ interrupt-names = "irq_dec"; -+ clocks = -+ <&cru ACLK_HEVC>, -+ <&cru HCLK_HEVC>, -+ <&cru SCLK_HEVC_CORE>, -+ <&cru SCLK_HEVC_CABAC>; -+ clock-names = -+ "aclk_vcodec", -+ "hclk_vcodec", -+ "clk_core", -+ "clk_cabac"; -+ /* -+ * The 4K hevc would also work well with 500/125/300/300, -+ * no more err irq and reset request. -+ */ -+ assigned-clocks = -+ <&cru ACLK_HEVC>, -+ <&cru HCLK_HEVC>, -+ <&cru SCLK_HEVC_CORE>, -+ <&cru SCLK_HEVC_CABAC>; -+ assigned-clock-rates = -+ <400000000>, -+ <100000000>, -+ <300000000>, -+ <300000000>; -+ -+ resets = <&cru SRST_HEVC>; -+ reset-names = "video"; -+ power-domains = <&power RK3288_PD_HEVC>; -+ rockchip,grf = <&grf>; -+ dev_mode = <1>; -+ iommus = <&hevc_mmu>; -+ iommu_enabled = <1>; -+ status = "disabled"; -+ /* 0 means ion, 1 means drm */ -+ allocator = <1>; -+ }; -+ - gpu: gpu@ffa30000 { - compatible = "rockchip,rk3288-mali", "arm,mali-t760"; - reg = <0x0 0xffa30000 0x0 0x10000>; --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2021-ARM-DTS-rk3288-miqi-Enable-the-Video-encoding-MM.patch b/buildroot-external/board/asus/tinker/patches/linux/2021-ARM-DTS-rk3288-miqi-Enable-the-Video-encoding-MM.patch deleted file mode 100644 index 72d13ac6c..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2021-ARM-DTS-rk3288-miqi-Enable-the-Video-encoding-MM.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 647d6012849191e9909a8acb0fc9ae5df1afc747 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Tue, 21 Nov 2017 21:51:31 +0100 -Subject: [PATCH 2/5] ARM: DTS: rk3288-miqi.dts: Enable the Video encoding MMU - and services - -Enable the : -* VPU MMU; -* VPU service; -* HEVC MMU; -* HEVC service; -on MiQi devices. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-miqi.dts | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts -index d7fde483..dd785c70 100644 ---- a/arch/arm/boot/dts/rk3288-miqi.dts -+++ b/arch/arm/boot/dts/rk3288-miqi.dts -@@ -124,7 +124,7 @@ - }; - - -- cpu0_opp_table: opp_table0 { -+ cpu0_opp_table: opp_table { - compatible = "operating-points-v2"; - opp-shared; - -@@ -575,6 +575,22 @@ - status = "okay"; - }; - -+&vpu_mmu { -+ status = "okay"; -+}; -+ -+&vpu_service { -+ status = "okay"; -+}; -+ -+&hevc_mmu { -+ status = "okay"; -+}; -+ -+&hevc_service { -+ status = "okay"; -+}; -+ - &wdt { - status = "okay"; - }; --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2022-ARM-DTS-rk3288-tinker-Enable-the-Video-encoding-MMU-.patch b/buildroot-external/board/asus/tinker/patches/linux/2022-ARM-DTS-rk3288-tinker-Enable-the-Video-encoding-MMU-.patch deleted file mode 100644 index bdddb437c..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2022-ARM-DTS-rk3288-tinker-Enable-the-Video-encoding-MMU-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 092c26ead2eb4035a57217f8705c9deed3bfb927 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Tue, 21 Nov 2017 21:54:22 +0100 -Subject: [PATCH 3/5] ARM: DTS: rk3288-tinker: Enable the Video encoding MMU - and services - -Enable the : -* VPU MMU; -* VPU Service; -* HEVC MMU; -* HEVC Service; -for ASUS Tinkerboard devices. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-tinker.dts | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index a0663425..07b4af4f 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -671,6 +671,22 @@ - status = "okay"; - }; - -+&vpu_mmu { -+ status = "okay"; -+}; -+ -+&vpu_service { -+ status = "okay"; -+}; -+ -+&hevc_mmu { -+ status = "okay"; -+}; -+ -+&hevc_service { -+ status = "okay"; -+}; -+ - &wdt { - status = "okay"; - }; --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2023-ARM-DTSI-rk3288-firefly-Enable-the-Video-encoding-MM.patch b/buildroot-external/board/asus/tinker/patches/linux/2023-ARM-DTSI-rk3288-firefly-Enable-the-Video-encoding-MM.patch deleted file mode 100644 index 568018eee..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2023-ARM-DTSI-rk3288-firefly-Enable-the-Video-encoding-MM.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 2769b0e656d849c5d652c75db71ce0faff1c0551 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Tue, 21 Nov 2017 21:56:45 +0100 -Subject: [PATCH 4/5] ARM: DTSI: rk3288-firefly: Enable the Video encoding MMU - and services - -Enable the : -* VPU MMU; -* VPU Service; -* HEVC MMU; -* HEVC Service; -for RK3288 Firefly devices. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-firefly.dtsi | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-firefly.dtsi b/arch/arm/boot/dts/rk3288-firefly.dtsi -index b9e6f3a9..9961acce 100644 ---- a/arch/arm/boot/dts/rk3288-firefly.dtsi -+++ b/arch/arm/boot/dts/rk3288-firefly.dtsi -@@ -606,6 +606,23 @@ - status = "okay"; - }; - -+&vpu_mmu { -+ status = "okay"; -+}; -+ -+&vpu_service { -+ status = "okay"; -+}; -+ -+&hevc_mmu { -+ status = "okay"; -+}; -+ -+&hevc_service { -+ status = "okay"; -+}; -+ - &wdt { - status = "okay"; - }; -+ --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2024-ARM-DTSI-rk3288-veyron-Enable-the-Video-encoding-MMU.patch b/buildroot-external/board/asus/tinker/patches/linux/2024-ARM-DTSI-rk3288-veyron-Enable-the-Video-encoding-MMU.patch deleted file mode 100644 index 31c1c5b6d..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2024-ARM-DTSI-rk3288-veyron-Enable-the-Video-encoding-MMU.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 4766516bcbf023813ad883c2d61c422316770d12 Mon Sep 17 00:00:00 2001 -From: Myy Miouyouyou -Date: Tue, 21 Nov 2017 21:58:22 +0100 -Subject: [PATCH 5/5] ARM: DTSI: rk3288-veyron: Enable the Video encoding MMU - and services - -Enable the : -* VPU MMU; -* VPU Service; -* HEVC MMU; -* HEVC Service; -for RK3288 Chromebook laptops. - -Signed-off-by: Myy Miouyouyou ---- - arch/arm/boot/dts/rk3288-veyron.dtsi | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi -index 6e5bd897..517b9242 100644 ---- a/arch/arm/boot/dts/rk3288-veyron.dtsi -+++ b/arch/arm/boot/dts/rk3288-veyron.dtsi -@@ -450,6 +450,22 @@ - status = "okay"; - }; - -+&vpu_mmu { -+ status = "okay"; -+}; -+ -+&vpu_service { -+ status = "okay"; -+}; -+ -+&hevc_mmu { -+ status = "okay"; -+}; -+ -+&hevc_service { -+ status = "okay"; -+}; -+ - &wdt { - status = "okay"; - }; --- -2.14.1 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2025-ARM-DTSI-rk3288-Renamed-the-VPU-services-clocks.patch b/buildroot-external/board/asus/tinker/patches/linux/2025-ARM-DTSI-rk3288-Renamed-the-VPU-services-clocks.patch deleted file mode 100644 index 9dd8fbfae..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2025-ARM-DTSI-rk3288-Renamed-the-VPU-services-clocks.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 29ef524e8890bbfd24602a61e14234259df92349 Mon Sep 17 00:00:00 2001 -From: "Miouyouyou (Myy)" -Date: Mon, 25 Jun 2018 17:05:37 +0200 -Subject: [PATCH 25/26] ARM: DTSI: rk3288: Renamed the VPU services clocks - -In order to conform to the naming scheme used in the whole DTSI. - -Signed-off-by: Miouyouyou (Myy) ---- - arch/arm/boot/dts/rk3288.dtsi | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi -index 796609e3..45ec4e89 100644 ---- a/arch/arm/boot/dts/rk3288.dtsi -+++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -1242,7 +1242,7 @@ - ; - interrupt-names = "irq_enc", "irq_dec"; - clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; -- clock-names = "aclk_vcodec", "hclk_vcodec"; -+ clock-names = "aclk", "iface"; - power-domains = <&power RK3288_PD_VIDEO>; - rockchip,grf = <&grf>; - resets = <&cru SRST_VCODEC_AXI>, <&cru SRST_VCODEC_AHB>; -@@ -1277,8 +1277,8 @@ - <&cru SCLK_HEVC_CORE>, - <&cru SCLK_HEVC_CABAC>; - clock-names = -- "aclk_vcodec", -- "hclk_vcodec", -+ "aclk", -+ "iface", - "clk_core", - "clk_cabac"; - /* --- -2.16.4 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/2027-ARM-dtsi-The-VPU-service-as-defined-in-the-V4L2-driv.patch b/buildroot-external/board/asus/tinker/patches/linux/2027-ARM-dtsi-The-VPU-service-as-defined-in-the-V4L2-driv.patch deleted file mode 100644 index 9e0374ed2..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/2027-ARM-dtsi-The-VPU-service-as-defined-in-the-V4L2-driv.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 7f8607ba9a20f8ddb5c24559d9b875af762d4717 Mon Sep 17 00:00:00 2001 -From: "Miouyouyou (Myy)" -Date: Tue, 11 Sep 2018 02:55:55 +0200 -Subject: [PATCH] ARM: dtsi: The VPU service as defined in the V4L2 driver - -Let's try the V4L2 road. -They've got a lot of things ready, like an entire H264 -movie with the V4L2 data of *every frame*. - -That might help in this endless endeavour. - -Signed-off-by: Miouyouyou (Myy) ---- - arch/arm/boot/dts/rk3288.dtsi | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi -index 72c36af6..d23c7fa5 100644 ---- a/arch/arm/boot/dts/rk3288.dtsi -+++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -1246,7 +1246,18 @@ - clock-names = "aclk", "iface"; - power-domains = <&power RK3288_PD_VIDEO>; - #iommu-cells = <0>; -- status = "disabled"; -+ }; -+ -+ vpu: video-codec@ff9a0000 { -+ clocks = <&cru ACLK_VCODEC>, <&cru HCLK_VCODEC>; -+ clock-names = "aclk", "hclk"; -+ compatible = "rockchip,rk3288-vpu"; -+ interrupts = , -+ ; -+ interrupt-names = "vepu", "vdpu"; -+ iommus = <&vpu_mmu>; -+ power-domains = <&power RK3288_PD_VIDEO>; -+ reg = <0x0 0xff9a0000 0x0 0x800>; - }; - - hevc_mmu: iommu@ff9c0440 { --- -2.16.4 - diff --git a/buildroot-external/board/asus/tinker/patches/linux/261_gpiomem_driver.patch b/buildroot-external/board/asus/tinker/patches/linux/261_gpiomem_driver.patch new file mode 100644 index 000000000..058563b9b --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/261_gpiomem_driver.patch @@ -0,0 +1,395 @@ +diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi +index e5b7ef1a5..f88c913ff 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dtsi ++++ b/arch/arm/boot/dts/rk3288-tinker.dtsi +@@ -544,3 +544,6 @@ + &wdt { + status = "okay"; + }; ++&gpiomem { ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index f3ca55496..14bbcb192 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1418,6 +1418,12 @@ + interrupts = ; + }; + ++ gpiomem: rk3288-gpiomem@ff750000 { ++ compatible = "rockchip,rk3288-gpiomem"; ++ reg = <0x0 0xff750000 0x0 0x1000>; ++ status = "disabled"; ++ }; ++ + pinctrl: pinctrl { + compatible = "rockchip,rk3288-pinctrl"; + rockchip,grf = <&grf>; + +diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig +index 3143db5..9c18b74 100644 +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -5,6 +5,7 @@ + menu "Character devices" + + source "drivers/tty/Kconfig" ++source "drivers/char/rockchip/Kconfig" + + config DEVMEM + bool "/dev/mem virtual device support" +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index d8a7579..290cb32 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -51,6 +51,8 @@ obj-$(CONFIG_PS3_FLASH) += ps3flash.o + obj-$(CONFIG_JS_RTC) += js-rtc.o + js-rtc-y = rtc.o + ++obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ ++ + obj-$(CONFIG_XILLYBUS) += xillybus/ + obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o + obj-$(CONFIG_ADI) += adi.o +diff --git a/drivers/char/rockchip/Kconfig b/drivers/char/rockchip/Kconfig +new file mode 100644 +index 0000000..6e97486 +--- /dev/null ++++ b/drivers/char/rockchip/Kconfig +@@ -0,0 +1,16 @@ ++# ++# Broadcom char driver config ++# ++ ++menuconfig RK_CHAR_DRIVERS ++ bool "Rockchip Char Drivers" ++ help ++ Rockchip's char drivers ++ ++config RK3288_DEVGPIOMEM ++ tristate "/dev/gpiomem rootless GPIO access via mmap() on the RK3288" ++ default y ++ help ++ Provides users with root-free access to the GPIO registers ++ on the 3288. Calling mmap(/dev/gpiomem) will map the GPIO ++ register page to the user's pointer. +\ No newline at end of file +diff --git a/drivers/char/rockchip/Makefile b/drivers/char/rockchip/Makefile +new file mode 100644 +index 0000000..2287ec2 +--- /dev/null ++++ b/drivers/char/rockchip/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_RK3288_DEVGPIOMEM)+= rk3288-gpiomem.o +\ No newline at end of file +diff --git a/drivers/char/rockchip/rk3288-gpiomem.c b/drivers/char/rockchip/rk3288-gpiomem.c +new file mode 100644 +index 0000000..984471c +--- /dev/null ++++ b/drivers/char/rockchip/rk3288-gpiomem.c +@@ -0,0 +1,303 @@ ++/** ++ * GPIO memory device driver ++ * ++ * Creates a chardev /dev/gpiomem which will provide user access to ++ * the rk3288's GPIO registers when it is mmap()'d. ++ * No longer need root for user GPIO access, but without relaxing permissions ++ * on /dev/mem. ++ * ++ * Written by Luke Wren ++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. ++ * ++ * 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, ++ * without modification. ++ * 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 names of the above-listed copyright holders may not be used ++ * to endorse or promote products derived from this software without ++ * specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") version 2, as published by the Free ++ * Software Foundation. ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DEVICE_NAME "rk3288-gpiomem" ++#define DRIVER_NAME "gpiomem-rk3288" ++#define DEVICE_MINOR 0 ++ ++struct rk3288_gpiomem_instance { ++ unsigned long gpio_regs_phys; ++ struct device *dev; ++}; ++ ++static struct cdev rk3288_gpiomem_cdev; ++static dev_t rk3288_gpiomem_devid; ++static struct class *rk3288_gpiomem_class; ++static struct device *rk3288_gpiomem_dev; ++static struct rk3288_gpiomem_instance *inst; ++ ++ ++/**************************************************************************** ++* ++* GPIO mem chardev file ops ++* ++***************************************************************************/ ++ ++static int rk3288_gpiomem_open(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) { ++ dev_err(inst->dev, "Unknown minor device: %d", dev); ++ ret = -ENXIO; ++ } ++ return ret; ++} ++ ++static int rk3288_gpiomem_release(struct inode *inode, struct file *file) ++{ ++ int dev = iminor(inode); ++ int ret = 0; ++ ++ if (dev != DEVICE_MINOR) { ++ dev_err(inst->dev, "Unknown minor device %d", dev); ++ ret = -ENXIO; ++ } ++ return ret; ++} ++ ++static const struct vm_operations_struct rk3288_gpiomem_vm_ops = { ++#ifdef CONFIG_HAVE_IOREMAP_PROT ++ .access = generic_access_phys ++#endif ++}; ++static int address_is_allowed(unsigned long pfn, unsigned long size) ++{ ++ unsigned long address = pfn << PAGE_SHIFT; ++ ++ dev_info(inst->dev, "address_is_allowed.pfn: 0x%08lx", address); ++ ++ switch(address) { ++ ++ case 0xff750000: ++ case 0xff760000: ++ case 0xff780000: ++ case 0xff790000: ++ case 0xff7a0000: ++ case 0xff7b0000: ++ case 0xff7c0000: ++ case 0xff7d0000: ++ case 0xff7e0000: ++ case 0xff7f0000: ++ case 0xff7f2000: ++ case 0xff770000: ++ case 0xff730000: ++ case 0xff680000: ++ dev_info(inst->dev, "address_is_allowed.return 1"); ++ return 1; ++ break; ++ default : ++ dev_info(inst->dev, "address_is_allowed.return 0"); ++ return 0; ++ } ++} ++ ++static int rk3288_gpiomem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ ++ size_t size; ++ ++ size = vma->vm_end - vma->vm_start; ++ ++ ++ if (!address_is_allowed(vma->vm_pgoff, size)) ++ return -EPERM; ++ ++ vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, ++ size, ++ vma->vm_page_prot); ++ ++ vma->vm_ops = &rk3288_gpiomem_vm_ops; ++ ++ /* Remap-pfn-range will mark the range VM_IO */ ++ if (remap_pfn_range(vma, ++ vma->vm_start, ++ vma->vm_pgoff, ++ size, ++ vma->vm_page_prot)) { ++ return -EAGAIN; ++ } ++ ++ return 0; ++} ++ ++static const struct file_operations ++rk3288_gpiomem_fops = { ++ .owner = THIS_MODULE, ++ .open = rk3288_gpiomem_open, ++ .release = rk3288_gpiomem_release, ++ .mmap = rk3288_gpiomem_mmap, ++}; ++ ++static int rk3288_gpiomem_dev_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ add_uevent_var(env, "DEVMODE=%#o", 0666); ++ return 0; ++} ++ ++ /**************************************************************************** ++* ++* Probe and remove functions ++* ++***************************************************************************/ ++ ++ ++static int rk3288_gpiomem_probe(struct platform_device *pdev) ++{ ++ int err; ++ void *ptr_err; ++ struct device *dev = &pdev->dev; ++ struct resource *ioresource; ++ ++ /* Allocate buffers and instance data */ ++ ++ inst = kzalloc(sizeof(struct rk3288_gpiomem_instance), GFP_KERNEL); ++ ++ if (!inst) { ++ err = -ENOMEM; ++ goto failed_inst_alloc; ++ } ++ ++ inst->dev = dev; ++ ++ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (ioresource) { ++ inst->gpio_regs_phys = ioresource->start; ++ } else { ++ dev_err(inst->dev, "failed to get IO resource"); ++ err = -ENOENT; ++ goto failed_get_resource; ++ } ++ ++ /* Create character device entries */ ++ ++ err = alloc_chrdev_region(&rk3288_gpiomem_devid, ++ DEVICE_MINOR, 1, DEVICE_NAME); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to allocate device number"); ++ goto failed_alloc_chrdev; ++ } ++ cdev_init(&rk3288_gpiomem_cdev, &rk3288_gpiomem_fops); ++ rk3288_gpiomem_cdev.owner = THIS_MODULE; ++ err = cdev_add(&rk3288_gpiomem_cdev, rk3288_gpiomem_devid, 1); ++ if (err != 0) { ++ dev_err(inst->dev, "unable to register device"); ++ goto failed_cdev_add; ++ } ++ ++ /* Create sysfs entries */ ++ ++ rk3288_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME); ++ ptr_err = rk3288_gpiomem_class; ++ if (IS_ERR(ptr_err)) ++ goto failed_class_create; ++ rk3288_gpiomem_class->dev_uevent = rk3288_gpiomem_dev_uevent; ++ rk3288_gpiomem_dev = device_create(rk3288_gpiomem_class, NULL, ++ rk3288_gpiomem_devid, NULL, ++ "gpiomem"); ++ ptr_err = rk3288_gpiomem_dev; ++ if (IS_ERR(ptr_err)) ++ goto failed_device_create; ++ ++ dev_info(inst->dev, "Initialised: Registers at 0x%08lx", ++ inst->gpio_regs_phys); ++ ++ return 0; ++ ++failed_device_create: ++ class_destroy(rk3288_gpiomem_class); ++failed_class_create: ++ cdev_del(&rk3288_gpiomem_cdev); ++ err = PTR_ERR(ptr_err); ++failed_cdev_add: ++ unregister_chrdev_region(rk3288_gpiomem_devid, 1); ++failed_alloc_chrdev: ++failed_get_resource: ++ kfree(inst); ++failed_inst_alloc: ++ dev_err(inst->dev, "could not load rk3288_gpiomem"); ++ return err; ++} ++ ++static int rk3288_gpiomem_remove(struct platform_device *pdev) ++{ ++ struct device *dev = inst->dev; ++ ++ kfree(inst); ++ device_destroy(rk3288_gpiomem_class, rk3288_gpiomem_devid); ++ class_destroy(rk3288_gpiomem_class); ++ cdev_del(&rk3288_gpiomem_cdev); ++ unregister_chrdev_region(rk3288_gpiomem_devid, 1); ++ ++ dev_info(dev, "GPIO mem driver removed - OK"); ++ return 0; ++} ++ ++ /**************************************************************************** ++* ++* Register the driver with device tree ++* ++***************************************************************************/ ++ ++static const struct of_device_id rk3288_gpiomem_of_match[] = { ++ {.compatible = "rockchip,rk3288-gpiomem",}, ++ { /* sentinel */ }, ++}; ++ ++MODULE_DEVICE_TABLE(of, rk3288_gpiomem_of_match); ++ ++static struct platform_driver rk3288_gpiomem_driver = { ++ .probe = rk3288_gpiomem_probe, ++ .remove = rk3288_gpiomem_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = rk3288_gpiomem_of_match, ++ }, ++}; ++ ++module_platform_driver(rk3288_gpiomem_driver); ++ ++MODULE_ALIAS("platform:gpiomem-rk3288"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace"); ++MODULE_AUTHOR("Luke Wren "); +\ No newline at end of file diff --git a/buildroot-external/board/asus/tinker/patches/linux/3000_RK3288-Tinkerboard-add-1.7_1.8Ghz_OPP.patch b/buildroot-external/board/asus/tinker/patches/linux/3000_RK3288-Tinkerboard-add-1.7_1.8Ghz_OPP.patch deleted file mode 100644 index 6d1f07880..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/3000_RK3288-Tinkerboard-add-1.7_1.8Ghz_OPP.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 2601316da..08ec7aa4b 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -210,8 +210,8 @@ - vdd_cpu: DCDC_REG1 { - regulator-always-on; - regulator-boot-on; -- regulator-min-microvolt = <750000>; -- regulator-max-microvolt = <1450000>; -+ regulator-min-microvolt = <712500>; -+ regulator-max-microvolt = <1500000>; - regulator-name = "vdd_arm"; - regulator-ramp-delay = <6000>; - regulator-state-mem { -@@ -222,8 +222,8 @@ - vdd_gpu: DCDC_REG2 { - regulator-always-on; - regulator-boot-on; -- regulator-min-microvolt = <850000>; -- regulator-max-microvolt = <1250000>; -+ regulator-min-microvolt = <712500>; -+ regulator-max-microvolt = <1500000>; - regulator-name = "vdd_gpu"; - regulator-ramp-delay = <6000>; - regulator-state-mem { -diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi -index 22bcaaa29..2fcd46098 100644 ---- a/arch/arm/boot/dts/rk3288.dtsi -+++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -149,6 +149,14 @@ - opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <1350000>; - }; -+ opp@1704000000 { -+ opp-hz = /bits/ 64 <1704000000>; -+ opp-microvolt = <1350000>; -+ }; -+ opp@1800000000 { -+ opp-hz = /bits/ 64 <1800000000>; -+ opp-microvolt = <1400000>; -+ }; - }; - - amba { \ No newline at end of file diff --git a/buildroot-external/board/asus/tinker/patches/linux/ARM-DTSI-rk3288-add-usbphy-reset.patch b/buildroot-external/board/asus/tinker/patches/linux/ARM-DTSI-rk3288-add-usbphy-reset.patch deleted file mode 100644 index 0588f9445..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/ARM-DTSI-rk3288-add-usbphy-reset.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi -index 0840ffb3..5393f2cd 100644 ---- a/arch/arm/boot/dts/rk3288.dtsi -+++ b/arch/arm/boot/dts/rk3288.dtsi -@@ -894,6 +894,8 @@ - reg = <0x320>; - clocks = <&cru SCLK_OTGPHY0>; - clock-names = "phyclk"; -+ resets = <&cru SRST_USBOTG_PHY>; -+ reset-names = "phy-reset"; - #clock-cells = <0>; - }; - -@@ -902,6 +904,8 @@ - reg = <0x334>; - clocks = <&cru SCLK_OTGPHY1>; - clock-names = "phyclk"; -+ resets = <&cru SRST_USBHOST0_PHY>; -+ reset-names = "phy-reset"; - #clock-cells = <0>; - }; - -@@ -910,6 +914,8 @@ - reg = <0x348>; - clocks = <&cru SCLK_OTGPHY2>; - clock-names = "phyclk"; -+ resets = <&cru SRST_USBHOST1_PHY>; -+ reset-names = "phy-reset"; - #clock-cells = <0>; - }; - }; diff --git a/buildroot-external/board/asus/tinker/patches/linux/RK3288-1.8GHz-and-boost.patch b/buildroot-external/board/asus/tinker/patches/linux/RK3288-1.8GHz-and-boost.patch new file mode 100644 index 000000000..83403b49e --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/RK3288-1.8GHz-and-boost.patch @@ -0,0 +1,80 @@ +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 58bd91539..9c0dac199 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -153,6 +153,75 @@ + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <1350000>; + }; ++ opp@1704000000 { ++ opp-hz = /bits/ 64 <1704000000>; ++ opp-microvolt = <1350000>; ++ }; ++ opp@1800000000 { ++ opp-hz = /bits/ 64 <1800000000>; ++ opp-microvolt = <1400000>; ++ }; ++ /* boot-only frequencies below */ ++ opp@1896000000 { ++ opp-hz = /bits/ 64 <1896000000>; ++ opp-microvolt = <1425000>; ++ turbo-mode; ++ }; ++ opp@1920000000 { ++ opp-hz = /bits/ 64 <1920000000>; ++ opp-microvolt = <1425000>; ++ turbo-mode; ++ }; ++ opp@1992000000 { ++ opp-hz = /bits/ 64 <1992000000>; ++ opp-microvolt = <1450000>; ++ turbo-mode; ++ }; ++ opp@2016000000 { ++ opp-hz = /bits/ 64 <2016000000>; ++ opp-microvolt = <1475000>; ++ turbo-mode; ++ }; ++ opp@2040000000 { ++ opp-hz = /bits/ 64 <2040000000>; ++ opp-microvolt = <1475000>; ++ turbo-mode; ++ }; ++ opp@2064000000 { ++ opp-hz = /bits/ 64 <2064000000>; ++ opp-microvolt = <1475000>; ++ turbo-mode; ++ }; ++ opp@2088000000 { ++ opp-hz = /bits/ 64 <2088000000>; ++ opp-microvolt = <1500000>; ++ turbo-mode; ++ }; ++ opp@2112000000 { ++ opp-hz = /bits/ 64 <2112000000>; ++ opp-microvolt = <1500000>; ++ turbo-mode; ++ }; ++ opp@2136000000 { ++ opp-hz = /bits/ 64 <2136000000>; ++ opp-microvolt = <1500000>; ++ turbo-mode; ++ }; ++ opp@2160000000 { ++ opp-hz = /bits/ 64 <2160000000>; ++ opp-microvolt = <1500000>; ++ turbo-mode; ++ }; ++ opp@2184000000 { ++ opp-hz = /bits/ 64 <2184000000>; ++ opp-microvolt = <1500000>; ++ turbo-mode; ++ }; ++ opp@2208000000 { ++ opp-hz = /bits/ 64 <2208000000>; ++ opp-microvolt = <1500000>; ++ turbo-mode; ++ }; + }; + + amba { diff --git a/buildroot-external/board/asus/tinker/patches/linux/assert-phy-reset-when-waking-up-in-rk3288-platform.patch b/buildroot-external/board/asus/tinker/patches/linux/assert-phy-reset-when-waking-up-in-rk3288-platform.patch deleted file mode 100644 index b98717b0d..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/assert-phy-reset-when-waking-up-in-rk3288-platform.patch +++ /dev/null @@ -1,68 +0,0 @@ -diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index cc9c93af..3ff41d87 100644 ---- a/drivers/usb/dwc2/core.h -+++ b/drivers/usb/dwc2/core.h -@@ -1021,6 +1021,7 @@ struct dwc2_hsotg { - u16 frame_number; - - struct phy *phy; -+ struct work_struct phy_rst_work; - struct usb_phy *uphy; - struct dwc2_hsotg_plat *plat; - struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; -diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c -index 19ae2595..f1270bf1 100644 ---- a/drivers/usb/dwc2/core_intr.c -+++ b/drivers/usb/dwc2/core_intr.c -@@ -396,6 +396,7 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg) - static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) - { - int ret; -+ struct device_node *np = hsotg->dev->of_node; - - /* Clear interrupt */ - dwc2_writel(hsotg, GINTSTS_WKUPINT, GINTSTS); -@@ -435,6 +436,16 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) - /* Restart the Phy Clock */ - pcgcctl &= ~PCGCTL_STOPPCLK; - dwc2_writel(hsotg, pcgcctl, PCGCTL); -+ -+ /* -+ * It is a quirk in Rockchip RK3288, causing by -+ * a hardware bug. This will propagate out and -+ * eventually we'll re-enumerate the device. -+ * Not great but the best we can do. -+ */ -+ if (of_device_is_compatible(np, "rockchip,rk3288-usb")) -+ schedule_work(&hsotg->phy_rst_work); -+ - mod_timer(&hsotg->wkp_timer, - jiffies + msecs_to_jiffies(71)); - } else { -diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index 57764289..748763bd 100644 ---- a/drivers/usb/dwc2/platform.c -+++ b/drivers/usb/dwc2/platform.c -@@ -208,6 +208,14 @@ int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) - return ret; - } - -+/* Only used to reset usb phy at interrupter runtime */ -+static void dwc2_reset_phy_work(struct work_struct *data) -+{ -+ struct dwc2_hsotg *hsotg = container_of(data, struct dwc2_hsotg, -+ phy_rst_work); -+ phy_reset(hsotg->phy); -+} -+ - static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) - { - int i, ret; -@@ -252,6 +260,7 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) - return ret; - } - } -+ INIT_WORK(&hsotg->phy_rst_work, dwc2_reset_phy_work); - - if (!hsotg->phy) { - hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2); diff --git a/buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-enable-emmc-support.patch b/buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-enable-emmc-support.patch index 207885fa0..d9e10ccb9 100644 --- a/buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-enable-emmc-support.patch +++ b/buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-enable-emmc-support.patch @@ -1,25 +1,25 @@ -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 77554262..57cce114 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -612,6 +612,20 @@ - vqmmc-supply = <&vccio_sd>; +diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi +index f88c913ff..7f04ccbdf 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dtsi ++++ b/arch/arm/boot/dts/rk3288-tinker.dtsi +@@ -547,3 +547,20 @@ + &gpiomem { + status = "okay"; }; - ++ +&emmc { -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ disable-wp; -+ non-removable; -+ num-slots = <1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>; -+ max-frequency = <150000000>; -+ mmc-hs200-1_8v; -+ mmc-ddr-1_8v; -+ status = "okay"; ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>; ++ max-frequency = <150000000>; ++ mmc-hs200-1_8v; ++ mmc-ddr-1_8v; ++ status = "okay"; +}; + - &tsadc { - rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */ - rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */ ++&hdmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hdmi_cec_c0>; ++}; diff --git a/buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-support-older-eMMC-installs.patch b/buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-support-older-eMMC-installs.patch deleted file mode 100644 index 5779bc54a..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/board-tinkerboard-support-older-eMMC-installs.patch +++ /dev/null @@ -1,665 +0,0 @@ -diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index 2d0b2f4c4..d5c9022e7 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -859,6 +859,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ - rk3288-firefly-beta.dtb \ - rk3288-firefly.dtb \ - rk3288-firefly-reload.dtb \ -+ rk3288-miniarm.dtb \ - rk3288-miqi.dtb \ - rk3288-phycore-rdk.dtb \ - rk3288-popmetal.dtb \ -diff --git a/arch/arm/boot/dts/rk3288-miniarm.dts b/arch/arm/boot/dts/rk3288-miniarm.dts -new file mode 100644 -index 000000000..d0961c35d ---- /dev/null -+++ b/arch/arm/boot/dts/rk3288-miniarm.dts -@@ -0,0 +1,647 @@ -+// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -+/* -+ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd. -+ */ -+ -+/dts-v1/; -+ -+#include "rk3288.dtsi" -+#include -+#include -+ -+/ { -+ model = "Rockchip RK3288 Tinker Board"; -+ compatible = "asus,rk3288-tinker", "rockchip,rk3288"; -+ -+ chosen { -+ stdout-path = "serial2:115200n8"; -+ }; -+ -+ memory { -+ reg = <0x0 0x0 0x0 0x80000000>; -+ device_type = "memory"; -+ }; -+ -+ ext_gmac: external-gmac-clock { -+ compatible = "fixed-clock"; -+ #clock-cells = <0>; -+ clock-frequency = <125000000>; -+ clock-output-names = "ext_gmac"; -+ }; -+ -+ gpio-keys { -+ compatible = "gpio-keys"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ autorepeat; -+ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwrbtn>; -+ -+ button@0 { -+ gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>; -+ linux,code = ; -+ label = "GPIO Key Power"; -+ linux,input-type = <1>; -+ wakeup-source; -+ debounce-interval = <100>; -+ }; -+ }; -+ -+ gpio-leds { -+ compatible = "gpio-leds"; -+ -+ act-led { -+ gpios=<&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; -+ linux,default-trigger="mmc0"; -+ }; -+ -+ heartbeat-led { -+ gpios=<&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>; -+ linux,default-trigger="heartbeat"; -+ }; -+ -+ pwr-led { -+ gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; -+ linux,default-trigger = "default-on"; -+ }; -+ }; -+ -+ sound { -+ compatible = "simple-audio-card"; -+ simple-audio-card,format = "i2s"; -+ simple-audio-card,name = "rockchip,tinker-codec"; -+ simple-audio-card,mclk-fs = <512>; -+ -+ simple-audio-card,codec { -+ sound-dai = <&hdmi>; -+ }; -+ -+ simple-audio-card,cpu { -+ sound-dai = <&i2s>; -+ }; -+ }; -+ -+ /* This is essential to get SDIO devices working. -+ The Wifi depends on SDIO ! */ -+ sdio_pwrseq: sdio-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ clocks = <&rk808 RK808_CLKOUT1>; -+ clock-names = "ext_clock"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&chip_enable_h>, <&wifi_enable_h>; -+ -+ /* -+ * On the module itself this is one of these (depending -+ * on the actual card populated): -+ * - SDIO_RESET_L_WL_REG_ON -+ * - PDN (power down when low) -+ */ -+ reset-gpios = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>, <&gpio4 RK_PD3 GPIO_ACTIVE_LOW>; -+ }; -+ -+ vcc_sys: vsys-regulator { -+ compatible = "regulator-fixed"; -+ regulator-name = "vcc_sys"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ regulator-always-on; -+ regulator-boot-on; -+ }; -+ -+ vcc_sd: sdmmc-regulator { -+ compatible = "regulator-fixed"; -+ gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc_pwr>; -+ regulator-name = "vcc_sd"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ startup-delay-us = <100000>; -+ vin-supply = <&vcc_io>; -+ }; -+ -+ wireless-wlan { -+ compatible = "wlan-platdata"; -+ rockchip,grf = <&grf>; -+ wifi_chip_type = "8723bs"; -+ sdio_vref = <1800>; -+ WIFI,host_wake_irq = <&gpio4 30 GPIO_ACTIVE_HIGH>; -+ status = "okay"; -+ }; -+/* -+ wireless-bluetooth { -+ compatible = "bluetooth-platdata"; -+ uart_rts_gpios = <&gpio4 19 GPIO_ACTIVE_LOW>; -+ pinctrl-names = "default","rts_gpio"; -+ pinctrl-0 = <&uart0_rts>; -+ pinctrl-1 = <&uart0_gpios>; -+ BT,reset_gpio = <&gpio4 29 GPIO_ACTIVE_HIGH>; -+ BT,wake_gpio = <&gpio4 26 GPIO_ACTIVE_HIGH>; -+ BT,wake_host_irq = <&gpio4 31 GPIO_ACTIVE_HIGH>; -+ status = "okay"; -+ }; -+*/ -+ -+}; -+ -+&cpu0 { -+ cpu0-supply = <&vdd_cpu>; -+}; -+ -+&gmac { -+ assigned-clocks = <&cru SCLK_MAC>; -+ assigned-clock-parents = <&ext_gmac>; -+ clock_in_out = "input"; -+ phy-mode = "rgmii"; -+ phy-supply = <&vcc33_lan>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&rgmii_pins>; -+ snps,reset-gpio = <&gpio4 7 0>; -+ snps,reset-active-low; -+ snps,reset-delays-us = <0 10000 1000000>; -+ tx_delay = <0x30>; -+ rx_delay = <0x10>; -+ status = "ok"; -+}; -+ -+&gpu { -+ mali-supply = <&vdd_gpu>; -+ status = "okay"; -+}; -+ -+&hdmi { -+ ddc-i2c-bus = <&i2c5>; -+ status = "okay"; -+}; -+ -+&i2c0 { -+ clock-frequency = <400000>; -+ status = "okay"; -+ -+ rk808: pmic@1b { -+ compatible = "rockchip,rk808"; -+ reg = <0x1b>; -+ interrupt-parent = <&gpio0>; -+ interrupts = <4 IRQ_TYPE_LEVEL_LOW>; -+ #clock-cells = <1>; -+ clock-output-names = "xin32k", "rk808-clkout2"; -+ dvs-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>, -+ <&gpio0 12 GPIO_ACTIVE_HIGH>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pmic_int &global_pwroff &dvs_1 &dvs_2>; -+ rockchip,system-power-controller; -+ wakeup-source; -+ -+ vcc1-supply = <&vcc_sys>; -+ vcc2-supply = <&vcc_sys>; -+ vcc3-supply = <&vcc_sys>; -+ vcc4-supply = <&vcc_sys>; -+ vcc6-supply = <&vcc_sys>; -+ vcc7-supply = <&vcc_sys>; -+ vcc8-supply = <&vcc_io>; -+ vcc9-supply = <&vcc_io>; -+ vcc10-supply = <&vcc_io>; -+ vcc11-supply = <&vcc_sys>; -+ vcc12-supply = <&vcc_io>; -+ vddio-supply = <&vcc_io>; -+ -+ regulators { -+ vdd_cpu: DCDC_REG1 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <712500>; -+ regulator-max-microvolt = <1500000>; -+ regulator-name = "vdd_arm"; -+ regulator-ramp-delay = <6000>; -+ regulator-state-mem { -+ regulator-off-in-suspend; -+ }; -+ }; -+ -+ vdd_gpu: DCDC_REG2 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <712500>; -+ regulator-max-microvolt = <1500000>; -+ regulator-name = "vdd_gpu"; -+ regulator-ramp-delay = <6000>; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ -+ vcc_ddr: DCDC_REG3 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-name = "vcc_ddr"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ }; -+ }; -+ -+ vcc_io: DCDC_REG4 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-name = "vcc_io"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <3300000>; -+ }; -+ }; -+ -+ vcc18_ldo1: LDO_REG1 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-name = "vcc18_ldo1"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vcc33_mipi: LDO_REG2 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-name = "vcc33_mipi"; -+ regulator-state-mem { -+ regulator-off-in-suspend; -+ }; -+ }; -+ -+ vdd_10: LDO_REG3 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1000000>; -+ regulator-name = "vdd_10"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ -+ vcc18_codec: LDO_REG4 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-name = "vcc18_codec"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vccio_sd: LDO_REG5 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-name = "vccio_sd"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <3300000>; -+ }; -+ }; -+ -+ vdd10_lcd: LDO_REG6 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <1000000>; -+ regulator-max-microvolt = <1000000>; -+ regulator-name = "vdd10_lcd"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1000000>; -+ }; -+ }; -+ -+ vcc_18: LDO_REG7 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-name = "vcc_18"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vcc18_lcd: LDO_REG8 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-name = "vcc18_lcd"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ regulator-suspend-microvolt = <1800000>; -+ }; -+ }; -+ -+ vcc33_sd: SWITCH_REG1 { -+ regulator-boot-on; -+ regulator-name = "vcc33_sd"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ }; -+ }; -+ -+ vcc33_lan: SWITCH_REG2 { -+ regulator-always-on; -+ regulator-boot-on; -+ regulator-name = "vcc33_lan"; -+ regulator-state-mem { -+ regulator-on-in-suspend; -+ }; -+ }; -+ }; -+ }; -+}; -+ -+&i2c1 { -+ status = "okay"; -+}; -+ -+&i2c2 { -+ status = "okay"; -+ -+ afc0:af-controller@0 { -+ status = "okay"; -+ compatible = "silicon touch,vm149C-v4l2-i2c-subdev"; -+ reg = <0x0c>; -+ }; -+ -+ eeprom:m24c08@50 { -+ compatible = "at,24c08"; -+ reg = <0x50>; -+ }; -+}; -+ -+&i2c3 { -+ status = "okay"; -+}; -+ -+&i2c4 { -+ status = "okay"; -+}; -+ -+&i2c5 { -+ status = "okay"; -+}; -+ -+&i2s { -+ #sound-dai-cells = <0>; -+ status = "okay"; -+}; -+ -+&io_domains { -+ status = "okay"; -+ rockchip,grf = <&grf>; -+ wifi-supply = <&vcc_18>; -+ sdcard-supply = <&vccio_sd>; -+}; -+ -+&sdio0 { -+ status = "okay"; -+ clock-frequency = <50000000>; -+ clock-freq-min-max = <200000 50000000>; -+ bus-width = <4>; -+ cap-sd-highspeed; -+ cap-sdio-irq; -+ disable-wp; -+ keep-power-in-suspend; -+ mmc-pwrseq = <&sdio_pwrseq>; -+ non-removable; -+ num-slots = <1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>; -+ sd-uhs-sdr104; -+ supports-sdio; -+ -+}; -+ -+&pinctrl { -+ pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma { -+ drive-strength = <8>; -+ }; -+ -+ pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma { -+ bias-pull-up; -+ drive-strength = <8>; -+ }; -+ -+ backlight { -+ bl_en: bl-en { -+ rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ buttons { -+ pwrbtn: pwrbtn { -+ rockchip,pins = <0 5 RK_FUNC_GPIO &pcfg_pull_up>; -+ }; -+ }; -+ -+ eth_phy { -+ eth_phy_pwr: eth-phy-pwr { -+ rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ pmic { -+ pmic_int: pmic-int { -+ rockchip,pins = ; -+ }; -+ -+ dvs_1: dvs-1 { -+ rockchip,pins = ; -+ }; -+ -+ dvs_2: dvs-2 { -+ rockchip,pins = ; -+ }; -+ }; -+ -+ sdio-pwrseq { -+ wifi_enable_h: wifienable-h { -+ rockchip,pins = <4 28 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ chip_enable_h: chip-enable-h { -+ rockchip,pins = <4 27 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ sdmmc { -+ sdmmc_bus4: sdmmc-bus4 { -+ rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_8ma>, -+ <6 17 RK_FUNC_1 &pcfg_pull_up_drv_8ma>, -+ <6 18 RK_FUNC_1 &pcfg_pull_up_drv_8ma>, -+ <6 19 RK_FUNC_1 &pcfg_pull_up_drv_8ma>; -+ }; -+ -+ sdmmc_clk: sdmmc-clk { -+ rockchip,pins = <6 20 RK_FUNC_1 \ -+ &pcfg_pull_none_drv_8ma>; -+ }; -+ -+ sdmmc_cmd: sdmmc-cmd { -+ rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_8ma>; -+ }; -+ -+ sdmmc_pwr: sdmmc-pwr { -+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ usb { -+ host_vbus_drv: host-vbus-drv { -+ rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ -+ pwr_3g: pwr-3g { -+ rockchip,pins = <7 8 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+ wireless-bluetooth { -+ uart0_gpios: uart0-gpios { -+ rockchip,pins = <4 19 RK_FUNC_GPIO &pcfg_pull_none>; -+ }; -+ }; -+ -+}; -+ -+&pwm0 { -+ status = "okay"; -+}; -+ -+&saradc { -+ vref-supply = <&vcc18_ldo1>; -+ status ="okay"; -+}; -+ -+&sdmmc { -+ bus-width = <4>; -+ cap-mmc-highspeed; -+ cap-sd-highspeed; -+ card-detect-delay = <200>; -+ disable-wp; /* wp not hooked up */ -+ pinctrl-names = "default"; -+ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>; -+ sd-uhs-sdr12; -+ sd-uhs-sdr25; -+ sd-uhs-sdr50; -+ sd-uhs-sdr104; -+ status = "okay"; -+ supports-sd; -+ vmmc-supply = <&vcc33_sd>; -+ vqmmc-supply = <&vccio_sd>; -+}; -+ -+&emmc { -+ bus-width = <8>; -+ cap-mmc-highspeed; -+ disable-wp; -+ non-removable; -+ num-slots = <1>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>; -+ max-frequency = <150000000>; -+ mmc-hs200-1_8v; -+ mmc-ddr-1_8v; -+ status = "okay"; -+}; -+ -+&tsadc { -+ rockchip,hw-tshut-mode = <1>; /* tshut mode 0:CRU 1:GPIO */ -+ rockchip,hw-tshut-polarity = <1>; /* tshut polarity 0:LOW 1:HIGH */ -+ status = "okay"; -+}; -+ -+&uart0 { -+ status = "okay"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&uart0_xfer>, <&uart0_cts>, <&uart0_rts>; -+}; -+ -+&uart1 { -+ status = "okay"; -+}; -+ -+&uart2 { -+ status = "okay"; -+}; -+ -+&uart3 { -+ status = "okay"; -+}; -+ -+&uart4 { -+ status = "okay"; -+}; -+ -+&usbphy { -+ status = "okay"; -+}; -+ -+&usb_host0_ehci { -+ status = "okay"; -+}; -+ -+&usb_host1 { -+ status = "okay"; -+}; -+ -+&usb_otg { -+ status= "okay"; -+}; -+ -+&vopb { -+ status = "okay"; -+}; -+ -+&vopb_mmu { -+ status = "okay"; -+}; -+ -+&vopl { -+ status = "okay"; -+}; -+ -+&vopl_mmu { -+ status = "okay"; -+}; -+ -+&vpu_mmu { -+ status = "okay"; -+}; -+ -+&vpu_service { -+ status = "okay"; -+}; -+ -+&hevc_mmu { -+ status = "okay"; -+}; -+ -+&hevc_service { -+ status = "okay"; -+}; -+ -+&wdt { -+ status = "okay"; -+}; diff --git a/buildroot-external/board/asus/tinker/patches/linux/general-adjust-tinker-dts-hdmi-sound.patch b/buildroot-external/board/asus/tinker/patches/linux/general-adjust-tinker-dts-hdmi-sound.patch index befe282f8..4745d5d96 100644 --- a/buildroot-external/board/asus/tinker/patches/linux/general-adjust-tinker-dts-hdmi-sound.patch +++ b/buildroot-external/board/asus/tinker/patches/linux/general-adjust-tinker-dts-hdmi-sound.patch @@ -1,8 +1,8 @@ -diff --git a/arch/arm/boot/dts/rk3288-tinker.dts b/arch/arm/boot/dts/rk3288-tinker.dts -index 958c0f3bf..59b8d8eac 100644 ---- a/arch/arm/boot/dts/rk3288-tinker.dts -+++ b/arch/arm/boot/dts/rk3288-tinker.dts -@@ -70,7 +70,7 @@ +diff --git a/arch/arm/boot/dts/rk3288-tinker.dtsi b/arch/arm/boot/dts/rk3288-tinker.dtsi +index 01be2bca9..5439e29e0 100644 +--- a/arch/arm/boot/dts/rk3288-tinker.dtsi ++++ b/arch/arm/boot/dts/rk3288-tinker.dtsi +@@ -64,7 +64,7 @@ sound { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; diff --git a/buildroot-external/board/asus/tinker/patches/linux/general-fix-reboot-from-kwiboo.patch b/buildroot-external/board/asus/tinker/patches/linux/general-fix-reboot-from-kwiboo.patch new file mode 100644 index 000000000..088b7ebe8 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/general-fix-reboot-from-kwiboo.patch @@ -0,0 +1,19 @@ +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index 5bd58b95d..48ebe081f 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -1684,6 +1684,14 @@ void mmc_power_off(struct mmc_host *host) + if (host->ios.power_mode == MMC_POWER_OFF) + return; + ++ mmc_set_initial_signal_voltage(host); ++ ++ /* ++ * This delay should be sufficient to allow the power supply ++ * to reach the minimum voltage. ++ */ ++ mmc_delay(host->ios.power_delay_ms); ++ + mmc_pwrseq_power_off(host); + + host->ios.clock = 0; diff --git a/buildroot-external/board/asus/tinker/patches/linux/general-increasing_DMA_block_memory_allocation_to_2048.patch b/buildroot-external/board/asus/tinker/patches/linux/general-increasing_DMA_block_memory_allocation_to_2048.patch deleted file mode 100644 index 8d8746273..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/general-increasing_DMA_block_memory_allocation_to_2048.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c -index 3216e09..21bce28 ---- a/arch/arm64/mm/dma-mapping.c -+++ b/arch/arm64/mm/dma-mapping.c -@@ -44,7 +44,7 @@ static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot, - - static struct gen_pool *atomic_pool; - --#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K -+#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_2M - static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE; - - static int __init early_coherent_pool(char *p) - -diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c -index ada8eb2..8df220f ---- a/arch/arm/mm/dma-mapping.c -+++ b/arch/arm/mm/dma-mapping.c -@@ -381,7 +381,7 @@ static void __dma_free_remap(void *cpu_addr, size_t size) - VM_ARM_DMA_CONSISTENT | VM_USERMAP); - } - --#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K -+#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_2M - static struct gen_pool *atomic_pool __ro_after_init; - - static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE; diff --git a/buildroot-external/board/asus/tinker/patches/linux/remove-broken-dtb.patch b/buildroot-external/board/asus/tinker/patches/linux/remove-broken-dtb.patch new file mode 100644 index 000000000..2b66c1d74 --- /dev/null +++ b/buildroot-external/board/asus/tinker/patches/linux/remove-broken-dtb.patch @@ -0,0 +1,22 @@ +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index a98dee2ae..d3cef7033 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -916,17 +916,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ + rk3288-rock2-square.dtb \ + rk3288-tinker.dtb \ + rk3288-tinker-s.dtb \ +- rk3288-veyron-brain.dtb \ +- rk3288-veyron-fievel.dtb \ +- rk3288-veyron-jaq.dtb \ +- rk3288-veyron-jerry.dtb \ +- rk3288-veyron-mickey.dtb \ +- rk3288-veyron-mighty.dtb \ +- rk3288-veyron-minnie.dtb \ +- rk3288-veyron-pinky.dtb \ +- rk3288-veyron-speedy.dtb \ +- rk3288-veyron-tiger.dtb \ + rk3288-vyasa.dtb + dtb-$(CONFIG_ARCH_S3C24XX) += \ + s3c2416-smdk2416.dtb + dtb-$(CONFIG_ARCH_S3C64XX) += \ diff --git a/buildroot-external/board/asus/tinker/patches/linux/wifi-2001-01-rtl8188eu-kconfig-makefile.patch b/buildroot-external/board/asus/tinker/patches/linux/wifi-2001-01-rtl8188eu-kconfig-makefile.patch deleted file mode 100644 index 4e9018082..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/wifi-2001-01-rtl8188eu-kconfig-makefile.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig -index 95cdb48fad061..db9ee74578012 100644 ---- a/drivers/net/wireless/Kconfig -+++ b/drivers/net/wireless/Kconfig -@@ -32,6 +32,7 @@ config WIRELESS_WDS - - source "drivers/net/wireless/admtek/Kconfig" - source "drivers/net/wireless/ath/Kconfig" -+source "drivers/net/wireless/rtl8188eu/Kconfig" - source "drivers/net/wireless/atmel/Kconfig" - source "drivers/net/wireless/broadcom/Kconfig" - source "drivers/net/wireless/cisco/Kconfig" -diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile -index edeb51f6fa551..2c4d8522929bf 100644 ---- a/drivers/net/wireless/Makefile -+++ b/drivers/net/wireless/Makefile -@@ -5,6 +5,7 @@ - - obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/ - obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/ -+obj-$(CONFIG_RTL8188EU) += rtl8188eu/ - obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/ - obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/ - obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/ diff --git a/buildroot-external/board/asus/tinker/patches/linux/wifi-2002-02-rtl8188eu.patch b/buildroot-external/board/asus/tinker/patches/linux/wifi-2002-02-rtl8188eu.patch deleted file mode 100644 index d356c74bf..000000000 --- a/buildroot-external/board/asus/tinker/patches/linux/wifi-2002-02-rtl8188eu.patch +++ /dev/null @@ -1,315825 +0,0 @@ -From e23751161230366c174e8af272e941281fb0eba8 Mon Sep 17 00:00:00 2001 -From: Anand Moon -Date: Sun, 14 Jan 2018 23:29:46 +0530 -Subject: [PATCH] ODROID-XU4 : Add Realtek RTL8188eu wifi driver - -source code: https://github.com/lwfinger/rtl8188eu - -Change-Id: I49119f7b9200a6e3c72a1df66e23e761feb7eae6 ---- - drivers/net/wireless/Kconfig | 1 + - drivers/net/wireless/Makefile | 3 +- - drivers/net/wireless/rtl8188eu/.gitignore | 96 + - drivers/net/wireless/rtl8188eu/COPYING | 356 + - drivers/net/wireless/rtl8188eu/Kconfig | 5 + - drivers/net/wireless/rtl8188eu/Makefile | 185 + - drivers/net/wireless/rtl8188eu/README.md | 36 + - drivers/net/wireless/rtl8188eu/control_ap | 162 + - drivers/net/wireless/rtl8188eu/core/rtw_ap.c | 1976 +++++ - drivers/net/wireless/rtl8188eu/core/rtw_br_ext.c | 1184 +++ - drivers/net/wireless/rtl8188eu/core/rtw_cmd.c | 2206 +++++ - drivers/net/wireless/rtl8188eu/core/rtw_debug.c | 943 +++ - drivers/net/wireless/rtl8188eu/core/rtw_efuse.c | 872 ++ - .../net/wireless/rtl8188eu/core/rtw_ieee80211.c | 1625 ++++ - drivers/net/wireless/rtl8188eu/core/rtw_io.c | 323 + - .../net/wireless/rtl8188eu/core/rtw_ioctl_set.c | 1118 +++ - drivers/net/wireless/rtl8188eu/core/rtw_iol.c | 209 + - drivers/net/wireless/rtl8188eu/core/rtw_led.c | 1700 ++++ - drivers/net/wireless/rtl8188eu/core/rtw_mlme.c | 2354 ++++++ - drivers/net/wireless/rtl8188eu/core/rtw_mlme_ext.c | 8407 ++++++++++++++++++++ - drivers/net/wireless/rtl8188eu/core/rtw_mp.c | 1001 +++ - drivers/net/wireless/rtl8188eu/core/rtw_mp_ioctl.c | 1352 ++++ - drivers/net/wireless/rtl8188eu/core/rtw_p2p.c | 2068 +++++ - drivers/net/wireless/rtl8188eu/core/rtw_pwrctrl.c | 655 ++ - drivers/net/wireless/rtl8188eu/core/rtw_recv.c | 2252 ++++++ - drivers/net/wireless/rtl8188eu/core/rtw_rf.c | 88 + - drivers/net/wireless/rtl8188eu/core/rtw_security.c | 1757 ++++ - drivers/net/wireless/rtl8188eu/core/rtw_sreset.c | 79 + - drivers/net/wireless/rtl8188eu/core/rtw_sta_mgt.c | 609 ++ - .../net/wireless/rtl8188eu/core/rtw_wlan_util.c | 1690 ++++ - drivers/net/wireless/rtl8188eu/core/rtw_xmit.c | 2370 ++++++ - drivers/net/wireless/rtl8188eu/dkms.conf | 9 + - .../net/wireless/rtl8188eu/hal/Hal8188EPwrSeq.c | 86 + - .../wireless/rtl8188eu/hal/Hal8188ERateAdaptive.c | 760 ++ - .../net/wireless/rtl8188eu/hal/HalHWImg8188E_BB.c | 720 ++ - .../net/wireless/rtl8188eu/hal/HalHWImg8188E_MAC.c | 230 + - .../net/wireless/rtl8188eu/hal/HalHWImg8188E_RF.c | 268 + - drivers/net/wireless/rtl8188eu/hal/HalPhyRf.c | 49 + - .../net/wireless/rtl8188eu/hal/HalPhyRf_8188e.c | 1505 ++++ - drivers/net/wireless/rtl8188eu/hal/HalPwrSeqCmd.c | 132 + - drivers/net/wireless/rtl8188eu/hal/hal_com.c | 381 + - drivers/net/wireless/rtl8188eu/hal/hal_intf.c | 468 ++ - drivers/net/wireless/rtl8188eu/hal/odm.c | 2174 +++++ - drivers/net/wireless/rtl8188eu/hal/odm_HWConfig.c | 601 ++ - drivers/net/wireless/rtl8188eu/hal/odm_RTL8188E.c | 400 + - .../wireless/rtl8188eu/hal/odm_RegConfig8188E.c | 130 + - drivers/net/wireless/rtl8188eu/hal/odm_debug.c | 32 + - drivers/net/wireless/rtl8188eu/hal/odm_interface.c | 205 + - drivers/net/wireless/rtl8188eu/hal/rtl8188e_cmd.c | 762 ++ - drivers/net/wireless/rtl8188eu/hal/rtl8188e_dm.c | 267 + - .../net/wireless/rtl8188eu/hal/rtl8188e_hal_init.c | 2390 ++++++ - drivers/net/wireless/rtl8188eu/hal/rtl8188e_mp.c | 851 ++ - .../net/wireless/rtl8188eu/hal/rtl8188e_phycfg.c | 1135 +++ - .../net/wireless/rtl8188eu/hal/rtl8188e_rf6052.c | 569 ++ - .../net/wireless/rtl8188eu/hal/rtl8188e_rxdesc.c | 202 + - .../net/wireless/rtl8188eu/hal/rtl8188e_sreset.c | 80 + - drivers/net/wireless/rtl8188eu/hal/rtl8188e_xmit.c | 91 + - drivers/net/wireless/rtl8188eu/hal/rtl8188eu_led.c | 111 + - .../net/wireless/rtl8188eu/hal/rtl8188eu_recv.c | 136 + - .../net/wireless/rtl8188eu/hal/rtl8188eu_xmit.c | 703 ++ - drivers/net/wireless/rtl8188eu/hal/usb_halinit.c | 2333 ++++++ - drivers/net/wireless/rtl8188eu/hal/usb_ops_linux.c | 716 ++ - drivers/net/wireless/rtl8188eu/hostapd-0.8/COPYING | 340 + - drivers/net/wireless/rtl8188eu/hostapd-0.8/README | 72 + - .../rtl8188eu/hostapd-0.8/hostapd/Android.mk | 816 ++ - .../rtl8188eu/hostapd-0.8/hostapd/ChangeLog | 647 ++ - .../rtl8188eu/hostapd-0.8/hostapd/Makefile | 836 ++ - .../wireless/rtl8188eu/hostapd-0.8/hostapd/README | 387 + - .../rtl8188eu/hostapd-0.8/hostapd/README-WPS | 291 + - .../rtl8188eu/hostapd-0.8/hostapd/config_file.c | 2119 +++++ - .../rtl8188eu/hostapd-0.8/hostapd/config_file.h | 20 + - .../rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.c | 1131 +++ - .../rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.h | 32 + - .../rtl8188eu/hostapd-0.8/hostapd/defconfig | 208 + - .../rtl8188eu/hostapd-0.8/hostapd/dump_state.c | 183 + - .../rtl8188eu/hostapd-0.8/hostapd/dump_state.h | 20 + - .../rtl8188eu/hostapd-0.8/hostapd/eap_register.c | 139 + - .../rtl8188eu/hostapd-0.8/hostapd/eap_register.h | 20 + - .../rtl8188eu/hostapd-0.8/hostapd/eap_testing.txt | 77 + - .../rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.c | 715 ++ - .../hostapd-0.8/hostapd/hlr_auc_gw.milenage_db | 13 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.8 | 59 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.accept | 6 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.conf | 1040 +++ - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.deny | 5 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.eap_user | 91 + - .../hostapd-0.8/hostapd/hostapd.radius_clients | 4 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.sim_db | 9 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.vlan | 9 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd.wpa_psk | 9 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.1 | 89 + - .../rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.c | 1044 +++ - .../rtl8188eu/hostapd-0.8/hostapd/logwatch/README | 9 + - .../rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd | 65 + - .../hostapd-0.8/hostapd/logwatch/hostapd.conf | 10 + - .../wireless/rtl8188eu/hostapd-0.8/hostapd/main.c | 599 ++ - .../hostapd-0.8/hostapd/nt_password_hash.c | 53 + - .../rtl8188eu/hostapd-0.8/hostapd/wired.conf | 40 + - .../wireless/rtl8188eu/hostapd-0.8/src/Makefile | 11 + - .../wireless/rtl8188eu/hostapd-0.8/src/ap/Makefile | 8 + - .../rtl8188eu/hostapd-0.8/src/ap/accounting.c | 505 ++ - .../rtl8188eu/hostapd-0.8/src/ap/accounting.h | 45 + - .../rtl8188eu/hostapd-0.8/src/ap/ap_config.c | 627 ++ - .../rtl8188eu/hostapd-0.8/src/ap/ap_config.h | 417 + - .../rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.c | 632 ++ - .../rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.h | 197 + - .../rtl8188eu/hostapd-0.8/src/ap/ap_list.c | 399 + - .../rtl8188eu/hostapd-0.8/src/ap/ap_list.h | 78 + - .../rtl8188eu/hostapd-0.8/src/ap/ap_mlme.c | 184 + - .../rtl8188eu/hostapd-0.8/src/ap/ap_mlme.h | 40 + - .../rtl8188eu/hostapd-0.8/src/ap/authsrv.c | 217 + - .../rtl8188eu/hostapd-0.8/src/ap/authsrv.h | 21 + - .../wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.c | 540 ++ - .../wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.h | 36 + - .../rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.c | 108 + - .../rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.h | 25 + - .../rtl8188eu/hostapd-0.8/src/ap/drv_callbacks.c | 539 ++ - .../rtl8188eu/hostapd-0.8/src/ap/hostapd.c | 929 +++ - .../rtl8188eu/hostapd-0.8/src/ap/hostapd.h | 262 + - .../rtl8188eu/hostapd-0.8/src/ap/hw_features.c | 754 ++ - .../rtl8188eu/hostapd-0.8/src/ap/hw_features.h | 70 + - .../wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.c | 535 ++ - .../wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.h | 45 + - .../rtl8188eu/hostapd-0.8/src/ap/ieee802_11.c | 1884 +++++ - .../rtl8188eu/hostapd-0.8/src/ap/ieee802_11.h | 68 + - .../rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.c | 524 ++ - .../rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.h | 31 + - .../rtl8188eu/hostapd-0.8/src/ap/ieee802_11_ht.c | 267 + - .../rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.c | 2085 +++++ - .../rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.h | 89 + - .../rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.c | 120 + - .../rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.h | 41 + - .../rtl8188eu/hostapd-0.8/src/ap/peerkey_auth.c | 402 + - .../hostapd-0.8/src/ap/pmksa_cache_auth.c | 425 + - .../hostapd-0.8/src/ap/pmksa_cache_auth.h | 64 + - .../rtl8188eu/hostapd-0.8/src/ap/preauth_auth.c | 279 + - .../rtl8188eu/hostapd-0.8/src/ap/preauth_auth.h | 58 + - .../rtl8188eu/hostapd-0.8/src/ap/sta_info.c | 796 ++ - .../rtl8188eu/hostapd-0.8/src/ap/sta_info.h | 165 + - .../hostapd-0.8/src/ap/tkip_countermeasures.c | 94 + - .../hostapd-0.8/src/ap/tkip_countermeasures.h | 20 + - .../wireless/rtl8188eu/hostapd-0.8/src/ap/utils.c | 88 + - .../rtl8188eu/hostapd-0.8/src/ap/vlan_init.c | 905 +++ - .../rtl8188eu/hostapd-0.8/src/ap/vlan_init.h | 59 + - .../wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.c | 327 + - .../wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.h | 29 + - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth.c | 2838 +++++++ - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth.h | 285 + - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ft.c | 1779 +++++ - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.c | 571 ++ - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.h | 22 + - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth_i.h | 234 + - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.c | 824 ++ - .../rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.h | 56 + - .../rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.c | 1380 ++++ - .../rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.h | 72 + - .../rtl8188eu/hostapd-0.8/src/common/Makefile | 8 + - .../rtl8188eu/hostapd-0.8/src/common/defs.h | 270 + - .../hostapd-0.8/src/common/eapol_common.h | 47 + - .../hostapd-0.8/src/common/ieee802_11_common.c | 347 + - .../hostapd-0.8/src/common/ieee802_11_common.h | 81 + - .../hostapd-0.8/src/common/ieee802_11_defs.h | 800 ++ - .../hostapd-0.8/src/common/privsep_commands.h | 75 + - .../rtl8188eu/hostapd-0.8/src/common/version.h | 10 + - .../rtl8188eu/hostapd-0.8/src/common/wpa_common.c | 927 +++ - .../rtl8188eu/hostapd-0.8/src/common/wpa_common.h | 361 + - .../rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.c | 500 ++ - .../rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.h | 274 + - .../rtl8188eu/hostapd-0.8/src/crypto/.gitignore | 1 + - .../rtl8188eu/hostapd-0.8/src/crypto/Makefile | 56 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes-cbc.c | 86 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes-ctr.c | 61 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes-eax.c | 151 + - .../hostapd-0.8/src/crypto/aes-encblock.c | 38 + - .../hostapd-0.8/src/crypto/aes-internal-dec.c | 151 + - .../hostapd-0.8/src/crypto/aes-internal-enc.c | 121 + - .../hostapd-0.8/src/crypto/aes-internal.c | 805 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/aes-omac1.c | 124 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes-unwrap.c | 79 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes-wrap.c | 76 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes.h | 27 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes_i.h | 122 + - .../rtl8188eu/hostapd-0.8/src/crypto/aes_wrap.h | 48 + - .../rtl8188eu/hostapd-0.8/src/crypto/crypto.h | 469 ++ - .../hostapd-0.8/src/crypto/crypto_cryptoapi.c | 789 ++ - .../hostapd-0.8/src/crypto/crypto_gnutls.c | 305 + - .../src/crypto/crypto_internal-cipher.c | 256 + - .../src/crypto/crypto_internal-modexp.c | 55 + - .../hostapd-0.8/src/crypto/crypto_internal-rsa.c | 115 + - .../hostapd-0.8/src/crypto/crypto_internal.c | 205 + - .../hostapd-0.8/src/crypto/crypto_libtomcrypt.c | 732 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/crypto_none.c | 29 + - .../rtl8188eu/hostapd-0.8/src/crypto/crypto_nss.c | 213 + - .../hostapd-0.8/src/crypto/crypto_openssl.c | 505 ++ - .../hostapd-0.8/src/crypto/des-internal.c | 499 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/des_i.h | 31 + - .../rtl8188eu/hostapd-0.8/src/crypto/dh_group5.c | 40 + - .../rtl8188eu/hostapd-0.8/src/crypto/dh_group5.h | 23 + - .../rtl8188eu/hostapd-0.8/src/crypto/dh_groups.c | 633 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/dh_groups.h | 32 + - .../hostapd-0.8/src/crypto/fips_prf_cryptoapi.c | 25 + - .../hostapd-0.8/src/crypto/fips_prf_gnutls.c | 26 + - .../hostapd-0.8/src/crypto/fips_prf_internal.c | 74 + - .../hostapd-0.8/src/crypto/fips_prf_nss.c | 25 + - .../hostapd-0.8/src/crypto/fips_prf_openssl.c | 83 + - .../hostapd-0.8/src/crypto/md4-internal.c | 278 + - .../hostapd-0.8/src/crypto/md5-internal.c | 293 + - .../hostapd-0.8/src/crypto/md5-non-fips.c | 113 + - .../rtl8188eu/hostapd-0.8/src/crypto/md5.c | 111 + - .../rtl8188eu/hostapd-0.8/src/crypto/md5.h | 35 + - .../rtl8188eu/hostapd-0.8/src/crypto/md5_i.h | 29 + - .../rtl8188eu/hostapd-0.8/src/crypto/milenage.c | 329 + - .../rtl8188eu/hostapd-0.8/src/crypto/milenage.h | 33 + - .../rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.c | 476 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.h | 64 + - .../rtl8188eu/hostapd-0.8/src/crypto/random.c | 337 + - .../rtl8188eu/hostapd-0.8/src/crypto/random.h | 34 + - .../rtl8188eu/hostapd-0.8/src/crypto/rc4.c | 60 + - .../hostapd-0.8/src/crypto/sha1-internal.c | 308 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha1-pbkdf2.c | 100 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha1-tlsprf.c | 109 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha1-tprf.c | 76 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha1.c | 163 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha1.h | 33 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha1_i.h | 29 + - .../hostapd-0.8/src/crypto/sha256-internal.c | 243 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha256.c | 157 + - .../rtl8188eu/hostapd-0.8/src/crypto/sha256.h | 27 + - .../rtl8188eu/hostapd-0.8/src/crypto/tls.h | 569 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/tls_gnutls.c | 1457 ++++ - .../hostapd-0.8/src/crypto/tls_internal.c | 651 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/tls_none.c | 229 + - .../rtl8188eu/hostapd-0.8/src/crypto/tls_nss.c | 680 ++ - .../rtl8188eu/hostapd-0.8/src/crypto/tls_openssl.c | 2992 +++++++ - .../hostapd-0.8/src/crypto/tls_schannel.c | 767 ++ - .../rtl8188eu/hostapd-0.8/src/drivers/.gitignore | 2 + - .../rtl8188eu/hostapd-0.8/src/drivers/Apple80211.h | 156 + - .../rtl8188eu/hostapd-0.8/src/drivers/Makefile | 9 + - .../hostapd-0.8/src/drivers/MobileApple80211.c | 189 + - .../hostapd-0.8/src/drivers/MobileApple80211.h | 43 + - .../rtl8188eu/hostapd-0.8/src/drivers/driver.h | 3230 ++++++++ - .../hostapd-0.8/src/drivers/driver_atheros.c | 1381 ++++ - .../hostapd-0.8/src/drivers/driver_broadcom.c | 599 ++ - .../rtl8188eu/hostapd-0.8/src/drivers/driver_bsd.c | 1573 ++++ - .../hostapd-0.8/src/drivers/driver_hostap.c | 1648 ++++ - .../hostapd-0.8/src/drivers/driver_hostap.h | 216 + - .../hostapd-0.8/src/drivers/driver_iphone.m | 466 ++ - .../hostapd-0.8/src/drivers/driver_madwifi.c | 1856 +++++ - .../hostapd-0.8/src/drivers/driver_ndis.c | 3331 ++++++++ - .../hostapd-0.8/src/drivers/driver_ndis.h | 65 + - .../hostapd-0.8/src/drivers/driver_ndis_.c | 105 + - .../hostapd-0.8/src/drivers/driver_nl80211.c | 6550 +++++++++++++++ - .../hostapd-0.8/src/drivers/driver_none.c | 99 + - .../rtl8188eu/hostapd-0.8/src/drivers/driver_osx.m | 459 ++ - .../hostapd-0.8/src/drivers/driver_privsep.c | 758 ++ - .../hostapd-0.8/src/drivers/driver_ralink.c | 1498 ++++ - .../hostapd-0.8/src/drivers/driver_ralink.h | 383 + - .../hostapd-0.8/src/drivers/driver_roboswitch.c | 480 ++ - .../rtl8188eu/hostapd-0.8/src/drivers/driver_rtl.h | 113 + - .../rtl8188eu/hostapd-0.8/src/drivers/driver_rtw.c | 1902 +++++ - .../hostapd-0.8/src/drivers/driver_test.c | 3391 ++++++++ - .../hostapd-0.8/src/drivers/driver_wext.c | 2356 ++++++ - .../hostapd-0.8/src/drivers/driver_wext.h | 87 + - .../hostapd-0.8/src/drivers/driver_wired.c | 629 ++ - .../rtl8188eu/hostapd-0.8/src/drivers/drivers.c | 120 + - .../rtl8188eu/hostapd-0.8/src/drivers/drivers.mak | 191 + - .../rtl8188eu/hostapd-0.8/src/drivers/drivers.mk | 183 + - .../hostapd-0.8/src/drivers/linux_ioctl.c | 198 + - .../hostapd-0.8/src/drivers/linux_ioctl.h | 27 + - .../hostapd-0.8/src/drivers/ndis_events.c | 808 ++ - .../rtl8188eu/hostapd-0.8/src/drivers/netlink.c | 204 + - .../rtl8188eu/hostapd-0.8/src/drivers/netlink.h | 34 + - .../hostapd-0.8/src/drivers/nl80211_copy.h | 1939 +++++ - .../hostapd-0.8/src/drivers/priv_netlink.h | 113 + - .../rtl8188eu/hostapd-0.8/src/drivers/rfkill.c | 194 + - .../rtl8188eu/hostapd-0.8/src/drivers/rfkill.h | 31 + - .../hostapd-0.8/src/drivers/wireless_copy.h | 1185 +++ - .../rtl8188eu/hostapd-0.8/src/eap_common/Makefile | 8 + - .../rtl8188eu/hostapd-0.8/src/eap_common/chap.c | 34 + - .../rtl8188eu/hostapd-0.8/src/eap_common/chap.h | 23 + - .../hostapd-0.8/src/eap_common/eap_common.c | 184 + - .../hostapd-0.8/src/eap_common/eap_common.h | 28 + - .../hostapd-0.8/src/eap_common/eap_defs.h | 86 + - .../hostapd-0.8/src/eap_common/eap_fast_common.c | 304 + - .../hostapd-0.8/src/eap_common/eap_fast_common.h | 113 + - .../hostapd-0.8/src/eap_common/eap_gpsk_common.c | 423 + - .../hostapd-0.8/src/eap_common/eap_gpsk_common.h | 66 + - .../hostapd-0.8/src/eap_common/eap_ikev2_common.c | 132 + - .../hostapd-0.8/src/eap_common/eap_ikev2_common.h | 42 + - .../hostapd-0.8/src/eap_common/eap_pax_common.c | 150 + - .../hostapd-0.8/src/eap_common/eap_pax_common.h | 97 + - .../hostapd-0.8/src/eap_common/eap_peap_common.c | 88 + - .../hostapd-0.8/src/eap_common/eap_peap_common.h | 22 + - .../hostapd-0.8/src/eap_common/eap_psk_common.c | 74 + - .../hostapd-0.8/src/eap_common/eap_psk_common.h | 78 + - .../hostapd-0.8/src/eap_common/eap_pwd_common.c | 312 + - .../hostapd-0.8/src/eap_common/eap_pwd_common.h | 79 + - .../hostapd-0.8/src/eap_common/eap_sake_common.c | 393 + - .../hostapd-0.8/src/eap_common/eap_sake_common.h | 102 + - .../hostapd-0.8/src/eap_common/eap_sim_common.c | 1215 +++ - .../hostapd-0.8/src/eap_common/eap_sim_common.h | 235 + - .../hostapd-0.8/src/eap_common/eap_tlv_common.h | 118 + - .../hostapd-0.8/src/eap_common/eap_ttls.h | 71 + - .../hostapd-0.8/src/eap_common/eap_wsc_common.c | 39 + - .../hostapd-0.8/src/eap_common/eap_wsc_common.h | 33 + - .../hostapd-0.8/src/eap_common/ikev2_common.c | 797 ++ - .../hostapd-0.8/src/eap_common/ikev2_common.h | 344 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/Makefile | 11 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap.c | 2159 +++++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap.h | 292 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_aka.c | 1389 ++++ - .../hostapd-0.8/src/eap_peer/eap_config.h | 669 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast.c | 1712 ++++ - .../hostapd-0.8/src/eap_peer/eap_fast_pac.c | 923 +++ - .../hostapd-0.8/src/eap_peer/eap_fast_pac.h | 56 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_gpsk.c | 738 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_gtc.c | 151 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_i.h | 356 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_ikev2.c | 506 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_leap.c | 416 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_md5.c | 120 + - .../hostapd-0.8/src/eap_peer/eap_methods.c | 373 + - .../hostapd-0.8/src/eap_peer/eap_methods.h | 114 + - .../hostapd-0.8/src/eap_peer/eap_mschapv2.c | 883 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_otp.c | 107 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_pax.c | 531 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_peap.c | 1288 +++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_psk.c | 483 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_pwd.c | 744 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_sake.c | 500 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_sim.c | 1101 +++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls.c | 289 + - .../hostapd-0.8/src/eap_peer/eap_tls_common.c | 1021 +++ - .../hostapd-0.8/src/eap_peer/eap_tls_common.h | 126 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_tnc.c | 434 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_ttls.c | 1986 +++++ - .../hostapd-0.8/src/eap_peer/eap_vendor_test.c | 195 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/eap_wsc.c | 553 ++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.c | 1304 +++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.h | 65 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.c | 123 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.h | 34 + - .../rtl8188eu/hostapd-0.8/src/eap_peer/tncc.c | 1369 ++++ - .../rtl8188eu/hostapd-0.8/src/eap_peer/tncc.h | 42 + - .../rtl8188eu/hostapd-0.8/src/eap_server/Makefile | 8 + - .../rtl8188eu/hostapd-0.8/src/eap_server/eap.h | 128 + - .../rtl8188eu/hostapd-0.8/src/eap_server/eap_i.h | 201 + - .../hostapd-0.8/src/eap_server/eap_methods.h | 54 + - .../hostapd-0.8/src/eap_server/eap_server.c | 1384 ++++ - .../hostapd-0.8/src/eap_server/eap_server_aka.c | 1278 +++ - .../hostapd-0.8/src/eap_server/eap_server_fast.c | 1620 ++++ - .../hostapd-0.8/src/eap_server/eap_server_gpsk.c | 634 ++ - .../hostapd-0.8/src/eap_server/eap_server_gtc.c | 230 + - .../src/eap_server/eap_server_identity.c | 180 + - .../hostapd-0.8/src/eap_server/eap_server_ikev2.c | 539 ++ - .../hostapd-0.8/src/eap_server/eap_server_md5.c | 177 + - .../src/eap_server/eap_server_methods.c | 175 + - .../src/eap_server/eap_server_mschapv2.c | 575 ++ - .../hostapd-0.8/src/eap_server/eap_server_pax.c | 570 ++ - .../hostapd-0.8/src/eap_server/eap_server_peap.c | 1387 ++++ - .../hostapd-0.8/src/eap_server/eap_server_psk.c | 518 ++ - .../hostapd-0.8/src/eap_server/eap_server_pwd.c | 844 ++ - .../hostapd-0.8/src/eap_server/eap_server_sake.c | 543 ++ - .../hostapd-0.8/src/eap_server/eap_server_sim.c | 798 ++ - .../hostapd-0.8/src/eap_server/eap_server_tls.c | 286 + - .../src/eap_server/eap_server_tls_common.c | 400 + - .../hostapd-0.8/src/eap_server/eap_server_tnc.c | 582 ++ - .../hostapd-0.8/src/eap_server/eap_server_ttls.c | 1430 ++++ - .../src/eap_server/eap_server_vendor_test.c | 198 + - .../hostapd-0.8/src/eap_server/eap_server_wsc.c | 517 ++ - .../hostapd-0.8/src/eap_server/eap_sim_db.c | 1338 ++++ - .../hostapd-0.8/src/eap_server/eap_sim_db.h | 91 + - .../hostapd-0.8/src/eap_server/eap_tls_common.h | 91 + - .../rtl8188eu/hostapd-0.8/src/eap_server/ikev2.c | 1206 +++ - .../rtl8188eu/hostapd-0.8/src/eap_server/ikev2.h | 67 + - .../rtl8188eu/hostapd-0.8/src/eap_server/tncs.c | 1273 +++ - .../rtl8188eu/hostapd-0.8/src/eap_server/tncs.h | 49 + - .../rtl8188eu/hostapd-0.8/src/eapol_auth/Makefile | 8 + - .../hostapd-0.8/src/eapol_auth/eapol_auth_dump.c | 231 + - .../hostapd-0.8/src/eapol_auth/eapol_auth_sm.c | 1145 +++ - .../hostapd-0.8/src/eapol_auth/eapol_auth_sm.h | 92 + - .../hostapd-0.8/src/eapol_auth/eapol_auth_sm_i.h | 183 + - .../rtl8188eu/hostapd-0.8/src/eapol_supp/Makefile | 8 + - .../hostapd-0.8/src/eapol_supp/eapol_supp_sm.c | 1913 +++++ - .../hostapd-0.8/src/eapol_supp/eapol_supp_sm.h | 352 + - .../rtl8188eu/hostapd-0.8/src/l2_packet/Makefile | 8 + - .../hostapd-0.8/src/l2_packet/l2_packet.h | 130 + - .../hostapd-0.8/src/l2_packet/l2_packet_freebsd.c | 316 + - .../hostapd-0.8/src/l2_packet/l2_packet_linux.c | 210 + - .../hostapd-0.8/src/l2_packet/l2_packet_ndis.c | 522 ++ - .../hostapd-0.8/src/l2_packet/l2_packet_none.c | 123 + - .../hostapd-0.8/src/l2_packet/l2_packet_pcap.c | 386 + - .../hostapd-0.8/src/l2_packet/l2_packet_privsep.c | 267 + - .../hostapd-0.8/src/l2_packet/l2_packet_winpcap.c | 341 + - .../wireless/rtl8188eu/hostapd-0.8/src/lib.rules | 21 + - .../rtl8188eu/hostapd-0.8/src/p2p/Makefile | 9 + - .../wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.c | 3490 ++++++++ - .../wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.h | 1473 ++++ - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_build.c | 431 + - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_dev_disc.c | 365 + - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_go_neg.c | 1127 +++ - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_group.c | 673 ++ - .../wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_i.h | 638 ++ - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_invitation.c | 489 ++ - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_parse.c | 718 ++ - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_pd.c | 347 + - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_sd.c | 951 +++ - .../rtl8188eu/hostapd-0.8/src/p2p/p2p_utils.c | 271 + - .../rtl8188eu/hostapd-0.8/src/radius/.gitignore | 1 + - .../rtl8188eu/hostapd-0.8/src/radius/Makefile | 22 + - .../rtl8188eu/hostapd-0.8/src/radius/radius.c | 1317 +++ - .../rtl8188eu/hostapd-0.8/src/radius/radius.h | 273 + - .../hostapd-0.8/src/radius/radius_client.c | 1499 ++++ - .../hostapd-0.8/src/radius/radius_client.h | 265 + - .../hostapd-0.8/src/radius/radius_server.c | 1527 ++++ - .../hostapd-0.8/src/radius/radius_server.h | 217 + - .../rtl8188eu/hostapd-0.8/src/rsn_supp/Makefile | 8 + - .../rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.c | 1186 +++ - .../rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.h | 87 + - .../hostapd-0.8/src/rsn_supp/pmksa_cache.c | 476 ++ - .../hostapd-0.8/src/rsn_supp/pmksa_cache.h | 127 + - .../rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.c | 518 ++ - .../rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.h | 85 + - .../rtl8188eu/hostapd-0.8/src/rsn_supp/tdls.c | 2069 +++++ - .../rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.c | 2644 ++++++ - .../rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.h | 351 + - .../rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ft.c | 1039 +++ - .../rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_i.h | 290 + - .../rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.c | 447 ++ - .../rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.h | 60 + - .../rtl8188eu/hostapd-0.8/src/tls/.gitignore | 1 + - .../rtl8188eu/hostapd-0.8/src/tls/Makefile | 37 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.c | 212 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.h | 72 + - .../rtl8188eu/hostapd-0.8/src/tls/bignum.c | 230 + - .../rtl8188eu/hostapd-0.8/src/tls/bignum.h | 38 + - .../rtl8188eu/hostapd-0.8/src/tls/libtommath.c | 3381 ++++++++ - .../wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.c | 201 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.h | 28 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.c | 238 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.h | 22 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.c | 193 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.h | 22 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.c | 358 + - .../wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.h | 29 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.c | 667 ++ - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.h | 59 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_i.h | 87 + - .../hostapd-0.8/src/tls/tlsv1_client_read.c | 976 +++ - .../hostapd-0.8/src/tls/tlsv1_client_write.c | 798 ++ - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.c | 241 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.h | 216 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.c | 493 ++ - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.h | 46 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.c | 409 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.h | 74 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.c | 592 ++ - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.h | 54 + - .../rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_i.h | 77 + - .../hostapd-0.8/src/tls/tlsv1_server_read.c | 1134 +++ - .../hostapd-0.8/src/tls/tlsv1_server_write.c | 791 ++ - .../rtl8188eu/hostapd-0.8/src/tls/x509v3.c | 1985 +++++ - .../rtl8188eu/hostapd-0.8/src/tls/x509v3.h | 129 + - .../rtl8188eu/hostapd-0.8/src/utils/.gitignore | 1 + - .../rtl8188eu/hostapd-0.8/src/utils/Makefile | 39 + - .../rtl8188eu/hostapd-0.8/src/utils/base64.c | 154 + - .../rtl8188eu/hostapd-0.8/src/utils/base64.h | 23 + - .../rtl8188eu/hostapd-0.8/src/utils/build_config.h | 105 + - .../rtl8188eu/hostapd-0.8/src/utils/common.c | 387 + - .../rtl8188eu/hostapd-0.8/src/utils/common.h | 502 ++ - .../rtl8188eu/hostapd-0.8/src/utils/edit.c | 1161 +++ - .../rtl8188eu/hostapd-0.8/src/utils/edit.h | 27 + - .../hostapd-0.8/src/utils/edit_readline.c | 184 + - .../rtl8188eu/hostapd-0.8/src/utils/edit_simple.c | 96 + - .../rtl8188eu/hostapd-0.8/src/utils/eloop.c | 627 ++ - .../rtl8188eu/hostapd-0.8/src/utils/eloop.h | 316 + - .../rtl8188eu/hostapd-0.8/src/utils/eloop_none.c | 401 + - .../rtl8188eu/hostapd-0.8/src/utils/eloop_win.c | 623 ++ - .../rtl8188eu/hostapd-0.8/src/utils/includes.h | 59 + - .../rtl8188eu/hostapd-0.8/src/utils/ip_addr.c | 83 + - .../rtl8188eu/hostapd-0.8/src/utils/ip_addr.h | 34 + - .../rtl8188eu/hostapd-0.8/src/utils/list.h | 98 + - .../wireless/rtl8188eu/hostapd-0.8/src/utils/os.h | 508 ++ - .../rtl8188eu/hostapd-0.8/src/utils/os_internal.c | 471 ++ - .../rtl8188eu/hostapd-0.8/src/utils/os_none.c | 226 + - .../rtl8188eu/hostapd-0.8/src/utils/os_unix.c | 474 ++ - .../rtl8188eu/hostapd-0.8/src/utils/os_win32.c | 222 + - .../rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.c | 1238 +++ - .../rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.h | 68 + - .../rtl8188eu/hostapd-0.8/src/utils/radiotap.c | 287 + - .../rtl8188eu/hostapd-0.8/src/utils/radiotap.h | 242 + - .../hostapd-0.8/src/utils/radiotap_iter.h | 41 + - .../hostapd-0.8/src/utils/state_machine.h | 144 + - .../rtl8188eu/hostapd-0.8/src/utils/trace.c | 329 + - .../rtl8188eu/hostapd-0.8/src/utils/trace.h | 74 + - .../rtl8188eu/hostapd-0.8/src/utils/uuid.c | 77 + - .../rtl8188eu/hostapd-0.8/src/utils/uuid.h | 24 + - .../rtl8188eu/hostapd-0.8/src/utils/wpa_debug.c | 484 ++ - .../rtl8188eu/hostapd-0.8/src/utils/wpa_debug.h | 307 + - .../rtl8188eu/hostapd-0.8/src/utils/wpabuf.c | 304 + - .../rtl8188eu/hostapd-0.8/src/utils/wpabuf.h | 168 + - .../rtl8188eu/hostapd-0.8/src/wps/Makefile | 8 + - .../wireless/rtl8188eu/hostapd-0.8/src/wps/http.h | 29 + - .../rtl8188eu/hostapd-0.8/src/wps/http_client.c | 374 + - .../rtl8188eu/hostapd-0.8/src/wps/http_client.h | 46 + - .../rtl8188eu/hostapd-0.8/src/wps/http_server.c | 312 + - .../rtl8188eu/hostapd-0.8/src/wps/http_server.h | 39 + - .../rtl8188eu/hostapd-0.8/src/wps/httpread.c | 861 ++ - .../rtl8188eu/hostapd-0.8/src/wps/httpread.h | 123 + - .../wireless/rtl8188eu/hostapd-0.8/src/wps/ndef.c | 175 + - .../rtl8188eu/hostapd-0.8/src/wps/upnp_xml.c | 252 + - .../rtl8188eu/hostapd-0.8/src/wps/upnp_xml.h | 23 + - .../wireless/rtl8188eu/hostapd-0.8/src/wps/wps.c | 627 ++ - .../wireless/rtl8188eu/hostapd-0.8/src/wps/wps.h | 964 +++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_attr_build.c | 422 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_attr_parse.c | 630 ++ - .../hostapd-0.8/src/wps/wps_attr_process.c | 335 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_common.c | 704 ++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_defs.h | 336 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_dev_attr.c | 444 ++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_dev_attr.h | 44 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_enrollee.c | 1350 ++++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_er.c | 1959 +++++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_er.h | 117 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_er_ssdp.c | 211 + - .../wireless/rtl8188eu/hostapd-0.8/src/wps/wps_i.h | 301 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_nfc.c | 117 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_nfc_pn531.c | 113 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_registrar.c | 3273 ++++++++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_ufd.c | 235 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_upnp.c | 1210 +++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_upnp.h | 48 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_upnp_ap.c | 91 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_upnp_event.c | 423 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_upnp_i.h | 193 + - .../rtl8188eu/hostapd-0.8/src/wps/wps_upnp_ssdp.c | 938 +++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_upnp_web.c | 1324 +++ - .../rtl8188eu/hostapd-0.8/src/wps/wps_validate.c | 1981 +++++ - .../wireless/rtl8188eu/include/Hal8188EPhyCfg.h | 269 + - .../wireless/rtl8188eu/include/Hal8188EPhyReg.h | 1088 +++ - .../wireless/rtl8188eu/include/Hal8188EPwrSeq.h | 173 + - .../rtl8188eu/include/Hal8188ERateAdaptive.h | 75 + - .../net/wireless/rtl8188eu/include/Hal8188EReg.h | 44 + - .../wireless/rtl8188eu/include/HalHWImg8188E_BB.h | 44 + - .../wireless/rtl8188eu/include/HalHWImg8188E_FW.h | 33 + - .../wireless/rtl8188eu/include/HalHWImg8188E_MAC.h | 30 + - .../wireless/rtl8188eu/include/HalHWImg8188E_RF.h | 30 + - drivers/net/wireless/rtl8188eu/include/HalPhyRf.h | 30 + - .../wireless/rtl8188eu/include/HalPhyRf_8188e.h | 58 + - .../net/wireless/rtl8188eu/include/HalPwrSeqCmd.h | 126 + - drivers/net/wireless/rtl8188eu/include/HalVerDef.h | 166 + - drivers/net/wireless/rtl8188eu/include/autoconf.h | 43 + - .../net/wireless/rtl8188eu/include/basic_types.h | 184 + - drivers/net/wireless/rtl8188eu/include/cmd_osdep.h | 32 + - drivers/net/wireless/rtl8188eu/include/drv_types.h | 344 + - .../wireless/rtl8188eu/include/drv_types_linux.h | 23 + - drivers/net/wireless/rtl8188eu/include/ethernet.h | 41 + - drivers/net/wireless/rtl8188eu/include/h2clbk.h | 32 + - drivers/net/wireless/rtl8188eu/include/hal_com.h | 172 + - drivers/net/wireless/rtl8188eu/include/hal_intf.h | 430 + - drivers/net/wireless/rtl8188eu/include/ieee80211.h | 1261 +++ - .../net/wireless/rtl8188eu/include/ieee80211_ext.h | 287 + - drivers/net/wireless/rtl8188eu/include/if_ether.h | 111 + - .../wireless/rtl8188eu/include/ioctl_cfg80211.h | 107 + - drivers/net/wireless/rtl8188eu/include/ip.h | 125 + - .../net/wireless/rtl8188eu/include/mlme_osdep.h | 35 + - .../net/wireless/rtl8188eu/include/mp_custom_oid.h | 349 + - drivers/net/wireless/rtl8188eu/include/nic_spec.h | 41 + - drivers/net/wireless/rtl8188eu/include/odm.h | 1182 +++ - .../net/wireless/rtl8188eu/include/odm_HWConfig.h | 133 + - .../net/wireless/rtl8188eu/include/odm_RTL8188E.h | 56 + - .../rtl8188eu/include/odm_RegConfig8188E.h | 43 + - .../wireless/rtl8188eu/include/odm_RegDefine11AC.h | 46 + - .../wireless/rtl8188eu/include/odm_RegDefine11N.h | 160 + - drivers/net/wireless/rtl8188eu/include/odm_debug.h | 143 + - .../net/wireless/rtl8188eu/include/odm_interface.h | 164 + - .../net/wireless/rtl8188eu/include/odm_precomp.h | 103 + - drivers/net/wireless/rtl8188eu/include/odm_reg.h | 116 + - drivers/net/wireless/rtl8188eu/include/odm_types.h | 61 + - .../net/wireless/rtl8188eu/include/osdep_intf.h | 83 + - .../net/wireless/rtl8188eu/include/osdep_service.h | 489 ++ - .../net/wireless/rtl8188eu/include/recv_osdep.h | 54 + - .../net/wireless/rtl8188eu/include/rtl8188e_cmd.h | 122 + - .../net/wireless/rtl8188eu/include/rtl8188e_dm.h | 62 + - .../net/wireless/rtl8188eu/include/rtl8188e_hal.h | 471 ++ - .../net/wireless/rtl8188eu/include/rtl8188e_led.h | 34 + - .../net/wireless/rtl8188eu/include/rtl8188e_recv.h | 69 + - .../net/wireless/rtl8188eu/include/rtl8188e_rf.h | 35 + - .../net/wireless/rtl8188eu/include/rtl8188e_spec.h | 1438 ++++ - .../wireless/rtl8188eu/include/rtl8188e_sreset.h | 31 + - .../net/wireless/rtl8188eu/include/rtl8188e_xmit.h | 177 + - .../net/wireless/rtl8188eu/include/rtw_android.h | 64 + - drivers/net/wireless/rtl8188eu/include/rtw_ap.h | 67 + - .../net/wireless/rtl8188eu/include/rtw_br_ext.h | 66 + - drivers/net/wireless/rtl8188eu/include/rtw_cmd.h | 991 +++ - drivers/net/wireless/rtl8188eu/include/rtw_debug.h | 274 + - .../net/wireless/rtl8188eu/include/rtw_eeprom.h | 130 + - drivers/net/wireless/rtl8188eu/include/rtw_efuse.h | 150 + - drivers/net/wireless/rtl8188eu/include/rtw_event.h | 113 + - drivers/net/wireless/rtl8188eu/include/rtw_ht.h | 44 + - drivers/net/wireless/rtl8188eu/include/rtw_io.h | 387 + - drivers/net/wireless/rtl8188eu/include/rtw_ioctl.h | 120 + - .../net/wireless/rtl8188eu/include/rtw_ioctl_rtl.h | 79 + - .../net/wireless/rtl8188eu/include/rtw_ioctl_set.h | 49 + - drivers/net/wireless/rtl8188eu/include/rtw_iol.h | 84 + - drivers/net/wireless/rtl8188eu/include/rtw_led.h | 201 + - drivers/net/wireless/rtl8188eu/include/rtw_mlme.h | 649 ++ - .../net/wireless/rtl8188eu/include/rtw_mlme_ext.h | 874 ++ - drivers/net/wireless/rtl8188eu/include/rtw_mp.h | 492 ++ - .../net/wireless/rtl8188eu/include/rtw_mp_ioctl.h | 339 + - .../wireless/rtl8188eu/include/rtw_mp_phy_regdef.h | 1079 +++ - drivers/net/wireless/rtl8188eu/include/rtw_p2p.h | 135 + - .../net/wireless/rtl8188eu/include/rtw_pwrctrl.h | 282 + - drivers/net/wireless/rtl8188eu/include/rtw_qos.h | 30 + - drivers/net/wireless/rtl8188eu/include/rtw_recv.h | 473 ++ - drivers/net/wireless/rtl8188eu/include/rtw_rf.h | 145 + - .../net/wireless/rtl8188eu/include/rtw_security.h | 380 + - .../net/wireless/rtl8188eu/include/rtw_sreset.h | 50 + - .../net/wireless/rtl8188eu/include/rtw_version.h | 1 + - drivers/net/wireless/rtl8188eu/include/rtw_xmit.h | 383 + - drivers/net/wireless/rtl8188eu/include/sta_info.h | 384 + - drivers/net/wireless/rtl8188eu/include/usb_hal.h | 26 + - drivers/net/wireless/rtl8188eu/include/usb_ops.h | 115 + - .../net/wireless/rtl8188eu/include/usb_ops_linux.h | 55 + - .../net/wireless/rtl8188eu/include/usb_osintf.h | 45 + - .../wireless/rtl8188eu/include/usb_vendor_req.h | 51 + - drivers/net/wireless/rtl8188eu/include/wifi.h | 1103 +++ - .../net/wireless/rtl8188eu/include/wlan_bssdef.h | 343 + - .../net/wireless/rtl8188eu/include/xmit_osdep.h | 67 + - .../net/wireless/rtl8188eu/os_dep/ioctl_linux.c | 8178 +++++++++++++++++++ - drivers/net/wireless/rtl8188eu/os_dep/mlme_linux.c | 302 + - drivers/net/wireless/rtl8188eu/os_dep/os_intfs.c | 1273 +++ - .../net/wireless/rtl8188eu/os_dep/osdep_service.c | 535 ++ - drivers/net/wireless/rtl8188eu/os_dep/recv_linux.c | 270 + - .../net/wireless/rtl8188eu/os_dep/rtw_android.c | 299 + - drivers/net/wireless/rtl8188eu/os_dep/usb_intf.c | 857 ++ - .../net/wireless/rtl8188eu/os_dep/usb_ops_linux.c | 283 + - drivers/net/wireless/rtl8188eu/os_dep/xmit_linux.c | 282 + - drivers/net/wireless/rtl8188eu/rtl_hostapd.conf | 78 + - 639 files changed, 310713 insertions(+), 2 deletions(-) - create mode 100644 drivers/net/wireless/rtl8188eu/.gitignore - create mode 100644 drivers/net/wireless/rtl8188eu/COPYING - create mode 100644 drivers/net/wireless/rtl8188eu/Kconfig - create mode 100644 drivers/net/wireless/rtl8188eu/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/README.md - create mode 100644 drivers/net/wireless/rtl8188eu/control_ap - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_ap.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_br_ext.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_cmd.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_debug.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_efuse.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_ieee80211.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_io.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_ioctl_set.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_iol.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_led.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_mlme.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_mlme_ext.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_mp.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_mp_ioctl.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_p2p.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_pwrctrl.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_recv.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_rf.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_security.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_sreset.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_sta_mgt.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_wlan_util.c - create mode 100644 drivers/net/wireless/rtl8188eu/core/rtw_xmit.c - create mode 100644 drivers/net/wireless/rtl8188eu/dkms.conf - create mode 100644 drivers/net/wireless/rtl8188eu/hal/Hal8188EPwrSeq.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/Hal8188ERateAdaptive.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_BB.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_MAC.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_RF.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/HalPhyRf.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/HalPhyRf_8188e.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/HalPwrSeqCmd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/hal_com.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/hal_intf.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/odm.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/odm_HWConfig.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/odm_RTL8188E.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/odm_RegConfig8188E.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/odm_debug.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/odm_interface.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_cmd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_dm.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_hal_init.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_mp.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_phycfg.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_rf6052.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_rxdesc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_sreset.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188e_xmit.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188eu_led.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188eu_recv.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/rtl8188eu_xmit.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/usb_halinit.c - create mode 100644 drivers/net/wireless/rtl8188eu/hal/usb_ops_linux.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/COPYING - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/README - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Android.mk - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ChangeLog - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README-WPS - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/defconfig - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_testing.txt - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.milenage_db - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.8 - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.accept - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.conf - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.deny - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.eap_user - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.radius_clients - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.sim_db - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.vlan - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.wpa_psk - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.1 - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/README - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd.conf - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/main.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/nt_password_hash.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/wired.conf - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/drv_callbacks.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_ht.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/peerkey_auth.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/utils.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ft.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/defs.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/eapol_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_defs.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/privsep_commands.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/version.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/.gitignore - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-cbc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-ctr.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-eax.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-encblock.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-dec.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-enc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-omac1.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-unwrap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-wrap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_wrap.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_cryptoapi.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_gnutls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-cipher.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-modexp.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-rsa.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_libtomcrypt.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_none.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_nss.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_openssl.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des-internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_cryptoapi.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_gnutls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_nss.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_openssl.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md4-internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-non-fips.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/rc4.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-pbkdf2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tlsprf.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tprf.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256-internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_gnutls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_none.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_nss.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_openssl.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_schannel.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/.gitignore - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Apple80211.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_atheros.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_broadcom.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_bsd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_iphone.m - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_madwifi.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis_.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_nl80211.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_none.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_osx.m - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_privsep.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_roboswitch.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtl.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtw.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_test.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wired.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mak - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mk - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/ndis_events.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/nl80211_copy.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/priv_netlink.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/wireless_copy.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_defs.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_tlv_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ttls.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_aka.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_config.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gpsk.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gtc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ikev2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_leap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_md5.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_mschapv2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_otp.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pax.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_peap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_psk.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pwd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sake.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sim.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tnc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ttls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_vendor_test.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_wsc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_methods.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_aka.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_fast.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gpsk.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gtc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_identity.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ikev2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_md5.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_methods.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_mschapv2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pax.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_peap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_psk.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pwd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sake.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sim.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tnc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ttls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_vendor_test.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_wsc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_tls_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_dump.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_freebsd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_linux.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_ndis.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_none.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_pcap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_privsep.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_winpcap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/lib.rules - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_build.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_dev_disc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_go_neg.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_group.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_invitation.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_parse.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_pd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_sd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_utils.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/.gitignore - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/tdls.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ft.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/.gitignore - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/libtommath.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_read.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_write.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_read.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_write.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/.gitignore - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/build_config.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_readline.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_simple.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_none.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_win.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/includes.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/list.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_internal.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_none.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_unix.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_win32.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap_iter.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/state_machine.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/Makefile - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/ndef.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/upnp_xml.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/upnp_xml.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_attr_build.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_attr_parse.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_attr_process.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_common.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_defs.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_dev_attr.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_dev_attr.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_enrollee.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_er.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_er.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_er_ssdp.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_nfc.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_nfc_pn531.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_registrar.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_ufd.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_upnp.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_upnp.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_upnp_ap.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_upnp_event.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_upnp_i.h - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_upnp_ssdp.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_upnp_web.c - create mode 100644 drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/wps_validate.c - create mode 100644 drivers/net/wireless/rtl8188eu/include/Hal8188EPhyCfg.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/Hal8188EPhyReg.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/Hal8188EPwrSeq.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/Hal8188ERateAdaptive.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/Hal8188EReg.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalHWImg8188E_BB.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalHWImg8188E_FW.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalHWImg8188E_MAC.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalHWImg8188E_RF.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalPhyRf.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalPhyRf_8188e.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalPwrSeqCmd.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/HalVerDef.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/autoconf.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/basic_types.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/cmd_osdep.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/drv_types.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/drv_types_linux.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/ethernet.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/h2clbk.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/hal_com.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/hal_intf.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/ieee80211.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/ieee80211_ext.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/if_ether.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/ioctl_cfg80211.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/ip.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/mlme_osdep.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/mp_custom_oid.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/nic_spec.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_HWConfig.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_RTL8188E.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_RegConfig8188E.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_RegDefine11AC.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_RegDefine11N.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_debug.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_interface.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_precomp.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_reg.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/odm_types.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/osdep_intf.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/osdep_service.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/recv_osdep.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_cmd.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_dm.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_hal.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_led.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_recv.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_rf.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_spec.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_sreset.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtl8188e_xmit.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_android.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_ap.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_br_ext.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_cmd.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_debug.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_eeprom.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_efuse.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_event.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_ht.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_io.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_ioctl.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_ioctl_rtl.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_ioctl_set.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_iol.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_led.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_mlme.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_mlme_ext.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_mp.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_mp_ioctl.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_mp_phy_regdef.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_p2p.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_pwrctrl.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_qos.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_recv.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_rf.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_security.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_sreset.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_version.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/rtw_xmit.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/sta_info.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/usb_hal.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/usb_ops.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/usb_ops_linux.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/usb_osintf.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/usb_vendor_req.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/wifi.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/wlan_bssdef.h - create mode 100644 drivers/net/wireless/rtl8188eu/include/xmit_osdep.h - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/ioctl_linux.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/mlme_linux.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/os_intfs.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/osdep_service.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/recv_linux.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/rtw_android.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/usb_intf.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/usb_ops_linux.c - create mode 100644 drivers/net/wireless/rtl8188eu/os_dep/xmit_linux.c - create mode 100644 drivers/net/wireless/rtl8188eu/rtl_hostapd.conf - -diff --git a/drivers/net/wireless/rtl8188eu/.gitignore b/drivers/net/wireless/rtl8188eu/.gitignore -new file mode 100644 -index 0000000000000..a916bfb75c40d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/.gitignore -@@ -0,0 +1,96 @@ -+# -+# NOTE! Don't add files that are generated in specific -+# subdirectories here. Add them in the ".gitignore" file -+# in that subdirectory instead. -+# -+# NOTE! Please use 'git ls-files -i --exclude-standard' -+# command after changing this file, to see if there are -+# any tracked files which get ignored after the change. -+# -+# Normal rules -+# -+.* -+*.o -+*.o.* -+*.a -+*.s -+*.ko -+*.so -+*.so.dbg -+*.mod.c -+*.i -+*.lst -+*.symtypes -+*.order -+modules.builtin -+*.elf -+*.bin -+*.gz -+*.bz2 -+*.lzma -+*.xz -+*.lzo -+*.patch -+*.gcno -+ -+# -+# Top-level generic files -+# -+/tags -+/TAGS -+/linux -+/vmlinux -+/vmlinuz -+/System.map -+/Module.markers -+/Module.symvers -+ -+# -+# Debian directory (make deb-pkg) -+# -+/debian/ -+ -+# -+# git files that we don't want to ignore even it they are dot-files -+# -+!.gitignore -+!.mailmap -+ -+# -+# Generated include files -+# -+include/config -+include/generated -+arch/*/include/generated -+ -+# stgit generated dirs -+patches-* -+ -+# quilt's files -+patches -+series -+ -+# cscope files -+cscope.* -+ncscope.* -+ -+# gnu global files -+GPATH -+GRTAGS -+GSYMS -+GTAGS -+ -+*.rej -+*.porig -+*.orig -+*~ -+\#*# -+ -+# -+# Leavings from module signing -+# -+extra_certificates -+signing_key.priv -+signing_key.x509 -+x509.genkey -+ -diff --git a/drivers/net/wireless/rtl8188eu/COPYING b/drivers/net/wireless/rtl8188eu/COPYING -new file mode 100644 -index 0000000000000..ca442d313d86d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/COPYING -@@ -0,0 +1,356 @@ -+ -+ NOTE! This copyright does *not* cover user programs that use kernel -+ services by normal system calls - this is merely considered normal use -+ of the kernel, and does *not* fall under the heading of "derived work". -+ Also note that the GPL below is copyrighted by the Free Software -+ Foundation, but the instance of code that it refers to (the Linux -+ kernel) is copyrighted by me and others who actually wrote it. -+ -+ Also note that the only valid version of the GPL as far as the kernel -+ is concerned is _this_ particular version of the license (ie v2, not -+ v2.2 or v3.x or whatever), unless explicitly otherwise stated. -+ -+ Linus Torvalds -+ -+---------------------------------------- -+ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 51 Franklin St, 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 Library 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 St, 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 Library General -+Public License instead of this License. -diff --git a/drivers/net/wireless/rtl8188eu/Kconfig b/drivers/net/wireless/rtl8188eu/Kconfig -new file mode 100644 -index 0000000000000..f91e2e10e4bbe ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/Kconfig -@@ -0,0 +1,5 @@ -+config RTL8188EU -+ tristate "Realtek 8188EU USB WiFi" -+ depends on USB -+ ---help--- -+ Help message of RTL8188EU -diff --git a/drivers/net/wireless/rtl8188eu/Makefile b/drivers/net/wireless/rtl8188eu/Makefile -new file mode 100644 -index 0000000000000..f3cc4ad018714 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/Makefile -@@ -0,0 +1,185 @@ -+SHELL := /bin/bash -+EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) -+EXTRA_CFLAGS += -O1 -+ -+EXTRA_CFLAGS += -Wno-unused-variable -+EXTRA_CFLAGS += -Wno-unused-value -+EXTRA_CFLAGS += -Wno-unused-label -+EXTRA_CFLAGS += -Wno-unused-parameter -+EXTRA_CFLAGS += -Wno-unused-function -+EXTRA_CFLAGS += -Wno-unused -+ -+EXTRA_CFLAGS += -Wno-uninitialized -+ -+EXTRA_CFLAGS += -I$(src)/include -+ -+ccflags-y += -D__CHECK_ENDIAN__ -+ -+CONFIG_AUTOCFG_CP = n -+ -+CONFIG_RTL8188EU = m -+ -+CONFIG_USB_HCI = y -+ -+CONFIG_BT_COEXIST = n -+CONFIG_WOWLAN = n -+ -+export TopDIR ?= $(shell pwd) -+ -+ -+OUTSRC_FILES := \ -+ hal/HalHWImg8188E_MAC.o \ -+ hal/HalHWImg8188E_BB.o \ -+ hal/HalHWImg8188E_RF.o \ -+ hal/HalPhyRf.o \ -+ hal/HalPhyRf_8188e.o \ -+ hal/HalPwrSeqCmd.o \ -+ hal/Hal8188EPwrSeq.o \ -+ hal/Hal8188ERateAdaptive.o\ -+ hal/hal_intf.o \ -+ hal/hal_com.o \ -+ hal/odm.o \ -+ hal/odm_debug.o \ -+ hal/odm_interface.o \ -+ hal/odm_HWConfig.o \ -+ hal/odm_RegConfig8188E.o\ -+ hal/odm_RTL8188E.o \ -+ hal/rtl8188e_cmd.o \ -+ hal/rtl8188e_dm.o \ -+ hal/rtl8188e_hal_init.o \ -+ hal/rtl8188e_mp.o \ -+ hal/rtl8188e_phycfg.o \ -+ hal/rtl8188e_rf6052.o \ -+ hal/rtl8188e_rxdesc.o \ -+ hal/rtl8188e_sreset.o \ -+ hal/rtl8188e_xmit.o \ -+ hal/rtl8188eu_led.o \ -+ hal/rtl8188eu_recv.o \ -+ hal/rtl8188eu_xmit.o \ -+ hal/usb_halinit.o \ -+ hal/usb_ops_linux.o -+ -+RTL871X = rtl8188e -+ -+HCI_NAME = usb -+ -+_OS_INTFS_FILES := \ -+ os_dep/ioctl_linux.o \ -+ os_dep/mlme_linux.o \ -+ os_dep/os_intfs.o \ -+ os_dep/osdep_service.o \ -+ os_dep/recv_linux.o \ -+ os_dep/rtw_android.o \ -+ os_dep/usb_intf.o \ -+ os_dep/usb_ops_linux.o \ -+ os_dep/xmit_linux.o -+ -+ -+ -+ -+_HAL_INTFS_FILES += $(OUTSRC_FILES) -+ -+ -+ifeq ($(CONFIG_AUTOCFG_CP), y) -+ -+$(shell cp $(TopDIR)/autoconf_rtl8188e_usb_linux.h $(TopDIR)/include/autoconf.h) -+endif -+ -+ifeq ($(CONFIG_BT_COEXIST), y) -+EXTRA_CFLAGS += -DCONFIG_BT_COEXIST -+endif -+ -+ifeq ($(CONFIG_WOWLAN), y) -+EXTRA_CFLAGS += -DCONFIG_WOWLAN -+endif -+ -+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ | sed -e s/ppc/powerpc/ | sed -e s/armv.l/arm/) -+ -+ARCH ?= $(SUBARCH) -+CROSS_COMPILE ?= -+KVER := $(shell uname -r) -+KSRC ?= /lib/modules/$(KVER)/build -+MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless -+INSTALL_PREFIX := -+ -+ifneq ($(KERNELRELEASE),) -+ -+rtk_core := \ -+ core/rtw_ap.o \ -+ core/rtw_br_ext.o \ -+ core/rtw_cmd.o \ -+ core/rtw_debug.o \ -+ core/rtw_efuse.o \ -+ core/rtw_ieee80211.o \ -+ core/rtw_io.o \ -+ core/rtw_ioctl_set.o \ -+ core/rtw_iol.o \ -+ core/rtw_led.o \ -+ core/rtw_mlme.o \ -+ core/rtw_mlme_ext.o \ -+ core/rtw_mp.o \ -+ core/rtw_mp_ioctl.o \ -+ core/rtw_pwrctrl.o \ -+ core/rtw_p2p.o \ -+ core/rtw_recv.o \ -+ core/rtw_rf.o \ -+ core/rtw_security.o \ -+ core/rtw_sreset.o \ -+ core/rtw_sta_mgt.o \ -+ core/rtw_wlan_util.o \ -+ core/rtw_xmit.o -+ -+8188eu-y += $(rtk_core) -+ -+8188eu-y += $(_HAL_INTFS_FILES) -+ -+8188eu-y += $(_OS_INTFS_FILES) -+ -+obj-$(CONFIG_RTL8188EU) := 8188eu.o -+ -+else -+ -+export CONFIG_RTL8188EU = m -+ -+obj-$(CONFIG_RTL8188EU) := 8188eu.o -+ -+endif -+ -+all: modules -+ -+modules: -+ $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) modules -+ -+strip: -+ $(CROSS_COMPILE)strip 8188eu.ko --strip-unneeded -+ -+install: -+ install -p -m 644 8188eu.ko $(MODDESTDIR) -+ @if [ -a /lib/modules/$(KVER)/kernel/drivers/staging/rtl8188eu/r8188eu.ko ] ; then modprobe -r r8188eu; fi; -+ @echo "blacklist r8188eu" > /etc/modprobe.d/50-8188eu.conf -+ cp rtl8188eufw.bin /lib/firmware/. -+ /sbin/depmod -a ${KVER} -+ mkdir -p /lib/firmware/rtlwifi -+ cp rtl8188eufw.bin /lib/firmware/rtlwifi/. -+ -+uninstall: -+ rm -f $(MODDESTDIR)/8188eu.ko -+ /sbin/depmod -a ${KVER} -+ @rm /etc/modprobe.d/50-8188eu.conf -+ -+config_r: -+ @echo "make config" -+ /bin/bash script/Configure script/config.in -+ -+.PHONY: modules clean clean_odm-8192c -+ -+clean_odm-8192c: -+ cd hal/OUTSRC/rtl8192c ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -+ -+clean: $(clean_more) -+ rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~ -+ rm -fr .tmp_versions -+ rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order -+ cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -+ cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -+ cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko -diff --git a/drivers/net/wireless/rtl8188eu/README.md b/drivers/net/wireless/rtl8188eu/README.md -new file mode 100644 -index 0000000000000..58fbc947affc3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/README.md -@@ -0,0 +1,36 @@ -+rtl8188eu -+========= -+ -+Repository for the stand-alone RTL8188EU driver. -+ -+Compiling & Building -+--------- -+### Dependencies -+To compile the driver, you need to have make and a compiler installed. In addition, -+you must have the kernel headers installed. If you do not understand what this means, -+consult your distro. -+### Compiling -+ -+> make all -+ -+### Installing -+ -+> sudo make install -+ -+DKMS -+--------- -+The module can also be installed with DKMS. Make sure to install the `dkms` package first. -+ -+ sudo dkms add ./rtl8188eu -+ sudo dkms build 8188eu/1.0 -+ sudo dkms install 8188eu/1.0 -+ -+Submitting Issues -+--------- -+ -+Frequently asked Questions -+--------- -+ -+### The network manager says: "Device is not ready"! -+Make sure you copied the firmware (rtl8188eufw.bin) to /lib/firmware/rtlwifi/ -+ -diff --git a/drivers/net/wireless/rtl8188eu/control_ap b/drivers/net/wireless/rtl8188eu/control_ap -new file mode 100644 -index 0000000000000..c7dbb9500b74a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/control_ap -@@ -0,0 +1,162 @@ -+#!/bin/sh -+# Script to start/stop a hostapd-based access point -+# -+# Sample start call "control_ap start wlan0 eth0" -+# Stop with "control_ap stop" -+# -+ -+case "$1" in -+start) -+ if [ $# -ne 3 ] -+ then -+ echo "Usage: $0 start AP_iface NET_iface" -+ exit 1 -+ fi -+;; -+stop) -+ if [ $# -ne 1 ] -+ then -+ echo "Usage: $0 stop" -+ exit 1 -+ fi -+;; -+*) -+ echo "Usage:" -+ echo "$0 start AP-iface net_iface" -+ echo "or" -+ echo "$0 stop" -+ exit 1 -+ ;; -+esac -+ -+# Symbols for needed programs -+ -+IPTABLES=/sbin/iptables -+IFCONFIG=/sbin/ifconfig -+DHCPD=/usr/sbin/dhcpd -+HOSTAPD=/home/finger/rtl8188eu/hostapd-0.8/hostapd/hostapd -+ -+# Symbols for AP and external interfaces -+ -+NET_AP=$2 -+NET_EXT=$3 -+ -+# First 3 octets of IP address for the AP -+ -+AP_ADDR=192.168.0 -+ -+# IP address for nameserver -+ -+NAME_SERVER=8.8.8.8 -+ -+# AP Channel, SSID, Encryption method, driver, and Encryption secret -+ -+AP_CHANNEL=11 -+AP_SSID=rtwap -+WPA_SECRET="87654321" -+ENCRYPT_MODE=2 -+DRIVER=rtl871xdrv -+ -+case "$1" in -+start) -+ echo "Starting AP mode for $NET_AP at address $AP_ADDR.1" -+ # Disable packet forwarding -+ echo 0 > /proc/sys/net/ipv4/ip_forward -+ # Stop any existing hostapd and dhcpd daemons -+ killall -q hostapd -+ killall -q dhcpd -+ #Set up forwarding -+ $IPTABLES -t nat -A POSTROUTING -o $NET_EXT -j MASQUERADE -+ $IPTABLES -A FORWARD -i $NET_EXT -o $NET_AP -m state \ -+ --state RELATED,ESTABLISHED -j ACCEPT -+ $IPTABLES -A FORWARD -i $NET_AP -o $NET_EXT -j ACCEPT -+ # Get the AP interface in the right state -+ $IFCONFIG $NET_AP down -+ $IFCONFIG $NET_AP up -+ $IFCONFIG $NET_AP $AP_ADDR.1 -+ # dhcpd needs to have a leases file available - create it if needed -+ if [ ! -f /var/lib/dhcp/db/dhcpd.leases ]; then -+ mkdir -p /var/lib/dhcp/db -+ touch /var/lib/dhcp/db/dhcpd.leases -+ fi -+ # Write the DHCP server configuration file -+ echo "option domain-name-servers $NAME_SERVER;" > ~/dhcpd.conf -+ echo "default-lease-time 600;" >> ~/dhcpd.conf -+ echo "max-lease-time 7200;" >> ~/dhcpd.conf -+ echo "ddns-update-style none; ddns-updates off;" >> ~/dhcpd.conf -+ echo "subnet $AP_ADDR.0 netmask 255.255.255.0 {" >> ~/dhcpd.conf -+ echo " range $AP_ADDR.200 $AP_ADDR.229;" >> ~/dhcpd.conf -+ echo " option subnet-mask 255.255.255.0;" >> ~/dhcpd.conf -+ echo " option broadcast-address $AP_ADDR.255;" >> ~/dhcpd.conf -+ echo " option routers $AP_ADDR.1;" >> ~/dhcpd.conf -+ echo "}" >> ~/dhcpd.conf -+ # Bring up the DHCP server -+ $DHCPD -cf ~/dhcpd.conf $NET_AP -+ # Write the hostapd configuration file -+ cat > ~/hostapd.conf << EOF -+auth_algs=1 -+beacon_int=100 -+country_code=US -+ctrl_interface_group=0 -+ctrl_interface=/var/run/hostapd -+dtim_period=2 -+dump_file=/tmp/hostapd.dump -+fragm_threshold=2346 -+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40][MAX-AMSDU-7935][DSSS_CCK-40] -+#ieee80211d=1 -+ieee80211n=1 -+ignore_broadcast_ssid=0 -+logger_stdout=-1 -+logger_stdout_level=2 -+logger_syslog=-1 -+logger_syslog_level=2 -+macaddr_acl=0 -+max_num_sta=255 -+rts_threshold=2347 -+wmm_ac_be_acm=0 -+wmm_ac_be_aifs=3 -+wmm_ac_be_cwmax=10 -+wmm_ac_be_cwmin=4 -+wmm_ac_be_txop_limit=0 -+wmm_ac_bk_acm=0 -+wmm_ac_bk_aifs=7 -+wmm_ac_bk_cwmax=10 -+wmm_ac_bk_cwmin=4 -+wmm_ac_bk_txop_limit=0 -+wmm_ac_vi_acm=0 -+wmm_ac_vi_aifs=2 -+wmm_ac_vi_cwmax=4 -+wmm_ac_vi_cwmin=3 -+wmm_ac_vi_txop_limit=94 -+wmm_ac_vo_acm=0 -+wmm_ac_vo_aifs=2 -+wmm_ac_vo_cwmax=3 -+wmm_ac_vo_cwmin=2 -+wmm_ac_vo_txop_limit=47 -+wmm_enabled=1 -+EOF -+ echo "interface=$NET_AP" >> ~/hostapd.conf -+ echo "ssid=$AP_SSID" >> ~/hostapd.conf -+ echo "driver=$DRIVER" >> ~/hostapd.conf -+ echo "hw_mode=g" >> ~/hostapd.conf -+ echo "channel=$AP_CHANNEL" >> ~/hostapd.conf -+ echo "wpa=$ENCRYPT_MODE" >> ~/hostapd.conf -+ echo "wpa_key_mgmt=WPA-PSK" >> ~/hostapd.conf -+ echo "wpa_pairwise=TKIP CCMP" >> ~/hostapd.conf -+ echo "rsn_pairwise=CCMP" >> ~/hostapd.conf -+ echo "wpa_passphrase=$WPA_SECRET" >> ~/hostapd.conf -+ # Enable packet forwarding -+ echo 1 > /proc/sys/net/ipv4/ip_forward -+ # Bring up hostapd -+ $HOSTAPD -dd -B ~/hostapd.conf -+ ;; -+stop) -+ echo "Stopping AP mode" -+ # Stop hostapd and dhcpd daemons -+ killall hostapd -+ killall dhcpd -+ rm -f ~/hostapd.conf -+ rm -f ~/dhcpd.conf -+ ;; -+esac -+ -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_ap.c b/drivers/net/wireless/rtl8188eu/core/rtw_ap.c -new file mode 100644 -index 0000000000000..ba475a4933ec0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_ap.c -@@ -0,0 +1,1976 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_AP_C_ -+ -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_88EU_AP_MODE -+ -+void init_mlme_ap_info(struct adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+ -+ spin_lock_init(&pmlmepriv->bcn_update_lock); -+ -+ /* for ACL */ -+ _rtw_init_queue(&pacl_list->acl_node_q); -+ -+ start_ap_mode(padapter); -+} -+ -+void free_mlme_ap_info(struct adapter *padapter) -+{ -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ pmlmepriv->update_bcn = false; -+ pmlmeext->bstart_bss = false; -+ -+ rtw_sta_flush(padapter); -+ -+ pmlmeinfo->state = _HW_STATE_NOLINK_; -+ -+ /* free_assoc_sta_resources */ -+ rtw_free_all_stainfo(padapter); -+ -+ /* free bc/mc sta_info */ -+ psta = rtw_get_bcmc_stainfo(padapter); -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ rtw_free_stainfo(padapter, psta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+} -+ -+static void update_BCNTIM(struct adapter *padapter) -+{ -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network); -+ unsigned char *pie = pnetwork_mlmeext->IEs; -+ -+ /* update TIM IE */ -+ if (true) { -+ u8 *p, *dst_ie, *premainder_ie = NULL; -+ u8 *pbackup_remainder_ie = NULL; -+ __le16 tim_bitmap_le; -+ uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen; -+ -+ tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); -+ -+ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); -+ if (p != NULL && tim_ielen > 0) { -+ tim_ielen += 2; -+ premainder_ie = p+tim_ielen; -+ tim_ie_offset = (int)(p - pie); -+ remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen; -+ /* append TIM IE from dst_ie offset */ -+ dst_ie = p; -+ } else { -+ tim_ielen = 0; -+ -+ /* calculate head_len */ -+ offset = _FIXED_IE_LENGTH_; -+ offset += pnetwork_mlmeext->Ssid.SsidLength + 2; -+ -+ /* get supported rates len */ -+ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); -+ if (p != NULL) -+ offset += tmp_len+2; -+ -+ /* DS Parameter Set IE, len = 3 */ -+ offset += 3; -+ -+ premainder_ie = pie + offset; -+ -+ remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen; -+ -+ /* append TIM IE from offset */ -+ dst_ie = pie + offset; -+ } -+ -+ if (remainder_ielen > 0) { -+ pbackup_remainder_ie = rtw_malloc(remainder_ielen); -+ if (pbackup_remainder_ie && premainder_ie) -+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); -+ } -+ *dst_ie++ = _TIM_IE_; -+ -+ if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc)) -+ tim_ielen = 5; -+ else -+ tim_ielen = 4; -+ -+ *dst_ie++ = tim_ielen; -+ -+ *dst_ie++ = 0;/* DTIM count */ -+ *dst_ie++ = 1;/* DTIM period */ -+ -+ if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */ -+ *dst_ie++ = BIT(0);/* bitmap ctrl */ -+ else -+ *dst_ie++ = 0; -+ -+ if (tim_ielen == 4) { -+ *dst_ie++ = *(u8 *)&tim_bitmap_le; -+ } else if (tim_ielen == 5) { -+ memcpy(dst_ie, &tim_bitmap_le, 2); -+ dst_ie += 2; -+ } -+ -+ /* copy remainder IE */ -+ if (pbackup_remainder_ie) { -+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); -+ -+ kfree(pbackup_remainder_ie); -+ } -+ offset = (uint)(dst_ie - pie); -+ pnetwork_mlmeext->IELength = offset + remainder_ielen; -+ } -+ -+ set_tx_beacon_cmd(padapter); -+} -+ -+void rtw_add_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index, u8 *data, u8 len) -+{ -+ struct ndis_802_11_var_ie *pIE; -+ u8 bmatch = false; -+ u8 *pie = pnetwork->IEs; -+ u8 *p = NULL, *dst_ie = NULL, *premainder_ie = NULL; -+ u8 *pbackup_remainder_ie = NULL; -+ u32 i, offset, ielen = 0, ie_offset, remainder_ielen = 0; -+ -+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) { -+ pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i); -+ -+ if (pIE->ElementID > index) { -+ break; -+ } else if (pIE->ElementID == index) { /* already exist the same IE */ -+ p = (u8 *)pIE; -+ ielen = pIE->Length; -+ bmatch = true; -+ break; -+ } -+ p = (u8 *)pIE; -+ ielen = pIE->Length; -+ i += (pIE->Length + 2); -+ } -+ -+ if (p != NULL && ielen > 0) { -+ ielen += 2; -+ -+ premainder_ie = p+ielen; -+ -+ ie_offset = (int)(p - pie); -+ -+ remainder_ielen = pnetwork->IELength - ie_offset - ielen; -+ -+ if (bmatch) -+ dst_ie = p; -+ else -+ dst_ie = (p+ielen); -+ } -+ -+ if (remainder_ielen > 0) { -+ pbackup_remainder_ie = rtw_malloc(remainder_ielen); -+ if (pbackup_remainder_ie && premainder_ie) -+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); -+ } -+ -+ *dst_ie++ = index; -+ *dst_ie++ = len; -+ -+ memcpy(dst_ie, data, len); -+ dst_ie += len; -+ -+ /* copy remainder IE */ -+ if (pbackup_remainder_ie) { -+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); -+ -+ kfree(pbackup_remainder_ie); -+ } -+ -+ offset = (uint)(dst_ie - pie); -+ pnetwork->IELength = offset + remainder_ielen; -+} -+ -+void rtw_remove_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index) -+{ -+ u8 *p, *dst_ie = NULL, *premainder_ie = NULL; -+ u8 *pbackup_remainder_ie = NULL; -+ uint offset, ielen, ie_offset, remainder_ielen = 0; -+ u8 *pie = pnetwork->IEs; -+ -+ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen, -+ pnetwork->IELength - _FIXED_IE_LENGTH_); -+ if (p != NULL && ielen > 0) { -+ ielen += 2; -+ -+ premainder_ie = p+ielen; -+ -+ ie_offset = (int)(p - pie); -+ -+ remainder_ielen = pnetwork->IELength - ie_offset - ielen; -+ -+ dst_ie = p; -+ } -+ -+ if (remainder_ielen > 0) { -+ pbackup_remainder_ie = rtw_malloc(remainder_ielen); -+ if (pbackup_remainder_ie && premainder_ie) -+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); -+ } -+ -+ /* copy remainder IE */ -+ if (pbackup_remainder_ie) { -+ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); -+ -+ kfree(pbackup_remainder_ie); -+ } -+ -+ offset = (uint)(dst_ie - pie); -+ pnetwork->IELength = offset + remainder_ielen; -+} -+ -+static u8 chk_sta_is_alive(struct sta_info *psta) -+{ -+ u8 ret = false; -+ -+ if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) == -+ (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts)) -+ ; -+ else -+ ret = true; -+ -+ sta_update_last_rx_pkts(psta); -+ -+ return ret; -+} -+ -+void expire_timeout_chk(struct adapter *padapter) -+{ -+ struct list_head *phead, *plist; -+ u8 updated = 0; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 chk_alive_num = 0; -+ char chk_alive_list[NUM_STA]; -+ int i; -+ -+ spin_lock_bh(&pstapriv->auth_list_lock); -+ -+ phead = &pstapriv->auth_list; -+ plist = phead->next; -+ -+ /* check auth_queue */ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, auth_list); -+ plist = plist->next; -+ -+ if (psta->expire_to > 0) { -+ psta->expire_to--; -+ if (psta->expire_to == 0) { -+ list_del_init(&psta->auth_list); -+ pstapriv->auth_list_cnt--; -+ -+ DBG_88E("auth expire %6ph\n", -+ psta->hwaddr); -+ -+ spin_unlock_bh(&pstapriv->auth_list_lock); -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ rtw_free_stainfo(padapter, psta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+ spin_lock_bh(&pstapriv->auth_list_lock); -+ } -+ } -+ -+ } -+ spin_unlock_bh(&pstapriv->auth_list_lock); -+ -+ psta = NULL; -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ -+ phead = &pstapriv->asoc_list; -+ plist = phead->next; -+ -+ /* check asoc_queue */ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, asoc_list); -+ plist = plist->next; -+ -+ if (chk_sta_is_alive(psta) || !psta->expire_to) { -+ psta->expire_to = pstapriv->expire_to; -+ psta->keep_alive_trycnt = 0; -+ psta->under_exist_checking = 0; -+ } else { -+ psta->expire_to--; -+ } -+ -+ if (psta->expire_to <= 0) { -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ -+ if (padapter->registrypriv.wifi_spec == 1) { -+ psta->expire_to = pstapriv->expire_to; -+ continue; -+ } -+ -+ if (psta->state & WIFI_SLEEP_STATE) { -+ if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { -+ /* to check if alive by another methods if station is at ps mode. */ -+ psta->expire_to = pstapriv->expire_to; -+ psta->state |= WIFI_STA_ALIVE_CHK_STATE; -+ -+ /* to update bcn with tim_bitmap for this station */ -+ pstapriv->tim_bitmap |= BIT(psta->aid); -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+ -+ if (!pmlmeext->active_keep_alive_check) -+ continue; -+ } -+ } -+ if (pmlmeext->active_keep_alive_check) { -+ int stainfo_offset; -+ -+ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); -+ if (stainfo_offset_valid(stainfo_offset)) -+ chk_alive_list[chk_alive_num++] = stainfo_offset; -+ continue; -+ } -+ -+ list_del_init(&psta->asoc_list); -+ pstapriv->asoc_list_cnt--; -+ -+ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state); -+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); -+ } else { -+ /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */ -+ if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt) && -+ padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME/pstapriv->asoc_list_cnt/2)) { -+ DBG_88E("%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__, -+ (psta->hwaddr), psta->sleepq_len, -+ padapter->xmitpriv.free_xmitframe_cnt, -+ pstapriv->asoc_list_cnt); -+ wakeup_sta_to_xmit(padapter, psta); -+ } -+ } -+ } -+ -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ if (chk_alive_num) { -+ u8 backup_oper_channel = 0; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ /* switch to correct channel of current network before issue keep-alive frames */ -+ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { -+ backup_oper_channel = rtw_get_oper_ch(padapter); -+ SelectChannel(padapter, pmlmeext->cur_channel); -+ } -+ -+ /* issue null data to check sta alive*/ -+ for (i = 0; i < chk_alive_num; i++) { -+ int ret = _FAIL; -+ -+ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); -+ -+ if (psta->state & WIFI_SLEEP_STATE) -+ ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50); -+ else -+ ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50); -+ -+ psta->keep_alive_trycnt++; -+ if (ret == _SUCCESS) { -+ DBG_88E("asoc check, sta(%pM) is alive\n", (psta->hwaddr)); -+ psta->expire_to = pstapriv->expire_to; -+ psta->keep_alive_trycnt = 0; -+ continue; -+ } else if (psta->keep_alive_trycnt <= 3) { -+ DBG_88E("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt); -+ psta->expire_to = 1; -+ continue; -+ } -+ -+ psta->keep_alive_trycnt = 0; -+ -+ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state); -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ list_del_init(&psta->asoc_list); -+ pstapriv->asoc_list_cnt--; -+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ } -+ -+ if (backup_oper_channel > 0) /* back to the original operation channel */ -+ SelectChannel(padapter, backup_oper_channel); -+ } -+ -+ associated_clients_update(padapter, updated); -+} -+ -+void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level) -+{ -+ int i; -+ u8 rf_type; -+ u32 init_rate = 0; -+ unsigned char sta_band = 0, raid, shortGIrate = false; -+ unsigned char limit; -+ unsigned int tx_ra_bitmap = 0; -+ struct ht_priv *psta_ht = NULL; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; -+ -+ if (psta) -+ psta_ht = &psta->htpriv; -+ else -+ return; -+ -+ if (!(psta->state & _FW_LINKED)) -+ return; -+ -+ /* b/g mode ra_bitmap */ -+ for (i = 0; i < sizeof(psta->bssrateset); i++) { -+ if (psta->bssrateset[i]) -+ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f); -+ } -+ /* n mode ra_bitmap */ -+ if (psta_ht->ht_option) { -+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ if (rf_type == RF_2T2R) -+ limit = 16;/* 2R */ -+ else -+ limit = 8;/* 1R */ -+ -+ for (i = 0; i < limit; i++) { -+ if (psta_ht->ht_cap.mcs.rx_mask[i/8] & BIT(i%8)) -+ tx_ra_bitmap |= BIT(i+12); -+ } -+ -+ /* max short GI rate */ -+ shortGIrate = psta_ht->sgi; -+ } -+ -+ if (pcur_network->Configuration.DSConfig > 14) { -+ /* 5G band */ -+ if (tx_ra_bitmap & 0xffff000) -+ sta_band |= WIRELESS_11_5N | WIRELESS_11A; -+ else -+ sta_band |= WIRELESS_11A; -+ } else { -+ if (tx_ra_bitmap & 0xffff000) -+ sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B; -+ else if (tx_ra_bitmap & 0xff0) -+ sta_band |= WIRELESS_11G | WIRELESS_11B; -+ else -+ sta_band |= WIRELESS_11B; -+ } -+ -+ psta->wireless_mode = sta_band; -+ -+ raid = networktype_to_raid(sta_band); -+ init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f; -+ -+ if (psta->aid < NUM_STA) { -+ u8 arg = 0; -+ -+ arg = psta->mac_id&0x1f; -+ -+ arg |= BIT(7);/* support entry 2~31 */ -+ -+ if (shortGIrate) -+ arg |= BIT(5); -+ -+ tx_ra_bitmap |= ((raid<<28)&0xf0000000); -+ -+ DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n", -+ __func__ , psta->mac_id, raid , tx_ra_bitmap, arg); -+ -+ /* bitmap[0:27] = tx_rate_bitmap */ -+ /* bitmap[28:31]= Rate Adaptive id */ -+ /* arg[0:4] = macid */ -+ /* arg[5] = Short GI */ -+ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level); -+ -+ if (shortGIrate) -+ init_rate |= BIT(6); -+ -+ /* set ra_id, init_rate */ -+ psta->raid = raid; -+ psta->init_rate = init_rate; -+ -+ } else { -+ DBG_88E("station aid %d exceed the max number\n", psta->aid); -+ } -+} -+ -+void update_bmc_sta(struct adapter *padapter) -+{ -+ u32 init_rate = 0; -+ unsigned char network_type, raid; -+ int i, supportRateNum = 0; -+ unsigned int tx_ra_bitmap = 0; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; -+ struct sta_info *psta = rtw_get_bcmc_stainfo(padapter); -+ -+ if (psta) { -+ psta->aid = 0;/* default set to 0 */ -+ psta->mac_id = psta->aid + 1; -+ -+ psta->qos_option = 0; -+ psta->htpriv.ht_option = false; -+ -+ psta->ieee8021x_blocked = 0; -+ -+ memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); -+ -+ /* prepare for add_RATid */ -+ supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates); -+ network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, 1); -+ -+ memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum); -+ psta->bssratelen = supportRateNum; -+ -+ /* b/g mode ra_bitmap */ -+ for (i = 0; i < supportRateNum; i++) { -+ if (psta->bssrateset[i]) -+ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f); -+ } -+ -+ if (pcur_network->Configuration.DSConfig > 14) { -+ /* force to A mode. 5G doesn't support CCK rates */ -+ network_type = WIRELESS_11A; -+ tx_ra_bitmap = 0x150; /* 6, 12, 24 Mbps */ -+ } else { -+ /* force to b mode */ -+ network_type = WIRELESS_11B; -+ tx_ra_bitmap = 0xf; -+ } -+ -+ raid = networktype_to_raid(network_type); -+ init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f; -+ -+ /* ap mode */ -+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); -+ -+ { -+ u8 arg = 0; -+ -+ arg = psta->mac_id&0x1f; -+ arg |= BIT(7); -+ tx_ra_bitmap |= ((raid<<28)&0xf0000000); -+ DBG_88E("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg); -+ -+ /* bitmap[0:27] = tx_rate_bitmap */ -+ /* bitmap[28:31]= Rate Adaptive id */ -+ /* arg[0:4] = macid */ -+ /* arg[5] = Short GI */ -+ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0); -+ } -+ /* set ra_id, init_rate */ -+ psta->raid = raid; -+ psta->init_rate = init_rate; -+ -+ rtw_sta_media_status_rpt(padapter, psta, 1); -+ -+ spin_lock_bh(&psta->lock); -+ psta->state = _FW_LINKED; -+ spin_unlock_bh(&psta->lock); -+ -+ } else { -+ DBG_88E("add_RATid_bmc_sta error!\n"); -+ } -+} -+ -+/* notes: */ -+/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */ -+/* MAC_ID = AID+1 for sta in ap/adhoc mode */ -+/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */ -+/* MAC_ID = 0 for bssid for sta/ap/adhoc */ -+/* CAM_ID = 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */ -+ -+void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; -+ struct ht_priv *phtpriv_sta = &psta->htpriv; -+ u16 sta_cap_info; -+ u16 ap_cap_info; -+ -+ psta->mac_id = psta->aid+1; -+ DBG_88E("%s\n", __func__); -+ -+ /* ap mode */ -+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); -+ -+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) -+ psta->ieee8021x_blocked = true; -+ else -+ psta->ieee8021x_blocked = false; -+ -+ /* update sta's cap */ -+ -+ /* ERP */ -+ VCS_update(padapter, psta); -+ /* HT related cap */ -+ if (phtpriv_sta->ht_option) { -+ /* check if sta supports rx ampdu */ -+ phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable; -+ sta_cap_info = le16_to_cpu(phtpriv_sta->ht_cap.cap_info); -+ ap_cap_info = le16_to_cpu(phtpriv_ap->ht_cap.cap_info); -+ -+ /* check if sta support s Short GI */ -+ if ((sta_cap_info & ap_cap_info) & -+ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) -+ phtpriv_sta->sgi = true; -+ -+ /* bwmode */ -+ if ((sta_cap_info & ap_cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) { -+ phtpriv_sta->bwmode = pmlmeext->cur_bwmode; -+ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; -+ } -+ psta->qos_option = true; -+ } else { -+ phtpriv_sta->ampdu_enable = false; -+ phtpriv_sta->sgi = false; -+ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; -+ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ } -+ -+ /* Rx AMPDU */ -+ send_delba(padapter, 0, psta->hwaddr);/* recipient */ -+ -+ /* TX AMPDU */ -+ send_delba(padapter, 1, psta->hwaddr);/* originator */ -+ phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */ -+ phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */ -+ -+ /* todo: init other variables */ -+ -+ memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); -+ -+ spin_lock_bh(&psta->lock); -+ psta->state |= _FW_LINKED; -+ spin_unlock_bh(&psta->lock); -+} -+ -+static void update_hw_ht_param(struct adapter *padapter) -+{ -+ unsigned char max_AMPDU_len; -+ unsigned char min_MPDU_spacing; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ DBG_88E("%s\n", __func__); -+ -+ /* handle A-MPDU parameter field */ -+ /* -+ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k -+ AMPDU_para [4:2]:Min MPDU Start Spacing -+ */ -+ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; -+ -+ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); -+ -+ /* */ -+ /* Config SM Power Save setting */ -+ /* */ -+ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2; -+ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) -+ DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); -+} -+ -+static void start_bss_network(struct adapter *padapter, u8 *pbuf) -+{ -+ u8 *p; -+ u8 val8, cur_channel, cur_bwmode, cur_ch_offset; -+ u16 bcn_interval; -+ u32 acparm; -+ int ie_len; -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct security_priv *psecuritypriv = &(padapter->securitypriv); -+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network); -+ struct HT_info_element *pht_info = NULL; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+ bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; -+ cur_channel = pnetwork->Configuration.DSConfig; -+ cur_bwmode = HT_CHANNEL_WIDTH_20; -+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ -+ /* check if there is wps ie, */ -+ /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */ -+ /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */ -+ if (!rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL)) -+ pmlmeext->bstart_bss = true; -+ -+ /* todo: update wmm, ht cap */ -+ if (pmlmepriv->qospriv.qos_option) -+ pmlmeinfo->WMM_enable = true; -+ if (pmlmepriv->htpriv.ht_option) { -+ pmlmeinfo->WMM_enable = true; -+ pmlmeinfo->HT_enable = true; -+ -+ update_hw_ht_param(padapter); -+ } -+ -+ if (pmlmepriv->cur_network.join_res != true) { /* setting only at first time */ -+ /* WEP Key will be set before this function, do not clear CAM. */ -+ if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && -+ (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)) -+ flush_all_cam_entry(padapter); /* clear CAM */ -+ } -+ -+ /* set MSR to AP_Mode */ -+ Set_MSR(padapter, _HW_STATE_AP_); -+ -+ /* Set BSSID REG */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress); -+ -+ /* Set EDCA param reg */ -+ acparm = 0x002F3217; /* VO */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); -+ acparm = 0x005E4317; /* VI */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); -+ acparm = 0x005ea42b; -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); -+ acparm = 0x0000A444; /* BK */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); -+ -+ /* Set Security */ -+ val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; -+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); -+ -+ /* Beacon Control related register */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval)); -+ -+ UpdateBrateTbl(padapter, pnetwork->SupportedRates); -+ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); -+ -+ if (!pmlmepriv->cur_network.join_res) { /* setting only at first time */ -+ /* turn on all dynamic functions */ -+ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); -+ } -+ /* set channel, bwmode */ -+ p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(struct ndis_802_11_fixed_ie))); -+ if (p && ie_len) { -+ pht_info = (struct HT_info_element *)(p+2); -+ -+ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) { -+ /* switch to the 40M Hz mode */ -+ cur_bwmode = HT_CHANNEL_WIDTH_40; -+ switch (pht_info->infos[0] & 0x3) { -+ case 1: -+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; -+ break; -+ case 3: -+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; -+ break; -+ default: -+ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ break; -+ } -+ } -+ } -+ /* TODO: need to judge the phy parameters on concurrent mode for single phy */ -+ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); -+ -+ DBG_88E("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, cur_ch_offset); -+ -+ /* */ -+ pmlmeext->cur_channel = cur_channel; -+ pmlmeext->cur_bwmode = cur_bwmode; -+ pmlmeext->cur_ch_offset = cur_ch_offset; -+ pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type; -+ -+ /* update cur_wireless_mode */ -+ update_wireless_mode(padapter); -+ -+ /* udpate capability after cur_wireless_mode updated */ -+ update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork)); -+ -+ /* let pnetwork_mlmeext == pnetwork_mlme. */ -+ memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length); -+ -+#ifdef CONFIG_88EU_P2P -+ memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.Ssid, pnetwork->Ssid.SsidLength); -+ pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.SsidLength; -+#endif /* CONFIG_88EU_P2P */ -+ -+ if (pmlmeext->bstart_bss) { -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+ -+ /* issue beacon frame */ -+ if (send_beacon(padapter) == _FAIL) -+ DBG_88E("issue_beacon, fail!\n"); -+ } -+ -+ /* update bc/mc sta_info */ -+ update_bmc_sta(padapter); -+} -+ -+int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) -+{ -+ int ret = _SUCCESS; -+ u8 *p; -+ u8 *pHT_caps_ie = NULL; -+ u8 *pHT_info_ie = NULL; -+ struct sta_info *psta = NULL; -+ u16 cap, ht_cap = false; -+ uint ie_len = 0; -+ int group_cipher, pairwise_cipher; -+ u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; -+ int supportRateNum = 0; -+ u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01}; -+ u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; -+ u8 *ie = pbss_network->IEs; -+ -+ /* SSID */ -+ /* Supported rates */ -+ /* DS Params */ -+ /* WLAN_EID_COUNTRY */ -+ /* ERP Information element */ -+ /* Extended supported rates */ -+ /* WPA/WPA2 */ -+ /* Wi-Fi Wireless Multimedia Extensions */ -+ /* ht_capab, ht_oper */ -+ /* WPS IE */ -+ -+ DBG_88E("%s, len =%d\n", __func__, len); -+ -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) -+ return _FAIL; -+ -+ if (len > MAX_IE_SZ) -+ return _FAIL; -+ -+ pbss_network->IELength = len; -+ -+ memset(ie, 0, MAX_IE_SZ); -+ -+ memcpy(ie, pbuf, pbss_network->IELength); -+ -+ if (pbss_network->InfrastructureMode != Ndis802_11APMode) -+ return _FAIL; -+ -+ pbss_network->Rssi = 0; -+ -+ memcpy(pbss_network->MacAddress, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ -+ /* beacon interval */ -+ p = rtw_get_beacon_interval_from_ie(ie);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ -+ pbss_network->Configuration.BeaconPeriod = get_unaligned_le16(p); -+ -+ /* capability */ -+ cap = get_unaligned_le16(ie); -+ -+ /* SSID */ -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) { -+ memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); -+ memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len); -+ pbss_network->Ssid.SsidLength = ie_len; -+ } -+ -+ /* channel */ -+ channel = 0; -+ pbss_network->Configuration.Length = 0; -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) -+ channel = *(p + 2); -+ -+ pbss_network->Configuration.DSConfig = channel; -+ -+ memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX); -+ /* get supported rates */ -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); -+ if (p != NULL) { -+ memcpy(supportRate, p+2, ie_len); -+ supportRateNum = ie_len; -+ } -+ -+ /* get ext_supported rates */ -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_); -+ if (p != NULL) { -+ memcpy(supportRate+supportRateNum, p+2, ie_len); -+ supportRateNum += ie_len; -+ } -+ -+ network_type = rtw_check_network_type(supportRate, supportRateNum, channel); -+ -+ rtw_set_supported_rate(pbss_network->SupportedRates, network_type); -+ -+ /* parsing ERP_IE */ -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) -+ ERP_IE_handler(padapter, (struct ndis_802_11_var_ie *)p); -+ -+ /* update privacy/security */ -+ if (cap & BIT(4)) -+ pbss_network->Privacy = 1; -+ else -+ pbss_network->Privacy = 0; -+ -+ psecuritypriv->wpa_psk = 0; -+ -+ /* wpa2 */ -+ group_cipher = 0; -+ pairwise_cipher = 0; -+ psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; -+ psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) { -+ if (rtw_parse_wpa2_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { -+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; -+ -+ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ -+ psecuritypriv->wpa_psk |= BIT(1); -+ -+ psecuritypriv->wpa2_group_cipher = group_cipher; -+ psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher; -+ } -+ } -+ /* wpa */ -+ ie_len = 0; -+ group_cipher = 0; -+ pairwise_cipher = 0; -+ psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; -+ psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; -+ for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) { -+ p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, -+ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); -+ if ((p) && (!memcmp(p+2, OUI1, 4))) { -+ if (rtw_parse_wpa_ie(p, ie_len+2, &group_cipher, -+ &pairwise_cipher, NULL) == _SUCCESS) { -+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; -+ -+ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ -+ -+ psecuritypriv->wpa_psk |= BIT(0); -+ -+ psecuritypriv->wpa_group_cipher = group_cipher; -+ psecuritypriv->wpa_pairwise_cipher = pairwise_cipher; -+ } -+ break; -+ } -+ if ((p == NULL) || (ie_len == 0)) -+ break; -+ } -+ -+ /* wmm */ -+ ie_len = 0; -+ pmlmepriv->qospriv.qos_option = 0; -+ if (pregistrypriv->wmm_enable) { -+ for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) { -+ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, -+ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); -+ if ((p) && !memcmp(p+2, WMM_PARA_IE, 6)) { -+ pmlmepriv->qospriv.qos_option = 1; -+ -+ *(p+8) |= BIT(7);/* QoS Info, support U-APSD */ -+ -+ /* disable all ACM bits since the WMM admission control is not supported */ -+ *(p + 10) &= ~BIT(4); /* BE */ -+ *(p + 14) &= ~BIT(4); /* BK */ -+ *(p + 18) &= ~BIT(4); /* VI */ -+ *(p + 22) &= ~BIT(4); /* VO */ -+ break; -+ } -+ -+ if ((p == NULL) || (ie_len == 0)) -+ break; -+ } -+ } -+ /* parsing HT_CAP_IE */ -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, -+ (pbss_network->IELength - _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) { -+ u8 rf_type; -+ struct ieee80211_ht_cap *pht_cap = (struct ieee80211_ht_cap *)(p+2); -+ -+ pHT_caps_ie = p; -+ ht_cap = true; -+ network_type |= WIRELESS_11_24N; -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ -+ if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || -+ (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) -+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2)); -+ else -+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); -+ -+ /* set Max Rx AMPDU size to 64K */ -+ pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & 0x03); -+ -+ if(rf_type == RF_1T1R) { -+ pht_cap->mcs.rx_mask[0] = 0xff; -+ pht_cap->mcs.rx_mask[1] = 0x0; -+ } -+ memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len); -+ } -+ -+ /* parsing HT_INFO_IE */ -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, -+ (pbss_network->IELength - _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) -+ pHT_info_ie = p; -+ switch (network_type) { -+ case WIRELESS_11B: -+ pbss_network->NetworkTypeInUse = Ndis802_11DS; -+ break; -+ case WIRELESS_11G: -+ case WIRELESS_11BG: -+ case WIRELESS_11G_24N: -+ case WIRELESS_11BG_24N: -+ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; -+ break; -+ case WIRELESS_11A: -+ pbss_network->NetworkTypeInUse = Ndis802_11OFDM5; -+ break; -+ default: -+ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; -+ break; -+ } -+ -+ pmlmepriv->cur_network.network_type = network_type; -+ -+ pmlmepriv->htpriv.ht_option = false; -+ -+ if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) || -+ (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) { -+ /* todo: */ -+ /* ht_cap = false; */ -+ } -+ -+ /* ht_cap */ -+ if (pregistrypriv->ht_enable && ht_cap) { -+ pmlmepriv->htpriv.ht_option = true; -+ pmlmepriv->qospriv.qos_option = 1; -+ -+ if (pregistrypriv->ampdu_enable == 1) -+ pmlmepriv->htpriv.ampdu_enable = true; -+ HT_caps_handler(padapter, (struct ndis_802_11_var_ie *)pHT_caps_ie); -+ -+ HT_info_handler(padapter, (struct ndis_802_11_var_ie *)pHT_info_ie); -+ } -+ -+ pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pbss_network); -+ -+ /* issue beacon to start bss network */ -+ start_bss_network(padapter, (u8 *)pbss_network); -+ -+ /* alloc sta_info for ap itself */ -+ psta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress); -+ if (!psta) { -+ psta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress); -+ if (psta == NULL) -+ return _FAIL; -+ } -+ -+ /* fix bug of flush_cam_entry at STOP AP mode */ -+ psta->state |= WIFI_AP_STATE; -+ rtw_indicate_connect(padapter); -+ pmlmepriv->cur_network.join_res = true;/* for check if already set beacon */ -+ return ret; -+} -+ -+void rtw_set_macaddr_acl(struct adapter *padapter, int mode) -+{ -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+ -+ DBG_88E("%s, mode =%d\n", __func__, mode); -+ -+ pacl_list->mode = mode; -+} -+ -+int rtw_acl_add_sta(struct adapter *padapter, u8 *addr) -+{ -+ struct list_head *plist, *phead; -+ u8 added = false; -+ int i, ret = 0; -+ struct rtw_wlan_acl_node *paclnode; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+ struct __queue *pacl_node_q = &pacl_list->acl_node_q; -+ -+ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr)); -+ -+ if ((NUM_ACL-1) < pacl_list->num) -+ return -1; -+ -+ spin_lock_bh(&pacl_node_q->lock); -+ -+ phead = get_list_head(pacl_node_q); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); -+ plist = plist->next; -+ -+ if (!memcmp(paclnode->addr, addr, ETH_ALEN)) { -+ if (paclnode->valid) { -+ added = true; -+ DBG_88E("%s, sta has been added\n", __func__); -+ break; -+ } -+ } -+ } -+ -+ spin_unlock_bh(&pacl_node_q->lock); -+ -+ if (added) -+ return ret; -+ -+ spin_lock_bh(&pacl_node_q->lock); -+ -+ for (i = 0; i < NUM_ACL; i++) { -+ paclnode = &pacl_list->aclnode[i]; -+ -+ if (!paclnode->valid) { -+ INIT_LIST_HEAD(&paclnode->list); -+ -+ memcpy(paclnode->addr, addr, ETH_ALEN); -+ -+ paclnode->valid = true; -+ -+ list_add_tail(&paclnode->list, get_list_head(pacl_node_q)); -+ -+ pacl_list->num++; -+ -+ break; -+ } -+ } -+ -+ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num); -+ -+ spin_unlock_bh(&pacl_node_q->lock); -+ -+ return ret; -+} -+ -+int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr) -+{ -+ struct list_head *plist, *phead; -+ int ret = 0; -+ struct rtw_wlan_acl_node *paclnode; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+ struct __queue *pacl_node_q = &pacl_list->acl_node_q; -+ -+ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr)); -+ -+ spin_lock_bh(&pacl_node_q->lock); -+ -+ phead = get_list_head(pacl_node_q); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); -+ plist = plist->next; -+ -+ if (!memcmp(paclnode->addr, addr, ETH_ALEN)) { -+ if (paclnode->valid) { -+ paclnode->valid = false; -+ -+ list_del_init(&paclnode->list); -+ -+ pacl_list->num--; -+ } -+ } -+ } -+ -+ spin_unlock_bh(&pacl_node_q->lock); -+ -+ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num); -+ return ret; -+} -+ -+static void update_bcn_fixed_ie(struct adapter *padapter) -+{ -+ DBG_88E("%s\n", __func__); -+} -+ -+static void update_bcn_erpinfo_ie(struct adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); -+ unsigned char *p, *ie = pnetwork->IEs; -+ u32 len = 0; -+ -+ DBG_88E("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable); -+ -+ if (!pmlmeinfo->ERP_enable) -+ return; -+ -+ /* parsing ERP_IE */ -+ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, -+ (pnetwork->IELength - _BEACON_IE_OFFSET_)); -+ if (p && len > 0) { -+ struct ndis_802_11_var_ie *pIE = (struct ndis_802_11_var_ie *)p; -+ -+ if (pmlmepriv->num_sta_non_erp == 1) -+ pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION; -+ else -+ pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION); -+ -+ if (pmlmepriv->num_sta_no_short_preamble > 0) -+ pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE; -+ else -+ pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE); -+ -+ ERP_IE_handler(padapter, pIE); -+ } -+} -+ -+static void update_bcn_htcap_ie(struct adapter *padapter) -+{ -+ DBG_88E("%s\n", __func__); -+} -+ -+static void update_bcn_htinfo_ie(struct adapter *padapter) -+{ -+ DBG_88E("%s\n", __func__); -+} -+ -+static void update_bcn_rsn_ie(struct adapter *padapter) -+{ -+ DBG_88E("%s\n", __func__); -+} -+ -+static void update_bcn_wpa_ie(struct adapter *padapter) -+{ -+ DBG_88E("%s\n", __func__); -+} -+ -+static void update_bcn_wmm_ie(struct adapter *padapter) -+{ -+ DBG_88E("%s\n", __func__); -+} -+ -+static void update_bcn_wps_ie(struct adapter *padapter) -+{ -+ u8 *pwps_ie = NULL, *pwps_ie_src; -+ u8 *premainder_ie, *pbackup_remainder_ie = NULL; -+ uint wps_ielen = 0, wps_offset, remainder_ielen; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); -+ unsigned char *ie = pnetwork->IEs; -+ u32 ielen = pnetwork->IELength; -+ -+ DBG_88E("%s\n", __func__); -+ -+ pwps_ie = rtw_get_wps_ie(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen); -+ -+ if (pwps_ie == NULL || wps_ielen == 0) -+ return; -+ -+ wps_offset = (uint)(pwps_ie-ie); -+ -+ premainder_ie = pwps_ie + wps_ielen; -+ -+ remainder_ielen = ielen - wps_offset - wps_ielen; -+ -+ if (remainder_ielen > 0) { -+ pbackup_remainder_ie = rtw_malloc(remainder_ielen); -+ if (pbackup_remainder_ie) -+ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); -+ } -+ -+ pwps_ie_src = pmlmepriv->wps_beacon_ie; -+ if (pwps_ie_src == NULL) -+ return; -+ -+ wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */ -+ if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) { -+ memcpy(pwps_ie, pwps_ie_src, wps_ielen+2); -+ pwps_ie += (wps_ielen+2); -+ -+ if (pbackup_remainder_ie) -+ memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen); -+ -+ /* update IELength */ -+ pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen; -+ } -+ -+ if (pbackup_remainder_ie) -+ kfree(pbackup_remainder_ie); -+} -+ -+static void update_bcn_p2p_ie(struct adapter *padapter) -+{ -+} -+ -+static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui) -+{ -+ DBG_88E("%s\n", __func__); -+ -+ if (!memcmp(RTW_WPA_OUI, oui, 4)) -+ update_bcn_wpa_ie(padapter); -+ else if (!memcmp(WMM_OUI, oui, 4)) -+ update_bcn_wmm_ie(padapter); -+ else if (!memcmp(WPS_OUI, oui, 4)) -+ update_bcn_wps_ie(padapter); -+ else if (!memcmp(P2P_OUI, oui, 4)) -+ update_bcn_p2p_ie(padapter); -+ else -+ DBG_88E("unknown OUI type!\n"); -+} -+ -+void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) -+{ -+ struct mlme_priv *pmlmepriv; -+ struct mlme_ext_priv *pmlmeext; -+ -+ if (!padapter) -+ return; -+ -+ pmlmepriv = &(padapter->mlmepriv); -+ pmlmeext = &(padapter->mlmeextpriv); -+ -+ if (!pmlmeext->bstart_bss) -+ return; -+ -+ spin_lock_bh(&pmlmepriv->bcn_update_lock); -+ -+ switch (ie_id) { -+ case 0xFF: -+ update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ -+ break; -+ case _TIM_IE_: -+ update_BCNTIM(padapter); -+ break; -+ case _ERPINFO_IE_: -+ update_bcn_erpinfo_ie(padapter); -+ break; -+ case _HT_CAPABILITY_IE_: -+ update_bcn_htcap_ie(padapter); -+ break; -+ case _RSN_IE_2_: -+ update_bcn_rsn_ie(padapter); -+ break; -+ case _HT_ADD_INFO_IE_: -+ update_bcn_htinfo_ie(padapter); -+ break; -+ case _VENDOR_SPECIFIC_IE_: -+ update_bcn_vendor_spec_ie(padapter, oui); -+ break; -+ default: -+ break; -+ } -+ -+ pmlmepriv->update_bcn = true; -+ -+ spin_unlock_bh(&pmlmepriv->bcn_update_lock); -+ -+ if (tx) -+ set_tx_beacon_cmd(padapter); -+} -+ -+/* -+op_mode -+Set to 0 (HT pure) under the followign conditions -+ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or -+ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS -+Set to 1 (HT non-member protection) if there may be non-HT STAs -+ in both the primary and the secondary channel -+Set to 2 if only HT STAs are associated in BSS, -+ however and at least one 20 MHz HT STA is associated -+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated -+ (currently non-GF HT station is considered as non-HT STA also) -+*/ -+static int rtw_ht_operation_update(struct adapter *padapter) -+{ -+ u16 cur_op_mode, new_op_mode; -+ int op_mode_changes = 0; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; -+ -+ if (pmlmepriv->htpriv.ht_option) -+ return 0; -+ -+ DBG_88E("%s current operation mode = 0x%X\n", -+ __func__, pmlmepriv->ht_op_mode); -+ -+ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && -+ pmlmepriv->num_sta_ht_no_gf) { -+ pmlmepriv->ht_op_mode |= -+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; -+ op_mode_changes++; -+ } else if ((pmlmepriv->ht_op_mode & -+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && -+ pmlmepriv->num_sta_ht_no_gf == 0) { -+ pmlmepriv->ht_op_mode &= -+ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; -+ op_mode_changes++; -+ } -+ -+ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && -+ (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) { -+ pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; -+ op_mode_changes++; -+ } else if ((pmlmepriv->ht_op_mode & -+ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && -+ (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) { -+ pmlmepriv->ht_op_mode &= -+ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; -+ op_mode_changes++; -+ } -+ -+ /* Note: currently we switch to the MIXED op mode if HT non-greenfield -+ * station is associated. Probably it's a theoretical case, since -+ * it looks like all known HT STAs support greenfield. -+ */ -+ new_op_mode = 0; -+ if (pmlmepriv->num_sta_no_ht || -+ (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)) -+ new_op_mode = OP_MODE_MIXED; -+ else if ((le16_to_cpu(phtpriv_ap->ht_cap.cap_info) & -+ IEEE80211_HT_CAP_SUP_WIDTH) && -+ pmlmepriv->num_sta_ht_20mhz) -+ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; -+ else if (pmlmepriv->olbc_ht) -+ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; -+ else -+ new_op_mode = OP_MODE_PURE; -+ -+ cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; -+ if (cur_op_mode != new_op_mode) { -+ pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; -+ pmlmepriv->ht_op_mode |= new_op_mode; -+ op_mode_changes++; -+ } -+ -+ DBG_88E("%s new operation mode = 0x%X changes =%d\n", -+ __func__, pmlmepriv->ht_op_mode, op_mode_changes); -+ -+ return op_mode_changes; -+} -+ -+void associated_clients_update(struct adapter *padapter, u8 updated) -+{ -+ /* update associcated stations cap. */ -+ if (updated) { -+ struct list_head *phead, *plist; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ -+ phead = &pstapriv->asoc_list; -+ plist = phead->next; -+ -+ /* check asoc_queue */ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, asoc_list); -+ -+ plist = plist->next; -+ -+ VCS_update(padapter, psta); -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ } -+} -+ -+/* called > TSR LEVEL for USB or SDIO Interface*/ -+void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) -+{ -+ u8 beacon_updated = false; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ -+ if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) { -+ if (!psta->no_short_preamble_set) { -+ psta->no_short_preamble_set = 1; -+ -+ pmlmepriv->num_sta_no_short_preamble++; -+ -+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && -+ (pmlmepriv->num_sta_no_short_preamble == 1)) { -+ beacon_updated = true; -+ update_beacon(padapter, 0xFF, NULL, true); -+ } -+ } -+ } else { -+ if (psta->no_short_preamble_set) { -+ psta->no_short_preamble_set = 0; -+ -+ pmlmepriv->num_sta_no_short_preamble--; -+ -+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && -+ (pmlmepriv->num_sta_no_short_preamble == 0)) { -+ beacon_updated = true; -+ update_beacon(padapter, 0xFF, NULL, true); -+ } -+ } -+ } -+ -+ if (psta->flags & WLAN_STA_NONERP) { -+ if (!psta->nonerp_set) { -+ psta->nonerp_set = 1; -+ -+ pmlmepriv->num_sta_non_erp++; -+ -+ if (pmlmepriv->num_sta_non_erp == 1) { -+ beacon_updated = true; -+ update_beacon(padapter, _ERPINFO_IE_, NULL, true); -+ } -+ } -+ } else { -+ if (psta->nonerp_set) { -+ psta->nonerp_set = 0; -+ -+ pmlmepriv->num_sta_non_erp--; -+ -+ if (pmlmepriv->num_sta_non_erp == 0) { -+ beacon_updated = true; -+ update_beacon(padapter, _ERPINFO_IE_, NULL, true); -+ } -+ } -+ } -+ -+ if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) { -+ if (!psta->no_short_slot_time_set) { -+ psta->no_short_slot_time_set = 1; -+ -+ pmlmepriv->num_sta_no_short_slot_time++; -+ -+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && -+ (pmlmepriv->num_sta_no_short_slot_time == 1)) { -+ beacon_updated = true; -+ update_beacon(padapter, 0xFF, NULL, true); -+ } -+ } -+ } else { -+ if (psta->no_short_slot_time_set) { -+ psta->no_short_slot_time_set = 0; -+ -+ pmlmepriv->num_sta_no_short_slot_time--; -+ -+ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && -+ (pmlmepriv->num_sta_no_short_slot_time == 0)) { -+ beacon_updated = true; -+ update_beacon(padapter, 0xFF, NULL, true); -+ } -+ } -+ } -+ -+ if (psta->flags & WLAN_STA_HT) { -+ u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); -+ -+ DBG_88E("HT: STA %pM HT Capabilities Info: 0x%04x\n", -+ (psta->hwaddr), ht_capab); -+ -+ if (psta->no_ht_set) { -+ psta->no_ht_set = 0; -+ pmlmepriv->num_sta_no_ht--; -+ } -+ -+ if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) { -+ if (!psta->no_ht_gf_set) { -+ psta->no_ht_gf_set = 1; -+ pmlmepriv->num_sta_ht_no_gf++; -+ } -+ DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n", -+ __func__, (psta->hwaddr), -+ pmlmepriv->num_sta_ht_no_gf); -+ } -+ -+ if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) { -+ if (!psta->ht_20mhz_set) { -+ psta->ht_20mhz_set = 1; -+ pmlmepriv->num_sta_ht_20mhz++; -+ } -+ DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n", -+ __func__, (psta->hwaddr), -+ pmlmepriv->num_sta_ht_20mhz); -+ } -+ } else { -+ if (!psta->no_ht_set) { -+ psta->no_ht_set = 1; -+ pmlmepriv->num_sta_no_ht++; -+ } -+ if (pmlmepriv->htpriv.ht_option) { -+ DBG_88E("%s STA %pM - no HT, num of non-HT stations %d\n", -+ __func__, (psta->hwaddr), -+ pmlmepriv->num_sta_no_ht); -+ } -+ } -+ -+ if (rtw_ht_operation_update(padapter) > 0) { -+ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false); -+ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); -+ } -+ -+ /* update associcated stations cap. */ -+ associated_clients_update(padapter, beacon_updated); -+ -+ DBG_88E("%s, updated =%d\n", __func__, beacon_updated); -+} -+ -+u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta) -+{ -+ u8 beacon_updated = false; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ -+ if (!psta) -+ return beacon_updated; -+ -+ if (psta->no_short_preamble_set) { -+ psta->no_short_preamble_set = 0; -+ pmlmepriv->num_sta_no_short_preamble--; -+ if (pmlmeext->cur_wireless_mode > WIRELESS_11B && -+ pmlmepriv->num_sta_no_short_preamble == 0) { -+ beacon_updated = true; -+ update_beacon(padapter, 0xFF, NULL, true); -+ } -+ } -+ -+ if (psta->nonerp_set) { -+ psta->nonerp_set = 0; -+ pmlmepriv->num_sta_non_erp--; -+ if (pmlmepriv->num_sta_non_erp == 0) { -+ beacon_updated = true; -+ update_beacon(padapter, _ERPINFO_IE_, NULL, true); -+ } -+ } -+ -+ if (psta->no_short_slot_time_set) { -+ psta->no_short_slot_time_set = 0; -+ pmlmepriv->num_sta_no_short_slot_time--; -+ if (pmlmeext->cur_wireless_mode > WIRELESS_11B && -+ pmlmepriv->num_sta_no_short_slot_time == 0) { -+ beacon_updated = true; -+ update_beacon(padapter, 0xFF, NULL, true); -+ } -+ } -+ -+ if (psta->no_ht_gf_set) { -+ psta->no_ht_gf_set = 0; -+ pmlmepriv->num_sta_ht_no_gf--; -+ } -+ -+ if (psta->no_ht_set) { -+ psta->no_ht_set = 0; -+ pmlmepriv->num_sta_no_ht--; -+ } -+ -+ if (psta->ht_20mhz_set) { -+ psta->ht_20mhz_set = 0; -+ pmlmepriv->num_sta_ht_20mhz--; -+ } -+ -+ if (rtw_ht_operation_update(padapter) > 0) { -+ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false); -+ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); -+ } -+ -+ /* update associcated stations cap. */ -+ -+ DBG_88E("%s, updated =%d\n", __func__, beacon_updated); -+ -+ return beacon_updated; -+} -+ -+u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta, -+ bool active, u16 reason) -+{ -+ u8 beacon_updated = false; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ if (!psta) -+ return beacon_updated; -+ -+ /* tear down Rx AMPDU */ -+ send_delba(padapter, 0, psta->hwaddr);/* recipient */ -+ -+ /* tear down TX AMPDU */ -+ send_delba(padapter, 1, psta->hwaddr);/* originator */ -+ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ -+ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ -+ -+ if (active) -+ issue_deauth(padapter, psta->hwaddr, reason); -+ -+ /* clear cam entry / key */ -+ rtw_clearstakey_cmd(padapter, (u8 *)psta, (u8)(psta->mac_id + 3), true); -+ -+ spin_lock_bh(&psta->lock); -+ psta->state &= ~_FW_LINKED; -+ spin_unlock_bh(&psta->lock); -+ -+ rtw_indicate_sta_disassoc_event(padapter, psta); -+ -+ report_del_sta_event(padapter, psta->hwaddr, reason); -+ -+ beacon_updated = bss_cap_update_on_sta_leave(padapter, psta); -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ rtw_free_stainfo(padapter, psta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+ return beacon_updated; -+} -+ -+int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset) -+{ -+ struct list_head *phead, *plist; -+ int ret = 0; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) -+ return ret; -+ -+ DBG_88E(FUNC_NDEV_FMT" with ch:%u, offset:%u\n", -+ FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset); -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ phead = &pstapriv->asoc_list; -+ plist = phead->next; -+ -+ /* for each sta in asoc_queue */ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, asoc_list); -+ plist = plist->next; -+ -+ issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset); -+ psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2); -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset); -+ -+ return ret; -+} -+ -+int rtw_sta_flush(struct adapter *padapter) -+{ -+ struct list_head *phead, *plist; -+ int ret = 0; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+ DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); -+ -+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) -+ return ret; -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ phead = &pstapriv->asoc_list; -+ plist = phead->next; -+ -+ /* free sta asoc_queue */ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, asoc_list); -+ -+ plist = plist->next; -+ -+ list_del_init(&psta->asoc_list); -+ pstapriv->asoc_list_cnt--; -+ -+ ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING); -+ -+ associated_clients_update(padapter, true); -+ -+ return ret; -+} -+ -+/* called > TSR LEVEL for USB or SDIO Interface*/ -+void sta_info_update(struct adapter *padapter, struct sta_info *psta) -+{ -+ int flags = psta->flags; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ /* update wmm cap. */ -+ if (WLAN_STA_WME&flags) -+ psta->qos_option = 1; -+ else -+ psta->qos_option = 0; -+ -+ if (pmlmepriv->qospriv.qos_option == 0) -+ psta->qos_option = 0; -+ -+ /* update 802.11n ht cap. */ -+ if (WLAN_STA_HT&flags) { -+ psta->htpriv.ht_option = true; -+ psta->qos_option = 1; -+ } else { -+ psta->htpriv.ht_option = false; -+ } -+ -+ if (!pmlmepriv->htpriv.ht_option) -+ psta->htpriv.ht_option = false; -+ -+ update_sta_info_apmode(padapter, psta); -+} -+ -+/* called >= TSR LEVEL for USB or SDIO Interface*/ -+void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta) -+{ -+ if (psta->state & _FW_LINKED) { -+ /* add ratid */ -+ add_RATid(padapter, psta, 0);/* DM_RATR_STA_INIT */ -+ } -+} -+ -+void start_ap_mode(struct adapter *padapter) -+{ -+ int i; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+ -+ pmlmepriv->update_bcn = false; -+ -+ pmlmeext->bstart_bss = false; -+ -+ pmlmepriv->num_sta_non_erp = 0; -+ -+ pmlmepriv->num_sta_no_short_slot_time = 0; -+ -+ pmlmepriv->num_sta_no_short_preamble = 0; -+ -+ pmlmepriv->num_sta_ht_no_gf = 0; -+ pmlmepriv->num_sta_no_ht = 0; -+ pmlmepriv->num_sta_ht_20mhz = 0; -+ -+ pmlmepriv->olbc = false; -+ -+ pmlmepriv->olbc_ht = false; -+ -+ pmlmepriv->ht_op_mode = 0; -+ -+ for (i = 0; i < NUM_STA; i++) -+ pstapriv->sta_aid[i] = NULL; -+ -+ pmlmepriv->wps_beacon_ie = NULL; -+ pmlmepriv->wps_probe_resp_ie = NULL; -+ pmlmepriv->wps_assoc_resp_ie = NULL; -+ -+ pmlmepriv->p2p_beacon_ie = NULL; -+ pmlmepriv->p2p_probe_resp_ie = NULL; -+ -+ /* for ACL */ -+ INIT_LIST_HEAD(&(pacl_list->acl_node_q.queue)); -+ pacl_list->num = 0; -+ pacl_list->mode = 0; -+ for (i = 0; i < NUM_ACL; i++) { -+ INIT_LIST_HEAD(&pacl_list->aclnode[i].list); -+ pacl_list->aclnode[i].valid = false; -+ } -+} -+ -+void stop_ap_mode(struct adapter *padapter) -+{ -+ struct list_head *phead, *plist; -+ struct rtw_wlan_acl_node *paclnode; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+ struct __queue *pacl_node_q = &pacl_list->acl_node_q; -+ -+ pmlmepriv->update_bcn = false; -+ pmlmeext->bstart_bss = false; -+ -+ /* reset and init security priv , this can refine with rtw_reset_securitypriv */ -+ memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv)); -+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; -+ padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; -+ -+ /* for ACL */ -+ spin_lock_bh(&pacl_node_q->lock); -+ phead = get_list_head(pacl_node_q); -+ plist = phead->next; -+ while (phead != plist) { -+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); -+ plist = plist->next; -+ -+ if (paclnode->valid) { -+ paclnode->valid = false; -+ -+ list_del_init(&paclnode->list); -+ -+ pacl_list->num--; -+ } -+ } -+ spin_unlock_bh(&pacl_node_q->lock); -+ -+ DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num); -+ -+ rtw_sta_flush(padapter); -+ -+ /* free_assoc_sta_resources */ -+ rtw_free_all_stainfo(padapter); -+ -+ psta = rtw_get_bcmc_stainfo(padapter); -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ rtw_free_stainfo(padapter, psta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+ rtw_init_bcmc_stainfo(padapter); -+ -+ rtw_free_mlme_priv_ie_data(pmlmepriv); -+} -+ -+#endif /* CONFIG_88EU_AP_MODE */ -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_br_ext.c b/drivers/net/wireless/rtl8188eu/core/rtw_br_ext.c -new file mode 100644 -index 0000000000000..1236f50dc22f7 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_br_ext.c -@@ -0,0 +1,1184 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_BR_EXT_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "rtw_br_ext.h" -+#include -+#include -+ -+#ifndef csum_ipv6_magic -+#include -+#endif -+ -+#include -+#include -+#include -+#include -+ -+#define NAT25_IPV4 01 -+#define NAT25_IPV6 02 -+#define NAT25_IPX 03 -+#define NAT25_APPLE 04 -+#define NAT25_PPPOE 05 -+ -+#define RTL_RELAY_TAG_LEN (ETH_ALEN) -+#define TAG_HDR_LEN 4 -+ -+#define MAGIC_CODE 0x8186 -+#define MAGIC_CODE_LEN 2 -+#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */ -+ -+/*----------------------------------------------------------------- -+ How database records network address: -+ 0 1 2 3 4 5 6 7 8 9 10 -+ |----|----|----|----|----|----|----|----|----|----|----| -+ IPv4 |type| | IP addr | -+ IPX |type| Net addr | Node addr | -+ IPX |type| Net addr |Sckt addr| -+ Apple |type| Network |node| -+ PPPoE |type| SID | AC MAC | -+-----------------------------------------------------------------*/ -+ -+/* Find a tag in pppoe frame and return the pointer */ -+static inline unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type) -+{ -+ unsigned char *cur_ptr, *start_ptr; -+ unsigned short tagLen, tagType; -+ -+ start_ptr = cur_ptr = (unsigned char *)ph->tag; -+ while ((cur_ptr - start_ptr) < ntohs(ph->length)) { -+ /* prevent un-alignment access */ -+ tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]); -+ tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]); -+ if (tagType == type) -+ return cur_ptr; -+ cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen; -+ } -+ return NULL; -+} -+ -+static inline int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag) -+{ -+ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); -+ int data_len; -+ -+ data_len = tag->tag_len + TAG_HDR_LEN; -+ if (skb_tailroom(skb) < data_len) { -+ _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n"); -+ return -1; -+ } -+ -+ skb_put(skb, data_len); -+ /* have a room for new tag */ -+ memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length)); -+ ph->length = htons(ntohs(ph->length) + data_len); -+ memcpy((unsigned char *)ph->tag, tag, data_len); -+ return data_len; -+} -+ -+static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len) -+{ -+ int tail_len; -+ unsigned long end, tail; -+ -+ if ((src+len) > skb_tail_pointer(skb) || skb->len < len) -+ return -1; -+ -+ tail = (unsigned long)skb_tail_pointer(skb); -+ end = (unsigned long)src+len; -+ if (tail < end) -+ return -1; -+ -+ tail_len = (int)(tail-end); -+ if (tail_len > 0) -+ memmove(src, src+len, tail_len); -+ -+ skb_trim(skb, skb->len-len); -+ return 0; -+} -+ -+static inline unsigned long __nat25_timeout(struct adapter *priv) -+{ -+ unsigned long timeout; -+ -+ timeout = jiffies - NAT25_AGEING_TIME*HZ; -+ -+ return timeout; -+} -+ -+static inline int __nat25_has_expired(struct adapter *priv, -+ struct nat25_network_db_entry *fdb) -+{ -+ if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv))) -+ return 1; -+ -+ return 0; -+} -+ -+static inline void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr, -+ unsigned int *ipAddr) -+{ -+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); -+ -+ networkAddr[0] = NAT25_IPV4; -+ memcpy(networkAddr+7, (unsigned char *)ipAddr, 4); -+} -+ -+static inline void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, -+ unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) -+{ -+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); -+ -+ networkAddr[0] = NAT25_IPX; -+ memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4); -+ memcpy(networkAddr+5, ipxNodeAddr, 6); -+} -+ -+static inline void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr, -+ unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr) -+{ -+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); -+ -+ networkAddr[0] = NAT25_IPX; -+ memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4); -+ memcpy(networkAddr+5, (unsigned char *)ipxSocketAddr, 2); -+} -+ -+static inline void __nat25_generate_apple_network_addr(unsigned char *networkAddr, -+ unsigned short *network, unsigned char *node) -+{ -+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); -+ -+ networkAddr[0] = NAT25_APPLE; -+ memcpy(networkAddr+1, (unsigned char *)network, 2); -+ networkAddr[3] = *node; -+} -+ -+static inline void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr, -+ unsigned char *ac_mac, unsigned short *sid) -+{ -+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); -+ -+ networkAddr[0] = NAT25_PPPOE; -+ memcpy(networkAddr+1, (unsigned char *)sid, 2); -+ memcpy(networkAddr+3, (unsigned char *)ac_mac, 6); -+} -+ -+static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr, -+ unsigned int *ipAddr) -+{ -+ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); -+ -+ networkAddr[0] = NAT25_IPV6; -+ memcpy(networkAddr+1, (unsigned char *)ipAddr, 16); -+} -+ -+static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b) -+{ -+ while (len > 0) { -+ if (*data == tag && *(data+1) == len8b && len >= len8b*8) -+ return data+2; -+ -+ len -= (*(data+1))*8; -+ data += (*(data+1))*8; -+ } -+ return NULL; -+} -+ -+static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac) -+{ -+ struct icmp6hdr *icmphdr = (struct icmp6hdr *)data; -+ unsigned char *mac; -+ -+ if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { -+ if (len >= 8) { -+ mac = scan_tlv(&data[8], len-8, 1, 1); -+ if (mac) { -+ _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", -+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], -+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); -+ memcpy(mac, replace_mac, 6); -+ return 1; -+ } -+ } -+ } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) { -+ if (len >= 16) { -+ mac = scan_tlv(&data[16], len-16, 1, 1); -+ if (mac) { -+ _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", -+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], -+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); -+ memcpy(mac, replace_mac, 6); -+ return 1; -+ } -+ } -+ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { -+ if (len >= 24) { -+ mac = scan_tlv(&data[24], len-24, 1, 1); -+ if (mac) { -+ _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", -+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], -+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); -+ memcpy(mac, replace_mac, 6); -+ return 1; -+ } -+ } -+ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { -+ if (len >= 24) { -+ mac = scan_tlv(&data[24], len-24, 2, 1); -+ if (mac) { -+ _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", -+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], -+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); -+ memcpy(mac, replace_mac, 6); -+ return 1; -+ } -+ } -+ } else if (icmphdr->icmp6_type == NDISC_REDIRECT) { -+ if (len >= 40) { -+ mac = scan_tlv(&data[40], len-40, 2, 1); -+ if (mac) { -+ _DEBUG_INFO("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", -+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], -+ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); -+ memcpy(mac, replace_mac, 6); -+ return 1; -+ } -+ } -+ } -+ return 0; -+} -+ -+static inline int __nat25_network_hash(unsigned char *networkAddr) -+{ -+ if (networkAddr[0] == NAT25_IPV4) { -+ unsigned long x; -+ -+ x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; -+ -+ return x & (NAT25_HASH_SIZE - 1); -+ } else if (networkAddr[0] == NAT25_IPX) { -+ unsigned long x; -+ -+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ -+ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; -+ -+ return x & (NAT25_HASH_SIZE - 1); -+ } else if (networkAddr[0] == NAT25_APPLE) { -+ unsigned long x; -+ -+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3]; -+ -+ return x & (NAT25_HASH_SIZE - 1); -+ } else if (networkAddr[0] == NAT25_PPPOE) { -+ unsigned long x; -+ -+ x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8]; -+ -+ return x & (NAT25_HASH_SIZE - 1); -+ } else if (networkAddr[0] == NAT25_IPV6) { -+ unsigned long x; -+ -+ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ -+ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^ -+ networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^ -+ networkAddr[16]; -+ -+ return x & (NAT25_HASH_SIZE - 1); -+ } else { -+ unsigned long x = 0; -+ int i; -+ -+ for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++) -+ x ^= networkAddr[i]; -+ -+ return x & (NAT25_HASH_SIZE - 1); -+ } -+} -+ -+static inline void __network_hash_link(struct adapter *priv, -+ struct nat25_network_db_entry *ent, int hash) -+{ -+ /* Caller must spin_lock already! */ -+ ent->next_hash = priv->nethash[hash]; -+ if (ent->next_hash != NULL) -+ ent->next_hash->pprev_hash = &ent->next_hash; -+ priv->nethash[hash] = ent; -+ ent->pprev_hash = &priv->nethash[hash]; -+} -+ -+static inline void __network_hash_unlink(struct nat25_network_db_entry *ent) -+{ -+ /* Caller must spin_lock already! */ -+ *(ent->pprev_hash) = ent->next_hash; -+ if (ent->next_hash != NULL) -+ ent->next_hash->pprev_hash = ent->pprev_hash; -+ ent->next_hash = NULL; -+ ent->pprev_hash = NULL; -+} -+ -+static int __nat25_db_network_lookup_and_replace(struct adapter *priv, -+ struct sk_buff *skb, unsigned char *networkAddr) -+{ -+ struct nat25_network_db_entry *db; -+ -+ spin_lock_bh(&priv->br_ext_lock); -+ -+ db = priv->nethash[__nat25_network_hash(networkAddr)]; -+ while (db != NULL) { -+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { -+ if (!__nat25_has_expired(priv, db)) { -+ /* replace the destination mac address */ -+ memcpy(skb->data, db->macAddr, ETH_ALEN); -+ atomic_inc(&db->use_count); -+ -+ DEBUG_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" -+ "%02x%02x%02x%02x%02x%02x\n", -+ db->macAddr[0], -+ db->macAddr[1], -+ db->macAddr[2], -+ db->macAddr[3], -+ db->macAddr[4], -+ db->macAddr[5], -+ db->networkAddr[0], -+ db->networkAddr[1], -+ db->networkAddr[2], -+ db->networkAddr[3], -+ db->networkAddr[4], -+ db->networkAddr[5], -+ db->networkAddr[6], -+ db->networkAddr[7], -+ db->networkAddr[8], -+ db->networkAddr[9], -+ db->networkAddr[10], -+ db->networkAddr[11], -+ db->networkAddr[12], -+ db->networkAddr[13], -+ db->networkAddr[14], -+ db->networkAddr[15], -+ db->networkAddr[16]); -+ } -+ spin_unlock_bh(&priv->br_ext_lock); -+ return 1; -+ } -+ db = db->next_hash; -+ } -+ spin_unlock_bh(&priv->br_ext_lock); -+ return 0; -+} -+ -+static void __nat25_db_network_insert(struct adapter *priv, -+ unsigned char *macAddr, unsigned char *networkAddr) -+{ -+ struct nat25_network_db_entry *db; -+ int hash; -+ -+ spin_lock_bh(&priv->br_ext_lock); -+ hash = __nat25_network_hash(networkAddr); -+ db = priv->nethash[hash]; -+ while (db != NULL) { -+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { -+ memcpy(db->macAddr, macAddr, ETH_ALEN); -+ db->ageing_timer = jiffies; -+ spin_unlock_bh(&priv->br_ext_lock); -+ return; -+ } -+ db = db->next_hash; -+ } -+ db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db)); -+ if (db == NULL) { -+ spin_unlock_bh(&priv->br_ext_lock); -+ return; -+ } -+ memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN); -+ memcpy(db->macAddr, macAddr, ETH_ALEN); -+ atomic_set(&db->use_count, 1); -+ db->ageing_timer = jiffies; -+ -+ __network_hash_link(priv, db, hash); -+ -+ spin_unlock_bh(&priv->br_ext_lock); -+} -+ -+static void __nat25_db_print(struct adapter *priv) -+{ -+} -+ -+/* -+ * NAT2.5 interface -+ */ -+ -+void nat25_db_cleanup(struct adapter *priv) -+{ -+ int i; -+ -+ spin_lock_bh(&priv->br_ext_lock); -+ -+ for (i = 0; i < NAT25_HASH_SIZE; i++) { -+ struct nat25_network_db_entry *f; -+ f = priv->nethash[i]; -+ while (f != NULL) { -+ struct nat25_network_db_entry *g; -+ -+ g = f->next_hash; -+ if (priv->scdb_entry == f) { -+ memset(priv->scdb_mac, 0, ETH_ALEN); -+ memset(priv->scdb_ip, 0, 4); -+ priv->scdb_entry = NULL; -+ } -+ __network_hash_unlink(f); -+ kfree(f); -+ f = g; -+ } -+ } -+ spin_unlock_bh(&priv->br_ext_lock); -+} -+ -+void nat25_db_expire(struct adapter *priv) -+{ -+ int i; -+ -+ spin_lock_bh(&priv->br_ext_lock); -+ -+ for (i = 0; i < NAT25_HASH_SIZE; i++) { -+ struct nat25_network_db_entry *f; -+ f = priv->nethash[i]; -+ -+ while (f != NULL) { -+ struct nat25_network_db_entry *g; -+ g = f->next_hash; -+ -+ if (__nat25_has_expired(priv, f)) { -+ if (atomic_dec_and_test(&f->use_count)) { -+ if (priv->scdb_entry == f) { -+ memset(priv->scdb_mac, 0, ETH_ALEN); -+ memset(priv->scdb_ip, 0, 4); -+ priv->scdb_entry = NULL; -+ } -+ __network_hash_unlink(f); -+ kfree(f); -+ } -+ } -+ f = g; -+ } -+ } -+ spin_unlock_bh(&priv->br_ext_lock); -+} -+ -+int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method) -+{ -+ unsigned short protocol; -+ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; -+ unsigned int tmp; -+ -+ if (skb == NULL) -+ return -1; -+ -+ if ((method <= NAT25_MIN) || (method >= NAT25_MAX)) -+ return -1; -+ -+ protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN))); -+ -+ /*---------------------------------------------------*/ -+ /* Handle IP frame */ -+ /*---------------------------------------------------*/ -+ if (protocol == ETH_P_IP) { -+ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); -+ -+ if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) { -+ DEBUG_WARN("NAT25: malformed IP packet !\n"); -+ return -1; -+ } -+ -+ switch (method) { -+ case NAT25_CHECK: -+ return -1; -+ case NAT25_INSERT: -+ /* some multicast with source IP is all zero, maybe other case is illegal */ -+ /* in class A, B, C, host address is all zero or all one is illegal */ -+ if (iph->saddr == 0) -+ return 0; -+ tmp = be32_to_cpu(iph->saddr); -+ DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr); -+ __nat25_generate_ipv4_network_addr(networkAddr, &tmp); -+ /* record source IP address and , source mac address into db */ -+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); -+ -+ __nat25_db_print(priv); -+ return 0; -+ case NAT25_LOOKUP: -+ DEBUG_INFO("NAT25: Lookup IP, SA =%08x, DA =%08x\n", iph->saddr, iph->daddr); -+ tmp = be32_to_cpu(iph->daddr); -+ __nat25_generate_ipv4_network_addr(networkAddr, &tmp); -+ -+ if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { -+ if (*((unsigned char *)&iph->daddr + 3) == 0xff) { -+ /* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */ -+ DEBUG_INFO("NAT25: Set DA as boardcast\n"); -+ memset(skb->data, 0xff, ETH_ALEN); -+ } else { -+ /* forward unknow IP packet to upper TCP/IP */ -+ DEBUG_INFO("NAT25: Replace DA with BR's MAC\n"); -+ if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0) { -+ printk("Re-init netdev_br_init() due to br_mac == 0!\n"); -+ netdev_br_init(priv->pnetdev); -+ } -+ memcpy(skb->data, priv->br_mac, ETH_ALEN); -+ } -+ } -+ return 0; -+ default: -+ return -1; -+ } -+ } else if (protocol == ETH_P_ARP) { -+ /*---------------------------------------------------*/ -+ /* Handle ARP frame */ -+ /*---------------------------------------------------*/ -+ struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN); -+ unsigned char *arp_ptr = (unsigned char *)(arp + 1); -+ unsigned int *sender, *target; -+ -+ if (arp->ar_pro != __constant_htons(ETH_P_IP)) { -+ DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro)); -+ return -1; -+ } -+ -+ switch (method) { -+ case NAT25_CHECK: -+ return 0; /* skb_copy for all ARP frame */ -+ case NAT25_INSERT: -+ DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0], -+ arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]); -+ -+ /* change to ARP sender mac address to wlan STA address */ -+ memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN); -+ arp_ptr += arp->ar_hln; -+ sender = (unsigned int *)arp_ptr; -+ __nat25_generate_ipv4_network_addr(networkAddr, sender); -+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); -+ __nat25_db_print(priv); -+ return 0; -+ case NAT25_LOOKUP: -+ DEBUG_INFO("NAT25: Lookup ARP\n"); -+ -+ arp_ptr += arp->ar_hln; -+ sender = (unsigned int *)arp_ptr; -+ arp_ptr += (arp->ar_hln + arp->ar_pln); -+ target = (unsigned int *)arp_ptr; -+ __nat25_generate_ipv4_network_addr(networkAddr, target); -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ /* change to ARP target mac address to Lookup result */ -+ arp_ptr = (unsigned char *)(arp + 1); -+ arp_ptr += (arp->ar_hln + arp->ar_pln); -+ memcpy(arp_ptr, skb->data, ETH_ALEN); -+ return 0; -+ default: -+ return -1; -+ } -+ } else if ((protocol == ETH_P_IPX) || -+ (protocol <= ETH_FRAME_LEN)) { -+ /*---------------------------------------------------*/ -+ /* Handle IPX and Apple Talk frame */ -+ /*---------------------------------------------------*/ -+ unsigned char ipx_header[2] = {0xFF, 0xFF}; -+ struct ipxhdr *ipx = NULL; -+ struct elapaarp *ea = NULL; -+ struct ddpehdr *ddp = NULL; -+ unsigned char *framePtr = skb->data + ETH_HLEN; -+ -+ if (protocol == ETH_P_IPX) { -+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet II)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else if (protocol <= ETH_FRAME_LEN) { -+ if (!memcmp(ipx_header, framePtr, 2)) { -+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.3)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else { -+ unsigned char ipx_8022_type = 0xE0; -+ unsigned char snap_8022_type = 0xAA; -+ -+ if (*framePtr == snap_8022_type) { -+ unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37}; /* IPX SNAP ID */ -+ unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /* Apple Talk AARP SNAP ID */ -+ unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; /* Apple Talk DDP SNAP ID */ -+ -+ framePtr += 3; /* eliminate the 802.2 header */ -+ -+ if (!memcmp(ipx_snap_id, framePtr, 5)) { -+ framePtr += 5; /* eliminate the SNAP header */ -+ -+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet SNAP)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else if (!memcmp(aarp_snap_id, framePtr, 5)) { -+ framePtr += 5; /* eliminate the SNAP header */ -+ -+ ea = (struct elapaarp *)framePtr; -+ } else if (!memcmp(ddp_snap_id, framePtr, 5)) { -+ framePtr += 5; /* eliminate the SNAP header */ -+ -+ ddp = (struct ddpehdr *)framePtr; -+ } else { -+ DEBUG_WARN("NAT25: Protocol = Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0], -+ framePtr[1], framePtr[2], framePtr[3], framePtr[4]); -+ return -1; -+ } -+ } else if (*framePtr == ipx_8022_type) { -+ framePtr += 3; /* eliminate the 802.2 header */ -+ -+ if (!memcmp(ipx_header, framePtr, 2)) { -+ DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.2)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else { -+ return -1; -+ } -+ } else { -+ return -1; -+ } -+ } -+ } else { -+ return -1; -+ } -+ -+ /* IPX */ -+ if (ipx != NULL) { -+ switch (method) { -+ case NAT25_CHECK: -+ if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) -+ DEBUG_INFO("NAT25: Check IPX skb_copy\n"); -+ return 0; -+ case NAT25_INSERT: -+ DEBUG_INFO("NAT25: Insert IPX, Dest =%08x,%02x%02x%02x%02x%02x%02x,%04x Source =%08x,%02x%02x%02x%02x%02x%02x,%04x\n", -+ ipx->ipx_dest.net, -+ ipx->ipx_dest.node[0], -+ ipx->ipx_dest.node[1], -+ ipx->ipx_dest.node[2], -+ ipx->ipx_dest.node[3], -+ ipx->ipx_dest.node[4], -+ ipx->ipx_dest.node[5], -+ ipx->ipx_dest.sock, -+ ipx->ipx_source.net, -+ ipx->ipx_source.node[0], -+ ipx->ipx_source.node[1], -+ ipx->ipx_source.node[2], -+ ipx->ipx_source.node[3], -+ ipx->ipx_source.node[4], -+ ipx->ipx_source.node[5], -+ ipx->ipx_source.sock); -+ -+ if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { -+ DEBUG_INFO("NAT25: Use IPX Net, and Socket as network addr\n"); -+ -+ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock); -+ -+ /* change IPX source node addr to wlan STA address */ -+ memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN); -+ } else { -+ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node); -+ } -+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); -+ __nat25_db_print(priv); -+ return 0; -+ case NAT25_LOOKUP: -+ if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) { -+ DEBUG_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n"); -+ -+ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock); -+ -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ -+ /* replace IPX destination node addr with Lookup destination MAC addr */ -+ memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN); -+ } else { -+ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node); -+ -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ } -+ return 0; -+ default: -+ return -1; -+ } -+ } else if (ea != NULL) { -+ /* Sanity check fields. */ -+ if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) { -+ DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n"); -+ return -1; -+ } -+ -+ switch (method) { -+ case NAT25_CHECK: -+ return 0; -+ case NAT25_INSERT: -+ /* change to AARP source mac address to wlan STA address */ -+ memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN); -+ -+ DEBUG_INFO("NAT25: Insert AARP, Source =%d,%d Destination =%d,%d\n", -+ ea->pa_src_net, -+ ea->pa_src_node, -+ ea->pa_dst_net, -+ ea->pa_dst_node); -+ -+ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node); -+ -+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); -+ -+ __nat25_db_print(priv); -+ return 0; -+ case NAT25_LOOKUP: -+ DEBUG_INFO("NAT25: Lookup AARP, Source =%d,%d Destination =%d,%d\n", -+ ea->pa_src_net, -+ ea->pa_src_node, -+ ea->pa_dst_net, -+ ea->pa_dst_node); -+ -+ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node); -+ -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ -+ /* change to AARP destination mac address to Lookup result */ -+ memcpy(ea->hw_dst, skb->data, ETH_ALEN); -+ return 0; -+ default: -+ return -1; -+ } -+ } else if (ddp != NULL) { -+ switch (method) { -+ case NAT25_CHECK: -+ return -1; -+ case NAT25_INSERT: -+ DEBUG_INFO("NAT25: Insert DDP, Source =%d,%d Destination =%d,%d\n", -+ ddp->deh_snet, -+ ddp->deh_snode, -+ ddp->deh_dnet, -+ ddp->deh_dnode); -+ -+ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode); -+ -+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); -+ -+ __nat25_db_print(priv); -+ return 0; -+ case NAT25_LOOKUP: -+ DEBUG_INFO("NAT25: Lookup DDP, Source =%d,%d Destination =%d,%d\n", -+ ddp->deh_snet, -+ ddp->deh_snode, -+ ddp->deh_dnet, -+ ddp->deh_dnode); -+ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode); -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ return 0; -+ default: -+ return -1; -+ } -+ } -+ -+ return -1; -+ } else if ((protocol == ETH_P_PPP_DISC) || -+ (protocol == ETH_P_PPP_SES)) { -+ /*---------------------------------------------------*/ -+ /* Handle PPPoE frame */ -+ /*---------------------------------------------------*/ -+ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); -+ unsigned short *pMagic; -+ -+ switch (method) { -+ case NAT25_CHECK: -+ if (ph->sid == 0) -+ return 0; -+ return 1; -+ case NAT25_INSERT: -+ if (ph->sid == 0) { /* Discovery phase according to tag */ -+ if (ph->code == PADI_CODE || ph->code == PADR_CODE) { -+ if (priv->ethBrExtInfo.addPPPoETag) { -+ struct pppoe_tag *tag, *pOldTag; -+ unsigned char tag_buf[40]; -+ int old_tag_len = 0; -+ -+ tag = (struct pppoe_tag *)tag_buf; -+ pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); -+ if (pOldTag) { /* if SID existed, copy old value and delete it */ -+ old_tag_len = ntohs(pOldTag->tag_len); -+ if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) { -+ DEBUG_ERR("SID tag length too long!\n"); -+ return -1; -+ } -+ -+ memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN, -+ pOldTag->tag_data, old_tag_len); -+ -+ if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) { -+ DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n"); -+ return -1; -+ } -+ ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len); -+ } -+ -+ tag->tag_type = PTT_RELAY_SID; -+ tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len); -+ -+ /* insert the magic_code+client mac in relay tag */ -+ pMagic = (unsigned short *)tag->tag_data; -+ *pMagic = htons(MAGIC_CODE); -+ memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN); -+ -+ /* Add relay tag */ -+ if (__nat25_add_pppoe_tag(skb, tag) < 0) -+ return -1; -+ -+ DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n", -+ (ph->code == PADI_CODE ? "PADI" : "PADR")); -+ } else { /* not add relay tag */ -+ if (priv->pppoe_connection_in_progress && -+ memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) { -+ DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n"); -+ return -2; -+ } -+ -+ if (priv->pppoe_connection_in_progress == 0) -+ memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN); -+ -+ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; -+ } -+ } else { -+ return -1; -+ } -+ } else { /* session phase */ -+ DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name); -+ -+ __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid)); -+ -+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); -+ -+ __nat25_db_print(priv); -+ -+ if (!priv->ethBrExtInfo.addPPPoETag && -+ priv->pppoe_connection_in_progress && -+ !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) -+ priv->pppoe_connection_in_progress = 0; -+ } -+ return 0; -+ case NAT25_LOOKUP: -+ if (ph->code == PADO_CODE || ph->code == PADS_CODE) { -+ if (priv->ethBrExtInfo.addPPPoETag) { -+ struct pppoe_tag *tag; -+ unsigned char *ptr; -+ unsigned short tagType, tagLen; -+ int offset = 0; -+ -+ ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); -+ if (ptr == NULL) { -+ DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n"); -+ return -1; -+ } -+ -+ tag = (struct pppoe_tag *)ptr; -+ tagType = (unsigned short)((ptr[0] << 8) + ptr[1]); -+ tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]); -+ -+ if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN))) { -+ DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen); -+ return -1; -+ } -+ -+ pMagic = (unsigned short *)tag->tag_data; -+ if (ntohs(*pMagic) != MAGIC_CODE) { -+ DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n", -+ (ph->code == PADO_CODE ? "PADO" : "PADS")); -+ return -1; -+ } -+ -+ memcpy(skb->data, tag->tag_data+MAGIC_CODE_LEN, ETH_ALEN); -+ -+ if (tagLen > MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN) -+ offset = TAG_HDR_LEN; -+ -+ if (skb_pull_and_merge(skb, ptr+offset, TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset) < 0) { -+ DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n"); -+ return -1; -+ } -+ ph->length = htons(ntohs(ph->length)-(TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset)); -+ if (offset > 0) -+ tag->tag_len = htons(tagLen-MAGIC_CODE_LEN-RTL_RELAY_TAG_LEN); -+ -+ DEBUG_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n", -+ (ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name); -+ } else { /* not add relay tag */ -+ if (!priv->pppoe_connection_in_progress) { -+ DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n"); -+ return -1; -+ } -+ memcpy(skb->data, priv->pppoe_addr, ETH_ALEN); -+ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; -+ } -+ } else { -+ if (ph->sid != 0) { -+ DEBUG_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name); -+ __nat25_generate_pppoe_network_addr(networkAddr, skb->data+ETH_ALEN, &(ph->sid)); -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ __nat25_db_print(priv); -+ } else { -+ return -1; -+ } -+ } -+ return 0; -+ default: -+ return -1; -+ } -+ } else if (protocol == 0x888e) { -+ /*---------------------------------------------------*/ -+ /* Handle EAP frame */ -+ /*---------------------------------------------------*/ -+ switch (method) { -+ case NAT25_CHECK: -+ return -1; -+ case NAT25_INSERT: -+ return 0; -+ case NAT25_LOOKUP: -+ return 0; -+ default: -+ return -1; -+ } -+ } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) { -+ /*---------------------------------------------------*/ -+ /* Handle C-Media proprietary frame */ -+ /*---------------------------------------------------*/ -+ switch (method) { -+ case NAT25_CHECK: -+ return -1; -+ case NAT25_INSERT: -+ return 0; -+ case NAT25_LOOKUP: -+ return 0; -+ default: -+ return -1; -+ } -+ } else if (protocol == ETH_P_IPV6) { -+ /*------------------------------------------------*/ -+ /* Handle IPV6 frame */ -+ /*------------------------------------------------*/ -+ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); -+ -+ if (sizeof(*iph) >= (skb->len - ETH_HLEN)) { -+ DEBUG_WARN("NAT25: malformed IPv6 packet !\n"); -+ return -1; -+ } -+ -+ switch (method) { -+ case NAT25_CHECK: -+ if (skb->data[0] & 1) -+ return 0; -+ return -1; -+ case NAT25_INSERT: -+ DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," -+ " DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", -+ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], -+ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], -+ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], -+ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); -+ -+ if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) { -+ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr); -+ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); -+ __nat25_db_print(priv); -+ -+ if (iph->nexthdr == IPPROTO_ICMPV6 && -+ skb->len > (ETH_HLEN + sizeof(*iph) + 4)) { -+ if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph), -+ skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) { -+ struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph)); -+ hdr->icmp6_cksum = 0; -+ hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr, -+ iph->payload_len, -+ IPPROTO_ICMPV6, -+ csum_partial((__u8 *)hdr, iph->payload_len, 0)); -+ } -+ } -+ } -+ return 0; -+ case NAT25_LOOKUP: -+ DEBUG_INFO("NAT25: Lookup IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x, DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", -+ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], -+ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], -+ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], -+ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); -+ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr); -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ return 0; -+ default: -+ return -1; -+ } -+ } -+ return -1; -+} -+ -+int nat25_handle_frame(struct adapter *priv, struct sk_buff *skb) -+{ -+ if (!(skb->data[0] & 1)) { -+ int is_vlan_tag = 0, i, retval = 0; -+ unsigned short vlan_hdr = 0; -+ unsigned short protocol; -+ -+ protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN))); -+ if (protocol == ETH_P_8021Q) { -+ is_vlan_tag = 1; -+ vlan_hdr = *((unsigned short *)(skb->data+ETH_ALEN*2+2)); -+ for (i = 0; i < 6; i++) -+ *((unsigned short *)(skb->data+ETH_ALEN*2+2-i*2)) = *((unsigned short *)(skb->data+ETH_ALEN*2-2-i*2)); -+ skb_pull(skb, 4); -+ } -+ -+ if (!priv->ethBrExtInfo.nat25_disable) { -+ spin_lock_bh(&priv->br_ext_lock); -+ /* -+ * This function look up the destination network address from -+ * the NAT2.5 database. Return value = -1 means that the -+ * corresponding network protocol is NOT support. -+ */ -+ if (!priv->ethBrExtInfo.nat25sc_disable && -+ (be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) && -+ !memcmp(priv->scdb_ip, skb->data+ETH_HLEN+16, 4)) { -+ memcpy(skb->data, priv->scdb_mac, ETH_ALEN); -+ -+ spin_unlock_bh(&priv->br_ext_lock); -+ } else { -+ spin_unlock_bh(&priv->br_ext_lock); -+ -+ retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); -+ } -+ } else { -+ if (((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) && -+ !memcmp(priv->br_ip, skb->data+ETH_HLEN+16, 4)) || -+ ((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_ARP) && -+ !memcmp(priv->br_ip, skb->data+ETH_HLEN+24, 4))) { -+ /* for traffic to upper TCP/IP */ -+ retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); -+ } -+ } -+ -+ if (is_vlan_tag) { -+ skb_push(skb, 4); -+ for (i = 0; i < 6; i++) -+ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2)); -+ *((__be16 *)(skb->data+ETH_ALEN*2)) = __constant_htons(ETH_P_8021Q); -+ *((unsigned short *)(skb->data+ETH_ALEN*2+2)) = vlan_hdr; -+ } -+ -+ if (retval == -1) { -+ /* DEBUG_ERR("NAT25: Lookup fail!\n"); */ -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+#define SERVER_PORT 67 -+#define CLIENT_PORT 68 -+#define DHCP_MAGIC 0x63825363 -+#define BROADCAST_FLAG 0x8000 -+ -+struct dhcpMessage { -+ u_int8_t op; -+ u_int8_t htype; -+ u_int8_t hlen; -+ u_int8_t hops; -+ u_int32_t xid; -+ u_int16_t secs; -+ u_int16_t flags; -+ u_int32_t ciaddr; -+ u_int32_t yiaddr; -+ u_int32_t siaddr; -+ u_int32_t giaddr; -+ u_int8_t chaddr[16]; -+ u_int8_t sname[64]; -+ u_int8_t file[128]; -+ u_int32_t cookie; -+ u_int8_t options[308]; /* 312 - cookie */ -+}; -+ -+void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb) -+{ -+ if (skb == NULL) -+ return; -+ -+ if (!priv->ethBrExtInfo.dhcp_bcst_disable) { -+ __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN)); -+ -+ if (protocol == __constant_htons(ETH_P_IP)) { /* IP */ -+ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); -+ -+ if (iph->protocol == IPPROTO_UDP) { /* UDP */ -+ struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2)); -+ -+ if ((udph->source == __constant_htons(CLIENT_PORT)) && -+ (udph->dest == __constant_htons(SERVER_PORT))) { /* DHCP request */ -+ struct dhcpMessage *dhcph = -+ (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr)); -+ u32 cookie = be32_to_cpu((__be32)dhcph->cookie); -+ -+ if (cookie == DHCP_MAGIC) { /* match magic word */ -+ if (!(dhcph->flags & htons(BROADCAST_FLAG))) { -+ /* if not broadcast */ -+ register int sum = 0; -+ -+ DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n"); -+ /* or BROADCAST flag */ -+ dhcph->flags |= htons(BROADCAST_FLAG); -+ /* recalculate checksum */ -+ sum = ~(udph->check) & 0xffff; -+ sum += be16_to_cpu(dhcph->flags); -+ while (sum >> 16) -+ sum = (sum & 0xffff) + (sum >> 16); -+ udph->check = ~sum; -+ } -+ } -+ } -+ } -+ } -+ } -+} -+ -+void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr, -+ unsigned char *ipAddr) -+{ -+ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; -+ struct nat25_network_db_entry *db; -+ int hash; -+ -+ __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr); -+ hash = __nat25_network_hash(networkAddr); -+ db = priv->nethash[hash]; -+ while (db != NULL) { -+ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { -+ return (void *)db; -+ } -+ -+ db = db->next_hash; -+ } -+ -+ return NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_cmd.c b/drivers/net/wireless/rtl8188eu/core/rtw_cmd.c -new file mode 100644 -index 0000000000000..421d49209d39e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_cmd.c -@@ -0,0 +1,2206 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_CMD_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+Caller and the rtw_cmd_thread can protect cmd_q by spin_lock. -+No irqsave is necessary. -+*/ -+ -+int _rtw_init_cmd_priv (struct cmd_priv *pcmdpriv) -+{ -+ int res = _SUCCESS; -+ -+ sema_init(&(pcmdpriv->cmd_queue_sema), 0); -+ /* sema_init(&(pcmdpriv->cmd_done_sema), 0); */ -+ sema_init(&(pcmdpriv->terminate_cmdthread_sema), 0); -+ -+ _rtw_init_queue(&(pcmdpriv->cmd_queue)); -+ -+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ -+ -+ pcmdpriv->cmd_seq = 1; -+ -+ pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ, -+ GFP_KERNEL); -+ -+ if (pcmdpriv->cmd_allocated_buf == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((size_t)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1)); -+ -+ pcmdpriv->rsp_allocated_buf = kzalloc(MAX_RSPSZ + 4, GFP_KERNEL); -+ -+ if (pcmdpriv->rsp_allocated_buf == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((size_t)(pcmdpriv->rsp_allocated_buf) & 3); -+ -+ pcmdpriv->cmd_issued_cnt = 0; -+ pcmdpriv->cmd_done_cnt = 0; -+ pcmdpriv->rsp_cnt = 0; -+exit: -+ -+ return res; -+} -+ -+static void c2h_wk_callback(struct work_struct *work); -+ -+int _rtw_init_evt_priv(struct evt_priv *pevtpriv) -+{ -+ int res = _SUCCESS; -+ -+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ -+ ATOMIC_SET(&pevtpriv->event_seq, 0); -+ pevtpriv->evt_done_cnt = 0; -+ -+ _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); -+ pevtpriv->c2h_wk_alive = false; -+ pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1); -+ -+ return res; -+} -+ -+void rtw_free_evt_priv(struct evt_priv *pevtpriv) -+{ -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+rtw_free_evt_priv\n")); -+ -+ _cancel_workitem_sync(&pevtpriv->c2h_wk); -+ while (pevtpriv->c2h_wk_alive) -+ rtw_msleep_os(10); -+ -+ while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) { -+ void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue); -+ if (c2h != NULL && c2h != (void *)pevtpriv) -+ kfree(c2h); -+ } -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("-rtw_free_evt_priv\n")); -+ -+} -+ -+void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv) -+{ -+ -+ if (pcmdpriv) { -+ _rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock)); -+ -+ if (pcmdpriv->cmd_allocated_buf) -+ kfree(pcmdpriv->cmd_allocated_buf); -+ -+ if (pcmdpriv->rsp_allocated_buf) -+ kfree(pcmdpriv->rsp_allocated_buf); -+ } -+ -+} -+ -+/* -+Calling Context: -+ -+rtw_enqueue_cmd can only be called between kernel thread, -+since only spin_lock is used. -+ -+ISR/Call-Back functions can't call this sub-function. -+ -+*/ -+ -+int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj) -+{ -+ unsigned long flags; -+ -+ if (obj == NULL) -+ goto exit; -+ -+ spin_lock_irqsave(&queue->lock, flags); -+ -+ list_add_tail(&obj->list, &queue->queue); -+ -+ spin_unlock_irqrestore(&queue->lock, flags); -+ -+exit: -+ -+ return _SUCCESS; -+} -+ -+struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue) -+{ -+ struct cmd_obj *obj; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&queue->lock, flags); -+ if (list_empty(&(queue->queue))) { -+ obj = NULL; -+ } else { -+ obj = container_of((&(queue->queue))->next, struct cmd_obj, list); -+ rtw_list_delete(&obj->list); -+ } -+ -+ spin_unlock_irqrestore(&queue->lock, flags); -+ -+ return obj; -+} -+ -+u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) -+{ -+ u32 res; -+ -+ res = _rtw_init_cmd_priv (pcmdpriv); -+ -+ return res; -+} -+ -+u32 rtw_init_evt_priv (struct evt_priv *pevtpriv) -+{ -+ int res; -+ -+ res = _rtw_init_evt_priv(pevtpriv); -+ -+ return res; -+} -+ -+void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) -+{ -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_cmd_priv\n")); -+ _rtw_free_cmd_priv(pcmdpriv); -+ -+} -+ -+static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) -+{ -+ u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */ -+ -+ /* To decide allow or not */ -+ if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) && -+ (!pcmdpriv->padapter->registrypriv.usbss_enable)) { -+ if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf; -+ if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID) -+ bAllow = true; -+ } -+ } -+ -+ if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) -+ bAllow = true; -+ -+ if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) || -+ !pcmdpriv->cmdthd_running) /* com_thread not running */ -+ return _FAIL; -+ return _SUCCESS; -+} -+ -+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) -+{ -+ int res = _FAIL; -+ struct adapter *padapter = pcmdpriv->padapter; -+ -+ if (cmd_obj == NULL) -+ goto exit; -+ -+ cmd_obj->padapter = padapter; -+ -+ res = rtw_cmd_filter(pcmdpriv, cmd_obj); -+ if (_FAIL == res) { -+ rtw_free_cmd_obj(cmd_obj); -+ goto exit; -+ } -+ -+ res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj); -+ -+ if (res == _SUCCESS) -+ up(&pcmdpriv->cmd_queue_sema); -+ -+exit: -+ -+ return res; -+} -+ -+struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) -+{ -+ struct cmd_obj *cmd_obj; -+ -+ cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue); -+ -+ return cmd_obj; -+} -+ -+void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv) -+{ -+ -+ pcmdpriv->cmd_done_cnt++; -+ /* up(&(pcmdpriv->cmd_done_sema)); */ -+ -+} -+ -+void rtw_free_cmd_obj(struct cmd_obj *pcmd) -+{ -+ -+ if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) { -+ /* free parmbuf in cmd_obj */ -+ kfree(pcmd->parmbuf); -+ } -+ -+ if (pcmd->rsp != NULL) { -+ if (pcmd->rspsz != 0) { -+ /* free rsp in cmd_obj */ -+ kfree(pcmd->rsp); -+ } -+ } -+ -+ /* free cmd_obj */ -+ kfree(pcmd); -+ -+} -+ -+int rtw_cmd_thread(void *context) -+{ -+ u8 ret; -+ struct cmd_obj *pcmd; -+ u8 *pcmdbuf; -+ u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf); -+ void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd); -+ struct adapter *padapter = (struct adapter *)context; -+ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); -+ -+ thread_enter("RTW_CMD_THREAD"); -+ -+ pcmdbuf = pcmdpriv->cmd_buf; -+ -+ pcmdpriv->cmdthd_running = true; -+ up(&pcmdpriv->terminate_cmdthread_sema); -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("start r871x rtw_cmd_thread !!!!\n")); -+ -+ while (1) { -+ if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL) -+ break; -+ -+ if (padapter->bDriverStopped || -+ padapter->bSurpriseRemoved) { -+ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", -+ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); -+ break; -+ } -+_next: -+ if (padapter->bDriverStopped || -+ padapter->bSurpriseRemoved) { -+ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", -+ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); -+ break; -+ } -+ -+ pcmd = rtw_dequeue_cmd(pcmdpriv); -+ if (!pcmd) -+ continue; -+ -+ if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) { -+ pcmd->res = H2C_DROPPED; -+ goto post_process; -+ } -+ -+ pcmdpriv->cmd_issued_cnt++; -+ -+ pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */ -+ -+ memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); -+ -+ if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) { -+ cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; -+ -+ if (cmd_hdl) { -+ ret = cmd_hdl(pcmd->padapter, pcmdbuf); -+ pcmd->res = ret; -+ } -+ -+ pcmdpriv->cmd_seq++; -+ } else { -+ pcmd->res = H2C_PARAMETERS_ERROR; -+ } -+ -+ cmd_hdl = NULL; -+ -+post_process: -+ -+ /* call callback function for post-processed */ -+ if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) { -+ pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; -+ if (pcmd_callback == NULL) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n", pcmd_callback, pcmd->cmdcode)); -+ rtw_free_cmd_obj(pcmd); -+ } else { -+ /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */ -+ pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */ -+ } -+ } else { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode)); -+ rtw_free_cmd_obj(pcmd); -+ } -+ -+ flush_signals_thread(); -+ -+ goto _next; -+ } -+ pcmdpriv->cmdthd_running = false; -+ -+ /* free all cmd_obj resources */ -+ do { -+ pcmd = rtw_dequeue_cmd(pcmdpriv); -+ if (pcmd == NULL) -+ break; -+ -+ /* DBG_88E("%s: leaving... drop cmdcode:%u\n", __func__, pcmd->cmdcode); */ -+ -+ rtw_free_cmd_obj(pcmd); -+ } while (1); -+ -+ up(&pcmdpriv->terminate_cmdthread_sema); -+ -+ thread_exit(); -+} -+ -+u8 rtw_setstandby_cmd(struct adapter *padapter, uint action) -+{ -+ struct cmd_obj *ph2c; -+ struct usb_suspend_parm *psetusbsuspend; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ u8 ret = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ psetusbsuspend = kzalloc(sizeof(struct usb_suspend_parm), GFP_ATOMIC); -+ if (psetusbsuspend == NULL) { -+ kfree(ph2c); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ psetusbsuspend->action = action; -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend)); -+ -+ ret = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return ret; -+} -+ -+/* -+rtw_sitesurvey_cmd(~) -+ ### NOTE:#### (!!!!) -+ MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock -+*/ -+u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num, -+ struct rtw_ieee80211_channel *ch, int ch_num) -+{ -+ u8 res = _FAIL; -+ struct cmd_obj *ph2c; -+ struct sitesurvey_parm *psurveyPara; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { -+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); -+ } -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { -+ p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1); -+ } -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) -+ return _FAIL; -+ -+ psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC); -+ if (psurveyPara == NULL) { -+ kfree(ph2c); -+ return _FAIL; -+ } -+ -+ rtw_free_network_queue(padapter, false); -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__)); -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); -+ -+ /* psurveyPara->bsslimit = 48; */ -+ psurveyPara->scan_mode = pmlmepriv->scan_mode; -+ -+ /* prepare ssid list */ -+ if (ssid) { -+ int i; -+ for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) { -+ if (ssid[i].SsidLength) { -+ memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid)); -+ psurveyPara->ssid_num++; -+ if (0) -+ DBG_88E(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter), -+ psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength); -+ } -+ } -+ } -+ -+ /* prepare channel list */ -+ if (ch) { -+ int i; -+ for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) { -+ if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) { -+ memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel)); -+ psurveyPara->ch_num++; -+ if (0) -+ DBG_88E(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), -+ psurveyPara->ch[i].hw_value); -+ } -+ } -+ } -+ -+ set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+ if (res == _SUCCESS) { -+ pmlmepriv->scan_start_time = jiffies; -+ -+ _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT); -+ -+ rtw_led_control(padapter, LED_CTL_SITE_SURVEY); -+ -+ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ -+ } else { -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); -+ } -+ -+ return res; -+} -+ -+u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset) -+{ -+ struct cmd_obj *ph2c; -+ struct setdatarate_parm *pbsetdataratepara; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pbsetdataratepara = kzalloc(sizeof(struct setdatarate_parm), GFP_ATOMIC); -+ if (pbsetdataratepara == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate)); -+ pbsetdataratepara->mac_id = 5; -+ memcpy(pbsetdataratepara->datarates, rateset, NumRates); -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset) -+{ -+ struct cmd_obj *ph2c; -+ struct setbasicrate_parm *pssetbasicratepara; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ pssetbasicratepara = kzalloc(sizeof(struct setbasicrate_parm), GFP_ATOMIC); -+ -+ if (pssetbasicratepara == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_); -+ -+ memcpy(pssetbasicratepara->basicrates, rateset, NumRates); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+/* -+unsigned char rtw_setphy_cmd(unsigned char *adapter) -+ -+1. be called only after rtw_update_registrypriv_dev_network(~) or mp testing program -+2. for AdHoc/Ap mode or mp mode? -+ -+*/ -+u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch) -+{ -+ struct cmd_obj *ph2c; -+ struct setphy_parm *psetphypara; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ psetphypara = kzalloc(sizeof(struct setphy_parm), GFP_ATOMIC); -+ -+ if (psetphypara == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_); -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("CH =%d, modem =%d", ch, modem)); -+ -+ psetphypara->modem = modem; -+ psetphypara->rfchannel = ch; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_setbbreg_cmd(struct adapter *padapter, u8 offset, u8 val) -+{ -+ struct cmd_obj *ph2c; -+ struct writeBB_parm *pwritebbparm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ pwritebbparm = kzalloc(sizeof(struct writeBB_parm), GFP_ATOMIC); -+ -+ if (pwritebbparm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg)); -+ -+ pwritebbparm->offset = offset; -+ pwritebbparm->value = val; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_getbbreg_cmd(struct adapter *padapter, u8 offset, u8 *pval) -+{ -+ struct cmd_obj *ph2c; -+ struct readBB_parm *prdbbparm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ prdbbparm = kzalloc(sizeof(struct readBB_parm), GFP_ATOMIC); -+ -+ if (prdbbparm == NULL) { -+ kfree(ph2c); -+ return _FAIL; -+ } -+ -+ INIT_LIST_HEAD(&ph2c->list); -+ ph2c->cmdcode = GEN_CMD_CODE(_GetBBReg); -+ ph2c->parmbuf = (unsigned char *)prdbbparm; -+ ph2c->cmdsz = sizeof(struct readBB_parm); -+ ph2c->rsp = pval; -+ ph2c->rspsz = sizeof(struct readBB_rsp); -+ -+ prdbbparm->offset = offset; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_setrfreg_cmd(struct adapter *padapter, u8 offset, u32 val) -+{ -+ struct cmd_obj *ph2c; -+ struct writeRF_parm *pwriterfparm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ pwriterfparm = kzalloc(sizeof(struct writeRF_parm), GFP_ATOMIC); -+ -+ if (pwriterfparm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); -+ -+ pwriterfparm->offset = offset; -+ pwriterfparm->value = val; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_getrfreg_cmd(struct adapter *padapter, u8 offset, u8 *pval) -+{ -+ struct cmd_obj *ph2c; -+ struct readRF_parm *prdrfparm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ prdrfparm = kzalloc(sizeof(struct readRF_parm), GFP_ATOMIC); -+ if (prdrfparm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ INIT_LIST_HEAD(&ph2c->list); -+ ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg); -+ ph2c->parmbuf = (unsigned char *)prdrfparm; -+ ph2c->cmdsz = sizeof(struct readRF_parm); -+ ph2c->rsp = pval; -+ ph2c->rspsz = sizeof(struct readRF_rsp); -+ -+ prdrfparm->offset = offset; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+} -+ -+void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ -+ -+ kfree(pcmd->parmbuf); -+ kfree(pcmd); -+ -+ if (padapter->registrypriv.mp_mode == 1) -+ padapter->mppriv.workparam.bcompleted = true; -+ -+} -+ -+void rtw_readtssi_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ -+ -+ kfree(pcmd->parmbuf); -+ kfree(pcmd); -+ -+ if (padapter->registrypriv.mp_mode == 1) -+ padapter->mppriv.workparam.bcompleted = true; -+ -+} -+ -+u8 rtw_createbss_cmd(struct adapter *padapter) -+{ -+ struct cmd_obj *pcmd; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network; -+ u8 res = _SUCCESS; -+ -+ rtw_led_control(padapter, LED_CTL_START_TO_LINK); -+ -+ if (pmlmepriv->assoc_ssid.SsidLength == 0) -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); -+ else -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); -+ -+ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (pcmd == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ INIT_LIST_HEAD(&pcmd->list); -+ pcmd->cmdcode = _CreateBss_CMD_; -+ pcmd->parmbuf = (unsigned char *)pdev_network; -+ pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); -+ pcmd->rsp = NULL; -+ pcmd->rspsz = 0; -+ pdev_network->Length = pcmd->cmdsz; -+ res = rtw_enqueue_cmd(pcmdpriv, pcmd); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_createbss_cmd_ex(struct adapter *padapter, unsigned char *pbss, unsigned int sz) -+{ -+ struct cmd_obj *pcmd; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (pcmd == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ INIT_LIST_HEAD(&pcmd->list); -+ pcmd->cmdcode = GEN_CMD_CODE(_CreateBss); -+ pcmd->parmbuf = pbss; -+ pcmd->cmdsz = sz; -+ pcmd->rsp = NULL; -+ pcmd->rspsz = 0; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, pcmd); -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) -+{ -+ u8 res = _SUCCESS; -+ uint t_len = 0; -+ struct wlan_bssid_ex *psecnetwork; -+ struct cmd_obj *pcmd; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct qos_priv *pqospriv = &pmlmepriv->qospriv; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ rtw_led_control(padapter, LED_CTL_START_TO_LINK); -+ -+ if (pmlmepriv->assoc_ssid.SsidLength == 0) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n")); -+ } else { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid)); -+ } -+ -+ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (pcmd == NULL) { -+ res = _FAIL; -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n")); -+ goto exit; -+ } -+ /* for IEs is fix buf size */ -+ t_len = sizeof(struct wlan_bssid_ex); -+ -+ /* for hidden ap to set fw_state here */ -+ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) { -+ switch (ndis_network_mode) { -+ case Ndis802_11IBSS: -+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); -+ break; -+ case Ndis802_11Infrastructure: -+ set_fwstate(pmlmepriv, WIFI_STATION_STATE); -+ break; -+ case Ndis802_11APMode: -+ case Ndis802_11AutoUnknown: -+ case Ndis802_11InfrastructureMax: -+ break; -+ } -+ } -+ -+ psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss; -+ if (psecnetwork == NULL) { -+ if (pcmd != NULL) -+ kfree(pcmd); -+ -+ res = _FAIL; -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd :psecnetwork == NULL!!!\n")); -+ -+ goto exit; -+ } -+ -+ memset(psecnetwork, 0, t_len); -+ -+ memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network)); -+ -+ psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength; -+ -+ if ((psecnetwork->IELength-12) < (256-1)) { -+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12); -+ } else { -+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1)); -+ } -+ -+ psecnetwork->IELength = 0; -+ /* Added by Albert 2009/02/18 */ -+ /* If the the driver wants to use the bssid to create the connection. */ -+ /* If not, we have to copy the connecting AP's MAC address to it so that */ -+ /* the driver just has the bssid information for PMKIDList searching. */ -+ -+ if (!pmlmepriv->assoc_by_bssid) -+ memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN); -+ -+ psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength); -+ -+ pqospriv->qos_option = 0; -+ -+ if (pregistrypriv->wmm_enable) { -+ u32 tmp_len; -+ -+ tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength); -+ -+ if (psecnetwork->IELength != tmp_len) { -+ psecnetwork->IELength = tmp_len; -+ pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */ -+ } else { -+ pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */ -+ } -+ } -+ -+ phtpriv->ht_option = false; -+ if (pregistrypriv->ht_enable) { -+ /* Added by Albert 2010/06/23 */ -+ /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */ -+ /* Especially for Realtek 8192u SoftAP. */ -+ if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) && -+ (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) && -+ (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) { -+ /* rtw_restructure_ht_ie */ -+ rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], -+ pnetwork->network.IELength, &psecnetwork->IELength); -+ } -+ } -+ -+ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength); -+ -+ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA) -+ padapter->pwrctrlpriv.smart_ps = 0; -+ else -+ padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps; -+ -+ DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps); -+ -+ pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */ -+ -+ INIT_LIST_HEAD(&pcmd->list); -+ pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ -+ pcmd->parmbuf = (unsigned char *)psecnetwork; -+ pcmd->rsp = NULL; -+ pcmd->rspsz = 0; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, pcmd); -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */ -+{ -+ struct cmd_obj *cmdobj = NULL; -+ struct disconnect_parm *param = NULL; -+ struct cmd_priv *cmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n")); -+ -+ /* prepare cmd parameter */ -+ param = kzalloc(sizeof(*param), GFP_ATOMIC); -+ if (param == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ param->deauth_timeout_ms = deauth_timeout_ms; -+ -+ if (enqueue) { -+ /* need enqueue, prepare cmd_obj and enqueue */ -+ cmdobj = kzalloc(sizeof(*cmdobj), GFP_ATOMIC); -+ if (cmdobj == NULL) { -+ res = _FAIL; -+ kfree(param); -+ goto exit; -+ } -+ init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); -+ res = rtw_enqueue_cmd(cmdpriv, cmdobj); -+ } else { -+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ -+ if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param)) -+ res = _FAIL; -+ kfree(param); -+ } -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra networktype) -+{ -+ struct cmd_obj *ph2c; -+ struct setopmode_parm *psetop; -+ -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (ph2c == NULL) { -+ res = false; -+ goto exit; -+ } -+ psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL); -+ -+ if (psetop == NULL) { -+ kfree(ph2c); -+ res = false; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); -+ psetop->mode = (u8)networktype; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key) -+{ -+ struct cmd_obj *ph2c; -+ struct set_stakey_parm *psetstakey_para; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct set_stakey_rsp *psetstakey_rsp = NULL; -+ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct sta_info *sta = (struct sta_info *)psta; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL); -+ if (psetstakey_para == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL); -+ if (psetstakey_rsp == NULL) { -+ kfree(ph2c); -+ kfree(psetstakey_para); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); -+ ph2c->rsp = (u8 *)psetstakey_rsp; -+ ph2c->rspsz = sizeof(struct set_stakey_rsp); -+ -+ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); -+ -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) -+ psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm; -+ else -+ GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false); -+ -+ if (unicast_key) -+ memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); -+ else -+ memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); -+ -+ /* jeff: set this because at least sw key is ready */ -+ padapter->securitypriv.busetkipkey = true; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue) -+{ -+ struct cmd_obj *ph2c; -+ struct set_stakey_parm *psetstakey_para; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct set_stakey_rsp *psetstakey_rsp = NULL; -+ struct sta_info *sta = (struct sta_info *)psta; -+ u8 res = _SUCCESS; -+ -+ if (!enqueue) { -+ clear_cam_entry(padapter, entry); -+ } else { -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), -+ GFP_ATOMIC); -+ if (psetstakey_para == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), -+ GFP_ATOMIC); -+ if (psetstakey_rsp == NULL) { -+ kfree(ph2c); -+ kfree(psetstakey_para); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); -+ ph2c->rsp = (u8 *)psetstakey_rsp; -+ ph2c->rspsz = sizeof(struct set_stakey_rsp); -+ -+ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); -+ -+ psetstakey_para->algorithm = _NO_PRIVACY_; -+ -+ psetstakey_para->id = entry; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ } -+exit: -+ -+ return res; -+} -+ -+u8 rtw_setrttbl_cmd(struct adapter *padapter, struct setratable_parm *prate_table) -+{ -+ struct cmd_obj *ph2c; -+ struct setratable_parm *psetrttblparm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ psetrttblparm = kzalloc(sizeof(struct setratable_parm), GFP_KERNEL); -+ -+ if (psetrttblparm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); -+ -+ memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_getrttbl_cmd(struct adapter *padapter, struct getratable_rsp *pval) -+{ -+ struct cmd_obj *ph2c; -+ struct getratable_parm *pgetrttblparm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ pgetrttblparm = kzalloc(sizeof(struct getratable_parm), GFP_KERNEL); -+ -+ if (pgetrttblparm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+/* init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */ -+ -+ INIT_LIST_HEAD(&ph2c->list); -+ ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable); -+ ph2c->parmbuf = (unsigned char *)pgetrttblparm; -+ ph2c->cmdsz = sizeof(struct getratable_parm); -+ ph2c->rsp = (u8 *)pval; -+ ph2c->rspsz = sizeof(struct getratable_rsp); -+ -+ pgetrttblparm->rsvd = 0x0; -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_setassocsta_cmd(struct adapter *padapter, u8 *mac_addr) -+{ -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct cmd_obj *ph2c; -+ struct set_assocsta_parm *psetassocsta_para; -+ struct set_stakey_rsp *psetassocsta_rsp = NULL; -+ -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ psetassocsta_para = kzalloc(sizeof(struct set_assocsta_parm), GFP_ATOMIC); -+ if (psetassocsta_para == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ psetassocsta_rsp = kzalloc(sizeof(struct set_assocsta_rsp), GFP_ATOMIC); -+ if (psetassocsta_rsp == NULL) { -+ kfree(ph2c); -+ kfree(psetassocsta_para); -+ return _FAIL; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_); -+ ph2c->rsp = (u8 *)psetassocsta_rsp; -+ ph2c->rspsz = sizeof(struct set_assocsta_rsp); -+ -+ memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+ } -+ -+u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr) -+{ -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct cmd_obj *ph2c; -+ struct addBaReq_parm *paddbareq_parm; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_KERNEL); -+ if (paddbareq_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ paddbareq_parm->tid = tid; -+ memcpy(paddbareq_parm->addr, addr, ETH_ALEN); -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); -+ -+ /* DBG_88E("rtw_addbareq_cmd, tid =%d\n", tid); */ -+ -+ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID; -+ pdrvextra_cmd_parm->type_size = 0; -+ pdrvextra_cmd_parm->pbuf = (u8 *)padapter; -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue) -+{ -+ struct cmd_obj *pcmdobj; -+ struct set_ch_parm *set_ch_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ u8 res = _SUCCESS; -+ -+ DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", -+ FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset); -+ -+ /* check input parameter */ -+ -+ /* prepare cmd parameter */ -+ set_ch_parm = kzalloc(sizeof(*set_ch_parm), GFP_ATOMIC); -+ if (set_ch_parm == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ set_ch_parm->ch = ch; -+ set_ch_parm->bw = bw; -+ set_ch_parm->ch_offset = ch_offset; -+ -+ if (enqueue) { -+ /* need enqueue, prepare cmd_obj and enqueue */ -+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (pcmdobj == NULL) { -+ kfree(set_ch_parm); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel)); -+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); -+ } else { -+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ -+ if (H2C_SUCCESS != set_ch_hdl(padapter, (u8 *)set_ch_parm)) -+ res = _FAIL; -+ -+ kfree(set_ch_parm); -+ } -+ -+ /* do something based on res... */ -+ -+exit: -+ -+ DBG_88E(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res); -+ -+ return res; -+} -+ -+u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue) -+{ -+ struct cmd_obj *pcmdobj; -+ struct SetChannelPlan_param *setChannelPlan_param; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ u8 res = _SUCCESS; -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n")); -+ -+ /* check input parameter */ -+ if (!rtw_is_channel_plan_valid(chplan)) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ /* prepare cmd parameter */ -+ setChannelPlan_param = kzalloc(sizeof(struct SetChannelPlan_param), -+ GFP_KERNEL); -+ if (setChannelPlan_param == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ setChannelPlan_param->channel_plan = chplan; -+ -+ if (enqueue) { -+ /* need enqueue, prepare cmd_obj and enqueue */ -+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (pcmdobj == NULL) { -+ kfree(setChannelPlan_param); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan)); -+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); -+ } else { -+ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ -+ if (H2C_SUCCESS != set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param)) -+ res = _FAIL; -+ -+ kfree(setChannelPlan_param); -+ } -+ -+ /* do something based on res... */ -+ if (res == _SUCCESS) -+ padapter->mlmepriv.ChannelPlan = chplan; -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed) -+{ -+ struct cmd_obj *pcmdobj; -+ struct LedBlink_param *ledBlink_param; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ u8 res = _SUCCESS; -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n")); -+ -+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (pcmdobj == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ ledBlink_param = kzalloc(sizeof(struct LedBlink_param), GFP_ATOMIC); -+ if (ledBlink_param == NULL) { -+ kfree(pcmdobj); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ ledBlink_param->pLed = pLed; -+ -+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink)); -+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no) -+{ -+ struct cmd_obj *pcmdobj; -+ struct SetChannelSwitch_param *setChannelSwitch_param; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ u8 res = _SUCCESS; -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n")); -+ -+ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (pcmdobj == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ setChannelSwitch_param = kzalloc(sizeof(struct SetChannelSwitch_param), -+ GFP_ATOMIC); -+ if (setChannelSwitch_param == NULL) { -+ kfree(pcmdobj); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ setChannelSwitch_param->new_ch_no = new_ch_no; -+ -+ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch)); -+ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); -+ -+exit: -+ -+ return res; -+} -+ -+u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option) -+{ -+ return _SUCCESS; -+} -+ -+static void traffic_status_watchdog(struct adapter *padapter) -+{ -+ u8 bEnterPS; -+ u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false; -+ u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ /* */ -+ /* Determine if our traffic is busy now */ -+ /* */ -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 || -+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) { -+ bBusyTraffic = true; -+ -+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) -+ bRxBusyTraffic = true; -+ else -+ bTxBusyTraffic = true; -+ } -+ -+ /* Higher Tx/Rx data. */ -+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 || -+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) { -+ bHigherBusyTraffic = true; -+ -+ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) -+ bHigherBusyRxTraffic = true; -+ else -+ bHigherBusyTxTraffic = true; -+ } -+ -+ /* check traffic for powersaving. */ -+ if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) || -+ (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) -+ bEnterPS = false; -+ else -+ bEnterPS = true; -+ -+ /* LeisurePS only work in infra mode. */ -+ if (bEnterPS) -+ LPS_Enter(padapter); -+ else -+ LPS_Leave(padapter); -+ } else { -+ LPS_Leave(padapter); -+ } -+ -+ pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0; -+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0; -+ pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; -+ pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic; -+ pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic; -+ pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic; -+ pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; -+ pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; -+ pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; -+} -+ -+static void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz) -+{ -+ struct mlme_priv *pmlmepriv; -+ -+ padapter = (struct adapter *)pbuf; -+ pmlmepriv = &(padapter->mlmepriv); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) -+ expire_timeout_chk(padapter); -+#endif -+ -+ rtw_hal_sreset_xmit_status_check(padapter); -+ -+ linked_status_chk(padapter); -+ traffic_status_watchdog(padapter); -+ -+ rtw_hal_dm_watchdog(padapter); -+} -+ -+static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ u8 mstatus; -+ -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) -+ return; -+ -+ switch (lps_ctrl_type) { -+ case LPS_CTRL_SCAN: -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { -+ /* connect */ -+ LPS_Leave(padapter); -+ } -+ break; -+ case LPS_CTRL_JOINBSS: -+ LPS_Leave(padapter); -+ break; -+ case LPS_CTRL_CONNECT: -+ mstatus = 1;/* connect */ -+ /* Reset LPS Setting */ -+ padapter->pwrctrlpriv.LpsIdleCount = 0; -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); -+ break; -+ case LPS_CTRL_DISCONNECT: -+ mstatus = 0;/* disconnect */ -+ LPS_Leave(padapter); -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); -+ break; -+ case LPS_CTRL_SPECIAL_PACKET: -+ /* DBG_88E("LPS_CTRL_SPECIAL_PACKET\n"); */ -+ pwrpriv->DelayLPSLastTimeStamp = jiffies; -+ LPS_Leave(padapter); -+ break; -+ case LPS_CTRL_LEAVE: -+ LPS_Leave(padapter); -+ break; -+ default: -+ break; -+ } -+ -+} -+ -+u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ /* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */ -+ u8 res = _SUCCESS; -+ -+ /* if (!pwrctrlpriv->bLeisurePs) */ -+ /* return res; */ -+ -+ if (enqueue) { -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), -+ GFP_ATOMIC); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID; -+ pdrvextra_cmd_parm->type_size = lps_ctrl_type; -+ pdrvextra_cmd_parm->pbuf = NULL; -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ } else { -+ lps_ctrl_wk_hdl(padapter, lps_ctrl_type); -+ } -+ -+exit: -+ -+ return res; -+} -+ -+static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time) -+{ -+ rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time)); -+} -+ -+u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), -+ GFP_ATOMIC); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID; -+ pdrvextra_cmd_parm->type_size = min_time; -+ pdrvextra_cmd_parm->pbuf = NULL; -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ -+ return res; -+} -+ -+static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna) -+{ -+ rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna)); -+} -+ -+u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 support_ant_div; -+ u8 res = _SUCCESS; -+ -+ rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div); -+ if (!support_ant_div) -+ return res; -+ -+ if (enqueue) { -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), -+ GFP_KERNEL); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID; -+ pdrvextra_cmd_parm->type_size = antenna; -+ pdrvextra_cmd_parm->pbuf = NULL; -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ } else { -+ antenna_select_wk_hdl(padapter, antenna); -+ } -+exit: -+ -+ return res; -+} -+ -+static void power_saving_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz) -+{ -+ rtw_ps_processor(padapter); -+} -+ -+#ifdef CONFIG_88EU_P2P -+u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return res; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID; -+ pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */ -+ pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */ -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+} -+#endif /* CONFIG_88EU_P2P */ -+ -+u8 rtw_ps_cmd(struct adapter *padapter) -+{ -+ struct cmd_obj *ppscmd; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ u8 res = _SUCCESS; -+ -+ ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ppscmd == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ppscmd); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID; -+ pdrvextra_cmd_parm->pbuf = NULL; -+ init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ppscmd); -+ -+exit: -+ -+ return res; -+} -+ -+#ifdef CONFIG_88EU_AP_MODE -+ -+static void rtw_chk_hi_queue_hdl(struct adapter *padapter) -+{ -+ int cnt = 0; -+ struct sta_info *psta_bmc; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ psta_bmc = rtw_get_bcmc_stainfo(padapter); -+ if (!psta_bmc) -+ return; -+ -+ if (psta_bmc->sleepq_len == 0) { -+ u8 val = 0; -+ -+ /* while ((rtw_read32(padapter, 0x414)&0x00ffff00)!= 0) */ -+ /* while ((rtw_read32(padapter, 0x414)&0x0000ff00)!= 0) */ -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); -+ -+ while (!val) { -+ rtw_msleep_os(100); -+ -+ cnt++; -+ -+ if (cnt > 10) -+ break; -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); -+ } -+ -+ if (cnt <= 10) { -+ pstapriv->tim_bitmap &= ~BIT(0); -+ pstapriv->sta_dz_bitmap &= ~BIT(0); -+ -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+ } else { /* re check again */ -+ rtw_chk_hi_queue_cmd(padapter); -+ } -+ } -+} -+ -+u8 rtw_chk_hi_queue_cmd(struct adapter *padapter) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID; -+ pdrvextra_cmd_parm->type_size = 0; -+ pdrvextra_cmd_parm->pbuf = NULL; -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+exit: -+ return res; -+} -+#endif -+ -+u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = C2H_WK_CID; -+ pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0; -+ pdrvextra_cmd_parm->pbuf = c2h_evt; -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+} -+ -+static s32 c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter) -+{ -+ s32 ret = _FAIL; -+ u8 buf[16]; -+ -+ if (!c2h_evt) { -+ /* No c2h event in cmd_obj, read c2h event before handling*/ -+ if (c2h_evt_read(adapter, buf) == _SUCCESS) { -+ c2h_evt = (struct c2h_evt_hdr *)buf; -+ -+ if (filter && filter(c2h_evt->id) == false) -+ goto exit; -+ -+ ret = rtw_hal_c2h_handler(adapter, c2h_evt); -+ } -+ } else { -+ if (filter && filter(c2h_evt->id) == false) -+ goto exit; -+ -+ ret = rtw_hal_c2h_handler(adapter, c2h_evt); -+ } -+exit: -+ return ret; -+} -+ -+static void c2h_wk_callback(struct work_struct *work) -+{ -+ struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); -+ struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv); -+ struct c2h_evt_hdr *c2h_evt; -+ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter); -+ -+ evtpriv->c2h_wk_alive = true; -+ -+ while (!rtw_cbuf_empty(evtpriv->c2h_queue)) { -+ if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) { -+ /* This C2H event is read, clear it */ -+ c2h_evt_clear(adapter); -+ } else if ((c2h_evt = (struct c2h_evt_hdr *)rtw_malloc(16)) != NULL) { -+ /* This C2H event is not read, read & clear now */ -+ if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS) -+ continue; -+ } -+ -+ /* Special pointer to trigger c2h_evt_clear only */ -+ if ((void *)c2h_evt == (void *)evtpriv) -+ continue; -+ -+ if (!c2h_evt_exist(c2h_evt)) { -+ kfree(c2h_evt); -+ continue; -+ } -+ -+ if (ccx_id_filter(c2h_evt->id) == true) { -+ /* Handle CCX report here */ -+ rtw_hal_c2h_handler(adapter, c2h_evt); -+ kfree(c2h_evt); -+ } else { -+#ifdef CONFIG_88EU_P2P -+ /* Enqueue into cmd_thread for others */ -+ rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt); -+#endif -+ } -+ } -+ -+ evtpriv->c2h_wk_alive = false; -+} -+ -+u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ struct drvextra_cmd_parm *pdrvextra_cmd; -+ -+ if (!pbuf) -+ return H2C_PARAMETERS_ERROR; -+ -+ pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf; -+ -+ switch (pdrvextra_cmd->ec_id) { -+ case DYNAMIC_CHK_WK_CID: -+ dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); -+ break; -+ case POWER_SAVING_CTRL_WK_CID: -+ power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); -+ break; -+ case LPS_CTRL_WK_CID: -+ lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size); -+ break; -+ case RTP_TIMER_CFG_WK_CID: -+ rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size); -+ break; -+ case ANT_SELECT_WK_CID: -+ antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size); -+ break; -+#ifdef CONFIG_88EU_P2P -+ case P2P_PS_WK_CID: -+ p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size); -+ break; -+ case P2P_PROTO_WK_CID: -+ /* Commented by Albert 2011/07/01 */ -+ /* I used the type_size as the type command */ -+ p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size); -+ break; -+#endif -+#ifdef CONFIG_88EU_AP_MODE -+ case CHECK_HIQ_WK_CID: -+ rtw_chk_hi_queue_hdl(padapter); -+ break; -+#endif /* CONFIG_88EU_AP_MODE */ -+ case C2H_WK_CID: -+ c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL); -+ break; -+ default: -+ break; -+ } -+ -+ if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0) -+ kfree(pdrvextra_cmd->pbuf); -+ -+ return H2C_SUCCESS; -+} -+ -+void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ if (pcmd->res == H2C_DROPPED) { -+ /* TODO: cancel timer and do timeout handler directly... */ -+ /* need to make timeout handlerOS independent */ -+ _set_timer(&pmlmepriv->scan_to_timer, 1); -+ } else if (pcmd->res != H2C_SUCCESS) { -+ _set_timer(&pmlmepriv->scan_to_timer, 1); -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n.")); -+ } -+ -+ /* free cmd */ -+ rtw_free_cmd_obj(pcmd); -+ -+} -+void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ if (pcmd->res != H2C_SUCCESS) { -+ spin_lock_bh(&pmlmepriv->lock); -+ set_fwstate(pmlmepriv, _FW_LINKED); -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n.")); -+ return; -+ } else /* clear bridge database */ -+ nat25_db_cleanup(padapter); -+ -+ /* free cmd */ -+ rtw_free_cmd_obj(pcmd); -+} -+ -+void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ if (pcmd->res == H2C_DROPPED) { -+ /* TODO: cancel timer and do timeout handler directly... */ -+ /* need to make timeout handlerOS independent */ -+ _set_timer(&pmlmepriv->assoc_timer, 1); -+ } else if (pcmd->res != H2C_SUCCESS) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("********Error:rtw_select_and_join_from_scanned_queue Wait Sema Fail ************\n")); -+ _set_timer(&pmlmepriv->assoc_timer, 1); -+ } -+ -+ rtw_free_cmd_obj(pcmd); -+} -+ -+void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ u8 timer_cancelled; -+ struct sta_info *psta = NULL; -+ struct wlan_network *pwlan = NULL; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf; -+ struct wlan_network *tgt_network = &(pmlmepriv->cur_network); -+ -+ if ((pcmd->res != H2C_SUCCESS)) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: rtw_createbss_cmd_callback Fail ************\n\n.")); -+ _set_timer(&pmlmepriv->assoc_timer, 1); -+ } -+ -+ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress); -+ if (!psta) { -+ psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); -+ if (psta == NULL) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nCan't alloc sta_info when createbss_cmd_callback\n")); -+ goto createbss_cmd_fail ; -+ } -+ } -+ -+ rtw_indicate_connect(padapter); -+ } else { -+ -+ pwlan = _rtw_alloc_network(pmlmepriv); -+ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); -+ if (pwlan == NULL) { -+ pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); -+ if (pwlan == NULL) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n Error: can't get pwlan in rtw_joinbss_event_callback\n")); -+ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); -+ goto createbss_cmd_fail; -+ } -+ pwlan->last_scanned = jiffies; -+ } else { -+ list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); -+ } -+ -+ pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork); -+ memcpy(&(pwlan->network), pnetwork, pnetwork->Length); -+ -+ memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork))); -+ -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ -+ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); -+ /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */ -+ } -+ -+createbss_cmd_fail: -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+ rtw_free_cmd_obj(pcmd); -+ -+} -+ -+void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp); -+ struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr); -+ -+ if (psta == NULL) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info\n\n")); -+ goto exit; -+ } -+exit: -+ rtw_free_cmd_obj(pcmd); -+ -+} -+ -+void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) -+{ -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf); -+ struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp); -+ struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr); -+ -+ if (psta == NULL) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info\n\n")); -+ goto exit; -+ } -+ -+ psta->aid = passocsta_rsp->cam_id; -+ psta->mac_id = passocsta_rsp->cam_id; -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)) -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ -+ set_fwstate(pmlmepriv, _FW_LINKED); -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+exit: -+ rtw_free_cmd_obj(pcmd); -+ -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_debug.c b/drivers/net/wireless/rtl8188eu/core/rtw_debug.c -new file mode 100644 -index 0000000000000..47e5f7cf84535 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_debug.c -@@ -0,0 +1,943 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_DEBUG_C_ -+ -+#include -+#include -+ -+int proc_get_drv_version(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "%s\n", DRIVERVERSION); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_write_reg(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ *eof = 1; -+ return 0; -+} -+ -+int proc_set_write_reg(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ char tmp[32]; -+ u32 addr, val, len; -+ -+ if (count < 3) { -+ DBG_88E("argument size is less than 3\n"); -+ return -EFAULT; -+ } -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ int num = sscanf(tmp, "%x %x %x", &addr, &val, &len); -+ -+ if (num != 3) { -+ DBG_88E("invalid write_reg parameter!\n"); -+ return count; -+ } -+ switch (len) { -+ case 1: -+ rtw_write8(padapter, addr, (u8)val); -+ break; -+ case 2: -+ rtw_write16(padapter, addr, (u16)val); -+ break; -+ case 4: -+ rtw_write32(padapter, addr, val); -+ break; -+ default: -+ DBG_88E("error write length =%d", len); -+ break; -+ } -+ } -+ return count; -+} -+ -+static u32 proc_get_read_addr = 0xeeeeeeee; -+static u32 proc_get_read_len = 0x4; -+ -+int proc_get_read_reg(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ -+ int len = 0; -+ -+ if (proc_get_read_addr == 0xeeeeeeee) { -+ *eof = 1; -+ return len; -+ } -+ -+ switch (proc_get_read_len) { -+ case 1: -+ len += snprintf(page + len, count - len, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr)); -+ break; -+ case 2: -+ len += snprintf(page + len, count - len, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr)); -+ break; -+ case 4: -+ len += snprintf(page + len, count - len, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr)); -+ break; -+ default: -+ len += snprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len); -+ break; -+ } -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_set_read_reg(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ char tmp[16]; -+ u32 addr, len; -+ -+ if (count < 2) { -+ DBG_88E("argument size is less than 2\n"); -+ return -EFAULT; -+ } -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ int num = sscanf(tmp, "%x %x", &addr, &len); -+ -+ if (num != 2) { -+ DBG_88E("invalid read_reg parameter!\n"); -+ return count; -+ } -+ -+ proc_get_read_addr = addr; -+ -+ proc_get_read_len = len; -+ } -+ -+ return count; -+} -+ -+int proc_get_fwstate(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "fwstate=0x%x\n", get_fwstate(pmlmepriv)); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_sec_info(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", -+ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, -+ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_mlmext_state(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_qos_option(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "qos_option=%d\n", pmlmepriv->qospriv.qos_option); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_ht_option(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ int len = 0; -+ len += snprintf(page + len, count - len, "ht_option=%d\n", pmlmepriv->htpriv.ht_option); -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_rf_info(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n", -+ pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_ap_info(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct sta_info *psta; -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct wlan_network *cur_network = &(pmlmepriv->cur_network); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ int len = 0; -+ -+ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); -+ if (psta) { -+ int i; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ -+ len += snprintf(page + len, count - len, "SSID=%s\n", cur_network->network.Ssid.Ssid); -+ len += snprintf(page + len, count - len, "sta's macaddr:%pM\n", psta->hwaddr); -+ len += snprintf(page + len, count - len, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); -+ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); -+ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); -+ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); -+ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); -+ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); -+ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); -+ -+ for (i = 0; i < 16; i++) { -+ preorder_ctrl = &psta->recvreorder_ctrl[i]; -+ if (preorder_ctrl->enable) -+ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", i, preorder_ctrl->indicate_seq); -+ } -+ } else { -+ len += snprintf(page + len, count - len, "can't get sta's macaddr, cur_network's macaddr: %pM\n", cur_network->network.MacAddress); -+ } -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_adapter_state(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n", -+ padapter->bSurpriseRemoved, padapter->bDriverStopped); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_trx_info(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d, free_ext_xmitbuf_cnt=%d, free_recvframe_cnt=%d\n", -+ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt, precvpriv->free_recvframe_cnt); -+ len += snprintf(page + len, count - len, "rx_urb_pending_cn=%d\n", precvpriv->rx_pending_cnt); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_mac_reg_dump1(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1; -+ -+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); -+ -+ for (i = 0x0; i < 0x300; i += 4) { -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_mac_reg_dump2(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1; -+ -+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); -+ memset(page, 0, count); -+ for (i = 0x300; i < 0x600; i += 4) { -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_mac_reg_dump3(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1; -+ -+ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); -+ -+ for (i = 0x600; i < 0x800; i += 4) { -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_bb_reg_dump1(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1; -+ -+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); -+ for (i = 0x800; i < 0xB00; i += 4) { -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_bb_reg_dump2(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1; -+ -+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); -+ for (i = 0xB00; i < 0xE00; i += 4) { -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_bb_reg_dump3(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1; -+ -+ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); -+ for (i = 0xE00; i < 0x1000; i += 4) { -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_rf_reg_dump1(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1, path; -+ u32 value; -+ -+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); -+ path = 1; -+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); -+ for (i = 0; i < 0xC0; i++) { -+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x ", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", value); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_rf_reg_dump2(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1, path; -+ u32 value; -+ -+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); -+ path = 1; -+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); -+ for (i = 0xC0; i < 0x100; i++) { -+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x ", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", value); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_rf_reg_dump3(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1, path; -+ u32 value; -+ -+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); -+ path = 2; -+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); -+ for (i = 0; i < 0xC0; i++) { -+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x ", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", value); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_rf_reg_dump4(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ int i, j = 1, path; -+ u32 value; -+ -+ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); -+ path = 2; -+ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); -+ for (i = 0xC0; i < 0x100; i++) { -+ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); -+ if (j%4 == 1) -+ len += snprintf(page + len, count - len, "0x%02x ", i); -+ len += snprintf(page + len, count - len, " 0x%08x ", value); -+ if ((j++)%4 == 0) -+ len += snprintf(page + len, count - len, "\n"); -+ } -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_rx_signal(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ int len = 0; -+ -+ len = snprintf(page + len, count, -+ "rssi:%d\n" -+ "rxpwdb:%d\n" -+ "signal_strength:%u\n" -+ "signal_qual:%u\n" -+ "noise:%u\n", -+ padapter->recvpriv.rssi, -+ padapter->recvpriv.rxpwdb, -+ padapter->recvpriv.signal_strength, -+ padapter->recvpriv.signal_qual, -+ padapter->recvpriv.noise -+ ); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_set_rx_signal(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ char tmp[32]; -+ u32 is_signal_dbg; -+ s32 signal_strength; -+ -+ if (count < 1) -+ return -EFAULT; -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength); -+ is_signal_dbg = is_signal_dbg == 0 ? 0 : 1; -+ if (is_signal_dbg && num != 2) -+ return count; -+ -+ signal_strength = signal_strength > 100 ? 100 : signal_strength; -+ signal_strength = signal_strength < 0 ? 0 : signal_strength; -+ -+ padapter->recvpriv.is_signal_dbg = is_signal_dbg; -+ padapter->recvpriv.signal_strength_dbg = signal_strength; -+ -+ if (is_signal_dbg) -+ DBG_88E("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength); -+ else -+ DBG_88E("set %s\n", "HW_SIGNAL_STRENGTH"); -+ } -+ return count; -+} -+ -+int proc_get_ht_enable(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ int len = 0; -+ -+ if (pregpriv) -+ len += snprintf(page + len, count - len, -+ "%d\n", -+ pregpriv->ht_enable -+ ); -+ *eof = 1; -+ return len; -+} -+ -+int proc_set_ht_enable(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ char tmp[32]; -+ s32 mode = 0; -+ -+ if (count < 1) -+ return -EFAULT; -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ if (pregpriv) { -+ pregpriv->ht_enable = mode; -+ pr_info("ht_enable=%d\n", pregpriv->ht_enable); -+ } -+ } -+ -+ return count; -+} -+ -+int proc_get_cbw40_enable(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ -+ int len = 0; -+ -+ if (pregpriv) -+ len += snprintf(page + len, count - len, -+ "%d\n", -+ pregpriv->cbw40_enable -+ ); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_set_cbw40_enable(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ char tmp[32]; -+ s32 mode = 0; -+ -+ if (count < 1) -+ return -EFAULT; -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ if (pregpriv) { -+ pregpriv->cbw40_enable = mode; -+ pr_info("cbw40_enable=%d\n", mode); -+ } -+ } -+ return count; -+} -+ -+int proc_get_ampdu_enable(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ -+ int len = 0; -+ -+ if (pregpriv) -+ len += snprintf(page + len, count - len, -+ "%d\n", -+ pregpriv->ampdu_enable -+ ); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_set_ampdu_enable(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ char tmp[32]; -+ s32 mode = 0; -+ -+ if (count < 1) -+ return -EFAULT; -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ if (pregpriv) { -+ pregpriv->ampdu_enable = mode; -+ pr_info("ampdu_enable=%d\n", mode); -+ } -+ } -+ return count; -+} -+ -+int proc_get_two_path_rssi(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ -+ int len = 0; -+ -+ if (padapter) -+ len += snprintf(page + len, count - len, -+ "%d %d\n", -+ padapter->recvpriv.RxRssi[0], -+ padapter->recvpriv.RxRssi[1] -+ ); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_get_rx_stbc(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ -+ int len = 0; -+ -+ if (pregpriv) -+ len += snprintf(page + len, count - len, -+ "%d\n", -+ pregpriv->rx_stbc -+ ); -+ -+ *eof = 1; -+ return len; -+} -+ -+int proc_set_rx_stbc(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ char tmp[32]; -+ u32 mode = 0; -+ -+ if (count < 1) -+ return -EFAULT; -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ if (pregpriv) { -+ pregpriv->rx_stbc = mode; -+ printk("rx_stbc=%d\n", mode); -+ } -+ } -+ return count; -+} -+ -+int proc_get_rssi_disp(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ *eof = 1; -+ return 0; -+} -+ -+int proc_set_rssi_disp(struct file *file, const char __user *buffer, -+ unsigned long count, void *data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ char tmp[32]; -+ u32 enable = 0; -+ -+ if (count < 1) { -+ DBG_88E("argument size is less than 1\n"); -+ return -EFAULT; -+ } -+ -+ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { -+ int num = sscanf(tmp, "%x", &enable); -+ -+ if (num != 1) { -+ DBG_88E("invalid set_rssi_disp parameter!\n"); -+ return count; -+ } -+ -+ if (enable) { -+ DBG_88E("Turn On Rx RSSI Display Function\n"); -+ padapter->bRxRSSIDisplay = enable ; -+ } else { -+ DBG_88E("Turn Off Rx RSSI Display Function\n"); -+ padapter->bRxRSSIDisplay = 0; -+ } -+ } -+ return count; -+} -+ -+#ifdef CONFIG_88EU_AP_MODE -+ -+int proc_get_all_sta_info(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct sta_info *psta; -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ int i, j; -+ struct list_head *plist, *phead; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ int len = 0; -+ -+ len += snprintf(page + len, count - len, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ -+ for (i = 0; i < NUM_STA; i++) { -+ phead = &(pstapriv->sta_hash[i]); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, hash_list); -+ -+ plist = plist->next; -+ -+ len += snprintf(page + len, count - len, "sta's macaddr: %pM\n", psta->hwaddr); -+ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); -+ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); -+ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); -+ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); -+ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); -+ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); -+ len += snprintf(page + len, count - len, "sleepq_len=%d\n", psta->sleepq_len); -+ len += snprintf(page + len, count - len, "capability=0x%x\n", psta->capability); -+ len += snprintf(page + len, count - len, "flags=0x%x\n", psta->flags); -+ len += snprintf(page + len, count - len, "wpa_psk=0x%x\n", psta->wpa_psk); -+ len += snprintf(page + len, count - len, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher); -+ len += snprintf(page + len, count - len, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher); -+ len += snprintf(page + len, count - len, "qos_info=0x%x\n", psta->qos_info); -+ len += snprintf(page + len, count - len, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy); -+ -+ for (j = 0; j < 16; j++) { -+ preorder_ctrl = &psta->recvreorder_ctrl[j]; -+ if (preorder_ctrl->enable) -+ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", j, preorder_ctrl->indicate_seq); -+ } -+ } -+ } -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+ *eof = 1; -+ return len; -+} -+#endif -+ -+int proc_get_best_channel(char *page, char **start, -+ off_t offset, int count, -+ int *eof, void *data) -+{ -+ struct net_device *dev = data; -+ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ int len = 0; -+ u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 0; -+ -+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) { -+ if (pmlmeext->channel_set[i].ChannelNum == 1) -+ index_24G = i; -+ if (pmlmeext->channel_set[i].ChannelNum == 36) -+ index_5G = i; -+ } -+ -+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) { -+ /* 2.4G */ -+ if (pmlmeext->channel_set[i].ChannelNum == 6) { -+ if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) { -+ index_24G = i; -+ best_channel_24G = pmlmeext->channel_set[i].ChannelNum; -+ } -+ } -+ -+ /* 5G */ -+ if (pmlmeext->channel_set[i].ChannelNum >= 36 && -+ pmlmeext->channel_set[i].ChannelNum < 140) { -+ /* Find primary channel */ -+ if (((pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0) && -+ (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) { -+ index_5G = i; -+ best_channel_5G = pmlmeext->channel_set[i].ChannelNum; -+ } -+ } -+ -+ if (pmlmeext->channel_set[i].ChannelNum >= 149 && -+ pmlmeext->channel_set[i].ChannelNum < 165) { -+ /* find primary channel */ -+ if (((pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0) && -+ (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) { -+ index_5G = i; -+ best_channel_5G = pmlmeext->channel_set[i].ChannelNum; -+ } -+ } -+ /* debug */ -+ len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n", -+ pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count); -+ } -+ -+ len += snprintf(page + len, count - len, "best_channel_5G = %d\n", best_channel_5G); -+ len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G); -+ -+ *eof = 1; -+ return len; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_efuse.c b/drivers/net/wireless/rtl8188eu/core/rtw_efuse.c -new file mode 100644 -index 0000000000000..53b73f442699b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_efuse.c -@@ -0,0 +1,872 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_EFUSE_C_ -+ -+#include -+#include -+#include -+ -+/*------------------------Define local variable------------------------------*/ -+u8 fakeEfuseBank; -+u32 fakeEfuseUsedBytes; -+u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0}; -+u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0}; -+u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0}; -+ -+u32 BTEfuseUsedBytes; -+u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; -+u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; -+u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; -+ -+u32 fakeBTEfuseUsedBytes; -+u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; -+u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; -+u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; -+/*------------------------Define local variable------------------------------*/ -+ -+/* */ -+#define REG_EFUSE_CTRL 0x0030 -+#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ -+/* */ -+ -+bool -+Efuse_Read1ByteFromFakeContent( -+ struct adapter *pAdapter, -+ u16 Offset, -+ u8 *Value); -+bool -+Efuse_Read1ByteFromFakeContent( -+ struct adapter *pAdapter, -+ u16 Offset, -+ u8 *Value) -+{ -+ if (Offset >= EFUSE_MAX_HW_SIZE) -+ return false; -+ if (fakeEfuseBank == 0) -+ *Value = fakeEfuseContent[Offset]; -+ else -+ *Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset]; -+ return true; -+} -+ -+static bool -+Efuse_Write1ByteToFakeContent( -+ struct adapter *pAdapter, -+ u16 Offset, -+ u8 Value) -+{ -+ if (Offset >= EFUSE_MAX_HW_SIZE) -+ return false; -+ if (fakeEfuseBank == 0) { -+ fakeEfuseContent[Offset] = Value; -+ } else { -+ fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value; -+ } -+ return true; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: Efuse_PowerSwitch -+ * -+ * Overview: When we want to enable write operation, we should change to -+ * pwr on state. When we stop write, we should switch to 500k mode -+ * and disable LDO 2.5V. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/17/2008 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+void -+Efuse_PowerSwitch( -+ struct adapter *pAdapter, -+ u8 write, -+ u8 PwrState) -+{ -+ pAdapter->HalFunc.EfusePowerSwitch(pAdapter, write, PwrState); -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: efuse_GetCurrentSize -+ * -+ * Overview: Get current efuse size!!! -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/16/2008 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+u16 -+Efuse_GetCurrentSize( -+ struct adapter *pAdapter, -+ u8 efuseType, -+ bool pseudo) -+{ -+ u16 ret = 0; -+ -+ ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType, pseudo); -+ -+ return ret; -+} -+ -+/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ -+u8 -+Efuse_CalculateWordCnts(u8 word_en) -+{ -+ u8 word_cnts = 0; -+ if (!(word_en & BIT(0))) -+ word_cnts++; /* 0 : write enable */ -+ if (!(word_en & BIT(1))) -+ word_cnts++; -+ if (!(word_en & BIT(2))) -+ word_cnts++; -+ if (!(word_en & BIT(3))) -+ word_cnts++; -+ return word_cnts; -+} -+ -+/* */ -+/* Description: */ -+/* Execute E-Fuse read byte operation. */ -+/* Referred from SD1 Richard. */ -+/* */ -+/* Assumption: */ -+/* 1. Boot from E-Fuse and successfully auto-load. */ -+/* 2. PASSIVE_LEVEL (USB interface) */ -+/* */ -+/* Created by Roger, 2008.10.21. */ -+/* */ -+void -+ReadEFuseByte( -+ struct adapter *Adapter, -+ u16 _offset, -+ u8 *pbuf, -+ bool pseudo) -+{ -+ u32 value32; -+ u8 readbyte; -+ u16 retry; -+ -+ if (pseudo) { -+ Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf); -+ return; -+ } -+ -+ /* Write Address */ -+ rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff)); -+ readbyte = rtw_read8(Adapter, EFUSE_CTRL+2); -+ rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); -+ -+ /* Write bit 32 0 */ -+ readbyte = rtw_read8(Adapter, EFUSE_CTRL+3); -+ rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f)); -+ -+ /* Check bit 32 read-ready */ -+ retry = 0; -+ value32 = rtw_read32(Adapter, EFUSE_CTRL); -+ while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { -+ value32 = rtw_read32(Adapter, EFUSE_CTRL); -+ retry++; -+ } -+ -+ /* 20100205 Joseph: Add delay suggested by SD1 Victor. */ -+ /* This fix the problem that Efuse read error in high temperature condition. */ -+ /* Designer says that there shall be some delay after ready bit is set, or the */ -+ /* result will always stay on last data we read. */ -+ rtw_udelay_os(50); -+ value32 = rtw_read32(Adapter, EFUSE_CTRL); -+ -+ *pbuf = (u8)(value32 & 0xff); -+} -+ -+/* */ -+/* Description: */ -+/* 1. Execute E-Fuse read byte operation according as map offset and */ -+/* save to E-Fuse table. */ -+/* 2. Referred from SD1 Richard. */ -+/* */ -+/* Assumption: */ -+/* 1. Boot from E-Fuse and successfully auto-load. */ -+/* 2. PASSIVE_LEVEL (USB interface) */ -+/* */ -+/* Created by Roger, 2008.10.21. */ -+/* */ -+/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ -+/* 2. Add efuse utilization collect. */ -+/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ -+/* write addr must be after sec5. */ -+/* */ -+ -+static void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool pseudo) -+{ -+ Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, pseudo); -+} -+ -+void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool pseudo -+ ) -+{ -+ pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, pseudo); -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: EFUSE_Read1Byte -+ * -+ * Overview: Copy from WMAC fot EFUSE read 1 byte. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 09/23/2008 MHC Copy from WMAC. -+ * -+ *---------------------------------------------------------------------------*/ -+u8 EFUSE_Read1Byte(struct adapter *Adapter, u16 Address) -+{ -+ u8 data; -+ u8 Bytetemp = {0x00}; -+ u8 temp = {0x00}; -+ u32 k = 0; -+ u16 contentLen = 0; -+ -+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); -+ -+ if (Address < contentLen) { /* E-fuse 512Byte */ -+ /* Write E-fuse Register address bit0~7 */ -+ temp = Address & 0xFF; -+ rtw_write8(Adapter, EFUSE_CTRL+1, temp); -+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); -+ /* Write E-fuse Register address bit8~9 */ -+ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); -+ rtw_write8(Adapter, EFUSE_CTRL+2, temp); -+ -+ /* Write 0x30[31]= 0 */ -+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); -+ temp = Bytetemp & 0x7F; -+ rtw_write8(Adapter, EFUSE_CTRL+3, temp); -+ -+ /* Wait Write-ready (0x30[31]= 1) */ -+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); -+ while (!(Bytetemp & 0x80)) { -+ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); -+ k++; -+ if (k == 1000) { -+ k = 0; -+ break; -+ } -+ } -+ data = rtw_read8(Adapter, EFUSE_CTRL); -+ return data; -+ } else { -+ return 0xFF; -+ } -+ -+} /* EFUSE_Read1Byte */ -+ -+/* 11/16/2008 MH Read one byte from real Efuse. */ -+u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data, bool pseudo) -+{ -+ u8 tmpidx = 0; -+ u8 result; -+ -+ if (pseudo) { -+ result = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data); -+ return result; -+ } -+ /* -----------------e-fuse reg ctrl --------------------------------- */ -+ /* address */ -+ rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr & 0xff)); -+ rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) | -+ (rtw_read8(pAdapter, EFUSE_CTRL+2) & 0xFC)); -+ -+ rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72);/* read cmd */ -+ -+ while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100)) -+ tmpidx++; -+ if (tmpidx < 100) { -+ *data = rtw_read8(pAdapter, EFUSE_CTRL); -+ result = true; -+ } else { -+ *data = 0xff; -+ result = false; -+ } -+ return result; -+} -+ -+/* 11/16/2008 MH Write one byte to reald Efuse. */ -+u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data, bool pseudo) -+{ -+ u8 tmpidx = 0; -+ u8 result; -+ -+ if (pseudo) { -+ result = Efuse_Write1ByteToFakeContent(pAdapter, addr, data); -+ return result; -+ } -+ -+ /* -----------------e-fuse reg ctrl --------------------------------- */ -+ /* address */ -+ rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff)); -+ rtw_write8(pAdapter, EFUSE_CTRL+2, -+ (rtw_read8(pAdapter, EFUSE_CTRL+2) & 0xFC) | -+ (u8)((addr>>8) & 0x03)); -+ rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */ -+ -+ rtw_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */ -+ -+ while ((0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100)) -+ tmpidx++; -+ -+ if (tmpidx < 100) -+ result = true; -+ else -+ result = false; -+ -+ return result; -+} -+ -+int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool pseudo) -+{ -+ int ret = 0; -+ -+ ret = pAdapter->HalFunc.Efuse_PgPacketRead(pAdapter, offset, data, pseudo); -+ -+ return ret; -+} -+ -+int Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo) -+{ -+ int ret; -+ -+ ret = pAdapter->HalFunc.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, pseudo); -+ -+ return ret; -+} -+ -+static int Efuse_PgPacketWrite_BT(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo) -+{ -+ int ret; -+ -+ ret = pAdapter->HalFunc.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, pseudo); -+ -+ return ret; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: efuse_WordEnableDataRead -+ * -+ * Overview: Read allowed word in current efuse section data. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/16/2008 MHC Create Version 0. -+ * 11/21/2008 MHC Fix Write bug when we only enable late word. -+ * -+ *---------------------------------------------------------------------------*/ -+void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata) -+{ -+ if (!(word_en&BIT(0))) { -+ targetdata[0] = sourdata[0]; -+ targetdata[1] = sourdata[1]; -+ } -+ if (!(word_en&BIT(1))) { -+ targetdata[2] = sourdata[2]; -+ targetdata[3] = sourdata[3]; -+ } -+ if (!(word_en&BIT(2))) { -+ targetdata[4] = sourdata[4]; -+ targetdata[5] = sourdata[5]; -+ } -+ if (!(word_en&BIT(3))) { -+ targetdata[6] = sourdata[6]; -+ targetdata[7] = sourdata[7]; -+ } -+} -+ -+u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool pseudo) -+{ -+ u8 ret = 0; -+ -+ ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, pseudo); -+ -+ return ret; -+} -+ -+static u8 efuse_read8(struct adapter *padapter, u16 address, u8 *value) -+{ -+ return efuse_OneByteRead(padapter, address, value, false); -+} -+ -+static u8 efuse_write8(struct adapter *padapter, u16 address, u8 *value) -+{ -+ return efuse_OneByteWrite(padapter, address, *value, false); -+} -+ -+/* -+ * read/wirte raw efuse data -+ */ -+u8 rtw_efuse_access(struct adapter *padapter, u8 write, u16 start_addr, u16 cnts, u8 *data) -+{ -+ int i = 0; -+ u16 real_content_len = 0, max_available_size = 0; -+ u8 res = _FAIL ; -+ u8 (*rw8)(struct adapter *, u16, u8*); -+ -+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&real_content_len, false); -+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); -+ -+ if (start_addr > real_content_len) -+ return _FAIL; -+ -+ if (write) { -+ if ((start_addr + cnts) > max_available_size) -+ return _FAIL; -+ rw8 = &efuse_write8; -+ } else { -+ rw8 = &efuse_read8; -+ } -+ -+ Efuse_PowerSwitch(padapter, write, true); -+ -+ /* e-fuse one byte read / write */ -+ for (i = 0; i < cnts; i++) { -+ if (start_addr >= real_content_len) { -+ res = _FAIL; -+ break; -+ } -+ -+ res = rw8(padapter, start_addr++, data++); -+ if (_FAIL == res) -+ break; -+ } -+ -+ Efuse_PowerSwitch(padapter, write, false); -+ -+ return res; -+} -+/* */ -+u16 efuse_GetMaxSize(struct adapter *padapter) -+{ -+ u16 max_size; -+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_size, false); -+ return max_size; -+} -+/* */ -+u8 efuse_GetCurrentSize(struct adapter *padapter, u16 *size) -+{ -+ Efuse_PowerSwitch(padapter, false, true); -+ *size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, false); -+ Efuse_PowerSwitch(padapter, false, false); -+ -+ return _SUCCESS; -+} -+/* */ -+u8 rtw_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) -+{ -+ u16 mapLen = 0; -+ -+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); -+ -+ if ((addr + cnts) > mapLen) -+ return _FAIL; -+ -+ Efuse_PowerSwitch(padapter, false, true); -+ -+ efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, false); -+ -+ Efuse_PowerSwitch(padapter, false, false); -+ -+ return _SUCCESS; -+} -+ -+u8 rtw_BT_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) -+{ -+ u16 mapLen = 0; -+ -+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); -+ -+ if ((addr + cnts) > mapLen) -+ return _FAIL; -+ -+ Efuse_PowerSwitch(padapter, false, true); -+ -+ efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, false); -+ -+ Efuse_PowerSwitch(padapter, false, false); -+ -+ return _SUCCESS; -+} -+/* */ -+u8 rtw_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) -+{ -+ u8 offset, word_en; -+ u8 *map; -+ u8 newdata[PGPKT_DATA_SIZE + 1]; -+ s32 i, idx; -+ u8 ret = _SUCCESS; -+ u16 mapLen = 0; -+ -+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); -+ -+ if ((addr + cnts) > mapLen) -+ return _FAIL; -+ -+ map = rtw_zmalloc(mapLen); -+ if (map == NULL) -+ return _FAIL; -+ -+ ret = rtw_efuse_map_read(padapter, 0, mapLen, map); -+ if (ret == _FAIL) -+ goto exit; -+ -+ Efuse_PowerSwitch(padapter, true, true); -+ -+ offset = (addr >> 3); -+ word_en = 0xF; -+ memset(newdata, 0xFF, PGPKT_DATA_SIZE + 1); -+ i = addr & 0x7; /* index of one package */ -+ idx = 0; /* data index */ -+ -+ if (i & 0x1) { -+ /* odd start */ -+ if (data[idx] != map[addr+idx]) { -+ word_en &= ~BIT(i >> 1); -+ newdata[i-1] = map[addr+idx-1]; -+ newdata[i] = data[idx]; -+ } -+ i++; -+ idx++; -+ } -+ do { -+ for (; i < PGPKT_DATA_SIZE; i += 2) { -+ if (cnts == idx) -+ break; -+ if ((cnts - idx) == 1) { -+ if (data[idx] != map[addr+idx]) { -+ word_en &= ~BIT(i >> 1); -+ newdata[i] = data[idx]; -+ newdata[i+1] = map[addr+idx+1]; -+ } -+ idx++; -+ break; -+ } else { -+ if ((data[idx] != map[addr+idx]) || -+ (data[idx+1] != map[addr+idx+1])) { -+ word_en &= ~BIT(i >> 1); -+ newdata[i] = data[idx]; -+ newdata[i+1] = data[idx + 1]; -+ } -+ idx += 2; -+ } -+ if (idx == cnts) -+ break; -+ } -+ -+ if (word_en != 0xF) { -+ ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, false); -+ DBG_88E("offset=%x\n", offset); -+ DBG_88E("word_en=%x\n", word_en); -+ -+ for (i = 0; i < PGPKT_DATA_SIZE; i++) -+ DBG_88E("data=%x \t", newdata[i]); -+ if (ret == _FAIL) -+ break; -+ } -+ -+ if (idx == cnts) -+ break; -+ -+ offset++; -+ i = 0; -+ word_en = 0xF; -+ memset(newdata, 0xFF, PGPKT_DATA_SIZE); -+ } while (1); -+ -+ Efuse_PowerSwitch(padapter, true, false); -+exit: -+ kfree(map); -+ return ret; -+} -+ -+/* */ -+u8 rtw_BT_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) -+{ -+ u8 offset, word_en; -+ u8 *map; -+ u8 newdata[PGPKT_DATA_SIZE + 1]; -+ s32 i, idx; -+ u8 ret = _SUCCESS; -+ u16 mapLen = 0; -+ -+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); -+ -+ if ((addr + cnts) > mapLen) -+ return _FAIL; -+ -+ map = rtw_zmalloc(mapLen); -+ if (map == NULL) -+ return _FAIL; -+ -+ ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map); -+ if (ret == _FAIL) -+ goto exit; -+ -+ Efuse_PowerSwitch(padapter, true, true); -+ -+ offset = (addr >> 3); -+ word_en = 0xF; -+ memset(newdata, 0xFF, PGPKT_DATA_SIZE + 1); -+ i = addr & 0x7; /* index of one package */ -+ idx = 0; /* data index */ -+ -+ if (i & 0x1) { -+ /* odd start */ -+ if (data[idx] != map[addr+idx]) { -+ word_en &= ~BIT(i >> 1); -+ newdata[i-1] = map[addr+idx-1]; -+ newdata[i] = data[idx]; -+ } -+ i++; -+ idx++; -+ } -+ do { -+ for (; i < PGPKT_DATA_SIZE; i += 2) { -+ if (cnts == idx) -+ break; -+ if ((cnts - idx) == 1) { -+ if (data[idx] != map[addr+idx]) { -+ word_en &= ~BIT(i >> 1); -+ newdata[i] = data[idx]; -+ newdata[i+1] = map[addr+idx+1]; -+ } -+ idx++; -+ break; -+ } else { -+ if ((data[idx] != map[addr+idx]) || -+ (data[idx+1] != map[addr+idx+1])) { -+ word_en &= ~BIT(i >> 1); -+ newdata[i] = data[idx]; -+ newdata[i+1] = data[idx + 1]; -+ } -+ idx += 2; -+ } -+ if (idx == cnts) -+ break; -+ } -+ -+ if (word_en != 0xF) { -+ DBG_88E("%s: offset=%#X\n", __func__, offset); -+ DBG_88E("%s: word_en=%#X\n", __func__, word_en); -+ DBG_88E("%s: data=", __func__); -+ for (i = 0; i < PGPKT_DATA_SIZE; i++) -+ DBG_88E("0x%02X ", newdata[i]); -+ DBG_88E("\n"); -+ -+ ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, false); -+ if (ret == _FAIL) -+ break; -+ } -+ -+ if (idx == cnts) -+ break; -+ -+ offset++; -+ i = 0; -+ word_en = 0xF; -+ memset(newdata, 0xFF, PGPKT_DATA_SIZE); -+ } while (1); -+ -+ Efuse_PowerSwitch(padapter, true, false); -+ -+exit: -+ -+ kfree(map); -+ -+ return ret; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: efuse_ShadowRead1Byte -+ * efuse_ShadowRead2Byte -+ * efuse_ShadowRead4Byte -+ * -+ * Overview: Read from efuse init map by one/two/four bytes !!!!! -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/12/2008 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+static void -+efuse_ShadowRead1Byte( -+ struct adapter *pAdapter, -+ u16 Offset, -+ u8 *Value) -+{ -+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); -+ -+ *Value = pEEPROM->efuse_eeprom_data[Offset]; -+ -+} /* EFUSE_ShadowRead1Byte */ -+ -+/* Read Two Bytes */ -+static void -+efuse_ShadowRead2Byte( -+ struct adapter *pAdapter, -+ u16 Offset, -+ u16 *Value) -+{ -+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); -+ -+ *Value = pEEPROM->efuse_eeprom_data[Offset]; -+ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; -+ -+} /* EFUSE_ShadowRead2Byte */ -+ -+/* Read Four Bytes */ -+static void -+efuse_ShadowRead4Byte( -+ struct adapter *pAdapter, -+ u16 Offset, -+ u32 *Value) -+{ -+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); -+ -+ *Value = pEEPROM->efuse_eeprom_data[Offset]; -+ *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8; -+ *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16; -+ *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24; -+ -+} /* efuse_ShadowRead4Byte */ -+ -+/*----------------------------------------------------------------------------- -+ * Function: Efuse_ReadAllMap -+ * -+ * Overview: Read All Efuse content -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/11/2008 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse, bool pseudo) -+{ -+ u16 mapLen = 0; -+ -+ Efuse_PowerSwitch(pAdapter, false, true); -+ -+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo); -+ -+ efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, pseudo); -+ -+ Efuse_PowerSwitch(pAdapter, false, false); -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: EFUSE_ShadowMapUpdate -+ * -+ * Overview: Transfer current EFUSE content to shadow init and modify map. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/13/2008 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+void EFUSE_ShadowMapUpdate( -+ struct adapter *pAdapter, -+ u8 efuseType, -+ bool pseudo) -+{ -+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); -+ u16 mapLen = 0; -+ -+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo); -+ -+ if (pEEPROM->bautoload_fail_flag) -+ memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); -+ else -+ Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data, pseudo); -+} /* EFUSE_ShadowMapUpdate */ -+ -+/*----------------------------------------------------------------------------- -+ * Function: EFUSE_ShadowRead -+ * -+ * Overview: Read from efuse init map !!!!! -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/12/2008 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+void EFUSE_ShadowRead(struct adapter *pAdapter, u8 Type, u16 Offset, u32 *Value) -+{ -+ if (Type == 1) -+ efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value); -+ else if (Type == 2) -+ efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value); -+ else if (Type == 4) -+ efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value); -+ -+} /* EFUSE_ShadowRead */ -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_ieee80211.c b/drivers/net/wireless/rtl8188eu/core/rtw_ieee80211.c -new file mode 100644 -index 0000000000000..808d9402bc239 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_ieee80211.c -@@ -0,0 +1,1625 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _IEEE80211_C -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; -+u16 RTW_WPA_VERSION = 1; -+u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 }; -+u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 }; -+u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 }; -+u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 }; -+u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 }; -+u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 }; -+u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 }; -+u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 }; -+u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 }; -+ -+u16 RSN_VERSION_BSD = 1; -+u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 }; -+u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 }; -+u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 }; -+u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 }; -+u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 }; -+u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 }; -+u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 }; -+u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 }; -+/* */ -+/* for adhoc-master to generate ie and provide supported-rate to fw */ -+/* */ -+ -+static u8 WIFI_CCKRATES[] = { -+ (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), -+ (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), -+ (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), -+ (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK) -+ }; -+ -+static u8 WIFI_OFDMRATES[] = { -+ (IEEE80211_OFDM_RATE_6MB), -+ (IEEE80211_OFDM_RATE_9MB), -+ (IEEE80211_OFDM_RATE_12MB), -+ (IEEE80211_OFDM_RATE_18MB), -+ (IEEE80211_OFDM_RATE_24MB), -+ IEEE80211_OFDM_RATE_36MB, -+ IEEE80211_OFDM_RATE_48MB, -+ IEEE80211_OFDM_RATE_54MB -+ }; -+ -+int rtw_get_bit_value_from_ieee_value(u8 val) -+{ -+ unsigned char dot11_rate_table[] = { -+ 2, 4, 11, 22, 12, 18, 24, 36, 48, -+ 72, 96, 108, 0}; /* last element must be zero!! */ -+ -+ int i = 0; -+ while (dot11_rate_table[i] != 0) { -+ if (dot11_rate_table[i] == val) -+ return BIT(i); -+ i++; -+ } -+ return 0; -+} -+ -+uint rtw_is_cckrates_included(u8 *rate) -+{ -+ u32 i = 0; -+ -+ while (rate[i] != 0) { -+ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || -+ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) -+ return true; -+ i++; -+ } -+ return false; -+} -+ -+uint rtw_is_cckratesonly_included(u8 *rate) -+{ -+ u32 i = 0; -+ -+ while (rate[i] != 0) { -+ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && -+ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) -+ return false; -+ i++; -+ } -+ -+ return true; -+} -+ -+int rtw_check_network_type(unsigned char *rate, int ratelen, int channel) -+{ -+ if (channel > 14) { -+ if ((rtw_is_cckrates_included(rate)) == true) -+ return WIRELESS_INVALID; -+ else -+ return WIRELESS_11A; -+ } else { /* could be pure B, pure G, or B/G */ -+ if ((rtw_is_cckratesonly_included(rate)) == true) -+ return WIRELESS_11B; -+ else if ((rtw_is_cckrates_included(rate)) == true) -+ return WIRELESS_11BG; -+ else -+ return WIRELESS_11G; -+ } -+} -+ -+u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, -+ unsigned int *frlen) -+{ -+ memcpy((void *)pbuf, (void *)source, len); -+ *frlen = *frlen + len; -+ return pbuf + len; -+} -+ -+/* rtw_set_ie will update frame length */ -+u8 *rtw_set_ie -+( -+ u8 *pbuf, -+ int index, -+ uint len, -+ u8 *source, -+ uint *frlen /* frame length */ -+) -+{ -+ -+ *pbuf = (u8)index; -+ -+ *(pbuf + 1) = (u8)len; -+ -+ if (len > 0) -+ memcpy((void *)(pbuf + 2), (void *)source, len); -+ -+ *frlen = *frlen + (len + 2); -+ -+ return pbuf + len + 2; -+} -+ -+inline u8 *rtw_set_ie_ch_switch (u8 *buf, u32 *buf_len, u8 ch_switch_mode, -+ u8 new_ch, u8 ch_switch_cnt) -+{ -+ u8 ie_data[3]; -+ -+ ie_data[0] = ch_switch_mode; -+ ie_data[1] = new_ch; -+ ie_data[2] = ch_switch_cnt; -+ return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH, 3, ie_data, buf_len); -+} -+ -+inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset) -+{ -+ if (ch_offset == SCN) -+ return HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ else if (ch_offset == SCA) -+ return HAL_PRIME_CHNL_OFFSET_UPPER; -+ else if (ch_offset == SCB) -+ return HAL_PRIME_CHNL_OFFSET_LOWER; -+ -+ return HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+} -+ -+inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset) -+{ -+ if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) -+ return SCN; -+ else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) -+ return SCB; -+ else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) -+ return SCA; -+ -+ return SCN; -+} -+ -+inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset) -+{ -+ return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET, 1, &secondary_ch_offset, buf_len); -+} -+ -+inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, -+ u8 flags, u16 reason, u16 precedence) -+{ -+ u8 ie_data[6]; -+ -+ ie_data[0] = ttl; -+ ie_data[1] = flags; -+ *(u16 *)(ie_data+2) = cpu_to_le16(reason); -+ *(u16 *)(ie_data+4) = cpu_to_le16(precedence); -+ -+ return rtw_set_ie(buf, 0x118, 6, ie_data, buf_len); -+} -+ -+/*---------------------------------------------------------------------------- -+index: the information element id index, limit is the limit for search -+-----------------------------------------------------------------------------*/ -+u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit) -+{ -+ int tmp, i; -+ u8 *p; -+ -+ if (limit < 1) { -+ -+ return NULL; -+ } -+ -+ p = pbuf; -+ i = 0; -+ *len = 0; -+ while (1) { -+ if (*p == index) { -+ *len = *(p + 1); -+ return p; -+ } else { -+ tmp = *(p + 1); -+ p += (tmp + 2); -+ i += (tmp + 2); -+ } -+ if (i >= limit) -+ break; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * rtw_get_ie_ex - Search specific IE from a series of IEs -+ * @in_ie: Address of IEs to search -+ * @in_len: Length limit from in_ie -+ * @eid: Element ID to match -+ * @oui: OUI to match -+ * @oui_len: OUI length -+ * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE -+ * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE -+ * -+ * Returns: The address of the specific IE found, or NULL -+ */ -+u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen) -+{ -+ uint cnt; -+ u8 *target_ie = NULL; -+ -+ if (ielen) -+ *ielen = 0; -+ -+ if (!in_ie || in_len <= 0) -+ return target_ie; -+ -+ cnt = 0; -+ -+ while (cnt < in_len) { -+ if (eid == in_ie[cnt] && (!oui || !memcmp(&in_ie[cnt+2], oui, oui_len))) { -+ target_ie = &in_ie[cnt]; -+ -+ if (ie) -+ memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2); -+ -+ if (ielen) -+ *ielen = in_ie[cnt+1]+2; -+ -+ break; -+ } else { -+ cnt += in_ie[cnt+1]+2; /* goto next */ -+ } -+ } -+ return target_ie; -+} -+ -+/** -+ * rtw_ies_remove_ie - Find matching IEs and remove -+ * @ies: Address of IEs to search -+ * @ies_len: Pointer of length of ies, will update to new length -+ * @offset: The offset to start scarch -+ * @eid: Element ID to match -+ * @oui: OUI to match -+ * @oui_len: OUI length -+ * -+ * Returns: _SUCCESS: ies is updated, _FAIL: not updated -+ */ -+int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len) -+{ -+ int ret = _FAIL; -+ u8 *target_ie; -+ u32 target_ielen; -+ u8 *start; -+ uint search_len; -+ -+ if (!ies || !ies_len || *ies_len <= offset) -+ goto exit; -+ -+ start = ies + offset; -+ search_len = *ies_len - offset; -+ -+ while (1) { -+ target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen); -+ if (target_ie && target_ielen) { -+ u8 buf[MAX_IE_SZ] = {0}; -+ u8 *remain_ies = target_ie + target_ielen; -+ uint remain_len = search_len - (remain_ies - start); -+ -+ memcpy(buf, remain_ies, remain_len); -+ memcpy(target_ie, buf, remain_len); -+ *ies_len = *ies_len - target_ielen; -+ ret = _SUCCESS; -+ -+ start = target_ie; -+ search_len = remain_len; -+ } else { -+ break; -+ } -+ } -+exit: -+ return ret; -+} -+ -+void rtw_set_supported_rate(u8 *SupportedRates, uint mode) -+{ -+ -+ memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); -+ -+ switch (mode) { -+ case WIRELESS_11B: -+ memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); -+ break; -+ case WIRELESS_11G: -+ case WIRELESS_11A: -+ case WIRELESS_11_5N: -+ case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */ -+ memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); -+ break; -+ case WIRELESS_11BG: -+ case WIRELESS_11G_24N: -+ case WIRELESS_11_24N: -+ case WIRELESS_11BG_24N: -+ memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); -+ memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); -+ break; -+ } -+ -+} -+ -+uint rtw_get_rateset_len(u8 *rateset) -+{ -+ uint i = 0; -+ -+ while (1) { -+ if ((rateset[i]) == 0) -+ break; -+ if (i > 12) -+ break; -+ i++; -+ } -+ -+ return i; -+} -+ -+int rtw_generate_ie(struct registry_priv *pregistrypriv) -+{ -+ u8 wireless_mode; -+ int sz = 0, rateLen; -+ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; -+ u8 *ie = pdev_network->IEs; -+ -+ /* timestamp will be inserted by hardware */ -+ sz += 8; -+ ie += sz; -+ -+ /* beacon interval : 2bytes */ -+ *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */ -+ sz += 2; -+ ie += 2; -+ -+ /* capability info */ -+ *(u16 *)ie = 0; -+ -+ *(__le16 *)ie |= cpu_to_le16(cap_IBSS); -+ -+ if (pregistrypriv->preamble == PREAMBLE_SHORT) -+ *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble); -+ -+ if (pdev_network->Privacy) -+ *(__le16 *)ie |= cpu_to_le16(cap_Privacy); -+ -+ sz += 2; -+ ie += 2; -+ -+ /* SSID */ -+ ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz); -+ -+ /* supported rates */ -+ if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) { -+ if (pdev_network->Configuration.DSConfig > 14) -+ wireless_mode = WIRELESS_11A_5N; -+ else -+ wireless_mode = WIRELESS_11BG_24N; -+ } else { -+ wireless_mode = pregistrypriv->wireless_mode; -+ } -+ -+ rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode); -+ -+ rateLen = rtw_get_rateset_len(pdev_network->SupportedRates); -+ -+ if (rateLen > 8) { -+ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz); -+ /* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */ -+ } else { -+ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz); -+ } -+ -+ /* DS parameter set */ -+ ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz); -+ -+ /* IBSS Parameter Set */ -+ -+ ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz); -+ -+ if (rateLen > 8) -+ ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); -+ -+ return sz; -+} -+ -+unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) -+{ -+ int len; -+ u16 val16; -+ __le16 le_tmp; -+ unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; -+ u8 *pbuf = pie; -+ int limit_new = limit; -+ -+ while (1) { -+ pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new); -+ -+ if (pbuf) { -+ /* check if oui matches... */ -+ if (memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type))) -+ goto check_next_ie; -+ -+ /* check version... */ -+ memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16)); -+ -+ val16 = le16_to_cpu(le_tmp); -+ if (val16 != 0x0001) -+ goto check_next_ie; -+ *wpa_ie_len = *(pbuf + 1); -+ return pbuf; -+ } else { -+ *wpa_ie_len = 0; -+ return NULL; -+ } -+ -+check_next_ie: -+ limit_new = limit - (pbuf - pie) - 2 - len; -+ if (limit_new <= 0) -+ break; -+ pbuf += (2 + len); -+ } -+ *wpa_ie_len = 0; -+ return NULL; -+} -+ -+unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) -+{ -+ -+ return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); -+} -+ -+int rtw_get_wpa_cipher_suite(u8 *s) -+{ -+ if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN)) -+ return WPA_CIPHER_NONE; -+ if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN)) -+ return WPA_CIPHER_WEP40; -+ if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN)) -+ return WPA_CIPHER_TKIP; -+ if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN)) -+ return WPA_CIPHER_CCMP; -+ if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN)) -+ return WPA_CIPHER_WEP104; -+ -+ return 0; -+} -+ -+int rtw_get_wpa2_cipher_suite(u8 *s) -+{ -+ if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN)) -+ return WPA_CIPHER_NONE; -+ if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN)) -+ return WPA_CIPHER_WEP40; -+ if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN)) -+ return WPA_CIPHER_TKIP; -+ if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN)) -+ return WPA_CIPHER_CCMP; -+ if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN)) -+ return WPA_CIPHER_WEP104; -+ -+ return 0; -+} -+ -+int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) -+{ -+ int i, ret = _SUCCESS; -+ int left, count; -+ u8 *pos; -+ u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1}; -+ -+ if (wpa_ie_len <= 0) { -+ /* No WPA IE - fail silently */ -+ return _FAIL; -+ } -+ -+ if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) || -+ (memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN))) -+ return _FAIL; -+ -+ pos = wpa_ie; -+ -+ pos += 8; -+ left = wpa_ie_len - 8; -+ -+ /* group_cipher */ -+ if (left >= WPA_SELECTOR_LEN) { -+ *group_cipher = rtw_get_wpa_cipher_suite(pos); -+ pos += WPA_SELECTOR_LEN; -+ left -= WPA_SELECTOR_LEN; -+ } else if (left > 0) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left)); -+ return _FAIL; -+ } -+ -+ /* pairwise_cipher */ -+ if (left >= 2) { -+ count = get_unaligned_le16(pos); -+ pos += 2; -+ left -= 2; -+ -+ if (count == 0 || left < count * WPA_SELECTOR_LEN) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), " -+ "count %u left %u", __func__, count, left)); -+ return _FAIL; -+ } -+ -+ for (i = 0; i < count; i++) { -+ *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos); -+ -+ pos += WPA_SELECTOR_LEN; -+ left -= WPA_SELECTOR_LEN; -+ } -+ } else if (left == 1) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__)); -+ return _FAIL; -+ } -+ -+ if (is_8021x) { -+ if (left >= 6) { -+ pos += 2; -+ if (!memcmp(pos, SUITE_1X, 4)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__)); -+ *is_8021x = 1; -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) -+{ -+ int i, ret = _SUCCESS; -+ int left, count; -+ u8 *pos; -+ u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01}; -+ -+ if (rsn_ie_len <= 0) { -+ /* No RSN IE - fail silently */ -+ return _FAIL; -+ } -+ -+ if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2))) -+ return _FAIL; -+ -+ pos = rsn_ie; -+ pos += 4; -+ left = rsn_ie_len - 4; -+ -+ /* group_cipher */ -+ if (left >= RSN_SELECTOR_LEN) { -+ *group_cipher = rtw_get_wpa2_cipher_suite(pos); -+ -+ pos += RSN_SELECTOR_LEN; -+ left -= RSN_SELECTOR_LEN; -+ -+ } else if (left > 0) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left)); -+ return _FAIL; -+ } -+ -+ /* pairwise_cipher */ -+ if (left >= 2) { -+ count = get_unaligned_le16(pos); -+ pos += 2; -+ left -= 2; -+ -+ if (count == 0 || left < count * RSN_SELECTOR_LEN) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), " -+ "count %u left %u", __func__, count, left)); -+ return _FAIL; -+ } -+ -+ for (i = 0; i < count; i++) { -+ *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos); -+ -+ pos += RSN_SELECTOR_LEN; -+ left -= RSN_SELECTOR_LEN; -+ } -+ -+ } else if (left == 1) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)", __func__)); -+ -+ return _FAIL; -+ } -+ -+ if (is_8021x) { -+ if (left >= 6) { -+ pos += 2; -+ if (!memcmp(pos, SUITE_1X, 4)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__)); -+ *is_8021x = 1; -+ } -+ } -+ } -+ return ret; -+} -+ -+int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len) -+{ -+ u8 authmode, sec_idx, i; -+ u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; -+ uint cnt; -+ -+ /* Search required WPA or WPA2 IE and copy to sec_ie[] */ -+ -+ cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); -+ -+ sec_idx = 0; -+ -+ while (cnt < in_len) { -+ authmode = in_ie[cnt]; -+ -+ if ((authmode == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt+2], &wpa_oui[0], 4))) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("\n rtw_get_wpa_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n", -+ sec_idx, in_ie[cnt+1]+2)); -+ -+ if (wpa_ie) { -+ memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt+1]+2); -+ -+ for (i = 0; i < (in_ie[cnt+1]+2); i += 8) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n", -+ wpa_ie[i], wpa_ie[i+1], wpa_ie[i+2], wpa_ie[i+3], wpa_ie[i+4], -+ wpa_ie[i+5], wpa_ie[i+6], wpa_ie[i+7])); -+ } -+ } -+ -+ *wpa_len = in_ie[cnt+1]+2; -+ cnt += in_ie[cnt+1]+2; /* get next */ -+ } else { -+ if (authmode == _WPA2_IE_ID_) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("\n get_rsn_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n", -+ sec_idx, in_ie[cnt+1]+2)); -+ -+ if (rsn_ie) { -+ memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt+1]+2); -+ -+ for (i = 0; i < (in_ie[cnt+1]+2); i += 8) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n", -+ rsn_ie[i], rsn_ie[i+1], rsn_ie[i+2], rsn_ie[i+3], rsn_ie[i+4], -+ rsn_ie[i+5], rsn_ie[i+6], rsn_ie[i+7])); -+ } -+ } -+ -+ *rsn_len = in_ie[cnt+1]+2; -+ cnt += in_ie[cnt+1]+2; /* get next */ -+ } else { -+ cnt += in_ie[cnt+1]+2; /* get next */ -+ } -+ } -+ } -+ -+ return *rsn_len + *wpa_len; -+} -+ -+u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen) -+{ -+ u8 match = false; -+ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; -+ -+ if (ie_ptr == NULL) -+ return match; -+ -+ eid = ie_ptr[0]; -+ -+ if ((eid == _WPA_IE_ID_) && (!memcmp(&ie_ptr[2], wps_oui, 4))) { -+ *wps_ielen = ie_ptr[1]+2; -+ match = true; -+ } -+ return match; -+} -+ -+/** -+ * rtw_get_wps_ie - Search WPS IE from a series of IEs -+ * @in_ie: Address of IEs to search -+ * @in_len: Length limit from in_ie -+ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie -+ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE -+ * -+ * Returns: The address of the WPS IE found, or NULL -+ */ -+u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) -+{ -+ uint cnt; -+ u8 *wpsie_ptr = NULL; -+ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; -+ -+ if (wps_ielen) -+ *wps_ielen = 0; -+ -+ if (!in_ie || in_len <= 0) -+ return wpsie_ptr; -+ -+ cnt = 0; -+ -+ while (cnt < in_len) { -+ eid = in_ie[cnt]; -+ -+ if ((eid == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt+2], wps_oui, 4))) { -+ wpsie_ptr = &in_ie[cnt]; -+ -+ if (wps_ie) -+ memcpy(wps_ie, &in_ie[cnt], in_ie[cnt+1]+2); -+ -+ if (wps_ielen) -+ *wps_ielen = in_ie[cnt+1]+2; -+ -+ cnt += in_ie[cnt+1]+2; -+ -+ break; -+ } else { -+ cnt += in_ie[cnt+1]+2; /* goto next */ -+ } -+ } -+ return wpsie_ptr; -+} -+ -+/** -+ * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE -+ * @wps_ie: Address of WPS IE to search -+ * @wps_ielen: Length limit from wps_ie -+ * @target_attr_id: The attribute ID of WPS attribute to search -+ * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr -+ * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute -+ * -+ * Returns: the address of the specific WPS attribute found, or NULL -+ */ -+u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_attr, u32 *len_attr) -+{ -+ u8 *attr_ptr = NULL; -+ u8 *target_attr_ptr = NULL; -+ u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04}; -+ -+ if (len_attr) -+ *len_attr = 0; -+ -+ if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) || -+ (memcmp(wps_ie + 2, wps_oui , 4))) -+ return attr_ptr; -+ -+ /* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */ -+ attr_ptr = wps_ie + 6; /* goto first attr */ -+ -+ while (attr_ptr - wps_ie < wps_ielen) { -+ /* 4 = 2(Attribute ID) + 2(Length) */ -+ u16 attr_id = RTW_GET_BE16(attr_ptr); -+ u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2); -+ u16 attr_len = attr_data_len + 4; -+ -+ if (attr_id == target_attr_id) { -+ target_attr_ptr = attr_ptr; -+ if (buf_attr) -+ memcpy(buf_attr, attr_ptr, attr_len); -+ if (len_attr) -+ *len_attr = attr_len; -+ break; -+ } else { -+ attr_ptr += attr_len; /* goto next */ -+ } -+ } -+ return target_attr_ptr; -+} -+ -+/** -+ * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE -+ * @wps_ie: Address of WPS IE to search -+ * @wps_ielen: Length limit from wps_ie -+ * @target_attr_id: The attribute ID of WPS attribute to search -+ * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content -+ * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content -+ * -+ * Returns: the address of the specific WPS attribute content found, or NULL -+ */ -+u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_content, uint *len_content) -+{ -+ u8 *attr_ptr; -+ u32 attr_len; -+ -+ if (len_content) -+ *len_content = 0; -+ -+ attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len); -+ -+ if (attr_ptr && attr_len) { -+ if (buf_content) -+ memcpy(buf_content, attr_ptr+4, attr_len-4); -+ -+ if (len_content) -+ *len_content = attr_len-4; -+ -+ return attr_ptr+4; -+ } -+ -+ return NULL; -+} -+ -+static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, -+ struct rtw_ieee802_11_elems *elems, -+ int show_errors) -+{ -+ unsigned int oui; -+ -+ /* first 3 bytes in vendor specific information element are the IEEE -+ * OUI of the vendor. The following byte is used a vendor specific -+ * sub-type. */ -+ if (elen < 4) { -+ if (show_errors) { -+ DBG_88E("short vendor specific information element ignored (len=%lu)\n", -+ (unsigned long) elen); -+ } -+ return -1; -+ } -+ -+ oui = RTW_GET_BE24(pos); -+ switch (oui) { -+ case OUI_MICROSOFT: -+ /* Microsoft/Wi-Fi information elements are further typed and -+ * subtyped */ -+ switch (pos[3]) { -+ case 1: -+ /* Microsoft OUI (00:50:F2) with OUI Type 1: -+ * real WPA information element */ -+ elems->wpa_ie = pos; -+ elems->wpa_ie_len = elen; -+ break; -+ case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ -+ if (elen < 5) { -+ DBG_88E("short WME information element ignored (len=%lu)\n", -+ (unsigned long) elen); -+ return -1; -+ } -+ switch (pos[4]) { -+ case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: -+ case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: -+ elems->wme = pos; -+ elems->wme_len = elen; -+ break; -+ case WME_OUI_SUBTYPE_TSPEC_ELEMENT: -+ elems->wme_tspec = pos; -+ elems->wme_tspec_len = elen; -+ break; -+ default: -+ DBG_88E("unknown WME information element ignored (subtype=%d len=%lu)\n", -+ pos[4], (unsigned long) elen); -+ return -1; -+ } -+ break; -+ case 4: -+ /* Wi-Fi Protected Setup (WPS) IE */ -+ elems->wps_ie = pos; -+ elems->wps_ie_len = elen; -+ break; -+ default: -+ DBG_88E("Unknown Microsoft information element ignored (type=%d len=%lu)\n", -+ pos[3], (unsigned long) elen); -+ return -1; -+ } -+ break; -+ -+ case OUI_BROADCOM: -+ switch (pos[3]) { -+ case VENDOR_HT_CAPAB_OUI_TYPE: -+ elems->vendor_ht_cap = pos; -+ elems->vendor_ht_cap_len = elen; -+ break; -+ default: -+ DBG_88E("Unknown Broadcom information element ignored (type=%d len=%lu)\n", -+ pos[3], (unsigned long) elen); -+ return -1; -+ } -+ break; -+ default: -+ DBG_88E("unknown vendor specific information element ignored (vendor OUI %02x:%02x:%02x len=%lu)\n", -+ pos[0], pos[1], pos[2], (unsigned long) elen); -+ return -1; -+ } -+ return 0; -+} -+ -+/** -+ * ieee802_11_parse_elems - Parse information elements in management frames -+ * @start: Pointer to the start of IEs -+ * @len: Length of IE buffer in octets -+ * @elems: Data structure for parsed elements -+ * @show_errors: Whether to show parsing errors in debug log -+ * Returns: Parsing result -+ */ -+enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len, -+ struct rtw_ieee802_11_elems *elems, -+ int show_errors) -+{ -+ uint left = len; -+ u8 *pos = start; -+ int unknown = 0; -+ -+ memset(elems, 0, sizeof(*elems)); -+ -+ while (left >= 2) { -+ u8 id, elen; -+ -+ id = *pos++; -+ elen = *pos++; -+ left -= 2; -+ -+ if (elen > left) { -+ if (show_errors) { -+ DBG_88E("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n", -+ id, elen, (unsigned long) left); -+ } -+ return ParseFailed; -+ } -+ -+ switch (id) { -+ case WLAN_EID_SSID: -+ elems->ssid = pos; -+ elems->ssid_len = elen; -+ break; -+ case WLAN_EID_SUPP_RATES: -+ elems->supp_rates = pos; -+ elems->supp_rates_len = elen; -+ break; -+ case WLAN_EID_FH_PARAMS: -+ elems->fh_params = pos; -+ elems->fh_params_len = elen; -+ break; -+ case WLAN_EID_DS_PARAMS: -+ elems->ds_params = pos; -+ elems->ds_params_len = elen; -+ break; -+ case WLAN_EID_CF_PARAMS: -+ elems->cf_params = pos; -+ elems->cf_params_len = elen; -+ break; -+ case WLAN_EID_TIM: -+ elems->tim = pos; -+ elems->tim_len = elen; -+ break; -+ case WLAN_EID_IBSS_PARAMS: -+ elems->ibss_params = pos; -+ elems->ibss_params_len = elen; -+ break; -+ case WLAN_EID_CHALLENGE: -+ elems->challenge = pos; -+ elems->challenge_len = elen; -+ break; -+ case WLAN_EID_ERP_INFO: -+ elems->erp_info = pos; -+ elems->erp_info_len = elen; -+ break; -+ case WLAN_EID_EXT_SUPP_RATES: -+ elems->ext_supp_rates = pos; -+ elems->ext_supp_rates_len = elen; -+ break; -+ case WLAN_EID_VENDOR_SPECIFIC: -+ if (rtw_ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors)) -+ unknown++; -+ break; -+ case WLAN_EID_RSN: -+ elems->rsn_ie = pos; -+ elems->rsn_ie_len = elen; -+ break; -+ case WLAN_EID_PWR_CAPABILITY: -+ elems->power_cap = pos; -+ elems->power_cap_len = elen; -+ break; -+ case WLAN_EID_SUPPORTED_CHANNELS: -+ elems->supp_channels = pos; -+ elems->supp_channels_len = elen; -+ break; -+ case WLAN_EID_MOBILITY_DOMAIN: -+ elems->mdie = pos; -+ elems->mdie_len = elen; -+ break; -+ case WLAN_EID_FAST_BSS_TRANSITION: -+ elems->ftie = pos; -+ elems->ftie_len = elen; -+ break; -+ case WLAN_EID_TIMEOUT_INTERVAL: -+ elems->timeout_int = pos; -+ elems->timeout_int_len = elen; -+ break; -+ case WLAN_EID_HT_CAP: -+ elems->ht_capabilities = pos; -+ elems->ht_capabilities_len = elen; -+ break; -+ case WLAN_EID_HT_OPERATION: -+ elems->ht_operation = pos; -+ elems->ht_operation_len = elen; -+ break; -+ default: -+ unknown++; -+ if (!show_errors) -+ break; -+ DBG_88E("IEEE 802.11 element parse ignored unknown element (id=%d elen=%d)\n", -+ id, elen); -+ break; -+ } -+ left -= elen; -+ pos += elen; -+ } -+ if (left) -+ return ParseFailed; -+ return unknown ? ParseUnknown : ParseOK; -+} -+ -+u8 key_char2num(u8 ch) -+{ -+ if ((ch >= '0') && (ch <= '9')) -+ return ch - '0'; -+ else if ((ch >= 'a') && (ch <= 'f')) -+ return ch - 'a' + 10; -+ else if ((ch >= 'A') && (ch <= 'F')) -+ return ch - 'A' + 10; -+ else -+ return 0xff; -+} -+ -+u8 str_2char2num(u8 hch, u8 lch) -+{ -+ return (key_char2num(hch) * 10) + key_char2num(lch); -+} -+ -+u8 key_2char2num(u8 hch, u8 lch) -+{ -+ return (key_char2num(hch) << 4) | key_char2num(lch); -+} -+ -+void rtw_macaddr_cfg(u8 *mac_addr) -+{ -+ u8 mac[ETH_ALEN]; -+ if (mac_addr == NULL) -+ return; -+ -+ if (rtw_initmac) { /* Users specify the mac address */ -+ int jj, kk; -+ -+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) -+ mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk + 1]); -+ memcpy(mac_addr, mac, ETH_ALEN); -+ } else { /* Use the mac address stored in the Efuse */ -+ memcpy(mac, mac_addr, ETH_ALEN); -+ } -+ -+ if (((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) && -+ (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff)) || -+ ((mac[0] == 0x0) && (mac[1] == 0x0) && (mac[2] == 0x0) && -+ (mac[3] == 0x0) && (mac[4] == 0x0) && (mac[5] == 0x0))) { -+ mac[0] = 0x00; -+ mac[1] = 0xe0; -+ mac[2] = 0x4c; -+ mac[3] = 0x87; -+ mac[4] = 0x00; -+ mac[5] = 0x00; -+ /* use default mac addresss */ -+ memcpy(mac_addr, mac, ETH_ALEN); -+ DBG_88E("MAC Address from efuse error, assign default one !!!\n"); -+ } -+ -+ DBG_88E("rtw_macaddr_cfg MAC Address = %pM\n", (mac_addr)); -+} -+ -+void dump_ies(u8 *buf, u32 buf_len) -+{ -+ u8 *pos = (u8 *)buf; -+ u8 id, len; -+ -+ while (pos-buf <= buf_len) { -+ id = *pos; -+ len = *(pos+1); -+ -+ DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len); -+ #ifdef CONFIG_88EU_P2P -+ dump_p2p_ie(pos, len); -+ #endif -+ dump_wps_ie(pos, len); -+ -+ pos += (2 + len); -+ } -+} -+ -+void dump_wps_ie(u8 *ie, u32 ie_len) -+{ -+ u8 *pos = (u8 *)ie; -+ u16 id; -+ u16 len; -+ u8 *wps_ie; -+ uint wps_ielen; -+ -+ wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen); -+ if (wps_ie != ie || wps_ielen == 0) -+ return; -+ -+ pos += 6; -+ while (pos-ie < ie_len) { -+ id = RTW_GET_BE16(pos); -+ len = RTW_GET_BE16(pos + 2); -+ DBG_88E("%s ID:0x%04x, LEN:%u\n", __func__, id, len); -+ pos += (4+len); -+ } -+} -+ -+#ifdef CONFIG_88EU_P2P -+void dump_p2p_ie(u8 *ie, u32 ie_len) -+{ -+ u8 *pos = (u8 *)ie; -+ u8 id; -+ u16 len; -+ u8 *p2p_ie; -+ uint p2p_ielen; -+ -+ p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen); -+ if (p2p_ie != ie || p2p_ielen == 0) -+ return; -+ -+ pos += 6; -+ while (pos-ie < ie_len) { -+ id = *pos; -+ len = get_unaligned_le16(pos+1); -+ DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len); -+ pos += (3+len); -+ } -+} -+ -+/** -+ * rtw_get_p2p_ie - Search P2P IE from a series of IEs -+ * @in_ie: Address of IEs to search -+ * @in_len: Length limit from in_ie -+ * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie -+ * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE -+ * -+ * Returns: The address of the P2P IE found, or NULL -+ */ -+u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen) -+{ -+ uint cnt = 0; -+ u8 *p2p_ie_ptr; -+ u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09}; -+ -+ if (p2p_ielen != NULL) -+ *p2p_ielen = 0; -+ -+ while (cnt < in_len) { -+ eid = in_ie[cnt]; -+ if ((in_len < 0) || (cnt > MAX_IE_SZ)) { -+ dump_stack(); -+ return NULL; -+ } -+ if ((eid == _VENDOR_SPECIFIC_IE_) && !memcmp(&in_ie[cnt+2], p2p_oui, 4)) { -+ p2p_ie_ptr = in_ie + cnt; -+ -+ if (p2p_ie != NULL) -+ memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); -+ if (p2p_ielen != NULL) -+ *p2p_ielen = in_ie[cnt + 1] + 2; -+ return p2p_ie_ptr; -+ } else { -+ cnt += in_ie[cnt + 1] + 2; /* goto next */ -+ } -+ } -+ return NULL; -+} -+ -+/** -+ * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE -+ * @p2p_ie: Address of P2P IE to search -+ * @p2p_ielen: Length limit from p2p_ie -+ * @target_attr_id: The attribute ID of P2P attribute to search -+ * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr -+ * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute -+ * -+ * Returns: the address of the specific WPS attribute found, or NULL -+ */ -+u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_attr, u32 *len_attr) -+{ -+ u8 *attr_ptr = NULL; -+ u8 *target_attr_ptr = NULL; -+ u8 p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09}; -+ -+ if (len_attr) -+ *len_attr = 0; -+ -+ if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) || -+ memcmp(p2p_ie + 2, p2p_oui , 4)) -+ return attr_ptr; -+ -+ /* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */ -+ attr_ptr = p2p_ie + 6; /* goto first attr */ -+ -+ while (attr_ptr - p2p_ie < p2p_ielen) { -+ /* 3 = 1(Attribute ID) + 2(Length) */ -+ u8 attr_id = *attr_ptr; -+ u16 attr_data_len = get_unaligned_le16(attr_ptr + 1); -+ u16 attr_len = attr_data_len + 3; -+ -+ if (attr_id == target_attr_id) { -+ target_attr_ptr = attr_ptr; -+ -+ if (buf_attr) -+ memcpy(buf_attr, attr_ptr, attr_len); -+ if (len_attr) -+ *len_attr = attr_len; -+ break; -+ } else { -+ attr_ptr += attr_len; /* goto next */ -+ } -+ } -+ return target_attr_ptr; -+} -+ -+/** -+ * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE -+ * @p2p_ie: Address of P2P IE to search -+ * @p2p_ielen: Length limit from p2p_ie -+ * @target_attr_id: The attribute ID of P2P attribute to search -+ * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content -+ * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content -+ * -+ * Returns: the address of the specific P2P attribute content found, or NULL -+ */ -+u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_content, uint *len_content) -+{ -+ u8 *attr_ptr; -+ u32 attr_len; -+ -+ if (len_content) -+ *len_content = 0; -+ -+ attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len); -+ -+ if (attr_ptr && attr_len) { -+ if (buf_content) -+ memcpy(buf_content, attr_ptr+3, attr_len-3); -+ -+ if (len_content) -+ *len_content = attr_len-3; -+ -+ return attr_ptr+3; -+ } -+ -+ return NULL; -+} -+ -+u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr) -+{ -+ u32 a_len; -+ -+ *pbuf = attr_id; -+ -+ /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */ -+ RTW_PUT_LE16(pbuf + 1, attr_len); -+ -+ if (pdata_attr) -+ memcpy(pbuf + 3, pdata_attr, attr_len); -+ -+ a_len = attr_len + 3; -+ -+ return a_len; -+} -+ -+static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id) -+{ -+ u8 *target_attr; -+ u32 target_attr_len; -+ uint ielen = ielen_ori; -+ -+ while (1) { -+ target_attr = rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len); -+ if (target_attr && target_attr_len) { -+ u8 *next_attr = target_attr+target_attr_len; -+ uint remain_len = ielen-(next_attr-ie); -+ -+ memset(target_attr, 0, target_attr_len); -+ memcpy(target_attr, next_attr, remain_len); -+ memset(target_attr+remain_len, 0, target_attr_len); -+ *(ie+1) -= target_attr_len; -+ ielen -= target_attr_len; -+ } else { -+ break; -+ } -+ } -+ return ielen; -+} -+ -+void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex, u8 attr_id) -+{ -+ u8 *p2p_ie; -+ uint p2p_ielen, p2p_ielen_ori; -+ -+ p2p_ie = rtw_get_p2p_ie(bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_, NULL, &p2p_ielen_ori); -+ if (p2p_ie) { -+ p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id); -+ if (p2p_ielen != p2p_ielen_ori) { -+ u8 *next_ie_ori = p2p_ie+p2p_ielen_ori; -+ u8 *next_ie = p2p_ie+p2p_ielen; -+ uint remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs); -+ -+ memcpy(next_ie, next_ie_ori, remain_len); -+ memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen); -+ bss_ex->IELength -= p2p_ielen_ori-p2p_ielen; -+ } -+ } -+} -+ -+#endif /* CONFIG_88EU_P2P */ -+ -+/* Baron adds to avoid FreeBSD warning */ -+int ieee80211_is_empty_essid(const char *essid, int essid_len) -+{ -+ /* Single white space is for Linksys APs */ -+ if (essid_len == 1 && essid[0] == ' ') -+ return 1; -+ -+ /* Otherwise, if the entire essid is 0, we assume it is hidden */ -+ while (essid_len) { -+ essid_len--; -+ if (essid[essid_len] != '\0') -+ return 0; -+ } -+ -+ return 1; -+} -+ -+int ieee80211_get_hdrlen(u16 fc) -+{ -+ int hdrlen = 24; -+ -+ switch (WLAN_FC_GET_TYPE(fc)) { -+ case RTW_IEEE80211_FTYPE_DATA: -+ if (fc & RTW_IEEE80211_STYPE_QOS_DATA) -+ hdrlen += 2; -+ if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS)) -+ hdrlen += 6; /* Addr4 */ -+ break; -+ case RTW_IEEE80211_FTYPE_CTL: -+ switch (WLAN_FC_GET_STYPE(fc)) { -+ case RTW_IEEE80211_STYPE_CTS: -+ case RTW_IEEE80211_STYPE_ACK: -+ hdrlen = 10; -+ break; -+ default: -+ hdrlen = 16; -+ break; -+ } -+ break; -+ } -+ -+ return hdrlen; -+} -+ -+static int rtw_get_cipher_info(struct wlan_network *pnetwork) -+{ -+ u32 wpa_ielen; -+ unsigned char *pbuf; -+ int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; -+ int ret = _FAIL; -+ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); -+ -+ if (pbuf && (wpa_ielen > 0)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen)); -+ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { -+ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; -+ pnetwork->BcnInfo.group_cipher = group_cipher; -+ pnetwork->BcnInfo.is_8021x = is8021x; -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d", -+ __func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x)); -+ ret = _SUCCESS; -+ } -+ } else { -+ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); -+ -+ if (pbuf && (wpa_ielen > 0)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n")); -+ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE OK!!!\n")); -+ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; -+ pnetwork->BcnInfo.group_cipher = group_cipher; -+ pnetwork->BcnInfo.is_8021x = is8021x; -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d," -+ "pnetwork->group_cipher is %d, is_8021x is %d", __func__, pnetwork->BcnInfo.pairwise_cipher, -+ pnetwork->BcnInfo.group_cipher, pnetwork->BcnInfo.is_8021x)); -+ ret = _SUCCESS; -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+void rtw_get_bcn_info(struct wlan_network *pnetwork) -+{ -+ unsigned short cap = 0; -+ u8 bencrypt = 0; -+ __le16 le_tmp; -+ u16 wpa_len = 0, rsn_len = 0; -+ struct HT_info_element *pht_info = NULL; -+ struct ieee80211_ht_cap *pht_cap = NULL; -+ unsigned int len; -+ unsigned char *p; -+ -+ memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); -+ cap = le16_to_cpu(le_tmp); -+ if (cap & WLAN_CAPABILITY_PRIVACY) { -+ bencrypt = 1; -+ pnetwork->network.Privacy = 1; -+ } else { -+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; -+ } -+ rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); -+ -+ if (rsn_len > 0) { -+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; -+ } else if (wpa_len > 0) { -+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA; -+ } else { -+ if (bencrypt) -+ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP; -+ } -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", -+ pnetwork->BcnInfo.encryp_protocol)); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n", -+ pnetwork->BcnInfo.encryp_protocol)); -+ rtw_get_cipher_info(pnetwork); -+ -+ /* get bwmode and ch_offset */ -+ /* parsing HT_CAP_IE */ -+ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); -+ if (p && len > 0) { -+ pht_cap = (struct ieee80211_ht_cap *)(p + 2); -+ pnetwork->BcnInfo.ht_cap_info = le16_to_cpu(pht_cap->cap_info); -+ } else { -+ pnetwork->BcnInfo.ht_cap_info = 0; -+ } -+ /* parsing HT_INFO_IE */ -+ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); -+ if (p && len > 0) { -+ pht_info = (struct HT_info_element *)(p + 2); -+ pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0]; -+ } else { -+ pnetwork->BcnInfo.ht_info_infos_0 = 0; -+ } -+} -+ -+/* show MCS rate, unit: 100Kbps */ -+u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char *MCS_rate) -+{ -+ u16 max_rate = 0; -+ -+ if (rf_type == RF_1T1R) { -+ if (MCS_rate[0] & BIT(7)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650); -+ else if (MCS_rate[0] & BIT(6)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585); -+ else if (MCS_rate[0] & BIT(5)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520); -+ else if (MCS_rate[0] & BIT(4)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390); -+ else if (MCS_rate[0] & BIT(3)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260); -+ else if (MCS_rate[0] & BIT(2)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195); -+ else if (MCS_rate[0] & BIT(1)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130); -+ else if (MCS_rate[0] & BIT(0)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65); -+ } else { -+ if (MCS_rate[1]) { -+ if (MCS_rate[1] & BIT(7)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 3000 : 2700) : ((short_GI_20) ? 1444 : 1300); -+ else if (MCS_rate[1] & BIT(6)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 2700 : 2430) : ((short_GI_20) ? 1300 : 1170); -+ else if (MCS_rate[1] & BIT(5)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 2400 : 2160) : ((short_GI_20) ? 1156 : 1040); -+ else if (MCS_rate[1] & BIT(4)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1800 : 1620) : ((short_GI_20) ? 867 : 780); -+ else if (MCS_rate[1] & BIT(3)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520); -+ else if (MCS_rate[1] & BIT(2)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390); -+ else if (MCS_rate[1] & BIT(1)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260); -+ else if (MCS_rate[1] & BIT(0)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130); -+ } else { -+ if (MCS_rate[0] & BIT(7)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650); -+ else if (MCS_rate[0] & BIT(6)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585); -+ else if (MCS_rate[0] & BIT(5)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520); -+ else if (MCS_rate[0] & BIT(4)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390); -+ else if (MCS_rate[0] & BIT(3)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260); -+ else if (MCS_rate[0] & BIT(2)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195); -+ else if (MCS_rate[0] & BIT(1)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130); -+ else if (MCS_rate[0] & BIT(0)) -+ max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65); -+ } -+ } -+ return max_rate; -+} -+ -+int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action) -+{ -+ const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr); -+ u16 fc; -+ u8 c, a = 0; -+ -+ fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl); -+ -+ if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) != -+ (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION)) -+ return false; -+ -+ c = frame_body[0]; -+ -+ switch (c) { -+ case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */ -+ break; -+ default: -+ a = frame_body[1]; -+ } -+ -+ if (category) -+ *category = c; -+ if (action) -+ *action = a; -+ -+ return true; -+} -+ -+static const char *_action_public_str[] = { -+ "ACT_PUB_BSSCOEXIST", -+ "ACT_PUB_DSE_ENABLE", -+ "ACT_PUB_DSE_DEENABLE", -+ "ACT_PUB_DSE_REG_LOCATION", -+ "ACT_PUB_EXT_CHL_SWITCH", -+ "ACT_PUB_DSE_MSR_REQ", -+ "ACT_PUB_DSE_MSR_RPRT", -+ "ACT_PUB_MP", -+ "ACT_PUB_DSE_PWR_CONSTRAINT", -+ "ACT_PUB_VENDOR", -+ "ACT_PUB_GAS_INITIAL_REQ", -+ "ACT_PUB_GAS_INITIAL_RSP", -+ "ACT_PUB_GAS_COMEBACK_REQ", -+ "ACT_PUB_GAS_COMEBACK_RSP", -+ "ACT_PUB_TDLS_DISCOVERY_RSP", -+ "ACT_PUB_LOCATION_TRACK", -+ "ACT_PUB_RSVD", -+}; -+ -+const char *action_public_str(u8 action) -+{ -+ action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action; -+ return _action_public_str[action]; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_io.c b/drivers/net/wireless/rtl8188eu/core/rtw_io.c -new file mode 100644 -index 0000000000000..db8576c3647ec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_io.c -@@ -0,0 +1,323 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 purpose of rtw_io.c -+ -+a. provides the API -+ -+b. provides the protocol engine -+ -+c. provides the software interface between caller and the hardware interface -+ -+Compiler Flag Option: -+ -+USB: -+ a. USE_ASYNC_IRP: Both sync/async operations are provided. -+ -+Only sync read/rtw_write_mem operations are provided. -+ -+jackson@realtek.com.tw -+ -+*/ -+ -+#define _RTW_IO_C_ -+#include -+#include -+#include -+#include -+#include -+ -+#define rtw_le16_to_cpu(val) le16_to_cpu(val) -+#define rtw_le32_to_cpu(val) le32_to_cpu(val) -+#define rtw_cpu_to_le16(val) cpu_to_le16(val) -+#define rtw_cpu_to_le32(val) cpu_to_le32(val) -+ -+u8 _rtw_read8(struct adapter *adapter, u32 addr) -+{ -+ u8 r_val; -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); -+ -+ -+ _read8 = pintfhdl->io_ops._read8; -+ r_val = _read8(pintfhdl, addr); -+ -+ return r_val; -+} -+ -+u16 _rtw_read16(struct adapter *adapter, u32 addr) -+{ -+ u16 r_val; -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); -+ -+ _read16 = pintfhdl->io_ops._read16; -+ -+ r_val = _read16(pintfhdl, addr); -+ -+ return r_val; -+} -+ -+u32 _rtw_read32(struct adapter *adapter, u32 addr) -+{ -+ u32 r_val; -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); -+ -+ _read32 = pintfhdl->io_ops._read32; -+ -+ r_val = _read32(pintfhdl, addr); -+ -+ return r_val; -+} -+ -+int _rtw_write8(struct adapter *adapter, u32 addr, u8 val) -+{ -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); -+ int ret; -+ -+ _write8 = pintfhdl->io_ops._write8; -+ -+ ret = _write8(pintfhdl, addr, val); -+ -+ -+ return RTW_STATUS_CODE(ret); -+} -+ -+int _rtw_write16(struct adapter *adapter, u32 addr, u16 val) -+{ -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); -+ int ret; -+ -+ _write16 = pintfhdl->io_ops._write16; -+ -+ ret = _write16(pintfhdl, addr, val); -+ -+ -+ return RTW_STATUS_CODE(ret); -+} -+int _rtw_write32(struct adapter *adapter, u32 addr, u32 val) -+{ -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); -+ int ret; -+ -+ _write32 = pintfhdl->io_ops._write32; -+ -+ ret = _write32(pintfhdl, addr, val); -+ -+ -+ return RTW_STATUS_CODE(ret); -+} -+ -+int _rtw_writeN(struct adapter *adapter, u32 addr , u32 length , u8 *pdata) -+{ -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = (struct intf_hdl *)(&(pio_priv->intf)); -+ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); -+ int ret; -+ -+ _writeN = pintfhdl->io_ops._writeN; -+ -+ ret = _writeN(pintfhdl, addr, length, pdata); -+ -+ -+ return RTW_STATUS_CODE(ret); -+} -+int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val) -+{ -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); -+ int ret; -+ -+ _write8_async = pintfhdl->io_ops._write8_async; -+ -+ ret = _write8_async(pintfhdl, addr, val); -+ -+ -+ return RTW_STATUS_CODE(ret); -+} -+ -+int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val) -+{ -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); -+ int ret; -+ -+ _write16_async = pintfhdl->io_ops._write16_async; -+ ret = _write16_async(pintfhdl, addr, val); -+ -+ return RTW_STATUS_CODE(ret); -+} -+ -+int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val) -+{ -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); -+ int ret; -+ -+ _write32_async = pintfhdl->io_ops._write32_async; -+ ret = _write32_async(pintfhdl, addr, val); -+ -+ return RTW_STATUS_CODE(ret); -+} -+ -+void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -+{ -+ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ -+ -+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) { -+ RT_TRACE(_module_rtl871x_io_c_, _drv_info_, -+ ("rtw_read_mem:bDriverStopped(%d) OR bSurpriseRemoved(%d)", -+ adapter->bDriverStopped, adapter->bSurpriseRemoved)); -+ return; -+ } -+ _read_mem = pintfhdl->io_ops._read_mem; -+ _read_mem(pintfhdl, addr, cnt, pmem); -+ -+} -+ -+void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -+{ -+ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ -+ -+ -+ _write_mem = pintfhdl->io_ops._write_mem; -+ -+ _write_mem(pintfhdl, addr, cnt, pmem); -+ -+ -+} -+ -+void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -+{ -+ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ -+ -+ -+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) { -+ RT_TRACE(_module_rtl871x_io_c_, _drv_info_, -+ ("rtw_read_port:bDriverStopped(%d) OR bSurpriseRemoved(%d)", -+ adapter->bDriverStopped, adapter->bSurpriseRemoved)); -+ return; -+ } -+ -+ _read_port = pintfhdl->io_ops._read_port; -+ -+ _read_port(pintfhdl, addr, cnt, pmem); -+ -+ -+} -+ -+void _rtw_read_port_cancel(struct adapter *adapter) -+{ -+ void (*_read_port_cancel)(struct intf_hdl *pintfhdl); -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ -+ _read_port_cancel = pintfhdl->io_ops._read_port_cancel; -+ -+ if (_read_port_cancel) -+ _read_port_cancel(pintfhdl); -+} -+ -+u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -+{ -+ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ u32 ret = _SUCCESS; -+ -+ -+ -+ _write_port = pintfhdl->io_ops._write_port; -+ -+ ret = _write_port(pintfhdl, addr, cnt, pmem); -+ -+ -+ -+ return ret; -+} -+ -+u32 _rtw_write_port_and_wait(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int timeout_ms) -+{ -+ int ret = _SUCCESS; -+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pmem; -+ struct submit_ctx sctx; -+ -+ rtw_sctx_init(&sctx, timeout_ms); -+ pxmitbuf->sctx = &sctx; -+ -+ ret = _rtw_write_port(adapter, addr, cnt, pmem); -+ -+ if (ret == _SUCCESS) -+ ret = rtw_sctx_wait(&sctx); -+ -+ return ret; -+} -+ -+void _rtw_write_port_cancel(struct adapter *adapter) -+{ -+ void (*_write_port_cancel)(struct intf_hdl *pintfhdl); -+ struct io_priv *pio_priv = &adapter->iopriv; -+ struct intf_hdl *pintfhdl = &(pio_priv->intf); -+ -+ _write_port_cancel = pintfhdl->io_ops._write_port_cancel; -+ -+ if (_write_port_cancel) -+ _write_port_cancel(pintfhdl); -+} -+ -+int rtw_init_io_priv(struct adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops)) -+{ -+ struct io_priv *piopriv = &padapter->iopriv; -+ struct intf_hdl *pintf = &piopriv->intf; -+ -+ if (set_intf_ops == NULL) -+ return _FAIL; -+ -+ piopriv->padapter = padapter; -+ pintf->padapter = padapter; -+ pintf->pintf_dev = adapter_to_dvobj(padapter); -+ -+ set_intf_ops(&pintf->io_ops); -+ -+ return _SUCCESS; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_ioctl_set.c b/drivers/net/wireless/rtl8188eu/core/rtw_ioctl_set.c -new file mode 100644 -index 0000000000000..78974325d8bd2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_ioctl_set.c -@@ -0,0 +1,1118 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_IOCTL_SET_C_ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+extern void indicate_wx_scan_complete_event(struct adapter *padapter); -+ -+#define IS_MAC_ADDRESS_BROADCAST(addr) \ -+(\ -+ ((addr[0] == 0xff) && (addr[1] == 0xff) && \ -+ (addr[2] == 0xff) && (addr[3] == 0xff) && \ -+ (addr[4] == 0xff) && (addr[5] == 0xff)) ? true : false \ -+) -+ -+u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid) -+{ -+ u8 i; -+ u8 ret = true; -+ -+ if (ssid->SsidLength > 32) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid length >32\n")); -+ ret = false; -+ goto exit; -+ } -+ -+ for (i = 0; i < ssid->SsidLength; i++) { -+ /* wifi, printable ascii code must be supported */ -+ if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid has nonprintabl ascii\n")); -+ ret = false; -+ break; -+ } -+ } -+ -+exit: -+ -+ return ret; -+} -+ -+u8 rtw_do_join(struct adapter *padapter) -+{ -+ struct list_head *plist, *phead; -+ u8 *pibss = NULL; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct __queue *queue = &(pmlmepriv->scanned_queue); -+ u8 ret = _SUCCESS; -+ -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ phead = get_list_head(queue); -+ plist = phead->next; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("\n rtw_do_join: phead = %p; plist = %p\n\n\n", phead, plist)); -+ -+ pmlmepriv->cur_network.join_res = -2; -+ -+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); -+ -+ pmlmepriv->pscanned = plist; -+ -+ pmlmepriv->to_join = true; -+ -+ if (list_empty(&queue->queue)) { -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ -+ /* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */ -+ /* we try to issue sitesurvey firstly */ -+ -+ if (!pmlmepriv->LinkDetectInfo.bBusyTraffic || -+ pmlmepriv->to_roaming > 0) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_do_join(): site survey if scanned_queue is empty\n.")); -+ /* submit site_survey_cmd */ -+ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); -+ if (_SUCCESS != ret) { -+ pmlmepriv->to_join = false; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_do_join(): site survey return error\n.")); -+ } -+ } else { -+ pmlmepriv->to_join = false; -+ ret = _FAIL; -+ } -+ -+ goto exit; -+ } else { -+ int select_ret; -+ -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv); -+ if (select_ret == _SUCCESS) { -+ pmlmepriv->to_join = false; -+ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); -+ } else { -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) { -+ /* submit createbss_cmd to change to a ADHOC_MASTER */ -+ -+ /* pmlmepriv->lock has been acquired by caller... */ -+ struct wlan_bssid_ex *pdev_network = &(padapter->registrypriv.dev_network); -+ -+ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; -+ -+ pibss = padapter->registrypriv.dev_network.MacAddress; -+ -+ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); -+ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); -+ -+ rtw_update_registrypriv_dev_network(padapter); -+ -+ rtw_generate_random_ibss(pibss); -+ -+ if (rtw_createbss_cmd(padapter) != _SUCCESS) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>do_goin: rtw_createbss_cmd status FAIL***\n ")); -+ ret = false; -+ goto exit; -+ } -+ pmlmepriv->to_join = false; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("***Error => rtw_select_and_join_from_scanned_queue FAIL under STA_Mode***\n ")); -+ } else { -+ /* can't associate ; reset under-linking */ -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ -+ /* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */ -+ /* we try to issue sitesurvey firstly */ -+ if (!pmlmepriv->LinkDetectInfo.bBusyTraffic || -+ pmlmepriv->to_roaming > 0) { -+ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); -+ if (_SUCCESS != ret) { -+ pmlmepriv->to_join = false; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n.")); -+ } -+ } else { -+ ret = _FAIL; -+ pmlmepriv->to_join = false; -+ } -+ } -+ } -+ } -+ -+exit: -+ -+ return ret; -+} -+ -+u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid) -+{ -+ u8 status = _SUCCESS; -+ u32 cur_time = 0; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ DBG_88E_LEVEL(_drv_info_, "set bssid:%pM\n", bssid); -+ -+ if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 && -+ bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) || -+ (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF && -+ bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) { -+ status = _FAIL; -+ goto exit; -+ } -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ DBG_88E("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); -+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) -+ goto handle_tkip_countermeasure; -+ else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) -+ goto release_mlme_lock; -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); -+ -+ if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) { -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false) -+ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ -+ } else { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set BSSID not the same bssid\n")); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid =%pM\n", (bssid))); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid =%pM\n", (pmlmepriv->cur_network.network.MacAddress))); -+ -+ rtw_disassoc_cmd(padapter, 0, true); -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) -+ rtw_indicate_disconnect(padapter); -+ -+ rtw_free_assoc_resources(padapter, 1); -+ -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { -+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); -+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); -+ } -+ } -+ } -+ -+handle_tkip_countermeasure: -+ /* should we add something here...? */ -+ -+ if (padapter->securitypriv.btkip_countermeasure) { -+ cur_time = jiffies; -+ -+ if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) { -+ padapter->securitypriv.btkip_countermeasure = false; -+ padapter->securitypriv.btkip_countermeasure_time = 0; -+ } else { -+ status = _FAIL; -+ goto release_mlme_lock; -+ } -+ } -+ -+ memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); -+ pmlmepriv->assoc_by_bssid = true; -+ -+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) -+ pmlmepriv->to_join = true; -+ else -+ status = rtw_do_join(padapter); -+ -+release_mlme_lock: -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+exit: -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("rtw_set_802_11_bssid: status=%d\n", status)); -+ -+ return status; -+} -+ -+u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) -+{ -+ u8 status = _SUCCESS; -+ u32 cur_time = 0; -+ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct wlan_network *pnetwork = &pmlmepriv->cur_network; -+ -+ DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n", -+ ssid->Ssid, get_fwstate(pmlmepriv)); -+ -+ if (!padapter->hw_init_completed) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("set_ssid: hw_init_completed == false =>exit!!!\n")); -+ status = _FAIL; -+ goto exit; -+ } -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ DBG_88E("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); -+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { -+ goto handle_tkip_countermeasure; -+ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { -+ goto release_mlme_lock; -+ } -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n")); -+ -+ if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && -+ (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) { -+ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("Set SSID is the same ssid, fw_state = 0x%08x\n", -+ get_fwstate(pmlmepriv))); -+ -+ if (!rtw_is_same_ibss(padapter, pnetwork)) { -+ /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */ -+ rtw_disassoc_cmd(padapter, 0, true); -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) -+ rtw_indicate_disconnect(padapter); -+ -+ rtw_free_assoc_resources(padapter, 1); -+ -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { -+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); -+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); -+ } -+ } else { -+ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ -+ } -+ } else { -+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1); -+ } -+ } else { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set SSID not the same ssid\n")); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->Ssid, (unsigned int)ssid->SsidLength)); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.Ssid, (unsigned int)pmlmepriv->assoc_ssid.SsidLength)); -+ -+ rtw_disassoc_cmd(padapter, 0, true); -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) -+ rtw_indicate_disconnect(padapter); -+ -+ rtw_free_assoc_resources(padapter, 1); -+ -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { -+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); -+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); -+ } -+ } -+ } -+ -+handle_tkip_countermeasure: -+ -+ if (padapter->securitypriv.btkip_countermeasure) { -+ cur_time = jiffies; -+ -+ if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) { -+ padapter->securitypriv.btkip_countermeasure = false; -+ padapter->securitypriv.btkip_countermeasure_time = 0; -+ } else { -+ status = _FAIL; -+ goto release_mlme_lock; -+ } -+ } -+ -+ memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); -+ pmlmepriv->assoc_by_bssid = false; -+ -+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { -+ pmlmepriv->to_join = true; -+ } else { -+ status = rtw_do_join(padapter); -+ } -+ -+release_mlme_lock: -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+exit: -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("-rtw_set_802_11_ssid: status =%d\n", status)); -+ -+ return status; -+} -+ -+u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, -+ enum ndis_802_11_network_infra networktype) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct wlan_network *cur_network = &pmlmepriv->cur_network; -+ enum ndis_802_11_network_infra *pold_state = &(cur_network->network.InfrastructureMode); -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_, -+ ("+rtw_set_802_11_infrastructure_mode: old =%d new =%d fw_state = 0x%08x\n", -+ *pold_state, networktype, get_fwstate(pmlmepriv))); -+ -+ if (*pold_state != networktype) { -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!")); -+ /* DBG_88E("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */ -+ -+ if (*pold_state == Ndis802_11APMode) { -+ /* change to other mode from Ndis802_11APMode */ -+ cur_network->join_res = -1; -+ -+#ifdef CONFIG_88EU_AP_MODE -+ stop_ap_mode(padapter); -+#endif -+ } -+ -+ if ((check_fwstate(pmlmepriv, _FW_LINKED)) || -+ (*pold_state == Ndis802_11IBSS)) -+ rtw_disassoc_cmd(padapter, 0, true); -+ -+ if ((check_fwstate(pmlmepriv, _FW_LINKED)) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) -+ rtw_free_assoc_resources(padapter, 1); -+ -+ if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) { -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) -+ rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */ -+ } -+ -+ *pold_state = networktype; -+ -+ _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE); -+ -+ switch (networktype) { -+ case Ndis802_11IBSS: -+ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); -+ break; -+ case Ndis802_11Infrastructure: -+ set_fwstate(pmlmepriv, WIFI_STATION_STATE); -+ break; -+ case Ndis802_11APMode: -+ set_fwstate(pmlmepriv, WIFI_AP_STATE); -+#ifdef CONFIG_88EU_AP_MODE -+ start_ap_mode(padapter); -+#endif -+ break; -+ case Ndis802_11AutoUnknown: -+ case Ndis802_11InfrastructureMax: -+ break; -+ } -+ spin_unlock_bh(&pmlmepriv->lock); -+ } -+ -+ return true; -+} -+ -+u8 rtw_set_802_11_disassociate(struct adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("MgntActrtw_set_802_11_disassociate: rtw_indicate_disconnect\n")); -+ -+ rtw_disassoc_cmd(padapter, 0, true); -+ rtw_indicate_disconnect(padapter); -+ rtw_free_assoc_resources(padapter, 1); -+ rtw_pwr_wakeup(padapter); -+ } -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+ return true; -+} -+ -+u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ u8 res = true; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv))); -+ -+ if (padapter == NULL) { -+ res = false; -+ goto exit; -+ } -+ if (!padapter->hw_init_completed) { -+ res = false; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === rtw_set_802_11_bssid_list_scan:hw_init_completed == false ===\n")); -+ goto exit; -+ } -+ -+ if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) || -+ (pmlmepriv->LinkDetectInfo.bBusyTraffic)) { -+ /* Scan or linking is in progress, do nothing. */ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv))); -+ res = true; -+ -+ if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)) == true) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n")); -+ } else { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###pmlmepriv->sitesurveyctrl.traffic_busy == true\n\n")); -+ } -+ } else { -+ if (rtw_is_scan_deny(padapter)) { -+ DBG_88E(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter)); -+ indicate_wx_scan_complete_event(padapter); -+ return _SUCCESS; -+ } -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0); -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ } -+exit: -+ -+ return res; -+} -+ -+u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_auth_mode authmode) -+{ -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ int res; -+ u8 ret; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_802_11_auth.mode(): mode =%x\n", authmode)); -+ -+ psecuritypriv->ndisauthtype = authmode; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype=%d", -+ psecuritypriv->ndisauthtype)); -+ -+ if (psecuritypriv->ndisauthtype > 3) -+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; -+ -+ res = rtw_set_auth(padapter, psecuritypriv); -+ -+ if (res == _SUCCESS) -+ ret = true; -+ else -+ ret = false; -+ -+ return ret; -+} -+ -+u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep) -+{ -+ int keyid, res; -+ struct security_priv *psecuritypriv = &(padapter->securitypriv); -+ u8 ret = _SUCCESS; -+ -+ keyid = wep->KeyIndex & 0x3fffffff; -+ -+ if (keyid >= 4) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MgntActrtw_set_802_11_add_wep:keyid>4 =>fail\n")); -+ ret = false; -+ goto exit; -+ } -+ -+ switch (wep->KeyLength) { -+ case 5: -+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 5\n")); -+ break; -+ case 13: -+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 13\n")); -+ break; -+ default: -+ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength!= 5 or 13\n")); -+ break; -+ } -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("rtw_set_802_11_add_wep:befor memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n", -+ wep->KeyLength, wep->KeyIndex, keyid)); -+ -+ memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength); -+ -+ psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength; -+ -+ psecuritypriv->dot11PrivacyKeyIndex = keyid; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("rtw_set_802_11_add_wep:security key material : %x %x %x %x %x %x %x %x %x %x %x %x %x\n", -+ psecuritypriv->dot11DefKey[keyid].skey[0], -+ psecuritypriv->dot11DefKey[keyid].skey[1], -+ psecuritypriv->dot11DefKey[keyid].skey[2], -+ psecuritypriv->dot11DefKey[keyid].skey[3], -+ psecuritypriv->dot11DefKey[keyid].skey[4], -+ psecuritypriv->dot11DefKey[keyid].skey[5], -+ psecuritypriv->dot11DefKey[keyid].skey[6], -+ psecuritypriv->dot11DefKey[keyid].skey[7], -+ psecuritypriv->dot11DefKey[keyid].skey[8], -+ psecuritypriv->dot11DefKey[keyid].skey[9], -+ psecuritypriv->dot11DefKey[keyid].skey[10], -+ psecuritypriv->dot11DefKey[keyid].skey[11], -+ psecuritypriv->dot11DefKey[keyid].skey[12])); -+ -+ res = rtw_set_key(padapter, psecuritypriv, keyid, 1); -+ -+ if (res == _FAIL) -+ ret = false; -+exit: -+ -+ return ret; -+} -+ -+u8 rtw_set_802_11_remove_wep(struct adapter *padapter, u32 keyindex) -+{ -+ u8 ret = _SUCCESS; -+ -+ if (keyindex >= 0x80000000 || padapter == NULL) { -+ ret = false; -+ goto exit; -+ } else { -+ int res; -+ struct security_priv *psecuritypriv = &(padapter->securitypriv); -+ if (keyindex < 4) { -+ memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16); -+ res = rtw_set_key(padapter, psecuritypriv, keyindex, 0); -+ psecuritypriv->dot11DefKeylen[keyindex] = 0; -+ if (res == _FAIL) -+ ret = _FAIL; -+ } else { -+ ret = _FAIL; -+ } -+ } -+exit: -+ -+ return ret; -+} -+ -+u8 rtw_set_802_11_add_key(struct adapter *padapter, struct ndis_802_11_key *key) -+{ -+ uint encryptionalgo; -+ u8 *pbssid; -+ struct sta_info *stainfo; -+ u8 bgroup = false; -+ u8 bgrouptkey = false;/* can be removed later */ -+ u8 ret = _SUCCESS; -+ -+ if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) { -+ /* It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */ -+ /* it must fail the request and return NDIS_STATUS_INVALID_DATA. */ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("rtw_set_802_11_add_key: ((key->KeyIndex & 0x80000000)==0)[=%d]", -+ (int)(key->KeyIndex & 0x80000000) == 0)); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("rtw_set_802_11_add_key:((key->KeyIndex & 0x40000000)>0)[=%d]", -+ (int)(key->KeyIndex & 0x40000000) > 0)); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, -+ ("rtw_set_802_11_add_key: key->KeyIndex=%d\n", -+ (int)key->KeyIndex)); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ if (key->KeyIndex & 0x40000000) { -+ /* Pairwise key */ -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ Pairwise key +++++\n")); -+ -+ pbssid = get_bssid(&padapter->mlmepriv); -+ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid); -+ -+ if ((stainfo != NULL) && (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("OID_802_11_ADD_KEY:(stainfo!=NULL)&&(Adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X)\n")); -+ encryptionalgo = stainfo->dot118021XPrivacy; -+ } else { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: stainfo == NULL)||(Adapter->securitypriv.dot11AuthAlgrthm!= dot11AuthAlgrthm_8021X)\n")); -+ encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm; -+ } -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("rtw_set_802_11_add_key: (encryptionalgo==%d)!\n", -+ encryptionalgo)); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11PrivacyAlgrthm==%d)!\n", -+ padapter->securitypriv.dot11PrivacyAlgrthm)); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11AuthAlgrthm==%d)!\n", -+ padapter->securitypriv.dot11AuthAlgrthm)); -+ -+ if ((stainfo != NULL)) -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("rtw_set_802_11_add_key: (stainfo->dot118021XPrivacy==%d)!\n", -+ stainfo->dot118021XPrivacy)); -+ -+ if (key->KeyIndex & 0x000000FF) { -+ /* The key index is specified in the lower 8 bits by values of zero to 255. */ -+ /* The key index should be set to zero for a Pairwise key, and the driver should fail with */ -+ /* NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero */ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, (" key->KeyIndex & 0x000000FF.\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* check BSSID */ -+ if (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == true) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MacAddr_isBcst(key->BSSID)\n")); -+ ret = false; -+ goto exit; -+ } -+ -+ /* Check key length for TKIP. */ -+ if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("TKIP KeyLength:0x%x != 32\n", key->KeyLength)); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* Check key length for AES. */ -+ if ((encryptionalgo == _AES_) && (key->KeyLength != 16)) { -+ /* For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. */ -+ if (key->KeyLength == 32) { -+ key->KeyLength = 16; -+ } else { -+ ret = _FAIL; -+ goto exit; -+ } -+ } -+ -+ /* Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. */ -+ if ((encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_) && -+ (key->KeyLength != 5 && key->KeyLength != 13)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("WEP KeyLength:0x%x != 5 or 13\n", key->KeyLength)); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ bgroup = false; -+ -+ /* Check the pairwise key. Added by Annie, 2005-07-06. */ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("[Pairwise Key set]\n")); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key index: 0x%8x(0x%8x)\n", key->KeyIndex, (key->KeyIndex&0x3))); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key Length: %d\n", key->KeyLength)); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")); -+ -+ } else { -+ /* Group key - KeyIndex(BIT30 == 0) */ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ Group key +++++\n")); -+ -+ /* when add wep key through add key and didn't assigned encryption type before */ -+ if ((padapter->securitypriv.ndisauthtype <= 3) && -+ (padapter->securitypriv.dot118021XGrpPrivacy == 0)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("keylen =%d(Adapter->securitypriv.dot11PrivacyAlgrthm=%x )padapter->securitypriv.dot118021XGrpPrivacy(%x)\n", -+ key->KeyLength, padapter->securitypriv.dot11PrivacyAlgrthm, -+ padapter->securitypriv.dot118021XGrpPrivacy)); -+ switch (key->KeyLength) { -+ case 5: -+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n", -+ padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength)); -+ break; -+ case 13: -+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n", -+ padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength)); -+ break; -+ default: -+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n", -+ padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength)); -+ break; -+ } -+ -+ encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ (" Adapter->securitypriv.dot11PrivacyAlgrthm=%x\n", -+ padapter->securitypriv.dot11PrivacyAlgrthm)); -+ -+ } else { -+ encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("(Adapter->securitypriv.dot11PrivacyAlgrthm=%x)encryptionalgo(%x)=padapter->securitypriv.dot118021XGrpPrivacy(%x)keylen=%d\n", -+ padapter->securitypriv.dot11PrivacyAlgrthm, encryptionalgo, -+ padapter->securitypriv.dot118021XGrpPrivacy, key->KeyLength)); -+ } -+ -+ if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) == true) && (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == false)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ (" IBSS but BSSID is not Broadcast Address.\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* Check key length for TKIP */ -+ if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) { -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ (" TKIP GTK KeyLength:%u != 32\n", key->KeyLength)); -+ ret = _FAIL; -+ goto exit; -+ } else if (encryptionalgo == _AES_ && (key->KeyLength != 16 && key->KeyLength != 32)) { -+ /* Check key length for AES */ -+ /* For NDTEST, we allow keylen = 32 in this case. 2005.01.27, by rcnjko. */ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("<=== SetInfo, OID_802_11_ADD_KEY: AES GTK KeyLength:%u != 16 or 32\n", -+ key->KeyLength)); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. */ -+ if ((encryptionalgo == _AES_) && (key->KeyLength == 32)) { -+ key->KeyLength = 16; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("AES key length changed: %u\n", key->KeyLength)); -+ } -+ -+ if (key->KeyIndex & 0x8000000) {/* error ??? 0x8000_0000 */ -+ bgrouptkey = true; -+ } -+ -+ if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE)) && -+ (check_fwstate(&padapter->mlmepriv, _FW_LINKED))) -+ bgrouptkey = true; -+ bgroup = true; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("[Group Key set]\n")); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")) ; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key index: 0x%8x(0x%8x)\n", key->KeyIndex, (key->KeyIndex&0x3))); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key Length: %d\n", key->KeyLength)) ; -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")); -+ } -+ -+ /* If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). */ -+ if ((padapter->securitypriv.dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) && -+ (encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_)) { -+ u32 keyindex; -+ u32 len = FIELD_OFFSET(struct ndis_802_11_key, KeyMaterial) + key->KeyLength; -+ struct ndis_802_11_wep *wep = &padapter->securitypriv.ndiswep; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ WEP key +++++\n")); -+ -+ wep->Length = len; -+ keyindex = key->KeyIndex&0x7fffffff; -+ wep->KeyIndex = keyindex ; -+ wep->KeyLength = key->KeyLength; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY:Before memcpy\n")); -+ -+ memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength); -+ memcpy(&(padapter->securitypriv.dot11DefKey[keyindex].skey[0]), key->KeyMaterial, key->KeyLength); -+ -+ padapter->securitypriv.dot11DefKeylen[keyindex] = key->KeyLength; -+ padapter->securitypriv.dot11PrivacyKeyIndex = keyindex; -+ -+ ret = rtw_set_802_11_add_wep(padapter, wep); -+ goto exit; -+ } -+ if (key->KeyIndex & 0x20000000) { -+ /* SetRSC */ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ SetRSC+++++\n")); -+ if (bgroup) { -+ unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL; -+ memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8); -+ } else { -+ unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL; -+ memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8); -+ } -+ } -+ -+ /* Indicate this key idx is used for TX */ -+ /* Save the key in KeyMaterial */ -+ if (bgroup) { /* Group transmit key */ -+ int res; -+ -+ if (bgrouptkey) -+ padapter->securitypriv.dot118021XGrpKeyid = (u8)key->KeyIndex; -+ if ((key->KeyIndex&0x3) == 0) { -+ ret = _FAIL; -+ goto exit; -+ } -+ memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16); -+ memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); -+ memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); -+ -+ if ((key->KeyIndex & 0x10000000)) { -+ memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); -+ memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7])); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n")); -+ } else { -+ memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); -+ memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6], -+ padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7])); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, -+ ("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n")); -+ } -+ -+ /* set group key by index */ -+ memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength); -+ -+ key->KeyIndex = key->KeyIndex & 0x03; -+ -+ padapter->securitypriv.binstallGrpkey = true; -+ -+ padapter->securitypriv.bcheck_grpkey = false; -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("reset group key")); -+ -+ res = rtw_set_key(padapter, &padapter->securitypriv, key->KeyIndex, 1); -+ -+ if (res == _FAIL) -+ ret = _FAIL; -+ -+ goto exit; -+ -+ } else { /* Pairwise Key */ -+ u8 res; -+ -+ pbssid = get_bssid(&padapter->mlmepriv); -+ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid); -+ -+ if (stainfo != NULL) { -+ memset(&stainfo->dot118021x_UncstKey, 0, 16);/* clear keybuffer */ -+ -+ memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16); -+ -+ if (encryptionalgo == _TKIP_) { -+ padapter->securitypriv.busetkipkey = false; -+ -+ /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ -+ -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n========== _set_timer\n")); -+ -+ /* if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] */ -+ if ((key->KeyIndex & 0x10000000)) { -+ memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8); -+ memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8); -+ -+ } else { -+ memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8); -+ memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8); -+ } -+ } -+ -+ /* Set key to CAM through H2C command */ -+ if (bgrouptkey) { /* never go to here */ -+ res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, false); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(group)\n")); -+ } else { -+ res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, true); -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(unicast)\n")); -+ } -+ if (!res) -+ ret = _FAIL; -+ } -+ } -+exit: -+ -+ return ret; -+} -+ -+u8 rtw_set_802_11_remove_key(struct adapter *padapter, struct ndis_802_11_remove_key *key) -+{ -+ u8 *pbssid; -+ struct sta_info *stainfo; -+ u8 bgroup = (key->KeyIndex & 0x4000000) > 0 ? false : true; -+ u8 keyIndex = (u8)key->KeyIndex & 0x03; -+ u8 ret = _SUCCESS; -+ -+ if ((key->KeyIndex & 0xbffffffc) > 0) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ if (bgroup) { -+ /* clear group key by index */ -+ -+ memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16); -+ -+ /* \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. */ -+ } else { -+ pbssid = get_bssid(&padapter->mlmepriv); -+ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid); -+ if (stainfo) { -+ /* clear key by BSSID */ -+ memset(&stainfo->dot118021x_UncstKey, 0, 16); -+ -+ /* \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. */ -+ } else { -+ ret = _FAIL; -+ goto exit; -+ } -+ } -+exit: -+ -+ return ret; -+} -+ -+/* -+* rtw_get_cur_max_rate - -+* @adapter: pointer to struct adapter structure -+* -+* Return 0 or 100Kbps -+*/ -+u16 rtw_get_cur_max_rate(struct adapter *adapter) -+{ -+ int i = 0; -+ u8 *p; -+ u16 rate = 0, max_rate = 0; -+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct registry_priv *pregistrypriv = &adapter->registrypriv; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; -+ struct ieee80211_ht_cap *pht_capie; -+ u8 rf_type = 0; -+ u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0; -+ u16 mcs_rate = 0; -+ u32 ht_ielen = 0; -+ -+ if (adapter->registrypriv.mp_mode == 1) { -+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) -+ return 0; -+ } -+ -+ if ((!check_fwstate(pmlmepriv, _FW_LINKED)) && -+ (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) -+ return 0; -+ -+ if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) { -+ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12); -+ if (p && ht_ielen > 0) { -+ pht_capie = (struct ieee80211_ht_cap *)(p+2); -+ -+ memcpy(&mcs_rate , pht_capie->mcs.rx_mask, 2); -+ -+ /* cur_bwmod is updated by beacon, pmlmeinfo is updated by association response */ -+ bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1 : 0; -+ -+ short_GI_20 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_20) ? 1 : 0; -+ short_GI_40 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_40) ? 1 : 0; -+ -+ rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ max_rate = rtw_mcs_rate( -+ rf_type, -+ bw_40MHz & (pregistrypriv->cbw40_enable), -+ short_GI_20, -+ short_GI_40, -+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate -+ ); -+ } -+ } else { -+ while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) { -+ rate = pcur_bss->SupportedRates[i]&0x7F; -+ if (rate > max_rate) -+ max_rate = rate; -+ i++; -+ } -+ -+ max_rate = max_rate*10/2; -+ } -+ -+ return max_rate; -+} -+ -+/* -+* rtw_set_scan_mode - -+* @adapter: pointer to struct adapter structure -+* @scan_mode: -+* -+* Return _SUCCESS or _FAIL -+*/ -+int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode) -+{ -+ if (scan_mode != SCAN_ACTIVE && scan_mode != SCAN_PASSIVE) -+ return _FAIL; -+ -+ adapter->mlmepriv.scan_mode = scan_mode; -+ -+ return _SUCCESS; -+} -+ -+/* -+* rtw_set_channel_plan - -+* @adapter: pointer to struct adapter structure -+* @channel_plan: -+* -+* Return _SUCCESS or _FAIL -+*/ -+int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan) -+{ -+ /* handle by cmd_thread to sync with scan operation */ -+ return rtw_set_chplan_cmd(adapter, channel_plan, 1); -+} -+ -+/* -+* rtw_set_country - -+* @adapter: pointer to struct adapter structure -+* @country_code: string of country code -+* -+* Return _SUCCESS or _FAIL -+*/ -+int rtw_set_country(struct adapter *adapter, const char *country_code) -+{ -+ int channel_plan = RT_CHANNEL_DOMAIN_WORLD_WIDE_5G; -+ -+ DBG_88E("%s country_code:%s\n", __func__, country_code); -+ -+ /* TODO: should have a table to match country code and RT_CHANNEL_DOMAIN */ -+ /* TODO: should consider 2-character and 3-character country code */ -+ if (0 == strcmp(country_code, "US")) -+ channel_plan = RT_CHANNEL_DOMAIN_FCC; -+ else if (0 == strcmp(country_code, "EU")) -+ channel_plan = RT_CHANNEL_DOMAIN_ETSI; -+ else if (0 == strcmp(country_code, "JP")) -+ channel_plan = RT_CHANNEL_DOMAIN_MKK; -+ else if (0 == strcmp(country_code, "CN")) -+ channel_plan = RT_CHANNEL_DOMAIN_CHINA; -+ else -+ DBG_88E("%s unknown country_code:%s\n", __func__, country_code); -+ -+ return rtw_set_channel_plan(adapter, channel_plan); -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_iol.c b/drivers/net/wireless/rtl8188eu/core/rtw_iol.c -new file mode 100644 -index 0000000000000..e6fdd32f9a3f4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_iol.c -@@ -0,0 +1,209 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include -+ -+struct xmit_frame *rtw_IOL_accquire_xmit_frame(struct adapter *adapter) -+{ -+ struct xmit_frame *xmit_frame; -+ struct xmit_buf *xmitbuf; -+ struct pkt_attrib *pattrib; -+ struct xmit_priv *pxmitpriv = &(adapter->xmitpriv); -+ -+ xmit_frame = rtw_alloc_xmitframe(pxmitpriv); -+ if (xmit_frame == NULL) { -+ DBG_88E("%s rtw_alloc_xmitframe return null\n", __func__); -+ goto exit; -+ } -+ -+ xmitbuf = rtw_alloc_xmitbuf(pxmitpriv); -+ if (xmitbuf == NULL) { -+ DBG_88E("%s rtw_alloc_xmitbuf return null\n", __func__); -+ rtw_free_xmitframe(pxmitpriv, xmit_frame); -+ xmit_frame = NULL; -+ goto exit; -+ } -+ -+ xmit_frame->frame_tag = MGNT_FRAMETAG; -+ xmit_frame->pxmitbuf = xmitbuf; -+ xmit_frame->buf_addr = xmitbuf->pbuf; -+ xmitbuf->priv_data = xmit_frame; -+ -+ pattrib = &xmit_frame->attrib; -+ update_mgntframe_attrib(adapter, pattrib); -+ pattrib->qsel = 0x10;/* Beacon */ -+ pattrib->subtype = WIFI_BEACON; -+ pattrib->pktlen = 0; -+ pattrib->last_txcmdsz = 0; -+exit: -+ return xmit_frame; -+} -+ -+int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len) -+{ -+ struct pkt_attrib *pattrib = &xmit_frame->attrib; -+ u16 buf_offset; -+ u32 ori_len; -+ -+ buf_offset = TXDESC_OFFSET; -+ ori_len = buf_offset+pattrib->pktlen; -+ -+ /* check if the io_buf can accommodate new cmds */ -+ if (ori_len + cmd_len + 8 > MAX_XMITBUF_SZ) { -+ DBG_88E("%s %u is large than MAX_XMITBUF_SZ:%u, can't accommodate new cmds\n", -+ __func__ , ori_len + cmd_len + 8, MAX_XMITBUF_SZ); -+ return _FAIL; -+ } -+ -+ memcpy(xmit_frame->buf_addr + buf_offset + pattrib->pktlen, IOL_cmds, cmd_len); -+ pattrib->pktlen += cmd_len; -+ pattrib->last_txcmdsz += cmd_len; -+ -+ return _SUCCESS; -+} -+ -+bool rtw_IOL_applied(struct adapter *adapter) -+{ -+ if (1 == adapter->registrypriv.fw_iol) -+ return true; -+ -+ if ((2 == adapter->registrypriv.fw_iol) && (!adapter_to_dvobj(adapter)->ishighspeed)) -+ return true; -+ return false; -+} -+ -+int rtw_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) -+{ -+ return rtw_hal_iol_cmd(adapter, xmit_frame, max_wating_ms, bndy_cnt); -+} -+ -+int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) -+{ -+ return _SUCCESS; -+} -+ -+int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask) -+{ -+ struct ioreg_cfg cmd = {8, IOREG_CMD_WB_REG, 0x0, 0x0, 0x0}; -+ -+ cmd.address = cpu_to_le16(addr); -+ cmd.data = cpu_to_le32(value); -+ -+ if (mask != 0xFF) { -+ cmd.length = 12; -+ cmd.mask = cpu_to_le32(mask); -+ } -+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); -+} -+ -+int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask) -+{ -+ struct ioreg_cfg cmd = {8, IOREG_CMD_WW_REG, 0x0, 0x0, 0x0}; -+ -+ cmd.address = cpu_to_le16(addr); -+ cmd.data = cpu_to_le32(value); -+ -+ if (mask != 0xFFFF) { -+ cmd.length = 12; -+ cmd.mask = cpu_to_le32(mask); -+ } -+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); -+} -+ -+int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask) -+{ -+ struct ioreg_cfg cmd = {8, IOREG_CMD_WD_REG, 0x0, 0x0, 0x0}; -+ -+ cmd.address = cpu_to_le16(addr); -+ cmd.data = cpu_to_le32(value); -+ -+ if (mask != 0xFFFFFFFF) { -+ cmd.length = 12; -+ cmd.mask = cpu_to_le32(mask); -+ } -+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); -+} -+ -+int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask) -+{ -+ struct ioreg_cfg cmd = {8, IOREG_CMD_W_RF, 0x0, 0x0, 0x0}; -+ -+ cmd.address = cpu_to_le16((rf_path<<8) | ((addr) & 0xFF)); -+ cmd.data = cpu_to_le32(value); -+ -+ if (mask != 0x000FFFFF) { -+ cmd.length = 12; -+ cmd.mask = cpu_to_le32(mask); -+ } -+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); -+} -+ -+int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) -+{ -+ struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; -+ cmd.address = cpu_to_le16(us); -+ -+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); -+} -+ -+int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) -+{ -+ struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; -+ -+ cmd.address = cpu_to_le16(ms); -+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); -+} -+ -+int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) -+{ -+ struct ioreg_cfg cmd = {4, IOREG_CMD_END, cpu_to_le16(0xFFFF), cpu_to_le32(0xFF), 0x0}; -+ -+ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); -+} -+ -+u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame) -+{ -+ u8 is_cmd_bndy = false; -+ if (((pxmit_frame->attrib.pktlen+32)%256) + 8 >= 256) { -+ rtw_IOL_append_END_cmd(pxmit_frame); -+ pxmit_frame->attrib.pktlen = ((((pxmit_frame->attrib.pktlen+32)/256)+1)*256); -+ -+ pxmit_frame->attrib.last_txcmdsz = pxmit_frame->attrib.pktlen; -+ is_cmd_bndy = true; -+ } -+ return is_cmd_bndy; -+} -+ -+void rtw_IOL_cmd_buf_dump(struct adapter *Adapter, int buf_len, u8 *pbuf) -+{ -+ int i; -+ int j = 1; -+ -+ pr_info("###### %s ######\n", __func__); -+ for (i = 0; i < buf_len; i++) { -+ printk("%02x-", *(pbuf+i)); -+ -+ if (j%32 == 0) -+ printk("\n"); -+ j++; -+ } -+ printk("\n"); -+ pr_info("=============ioreg_cmd len=%d===============\n", buf_len); -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_led.c b/drivers/net/wireless/rtl8188eu/core/rtw_led.c -new file mode 100644 -index 0000000000000..32361807bd6f6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_led.c -@@ -0,0 +1,1700 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include -+#include "rtw_led.h" -+ -+/* */ -+/* Description: */ -+/* Callback function of LED BlinkTimer, */ -+/* it just schedules to corresponding BlinkWorkItem/led_blink_hdl */ -+/* */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+void BlinkTimerCallback(struct timer_list *t) -+#else -+void BlinkTimerCallback(void *data) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct LED_871x *pLed = from_timer(pLed, t, BlinkTimer); -+#else -+ struct LED_871x *pLed = (struct LED_871x *)data; -+#endif -+ struct adapter *padapter = pLed->padapter; -+ -+ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped)) -+ return; -+ -+ _set_workitem(&(pLed->BlinkWorkItem)); -+} -+ -+/* */ -+/* Description: */ -+/* Callback function of LED BlinkWorkItem. */ -+/* We dispatch acture LED blink action according to LedStrategy. */ -+/* */ -+void BlinkWorkItemCallback(struct work_struct *work) -+{ -+ struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem); -+ BlinkHandler(pLed); -+} -+ -+/* */ -+/* Description: */ -+/* Reset status of LED_871x object. */ -+/* */ -+void ResetLedStatus(struct LED_871x *pLed) -+{ -+ pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */ -+ pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */ -+ -+ pLed->bLedBlinkInProgress = false; /* true if it is blinking, false o.w.. */ -+ pLed->bLedWPSBlinkInProgress = false; -+ -+ pLed->BlinkTimes = 0; /* Number of times to toggle led state for blinking. */ -+ pLed->BlinkingLedState = LED_UNKNOWN; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */ -+ -+ pLed->bLedNoLinkBlinkInProgress = false; -+ pLed->bLedLinkBlinkInProgress = false; -+ pLed->bLedStartToLinkBlinkInProgress = false; -+ pLed->bLedScanBlinkInProgress = false; -+} -+ -+/*Description: */ -+/* Initialize an LED_871x object. */ -+void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, enum LED_PIN_871x LedPin) -+{ -+ pLed->padapter = padapter; -+ pLed->LedPin = LedPin; -+ -+ ResetLedStatus(pLed); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ timer_setup(&pLed->BlinkTimer, BlinkTimerCallback, 0); -+#else -+ _init_timer(&(pLed->BlinkTimer), padapter->pnetdev, BlinkTimerCallback, pLed); -+#endif -+ _init_workitem(&(pLed->BlinkWorkItem), BlinkWorkItemCallback, pLed); -+} -+ -+/* */ -+/* Description: */ -+/* DeInitialize an LED_871x object. */ -+/* */ -+void DeInitLed871x(struct LED_871x *pLed) -+{ -+ _cancel_workitem_sync(&(pLed->BlinkWorkItem)); -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ ResetLedStatus(pLed); -+} -+ -+/* */ -+/* Description: */ -+/* Implementation of LED blinking behavior. */ -+/* It toggle off LED and schedule corresponding timer if necessary. */ -+/* */ -+ -+static void SwLedBlink(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ u8 bStopBlinking = false; -+ -+ /* Change LED according to BlinkingLedState specified. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); -+ } else { -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); -+ } -+ -+ /* Determine if we shall change LED state again. */ -+ pLed->BlinkTimes--; -+ switch (pLed->CurrLedState) { -+ case LED_BLINK_NORMAL: -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ break; -+ case LED_BLINK_StartToBlink: -+ if (check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE)) -+ bStopBlinking = true; -+ if (check_fwstate(pmlmepriv, _FW_LINKED) && -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || -+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) -+ bStopBlinking = true; -+ else if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ break; -+ case LED_BLINK_WPS: -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ break; -+ default: -+ bStopBlinking = true; -+ break; -+ } -+ -+ if (bStopBlinking) { -+ /* if (padapter->pwrctrlpriv.cpwm >= PS_STATE_S2) */ -+ if (0) { -+ SwLedOff(padapter, pLed); -+ } else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && (!pLed->bLedOn)) { -+ SwLedOn(padapter, pLed); -+ } else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && pLed->bLedOn) { -+ SwLedOff(padapter, pLed); -+ } -+ pLed->BlinkTimes = 0; -+ pLed->bLedBlinkInProgress = false; -+ } else { -+ /* Assign LED state to toggle. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ -+ /* Schedule a timer to toggle LED state. */ -+ switch (pLed->CurrLedState) { -+ case LED_BLINK_NORMAL: -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ break; -+ case LED_BLINK_SLOWLY: -+ case LED_BLINK_StartToBlink: -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); -+ break; -+ case LED_BLINK_WPS: -+ if (pLed->BlinkingLedState == RTW_LED_ON) -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); -+ else -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); -+ break; -+ default: -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); -+ break; -+ } -+ } -+} -+ -+static void SwLedBlink1(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ u8 bStopBlinking = false; -+ -+ /* Change LED according to BlinkingLedState specified. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); -+ } else { -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); -+ } -+ -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ ResetLedStatus(pLed); -+ return; -+ } -+ -+ switch (pLed->CurrLedState) { -+ case LED_BLINK_SLOWLY: -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ break; -+ case LED_BLINK_NORMAL: -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); -+ break; -+ case LED_BLINK_SCAN: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ if (bStopBlinking) { -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->bLedLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_NORMAL; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ pLed->bLedScanBlinkInProgress = false; -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_BLINK_TXRX: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ if (bStopBlinking) { -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->bLedLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_NORMAL; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ pLed->BlinkTimes = 0; -+ pLed->bLedBlinkInProgress = false; -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_BLINK_WPS: -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ break; -+ case LED_BLINK_WPS_STOP: /* WPS success */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) -+ bStopBlinking = false; -+ else -+ bStopBlinking = true; -+ -+ if (bStopBlinking) { -+ pLed->bLedLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_NORMAL; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ -+ pLed->bLedWPSBlinkInProgress = false; -+ } else { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void SwLedBlink2(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ u8 bStopBlinking = false; -+ -+ /* Change LED according to BlinkingLedState specified. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); -+ } else { -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); -+ } -+ -+ switch (pLed->CurrLedState) { -+ case LED_BLINK_SCAN: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState)); -+ -+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ pLed->bLedScanBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ case LED_BLINK_TXRX: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState)); -+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ pLed->bLedBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void SwLedBlink3(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ u8 bStopBlinking = false; -+ -+ /* Change LED according to BlinkingLedState specified. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); -+ } else { -+ if (pLed->CurrLedState != LED_BLINK_WPS_STOP) -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); -+ } -+ -+ switch (pLed->CurrLedState) { -+ case LED_BLINK_SCAN: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ if (!pLed->bLedOn) -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ if (pLed->bLedOn) -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ pLed->bLedScanBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ case LED_BLINK_TXRX: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ if (!pLed->bLedOn) -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ -+ if (pLed->bLedOn) -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ pLed->bLedBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ case LED_BLINK_WPS: -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ break; -+ case LED_BLINK_WPS_STOP: /* WPS success */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); -+ bStopBlinking = false; -+ } else { -+ bStopBlinking = true; -+ } -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void SwLedBlink4(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ struct LED_871x *pLed1 = &(ledpriv->SwLed1); -+ u8 bStopBlinking = false; -+ -+ /* Change LED according to BlinkingLedState specified. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); -+ } else { -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); -+ } -+ -+ if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) { -+ pLed1->BlinkingLedState = RTW_LED_OFF; -+ pLed1->CurrLedState = RTW_LED_OFF; -+ SwLedOff(padapter, pLed1); -+ } -+ -+ switch (pLed->CurrLedState) { -+ case LED_BLINK_SLOWLY: -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ break; -+ case LED_BLINK_StartToBlink: -+ if (pLed->bLedOn) { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); -+ } else { -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ } -+ break; -+ case LED_BLINK_SCAN: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = false; -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ SwLedOff(padapter, pLed); -+ } else { -+ pLed->bLedNoLinkBlinkInProgress = false; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ } -+ pLed->bLedScanBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ case LED_BLINK_TXRX: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ SwLedOff(padapter, pLed); -+ } else { -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ } -+ pLed->bLedBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ case LED_BLINK_WPS: -+ if (pLed->bLedOn) { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); -+ } else { -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ } -+ break; -+ case LED_BLINK_WPS_STOP: /* WPS authentication fail */ -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ break; -+ case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */ -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) { -+ if (pLed->bLedOn) -+ pLed->BlinkTimes = 1; -+ else -+ bStopBlinking = true; -+ } -+ -+ if (bStopBlinking) { -+ pLed->BlinkTimes = 10; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ } -+ break; -+ default: -+ break; -+ } -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink4 CurrLedState %d\n", pLed->CurrLedState)); -+} -+ -+static void SwLedBlink5(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ u8 bStopBlinking = false; -+ -+ /* Change LED according to BlinkingLedState specified. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); -+ } else { -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); -+ } -+ -+ switch (pLed->CurrLedState) { -+ case LED_BLINK_SCAN: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ if (pLed->bLedOn) -+ SwLedOff(padapter, pLed); -+ } else { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ if (!pLed->bLedOn) -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ -+ pLed->bLedScanBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ case LED_BLINK_TXRX: -+ pLed->BlinkTimes--; -+ if (pLed->BlinkTimes == 0) -+ bStopBlinking = true; -+ -+ if (bStopBlinking) { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ if (pLed->bLedOn) -+ SwLedOff(padapter, pLed); -+ } else { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ if (!pLed->bLedOn) -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ -+ pLed->bLedBlinkInProgress = false; -+ } else { -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { -+ SwLedOff(padapter, pLed); -+ } else { -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink5 CurrLedState %d\n", pLed->CurrLedState)); -+} -+ -+static void SwLedBlink6(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ -+ /* Change LED according to BlinkingLedState specified. */ -+ if (pLed->BlinkingLedState == RTW_LED_ON) { -+ SwLedOn(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes)); -+ } else { -+ SwLedOff(padapter, pLed); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes)); -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("<==== blink6\n")); -+} -+ -+ /* ALPHA, added by chiyoko, 20090106 */ -+static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ struct LED_871x *pLed = &(ledpriv->SwLed0); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ switch (LedAction) { -+ case LED_CTL_POWER_ON: -+ case LED_CTL_START_TO_LINK: -+ case LED_CTL_NO_LINK: -+ if (!pLed->bLedNoLinkBlinkInProgress) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ if (pLed->bLedLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_LINK: -+ if (!pLed->bLedLinkBlinkInProgress) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ pLed->bLedLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_NORMAL; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_SITE_SURVEY: -+ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { -+ ; -+ } else if (!pLed->bLedScanBlinkInProgress) { -+ if (IS_LED_WPS_BLINKING(pLed)) -+ return; -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ pLed->bLedScanBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SCAN; -+ pLed->BlinkTimes = 24; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_TX: -+ case LED_CTL_RX: -+ if (!pLed->bLedBlinkInProgress) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedLinkBlinkInProgress = false; -+ } -+ pLed->bLedBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_TXRX; -+ pLed->BlinkTimes = 2; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_START_WPS: /* wait until xinpin finish */ -+ case LED_CTL_START_WPS_BOTTON: -+ if (!pLed->bLedWPSBlinkInProgress) { -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ pLed->bLedWPSBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_WPS; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_STOP_WPS: -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ if (pLed->bLedWPSBlinkInProgress) -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ else -+ pLed->bLedWPSBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_WPS_STOP; -+ if (pLed->bLedOn) { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); -+ } else { -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ break; -+ case LED_CTL_STOP_WPS_FAIL: -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ break; -+ case LED_CTL_POWER_OFF: -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ SwLedOff(padapter, pLed); -+ break; -+ default: -+ break; -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); -+} -+ -+ /* Arcadyan/Sitecom , added by chiyoko, 20090216 */ -+static void SwLedControlMode2(struct adapter *padapter, enum LED_CTL_MODE LedAction) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct LED_871x *pLed = &(ledpriv->SwLed0); -+ -+ switch (LedAction) { -+ case LED_CTL_SITE_SURVEY: -+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { -+ } else if (!pLed->bLedScanBlinkInProgress) { -+ if (IS_LED_WPS_BLINKING(pLed)) -+ return; -+ -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ pLed->bLedScanBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SCAN; -+ pLed->BlinkTimes = 24; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_TX: -+ case LED_CTL_RX: -+ if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ pLed->bLedBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_TXRX; -+ pLed->BlinkTimes = 2; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_LINK: -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ _set_timer(&(pLed->BlinkTimer), 0); -+ break; -+ case LED_CTL_START_WPS: /* wait until xinpin finish */ -+ case LED_CTL_START_WPS_BOTTON: -+ if (!pLed->bLedWPSBlinkInProgress) { -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ pLed->bLedWPSBlinkInProgress = true; -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ break; -+ case LED_CTL_STOP_WPS: -+ pLed->bLedWPSBlinkInProgress = false; -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else { -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ break; -+ case LED_CTL_STOP_WPS_FAIL: -+ pLed->bLedWPSBlinkInProgress = false; -+ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { -+ SwLedOff(padapter, pLed); -+ } else { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+ } -+ break; -+ case LED_CTL_START_TO_LINK: -+ case LED_CTL_NO_LINK: -+ if (!IS_LED_BLINKING(pLed)) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ break; -+ case LED_CTL_POWER_OFF: -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ -+ _set_timer(&(pLed->BlinkTimer), 0); -+ break; -+ default: -+ break; -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState)); -+} -+ -+ /* COREGA, added by chiyoko, 20090316 */ -+ static void SwLedControlMode3(struct adapter *padapter, enum LED_CTL_MODE LedAction) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct LED_871x *pLed = &(ledpriv->SwLed0); -+ -+ switch (LedAction) { -+ case LED_CTL_SITE_SURVEY: -+ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { -+ } else if (!pLed->bLedScanBlinkInProgress) { -+ if (IS_LED_WPS_BLINKING(pLed)) -+ return; -+ -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ pLed->bLedScanBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SCAN; -+ pLed->BlinkTimes = 24; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_TX: -+ case LED_CTL_RX: -+ if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ pLed->bLedBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_TXRX; -+ pLed->BlinkTimes = 2; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_LINK: -+ if (IS_LED_WPS_BLINKING(pLed)) -+ return; -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ -+ _set_timer(&(pLed->BlinkTimer), 0); -+ break; -+ case LED_CTL_START_WPS: /* wait until xinpin finish */ -+ case LED_CTL_START_WPS_BOTTON: -+ if (!pLed->bLedWPSBlinkInProgress) { -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ pLed->bLedWPSBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_WPS; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_STOP_WPS: -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } else { -+ pLed->bLedWPSBlinkInProgress = true; -+ } -+ -+ pLed->CurrLedState = LED_BLINK_WPS_STOP; -+ if (pLed->bLedOn) { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); -+ } else { -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ break; -+ case LED_CTL_STOP_WPS_FAIL: -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ break; -+ case LED_CTL_START_TO_LINK: -+ case LED_CTL_NO_LINK: -+ if (!IS_LED_BLINKING(pLed)) { -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ break; -+ case LED_CTL_POWER_OFF: -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ -+ _set_timer(&(pLed->BlinkTimer), 0); -+ break; -+ default: -+ break; -+ } -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, -+ ("CurrLedState %d\n", pLed->CurrLedState)); -+} -+ -+ /* Edimax-Belkin, added by chiyoko, 20090413 */ -+static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAction) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct LED_871x *pLed = &(ledpriv->SwLed0); -+ struct LED_871x *pLed1 = &(ledpriv->SwLed1); -+ -+ switch (LedAction) { -+ case LED_CTL_START_TO_LINK: -+ if (pLed1->bLedWPSBlinkInProgress) { -+ pLed1->bLedWPSBlinkInProgress = false; -+ _cancel_timer_ex(&(pLed1->BlinkTimer)); -+ -+ pLed1->BlinkingLedState = RTW_LED_OFF; -+ pLed1->CurrLedState = RTW_LED_OFF; -+ -+ if (pLed1->bLedOn) -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ -+ if (!pLed->bLedStartToLinkBlinkInProgress) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ -+ pLed->bLedStartToLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_StartToBlink; -+ if (pLed->bLedOn) { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); -+ } else { -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ } -+ } -+ break; -+ case LED_CTL_LINK: -+ case LED_CTL_NO_LINK: -+ /* LED1 settings */ -+ if (LedAction == LED_CTL_LINK) { -+ if (pLed1->bLedWPSBlinkInProgress) { -+ pLed1->bLedWPSBlinkInProgress = false; -+ _cancel_timer_ex(&(pLed1->BlinkTimer)); -+ -+ pLed1->BlinkingLedState = RTW_LED_OFF; -+ pLed1->CurrLedState = RTW_LED_OFF; -+ -+ if (pLed1->bLedOn) -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ } -+ -+ if (!pLed->bLedNoLinkBlinkInProgress) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_SITE_SURVEY: -+ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { -+ } else if (!pLed->bLedScanBlinkInProgress) { -+ if (IS_LED_WPS_BLINKING(pLed)) -+ return; -+ -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ pLed->bLedScanBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SCAN; -+ pLed->BlinkTimes = 24; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_TX: -+ case LED_CTL_RX: -+ if (!pLed->bLedBlinkInProgress) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) -+ return; -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ pLed->bLedBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_TXRX; -+ pLed->BlinkTimes = 2; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_START_WPS: /* wait until xinpin finish */ -+ case LED_CTL_START_WPS_BOTTON: -+ if (pLed1->bLedWPSBlinkInProgress) { -+ pLed1->bLedWPSBlinkInProgress = false; -+ _cancel_timer_ex(&(pLed1->BlinkTimer)); -+ -+ pLed1->BlinkingLedState = RTW_LED_OFF; -+ pLed1->CurrLedState = RTW_LED_OFF; -+ -+ if (pLed1->bLedOn) -+ _set_timer(&(pLed->BlinkTimer), 0); -+ } -+ -+ if (!pLed->bLedWPSBlinkInProgress) { -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ pLed->bLedWPSBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_WPS; -+ if (pLed->bLedOn) { -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); -+ } else { -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ } -+ } -+ break; -+ case LED_CTL_STOP_WPS: /* WPS connect success */ -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ -+ break; -+ case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */ -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ -+ /* LED1 settings */ -+ if (pLed1->bLedWPSBlinkInProgress) -+ _cancel_timer_ex(&(pLed1->BlinkTimer)); -+ else -+ pLed1->bLedWPSBlinkInProgress = true; -+ pLed1->CurrLedState = LED_BLINK_WPS_STOP; -+ if (pLed1->bLedOn) -+ pLed1->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed1->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ break; -+ case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ pLed->bLedNoLinkBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SLOWLY; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); -+ -+ /* LED1 settings */ -+ if (pLed1->bLedWPSBlinkInProgress) -+ _cancel_timer_ex(&(pLed1->BlinkTimer)); -+ else -+ pLed1->bLedWPSBlinkInProgress = true; -+ pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; -+ pLed1->BlinkTimes = 10; -+ if (pLed1->bLedOn) -+ pLed1->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed1->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); -+ break; -+ case LED_CTL_POWER_OFF: -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ -+ if (pLed->bLedNoLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedNoLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedLinkBlinkInProgress = false; -+ } -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ if (pLed->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedWPSBlinkInProgress = false; -+ } -+ if (pLed->bLedScanBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedScanBlinkInProgress = false; -+ } -+ if (pLed->bLedStartToLinkBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedStartToLinkBlinkInProgress = false; -+ } -+ if (pLed1->bLedWPSBlinkInProgress) { -+ _cancel_timer_ex(&(pLed1->BlinkTimer)); -+ pLed1->bLedWPSBlinkInProgress = false; -+ } -+ pLed1->BlinkingLedState = LED_UNKNOWN; -+ SwLedOff(padapter, pLed); -+ SwLedOff(padapter, pLed1); -+ break; -+ default: -+ break; -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); -+} -+ -+ /* Sercomm-Belkin, added by chiyoko, 20090415 */ -+static void -+SwLedControlMode5( -+ struct adapter *padapter, -+ enum LED_CTL_MODE LedAction -+) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct LED_871x *pLed = &(ledpriv->SwLed0); -+ -+ switch (LedAction) { -+ case LED_CTL_POWER_ON: -+ case LED_CTL_NO_LINK: -+ case LED_CTL_LINK: /* solid blue */ -+ pLed->CurrLedState = RTW_LED_ON; -+ pLed->BlinkingLedState = RTW_LED_ON; -+ -+ _set_timer(&(pLed->BlinkTimer), 0); -+ break; -+ case LED_CTL_SITE_SURVEY: -+ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { -+ } else if (!pLed->bLedScanBlinkInProgress) { -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ pLed->bLedScanBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_SCAN; -+ pLed->BlinkTimes = 24; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_TX: -+ case LED_CTL_RX: -+ if (!pLed->bLedBlinkInProgress) { -+ if (pLed->CurrLedState == LED_BLINK_SCAN) -+ return; -+ pLed->bLedBlinkInProgress = true; -+ pLed->CurrLedState = LED_BLINK_TXRX; -+ pLed->BlinkTimes = 2; -+ if (pLed->bLedOn) -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ else -+ pLed->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); -+ } -+ break; -+ case LED_CTL_POWER_OFF: -+ pLed->CurrLedState = RTW_LED_OFF; -+ pLed->BlinkingLedState = RTW_LED_OFF; -+ -+ if (pLed->bLedBlinkInProgress) { -+ _cancel_timer_ex(&(pLed->BlinkTimer)); -+ pLed->bLedBlinkInProgress = false; -+ } -+ SwLedOff(padapter, pLed); -+ break; -+ default: -+ break; -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState)); -+} -+ -+ /* WNC-Corega, added by chiyoko, 20090902 */ -+static void -+SwLedControlMode6( -+ struct adapter *padapter, -+ enum LED_CTL_MODE LedAction -+) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ struct LED_871x *pLed0 = &(ledpriv->SwLed0); -+ -+ switch (LedAction) { -+ case LED_CTL_POWER_ON: -+ case LED_CTL_LINK: -+ case LED_CTL_NO_LINK: -+ _cancel_timer_ex(&(pLed0->BlinkTimer)); -+ pLed0->CurrLedState = RTW_LED_ON; -+ pLed0->BlinkingLedState = RTW_LED_ON; -+ _set_timer(&(pLed0->BlinkTimer), 0); -+ break; -+ case LED_CTL_POWER_OFF: -+ SwLedOff(padapter, pLed0); -+ break; -+ default: -+ break; -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("ledcontrol 6 Led %d\n", pLed0->CurrLedState)); -+} -+ -+/* */ -+/* Description: */ -+/* Handler function of LED Blinking. */ -+/* We dispatch acture LED blink action according to LedStrategy. */ -+/* */ -+void BlinkHandler(struct LED_871x *pLed) -+{ -+ struct adapter *padapter = pLed->padapter; -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ -+ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped)) -+ return; -+ -+ switch (ledpriv->LedStrategy) { -+ case SW_LED_MODE0: -+ SwLedBlink(pLed); -+ break; -+ case SW_LED_MODE1: -+ SwLedBlink1(pLed); -+ break; -+ case SW_LED_MODE2: -+ SwLedBlink2(pLed); -+ break; -+ case SW_LED_MODE3: -+ SwLedBlink3(pLed); -+ break; -+ case SW_LED_MODE4: -+ SwLedBlink4(pLed); -+ break; -+ case SW_LED_MODE5: -+ SwLedBlink5(pLed); -+ break; -+ case SW_LED_MODE6: -+ SwLedBlink6(pLed); -+ break; -+ default: -+ break; -+ } -+} -+ -+void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ -+ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) || -+ (!padapter->hw_init_completed)) -+ return; -+ -+ if (!ledpriv->bRegUseLed) -+ return; -+ -+ if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on && -+ padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) && -+ (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX || -+ LedAction == LED_CTL_SITE_SURVEY || -+ LedAction == LED_CTL_LINK || -+ LedAction == LED_CTL_NO_LINK || -+ LedAction == LED_CTL_POWER_ON)) -+ return; -+ -+ switch (ledpriv->LedStrategy) { -+ case SW_LED_MODE0: -+ break; -+ case SW_LED_MODE1: -+ SwLedControlMode1(padapter, LedAction); -+ break; -+ case SW_LED_MODE2: -+ SwLedControlMode2(padapter, LedAction); -+ break; -+ case SW_LED_MODE3: -+ SwLedControlMode3(padapter, LedAction); -+ break; -+ case SW_LED_MODE4: -+ SwLedControlMode4(padapter, LedAction); -+ break; -+ case SW_LED_MODE5: -+ SwLedControlMode5(padapter, LedAction); -+ break; -+ case SW_LED_MODE6: -+ SwLedControlMode6(padapter, LedAction); -+ break; -+ default: -+ break; -+ } -+ -+ RT_TRACE(_module_rtl8712_led_c_, _drv_info_, -+ ("LedStrategy:%d, LedAction %d\n", -+ ledpriv->LedStrategy, LedAction)); -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_mlme.c b/drivers/net/wireless/rtl8188eu/core/rtw_mlme.c -new file mode 100644 -index 0000000000000..a30c2bd693139 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_mlme.c -@@ -0,0 +1,2354 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_MLME_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+extern unsigned char MCS_rate_2R[16]; -+extern unsigned char MCS_rate_1R[16]; -+ -+void rtw_set_roaming(struct adapter *adapter, u8 to_roaming) -+{ -+ if (to_roaming == 0) -+ adapter->mlmepriv.to_join = false; -+ adapter->mlmepriv.to_roaming = to_roaming; -+} -+ -+u8 rtw_to_roaming(struct adapter *adapter) -+{ -+ return adapter->mlmepriv.to_roaming; -+} -+ -+int _rtw_init_mlme_priv (struct adapter *padapter) -+{ -+ int i; -+ u8 *pbuf; -+ struct wlan_network *pnetwork; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ int res = _SUCCESS; -+ -+ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */ -+ -+ pmlmepriv->nic_hdl = (u8 *)padapter; -+ -+ pmlmepriv->pscanned = NULL; -+ pmlmepriv->fw_state = 0; -+ pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; -+ pmlmepriv->scan_mode = SCAN_ACTIVE;/* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ -+ -+ spin_lock_init(&(pmlmepriv->lock)); -+ _rtw_init_queue(&(pmlmepriv->free_bss_pool)); -+ _rtw_init_queue(&(pmlmepriv->scanned_queue)); -+ -+ set_scanned_network_val(pmlmepriv, 0); -+ -+ memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); -+ -+ pbuf = rtw_zvmalloc(MAX_BSS_CNT * (sizeof(struct wlan_network))); -+ -+ if (pbuf == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ pmlmepriv->free_bss_buf = pbuf; -+ -+ pnetwork = (struct wlan_network *)pbuf; -+ -+ for (i = 0; i < MAX_BSS_CNT; i++) { -+ INIT_LIST_HEAD(&(pnetwork->list)); -+ -+ list_add_tail(&(pnetwork->list), &(pmlmepriv->free_bss_pool.queue)); -+ -+ pnetwork++; -+ } -+ -+ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ -+ -+ rtw_clear_scan_deny(padapter); -+ -+ rtw_init_mlme_timer(padapter); -+ -+exit: -+ -+ return res; -+} -+ -+static void rtw_mfree_mlme_priv_lock (struct mlme_priv *pmlmepriv) -+{ -+ _rtw_spinlock_free(&pmlmepriv->lock); -+ _rtw_spinlock_free(&(pmlmepriv->free_bss_pool.lock)); -+ _rtw_spinlock_free(&(pmlmepriv->scanned_queue.lock)); -+} -+ -+#if defined (CONFIG_88EU_AP_MODE) -+static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) -+{ -+ kfree(*ppie); -+ *plen = 0; -+ *ppie = NULL; -+} -+ -+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) -+{ -+ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); -+ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len); -+ -+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); -+ rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); -+} -+#else -+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) -+{ -+} -+#endif -+ -+void _rtw_free_mlme_priv (struct mlme_priv *pmlmepriv) -+{ -+ -+ rtw_free_mlme_priv_ie_data(pmlmepriv); -+ -+ if (pmlmepriv) { -+ rtw_mfree_mlme_priv_lock (pmlmepriv); -+ -+ if (pmlmepriv->free_bss_buf) { -+ rtw_vmfree(pmlmepriv->free_bss_buf, MAX_BSS_CNT * sizeof(struct wlan_network)); -+ } -+ } -+ -+} -+ -+int _rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork) -+{ -+ -+ if (pnetwork == NULL) -+ goto exit; -+ -+ spin_lock_bh(&queue->lock); -+ -+ list_add_tail(&pnetwork->list, &queue->queue); -+ -+ spin_unlock_bh(&queue->lock); -+ -+exit: -+ -+ return _SUCCESS; -+} -+ -+struct wlan_network *_rtw_dequeue_network(struct __queue *queue) -+{ -+ struct wlan_network *pnetwork; -+ -+ spin_lock_bh(&queue->lock); -+ -+ if (list_empty(&queue->queue)) { -+ pnetwork = NULL; -+ } else { -+ pnetwork = container_of((&queue->queue)->next, struct wlan_network, list); -+ -+ list_del_init(&(pnetwork->list)); -+ } -+ -+ spin_unlock_bh(&queue->lock); -+ -+ return pnetwork; -+} -+ -+struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv)/* _queue *free_queue) */ -+{ -+ struct wlan_network *pnetwork; -+ struct __queue *free_queue = &pmlmepriv->free_bss_pool; -+ struct list_head *plist = NULL; -+ -+ spin_lock_bh(&free_queue->lock); -+ -+ if (list_empty(&free_queue->queue)) { -+ pnetwork = NULL; -+ goto exit; -+ } -+ plist = (&(free_queue->queue))->next; -+ -+ pnetwork = container_of(plist , struct wlan_network, list); -+ -+ list_del_init(&pnetwork->list); -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("_rtw_alloc_network: ptr=%p\n", plist)); -+ pnetwork->network_type = 0; -+ pnetwork->fixed = false; -+ pnetwork->last_scanned = jiffies; -+ pnetwork->aid = 0; -+ pnetwork->join_res = 0; -+ -+ pmlmepriv->num_of_scanned++; -+ -+exit: -+ spin_unlock_bh(&free_queue->lock); -+ -+ return pnetwork; -+} -+ -+void _rtw_free_network(struct mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall) -+{ -+ u32 curr_time, delta_time; -+ u32 lifetime = SCANQUEUE_LIFETIME; -+ struct __queue *free_queue = &(pmlmepriv->free_bss_pool); -+ -+ if (pnetwork == NULL) -+ return; -+ -+ if (pnetwork->fixed) -+ return; -+ curr_time = jiffies; -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) -+ lifetime = 1; -+ if (!isfreeall) { -+ delta_time = (curr_time - pnetwork->last_scanned)/HZ; -+ if (delta_time < lifetime)/* unit:sec */ -+ return; -+ } -+ spin_lock_bh(&free_queue->lock); -+ list_del_init(&(pnetwork->list)); -+ list_add_tail(&(pnetwork->list), &(free_queue->queue)); -+ pmlmepriv->num_of_scanned--; -+ spin_unlock_bh(&free_queue->lock); -+} -+ -+void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) -+{ -+ struct __queue *free_queue = &(pmlmepriv->free_bss_pool); -+ -+ if (pnetwork == NULL) -+ return; -+ if (pnetwork->fixed) -+ return; -+ list_del_init(&(pnetwork->list)); -+ list_add_tail(&(pnetwork->list), get_list_head(free_queue)); -+ pmlmepriv->num_of_scanned--; -+} -+ -+/* -+ return the wlan_network with the matching addr -+ -+ Shall be calle under atomic context... to avoid possible racing condition... -+*/ -+struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr) -+{ -+ struct list_head *phead, *plist; -+ struct wlan_network *pnetwork = NULL; -+ u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; -+ -+ if (!memcmp(zero_addr, addr, ETH_ALEN)) { -+ pnetwork = NULL; -+ goto exit; -+ } -+ phead = get_list_head(scanned_queue); -+ plist = phead->next; -+ -+ while (plist != phead) { -+ pnetwork = container_of(plist, struct wlan_network , list); -+ if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN)) -+ break; -+ plist = plist->next; -+ } -+ if (plist == phead) -+ pnetwork = NULL; -+exit: -+ -+ return pnetwork; -+} -+ -+void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall) -+{ -+ struct list_head *phead, *plist; -+ struct wlan_network *pnetwork; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct __queue *scanned_queue = &pmlmepriv->scanned_queue; -+ -+ spin_lock_bh(&scanned_queue->lock); -+ -+ phead = get_list_head(scanned_queue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ pnetwork = container_of(plist, struct wlan_network, list); -+ -+ plist = plist->next; -+ -+ _rtw_free_network(pmlmepriv, pnetwork, isfreeall); -+ } -+ spin_unlock_bh(&scanned_queue->lock); -+ -+} -+ -+int rtw_if_up(struct adapter *padapter) -+{ -+ int res; -+ -+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved || -+ (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("rtw_if_up:bDriverStopped(%d) OR bSurpriseRemoved(%d)", -+ padapter->bDriverStopped, padapter->bSurpriseRemoved)); -+ res = false; -+ } else { -+ res = true; -+ } -+ -+ return res; -+} -+ -+void rtw_generate_random_ibss(u8 *pibss) -+{ -+ u32 curtime = jiffies; -+ -+ pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */ -+ pibss[1] = 0x11; -+ pibss[2] = 0x87; -+ pibss[3] = (u8)(curtime & 0xff);/* p[0]; */ -+ pibss[4] = (u8)((curtime>>8) & 0xff);/* p[1]; */ -+ pibss[5] = (u8)((curtime>>16) & 0xff);/* p[2]; */ -+ -+ return; -+} -+ -+u8 *rtw_get_capability_from_ie(u8 *ie) -+{ -+ return ie + 8 + 2; -+} -+ -+u16 rtw_get_capability(struct wlan_bssid_ex *bss) -+{ -+ __le16 val; -+ -+ memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2); -+ -+ return le16_to_cpu(val); -+} -+ -+u8 *rtw_get_timestampe_from_ie(u8 *ie) -+{ -+ return ie + 0; -+} -+ -+u8 *rtw_get_beacon_interval_from_ie(u8 *ie) -+{ -+ return ie + 8; -+} -+ -+int rtw_init_mlme_priv (struct adapter *padapter)/* struct mlme_priv *pmlmepriv) */ -+{ -+ int res; -+ -+ res = _rtw_init_mlme_priv(padapter);/* (pmlmepriv); */ -+ -+ return res; -+} -+ -+void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv) -+{ -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv\n")); -+ _rtw_free_mlme_priv (pmlmepriv); -+ -+} -+ -+static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) -+{ -+ struct wlan_network *pnetwork; -+ -+ pnetwork = _rtw_alloc_network(pmlmepriv); -+ -+ return pnetwork; -+} -+ -+static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, -+ struct wlan_network *pnetwork) -+{ -+ -+ _rtw_free_network_nolock(pmlmepriv, pnetwork); -+ -+} -+ -+void rtw_free_network_queue(struct adapter *dev, u8 isfreeall) -+{ -+ -+ _rtw_free_network_queue(dev, isfreeall); -+ -+} -+ -+/* -+ return the wlan_network with the matching addr -+ -+ Shall be calle under atomic context... to avoid possible racing condition... -+*/ -+struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr) -+{ -+ struct wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr); -+ -+ return pnetwork; -+} -+ -+int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork) -+{ -+ int ret = true; -+ struct security_priv *psecuritypriv = &adapter->securitypriv; -+ -+ if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) && -+ (pnetwork->network.Privacy == 0)) -+ ret = false; -+ else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) && -+ (pnetwork->network.Privacy == 1)) -+ ret = false; -+ else -+ ret = true; -+ return ret; -+} -+ -+static int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) -+{ -+ return (a->Ssid.SsidLength == b->Ssid.SsidLength) && -+ !memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength); -+} -+ -+int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) -+{ -+ u16 s_cap, d_cap; -+ __le16 le_scap, le_dcap; -+ -+ memcpy((u8 *)&le_scap, rtw_get_capability_from_ie(src->IEs), 2); -+ memcpy((u8 *)&le_dcap, rtw_get_capability_from_ie(dst->IEs), 2); -+ -+ s_cap = le16_to_cpu(le_scap); -+ d_cap = le16_to_cpu(le_dcap); -+ -+ return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) && -+ ((!memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN))) && -+ ((!memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength))) && -+ ((s_cap & WLAN_CAPABILITY_IBSS) == -+ (d_cap & WLAN_CAPABILITY_IBSS)) && -+ ((s_cap & WLAN_CAPABILITY_BSS) == -+ (d_cap & WLAN_CAPABILITY_BSS))); -+} -+ -+struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue) -+{ -+ struct list_head *plist, *phead; -+ struct wlan_network *pwlan = NULL; -+ struct wlan_network *oldest = NULL; -+ -+ phead = get_list_head(scanned_queue); -+ -+ plist = phead->next; -+ -+ while (1) { -+ if (phead == plist) -+ break; -+ -+ pwlan = container_of(plist, struct wlan_network, list); -+ -+ if (!pwlan->fixed) { -+ if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned)) -+ oldest = pwlan; -+ } -+ -+ plist = plist->next; -+ } -+ -+ return oldest; -+} -+ -+void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, -+ struct adapter *padapter, bool update_ie) -+{ -+ long rssi_ori = dst->Rssi; -+ u8 sq_smp = src->PhyInfo.SignalQuality; -+ u8 ss_final; -+ u8 sq_final; -+ long rssi_final; -+ -+ rtw_hal_antdiv_rssi_compared(padapter, dst, src); /* this will update src.Rssi, need consider again */ -+ -+ /* The rule below is 1/5 for sample value, 4/5 for history value */ -+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src)) { -+ /* Take the recvpriv's value for the connected AP*/ -+ ss_final = padapter->recvpriv.signal_strength; -+ sq_final = padapter->recvpriv.signal_qual; -+ /* the rssi value here is undecorated, and will be used for antenna diversity */ -+ if (sq_smp != 101) /* from the right channel */ -+ rssi_final = dst->Rssi; //(src->Rssi+dst->Rssi*4)/5; -+ else -+ rssi_final = rssi_ori; -+ } else { -+// if (sq_smp != 101) { /* from the right channel */ -+ ss_final = (u32)dst->PhyInfo.SignalStrength; //((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5; -+ sq_final = (u32)dst->PhyInfo.SignalQuality; //((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5; -+ rssi_final = dst->Rssi; //(src->Rssi+dst->Rssi*4)/5; -+// } else { -+// /* bss info not receiving from the right channel, use the original RX signal infos */ -+// ss_final = dst->PhyInfo.SignalStrength; -+// sq_final = dst->PhyInfo.SignalQuality; -+// rssi_final = dst->Rssi; -+// } -+ } -+ if (update_ie) { -+ dst->Reserved[0] = src->Reserved[0]; -+ dst->Reserved[1] = src->Reserved[1]; -+ memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src)); -+ } -+ dst->PhyInfo.SignalStrength = ss_final; -+ dst->PhyInfo.SignalQuality = sq_final; -+ dst->Rssi = rssi_final; -+ -+} -+ -+static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) -+{ -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ -+ if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && -+ (is_same_network(&(pmlmepriv->cur_network.network), pnetwork))) { -+ update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true); -+ rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(struct ndis_802_11_fixed_ie), -+ pmlmepriv->cur_network.network.IELength); -+ } -+ -+} -+ -+/* -+Caller must hold pmlmepriv->lock first. -+*/ -+void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target) -+{ -+ struct list_head *plist, *phead; -+ u32 bssid_ex_sz; -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ struct __queue *queue = &(pmlmepriv->scanned_queue); -+ struct wlan_network *pnetwork = NULL; -+ struct wlan_network *oldest = NULL; -+ -+ spin_lock_bh(&queue->lock); -+ phead = get_list_head(queue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ pnetwork = container_of(plist, struct wlan_network, list); -+ -+ if (is_same_network(&(pnetwork->network), target)) -+ break; -+ if ((oldest == ((struct wlan_network *)0)) || -+ time_after(oldest->last_scanned, pnetwork->last_scanned)) -+ oldest = pnetwork; -+ plist = plist->next; -+ } -+ /* If we didn't find a match, then get a new network slot to initialize -+ * with this beacon's information */ -+ if (phead == plist) { -+ if (list_empty(&(pmlmepriv->free_bss_pool.queue))) { -+ /* If there are no more slots, expire the oldest */ -+ pnetwork = oldest; -+ -+ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna)); -+ memcpy(&(pnetwork->network), target, get_wlan_bssid_ex_sz(target)); -+ /* variable initialize */ -+ pnetwork->fixed = false; -+ pnetwork->last_scanned = jiffies; -+ -+ pnetwork->network_type = 0; -+ pnetwork->aid = 0; -+ pnetwork->join_res = 0; -+ -+ /* bss info not receiving from the right channel */ -+ if (pnetwork->network.PhyInfo.SignalQuality == 101) -+ pnetwork->network.PhyInfo.SignalQuality = 0; -+ } else { -+ /* Otherwise just pull from the free list */ -+ -+ pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */ -+ -+ if (pnetwork == NULL) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n")); -+ goto exit; -+ } -+ -+ bssid_ex_sz = get_wlan_bssid_ex_sz(target); -+ target->Length = bssid_ex_sz; -+ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna)); -+ memcpy(&(pnetwork->network), target, bssid_ex_sz); -+ -+ pnetwork->last_scanned = jiffies; -+ -+ /* bss info not receiving from the right channel */ -+ if (pnetwork->network.PhyInfo.SignalQuality == 101) -+ pnetwork->network.PhyInfo.SignalQuality = 0; -+ list_add_tail(&(pnetwork->list), &(queue->queue)); -+ } -+ } else { -+ /* we have an entry and we are going to update it. But this entry may -+ * be already expired. In this case we do the same as we found a new -+ * net and call the new_net handler -+ */ -+ bool update_ie = true; -+ -+ pnetwork->last_scanned = jiffies; -+ -+ /* target.Reserved[0]== 1, means that scanned network is a bcn frame. */ -+ /* probe resp(3) > beacon(1) > probe req(2) */ -+ if ((target->Reserved[0] != 2) && -+ (target->Reserved[0] >= pnetwork->network.Reserved[0])) -+ update_ie = true; -+ else -+ update_ie = false; -+ update_network(&(pnetwork->network), target, adapter, update_ie); -+ } -+ -+exit: -+ spin_unlock_bh(&queue->lock); -+ -+} -+ -+static void rtw_add_network(struct adapter *adapter, -+ struct wlan_bssid_ex *pnetwork) -+{ -+ -+#if defined(CONFIG_88EU_P2P) -+ rtw_wlan_bssid_ex_remove_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO); -+#endif -+ update_current_network(adapter, pnetwork); -+ rtw_update_scanned_network(adapter, pnetwork); -+ -+} -+ -+/* select the desired network based on the capability of the (i)bss. */ -+/* check items: (1) security */ -+/* (2) network_type */ -+/* (3) WMM */ -+/* (4) HT */ -+/* (5) others */ -+static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork) -+{ -+ struct security_priv *psecuritypriv = &adapter->securitypriv; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ u32 desired_encmode; -+ u32 privacy; -+ -+ /* u8 wps_ie[512]; */ -+ uint wps_ielen; -+ -+ int bselected = true; -+ -+ desired_encmode = psecuritypriv->ndisencryptstatus; -+ privacy = pnetwork->network.Privacy; -+ -+ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { -+ if (rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen) != NULL) -+ return true; -+ else -+ return false; -+ } -+ if (adapter->registrypriv.wifi_spec == 1) { /* for correct flow of 8021X to do.... */ -+ u8 *p = NULL; -+ uint ie_len = 0; -+ -+ if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0)) -+ bselected = false; -+ if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { -+ p = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, -+ _RSN_IE_2_, &ie_len, -+ (pnetwork->network.IELength - -+ _BEACON_IE_OFFSET_)); -+ if (p && ie_len > 0) -+ bselected = true; -+ else -+ bselected = false; -+ } -+ } -+ -+ if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { -+ DBG_88E("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); -+ bselected = false; -+ } -+ -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) { -+ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) -+ bselected = false; -+ } -+ -+ return bselected; -+} -+ -+/* TODO: Perry: For Power Management */ -+void rtw_atimdone_event_callback(struct adapter *adapter , u8 *pbuf) -+{ -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_evet\n")); -+ -+ return; -+} -+ -+void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) -+{ -+ u32 len; -+ struct wlan_bssid_ex *pnetwork; -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ -+ pnetwork = (struct wlan_bssid_ex *)pbuf; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_survey_event_callback, ssid=%s\n", pnetwork->Ssid.Ssid)); -+ -+ len = get_wlan_bssid_ex_sz(pnetwork); -+ if (len > (sizeof(struct wlan_bssid_ex))) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n****rtw_survey_event_callback: return a wrong bss ***\n")); -+ return; -+ } -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ /* update IBSS_network 's timestamp */ -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) { -+ if (!memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) { -+ struct wlan_network *ibss_wlan = NULL; -+ -+ memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8); -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress); -+ if (ibss_wlan) { -+ memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8); -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ goto exit; -+ } -+ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); -+ } -+ } -+ -+ /* lock pmlmepriv->lock when you accessing network_q */ -+ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) { -+ if (pnetwork->Ssid.Ssid[0] == 0) -+ pnetwork->Ssid.SsidLength = 0; -+ rtw_add_network(adapter, pnetwork); -+ } -+ -+exit: -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+ return; -+} -+ -+void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) -+{ -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext; -+ u8 timer_cancelled = 0; -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if (pmlmepriv->wps_probe_req_ie) { -+ pmlmepriv->wps_probe_req_ie_len = 0; -+ kfree(pmlmepriv->wps_probe_req_ie); -+ pmlmepriv->wps_probe_req_ie = NULL; -+ } -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback: fw_state:%x\n\n", get_fwstate(pmlmepriv))); -+ -+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { -+ timer_cancelled = 1; -+ -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); -+ } else { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status=%x, survey done event comes too late!\n", get_fwstate(pmlmepriv))); -+ } -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+ if (timer_cancelled) -+ _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ rtw_set_signal_stat_timer(&adapter->recvpriv); -+ -+ if (pmlmepriv->to_join) { -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == false) { -+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); -+ -+ if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) { -+ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); -+ } else { -+ struct wlan_bssid_ex *pdev_network = &(adapter->registrypriv.dev_network); -+ u8 *pibss = adapter->registrypriv.dev_network.MacAddress; -+ -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n")); -+ -+ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); -+ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); -+ -+ rtw_update_registrypriv_dev_network(adapter); -+ rtw_generate_random_ibss(pibss); -+ -+ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; -+ -+ if (rtw_createbss_cmd(adapter) != _SUCCESS) -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error=>rtw_createbss_cmd status FAIL\n")); -+ pmlmepriv->to_join = false; -+ } -+ } -+ } else { -+ int s_ret; -+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); -+ pmlmepriv->to_join = false; -+ s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv); -+ if (_SUCCESS == s_ret) { -+ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); -+ } else if (s_ret == 2) { /* there is no need to wait for join */ -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ rtw_indicate_connect(adapter); -+ } else { -+ DBG_88E("try_to_join, but select scanning queue fail, to_roaming:%d\n", -+ pmlmepriv->to_roaming); -+ if (rtw_to_roaming(adapter) != 0) { -+ if (--pmlmepriv->to_roaming == 0 || -+ _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)) { -+ rtw_set_roaming(adapter, 0); -+ rtw_free_assoc_resources(adapter, 1); -+ rtw_indicate_disconnect(adapter); -+ } else { -+ pmlmepriv->to_join = true; -+ } -+ } else { -+ rtw_indicate_disconnect(adapter); -+ } -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ } -+ } -+ } -+ -+ indicate_wx_scan_complete_event(adapter); -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) -+ p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0); -+ -+ rtw_os_xmit_schedule(adapter); -+ -+ pmlmeext = &adapter->mlmeextpriv; -+ -+} -+ -+void rtw_dummy_event_callback(struct adapter *adapter , u8 *pbuf) -+{ -+} -+ -+void rtw_fwdbg_event_callback(struct adapter *adapter , u8 *pbuf) -+{ -+} -+ -+static void free_scanqueue(struct mlme_priv *pmlmepriv) -+{ -+ struct __queue *free_queue = &pmlmepriv->free_bss_pool; -+ struct __queue *scan_queue = &pmlmepriv->scanned_queue; -+ struct list_head *plist, *phead, *ptemp; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n")); -+ spin_lock_bh(&scan_queue->lock); -+ spin_lock_bh(&free_queue->lock); -+ -+ phead = get_list_head(scan_queue); -+ plist = phead->next; -+ -+ while (plist != phead) { -+ ptemp = plist->next; -+ list_del_init(plist); -+ list_add_tail(plist, &free_queue->queue); -+ plist = ptemp; -+ pmlmepriv->num_of_scanned--; -+ } -+ -+ spin_unlock_bh(&free_queue->lock); -+ spin_unlock_bh(&scan_queue->lock); -+} -+ -+/* -+*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock -+*/ -+void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) -+{ -+ struct wlan_network *pwlan = NULL; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ struct sta_priv *pstapriv = &adapter->stapriv; -+ struct wlan_network *tgt_network = &pmlmepriv->cur_network; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n")); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("tgt_network->network.MacAddress=%pM ssid=%s\n", -+ tgt_network->network.MacAddress, tgt_network->network.Ssid.Ssid)); -+ -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE)) { -+ struct sta_info *psta; -+ -+ psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress); -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ rtw_free_stainfo(adapter, psta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ } -+ -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) { -+ struct sta_info *psta; -+ -+ rtw_free_all_stainfo(adapter); -+ -+ psta = rtw_get_bcmc_stainfo(adapter); -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ rtw_free_stainfo(adapter, psta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+ rtw_init_bcmc_stainfo(adapter); -+ } -+ -+ if (lock_scanned_queue) -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ -+ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); -+ if (pwlan) -+ pwlan->fixed = false; -+ else -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources:pwlan==NULL\n\n")); -+ -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1))) -+ rtw_free_network_nolock(pmlmepriv, pwlan); -+ -+ if (lock_scanned_queue) -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ pmlmepriv->key_mask = 0; -+ -+} -+ -+/* -+*rtw_indicate_connect: the caller has to lock pmlmepriv->lock -+*/ -+void rtw_indicate_connect(struct adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n")); -+ -+ pmlmepriv->to_join = false; -+ -+ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { -+ set_fwstate(pmlmepriv, _FW_LINKED); -+ -+ rtw_led_control(padapter, LED_CTL_LINK); -+ -+ rtw_os_indicate_connect(padapter); -+ } -+ -+ pmlmepriv->to_roaming = 0; -+ -+ rtw_set_scan_deny(padapter, 3000); -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state=0x%08x\n", get_fwstate(pmlmepriv))); -+ -+} -+ -+/* -+*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock -+*/ -+void rtw_indicate_disconnect(struct adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect\n")); -+ -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS); -+ -+ if (pmlmepriv->to_roaming > 0) -+ _clr_fwstate_(pmlmepriv, _FW_LINKED); -+ -+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) || -+ (pmlmepriv->to_roaming <= 0)) { -+ rtw_os_indicate_disconnect(padapter); -+ -+ _clr_fwstate_(pmlmepriv, _FW_LINKED); -+ rtw_led_control(padapter, LED_CTL_NO_LINK); -+ rtw_clear_scan_deny(padapter); -+ } -+ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); -+ -+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1); -+ -+} -+ -+inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted) -+{ -+ rtw_os_indicate_scan_done(padapter, aborted); -+} -+ -+void rtw_scan_abort(struct adapter *adapter) -+{ -+ u32 start; -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); -+ -+ start = jiffies; -+ pmlmeext->scan_abort = true; -+ while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) && -+ rtw_get_passing_time_ms(start) <= 200) { -+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) -+ break; -+ DBG_88E(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); -+ rtw_msleep_os(20); -+ } -+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { -+ if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved) -+ DBG_88E(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); -+ rtw_indicate_scan_done(adapter, true); -+ } -+ pmlmeext->scan_abort = false; -+} -+ -+static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, struct wlan_network *pnetwork) -+{ -+ int i; -+ struct sta_info *bmc_sta, *psta = NULL; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress); -+ if (psta == NULL) -+ psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress); -+ -+ if (psta) { /* update ptarget_sta */ -+ DBG_88E("%s\n", __func__); -+ psta->aid = pnetwork->join_res; -+ psta->mac_id = 0; -+ /* sta mode */ -+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); -+ /* security related */ -+ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { -+ padapter->securitypriv.binstallGrpkey = false; -+ padapter->securitypriv.busetkipkey = false; -+ padapter->securitypriv.bgrpkey_handshake = false; -+ psta->ieee8021x_blocked = true; -+ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; -+ memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype)); -+ memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype)); -+ memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype)); -+ memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48)); -+ memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48)); -+ } -+ /* Commented by Albert 2012/07/21 */ -+ /* When doing the WPS, the wps_ie_len won't equal to 0 */ -+ /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */ -+ if (padapter->securitypriv.wps_ie_len != 0) { -+ psta->ieee8021x_blocked = true; -+ padapter->securitypriv.wps_ie_len = 0; -+ } -+ /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ -+ /* if A-MPDU Rx is enabled, resetting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ -+ /* todo: check if AP can send A-MPDU packets */ -+ for (i = 0; i < 16; i++) { -+ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ -+ preorder_ctrl = &psta->recvreorder_ctrl[i]; -+ preorder_ctrl->enable = false; -+ preorder_ctrl->indicate_seq = 0xffff; -+ preorder_ctrl->wend_b = 0xffff; -+ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ -+ } -+ bmc_sta = rtw_get_bcmc_stainfo(padapter); -+ if (bmc_sta) { -+ for (i = 0; i < 16; i++) { -+ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ -+ preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; -+ preorder_ctrl->enable = false; -+ preorder_ctrl->indicate_seq = 0xffff; -+ preorder_ctrl->wend_b = 0xffff; -+ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ -+ } -+ } -+ /* misc. */ -+ update_sta_info(padapter, psta); -+ } -+ return psta; -+} -+ -+/* pnetwork: returns from rtw_joinbss_event_callback */ -+/* ptarget_wlan: found from scanned_queue */ -+static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct wlan_network *cur_network = &(pmlmepriv->cur_network); -+ -+ DBG_88E("%s\n", __func__); -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("\nfw_state:%x, BSSID:%pM\n", -+ get_fwstate(pmlmepriv), pnetwork->network.MacAddress)); -+ -+ /* why not use ptarget_wlan?? */ -+ memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); -+ /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ -+ cur_network->network.IELength = ptarget_wlan->network.IELength; -+ memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ); -+ -+ cur_network->aid = pnetwork->join_res; -+ -+ rtw_set_signal_stat_timer(&padapter->recvpriv); -+ padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; -+ padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; -+ /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */ -+ padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); -+ rtw_set_signal_stat_timer(&padapter->recvpriv); -+ -+ /* update fw_state will clr _FW_UNDER_LINKING here indirectly */ -+ switch (pnetwork->network.InfrastructureMode) { -+ case Ndis802_11Infrastructure: -+ if (pmlmepriv->fw_state&WIFI_UNDER_WPS) -+ pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS; -+ else -+ pmlmepriv->fw_state = WIFI_STATION_STATE; -+ break; -+ case Ndis802_11IBSS: -+ pmlmepriv->fw_state = WIFI_ADHOC_STATE; -+ break; -+ default: -+ pmlmepriv->fw_state = WIFI_NULL_STATE; -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n")); -+ break; -+ } -+ -+ rtw_update_protection(padapter, (cur_network->network.IEs) + -+ sizeof(struct ndis_802_11_fixed_ie), -+ (cur_network->network.IELength)); -+ rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength); -+} -+ -+/* Notes: the function could be > passive_level (the same context as Rx tasklet) */ -+/* pnetwork: returns from rtw_joinbss_event_callback */ -+/* ptarget_wlan: found from scanned_queue */ -+/* if join_res > 0, for (fw_state == WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. */ -+/* if join_res > 0, for (fw_state == WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */ -+/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan != NULL). */ -+ -+void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) -+{ -+ u8 timer_cancelled; -+ struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; -+ struct sta_priv *pstapriv = &adapter->stapriv; -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; -+ struct wlan_network *cur_network = &(pmlmepriv->cur_network); -+ struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; -+ unsigned int the_same_macaddr = false; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("joinbss event call back received with res=%d\n", pnetwork->join_res)); -+ -+ rtw_get_encrypt_decrypt_from_registrypriv(adapter); -+ -+ if (pmlmepriv->assoc_ssid.SsidLength == 0) -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ joinbss event call back for Any SSid\n")); -+ else -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); -+ -+ the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); -+ -+ pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network); -+ if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n")); -+ return; -+ } -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nrtw_joinbss_event_callback!! spin_lock_init\n")); -+ -+ if (pnetwork->join_res > 0) { -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { -+ /* s1. find ptarget_wlan */ -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ if (the_same_macaddr) { -+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); -+ } else { -+ pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); -+ if (pcur_wlan) -+ pcur_wlan->fixed = false; -+ -+ pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); -+ if (pcur_sta) { -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ rtw_free_stainfo(adapter, pcur_sta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ } -+ -+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { -+ if (ptarget_wlan) -+ ptarget_wlan->fixed = true; -+ } -+ } -+ } else { -+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { -+ if (ptarget_wlan) -+ ptarget_wlan->fixed = true; -+ } -+ } -+ -+ /* s2. update cur_network */ -+ if (ptarget_wlan) { -+ rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork); -+ } else { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't find ptarget_wlan when joinbss_event callback\n")); -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ goto ignore_joinbss_callback; -+ } -+ -+ /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */ -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { -+ ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); -+ if (ptarget_sta == NULL) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't update stainfo when joinbss_event callback\n")); -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ goto ignore_joinbss_callback; -+ } -+ } -+ -+ /* s4. indicate connect */ -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { -+ pmlmepriv->cur_network_scanned = ptarget_wlan; -+ rtw_indicate_connect(adapter); -+ } else { -+ /* adhoc mode will rtw_indicate_connect when rtw_stassoc_event_callback */ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv))); -+ } -+ -+ /* s5. Cancle assoc_timer */ -+ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("Cancle assoc_timer\n")); -+ -+ } else { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_joinbss_event_callback err: fw_state:%x", get_fwstate(pmlmepriv))); -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ goto ignore_joinbss_callback; -+ } -+ -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ -+ } else if (pnetwork->join_res == -4) { -+ rtw_reset_securitypriv(adapter); -+ _set_timer(&pmlmepriv->assoc_timer, 1); -+ -+ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == true) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n", get_fwstate(pmlmepriv))); -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ } -+ } else { /* if join_res < 0 (join fails), then try again */ -+ _set_timer(&pmlmepriv->assoc_timer, 1); -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ } -+ -+ignore_joinbss_callback: -+ spin_unlock_bh(&pmlmepriv->lock); -+} -+ -+void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf) -+{ -+ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; -+ -+ mlmeext_joinbss_event_callback(adapter, pnetwork->join_res); -+ -+ rtw_os_xmit_schedule(adapter); -+ -+} -+ -+static u8 search_max_mac_id(struct adapter *padapter) -+{ -+ u8 mac_id; -+#if defined (CONFIG_88EU_AP_MODE) -+ u8 aid; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+#endif -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+#if defined (CONFIG_88EU_AP_MODE) -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ for (aid = (pstapriv->max_num_sta); aid > 0; aid--) { -+ if (pstapriv->sta_aid[aid-1] != NULL) -+ break; -+ } -+ mac_id = aid + 1; -+ } else -+#endif -+ {/* adhoc id = 31~2 */ -+ for (mac_id = (NUM_STA-1); mac_id >= IBSS_START_MAC_ID; mac_id--) { -+ if (pmlmeinfo->FW_sta_info[mac_id].status == 1) -+ break; -+ } -+ } -+ return mac_id; -+} -+ -+/* FOR AP , AD-HOC mode */ -+void rtw_sta_media_status_rpt(struct adapter *adapter,struct sta_info *psta, -+ u32 mstatus) -+{ -+ u16 media_status_rpt; -+ u8 macid; -+ -+ if (psta == NULL) -+ return; -+ -+ macid = search_max_mac_id(adapter); -+ rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&macid); -+ /* MACID|OPMODE:1 connect */ -+ media_status_rpt = (u16)((psta->mac_id<<8) | mstatus); -+ rtw_hal_set_hwreg(adapter,HW_VAR_H2C_MEDIA_STATUS_RPT, -+ (u8 *)&media_status_rpt); -+} -+ -+void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) -+{ -+ struct sta_info *psta; -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf; -+ struct wlan_network *cur_network = &(pmlmepriv->cur_network); -+ struct wlan_network *ptarget_wlan = NULL; -+ -+ if (rtw_access_ctrl(adapter, pstassoc->macaddr) == false) -+ return; -+ -+#if defined (CONFIG_88EU_AP_MODE) -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); -+ if (psta) -+ rtw_indicate_sta_assoc_event(adapter, psta); -+ return; -+ } -+#endif -+ /* for AD-HOC mode */ -+ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); -+ if (psta != NULL) { -+ /* the sta have been in sta_info_queue => do nothing */ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue\n")); -+ return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */ -+ } -+ psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); -+ if (psta == NULL) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't alloc sta_info when rtw_stassoc_event_callback\n")); -+ return; -+ } -+ /* to do: init sta_info variable */ -+ psta->qos_option = 0; -+ psta->mac_id = (uint)pstassoc->cam_id; -+ DBG_88E("%s\n", __func__); -+ /* for ad-hoc mode */ -+ rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true); -+ rtw_sta_media_status_rpt(adapter, psta, 1); -+ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) -+ psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; -+ psta->ieee8021x_blocked = false; -+ spin_lock_bh(&pmlmepriv->lock); -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) { -+ if (adapter->stapriv.asoc_sta_count == 2) { -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); -+ pmlmepriv->cur_network_scanned = ptarget_wlan; -+ if (ptarget_wlan) -+ ptarget_wlan->fixed = true; -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ -+ rtw_indicate_connect(adapter); -+ } -+ } -+ spin_unlock_bh(&pmlmepriv->lock); -+ mlmeext_sta_add_event_callback(adapter, psta); -+} -+ -+void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) -+{ -+ int mac_id = -1; -+ struct sta_info *psta; -+ struct wlan_network *pwlan = NULL; -+ struct wlan_bssid_ex *pdev_network = NULL; -+ u8 *pibss = NULL; -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ struct stadel_event *pstadel = (struct stadel_event *)pbuf; -+ struct sta_priv *pstapriv = &adapter->stapriv; -+ struct wlan_network *tgt_network = &(pmlmepriv->cur_network); -+ -+ psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr); -+ if (psta) -+ mac_id = psta->mac_id; -+ else -+ mac_id = pstadel->mac_id; -+ -+ DBG_88E("%s(mac_id=%d)=%pM\n", __func__, mac_id, pstadel->macaddr); -+ -+ if (mac_id >= 0) { -+ u16 media_status; -+ media_status = (mac_id<<8)|0; /* MACID|OPMODE:0 means disconnect */ -+ /* for STA, AP, ADHOC mode, report disconnect stauts to FW */ -+ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); -+ } -+ -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) -+ return; -+ -+ mlmeext_sta_del_event_callback(adapter); -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { -+ if(adapter->registrypriv.wifi_spec == 1) -+ rtw_set_roaming(adapter, 0); /* don't roam */ -+ else if (rtw_to_roaming(adapter) > 0) -+ pmlmepriv->to_roaming--; /* this stadel_event is caused by roaming, decrease to_roaming */ -+ else if (rtw_to_roaming(adapter) == 0) -+ rtw_set_roaming(adapter, -+ adapter->registrypriv.max_roaming_times); -+ -+ if (*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK) -+ rtw_set_roaming(adapter, 0); /* don't roam */ -+ -+ rtw_free_uc_swdec_pending_queue(adapter); -+ -+ rtw_free_assoc_resources(adapter, 1); -+ rtw_indicate_disconnect(adapter); -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ /* remove the network entry in scanned_queue */ -+ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); -+ if (pwlan) { -+ pwlan->fixed = false; -+ rtw_free_network_nolock(pmlmepriv, pwlan); -+ } -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ _rtw_roaming(adapter, tgt_network); -+ } -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || -+ check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { -+ spin_lock_bh(&(pstapriv->sta_hash_lock)); -+ rtw_free_stainfo(adapter, psta); -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+ if (adapter->stapriv.asoc_sta_count == 1) { /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ /* free old ibss network */ -+ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); -+ if (pwlan) { -+ pwlan->fixed = false; -+ rtw_free_network_nolock(pmlmepriv, pwlan); -+ } -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ /* re-create ibss */ -+ pdev_network = &(adapter->registrypriv.dev_network); -+ pibss = adapter->registrypriv.dev_network.MacAddress; -+ -+ memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); -+ -+ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); -+ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); -+ -+ rtw_update_registrypriv_dev_network(adapter); -+ -+ rtw_generate_random_ibss(pibss); -+ -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { -+ set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); -+ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); -+ } -+ -+ if (rtw_createbss_cmd(adapter) != _SUCCESS) -+ RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error=>stadel_event_callback: rtw_createbss_cmd status FAIL***\n ")); -+ } -+ } -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+} -+ -+void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf) -+{ -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_cpwm_event_callback !!!\n")); -+ -+} -+ -+/* -+* _rtw_join_timeout_handler - Timeout/faliure handler for CMD JoinBss -+* @adapter: pointer to struct adapter structure -+*/ -+void _rtw_join_timeout_handler (struct adapter *adapter) -+{ -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ int do_join_r; -+ -+ DBG_88E("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv)); -+ -+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) -+ return; -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if (rtw_to_roaming(adapter) > 0) { /* join timeout caused by roaming */ -+ while (1) { -+ pmlmepriv->to_roaming--; -+ if (rtw_to_roaming(adapter) != 0) { /* try another */ -+ DBG_88E("%s try another roaming\n", __func__); -+ do_join_r = rtw_do_join(adapter); -+ if (_SUCCESS != do_join_r) { -+ DBG_88E("%s roaming do_join return %d\n", __func__ , do_join_r); -+ continue; -+ } -+ break; -+ } else { -+ DBG_88E("%s We've try roaming but fail\n", __func__); -+ rtw_indicate_disconnect(adapter); -+ break; -+ } -+ } -+ } else { -+ rtw_indicate_disconnect(adapter); -+ free_scanqueue(pmlmepriv);/* */ -+ } -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+} -+ -+/* -+* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey -+* @adapter: pointer to struct adapter structure -+*/ -+void rtw_scan_timeout_handler (struct adapter *adapter) -+{ -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ -+ DBG_88E(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); -+ spin_lock_bh(&pmlmepriv->lock); -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); -+ spin_unlock_bh(&pmlmepriv->lock); -+ rtw_indicate_scan_done(adapter, true); -+} -+ -+static void rtw_auto_scan_handler(struct adapter *padapter) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ /* auto site survey per 60sec */ -+ if (pmlmepriv->scan_interval > 0) { -+ pmlmepriv->scan_interval--; -+ if (pmlmepriv->scan_interval == 0) { -+ DBG_88E("%s\n", __func__); -+ rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); -+ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ -+ } -+ } -+} -+ -+void rtw_dynamic_check_timer_handlder(struct adapter *adapter) -+{ -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ struct registry_priv *pregistrypriv = &adapter->registrypriv; -+ -+ if (!adapter) -+ return; -+ if (!adapter->hw_init_completed) -+ return; -+ if ((adapter->bDriverStopped) || (adapter->bSurpriseRemoved)) -+ return; -+ if (adapter->net_closed) -+ return; -+ rtw_dynamic_chk_wk_cmd(adapter); -+ -+ if (pregistrypriv->wifi_spec == 1) { -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &adapter->wdinfo; -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+#endif -+ { -+ /* auto site survey */ -+ rtw_auto_scan_handler(adapter); -+ } -+ } -+ -+ rcu_read_lock(); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) -+ if (rcu_dereference(adapter->pnetdev->rx_handler_data) && -+#else -+ if (rcu_dereference(adapter->pnetdev->br_port) && -+#endif -+ (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == true)) { -+ /* expire NAT2.5 entry */ -+ nat25_db_expire(adapter); -+ -+ if (adapter->pppoe_connection_in_progress > 0) { -+ adapter->pppoe_connection_in_progress--; -+ } -+ -+ /* due to rtw_dynamic_check_timer_handlder() is called every 2 seconds */ -+ if (adapter->pppoe_connection_in_progress > 0) { -+ adapter->pppoe_connection_in_progress--; -+ } -+ } -+ -+ rcu_read_unlock(); -+} -+ -+#define RTW_SCAN_RESULT_EXPIRE 2000 -+ -+/* -+* Select a new join candidate from the original @param candidate and @param competitor -+* @return true: candidate is updated -+* @return false: candidate is not updated -+*/ -+static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv -+ , struct wlan_network **candidate, struct wlan_network *competitor) -+{ -+ int updated = false; -+ struct adapter *adapter = container_of(pmlmepriv, struct adapter, mlmepriv); -+ -+ /* check bssid, if needed */ -+ if (pmlmepriv->assoc_by_bssid) { -+ if (memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN)) -+ goto exit; -+ } -+ -+ /* check ssid, if needed */ -+ if (pmlmepriv->assoc_ssid.Ssid && pmlmepriv->assoc_ssid.SsidLength) { -+ if (competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength || -+ memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength)) -+ goto exit; -+ } -+ -+ if (rtw_is_desired_network(adapter, competitor) == false) -+ goto exit; -+ -+ if(rtw_to_roaming(adapter) > 0) { -+ if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= RTW_SCAN_RESULT_EXPIRE || -+ is_same_ess(&competitor->network, &pmlmepriv->cur_network.network) == false) -+ goto exit; -+ } -+ -+ if (*candidate == NULL || (*candidate)->network.Rssi < competitor->network.Rssi) { -+ *candidate = competitor; -+ updated = true; -+ } -+ if (updated) { -+ DBG_88E("[by_bssid:%u][assoc_ssid:%s]new candidate: %s(%pM rssi:%d\n", -+ pmlmepriv->assoc_by_bssid, -+ pmlmepriv->assoc_ssid.Ssid, -+ (*candidate)->network.Ssid.Ssid, -+ (*candidate)->network.MacAddress, -+ (int)(*candidate)->network.Rssi); -+ DBG_88E("[to_roaming:%u]\n",rtw_to_roaming(adapter)); -+ } -+ -+exit: -+ return updated; -+} -+ -+/* -+Calling context: -+The caller of the sub-routine will be in critical section... -+The caller must hold the following spinlock -+pmlmepriv->lock -+*/ -+ -+int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) -+{ -+ int ret; -+ struct list_head *phead; -+ struct adapter *adapter; -+ struct __queue *queue = &(pmlmepriv->scanned_queue); -+ struct wlan_network *pnetwork = NULL; -+ struct wlan_network *candidate = NULL; -+ u8 supp_ant_div = false; -+ -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ phead = get_list_head(queue); -+ adapter = (struct adapter *)pmlmepriv->nic_hdl; -+ pmlmepriv->pscanned = phead->next; -+ while (phead != pmlmepriv->pscanned) { -+ pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list); -+ if (pnetwork == NULL) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork==NULL)\n", __func__)); -+ ret = _FAIL; -+ goto exit; -+ } -+ pmlmepriv->pscanned = pmlmepriv->pscanned->next; -+ rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); -+ } -+ if (candidate == NULL) { -+ DBG_88E("%s: return _FAIL(candidate==NULL)\n", __func__); -+ ret = _FAIL; -+ goto exit; -+ } else { -+ DBG_88E("%s: candidate: %s(%pM ch:%u)\n", __func__, -+ candidate->network.Ssid.Ssid, candidate->network.MacAddress, -+ candidate->network.Configuration.DSConfig); -+ } -+ -+ /* check for situation of _FW_LINKED */ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { -+ DBG_88E("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__); -+ -+ rtw_disassoc_cmd(adapter, 0, true); -+ rtw_indicate_disconnect(adapter); -+ rtw_free_assoc_resources(adapter, 0); -+ } -+ -+ rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(supp_ant_div)); -+ if (supp_ant_div) { -+ u8 cur_ant; -+ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(cur_ant)); -+ DBG_88E("#### Opt_Ant_(%s), cur_Ant(%s)\n", -+ (2 == candidate->network.PhyInfo.Optimum_antenna) ? "A" : "B", -+ (2 == cur_ant) ? "A" : "B" -+ ); -+ } -+ -+ ret = rtw_joinbss_cmd(adapter, candidate); -+ -+exit: -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ -+ return ret; -+} -+ -+int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) -+{ -+ struct cmd_obj *pcmd; -+ struct setauth_parm *psetauthparm; -+ struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); -+ int res = _SUCCESS; -+ -+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (pcmd == NULL) { -+ res = _FAIL; /* try again */ -+ goto exit; -+ } -+ -+ psetauthparm = (struct setauth_parm *)rtw_zmalloc(sizeof(struct setauth_parm)); -+ if (psetauthparm == NULL) { -+ kfree(pcmd); -+ res = _FAIL; -+ goto exit; -+ } -+ memset(psetauthparm, 0, sizeof(struct setauth_parm)); -+ psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm; -+ pcmd->cmdcode = _SetAuth_CMD_; -+ pcmd->parmbuf = (unsigned char *)psetauthparm; -+ pcmd->cmdsz = (sizeof(struct setauth_parm)); -+ pcmd->rsp = NULL; -+ pcmd->rspsz = 0; -+ INIT_LIST_HEAD(&pcmd->list); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, -+ ("after enqueue set_auth_cmd, auth_mode=%x\n", -+ psecuritypriv->dot11AuthAlgrthm)); -+ res = rtw_enqueue_cmd(pcmdpriv, pcmd); -+exit: -+ -+ return res; -+} -+ -+int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, int keyid, u8 set_tx) -+{ -+ u8 keylen; -+ struct cmd_obj *pcmd; -+ struct setkey_parm *psetkeyparm; -+ struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+ int res = _SUCCESS; -+ -+ pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (pcmd == NULL) { -+ res = _FAIL; /* try again */ -+ goto exit; -+ } -+ psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm)); -+ if (psetkeyparm == NULL) { -+ kfree(pcmd); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ memset(psetkeyparm, 0, sizeof(struct setkey_parm)); -+ -+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { -+ psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy; -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, -+ ("\n rtw_set_key: psetkeyparm->algorithm=(unsigned char)psecuritypriv->dot118021XGrpPrivacy=%d\n", -+ psetkeyparm->algorithm)); -+ } else { -+ psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm; -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, -+ ("\n rtw_set_key: psetkeyparm->algorithm=(u8)psecuritypriv->dot11PrivacyAlgrthm=%d\n", -+ psetkeyparm->algorithm)); -+ } -+ psetkeyparm->keyid = (u8)keyid;/* 0~3 */ -+ psetkeyparm->set_tx = set_tx; -+ pmlmepriv->key_mask |= BIT(psetkeyparm->keyid); -+ DBG_88E("==> rtw_set_key algorithm(%x), keyid(%x), key_mask(%x)\n", -+ psetkeyparm->algorithm, psetkeyparm->keyid, pmlmepriv->key_mask); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, -+ ("\n rtw_set_key: psetkeyparm->algorithm=%d psetkeyparm->keyid=(u8)keyid=%d\n", -+ psetkeyparm->algorithm, keyid)); -+ -+ switch (psetkeyparm->algorithm) { -+ case _WEP40_: -+ keylen = 5; -+ memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); -+ break; -+ case _WEP104_: -+ keylen = 13; -+ memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); -+ break; -+ case _TKIP_: -+ keylen = 16; -+ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); -+ psetkeyparm->grpkey = 1; -+ break; -+ case _AES_: -+ keylen = 16; -+ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); -+ psetkeyparm->grpkey = 1; -+ break; -+ default: -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, -+ ("\n rtw_set_key:psecuritypriv->dot11PrivacyAlgrthm=%x (must be 1 or 2 or 4 or 5)\n", -+ psecuritypriv->dot11PrivacyAlgrthm)); -+ res = _FAIL; -+ goto exit; -+ } -+ pcmd->cmdcode = _SetKey_CMD_; -+ pcmd->parmbuf = (u8 *)psetkeyparm; -+ pcmd->cmdsz = (sizeof(struct setkey_parm)); -+ pcmd->rsp = NULL; -+ pcmd->rspsz = 0; -+ INIT_LIST_HEAD(&pcmd->list); -+ res = rtw_enqueue_cmd(pcmdpriv, pcmd); -+exit: -+ -+ return res; -+} -+ -+/* adjust IEs for rtw_joinbss_cmd in WMM */ -+int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len) -+{ -+ unsigned int ielength = 0; -+ unsigned int i, j; -+ -+ i = 12; /* after the fixed IE */ -+ while (i < in_len) { -+ ielength = initial_out_len; -+ -+ if (in_ie[i] == 0xDD && in_ie[i+2] == 0x00 && in_ie[i+3] == 0x50 && in_ie[i+4] == 0xF2 && in_ie[i+5] == 0x02 && i+5 < in_len) { -+ /* WMM element ID and OUI */ -+ /* Append WMM IE to the last index of out_ie */ -+ -+ for (j = i; j < i + 9; j++) { -+ out_ie[ielength] = in_ie[j]; -+ ielength++; -+ } -+ out_ie[initial_out_len + 1] = 0x07; -+ out_ie[initial_out_len + 6] = 0x00; -+ out_ie[initial_out_len + 8] = 0x00; -+ break; -+ } -+ i += (in_ie[i+1]+2); /* to the next IE element */ -+ } -+ return ielength; -+} -+ -+/* */ -+/* Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */ -+/* Added by Annie, 2006-05-07. */ -+/* */ -+/* Search by BSSID, */ -+/* Return Value: */ -+/* -1 :if there is no pre-auth key in the table */ -+/* >= 0 :if there is pre-auth key, and return the entry id */ -+/* */ -+/* */ -+ -+static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid) -+{ -+ struct security_priv *psecuritypriv = &Adapter->securitypriv; -+ int i = 0; -+ -+ do { -+ if ((psecuritypriv->PMKIDList[i].bUsed) && -+ (!memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN))) { -+ break; -+ } else { -+ i++; -+ /* continue; */ -+ } -+ -+ } while (i < NUM_PMKID_CACHE); -+ -+ if (i == NUM_PMKID_CACHE) { -+ i = -1;/* Could not find. */ -+ } else { -+ /* There is one Pre-Authentication Key for the specific BSSID. */ -+ } -+ return i; -+} -+ -+/* */ -+/* Check the RSN IE length */ -+/* If the RSN IE length <= 20, the RSN IE didn't include the PMKID information */ -+/* 0-11th element in the array are the fixed IE */ -+/* 12th element in the array is the IE */ -+/* 13th element in the array is the IE length */ -+/* */ -+ -+static int rtw_append_pmkid(struct adapter *Adapter, int iEntry, u8 *ie, uint ie_len) -+{ -+ struct security_priv *psecuritypriv = &Adapter->securitypriv; -+ -+ if (ie[13] <= 20) { -+ /* The RSN IE didn't include the PMK ID, append the PMK information */ -+ ie[ie_len] = 1; -+ ie_len++; -+ ie[ie_len] = 0; /* PMKID count = 0x0100 */ -+ ie_len++; -+ memcpy(&ie[ie_len], &psecuritypriv->PMKIDList[iEntry].PMKID, 16); -+ -+ ie_len += 16; -+ ie[13] += 18;/* PMKID length = 2+16 */ -+ } -+ return ie_len; -+} -+ -+int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len) -+{ -+ u8 authmode; -+ uint ielength; -+ int iEntry; -+ -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ struct security_priv *psecuritypriv = &adapter->securitypriv; -+ uint ndisauthmode = psecuritypriv->ndisauthtype; -+ uint ndissecuritytype = psecuritypriv->ndisencryptstatus; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, -+ ("+rtw_restruct_sec_ie: ndisauthmode=%d ndissecuritytype=%d\n", -+ ndisauthmode, ndissecuritytype)); -+ -+ /* copy fixed ie only */ -+ memcpy(out_ie, in_ie, 12); -+ ielength = 12; -+ if ((ndisauthmode == Ndis802_11AuthModeWPA) || -+ (ndisauthmode == Ndis802_11AuthModeWPAPSK)) -+ authmode = _WPA_IE_ID_; -+ if ((ndisauthmode == Ndis802_11AuthModeWPA2) || -+ (ndisauthmode == Ndis802_11AuthModeWPA2PSK)) -+ authmode = _WPA2_IE_ID_; -+ -+ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { -+ memcpy(out_ie+ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len); -+ -+ ielength += psecuritypriv->wps_ie_len; -+ } else if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) { -+ /* copy RSN or SSN */ -+ memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1]+2); -+ ielength += psecuritypriv->supplicant_ie[1]+2; -+ rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie); -+ } -+ -+ iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); -+ if (iEntry < 0) { -+ return ielength; -+ } else { -+ if (authmode == _WPA2_IE_ID_) -+ ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength); -+ } -+ -+ return ielength; -+} -+ -+void rtw_init_registrypriv_dev_network(struct adapter *adapter) -+{ -+ struct registry_priv *pregistrypriv = &adapter->registrypriv; -+ struct eeprom_priv *peepriv = &adapter->eeprompriv; -+ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; -+ u8 *myhwaddr = myid(peepriv); -+ -+ memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); -+ -+ memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid)); -+ -+ pdev_network->Configuration.Length = sizeof(struct ndis_802_11_config); -+ pdev_network->Configuration.BeaconPeriod = 100; -+ pdev_network->Configuration.FHConfig.Length = 0; -+ pdev_network->Configuration.FHConfig.HopPattern = 0; -+ pdev_network->Configuration.FHConfig.HopSet = 0; -+ pdev_network->Configuration.FHConfig.DwellTime = 0; -+ -+} -+ -+void rtw_update_registrypriv_dev_network(struct adapter *adapter) -+{ -+ int sz = 0; -+ struct registry_priv *pregistrypriv = &adapter->registrypriv; -+ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; -+ struct security_priv *psecuritypriv = &adapter->securitypriv; -+ struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; -+ -+ pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0); /* adhoc no 802.1x */ -+ -+ pdev_network->Rssi = 0; -+ -+ switch (pregistrypriv->wireless_mode) { -+ case WIRELESS_11B: -+ pdev_network->NetworkTypeInUse = (Ndis802_11DS); -+ break; -+ case WIRELESS_11G: -+ case WIRELESS_11BG: -+ case WIRELESS_11_24N: -+ case WIRELESS_11G_24N: -+ case WIRELESS_11BG_24N: -+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); -+ break; -+ case WIRELESS_11A: -+ case WIRELESS_11A_5N: -+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); -+ break; -+ case WIRELESS_11ABGN: -+ if (pregistrypriv->channel > 14) -+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); -+ else -+ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); -+ break; -+ default: -+ /* TODO */ -+ break; -+ } -+ -+ pdev_network->Configuration.DSConfig = (pregistrypriv->channel); -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("pregistrypriv->channel=%d, pdev_network->Configuration.DSConfig=0x%x\n", -+ pregistrypriv->channel, pdev_network->Configuration.DSConfig)); -+ -+ if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) -+ pdev_network->Configuration.ATIMWindow = (0); -+ -+ pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode); -+ -+ /* 1. Supported rates */ -+ /* 2. IE */ -+ -+ sz = rtw_generate_ie(pregistrypriv); -+ pdev_network->IELength = sz; -+ pdev_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); -+ -+ /* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */ -+ /* pdev_network->IELength = cpu_to_le32(sz); */ -+ -+} -+ -+void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter) -+{ -+ -+} -+ -+/* the function is at passive_level */ -+void rtw_joinbss_reset(struct adapter *padapter) -+{ -+ u8 threshold; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ -+ /* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */ -+ pmlmepriv->num_FortyMHzIntolerant = 0; -+ -+ pmlmepriv->num_sta_no_ht = 0; -+ -+ phtpriv->ampdu_enable = false;/* reset to disabled */ -+ -+ /* TH = 1 => means that invalidate usb rx aggregation */ -+ /* TH = 0 => means that validate usb rx aggregation, use init value. */ -+ if (phtpriv->ht_option) { -+ if (padapter->registrypriv.wifi_spec == 1) -+ threshold = 1; -+ else -+ threshold = 0; -+ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); -+ } else { -+ threshold = 1; -+ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); -+ } -+} -+ -+/* the function is >= passive_level */ -+unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) -+{ -+ u32 ielen, out_len; -+ enum ht_cap_ampdu_factor max_rx_ampdu_factor; -+ unsigned char *p; -+ struct ieee80211_ht_cap ht_capie; -+ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct qos_priv *pqospriv = &pmlmepriv->qospriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ u32 rx_packet_offset, max_recvbuf_sz; -+ -+ phtpriv->ht_option = false; -+ -+ p = rtw_get_ie(in_ie+12, _HT_CAPABILITY_IE_, &ielen, in_len-12); -+ -+ if (p && ielen > 0) { -+ if (pqospriv->qos_option == 0) { -+ out_len = *pout_len; -+ rtw_set_ie(out_ie+out_len, _VENDOR_SPECIFIC_IE_, -+ _WMM_IE_Length_, WMM_IE, pout_len); -+ -+ pqospriv->qos_option = 1; -+ } -+ -+ out_len = *pout_len; -+ -+ memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap)); -+ -+ ht_capie.cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH | -+ IEEE80211_HT_CAP_SGI_20 | -+ IEEE80211_HT_CAP_SGI_40 | -+ IEEE80211_HT_CAP_TX_STBC | -+ IEEE80211_HT_CAP_DSSSCCK40); -+ -+ rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); -+ rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); -+ -+ /* -+ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k -+ AMPDU_para [4:2]:Min MPDU Start Spacing -+ */ -+ -+ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); -+ ht_capie.ampdu_params_info = (max_rx_ampdu_factor&0x03); -+ -+ if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) -+ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2)); -+ else -+ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); -+ -+ rtw_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_, -+ sizeof(struct ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len); -+ -+ phtpriv->ht_option = true; -+ -+ p = rtw_get_ie(in_ie+12, _HT_ADD_INFO_IE_, &ielen, in_len-12); -+ if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { -+ out_len = *pout_len; -+ rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2 , pout_len); -+ } -+ } -+ return phtpriv->ht_option; -+} -+ -+/* the function is > passive_level (in critical_section) */ -+void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len) -+{ -+ u8 *p, max_ampdu_sz; -+ int len; -+ struct ieee80211_ht_cap *pht_capie; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (!phtpriv->ht_option) -+ return; -+ -+ if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) -+ return; -+ -+ DBG_88E("+rtw_update_ht_cap()\n"); -+ -+ /* maybe needs check if ap supports rx ampdu. */ -+ if ((!phtpriv->ampdu_enable) && (pregistrypriv->ampdu_enable == 1)) { -+ if (pregistrypriv->wifi_spec == 1) -+ phtpriv->ampdu_enable = false; -+ else -+ phtpriv->ampdu_enable = true; -+ } else if (pregistrypriv->ampdu_enable == 2) { -+ phtpriv->ampdu_enable = true; -+ } -+ -+ /* check Max Rx A-MPDU Size */ -+ len = 0; -+ p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fixed_ie), _HT_CAPABILITY_IE_, &len, ie_len-sizeof(struct ndis_802_11_fixed_ie)); -+ if (p && len > 0) { -+ pht_capie = (struct ieee80211_ht_cap *)(p+2); -+ max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR); -+ max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */ -+ phtpriv->rx_ampdu_maxlen = max_ampdu_sz; -+ } -+ len = 0; -+ p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fixed_ie), _HT_ADD_INFO_IE_, &len, ie_len-sizeof(struct ndis_802_11_fixed_ie)); -+ -+ /* update cur_bwmode & cur_ch_offset */ -+ if ((pregistrypriv->cbw40_enable) && -+ (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & BIT(1)) && -+ (pmlmeinfo->HT_info.infos[0] & BIT(2))) { -+ int i; -+ u8 rf_type; -+ -+ padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ -+ /* update the MCS rates */ -+ for (i = 0; i < 16; i++) { -+ if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) -+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; -+ else -+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; -+ } -+ /* switch to the 40M Hz mode according to the AP */ -+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; -+ switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) { -+ case HT_EXTCHNL_OFFSET_UPPER: -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; -+ break; -+ case HT_EXTCHNL_OFFSET_LOWER: -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; -+ break; -+ default: -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ break; -+ } -+ } -+ -+ /* Config SM Power Save setting */ -+ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2; -+ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) -+ DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); -+ -+ /* Config current HT Protection mode. */ -+ pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; -+} -+ -+void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitframe) -+{ -+ u8 issued; -+ int priority; -+ struct sta_info *psta = NULL; -+ struct ht_priv *phtpriv; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ s32 bmcst = IS_MCAST(pattrib->ra); -+ -+ if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100)) -+ return; -+ -+ priority = pattrib->priority; -+ -+ if (pattrib->psta) -+ psta = pattrib->psta; -+ else -+ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); -+ -+ if (psta == NULL) -+ return; -+ -+ phtpriv = &psta->htpriv; -+ -+ if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) { -+ issued = (phtpriv->agg_enable_bitmap>>priority)&0x1; -+ issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1; -+ -+ if (0 == issued) { -+ DBG_88E("rtw_issue_addbareq_cmd, p=%d\n", priority); -+ psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); -+ rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra); -+ } -+ } -+} -+ -+void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ _rtw_roaming(padapter, tgt_network); -+ spin_unlock_bh(&pmlmepriv->lock); -+} -+void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) -+{ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ int do_join_r; -+ -+ struct wlan_network *pnetwork; -+ -+ if (tgt_network != NULL) -+ pnetwork = tgt_network; -+ else -+ pnetwork = &pmlmepriv->cur_network; -+ -+ if (0 < rtw_to_roaming(padapter)) { -+ DBG_88E("roaming from %s(%pM length:%d\n", -+ pnetwork->network.Ssid.Ssid, pnetwork->network.MacAddress, -+ pnetwork->network.Ssid.SsidLength); -+ memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid)); -+ -+ pmlmepriv->assoc_by_bssid = false; -+ -+ while (1) { -+ do_join_r = rtw_do_join(padapter); -+ if (_SUCCESS == do_join_r) { -+ break; -+ } else { -+ DBG_88E("roaming do_join return %d\n", do_join_r); -+ pmlmepriv->to_roaming--; -+ -+ if (0 < pmlmepriv->to_roaming) { -+ continue; -+ } else { -+ DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__); -+ rtw_indicate_disconnect(padapter); -+ break; -+ } -+ } -+ } -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_mlme_ext.c b/drivers/net/wireless/rtl8188eu/core/rtw_mlme_ext.c -new file mode 100644 -index 0000000000000..6c420d5238a84 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_mlme_ext.c -@@ -0,0 +1,8407 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_MLME_EXT_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static struct mlme_handler mlme_sta_tbl[] = { -+ {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, -+ {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, -+ {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, -+ {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, -+ {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, -+ {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, -+ -+ /*---------------------------------------------------------- -+ below 2 are reserved -+ -----------------------------------------------------------*/ -+ {0, "DoReserved", &DoReserved}, -+ {0, "DoReserved", &DoReserved}, -+ {WIFI_BEACON, "OnBeacon", &OnBeacon}, -+ {WIFI_ATIM, "OnATIM", &OnAtim}, -+ {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, -+ {WIFI_AUTH, "OnAuth", &OnAuthClient}, -+ {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, -+ {WIFI_ACTION, "OnAction", &OnAction}, -+}; -+ -+static struct action_handler OnAction_tbl[] = { -+ {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct}, -+ {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos}, -+ {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls}, -+ {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back}, -+ {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public}, -+ {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved}, -+ {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &DoReserved}, -+ {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht}, -+ {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved}, -+ {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm}, -+ {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p}, -+}; -+ -+static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; -+ -+/************************************************** -+OUI definitions for the vendor specific IE -+***************************************************/ -+unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; -+unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02}; -+unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; -+unsigned char P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09}; -+unsigned char WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A}; -+ -+unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; -+unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; -+ -+unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02}; -+unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02}; -+ -+extern unsigned char REALTEK_96B_IE[]; -+ -+/******************************************************** -+MCS rate definitions -+*********************************************************/ -+unsigned char MCS_rate_2R[16] = {0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; -+unsigned char MCS_rate_1R[16] = {0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; -+ -+/******************************************************** -+ChannelPlan definitions -+*********************************************************/ -+static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { -+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */ -+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */ -+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */ -+ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */ -+ {{10, 11, 12, 13}, 4}, /* 0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */ -+ {{}, 0}, /* 0x05, RT_CHANNEL_DOMAIN_2G_NULL */ -+}; -+ -+static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { -+ /* 0x00 ~ 0x1F , Old Define ===== */ -+ {0x02}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */ -+ {0x02}, /* 0x01, RT_CHANNEL_DOMAIN_IC */ -+ {0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */ -+ {0x01}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */ -+ {0x01}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */ -+ {0x03}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */ -+ {0x03}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */ -+ {0x01}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */ -+ {0x03}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */ -+ {0x03}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */ -+ {0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */ -+ {0x02}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */ -+ {0x01}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */ -+ {0x02}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */ -+ {0x02}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */ -+ {0x02}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */ -+ {0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */ -+ {0x02}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */ -+ {0x01}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ -+ {0x00}, /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */ -+ {0x02}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */ -+ {0x00}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */ -+ {0x00}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */ -+ {0x03}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ -+ {0x05}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */ -+ {0x02}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */ -+ {0x00}, /* 0x1A, */ -+ {0x00}, /* 0x1B, */ -+ {0x00}, /* 0x1C, */ -+ {0x00}, /* 0x1D, */ -+ {0x00}, /* 0x1E, */ -+ {0x05}, /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */ -+ /* 0x20 ~ 0x7F , New Define ===== */ -+ {0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */ -+ {0x01}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */ -+ {0x02}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */ -+ {0x03}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */ -+ {0x04}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */ -+ {0x02}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */ -+ {0x00}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */ -+ {0x03}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */ -+ {0x00}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */ -+ {0x00}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */ -+ {0x00}, /* 0x2A, */ -+ {0x00}, /* 0x2B, */ -+ {0x00}, /* 0x2C, */ -+ {0x00}, /* 0x2D, */ -+ {0x00}, /* 0x2E, */ -+ {0x00}, /* 0x2F, */ -+ {0x00}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */ -+ {0x00}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */ -+ {0x00}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */ -+ {0x00}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */ -+ {0x02}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */ -+ {0x00}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */ -+ {0x00}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */ -+ {0x03}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */ -+ {0x03}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */ -+ {0x02}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */ -+ {0x00}, /* 0x3A, */ -+ {0x00}, /* 0x3B, */ -+ {0x00}, /* 0x3C, */ -+ {0x00}, /* 0x3D, */ -+ {0x00}, /* 0x3E, */ -+ {0x00}, /* 0x3F, */ -+ {0x02}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */ -+ {0x03}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */ -+}; -+ -+static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the conbination for max channel numbers */ -+ -+/* -+ * Search the @param channel_num in given @param channel_set -+ * @ch_set: the given channel set -+ * @ch: the given channel number -+ * -+ * return the index of channel_num in channel_set, -1 if not found -+ */ -+int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch) -+{ -+ int i; -+ for (i = 0; ch_set[i].ChannelNum != 0; i++) { -+ if (ch == ch_set[i].ChannelNum) -+ break; -+ } -+ -+ if (i >= ch_set[i].ChannelNum) -+ return -1; -+ return i; -+} -+ -+/**************************************************************************** -+ -+Following are the initialization functions for WiFi MLME -+ -+*****************************************************************************/ -+ -+int init_hw_mlme_ext(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); -+ return _SUCCESS; -+} -+ -+static void init_mlme_ext_priv_value(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ unsigned char mixed_datarate[NumRates] = { -+ _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, -+ _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, -+ _48M_RATE_, _54M_RATE_, 0xff -+ }; -+ unsigned char mixed_basicrate[NumRates] = { -+ _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, -+ _12M_RATE_, _24M_RATE_, 0xff, -+ }; -+ -+ ATOMIC_SET(&pmlmeext->event_seq, 0); -+ pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ -+ -+ pmlmeext->cur_channel = padapter->registrypriv.channel; -+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ pmlmeext->retry = 0; -+ -+ pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; -+ -+ memcpy(pmlmeext->datarate, mixed_datarate, NumRates); -+ memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); -+ -+ pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; -+ -+ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; -+ pmlmeext->sitesurvey_res.channel_idx = 0; -+ pmlmeext->sitesurvey_res.bss_cnt = 0; -+ pmlmeext->scan_abort = false; -+ -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ pmlmeinfo->reauth_count = 0; -+ pmlmeinfo->reassoc_count = 0; -+ pmlmeinfo->link_count = 0; -+ pmlmeinfo->auth_seq = 0; -+ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; -+ pmlmeinfo->key_index = 0; -+ pmlmeinfo->iv = 0; -+ -+ pmlmeinfo->enc_algo = _NO_PRIVACY_; -+ pmlmeinfo->authModeToggle = 0; -+ -+ memset(pmlmeinfo->chg_txt, 0, 128); -+ -+ pmlmeinfo->slotTime = SHORT_SLOT_TIME; -+ pmlmeinfo->preamble_mode = PREAMBLE_AUTO; -+ -+ pmlmeinfo->dialogToken = 0; -+ -+ pmlmeext->action_public_rxseq = 0xffff; -+ pmlmeext->action_public_dialog_token = 0xff; -+} -+ -+static int has_channel(struct rt_channel_info *channel_set, -+ u8 chanset_size, -+ u8 chan) { -+ int i; -+ -+ for (i = 0; i < chanset_size; i++) { -+ if (channel_set[i].ChannelNum == chan) -+ return 1; -+ } -+ return 0; -+} -+ -+static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set, -+ u8 chanset_size, -+ struct p2p_channels *channel_list) { -+ struct p2p_oper_class_map op_class[] = { -+ { IEEE80211G, 81, 1, 13, 1, BW20 }, -+ { IEEE80211G, 82, 14, 14, 1, BW20 }, -+ { -1, 0, 0, 0, 0, BW20 } -+ }; -+ -+ int cla, op; -+ -+ cla = 0; -+ -+ for (op = 0; op_class[op].op_class; op++) { -+ u8 ch; -+ struct p2p_oper_class_map *o = &op_class[op]; -+ struct p2p_reg_class *reg = NULL; -+ -+ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { -+ if (!has_channel(channel_set, chanset_size, ch)) { -+ continue; -+ } -+ -+ if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc)) -+ continue; -+ -+ if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) && -+ ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) -+ continue; -+ -+ if (reg == NULL) { -+ reg = &channel_list->reg_class[cla]; -+ cla++; -+ reg->reg_class = o->op_class; -+ reg->channels = 0; -+ } -+ reg->channel[reg->channels] = ch; -+ reg->channels++; -+ } -+ } -+ channel_list->reg_classes = cla; -+} -+ -+static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set) -+{ -+ u8 index, chanset_size = 0; -+ u8 b2_4GBand = false; -+ u8 Index2G = 0; -+ -+ memset(channel_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM); -+ -+ if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { -+ DBG_88E("ChannelPlan ID %x error !!!!!\n", ChannelPlan); -+ return chanset_size; -+ } -+ -+ if (padapter->registrypriv.wireless_mode & WIRELESS_11G) { -+ b2_4GBand = true; -+ if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) -+ Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; -+ else -+ Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; -+ } -+ -+ if (b2_4GBand) { -+ for (index = 0; index < RTW_ChannelPlan2G[Index2G].Len; index++) { -+ channel_set[chanset_size].ChannelNum = RTW_ChannelPlan2G[Index2G].Channel[index]; -+ -+ if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == ChannelPlan) ||/* Channel 1~11 is active, and 12~14 is passive */ -+ (RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == ChannelPlan)) { -+ if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11) -+ channel_set[chanset_size].ScanType = SCAN_ACTIVE; -+ else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) -+ channel_set[chanset_size].ScanType = SCAN_PASSIVE; -+ } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan || -+ RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {/* channel 12~13, passive scan */ -+ if (channel_set[chanset_size].ChannelNum <= 11) -+ channel_set[chanset_size].ScanType = SCAN_ACTIVE; -+ else -+ channel_set[chanset_size].ScanType = SCAN_PASSIVE; -+ } else { -+ channel_set[chanset_size].ScanType = SCAN_ACTIVE; -+ } -+ -+ chanset_size++; -+ } -+ } -+ return chanset_size; -+} -+ -+int init_mlme_ext_priv(struct adapter *padapter) -+{ -+ int res = _SUCCESS; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ pmlmeext->padapter = padapter; -+ -+ init_mlme_ext_priv_value(padapter); -+ pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; -+ -+ init_mlme_ext_timer(padapter); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ init_mlme_ap_info(padapter); -+#endif -+ -+ pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set); -+ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); -+ -+ pmlmeext->chan_scan_time = SURVEY_TO; -+ pmlmeext->mlmeext_init = true; -+ -+ pmlmeext->active_keep_alive_check = true; -+ -+ return res; -+} -+ -+void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext) -+{ -+ struct adapter *padapter = pmlmeext->padapter; -+ -+ if (!padapter) -+ return; -+ -+ if (padapter->bDriverStopped) { -+ _cancel_timer_ex(&pmlmeext->survey_timer); -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ /* _cancel_timer_ex(&pmlmeext->ADDBA_timer); */ -+ } -+} -+ -+static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, struct recv_frame *precv_frame) -+{ -+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ u8 *pframe = precv_frame->rx_data; -+ -+ if (ptable->func) { -+ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ -+ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && -+ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) -+ return; -+ ptable->func(padapter, precv_frame); -+ } -+} -+ -+void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ int index; -+ struct mlme_handler *ptable; -+#ifdef CONFIG_88EU_AP_MODE -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+#endif /* CONFIG_88EU_AP_MODE */ -+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ u8 *pframe = precv_frame->rx_data; -+ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe)); -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n", -+ GetFrameType(pframe), GetFrameSubType(pframe))); -+ -+ if (GetFrameType(pframe) != WIFI_MGT_TYPE) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe))); -+ return; -+ } -+ -+ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ -+ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && -+ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) -+ return; -+ -+ ptable = mlme_sta_tbl; -+ -+ index = GetFrameSubType(pframe) >> 4; -+ -+ if (index > 13) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type=%d\n", index)); -+ return; -+ } -+ ptable += index; -+ -+ if (psta != NULL) { -+ if (GetRetry(pframe)) { -+ if (precv_frame->attrib.seq_num == psta->RxMgmtFrameSeqNum) { -+ /* drop the duplicate management frame */ -+ DBG_88E("Drop duplicate management frame with seq_num=%d.\n", precv_frame->attrib.seq_num); -+ return; -+ } -+ } -+ psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num; -+ } -+ -+#ifdef CONFIG_88EU_AP_MODE -+ switch (GetFrameSubType(pframe)) { -+ case WIFI_AUTH: -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) -+ ptable->func = &OnAuth; -+ else -+ ptable->func = &OnAuthClient; -+ /* fall through */ -+ case WIFI_ASSOCREQ: -+ case WIFI_REASSOCREQ: -+ _mgt_dispatcher(padapter, ptable, precv_frame); -+ break; -+ case WIFI_PROBEREQ: -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) -+ _mgt_dispatcher(padapter, ptable, precv_frame); -+ else -+ _mgt_dispatcher(padapter, ptable, precv_frame); -+ break; -+ case WIFI_BEACON: -+ _mgt_dispatcher(padapter, ptable, precv_frame); -+ break; -+ case WIFI_ACTION: -+ _mgt_dispatcher(padapter, ptable, precv_frame); -+ break; -+ default: -+ _mgt_dispatcher(padapter, ptable, precv_frame); -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) -+ rtw_hostapd_mlme_rx(padapter, precv_frame); -+ break; -+ } -+#else -+ _mgt_dispatcher(padapter, ptable, precv_frame); -+#endif -+} -+ -+#ifdef CONFIG_88EU_P2P -+static u32 p2p_listen_state_process(struct adapter *padapter, unsigned char *da) -+{ -+ bool response = true; -+ -+ /* do nothing if the device name is empty */ -+ if (!padapter->wdinfo.device_name_len) -+ response = false; -+ -+ if (response) -+ issue_probersp_p2p(padapter, da); -+ -+ return _SUCCESS; -+} -+#endif /* CONFIG_88EU_P2P */ -+ -+/**************************************************************************** -+ -+Following are the callback functions for each subtype of the management frames -+ -+*****************************************************************************/ -+ -+unsigned int OnProbeReq(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ unsigned int ielen; -+ unsigned char *p; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur = &(pmlmeinfo->network); -+ u8 *pframe = precv_frame->rx_data; -+ uint len = precv_frame->len; -+ u8 is_valid_p2p_probereq = false; -+ -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ u8 wifi_test_chk_rate = 1; -+ -+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && -+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) && -+ !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && -+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) && -+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)) { -+ /* mcs_rate = 0 -> CCK 1M rate */ -+ /* mcs_rate = 1 -> CCK 2M rate */ -+ /* mcs_rate = 2 -> CCK 5.5M rate */ -+ /* mcs_rate = 3 -> CCK 11M rate */ -+ /* In the P2P mode, the driver should not support the CCK rate */ -+ -+ /* Commented by Kurt 2012/10/16 */ -+ /* IOT issue: Google Nexus7 use 1M rate to send p2p_probe_req after GO nego completed and Nexus7 is client */ -+ if (wifi_test_chk_rate == 1) { -+ is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len); -+ if (is_valid_p2p_probereq) { -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { -+ /* FIXME */ -+ report_survey_event(padapter, precv_frame); -+ p2p_listen_state_process(padapter, get_sa(pframe)); -+ -+ return _SUCCESS; -+ } -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) -+ goto _continue; -+ } -+ } -+ } -+ -+_continue: -+#endif /* CONFIG_88EU_P2P */ -+ -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) -+ return _SUCCESS; -+ -+ if (!check_fwstate(pmlmepriv, _FW_LINKED) && -+ !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE)) -+ return _SUCCESS; -+ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, -+ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); -+ -+ /* check (wildcard) SSID */ -+ if (p != NULL) { -+ if (is_valid_p2p_probereq) -+ goto _issue_probersp; -+ -+ if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) || -+ (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) -+ return _SUCCESS; -+ -+_issue_probersp: -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) && -+ (pmlmepriv->cur_network.join_res || -+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) -+ issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); -+ } -+ return _SUCCESS; -+} -+ -+unsigned int OnProbeRsp(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ u8 *pframe = precv_frame->rx_data; -+#endif -+ -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { -+ if (pwdinfo->tx_prov_disc_info.benable) { -+ if (!memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr2Ptr(pframe), ETH_ALEN)) { -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { -+ pwdinfo->tx_prov_disc_info.benable = false; -+ issue_p2p_provision_request(padapter, -+ pwdinfo->tx_prov_disc_info.ssid.Ssid, -+ pwdinfo->tx_prov_disc_info.ssid.SsidLength, -+ pwdinfo->tx_prov_disc_info.peerDevAddr); -+ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ pwdinfo->tx_prov_disc_info.benable = false; -+ issue_p2p_provision_request(padapter, NULL, 0, -+ pwdinfo->tx_prov_disc_info.peerDevAddr); -+ } -+ } -+ } -+ return _SUCCESS; -+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { -+ if (pwdinfo->nego_req_info.benable) { -+ DBG_88E("[%s] P2P State is GONEGO ING!\n", __func__); -+ if (!memcmp(pwdinfo->nego_req_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN)) { -+ pwdinfo->nego_req_info.benable = false; -+ issue_p2p_GO_request(padapter, pwdinfo->nego_req_info.peerDevAddr); -+ } -+ } -+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { -+ if (pwdinfo->invitereq_info.benable) { -+ DBG_88E("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__); -+ if (!memcmp(pwdinfo->invitereq_info.peer_macaddr, GetAddr2Ptr(pframe), ETH_ALEN)) { -+ pwdinfo->invitereq_info.benable = false; -+ issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr); -+ } -+ } -+ } -+#endif -+ -+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { -+ report_survey_event(padapter, precv_frame); -+ return _SUCCESS; -+ } -+ -+ return _SUCCESS; -+} -+ -+unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ int cam_idx; -+ struct sta_info *psta; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 *pframe = precv_frame->rx_data; -+ uint len = precv_frame->len; -+ struct wlan_bssid_ex *pbss; -+ int ret = _SUCCESS; -+ -+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { -+ report_survey_event(padapter, precv_frame); -+ return _SUCCESS; -+ } -+ -+ if (!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) { -+ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { -+ /* we should update current network before auth, or some IE is wrong */ -+ pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex)); -+ if (pbss) { -+ if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) { -+ update_network(&(pmlmepriv->cur_network.network), pbss, padapter, true); -+ rtw_get_bcn_info(&(pmlmepriv->cur_network)); -+ } -+ kfree(pbss); -+ } -+ -+ /* check the vendor of the assoc AP */ -+ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe+sizeof(struct rtw_ieee80211_hdr_3addr), len-sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ /* update TSF Value */ -+ update_TSF(pmlmeext, pframe, len); -+ -+ /* start auth */ -+ start_clnt_auth(padapter); -+ -+ return _SUCCESS; -+ } -+ -+ if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { -+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); -+ if (psta != NULL) { -+ ret = rtw_check_bcn_info(padapter, pframe, len); -+ if (!ret) { -+ DBG_88E_LEVEL(_drv_info_, "ap has changed, disconnect now\n "); -+ receive_disconnect(padapter, pmlmeinfo->network.MacAddress, 0); -+ return _SUCCESS; -+ } -+ /* update WMM, ERP in the beacon */ -+ /* todo: the timer is used instead of the number of the beacon received */ -+ if ((sta_rx_pkts(psta) & 0xf) == 0) -+ update_beacon_info(padapter, pframe, len, psta); -+ process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)); -+ } -+ } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { -+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); -+ if (psta != NULL) { -+ /* update WMM, ERP in the beacon */ -+ /* todo: the timer is used instead of the number of the beacon received */ -+ if ((sta_rx_pkts(psta) & 0xf) == 0) -+ update_beacon_info(padapter, pframe, len, psta); -+ } else { -+ /* allocate a new CAM entry for IBSS station */ -+ cam_idx = allocate_fw_sta_entry(padapter); -+ if (cam_idx == NUM_STA) -+ goto _END_ONBEACON_; -+ -+ /* get supported rate */ -+ if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) { -+ pmlmeinfo->FW_sta_info[cam_idx].status = 0; -+ goto _END_ONBEACON_; -+ } -+ -+ /* update TSF Value */ -+ update_TSF(pmlmeext, pframe, len); -+ -+ /* report sta add event */ -+ report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); -+ } -+ } -+ } -+ -+_END_ONBEACON_: -+ -+ return _SUCCESS; -+} -+ -+unsigned int OnAuth(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+#ifdef CONFIG_88EU_AP_MODE -+ unsigned int auth_mode, ie_len; -+ u16 seq; -+ unsigned char *sa, *p; -+ u16 algorithm; -+ int status; -+ static struct sta_info stat; -+ struct sta_info *pstat = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 *pframe = precv_frame->rx_data; -+ uint len = precv_frame->len; -+ -+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) -+ return _FAIL; -+ -+ DBG_88E("+OnAuth\n"); -+ -+ sa = GetAddr2Ptr(pframe); -+ -+ auth_mode = psecuritypriv->dot11AuthAlgrthm; -+ seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + 2)); -+ algorithm = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN)); -+ -+ DBG_88E("auth alg=%x, seq=%X\n", algorithm, seq); -+ -+ if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && -+ psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) -+ auth_mode = 0; -+ -+ if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ -+ (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */ -+ DBG_88E("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n", -+ algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); -+ -+ status = _STATS_NO_SUPP_ALG_; -+ -+ goto auth_fail; -+ } -+ -+ if (!rtw_access_ctrl(padapter, sa)) { -+ status = _STATS_UNABLE_HANDLE_STA_; -+ goto auth_fail; -+ } -+ -+ pstat = rtw_get_stainfo(pstapriv, sa); -+ if (pstat == NULL) { -+ /* allocate a new one */ -+ DBG_88E("going to alloc stainfo for sa=%pM\n", sa); -+ pstat = rtw_alloc_stainfo(pstapriv, sa); -+ if (pstat == NULL) { -+ DBG_88E(" Exceed the upper limit of supported clients...\n"); -+ status = _STATS_UNABLE_HANDLE_STA_; -+ goto auth_fail; -+ } -+ -+ pstat->state = WIFI_FW_AUTH_NULL; -+ pstat->auth_seq = 0; -+ } else { -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ if (!list_empty(&pstat->asoc_list)) { -+ list_del_init(&pstat->asoc_list); -+ pstapriv->asoc_list_cnt--; -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ if (seq == 1) { -+ /* TODO: STA re_auth and auth timeout */ -+ } -+ } -+ -+ spin_lock_bh(&pstapriv->auth_list_lock); -+ if (list_empty(&pstat->auth_list)) { -+ list_add_tail(&pstat->auth_list, &pstapriv->auth_list); -+ pstapriv->auth_list_cnt++; -+ } -+ spin_unlock_bh(&pstapriv->auth_list_lock); -+ -+ if (pstat->auth_seq == 0) -+ pstat->expire_to = pstapriv->auth_to; -+ -+ if ((pstat->auth_seq + 1) != seq) { -+ DBG_88E("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", -+ seq, pstat->auth_seq+1); -+ status = _STATS_OUT_OF_AUTH_SEQ_; -+ goto auth_fail; -+ } -+ -+ if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) { -+ if (seq == 1) { -+ pstat->state &= ~WIFI_FW_AUTH_NULL; -+ pstat->state |= WIFI_FW_AUTH_SUCCESS; -+ pstat->expire_to = pstapriv->assoc_to; -+ pstat->authalg = algorithm; -+ } else { -+ DBG_88E("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", -+ seq, pstat->auth_seq+1); -+ status = _STATS_OUT_OF_AUTH_SEQ_; -+ goto auth_fail; -+ } -+ } else { /* shared system or auto authentication */ -+ if (seq == 1) { -+ /* prepare for the challenging txt... */ -+ -+ pstat->state &= ~WIFI_FW_AUTH_NULL; -+ pstat->state |= WIFI_FW_AUTH_STATE; -+ pstat->authalg = algorithm; -+ pstat->auth_seq = 2; -+ } else if (seq == 3) { -+ /* checking for challenging txt... */ -+ DBG_88E("checking for challenging txt...\n"); -+ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len, -+ len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); -+ -+ if ((p == NULL) || (ie_len <= 0)) { -+ DBG_88E("auth rejected because challenge failure!(1)\n"); -+ status = _STATS_CHALLENGE_FAIL_; -+ goto auth_fail; -+ } -+ -+ if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) { -+ pstat->state &= (~WIFI_FW_AUTH_STATE); -+ pstat->state |= WIFI_FW_AUTH_SUCCESS; -+ /* challenging txt is correct... */ -+ pstat->expire_to = pstapriv->assoc_to; -+ } else { -+ DBG_88E("auth rejected because challenge failure!\n"); -+ status = _STATS_CHALLENGE_FAIL_; -+ goto auth_fail; -+ } -+ } else { -+ DBG_88E("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", -+ seq, pstat->auth_seq+1); -+ status = _STATS_OUT_OF_AUTH_SEQ_; -+ goto auth_fail; -+ } -+ } -+ -+ /* Now, we are going to issue_auth... */ -+ pstat->auth_seq = seq + 1; -+ -+#ifdef CONFIG_88EU_AP_MODE -+ issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_)); -+#endif -+ -+ if (pstat->state & WIFI_FW_AUTH_SUCCESS) -+ pstat->auth_seq = 0; -+ -+ return _SUCCESS; -+ -+auth_fail: -+ -+ if (pstat) -+ rtw_free_stainfo(padapter , pstat); -+ -+ pstat = &stat; -+ memset((char *)pstat, '\0', sizeof(stat)); -+ pstat->auth_seq = 2; -+ memcpy(pstat->hwaddr, sa, 6); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ issue_auth(padapter, pstat, (unsigned short)status); -+#endif -+ -+#endif -+ return _FAIL; -+} -+ -+unsigned int OnAuthClient(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ unsigned int seq, len, status, offset; -+ unsigned char *p; -+ unsigned int go2asoc = 0; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 *pframe = precv_frame->rx_data; -+ uint pkt_len = precv_frame->len; -+ -+ DBG_88E("%s\n", __func__); -+ -+ /* check A1 matches or not */ -+ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) -+ return _SUCCESS; -+ -+ if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) -+ return _SUCCESS; -+ -+ offset = (GetPrivacy(pframe)) ? 4 : 0; -+ -+ seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 2)); -+ status = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 4)); -+ -+ if (status != 0) { -+ DBG_88E("clnt auth fail, status: %d\n", status); -+ if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ -+ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) -+ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; -+ else -+ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; -+ } -+ -+ set_link_timer(pmlmeext, 1); -+ goto authclnt_fail; -+ } -+ -+ if (seq == 2) { -+ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { -+ /* legendary shared system */ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, -+ pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); -+ -+ if (p == NULL) -+ goto authclnt_fail; -+ -+ memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); -+ pmlmeinfo->auth_seq = 3; -+ issue_auth(padapter, NULL, 0); -+ set_link_timer(pmlmeext, REAUTH_TO); -+ -+ return _SUCCESS; -+ } else { -+ /* open system */ -+ go2asoc = 1; -+ } -+ } else if (seq == 4) { -+ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) -+ go2asoc = 1; -+ else -+ goto authclnt_fail; -+ } else { -+ /* this is also illegal */ -+ goto authclnt_fail; -+ } -+ -+ if (go2asoc) { -+ DBG_88E_LEVEL(_drv_info_, "auth success, start assoc\n"); -+ start_clnt_assoc(padapter); -+ return _SUCCESS; -+ } -+authclnt_fail: -+ return _FAIL; -+} -+ -+unsigned int OnAssocReq(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+#ifdef CONFIG_88EU_AP_MODE -+ u16 capab_info; -+ struct rtw_ieee802_11_elems elems; -+ struct sta_info *pstat; -+ unsigned char reassoc, *p, *pos, *wpa_ie; -+ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; -+ int i, ie_len, wpa_ie_len, left; -+ unsigned char supportRate[16]; -+ int supportRateNum; -+ unsigned short status = _STATS_SUCCESSFUL_; -+ unsigned short frame_type, ie_offset = 0; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur = &(pmlmeinfo->network); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 *pframe = precv_frame->rx_data; -+ uint pkt_len = precv_frame->len; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ u8 p2p_status_code = P2P_STATUS_SUCCESS; -+ u8 *p2pie; -+ u32 p2pielen = 0; -+#endif /* CONFIG_88EU_P2P */ -+ -+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) -+ return _FAIL; -+ -+ frame_type = GetFrameSubType(pframe); -+ if (frame_type == WIFI_ASSOCREQ) { -+ reassoc = 0; -+ ie_offset = _ASOCREQ_IE_OFFSET_; -+ } else { /* WIFI_REASSOCREQ */ -+ reassoc = 1; -+ ie_offset = _REASOCREQ_IE_OFFSET_; -+ } -+ -+ if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { -+ DBG_88E("handle_assoc(reassoc=%d) - too short payload (len=%lu)" -+ "\n", reassoc, (unsigned long)pkt_len); -+ return _FAIL; -+ } -+ -+ pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); -+ if (pstat == (struct sta_info *)NULL) { -+ status = _RSON_CLS2_; -+ goto asoc_class2_error; -+ } -+ -+ capab_info = get_unaligned_le16(pframe + WLAN_HDR_A3_LEN); -+ -+ left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); -+ pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); -+ -+ DBG_88E("%s\n", __func__); -+ -+ /* check if this stat has been successfully authenticated/assocated */ -+ if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) { -+ if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) { -+ status = _RSON_CLS2_; -+ goto asoc_class2_error; -+ } else { -+ pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); -+ pstat->state |= WIFI_FW_ASSOC_STATE; -+ } -+ } else { -+ pstat->state &= (~WIFI_FW_AUTH_SUCCESS); -+ pstat->state |= WIFI_FW_ASSOC_STATE; -+ } -+ pstat->capability = capab_info; -+ /* now parse all ieee802_11 ie to point to elems */ -+ if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || -+ !elems.ssid) { -+ DBG_88E("STA %pM sent invalid association request\n", -+ pstat->hwaddr); -+ status = _STATS_FAILURE_; -+ goto OnAssocReqFail; -+ } -+ -+ /* now we should check all the fields... */ -+ /* checking SSID */ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, -+ pkt_len - WLAN_HDR_A3_LEN - ie_offset); -+ if (p == NULL) -+ status = _STATS_FAILURE_; -+ -+ if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */ -+ status = _STATS_FAILURE_; -+ } else { -+ /* check if ssid match */ -+ if (memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) -+ status = _STATS_FAILURE_; -+ -+ if (ie_len != cur->Ssid.SsidLength) -+ status = _STATS_FAILURE_; -+ } -+ -+ if (_STATS_SUCCESSFUL_ != status) -+ goto OnAssocReqFail; -+ -+ /* check if the supported rate is ok */ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); -+ if (p == NULL) { -+ DBG_88E("Rx a sta assoc-req which supported rate is empty!\n"); -+ /* use our own rate set as statoin used */ -+ /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ -+ /* supportRateNum = AP_BSSRATE_LEN; */ -+ -+ status = _STATS_FAILURE_; -+ goto OnAssocReqFail; -+ } else { -+ memcpy(supportRate, p+2, ie_len); -+ supportRateNum = ie_len; -+ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_ , &ie_len, -+ pkt_len - WLAN_HDR_A3_LEN - ie_offset); -+ if (p != NULL) { -+ if (supportRateNum <= sizeof(supportRate)) { -+ memcpy(supportRate+supportRateNum, p+2, ie_len); -+ supportRateNum += ie_len; -+ } -+ } -+ } -+ -+ /* todo: mask supportRate between AP & STA -> move to update raid */ -+ /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */ -+ -+ /* update station supportRate */ -+ pstat->bssratelen = supportRateNum; -+ memcpy(pstat->bssrateset, supportRate, supportRateNum); -+ UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen); -+ -+ /* check RSN/WPA/WPS */ -+ pstat->dot8021xalg = 0; -+ pstat->wpa_psk = 0; -+ pstat->wpa_group_cipher = 0; -+ pstat->wpa2_group_cipher = 0; -+ pstat->wpa_pairwise_cipher = 0; -+ pstat->wpa2_pairwise_cipher = 0; -+ memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); -+ if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { -+ int group_cipher = 0, pairwise_cipher = 0; -+ -+ wpa_ie = elems.rsn_ie; -+ wpa_ie_len = elems.rsn_ie_len; -+ -+ if (rtw_parse_wpa2_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { -+ pstat->dot8021xalg = 1;/* psk, todo:802.1x */ -+ pstat->wpa_psk |= BIT(1); -+ -+ pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher; -+ pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher; -+ -+ if (!pstat->wpa2_group_cipher) -+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; -+ -+ if (!pstat->wpa2_pairwise_cipher) -+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; -+ } else { -+ status = WLAN_STATUS_INVALID_IE; -+ } -+ } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { -+ int group_cipher = 0, pairwise_cipher = 0; -+ -+ wpa_ie = elems.wpa_ie; -+ wpa_ie_len = elems.wpa_ie_len; -+ -+ if (rtw_parse_wpa_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { -+ pstat->dot8021xalg = 1;/* psk, todo:802.1x */ -+ pstat->wpa_psk |= BIT(0); -+ -+ pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher; -+ pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher; -+ -+ if (!pstat->wpa_group_cipher) -+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; -+ -+ if (!pstat->wpa_pairwise_cipher) -+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; -+ } else { -+ status = WLAN_STATUS_INVALID_IE; -+ } -+ } else { -+ wpa_ie = NULL; -+ wpa_ie_len = 0; -+ } -+ -+ if (_STATS_SUCCESSFUL_ != status) -+ goto OnAssocReqFail; -+ -+ pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); -+ if (wpa_ie == NULL) { -+ if (elems.wps_ie) { -+ DBG_88E("STA included WPS IE in " -+ "(Re)Association Request - assume WPS is " -+ "used\n"); -+ pstat->flags |= WLAN_STA_WPS; -+ /* wpabuf_free(sta->wps_ie); */ -+ /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ -+ /* elems.wps_ie_len - 4); */ -+ } else { -+ DBG_88E("STA did not include WPA/RSN IE " -+ "in (Re)Association Request - possible WPS " -+ "use\n"); -+ pstat->flags |= WLAN_STA_MAYBE_WPS; -+ } -+ -+ /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ -+ /* that the selected registrar of AP is _FLASE */ -+ if ((psecuritypriv->wpa_psk > 0) && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) { -+ if (pmlmepriv->wps_beacon_ie) { -+ u8 selected_registrar = 0; -+ -+ rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL); -+ -+ if (!selected_registrar) { -+ DBG_88E("selected_registrar is false , or AP is not ready to do WPS\n"); -+ -+ status = _STATS_UNABLE_HANDLE_STA_; -+ -+ goto OnAssocReqFail; -+ } -+ } -+ } -+ } else { -+ int copy_len; -+ -+ if (psecuritypriv->wpa_psk == 0) { -+ DBG_88E("STA %pM: WPA/RSN IE in association " -+ "request, but AP don't support WPA/RSN\n", pstat->hwaddr); -+ -+ status = WLAN_STATUS_INVALID_IE; -+ -+ goto OnAssocReqFail; -+ } -+ -+ if (elems.wps_ie) { -+ DBG_88E("STA included WPS IE in " -+ "(Re)Association Request - WPS is " -+ "used\n"); -+ pstat->flags |= WLAN_STA_WPS; -+ copy_len = 0; -+ } else { -+ copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)) : (wpa_ie_len+2); -+ } -+ if (copy_len > 0) -+ memcpy(pstat->wpa_ie, wpa_ie-2, copy_len); -+ } -+ /* check if there is WMM IE & support WWM-PS */ -+ pstat->flags &= ~WLAN_STA_WME; -+ pstat->qos_option = 0; -+ pstat->qos_info = 0; -+ pstat->has_legacy_ac = true; -+ pstat->uapsd_vo = 0; -+ pstat->uapsd_vi = 0; -+ pstat->uapsd_be = 0; -+ pstat->uapsd_bk = 0; -+ if (pmlmepriv->qospriv.qos_option) { -+ p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0; -+ for (;;) { -+ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); -+ if (p != NULL) { -+ if (!memcmp(p+2, WMM_IE, 6)) { -+ pstat->flags |= WLAN_STA_WME; -+ -+ pstat->qos_option = 1; -+ pstat->qos_info = *(p+8); -+ -+ pstat->max_sp_len = (pstat->qos_info>>5)&0x3; -+ -+ if ((pstat->qos_info&0xf) != 0xf) -+ pstat->has_legacy_ac = true; -+ else -+ pstat->has_legacy_ac = false; -+ -+ if (pstat->qos_info&0xf) { -+ if (pstat->qos_info&BIT(0)) -+ pstat->uapsd_vo = BIT(0)|BIT(1); -+ else -+ pstat->uapsd_vo = 0; -+ -+ if (pstat->qos_info&BIT(1)) -+ pstat->uapsd_vi = BIT(0)|BIT(1); -+ else -+ pstat->uapsd_vi = 0; -+ -+ if (pstat->qos_info&BIT(2)) -+ pstat->uapsd_bk = BIT(0)|BIT(1); -+ else -+ pstat->uapsd_bk = 0; -+ -+ if (pstat->qos_info&BIT(3)) -+ pstat->uapsd_be = BIT(0)|BIT(1); -+ else -+ pstat->uapsd_be = 0; -+ } -+ break; -+ } -+ } else { -+ break; -+ } -+ p = p + ie_len + 2; -+ } -+ } -+ -+ /* save HT capabilities in the sta object */ -+ memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap)); -+ if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_cap)) { -+ pstat->flags |= WLAN_STA_HT; -+ -+ pstat->flags |= WLAN_STA_WME; -+ -+ memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct ieee80211_ht_cap)); -+ } else { -+ pstat->flags &= ~WLAN_STA_HT; -+ } -+ if ((!pmlmepriv->htpriv.ht_option) && (pstat->flags&WLAN_STA_HT)) { -+ status = _STATS_FAILURE_; -+ goto OnAssocReqFail; -+ } -+ -+ if ((pstat->flags & WLAN_STA_HT) && -+ ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || -+ (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) { -+ DBG_88E("HT: %pM tried to " -+ "use TKIP with HT association\n", pstat->hwaddr); -+ -+ /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ -+ /* goto OnAssocReqFail; */ -+ } -+ -+ pstat->flags |= WLAN_STA_NONERP; -+ for (i = 0; i < pstat->bssratelen; i++) { -+ if ((pstat->bssrateset[i] & 0x7f) > 22) { -+ pstat->flags &= ~WLAN_STA_NONERP; -+ break; -+ } -+ } -+ -+ if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) -+ pstat->flags |= WLAN_STA_SHORT_PREAMBLE; -+ else -+ pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; -+ -+ if (status != _STATS_SUCCESSFUL_) -+ goto OnAssocReqFail; -+ -+#ifdef CONFIG_88EU_P2P -+ pstat->is_p2p_device = false; -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + ie_offset , pkt_len - WLAN_HDR_A3_LEN - ie_offset , NULL, &p2pielen); -+ if (p2pie) { -+ pstat->is_p2p_device = true; -+ p2p_status_code = (u8)process_assoc_req_p2p_ie(pwdinfo, pframe, pkt_len, pstat); -+ if (p2p_status_code > 0) { -+ pstat->p2p_status_code = p2p_status_code; -+ status = _STATS_CAP_FAIL_; -+ goto OnAssocReqFail; -+ } -+ } -+ } -+ pstat->p2p_status_code = p2p_status_code; -+#endif /* CONFIG_88EU_P2P */ -+ -+ /* TODO: identify_proprietary_vendor_ie(); */ -+ /* Realtek proprietary IE */ -+ /* identify if this is Broadcom sta */ -+ /* identify if this is ralink sta */ -+ /* Customer proprietary IE */ -+ -+ /* get a unique AID */ -+ if (pstat->aid > 0) { -+ DBG_88E(" old AID %d\n", pstat->aid); -+ } else { -+ for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) -+ if (pstapriv->sta_aid[pstat->aid - 1] == NULL) -+ break; -+ -+ /* if (pstat->aid > NUM_STA) { */ -+ if (pstat->aid > pstapriv->max_num_sta) { -+ pstat->aid = 0; -+ -+ DBG_88E(" no room for more AIDs\n"); -+ -+ status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; -+ -+ goto OnAssocReqFail; -+ } else { -+ pstapriv->sta_aid[pstat->aid - 1] = pstat; -+ DBG_88E("allocate new AID=(%d)\n", pstat->aid); -+ } -+ } -+ -+ pstat->state &= (~WIFI_FW_ASSOC_STATE); -+ pstat->state |= WIFI_FW_ASSOC_SUCCESS; -+ -+ spin_lock_bh(&pstapriv->auth_list_lock); -+ if (!list_empty(&pstat->auth_list)) { -+ list_del_init(&pstat->auth_list); -+ pstapriv->auth_list_cnt--; -+ } -+ spin_unlock_bh(&pstapriv->auth_list_lock); -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ if (list_empty(&pstat->asoc_list)) { -+ pstat->expire_to = pstapriv->expire_to; -+ list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list); -+ pstapriv->asoc_list_cnt++; -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ /* now the station is qualified to join our BSS... */ -+ if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) { -+#ifdef CONFIG_88EU_AP_MODE -+ /* 1 bss_cap_update & sta_info_update */ -+ bss_cap_update_on_sta_join(padapter, pstat); -+ sta_info_update(padapter, pstat); -+ -+ /* issue assoc rsp before notify station join event. */ -+ if (frame_type == WIFI_ASSOCREQ) -+ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); -+ else -+ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); -+ -+ /* 2 - report to upper layer */ -+ DBG_88E("indicate_sta_join_event to upper layer - hostapd\n"); -+ rtw_indicate_sta_assoc_event(padapter, pstat); -+ -+ /* 3-(1) report sta add event */ -+ report_add_sta_event(padapter, pstat->hwaddr, pstat->aid); -+#endif -+ } -+ -+ return _SUCCESS; -+ -+asoc_class2_error: -+ -+#ifdef CONFIG_88EU_AP_MODE -+ issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status); -+#endif -+ -+ return _FAIL; -+ -+OnAssocReqFail: -+ -+#ifdef CONFIG_88EU_AP_MODE -+ pstat->aid = 0; -+ if (frame_type == WIFI_ASSOCREQ) -+ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); -+ else -+ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); -+#endif -+ -+#endif /* CONFIG_88EU_AP_MODE */ -+ -+ return _FAIL; -+} -+ -+unsigned int OnAssocRsp(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ uint i; -+ int res; -+ unsigned short status; -+ struct ndis_802_11_var_ie *pIE; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ /* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */ -+ u8 *pframe = precv_frame->rx_data; -+ uint pkt_len = precv_frame->len; -+ -+ DBG_88E("%s\n", __func__); -+ -+ /* check A1 matches or not */ -+ if (memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN)) -+ return _SUCCESS; -+ -+ if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) -+ return _SUCCESS; -+ -+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) -+ return _SUCCESS; -+ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ -+ /* status */ -+ status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2)); -+ if (status > 0) { -+ DBG_88E("assoc reject, status code: %d\n", status); -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ res = -4; -+ goto report_assoc_result; -+ } -+ -+ /* get capabilities */ -+ pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); -+ -+ /* set slot time */ -+ pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20; -+ -+ /* AID */ -+ pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff); -+ res = pmlmeinfo->aid; -+ -+ /* following are moved to join event callback function */ -+ /* to handle HT, WMM, rate adaptive, update MAC reg */ -+ /* for not to handle the synchronous IO in the tasklet */ -+ for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) { -+ pIE = (struct ndis_802_11_var_ie *)(pframe + i); -+ -+ switch (pIE->ElementID) { -+ case _VENDOR_SPECIFIC_IE_: -+ if (!memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */ -+ WMM_param_handler(padapter, pIE); -+ break; -+ case _HT_CAPABILITY_IE_: /* HT caps */ -+ HT_caps_handler(padapter, pIE); -+ break; -+ case _HT_EXTRA_INFO_IE_: /* HT info */ -+ HT_info_handler(padapter, pIE); -+ break; -+ case _ERPINFO_IE_: -+ ERP_IE_handler(padapter, pIE); -+ default: -+ break; -+ } -+ -+ i += (pIE->Length + 2); -+ } -+ -+ pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); -+ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; -+ -+ /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ -+ UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates); -+ -+report_assoc_result: -+ if (res > 0) { -+ rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len); -+ } else { -+ rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); -+ } -+ -+ report_join_res(padapter, res); -+ -+ return _SUCCESS; -+} -+ -+unsigned int OnDeAuth(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ unsigned short reason; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 *pframe = precv_frame->rx_data; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+ /* check A3 */ -+ if (!(!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) -+ return _SUCCESS; -+ -+#ifdef CONFIG_88EU_P2P -+ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { -+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); -+ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); -+ } -+#endif /* CONFIG_88EU_P2P */ -+ -+ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); -+ -+ DBG_88E("%s Reason code(%d)\n", __func__, reason); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ struct sta_info *psta; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ DBG_88E_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n", -+ reason, GetAddr2Ptr(pframe)); -+ -+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); -+ if (psta) { -+ u8 updated = 0; -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ if (!list_empty(&psta->asoc_list)) { -+ list_del_init(&psta->asoc_list); -+ pstapriv->asoc_list_cnt--; -+ updated = ap_free_sta(padapter, psta, false, reason); -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ associated_clients_update(padapter, updated); -+ } -+ -+ return _SUCCESS; -+ } else -+#endif -+ { -+ int ignore_received_deauth = 0; -+ -+ /* Before sending the auth frame to start the STA/GC mode connection with AP/GO, -+ * we will send the deauth first. -+ * However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. -+ * Added the following code to avoid this case. -+ */ -+ if ((pmlmeinfo->state & WIFI_FW_AUTH_STATE) || -+ (pmlmeinfo->state & WIFI_FW_ASSOC_STATE )) { -+ if (reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA) { -+ ignore_received_deauth = 1; -+ } else if (WLAN_REASON_PREV_AUTH_NOT_VALID == reason) { -+ // TODO: 802.11r -+ ignore_received_deauth = 1; -+ } -+ } -+ -+ DBG_88E_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM, ignore = %d\n", -+ reason, GetAddr3Ptr(pframe), ignore_received_deauth); -+ -+ if (!ignore_received_deauth) -+ receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); -+ } -+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; -+ return _SUCCESS; -+} -+ -+unsigned int OnDisassoc(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ u16 reason; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 *pframe = precv_frame->rx_data; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+ /* check A3 */ -+ if (!(!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) -+ return _SUCCESS; -+ -+#ifdef CONFIG_88EU_P2P -+ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { -+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); -+ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); -+ } -+#endif /* CONFIG_88EU_P2P */ -+ -+ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); -+ -+ DBG_88E("%s Reason code(%d)\n", __func__, reason); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ struct sta_info *psta; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", -+ reason, GetAddr2Ptr(pframe)); -+ -+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); -+ if (psta) { -+ u8 updated = 0; -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ if (!list_empty(&psta->asoc_list)) { -+ list_del_init(&psta->asoc_list); -+ pstapriv->asoc_list_cnt--; -+ updated = ap_free_sta(padapter, psta, false, reason); -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ associated_clients_update(padapter, updated); -+ } -+ -+ return _SUCCESS; -+ } else -+#endif -+ { -+ DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", -+ reason, GetAddr3Ptr(pframe)); -+ -+ receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); -+ } -+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; -+ return _SUCCESS; -+} -+ -+unsigned int OnAtim(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ DBG_88E("%s\n", __func__); -+ return _SUCCESS; -+} -+ -+unsigned int on_action_spct(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ unsigned int ret = _FAIL; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 *pframe = precv_frame->rx_data; -+ u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ u8 category; -+ u8 action; -+ -+ DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); -+ -+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); -+ -+ if (!psta) -+ goto exit; -+ -+ category = frame_body[0]; -+ if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) -+ goto exit; -+ -+ action = frame_body[1]; -+ switch (action) { -+ case RTW_WLAN_ACTION_SPCT_MSR_REQ: -+ case RTW_WLAN_ACTION_SPCT_MSR_RPRT: -+ case RTW_WLAN_ACTION_SPCT_TPC_REQ: -+ case RTW_WLAN_ACTION_SPCT_TPC_RPRT: -+ break; -+ case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: -+ break; -+ default: -+ break; -+ } -+ -+exit: -+ return ret; -+} -+ -+unsigned int OnAction_qos(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ return _SUCCESS; -+} -+ -+unsigned int OnAction_dls(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ return _SUCCESS; -+} -+ -+unsigned int OnAction_back(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ u8 *addr; -+ struct sta_info *psta = NULL; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ unsigned char *frame_body; -+ unsigned char category, action; -+ unsigned short tid, status, reason_code = 0; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 *pframe = precv_frame->rx_data; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ /* check RA matches or not */ -+ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */ -+ return _SUCCESS; -+ -+ DBG_88E("%s\n", __func__); -+ -+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) -+ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) -+ return _SUCCESS; -+ -+ addr = GetAddr2Ptr(pframe); -+ psta = rtw_get_stainfo(pstapriv, addr); -+ -+ if (psta == NULL) -+ return _SUCCESS; -+ -+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ category = frame_body[0]; -+ if (category == RTW_WLAN_CATEGORY_BACK) { /* representing Block Ack */ -+ if (!pmlmeinfo->HT_enable) -+ return _SUCCESS; -+ action = frame_body[1]; -+ DBG_88E("%s, action=%d\n", __func__, action); -+ switch (action) { -+ case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ -+ memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); -+ process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr); -+ -+ if (pmlmeinfo->bAcceptAddbaReq) -+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0); -+ else -+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */ -+ break; -+ case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ -+ status = get_unaligned_le16(&frame_body[3]); -+ tid = ((frame_body[5] >> 2) & 0x7); -+ if (status == 0) { /* successful */ -+ DBG_88E("agg_enable for TID=%d\n", tid); -+ psta->htpriv.agg_enable_bitmap |= 1 << tid; -+ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); -+ } else { -+ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); -+ } -+ break; -+ case RTW_WLAN_ACTION_DELBA: /* DELBA */ -+ if ((frame_body[3] & BIT(3)) == 0) { -+ psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); -+ psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); -+ reason_code = get_unaligned_le16(&frame_body[4]); -+ } else if ((frame_body[3] & BIT(3)) == BIT(3)) { -+ tid = (frame_body[3] >> 4) & 0x0F; -+ preorder_ctrl = &psta->recvreorder_ctrl[tid]; -+ preorder_ctrl->enable = false; -+ preorder_ctrl->indicate_seq = 0xffff; -+ } -+ DBG_88E("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code); -+ /* todo: how to notify the host while receiving DELETE BA */ -+ break; -+ default: -+ break; -+ } -+ } -+ return _SUCCESS; -+} -+ -+#ifdef CONFIG_88EU_P2P -+ -+static int get_reg_classes_full_count(struct p2p_channels *channel_list) -+{ -+ int cnt = 0; -+ int i; -+ -+ for (i = 0; i < channel_list->reg_classes; i++) { -+ cnt += channel_list->reg_class[i].channels; -+ } -+ -+ return cnt; -+} -+ -+void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr) -+{ -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_GO_NEGO_REQ; -+ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; -+ u8 wpsielen = 0, p2pielen = 0; -+ u16 len_channellist_attr = 0; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ DBG_88E("[%s] In\n", __func__); -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pwdinfo->negotiation_dialog_token = 1; /* Initialize the dialog value */ -+ pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &(pattrib->pktlen)); -+ -+ /* WPS Section */ -+ wpsielen = 0; -+ /* WPS OUI */ -+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); -+ wpsielen += 4; -+ -+ /* WPS version */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ -+ -+ /* Device Password ID */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); -+ wpsielen += 2; -+ -+ /* Value: */ -+ -+ if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); -+ else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN) -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); -+ else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); -+ -+ wpsielen += 2; -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); -+ -+ /* P2P IE Section. */ -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20110306 */ -+ /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */ -+ /* 1. P2P Capability */ -+ /* 2. Group Owner Intent */ -+ /* 3. Configuration Timeout */ -+ /* 4. Listen Channel */ -+ /* 5. Extended Listen Timing */ -+ /* 6. Intended P2P Interface Address */ -+ /* 7. Channel List */ -+ /* 8. P2P Device Info */ -+ /* 9. Operating Channel */ -+ -+ /* P2P Capability */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; -+ -+ /* Group Capability Bitmap, 1 byte */ -+ if (pwdinfo->persistent_supported) -+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; -+ else -+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; -+ -+ /* Group Owner Intent */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Todo the tie breaker bit. */ -+ p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); -+ -+ /* Configuration Timeout */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ -+ -+ /* Listen Channel */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->listen_channel; /* listening channel number */ -+ -+ /* Extended Listen Timing ATTR */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Availability Period */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); -+ p2pielen += 2; -+ -+ /* Availability Interval */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); -+ p2pielen += 2; -+ -+ /* Intended P2P Interface Address */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Channel List */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; -+ -+ /* Length: */ -+ /* Country String(3) */ -+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ -+ /* + number of channels in all classes */ -+ len_channellist_attr = 3 -+ + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes) -+ + get_reg_classes_full_count(&pmlmeext->channel_list); -+ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Channel Entry List */ -+ -+ { -+ int i, j; -+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { -+ /* Operating Class */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; -+ -+ /* Number of Channels */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; -+ -+ /* Channel List */ -+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; -+ } -+ } -+ } -+ -+ /* Device Info */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; -+ -+ /* Length: */ -+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ -+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address */ -+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Config Method */ -+ /* This field should be big endian. Noted by P2P specification. */ -+ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); -+ -+ p2pielen += 2; -+ -+ /* Primary Device Type */ -+ /* Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); -+ p2pielen += 2; -+ -+ /* OUI */ -+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); -+ p2pielen += 4; -+ -+ /* Sub Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); -+ p2pielen += 2; -+ -+ /* Number of Secondary Device Types */ -+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ -+ -+ /* Device Name */ -+ /* Type: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); -+ p2pielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len); -+ p2pielen += pwdinfo->device_name_len; -+ -+ /* Operating Channel */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result) -+{ -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_GO_NEGO_RESP; -+ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; -+ u8 p2pielen = 0; -+ uint wpsielen = 0; -+ u16 wps_devicepassword_id = 0x0000; -+ __be16 be_tmp; -+ uint wps_devicepassword_id_len = 0; -+ u16 len_channellist_attr = 0; -+ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ DBG_88E("[%s] In, result=%d\n", __func__, result); -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pwdinfo->negotiation_dialog_token = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen)); -+ -+ /* Commented by Albert 20110328 */ -+ /* Try to get the device password ID from the WPS IE of group negotiation request frame */ -+ /* WiFi Direct test plan 5.1.15 */ -+ rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen); -+ rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len); -+ wps_devicepassword_id = be16_to_cpu(be_tmp); -+ -+ memset(wpsie, 0x00, 255); -+ wpsielen = 0; -+ -+ /* WPS Section */ -+ wpsielen = 0; -+ /* WPS OUI */ -+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); -+ wpsielen += 4; -+ -+ /* WPS version */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ -+ -+ /* Device Password ID */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); -+ wpsielen += 2; -+ -+ /* Value: */ -+ if (wps_devicepassword_id == WPS_DPID_USER_SPEC) -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); -+ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); -+ else -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); -+ wpsielen += 2; -+ -+ /* Commented by Kurt 20120113 */ -+ /* If some device wants to do p2p handshake without sending prov_disc_req */ -+ /* We have to get peer_req_cm from here. */ -+ if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { -+ if (wps_devicepassword_id == WPS_DPID_USER_SPEC) -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); -+ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); -+ else -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); -+ } -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); -+ -+ /* P2P IE Section. */ -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20100908 */ -+ /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */ -+ /* 1. Status */ -+ /* 2. P2P Capability */ -+ /* 3. Group Owner Intent */ -+ /* 4. Configuration Timeout */ -+ /* 5. Operating Channel */ -+ /* 6. Intended P2P Interface Address */ -+ /* 7. Channel List */ -+ /* 8. Device Info */ -+ /* 9. Group ID (Only GO) */ -+ -+ /* ToDo: */ -+ -+ /* P2P Status */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_STATUS; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); -+ p2pielen += 2; -+ -+ /* Value: */ -+ p2pie[p2pielen++] = result; -+ -+ /* P2P Capability */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { -+ /* Commented by Albert 2011/03/08 */ -+ /* According to the P2P specification */ -+ /* if the sending device will be client, the P2P Capability should be reserved of group negotiation response frame */ -+ p2pie[p2pielen++] = 0; -+ } else { -+ /* Be group owner or meet the error case */ -+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; -+ } -+ -+ /* Group Capability Bitmap, 1 byte */ -+ if (pwdinfo->persistent_supported) { -+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; -+ } else { -+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; -+ } -+ -+ /* Group Owner Intent */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); -+ p2pielen += 2; -+ -+ /* Value: */ -+ if (pwdinfo->peer_intent & 0x01) { -+ /* Peer's tie breaker bit is 1, our tie breaker bit should be 0 */ -+ p2pie[p2pielen++] = (pwdinfo->intent << 1); -+ } else { -+ /* Peer's tie breaker bit is 0, our tie breaker bit should be 1 */ -+ p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); -+ } -+ -+ /* Configuration Timeout */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ -+ -+ /* Operating Channel */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ -+ -+ /* Intended P2P Interface Address */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Channel List */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; -+ -+ /* Country String(3) */ -+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ -+ /* + number of channels in all classes */ -+ len_channellist_attr = 3 -+ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes -+ + get_reg_classes_full_count(&pmlmeext->channel_list); -+ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); -+ -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Channel Entry List */ -+ -+ { -+ int i, j; -+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { -+ /* Operating Class */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; -+ -+ /* Number of Channels */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; -+ -+ /* Channel List */ -+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; -+ } -+ } -+ } -+ -+ /* Device Info */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; -+ -+ /* Length: */ -+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ -+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address */ -+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Config Method */ -+ /* This field should be big endian. Noted by P2P specification. */ -+ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); -+ -+ p2pielen += 2; -+ -+ /* Primary Device Type */ -+ /* Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); -+ p2pielen += 2; -+ -+ /* OUI */ -+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); -+ p2pielen += 4; -+ -+ /* Sub Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); -+ p2pielen += 2; -+ -+ /* Number of Secondary Device Types */ -+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ -+ -+ /* Device Name */ -+ /* Type: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); -+ p2pielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len); -+ p2pielen += pwdinfo->device_name_len; -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ /* Group ID Attribute */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* p2P Device Address */ -+ memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* SSID */ -+ memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); -+ p2pielen += pwdinfo->nego_ssidlen; -+ } -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ return; -+} -+ -+static void issue_p2p_GO_confirm(struct adapter *padapter, u8 *raddr, u8 result) -+{ -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_GO_NEGO_CONF; -+ u8 p2pie[255] = { 0x00 }; -+ u8 p2pielen = 0; -+ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ DBG_88E("[%s] In\n", __func__); -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen)); -+ -+ /* P2P IE Section. */ -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20110306 */ -+ /* According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */ -+ /* 1. Status */ -+ /* 2. P2P Capability */ -+ /* 3. Operating Channel */ -+ /* 4. Channel List */ -+ /* 5. Group ID (if this WiFi is GO) */ -+ -+ /* P2P Status */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_STATUS; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); -+ p2pielen += 2; -+ -+ /* Value: */ -+ p2pie[p2pielen++] = result; -+ -+ /* P2P Capability */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; -+ -+ /* Group Capability Bitmap, 1 byte */ -+ if (pwdinfo->persistent_supported) -+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; -+ else -+ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; -+ -+ /* Operating Channel */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; -+ p2pie[p2pielen++] = pwdinfo->peer_operating_ch; -+ } else { -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* Use the listen channel as the operating channel */ -+ } -+ -+ /* Channel List */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(pwdinfo->channel_list_attr_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len); -+ p2pielen += pwdinfo->channel_list_attr_len; -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ /* Group ID Attribute */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* p2P Device Address */ -+ memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* SSID */ -+ memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); -+ p2pielen += pwdinfo->nego_ssidlen; -+ } -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ dump_mgntframe(padapter, pmgntframe); -+ return; -+} -+ -+void issue_p2p_invitation_request(struct adapter *padapter, u8 *raddr) -+{ -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_INVIT_REQ; -+ u8 p2pie[255] = { 0x00 }; -+ u8 p2pielen = 0; -+ u8 dialogToken = 3; -+ u16 len_channellist_attr = 0; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); -+ -+ /* P2P IE Section. */ -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20101011 */ -+ /* According to the P2P Specification, the P2P Invitation request frame should contain 7 P2P attributes */ -+ /* 1. Configuration Timeout */ -+ /* 2. Invitation Flags */ -+ /* 3. Operating Channel (Only GO) */ -+ /* 4. P2P Group BSSID (Should be included if I am the GO) */ -+ /* 5. Channel List */ -+ /* 6. P2P Group ID */ -+ /* 7. P2P Device Info */ -+ -+ /* Configuration Timeout */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ -+ -+ /* Invitation Flags */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); -+ p2pielen += 2; -+ -+ /* Value: */ -+ p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT; -+ -+ /* Operating Channel */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; /* operating channel number */ -+ -+ if (!memcmp(myid(&padapter->eeprompriv), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) { -+ /* P2P Group BSSID */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address for GO */ -+ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ } -+ -+ /* Channel List */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; -+ -+ /* Length: */ -+ /* Country String(3) */ -+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ -+ /* + number of channels in all classes */ -+ len_channellist_attr = 3 -+ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes -+ + get_reg_classes_full_count(&pmlmeext->channel_list); -+ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); -+ -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Channel Entry List */ -+ { -+ int i, j; -+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { -+ /* Operating Class */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; -+ -+ /* Number of Channels */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; -+ -+ /* Channel List */ -+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; -+ } -+ } -+ } -+ -+ /* P2P Group ID */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address for GO */ -+ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* SSID */ -+ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, pwdinfo->invitereq_info.ssidlen); -+ p2pielen += pwdinfo->invitereq_info.ssidlen; -+ -+ /* Device Info */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; -+ -+ /* Length: */ -+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ -+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address */ -+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Config Method */ -+ /* This field should be big endian. Noted by P2P specification. */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); -+ p2pielen += 2; -+ -+ /* Primary Device Type */ -+ /* Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); -+ p2pielen += 2; -+ -+ /* OUI */ -+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); -+ p2pielen += 4; -+ -+ /* Sub Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); -+ p2pielen += 2; -+ -+ /* Number of Secondary Device Types */ -+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ -+ -+ /* Device Name */ -+ /* Type: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); -+ p2pielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); -+ p2pielen += pwdinfo->device_name_len; -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr, u8 dialogToken, u8 status_code) -+{ -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_INVIT_RESP; -+ u8 p2pie[255] = { 0x00 }; -+ u8 p2pielen = 0; -+ u16 len_channellist_attr = 0; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); -+ -+ /* P2P IE Section. */ -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20101005 */ -+ /* According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */ -+ /* 1. Status */ -+ /* 2. Configuration Timeout */ -+ /* 3. Operating Channel (Only GO) */ -+ /* 4. P2P Group BSSID (Only GO) */ -+ /* 5. Channel List */ -+ -+ /* P2P Status */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_STATUS; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */ -+ /* Sent the event receiving the P2P Invitation Req frame to DMP UI. */ -+ /* DMP had to compare the MAC address to find out the profile. */ -+ /* So, the WiFi driver will send the P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */ -+ /* If the UI found the corresponding profile, the WiFi driver sends the P2P Invitation Req */ -+ /* to NB to rebuild the persistent group. */ -+ p2pie[p2pielen++] = status_code; -+ -+ /* Configuration Timeout */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ -+ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ -+ -+ if (status_code == P2P_STATUS_SUCCESS) { -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ /* The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */ -+ /* In this case, the P2P Invitation response frame should carry the two more P2P attributes. */ -+ /* First one is operating channel attribute. */ -+ /* Second one is P2P Group BSSID attribute. */ -+ -+ /* Operating Channel */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ -+ -+ /* P2P Group BSSID */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address for GO */ -+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ } -+ -+ /* Channel List */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; -+ -+ /* Length: */ -+ /* Country String(3) */ -+ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ -+ /* + number of channels in all classes */ -+ len_channellist_attr = 3 -+ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes -+ + get_reg_classes_full_count(&pmlmeext->channel_list); -+ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Channel Entry List */ -+ { -+ int i, j; -+ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { -+ /* Operating Class */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; -+ -+ /* Number of Channels */ -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; -+ -+ /* Channel List */ -+ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { -+ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; -+ } -+ } -+ } -+ } -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+void issue_p2p_provision_request(struct adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr) -+{ -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ u8 dialogToken = 1; -+ u8 oui_subtype = P2P_PROVISION_DISC_REQ; -+ u8 wpsie[100] = { 0x00 }; -+ u8 wpsielen = 0; -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u32 p2pielen = 0; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ DBG_88E("[%s] In\n", __func__); -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); -+ -+ p2pielen = build_prov_disc_request_p2p_ie(pwdinfo, pframe, pssid, ussidlen, pdev_raddr); -+ -+ pframe += p2pielen; -+ pattrib->pktlen += p2pielen; -+ -+ wpsielen = 0; -+ /* WPS OUI */ -+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); -+ wpsielen += 4; -+ -+ /* WPS version */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ -+ -+ /* Config Method */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); -+ wpsielen += 2; -+ -+ /* Value: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); -+ wpsielen += 2; -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+static u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo) -+{ -+ u8 i, match_result = 0; -+ -+ DBG_88E("[%s] peermac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, -+ peermacaddr[0], peermacaddr[1], peermacaddr[2], peermacaddr[3], peermacaddr[4], peermacaddr[5]); -+ -+ for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) { -+ DBG_88E("[%s] profileinfo_mac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, -+ profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]); -+ if (!memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) { -+ match_result = 1; -+ DBG_88E("[%s] Match!\n", __func__); -+ break; -+ } -+ } -+ return match_result; -+} -+ -+void issue_probersp_p2p(struct adapter *padapter, unsigned char *da) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ unsigned char *mac; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ u16 beacon_interval = 100; -+ u16 capInfo = 0; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ u8 wpsie[255] = { 0x00 }; -+ u32 wpsielen = 0, p2pielen = 0; -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ mac = myid(&(padapter->eeprompriv)); -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); -+ -+ /* Use the device address for BSSID field. */ -+ memcpy(pwlanhdr->addr3, mac, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(fctrl, WIFI_PROBERSP); -+ -+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = pattrib->hdrlen; -+ pframe += pattrib->hdrlen; -+ -+ /* timestamp will be inserted by hardware */ -+ pframe += 8; -+ pattrib->pktlen += 8; -+ -+ /* beacon interval: 2 bytes */ -+ memcpy(pframe, (unsigned char *)&beacon_interval, 2); -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* capability info: 2 bytes */ -+ /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */ -+ capInfo |= cap_ShortPremble; -+ capInfo |= cap_ShortSlot; -+ -+ memcpy(pframe, (unsigned char *)&capInfo, 2); -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* SSID */ -+ pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen); -+ -+ /* supported rates... */ -+ /* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); -+ -+ /* DS parameter set */ -+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pattrib->pktlen); -+ -+ /* Todo: WPS IE */ -+ /* Noted by Albert 20100907 */ -+ /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ -+ -+ wpsielen = 0; -+ /* WPS OUI */ -+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); -+ wpsielen += 4; -+ -+ /* WPS version */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ -+ -+ /* WiFi Simple Config State */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; /* Not Configured. */ -+ -+ /* Response Type */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; -+ -+ /* UUID-E */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); -+ wpsielen += 2; -+ -+ /* Value: */ -+ memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ wpsielen += 0x10; -+ -+ /* Manufacturer */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007); -+ wpsielen += 2; -+ -+ /* Value: */ -+ memcpy(wpsie + wpsielen, "Realtek", 7); -+ wpsielen += 7; -+ -+ /* Model Name */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006); -+ wpsielen += 2; -+ -+ /* Value: */ -+ memcpy(wpsie + wpsielen, "8188EU", 6); -+ wpsielen += 6; -+ -+ /* Model Number */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = 0x31; /* character 1 */ -+ -+ /* Serial Number */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN); -+ wpsielen += 2; -+ -+ /* Value: */ -+ memcpy(wpsie + wpsielen, "123456" , ETH_ALEN); -+ wpsielen += ETH_ALEN; -+ -+ /* Primary Device Type */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); -+ wpsielen += 2; -+ -+ /* Value: */ -+ /* Category ID */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); -+ wpsielen += 2; -+ -+ /* OUI */ -+ *(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); -+ wpsielen += 4; -+ -+ /* Sub Category ID */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); -+ wpsielen += 2; -+ -+ /* Device Name */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); -+ wpsielen += 2; -+ -+ /* Value: */ -+ if (pwdinfo->device_name_len) { -+ memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); -+ wpsielen += pwdinfo->device_name_len; -+ } -+ -+ /* Config Method */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); -+ wpsielen += 2; -+ -+ /* Value: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); -+ wpsielen += 2; -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); -+ -+ p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe); -+ pframe += p2pielen; -+ pattrib->pktlen += p2pielen; -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+static int _issue_probereq_p2p(struct adapter *padapter, u8 *da, int wait_ack) -+{ -+ int ret = _FAIL; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ unsigned char *mac; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; -+ u16 wpsielen = 0, p2pielen = 0; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ goto exit; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ mac = myid(&(padapter->eeprompriv)); -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ if (da) { -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, da, ETH_ALEN); -+ } else { -+ if ((pwdinfo->p2p_info.scan_op_ch_only) || (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { -+ /* This two flags will be set when this is only the P2P client mode. */ -+ memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); -+ } else { -+ /* broadcast probe request frame */ -+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); -+ } -+ } -+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_PROBEREQ); -+ -+ pframe += sizeof (struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) -+ pframe = rtw_set_ie(pframe, _SSID_IE_, pwdinfo->tx_prov_disc_info.ssid.SsidLength, pwdinfo->tx_prov_disc_info.ssid.Ssid, &(pattrib->pktlen)); -+ else -+ pframe = rtw_set_ie(pframe, _SSID_IE_, P2P_WILDCARD_SSID_LEN, pwdinfo->p2p_wildcard_ssid, &(pattrib->pktlen)); -+ -+ /* Use the OFDM rate in the P2P probe request frame. (6(B), 9(B), 12(B), 24(B), 36, 48, 54) */ -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); -+ -+ /* WPS IE */ -+ /* Noted by Albert 20110221 */ -+ /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ -+ -+ wpsielen = 0; -+ /* WPS OUI */ -+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); -+ wpsielen += 4; -+ -+ /* WPS version */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); -+ wpsielen += 2; -+ -+ /* Value: */ -+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ -+ -+ if (pmlmepriv->wps_probe_req_ie == NULL) { -+ /* UUID-E */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); -+ wpsielen += 2; -+ -+ /* Value: */ -+ memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ wpsielen += 0x10; -+ -+ /* Config Method */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); -+ wpsielen += 2; -+ -+ /* Value: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); -+ wpsielen += 2; -+ } -+ -+ /* Device Name */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); -+ wpsielen += 2; -+ -+ /* Value: */ -+ memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); -+ wpsielen += pwdinfo->device_name_len; -+ -+ /* Primary Device Type */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); -+ wpsielen += 2; -+ -+ /* Value: */ -+ /* Category ID */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI); -+ wpsielen += 2; -+ -+ /* OUI */ -+ *(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); -+ wpsielen += 4; -+ -+ /* Sub Category ID */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP); -+ wpsielen += 2; -+ -+ /* Device Password ID */ -+ /* Type: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); -+ wpsielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); -+ wpsielen += 2; -+ -+ /* Value: */ -+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); /* Registrar-specified */ -+ wpsielen += 2; -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20110221 */ -+ /* According to the P2P Specification, the probe request frame should contain 5 P2P attributes */ -+ /* 1. P2P Capability */ -+ /* 2. P2P Device ID if this probe request wants to find the specific P2P device */ -+ /* 3. Listen Channel */ -+ /* 4. Extended Listen Timing */ -+ /* 5. Operating Channel if this WiFi is working as the group owner now */ -+ -+ /* P2P Capability */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; -+ -+ /* Group Capability Bitmap, 1 byte */ -+ if (pwdinfo->persistent_supported) -+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; -+ else -+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; -+ -+ /* Listen Channel */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->listen_channel; /* listen channel */ -+ -+ /* Extended Listen Timing */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Availability Period */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); -+ p2pielen += 2; -+ -+ /* Availability Interval */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); -+ p2pielen += 2; -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ /* Operating Channel (if this WiFi is working as the group owner now) */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Country String */ -+ p2pie[p2pielen++] = 'X'; -+ p2pie[p2pielen++] = 'X'; -+ -+ /* The third byte should be set to 0x04. */ -+ /* Described in the "Operating Channel Attribute" section. */ -+ p2pie[p2pielen++] = 0x04; -+ -+ /* Operating Class */ -+ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ -+ -+ /* Channel Number */ -+ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ -+ } -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); -+ -+ if (pmlmepriv->wps_probe_req_ie != NULL) { -+ /* WPS IE */ -+ memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); -+ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; -+ pframe += pmlmepriv->wps_probe_req_ie_len; -+ } -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz)); -+ -+ if (wait_ack) { -+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); -+ } else { -+ dump_mgntframe(padapter, pmgntframe); -+ ret = _SUCCESS; -+ } -+ -+exit: -+ return ret; -+} -+ -+inline void issue_probereq_p2p(struct adapter *adapter, u8 *da) -+{ -+ _issue_probereq_p2p(adapter, da, false); -+} -+ -+int issue_probereq_p2p_ex(struct adapter *adapter, u8 *da, int try_cnt, int wait_ms) -+{ -+ int ret; -+ int i = 0; -+ u32 start = jiffies; -+ -+ do { -+ ret = _issue_probereq_p2p(adapter, da, wait_ms > 0 ? true : false); -+ -+ i++; -+ -+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) -+ break; -+ -+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) -+ rtw_msleep_os(wait_ms); -+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); -+ -+ if (ret != _FAIL) { -+ ret = _SUCCESS; -+ goto exit; -+ } -+ -+ if (try_cnt && wait_ms) { -+ if (da) -+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(adapter), da, rtw_get_oper_ch(adapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ else -+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(adapter), rtw_get_oper_ch(adapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ } -+exit: -+ return ret; -+} -+ -+#endif /* CONFIG_88EU_P2P */ -+ -+static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) -+{ -+ struct adapter *adapter = recv_frame->adapter; -+ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); -+ u8 *frame = recv_frame->rx_data; -+ u16 seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) | -+ (recv_frame->attrib.frag_num & 0xf); -+ -+ if (GetRetry(frame)) { -+ if (token >= 0) { -+ if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token)) { -+ DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n", -+ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); -+ return _FAIL; -+ } -+ } else { -+ if (seq_ctrl == mlmeext->action_public_rxseq) { -+ DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n", -+ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq); -+ return _FAIL; -+ } -+ } -+ } -+ -+ mlmeext->action_public_rxseq = seq_ctrl; -+ -+ if (token >= 0) -+ mlmeext->action_public_dialog_token = token; -+ -+ return _SUCCESS; -+} -+ -+static unsigned int on_action_public_p2p(struct recv_frame *precv_frame) -+{ -+ u8 *pframe = precv_frame->rx_data; -+ u8 *frame_body; -+ u8 dialogToken = 0; -+#ifdef CONFIG_88EU_P2P -+ struct adapter *padapter = precv_frame->adapter; -+ uint len = precv_frame->len; -+ u8 *p2p_ie; -+ u32 p2p_ielen; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ u8 result = P2P_STATUS_SUCCESS; -+ u8 empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -+#endif /* CONFIG_88EU_P2P */ -+ -+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ dialogToken = frame_body[7]; -+ -+ if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) -+ return _FAIL; -+ -+#ifdef CONFIG_88EU_P2P -+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); -+ /* Do nothing if the driver doesn't enable the P2P function. */ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) -+ return _SUCCESS; -+ -+ len -= sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ switch (frame_body[6]) { /* OUI Subtype */ -+ case P2P_GO_NEGO_REQ: -+ DBG_88E("[%s] Got GO Nego Req Frame\n", __func__); -+ memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) -+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) { -+ /* Commented by Albert 20110526 */ -+ /* In this case, this means the previous nego fail doesn't be reset yet. */ -+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); -+ /* Restore the previous p2p state */ -+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); -+ DBG_88E("[%s] Restore the previous p2p state to %d\n", __func__, rtw_p2p_state(pwdinfo)); -+ } -+ -+ /* Commented by Kurt 20110902 */ -+ /* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ -+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) -+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); -+ -+ /* Commented by Kurt 20120113 */ -+ /* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */ -+ if (!memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN)) -+ memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN); -+ -+ result = process_p2p_group_negotation_req(pwdinfo, frame_body, len); -+ issue_p2p_GO_response(padapter, GetAddr2Ptr(pframe), frame_body, len, result); -+ -+ /* Commented by Albert 20110718 */ -+ /* No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */ -+ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); -+ break; -+ case P2P_GO_NEGO_RESP: -+ DBG_88E("[%s] Got GO Nego Resp Frame\n", __func__); -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { -+ /* Commented by Albert 20110425 */ -+ /* The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */ -+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); -+ pwdinfo->nego_req_info.benable = false; -+ result = process_p2p_group_negotation_resp(pwdinfo, frame_body, len); -+ issue_p2p_GO_confirm(pwdinfo->padapter, GetAddr2Ptr(pframe), result); -+ if (P2P_STATUS_SUCCESS == result) { -+ if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) { -+ pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch; -+ pwdinfo->p2p_info.scan_op_ch_only = 1; -+ _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH); -+ } -+ } -+ /* Reset the dialog token for group negotiation frames. */ -+ pwdinfo->negotiation_dialog_token = 1; -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) -+ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); -+ } else { -+ DBG_88E("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __func__); -+ } -+ break; -+ case P2P_GO_NEGO_CONF: -+ DBG_88E("[%s] Got GO Nego Confirm Frame\n", __func__); -+ result = process_p2p_group_negotation_confirm(pwdinfo, frame_body, len); -+ if (P2P_STATUS_SUCCESS == result) { -+ if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) { -+ pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch; -+ pwdinfo->p2p_info.scan_op_ch_only = 1; -+ _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH); -+ } -+ } -+ break; -+ case P2P_INVIT_REQ: -+ /* Added by Albert 2010/10/05 */ -+ /* Received the P2P Invite Request frame. */ -+ -+ DBG_88E("[%s] Got invite request frame!\n", __func__); -+ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); -+ if (p2p_ie) { -+ /* Parse the necessary information from the P2P Invitation Request frame. */ -+ /* For example: The MAC address of sending this P2P Invitation Request frame. */ -+ u32 attr_contentlen = 0; -+ u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; -+ struct group_id_info group_id; -+ u8 invitation_flag = 0; -+ -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen); -+ if (attr_contentlen) { -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen); -+ /* Commented by Albert 20120510 */ -+ /* Copy to the pwdinfo->p2p_peer_interface_addr. */ -+ /* So that the WFD UI (or Sigma) can get the peer interface address by using the following command. */ -+ /* #> iwpriv wlan0 p2p_get peer_ifa */ -+ /* After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */ -+ -+ if (attr_contentlen) { -+ DBG_88E("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, -+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], -+ pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3], -+ pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); -+ } -+ -+ if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) { -+ /* Re-invoke the persistent group. */ -+ -+ memset(&group_id, 0x00, sizeof(struct group_id_info)); -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen); -+ if (attr_contentlen) { -+ if (!memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) { -+ /* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ status_code = P2P_STATUS_SUCCESS; -+ } else { -+ /* The p2p device sending this p2p invitation request wants to be the persistent GO. */ -+ if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[0])) { -+ u8 operatingch_info[5] = { 0x00 }; -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { -+ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4])) { -+ /* The operating channel is acceptable for this device. */ -+ pwdinfo->rx_invitereq_info.operation_ch[0] = operatingch_info[4]; -+ pwdinfo->rx_invitereq_info.scan_op_ch_only = 1; -+ _set_timer(&pwdinfo->reset_ch_sitesurvey, P2P_RESET_SCAN_CH); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ status_code = P2P_STATUS_SUCCESS; -+ } else { -+ /* The operating channel isn't supported by this device. */ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ status_code = P2P_STATUS_FAIL_NO_COMMON_CH; -+ _set_timer(&pwdinfo->restore_p2p_state_timer, 3000); -+ } -+ } else { -+ /* Commented by Albert 20121130 */ -+ /* Intel will use the different P2P IE to store the operating channel information */ -+ /* Workaround for Intel WiDi 3.5 */ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ status_code = P2P_STATUS_SUCCESS; -+ } -+ } else { -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); -+ status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; -+ } -+ } -+ } else { -+ DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); -+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; -+ } -+ } else { -+ /* Received the invitation to join a P2P group. */ -+ -+ memset(&group_id, 0x00, sizeof(struct group_id_info)); -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen); -+ if (attr_contentlen) { -+ if (!memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) { -+ /* In this case, the GO can't be myself. */ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); -+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; -+ } else { -+ /* The p2p device sending this p2p invitation request wants to join an existing P2P group */ -+ /* Commented by Albert 2012/06/28 */ -+ /* In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */ -+ /* The peer device address should be the destination address for the provisioning discovery request. */ -+ /* Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */ -+ /* The peer interface address should be the address for WPS mac address */ -+ memcpy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN); -+ status_code = P2P_STATUS_SUCCESS; -+ } -+ } else { -+ DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); -+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; -+ } -+ } -+ } else { -+ DBG_88E("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __func__); -+ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; -+ } -+ -+ DBG_88E("[%s] status_code = %d\n", __func__, status_code); -+ -+ pwdinfo->inviteresp_info.token = frame_body[7]; -+ issue_p2p_invitation_response(padapter, GetAddr2Ptr(pframe), pwdinfo->inviteresp_info.token, status_code); -+ } -+ break; -+ case P2P_INVIT_RESP: { -+ u8 attr_content = 0x00; -+ u32 attr_contentlen = 0; -+ -+ DBG_88E("[%s] Got invite response frame!\n", __func__); -+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); -+ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); -+ if (p2p_ie) { -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); -+ -+ if (attr_contentlen == 1) { -+ DBG_88E("[%s] Status = %d\n", __func__, attr_content); -+ pwdinfo->invitereq_info.benable = false; -+ -+ if (attr_content == P2P_STATUS_SUCCESS) { -+ if (!memcmp(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv), ETH_ALEN)) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ } else { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ } -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK); -+ } else { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); -+ } -+ } else { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); -+ } -+ } else { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); -+ } -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL)) -+ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); -+ break; -+ } -+ case P2P_DEVDISC_REQ: -+ process_p2p_devdisc_req(pwdinfo, pframe, len); -+ break; -+ case P2P_DEVDISC_RESP: -+ process_p2p_devdisc_resp(pwdinfo, pframe, len); -+ break; -+ case P2P_PROVISION_DISC_REQ: -+ DBG_88E("[%s] Got Provisioning Discovery Request Frame\n", __func__); -+ process_p2p_provdisc_req(pwdinfo, pframe, len); -+ memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN); -+ -+ /* 20110902 Kurt */ -+ /* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ -+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) -+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); -+ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ); -+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT); -+ break; -+ case P2P_PROVISION_DISC_RESP: -+ /* Commented by Albert 20110707 */ -+ /* Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */ -+ DBG_88E("[%s] Got Provisioning Discovery Response Frame\n", __func__); -+ /* Commented by Albert 20110426 */ -+ /* The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */ -+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP); -+ process_p2p_provdisc_resp(pwdinfo, pframe); -+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT); -+ break; -+ } -+#endif /* CONFIG_88EU_P2P */ -+ -+ return _SUCCESS; -+} -+ -+static unsigned int on_action_public_vendor(struct recv_frame *precv_frame) -+{ -+ unsigned int ret = _FAIL; -+ u8 *pframe = precv_frame->rx_data; -+ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ if (!memcmp(frame_body + 2, P2P_OUI, 4)) { -+ ret = on_action_public_p2p(precv_frame); -+ } -+ -+ return ret; -+} -+ -+static unsigned int on_action_public_default(struct recv_frame *precv_frame, u8 action) -+{ -+ unsigned int ret = _FAIL; -+ u8 *pframe = precv_frame->rx_data; -+ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); -+ u8 token; -+ -+ token = frame_body[2]; -+ -+ if (rtw_action_public_decache(precv_frame, token) == _FAIL) -+ goto exit; -+ -+ ret = _SUCCESS; -+ -+exit: -+ return ret; -+} -+ -+unsigned int on_action_public(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ unsigned int ret = _FAIL; -+ u8 *pframe = precv_frame->rx_data; -+ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); -+ u8 category, action; -+ -+ /* check RA matches or not */ -+ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN)) -+ goto exit; -+ -+ category = frame_body[0]; -+ if (category != RTW_WLAN_CATEGORY_PUBLIC) -+ goto exit; -+ -+ action = frame_body[1]; -+ switch (action) { -+ case ACT_PUBLIC_VENDOR: -+ ret = on_action_public_vendor(precv_frame); -+ break; -+ default: -+ ret = on_action_public_default(precv_frame, action); -+ break; -+ } -+ -+exit: -+ return ret; -+} -+ -+unsigned int OnAction_ht(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ return _SUCCESS; -+} -+ -+unsigned int OnAction_wmm(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ return _SUCCESS; -+} -+ -+unsigned int OnAction_p2p(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+#ifdef CONFIG_88EU_P2P -+ u8 *frame_body; -+ u8 category, OUI_Subtype; -+ u8 *pframe = precv_frame->rx_data; -+ uint len = precv_frame->len; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ DBG_88E("%s\n", __func__); -+ -+ /* check RA matches or not */ -+ if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */ -+ return _SUCCESS; -+ -+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ category = frame_body[0]; -+ if (category != RTW_WLAN_CATEGORY_P2P) -+ return _SUCCESS; -+ -+ if (be32_to_cpu(*((__be32 *)(frame_body + 1))) != P2POUI) -+ return _SUCCESS; -+ -+ len -= sizeof(struct rtw_ieee80211_hdr_3addr); -+ OUI_Subtype = frame_body[5]; -+ -+ switch (OUI_Subtype) { -+ case P2P_NOTICE_OF_ABSENCE: -+ break; -+ case P2P_PRESENCE_REQUEST: -+ process_p2p_presence_req(pwdinfo, pframe, len); -+ break; -+ case P2P_PRESENCE_RESPONSE: -+ break; -+ case P2P_GO_DISC_REQUEST: -+ break; -+ default: -+ break; -+ } -+#endif /* CONFIG_88EU_P2P */ -+ return _SUCCESS; -+} -+ -+unsigned int OnAction(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ int i; -+ unsigned char category; -+ struct action_handler *ptable; -+ unsigned char *frame_body; -+ u8 *pframe = precv_frame->rx_data; -+ -+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ category = frame_body[0]; -+ -+ for (i = 0; i < sizeof(OnAction_tbl)/sizeof(struct action_handler); i++) { -+ ptable = &OnAction_tbl[i]; -+ if (category == ptable->num) -+ ptable->func(padapter, precv_frame); -+ } -+ return _SUCCESS; -+} -+ -+unsigned int DoReserved(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ return _SUCCESS; -+} -+ -+struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) -+{ -+ struct xmit_frame *pmgntframe; -+ struct xmit_buf *pxmitbuf; -+ -+ pmgntframe = rtw_alloc_xmitframe(pxmitpriv); -+ if (pmgntframe == NULL) { -+ DBG_88E("%s, alloc xmitframe fail\n", __func__); -+ return NULL; -+ } -+ -+ pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); -+ if (pxmitbuf == NULL) { -+ DBG_88E("%s, alloc xmitbuf fail\n", __func__); -+ rtw_free_xmitframe(pxmitpriv, pmgntframe); -+ return NULL; -+ } -+ pmgntframe->frame_tag = MGNT_FRAMETAG; -+ pmgntframe->pxmitbuf = pxmitbuf; -+ pmgntframe->buf_addr = pxmitbuf->pbuf; -+ pxmitbuf->priv_data = pmgntframe; -+ return pmgntframe; -+} -+ -+/**************************************************************************** -+ -+Following are some TX fuctions for WiFi MLME -+ -+*****************************************************************************/ -+ -+void update_mgnt_tx_rate(struct adapter *padapter, u8 rate) -+{ -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ -+ pmlmeext->tx_rate = rate; -+ DBG_88E("%s(): rate = %x\n", __func__, rate); -+} -+ -+void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib) -+{ -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ -+ memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); -+ -+ pattrib->hdrlen = 24; -+ pattrib->nr_frags = 1; -+ pattrib->priority = 7; -+ pattrib->mac_id = 0; -+ pattrib->qsel = 0x12; -+ -+ pattrib->pktlen = 0; -+ -+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) -+ pattrib->raid = 6;/* b mode */ -+ else -+ pattrib->raid = 5;/* a/g mode */ -+ -+ pattrib->encrypt = _NO_PRIVACY_; -+ pattrib->bswenc = false; -+ -+ pattrib->qos_en = false; -+ pattrib->ht_en = false; -+ pattrib->bwmode = HT_CHANNEL_WIDTH_20; -+ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ pattrib->sgi = false; -+ -+ pattrib->seqnum = pmlmeext->mgnt_seq; -+ -+ pattrib->retry_ctrl = true; -+} -+ -+void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe) -+{ -+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) -+ return; -+ -+ rtw_hal_mgnt_xmit(padapter, pmgntframe); -+} -+ -+s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) -+{ -+ s32 ret = _FAIL; -+ struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; -+ struct submit_ctx sctx; -+ -+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) -+ return ret; -+ -+ rtw_sctx_init(&sctx, timeout_ms); -+ pxmitbuf->sctx = &sctx; -+ -+ ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); -+ -+ if (ret == _SUCCESS) -+ ret = rtw_sctx_wait(&sctx); -+ -+ return ret; -+} -+ -+s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe) -+{ -+ s32 ret = _FAIL; -+ u32 timeout_ms = 500;/* 500ms */ -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) -+ return -1; -+ -+ _enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); -+ pxmitpriv->ack_tx = true; -+ -+ pmgntframe->ack_report = 1; -+ if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) { -+ ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms); -+ } -+ -+ pxmitpriv->ack_tx = false; -+ _exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); -+ -+ return ret; -+} -+ -+static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) -+{ -+ u8 *ssid_ie; -+ int ssid_len_ori; -+ int len_diff = 0; -+ -+ ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); -+ -+ if (ssid_ie && ssid_len_ori > 0) { -+ switch (hidden_ssid_mode) { -+ case 1: { -+ u8 *next_ie = ssid_ie + 2 + ssid_len_ori; -+ u32 remain_len = 0; -+ -+ remain_len = ies_len - (next_ie - ies); -+ -+ ssid_ie[1] = 0; -+ memcpy(ssid_ie+2, next_ie, remain_len); -+ len_diff -= ssid_len_ori; -+ -+ break; -+ } -+ case 2: -+ memset(&ssid_ie[2], 0, ssid_len_ori); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ return len_diff; -+} -+ -+void issue_beacon(struct adapter *padapter, int timeout_ms) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ unsigned int rate_len; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) { -+ DBG_88E("%s, alloc mgnt frame fail\n", __func__); -+ return; -+ } -+#if defined (CONFIG_88EU_AP_MODE) -+ spin_lock_bh(&pmlmepriv->bcn_update_lock); -+#endif /* if defined (CONFIG_88EU_AP_MODE) */ -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ pattrib->qsel = 0x10; -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); -+ /* pmlmeext->mgnt_seq++; */ -+ SetFrameSubType(pframe, WIFI_BEACON); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { -+#ifdef CONFIG_88EU_P2P -+ /* for P2P : Primary Device Type & Device Name */ -+ u32 wpsielen = 0, insert_len = 0; -+ u8 *wpsie = NULL; -+ wpsie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wpsielen); -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) { -+ uint wps_offset, remainder_ielen; -+ u8 *premainder_ie, *pframe_wscie; -+ -+ wps_offset = (uint)(wpsie - cur_network->IEs); -+ premainder_ie = wpsie + wpsielen; -+ remainder_ielen = cur_network->IELength - wps_offset - wpsielen; -+ pframe_wscie = pframe + wps_offset; -+ memcpy(pframe, cur_network->IEs, wps_offset+wpsielen); -+ pframe += (wps_offset + wpsielen); -+ pattrib->pktlen += (wps_offset + wpsielen); -+ -+ /* now pframe is end of wsc ie, insert Primary Device Type & Device Name */ -+ /* Primary Device Type */ -+ /* Type: */ -+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); -+ insert_len += 2; -+ -+ /* Length: */ -+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(0x0008); -+ insert_len += 2; -+ -+ /* Value: */ -+ /* Category ID */ -+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); -+ insert_len += 2; -+ -+ /* OUI */ -+ *(__be32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI); -+ insert_len += 4; -+ -+ /* Sub Category ID */ -+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); -+ insert_len += 2; -+ -+ /* Device Name */ -+ /* Type: */ -+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); -+ insert_len += 2; -+ -+ /* Length: */ -+ *(__be16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len); -+ insert_len += 2; -+ -+ /* Value: */ -+ memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len); -+ insert_len += pwdinfo->device_name_len; -+ -+ /* update wsc ie length */ -+ *(pframe_wscie+1) = (wpsielen-2) + insert_len; -+ -+ /* pframe move to end */ -+ pframe += insert_len; -+ pattrib->pktlen += insert_len; -+ -+ /* copy remainder_ie to pframe */ -+ memcpy(pframe, premainder_ie, remainder_ielen); -+ pframe += remainder_ielen; -+ pattrib->pktlen += remainder_ielen; -+ } else -+#endif /* CONFIG_88EU_P2P */ -+ { -+ int len_diff; -+ memcpy(pframe, cur_network->IEs, cur_network->IELength); -+ len_diff = update_hidden_ssid( -+ pframe+_BEACON_IE_OFFSET_ -+ , cur_network->IELength-_BEACON_IE_OFFSET_ -+ , pmlmeinfo->hidden_ssid_mode -+ ); -+ pframe += (cur_network->IELength+len_diff); -+ pattrib->pktlen += (cur_network->IELength+len_diff); -+ } -+ -+ { -+ u8 *wps_ie; -+ uint wps_ielen; -+ u8 sr = 0; -+ wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof (struct rtw_ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_, -+ pattrib->pktlen-sizeof (struct rtw_ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen); -+ if (wps_ie && wps_ielen > 0) -+ rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); -+ if (sr != 0) -+ set_fwstate(pmlmepriv, WIFI_UNDER_WPS); -+ else -+ _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); -+ } -+ -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ u32 len; -+ len = build_beacon_p2p_ie(pwdinfo, pframe); -+ -+ pframe += len; -+ pattrib->pktlen += len; -+ } -+#endif /* CONFIG_88EU_P2P */ -+ -+ goto _issue_bcn; -+ } -+ -+ /* below for ad-hoc mode */ -+ -+ /* timestamp will be inserted by hardware */ -+ pframe += 8; -+ pattrib->pktlen += 8; -+ -+ /* beacon interval: 2 bytes */ -+ -+ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); -+ -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* capability info: 2 bytes */ -+ -+ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); -+ -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* SSID */ -+ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); -+ -+ /* supported rates... */ -+ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); -+ -+ /* DS parameter set */ -+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); -+ -+ { -+ u8 erpinfo = 0; -+ u32 ATIMWindow; -+ /* IBSS Parameter Set... */ -+ ATIMWindow = 0; -+ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); -+ -+ /* ERP IE */ -+ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); -+ } -+ -+ /* EXTERNDED SUPPORTED RATE */ -+ if (rate_len > 8) -+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); -+ /* todo:HT for adhoc */ -+_issue_bcn: -+ -+#if defined (CONFIG_88EU_AP_MODE) -+ pmlmepriv->update_bcn = false; -+ -+ spin_unlock_bh(&pmlmepriv->bcn_update_lock); -+#endif /* if defined (CONFIG_88EU_AP_MODE) */ -+ -+ if ((pattrib->pktlen + TXDESC_SIZE) > 512) { -+ DBG_88E("beacon frame too large\n"); -+ return; -+ } -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ /* DBG_88E("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */ -+ if (timeout_ms > 0) -+ dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); -+ else -+ dump_mgntframe(padapter, pmgntframe); -+} -+ -+void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ unsigned char *mac, *bssid; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+#if defined (CONFIG_88EU_AP_MODE) -+ u8 *pwps_ie; -+ uint wps_ielen; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+#endif /* if defined (CONFIG_88EU_AP_MODE) */ -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ unsigned int rate_len; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) { -+ DBG_88E("%s, alloc mgnt frame fail\n", __func__); -+ return; -+ } -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ mac = myid(&(padapter->eeprompriv)); -+ bssid = cur_network->MacAddress; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(fctrl, WIFI_PROBERSP); -+ -+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = pattrib->hdrlen; -+ pframe += pattrib->hdrlen; -+ -+ if (cur_network->IELength > MAX_IE_SZ) -+ return; -+ -+#if defined(CONFIG_88EU_AP_MODE) -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { -+ pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen); -+ -+ /* inerset & update wps_probe_resp_ie */ -+ if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) { -+ uint wps_offset, remainder_ielen; -+ u8 *premainder_ie; -+ -+ wps_offset = (uint)(pwps_ie - cur_network->IEs); -+ -+ premainder_ie = pwps_ie + wps_ielen; -+ -+ remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; -+ -+ memcpy(pframe, cur_network->IEs, wps_offset); -+ pframe += wps_offset; -+ pattrib->pktlen += wps_offset; -+ -+ wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ -+ if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) { -+ memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2); -+ pframe += wps_ielen+2; -+ pattrib->pktlen += wps_ielen+2; -+ } -+ -+ if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) { -+ memcpy(pframe, premainder_ie, remainder_ielen); -+ pframe += remainder_ielen; -+ pattrib->pktlen += remainder_ielen; -+ } -+ } else { -+ memcpy(pframe, cur_network->IEs, cur_network->IELength); -+ pframe += cur_network->IELength; -+ pattrib->pktlen += cur_network->IELength; -+ } -+ } else -+#endif -+ { -+ /* timestamp will be inserted by hardware */ -+ pframe += 8; -+ pattrib->pktlen += 8; -+ -+ /* beacon interval: 2 bytes */ -+ -+ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); -+ -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* capability info: 2 bytes */ -+ -+ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); -+ -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* below for ad-hoc mode */ -+ -+ /* SSID */ -+ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); -+ -+ /* supported rates... */ -+ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); -+ -+ /* DS parameter set */ -+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { -+ u8 erpinfo = 0; -+ u32 ATIMWindow; -+ /* IBSS Parameter Set... */ -+ /* ATIMWindow = cur->Configuration.ATIMWindow; */ -+ ATIMWindow = 0; -+ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); -+ -+ /* ERP IE */ -+ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); -+ } -+ -+ /* EXTERNDED SUPPORTED RATE */ -+ if (rate_len > 8) -+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); -+ /* todo:HT for adhoc */ -+ } -+ -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && is_valid_p2p_probereq) { -+ u32 len; -+ len = build_probe_resp_p2p_ie(pwdinfo, pframe); -+ -+ pframe += len; -+ pattrib->pktlen += len; -+ } -+#endif /* CONFIG_88EU_P2P */ -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, int wait_ack) -+{ -+ int ret = _FAIL; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ unsigned char *mac; -+ unsigned char bssrate[NumRates]; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ int bssrate_len = 0; -+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n")); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ goto exit; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ mac = myid(&(padapter->eeprompriv)); -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ if (da) { -+ /* unicast probe request frame */ -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, da, ETH_ALEN); -+ } else { -+ /* broadcast probe request frame */ -+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); -+ } -+ -+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_PROBEREQ); -+ -+ pframe += sizeof (struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr); -+ -+ if (pssid) -+ pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen)); -+ else -+ pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen)); -+ -+ get_rate_set(padapter, bssrate, &bssrate_len); -+ -+ if (bssrate_len > 8) { -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); -+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); -+ } else { -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); -+ } -+ -+ /* add wps_ie for wps2.0 */ -+ if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) { -+ memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); -+ pframe += pmlmepriv->wps_probe_req_ie_len; -+ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; -+ } -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, -+ ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz)); -+ -+ if (wait_ack) { -+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); -+ } else { -+ dump_mgntframe(padapter, pmgntframe); -+ ret = _SUCCESS; -+ } -+ -+exit: -+ return ret; -+} -+ -+inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da) -+{ -+ _issue_probereq(padapter, pssid, da, false); -+} -+ -+int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, -+ int try_cnt, int wait_ms) -+{ -+ int ret; -+ int i = 0; -+ u32 start = jiffies; -+ -+ do { -+ ret = _issue_probereq(padapter, pssid, da, wait_ms > 0 ? true : false); -+ -+ i++; -+ -+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) -+ break; -+ -+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) -+ rtw_msleep_os(wait_ms); -+ -+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); -+ -+ if (ret != _FAIL) { -+ ret = _SUCCESS; -+ goto exit; -+ } -+ -+ if (try_cnt && wait_ms) { -+ if (da) -+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ else -+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ } -+exit: -+ return ret; -+} -+ -+/* if psta == NULL, indiate we are station(client) now... */ -+void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ unsigned int val32; -+ u16 val16; -+#ifdef CONFIG_88EU_AP_MODE -+ __le16 le_val16; -+#endif -+ int use_shared_key = 0; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_AUTH); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ if (psta) {/* for AP mode */ -+#ifdef CONFIG_88EU_AP_MODE -+ -+ memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ -+ /* setting auth algo number */ -+ val16 = (u16)psta->authalg; -+ -+ if (status != _STATS_SUCCESSFUL_) -+ val16 = 0; -+ -+ if (val16) { -+ le_val16 = cpu_to_le16(val16); -+ use_shared_key = 1; -+ } else { -+ le_val16 = 0; -+ } -+ -+ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen)); -+ -+ /* setting auth seq number */ -+ val16 = (u16)psta->auth_seq; -+ le_val16 = cpu_to_le16(val16); -+ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen)); -+ -+ /* setting status code... */ -+ val16 = status; -+ le_val16 = cpu_to_le16(val16); -+ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_val16, &(pattrib->pktlen)); -+ -+ /* added challenging text... */ -+ if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) -+ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen)); -+#endif -+ } else { -+ __le32 le_tmp32; -+ __le16 le_tmp16; -+ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); -+ -+ /* setting auth algo number */ -+ val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/* 0:OPEN System, 1:Shared key */ -+ if (val16) -+ use_shared_key = 1; -+ -+ /* setting IV for auth seq #3 */ -+ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { -+ val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30)); -+ le_tmp32 = cpu_to_le32(val32); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &(pattrib->pktlen)); -+ -+ pattrib->iv_len = 4; -+ } -+ -+ le_tmp16 = cpu_to_le16(val16); -+ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); -+ -+ /* setting auth seq number */ -+ val16 = pmlmeinfo->auth_seq; -+ le_tmp16 = cpu_to_le16(val16); -+ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); -+ -+ /* setting status code... */ -+ le_tmp16 = cpu_to_le16(status); -+ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp16, &(pattrib->pktlen)); -+ -+ /* then checking to see if sending challenging text... */ -+ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { -+ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen)); -+ -+ SetPrivacy(fctrl); -+ -+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pattrib->encrypt = _WEP40_; -+ -+ pattrib->icv_len = 4; -+ -+ pattrib->pktlen += pattrib->icv_len; -+ } -+ } -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ rtw_wep_encrypt(padapter, (u8 *)pmgntframe); -+ DBG_88E("%s\n", __func__); -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) -+{ -+#ifdef CONFIG_88EU_AP_MODE -+ struct xmit_frame *pmgntframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ struct pkt_attrib *pattrib; -+ unsigned char *pbuf, *pframe; -+ unsigned short val; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); -+ u8 *ie = pnetwork->IEs; -+ __le16 lestatus, leval; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+ DBG_88E("%s\n", __func__); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); -+ memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) -+ SetFrameSubType(pwlanhdr, pkt_type); -+ else -+ return; -+ -+ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen += pattrib->hdrlen; -+ pframe += pattrib->hdrlen; -+ -+ /* capability */ -+ val = *(unsigned short *)rtw_get_capability_from_ie(ie); -+ -+ pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen)); -+ -+ lestatus = cpu_to_le16(status); -+ pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&lestatus, &(pattrib->pktlen)); -+ -+ leval = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); -+ pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&leval, &(pattrib->pktlen)); -+ -+ if (pstat->bssratelen <= 8) { -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen)); -+ } else { -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen)); -+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen-8), pstat->bssrateset+8, &(pattrib->pktlen)); -+ } -+ -+ if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { -+ uint ie_len = 0; -+ -+ /* FILL HT CAP INFO IE */ -+ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); -+ if (pbuf && ie_len > 0) { -+ memcpy(pframe, pbuf, ie_len+2); -+ pframe += (ie_len+2); -+ pattrib->pktlen += (ie_len+2); -+ } -+ -+ /* FILL HT ADD INFO IE */ -+ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); -+ if (pbuf && ie_len > 0) { -+ memcpy(pframe, pbuf, ie_len+2); -+ pframe += (ie_len+2); -+ pattrib->pktlen += (ie_len+2); -+ } -+ } -+ -+ /* FILL WMM IE */ -+ if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) { -+ uint ie_len = 0; -+ unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; -+ -+ for (pbuf = ie + _BEACON_IE_OFFSET_;; pbuf += (ie_len + 2)) { -+ pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); -+ if (pbuf && !memcmp(pbuf+2, WMM_PARA_IE, 6)) { -+ memcpy(pframe, pbuf, ie_len+2); -+ pframe += (ie_len+2); -+ pattrib->pktlen += (ie_len+2); -+ break; -+ } -+ -+ if ((pbuf == NULL) || (ie_len == 0)) -+ break; -+ } -+ } -+ -+ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); -+ -+ /* add WPS IE ie for wps 2.0 */ -+ if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) { -+ memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); -+ -+ pframe += pmlmepriv->wps_assoc_resp_ie_len; -+ pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; -+ } -+ -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device)) { -+ u32 len; -+ -+ len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code); -+ -+ pframe += len; -+ pattrib->pktlen += len; -+ } -+#endif /* CONFIG_88EU_P2P */ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ dump_mgntframe(padapter, pmgntframe); -+#endif -+} -+ -+void issue_assocreq(struct adapter *padapter) -+{ -+ int ret = _FAIL; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe, *p; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ __le16 le_tmp; -+ unsigned int i, j, ie_len, index = 0; -+ unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; -+ struct ndis_802_11_var_ie *pIE; -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ int bssrate_len = 0, sta_bssrate_len = 0; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ u8 p2pie[255] = { 0x00 }; -+ u16 p2pielen = 0; -+#endif /* CONFIG_88EU_P2P */ -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ goto exit; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ASSOCREQ); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ /* caps */ -+ -+ memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); -+ -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* listen interval */ -+ /* todo: listen interval for power saving */ -+ le_tmp = cpu_to_le16(3); -+ memcpy(pframe , (unsigned char *)&le_tmp, 2); -+ pframe += 2; -+ pattrib->pktlen += 2; -+ -+ /* SSID */ -+ pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen)); -+ -+ /* supported rate & extended supported rate */ -+ -+ /* Check if the AP's supported rates are also supported by STA. */ -+ get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); -+ -+ if (pmlmeext->cur_channel == 14)/* for JAPAN, channel 14 can only uses B Mode(CCK) */ -+ sta_bssrate_len = 4; -+ -+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { -+ if (pmlmeinfo->network.SupportedRates[i] == 0) -+ break; -+ DBG_88E("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); -+ } -+ -+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { -+ if (pmlmeinfo->network.SupportedRates[i] == 0) -+ break; -+ -+ /* Check if the AP's supported rates are also supported by STA. */ -+ for (j = 0; j < sta_bssrate_len; j++) { -+ /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ -+ if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK) -+ == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) -+ break; -+ } -+ -+ if (j == sta_bssrate_len) { -+ /* the rate is not supported by STA */ -+ DBG_88E("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]); -+ } else { -+ /* the rate is supported by STA */ -+ bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; -+ } -+ } -+ -+ bssrate_len = index; -+ DBG_88E("bssrate_len=%d\n", bssrate_len); -+ -+ if (bssrate_len == 0) { -+ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); -+ rtw_free_xmitframe(pxmitpriv, pmgntframe); -+ goto exit; /* don't connect to AP if no joint supported rate */ -+ } -+ -+ if (bssrate_len > 8) { -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); -+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); -+ } else { -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); -+ } -+ -+ /* RSN */ -+ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); -+ if (p != NULL) -+ pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen)); -+ -+ /* HT caps */ -+ if (padapter->mlmepriv.htpriv.ht_option) { -+ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_CAPABILITY_IE_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); -+ if ((p != NULL) && (!(is_ap_in_tkip(padapter)))) { -+ memcpy(&(pmlmeinfo->HT_caps), (p + 2), sizeof(struct HT_caps_element)); -+ -+ /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ -+ if (pregpriv->cbw40_enable == 0) -+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= cpu_to_le16(~(BIT(6) | BIT(1))); -+ else -+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(BIT(1)); -+ -+ /* todo: disable SM power save mode */ -+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x000c); -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ switch (rf_type) { -+ case RF_1T1R: -+ if (pregpriv->rx_stbc) -+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */ -+ memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16); -+ break; -+ case RF_2T2R: -+ case RF_1T2R: -+ default: -+ if ((pregpriv->rx_stbc == 0x3) ||/* enable for 2.4/5 GHz */ -+ ((pmlmeext->cur_wireless_mode & WIRELESS_11_24N) && (pregpriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */ -+ (pregpriv->wifi_spec == 1)) { -+ DBG_88E("declare supporting RX STBC\n"); -+ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */ -+ } -+ memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16); -+ break; -+ } -+ pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen)); -+ } -+ } -+ -+ /* vendor specific IE, such as WPA, WMM, WPS */ -+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { -+ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); -+ -+ switch (pIE->ElementID) { -+ case _VENDOR_SPECIFIC_IE_: -+ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) || -+ (!memcmp(pIE->data, WMM_OUI, 4)) || -+ (!memcmp(pIE->data, WPS_OUI, 4))) { -+ if (!padapter->registrypriv.wifi_spec) { -+ /* Commented by Kurt 20110629 */ -+ /* In some older APs, WPS handshake */ -+ /* would be fail if we append vender extensions informations to AP */ -+ if (!memcmp(pIE->data, WPS_OUI, 4)) -+ pIE->Length = 14; -+ } -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &(pattrib->pktlen)); -+ } -+ break; -+ default: -+ break; -+ } -+ i += (pIE->Length + 2); -+ } -+ -+ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); -+ -+#ifdef CONFIG_88EU_P2P -+ -+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { -+ /* Should add the P2P IE in the association request frame. */ -+ /* P2P OUI */ -+ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20101109 */ -+ /* According to the P2P Specification, the association request frame should contain 3 P2P attributes */ -+ /* 1. P2P Capability */ -+ /* 2. Extended Listen Timing */ -+ /* 3. Device Info */ -+ /* Commented by Albert 20110516 */ -+ /* 4. P2P Interface */ -+ -+ /* P2P Capability */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; -+ -+ /* Group Capability Bitmap, 1 byte */ -+ if (pwdinfo->persistent_supported) -+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; -+ else -+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; -+ -+ /* Extended Listen Timing */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Availability Period */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); -+ p2pielen += 2; -+ -+ /* Availability Interval */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); -+ p2pielen += 2; -+ -+ /* Device Info */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; -+ -+ /* Length: */ -+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ -+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address */ -+ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Config Method */ -+ /* This field should be big endian. Noted by P2P specification. */ -+ if ((pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) || -+ (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)) -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); -+ else -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); -+ -+ p2pielen += 2; -+ -+ /* Primary Device Type */ -+ /* Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); -+ p2pielen += 2; -+ -+ /* OUI */ -+ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); -+ p2pielen += 4; -+ -+ /* Sub Category ID */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); -+ p2pielen += 2; -+ -+ /* Number of Secondary Device Types */ -+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ -+ -+ /* Device Name */ -+ /* Type: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); -+ p2pielen += 2; -+ -+ /* Length: */ -+ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); -+ p2pielen += pwdinfo->device_name_len; -+ -+ /* P2P Interface */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_INTERFACE; -+ -+ /* Length: */ -+ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x000D); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Device Address */ -+ p2pielen += ETH_ALEN; -+ -+ p2pie[p2pielen++] = 1; /* P2P Interface Address Count */ -+ -+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Interface Address List */ -+ p2pielen += ETH_ALEN; -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); -+ } -+ -+#endif /* CONFIG_88EU_P2P */ -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ dump_mgntframe(padapter, pmgntframe); -+ -+ ret = _SUCCESS; -+ -+exit: -+ if (ret == _SUCCESS) -+ rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); -+ else -+ rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); -+ -+ return; -+} -+ -+/* when wait_ack is ture, this function shoule be called at process context */ -+static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) -+{ -+ int ret = _FAIL; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv; -+ struct mlme_ext_priv *pmlmeext; -+ struct mlme_ext_info *pmlmeinfo; -+ -+ if (!padapter) -+ goto exit; -+ -+ pxmitpriv = &(padapter->xmitpriv); -+ pmlmeext = &(padapter->mlmeextpriv); -+ pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ goto exit; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ pattrib->retry_ctrl = false; -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) -+ SetFrDs(fctrl); -+ else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) -+ SetToDs(fctrl); -+ -+ if (power_mode) -+ SetPwrMgt(fctrl); -+ -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_DATA_NULL); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ if (wait_ack) { -+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); -+ } else { -+ dump_mgntframe(padapter, pmgntframe); -+ ret = _SUCCESS; -+ } -+ -+exit: -+ return ret; -+} -+ -+/* when wait_ms > 0 , this function shoule be called at process context */ -+/* da == NULL for station mode */ -+int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) -+{ -+ int ret; -+ int i = 0; -+ u32 start = jiffies; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ /* da == NULL, assum it's null data for sta to ap*/ -+ if (da == NULL) -+ da = get_my_bssid(&(pmlmeinfo->network)); -+ -+ do { -+ ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? true : false); -+ -+ i++; -+ -+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) -+ break; -+ -+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) -+ rtw_msleep_os(wait_ms); -+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); -+ -+ if (ret != _FAIL) { -+ ret = _SUCCESS; -+ goto exit; -+ } -+ -+ if (try_cnt && wait_ms) { -+ if (da) -+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ else -+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ } -+exit: -+ return ret; -+} -+ -+/* when wait_ack is ture, this function shoule be called at process context */ -+static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack) -+{ -+ int ret = _FAIL; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ unsigned short *qc; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ DBG_88E("%s\n", __func__); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ goto exit; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ pattrib->hdrlen += 2; -+ pattrib->qos_en = true; -+ pattrib->eosp = 1; -+ pattrib->ack_policy = 0; -+ pattrib->mdata = 0; -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) -+ SetFrDs(fctrl); -+ else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) -+ SetToDs(fctrl); -+ -+ if (pattrib->mdata) -+ SetMData(fctrl); -+ -+ qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); -+ -+ SetPriority(qc, tid); -+ -+ SetEOSP(qc, pattrib->eosp); -+ -+ SetAckpolicy(qc, pattrib->ack_policy); -+ -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ if (wait_ack) { -+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); -+ } else { -+ dump_mgntframe(padapter, pmgntframe); -+ ret = _SUCCESS; -+ } -+ -+exit: -+ return ret; -+} -+ -+/* when wait_ms > 0 , this function shoule be called at process context */ -+/* da == NULL for station mode */ -+int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) -+{ -+ int ret; -+ int i = 0; -+ u32 start = jiffies; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ /* da == NULL, assum it's null data for sta to ap*/ -+ if (da == NULL) -+ da = get_my_bssid(&(pmlmeinfo->network)); -+ -+ do { -+ ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? true : false); -+ -+ i++; -+ -+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) -+ break; -+ -+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) -+ rtw_msleep_os(wait_ms); -+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); -+ -+ if (ret != _FAIL) { -+ ret = _SUCCESS; -+ goto exit; -+ } -+ -+ if (try_cnt && wait_ms) { -+ if (da) -+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ else -+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ } -+exit: -+ return ret; -+} -+ -+static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ int ret = _FAIL; -+ __le16 le_tmp; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+#ifdef CONFIG_88EU_P2P -+ if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { -+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); -+ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); -+ } -+#endif /* CONFIG_88EU_P2P */ -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ goto exit; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ pattrib->retry_ctrl = false; -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_DEAUTH); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ le_tmp = cpu_to_le16(reason); -+ pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&le_tmp, &(pattrib->pktlen)); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ if (wait_ack) { -+ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); -+ } else { -+ dump_mgntframe(padapter, pmgntframe); -+ ret = _SUCCESS; -+ } -+ -+exit: -+ return ret; -+} -+ -+int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) -+{ -+ DBG_88E("%s to %pM\n", __func__, da); -+ return _issue_deauth(padapter, da, reason, false); -+} -+ -+int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt, -+ int wait_ms) -+{ -+ int ret; -+ int i = 0; -+ u32 start = jiffies; -+ -+ do { -+ ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? true : false); -+ -+ i++; -+ -+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) -+ break; -+ -+ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) -+ rtw_msleep_os(wait_ms); -+ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); -+ -+ if (ret != _FAIL) { -+ ret = _SUCCESS; -+ goto exit; -+ } -+ -+ if (try_cnt && wait_ms) { -+ if (da) -+ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ else -+ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", -+ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), -+ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); -+ } -+exit: -+ return ret; -+} -+ -+void issue_action_spct_ch_switch (struct adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ -+ DBG_88E(FUNC_NDEV_FMT" ra =%pM, ch:%u, offset:%u\n", -+ FUNC_NDEV_ARG(padapter->pnetdev), ra, new_ch, ch_offset); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */ -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); /* TA */ -+ memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */ -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ /* category, action */ -+ { -+ u8 category, action; -+ category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT; -+ action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH; -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ } -+ -+ pframe = rtw_set_ie_ch_switch (pframe, &(pattrib->pktlen), 0, new_ch, 0); -+ pframe = rtw_set_ie_secondary_ch_offset(pframe, &(pattrib->pktlen), -+ hal_ch_offset_to_secondary_ch_offset(ch_offset)); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+} -+ -+void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) -+{ -+ u8 category = RTW_WLAN_CATEGORY_BACK; -+ u16 start_seq; -+ u16 BA_para_set; -+ u16 reason_code; -+ u16 BA_timeout_value; -+ __le16 le_tmp; -+ u16 BA_starting_seqctrl = 0; -+ enum ht_cap_ampdu_factor max_rx_ampdu_factor; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ u8 *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct sta_info *psta; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ -+ DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ -+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ -+ if (category == 3) { -+ switch (action) { -+ case 0: /* ADDBA req */ -+ do { -+ pmlmeinfo->dialogToken++; -+ } while (pmlmeinfo->dialogToken == 0); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen)); -+ -+ BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ -+ le_tmp = cpu_to_le16(BA_para_set); -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); -+ -+ BA_timeout_value = 5000;/* 5ms */ -+ le_tmp = cpu_to_le16(BA_timeout_value); -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); -+ -+ psta = rtw_get_stainfo(pstapriv, raddr); -+ if (psta != NULL) { -+ start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; -+ -+ DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07); -+ -+ psta->BA_starting_seqctrl[status & 0x07] = start_seq; -+ -+ BA_starting_seqctrl = start_seq << 4; -+ } -+ le_tmp = cpu_to_le16(BA_starting_seqctrl); -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); -+ break; -+ case 1: /* ADDBA rsp */ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen)); -+ BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; -+ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); -+ switch (max_rx_ampdu_factor) { -+ case MAX_AMPDU_FACTOR_64K: -+ BA_para_set |= 0x1000; /* 64 buffer size */ -+ break; -+ case MAX_AMPDU_FACTOR_32K: -+ BA_para_set |= 0x0800; /* 32 buffer size */ -+ break; -+ case MAX_AMPDU_FACTOR_16K: -+ BA_para_set |= 0x0400; /* 16 buffer size */ -+ break; -+ case MAX_AMPDU_FACTOR_8K: -+ BA_para_set |= 0x0200; /* 8 buffer size */ -+ break; -+ default: -+ BA_para_set |= 0x1000; /* 64 buffer size */ -+ break; -+ } -+ -+ if (pregpriv->ampdu_amsdu == 0)/* disabled */ -+ BA_para_set = BA_para_set & ~BIT(0); -+ else if (pregpriv->ampdu_amsdu == 1)/* enabled */ -+ BA_para_set = BA_para_set | BIT(0); -+ le_tmp = cpu_to_le16(BA_para_set); -+ -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen)); -+ break; -+ case 2:/* DELBA */ -+ BA_para_set = (status & 0x1F) << 3; -+ le_tmp = cpu_to_le16(BA_para_set); -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); -+ -+ reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */ -+ le_tmp = cpu_to_le16(reason_code); -+ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen)); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+} -+ -+static void issue_action_BSSCoexistPacket(struct adapter *padapter) -+{ -+ struct list_head *plist, *phead; -+ unsigned char category, action; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct wlan_network *pnetwork = NULL; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct __queue *queue = &(pmlmepriv->scanned_queue); -+ u8 InfoContent[16] = {0}; -+ u8 ICS[8][15]; -+ if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) -+ return; -+ -+ if (pmlmeinfo->bwmode_updated) -+ return; -+ -+ DBG_88E("%s\n", __func__); -+ -+ category = RTW_WLAN_CATEGORY_PUBLIC; -+ action = ACT_PUBLIC_BSSCOEXIST; -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ -+ /* */ -+ if (pmlmepriv->num_FortyMHzIntolerant > 0) { -+ u8 iedata = 0; -+ -+ iedata |= BIT(2);/* 20 MHz BSS Width Request */ -+ -+ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); -+ } -+ -+ /* */ -+ memset(ICS, 0, sizeof(ICS)); -+ if (pmlmepriv->num_sta_no_ht > 0) { -+ int i; -+ -+ spin_lock_bh(&pmlmepriv->scanned_queue.lock); -+ -+ phead = get_list_head(queue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ int len; -+ u8 *p; -+ struct wlan_bssid_ex *pbss_network; -+ -+ pnetwork = container_of(plist, struct wlan_network, list); -+ -+ plist = plist->next; -+ -+ pbss_network = (struct wlan_bssid_ex *)&pnetwork->network; -+ -+ p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); -+ if ((p == NULL) || (len == 0)) { /* non-HT */ -+ if ((pbss_network->Configuration.DSConfig <= 0) || (pbss_network->Configuration.DSConfig > 14)) -+ continue; -+ -+ ICS[0][pbss_network->Configuration.DSConfig] = 1; -+ -+ if (ICS[0][0] == 0) -+ ICS[0][0] = 1; -+ } -+ } -+ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); -+ -+ for (i = 0; i < 8; i++) { -+ if (ICS[i][0] == 1) { -+ int j, k = 0; -+ -+ InfoContent[k] = i; -+ /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ -+ k++; -+ -+ for (j = 1; j <= 14; j++) { -+ if (ICS[i][j] == 1) { -+ if (k < 16) { -+ InfoContent[k] = j; /* channel number */ -+ /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ -+ k++; -+ } -+ } -+ } -+ -+ pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen)); -+ } -+ } -+ } -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+} -+ -+unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) -+{ -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct sta_info *psta = NULL; -+ /* struct recv_reorder_ctrl *preorder_ctrl; */ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u16 tid; -+ -+ if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) -+ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) -+ return _SUCCESS; -+ -+ psta = rtw_get_stainfo(pstapriv, addr); -+ if (psta == NULL) -+ return _SUCCESS; -+ -+ if (initiator == 0) { /* recipient */ -+ for (tid = 0; tid < MAXTID; tid++) { -+ if (psta->recvreorder_ctrl[tid].enable) { -+ DBG_88E("rx agg disable tid(%d)\n", tid); -+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); -+ psta->recvreorder_ctrl[tid].enable = false; -+ psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; -+ } -+ } -+ } else if (initiator == 1) { /* originator */ -+ for (tid = 0; tid < MAXTID; tid++) { -+ if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { -+ DBG_88E("tx agg disable tid(%d)\n", tid); -+ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); -+ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); -+ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); -+ } -+ } -+ } -+ -+ return _SUCCESS; -+} -+ -+unsigned int send_beacon(struct adapter *padapter) -+{ -+ u8 bxmitok = false; -+ int issue = 0; -+ int poll = 0; -+ -+ u32 start = jiffies; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); -+ do { -+ issue_beacon(padapter, 100); -+ issue++; -+ do { -+ rtw_yield_os(); -+ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); -+ poll++; -+ } while ((poll%10) != 0 && !bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); -+ } while (!bxmitok && issue < 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); -+ -+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) -+ return _FAIL; -+ if (!bxmitok) { -+ DBG_88E("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms(start)); -+ return _FAIL; -+ } else { -+ u32 passing_time = rtw_get_passing_time_ms(start); -+ -+ if (passing_time > 100 || issue > 3) -+ DBG_88E("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, rtw_get_passing_time_ms(start)); -+ return _SUCCESS; -+ } -+} -+ -+/**************************************************************************** -+ -+Following are some utitity fuctions for WiFi MLME -+ -+*****************************************************************************/ -+ -+void site_survey(struct adapter *padapter) -+{ -+ unsigned char survey_channel = 0, val8; -+ enum rt_scan_type ScanType = SCAN_PASSIVE; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u32 initialgain = 0; -+ -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) { -+ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { -+ survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; -+ } else { -+ survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; -+ } -+ ScanType = SCAN_ACTIVE; -+ } else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) { -+ /* Commented by Albert 2011/06/03 */ -+ /* The driver is in the find phase, it should go through the social channel. */ -+ int ch_set_idx; -+ survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx]; -+ ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, survey_channel); -+ if (ch_set_idx >= 0) -+ ScanType = pmlmeext->channel_set[ch_set_idx].ScanType; -+ else -+ ScanType = SCAN_ACTIVE; -+ } else -+#endif /* CONFIG_88EU_P2P */ -+ { -+ struct rtw_ieee80211_channel *ch; -+ if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { -+ ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; -+ survey_channel = ch->hw_value; -+ ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; -+ } -+ } -+ -+ if (survey_channel != 0) { -+ /* PAUSE 4-AC Queue when site_survey */ -+ /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ -+ /* val8 |= 0x0f; */ -+ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ -+ if (pmlmeext->sitesurvey_res.channel_idx == 0) -+ set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ else -+ SelectChannel(padapter, survey_channel); -+ -+ if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */ -+ #ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || -+ rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) { -+ issue_probereq_p2p(padapter, NULL); -+ issue_probereq_p2p(padapter, NULL); -+ issue_probereq_p2p(padapter, NULL); -+ } else -+ #endif /* CONFIG_88EU_P2P */ -+ { -+ int i; -+ for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { -+ if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) { -+ /* todo: to issue two probe req??? */ -+ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); -+ /* rtw_msleep_os(SURVEY_TO>>1); */ -+ issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); -+ } -+ } -+ -+ if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { -+ /* todo: to issue two probe req??? */ -+ issue_probereq(padapter, NULL, NULL); -+ /* rtw_msleep_os(SURVEY_TO>>1); */ -+ issue_probereq(padapter, NULL, NULL); -+ } -+ } -+ } -+ -+ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); -+ } else { -+ /* channel number is 0 or this channel is not valid. */ -+ -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) { -+ if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) { -+ /* Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. */ -+ /* This will let the following flow to run the scanning end. */ -+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); -+ } -+ } -+ -+ if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) { -+ /* Set the P2P State to the listen state of find phase and set the current channel to the listen channel */ -+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN); -+ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; -+ -+ initialgain = 0xff; /* restore RX GAIN */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); -+ /* turn on dynamic functions */ -+ Restore_DM_Func_Flag(padapter); -+ /* Switch_DM_Func(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, true); */ -+ -+ _set_timer(&pwdinfo->find_phase_timer, (u32)((u32)(pwdinfo->listen_dwell) * 100)); -+ } else -+#endif /* CONFIG_88EU_P2P */ -+ { -+ /* 20100721:Interrupt scan operation here. */ -+ /* For SW antenna diversity before link, it needs to switch to another antenna and scan again. */ -+ /* It compares the scan result and select beter one to do connection. */ -+ if (rtw_hal_antdiv_before_linked(padapter)) { -+ pmlmeext->sitesurvey_res.bss_cnt = 0; -+ pmlmeext->sitesurvey_res.channel_idx = -1; -+ pmlmeext->chan_scan_time = SURVEY_TO / 2; -+ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); -+ return; -+ } -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) -+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); -+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); -+#endif /* CONFIG_88EU_P2P */ -+ -+ pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; -+ -+ /* switch back to the original channel */ -+ -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN)) -+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ else -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); -+#endif /* CONFIG_88EU_P2P */ -+ -+ /* flush 4-AC Queue after site_survey */ -+ /* val8 = 0; */ -+ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ -+ -+ /* config MSR */ -+ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); -+ -+ initialgain = 0xff; /* restore RX GAIN */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); -+ /* turn on dynamic functions */ -+ Restore_DM_Func_Flag(padapter); -+ /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ -+ -+ if (is_client_associated_to_ap(padapter)) -+ issue_nulldata(padapter, NULL, 0, 3, 500); -+ -+ val8 = 0; /* survey done */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); -+ -+ report_surveydone_event(padapter); -+ -+ pmlmeext->chan_scan_time = SURVEY_TO; -+ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; -+ -+ issue_action_BSSCoexistPacket(padapter); -+ issue_action_BSSCoexistPacket(padapter); -+ issue_action_BSSCoexistPacket(padapter); -+ } -+ } -+ return; -+} -+ -+/* collect bss info from Beacon and Probe request/response frames. */ -+u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid) -+{ -+ int i; -+ u32 len; -+ u8 *p; -+ u16 val16, subtype; -+ u8 *pframe = precv_frame->rx_data; -+ u32 packet_len = precv_frame->len; -+ u8 ie_offset; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ __le32 le32_tmp; -+ -+ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ if (len > MAX_IE_SZ) -+ return _FAIL; -+ -+ memset(bssid, 0, sizeof(struct wlan_bssid_ex)); -+ -+ subtype = GetFrameSubType(pframe); -+ -+ if (subtype == WIFI_BEACON) { -+ bssid->Reserved[0] = 1; -+ ie_offset = _BEACON_IE_OFFSET_; -+ } else { -+ /* FIXME : more type */ -+ if (subtype == WIFI_PROBEREQ) { -+ ie_offset = _PROBEREQ_IE_OFFSET_; -+ bssid->Reserved[0] = 2; -+ } else if (subtype == WIFI_PROBERSP) { -+ ie_offset = _PROBERSP_IE_OFFSET_; -+ bssid->Reserved[0] = 3; -+ } else { -+ bssid->Reserved[0] = 0; -+ ie_offset = _FIXED_IE_LENGTH_; -+ } -+ } -+ -+ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; -+ -+ /* below is to copy the information element */ -+ bssid->IELength = len; -+ memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); -+ -+ /* get the signal strength */ -+ bssid->Rssi = precv_frame->attrib.phy_info.recvpower; /* in dBM.raw data */ -+ bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */ -+ bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */ -+ rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA, &bssid->PhyInfo.Optimum_antenna); -+ -+ /* checking SSID */ -+ p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset); -+ if (p == NULL) { -+ DBG_88E("marc: cannot find SSID for survey event\n"); -+ return _FAIL; -+ } -+ -+ if (*(p + 1)) { -+ if (len > NDIS_802_11_LENGTH_SSID) { -+ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); -+ return _FAIL; -+ } -+ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); -+ bssid->Ssid.SsidLength = *(p + 1); -+ } else { -+ bssid->Ssid.SsidLength = 0; -+ } -+ -+ memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); -+ -+ /* checking rate info... */ -+ i = 0; -+ p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); -+ if (p != NULL) { -+ if (len > NDIS_802_11_LENGTH_RATES_EX) { -+ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); -+ return _FAIL; -+ } -+ memcpy(bssid->SupportedRates, (p + 2), len); -+ i = len; -+ } -+ -+ p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); -+ if (p != NULL) { -+ if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) { -+ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); -+ return _FAIL; -+ } -+ memcpy(bssid->SupportedRates + i, (p + 2), len); -+ } -+ -+ /* todo: */ -+ bssid->NetworkTypeInUse = Ndis802_11OFDM24; -+ -+ if (bssid->IELength < 12) -+ return _FAIL; -+ -+ /* Checking for DSConfig */ -+ p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); -+ -+ bssid->Configuration.DSConfig = 0; -+ bssid->Configuration.Length = 0; -+ -+ if (p) { -+ bssid->Configuration.DSConfig = *(p + 2); -+ } else {/* In 5G, some ap do not have DSSET IE */ -+ /* checking HT info for channel */ -+ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); -+ if (p) { -+ struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); -+ bssid->Configuration.DSConfig = HT_info->primary_channel; -+ } else { /* use current channel */ -+ bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); -+ } -+ } -+ -+ memcpy(&le32_tmp, rtw_get_beacon_interval_from_ie(bssid->IEs), 2); -+ bssid->Configuration.BeaconPeriod = le32_to_cpu(le32_tmp); -+ -+ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); -+ -+ if (val16 & BIT(0)) { -+ bssid->InfrastructureMode = Ndis802_11Infrastructure; -+ memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); -+ } else { -+ bssid->InfrastructureMode = Ndis802_11IBSS; -+ memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN); -+ } -+ -+ if (val16 & BIT(4)) -+ bssid->Privacy = 1; -+ else -+ bssid->Privacy = 0; -+ -+ bssid->Configuration.ATIMWindow = 0; -+ -+ /* 20/40 BSS Coexistence check */ -+ if ((pregistrypriv->wifi_spec == 1) && (!pmlmeinfo->bwmode_updated)) { -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); -+ if (p && len > 0) { -+ struct HT_caps_element *pHT_caps; -+ pHT_caps = (struct HT_caps_element *)(p + 2); -+ -+ if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info)&BIT(14)) -+ pmlmepriv->num_FortyMHzIntolerant++; -+ } else { -+ pmlmepriv->num_sta_no_ht++; -+ } -+ } -+ -+ /* mark bss info receiving from nearby channel as SignalQuality 101 */ -+ if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) -+ bssid->PhyInfo.SignalQuality = 101; -+ return _SUCCESS; -+} -+ -+void start_create_ibss(struct adapter *padapter) -+{ -+ unsigned short caps; -+ u8 val8; -+ u8 join_type; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); -+ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; -+ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); -+ -+ /* update wireless mode */ -+ update_wireless_mode(padapter); -+ -+ /* udpate capability */ -+ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); -+ update_capinfo(padapter, caps); -+ if (caps&cap_IBSS) {/* adhoc master */ -+ val8 = 0xcf; -+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); -+ -+ /* switch channel */ -+ /* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ -+ beacon_timing_control(padapter); -+ -+ /* set msr to WIFI_FW_ADHOC_STATE */ -+ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; -+ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); -+ -+ /* issue beacon */ -+ if (send_beacon(padapter) == _FAIL) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n")); -+ -+ report_join_res(padapter, -1); -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ } else { -+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); -+ join_type = 0; -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); -+ -+ report_join_res(padapter, 1); -+ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; -+ rtw_indicate_connect(padapter); -+ } -+ } else { -+ DBG_88E("start_create_ibss, invalid cap:%x\n", caps); -+ return; -+ } -+ /* update bc/mc sta_info */ -+ update_bmc_sta(padapter); -+} -+ -+void start_clnt_join(struct adapter *padapter) -+{ -+ unsigned short caps; -+ u8 val8; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); -+ int beacon_timeout; -+ -+ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; -+ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); -+ -+ /* update wireless mode */ -+ update_wireless_mode(padapter); -+ -+ /* udpate capability */ -+ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); -+ update_capinfo(padapter, caps); -+ if (caps&cap_ESS) { -+ Set_MSR(padapter, WIFI_FW_STATION_STATE); -+ -+ val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); -+ -+ /* switch channel */ -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); -+ -+ /* here wait for receiving the beacon to start auth */ -+ /* and enable a timer */ -+ beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval); -+ set_link_timer(pmlmeext, beacon_timeout); -+ _set_timer(&padapter->mlmepriv.assoc_timer, -+ (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout); -+ -+ pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; -+ } else if (caps&cap_IBSS) { /* adhoc client */ -+ Set_MSR(padapter, WIFI_FW_ADHOC_STATE); -+ -+ val8 = 0xcf; -+ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); -+ -+ /* switch channel */ -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); -+ -+ beacon_timing_control(padapter); -+ -+ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; -+ -+ report_join_res(padapter, 1); -+ } else { -+ return; -+ } -+} -+ -+void start_clnt_auth(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ -+ pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); -+ pmlmeinfo->state |= WIFI_FW_AUTH_STATE; -+ -+ pmlmeinfo->auth_seq = 1; -+ pmlmeinfo->reauth_count = 0; -+ pmlmeinfo->reassoc_count = 0; -+ pmlmeinfo->link_count = 0; -+ pmlmeext->retry = 0; -+ -+ /* Because of AP's not receiving deauth before */ -+ /* AP may: 1)not response auth or 2)deauth us after link is complete */ -+ /* issue deauth before issuing auth to deal with the situation */ -+ /* Commented by Albert 2012/07/21 */ -+ /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ -+ issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING); -+ -+ DBG_88E_LEVEL(_drv_info_, "start auth\n"); -+ issue_auth(padapter, NULL, 0); -+ -+ set_link_timer(pmlmeext, REAUTH_TO); -+} -+ -+void start_clnt_assoc(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ -+ pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); -+ pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); -+ -+ issue_assocreq(padapter); -+ -+ set_link_timer(pmlmeext, REASSOC_TO); -+} -+ -+unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ /* check A3 */ -+ if (!(!memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) -+ return _SUCCESS; -+ -+ DBG_88E("%s\n", __func__); -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { -+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ report_del_sta_event(padapter, MacAddr, reason); -+ } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) { -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ report_join_res(padapter, -2); -+ } -+ } -+ return _SUCCESS; -+} -+ -+static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid) -+{ -+ struct registry_priv *pregistrypriv; -+ struct mlme_ext_priv *pmlmeext; -+ struct rt_channel_info *chplan_new; -+ u8 channel; -+ u8 i; -+ -+ pregistrypriv = &padapter->registrypriv; -+ pmlmeext = &padapter->mlmeextpriv; -+ -+ /* Adjust channel plan by AP Country IE */ -+ if (pregistrypriv->enable80211d && -+ (!pmlmeext->update_channel_plan_by_ap_done)) { -+ u8 *ie, *p; -+ u32 len; -+ struct rt_channel_plan chplan_ap; -+ struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; -+ u8 country[4]; -+ u8 fcn; /* first channel number */ -+ u8 noc; /* number of channel */ -+ u8 j, k; -+ -+ ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); -+ if (!ie) -+ return; -+ if (len < 6) -+ return; -+ ie += 2; -+ p = ie; -+ ie += len; -+ -+ memset(country, 0, 4); -+ memcpy(country, p, 3); -+ p += 3; -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, -+ ("%s: 802.11d country =%s\n", __func__, country)); -+ -+ i = 0; -+ while ((ie - p) >= 3) { -+ fcn = *(p++); -+ noc = *(p++); -+ p++; -+ -+ for (j = 0; j < noc; j++) { -+ if (fcn <= 14) -+ channel = fcn + j; /* 2.4 GHz */ -+ else -+ channel = fcn + j*4; /* 5 GHz */ -+ -+ chplan_ap.Channel[i++] = channel; -+ } -+ } -+ chplan_ap.Len = i; -+ -+ memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); -+ -+ memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); -+ chplan_new = pmlmeext->channel_set; -+ -+ i = 0; -+ j = 0; -+ k = 0; -+ if (pregistrypriv->wireless_mode & WIRELESS_11G) { -+ do { -+ if ((i == MAX_CHANNEL_NUM) || -+ (chplan_sta[i].ChannelNum == 0) || -+ (chplan_sta[i].ChannelNum > 14)) -+ break; -+ -+ if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) -+ break; -+ -+ if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { -+ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; -+ chplan_new[k].ScanType = SCAN_ACTIVE; -+ i++; -+ j++; -+ k++; -+ } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { -+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; -+ chplan_new[k].ScanType = SCAN_PASSIVE; -+ i++; -+ k++; -+ } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { -+ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; -+ chplan_new[k].ScanType = SCAN_ACTIVE; -+ j++; -+ k++; -+ } -+ } while (1); -+ -+ /* change AP not support channel to Passive scan */ -+ while ((i < MAX_CHANNEL_NUM) && -+ (chplan_sta[i].ChannelNum != 0) && -+ (chplan_sta[i].ChannelNum <= 14)) { -+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; -+ chplan_new[k].ScanType = SCAN_PASSIVE; -+ i++; -+ k++; -+ } -+ -+ /* add channel AP supported */ -+ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { -+ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; -+ chplan_new[k].ScanType = SCAN_ACTIVE; -+ j++; -+ k++; -+ } -+ } else { -+ /* keep original STA 2.4G channel plan */ -+ while ((i < MAX_CHANNEL_NUM) && -+ (chplan_sta[i].ChannelNum != 0) && -+ (chplan_sta[i].ChannelNum <= 14)) { -+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; -+ chplan_new[k].ScanType = chplan_sta[i].ScanType; -+ i++; -+ k++; -+ } -+ -+ /* skip AP 2.4G channel plan */ -+ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) -+ j++; -+ } -+ -+ /* keep original STA 5G channel plan */ -+ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { -+ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; -+ chplan_new[k].ScanType = chplan_sta[i].ScanType; -+ i++; -+ k++; -+ } -+ -+ pmlmeext->update_channel_plan_by_ap_done = 1; -+ } -+ -+ /* If channel is used by AP, set channel scan type to active */ -+ channel = bssid->Configuration.DSConfig; -+ chplan_new = pmlmeext->channel_set; -+ i = 0; -+ while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { -+ if (chplan_new[i].ChannelNum == channel) { -+ if (chplan_new[i].ScanType == SCAN_PASSIVE) { -+ chplan_new[i].ScanType = SCAN_ACTIVE; -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, -+ ("%s: change channel %d scan type from passive to active\n", -+ __func__, channel)); -+ } -+ break; -+ } -+ i++; -+ } -+} -+ -+/**************************************************************************** -+ -+Following are the functions to report events -+ -+*****************************************************************************/ -+ -+void report_survey_event(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ struct cmd_obj *pcmd_obj; -+ u8 *pevtcmd; -+ u32 cmdsz; -+ struct survey_event *psurvey_evt; -+ struct C2HEvent_Header *pc2h_evt_hdr; -+ struct mlme_ext_priv *pmlmeext; -+ struct cmd_priv *pcmdpriv; -+ /* u8 *pframe = precv_frame->rx_data; */ -+ /* uint len = precv_frame->len; */ -+ -+ if (!padapter) -+ return; -+ -+ pmlmeext = &padapter->mlmeextpriv; -+ pcmdpriv = &padapter->cmdpriv; -+ -+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (pcmd_obj == NULL) -+ return; -+ -+ cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); -+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz); -+ if (pevtcmd == NULL) { -+ kfree(pcmd_obj); -+ return; -+ } -+ -+ INIT_LIST_HEAD(&pcmd_obj->list); -+ -+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); -+ pcmd_obj->cmdsz = cmdsz; -+ pcmd_obj->parmbuf = pevtcmd; -+ -+ pcmd_obj->rsp = NULL; -+ pcmd_obj->rspsz = 0; -+ -+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); -+ pc2h_evt_hdr->len = sizeof(struct survey_event); -+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); -+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); -+ -+ psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); -+ -+ if (collect_bss_info(padapter, precv_frame, (struct wlan_bssid_ex *)&psurvey_evt->bss) == _FAIL) { -+ kfree(pcmd_obj); -+ kfree(pevtcmd); -+ return; -+ } -+ -+ process_80211d(padapter, &psurvey_evt->bss); -+ -+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); -+ -+ pmlmeext->sitesurvey_res.bss_cnt++; -+ -+ return; -+} -+ -+void report_surveydone_event(struct adapter *padapter) -+{ -+ struct cmd_obj *pcmd_obj; -+ u8 *pevtcmd; -+ u32 cmdsz; -+ struct surveydone_event *psurveydone_evt; -+ struct C2HEvent_Header *pc2h_evt_hdr; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (pcmd_obj == NULL) -+ return; -+ -+ cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header)); -+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz); -+ if (pevtcmd == NULL) { -+ kfree(pcmd_obj); -+ return; -+ } -+ -+ INIT_LIST_HEAD(&pcmd_obj->list); -+ -+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); -+ pcmd_obj->cmdsz = cmdsz; -+ pcmd_obj->parmbuf = pevtcmd; -+ -+ pcmd_obj->rsp = NULL; -+ pcmd_obj->rspsz = 0; -+ -+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); -+ pc2h_evt_hdr->len = sizeof(struct surveydone_event); -+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); -+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); -+ -+ psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); -+ psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; -+ -+ DBG_88E("survey done event(%x)\n", psurveydone_evt->bss_cnt); -+ -+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); -+ -+ return; -+} -+ -+void report_join_res(struct adapter *padapter, int res) -+{ -+ struct cmd_obj *pcmd_obj; -+ u8 *pevtcmd; -+ u32 cmdsz; -+ struct joinbss_event *pjoinbss_evt; -+ struct C2HEvent_Header *pc2h_evt_hdr; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (pcmd_obj == NULL) -+ return; -+ -+ cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); -+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz); -+ if (pevtcmd == NULL) { -+ kfree(pcmd_obj); -+ return; -+ } -+ -+ INIT_LIST_HEAD(&pcmd_obj->list); -+ -+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); -+ pcmd_obj->cmdsz = cmdsz; -+ pcmd_obj->parmbuf = pevtcmd; -+ -+ pcmd_obj->rsp = NULL; -+ pcmd_obj->rspsz = 0; -+ -+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); -+ pc2h_evt_hdr->len = sizeof(struct joinbss_event); -+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); -+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); -+ -+ pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); -+ memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); -+ pjoinbss_evt->network.join_res = res; -+ pjoinbss_evt->network.aid = res; -+ -+ DBG_88E("report_join_res(%d)\n", res); -+ -+ rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network); -+ -+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); -+ -+ return; -+} -+ -+void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) -+{ -+ struct cmd_obj *pcmd_obj; -+ u8 *pevtcmd; -+ u32 cmdsz; -+ struct sta_info *psta; -+ int mac_id; -+ struct stadel_event *pdel_sta_evt; -+ struct C2HEvent_Header *pc2h_evt_hdr; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (pcmd_obj == NULL) -+ return; -+ -+ cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); -+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz); -+ if (pevtcmd == NULL) { -+ kfree(pcmd_obj); -+ return; -+ } -+ -+ INIT_LIST_HEAD(&pcmd_obj->list); -+ -+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); -+ pcmd_obj->cmdsz = cmdsz; -+ pcmd_obj->parmbuf = pevtcmd; -+ -+ pcmd_obj->rsp = NULL; -+ pcmd_obj->rspsz = 0; -+ -+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); -+ pc2h_evt_hdr->len = sizeof(struct stadel_event); -+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); -+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); -+ -+ pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); -+ memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); -+ memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2); -+ -+ psta = rtw_get_stainfo(&padapter->stapriv, MacAddr); -+ if (psta) -+ mac_id = (int)psta->mac_id; -+ else -+ mac_id = (-1); -+ -+ pdel_sta_evt->mac_id = mac_id; -+ -+ DBG_88E("report_del_sta_event: delete STA, mac_id =%d\n", mac_id); -+ -+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); -+ -+ return; -+} -+ -+void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int cam_idx) -+{ -+ struct cmd_obj *pcmd_obj; -+ u8 *pevtcmd; -+ u32 cmdsz; -+ struct stassoc_event *padd_sta_evt; -+ struct C2HEvent_Header *pc2h_evt_hdr; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ -+ pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (pcmd_obj == NULL) -+ return; -+ -+ cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); -+ pevtcmd = (u8 *)rtw_zmalloc(cmdsz); -+ if (pevtcmd == NULL) { -+ kfree(pcmd_obj); -+ return; -+ } -+ -+ INIT_LIST_HEAD(&pcmd_obj->list); -+ -+ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); -+ pcmd_obj->cmdsz = cmdsz; -+ pcmd_obj->parmbuf = pevtcmd; -+ -+ pcmd_obj->rsp = NULL; -+ pcmd_obj->rspsz = 0; -+ -+ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); -+ pc2h_evt_hdr->len = sizeof(struct stassoc_event); -+ pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); -+ pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); -+ -+ padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); -+ memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); -+ padd_sta_evt->cam_id = cam_idx; -+ -+ DBG_88E("report_add_sta_event: add STA\n"); -+ -+ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); -+ -+ return; -+} -+ -+/**************************************************************************** -+ -+Following are the event callback functions -+ -+*****************************************************************************/ -+ -+/* for sta/adhoc mode */ -+void update_sta_info(struct adapter *padapter, struct sta_info *psta) -+{ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ /* ERP */ -+ VCS_update(padapter, psta); -+ -+ /* HT */ -+ if (pmlmepriv->htpriv.ht_option) { -+ psta->htpriv.ht_option = true; -+ -+ psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable; -+ -+ if (support_short_GI(padapter, &(pmlmeinfo->HT_caps))) -+ psta->htpriv.sgi = true; -+ -+ psta->qos_option = true; -+ } else { -+ psta->htpriv.ht_option = false; -+ -+ psta->htpriv.ampdu_enable = false; -+ -+ psta->htpriv.sgi = false; -+ psta->qos_option = false; -+ } -+ psta->htpriv.bwmode = pmlmeext->cur_bwmode; -+ psta->htpriv.ch_offset = pmlmeext->cur_ch_offset; -+ -+ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ -+ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ -+ -+ /* QoS */ -+ if (pmlmepriv->qospriv.qos_option) -+ psta->qos_option = true; -+ -+ psta->state = _FW_LINKED; -+} -+ -+void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) -+{ -+ struct sta_info *psta, *psta_bmc; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 join_type; -+ u16 media_status; -+ -+ if (join_res < 0) { -+ join_type = 1; -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); -+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); -+ -+ /* restore to initial setting. */ -+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); -+ -+ goto exit_mlmeext_joinbss_event_callback; -+ } -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { -+ /* for bc/mc */ -+ psta_bmc = rtw_get_bcmc_stainfo(padapter); -+ if (psta_bmc) { -+ pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc; -+ update_bmc_sta_support_rate(padapter, psta_bmc->mac_id); -+ Update_RA_Entry(padapter, psta_bmc->mac_id); -+ } -+ } -+ -+ /* turn on dynamic functions */ -+ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); -+ -+ /* update IOT-releated issue */ -+ update_IOT_info(padapter); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); -+ -+ /* BCN interval */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); -+ -+ /* udpate capability */ -+ update_capinfo(padapter, pmlmeinfo->capability); -+ -+ /* WMM, Update EDCA param */ -+ WMMOnAssocRsp(padapter); -+ -+ /* HT */ -+ HTOnAssocRsp(padapter); -+ -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); -+ -+ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); -+ if (psta) { /* only for infra. mode */ -+ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; -+ -+ psta->wireless_mode = pmlmeext->cur_wireless_mode; -+ -+ /* set per sta rate after updating HT cap. */ -+ set_sta_rate(padapter, psta); -+ rtw_hal_set_hwreg(padapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&psta->mac_id); -+ media_status = (psta->mac_id<<8)|1; /* MACID|OPMODE: 1 means connect */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); -+ } -+ -+ join_type = 2; -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { -+ /* correcting TSF */ -+ correct_TSF(padapter, pmlmeext); -+ } -+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); -+ -+exit_mlmeext_joinbss_event_callback: -+ -+ DBG_88E("=>%s\n", __func__); -+} -+ -+void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *psta) -+{ -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 join_type; -+ -+ DBG_88E("%s\n", __func__); -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { -+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {/* adhoc master or sta_count>1 */ -+ /* nothing to do */ -+ } else { /* adhoc client */ -+ /* correcting TSF */ -+ correct_TSF(padapter, pmlmeext); -+ -+ /* start beacon */ -+ if (send_beacon(padapter) == _FAIL) { -+ pmlmeinfo->FW_sta_info[psta->mac_id].status = 0; -+ pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE; -+ return; -+ } -+ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; -+ } -+ -+ join_type = 2; -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); -+ } -+ -+ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; -+ -+ /* rate radaptive */ -+ Update_RA_Entry(padapter, psta->mac_id); -+ -+ /* update adhoc sta_info */ -+ update_sta_info(padapter, psta); -+} -+ -+void mlmeext_sta_del_event_callback(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) { -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); -+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); -+ -+ /* restore to initial setting. */ -+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); -+ -+ /* switch to the 20M Hz mode after disconnect */ -+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ -+ /* SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */ -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); -+ -+ flush_all_cam_entry(padapter); -+ -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ -+ /* set MSR to no link state -> infra. mode */ -+ Set_MSR(padapter, _HW_STATE_STATION_); -+ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ } -+} -+ -+/**************************************************************************** -+ -+Following are the functions for the timer handlers -+ -+*****************************************************************************/ -+void _linked_rx_signal_strehgth_display(struct adapter *padapter); -+void _linked_rx_signal_strehgth_display(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 mac_id; -+ int UndecoratedSmoothedPWDB; -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) -+ mac_id = 0; -+ else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_) -+ mac_id = 2; -+ -+ rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, &mac_id); -+ -+ rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); -+ DBG_88E("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB); -+} -+ -+static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta) -+{ -+ u8 ret = false; -+ -+ if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) && -+ sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) && -+ sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta)) -+ ret = false; -+ else -+ ret = true; -+ -+ sta_update_last_rx_pkts(psta); -+ -+ return ret; -+} -+ -+void linked_status_chk(struct adapter *padapter) -+{ -+ u32 i; -+ struct sta_info *psta; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ if (padapter->bRxRSSIDisplay) -+ _linked_rx_signal_strehgth_display(padapter); -+ -+ rtw_hal_sreset_linked_status_check(padapter); -+ -+ if (is_client_associated_to_ap(padapter)) { -+ /* linked infrastructure client mode */ -+ -+ int tx_chk = _SUCCESS, rx_chk = _SUCCESS; -+ int rx_chk_limit; -+ -+ rx_chk_limit = 4; -+ psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); -+ if (psta != NULL) { -+ bool is_p2p_enable = false; -+ #ifdef CONFIG_88EU_P2P -+ is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE); -+ #endif -+ -+ if (!chk_ap_is_alive(padapter, psta)) -+ rx_chk = _FAIL; -+ -+ if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts) -+ tx_chk = _FAIL; -+ -+ if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)) { -+ u8 backup_oper_channel = 0; -+ -+ /* switch to correct channel of current network before issue keep-alive frames */ -+ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { -+ backup_oper_channel = rtw_get_oper_ch(padapter); -+ SelectChannel(padapter, pmlmeext->cur_channel); -+ } -+ -+ if (rx_chk != _SUCCESS) -+ issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1); -+ -+ if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) { -+ tx_chk = issue_nulldata(padapter, psta->hwaddr, 0, 3, 1); -+ /* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */ -+ if (tx_chk == _SUCCESS && !is_p2p_enable) -+ rx_chk = _SUCCESS; -+ } -+ -+ /* back to the original operation channel */ -+ if (backup_oper_channel > 0) -+ SelectChannel(padapter, backup_oper_channel); -+ } else { -+ if (rx_chk != _SUCCESS) { -+ if (pmlmeext->retry == 0) { -+ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); -+ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); -+ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); -+ } -+ } -+ -+ if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) { -+ tx_chk = issue_nulldata(padapter, NULL, 0, 1, 0); -+ } -+ } -+ -+ if (rx_chk == _FAIL) { -+ pmlmeext->retry++; -+ if (pmlmeext->retry > rx_chk_limit) { -+ DBG_88E_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n", -+ FUNC_ADPT_ARG(padapter)); -+ receive_disconnect(padapter, pmlmeinfo->network.MacAddress, -+ WLAN_REASON_EXPIRATION_CHK); -+ return; -+ } -+ } else { -+ pmlmeext->retry = 0; -+ } -+ -+ if (tx_chk == _FAIL) { -+ pmlmeinfo->link_count &= 0xf; -+ } else { -+ pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts; -+ pmlmeinfo->link_count = 0; -+ } -+ } /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) */ -+ } else if (is_client_associated_to_ibss(padapter)) { -+ /* linked IBSS mode */ -+ /* for each assoc list entry to check the rx pkt counter */ -+ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) { -+ if (pmlmeinfo->FW_sta_info[i].status == 1) { -+ psta = pmlmeinfo->FW_sta_info[i].psta; -+ -+ if (NULL == psta) -+ continue; -+ if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) { -+ if (pmlmeinfo->FW_sta_info[i].retry < 3) { -+ pmlmeinfo->FW_sta_info[i].retry++; -+ } else { -+ pmlmeinfo->FW_sta_info[i].retry = 0; -+ pmlmeinfo->FW_sta_info[i].status = 0; -+ report_del_sta_event(padapter, psta->hwaddr -+ , 65535/* indicate disconnect caused by no rx */ -+ ); -+ } -+ } else { -+ pmlmeinfo->FW_sta_info[i].retry = 0; -+ pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta); -+ } -+ } -+ } -+ } -+} -+ -+void survey_timer_hdl(struct adapter *padapter) -+{ -+ struct cmd_obj *ph2c; -+ struct sitesurvey_parm *psurveyPara; -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif -+ -+ /* issue rtw_sitesurvey_cmd */ -+ if (pmlmeext->sitesurvey_res.state > SCAN_START) { -+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) -+ pmlmeext->sitesurvey_res.channel_idx++; -+ -+ if (pmlmeext->scan_abort) { -+ #ifdef CONFIG_88EU_P2P -+ if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) { -+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); -+ pmlmeext->sitesurvey_res.channel_idx = 3; -+ DBG_88E("%s idx:%d, cnt:%u\n", __func__ -+ , pmlmeext->sitesurvey_res.channel_idx -+ , pwdinfo->find_phase_state_exchange_cnt -+ ); -+ } else -+ #endif -+ { -+ pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; -+ DBG_88E("%s idx:%d\n", __func__ -+ , pmlmeext->sitesurvey_res.channel_idx -+ ); -+ } -+ -+ pmlmeext->scan_abort = false;/* reset */ -+ } -+ -+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (ph2c == NULL) -+ goto exit_survey_timer_hdl; -+ -+ psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm)); -+ if (psurveyPara == NULL) { -+ kfree(ph2c); -+ goto exit_survey_timer_hdl; -+ } -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); -+ rtw_enqueue_cmd(pcmdpriv, ph2c); -+ } -+ -+exit_survey_timer_hdl: -+ return; -+} -+ -+void link_timer_hdl(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { -+ DBG_88E("link_timer_hdl:no beacon while connecting\n"); -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ report_join_res(padapter, -3); -+ } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) { -+ /* re-auth timer */ -+ if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) { -+ pmlmeinfo->state = 0; -+ report_join_res(padapter, -1); -+ return; -+ } -+ -+ DBG_88E("link_timer_hdl: auth timeout and try again\n"); -+ pmlmeinfo->auth_seq = 1; -+ issue_auth(padapter, NULL, 0); -+ set_link_timer(pmlmeext, REAUTH_TO); -+ } else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) { -+ /* re-assoc timer */ -+ if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) { -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ report_join_res(padapter, -2); -+ return; -+ } -+ -+ DBG_88E("link_timer_hdl: assoc timeout and try again\n"); -+ issue_assocreq(padapter); -+ set_link_timer(pmlmeext, REASSOC_TO); -+ } -+ return; -+} -+ -+void addba_timer_hdl(struct sta_info *psta) -+{ -+ struct ht_priv *phtpriv; -+ -+ if (!psta) -+ return; -+ -+ phtpriv = &psta->htpriv; -+ -+ if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) { -+ if (phtpriv->candidate_tid_bitmap) -+ phtpriv->candidate_tid_bitmap = 0x0; -+ } -+} -+ -+u8 NULL_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ return H2C_SUCCESS; -+} -+ -+u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ u8 type; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; -+ -+ if (psetop->mode == Ndis802_11APMode) { -+ pmlmeinfo->state = WIFI_FW_AP_STATE; -+ type = _HW_STATE_AP_; -+ } else if (psetop->mode == Ndis802_11Infrastructure) { -+ pmlmeinfo->state &= ~(BIT(0)|BIT(1));/* clear state */ -+ pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */ -+ type = _HW_STATE_STATION_; -+ } else if (psetop->mode == Ndis802_11IBSS) { -+ type = _HW_STATE_ADHOC_; -+ } else { -+ type = _HW_STATE_NOLINK_; -+ } -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); -+ /* Set_NETYPE0_MSR(padapter, type); */ -+ -+ return H2C_SUCCESS; -+} -+ -+u8 createbss_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); -+ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; -+ /* u32 initialgain; */ -+ -+ if (pparm->network.InfrastructureMode == Ndis802_11APMode) { -+#ifdef CONFIG_88EU_AP_MODE -+ -+ if (pmlmeinfo->state == WIFI_FW_AP_STATE) { -+ /* todo: */ -+ return H2C_SUCCESS; -+ } -+#endif -+ } -+ -+ /* below is for ad-hoc master */ -+ if (pparm->network.InfrastructureMode == Ndis802_11IBSS) { -+ rtw_joinbss_reset(padapter); -+ -+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ pmlmeinfo->ERP_enable = 0; -+ pmlmeinfo->WMM_enable = 0; -+ pmlmeinfo->HT_enable = 0; -+ pmlmeinfo->HT_caps_enable = 0; -+ pmlmeinfo->HT_info_enable = 0; -+ pmlmeinfo->agg_enable_bitmap = 0; -+ pmlmeinfo->candidate_tid_bitmap = 0; -+ -+ /* disable dynamic functions, such as high power, DIG */ -+ Save_DM_Func_Flag(padapter); -+ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); -+ -+ /* config the initial gain under linking, need to write the BB registers */ -+ /* initialgain = 0x1E; */ -+ /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ -+ -+ /* cancel link timer */ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ -+ /* clear CAM */ -+ flush_all_cam_entry(padapter); -+ -+ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); -+ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; -+ -+ if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ -+ return H2C_PARAMETERS_ERROR; -+ -+ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength); -+ -+ start_create_ibss(padapter); -+ } -+ -+ return H2C_SUCCESS; -+} -+ -+u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ u8 join_type; -+ struct ndis_802_11_var_ie *pIE; -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); -+ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; -+ u32 i; -+ -+ /* check already connecting to AP or not */ -+ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { -+ if (pmlmeinfo->state & WIFI_FW_STATION_STATE) -+ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 5, 100); -+ -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ -+ /* clear CAM */ -+ flush_all_cam_entry(padapter); -+ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ -+ /* set MSR to nolink -> infra. mode */ -+ Set_MSR(padapter, _HW_STATE_STATION_); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); -+ } -+ -+ rtw_antenna_select_cmd(padapter, pparm->network.PhyInfo.Optimum_antenna, false); -+ -+ rtw_joinbss_reset(padapter); -+ -+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ pmlmeinfo->ERP_enable = 0; -+ pmlmeinfo->WMM_enable = 0; -+ pmlmeinfo->HT_enable = 0; -+ pmlmeinfo->HT_caps_enable = 0; -+ pmlmeinfo->HT_info_enable = 0; -+ pmlmeinfo->agg_enable_bitmap = 0; -+ pmlmeinfo->candidate_tid_bitmap = 0; -+ pmlmeinfo->bwmode_updated = false; -+ -+ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); -+ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; -+ -+ if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ -+ return H2C_PARAMETERS_ERROR; -+ -+ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength); -+ -+ /* Check AP vendor to move rtw_joinbss_cmd() */ -+ -+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) { -+ pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i); -+ -+ switch (pIE->ElementID) { -+ case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */ -+ if (!memcmp(pIE->data, WMM_OUI, 4)) -+ pmlmeinfo->WMM_enable = 1; -+ break; -+ case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */ -+ pmlmeinfo->HT_caps_enable = 1; -+ break; -+ case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */ -+ pmlmeinfo->HT_info_enable = 1; -+ -+ /* spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz */ -+ { -+ struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data); -+ -+ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) { -+ /* switch to the 40M Hz mode according to the AP */ -+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; -+ switch (pht_info->infos[0] & 0x3) { -+ case 1: -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; -+ break; -+ case 3: -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; -+ break; -+ default: -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ break; -+ } -+ -+ DBG_88E("set ch/bw before connected\n"); -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ -+ i += (pIE->Length + 2); -+ } -+ /* disable dynamic functions, such as high power, DIG */ -+ -+ /* config the initial gain under linking, need to write the BB registers */ -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); -+ join_type = 0; -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); -+ -+ /* cancel link timer */ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ -+ start_clnt_join(padapter); -+ -+ return H2C_SUCCESS; -+} -+ -+u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ struct disconnect_parm *param = (struct disconnect_parm *)pbuf; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network)); -+ u8 val8; -+ -+ if (is_client_associated_to_ap(padapter)) -+ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms/100, 100); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); -+ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); -+ -+ /* restore to initial setting. */ -+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); -+ -+ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) { -+ /* Stop BCN */ -+ val8 = 0; -+ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8)); -+ } -+ -+ /* set MSR to no link state -> infra. mode */ -+ Set_MSR(padapter, _HW_STATE_STATION_); -+ -+ pmlmeinfo->state = WIFI_FW_NULL_STATE; -+ -+ /* switch to the 20M Hz mode after disconnect */ -+ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; -+ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ -+ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); -+ -+ flush_all_cam_entry(padapter); -+ -+ _cancel_timer_ex(&pmlmeext->link_timer); -+ -+ rtw_free_uc_swdec_pending_queue(padapter); -+ -+ return H2C_SUCCESS; -+} -+ -+static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_channel *out, -+ u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) -+{ -+ int i, j; -+ int set_idx; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ -+ /* clear out first */ -+ memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num); -+ -+ /* acquire channels from in */ -+ j = 0; -+ for (i = 0; i < in_num; i++) { -+ set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value); -+ if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED) && -+ set_idx >= 0) { -+ memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel)); -+ -+ if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE) -+ out[j].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN; -+ -+ j++; -+ } -+ if (j >= out_num) -+ break; -+ } -+ -+ /* if out is empty, use channel_set as default */ -+ if (j == 0) { -+ for (i = 0; i < pmlmeext->max_chan_nums; i++) { -+ out[i].hw_value = pmlmeext->channel_set[i].ChannelNum; -+ -+ if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE) -+ out[i].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN; -+ -+ j++; -+ } -+ } -+ -+ return j; -+} -+ -+u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; -+ u8 bdelayscan = false; -+ u8 val8; -+ u32 initialgain; -+ u32 i; -+ -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+#endif -+ -+ if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) { -+ /* for first time sitesurvey_cmd */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, NULL); -+ -+ pmlmeext->sitesurvey_res.state = SCAN_START; -+ pmlmeext->sitesurvey_res.bss_cnt = 0; -+ pmlmeext->sitesurvey_res.channel_idx = 0; -+ -+ for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { -+ if (pparm->ssid[i].SsidLength) { -+ memcpy(pmlmeext->sitesurvey_res.ssid[i].Ssid, pparm->ssid[i].Ssid, IW_ESSID_MAX_SIZE); -+ pmlmeext->sitesurvey_res.ssid[i].SsidLength = pparm->ssid[i].SsidLength; -+ } else { -+ pmlmeext->sitesurvey_res.ssid[i].SsidLength = 0; -+ } -+ } -+ -+ pmlmeext->sitesurvey_res.ch_num = rtw_scan_ch_decision(padapter -+ , pmlmeext->sitesurvey_res.ch, RTW_CHANNEL_SCAN_AMOUNT -+ , pparm->ch, pparm->ch_num -+ ); -+ -+ pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode; -+ -+ /* issue null data if associating to the AP */ -+ if (is_client_associated_to_ap(padapter)) { -+ pmlmeext->sitesurvey_res.state = SCAN_TXNULL; -+ -+ issue_nulldata(padapter, NULL, 1, 3, 500); -+ -+ bdelayscan = true; -+ } -+ if (bdelayscan) { -+ /* delay 50ms to protect nulldata(1). */ -+ set_survey_timer(pmlmeext, 50); -+ return H2C_SUCCESS; -+ } -+ } -+ -+ if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) { -+ /* disable dynamic functions, such as high power, DIG */ -+ Save_DM_Func_Flag(padapter); -+ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); -+ -+ /* config the initial gain under scanning, need to write the BB registers */ -+#ifdef CONFIG_88EU_P2P -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ initialgain = 0x1E; -+ else -+ initialgain = 0x28; -+#else /* CONFIG_88EU_P2P */ -+ initialgain = 0x1E; -+#endif /* CONFIG_88EU_P2P */ -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); -+ -+ /* set MSR to no link state */ -+ Set_MSR(padapter, _HW_STATE_NOLINK_); -+ -+ val8 = 1; /* under site survey */ -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); -+ -+ pmlmeext->sitesurvey_res.state = SCAN_PROCESS; -+ } -+ -+ site_survey(padapter); -+ -+ return H2C_SUCCESS; -+} -+ -+u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ struct setauth_parm *pparm = (struct setauth_parm *)pbuf; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pparm->mode < 4) -+ pmlmeinfo->auth_algo = pparm->mode; -+ return H2C_SUCCESS; -+} -+ -+u8 setkey_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ unsigned short ctrl; -+ struct setkey_parm *pparm = (struct setkey_parm *)pbuf; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -+ -+ /* main tx key for wep. */ -+ if (pparm->set_tx) -+ pmlmeinfo->key_index = pparm->keyid; -+ -+ /* write cam */ -+ ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; -+ -+ DBG_88E_LEVEL(_drv_info_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) " -+ "keyid:%d\n", pparm->algorithm, pparm->keyid); -+ write_cam(padapter, pparm->keyid, ctrl, null_sta, pparm->key); -+ -+ return H2C_SUCCESS; -+} -+ -+u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ u16 ctrl = 0; -+ u8 cam_id;/* cam_entry */ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; -+ -+ /* cam_entry: */ -+ /* 0~3 for default key */ -+ -+ /* for concurrent mode (ap+sta): */ -+ /* default key is disable, using sw encrypt/decrypt */ -+ /* cam_entry = 4 for sta mode (macid = 0) */ -+ /* cam_entry(macid+3) = 5 ~ N for ap mode (aid = 1~N, macid = 2 ~N) */ -+ -+ /* for concurrent mode (sta+sta): */ -+ /* default key is disable, using sw encrypt/decrypt */ -+ /* cam_entry = 4 mapping to macid = 0 */ -+ /* cam_entry = 5 mapping to macid = 2 */ -+ -+ cam_id = 4; -+ -+ DBG_88E_LEVEL(_drv_info_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n", -+ pparm->algorithm, cam_id); -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { -+ struct sta_info *psta; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ if (pparm->algorithm == _NO_PRIVACY_) /* clear cam entry */ { -+ clear_cam_entry(padapter, pparm->id); -+ return H2C_SUCCESS_RSP; -+ } -+ -+ psta = rtw_get_stainfo(pstapriv, pparm->addr); -+ if (psta) { -+ ctrl = (BIT(15) | ((pparm->algorithm) << 2)); -+ -+ DBG_88E("r871x_set_stakey_hdl(): enc_algorithm=%d\n", pparm->algorithm); -+ -+ if ((psta->mac_id < 1) || (psta->mac_id > (NUM_STA-4))) { -+ DBG_88E("r871x_set_stakey_hdl():set_stakey failed, mac_id(aid)=%d\n", psta->mac_id); -+ return H2C_REJECTED; -+ } -+ -+ cam_id = (psta->mac_id + 3);/* 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */ -+ -+ DBG_88E("Write CAM, mac_addr =%x:%x:%x:%x:%x:%x, cam_entry=%d\n", pparm->addr[0], -+ pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4], -+ pparm->addr[5], cam_id); -+ -+ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); -+ -+ return H2C_SUCCESS_RSP; -+ } else { -+ DBG_88E("r871x_set_stakey_hdl(): sta has been free\n"); -+ return H2C_REJECTED; -+ } -+ } -+ -+ /* below for sta mode */ -+ -+ if (pparm->algorithm == _NO_PRIVACY_) { /* clear cam entry */ -+ clear_cam_entry(padapter, pparm->id); -+ return H2C_SUCCESS; -+ } -+ ctrl = BIT(15) | ((pparm->algorithm) << 2); -+ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); -+ pmlmeinfo->enc_algo = pparm->algorithm; -+ return H2C_SUCCESS; -+} -+ -+u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr); -+ -+ if (!psta) -+ return H2C_SUCCESS; -+ -+ if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) || -+ ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) { -+ issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); -+ _set_timer(&psta->addba_retry_timer, ADDBA_TO); -+ } else { -+ psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid); -+ } -+ return H2C_SUCCESS; -+} -+ -+u8 set_tx_beacon_cmd(struct adapter *padapter) -+{ -+ struct cmd_obj *ph2c; -+ struct Tx_Beacon_param *ptxBeacon_parm; -+ struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u8 res = _SUCCESS; -+ int len_diff = 0; -+ -+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ ptxBeacon_parm = (struct Tx_Beacon_param *)rtw_zmalloc(sizeof(struct Tx_Beacon_param)); -+ if (ptxBeacon_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); -+ -+ len_diff = update_hidden_ssid(ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_, -+ ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_, -+ pmlmeinfo->hidden_ssid_mode); -+ ptxBeacon_parm->network.IELength += len_diff; -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ -+exit: -+ -+ return res; -+} -+ -+u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ u8 evt_code; -+ u16 evt_sz; -+ uint *peventbuf; -+ void (*event_callback)(struct adapter *dev, u8 *pbuf); -+ struct evt_priv *pevt_priv = &(padapter->evtpriv); -+ -+ peventbuf = (uint *)pbuf; -+ evt_sz = (u16)(*peventbuf&0xffff); -+ evt_code = (u8)((*peventbuf>>16)&0xff); -+ -+ /* checking if event code is valid */ -+ if (evt_code >= MAX_C2HEVT) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code)); -+ goto _abort_event_; -+ } -+ -+ /* checking if event size match the event parm size */ -+ if ((wlanevents[evt_code].parmsize != 0) && -+ (wlanevents[evt_code].parmsize != evt_sz)) { -+ RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, -+ ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n", -+ evt_code, wlanevents[evt_code].parmsize, evt_sz)); -+ goto _abort_event_; -+ } -+ -+ ATOMIC_INC(&pevt_priv->event_seq); -+ -+ peventbuf += 2; -+ -+ if (peventbuf) { -+ event_callback = wlanevents[evt_code].event_callback; -+ event_callback(padapter, (u8 *)peventbuf); -+ -+ pevt_priv->evt_done_cnt++; -+ } -+ -+_abort_event_: -+ return H2C_SUCCESS; -+} -+ -+u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ if (!pbuf) -+ return H2C_PARAMETERS_ERROR; -+ -+ return H2C_SUCCESS; -+} -+ -+u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ if (send_beacon(padapter) == _FAIL) { -+ DBG_88E("issue_beacon, fail!\n"); -+ return H2C_PARAMETERS_ERROR; -+ } -+#ifdef CONFIG_88EU_AP_MODE -+ else { /* tx bc/mc frames after update TIM */ -+ struct sta_info *psta_bmc; -+ struct list_head *xmitframe_plist, *xmitframe_phead; -+ struct xmit_frame *pxmitframe = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ /* for BC/MC Frames */ -+ psta_bmc = rtw_get_bcmc_stainfo(padapter); -+ if (!psta_bmc) -+ return H2C_SUCCESS; -+ -+ if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len > 0)) { -+ rtw_msleep_os(10);/* 10ms, ATIM(HIQ) Windows */ -+ spin_lock_bh(&psta_bmc->sleep_q.lock); -+ -+ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); -+ xmitframe_plist = xmitframe_phead->next; -+ -+ while (xmitframe_phead != xmitframe_plist) { -+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); -+ -+ xmitframe_plist = xmitframe_plist->next; -+ -+ list_del_init(&pxmitframe->list); -+ -+ psta_bmc->sleepq_len--; -+ if (psta_bmc->sleepq_len > 0) -+ pxmitframe->attrib.mdata = 1; -+ else -+ pxmitframe->attrib.mdata = 0; -+ -+ pxmitframe->attrib.triggered = 1; -+ -+ pxmitframe->attrib.qsel = 0x11;/* HIQ */ -+ -+ spin_unlock_bh(&psta_bmc->sleep_q.lock); -+ if (rtw_hal_xmit(padapter, pxmitframe)) -+ rtw_os_xmit_complete(padapter, pxmitframe); -+ spin_lock_bh(&psta_bmc->sleep_q.lock); -+ } -+ spin_unlock_bh(&psta_bmc->sleep_q.lock); -+ } -+ } -+#endif -+ return H2C_SUCCESS; -+} -+ -+u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf) -+{ -+ struct set_ch_parm *set_ch_parm; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ -+ if (!pbuf) -+ return H2C_PARAMETERS_ERROR; -+ -+ set_ch_parm = (struct set_ch_parm *)pbuf; -+ -+ DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", -+ FUNC_NDEV_ARG(padapter->pnetdev), -+ set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset); -+ -+ pmlmeext->cur_channel = set_ch_parm->ch; -+ pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; -+ pmlmeext->cur_bwmode = set_ch_parm->bw; -+ -+ set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw); -+ -+ return H2C_SUCCESS; -+} -+ -+u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ struct SetChannelPlan_param *setChannelPlan_param; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ -+ if (!pbuf) -+ return H2C_PARAMETERS_ERROR; -+ -+ setChannelPlan_param = (struct SetChannelPlan_param *)pbuf; -+ -+ pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set); -+ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); -+ -+ return H2C_SUCCESS; -+} -+ -+u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ if (!pbuf) -+ return H2C_PARAMETERS_ERROR; -+ return H2C_SUCCESS; -+} -+ -+u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ return H2C_REJECTED; -+} -+ -+/* TDLS_WRCR : write RCR DATA BIT */ -+/* TDLS_SD_PTI : issue peer traffic indication */ -+/* TDLS_CS_OFF : go back to the channel linked with AP, terminating channel switch procedure */ -+/* TDLS_INIT_CH_SEN : init channel sensing, receive all data and mgnt frame */ -+/* TDLS_DONE_CH_SEN: channel sensing and report candidate channel */ -+/* TDLS_OFF_CH : first time set channel to off channel */ -+/* TDLS_BASE_CH : go back tp the channel linked with AP when set base channel as target channel */ -+/* TDLS_P_OFF_CH : periodically go to off channel */ -+/* TDLS_P_BASE_CH : periodically go back to base channel */ -+/* TDLS_RS_RCR : restore RCR */ -+/* TDLS_CKALV_PH1 : check alive timer phase1 */ -+/* TDLS_CKALV_PH2 : check alive timer phase2 */ -+/* TDLS_FREE_STA : free tdls sta */ -+u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf) -+{ -+ return H2C_REJECTED; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_mp.c b/drivers/net/wireless/rtl8188eu/core/rtw_mp.c -new file mode 100644 -index 0000000000000..59c7af2c20a5b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_mp.c -@@ -0,0 +1,1001 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_MP_C_ -+ -+#include -+ -+#include "odm_precomp.h" -+#include "rtl8188e_hal.h" -+ -+u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz) -+{ -+ u32 val = 0; -+ -+ switch (sz) { -+ case 1: -+ val = rtw_read8(padapter, addr); -+ break; -+ case 2: -+ val = rtw_read16(padapter, addr); -+ break; -+ case 4: -+ val = rtw_read32(padapter, addr); -+ break; -+ default: -+ val = 0xffffffff; -+ break; -+ } -+ -+ return val; -+} -+ -+void write_macreg(struct adapter *padapter, u32 addr, u32 val, u32 sz) -+{ -+ switch (sz) { -+ case 1: -+ rtw_write8(padapter, addr, (u8)val); -+ break; -+ case 2: -+ rtw_write16(padapter, addr, (u16)val); -+ break; -+ case 4: -+ rtw_write32(padapter, addr, val); -+ break; -+ default: -+ break; -+ } -+} -+ -+u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask) -+{ -+ return rtw_hal_read_bbreg(padapter, addr, bitmask); -+} -+ -+void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val) -+{ -+ rtw_hal_write_bbreg(padapter, addr, bitmask, val); -+} -+ -+u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask) -+{ -+ return rtw_hal_read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask); -+} -+ -+void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val) -+{ -+ rtw_hal_write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask, val); -+} -+ -+u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr) -+{ -+ return _read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask); -+} -+ -+void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val) -+{ -+ _write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask, val); -+} -+ -+static void _init_mp_priv_(struct mp_priv *pmp_priv) -+{ -+ struct wlan_bssid_ex *pnetwork; -+ -+ memset(pmp_priv, 0, sizeof(struct mp_priv)); -+ -+ pmp_priv->mode = MP_OFF; -+ -+ pmp_priv->channel = 1; -+ pmp_priv->bandwidth = HT_CHANNEL_WIDTH_20; -+ pmp_priv->prime_channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ pmp_priv->rateidx = MPT_RATE_1M; -+ pmp_priv->txpoweridx = 0x2A; -+ -+ pmp_priv->antenna_tx = ANTENNA_A; -+ pmp_priv->antenna_rx = ANTENNA_AB; -+ -+ pmp_priv->check_mp_pkt = 0; -+ -+ pmp_priv->tx_pktcount = 0; -+ -+ pmp_priv->rx_pktcount = 0; -+ pmp_priv->rx_crcerrpktcount = 0; -+ -+ pmp_priv->network_macaddr[0] = 0x00; -+ pmp_priv->network_macaddr[1] = 0xE0; -+ pmp_priv->network_macaddr[2] = 0x4C; -+ pmp_priv->network_macaddr[3] = 0x87; -+ pmp_priv->network_macaddr[4] = 0x66; -+ pmp_priv->network_macaddr[5] = 0x55; -+ -+ pnetwork = &pmp_priv->mp_network.network; -+ memcpy(pnetwork->MacAddress, pmp_priv->network_macaddr, ETH_ALEN); -+ -+ pnetwork->Ssid.SsidLength = 8; -+ memcpy(pnetwork->Ssid.Ssid, "mp_871x", pnetwork->Ssid.SsidLength); -+} -+ -+static void mp_init_xmit_attrib(struct mp_tx *pmptx, struct adapter *padapter) -+{ -+ struct pkt_attrib *pattrib; -+ struct tx_desc *desc; -+ -+ /* init xmitframe attribute */ -+ pattrib = &pmptx->attrib; -+ memset(pattrib, 0, sizeof(struct pkt_attrib)); -+ desc = &pmptx->desc; -+ memset(desc, 0, TXDESC_SIZE); -+ -+ pattrib->ether_type = 0x8712; -+ memset(pattrib->dst, 0xFF, ETH_ALEN); -+ pattrib->ack_policy = 0; -+ pattrib->hdrlen = WLAN_HDR_A3_LEN; -+ pattrib->subtype = WIFI_DATA; -+ pattrib->priority = 0; -+ pattrib->qsel = pattrib->priority; -+ pattrib->nr_frags = 1; -+ pattrib->encrypt = 0; -+ pattrib->bswenc = false; -+ pattrib->qos_en = false; -+} -+ -+s32 init_mp_priv(struct adapter *padapter) -+{ -+ struct mp_priv *pmppriv = &padapter->mppriv; -+ -+ _init_mp_priv_(pmppriv); -+ pmppriv->papdater = padapter; -+ -+ pmppriv->tx.stop = 1; -+ mp_init_xmit_attrib(&pmppriv->tx, padapter); -+ -+ switch (padapter->registrypriv.rf_config) { -+ case RF_1T1R: -+ pmppriv->antenna_tx = ANTENNA_A; -+ pmppriv->antenna_rx = ANTENNA_A; -+ break; -+ case RF_1T2R: -+ default: -+ pmppriv->antenna_tx = ANTENNA_A; -+ pmppriv->antenna_rx = ANTENNA_AB; -+ break; -+ case RF_2T2R: -+ case RF_2T2R_GREEN: -+ pmppriv->antenna_tx = ANTENNA_AB; -+ pmppriv->antenna_rx = ANTENNA_AB; -+ break; -+ case RF_2T4R: -+ pmppriv->antenna_tx = ANTENNA_AB; -+ pmppriv->antenna_rx = ANTENNA_ABCD; -+ break; -+ } -+ -+ return _SUCCESS; -+} -+ -+void free_mp_priv(struct mp_priv *pmp_priv) -+{ -+ kfree(pmp_priv->pallocated_mp_xmitframe_buf); -+ pmp_priv->pallocated_mp_xmitframe_buf = NULL; -+ pmp_priv->pmp_xmtframe_buf = NULL; -+} -+ -+#define PHY_IQCalibrate(a, b) PHY_IQCalibrate_8188E(a, b) -+#define PHY_LCCalibrate(a) PHY_LCCalibrate_8188E(a) -+#define PHY_SetRFPathSwitch(a, b) PHY_SetRFPathSwitch_8188E(a, b) -+ -+s32 MPT_InitializeAdapter(struct adapter *pAdapter, u8 Channel) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ s32 rtStatus = _SUCCESS; -+ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx; -+ struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv; -+ -+ /* HW Initialization for 8190 MPT. */ -+ /* SW Initialization for 8190 MP. */ -+ pMptCtx->bMptDrvUnload = false; -+ pMptCtx->bMassProdTest = false; -+ pMptCtx->bMptIndexEven = true; /* default gain index is -6.0db */ -+ pMptCtx->h2cReqNum = 0x0; -+ /* Init mpt event. */ -+ /* init for BT MP */ -+ -+ pMptCtx->bMptWorkItemInProgress = false; -+ pMptCtx->CurrMptAct = NULL; -+ /* */ -+ -+ /* Don't accept any packets */ -+ rtw_write32(pAdapter, REG_RCR, 0); -+ -+ PHY_IQCalibrate(pAdapter, false); -+ dm_CheckTXPowerTracking(&pHalData->odmpriv); /* trigger thermal meter */ -+ PHY_LCCalibrate(pAdapter); -+ -+ pMptCtx->backup0xc50 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XAAGCCore1, bMaskByte0); -+ pMptCtx->backup0xc58 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XBAGCCore1, bMaskByte0); -+ pMptCtx->backup0xc30 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_RxDetector1, bMaskByte0); -+ pMptCtx->backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); -+ pMptCtx->backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); -+ -+ /* set ant to wifi side in mp mode */ -+ rtw_write16(pAdapter, 0x870, 0x300); -+ rtw_write16(pAdapter, 0x860, 0x110); -+ -+ if (pAdapter->registrypriv.mp_mode == 1) -+ pmlmepriv->fw_state = WIFI_MP_STATE; -+ -+ return rtStatus; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: MPT_DeInitAdapter() -+ * -+ * Overview: Extra DeInitialization for Mass Production Test. -+ * -+ * Input: struct adapter * pAdapter -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 05/08/2007 MHC Create Version 0. -+ * 05/18/2007 MHC Add normal driver MPHalt code. -+ * -+ *---------------------------------------------------------------------------*/ -+void MPT_DeInitAdapter(struct adapter *pAdapter) -+{ -+ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx; -+ -+ pMptCtx->bMptDrvUnload = true; -+} -+ -+static u8 mpt_ProStartTest(struct adapter *padapter) -+{ -+ struct mpt_context *pMptCtx = &padapter->mppriv.MptCtx; -+ -+ pMptCtx->bMassProdTest = true; -+ pMptCtx->bStartContTx = false; -+ pMptCtx->bCckContTx = false; -+ pMptCtx->bOfdmContTx = false; -+ pMptCtx->bSingleCarrier = false; -+ pMptCtx->bCarrierSuppression = false; -+ pMptCtx->bSingleTone = false; -+ -+ return _SUCCESS; -+} -+ -+/* -+ * General use -+ */ -+s32 SetPowerTracking(struct adapter *padapter, u8 enable) -+{ -+ Hal_SetPowerTracking(padapter, enable); -+ return 0; -+} -+ -+void GetPowerTracking(struct adapter *padapter, u8 *enable) -+{ -+ Hal_GetPowerTracking(padapter, enable); -+} -+ -+static void disable_dm(struct adapter *padapter) -+{ -+ u8 v8; -+ -+ /* 3 1. disable firmware dynamic mechanism */ -+ /* disable Power Training, Rate Adaptive */ -+ v8 = rtw_read8(padapter, REG_BCN_CTRL); -+ v8 &= ~EN_BCN_FUNCTION; -+ rtw_write8(padapter, REG_BCN_CTRL, v8); -+ -+ /* 3 2. disable driver dynamic mechanism */ -+ /* disable Dynamic Initial Gain */ -+ /* disable High Power */ -+ /* disable Power Tracking */ -+ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); -+ -+ /* enable APK, LCK and IQK but disable power tracking */ -+ Switch_DM_Func(padapter, DYNAMIC_RF_CALIBRATION, true); -+} -+ -+/* This function initializes the DUT to the MP test mode */ -+s32 mp_start_test(struct adapter *padapter) -+{ -+ struct wlan_bssid_ex bssid; -+ struct sta_info *psta; -+ u32 length; -+ u8 val8; -+ s32 res = _SUCCESS; -+ struct mp_priv *pmppriv = &padapter->mppriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct wlan_network *tgt_network = &pmlmepriv->cur_network; -+ -+ padapter->registrypriv.mp_mode = 1; -+ pmppriv->bSetTxPower = 0; /* for manually set tx power */ -+ -+ /* 3 disable dynamic mechanism */ -+ disable_dm(padapter); -+ -+ /* 3 0. update mp_priv */ -+ -+ if (padapter->registrypriv.rf_config == RF_819X_MAX_TYPE) { -+ switch (GET_RF_TYPE(padapter)) { -+ case RF_1T1R: -+ pmppriv->antenna_tx = ANTENNA_A; -+ pmppriv->antenna_rx = ANTENNA_A; -+ break; -+ case RF_1T2R: -+ default: -+ pmppriv->antenna_tx = ANTENNA_A; -+ pmppriv->antenna_rx = ANTENNA_AB; -+ break; -+ case RF_2T2R: -+ case RF_2T2R_GREEN: -+ pmppriv->antenna_tx = ANTENNA_AB; -+ pmppriv->antenna_rx = ANTENNA_AB; -+ break; -+ case RF_2T4R: -+ pmppriv->antenna_tx = ANTENNA_AB; -+ pmppriv->antenna_rx = ANTENNA_ABCD; -+ break; -+ } -+ } -+ -+ mpt_ProStartTest(padapter); -+ -+ /* 3 1. initialize a new struct wlan_bssid_ex */ -+/* memset(&bssid, 0, sizeof(struct wlan_bssid_ex)); */ -+ memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN); -+ bssid.Ssid.SsidLength = strlen("mp_pseudo_adhoc"); -+ memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_adhoc", bssid.Ssid.SsidLength); -+ bssid.InfrastructureMode = Ndis802_11IBSS; -+ bssid.NetworkTypeInUse = Ndis802_11DS; -+ bssid.IELength = 0; -+ -+ length = get_wlan_bssid_ex_sz(&bssid); -+ if (length % 4) -+ bssid.Length = ((length >> 2) + 1) << 2; /* round up to multiple of 4 bytes. */ -+ else -+ bssid.Length = length; -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) -+ goto end_of_mp_start_test; -+ -+ /* init mp_start_test status */ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { -+ rtw_disassoc_cmd(padapter, 500, true); -+ rtw_indicate_disconnect(padapter); -+ rtw_free_assoc_resources(padapter, 1); -+ } -+ pmppriv->prev_fw_state = get_fwstate(pmlmepriv); -+ if (padapter->registrypriv.mp_mode == 1) -+ pmlmepriv->fw_state = WIFI_MP_STATE; -+ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); -+ -+ /* 3 2. create a new psta for mp driver */ -+ /* clear psta in the cur_network, if any */ -+ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); -+ if (psta) -+ rtw_free_stainfo(padapter, psta); -+ -+ psta = rtw_alloc_stainfo(&padapter->stapriv, bssid.MacAddress); -+ if (psta == NULL) { -+ RT_TRACE(_module_mp_, _drv_err_, ("mp_start_test: Can't alloc sta_info!\n")); -+ pmlmepriv->fw_state = pmppriv->prev_fw_state; -+ res = _FAIL; -+ goto end_of_mp_start_test; -+ } -+ -+ /* 3 3. join psudo AdHoc */ -+ tgt_network->join_res = 1; -+ tgt_network->aid = 1; -+ psta->aid = 1; -+ memcpy(&tgt_network->network, &bssid, length); -+ -+ rtw_indicate_connect(padapter); -+ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); -+ -+end_of_mp_start_test: -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+ if (res == _SUCCESS) { -+ /* set MSR to WIFI_FW_ADHOC_STATE */ -+ val8 = rtw_read8(padapter, MSR) & 0xFC; /* 0x0102 */ -+ val8 |= WIFI_FW_ADHOC_STATE; -+ rtw_write8(padapter, MSR, val8); /* Link in ad hoc network */ -+ } -+ return res; -+} -+/* */ -+/* This function change the DUT from the MP test mode into normal mode */ -+void mp_stop_test(struct adapter *padapter) -+{ -+ struct mp_priv *pmppriv = &padapter->mppriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct wlan_network *tgt_network = &pmlmepriv->cur_network; -+ struct sta_info *psta; -+ -+ if (pmppriv->mode == MP_ON) { -+ pmppriv->bSetTxPower = 0; -+ spin_lock_bh(&pmlmepriv->lock); -+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false) -+ goto end_of_mp_stop_test; -+ -+ /* 3 1. disconnect psudo AdHoc */ -+ rtw_indicate_disconnect(padapter); -+ -+ /* 3 2. clear psta used in mp test mode. */ -+ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); -+ if (psta) -+ rtw_free_stainfo(padapter, psta); -+ -+ /* 3 3. return to normal state (default:station mode) */ -+ pmlmepriv->fw_state = pmppriv->prev_fw_state; /* WIFI_STATION_STATE; */ -+ -+ /* flush the cur_network */ -+ memset(tgt_network, 0, sizeof(struct wlan_network)); -+ -+ _clr_fwstate_(pmlmepriv, WIFI_MP_STATE); -+ -+end_of_mp_stop_test: -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+ } -+} -+ -+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ -+/* -+ * SetChannel -+ * Description -+ * Use H2C command to change channel, -+ * not only modify rf register, but also other setting need to be done. -+ */ -+void SetChannel(struct adapter *pAdapter) -+{ -+ Hal_SetChannel(pAdapter); -+} -+ -+/* -+ * Notice -+ * Switch bandwitdth may change center frequency(channel) -+ */ -+void SetBandwidth(struct adapter *pAdapter) -+{ -+ Hal_SetBandwidth(pAdapter); -+} -+ -+void SetAntenna(struct adapter *pAdapter) -+{ -+ Hal_SetAntenna(pAdapter); -+} -+ -+void SetAntennaPathPower(struct adapter *pAdapter) -+{ -+ Hal_SetAntennaPathPower(pAdapter); -+} -+ -+void SetTxPower(struct adapter *pAdapter) -+{ -+ Hal_SetTxPower(pAdapter); -+ } -+ -+void SetDataRate(struct adapter *pAdapter) -+{ -+ Hal_SetDataRate(pAdapter); -+} -+ -+void MP_PHY_SetRFPathSwitch(struct adapter *pAdapter , bool bMain) -+{ -+ PHY_SetRFPathSwitch(pAdapter, bMain); -+} -+ -+s32 SetThermalMeter(struct adapter *pAdapter, u8 target_ther) -+{ -+ return Hal_SetThermalMeter(pAdapter, target_ther); -+} -+ -+void GetThermalMeter(struct adapter *pAdapter, u8 *value) -+{ -+ Hal_GetThermalMeter(pAdapter, value); -+} -+ -+void SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart) -+{ -+ PhySetTxPowerLevel(pAdapter); -+ Hal_SetSingleCarrierTx(pAdapter, bStart); -+} -+ -+void SetSingleToneTx(struct adapter *pAdapter, u8 bStart) -+{ -+ PhySetTxPowerLevel(pAdapter); -+ Hal_SetSingleToneTx(pAdapter, bStart); -+} -+ -+void SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart) -+{ -+ PhySetTxPowerLevel(pAdapter); -+ Hal_SetCarrierSuppressionTx(pAdapter, bStart); -+} -+ -+void SetContinuousTx(struct adapter *pAdapter, u8 bStart) -+{ -+ PhySetTxPowerLevel(pAdapter); -+ Hal_SetContinuousTx(pAdapter, bStart); -+} -+ -+void PhySetTxPowerLevel(struct adapter *pAdapter) -+{ -+ struct mp_priv *pmp_priv = &pAdapter->mppriv; -+ -+ if (pmp_priv->bSetTxPower == 0) /* for NO manually set power index */ -+ PHY_SetTxPowerLevel8188E(pAdapter, pmp_priv->channel); -+} -+ -+/* */ -+static void dump_mpframe(struct adapter *padapter, struct xmit_frame *pmpframe) -+{ -+ rtw_hal_mgnt_xmit(padapter, pmpframe); -+} -+ -+static struct xmit_frame *alloc_mp_xmitframe(struct xmit_priv *pxmitpriv) -+{ -+ struct xmit_frame *pmpframe; -+ struct xmit_buf *pxmitbuf; -+ -+ pmpframe = rtw_alloc_xmitframe(pxmitpriv); -+ if (pmpframe == NULL) -+ return NULL; -+ -+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); -+ if (pxmitbuf == NULL) { -+ rtw_free_xmitframe(pxmitpriv, pmpframe); -+ return NULL; -+ } -+ -+ pmpframe->frame_tag = MP_FRAMETAG; -+ -+ pmpframe->pxmitbuf = pxmitbuf; -+ -+ pmpframe->buf_addr = pxmitbuf->pbuf; -+ -+ pxmitbuf->priv_data = pmpframe; -+ -+ return pmpframe; -+} -+ -+static int mp_xmit_packet_thread(void *context) -+{ -+ struct xmit_frame *pxmitframe; -+ struct mp_tx *pmptx; -+ struct mp_priv *pmp_priv; -+ struct xmit_priv *pxmitpriv; -+ struct adapter *padapter; -+ -+ pmp_priv = (struct mp_priv *)context; -+ pmptx = &pmp_priv->tx; -+ padapter = pmp_priv->papdater; -+ pxmitpriv = &(padapter->xmitpriv); -+ -+ thread_enter("RTW_MP_THREAD"); -+ -+ /* DBG_88E("%s:pkTx Start\n", __func__); */ -+ while (1) { -+ pxmitframe = alloc_mp_xmitframe(pxmitpriv); -+ if (pxmitframe == NULL) { -+ if (pmptx->stop || -+ padapter->bSurpriseRemoved || -+ padapter->bDriverStopped) { -+ goto exit; -+ } else { -+ rtw_msleep_os(1); -+ continue; -+ } -+ } -+ -+ memcpy((u8 *)(pxmitframe->buf_addr+TXDESC_OFFSET), pmptx->buf, pmptx->write_size); -+ memcpy(&(pxmitframe->attrib), &(pmptx->attrib), sizeof(struct pkt_attrib)); -+ -+ dump_mpframe(padapter, pxmitframe); -+ -+ pmptx->sended++; -+ pmp_priv->tx_pktcount++; -+ -+ if (pmptx->stop || -+ padapter->bSurpriseRemoved || -+ padapter->bDriverStopped) -+ goto exit; -+ if ((pmptx->count != 0) && -+ (pmptx->count == pmptx->sended)) -+ goto exit; -+ -+ flush_signals_thread(); -+ } -+ -+exit: -+ kfree(pmptx->pallocated_buf); -+ pmptx->pallocated_buf = NULL; -+ pmptx->stop = 1; -+ -+ thread_exit(); -+} -+ -+void fill_txdesc_for_mp(struct adapter *padapter, struct tx_desc *ptxdesc) -+{ -+ struct mp_priv *pmp_priv = &padapter->mppriv; -+ memcpy(ptxdesc, &(pmp_priv->tx.desc), TXDESC_SIZE); -+} -+ -+void SetPacketTx(struct adapter *padapter) -+{ -+ u8 *ptr, *pkt_start, *pkt_end; -+ u32 pkt_size; -+ struct tx_desc *desc; -+ struct rtw_ieee80211_hdr *hdr; -+ u8 payload; -+ s32 bmcast; -+ struct pkt_attrib *pattrib; -+ struct mp_priv *pmp_priv; -+ -+ pmp_priv = &padapter->mppriv; -+ if (pmp_priv->tx.stop) -+ return; -+ pmp_priv->tx.sended = 0; -+ pmp_priv->tx.stop = 0; -+ pmp_priv->tx_pktcount = 0; -+ -+ /* 3 1. update_attrib() */ -+ pattrib = &pmp_priv->tx.attrib; -+ memcpy(pattrib->src, padapter->eeprompriv.mac_addr, ETH_ALEN); -+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); -+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); -+ bmcast = IS_MCAST(pattrib->ra); -+ if (bmcast) { -+ pattrib->mac_id = 1; -+ pattrib->psta = rtw_get_bcmc_stainfo(padapter); -+ } else { -+ pattrib->mac_id = 0; -+ pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); -+ } -+ -+ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen; -+ -+ /* 3 2. allocate xmit buffer */ -+ pkt_size = pattrib->last_txcmdsz; -+ -+ kfree(pmp_priv->tx.pallocated_buf); -+ pmp_priv->tx.write_size = pkt_size; -+ pmp_priv->tx.buf_size = pkt_size + XMITBUF_ALIGN_SZ; -+ pmp_priv->tx.pallocated_buf = rtw_zmalloc(pmp_priv->tx.buf_size); -+ if (pmp_priv->tx.pallocated_buf == NULL) { -+ DBG_88E("%s: malloc(%d) fail!!\n", __func__, pmp_priv->tx.buf_size); -+ return; -+ } -+ pmp_priv->tx.buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pmp_priv->tx.pallocated_buf), XMITBUF_ALIGN_SZ); -+ ptr = pmp_priv->tx.buf; -+ -+ desc = &(pmp_priv->tx.desc); -+ memset(desc, 0, TXDESC_SIZE); -+ pkt_start = ptr; -+ pkt_end = pkt_start + pkt_size; -+ -+ /* 3 3. init TX descriptor */ -+ /* offset 0 */ -+ desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); -+ desc->txdw0 |= cpu_to_le32(pkt_size & 0x0000FFFF); /* packet size */ -+ desc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00FF0000); /* 32 bytes for TX Desc */ -+ if (bmcast) -+ desc->txdw0 |= cpu_to_le32(BMC); /* broadcast packet */ -+ -+ desc->txdw1 |= cpu_to_le32((0x01 << 26) & 0xff000000); -+ /* offset 4 */ -+ desc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x3F); /* CAM_ID(MAC_ID) */ -+ desc->txdw1 |= cpu_to_le32((pattrib->qsel << QSEL_SHT) & 0x00001F00); /* Queue Select, TID */ -+ -+ desc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); /* Rate Adaptive ID */ -+ /* offset 8 */ -+ /* offset 12 */ -+ -+ desc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0x0fff0000); -+ -+ /* offset 16 */ -+ desc->txdw4 |= cpu_to_le32(HW_SSN); -+ desc->txdw4 |= cpu_to_le32(USERATE); -+ desc->txdw4 |= cpu_to_le32(DISDATAFB); -+ -+ if (pmp_priv->preamble) { -+ if (pmp_priv->rateidx <= MPT_RATE_54M) -+ desc->txdw4 |= cpu_to_le32(DATA_SHORT); /* CCK Short Preamble */ -+ } -+ if (pmp_priv->bandwidth == HT_CHANNEL_WIDTH_40) -+ desc->txdw4 |= cpu_to_le32(DATA_BW); -+ -+ /* offset 20 */ -+ desc->txdw5 |= cpu_to_le32(pmp_priv->rateidx & 0x0000001F); -+ -+ if (pmp_priv->preamble) { -+ if (pmp_priv->rateidx > MPT_RATE_54M) -+ desc->txdw5 |= cpu_to_le32(SGI); /* MCS Short Guard Interval */ -+ } -+ desc->txdw5 |= cpu_to_le32(RTY_LMT_EN); /* retry limit enable */ -+ desc->txdw5 |= cpu_to_le32(0x00180000); /* DATA/RTS Rate Fallback Limit */ -+ -+ /* 3 4. make wlan header, make_wlanhdr() */ -+ hdr = (struct rtw_ieee80211_hdr *)pkt_start; -+ SetFrameSubType(&hdr->frame_ctl, pattrib->subtype); -+ memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); /* DA */ -+ memcpy(hdr->addr2, pattrib->src, ETH_ALEN); /* SA */ -+ memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); /* RA, BSSID */ -+ -+ /* 3 5. make payload */ -+ ptr = pkt_start + pattrib->hdrlen; -+ -+ switch (pmp_priv->tx.payload) { -+ case 0: -+ payload = 0x00; -+ break; -+ case 1: -+ payload = 0x5a; -+ break; -+ case 2: -+ payload = 0xa5; -+ break; -+ case 3: -+ payload = 0xff; -+ break; -+ default: -+ payload = 0x00; -+ break; -+ } -+ -+ memset(ptr, payload, pkt_end - ptr); -+ -+ /* 3 6. start thread */ -+ pmp_priv->tx.PktTxThread = kthread_run(mp_xmit_packet_thread, pmp_priv, "RTW_MP_THREAD"); -+ if (IS_ERR(pmp_priv->tx.PktTxThread)) -+ DBG_88E("Create PktTx Thread Fail !!!!!\n"); -+} -+ -+void SetPacketRx(struct adapter *pAdapter, u8 bStartRx) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ -+ if (bStartRx) { -+ /* Accept CRC error and destination address */ -+ pHalData->ReceiveConfig = AAP | APM | AM | AB | APP_ICV | -+ AMF | ADF | APP_FCS | HTC_LOC_CTRL | -+ APP_MIC | APP_PHYSTS; -+ -+ pHalData->ReceiveConfig |= (RCR_ACRC32 | RCR_AAP); -+ -+ rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig); -+ -+ /* Accept all data frames */ -+ rtw_write16(pAdapter, REG_RXFLTMAP2, 0xFFFF); -+ } else { -+ rtw_write32(pAdapter, REG_RCR, 0); -+ } -+} -+ -+void ResetPhyRxPktCount(struct adapter *pAdapter) -+{ -+ u32 i, phyrx_set = 0; -+ -+ for (i = 0; i <= 0xF; i++) { -+ phyrx_set = 0; -+ phyrx_set |= _RXERR_RPT_SEL(i); /* select */ -+ phyrx_set |= RXERR_RPT_RST; /* set counter to zero */ -+ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); -+ } -+} -+ -+static u32 GetPhyRxPktCounts(struct adapter *pAdapter, u32 selbit) -+{ -+ /* selection */ -+ u32 phyrx_set = 0, count = 0; -+ -+ phyrx_set = _RXERR_RPT_SEL(selbit & 0xF); -+ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); -+ -+ /* Read packet count */ -+ count = rtw_read32(pAdapter, REG_RXERR_RPT) & RXERR_COUNTER_MASK; -+ -+ return count; -+} -+ -+u32 GetPhyRxPktReceived(struct adapter *pAdapter) -+{ -+ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; -+ -+ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_OK); -+ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_OK); -+ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_OK); -+ -+ return OFDM_cnt + CCK_cnt + HT_cnt; -+} -+ -+u32 GetPhyRxPktCRC32Error(struct adapter *pAdapter) -+{ -+ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; -+ -+ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_FAIL); -+ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_FAIL); -+ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_FAIL); -+ -+ return OFDM_cnt + CCK_cnt + HT_cnt; -+} -+ -+/* reg 0x808[9:0]: FFT data x */ -+/* reg 0x808[22]: 0 --> 1 to get 1 FFT data y */ -+/* reg 0x8B4[15:0]: FFT data y report */ -+static u32 rtw_GetPSDData(struct adapter *pAdapter, u32 point) -+{ -+ int psd_val; -+ -+ psd_val = rtw_read32(pAdapter, 0x808); -+ psd_val &= 0xFFBFFC00; -+ psd_val |= point; -+ -+ rtw_write32(pAdapter, 0x808, psd_val); -+ rtw_mdelay_os(1); -+ psd_val |= 0x00400000; -+ -+ rtw_write32(pAdapter, 0x808, psd_val); -+ rtw_mdelay_os(1); -+ psd_val = rtw_read32(pAdapter, 0x8B4); -+ -+ psd_val &= 0x0000FFFF; -+ -+ return psd_val; -+} -+ -+/* -+ *pts start_point_min stop_point_max -+ * 128 64 64 + 128 = 192 -+ * 256 128 128 + 256 = 384 -+ * 512 256 256 + 512 = 768 -+ * 1024 512 512 + 1024 = 1536 -+ */ -+u32 mp_query_psd(struct adapter *pAdapter, u8 *data) -+{ -+ u32 i, psd_pts = 0, psd_start = 0, psd_stop = 0; -+ u32 psd_data = 0; -+ -+ if (!netif_running(pAdapter->pnetdev)) { -+ RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! interface not opened!\n")); -+ return 0; -+ } -+ -+ if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == false) { -+ RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! not in MP mode!\n")); -+ return 0; -+ } -+ -+ if (strlen(data) == 0) { /* default value */ -+ psd_pts = 128; -+ psd_start = 64; -+ psd_stop = 128; -+ } else { -+ sscanf(data, "pts =%d, start =%d, stop =%d", &psd_pts, &psd_start, &psd_stop); -+ } -+ -+ memset(data, '\0', sizeof(*data)); -+ -+ i = psd_start; -+ while (i < psd_stop) { -+ if (i >= psd_pts) { -+ psd_data = rtw_GetPSDData(pAdapter, i-psd_pts); -+ } else { -+ psd_data = rtw_GetPSDData(pAdapter, i); -+ } -+ sprintf(data, "%s%x ", data, psd_data); -+ i++; -+ } -+ -+ rtw_msleep_os(100); -+ return strlen(data)+1; -+} -+ -+void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv) -+{ -+ int i, res; -+ struct adapter *padapter = pxmitpriv->adapter; -+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; -+ -+ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; -+ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; -+ if (padapter->registrypriv.mp_mode == 0) { -+ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; -+ num_xmit_extbuf = NR_XMIT_EXTBUFF; -+ } else { -+ max_xmit_extbuf_size = 6000; -+ num_xmit_extbuf = 8; -+ } -+ -+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; -+ for (i = 0; i < num_xmit_extbuf; i++) { -+ rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ)); -+ -+ pxmitbuf++; -+ } -+ -+ if (pxmitpriv->pallocated_xmit_extbuf) -+ rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4); -+ -+ if (padapter->registrypriv.mp_mode == 0) { -+ max_xmit_extbuf_size = 6000; -+ num_xmit_extbuf = 8; -+ } else { -+ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; -+ num_xmit_extbuf = NR_XMIT_EXTBUFF; -+ } -+ -+ /* Init xmit extension buff */ -+ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); -+ -+ pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); -+ -+ if (pxmitpriv->pallocated_xmit_extbuf == NULL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n")); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4); -+ -+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; -+ -+ for (i = 0; i < num_xmit_extbuf; i++) { -+ INIT_LIST_HEAD(&pxmitbuf->list); -+ -+ pxmitbuf->priv_data = NULL; -+ pxmitbuf->padapter = padapter; -+ pxmitbuf->ext_tag = true; -+ -+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ); -+ if (res == _FAIL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ list_add_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); -+ pxmitbuf++; -+ } -+ -+ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; -+ -+exit: -+ ; -+} -+ -+void Hal_ProSetCrystalCap (struct adapter *pAdapter, u32 CrystalCapVal) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ -+ CrystalCapVal = CrystalCapVal & 0x3F; -+ -+ // write 0x24[16:11] = 0x24[22:17] = CrystalCap -+ PHY_SetBBReg(pAdapter, REG_AFE_XTAL_CTRL, 0x7FF800, -+ (CrystalCapVal | (CrystalCapVal << 6))); -+} -+ -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_mp_ioctl.c b/drivers/net/wireless/rtl8188eu/core/rtw_mp_ioctl.c -new file mode 100644 -index 0000000000000..87c3f29b16ef0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_mp_ioctl.c -@@ -0,0 +1,1352 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_MP_IOCTL_C_ -+ -+#include -+#include -+#include -+ -+/* include */ -+#include -+ -+/* rtl8188eu_oid_rtl_seg_81_85 section start **************** */ -+int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->information_buf_len < sizeof(u8)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ if (poid_par_priv->type_of_oid == SET_OID) { -+ Adapter->registrypriv.wireless_mode = *(u8 *)poid_par_priv->information_buf; -+ } else if (poid_par_priv->type_of_oid == QUERY_OID) { -+ *(u8 *)poid_par_priv->information_buf = Adapter->registrypriv.wireless_mode; -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ RT_TRACE(_module_mp_, _drv_info_, ("-query Wireless Mode=%d\n", Adapter->registrypriv.wireless_mode)); -+ } else { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ } -+ -+ return status; -+} -+/* rtl8188eu_oid_rtl_seg_81_87_80 section start **************** */ -+int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct bb_reg_param *pbbreg; -+ u16 offset; -+ u32 value; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_bb_reg_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); -+ -+ offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */ -+ if (offset < BB_REG_BASE_ADDR) -+ offset |= BB_REG_BASE_ADDR; -+ -+ value = pbbreg->value; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_write_bb_reg_hdl: offset=0x%03X value=0x%08X\n", -+ offset, value)); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ write_bbreg(Adapter, offset, 0xFFFFFFFF, value); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct bb_reg_param *pbbreg; -+ u16 offset; -+ u32 value; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_bb_reg_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); -+ -+ offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */ -+ if (offset < BB_REG_BASE_ADDR) -+ offset |= BB_REG_BASE_ADDR; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ value = read_bbreg(Adapter, offset, 0xFFFFFFFF); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ pbbreg->value = value; -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("-rtl8188eu_oid_rt_pro_read_bb_reg_hdl: offset=0x%03X value:0x%08X\n", -+ offset, value)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct rf_reg_param *pbbreg; -+ u8 path; -+ u8 offset; -+ u32 value; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_rf_reg_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); -+ -+ if (pbbreg->path >= RF_PATH_MAX) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ if (pbbreg->offset > 0xFF) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ if (pbbreg->value > 0xFFFFF) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ path = (u8)pbbreg->path; -+ offset = (u8)pbbreg->offset; -+ value = pbbreg->value; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_write_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n", -+ path, offset, value)); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ write_rfreg(Adapter, path, offset, value); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct rf_reg_param *pbbreg; -+ u8 path; -+ u8 offset; -+ u32 value; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ int status = NDIS_STATUS_SUCCESS; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_rf_reg_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); -+ -+ if (pbbreg->path >= RF_PATH_MAX) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ if (pbbreg->offset > 0xFF) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ path = (u8)pbbreg->path; -+ offset = (u8)pbbreg->offset; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ value = read_rfreg(Adapter, path, offset); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ pbbreg->value = value; -+ -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("-rtl8188eu_oid_rt_pro_read_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n", -+ path, offset, value)); -+ -+ return status; -+} -+/* rtl8188eu_oid_rtl_seg_81_87_00 section end**************** */ -+/* */ -+ -+/* rtl8188eu_oid_rtl_seg_81_80_00 section start **************** */ -+/* */ -+int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 ratevalue;/* 4 */ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("+rtl8188eu_oid_rt_pro_set_data_rate_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len != sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ ratevalue = *((u32 *)poid_par_priv->information_buf);/* 4 */ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_set_data_rate_hdl: data rate idx=%d\n", ratevalue)); -+ if (ratevalue >= MPT_RATE_LAST) -+ return NDIS_STATUS_INVALID_DATA; -+ -+ Adapter->mppriv.rateidx = ratevalue; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetDataRate(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 mode; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_start_test_hdl\n")); -+ -+ if (Adapter->registrypriv.mp_mode == 0) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ -+ /* IQCalibrateBcut(Adapter); */ -+ -+ mode = *((u32 *)poid_par_priv->information_buf); -+ Adapter->mppriv.mode = mode;/* 1 for loopback */ -+ -+ if (mp_start_test(Adapter) == _FAIL) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ goto exit; -+ } -+ -+exit: -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_pro_start_test_hdl: mp_mode=%d\n", Adapter->mppriv.mode)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+Set OID_RT_PRO_STOP_TEST\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ mp_stop_test(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("-Set OID_RT_PRO_STOP_TEST\n")); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 Channel; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl\n")); -+ -+ if (poid_par_priv->information_buf_len != sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ if (poid_par_priv->type_of_oid == QUERY_OID) { -+ *((u32 *)poid_par_priv->information_buf) = Adapter->mppriv.channel; -+ return NDIS_STATUS_SUCCESS; -+ } -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ Channel = *((u32 *)poid_par_priv->information_buf); -+ RT_TRACE(_module_mp_, _drv_notice_, ("rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl: Channel=%d\n", Channel)); -+ if (Channel > 14) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ Adapter->mppriv.channel = Channel; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetChannel(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u16 bandwidth; -+ u16 channel_offset; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("+rtl8188eu_oid_rt_set_bandwidth_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ bandwidth = *((u32 *)poid_par_priv->information_buf);/* 4 */ -+ channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ -+ if (bandwidth != HT_CHANNEL_WIDTH_40) -+ bandwidth = HT_CHANNEL_WIDTH_20; -+ padapter->mppriv.bandwidth = (u8)bandwidth; -+ padapter->mppriv.prime_channel_offset = (u8)channel_offset; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetBandwidth(padapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("-rtl8188eu_oid_rt_set_bandwidth_hdl: bandwidth=%d channel_offset=%d\n", -+ bandwidth, channel_offset)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 antenna; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_antenna_bb_hdl\n")); -+ -+ if (poid_par_priv->information_buf_len != sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ if (poid_par_priv->type_of_oid == SET_OID) { -+ antenna = *(u32 *)poid_par_priv->information_buf; -+ -+ Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16); -+ Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF); -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_set_antenna_bb_hdl: tx_ant=0x%04x rx_ant=0x%04x\n", -+ Adapter->mppriv.antenna_tx, Adapter->mppriv.antenna_rx)); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetAntenna(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ } else { -+ antenna = (Adapter->mppriv.antenna_tx << 16)|Adapter->mppriv.antenna_rx; -+ *(u32 *)poid_par_priv->information_buf = antenna; -+ } -+ -+ return status; -+} -+ -+int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 tx_pwr_idx; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_set_tx_power_control_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len != sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ tx_pwr_idx = *((u32 *)poid_par_priv->information_buf); -+ if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ Adapter->mppriv.txpoweridx = (u8)tx_pwr_idx; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_set_tx_power_control_hdl: idx=0x%2x\n", -+ Adapter->mppriv.txpoweridx)); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetTxPower(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+ -+/* */ -+/* rtl8188eu_oid_rtl_seg_81_80_20 section start **************** */ -+/* */ -+int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ return status; -+ } -+ -+ if (poid_par_priv->information_buf_len == sizeof(u32)) { -+ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.tx_pktcount; -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ } else { -+ status = NDIS_STATUS_INVALID_LENGTH; -+ } -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ return status; -+ } -+ RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl.\n")); -+ if (poid_par_priv->information_buf_len == sizeof(u32)) { -+ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_pktcount; -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ RT_TRACE(_module_mp_, _drv_alert_, ("recv_ok:%d\n", Adapter->mppriv.rx_pktcount)); -+ } else { -+ status = NDIS_STATUS_INVALID_LENGTH; -+ } -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ return status; -+ } -+ RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl.\n")); -+ if (poid_par_priv->information_buf_len == sizeof(u32)) { -+ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_crcerrpktcount; -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ RT_TRACE(_module_mp_, _drv_alert_, ("recv_err:%d\n", Adapter->mppriv.rx_crcerrpktcount)); -+ } else { -+ status = NDIS_STATUS_INVALID_LENGTH; -+ } -+ -+ return status; -+} -+/* */ -+ -+int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ return status; -+ } -+ -+ RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl.\n")); -+ Adapter->mppriv.tx_pktcount = 0; -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ return status; -+ } -+ -+ if (poid_par_priv->information_buf_len == sizeof(u32)) { -+ Adapter->mppriv.rx_pktcount = 0; -+ Adapter->mppriv.rx_crcerrpktcount = 0; -+ } else { -+ status = NDIS_STATUS_INVALID_LENGTH; -+ } -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ return status; -+ } -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ ResetPhyRxPktCount(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len != sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ *(u32 *)poid_par_priv->information_buf = GetPhyRxPktReceived(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl: recv_ok=%d\n", *(u32 *)poid_par_priv->information_buf)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len != sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ *(u32 *)poid_par_priv->information_buf = GetPhyRxPktCRC32Error(Adapter); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("-rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl: recv_err =%d\n", -+ *(u32 *)poid_par_priv->information_buf)); -+ -+ return status; -+} -+/* rtl8188eu_oid_rtl_seg_81_80_20 section end **************** */ -+int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 bStartTest; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_continuous_tx_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ bStartTest = *((u32 *)poid_par_priv->information_buf); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetContinuousTx(Adapter, (u8)bStartTest); -+ if (bStartTest) { -+ struct mp_priv *pmp_priv = &Adapter->mppriv; -+ if (pmp_priv->tx.stop == 0) { -+ pmp_priv->tx.stop = 1; -+ DBG_88E("%s: pkt tx is running...\n", __func__); -+ rtw_msleep_os(5); -+ } -+ pmp_priv->tx.stop = 0; -+ pmp_priv->tx.count = 1; -+ SetPacketTx(Adapter); -+ } -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+ -+int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 bStartTest; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ bStartTest = *((u32 *)poid_par_priv->information_buf); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetSingleCarrierTx(Adapter, (u8)bStartTest); -+ if (bStartTest) { -+ struct mp_priv *pmp_priv = &Adapter->mppriv; -+ if (pmp_priv->tx.stop == 0) { -+ pmp_priv->tx.stop = 1; -+ DBG_88E("%s: pkt tx is running...\n", __func__); -+ rtw_msleep_os(5); -+ } -+ pmp_priv->tx.stop = 0; -+ pmp_priv->tx.count = 1; -+ SetPacketTx(Adapter); -+ } -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+ -+int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 bStartTest; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ bStartTest = *((u32 *)poid_par_priv->information_buf); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetCarrierSuppressionTx(Adapter, (u8)bStartTest); -+ if (bStartTest) { -+ struct mp_priv *pmp_priv = &Adapter->mppriv; -+ if (pmp_priv->tx.stop == 0) { -+ pmp_priv->tx.stop = 1; -+ DBG_88E("%s: pkt tx is running...\n", __func__); -+ rtw_msleep_os(5); -+ } -+ pmp_priv->tx.stop = 0; -+ pmp_priv->tx.count = 1; -+ SetPacketTx(Adapter); -+ } -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+ -+int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u32 bStartTest; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ bStartTest = *((u32 *)poid_par_priv->information_buf); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ SetSingleToneTx(Adapter, (u8)bStartTest); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+ -+int rtl8188eu_oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ int status = NDIS_STATUS_SUCCESS; -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ rtw_hal_set_hwreg(Adapter, HW_VAR_TRIGGER_GPIO_0, NULL); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* rtl8188eu_oid_rtl_seg_81_80_00 section end **************** */ -+/* */ -+int rtl8188eu_oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct mp_rw_reg *RegRWStruct; -+ u32 offset, width; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("+rtl8188eu_oid_rt_pro_read_register_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; -+ offset = RegRWStruct->offset; -+ width = RegRWStruct->width; -+ -+ if (offset > 0xFFF) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ -+ switch (width) { -+ case 1: -+ RegRWStruct->value = rtw_read8(Adapter, offset); -+ break; -+ case 2: -+ RegRWStruct->value = rtw_read16(Adapter, offset); -+ break; -+ default: -+ width = 4; -+ RegRWStruct->value = rtw_read32(Adapter, offset); -+ break; -+ } -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_read_register_hdl: offset:0x%04X value:0x%X\n", -+ offset, RegRWStruct->value)); -+ -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ *poid_par_priv->bytes_rw = width; -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct mp_rw_reg *RegRWStruct; -+ u32 offset, width, value; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("+rtl8188eu_oid_rt_pro_write_register_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; -+ offset = RegRWStruct->offset; -+ width = RegRWStruct->width; -+ value = RegRWStruct->value; -+ -+ if (offset > 0xFFF) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ -+ switch (RegRWStruct->width) { -+ case 1: -+ if (value > 0xFF) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ break; -+ } -+ rtw_write8(padapter, offset, (u8)value); -+ break; -+ case 2: -+ if (value > 0xFFFF) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ break; -+ } -+ rtw_write16(padapter, offset, (u16)value); -+ break; -+ case 4: -+ rtw_write32(padapter, offset, value); -+ break; -+ default: -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ break; -+ } -+ -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("-rtl8188eu_oid_rt_pro_write_register_hdl: offset=0x%08X width=%d value=0x%X\n", -+ offset, width, value)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+/* */ -+int rtl8188eu_oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+/* */ -+int rtl8188eu_oid_rt_pro_write16_eeprom_hdl (struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_wr_attrib_mem_hdl (struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ int status = NDIS_STATUS_SUCCESS; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+OID_RT_PRO_SET_DATA_RATE_EX\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ -+ if (rtw_setdatarate_cmd(Adapter, poid_par_priv->information_buf) != _SUCCESS) -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ u8 thermal = 0; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_get_thermal_meter_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ GetThermalMeter(Adapter, &thermal); -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ *(u32 *)poid_par_priv->information_buf = (u32)thermal; -+ *poid_par_priv->bytes_rw = sizeof(u32); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->information_buf_len < sizeof(u8)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ if (poid_par_priv->type_of_oid == SET_OID) { -+ u8 enable; -+ -+ enable = *(u8 *)poid_par_priv->information_buf; -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("+rtl8188eu_oid_rt_pro_set_power_tracking_hdl: enable =%d\n", enable)); -+ -+ SetPowerTracking(Adapter, enable); -+ } else { -+ GetPowerTracking(Adapter, (u8 *)poid_par_priv->information_buf); -+ } -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+/* rtl8188eu_oid_rtl_seg_87_12_00 section start **************** */ -+int rtl8188eu_oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+int rtl8188eu_oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+int rtl8188eu_oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+int rtl8188eu_oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+int rtl8188eu_oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return NDIS_STATUS_SUCCESS; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct efuse_access_struct *pefuse; -+ u8 *data; -+ u16 addr = 0, cnts = 0, max_available_size = 0; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(struct efuse_access_struct)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf; -+ addr = pefuse->start_addr; -+ cnts = pefuse->cnts; -+ data = pefuse->data; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("+rtl8188eu_oid_rt_pro_read_efuse_hd: buf_len=%d addr=%d cnts=%d\n", -+ poid_par_priv->information_buf_len, addr, cnts)); -+ -+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); -+ -+ if ((addr + cnts) > max_available_size) { -+ RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_read_efuse_hdl: parameter error!\n")); -+ return NDIS_STATUS_NOT_ACCEPTED; -+ } -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ if (rtw_efuse_access(Adapter, false, addr, cnts, data) == _FAIL) { -+ RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_read_efuse_hdl: rtw_efuse_access FAIL!\n")); -+ status = NDIS_STATUS_FAILURE; -+ } else { -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ } -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct efuse_access_struct *pefuse; -+ u8 *data; -+ u16 addr = 0, cnts = 0, max_available_size = 0; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf; -+ addr = pefuse->start_addr; -+ cnts = pefuse->cnts; -+ data = pefuse->data; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("+rtl8188eu_oid_rt_pro_write_efuse_hdl: buf_len=%d addr=0x%04x cnts=%d\n", -+ poid_par_priv->information_buf_len, addr, cnts)); -+ -+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); -+ -+ if ((addr + cnts) > max_available_size) { -+ RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_write_efuse_hdl: parameter error")); -+ return NDIS_STATUS_NOT_ACCEPTED; -+ } -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ if (rtw_efuse_access(Adapter, true, addr, cnts, data) == _FAIL) -+ status = NDIS_STATUS_FAILURE; -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct pgpkt *ppgpkt; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ *poid_par_priv->bytes_rw = 0; -+ -+ if (poid_par_priv->information_buf_len < sizeof(struct pgpkt *)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ ppgpkt = (struct pgpkt *)poid_par_priv->information_buf; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ -+ if (poid_par_priv->type_of_oid == QUERY_OID) { -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: Read offset=0x%x\n",\ -+ ppgpkt->offset)); -+ -+ Efuse_PowerSwitch(Adapter, false, true); -+ if (Efuse_PgPacketRead(Adapter, ppgpkt->offset, ppgpkt->data, false) == true) -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ else -+ status = NDIS_STATUS_FAILURE; -+ Efuse_PowerSwitch(Adapter, false, false); -+ } else { -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: Write offset=0x%x word_en=0x%x\n",\ -+ ppgpkt->offset, ppgpkt->word_en)); -+ -+ Efuse_PowerSwitch(Adapter, true, true); -+ if (Efuse_PgPacketWrite(Adapter, ppgpkt->offset, ppgpkt->word_en, ppgpkt->data, false) == true) -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ else -+ status = NDIS_STATUS_FAILURE; -+ Efuse_PowerSwitch(Adapter, true, false); -+ } -+ -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("-rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: status=0x%08X\n", status)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u16 size; -+ u8 ret; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ ret = efuse_GetCurrentSize(Adapter, &size); -+ _irqlevel_changed_(&oldirql, RAISE); -+ if (ret == _SUCCESS) { -+ *(u32 *)poid_par_priv->information_buf = size; -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ } else { -+ status = NDIS_STATUS_FAILURE; -+ } -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ -+ if (poid_par_priv->type_of_oid != QUERY_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(u32)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ *(u32 *)poid_par_priv->information_buf = efuse_GetMaxSize(Adapter); -+ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("-rtl8188eu_oid_rt_get_efuse_max_size_hdl: size=%d status=0x%08X\n", -+ *(int *)poid_par_priv->information_buf, status)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status; -+ -+ RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_efuse_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid == QUERY_OID) -+ status = rtl8188eu_oid_rt_pro_read_efuse_hdl(poid_par_priv); -+ else -+ status = rtl8188eu_oid_rt_pro_write_efuse_hdl(poid_par_priv); -+ -+ RT_TRACE(_module_mp_, _drv_info_, ("-rtl8188eu_oid_rt_pro_efuse_hdl: status=0x%08X\n", status)); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u8 *data; -+ int status = NDIS_STATUS_SUCCESS; -+ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); -+ u16 maplen = 0; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_efuse_map_hdl\n")); -+ -+ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&maplen, false); -+ -+ *poid_par_priv->bytes_rw = 0; -+ -+ if (poid_par_priv->information_buf_len < maplen) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ data = (u8 *)poid_par_priv->information_buf; -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ -+ if (poid_par_priv->type_of_oid == QUERY_OID) { -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: READ\n")); -+ -+ if (rtw_efuse_map_read(Adapter, 0, maplen, data) == _SUCCESS) { -+ *poid_par_priv->bytes_rw = maplen; -+ } else { -+ RT_TRACE(_module_mp_, _drv_err_, -+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: READ fail\n")); -+ status = NDIS_STATUS_FAILURE; -+ } -+ } else { -+ /* SET_OID */ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: WRITE\n")); -+ -+ if (rtw_efuse_map_write(Adapter, 0, maplen, data) == _SUCCESS) { -+ *poid_par_priv->bytes_rw = maplen; -+ } else { -+ RT_TRACE(_module_mp_, _drv_err_, -+ ("rtl8188eu_oid_rt_pro_efuse_map_hdl: WRITE fail\n")); -+ status = NDIS_STATUS_FAILURE; -+ } -+ } -+ -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("-rtl8188eu_oid_rt_pro_efuse_map_hdl: status=0x%08X\n", status)); -+ -+ return status; -+} -+ -+int rtl8188eu_oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ return status; -+} -+ -+int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ u8 rx_pkt_type; -+ int status = NDIS_STATUS_SUCCESS; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_set_rx_packet_type_hdl\n")); -+ -+ if (poid_par_priv->type_of_oid != SET_OID) -+ return NDIS_STATUS_NOT_ACCEPTED; -+ -+ if (poid_par_priv->information_buf_len < sizeof(u8)) -+ return NDIS_STATUS_INVALID_LENGTH; -+ -+ rx_pkt_type = *((u8 *)poid_par_priv->information_buf);/* 4 */ -+ -+ RT_TRACE(_module_mp_, _drv_info_, ("rx_pkt_type: %x\n", rx_pkt_type)); -+ -+ return status; -+} -+ -+int rtl8188eu_oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+int rtl8188eu_oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -+ -+int rtl8188eu_mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ struct mp_xmit_parm *pparm; -+ struct adapter *padapter; -+ struct mp_priv *pmp_priv; -+ struct pkt_attrib *pattrib; -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("+%s\n", __func__)); -+ -+ pparm = (struct mp_xmit_parm *)poid_par_priv->information_buf; -+ padapter = (struct adapter *)poid_par_priv->adapter_context; -+ pmp_priv = &padapter->mppriv; -+ -+ if (poid_par_priv->type_of_oid == QUERY_OID) { -+ pparm->enable = !pmp_priv->tx.stop; -+ pparm->count = pmp_priv->tx.sended; -+ } else { -+ if (pparm->enable == 0) { -+ pmp_priv->tx.stop = 1; -+ } else if (pmp_priv->tx.stop == 1) { -+ pmp_priv->tx.stop = 0; -+ pmp_priv->tx.count = pparm->count; -+ pmp_priv->tx.payload = pparm->payload_type; -+ pattrib = &pmp_priv->tx.attrib; -+ pattrib->pktlen = pparm->length; -+ memcpy(pattrib->dst, pparm->da, ETH_ALEN); -+ SetPacketTx(padapter); -+ } else { -+ return NDIS_STATUS_FAILURE; -+ } -+ } -+ -+ return NDIS_STATUS_SUCCESS; -+} -+ -+/* */ -+int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ int status = NDIS_STATUS_SUCCESS; -+ -+ if (poid_par_priv->type_of_oid != SET_OID) { -+ status = NDIS_STATUS_NOT_ACCEPTED; -+ return status; -+ } -+ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("\n ===> Setrtl8188eu_oid_rt_set_power_down_hdl.\n")); -+ -+ _irqlevel_changed_(&oldirql, LOWER); -+ -+ /* CALL the power_down function */ -+ _irqlevel_changed_(&oldirql, RAISE); -+ -+ return status; -+} -+/* */ -+int rtl8188eu_oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv) -+{ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_p2p.c b/drivers/net/wireless/rtl8188eu/core/rtw_p2p.c -new file mode 100644 -index 0000000000000..2e21496fe71b1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_p2p.c -@@ -0,0 +1,2068 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_P2P_C_ -+ -+#include -+#include -+#include -+ -+#ifdef CONFIG_88EU_P2P -+ -+static int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt) -+{ -+ int found = 0, i = 0; -+ -+ for (i = 0; i < ch_cnt; i++) { -+ if (ch_list[i] == desired_ch) { -+ found = 1; -+ break; -+ } -+ } -+ return found; -+} -+ -+static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) -+{ -+ struct list_head *phead, *plist; -+ u32 len = 0; -+ u16 attr_len = 0; -+ u8 tmplen, *pdata_attr, *pstart, *pcur; -+ struct sta_info *psta = NULL; -+ struct adapter *padapter = pwdinfo->padapter; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ DBG_88E("%s\n", __func__); -+ -+ pdata_attr = rtw_zmalloc(MAX_P2P_IE_LEN); -+ -+ pstart = pdata_attr; -+ pcur = pdata_attr; -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ phead = &pstapriv->asoc_list; -+ plist = phead->next; -+ -+ /* look up sta asoc_queue */ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, asoc_list); -+ -+ plist = plist->next; -+ -+ if (psta->is_p2p_device) { -+ tmplen = 0; -+ -+ pcur++; -+ -+ /* P2P device address */ -+ memcpy(pcur, psta->dev_addr, ETH_ALEN); -+ pcur += ETH_ALEN; -+ -+ /* P2P interface address */ -+ memcpy(pcur, psta->hwaddr, ETH_ALEN); -+ pcur += ETH_ALEN; -+ -+ *pcur = psta->dev_cap; -+ pcur++; -+ -+ /* u16*)(pcur) = cpu_to_be16(psta->config_methods); */ -+ RTW_PUT_BE16(pcur, psta->config_methods); -+ pcur += 2; -+ -+ memcpy(pcur, psta->primary_dev_type, 8); -+ pcur += 8; -+ -+ *pcur = psta->num_of_secdev_type; -+ pcur++; -+ -+ memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type*8); -+ pcur += psta->num_of_secdev_type*8; -+ -+ if (psta->dev_name_len > 0) { -+ /* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ -+ RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME); -+ pcur += 2; -+ -+ /* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */ -+ RTW_PUT_BE16(pcur, psta->dev_name_len); -+ pcur += 2; -+ -+ memcpy(pcur, psta->dev_name, psta->dev_name_len); -+ pcur += psta->dev_name_len; -+ } -+ -+ tmplen = (u8)(pcur-pstart); -+ -+ *pstart = (tmplen-1); -+ -+ attr_len += tmplen; -+ -+ /* pstart += tmplen; */ -+ pstart = pcur; -+ } -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ -+ if (attr_len > 0) -+ len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr); -+ -+ kfree(pdata_attr); -+ return len; -+} -+ -+static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct adapter *padapter = pwdinfo->padapter; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */ -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_GO_DISC_REQUEST; -+ u8 dialogToken = 0; -+ -+ DBG_88E("[%s]\n", __func__); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ /* Build P2P action frame header */ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); -+ -+ /* there is no IE in this P2P action frame */ -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+} -+ -+static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct adapter *padapter = pwdinfo->padapter; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_DEVDISC_RESP; -+ u8 p2pie[8] = { 0x00 }; -+ u32 p2pielen = 0; -+ -+ DBG_88E("[%s]\n", __func__); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ /* Build P2P public action frame header */ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); -+ -+ /* Build P2P IE */ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* P2P_ATTR_STATUS */ -+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+} -+ -+static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8 *raddr, u8 *frame_body, u16 config_method) -+{ -+ struct adapter *padapter = pwdinfo->padapter; -+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; -+ u8 action = P2P_PUB_ACTION_ACTION; -+ u8 dialogToken = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_PROVISION_DISC_RESP; -+ u8 wpsie[100] = { 0x00 }; -+ u8 wpsielen = 0; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); -+ -+ wpsielen = 0; -+ /* WPS OUI */ -+ RTW_PUT_BE32(wpsie, WPSOUI); -+ wpsielen += 4; -+ -+ /* Config Method */ -+ /* Type: */ -+ RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); -+ wpsielen += 2; -+ -+ /* Length: */ -+ RTW_PUT_BE16(wpsie + wpsielen, 0x0002); -+ wpsielen += 2; -+ -+ /* Value: */ -+ RTW_PUT_BE16(wpsie + wpsielen, config_method); -+ wpsielen += 2; -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+ -+ return; -+} -+ -+static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) -+{ -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ unsigned char *pframe; -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ struct adapter *padapter = pwdinfo->padapter; -+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */ -+ __be32 p2poui = cpu_to_be32(P2POUI); -+ u8 oui_subtype = P2P_PRESENCE_RESPONSE; -+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; -+ u8 noa_attr_content[32] = { 0x00 }; -+ u32 p2pielen = 0; -+ -+ DBG_88E("[%s]\n", __func__); -+ -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ return; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(padapter, pattrib); -+ -+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); -+ -+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, da, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); -+ pmlmeext->mgnt_seq++; -+ SetFrameSubType(pframe, WIFI_ACTION); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ /* Build P2P action frame header */ -+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); -+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); -+ -+ /* Add P2P IE header */ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Add Status attribute in P2P IE */ -+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); -+ -+ /* Add NoA attribute in P2P IE */ -+ noa_attr_content[0] = 0x1;/* index */ -+ noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */ -+ -+ /* todo: Notice of Absence Descriptor(s) */ -+ -+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content); -+ -+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &(pattrib->pktlen)); -+ -+ pattrib->last_txcmdsz = pattrib->pktlen; -+ -+ dump_mgntframe(padapter, pmgntframe); -+} -+ -+u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -+{ -+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; -+ u16 capability = 0; -+ u32 len = 0, p2pielen = 0; -+ __le16 le_tmp; -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* According to the P2P Specification, the beacon frame should contain 3 P2P attributes */ -+ /* 1. P2P Capability */ -+ /* 2. P2P Device ID */ -+ /* 3. Notice of Absence (NOA) */ -+ -+ /* P2P Capability ATTR */ -+ /* Type: */ -+ /* Length: */ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ /* Be able to participate in additional P2P Groups and */ -+ /* support the P2P Invitation Procedure */ -+ /* Group Capability Bitmap, 1 byte */ -+ capability = P2P_DEVCAP_INVITATION_PROC|P2P_DEVCAP_CLIENT_DISCOVERABILITY; -+ capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8); -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) -+ capability |= (P2P_GRPCAP_GROUP_FORMATION<<8); -+ -+ le_tmp = cpu_to_le16(capability); -+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8 *)&le_tmp); -+ -+ /* P2P Device ID ATTR */ -+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr); -+ -+ /* Notice of Absence ATTR */ -+ /* Type: */ -+ /* Length: */ -+ /* Value: */ -+ -+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); -+ return len; -+} -+ -+u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -+{ -+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; -+ u32 len = 0, p2pielen = 0; -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20100907 */ -+ /* According to the P2P Specification, the probe response frame should contain 5 P2P attributes */ -+ /* 1. P2P Capability */ -+ /* 2. Extended Listen Timing */ -+ /* 3. Notice of Absence (NOA) (Only GO needs this) */ -+ /* 4. Device Info */ -+ /* 5. Group Info (Only GO need this) */ -+ -+ /* P2P Capability ATTR */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; -+ -+ /* Length: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ -+ RTW_PUT_LE16(p2pie + p2pielen, 0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; -+ -+ /* Group Capability Bitmap, 1 byte */ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ p2pie[p2pielen] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS); -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) -+ p2pie[p2pielen] |= P2P_GRPCAP_GROUP_FORMATION; -+ -+ p2pielen++; -+ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { -+ /* Group Capability Bitmap, 1 byte */ -+ if (pwdinfo->persistent_supported) -+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; -+ else -+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; -+ } -+ -+ /* Extended Listen Timing ATTR */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; -+ -+ /* Length: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */ -+ RTW_PUT_LE16(p2pie + p2pielen, 0x0004); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Availability Period */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ -+ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); -+ p2pielen += 2; -+ -+ /* Availability Interval */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ -+ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); -+ p2pielen += 2; -+ -+ /* Notice of Absence ATTR */ -+ /* Type: */ -+ /* Length: */ -+ /* Value: */ -+ -+ /* Device Info ATTR */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; -+ -+ /* Length: */ -+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ -+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ -+ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Config Method */ -+ /* This field should be big endian. Noted by P2P specification. */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */ -+ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm); -+ p2pielen += 2; -+ -+ /* Primary Device Type */ -+ /* Category ID */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); -+ p2pielen += 2; -+ -+ /* OUI */ -+ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ -+ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); -+ p2pielen += 4; -+ -+ /* Sub Category ID */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); -+ p2pielen += 2; -+ -+ /* Number of Secondary Device Types */ -+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ -+ -+ /* Device Name */ -+ /* Type: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); -+ p2pielen += 2; -+ -+ /* Length: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ -+ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); -+ p2pielen += pwdinfo->device_name_len; -+ -+ /* Group Info ATTR */ -+ /* Type: */ -+ /* Length: */ -+ /* Value: */ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) -+ p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen); -+ -+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); -+ -+ return len; -+} -+ -+u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 *pssid, u8 ussidlen, u8 *pdev_raddr) -+{ -+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; -+ u32 len = 0, p2pielen = 0; -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* Commented by Albert 20110301 */ -+ /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ -+ /* 1. P2P Capability */ -+ /* 2. Device Info */ -+ /* 3. Group ID (When joining an operating P2P Group) */ -+ -+ /* P2P Capability ATTR */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; -+ -+ /* Length: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ -+ RTW_PUT_LE16(p2pie + p2pielen, 0x0002); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* Device Capability Bitmap, 1 byte */ -+ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; -+ -+ /* Group Capability Bitmap, 1 byte */ -+ if (pwdinfo->persistent_supported) -+ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; -+ else -+ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; -+ -+ /* Device Info ATTR */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; -+ -+ /* Length: */ -+ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ -+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ -+ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ /* P2P Device Address */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ /* Config Method */ -+ /* This field should be big endian. Noted by P2P specification. */ -+ if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) { -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC); -+ } else { -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY); -+ } -+ -+ p2pielen += 2; -+ -+ /* Primary Device Type */ -+ /* Category ID */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); -+ p2pielen += 2; -+ -+ /* OUI */ -+ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ -+ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); -+ p2pielen += 4; -+ -+ /* Sub Category ID */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); -+ p2pielen += 2; -+ -+ /* Number of Secondary Device Types */ -+ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ -+ -+ /* Device Name */ -+ /* Type: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ -+ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); -+ p2pielen += 2; -+ -+ /* Length: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ -+ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); -+ p2pielen += pwdinfo->device_name_len; -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { -+ /* Added by Albert 2011/05/19 */ -+ /* In this case, the pdev_raddr is the device address of the group owner. */ -+ -+ /* P2P Group ID ATTR */ -+ /* Type: */ -+ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; -+ -+ /* Length: */ -+ /* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */ -+ RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen); -+ p2pielen += 2; -+ -+ /* Value: */ -+ memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN); -+ p2pielen += ETH_ALEN; -+ -+ memcpy(p2pie + p2pielen, pssid, ussidlen); -+ p2pielen += ussidlen; -+ } -+ -+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); -+ -+ return len; -+} -+ -+u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code) -+{ -+ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; -+ u32 len = 0, p2pielen = 0; -+ -+ /* P2P OUI */ -+ p2pielen = 0; -+ p2pie[p2pielen++] = 0x50; -+ p2pie[p2pielen++] = 0x6F; -+ p2pie[p2pielen++] = 0x9A; -+ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ -+ -+ /* According to the P2P Specification, the Association response frame should contain 2 P2P attributes */ -+ /* 1. Status */ -+ /* 2. Extended Listen Timing (optional) */ -+ -+ /* Status ATTR */ -+ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code); -+ -+ /* Extended Listen Timing ATTR */ -+ /* Type: */ -+ /* Length: */ -+ /* Value: */ -+ -+ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); -+ -+ return len; -+} -+ -+u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) -+{ -+ u32 len = 0; -+ -+ return len; -+} -+ -+u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ u8 *p; -+ u32 ret = false; -+ u8 *p2pie; -+ u32 p2pielen = 0; -+ int ssid_len = 0, rate_cnt = 0; -+ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt, -+ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); -+ -+ if (rate_cnt <= 4) { -+ int i, g_rate = 0; -+ -+ for (i = 0; i < rate_cnt; i++) { -+ if (((*(p + 2 + i) & 0xff) != 0x02) && -+ ((*(p + 2 + i) & 0xff) != 0x04) && -+ ((*(p + 2 + i) & 0xff) != 0x0B) && -+ ((*(p + 2 + i) & 0xff) != 0x16)) -+ g_rate = 1; -+ } -+ -+ if (g_rate == 0) { -+ /* There is no OFDM rate included in SupportedRates IE of this probe request frame */ -+ /* The driver should response this probe request. */ -+ return ret; -+ } -+ } else { -+ /* rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */ -+ /* We should proceed the following check for this probe request. */ -+ } -+ -+ /* Added comments by Albert 20100906 */ -+ /* There are several items we should check here. */ -+ /* 1. This probe request frame must contain the P2P IE. (Done) */ -+ /* 2. This probe request frame must contain the wildcard SSID. (Done) */ -+ /* 3. Wildcard BSSID. (Todo) */ -+ /* 4. Destination Address. (Done in mgt_dispatcher function) */ -+ /* 5. Requested Device Type in WSC IE. (Todo) */ -+ /* 6. Device ID attribute in P2P IE. (Todo) */ -+ -+ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len, -+ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); -+ -+ ssid_len &= 0xff; /* Just last 1 byte is valid for ssid len of the probe request */ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_ , len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_ , NULL, &p2pielen); -+ if (p2pie) { -+ if ((p != NULL) && !memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid , 7)) { -+ /* todo: */ -+ /* Check Requested Device Type attributes in WSC IE. */ -+ /* Check Device ID attribute in P2P IE */ -+ -+ ret = true; -+ } else if ((p != NULL) && (ssid_len == 0)) { -+ ret = true; -+ } -+ } else { -+ /* non -p2p device */ -+ } -+ } -+ -+ return ret; -+} -+ -+u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta) -+{ -+ u8 status_code = P2P_STATUS_SUCCESS; -+ u8 *pbuf, *pattr_content = NULL; -+ u32 attr_contentlen = 0; -+ u16 cap_attr = 0; -+ unsigned short frame_type, ie_offset = 0; -+ u8 *ies; -+ u32 ies_len; -+ u8 *p2p_ie; -+ u32 p2p_ielen = 0; -+ __be16 be_tmp; -+ __le16 le_tmp; -+ -+ if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) -+ return P2P_STATUS_FAIL_REQUEST_UNABLE; -+ -+ frame_type = GetFrameSubType(pframe); -+ if (frame_type == WIFI_ASSOCREQ) -+ ie_offset = _ASOCREQ_IE_OFFSET_; -+ else /* WIFI_REASSOCREQ */ -+ ie_offset = _REASOCREQ_IE_OFFSET_; -+ -+ ies = pframe + WLAN_HDR_A3_LEN + ie_offset; -+ ies_len = len - WLAN_HDR_A3_LEN - ie_offset; -+ -+ p2p_ie = rtw_get_p2p_ie(ies , ies_len , NULL, &p2p_ielen); -+ -+ if (!p2p_ie) { -+ DBG_88E("[%s] P2P IE not Found!!\n", __func__); -+ status_code = P2P_STATUS_FAIL_INVALID_PARAM; -+ } else { -+ DBG_88E("[%s] P2P IE Found!!\n", __func__); -+ } -+ -+ while (p2p_ie) { -+ /* Check P2P Capability ATTR */ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&le_tmp, (uint *)&attr_contentlen)) { -+ DBG_88E("[%s] Got P2P Capability Attr!!\n", __func__); -+ cap_attr = le16_to_cpu(le_tmp); -+ psta->dev_cap = cap_attr&0xff; -+ } -+ -+ /* Check Extended Listen Timing ATTR */ -+ -+ /* Check P2P Device Info ATTR */ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint *)&attr_contentlen)) { -+ DBG_88E("[%s] Got P2P DEVICE INFO Attr!!\n", __func__); -+ pattr_content = rtw_zmalloc(attr_contentlen); -+ pbuf = pattr_content; -+ if (pattr_content) { -+ u8 num_of_secdev_type; -+ u16 dev_name_len; -+ -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO , pattr_content, (uint *)&attr_contentlen); -+ -+ memcpy(psta->dev_addr, pattr_content, ETH_ALEN);/* P2P Device Address */ -+ -+ pattr_content += ETH_ALEN; -+ -+ memcpy(&be_tmp, pattr_content, 2);/* Config Methods */ -+ psta->config_methods = be16_to_cpu(be_tmp); -+ -+ pattr_content += 2; -+ -+ memcpy(psta->primary_dev_type, pattr_content, 8); -+ -+ pattr_content += 8; -+ -+ num_of_secdev_type = *pattr_content; -+ pattr_content += 1; -+ -+ if (num_of_secdev_type == 0) { -+ psta->num_of_secdev_type = 0; -+ } else { -+ u32 len; -+ -+ psta->num_of_secdev_type = num_of_secdev_type; -+ -+ len = (sizeof(psta->secdev_types_list) < (num_of_secdev_type*8)) ? -+ (sizeof(psta->secdev_types_list)) : (num_of_secdev_type*8); -+ -+ memcpy(psta->secdev_types_list, pattr_content, len); -+ -+ pattr_content += (num_of_secdev_type*8); -+ } -+ -+ psta->dev_name_len = 0; -+ if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(__be16 *)pattr_content)) { -+ dev_name_len = be16_to_cpu(*(__be16 *)(pattr_content+2)); -+ -+ psta->dev_name_len = (sizeof(psta->dev_name) < dev_name_len) ? sizeof(psta->dev_name) : dev_name_len; -+ -+ memcpy(psta->dev_name, pattr_content+4, psta->dev_name_len); -+ } -+ kfree(pbuf); -+ } -+ } -+ -+ /* Get the next P2P IE */ -+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); -+ } -+ -+ return status_code; -+} -+ -+u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ u8 *frame_body; -+ u8 status, dialogToken; -+ struct sta_info *psta = NULL; -+ struct adapter *padapter = pwdinfo->padapter; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 *p2p_ie; -+ u32 p2p_ielen = 0; -+ -+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ dialogToken = frame_body[7]; -+ status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; -+ -+ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); -+ if (p2p_ie) { -+ u8 groupid[38] = { 0x00 }; -+ u8 dev_addr[ETH_ALEN] = { 0x00 }; -+ u32 attr_contentlen = 0; -+ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { -+ if (!memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) && -+ !memcmp(pwdinfo->p2p_group_ssid, groupid+ETH_ALEN, pwdinfo->p2p_group_ssid_len)) { -+ attr_contentlen = 0; -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) { -+ struct list_head *phead, *plist; -+ -+ spin_lock_bh(&pstapriv->asoc_list_lock); -+ phead = &pstapriv->asoc_list; -+ plist = phead->next; -+ -+ /* look up sta asoc_queue */ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, asoc_list); -+ -+ plist = plist->next; -+ -+ if (psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) && -+ !memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) { -+ /* issue GO Discoverability Request */ -+ issue_group_disc_req(pwdinfo, psta->hwaddr); -+ status = P2P_STATUS_SUCCESS; -+ break; -+ } else { -+ status = P2P_STATUS_FAIL_INFO_UNAVAILABLE; -+ } -+ } -+ spin_unlock_bh(&pstapriv->asoc_list_lock); -+ } else { -+ status = P2P_STATUS_FAIL_INVALID_PARAM; -+ } -+ } else { -+ status = P2P_STATUS_FAIL_INVALID_PARAM; -+ } -+ } -+ } -+ -+ /* issue Device Discoverability Response */ -+ issue_p2p_devdisc_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken); -+ -+ return (status == P2P_STATUS_SUCCESS) ? true : false; -+} -+ -+u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ return true; -+} -+ -+u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ u8 *frame_body; -+ u8 *wpsie; -+ uint wps_ielen = 0, attr_contentlen = 0; -+ u16 uconfig_method = 0; -+ __be16 be_tmp; -+ -+ frame_body = (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ wpsie = rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen); -+ if (wpsie) { -+ if (rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD, (u8 *)&be_tmp, &attr_contentlen)) { -+ uconfig_method = be16_to_cpu(be_tmp); -+ switch (uconfig_method) { -+ case WPS_CM_DISPLYA: -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); -+ break; -+ case WPS_CM_LABEL: -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "lab", 3); -+ break; -+ case WPS_CM_PUSH_BUTTON: -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); -+ break; -+ case WPS_CM_KEYPAD: -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); -+ break; -+ } -+ issue_p2p_provision_resp(pwdinfo, GetAddr2Ptr(pframe), frame_body, uconfig_method); -+ } -+ } -+ DBG_88E("[%s] config method = %s\n", __func__, pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req); -+ return true; -+} -+ -+u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe) -+{ -+ return true; -+} -+ -+static u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list) -+{ -+ u8 i = 0, j = 0; -+ u8 temp = 0; -+ u8 ch_no = 0; -+ ch_content += 3; -+ ch_cnt -= 3; -+ -+ while (ch_cnt > 0) { -+ ch_content += 1; -+ ch_cnt -= 1; -+ temp = *ch_content; -+ for (i = 0 ; i < temp ; i++, j++) -+ peer_ch_list[j] = *(ch_content + 1 + i); -+ ch_content += (temp + 1); -+ ch_cnt -= (temp + 1); -+ ch_no += temp ; -+ } -+ -+ return ch_no; -+} -+ -+static u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned) -+{ -+ int i = 0, j = 0, temp = 0; -+ u8 ch_no = 0; -+ -+ for (i = 0; i < peer_ch_num; i++) { -+ for (j = temp; j < pmlmeext->max_chan_nums; j++) { -+ if (*(peer_ch_list + i) == pmlmeext->channel_set[j].ChannelNum) { -+ ch_list_inclusioned[ch_no++] = *(peer_ch_list + i); -+ temp = j; -+ break; -+ } -+ } -+ } -+ -+ return ch_no; -+} -+ -+u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ struct adapter *padapter = pwdinfo->padapter; -+ u8 result = P2P_STATUS_SUCCESS; -+ u32 p2p_ielen = 0, wps_ielen = 0; -+ u8 *ies; -+ u32 ies_len; -+ u8 *p2p_ie; -+ u8 *wpsie; -+ u16 wps_devicepassword_id = 0x0000; -+ uint wps_devicepassword_id_len = 0; -+ __be16 be_tmp; -+ -+ wpsie = rtw_get_wps_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen); -+ if (wpsie) { -+ /* Commented by Kurt 20120113 */ -+ /* If some device wants to do p2p handshake without sending prov_disc_req */ -+ /* We have to get peer_req_cm from here. */ -+ if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { -+ rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len); -+ wps_devicepassword_id = be16_to_cpu(be_tmp); -+ -+ if (wps_devicepassword_id == WPS_DPID_USER_SPEC) -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); -+ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); -+ else -+ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); -+ } -+ } else { -+ DBG_88E("[%s] WPS IE not Found!!\n", __func__); -+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ return result; -+ } -+ -+ if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) { -+ result = P2P_STATUS_FAIL_INFO_UNAVAILABLE; -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY); -+ return result; -+ } -+ -+ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; -+ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; -+ -+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); -+ -+ if (!p2p_ie) { -+ DBG_88E("[%s] P2P IE not Found!!\n", __func__); -+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ } -+ -+ while (p2p_ie) { -+ u8 attr_content = 0x00; -+ u32 attr_contentlen = 0; -+ u8 ch_content[50] = { 0x00 }; -+ uint ch_cnt = 0; -+ u8 peer_ch_list[50] = { 0x00 }; -+ u8 peer_ch_num = 0; -+ u8 ch_list_inclusioned[50] = { 0x00 }; -+ u8 ch_num_inclusioned = 0; -+ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); -+ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) { -+ DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); -+ pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ -+ -+ if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) { -+ /* Try to match the tie breaker value */ -+ if (pwdinfo->intent == P2P_MAX_INTENT) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; -+ } else { -+ if (attr_content & 0x01) -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ else -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ } -+ } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ } else { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ } -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ /* Store the group id information. */ -+ memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); -+ memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); -+ } -+ } -+ -+ attr_contentlen = 0; -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) { -+ if (attr_contentlen != ETH_ALEN) -+ memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); -+ } -+ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) { -+ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list); -+ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); -+ -+ if (ch_num_inclusioned == 0) { -+ DBG_88E("[%s] No common channel in channel list!\n", __func__); -+ result = P2P_STATUS_FAIL_NO_COMMON_CH; -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ break; -+ } -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, -+ ch_list_inclusioned, ch_num_inclusioned)) { -+ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; -+ attr_contentlen = 0; -+ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) -+ peer_operating_ch = operatingch_info[4]; -+ -+ if (rtw_p2p_is_channel_list_ok(peer_operating_ch, -+ ch_list_inclusioned, ch_num_inclusioned)) { -+ /** -+ * Change our operating channel as peer's for compatibility. -+ */ -+ pwdinfo->operating_channel = peer_operating_ch; -+ DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); -+ } else { -+ /* Take first channel of ch_list_inclusioned as operating channel */ -+ pwdinfo->operating_channel = ch_list_inclusioned[0]; -+ DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); -+ } -+ } -+ } -+ } -+ -+ /* Get the next P2P IE */ -+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); -+ } -+ return result; -+} -+ -+u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ struct adapter *padapter = pwdinfo->padapter; -+ u8 result = P2P_STATUS_SUCCESS; -+ u32 p2p_ielen, wps_ielen; -+ u8 *ies; -+ u32 ies_len; -+ u8 *p2p_ie; -+ -+ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; -+ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; -+ -+ /* Be able to know which one is the P2P GO and which one is P2P client. */ -+ -+ if (rtw_get_wps_ie(ies, ies_len, NULL, &wps_ielen)) { -+ } else { -+ DBG_88E("[%s] WPS IE not Found!!\n", __func__); -+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ } -+ -+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); -+ if (!p2p_ie) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; -+ } else { -+ u8 attr_content = 0x00; -+ u32 attr_contentlen = 0; -+ u8 operatingch_info[5] = { 0x00 }; -+ u8 groupid[38]; -+ u8 peer_ch_list[50] = { 0x00 }; -+ u8 peer_ch_num = 0; -+ u8 ch_list_inclusioned[50] = { 0x00 }; -+ u8 ch_num_inclusioned = 0; -+ -+ while (p2p_ie) { /* Found the P2P IE. */ -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); -+ if (attr_contentlen == 1) { -+ DBG_88E("[%s] Status = %d\n", __func__, attr_content); -+ if (attr_content == P2P_STATUS_SUCCESS) { -+ /* Do nothing. */ -+ } else { -+ if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) { -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY); -+ } else { -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ } -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ result = attr_content; -+ break; -+ } -+ } -+ -+ /* Try to get the peer's interface address */ -+ attr_contentlen = 0; -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) { -+ if (attr_contentlen != ETH_ALEN) -+ memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); -+ } -+ -+ /* Try to get the peer's intent and tie breaker value. */ -+ attr_content = 0x00; -+ attr_contentlen = 0; -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) { -+ DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); -+ pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ -+ -+ if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) { -+ /* Try to match the tie breaker value */ -+ if (pwdinfo->intent == P2P_MAX_INTENT) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ } else { -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ if (attr_content & 0x01) -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ else -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ } -+ } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) { -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ } else { -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ } -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ /* Store the group id information. */ -+ memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); -+ memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); -+ } -+ } -+ -+ /* Try to get the operation channel information */ -+ -+ attr_contentlen = 0; -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { -+ DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); -+ pwdinfo->peer_operating_ch = operatingch_info[4]; -+ } -+ -+ /* Try to get the channel list information */ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) { -+ DBG_88E("[%s] channel list attribute found, len = %d\n", __func__, pwdinfo->channel_list_attr_len); -+ -+ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list); -+ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); -+ -+ if (ch_num_inclusioned == 0) { -+ DBG_88E("[%s] No common channel in channel list!\n", __func__); -+ result = P2P_STATUS_FAIL_NO_COMMON_CH; -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ break; -+ } -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { -+ if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, -+ ch_list_inclusioned, ch_num_inclusioned)) { -+ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; -+ attr_contentlen = 0; -+ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) -+ peer_operating_ch = operatingch_info[4]; -+ -+ if (rtw_p2p_is_channel_list_ok(peer_operating_ch, -+ ch_list_inclusioned, ch_num_inclusioned)) { -+ /** -+ * Change our operating channel as peer's for compatibility. -+ */ -+ pwdinfo->operating_channel = peer_operating_ch; -+ DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); -+ } else { -+ /* Take first channel of ch_list_inclusioned as operating channel */ -+ pwdinfo->operating_channel = ch_list_inclusioned[0]; -+ DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); -+ } -+ } -+ } -+ } else { -+ DBG_88E("[%s] channel list attribute not found!\n", __func__); -+ } -+ -+ /* Try to get the group id information if peer is GO */ -+ attr_contentlen = 0; -+ memset(groupid, 0x00, 38); -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { -+ memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); -+ memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); -+ } -+ -+ /* Get the next P2P IE */ -+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); -+ } -+ } -+ return result; -+} -+ -+u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ u8 *ies; -+ u32 ies_len; -+ u8 *p2p_ie; -+ u32 p2p_ielen = 0; -+ u8 result = P2P_STATUS_SUCCESS; -+ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; -+ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; -+ -+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); -+ while (p2p_ie) { /* Found the P2P IE. */ -+ u8 attr_content = 0x00, operatingch_info[5] = { 0x00 }; -+ u8 groupid[38] = { 0x00 }; -+ u32 attr_contentlen = 0; -+ -+ pwdinfo->negotiation_dialog_token = 1; -+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); -+ if (attr_contentlen == 1) { -+ DBG_88E("[%s] Status = %d\n", __func__, attr_content); -+ result = attr_content; -+ -+ if (attr_content == P2P_STATUS_SUCCESS) { -+ u8 bcancelled = 0; -+ -+ _cancel_timer(&pwdinfo->restore_p2p_state_timer, &bcancelled); -+ -+ /* Commented by Albert 20100911 */ -+ /* Todo: Need to handle the case which both Intents are the same. */ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1)) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ } else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1)) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ } else { -+ /* Have to compare the Tie Breaker */ -+ if (pwdinfo->peer_intent & 0x01) -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ else -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ } -+ } else { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); -+ break; -+ } -+ } -+ -+ /* Try to get the group id information */ -+ attr_contentlen = 0; -+ memset(groupid, 0x00, 38); -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { -+ DBG_88E("[%s] Ssid = %s, ssidlen = %zu\n", __func__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN])); -+ memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); -+ memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); -+ } -+ -+ attr_contentlen = 0; -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { -+ DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); -+ pwdinfo->peer_operating_ch = operatingch_info[4]; -+ } -+ -+ /* Get the next P2P IE */ -+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); -+ } -+ return result; -+} -+ -+u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) -+{ -+ u8 *frame_body; -+ u8 dialogToken = 0; -+ u8 status = P2P_STATUS_SUCCESS; -+ -+ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); -+ -+ dialogToken = frame_body[6]; -+ -+ /* todo: check NoA attribute */ -+ -+ issue_p2p_presence_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken); -+ -+ return true; -+} -+ -+static void find_phase_handler(struct adapter *padapter) -+{ -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct ndis_802_11_ssid ssid; -+ -+ memset((unsigned char *)&ssid, 0, sizeof(struct ndis_802_11_ssid)); -+ memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN); -+ ssid.SsidLength = P2P_WILDCARD_SSID_LEN; -+ -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ spin_unlock_bh(&pmlmepriv->lock); -+ -+} -+ -+void p2p_concurrent_handler(struct adapter *padapter); -+ -+static void restore_p2p_state_handler(struct adapter *padapter) -+{ -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); -+ -+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { -+ /* In the P2P client mode, the driver should not switch back to its listen channel */ -+ /* because this P2P client should stay at the operating channel of P2P GO. */ -+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ } -+ -+} -+ -+static void pre_tx_invitereq_handler(struct adapter *padapter) -+{ -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ u8 val8 = 1; -+ -+ set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); -+ issue_probereq_p2p(padapter, NULL); -+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); -+ -+} -+ -+static void pre_tx_provdisc_handler(struct adapter *padapter) -+{ -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ u8 val8 = 1; -+ -+ set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); -+ issue_probereq_p2p(padapter, NULL); -+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); -+ -+} -+ -+static void pre_tx_negoreq_handler(struct adapter *padapter) -+{ -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ u8 val8 = 1; -+ -+ set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); -+ issue_probereq_p2p(padapter, NULL); -+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); -+ -+} -+ -+void p2p_protocol_wk_hdl(struct adapter *padapter, int intCmdType) -+{ -+ -+ switch (intCmdType) { -+ case P2P_FIND_PHASE_WK: -+ find_phase_handler(padapter); -+ break; -+ case P2P_RESTORE_STATE_WK: -+ restore_p2p_state_handler(padapter); -+ break; -+ case P2P_PRE_TX_PROVDISC_PROCESS_WK: -+ pre_tx_provdisc_handler(padapter); -+ break; -+ case P2P_PRE_TX_INVITEREQ_PROCESS_WK: -+ pre_tx_invitereq_handler(padapter); -+ break; -+ case P2P_PRE_TX_NEGOREQ_PROCESS_WK: -+ pre_tx_negoreq_handler(padapter); -+ break; -+ } -+ -+} -+ -+void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength) -+{ -+ u8 *ies; -+ u32 ies_len; -+ u8 *p2p_ie; -+ u32 p2p_ielen = 0; -+ u8 noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */ -+ u32 attr_contentlen = 0; -+ -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ u8 find_p2p = false, find_p2p_ps = false; -+ u8 noa_offset, noa_num, noa_index; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return; -+ if (IELength <= _BEACON_IE_OFFSET_) -+ return; -+ -+ ies = IEs + _BEACON_IE_OFFSET_; -+ ies_len = IELength - _BEACON_IE_OFFSET_; -+ -+ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); -+ -+ while (p2p_ie) { -+ find_p2p = true; -+ /* Get Notice of Absence IE. */ -+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) { -+ find_p2p_ps = true; -+ noa_index = noa_attr[0]; -+ -+ if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) || -+ (noa_index != pwdinfo->noa_index)) { /* if index change, driver should reconfigure related setting. */ -+ pwdinfo->noa_index = noa_index; -+ pwdinfo->opp_ps = noa_attr[1] >> 7; -+ pwdinfo->ctwindow = noa_attr[1] & 0x7F; -+ -+ noa_offset = 2; -+ noa_num = 0; -+ /* NoA length should be n*(13) + 2 */ -+ if (attr_contentlen > 2) { -+ while (noa_offset < attr_contentlen) { -+ /* memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */ -+ pwdinfo->noa_count[noa_num] = noa_attr[noa_offset]; -+ noa_offset += 1; -+ -+ memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4); -+ noa_offset += 4; -+ -+ memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4); -+ noa_offset += 4; -+ -+ memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4); -+ noa_offset += 4; -+ -+ noa_num++; -+ } -+ } -+ pwdinfo->noa_num = noa_num; -+ -+ if (pwdinfo->opp_ps == 1) { -+ pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW; -+ /* driver should wait LPS for entering CTWindow */ -+ if (padapter->pwrctrlpriv.bFwCurrentInPSMode) -+ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); -+ } else if (pwdinfo->noa_num > 0) { -+ pwdinfo->p2p_ps_mode = P2P_PS_NOA; -+ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); -+ } else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { -+ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); -+ } -+ } -+ -+ break; /* find target, just break. */ -+ } -+ -+ /* Get the next P2P IE */ -+ p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); -+ } -+ -+ if (find_p2p) { -+ if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && !find_p2p_ps) -+ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); -+ } -+ -+} -+ -+void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ /* Pre action for p2p state */ -+ switch (p2p_ps_state) { -+ case P2P_PS_DISABLE: -+ pwdinfo->p2p_ps_state = p2p_ps_state; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); -+ -+ pwdinfo->noa_index = 0; -+ pwdinfo->ctwindow = 0; -+ pwdinfo->opp_ps = 0; -+ pwdinfo->noa_num = 0; -+ pwdinfo->p2p_ps_mode = P2P_PS_NONE; -+ if (padapter->pwrctrlpriv.bFwCurrentInPSMode) { -+ if (pwrpriv->smart_ps == 0) { -+ pwrpriv->smart_ps = 2; -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(padapter->pwrctrlpriv.pwr_mode))); -+ } -+ } -+ break; -+ case P2P_PS_ENABLE: -+ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { -+ pwdinfo->p2p_ps_state = p2p_ps_state; -+ -+ if (pwdinfo->ctwindow > 0) { -+ if (pwrpriv->smart_ps != 0) { -+ pwrpriv->smart_ps = 0; -+ DBG_88E("%s(): Enter CTW, change SmartPS\n", __func__); -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(padapter->pwrctrlpriv.pwr_mode))); -+ } -+ } -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); -+ } -+ break; -+ case P2P_PS_SCAN: -+ case P2P_PS_SCAN_DONE: -+ case P2P_PS_ALLSTASLEEP: -+ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { -+ pwdinfo->p2p_ps_state = p2p_ps_state; -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); -+ } -+ break; -+ default: -+ break; -+ } -+ -+} -+ -+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue) -+{ -+ struct cmd_obj *ph2c; -+ struct drvextra_cmd_parm *pdrvextra_cmd_parm; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -+ u8 res = _SUCCESS; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return res; -+ -+ if (enqueue) { -+ ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); -+ if (ph2c == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); -+ if (pdrvextra_cmd_parm == NULL) { -+ kfree(ph2c); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID; -+ pdrvextra_cmd_parm->type_size = p2p_ps_state; -+ pdrvextra_cmd_parm->pbuf = NULL; -+ -+ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); -+ -+ res = rtw_enqueue_cmd(pcmdpriv, ph2c); -+ } else { -+ p2p_ps_wk_hdl(padapter, p2p_ps_state); -+ } -+ -+exit: -+ -+ return res; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+static void reset_ch_sitesurvey_timer_process(struct timer_list *t) -+#else -+static void reset_ch_sitesurvey_timer_process (void *FunctionContext) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct adapter *adapter = from_timer(adapter, t, pwrctrlpriv.pwr_state_check_timer); -+#else -+ struct adapter *adapter = (struct adapter *)FunctionContext; -+#endif -+ struct wifidirect_info *pwdinfo = &adapter->wdinfo; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return; -+ -+ DBG_88E("[%s] In\n", __func__); -+ /* Reset the operation channel information */ -+ pwdinfo->rx_invitereq_info.operation_ch[0] = 0; -+ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+static void reset_ch_sitesurvey_timer_process2 (struct timer_list *t) -+#else -+static void reset_ch_sitesurvey_timer_process2 (void *FunctionContext) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct adapter *adapter = from_timer(adapter, t, pwrctrlpriv.pwr_state_check_timer); -+#else -+ struct adapter *adapter = (struct adapter *)FunctionContext; -+#endif -+ struct wifidirect_info *pwdinfo = &adapter->wdinfo; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return; -+ -+ DBG_88E("[%s] In\n", __func__); -+ /* Reset the operation channel information */ -+ pwdinfo->p2p_info.operation_ch[0] = 0; -+ pwdinfo->p2p_info.scan_op_ch_only = 0; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+static void restore_p2p_state_timer_process(struct timer_list *t) -+#else -+static void restore_p2p_state_timer_process (void *FunctionContext) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct adapter *adapter = from_timer(adapter, t, wdinfo.restore_p2p_state_timer); -+#else -+ struct adapter *adapter = (struct adapter *)FunctionContext; -+#endif -+ struct wifidirect_info *pwdinfo = &adapter->wdinfo; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return; -+ -+ p2p_protocol_wk_cmd(adapter, P2P_RESTORE_STATE_WK); -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+static void pre_tx_scan_timer_process(struct timer_list *t) -+#else -+static void pre_tx_scan_timer_process(void *FunctionContext) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct adapter *adapter = from_timer(adapter, t, wdinfo.pre_tx_scan_timer); -+#else -+ struct adapter *adapter = (struct adapter *)FunctionContext; -+#endif -+ struct wifidirect_info *pwdinfo = &adapter->wdinfo; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return; -+ -+ spin_lock_bh(&pmlmepriv->lock); -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { -+ if (pwdinfo->tx_prov_disc_info.benable) { /* the provision discovery request frame is trigger to send or not */ -+ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK); -+ /* issue_probereq_p2p(adapter, NULL); */ -+ /* _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); */ -+ } -+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { -+ if (pwdinfo->nego_req_info.benable) -+ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK); -+ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { -+ if (pwdinfo->invitereq_info.benable) -+ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK); -+ } else { -+ DBG_88E("[%s] p2p_state is %d, ignore!!\n", __func__, rtw_p2p_state(pwdinfo)); -+ } -+ -+ spin_unlock_bh(&pmlmepriv->lock); -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+static void find_phase_timer_process(struct timer_list *t) -+#else -+static void find_phase_timer_process(void *FunctionContext) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct adapter *adapter = from_timer(adapter, t, wdinfo.find_phase_timer); -+#else -+ struct adapter *adapter = (struct adapter *)FunctionContext; -+#endif -+ struct wifidirect_info *pwdinfo = &adapter->wdinfo; -+ -+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return; -+ -+ adapter->wdinfo.find_phase_state_exchange_cnt++; -+ -+ p2p_protocol_wk_cmd(adapter, P2P_FIND_PHASE_WK); -+} -+ -+void reset_global_wifidirect_info(struct adapter *padapter) -+{ -+ struct wifidirect_info *pwdinfo; -+ -+ pwdinfo = &padapter->wdinfo; -+ pwdinfo->persistent_supported = 0; -+ pwdinfo->session_available = true; -+ pwdinfo->wfd_tdls_enable = 0; -+ pwdinfo->wfd_tdls_weaksec = 0; -+} -+ -+void rtw_init_wifidirect_timers(struct adapter *padapter) -+{ -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ timer_setup(&pwdinfo->find_phase_timer, find_phase_timer_process, 0); -+ timer_setup(&pwdinfo->restore_p2p_state_timer, restore_p2p_state_timer_process, 0); -+ timer_setup(&pwdinfo->pre_tx_scan_timer, pre_tx_scan_timer_process, 0); -+ timer_setup(&pwdinfo->reset_ch_sitesurvey, reset_ch_sitesurvey_timer_process, 0); -+ timer_setup(&pwdinfo->reset_ch_sitesurvey2, reset_ch_sitesurvey_timer_process2, 0); -+#else -+ _init_timer(&pwdinfo->find_phase_timer, padapter->pnetdev, find_phase_timer_process, padapter); -+ _init_timer(&pwdinfo->restore_p2p_state_timer, padapter->pnetdev, restore_p2p_state_timer_process, padapter); -+ _init_timer(&pwdinfo->pre_tx_scan_timer, padapter->pnetdev, pre_tx_scan_timer_process, padapter); -+ _init_timer(&pwdinfo->reset_ch_sitesurvey, padapter->pnetdev, reset_ch_sitesurvey_timer_process, padapter); -+ _init_timer(&pwdinfo->reset_ch_sitesurvey2, padapter->pnetdev, reset_ch_sitesurvey_timer_process2, padapter); -+#endif -+} -+ -+void rtw_init_wifidirect_addrs(struct adapter *padapter, u8 *dev_addr, u8 *iface_addr) -+{ -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ -+ /*init device&interface address */ -+ if (dev_addr) -+ memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN); -+ if (iface_addr) -+ memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN); -+#endif -+} -+ -+void init_wifidirect_info(struct adapter *padapter, enum P2P_ROLE role) -+{ -+ struct wifidirect_info *pwdinfo; -+ -+ pwdinfo = &padapter->wdinfo; -+ pwdinfo->padapter = padapter; -+ -+ /* 1, 6, 11 are the social channel defined in the WiFi Direct specification. */ -+ pwdinfo->social_chan[0] = 1; -+ pwdinfo->social_chan[1] = 6; -+ pwdinfo->social_chan[2] = 11; -+ pwdinfo->social_chan[3] = 0; /* channel 0 for scanning ending in site survey function. */ -+ -+ /* Use the channel 11 as the listen channel */ -+ pwdinfo->listen_channel = 11; -+ -+ if (role == P2P_ROLE_DEVICE) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); -+ pwdinfo->intent = 1; -+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN); -+ } else if (role == P2P_ROLE_CLIENT) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ pwdinfo->intent = 1; -+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ } else if (role == P2P_ROLE_GO) { -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ pwdinfo->intent = 15; -+ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); -+ } -+ -+/* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ -+ pwdinfo->support_rate[0] = 0x8c; /* 6(B) */ -+ pwdinfo->support_rate[1] = 0x92; /* 9(B) */ -+ pwdinfo->support_rate[2] = 0x18; /* 12 */ -+ pwdinfo->support_rate[3] = 0x24; /* 18 */ -+ pwdinfo->support_rate[4] = 0x30; /* 24 */ -+ pwdinfo->support_rate[5] = 0x48; /* 36 */ -+ pwdinfo->support_rate[6] = 0x60; /* 48 */ -+ pwdinfo->support_rate[7] = 0x6c; /* 54 */ -+ -+ memcpy(pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7); -+ -+ memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN); -+ pwdinfo->device_name_len = 0; -+ -+ memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info)); -+ pwdinfo->invitereq_info.token = 3; /* Token used for P2P invitation request frame. */ -+ -+ memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info)); -+ pwdinfo->inviteresp_info.token = 0; -+ -+ pwdinfo->profileindex = 0; -+ memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM); -+ -+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); -+ -+ pwdinfo->listen_dwell = (u8) ((jiffies % 3) + 1); -+ -+ memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info)); -+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE; -+ -+ memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info)); -+ -+ pwdinfo->device_password_id_for_nego = WPS_DPID_PBC; -+ pwdinfo->negotiation_dialog_token = 1; -+ -+ memset(pwdinfo->nego_ssid, 0x00, WLAN_SSID_MAXLEN); -+ pwdinfo->nego_ssidlen = 0; -+ -+ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; -+ pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD; -+ pwdinfo->channel_list_attr_len = 0; -+ memset(pwdinfo->channel_list_attr, 0x00, 100); -+ -+ memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4); -+ memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3); -+ memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); -+ pwdinfo->wfd_tdls_enable = 0; -+ memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); -+ memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN); -+ -+ pwdinfo->rx_invitereq_info.operation_ch[0] = 0; -+ pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ -+ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; -+ pwdinfo->p2p_info.operation_ch[0] = 0; -+ pwdinfo->p2p_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ -+ pwdinfo->p2p_info.scan_op_ch_only = 0; -+} -+ -+int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role) -+{ -+ int ret = _SUCCESS; -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+ -+ if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) { -+ /* leave IPS/Autosuspend */ -+ if (_FAIL == rtw_pwr_wakeup(padapter)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* Added by Albert 2011/03/22 */ -+ /* In the P2P mode, the driver should not support the b mode. */ -+ /* So, the Tx packet shouldn't use the CCK rate */ -+ update_tx_basic_rate(padapter, WIRELESS_11AGN); -+ -+ /* Enable P2P function */ -+ init_wifidirect_info(padapter, role); -+ -+ rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, true); -+ } else if (role == P2P_ROLE_DISABLE) { -+ if (_FAIL == rtw_pwr_wakeup(padapter)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* Disable P2P function */ -+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { -+ _cancel_timer_ex(&pwdinfo->find_phase_timer); -+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); -+ _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer); -+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); -+ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2); -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+#else -+ reset_ch_sitesurvey_timer_process(padapter); -+ reset_ch_sitesurvey_timer_process2(padapter); -+#endif -+ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); -+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE); -+ memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info)); -+ } -+ -+ rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, false); -+ -+ /* Restore to initial setting. */ -+ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); -+ } -+ -+exit: -+ return ret; -+} -+ -+#else -+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue) -+{ -+ return _FAIL; -+} -+ -+void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength) -+{ -+} -+ -+#endif /* CONFIG_88EU_P2P */ -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_pwrctrl.c b/drivers/net/wireless/rtl8188eu/core/rtw_pwrctrl.c -new file mode 100644 -index 0000000000000..50e8b5e6aed81 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_pwrctrl.c -@@ -0,0 +1,655 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_PWRCTRL_C_ -+ -+#include -+#include -+#include -+#include -+ -+void ips_enter(struct adapter *padapter) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ struct xmit_priv *pxmit_priv = &padapter->xmitpriv; -+ -+ if (padapter->registrypriv.mp_mode == 1) -+ return; -+ -+ if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || -+ pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { -+ DBG_88E_LEVEL(_drv_info_, "There are some pkts to transmit\n"); -+ DBG_88E_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", -+ pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); -+ return; -+ } -+ -+ _enter_pwrlock(&pwrpriv->lock); -+ -+ pwrpriv->bips_processing = true; -+ -+ /* syn ips_mode with request */ -+ pwrpriv->ips_mode = pwrpriv->ips_mode_req; -+ -+ pwrpriv->ips_enter_cnts++; -+ DBG_88E("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts); -+ if (rf_off == pwrpriv->change_rfpwrstate) { -+ pwrpriv->bpower_saving = true; -+ DBG_88E_LEVEL(_drv_info_, "nolinked power save enter\n"); -+ -+ if (pwrpriv->ips_mode == IPS_LEVEL_2) -+ pwrpriv->bkeepfwalive = true; -+ -+ rtw_ips_pwr_down(padapter); -+ pwrpriv->rf_pwrstate = rf_off; -+ } -+ pwrpriv->bips_processing = false; -+ -+ _exit_pwrlock(&pwrpriv->lock); -+} -+ -+int ips_leave(struct adapter *padapter) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ struct security_priv *psecuritypriv = &(padapter->securitypriv); -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ int result = _SUCCESS; -+ int keyid; -+ -+ _enter_pwrlock(&pwrpriv->lock); -+ -+ if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) { -+ pwrpriv->bips_processing = true; -+ pwrpriv->change_rfpwrstate = rf_on; -+ pwrpriv->ips_leave_cnts++; -+ DBG_88E("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts); -+ -+ result = rtw_ips_pwr_up(padapter); -+ if (result == _SUCCESS) { -+ pwrpriv->rf_pwrstate = rf_on; -+ } -+ DBG_88E_LEVEL(_drv_info_, "nolinked power save leave\n"); -+ -+ if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) || (_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm)) { -+ DBG_88E("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing); -+ set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); -+ for (keyid = 0; keyid < 4; keyid++) { -+ if (pmlmepriv->key_mask & BIT(keyid)) { -+ if (keyid == psecuritypriv->dot11PrivacyKeyIndex) -+ result = rtw_set_key(padapter, psecuritypriv, keyid, 1); -+ else -+ result = rtw_set_key(padapter, psecuritypriv, keyid, 0); -+ } -+ } -+ } -+ -+ DBG_88E("==> ips_leave.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c)); -+ pwrpriv->bips_processing = false; -+ -+ pwrpriv->bkeepfwalive = false; -+ pwrpriv->bpower_saving = false; -+ } -+ -+ _exit_pwrlock(&pwrpriv->lock); -+ -+ return result; -+} -+ -+static bool rtw_pwr_unassociated_idle(struct adapter *adapter) -+{ -+ struct adapter *buddy = adapter->pbuddy_adapter; -+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(adapter->wdinfo); -+#endif -+ -+ bool ret = false; -+ -+ if (adapter->pwrctrlpriv.ips_deny_time >= jiffies) -+ goto exit; -+ -+ if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || -+ check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) || -+ check_fwstate(pmlmepriv, WIFI_UNDER_WPS) || -+ check_fwstate(pmlmepriv, WIFI_AP_STATE) || -+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) || -+#if defined(CONFIG_88EU_P2P) -+ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+#else -+ 0) -+#endif -+ goto exit; -+ -+ /* consider buddy, if exist */ -+ if (buddy) { -+ struct mlme_priv *b_pmlmepriv = &(buddy->mlmepriv); -+ #ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *b_pwdinfo = &(buddy->wdinfo); -+ #endif -+ -+ if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) || -+ check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) || -+ check_fwstate(b_pmlmepriv, WIFI_AP_STATE) || -+ check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) || -+#if defined(CONFIG_88EU_P2P) -+ !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE)) -+#else -+ 0) -+#endif -+ goto exit; -+ } -+ ret = true; -+ -+exit: -+ return ret; -+} -+ -+void rtw_ps_processor(struct adapter *padapter) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ enum rt_rf_power_state rfpwrstate; -+ -+ pwrpriv->ps_processing = true; -+ -+ if (pwrpriv->bips_processing) -+ goto exit; -+ -+ if (padapter->pwrctrlpriv.bHWPwrPindetect) { -+ rfpwrstate = RfOnOffDetect(padapter); -+ DBG_88E("@@@@- #2 %s==> rfstate:%s\n", __func__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off"); -+ -+ if (rfpwrstate != pwrpriv->rf_pwrstate) { -+ if (rfpwrstate == rf_off) { -+ pwrpriv->change_rfpwrstate = rf_off; -+ pwrpriv->brfoffbyhw = true; -+ padapter->bCardDisableWOHSM = true; -+ rtw_hw_suspend(padapter); -+ } else { -+ pwrpriv->change_rfpwrstate = rf_on; -+ rtw_hw_resume(padapter); -+ } -+ DBG_88E("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on"); -+ } -+ pwrpriv->pwr_state_check_cnts++; -+ } -+ -+ if (pwrpriv->ips_mode_req == IPS_NONE) -+ goto exit; -+ -+ if (!rtw_pwr_unassociated_idle(padapter)) -+ goto exit; -+ -+ if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) { -+ DBG_88E("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv)); -+ pwrpriv->change_rfpwrstate = rf_off; -+ -+ ips_enter(padapter); -+ } -+exit: -+ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); -+ pwrpriv->ps_processing = false; -+ return; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+static void pwr_state_check_handler(struct timer_list *t) -+#else -+static void pwr_state_check_handler(void *FunctionContext) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct adapter *padapter = -+ from_timer(padapter, t, -+ pwrctrlpriv.pwr_state_check_timer); -+#else -+ struct adapter *padapter = (struct adapter *)FunctionContext; -+#endif -+ rtw_ps_cmd(padapter); -+} -+ -+/* -+ * -+ * Parameters -+ * padapter -+ * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 -+ * -+ */ -+void rtw_set_rpwm(struct adapter *padapter, u8 pslv) -+{ -+ u8 rpwm; -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ -+ pslv = PS_STATE(pslv); -+ -+ if (pwrpriv->btcoex_rfon) { -+ if (pslv < PS_STATE_S4) -+ pslv = PS_STATE_S3; -+ } -+ -+ if ((pwrpriv->rpwm == pslv)) { -+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, -+ ("%s: Already set rpwm[0x%02X], new=0x%02X!\n", __func__, pwrpriv->rpwm, pslv)); -+ return; -+ } -+ -+ if ((padapter->bSurpriseRemoved) || -+ (!padapter->hw_init_completed)) { -+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, -+ ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n", -+ __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed)); -+ -+ pwrpriv->cpwm = PS_STATE_S4; -+ -+ return; -+ } -+ -+ if (padapter->bDriverStopped) { -+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, -+ ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv)); -+ -+ if (pslv < PS_STATE_S2) { -+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, -+ ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv)); -+ return; -+ } -+ } -+ -+ rpwm = pslv | pwrpriv->tog; -+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, -+ ("rtw_set_rpwm: rpwm=0x%02x cpwm=0x%02x\n", rpwm, pwrpriv->cpwm)); -+ -+ pwrpriv->rpwm = pslv; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); -+ -+ pwrpriv->tog += 0x80; -+ pwrpriv->cpwm = pslv; -+ -+} -+ -+static u8 PS_RDY_CHECK(struct adapter *padapter) -+{ -+ u32 curr_time, delta_time; -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ -+ curr_time = jiffies; -+ delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp; -+ -+ if (delta_time < LPS_DELAY_TIME) -+ return false; -+ -+ if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) || -+ (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) || -+ (check_fwstate(pmlmepriv, WIFI_AP_STATE)) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) -+ return false; -+ if (pwrpriv->bInSuspend) -+ return false; -+ if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) { -+ DBG_88E("Group handshake still in progress !!!\n"); -+ return false; -+ } -+ return true; -+} -+ -+void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo); -+#endif /* CONFIG_88EU_P2P */ -+ -+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, -+ ("%s: PowerMode=%d Smart_PS=%d\n", -+ __func__, ps_mode, smart_ps)); -+ -+ if (ps_mode > PM_Card_Disable) { -+ RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode)); -+ return; -+ } -+ -+ if (pwrpriv->pwr_mode == ps_mode) { -+ if (PS_MODE_ACTIVE == ps_mode) -+ return; -+ -+ if ((pwrpriv->smart_ps == smart_ps) && -+ (pwrpriv->bcn_ant_mode == bcn_ant_mode)) -+ return; -+ } -+ -+ /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */ -+ if (ps_mode == PS_MODE_ACTIVE) { -+#ifdef CONFIG_88EU_P2P -+ if (pwdinfo->opp_ps == 0) { -+ DBG_88E("rtw_set_ps_mode: Leave 802.11 power save\n"); -+ pwrpriv->pwr_mode = ps_mode; -+ rtw_set_rpwm(padapter, PS_STATE_S4); -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); -+ pwrpriv->bFwCurrentInPSMode = false; -+ } -+ } else { -+#endif /* CONFIG_88EU_P2P */ -+ if (PS_RDY_CHECK(padapter)) { -+ DBG_88E("%s: Enter 802.11 power save\n", __func__); -+ pwrpriv->bFwCurrentInPSMode = true; -+ pwrpriv->pwr_mode = ps_mode; -+ pwrpriv->smart_ps = smart_ps; -+ pwrpriv->bcn_ant_mode = bcn_ant_mode; -+ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); -+ -+#ifdef CONFIG_88EU_P2P -+ /* Set CTWindow after LPS */ -+ if (pwdinfo->opp_ps == 1) -+ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0); -+#endif /* CONFIG_88EU_P2P */ -+ -+ rtw_set_rpwm(padapter, PS_STATE_S2); -+ } -+ } -+ -+} -+ -+/* -+ * Return: -+ * 0: Leave OK -+ * -1: Timeout -+ * -2: Other error -+ */ -+s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) -+{ -+ u32 start_time; -+ u8 bAwake = false; -+ s32 err = 0; -+ -+ start_time = jiffies; -+ while (1) { -+ rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); -+ if (bAwake) -+ break; -+ -+ if (padapter->bSurpriseRemoved) { -+ err = -2; -+ DBG_88E("%s: device surprise removed!!\n", __func__); -+ break; -+ } -+ -+ if (rtw_get_passing_time_ms(start_time) > delay_ms) { -+ err = -1; -+ DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); -+ break; -+ } -+ rtw_usleep_os(100); -+ } -+ -+ return err; -+} -+ -+/* */ -+/* Description: */ -+/* Enter the leisure power save mode. */ -+/* */ -+void LPS_Enter(struct adapter *padapter) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ -+ if (PS_RDY_CHECK(padapter) == false) -+ return; -+ -+ if (pwrpriv->bLeisurePs) { -+ /* Idle for a while if we connect to AP a while ago. */ -+ if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ -+ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { -+ pwrpriv->bpower_saving = true; -+ DBG_88E("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps); -+ /* For Tenda W311R IOT issue */ -+ rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, -+ pwrpriv->smart_ps, 0x40); -+ } -+ } else { -+ pwrpriv->LpsIdleCount++; -+ } -+ } -+ -+} -+ -+#define LPS_LEAVE_TIMEOUT_MS 100 -+ -+/* Description: */ -+/* Leave the leisure power save mode. */ -+void LPS_Leave(struct adapter *padapter) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ -+ if (pwrpriv->bLeisurePs) { -+ if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { -+ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0x40); -+ -+ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) -+ LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS); -+ } -+ } -+ -+ pwrpriv->bpower_saving = false; -+ -+} -+ -+/* */ -+/* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */ -+/* Move code to function by tynli. 2010.03.26. */ -+/* */ -+void LeaveAllPowerSaveMode(struct adapter *Adapter) -+{ -+ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); -+ u8 enqueue = 0; -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */ -+ p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue); -+ -+ rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); -+ } -+ -+} -+ -+void rtw_init_pwrctrl_priv(struct adapter *padapter) -+{ -+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; -+ -+ _init_pwrlock(&pwrctrlpriv->lock); -+ pwrctrlpriv->rf_pwrstate = rf_on; -+ pwrctrlpriv->ips_enter_cnts = 0; -+ pwrctrlpriv->ips_leave_cnts = 0; -+ pwrctrlpriv->bips_processing = false; -+ -+ pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; -+ pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; -+ -+ pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; -+ pwrctrlpriv->pwr_state_check_cnts = 0; -+ pwrctrlpriv->bInternalAutoSuspend = false; -+ pwrctrlpriv->bInSuspend = false; -+ pwrctrlpriv->bkeepfwalive = false; -+ -+ pwrctrlpriv->LpsIdleCount = 0; -+ if (padapter->registrypriv.mp_mode == 1) -+ pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE ; -+ else -+ pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ -+ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; -+ -+ pwrctrlpriv->bFwCurrentInPSMode = false; -+ -+ pwrctrlpriv->rpwm = 0; -+ pwrctrlpriv->cpwm = PS_STATE_S4; -+ -+ pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; -+ pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; -+ pwrctrlpriv->bcn_ant_mode = 0; -+ -+ pwrctrlpriv->tog = 0x80; -+ -+ pwrctrlpriv->btcoex_rfon = false; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ timer_setup(&pwrctrlpriv->pwr_state_check_timer, pwr_state_check_handler, 0); -+#else -+ _init_timer(&(pwrctrlpriv->pwr_state_check_timer), padapter->pnetdev, pwr_state_check_handler, (u8 *)padapter); -+#endif -+} -+ -+void rtw_free_pwrctrl_priv(struct adapter *adapter) -+{ -+ struct pwrctrl_priv *pwrctrlpriv = &adapter->pwrctrlpriv; -+ -+ _free_pwrlock(&pwrctrlpriv->lock); -+ -+} -+ -+u8 rtw_interface_ps_func(struct adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val) -+{ -+ u8 bResult = true; -+ rtw_hal_intf_ps_func(padapter, efunc_id, val); -+ -+ return bResult; -+} -+ -+inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ms); -+} -+ -+/* -+* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend -+* @adapter: pointer to struct adapter structure -+* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup -+* Return _SUCCESS or _FAIL -+*/ -+ -+int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller) -+{ -+ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ int ret = _SUCCESS; -+ u32 start = jiffies; -+ -+ if (pwrpriv->ips_deny_time < jiffies + rtw_ms_to_systime(ips_deffer_ms)) -+ pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ips_deffer_ms); -+ -+ if (pwrpriv->ps_processing) { -+ DBG_88E("%s wait ps_processing...\n", __func__); -+ while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000) -+ rtw_msleep_os(10); -+ if (pwrpriv->ps_processing) -+ DBG_88E("%s wait ps_processing timeout\n", __func__); -+ else -+ DBG_88E("%s wait ps_processing done\n", __func__); -+ } -+ -+ /* System suspend is not allowed to wakeup */ -+ if ((!pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) { -+ while (pwrpriv->bInSuspend && -+ (rtw_get_passing_time_ms(start) <= 3000 || -+ (rtw_get_passing_time_ms(start) <= 500))) -+ rtw_msleep_os(10); -+ if (pwrpriv->bInSuspend) -+ DBG_88E("%s wait bInSuspend timeout\n", __func__); -+ else -+ DBG_88E("%s wait bInSuspend done\n", __func__); -+ } -+ -+ /* block??? */ -+ if ((pwrpriv->bInternalAutoSuspend) && (padapter->net_closed)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* I think this should be check in IPS, LPS, autosuspend functions... */ -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) { -+ ret = _SUCCESS; -+ goto exit; -+ } -+ if (rf_off == pwrpriv->rf_pwrstate) { -+ DBG_88E("%s call ips_leave....\n", __func__); -+ if (_FAIL == ips_leave(padapter)) { -+ DBG_88E("======> ips_leave fail.............\n"); -+ ret = _FAIL; -+ goto exit; -+ } -+ } -+ -+ /* TODO: the following checking need to be merged... */ -+ if (padapter->bDriverStopped || !padapter->bup || -+ !padapter->hw_init_completed) { -+ DBG_88E("%s: bDriverStopped=%d, bup=%d, hw_init_completed =%u\n" -+ , caller -+ , padapter->bDriverStopped -+ , padapter->bup -+ , padapter->hw_init_completed); -+ ret = false; -+ goto exit; -+ } -+ -+exit: -+ if (pwrpriv->ips_deny_time < jiffies + rtw_ms_to_systime(ips_deffer_ms)) -+ pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ips_deffer_ms); -+ return ret; -+} -+ -+int rtw_pm_set_lps(struct adapter *padapter, u8 mode) -+{ -+ int ret = 0; -+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; -+ -+ if (mode < PS_MODE_NUM) { -+ if (pwrctrlpriv->power_mgnt != mode) { -+ if (PS_MODE_ACTIVE == mode) -+ LeaveAllPowerSaveMode(padapter); -+ else -+ pwrctrlpriv->LpsIdleCount = 2; -+ pwrctrlpriv->power_mgnt = mode; -+ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; -+ } -+ } else { -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+int rtw_pm_set_ips(struct adapter *padapter, u8 mode) -+{ -+ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; -+ -+ if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { -+ rtw_ips_mode_req(pwrctrlpriv, mode); -+ DBG_88E("%s %s\n", __func__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2"); -+ return 0; -+ } else if (mode == IPS_NONE) { -+ rtw_ips_mode_req(pwrctrlpriv, mode); -+ DBG_88E("%s %s\n", __func__, "IPS_NONE"); -+ if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter))) -+ return -EFAULT; -+ } else { -+ return -EINVAL; -+ } -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_recv.c b/drivers/net/wireless/rtl8188eu/core/rtw_recv.c -new file mode 100644 -index 0000000000000..16a38a2fbe878 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_recv.c -@@ -0,0 +1,2252 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_RECV_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37}; -+static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3}; -+ -+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -+static u8 rtw_bridge_tunnel_header[] = { -+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 -+}; -+ -+static u8 rtw_rfc1042_header[] = { -+ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 -+}; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+void rtw_signal_stat_timer_hdl(struct timer_list *); -+#else -+void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS); -+#endif -+ -+void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) -+{ -+ -+ memset((u8 *)psta_recvpriv, 0, sizeof (struct sta_recv_priv)); -+ -+ spin_lock_init(&psta_recvpriv->lock); -+ -+ _rtw_init_queue(&psta_recvpriv->defrag_q); -+ -+} -+ -+int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) -+{ -+ int i; -+ -+ struct recv_frame *precvframe; -+ -+ int res = _SUCCESS; -+ -+ spin_lock_init(&precvpriv->lock); -+ -+ _rtw_init_queue(&precvpriv->free_recv_queue); -+ _rtw_init_queue(&precvpriv->recv_pending_queue); -+ _rtw_init_queue(&precvpriv->uc_swdec_pending_queue); -+ -+ precvpriv->adapter = padapter; -+ -+ precvpriv->free_recvframe_cnt = NR_RECVFRAME; -+ -+ rtw_os_recv_resource_init(precvpriv, padapter); -+ -+ precvpriv->pallocated_frame_buf = rtw_zvmalloc(NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ); -+ -+ if (precvpriv->pallocated_frame_buf == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); -+ -+ precvframe = (struct recv_frame *)precvpriv->precv_frame_buf; -+ -+ for (i = 0; i < NR_RECVFRAME; i++) { -+ INIT_LIST_HEAD(&(precvframe->list)); -+ -+ list_add_tail(&(precvframe->list), &(precvpriv->free_recv_queue.queue)); -+ -+ res = rtw_os_recv_resource_alloc(padapter, precvframe); -+ -+ precvframe->len = 0; -+ -+ precvframe->adapter = padapter; -+ precvframe++; -+ } -+ precvpriv->rx_pending_cnt = 1; -+ -+ sema_init(&precvpriv->allrxreturnevt, 0); -+ -+ res = rtw_hal_init_recv_priv(padapter); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ timer_setup(&precvpriv->signal_stat_timer, rtw_signal_stat_timer_hdl, 0); -+#else -+ _init_timer(&precvpriv->signal_stat_timer, padapter->pnetdev, RTW_TIMER_HDL_NAME(signal_stat), padapter); -+#endif -+ precvpriv->signal_stat_sampling_interval = 1000; /* ms */ -+ -+ rtw_set_signal_stat_timer(precvpriv); -+exit: -+ -+ return res; -+} -+ -+static void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv) -+{ -+ _rtw_spinlock_free(&precvpriv->lock); -+ _rtw_spinlock_free(&precvpriv->free_recv_queue.lock); -+ _rtw_spinlock_free(&precvpriv->recv_pending_queue.lock); -+ -+ _rtw_spinlock_free(&precvpriv->free_recv_buf_queue.lock); -+} -+ -+void _rtw_free_recv_priv (struct recv_priv *precvpriv) -+{ -+ struct adapter *padapter = precvpriv->adapter; -+ -+ rtw_free_uc_swdec_pending_queue(padapter); -+ -+ rtw_mfree_recv_priv_lock(precvpriv); -+ -+ rtw_os_recv_resource_free(precvpriv); -+ -+ if (precvpriv->pallocated_frame_buf) { -+ rtw_vmfree(precvpriv->pallocated_frame_buf, NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ); -+ } -+ -+ rtw_hal_free_recv_priv(padapter); -+ -+} -+ -+struct recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue) -+{ -+ struct recv_frame *hdr; -+ struct list_head *plist, *phead; -+ struct adapter *padapter; -+ struct recv_priv *precvpriv; -+ -+ if (list_empty(&pfree_recv_queue->queue)) { -+ hdr = NULL; -+ } else { -+ phead = get_list_head(pfree_recv_queue); -+ -+ plist = phead->next; -+ -+ hdr = container_of(plist, struct recv_frame, list); -+ -+ list_del_init(&hdr->list); -+ padapter = hdr->adapter; -+ if (padapter != NULL) { -+ precvpriv = &padapter->recvpriv; -+ if (pfree_recv_queue == &precvpriv->free_recv_queue) -+ precvpriv->free_recvframe_cnt--; -+ } -+ } -+ -+ return (struct recv_frame *)hdr; -+} -+ -+struct recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue) -+{ -+ struct recv_frame *precvframe; -+ -+ spin_lock_bh(&pfree_recv_queue->lock); -+ -+ precvframe = _rtw_alloc_recvframe(pfree_recv_queue); -+ -+ spin_unlock_bh(&pfree_recv_queue->lock); -+ -+ return precvframe; -+} -+ -+void rtw_init_recvframe(struct recv_frame *precvframe, struct recv_priv *precvpriv) -+{ -+ /* Perry: This can be removed */ -+ INIT_LIST_HEAD(&precvframe->list); -+ -+ precvframe->len = 0; -+} -+ -+int rtw_free_recvframe(struct recv_frame *precvframe, struct __queue *pfree_recv_queue) -+{ -+ struct adapter *padapter; -+ struct recv_priv *precvpriv; -+ -+ if (!precvframe) -+ return _FAIL; -+ padapter = precvframe->adapter; -+ precvpriv = &padapter->recvpriv; -+ if (precvframe->pkt) { -+ dev_kfree_skb_any(precvframe->pkt);/* free skb by driver */ -+ precvframe->pkt = NULL; -+ } -+ -+ spin_lock_bh(&pfree_recv_queue->lock); -+ -+ list_del_init(&(precvframe->list)); -+ -+ precvframe->len = 0; -+ -+ list_add_tail(&(precvframe->list), get_list_head(pfree_recv_queue)); -+ -+ if (padapter != NULL) { -+ if (pfree_recv_queue == &precvpriv->free_recv_queue) -+ precvpriv->free_recvframe_cnt++; -+ } -+ -+ spin_unlock_bh(&pfree_recv_queue->lock); -+ -+ return _SUCCESS; -+} -+ -+int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) -+{ -+ struct adapter *padapter = precvframe->adapter; -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ -+ list_del_init(&(precvframe->list)); -+ list_add_tail(&(precvframe->list), get_list_head(queue)); -+ -+ if (padapter != NULL) { -+ if (queue == &precvpriv->free_recv_queue) -+ precvpriv->free_recvframe_cnt++; -+ } -+ -+ return _SUCCESS; -+} -+ -+int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) -+{ -+ int ret; -+ -+ spin_lock_bh(&queue->lock); -+ ret = _rtw_enqueue_recvframe(precvframe, queue); -+ spin_unlock_bh(&queue->lock); -+ -+ return ret; -+} -+ -+/* -+caller : defrag ; recvframe_chk_defrag in recv_thread (passive) -+pframequeue: defrag_queue : will be accessed in recv_thread (passive) -+ -+using spinlock to protect -+ -+*/ -+ -+void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue) -+{ -+ struct recv_frame *hdr; -+ struct list_head *plist, *phead; -+ -+ spin_lock(&pframequeue->lock); -+ -+ phead = get_list_head(pframequeue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ hdr = container_of(plist, struct recv_frame, list); -+ -+ plist = plist->next; -+ -+ rtw_free_recvframe((struct recv_frame *)hdr, pfree_recv_queue); -+ } -+ -+ spin_unlock(&pframequeue->lock); -+ -+} -+ -+u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) -+{ -+ u32 cnt = 0; -+ struct recv_frame *pending_frame; -+ while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) { -+ rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue); -+ DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__); -+ cnt++; -+ } -+ -+ return cnt; -+} -+ -+int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue) -+{ -+ spin_lock_bh(&queue->lock); -+ -+ list_del_init(&precvbuf->list); -+ list_add(&precvbuf->list, get_list_head(queue)); -+ -+ spin_unlock_bh(&queue->lock); -+ -+ return _SUCCESS; -+} -+ -+int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&queue->lock, flags); -+ -+ list_del_init(&precvbuf->list); -+ -+ list_add_tail(&precvbuf->list, get_list_head(queue)); -+ spin_unlock_irqrestore(&queue->lock, flags); -+ return _SUCCESS; -+} -+ -+struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue) -+{ -+ struct recv_buf *precvbuf; -+ struct list_head *plist, *phead; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&queue->lock, flags); -+ -+ if (list_empty(&queue->queue)) { -+ precvbuf = NULL; -+ } else { -+ phead = get_list_head(queue); -+ -+ plist = phead->next; -+ -+ precvbuf = container_of(plist, struct recv_buf, list); -+ -+ list_del_init(&precvbuf->list); -+ } -+ -+ spin_unlock_irqrestore(&queue->lock, flags); -+ -+ return precvbuf; -+} -+ -+static int recvframe_chkmic(struct adapter *adapter, struct recv_frame *precvframe) -+{ -+ int i, res = _SUCCESS; -+ u32 datalen; -+ u8 miccode[8]; -+ u8 bmic_err = false, brpt_micerror = true; -+ u8 *pframe, *payload, *pframemic; -+ u8 *mickey; -+ struct sta_info *stainfo; -+ struct rx_pkt_attrib *prxattrib = &precvframe->attrib; -+ struct security_priv *psecuritypriv = &adapter->securitypriv; -+ -+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); -+ -+ if (prxattrib->encrypt == _TKIP_) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:prxattrib->encrypt==_TKIP_\n")); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", -+ prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5])); -+ -+ /* calculate mic code */ -+ if (stainfo != NULL) { -+ if (IS_MCAST(prxattrib->ra)) { -+ mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n")); -+ -+ if (!psecuritypriv) { -+ res = _FAIL; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n")); -+ DBG_88E("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"); -+ goto exit; -+ } -+ } else { -+ mickey = &stainfo->dot11tkiprxmickey.skey[0]; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic: unicast key\n")); -+ } -+ -+ datalen = precvframe->len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */ -+ pframe = precvframe->rx_data; -+ payload = pframe+prxattrib->hdrlen+prxattrib->iv_len; -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len)); -+ rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], -+ (unsigned char)prxattrib->priority); /* care the length of the data */ -+ -+ pframemic = payload+datalen; -+ -+ bmic_err = false; -+ -+ for (i = 0; i < 8; i++) { -+ if (miccode[i] != *(pframemic+i)) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, -+ ("recvframe_chkmic:miccode[%d](%02x)!=*(pframemic+%d)(%02x) ", -+ i, miccode[i], i, *(pframemic+i))); -+ bmic_err = true; -+ } -+ } -+ -+ if (bmic_err) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, -+ ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", -+ *(pframemic-8), *(pframemic-7), *(pframemic-6), -+ *(pframemic-5), *(pframemic-4), *(pframemic-3), -+ *(pframemic-2), *(pframemic-1))); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, -+ ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", -+ *(pframemic-16), *(pframemic-15), *(pframemic-14), -+ *(pframemic-13), *(pframemic-12), *(pframemic-11), -+ *(pframemic-10), *(pframemic-9))); -+ { -+ uint i; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet (len=%d)======\n", precvframe->len)); -+ for (i = 0; i < precvframe->len; i = i+8) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x", -+ *(precvframe->rx_data+i), *(precvframe->rx_data+i+1), -+ *(precvframe->rx_data+i+2), *(precvframe->rx_data+i+3), -+ *(precvframe->rx_data+i+4), *(precvframe->rx_data+i+5), -+ *(precvframe->rx_data+i+6), *(precvframe->rx_data+i+7))); -+ } -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ====== demp packet end [len=%d]======\n", precvframe->len)); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n hrdlen=%d,\n", prxattrib->hdrlen)); -+ } -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, -+ ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ", -+ prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], -+ prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey)); -+ -+ /* double check key_index for some timing issue , */ -+ /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ -+ if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index)) -+ brpt_micerror = false; -+ -+ if ((prxattrib->bdecrypted) && (brpt_micerror)) { -+ rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra)); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); -+ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); -+ } else { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); -+ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); -+ } -+ res = _FAIL; -+ } else { -+ /* mic checked ok */ -+ if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(prxattrib->ra))) { -+ psecuritypriv->bcheck_grpkey = true; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true")); -+ } -+ } -+ } else { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic: rtw_get_stainfo==NULL!!!\n")); -+ } -+ -+ recvframe_pull_tail(precvframe, 8); -+ } -+ -+exit: -+ -+ return res; -+} -+ -+/* decrypt and set the ivlen, icvlen of the recv_frame */ -+static struct recv_frame *decryptor(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ struct rx_pkt_attrib *prxattrib = &precv_frame->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct recv_frame *return_packet = precv_frame; -+ u32 res = _SUCCESS; -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted=%x prxattrib->encrypt=0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt)); -+ -+ if (prxattrib->encrypt > 0) { -+ u8 *iv = precv_frame->rx_data+prxattrib->hdrlen; -+ prxattrib->key_index = (((iv[3])>>6)&0x3); -+ -+ if (prxattrib->key_index > WEP_KEYS) { -+ DBG_88E("prxattrib->key_index(%d)>WEP_KEYS\n", prxattrib->key_index); -+ -+ switch (prxattrib->encrypt) { -+ case _WEP40_: -+ case _WEP104_: -+ prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex; -+ break; -+ case _TKIP_: -+ case _AES_: -+ default: -+ prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid; -+ break; -+ } -+ } -+ } -+ -+ if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || (psecuritypriv->sw_decrypt))) { -+ psecuritypriv->hw_decrypted = false; -+ -+ switch (prxattrib->encrypt) { -+ case _WEP40_: -+ case _WEP104_: -+ rtw_wep_decrypt(padapter, (u8 *)precv_frame); -+ break; -+ case _TKIP_: -+ res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); -+ break; -+ case _AES_: -+ res = rtw_aes_decrypt(padapter, (u8 *)precv_frame); -+ break; -+ default: -+ break; -+ } -+ } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 && -+ (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_)) -+ psecuritypriv->hw_decrypted = true; -+ -+ if (res == _FAIL) { -+ rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue); -+ return_packet = NULL; -+ } else { -+ prxattrib->bdecrypted = true; -+ } -+ -+ return return_packet; -+} -+ -+/* set the security information in the recv_frame */ -+static struct recv_frame *portctrl(struct adapter *adapter, struct recv_frame *precv_frame) -+{ -+ u8 *psta_addr, *ptr; -+ uint auth_alg; -+ struct recv_frame *pfhdr; -+ struct sta_info *psta; -+ struct sta_priv *pstapriv; -+ struct recv_frame *prtnframe; -+ u16 ether_type; -+ u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ -+ struct rx_pkt_attrib *pattrib; -+ __be16 be_tmp; -+ -+ pstapriv = &adapter->stapriv; -+ -+ auth_alg = adapter->securitypriv.dot11AuthAlgrthm; -+ -+ ptr = precv_frame->rx_data; -+ pfhdr = precv_frame; -+ pattrib = &pfhdr->attrib; -+ psta_addr = pattrib->ta; -+ -+ prtnframe = NULL; -+ -+ psta = rtw_get_stainfo(pstapriv, psta_addr); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, -+ ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n", -+ adapter->securitypriv.dot11AuthAlgrthm)); -+ -+ if (auth_alg == 2) { -+ if ((psta != NULL) && (psta->ieee8021x_blocked)) { -+ /* blocked */ -+ /* only accept EAPOL frame */ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==1\n")); -+ -+ prtnframe = precv_frame; -+ -+ /* get ether_type */ -+ ptr = ptr+pfhdr->attrib.hdrlen+pfhdr->attrib.iv_len+LLC_HEADER_SIZE; -+ memcpy(&be_tmp, ptr, 2); -+ ether_type = ntohs(be_tmp); -+ -+ if (ether_type == eapol_type) { -+ prtnframe = precv_frame; -+ } else { -+ /* free this frame */ -+ rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue); -+ prtnframe = NULL; -+ } -+ } else { -+ /* allowed */ -+ /* check decryption status, and decrypt the frame if needed */ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==0\n")); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:precv_frame->hdr.attrib.privacy=%x\n", precv_frame->attrib.privacy)); -+ -+ if (pattrib->bdecrypted == 0) -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted)); -+ -+ prtnframe = precv_frame; -+ /* check is the EAPOL frame or not (Rekey) */ -+ if (ether_type == eapol_type) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type==0x888e\n")); -+ /* check Rekey */ -+ -+ prtnframe = precv_frame; -+ } else { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type=0x%04x\n", ether_type)); -+ } -+ } -+ } else { -+ prtnframe = precv_frame; -+ } -+ -+ return prtnframe; -+} -+ -+static int recv_decache(struct recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) -+{ -+ int tid = precv_frame->attrib.priority; -+ -+ u16 seq_ctrl = ((precv_frame->attrib.seq_num&0xffff) << 4) | -+ (precv_frame->attrib.frag_num & 0xf); -+ -+ if (tid > 15) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid)); -+ -+ return _FAIL; -+ } -+ -+ if (1) {/* if (bretry) */ -+ if (seq_ctrl == prxcache->tid_rxseq[tid]) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid])); -+ -+ return _FAIL; -+ } -+ } -+ -+ prxcache->tid_rxseq[tid] = seq_ctrl; -+ -+ return _SUCCESS; -+} -+ -+void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame); -+void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+#ifdef CONFIG_88EU_AP_MODE -+ unsigned char pwrbit; -+ u8 *ptr = precv_frame->rx_data; -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct sta_info *psta = NULL; -+ -+ psta = rtw_get_stainfo(pstapriv, pattrib->src); -+ -+ pwrbit = GetPwrMgt(ptr); -+ -+ if (psta) { -+ if (pwrbit) { -+ if (!(psta->state & WIFI_SLEEP_STATE)) -+ stop_sta_xmit(padapter, psta); -+ } else { -+ if (psta->state & WIFI_SLEEP_STATE) -+ wakeup_sta_to_xmit(padapter, psta); -+ } -+ } -+ -+#endif -+} -+ -+static void process_wmmps_data(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+#ifdef CONFIG_88EU_AP_MODE -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct sta_info *psta = NULL; -+ -+ psta = rtw_get_stainfo(pstapriv, pattrib->src); -+ -+ if (!psta) -+ return; -+ -+ if (!psta->qos_option) -+ return; -+ -+ if (!(psta->qos_info&0xf)) -+ return; -+ -+ if (psta->state&WIFI_SLEEP_STATE) { -+ u8 wmmps_ac = 0; -+ -+ switch (pattrib->priority) { -+ case 1: -+ case 2: -+ wmmps_ac = psta->uapsd_bk&BIT(1); -+ break; -+ case 4: -+ case 5: -+ wmmps_ac = psta->uapsd_vi&BIT(1); -+ break; -+ case 6: -+ case 7: -+ wmmps_ac = psta->uapsd_vo&BIT(1); -+ break; -+ case 0: -+ case 3: -+ default: -+ wmmps_ac = psta->uapsd_be&BIT(1); -+ break; -+ } -+ -+ if (wmmps_ac) { -+ if (psta->sleepq_ac_len > 0) { -+ /* process received triggered frame */ -+ xmit_delivery_enabled_frames(padapter, psta); -+ } else { -+ /* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */ -+ issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0); -+ } -+ } -+ } -+ -+#endif -+} -+ -+static void count_rx_stats(struct adapter *padapter, struct recv_frame *prframe, struct sta_info *sta) -+{ -+ int sz; -+ struct sta_info *psta = NULL; -+ struct stainfo_stats *pstats = NULL; -+ struct rx_pkt_attrib *pattrib = &prframe->attrib; -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ -+ sz = get_recvframe_len(prframe); -+ precvpriv->rx_bytes += sz; -+ -+ padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++; -+ -+ if ((!MacAddr_isBcst(pattrib->dst)) && (!IS_MCAST(pattrib->dst))) -+ padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++; -+ -+ if (sta) -+ psta = sta; -+ else -+ psta = prframe->psta; -+ -+ if (psta) { -+ pstats = &psta->sta_stats; -+ -+ pstats->rx_data_pkts++; -+ pstats->rx_bytes += sz; -+ } -+} -+ -+int sta2sta_data_frame( -+ struct adapter *adapter, -+ struct recv_frame *precv_frame, -+ struct sta_info **psta -+); -+ -+int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame, struct sta_info **psta) -+{ -+ u8 *ptr = precv_frame->rx_data; -+ int ret = _SUCCESS; -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ struct sta_priv *pstapriv = &adapter->stapriv; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ u8 *mybssid = get_bssid(pmlmepriv); -+ u8 *myhwaddr = myid(&adapter->eeprompriv); -+ u8 *sta_addr = NULL; -+ int bmcast = IS_MCAST(pattrib->dst); -+ -+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { -+ /* filter packets that SA is myself or multicast or broadcast */ -+ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || -+ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || -+ memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ sta_addr = pattrib->src; -+ } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { -+ /* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */ -+ if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid!=TA under STATION_MODE; drop pkt\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ sta_addr = pattrib->bssid; -+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ if (bmcast) { -+ /* For AP mode, if DA == MCAST, then BSSID should be also MCAST */ -+ if (!IS_MCAST(pattrib->bssid)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ } else { /* not mc-frame */ -+ /* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */ -+ if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ sta_addr = pattrib->src; -+ } -+ } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { -+ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); -+ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); -+ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); -+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); -+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); -+ -+ sta_addr = mybssid; -+ } else { -+ ret = _FAIL; -+ } -+ -+ if (bmcast) -+ *psta = rtw_get_bcmc_stainfo(adapter); -+ else -+ *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */ -+ -+ if (*psta == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n")); -+ if (adapter->registrypriv.mp_mode == 1) { -+ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) -+ adapter->mppriv.rx_pktloss++; -+ } -+ ret = _FAIL; -+ goto exit; -+ } -+ -+exit: -+ -+ return ret; -+} -+ -+static int ap2sta_data_frame ( -+ struct adapter *adapter, -+ struct recv_frame *precv_frame, -+ struct sta_info **psta) -+{ -+ u8 *ptr = precv_frame->rx_data; -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ int ret = _SUCCESS; -+ struct sta_priv *pstapriv = &adapter->stapriv; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ u8 *mybssid = get_bssid(pmlmepriv); -+ u8 *myhwaddr = myid(&adapter->eeprompriv); -+ int bmcast = IS_MCAST(pattrib->dst); -+ -+ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) && -+ (check_fwstate(pmlmepriv, _FW_LINKED) == true || -+ check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) { -+ /* filter packets that SA is myself or multicast or broadcast */ -+ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* da should be for me */ -+ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, -+ (" ap2sta_data_frame: compare DA fail; DA=%pM\n", (pattrib->dst))); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* check BSSID */ -+ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || -+ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || -+ (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, -+ (" ap2sta_data_frame: compare BSSID fail ; BSSID=%pM\n", (pattrib->bssid))); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid))); -+ -+ if (!bmcast) { -+ DBG_88E("issue_deauth to the nonassociated ap=%pM for the reason(7)\n", (pattrib->bssid)); -+ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); -+ } -+ -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ if (bmcast) -+ *psta = rtw_get_bcmc_stainfo(adapter); -+ else -+ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */ -+ -+ if (*psta == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { */ -+ /* */ -+ -+ if (GetFrameSubType(ptr) & BIT(6)) { -+ /* No data, will not indicate to upper layer, temporily count it here */ -+ count_rx_stats(adapter, precv_frame, *psta); -+ ret = RTW_RX_HANDLED; -+ goto exit; -+ } -+ } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && -+ (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { -+ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); -+ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); -+ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); -+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); -+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); -+ -+ /* */ -+ memcpy(pattrib->bssid, mybssid, ETH_ALEN); -+ -+ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ -+ if (*psta == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ /* Special case */ -+ ret = RTW_RX_HANDLED; -+ goto exit; -+ } else { -+ if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) { -+ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ -+ if (*psta == NULL) { -+ DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid)); -+ -+ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); -+ } -+ } -+ -+ ret = _FAIL; -+ } -+ -+exit: -+ -+ return ret; -+} -+ -+static int sta2ap_data_frame(struct adapter *adapter, -+ struct recv_frame *precv_frame, -+ struct sta_info **psta) -+{ -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ struct sta_priv *pstapriv = &adapter->stapriv; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ u8 *ptr = precv_frame->rx_data; -+ unsigned char *mybssid = get_bssid(pmlmepriv); -+ int ret = _SUCCESS; -+ -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { -+ /* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */ -+ if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ *psta = rtw_get_stainfo(pstapriv, pattrib->src); -+ if (*psta == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n")); -+ DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src)); -+ -+ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); -+ -+ ret = RTW_RX_HANDLED; -+ goto exit; -+ } -+ -+ process_pwrbit_data(adapter, precv_frame); -+ -+ if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { -+ process_wmmps_data(adapter, precv_frame); -+ } -+ -+ if (GetFrameSubType(ptr) & BIT(6)) { -+ /* No data, will not indicate to upper layer, temporily count it here */ -+ count_rx_stats(adapter, precv_frame, *psta); -+ ret = RTW_RX_HANDLED; -+ goto exit; -+ } -+ } else { -+ u8 *myhwaddr = myid(&adapter->eeprompriv); -+ if (memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) { -+ ret = RTW_RX_HANDLED; -+ goto exit; -+ } -+ DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src)); -+ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); -+ ret = RTW_RX_HANDLED; -+ goto exit; -+ } -+ -+exit: -+ -+ return ret; -+} -+ -+static int validate_recv_ctrl_frame(struct adapter *padapter, -+ struct recv_frame *precv_frame) -+{ -+#ifdef CONFIG_88EU_AP_MODE -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 *pframe = precv_frame->rx_data; -+ /* uint len = precv_frame->len; */ -+ -+ if (GetFrameType(pframe) != WIFI_CTRL_TYPE) -+ return _FAIL; -+ -+ /* receive the frames that ra(a1) is my address */ -+ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN)) -+ return _FAIL; -+ -+ /* only handle ps-poll */ -+ if (GetFrameSubType(pframe) == WIFI_PSPOLL) { -+ u16 aid; -+ u8 wmmps_ac = 0; -+ struct sta_info *psta = NULL; -+ -+ aid = GetAid(pframe); -+ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); -+ -+ if ((psta == NULL) || (psta->aid != aid)) -+ return _FAIL; -+ -+ /* for rx pkt statistics */ -+ psta->sta_stats.rx_ctrl_pkts++; -+ -+ switch (pattrib->priority) { -+ case 1: -+ case 2: -+ wmmps_ac = psta->uapsd_bk&BIT(0); -+ break; -+ case 4: -+ case 5: -+ wmmps_ac = psta->uapsd_vi&BIT(0); -+ break; -+ case 6: -+ case 7: -+ wmmps_ac = psta->uapsd_vo&BIT(0); -+ break; -+ case 0: -+ case 3: -+ default: -+ wmmps_ac = psta->uapsd_be&BIT(0); -+ break; -+ } -+ -+ if (wmmps_ac) -+ return _FAIL; -+ -+ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { -+ DBG_88E("%s alive check-rx ps-poll\n", __func__); -+ psta->expire_to = pstapriv->expire_to; -+ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; -+ } -+ -+ if ((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) { -+ struct list_head *xmitframe_plist, *xmitframe_phead; -+ struct xmit_frame *pxmitframe = NULL; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+ spin_lock_bh(&pxmitpriv->lock); -+ -+ xmitframe_phead = get_list_head(&psta->sleep_q); -+ xmitframe_plist = xmitframe_phead->next; -+ -+ if (xmitframe_phead != xmitframe_plist) { -+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); -+ -+ xmitframe_plist = xmitframe_plist->next; -+ -+ list_del_init(&pxmitframe->list); -+ -+ psta->sleepq_len--; -+ -+ if (psta->sleepq_len > 0) -+ pxmitframe->attrib.mdata = 1; -+ else -+ pxmitframe->attrib.mdata = 0; -+ -+ pxmitframe->attrib.triggered = 1; -+ -+ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); -+ -+ if (psta->sleepq_len == 0) { -+ pstapriv->tim_bitmap &= ~BIT(psta->aid); -+ -+ /* upate BCN for TIM IE */ -+ /* update_BCNTIM(padapter); */ -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+ } -+ } else { -+ if (pstapriv->tim_bitmap&BIT(psta->aid)) { -+ if (psta->sleepq_len == 0) { -+ DBG_88E("no buffered packets to xmit\n"); -+ -+ /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ -+ issue_nulldata(padapter, psta->hwaddr, 0, 0, 0); -+ } else { -+ DBG_88E("error!psta->sleepq_len=%d\n", psta->sleepq_len); -+ psta->sleepq_len = 0; -+ } -+ -+ pstapriv->tim_bitmap &= ~BIT(psta->aid); -+ -+ /* upate BCN for TIM IE */ -+ /* update_BCNTIM(padapter); */ -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+ } -+ } -+ spin_unlock_bh(&pxmitpriv->lock); -+ } -+ } -+ -+#endif -+ -+ return _FAIL; -+} -+ -+struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, struct recv_frame *precv_frame); -+ -+static int validate_recv_mgnt_frame(struct adapter *padapter, -+ struct recv_frame *precv_frame) -+{ -+ struct sta_info *psta; -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n")); -+ -+ precv_frame = recvframe_chk_defrag(padapter, precv_frame); -+ if (precv_frame == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__)); -+ return _SUCCESS; -+ } -+ -+ /* for rx pkt statistics */ -+ psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->rx_data)); -+ if (psta) { -+ psta->sta_stats.rx_mgnt_pkts++; -+ if (GetFrameSubType(precv_frame->rx_data) == WIFI_BEACON) { -+ psta->sta_stats.rx_beacon_pkts++; -+ } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBEREQ) { -+ psta->sta_stats.rx_probereq_pkts++; -+ } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBERSP) { -+ if (!memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->rx_data), ETH_ALEN)) -+ psta->sta_stats.rx_probersp_pkts++; -+ else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->rx_data)) || -+ is_multicast_mac_addr(GetAddr1Ptr(precv_frame->rx_data))) -+ psta->sta_stats.rx_probersp_bm_pkts++; -+ else -+ psta->sta_stats.rx_probersp_uo_pkts++; -+ } -+ } -+ -+ mgt_dispatcher(padapter, precv_frame); -+ -+ return _SUCCESS; -+} -+ -+static int validate_recv_data_frame(struct adapter *adapter, -+ struct recv_frame *precv_frame) -+{ -+ u8 bretry; -+ u8 *psa, *pda, *pbssid; -+ struct sta_info *psta = NULL; -+ u8 *ptr = precv_frame->rx_data; -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ struct security_priv *psecuritypriv = &adapter->securitypriv; -+ int ret = _SUCCESS; -+ -+ bretry = GetRetry(ptr); -+ pda = get_da(ptr); -+ psa = get_sa(ptr); -+ pbssid = get_hdr_bssid(ptr); -+ -+ if (pbssid == NULL) { -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ memcpy(pattrib->dst, pda, ETH_ALEN); -+ memcpy(pattrib->src, psa, ETH_ALEN); -+ -+ memcpy(pattrib->bssid, pbssid, ETH_ALEN); -+ -+ switch (pattrib->to_fr_ds) { -+ case 0: -+ memcpy(pattrib->ra, pda, ETH_ALEN); -+ memcpy(pattrib->ta, psa, ETH_ALEN); -+ ret = sta2sta_data_frame(adapter, precv_frame, &psta); -+ break; -+ case 1: -+ memcpy(pattrib->ra, pda, ETH_ALEN); -+ memcpy(pattrib->ta, pbssid, ETH_ALEN); -+ ret = ap2sta_data_frame(adapter, precv_frame, &psta); -+ break; -+ case 2: -+ memcpy(pattrib->ra, pbssid, ETH_ALEN); -+ memcpy(pattrib->ta, psa, ETH_ALEN); -+ ret = sta2ap_data_frame(adapter, precv_frame, &psta); -+ break; -+ case 3: -+ memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); -+ memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); -+ ret = _FAIL; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n")); -+ break; -+ default: -+ ret = _FAIL; -+ break; -+ } -+ -+ if (ret == _FAIL) { -+ goto exit; -+ } else if (ret == RTW_RX_HANDLED) { -+ goto exit; -+ } -+ -+ if (psta == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ /* psta->rssi = prxcmd->rssi; */ -+ /* psta->signal_quality = prxcmd->sq; */ -+ precv_frame->psta = psta; -+ -+ pattrib->amsdu = 0; -+ pattrib->ack_policy = 0; -+ /* parsing QC field */ -+ if (pattrib->qos == 1) { -+ pattrib->priority = GetPriority((ptr + 24)); -+ pattrib->ack_policy = GetAckpolicy((ptr + 24)); -+ pattrib->amsdu = GetAMsdu((ptr + 24)); -+ pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26; -+ -+ if (pattrib->priority != 0 && pattrib->priority != 3) -+ adapter->recvpriv.bIsAnyNonBEPkts = true; -+ } else { -+ pattrib->priority = 0; -+ pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24; -+ } -+ -+ if (pattrib->order)/* HT-CTRL 11n */ -+ pattrib->hdrlen += 4; -+ -+ precv_frame->preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority]; -+ -+ /* decache, drop duplicate recv packets */ -+ if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decache : drop pkt\n")); -+ ret = _FAIL; -+ goto exit; -+ } -+ -+ if (pattrib->privacy) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy)); -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra))); -+ -+ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra)); -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt=%d\n", pattrib->encrypt)); -+ -+ SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); -+ } else { -+ pattrib->encrypt = 0; -+ pattrib->iv_len = 0; -+ pattrib->icv_len = 0; -+ } -+ -+exit: -+ -+ return ret; -+} -+ -+static int validate_recv_frame(struct adapter *adapter, struct recv_frame *precv_frame) -+{ -+ /* shall check frame subtype, to / from ds, da, bssid */ -+ -+ /* then call check if rx seq/frag. duplicated. */ -+ -+ u8 type; -+ u8 subtype; -+ int retval = _SUCCESS; -+ u8 bDumpRxPkt; -+ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; -+ u8 *ptr = precv_frame->rx_data; -+ u8 ver = (unsigned char) (*ptr)&0x3; -+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; -+ -+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { -+ int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter)); -+ if (ch_set_idx >= 0) -+ pmlmeext->channel_set[ch_set_idx].rx_count++; -+ } -+ -+ /* add version chk */ -+ if (ver != 0) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! (ver!=0)\n")); -+ retval = _FAIL; -+ goto exit; -+ } -+ -+ type = GetFrameType(ptr); -+ subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */ -+ -+ pattrib->to_fr_ds = get_tofr_ds(ptr); -+ -+ pattrib->frag_num = GetFragNum(ptr); -+ pattrib->seq_num = GetSequence(ptr); -+ -+ pattrib->pw_save = GetPwrMgt(ptr); -+ pattrib->mfrag = GetMFrag(ptr); -+ pattrib->mdata = GetMData(ptr); -+ pattrib->privacy = GetPrivacy(ptr); -+ pattrib->order = GetOrder(ptr); -+ -+ /* Dump rx packets */ -+ rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); -+ if (bDumpRxPkt == 1) {/* dump all rx packets */ -+ int i; -+ DBG_88E("#############################\n"); -+ -+ for (i = 0; i < 64; i = i+8) -+ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), -+ *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); -+ DBG_88E("#############################\n"); -+ } else if (bDumpRxPkt == 2) { -+ if (type == WIFI_MGT_TYPE) { -+ int i; -+ DBG_88E("#############################\n"); -+ -+ for (i = 0; i < 64; i = i+8) -+ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), -+ *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); -+ DBG_88E("#############################\n"); -+ } -+ } else if (bDumpRxPkt == 3) { -+ if (type == WIFI_DATA_TYPE) { -+ int i; -+ DBG_88E("#############################\n"); -+ -+ for (i = 0; i < 64; i = i+8) -+ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), -+ *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); -+ DBG_88E("#############################\n"); -+ } -+ } -+ switch (type) { -+ case WIFI_MGT_TYPE: /* mgnt */ -+ retval = validate_recv_mgnt_frame(adapter, precv_frame); -+ if (retval == _FAIL) -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_mgnt_frame fail\n")); -+ retval = _FAIL; /* only data frame return _SUCCESS */ -+ break; -+ case WIFI_CTRL_TYPE: /* ctrl */ -+ retval = validate_recv_ctrl_frame(adapter, precv_frame); -+ if (retval == _FAIL) -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_ctrl_frame fail\n")); -+ retval = _FAIL; /* only data frame return _SUCCESS */ -+ break; -+ case WIFI_DATA_TYPE: /* data */ -+ rtw_led_control(adapter, LED_CTL_RX); -+ pattrib->qos = (subtype & BIT(7)) ? 1 : 0; -+ retval = validate_recv_data_frame(adapter, precv_frame); -+ if (retval == _FAIL) { -+ struct recv_priv *precvpriv = &adapter->recvpriv; -+ precvpriv->rx_drop++; -+ } -+ break; -+ default: -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! type= 0x%x\n", type)); -+ retval = _FAIL; -+ break; -+ } -+ -+exit: -+ -+ return retval; -+} -+ -+/* remove the wlanhdr and add the eth_hdr */ -+ -+static int wlanhdr_to_ethhdr (struct recv_frame *precvframe) -+{ -+ int rmv_len; -+ u16 eth_type, len; -+ __be16 be_tmp; -+ u8 bsnaphdr; -+ u8 *psnap_type; -+ struct ieee80211_snap_hdr *psnap; -+ -+ int ret = _SUCCESS; -+ struct adapter *adapter = precvframe->adapter; -+ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; -+ -+ u8 *ptr = get_recvframe_data(precvframe); /* point to frame_ctrl field */ -+ struct rx_pkt_attrib *pattrib = &precvframe->attrib; -+ -+ if (pattrib->encrypt) -+ recvframe_pull_tail(precvframe, pattrib->icv_len); -+ -+ psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len); -+ psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; -+ /* convert hdr + possible LLC headers into Ethernet header */ -+ if ((!memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && -+ memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) && -+ memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2)) || -+ !memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) { -+ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ -+ bsnaphdr = true; -+ } else { -+ /* Leave Ethernet header part of hdr and full payload */ -+ bsnaphdr = false; -+ } -+ -+ rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); -+ len = precvframe->len - rmv_len; -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, -+ ("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x===\n\n", pattrib->hdrlen, pattrib->iv_len)); -+ -+ memcpy(&be_tmp, ptr+rmv_len, 2); -+ eth_type = ntohs(be_tmp); /* pattrib->ether_type */ -+ pattrib->eth_type = eth_type; -+ -+ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE))) { -+ ptr += rmv_len; -+ *ptr = 0x87; -+ *(ptr+1) = 0x12; -+ -+ eth_type = 0x8712; -+ /* append rx status for mp test packets */ -+ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24); -+ memcpy(ptr, get_rxmem(precvframe), 24); -+ ptr += 24; -+ } else { -+ ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); -+ } -+ -+ memcpy(ptr, pattrib->dst, ETH_ALEN); -+ memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); -+ -+ if (!bsnaphdr) { -+ be_tmp = htons(len); -+ memcpy(ptr+12, &be_tmp, 2); -+ } -+ -+ return ret; -+} -+ -+/* perform defrag */ -+static struct recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q) -+{ -+ struct list_head *plist, *phead; -+ u8 wlanhdr_offset; -+ u8 curfragnum; -+ struct recv_frame *pfhdr, *pnfhdr; -+ struct recv_frame *prframe, *pnextrframe; -+ struct __queue *pfree_recv_queue; -+ -+ curfragnum = 0; -+ pfree_recv_queue = &adapter->recvpriv.free_recv_queue; -+ -+ phead = get_list_head(defrag_q); -+ plist = phead->next; -+ pfhdr = container_of(plist, struct recv_frame, list); -+ prframe = (struct recv_frame *)pfhdr; -+ list_del_init(&(prframe->list)); -+ -+ if (curfragnum != pfhdr->attrib.frag_num) { -+ /* the first fragment number must be 0 */ -+ /* free the whole queue */ -+ rtw_free_recvframe(prframe, pfree_recv_queue); -+ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); -+ -+ return NULL; -+ } -+ -+ curfragnum++; -+ -+ plist = get_list_head(defrag_q); -+ plist = phead->next; -+ pfhdr = container_of(plist, struct recv_frame, list); -+ prframe = (struct recv_frame *)pfhdr; -+ list_del_init(&(prframe->list)); -+ -+ plist = plist->next; -+ -+ while (phead != plist) { -+ pnfhdr = container_of(plist, struct recv_frame, list); -+ pnextrframe = (struct recv_frame *)pnfhdr; -+ -+ /* check the fragment sequence (2nd ~n fragment frame) */ -+ -+ if (curfragnum != pnfhdr->attrib.frag_num) { -+ /* the fragment number must be increasing (after decache) */ -+ /* release the defrag_q & prframe */ -+ rtw_free_recvframe(prframe, pfree_recv_queue); -+ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); -+ return NULL; -+ } -+ -+ curfragnum++; -+ -+ /* copy the 2nd~n fragment frame's payload to the first fragment */ -+ /* get the 2nd~last fragment frame's payload */ -+ -+ wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; -+ -+ recvframe_pull(pnextrframe, wlanhdr_offset); -+ -+ /* append to first fragment frame's tail (if privacy frame, pull the ICV) */ -+ recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); -+ -+ /* memcpy */ -+ memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); -+ -+ recvframe_put(prframe, pnfhdr->len); -+ -+ pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; -+ plist = plist->next; -+ } -+ -+ /* free the defrag_q queue and return the prframe */ -+ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n")); -+ -+ return prframe; -+} -+ -+/* check if need to defrag, if needed queue the frame to defrag_q */ -+struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, struct recv_frame *precv_frame) -+{ -+ u8 ismfrag; -+ u8 fragnum; -+ u8 *psta_addr; -+ struct recv_frame *pfhdr; -+ struct sta_info *psta; -+ struct sta_priv *pstapriv; -+ struct list_head *phead; -+ struct recv_frame *prtnframe = NULL; -+ struct __queue *pfree_recv_queue, *pdefrag_q; -+ -+ pstapriv = &padapter->stapriv; -+ -+ pfhdr = precv_frame; -+ -+ pfree_recv_queue = &padapter->recvpriv.free_recv_queue; -+ -+ /* need to define struct of wlan header frame ctrl */ -+ ismfrag = pfhdr->attrib.mfrag; -+ fragnum = pfhdr->attrib.frag_num; -+ -+ psta_addr = pfhdr->attrib.ta; -+ psta = rtw_get_stainfo(pstapriv, psta_addr); -+ if (psta == NULL) { -+ u8 type = GetFrameType(pfhdr->rx_data); -+ if (type != WIFI_DATA_TYPE) { -+ psta = rtw_get_bcmc_stainfo(padapter); -+ pdefrag_q = &psta->sta_recvpriv.defrag_q; -+ } else { -+ pdefrag_q = NULL; -+ } -+ } else { -+ pdefrag_q = &psta->sta_recvpriv.defrag_q; -+ } -+ -+ if ((ismfrag == 0) && (fragnum == 0)) -+ prtnframe = precv_frame;/* isn't a fragment frame */ -+ -+ if (ismfrag == 1) { -+ /* 0~(n-1) fragment frame */ -+ /* enqueue to defraf_g */ -+ if (pdefrag_q != NULL) { -+ if (fragnum == 0) { -+ /* the first fragment */ -+ if (!list_empty(&pdefrag_q->queue)) { -+ /* free current defrag_q */ -+ rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); -+ } -+ } -+ -+ /* Then enqueue the 0~(n-1) fragment into the defrag_q */ -+ -+ phead = get_list_head(pdefrag_q); -+ list_add_tail(&pfhdr->list, phead); -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Enqueuq: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); -+ -+ prtnframe = NULL; -+ } else { -+ /* can't find this ta's defrag_queue, so free this recv_frame */ -+ if (precv_frame && pfree_recv_queue) -+ rtw_free_recvframe(precv_frame, pfree_recv_queue); -+ prtnframe = NULL; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); -+ } -+ } -+ -+ if ((ismfrag == 0) && (fragnum != 0)) { -+ /* the last fragment frame */ -+ /* enqueue the last fragment */ -+ if (pdefrag_q != NULL) { -+ phead = get_list_head(pdefrag_q); -+ list_add_tail(&pfhdr->list, phead); -+ -+ /* call recvframe_defrag to defrag */ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("defrag: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); -+ precv_frame = recvframe_defrag(padapter, pdefrag_q); -+ prtnframe = precv_frame; -+ } else { -+ /* can't find this ta's defrag_queue, so free this recv_frame */ -+ if (precv_frame && pfree_recv_queue) -+ rtw_free_recvframe(precv_frame, pfree_recv_queue); -+ prtnframe = NULL; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); -+ } -+ } -+ -+ if ((prtnframe != NULL) && (prtnframe->attrib.privacy)) { -+ /* after defrag we must check tkip mic code */ -+ if (recvframe_chkmic(padapter, prtnframe) == _FAIL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe)==_FAIL\n")); -+ if (precv_frame && pfree_recv_queue) -+ rtw_free_recvframe(prtnframe, pfree_recv_queue); -+ prtnframe = NULL; -+ } -+ } -+ -+ return prtnframe; -+} -+ -+static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) -+{ -+ int a_len, padding_len; -+ u16 eth_type, nSubframe_Length; -+ u8 nr_subframes, i; -+ unsigned char *pdata; -+ struct rx_pkt_attrib *pattrib; -+ unsigned char *data_ptr; -+ struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue); -+ int ret = _SUCCESS; -+ nr_subframes = 0; -+ -+ pattrib = &prframe->attrib; -+ -+ recvframe_pull(prframe, prframe->attrib.hdrlen); -+ -+ if (prframe->attrib.iv_len > 0) -+ recvframe_pull(prframe, prframe->attrib.iv_len); -+ -+ a_len = prframe->len; -+ -+ pdata = prframe->rx_data; -+ -+ while (a_len > ETH_HLEN) { -+ /* Offset 12 denote 2 mac address */ -+ nSubframe_Length = RTW_GET_BE16(pdata + 12); -+ -+ if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { -+ DBG_88E("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length); -+ goto exit; -+ } -+ -+ /* move the data point to data content */ -+ pdata += ETH_HLEN; -+ a_len -= ETH_HLEN; -+ -+ /* Allocate new skb for releasing to upper layer */ -+ sub_skb = dev_alloc_skb(nSubframe_Length + 12); -+ if (sub_skb) { -+ skb_reserve(sub_skb, 12); -+ data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); -+ memcpy(data_ptr, pdata, nSubframe_Length); -+ } else { -+ sub_skb = skb_clone(prframe->pkt, GFP_ATOMIC); -+ if (sub_skb) { -+ sub_skb->data = pdata; -+ sub_skb->len = nSubframe_Length; -+ skb_set_tail_pointer(sub_skb, nSubframe_Length); -+ } else { -+ DBG_88E("skb_clone() Fail!!! , nr_subframes=%d\n", nr_subframes); -+ break; -+ } -+ } -+ -+ subframes[nr_subframes++] = sub_skb; -+ -+ if (nr_subframes >= MAX_SUBFRAME_COUNT) { -+ DBG_88E("ParseSubframe(): Too many Subframes! Packets dropped!\n"); -+ break; -+ } -+ -+ pdata += nSubframe_Length; -+ a_len -= nSubframe_Length; -+ if (a_len != 0) { -+ padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4-1)); -+ if (padding_len == 4) { -+ padding_len = 0; -+ } -+ -+ if (a_len < padding_len) { -+ goto exit; -+ } -+ pdata += padding_len; -+ a_len -= padding_len; -+ } -+ } -+ -+ for (i = 0; i < nr_subframes; i++) { -+ sub_skb = subframes[i]; -+ /* convert hdr + possible LLC headers into Ethernet header */ -+ eth_type = RTW_GET_BE16(&sub_skb->data[6]); -+ if (sub_skb->len >= 8 && -+ ((!memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) && -+ eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || -+ !memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) { -+ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ -+ skb_pull(sub_skb, SNAP_SIZE); -+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); -+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); -+ } else { -+ __be16 len; -+ /* Leave Ethernet header part of hdr and full payload */ -+ len = htons(sub_skb->len); -+ memcpy(skb_push(sub_skb, 2), &len, 2); -+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); -+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); -+ } -+ -+ /* Indicate the packets to upper layer */ -+ /* Insert NAT2.5 RX here! */ -+ sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev); -+ sub_skb->dev = padapter->pnetdev; -+ -+ sub_skb->ip_summed = CHECKSUM_NONE; -+ -+ netif_rx(sub_skb); -+ } -+ -+exit: -+ -+ prframe->len = 0; -+ rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */ -+ -+ return ret; -+} -+ -+static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) -+{ -+ u8 wsize = preorder_ctrl->wsize_b; -+ u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF;/* 4096; */ -+ -+ /* Rx Reorder initialize condition. */ -+ if (preorder_ctrl->indicate_seq == 0xFFFF) -+ preorder_ctrl->indicate_seq = seq_num; -+ -+ /* Drop out the packet which SeqNum is smaller than WinStart */ -+ if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) -+ return false; -+ -+ /* */ -+ /* Sliding window manipulation. Conditions includes: */ -+ /* 1. Incoming SeqNum is equal to WinStart =>Window shift 1 */ -+ /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ -+ /* */ -+ if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) { -+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; -+ } else if (SN_LESS(wend, seq_num)) { -+ if (seq_num >= (wsize - 1)) -+ preorder_ctrl->indicate_seq = seq_num + 1 - wsize; -+ else -+ preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; -+ } -+ -+ return true; -+} -+ -+int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, struct recv_frame *prframe); -+int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, struct recv_frame *prframe) -+{ -+ struct rx_pkt_attrib *pattrib = &prframe->attrib; -+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; -+ struct list_head *phead, *plist; -+ struct recv_frame *hdr; -+ struct rx_pkt_attrib *pnextattrib; -+ -+ phead = get_list_head(ppending_recvframe_queue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ hdr = container_of(plist, struct recv_frame, list); -+ pnextattrib = &hdr->attrib; -+ -+ if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) -+ plist = plist->next; -+ else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) -+ return false; -+ else -+ break; -+ } -+ -+ list_del_init(&(prframe->list)); -+ -+ list_add_tail(&(prframe->list), plist); -+ return true; -+} -+ -+static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) -+{ -+ struct list_head *phead, *plist; -+ struct recv_frame *prframe; -+ struct rx_pkt_attrib *pattrib; -+ int bPktInBuf = false; -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; -+ -+ phead = get_list_head(ppending_recvframe_queue); -+ plist = phead->next; -+ -+ /* Handling some condition for forced indicate case. */ -+ if (bforced) { -+ if (list_empty(phead)) -+ return true; -+ -+ prframe = container_of(plist, struct recv_frame, list); -+ pattrib = &prframe->attrib; -+ preorder_ctrl->indicate_seq = pattrib->seq_num; -+ } -+ -+ /* Prepare indication list and indication. */ -+ /* Check if there is any packet need indicate. */ -+ while (!list_empty(phead)) { -+ prframe = container_of(plist, struct recv_frame, list); -+ pattrib = &prframe->attrib; -+ -+ if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, -+ ("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n", -+ preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu)); -+ plist = plist->next; -+ list_del_init(&(prframe->list)); -+ -+ if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) -+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; -+ -+ /* Set this as a lock to make sure that only one thread is indicating packet. */ -+ -+ /* indicate this recv_frame */ -+ if (!pattrib->amsdu) { -+ if ((!padapter->bDriverStopped) && -+ (!padapter->bSurpriseRemoved)) -+ rtw_recv_indicatepkt(padapter, prframe);/* indicate this recv_frame */ -+ } else if (pattrib->amsdu == 1) { -+ if (amsdu_to_msdu(padapter, prframe) != _SUCCESS) -+ rtw_free_recvframe(prframe, &precvpriv->free_recv_queue); -+ } else { -+ /* error condition; */ -+ } -+ -+ /* Update local variables. */ -+ bPktInBuf = false; -+ } else { -+ bPktInBuf = true; -+ break; -+ } -+ } -+ return bPktInBuf; -+} -+ -+static int recv_indicatepkt_reorder(struct adapter *padapter, struct recv_frame *prframe) -+{ -+ int retval = _SUCCESS; -+ struct rx_pkt_attrib *pattrib = &prframe->attrib; -+ struct recv_reorder_ctrl *preorder_ctrl = prframe->preorder_ctrl; -+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; -+ -+ if (!pattrib->amsdu) { -+ /* s1. */ -+ wlanhdr_to_ethhdr(prframe); -+ -+ if (pattrib->qos != 1) { -+ if (!padapter->bDriverStopped && -+ !padapter->bSurpriseRemoved) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, -+ ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n")); -+ -+ rtw_recv_indicatepkt(padapter, prframe); -+ return _SUCCESS; -+ } -+ -+ return _FAIL; -+ } -+ -+ if (!preorder_ctrl->enable) { -+ /* indicate this recv_frame */ -+ preorder_ctrl->indicate_seq = pattrib->seq_num; -+ rtw_recv_indicatepkt(padapter, prframe); -+ -+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; -+ return _SUCCESS; -+ } -+ } else if (pattrib->amsdu == 1) { /* temp filter -> means didn't support A-MSDUs in a A-MPDU */ -+ if (!preorder_ctrl->enable) { -+ preorder_ctrl->indicate_seq = pattrib->seq_num; -+ retval = amsdu_to_msdu(padapter, prframe); -+ -+ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; -+ return retval; -+ } -+ } -+ -+ spin_lock_bh(&ppending_recvframe_queue->lock); -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, -+ ("recv_indicatepkt_reorder: indicate=%d seq=%d\n", -+ preorder_ctrl->indicate_seq, pattrib->seq_num)); -+ -+ /* s2. check if winstart_b(indicate_seq) needs to been updated */ -+ if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) -+ goto _err_exit; -+ -+ /* s3. Insert all packet into Reorder Queue to maintain its ordering. */ -+ if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) -+ goto _err_exit; -+ -+ /* s4. */ -+ /* Indication process. */ -+ /* After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */ -+ /* with the SeqNum smaller than latest WinStart and buffer other packets. */ -+ /* */ -+ /* For Rx Reorder condition: */ -+ /* 1. All packets with SeqNum smaller than WinStart => Indicate */ -+ /* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */ -+ /* */ -+ -+ /* recv_indicatepkts_in_order(padapter, preorder_ctrl, true); */ -+ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) { -+ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); -+ spin_unlock_bh(&ppending_recvframe_queue->lock); -+ } else { -+ spin_unlock_bh(&ppending_recvframe_queue->lock); -+ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); -+ } -+ -+_success_exit: -+ -+ return _SUCCESS; -+ -+_err_exit: -+ -+ spin_unlock_bh(&ppending_recvframe_queue->lock); -+ -+ return _FAIL; -+} -+ -+void rtw_reordering_ctrl_timeout_handler(void *pcontext) -+{ -+ struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; -+ struct adapter *padapter = preorder_ctrl->padapter; -+ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; -+ -+ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) -+ return; -+ -+ spin_lock_bh(&ppending_recvframe_queue->lock); -+ -+ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) == true) -+ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); -+ -+ spin_unlock_bh(&ppending_recvframe_queue->lock); -+} -+ -+static int process_recv_indicatepkts(struct adapter *padapter, struct recv_frame *prframe) -+{ -+ int retval = _SUCCESS; -+ /* struct recv_priv *precvpriv = &padapter->recvpriv; */ -+ /* struct rx_pkt_attrib *pattrib = &prframe->attrib; */ -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ -+ if (phtpriv->ht_option) { /* B/G/N Mode */ -+ /* prframe->preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */ -+ -+ if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) { -+ /* including perform A-MPDU Rx Ordering Buffer Control */ -+ if ((!padapter->bDriverStopped) && -+ (!padapter->bSurpriseRemoved)) { -+ retval = _FAIL; -+ return retval; -+ } -+ } -+ } else { /* B/G mode */ -+ retval = wlanhdr_to_ethhdr (prframe); -+ if (retval != _SUCCESS) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("wlanhdr_to_ethhdr: drop pkt\n")); -+ return retval; -+ } -+ -+ if ((!padapter->bDriverStopped) && -+ (!padapter->bSurpriseRemoved)) { -+ /* indicate this recv_frame */ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n")); -+ rtw_recv_indicatepkt(padapter, prframe); -+ } else { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n")); -+ -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); -+ retval = _FAIL; -+ return retval; -+ } -+ } -+ -+ return retval; -+} -+ -+static int recv_func_prehandle(struct adapter *padapter, struct recv_frame *rframe) -+{ -+ int ret = _SUCCESS; -+ struct rx_pkt_attrib *pattrib = &rframe->attrib; -+ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ if (padapter->registrypriv.mp_mode == 1) { -+ if (pattrib->crc_err == 1) -+ padapter->mppriv.rx_crcerrpktcount++; -+ else -+ padapter->mppriv.rx_pktcount++; -+ -+ if (check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE) == false) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_alert_, ("MP - Not in loopback mode , drop pkt\n")); -+ ret = _FAIL; -+ rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ -+ goto exit; -+ } -+ } -+ -+ /* check the frame crtl field and decache */ -+ ret = validate_recv_frame(padapter, rframe); -+ if (ret != _SUCCESS) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n")); -+ rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ -+ goto exit; -+ } -+ -+exit: -+ return ret; -+} -+ -+static int recv_func_posthandle(struct adapter *padapter, struct recv_frame *prframe) -+{ -+ int ret = _SUCCESS; -+ struct recv_frame *orig_prframe = prframe; -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; -+ -+ /* DATA FRAME */ -+ rtw_led_control(padapter, LED_CTL_RX); -+ -+ prframe = decryptor(padapter, prframe); -+ if (prframe == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n")); -+ ret = _FAIL; -+ goto _recv_data_drop; -+ } -+ -+ prframe = recvframe_chk_defrag(padapter, prframe); -+ if (prframe == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n")); -+ goto _recv_data_drop; -+ } -+ -+ prframe = portctrl(padapter, prframe); -+ if (prframe == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n")); -+ ret = _FAIL; -+ goto _recv_data_drop; -+ } -+ -+ count_rx_stats(padapter, prframe, NULL); -+ -+ ret = process_recv_indicatepkts(padapter, prframe); -+ if (ret != _SUCCESS) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recv_func: process_recv_indicatepkts fail!\n")); -+ rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */ -+ goto _recv_data_drop; -+ } -+ return ret; -+ -+_recv_data_drop: -+ precvpriv->rx_drop++; -+ return ret; -+} -+ -+static int recv_func(struct adapter *padapter, struct recv_frame *rframe) -+{ -+ int ret; -+ struct rx_pkt_attrib *prxattrib = &rframe->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct mlme_priv *mlmepriv = &padapter->mlmepriv; -+ struct recv_priv *recvpriv = &padapter->recvpriv; -+ -+ /* check if need to handle uc_swdec_pending_queue*/ -+ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && -+ psecuritypriv->busetkipkey) { -+ struct recv_frame *pending_frame; -+ int cnt = 0; -+ -+ pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); -+ while (pending_frame) { -+ cnt++; -+ recv_func_posthandle(padapter, pending_frame); -+ } -+ } -+ -+ ret = recv_func_prehandle(padapter, rframe); -+ -+ if (ret == _SUCCESS) { -+ /* check if need to enqueue into uc_swdec_pending_queue*/ -+ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && -+ !IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 && -+ (prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt) && -+ psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK && -+ !psecuritypriv->busetkipkey) { -+ rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); -+ DBG_88E("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); -+ if (recvpriv->free_recvframe_cnt < NR_RECVFRAME/4) { -+ /* to prevent from recvframe starvation, -+ * get recvframe from uc_swdec_pending_queue to -+ * free_recvframe_cnt */ -+ rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); -+ if (rframe) -+ goto do_posthandle; -+ } -+ goto exit; -+ } -+do_posthandle: -+ ret = recv_func_posthandle(padapter, rframe); -+ } -+ -+exit: -+ return ret; -+} -+ -+s32 rtw_recv_entry(struct recv_frame *precvframe) -+{ -+ struct adapter *padapter; -+ struct recv_priv *precvpriv; -+ s32 ret = _SUCCESS; -+ -+ padapter = precvframe->adapter; -+ -+ precvpriv = &padapter->recvpriv; -+ -+ ret = recv_func(padapter, precvframe); -+ if (ret == _FAIL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n")); -+ goto _recv_entry_drop; -+ } -+ -+ precvpriv->rx_pkts++; -+ -+ return ret; -+ -+_recv_entry_drop: -+ -+ if (padapter->registrypriv.mp_mode == 1) -+ padapter->mppriv.rx_pktloss = precvpriv->rx_drop; -+ -+ return ret; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+void rtw_signal_stat_timer_hdl(struct timer_list *t) -+#else -+void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -+ struct adapter *adapter = from_timer(adapter, t, recvpriv.signal_stat_timer); -+#else -+ struct adapter *adapter = (struct adapter *)FunctionContext; -+#endif -+ struct recv_priv *recvpriv = &adapter->recvpriv; -+ -+ u32 tmp_s, tmp_q; -+ u8 avg_signal_strength = 0; -+ u8 avg_signal_qual = 0; -+ u8 _alpha = 3; /* this value is based on converging_constant = 5000 and sampling_interval = 1000 */ -+ -+ if (adapter->recvpriv.is_signal_dbg) { -+ /* update the user specific value, signal_strength_dbg, to signal_strength, rssi */ -+ adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg; -+ adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg); -+ } else { -+ if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */ -+ avg_signal_strength = recvpriv->signal_strength_data.avg_val; -+ /* after avg_vals are accquired, we can re-stat the signal values */ -+ recvpriv->signal_strength_data.update_req = 1; -+ } -+ -+ if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */ -+ avg_signal_qual = recvpriv->signal_qual_data.avg_val; -+ /* after avg_vals are accquired, we can re-stat the signal values */ -+ recvpriv->signal_qual_data.update_req = 1; -+ } -+ -+ /* update value of signal_strength, rssi, signal_qual */ -+ if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == false) { -+ tmp_s = (avg_signal_strength+(_alpha-1)*recvpriv->signal_strength); -+ if (tmp_s % _alpha) -+ tmp_s = tmp_s/_alpha + 1; -+ else -+ tmp_s = tmp_s/_alpha; -+ if (tmp_s > 100) -+ tmp_s = 100; -+ -+ tmp_q = (avg_signal_qual+(_alpha-1)*recvpriv->signal_qual); -+ if (tmp_q % _alpha) -+ tmp_q = tmp_q/_alpha + 1; -+ else -+ tmp_q = tmp_q/_alpha; -+ if (tmp_q > 100) -+ tmp_q = 100; -+ -+ recvpriv->signal_strength = tmp_s; -+ recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); -+ recvpriv->signal_qual = tmp_q; -+ } -+ } -+ rtw_set_signal_stat_timer(recvpriv); -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_rf.c b/drivers/net/wireless/rtl8188eu/core/rtw_rf.c -new file mode 100644 -index 0000000000000..40c0f5aa0731d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_rf.c -@@ -0,0 +1,88 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_RF_C_ -+ -+#include -+#include -+#include -+#include -+ -+struct ch_freq { -+ u32 channel; -+ u32 frequency; -+}; -+ -+static struct ch_freq ch_freq_map[] = { -+ {1, 2412}, {2, 2417}, {3, 2422}, {4, 2427}, {5, 2432}, -+ {6, 2437}, {7, 2442}, {8, 2447}, {9, 2452}, {10, 2457}, -+ {11, 2462}, {12, 2467}, {13, 2472}, {14, 2484}, -+ /* UNII */ -+ {36, 5180}, {40, 5200}, {44, 5220}, {48, 5240}, {52, 5260}, -+ {56, 5280}, {60, 5300}, {64, 5320}, {149, 5745}, {153, 5765}, -+ {157, 5785}, {161, 5805}, {165, 5825}, {167, 5835}, {169, 5845}, -+ {171, 5855}, {173, 5865}, -+ /* HiperLAN2 */ -+ {100, 5500}, {104, 5520}, {108, 5540}, {112, 5560}, {116, 5580}, -+ {120, 5600}, {124, 5620}, {128, 5640}, {132, 5660}, {136, 5680}, -+ {140, 5700}, -+ /* Japan MMAC */ -+ {34, 5170}, {38, 5190}, {42, 5210}, {46, 5230}, -+ /* Japan */ -+ {184, 4920}, {188, 4940}, {192, 4960}, {196, 4980}, -+ {208, 5040},/* Japan, means J08 */ -+ {212, 5060},/* Japan, means J12 */ -+ {216, 5080},/* Japan, means J16 */ -+}; -+ -+static int ch_freq_map_num = (sizeof(ch_freq_map) / sizeof(struct ch_freq)); -+ -+u32 rtw_ch2freq(u32 channel) -+{ -+ u8 i; -+ u32 freq = 0; -+ -+ for (i = 0; i < ch_freq_map_num; i++) { -+ if (channel == ch_freq_map[i].channel) { -+ freq = ch_freq_map[i].frequency; -+ break; -+ } -+ } -+ if (i == ch_freq_map_num) -+ freq = 2412; -+ -+ return freq; -+} -+ -+u32 rtw_freq2ch(u32 freq) -+{ -+ u8 i; -+ u32 ch = 0; -+ -+ for (i = 0; i < ch_freq_map_num; i++) { -+ if (freq == ch_freq_map[i].frequency) { -+ ch = ch_freq_map[i].channel; -+ break; -+ } -+ } -+ if (i == ch_freq_map_num) -+ ch = 1; -+ -+ return ch; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_security.c b/drivers/net/wireless/rtl8188eu/core/rtw_security.c -new file mode 100644 -index 0000000000000..1da908694e186 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_security.c -@@ -0,0 +1,1757 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_SECURITY_C_ -+ -+#include -+#include -+#include -+#include -+ -+/* WEP related ===== */ -+ -+#define CRC32_POLY 0x04c11db7 -+ -+struct arc4context { -+ u32 x; -+ u32 y; -+ u8 state[256]; -+}; -+ -+static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len) -+{ -+ u32 t, u; -+ u32 keyindex; -+ u32 stateindex; -+ u8 *state; -+ u32 counter; -+ -+ state = parc4ctx->state; -+ parc4ctx->x = 0; -+ parc4ctx->y = 0; -+ for (counter = 0; counter < 256; counter++) -+ state[counter] = (u8)counter; -+ keyindex = 0; -+ stateindex = 0; -+ for (counter = 0; counter < 256; counter++) { -+ t = state[counter]; -+ stateindex = (stateindex + key[keyindex] + t) & 0xff; -+ u = state[stateindex]; -+ state[stateindex] = (u8)t; -+ state[counter] = (u8)u; -+ if (++keyindex >= key_len) -+ keyindex = 0; -+ } -+ -+} -+ -+static u32 arcfour_byte(struct arc4context *parc4ctx) -+{ -+ u32 x; -+ u32 y; -+ u32 sx, sy; -+ u8 *state; -+ -+ state = parc4ctx->state; -+ x = (parc4ctx->x + 1) & 0xff; -+ sx = state[x]; -+ y = (sx + parc4ctx->y) & 0xff; -+ sy = state[y]; -+ parc4ctx->x = x; -+ parc4ctx->y = y; -+ state[y] = (u8)sx; -+ state[x] = (u8)sy; -+ -+ return state[(sx + sy) & 0xff]; -+} -+ -+static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len) -+{ -+ u32 i; -+ -+ for (i = 0; i < len; i++) -+ dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); -+ -+} -+ -+static int bcrc32initialized; -+static u32 crc32_table[256]; -+ -+static u8 crc32_reverseBit(u8 data) -+{ -+ return (u8)((data<<7)&0x80) | ((data<<5)&0x40) | ((data<<3)&0x20) | -+ ((data<<1)&0x10) | ((data>>1)&0x08) | ((data>>3)&0x04) | -+ ((data>>5)&0x02) | ((data>>7)&0x01); -+} -+ -+static void crc32_init(void) -+{ -+ if (bcrc32initialized == 1) { -+ return; -+ } else { -+ int i, j; -+ u32 c; -+ u8 *p = (u8 *)&c, *p1; -+ u8 k; -+ -+ c = 0x12340000; -+ -+ for (i = 0; i < 256; ++i) { -+ k = crc32_reverseBit((u8)i); -+ for (c = ((u32)k) << 24, j = 8; j > 0; --j) -+ c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1); -+ p1 = (u8 *)&crc32_table[i]; -+ -+ p1[0] = crc32_reverseBit(p[3]); -+ p1[1] = crc32_reverseBit(p[2]); -+ p1[2] = crc32_reverseBit(p[1]); -+ p1[3] = crc32_reverseBit(p[0]); -+ } -+ bcrc32initialized = 1; -+ } -+} -+ -+static __le32 getcrc32(u8 *buf, int len) -+{ -+ u8 *p; -+ u32 crc; -+ -+ if (bcrc32initialized == 0) -+ crc32_init(); -+ -+ crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ -+ -+ for (p = buf; len > 0; ++p, --len) -+ crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8); -+ -+ return cpu_to_le32(~crc); /* transmit complement, per CRC-32 spec */ -+} -+ -+/* -+ Need to consider the fragment situation -+*/ -+void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) -+{ /* exclude ICV */ -+ -+ unsigned char crc[4]; -+ struct arc4context mycontext; -+ -+ int curfragnum, length; -+ u32 keylength; -+ -+ u8 *pframe, *payload, *iv; /* wepkey */ -+ u8 wepkey[16]; -+ u8 hw_hdr_offset = 0; -+ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+ if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) -+ return; -+ -+ hw_hdr_offset = TXDESC_SIZE + -+ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); -+ -+ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; -+ -+ /* start to encrypt each fragment */ -+ if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) { -+ keylength = psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex]; -+ -+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { -+ iv = pframe+pattrib->hdrlen; -+ memcpy(&wepkey[0], iv, 3); -+ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); -+ payload = pframe+pattrib->iv_len+pattrib->hdrlen; -+ -+ if ((curfragnum+1) == pattrib->nr_frags) { /* the last fragment */ -+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len; -+ -+ *((__le32 *)crc) = getcrc32(payload, length); -+ -+ arcfour_init(&mycontext, wepkey, 3+keylength); -+ arcfour_encrypt(&mycontext, payload, payload, length); -+ arcfour_encrypt(&mycontext, payload+length, crc, 4); -+ } else { -+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len; -+ *((__le32 *)crc) = getcrc32(payload, length); -+ arcfour_init(&mycontext, wepkey, 3+keylength); -+ arcfour_encrypt(&mycontext, payload, payload, length); -+ arcfour_encrypt(&mycontext, payload+length, crc, 4); -+ -+ pframe += pxmitpriv->frag_len; -+ pframe = (u8 *)RND4((size_t)(pframe)); -+ } -+ } -+ } -+ -+} -+ -+void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) -+{ -+ /* exclude ICV */ -+ u8 crc[4]; -+ struct arc4context mycontext; -+ int length; -+ u32 keylength; -+ u8 *pframe, *payload, *iv, wepkey[16]; -+ u8 keyindex; -+ struct rx_pkt_attrib *prxattrib = &(((struct recv_frame *)precvframe)->attrib); -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ -+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data; -+ -+ /* start to decrypt recvframe */ -+ if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) { -+ iv = pframe+prxattrib->hdrlen; -+ keyindex = prxattrib->key_index; -+ keylength = psecuritypriv->dot11DefKeylen[keyindex]; -+ memcpy(&wepkey[0], iv, 3); -+ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength); -+ length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len; -+ -+ payload = pframe+prxattrib->iv_len+prxattrib->hdrlen; -+ -+ /* decrypt payload include icv */ -+ arcfour_init(&mycontext, wepkey, 3+keylength); -+ arcfour_encrypt(&mycontext, payload, payload, length); -+ -+ /* calculate icv and compare the icv */ -+ *((__le32 *)crc) = getcrc32(payload, length - 4); -+ -+ if (crc[3] != payload[length-1] || -+ crc[2] != payload[length-2] || -+ crc[1] != payload[length-3] || -+ crc[0] != payload[length-4]) { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, -+ ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n", -+ &crc, &payload[length-4])); -+ } -+ } -+ -+ return; -+} -+ -+/* 3 ===== TKIP related ===== */ -+ -+static u32 secmicgetuint32(u8 *p) -+/* Convert from Byte[] to Us3232 in a portable way */ -+{ -+ s32 i; -+ u32 res = 0; -+ -+ for (i = 0; i < 4; i++) -+ res |= ((u32)(*p++)) << (8*i); -+ -+ return res; -+} -+ -+static void secmicputuint32(u8 *p, u32 val) -+/* Convert from Us3232 to Byte[] in a portable way */ -+{ -+ long i; -+ -+ for (i = 0; i < 4; i++) { -+ *p++ = (u8) (val & 0xff); -+ val >>= 8; -+ } -+ -+} -+ -+static void secmicclear(struct mic_data *pmicdata) -+{ -+/* Reset the state to the empty message. */ -+ -+ pmicdata->L = pmicdata->K0; -+ pmicdata->R = pmicdata->K1; -+ pmicdata->nBytesInM = 0; -+ pmicdata->M = 0; -+ -+} -+ -+void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key) -+{ -+ /* Set the key */ -+ -+ pmicdata->K0 = secmicgetuint32(key); -+ pmicdata->K1 = secmicgetuint32(key + 4); -+ /* and reset the message */ -+ secmicclear(pmicdata); -+ -+} -+ -+void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b) -+{ -+ -+ /* Append the byte to our word-sized buffer */ -+ pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM); -+ pmicdata->nBytesInM++; -+ /* Process the word if it is full. */ -+ if (pmicdata->nBytesInM >= 4) { -+ pmicdata->L ^= pmicdata->M; -+ pmicdata->R ^= ROL32(pmicdata->L, 17); -+ pmicdata->L += pmicdata->R; -+ pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8); -+ pmicdata->L += pmicdata->R; -+ pmicdata->R ^= ROL32(pmicdata->L, 3); -+ pmicdata->L += pmicdata->R; -+ pmicdata->R ^= ROR32(pmicdata->L, 2); -+ pmicdata->L += pmicdata->R; -+ /* Clear the buffer */ -+ pmicdata->M = 0; -+ pmicdata->nBytesInM = 0; -+ } -+ -+} -+ -+void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes) -+{ -+ -+ /* This is simple */ -+ while (nbytes > 0) { -+ rtw_secmicappendbyte(pmicdata, *src++); -+ nbytes--; -+ } -+ -+} -+ -+void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst) -+{ -+ -+ /* Append the minimum padding */ -+ rtw_secmicappendbyte(pmicdata, 0x5a); -+ rtw_secmicappendbyte(pmicdata, 0); -+ rtw_secmicappendbyte(pmicdata, 0); -+ rtw_secmicappendbyte(pmicdata, 0); -+ rtw_secmicappendbyte(pmicdata, 0); -+ /* and then zeroes until the length is a multiple of 4 */ -+ while (pmicdata->nBytesInM != 0) -+ rtw_secmicappendbyte(pmicdata, 0); -+ /* The appendByte function has already computed the result. */ -+ secmicputuint32(dst, pmicdata->L); -+ secmicputuint32(dst+4, pmicdata->R); -+ /* Reset to the empty message. */ -+ secmicclear(pmicdata); -+ -+} -+ -+void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri) -+{ -+ struct mic_data micdata; -+ u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; -+ -+ rtw_secmicsetkey(&micdata, key); -+ priority[0] = pri; -+ -+ /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ -+ if (header[1]&1) { /* ToDS == 1 */ -+ rtw_secmicappend(&micdata, &header[16], 6); /* DA */ -+ if (header[1]&2) /* From Ds == 1 */ -+ rtw_secmicappend(&micdata, &header[24], 6); -+ else -+ rtw_secmicappend(&micdata, &header[10], 6); -+ } else { /* ToDS == 0 */ -+ rtw_secmicappend(&micdata, &header[4], 6); /* DA */ -+ if (header[1]&2) /* From Ds == 1 */ -+ rtw_secmicappend(&micdata, &header[16], 6); -+ else -+ rtw_secmicappend(&micdata, &header[10], 6); -+ } -+ rtw_secmicappend(&micdata, &priority[0], 4); -+ -+ rtw_secmicappend(&micdata, data, data_len); -+ -+ rtw_secgetmic(&micdata, mic_code); -+ -+} -+ -+/* macros for extraction/creation of unsigned char/unsigned short values */ -+#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) -+#define Lo8(v16) ((u8)((v16) & 0x00FF)) -+#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) -+#define Lo16(v32) ((u16)((v32) & 0xFFFF)) -+#define Hi16(v32) ((u16)(((v32) >> 16) & 0xFFFF)) -+#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8)) -+ -+/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ -+#define TK16(N) Mk16(tk[2*(N)+1], tk[2*(N)]) -+ -+/* S-box lookup: 16 bits --> 16 bits */ -+#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][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-unsigned char by 2-unsigned char subset of the full AES S-box table */ -+static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM) */ -+{ -+ 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, -+ }, -+ -+ { /* second half of table is unsigned char-reversed version of first! */ -+ 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, -+ 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, -+ 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, -+ 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, -+ 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, -+ 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, -+ 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, -+ 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, -+ 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, -+ 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, -+ 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, -+ 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, -+ 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, -+ 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, -+ 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, -+ 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, -+ 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, -+ 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, -+ 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, -+ 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, -+ 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, -+ 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, -+ 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, -+ 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, -+ 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, -+ 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, -+ 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, -+ 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, -+ 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, -+ 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, -+ 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, -+ 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C, -+ } -+}; -+ -+ /* -+********************************************************************** -+* 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 packets, -+* although in theory it could be called every packet. -+* -+********************************************************************** -+*/ -+static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 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] += (unsigned short)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 packet [128 bits] -+* -+* Note: -+* The value {TA, IV32, IV16} for Phase1/Phase2 must be unique -+* across all packets 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 packets. -+* -+* Suggested implementation optimization: if PPK[] is "overlaid" -+* appropriately on RC4KEY[], there is no need for the final -+* for loop below that copies the PPK[] result into RC4KEY[]. -+* -+********************************************************************** -+*/ -+static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) -+{ -+ int i; -+ u16 PPK[6]; /* temporary key for mixing */ -+ -+ /* Note: 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]); -+ /* Note: 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 weak (FMS) keys */ -+ rc4key[2] = Lo8(iv16); -+ rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); -+ -+ /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ -+ for (i = 0; i < 6; i++) { -+ rc4key[4+2*i] = Lo8(PPK[i]); -+ rc4key[5+2*i] = Hi8(PPK[i]); -+ } -+ -+} -+ -+/* The hlen isn't include the IV */ -+u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) -+{ /* exclude ICV */ -+ u16 pnl; -+ u32 pnh; -+ u8 rc4key[16]; -+ u8 ttkey[16]; -+ u8 crc[4]; -+ u8 hw_hdr_offset = 0; -+ struct arc4context mycontext; -+ int curfragnum, length; -+ -+ u8 *pframe, *payload, *iv, *prwskey; -+ union pn48 dot11txpn; -+ struct sta_info *stainfo; -+ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ u32 res = _SUCCESS; -+ -+ if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) -+ return _FAIL; -+ -+ hw_hdr_offset = TXDESC_SIZE + -+ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); -+ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; -+ /* 4 start to encrypt each fragment */ -+ if (pattrib->encrypt == _TKIP_) { -+ if (pattrib->psta) -+ stainfo = pattrib->psta; -+ else -+ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); -+ -+ if (stainfo != NULL) { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo!= NULL!!!\n")); -+ -+ if (IS_MCAST(pattrib->ra)) -+ prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; -+ else -+ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; -+ -+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { -+ iv = pframe+pattrib->hdrlen; -+ payload = pframe+pattrib->iv_len+pattrib->hdrlen; -+ -+ GET_TKIP_PN(iv, dot11txpn); -+ -+ pnl = (u16)(dot11txpn.val); -+ pnh = (u32)(dot11txpn.val>>16); -+ phase1((u16 *)&ttkey[0], prwskey, &pattrib->ta[0], pnh); -+ phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl); -+ -+ if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */ -+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len; -+ RT_TRACE(_module_rtl871x_security_c_, _drv_info_, -+ ("pattrib->iv_len=%x, pattrib->icv_len=%x\n", -+ pattrib->iv_len, pattrib->icv_len)); -+ *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/ -+ -+ arcfour_init(&mycontext, rc4key, 16); -+ arcfour_encrypt(&mycontext, payload, payload, length); -+ arcfour_encrypt(&mycontext, payload+length, crc, 4); -+ } else { -+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; -+ *((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/ -+ arcfour_init(&mycontext, rc4key, 16); -+ arcfour_encrypt(&mycontext, payload, payload, length); -+ arcfour_encrypt(&mycontext, payload+length, crc, 4); -+ -+ pframe += pxmitpriv->frag_len; -+ pframe = (u8 *)RND4((size_t)(pframe)); -+ } -+ } -+ } else { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo==NULL!!!\n")); -+ res = _FAIL; -+ } -+ } -+ -+ return res; -+} -+ -+/* The hlen isn't include the IV */ -+u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) -+{ /* exclude ICV */ -+ u16 pnl; -+ u32 pnh; -+ u8 rc4key[16]; -+ u8 ttkey[16]; -+ u8 crc[4]; -+ struct arc4context mycontext; -+ int length; -+ -+ u8 *pframe, *payload, *iv, *prwskey; -+ union pn48 dot11txpn; -+ struct sta_info *stainfo; -+ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ u32 res = _SUCCESS; -+ -+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data; -+ -+ /* 4 start to decrypt recvframe */ -+ if (prxattrib->encrypt == _TKIP_) { -+ stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); -+ if (stainfo != NULL) { -+ if (IS_MCAST(prxattrib->ra)) { -+ if (!psecuritypriv->binstallGrpkey) { -+ res = _FAIL; -+ DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); -+ goto exit; -+ } -+ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; -+ } else { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo!= NULL!!!\n")); -+ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; -+ } -+ -+ iv = pframe+prxattrib->hdrlen; -+ payload = pframe+prxattrib->iv_len+prxattrib->hdrlen; -+ length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len; -+ -+ GET_TKIP_PN(iv, dot11txpn); -+ -+ pnl = (u16)(dot11txpn.val); -+ pnh = (u32)(dot11txpn.val>>16); -+ -+ phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh); -+ phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl); -+ -+ /* 4 decrypt payload include icv */ -+ -+ arcfour_init(&mycontext, rc4key, 16); -+ arcfour_encrypt(&mycontext, payload, payload, length); -+ -+ *((__le32 *)crc) = getcrc32(payload, length-4); -+ -+ if (crc[3] != payload[length-1] || -+ crc[2] != payload[length-2] || -+ crc[1] != payload[length-3] || -+ crc[0] != payload[length-4]) { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, -+ ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n", -+ &crc, &payload[length-4])); -+ res = _FAIL; -+ } -+ } else { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo==NULL!!!\n")); -+ res = _FAIL; -+ } -+ } -+ -+exit: -+ return res; -+} -+ -+/* 3 ===== AES related ===== */ -+ -+#define MAX_MSG_SIZE 2048 -+/*****************************/ -+/******** SBOX Table *********/ -+/*****************************/ -+ -+static u8 sbox_table[256] = { -+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, -+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, -+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, -+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, -+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, -+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, -+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, -+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, -+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, -+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, -+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, -+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, -+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, -+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, -+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, -+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, -+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, -+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, -+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, -+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, -+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, -+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, -+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, -+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, -+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, -+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, -+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, -+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, -+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, -+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, -+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, -+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -+}; -+ -+/*****************************/ -+/**** Function Prototypes ****/ -+/*****************************/ -+ -+static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); -+static void construct_mic_iv(u8 *mic_header1, int qc_exists, int a4_exists, u8 *mpdu, uint payload_length, u8 *pn_vector); -+static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu); -+static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists); -+static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c); -+static void xor_128(u8 *a, u8 *b, u8 *out); -+static void xor_32(u8 *a, u8 *b, u8 *out); -+static u8 sbox(u8 a); -+static void next_key(u8 *key, int round); -+static void byte_sub(u8 *in, u8 *out); -+static void shift_row(u8 *in, u8 *out); -+static void mix_column(u8 *in, u8 *out); -+static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext); -+ -+/****************************************/ -+/* aes128k128d() */ -+/* Performs a 128 bit AES encrypt with */ -+/* 128 bit data. */ -+/****************************************/ -+static void xor_128(u8 *a, u8 *b, u8 *out) -+{ -+ int i; -+ -+ for (i = 0; i < 16; i++) -+ out[i] = a[i] ^ b[i]; -+ -+} -+ -+static void xor_32(u8 *a, u8 *b, u8 *out) -+{ -+ int i; -+ -+ for (i = 0; i < 4; i++) -+ out[i] = a[i] ^ b[i]; -+ -+} -+ -+static u8 sbox(u8 a) -+{ -+ return sbox_table[(int)a]; -+} -+ -+static void next_key(u8 *key, int round) -+{ -+ u8 rcon; -+ u8 sbox_key[4]; -+ u8 rcon_table[12] = { -+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, -+ 0x1b, 0x36, 0x36, 0x36 -+ }; -+ -+ sbox_key[0] = sbox(key[13]); -+ sbox_key[1] = sbox(key[14]); -+ sbox_key[2] = sbox(key[15]); -+ sbox_key[3] = sbox(key[12]); -+ -+ rcon = rcon_table[round]; -+ -+ xor_32(&key[0], sbox_key, &key[0]); -+ key[0] = key[0] ^ rcon; -+ -+ xor_32(&key[4], &key[0], &key[4]); -+ xor_32(&key[8], &key[4], &key[8]); -+ xor_32(&key[12], &key[8], &key[12]); -+ -+} -+ -+static void byte_sub(u8 *in, u8 *out) -+{ -+ int i; -+ -+ for (i = 0; i < 16; i++) -+ out[i] = sbox(in[i]); -+ -+} -+ -+static void shift_row(u8 *in, u8 *out) -+{ -+ -+ out[0] = in[0]; -+ out[1] = in[5]; -+ out[2] = in[10]; -+ out[3] = in[15]; -+ out[4] = in[4]; -+ out[5] = in[9]; -+ out[6] = in[14]; -+ out[7] = in[3]; -+ out[8] = in[8]; -+ out[9] = in[13]; -+ out[10] = in[2]; -+ out[11] = in[7]; -+ out[12] = in[12]; -+ out[13] = in[1]; -+ out[14] = in[6]; -+ out[15] = in[11]; -+ -+} -+ -+static void mix_column(u8 *in, u8 *out) -+{ -+ int i; -+ u8 add1b[4]; -+ u8 add1bf7[4]; -+ u8 rotl[4]; -+ u8 swap_halfs[4]; -+ u8 andf7[4]; -+ u8 rotr[4]; -+ u8 temp[4]; -+ u8 tempb[4]; -+ -+ for (i = 0 ; i < 4; i++) { -+ if ((in[i] & 0x80) == 0x80) -+ add1b[i] = 0x1b; -+ else -+ add1b[i] = 0x00; -+ } -+ -+ swap_halfs[0] = in[2]; /* Swap halves */ -+ swap_halfs[1] = in[3]; -+ swap_halfs[2] = in[0]; -+ swap_halfs[3] = in[1]; -+ -+ rotl[0] = in[3]; /* Rotate left 8 bits */ -+ rotl[1] = in[0]; -+ rotl[2] = in[1]; -+ rotl[3] = in[2]; -+ -+ andf7[0] = in[0] & 0x7f; -+ andf7[1] = in[1] & 0x7f; -+ andf7[2] = in[2] & 0x7f; -+ andf7[3] = in[3] & 0x7f; -+ -+ for (i = 3; i > 0; i--) { /* logical shift left 1 bit */ -+ andf7[i] = andf7[i] << 1; -+ if ((andf7[i-1] & 0x80) == 0x80) -+ andf7[i] = (andf7[i] | 0x01); -+ } -+ andf7[0] = andf7[0] << 1; -+ andf7[0] = andf7[0] & 0xfe; -+ -+ xor_32(add1b, andf7, add1bf7); -+ -+ xor_32(in, add1bf7, rotr); -+ -+ temp[0] = rotr[0]; /* Rotate right 8 bits */ -+ rotr[0] = rotr[1]; -+ rotr[1] = rotr[2]; -+ rotr[2] = rotr[3]; -+ rotr[3] = temp[0]; -+ -+ xor_32(add1bf7, rotr, temp); -+ xor_32(swap_halfs, rotl, tempb); -+ xor_32(temp, tempb, out); -+ -+} -+ -+static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) -+{ -+ int round; -+ int i; -+ u8 intermediatea[16]; -+ u8 intermediateb[16]; -+ u8 round_key[16]; -+ -+ for (i = 0; i < 16; i++) -+ round_key[i] = key[i]; -+ for (round = 0; round < 11; round++) { -+ if (round == 0) { -+ xor_128(round_key, data, ciphertext); -+ next_key(round_key, round); -+ } else if (round == 10) { -+ byte_sub(ciphertext, intermediatea); -+ shift_row(intermediatea, intermediateb); -+ xor_128(intermediateb, round_key, ciphertext); -+ } else { /* 1 - 9 */ -+ byte_sub(ciphertext, intermediatea); -+ shift_row(intermediatea, intermediateb); -+ mix_column(&intermediateb[0], &intermediatea[0]); -+ mix_column(&intermediateb[4], &intermediatea[4]); -+ mix_column(&intermediateb[8], &intermediatea[8]); -+ mix_column(&intermediateb[12], &intermediatea[12]); -+ xor_128(intermediatea, round_key, ciphertext); -+ next_key(round_key, round); -+ } -+ } -+ -+} -+ -+/************************************************/ -+/* construct_mic_iv() */ -+/* Builds the MIC IV from header fields and PN */ -+/************************************************/ -+static void construct_mic_iv(u8 *mic_iv, int qc_exists, int a4_exists, u8 *mpdu, -+ uint payload_length, u8 *pn_vector) -+{ -+ int i; -+ -+ mic_iv[0] = 0x59; -+ if (qc_exists && a4_exists) -+ mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ -+ if (qc_exists && !a4_exists) -+ mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ -+ if (!qc_exists) -+ mic_iv[1] = 0x00; -+ for (i = 2; i < 8; i++) -+ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ -+ for (i = 8; i < 14; i++) -+ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ -+ mic_iv[14] = (unsigned char) (payload_length / 256); -+ mic_iv[15] = (unsigned char) (payload_length % 256); -+ -+} -+ -+/************************************************/ -+/* construct_mic_header1() */ -+/* Builds the first MIC header block from */ -+/* header fields. */ -+/************************************************/ -+static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu) -+{ -+ -+ mic_header1[0] = (u8)((header_length - 2) / 256); -+ mic_header1[1] = (u8)((header_length - 2) % 256); -+ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ -+ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ -+ mic_header1[4] = mpdu[4]; /* A1 */ -+ mic_header1[5] = mpdu[5]; -+ mic_header1[6] = mpdu[6]; -+ mic_header1[7] = mpdu[7]; -+ mic_header1[8] = mpdu[8]; -+ mic_header1[9] = mpdu[9]; -+ mic_header1[10] = mpdu[10]; /* A2 */ -+ mic_header1[11] = mpdu[11]; -+ mic_header1[12] = mpdu[12]; -+ mic_header1[13] = mpdu[13]; -+ mic_header1[14] = mpdu[14]; -+ mic_header1[15] = mpdu[15]; -+ -+} -+ -+/************************************************/ -+/* construct_mic_header2() */ -+/* Builds the last MIC header block from */ -+/* header fields. */ -+/************************************************/ -+static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists) -+{ -+ int i; -+ -+ for (i = 0; i < 16; i++) -+ mic_header2[i] = 0x00; -+ -+ mic_header2[0] = mpdu[16]; /* A3 */ -+ mic_header2[1] = mpdu[17]; -+ mic_header2[2] = mpdu[18]; -+ mic_header2[3] = mpdu[19]; -+ mic_header2[4] = mpdu[20]; -+ mic_header2[5] = mpdu[21]; -+ -+ mic_header2[6] = 0x00; -+ mic_header2[7] = 0x00; /* mpdu[23]; */ -+ -+ if (!qc_exists && a4_exists) { -+ for (i = 0; i < 6; i++) -+ mic_header2[8+i] = mpdu[24+i]; /* A4 */ -+ } -+ -+ if (qc_exists && !a4_exists) { -+ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ -+ mic_header2[9] = mpdu[25] & 0x00; -+ } -+ -+ if (qc_exists && a4_exists) { -+ for (i = 0; i < 6; i++) -+ mic_header2[8+i] = mpdu[24+i]; /* A4 */ -+ -+ mic_header2[14] = mpdu[30] & 0x0f; -+ mic_header2[15] = mpdu[31] & 0x00; -+ } -+ -+} -+ -+/************************************************/ -+/* construct_mic_header2() */ -+/* Builds the last MIC header block from */ -+/* header fields. */ -+/************************************************/ -+static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c) -+{ -+ int i; -+ -+ for (i = 0; i < 16; i++) -+ ctr_preload[i] = 0x00; -+ i = 0; -+ -+ ctr_preload[0] = 0x01; /* flag */ -+ if (qc_exists && a4_exists) -+ ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ -+ if (qc_exists && !a4_exists) -+ ctr_preload[1] = mpdu[24] & 0x0f; -+ -+ for (i = 2; i < 8; i++) -+ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ -+ for (i = 8; i < 14; i++) -+ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ -+ ctr_preload[14] = (unsigned char) (c / 256); /* Ctr */ -+ ctr_preload[15] = (unsigned char) (c % 256); -+ -+} -+ -+/************************************/ -+/* bitwise_xor() */ -+/* A 128 bit, bitwise exclusive or */ -+/************************************/ -+static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) -+{ -+ int i; -+ -+ for (i = 0; i < 16; i++) -+ out[i] = ina[i] ^ inb[i]; -+ -+} -+ -+static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen) -+{ -+ uint qc_exists, a4_exists, i, j, payload_remainder, -+ num_blocks, payload_index; -+ -+ u8 pn_vector[6]; -+ u8 mic_iv[16]; -+ u8 mic_header1[16]; -+ u8 mic_header2[16]; -+ u8 ctr_preload[16]; -+ -+ /* Intermediate Buffers */ -+ u8 chain_buffer[16]; -+ u8 aes_out[16]; -+ u8 padded_buffer[16]; -+ u8 mic[8]; -+ uint frtype = GetFrameType(pframe); -+ uint frsubtype = GetFrameSubType(pframe); -+ -+ frsubtype = frsubtype>>4; -+ -+ memset((void *)mic_iv, 0, 16); -+ memset((void *)mic_header1, 0, 16); -+ memset((void *)mic_header2, 0, 16); -+ memset((void *)ctr_preload, 0, 16); -+ memset((void *)chain_buffer, 0, 16); -+ memset((void *)aes_out, 0, 16); -+ memset((void *)padded_buffer, 0, 16); -+ -+ if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) -+ a4_exists = 0; -+ else -+ a4_exists = 1; -+ -+ if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || (frtype == WIFI_DATA_CFACKPOLL)) { -+ qc_exists = 1; -+ if (hdrlen != WLAN_HDR_A3_QOS_LEN) -+ hdrlen += 2; -+ } else if ((frsubtype == 0x08) || (frsubtype == 0x09) || (frsubtype == 0x0a) || (frsubtype == 0x0b)) { -+ if (hdrlen != WLAN_HDR_A3_QOS_LEN) -+ hdrlen += 2; -+ qc_exists = 1; -+ } else { -+ qc_exists = 0; -+ } -+ -+ pn_vector[0] = pframe[hdrlen]; -+ pn_vector[1] = pframe[hdrlen+1]; -+ pn_vector[2] = pframe[hdrlen+4]; -+ pn_vector[3] = pframe[hdrlen+5]; -+ pn_vector[4] = pframe[hdrlen+6]; -+ pn_vector[5] = pframe[hdrlen+7]; -+ -+ construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector); -+ -+ construct_mic_header1(mic_header1, hdrlen, pframe); -+ construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists); -+ -+ payload_remainder = plen % 16; -+ num_blocks = plen / 16; -+ -+ /* Find start of payload */ -+ payload_index = (hdrlen + 8); -+ -+ /* Calculate MIC */ -+ aes128k128d(key, mic_iv, aes_out); -+ bitwise_xor(aes_out, mic_header1, chain_buffer); -+ aes128k128d(key, chain_buffer, aes_out); -+ bitwise_xor(aes_out, mic_header2, chain_buffer); -+ aes128k128d(key, chain_buffer, aes_out); -+ -+ for (i = 0; i < num_blocks; i++) { -+ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ -+ -+ payload_index += 16; -+ aes128k128d(key, chain_buffer, aes_out); -+ } -+ -+ /* Add on the final payload block if it needs padding */ -+ if (payload_remainder > 0) { -+ for (j = 0; j < 16; j++) -+ padded_buffer[j] = 0x00; -+ for (j = 0; j < payload_remainder; j++) -+ padded_buffer[j] = pframe[payload_index++];/* padded_buffer[j] = message[payload_index++]; */ -+ bitwise_xor(aes_out, padded_buffer, chain_buffer); -+ aes128k128d(key, chain_buffer, aes_out); -+ } -+ -+ for (j = 0; j < 8; j++) -+ mic[j] = aes_out[j]; -+ -+ /* Insert MIC into payload */ -+ for (j = 0; j < 8; j++) -+ pframe[payload_index+j] = mic[j]; /* message[payload_index+j] = mic[j]; */ -+ -+ payload_index = hdrlen + 8; -+ for (i = 0; i < num_blocks; i++) { -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1); -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); -+ for (j = 0; j < 16; j++) -+ pframe[payload_index++] = chain_buffer[j]; -+ } -+ -+ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ -+ /* encrypt it and copy the unpadded part back */ -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1); -+ -+ for (j = 0; j < 16; j++) -+ padded_buffer[j] = 0x00; -+ for (j = 0; j < payload_remainder; j++) -+ padded_buffer[j] = pframe[payload_index+j]; -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, padded_buffer, chain_buffer); -+ for (j = 0; j < payload_remainder; j++) -+ pframe[payload_index++] = chain_buffer[j]; -+ } -+ /* Encrypt the MIC */ -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, 0); -+ -+ for (j = 0; j < 16; j++) -+ padded_buffer[j] = 0x00; -+ for (j = 0; j < 8; j++) -+ padded_buffer[j] = pframe[j+hdrlen+8+plen]; -+ -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, padded_buffer, chain_buffer); -+ for (j = 0; j < 8; j++) -+ pframe[payload_index++] = chain_buffer[j]; -+ -+ return _SUCCESS; -+} -+ -+u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) -+{ /* exclude ICV */ -+ -+ /*static*/ -+/* unsigned char message[MAX_MSG_SIZE]; */ -+ -+ /* Intermediate Buffers */ -+ int curfragnum, length; -+ u8 *pframe, *prwskey; /* *payload,*iv */ -+ u8 hw_hdr_offset = 0; -+ struct sta_info *stainfo; -+ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+/* uint offset = 0; */ -+ u32 res = _SUCCESS; -+ -+ if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) -+ return _FAIL; -+ -+ hw_hdr_offset = TXDESC_SIZE + -+ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); -+ -+ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; -+ -+ /* 4 start to encrypt each fragment */ -+ if ((pattrib->encrypt == _AES_)) { -+ if (pattrib->psta) -+ stainfo = pattrib->psta; -+ else -+ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); -+ -+ if (stainfo != NULL) { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n")); -+ -+ if (IS_MCAST(pattrib->ra)) -+ prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; -+ else -+ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; -+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { -+ if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */ -+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len; -+ -+ aes_cipher(prwskey, pattrib->hdrlen, pframe, length); -+ } else{ -+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ; -+ -+ aes_cipher(prwskey, pattrib->hdrlen, pframe, length); -+ pframe += pxmitpriv->frag_len; -+ pframe = (u8 *)RND4((size_t)(pframe)); -+ } -+ } -+ } else{ -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n")); -+ res = _FAIL; -+ } -+ } -+ -+ return res; -+} -+ -+static int aes_decipher(u8 *key, uint hdrlen, -+ u8 *pframe, uint plen) -+{ -+ static u8 message[MAX_MSG_SIZE]; -+ uint qc_exists, a4_exists, i, j, payload_remainder, -+ num_blocks, payload_index; -+ int res = _SUCCESS; -+ u8 pn_vector[6]; -+ u8 mic_iv[16]; -+ u8 mic_header1[16]; -+ u8 mic_header2[16]; -+ u8 ctr_preload[16]; -+ -+ /* Intermediate Buffers */ -+ u8 chain_buffer[16]; -+ u8 aes_out[16]; -+ u8 padded_buffer[16]; -+ u8 mic[8]; -+ -+/* uint offset = 0; */ -+ uint frtype = GetFrameType(pframe); -+ uint frsubtype = GetFrameSubType(pframe); -+ -+ frsubtype = frsubtype>>4; -+ -+ memset((void *)mic_iv, 0, 16); -+ memset((void *)mic_header1, 0, 16); -+ memset((void *)mic_header2, 0, 16); -+ memset((void *)ctr_preload, 0, 16); -+ memset((void *)chain_buffer, 0, 16); -+ memset((void *)aes_out, 0, 16); -+ memset((void *)padded_buffer, 0, 16); -+ -+ /* start to decrypt the payload */ -+ -+ num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */ -+ -+ payload_remainder = (plen-8) % 16; -+ -+ pn_vector[0] = pframe[hdrlen]; -+ pn_vector[1] = pframe[hdrlen+1]; -+ pn_vector[2] = pframe[hdrlen+4]; -+ pn_vector[3] = pframe[hdrlen+5]; -+ pn_vector[4] = pframe[hdrlen+6]; -+ pn_vector[5] = pframe[hdrlen+7]; -+ -+ if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) -+ a4_exists = 0; -+ else -+ a4_exists = 1; -+ -+ if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || -+ (frtype == WIFI_DATA_CFACKPOLL)) { -+ qc_exists = 1; -+ if (hdrlen != WLAN_HDR_A3_QOS_LEN) -+ hdrlen += 2; -+ } else if ((frsubtype == 0x08) || (frsubtype == 0x09) || -+ (frsubtype == 0x0a) || (frsubtype == 0x0b)) { -+ if (hdrlen != WLAN_HDR_A3_QOS_LEN) -+ hdrlen += 2; -+ qc_exists = 1; -+ } else { -+ qc_exists = 0; -+ } -+ -+ /* now, decrypt pframe with hdrlen offset and plen long */ -+ -+ payload_index = hdrlen + 8; /* 8 is for extiv */ -+ -+ for (i = 0; i < num_blocks; i++) { -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1); -+ -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); -+ -+ for (j = 0; j < 16; j++) -+ pframe[payload_index++] = chain_buffer[j]; -+ } -+ -+ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ -+ /* encrypt it and copy the unpadded part back */ -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1); -+ -+ for (j = 0; j < 16; j++) -+ padded_buffer[j] = 0x00; -+ for (j = 0; j < payload_remainder; j++) -+ padded_buffer[j] = pframe[payload_index+j]; -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, padded_buffer, chain_buffer); -+ for (j = 0; j < payload_remainder; j++) -+ pframe[payload_index++] = chain_buffer[j]; -+ } -+ -+ /* start to calculate the mic */ -+ if ((hdrlen+plen+8) <= MAX_MSG_SIZE) -+ memcpy(message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */ -+ -+ pn_vector[0] = pframe[hdrlen]; -+ pn_vector[1] = pframe[hdrlen+1]; -+ pn_vector[2] = pframe[hdrlen+4]; -+ pn_vector[3] = pframe[hdrlen+5]; -+ pn_vector[4] = pframe[hdrlen+6]; -+ pn_vector[5] = pframe[hdrlen+7]; -+ construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector); -+ -+ construct_mic_header1(mic_header1, hdrlen, message); -+ construct_mic_header2(mic_header2, message, a4_exists, qc_exists); -+ -+ payload_remainder = (plen-8) % 16; -+ num_blocks = (plen-8) / 16; -+ -+ /* Find start of payload */ -+ payload_index = (hdrlen + 8); -+ -+ /* Calculate MIC */ -+ aes128k128d(key, mic_iv, aes_out); -+ bitwise_xor(aes_out, mic_header1, chain_buffer); -+ aes128k128d(key, chain_buffer, aes_out); -+ bitwise_xor(aes_out, mic_header2, chain_buffer); -+ aes128k128d(key, chain_buffer, aes_out); -+ -+ for (i = 0; i < num_blocks; i++) { -+ bitwise_xor(aes_out, &message[payload_index], chain_buffer); -+ -+ payload_index += 16; -+ aes128k128d(key, chain_buffer, aes_out); -+ } -+ -+ /* Add on the final payload block if it needs padding */ -+ if (payload_remainder > 0) { -+ for (j = 0; j < 16; j++) -+ padded_buffer[j] = 0x00; -+ for (j = 0; j < payload_remainder; j++) -+ padded_buffer[j] = message[payload_index++]; -+ bitwise_xor(aes_out, padded_buffer, chain_buffer); -+ aes128k128d(key, chain_buffer, aes_out); -+ } -+ -+ for (j = 0 ; j < 8; j++) -+ mic[j] = aes_out[j]; -+ -+ /* Insert MIC into payload */ -+ for (j = 0; j < 8; j++) -+ message[payload_index+j] = mic[j]; -+ -+ payload_index = hdrlen + 8; -+ for (i = 0; i < num_blocks; i++) { -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1); -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, &message[payload_index], chain_buffer); -+ for (j = 0; j < 16; j++) -+ message[payload_index++] = chain_buffer[j]; -+ } -+ -+ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ -+ /* encrypt it and copy the unpadded part back */ -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, num_blocks+1); -+ -+ for (j = 0; j < 16; j++) -+ padded_buffer[j] = 0x00; -+ for (j = 0; j < payload_remainder; j++) -+ padded_buffer[j] = message[payload_index+j]; -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, padded_buffer, chain_buffer); -+ for (j = 0; j < payload_remainder; j++) -+ message[payload_index++] = chain_buffer[j]; -+ } -+ -+ /* Encrypt the MIC */ -+ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0); -+ -+ for (j = 0; j < 16; j++) -+ padded_buffer[j] = 0x00; -+ for (j = 0; j < 8; j++) -+ padded_buffer[j] = message[j+hdrlen+8+plen-8]; -+ -+ aes128k128d(key, ctr_preload, aes_out); -+ bitwise_xor(aes_out, padded_buffer, chain_buffer); -+ for (j = 0; j < 8; j++) -+ message[payload_index++] = chain_buffer[j]; -+ -+ /* compare the mic */ -+ for (i = 0; i < 8; i++) { -+ if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, -+ ("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n", -+ i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i])); -+ DBG_88E("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n", -+ i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]); -+ res = _FAIL; -+ } -+ } -+ -+ return res; -+} -+ -+u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) -+{ /* exclude ICV */ -+ /* Intermediate Buffers */ -+ int length; -+ u8 *pframe, *prwskey; /* *payload,*iv */ -+ struct sta_info *stainfo; -+ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ u32 res = _SUCCESS; -+ -+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data; -+ /* 4 start to encrypt each fragment */ -+ if ((prxattrib->encrypt == _AES_)) { -+ stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); -+ if (stainfo != NULL) { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n")); -+ -+ if (IS_MCAST(prxattrib->ra)) { -+ /* in concurrent we should use sw descrypt in group key, so we remove this message */ -+ if (!psecuritypriv->binstallGrpkey) { -+ res = _FAIL; -+ DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); -+ goto exit; -+ } -+ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; -+ if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) { -+ DBG_88E("not match packet_index=%d, install_index=%d\n", -+ prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); -+ res = _FAIL; -+ goto exit; -+ } -+ } else { -+ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; -+ } -+ length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len; -+ res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); -+ } else { -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n")); -+ res = _FAIL; -+ } -+ } -+ -+exit: -+ return res; -+} -+ -+/* AES tables*/ -+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, -+}; -+ -+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, -+}; -+ -+const u8 Td4s[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, -+}; -+const u8 rcons[] = { -+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 -+ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -+}; -+ -+/** -+ * Expand the cipher key into the encryption key schedule. -+ * -+ * @return the number of rounds for the given cipher key size. -+ */ -+#define ROUND(i, d, s) \ -+do { \ -+ d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ -+ d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ -+ d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ -+ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]; \ -+} while (0); -+ -+/** -+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) -+ * @key: 128-bit key for the hash operation -+ * @data: Data buffer for which a MAC is determined -+ * @data_len: Length of data buffer in bytes -+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is a mode for using block cipher (AES in this case) for authentication. -+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication -+ * (SP) 800-38B. -+ */ -+void rtw_use_tkipkey_handler(void *FunctionContext) -+{ -+ struct adapter *padapter = (struct adapter *)FunctionContext; -+ -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler ^^^\n")); -+ -+ padapter->securitypriv.busetkipkey = true; -+ -+ RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler padapter->securitypriv.busetkipkey=%d^^^\n", padapter->securitypriv.busetkipkey)); -+ -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_sreset.c b/drivers/net/wireless/rtl8188eu/core/rtw_sreset.c -new file mode 100644 -index 0000000000000..298f75400c8fb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_sreset.c -@@ -0,0 +1,79 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include -+ -+void sreset_init_value(struct adapter *padapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct sreset_priv *psrtpriv = &pHalData->srestpriv; -+ -+ _rtw_mutex_init(&psrtpriv->silentreset_mutex); -+ psrtpriv->silent_reset_inprogress = false; -+ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; -+ psrtpriv->last_tx_time = 0; -+ psrtpriv->last_tx_complete_time = 0; -+} -+void sreset_reset_value(struct adapter *padapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct sreset_priv *psrtpriv = &pHalData->srestpriv; -+ -+ psrtpriv->silent_reset_inprogress = false; -+ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; -+ psrtpriv->last_tx_time = 0; -+ psrtpriv->last_tx_complete_time = 0; -+} -+ -+u8 sreset_get_wifi_status(struct adapter *padapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct sreset_priv *psrtpriv = &pHalData->srestpriv; -+ -+ u8 status = WIFI_STATUS_SUCCESS; -+ u32 val32 = 0; -+ -+ if (psrtpriv->silent_reset_inprogress) -+ return status; -+ val32 = rtw_read32(padapter, REG_TXDMA_STATUS); -+ if (val32 == 0xeaeaeaea) { -+ psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST; -+ } else if (val32 != 0) { -+ DBG_88E("txdmastatu(%x)\n", val32); -+ psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR; -+ } -+ -+ if (WIFI_STATUS_SUCCESS != psrtpriv->Wifi_Error_Status) { -+ DBG_88E("==>%s error_status(0x%x)\n", __func__, psrtpriv->Wifi_Error_Status); -+ status = (psrtpriv->Wifi_Error_Status & (~(USB_READ_PORT_FAIL|USB_WRITE_PORT_FAIL))); -+ } -+ DBG_88E("==> %s wifi_status(0x%x)\n", __func__, status); -+ -+ /* status restore */ -+ psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; -+ -+ return status; -+} -+ -+void sreset_set_wifi_error_status(struct adapter *padapter, u32 status) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ pHalData->srestpriv.Wifi_Error_Status = status; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_sta_mgt.c b/drivers/net/wireless/rtl8188eu/core/rtw_sta_mgt.c -new file mode 100644 -index 0000000000000..30a1dd369112d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_sta_mgt.c -@@ -0,0 +1,609 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_STA_MGT_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static void _rtw_init_stainfo(struct sta_info *psta) -+{ -+ -+ memset((u8 *)psta, 0, sizeof (struct sta_info)); -+ -+ spin_lock_init(&psta->lock); -+ INIT_LIST_HEAD(&psta->list); -+ INIT_LIST_HEAD(&psta->hash_list); -+ _rtw_init_queue(&psta->sleep_q); -+ psta->sleepq_len = 0; -+ -+ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); -+ _rtw_init_sta_recv_priv(&psta->sta_recvpriv); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ -+ INIT_LIST_HEAD(&psta->asoc_list); -+ -+ INIT_LIST_HEAD(&psta->auth_list); -+ -+ psta->expire_to = 0; -+ -+ psta->flags = 0; -+ -+ psta->capability = 0; -+ -+ psta->bpairwise_key_installed = false; -+ -+#ifdef CONFIG_88EU_AP_MODE -+ psta->nonerp_set = 0; -+ psta->no_short_slot_time_set = 0; -+ psta->no_short_preamble_set = 0; -+ psta->no_ht_gf_set = 0; -+ psta->no_ht_set = 0; -+ psta->ht_20mhz_set = 0; -+#endif -+ -+ psta->under_exist_checking = 0; -+ -+ psta->keep_alive_trycnt = 0; -+ -+#endif /* CONFIG_88EU_AP_MODE */ -+ -+} -+ -+u32 _rtw_init_sta_priv(struct sta_priv *pstapriv) -+{ -+ struct sta_info *psta; -+ s32 i; -+ -+ pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA + 4); -+ -+ if (!pstapriv->pallocated_stainfo_buf) -+ return _FAIL; -+ -+ pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - -+ ((size_t)(pstapriv->pallocated_stainfo_buf) & 3); -+ -+ _rtw_init_queue(&pstapriv->free_sta_queue); -+ -+ spin_lock_init(&pstapriv->sta_hash_lock); -+ -+ pstapriv->asoc_sta_count = 0; -+ _rtw_init_queue(&pstapriv->sleep_q); -+ _rtw_init_queue(&pstapriv->wakeup_q); -+ -+ psta = (struct sta_info *)(pstapriv->pstainfo_buf); -+ -+ for (i = 0; i < NUM_STA; i++) { -+ _rtw_init_stainfo(psta); -+ -+ INIT_LIST_HEAD(&(pstapriv->sta_hash[i])); -+ -+ list_add_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue)); -+ -+ psta++; -+ } -+ -+#ifdef CONFIG_88EU_AP_MODE -+ -+ pstapriv->sta_dz_bitmap = 0; -+ pstapriv->tim_bitmap = 0; -+ -+ INIT_LIST_HEAD(&pstapriv->asoc_list); -+ INIT_LIST_HEAD(&pstapriv->auth_list); -+ spin_lock_init(&pstapriv->asoc_list_lock); -+ spin_lock_init(&pstapriv->auth_list_lock); -+ pstapriv->asoc_list_cnt = 0; -+ pstapriv->auth_list_cnt = 0; -+ -+ pstapriv->auth_to = 3; /* 3*2 = 6 sec */ -+ pstapriv->assoc_to = 3; -+ pstapriv->expire_to = 3; /* 3*2 = 6 sec */ -+ pstapriv->max_num_sta = NUM_STA; -+#endif -+ -+ return _SUCCESS; -+} -+ -+inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta) -+{ -+ int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info); -+ -+ if (!stainfo_offset_valid(offset)) -+ DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset); -+ -+ return offset; -+} -+ -+inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset) -+{ -+ if (!stainfo_offset_valid(offset)) -+ DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset); -+ -+ return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); -+} -+ -+void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv); -+void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv) -+{ -+ -+ _rtw_spinlock_free(&psta_xmitpriv->lock); -+ -+ _rtw_spinlock_free(&(psta_xmitpriv->be_q.sta_pending.lock)); -+ _rtw_spinlock_free(&(psta_xmitpriv->bk_q.sta_pending.lock)); -+ _rtw_spinlock_free(&(psta_xmitpriv->vi_q.sta_pending.lock)); -+ _rtw_spinlock_free(&(psta_xmitpriv->vo_q.sta_pending.lock)); -+ -+} -+ -+static void _rtw_free_sta_recv_priv_lock(struct sta_recv_priv *psta_recvpriv) -+{ -+ -+ _rtw_spinlock_free(&psta_recvpriv->lock); -+ -+ _rtw_spinlock_free(&(psta_recvpriv->defrag_q.lock)); -+ -+} -+ -+void rtw_mfree_stainfo(struct sta_info *psta); -+void rtw_mfree_stainfo(struct sta_info *psta) -+{ -+ -+ if (&psta->lock != NULL) -+ _rtw_spinlock_free(&psta->lock); -+ -+ _rtw_free_sta_xmit_priv_lock(&psta->sta_xmitpriv); -+ _rtw_free_sta_recv_priv_lock(&psta->sta_recvpriv); -+ -+} -+ -+/* this function is used to free the memory of lock || sema for all stainfos */ -+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv); -+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) -+{ -+ struct list_head *plist, *phead; -+ struct sta_info *psta = NULL; -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ -+ phead = get_list_head(&pstapriv->free_sta_queue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info , list); -+ plist = plist->next; -+ } -+ -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+} -+ -+static void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv) -+{ -+#ifdef CONFIG_88EU_AP_MODE -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+#endif -+ -+ rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ -+ -+ _rtw_spinlock_free(&pstapriv->free_sta_queue.lock); -+ -+ _rtw_spinlock_free(&pstapriv->sta_hash_lock); -+ _rtw_spinlock_free(&pstapriv->wakeup_q.lock); -+ _rtw_spinlock_free(&pstapriv->sleep_q.lock); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ _rtw_spinlock_free(&pstapriv->asoc_list_lock); -+ _rtw_spinlock_free(&pstapriv->auth_list_lock); -+ _rtw_spinlock_free(&pacl_list->acl_node_q.lock); -+#endif -+} -+ -+u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) -+{ -+ struct list_head *phead, *plist; -+ struct sta_info *psta = NULL; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ int index; -+ -+ if (pstapriv) { -+ /* delete all reordering_ctrl_timer */ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ for (index = 0; index < NUM_STA; index++) { -+ phead = &(pstapriv->sta_hash[index]); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ int i; -+ psta = container_of(plist, struct sta_info , hash_list); -+ plist = plist->next; -+ -+ for (i = 0; i < 16; i++) { -+ preorder_ctrl = &psta->recvreorder_ctrl[i]; -+ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); -+ } -+ } -+ } -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ /*===============================*/ -+ -+ rtw_mfree_sta_priv_lock(pstapriv); -+ -+ if (pstapriv->pallocated_stainfo_buf) -+ rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4); -+ } -+ -+ return _SUCCESS; -+} -+ -+struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) -+{ -+ s32 index; -+ struct list_head *phash_list; -+ struct sta_info *psta; -+ struct __queue *pfree_sta_queue; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ int i = 0; -+ u16 wRxSeqInitialValue = 0xffff; -+ -+ pfree_sta_queue = &pstapriv->free_sta_queue; -+ -+ spin_lock_bh(&pfree_sta_queue->lock); -+ -+ if (list_empty(&pfree_sta_queue->queue)) { -+ spin_unlock_bh(&pfree_sta_queue->lock); -+ psta = NULL; -+ } else { -+ psta = container_of((&pfree_sta_queue->queue)->next, struct sta_info, list); -+ list_del_init(&(psta->list)); -+ spin_unlock_bh(&pfree_sta_queue->lock); -+ _rtw_init_stainfo(psta); -+ memcpy(psta->hwaddr, hwaddr, ETH_ALEN); -+ index = wifi_mac_hash(hwaddr); -+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("rtw_alloc_stainfo: index=%x", index)); -+ if (index >= NUM_STA) { -+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => rtw_alloc_stainfo: index >= NUM_STA")); -+ psta = NULL; -+ goto exit; -+ } -+ phash_list = &(pstapriv->sta_hash[index]); -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ -+ list_add_tail(&psta->hash_list, phash_list); -+ -+ pstapriv->asoc_sta_count++ ; -+ -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+/* Commented by Albert 2009/08/13 */ -+/* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */ -+/* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */ -+/* So, we initialize the tid_rxseq variable as the 0xffff. */ -+ -+ for (i = 0; i < 16; i++) -+ memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); -+ -+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, -+ ("alloc number_%d stainfo with hwaddr = %pM\n", -+ pstapriv->asoc_sta_count , hwaddr)); -+ -+ init_addba_retry_timer(pstapriv->padapter, psta); -+ -+ /* for A-MPDU Rx reordering buffer control */ -+ for (i = 0; i < 16; i++) { -+ preorder_ctrl = &psta->recvreorder_ctrl[i]; -+ -+ preorder_ctrl->padapter = pstapriv->padapter; -+ -+ preorder_ctrl->enable = false; -+ -+ preorder_ctrl->indicate_seq = 0xffff; -+ preorder_ctrl->wend_b = 0xffff; -+ preorder_ctrl->wsize_b = 64;/* 64; */ -+ -+ _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue); -+ -+ rtw_init_recv_timer(preorder_ctrl); -+ } -+ -+ /* init for DM */ -+ psta->rssi_stat.UndecoratedSmoothedPWDB = (-1); -+ psta->rssi_stat.UndecoratedSmoothedCCK = (-1); -+ -+ /* init for the sequence number of received management frame */ -+ psta->RxMgmtFrameSeqNum = 0xffff; -+ } -+ -+exit: -+ -+ return psta; -+} -+ -+/* using pstapriv->sta_hash_lock to protect */ -+u32 rtw_free_stainfo(struct adapter *padapter , struct sta_info *psta) -+{ -+ int i; -+ struct __queue *pfree_sta_queue; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ struct sta_xmit_priv *pstaxmitpriv; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ if (psta == NULL) -+ goto exit; -+ -+ pfree_sta_queue = &pstapriv->free_sta_queue; -+ -+ pstaxmitpriv = &psta->sta_xmitpriv; -+ -+ spin_lock_bh(&pxmitpriv->lock); -+ -+ rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q); -+ psta->sleepq_len = 0; -+ -+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); -+ -+ list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); -+ -+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); -+ -+ list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); -+ -+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); -+ -+ list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); -+ -+ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); -+ -+ list_del_init(&(pstaxmitpriv->be_q.tx_pending)); -+ -+ spin_unlock_bh(&pxmitpriv->lock); -+ -+ list_del_init(&psta->hash_list); -+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("\n free number_%d stainfo with hwaddr=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", pstapriv->asoc_sta_count , psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5])); -+ pstapriv->asoc_sta_count--; -+ -+ /* re-init sta_info; 20061114 */ -+ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); -+ _rtw_init_sta_recv_priv(&psta->sta_recvpriv); -+ -+ _cancel_timer_ex(&psta->addba_retry_timer); -+ -+ /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ -+ for (i = 0; i < 16 ; i++) { -+ struct list_head *phead, *plist; -+ struct recv_frame *prframe; -+ struct __queue *ppending_recvframe_queue; -+ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; -+ -+ preorder_ctrl = &psta->recvreorder_ctrl[i]; -+ -+ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); -+ -+ ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; -+ -+ spin_lock_bh(&ppending_recvframe_queue->lock); -+ -+ phead = get_list_head(ppending_recvframe_queue); -+ plist = phead->next; -+ -+ while (!list_empty(phead)) { -+ prframe = container_of(plist, struct recv_frame, list); -+ -+ plist = plist->next; -+ -+ list_del_init(&(prframe->list)); -+ -+ rtw_free_recvframe(prframe, pfree_recv_queue); -+ } -+ -+ spin_unlock_bh(&ppending_recvframe_queue->lock); -+ } -+ -+ if (!(psta->state & WIFI_AP_STATE)) -+ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, false); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ -+ spin_lock_bh(&pstapriv->auth_list_lock); -+ if (!list_empty(&psta->auth_list)) { -+ list_del_init(&psta->auth_list); -+ pstapriv->auth_list_cnt--; -+ } -+ spin_unlock_bh(&pstapriv->auth_list_lock); -+ -+ psta->expire_to = 0; -+ -+ psta->sleepq_ac_len = 0; -+ psta->qos_info = 0; -+ -+ psta->max_sp_len = 0; -+ psta->uapsd_bk = 0; -+ psta->uapsd_be = 0; -+ psta->uapsd_vi = 0; -+ psta->uapsd_vo = 0; -+ psta->has_legacy_ac = 0; -+ -+ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); -+ pstapriv->tim_bitmap &= ~BIT(psta->aid); -+ -+ if ((psta->aid > 0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) { -+ pstapriv->sta_aid[psta->aid - 1] = NULL; -+ psta->aid = 0; -+ } -+ -+ psta->under_exist_checking = 0; -+ -+#endif /* CONFIG_88EU_AP_MODE */ -+ -+ spin_lock_bh(&pfree_sta_queue->lock); -+ list_add_tail(&psta->list, get_list_head(pfree_sta_queue)); -+ spin_unlock_bh(&pfree_sta_queue->lock); -+ -+exit: -+ -+ return _SUCCESS; -+} -+ -+/* free all stainfo which in sta_hash[all] */ -+void rtw_free_all_stainfo(struct adapter *padapter) -+{ -+ struct list_head *plist, *phead; -+ s32 index; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter); -+ -+ if (pstapriv->asoc_sta_count == 1) -+ return; -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ -+ for (index = 0; index < NUM_STA; index++) { -+ phead = &(pstapriv->sta_hash[index]); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info , hash_list); -+ -+ plist = plist->next; -+ -+ if (pbcmc_stainfo != psta) -+ rtw_free_stainfo(padapter , psta); -+ } -+ } -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+} -+ -+/* any station allocated can be searched by hash list */ -+struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) -+{ -+ struct list_head *plist, *phead; -+ struct sta_info *psta = NULL; -+ u32 index; -+ u8 *addr; -+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+ if (hwaddr == NULL) -+ return NULL; -+ -+ if (IS_MCAST(hwaddr)) -+ addr = bc_addr; -+ else -+ addr = hwaddr; -+ -+ index = wifi_mac_hash(addr); -+ -+ spin_lock_bh(&pstapriv->sta_hash_lock); -+ -+ phead = &(pstapriv->sta_hash[index]); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ psta = container_of(plist, struct sta_info, hash_list); -+ -+ if ((!memcmp(psta->hwaddr, addr, ETH_ALEN))) { -+ /* if found the matched address */ -+ break; -+ } -+ psta = NULL; -+ plist = plist->next; -+ } -+ -+ spin_unlock_bh(&pstapriv->sta_hash_lock); -+ -+ return psta; -+} -+ -+u32 rtw_init_bcmc_stainfo(struct adapter *padapter) -+{ -+ struct sta_info *psta; -+ u32 res = _SUCCESS; -+ unsigned char bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ psta = rtw_alloc_stainfo(pstapriv, bcast_addr); -+ -+ if (psta == NULL) { -+ res = _FAIL; -+ RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("rtw_alloc_stainfo fail")); -+ goto exit; -+ } -+ -+ /* default broadcast & multicast use macid 1 */ -+ psta->mac_id = 1; -+ -+exit: -+ -+ return res; -+} -+ -+struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter) -+{ -+ struct sta_info *psta; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+ psta = rtw_get_stainfo(pstapriv, bc_addr); -+ -+ return psta; -+} -+ -+u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) -+{ -+ u8 res = true; -+#ifdef CONFIG_88EU_AP_MODE -+ struct list_head *plist, *phead; -+ struct rtw_wlan_acl_node *paclnode; -+ u8 match = false; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; -+ struct __queue *pacl_node_q = &pacl_list->acl_node_q; -+ -+ spin_lock_bh(&pacl_node_q->lock); -+ phead = get_list_head(pacl_node_q); -+ plist = phead->next; -+ while (phead != plist) { -+ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); -+ plist = plist->next; -+ -+ if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) { -+ if (paclnode->valid) { -+ match = true; -+ break; -+ } -+ } -+ } -+ spin_unlock_bh(&pacl_node_q->lock); -+ -+ if (pacl_list->mode == 1)/* accept unless in deny list */ -+ res = (match) ? false : true; -+ else if (pacl_list->mode == 2)/* deny unless in accept list */ -+ res = (match) ? true : false; -+ else -+ res = true; -+ -+#endif -+ -+ return res; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_wlan_util.c b/drivers/net/wireless/rtl8188eu/core/rtw_wlan_util.c -new file mode 100644 -index 0000000000000..8869e154afba4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_wlan_util.c -@@ -0,0 +1,1690 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_WLAN_UTIL_C_ -+ -+#include -+#include -+#include -+ -+static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; -+static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; -+ -+static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18}; -+static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7}; -+ -+static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96}; -+static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43}; -+static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43}; -+static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c}; -+static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; -+static unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c}; -+ -+unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; -+ -+#define R2T_PHY_DELAY (0) -+ -+/* define WAIT_FOR_BCN_TO_M (3000) */ -+#define WAIT_FOR_BCN_TO_MIN (6000) -+#define WAIT_FOR_BCN_TO_MAX (20000) -+ -+static u8 rtw_basic_rate_cck[4] = { -+ IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK, -+ IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK -+}; -+ -+static u8 rtw_basic_rate_ofdm[3] = { -+ IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK, -+ IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK -+}; -+ -+static u8 rtw_basic_rate_mix[7] = { -+ IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK, -+ IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK, -+ IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK, -+ IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK -+}; -+ -+int cckrates_included(unsigned char *rate, int ratelen) -+{ -+ int i; -+ -+ for (i = 0; i < ratelen; i++) { -+ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || -+ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) -+ return true; -+ } -+ return false; -+} -+ -+int cckratesonly_included(unsigned char *rate, int ratelen) -+{ -+ int i; -+ -+ for (i = 0; i < ratelen; i++) { -+ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && -+ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) -+ return false; -+ } -+ -+ return true; -+} -+ -+unsigned char networktype_to_raid(unsigned char network_type) -+{ -+ unsigned char raid; -+ -+ switch (network_type) { -+ case WIRELESS_11B: -+ raid = RATR_INX_WIRELESS_B; -+ break; -+ case WIRELESS_11A: -+ case WIRELESS_11G: -+ raid = RATR_INX_WIRELESS_G; -+ break; -+ case WIRELESS_11BG: -+ raid = RATR_INX_WIRELESS_GB; -+ break; -+ case WIRELESS_11_24N: -+ case WIRELESS_11_5N: -+ raid = RATR_INX_WIRELESS_N; -+ break; -+ case WIRELESS_11A_5N: -+ case WIRELESS_11G_24N: -+ raid = RATR_INX_WIRELESS_NG; -+ break; -+ case WIRELESS_11BG_24N: -+ raid = RATR_INX_WIRELESS_NGB; -+ break; -+ default: -+ raid = RATR_INX_WIRELESS_GB; -+ break; -+ } -+ return raid; -+} -+ -+u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int ratelen) -+{ -+ u8 network_type = 0; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pmlmeext->cur_channel > 14) { -+ if (pmlmeinfo->HT_enable) -+ network_type = WIRELESS_11_5N; -+ -+ network_type |= WIRELESS_11A; -+ } else { -+ if (pmlmeinfo->HT_enable) -+ network_type = WIRELESS_11_24N; -+ -+ if ((cckratesonly_included(rate, ratelen)) == true) -+ network_type |= WIRELESS_11B; -+ else if ((cckrates_included(rate, ratelen)) == true) -+ network_type |= WIRELESS_11BG; -+ else -+ network_type |= WIRELESS_11G; -+ } -+ return network_type; -+} -+ -+static unsigned char ratetbl_val_2wifirate(unsigned char rate) -+{ -+ unsigned char val = 0; -+ -+ switch (rate & 0x7f) { -+ case 0: -+ val = IEEE80211_CCK_RATE_1MB; -+ break; -+ case 1: -+ val = IEEE80211_CCK_RATE_2MB; -+ break; -+ case 2: -+ val = IEEE80211_CCK_RATE_5MB; -+ break; -+ case 3: -+ val = IEEE80211_CCK_RATE_11MB; -+ break; -+ case 4: -+ val = IEEE80211_OFDM_RATE_6MB; -+ break; -+ case 5: -+ val = IEEE80211_OFDM_RATE_9MB; -+ break; -+ case 6: -+ val = IEEE80211_OFDM_RATE_12MB; -+ break; -+ case 7: -+ val = IEEE80211_OFDM_RATE_18MB; -+ break; -+ case 8: -+ val = IEEE80211_OFDM_RATE_24MB; -+ break; -+ case 9: -+ val = IEEE80211_OFDM_RATE_36MB; -+ break; -+ case 10: -+ val = IEEE80211_OFDM_RATE_48MB; -+ break; -+ case 11: -+ val = IEEE80211_OFDM_RATE_54MB; -+ break; -+ } -+ return val; -+} -+ -+static int is_basicrate(struct adapter *padapter, unsigned char rate) -+{ -+ int i; -+ unsigned char val; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ -+ for (i = 0; i < NumRates; i++) { -+ val = pmlmeext->basicrate[i]; -+ -+ if ((val != 0xff) && (val != 0xfe)) { -+ if (rate == ratetbl_val_2wifirate(val)) -+ return true; -+ } -+ } -+ return false; -+} -+ -+static unsigned int ratetbl2rateset(struct adapter *padapter, unsigned char *rateset) -+{ -+ int i; -+ unsigned char rate; -+ unsigned int len = 0; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ -+ for (i = 0; i < NumRates; i++) { -+ rate = pmlmeext->datarate[i]; -+ -+ switch (rate) { -+ case 0xff: -+ return len; -+ case 0xfe: -+ continue; -+ default: -+ rate = ratetbl_val_2wifirate(rate); -+ -+ if (is_basicrate(padapter, rate) == true) -+ rate |= IEEE80211_BASIC_RATE_MASK; -+ -+ rateset[len] = rate; -+ len++; -+ break; -+ } -+ } -+ return len; -+} -+ -+void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrate_len) -+{ -+ unsigned char supportedrates[NumRates]; -+ -+ memset(supportedrates, 0, NumRates); -+ *bssrate_len = ratetbl2rateset(padapter, supportedrates); -+ memcpy(pbssrate, supportedrates, *bssrate_len); -+} -+ -+void UpdateBrateTbl(struct adapter *Adapter, u8 *mbrate) -+{ -+ u8 i; -+ u8 rate; -+ -+ /* 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */ -+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { -+ rate = mbrate[i] & 0x7f; -+ switch (rate) { -+ case IEEE80211_CCK_RATE_1MB: -+ case IEEE80211_CCK_RATE_2MB: -+ case IEEE80211_CCK_RATE_5MB: -+ case IEEE80211_CCK_RATE_11MB: -+ case IEEE80211_OFDM_RATE_6MB: -+ case IEEE80211_OFDM_RATE_12MB: -+ case IEEE80211_OFDM_RATE_24MB: -+ mbrate[i] |= IEEE80211_BASIC_RATE_MASK; -+ break; -+ } -+ } -+} -+ -+void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen) -+{ -+ u8 i; -+ u8 rate; -+ -+ for (i = 0; i < bssratelen; i++) { -+ rate = bssrateset[i] & 0x7f; -+ switch (rate) { -+ case IEEE80211_CCK_RATE_1MB: -+ case IEEE80211_CCK_RATE_2MB: -+ case IEEE80211_CCK_RATE_5MB: -+ case IEEE80211_CCK_RATE_11MB: -+ bssrateset[i] |= IEEE80211_BASIC_RATE_MASK; -+ break; -+ } -+ } -+} -+ -+void Save_DM_Func_Flag(struct adapter *padapter) -+{ -+ u8 saveflag = true; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag)); -+} -+ -+void Restore_DM_Func_Flag(struct adapter *padapter) -+{ -+ u8 saveflag = false; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag)); -+} -+ -+void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable) -+{ -+ if (enable) -+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_SET, (u8 *)(&mode)); -+ else -+ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode)); -+} -+ -+static void Set_NETYPE0_MSR(struct adapter *padapter, u8 type) -+{ -+ rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type)); -+} -+ -+void Set_MSR(struct adapter *padapter, u8 type) -+{ -+ Set_NETYPE0_MSR(padapter, type); -+} -+ -+inline u8 rtw_get_oper_ch(struct adapter *adapter) -+{ -+ return adapter->mlmeextpriv.oper_channel; -+} -+ -+inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) -+{ -+ adapter->mlmeextpriv.oper_channel = ch; -+} -+ -+inline u8 rtw_get_oper_bw(struct adapter *adapter) -+{ -+ return adapter->mlmeextpriv.oper_bwmode; -+} -+ -+inline void rtw_set_oper_bw(struct adapter *adapter, u8 bw) -+{ -+ adapter->mlmeextpriv.oper_bwmode = bw; -+} -+ -+inline u8 rtw_get_oper_choffset(struct adapter *adapter) -+{ -+ return adapter->mlmeextpriv.oper_ch_offset; -+} -+ -+inline void rtw_set_oper_choffset(struct adapter *adapter, u8 offset) -+{ -+ adapter->mlmeextpriv.oper_ch_offset = offset; -+} -+ -+void SelectChannel(struct adapter *padapter, unsigned char channel) -+{ -+ /* saved channel info */ -+ rtw_set_oper_ch(padapter, channel); -+ rtw_hal_set_chan(padapter, channel); -+} -+ -+void SetBWMode(struct adapter *padapter, unsigned short bwmode, -+ unsigned char channel_offset) -+{ -+ /* saved bw info */ -+ rtw_set_oper_bw(padapter, bwmode); -+ rtw_set_oper_choffset(padapter, channel_offset); -+ -+ rtw_hal_set_bwmode(padapter, (enum ht_channel_width)bwmode, channel_offset); -+} -+ -+void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode) -+{ -+ u8 center_ch; -+ -+ if (padapter->bNotifyChannelChange) -+ DBG_88E("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode); -+ -+ if ((bwmode == HT_CHANNEL_WIDTH_20) || -+ (channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)) { -+ /* SelectChannel(padapter, channel); */ -+ center_ch = channel; -+ } else { -+ /* switch to the proper channel */ -+ if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) { -+ /* SelectChannel(padapter, channel + 2); */ -+ center_ch = channel + 2; -+ } else { -+ /* SelectChannel(padapter, channel - 2); */ -+ center_ch = channel - 2; -+ } -+ } -+ -+ /* set Channel */ -+ /* saved channel/bw info */ -+ rtw_set_oper_ch(padapter, channel); -+ rtw_set_oper_bw(padapter, bwmode); -+ rtw_set_oper_choffset(padapter, channel_offset); -+ -+ rtw_hal_set_chan(padapter, center_ch); /* set center channel */ -+ SetBWMode(padapter, bwmode, channel_offset); -+} -+ -+int get_bsstype(unsigned short capability) -+{ -+ if (capability & BIT(0)) -+ return WIFI_FW_AP_STATE; -+ else if (capability & BIT(1)) -+ return WIFI_FW_ADHOC_STATE; -+ else -+ return 0; -+} -+ -+__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork) -+{ -+ return pnetwork->MacAddress; -+} -+ -+u16 get_beacon_interval(struct wlan_bssid_ex *bss) -+{ -+ __le16 val; -+ memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2); -+ -+ return le16_to_cpu(val); -+} -+ -+int is_client_associated_to_ap(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext; -+ struct mlme_ext_info *pmlmeinfo; -+ -+ if (!padapter) -+ return _FAIL; -+ -+ pmlmeext = &padapter->mlmeextpriv; -+ pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)) -+ return true; -+ else -+ return _FAIL; -+} -+ -+int is_client_associated_to_ibss(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) -+ return true; -+ else -+ return _FAIL; -+} -+ -+int is_IBSS_empty(struct adapter *padapter) -+{ -+ unsigned int i; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) { -+ if (pmlmeinfo->FW_sta_info[i].status == 1) -+ return _FAIL; -+ } -+ return true; -+} -+ -+unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval) -+{ -+ if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN) -+ return WAIT_FOR_BCN_TO_MIN; -+ else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX) -+ return WAIT_FOR_BCN_TO_MAX; -+ else -+ return bcn_interval << 2; -+} -+ -+void CAM_empty_entry(struct adapter *Adapter, u8 ucIndex) -+{ -+ rtw_hal_set_hwreg(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex)); -+} -+ -+void invalidate_cam_all(struct adapter *padapter) -+{ -+ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL); -+} -+ -+void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) -+{ -+ unsigned int i, val, addr; -+ int j; -+ u32 cam_val[2]; -+ -+ addr = entry << 3; -+ -+ for (j = 5; j >= 0; j--) { -+ switch (j) { -+ case 0: -+ val = (ctrl | (mac[0] << 16) | (mac[1] << 24)); -+ break; -+ case 1: -+ val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); -+ break; -+ default: -+ i = (j - 2) << 2; -+ val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24)); -+ break; -+ } -+ -+ cam_val[0] = val; -+ cam_val[1] = addr + (unsigned int)j; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); -+ } -+} -+ -+void clear_cam_entry(struct adapter *padapter, u8 entry) -+{ -+ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -+ unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -+ -+ write_cam(padapter, entry, 0, null_sta, null_key); -+} -+ -+int allocate_fw_sta_entry(struct adapter *padapter) -+{ -+ unsigned int mac_id; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) { -+ if (pmlmeinfo->FW_sta_info[mac_id].status == 0) { -+ pmlmeinfo->FW_sta_info[mac_id].status = 1; -+ pmlmeinfo->FW_sta_info[mac_id].retry = 0; -+ break; -+ } -+ } -+ -+ return mac_id; -+} -+ -+void flush_all_cam_entry(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL); -+ -+ memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info)); -+} -+ -+int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) -+{ -+ /* struct registry_priv *pregpriv = &padapter->registrypriv; */ -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pmlmepriv->qospriv.qos_option == 0) { -+ pmlmeinfo->WMM_enable = 0; -+ return _FAIL; -+ } -+ -+ pmlmeinfo->WMM_enable = 1; -+ memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element)); -+ return true; -+} -+ -+void WMMOnAssocRsp(struct adapter *padapter) -+{ -+ u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; -+ u8 acm_mask; -+ u16 TXOP; -+ u32 acParm, i; -+ u32 edca[4], inx[4]; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ -+ if (pmlmeinfo->WMM_enable == 0) { -+ padapter->mlmepriv.acm_mask = 0; -+ return; -+ } -+ -+ acm_mask = 0; -+ -+ if (pmlmeext->cur_wireless_mode == WIRELESS_11B) -+ aSifsTime = 10; -+ else -+ aSifsTime = 16; -+ -+ for (i = 0; i < 4; i++) { -+ ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03; -+ ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01; -+ -+ /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */ -+ AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime; -+ -+ ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f); -+ ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4; -+ TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit); -+ -+ acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); -+ -+ switch (ACI) { -+ case 0x0: -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); -+ acm_mask |= (ACM ? BIT(1) : 0); -+ edca[XMIT_BE_QUEUE] = acParm; -+ break; -+ case 0x1: -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); -+ edca[XMIT_BK_QUEUE] = acParm; -+ break; -+ case 0x2: -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); -+ acm_mask |= (ACM ? BIT(2) : 0); -+ edca[XMIT_VI_QUEUE] = acParm; -+ break; -+ case 0x3: -+ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); -+ acm_mask |= (ACM ? BIT(3) : 0); -+ edca[XMIT_VO_QUEUE] = acParm; -+ break; -+ } -+ -+ DBG_88E("WMM(%x): %x, %x\n", ACI, ACM, acParm); -+ } -+ -+ if (padapter->registrypriv.acm_method == 1) -+ rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); -+ else -+ padapter->mlmepriv.acm_mask = acm_mask; -+ -+ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; -+ -+ if (pregpriv->wifi_spec == 1) { -+ u32 j, tmp, change_inx = false; -+ -+ /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ -+ for (i = 0; i < 4; i++) { -+ for (j = i+1; j < 4; j++) { -+ /* compare CW and AIFS */ -+ if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) { -+ change_inx = true; -+ } else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) { -+ /* compare TXOP */ -+ if ((edca[j] >> 16) > (edca[i] >> 16)) -+ change_inx = true; -+ } -+ -+ if (change_inx) { -+ tmp = edca[i]; -+ edca[i] = edca[j]; -+ edca[j] = tmp; -+ -+ tmp = inx[i]; -+ inx[i] = inx[j]; -+ inx[j] = tmp; -+ -+ change_inx = false; -+ } -+ } -+ } -+ } -+ -+ for (i = 0; i < 4; i++) { -+ pxmitpriv->wmm_para_seq[i] = inx[i]; -+ DBG_88E("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); -+ } -+ -+ return; -+} -+ -+static void bwmode_update_check(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) -+{ -+ unsigned char new_bwmode; -+ unsigned char new_ch_offset; -+ struct HT_info_element *pHT_info; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ -+ if (!pIE) -+ return; -+ -+ if (!phtpriv) -+ return; -+ -+ if (pIE->Length > sizeof(struct HT_info_element)) -+ return; -+ -+ pHT_info = (struct HT_info_element *)pIE->data; -+ -+ if ((pHT_info->infos[0] & BIT(2)) && pregistrypriv->cbw40_enable) { -+ new_bwmode = HT_CHANNEL_WIDTH_40; -+ -+ switch (pHT_info->infos[0] & 0x3) { -+ case 1: -+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; -+ break; -+ case 3: -+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; -+ break; -+ default: -+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ break; -+ } -+ } else { -+ new_bwmode = HT_CHANNEL_WIDTH_20; -+ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ } -+ -+ if ((new_bwmode != pmlmeext->cur_bwmode) || -+ (new_ch_offset != pmlmeext->cur_ch_offset)) { -+ pmlmeinfo->bwmode_updated = true; -+ -+ pmlmeext->cur_bwmode = new_bwmode; -+ pmlmeext->cur_ch_offset = new_ch_offset; -+ -+ /* update HT info also */ -+ HT_info_handler(padapter, pIE); -+ } else { -+ pmlmeinfo->bwmode_updated = false; -+ } -+ -+ if (pmlmeinfo->bwmode_updated) { -+ struct sta_info *psta; -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ -+ -+ /* update ap's stainfo */ -+ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); -+ if (psta) { -+ struct ht_priv *phtpriv_sta = &psta->htpriv; -+ -+ if (phtpriv_sta->ht_option) { -+ /* bwmode */ -+ phtpriv_sta->bwmode = pmlmeext->cur_bwmode; -+ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; -+ } else { -+ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; -+ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; -+ } -+ } -+ } -+} -+ -+void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) -+{ -+ unsigned int i; -+ u8 rf_type; -+ u8 max_AMPDU_len, min_MPDU_spacing; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ -+ if (pIE == NULL) -+ return; -+ -+ if (!phtpriv->ht_option) -+ return; -+ -+ pmlmeinfo->HT_caps_enable = 1; -+ -+ for (i = 0; i < (pIE->Length); i++) { -+ if (i != 2) { -+ /* Got the endian issue here. */ -+ pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); -+ } else { -+ /* modify from fw by Thomas 2010/11/17 */ -+ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3)) -+ max_AMPDU_len = (pIE->data[i] & 0x3); -+ else -+ max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3); -+ -+ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c)) -+ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c); -+ else -+ min_MPDU_spacing = (pIE->data[i] & 0x1c); -+ -+ pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing; -+ } -+ } -+ -+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); -+ -+ /* update the MCS rates */ -+ for (i = 0; i < 16; i++) { -+ if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) -+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; -+ else -+ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; -+ } -+ return; -+} -+ -+void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct ht_priv *phtpriv = &pmlmepriv->htpriv; -+ -+ if (pIE == NULL) -+ return; -+ -+ if (!phtpriv->ht_option) -+ return; -+ -+ if (pIE->Length > sizeof(struct HT_info_element)) -+ return; -+ -+ pmlmeinfo->HT_info_enable = 1; -+ memcpy(&(pmlmeinfo->HT_info), pIE->data, pIE->Length); -+ return; -+} -+ -+void HTOnAssocRsp(struct adapter *padapter) -+{ -+ unsigned char max_AMPDU_len; -+ unsigned char min_MPDU_spacing; -+ /* struct registry_priv *pregpriv = &padapter->registrypriv; */ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ DBG_88E("%s\n", __func__); -+ -+ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) { -+ pmlmeinfo->HT_enable = 1; -+ } else { -+ pmlmeinfo->HT_enable = 0; -+ return; -+ } -+ -+ /* handle A-MPDU parameter field */ -+ /* -+ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k -+ AMPDU_para [4:2]:Min MPDU Start Spacing -+ */ -+ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; -+ -+ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); -+} -+ -+void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pIE->Length > 1) -+ return; -+ -+ pmlmeinfo->ERP_enable = 1; -+ memcpy(&(pmlmeinfo->ERP_IE), pIE->data, pIE->Length); -+} -+ -+void VCS_update(struct adapter *padapter, struct sta_info *psta) -+{ -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */ -+ case 0: /* off */ -+ psta->rtsen = 0; -+ psta->cts2self = 0; -+ break; -+ case 1: /* on */ -+ if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */ -+ psta->rtsen = 1; -+ psta->cts2self = 0; -+ } else { -+ psta->rtsen = 0; -+ psta->cts2self = 1; -+ } -+ break; -+ case 2: /* auto */ -+ default: -+ if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) { -+ if (pregpriv->vcs_type == 1) { -+ psta->rtsen = 1; -+ psta->cts2self = 0; -+ } else { -+ psta->rtsen = 0; -+ psta->cts2self = 1; -+ } -+ } else { -+ psta->rtsen = 0; -+ psta->cts2self = 0; -+ } -+ break; -+ } -+} -+ -+int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) -+{ -+ unsigned int len; -+ unsigned char *p; -+ unsigned short val16, subtype; -+ struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network); -+ /* u8 wpa_ie[255], rsn_ie[255]; */ -+ u16 wpa_len = 0, rsn_len = 0; -+ u8 encryp_protocol = 0; -+ struct wlan_bssid_ex *bssid; -+ int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0; -+ unsigned char *pbuf; -+ u32 wpa_ielen = 0; -+ u8 *pbssid = GetAddr3Ptr(pframe); -+ u32 hidden_ssid = 0; -+ struct HT_info_element *pht_info = NULL; -+ struct ieee80211_ht_cap *pht_cap = NULL; -+ u32 bcn_channel; -+ unsigned short ht_cap_info; -+ unsigned char ht_info_infos_0; -+ -+ if (is_client_associated_to_ap(Adapter) == false) -+ return true; -+ -+ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ if (len > MAX_IE_SZ) { -+ DBG_88E("%s IE too long for survey event\n", __func__); -+ return _FAIL; -+ } -+ -+ if (memcmp(cur_network->network.MacAddress, pbssid, 6)) { -+ DBG_88E("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n%pM %pM\n", -+ (pbssid), (cur_network->network.MacAddress)); -+ return true; -+ } -+ -+ bssid = (struct wlan_bssid_ex *)rtw_zmalloc(sizeof(struct wlan_bssid_ex)); -+ if (!bssid) -+ return _FAIL; -+ -+ subtype = GetFrameSubType(pframe) >> 4; -+ -+ if (subtype == WIFI_BEACON) -+ bssid->Reserved[0] = 1; -+ -+ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; -+ -+ /* below is to copy the information element */ -+ bssid->IELength = len; -+ memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); -+ -+ /* check bw and channel offset */ -+ /* parsing HT_CAP_IE */ -+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); -+ if (p && len > 0) { -+ pht_cap = (struct ieee80211_ht_cap *)(p + 2); -+ ht_cap_info = le16_to_cpu(pht_cap->cap_info); -+ } else { -+ ht_cap_info = 0; -+ } -+ /* parsing HT_INFO_IE */ -+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); -+ if (p && len > 0) { -+ pht_info = (struct HT_info_element *)(p + 2); -+ ht_info_infos_0 = pht_info->infos[0]; -+ } else { -+ ht_info_infos_0 = 0; -+ } -+ if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || -+ ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) { -+ DBG_88E("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, -+ ht_cap_info, ht_info_infos_0); -+ DBG_88E("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, -+ cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); -+ DBG_88E("%s bw mode change, disconnect\n", __func__); -+ /* bcn_info_update */ -+ cur_network->BcnInfo.ht_cap_info = ht_cap_info; -+ cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; -+ /* to do : need to check that whether modify related register of BB or not */ -+ /* goto _mismatch; */ -+ } -+ -+ /* Checking for channel */ -+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); -+ if (p) { -+ bcn_channel = *(p + 2); -+ } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ -+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); -+ if (pht_info) { -+ bcn_channel = pht_info->primary_channel; -+ } else { /* we don't find channel IE, so don't check it */ -+ DBG_88E("Oops: %s we don't find channel IE, so don't check it\n", __func__); -+ bcn_channel = Adapter->mlmeextpriv.cur_channel; -+ } -+ } -+ if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { -+ DBG_88E("%s beacon channel:%d cur channel:%d disconnect\n", __func__, -+ bcn_channel, Adapter->mlmeextpriv.cur_channel); -+ goto _mismatch; -+ } -+ -+ /* checking SSID */ -+ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); -+ if (p == NULL) { -+ DBG_88E("%s marc: cannot find SSID for survey event\n", __func__); -+ hidden_ssid = true; -+ } else { -+ hidden_ssid = false; -+ } -+ -+ if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) { -+ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); -+ bssid->Ssid.SsidLength = *(p + 1); -+ } else { -+ bssid->Ssid.SsidLength = 0; -+ bssid->Ssid.Ssid[0] = '\0'; -+ } -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " -+ "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid, -+ bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid, -+ cur_network->network.Ssid.SsidLength)); -+ -+ if (memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) || -+ bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) { -+ if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */ -+ DBG_88E("%s(), SSID is not match return FAIL\n", __func__); -+ goto _mismatch; -+ } -+ } -+ -+ /* check encryption info */ -+ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); -+ -+ if (val16 & BIT(4)) -+ bssid->Privacy = 1; -+ else -+ bssid->Privacy = 0; -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n", -+ __func__, cur_network->network.Privacy, bssid->Privacy)); -+ if (cur_network->network.Privacy != bssid->Privacy) { -+ DBG_88E("%s(), privacy is not match return FAIL\n", __func__); -+ goto _mismatch; -+ } -+ -+ rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL, &rsn_len, NULL, &wpa_len); -+ -+ if (rsn_len > 0) { -+ encryp_protocol = ENCRYP_PROTOCOL_WPA2; -+ } else if (wpa_len > 0) { -+ encryp_protocol = ENCRYP_PROTOCOL_WPA; -+ } else { -+ if (bssid->Privacy) -+ encryp_protocol = ENCRYP_PROTOCOL_WEP; -+ } -+ -+ if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { -+ DBG_88E("%s(): enctyp is not match , return FAIL\n", __func__); -+ goto _mismatch; -+ } -+ -+ if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { -+ pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); -+ if (pbuf && (wpa_ielen > 0)) { -+ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__, -+ pairwise_cipher, group_cipher, is_8021x)); -+ } -+ } else { -+ pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12); -+ -+ if (pbuf && (wpa_ielen > 0)) { -+ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) { -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, -+ ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n", -+ __func__, pairwise_cipher, group_cipher, is_8021x)); -+ } -+ } -+ } -+ -+ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, -+ ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher)); -+ if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { -+ DBG_88E("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__, -+ pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, -+ group_cipher, cur_network->BcnInfo.group_cipher); -+ goto _mismatch; -+ } -+ -+ if (is_8021x != cur_network->BcnInfo.is_8021x) { -+ DBG_88E("%s authentication is not match , return FAIL\n", __func__); -+ goto _mismatch; -+ } -+ } -+ -+ kfree(bssid); -+ -+ return _SUCCESS; -+ -+_mismatch: -+ kfree(bssid); -+ -+ return _FAIL; -+} -+ -+void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta) -+{ -+ unsigned int i; -+ unsigned int len; -+ struct ndis_802_11_var_ie *pIE; -+ -+ len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN); -+ -+ for (i = 0; i < len;) { -+ pIE = (struct ndis_802_11_var_ie *)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i); -+ -+ switch (pIE->ElementID) { -+ case _HT_EXTRA_INFO_IE_: /* HT info */ -+ /* HT_info_handler(padapter, pIE); */ -+ bwmode_update_check(padapter, pIE); -+ break; -+ case _ERPINFO_IE_: -+ ERP_IE_handler(padapter, pIE); -+ VCS_update(padapter, psta); -+ break; -+ default: -+ break; -+ } -+ -+ i += (pIE->Length + 2); -+ } -+} -+ -+unsigned int is_ap_in_tkip(struct adapter *padapter) -+{ -+ u32 i; -+ struct ndis_802_11_var_ie *pIE; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ -+ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { -+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { -+ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); -+ -+ switch (pIE->ElementID) { -+ case _VENDOR_SPECIFIC_IE_: -+ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4))) -+ return true; -+ break; -+ case _RSN_IE_2_: -+ if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4)) -+ return true; -+ default: -+ break; -+ } -+ -+ i += (pIE->Length + 2); -+ } -+ return false; -+ } else { -+ return false; -+ } -+} -+ -+unsigned int should_forbid_n_rate(struct adapter *padapter) -+{ -+ u32 i; -+ struct ndis_802_11_var_ie *pIE; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct wlan_bssid_ex *cur_network = &pmlmepriv->cur_network.network; -+ -+ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { -+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < cur_network->IELength;) { -+ pIE = (struct ndis_802_11_var_ie *)(cur_network->IEs + i); -+ -+ switch (pIE->ElementID) { -+ case _VENDOR_SPECIFIC_IE_: -+ if (!memcmp(pIE->data, RTW_WPA_OUI, 4) && -+ ((!memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) || -+ (!memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4)))) -+ return false; -+ break; -+ case _RSN_IE_2_: -+ if ((!memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) || -+ (!memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4))) -+ return false; -+ default: -+ break; -+ } -+ -+ i += (pIE->Length + 2); -+ } -+ -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+unsigned int is_ap_in_wep(struct adapter *padapter) -+{ -+ u32 i; -+ struct ndis_802_11_var_ie *pIE; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ -+ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { -+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { -+ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); -+ -+ switch (pIE->ElementID) { -+ case _VENDOR_SPECIFIC_IE_: -+ if (!memcmp(pIE->data, RTW_WPA_OUI, 4)) -+ return false; -+ break; -+ case _RSN_IE_2_: -+ return false; -+ default: -+ break; -+ } -+ i += (pIE->Length + 2); -+ } -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+int wifirate2_ratetbl_inx(unsigned char rate) -+{ -+ int inx = 0; -+ rate = rate & 0x7f; -+ -+ switch (rate) { -+ case 54*2: -+ inx = 11; -+ break; -+ case 48*2: -+ inx = 10; -+ break; -+ case 36*2: -+ inx = 9; -+ break; -+ case 24*2: -+ inx = 8; -+ break; -+ case 18*2: -+ inx = 7; -+ break; -+ case 12*2: -+ inx = 6; -+ break; -+ case 9*2: -+ inx = 5; -+ break; -+ case 6*2: -+ inx = 4; -+ break; -+ case 11*2: -+ inx = 3; -+ break; -+ case 11: -+ inx = 2; -+ break; -+ case 2*2: -+ inx = 1; -+ break; -+ case 1*2: -+ inx = 0; -+ break; -+ } -+ return inx; -+} -+ -+unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz) -+{ -+ unsigned int i, num_of_rate; -+ unsigned int mask = 0; -+ -+ num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; -+ -+ for (i = 0; i < num_of_rate; i++) { -+ if ((*(ptn + i)) & 0x80) -+ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); -+ } -+ return mask; -+} -+ -+unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz) -+{ -+ unsigned int i, num_of_rate; -+ unsigned int mask = 0; -+ -+ num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; -+ -+ for (i = 0; i < num_of_rate; i++) -+ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); -+ return mask; -+} -+ -+unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps) -+{ -+ unsigned int mask = 0; -+ -+ mask = ((pHT_caps->u.HT_cap_element.MCS_rate[0] << 12) | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 20)); -+ -+ return mask; -+} -+ -+int support_short_GI(struct adapter *padapter, struct HT_caps_element *pHT_caps) -+{ -+ unsigned char bit_offset; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (!(pmlmeinfo->HT_enable)) -+ return _FAIL; -+ -+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK)) -+ return _FAIL; -+ -+ bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40) ? 6 : 5; -+ -+ if (__le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & (0x1 << bit_offset)) -+ return _SUCCESS; -+ else -+ return _FAIL; -+} -+ -+unsigned char get_highest_rate_idx(u32 mask) -+{ -+ int i; -+ unsigned char rate_idx = 0; -+ -+ for (i = 27; i >= 0; i--) { -+ if (mask & BIT(i)) { -+ rate_idx = i; -+ break; -+ } -+ } -+ return rate_idx; -+} -+ -+void Update_RA_Entry(struct adapter *padapter, u32 mac_id) -+{ -+ rtw_hal_update_ra_mask(padapter, mac_id, 0); -+} -+ -+static void enable_rate_adaptive(struct adapter *padapter, u32 mac_id) -+{ -+ Update_RA_Entry(padapter, mac_id); -+} -+ -+void set_sta_rate(struct adapter *padapter, struct sta_info *psta) -+{ -+ /* rate adaptive */ -+ enable_rate_adaptive(padapter, psta->mac_id); -+} -+ -+/* Update RRSR and Rate for USERATE */ -+void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode) -+{ -+ unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX]; -+#ifdef CONFIG_88EU_P2P -+ struct wifidirect_info *pwdinfo = &padapter->wdinfo; -+ -+ /* Added by Albert 2011/03/22 */ -+ /* In the P2P mode, the driver should not support the b mode. */ -+ /* So, the Tx packet shouldn't use the CCK rate */ -+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) -+ return; -+#endif /* CONFIG_88EU_P2P */ -+ memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); -+ -+ if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) -+ memcpy(supported_rates, rtw_basic_rate_cck, 4); -+ else if (wirelessmode & WIRELESS_11B) -+ memcpy(supported_rates, rtw_basic_rate_mix, 7); -+ else -+ memcpy(supported_rates, rtw_basic_rate_ofdm, 3); -+ -+ if (wirelessmode & WIRELESS_11B) -+ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); -+ else -+ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); -+ -+ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, supported_rates); -+} -+ -+unsigned char check_assoc_AP(u8 *pframe, uint len) -+{ -+ unsigned int i; -+ struct ndis_802_11_var_ie *pIE; -+ u8 epigram_vendor_flag; -+ u8 ralink_vendor_flag; -+ epigram_vendor_flag = 0; -+ ralink_vendor_flag = 0; -+ -+ for (i = sizeof(struct ndis_802_11_fixed_ie); i < len;) { -+ pIE = (struct ndis_802_11_var_ie *)(pframe + i); -+ -+ switch (pIE->ElementID) { -+ case _VENDOR_SPECIFIC_IE_: -+ if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || -+ (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) { -+ DBG_88E("link to Artheros AP\n"); -+ return HT_IOT_PEER_ATHEROS; -+ } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) || -+ (!memcmp(pIE->data, BROADCOM_OUI2, 3)) || -+ (!memcmp(pIE->data, BROADCOM_OUI2, 3))) { -+ DBG_88E("link to Broadcom AP\n"); -+ return HT_IOT_PEER_BROADCOM; -+ } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) { -+ DBG_88E("link to Marvell AP\n"); -+ return HT_IOT_PEER_MARVELL; -+ } else if (!memcmp(pIE->data, RALINK_OUI, 3)) { -+ if (!ralink_vendor_flag) { -+ ralink_vendor_flag = 1; -+ } else { -+ DBG_88E("link to Ralink AP\n"); -+ return HT_IOT_PEER_RALINK; -+ } -+ } else if (!memcmp(pIE->data, CISCO_OUI, 3)) { -+ DBG_88E("link to Cisco AP\n"); -+ return HT_IOT_PEER_CISCO; -+ } else if (!memcmp(pIE->data, REALTEK_OUI, 3)) { -+ DBG_88E("link to Realtek 96B\n"); -+ return HT_IOT_PEER_REALTEK; -+ } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) { -+ DBG_88E("link to Airgo Cap\n"); -+ return HT_IOT_PEER_AIRGO; -+ } else if (!memcmp(pIE->data, EPIGRAM_OUI, 3)) { -+ epigram_vendor_flag = 1; -+ if (ralink_vendor_flag) { -+ DBG_88E("link to Tenda W311R AP\n"); -+ return HT_IOT_PEER_TENDA; -+ } else { -+ DBG_88E("Capture EPIGRAM_OUI\n"); -+ } -+ } else { -+ break; -+ } -+ -+ default: -+ break; -+ } -+ i += (pIE->Length + 2); -+ } -+ -+ if (ralink_vendor_flag && !epigram_vendor_flag) { -+ DBG_88E("link to Ralink AP\n"); -+ return HT_IOT_PEER_RALINK; -+ } else if (ralink_vendor_flag && epigram_vendor_flag) { -+ DBG_88E("link to Tenda W311R AP\n"); -+ return HT_IOT_PEER_TENDA; -+ } else { -+ DBG_88E("link to new AP\n"); -+ return HT_IOT_PEER_UNKNOWN; -+ } -+} -+ -+void update_IOT_info(struct adapter *padapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ switch (pmlmeinfo->assoc_AP_vendor) { -+ case HT_IOT_PEER_MARVELL: -+ pmlmeinfo->turboMode_cts2self = 1; -+ pmlmeinfo->turboMode_rtsen = 0; -+ break; -+ case HT_IOT_PEER_RALINK: -+ pmlmeinfo->turboMode_cts2self = 0; -+ pmlmeinfo->turboMode_rtsen = 1; -+ /* disable high power */ -+ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false); -+ break; -+ case HT_IOT_PEER_REALTEK: -+ /* rtw_write16(padapter, 0x4cc, 0xffff); */ -+ /* rtw_write16(padapter, 0x546, 0x01c0); */ -+ /* disable high power */ -+ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false); -+ break; -+ default: -+ pmlmeinfo->turboMode_cts2self = 0; -+ pmlmeinfo->turboMode_rtsen = 1; -+ break; -+ } -+} -+ -+void update_capinfo(struct adapter *Adapter, u16 updateCap) -+{ -+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ bool ShortPreamble; -+ -+ /* Check preamble mode, 2005.01.06, by rcnjko. */ -+ /* Mark to update preamble value forever, 2008.03.18 by lanhsin */ -+ -+ if (updateCap & cShortPreamble) { /* Short Preamble */ -+ if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { /* PREAMBLE_LONG or PREAMBLE_AUTO */ -+ ShortPreamble = true; -+ pmlmeinfo->preamble_mode = PREAMBLE_SHORT; -+ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); -+ } -+ } else { /* Long Preamble */ -+ if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { /* PREAMBLE_SHORT or PREAMBLE_AUTO */ -+ ShortPreamble = false; -+ pmlmeinfo->preamble_mode = PREAMBLE_LONG; -+ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); -+ } -+ } -+ -+ if (updateCap & cIBSS) { -+ /* Filen: See 802.11-2007 p.91 */ -+ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; -+ } else { /* Filen: See 802.11-2007 p.90 */ -+ if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11_24N)) { -+ if (updateCap & cShortSlotTime) { /* Short Slot Time */ -+ if (pmlmeinfo->slotTime != SHORT_SLOT_TIME) -+ pmlmeinfo->slotTime = SHORT_SLOT_TIME; -+ } else { /* Long Slot Time */ -+ if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME) -+ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; -+ } -+ } else if (pmlmeext->cur_wireless_mode & (WIRELESS_11A | WIRELESS_11_5N)) { -+ pmlmeinfo->slotTime = SHORT_SLOT_TIME; -+ } else { -+ /* B Mode */ -+ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; -+ } -+ } -+ -+ rtw_hal_set_hwreg(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); -+} -+ -+void update_wireless_mode(struct adapter *padapter) -+{ -+ int ratelen, network_type = 0; -+ u32 SIFS_Timer; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ unsigned char *rate = cur_network->SupportedRates; -+ -+ ratelen = rtw_get_rateset_len(cur_network->SupportedRates); -+ -+ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) -+ pmlmeinfo->HT_enable = 1; -+ -+ if (pmlmeext->cur_channel > 14) { -+ if (pmlmeinfo->HT_enable) -+ network_type = WIRELESS_11_5N; -+ -+ network_type |= WIRELESS_11A; -+ } else { -+ if (pmlmeinfo->HT_enable) -+ network_type = WIRELESS_11_24N; -+ -+ if ((cckratesonly_included(rate, ratelen)) == true) -+ network_type |= WIRELESS_11B; -+ else if ((cckrates_included(rate, ratelen)) == true) -+ network_type |= WIRELESS_11BG; -+ else -+ network_type |= WIRELESS_11G; -+ } -+ -+ pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode; -+ -+ SIFS_Timer = 0x0a0a0808;/* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ -+ /* change this value if having IOT issues. */ -+ -+ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); -+ -+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) -+ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); -+ else -+ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); -+} -+ -+void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id) -+{ -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { -+ /* Only B, B/G, and B/G/N AP could use CCK rate */ -+ memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4); -+ } else { -+ memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 3); -+ } -+} -+ -+int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx) -+{ -+ unsigned int ie_len; -+ struct ndis_802_11_var_ie *pIE; -+ int supportRateNum = 0; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); -+ if (pIE == NULL) -+ return _FAIL; -+ -+ memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len); -+ supportRateNum = ie_len; -+ -+ pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len); -+ if (pIE) -+ memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len); -+ -+ return _SUCCESS; -+} -+ -+void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr) -+{ -+ struct sta_info *psta; -+ u16 tid; -+ u16 param; -+ struct recv_reorder_ctrl *preorder_ctrl; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct ADDBA_request *preq = (struct ADDBA_request *)paddba_req; -+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ psta = rtw_get_stainfo(pstapriv, addr); -+ -+ if (psta) { -+ param = le16_to_cpu(preq->BA_para_set); -+ tid = (param>>2)&0x0f; -+ preorder_ctrl = &psta->recvreorder_ctrl[tid]; -+ preorder_ctrl->indicate_seq = 0xffff; -+ preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq) ? true : false; -+ } -+} -+ -+void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) -+{ -+ u8 *pIE; -+ __le32 *pbuf; -+ -+ pIE = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); -+ pbuf = (__le32 *)pIE; -+ -+ pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1)); -+ -+ pmlmeext->TSFValue = pmlmeext->TSFValue << 32; -+ -+ pmlmeext->TSFValue |= le32_to_cpu(*pbuf); -+} -+ -+void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext) -+{ -+ rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, NULL); -+} -+ -+void beacon_timing_control(struct adapter *padapter) -+{ -+ rtw_hal_bcn_related_reg_setting(padapter); -+} -+ -+static struct adapter *pbuddy_padapter; -+ -+int rtw_handle_dualmac(struct adapter *adapter, bool init) -+{ -+ int status = _SUCCESS; -+ -+ if (init) { -+ if (pbuddy_padapter == NULL) { -+ pbuddy_padapter = adapter; -+ DBG_88E("%s(): pbuddy_padapter == NULL, Set pbuddy_padapter\n", __func__); -+ } else { -+ adapter->pbuddy_adapter = pbuddy_padapter; -+ pbuddy_padapter->pbuddy_adapter = adapter; -+ /* clear global value */ -+ pbuddy_padapter = NULL; -+ DBG_88E("%s(): pbuddy_padapter exist, Exchange Information\n", __func__); -+ } -+ } else { -+ pbuddy_padapter = NULL; -+ } -+ return status; -+} -diff --git a/drivers/net/wireless/rtl8188eu/core/rtw_xmit.c b/drivers/net/wireless/rtl8188eu/core/rtw_xmit.c -new file mode 100644 -index 0000000000000..c5bc79135127a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/core/rtw_xmit.c -@@ -0,0 +1,2370 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTW_XMIT_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; -+static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; -+ -+static void _init_txservq(struct tx_servq *ptxservq) -+{ -+ -+ INIT_LIST_HEAD(&ptxservq->tx_pending); -+ _rtw_init_queue(&ptxservq->sta_pending); -+ ptxservq->qcnt = 0; -+ -+} -+ -+void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) -+{ -+ -+ memset((unsigned char *)psta_xmitpriv, 0, sizeof (struct sta_xmit_priv)); -+ spin_lock_init(&psta_xmitpriv->lock); -+ _init_txservq(&psta_xmitpriv->be_q); -+ _init_txservq(&psta_xmitpriv->bk_q); -+ _init_txservq(&psta_xmitpriv->vi_q); -+ _init_txservq(&psta_xmitpriv->vo_q); -+ INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); -+ INIT_LIST_HEAD(&psta_xmitpriv->apsd); -+ -+} -+ -+s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) -+{ -+ int i; -+ struct xmit_buf *pxmitbuf; -+ struct xmit_frame *pxframe; -+ int res = _SUCCESS; -+ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; -+ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; -+ -+ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */ -+ -+ spin_lock_init(&pxmitpriv->lock); -+ sema_init(&pxmitpriv->xmit_sema, 0); -+ sema_init(&pxmitpriv->terminate_xmitthread_sema, 0); -+ -+ /* -+ Please insert all the queue initializaiton using _rtw_init_queue below -+ */ -+ -+ pxmitpriv->adapter = padapter; -+ -+ _rtw_init_queue(&pxmitpriv->be_pending); -+ _rtw_init_queue(&pxmitpriv->bk_pending); -+ _rtw_init_queue(&pxmitpriv->vi_pending); -+ _rtw_init_queue(&pxmitpriv->vo_pending); -+ _rtw_init_queue(&pxmitpriv->bm_pending); -+ -+ _rtw_init_queue(&pxmitpriv->free_xmit_queue); -+ -+ /* -+ Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, -+ and initialize free_xmit_frame below. -+ Please also apply free_txobj to link_up all the xmit_frames... -+ */ -+ -+ pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); -+ -+ if (pxmitpriv->pallocated_frame_buf == NULL) { -+ pxmitpriv->pxmit_frame_buf = NULL; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n")); -+ res = _FAIL; -+ goto exit; -+ } -+ pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_frame_buf), 4); -+ /* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */ -+ /* ((size_t) (pxmitpriv->pallocated_frame_buf) &3); */ -+ -+ pxframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf; -+ -+ for (i = 0; i < NR_XMITFRAME; i++) { -+ INIT_LIST_HEAD(&(pxframe->list)); -+ -+ pxframe->padapter = padapter; -+ pxframe->frame_tag = NULL_FRAMETAG; -+ -+ pxframe->pkt = NULL; -+ -+ pxframe->buf_addr = NULL; -+ pxframe->pxmitbuf = NULL; -+ -+ list_add_tail(&(pxframe->list), &(pxmitpriv->free_xmit_queue.queue)); -+ -+ pxframe++; -+ } -+ -+ pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; -+ -+ pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; -+ -+ /* init xmit_buf */ -+ _rtw_init_queue(&pxmitpriv->free_xmitbuf_queue); -+ _rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue); -+ -+ pxmitpriv->pallocated_xmitbuf = rtw_zvmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); -+ -+ if (pxmitpriv->pallocated_xmitbuf == NULL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n")); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmitbuf), 4); -+ /* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */ -+ /* ((size_t) (pxmitpriv->pallocated_xmitbuf) &3); */ -+ -+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; -+ -+ for (i = 0; i < NR_XMITBUFF; i++) { -+ INIT_LIST_HEAD(&pxmitbuf->list); -+ -+ pxmitbuf->priv_data = NULL; -+ pxmitbuf->padapter = padapter; -+ pxmitbuf->ext_tag = false; -+ -+ /* Tx buf allocation may fail sometimes, so sleep and retry. */ -+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); -+ if (res == _FAIL) { -+ rtw_msleep_os(10); -+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); -+ if (res == _FAIL) { -+ goto exit; -+ } -+ } -+ -+ pxmitbuf->flags = XMIT_VO_QUEUE; -+ -+ list_add_tail(&pxmitbuf->list, &(pxmitpriv->free_xmitbuf_queue.queue)); -+ pxmitbuf++; -+ } -+ -+ pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; -+ -+ /* Init xmit extension buff */ -+ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); -+ -+ pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); -+ -+ if (pxmitpriv->pallocated_xmit_extbuf == NULL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n")); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4); -+ -+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; -+ -+ for (i = 0; i < num_xmit_extbuf; i++) { -+ INIT_LIST_HEAD(&pxmitbuf->list); -+ -+ pxmitbuf->priv_data = NULL; -+ pxmitbuf->padapter = padapter; -+ pxmitbuf->ext_tag = true; -+ -+ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ); -+ if (res == _FAIL) { -+ res = _FAIL; -+ goto exit; -+ } -+ -+ list_add_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); -+ pxmitbuf++; -+ } -+ -+ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; -+ -+ rtw_alloc_hwxmits(padapter); -+ rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); -+ -+ for (i = 0; i < 4; i++) -+ pxmitpriv->wmm_para_seq[i] = i; -+ -+ pxmitpriv->txirp_cnt = 1; -+ -+ sema_init(&(pxmitpriv->tx_retevt), 0); -+ -+ /* per AC pending irp */ -+ pxmitpriv->beq_cnt = 0; -+ pxmitpriv->bkq_cnt = 0; -+ pxmitpriv->viq_cnt = 0; -+ pxmitpriv->voq_cnt = 0; -+ -+ pxmitpriv->ack_tx = false; -+ _rtw_mutex_init(&pxmitpriv->ack_tx_mutex); -+ rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0); -+ -+ rtw_hal_init_xmit_priv(padapter); -+ -+exit: -+ -+ return res; -+} -+ -+static void rtw_mfree_xmit_priv_lock (struct xmit_priv *pxmitpriv) -+{ -+ _rtw_spinlock_free(&pxmitpriv->lock); -+ -+ _rtw_spinlock_free(&pxmitpriv->be_pending.lock); -+ _rtw_spinlock_free(&pxmitpriv->bk_pending.lock); -+ _rtw_spinlock_free(&pxmitpriv->vi_pending.lock); -+ _rtw_spinlock_free(&pxmitpriv->vo_pending.lock); -+ _rtw_spinlock_free(&pxmitpriv->bm_pending.lock); -+ -+ _rtw_spinlock_free(&pxmitpriv->free_xmit_queue.lock); -+ _rtw_spinlock_free(&pxmitpriv->free_xmitbuf_queue.lock); -+ _rtw_spinlock_free(&pxmitpriv->pending_xmitbuf_queue.lock); -+} -+ -+void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv) -+{ -+ int i; -+ struct adapter *padapter = pxmitpriv->adapter; -+ struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf; -+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; -+ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; -+ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; -+ -+ rtw_hal_free_xmit_priv(padapter); -+ -+ rtw_mfree_xmit_priv_lock(pxmitpriv); -+ -+ if (pxmitpriv->pxmit_frame_buf == NULL) -+ return; -+ -+ for (i = 0; i < NR_XMITFRAME; i++) { -+ rtw_os_xmit_complete(padapter, pxmitframe); -+ -+ pxmitframe++; -+ } -+ -+ for (i = 0; i < NR_XMITBUFF; i++) { -+ rtw_os_xmit_resource_free(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); -+ pxmitbuf++; -+ } -+ -+ if (pxmitpriv->pallocated_frame_buf) -+ rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4); -+ -+ if (pxmitpriv->pallocated_xmitbuf) -+ rtw_vmfree(pxmitpriv->pallocated_xmitbuf, NR_XMITBUFF * sizeof(struct xmit_buf) + 4); -+ -+ /* free xmit extension buff */ -+ _rtw_spinlock_free(&pxmitpriv->free_xmit_extbuf_queue.lock); -+ -+ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; -+ for (i = 0; i < num_xmit_extbuf; i++) { -+ rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ)); -+ pxmitbuf++; -+ } -+ -+ if (pxmitpriv->pallocated_xmit_extbuf) { -+ rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4); -+ } -+ -+ rtw_free_hwxmits(padapter); -+ -+ _rtw_mutex_free(&pxmitpriv->ack_tx_mutex); -+} -+ -+static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe) -+{ -+ u32 sz; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ struct sta_info *psta = pattrib->psta; -+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if (pattrib->nr_frags != 1) -+ sz = padapter->xmitpriv.frag_len; -+ else /* no frag */ -+ sz = pattrib->last_txcmdsz; -+ -+ /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */ -+ /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */ -+ /* Other fragments are protected by previous fragment. */ -+ /* So we only need to check the length of first fragment. */ -+ if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { -+ if (sz > padapter->registrypriv.rts_thresh) { -+ pattrib->vcs_mode = RTS_CTS; -+ } else { -+ if (psta->rtsen) -+ pattrib->vcs_mode = RTS_CTS; -+ else if (psta->cts2self) -+ pattrib->vcs_mode = CTS_TO_SELF; -+ else -+ pattrib->vcs_mode = NONE_VCS; -+ } -+ } else { -+ while (true) { -+ /* IOT action */ -+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && pattrib->ampdu_en && -+ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { -+ pattrib->vcs_mode = CTS_TO_SELF; -+ break; -+ } -+ -+ /* check ERP protection */ -+ if (psta->rtsen || psta->cts2self) { -+ if (psta->rtsen) -+ pattrib->vcs_mode = RTS_CTS; -+ else if (psta->cts2self) -+ pattrib->vcs_mode = CTS_TO_SELF; -+ -+ break; -+ } -+ -+ /* check HT op mode */ -+ if (pattrib->ht_en) { -+ u8 htopmode = pmlmeinfo->HT_protection; -+ if ((pmlmeext->cur_bwmode && (htopmode == 2 || htopmode == 3)) || -+ (!pmlmeext->cur_bwmode && htopmode == 3)) { -+ pattrib->vcs_mode = RTS_CTS; -+ break; -+ } -+ } -+ -+ /* check rts */ -+ if (sz > padapter->registrypriv.rts_thresh) { -+ pattrib->vcs_mode = RTS_CTS; -+ break; -+ } -+ -+ /* to do list: check MIMO power save condition. */ -+ -+ /* check AMPDU aggregation for TXOP */ -+ if (pattrib->ampdu_en) { -+ pattrib->vcs_mode = RTS_CTS; -+ break; -+ } -+ -+ pattrib->vcs_mode = NONE_VCS; -+ break; -+ } -+ } -+} -+ -+static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta) -+{ -+ /*if (psta->rtsen) -+ pattrib->vcs_mode = RTS_CTS; -+ else if (psta->cts2self) -+ pattrib->vcs_mode = CTS_TO_SELF; -+ else -+ pattrib->vcs_mode = NONE_VCS;*/ -+ -+ pattrib->mdata = 0; -+ pattrib->eosp = 0; -+ pattrib->triggered = 0; -+ -+ /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */ -+ pattrib->qos_en = psta->qos_option; -+ -+ pattrib->raid = psta->raid; -+ pattrib->ht_en = psta->htpriv.ht_option; -+ pattrib->bwmode = psta->htpriv.bwmode; -+ pattrib->ch_offset = psta->htpriv.ch_offset; -+ pattrib->sgi = psta->htpriv.sgi; -+ pattrib->ampdu_en = false; -+ pattrib->retry_ctrl = false; -+} -+ -+u8 qos_acm(u8 acm_mask, u8 priority) -+{ -+ u8 change_priority = priority; -+ -+ switch (priority) { -+ case 0: -+ case 3: -+ if (acm_mask & BIT(1)) -+ change_priority = 1; -+ break; -+ case 1: -+ case 2: -+ break; -+ case 4: -+ case 5: -+ if (acm_mask & BIT(2)) -+ change_priority = 0; -+ break; -+ case 6: -+ case 7: -+ if (acm_mask & BIT(3)) -+ change_priority = 5; -+ break; -+ default: -+ DBG_88E("qos_acm(): invalid pattrib->priority: %d!!!\n", priority); -+ break; -+ } -+ -+ return change_priority; -+} -+ -+static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) -+{ -+ struct ethhdr etherhdr; -+ struct iphdr ip_hdr; -+ s32 user_prio = 0; -+ -+ _rtw_open_pktfile(ppktfile->pkt, ppktfile); -+ _rtw_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); -+ -+ /* get user_prio from IP hdr */ -+ if (pattrib->ether_type == 0x0800) { -+ _rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); -+/* user_prio = (ntohs(ip_hdr.tos) >> 5) & 0x3; */ -+ user_prio = ip_hdr.tos >> 5; -+ } else if (pattrib->ether_type == 0x888e) { -+ /* "When priority processing of data frames is supported, */ -+ /* a STA's SME should send EAPOL-Key frames at the highest priority." */ -+ user_prio = 7; -+ } -+ -+ pattrib->priority = user_prio; -+ pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; -+ pattrib->subtype = WIFI_QOS_DATA_TYPE; -+} -+ -+static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib) -+{ -+ struct pkt_file pktfile; -+ struct sta_info *psta = NULL; -+ struct ethhdr etherhdr; -+ -+ int bmcast; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct qos_priv *pqospriv = &pmlmepriv->qospriv; -+ int res = _SUCCESS; -+ -+ -+ -+ _rtw_open_pktfile(pkt, &pktfile); -+ _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); -+ -+ pattrib->ether_type = ntohs(etherhdr.h_proto); -+ -+ memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); -+ memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); -+ -+ pattrib->pctrl = 0; -+ -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || -+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { -+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); -+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); -+ } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { -+ memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); -+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); -+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); -+ memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); -+ } -+ -+ pattrib->pktlen = pktfile.pkt_len; -+ -+ if (ETH_P_IP == pattrib->ether_type) { -+ /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ -+ /* to prevent DHCP protocol fail */ -+ u8 tmp[24]; -+ _rtw_pktfile_read(&pktfile, &tmp[0], 24); -+ pattrib->dhcp_pkt = 0; -+ if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ -+ if (ETH_P_IP == pattrib->ether_type) {/* IP header */ -+ if (((tmp[21] == 68) && (tmp[23] == 67)) || -+ ((tmp[21] == 67) && (tmp[23] == 68))) { -+ /* 68 : UDP BOOTP client */ -+ /* 67 : UDP BOOTP server */ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== update_attrib: get DHCP Packet\n")); -+ /* Use low rate to send DHCP packet. */ -+ pattrib->dhcp_pkt = 1; -+ } -+ } -+ } -+ } else if (0x888e == pattrib->ether_type) { -+ DBG_88E_LEVEL(_drv_info_, "send eapol packet\n"); -+ } -+ -+ if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) -+ rtw_set_scan_deny(padapter, 3000); -+ -+ /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ -+ if ((pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) -+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1); -+ -+ bmcast = IS_MCAST(pattrib->ra); -+ -+ /* get sta_info */ -+ if (bmcast) { -+ psta = rtw_get_bcmc_stainfo(padapter); -+ } else { -+ psta = rtw_get_stainfo(pstapriv, pattrib->ra); -+ if (psta == NULL) { /* if we cannot get psta => drrp the pkt */ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra: %pM\n", (pattrib->ra))); -+ res = _FAIL; -+ goto exit; -+ } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) && (!(psta->state & _FW_LINKED))) { -+ res = _FAIL; -+ goto exit; -+ } -+ } -+ -+ if (psta) { -+ pattrib->mac_id = psta->mac_id; -+ /* DBG_88E("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */ -+ pattrib->psta = psta; -+ } else { -+ /* if we cannot get psta => drop the pkt */ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", (pattrib->ra))); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ pattrib->ack_policy = 0; -+ /* get ether_hdr_len */ -+ pattrib->pkt_hdrlen = ETH_HLEN;/* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */ -+ -+ pattrib->hdrlen = WLAN_HDR_A3_LEN; -+ pattrib->subtype = WIFI_DATA_TYPE; -+ pattrib->priority = 0; -+ -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) { -+ if (psta->qos_option) -+ set_qos(&pktfile, pattrib); -+ } else { -+ if (pqospriv->qos_option) { -+ set_qos(&pktfile, pattrib); -+ -+ if (pmlmepriv->acm_mask != 0) -+ pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority); -+ } -+ } -+ -+ if (psta->ieee8021x_blocked) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\n psta->ieee8021x_blocked == true\n")); -+ -+ pattrib->encrypt = 0; -+ -+ if ((pattrib->ether_type != 0x888e) && !check_fwstate(pmlmepriv, WIFI_MP_STATE)) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, pattrib->ether_type(%.4x) != 0x888e\n", pattrib->ether_type)); -+ res = _FAIL; -+ goto exit; -+ } -+ } else { -+ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); -+ -+ switch (psecuritypriv->dot11AuthAlgrthm) { -+ case dot11AuthAlgrthm_Open: -+ case dot11AuthAlgrthm_Shared: -+ case dot11AuthAlgrthm_Auto: -+ pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; -+ break; -+ case dot11AuthAlgrthm_8021X: -+ if (bmcast) -+ pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid; -+ else -+ pattrib->key_idx = 0; -+ break; -+ default: -+ pattrib->key_idx = 0; -+ break; -+ } -+ } -+ -+ switch (pattrib->encrypt) { -+ case _WEP40_: -+ case _WEP104_: -+ pattrib->iv_len = 4; -+ pattrib->icv_len = 4; -+ break; -+ case _TKIP_: -+ pattrib->iv_len = 8; -+ pattrib->icv_len = 4; -+ -+ if (padapter->securitypriv.busetkipkey == _FAIL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, -+ ("\npadapter->securitypriv.busetkipkey(%d) == _FAIL drop packet\n", -+ padapter->securitypriv.busetkipkey)); -+ res = _FAIL; -+ goto exit; -+ } -+ break; -+ case _AES_: -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("pattrib->encrypt=%d (_AES_)\n", pattrib->encrypt)); -+ pattrib->iv_len = 8; -+ pattrib->icv_len = 8; -+ break; -+ default: -+ pattrib->iv_len = 0; -+ pattrib->icv_len = 0; -+ break; -+ } -+ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, -+ ("update_attrib: encrypt=%d securitypriv.sw_encrypt=%d\n", -+ pattrib->encrypt, padapter->securitypriv.sw_encrypt)); -+ -+ if (pattrib->encrypt && -+ (padapter->securitypriv.sw_encrypt || !psecuritypriv->hw_decrypted)) { -+ pattrib->bswenc = true; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, -+ ("update_attrib: encrypt=%d securitypriv.hw_decrypted=%d bswenc = true\n", -+ pattrib->encrypt, padapter->securitypriv.sw_encrypt)); -+ } else { -+ pattrib->bswenc = false; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("update_attrib: bswenc = false\n")); -+ } -+ -+ rtw_set_tx_chksum_offload(pkt, pattrib); -+ -+ update_attrib_phy_info(pattrib, psta); -+ -+exit: -+ -+ return res; -+} -+ -+static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe) -+{ -+ int curfragnum, length; -+ u8 *pframe, *payload, mic[8]; -+ struct mic_data micdata; -+ struct sta_info *stainfo; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ struct security_priv *psecuritypriv = &padapter->securitypriv; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; -+ u8 hw_hdr_offset = 0; -+ int bmcst = IS_MCAST(pattrib->ra); -+ -+ if (pattrib->psta) -+ stainfo = pattrib->psta; -+ else -+ stainfo = rtw_get_stainfo(&padapter->stapriv , &pattrib->ra[0]); -+ -+ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);; -+ -+ if (pattrib->encrypt == _TKIP_) {/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */ -+ /* encode mic code */ -+ if (stainfo != NULL) { -+ u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -+ 0x0, 0x0}; -+ -+ pframe = pxmitframe->buf_addr + hw_hdr_offset; -+ -+ if (bmcst) { -+ if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)) -+ return _FAIL; -+ /* start to calculate the mic code */ -+ rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); -+ } else { -+ if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16)) { -+ /* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey == 0\n"); */ -+ /* rtw_msleep_os(10); */ -+ return _FAIL; -+ } -+ /* start to calculate the mic code */ -+ rtw_secmicsetkey(&micdata, &stainfo->dot11tkiptxmickey.skey[0]); -+ } -+ -+ if (pframe[1]&1) { /* ToDS == 1 */ -+ rtw_secmicappend(&micdata, &pframe[16], 6); /* DA */ -+ if (pframe[1]&2) /* From Ds == 1 */ -+ rtw_secmicappend(&micdata, &pframe[24], 6); -+ else -+ rtw_secmicappend(&micdata, &pframe[10], 6); -+ } else { /* ToDS == 0 */ -+ rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */ -+ if (pframe[1]&2) /* From Ds == 1 */ -+ rtw_secmicappend(&micdata, &pframe[16], 6); -+ else -+ rtw_secmicappend(&micdata, &pframe[10], 6); -+ } -+ -+ if (pattrib->qos_en) -+ priority[0] = (u8)pxmitframe->attrib.priority; -+ -+ rtw_secmicappend(&micdata, &priority[0], 4); -+ -+ payload = pframe; -+ -+ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { -+ payload = (u8 *)RND4((size_t)(payload)); -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, -+ ("=== curfragnum=%d, pframe = 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n", -+ curfragnum, *payload, *(payload+1), -+ *(payload+2), *(payload+3), -+ *(payload+4), *(payload+5), -+ *(payload+6), *(payload+7))); -+ -+ payload = payload+pattrib->hdrlen+pattrib->iv_len; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, -+ ("curfragnum=%d pattrib->hdrlen=%d pattrib->iv_len=%d", -+ curfragnum, pattrib->hdrlen, pattrib->iv_len)); -+ if ((curfragnum+1) == pattrib->nr_frags) { -+ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); -+ rtw_secmicappend(&micdata, payload, length); -+ payload = payload+length; -+ } else { -+ length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0); -+ rtw_secmicappend(&micdata, payload, length); -+ payload = payload+length+pattrib->icv_len; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum=%d length=%d pattrib->icv_len=%d", curfragnum, length, pattrib->icv_len)); -+ } -+ } -+ rtw_secgetmic(&micdata, &(mic[0])); -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n")); -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz=%d!!!\n", pattrib->last_txcmdsz)); -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\ -+ mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n", -+ mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7])); -+ /* add mic code and add the mic code length in last_txcmdsz */ -+ -+ memcpy(payload, &(mic[0]), 8); -+ pattrib->last_txcmdsz += 8; -+ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ======== last pkt ========\n")); -+ payload = payload-pattrib->last_txcmdsz+8; -+ for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; curfragnum = curfragnum+8) -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, -+ (" %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x, %.2x ", -+ *(payload+curfragnum), *(payload+curfragnum+1), -+ *(payload+curfragnum+2), *(payload+curfragnum+3), -+ *(payload+curfragnum+4), *(payload+curfragnum+5), -+ *(payload+curfragnum+6), *(payload+curfragnum+7))); -+ } else { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: rtw_get_stainfo==NULL!!!\n")); -+ } -+ } -+ -+ return _SUCCESS; -+} -+ -+static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe) -+{ -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ -+ if (pattrib->bswenc) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n")); -+ switch (pattrib->encrypt) { -+ case _WEP40_: -+ case _WEP104_: -+ rtw_wep_encrypt(padapter, (u8 *)pxmitframe); -+ break; -+ case _TKIP_: -+ rtw_tkip_encrypt(padapter, (u8 *)pxmitframe); -+ break; -+ case _AES_: -+ rtw_aes_encrypt(padapter, (u8 *)pxmitframe); -+ break; -+ default: -+ break; -+ } -+ } else { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n")); -+ } -+ -+ return _SUCCESS; -+} -+ -+s32 rtw_make_wlanhdr (struct adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib) -+{ -+ u16 *qc; -+ -+ struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ struct qos_priv *pqospriv = &pmlmepriv->qospriv; -+ u8 qos_option = false; -+ -+ int res = _SUCCESS; -+ __le16 *fctrl = &pwlanhdr->frame_ctl; -+ -+ struct sta_info *psta; -+ -+ int bmcst = IS_MCAST(pattrib->ra); -+ -+ if (pattrib->psta) { -+ psta = pattrib->psta; -+ } else { -+ if (bmcst) { -+ psta = rtw_get_bcmc_stainfo(padapter); -+ } else { -+ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); -+ } -+ } -+ -+ memset(hdr, 0, WLANHDR_OFFSET); -+ -+ SetFrameSubType(fctrl, pattrib->subtype); -+ -+ if (pattrib->subtype & WIFI_DATA_TYPE) { -+ if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)) { -+ /* to_ds = 1, fr_ds = 0; */ -+ /* Data transfer to AP */ -+ SetToDs(fctrl); -+ memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); -+ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); -+ -+ if (pqospriv->qos_option) -+ qos_option = true; -+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { -+ /* to_ds = 0, fr_ds = 1; */ -+ SetFrDs(fctrl); -+ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); -+ -+ if (psta->qos_option) -+ qos_option = true; -+ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || -+ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { -+ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); -+ -+ if (psta->qos_option) -+ qos_option = true; -+ } else { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv))); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ if (pattrib->mdata) -+ SetMData(fctrl); -+ -+ if (pattrib->encrypt) -+ SetPrivacy(fctrl); -+ -+ if (qos_option) { -+ qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); -+ -+ if (pattrib->priority) -+ SetPriority(qc, pattrib->priority); -+ -+ SetEOSP(qc, pattrib->eosp); -+ -+ SetAckpolicy(qc, pattrib->ack_policy); -+ } -+ -+ /* TODO: fill HT Control Field */ -+ -+ /* Update Seq Num will be handled by f/w */ -+ if (psta) { -+ psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; -+ psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; -+ -+ pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; -+ -+ SetSeqNum(hdr, pattrib->seqnum); -+ -+ /* check if enable ampdu */ -+ if (pattrib->ht_en && psta->htpriv.ampdu_enable) { -+ if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) -+ pattrib->ampdu_en = true; -+ } -+ -+ /* re-check if enable ampdu by BA_starting_seqctrl */ -+ if (pattrib->ampdu_en) { -+ u16 tx_seq; -+ -+ tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; -+ -+ /* check BA_starting_seqctrl */ -+ if (SN_LESS(pattrib->seqnum, tx_seq)) { -+ pattrib->ampdu_en = false;/* AGG BK */ -+ } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) { -+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff; -+ -+ pattrib->ampdu_en = true;/* AGG EN */ -+ } else { -+ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff; -+ pattrib->ampdu_en = true;/* AGG EN */ -+ } -+ } -+ } -+ } -+exit: -+ -+ return res; -+} -+ -+s32 rtw_txframes_pending(struct adapter *padapter) -+{ -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+ return (!list_empty(&pxmitpriv->be_pending.queue) || -+ !list_empty(&pxmitpriv->bk_pending.queue) || -+ !list_empty(&pxmitpriv->vi_pending.queue) || -+ !list_empty(&pxmitpriv->vo_pending.queue)); -+} -+ -+s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, struct pkt_attrib *pattrib) -+{ -+ struct sta_info *psta; -+ struct tx_servq *ptxservq; -+ int priority = pattrib->priority; -+ -+ psta = pattrib->psta; -+ -+ switch (priority) { -+ case 1: -+ case 2: -+ ptxservq = &(psta->sta_xmitpriv.bk_q); -+ break; -+ case 4: -+ case 5: -+ ptxservq = &(psta->sta_xmitpriv.vi_q); -+ break; -+ case 6: -+ case 7: -+ ptxservq = &(psta->sta_xmitpriv.vo_q); -+ break; -+ case 0: -+ case 3: -+ default: -+ ptxservq = &(psta->sta_xmitpriv.be_q); -+ break; -+ } -+ -+ if (ptxservq) -+ return ptxservq->qcnt; -+ return 0; -+} -+ -+/* -+ * Calculate wlan 802.11 packet MAX size from pkt_attrib -+ * This function doesn't consider fragment case -+ */ -+u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib) -+{ -+ u32 len = 0; -+ -+ len = pattrib->hdrlen + pattrib->iv_len; /* WLAN Header and IV */ -+ len += SNAP_SIZE + sizeof(u16); /* LLC */ -+ len += pattrib->pktlen; -+ if (pattrib->encrypt == _TKIP_) -+ len += 8; /* MIC */ -+ len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /* ICV */ -+ -+ return len; -+} -+ -+/* -+ -+This sub-routine will perform all the following: -+ -+1. remove 802.3 header. -+2. create wlan_header, based on the info in pxmitframe -+3. append sta's iv/ext-iv -+4. append LLC -+5. move frag chunk from pframe to pxmitframe->mem -+6. apply sw-encrypt, if necessary. -+ -+*/ -+s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) -+{ -+ struct pkt_file pktfile; -+ s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; -+ size_t addr; -+ u8 *pframe, *mem_start; -+ u8 hw_hdr_offset; -+ struct sta_info *psta; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ u8 *pbuf_start; -+ s32 bmcst = IS_MCAST(pattrib->ra); -+ s32 res = _SUCCESS; -+ -+ if (!pkt) -+ return _FAIL; -+ -+ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); -+ -+ if (psta == NULL) -+ return _FAIL; -+ -+ if (pxmitframe->buf_addr == NULL) { -+ DBG_88E("==> %s buf_addr == NULL\n", __func__); -+ return _FAIL; -+ } -+ -+ pbuf_start = pxmitframe->buf_addr; -+ -+ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); -+ -+ mem_start = pbuf_start + hw_hdr_offset; -+ -+ if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n")); -+ DBG_88E("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ _rtw_open_pktfile(pkt, &pktfile); -+ _rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen); -+ -+ frg_inx = 0; -+ frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ -+ -+ while (1) { -+ llc_sz = 0; -+ -+ mpdu_len = frg_len; -+ -+ pframe = mem_start; -+ -+ SetMFrag(mem_start); -+ -+ pframe += pattrib->hdrlen; -+ mpdu_len -= pattrib->hdrlen; -+ -+ /* adding icv, if necessary... */ -+ if (pattrib->iv_len) { -+ if (psta != NULL) { -+ switch (pattrib->encrypt) { -+ case _WEP40_: -+ case _WEP104_: -+ WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); -+ break; -+ case _TKIP_: -+ if (bmcst) -+ TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); -+ else -+ TKIP_IV(pattrib->iv, psta->dot11txpn, 0); -+ break; -+ case _AES_: -+ if (bmcst) -+ AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); -+ else -+ AES_IV(pattrib->iv, psta->dot11txpn, 0); -+ break; -+ } -+ } -+ -+ memcpy(pframe, pattrib->iv, pattrib->iv_len); -+ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, -+ ("rtw_xmitframe_coalesce: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n", -+ padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3))); -+ -+ pframe += pattrib->iv_len; -+ -+ mpdu_len -= pattrib->iv_len; -+ } -+ -+ if (frg_inx == 0) { -+ llc_sz = rtw_put_snap(pframe, pattrib->ether_type); -+ pframe += llc_sz; -+ mpdu_len -= llc_sz; -+ } -+ -+ if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { -+ mpdu_len -= pattrib->icv_len; -+ } -+ -+ if (bmcst) { -+ /* don't do fragment to broadcat/multicast packets */ -+ mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); -+ } else { -+ mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len); -+ } -+ -+ pframe += mem_sz; -+ -+ if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { -+ memcpy(pframe, pattrib->icv, pattrib->icv_len); -+ pframe += pattrib->icv_len; -+ } -+ -+ frg_inx++; -+ -+ if (bmcst || rtw_endofpktfile(&pktfile)) { -+ pattrib->nr_frags = frg_inx; -+ -+ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) + -+ ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz; -+ -+ ClearMFrag(mem_start); -+ -+ break; -+ } else { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); -+ } -+ -+ addr = (size_t)(pframe); -+ -+ mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset; -+ memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); -+ } -+ -+ if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n")); -+ DBG_88E("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"); -+ res = _FAIL; -+ goto exit; -+ } -+ -+ xmitframe_swencrypt(padapter, pxmitframe); -+ -+ if (!bmcst) -+ update_attrib_vcs_info(padapter, pxmitframe); -+ else -+ pattrib->vcs_mode = NONE_VCS; -+ -+exit: -+ -+ return res; -+} -+ -+/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header -+ * IEEE LLC/SNAP header contains 8 octets -+ * First 3 octets comprise the LLC portion -+ * SNAP portion, 5 octets, is divided into two fields: -+ * Organizationally Unique Identifier(OUI), 3 octets, -+ * type, defined by that organization, 2 octets. -+ */ -+s32 rtw_put_snap(u8 *data, u16 h_proto) -+{ -+ struct ieee80211_snap_hdr *snap; -+ u8 *oui; -+ -+ snap = (struct ieee80211_snap_hdr *)data; -+ snap->dsap = 0xaa; -+ snap->ssap = 0xaa; -+ snap->ctrl = 0x03; -+ -+ if (h_proto == 0x8137 || h_proto == 0x80f3) -+ oui = P802_1H_OUI; -+ else -+ oui = RFC1042_OUI; -+ -+ snap->oui[0] = oui[0]; -+ snap->oui[1] = oui[1]; -+ snap->oui[2] = oui[2]; -+ -+ *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); -+ -+ return SNAP_SIZE + sizeof(u16); -+} -+ -+void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) -+{ -+ uint protection; -+ u8 *perp; -+ int erp_len; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ struct registry_priv *pregistrypriv = &padapter->registrypriv; -+ -+ switch (pxmitpriv->vcs_setting) { -+ case DISABLE_VCS: -+ pxmitpriv->vcs = NONE_VCS; -+ break; -+ case ENABLE_VCS: -+ break; -+ case AUTO_VCS: -+ default: -+ perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); -+ if (perp == NULL) { -+ pxmitpriv->vcs = NONE_VCS; -+ } else { -+ protection = (*(perp + 2)) & BIT(1); -+ if (protection) { -+ if (pregistrypriv->vcs_type == RTS_CTS) -+ pxmitpriv->vcs = RTS_CTS; -+ else -+ pxmitpriv->vcs = CTS_TO_SELF; -+ } else { -+ pxmitpriv->vcs = NONE_VCS; -+ } -+ } -+ break; -+ } -+ -+} -+ -+void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz) -+{ -+ struct sta_info *psta = NULL; -+ struct stainfo_stats *pstats = NULL; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ -+ if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { -+ pxmitpriv->tx_bytes += sz; -+ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pxmitframe->agg_num; -+ -+ psta = pxmitframe->attrib.psta; -+ if (psta) { -+ pstats = &psta->sta_stats; -+ pstats->tx_pkts += pxmitframe->agg_num; -+ pstats->tx_bytes += sz; -+ } -+ } -+} -+ -+struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) -+{ -+ struct xmit_buf *pxmitbuf = NULL; -+ struct list_head *plist, *phead; -+ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&pfree_queue->lock, flags); -+ -+ if (list_empty(&pfree_queue->queue)) { -+ pxmitbuf = NULL; -+ } else { -+ phead = get_list_head(pfree_queue); -+ -+ plist = phead->next; -+ -+ pxmitbuf = container_of(plist, struct xmit_buf, list); -+ -+ list_del_init(&(pxmitbuf->list)); -+ } -+ -+ if (pxmitbuf != NULL) { -+ pxmitpriv->free_xmit_extbuf_cnt--; -+ -+ pxmitbuf->priv_data = NULL; -+ /* pxmitbuf->ext_tag = true; */ -+ -+ if (pxmitbuf->sctx) { -+ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); -+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); -+ } -+ } -+ -+ spin_unlock_irqrestore(&pfree_queue->lock, flags); -+ -+ return pxmitbuf; -+} -+ -+s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) -+{ -+ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; -+ unsigned long flags; -+ -+ if (pxmitbuf == NULL) -+ return _FAIL; -+ -+ spin_lock_irqsave(&pfree_queue->lock, flags); -+ -+ list_del_init(&pxmitbuf->list); -+ -+ list_add_tail(&(pxmitbuf->list), get_list_head(pfree_queue)); -+ pxmitpriv->free_xmit_extbuf_cnt++; -+ -+ spin_unlock_irqrestore(&pfree_queue->lock, flags); -+ -+ return _SUCCESS; -+} -+ -+struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) -+{ -+ struct xmit_buf *pxmitbuf = NULL; -+ struct list_head *plist, *phead; -+ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; -+ unsigned long flags; -+ -+ /* DBG_88E("+rtw_alloc_xmitbuf\n"); */ -+ -+ spin_lock_irqsave(&pfree_xmitbuf_queue->lock, flags); -+ -+ if (list_empty(&pfree_xmitbuf_queue->queue)) { -+ pxmitbuf = NULL; -+ } else { -+ phead = get_list_head(pfree_xmitbuf_queue); -+ -+ plist = phead->next; -+ -+ pxmitbuf = container_of(plist, struct xmit_buf, list); -+ -+ list_del_init(&(pxmitbuf->list)); -+ } -+ -+ if (pxmitbuf != NULL) { -+ pxmitpriv->free_xmitbuf_cnt--; -+ pxmitbuf->priv_data = NULL; -+ if (pxmitbuf->sctx) { -+ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); -+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); -+ } -+ } -+ spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, flags); -+ -+ return pxmitbuf; -+} -+ -+s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) -+{ -+ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; -+ unsigned long flags; -+ -+ if (pxmitbuf == NULL) -+ return _FAIL; -+ -+ if (pxmitbuf->sctx) { -+ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); -+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); -+ } -+ -+ if (pxmitbuf->ext_tag) { -+ rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf); -+ } else { -+ spin_lock_irqsave(&pfree_xmitbuf_queue->lock, flags); -+ -+ list_del_init(&pxmitbuf->list); -+ -+ list_add_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue)); -+ -+ pxmitpriv->free_xmitbuf_cnt++; -+ spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, flags); -+ } -+ -+ return _SUCCESS; -+} -+ -+/* -+Calling context: -+1. OS_TXENTRY -+2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) -+ -+If we turn on USE_RXTHREAD, then, no need for critical section. -+Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... -+ -+Must be very very cautious... -+ -+*/ -+ -+struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */ -+{ -+ /* -+ Please remember to use all the osdep_service api, -+ and lock/unlock or _enter/_exit critical to protect -+ pfree_xmit_queue -+ */ -+ -+ struct xmit_frame *pxframe = NULL; -+ struct list_head *plist, *phead; -+ struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; -+ -+ spin_lock_bh(&pfree_xmit_queue->lock); -+ -+ if (list_empty(&pfree_xmit_queue->queue)) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe:%d\n", pxmitpriv->free_xmitframe_cnt)); -+ pxframe = NULL; -+ } else { -+ phead = get_list_head(pfree_xmit_queue); -+ -+ plist = phead->next; -+ -+ pxframe = container_of(plist, struct xmit_frame, list); -+ -+ list_del_init(&(pxframe->list)); -+ } -+ -+ if (pxframe != NULL) { /* default value setting */ -+ pxmitpriv->free_xmitframe_cnt--; -+ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt)); -+ -+ pxframe->buf_addr = NULL; -+ pxframe->pxmitbuf = NULL; -+ -+ memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); -+ /* pxframe->attrib.psta = NULL; */ -+ -+ pxframe->frame_tag = DATA_FRAMETAG; -+ -+ pxframe->pkt = NULL; -+ pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */ -+ -+ pxframe->agg_num = 1; -+ pxframe->ack_report = 0; -+ } -+ -+ spin_unlock_bh(&pfree_xmit_queue->lock); -+ -+ return pxframe; -+} -+ -+s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) -+{ -+ struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; -+ struct adapter *padapter = pxmitpriv->adapter; -+ struct sk_buff *pndis_pkt = NULL; -+ -+ if (pxmitframe == NULL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n")); -+ goto exit; -+ } -+ -+ spin_lock_bh(&pfree_xmit_queue->lock); -+ -+ list_del_init(&pxmitframe->list); -+ -+ if (pxmitframe->pkt) { -+ pndis_pkt = pxmitframe->pkt; -+ pxmitframe->pkt = NULL; -+ } -+ -+ list_add_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue)); -+ -+ pxmitpriv->free_xmitframe_cnt++; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt)); -+ -+ spin_unlock_bh(&pfree_xmit_queue->lock); -+ -+ if (pndis_pkt) -+ rtw_os_pkt_complete(padapter, pndis_pkt); -+ -+exit: -+ -+ return _SUCCESS; -+} -+ -+void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue) -+{ -+ struct list_head *plist, *phead; -+ struct xmit_frame *pxmitframe; -+ -+ spin_lock_bh(&pframequeue->lock); -+ -+ phead = get_list_head(pframequeue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ pxmitframe = container_of(plist, struct xmit_frame, list); -+ -+ plist = plist->next; -+ -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ } -+ spin_unlock_bh(&pframequeue->lock); -+ -+} -+ -+s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) -+{ -+ if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, -+ ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n")); -+/* pxmitframe->pkt = NULL; */ -+ return _FAIL; -+ } -+ -+ return _SUCCESS; -+} -+ -+static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, struct __queue *pframe_queue) -+{ -+ struct list_head *xmitframe_plist, *xmitframe_phead; -+ struct xmit_frame *pxmitframe = NULL; -+ -+ xmitframe_phead = get_list_head(pframe_queue); -+ xmitframe_plist = xmitframe_phead->next; -+ -+ if (xmitframe_phead != xmitframe_plist) { -+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); -+ -+ xmitframe_plist = xmitframe_plist->next; -+ -+ list_del_init(&pxmitframe->list); -+ -+ ptxservq->qcnt--; -+ } -+ return pxmitframe; -+} -+ -+struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, int entry) -+{ -+ struct list_head *sta_plist, *sta_phead; -+ struct hw_xmit *phwxmit; -+ struct tx_servq *ptxservq = NULL; -+ struct __queue *pframe_queue = NULL; -+ struct xmit_frame *pxmitframe = NULL; -+ struct adapter *padapter = pxmitpriv->adapter; -+ struct registry_priv *pregpriv = &padapter->registrypriv; -+ int i, inx[4]; -+ -+ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; -+ -+ if (pregpriv->wifi_spec == 1) { -+ int j; -+ -+ for (j = 0; j < 4; j++) -+ inx[j] = pxmitpriv->wmm_para_seq[j]; -+ } -+ -+ spin_lock_bh(&pxmitpriv->lock); -+ -+ for (i = 0; i < entry; i++) { -+ phwxmit = phwxmit_i + inx[i]; -+ -+ sta_phead = get_list_head(phwxmit->sta_queue); -+ sta_plist = sta_phead->next; -+ -+ while (sta_phead != sta_plist) { -+ ptxservq = container_of(sta_plist, struct tx_servq, tx_pending); -+ -+ pframe_queue = &ptxservq->sta_pending; -+ -+ pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue); -+ -+ if (pxmitframe) { -+ phwxmit->accnt--; -+ -+ /* Remove sta node when there are no pending packets. */ -+ if (list_empty(&pframe_queue->queue)) /* must be done after get_next and before break */ -+ list_del_init(&ptxservq->tx_pending); -+ goto exit; -+ } -+ -+ sta_plist = sta_plist->next; -+ } -+ } -+exit: -+ spin_unlock_bh(&pxmitpriv->lock); -+ -+ return pxmitframe; -+} -+ -+struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, int up, u8 *ac) -+{ -+ struct tx_servq *ptxservq; -+ -+ switch (up) { -+ case 1: -+ case 2: -+ ptxservq = &(psta->sta_xmitpriv.bk_q); -+ *(ac) = 3; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n")); -+ break; -+ case 4: -+ case 5: -+ ptxservq = &(psta->sta_xmitpriv.vi_q); -+ *(ac) = 1; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n")); -+ break; -+ case 6: -+ case 7: -+ ptxservq = &(psta->sta_xmitpriv.vo_q); -+ *(ac) = 0; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n")); -+ break; -+ case 0: -+ case 3: -+ default: -+ ptxservq = &(psta->sta_xmitpriv.be_q); -+ *(ac) = 2; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n")); -+ break; -+ } -+ -+ return ptxservq; -+} -+ -+/* -+ * Will enqueue pxmitframe to the proper queue, -+ * and indicate it to xx_pending list..... -+ */ -+s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) -+{ -+ u8 ac_index; -+ struct sta_info *psta; -+ struct tx_servq *ptxservq; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; -+ int res = _SUCCESS; -+ -+ if (pattrib->psta) { -+ psta = pattrib->psta; -+ } else { -+ psta = rtw_get_stainfo(pstapriv, pattrib->ra); -+ } -+ -+ if (psta == NULL) { -+ res = _FAIL; -+ DBG_88E("rtw_xmit_classifier: psta == NULL\n"); -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmit_classifier: psta == NULL\n")); -+ goto exit; -+ } -+ -+ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); -+ -+ if (list_empty(&ptxservq->tx_pending)) -+ list_add_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue)); -+ -+ list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending)); -+ ptxservq->qcnt++; -+ phwxmits[ac_index].accnt++; -+exit: -+ -+ return res; -+} -+ -+void rtw_alloc_hwxmits(struct adapter *padapter) -+{ -+ struct hw_xmit *hwxmits; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+ pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; -+ -+ pxmitpriv->hwxmits = (struct hw_xmit *)rtw_zmalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry); -+ -+ hwxmits = pxmitpriv->hwxmits; -+ -+ if (pxmitpriv->hwxmit_entry == 5) { -+ hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; -+ hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; -+ hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; -+ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; -+ hwxmits[4] .sta_queue = &pxmitpriv->be_pending; -+ } else if (pxmitpriv->hwxmit_entry == 4) { -+ hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; -+ hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; -+ hwxmits[2] .sta_queue = &pxmitpriv->be_pending; -+ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; -+ } else { -+ } -+} -+ -+void rtw_free_hwxmits(struct adapter *padapter) -+{ -+ struct hw_xmit *hwxmits; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+ hwxmits = pxmitpriv->hwxmits; -+ kfree(hwxmits); -+} -+ -+void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry) -+{ -+ int i; -+ -+ for (i = 0; i < entry; i++, phwxmit++) -+ phwxmit->accnt = 0; -+ -+} -+ -+static int rtw_br_client_tx(struct adapter *padapter, struct sk_buff **pskb) -+{ -+ struct sk_buff *skb = *pskb; -+ int res, is_vlan_tag = 0, i, do_nat25 = 1; -+ unsigned short vlan_hdr = 0; -+ void *br_port = NULL; -+ -+ rcu_read_lock(); -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) -+ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); -+#else -+ br_port = rcu_dereference(padapter->pnetdev->br_port); -+#endif -+ rcu_read_unlock(); -+ spin_lock_bh(&padapter->br_ext_lock); -+ if (!(skb->data[0] & 1) && br_port && -+ memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) && -+ *((__be16 *)(skb->data+MACADDRLEN*2)) != __constant_htons(ETH_P_8021Q) && -+ *((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP) && -+ !memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN) && padapter->scdb_entry) { -+ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); -+ padapter->scdb_entry->ageing_timer = jiffies; -+ spin_unlock_bh(&padapter->br_ext_lock); -+ } else { -+ if (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_8021Q)) { -+ is_vlan_tag = 1; -+ vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2)); -+ for (i = 0; i < 6; i++) -+ *((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2)); -+ skb_pull(skb, 4); -+ } -+ if (!memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) && -+ (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP))) -+ memcpy(padapter->br_ip, skb->data+WLAN_ETHHDR_LEN+12, 4); -+ -+ if (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP)) { -+ if (memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN)) { -+ padapter->scdb_entry = (struct nat25_network_db_entry *)scdb_findEntry(padapter, -+ skb->data+MACADDRLEN, skb->data+WLAN_ETHHDR_LEN+12); -+ if (padapter->scdb_entry) { -+ memcpy(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN); -+ memcpy(padapter->scdb_ip, skb->data+WLAN_ETHHDR_LEN+12, 4); -+ padapter->scdb_entry->ageing_timer = jiffies; -+ do_nat25 = 0; -+ } -+ } else { -+ if (padapter->scdb_entry) { -+ padapter->scdb_entry->ageing_timer = jiffies; -+ do_nat25 = 0; -+ } else { -+ memset(padapter->scdb_mac, 0, MACADDRLEN); -+ memset(padapter->scdb_ip, 0, 4); -+ } -+ } -+ } -+ spin_unlock_bh(&padapter->br_ext_lock); -+ if (do_nat25) { -+ if (nat25_db_handle(padapter, skb, NAT25_CHECK) == 0) { -+ struct sk_buff *newskb; -+ -+ if (is_vlan_tag) { -+ skb_push(skb, 4); -+ for (i = 0; i < 6; i++) -+ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2)); -+ *((__be16 *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q); -+ *((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr; -+ } -+ -+ newskb = skb_copy(skb, GFP_ATOMIC); -+ if (newskb == NULL) { -+ DEBUG_ERR("TX DROP: skb_copy fail!\n"); -+ return -1; -+ } -+ dev_kfree_skb_any(skb); -+ -+ *pskb = skb = newskb; -+ if (is_vlan_tag) { -+ vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2)); -+ for (i = 0; i < 6; i++) -+ *((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2)); -+ skb_pull(skb, 4); -+ } -+ } -+ -+ if (skb_is_nonlinear(skb)) -+ DEBUG_ERR("%s(): skb_is_nonlinear!!\n", __func__); -+ -+ res = skb_linearize(skb); -+ if (res < 0) { -+ DEBUG_ERR("TX DROP: skb_linearize fail!\n"); -+ return -1; -+ } -+ -+ res = nat25_db_handle(padapter, skb, NAT25_INSERT); -+ if (res < 0) { -+ if (res == -2) { -+ DEBUG_ERR("TX DROP: nat25_db_handle fail!\n"); -+ return -1; -+ } -+ return 0; -+ } -+ } -+ -+ memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); -+ -+ dhcp_flag_bcast(padapter, skb); -+ -+ if (is_vlan_tag) { -+ skb_push(skb, 4); -+ for (i = 0; i < 6; i++) -+ *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2)); -+ *((__be16 *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q); -+ *((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr; -+ } -+ } -+ -+ /* check if SA is equal to our MAC */ -+ if (memcmp(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN)) { -+ DEBUG_ERR("TX DROP: untransformed frame SA:%02X%02X%02X%02X%02X%02X!\n", -+ skb->data[6], skb->data[7], skb->data[8], skb->data[9], skb->data[10], skb->data[11]); -+ return -1; -+ } -+ return 0; -+} -+ -+u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe) -+{ -+ u32 addr; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ -+ switch (pattrib->qsel) { -+ case 0: -+ case 3: -+ addr = BE_QUEUE_INX; -+ break; -+ case 1: -+ case 2: -+ addr = BK_QUEUE_INX; -+ break; -+ case 4: -+ case 5: -+ addr = VI_QUEUE_INX; -+ break; -+ case 6: -+ case 7: -+ addr = VO_QUEUE_INX; -+ break; -+ case 0x10: -+ addr = BCN_QUEUE_INX; -+ break; -+ case 0x11:/* BC/MC in PS (HIQ) */ -+ addr = HIGH_QUEUE_INX; -+ break; -+ case 0x12: -+ default: -+ addr = MGT_QUEUE_INX; -+ break; -+ } -+ -+ return addr; -+} -+ -+static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib) -+{ -+ u8 qsel; -+ -+ qsel = pattrib->priority; -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("### do_queue_select priority=%d , qsel = %d\n", pattrib->priority , qsel)); -+ -+ pattrib->qsel = qsel; -+} -+ -+/* -+ * The main transmit(tx) entry -+ * -+ * Return -+ * 1 enqueue -+ * 0 success, hardware will handle this xmit frame(packet) -+ * <0 fail -+ */ -+s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) -+{ -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ struct xmit_frame *pxmitframe = NULL; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ void *br_port = NULL; -+ s32 res; -+ -+ pxmitframe = rtw_alloc_xmitframe(pxmitpriv); -+ if (pxmitframe == NULL) { -+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n")); -+ DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__); -+ return -1; -+ } -+ -+ rcu_read_lock(); -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) -+ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); -+#else -+ br_port = rcu_dereference(padapter->pnetdev->br_port); -+#endif -+ rcu_read_unlock(); -+ -+ if (br_port && check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) { -+ res = rtw_br_client_tx(padapter, ppkt); -+ if (res == -1) { -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ return -1; -+ } -+ } -+ -+ res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); -+ -+ if (res == _FAIL) { -+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n")); -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ return -1; -+ } -+ pxmitframe->pkt = *ppkt; -+ -+ rtw_led_control(padapter, LED_CTL_TX); -+ -+ do_queue_select(padapter, &pxmitframe->attrib); -+ -+#ifdef CONFIG_88EU_AP_MODE -+ spin_lock_bh(&pxmitpriv->lock); -+ if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe)) { -+ spin_unlock_bh(&pxmitpriv->lock); -+ return 1; -+ } -+ spin_unlock_bh(&pxmitpriv->lock); -+#endif -+ -+ if (rtw_hal_xmit(padapter, pxmitframe) == false) -+ return 1; -+ -+ return 0; -+} -+ -+#if defined(CONFIG_88EU_AP_MODE) -+ -+int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe) -+{ -+ int ret = false; -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; -+ int bmcst = IS_MCAST(pattrib->ra); -+ -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false) -+ return ret; -+ -+ if (pattrib->psta) -+ psta = pattrib->psta; -+ else -+ psta = rtw_get_stainfo(pstapriv, pattrib->ra); -+ -+ if (psta == NULL) -+ return ret; -+ -+ if (pattrib->triggered == 1) { -+ if (bmcst) -+ pattrib->qsel = 0x11;/* HIQ */ -+ return ret; -+ } -+ -+ if (bmcst) { -+ spin_lock_bh(&psta->sleep_q.lock); -+ -+ if (pstapriv->sta_dz_bitmap) {/* if any one sta is in ps mode */ -+ list_del_init(&pxmitframe->list); -+ -+ list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); -+ -+ psta->sleepq_len++; -+ -+ pstapriv->tim_bitmap |= BIT(0);/* */ -+ pstapriv->sta_dz_bitmap |= BIT(0); -+ -+ update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */ -+ -+ ret = true; -+ } -+ -+ spin_unlock_bh(&psta->sleep_q.lock); -+ -+ return ret; -+ } -+ -+ spin_lock_bh(&psta->sleep_q.lock); -+ -+ if (psta->state&WIFI_SLEEP_STATE) { -+ u8 wmmps_ac = 0; -+ -+ if (pstapriv->sta_dz_bitmap&BIT(psta->aid)) { -+ list_del_init(&pxmitframe->list); -+ -+ list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); -+ -+ psta->sleepq_len++; -+ -+ switch (pattrib->priority) { -+ case 1: -+ case 2: -+ wmmps_ac = psta->uapsd_bk&BIT(0); -+ break; -+ case 4: -+ case 5: -+ wmmps_ac = psta->uapsd_vi&BIT(0); -+ break; -+ case 6: -+ case 7: -+ wmmps_ac = psta->uapsd_vo&BIT(0); -+ break; -+ case 0: -+ case 3: -+ default: -+ wmmps_ac = psta->uapsd_be&BIT(0); -+ break; -+ } -+ -+ if (wmmps_ac) -+ psta->sleepq_ac_len++; -+ -+ if (((psta->has_legacy_ac) && (!wmmps_ac)) || -+ ((!psta->has_legacy_ac) && (wmmps_ac))) { -+ pstapriv->tim_bitmap |= BIT(psta->aid); -+ -+ if (psta->sleepq_len == 1) { -+ /* upate BCN for TIM IE */ -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+ } -+ } -+ ret = true; -+ } -+ } -+ -+ spin_unlock_bh(&psta->sleep_q.lock); -+ -+ return ret; -+} -+ -+static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue) -+{ -+ struct list_head *plist, *phead; -+ u8 ac_index; -+ struct tx_servq *ptxservq; -+ struct pkt_attrib *pattrib; -+ struct xmit_frame *pxmitframe; -+ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; -+ -+ phead = get_list_head(pframequeue); -+ plist = phead->next; -+ -+ while (phead != plist) { -+ pxmitframe = container_of(plist, struct xmit_frame, list); -+ -+ plist = plist->next; -+ -+ xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe); -+ -+ pattrib = &pxmitframe->attrib; -+ -+ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); -+ -+ ptxservq->qcnt--; -+ phwxmits[ac_index].accnt--; -+ } -+} -+ -+void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta) -+{ -+ struct sta_info *psta_bmc; -+ struct sta_xmit_priv *pstaxmitpriv; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ -+ pstaxmitpriv = &psta->sta_xmitpriv; -+ -+ /* for BC/MC Frames */ -+ psta_bmc = rtw_get_bcmc_stainfo(padapter); -+ -+ spin_lock_bh(&pxmitpriv->lock); -+ -+ psta->state |= WIFI_SLEEP_STATE; -+ -+ pstapriv->sta_dz_bitmap |= BIT(psta->aid); -+ -+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending); -+ list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); -+ -+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending); -+ list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); -+ -+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending); -+ list_del_init(&(pstaxmitpriv->be_q.tx_pending)); -+ -+ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending); -+ list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); -+ -+ /* for BC/MC Frames */ -+ pstaxmitpriv = &psta_bmc->sta_xmitpriv; -+ dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending); -+ list_del_init(&(pstaxmitpriv->be_q.tx_pending)); -+ -+ spin_unlock_bh(&pxmitpriv->lock); -+} -+ -+void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta) -+{ -+ u8 update_mask = 0, wmmps_ac = 0; -+ struct sta_info *psta_bmc; -+ struct list_head *xmitframe_plist, *xmitframe_phead; -+ struct xmit_frame *pxmitframe = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ spin_lock_bh(&psta->sleep_q.lock); -+ -+ xmitframe_phead = get_list_head(&psta->sleep_q); -+ xmitframe_plist = xmitframe_phead->next; -+ -+ while (xmitframe_phead != xmitframe_plist) { -+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); -+ -+ xmitframe_plist = xmitframe_plist->next; -+ -+ list_del_init(&pxmitframe->list); -+ -+ switch (pxmitframe->attrib.priority) { -+ case 1: -+ case 2: -+ wmmps_ac = psta->uapsd_bk&BIT(1); -+ break; -+ case 4: -+ case 5: -+ wmmps_ac = psta->uapsd_vi&BIT(1); -+ break; -+ case 6: -+ case 7: -+ wmmps_ac = psta->uapsd_vo&BIT(1); -+ break; -+ case 0: -+ case 3: -+ default: -+ wmmps_ac = psta->uapsd_be&BIT(1); -+ break; -+ } -+ -+ psta->sleepq_len--; -+ if (psta->sleepq_len > 0) -+ pxmitframe->attrib.mdata = 1; -+ else -+ pxmitframe->attrib.mdata = 0; -+ -+ if (wmmps_ac) { -+ psta->sleepq_ac_len--; -+ if (psta->sleepq_ac_len > 0) { -+ pxmitframe->attrib.mdata = 1; -+ pxmitframe->attrib.eosp = 0; -+ } else { -+ pxmitframe->attrib.mdata = 0; -+ pxmitframe->attrib.eosp = 1; -+ } -+ } -+ -+ pxmitframe->attrib.triggered = 1; -+ -+ spin_unlock_bh(&psta->sleep_q.lock); -+ if (rtw_hal_xmit(padapter, pxmitframe)) -+ rtw_os_xmit_complete(padapter, pxmitframe); -+ spin_lock_bh(&psta->sleep_q.lock); -+ } -+ -+ if (psta->sleepq_len == 0) { -+ pstapriv->tim_bitmap &= ~BIT(psta->aid); -+ -+ update_mask = BIT(0); -+ -+ if (psta->state&WIFI_SLEEP_STATE) -+ psta->state ^= WIFI_SLEEP_STATE; -+ -+ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { -+ psta->expire_to = pstapriv->expire_to; -+ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; -+ } -+ -+ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); -+ } -+ -+ spin_unlock_bh(&psta->sleep_q.lock); -+ -+ /* for BC/MC Frames */ -+ psta_bmc = rtw_get_bcmc_stainfo(padapter); -+ if (!psta_bmc) -+ return; -+ -+ if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) { /* no any sta in ps mode */ -+ spin_lock_bh(&psta_bmc->sleep_q.lock); -+ -+ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); -+ xmitframe_plist = xmitframe_phead->next; -+ -+ while (xmitframe_phead != xmitframe_plist) { -+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); -+ -+ xmitframe_plist = xmitframe_plist->next; -+ -+ list_del_init(&pxmitframe->list); -+ -+ psta_bmc->sleepq_len--; -+ if (psta_bmc->sleepq_len > 0) -+ pxmitframe->attrib.mdata = 1; -+ else -+ pxmitframe->attrib.mdata = 0; -+ -+ pxmitframe->attrib.triggered = 1; -+ -+ spin_unlock_bh(&psta_bmc->sleep_q.lock); -+ if (rtw_hal_xmit(padapter, pxmitframe)) -+ rtw_os_xmit_complete(padapter, pxmitframe); -+ spin_lock_bh(&psta_bmc->sleep_q.lock); -+ } -+ -+ if (psta_bmc->sleepq_len == 0) { -+ pstapriv->tim_bitmap &= ~BIT(0); -+ pstapriv->sta_dz_bitmap &= ~BIT(0); -+ -+ update_mask |= BIT(1); -+ } -+ -+ spin_unlock_bh(&psta_bmc->sleep_q.lock); -+ } -+ -+ if (update_mask) -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+} -+ -+void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta) -+{ -+ u8 wmmps_ac = 0; -+ struct list_head *xmitframe_plist, *xmitframe_phead; -+ struct xmit_frame *pxmitframe = NULL; -+ struct sta_priv *pstapriv = &padapter->stapriv; -+ -+ spin_lock_bh(&psta->sleep_q.lock); -+ -+ xmitframe_phead = get_list_head(&psta->sleep_q); -+ xmitframe_plist = xmitframe_phead->next; -+ -+ while (xmitframe_phead != xmitframe_plist) { -+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); -+ -+ xmitframe_plist = xmitframe_plist->next; -+ -+ switch (pxmitframe->attrib.priority) { -+ case 1: -+ case 2: -+ wmmps_ac = psta->uapsd_bk&BIT(1); -+ break; -+ case 4: -+ case 5: -+ wmmps_ac = psta->uapsd_vi&BIT(1); -+ break; -+ case 6: -+ case 7: -+ wmmps_ac = psta->uapsd_vo&BIT(1); -+ break; -+ case 0: -+ case 3: -+ default: -+ wmmps_ac = psta->uapsd_be&BIT(1); -+ break; -+ } -+ -+ if (!wmmps_ac) -+ continue; -+ -+ list_del_init(&pxmitframe->list); -+ -+ psta->sleepq_len--; -+ psta->sleepq_ac_len--; -+ -+ if (psta->sleepq_ac_len > 0) { -+ pxmitframe->attrib.mdata = 1; -+ pxmitframe->attrib.eosp = 0; -+ } else { -+ pxmitframe->attrib.mdata = 0; -+ pxmitframe->attrib.eosp = 1; -+ } -+ -+ pxmitframe->attrib.triggered = 1; -+ -+ if (rtw_hal_xmit(padapter, pxmitframe) == true) -+ rtw_os_xmit_complete(padapter, pxmitframe); -+ -+ if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) { -+ pstapriv->tim_bitmap &= ~BIT(psta->aid); -+ -+ /* upate BCN for TIM IE */ -+ update_beacon(padapter, _TIM_IE_, NULL, false); -+ } -+ } -+ -+ spin_unlock_bh(&psta->sleep_q.lock); -+} -+ -+#endif -+ -+void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms) -+{ -+ sctx->timeout_ms = timeout_ms; -+ sctx->submit_time = jiffies; -+ init_completion(&sctx->done); -+ sctx->status = RTW_SCTX_SUBMITTED; -+} -+ -+int rtw_sctx_wait(struct submit_ctx *sctx) -+{ -+ int ret = _FAIL; -+ unsigned long expire; -+ int status = 0; -+ -+ expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; -+ if (!wait_for_completion_timeout(&sctx->done, expire)) { -+ /* timeout, do something?? */ -+ status = RTW_SCTX_DONE_TIMEOUT; -+ DBG_88E("%s timeout\n", __func__); -+ } else { -+ status = sctx->status; -+ } -+ -+ if (status == RTW_SCTX_DONE_SUCCESS) -+ ret = _SUCCESS; -+ -+ return ret; -+} -+ -+static bool rtw_sctx_chk_waring_status(int status) -+{ -+ switch (status) { -+ case RTW_SCTX_DONE_UNKNOWN: -+ case RTW_SCTX_DONE_BUF_ALLOC: -+ case RTW_SCTX_DONE_BUF_FREE: -+ -+ case RTW_SCTX_DONE_DRV_STOP: -+ case RTW_SCTX_DONE_DEV_REMOVE: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+void rtw_sctx_done_err(struct submit_ctx **sctx, int status) -+{ -+ if (*sctx) { -+ if (rtw_sctx_chk_waring_status(status)) -+ DBG_88E("%s status:%d\n", __func__, status); -+ (*sctx)->status = status; -+ complete(&((*sctx)->done)); -+ *sctx = NULL; -+ } -+} -+ -+void rtw_sctx_done(struct submit_ctx **sctx) -+{ -+ rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS); -+} -+ -+int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms) -+{ -+ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; -+ -+ pack_tx_ops->submit_time = jiffies; -+ pack_tx_ops->timeout_ms = timeout_ms; -+ pack_tx_ops->status = RTW_SCTX_SUBMITTED; -+ -+ return rtw_sctx_wait(pack_tx_ops); -+} -+ -+void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) -+{ -+ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; -+ -+ if (pxmitpriv->ack_tx) -+ rtw_sctx_done_err(&pack_tx_ops, status); -+ else -+ DBG_88E("%s ack_tx not set\n", __func__); -+} -diff --git a/drivers/net/wireless/rtl8188eu/dkms.conf b/drivers/net/wireless/rtl8188eu/dkms.conf -new file mode 100644 -index 0000000000000..ecf516ff6dff5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/dkms.conf -@@ -0,0 +1,9 @@ -+PACKAGE_NAME="8188eu" -+PACKAGE_VERSION="1.0" -+BUILT_MODULE_NAME="8188eu" -+DEST_MODULE_LOCATION="/kernel/drivers/net/wireless/" -+REMAKE_INITRD="yes" -+AUTOINSTALL="yes" -+MAKE="'make' all KVER=${kernelver}" -+MAKE="'make' all" -+CLEAN="'make' clean" -diff --git a/drivers/net/wireless/rtl8188eu/hal/Hal8188EPwrSeq.c b/drivers/net/wireless/rtl8188eu/hal/Hal8188EPwrSeq.c -new file mode 100644 -index 0000000000000..fc23bf1593458 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/Hal8188EPwrSeq.c -@@ -0,0 +1,86 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include "Hal8188EPwrSeq.h" -+#include -+ -+/* -+ drivers should parse below arrays and do the corresponding actions -+*/ -+/* 3 Power on Array */ -+struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ RTL8188E_TRANS_CARDEMU_TO_ACT -+ RTL8188E_TRANS_END -+}; -+ -+/* 3Radio off Array */ -+struct wl_pwr_cfg rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ RTL8188E_TRANS_ACT_TO_CARDEMU -+ RTL8188E_TRANS_END -+}; -+ -+/* 3Card Disable Array */ -+struct wl_pwr_cfg rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ RTL8188E_TRANS_ACT_TO_CARDEMU -+ RTL8188E_TRANS_CARDEMU_TO_CARDDIS -+ RTL8188E_TRANS_END -+}; -+ -+/* 3 Card Enable Array */ -+struct wl_pwr_cfg rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ RTL8188E_TRANS_CARDDIS_TO_CARDEMU -+ RTL8188E_TRANS_CARDEMU_TO_ACT -+ RTL8188E_TRANS_END -+}; -+ -+/* 3Suspend Array */ -+struct wl_pwr_cfg rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ RTL8188E_TRANS_ACT_TO_CARDEMU -+ RTL8188E_TRANS_CARDEMU_TO_SUS -+ RTL8188E_TRANS_END -+}; -+ -+/* 3 Resume Array */ -+struct wl_pwr_cfg rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ RTL8188E_TRANS_SUS_TO_CARDEMU -+ RTL8188E_TRANS_CARDEMU_TO_ACT -+ RTL8188E_TRANS_END -+}; -+ -+/* 3HWPDN Array */ -+struct wl_pwr_cfg rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ RTL8188E_TRANS_ACT_TO_CARDEMU -+ RTL8188E_TRANS_CARDEMU_TO_PDN -+ RTL8188E_TRANS_END -+}; -+ -+/* 3 Enter LPS */ -+struct wl_pwr_cfg rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ /* FW behavior */ -+ RTL8188E_TRANS_ACT_TO_LPS -+ RTL8188E_TRANS_END -+}; -+ -+/* 3 Leave LPS */ -+struct wl_pwr_cfg rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = { -+ /* FW behavior */ -+ RTL8188E_TRANS_LPS_TO_ACT -+ RTL8188E_TRANS_END -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hal/Hal8188ERateAdaptive.c b/drivers/net/wireless/rtl8188eu/hal/Hal8188ERateAdaptive.c -new file mode 100644 -index 0000000000000..aaa261771ab9b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/Hal8188ERateAdaptive.c -@@ -0,0 +1,760 @@ -+/*++ -+Copyright (c) Realtek Semiconductor Corp. All rights reserved. -+ -+Module Name: -+ RateAdaptive.c -+ -+Abstract: -+ Implement Rate Adaptive functions for common operations. -+ -+Major Change History: -+ When Who What -+ ---------- --------------- ------------------------------- -+ 2011-08-12 Page Create. -+ -+--*/ -+#include "odm_precomp.h" -+ -+/* Rate adaptive parameters */ -+ -+static u8 RETRY_PENALTY[PERENTRY][RETRYSIZE+1] = { -+ {5, 4, 3, 2, 0, 3}, /* 92 , idx = 0 */ -+ {6, 5, 4, 3, 0, 4}, /* 86 , idx = 1 */ -+ {6, 5, 4, 2, 0, 4}, /* 81 , idx = 2 */ -+ {8, 7, 6, 4, 0, 6}, /* 75 , idx = 3 */ -+ {10, 9, 8, 6, 0, 8}, /* 71 , idx = 4 */ -+ {10, 9, 8, 4, 0, 8}, /* 66 , idx = 5 */ -+ {10, 9, 8, 2, 0, 8}, /* 62 , idx = 6 */ -+ {10, 9, 8, 0, 0, 8}, /* 59 , idx = 7 */ -+ {18, 17, 16, 8, 0, 16}, /* 53 , idx = 8 */ -+ {26, 25, 24, 16, 0, 24}, /* 50 , idx = 9 */ -+ {34, 33, 32, 24, 0, 32}, /* 47 , idx = 0x0a */ -+ {34, 31, 28, 20, 0, 32}, /* 43 , idx = 0x0b */ -+ {34, 31, 27, 18, 0, 32}, /* 40 , idx = 0x0c */ -+ {34, 31, 26, 16, 0, 32}, /* 37 , idx = 0x0d */ -+ {34, 30, 22, 16, 0, 32}, /* 32 , idx = 0x0e */ -+ {34, 30, 24, 16, 0, 32}, /* 26 , idx = 0x0f */ -+ {49, 46, 40, 16, 0, 48}, /* 20 , idx = 0x10 */ -+ {49, 45, 32, 0, 0, 48}, /* 17 , idx = 0x11 */ -+ {49, 45, 22, 18, 0, 48}, /* 15 , idx = 0x12 */ -+ {49, 40, 24, 16, 0, 48}, /* 12 , idx = 0x13 */ -+ {49, 32, 18, 12, 0, 48}, /* 9 , idx = 0x14 */ -+ {49, 22, 18, 14, 0, 48}, /* 6 , idx = 0x15 */ -+ {49, 16, 16, 0, 0, 48} -+ }; /* 3, idx = 0x16 */ -+ -+static u8 PT_PENALTY[RETRYSIZE+1] = {34, 31, 30, 24, 0, 32}; -+ -+/* wilson modify */ -+static u8 RETRY_PENALTY_IDX[2][RATESIZE] = { -+ {4, 4, 4, 5, 4, 4, 5, 7, 7, 7, 8, 0x0a, /* SS>TH */ -+ 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d, -+ 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f}, /* 0329 R01 */ -+ {0x0a, 0x0a, 0x0b, 0x0c, 0x0a, -+ 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x14, /* SSTH */ -+ 0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15, -+ 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15}; -+ -+static u8 RSSI_THRESHOLD[RATESIZE] = { -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0x24, 0x26, 0x2a, -+ 0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a, -+ 0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c}; -+ -+static u16 N_THRESHOLD_HIGH[RATESIZE] = { -+ 4, 4, 8, 16, -+ 24, 36, 48, 72, 96, 144, 192, 216, -+ 60, 80, 100, 160, 240, 400, 560, 640, -+ 300, 320, 480, 720, 1000, 1200, 1600, 2000}; -+static u16 N_THRESHOLD_LOW[RATESIZE] = { -+ 2, 2, 4, 8, -+ 12, 18, 24, 36, 48, 72, 96, 108, -+ 30, 40, 50, 80, 120, 200, 280, 320, -+ 150, 160, 240, 360, 500, 600, 800, 1000}; -+ -+static u8 DROPING_NECESSARY[RATESIZE] = { -+ 1, 1, 1, 1, -+ 1, 2, 3, 4, 5, 6, 7, 8, -+ 1, 2, 3, 4, 5, 6, 7, 8, -+ 5, 6, 7, 8, 9, 10, 11, 12}; -+ -+static u8 PendingForRateUpFail[5] = {2, 10, 24, 40, 60}; -+static u16 DynamicTxRPTTiming[6] = { -+ 0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12 , 0x927c}; /* 200ms-1200ms */ -+ -+/* End Rate adaptive parameters */ -+ -+static void odm_SetTxRPTTiming_8188E( -+ struct odm_dm_struct *dm_odm, -+ struct odm_ra_info *pRaInfo, -+ u8 extend -+ ) -+{ -+ u8 idx = 0; -+ -+ for (idx = 0; idx < 5; idx++) -+ if (DynamicTxRPTTiming[idx] == pRaInfo->RptTime) -+ break; -+ -+ if (extend == 0) { /* back to default timing */ -+ idx = 0; /* 200ms */ -+ } else if (extend == 1) {/* increase the timing */ -+ idx += 1; -+ if (idx > 5) -+ idx = 5; -+ } else if (extend == 2) {/* decrease the timing */ -+ if (idx != 0) -+ idx -= 1; -+ } -+ pRaInfo->RptTime = DynamicTxRPTTiming[idx]; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("pRaInfo->RptTime = 0x%x\n", pRaInfo->RptTime)); -+} -+ -+static int odm_RateDown_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo) -+{ -+ u8 RateID, LowestRate, HighestRate; -+ u8 i; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDown_8188E()\n")); -+ if (NULL == pRaInfo) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateDown_8188E(): pRaInfo is NULL\n")); -+ return -1; -+ } -+ RateID = pRaInfo->PreRate; -+ LowestRate = pRaInfo->LowestRate; -+ HighestRate = pRaInfo->HighestRate; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ (" RateID =%d LowestRate =%d HighestRate =%d RateSGI =%d\n", -+ RateID, LowestRate, HighestRate, pRaInfo->RateSGI)); -+ if (RateID > HighestRate) { -+ RateID = HighestRate; -+ } else if (pRaInfo->RateSGI) { -+ pRaInfo->RateSGI = 0; -+ } else if (RateID > LowestRate) { -+ if (RateID > 0) { -+ for (i = RateID-1; i > LowestRate; i--) { -+ if (pRaInfo->RAUseRate & BIT(i)) { -+ RateID = i; -+ goto RateDownFinish; -+ } -+ } -+ } -+ } else if (RateID <= LowestRate) { -+ RateID = LowestRate; -+ } -+RateDownFinish: -+ if (pRaInfo->RAWaitingCounter == 1) { -+ pRaInfo->RAWaitingCounter += 1; -+ pRaInfo->RAPendingCounter += 1; -+ } else if (pRaInfo->RAWaitingCounter == 0) { -+ ; -+ } else { -+ pRaInfo->RAWaitingCounter = 0; -+ pRaInfo->RAPendingCounter = 0; -+ } -+ -+ if (pRaInfo->RAPendingCounter >= 4) -+ pRaInfo->RAPendingCounter = 4; -+ -+ pRaInfo->DecisionRate = RateID; -+ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 2); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down, RPT Timing default\n")); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d", pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter)); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down to RateID %d RateSGI %d\n", RateID, pRaInfo->RateSGI)); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateDown_8188E()\n")); -+ return 0; -+} -+ -+static int odm_RateUp_8188E( -+ struct odm_dm_struct *dm_odm, -+ struct odm_ra_info *pRaInfo -+ ) -+{ -+ u8 RateID, HighestRate; -+ u8 i; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateUp_8188E()\n")); -+ if (NULL == pRaInfo) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E(): pRaInfo is NULL\n")); -+ return -1; -+ } -+ RateID = pRaInfo->PreRate; -+ HighestRate = pRaInfo->HighestRate; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ (" RateID =%d HighestRate =%d\n", -+ RateID, HighestRate)); -+ if (pRaInfo->RAWaitingCounter == 1) { -+ pRaInfo->RAWaitingCounter = 0; -+ pRaInfo->RAPendingCounter = 0; -+ } else if (pRaInfo->RAWaitingCounter > 1) { -+ pRaInfo->PreRssiStaRA = pRaInfo->RssiStaRA; -+ goto RateUpfinish; -+ } -+ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 0); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E():Decrease RPT Timing\n")); -+ -+ if (RateID < HighestRate) { -+ for (i = RateID+1; i <= HighestRate; i++) { -+ if (pRaInfo->RAUseRate & BIT(i)) { -+ RateID = i; -+ goto RateUpfinish; -+ } -+ } -+ } else if (RateID == HighestRate) { -+ if (pRaInfo->SGIEnable && (pRaInfo->RateSGI != 1)) -+ pRaInfo->RateSGI = 1; -+ else if ((pRaInfo->SGIEnable) != 1) -+ pRaInfo->RateSGI = 0; -+ } else { -+ RateID = HighestRate; -+ } -+RateUpfinish: -+ if (pRaInfo->RAWaitingCounter == (4+PendingForRateUpFail[pRaInfo->RAPendingCounter])) -+ pRaInfo->RAWaitingCounter = 0; -+ else -+ pRaInfo->RAWaitingCounter++; -+ -+ pRaInfo->DecisionRate = RateID; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate up to RateID %d\n", RateID)); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d", pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter)); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateUp_8188E()\n")); -+ return 0; -+} -+ -+static void odm_ResetRaCounter_8188E(struct odm_ra_info *pRaInfo) -+{ -+ u8 RateID; -+ -+ RateID = pRaInfo->DecisionRate; -+ pRaInfo->NscUp = (N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1; -+ pRaInfo->NscDown = (N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1; -+} -+ -+static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm, -+ struct odm_ra_info *pRaInfo -+ ) -+{ -+ u8 RateID = 0, RtyPtID = 0, PenaltyID1 = 0, PenaltyID2 = 0; -+ /* u32 pool_retry; */ -+ static u8 DynamicTxRPTTimingCounter; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDecision_8188E()\n")); -+ -+ if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) { /* STA used and data packet exits */ -+ if ((pRaInfo->RssiStaRA < (pRaInfo->PreRssiStaRA - 3)) || -+ (pRaInfo->RssiStaRA > (pRaInfo->PreRssiStaRA + 3))) { -+ pRaInfo->RAWaitingCounter = 0; -+ pRaInfo->RAPendingCounter = 0; -+ } -+ /* Start RA decision */ -+ if (pRaInfo->PreRate > pRaInfo->HighestRate) -+ RateID = pRaInfo->HighestRate; -+ else -+ RateID = pRaInfo->PreRate; -+ if (pRaInfo->RssiStaRA > RSSI_THRESHOLD[RateID]) -+ RtyPtID = 0; -+ else -+ RtyPtID = 1; -+ PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; /* TODO by page */ -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ (" NscDown init is %d\n", pRaInfo->NscDown)); -+ pRaInfo->NscDown += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID1][0]; -+ pRaInfo->NscDown += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID1][1]; -+ pRaInfo->NscDown += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID1][2]; -+ pRaInfo->NscDown += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID1][3]; -+ pRaInfo->NscDown += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID1][4]; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ (" NscDown is %d, total*penalty[5] is %d\n", -+ pRaInfo->NscDown, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]))); -+ if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])) -+ pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]; -+ else -+ pRaInfo->NscDown = 0; -+ -+ /* rate up */ -+ PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID]; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ (" NscUp init is %d\n", pRaInfo->NscUp)); -+ pRaInfo->NscUp += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID2][0]; -+ pRaInfo->NscUp += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID2][1]; -+ pRaInfo->NscUp += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID2][2]; -+ pRaInfo->NscUp += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID2][3]; -+ pRaInfo->NscUp += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID2][4]; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ ("NscUp is %d, total*up[5] is %d\n", -+ pRaInfo->NscUp, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]))); -+ if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])) -+ pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]; -+ else -+ pRaInfo->NscUp = 0; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE|ODM_COMP_INIT, ODM_DBG_LOUD, -+ (" RssiStaRa = %d RtyPtID =%d PenaltyID1 = 0x%x PenaltyID2 = 0x%x RateID =%d NscDown =%d NscUp =%d SGI =%d\n", -+ pRaInfo->RssiStaRA, RtyPtID, PenaltyID1, PenaltyID2, RateID, pRaInfo->NscDown, pRaInfo->NscUp, pRaInfo->RateSGI)); -+ if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) || -+ (pRaInfo->DROP > DROPING_NECESSARY[RateID])) -+ odm_RateDown_8188E(dm_odm, pRaInfo); -+ else if (pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID]) -+ odm_RateUp_8188E(dm_odm, pRaInfo); -+ -+ if (pRaInfo->DecisionRate > pRaInfo->HighestRate) -+ pRaInfo->DecisionRate = pRaInfo->HighestRate; -+ -+ if ((pRaInfo->DecisionRate) == (pRaInfo->PreRate)) -+ DynamicTxRPTTimingCounter += 1; -+ else -+ DynamicTxRPTTimingCounter = 0; -+ -+ if (DynamicTxRPTTimingCounter >= 4) { -+ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 1); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, -+ ODM_DBG_LOUD, ("<===== Rate don't change 4 times, Extend RPT Timing\n")); -+ DynamicTxRPTTimingCounter = 0; -+ } -+ -+ pRaInfo->PreRate = pRaInfo->DecisionRate; /* YJ, add, 120120 */ -+ -+ odm_ResetRaCounter_8188E(pRaInfo); -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateDecision_8188E()\n")); -+} -+ -+static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo) -+{ /* Wilson 2011/10/26 */ -+ u32 MaskFromReg; -+ s8 i; -+ -+ switch (pRaInfo->RateID) { -+ case RATR_INX_WIRELESS_NGB: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff015; -+ break; -+ case RATR_INX_WIRELESS_NG: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff010; -+ break; -+ case RATR_INX_WIRELESS_NB: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff005; -+ break; -+ case RATR_INX_WIRELESS_N: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff000; -+ break; -+ case RATR_INX_WIRELESS_GB: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x00000ff5; -+ break; -+ case RATR_INX_WIRELESS_G: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x00000ff0; -+ break; -+ case RATR_INX_WIRELESS_B: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0000000d; -+ break; -+ case 12: -+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR0); -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg; -+ break; -+ case 13: -+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR1); -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg; -+ break; -+ case 14: -+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR2); -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg; -+ break; -+ case 15: -+ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR3); -+ pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg; -+ break; -+ default: -+ pRaInfo->RAUseRate = (pRaInfo->RateMask); -+ break; -+ } -+ /* Highest rate */ -+ if (pRaInfo->RAUseRate) { -+ for (i = RATESIZE; i >= 0; i--) { -+ if ((pRaInfo->RAUseRate)&BIT(i)) { -+ pRaInfo->HighestRate = i; -+ break; -+ } -+ } -+ } else { -+ pRaInfo->HighestRate = 0; -+ } -+ /* Lowest rate */ -+ if (pRaInfo->RAUseRate) { -+ for (i = 0; i < RATESIZE; i++) { -+ if ((pRaInfo->RAUseRate) & BIT(i)) { -+ pRaInfo->LowestRate = i; -+ break; -+ } -+ } -+ } else { -+ pRaInfo->LowestRate = 0; -+ } -+ if (pRaInfo->HighestRate > 0x13) -+ pRaInfo->PTModeSS = 3; -+ else if (pRaInfo->HighestRate > 0x0b) -+ pRaInfo->PTModeSS = 2; -+ else if (pRaInfo->HighestRate > 0x0b) -+ pRaInfo->PTModeSS = 1; -+ else -+ pRaInfo->PTModeSS = 0; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, -+ ("ODM_ARFBRefresh_8188E(): PTModeSS =%d\n", pRaInfo->PTModeSS)); -+ -+ if (pRaInfo->DecisionRate > pRaInfo->HighestRate) -+ pRaInfo->DecisionRate = pRaInfo->HighestRate; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, -+ ("ODM_ARFBRefresh_8188E(): RateID =%d RateMask =%8.8x RAUseRate =%8.8x HighestRate =%d, DecisionRate =%d\n", -+ pRaInfo->RateID, pRaInfo->RateMask, pRaInfo->RAUseRate, pRaInfo->HighestRate, pRaInfo->DecisionRate)); -+ return 0; -+} -+ -+static void odm_PTTryState_8188E(struct odm_ra_info *pRaInfo) -+{ -+ pRaInfo->PTTryState = 0; -+ switch (pRaInfo->PTModeSS) { -+ case 3: -+ if (pRaInfo->DecisionRate >= 0x19) -+ pRaInfo->PTTryState = 1; -+ break; -+ case 2: -+ if (pRaInfo->DecisionRate >= 0x11) -+ pRaInfo->PTTryState = 1; -+ break; -+ case 1: -+ if (pRaInfo->DecisionRate >= 0x0a) -+ pRaInfo->PTTryState = 1; -+ break; -+ case 0: -+ if (pRaInfo->DecisionRate >= 0x03) -+ pRaInfo->PTTryState = 1; -+ break; -+ default: -+ pRaInfo->PTTryState = 0; -+ break; -+ } -+ -+ if (pRaInfo->RssiStaRA < 48) { -+ pRaInfo->PTStage = 0; -+ } else if (pRaInfo->PTTryState == 1) { -+ if ((pRaInfo->PTStopCount >= 10) || -+ (pRaInfo->PTPreRssi > pRaInfo->RssiStaRA + 5) || -+ (pRaInfo->PTPreRssi < pRaInfo->RssiStaRA - 5) || -+ (pRaInfo->DecisionRate != pRaInfo->PTPreRate)) { -+ if (pRaInfo->PTStage == 0) -+ pRaInfo->PTStage = 1; -+ else if (pRaInfo->PTStage == 1) -+ pRaInfo->PTStage = 3; -+ else -+ pRaInfo->PTStage = 5; -+ -+ pRaInfo->PTPreRssi = pRaInfo->RssiStaRA; -+ pRaInfo->PTStopCount = 0; -+ } else { -+ pRaInfo->RAstage = 0; -+ pRaInfo->PTStopCount++; -+ } -+ } else { -+ pRaInfo->PTStage = 0; -+ pRaInfo->RAstage = 0; -+ } -+ pRaInfo->PTPreRate = pRaInfo->DecisionRate; -+} -+ -+static void odm_PTDecision_8188E(struct odm_ra_info *pRaInfo) -+{ -+ u8 j; -+ u8 temp_stage; -+ u32 numsc; -+ u32 num_total; -+ u8 stage_id; -+ -+ numsc = 0; -+ num_total = pRaInfo->TOTAL * PT_PENALTY[5]; -+ for (j = 0; j <= 4; j++) { -+ numsc += pRaInfo->RTY[j] * PT_PENALTY[j]; -+ if (numsc > num_total) -+ break; -+ } -+ -+ j = j >> 1; -+ temp_stage = (pRaInfo->PTStage + 1) >> 1; -+ if (temp_stage > j) -+ stage_id = temp_stage-j; -+ else -+ stage_id = 0; -+ -+ pRaInfo->PTSmoothFactor = (pRaInfo->PTSmoothFactor>>1) + (pRaInfo->PTSmoothFactor>>2) + stage_id*16+2; -+ if (pRaInfo->PTSmoothFactor > 192) -+ pRaInfo->PTSmoothFactor = 192; -+ stage_id = pRaInfo->PTSmoothFactor >> 6; -+ temp_stage = stage_id*2; -+ if (temp_stage != 0) -+ temp_stage -= 1; -+ if (pRaInfo->DROP > 3) -+ temp_stage = 0; -+ pRaInfo->PTStage = temp_stage; -+} -+ -+static void -+odm_RATxRPTTimerSetting( -+ struct odm_dm_struct *dm_odm, -+ u16 minRptTime -+) -+{ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, (" =====>odm_RATxRPTTimerSetting()\n")); -+ -+ if (dm_odm->CurrminRptTime != minRptTime) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, -+ (" CurrminRptTime = 0x%04x minRptTime = 0x%04x\n", dm_odm->CurrminRptTime, minRptTime)); -+ rtw_rpt_timer_cfg_cmd(dm_odm->Adapter, minRptTime); -+ dm_odm->CurrminRptTime = minRptTime; -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, (" <===== odm_RATxRPTTimerSetting()\n")); -+} -+ -+void -+ODM_RASupport_Init( -+ struct odm_dm_struct *dm_odm -+ ) -+{ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RASupport_Init()\n")); -+ -+ /* 2012/02/14 MH Be noticed, the init must be after IC type is recognized!!!!! */ -+ if (dm_odm->SupportICType == ODM_RTL8188E) -+ dm_odm->RaSupport88E = true; -+} -+ -+int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 macid) -+{ -+ struct odm_ra_info *pRaInfo = &dm_odm->RAInfo[macid]; -+ u8 WirelessMode = 0xFF; /* invalid value */ -+ u8 max_rate_idx = 0x13; /* MCS7 */ -+ if (dm_odm->pWirelessMode != NULL) -+ WirelessMode = *(dm_odm->pWirelessMode); -+ -+ if (WirelessMode != 0xFF) { -+ if (WirelessMode & ODM_WM_N24G) -+ max_rate_idx = 0x13; -+ else if (WirelessMode & ODM_WM_G) -+ max_rate_idx = 0x0b; -+ else if (WirelessMode & ODM_WM_B) -+ max_rate_idx = 0x03; -+ } -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, -+ ("ODM_RAInfo_Init(): WirelessMode:0x%08x , max_raid_idx:0x%02x\n", -+ WirelessMode, max_rate_idx)); -+ -+ pRaInfo->DecisionRate = max_rate_idx; -+ pRaInfo->PreRate = max_rate_idx; -+ pRaInfo->HighestRate = max_rate_idx; -+ pRaInfo->LowestRate = 0; -+ pRaInfo->RateID = 0; -+ pRaInfo->RateMask = 0xffffffff; -+ pRaInfo->RssiStaRA = 0; -+ pRaInfo->PreRssiStaRA = 0; -+ pRaInfo->SGIEnable = 0; -+ pRaInfo->RAUseRate = 0xffffffff; -+ pRaInfo->NscDown = (N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2; -+ pRaInfo->NscUp = (N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2; -+ pRaInfo->RateSGI = 0; -+ pRaInfo->Active = 1; /* Active is not used at present. by page, 110819 */ -+ pRaInfo->RptTime = 0x927c; -+ pRaInfo->DROP = 0; -+ pRaInfo->RTY[0] = 0; -+ pRaInfo->RTY[1] = 0; -+ pRaInfo->RTY[2] = 0; -+ pRaInfo->RTY[3] = 0; -+ pRaInfo->RTY[4] = 0; -+ pRaInfo->TOTAL = 0; -+ pRaInfo->RAWaitingCounter = 0; -+ pRaInfo->RAPendingCounter = 0; -+ pRaInfo->PTActive = 1; /* Active when this STA is use */ -+ pRaInfo->PTTryState = 0; -+ pRaInfo->PTStage = 5; /* Need to fill into HW_PWR_STATUS */ -+ pRaInfo->PTSmoothFactor = 192; -+ pRaInfo->PTStopCount = 0; -+ pRaInfo->PTPreRate = 0; -+ pRaInfo->PTPreRssi = 0; -+ pRaInfo->PTModeSS = 0; -+ pRaInfo->RAstage = 0; -+ return 0; -+} -+ -+int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm) -+{ -+ u8 macid = 0; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>\n")); -+ dm_odm->CurrminRptTime = 0; -+ -+ for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++) -+ ODM_RAInfo_Init(dm_odm, macid); -+ -+ return 0; -+} -+ -+u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 macid) -+{ -+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) -+ return 0; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ ("macid =%d SGI =%d\n", macid, dm_odm->RAInfo[macid].RateSGI)); -+ return dm_odm->RAInfo[macid].RateSGI; -+} -+ -+u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 macid) -+{ -+ u8 DecisionRate = 0; -+ -+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) -+ return 0; -+ DecisionRate = (dm_odm->RAInfo[macid].DecisionRate); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ (" macid =%d DecisionRate = 0x%x\n", macid, DecisionRate)); -+ return DecisionRate; -+} -+ -+u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 macid) -+{ -+ u8 PTStage = 5; -+ -+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) -+ return 0; -+ PTStage = (dm_odm->RAInfo[macid].PTStage); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ ("macid =%d PTStage = 0x%x\n", macid, PTStage)); -+ return PTStage; -+} -+ -+void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 RateID, u32 RateMask, u8 SGIEnable) -+{ -+ struct odm_ra_info *pRaInfo = NULL; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, -+ ("macid =%d RateID = 0x%x RateMask = 0x%x SGIEnable =%d\n", -+ macid, RateID, RateMask, SGIEnable)); -+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) -+ return; -+ -+ pRaInfo = &(dm_odm->RAInfo[macid]); -+ pRaInfo->RateID = RateID; -+ pRaInfo->RateMask = RateMask; -+ pRaInfo->SGIEnable = SGIEnable; -+ odm_ARFBRefresh_8188E(dm_odm, pRaInfo); -+} -+ -+void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 Rssi) -+{ -+ struct odm_ra_info *pRaInfo = NULL; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, -+ (" macid =%d Rssi =%d\n", macid, Rssi)); -+ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) -+ return; -+ -+ pRaInfo = &(dm_odm->RAInfo[macid]); -+ pRaInfo->RssiStaRA = Rssi; -+} -+ -+void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime) -+{ -+ ODM_Write2Byte(dm_odm, REG_TX_RPT_TIME, minRptTime); -+} -+ -+void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16 TxRPT_Len, u32 macid_entry0, u32 macid_entry1) -+{ -+ struct odm_ra_info *pRAInfo = NULL; -+ u8 MacId = 0; -+ u8 *pBuffer = NULL; -+ u32 valid = 0, ItemNum = 0; -+ u16 minRptTime = 0x927c; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, -+ ("=====>ODM_RA_TxRPT2Handle_8188E(): valid0 =%d valid1 =%d BufferLength =%d\n", -+ macid_entry0, macid_entry1, TxRPT_Len)); -+ -+ ItemNum = TxRPT_Len >> 3; -+ pBuffer = TxRPT_Buf; -+ -+ do { -+ if (MacId >= ASSOCIATE_ENTRY_NUM) -+ valid = 0; -+ else if (MacId >= 32) -+ valid = (1 << (MacId - 32)) & macid_entry1; -+ else -+ valid = (1 << MacId) & macid_entry0; -+ -+ pRAInfo = &(dm_odm->RAInfo[MacId]); -+ if (valid) { -+ pRAInfo->RTY[0] = (u16)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer); -+ pRAInfo->RTY[1] = (u16)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer); -+ pRAInfo->RTY[2] = (u16)GET_TX_REPORT_TYPE1_RERTY_2(pBuffer); -+ pRAInfo->RTY[3] = (u16)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer); -+ pRAInfo->RTY[4] = (u16)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer); -+ pRAInfo->DROP = (u16)GET_TX_REPORT_TYPE1_DROP_0(pBuffer); -+ pRAInfo->TOTAL = pRAInfo->RTY[0] + pRAInfo->RTY[1] + -+ pRAInfo->RTY[2] + pRAInfo->RTY[3] + -+ pRAInfo->RTY[4] + pRAInfo->DROP; -+ if (pRAInfo->TOTAL != 0) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, -+ ("macid =%d Total =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d D0 =%d valid0 =%x valid1 =%x\n", -+ MacId, pRAInfo->TOTAL, -+ pRAInfo->RTY[0], pRAInfo->RTY[1], -+ pRAInfo->RTY[2], pRAInfo->RTY[3], -+ pRAInfo->RTY[4], pRAInfo->DROP, -+ macid_entry0 , macid_entry1)); -+ if (pRAInfo->PTActive) { -+ if (pRAInfo->RAstage < 5) -+ odm_RateDecision_8188E(dm_odm, pRAInfo); -+ else if (pRAInfo->RAstage == 5) /* Power training try state */ -+ odm_PTTryState_8188E(pRAInfo); -+ else /* RAstage == 6 */ -+ odm_PTDecision_8188E(pRAInfo); -+ -+ /* Stage_RA counter */ -+ if (pRAInfo->RAstage <= 5) -+ pRAInfo->RAstage++; -+ else -+ pRAInfo->RAstage = 0; -+ } else { -+ odm_RateDecision_8188E(dm_odm, pRAInfo); -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, -+ ("macid =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d drop =%d valid0 =%x RateID =%d SGI =%d\n", -+ MacId, -+ pRAInfo->RTY[0], -+ pRAInfo->RTY[1], -+ pRAInfo->RTY[2], -+ pRAInfo->RTY[3], -+ pRAInfo->RTY[4], -+ pRAInfo->DROP, -+ macid_entry0, -+ pRAInfo->DecisionRate, -+ pRAInfo->RateSGI)); -+ } else { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, (" TOTAL = 0!!!!\n")); -+ } -+ } -+ -+ if (minRptTime > pRAInfo->RptTime) -+ minRptTime = pRAInfo->RptTime; -+ -+ pBuffer += TX_RPT2_ITEM_SIZE; -+ MacId++; -+ } while (MacId < ItemNum); -+ -+ odm_RATxRPTTimerSetting(dm_odm, minRptTime); -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<===== ODM_RA_TxRPT2Handle_8188E()\n")); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_BB.c b/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_BB.c -new file mode 100644 -index 0000000000000..f06c14cd4e046 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_BB.c -@@ -0,0 +1,720 @@ -+/****************************************************************************** -+* -+* Copyright(c) 2007 - 2011 Realtek 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 -+* -+* -+******************************************************************************/ -+ -+#include "odm_precomp.h" -+ -+#include -+ -+#define read_next_pair(array, v1, v2, i) \ -+ do { \ -+ i += 2; \ -+ v1 = array[i]; \ -+ v2 = array[i+1]; \ -+ } while (0) -+ -+static bool CheckCondition(const u32 condition, const u32 hex) -+{ -+ u32 _board = (hex & 0x000000FF); -+ u32 _interface = (hex & 0x0000FF00) >> 8; -+ u32 _platform = (hex & 0x00FF0000) >> 16; -+ u32 cond = condition; -+ -+ if (condition == 0xCDCDCDCD) -+ return true; -+ -+ cond = condition & 0x000000FF; -+ if ((_board == cond) && cond != 0x00) -+ return false; -+ -+ cond = condition & 0x0000FF00; -+ cond = cond >> 8; -+ if ((_interface & cond) == 0 && cond != 0x07) -+ return false; -+ -+ cond = condition & 0x00FF0000; -+ cond = cond >> 16; -+ if ((_platform & cond) == 0 && cond != 0x0F) -+ return false; -+ return true; -+} -+ -+/****************************************************************************** -+* AGC_TAB_1T.TXT -+******************************************************************************/ -+ -+static u32 array_agc_tab_1t_8188e[] = { -+ 0xC78, 0xFB000001, -+ 0xC78, 0xFB010001, -+ 0xC78, 0xFB020001, -+ 0xC78, 0xFB030001, -+ 0xC78, 0xFB040001, -+ 0xC78, 0xFB050001, -+ 0xC78, 0xFA060001, -+ 0xC78, 0xF9070001, -+ 0xC78, 0xF8080001, -+ 0xC78, 0xF7090001, -+ 0xC78, 0xF60A0001, -+ 0xC78, 0xF50B0001, -+ 0xC78, 0xF40C0001, -+ 0xC78, 0xF30D0001, -+ 0xC78, 0xF20E0001, -+ 0xC78, 0xF10F0001, -+ 0xC78, 0xF0100001, -+ 0xC78, 0xEF110001, -+ 0xC78, 0xEE120001, -+ 0xC78, 0xED130001, -+ 0xC78, 0xEC140001, -+ 0xC78, 0xEB150001, -+ 0xC78, 0xEA160001, -+ 0xC78, 0xE9170001, -+ 0xC78, 0xE8180001, -+ 0xC78, 0xE7190001, -+ 0xC78, 0xE61A0001, -+ 0xC78, 0xE51B0001, -+ 0xC78, 0xE41C0001, -+ 0xC78, 0xE31D0001, -+ 0xC78, 0xE21E0001, -+ 0xC78, 0xE11F0001, -+ 0xC78, 0x8A200001, -+ 0xC78, 0x89210001, -+ 0xC78, 0x88220001, -+ 0xC78, 0x87230001, -+ 0xC78, 0x86240001, -+ 0xC78, 0x85250001, -+ 0xC78, 0x84260001, -+ 0xC78, 0x83270001, -+ 0xC78, 0x82280001, -+ 0xC78, 0x6B290001, -+ 0xC78, 0x6A2A0001, -+ 0xC78, 0x692B0001, -+ 0xC78, 0x682C0001, -+ 0xC78, 0x672D0001, -+ 0xC78, 0x662E0001, -+ 0xC78, 0x652F0001, -+ 0xC78, 0x64300001, -+ 0xC78, 0x63310001, -+ 0xC78, 0x62320001, -+ 0xC78, 0x61330001, -+ 0xC78, 0x46340001, -+ 0xC78, 0x45350001, -+ 0xC78, 0x44360001, -+ 0xC78, 0x43370001, -+ 0xC78, 0x42380001, -+ 0xC78, 0x41390001, -+ 0xC78, 0x403A0001, -+ 0xC78, 0x403B0001, -+ 0xC78, 0x403C0001, -+ 0xC78, 0x403D0001, -+ 0xC78, 0x403E0001, -+ 0xC78, 0x403F0001, -+ 0xC78, 0xFB400001, -+ 0xC78, 0xFB410001, -+ 0xC78, 0xFB420001, -+ 0xC78, 0xFB430001, -+ 0xC78, 0xFB440001, -+ 0xC78, 0xFB450001, -+ 0xC78, 0xFB460001, -+ 0xC78, 0xFB470001, -+ 0xC78, 0xFB480001, -+ 0xC78, 0xFA490001, -+ 0xC78, 0xF94A0001, -+ 0xC78, 0xF84B0001, -+ 0xC78, 0xF74C0001, -+ 0xC78, 0xF64D0001, -+ 0xC78, 0xF54E0001, -+ 0xC78, 0xF44F0001, -+ 0xC78, 0xF3500001, -+ 0xC78, 0xF2510001, -+ 0xC78, 0xF1520001, -+ 0xC78, 0xF0530001, -+ 0xC78, 0xEF540001, -+ 0xC78, 0xEE550001, -+ 0xC78, 0xED560001, -+ 0xC78, 0xEC570001, -+ 0xC78, 0xEB580001, -+ 0xC78, 0xEA590001, -+ 0xC78, 0xE95A0001, -+ 0xC78, 0xE85B0001, -+ 0xC78, 0xE75C0001, -+ 0xC78, 0xE65D0001, -+ 0xC78, 0xE55E0001, -+ 0xC78, 0xE45F0001, -+ 0xC78, 0xE3600001, -+ 0xC78, 0xE2610001, -+ 0xC78, 0xC3620001, -+ 0xC78, 0xC2630001, -+ 0xC78, 0xC1640001, -+ 0xC78, 0x8B650001, -+ 0xC78, 0x8A660001, -+ 0xC78, 0x89670001, -+ 0xC78, 0x88680001, -+ 0xC78, 0x87690001, -+ 0xC78, 0x866A0001, -+ 0xC78, 0x856B0001, -+ 0xC78, 0x846C0001, -+ 0xC78, 0x676D0001, -+ 0xC78, 0x666E0001, -+ 0xC78, 0x656F0001, -+ 0xC78, 0x64700001, -+ 0xC78, 0x63710001, -+ 0xC78, 0x62720001, -+ 0xC78, 0x61730001, -+ 0xC78, 0x60740001, -+ 0xC78, 0x46750001, -+ 0xC78, 0x45760001, -+ 0xC78, 0x44770001, -+ 0xC78, 0x43780001, -+ 0xC78, 0x42790001, -+ 0xC78, 0x417A0001, -+ 0xC78, 0x407B0001, -+ 0xC78, 0x407C0001, -+ 0xC78, 0x407D0001, -+ 0xC78, 0x407E0001, -+ 0xC78, 0x407F0001, -+}; -+ -+enum HAL_STATUS ODM_ReadAndConfig_AGC_TAB_1T_8188E(struct odm_dm_struct *dm_odm) -+{ -+ u32 hex = 0; -+ u32 i = 0; -+ u8 platform = dm_odm->SupportPlatform; -+ u8 interfaceValue = dm_odm->SupportInterface; -+ u8 board = dm_odm->BoardType; -+ u32 arraylen = sizeof(array_agc_tab_1t_8188e)/sizeof(u32); -+ u32 *array = array_agc_tab_1t_8188e; -+ bool biol = false; -+ struct adapter *adapter = dm_odm->Adapter; -+ struct xmit_frame *pxmit_frame = NULL; -+ u8 bndy_cnt = 1; -+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; -+ -+ hex += board; -+ hex += interfaceValue << 8; -+ hex += platform << 16; -+ hex += 0xFF000000; -+ biol = rtw_IOL_applied(adapter); -+ -+ if (biol) { -+ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter); -+ if (pxmit_frame == NULL) { -+ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); -+ return HAL_STATUS_FAILURE; -+ } -+ } -+ -+ for (i = 0; i < arraylen; i += 2) { -+ u32 v1 = array[i]; -+ u32 v2 = array[i+1]; -+ -+ /* This (offset, data) pair meets the condition. */ -+ if (v1 < 0xCDCDCDCD) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); -+ } else { -+ odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2); -+ } -+ continue; -+ } else { -+ /* This line is the start line of branch. */ -+ if (!CheckCondition(array[i], hex)) { -+ /* Discard the following (offset, data) pairs. */ -+ read_next_pair(array, v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < arraylen - 2) -+ read_next_pair(array, v1, v2, i); -+ i -= 2; /* prevent from for-loop += 2 */ -+ } else { /* Configure matched pairs and skip to end of if-else. */ -+ read_next_pair(array, v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < arraylen - 2) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); -+ } else { -+ odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2); -+ } -+ read_next_pair(array, v1, v2, i); -+ } -+ -+ while (v2 != 0xDEAD && i < arraylen - 2) -+ read_next_pair(array, v1, v2, i); -+ } -+ } -+ } -+ if (biol) { -+ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { -+ printk("~~~ %s IOL_exec_cmds Failed !!!\n", __func__); -+ rst = HAL_STATUS_FAILURE; -+ } -+ } -+ return rst; -+} -+ -+/****************************************************************************** -+* PHY_REG_1T.TXT -+******************************************************************************/ -+ -+static u32 array_phy_reg_1t_8188e[] = { -+ 0x800, 0x80040000, -+ 0x804, 0x00000003, -+ 0x808, 0x0000FC00, -+ 0x80C, 0x0000000A, -+ 0x810, 0x10001331, -+ 0x814, 0x020C3D10, -+ 0x818, 0x02200385, -+ 0x81C, 0x00000000, -+ 0x820, 0x01000100, -+ 0x824, 0x00390204, -+ 0x828, 0x00000000, -+ 0x82C, 0x00000000, -+ 0x830, 0x00000000, -+ 0x834, 0x00000000, -+ 0x838, 0x00000000, -+ 0x83C, 0x00000000, -+ 0x840, 0x00010000, -+ 0x844, 0x00000000, -+ 0x848, 0x00000000, -+ 0x84C, 0x00000000, -+ 0x850, 0x00000000, -+ 0x854, 0x00000000, -+ 0x858, 0x569A11A9, -+ 0x85C, 0x01000014, -+ 0x860, 0x66F60110, -+ 0x864, 0x061F0649, -+ 0x868, 0x00000000, -+ 0x86C, 0x27272700, -+ 0x870, 0x07000760, -+ 0x874, 0x25004000, -+ 0x878, 0x00000808, -+ 0x87C, 0x00000000, -+ 0x880, 0xB0000C1C, -+ 0x884, 0x00000001, -+ 0x888, 0x00000000, -+ 0x88C, 0xCCC000C0, -+ 0x890, 0x00000800, -+ 0x894, 0xFFFFFFFE, -+ 0x898, 0x40302010, -+ 0x89C, 0x00706050, -+ 0x900, 0x00000000, -+ 0x904, 0x00000023, -+ 0x908, 0x00000000, -+ 0x90C, 0x81121111, -+ 0x910, 0x00000002, -+ 0x914, 0x00000201, -+ 0xA00, 0x00D047C8, -+ 0xA04, 0x80FF000C, -+ 0xA08, 0x8C838300, -+ 0xA0C, 0x2E7F120F, -+ 0xA10, 0x9500BB78, -+ 0xA14, 0x1114D028, -+ 0xA18, 0x00881117, -+ 0xA1C, 0x89140F00, -+ 0xA20, 0x1A1B0000, -+ 0xA24, 0x090E1317, -+ 0xA28, 0x00000204, -+ 0xA2C, 0x00D30000, -+ 0xA70, 0x101FBF00, -+ 0xA74, 0x00000007, -+ 0xA78, 0x00000900, -+ 0xA7C, 0x225B0606, -+ 0xA80, 0x218075B1, -+ 0xB2C, 0x80000000, -+ 0xC00, 0x48071D40, -+ 0xC04, 0x03A05611, -+ 0xC08, 0x000000E4, -+ 0xC0C, 0x6C6C6C6C, -+ 0xC10, 0x08800000, -+ 0xC14, 0x40000100, -+ 0xC18, 0x08800000, -+ 0xC1C, 0x40000100, -+ 0xC20, 0x00000000, -+ 0xC24, 0x00000000, -+ 0xC28, 0x00000000, -+ 0xC2C, 0x00000000, -+ 0xC30, 0x69E9AC47, -+ 0xC34, 0x469652AF, -+ 0xC38, 0x49795994, -+ 0xC3C, 0x0A97971C, -+ 0xC40, 0x1F7C403F, -+ 0xC44, 0x000100B7, -+ 0xC48, 0xEC020107, -+ 0xC4C, 0x007F037F, -+ 0xC50, 0x69553420, -+ 0xC54, 0x43BC0094, -+ 0xC58, 0x00013169, -+ 0xC5C, 0x00250492, -+ 0xC60, 0x00000000, -+ 0xC64, 0x7112848B, -+ 0xC68, 0x47C00BFF, -+ 0xC6C, 0x00000036, -+ 0xC70, 0x2C7F000D, -+ 0xC74, 0x020610DB, -+ 0xC78, 0x0000001F, -+ 0xC7C, 0x00B91612, -+ 0xC80, 0x390000E4, -+ 0xC84, 0x20F60000, -+ 0xC88, 0x40000100, -+ 0xC8C, 0x20200000, -+ 0xC90, 0x00091521, -+ 0xC94, 0x00000000, -+ 0xC98, 0x00121820, -+ 0xC9C, 0x00007F7F, -+ 0xCA0, 0x00000000, -+ 0xCA4, 0x000300A0, -+ 0xCA8, 0x00000000, -+ 0xCAC, 0x00000000, -+ 0xCB0, 0x00000000, -+ 0xCB4, 0x00000000, -+ 0xCB8, 0x00000000, -+ 0xCBC, 0x28000000, -+ 0xCC0, 0x00000000, -+ 0xCC4, 0x00000000, -+ 0xCC8, 0x00000000, -+ 0xCCC, 0x00000000, -+ 0xCD0, 0x00000000, -+ 0xCD4, 0x00000000, -+ 0xCD8, 0x64B22427, -+ 0xCDC, 0x00766932, -+ 0xCE0, 0x00222222, -+ 0xCE4, 0x00000000, -+ 0xCE8, 0x37644302, -+ 0xCEC, 0x2F97D40C, -+ 0xD00, 0x00000740, -+ 0xD04, 0x00020401, -+ 0xD08, 0x0000907F, -+ 0xD0C, 0x20010201, -+ 0xD10, 0xA0633333, -+ 0xD14, 0x3333BC43, -+ 0xD18, 0x7A8F5B6F, -+ 0xD2C, 0xCC979975, -+ 0xD30, 0x00000000, -+ 0xD34, 0x80608000, -+ 0xD38, 0x00000000, -+ 0xD3C, 0x00127353, -+ 0xD40, 0x00000000, -+ 0xD44, 0x00000000, -+ 0xD48, 0x00000000, -+ 0xD4C, 0x00000000, -+ 0xD50, 0x6437140A, -+ 0xD54, 0x00000000, -+ 0xD58, 0x00000282, -+ 0xD5C, 0x30032064, -+ 0xD60, 0x4653DE68, -+ 0xD64, 0x04518A3C, -+ 0xD68, 0x00002101, -+ 0xD6C, 0x2A201C16, -+ 0xD70, 0x1812362E, -+ 0xD74, 0x322C2220, -+ 0xD78, 0x000E3C24, -+ 0xE00, 0x2D2D2D2D, -+ 0xE04, 0x2D2D2D2D, -+ 0xE08, 0x0390272D, -+ 0xE10, 0x2D2D2D2D, -+ 0xE14, 0x2D2D2D2D, -+ 0xE18, 0x2D2D2D2D, -+ 0xE1C, 0x2D2D2D2D, -+ 0xE28, 0x00000000, -+ 0xE30, 0x1000DC1F, -+ 0xE34, 0x10008C1F, -+ 0xE38, 0x02140102, -+ 0xE3C, 0x681604C2, -+ 0xE40, 0x01007C00, -+ 0xE44, 0x01004800, -+ 0xE48, 0xFB000000, -+ 0xE4C, 0x000028D1, -+ 0xE50, 0x1000DC1F, -+ 0xE54, 0x10008C1F, -+ 0xE58, 0x02140102, -+ 0xE5C, 0x28160D05, -+ 0xE60, 0x00000008, -+ 0xE68, 0x001B25A4, -+ 0xE6C, 0x00C00014, -+ 0xE70, 0x00C00014, -+ 0xE74, 0x01000014, -+ 0xE78, 0x01000014, -+ 0xE7C, 0x01000014, -+ 0xE80, 0x01000014, -+ 0xE84, 0x00C00014, -+ 0xE88, 0x01000014, -+ 0xE8C, 0x00C00014, -+ 0xED0, 0x00C00014, -+ 0xED4, 0x00C00014, -+ 0xED8, 0x00C00014, -+ 0xEDC, 0x00000014, -+ 0xEE0, 0x00000014, -+ 0xEEC, 0x01C00014, -+ 0xF14, 0x00000003, -+ 0xF4C, 0x00000000, -+ 0xF00, 0x00000300, -+}; -+ -+enum HAL_STATUS ODM_ReadAndConfig_PHY_REG_1T_8188E(struct odm_dm_struct *dm_odm) -+{ -+ u32 hex = 0; -+ u32 i = 0; -+ u8 platform = dm_odm->SupportPlatform; -+ u8 interfaceValue = dm_odm->SupportInterface; -+ u8 board = dm_odm->BoardType; -+ u32 arraylen = sizeof(array_phy_reg_1t_8188e)/sizeof(u32); -+ u32 *array = array_phy_reg_1t_8188e; -+ bool biol = false; -+ struct adapter *adapter = dm_odm->Adapter; -+ struct xmit_frame *pxmit_frame = NULL; -+ u8 bndy_cnt = 1; -+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; -+ hex += board; -+ hex += interfaceValue << 8; -+ hex += platform << 16; -+ hex += 0xFF000000; -+ biol = rtw_IOL_applied(adapter); -+ -+ if (biol) { -+ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter); -+ if (pxmit_frame == NULL) { -+ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); -+ return HAL_STATUS_FAILURE; -+ } -+ } -+ -+ for (i = 0; i < arraylen; i += 2) { -+ u32 v1 = array[i]; -+ u32 v2 = array[i+1]; -+ -+ /* This (offset, data) pair meets the condition. */ -+ if (v1 < 0xCDCDCDCD) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ if (v1 == 0xfe) { -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); -+ } else if (v1 == 0xfd) { -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); -+ } else if (v1 == 0xfc) { -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); -+ } else if (v1 == 0xfb) { -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); -+ } else if (v1 == 0xfa) { -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); -+ } else if (v1 == 0xf9) { -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); -+ } else { -+ if (v1 == 0xa24) -+ dm_odm->RFCalibrateInfo.RegA24 = v2; -+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); -+ } -+ } else { -+ odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2); -+ } -+ continue; -+ } else { /* This line is the start line of branch. */ -+ if (!CheckCondition(array[i], hex)) { -+ /* Discard the following (offset, data) pairs. */ -+ read_next_pair(array, v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < arraylen - 2) -+ read_next_pair(array, v1, v2, i); -+ i -= 2; /* prevent from for-loop += 2 */ -+ } else { /* Configure matched pairs and skip to end of if-else. */ -+ read_next_pair(array, v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < arraylen - 2) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ if (v1 == 0xfe) { -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); -+ } else if (v1 == 0xfd) { -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); -+ } else if (v1 == 0xfc) { -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); -+ } else if (v1 == 0xfb) { -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); -+ } else if (v1 == 0xfa) { -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); -+ } else if (v1 == 0xf9) { -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); -+ } else{ -+ if (v1 == 0xa24) -+ dm_odm->RFCalibrateInfo.RegA24 = v2; -+ -+ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); -+ } -+ } else { -+ odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2); -+ } -+ read_next_pair(array, v1, v2, i); -+ } -+ -+ while (v2 != 0xDEAD && i < arraylen - 2) -+ read_next_pair(array, v1, v2, i); -+ } -+ } -+ } -+ if (biol) { -+ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { -+ rst = HAL_STATUS_FAILURE; -+ pr_info("~~~ IOL Config %s Failed !!!\n", __func__); -+ } -+ } -+ return rst; -+} -+ -+/****************************************************************************** -+* PHY_REG_PG.TXT -+******************************************************************************/ -+ -+static u32 array_phy_reg_pg_8188e[] = { -+ 0xE00, 0xFFFFFFFF, 0x06070809, -+ 0xE04, 0xFFFFFFFF, 0x02020405, -+ 0xE08, 0x0000FF00, 0x00000006, -+ 0x86C, 0xFFFFFF00, 0x00020400, -+ 0xE10, 0xFFFFFFFF, 0x08090A0B, -+ 0xE14, 0xFFFFFFFF, 0x01030607, -+ 0xE18, 0xFFFFFFFF, 0x08090A0B, -+ 0xE1C, 0xFFFFFFFF, 0x01030607, -+ 0xE00, 0xFFFFFFFF, 0x00000000, -+ 0xE04, 0xFFFFFFFF, 0x00000000, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x00000000, -+ 0xE14, 0xFFFFFFFF, 0x00000000, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x02020202, -+ 0xE04, 0xFFFFFFFF, 0x00020202, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x04040404, -+ 0xE14, 0xFFFFFFFF, 0x00020404, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x02020202, -+ 0xE04, 0xFFFFFFFF, 0x00020202, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x04040404, -+ 0xE14, 0xFFFFFFFF, 0x00020404, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x00000000, -+ 0xE04, 0xFFFFFFFF, 0x00000000, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x00000000, -+ 0xE14, 0xFFFFFFFF, 0x00000000, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x02020202, -+ 0xE04, 0xFFFFFFFF, 0x00020202, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x04040404, -+ 0xE14, 0xFFFFFFFF, 0x00020404, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x00000000, -+ 0xE04, 0xFFFFFFFF, 0x00000000, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x00000000, -+ 0xE14, 0xFFFFFFFF, 0x00000000, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x00000000, -+ 0xE04, 0xFFFFFFFF, 0x00000000, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x00000000, -+ 0xE14, 0xFFFFFFFF, 0x00000000, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x00000000, -+ 0xE04, 0xFFFFFFFF, 0x00000000, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x00000000, -+ 0xE14, 0xFFFFFFFF, 0x00000000, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x00000000, -+ 0xE04, 0xFFFFFFFF, 0x00000000, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x00000000, -+ 0xE14, 0xFFFFFFFF, 0x00000000, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ 0xE00, 0xFFFFFFFF, 0x00000000, -+ 0xE04, 0xFFFFFFFF, 0x00000000, -+ 0xE08, 0x0000FF00, 0x00000000, -+ 0x86C, 0xFFFFFF00, 0x00000000, -+ 0xE10, 0xFFFFFFFF, 0x00000000, -+ 0xE14, 0xFFFFFFFF, 0x00000000, -+ 0xE18, 0xFFFFFFFF, 0x00000000, -+ 0xE1C, 0xFFFFFFFF, 0x00000000, -+ -+}; -+ -+void ODM_ReadAndConfig_PHY_REG_PG_8188E(struct odm_dm_struct *dm_odm) -+{ -+ u32 hex; -+ u32 i = 0; -+ u8 platform = dm_odm->SupportPlatform; -+ u8 interfaceValue = dm_odm->SupportInterface; -+ u8 board = dm_odm->BoardType; -+ u32 arraylen = sizeof(array_phy_reg_pg_8188e) / sizeof(u32); -+ u32 *array = array_phy_reg_pg_8188e; -+ -+ hex = board + (interfaceValue << 8); -+ hex += (platform << 16) + 0xFF000000; -+ -+ for (i = 0; i < arraylen; i += 3) { -+ u32 v1 = array[i]; -+ u32 v2 = array[i+1]; -+ u32 v3 = array[i+2]; -+ -+ /* this line is a line of pure_body */ -+ if (v1 < 0xCDCDCDCD) { -+ odm_ConfigBB_PHY_REG_PG_8188E(dm_odm, v1, v2, v3); -+ continue; -+ } else { /* this line is the start of branch */ -+ if (!CheckCondition(array[i], hex)) { -+ /* don't need the hw_body */ -+ i += 2; /* skip the pair of expression */ -+ v1 = array[i]; -+ v2 = array[i+1]; -+ v3 = array[i+2]; -+ while (v2 != 0xDEAD) { -+ i += 3; -+ v1 = array[i]; -+ v2 = array[i+1]; -+ v3 = array[i+1]; -+ } -+ } -+ } -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_MAC.c b/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_MAC.c -new file mode 100644 -index 0000000000000..bac0238e314cc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_MAC.c -@@ -0,0 +1,230 @@ -+/****************************************************************************** -+* -+* Copyright(c) 2007 - 2011 Realtek 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 -+* -+* -+******************************************************************************/ -+ -+#include "odm_precomp.h" -+#include -+ -+static bool Checkcondition(const u32 condition, const u32 hex) -+{ -+ u32 _board = (hex & 0x000000FF); -+ u32 _interface = (hex & 0x0000FF00) >> 8; -+ u32 _platform = (hex & 0x00FF0000) >> 16; -+ u32 cond = condition; -+ -+ if (condition == 0xCDCDCDCD) -+ return true; -+ -+ cond = condition & 0x000000FF; -+ if ((_board == cond) && cond != 0x00) -+ return false; -+ -+ cond = condition & 0x0000FF00; -+ cond = cond >> 8; -+ if ((_interface & cond) == 0 && cond != 0x07) -+ return false; -+ -+ cond = condition & 0x00FF0000; -+ cond = cond >> 16; -+ if ((_platform & cond) == 0 && cond != 0x0F) -+ return false; -+ return true; -+} -+ -+/****************************************************************************** -+* MAC_REG.TXT -+******************************************************************************/ -+ -+static u32 array_MAC_REG_8188E[] = { -+ 0x026, 0x00000041, -+ 0x027, 0x00000035, -+ 0x428, 0x0000000A, -+ 0x429, 0x00000010, -+ 0x430, 0x00000000, -+ 0x431, 0x00000001, -+ 0x432, 0x00000002, -+ 0x433, 0x00000004, -+ 0x434, 0x00000005, -+ 0x435, 0x00000006, -+ 0x436, 0x00000007, -+ 0x437, 0x00000008, -+ 0x438, 0x00000000, -+ 0x439, 0x00000000, -+ 0x43A, 0x00000001, -+ 0x43B, 0x00000002, -+ 0x43C, 0x00000004, -+ 0x43D, 0x00000005, -+ 0x43E, 0x00000006, -+ 0x43F, 0x00000007, -+ 0x440, 0x0000005D, -+ 0x441, 0x00000001, -+ 0x442, 0x00000000, -+ 0x444, 0x00000015, -+ 0x445, 0x000000F0, -+ 0x446, 0x0000000F, -+ 0x447, 0x00000000, -+ 0x458, 0x00000041, -+ 0x459, 0x000000A8, -+ 0x45A, 0x00000072, -+ 0x45B, 0x000000B9, -+ 0x460, 0x00000066, -+ 0x461, 0x00000066, -+ 0x480, 0x00000008, -+ 0x4C8, 0x000000FF, -+ 0x4C9, 0x00000008, -+ 0x4CC, 0x000000FF, -+ 0x4CD, 0x000000FF, -+ 0x4CE, 0x00000001, -+ 0x4D3, 0x00000001, -+ 0x500, 0x00000026, -+ 0x501, 0x000000A2, -+ 0x502, 0x0000002F, -+ 0x503, 0x00000000, -+ 0x504, 0x00000028, -+ 0x505, 0x000000A3, -+ 0x506, 0x0000005E, -+ 0x507, 0x00000000, -+ 0x508, 0x0000002B, -+ 0x509, 0x000000A4, -+ 0x50A, 0x0000005E, -+ 0x50B, 0x00000000, -+ 0x50C, 0x0000004F, -+ 0x50D, 0x000000A4, -+ 0x50E, 0x00000000, -+ 0x50F, 0x00000000, -+ 0x512, 0x0000001C, -+ 0x514, 0x0000000A, -+ 0x516, 0x0000000A, -+ 0x525, 0x0000004F, -+ 0x550, 0x00000010, -+ 0x551, 0x00000010, -+ 0x559, 0x00000002, -+ 0x55D, 0x000000FF, -+ 0x605, 0x00000030, -+ 0x608, 0x0000000E, -+ 0x609, 0x0000002A, -+ 0x620, 0x000000FF, -+ 0x621, 0x000000FF, -+ 0x622, 0x000000FF, -+ 0x623, 0x000000FF, -+ 0x624, 0x000000FF, -+ 0x625, 0x000000FF, -+ 0x626, 0x000000FF, -+ 0x627, 0x000000FF, -+ 0x652, 0x00000020, -+ 0x63C, 0x0000000A, -+ 0x63D, 0x0000000A, -+ 0x63E, 0x0000000E, -+ 0x63F, 0x0000000E, -+ 0x640, 0x00000040, -+ 0x66E, 0x00000005, -+ 0x700, 0x00000021, -+ 0x701, 0x00000043, -+ 0x702, 0x00000065, -+ 0x703, 0x00000087, -+ 0x708, 0x00000021, -+ 0x709, 0x00000043, -+ 0x70A, 0x00000065, -+ 0x70B, 0x00000087, -+}; -+ -+enum HAL_STATUS ODM_ReadAndConfig_MAC_REG_8188E(struct odm_dm_struct *dm_odm) -+{ -+ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = array[i]; v2 = array[i+1]; } while (0) -+ -+ u32 hex = 0; -+ u32 i; -+ u8 platform = dm_odm->SupportPlatform; -+ u8 interface_val = dm_odm->SupportInterface; -+ u8 board = dm_odm->BoardType; -+ u32 array_len = sizeof(array_MAC_REG_8188E)/sizeof(u32); -+ u32 *array = array_MAC_REG_8188E; -+ bool biol = false; -+ -+ struct adapter *adapt = dm_odm->Adapter; -+ struct xmit_frame *pxmit_frame = NULL; -+ u8 bndy_cnt = 1; -+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; -+ hex += board; -+ hex += interface_val << 8; -+ hex += platform << 16; -+ hex += 0xFF000000; -+ -+ biol = rtw_IOL_applied(adapt); -+ -+ if (biol) { -+ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapt); -+ if (pxmit_frame == NULL) { -+ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); -+ return HAL_STATUS_FAILURE; -+ } -+ } -+ -+ for (i = 0; i < array_len; i += 2) { -+ u32 v1 = array[i]; -+ u32 v2 = array[i+1]; -+ -+ /* This (offset, data) pair meets the condition. */ -+ if (v1 < 0xCDCDCDCD) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF); -+ } else { -+ odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2); -+ } -+ continue; -+ } else { /* This line is the start line of branch. */ -+ if (!Checkcondition(array[i], hex)) { -+ /* Discard the following (offset, data) pairs. */ -+ READ_NEXT_PAIR(v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < array_len - 2) { -+ READ_NEXT_PAIR(v1, v2, i); -+ } -+ i -= 2; /* prevent from for-loop += 2 */ -+ } else { /* Configure matched pairs and skip to end of if-else. */ -+ READ_NEXT_PAIR(v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < array_len - 2) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF); -+ } else { -+ odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2); -+ } -+ -+ READ_NEXT_PAIR(v1, v2, i); -+ } -+ while (v2 != 0xDEAD && i < array_len - 2) -+ READ_NEXT_PAIR(v1, v2, i); -+ } -+ } -+ } -+ if (biol) { -+ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { -+ pr_info("~~~ MAC IOL_exec_cmds Failed !!!\n"); -+ rst = HAL_STATUS_FAILURE; -+ } -+ } -+ return rst; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_RF.c b/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_RF.c -new file mode 100644 -index 0000000000000..b5d5050c0a17d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/HalHWImg8188E_RF.c -@@ -0,0 +1,268 @@ -+/****************************************************************************** -+* -+* Copyright(c) 2007 - 2011 Realtek 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 -+* -+* -+******************************************************************************/ -+ -+#include "odm_precomp.h" -+ -+#include -+ -+static bool CheckCondition(const u32 Condition, const u32 Hex) -+{ -+ u32 _board = (Hex & 0x000000FF); -+ u32 _interface = (Hex & 0x0000FF00) >> 8; -+ u32 _platform = (Hex & 0x00FF0000) >> 16; -+ u32 cond = Condition; -+ -+ if (Condition == 0xCDCDCDCD) -+ return true; -+ -+ cond = Condition & 0x000000FF; -+ if ((_board == cond) && cond != 0x00) -+ return false; -+ -+ cond = Condition & 0x0000FF00; -+ cond = cond >> 8; -+ if ((_interface & cond) == 0 && cond != 0x07) -+ return false; -+ -+ cond = Condition & 0x00FF0000; -+ cond = cond >> 16; -+ if ((_platform & cond) == 0 && cond != 0x0F) -+ return false; -+ return true; -+} -+ -+/****************************************************************************** -+* RadioA_1T.TXT -+******************************************************************************/ -+ -+static u32 Array_RadioA_1T_8188E[] = { -+ 0x000, 0x00030000, -+ 0x008, 0x00084000, -+ 0x018, 0x00000407, -+ 0x019, 0x00000012, -+ 0x01E, 0x00080009, -+ 0x01F, 0x00000880, -+ 0x02F, 0x0001A060, -+ 0x03F, 0x00000000, -+ 0x042, 0x000060C0, -+ 0x057, 0x000D0000, -+ 0x058, 0x000BE180, -+ 0x067, 0x00001552, -+ 0x083, 0x00000000, -+ 0x0B0, 0x000FF8FC, -+ 0x0B1, 0x00054400, -+ 0x0B2, 0x000CCC19, -+ 0x0B4, 0x00043003, -+ 0x0B6, 0x0004953E, -+ 0x0B7, 0x0001C718, -+ 0x0B8, 0x000060FF, -+ 0x0B9, 0x00080001, -+ 0x0BA, 0x00040000, -+ 0x0BB, 0x00000400, -+ 0x0BF, 0x000C0000, -+ 0x0C2, 0x00002400, -+ 0x0C3, 0x00000009, -+ 0x0C4, 0x00040C91, -+ 0x0C5, 0x00099999, -+ 0x0C6, 0x000000A3, -+ 0x0C7, 0x00088820, -+ 0x0C8, 0x00076C06, -+ 0x0C9, 0x00000000, -+ 0x0CA, 0x00080000, -+ 0x0DF, 0x00000180, -+ 0x0EF, 0x000001A0, -+ 0x051, 0x0006B27D, -+ 0xFF0F041F, 0xABCD, -+ 0x052, 0x0007E4DD, -+ 0xCDCDCDCD, 0xCDCD, -+ 0x052, 0x0007E49D, -+ 0xFF0F041F, 0xDEAD, -+ 0x053, 0x00000073, -+ 0x056, 0x00051FF3, -+ 0x035, 0x00000086, -+ 0x035, 0x00000186, -+ 0x035, 0x00000286, -+ 0x036, 0x00001C25, -+ 0x036, 0x00009C25, -+ 0x036, 0x00011C25, -+ 0x036, 0x00019C25, -+ 0x0B6, 0x00048538, -+ 0x018, 0x00000C07, -+ 0x05A, 0x0004BD00, -+ 0x019, 0x000739D0, -+ 0x034, 0x0000ADF3, -+ 0x034, 0x00009DF0, -+ 0x034, 0x00008DED, -+ 0x034, 0x00007DEA, -+ 0x034, 0x00006DE7, -+ 0x034, 0x000054EE, -+ 0x034, 0x000044EB, -+ 0x034, 0x000034E8, -+ 0x034, 0x0000246B, -+ 0x034, 0x00001468, -+ 0x034, 0x0000006D, -+ 0x000, 0x00030159, -+ 0x084, 0x00068200, -+ 0x086, 0x000000CE, -+ 0x087, 0x00048A00, -+ 0x08E, 0x00065540, -+ 0x08F, 0x00088000, -+ 0x0EF, 0x000020A0, -+ 0x03B, 0x000F02B0, -+ 0x03B, 0x000EF7B0, -+ 0x03B, 0x000D4FB0, -+ 0x03B, 0x000CF060, -+ 0x03B, 0x000B0090, -+ 0x03B, 0x000A0080, -+ 0x03B, 0x00090080, -+ 0x03B, 0x0008F780, -+ 0x03B, 0x000722B0, -+ 0x03B, 0x0006F7B0, -+ 0x03B, 0x00054FB0, -+ 0x03B, 0x0004F060, -+ 0x03B, 0x00030090, -+ 0x03B, 0x00020080, -+ 0x03B, 0x00010080, -+ 0x03B, 0x0000F780, -+ 0x0EF, 0x000000A0, -+ 0x000, 0x00010159, -+ 0x018, 0x0000F407, -+ 0xFFE, 0x00000000, -+ 0xFFE, 0x00000000, -+ 0x01F, 0x00080003, -+ 0xFFE, 0x00000000, -+ 0xFFE, 0x00000000, -+ 0x01E, 0x00000001, -+ 0x01F, 0x00080000, -+ 0x000, 0x00033E60, -+}; -+ -+enum HAL_STATUS ODM_ReadAndConfig_RadioA_1T_8188E(struct odm_dm_struct *pDM_Odm) -+{ -+ #define READ_NEXT_PAIR(v1, v2, i) do \ -+ { i += 2; v1 = Array[i]; \ -+ v2 = Array[i+1]; } while (0) -+ -+ u32 hex = 0; -+ u32 i = 0; -+ u8 platform = pDM_Odm->SupportPlatform; -+ u8 interfaceValue = pDM_Odm->SupportInterface; -+ u8 board = pDM_Odm->BoardType; -+ u32 ArrayLen = sizeof(Array_RadioA_1T_8188E)/sizeof(u32); -+ u32 *Array = Array_RadioA_1T_8188E; -+ bool biol = false; -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ struct xmit_frame *pxmit_frame = NULL; -+ u8 bndy_cnt = 1; -+ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; -+ -+ hex += board; -+ hex += interfaceValue << 8; -+ hex += platform << 16; -+ hex += 0xFF000000; -+ biol = rtw_IOL_applied(Adapter); -+ -+ if (biol) { -+ pxmit_frame = rtw_IOL_accquire_xmit_frame(Adapter); -+ if (pxmit_frame == NULL) { -+ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); -+ return HAL_STATUS_FAILURE; -+ } -+ } -+ -+ for (i = 0; i < ArrayLen; i += 2) { -+ u32 v1 = Array[i]; -+ u32 v2 = Array[i+1]; -+ -+ /* This (offset, data) pair meets the condition. */ -+ if (v1 < 0xCDCDCDCD) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ -+ if (v1 == 0xffe) -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); -+ else if (v1 == 0xfd) -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); -+ else if (v1 == 0xfc) -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); -+ else if (v1 == 0xfb) -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); -+ else if (v1 == 0xfa) -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); -+ else if (v1 == 0xf9) -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); -+ else -+ rtw_IOL_append_WRF_cmd(pxmit_frame, RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask); -+ } else { -+ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); -+ } -+ continue; -+ } else { /* This line is the start line of branch. */ -+ if (!CheckCondition(Array[i], hex)) { -+ /* Discard the following (offset, data) pairs. */ -+ READ_NEXT_PAIR(v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < ArrayLen - 2) -+ READ_NEXT_PAIR(v1, v2, i); -+ i -= 2; /* prevent from for-loop += 2 */ -+ } else { /* Configure matched pairs and skip to end of if-else. */ -+ READ_NEXT_PAIR(v1, v2, i); -+ while (v2 != 0xDEAD && -+ v2 != 0xCDEF && -+ v2 != 0xCDCD && i < ArrayLen - 2) { -+ if (biol) { -+ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) -+ bndy_cnt++; -+ -+ if (v1 == 0xffe) -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); -+ else if (v1 == 0xfd) -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); -+ else if (v1 == 0xfc) -+ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); -+ else if (v1 == 0xfb) -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); -+ else if (v1 == 0xfa) -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); -+ else if (v1 == 0xf9) -+ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); -+ else -+ rtw_IOL_append_WRF_cmd(pxmit_frame, RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask); -+ } else { -+ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); -+ } -+ READ_NEXT_PAIR(v1, v2, i); -+ } -+ -+ while (v2 != 0xDEAD && i < ArrayLen - 2) -+ READ_NEXT_PAIR(v1, v2, i); -+ } -+ } -+ } -+ if (biol) { -+ if (!rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { -+ rst = HAL_STATUS_FAILURE; -+ pr_info("~~~ IOL Config %s Failed !!!\n", __func__); -+ } -+ } -+ return rst; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/HalPhyRf.c b/drivers/net/wireless/rtl8188eu/hal/HalPhyRf.c -new file mode 100644 -index 0000000000000..980f7da8ab3bd ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/HalPhyRf.c -@@ -0,0 +1,49 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+ #include "odm_precomp.h" -+ -+/* 3============================================================ */ -+/* 3 IQ Calibration */ -+/* 3============================================================ */ -+ -+void ODM_ResetIQKResult(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+u8 ODM_GetRightChnlPlaceforIQK(u8 chnl) -+{ -+ u8 channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = { -+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, -+ 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, -+ 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, -+ 124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, -+ 155, 157, 159, 161, 163, 165 -+ }; -+ u8 place = chnl; -+ -+ if (chnl > 14) { -+ for (place = 14; place < sizeof(channel_all); place++) { -+ if (channel_all[place] == chnl) -+ return place-13; -+ } -+ } -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/HalPhyRf_8188e.c b/drivers/net/wireless/rtl8188eu/hal/HalPhyRf_8188e.c -new file mode 100644 -index 0000000000000..8a7947d8de7fe ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/HalPhyRf_8188e.c -@@ -0,0 +1,1505 @@ -+ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include "odm_precomp.h" -+ -+/*---------------------------Define Local Constant---------------------------*/ -+/* 2010/04/25 MH Define the max tx power tracking tx agc power. */ -+#define ODM_TXPWRTRACK_MAX_IDX_88E 6 -+ -+/*---------------------------Define Local Constant---------------------------*/ -+ -+/* 3============================================================ */ -+/* 3 Tx Power Tracking */ -+/* 3============================================================ */ -+/*----------------------------------------------------------------------------- -+ * Function: ODM_TxPwrTrackAdjust88E() -+ * -+ * Overview: 88E we can not write 0xc80/c94/c4c/ 0xa2x. Instead of write TX agc. -+ * No matter OFDM & CCK use the same method. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 04/23/2012 MHC Create Version 0. -+ * 04/23/2012 MHC Adjust TX agc directly not throughput BB digital. -+ * -+ *---------------------------------------------------------------------------*/ -+void ODM_TxPwrTrackAdjust88E(struct odm_dm_struct *dm_odm, u8 Type,/* 0 = OFDM, 1 = CCK */ -+ u8 *pDirection, /* 1 = +(increase) 2 = -(decrease) */ -+ u32 *pOutWriteVal /* Tx tracking CCK/OFDM BB swing index adjust */ -+ ) -+{ -+ u8 pwr_value = 0; -+ /* Tx power tracking BB swing table. */ -+ /* The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */ -+ if (Type == 0) { /* For OFDM afjust */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, -+ ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n", -+ dm_odm->BbSwingIdxOfdm, dm_odm->BbSwingFlagOfdm)); -+ -+ if (dm_odm->BbSwingIdxOfdm <= dm_odm->BbSwingIdxOfdmBase) { -+ *pDirection = 1; -+ pwr_value = (dm_odm->BbSwingIdxOfdmBase - dm_odm->BbSwingIdxOfdm); -+ } else { -+ *pDirection = 2; -+ pwr_value = (dm_odm->BbSwingIdxOfdm - dm_odm->BbSwingIdxOfdmBase); -+ } -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, -+ ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n", -+ dm_odm->BbSwingIdxOfdm, dm_odm->BbSwingFlagOfdm)); -+ } else if (Type == 1) { /* For CCK adjust. */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, -+ ("dm_odm->BbSwingIdxCck = %d dm_odm->BbSwingIdxCckBase = %d\n", -+ dm_odm->BbSwingIdxCck, dm_odm->BbSwingIdxCckBase)); -+ -+ if (dm_odm->BbSwingIdxCck <= dm_odm->BbSwingIdxCckBase) { -+ *pDirection = 1; -+ pwr_value = (dm_odm->BbSwingIdxCckBase - dm_odm->BbSwingIdxCck); -+ } else { -+ *pDirection = 2; -+ pwr_value = (dm_odm->BbSwingIdxCck - dm_odm->BbSwingIdxCckBase); -+ } -+ } -+ -+ /* */ -+ /* 2012/04/25 MH According to Ed/Luke.Lees estimate for EVM the max tx power tracking */ -+ /* need to be less than 6 power index for 88E. */ -+ /* */ -+ if (pwr_value >= ODM_TXPWRTRACK_MAX_IDX_88E && *pDirection == 1) -+ pwr_value = ODM_TXPWRTRACK_MAX_IDX_88E; -+ -+ *pOutWriteVal = pwr_value | (pwr_value<<8) | (pwr_value<<16) | (pwr_value<<24); -+} /* ODM_TxPwrTrackAdjust88E */ -+ -+/*----------------------------------------------------------------------------- -+ * Function: odm_TxPwrTrackSetPwr88E() -+ * -+ * Overview: 88E change all channel tx power accordign to flag. -+ * OFDM & CCK are all different. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 04/23/2012 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+static void odm_TxPwrTrackSetPwr88E(struct odm_dm_struct *dm_odm) -+{ -+ if (dm_odm->BbSwingFlagOfdm || dm_odm->BbSwingFlagCck) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("odm_TxPwrTrackSetPwr88E CH=%d\n", *(dm_odm->pChannel))); -+ PHY_SetTxPowerLevel8188E(dm_odm->Adapter, *(dm_odm->pChannel)); -+ dm_odm->BbSwingFlagOfdm = false; -+ dm_odm->BbSwingFlagCck = false; -+ } -+} /* odm_TxPwrTrackSetPwr88E */ -+ -+/* 091212 chiyokolin */ -+void -+odm_TXPowerTrackingCallback_ThermalMeter_8188E( -+ struct adapter *Adapter -+ ) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, offset; -+ u8 ThermalValue_AVG_count = 0; -+ u32 ThermalValue_AVG = 0; -+ s32 ele_A = 0, ele_D, TempCCk, X, value32; -+ s32 Y, ele_C = 0; -+ s8 OFDM_index[2], CCK_index = 0; -+ s8 OFDM_index_old[2] = {0, 0}, CCK_index_old = 0; -+ u32 i = 0, j = 0; -+ bool is2t = false; -+ -+ u8 OFDM_min_index = 6, rf; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */ -+ u8 Indexforchannel = 0/*GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/; -+ s8 OFDM_index_mapping[2][index_mapping_NUM_88E] = { -+ {0, 0, 2, 3, 4, 4, /* 2.4G, decrease power */ -+ 5, 6, 7, 7, 8, 9, -+ 10, 10, 11}, /* For lower temperature, 20120220 updated on 20120220. */ -+ {0, 0, -1, -2, -3, -4, /* 2.4G, increase power */ -+ -4, -4, -4, -5, -7, -8, -+ -9, -9, -10}, -+ }; -+ u8 Thermal_mapping[2][index_mapping_NUM_88E] = { -+ {0, 2, 4, 6, 8, 10, /* 2.4G, decrease power */ -+ 12, 14, 16, 18, 20, 22, -+ 24, 26, 27}, -+ {0, 2, 4, 6, 8, 10, /* 2.4G,, increase power */ -+ 12, 14, 16, 18, 20, 22, -+ 25, 25, 25}, -+ }; -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ /* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */ -+ odm_TxPwrTrackSetPwr88E(dm_odm); -+ -+ dm_odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++; /* cosa add for debug */ -+ dm_odm->RFCalibrateInfo.bTXPowerTrackingInit = true; -+ -+ /* RFCalibrateInfo.RegA24 will be initialized when ODM HW configuring, but MP configures with para files. */ -+ dm_odm->RFCalibrateInfo.RegA24 = 0x090e1317; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("===>dm_TXPowerTrackingCallback_ThermalMeter_8188E txpowercontrol %d\n", -+ dm_odm->RFCalibrateInfo.TxPowerTrackControl)); -+ -+ ThermalValue = (u8)ODM_GetRFReg(dm_odm, RF_PATH_A, RF_T_METER_88E, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n", -+ ThermalValue, dm_odm->RFCalibrateInfo.ThermalValue, pHalData->EEPROMThermalMeter)); -+ -+ if (is2t) -+ rf = 2; -+ else -+ rf = 1; -+ -+ if (ThermalValue) { -+ /* Query OFDM path A default setting */ -+ ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord)&bMaskOFDM_D; -+ for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { /* find the index */ -+ if (ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) { -+ OFDM_index_old[0] = (u8)i; -+ dm_odm->BbSwingIdxOfdmBase = (u8)i; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Initial pathA ele_D reg0x%x = 0x%x, OFDM_index=0x%x\n", -+ rOFDM0_XATxIQImbalance, ele_D, OFDM_index_old[0])); -+ break; -+ } -+ } -+ -+ /* Query OFDM path B default setting */ -+ if (is2t) { -+ ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord)&bMaskOFDM_D; -+ for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { /* find the index */ -+ if (ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) { -+ OFDM_index_old[1] = (u8)i; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Initial pathB ele_D reg0x%x = 0x%x, OFDM_index=0x%x\n", -+ rOFDM0_XBTxIQImbalance, ele_D, OFDM_index_old[1])); -+ break; -+ } -+ } -+ } -+ -+ /* Query CCK default setting From 0xa24 */ -+ TempCCk = dm_odm->RFCalibrateInfo.RegA24; -+ -+ for (i = 0; i < CCK_TABLE_SIZE; i++) { -+ if (dm_odm->RFCalibrateInfo.bCCKinCH14) { -+ if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4) == 0) { -+ CCK_index_old = (u8)i; -+ dm_odm->BbSwingIdxCckBase = (u8)i; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Initial reg0x%x = 0x%x, CCK_index=0x%x, ch 14 %d\n", -+ rCCK0_TxFilter2, TempCCk, CCK_index_old, dm_odm->RFCalibrateInfo.bCCKinCH14)); -+ break; -+ } -+ } else { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("RegA24: 0x%X, CCKSwingTable_Ch1_Ch13[%d][2]: CCKSwingTable_Ch1_Ch13[i][2]: 0x%X\n", -+ TempCCk, i, CCKSwingTable_Ch1_Ch13[i][2])); -+ if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4) == 0) { -+ CCK_index_old = (u8)i; -+ dm_odm->BbSwingIdxCckBase = (u8)i; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Initial reg0x%x = 0x%x, CCK_index=0x%x, ch14 %d\n", -+ rCCK0_TxFilter2, TempCCk, CCK_index_old, dm_odm->RFCalibrateInfo.bCCKinCH14)); -+ break; -+ } -+ } -+ } -+ -+ if (!dm_odm->RFCalibrateInfo.ThermalValue) { -+ dm_odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; -+ dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; -+ dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue; -+ -+ for (i = 0; i < rf; i++) -+ dm_odm->RFCalibrateInfo.OFDM_index[i] = OFDM_index_old[i]; -+ dm_odm->RFCalibrateInfo.CCK_index = CCK_index_old; -+ } -+ -+ if (dm_odm->RFCalibrateInfo.bReloadtxpowerindex) -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("reload ofdm index for band switch\n")); -+ -+ /* calculate average thermal meter */ -+ dm_odm->RFCalibrateInfo.ThermalValue_AVG[dm_odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue; -+ dm_odm->RFCalibrateInfo.ThermalValue_AVG_index++; -+ if (dm_odm->RFCalibrateInfo.ThermalValue_AVG_index == AVG_THERMAL_NUM_88E) -+ dm_odm->RFCalibrateInfo.ThermalValue_AVG_index = 0; -+ -+ for (i = 0; i < AVG_THERMAL_NUM_88E; i++) { -+ if (dm_odm->RFCalibrateInfo.ThermalValue_AVG[i]) { -+ ThermalValue_AVG += dm_odm->RFCalibrateInfo.ThermalValue_AVG[i]; -+ ThermalValue_AVG_count++; -+ } -+ } -+ -+ if (ThermalValue_AVG_count) { -+ ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("AVG Thermal Meter = 0x%x\n", ThermalValue)); -+ } -+ -+ if (dm_odm->RFCalibrateInfo.bReloadtxpowerindex) { -+ delta = ThermalValue > pHalData->EEPROMThermalMeter ? -+ (ThermalValue - pHalData->EEPROMThermalMeter) : -+ (pHalData->EEPROMThermalMeter - ThermalValue); -+ dm_odm->RFCalibrateInfo.bReloadtxpowerindex = false; -+ dm_odm->RFCalibrateInfo.bDoneTxpower = false; -+ } else if (dm_odm->RFCalibrateInfo.bDoneTxpower) { -+ delta = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue) ? -+ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue) : -+ (dm_odm->RFCalibrateInfo.ThermalValue - ThermalValue); -+ } else { -+ delta = ThermalValue > pHalData->EEPROMThermalMeter ? -+ (ThermalValue - pHalData->EEPROMThermalMeter) : -+ (pHalData->EEPROMThermalMeter - ThermalValue); -+ } -+ delta_LCK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_LCK) ? -+ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_LCK) : -+ (dm_odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue); -+ delta_IQK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_IQK) ? -+ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_IQK) : -+ (dm_odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x delta 0x%x delta_LCK 0x%x delta_IQK 0x%x\n", -+ ThermalValue, dm_odm->RFCalibrateInfo.ThermalValue, -+ pHalData->EEPROMThermalMeter, delta, delta_LCK, delta_IQK)); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("pre thermal meter LCK 0x%x pre thermal meter IQK 0x%x delta_LCK_bound 0x%x delta_IQK_bound 0x%x\n", -+ dm_odm->RFCalibrateInfo.ThermalValue_LCK, -+ dm_odm->RFCalibrateInfo.ThermalValue_IQK, -+ dm_odm->RFCalibrateInfo.Delta_LCK, -+ dm_odm->RFCalibrateInfo.Delta_IQK)); -+ -+ if ((delta_LCK >= 8)) { /* Delta temperature is equal to or larger than 20 centigrade. */ -+ dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; -+ PHY_LCCalibrate_8188E(Adapter); -+ } -+ -+ if (delta > 0 && dm_odm->RFCalibrateInfo.TxPowerTrackControl) { -+ delta = ThermalValue > pHalData->EEPROMThermalMeter ? -+ (ThermalValue - pHalData->EEPROMThermalMeter) : -+ (pHalData->EEPROMThermalMeter - ThermalValue); -+ /* calculate new OFDM / CCK offset */ -+ if (ThermalValue > pHalData->EEPROMThermalMeter) -+ j = 1; -+ else -+ j = 0; -+ for (offset = 0; offset < index_mapping_NUM_88E; offset++) { -+ if (delta < Thermal_mapping[j][offset]) { -+ if (offset != 0) -+ offset--; -+ break; -+ } -+ } -+ if (offset >= index_mapping_NUM_88E) -+ offset = index_mapping_NUM_88E-1; -+ for (i = 0; i < rf; i++) -+ OFDM_index[i] = dm_odm->RFCalibrateInfo.OFDM_index[i] + OFDM_index_mapping[j][offset]; -+ CCK_index = dm_odm->RFCalibrateInfo.CCK_index + OFDM_index_mapping[j][offset]; -+ -+ if (is2t) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("temp OFDM_A_index=0x%x, OFDM_B_index=0x%x, CCK_index=0x%x\n", -+ dm_odm->RFCalibrateInfo.OFDM_index[0], -+ dm_odm->RFCalibrateInfo.OFDM_index[1], -+ dm_odm->RFCalibrateInfo.CCK_index)); -+ } else { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("temp OFDM_A_index=0x%x, CCK_index=0x%x\n", -+ dm_odm->RFCalibrateInfo.OFDM_index[0], -+ dm_odm->RFCalibrateInfo.CCK_index)); -+ } -+ -+ for (i = 0; i < rf; i++) { -+ if (OFDM_index[i] > OFDM_TABLE_SIZE_92D-1) -+ OFDM_index[i] = OFDM_TABLE_SIZE_92D-1; -+ else if (OFDM_index[i] < OFDM_min_index) -+ OFDM_index[i] = OFDM_min_index; -+ } -+ -+ if (CCK_index > CCK_TABLE_SIZE-1) -+ CCK_index = CCK_TABLE_SIZE-1; -+ else if (CCK_index < 0) -+ CCK_index = 0; -+ -+ if (is2t) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("new OFDM_A_index=0x%x, OFDM_B_index=0x%x, CCK_index=0x%x\n", -+ OFDM_index[0], OFDM_index[1], CCK_index)); -+ } else { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("new OFDM_A_index=0x%x, CCK_index=0x%x\n", -+ OFDM_index[0], CCK_index)); -+ } -+ -+ /* 2 temporarily remove bNOPG */ -+ /* Config by SwingTable */ -+ if (dm_odm->RFCalibrateInfo.TxPowerTrackControl) { -+ dm_odm->RFCalibrateInfo.bDoneTxpower = true; -+ -+ /* Adujst OFDM Ant_A according to IQK result */ -+ ele_D = (OFDMSwingTable[(u8)OFDM_index[0]] & 0xFFC00000)>>22; -+ X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][0]; -+ Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][1]; -+ -+ /* Revse TX power table. */ -+ dm_odm->BbSwingIdxOfdm = (u8)OFDM_index[0]; -+ dm_odm->BbSwingIdxCck = (u8)CCK_index; -+ -+ if (dm_odm->BbSwingIdxOfdmCurrent != dm_odm->BbSwingIdxOfdm) { -+ dm_odm->BbSwingIdxOfdmCurrent = dm_odm->BbSwingIdxOfdm; -+ dm_odm->BbSwingFlagOfdm = true; -+ } -+ -+ if (dm_odm->BbSwingIdxCckCurrent != dm_odm->BbSwingIdxCck) { -+ dm_odm->BbSwingIdxCckCurrent = dm_odm->BbSwingIdxCck; -+ dm_odm->BbSwingFlagCck = true; -+ } -+ -+ if (X != 0) { -+ if ((X & 0x00000200) != 0) -+ X = X | 0xFFFFFC00; -+ ele_A = ((X * ele_D)>>8)&0x000003FF; -+ -+ /* new element C = element D x Y */ -+ if ((Y & 0x00000200) != 0) -+ Y = Y | 0xFFFFFC00; -+ ele_C = ((Y * ele_D)>>8)&0x000003FF; -+ -+ /* 2012/04/23 MH According to Luke's suggestion, we can not write BB digital */ -+ /* to increase TX power. Otherwise, EVM will be bad. */ -+ } -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("TxPwrTracking for path A: X=0x%x, Y=0x%x ele_A=0x%x ele_C=0x%x ele_D=0x%x 0xe94=0x%x 0xe9c=0x%x\n", -+ (u32)X, (u32)Y, (u32)ele_A, (u32)ele_C, (u32)ele_D, (u32)X, (u32)Y)); -+ -+ if (is2t) { -+ ele_D = (OFDMSwingTable[(u8)OFDM_index[1]] & 0xFFC00000)>>22; -+ -+ /* new element A = element D x X */ -+ X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][4]; -+ Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][5]; -+ -+ if ((X != 0) && (*(dm_odm->pBandType) == ODM_BAND_2_4G)) { -+ if ((X & 0x00000200) != 0) /* consider minus */ -+ X = X | 0xFFFFFC00; -+ ele_A = ((X * ele_D)>>8)&0x000003FF; -+ -+ /* new element C = element D x Y */ -+ if ((Y & 0x00000200) != 0) -+ Y = Y | 0xFFFFFC00; -+ ele_C = ((Y * ele_D)>>8)&0x00003FF; -+ -+ /* wtite new elements A, C, D to regC88 and regC9C, element B is always 0 */ -+ value32 = (ele_D<<22) | ((ele_C&0x3F)<<16) | ele_A; -+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, value32); -+ -+ value32 = (ele_C&0x000003C0)>>6; -+ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, value32); -+ -+ value32 = ((X * ele_D)>>7)&0x01; -+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT28, value32); -+ } else { -+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable[(u8)OFDM_index[1]]); -+ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00); -+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT28, 0x00); -+ } -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("TxPwrTracking path B: X=0x%x, Y=0x%x ele_A=0x%x ele_C=0x%x ele_D=0x%x 0xeb4=0x%x 0xebc=0x%x\n", -+ (u32)X, (u32)Y, (u32)ele_A, -+ (u32)ele_C, (u32)ele_D, (u32)X, (u32)Y)); -+ } -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n", -+ ODM_GetBBReg(dm_odm, 0xc80, bMaskDWord), ODM_GetBBReg(dm_odm, -+ 0xc94, bMaskDWord), ODM_GetRFReg(dm_odm, RF_PATH_A, 0x24, bRFRegOffsetMask))); -+ } -+ } -+ -+ if (delta_IQK >= 8) { /* Delta temperature is equal to or larger than 20 centigrade. */ -+ ODM_ResetIQKResult(dm_odm); -+ -+ dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue; -+ PHY_IQCalibrate_8188E(Adapter, false); -+ } -+ /* update thermal meter value */ -+ if (dm_odm->RFCalibrateInfo.TxPowerTrackControl) -+ dm_odm->RFCalibrateInfo.ThermalValue = ThermalValue; -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("<===dm_TXPowerTrackingCallback_ThermalMeter_8188E\n")); -+ dm_odm->RFCalibrateInfo.TXPowercount = 0; -+} -+ -+/* 1 7. IQK */ -+#define MAX_TOLERANCE 5 -+#define IQK_DELAY_TIME 1 /* ms */ -+ -+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ -+phy_PathA_IQK_8188E(struct adapter *adapt, bool configPathB) -+{ -+ u32 regeac, regE94, regE9C, regEA4; -+ u8 result = 0x00; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK!\n")); -+ -+ /* 1 Tx IQK */ -+ /* path-A IQK setting */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A IQK setting!\n")); -+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); -+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); -+ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x8214032a); -+ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); -+ -+ /* LO calibration setting */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x00462911); -+ -+ /* One shot, path A LOK & IQK */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); -+ -+ /* delay x ms */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); -+ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */ -+ ODM_delay_ms(IQK_DELAY_TIME_88E); -+ -+ /* Check failed */ -+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regeac)); -+ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); -+ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); -+ regEA4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4)); -+ -+ if (!(regeac & BIT28) && -+ (((regE94 & 0x03FF0000)>>16) != 0x142) && -+ (((regE9C & 0x03FF0000)>>16) != 0x42)) -+ result |= 0x01; -+ return result; -+} -+ -+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ -+phy_PathA_RxIQK(struct adapter *adapt, bool configPathB) -+{ -+ u32 regeac, regE94, regE9C, regEA4, u4tmp; -+ u8 result = 0x00; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n")); -+ -+ /* 1 Get TXIMR setting */ -+ /* modify RXIQK mode table */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n")); -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf117B); -+ -+ /* PA,PAD off */ -+ ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x980); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, 0x56, bRFRegOffsetMask, 0x51000); -+ -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); -+ -+ /* IQK setting */ -+ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00); -+ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800); -+ -+ /* path-A IQK setting */ -+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); -+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); -+ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c1f); -+ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); -+ -+ /* LO calibration setting */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); -+ -+ /* One shot, path A LOK & IQK */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); -+ -+ /* delay x ms */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Delay %d ms for One shot, path A LOK & IQK.\n", -+ IQK_DELAY_TIME_88E)); -+ ODM_delay_ms(IQK_DELAY_TIME_88E); -+ -+ /* Check failed */ -+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xeac = 0x%x\n", regeac)); -+ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xe94 = 0x%x\n", regE94)); -+ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xe9c = 0x%x\n", regE9C)); -+ -+ if (!(regeac & BIT28) && -+ (((regE94 & 0x03FF0000)>>16) != 0x142) && -+ (((regE9C & 0x03FF0000)>>16) != 0x42)) -+ result |= 0x01; -+ else /* if Tx not OK, ignore Rx */ -+ return result; -+ -+ u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16); -+ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, u4tmp); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x\n", ODM_GetBBReg(dm_odm, rTx_IQK, bMaskDWord), u4tmp)); -+ -+ /* 1 RX IQK */ -+ /* modify RXIQK mode table */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table 2!\n")); -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7ffa); -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); -+ -+ /* IQK setting */ -+ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x01004800); -+ -+ /* path-A IQK setting */ -+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x38008c1c); -+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x18008c1c); -+ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c05); -+ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160c1f); -+ -+ /* LO calibration setting */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); -+ -+ /* One shot, path A LOK & IQK */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); -+ -+ /* delay x ms */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); -+ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */ -+ ODM_delay_ms(IQK_DELAY_TIME_88E); -+ -+ /* Check failed */ -+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regeac)); -+ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); -+ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); -+ regEA4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4)); -+ -+ /* reload RF 0xdf */ -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x180); -+ -+ if (!(regeac & BIT27) && /* if Tx is OK, check whether Rx is OK */ -+ (((regEA4 & 0x03FF0000)>>16) != 0x132) && -+ (((regeac & 0x03FF0000)>>16) != 0x36)) -+ result |= 0x02; -+ else -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK fail!!\n")); -+ -+ return result; -+} -+ -+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ -+phy_PathB_IQK_8188E(struct adapter *adapt) -+{ -+ u32 regeac, regeb4, regebc, regec4, regecc; -+ u8 result = 0x00; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK!\n")); -+ -+ /* One shot, path B LOK & IQK */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000002); -+ ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000000); -+ -+ /* delay x ms */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Delay %d ms for One shot, path B LOK & IQK.\n", -+ IQK_DELAY_TIME_88E)); -+ ODM_delay_ms(IQK_DELAY_TIME_88E); -+ -+ /* Check failed */ -+ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xeac = 0x%x\n", regeac)); -+ regeb4 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xeb4 = 0x%x\n", regeb4)); -+ regebc = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xebc = 0x%x\n", regebc)); -+ regec4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xec4 = 0x%x\n", regec4)); -+ regecc = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("0xecc = 0x%x\n", regecc)); -+ -+ if (!(regeac & BIT31) && -+ (((regeb4 & 0x03FF0000)>>16) != 0x142) && -+ (((regebc & 0x03FF0000)>>16) != 0x42)) -+ result |= 0x01; -+ else -+ return result; -+ -+ if (!(regeac & BIT30) && -+ (((regec4 & 0x03FF0000)>>16) != 0x132) && -+ (((regecc & 0x03FF0000)>>16) != 0x36)) -+ result |= 0x02; -+ else -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK fail!!\n")); -+ return result; -+} -+ -+static void patha_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly) -+{ -+ u32 Oldval_0, X, TX0_A, reg; -+ s32 Y, TX0_C; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Path A IQ Calibration %s !\n", -+ (iqkok) ? "Success" : "Failed")); -+ -+ if (final_candidate == 0xFF) { -+ return; -+ } else if (iqkok) { -+ Oldval_0 = (ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; -+ -+ X = result[final_candidate][0]; -+ if ((X & 0x00000200) != 0) -+ X = X | 0xFFFFFC00; -+ TX0_A = (X * Oldval_0) >> 8; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n", -+ X, TX0_A, Oldval_0)); -+ ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); -+ -+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(31), ((X * Oldval_0>>7) & 0x1)); -+ -+ Y = result[final_candidate][1]; -+ if ((Y & 0x00000200) != 0) -+ Y = Y | 0xFFFFFC00; -+ -+ TX0_C = (Y * Oldval_0) >> 8; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C)); -+ ODM_SetBBReg(dm_odm, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6)); -+ ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F)); -+ -+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(29), ((Y * Oldval_0>>7) & 0x1)); -+ -+ if (txonly) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("patha_fill_iqk only Tx OK\n")); -+ return; -+ } -+ -+ reg = result[final_candidate][2]; -+ ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0x3FF, reg); -+ -+ reg = result[final_candidate][3] & 0x3F; -+ ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0xFC00, reg); -+ -+ reg = (result[final_candidate][3] >> 6) & 0xF; -+ ODM_SetBBReg(dm_odm, rOFDM0_RxIQExtAnta, 0xF0000000, reg); -+ } -+} -+ -+static void pathb_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly) -+{ -+ u32 Oldval_1, X, TX1_A, reg; -+ s32 Y, TX1_C; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("Path B IQ Calibration %s !\n", -+ (iqkok) ? "Success" : "Failed")); -+ -+ if (final_candidate == 0xFF) { -+ return; -+ } else if (iqkok) { -+ Oldval_1 = (ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; -+ -+ X = result[final_candidate][4]; -+ if ((X & 0x00000200) != 0) -+ X = X | 0xFFFFFC00; -+ TX1_A = (X * Oldval_1) >> 8; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A)); -+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); -+ -+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(27), ((X * Oldval_1>>7) & 0x1)); -+ -+ Y = result[final_candidate][5]; -+ if ((Y & 0x00000200) != 0) -+ Y = Y | 0xFFFFFC00; -+ -+ TX1_C = (Y * Oldval_1) >> 8; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C)); -+ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6)); -+ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F)); -+ -+ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(25), ((Y * Oldval_1>>7) & 0x1)); -+ -+ if (txonly) -+ return; -+ -+ reg = result[final_candidate][6]; -+ ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0x3FF, reg); -+ -+ reg = result[final_candidate][7] & 0x3F; -+ ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0xFC00, reg); -+ -+ reg = (result[final_candidate][7] >> 6) & 0xF; -+ ODM_SetBBReg(dm_odm, rOFDM0_AGCRSSITable, 0x0000F000, reg); -+ } -+} -+ -+/* */ -+/* 2011/07/26 MH Add an API for testing IQK fail case. */ -+/* */ -+/* MP Already declare in odm.c */ -+static bool ODM_CheckPowerStatus(struct adapter *Adapter) -+{ -+ return true; -+} -+ -+void _PHY_SaveADDARegisters(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegisterNum) -+{ -+ u32 i; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ if (!ODM_CheckPowerStatus(adapt)) -+ return; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n")); -+ for (i = 0; i < RegisterNum; i++) { -+ ADDABackup[i] = ODM_GetBBReg(dm_odm, ADDAReg[i], bMaskDWord); -+ } -+} -+ -+static void _PHY_SaveMACRegisters( -+ struct adapter *adapt, -+ u32 *MACReg, -+ u32 *MACBackup -+ ) -+{ -+ u32 i; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n")); -+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) { -+ MACBackup[i] = ODM_Read1Byte(dm_odm, MACReg[i]); -+ } -+ MACBackup[i] = ODM_Read4Byte(dm_odm, MACReg[i]); -+} -+ -+static void reload_adda_reg(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum) -+{ -+ u32 i; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n")); -+ for (i = 0; i < RegiesterNum; i++) -+ ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, ADDABackup[i]); -+} -+ -+static void -+_PHY_ReloadMACRegisters( -+ struct adapter *adapt, -+ u32 *MACReg, -+ u32 *MACBackup -+ ) -+{ -+ u32 i; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload MAC parameters !\n")); -+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) { -+ ODM_Write1Byte(dm_odm, MACReg[i], (u8)MACBackup[i]); -+ } -+ ODM_Write4Byte(dm_odm, MACReg[i], MACBackup[i]); -+} -+ -+void -+_PHY_PathADDAOn( -+ struct adapter *adapt, -+ u32 *ADDAReg, -+ bool isPathAOn, -+ bool is2t -+ ) -+{ -+ u32 pathOn; -+ u32 i; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n")); -+ -+ pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4; -+ if (!is2t) { -+ pathOn = 0x0bdb25a0; -+ ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, 0x0b1b25a0); -+ } else { -+ ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, pathOn); -+ } -+ -+ for (i = 1; i < IQK_ADDA_REG_NUM; i++) -+ ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, pathOn); -+} -+ -+void -+_PHY_MACSettingCalibration( -+ struct adapter *adapt, -+ u32 *MACReg, -+ u32 *MACBackup -+ ) -+{ -+ u32 i = 0; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n")); -+ -+ ODM_Write1Byte(dm_odm, MACReg[i], 0x3F); -+ -+ for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) { -+ ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT3))); -+ } -+ ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT5))); -+} -+ -+void -+_PHY_PathAStandBy( -+ struct adapter *adapt -+ ) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A standby mode!\n")); -+ -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x0); -+ ODM_SetBBReg(dm_odm, 0x840, bMaskDWord, 0x00010000); -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); -+} -+ -+static void _PHY_PIModeSwitch( -+ struct adapter *adapt, -+ bool PIMode -+ ) -+{ -+ u32 mode; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("BB Switch to %s mode!\n", (PIMode ? "PI" : "SI"))); -+ -+ mode = PIMode ? 0x01000100 : 0x01000000; -+ ODM_SetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, bMaskDWord, mode); -+ ODM_SetBBReg(dm_odm, rFPGA0_XB_HSSIParameter1, bMaskDWord, mode); -+} -+ -+static bool phy_SimularityCompare_8188E( -+ struct adapter *adapt, -+ s32 resulta[][8], -+ u8 c1, -+ u8 c2 -+ ) -+{ -+ u32 i, j, diff, sim_bitmap, bound = 0; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ -+ bool result = true; -+ bool is2t; -+ s32 tmp1 = 0, tmp2 = 0; -+ -+ if ((dm_odm->RFType == ODM_2T2R) || (dm_odm->RFType == ODM_2T3R) || (dm_odm->RFType == ODM_2T4R)) -+ is2t = true; -+ else -+ is2t = false; -+ -+ if (is2t) -+ bound = 8; -+ else -+ bound = 4; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("===> IQK:phy_SimularityCompare_8188E c1 %d c2 %d!!!\n", c1, c2)); -+ -+ sim_bitmap = 0; -+ -+ for (i = 0; i < bound; i++) { -+ if ((i == 1) || (i == 3) || (i == 5) || (i == 7)) { -+ if ((resulta[c1][i] & 0x00000200) != 0) -+ tmp1 = resulta[c1][i] | 0xFFFFFC00; -+ else -+ tmp1 = resulta[c1][i]; -+ -+ if ((resulta[c2][i] & 0x00000200) != 0) -+ tmp2 = resulta[c2][i] | 0xFFFFFC00; -+ else -+ tmp2 = resulta[c2][i]; -+ } else { -+ tmp1 = resulta[c1][i]; -+ tmp2 = resulta[c2][i]; -+ } -+ -+ diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1); -+ -+ if (diff > MAX_TOLERANCE) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("IQK:phy_SimularityCompare_8188E differnece overflow index %d compare1 0x%x compare2 0x%x!!!\n", -+ i, resulta[c1][i], resulta[c2][i])); -+ -+ if ((i == 2 || i == 6) && !sim_bitmap) { -+ if (resulta[c1][i] + resulta[c1][i+1] == 0) -+ final_candidate[(i/4)] = c2; -+ else if (resulta[c2][i] + resulta[c2][i+1] == 0) -+ final_candidate[(i/4)] = c1; -+ else -+ sim_bitmap = sim_bitmap | (1<odmpriv; -+ u32 i; -+ u8 PathAOK, PathBOK; -+ u32 ADDA_REG[IQK_ADDA_REG_NUM] = { -+ rFPGA0_XCD_SwitchControl, rBlue_Tooth, -+ rRx_Wait_CCA, rTx_CCK_RFON, -+ rTx_CCK_BBON, rTx_OFDM_RFON, -+ rTx_OFDM_BBON, rTx_To_Rx, -+ rTx_To_Tx, rRx_CCK, -+ rRx_OFDM, rRx_Wait_RIFS, -+ rRx_TO_Rx, rStandby, -+ rSleep, rPMPD_ANAEN }; -+ u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = { -+ REG_TXPAUSE, REG_BCN_CTRL, -+ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; -+ -+ /* since 92C & 92D have the different define in IQK_BB_REG */ -+ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { -+ rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar, -+ rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB, -+ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, -+ rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD -+ }; -+ -+ u32 retryCount = 9; -+ if (*(dm_odm->mp_mode) == 1) -+ retryCount = 9; -+ else -+ retryCount = 2; -+ /* Note: IQ calibration must be performed after loading */ -+ /* PHY_REG.txt , and radio_a, radio_b.txt */ -+ -+ if (t == 0) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2t ? "2T2R" : "1T1R"), t)); -+ -+ /* Save ADDA parameters, turn Path A ADDA on */ -+ _PHY_SaveADDARegisters(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); -+ _PHY_SaveMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup); -+ _PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2t ? "2T2R" : "1T1R"), t)); -+ -+ _PHY_PathADDAOn(adapt, ADDA_REG, true, is2t); -+ if (t == 0) -+ dm_odm->RFCalibrateInfo.bRfPiEnable = (u8)ODM_GetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, BIT(8)); -+ -+ if (!dm_odm->RFCalibrateInfo.bRfPiEnable) { -+ /* Switch BB to PI mode to do IQ Calibration. */ -+ _PHY_PIModeSwitch(adapt, true); -+ } -+ -+ /* BB setting */ -+ ODM_SetBBReg(dm_odm, rFPGA0_RFMOD, BIT24, 0x00); -+ ODM_SetBBReg(dm_odm, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600); -+ ODM_SetBBReg(dm_odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4); -+ ODM_SetBBReg(dm_odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000); -+ -+ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01); -+ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01); -+ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00); -+ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00); -+ -+ if (is2t) { -+ ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000); -+ ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000); -+ } -+ -+ /* MAC settings */ -+ _PHY_MACSettingCalibration(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup); -+ -+ /* Page B init */ -+ /* AP or IQK */ -+ ODM_SetBBReg(dm_odm, rConfig_AntA, bMaskDWord, 0x0f600000); -+ -+ if (is2t) -+ ODM_SetBBReg(dm_odm, rConfig_AntB, bMaskDWord, 0x0f600000); -+ -+ /* IQ calibration setting */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK setting!\n")); -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); -+ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00); -+ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800); -+ -+ for (i = 0; i < retryCount; i++) { -+ PathAOK = phy_PathA_IQK_8188E(adapt, is2t); -+ if (PathAOK == 0x01) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Tx IQK Success!!\n")); -+ result[t][0] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; -+ result[t][1] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; -+ break; -+ } -+ } -+ -+ for (i = 0; i < retryCount; i++) { -+ PathAOK = phy_PathA_RxIQK(adapt, is2t); -+ if (PathAOK == 0x03) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Success!!\n")); -+ result[t][2] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; -+ result[t][3] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; -+ break; -+ } else { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Fail!!\n")); -+ } -+ } -+ -+ if (0x00 == PathAOK) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK failed!!\n")); -+ } -+ -+ if (is2t) { -+ _PHY_PathAStandBy(adapt); -+ -+ /* Turn Path B ADDA on */ -+ _PHY_PathADDAOn(adapt, ADDA_REG, false, is2t); -+ -+ for (i = 0; i < retryCount; i++) { -+ PathBOK = phy_PathB_IQK_8188E(adapt); -+ if (PathBOK == 0x03) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK Success!!\n")); -+ result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; -+ result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; -+ result[t][6] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; -+ result[t][7] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; -+ break; -+ } else if (i == (retryCount - 1) && PathBOK == 0x01) { /* Tx IQK OK */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Only Tx IQK Success!!\n")); -+ result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; -+ result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; -+ } -+ } -+ -+ if (0x00 == PathBOK) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK failed!!\n")); -+ } -+ } -+ -+ /* Back to BB mode, load original value */ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Back to BB mode, load original value!\n")); -+ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0); -+ -+ if (t != 0) { -+ if (!dm_odm->RFCalibrateInfo.bRfPiEnable) { -+ /* Switch back BB to SI mode after finish IQ Calibration. */ -+ _PHY_PIModeSwitch(adapt, false); -+ } -+ -+ /* Reload ADDA power saving parameters */ -+ reload_adda_reg(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); -+ -+ /* Reload MAC parameters */ -+ _PHY_ReloadMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup); -+ -+ reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); -+ -+ /* Restore RX initial gain */ -+ ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3); -+ if (is2t) -+ ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3); -+ -+ /* load 0xe30 IQC default value */ -+ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); -+ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_IQCalibrate_8188E() <==\n")); -+} -+ -+static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t) -+{ -+ u8 tmpreg; -+ u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ /* Check continuous TX and Packet TX */ -+ tmpreg = ODM_Read1Byte(dm_odm, 0xd03); -+ -+ if ((tmpreg&0x70) != 0) /* Deal with contisuous TX case */ -+ ODM_Write1Byte(dm_odm, 0xd03, tmpreg&0x8F); /* disable all continuous TX */ -+ else /* Deal with Packet TX case */ -+ ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0xFF); /* block all queues */ -+ -+ if ((tmpreg&0x70) != 0) { -+ /* 1. Read original RF mode */ -+ /* Path-A */ -+ RF_Amode = PHY_QueryRFReg(adapt, RF_PATH_A, RF_AC, bMask12Bits); -+ -+ /* Path-B */ -+ if (is2t) -+ RF_Bmode = PHY_QueryRFReg(adapt, RF_PATH_B, RF_AC, bMask12Bits); -+ -+ /* 2. Set RF mode = standby mode */ -+ /* Path-A */ -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000); -+ -+ /* Path-B */ -+ if (is2t) -+ ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000); -+ } -+ -+ /* 3. Read RF reg18 */ -+ LC_Cal = PHY_QueryRFReg(adapt, RF_PATH_A, RF_CHNLBW, bMask12Bits); -+ -+ /* 4. Set LC calibration begin bit15 */ -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000); -+ -+ ODM_sleep_ms(100); -+ -+ /* Restore original situation */ -+ if ((tmpreg&0x70) != 0) { -+ /* Deal with continuous TX case */ -+ /* Path-A */ -+ ODM_Write1Byte(dm_odm, 0xd03, tmpreg); -+ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode); -+ -+ /* Path-B */ -+ if (is2t) -+ ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode); -+ } else { -+ /* Deal with Packet TX case */ -+ ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0x00); -+ } -+} -+ -+void PHY_IQCalibrate_8188E(struct adapter *adapt, bool recovery) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx); -+ s32 result[4][8]; /* last is final result */ -+ u8 i, final_candidate, Indexforchannel; -+ bool pathaok, pathbok; -+ s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC; -+ bool is12simular, is13simular, is23simular; -+ bool singletone = false, carrier_sup = false; -+ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { -+ rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, -+ rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, -+ rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance, -+ rOFDM0_XCTxAFE, rOFDM0_XDTxAFE, -+ rOFDM0_RxIQExtAnta}; -+ bool is2t; -+ -+ is2t = (dm_odm->RFType == ODM_2T2R) ? true : false; -+ if (!ODM_CheckPowerStatus(adapt)) -+ return; -+ -+ if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION)) -+ return; -+ -+ if (*(dm_odm->mp_mode) == 1) { -+ singletone = pMptCtx->bSingleTone; -+ carrier_sup = pMptCtx->bCarrierSuppression; -+ } -+ -+ /* 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) */ -+ if (singletone || carrier_sup) -+ return; -+ -+ if (recovery) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("PHY_IQCalibrate_8188E: Return due to recovery!\n")); -+ reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); -+ return; -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Start!!!\n")); -+ -+ for (i = 0; i < 8; i++) { -+ result[0][i] = 0; -+ result[1][i] = 0; -+ result[2][i] = 0; -+ if ((i == 0) || (i == 2) || (i == 4) || (i == 6)) -+ result[3][i] = 0x100; -+ else -+ result[3][i] = 0; -+ } -+ final_candidate = 0xff; -+ pathaok = false; -+ pathbok = false; -+ is12simular = false; -+ is23simular = false; -+ is13simular = false; -+ -+ for (i = 0; i < 3; i++) { -+ phy_IQCalibrate_8188E(adapt, result, i, is2t); -+ -+ if (i == 1) { -+ is12simular = phy_SimularityCompare_8188E(adapt, result, 0, 1); -+ if (is12simular) { -+ final_candidate = 0; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is12simular final_candidate is %x\n", final_candidate)); -+ break; -+ } -+ } -+ -+ if (i == 2) { -+ is13simular = phy_SimularityCompare_8188E(adapt, result, 0, 2); -+ if (is13simular) { -+ final_candidate = 0; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is13simular final_candidate is %x\n", final_candidate)); -+ -+ break; -+ } -+ is23simular = phy_SimularityCompare_8188E(adapt, result, 1, 2); -+ if (is23simular) { -+ final_candidate = 1; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is23simular final_candidate is %x\n", final_candidate)); -+ } else { -+ final_candidate = 3; -+ } -+ } -+ } -+ -+ for (i = 0; i < 4; i++) { -+ RegE94 = result[i][0]; -+ RegE9C = result[i][1]; -+ RegEA4 = result[i][2]; -+ RegEAC = result[i][3]; -+ RegEB4 = result[i][4]; -+ RegEBC = result[i][5]; -+ RegEC4 = result[i][6]; -+ RegECC = result[i][7]; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n", -+ RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); -+ } -+ -+ if (final_candidate != 0xff) { -+ RegE94 = result[final_candidate][0]; -+ RegE9C = result[final_candidate][1]; -+ RegEA4 = result[final_candidate][2]; -+ RegEAC = result[final_candidate][3]; -+ RegEB4 = result[final_candidate][4]; -+ RegEBC = result[final_candidate][5]; -+ dm_odm->RFCalibrateInfo.RegE94 = RegE94; -+ dm_odm->RFCalibrateInfo.RegE9C = RegE9C; -+ dm_odm->RFCalibrateInfo.RegEB4 = RegEB4; -+ dm_odm->RFCalibrateInfo.RegEBC = RegEBC; -+ RegEC4 = result[final_candidate][6]; -+ RegECC = result[final_candidate][7]; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("IQK: final_candidate is %x\n", final_candidate)); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n", -+ RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); -+ pathaok = true; -+ pathbok = true; -+ } else { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: FAIL use default value\n")); -+ dm_odm->RFCalibrateInfo.RegE94 = 0x100; -+ dm_odm->RFCalibrateInfo.RegEB4 = 0x100; /* X default value */ -+ dm_odm->RFCalibrateInfo.RegE9C = 0x0; -+ dm_odm->RFCalibrateInfo.RegEBC = 0x0; /* Y default value */ -+ } -+ if (RegE94 != 0) -+ patha_fill_iqk(adapt, pathaok, result, final_candidate, (RegEA4 == 0)); -+ if (is2t) { -+ if (RegEB4 != 0) -+ pathb_fill_iqk(adapt, pathbok, result, final_candidate, (RegEC4 == 0)); -+ } -+ -+ Indexforchannel = ODM_GetRightChnlPlaceforIQK(pHalData->CurrentChannel); -+ -+/* To Fix BSOD when final_candidate is 0xff */ -+/* by sherry 20120321 */ -+ if (final_candidate < 4) { -+ for (i = 0; i < IQK_Matrix_REG_NUM; i++) -+ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][i] = result[final_candidate][i]; -+ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].bIQKDone = true; -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); -+ -+ _PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK finished\n")); -+} -+ -+void PHY_LCCalibrate_8188E(struct adapter *adapt) -+{ -+ bool singletone = false, carrier_sup = false; -+ u32 timeout = 2000, timecount = 0; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx); -+ -+ if (*(dm_odm->mp_mode) == 1) { -+ singletone = pMptCtx->bSingleTone; -+ carrier_sup = pMptCtx->bCarrierSuppression; -+ } -+ if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION)) -+ return; -+ /* 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) */ -+ if (singletone || carrier_sup) -+ return; -+ -+ while (*(dm_odm->pbScanInProcess) && timecount < timeout) { -+ ODM_delay_ms(50); -+ timecount += 50; -+ } -+ -+ dm_odm->RFCalibrateInfo.bLCKInProgress = true; -+ -+ if (dm_odm->RFType == ODM_2T2R) { -+ phy_LCCalibrate_8188E(adapt, true); -+ } else { -+ /* For 88C 1T1R */ -+ phy_LCCalibrate_8188E(adapt, false); -+ } -+ -+ dm_odm->RFCalibrateInfo.bLCKInProgress = false; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, -+ ("LCK:Finish!!!interface %d\n", dm_odm->InterfaceIndex)); -+} -+ -+static void phy_setrfpathswitch_8188e(struct adapter *adapt, bool main, bool is2t) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ if (!adapt->hw_init_completed) { -+ u8 u1btmp; -+ u1btmp = ODM_Read1Byte(dm_odm, REG_LEDCFG2) | BIT7; -+ ODM_Write1Byte(dm_odm, REG_LEDCFG2, u1btmp); -+ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFParameter, BIT13, 0x01); -+ } -+ -+ if (is2t) { /* 92C */ -+ if (main) -+ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x1); /* 92C_Path_A */ -+ else -+ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x2); /* BT */ -+ } else { /* 88C */ -+ if (main) -+ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x2); /* Main */ -+ else -+ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x1); /* Aux */ -+ } -+} -+ -+void PHY_SetRFPathSwitch_8188E(struct adapter *adapt, bool main) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); -+ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; -+ -+ if (dm_odm->RFType == ODM_2T2R) { -+ phy_setrfpathswitch_8188e(adapt, main, true); -+ } else { -+ /* For 88C 1T1R */ -+ phy_setrfpathswitch_8188e(adapt, main, false); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/HalPwrSeqCmd.c b/drivers/net/wireless/rtl8188eu/hal/HalPwrSeqCmd.c -new file mode 100644 -index 0000000000000..5700dbce5b8c5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/HalPwrSeqCmd.c -@@ -0,0 +1,132 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+/*++ -+Copyright (c) Realtek Semiconductor Corp. All rights reserved. -+ -+Module Name: -+ HalPwrSeqCmd.c -+ -+Abstract: -+ Implement HW Power sequence configuration CMD handling routine for Realtek devices. -+ -+Major Change History: -+ When Who What -+ ---------- --------------- ------------------------------- -+ 2011-10-26 Lucas Modify to be compatible with SD4-CE driver. -+ 2011-07-07 Roger Create. -+ -+--*/ -+ -+#include -+ -+/* Description: */ -+/* This routine deals with the Power Configuration CMDs parsing -+ * for RTL8723/RTL8188E Series IC. -+ * Assumption: -+ * We should follow specific format which was released from HW SD. -+ */ -+u8 HalPwrSeqCmdParsing(struct adapter *padapter, u8 cut_vers, u8 fab_vers, -+ u8 ifacetype, struct wl_pwr_cfg pwrseqcmd[]) -+{ -+ struct wl_pwr_cfg pwrcfgcmd = {0}; -+ u8 poll_bit = false; -+ u32 aryidx = 0; -+ u8 value = 0; -+ u32 offset = 0; -+ u32 poll_count = 0; /* polling autoload done. */ -+ u32 max_poll_count = 5000; -+ -+ do { -+ pwrcfgcmd = pwrseqcmd[aryidx]; -+ -+ RT_TRACE(_module_hal_init_c_ , _drv_info_, -+ ("HalPwrSeqCmdParsing: offset(%#x) cut_msk(%#x) fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) msk(%#x) value(%#x)\n", -+ GET_PWR_CFG_OFFSET(pwrcfgcmd), -+ GET_PWR_CFG_CUT_MASK(pwrcfgcmd), -+ GET_PWR_CFG_FAB_MASK(pwrcfgcmd), -+ GET_PWR_CFG_INTF_MASK(pwrcfgcmd), -+ GET_PWR_CFG_BASE(pwrcfgcmd), -+ GET_PWR_CFG_CMD(pwrcfgcmd), -+ GET_PWR_CFG_MASK(pwrcfgcmd), -+ GET_PWR_CFG_VALUE(pwrcfgcmd))); -+ -+ /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */ -+ if ((GET_PWR_CFG_FAB_MASK(pwrcfgcmd) & fab_vers) && -+ (GET_PWR_CFG_CUT_MASK(pwrcfgcmd) & cut_vers) && -+ (GET_PWR_CFG_INTF_MASK(pwrcfgcmd) & ifacetype)) { -+ switch (GET_PWR_CFG_CMD(pwrcfgcmd)) { -+ case PWR_CMD_READ: -+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_READ\n")); -+ break; -+ case PWR_CMD_WRITE: -+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_WRITE\n")); -+ offset = GET_PWR_CFG_OFFSET(pwrcfgcmd); -+ -+ /* Read the value from system register */ -+ value = rtw_read8(padapter, offset); -+ -+ value &= ~(GET_PWR_CFG_MASK(pwrcfgcmd)); -+ value |= (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd)); -+ -+ /* Write the value back to system register */ -+ rtw_write8(padapter, offset, value); -+ break; -+ case PWR_CMD_POLLING: -+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_POLLING\n")); -+ -+ poll_bit = false; -+ offset = GET_PWR_CFG_OFFSET(pwrcfgcmd); -+ do { -+ value = rtw_read8(padapter, offset); -+ -+ value &= GET_PWR_CFG_MASK(pwrcfgcmd); -+ if (value == (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd))) -+ poll_bit = true; -+ else -+ rtw_udelay_os(10); -+ -+ if (poll_count++ > max_poll_count) { -+ DBG_88E("Fail to polling Offset[%#x]\n", offset); -+ return false; -+ } -+ } while (!poll_bit); -+ break; -+ case PWR_CMD_DELAY: -+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_DELAY\n")); -+ if (GET_PWR_CFG_VALUE(pwrcfgcmd) == PWRSEQ_DELAY_US) -+ rtw_udelay_os(GET_PWR_CFG_OFFSET(pwrcfgcmd)); -+ else -+ rtw_udelay_os(GET_PWR_CFG_OFFSET(pwrcfgcmd)*1000); -+ break; -+ case PWR_CMD_END: -+ /* When this command is parsed, end the process */ -+ RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_END\n")); -+ return true; -+ break; -+ default: -+ RT_TRACE(_module_hal_init_c_ , _drv_err_, ("HalPwrSeqCmdParsing: Unknown CMD!!\n")); -+ break; -+ } -+ } -+ -+ aryidx++;/* Add Array Index */ -+ } while (1); -+ return true; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/hal_com.c b/drivers/net/wireless/rtl8188eu/hal/hal_com.c -new file mode 100644 -index 0000000000000..60ff30f1c3ac5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/hal_com.c -@@ -0,0 +1,381 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#include -+#include -+ -+#include -+#include -+#include -+ -+#define _HAL_INIT_C_ -+ -+void dump_chip_info(struct HAL_VERSION chip_vers) -+{ -+ uint cnt = 0; -+ char buf[128]; -+ -+ if (IS_81XXC(chip_vers)) { -+ cnt += sprintf((buf+cnt), "Chip Version Info: %s_", -+ IS_92C_SERIAL(chip_vers) ? -+ "CHIP_8192C" : "CHIP_8188C"); -+ } else if (IS_92D(chip_vers)) { -+ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8192D_"); -+ } else if (IS_8723_SERIES(chip_vers)) { -+ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8723A_"); -+ } else if (IS_8188E(chip_vers)) { -+ cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_"); -+ } -+ -+ cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ? -+ "Normal_Chip" : "Test_Chip"); -+ cnt += sprintf((buf+cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ? -+ "TSMC" : "UMC"); -+ if (IS_A_CUT(chip_vers)) -+ cnt += sprintf((buf+cnt), "A_CUT_"); -+ else if (IS_B_CUT(chip_vers)) -+ cnt += sprintf((buf+cnt), "B_CUT_"); -+ else if (IS_C_CUT(chip_vers)) -+ cnt += sprintf((buf+cnt), "C_CUT_"); -+ else if (IS_D_CUT(chip_vers)) -+ cnt += sprintf((buf+cnt), "D_CUT_"); -+ else if (IS_E_CUT(chip_vers)) -+ cnt += sprintf((buf+cnt), "E_CUT_"); -+ else -+ cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_", -+ chip_vers.CUTVersion); -+ -+ if (IS_1T1R(chip_vers)) -+ cnt += sprintf((buf+cnt), "1T1R_"); -+ else if (IS_1T2R(chip_vers)) -+ cnt += sprintf((buf+cnt), "1T2R_"); -+ else if (IS_2T2R(chip_vers)) -+ cnt += sprintf((buf+cnt), "2T2R_"); -+ else -+ cnt += sprintf((buf+cnt), "UNKNOWN_RFTYPE(%d)_", -+ chip_vers.RFType); -+ -+ cnt += sprintf((buf+cnt), "RomVer(%d)\n", chip_vers.ROMVer); -+ -+ pr_info("%s", buf); -+} -+ -+#define CHAN_PLAN_HW 0x80 -+ -+u8 /* return the final channel plan decision */ -+hal_com_get_channel_plan(struct adapter *padapter, u8 hw_channel_plan, -+ u8 sw_channel_plan, u8 def_channel_plan, -+ bool load_fail) -+{ -+ u8 sw_cfg; -+ u8 chnlplan; -+ -+ sw_cfg = true; -+ if (!load_fail) { -+ if (!rtw_is_channel_plan_valid(sw_channel_plan)) -+ sw_cfg = false; -+ if (hw_channel_plan & CHAN_PLAN_HW) -+ sw_cfg = false; -+ } -+ -+ if (sw_cfg) -+ chnlplan = sw_channel_plan; -+ else -+ chnlplan = hw_channel_plan & (~CHAN_PLAN_HW); -+ -+ if (!rtw_is_channel_plan_valid(chnlplan)) -+ chnlplan = def_channel_plan; -+ -+ return chnlplan; -+} -+ -+u8 MRateToHwRate(u8 rate) -+{ -+ u8 ret = DESC_RATE1M; -+ -+ switch (rate) { -+ /* CCK and OFDM non-HT rates */ -+ case IEEE80211_CCK_RATE_1MB: -+ ret = DESC_RATE1M; -+ break; -+ case IEEE80211_CCK_RATE_2MB: -+ ret = DESC_RATE2M; -+ break; -+ case IEEE80211_CCK_RATE_5MB: -+ ret = DESC_RATE5_5M; -+ break; -+ case IEEE80211_CCK_RATE_11MB: -+ ret = DESC_RATE11M; -+ break; -+ case IEEE80211_OFDM_RATE_6MB: -+ ret = DESC_RATE6M; -+ break; -+ case IEEE80211_OFDM_RATE_9MB: -+ ret = DESC_RATE9M; -+ break; -+ case IEEE80211_OFDM_RATE_12MB: -+ ret = DESC_RATE12M; -+ break; -+ case IEEE80211_OFDM_RATE_18MB: -+ ret = DESC_RATE18M; -+ break; -+ case IEEE80211_OFDM_RATE_24MB: -+ ret = DESC_RATE24M; -+ break; -+ case IEEE80211_OFDM_RATE_36MB: -+ ret = DESC_RATE36M; -+ break; -+ case IEEE80211_OFDM_RATE_48MB: -+ ret = DESC_RATE48M; -+ break; -+ case IEEE80211_OFDM_RATE_54MB: -+ ret = DESC_RATE54M; -+ break; -+ default: -+ break; -+ } -+ return ret; -+} -+ -+void HalSetBrateCfg(struct adapter *adapt, u8 *brates, u16 *rate_cfg) -+{ -+ u8 i, is_brate, brate; -+ -+ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { -+ is_brate = brates[i] & IEEE80211_BASIC_RATE_MASK; -+ brate = brates[i] & 0x7f; -+ -+ if (is_brate) { -+ switch (brate) { -+ case IEEE80211_CCK_RATE_1MB: -+ *rate_cfg |= RATE_1M; -+ break; -+ case IEEE80211_CCK_RATE_2MB: -+ *rate_cfg |= RATE_2M; -+ break; -+ case IEEE80211_CCK_RATE_5MB: -+ *rate_cfg |= RATE_5_5M; -+ break; -+ case IEEE80211_CCK_RATE_11MB: -+ *rate_cfg |= RATE_11M; -+ break; -+ case IEEE80211_OFDM_RATE_6MB: -+ *rate_cfg |= RATE_6M; -+ break; -+ case IEEE80211_OFDM_RATE_9MB: -+ *rate_cfg |= RATE_9M; -+ break; -+ case IEEE80211_OFDM_RATE_12MB: -+ *rate_cfg |= RATE_12M; -+ break; -+ case IEEE80211_OFDM_RATE_18MB: -+ *rate_cfg |= RATE_18M; -+ break; -+ case IEEE80211_OFDM_RATE_24MB: -+ *rate_cfg |= RATE_24M; -+ break; -+ case IEEE80211_OFDM_RATE_36MB: -+ *rate_cfg |= RATE_36M; -+ break; -+ case IEEE80211_OFDM_RATE_48MB: -+ *rate_cfg |= RATE_48M; -+ break; -+ case IEEE80211_OFDM_RATE_54MB: -+ *rate_cfg |= RATE_54M; -+ break; -+ } -+ } -+ } -+} -+ -+static void one_out_pipe(struct adapter *adapter) -+{ -+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter); -+ -+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ -+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ -+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */ -+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ -+ -+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ -+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ -+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ -+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ -+} -+ -+static void two_out_pipe(struct adapter *adapter, bool wifi_cfg) -+{ -+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter); -+ -+ if (wifi_cfg) { /* WMM */ -+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ -+ /* 0, 1, 0, 1, 0, 0, 0, 0, 0}; */ -+ /* 0:H, 1:L */ -+ -+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */ -+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ -+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ -+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ -+ -+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ -+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ -+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ -+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ -+ -+ } else {/* typical setting */ -+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ -+ /* 1, 1, 0, 0, 0, 0, 0, 0, 0}; */ -+ /* 0:H, 1:L */ -+ -+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ -+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ -+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ -+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ -+ -+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ -+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ -+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ -+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ -+ } -+} -+ -+static void three_out_pipe(struct adapter *adapter, bool wifi_cfg) -+{ -+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter); -+ -+ if (wifi_cfg) {/* for WMM */ -+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ -+ /* 1, 2, 1, 0, 0, 0, 0, 0, 0}; */ -+ /* 0:H, 1:N, 2:L */ -+ -+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ -+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ -+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ -+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ -+ -+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ -+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ -+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ -+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ -+ -+ } else {/* typical setting */ -+ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ -+ /* 2, 2, 1, 0, 0, 0, 0, 0, 0}; */ -+ /* 0:H, 1:N, 2:L */ -+ -+ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ -+ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ -+ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ -+ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */ -+ -+ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ -+ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ -+ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ -+ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ -+ } -+} -+ -+bool Hal_MappingOutPipe(struct adapter *adapter, u8 numoutpipe) -+{ -+ struct registry_priv *pregistrypriv = &adapter->registrypriv; -+ bool wifi_cfg = (pregistrypriv->wifi_spec) ? true : false; -+ bool result = true; -+ -+ switch (numoutpipe) { -+ case 2: -+ two_out_pipe(adapter, wifi_cfg); -+ break; -+ case 3: -+ three_out_pipe(adapter, wifi_cfg); -+ break; -+ case 1: -+ one_out_pipe(adapter); -+ break; -+ default: -+ result = false; -+ break; -+ } -+ return result; -+} -+ -+void hal_init_macaddr(struct adapter *adapter) -+{ -+ rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR, -+ adapter->eeprompriv.mac_addr); -+} -+ -+/* -+* C2H event format: -+* Field TRIGGER CONTENT CMD_SEQ CMD_LEN CMD_ID -+* BITS [127:120] [119:16] [15:8] [7:4] [3:0] -+*/ -+ -+void c2h_evt_clear(struct adapter *adapter) -+{ -+ rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); -+} -+ -+s32 c2h_evt_read(struct adapter *adapter, u8 *buf) -+{ -+ s32 ret = _FAIL; -+ struct c2h_evt_hdr *c2h_evt; -+ int i; -+ u8 trigger; -+ -+ if (buf == NULL) -+ goto exit; -+ -+ trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); -+ -+ if (trigger == C2H_EVT_HOST_CLOSE) -+ goto exit; /* Not ready */ -+ else if (trigger != C2H_EVT_FW_CLOSE) -+ goto clear_evt; /* Not a valid value */ -+ -+ c2h_evt = (struct c2h_evt_hdr *)buf; -+ -+ memset(c2h_evt, 0, 16); -+ -+ *buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); -+ *(buf+1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1); -+ -+ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): ", -+ &c2h_evt , sizeof(c2h_evt)); -+ -+ /* Read the content */ -+ for (i = 0; i < c2h_evt->plen; i++) -+ c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + -+ sizeof(*c2h_evt) + i); -+ -+ RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, -+ "c2h_evt_read(): Command Content:\n", -+ c2h_evt->payload, c2h_evt->plen); -+ -+ ret = _SUCCESS; -+ -+clear_evt: -+ /* -+ * Clear event to notify FW we have read the command. -+ * If this field isn't clear, the FW won't update the next -+ * command message. -+ */ -+ c2h_evt_clear(adapter); -+exit: -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/hal_intf.c b/drivers/net/wireless/rtl8188eu/hal/hal_intf.c -new file mode 100644 -index 0000000000000..ce37c7594f2dc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/hal_intf.c -@@ -0,0 +1,468 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2012 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#define _HAL_INTF_C_ -+#include -+#include -+#include -+#include -+ -+void rtw_hal_chip_configure(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.intf_chip_configure) -+ adapt->HalFunc.intf_chip_configure(adapt); -+} -+ -+void rtw_hal_read_chip_info(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.read_adapter_info) -+ adapt->HalFunc.read_adapter_info(adapt); -+} -+ -+void rtw_hal_read_chip_version(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.read_chip_version) -+ adapt->HalFunc.read_chip_version(adapt); -+} -+ -+void rtw_hal_def_value_init(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.init_default_value) -+ adapt->HalFunc.init_default_value(adapt); -+} -+ -+void rtw_hal_free_data(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.free_hal_data) -+ adapt->HalFunc.free_hal_data(adapt); -+} -+ -+void rtw_hal_dm_init(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.dm_init) -+ adapt->HalFunc.dm_init(adapt); -+} -+ -+void rtw_hal_dm_deinit(struct adapter *adapt) -+{ -+ /* cancel dm timer */ -+ if (adapt->HalFunc.dm_deinit) -+ adapt->HalFunc.dm_deinit(adapt); -+} -+ -+void rtw_hal_sw_led_init(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.InitSwLeds) -+ adapt->HalFunc.InitSwLeds(adapt); -+} -+ -+void rtw_hal_sw_led_deinit(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.DeInitSwLeds) -+ adapt->HalFunc.DeInitSwLeds(adapt); -+} -+ -+u32 rtw_hal_power_on(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.hal_power_on) -+ return adapt->HalFunc.hal_power_on(adapt); -+ return _FAIL; -+} -+ -+uint rtw_hal_init(struct adapter *adapt) -+{ -+ uint status = _SUCCESS; -+ -+ adapt->hw_init_completed = false; -+ -+ status = adapt->HalFunc.hal_init(adapt); -+ -+ if (status == _SUCCESS) { -+ adapt->hw_init_completed = true; -+ -+ if (adapt->registrypriv.notch_filter == 1) -+ rtw_hal_notch_filter(adapt, 1); -+ -+ rtw_hal_reset_security_engine(adapt); -+ } else { -+ adapt->hw_init_completed = false; -+ DBG_88E("rtw_hal_init: hal__init fail\n"); -+ } -+ -+ RT_TRACE(_module_hal_init_c_, _drv_err_, -+ ("-rtl871x_hal_init:status=0x%x\n", status)); -+ -+ return status; -+} -+ -+uint rtw_hal_deinit(struct adapter *adapt) -+{ -+ uint status = _SUCCESS; -+ -+ status = adapt->HalFunc.hal_deinit(adapt); -+ -+ if (status == _SUCCESS) -+ adapt->hw_init_completed = false; -+ else -+ DBG_88E("\n rtw_hal_deinit: hal_init fail\n"); -+ -+ return status; -+} -+ -+void rtw_hal_set_hwreg(struct adapter *adapt, u8 variable, u8 *val) -+{ -+ if (adapt->HalFunc.SetHwRegHandler) -+ adapt->HalFunc.SetHwRegHandler(adapt, variable, val); -+} -+ -+void rtw_hal_get_hwreg(struct adapter *adapt, u8 variable, u8 *val) -+{ -+ if (adapt->HalFunc.GetHwRegHandler) -+ adapt->HalFunc.GetHwRegHandler(adapt, variable, val); -+} -+ -+u8 rtw_hal_set_def_var(struct adapter *adapt, enum hal_def_variable var, -+ void *val) -+{ -+ if (adapt->HalFunc.SetHalDefVarHandler) -+ return adapt->HalFunc.SetHalDefVarHandler(adapt, var, val); -+ return _FAIL; -+} -+ -+u8 rtw_hal_get_def_var(struct adapter *adapt, -+ enum hal_def_variable var, void *val) -+{ -+ if (adapt->HalFunc.GetHalDefVarHandler) -+ return adapt->HalFunc.GetHalDefVarHandler(adapt, var, val); -+ return _FAIL; -+} -+ -+void rtw_hal_set_odm_var(struct adapter *adapt, -+ enum hal_odm_variable var, void *val1, -+ bool set) -+{ -+ if (adapt->HalFunc.SetHalODMVarHandler) -+ adapt->HalFunc.SetHalODMVarHandler(adapt, var, -+ val1, set); -+} -+ -+void rtw_hal_get_odm_var(struct adapter *adapt, -+ enum hal_odm_variable var, void *val1, -+ bool set) -+{ -+ if (adapt->HalFunc.GetHalODMVarHandler) -+ adapt->HalFunc.GetHalODMVarHandler(adapt, var, -+ val1, set); -+} -+ -+void rtw_hal_enable_interrupt(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.enable_interrupt) -+ adapt->HalFunc.enable_interrupt(adapt); -+ else -+ DBG_88E("%s: HalFunc.enable_interrupt is NULL!\n", __func__); -+} -+ -+void rtw_hal_disable_interrupt(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.disable_interrupt) -+ adapt->HalFunc.disable_interrupt(adapt); -+ else -+ DBG_88E("%s: HalFunc.disable_interrupt is NULL!\n", __func__); -+} -+ -+u32 rtw_hal_inirp_init(struct adapter *adapt) -+{ -+ u32 rst = _FAIL; -+ -+ if (adapt->HalFunc.inirp_init) -+ rst = adapt->HalFunc.inirp_init(adapt); -+ else -+ DBG_88E(" %s HalFunc.inirp_init is NULL!!!\n", __func__); -+ return rst; -+} -+ -+u32 rtw_hal_inirp_deinit(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.inirp_deinit) -+ return adapt->HalFunc.inirp_deinit(adapt); -+ -+ return _FAIL; -+} -+ -+u8 rtw_hal_intf_ps_func(struct adapter *adapt, -+ enum hal_intf_ps_func efunc_id, u8 *val) -+{ -+ if (adapt->HalFunc.interface_ps_func) -+ return adapt->HalFunc.interface_ps_func(adapt, efunc_id, -+ val); -+ return _FAIL; -+} -+ -+s32 rtw_hal_xmitframe_enqueue(struct adapter *padapter, -+ struct xmit_frame *pxmitframe) -+{ -+ if(padapter->HalFunc.hal_xmitframe_enqueue) -+ return padapter->HalFunc.hal_xmitframe_enqueue(padapter, pxmitframe); -+ return false; -+} -+ -+s32 rtw_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe) -+{ -+ if (adapt->HalFunc.hal_xmit) -+ return adapt->HalFunc.hal_xmit(adapt, pxmitframe); -+ -+ return false; -+} -+ -+s32 rtw_hal_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe) -+{ -+ s32 ret = _FAIL; -+ if (adapt->HalFunc.mgnt_xmit) -+ ret = adapt->HalFunc.mgnt_xmit(adapt, pmgntframe); -+ return ret; -+} -+ -+s32 rtw_hal_init_xmit_priv(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.init_xmit_priv != NULL) -+ return adapt->HalFunc.init_xmit_priv(adapt); -+ return _FAIL; -+} -+ -+void rtw_hal_free_xmit_priv(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.free_xmit_priv != NULL) -+ adapt->HalFunc.free_xmit_priv(adapt); -+} -+ -+s32 rtw_hal_init_recv_priv(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.init_recv_priv) -+ return adapt->HalFunc.init_recv_priv(adapt); -+ -+ return _FAIL; -+} -+ -+void rtw_hal_free_recv_priv(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.free_recv_priv) -+ adapt->HalFunc.free_recv_priv(adapt); -+} -+ -+void rtw_hal_update_ra_mask(struct adapter *adapt, u32 mac_id, u8 rssi_level) -+{ -+ struct mlme_priv *pmlmepriv = &(adapt->mlmepriv); -+ -+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { -+#ifdef CONFIG_88EU_AP_MODE -+ struct sta_info *psta = NULL; -+ struct sta_priv *pstapriv = &adapt->stapriv; -+ if ((mac_id-1) > 0) -+ psta = pstapriv->sta_aid[(mac_id-1) - 1]; -+ if (psta) -+ add_RATid(adapt, psta, 0);/* todo: based on rssi_level*/ -+#endif -+ } else { -+ if (adapt->HalFunc.UpdateRAMaskHandler) -+ adapt->HalFunc.UpdateRAMaskHandler(adapt, mac_id, -+ rssi_level); -+ } -+} -+ -+void rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg, -+ u8 rssi_level) -+{ -+ if (adapt->HalFunc.Add_RateATid) -+ adapt->HalFunc.Add_RateATid(adapt, bitmap, arg, -+ rssi_level); -+} -+ -+/* Start specifical interface thread */ -+void rtw_hal_start_thread(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.run_thread) -+ adapt->HalFunc.run_thread(adapt); -+} -+ -+/* Start specifical interface thread */ -+void rtw_hal_stop_thread(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.cancel_thread) -+ adapt->HalFunc.cancel_thread(adapt); -+} -+ -+u32 rtw_hal_read_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask) -+{ -+ u32 data = 0; -+ -+ if (adapt->HalFunc.read_bbreg) -+ data = adapt->HalFunc.read_bbreg(adapt, regaddr, bitmask); -+ return data; -+} -+ -+void rtw_hal_write_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask, -+ u32 data) -+{ -+ if (adapt->HalFunc.write_bbreg) -+ adapt->HalFunc.write_bbreg(adapt, regaddr, bitmask, data); -+} -+ -+u32 rtw_hal_read_rfreg(struct adapter *adapt, enum rf_radio_path rfpath, -+ u32 regaddr, u32 bitmask) -+{ -+ u32 data = 0; -+ -+ if (adapt->HalFunc.read_rfreg) -+ data = adapt->HalFunc.read_rfreg(adapt, rfpath, regaddr, -+ bitmask); -+ return data; -+} -+ -+void rtw_hal_write_rfreg(struct adapter *adapt, enum rf_radio_path rfpath, -+ u32 regaddr, u32 bitmask, u32 data) -+{ -+ if (adapt->HalFunc.write_rfreg) -+ adapt->HalFunc.write_rfreg(adapt, rfpath, regaddr, -+ bitmask, data); -+} -+ -+s32 rtw_hal_interrupt_handler(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.interrupt_handler) -+ return adapt->HalFunc.interrupt_handler(adapt); -+ return _FAIL; -+} -+ -+void rtw_hal_set_bwmode(struct adapter *adapt, -+ enum ht_channel_width bandwidth, u8 offset) -+{ -+ if (adapt->HalFunc.set_bwmode_handler) -+ adapt->HalFunc.set_bwmode_handler(adapt, bandwidth, -+ offset); -+} -+ -+void rtw_hal_set_chan(struct adapter *adapt, u8 channel) -+{ -+ if (adapt->HalFunc.set_channel_handler) -+ adapt->HalFunc.set_channel_handler(adapt, channel); -+} -+ -+void rtw_hal_dm_watchdog(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.hal_dm_watchdog) -+ adapt->HalFunc.hal_dm_watchdog(adapt); -+} -+ -+void rtw_hal_bcn_related_reg_setting(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.SetBeaconRelatedRegistersHandler) -+ adapt->HalFunc.SetBeaconRelatedRegistersHandler(adapt); -+} -+ -+u8 rtw_hal_antdiv_before_linked(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.AntDivBeforeLinkHandler) -+ return adapt->HalFunc.AntDivBeforeLinkHandler(adapt); -+ return false; -+} -+ -+void rtw_hal_antdiv_rssi_compared(struct adapter *adapt, -+ struct wlan_bssid_ex *dst, -+ struct wlan_bssid_ex *src) -+{ -+ if (adapt->HalFunc.AntDivCompareHandler) -+ adapt->HalFunc.AntDivCompareHandler(adapt, dst, src); -+} -+ -+void rtw_hal_sreset_init(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.sreset_init_value) -+ adapt->HalFunc.sreset_init_value(adapt); -+} -+ -+void rtw_hal_sreset_reset(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.silentreset) -+ adapt->HalFunc.silentreset(adapt); -+} -+ -+void rtw_hal_sreset_reset_value(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.sreset_reset_value) -+ adapt->HalFunc.sreset_reset_value(adapt); -+} -+ -+void rtw_hal_sreset_xmit_status_check(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.sreset_xmit_status_check) -+ adapt->HalFunc.sreset_xmit_status_check(adapt); -+} -+ -+void rtw_hal_sreset_linked_status_check(struct adapter *adapt) -+{ -+ if (adapt->HalFunc.sreset_linked_status_check) -+ adapt->HalFunc.sreset_linked_status_check(adapt); -+} -+ -+u8 rtw_hal_sreset_get_wifi_status(struct adapter *adapt) -+{ -+ u8 status = 0; -+ -+ if (adapt->HalFunc.sreset_get_wifi_status) -+ status = adapt->HalFunc.sreset_get_wifi_status(adapt); -+ return status; -+} -+ -+int rtw_hal_iol_cmd(struct adapter *adapter, struct xmit_frame *xmit_frame, -+ u32 max_wating_ms, u32 bndy_cnt) -+{ -+ if (adapter->HalFunc.IOL_exec_cmds_sync) -+ return adapter->HalFunc.IOL_exec_cmds_sync(adapter, xmit_frame, -+ max_wating_ms, -+ bndy_cnt); -+ return _FAIL; -+} -+ -+void rtw_hal_notch_filter(struct adapter *adapter, bool enable) -+{ -+ if (adapter->HalFunc.hal_notch_filter) -+ adapter->HalFunc.hal_notch_filter(adapter, enable); -+} -+ -+void rtw_hal_reset_security_engine(struct adapter *adapter) -+{ -+ if (adapter->HalFunc.hal_reset_security_engine) -+ adapter->HalFunc.hal_reset_security_engine(adapter); -+} -+ -+s32 rtw_hal_c2h_handler(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt) -+{ -+ s32 ret = _FAIL; -+ -+ if (adapter->HalFunc.c2h_handler) -+ ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt); -+ return ret; -+} -+ -+c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter) -+{ -+ return adapter->HalFunc.c2h_id_filter_ccx; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/odm.c b/drivers/net/wireless/rtl8188eu/hal/odm.c -new file mode 100644 -index 0000000000000..8b8754c42bc10 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/odm.c -@@ -0,0 +1,2174 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+/* include files */ -+ -+#include "odm_precomp.h" -+ -+static const u16 dB_Invert_Table[8][12] = { -+ {1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4}, -+ {4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16}, -+ {18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63}, -+ {71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251}, -+ {282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000}, -+ {1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981}, -+ {4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, 15849}, -+ {17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535} -+}; -+ -+/* avoid to warn in FreeBSD ==> To DO modify */ -+static u32 EDCAParam[HT_IOT_PEER_MAX][3] = { -+ /* UL DL */ -+ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 0:unknown AP */ -+ {0xa44f, 0x5ea44f, 0x5e431c}, /* 1:realtek AP */ -+ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 2:unknown AP => realtek_92SE */ -+ {0x5ea32b, 0x5ea42b, 0x5e4322}, /* 3:broadcom AP */ -+ {0x5ea422, 0x00a44f, 0x00a44f}, /* 4:ralink AP */ -+ {0x5ea322, 0x00a630, 0x00a44f}, /* 5:atheros AP */ -+ {0x5e4322, 0x5e4322, 0x5e4322},/* 6:cisco AP */ -+ {0x5ea44f, 0x00a44f, 0x5ea42b}, /* 8:marvell AP */ -+ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 10:unknown AP=> 92U AP */ -+ {0x5ea42b, 0xa630, 0x5e431c}, /* 11:airgocap AP */ -+}; -+ -+/* Global var */ -+u32 OFDMSwingTable[OFDM_TABLE_SIZE_92D] = { -+ 0x7f8001fe, /* 0, +6.0dB */ -+ 0x788001e2, /* 1, +5.5dB */ -+ 0x71c001c7, /* 2, +5.0dB */ -+ 0x6b8001ae, /* 3, +4.5dB */ -+ 0x65400195, /* 4, +4.0dB */ -+ 0x5fc0017f, /* 5, +3.5dB */ -+ 0x5a400169, /* 6, +3.0dB */ -+ 0x55400155, /* 7, +2.5dB */ -+ 0x50800142, /* 8, +2.0dB */ -+ 0x4c000130, /* 9, +1.5dB */ -+ 0x47c0011f, /* 10, +1.0dB */ -+ 0x43c0010f, /* 11, +0.5dB */ -+ 0x40000100, /* 12, +0dB */ -+ 0x3c8000f2, /* 13, -0.5dB */ -+ 0x390000e4, /* 14, -1.0dB */ -+ 0x35c000d7, /* 15, -1.5dB */ -+ 0x32c000cb, /* 16, -2.0dB */ -+ 0x300000c0, /* 17, -2.5dB */ -+ 0x2d4000b5, /* 18, -3.0dB */ -+ 0x2ac000ab, /* 19, -3.5dB */ -+ 0x288000a2, /* 20, -4.0dB */ -+ 0x26000098, /* 21, -4.5dB */ -+ 0x24000090, /* 22, -5.0dB */ -+ 0x22000088, /* 23, -5.5dB */ -+ 0x20000080, /* 24, -6.0dB */ -+ 0x1e400079, /* 25, -6.5dB */ -+ 0x1c800072, /* 26, -7.0dB */ -+ 0x1b00006c, /* 27. -7.5dB */ -+ 0x19800066, /* 28, -8.0dB */ -+ 0x18000060, /* 29, -8.5dB */ -+ 0x16c0005b, /* 30, -9.0dB */ -+ 0x15800056, /* 31, -9.5dB */ -+ 0x14400051, /* 32, -10.0dB */ -+ 0x1300004c, /* 33, -10.5dB */ -+ 0x12000048, /* 34, -11.0dB */ -+ 0x11000044, /* 35, -11.5dB */ -+ 0x10000040, /* 36, -12.0dB */ -+ 0x0f00003c,/* 37, -12.5dB */ -+ 0x0e400039,/* 38, -13.0dB */ -+ 0x0d800036,/* 39, -13.5dB */ -+ 0x0cc00033,/* 40, -14.0dB */ -+ 0x0c000030,/* 41, -14.5dB */ -+ 0x0b40002d,/* 42, -15.0dB */ -+}; -+ -+u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = { -+ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ -+ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ -+ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */ -+ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */ -+ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ -+ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */ -+ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */ -+ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */ -+ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ -+ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */ -+ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ -+ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */ -+ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */ -+ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */ -+ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ -+ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */ -+ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ -+ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */ -+ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ -+ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */ -+ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */ -+ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */ -+ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */ -+ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */ -+ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */ -+ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */ -+ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */ -+ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */ -+ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */ -+ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */ -+ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */ -+ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */ -+ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB */ -+}; -+ -+u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = { -+ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ -+ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ -+ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ -+ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */ -+ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ -+ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */ -+ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ -+ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ -+ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ -+ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */ -+ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ -+ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */ -+ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */ -+ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ -+ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ -+ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */ -+ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ -+ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */ -+ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ -+ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */ -+ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */ -+ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */ -+ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */ -+ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */ -+ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */ -+ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */ -+ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */ -+ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */ -+ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */ -+ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */ -+ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */ -+ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */ -+ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ -+}; -+ -+#define RxDefaultAnt1 0x65a9 -+#define RxDefaultAnt2 0x569a -+ -+/* 3 Export Interface */ -+ -+/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */ -+void ODM_DMInit(struct odm_dm_struct *pDM_Odm) -+{ -+ /* 2012.05.03 Luke: For all IC series */ -+ odm_CommonInfoSelfInit(pDM_Odm); -+ odm_CmnInfoInit_Debug(pDM_Odm); -+ odm_DIGInit(pDM_Odm); -+ odm_RateAdaptiveMaskInit(pDM_Odm); -+ -+ if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { -+ ; -+ } else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { -+ odm_PrimaryCCA_Init(pDM_Odm); /* Gary */ -+ odm_DynamicBBPowerSavingInit(pDM_Odm); -+ odm_DynamicTxPowerInit(pDM_Odm); -+ odm_TXPowerTrackingInit(pDM_Odm); -+ ODM_EdcaTurboInit(pDM_Odm); -+ ODM_RAInfo_Init_all(pDM_Odm); -+ if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) || -+ (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) || -+ (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV)) -+ odm_InitHybridAntDiv(pDM_Odm); -+ else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) -+ odm_SwAntDivInit(pDM_Odm); -+ } -+} -+ -+/* 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */ -+/* You can not add any dummy function here, be care, you can only use DM structure */ -+/* to perform any new ODM_DM. */ -+void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm) -+{ -+ /* 2012.05.03 Luke: For all IC series */ -+ odm_GlobalAdapterCheck(); -+ odm_CmnInfoHook_Debug(pDM_Odm); -+ odm_CmnInfoUpdate_Debug(pDM_Odm); -+ odm_CommonInfoSelfUpdate(pDM_Odm); -+ odm_FalseAlarmCounterStatistics(pDM_Odm); -+ odm_RSSIMonitorCheck(pDM_Odm); -+ -+ /* For CE Platform(SPRD or Tablet) */ -+ /* 8723A or 8189ES platform */ -+ /* NeilChen--2012--08--24-- */ -+ /* Fix Leave LPS issue */ -+ if ((pDM_Odm->Adapter->pwrctrlpriv.pwr_mode != PS_MODE_ACTIVE) &&/* in LPS mode */ -+ ((pDM_Odm->SupportICType & (ODM_RTL8723A)) || -+ (pDM_Odm->SupportICType & (ODM_RTL8188E) && -+ ((pDM_Odm->SupportInterface == ODM_ITRF_SDIO))))) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n")); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n")); -+ odm_DIGbyRSSI_LPS(pDM_Odm); -+ } else { -+ odm_DIG(pDM_Odm); -+ } -+ odm_CCKPacketDetectionThresh(pDM_Odm); -+ -+ if (*(pDM_Odm->pbPowerSaving)) -+ return; -+ -+ odm_RefreshRateAdaptiveMask(pDM_Odm); -+ -+ odm_DynamicBBPowerSaving(pDM_Odm); -+ odm_DynamicPrimaryCCA(pDM_Odm); -+ if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) || -+ (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) || -+ (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV)) -+ odm_HwAntDiv(pDM_Odm); -+ else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) -+ odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK); -+ -+ if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { -+ ; -+ } else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { -+ ODM_TXPowerTrackingCheck(pDM_Odm); -+ odm_EdcaTurboCheck(pDM_Odm); -+ odm_DynamicTxPower(pDM_Odm); -+ } -+ odm_dtc(pDM_Odm); -+} -+ -+/* Init /.. Fixed HW value. Only init time. */ -+void ODM_CmnInfoInit(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u32 Value) -+{ -+ /* This section is used for init value */ -+ switch (CmnInfo) { -+ /* Fixed ODM value. */ -+ case ODM_CMNINFO_ABILITY: -+ pDM_Odm->SupportAbility = (u32)Value; -+ break; -+ case ODM_CMNINFO_PLATFORM: -+ pDM_Odm->SupportPlatform = (u8)Value; -+ break; -+ case ODM_CMNINFO_INTERFACE: -+ pDM_Odm->SupportInterface = (u8)Value; -+ break; -+ case ODM_CMNINFO_MP_TEST_CHIP: -+ pDM_Odm->bIsMPChip = (u8)Value; -+ break; -+ case ODM_CMNINFO_IC_TYPE: -+ pDM_Odm->SupportICType = Value; -+ break; -+ case ODM_CMNINFO_CUT_VER: -+ pDM_Odm->CutVersion = (u8)Value; -+ break; -+ case ODM_CMNINFO_FAB_VER: -+ pDM_Odm->FabVersion = (u8)Value; -+ break; -+ case ODM_CMNINFO_RF_TYPE: -+ pDM_Odm->RFType = (u8)Value; -+ break; -+ case ODM_CMNINFO_RF_ANTENNA_TYPE: -+ pDM_Odm->AntDivType = (u8)Value; -+ break; -+ case ODM_CMNINFO_BOARD_TYPE: -+ pDM_Odm->BoardType = (u8)Value; -+ break; -+ case ODM_CMNINFO_EXT_LNA: -+ pDM_Odm->ExtLNA = (u8)Value; -+ break; -+ case ODM_CMNINFO_EXT_PA: -+ pDM_Odm->ExtPA = (u8)Value; -+ break; -+ case ODM_CMNINFO_EXT_TRSW: -+ pDM_Odm->ExtTRSW = (u8)Value; -+ break; -+ case ODM_CMNINFO_PATCH_ID: -+ pDM_Odm->PatchID = (u8)Value; -+ break; -+ case ODM_CMNINFO_BINHCT_TEST: -+ pDM_Odm->bInHctTest = (bool)Value; -+ break; -+ case ODM_CMNINFO_BWIFI_TEST: -+ pDM_Odm->bWIFITest = (bool)Value; -+ break; -+ case ODM_CMNINFO_SMART_CONCURRENT: -+ pDM_Odm->bDualMacSmartConcurrent = (bool)Value; -+ break; -+ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ -+ default: -+ /* do nothing */ -+ break; -+ } -+ -+ /* Tx power tracking BB swing table. */ -+ /* The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */ -+ pDM_Odm->BbSwingIdxOfdm = 12; /* Set defalut value as index 12. */ -+ pDM_Odm->BbSwingIdxOfdmCurrent = 12; -+ pDM_Odm->BbSwingFlagOfdm = false; -+} -+ -+void ODM_CmnInfoHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, void *pValue) -+{ -+ /* */ -+ /* Hook call by reference pointer. */ -+ /* */ -+ switch (CmnInfo) { -+ /* Dynamic call by reference pointer. */ -+ case ODM_CMNINFO_MAC_PHY_MODE: -+ pDM_Odm->pMacPhyMode = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_TX_UNI: -+ pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue; -+ break; -+ case ODM_CMNINFO_RX_UNI: -+ pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue; -+ break; -+ case ODM_CMNINFO_WM_MODE: -+ pDM_Odm->pWirelessMode = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_BAND: -+ pDM_Odm->pBandType = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_SEC_CHNL_OFFSET: -+ pDM_Odm->pSecChOffset = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_SEC_MODE: -+ pDM_Odm->pSecurity = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_BW: -+ pDM_Odm->pBandWidth = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_CHNL: -+ pDM_Odm->pChannel = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_DMSP_GET_VALUE: -+ pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_BUDDY_ADAPTOR: -+ pDM_Odm->pBuddyAdapter = (struct adapter **)pValue; -+ break; -+ case ODM_CMNINFO_DMSP_IS_MASTER: -+ pDM_Odm->pbMasterOfDMSP = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_SCAN: -+ pDM_Odm->pbScanInProcess = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_POWER_SAVING: -+ pDM_Odm->pbPowerSaving = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_ONE_PATH_CCA: -+ pDM_Odm->pOnePathCCA = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_DRV_STOP: -+ pDM_Odm->pbDriverStopped = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_PNP_IN: -+ pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_INIT_ON: -+ pDM_Odm->pinit_adpt_in_progress = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_ANT_TEST: -+ pDM_Odm->pAntennaTest = (u8 *)pValue; -+ break; -+ case ODM_CMNINFO_NET_CLOSED: -+ pDM_Odm->pbNet_closed = (bool *)pValue; -+ break; -+ case ODM_CMNINFO_MP_MODE: -+ pDM_Odm->mp_mode = (u8 *)pValue; -+ break; -+ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ -+ default: -+ /* do nothing */ -+ break; -+ } -+} -+ -+void ODM_CmnInfoPtrArrayHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u16 Index, void *pValue) -+{ -+ /* Hook call by reference pointer. */ -+ switch (CmnInfo) { -+ /* Dynamic call by reference pointer. */ -+ case ODM_CMNINFO_STA_STATUS: -+ pDM_Odm->pODM_StaInfo[Index] = (struct sta_info *)pValue; -+ break; -+ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ -+ default: -+ /* do nothing */ -+ break; -+ } -+} -+ -+/* Update Band/CHannel/.. The values are dynamic but non-per-packet. */ -+void ODM_CmnInfoUpdate(struct odm_dm_struct *pDM_Odm, u32 CmnInfo, u64 Value) -+{ -+ /* */ -+ /* This init variable may be changed in run time. */ -+ /* */ -+ switch (CmnInfo) { -+ case ODM_CMNINFO_ABILITY: -+ pDM_Odm->SupportAbility = (u32)Value; -+ break; -+ case ODM_CMNINFO_RF_TYPE: -+ pDM_Odm->RFType = (u8)Value; -+ break; -+ case ODM_CMNINFO_WIFI_DIRECT: -+ pDM_Odm->bWIFI_Direct = (bool)Value; -+ break; -+ case ODM_CMNINFO_WIFI_DISPLAY: -+ pDM_Odm->bWIFI_Display = (bool)Value; -+ break; -+ case ODM_CMNINFO_LINK: -+ pDM_Odm->bLinked = (bool)Value; -+ break; -+ case ODM_CMNINFO_RSSI_MIN: -+ pDM_Odm->RSSI_Min = (u8)Value; -+ break; -+ case ODM_CMNINFO_DBG_COMP: -+ pDM_Odm->DebugComponents = Value; -+ break; -+ case ODM_CMNINFO_DBG_LEVEL: -+ pDM_Odm->DebugLevel = (u32)Value; -+ break; -+ case ODM_CMNINFO_RA_THRESHOLD_HIGH: -+ pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value; -+ break; -+ case ODM_CMNINFO_RA_THRESHOLD_LOW: -+ pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value; -+ break; -+ } -+} -+ -+void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm) -+{ -+ pDM_Odm->bCckHighPower = (bool) ODM_GetBBReg(pDM_Odm, 0x824, BIT9); -+ pDM_Odm->RFPathRxEnable = (u8) ODM_GetBBReg(pDM_Odm, 0xc04, 0x0F); -+ if (pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8192D)) -+ pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; -+ if (pDM_Odm->SupportICType & (ODM_RTL8723A)) -+ pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; -+ -+ ODM_InitDebugSetting(pDM_Odm); -+} -+ -+void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm) -+{ -+ u8 EntryCnt = 0; -+ u8 i; -+ struct sta_info *pEntry; -+ -+ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) { -+ if (*(pDM_Odm->pSecChOffset) == 1) -+ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) - 2; -+ else if (*(pDM_Odm->pSecChOffset) == 2) -+ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) + 2; -+ } else { -+ pDM_Odm->ControlChannel = *(pDM_Odm->pChannel); -+ } -+ -+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { -+ pEntry = pDM_Odm->pODM_StaInfo[i]; -+ if (IS_STA_VALID(pEntry)) -+ EntryCnt++; -+ } -+ if (EntryCnt == 1) -+ pDM_Odm->bOneEntryOnly = true; -+ else -+ pDM_Odm->bOneEntryOnly = false; -+} -+ -+void odm_CmnInfoInit_Debug(struct odm_dm_struct *pDM_Odm) -+{ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug==>\n")); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform=%d\n", pDM_Odm->SupportPlatform)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility=0x%x\n", pDM_Odm->SupportAbility)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface=%d\n", pDM_Odm->SupportInterface)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType=0x%x\n", pDM_Odm->SupportICType)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion=%d\n", pDM_Odm->CutVersion)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion=%d\n", pDM_Odm->FabVersion)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType=%d\n", pDM_Odm->RFType)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType=%d\n", pDM_Odm->BoardType)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA=%d\n", pDM_Odm->ExtLNA)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA=%d\n", pDM_Odm->ExtPA)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW=%d\n", pDM_Odm->ExtTRSW)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID=%d\n", pDM_Odm->PatchID)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest=%d\n", pDM_Odm->bInHctTest)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest=%d\n", pDM_Odm->bWIFITest)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent=%d\n", pDM_Odm->bDualMacSmartConcurrent)); -+} -+ -+void odm_CmnInfoHook_Debug(struct odm_dm_struct *pDM_Odm) -+{ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoHook_Debug==>\n")); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast=%llu\n", *(pDM_Odm->pNumTxBytesUnicast))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast=%llu\n", *(pDM_Odm->pNumRxBytesUnicast))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode=0x%x\n", *(pDM_Odm->pWirelessMode))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset=%d\n", *(pDM_Odm->pSecChOffset))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity=%d\n", *(pDM_Odm->pSecurity))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth=%d\n", *(pDM_Odm->pBandWidth))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel=%d\n", *(pDM_Odm->pChannel))); -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess=%d\n", *(pDM_Odm->pbScanInProcess))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving=%d\n", *(pDM_Odm->pbPowerSaving))); -+ -+ if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pOnePathCCA=%d\n", *(pDM_Odm->pOnePathCCA))); -+} -+ -+void odm_CmnInfoUpdate_Debug(struct odm_dm_struct *pDM_Odm) -+{ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoUpdate_Debug==>\n")); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct=%d\n", pDM_Odm->bWIFI_Direct)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display=%d\n", pDM_Odm->bWIFI_Display)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked=%d\n", pDM_Odm->bLinked)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min=%d\n", pDM_Odm->RSSI_Min)); -+} -+ -+static int getIGIForDiff(int value_IGI) -+{ -+ #define ONERCCA_LOW_TH 0x30 -+ #define ONERCCA_LOW_DIFF 8 -+ -+ if (value_IGI < ONERCCA_LOW_TH) { -+ if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF) -+ return ONERCCA_LOW_TH; -+ else -+ return value_IGI + ONERCCA_LOW_DIFF; -+ } else { -+ return value_IGI; -+ } -+} -+ -+void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI) -+{ -+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, -+ ("ODM_REG(IGI_A,pDM_Odm)=0x%x, ODM_BIT(IGI,pDM_Odm)=0x%x\n", -+ ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm))); -+ -+ if (pDM_DigTable->CurIGValue != CurrentIGI) { -+ if (pDM_Odm->SupportPlatform & (ODM_CE|ODM_MP)) { -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); -+ if (pDM_Odm->SupportICType != ODM_RTL8188E) -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); -+ } else if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) { -+ switch (*(pDM_Odm->pOnePathCCA)) { -+ case ODM_CCA_2R: -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); -+ if (pDM_Odm->SupportICType != ODM_RTL8188E) -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); -+ break; -+ case ODM_CCA_1R_A: -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); -+ if (pDM_Odm->SupportICType != ODM_RTL8188E) -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI)); -+ break; -+ case ODM_CCA_1R_B: -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI)); -+ if (pDM_Odm->SupportICType != ODM_RTL8188E) -+ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); -+ break; -+ } -+ } -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("CurrentIGI(0x%02x).\n", CurrentIGI)); -+ /* pDM_DigTable->PreIGValue = pDM_DigTable->CurIGValue; */ -+ pDM_DigTable->CurIGValue = CurrentIGI; -+ } -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_Write_DIG():CurrentIGI=0x%x\n", CurrentIGI)); -+ -+/* Add by Neil Chen to enable edcca to MP Platform */ -+} -+ -+/* Need LPS mode for CE platform --2012--08--24--- */ -+/* 8723AS/8189ES */ -+void odm_DIGbyRSSI_LPS(struct odm_dm_struct *pDM_Odm) -+{ -+ struct adapter *pAdapter = pDM_Odm->Adapter; -+ struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; -+ -+ u8 RSSI_Lower = DM_DIG_MIN_NIC; /* 0x1E or 0x1C */ -+ u8 bFwCurrentInPSMode = false; -+ u8 CurrentIGI = pDM_Odm->RSSI_Min; -+ -+ if (!(pDM_Odm->SupportICType & (ODM_RTL8723A | ODM_RTL8188E))) -+ return; -+ -+ CurrentIGI = CurrentIGI + RSSI_OFFSET_DIG; -+ bFwCurrentInPSMode = pAdapter->pwrctrlpriv.bFwCurrentInPSMode; -+ -+ /* Using FW PS mode to make IGI */ -+ if (bFwCurrentInPSMode) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Neil---odm_DIG is in LPS mode\n")); -+ /* Adjust by FA in LPS MODE */ -+ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_LPS) -+ CurrentIGI = CurrentIGI+2; -+ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS) -+ CurrentIGI = CurrentIGI+1; -+ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS) -+ CurrentIGI = CurrentIGI-1; -+ } else { -+ CurrentIGI = RSSI_Lower; -+ } -+ -+ /* Lower bound checking */ -+ -+ /* RSSI Lower bound check */ -+ if ((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC) -+ RSSI_Lower = (pDM_Odm->RSSI_Min-10); -+ else -+ RSSI_Lower = DM_DIG_MIN_NIC; -+ -+ /* Upper and Lower Bound checking */ -+ if (CurrentIGI > DM_DIG_MAX_NIC) -+ CurrentIGI = DM_DIG_MAX_NIC; -+ else if (CurrentIGI < RSSI_Lower) -+ CurrentIGI = RSSI_Lower; -+ -+ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */ -+} -+ -+void odm_DIGInit(struct odm_dm_struct *pDM_Odm) -+{ -+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; -+ -+ pDM_DigTable->CurIGValue = (u8) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)); -+ pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW; -+ pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH; -+ pDM_DigTable->FALowThresh = DM_false_ALARM_THRESH_LOW; -+ pDM_DigTable->FAHighThresh = DM_false_ALARM_THRESH_HIGH; -+ if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) { -+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; -+ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; -+ } else { -+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; -+ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; -+ } -+ pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT; -+ pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX; -+ pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN; -+ pDM_DigTable->PreCCK_CCAThres = 0xFF; -+ pDM_DigTable->CurCCK_CCAThres = 0x83; -+ pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC; -+ pDM_DigTable->LargeFAHit = 0; -+ pDM_DigTable->Recover_cnt = 0; -+ pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC; -+ pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC; -+ pDM_DigTable->bMediaConnect_0 = false; -+ pDM_DigTable->bMediaConnect_1 = false; -+ -+ /* To Initialize pDM_Odm->bDMInitialGainEnable == false to avoid DIG error */ -+ pDM_Odm->bDMInitialGainEnable = true; -+} -+ -+void odm_DIG(struct odm_dm_struct *pDM_Odm) -+{ -+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; -+ struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; -+ u8 DIG_Dynamic_MIN; -+ u8 DIG_MaxOfMin; -+ bool FirstConnect, FirstDisConnect; -+ u8 dm_dig_max, dm_dig_min; -+ u8 CurrentIGI = pDM_DigTable->CurIGValue; -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG()==>\n")); -+ if ((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, -+ ("odm_DIG() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n")); -+ return; -+ } -+ -+ if (*(pDM_Odm->pbScanInProcess)) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In Scan Progress\n")); -+ return; -+ } -+ -+ /* add by Neil Chen to avoid PSD is processing */ -+ if (pDM_Odm->bDMInitialGainEnable == false) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: PSD is Processing\n")); -+ return; -+ } -+ -+ if (pDM_Odm->SupportICType == ODM_RTL8192D) { -+ if (*(pDM_Odm->pMacPhyMode) == ODM_DMSP) { -+ if (*(pDM_Odm->pbMasterOfDMSP)) { -+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; -+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0); -+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0); -+ } else { -+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; -+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1); -+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1); -+ } -+ } else { -+ if (*(pDM_Odm->pBandType) == ODM_BAND_5G) { -+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; -+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0); -+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0); -+ } else { -+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; -+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1); -+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1); -+ } -+ } -+ } else { -+ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; -+ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0); -+ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0); -+ } -+ -+ /* 1 Boundary Decision */ -+ if ((pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8723A)) && -+ ((pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) || pDM_Odm->ExtLNA)) { -+ if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) { -+ dm_dig_max = DM_DIG_MAX_AP_HP; -+ dm_dig_min = DM_DIG_MIN_AP_HP; -+ } else { -+ dm_dig_max = DM_DIG_MAX_NIC_HP; -+ dm_dig_min = DM_DIG_MIN_NIC_HP; -+ } -+ DIG_MaxOfMin = DM_DIG_MAX_AP_HP; -+ } else { -+ if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) { -+ dm_dig_max = DM_DIG_MAX_AP; -+ dm_dig_min = DM_DIG_MIN_AP; -+ DIG_MaxOfMin = dm_dig_max; -+ } else { -+ dm_dig_max = DM_DIG_MAX_NIC; -+ dm_dig_min = DM_DIG_MIN_NIC; -+ DIG_MaxOfMin = DM_DIG_MAX_AP; -+ } -+ } -+ if (pDM_Odm->bLinked) { -+ /* 2 8723A Series, offset need to be 10 */ -+ if (pDM_Odm->SupportICType == (ODM_RTL8723A)) { -+ /* 2 Upper Bound */ -+ if ((pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC) -+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; -+ else if ((pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC) -+ pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC; -+ else -+ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; -+ /* 2 If BT is Concurrent, need to set Lower Bound */ -+ DIG_Dynamic_MIN = DM_DIG_MIN_NIC; -+ } else { -+ /* 2 Modify DIG upper bound */ -+ if ((pDM_Odm->RSSI_Min + 20) > dm_dig_max) -+ pDM_DigTable->rx_gain_range_max = dm_dig_max; -+ else if ((pDM_Odm->RSSI_Min + 20) < dm_dig_min) -+ pDM_DigTable->rx_gain_range_max = dm_dig_min; -+ else -+ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20; -+ /* 2 Modify DIG lower bound */ -+ if (pDM_Odm->bOneEntryOnly) { -+ if (pDM_Odm->RSSI_Min < dm_dig_min) -+ DIG_Dynamic_MIN = dm_dig_min; -+ else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin) -+ DIG_Dynamic_MIN = DIG_MaxOfMin; -+ else -+ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, -+ ("odm_DIG() : bOneEntryOnly=true, DIG_Dynamic_MIN=0x%x\n", -+ DIG_Dynamic_MIN)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, -+ ("odm_DIG() : pDM_Odm->RSSI_Min=%d\n", -+ pDM_Odm->RSSI_Min)); -+ } else if ((pDM_Odm->SupportICType == ODM_RTL8188E) && -+ (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) { -+ /* 1 Lower Bound for 88E AntDiv */ -+ if (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) { -+ DIG_Dynamic_MIN = (u8) pDM_DigTable->AntDiv_RSSI_max; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("odm_DIG(): pDM_DigTable->AntDiv_RSSI_max=%d\n", -+ pDM_DigTable->AntDiv_RSSI_max)); -+ } -+ } else { -+ DIG_Dynamic_MIN = dm_dig_min; -+ } -+ } -+ } else { -+ pDM_DigTable->rx_gain_range_max = dm_dig_max; -+ DIG_Dynamic_MIN = dm_dig_min; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : No Link\n")); -+ } -+ -+ /* 1 Modify DIG lower bound, deal with abnormally large false alarm */ -+ if (pFalseAlmCnt->Cnt_all > 10000) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("dm_DIG(): Abnornally false alarm case.\n")); -+ -+ if (pDM_DigTable->LargeFAHit != 3) -+ pDM_DigTable->LargeFAHit++; -+ if (pDM_DigTable->ForbiddenIGI < CurrentIGI) { -+ pDM_DigTable->ForbiddenIGI = CurrentIGI; -+ pDM_DigTable->LargeFAHit = 1; -+ } -+ -+ if (pDM_DigTable->LargeFAHit >= 3) { -+ if ((pDM_DigTable->ForbiddenIGI+1) > pDM_DigTable->rx_gain_range_max) -+ pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; -+ else -+ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); -+ pDM_DigTable->Recover_cnt = 3600; /* 3600=2hr */ -+ } -+ -+ } else { -+ /* Recovery mechanism for IGI lower bound */ -+ if (pDM_DigTable->Recover_cnt != 0) { -+ pDM_DigTable->Recover_cnt--; -+ } else { -+ if (pDM_DigTable->LargeFAHit < 3) { -+ if ((pDM_DigTable->ForbiddenIGI-1) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */ -+ pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ -+ pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n")); -+ } else { -+ pDM_DigTable->ForbiddenIGI--; -+ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n")); -+ } -+ } else { -+ pDM_DigTable->LargeFAHit = 0; -+ } -+ } -+ } -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, -+ ("odm_DIG(): pDM_DigTable->LargeFAHit=%d\n", -+ pDM_DigTable->LargeFAHit)); -+ -+ /* 1 Adjust initial gain by false alarm */ -+ if (pDM_Odm->bLinked) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG AfterLink\n")); -+ if (FirstConnect) { -+ CurrentIGI = pDM_Odm->RSSI_Min; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n")); -+ } else { -+ if (pDM_Odm->SupportICType == ODM_RTL8192D) { -+ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_92D) -+ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ -+ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_92D) -+ CurrentIGI = CurrentIGI + 1; /* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ -+ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_92D) -+ CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */ -+ } else { -+ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) -+ CurrentIGI = CurrentIGI + 4;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ -+ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) -+ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ -+ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) -+ CurrentIGI = CurrentIGI - 2;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */ -+ } -+ } -+ } else { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG BeforeLink\n")); -+ if (FirstDisConnect) { -+ CurrentIGI = pDM_DigTable->rx_gain_range_min; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First DisConnect\n")); -+ } else { -+ /* 2012.03.30 LukeLee: enable DIG before link but with very high thresholds */ -+ if (pFalseAlmCnt->Cnt_all > 10000) -+ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ -+ else if (pFalseAlmCnt->Cnt_all > 8000) -+ CurrentIGI = CurrentIGI + 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ -+ else if (pFalseAlmCnt->Cnt_all < 500) -+ CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): England DIG\n")); -+ } -+ } -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG End Adjust IGI\n")); -+ /* 1 Check initial gain by upper/lower bound */ -+ if (CurrentIGI > pDM_DigTable->rx_gain_range_max) -+ CurrentIGI = pDM_DigTable->rx_gain_range_max; -+ if (CurrentIGI < pDM_DigTable->rx_gain_range_min) -+ CurrentIGI = pDM_DigTable->rx_gain_range_min; -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, -+ ("odm_DIG(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n", -+ pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): TotalFA=%d\n", pFalseAlmCnt->Cnt_all)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue=0x%x\n", CurrentIGI)); -+ -+ /* 2 High power RSSI threshold */ -+ -+ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */ -+ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; -+ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; -+} -+ -+/* 3============================================================ */ -+/* 3 FASLE ALARM CHECK */ -+/* 3============================================================ */ -+ -+void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm) -+{ -+ u32 ret_value; -+ struct false_alarm_stats *FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); -+ -+ if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) -+ return; -+ -+ if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { -+ /* hold ofdm counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); /* hold page C counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); /* hold page D counter */ -+ -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord); -+ FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff); -+ FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16); -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord); -+ FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff); -+ FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16); -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord); -+ FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff); -+ FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16); -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord); -+ FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff); -+ -+ FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal + -+ FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail + -+ FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail; -+ -+ if (pDM_Odm->SupportICType == ODM_RTL8188E) { -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_SC_CNT_11N, bMaskDWord); -+ FalseAlmCnt->Cnt_BW_LSC = (ret_value&0xffff); -+ FalseAlmCnt->Cnt_BW_USC = ((ret_value&0xffff0000)>>16); -+ } -+ -+ /* hold cck counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT12, 1); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT14, 1); -+ -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0); -+ FalseAlmCnt->Cnt_Cck_fail = ret_value; -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3); -+ FalseAlmCnt->Cnt_Cck_fail += (ret_value & 0xff)<<8; -+ -+ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord); -+ FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) | ((ret_value&0xFF00)>>8); -+ -+ FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync + -+ FalseAlmCnt->Cnt_SB_Search_fail + -+ FalseAlmCnt->Cnt_Parity_Fail + -+ FalseAlmCnt->Cnt_Rate_Illegal + -+ FalseAlmCnt->Cnt_Crc8_fail + -+ FalseAlmCnt->Cnt_Mcs_fail + -+ FalseAlmCnt->Cnt_Cck_fail); -+ -+ FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA; -+ -+ if (pDM_Odm->SupportICType >= ODM_RTL8723A) { -+ /* reset false alarm counter registers */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 1); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 0); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 1); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 0); -+ /* update ofdm counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 0); /* update page C counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 0); /* update page D counter */ -+ -+ /* reset CCK CCA counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 0); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 2); -+ /* reset CCK FA counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 0); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 2); -+ } -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics\n")); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, -+ ("Cnt_Fast_Fsync=%d, Cnt_SB_Search_fail=%d\n", -+ FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, -+ ("Cnt_Parity_Fail=%d, Cnt_Rate_Illegal=%d\n", -+ FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, -+ ("Cnt_Crc8_fail=%d, Cnt_Mcs_fail=%d\n", -+ FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail)); -+ } else { /* FOR ODM_IC_11AC_SERIES */ -+ /* read OFDM FA counter */ -+ FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord); -+ FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord); -+ FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail; -+ -+ /* reset OFDM FA coutner */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 1); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 0); -+ /* reset CCK FA counter */ -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 0); -+ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 1); -+ } -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail=%d\n", FalseAlmCnt->Cnt_Cck_fail)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail=%d\n", FalseAlmCnt->Cnt_Ofdm_fail)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm=%d\n", FalseAlmCnt->Cnt_all)); -+} -+ -+/* 3============================================================ */ -+/* 3 CCK Packet Detect Threshold */ -+/* 3============================================================ */ -+ -+void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm) -+{ -+ u8 CurCCK_CCAThres; -+ struct false_alarm_stats *FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); -+ -+ if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT))) -+ return; -+ if (pDM_Odm->ExtLNA) -+ return; -+ if (pDM_Odm->bLinked) { -+ if (pDM_Odm->RSSI_Min > 25) { -+ CurCCK_CCAThres = 0xcd; -+ } else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) { -+ CurCCK_CCAThres = 0x83; -+ } else { -+ if (FalseAlmCnt->Cnt_Cck_fail > 1000) -+ CurCCK_CCAThres = 0x83; -+ else -+ CurCCK_CCAThres = 0x40; -+ } -+ } else { -+ if (FalseAlmCnt->Cnt_Cck_fail > 1000) -+ CurCCK_CCAThres = 0x83; -+ else -+ CurCCK_CCAThres = 0x40; -+ } -+ ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres); -+} -+ -+void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres) -+{ -+ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; -+ -+ if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres) /* modify by Guo.Mingzhi 2012-01-03 */ -+ ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres); -+ pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres; -+ pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres; -+} -+ -+/* 3============================================================ */ -+/* 3 BB Power Save */ -+/* 3============================================================ */ -+void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm) -+{ -+ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable; -+ -+ pDM_PSTable->PreCCAState = CCA_MAX; -+ pDM_PSTable->CurCCAState = CCA_MAX; -+ pDM_PSTable->PreRFState = RF_MAX; -+ pDM_PSTable->CurRFState = RF_MAX; -+ pDM_PSTable->Rssi_val_min = 0; -+ pDM_PSTable->initialize = 0; -+} -+ -+void odm_DynamicBBPowerSaving(struct odm_dm_struct *pDM_Odm) -+{ -+ if ((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8723A)) -+ return; -+ if (!(pDM_Odm->SupportAbility & ODM_BB_PWR_SAVE)) -+ return; -+ if (!(pDM_Odm->SupportPlatform & (ODM_MP|ODM_CE))) -+ return; -+ -+ /* 1 2.Power Saving for 92C */ -+ if ((pDM_Odm->SupportICType == ODM_RTL8192C) && (pDM_Odm->RFType == ODM_2T2R)) { -+ odm_1R_CCA(pDM_Odm); -+ } else { -+ /* 20100628 Joseph: Turn off BB power save for 88CE because it makesthroughput unstable. */ -+ /* 20100831 Joseph: Turn ON BB power save again after modifying AGC delay from 900ns ot 600ns. */ -+ /* 1 3.Power Saving for 88C */ -+ ODM_RF_Saving(pDM_Odm, false); -+ } -+} -+ -+void odm_1R_CCA(struct odm_dm_struct *pDM_Odm) -+{ -+ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable; -+ -+ if (pDM_Odm->RSSI_Min != 0xFF) { -+ if (pDM_PSTable->PreCCAState == CCA_2R) { -+ if (pDM_Odm->RSSI_Min >= 35) -+ pDM_PSTable->CurCCAState = CCA_1R; -+ else -+ pDM_PSTable->CurCCAState = CCA_2R; -+ } else { -+ if (pDM_Odm->RSSI_Min <= 30) -+ pDM_PSTable->CurCCAState = CCA_2R; -+ else -+ pDM_PSTable->CurCCAState = CCA_1R; -+ } -+ } else { -+ pDM_PSTable->CurCCAState = CCA_MAX; -+ } -+ -+ if (pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) { -+ if (pDM_PSTable->CurCCAState == CCA_1R) { -+ if (pDM_Odm->RFType == ODM_2T2R) -+ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13); -+ else -+ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23); -+ } else { -+ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33); -+ } -+ pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState; -+ } -+} -+ -+void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal) -+{ -+ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable; -+ u8 Rssi_Up_bound = 30; -+ u8 Rssi_Low_bound = 25; -+ -+ if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */ -+ Rssi_Up_bound = 50; -+ Rssi_Low_bound = 45; -+ } -+ if (pDM_PSTable->initialize == 0) { -+ pDM_PSTable->Reg874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord)&0x1CC000)>>14; -+ pDM_PSTable->RegC70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord)&BIT3)>>3; -+ pDM_PSTable->Reg85C = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord)&0xFF000000)>>24; -+ pDM_PSTable->RegA74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord)&0xF000)>>12; -+ pDM_PSTable->initialize = 1; -+ } -+ -+ if (!bForceInNormal) { -+ if (pDM_Odm->RSSI_Min != 0xFF) { -+ if (pDM_PSTable->PreRFState == RF_Normal) { -+ if (pDM_Odm->RSSI_Min >= Rssi_Up_bound) -+ pDM_PSTable->CurRFState = RF_Save; -+ else -+ pDM_PSTable->CurRFState = RF_Normal; -+ } else { -+ if (pDM_Odm->RSSI_Min <= Rssi_Low_bound) -+ pDM_PSTable->CurRFState = RF_Normal; -+ else -+ pDM_PSTable->CurRFState = RF_Save; -+ } -+ } else { -+ pDM_PSTable->CurRFState = RF_MAX; -+ } -+ } else { -+ pDM_PSTable->CurRFState = RF_Normal; -+ } -+ -+ if (pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) { -+ if (pDM_PSTable->CurRFState == RF_Save) { -+ /* 8723 RSSI report will be wrong. Set 0x874[5]=1 when enter BB power saving mode. */ -+ /* Suggested by SD3 Yu-Nan. 2011.01.20. */ -+ if (pDM_Odm->SupportICType == ODM_RTL8723A) -+ ODM_SetBBReg(pDM_Odm, 0x874 , BIT5, 0x1); /* Reg874[5]=1b'1 */ -+ ODM_SetBBReg(pDM_Odm, 0x874 , 0x1C0000, 0x2); /* Reg874[20:18]=3'b010 */ -+ ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, 0); /* RegC70[3]=1'b0 */ -+ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); /* Reg85C[31:24]=0x63 */ -+ ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); /* Reg874[15:14]=2'b10 */ -+ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); /* RegA75[7:4]=0x3 */ -+ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); /* Reg818[28]=1'b0 */ -+ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x1); /* Reg818[28]=1'b1 */ -+ } else { -+ ODM_SetBBReg(pDM_Odm, 0x874 , 0x1CC000, pDM_PSTable->Reg874); -+ ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, pDM_PSTable->RegC70); -+ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->Reg85C); -+ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->RegA74); -+ ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); -+ -+ if (pDM_Odm->SupportICType == ODM_RTL8723A) -+ ODM_SetBBReg(pDM_Odm, 0x874, BIT5, 0x0); /* Reg874[5]=1b'0 */ -+ } -+ pDM_PSTable->PreRFState = pDM_PSTable->CurRFState; -+ } -+} -+ -+/* 3============================================================ */ -+/* 3 RATR MASK */ -+/* 3============================================================ */ -+/* 3============================================================ */ -+/* 3 Rate Adaptive */ -+/* 3============================================================ */ -+ -+void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm) -+{ -+ struct odm_rate_adapt *pOdmRA = &pDM_Odm->RateAdaptive; -+ -+ pOdmRA->Type = DM_Type_ByDriver; -+ if (pOdmRA->Type == DM_Type_ByDriver) -+ pDM_Odm->bUseRAMask = true; -+ else -+ pDM_Odm->bUseRAMask = false; -+ -+ pOdmRA->RATRState = DM_RATR_STA_INIT; -+ pOdmRA->HighRSSIThresh = 50; -+ pOdmRA->LowRSSIThresh = 20; -+} -+ -+u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u8 rssi_level) -+{ -+ struct sta_info *pEntry; -+ u32 rate_bitmap = 0x0fffffff; -+ u8 WirelessMode; -+ -+ pEntry = pDM_Odm->pODM_StaInfo[macid]; -+ if (!IS_STA_VALID(pEntry)) -+ return ra_mask; -+ -+ WirelessMode = pEntry->wireless_mode; -+ -+ switch (WirelessMode) { -+ case ODM_WM_B: -+ if (ra_mask & 0x0000000c) /* 11M or 5.5M enable */ -+ rate_bitmap = 0x0000000d; -+ else -+ rate_bitmap = 0x0000000f; -+ break; -+ case (ODM_WM_A|ODM_WM_G): -+ if (rssi_level == DM_RATR_STA_HIGH) -+ rate_bitmap = 0x00000f00; -+ else -+ rate_bitmap = 0x00000ff0; -+ break; -+ case (ODM_WM_B|ODM_WM_G): -+ if (rssi_level == DM_RATR_STA_HIGH) -+ rate_bitmap = 0x00000f00; -+ else if (rssi_level == DM_RATR_STA_MIDDLE) -+ rate_bitmap = 0x00000ff0; -+ else -+ rate_bitmap = 0x00000ff5; -+ break; -+ case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G): -+ case (ODM_WM_A|ODM_WM_B|ODM_WM_G|ODM_WM_N24G): -+ if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) { -+ if (rssi_level == DM_RATR_STA_HIGH) { -+ rate_bitmap = 0x000f0000; -+ } else if (rssi_level == DM_RATR_STA_MIDDLE) { -+ rate_bitmap = 0x000ff000; -+ } else { -+ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) -+ rate_bitmap = 0x000ff015; -+ else -+ rate_bitmap = 0x000ff005; -+ } -+ } else { -+ if (rssi_level == DM_RATR_STA_HIGH) { -+ rate_bitmap = 0x0f8f0000; -+ } else if (rssi_level == DM_RATR_STA_MIDDLE) { -+ rate_bitmap = 0x0f8ff000; -+ } else { -+ if (*(pDM_Odm->pBandWidth) == ODM_BW40M) -+ rate_bitmap = 0x0f8ff015; -+ else -+ rate_bitmap = 0x0f8ff005; -+ } -+ } -+ break; -+ default: -+ /* case WIRELESS_11_24N: */ -+ /* case WIRELESS_11_5N: */ -+ if (pDM_Odm->RFType == RF_1T2R) -+ rate_bitmap = 0x000fffff; -+ else -+ rate_bitmap = 0x0fffffff; -+ break; -+ } -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, -+ (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n", -+ rssi_level, WirelessMode, rate_bitmap)); -+ -+ return rate_bitmap; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: odm_RefreshRateAdaptiveMask() -+ * -+ * Overview: Update rate table mask according to rssi -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 05/27/2009 hpfan Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm) -+{ -+ if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) -+ return; -+ /* */ -+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ -+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ -+ /* HW dynamic mechanism. */ -+ /* */ -+ switch (pDM_Odm->SupportPlatform) { -+ case ODM_MP: -+ odm_RefreshRateAdaptiveMaskMP(pDM_Odm); -+ break; -+ case ODM_CE: -+ odm_RefreshRateAdaptiveMaskCE(pDM_Odm); -+ break; -+ case ODM_AP: -+ case ODM_ADSL: -+ odm_RefreshRateAdaptiveMaskAPADSL(pDM_Odm); -+ break; -+ } -+} -+ -+void odm_RefreshRateAdaptiveMaskMP(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm) -+{ -+ u8 i; -+ struct adapter *pAdapter = pDM_Odm->Adapter; -+ -+ if (pAdapter->bDriverStopped) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); -+ return; -+ } -+ -+ if (!pDM_Odm->bUseRAMask) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); -+ return; -+ } -+ -+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { -+ struct sta_info *pstat = pDM_Odm->pODM_StaInfo[i]; -+ if (IS_STA_VALID(pstat)) { -+ if (ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false , &pstat->rssi_level)) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, -+ ("RSSI:%d, RSSI_LEVEL:%d\n", -+ pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level)); -+ rtw_hal_update_ra_mask(pAdapter, i, pstat->rssi_level); -+ } -+ } -+ } -+} -+ -+void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+/* Return Value: bool */ -+/* - true: RATRState is changed. */ -+bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, bool bForceUpdate, u8 *pRATRState) -+{ -+ struct odm_rate_adapt *pRA = &pDM_Odm->RateAdaptive; -+ const u8 GoUpGap = 5; -+ u8 HighRSSIThreshForRA = pRA->HighRSSIThresh; -+ u8 LowRSSIThreshForRA = pRA->LowRSSIThresh; -+ u8 RATRState; -+ -+ /* Threshold Adjustment: */ -+ /* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */ -+ /* Here GoUpGap is added to solve the boundary's level alternation issue. */ -+ switch (*pRATRState) { -+ case DM_RATR_STA_INIT: -+ case DM_RATR_STA_HIGH: -+ break; -+ case DM_RATR_STA_MIDDLE: -+ HighRSSIThreshForRA += GoUpGap; -+ break; -+ case DM_RATR_STA_LOW: -+ HighRSSIThreshForRA += GoUpGap; -+ LowRSSIThreshForRA += GoUpGap; -+ break; -+ default: -+ ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState)); -+ break; -+ } -+ -+ /* Decide RATRState by RSSI. */ -+ if (RSSI > HighRSSIThreshForRA) -+ RATRState = DM_RATR_STA_HIGH; -+ else if (RSSI > LowRSSIThreshForRA) -+ RATRState = DM_RATR_STA_MIDDLE; -+ else -+ RATRState = DM_RATR_STA_LOW; -+ -+ if (*pRATRState != RATRState || bForceUpdate) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState)); -+ *pRATRState = RATRState; -+ return true; -+ } -+ return false; -+} -+ -+/* 3============================================================ */ -+/* 3 Dynamic Tx Power */ -+/* 3============================================================ */ -+ -+void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &pHalData->dmpriv; -+ pdmpriv->bDynamicTxPowerEnable = false; -+ pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal; -+ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; -+} -+ -+void odm_DynamicTxPower(struct odm_dm_struct *pDM_Odm) -+{ -+ /* For AP/ADSL use struct rtl8192cd_priv * */ -+ /* For CE/NIC use struct adapter * */ -+ -+ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) -+ return; -+ -+ /* 2012/01/12 MH According to Luke's suggestion, only high power will support the feature. */ -+ if (!pDM_Odm->ExtPA) -+ return; -+ -+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ -+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ -+ /* HW dynamic mechanism. */ -+ switch (pDM_Odm->SupportPlatform) { -+ case ODM_MP: -+ case ODM_CE: -+ odm_DynamicTxPowerNIC(pDM_Odm); -+ break; -+ case ODM_AP: -+ odm_DynamicTxPowerAP(pDM_Odm); -+ break; -+ case ODM_ADSL: -+ break; -+ } -+} -+ -+void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm) -+{ -+ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) -+ return; -+ -+ if (pDM_Odm->SupportICType == ODM_RTL8188E) { -+ /* ??? */ -+ /* This part need to be redefined. */ -+ } -+} -+ -+void odm_DynamicTxPowerAP(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+/* 3============================================================ */ -+/* 3 RSSI Monitor */ -+/* 3============================================================ */ -+ -+void odm_RSSIMonitorCheck(struct odm_dm_struct *pDM_Odm) -+{ -+ if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) -+ return; -+ -+ /* */ -+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ -+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ -+ /* HW dynamic mechanism. */ -+ /* */ -+ switch (pDM_Odm->SupportPlatform) { -+ case ODM_MP: -+ odm_RSSIMonitorCheckMP(pDM_Odm); -+ break; -+ case ODM_CE: -+ odm_RSSIMonitorCheckCE(pDM_Odm); -+ break; -+ case ODM_AP: -+ odm_RSSIMonitorCheckAP(pDM_Odm); -+ break; -+ case ODM_ADSL: -+ /* odm_DIGAP(pDM_Odm); */ -+ break; -+ } -+ -+} /* odm_RSSIMonitorCheck */ -+ -+void odm_RSSIMonitorCheckMP(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+static void FindMinimumRSSI(struct adapter *pAdapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ struct dm_priv *pdmpriv = &pHalData->dmpriv; -+ struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv; -+ -+ /* 1 1.Determine the minimum RSSI */ -+ if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) && -+ (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) -+ pdmpriv->MinUndecoratedPWDBForDM = 0; -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) /* Default port */ -+ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; -+ else /* associated entry pwdb */ -+ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; -+} -+ -+void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &pHalData->dmpriv; -+ int i; -+ int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff; -+ u8 sta_cnt = 0; -+ u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */ -+ struct sta_info *psta; -+ u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+ if (!check_fwstate(&Adapter->mlmepriv, _FW_LINKED)) -+ return; -+ -+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { -+ psta = pDM_Odm->pODM_StaInfo[i]; -+ if (IS_STA_VALID(psta) && -+ (psta->state & WIFI_ASOC_STATE) && -+ memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) && -+ memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) { -+ if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) -+ tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; -+ -+ if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) -+ tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; -+ if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) -+ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16)); -+ } -+ } -+ -+ for (i = 0; i < sta_cnt; i++) { -+ if (PWDB_rssi[i] != (0)) { -+ if (pHalData->fw_ractrl) { -+ /* Report every sta's RSSI to FW */ -+ } else { -+ ODM_RA_SetRSSI_8188E( -+ &(pHalData->odmpriv), (PWDB_rssi[i]&0xFF), (u8)((PWDB_rssi[i]>>16) & 0xFF)); -+ } -+ } -+ } -+ -+ if (tmpEntryMaxPWDB != 0) /* If associated entry is found */ -+ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; -+ else -+ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; -+ -+ if (tmpEntryMinPWDB != 0xff) /* If associated entry is found */ -+ pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; -+ else -+ pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; -+ -+ FindMinimumRSSI(Adapter); -+ ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); -+} -+ -+void odm_RSSIMonitorCheckAP(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+void ODM_InitAllTimers(struct odm_dm_struct *pDM_Odm) -+{ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) -+ ODM_InitializeTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer, -+ (void *)odm_SwAntDivChkAntSwitchCallback, NULL, "SwAntennaSwitchTimer"); -+#else -+ timer_setup(&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer, odm_SwAntDivChkAntSwitchCallback, 0); -+#endif -+} -+ -+void ODM_CancelAllTimers(struct odm_dm_struct *pDM_Odm) -+{ -+ ODM_CancelTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); -+} -+ -+void ODM_ReleaseAllTimers(struct odm_dm_struct *pDM_Odm) -+{ -+ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); -+ -+ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->FastAntTrainingTimer); -+} -+ -+/* 3============================================================ */ -+/* 3 Tx Power Tracking */ -+/* 3============================================================ */ -+ -+void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm) -+{ -+ odm_TXPowerTrackingThermalMeterInit(pDM_Odm); -+} -+ -+void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm) -+{ -+ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true; -+ pDM_Odm->RFCalibrateInfo.TXPowercount = 0; -+ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false; -+ if (*(pDM_Odm->mp_mode) != 1) -+ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; -+ MSG_88E("pDM_Odm TxPowerTrackControl = %d\n", pDM_Odm->RFCalibrateInfo.TxPowerTrackControl); -+ -+ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; -+} -+ -+void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm) -+{ -+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ -+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ -+ /* HW dynamic mechanism. */ -+ switch (pDM_Odm->SupportPlatform) { -+ case ODM_MP: -+ odm_TXPowerTrackingCheckMP(pDM_Odm); -+ break; -+ case ODM_CE: -+ odm_TXPowerTrackingCheckCE(pDM_Odm); -+ break; -+ case ODM_AP: -+ odm_TXPowerTrackingCheckAP(pDM_Odm); -+ break; -+ case ODM_ADSL: -+ break; -+ } -+} -+ -+void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ -+ if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) -+ return; -+ -+ if (!pDM_Odm->RFCalibrateInfo.TM_Trigger) { /* at least delay 1 sec */ -+ PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER_88E, BIT17 | BIT16, 0x03); -+ -+ pDM_Odm->RFCalibrateInfo.TM_Trigger = 1; -+ return; -+ } else { -+ odm_TXPowerTrackingCallback_ThermalMeter_8188E(Adapter); -+ pDM_Odm->RFCalibrateInfo.TM_Trigger = 0; -+ } -+} -+ -+void odm_TXPowerTrackingCheckMP(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+void odm_TXPowerTrackingCheckAP(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+/* antenna mapping info */ -+/* 1: right-side antenna */ -+/* 2/0: left-side antenna */ -+/* PDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt: for right-side antenna: Ant:1 RxDefaultAnt1 */ -+/* PDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt: for left-side antenna: Ant:0 RxDefaultAnt2 */ -+/* We select left antenna as default antenna in initial process, modify it as needed */ -+/* */ -+ -+/* 3============================================================ */ -+/* 3 SW Antenna Diversity */ -+/* 3============================================================ */ -+void odm_SwAntDivInit(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+void ODM_SwAntDivChkPerPktRssi(struct odm_dm_struct *pDM_Odm, u8 StationID, struct odm_phy_status_info *pPhyInfo) -+{ -+} -+ -+void odm_SwAntDivChkAntSwitch(struct odm_dm_struct *pDM_Odm, u8 Step) -+{ -+} -+ -+void ODM_SwAntDivRestAfterLink(struct odm_dm_struct *pDM_Odm) -+{ -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) -+void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext) -+#else -+void odm_SwAntDivChkAntSwitchCallback(struct timer_list *t) -+#endif -+{ -+} -+ -+/* 3============================================================ */ -+/* 3 SW Antenna Diversity */ -+/* 3============================================================ */ -+ -+void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm) -+{ -+ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n")); -+ return; -+ } -+ -+ if (pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D)) -+ ; -+ else if (pDM_Odm->SupportICType == ODM_RTL8188E) -+ ODM_AntennaDiversityInit_88E(pDM_Odm); -+} -+ -+void ODM_AntselStatistics_88C(struct odm_dm_struct *pDM_Odm, u8 MacId, u32 PWDBAll, bool isCCKrate) -+{ -+ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; -+ -+ if (pDM_SWAT_Table->antsel == 1) { -+ if (isCCKrate) { -+ pDM_SWAT_Table->CCK_Ant1_Cnt[MacId]++; -+ } else { -+ pDM_SWAT_Table->OFDM_Ant1_Cnt[MacId]++; -+ pDM_SWAT_Table->RSSI_Ant1_Sum[MacId] += PWDBAll; -+ } -+ } else { -+ if (isCCKrate) { -+ pDM_SWAT_Table->CCK_Ant2_Cnt[MacId]++; -+ } else { -+ pDM_SWAT_Table->OFDM_Ant2_Cnt[MacId]++; -+ pDM_SWAT_Table->RSSI_Ant2_Sum[MacId] += PWDBAll; -+ } -+ } -+} -+ -+void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm) -+{ -+ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n")); -+ return; -+ } -+ -+ if (pDM_Odm->SupportICType == ODM_RTL8188E) -+ ODM_AntennaDiversity_88E(pDM_Odm); -+} -+ -+/* EDCA Turbo */ -+void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; -+ pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false; -+ Adapter->recvpriv.bIsAnyNonBEPkts = false; -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VO PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VO_PARAM))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VI PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VI_PARAM))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BE PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM))); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BK PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BK_PARAM))); -+} /* ODM_InitEdcaTurbo */ -+ -+void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm) -+{ -+ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ -+ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ -+ /* HW dynamic mechanism. */ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("odm_EdcaTurboCheck========================>\n")); -+ -+ if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO)) -+ return; -+ -+ switch (pDM_Odm->SupportPlatform) { -+ case ODM_MP: -+ break; -+ case ODM_CE: -+ odm_EdcaTurboCheckCE(pDM_Odm); -+ break; -+ case ODM_AP: -+ case ODM_ADSL: -+ break; -+ } -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("<========================odm_EdcaTurboCheck\n")); -+} /* odm_CheckEdcaTurbo */ -+ -+void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ u32 trafficIndex; -+ u32 edca_param; -+ u64 cur_tx_bytes = 0; -+ u64 cur_rx_bytes = 0; -+ u8 bbtchange = false; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); -+ struct recv_priv *precvpriv = &(Adapter->recvpriv); -+ struct registry_priv *pregpriv = &Adapter->registrypriv; -+ struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if ((pregpriv->wifi_spec == 1))/* (pmlmeinfo->HT_enable == 0)) */ -+ goto dm_CheckEdcaTurbo_EXIT; -+ -+ if (pmlmeinfo->assoc_AP_vendor >= HT_IOT_PEER_MAX) -+ goto dm_CheckEdcaTurbo_EXIT; -+ -+ /* Check if the status needs to be changed. */ -+ if ((bbtchange) || (!precvpriv->bIsAnyNonBEPkts)) { -+ cur_tx_bytes = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes; -+ cur_rx_bytes = precvpriv->rx_bytes - precvpriv->last_rx_bytes; -+ -+ /* traffic, TX or RX */ -+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) || -+ (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS)) { -+ if (cur_tx_bytes > (cur_rx_bytes << 2)) { -+ /* Uplink TP is present. */ -+ trafficIndex = UP_LINK; -+ } else { -+ /* Balance TP is present. */ -+ trafficIndex = DOWN_LINK; -+ } -+ } else { -+ if (cur_rx_bytes > (cur_tx_bytes << 2)) { -+ /* Downlink TP is present. */ -+ trafficIndex = DOWN_LINK; -+ } else { -+ /* Balance TP is present. */ -+ trafficIndex = UP_LINK; -+ } -+ } -+ -+ if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) || (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) { -+ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_CISCO) && (pmlmeext->cur_wireless_mode & WIRELESS_11_24N)) -+ edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex]; -+ else -+ edca_param = EDCAParam[HT_IOT_PEER_UNKNOWN][trafficIndex]; -+ -+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param); -+ -+ pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex; -+ } -+ -+ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = true; -+ } else { -+ /* Turn Off EDCA turbo here. */ -+ /* Restore original EDCA according to the declaration of AP. */ -+ if (pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) { -+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE); -+ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; -+ } -+ } -+ -+dm_CheckEdcaTurbo_EXIT: -+ /* Set variables for next time. */ -+ precvpriv->bIsAnyNonBEPkts = false; -+ pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes; -+ precvpriv->last_rx_bytes = precvpriv->rx_bytes; -+} -+ -+/* need to ODM CE Platform */ -+/* move to here for ANT detection mechanism using */ -+ -+u32 GetPSDData(struct odm_dm_struct *pDM_Odm, unsigned int point, u8 initial_gain_psd) -+{ -+ u32 psd_report; -+ -+ /* Set DCO frequency index, offset=(40MHz/SamplePts)*point */ -+ ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point); -+ -+ /* Start PSD calculation, Reg808[22]=0->1 */ -+ ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 1); -+ /* Need to wait for HW PSD report */ -+ ODM_StallExecution(30); -+ ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 0); -+ /* Read PSD report, Reg8B4[15:0] */ -+ psd_report = ODM_GetBBReg(pDM_Odm, 0x8B4, bMaskDWord) & 0x0000FFFF; -+ -+ psd_report = (u32) (ConvertTo_dB(psd_report))+(u32)(initial_gain_psd-0x1c); -+ -+ return psd_report; -+} -+ -+u32 ConvertTo_dB(u32 Value) -+{ -+ u8 i; -+ u8 j; -+ u32 dB; -+ -+ Value = Value & 0xFFFF; -+ for (i = 0; i < 8; i++) { -+ if (Value <= dB_Invert_Table[i][11]) -+ break; -+ } -+ -+ if (i >= 8) -+ return 96; /* maximum 96 dB */ -+ -+ for (j = 0; j < 12; j++) { -+ if (Value <= dB_Invert_Table[i][j]) -+ break; -+ } -+ -+ dB = i*12 + j + 1; -+ -+ return dB; -+} -+ -+/* 2011/09/22 MH Add for 92D global spin lock utilization. */ -+void odm_GlobalAdapterCheck(void) -+{ -+} /* odm_GlobalAdapterCheck */ -+ -+/* Description: */ -+/* Set Single/Dual Antenna default setting for products that do not do detection in advance. */ -+/* Added by Joseph, 2012.03.22 */ -+void ODM_SingleDualAntennaDefaultSetting(struct odm_dm_struct *pDM_Odm) -+{ -+ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; -+ -+ pDM_SWAT_Table->ANTA_ON = true; -+ pDM_SWAT_Table->ANTB_ON = true; -+} -+ -+/* 2 8723A ANT DETECT */ -+ -+static void odm_PHY_SaveAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegisterNum) -+{ -+ u32 i; -+ -+ /* RTPRINT(FINIT, INIT_IQK, ("Save ADDA parameters.\n")); */ -+ for (i = 0; i < RegisterNum; i++) -+ AFEBackup[i] = ODM_GetBBReg(pDM_Odm, AFEReg[i], bMaskDWord); -+} -+ -+static void odm_PHY_ReloadAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegiesterNum) -+{ -+ u32 i; -+ -+ for (i = 0; i < RegiesterNum; i++) -+ ODM_SetBBReg(pDM_Odm, AFEReg[i], bMaskDWord, AFEBackup[i]); -+} -+ -+/* 2 8723A ANT DETECT */ -+/* Description: */ -+/* Implement IQK single tone for RF DPK loopback and BB PSD scanning. */ -+/* This function is cooperated with BB team Neil. */ -+bool ODM_SingleDualAntennaDetection(struct odm_dm_struct *pDM_Odm, u8 mode) -+{ -+ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; -+ u32 CurrentChannel, RfLoopReg; -+ u8 n; -+ u32 Reg88c, Regc08, Reg874, Regc50; -+ u8 initial_gain = 0x5a; -+ u32 PSD_report_tmp; -+ u32 AntA_report = 0x0, AntB_report = 0x0, AntO_report = 0x0; -+ bool bResult = true; -+ u32 AFE_Backup[16]; -+ u32 AFE_REG_8723A[16] = { -+ rRx_Wait_CCA, rTx_CCK_RFON, -+ rTx_CCK_BBON, rTx_OFDM_RFON, -+ rTx_OFDM_BBON, rTx_To_Rx, -+ rTx_To_Tx, rRx_CCK, -+ rRx_OFDM, rRx_Wait_RIFS, -+ rRx_TO_Rx, rStandby, -+ rSleep, rPMPD_ANAEN, -+ rFPGA0_XCD_SwitchControl, rBlue_Tooth}; -+ -+ if (!(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C))) -+ return bResult; -+ -+ if (!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV)) -+ return bResult; -+ -+ if (pDM_Odm->SupportICType == ODM_RTL8192C) { -+ /* Which path in ADC/DAC is turnned on for PSD: both I/Q */ -+ ODM_SetBBReg(pDM_Odm, 0x808, BIT10|BIT11, 0x3); -+ /* Ageraged number: 8 */ -+ ODM_SetBBReg(pDM_Odm, 0x808, BIT12|BIT13, 0x1); -+ /* pts = 128; */ -+ ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0); -+ } -+ -+ /* 1 Backup Current RF/BB Settings */ -+ -+ CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask); -+ RfLoopReg = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask); -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A); /* change to Antenna A */ -+ /* Step 1: USE IQK to transmitter single tone */ -+ -+ ODM_StallExecution(10); -+ -+ /* Store A Path Register 88c, c08, 874, c50 */ -+ Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord); -+ Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord); -+ Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord); -+ Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord); -+ -+ /* Store AFE Registers */ -+ odm_PHY_SaveAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); -+ -+ /* Set PSD 128 pts */ -+ ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT14|BIT15, 0x0); /* 128 pts */ -+ -+ /* To SET CH1 to do */ -+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x01); /* Channel 1 */ -+ -+ /* AFE all on step */ -+ ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4); -+ ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4); -+ -+ /* 3 wire Disable */ -+ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0); -+ -+ /* BB IQK Setting */ -+ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4); -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000); -+ -+ /* IQK setting tone@ 4.34Mhz */ -+ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C); -+ ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); -+ -+ /* Page B init */ -+ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000); -+ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000); -+ ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800); -+ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f); -+ ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008); -+ ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008); -+ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0); -+ -+ /* RF loop Setting */ -+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0, 0xFFFFF, 0x50008); -+ -+ /* IQK Single tone start */ -+ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); -+ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); -+ ODM_StallExecution(1000); -+ PSD_report_tmp = 0x0; -+ -+ for (n = 0; n < 2; n++) { -+ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); -+ if (PSD_report_tmp > AntA_report) -+ AntA_report = PSD_report_tmp; -+ } -+ -+ PSD_report_tmp = 0x0; -+ -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); /* change to Antenna B */ -+ ODM_StallExecution(10); -+ -+ for (n = 0; n < 2; n++) { -+ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); -+ if (PSD_report_tmp > AntB_report) -+ AntB_report = PSD_report_tmp; -+ } -+ -+ /* change to open case */ -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, 0); /* change to Ant A and B all open case */ -+ ODM_StallExecution(10); -+ -+ for (n = 0; n < 2; n++) { -+ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); -+ if (PSD_report_tmp > AntO_report) -+ AntO_report = PSD_report_tmp; -+ } -+ -+ /* Close IQK Single Tone function */ -+ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); -+ PSD_report_tmp = 0x0; -+ -+ /* 1 Return to antanna A */ -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); -+ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c); -+ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08); -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874); -+ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40); -+ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50); -+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel); -+ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask, RfLoopReg); -+ -+ /* Reload AFE Registers */ -+ odm_PHY_ReloadAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d\n", 2416, AntA_report)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d\n", 2416, AntB_report)); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d\n", 2416, AntO_report)); -+ -+ if (pDM_Odm->SupportICType == ODM_RTL8723A) { -+ /* 2 Test Ant B based on Ant A is ON */ -+ if (mode == ANTTESTB) { -+ if (AntA_report >= 100) { -+ if (AntB_report > (AntA_report+1)) { -+ pDM_SWAT_Table->ANTB_ON = false; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); -+ } else { -+ pDM_SWAT_Table->ANTB_ON = true; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n")); -+ } -+ } else { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); -+ pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */ -+ bResult = false; -+ } -+ } else if (mode == ANTTESTALL) { -+ /* 2 Test Ant A and B based on DPDT Open */ -+ if ((AntO_report >= 100)&(AntO_report < 118)) { -+ if (AntA_report > (AntO_report+1)) { -+ pDM_SWAT_Table->ANTA_ON = false; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is OFF")); -+ } else { -+ pDM_SWAT_Table->ANTA_ON = true; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is ON")); -+ } -+ -+ if (AntB_report > (AntO_report+2)) { -+ pDM_SWAT_Table->ANTB_ON = false; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is OFF")); -+ } else { -+ pDM_SWAT_Table->ANTB_ON = true; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is ON")); -+ } -+ } -+ } -+ } else if (pDM_Odm->SupportICType == ODM_RTL8192C) { -+ if (AntA_report >= 100) { -+ if (AntB_report > (AntA_report+2)) { -+ pDM_SWAT_Table->ANTA_ON = false; -+ pDM_SWAT_Table->ANTB_ON = true; -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna B\n")); -+ } else if (AntA_report > (AntB_report+2)) { -+ pDM_SWAT_Table->ANTA_ON = true; -+ pDM_SWAT_Table->ANTB_ON = false; -+ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); -+ } else { -+ pDM_SWAT_Table->ANTA_ON = true; -+ pDM_SWAT_Table->ANTB_ON = true; -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("ODM_SingleDualAntennaDetection(): Dual Antenna\n")); -+ } -+ } else { -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); -+ pDM_SWAT_Table->ANTA_ON = true; /* Set Antenna A on as default */ -+ pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */ -+ bResult = false; -+ } -+ } -+ return bResult; -+} -+ -+/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */ -+void odm_dtc(struct odm_dm_struct *pDM_Odm) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/odm_HWConfig.c b/drivers/net/wireless/rtl8188eu/hal/odm_HWConfig.c -new file mode 100644 -index 0000000000000..523801cabb430 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/odm_HWConfig.c -@@ -0,0 +1,601 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+/* include files */ -+ -+#include "odm_precomp.h" -+ -+#define READ_AND_CONFIG READ_AND_CONFIG_MP -+ -+#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(dm_odm)) -+#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(dm_odm)) -+ -+static u8 odm_QueryRxPwrPercentage(s8 AntPower) -+{ -+ if ((AntPower <= -100) || (AntPower >= 20)) -+ return 0; -+ else if (AntPower >= 0) -+ return 100; -+ else -+ return 100+AntPower; -+} -+ -+/* 2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. */ -+/* IF other SW team do not support the feature, remove this section.?? */ -+static s32 odm_sig_patch_lenove(struct odm_dm_struct *dm_odm, s32 CurrSig) -+{ -+ return 0; -+} -+ -+static s32 odm_sig_patch_netcore(struct odm_dm_struct *dm_odm, s32 CurrSig) -+{ -+ return 0; -+} -+ -+static s32 odm_SignalScaleMapping_92CSeries(struct odm_dm_struct *dm_odm, s32 CurrSig) -+{ -+ s32 RetSig = 0; -+ -+ if ((dm_odm->SupportInterface == ODM_ITRF_USB) || -+ (dm_odm->SupportInterface == ODM_ITRF_SDIO)) { -+ if (CurrSig >= 51 && CurrSig <= 100) -+ RetSig = 100; -+ else if (CurrSig >= 41 && CurrSig <= 50) -+ RetSig = 80 + ((CurrSig - 40)*2); -+ else if (CurrSig >= 31 && CurrSig <= 40) -+ RetSig = 66 + (CurrSig - 30); -+ else if (CurrSig >= 21 && CurrSig <= 30) -+ RetSig = 54 + (CurrSig - 20); -+ else if (CurrSig >= 10 && CurrSig <= 20) -+ RetSig = 42 + (((CurrSig - 10) * 2) / 3); -+ else if (CurrSig >= 5 && CurrSig <= 9) -+ RetSig = 22 + (((CurrSig - 5) * 3) / 2); -+ else if (CurrSig >= 1 && CurrSig <= 4) -+ RetSig = 6 + (((CurrSig - 1) * 3) / 2); -+ else -+ RetSig = CurrSig; -+ } -+ return RetSig; -+} -+ -+static s32 odm_SignalScaleMapping(struct odm_dm_struct *dm_odm, s32 CurrSig) -+{ -+ if ((dm_odm->SupportPlatform == ODM_MP) && -+ (dm_odm->SupportInterface != ODM_ITRF_PCIE) && /* USB & SDIO */ -+ (dm_odm->PatchID == 10)) -+ return odm_sig_patch_netcore(dm_odm, CurrSig); -+ else if ((dm_odm->SupportPlatform == ODM_MP) && -+ (dm_odm->SupportInterface == ODM_ITRF_PCIE) && -+ (dm_odm->PatchID == 19)) -+ return odm_sig_patch_lenove(dm_odm, CurrSig); -+ else -+ return odm_SignalScaleMapping_92CSeries(dm_odm, CurrSig); -+} -+ -+/* pMgntInfo->CustomerID == RT_CID_819x_Lenovo */ -+static u8 odm_SQ_process_patch_RT_CID_819x_Lenovo(struct odm_dm_struct *dm_odm, -+ u8 isCCKrate, u8 PWDB_ALL, u8 path, u8 RSSI) -+{ -+ return 0; -+} -+ -+static u8 odm_EVMdbToPercentage(s8 Value) -+{ -+ /* -33dB~0dB to 0%~99% */ -+ s8 ret_val; -+ -+ ret_val = Value; -+ -+ if (ret_val >= 0) -+ ret_val = 0; -+ if (ret_val <= -33) -+ ret_val = -33; -+ -+ ret_val = 0 - ret_val; -+ ret_val *= 3; -+ -+ if (ret_val == 99) -+ ret_val = 100; -+ return ret_val; -+} -+ -+static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm, -+ struct odm_phy_status_info *pPhyInfo, -+ u8 *pPhyStatus, -+ struct odm_per_pkt_info *pPktinfo, -+ struct adapter *adapt) -+{ -+ struct sw_ant_switch *pDM_SWAT_Table = &dm_odm->DM_SWAT_Table; -+ u8 i, Max_spatial_stream; -+ s8 rx_pwr[4], rx_pwr_all = 0; -+ u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT; -+ u8 RSSI, total_rssi = 0; -+ u8 isCCKrate = 0; -+ u8 rf_rx_num = 0; -+ u8 cck_highpwr = 0; -+ u8 LNA_idx, VGA_idx; -+ -+ struct phy_status_rpt *pPhyStaRpt = (struct phy_status_rpt *)pPhyStatus; -+ -+ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false; -+ -+ pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = -1; -+ pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; -+ -+ if (isCCKrate) { -+ u8 report; -+ u8 cck_agc_rpt; -+ -+ dm_odm->PhyDbgInfo.NumQryPhyStatusCCK++; -+ /* (1)Hardware does not provide RSSI for CCK */ -+ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ -+ -+ cck_highpwr = dm_odm->bCckHighPower; -+ -+ cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ; -+ -+ /* 2011.11.28 LukeLee: 88E use different LNA & VGA gain table */ -+ /* The RSSI formula should be modified according to the gain table */ -+ /* In 88E, cck_highpwr is always set to 1 */ -+ if (dm_odm->SupportICType & (ODM_RTL8188E|ODM_RTL8812)) { -+ LNA_idx = ((cck_agc_rpt & 0xE0) >> 5); -+ VGA_idx = (cck_agc_rpt & 0x1F); -+ switch (LNA_idx) { -+ case 7: -+ if (VGA_idx <= 27) -+ rx_pwr_all = -100 + 2*(27-VGA_idx); /* VGA_idx = 27~2 */ -+ else -+ rx_pwr_all = -100; -+ break; -+ case 6: -+ rx_pwr_all = -48 + 2*(2-VGA_idx); /* VGA_idx = 2~0 */ -+ break; -+ case 5: -+ rx_pwr_all = -42 + 2*(7-VGA_idx); /* VGA_idx = 7~5 */ -+ break; -+ case 4: -+ rx_pwr_all = -36 + 2*(7-VGA_idx); /* VGA_idx = 7~4 */ -+ break; -+ case 3: -+ rx_pwr_all = -24 + 2*(7-VGA_idx); /* VGA_idx = 7~0 */ -+ break; -+ case 2: -+ if (cck_highpwr) -+ rx_pwr_all = -12 + 2*(5-VGA_idx); /* VGA_idx = 5~0 */ -+ else -+ rx_pwr_all = -6 + 2*(5-VGA_idx); -+ break; -+ case 1: -+ rx_pwr_all = 8-2*VGA_idx; -+ break; -+ case 0: -+ rx_pwr_all = 14-2*VGA_idx; -+ break; -+ default: -+ break; -+ } -+ rx_pwr_all += 6; -+ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); -+ if (!cck_highpwr) { -+ if (PWDB_ALL >= 80) -+ PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80; -+ else if ((PWDB_ALL <= 78) && (PWDB_ALL >= 20)) -+ PWDB_ALL += 3; -+ if (PWDB_ALL > 100) -+ PWDB_ALL = 100; -+ } -+ } else { -+ if (!cck_highpwr) { -+ report = (cck_agc_rpt & 0xc0)>>6; -+ switch (report) { -+ /* 03312009 modified by cosa */ -+ /* Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion */ -+ /* Note: different RF with the different RNA gain. */ -+ case 0x3: -+ rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); -+ break; -+ case 0x2: -+ rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); -+ break; -+ case 0x1: -+ rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); -+ break; -+ case 0x0: -+ rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); -+ break; -+ } -+ } else { -+ report = (cck_agc_rpt & 0x60)>>5; -+ switch (report) { -+ case 0x3: -+ rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ; -+ break; -+ case 0x2: -+ rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1); -+ break; -+ case 0x1: -+ rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1); -+ break; -+ case 0x0: -+ rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1); -+ break; -+ } -+ } -+ -+ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); -+ -+ /* Modification for ext-LNA board */ -+ if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) { -+ if ((cck_agc_rpt>>7) == 0) { -+ PWDB_ALL = (PWDB_ALL > 94) ? 100 : (PWDB_ALL+6); -+ } else { -+ if (PWDB_ALL > 38) -+ PWDB_ALL -= 16; -+ else -+ PWDB_ALL = (PWDB_ALL <= 16) ? (PWDB_ALL>>2) : (PWDB_ALL-12); -+ } -+ -+ /* CCK modification */ -+ if (PWDB_ALL > 25 && PWDB_ALL <= 60) -+ PWDB_ALL += 6; -+ } else {/* Modification for int-LNA board */ -+ if (PWDB_ALL > 99) -+ PWDB_ALL -= 8; -+ else if (PWDB_ALL > 50 && PWDB_ALL <= 68) -+ PWDB_ALL += 4; -+ } -+ } -+ -+ pPhyInfo->RxPWDBAll = PWDB_ALL; -+ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; -+ pPhyInfo->RecvSignalPower = rx_pwr_all; -+ /* (3) Get Signal Quality (EVM) */ -+ if (pPktinfo->bPacketMatchBSSID) { -+ u8 SQ, SQ_rpt; -+ -+ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) { -+ SQ = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, 0, 0); -+ } else if (pPhyInfo->RxPWDBAll > 40 && !dm_odm->bInHctTest) { -+ SQ = 100; -+ } else { -+ SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; -+ -+ if (SQ_rpt > 64) -+ SQ = 0; -+ else if (SQ_rpt < 20) -+ SQ = 100; -+ else -+ SQ = ((64-SQ_rpt) * 100) / 44; -+ } -+ pPhyInfo->SignalQuality = SQ; -+ pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = SQ; -+ pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; -+ } -+ } else { /* is OFDM rate */ -+ dm_odm->PhyDbgInfo.NumQryPhyStatusOFDM++; -+ -+ /* (1)Get RSSI for HT rate */ -+ -+ for (i = RF_PATH_A; i < RF_PATH_MAX; i++) { -+ /* 2008/01/30 MH we will judge RF RX path now. */ -+ if (dm_odm->RFPathRxEnable & BIT(i)) -+ rf_rx_num++; -+ -+ rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F)*2) - 110; -+ if (i == RF_PATH_A) -+ adapt->signal_strength = rx_pwr[i]; -+ -+ pPhyInfo->RxPwr[i] = rx_pwr[i]; -+ -+ /* Translate DBM to percentage. */ -+ RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); -+ total_rssi += RSSI; -+ -+ /* Modification for ext-LNA board */ -+ if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) { -+ if ((pPhyStaRpt->path_agc[i].trsw) == 1) -+ RSSI = (RSSI > 94) ? 100 : (RSSI + 6); -+ else -+ RSSI = (RSSI <= 16) ? (RSSI >> 3) : (RSSI - 16); -+ -+ if ((RSSI <= 34) && (RSSI >= 4)) -+ RSSI -= 4; -+ } -+ -+ pPhyInfo->RxMIMOSignalStrength[i] = (u8)RSSI; -+ -+ /* Get Rx snr value in DB */ -+ pPhyInfo->RxSNR[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2); -+ dm_odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2); -+ -+ /* Record Signal Strength for next packet */ -+ if (pPktinfo->bPacketMatchBSSID) { -+ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) { -+ if (i == RF_PATH_A) -+ pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, i, RSSI); -+ } -+ } -+ } -+ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ -+ rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f) - 110; -+ -+ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); -+ PWDB_ALL_BT = PWDB_ALL; -+ -+ pPhyInfo->RxPWDBAll = PWDB_ALL; -+ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; -+ pPhyInfo->RxPower = rx_pwr_all; -+ pPhyInfo->RecvSignalPower = rx_pwr_all; -+ -+ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) { -+ /* do nothing */ -+ } else { -+ /* (3)EVM of HT rate */ -+ if (pPktinfo->Rate >= DESC92C_RATEMCS8 && pPktinfo->Rate <= DESC92C_RATEMCS15) -+ Max_spatial_stream = 2; /* both spatial stream make sense */ -+ else -+ Max_spatial_stream = 1; /* only spatial stream 1 makes sense */ -+ -+ for (i = 0; i < Max_spatial_stream; i++) { -+ /* Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */ -+ /* fill most significant bit to "zero" when doing shifting operation which may change a negative */ -+ /* value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. */ -+ EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */ -+ -+ if (pPktinfo->bPacketMatchBSSID) { -+ if (i == RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */ -+ pPhyInfo->SignalQuality = (u8)(EVM & 0xff); -+ pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff); -+ } -+ } -+ } -+ } -+ /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */ -+ /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */ -+ if (isCCKrate) { -+ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, PWDB_ALL));/* PWDB_ALL; */ -+ } else { -+ if (rf_rx_num != 0) -+ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, total_rssi /= rf_rx_num)); -+ } -+ -+ /* For 92C/92D HW (Hybrid) Antenna Diversity */ -+ pDM_SWAT_Table->antsel = pPhyStaRpt->ant_sel; -+ /* For 88E HW Antenna Diversity */ -+ dm_odm->DM_FatTable.antsel_rx_keep_0 = pPhyStaRpt->ant_sel; -+ dm_odm->DM_FatTable.antsel_rx_keep_1 = pPhyStaRpt->ant_sel_b; -+ dm_odm->DM_FatTable.antsel_rx_keep_2 = pPhyStaRpt->antsel_rx_keep_2; -+} -+ -+void odm_Init_RSSIForDM(struct odm_dm_struct *dm_odm) -+{ -+} -+ -+static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm, -+ struct odm_phy_status_info *pPhyInfo, -+ struct odm_per_pkt_info *pPktinfo) -+{ -+ s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK; -+ s32 UndecoratedSmoothedOFDM, RSSI_Ave; -+ u8 isCCKrate = 0; -+ u8 RSSI_max, RSSI_min, i; -+ u32 OFDM_pkt = 0; -+ u32 Weighting = 0; -+ struct sta_info *pEntry; -+ -+ if (pPktinfo->StationID == 0xFF) -+ return; -+ pEntry = dm_odm->pODM_StaInfo[pPktinfo->StationID]; -+ if (!IS_STA_VALID(pEntry)) -+ return; -+ if ((!pPktinfo->bPacketMatchBSSID)) -+ return; -+ -+ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false; -+ -+ /* Smart Antenna Debug Message------------------ */ -+ if (dm_odm->SupportICType == ODM_RTL8188E) { -+ u8 antsel_tr_mux; -+ struct fast_ant_train *pDM_FatTable = &dm_odm->DM_FatTable; -+ -+ if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV) { -+ if (pDM_FatTable->FAT_State == FAT_TRAINING_STATE) { -+ if (pPktinfo->bPacketToSelf) { -+ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) | -+ (pDM_FatTable->antsel_rx_keep_1<<1) | -+ pDM_FatTable->antsel_rx_keep_0; -+ pDM_FatTable->antSumRSSI[antsel_tr_mux] += pPhyInfo->RxPWDBAll; -+ pDM_FatTable->antRSSIcnt[antsel_tr_mux]++; -+ } -+ } -+ } else if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)) { -+ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) { -+ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) | -+ (pDM_FatTable->antsel_rx_keep_1<<1) | pDM_FatTable->antsel_rx_keep_0; -+ ODM_AntselStatistics_88E(dm_odm, antsel_tr_mux, pPktinfo->StationID, pPhyInfo->RxPWDBAll); -+ } -+ } -+ } -+ /* Smart Antenna Debug Message------------------ */ -+ -+ UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK; -+ UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; -+ UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; -+ -+ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) { -+ if (!isCCKrate) { /* ofdm rate */ -+ if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_B] == 0) { -+ RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; -+ } else { -+ if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]) { -+ RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; -+ RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; -+ } else { -+ RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; -+ RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; -+ } -+ if ((RSSI_max - RSSI_min) < 3) -+ RSSI_Ave = RSSI_max; -+ else if ((RSSI_max - RSSI_min) < 6) -+ RSSI_Ave = RSSI_max - 1; -+ else if ((RSSI_max - RSSI_min) < 10) -+ RSSI_Ave = RSSI_max - 2; -+ else -+ RSSI_Ave = RSSI_max - 3; -+ } -+ -+ /* 1 Process OFDM RSSI */ -+ if (UndecoratedSmoothedOFDM <= 0) { /* initialize */ -+ UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; -+ } else { -+ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) { -+ UndecoratedSmoothedOFDM = -+ (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + -+ (RSSI_Ave)) / (Rx_Smooth_Factor); -+ UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1; -+ } else { -+ UndecoratedSmoothedOFDM = -+ (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + -+ (RSSI_Ave)) / (Rx_Smooth_Factor); -+ } -+ } -+ -+ pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0; -+ -+ } else { -+ RSSI_Ave = pPhyInfo->RxPWDBAll; -+ -+ /* 1 Process CCK RSSI */ -+ if (UndecoratedSmoothedCCK <= 0) { /* initialize */ -+ UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; -+ } else { -+ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) { -+ UndecoratedSmoothedCCK = -+ ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) + -+ pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor; -+ UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; -+ } else { -+ UndecoratedSmoothedCCK = -+ ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) + -+ pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor; -+ } -+ } -+ pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1; -+ } -+ /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */ -+ if (pEntry->rssi_stat.ValidBit >= 64) -+ pEntry->rssi_stat.ValidBit = 64; -+ else -+ pEntry->rssi_stat.ValidBit++; -+ -+ for (i = 0; i < pEntry->rssi_stat.ValidBit; i++) -+ OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i)&BIT0; -+ -+ if (pEntry->rssi_stat.ValidBit == 64) { -+ Weighting = ((OFDM_pkt<<4) > 64) ? 64 : (OFDM_pkt<<4); -+ UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6; -+ } else { -+ if (pEntry->rssi_stat.ValidBit != 0) -+ UndecoratedSmoothedPWDB = (OFDM_pkt * UndecoratedSmoothedOFDM + -+ (pEntry->rssi_stat.ValidBit-OFDM_pkt) * -+ UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit; -+ else -+ UndecoratedSmoothedPWDB = 0; -+ } -+ pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK; -+ pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM; -+ pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB; -+ } -+} -+ -+/* Endianness before calling this API */ -+static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm, -+ struct odm_phy_status_info *pPhyInfo, -+ u8 *pPhyStatus, -+ struct odm_per_pkt_info *pPktinfo, -+ struct adapter *adapt) -+{ -+ odm_RxPhyStatus92CSeries_Parsing(dm_odm, pPhyInfo, pPhyStatus, -+ pPktinfo, adapt); -+ if (dm_odm->RSSI_test) { -+ /* Select the packets to do RSSI checking for antenna switching. */ -+ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) -+ ODM_SwAntDivChkPerPktRssi(dm_odm, pPktinfo->StationID, pPhyInfo); -+ } else { -+ odm_Process_RSSIForDM(dm_odm, pPhyInfo, pPktinfo); -+ } -+} -+ -+void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm, -+ struct odm_phy_status_info *pPhyInfo, -+ u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo, -+ struct adapter *adapt) -+{ -+ ODM_PhyStatusQuery_92CSeries(dm_odm, pPhyInfo, pPhyStatus, pPktinfo, adapt); -+} -+ -+/* For future use. */ -+void ODM_MacStatusQuery(struct odm_dm_struct *dm_odm, u8 *mac_stat, -+ u8 macid, bool pkt_match_bssid, -+ bool pkttoself, bool pkt_beacon) -+{ -+ /* 2011/10/19 Driver team will handle in the future. */ -+} -+ -+enum HAL_STATUS ODM_ConfigRFWithHeaderFile(struct odm_dm_struct *dm_odm, -+ enum rf_radio_path content, -+ enum rf_radio_path rfpath) -+{ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===>ODM_ConfigRFWithHeaderFile\n")); -+ if (dm_odm->SupportICType == ODM_RTL8188E) { -+ if (rfpath == RF_PATH_A) -+ READ_AND_CONFIG(8188E, _RadioA_1T_); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_A:Rtl8188ERadioA_1TArray\n")); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_B:Rtl8188ERadioB_1TArray\n")); -+ } -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("ODM_ConfigRFWithHeaderFile: Radio No %x\n", rfpath)); -+ return HAL_STATUS_SUCCESS; -+} -+ -+enum HAL_STATUS ODM_ConfigBBWithHeaderFile(struct odm_dm_struct *dm_odm, -+ enum odm_bb_config_type config_tp) -+{ -+ if (dm_odm->SupportICType == ODM_RTL8188E) { -+ if (config_tp == CONFIG_BB_PHY_REG) { -+ READ_AND_CONFIG(8188E, _PHY_REG_1T_); -+ } else if (config_tp == CONFIG_BB_AGC_TAB) { -+ READ_AND_CONFIG(8188E, _AGC_TAB_1T_); -+ } else if (config_tp == CONFIG_BB_PHY_REG_PG) { -+ READ_AND_CONFIG(8188E, _PHY_REG_PG_); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, -+ (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8188EPHY_REG_PGArray\n")); -+ } -+ } -+ return HAL_STATUS_SUCCESS; -+} -+ -+enum HAL_STATUS ODM_ConfigMACWithHeaderFile(struct odm_dm_struct *dm_odm) -+{ -+ u8 result = HAL_STATUS_SUCCESS; -+ if (dm_odm->SupportICType == ODM_RTL8188E) -+ result = READ_AND_CONFIG(8188E, _MAC_REG_); -+ return result; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/odm_RTL8188E.c b/drivers/net/wireless/rtl8188eu/hal/odm_RTL8188E.c -new file mode 100644 -index 0000000000000..858fc39de6aab ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/odm_RTL8188E.c -@@ -0,0 +1,400 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include "odm_precomp.h" -+ -+void ODM_DIG_LowerBound_88E(struct odm_dm_struct *dm_odm) -+{ -+ struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable; -+ -+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) { -+ pDM_DigTable->rx_gain_range_min = (u8) pDM_DigTable->AntDiv_RSSI_max; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("ODM_DIG_LowerBound_88E(): pDM_DigTable->AntDiv_RSSI_max=%d\n", pDM_DigTable->AntDiv_RSSI_max)); -+ } -+ /* If only one Entry connected */ -+} -+ -+static void odm_RX_HWAntDivInit(struct odm_dm_struct *dm_odm) -+{ -+ u32 value32; -+ -+ if (*(dm_odm->mp_mode) == 1) { -+ dm_odm->AntDivType = CGCS_RX_SW_ANTDIV; -+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /* disable HW AntDiv */ -+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1); /* 1:CG, 0:CS */ -+ return; -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_RX_HWAntDivInit()\n")); -+ -+ /* MAC Setting */ -+ value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); -+ ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */ -+ /* Pin Settings */ -+ ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */ -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT10, 0); /* Reg864[10]=1'b0 antsel2 by HW */ -+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT22, 1); /* Regb2c[22]=1'b0 disable CS/CG switch */ -+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1); /* Regb2c[31]=1'b1 output at CG only */ -+ /* OFDM Settings */ -+ ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0); -+ /* CCK Settings */ -+ ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT7, 1); /* Fix CCK PHY status report issue */ -+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 1); /* CCK complete HW AntDiv within 64 samples */ -+ ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT); -+ ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, 0xFFFF, 0x0201); /* antenna mapping table */ -+} -+ -+static void odm_TRX_HWAntDivInit(struct odm_dm_struct *dm_odm) -+{ -+ u32 value32; -+ -+ if (*(dm_odm->mp_mode) == 1) { -+ dm_odm->AntDivType = CGCS_RX_SW_ANTDIV; -+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /* disable HW AntDiv */ -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, 0); /* Default RX (0/1) */ -+ return; -+ } -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_TRX_HWAntDivInit()\n")); -+ -+ /* MAC Setting */ -+ value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); -+ ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */ -+ /* Pin Settings */ -+ ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */ -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT10, 0); /* Reg864[10]=1'b0 antsel2 by HW */ -+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT22, 0); /* Regb2c[22]=1'b0 disable CS/CG switch */ -+ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1); /* Regb2c[31]=1'b1 output at CG only */ -+ /* OFDM Settings */ -+ ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0); -+ /* CCK Settings */ -+ ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT7, 1); /* Fix CCK PHY status report issue */ -+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 1); /* CCK complete HW AntDiv within 64 samples */ -+ /* Tx Settings */ -+ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 0); /* Reg80c[21]=1'b0 from TX Reg */ -+ ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT); -+ -+ /* antenna mapping table */ -+ if (!dm_odm->bIsMPChip) { /* testchip */ -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT10|BIT9|BIT8, 1); /* Reg858[10:8]=3'b001 */ -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT13|BIT12|BIT11, 2); /* Reg858[13:11]=3'b010 */ -+ } else { /* MPchip */ -+ ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, bMaskDWord, 0x0201); /* Reg914=3'b010, Reg915=3'b001 */ -+ } -+} -+ -+static void odm_FastAntTrainingInit(struct odm_dm_struct *dm_odm) -+{ -+ u32 value32, i; -+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; -+ u32 AntCombination = 2; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_FastAntTrainingInit()\n")); -+ -+ if (*(dm_odm->mp_mode) == 1) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("dm_odm->AntDivType: %d\n", dm_odm->AntDivType)); -+ return; -+ } -+ -+ for (i = 0; i < 6; i++) { -+ dm_fat_tbl->Bssid[i] = 0; -+ dm_fat_tbl->antSumRSSI[i] = 0; -+ dm_fat_tbl->antRSSIcnt[i] = 0; -+ dm_fat_tbl->antAveRSSI[i] = 0; -+ } -+ dm_fat_tbl->TrainIdx = 0; -+ dm_fat_tbl->FAT_State = FAT_NORMAL_STATE; -+ -+ /* MAC Setting */ -+ value32 = ODM_GetMACReg(dm_odm, 0x4c, bMaskDWord); -+ ODM_SetMACReg(dm_odm, 0x4c, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */ -+ value32 = ODM_GetMACReg(dm_odm, 0x7B4, bMaskDWord); -+ ODM_SetMACReg(dm_odm, 0x7b4, bMaskDWord, value32|(BIT16|BIT17)); /* Reg7B4[16]=1 enable antenna training, Reg7B4[17]=1 enable A2 match */ -+ -+ /* Match MAC ADDR */ -+ ODM_SetMACReg(dm_odm, 0x7b4, 0xFFFF, 0); -+ ODM_SetMACReg(dm_odm, 0x7b0, bMaskDWord, 0); -+ -+ ODM_SetBBReg(dm_odm, 0x870, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */ -+ ODM_SetBBReg(dm_odm, 0x864, BIT10, 0); /* Reg864[10]=1'b0 antsel2 by HW */ -+ ODM_SetBBReg(dm_odm, 0xb2c, BIT22, 0); /* Regb2c[22]=1'b0 disable CS/CG switch */ -+ ODM_SetBBReg(dm_odm, 0xb2c, BIT31, 1); /* Regb2c[31]=1'b1 output at CG only */ -+ ODM_SetBBReg(dm_odm, 0xca4, bMaskDWord, 0x000000a0); -+ -+ /* antenna mapping table */ -+ if (AntCombination == 2) { -+ if (!dm_odm->bIsMPChip) { /* testchip */ -+ ODM_SetBBReg(dm_odm, 0x858, BIT10|BIT9|BIT8, 1); /* Reg858[10:8]=3'b001 */ -+ ODM_SetBBReg(dm_odm, 0x858, BIT13|BIT12|BIT11, 2); /* Reg858[13:11]=3'b010 */ -+ } else { /* MPchip */ -+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 1); -+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 2); -+ } -+ } else if (AntCombination == 7) { -+ if (!dm_odm->bIsMPChip) { /* testchip */ -+ ODM_SetBBReg(dm_odm, 0x858, BIT10|BIT9|BIT8, 0); /* Reg858[10:8]=3'b000 */ -+ ODM_SetBBReg(dm_odm, 0x858, BIT13|BIT12|BIT11, 1); /* Reg858[13:11]=3'b001 */ -+ ODM_SetBBReg(dm_odm, 0x878, BIT16, 0); -+ ODM_SetBBReg(dm_odm, 0x858, BIT15|BIT14, 2); /* Reg878[0],Reg858[14:15])=3'b010 */ -+ ODM_SetBBReg(dm_odm, 0x878, BIT19|BIT18|BIT17, 3);/* Reg878[3:1]=3b'011 */ -+ ODM_SetBBReg(dm_odm, 0x878, BIT22|BIT21|BIT20, 4);/* Reg878[6:4]=3b'100 */ -+ ODM_SetBBReg(dm_odm, 0x878, BIT25|BIT24|BIT23, 5);/* Reg878[9:7]=3b'101 */ -+ ODM_SetBBReg(dm_odm, 0x878, BIT28|BIT27|BIT26, 6);/* Reg878[12:10]=3b'110 */ -+ ODM_SetBBReg(dm_odm, 0x878, BIT31|BIT30|BIT29, 7);/* Reg878[15:13]=3b'111 */ -+ } else { /* MPchip */ -+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 0); -+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 1); -+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte2, 2); -+ ODM_SetBBReg(dm_odm, 0x914, bMaskByte3, 3); -+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte0, 4); -+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte1, 5); -+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte2, 6); -+ ODM_SetBBReg(dm_odm, 0x918, bMaskByte3, 7); -+ } -+ } -+ -+ /* Default Ant Setting when no fast training */ -+ ODM_SetBBReg(dm_odm, 0x80c, BIT21, 1); /* Reg80c[21]=1'b1 from TX Info */ -+ ODM_SetBBReg(dm_odm, 0x864, BIT5|BIT4|BIT3, 0); /* Default RX */ -+ ODM_SetBBReg(dm_odm, 0x864, BIT8|BIT7|BIT6, 1); /* Optional RX */ -+ -+ /* Enter Traing state */ -+ ODM_SetBBReg(dm_odm, 0x864, BIT2|BIT1|BIT0, (AntCombination-1)); /* Reg864[2:0]=3'd6 ant combination=reg864[2:0]+1 */ -+ ODM_SetBBReg(dm_odm, 0xc50, BIT7, 1); /* RegC50[7]=1'b1 enable HW AntDiv */ -+} -+ -+void ODM_AntennaDiversityInit_88E(struct odm_dm_struct *dm_odm) -+{ -+ if (dm_odm->SupportICType != ODM_RTL8188E) -+ return; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_odm->AntDivType=%d\n", dm_odm->AntDivType)); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_odm->bIsMPChip=%s\n", (dm_odm->bIsMPChip ? "true" : "false"))); -+ -+ if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) -+ odm_RX_HWAntDivInit(dm_odm); -+ else if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) -+ odm_TRX_HWAntDivInit(dm_odm); -+ else if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV) -+ odm_FastAntTrainingInit(dm_odm); -+} -+ -+void ODM_UpdateRxIdleAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant) -+{ -+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; -+ u32 DefaultAnt, OptionalAnt; -+ -+ if (dm_fat_tbl->RxIdleAnt != Ant) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Update Rx Idle Ant\n")); -+ if (Ant == MAIN_ANT) { -+ DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX; -+ OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX; -+ } else { -+ DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX; -+ OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX; -+ } -+ -+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) { -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, DefaultAnt); /* Default RX */ -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT8|BIT7|BIT6, OptionalAnt); /* Optional RX */ -+ ODM_SetBBReg(dm_odm, ODM_REG_ANTSEL_CTRL_11N, BIT14|BIT13|BIT12, DefaultAnt); /* Default TX */ -+ ODM_SetMACReg(dm_odm, ODM_REG_RESP_TX_11N, BIT6|BIT7, DefaultAnt); /* Resp Tx */ -+ } else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) { -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, DefaultAnt); /* Default RX */ -+ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT8|BIT7|BIT6, OptionalAnt); /* Optional RX */ -+ } -+ } -+ dm_fat_tbl->RxIdleAnt = Ant; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("RxIdleAnt=%s\n", (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT")); -+ if (Ant != MAIN_ANT) -+ pr_info("RxIdleAnt=AUX_ANT\n"); -+} -+ -+static void odm_UpdateTxAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant, u32 MacId) -+{ -+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; -+ u8 TargetAnt; -+ -+ if (Ant == MAIN_ANT) -+ TargetAnt = MAIN_ANT_CG_TRX; -+ else -+ TargetAnt = AUX_ANT_CG_TRX; -+ dm_fat_tbl->antsel_a[MacId] = TargetAnt&BIT0; -+ dm_fat_tbl->antsel_b[MacId] = (TargetAnt&BIT1)>>1; -+ dm_fat_tbl->antsel_c[MacId] = (TargetAnt&BIT2)>>2; -+ -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("Tx from TxInfo, TargetAnt=%s\n", -+ (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT")); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("antsel_tr_mux=3'b%d%d%d\n", -+ dm_fat_tbl->antsel_c[MacId], dm_fat_tbl->antsel_b[MacId], dm_fat_tbl->antsel_a[MacId])); -+} -+ -+void ODM_SetTxAntByTxInfo_88E(struct odm_dm_struct *dm_odm, u8 *pDesc, u8 macId) -+{ -+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; -+ -+ if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV)) { -+ SET_TX_DESC_ANTSEL_A_88E(pDesc, dm_fat_tbl->antsel_a[macId]); -+ SET_TX_DESC_ANTSEL_B_88E(pDesc, dm_fat_tbl->antsel_b[macId]); -+ SET_TX_DESC_ANTSEL_C_88E(pDesc, dm_fat_tbl->antsel_c[macId]); -+ } -+} -+ -+void ODM_AntselStatistics_88E(struct odm_dm_struct *dm_odm, u8 antsel_tr_mux, u32 MacId, u8 RxPWDBAll) -+{ -+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; -+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) { -+ if (antsel_tr_mux == MAIN_ANT_CG_TRX) { -+ dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll; -+ dm_fat_tbl->MainAnt_Cnt[MacId]++; -+ } else { -+ dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll; -+ dm_fat_tbl->AuxAnt_Cnt[MacId]++; -+ } -+ } else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) { -+ if (antsel_tr_mux == MAIN_ANT_CGCS_RX) { -+ dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll; -+ dm_fat_tbl->MainAnt_Cnt[MacId]++; -+ } else { -+ dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll; -+ dm_fat_tbl->AuxAnt_Cnt[MacId]++; -+ } -+ } -+} -+ -+static void odm_HWAntDiv(struct odm_dm_struct *dm_odm) -+{ -+ u32 i, MinRSSI = 0xFF, AntDivMaxRSSI = 0, MaxRSSI = 0, LocalMinRSSI, LocalMaxRSSI; -+ u32 Main_RSSI, Aux_RSSI; -+ u8 RxIdleAnt = 0, TargetAnt = 7; -+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; -+ struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable; -+ struct sta_info *pEntry; -+ -+ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { -+ pEntry = dm_odm->pODM_StaInfo[i]; -+ if (IS_STA_VALID(pEntry)) { -+ /* 2 Caculate RSSI per Antenna */ -+ Main_RSSI = (dm_fat_tbl->MainAnt_Cnt[i] != 0) ? (dm_fat_tbl->MainAnt_Sum[i]/dm_fat_tbl->MainAnt_Cnt[i]) : 0; -+ Aux_RSSI = (dm_fat_tbl->AuxAnt_Cnt[i] != 0) ? (dm_fat_tbl->AuxAnt_Sum[i]/dm_fat_tbl->AuxAnt_Cnt[i]) : 0; -+ TargetAnt = (Main_RSSI >= Aux_RSSI) ? MAIN_ANT : AUX_ANT; -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("MacID=%d, MainAnt_Sum=%d, MainAnt_Cnt=%d\n", -+ i, dm_fat_tbl->MainAnt_Sum[i], -+ dm_fat_tbl->MainAnt_Cnt[i])); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("MacID=%d, AuxAnt_Sum=%d, AuxAnt_Cnt=%d\n", -+ i, dm_fat_tbl->AuxAnt_Sum[i], dm_fat_tbl->AuxAnt_Cnt[i])); -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, -+ ("MacID=%d, Main_RSSI= %d, Aux_RSSI= %d\n", -+ i, Main_RSSI, Aux_RSSI)); -+ /* 2 Select MaxRSSI for DIG */ -+ LocalMaxRSSI = (Main_RSSI > Aux_RSSI) ? Main_RSSI : Aux_RSSI; -+ if ((LocalMaxRSSI > AntDivMaxRSSI) && (LocalMaxRSSI < 40)) -+ AntDivMaxRSSI = LocalMaxRSSI; -+ if (LocalMaxRSSI > MaxRSSI) -+ MaxRSSI = LocalMaxRSSI; -+ -+ /* 2 Select RX Idle Antenna */ -+ if ((dm_fat_tbl->RxIdleAnt == MAIN_ANT) && (Main_RSSI == 0)) -+ Main_RSSI = Aux_RSSI; -+ else if ((dm_fat_tbl->RxIdleAnt == AUX_ANT) && (Aux_RSSI == 0)) -+ Aux_RSSI = Main_RSSI; -+ -+ LocalMinRSSI = (Main_RSSI > Aux_RSSI) ? Aux_RSSI : Main_RSSI; -+ if (LocalMinRSSI < MinRSSI) { -+ MinRSSI = LocalMinRSSI; -+ RxIdleAnt = TargetAnt; -+ } -+ /* 2 Select TRX Antenna */ -+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) -+ odm_UpdateTxAnt_88E(dm_odm, TargetAnt, i); -+ } -+ dm_fat_tbl->MainAnt_Sum[i] = 0; -+ dm_fat_tbl->AuxAnt_Sum[i] = 0; -+ dm_fat_tbl->MainAnt_Cnt[i] = 0; -+ dm_fat_tbl->AuxAnt_Cnt[i] = 0; -+ } -+ -+ /* 2 Set RX Idle Antenna */ -+ ODM_UpdateRxIdleAnt_88E(dm_odm, RxIdleAnt); -+ -+ pDM_DigTable->AntDiv_RSSI_max = AntDivMaxRSSI; -+ pDM_DigTable->RSSI_max = MaxRSSI; -+} -+ -+void ODM_AntennaDiversity_88E(struct odm_dm_struct *dm_odm) -+{ -+ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; -+ if ((dm_odm->SupportICType != ODM_RTL8188E) || (!(dm_odm->SupportAbility & ODM_BB_ANT_DIV))) -+ return; -+ if (!dm_odm->bLinked) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_AntennaDiversity_88E(): No Link.\n")); -+ if (dm_fat_tbl->bBecomeLinked) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn off HW AntDiv\n")); -+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /* RegC50[7]=1'b1 enable HW AntDiv */ -+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 0); /* Enable CCK AntDiv */ -+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) -+ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 0); /* Reg80c[21]=1'b0 from TX Reg */ -+ dm_fat_tbl->bBecomeLinked = dm_odm->bLinked; -+ } -+ return; -+ } else { -+ if (!dm_fat_tbl->bBecomeLinked) { -+ ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn on HW AntDiv\n")); -+ /* Because HW AntDiv is disabled before Link, we enable HW AntDiv after link */ -+ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 1); /* RegC50[7]=1'b1 enable HW AntDiv */ -+ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 1); /* Enable CCK AntDiv */ -+ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) -+ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 1); /* Reg80c[21]=1'b1 from TX Info */ -+ dm_fat_tbl->bBecomeLinked = dm_odm->bLinked; -+ } -+ } -+ if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)) -+ odm_HWAntDiv(dm_odm); -+} -+ -+/* 3============================================================ */ -+/* 3 Dynamic Primary CCA */ -+/* 3============================================================ */ -+ -+void odm_PrimaryCCA_Init(struct odm_dm_struct *dm_odm) -+{ -+ struct dyn_primary_cca *PrimaryCCA = &(dm_odm->DM_PriCCA); -+ -+ PrimaryCCA->DupRTS_flag = 0; -+ PrimaryCCA->intf_flag = 0; -+ PrimaryCCA->intf_type = 0; -+ PrimaryCCA->Monitor_flag = 0; -+ PrimaryCCA->PriCCA_flag = 0; -+} -+ -+bool ODM_DynamicPrimaryCCA_DupRTS(struct odm_dm_struct *dm_odm) -+{ -+ struct dyn_primary_cca *PrimaryCCA = &(dm_odm->DM_PriCCA); -+ -+ return PrimaryCCA->DupRTS_flag; -+} -+ -+void odm_DynamicPrimaryCCA(struct odm_dm_struct *dm_odm) -+{ -+ return; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/odm_RegConfig8188E.c b/drivers/net/wireless/rtl8188eu/hal/odm_RegConfig8188E.c -new file mode 100644 -index 0000000000000..0ff31370fb984 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/odm_RegConfig8188E.c -@@ -0,0 +1,130 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include "odm_precomp.h" -+ -+void odm_ConfigRFReg_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, -+ u32 Data, enum rf_radio_path RF_PATH, -+ u32 RegAddr) -+{ -+ if (Addr == 0xffe) { -+ ODM_sleep_ms(50); -+ } else if (Addr == 0xfd) { -+ ODM_delay_ms(5); -+ } else if (Addr == 0xfc) { -+ ODM_delay_ms(1); -+ } else if (Addr == 0xfb) { -+ ODM_delay_us(50); -+ } else if (Addr == 0xfa) { -+ ODM_delay_us(5); -+ } else if (Addr == 0xf9) { -+ ODM_delay_us(1); -+ } else { -+ ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data); -+ /* Add 1us delay between BB/RF register setting. */ -+ ODM_delay_us(1); -+ } -+} -+ -+void odm_ConfigRF_RadioA_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data) -+{ -+ u32 content = 0x1000; /* RF_Content: radioa_txt */ -+ u32 maskforPhySet = (u32)(content&0xE000); -+ -+ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, RF_PATH_A, Addr|maskforPhySet); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioA] %08X %08X\n", Addr, Data)); -+} -+ -+void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data) -+{ -+ u32 content = 0x1001; /* RF_Content: radiob_txt */ -+ u32 maskforPhySet = (u32)(content&0xE000); -+ -+ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, RF_PATH_B, Addr|maskforPhySet); -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioB] %08X %08X\n", Addr, Data)); -+} -+ -+void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data) -+{ -+ ODM_Write1Byte(pDM_Odm, Addr, Data); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n", Addr, Data)); -+} -+ -+void odm_ConfigBB_AGC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data) -+{ -+ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); -+ /* Add 1us delay between BB/RF register setting. */ -+ ODM_delay_us(1); -+ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, -+ ("===> ODM_ConfigBBWithHeaderFile: [AGC_TAB] %08X %08X\n", -+ Addr, Data)); -+} -+ -+void odm_ConfigBB_PHY_REG_PG_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, -+ u32 Bitmask, u32 Data) -+{ -+ if (Addr == 0xfe) { -+ ODM_sleep_ms(50); -+ } else if (Addr == 0xfd) { -+ ODM_delay_ms(5); -+ } else if (Addr == 0xfc) { -+ ODM_delay_ms(1); -+ } else if (Addr == 0xfb) { -+ ODM_delay_us(50); -+ } else if (Addr == 0xfa) { -+ ODM_delay_us(5); -+ } else if (Addr == 0xf9) { -+ ODM_delay_us(1); -+ } else{ -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, -+ ("===> @@@@@@@ ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X %08X\n", -+ Addr, Bitmask, Data)); -+ storePwrIndexDiffRateOffset(pDM_Odm->Adapter, Addr, Bitmask, Data); -+ } -+} -+ -+void odm_ConfigBB_PHY_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data) -+{ -+ if (Addr == 0xfe) { -+ ODM_sleep_ms(50); -+ } else if (Addr == 0xfd) { -+ ODM_delay_ms(5); -+ } else if (Addr == 0xfc) { -+ ODM_delay_ms(1); -+ } else if (Addr == 0xfb) { -+ ODM_delay_us(50); -+ } else if (Addr == 0xfa) { -+ ODM_delay_us(5); -+ } else if (Addr == 0xf9) { -+ ODM_delay_us(1); -+ } else { -+ if (Addr == 0xa24) -+ pDM_Odm->RFCalibrateInfo.RegA24 = Data; -+ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); -+ -+ /* Add 1us delay between BB/RF register setting. */ -+ ODM_delay_us(1); -+ ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, -+ ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X\n", -+ Addr, Data)); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/odm_debug.c b/drivers/net/wireless/rtl8188eu/hal/odm_debug.c -new file mode 100644 -index 0000000000000..84caadd6c8e58 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/odm_debug.c -@@ -0,0 +1,32 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+/* include files */ -+ -+#include "odm_precomp.h" -+ -+void ODM_InitDebugSetting(struct odm_dm_struct *pDM_Odm) -+{ -+ pDM_Odm->DebugLevel = ODM_DBG_TRACE; -+ -+ pDM_Odm->DebugComponents = 0; -+} -+ -+u32 GlobalDebugLevel; -diff --git a/drivers/net/wireless/rtl8188eu/hal/odm_interface.c b/drivers/net/wireless/rtl8188eu/hal/odm_interface.c -new file mode 100644 -index 0000000000000..3be5a5f8d873a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/odm_interface.c -@@ -0,0 +1,205 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include "odm_precomp.h" -+/* ODM IO Relative API. */ -+ -+u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ return rtw_read8(Adapter, RegAddr); -+} -+ -+u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ return rtw_read16(Adapter, RegAddr); -+} -+ -+u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ return rtw_read32(Adapter, RegAddr); -+} -+ -+void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ rtw_write8(Adapter, RegAddr, Data); -+} -+ -+void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ rtw_write16(Adapter, RegAddr, Data); -+} -+ -+void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ rtw_write32(Adapter, RegAddr, Data); -+} -+ -+void ODM_SetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); -+} -+ -+u32 ODM_GetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ return PHY_QueryBBReg(Adapter, RegAddr, BitMask); -+} -+ -+void ODM_SetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); -+} -+ -+u32 ODM_GetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ return PHY_QueryBBReg(Adapter, RegAddr, BitMask); -+} -+ -+void ODM_SetRFReg(struct odm_dm_struct *pDM_Odm, enum rf_radio_path eRFPath, u32 RegAddr, u32 BitMask, u32 Data) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask, Data); -+} -+ -+u32 ODM_GetRFReg(struct odm_dm_struct *pDM_Odm, enum rf_radio_path eRFPath, u32 RegAddr, u32 BitMask) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ return PHY_QueryRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask); -+} -+ -+/* ODM Memory relative API. */ -+void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length) -+{ -+ *pPtr = rtw_zvmalloc(length); -+} -+ -+/* length could be ignored, used to detect memory leakage. */ -+void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length) -+{ -+ rtw_vmfree(pPtr, length); -+} -+ -+s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2, u32 length) -+{ -+ return !memcmp(pBuf1, pBuf2, length); -+} -+ -+/* ODM MISC relative API. */ -+void ODM_AcquireSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type) -+{ -+} -+ -+void ODM_ReleaseSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type) -+{ -+} -+ -+/* Work item relative API. FOr MP driver only~! */ -+void ODM_InitializeWorkItem(struct odm_dm_struct *pDM_Odm, void *pRtWorkItem, -+ RT_WORKITEM_CALL_BACK RtWorkItemCallback, -+ void *pContext, const char *szID) -+{ -+} -+ -+void ODM_StartWorkItem(void *pRtWorkItem) -+{ -+} -+ -+void ODM_StopWorkItem(void *pRtWorkItem) -+{ -+} -+ -+void ODM_FreeWorkItem(void *pRtWorkItem) -+{ -+} -+ -+void ODM_ScheduleWorkItem(void *pRtWorkItem) -+{ -+} -+ -+void ODM_IsWorkItemScheduled(void *pRtWorkItem) -+{ -+} -+ -+/* ODM Timer relative API. */ -+void ODM_StallExecution(u32 usDelay) -+{ -+ rtw_udelay_os(usDelay); -+} -+ -+void ODM_delay_ms(u32 ms) -+{ -+ rtw_mdelay_os(ms); -+} -+ -+void ODM_delay_us(u32 us) -+{ -+ rtw_udelay_os(us); -+} -+ -+void ODM_sleep_ms(u32 ms) -+{ -+ rtw_msleep_os(ms); -+} -+ -+void ODM_sleep_us(u32 us) -+{ -+ rtw_usleep_os(us); -+} -+ -+void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer, u32 msDelay) -+{ -+ _set_timer(pTimer, msDelay); /* ms */ -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) -+void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer, -+ void *CallBackFunc, void *pContext, -+ const char *szID) -+{ -+ struct adapter *Adapter = pDM_Odm->Adapter; -+ _init_timer(pTimer, Adapter->pnetdev, CallBackFunc, pDM_Odm); -+} -+#endif -+ -+void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer) -+{ -+ _cancel_timer_ex(pTimer); -+} -+ -+void ODM_ReleaseTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer) -+{ -+} -+ -+/* ODM FW relative API. */ -+u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum, -+ u32 *pElementID, u32 *pCmdLen, -+ u8 **pCmbBuffer, u8 *CmdStartSeq) -+{ -+ return true; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_cmd.c -new file mode 100644 -index 0000000000000..d60db45a6f0bc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_cmd.c -@@ -0,0 +1,762 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188E_CMD_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define RTL88E_MAX_H2C_BOX_NUMS 4 -+#define RTL88E_MAX_CMD_LEN 7 -+#define RTL88E_MESSAGE_BOX_SIZE 4 -+#define RTL88E_EX_MESSAGE_BOX_SIZE 4 -+ -+static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num) -+{ -+ u8 read_down = false; -+ int retry_cnts = 100; -+ -+ u8 valid; -+ -+ do { -+ valid = rtw_read8(adapt, REG_HMETFR) & BIT(msgbox_num); -+ if (0 == valid) -+ read_down = true; -+ } while ((!read_down) && (retry_cnts--)); -+ -+ return read_down; -+} -+ -+/***************************************** -+* H2C Msg format : -+* 0x1DF - 0x1D0 -+*| 31 - 8 | 7-5 4 - 0 | -+*| h2c_msg |Class_ID CMD_ID | -+* -+* Extend 0x1FF - 0x1F0 -+*|31 - 0 | -+*|ext_msg| -+******************************************/ -+static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) -+{ -+ u8 bcmd_down = false; -+ s32 retry_cnts = 100; -+ u8 h2c_box_num; -+ u32 msgbox_addr; -+ u32 msgbox_ex_addr; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ u8 cmd_idx, ext_cmd_len; -+ u32 h2c_cmd = 0; -+ u32 h2c_cmd_ex = 0; -+ s32 ret = _FAIL; -+ -+ if (!adapt->bFWReady) { -+ DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n"); -+ return ret; -+ } -+ -+ if (!pCmdBuffer) -+ goto exit; -+ if (CmdLen > RTL88E_MAX_CMD_LEN) -+ goto exit; -+ if (adapt->bSurpriseRemoved) -+ goto exit; -+ -+ /* pay attention to if race condition happened in H2C cmd setting. */ -+ do { -+ h2c_box_num = haldata->LastHMEBoxNum; -+ -+ if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) { -+ DBG_88E(" fw read cmd failed...\n"); -+ goto exit; -+ } -+ -+ *(u8 *)(&h2c_cmd) = ElementID; -+ -+ if (CmdLen <= 3) { -+ memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen); -+ } else { -+ memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3); -+ ext_cmd_len = CmdLen-3; -+ memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, ext_cmd_len); -+ -+ /* Write Ext command */ -+ msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * RTL88E_EX_MESSAGE_BOX_SIZE); -+ for (cmd_idx = 0; cmd_idx < ext_cmd_len; cmd_idx++) { -+ rtw_write8(adapt, msgbox_ex_addr+cmd_idx, *((u8 *)(&h2c_cmd_ex)+cmd_idx)); -+ } -+ } -+ /* Write command */ -+ msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * RTL88E_MESSAGE_BOX_SIZE); -+ for (cmd_idx = 0; cmd_idx < RTL88E_MESSAGE_BOX_SIZE; cmd_idx++) { -+ rtw_write8(adapt, msgbox_addr+cmd_idx, *((u8 *)(&h2c_cmd)+cmd_idx)); -+ } -+ bcmd_down = true; -+ -+ haldata->LastHMEBoxNum = (h2c_box_num+1) % RTL88E_MAX_H2C_BOX_NUMS; -+ -+ } while ((!bcmd_down) && (retry_cnts--)); -+ -+ ret = _SUCCESS; -+ -+exit: -+ -+ return ret; -+} -+ -+u8 rtl8188e_set_rssi_cmd(struct adapter *adapt, u8 *param) -+{ -+ u8 res = _SUCCESS; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ -+ if (haldata->fw_ractrl) { -+ ; -+ } else { -+ DBG_88E("==>%s fw dont support RA\n", __func__); -+ res = _FAIL; -+ } -+ -+ return res; -+} -+ -+u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask) -+{ -+ u8 buf[3]; -+ u8 res = _SUCCESS; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ -+ if (haldata->fw_ractrl) { -+ __le32 lmask; -+ -+ memset(buf, 0, 3); -+ lmask = cpu_to_le32(mask); -+ memcpy(buf, &lmask, 3); -+ -+ FillH2CCmd_88E(adapt, H2C_DM_MACID_CFG, 3, buf); -+ } else { -+ DBG_88E("==>%s fw dont support RA\n", __func__); -+ res = _FAIL; -+ } -+ -+ return res; -+} -+ -+/* bitmap[0:27] = tx_rate_bitmap */ -+/* bitmap[28:31]= Rate Adaptive id */ -+/* arg[0:4] = macid */ -+/* arg[5] = Short GI */ -+void rtl8188e_Add_RateATid(struct adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(pAdapter); -+ -+ u8 macid, init_rate, raid, shortGIrate = false; -+ -+ macid = arg&0x1f; -+ -+ raid = (bitmap>>28) & 0x0f; -+ bitmap &= 0x0fffffff; -+ -+ if (rssi_level != DM_RATR_STA_INIT) -+ bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, macid, bitmap, rssi_level); -+ -+ bitmap |= ((raid<<28)&0xf0000000); -+ -+ init_rate = get_highest_rate_idx(bitmap&0x0fffffff)&0x3f; -+ -+ shortGIrate = (arg&BIT(5)) ? true : false; -+ -+ if (shortGIrate) -+ init_rate |= BIT(6); -+ -+ raid = (bitmap>>28) & 0x0f; -+ -+ bitmap &= 0x0fffffff; -+ -+ DBG_88E("%s=> mac_id:%d, raid:%d, ra_bitmap=0x%x, shortGIrate=0x%02x\n", -+ __func__, macid, raid, bitmap, shortGIrate); -+ -+ ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv), macid, raid, bitmap, shortGIrate); -+} -+ -+void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode) -+{ -+ struct setpwrmode_parm H2CSetPwrMode; -+ struct pwrctrl_priv *pwrpriv = &adapt->pwrctrlpriv; -+ u8 RLBM = 0; /* 0:Min, 1:Max, 2:User define */ -+ -+ DBG_88E("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __func__, -+ Mode, pwrpriv->smart_ps, adapt->registrypriv.uapsd_enable); -+ -+ switch (Mode) { -+ case PS_MODE_ACTIVE: -+ H2CSetPwrMode.Mode = 0; -+ break; -+ case PS_MODE_MIN: -+ H2CSetPwrMode.Mode = 1; -+ break; -+ case PS_MODE_MAX: -+ RLBM = 1; -+ H2CSetPwrMode.Mode = 1; -+ break; -+ case PS_MODE_DTIM: -+ RLBM = 2; -+ H2CSetPwrMode.Mode = 1; -+ break; -+ case PS_MODE_UAPSD_WMM: -+ H2CSetPwrMode.Mode = 2; -+ break; -+ default: -+ H2CSetPwrMode.Mode = 0; -+ break; -+ } -+ -+ H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps<<4)&0xf0) | (RLBM & 0x0f)); -+ -+ H2CSetPwrMode.AwakeInterval = 1; -+ -+ H2CSetPwrMode.bAllQueueUAPSD = adapt->registrypriv.uapsd_enable; -+ -+ if (Mode > 0) -+ H2CSetPwrMode.PwrState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ -+ else -+ H2CSetPwrMode.PwrState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ -+ -+ FillH2CCmd_88E(adapt, H2C_PS_PWR_MODE, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode); -+ -+} -+ -+void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt) -+{ -+ u8 opmode, macid; -+ u16 mst_rpt = le16_to_cpu(mstatus_rpt); -+ opmode = (u8) mst_rpt; -+ macid = (u8)(mst_rpt >> 8); -+ -+ DBG_88E("### %s: MStatus=%x MACID=%d\n", __func__, opmode, macid); -+ FillH2CCmd_88E(adapt, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt); -+} -+ -+static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength) -+{ -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ u32 rate_len, pktlen; -+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ -+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); -+ SetFrameSubType(pframe, WIFI_BEACON); -+ -+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); -+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ -+ /* timestamp will be inserted by hardware */ -+ pframe += 8; -+ pktlen += 8; -+ -+ /* beacon interval: 2 bytes */ -+ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); -+ -+ pframe += 2; -+ pktlen += 2; -+ -+ /* capability info: 2 bytes */ -+ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); -+ -+ pframe += 2; -+ pktlen += 2; -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { -+ pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ie); -+ memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fixed_ie), pktlen); -+ -+ goto _ConstructBeacon; -+ } -+ -+ /* below for ad-hoc mode */ -+ -+ /* SSID */ -+ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); -+ -+ /* supported rates... */ -+ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); -+ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); -+ -+ /* DS parameter set */ -+ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); -+ -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) { -+ u32 ATIMWindow; -+ /* IBSS Parameter Set... */ -+ ATIMWindow = 0; -+ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); -+ } -+ -+ /* todo: ERP IE */ -+ -+ /* EXTERNDED SUPPORTED RATE */ -+ if (rate_len > 8) -+ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); -+ -+ /* todo:HT for adhoc */ -+ -+_ConstructBeacon: -+ -+ if ((pktlen + TXDESC_SIZE) > 512) { -+ DBG_88E("beacon frame too large\n"); -+ return; -+ } -+ -+ *pLength = pktlen; -+} -+ -+static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength) -+{ -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ __le16 *fctrl; -+ -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ /* Frame control. */ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ SetPwrMgt(fctrl); -+ SetFrameSubType(pframe, WIFI_PSPOLL); -+ -+ /* AID. */ -+ SetDuration(pframe, (pmlmeinfo->aid | 0xc000)); -+ -+ /* BSSID. */ -+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ -+ /* TA. */ -+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN); -+ -+ *pLength = 16; -+} -+ -+static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe, -+ u32 *pLength, -+ u8 *StaAddr, -+ u8 bQoS, -+ u8 AC, -+ u8 bEosp, -+ u8 bForcePowerSave) -+{ -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ u32 pktlen; -+ struct mlme_priv *pmlmepriv = &adapt->mlmepriv; -+ struct wlan_network *cur_network = &pmlmepriv->cur_network; -+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ fctrl = &pwlanhdr->frame_ctl; -+ *(fctrl) = 0; -+ if (bForcePowerSave) -+ SetPwrMgt(fctrl); -+ -+ switch (cur_network->network.InfrastructureMode) { -+ case Ndis802_11Infrastructure: -+ SetToDs(fctrl); -+ memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); -+ break; -+ case Ndis802_11APMode: -+ SetFrDs(fctrl); -+ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, myid(&(adapt->eeprompriv)), ETH_ALEN); -+ break; -+ case Ndis802_11IBSS: -+ default: -+ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN); -+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); -+ break; -+ } -+ -+ SetSeqNum(pwlanhdr, 0); -+ -+ if (bQoS) { -+ struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr; -+ -+ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); -+ -+ pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos *)pframe; -+ SetPriority(&pwlanqoshdr->qc, AC); -+ SetEOSP(&pwlanqoshdr->qc, bEosp); -+ -+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); -+ } else { -+ SetFrameSubType(pframe, WIFI_DATA_NULL); -+ -+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ } -+ -+ *pLength = pktlen; -+} -+ -+static void ConstructProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) -+{ -+ struct rtw_ieee80211_hdr *pwlanhdr; -+ __le16 *fctrl; -+ u8 *mac, *bssid; -+ u32 pktlen; -+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ -+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; -+ -+ mac = myid(&(adapt->eeprompriv)); -+ bssid = cur_network->MacAddress; -+ -+ fctrl = &(pwlanhdr->frame_ctl); -+ *(fctrl) = 0; -+ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); -+ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); -+ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); -+ -+ SetSeqNum(pwlanhdr, 0); -+ SetFrameSubType(fctrl, WIFI_PROBERSP); -+ -+ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); -+ pframe += pktlen; -+ -+ if (cur_network->IELength > MAX_IE_SZ) -+ return; -+ -+ memcpy(pframe, cur_network->IEs, cur_network->IELength); -+ pframe += cur_network->IELength; -+ pktlen += cur_network->IELength; -+ -+ *pLength = pktlen; -+} -+ -+/* To check if reserved page content is destroyed by beacon because beacon is too large. */ -+/* 2010.06.23. Added by tynli. */ -+void CheckFwRsvdPageContent(struct adapter *Adapter) -+{ -+} -+ -+/* */ -+/* Description: Fill the reserved packets that FW will use to RSVD page. */ -+/* Now we just send 4 types packet to rsvd page. */ -+/* (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */ -+/* Input: */ -+/* bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */ -+/* so we need to set the packet length to total length. */ -+/* true: At the second time, we should send the first packet (default:beacon) */ -+/* to Hw again and set the length in descriptor to the real beacon length. */ -+/* 2009.10.15 by tynli. */ -+static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished) -+{ -+ struct hal_data_8188e *haldata; -+ struct xmit_frame *pmgntframe; -+ struct pkt_attrib *pattrib; -+ struct xmit_priv *pxmitpriv; -+ struct mlme_ext_priv *pmlmeext; -+ struct mlme_ext_info *pmlmeinfo; -+ u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength; -+ u32 NullDataLength, QosNullLength; -+ u8 *ReservedPagePacket; -+ u8 PageNum, PageNeed, TxDescLen; -+ u16 BufIndex; -+ u32 TotalPacketLen; -+ struct rsvdpage_loc RsvdPageLoc; -+ -+ DBG_88E("%s\n", __func__); -+ ReservedPagePacket = (u8 *)rtw_zmalloc(1000); -+ if (ReservedPagePacket == NULL) { -+ DBG_88E("%s: alloc ReservedPagePacket fail!\n", __func__); -+ return; -+ } -+ -+ haldata = GET_HAL_DATA(adapt); -+ pxmitpriv = &adapt->xmitpriv; -+ pmlmeext = &adapt->mlmeextpriv; -+ pmlmeinfo = &pmlmeext->mlmext_info; -+ -+ TxDescLen = TXDESC_SIZE; -+ PageNum = 0; -+ -+ /* 3 (1) beacon * 2 pages */ -+ BufIndex = TXDESC_OFFSET; -+ ConstructBeacon(adapt, &ReservedPagePacket[BufIndex], &BeaconLength); -+ -+ /* When we count the first page size, we need to reserve description size for the RSVD */ -+ /* packet, it will be filled in front of the packet in TXPKTBUF. */ -+ PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength); -+ /* To reserved 2 pages for beacon buffer. 2010.06.24. */ -+ if (PageNeed == 1) -+ PageNeed += 1; -+ PageNum += PageNeed; -+ haldata->FwRsvdPageStartOffset = PageNum; -+ -+ BufIndex += PageNeed*128; -+ -+ /* 3 (2) ps-poll *1 page */ -+ RsvdPageLoc.LocPsPoll = PageNum; -+ ConstructPSPoll(adapt, &ReservedPagePacket[BufIndex], &PSPollLength); -+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false); -+ -+ PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength); -+ PageNum += PageNeed; -+ -+ BufIndex += PageNeed*128; -+ -+ /* 3 (3) null data * 1 page */ -+ RsvdPageLoc.LocNullData = PageNum; -+ ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, get_my_bssid(&pmlmeinfo->network), false, 0, 0, false); -+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false); -+ -+ PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength); -+ PageNum += PageNeed; -+ -+ BufIndex += PageNeed*128; -+ -+ /* 3 (4) probe response * 1page */ -+ RsvdPageLoc.LocProbeRsp = PageNum; -+ ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, get_my_bssid(&pmlmeinfo->network), false); -+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false); -+ -+ PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength); -+ PageNum += PageNeed; -+ -+ BufIndex += PageNeed*128; -+ -+ /* 3 (5) Qos null data */ -+ RsvdPageLoc.LocQosNull = PageNum; -+ ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], -+ &QosNullLength, get_my_bssid(&pmlmeinfo->network), true, 0, 0, false); -+ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false); -+ -+ PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength); -+ PageNum += PageNeed; -+ -+ TotalPacketLen = BufIndex + QosNullLength; -+ pmgntframe = alloc_mgtxmitframe(pxmitpriv); -+ if (pmgntframe == NULL) -+ goto exit; -+ -+ /* update attribute */ -+ pattrib = &pmgntframe->attrib; -+ update_mgntframe_attrib(adapt, pattrib); -+ pattrib->qsel = 0x10; -+ pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET; -+ pattrib->pktlen = pattrib->last_txcmdsz; -+ memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen); -+ -+ rtw_hal_mgnt_xmit(adapt, pmgntframe); -+ -+ DBG_88E("%s: Set RSVD page location to Fw\n", __func__); -+ FillH2CCmd_88E(adapt, H2C_COM_RSVD_PAGE, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc); -+ -+exit: -+ kfree(ReservedPagePacket); -+} -+ -+void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ bool bSendBeacon = false; -+ bool bcn_valid = false; -+ u8 DLBcnCount = 0; -+ u32 poll = 0; -+ -+ DBG_88E("%s mstatus(%x)\n", __func__, mstatus); -+ -+ if (mstatus == 1) { -+ /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ -+ /* Suggested by filen. Added by tynli. */ -+ rtw_write16(adapt, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid)); -+ /* Do not set TSF again here or vWiFi beacon DMA INT will not work. */ -+ -+ /* Set REG_CR bit 8. DMA beacon by SW. */ -+ haldata->RegCR_1 |= BIT0; -+ rtw_write8(adapt, REG_CR+1, haldata->RegCR_1); -+ -+ /* Disable Hw protection for a time which revserd for Hw sending beacon. */ -+ /* Fix download reserved page packet fail that access collision with the protection time. */ -+ /* 2010.05.11. Added by tynli. */ -+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)&(~BIT(3))); -+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)|BIT(4)); -+ -+ if (haldata->RegFwHwTxQCtrl&BIT6) { -+ DBG_88E("HalDownloadRSVDPage(): There is an Adapter is sending beacon.\n"); -+ bSendBeacon = true; -+ } -+ -+ /* Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. */ -+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl&(~BIT6))); -+ haldata->RegFwHwTxQCtrl &= (~BIT6); -+ -+ /* Clear beacon valid check bit. */ -+ rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL); -+ DLBcnCount = 0; -+ poll = 0; -+ do { -+ /* download rsvd page. */ -+ SetFwRsvdPagePkt(adapt, false); -+ DLBcnCount++; -+ do { -+ rtw_yield_os(); -+ /* rtw_mdelay_os(10); */ -+ /* check rsvd page download OK. */ -+ rtw_hal_get_hwreg(adapt, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid)); -+ poll++; -+ } while (!bcn_valid && (poll%10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped); -+ } while (!bcn_valid && DLBcnCount <= 100 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped); -+ -+ if (adapt->bSurpriseRemoved || adapt->bDriverStopped) -+ ; -+ else if (!bcn_valid) -+ DBG_88E("%s: 1 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll); -+ else -+ DBG_88E("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll); -+ /* */ -+ /* We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) */ -+ /* because we need to free the Tx BCN Desc which is used by the first reserved page packet. */ -+ /* At run time, we cannot get the Tx Desc until it is released in TxHandleInterrupt() so we will return */ -+ /* the beacon TCB in the following code. 2011.11.23. by tynli. */ -+ /* */ -+ -+ /* Enable Bcn */ -+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)|BIT(3)); -+ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)&(~BIT(4))); -+ -+ /* To make sure that if there exists an adapter which would like to send beacon. */ -+ /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ -+ /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ -+ /* the beacon cannot be sent by HW. */ -+ /* 2010.06.23. Added by tynli. */ -+ if (bSendBeacon) { -+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl|BIT6)); -+ haldata->RegFwHwTxQCtrl |= BIT6; -+ } -+ -+ /* Update RSVD page location H2C to Fw. */ -+ if (bcn_valid) { -+ rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL); -+ DBG_88E("Set RSVD page location to Fw.\n"); -+ } -+ -+ /* Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. */ -+ /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ -+ haldata->RegCR_1 &= (~BIT0); -+ rtw_write8(adapt, REG_CR+1, haldata->RegCR_1); -+ } -+ -+} -+ -+void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state) -+{ -+#ifdef CONFIG_88EU_P2P -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ struct wifidirect_info *pwdinfo = &(adapt->wdinfo); -+ struct P2P_PS_Offload_t *p2p_ps_offload = &haldata->p2p_ps_offload; -+ u8 i; -+ -+ switch (p2p_ps_state) { -+ case P2P_PS_DISABLE: -+ DBG_88E("P2P_PS_DISABLE\n"); -+ memset(p2p_ps_offload, 0, 1); -+ break; -+ case P2P_PS_ENABLE: -+ DBG_88E("P2P_PS_ENABLE\n"); -+ /* update CTWindow value. */ -+ if (pwdinfo->ctwindow > 0) { -+ p2p_ps_offload->CTWindow_En = 1; -+ rtw_write8(adapt, REG_P2P_CTWIN, pwdinfo->ctwindow); -+ } -+ -+ /* hw only support 2 set of NoA */ -+ for (i = 0; i < pwdinfo->noa_num; i++) { -+ /* To control the register setting for which NOA */ -+ rtw_write8(adapt, REG_NOA_DESC_SEL, (i << 4)); -+ if (i == 0) -+ p2p_ps_offload->NoA0_En = 1; -+ else -+ p2p_ps_offload->NoA1_En = 1; -+ -+ /* config P2P NoA Descriptor Register */ -+ rtw_write32(adapt, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]); -+ rtw_write32(adapt, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]); -+ rtw_write32(adapt, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]); -+ rtw_write8(adapt, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]); -+ } -+ -+ if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) { -+ /* rst p2p circuit */ -+ rtw_write8(adapt, REG_DUAL_TSF_RST, BIT(4)); -+ -+ p2p_ps_offload->Offload_En = 1; -+ -+ if (pwdinfo->role == P2P_ROLE_GO) { -+ p2p_ps_offload->role = 1; -+ p2p_ps_offload->AllStaSleep = 0; -+ } else { -+ p2p_ps_offload->role = 0; -+ } -+ -+ p2p_ps_offload->discovery = 0; -+ } -+ break; -+ case P2P_PS_SCAN: -+ DBG_88E("P2P_PS_SCAN\n"); -+ p2p_ps_offload->discovery = 1; -+ break; -+ case P2P_PS_SCAN_DONE: -+ DBG_88E("P2P_PS_SCAN_DONE\n"); -+ p2p_ps_offload->discovery = 0; -+ pwdinfo->p2p_ps_state = P2P_PS_ENABLE; -+ break; -+ default: -+ break; -+ } -+ -+ FillH2CCmd_88E(adapt, H2C_PS_P2P_OFFLOAD, 1, (u8 *)p2p_ps_offload); -+#endif -+ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_dm.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_dm.c -new file mode 100644 -index 0000000000000..85b05dd6e2af2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_dm.c -@@ -0,0 +1,267 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+/* */ -+/* Description: */ -+/* */ -+/* This file is for 92CE/92CU dynamic mechanism only */ -+/* */ -+/* */ -+/* */ -+#define _RTL8188E_DM_C_ -+ -+#include -+#include -+ -+#include -+ -+static void dm_CheckStatistics(struct adapter *Adapter) -+{ -+} -+ -+/* Initialize GPIO setting registers */ -+static void dm_InitGPIOSetting(struct adapter *Adapter) -+{ -+ u8 tmp1byte; -+ -+ tmp1byte = rtw_read8(Adapter, REG_GPIO_MUXCFG); -+ tmp1byte &= (GPIOSEL_GPIO | ~GPIOSEL_ENBT); -+ -+ rtw_write8(Adapter, REG_GPIO_MUXCFG, tmp1byte); -+} -+ -+/* */ -+/* functions */ -+/* */ -+static void Init_ODM_ComInfo_88E(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &hal_data->dmpriv; -+ struct odm_dm_struct *dm_odm = &(hal_data->odmpriv); -+ u8 cut_ver, fab_ver; -+ -+ /* Init Value */ -+ memset(dm_odm, 0, sizeof(*dm_odm)); -+ -+ dm_odm->Adapter = Adapter; -+ -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PLATFORM, ODM_CE); -+ -+ if (Adapter->interface_type == RTW_GSPI) -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, ODM_ITRF_SDIO); -+ else -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, Adapter->interface_type);/* RTL871X_HCI_TYPE */ -+ -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_IC_TYPE, ODM_RTL8188E); -+ -+ fab_ver = ODM_TSMC; -+ cut_ver = ODM_CUT_A; -+ -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_FAB_VER, fab_ver); -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_CUT_VER, cut_ver); -+ -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(hal_data->VersionID)); -+ -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PATCH_ID, hal_data->CustomerID); -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec); -+ -+ if (hal_data->rf_type == RF_1T1R) -+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R); -+ else if (hal_data->rf_type == RF_2T2R) -+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R); -+ else if (hal_data->rf_type == RF_1T2R) -+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R); -+ -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType); -+ -+ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION | -+ ODM_RF_TX_PWR_TRACK; -+ -+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag); -+} -+ -+static void Update_ODM_ComInfo_88E(struct adapter *Adapter) -+{ -+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; -+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; -+ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; -+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); -+ struct odm_dm_struct *dm_odm = &(hal_data->odmpriv); -+ struct dm_priv *pdmpriv = &hal_data->dmpriv; -+ int i; -+ -+ pdmpriv->InitODMFlag = ODM_BB_DIG | -+ ODM_BB_RA_MASK | -+ ODM_BB_DYNAMIC_TXPWR | -+ ODM_BB_FA_CNT | -+ ODM_BB_RSSI_MONITOR | -+ ODM_BB_CCK_PD | -+ ODM_BB_PWR_SAVE | -+ ODM_MAC_EDCA_TURBO | -+ ODM_RF_CALIBRATION | -+ ODM_RF_TX_PWR_TRACK; -+ if (hal_data->AntDivCfg) -+ pdmpriv->InitODMFlag |= ODM_BB_ANT_DIV; -+ -+ if (Adapter->registrypriv.mp_mode == 1) { -+ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION | -+ ODM_RF_TX_PWR_TRACK; -+ } -+ -+ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag); -+ -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_TX_UNI, &(Adapter->xmitpriv.tx_bytes)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_RX_UNI, &(Adapter->recvpriv.rx_bytes)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_WM_MODE, &(pmlmeext->cur_wireless_mode)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_CHNL_OFFSET, &(hal_data->nCur40MhzPrimeSC)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_MODE, &(Adapter->securitypriv.dot11PrivacyAlgrthm)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_BW, &(hal_data->CurrentChannelBW)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_CHNL, &(hal_data->CurrentChannel)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_NET_CLOSED, &(Adapter->net_closed)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_MP_MODE, &(Adapter->registrypriv.mp_mode)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SCAN, &(pmlmepriv->bScanInProcess)); -+ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_POWER_SAVING, &(pwrctrlpriv->bpower_saving)); -+ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType); -+ -+ for (i = 0; i < NUM_STA; i++) -+ ODM_CmnInfoPtrArrayHook(dm_odm, ODM_CMNINFO_STA_STATUS, i, NULL); -+} -+ -+void rtl8188e_InitHalDm(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &hal_data->dmpriv; -+ struct odm_dm_struct *dm_odm = &(hal_data->odmpriv); -+ -+ dm_InitGPIOSetting(Adapter); -+ pdmpriv->DM_Type = DM_Type_ByDriver; -+ pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE; -+ Update_ODM_ComInfo_88E(Adapter); -+ ODM_DMInit(dm_odm); -+ Adapter->fix_rate = 0xFF; -+} -+ -+void rtl8188e_HalDmWatchDog(struct adapter *Adapter) -+{ -+ bool fw_cur_in_ps = false; -+ bool fw_ps_awake = true; -+ u8 hw_init_completed = false; -+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); -+ -+ -+ hw_init_completed = Adapter->hw_init_completed; -+ -+ if (!hw_init_completed) -+ goto skip_dm; -+ -+ fw_cur_in_ps = Adapter->pwrctrlpriv.bFwCurrentInPSMode; -+ rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&fw_ps_awake)); -+ -+ /* Fw is under p2p powersaving mode, driver should stop dynamic mechanism. */ -+ /* modifed by thomas. 2011.06.11. */ -+ if (Adapter->wdinfo.p2p_ps_mode) -+ fw_ps_awake = false; -+ -+ if (hw_init_completed && ((!fw_cur_in_ps) && fw_ps_awake)) { -+ /* Calculate Tx/Rx statistics. */ -+ dm_CheckStatistics(Adapter); -+ -+ -+ } -+ -+ /* ODM */ -+ if (hw_init_completed) { -+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; -+ u8 bLinked = false; -+ -+ if ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) || -+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE))) { -+ if (Adapter->stapriv.asoc_sta_count > 2) -+ bLinked = true; -+ } else {/* Station mode */ -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) -+ bLinked = true; -+ } -+ -+ ODM_CmnInfoUpdate(&hal_data->odmpriv, ODM_CMNINFO_LINK, bLinked); -+ ODM_DMWatchdog(&hal_data->odmpriv); -+ } -+skip_dm: -+ /* Check GPIO to determine current RF on/off and Pbc status. */ -+ /* Check Hardware Radio ON/OFF or not */ -+ return; -+} -+ -+void rtl8188e_init_dm_priv(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &hal_data->dmpriv; -+ struct odm_dm_struct *podmpriv = &hal_data->odmpriv; -+ -+ memset(pdmpriv, 0, sizeof(struct dm_priv)); -+ Init_ODM_ComInfo_88E(Adapter); -+ ODM_InitDebugSetting(podmpriv); -+} -+ -+void rtl8188e_deinit_dm_priv(struct adapter *Adapter) -+{ -+} -+ -+/* Add new function to reset the state of antenna diversity before link. */ -+/* Compare RSSI for deciding antenna */ -+void AntDivCompare8188E(struct adapter *Adapter, struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src) -+{ -+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); -+ -+ if (0 != hal_data->AntDivCfg) { -+ /* select optimum_antenna for before linked =>For antenna diversity */ -+ if (dst->Rssi >= src->Rssi) {/* keep org parameter */ -+ src->Rssi = dst->Rssi; -+ src->PhyInfo.Optimum_antenna = dst->PhyInfo.Optimum_antenna; -+ } -+ } -+} -+ -+/* Add new function to reset the state of antenna diversity before link. */ -+u8 AntDivBeforeLink8188E(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); -+ struct odm_dm_struct *dm_odm = &hal_data->odmpriv; -+ struct sw_ant_switch *dm_swat_tbl = &dm_odm->DM_SWAT_Table; -+ struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); -+ -+ /* Condition that does not need to use antenna diversity. */ -+ if (hal_data->AntDivCfg == 0) -+ return false; -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED)) -+ return false; -+ -+ if (dm_swat_tbl->SWAS_NoLink_State == 0) { -+ /* switch channel */ -+ dm_swat_tbl->SWAS_NoLink_State = 1; -+ dm_swat_tbl->CurAntenna = (dm_swat_tbl->CurAntenna == Antenna_A) ? Antenna_B : Antenna_A; -+ -+ rtw_antenna_select_cmd(Adapter, dm_swat_tbl->CurAntenna, false); -+ return true; -+ } else { -+ dm_swat_tbl->SWAS_NoLink_State = 0; -+ return false; -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_hal_init.c -new file mode 100644 -index 0000000000000..d9f115d187c94 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_hal_init.c -@@ -0,0 +1,2390 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _HAL_INIT_C_ -+ -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#include -+ -+static void iol_mode_enable(struct adapter *padapter, u8 enable) -+{ -+ u8 reg_0xf0 = 0; -+ -+ if (enable) { -+ /* Enable initial offload */ -+ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); -+ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0|SW_OFFLOAD_EN); -+ -+ if (!padapter->bFWReady) { -+ DBG_88E("bFWReady == false call reset 8051...\n"); -+ _8051Reset88E(padapter); -+ } -+ -+ } else { -+ /* disable initial offload */ -+ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); -+ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 & ~SW_OFFLOAD_EN); -+ } -+} -+ -+static s32 iol_execute(struct adapter *padapter, u8 control) -+{ -+ s32 status = _FAIL; -+ u8 reg_0x88 = 0; -+ u32 start = 0, passing_time = 0; -+ -+ control = control&0x0f; -+ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); -+ rtw_write8(padapter, REG_HMEBOX_E0, reg_0x88|control); -+ -+ start = jiffies; -+ while ((reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0)) & control && -+ (passing_time = rtw_get_passing_time_ms(start)) < 1000) { -+ ; -+ } -+ -+ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); -+ status = (reg_0x88 & control) ? _FAIL : _SUCCESS; -+ if (reg_0x88 & control<<4) -+ status = _FAIL; -+ return status; -+} -+ -+static s32 iol_InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) -+{ -+ s32 rst = _SUCCESS; -+ iol_mode_enable(padapter, 1); -+ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); -+ rst = iol_execute(padapter, CMD_INIT_LLT); -+ iol_mode_enable(padapter, 0); -+ return rst; -+} -+ -+static void -+efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf) -+{ -+ u8 *efuseTbl = NULL; -+ u8 rtemp8; -+ u16 eFuse_Addr = 0; -+ u8 offset, wren; -+ u16 i, j; -+ u16 **eFuseWord = NULL; -+ u16 efuse_utilized = 0; -+ u8 u1temp = 0; -+ -+ efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E); -+ if (efuseTbl == NULL) { -+ DBG_88E("%s: alloc efuseTbl fail!\n", __func__); -+ goto exit; -+ } -+ -+ eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); -+ if (eFuseWord == NULL) { -+ DBG_88E("%s: alloc eFuseWord fail!\n", __func__); -+ goto exit; -+ } -+ -+ /* 0. Refresh efuse init map as all oxFF. */ -+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) -+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) -+ eFuseWord[i][j] = 0xFFFF; -+ -+ /* */ -+ /* 1. Read the first byte to check if efuse is empty!!! */ -+ /* */ -+ /* */ -+ rtemp8 = *(phymap+eFuse_Addr); -+ if (rtemp8 != 0xFF) { -+ efuse_utilized++; -+ eFuse_Addr++; -+ } else { -+ DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8); -+ goto exit; -+ } -+ -+ /* */ -+ /* 2. Read real efuse content. Filter PG header and every section data. */ -+ /* */ -+ while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { -+ /* Check PG header for section num. */ -+ if ((rtemp8 & 0x1F) == 0x0F) { /* extended header */ -+ u1temp = ((rtemp8 & 0xE0) >> 5); -+ rtemp8 = *(phymap+eFuse_Addr); -+ if ((rtemp8 & 0x0F) == 0x0F) { -+ eFuse_Addr++; -+ rtemp8 = *(phymap+eFuse_Addr); -+ -+ if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) -+ eFuse_Addr++; -+ continue; -+ } else { -+ offset = ((rtemp8 & 0xF0) >> 1) | u1temp; -+ wren = (rtemp8 & 0x0F); -+ eFuse_Addr++; -+ } -+ } else { -+ offset = ((rtemp8 >> 4) & 0x0f); -+ wren = (rtemp8 & 0x0f); -+ } -+ -+ if (offset < EFUSE_MAX_SECTION_88E) { -+ /* Get word enable value from PG header */ -+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { -+ /* Check word enable condition in the section */ -+ if (!(wren & 0x01)) { -+ rtemp8 = *(phymap+eFuse_Addr); -+ eFuse_Addr++; -+ efuse_utilized++; -+ eFuseWord[offset][i] = (rtemp8 & 0xff); -+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) -+ break; -+ rtemp8 = *(phymap+eFuse_Addr); -+ eFuse_Addr++; -+ efuse_utilized++; -+ eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00); -+ -+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) -+ break; -+ } -+ wren >>= 1; -+ } -+ } -+ /* Read next PG header */ -+ rtemp8 = *(phymap+eFuse_Addr); -+ -+ if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { -+ efuse_utilized++; -+ eFuse_Addr++; -+ } -+ } -+ -+ /* */ -+ /* 3. Collect 16 sections and 4 word unit into Efuse map. */ -+ /* */ -+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) { -+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { -+ efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff); -+ efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff); -+ } -+ } -+ -+ /* */ -+ /* 4. Copy from Efuse map to output pointer memory!!! */ -+ /* */ -+ for (i = 0; i < _size_byte; i++) -+ pbuf[i] = efuseTbl[_offset+i]; -+ -+ /* */ -+ /* 5. Calculate Efuse utilization. */ -+ /* */ -+ -+exit: -+ kfree(efuseTbl); -+ -+ if (eFuseWord) -+ rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); -+} -+ -+static void efuse_read_phymap_from_txpktbuf( -+ struct adapter *adapter, -+ int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */ -+ u8 *content, /* buffer to store efuse physical map */ -+ u16 *size /* for efuse content: the max byte to read. will update to byte read */ -+ ) -+{ -+ u16 dbg_addr = 0; -+ u32 start = 0, passing_time = 0; -+ u8 reg_0x143 = 0; -+ __le32 lo32 = 0, hi32 = 0; -+ u16 len = 0, count = 0; -+ int i = 0; -+ u16 limit = *size; -+ -+ u8 *pos = content; -+ -+ if (bcnhead < 0) /* if not valid */ -+ bcnhead = rtw_read8(adapter, REG_TDECTRL+1); -+ -+ DBG_88E("%s bcnhead:%d\n", __func__, bcnhead); -+ -+ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); -+ -+ dbg_addr = bcnhead*128/8; /* 8-bytes addressing */ -+ -+ while (1) { -+ rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i); -+ -+ rtw_write8(adapter, REG_TXPKTBUF_DBG, 0); -+ start = jiffies; -+ while (!(reg_0x143 = rtw_read8(adapter, REG_TXPKTBUF_DBG)) && -+ (passing_time = rtw_get_passing_time_ms(start)) < 1000) { -+ DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, rtw_read8(adapter, 0x106)); -+ rtw_usleep_os(100); -+ } -+ -+ /* data from EEPROM needs to be in LE */ -+ lo32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L)); -+ hi32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H)); -+ -+ if (i == 0) { -+ /* Although lenc is only used in a debug statement, -+ * do not remove it as the rtw_read16() call consumes -+ * 2 bytes from the EEPROM source. -+ */ -+ u16 lenc = rtw_read16(adapter, REG_PKTBUF_DBG_DATA_L); -+ -+ len = le32_to_cpu(lo32) & 0x0000ffff; -+ -+ limit = (len-2 < limit) ? len-2 : limit; -+ -+ DBG_88E("%s len:%u, lenc:%u\n", __func__, len, lenc); -+ -+ memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count); -+ count += (limit >= count+2) ? 2 : limit-count; -+ pos = content+count; -+ } else { -+ memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count); -+ count += (limit >= count+4) ? 4 : limit-count; -+ pos = content+count; -+ } -+ -+ if (limit > count && len-2 > count) { -+ memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count); -+ count += (limit >= count+4) ? 4 : limit-count; -+ pos = content+count; -+ } -+ -+ if (limit <= count || len-2 <= count) -+ break; -+ i++; -+ } -+ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); -+ DBG_88E("%s read count:%u\n", __func__, count); -+ *size = count; -+} -+ -+static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map) -+{ -+ s32 status = _FAIL; -+ u8 physical_map[512]; -+ u16 size = 512; -+ -+ rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy); -+ memset(physical_map, 0xFF, 512); -+ rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); -+ status = iol_execute(padapter, CMD_READ_EFUSE_MAP); -+ if (status == _SUCCESS) -+ efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size); -+ efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map); -+ return status; -+} -+ -+s32 rtl8188e_iol_efuse_patch(struct adapter *padapter) -+{ -+ s32 result = _SUCCESS; -+ -+ DBG_88E("==> %s\n", __func__); -+ if (rtw_IOL_applied(padapter)) { -+ iol_mode_enable(padapter, 1); -+ result = iol_execute(padapter, CMD_READ_EFUSE_MAP); -+ if (result == _SUCCESS) -+ result = iol_execute(padapter, CMD_EFUSE_PATCH); -+ -+ iol_mode_enable(padapter, 0); -+ } -+ return result; -+} -+ -+static s32 iol_ioconfig(struct adapter *padapter, u8 iocfg_bndy) -+{ -+ s32 rst = _SUCCESS; -+ -+ rtw_write8(padapter, REG_TDECTRL+1, iocfg_bndy); -+ rst = iol_execute(padapter, CMD_IOCONFIG); -+ return rst; -+} -+ -+static int rtl8188e_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) -+{ -+ struct pkt_attrib *pattrib = &xmit_frame->attrib; -+ u8 i; -+ int ret = _FAIL; -+ -+ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS) -+ goto exit; -+ if (rtw_usb_bulk_size_boundary(adapter, TXDESC_SIZE+pattrib->last_txcmdsz)) { -+ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS) -+ goto exit; -+ } -+ -+ dump_mgntframe_and_wait(adapter, xmit_frame, max_wating_ms); -+ -+ iol_mode_enable(adapter, 1); -+ for (i = 0; i < bndy_cnt; i++) { -+ u8 page_no = 0; -+ page_no = i*2; -+ ret = iol_ioconfig(adapter, page_no); -+ if (ret != _SUCCESS) -+ break; -+ } -+ iol_mode_enable(adapter, 0); -+exit: -+ /* restore BCN_HEAD */ -+ rtw_write8(adapter, REG_TDECTRL+1, 0); -+ return ret; -+} -+ -+void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int data_len) -+{ -+ u32 fifo_data, reg_140; -+ u32 addr, rstatus, loop = 0; -+ u16 data_cnts = (data_len/8)+1; -+ u8 *pbuf = rtw_zvmalloc(data_len+10); -+ DBG_88E("###### %s ######\n", __func__); -+ -+ rtw_write8(Adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); -+ if (pbuf) { -+ for (addr = 0; addr < data_cnts; addr++) { -+ rtw_write32(Adapter, 0x140, addr); -+ rtw_usleep_os(2); -+ loop = 0; -+ do { -+ rstatus = (reg_140 = rtw_read32(Adapter, REG_PKTBUF_DBG_CTRL)&BIT24); -+ if (rstatus) { -+ fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_L); -+ memcpy(pbuf+(addr*8), &fifo_data, 4); -+ -+ fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_H); -+ memcpy(pbuf+(addr*8+4), &fifo_data, 4); -+ } -+ rtw_usleep_os(2); -+ } while (!rstatus && (loop++ < 10)); -+ } -+ rtw_IOL_cmd_buf_dump(Adapter, data_len, pbuf); -+ rtw_vmfree(pbuf, data_len+10); -+ } -+ DBG_88E("###### %s ######\n", __func__); -+} -+ -+static void _FWDownloadEnable(struct adapter *padapter, bool enable) -+{ -+ u8 tmp; -+ -+ if (enable) { -+ /* MCU firmware download enable. */ -+ tmp = rtw_read8(padapter, REG_MCUFWDL); -+ rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01); -+ -+ /* 8051 reset */ -+ tmp = rtw_read8(padapter, REG_MCUFWDL+2); -+ rtw_write8(padapter, REG_MCUFWDL+2, tmp&0xf7); -+ } else { -+ /* MCU firmware download disable. */ -+ tmp = rtw_read8(padapter, REG_MCUFWDL); -+ rtw_write8(padapter, REG_MCUFWDL, tmp&0xfe); -+ -+ /* Reserved for fw extension. */ -+ rtw_write8(padapter, REG_MCUFWDL+1, 0x00); -+ } -+} -+ -+#define MAX_REG_BOLCK_SIZE 196 -+ -+static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) -+{ -+ int ret = _SUCCESS; -+ u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */ -+ u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */ -+ u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */ -+ u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; -+ u32 remainSize_p1 = 0, remainSize_p2 = 0; -+ u8 *bufferPtr = (u8 *)buffer; -+ u32 i = 0, offset = 0; -+ -+ blockSize_p1 = MAX_REG_BOLCK_SIZE; -+ -+ /* 3 Phase #1 */ -+ blockCount_p1 = buffSize / blockSize_p1; -+ remainSize_p1 = buffSize % blockSize_p1; -+ -+ if (blockCount_p1) { -+ RT_TRACE(_module_hal_init_c_, _drv_notice_, -+ ("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) blockCount_p1(%d) remainSize_p1(%d)\n", -+ buffSize, blockSize_p1, blockCount_p1, remainSize_p1)); -+ } -+ -+ for (i = 0; i < blockCount_p1; i++) { -+ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1)); -+ if (ret == _FAIL) -+ goto exit; -+ } -+ -+ /* 3 Phase #2 */ -+ if (remainSize_p1) { -+ offset = blockCount_p1 * blockSize_p1; -+ -+ blockCount_p2 = remainSize_p1/blockSize_p2; -+ remainSize_p2 = remainSize_p1%blockSize_p2; -+ -+ if (blockCount_p2) { -+ RT_TRACE(_module_hal_init_c_, _drv_notice_, -+ ("_BlockWrite: [P2] buffSize_p2(%d) blockSize_p2(%d) blockCount_p2(%d) remainSize_p2(%d)\n", -+ (buffSize-offset), blockSize_p2 , blockCount_p2, remainSize_p2)); -+ } -+ -+ for (i = 0; i < blockCount_p2; i++) { -+ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i*blockSize_p2), blockSize_p2, (bufferPtr + offset + i*blockSize_p2)); -+ -+ if (ret == _FAIL) -+ goto exit; -+ } -+ } -+ -+ /* 3 Phase #3 */ -+ if (remainSize_p2) { -+ offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2); -+ -+ blockCount_p3 = remainSize_p2 / blockSize_p3; -+ -+ RT_TRACE(_module_hal_init_c_, _drv_notice_, -+ ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) blockCount_p3(%d)\n", -+ (buffSize-offset), blockSize_p3, blockCount_p3)); -+ -+ for (i = 0; i < blockCount_p3; i++) { -+ ret = rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i)); -+ -+ if (ret == _FAIL) -+ goto exit; -+ } -+ } -+ -+exit: -+ return ret; -+} -+ -+static int _PageWrite(struct adapter *padapter, u32 page, void *buffer, u32 size) -+{ -+ u8 value8; -+ u8 u8Page = (u8)(page & 0x07); -+ -+ value8 = (rtw_read8(padapter, REG_MCUFWDL+2) & 0xF8) | u8Page; -+ rtw_write8(padapter, REG_MCUFWDL+2, value8); -+ -+ return _BlockWrite(padapter, buffer, size); -+} -+ -+static int _WriteFW(struct adapter *padapter, void *buffer, u32 size) -+{ -+ /* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */ -+ /* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */ -+ int ret = _SUCCESS; -+ u32 pageNums, remainSize; -+ u32 page, offset; -+ u8 *bufferPtr = (u8 *)buffer; -+ -+ pageNums = size / MAX_PAGE_SIZE; -+ remainSize = size % MAX_PAGE_SIZE; -+ -+ for (page = 0; page < pageNums; page++) { -+ offset = page * MAX_PAGE_SIZE; -+ ret = _PageWrite(padapter, page, bufferPtr+offset, MAX_PAGE_SIZE); -+ -+ if (ret == _FAIL) -+ goto exit; -+ } -+ if (remainSize) { -+ offset = pageNums * MAX_PAGE_SIZE; -+ page = pageNums; -+ ret = _PageWrite(padapter, page, bufferPtr+offset, remainSize); -+ -+ if (ret == _FAIL) -+ goto exit; -+ } -+ RT_TRACE(_module_hal_init_c_, _drv_info_, ("_WriteFW Done- for Normal chip.\n")); -+exit: -+ return ret; -+} -+ -+void _8051Reset88E(struct adapter *padapter) -+{ -+ u8 u1bTmp; -+ -+ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1); -+ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT2)); -+ rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp|(BIT2)); -+ DBG_88E("=====> _8051Reset88E(): 8051 reset success .\n"); -+} -+ -+static s32 _FWFreeToGo(struct adapter *padapter) -+{ -+ u32 counter = 0; -+ u32 value32; -+ -+ /* polling CheckSum report */ -+ do { -+ value32 = rtw_read32(padapter, REG_MCUFWDL); -+ if (value32 & FWDL_ChkSum_rpt) -+ break; -+ } while (counter++ < POLLING_READY_TIMEOUT_COUNT); -+ -+ if (counter >= POLLING_READY_TIMEOUT_COUNT) { -+ DBG_88E("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", __func__, value32); -+ return _FAIL; -+ } -+ DBG_88E("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__, value32); -+ -+ value32 = rtw_read32(padapter, REG_MCUFWDL); -+ value32 |= MCUFWDL_RDY; -+ value32 &= ~WINTINI_RDY; -+ rtw_write32(padapter, REG_MCUFWDL, value32); -+ -+ _8051Reset88E(padapter); -+ -+ /* polling for FW ready */ -+ counter = 0; -+ do { -+ value32 = rtw_read32(padapter, REG_MCUFWDL); -+ if (value32 & WINTINI_RDY) { -+ DBG_88E("%s: Polling FW ready success!! REG_MCUFWDL:0x%08x\n", __func__, value32); -+ return _SUCCESS; -+ } -+ rtw_udelay_os(5); -+ } while (counter++ < POLLING_READY_TIMEOUT_COUNT); -+ -+ DBG_88E("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __func__, value32); -+ return _FAIL; -+} -+ -+#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0) -+ -+static int load_firmware(struct rt_firmware *pFirmware, struct device *device) -+{ -+ s32 rtStatus = _SUCCESS; -+ const struct firmware *fw; -+ const char *fw_name = "rtlwifi/rtl8188eufw.bin"; -+ int err = request_firmware(&fw, fw_name, device); -+ -+ if (err) { -+ pr_err("Request firmware failed with error 0x%x\n", err); -+ rtStatus = _FAIL; -+ goto Exit; -+ } -+ if (!fw) { -+ pr_err("Firmware %s not available\n", fw_name); -+ rtStatus = _FAIL; -+ goto Exit; -+ } -+ if (fw->size > FW_8188E_SIZE) { -+ rtStatus = _FAIL; -+ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE)); -+ goto Exit; -+ } -+ -+ pFirmware->szFwBuffer = kzalloc(FW_8188E_SIZE, GFP_KERNEL); -+ if (!pFirmware->szFwBuffer) { -+ pr_err("Failed to allocate pFirmware->szFwBuffer\n"); -+ rtStatus = _FAIL; -+ goto Exit; -+ } -+ memcpy(pFirmware->szFwBuffer, fw->data, fw->size); -+ pFirmware->ulFwLength = fw->size; -+ release_firmware(fw); -+ DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, pFirmware->ulFwLength); -+ -+Exit: -+ return rtStatus; -+} -+ -+s32 rtl8188e_FirmwareDownload(struct adapter *padapter) -+{ -+ s32 rtStatus = _SUCCESS; -+ u8 writeFW_retry = 0; -+ u32 fwdl_start_time; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); -+ struct device *device = dvobj_to_dev(dvobj); -+ struct rt_firmware_hdr *pFwHdr = NULL; -+ u8 *pFirmwareBuf; -+ u32 FirmwareLen; -+ static int log_version; -+ -+ RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__)); -+ if (!dvobj->firmware.szFwBuffer) -+ rtStatus = load_firmware(&dvobj->firmware, device); -+ if (rtStatus == _FAIL) { -+ dvobj->firmware.szFwBuffer = NULL; -+ goto Exit; -+ } -+ pFirmwareBuf = dvobj->firmware.szFwBuffer; -+ FirmwareLen = dvobj->firmware.ulFwLength; -+ -+ /* To Check Fw header. Added by tynli. 2009.12.04. */ -+ pFwHdr = (struct rt_firmware_hdr *)dvobj->firmware.szFwBuffer; -+ -+ pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version); -+ pHalData->FirmwareSubVersion = pFwHdr->Subversion; -+ pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature); -+ -+ if (!log_version++) -+ pr_info("%sFirmware Version %d, SubVersion %d, Signature 0x%x\n", -+ DRIVER_PREFIX, pHalData->FirmwareVersion, -+ pHalData->FirmwareSubVersion, pHalData->FirmwareSignature); -+ -+ if (IS_FW_HEADER_EXIST(pFwHdr)) { -+ /* Shift 32 bytes for FW header */ -+ pFirmwareBuf = pFirmwareBuf + 32; -+ FirmwareLen = FirmwareLen - 32; -+ } -+ -+ /* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */ -+ /* or it will cause download Fw fail. 2010.02.01. by tynli. */ -+ if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */ -+ rtw_write8(padapter, REG_MCUFWDL, 0x00); -+ _8051Reset88E(padapter); -+ } -+ -+ _FWDownloadEnable(padapter, true); -+ fwdl_start_time = jiffies; -+ while (1) { -+ /* reset the FWDL chksum */ -+ rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_ChkSum_rpt); -+ -+ rtStatus = _WriteFW(padapter, pFirmwareBuf, FirmwareLen); -+ -+ if (rtStatus == _SUCCESS || -+ (rtw_get_passing_time_ms(fwdl_start_time) > 500 && writeFW_retry++ >= 3)) -+ break; -+ -+ DBG_88E("%s writeFW_retry:%u, time after fwdl_start_time:%ums\n", -+ __func__, writeFW_retry, rtw_get_passing_time_ms(fwdl_start_time) -+ ); -+ } -+ _FWDownloadEnable(padapter, false); -+ if (_SUCCESS != rtStatus) { -+ DBG_88E("DL Firmware failed!\n"); -+ goto Exit; -+ } -+ -+ rtStatus = _FWFreeToGo(padapter); -+ if (_SUCCESS != rtStatus) { -+ DBG_88E("DL Firmware failed!\n"); -+ goto Exit; -+ } -+ RT_TRACE(_module_hal_init_c_, _drv_info_, ("Firmware is ready to run!\n")); -+ -+Exit: -+ return rtStatus; -+} -+ -+void rtl8188e_InitializeFirmwareVars(struct adapter *padapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ -+ /* Init Fw LPS related. */ -+ padapter->pwrctrlpriv.bFwCurrentInPSMode = false; -+ -+ /* Init H2C counter. by tynli. 2009.12.09. */ -+ pHalData->LastHMEBoxNum = 0; -+} -+ -+static void rtl8188e_free_hal_data(struct adapter *padapter) -+{ -+ -+ kfree(padapter->HalData); -+ padapter->HalData = NULL; -+ -+} -+ -+/* */ -+/* Efuse related code */ -+/* */ -+enum{ -+ VOLTAGE_V25 = 0x03, -+ LDOE25_SHIFT = 28 , -+ }; -+ -+static bool -+hal_EfusePgPacketWrite2ByteHeader( -+ struct adapter *pAdapter, -+ u8 efuseType, -+ u16 *pAddr, -+ struct pgpkt *pTargetPkt, -+ bool bPseudoTest); -+static bool -+hal_EfusePgPacketWrite1ByteHeader( -+ struct adapter *pAdapter, -+ u8 efuseType, -+ u16 *pAddr, -+ struct pgpkt *pTargetPkt, -+ bool bPseudoTest); -+static bool -+hal_EfusePgPacketWriteData( -+ struct adapter *pAdapter, -+ u8 efuseType, -+ u16 *pAddr, -+ struct pgpkt *pTargetPkt, -+ bool bPseudoTest); -+ -+static void -+hal_EfusePowerSwitch_RTL8188E( -+ struct adapter *pAdapter, -+ u8 bWrite, -+ u8 PwrState) -+{ -+ u8 tempval; -+ u16 tmpV16; -+ -+ if (PwrState) { -+ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); -+ -+ /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */ -+ tmpV16 = rtw_read16(pAdapter, REG_SYS_ISO_CTRL); -+ if (!(tmpV16 & PWC_EV12V)) { -+ tmpV16 |= PWC_EV12V; -+ rtw_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16); -+ } -+ /* Reset: 0x0000h[28], default valid */ -+ tmpV16 = rtw_read16(pAdapter, REG_SYS_FUNC_EN); -+ if (!(tmpV16 & FEN_ELDR)) { -+ tmpV16 |= FEN_ELDR; -+ rtw_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16); -+ } -+ -+ /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ -+ tmpV16 = rtw_read16(pAdapter, REG_SYS_CLKR); -+ if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { -+ tmpV16 |= (LOADER_CLK_EN | ANA8M); -+ rtw_write16(pAdapter, REG_SYS_CLKR, tmpV16); -+ } -+ -+ if (bWrite) { -+ /* Enable LDO 2.5V before read/write action */ -+ tempval = rtw_read8(pAdapter, EFUSE_TEST+3); -+ tempval &= 0x0F; -+ tempval |= (VOLTAGE_V25 << 4); -+ rtw_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80)); -+ } -+ } else { -+ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); -+ -+ if (bWrite) { -+ /* Disable LDO 2.5V after read/write action */ -+ tempval = rtw_read8(pAdapter, EFUSE_TEST+3); -+ rtw_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F)); -+ } -+ } -+} -+ -+static void -+rtl8188e_EfusePowerSwitch( -+ struct adapter *pAdapter, -+ u8 bWrite, -+ u8 PwrState) -+{ -+ hal_EfusePowerSwitch_RTL8188E(pAdapter, bWrite, PwrState); -+} -+ -+static void Hal_EfuseReadEFuse88E(struct adapter *Adapter, -+ u16 _offset, -+ u16 _size_byte, -+ u8 *pbuf, -+ bool bPseudoTest -+ ) -+{ -+ u8 *efuseTbl = NULL; -+ u8 rtemp8[1]; -+ u16 eFuse_Addr = 0; -+ u8 offset, wren; -+ u16 i, j; -+ u16 **eFuseWord = NULL; -+ u16 efuse_utilized = 0; -+ u8 u1temp = 0; -+ -+ /* */ -+ /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ -+ /* */ -+ if ((_offset + _size_byte) > EFUSE_MAP_LEN_88E) {/* total E-Fuse table is 512bytes */ -+ DBG_88E("Hal_EfuseReadEFuse88E(): Invalid offset(%#x) with read bytes(%#x)!!\n", _offset, _size_byte); -+ goto exit; -+ } -+ -+ efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E); -+ if (efuseTbl == NULL) { -+ DBG_88E("%s: alloc efuseTbl fail!\n", __func__); -+ goto exit; -+ } -+ -+ eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); -+ if (eFuseWord == NULL) { -+ DBG_88E("%s: alloc eFuseWord fail!\n", __func__); -+ goto exit; -+ } -+ -+ /* 0. Refresh efuse init map as all oxFF. */ -+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) -+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) -+ eFuseWord[i][j] = 0xFFFF; -+ -+ /* */ -+ /* 1. Read the first byte to check if efuse is empty!!! */ -+ /* */ -+ /* */ -+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); -+ if (*rtemp8 != 0xFF) { -+ efuse_utilized++; -+ eFuse_Addr++; -+ } else { -+ DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, *rtemp8); -+ goto exit; -+ } -+ -+ /* */ -+ /* 2. Read real efuse content. Filter PG header and every section data. */ -+ /* */ -+ while ((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { -+ /* Check PG header for section num. */ -+ if ((*rtemp8 & 0x1F) == 0x0F) { /* extended header */ -+ u1temp = ((*rtemp8 & 0xE0) >> 5); -+ -+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); -+ -+ if ((*rtemp8 & 0x0F) == 0x0F) { -+ eFuse_Addr++; -+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); -+ -+ if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) -+ eFuse_Addr++; -+ continue; -+ } else { -+ offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; -+ wren = (*rtemp8 & 0x0F); -+ eFuse_Addr++; -+ } -+ } else { -+ offset = ((*rtemp8 >> 4) & 0x0f); -+ wren = (*rtemp8 & 0x0f); -+ } -+ -+ if (offset < EFUSE_MAX_SECTION_88E) { -+ /* Get word enable value from PG header */ -+ -+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { -+ /* Check word enable condition in the section */ -+ if (!(wren & 0x01)) { -+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); -+ eFuse_Addr++; -+ efuse_utilized++; -+ eFuseWord[offset][i] = (*rtemp8 & 0xff); -+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) -+ break; -+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); -+ eFuse_Addr++; -+ efuse_utilized++; -+ eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00); -+ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) -+ break; -+ } -+ wren >>= 1; -+ } -+ } -+ -+ /* Read next PG header */ -+ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); -+ -+ if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { -+ efuse_utilized++; -+ eFuse_Addr++; -+ } -+ } -+ -+ /* 3. Collect 16 sections and 4 word unit into Efuse map. */ -+ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) { -+ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { -+ efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff); -+ efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff); -+ } -+ } -+ -+ /* 4. Copy from Efuse map to output pointer memory!!! */ -+ for (i = 0; i < _size_byte; i++) -+ pbuf[i] = efuseTbl[_offset+i]; -+ -+ /* 5. Calculate Efuse utilization. */ -+ rtw_hal_set_hwreg(Adapter, HW_VAR_EFUSE_BYTES, (u8 *)&eFuse_Addr); -+ -+exit: -+ kfree(efuseTbl); -+ -+ if (eFuseWord) -+ rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); -+} -+ -+static void ReadEFuseByIC(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest) -+{ -+ if (!bPseudoTest) { -+ int ret = _FAIL; -+ if (rtw_IOL_applied(Adapter)) { -+ rtw_hal_power_on(Adapter); -+ -+ iol_mode_enable(Adapter, 1); -+ ret = iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf); -+ iol_mode_enable(Adapter, 0); -+ -+ if (_SUCCESS == ret) -+ goto exit; -+ } -+ } -+ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest); -+ -+exit: -+ return; -+} -+ -+static void ReadEFuse_Pseudo(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest) -+{ -+ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest); -+} -+ -+static void rtl8188e_ReadEFuse(struct adapter *Adapter, u8 efuseType, -+ u16 _offset, u16 _size_byte, u8 *pbuf, -+ bool bPseudoTest) -+{ -+ if (bPseudoTest) -+ ReadEFuse_Pseudo (Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); -+ else -+ ReadEFuseByIC(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); -+} -+ -+/* Do not support BT */ -+static void Hal_EFUSEGetEfuseDefinition88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut) -+{ -+ switch (type) { -+ case TYPE_EFUSE_MAX_SECTION: -+ { -+ u8 *pMax_section; -+ pMax_section = (u8 *)pOut; -+ *pMax_section = EFUSE_MAX_SECTION_88E; -+ } -+ break; -+ case TYPE_EFUSE_REAL_CONTENT_LEN: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; -+ } -+ break; -+ case TYPE_EFUSE_CONTENT_LEN_BANK: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; -+ } -+ break; -+ case TYPE_AVAILABLE_EFUSE_BYTES_BANK: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); -+ } -+ break; -+ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); -+ } -+ break; -+ case TYPE_EFUSE_MAP_LEN: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = (u16)EFUSE_MAP_LEN_88E; -+ } -+ break; -+ case TYPE_EFUSE_PROTECT_BYTES_BANK: -+ { -+ u8 *pu1Tmp; -+ pu1Tmp = (u8 *)pOut; -+ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); -+ } -+ break; -+ default: -+ { -+ u8 *pu1Tmp; -+ pu1Tmp = (u8 *)pOut; -+ *pu1Tmp = 0; -+ } -+ break; -+ } -+} -+ -+static void Hal_EFUSEGetEfuseDefinition_Pseudo88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut) -+{ -+ switch (type) { -+ case TYPE_EFUSE_MAX_SECTION: -+ { -+ u8 *pMax_section; -+ pMax_section = (u8 *)pOut; -+ *pMax_section = EFUSE_MAX_SECTION_88E; -+ } -+ break; -+ case TYPE_EFUSE_REAL_CONTENT_LEN: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; -+ } -+ break; -+ case TYPE_EFUSE_CONTENT_LEN_BANK: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; -+ } -+ break; -+ case TYPE_AVAILABLE_EFUSE_BYTES_BANK: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); -+ } -+ break; -+ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E); -+ } -+ break; -+ case TYPE_EFUSE_MAP_LEN: -+ { -+ u16 *pu2Tmp; -+ pu2Tmp = (u16 *)pOut; -+ *pu2Tmp = (u16)EFUSE_MAP_LEN_88E; -+ } -+ break; -+ case TYPE_EFUSE_PROTECT_BYTES_BANK: -+ { -+ u8 *pu1Tmp; -+ pu1Tmp = (u8 *)pOut; -+ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); -+ } -+ break; -+ default: -+ { -+ u8 *pu1Tmp; -+ pu1Tmp = (u8 *)pOut; -+ *pu1Tmp = 0; -+ } -+ break; -+ } -+} -+ -+static void rtl8188e_EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest) -+{ -+ if (bPseudoTest) -+ Hal_EFUSEGetEfuseDefinition_Pseudo88E(pAdapter, efuseType, type, pOut); -+ else -+ Hal_EFUSEGetEfuseDefinition88E(pAdapter, efuseType, type, pOut); -+} -+ -+static u8 Hal_EfuseWordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest) -+{ -+ u16 tmpaddr = 0; -+ u16 start_addr = efuse_addr; -+ u8 badworden = 0x0F; -+ u8 tmpdata[8]; -+ -+ memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE); -+ -+ if (!(word_en&BIT0)) { -+ tmpaddr = start_addr; -+ efuse_OneByteWrite(pAdapter, start_addr++, data[0], bPseudoTest); -+ efuse_OneByteWrite(pAdapter, start_addr++, data[1], bPseudoTest); -+ -+ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0], bPseudoTest); -+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1], bPseudoTest); -+ if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) -+ badworden &= (~BIT0); -+ } -+ if (!(word_en&BIT1)) { -+ tmpaddr = start_addr; -+ efuse_OneByteWrite(pAdapter, start_addr++, data[2], bPseudoTest); -+ efuse_OneByteWrite(pAdapter, start_addr++, data[3], bPseudoTest); -+ -+ efuse_OneByteRead(pAdapter, tmpaddr , &tmpdata[2], bPseudoTest); -+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3], bPseudoTest); -+ if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) -+ badworden &= (~BIT1); -+ } -+ if (!(word_en&BIT2)) { -+ tmpaddr = start_addr; -+ efuse_OneByteWrite(pAdapter, start_addr++, data[4], bPseudoTest); -+ efuse_OneByteWrite(pAdapter, start_addr++, data[5], bPseudoTest); -+ -+ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4], bPseudoTest); -+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5], bPseudoTest); -+ if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) -+ badworden &= (~BIT2); -+ } -+ if (!(word_en&BIT3)) { -+ tmpaddr = start_addr; -+ efuse_OneByteWrite(pAdapter, start_addr++, data[6], bPseudoTest); -+ efuse_OneByteWrite(pAdapter, start_addr++, data[7], bPseudoTest); -+ -+ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6], bPseudoTest); -+ efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7], bPseudoTest); -+ if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) -+ badworden &= (~BIT3); -+ } -+ return badworden; -+} -+ -+static u8 Hal_EfuseWordEnableDataWrite_Pseudo(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest) -+{ -+ u8 ret; -+ -+ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); -+ return ret; -+} -+ -+static u8 rtl8188e_Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest) -+{ -+ u8 ret = 0; -+ -+ if (bPseudoTest) -+ ret = Hal_EfuseWordEnableDataWrite_Pseudo (pAdapter, efuse_addr, word_en, data, bPseudoTest); -+ else -+ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); -+ return ret; -+} -+ -+static u16 hal_EfuseGetCurrentSize_8188e(struct adapter *pAdapter, bool bPseudoTest) -+{ -+ int bContinual = true; -+ u16 efuse_addr = 0; -+ u8 hoffset = 0, hworden = 0; -+ u8 efuse_data, word_cnts = 0; -+ -+ if (bPseudoTest) -+ efuse_addr = (u16)(fakeEfuseUsedBytes); -+ else -+ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); -+ -+ while (bContinual && -+ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) && -+ AVAILABLE_EFUSE_ADDR(efuse_addr)) { -+ if (efuse_data != 0xFF) { -+ if ((efuse_data&0x1F) == 0x0F) { /* extended header */ -+ hoffset = efuse_data; -+ efuse_addr++; -+ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest); -+ if ((efuse_data & 0x0F) == 0x0F) { -+ efuse_addr++; -+ continue; -+ } else { -+ hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); -+ hworden = efuse_data & 0x0F; -+ } -+ } else { -+ hoffset = (efuse_data>>4) & 0x0F; -+ hworden = efuse_data & 0x0F; -+ } -+ word_cnts = Efuse_CalculateWordCnts(hworden); -+ /* read next header */ -+ efuse_addr = efuse_addr + (word_cnts*2)+1; -+ } else { -+ bContinual = false; -+ } -+ } -+ -+ if (bPseudoTest) -+ fakeEfuseUsedBytes = efuse_addr; -+ else -+ rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); -+ -+ return efuse_addr; -+} -+ -+static u16 Hal_EfuseGetCurrentSize_Pseudo(struct adapter *pAdapter, bool bPseudoTest) -+{ -+ u16 ret = 0; -+ -+ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest); -+ return ret; -+} -+ -+static u16 rtl8188e_EfuseGetCurrentSize(struct adapter *pAdapter, u8 efuseType, bool bPseudoTest) -+{ -+ u16 ret = 0; -+ -+ if (bPseudoTest) -+ ret = Hal_EfuseGetCurrentSize_Pseudo(pAdapter, bPseudoTest); -+ else -+ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest); -+ return ret; -+} -+ -+static int hal_EfusePgPacketRead_8188e(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) -+{ -+ u8 ReadState = PG_STATE_HEADER; -+ int bContinual = true; -+ int bDataEmpty = true; -+ u8 efuse_data, word_cnts = 0; -+ u16 efuse_addr = 0; -+ u8 hoffset = 0, hworden = 0; -+ u8 tmpidx = 0; -+ u8 tmpdata[8]; -+ u8 max_section = 0; -+ u8 tmp_header = 0; -+ -+ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section, bPseudoTest); -+ -+ if (data == NULL) -+ return false; -+ if (offset > max_section) -+ return false; -+ -+ memset((void *)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); -+ memset((void *)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE); -+ -+ /* Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */ -+ /* Skip dummy parts to prevent unexpected data read from Efuse. */ -+ /* By pass right now. 2009.02.19. */ -+ while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) { -+ /* Header Read ------------- */ -+ if (ReadState & PG_STATE_HEADER) { -+ if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) { -+ if (EXT_HEADER(efuse_data)) { -+ tmp_header = efuse_data; -+ efuse_addr++; -+ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest); -+ if (!ALL_WORDS_DISABLED(efuse_data)) { -+ hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); -+ hworden = efuse_data & 0x0F; -+ } else { -+ DBG_88E("Error, All words disabled\n"); -+ efuse_addr++; -+ continue; -+ } -+ } else { -+ hoffset = (efuse_data>>4) & 0x0F; -+ hworden = efuse_data & 0x0F; -+ } -+ word_cnts = Efuse_CalculateWordCnts(hworden); -+ bDataEmpty = true; -+ -+ if (hoffset == offset) { -+ for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) { -+ if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data, bPseudoTest)) { -+ tmpdata[tmpidx] = efuse_data; -+ if (efuse_data != 0xff) -+ bDataEmpty = false; -+ } -+ } -+ if (bDataEmpty == false) { -+ ReadState = PG_STATE_DATA; -+ } else {/* read next header */ -+ efuse_addr = efuse_addr + (word_cnts*2)+1; -+ ReadState = PG_STATE_HEADER; -+ } -+ } else {/* read next header */ -+ efuse_addr = efuse_addr + (word_cnts*2)+1; -+ ReadState = PG_STATE_HEADER; -+ } -+ } else { -+ bContinual = false; -+ } -+ } else if (ReadState & PG_STATE_DATA) { -+ /* Data section Read ------------- */ -+ efuse_WordEnableDataRead(hworden, tmpdata, data); -+ efuse_addr = efuse_addr + (word_cnts*2)+1; -+ ReadState = PG_STATE_HEADER; -+ } -+ -+ } -+ -+ if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff) && (data[3] == 0xff) && -+ (data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff) && (data[7] == 0xff)) -+ return false; -+ else -+ return true; -+} -+ -+static int Hal_EfusePgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) -+{ -+ int ret; -+ -+ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest); -+ return ret; -+} -+ -+static int Hal_EfusePgPacketRead_Pseudo(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) -+{ -+ int ret; -+ -+ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest); -+ return ret; -+} -+ -+static int rtl8188e_Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) -+{ -+ int ret; -+ -+ if (bPseudoTest) -+ ret = Hal_EfusePgPacketRead_Pseudo (pAdapter, offset, data, bPseudoTest); -+ else -+ ret = Hal_EfusePgPacketRead(pAdapter, offset, data, bPseudoTest); -+ return ret; -+} -+ -+static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr, bool bPseudoTest) -+{ -+ u8 originaldata[8], badworden = 0; -+ u16 efuse_addr = *pAddr; -+ u32 PgWriteSuccess = 0; -+ -+ memset((void *)originaldata, 0xff, 8); -+ -+ if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata, bPseudoTest)) { -+ /* check if data exist */ -+ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata, bPseudoTest); -+ -+ if (badworden != 0xf) { /* write fail */ -+ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata, bPseudoTest); -+ -+ if (!PgWriteSuccess) -+ return false; -+ else -+ efuse_addr = Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest); -+ } else { -+ efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1; -+ } -+ } else { -+ efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1; -+ } -+ *pAddr = efuse_addr; -+ return true; -+} -+ -+static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) -+{ -+ bool bRet = false; -+ u16 efuse_addr = *pAddr, efuse_max_available_len = 0; -+ u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0; -+ u8 repeatcnt = 0; -+ -+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest); -+ -+ while (efuse_addr < efuse_max_available_len) { -+ pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; -+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); -+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); -+ -+ while (tmp_header == 0xFF) { -+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) -+ return false; -+ -+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); -+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); -+ } -+ -+ /* to write ext_header */ -+ if (tmp_header == pg_header) { -+ efuse_addr++; -+ pg_header_temp = pg_header; -+ pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; -+ -+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); -+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); -+ -+ while (tmp_header == 0xFF) { -+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) -+ return false; -+ -+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); -+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); -+ } -+ -+ if ((tmp_header & 0x0F) == 0x0F) { /* word_en PG fail */ -+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { -+ return false; -+ } else { -+ efuse_addr++; -+ continue; -+ } -+ } else if (pg_header != tmp_header) { /* offset PG fail */ -+ struct pgpkt fixPkt; -+ fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1); -+ fixPkt.word_en = tmp_header & 0x0F; -+ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); -+ if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest)) -+ return false; -+ } else { -+ bRet = true; -+ break; -+ } -+ } else if ((tmp_header & 0x1F) == 0x0F) { /* wrong extended header */ -+ efuse_addr += 2; -+ continue; -+ } -+ } -+ -+ *pAddr = efuse_addr; -+ return bRet; -+} -+ -+static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) -+{ -+ bool bRet = false; -+ u8 pg_header = 0, tmp_header = 0; -+ u16 efuse_addr = *pAddr; -+ u8 repeatcnt = 0; -+ -+ pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; -+ -+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); -+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); -+ -+ while (tmp_header == 0xFF) { -+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) -+ return false; -+ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); -+ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); -+ } -+ -+ if (pg_header == tmp_header) { -+ bRet = true; -+ } else { -+ struct pgpkt fixPkt; -+ fixPkt.offset = (tmp_header>>4) & 0x0F; -+ fixPkt.word_en = tmp_header & 0x0F; -+ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); -+ if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest)) -+ return false; -+ } -+ -+ *pAddr = efuse_addr; -+ return bRet; -+} -+ -+static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) -+{ -+ u16 efuse_addr = *pAddr; -+ u8 badworden = 0; -+ u32 PgWriteSuccess = 0; -+ -+ badworden = 0x0f; -+ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); -+ if (badworden == 0x0F) { -+ /* write ok */ -+ return true; -+ } else { -+ /* reorganize other pg packet */ -+ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); -+ if (!PgWriteSuccess) -+ return false; -+ else -+ return true; -+ } -+} -+ -+static bool -+hal_EfusePgPacketWriteHeader( -+ struct adapter *pAdapter, -+ u8 efuseType, -+ u16 *pAddr, -+ struct pgpkt *pTargetPkt, -+ bool bPseudoTest) -+{ -+ bool bRet = false; -+ -+ if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) -+ bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest); -+ else -+ bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest); -+ -+ return bRet; -+} -+ -+static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt, -+ u8 *pWden) -+{ -+ u8 match_word_en = 0x0F; /* default all words are disabled */ -+ -+ /* check if the same words are enabled both target and current PG packet */ -+ if (((pTargetPkt->word_en & BIT0) == 0) && -+ ((pCurPkt->word_en & BIT0) == 0)) -+ match_word_en &= ~BIT0; /* enable word 0 */ -+ if (((pTargetPkt->word_en & BIT1) == 0) && -+ ((pCurPkt->word_en & BIT1) == 0)) -+ match_word_en &= ~BIT1; /* enable word 1 */ -+ if (((pTargetPkt->word_en & BIT2) == 0) && -+ ((pCurPkt->word_en & BIT2) == 0)) -+ match_word_en &= ~BIT2; /* enable word 2 */ -+ if (((pTargetPkt->word_en & BIT3) == 0) && -+ ((pCurPkt->word_en & BIT3) == 0)) -+ match_word_en &= ~BIT3; /* enable word 3 */ -+ -+ *pWden = match_word_en; -+ -+ if (match_word_en != 0xf) -+ return true; -+ else -+ return false; -+} -+ -+static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr, bool bPseudoTest) -+{ -+ bool bRet = false; -+ u8 i, efuse_data; -+ -+ for (i = 0; i < (word_cnts*2); i++) { -+ if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) -+ bRet = true; -+ } -+ return bRet; -+} -+ -+static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) -+{ -+ bool bRet = false; -+ u8 i, efuse_data = 0, cur_header = 0; -+ u8 matched_wden = 0, badworden = 0; -+ u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; -+ struct pgpkt curPkt; -+ -+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest); -+ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max, bPseudoTest); -+ -+ if (efuseType == EFUSE_WIFI) { -+ if (bPseudoTest) { -+ startAddr = (u16)(fakeEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN); -+ } else { -+ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); -+ startAddr %= EFUSE_REAL_CONTENT_LEN; -+ } -+ } else { -+ if (bPseudoTest) -+ startAddr = (u16)(fakeBTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN); -+ else -+ startAddr = (u16)(BTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN); -+ } -+ -+ while (1) { -+ if (startAddr >= efuse_max_available_len) { -+ bRet = false; -+ break; -+ } -+ -+ if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) { -+ if (EXT_HEADER(efuse_data)) { -+ cur_header = efuse_data; -+ startAddr++; -+ efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest); -+ if (ALL_WORDS_DISABLED(efuse_data)) { -+ bRet = false; -+ break; -+ } else { -+ curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); -+ curPkt.word_en = efuse_data & 0x0F; -+ } -+ } else { -+ cur_header = efuse_data; -+ curPkt.offset = (cur_header>>4) & 0x0F; -+ curPkt.word_en = cur_header & 0x0F; -+ } -+ -+ curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); -+ /* if same header is found but no data followed */ -+ /* write some part of data followed by the header. */ -+ if ((curPkt.offset == pTargetPkt->offset) && -+ (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1, bPseudoTest)) && -+ wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) { -+ /* Here to write partial data */ -+ badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest); -+ if (badworden != 0x0F) { -+ u32 PgWriteSuccess = 0; -+ /* if write fail on some words, write these bad words again */ -+ -+ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); -+ -+ if (!PgWriteSuccess) { -+ bRet = false; /* write fail, return */ -+ break; -+ } -+ } -+ /* partial write ok, update the target packet for later use */ -+ for (i = 0; i < 4; i++) { -+ if ((matched_wden & (0x1<word_en |= (0x1<word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); -+ } -+ /* read from next header */ -+ startAddr = startAddr + (curPkt.word_cnts*2) + 1; -+ } else { -+ /* not used header, 0xff */ -+ *pAddr = startAddr; -+ bRet = true; -+ break; -+ } -+ } -+ return bRet; -+} -+ -+static bool -+hal_EfusePgCheckAvailableAddr( -+ struct adapter *pAdapter, -+ u8 efuseType, -+ bool bPseudoTest -+ ) -+{ -+ u16 efuse_max_available_len = 0; -+ -+ /* Change to check TYPE_EFUSE_MAP_LEN , because 8188E raw 256, logic map over 256. */ -+ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len, false); -+ -+ if (Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest) >= efuse_max_available_len) -+ return false; -+ return true; -+} -+ -+static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt) -+{ -+ memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8); -+ pTargetPkt->offset = offset; -+ pTargetPkt->word_en = word_en; -+ efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); -+ pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); -+} -+ -+static bool hal_EfusePgPacketWrite_8188e(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData, bool bPseudoTest) -+{ -+ struct pgpkt targetPkt; -+ u16 startAddr = 0; -+ u8 efuseType = EFUSE_WIFI; -+ -+ if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType, bPseudoTest)) -+ return false; -+ -+ hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); -+ -+ if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) -+ return false; -+ -+ if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) -+ return false; -+ -+ if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) -+ return false; -+ -+ return true; -+} -+ -+static int Hal_EfusePgPacketWrite_Pseudo(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest) -+{ -+ int ret; -+ -+ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest); -+ return ret; -+} -+ -+static int Hal_EfusePgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest) -+{ -+ int ret = 0; -+ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest); -+ -+ return ret; -+} -+ -+static int rtl8188e_Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest) -+{ -+ int ret; -+ -+ if (bPseudoTest) -+ ret = Hal_EfusePgPacketWrite_Pseudo (pAdapter, offset, word_en, data, bPseudoTest); -+ else -+ ret = Hal_EfusePgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest); -+ return ret; -+} -+ -+static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) -+{ -+ u32 value32; -+ struct HAL_VERSION ChipVersion; -+ struct hal_data_8188e *pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ -+ value32 = rtw_read32(padapter, REG_SYS_CFG); -+ ChipVersion.ICType = CHIP_8188E; -+ ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); -+ -+ ChipVersion.RFType = RF_TYPE_1T1R; -+ ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); -+ ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ -+ -+ /* For regulator mode. by tynli. 2011.01.14 */ -+ pHalData->RegulatorMode = ((value32 & TRP_BT_EN) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR); -+ -+ ChipVersion.ROMVer = 0; /* ROM code version. */ -+ pHalData->MultiFunc = RT_MULTI_FUNC_NONE; -+ -+ dump_chip_info(ChipVersion); -+ -+ pHalData->VersionID = ChipVersion; -+ -+ if (IS_1T2R(ChipVersion)) { -+ pHalData->rf_type = RF_1T2R; -+ pHalData->NumTotalRFPath = 2; -+ } else if (IS_2T2R(ChipVersion)) { -+ pHalData->rf_type = RF_2T2R; -+ pHalData->NumTotalRFPath = 2; -+ } else{ -+ pHalData->rf_type = RF_1T1R; -+ pHalData->NumTotalRFPath = 1; -+ } -+ -+ MSG_88E("RF_Type is %x!!\n", pHalData->rf_type); -+ -+ return ChipVersion; -+} -+ -+static void rtl8188e_read_chip_version(struct adapter *padapter) -+{ -+ ReadChipVersion8188E(padapter); -+} -+ -+static void rtl8188e_GetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) -+{ -+} -+ -+static void rtl8188e_SetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct odm_dm_struct *podmpriv = &pHalData->odmpriv; -+ switch (eVariable) { -+ case HAL_ODM_STA_INFO: -+ { -+ struct sta_info *psta = (struct sta_info *)pValue1; -+ if (bSet) { -+ DBG_88E("### Set STA_(%d) info\n", psta->mac_id); -+ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta); -+ ODM_RAInfo_Init(podmpriv, psta->mac_id); -+ } else { -+ DBG_88E("### Clean STA_(%d) info\n", psta->mac_id); -+ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL); -+ } -+ } -+ break; -+ case HAL_ODM_P2P_STATE: -+ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet); -+ break; -+ case HAL_ODM_WIFI_DISPLAY_STATE: -+ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet); -+ break; -+ default: -+ break; -+ } -+} -+ -+void rtl8188e_clone_haldata(struct adapter *dst_adapter, struct adapter *src_adapter) -+{ -+ memcpy(dst_adapter->HalData, src_adapter->HalData, dst_adapter->hal_data_sz); -+} -+ -+void rtl8188e_start_thread(struct adapter *padapter) -+{ -+} -+ -+void rtl8188e_stop_thread(struct adapter *padapter) -+{ -+} -+ -+static void hal_notch_filter_8188e(struct adapter *adapter, bool enable) -+{ -+ if (enable) { -+ DBG_88E("Enable notch filter\n"); -+ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1); -+ } else { -+ DBG_88E("Disable notch filter\n"); -+ rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1); -+ } -+} -+void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc) -+{ -+ pHalFunc->free_hal_data = &rtl8188e_free_hal_data; -+ -+ pHalFunc->dm_init = &rtl8188e_init_dm_priv; -+ pHalFunc->dm_deinit = &rtl8188e_deinit_dm_priv; -+ -+ pHalFunc->read_chip_version = &rtl8188e_read_chip_version; -+ -+ pHalFunc->set_bwmode_handler = &PHY_SetBWMode8188E; -+ pHalFunc->set_channel_handler = &PHY_SwChnl8188E; -+ -+ pHalFunc->hal_dm_watchdog = &rtl8188e_HalDmWatchDog; -+ -+ pHalFunc->Add_RateATid = &rtl8188e_Add_RateATid; -+ pHalFunc->run_thread = &rtl8188e_start_thread; -+ pHalFunc->cancel_thread = &rtl8188e_stop_thread; -+ -+ pHalFunc->AntDivBeforeLinkHandler = &AntDivBeforeLink8188E; -+ pHalFunc->AntDivCompareHandler = &AntDivCompare8188E; -+ pHalFunc->read_bbreg = &rtl8188e_PHY_QueryBBReg; -+ pHalFunc->write_bbreg = &rtl8188e_PHY_SetBBReg; -+ pHalFunc->read_rfreg = &rtl8188e_PHY_QueryRFReg; -+ pHalFunc->write_rfreg = &rtl8188e_PHY_SetRFReg; -+ -+ /* Efuse related function */ -+ pHalFunc->EfusePowerSwitch = &rtl8188e_EfusePowerSwitch; -+ pHalFunc->ReadEFuse = &rtl8188e_ReadEFuse; -+ pHalFunc->EFUSEGetEfuseDefinition = &rtl8188e_EFUSE_GetEfuseDefinition; -+ pHalFunc->EfuseGetCurrentSize = &rtl8188e_EfuseGetCurrentSize; -+ pHalFunc->Efuse_PgPacketRead = &rtl8188e_Efuse_PgPacketRead; -+ pHalFunc->Efuse_PgPacketWrite = &rtl8188e_Efuse_PgPacketWrite; -+ pHalFunc->Efuse_WordEnableDataWrite = &rtl8188e_Efuse_WordEnableDataWrite; -+ -+ pHalFunc->sreset_init_value = &sreset_init_value; -+ pHalFunc->sreset_reset_value = &sreset_reset_value; -+ pHalFunc->silentreset = &rtl8188e_silentreset_for_specific_platform; -+ pHalFunc->sreset_xmit_status_check = &rtl8188e_sreset_xmit_status_check; -+ pHalFunc->sreset_linked_status_check = &rtl8188e_sreset_linked_status_check; -+ pHalFunc->sreset_get_wifi_status = &sreset_get_wifi_status; -+ -+ pHalFunc->GetHalODMVarHandler = &rtl8188e_GetHalODMVar; -+ pHalFunc->SetHalODMVarHandler = &rtl8188e_SetHalODMVar; -+ -+ pHalFunc->IOL_exec_cmds_sync = &rtl8188e_IOL_exec_cmds_sync; -+ -+ pHalFunc->hal_notch_filter = &hal_notch_filter_8188e; -+} -+ -+u8 GetEEPROMSize8188E(struct adapter *padapter) -+{ -+ u8 size = 0; -+ u32 cr; -+ -+ cr = rtw_read16(padapter, REG_9346CR); -+ /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */ -+ size = (cr & BOOT_FROM_EEPROM) ? 6 : 4; -+ -+ MSG_88E("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46"); -+ -+ return size; -+} -+ -+/* */ -+/* */ -+/* LLT R/W/Init function */ -+/* */ -+/* */ -+static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data) -+{ -+ s32 status = _SUCCESS; -+ s32 count = 0; -+ u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); -+ u16 LLTReg = REG_LLT_INIT; -+ -+ rtw_write32(padapter, LLTReg, value); -+ -+ /* polling */ -+ do { -+ value = rtw_read32(padapter, LLTReg); -+ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) -+ break; -+ -+ if (count > POLLING_LLT_THRESHOLD) { -+ RT_TRACE(_module_hal_init_c_, _drv_err_, ("Failed to polling write LLT done at address %d!\n", address)); -+ status = _FAIL; -+ break; -+ } -+ } while (count++); -+ -+ return status; -+} -+ -+s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) -+{ -+ s32 status = _FAIL; -+ u32 i; -+ u32 Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER;/* 176, 22k */ -+ -+ if (rtw_IOL_applied(padapter)) { -+ status = iol_InitLLTTable(padapter, txpktbuf_bndy); -+ } else { -+ for (i = 0; i < (txpktbuf_bndy - 1); i++) { -+ status = _LLTWrite(padapter, i, i + 1); -+ if (_SUCCESS != status) -+ return status; -+ } -+ -+ /* end of list */ -+ status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF); -+ if (_SUCCESS != status) -+ return status; -+ -+ /* Make the other pages as ring buffer */ -+ /* This ring buffer is used as beacon buffer if we config this MAC as two MAC transfer. */ -+ /* Otherwise used as local loopback buffer. */ -+ for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) { -+ status = _LLTWrite(padapter, i, (i + 1)); -+ if (_SUCCESS != status) -+ return status; -+ } -+ -+ /* Let last entry point to the start entry of ring buffer */ -+ status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy); -+ if (_SUCCESS != status) { -+ return status; -+ } -+ } -+ -+ return status; -+} -+ -+void -+Hal_InitPGData88E(struct adapter *padapter) -+{ -+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); -+ -+ if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */ -+ if (!is_boot_from_eeprom(padapter)) { -+ /* Read EFUSE real map to shadow. */ -+ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); -+ } -+ } else {/* autoload fail */ -+ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n")); -+ /* update to default value 0xFF */ -+ if (!is_boot_from_eeprom(padapter)) -+ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); -+ } -+} -+ -+void -+Hal_EfuseParseIDCode88E( -+ struct adapter *padapter, -+ u8 *hwinfo -+ ) -+{ -+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); -+ u16 EEPROMId; -+ -+ /* Check 0x8129 again for making sure autoload status!! */ -+ EEPROMId = le16_to_cpu(*((__le16 *)hwinfo)); -+ if (EEPROMId != RTL_EEPROM_ID) { -+ pr_err("EEPROM ID(%#x) is invalid!!\n", EEPROMId); -+ pEEPROM->bautoload_fail_flag = true; -+ } else { -+ pEEPROM->bautoload_fail_flag = false; -+ } -+ -+ pr_info("EEPROM ID = 0x%04x\n", EEPROMId); -+} -+ -+static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G, u8 *PROMContent, bool AutoLoadFail) -+{ -+ u32 rfPath, eeAddr = EEPROM_TX_PWR_INX_88E, group, TxCount = 0; -+ -+ memset(pwrInfo24G, 0, sizeof(struct txpowerinfo24g)); -+ -+ if (AutoLoadFail) { -+ for (rfPath = 0; rfPath < RF_PATH_MAX; rfPath++) { -+ /* 2.4G default value */ -+ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { -+ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; -+ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; -+ } -+ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { -+ if (TxCount == 0) { -+ pwrInfo24G->BW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF; -+ pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF; -+ } else { -+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ } -+ } -+ } -+ return; -+ } -+ -+ for (rfPath = 0; rfPath < RF_PATH_MAX; rfPath++) { -+ /* 2.4G default value */ -+ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { -+ pwrInfo24G->IndexCCK_Base[rfPath][group] = PROMContent[eeAddr++]; -+ if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF) -+ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; -+ } -+ for (group = 0; group < MAX_CHNL_GROUP_24G-1; group++) { -+ pwrInfo24G->IndexBW40_Base[rfPath][group] = PROMContent[eeAddr++]; -+ if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF) -+ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; -+ } -+ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { -+ if (TxCount == 0) { -+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = 0; -+ if (PROMContent[eeAddr] == 0xFF) { -+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF; -+ } else { -+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; -+ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ -+ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; -+ } -+ -+ if (PROMContent[eeAddr] == 0xFF) { -+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_OFDM_DIFF; -+ } else { -+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); -+ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ -+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; -+ } -+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0; -+ eeAddr++; -+ } else { -+ if (PROMContent[eeAddr] == 0xFF) { -+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ } else { -+ pwrInfo24G->BW40_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; -+ if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ -+ pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0; -+ } -+ -+ if (PROMContent[eeAddr] == 0xFF) { -+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ } else { -+ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); -+ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ -+ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; -+ } -+ eeAddr++; -+ -+ if (PROMContent[eeAddr] == 0xFF) { -+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ } else { -+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4; -+ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ -+ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; -+ } -+ -+ if (PROMContent[eeAddr] == 0xFF) { -+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; -+ } else { -+ pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f); -+ if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT3) /* 4bit sign number to 8 bit sign number */ -+ pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0; -+ } -+ eeAddr++; -+ } -+ } -+ } -+} -+ -+static u8 Hal_GetChnlGroup88E(u8 chnl, u8 *pGroup) -+{ -+ u8 bIn24G = true; -+ -+ if (chnl <= 14) { -+ bIn24G = true; -+ -+ if (chnl < 3) /* Channel 1-2 */ -+ *pGroup = 0; -+ else if (chnl < 6) /* Channel 3-5 */ -+ *pGroup = 1; -+ else if (chnl < 9) /* Channel 6-8 */ -+ *pGroup = 2; -+ else if (chnl < 12) /* Channel 9-11 */ -+ *pGroup = 3; -+ else if (chnl < 14) /* Channel 12-13 */ -+ *pGroup = 4; -+ else if (chnl == 14) /* Channel 14 */ -+ *pGroup = 5; -+ } else { -+ bIn24G = false; -+ -+ if (chnl <= 40) -+ *pGroup = 0; -+ else if (chnl <= 48) -+ *pGroup = 1; -+ else if (chnl <= 56) -+ *pGroup = 2; -+ else if (chnl <= 64) -+ *pGroup = 3; -+ else if (chnl <= 104) -+ *pGroup = 4; -+ else if (chnl <= 112) -+ *pGroup = 5; -+ else if (chnl <= 120) -+ *pGroup = 5; -+ else if (chnl <= 128) -+ *pGroup = 6; -+ else if (chnl <= 136) -+ *pGroup = 7; -+ else if (chnl <= 144) -+ *pGroup = 8; -+ else if (chnl <= 153) -+ *pGroup = 9; -+ else if (chnl <= 161) -+ *pGroup = 10; -+ else if (chnl <= 177) -+ *pGroup = 11; -+ } -+ return bIn24G; -+} -+ -+void Hal_ReadPowerSavingMode88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) -+{ -+ if (AutoLoadFail) { -+ padapter->pwrctrlpriv.bHWPowerdown = false; -+ padapter->pwrctrlpriv.bSupportRemoteWakeup = false; -+ } else { -+ /* hw power down mode selection , 0:rf-off / 1:power down */ -+ -+ if (padapter->registrypriv.hwpdn_mode == 2) -+ padapter->pwrctrlpriv.bHWPowerdown = (hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & BIT4); -+ else -+ padapter->pwrctrlpriv.bHWPowerdown = padapter->registrypriv.hwpdn_mode; -+ -+ /* decide hw if support remote wakeup function */ -+ /* if hw supported, 8051 (SIE) will generate WeakUP signal(D+/D- toggle) when autoresume */ -+ padapter->pwrctrlpriv.bSupportRemoteWakeup = (hwinfo[EEPROM_USB_OPTIONAL_FUNCTION0] & BIT1) ? true : false; -+ -+ DBG_88E("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) , bSupportRemoteWakeup(%x)\n", __func__, -+ padapter->pwrctrlpriv.bHWPwrPindetect, padapter->pwrctrlpriv.bHWPowerdown , padapter->pwrctrlpriv.bSupportRemoteWakeup); -+ -+ DBG_88E("### PS params => power_mgnt(%x), usbss_enable(%x) ###\n", padapter->registrypriv.power_mgnt, padapter->registrypriv.usbss_enable); -+ } -+} -+ -+void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool AutoLoadFail) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct txpowerinfo24g pwrInfo24G; -+ u8 rfPath, ch, group; -+ u8 bIn24G, TxCount; -+ -+ Hal_ReadPowerValueFromPROM_8188E(&pwrInfo24G, PROMContent, AutoLoadFail); -+ -+ if (!AutoLoadFail) -+ pHalData->bTXPowerDataReadFromEEPORM = true; -+ -+ for (rfPath = 0; rfPath < pHalData->NumTotalRFPath; rfPath++) { -+ for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { -+ bIn24G = Hal_GetChnlGroup88E(ch, &group); -+ if (bIn24G) { -+ pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group]; -+ if (ch == 14) -+ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][4]; -+ else -+ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group]; -+ } -+ if (bIn24G) { -+ DBG_88E("======= Path %d, Channel %d =======\n", rfPath, ch); -+ DBG_88E("Index24G_CCK_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_CCK_Base[rfPath][ch]); -+ DBG_88E("Index24G_BW40_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_BW40_Base[rfPath][ch]); -+ } -+ } -+ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { -+ pHalData->CCK_24G_Diff[rfPath][TxCount] = pwrInfo24G.CCK_Diff[rfPath][TxCount]; -+ pHalData->OFDM_24G_Diff[rfPath][TxCount] = pwrInfo24G.OFDM_Diff[rfPath][TxCount]; -+ pHalData->BW20_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW20_Diff[rfPath][TxCount]; -+ pHalData->BW40_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW40_Diff[rfPath][TxCount]; -+ DBG_88E("======= TxCount %d =======\n", TxCount); -+ DBG_88E("CCK_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->CCK_24G_Diff[rfPath][TxCount]); -+ DBG_88E("OFDM_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->OFDM_24G_Diff[rfPath][TxCount]); -+ DBG_88E("BW20_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW20_24G_Diff[rfPath][TxCount]); -+ DBG_88E("BW40_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW40_24G_Diff[rfPath][TxCount]); -+ } -+ } -+ -+ /* 2010/10/19 MH Add Regulator recognize for CU. */ -+ if (!AutoLoadFail) { -+ pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x7); /* bit0~2 */ -+ if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF) -+ pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); /* bit0~2 */ -+ } else { -+ pHalData->EEPROMRegulatory = 0; -+ } -+ DBG_88E("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory); -+} -+ -+void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ -+ if (!AutoLoadFail) { -+ pHalData->CrystalCap = hwinfo[EEPROM_XTAL_88E]; -+ if (pHalData->CrystalCap == 0xFF) -+ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E; -+ } else { -+ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E; -+ } -+ DBG_88E("CrystalCap: 0x%2x\n", pHalData->CrystalCap); -+} -+ -+void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ -+ if (!AutoLoadFail) -+ pHalData->BoardType = ((hwinfo[EEPROM_RF_BOARD_OPTION_88E]&0xE0)>>5); -+ else -+ pHalData->BoardType = 0; -+ DBG_88E("Board Type: 0x%2x\n", pHalData->BoardType); -+} -+ -+void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ -+ if (!AutoLoadFail) { -+ pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_88E]; -+ if (pHalData->EEPROMVersion == 0xFF) -+ pHalData->EEPROMVersion = EEPROM_Default_Version; -+ } else { -+ pHalData->EEPROMVersion = 1; -+ } -+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, -+ ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n", -+ pHalData->EEPROMVersion)); -+} -+ -+void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) -+{ -+ padapter->mlmepriv.ChannelPlan = -+ hal_com_get_channel_plan(padapter, -+ hwinfo ? hwinfo[EEPROM_ChannelPlan_88E] : 0xFF, -+ padapter->registrypriv.channel_plan, -+ RT_CHANNEL_DOMAIN_WORLD_WIDE_13, AutoLoadFail); -+ -+ DBG_88E("mlmepriv.ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan); -+} -+ -+void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ -+ if (!AutoLoadFail) { -+ pHalData->EEPROMCustomerID = hwinfo[EEPROM_CUSTOMERID_88E]; -+ } else { -+ pHalData->EEPROMCustomerID = 0; -+ pHalData->EEPROMSubCustomerID = 0; -+ } -+ DBG_88E("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID); -+} -+ -+void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool AutoLoadFail) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ struct registry_priv *registry_par = &pAdapter->registrypriv; -+ -+ if (!AutoLoadFail) { -+ /* Antenna Diversity setting. */ -+ if (registry_par->antdiv_cfg == 2) { /* 2:By EFUSE */ -+ pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x18)>>3; -+ if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF) -+ pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION&0x18)>>3;; -+ } else { -+ pHalData->AntDivCfg = registry_par->antdiv_cfg; /* 0:OFF , 1:ON, 2:By EFUSE */ -+ } -+ -+ if (registry_par->antdiv_type == 0) { -+ /* If TRxAntDivType is AUTO in advanced setting, use EFUSE value instead. */ -+ pHalData->TRxAntDivType = PROMContent[EEPROM_RF_ANTENNA_OPT_88E]; -+ if (pHalData->TRxAntDivType == 0xFF) -+ pHalData->TRxAntDivType = CG_TRX_HW_ANTDIV; /* For 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */ -+ } else { -+ pHalData->TRxAntDivType = registry_par->antdiv_type; -+ } -+ -+ if (pHalData->TRxAntDivType == CG_TRX_HW_ANTDIV || pHalData->TRxAntDivType == CGCS_RX_HW_ANTDIV) -+ pHalData->AntDivCfg = 1; /* 0xC1[3] is ignored. */ -+ } else { -+ pHalData->AntDivCfg = 0; -+ pHalData->TRxAntDivType = pHalData->TRxAntDivType; /* The value in the driver setting of device manager. */ -+ } -+ DBG_88E("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n", pHalData->AntDivCfg, pHalData->TRxAntDivType); -+} -+ -+void Hal_ReadThermalMeter_88E(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ -+ /* ThermalMeter from EEPROM */ -+ if (!AutoloadFail) -+ pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_88E]; -+ else -+ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E; -+ -+ if (pHalData->EEPROMThermalMeter == 0xff || AutoloadFail) { -+ pHalData->bAPKThermalMeterIgnore = true; -+ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E; -+ } -+ DBG_88E("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter); -+} -+ -+void Hal_InitChannelPlan(struct adapter *padapter) -+{ -+} -+ -+bool HalDetectPwrDownMode88E(struct adapter *Adapter) -+{ -+ u8 tmpvalue = 0; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; -+ -+ EFUSE_ShadowRead(Adapter, 1, EEPROM_RF_FEATURE_OPTION_88E, (u32 *)&tmpvalue); -+ -+ /* 2010/08/25 MH INF priority > PDN Efuse value. */ -+ if (tmpvalue & BIT(4) && pwrctrlpriv->reg_pdnmode) -+ pHalData->pwrdown = true; -+ else -+ pHalData->pwrdown = false; -+ -+ DBG_88E("HalDetectPwrDownMode(): PDN =%d\n", pHalData->pwrdown); -+ -+ return pHalData->pwrdown; -+} /* HalDetectPwrDownMode */ -+ -+/* This function is used only for 92C to set REG_BCN_CTRL(0x550) register. */ -+/* We just reserve the value of the register in variable pHalData->RegBcnCtrlVal and then operate */ -+/* the value of the register via atomic operation. */ -+/* This prevents from race condition when setting this register. */ -+/* The value of pHalData->RegBcnCtrlVal is initialized in HwConfigureRTL8192CE() function. */ -+ -+void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits) -+{ -+ struct hal_data_8188e *pHalData; -+ -+ pHalData = GET_HAL_DATA(padapter); -+ -+ pHalData->RegBcnCtrlVal |= SetBits; -+ pHalData->RegBcnCtrlVal &= ~ClearBits; -+ -+ rtw_write8(padapter, REG_BCN_CTRL, (u8)pHalData->RegBcnCtrlVal); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_mp.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_mp.c -new file mode 100644 -index 0000000000000..66388902ab948 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_mp.c -@@ -0,0 +1,851 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188E_MP_C_ -+ -+#include -+#include -+#include -+#include -+ -+s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv); -+ -+ if (!netif_running(padapter->pnetdev)) { -+ RT_TRACE(_module_mp_, _drv_warning_, -+ ("SetPowerTracking! Fail: interface not opened!\n")); -+ return _FAIL; -+ } -+ -+ if (!check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE)) { -+ RT_TRACE(_module_mp_, _drv_warning_, -+ ("SetPowerTracking! Fail: not in MP mode!\n")); -+ return _FAIL; -+ } -+ -+ if (enable) -+ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true; -+ else -+ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false; -+ -+ return _SUCCESS; -+} -+ -+void Hal_GetPowerTracking(struct adapter *padapter, u8 *enable) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv); -+ -+ *enable = pDM_Odm->RFCalibrateInfo.TxPowerTrackControl; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: mpt_SwitchRfSetting -+ * -+ * Overview: Change RF Setting when we siwthc channel/rate/BW for MP. -+ * -+ * Input: struct adapter * pAdapter -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 01/08/2009 MHC Suggestion from SD3 Willis for 92S series. -+ * 01/09/2009 MHC Add CCK modification for 40MHZ. Suggestion from SD3. -+ * -+ *---------------------------------------------------------------------------*/ -+void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter) -+{ -+ struct mp_priv *pmp = &pAdapter->mppriv; -+ -+ /* <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis. */ -+ pmp->MptCtx.backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); -+ pmp->MptCtx.backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0); -+ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0, 0xD); -+ PHY_SetRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0, 0xD); -+ -+ return; -+} -+/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/ -+ -+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ -+void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14) -+{ -+ u32 TempVal = 0, TempVal2 = 0, TempVal3 = 0; -+ u32 CurrCCKSwingVal = 0, CCKSwingIndex = 12; -+ u8 i; -+ -+ /* get current cck swing value and check 0xa22 & 0xa23 later to match the table. */ -+ CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord); -+ -+ if (!bInCH14) { -+ /* Readback the current bb cck swing value and compare with the table to */ -+ /* get the current swing index */ -+ for (i = 0; i < CCK_TABLE_SIZE; i++) { -+ if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch1_Ch13[i][0]) && -+ (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch1_Ch13[i][1])) { -+ CCKSwingIndex = i; -+ break; -+ } -+ } -+ -+ /* Write 0xa22 0xa23 */ -+ TempVal = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][0] + -+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][1]<<8); -+ -+ /* Write 0xa24 ~ 0xa27 */ -+ TempVal2 = 0; -+ TempVal2 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][2] + -+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][3]<<8) + -+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][4]<<16)+ -+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][5]<<24); -+ -+ /* Write 0xa28 0xa29 */ -+ TempVal3 = 0; -+ TempVal3 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][6] + -+ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][7]<<8); -+ } else { -+ for (i = 0; i < CCK_TABLE_SIZE; i++) { -+ if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch14[i][0]) && -+ (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch14[i][1])) { -+ CCKSwingIndex = i; -+ break; -+ } -+ } -+ -+ /* Write 0xa22 0xa23 */ -+ TempVal = CCKSwingTable_Ch14[CCKSwingIndex][0] + -+ (CCKSwingTable_Ch14[CCKSwingIndex][1]<<8); -+ -+ /* Write 0xa24 ~ 0xa27 */ -+ TempVal2 = 0; -+ TempVal2 = CCKSwingTable_Ch14[CCKSwingIndex][2] + -+ (CCKSwingTable_Ch14[CCKSwingIndex][3]<<8) + -+ (CCKSwingTable_Ch14[CCKSwingIndex][4]<<16)+ -+ (CCKSwingTable_Ch14[CCKSwingIndex][5]<<24); -+ -+ /* Write 0xa28 0xa29 */ -+ TempVal3 = 0; -+ TempVal3 = CCKSwingTable_Ch14[CCKSwingIndex][6] + -+ (CCKSwingTable_Ch14[CCKSwingIndex][7]<<8); -+ } -+ -+ write_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord, TempVal); -+ write_bbreg(Adapter, rCCK0_TxFilter2, bMaskDWord, TempVal2); -+ write_bbreg(Adapter, rCCK0_DebugPort, bMaskLWord, TempVal3); -+} -+ -+void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx; -+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv); -+ s32 TempCCk; -+ u8 CCK_index, CCK_index_old = 0; -+ u8 Action = 0; /* 0: no action, 1: even->odd, 2:odd->even */ -+ s32 i = 0; -+ -+ if (!IS_92C_SERIAL(pHalData->VersionID)) -+ return; -+ if (beven && !pMptCtx->bMptIndexEven) { -+ /* odd->even */ -+ Action = 2; -+ pMptCtx->bMptIndexEven = true; -+ } else if (!beven && pMptCtx->bMptIndexEven) { -+ /* even->odd */ -+ Action = 1; -+ pMptCtx->bMptIndexEven = false; -+ } -+ -+ if (Action != 0) { -+ /* Query CCK default setting From 0xa24 */ -+ TempCCk = read_bbreg(pAdapter, rCCK0_TxFilter2, bMaskDWord) & bMaskCCK; -+ for (i = 0; i < CCK_TABLE_SIZE; i++) { -+ if (pDM_Odm->RFCalibrateInfo.bCCKinCH14) { -+ if (!memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4)) { -+ CCK_index_old = (u8)i; -+ break; -+ } -+ } else { -+ if (!memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4)) { -+ CCK_index_old = (u8)i; -+ break; -+ } -+ } -+ } -+ -+ if (Action == 1) -+ CCK_index = CCK_index_old - 1; -+ else -+ CCK_index = CCK_index_old + 1; -+ -+ /* Adjust CCK according to gain index */ -+ if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) { -+ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]); -+ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch1_Ch13[CCK_index][1]); -+ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch1_Ch13[CCK_index][2]); -+ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch1_Ch13[CCK_index][3]); -+ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch1_Ch13[CCK_index][4]); -+ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch1_Ch13[CCK_index][5]); -+ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch1_Ch13[CCK_index][6]); -+ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch1_Ch13[CCK_index][7]); -+ } else { -+ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch14[CCK_index][0]); -+ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch14[CCK_index][1]); -+ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch14[CCK_index][2]); -+ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch14[CCK_index][3]); -+ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch14[CCK_index][4]); -+ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch14[CCK_index][5]); -+ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch14[CCK_index][6]); -+ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch14[CCK_index][7]); -+ } -+ } -+} -+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ -+ -+/* -+ * SetChannel -+ * Description -+ * Use H2C command to change channel, -+ * not only modify rf register, but also other setting need to be done. -+ */ -+void Hal_SetChannel(struct adapter *pAdapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ struct mp_priv *pmp = &pAdapter->mppriv; -+ struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv); -+ u8 eRFPath; -+ u8 channel = pmp->channel; -+ -+ /* set RF channel register */ -+ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) -+ _write_rfreg(pAdapter, eRFPath, ODM_CHANNEL, 0x3FF, channel); -+ Hal_mpt_SwitchRfSetting(pAdapter); -+ -+ SelectChannel(pAdapter, channel); -+ -+ if (pHalData->CurrentChannel == 14 && !pDM_Odm->RFCalibrateInfo.bCCKinCH14) { -+ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = true; -+ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14); -+ } else if (pHalData->CurrentChannel != 14 && pDM_Odm->RFCalibrateInfo.bCCKinCH14) { -+ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = false; -+ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14); -+ } -+} -+ -+/* -+ * Notice -+ * Switch bandwitdth may change center frequency(channel) -+ */ -+void Hal_SetBandwidth(struct adapter *pAdapter) -+{ -+ struct mp_priv *pmp = &pAdapter->mppriv; -+ -+ SetBWMode(pAdapter, pmp->bandwidth, pmp->prime_channel_offset); -+ Hal_mpt_SwitchRfSetting(pAdapter); -+} -+ -+void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 *TxPower) -+{ -+ u32 tmpval = 0; -+ -+ /* rf-A cck tx power */ -+ write_bbreg(pAdapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, TxPower[RF_PATH_A]); -+ tmpval = (TxPower[RF_PATH_A]<<16) | (TxPower[RF_PATH_A]<<8) | TxPower[RF_PATH_A]; -+ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); -+ -+ /* rf-B cck tx power */ -+ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, TxPower[RF_PATH_B]); -+ tmpval = (TxPower[RF_PATH_B]<<16) | (TxPower[RF_PATH_B]<<8) | TxPower[RF_PATH_B]; -+ write_bbreg(pAdapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); -+ -+ RT_TRACE(_module_mp_, _drv_notice_, -+ ("-SetCCKTxPower: A[0x%02x] B[0x%02x]\n", -+ TxPower[RF_PATH_A], TxPower[RF_PATH_B])); -+} -+ -+void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 *TxPower) -+{ -+ u32 TxAGC = 0; -+ u8 tmpval = 0; -+ -+ /* HT Tx-rf(A) */ -+ tmpval = TxPower[RF_PATH_A]; -+ TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval; -+ -+ write_bbreg(pAdapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC); -+ -+ /* HT Tx-rf(B) */ -+ tmpval = TxPower[RF_PATH_B]; -+ TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval; -+ -+ write_bbreg(pAdapter, rTxAGC_B_Rate18_06, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_B_Rate54_24, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_B_Mcs03_Mcs00, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_B_Mcs07_Mcs04, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_B_Mcs11_Mcs08, bMaskDWord, TxAGC); -+ write_bbreg(pAdapter, rTxAGC_B_Mcs15_Mcs12, bMaskDWord, TxAGC); -+} -+ -+void Hal_SetAntennaPathPower(struct adapter *pAdapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ u8 TxPowerLevel[RF_PATH_MAX]; -+ u8 rfPath; -+ -+ TxPowerLevel[RF_PATH_A] = pAdapter->mppriv.txpoweridx; -+ TxPowerLevel[RF_PATH_B] = pAdapter->mppriv.txpoweridx_b; -+ -+ switch (pAdapter->mppriv.antenna_tx) { -+ case ANTENNA_A: -+ default: -+ rfPath = RF_PATH_A; -+ break; -+ case ANTENNA_B: -+ rfPath = RF_PATH_B; -+ break; -+ case ANTENNA_C: -+ rfPath = RF_PATH_C; -+ break; -+ } -+ -+ switch (pHalData->rf_chip) { -+ case RF_8225: -+ case RF_8256: -+ case RF_6052: -+ Hal_SetCCKTxPower(pAdapter, TxPowerLevel); -+ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */ -+ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0); -+ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel); -+ break; -+ default: -+ break; -+ } -+} -+ -+void Hal_SetTxPower(struct adapter *pAdapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ u8 TxPower = pAdapter->mppriv.txpoweridx; -+ u8 TxPowerLevel[RF_PATH_MAX]; -+ u8 rf, rfPath; -+ -+ for (rf = 0; rf < RF_PATH_MAX; rf++) -+ TxPowerLevel[rf] = TxPower; -+ -+ switch (pAdapter->mppriv.antenna_tx) { -+ case ANTENNA_A: -+ default: -+ rfPath = RF_PATH_A; -+ break; -+ case ANTENNA_B: -+ rfPath = RF_PATH_B; -+ break; -+ case ANTENNA_C: -+ rfPath = RF_PATH_C; -+ break; -+ } -+ -+ switch (pHalData->rf_chip) { -+ /* 2008/09/12 MH Test only !! We enable the TX power tracking for MP!!!!! */ -+ /* We should call normal driver API later!! */ -+ case RF_8225: -+ case RF_8256: -+ case RF_6052: -+ Hal_SetCCKTxPower(pAdapter, TxPowerLevel); -+ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */ -+ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0); -+ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel); -+ break; -+ default: -+ break; -+ } -+} -+ -+void Hal_SetDataRate(struct adapter *pAdapter) -+{ -+ Hal_mpt_SwitchRfSetting(pAdapter); -+} -+ -+void Hal_SetAntenna(struct adapter *pAdapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ -+ struct ant_sel_ofdm *p_ofdm_tx; /* OFDM Tx register */ -+ struct ant_sel_cck *p_cck_txrx; -+ u8 r_rx_antenna_ofdm = 0, r_ant_select_cck_val = 0; -+ u8 chgTx = 0, chgRx = 0; -+ u32 r_ant_select_ofdm_val = 0, r_ofdm_tx_en_val = 0; -+ -+ p_ofdm_tx = (struct ant_sel_ofdm *)&r_ant_select_ofdm_val; -+ p_cck_txrx = (struct ant_sel_cck *)&r_ant_select_cck_val; -+ -+ p_ofdm_tx->r_ant_ht1 = 0x1; -+ p_ofdm_tx->r_ant_ht2 = 0x2; /* Second TX RF path is A */ -+ p_ofdm_tx->r_ant_non_ht = 0x3; /* 0x1+0x2=0x3 */ -+ -+ switch (pAdapter->mppriv.antenna_tx) { -+ case ANTENNA_A: -+ p_ofdm_tx->r_tx_antenna = 0x1; -+ r_ofdm_tx_en_val = 0x1; -+ p_ofdm_tx->r_ant_l = 0x1; -+ p_ofdm_tx->r_ant_ht_s1 = 0x1; -+ p_ofdm_tx->r_ant_non_ht_s1 = 0x1; -+ p_cck_txrx->r_ccktx_enable = 0x8; -+ chgTx = 1; -+ -+ /* From SD3 Willis suggestion !!! Set RF A=TX and B as standby */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1); -+ r_ofdm_tx_en_val = 0x3; -+ -+ /* Power save */ -+ -+ /* We need to close RFB by SW control */ -+ if (pHalData->rf_type == RF_2T2R) { -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 1); -+ PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 0); -+ } -+ break; -+ case ANTENNA_B: -+ p_ofdm_tx->r_tx_antenna = 0x2; -+ r_ofdm_tx_en_val = 0x2; -+ p_ofdm_tx->r_ant_l = 0x2; -+ p_ofdm_tx->r_ant_ht_s1 = 0x2; -+ p_ofdm_tx->r_ant_non_ht_s1 = 0x2; -+ p_cck_txrx->r_ccktx_enable = 0x4; -+ chgTx = 1; -+ /* From SD3 Willis suggestion !!! Set RF A as standby */ -+ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1); -+ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); -+ -+ /* Power save */ -+ /* cosa r_ant_select_ofdm_val = 0x22222222; */ -+ -+ /* 2008/10/31 MH From SD3 Willi's suggestion. We must read RF 1T table. */ -+ /* 2009/01/08 MH From Sd3 Willis. We need to close RFA by SW control */ -+ if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_1T2R) { -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 1); -+ PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 0); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1); -+ } -+ break; -+ case ANTENNA_AB: /* For 8192S */ -+ p_ofdm_tx->r_tx_antenna = 0x3; -+ r_ofdm_tx_en_val = 0x3; -+ p_ofdm_tx->r_ant_l = 0x3; -+ p_ofdm_tx->r_ant_ht_s1 = 0x3; -+ p_ofdm_tx->r_ant_non_ht_s1 = 0x3; -+ p_cck_txrx->r_ccktx_enable = 0xC; -+ chgTx = 1; -+ -+ /* From SD3 Willis suggestion !!! Set RF B as standby */ -+ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); -+ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); -+ -+ /* Disable Power save */ -+ /* cosa r_ant_select_ofdm_val = 0x3321333; */ -+ /* 2009/01/08 MH From Sd3 Willis. We need to enable RFA/B by SW control */ -+ if (pHalData->rf_type == RF_2T2R) { -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1); -+ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1); -+ } -+ break; -+ default: -+ break; -+ } -+ -+ /* r_rx_antenna_ofdm, bit0=A, bit1=B, bit2=C, bit3=D */ -+ /* r_cckrx_enable : CCK default, 0=A, 1=B, 2=C, 3=D */ -+ /* r_cckrx_enable_2 : CCK option, 0=A, 1=B, 2=C, 3=D */ -+ switch (pAdapter->mppriv.antenna_rx) { -+ case ANTENNA_A: -+ r_rx_antenna_ofdm = 0x1; /* A */ -+ p_cck_txrx->r_cckrx_enable = 0x0; /* default: A */ -+ p_cck_txrx->r_cckrx_enable_2 = 0x0; /* option: A */ -+ chgRx = 1; -+ break; -+ case ANTENNA_B: -+ r_rx_antenna_ofdm = 0x2; /* B */ -+ p_cck_txrx->r_cckrx_enable = 0x1; /* default: B */ -+ p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option: B */ -+ chgRx = 1; -+ break; -+ case ANTENNA_AB: -+ r_rx_antenna_ofdm = 0x3; /* AB */ -+ p_cck_txrx->r_cckrx_enable = 0x0; /* default:A */ -+ p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option:B */ -+ chgRx = 1; -+ break; -+ default: -+ break; -+ } -+ -+ if (chgTx && chgRx) { -+ switch (pHalData->rf_chip) { -+ case RF_8225: -+ case RF_8256: -+ case RF_6052: -+ /* r_ant_sel_cck_val = r_ant_select_cck_val; */ -+ PHY_SetBBReg(pAdapter, rFPGA1_TxInfo, 0x7fffffff, r_ant_select_ofdm_val); /* OFDM Tx */ -+ PHY_SetBBReg(pAdapter, rFPGA0_TxInfo, 0x0000000f, r_ofdm_tx_en_val); /* OFDM Tx */ -+ PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */ -+ PHY_SetBBReg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */ -+ PHY_SetBBReg(pAdapter, rCCK0_AFESetting, bMaskByte3, r_ant_select_cck_val); /* CCK TxRx */ -+ -+ break; -+ default: -+ break; -+ } -+ } -+ -+ RT_TRACE(_module_mp_, _drv_notice_, ("-SwitchAntenna: finished\n")); -+} -+ -+s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ -+ if (!netif_running(pAdapter->pnetdev)) { -+ RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter! Fail: interface not opened!\n")); -+ return _FAIL; -+ } -+ -+ if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == false) { -+ RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter: Fail! not in MP mode!\n")); -+ return _FAIL; -+ } -+ -+ target_ther &= 0xff; -+ if (target_ther < 0x07) -+ target_ther = 0x07; -+ else if (target_ther > 0x1d) -+ target_ther = 0x1d; -+ -+ pHalData->EEPROMThermalMeter = target_ther; -+ -+ return _SUCCESS; -+} -+ -+void Hal_TriggerRFThermalMeter(struct adapter *pAdapter) -+{ -+ _write_rfreg(pAdapter, RF_PATH_A , RF_T_METER_88E , BIT17 | BIT16 , 0x03); -+} -+ -+u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter) -+{ -+ u32 ThermalValue = 0; -+ -+ ThermalValue = _read_rfreg(pAdapter, RF_PATH_A, RF_T_METER_88E, 0xfc00); -+ return (u8)ThermalValue; -+} -+ -+void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value) -+{ -+ Hal_TriggerRFThermalMeter(pAdapter); -+ rtw_msleep_os(1000); -+ *value = Hal_ReadRFThermalMeter(pAdapter); -+} -+ -+void Hal_SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart) -+{ -+ pAdapter->mppriv.MptCtx.bSingleCarrier = bStart; -+ if (bStart) { -+ /* Start Single Carrier. */ -+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test start\n")); -+ /* 1. if OFDM block on? */ -+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) -+ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */ -+ -+ /* 2. set CCK test mode off, set to CCK normal mode */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); -+ /* 3. turn on scramble setting */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); -+ /* 4. Turn On Single Carrier Tx and turn off the other test modes. */ -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); -+ /* for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); -+ } else { -+ /* Stop Single Carrier. */ -+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test stop\n")); -+ -+ /* Turn off all test modes. */ -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); -+ rtw_msleep_os(10); -+ -+ /* BB Reset */ -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); -+ -+ /* Stop for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); -+ } -+} -+ -+void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); -+ bool is92C = IS_92C_SERIAL(pHalData->VersionID); -+ -+ u8 rfPath; -+ u32 reg58 = 0x0; -+ switch (pAdapter->mppriv.antenna_tx) { -+ case ANTENNA_A: -+ default: -+ rfPath = RF_PATH_A; -+ break; -+ case ANTENNA_B: -+ rfPath = RF_PATH_B; -+ break; -+ case ANTENNA_C: -+ rfPath = RF_PATH_C; -+ break; -+ } -+ -+ pAdapter->mppriv.MptCtx.bSingleTone = bStart; -+ if (bStart) { -+ /* Start Single Tone. */ -+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test start\n")); -+ /* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */ -+ if (IS_HARDWARE_TYPE_8188E(pAdapter)) { -+ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask); -+ reg58 &= 0xFFFFFFF0; -+ reg58 += 2; -+ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58); -+ } -+ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x0); -+ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x0); -+ -+ if (is92C) { -+ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x01); -+ rtw_usleep_os(100); -+ if (rfPath == RF_PATH_A) -+ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x10000); /* PAD all on. */ -+ else if (rfPath == RF_PATH_B) -+ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x10000); /* PAD all on. */ -+ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */ -+ rtw_usleep_os(100); -+ } else { -+ write_rfreg(pAdapter, rfPath, 0x21, 0xd4000); -+ rtw_usleep_os(100); -+ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */ -+ rtw_usleep_os(100); -+ } -+ -+ /* for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); -+ -+ } else { -+ /* Stop Single Tone. */ -+ RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test stop\n")); -+ -+ /* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */ -+ /* <20120326, Kordan> Only in single tone mode. (asked by Edlu) */ -+ if (IS_HARDWARE_TYPE_8188E(pAdapter)) { -+ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask); -+ reg58 &= 0xFFFFFFF0; -+ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58); -+ } -+ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x1); -+ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x1); -+ if (is92C) { -+ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x00); -+ rtw_usleep_os(100); -+ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x32d75); /* PAD all on. */ -+ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x32d75); /* PAD all on. */ -+ rtw_usleep_os(100); -+ } else { -+ write_rfreg(pAdapter, rfPath, 0x21, 0x54000); -+ rtw_usleep_os(100); -+ write_rfreg(pAdapter, rfPath, 0x00, 0x30000); /* PAD all on. */ -+ rtw_usleep_os(100); -+ } -+ -+ /* Stop for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); -+ } -+} -+ -+void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart) -+{ -+ pAdapter->mppriv.MptCtx.bCarrierSuppression = bStart; -+ if (bStart) { -+ /* Start Carrier Suppression. */ -+ RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test start\n")); -+ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) { -+ /* 1. if CCK block on? */ -+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn)) -+ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */ -+ -+ /* Turn Off All Test Mode */ -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); -+ -+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x0); /* turn off scramble setting */ -+ -+ /* Set CCK Tx Test Rate */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); /* Set FTxRate to 1Mbps */ -+ } -+ -+ /* for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); -+ } else { -+ /* Stop Carrier Suppression. */ -+ RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test stop\n")); -+ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) { -+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x1); /* turn on scramble setting */ -+ -+ /* BB Reset */ -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); -+ } -+ -+ /* Stop for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); -+ } -+} -+ -+void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart) -+{ -+ u32 cckrate; -+ -+ if (bStart) { -+ RT_TRACE(_module_mp_, _drv_alert_, -+ ("SetCCKContinuousTx: test start\n")); -+ -+ /* 1. if CCK block on? */ -+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn)) -+ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */ -+ -+ /* Turn Off All Test Mode */ -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); -+ /* Set CCK Tx Test Rate */ -+ cckrate = pAdapter->mppriv.rateidx; -+ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, cckrate); -+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */ -+ -+ /* for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); -+ } else { -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("SetCCKContinuousTx: test stop\n")); -+ -+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */ -+ -+ /* BB Reset */ -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); -+ -+ /* Stop for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); -+ } -+ -+ pAdapter->mppriv.MptCtx.bCckContTx = bStart; -+ pAdapter->mppriv.MptCtx.bOfdmContTx = false; -+} /* mpt_StartCckContTx */ -+ -+void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart) -+{ -+ if (bStart) { -+ RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test start\n")); -+ /* 1. if OFDM block on? */ -+ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) -+ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */ -+ -+ /* 2. set CCK test mode off, set to CCK normal mode */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); -+ -+ /* 3. turn on scramble setting */ -+ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); -+ /* 4. Turn On Continue Tx and turn off the other test modes. */ -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); -+ -+ /* for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); -+ -+ } else { -+ RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test stop\n")); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); -+ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); -+ /* Delay 10 ms */ -+ rtw_msleep_os(10); -+ /* BB Reset */ -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); -+ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); -+ -+ /* Stop for dynamic set Power index. */ -+ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); -+ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); -+ } -+ -+ pAdapter->mppriv.MptCtx.bCckContTx = false; -+ pAdapter->mppriv.MptCtx.bOfdmContTx = bStart; -+} /* mpt_StartOfdmContTx */ -+ -+void Hal_SetContinuousTx(struct adapter *pAdapter, u8 bStart) -+{ -+ RT_TRACE(_module_mp_, _drv_info_, -+ ("SetContinuousTx: rate:%d\n", pAdapter->mppriv.rateidx)); -+ -+ pAdapter->mppriv.MptCtx.bStartContTx = bStart; -+ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) -+ Hal_SetCCKContinuousTx(pAdapter, bStart); -+ else if ((pAdapter->mppriv.rateidx >= MPT_RATE_6M) && -+ (pAdapter->mppriv.rateidx <= MPT_RATE_MCS15)) -+ Hal_SetOFDMContinuousTx(pAdapter, bStart); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_phycfg.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_phycfg.c -new file mode 100644 -index 0000000000000..36ad9dbbd8b08 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_phycfg.c -@@ -0,0 +1,1135 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188E_PHYCFG_C_ -+ -+#include -+#include -+#include -+#include -+ -+/*---------------------------Define Local Constant---------------------------*/ -+/* Channel switch:The size of command tables for switch channel*/ -+#define MAX_PRECMD_CNT 16 -+#define MAX_RFDEPENDCMD_CNT 16 -+#define MAX_POSTCMD_CNT 16 -+ -+#define MAX_DOZE_WAITING_TIMES_9x 64 -+ -+/*---------------------------Define Local Constant---------------------------*/ -+ -+/*------------------------Define global variable-----------------------------*/ -+ -+/*------------------------Define local variable------------------------------*/ -+ -+/*--------------------Define export function prototype-----------------------*/ -+/* Please refer to header file */ -+/*--------------------Define export function prototype-----------------------*/ -+ -+/*----------------------------Function Body----------------------------------*/ -+/* */ -+/* 1. BB register R/W API */ -+/* */ -+ -+/** -+* Function: phy_CalculateBitShift -+* -+* OverView: Get shifted position of the BitMask -+* -+* Input: -+* u32 BitMask, -+* -+* Output: none -+* Return: u32 Return the shift bit bit position of the mask -+*/ -+static u32 phy_CalculateBitShift(u32 BitMask) -+{ -+ u32 i; -+ -+ for (i = 0; i <= 31; i++) { -+ if (((BitMask>>i) & 0x1) == 1) -+ break; -+ } -+ return i; -+} -+ -+/** -+* Function: PHY_QueryBBReg -+* -+* OverView: Read "sepcific bits" from BB register -+* -+* Input: -+* struct adapter *Adapter, -+* u32 RegAddr, The target address to be readback -+* u32 BitMask The target bit position in the target address -+* to be readback -+* Output: None -+* Return: u32 Data The readback register value -+* Note: This function is equal to "GetRegSetting" in PHY programming guide -+*/ -+u32 -+rtl8188e_PHY_QueryBBReg( -+ struct adapter *Adapter, -+ u32 RegAddr, -+ u32 BitMask -+ ) -+{ -+ u32 ReturnValue = 0, OriginalValue, BitShift; -+ -+ OriginalValue = rtw_read32(Adapter, RegAddr); -+ BitShift = phy_CalculateBitShift(BitMask); -+ ReturnValue = (OriginalValue & BitMask) >> BitShift; -+ return ReturnValue; -+} -+ -+/** -+* Function: PHY_SetBBReg -+* -+* OverView: Write "Specific bits" to BB register (page 8~) -+* -+* Input: -+* struct adapter *Adapter, -+* u32 RegAddr, The target address to be modified -+* u32 BitMask The target bit position in the target address -+* to be modified -+* u32 Data The new register value in the target bit position -+* of the target address -+* -+* Output: None -+* Return: None -+* Note: This function is equal to "PutRegSetting" in PHY programming guide -+*/ -+ -+void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data) -+{ -+ u32 OriginalValue, BitShift; -+ -+ if (BitMask != bMaskDWord) { /* if not "double word" write */ -+ OriginalValue = rtw_read32(Adapter, RegAddr); -+ BitShift = phy_CalculateBitShift(BitMask); -+ Data = ((OriginalValue & (~BitMask)) | (Data << BitShift)); -+ } -+ -+ rtw_write32(Adapter, RegAddr, Data); -+} -+ -+/* */ -+/* 2. RF register R/W API */ -+/* */ -+/** -+* Function: phy_RFSerialRead -+* -+* OverView: Read regster from RF chips -+* -+* Input: -+* struct adapter *Adapter, -+* enum rf_radio_path eRFPath, Radio path of A/B/C/D -+* u32 Offset, The target address to be read -+* -+* Output: None -+* Return: u32 reback value -+* Note: Threre are three types of serial operations: -+* 1. Software serial write -+* 2. Hardware LSSI-Low Speed Serial Interface -+* 3. Hardware HSSI-High speed -+* serial write. Driver need to implement (1) and (2). -+* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() -+*/ -+static u32 -+phy_RFSerialRead( -+ struct adapter *Adapter, -+ enum rf_radio_path eRFPath, -+ u32 Offset -+ ) -+{ -+ u32 retValue = 0; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath]; -+ u32 NewOffset; -+ u32 tmplong, tmplong2; -+ u8 RfPiEnable = 0; -+ /* */ -+ /* Make sure RF register offset is correct */ -+ /* */ -+ Offset &= 0xff; -+ -+ /* */ -+ /* Switch page for 8256 RF IC */ -+ /* */ -+ NewOffset = Offset; -+ -+ /* For 92S LSSI Read RFLSSIRead */ -+ /* For RF A/B write 0x824/82c(does not work in the future) */ -+ /* We must use 0x824 for RF A and B to execute read trigger */ -+ tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord); -+ if (eRFPath == RF_PATH_A) -+ tmplong2 = tmplong; -+ else -+ tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord); -+ -+ tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge; /* T65 RF */ -+ -+ PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong&(~bLSSIReadEdge)); -+ rtw_udelay_os(10);/* PlatformStallExecution(10); */ -+ -+ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2); -+ rtw_udelay_os(100);/* PlatformStallExecution(100); */ -+ -+ rtw_udelay_os(10);/* PlatformStallExecution(10); */ -+ -+ if (eRFPath == RF_PATH_A) -+ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter1, BIT8); -+ else if (eRFPath == RF_PATH_B) -+ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter1, BIT8); -+ -+ if (RfPiEnable) { /* Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */ -+ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData); -+ } else { /* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */ -+ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); -+ } -+ return retValue; -+} -+ -+/** -+* Function: phy_RFSerialWrite -+* -+* OverView: Write data to RF register (page 8~) -+* -+* Input: -+* struct adapter *Adapter, -+* enum rf_radio_path eRFPath, Radio path of A/B/C/D -+* u32 Offset, The target address to be read -+* u32 Data The new register Data in the target bit position -+* of the target to be read -+* -+* Output: None -+* Return: None -+* Note: Threre are three types of serial operations: -+* 1. Software serial write -+* 2. Hardware LSSI-Low Speed Serial Interface -+* 3. Hardware HSSI-High speed -+* serial write. Driver need to implement (1) and (2). -+* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() -+ * -+ * Note: For RF8256 only -+ * The total count of RTL8256(Zebra4) register is around 36 bit it only employs -+ * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10]) -+ * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration -+ * programming guide" for more details. -+ * Thus, we define a sub-finction for RTL8526 register address conversion -+ * =========================================================== -+ * Register Mode RegCTL[1] RegCTL[0] Note -+ * (Reg00[12]) (Reg00[10]) -+ * =========================================================== -+ * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) -+ * ------------------------------------------------------------------ -+ * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) -+ * ------------------------------------------------------------------ -+ * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) -+ * ------------------------------------------------------------------ -+ * -+ * 2008/09/02 MH Add 92S RF definition -+ * -+ * -+ * -+*/ -+static void -+phy_RFSerialWrite( -+ struct adapter *Adapter, -+ enum rf_radio_path eRFPath, -+ u32 Offset, -+ u32 Data -+ ) -+{ -+ u32 DataAndAddr = 0; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath]; -+ u32 NewOffset; -+ -+ /* 2009/06/17 MH We can not execute IO for power save or other accident mode. */ -+ -+ Offset &= 0xff; -+ -+ /* */ -+ /* Switch page for 8256 RF IC */ -+ /* */ -+ NewOffset = Offset; -+ -+ /* */ -+ /* Put write addr in [5:0] and write data in [31:16] */ -+ /* */ -+ DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff; /* T65 RF */ -+ -+ /* */ -+ /* Write Operation */ -+ /* */ -+ PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); -+} -+ -+/** -+* Function: PHY_QueryRFReg -+* -+* OverView: Query "Specific bits" to RF register (page 8~) -+* -+* Input: -+* struct adapter *Adapter, -+* enum rf_radio_path eRFPath, Radio path of A/B/C/D -+* u32 RegAddr, The target address to be read -+* u32 BitMask The target bit position in the target address -+* to be read -+* -+* Output: None -+* Return: u32 Readback value -+* Note: This function is equal to "GetRFRegSetting" in PHY programming guide -+*/ -+u32 rtl8188e_PHY_QueryRFReg(struct adapter *Adapter, enum rf_radio_path eRFPath, -+ u32 RegAddr, u32 BitMask) -+{ -+ u32 Original_Value, Readback_Value, BitShift; -+ -+ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); -+ -+ BitShift = phy_CalculateBitShift(BitMask); -+ Readback_Value = (Original_Value & BitMask) >> BitShift; -+ return Readback_Value; -+} -+ -+/** -+* Function: PHY_SetRFReg -+* -+* OverView: Write "Specific bits" to RF register (page 8~) -+* -+* Input: -+* struct adapter *Adapter, -+* enum rf_radio_path eRFPath, Radio path of A/B/C/D -+* u32 RegAddr, The target address to be modified -+* u32 BitMask The target bit position in the target address -+* to be modified -+* u32 Data The new register Data in the target bit position -+* of the target address -+* -+* Output: None -+* Return: None -+* Note: This function is equal to "PutRFRegSetting" in PHY programming guide -+*/ -+void -+rtl8188e_PHY_SetRFReg( -+ struct adapter *Adapter, -+ enum rf_radio_path eRFPath, -+ u32 RegAddr, -+ u32 BitMask, -+ u32 Data -+ ) -+{ -+ u32 Original_Value, BitShift; -+ -+ /* RF data is 12 bits only */ -+ if (BitMask != bRFRegOffsetMask) { -+ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); -+ BitShift = phy_CalculateBitShift(BitMask); -+ Data = ((Original_Value & (~BitMask)) | (Data << BitShift)); -+ } -+ -+ phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data); -+} -+ -+/* */ -+/* 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */ -+/* */ -+ -+/*----------------------------------------------------------------------------- -+ * Function: PHY_MACConfig8192C -+ * -+ * Overview: Condig MAC by header file or parameter file. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 08/12/2008 MHC Create Version 0. -+ * -+ *---------------------------------------------------------------------------*/ -+s32 PHY_MACConfig8188E(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ int rtStatus = _SUCCESS; -+ -+ /* */ -+ /* Config MAC */ -+ /* */ -+ if (HAL_STATUS_FAILURE == ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv)) -+ rtStatus = _FAIL; -+ -+ /* 2010.07.13 AMPDU aggregation number B */ -+ rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM); -+ -+ return rtStatus; -+} -+ -+/** -+* Function: phy_InitBBRFRegisterDefinition -+* -+* OverView: Initialize Register definition offset for Radio Path A/B/C/D -+* -+* Input: -+* struct adapter *Adapter, -+* -+* Output: None -+* Return: None -+* Note: The initialization value is constant and it should never be changes -+*/ -+static void -+phy_InitBBRFRegisterDefinition( -+ struct adapter *Adapter -+) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ -+ /* RF Interface Sowrtware Control */ -+ pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 LSBs if read 32-bit from 0x870 */ -+ pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */ -+ pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 LSBs if read 32-bit from 0x874 */ -+ pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */ -+ -+ /* RF Interface Readback Value */ -+ pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; /* 16 LSBs if read 32-bit from 0x8E0 */ -+ pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */ -+ pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 LSBs if read 32-bit from 0x8E4 */ -+ pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */ -+ -+ /* RF Interface Output (and Enable) */ -+ pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x860 */ -+ pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x864 */ -+ -+ /* RF Interface (Output and) Enable */ -+ pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */ -+ pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */ -+ -+ /* Addr of LSSI. Wirte RF register by driver */ -+ pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; /* LSSI Parameter */ -+ pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; -+ -+ /* RF parameter */ -+ pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; /* BB Band Select */ -+ pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; -+ pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; -+ pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; -+ -+ /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ -+ pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ -+ pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ -+ pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ -+ pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ -+ -+ /* Tranceiver A~D HSSI Parameter-1 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; /* wire control parameter1 */ -+ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; /* wire control parameter1 */ -+ -+ /* Tranceiver A~D HSSI Parameter-2 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; /* wire control parameter2 */ -+ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; /* wire control parameter2 */ -+ -+ /* RF switch Control */ -+ pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */ -+ pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; -+ pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; -+ pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; -+ -+ /* AGC control 1 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; -+ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; -+ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; -+ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; -+ -+ /* AGC control 2 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; -+ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; -+ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; -+ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; -+ -+ /* RX AFE control 1 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; -+ pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; -+ pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; -+ pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; -+ -+ /* RX AFE control 1 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE; -+ pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; -+ pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; -+ pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; -+ -+ /* Tx AFE control 1 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; -+ pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; -+ pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; -+ pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; -+ -+ /* Tx AFE control 2 */ -+ pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE; -+ pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; -+ pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; -+ pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; -+ -+ /* Tranceiver LSSI Readback SI mode */ -+ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; -+ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; -+ pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; -+ pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; -+ -+ /* Tranceiver LSSI Readback PI mode */ -+ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback; -+ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback; -+} -+ -+void storePwrIndexDiffRateOffset(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ -+ if (RegAddr == rTxAGC_A_Rate18_06) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data; -+ if (RegAddr == rTxAGC_A_Rate54_24) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data; -+ if (RegAddr == rTxAGC_A_CCK1_Mcs32) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data; -+ if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data; -+ if (RegAddr == rTxAGC_A_Mcs03_Mcs00) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data; -+ if (RegAddr == rTxAGC_A_Mcs07_Mcs04) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data; -+ if (RegAddr == rTxAGC_A_Mcs11_Mcs08) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data; -+ if (RegAddr == rTxAGC_A_Mcs15_Mcs12) { -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data; -+ if (pHalData->rf_type == RF_1T1R) -+ pHalData->pwrGroupCnt++; -+ } -+ if (RegAddr == rTxAGC_B_Rate18_06) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data; -+ if (RegAddr == rTxAGC_B_Rate54_24) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data; -+ if (RegAddr == rTxAGC_B_CCK1_55_Mcs32) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data; -+ if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data; -+ if (RegAddr == rTxAGC_B_Mcs03_Mcs00) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data; -+ if (RegAddr == rTxAGC_B_Mcs07_Mcs04) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data; -+ if (RegAddr == rTxAGC_B_Mcs11_Mcs08) -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data; -+ if (RegAddr == rTxAGC_B_Mcs15_Mcs12) { -+ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data; -+ if (pHalData->rf_type != RF_1T1R) -+ pHalData->pwrGroupCnt++; -+ } -+} -+ -+static int phy_BB8188E_Config_ParaFile(struct adapter *Adapter) -+{ -+ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter); -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ int rtStatus = _SUCCESS; -+ -+ /* */ -+ /* 1. Read PHY_REG.TXT BB INIT!! */ -+ /* We will separate as 88C / 92C according to chip version */ -+ /* */ -+ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG)) -+ rtStatus = _FAIL; -+ if (rtStatus != _SUCCESS) -+ goto phy_BB8190_Config_ParaFile_Fail; -+ -+ /* 2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */ -+ if (!pEEPROM->bautoload_fail_flag) { -+ pHalData->pwrGroupCnt = 0; -+ -+ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG)) -+ rtStatus = _FAIL; -+ } -+ -+ if (rtStatus != _SUCCESS) -+ goto phy_BB8190_Config_ParaFile_Fail; -+ -+ /* 3. BB AGC table Initialization */ -+ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB)) -+ rtStatus = _FAIL; -+ -+ if (rtStatus != _SUCCESS) -+ goto phy_BB8190_Config_ParaFile_Fail; -+ -+phy_BB8190_Config_ParaFile_Fail: -+ -+ return rtStatus; -+} -+ -+int -+PHY_BBConfig8188E( -+ struct adapter *Adapter -+ ) -+{ -+ int rtStatus = _SUCCESS; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u32 RegVal; -+ u8 CrystalCap; -+ -+ phy_InitBBRFRegisterDefinition(Adapter); -+ -+ /* Enable BB and RF */ -+ RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN); -+ rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal|BIT13|BIT0|BIT1)); -+ -+ /* 20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. */ -+ -+ rtw_write8(Adapter, REG_RF_CTRL, RF_EN|RF_RSTB|RF_SDMRSTB); -+ -+ rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB); -+ -+ /* Config BB and AGC */ -+ rtStatus = phy_BB8188E_Config_ParaFile(Adapter); -+ -+ /* write 0x24[16:11] = 0x24[22:17] = CrystalCap */ -+ CrystalCap = pHalData->CrystalCap & 0x3F; -+ PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6))); -+ -+ return rtStatus; -+} -+ -+int PHY_RFConfig8188E(struct adapter *Adapter) -+{ -+ int rtStatus = _SUCCESS; -+ -+ /* RF config */ -+ rtStatus = PHY_RF6052_Config8188E(Adapter); -+ return rtStatus; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: PHY_ConfigRFWithParaFile() -+ * -+ * Overview: This function read RF parameters from general file format, and do RF 3-wire -+ * -+ * Input: struct adapter *Adapter -+ * ps8 pFileName -+ * enum rf_radio_path eRFPath -+ * -+ * Output: NONE -+ * -+ * Return: RT_STATUS_SUCCESS: configuration file exist -+ * -+ * Note: Delay may be required for RF configuration -+ *---------------------------------------------------------------------------*/ -+int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *Adapter, u8 *pFileName, enum rf_radio_path eRFPath) -+{ -+ return _SUCCESS; -+} -+ -+void -+rtl8192c_PHY_GetHWRegOriginalValue( -+ struct adapter *Adapter -+ ) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ -+ /* read rx initial gain */ -+ pHalData->DefaultInitialGain[0] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XAAGCCore1, bMaskByte0); -+ pHalData->DefaultInitialGain[1] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XBAGCCore1, bMaskByte0); -+ pHalData->DefaultInitialGain[2] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XCAGCCore1, bMaskByte0); -+ pHalData->DefaultInitialGain[3] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XDAGCCore1, bMaskByte0); -+ -+ /* read framesync */ -+ pHalData->framesync = (u8)PHY_QueryBBReg(Adapter, rOFDM0_RxDetector3, bMaskByte0); -+ pHalData->framesyncC34 = PHY_QueryBBReg(Adapter, rOFDM0_RxDetector2, bMaskDWord); -+} -+ -+/* */ -+/* Description: */ -+/* Map dBm into Tx power index according to */ -+/* current HW model, for example, RF and PA, and */ -+/* current wireless mode. */ -+/* By Bruce, 2008-01-29. */ -+/* */ -+static u8 phy_DbmToTxPwrIdx(struct adapter *Adapter, enum wireless_mode WirelessMode, int PowerInDbm) -+{ -+ u8 TxPwrIdx = 0; -+ int Offset = 0; -+ -+ /* */ -+ /* Tested by MP, we found that CCK Index 0 equals to 8dbm, OFDM legacy equals to */ -+ /* 3dbm, and OFDM HT equals to 0dbm respectively. */ -+ /* Note: */ -+ /* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */ -+ /* By Bruce, 2008-01-29. */ -+ /* */ -+ switch (WirelessMode) { -+ case WIRELESS_MODE_B: -+ Offset = -7; -+ break; -+ -+ case WIRELESS_MODE_G: -+ case WIRELESS_MODE_N_24G: -+ default: -+ Offset = -8; -+ break; -+ } -+ -+ if ((PowerInDbm - Offset) > 0) -+ TxPwrIdx = (u8)((PowerInDbm - Offset) * 2); -+ else -+ TxPwrIdx = 0; -+ -+ /* Tx Power Index is too large. */ -+ if (TxPwrIdx > MAX_TXPWR_IDX_NMODE_92S) -+ TxPwrIdx = MAX_TXPWR_IDX_NMODE_92S; -+ -+ return TxPwrIdx; -+} -+ -+/* */ -+/* Description: */ -+/* Map Tx power index into dBm according to */ -+/* current HW model, for example, RF and PA, and */ -+/* current wireless mode. */ -+/* By Bruce, 2008-01-29. */ -+/* */ -+static int phy_TxPwrIdxToDbm(struct adapter *Adapter, enum wireless_mode WirelessMode, u8 TxPwrIdx) -+{ -+ int Offset = 0; -+ int PwrOutDbm = 0; -+ -+ /* */ -+ /* Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to -8dbm. */ -+ /* Note: */ -+ /* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */ -+ /* By Bruce, 2008-01-29. */ -+ /* */ -+ switch (WirelessMode) { -+ case WIRELESS_MODE_B: -+ Offset = -7; -+ break; -+ case WIRELESS_MODE_G: -+ case WIRELESS_MODE_N_24G: -+ default: -+ Offset = -8; -+ break; -+ } -+ -+ PwrOutDbm = TxPwrIdx / 2 + Offset; /* Discard the decimal part. */ -+ -+ return PwrOutDbm; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: GetTxPowerLevel8190() -+ * -+ * Overview: This function is export to "common" moudule -+ * -+ * Input: struct adapter *Adapter -+ * psByte Power Level -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ *---------------------------------------------------------------------------*/ -+void PHY_GetTxPowerLevel8188E(struct adapter *Adapter, u32 *powerlevel) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u8 TxPwrLevel = 0; -+ int TxPwrDbm; -+ -+ /* */ -+ /* Because the Tx power indexes are different, we report the maximum of them to */ -+ /* meet the CCX TPC request. By Bruce, 2008-01-31. */ -+ /* */ -+ -+ /* CCK */ -+ TxPwrLevel = pHalData->CurrentCckTxPwrIdx; -+ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_B, TxPwrLevel); -+ -+ /* Legacy OFDM */ -+ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx + pHalData->LegacyHTTxPowerDiff; -+ -+ /* Compare with Legacy OFDM Tx power. */ -+ if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel) > TxPwrDbm) -+ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel); -+ -+ /* HT OFDM */ -+ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx; -+ -+ /* Compare with HT OFDM Tx power. */ -+ if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel) > TxPwrDbm) -+ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel); -+ -+ *powerlevel = TxPwrDbm; -+} -+ -+static void getTxPowerIndex88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel, -+ u8 *ofdmPowerLevel, u8 *BW20PowerLevel, -+ u8 *BW40PowerLevel) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u8 index = (channel - 1); -+ u8 TxCount = 0, path_nums; -+ -+ if ((RF_1T2R == pHalData->rf_type) || (RF_1T1R == pHalData->rf_type)) -+ path_nums = 1; -+ else -+ path_nums = 2; -+ -+ for (TxCount = 0; TxCount < path_nums; TxCount++) { -+ if (TxCount == RF_PATH_A) { -+ /* 1. CCK */ -+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; -+ /* 2. OFDM */ -+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->OFDM_24G_Diff[TxCount][RF_PATH_A]; -+ /* 1. BW20 */ -+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]; -+ /* 2. BW40 */ -+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; -+ } else if (TxCount == RF_PATH_B) { -+ /* 1. CCK */ -+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; -+ /* 2. OFDM */ -+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[TxCount][index]; -+ /* 1. BW20 */ -+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]+ -+ pHalData->BW20_24G_Diff[TxCount][index]; -+ /* 2. BW40 */ -+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; -+ } else if (TxCount == RF_PATH_C) { -+ /* 1. CCK */ -+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; -+ /* 2. OFDM */ -+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ -+ pHalData->BW20_24G_Diff[TxCount][index]; -+ /* 1. BW20 */ -+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ -+ pHalData->BW20_24G_Diff[TxCount][index]; -+ /* 2. BW40 */ -+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; -+ } else if (TxCount == RF_PATH_D) { -+ /* 1. CCK */ -+ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; -+ /* 2. OFDM */ -+ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_C][index]+ -+ pHalData->BW20_24G_Diff[TxCount][index]; -+ -+ /* 1. BW20 */ -+ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_A][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_B][index]+ -+ pHalData->BW20_24G_Diff[RF_PATH_C][index]+ -+ pHalData->BW20_24G_Diff[TxCount][index]; -+ -+ /* 2. BW40 */ -+ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; -+ } -+ } -+} -+ -+static void phy_PowerIndexCheck88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel, -+ u8 *ofdmPowerLevel, u8 *BW20PowerLevel, u8 *BW40PowerLevel) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ -+ pHalData->CurrentCckTxPwrIdx = cckPowerLevel[0]; -+ pHalData->CurrentOfdm24GTxPwrIdx = ofdmPowerLevel[0]; -+ pHalData->CurrentBW2024GTxPwrIdx = BW20PowerLevel[0]; -+ pHalData->CurrentBW4024GTxPwrIdx = BW40PowerLevel[0]; -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: SetTxPowerLevel8190() -+ * -+ * Overview: This function is export to "HalCommon" moudule -+ * We must consider RF path later!!!!!!! -+ * -+ * Input: struct adapter *Adapter -+ * u8 channel -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * 2008/11/04 MHC We remove EEPROM_93C56. -+ * We need to move CCX relative code to independet file. -+ * 2009/01/21 MHC Support new EEPROM format from SD3 requirement. -+ * -+ *---------------------------------------------------------------------------*/ -+void -+PHY_SetTxPowerLevel8188E( -+ struct adapter *Adapter, -+ u8 channel -+ ) -+{ -+ u8 cckPowerLevel[MAX_TX_COUNT] = {0}; -+ u8 ofdmPowerLevel[MAX_TX_COUNT] = {0};/* [0]:RF-A, [1]:RF-B */ -+ u8 BW20PowerLevel[MAX_TX_COUNT] = {0}; -+ u8 BW40PowerLevel[MAX_TX_COUNT] = {0}; -+ -+ getTxPowerIndex88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]); -+ -+ phy_PowerIndexCheck88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]); -+ -+ rtl8188e_PHY_RF6052SetCckTxPower(Adapter, &cckPowerLevel[0]); -+ rtl8188e_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0], channel); -+} -+ -+/* */ -+/* Description: */ -+/* Update transmit power level of all channel supported. */ -+/* */ -+/* TODO: */ -+/* A mode. */ -+/* By Bruce, 2008-02-04. */ -+/* */ -+bool -+PHY_UpdateTxPowerDbm8188E( -+ struct adapter *Adapter, -+ int powerInDbm -+ ) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u8 idx; -+ u8 rf_path; -+ -+ /* TODO: A mode Tx power. */ -+ u8 CckTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, powerInDbm); -+ u8 OfdmTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, powerInDbm); -+ -+ if (OfdmTxPwrIdx - pHalData->LegacyHTTxPowerDiff > 0) -+ OfdmTxPwrIdx -= pHalData->LegacyHTTxPowerDiff; -+ else -+ OfdmTxPwrIdx = 0; -+ -+ for (idx = 0; idx < 14; idx++) { -+ for (rf_path = 0; rf_path < 2; rf_path++) { -+ pHalData->TxPwrLevelCck[rf_path][idx] = CckTxPwrIdx; -+ pHalData->TxPwrLevelHT40_1S[rf_path][idx] = -+ pHalData->TxPwrLevelHT40_2S[rf_path][idx] = OfdmTxPwrIdx; -+ } -+ } -+ return true; -+} -+ -+void -+PHY_ScanOperationBackup8188E( -+ struct adapter *Adapter, -+ u8 Operation -+ ) -+{ -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: PHY_SetBWModeCallback8192C() -+ * -+ * Overview: Timer callback function for SetSetBWMode -+ * -+ * Input: PRT_TIMER pTimer -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Note: (1) We do not take j mode into consideration now -+ * (2) Will two workitem of "switch channel" and "switch channel bandwidth" run -+ * concurrently? -+ *---------------------------------------------------------------------------*/ -+static void -+_PHY_SetBWMode92C( -+ struct adapter *Adapter -+) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u8 regBwOpMode; -+ u8 regRRSR_RSC; -+ -+ if (pHalData->rf_chip == RF_PSEUDO_11N) -+ return; -+ -+ /* There is no 40MHz mode in RF_8225. */ -+ if (pHalData->rf_chip == RF_8225) -+ return; -+ -+ if (Adapter->bDriverStopped) -+ return; -+ -+ /* 3 */ -+ /* 3<1>Set MAC register */ -+ /* 3 */ -+ -+ regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE); -+ regRRSR_RSC = rtw_read8(Adapter, REG_RRSR+2); -+ -+ switch (pHalData->CurrentChannelBW) { -+ case HT_CHANNEL_WIDTH_20: -+ regBwOpMode |= BW_OPMODE_20MHZ; -+ /* 2007/02/07 Mark by Emily because we have not verify whether this register works */ -+ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); -+ break; -+ case HT_CHANNEL_WIDTH_40: -+ regBwOpMode &= ~BW_OPMODE_20MHZ; -+ /* 2007/02/07 Mark by Emily because we have not verify whether this register works */ -+ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); -+ regRRSR_RSC = (regRRSR_RSC&0x90) | (pHalData->nCur40MhzPrimeSC<<5); -+ rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC); -+ break; -+ default: -+ break; -+ } -+ -+ /* 3 */ -+ /* 3 <2>Set PHY related register */ -+ /* 3 */ -+ switch (pHalData->CurrentChannelBW) { -+ /* 20 MHz channel*/ -+ case HT_CHANNEL_WIDTH_20: -+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0); -+ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0); -+ break; -+ /* 40 MHz channel*/ -+ case HT_CHANNEL_WIDTH_40: -+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1); -+ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1); -+ /* Set Control channel to upper or lower. These settings are required only for 40MHz */ -+ PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, (pHalData->nCur40MhzPrimeSC>>1)); -+ PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, pHalData->nCur40MhzPrimeSC); -+ PHY_SetBBReg(Adapter, 0x818, (BIT26 | BIT27), -+ (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); -+ break; -+ default: -+ break; -+ } -+ /* Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 */ -+ -+ /* 3<3>Set RF related register */ -+ switch (pHalData->rf_chip) { -+ case RF_8225: -+ break; -+ case RF_8256: -+ /* Please implement this function in Hal8190PciPhy8256.c */ -+ break; -+ case RF_8258: -+ /* Please implement this function in Hal8190PciPhy8258.c */ -+ break; -+ case RF_PSEUDO_11N: -+ break; -+ case RF_6052: -+ rtl8188e_PHY_RF6052SetBandwidth(Adapter, pHalData->CurrentChannelBW); -+ break; -+ default: -+ break; -+ } -+} -+ -+ /*----------------------------------------------------------------------------- -+ * Function: SetBWMode8190Pci() -+ * -+ * Overview: This function is export to "HalCommon" moudule -+ * -+ * Input: struct adapter *Adapter -+ * enum ht_channel_width Bandwidth 20M or 40M -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Note: We do not take j mode into consideration now -+ *---------------------------------------------------------------------------*/ -+void PHY_SetBWMode8188E(struct adapter *Adapter, enum ht_channel_width Bandwidth, /* 20M or 40M */ -+ unsigned char Offset) /* Upper, Lower, or Don't care */ -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ enum ht_channel_width tmpBW = pHalData->CurrentChannelBW; -+ -+ pHalData->CurrentChannelBW = Bandwidth; -+ -+ pHalData->nCur40MhzPrimeSC = Offset; -+ -+ if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) -+ _PHY_SetBWMode92C(Adapter); -+ else -+ pHalData->CurrentChannelBW = tmpBW; -+} -+ -+static void _PHY_SwChnl8192C(struct adapter *Adapter, u8 channel) -+{ -+ u8 eRFPath; -+ u32 param1, param2; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ -+ if (Adapter->bNotifyChannelChange) -+ DBG_88E("[%s] ch = %d\n", __func__, channel); -+ -+ /* s1. pre common command - CmdID_SetTxPowerLevel */ -+ PHY_SetTxPowerLevel8188E(Adapter, channel); -+ -+ /* s2. RF dependent command - CmdID_RF_WriteReg, param1=RF_CHNLBW, param2=channel */ -+ param1 = RF_CHNLBW; -+ param2 = channel; -+ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { -+ pHalData->RfRegChnlVal[eRFPath] = ((pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2); -+ PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, param1, bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]); -+ } -+} -+ -+void PHY_SwChnl8188E(struct adapter *Adapter, u8 channel) -+{ -+ /* Call after initialization */ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u8 tmpchannel = pHalData->CurrentChannel; -+ bool bResult = true; -+ -+ if (pHalData->rf_chip == RF_PSEUDO_11N) -+ return; /* return immediately if it is peudo-phy */ -+ -+ if (channel == 0) -+ channel = 1; -+ -+ pHalData->CurrentChannel = channel; -+ -+ if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) { -+ _PHY_SwChnl8192C(Adapter, channel); -+ -+ if (bResult) -+ ; -+ else -+ pHalData->CurrentChannel = tmpchannel; -+ -+ } else { -+ pHalData->CurrentChannel = tmpchannel; -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_rf6052.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_rf6052.c -new file mode 100644 -index 0000000000000..0ed6ff67ad57c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_rf6052.c -@@ -0,0 +1,569 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+/****************************************************************************** -+ * -+ * -+ * Module: rtl8192c_rf6052.c ( Source C File) -+ * -+ * Note: Provide RF 6052 series relative API. -+ * -+ * Function: -+ * -+ * Export: -+ * -+ * Abbrev: -+ * -+ * History: -+ * Data Who Remark -+ * -+ * 09/25/2008 MHC Create initial version. -+ * 11/05/2008 MHC Add API for tw power setting. -+ * -+ * -+******************************************************************************/ -+ -+#define _RTL8188E_RF6052_C_ -+ -+#include -+#include -+ -+#include -+ -+/*---------------------------Define Local Constant---------------------------*/ -+/* Define local structure for debug!!!!! */ -+struct rf_shadow { -+ /* Shadow register value */ -+ u32 Value; -+ /* Compare or not flag */ -+ u8 Compare; -+ /* Record If it had ever modified unpredicted */ -+ u8 ErrorOrNot; -+ /* Recorver Flag */ -+ u8 Recorver; -+ /* */ -+ u8 Driver_Write; -+}; -+ -+/*---------------------------Define Local Constant---------------------------*/ -+ -+/*------------------------Define global variable-----------------------------*/ -+ -+/*------------------------Define local variable------------------------------*/ -+ -+/*----------------------------------------------------------------------------- -+ * Function: RF_ChangeTxPath -+ * -+ * Overview: For RL6052, we must change some RF settign for 1T or 2T. -+ * -+ * Input: u16 DataRate 0x80-8f, 0x90-9f -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 09/25/2008 MHC Create Version 0. -+ * Firmwaer support the utility later. -+ * -+ *---------------------------------------------------------------------------*/ -+void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate) -+{ -+/* We do not support gain table change inACUT now !!!! Delete later !!! */ -+} /* RF_ChangeTxPath */ -+ -+/*----------------------------------------------------------------------------- -+ * Function: PHY_RF6052SetBandwidth() -+ * -+ * Overview: This function is called by SetBWModeCallback8190Pci() only -+ * -+ * Input: struct adapter *Adapter -+ * WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Note: For RF type 0222D -+ *---------------------------------------------------------------------------*/ -+void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter, -+ enum ht_channel_width Bandwidth) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ -+ switch (Bandwidth) { -+ case HT_CHANNEL_WIDTH_20: -+ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10) | BIT(11)); -+ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); -+ break; -+ case HT_CHANNEL_WIDTH_40: -+ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10)); -+ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); -+ break; -+ default: -+ break; -+ } -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: PHY_RF6052SetCckTxPower -+ * -+ * Overview: -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/05/2008 MHC Simulate 8192series.. -+ * -+ *---------------------------------------------------------------------------*/ -+ -+void -+rtl8188e_PHY_RF6052SetCckTxPower( -+ struct adapter *Adapter, -+ u8 *pPowerlevel) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &pHalData->dmpriv; -+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; -+ u32 TxAGC[2] = {0, 0}, tmpval = 0, pwrtrac_value; -+ bool TurboScanOff = false; -+ u8 idx1, idx2; -+ u8 *ptr; -+ u8 direction; -+ /* FOR CE ,must disable turbo scan */ -+ TurboScanOff = true; -+ -+ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { -+ TxAGC[RF_PATH_A] = 0x3f3f3f3f; -+ TxAGC[RF_PATH_B] = 0x3f3f3f3f; -+ -+ TurboScanOff = true;/* disable turbo scan */ -+ -+ if (TurboScanOff) { -+ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { -+ TxAGC[idx1] = -+ pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | -+ (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); -+ /* 2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. */ -+ if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA) -+ TxAGC[idx1] = 0x20; -+ } -+ } -+ } else { -+ /* Driver dynamic Tx power shall not affect Tx power. -+ * It shall be determined by power training mechanism. -+i * Currently, we cannot fully disable driver dynamic -+ * tx power mechanism because it is referenced by BT -+ * coexist mechanism. -+ * In the future, two mechanism shall be separated from -+ * each other and maintained independently. */ -+ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) { -+ TxAGC[RF_PATH_A] = 0x10101010; -+ TxAGC[RF_PATH_B] = 0x10101010; -+ } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) { -+ TxAGC[RF_PATH_A] = 0x00000000; -+ TxAGC[RF_PATH_B] = 0x00000000; -+ } else { -+ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { -+ TxAGC[idx1] = -+ pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) | -+ (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24); -+ } -+ if (pHalData->EEPROMRegulatory == 0) { -+ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) + -+ (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8); -+ TxAGC[RF_PATH_A] += tmpval; -+ -+ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) + -+ (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24); -+ TxAGC[RF_PATH_B] += tmpval; -+ } -+ } -+ } -+ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { -+ ptr = (u8 *)(&(TxAGC[idx1])); -+ for (idx2 = 0; idx2 < 4; idx2++) { -+ if (*ptr > RF6052_MAX_TX_PWR) -+ *ptr = RF6052_MAX_TX_PWR; -+ ptr++; -+ } -+ } -+ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value); -+ -+ if (direction == 1) { -+ /* Increase TX power */ -+ TxAGC[0] += pwrtrac_value; -+ TxAGC[1] += pwrtrac_value; -+ } else if (direction == 2) { -+ /* Decrease TX power */ -+ TxAGC[0] -= pwrtrac_value; -+ TxAGC[1] -= pwrtrac_value; -+ } -+ -+ /* rf-A cck tx power */ -+ tmpval = TxAGC[RF_PATH_A]&0xff; -+ PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval); -+ tmpval = TxAGC[RF_PATH_A]>>8; -+ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); -+ -+ /* rf-B cck tx power */ -+ tmpval = TxAGC[RF_PATH_B]>>24; -+ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval); -+ tmpval = TxAGC[RF_PATH_B]&0x00ffffff; -+ PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); -+} /* PHY_RF6052SetCckTxPower */ -+ -+/* */ -+/* powerbase0 for OFDM rates */ -+/* powerbase1 for HT MCS rates */ -+/* */ -+static void getpowerbase88e(struct adapter *Adapter, u8 *pPowerLevelOFDM, -+ u8 *pPowerLevelBW20, u8 *pPowerLevelBW40, u8 Channel, u32 *OfdmBase, u32 *MCSBase) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u32 powerBase0, powerBase1; -+ u8 i, powerlevel[2]; -+ -+ for (i = 0; i < 2; i++) { -+ powerBase0 = pPowerLevelOFDM[i]; -+ -+ powerBase0 = (powerBase0<<24) | (powerBase0<<16) | (powerBase0<<8) | powerBase0; -+ *(OfdmBase+i) = powerBase0; -+ } -+ for (i = 0; i < pHalData->NumTotalRFPath; i++) { -+ /* Check HT20 to HT40 diff */ -+ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) -+ powerlevel[i] = pPowerLevelBW20[i]; -+ else -+ powerlevel[i] = pPowerLevelBW40[i]; -+ powerBase1 = powerlevel[i]; -+ powerBase1 = (powerBase1<<24) | (powerBase1<<16) | (powerBase1<<8) | powerBase1; -+ *(MCSBase+i) = powerBase1; -+ } -+} -+static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel, -+ u8 index, u32 *powerBase0, u32 *powerBase1, -+ u32 *pOutWriteVal) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &pHalData->dmpriv; -+ u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit; -+ s8 pwr_diff = 0; -+ u32 writeVal, customer_limit, rf; -+ u8 Regulatory = pHalData->EEPROMRegulatory; -+ -+ /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ -+ -+ for (rf = 0; rf < 2; rf++) { -+ switch (Regulatory) { -+ case 0: /* Realtek better performance */ -+ /* increase power diff defined by Realtek for large power */ -+ chnlGroup = 0; -+ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] + -+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]); -+ break; -+ case 1: /* Realtek regulatory */ -+ /* increase power diff defined by Realtek for regulatory */ -+ if (pHalData->pwrGroupCnt == 1) -+ chnlGroup = 0; -+ if (pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) { -+ if (Channel < 3) /* Channel 1-2 */ -+ chnlGroup = 0; -+ else if (Channel < 6) /* Channel 3-5 */ -+ chnlGroup = 1; -+ else if (Channel < 9) /* Channel 6-8 */ -+ chnlGroup = 2; -+ else if (Channel < 12) /* Channel 9-11 */ -+ chnlGroup = 3; -+ else if (Channel < 14) /* Channel 12-13 */ -+ chnlGroup = 4; -+ else if (Channel == 14) /* Channel 14 */ -+ chnlGroup = 5; -+ } -+ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] + -+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]); -+ break; -+ case 2: /* Better regulatory */ -+ /* don't increase any power diff */ -+ writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]); -+ break; -+ case 3: /* Customer defined power diff. */ -+ /* increase power diff defined by customer. */ -+ chnlGroup = 0; -+ -+ if (index < 2) -+ pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel-1]; -+ else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) -+ pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel-1]; -+ -+ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) -+ customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel-1]; -+ else -+ customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel-1]; -+ -+ if (pwr_diff >= customer_pwr_limit) -+ pwr_diff = 0; -+ else -+ pwr_diff = customer_pwr_limit - pwr_diff; -+ -+ for (i = 0; i < 4; i++) { -+ pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)]&(0x7f<<(i*8)))>>(i*8)); -+ -+ if (pwr_diff_limit[i] > pwr_diff) -+ pwr_diff_limit[i] = pwr_diff; -+ } -+ customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) | -+ (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]); -+ writeVal = customer_limit + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); -+ break; -+ default: -+ chnlGroup = 0; -+ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] + -+ ((index < 2) ? powerBase0[rf] : powerBase1[rf]); -+ break; -+ } -+/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */ -+/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */ -+/* In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */ -+ /* 92d do not need this */ -+ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) -+ writeVal = 0x14141414; -+ else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) -+ writeVal = 0x00000000; -+ -+ /* 20100628 Joseph: High power mode for BT-Coexist mechanism. */ -+ /* This mechanism is only applied when Driver-Highpower-Mechanism is OFF. */ -+ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1) -+ writeVal = writeVal - 0x06060606; -+ else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2) -+ writeVal = writeVal; -+ *(pOutWriteVal+rf) = writeVal; -+ } -+} -+static void writeOFDMPowerReg88E(struct adapter *Adapter, u8 index, u32 *pValue) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u16 regoffset_a[6] = { -+ rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24, -+ rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04, -+ rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12}; -+ u16 regoffset_b[6] = { -+ rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24, -+ rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04, -+ rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12}; -+ u8 i, rf, pwr_val[4]; -+ u32 writeVal; -+ u16 regoffset; -+ -+ for (rf = 0; rf < 2; rf++) { -+ writeVal = pValue[rf]; -+ for (i = 0; i < 4; i++) { -+ pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8)); -+ if (pwr_val[i] > RF6052_MAX_TX_PWR) -+ pwr_val[i] = RF6052_MAX_TX_PWR; -+ } -+ writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) | (pwr_val[1]<<8) | pwr_val[0]; -+ -+ if (rf == 0) -+ regoffset = regoffset_a[index]; -+ else -+ regoffset = regoffset_b[index]; -+ -+ PHY_SetBBReg(Adapter, regoffset, bMaskDWord, writeVal); -+ -+ /* 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */ -+ if (((pHalData->rf_type == RF_2T2R) && -+ (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs15_Mcs12)) || -+ ((pHalData->rf_type != RF_2T2R) && -+ (regoffset == rTxAGC_A_Mcs07_Mcs04 || regoffset == rTxAGC_B_Mcs07_Mcs04))) { -+ writeVal = pwr_val[3]; -+ if (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_A_Mcs07_Mcs04) -+ regoffset = 0xc90; -+ if (regoffset == rTxAGC_B_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs07_Mcs04) -+ regoffset = 0xc98; -+ for (i = 0; i < 3; i++) { -+ if (i != 2) -+ writeVal = (writeVal > 8) ? (writeVal-8) : 0; -+ else -+ writeVal = (writeVal > 6) ? (writeVal-6) : 0; -+ rtw_write8(Adapter, (u32)(regoffset+i), (u8)writeVal); -+ } -+ } -+ } -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: PHY_RF6052SetOFDMTxPower -+ * -+ * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for -+ * different channel and read original value in TX power register area from -+ * 0xe00. We increase offset and original value to be correct tx pwr. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 11/05/2008 MHC Simulate 8192 series method. -+ * 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to -+ * A/B pwr difference or legacy/HT pwr diff. -+ * 2. We concern with path B legacy/HT OFDM difference. -+ * 01/22/2009 MHC Support new EPRO format from SD3. -+ * -+ *---------------------------------------------------------------------------*/ -+ -+void -+rtl8188e_PHY_RF6052SetOFDMTxPower( -+ struct adapter *Adapter, -+ u8 *pPowerLevelOFDM, -+ u8 *pPowerLevelBW20, -+ u8 *pPowerLevelBW40, -+ u8 Channel) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value; -+ u8 direction; -+ u8 index = 0; -+ -+ getpowerbase88e(Adapter, pPowerLevelOFDM, pPowerLevelBW20, pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]); -+ -+ /* 2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. */ -+ /* This is ued to fix unstable power tracking mode. */ -+ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value); -+ -+ for (index = 0; index < 6; index++) { -+ get_rx_power_val_by_reg(Adapter, Channel, index, -+ &powerBase0[0], &powerBase1[0], -+ &writeVal[0]); -+ -+ if (direction == 1) { -+ writeVal[0] += pwrtrac_value; -+ writeVal[1] += pwrtrac_value; -+ } else if (direction == 2) { -+ writeVal[0] -= pwrtrac_value; -+ writeVal[1] -= pwrtrac_value; -+ } -+ writeOFDMPowerReg88E(Adapter, index, &writeVal[0]); -+ } -+} -+ -+static int phy_RF6052_Config_ParaFile(struct adapter *Adapter) -+{ -+ struct bb_reg_def *pPhyReg; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ u32 u4RegValue = 0; -+ u8 eRFPath; -+ int rtStatus = _SUCCESS; -+ -+ /* 3----------------------------------------------------------------- */ -+ /* 3 <2> Initialize RF */ -+ /* 3----------------------------------------------------------------- */ -+ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { -+ pPhyReg = &pHalData->PHYRegDef[eRFPath]; -+ -+ /*----Store original RFENV control type----*/ -+ switch (eRFPath) { -+ case RF_PATH_A: -+ case RF_PATH_C: -+ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV); -+ break; -+ case RF_PATH_B: -+ case RF_PATH_D: -+ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16); -+ break; -+ } -+ /*----Set RF_ENV enable----*/ -+ PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); -+ rtw_udelay_os(1);/* PlatformStallExecution(1); */ -+ -+ /*----Set RF_ENV output high----*/ -+ PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); -+ rtw_udelay_os(1);/* PlatformStallExecution(1); */ -+ -+ /* Set bit number of Address and Data for RF register */ -+ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 1 to 4 bits for 8255 */ -+ rtw_udelay_os(1);/* PlatformStallExecution(1); */ -+ -+ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for 8255 */ -+ rtw_udelay_os(1);/* PlatformStallExecution(1); */ -+ -+ /*----Initialize RF fom connfiguration file----*/ -+ switch (eRFPath) { -+ case RF_PATH_A: -+ if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum rf_radio_path)eRFPath, (enum rf_radio_path)eRFPath)) -+ rtStatus = _FAIL; -+ break; -+ case RF_PATH_B: -+ if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum rf_radio_path)eRFPath, (enum rf_radio_path)eRFPath)) -+ rtStatus = _FAIL; -+ break; -+ case RF_PATH_C: -+ break; -+ case RF_PATH_D: -+ break; -+ } -+ /*----Restore RFENV control type----*/; -+ switch (eRFPath) { -+ case RF_PATH_A: -+ case RF_PATH_C: -+ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); -+ break; -+ case RF_PATH_B: -+ case RF_PATH_D: -+ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue); -+ break; -+ } -+ if (rtStatus != _SUCCESS) -+ goto phy_RF6052_Config_ParaFile_Fail; -+ } -+ return rtStatus; -+ -+phy_RF6052_Config_ParaFile_Fail: -+ return rtStatus; -+} -+ -+int PHY_RF6052_Config8188E(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); -+ int rtStatus = _SUCCESS; -+ -+ /* */ -+ /* Initialize general global value */ -+ /* */ -+ /* TODO: Extend RF_PATH_C and RF_PATH_D in the future */ -+ if (pHalData->rf_type == RF_1T1R) -+ pHalData->NumTotalRFPath = 1; -+ else -+ pHalData->NumTotalRFPath = 2; -+ -+ /* */ -+ /* Config BB and RF */ -+ /* */ -+ rtStatus = phy_RF6052_Config_ParaFile(Adapter); -+ return rtStatus; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_rxdesc.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_rxdesc.c -new file mode 100644 -index 0000000000000..a07ad95ad84b1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_rxdesc.c -@@ -0,0 +1,202 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188E_REDESC_C_ -+ -+#include -+#include -+#include -+ -+static void process_rssi(struct adapter *padapter, struct recv_frame *prframe) -+{ -+ struct rx_pkt_attrib *pattrib = &prframe->attrib; -+ struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data; -+ -+ if (signal_stat->update_req) { -+ signal_stat->total_num = 0; -+ signal_stat->total_val = 0; -+ signal_stat->update_req = 0; -+ } -+ -+ signal_stat->total_num++; -+ signal_stat->total_val += pattrib->phy_info.SignalStrength; -+ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; -+} /* Process_UI_RSSI_8192C */ -+ -+static void process_link_qual(struct adapter *padapter, struct recv_frame *prframe) -+{ -+ struct rx_pkt_attrib *pattrib; -+ struct signal_stat *signal_stat; -+ -+ if (prframe == NULL || padapter == NULL) -+ return; -+ -+ pattrib = &prframe->attrib; -+ signal_stat = &padapter->recvpriv.signal_qual_data; -+ -+ if (signal_stat->update_req) { -+ signal_stat->total_num = 0; -+ signal_stat->total_val = 0; -+ signal_stat->update_req = 0; -+ } -+ -+ signal_stat->total_num++; -+ signal_stat->total_val += pattrib->phy_info.SignalQuality; -+ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; -+} -+ -+void rtl8188e_process_phy_info(struct adapter *padapter, void *prframe) -+{ -+ struct recv_frame *precvframe = (struct recv_frame *)prframe; -+ -+ /* Check RSSI */ -+ process_rssi(padapter, precvframe); -+ /* Check EVM */ -+ process_link_qual(padapter, precvframe); -+} -+ -+void update_recvframe_attrib_88e(struct recv_frame *precvframe, struct recv_stat *prxstat) -+{ -+ struct rx_pkt_attrib *pattrib; -+ struct recv_stat report; -+ -+ report.rxdw0 = prxstat->rxdw0; -+ report.rxdw1 = prxstat->rxdw1; -+ report.rxdw2 = prxstat->rxdw2; -+ report.rxdw3 = prxstat->rxdw3; -+ report.rxdw4 = prxstat->rxdw4; -+ report.rxdw5 = prxstat->rxdw5; -+ -+ pattrib = &precvframe->attrib; -+ memset(pattrib, 0, sizeof(struct rx_pkt_attrib)); -+ -+ pattrib->crc_err = (u8)((le32_to_cpu(report.rxdw0) >> 14) & 0x1);;/* u8)prxreport->crc32; */ -+ -+ /* update rx report to recv_frame attribute */ -+ pattrib->pkt_rpt_type = (u8)((le32_to_cpu(report.rxdw3) >> 14) & 0x3);/* prxreport->rpt_sel; */ -+ -+ if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */ -+ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */ -+ pattrib->drvinfo_sz = (u8)((le32_to_cpu(report.rxdw0) >> 16) & 0xf) * 8;/* u8)(prxreport->drvinfosize << 3); */ -+ -+ pattrib->physt = (u8)((le32_to_cpu(report.rxdw0) >> 26) & 0x1);/* u8)prxreport->physt; */ -+ -+ pattrib->bdecrypted = (le32_to_cpu(report.rxdw0) & BIT(27)) ? 0 : 1;/* u8)(prxreport->swdec ? 0 : 1); */ -+ pattrib->encrypt = (u8)((le32_to_cpu(report.rxdw0) >> 20) & 0x7);/* u8)prxreport->security; */ -+ -+ pattrib->qos = (u8)((le32_to_cpu(report.rxdw0) >> 23) & 0x1);/* u8)prxreport->qos; */ -+ pattrib->priority = (u8)((le32_to_cpu(report.rxdw1) >> 8) & 0xf);/* u8)prxreport->tid; */ -+ -+ pattrib->amsdu = (u8)((le32_to_cpu(report.rxdw1) >> 13) & 0x1);/* u8)prxreport->amsdu; */ -+ -+ pattrib->seq_num = (u16)(le32_to_cpu(report.rxdw2) & 0x00000fff);/* u16)prxreport->seq; */ -+ pattrib->frag_num = (u8)((le32_to_cpu(report.rxdw2) >> 12) & 0xf);/* u8)prxreport->frag; */ -+ pattrib->mfrag = (u8)((le32_to_cpu(report.rxdw1) >> 27) & 0x1);/* u8)prxreport->mf; */ -+ pattrib->mdata = (u8)((le32_to_cpu(report.rxdw1) >> 26) & 0x1);/* u8)prxreport->md; */ -+ -+ pattrib->mcs_rate = (u8)(le32_to_cpu(report.rxdw3) & 0x3f);/* u8)prxreport->rxmcs; */ -+ pattrib->rxht = (u8)((le32_to_cpu(report.rxdw3) >> 6) & 0x1);/* u8)prxreport->rxht; */ -+ -+ pattrib->icv_err = (u8)((le32_to_cpu(report.rxdw0) >> 15) & 0x1);/* u8)prxreport->icverr; */ -+ pattrib->shift_sz = (u8)((le32_to_cpu(report.rxdw0) >> 24) & 0x3); -+ } else if (pattrib->pkt_rpt_type == TX_REPORT1) { /* CCX */ -+ pattrib->pkt_len = TX_RPT1_PKT_LEN; -+ pattrib->drvinfo_sz = 0; -+ } else if (pattrib->pkt_rpt_type == TX_REPORT2) { /* TX RPT */ -+ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x3FF);/* Rx length[9:0] */ -+ pattrib->drvinfo_sz = 0; -+ -+ /* */ -+ /* Get TX report MAC ID valid. */ -+ /* */ -+ pattrib->MacIDValidEntry[0] = le32_to_cpu(report.rxdw4); -+ pattrib->MacIDValidEntry[1] = le32_to_cpu(report.rxdw5); -+ -+ } else if (pattrib->pkt_rpt_type == HIS_REPORT) { /* USB HISR RPT */ -+ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */ -+ } -+} -+ -+/* -+ * Notice: -+ * Before calling this function, -+ * precvframe->rx_data should be ready! -+ */ -+void update_recvframe_phyinfo_88e(struct recv_frame *precvframe, struct phy_stat *pphy_status) -+{ -+ struct adapter *padapter = precvframe->adapter; -+ struct rx_pkt_attrib *pattrib = &precvframe->attrib; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct odm_phy_status_info *pPHYInfo = (struct odm_phy_status_info *)(&pattrib->phy_info); -+ u8 *wlanhdr; -+ struct odm_per_pkt_info pkt_info; -+ u8 *sa = NULL; -+ struct sta_priv *pstapriv; -+ struct sta_info *psta; -+ -+ pkt_info.bPacketMatchBSSID = false; -+ pkt_info.bPacketToSelf = false; -+ pkt_info.bPacketBeacon = false; -+ -+ wlanhdr = get_recvframe_data(precvframe); -+ -+ pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) && -+ !pattrib->icv_err && !pattrib->crc_err && -+ !memcmp(get_hdr_bssid(wlanhdr), -+ get_bssid(&padapter->mlmepriv), ETH_ALEN)); -+ -+ pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && -+ (!memcmp(get_da(wlanhdr), -+ myid(&padapter->eeprompriv), ETH_ALEN)); -+ -+ pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && -+ (GetFrameSubType(wlanhdr) == WIFI_BEACON); -+ -+ if (pkt_info.bPacketBeacon) { -+ if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) -+ sa = padapter->mlmepriv.cur_network.network.MacAddress; -+ /* to do Ad-hoc */ -+ } else { -+ sa = get_sa(wlanhdr); -+ } -+ -+ pstapriv = &padapter->stapriv; -+ pkt_info.StationID = 0xFF; -+ psta = rtw_get_stainfo(pstapriv, sa); -+ if (psta) -+ pkt_info.StationID = psta->mac_id; -+ pkt_info.Rate = pattrib->mcs_rate; -+ -+ ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status, &(pkt_info), padapter); -+ -+ precvframe->psta = NULL; -+ if (pkt_info.bPacketMatchBSSID && -+ (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE))) { -+ if (psta) { -+ precvframe->psta = psta; -+ rtl8188e_process_phy_info(padapter, precvframe); -+ } -+ } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) { -+ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) { -+ if (psta) -+ precvframe->psta = psta; -+ } -+ rtl8188e_process_phy_info(padapter, precvframe); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_sreset.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_sreset.c -new file mode 100644 -index 0000000000000..047b53482e67f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_sreset.c -@@ -0,0 +1,80 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188E_SRESET_C_ -+ -+#include -+#include -+ -+void rtl8188e_silentreset_for_specific_platform(struct adapter *padapter) -+{ -+} -+ -+void rtl8188e_sreset_xmit_status_check(struct adapter *padapter) -+{ -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ struct sreset_priv *psrtpriv = &pHalData->srestpriv; -+ -+ unsigned long current_time; -+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -+ unsigned int diff_time; -+ u32 txdma_status; -+ -+ txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS); -+ if (txdma_status != 0x00) { -+ DBG_88E("%s REG_TXDMA_STATUS:0x%08x\n", __func__, txdma_status); -+ rtw_write32(padapter, REG_TXDMA_STATUS, txdma_status); -+ rtl8188e_silentreset_for_specific_platform(padapter); -+ } -+ /* total xmit irp = 4 */ -+ current_time = jiffies; -+ if (0 == pxmitpriv->free_xmitbuf_cnt) { -+ diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_time); -+ -+ if (diff_time > 2000) { -+ if (psrtpriv->last_tx_complete_time == 0) { -+ psrtpriv->last_tx_complete_time = current_time; -+ } else { -+ diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_complete_time); -+ if (diff_time > 4000) { -+ DBG_88E("%s tx hang\n", __func__); -+ rtl8188e_silentreset_for_specific_platform(padapter); -+ } -+ } -+ } -+ } -+} -+ -+void rtl8188e_sreset_linked_status_check(struct adapter *padapter) -+{ -+ u32 rx_dma_status = 0; -+ u8 fw_status = 0; -+ rx_dma_status = rtw_read32(padapter, REG_RXDMA_STATUS); -+ if (rx_dma_status != 0x00) { -+ DBG_88E("%s REG_RXDMA_STATUS:0x%08x\n", __func__, rx_dma_status); -+ rtw_write32(padapter, REG_RXDMA_STATUS, rx_dma_status); -+ } -+ fw_status = rtw_read8(padapter, REG_FMETHR); -+ if (fw_status != 0x00) { -+ if (fw_status == 1) -+ DBG_88E("%s REG_FW_STATUS (0x%02x), Read_Efuse_Fail !!\n", __func__, fw_status); -+ else if (fw_status == 2) -+ DBG_88E("%s REG_FW_STATUS (0x%02x), Condition_No_Match !!\n", __func__, fw_status); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188e_xmit.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_xmit.c -new file mode 100644 -index 0000000000000..7ecbcf731ea93 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188e_xmit.c -@@ -0,0 +1,91 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188E_XMIT_C_ -+ -+#include -+#include -+#include -+ -+void dump_txrpt_ccx_88e(void *buf) -+{ -+ struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf; -+ -+ DBG_88E("%s:\n" -+ "tag1:%u, pkt_num:%u, txdma_underflow:%u, int_bt:%u, int_tri:%u, int_ccx:%u\n" -+ "mac_id:%u, pkt_ok:%u, bmc:%u\n" -+ "retry_cnt:%u, lifetime_over:%u, retry_over:%u\n" -+ "ccx_qtime:%u\n" -+ "final_data_rate:0x%02x\n" -+ "qsel:%u, sw:0x%03x\n", -+ __func__, txrpt_ccx->tag1, txrpt_ccx->pkt_num, -+ txrpt_ccx->txdma_underflow, txrpt_ccx->int_bt, -+ txrpt_ccx->int_tri, txrpt_ccx->int_ccx, -+ txrpt_ccx->mac_id, txrpt_ccx->pkt_ok, txrpt_ccx->bmc, -+ txrpt_ccx->retry_cnt, txrpt_ccx->lifetime_over, -+ txrpt_ccx->retry_over, txrpt_ccx_qtime_88e(txrpt_ccx), -+ txrpt_ccx->final_data_rate, txrpt_ccx->qsel, -+ txrpt_ccx_sw_88e(txrpt_ccx) -+ ); -+} -+ -+void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf) -+{ -+ struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf; -+ -+ if (txrpt_ccx->int_ccx) { -+ if (txrpt_ccx->pkt_ok) -+ rtw_ack_tx_done(&adapter->xmitpriv, -+ RTW_SCTX_DONE_SUCCESS); -+ else -+ rtw_ack_tx_done(&adapter->xmitpriv, -+ RTW_SCTX_DONE_CCX_PKT_FAIL); -+ } -+} -+ -+void _dbg_dump_tx_info(struct adapter *padapter, int frame_tag, -+ struct tx_desc *ptxdesc) -+{ -+ u8 dmp_txpkt; -+ bool dump_txdesc = false; -+ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(dmp_txpkt)); -+ -+ if (dmp_txpkt == 1) {/* dump txdesc for data frame */ -+ DBG_88E("dump tx_desc for data frame\n"); -+ if ((frame_tag & 0x0f) == DATA_FRAMETAG) -+ dump_txdesc = true; -+ } else if (dmp_txpkt == 2) {/* dump txdesc for mgnt frame */ -+ DBG_88E("dump tx_desc for mgnt frame\n"); -+ if ((frame_tag & 0x0f) == MGNT_FRAMETAG) -+ dump_txdesc = true; -+ } -+ -+ if (dump_txdesc) { -+ DBG_88E("=====================================\n"); -+ DBG_88E("txdw0(0x%08x)\n", ptxdesc->txdw0); -+ DBG_88E("txdw1(0x%08x)\n", ptxdesc->txdw1); -+ DBG_88E("txdw2(0x%08x)\n", ptxdesc->txdw2); -+ DBG_88E("txdw3(0x%08x)\n", ptxdesc->txdw3); -+ DBG_88E("txdw4(0x%08x)\n", ptxdesc->txdw4); -+ DBG_88E("txdw5(0x%08x)\n", ptxdesc->txdw5); -+ DBG_88E("txdw6(0x%08x)\n", ptxdesc->txdw6); -+ DBG_88E("txdw7(0x%08x)\n", ptxdesc->txdw7); -+ DBG_88E("=====================================\n"); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_led.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_led.c -new file mode 100644 -index 0000000000000..08dfd94163e6b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_led.c -@@ -0,0 +1,111 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+ -+#include -+#include -+#include -+#include -+ -+/* LED object. */ -+ -+/* LED_819xUsb routines. */ -+/* Description: */ -+/* Turn on LED according to LedPin specified. */ -+void SwLedOn(struct adapter *padapter, struct LED_871x *pLed) -+{ -+ u8 LedCfg; -+ -+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) -+ return; -+ LedCfg = rtw_read8(padapter, REG_LEDCFG2); -+ switch (pLed->LedPin) { -+ case LED_PIN_LED0: -+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0xf0)|BIT5|BIT6); /* SW control led0 on. */ -+ break; -+ case LED_PIN_LED1: -+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x0f)|BIT5); /* SW control led1 on. */ -+ break; -+ default: -+ break; -+ } -+ pLed->bLedOn = true; -+} -+ -+/* Description: */ -+/* Turn off LED according to LedPin specified. */ -+void SwLedOff(struct adapter *padapter, struct LED_871x *pLed) -+{ -+ u8 LedCfg; -+ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); -+ -+ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) -+ goto exit; -+ -+ LedCfg = rtw_read8(padapter, REG_LEDCFG2);/* 0x4E */ -+ -+ switch (pLed->LedPin) { -+ case LED_PIN_LED0: -+ if (pHalData->bLedOpenDrain) { -+ /* Open-drain arrangement for controlling the LED) */ -+ LedCfg &= 0x90; /* Set to software control. */ -+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3)); -+ LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG); -+ LedCfg &= 0xFE; -+ rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg); -+ } else { -+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3|BIT5|BIT6)); -+ } -+ break; -+ case LED_PIN_LED1: -+ LedCfg &= 0x0f; /* Set to software control. */ -+ rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3)); -+ break; -+ default: -+ break; -+ } -+exit: -+ pLed->bLedOn = false; -+} -+ -+/* Interface to manipulate LED objects. */ -+/* Default LED behavior. */ -+ -+/* Description: */ -+/* Initialize all LED_871x objects. */ -+void rtl8188eu_InitSwLeds(struct adapter *padapter) -+{ -+ struct led_priv *pledpriv = &(padapter->ledpriv); -+ -+ pledpriv->LedControlHandler = LedControl8188eu; -+ -+ InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0); -+ -+ InitLed871x(padapter, &(pledpriv->SwLed1), LED_PIN_LED1); -+} -+ -+/* Description: */ -+/* DeInitialize all LED_819xUsb objects. */ -+void rtl8188eu_DeInitSwLeds(struct adapter *padapter) -+{ -+ struct led_priv *ledpriv = &(padapter->ledpriv); -+ -+ DeInitLed871x(&(ledpriv->SwLed0)); -+ DeInitLed871x(&(ledpriv->SwLed1)); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_recv.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_recv.c -new file mode 100644 -index 0000000000000..ab0853ceeb61e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_recv.c -@@ -0,0 +1,136 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188EU_RECV_C_ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *precvbuf) -+{ -+ precvbuf->transfer_len = 0; -+ -+ precvbuf->len = 0; -+ -+ precvbuf->ref_cnt = 0; -+ -+ if (precvbuf->pbuf) { -+ precvbuf->pdata = precvbuf->pbuf; -+ precvbuf->phead = precvbuf->pbuf; -+ precvbuf->ptail = precvbuf->pbuf; -+ precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ; -+ } -+} -+ -+int rtl8188eu_init_recv_priv(struct adapter *padapter) -+{ -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ int i, res = _SUCCESS; -+ struct recv_buf *precvbuf; -+ -+ tasklet_init(&precvpriv->recv_tasklet, -+ (void(*)(unsigned long))rtl8188eu_recv_tasklet, -+ (unsigned long)padapter); -+ -+ /* init recv_buf */ -+ _rtw_init_queue(&precvpriv->free_recv_buf_queue); -+ -+ precvpriv->pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4); -+ if (precvpriv->pallocated_recv_buf == NULL) { -+ res = _FAIL; -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n")); -+ goto exit; -+ } -+ memset(precvpriv->pallocated_recv_buf, 0, NR_RECVBUFF * sizeof(struct recv_buf) + 4); -+ -+ precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_recv_buf), 4); -+ -+ precvbuf = (struct recv_buf *)precvpriv->precv_buf; -+ -+ for (i = 0; i < NR_RECVBUFF; i++) { -+ INIT_LIST_HEAD(&precvbuf->list); -+ spin_lock_init(&precvbuf->recvbuf_lock); -+ precvbuf->alloc_sz = MAX_RECVBUF_SZ; -+ res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); -+ if (res == _FAIL) -+ break; -+ precvbuf->ref_cnt = 0; -+ precvbuf->adapter = padapter; -+ precvbuf++; -+ } -+ precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; -+ skb_queue_head_init(&precvpriv->rx_skb_queue); -+ { -+ int i; -+ size_t tmpaddr = 0; -+ size_t alignment = 0; -+ struct sk_buff *pskb = NULL; -+ -+ skb_queue_head_init(&precvpriv->free_recv_skb_queue); -+ -+ for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) { -+ pskb = __netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ, GFP_KERNEL); -+ if (pskb) { -+ pskb->dev = padapter->pnetdev; -+ tmpaddr = (size_t)pskb->data; -+ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); -+ skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); -+ -+ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); -+ } -+ pskb = NULL; -+ } -+ } -+exit: -+ return res; -+} -+ -+void rtl8188eu_free_recv_priv(struct adapter *padapter) -+{ -+ int i; -+ struct recv_buf *precvbuf; -+ struct recv_priv *precvpriv = &padapter->recvpriv; -+ -+ precvbuf = (struct recv_buf *)precvpriv->precv_buf; -+ -+ for (i = 0; i < NR_RECVBUFF; i++) { -+ rtw_os_recvbuf_resource_free(padapter, precvbuf); -+ precvbuf++; -+ } -+ -+ kfree(precvpriv->pallocated_recv_buf); -+ -+ if (skb_queue_len(&precvpriv->rx_skb_queue)) -+ DBG_88E(KERN_WARNING "rx_skb_queue not empty\n"); -+ skb_queue_purge(&precvpriv->rx_skb_queue); -+ -+ if (skb_queue_len(&precvpriv->free_recv_skb_queue)) -+ DBG_88E(KERN_WARNING "free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue)); -+ -+ skb_queue_purge(&precvpriv->free_recv_skb_queue); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_xmit.c -new file mode 100644 -index 0000000000000..7f5d677b1d6fa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/rtl8188eu_xmit.c -@@ -0,0 +1,703 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _RTL8188E_XMIT_C_ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+s32 rtl8188eu_init_xmit_priv(struct adapter *adapt) -+{ -+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; -+ -+ tasklet_init(&pxmitpriv->xmit_tasklet, -+ (void(*)(unsigned long))rtl8188eu_xmit_tasklet, -+ (unsigned long)adapt); -+ return _SUCCESS; -+} -+ -+void rtl8188eu_free_xmit_priv(struct adapter *adapt) -+{ -+} -+ -+static u8 urb_zero_packet_chk(struct adapter *adapt, int sz) -+{ -+ u8 set_tx_desc_offset; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ set_tx_desc_offset = (((sz + TXDESC_SIZE) % haldata->UsbBulkOutSize) == 0) ? 1 : 0; -+ -+ return set_tx_desc_offset; -+} -+ -+static void rtl8188eu_cal_txdesc_chksum(struct tx_desc *ptxdesc) -+{ -+ u16 *usptr = (u16 *)ptxdesc; -+ u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */ -+ u32 index; -+ u16 checksum = 0; -+ -+ /* Clear first */ -+ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); -+ -+ for (index = 0; index < count; index++) -+ checksum = checksum ^ le16_to_cpu(*(__le16 *)(usptr + index)); -+ ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff & checksum); -+} -+ -+/* Description: In normal chip, we should send some packet to Hw which will be used by Fw */ -+/* in FW LPS mode. The function is to fill the Tx descriptor of this packets, then */ -+/* Fw can tell Hw to send these packet derectly. */ -+void rtl8188e_fill_fake_txdesc(struct adapter *adapt, u8 *desc, u32 BufferLen, u8 ispspoll, u8 is_btqosnull) -+{ -+ struct tx_desc *ptxdesc; -+ -+ /* Clear all status */ -+ ptxdesc = (struct tx_desc *)desc; -+ memset(desc, 0, TXDESC_SIZE); -+ -+ /* offset 0 */ -+ ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); /* own, bFirstSeg, bLastSeg; */ -+ -+ ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<txdw0 |= cpu_to_le32(BufferLen&0x0000ffff); /* Buffer size + command header */ -+ -+ /* offset 4 */ -+ ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT<txdw1 |= cpu_to_le32(NAVUSEHDR); -+ } else { -+ ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); /* Hw set sequence number */ -+ ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); /* set bit3 to 1. Suugested by TimChen. 2009.12.29. */ -+ } -+ -+ if (is_btqosnull) -+ ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); /* BT NULL */ -+ -+ /* offset 16 */ -+ ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ -+ -+ /* USB interface drop packet if the checksum of descriptor isn't correct. */ -+ /* Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). */ -+ rtl8188eu_cal_txdesc_chksum(ptxdesc); -+} -+ -+static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc) -+{ -+ if ((pattrib->encrypt > 0) && !pattrib->bswenc) { -+ switch (pattrib->encrypt) { -+ /* SEC_TYPE : 0:NO_ENC,1:WEP40/TKIP,2:WAPI,3:AES */ -+ case _WEP40_: -+ case _WEP104_: -+ ptxdesc->txdw1 |= cpu_to_le32((0x01<txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); -+ break; -+ case _TKIP_: -+ case _TKIP_WTMIC_: -+ ptxdesc->txdw1 |= cpu_to_le32((0x01<txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); -+ break; -+ case _AES_: -+ ptxdesc->txdw1 |= cpu_to_le32((0x03<txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); -+ break; -+ case _NO_PRIVACY_: -+ default: -+ break; -+ } -+ } -+} -+ -+static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw) -+{ -+ switch (pattrib->vcs_mode) { -+ case RTS_CTS: -+ *pdw |= cpu_to_le32(RTS_EN); -+ break; -+ case CTS_TO_SELF: -+ *pdw |= cpu_to_le32(CTS_2_SELF); -+ break; -+ case NONE_VCS: -+ default: -+ break; -+ } -+ if (pattrib->vcs_mode) { -+ *pdw |= cpu_to_le32(HW_RTS_EN); -+ /* Set RTS BW */ -+ if (pattrib->ht_en) { -+ *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0; -+ -+ if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) -+ *pdw |= cpu_to_le32((0x01 << 28) & 0x30000000); -+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) -+ *pdw |= cpu_to_le32((0x02 << 28) & 0x30000000); -+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) -+ *pdw |= 0; -+ else -+ *pdw |= cpu_to_le32((0x03 << 28) & 0x30000000); -+ } -+ } -+} -+ -+static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw) -+{ -+ if (pattrib->ht_en) { -+ *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0; -+ -+ if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) -+ *pdw |= cpu_to_le32((0x01 << DATA_SC_SHT) & 0x003f0000); -+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) -+ *pdw |= cpu_to_le32((0x02 << DATA_SC_SHT) & 0x003f0000); -+ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) -+ *pdw |= 0; -+ else -+ *pdw |= cpu_to_le32((0x03 << DATA_SC_SHT) & 0x003f0000); -+ } -+} -+ -+static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt) -+{ -+ int pull = 0; -+ uint qsel; -+ u8 data_rate, pwr_status, offset; -+ struct adapter *adapt = pxmitframe->padapter; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ struct tx_desc *ptxdesc = (struct tx_desc *)pmem; -+ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ int bmcst = IS_MCAST(pattrib->ra); -+ -+ if (adapt->registrypriv.mp_mode == 0) { -+ if ((!bagg_pkt) && (urb_zero_packet_chk(adapt, sz) == 0)) { -+ ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ); -+ pull = 1; -+ } -+ } -+ -+ memset(ptxdesc, 0, sizeof(struct tx_desc)); -+ -+ /* 4 offset 0 */ -+ ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); -+ ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff);/* update TXPKTSIZE */ -+ -+ offset = TXDESC_SIZE + OFFSET_SZ; -+ -+ ptxdesc->txdw0 |= cpu_to_le32(((offset) << OFFSET_SHT) & 0x00ff0000);/* 32 bytes for TX Desc */ -+ -+ if (bmcst) -+ ptxdesc->txdw0 |= cpu_to_le32(BMC); -+ -+ if (adapt->registrypriv.mp_mode == 0) { -+ if (!bagg_pkt) { -+ if ((pull) && (pxmitframe->pkt_offset > 0)) -+ pxmitframe->pkt_offset = pxmitframe->pkt_offset - 1; -+ } -+ } -+ -+ /* pkt_offset, unit:8 bytes padding */ -+ if (pxmitframe->pkt_offset > 0) -+ ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000); -+ -+ /* driver uses rate */ -+ ptxdesc->txdw4 |= cpu_to_le32(USERATE);/* rate control always by driver */ -+ -+ if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) { -+ /* offset 4 */ -+ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3F); -+ -+ qsel = (uint)(pattrib->qsel & 0x0000001f); -+ ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); -+ -+ ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); -+ -+ fill_txdesc_sectype(pattrib, ptxdesc); -+ -+ if (pattrib->ampdu_en) { -+ ptxdesc->txdw2 |= cpu_to_le32(AGG_EN);/* AGG EN */ -+ ptxdesc->txdw6 = cpu_to_le32(0x6666f800); -+ } else { -+ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */ -+ } -+ -+ /* offset 8 */ -+ -+ /* offset 12 */ -+ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0FFF0000); -+ -+ /* offset 16 , offset 20 */ -+ if (pattrib->qos_en) -+ ptxdesc->txdw4 |= cpu_to_le32(QOS);/* QoS */ -+ -+ /* offset 20 */ -+ if (pxmitframe->agg_num > 1) -+ ptxdesc->txdw5 |= cpu_to_le32((pxmitframe->agg_num << USB_TXAGG_NUM_SHT) & 0xFF000000); -+ -+ if ((pattrib->ether_type != 0x888e) && -+ (pattrib->ether_type != 0x0806) && -+ (pattrib->ether_type != 0x88b4) && -+ (pattrib->dhcp_pkt != 1)) { -+ /* Non EAP & ARP & DHCP type data packet */ -+ -+ fill_txdesc_vcs(pattrib, &ptxdesc->txdw4); -+ fill_txdesc_phy(pattrib, &ptxdesc->txdw4); -+ -+ ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate=24M */ -+ ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/* DATA/RTS Rate FB LMT */ -+ -+ if (pattrib->ht_en) { -+ if (ODM_RA_GetShortGI_8188E(&haldata->odmpriv, pattrib->mac_id)) -+ ptxdesc->txdw5 |= cpu_to_le32(SGI);/* SGI */ -+ } -+ data_rate = ODM_RA_GetDecisionRate_8188E(&haldata->odmpriv, pattrib->mac_id); -+ ptxdesc->txdw5 |= cpu_to_le32(data_rate & 0x3F); -+ pwr_status = ODM_RA_GetHwPwrStatus_8188E(&haldata->odmpriv, pattrib->mac_id); -+ ptxdesc->txdw4 |= cpu_to_le32((pwr_status & 0x7) << PWR_STATUS_SHT); -+ } else { -+ /* EAP data packet and ARP packet and DHCP. */ -+ /* Use the 1M data rate to send the EAP/ARP packet. */ -+ /* This will maybe make the handshake smooth. */ -+ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */ -+ if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) -+ ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/* DATA_SHORT */ -+ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); -+ } -+ } else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) { -+ /* offset 4 */ -+ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3f); -+ -+ qsel = (uint)(pattrib->qsel&0x0000001f); -+ ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); -+ -+ ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000f0000); -+ -+ /* offset 8 */ -+ /* CCX-TXRPT ack for xmit mgmt frames. */ -+ if (pxmitframe->ack_report) -+ ptxdesc->txdw2 |= cpu_to_le32(BIT(19)); -+ -+ /* offset 12 */ -+ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<txdw5 |= cpu_to_le32(RTY_LMT_EN);/* retry limit enable */ -+ if (pattrib->retry_ctrl) -+ ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */ -+ else -+ ptxdesc->txdw5 |= cpu_to_le32(0x00300000);/* retry limit = 12 */ -+ -+ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); -+ } else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) { -+ DBG_88E("pxmitframe->frame_tag == TXAGG_FRAMETAG\n"); -+ } else if (((pxmitframe->frame_tag&0x0f) == MP_FRAMETAG) && -+ (adapt->registrypriv.mp_mode == 1)) { -+ fill_txdesc_for_mp(adapt, ptxdesc); -+ } else { -+ DBG_88E("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag); -+ -+ /* offset 4 */ -+ ptxdesc->txdw1 |= cpu_to_le32((4) & 0x3f);/* CAM_ID(MAC_ID) */ -+ -+ ptxdesc->txdw1 |= cpu_to_le32((6 << RATE_ID_SHT) & 0x000f0000);/* raid */ -+ -+ /* offset 8 */ -+ -+ /* offset 12 */ -+ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); -+ } -+ -+ /* 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */ -+ /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */ -+ /* mgnt frame should be controlled by Hw because Fw will also send null data */ -+ /* which we cannot control when Fw LPS enable. */ -+ /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */ -+ /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */ -+ /* (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */ -+ /* 2010.06.23. Added by tynli. */ -+ if (!pattrib->qos_en) { -+ ptxdesc->txdw3 |= cpu_to_le32(EN_HWSEQ); /* Hw set sequence number */ -+ ptxdesc->txdw4 |= cpu_to_le32(HW_SSN); /* Hw set sequence number */ -+ } -+ -+ ODM_SetTxAntByTxInfo_88E(&haldata->odmpriv, pmem, pattrib->mac_id); -+ -+ rtl8188eu_cal_txdesc_chksum(ptxdesc); -+ _dbg_dump_tx_info(adapt, pxmitframe->frame_tag, ptxdesc); -+ return pull; -+} -+ -+/* for non-agg data frame or management frame */ -+static s32 rtw_dump_xframe(struct adapter *adapt, struct xmit_frame *pxmitframe) -+{ -+ s32 ret = _SUCCESS; -+ s32 inner_ret = _SUCCESS; -+ int t, sz, w_sz, pull = 0; -+ u8 *mem_addr; -+ u32 ff_hwaddr; -+ struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; -+ struct security_priv *psecuritypriv = &adapt->securitypriv; -+ if ((pxmitframe->frame_tag == DATA_FRAMETAG) && -+ (pxmitframe->attrib.ether_type != 0x0806) && -+ (pxmitframe->attrib.ether_type != 0x888e) && -+ (pxmitframe->attrib.ether_type != 0x88b4) && -+ (pxmitframe->attrib.dhcp_pkt != 1)) -+ rtw_issue_addbareq_cmd(adapt, pxmitframe); -+ mem_addr = pxmitframe->buf_addr; -+ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_dump_xframe()\n")); -+ -+ for (t = 0; t < pattrib->nr_frags; t++) { -+ if (inner_ret != _SUCCESS && ret == _SUCCESS) -+ ret = _FAIL; -+ -+ if (t != (pattrib->nr_frags - 1)) { -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("pattrib->nr_frags=%d\n", pattrib->nr_frags)); -+ -+ sz = pxmitpriv->frag_len; -+ sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : pattrib->icv_len); -+ } else { -+ /* no frag */ -+ sz = pattrib->last_txcmdsz; -+ } -+ -+ pull = update_txdesc(pxmitframe, mem_addr, sz, false); -+ -+ if (pull) { -+ mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */ -+ pxmitframe->buf_addr = mem_addr; -+ w_sz = sz + TXDESC_SIZE; -+ } else { -+ w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ; -+ } -+ ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); -+ -+ inner_ret = rtw_write_port(adapt, ff_hwaddr, w_sz, (unsigned char *)pxmitbuf); -+ -+ rtw_count_tx_stats(adapt, pxmitframe, sz); -+ -+ RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_write_port, w_sz=%d\n", w_sz)); -+ -+ mem_addr += w_sz; -+ -+ mem_addr = (u8 *)RND4(((size_t)(mem_addr))); -+ } -+ -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ -+ if (ret != _SUCCESS) -+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); -+ -+ return ret; -+} -+ -+static u32 xmitframe_need_length(struct xmit_frame *pxmitframe) -+{ -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ -+ u32 len = 0; -+ -+ /* no consider fragement */ -+ len = pattrib->hdrlen + pattrib->iv_len + -+ SNAP_SIZE + sizeof(u16) + -+ pattrib->pktlen + -+ ((pattrib->bswenc) ? pattrib->icv_len : 0); -+ -+ if (pattrib->encrypt == _TKIP_) -+ len += 8; -+ -+ return len; -+} -+ -+s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ struct xmit_frame *pxmitframe = NULL; -+ struct xmit_frame *pfirstframe = NULL; -+ -+ /* aggregate variable */ -+ struct hw_xmit *phwxmit; -+ struct sta_info *psta = NULL; -+ struct tx_servq *ptxservq = NULL; -+ struct list_head *xmitframe_plist = NULL, *xmitframe_phead = NULL; -+ -+ u32 pbuf; /* next pkt address */ -+ u32 pbuf_tail; /* last pkt tail */ -+ u32 len; /* packet length, except TXDESC_SIZE and PKT_OFFSET */ -+ -+ u32 bulksize = haldata->UsbBulkOutSize; -+ u8 desc_cnt; -+ u32 bulkptr; -+ -+ /* dump frame variable */ -+ u32 ff_hwaddr; -+ -+ RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n")); -+ -+ /* check xmitbuffer is ok */ -+ if (pxmitbuf == NULL) { -+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); -+ if (pxmitbuf == NULL) -+ return false; -+ } -+ -+ /* 3 1. pick up first frame */ -+ do { -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ -+ pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); -+ if (pxmitframe == NULL) { -+ /* no more xmit frame, release xmit buffer */ -+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); -+ return false; -+ } -+ -+ pxmitframe->pxmitbuf = pxmitbuf; -+ pxmitframe->buf_addr = pxmitbuf->pbuf; -+ pxmitbuf->priv_data = pxmitframe; -+ -+ pxmitframe->agg_num = 1; /* alloc xmitframe should assign to 1. */ -+ pxmitframe->pkt_offset = 1; /* first frame of aggregation, reserve offset */ -+ -+ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); -+ -+ /* always return ndis_packet after rtw_xmitframe_coalesce */ -+ rtw_os_xmit_complete(adapt, pxmitframe); -+ -+ break; -+ } while (1); -+ -+ /* 3 2. aggregate same priority and same DA(AP or STA) frames */ -+ pfirstframe = pxmitframe; -+ len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE + (pfirstframe->pkt_offset*PACKET_OFFSET_SZ); -+ pbuf_tail = len; -+ pbuf = _RND8(pbuf_tail); -+ -+ /* check pkt amount in one bulk */ -+ desc_cnt = 0; -+ bulkptr = bulksize; -+ if (pbuf < bulkptr) { -+ desc_cnt++; -+ } else { -+ desc_cnt = 0; -+ bulkptr = ((pbuf / bulksize) + 1) * bulksize; /* round to next bulksize */ -+ } -+ -+ /* dequeue same priority packet from station tx queue */ -+ psta = pfirstframe->attrib.psta; -+ switch (pfirstframe->attrib.priority) { -+ case 1: -+ case 2: -+ ptxservq = &(psta->sta_xmitpriv.bk_q); -+ phwxmit = pxmitpriv->hwxmits + 3; -+ break; -+ case 4: -+ case 5: -+ ptxservq = &(psta->sta_xmitpriv.vi_q); -+ phwxmit = pxmitpriv->hwxmits + 1; -+ break; -+ case 6: -+ case 7: -+ ptxservq = &(psta->sta_xmitpriv.vo_q); -+ phwxmit = pxmitpriv->hwxmits; -+ break; -+ case 0: -+ case 3: -+ default: -+ ptxservq = &(psta->sta_xmitpriv.be_q); -+ phwxmit = pxmitpriv->hwxmits + 2; -+ break; -+ } -+ spin_lock_bh(&pxmitpriv->lock); -+ -+ xmitframe_phead = get_list_head(&ptxservq->sta_pending); -+ xmitframe_plist = xmitframe_phead->next; -+ -+ while (xmitframe_phead != xmitframe_plist) { -+ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); -+ xmitframe_plist = xmitframe_plist->next; -+ -+ pxmitframe->agg_num = 0; /* not first frame of aggregation */ -+ pxmitframe->pkt_offset = 0; /* not first frame of aggregation, no need to reserve offset */ -+ -+ len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + (pxmitframe->pkt_offset*PACKET_OFFSET_SZ); -+ -+ if (_RND8(pbuf + len) > MAX_XMITBUF_SZ) { -+ pxmitframe->agg_num = 1; -+ pxmitframe->pkt_offset = 1; -+ break; -+ } -+ list_del_init(&pxmitframe->list); -+ ptxservq->qcnt--; -+ phwxmit->accnt--; -+ -+ pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; -+ -+ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); -+ /* always return ndis_packet after rtw_xmitframe_coalesce */ -+ rtw_os_xmit_complete(adapt, pxmitframe); -+ -+ /* (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz */ -+ update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz, true); -+ -+ /* don't need xmitframe any more */ -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ -+ /* handle pointer and stop condition */ -+ pbuf_tail = pbuf + len; -+ pbuf = _RND8(pbuf_tail); -+ -+ pfirstframe->agg_num++; -+ if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num) -+ break; -+ -+ if (pbuf < bulkptr) { -+ desc_cnt++; -+ if (desc_cnt == haldata->UsbTxAggDescNum) -+ break; -+ } else { -+ desc_cnt = 0; -+ bulkptr = ((pbuf / bulksize) + 1) * bulksize; -+ } -+ } /* end while (aggregate same priority and same DA(AP or STA) frames) */ -+ -+ if (list_empty(&ptxservq->sta_pending.queue)) -+ list_del_init(&ptxservq->tx_pending); -+ -+ spin_unlock_bh(&pxmitpriv->lock); -+ if ((pfirstframe->attrib.ether_type != 0x0806) && -+ (pfirstframe->attrib.ether_type != 0x888e) && -+ (pfirstframe->attrib.ether_type != 0x88b4) && -+ (pfirstframe->attrib.dhcp_pkt != 1)) -+ rtw_issue_addbareq_cmd(adapt, pfirstframe); -+ /* 3 3. update first frame txdesc */ -+ if ((pbuf_tail % bulksize) == 0) { -+ /* remove pkt_offset */ -+ pbuf_tail -= PACKET_OFFSET_SZ; -+ pfirstframe->buf_addr += PACKET_OFFSET_SZ; -+ pfirstframe->pkt_offset--; -+ } -+ -+ update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz, true); -+ -+ /* 3 4. write xmit buffer to USB FIFO */ -+ ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe); -+ rtw_write_port(adapt, ff_hwaddr, pbuf_tail, (u8 *)pxmitbuf); -+ -+ /* 3 5. update statisitc */ -+ pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE); -+ pbuf_tail -= (pfirstframe->pkt_offset * PACKET_OFFSET_SZ); -+ -+ rtw_count_tx_stats(adapt, pfirstframe, pbuf_tail); -+ -+ rtw_free_xmitframe(pxmitpriv, pfirstframe); -+ -+ return true; -+} -+ -+static s32 xmitframe_direct(struct adapter *adapt, struct xmit_frame *pxmitframe) -+{ -+ s32 res = _SUCCESS; -+ -+ res = rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); -+ if (res == _SUCCESS) -+ rtw_dump_xframe(adapt, pxmitframe); -+ else -+ DBG_88E("==> %s xmitframe_coalsece failed\n", __func__); -+ return res; -+} -+ -+/* -+ * Return -+ * true dump packet directly -+ * false enqueue packet -+ */ -+static s32 pre_xmitframe(struct adapter *adapt, struct xmit_frame *pxmitframe) -+{ -+ s32 res; -+ struct xmit_buf *pxmitbuf = NULL; -+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; -+ struct pkt_attrib *pattrib = &pxmitframe->attrib; -+ struct mlme_priv *pmlmepriv = &adapt->mlmepriv; -+ -+ spin_lock_bh(&pxmitpriv->lock); -+ -+ if (rtw_txframes_sta_ac_pending(adapt, pattrib) > 0) -+ goto enqueue; -+ -+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) -+ goto enqueue; -+ -+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); -+ if (pxmitbuf == NULL) -+ goto enqueue; -+ -+ spin_unlock_bh(&pxmitpriv->lock); -+ -+ pxmitframe->pxmitbuf = pxmitbuf; -+ pxmitframe->buf_addr = pxmitbuf->pbuf; -+ pxmitbuf->priv_data = pxmitframe; -+ -+ if (xmitframe_direct(adapt, pxmitframe) != _SUCCESS) { -+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ } -+ -+ return true; -+ -+enqueue: -+ res = rtw_xmitframe_enqueue(adapt, pxmitframe); -+ spin_unlock_bh(&pxmitpriv->lock); -+ -+ if (res != _SUCCESS) { -+ RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n")); -+ rtw_free_xmitframe(pxmitpriv, pxmitframe); -+ -+ /* Trick, make the statistics correct */ -+ pxmitpriv->tx_pkts--; -+ pxmitpriv->tx_drop++; -+ return true; -+ } -+ -+ return false; -+} -+ -+s32 rtl8188eu_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe) -+{ -+ return rtw_dump_xframe(adapt, pmgntframe); -+} -+ -+/* -+ * Return -+ * true dump packet directly ok -+ * false temporary can't transmit packets to hardware -+ */ -+s32 rtl8188eu_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe) -+{ -+ return pre_xmitframe(adapt, pxmitframe); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/usb_halinit.c b/drivers/net/wireless/rtl8188eu/hal/usb_halinit.c -new file mode 100644 -index 0000000000000..8ae7fd7b3a584 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/usb_halinit.c -@@ -0,0 +1,2333 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _HCI_HAL_INIT_C_ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define HAL_MAC_ENABLE 1 -+#define HAL_BB_ENABLE 1 -+#define HAL_RF_ENABLE 1 -+ -+static void _ConfigNormalChipOutEP_8188E(struct adapter *adapt, u8 NumOutPipe) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ -+ switch (NumOutPipe) { -+ case 3: -+ haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ | TX_SELE_NQ; -+ haldata->OutEpNumber = 3; -+ break; -+ case 2: -+ haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_NQ; -+ haldata->OutEpNumber = 2; -+ break; -+ case 1: -+ haldata->OutEpQueueSel = TX_SELE_HQ; -+ haldata->OutEpNumber = 1; -+ break; -+ default: -+ break; -+ } -+ DBG_88E("%s OutEpQueueSel(0x%02x), OutEpNumber(%d)\n", __func__, haldata->OutEpQueueSel, haldata->OutEpNumber); -+} -+ -+static bool HalUsbSetQueuePipeMapping8188EUsb(struct adapter *adapt, u8 NumInPipe, u8 NumOutPipe) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ bool result = false; -+ -+ _ConfigNormalChipOutEP_8188E(adapt, NumOutPipe); -+ -+ /* Normal chip with one IN and one OUT doesn't have interrupt IN EP. */ -+ if (1 == haldata->OutEpNumber) { -+ if (1 != NumInPipe) -+ return result; -+ } -+ -+ /* All config other than above support one Bulk IN and one Interrupt IN. */ -+ -+ result = Hal_MappingOutPipe(adapt, NumOutPipe); -+ -+ return result; -+} -+ -+static void rtl8188eu_interface_configure(struct adapter *adapt) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapt); -+ -+ if (pdvobjpriv->ishighspeed) -+ haldata->UsbBulkOutSize = USB_HIGH_SPEED_BULK_SIZE;/* 512 bytes */ -+ else -+ haldata->UsbBulkOutSize = USB_FULL_SPEED_BULK_SIZE;/* 64 bytes */ -+ -+ haldata->interfaceIndex = pdvobjpriv->InterfaceNumber; -+ -+ haldata->UsbTxAggMode = 1; -+ haldata->UsbTxAggDescNum = 0x6; /* only 4 bits */ -+ -+ haldata->UsbRxAggMode = USB_RX_AGG_DMA;/* USB_RX_AGG_DMA; */ -+ haldata->UsbRxAggBlockCount = 8; /* unit : 512b */ -+ haldata->UsbRxAggBlockTimeout = 0x6; -+ haldata->UsbRxAggPageCount = 48; /* uint :128 b 0x0A; 10 = MAX_RX_DMA_BUFFER_SIZE/2/haldata->UsbBulkOutSize */ -+ haldata->UsbRxAggPageTimeout = 0x4; /* 6, absolute time = 34ms/(2^6) */ -+ -+ HalUsbSetQueuePipeMapping8188EUsb(adapt, -+ pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes); -+} -+ -+static u32 rtl8188eu_InitPowerOn(struct adapter *adapt) -+{ -+ u16 value16; -+ /* HW Power on sequence */ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ if (haldata->bMacPwrCtrlOn) -+ return _SUCCESS; -+ -+ if (!HalPwrSeqCmdParsing(adapt, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_PWR_ON_FLOW)) { -+ DBG_88E(KERN_ERR "%s: run power on flow fail\n", __func__); -+ return _FAIL; -+ } -+ -+ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ -+ /* Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */ -+ rtw_write16(adapt, REG_CR, 0x00); /* suggseted by zhouzhou, by page, 20111230 */ -+ -+ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ -+ value16 = rtw_read16(adapt, REG_CR); -+ value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN -+ | PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN); -+ /* for SDIO - Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */ -+ -+ rtw_write16(adapt, REG_CR, value16); -+ haldata->bMacPwrCtrlOn = true; -+ -+ return _SUCCESS; -+} -+ -+/* Shall USB interface init this? */ -+static void _InitInterrupt(struct adapter *Adapter) -+{ -+ u32 imr, imr_ex; -+ u8 usb_opt; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ /* HISR write one to clear */ -+ rtw_write32(Adapter, REG_HISR_88E, 0xFFFFFFFF); -+ /* HIMR - */ -+ imr = IMR_PSTIMEOUT_88E | IMR_TBDER_88E | IMR_CPWM_88E | IMR_CPWM2_88E; -+ rtw_write32(Adapter, REG_HIMR_88E, imr); -+ haldata->IntrMask[0] = imr; -+ -+ imr_ex = IMR_TXERR_88E | IMR_RXERR_88E | IMR_TXFOVW_88E | IMR_RXFOVW_88E; -+ rtw_write32(Adapter, REG_HIMRE_88E, imr_ex); -+ haldata->IntrMask[1] = imr_ex; -+ -+ /* REG_USB_SPECIAL_OPTION - BIT(4) */ -+ /* 0; Use interrupt endpoint to upload interrupt pkt */ -+ /* 1; Use bulk endpoint to upload interrupt pkt, */ -+ usb_opt = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); -+ -+ if (!adapter_to_dvobj(Adapter)->ishighspeed) -+ usb_opt = usb_opt & (~INT_BULK_SEL); -+ else -+ usb_opt = usb_opt | (INT_BULK_SEL); -+ -+ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, usb_opt); -+} -+ -+static void _InitQueueReservedPage(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ struct registry_priv *pregistrypriv = &Adapter->registrypriv; -+ u32 numHQ = 0; -+ u32 numLQ = 0; -+ u32 numNQ = 0; -+ u32 numPubQ; -+ u32 value32; -+ u8 value8; -+ bool bWiFiConfig = pregistrypriv->wifi_spec; -+ -+ if (bWiFiConfig) { -+ if (haldata->OutEpQueueSel & TX_SELE_HQ) -+ numHQ = 0x29; -+ -+ if (haldata->OutEpQueueSel & TX_SELE_LQ) -+ numLQ = 0x1C; -+ -+ /* NOTE: This step shall be proceed before writting REG_RQPN. */ -+ if (haldata->OutEpQueueSel & TX_SELE_NQ) -+ numNQ = 0x1C; -+ value8 = (u8)_NPQ(numNQ); -+ rtw_write8(Adapter, REG_RQPN_NPQ, value8); -+ -+ numPubQ = 0xA8 - numHQ - numLQ - numNQ; -+ -+ /* TX DMA */ -+ value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN; -+ rtw_write32(Adapter, REG_RQPN, value32); -+ } else { -+ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0000);/* Just follow MP Team,??? Georgia 03/28 */ -+ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0d); -+ rtw_write32(Adapter, REG_RQPN, 0x808E000d);/* reserve 7 page for LPS */ -+ } -+} -+ -+static void _InitTxBufferBoundary(struct adapter *Adapter, u8 txpktbuf_bndy) -+{ -+ rtw_write8(Adapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); -+ rtw_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); -+ rtw_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy); -+ rtw_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy); -+ rtw_write8(Adapter, REG_TDECTRL+1, txpktbuf_bndy); -+} -+ -+static void _InitPageBoundary(struct adapter *Adapter) -+{ -+ /* RX Page Boundary */ -+ /* */ -+ u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E-1; -+ -+ rtw_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); -+} -+ -+static void _InitNormalChipRegPriority(struct adapter *Adapter, u16 beQ, -+ u16 bkQ, u16 viQ, u16 voQ, u16 mgtQ, -+ u16 hiQ) -+{ -+ u16 value16 = (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7); -+ -+ value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | -+ _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | -+ _TXDMA_MGQ_MAP(mgtQ) | _TXDMA_HIQ_MAP(hiQ); -+ -+ rtw_write16(Adapter, REG_TRXDMA_CTRL, value16); -+} -+ -+static void _InitNormalChipOneOutEpPriority(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ u16 value = 0; -+ switch (haldata->OutEpQueueSel) { -+ case TX_SELE_HQ: -+ value = QUEUE_HIGH; -+ break; -+ case TX_SELE_LQ: -+ value = QUEUE_LOW; -+ break; -+ case TX_SELE_NQ: -+ value = QUEUE_NORMAL; -+ break; -+ default: -+ break; -+ } -+ _InitNormalChipRegPriority(Adapter, value, value, value, value, -+ value, value); -+} -+ -+static void _InitNormalChipTwoOutEpPriority(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ struct registry_priv *pregistrypriv = &Adapter->registrypriv; -+ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; -+ u16 valueHi = 0; -+ u16 valueLow = 0; -+ -+ switch (haldata->OutEpQueueSel) { -+ case (TX_SELE_HQ | TX_SELE_LQ): -+ valueHi = QUEUE_HIGH; -+ valueLow = QUEUE_LOW; -+ break; -+ case (TX_SELE_NQ | TX_SELE_LQ): -+ valueHi = QUEUE_NORMAL; -+ valueLow = QUEUE_LOW; -+ break; -+ case (TX_SELE_HQ | TX_SELE_NQ): -+ valueHi = QUEUE_HIGH; -+ valueLow = QUEUE_NORMAL; -+ break; -+ default: -+ break; -+ } -+ -+ if (!pregistrypriv->wifi_spec) { -+ beQ = valueLow; -+ bkQ = valueLow; -+ viQ = valueHi; -+ voQ = valueHi; -+ mgtQ = valueHi; -+ hiQ = valueHi; -+ } else {/* for WMM ,CONFIG_OUT_EP_WIFI_MODE */ -+ beQ = valueLow; -+ bkQ = valueHi; -+ viQ = valueHi; -+ voQ = valueLow; -+ mgtQ = valueHi; -+ hiQ = valueHi; -+ } -+ _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); -+} -+ -+static void _InitNormalChipThreeOutEpPriority(struct adapter *Adapter) -+{ -+ struct registry_priv *pregistrypriv = &Adapter->registrypriv; -+ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; -+ -+ if (!pregistrypriv->wifi_spec) {/* typical setting */ -+ beQ = QUEUE_LOW; -+ bkQ = QUEUE_LOW; -+ viQ = QUEUE_NORMAL; -+ voQ = QUEUE_HIGH; -+ mgtQ = QUEUE_HIGH; -+ hiQ = QUEUE_HIGH; -+ } else {/* for WMM */ -+ beQ = QUEUE_LOW; -+ bkQ = QUEUE_NORMAL; -+ viQ = QUEUE_NORMAL; -+ voQ = QUEUE_HIGH; -+ mgtQ = QUEUE_HIGH; -+ hiQ = QUEUE_HIGH; -+ } -+ _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); -+} -+ -+static void _InitQueuePriority(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ switch (haldata->OutEpNumber) { -+ case 1: -+ _InitNormalChipOneOutEpPriority(Adapter); -+ break; -+ case 2: -+ _InitNormalChipTwoOutEpPriority(Adapter); -+ break; -+ case 3: -+ _InitNormalChipThreeOutEpPriority(Adapter); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void _InitNetworkType(struct adapter *Adapter) -+{ -+ u32 value32; -+ -+ value32 = rtw_read32(Adapter, REG_CR); -+ /* TODO: use the other function to set network type */ -+ value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP); -+ -+ rtw_write32(Adapter, REG_CR, value32); -+} -+ -+static void _InitTransferPageSize(struct adapter *Adapter) -+{ -+ /* Tx page size is always 128. */ -+ -+ u8 value8; -+ value8 = _PSRX(PBP_128) | _PSTX(PBP_128); -+ rtw_write8(Adapter, REG_PBP, value8); -+} -+ -+static void _InitDriverInfoSize(struct adapter *Adapter, u8 drvInfoSize) -+{ -+ rtw_write8(Adapter, REG_RX_DRVINFO_SZ, drvInfoSize); -+} -+ -+static void _InitWMACSetting(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ haldata->ReceiveConfig = RCR_AAP | RCR_APM | RCR_AM | RCR_AB | -+ RCR_CBSSID_DATA | RCR_CBSSID_BCN | -+ RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | -+ RCR_APP_MIC | RCR_APP_PHYSTS; -+ -+ /* some REG_RCR will be modified later by phy_ConfigMACWithHeaderFile() */ -+ rtw_write32(Adapter, REG_RCR, haldata->ReceiveConfig); -+ -+ /* Accept all multicast address */ -+ rtw_write32(Adapter, REG_MAR, 0xFFFFFFFF); -+ rtw_write32(Adapter, REG_MAR + 4, 0xFFFFFFFF); -+} -+ -+static void _InitAdaptiveCtrl(struct adapter *Adapter) -+{ -+ u16 value16; -+ u32 value32; -+ -+ /* Response Rate Set */ -+ value32 = rtw_read32(Adapter, REG_RRSR); -+ value32 &= ~RATE_BITMAP_ALL; -+ value32 |= RATE_RRSR_CCK_ONLY_1M; -+ rtw_write32(Adapter, REG_RRSR, value32); -+ -+ /* CF-END Threshold */ -+ -+ /* SIFS (used in NAV) */ -+ value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); -+ rtw_write16(Adapter, REG_SPEC_SIFS, value16); -+ -+ /* Retry Limit */ -+ value16 = _LRL(0x30) | _SRL(0x30); -+ rtw_write16(Adapter, REG_RL, value16); -+} -+ -+static void _InitEDCA(struct adapter *Adapter) -+{ -+ /* Set Spec SIFS (used in NAV) */ -+ rtw_write16(Adapter, REG_SPEC_SIFS, 0x100a); -+ rtw_write16(Adapter, REG_MAC_SPEC_SIFS, 0x100a); -+ -+ /* Set SIFS for CCK */ -+ rtw_write16(Adapter, REG_SIFS_CTX, 0x100a); -+ -+ /* Set SIFS for OFDM */ -+ rtw_write16(Adapter, REG_SIFS_TRX, 0x100a); -+ -+ /* TXOP */ -+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, 0x005EA42B); -+ rtw_write32(Adapter, REG_EDCA_BK_PARAM, 0x0000A44F); -+ rtw_write32(Adapter, REG_EDCA_VI_PARAM, 0x005EA324); -+ rtw_write32(Adapter, REG_EDCA_VO_PARAM, 0x002FA226); -+} -+ -+static void _InitBeaconMaxError(struct adapter *Adapter, bool InfraMode) -+{ -+} -+ -+static void _InitHWLed(struct adapter *Adapter) -+{ -+ struct led_priv *pledpriv = &(Adapter->ledpriv); -+ -+ if (pledpriv->LedStrategy != HW_LED) -+ return; -+ -+/* HW led control */ -+/* to do .... */ -+/* must consider cases of antenna diversity/ commbo card/solo card/mini card */ -+} -+ -+static void _InitRDGSetting(struct adapter *Adapter) -+{ -+ rtw_write8(Adapter, REG_RD_CTRL, 0xFF); -+ rtw_write16(Adapter, REG_RD_NAV_NXT, 0x200); -+ rtw_write8(Adapter, REG_RD_RESP_PKT_TH, 0x05); -+} -+ -+static void _InitRxSetting(struct adapter *Adapter) -+{ -+ rtw_write32(Adapter, REG_MACID, 0x87654321); -+ rtw_write32(Adapter, 0x0700, 0x87654321); -+} -+ -+static void _InitRetryFunction(struct adapter *Adapter) -+{ -+ u8 value8; -+ -+ value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL); -+ value8 |= EN_AMPDU_RTY_NEW; -+ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8); -+ -+ /* Set ACK timeout */ -+ rtw_write8(Adapter, REG_ACKTO, 0x40); -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: usb_AggSettingTxUpdate() -+ * -+ * Overview: Separate TX/RX parameters update independent for TP detection and -+ * dynamic TX/RX aggreagtion parameters update. -+ * -+ * Input: struct adapter * -+ * -+ * Output/Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 12/10/2010 MHC Separate to smaller function. -+ * -+ *---------------------------------------------------------------------------*/ -+static void usb_AggSettingTxUpdate(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ u32 value32; -+ -+ if (Adapter->registrypriv.wifi_spec) -+ haldata->UsbTxAggMode = false; -+ -+ if (haldata->UsbTxAggMode) { -+ value32 = rtw_read32(Adapter, REG_TDECTRL); -+ value32 = value32 & ~(BLK_DESC_NUM_MASK << BLK_DESC_NUM_SHIFT); -+ value32 |= ((haldata->UsbTxAggDescNum & BLK_DESC_NUM_MASK) << BLK_DESC_NUM_SHIFT); -+ -+ rtw_write32(Adapter, REG_TDECTRL, value32); -+ } -+} /* usb_AggSettingTxUpdate */ -+ -+/*----------------------------------------------------------------------------- -+ * Function: usb_AggSettingRxUpdate() -+ * -+ * Overview: Separate TX/RX parameters update independent for TP detection and -+ * dynamic TX/RX aggreagtion parameters update. -+ * -+ * Input: struct adapter * -+ * -+ * Output/Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 12/10/2010 MHC Separate to smaller function. -+ * -+ *---------------------------------------------------------------------------*/ -+static void -+usb_AggSettingRxUpdate( -+ struct adapter *Adapter -+ ) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ u8 valueDMA; -+ u8 valueUSB; -+ -+ valueDMA = rtw_read8(Adapter, REG_TRXDMA_CTRL); -+ valueUSB = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); -+ -+ switch (haldata->UsbRxAggMode) { -+ case USB_RX_AGG_DMA: -+ valueDMA |= RXDMA_AGG_EN; -+ valueUSB &= ~USB_AGG_EN; -+ break; -+ case USB_RX_AGG_USB: -+ valueDMA &= ~RXDMA_AGG_EN; -+ valueUSB |= USB_AGG_EN; -+ break; -+ case USB_RX_AGG_MIX: -+ valueDMA |= RXDMA_AGG_EN; -+ valueUSB |= USB_AGG_EN; -+ break; -+ case USB_RX_AGG_DISABLE: -+ default: -+ valueDMA &= ~RXDMA_AGG_EN; -+ valueUSB &= ~USB_AGG_EN; -+ break; -+ } -+ -+ rtw_write8(Adapter, REG_TRXDMA_CTRL, valueDMA); -+ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, valueUSB); -+ -+ switch (haldata->UsbRxAggMode) { -+ case USB_RX_AGG_DMA: -+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount); -+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, haldata->UsbRxAggPageTimeout); -+ break; -+ case USB_RX_AGG_USB: -+ rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount); -+ rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout); -+ break; -+ case USB_RX_AGG_MIX: -+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount); -+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, (haldata->UsbRxAggPageTimeout & 0x1F));/* 0x280[12:8] */ -+ rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount); -+ rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout); -+ break; -+ case USB_RX_AGG_DISABLE: -+ default: -+ /* TODO: */ -+ break; -+ } -+ -+ switch (PBP_128) { -+ case PBP_128: -+ haldata->HwRxPageSize = 128; -+ break; -+ case PBP_64: -+ haldata->HwRxPageSize = 64; -+ break; -+ case PBP_256: -+ haldata->HwRxPageSize = 256; -+ break; -+ case PBP_512: -+ haldata->HwRxPageSize = 512; -+ break; -+ case PBP_1024: -+ haldata->HwRxPageSize = 1024; -+ break; -+ default: -+ break; -+ } -+} /* usb_AggSettingRxUpdate */ -+ -+static void InitUsbAggregationSetting(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ /* Tx aggregation setting */ -+ usb_AggSettingTxUpdate(Adapter); -+ -+ /* Rx aggregation setting */ -+ usb_AggSettingRxUpdate(Adapter); -+ -+ /* 201/12/10 MH Add for USB agg mode dynamic switch. */ -+ haldata->UsbRxHighSpeedMode = false; -+} -+ -+static void _InitOperationMode(struct adapter *Adapter) -+{ -+} -+ -+static void _InitBeaconParameters(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ rtw_write16(Adapter, REG_BCN_CTRL, 0x1010); -+ -+ /* TODO: Remove these magic number */ -+ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0x6404);/* ms */ -+ rtw_write8(Adapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/* 5ms */ -+ rtw_write8(Adapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); /* 2ms */ -+ -+ /* Suggested by designer timchen. Change beacon AIFS to the largest number */ -+ /* beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 */ -+ rtw_write16(Adapter, REG_BCNTCFG, 0x660F); -+ -+ haldata->RegBcnCtrlVal = rtw_read8(Adapter, REG_BCN_CTRL); -+ haldata->RegTxPause = rtw_read8(Adapter, REG_TXPAUSE); -+ haldata->RegFwHwTxQCtrl = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL+2); -+ haldata->RegReg542 = rtw_read8(Adapter, REG_TBTT_PROHIBIT+2); -+ haldata->RegCR_1 = rtw_read8(Adapter, REG_CR+1); -+} -+ -+static void _BeaconFunctionEnable(struct adapter *Adapter, -+ bool Enable, bool Linked) -+{ -+ rtw_write8(Adapter, REG_BCN_CTRL, (BIT4 | BIT3 | BIT1)); -+ -+ rtw_write8(Adapter, REG_RD_CTRL+1, 0x6F); -+} -+ -+/* Set CCK and OFDM Block "ON" */ -+static void _BBTurnOnBlock(struct adapter *Adapter) -+{ -+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bCCKEn, 0x1); -+ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bOFDMEn, 0x1); -+} -+ -+enum { -+ Antenna_Lfet = 1, -+ Antenna_Right = 2, -+}; -+ -+static void _InitAntenna_Selection(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ if (haldata->AntDivCfg == 0) -+ return; -+ DBG_88E("==> %s ....\n", __func__); -+ -+ rtw_write32(Adapter, REG_LEDCFG0, rtw_read32(Adapter, REG_LEDCFG0)|BIT23); -+ PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, BIT13, 0x01); -+ -+ if (PHY_QueryBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300) == Antenna_A) -+ haldata->CurAntenna = Antenna_A; -+ else -+ haldata->CurAntenna = Antenna_B; -+ DBG_88E("%s,Cur_ant:(%x)%s\n", __func__, haldata->CurAntenna, (haldata->CurAntenna == Antenna_A) ? "Antenna_A" : "Antenna_B"); -+} -+ -+/*----------------------------------------------------------------------------- -+ * Function: HwSuspendModeEnable92Cu() -+ * -+ * Overview: HW suspend mode switch. -+ * -+ * Input: NONE -+ * -+ * Output: NONE -+ * -+ * Return: NONE -+ * -+ * Revised History: -+ * When Who Remark -+ * 08/23/2010 MHC HW suspend mode switch test.. -+ *---------------------------------------------------------------------------*/ -+enum rt_rf_power_state RfOnOffDetect(struct adapter *adapt) -+{ -+ u8 val8; -+ enum rt_rf_power_state rfpowerstate = rf_off; -+ -+ if (adapt->pwrctrlpriv.bHWPowerdown) { -+ val8 = rtw_read8(adapt, REG_HSISR); -+ DBG_88E("pwrdown, 0x5c(BIT7)=%02x\n", val8); -+ rfpowerstate = (val8 & BIT7) ? rf_off : rf_on; -+ } else { /* rf on/off */ -+ rtw_write8(adapt, REG_MAC_PINMUX_CFG, rtw_read8(adapt, REG_MAC_PINMUX_CFG)&~(BIT3)); -+ val8 = rtw_read8(adapt, REG_GPIO_IO_SEL); -+ DBG_88E("GPIO_IN=%02x\n", val8); -+ rfpowerstate = (val8 & BIT3) ? rf_on : rf_off; -+ } -+ return rfpowerstate; -+} /* HalDetectPwrDownMode */ -+ -+static u32 rtl8188eu_hal_init(struct adapter *Adapter) -+{ -+ u8 value8 = 0; -+ u16 value16; -+ u8 txpktbuf_bndy; -+ u32 status = _SUCCESS; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; -+ struct registry_priv *pregistrypriv = &Adapter->registrypriv; -+ u32 init_start_time = jiffies; -+ -+ #define HAL_INIT_PROFILE_TAG(stage) do {} while (0) -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN); -+ -+ if (Adapter->pwrctrlpriv.bkeepfwalive) { -+ _ps_open_RF(Adapter); -+ -+ if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) { -+ PHY_IQCalibrate_8188E(Adapter, true); -+ } else { -+ PHY_IQCalibrate_8188E(Adapter, false); -+ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true; -+ } -+ -+ ODM_TXPowerTrackingCheck(&haldata->odmpriv); -+ PHY_LCCalibrate_8188E(Adapter); -+ -+ goto exit; -+ } -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON); -+ status = rtl8188eu_InitPowerOn(Adapter); -+ if (status == _FAIL) { -+ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init power on!\n")); -+ goto exit; -+ } -+ -+ /* Save target channel */ -+ haldata->CurrentChannel = 6;/* default set to 6 */ -+ -+ if (pwrctrlpriv->reg_rfoff) { -+ pwrctrlpriv->rf_pwrstate = rf_off; -+ } -+ -+ /* 2010/08/09 MH We need to check if we need to turnon or off RF after detecting */ -+ /* HW GPIO pin. Before PHY_RFConfig8192C. */ -+ /* 2010/08/26 MH If Efuse does not support sective suspend then disable the function. */ -+ -+ if (!pregistrypriv->wifi_spec) { -+ txpktbuf_bndy = TX_PAGE_BOUNDARY_88E; -+ } else { -+ /* for WMM */ -+ txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_88E; -+ } -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01); -+ _InitQueueReservedPage(Adapter); -+ _InitQueuePriority(Adapter); -+ _InitPageBoundary(Adapter); -+ _InitTransferPageSize(Adapter); -+ -+ _InitTxBufferBoundary(Adapter, 0); -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW); -+ if (Adapter->registrypriv.mp_mode == 1) { -+ _InitRxSetting(Adapter); -+ Adapter->bFWReady = false; -+ haldata->fw_ractrl = false; -+ } else { -+ status = rtl8188e_FirmwareDownload(Adapter); -+ -+ if (status != _SUCCESS) { -+ DBG_88E("%s: Download Firmware failed!!\n", __func__); -+ Adapter->bFWReady = false; -+ haldata->fw_ractrl = false; -+ return status; -+ } else { -+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializeadapt8192CSdio(): Download Firmware Success!!\n")); -+ Adapter->bFWReady = true; -+ haldata->fw_ractrl = false; -+ } -+ } -+ rtl8188e_InitializeFirmwareVars(Adapter); -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC); -+#if (HAL_MAC_ENABLE == 1) -+ status = PHY_MACConfig8188E(Adapter); -+ if (status == _FAIL) { -+ DBG_88E(" ### Failed to init MAC ......\n "); -+ goto exit; -+ } -+#endif -+ -+ /* */ -+ /* d. Initialize BB related configurations. */ -+ /* */ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB); -+#if (HAL_BB_ENABLE == 1) -+ status = PHY_BBConfig8188E(Adapter); -+ if (status == _FAIL) { -+ DBG_88E(" ### Failed to init BB ......\n "); -+ goto exit; -+ } -+#endif -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF); -+#if (HAL_RF_ENABLE == 1) -+ status = PHY_RFConfig8188E(Adapter); -+ if (status == _FAIL) { -+ DBG_88E(" ### Failed to init RF ......\n "); -+ goto exit; -+ } -+#endif -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_EFUSE_PATCH); -+ status = rtl8188e_iol_efuse_patch(Adapter); -+ if (status == _FAIL) { -+ DBG_88E("%s rtl8188e_iol_efuse_patch failed\n", __func__); -+ goto exit; -+ } -+ -+ _InitTxBufferBoundary(Adapter, txpktbuf_bndy); -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT); -+ status = InitLLTTable(Adapter, txpktbuf_bndy); -+ if (status == _FAIL) { -+ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init LLT table\n")); -+ goto exit; -+ } -+ -+ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02); -+ /* Get Rx PHY status in order to report RSSI and others. */ -+ _InitDriverInfoSize(Adapter, DRVINFO_SZ); -+ -+ _InitInterrupt(Adapter); -+ hal_init_macaddr(Adapter);/* set mac_address */ -+ _InitNetworkType(Adapter);/* set msr */ -+ _InitWMACSetting(Adapter); -+ _InitAdaptiveCtrl(Adapter); -+ _InitEDCA(Adapter); -+ _InitRetryFunction(Adapter); -+ InitUsbAggregationSetting(Adapter); -+ _InitOperationMode(Adapter);/* todo */ -+ _InitBeaconParameters(Adapter); -+ _InitBeaconMaxError(Adapter, true); -+ -+ /* */ -+ /* Init CR MACTXEN, MACRXEN after setting RxFF boundary REG_TRXFF_BNDY to patch */ -+ /* Hw bug which Hw initials RxFF boundary size to a value which is larger than the real Rx buffer size in 88E. */ -+ /* */ -+ /* Enable MACTXEN/MACRXEN block */ -+ value16 = rtw_read16(Adapter, REG_CR); -+ value16 |= (MACTXEN | MACRXEN); -+ rtw_write8(Adapter, REG_CR, value16); -+ -+ if (haldata->bRDGEnable) -+ _InitRDGSetting(Adapter); -+ -+ /* Enable TX Report */ -+ /* Enable Tx Report Timer */ -+ value8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); -+ rtw_write8(Adapter, REG_TX_RPT_CTRL, (value8|BIT1|BIT0)); -+ /* Set MAX RPT MACID */ -+ rtw_write8(Adapter, REG_TX_RPT_CTRL+1, 2);/* FOR sta mode ,0: bc/mc ,1:AP */ -+ /* Tx RPT Timer. Unit: 32us */ -+ rtw_write16(Adapter, REG_TX_RPT_TIME, 0xCdf0); -+ -+ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL, 0); -+ -+ rtw_write16(Adapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ -+ rtw_write16(Adapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ -+ -+ _InitHWLed(Adapter); -+ -+ /* Keep RfRegChnlVal for later use. */ -+ haldata->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)0, RF_CHNLBW, bRFRegOffsetMask); -+ haldata->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)1, RF_CHNLBW, bRFRegOffsetMask); -+ -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK); -+ _BBTurnOnBlock(Adapter); -+ -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY); -+ invalidate_cam_all(Adapter); -+ -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11); -+ /* 2010/12/17 MH We need to set TX power according to EFUSE content at first. */ -+ PHY_SetTxPowerLevel8188E(Adapter, haldata->CurrentChannel); -+ -+/* Move by Neo for USB SS to below setp */ -+/* _RfPowerSave(Adapter); */ -+ -+ _InitAntenna_Selection(Adapter); -+ -+ /* */ -+ /* Disable BAR, suggested by Scott */ -+ /* 2010.04.09 add by hpfan */ -+ /* */ -+ rtw_write32(Adapter, REG_BAR_MODE_CTRL, 0x0201ffff); -+ -+ /* HW SEQ CTRL */ -+ /* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */ -+ rtw_write8(Adapter, REG_HWSEQ_CTRL, 0xFF); -+ -+ if (pregistrypriv->wifi_spec) -+ rtw_write16(Adapter, REG_FAST_EDCA_CTRL, 0); -+ -+ /* Nav limit , suggest by scott */ -+ rtw_write8(Adapter, 0x652, 0x0); -+ -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM); -+ rtl8188e_InitHalDm(Adapter); -+ -+ if (Adapter->registrypriv.mp_mode == 1) { -+ Adapter->mppriv.channel = haldata->CurrentChannel; -+ MPT_InitializeAdapter(Adapter, Adapter->mppriv.channel); -+ } else { -+ /* 2010/08/11 MH Merge from 8192SE for Minicard init. We need to confirm current radio status */ -+ /* and then decide to enable RF or not.!!!??? For Selective suspend mode. We may not */ -+ /* call initstruct adapter. May cause some problem?? */ -+ /* Fix the bug that Hw/Sw radio off before S3/S4, the RF off action will not be executed */ -+ /* in MgntActSet_RF_State() after wake up, because the value of haldata->eRFPowerState */ -+ /* is the same as eRfOff, we should change it to eRfOn after we config RF parameters. */ -+ /* Added by tynli. 2010.03.30. */ -+ pwrctrlpriv->rf_pwrstate = rf_on; -+ -+ /* enable Tx report. */ -+ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL+1, 0x0F); -+ -+ /* Suggested by SD1 pisa. Added by tynli. 2011.10.21. */ -+ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL+3, 0x01);/* Pretx_en, for WEP/TKIP SEC */ -+ -+ /* tynli_test_tx_report. */ -+ rtw_write16(Adapter, REG_TX_RPT_TIME, 0x3DF0); -+ -+ /* enable tx DMA to drop the redundate data of packet */ -+ rtw_write16(Adapter, REG_TXDMA_OFFSET_CHK, (rtw_read16(Adapter, REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN)); -+ -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK); -+ /* 2010/08/26 MH Merge from 8192CE. */ -+ if (pwrctrlpriv->rf_pwrstate == rf_on) { -+ if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) { -+ PHY_IQCalibrate_8188E(Adapter, true); -+ } else { -+ PHY_IQCalibrate_8188E(Adapter, false); -+ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true; -+ } -+ -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK); -+ -+ ODM_TXPowerTrackingCheck(&haldata->odmpriv); -+ -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK); -+ PHY_LCCalibrate_8188E(Adapter); -+ } -+ } -+ -+/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */ -+/* _InitPABias(Adapter); */ -+ rtw_write8(Adapter, REG_USB_HRPWM, 0); -+ -+ /* ack for xmit mgmt frames. */ -+ rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL)|BIT(12)); -+ -+exit: -+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END); -+ -+ DBG_88E("%s in %dms\n", __func__, rtw_get_passing_time_ms(init_start_time)); -+ -+ return status; -+} -+ -+void _ps_open_RF(struct adapter *adapt) -+{ -+ /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */ -+ /* phy_SsPwrSwitch92CU(adapt, rf_on, 1); */ -+} -+ -+static void _ps_close_RF(struct adapter *adapt) -+{ -+ /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */ -+ /* phy_SsPwrSwitch92CU(adapt, rf_off, 1); */ -+} -+ -+static void CardDisableRTL8188EU(struct adapter *Adapter) -+{ -+ u8 val8; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("CardDisableRTL8188EU\n")); -+ -+ /* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */ -+ val8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); -+ rtw_write8(Adapter, REG_TX_RPT_CTRL, val8&(~BIT1)); -+ -+ /* stop rx */ -+ rtw_write8(Adapter, REG_CR, 0x0); -+ -+ /* Run LPS WL RFOFF flow */ -+ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_LPS_ENTER_FLOW); -+ -+ /* 2. 0x1F[7:0] = 0 turn off RF */ -+ -+ val8 = rtw_read8(Adapter, REG_MCUFWDL); -+ if ((val8 & RAM_DL_SEL) && Adapter->bFWReady) { /* 8051 RAM code */ -+ /* Reset MCU 0x2[10]=0. */ -+ val8 = rtw_read8(Adapter, REG_SYS_FUNC_EN+1); -+ val8 &= ~BIT(2); /* 0x2[10], FEN_CPUEN */ -+ rtw_write8(Adapter, REG_SYS_FUNC_EN+1, val8); -+ } -+ -+ /* reset MCU ready status */ -+ rtw_write8(Adapter, REG_MCUFWDL, 0); -+ -+ /* YJ,add,111212 */ -+ /* Disable 32k */ -+ val8 = rtw_read8(Adapter, REG_32K_CTRL); -+ rtw_write8(Adapter, REG_32K_CTRL, val8&(~BIT0)); -+ -+ /* Card disable power action flow */ -+ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_DISABLE_FLOW); -+ -+ /* Reset MCU IO Wrapper */ -+ val8 = rtw_read8(Adapter, REG_RSV_CTRL+1); -+ rtw_write8(Adapter, REG_RSV_CTRL+1, (val8&(~BIT3))); -+ val8 = rtw_read8(Adapter, REG_RSV_CTRL+1); -+ rtw_write8(Adapter, REG_RSV_CTRL+1, val8|BIT3); -+ -+ /* YJ,test add, 111207. For Power Consumption. */ -+ val8 = rtw_read8(Adapter, GPIO_IN); -+ rtw_write8(Adapter, GPIO_OUT, val8); -+ rtw_write8(Adapter, GPIO_IO_SEL, 0xFF);/* Reg0x46 */ -+ -+ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL); -+ rtw_write8(Adapter, REG_GPIO_IO_SEL, (val8<<4)); -+ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL+1); -+ rtw_write8(Adapter, REG_GPIO_IO_SEL+1, val8|0x0F);/* Reg0x43 */ -+ rtw_write32(Adapter, REG_BB_PAD_CTRL, 0x00080808);/* set LNA ,TRSW,EX_PA Pin to output mode */ -+ haldata->bMacPwrCtrlOn = false; -+ Adapter->bFWReady = false; -+} -+static void rtl8192cu_hw_power_down(struct adapter *adapt) -+{ -+ /* 2010/-8/09 MH For power down module, we need to enable register block contrl reg at 0x1c. */ -+ /* Then enable power down control bit of register 0x04 BIT4 and BIT15 as 1. */ -+ -+ /* Enable register area 0x0-0xc. */ -+ rtw_write8(adapt, REG_RSV_CTRL, 0x0); -+ rtw_write16(adapt, REG_APS_FSMCO, 0x8812); -+} -+ -+static u32 rtl8188eu_hal_deinit(struct adapter *Adapter) -+{ -+ -+ DBG_88E("==> %s\n", __func__); -+ -+ rtw_write32(Adapter, REG_HIMR_88E, IMR_DISABLED_88E); -+ rtw_write32(Adapter, REG_HIMRE_88E, IMR_DISABLED_88E); -+ -+ DBG_88E("bkeepfwalive(%x)\n", Adapter->pwrctrlpriv.bkeepfwalive); -+ if (Adapter->pwrctrlpriv.bkeepfwalive) { -+ _ps_close_RF(Adapter); -+ if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown)) -+ rtl8192cu_hw_power_down(Adapter); -+ } else { -+ if (Adapter->hw_init_completed) { -+ CardDisableRTL8188EU(Adapter); -+ -+ if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown)) -+ rtl8192cu_hw_power_down(Adapter); -+ } -+ } -+ return _SUCCESS; -+ } -+ -+static unsigned int rtl8188eu_inirp_init(struct adapter *Adapter) -+{ -+ u8 i; -+ struct recv_buf *precvbuf; -+ uint status; -+ struct intf_hdl *pintfhdl = &Adapter->iopriv.intf; -+ struct recv_priv *precvpriv = &(Adapter->recvpriv); -+ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); -+ -+ _read_port = pintfhdl->io_ops._read_port; -+ -+ status = _SUCCESS; -+ -+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, -+ ("===> usb_inirp_init\n")); -+ -+ precvpriv->ff_hwaddr = RECV_BULK_IN_ADDR; -+ -+ /* issue Rx irp to receive data */ -+ precvbuf = (struct recv_buf *)precvpriv->precv_buf; -+ for (i = 0; i < NR_RECVBUFF; i++) { -+ if (_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf) == false) { -+ RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("usb_rx_init: usb_read_port error\n")); -+ status = _FAIL; -+ goto exit; -+ } -+ -+ precvbuf++; -+ precvpriv->free_recv_buf_queue_cnt--; -+ } -+ -+exit: -+ -+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<=== usb_inirp_init\n")); -+ -+ return status; -+} -+ -+static unsigned int rtl8188eu_inirp_deinit(struct adapter *Adapter) -+{ -+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("\n ===> usb_rx_deinit\n")); -+ -+ rtw_read_port_cancel(Adapter); -+ -+ RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("\n <=== usb_rx_deinit\n")); -+ -+ return _SUCCESS; -+} -+ -+/* */ -+/* */ -+/* EEPROM/EFUSE Content Parsing */ -+/* */ -+/* */ -+static void _ReadLEDSetting(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail) -+{ -+ struct led_priv *pledpriv = &(Adapter->ledpriv); -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ pledpriv->bRegUseLed = true; -+ pledpriv->LedStrategy = SW_LED_MODE1; -+ haldata->bLedOpenDrain = true;/* Support Open-drain arrangement for controlling the LED. */ -+} -+ -+static void Hal_EfuseParsePIDVID_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ -+ if (!AutoLoadFail) { -+ /* VID, PID */ -+ haldata->EEPROMVID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_VID_88EU]); -+ haldata->EEPROMPID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_PID_88EU]); -+ -+ /* Customer ID, 0x00 and 0xff are reserved for Realtek. */ -+ haldata->EEPROMCustomerID = *(u8 *)&hwinfo[EEPROM_CUSTOMERID_88E]; -+ haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID; -+ } else { -+ haldata->EEPROMVID = EEPROM_Default_VID; -+ haldata->EEPROMPID = EEPROM_Default_PID; -+ -+ /* Customer ID, 0x00 and 0xff are reserved for Realtek. */ -+ haldata->EEPROMCustomerID = EEPROM_Default_CustomerID; -+ haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID; -+ } -+ -+ DBG_88E("VID = 0x%04X, PID = 0x%04X\n", haldata->EEPROMVID, haldata->EEPROMPID); -+ DBG_88E("Customer ID: 0x%02X, SubCustomer ID: 0x%02X\n", haldata->EEPROMCustomerID, haldata->EEPROMSubCustomerID); -+} -+ -+static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail) -+{ -+ u16 i; -+ u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x02}; -+ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt); -+ -+ if (AutoLoadFail) { -+ for (i = 0; i < 6; i++) -+ eeprom->mac_addr[i] = sMacAddr[i]; -+ } else { -+ /* Read Permanent MAC address */ -+ memcpy(eeprom->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN); -+ } -+ RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, -+ ("Hal_EfuseParseMACAddr_8188EU: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", -+ eeprom->mac_addr[0], eeprom->mac_addr[1], -+ eeprom->mac_addr[2], eeprom->mac_addr[3], -+ eeprom->mac_addr[4], eeprom->mac_addr[5])); -+} -+ -+static void Hal_CustomizeByCustomerID_8188EU(struct adapter *adapt) -+{ -+} -+ -+static void -+readAdapterInfo_8188EU( -+ struct adapter *adapt -+ ) -+{ -+ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt); -+ -+ /* parse the eeprom/efuse content */ -+ Hal_EfuseParseIDCode88E(adapt, eeprom->efuse_eeprom_data); -+ Hal_EfuseParsePIDVID_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_EfuseParseMACAddr_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ -+ Hal_ReadPowerSavingMode88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_ReadTxPowerInfo88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_EfuseParseEEPROMVer88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ rtl8188e_EfuseParseChnlPlan(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_EfuseParseXtal_8188E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_EfuseParseCustomerID88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_ReadAntennaDiversity88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_EfuseParseBoardType88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ Hal_ReadThermalMeter_88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+ -+ /* */ -+ /* The following part initialize some vars by PG info. */ -+ /* */ -+ Hal_InitChannelPlan(adapt); -+ Hal_CustomizeByCustomerID_8188EU(adapt); -+ -+ _ReadLEDSetting(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); -+} -+ -+static void _ReadPROMContent( -+ struct adapter *Adapter -+ ) -+{ -+ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(Adapter); -+ u8 eeValue; -+ -+ /* check system boot selection */ -+ eeValue = rtw_read8(Adapter, REG_9346CR); -+ eeprom->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false; -+ eeprom->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true; -+ -+ DBG_88E("Boot from %s, Autoload %s !\n", (eeprom->EepromOrEfuse ? "EEPROM" : "EFUSE"), -+ (eeprom->bautoload_fail_flag ? "Fail" : "OK")); -+ -+ Hal_InitPGData88E(Adapter); -+ readAdapterInfo_8188EU(Adapter); -+} -+ -+static void _ReadRFType(struct adapter *Adapter) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ -+ haldata->rf_chip = RF_6052; -+} -+ -+static int _ReadAdapterInfo8188EU(struct adapter *Adapter) -+{ -+ u32 start = jiffies; -+ -+ MSG_88E("====> %s\n", __func__); -+ -+ _ReadRFType(Adapter);/* rf_chip -> _InitRFType() */ -+ _ReadPROMContent(Adapter); -+ -+ MSG_88E("<==== %s in %d ms\n", __func__, rtw_get_passing_time_ms(start)); -+ -+ return _SUCCESS; -+} -+ -+static void ReadAdapterInfo8188EU(struct adapter *Adapter) -+{ -+ /* Read EEPROM size before call any EEPROM function */ -+ Adapter->EepromAddressSize = GetEEPROMSize8188E(Adapter); -+ -+ _ReadAdapterInfo8188EU(Adapter); -+} -+ -+#define GPIO_DEBUG_PORT_NUM 0 -+static void rtl8192cu_trigger_gpio_0(struct adapter *adapt) -+{ -+} -+ -+static void ResumeTxBeacon(struct adapter *adapt) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ -+ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ -+ /* which should be read from register to a global variable. */ -+ -+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) | BIT6); -+ haldata->RegFwHwTxQCtrl |= BIT6; -+ rtw_write8(adapt, REG_TBTT_PROHIBIT+1, 0xff); -+ haldata->RegReg542 |= BIT0; -+ rtw_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542); -+} -+ -+static void StopTxBeacon(struct adapter *adapt) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ -+ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ -+ /* which should be read from register to a global variable. */ -+ -+ rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) & (~BIT6)); -+ haldata->RegFwHwTxQCtrl &= (~BIT6); -+ rtw_write8(adapt, REG_TBTT_PROHIBIT+1, 0x64); -+ haldata->RegReg542 &= ~(BIT0); -+ rtw_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542); -+ -+ /* todo: CheckFwRsvdPageContent(Adapter); 2010.06.23. Added by tynli. */ -+} -+ -+static void hw_var_set_opmode(struct adapter *Adapter, u8 variable, u8 *val) -+{ -+ u8 val8; -+ u8 mode = *((u8 *)val); -+ -+ /* disable Port0 TSF update */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); -+ -+ /* set net_type */ -+ val8 = rtw_read8(Adapter, MSR)&0x0c; -+ val8 |= mode; -+ rtw_write8(Adapter, MSR, val8); -+ -+ DBG_88E("%s()-%d mode = %d\n", __func__, __LINE__, mode); -+ -+ if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { -+ StopTxBeacon(Adapter); -+ -+ rtw_write8(Adapter, REG_BCN_CTRL, 0x19);/* disable atim wnd */ -+ } else if ((mode == _HW_STATE_ADHOC_)) { -+ ResumeTxBeacon(Adapter); -+ rtw_write8(Adapter, REG_BCN_CTRL, 0x1a); -+ } else if (mode == _HW_STATE_AP_) { -+ ResumeTxBeacon(Adapter); -+ -+ rtw_write8(Adapter, REG_BCN_CTRL, 0x12); -+ -+ /* Set RCR */ -+ rtw_write32(Adapter, REG_RCR, 0x7000208e);/* CBSSID_DATA must set to 0,reject ICV_ERR packet */ -+ /* enable to rx data frame */ -+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); -+ /* enable to rx ps-poll */ -+ rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400); -+ -+ /* Beacon Control related register for first time */ -+ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); /* 2ms */ -+ -+ rtw_write8(Adapter, REG_ATIMWND, 0x0a); /* 10ms */ -+ rtw_write16(Adapter, REG_BCNTCFG, 0x00); -+ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); -+ rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */ -+ -+ /* reset TSF */ -+ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); -+ -+ /* BIT3 - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 */ -+ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM) | BIT(3) | BIT(4)); -+ -+ /* enable BCN0 Function for if1 */ -+ /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */ -+ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | BIT(1))); -+ -+ /* dis BCN1 ATIM WND if if2 is station */ -+ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1) | BIT(0)); -+ } -+} -+ -+static void hw_var_set_macaddr(struct adapter *Adapter, u8 variable, u8 *val) -+{ -+ u8 idx = 0; -+ u32 reg_macid; -+ -+ reg_macid = REG_MACID; -+ -+ for (idx = 0; idx < 6; idx++) -+ rtw_write8(Adapter, (reg_macid+idx), val[idx]); -+} -+ -+static void hw_var_set_bssid(struct adapter *Adapter, u8 variable, u8 *val) -+{ -+ u8 idx = 0; -+ u32 reg_bssid; -+ -+ reg_bssid = REG_BSSID; -+ -+ for (idx = 0; idx < 6; idx++) -+ rtw_write8(Adapter, (reg_bssid+idx), val[idx]); -+} -+ -+static void hw_var_set_bcn_func(struct adapter *Adapter, u8 variable, u8 *val) -+{ -+ u32 bcn_ctrl_reg; -+ -+ bcn_ctrl_reg = REG_BCN_CTRL; -+ -+ if (*((u8 *)val)) -+ rtw_write8(Adapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT)); -+ else -+ rtw_write8(Adapter, bcn_ctrl_reg, rtw_read8(Adapter, bcn_ctrl_reg)&(~(EN_BCN_FUNCTION | EN_TXBCN_RPT))); -+} -+ -+static void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ struct dm_priv *pdmpriv = &haldata->dmpriv; -+ struct odm_dm_struct *podmpriv = &haldata->odmpriv; -+ -+ switch (variable) { -+ case HW_VAR_MEDIA_STATUS: -+ { -+ u8 val8; -+ -+ val8 = rtw_read8(Adapter, MSR)&0x0c; -+ val8 |= *((u8 *)val); -+ rtw_write8(Adapter, MSR, val8); -+ } -+ break; -+ case HW_VAR_MEDIA_STATUS1: -+ { -+ u8 val8; -+ -+ val8 = rtw_read8(Adapter, MSR) & 0x03; -+ val8 |= *((u8 *)val) << 2; -+ rtw_write8(Adapter, MSR, val8); -+ } -+ break; -+ case HW_VAR_SET_OPMODE: -+ hw_var_set_opmode(Adapter, variable, val); -+ break; -+ case HW_VAR_MAC_ADDR: -+ hw_var_set_macaddr(Adapter, variable, val); -+ break; -+ case HW_VAR_BSSID: -+ hw_var_set_bssid(Adapter, variable, val); -+ break; -+ case HW_VAR_BASIC_RATE: -+ { -+ u16 BrateCfg = 0; -+ u8 RateIndex = 0; -+ -+ /* 2007.01.16, by Emily */ -+ /* Select RRSR (in Legacy-OFDM and CCK) */ -+ /* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */ -+ /* We do not use other rates. */ -+ HalSetBrateCfg(Adapter, val, &BrateCfg); -+ DBG_88E("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg); -+ -+ /* 2011.03.30 add by Luke Lee */ -+ /* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */ -+ /* because CCK 2M has poor TXEVM */ -+ /* CCK 5.5M & 11M ACK should be enabled for better performance */ -+ -+ BrateCfg = (BrateCfg | 0xd) & 0x15d; -+ haldata->BasicRateSet = BrateCfg; -+ -+ BrateCfg |= 0x01; /* default enable 1M ACK rate */ -+ /* Set RRSR rate table. */ -+ rtw_write8(Adapter, REG_RRSR, BrateCfg & 0xff); -+ rtw_write8(Adapter, REG_RRSR+1, (BrateCfg >> 8) & 0xff); -+ rtw_write8(Adapter, REG_RRSR+2, rtw_read8(Adapter, REG_RRSR+2)&0xf0); -+ -+ /* Set RTS initial rate */ -+ while (BrateCfg > 0x1) { -+ BrateCfg = (BrateCfg >> 1); -+ RateIndex++; -+ } -+ /* Ziv - Check */ -+ rtw_write8(Adapter, REG_INIRTS_RATE_SEL, RateIndex); -+ } -+ break; -+ case HW_VAR_TXPAUSE: -+ rtw_write8(Adapter, REG_TXPAUSE, *((u8 *)val)); -+ break; -+ case HW_VAR_BCN_FUNC: -+ hw_var_set_bcn_func(Adapter, variable, val); -+ break; -+ case HW_VAR_CORRECT_TSF: -+ { -+ u64 tsf; -+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) - 1024; /* us */ -+ -+ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) -+ StopTxBeacon(Adapter); -+ -+ /* disable related TSF function */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3))); -+ -+ rtw_write32(Adapter, REG_TSFTR, tsf); -+ rtw_write32(Adapter, REG_TSFTR+4, tsf>>32); -+ -+ /* enable related TSF function */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3)); -+ -+ if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) -+ ResumeTxBeacon(Adapter); -+ } -+ break; -+ case HW_VAR_CHECK_BSSID: -+ if (*((u8 *)val)) { -+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); -+ } else { -+ u32 val32; -+ -+ val32 = rtw_read32(Adapter, REG_RCR); -+ -+ val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); -+ -+ rtw_write32(Adapter, REG_RCR, val32); -+ } -+ break; -+ case HW_VAR_MLME_DISCONNECT: -+ /* Set RCR to not to receive data frame when NO LINK state */ -+ /* reject all data frames */ -+ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); -+ -+ /* reset TSF */ -+ rtw_write8(Adapter, REG_DUAL_TSF_RST, (BIT(0)|BIT(1))); -+ -+ /* disable update TSF */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); -+ break; -+ case HW_VAR_MLME_SITESURVEY: -+ if (*((u8 *)val)) { /* under sitesurvey */ -+ /* config RCR to receive different BSSID & not to receive data frame */ -+ u32 v = rtw_read32(Adapter, REG_RCR); -+ v &= ~(RCR_CBSSID_BCN); -+ rtw_write32(Adapter, REG_RCR, v); -+ /* reject all data frame */ -+ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); -+ -+ /* disable update TSF */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4)); -+ } else { /* sitesurvey done */ -+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ if ((is_client_associated_to_ap(Adapter)) || -+ ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) { -+ /* enable to rx data frame */ -+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); -+ -+ /* enable update TSF */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); -+ } else if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { -+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); -+ /* enable update TSF */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); -+ } -+ if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) { -+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); -+ } else { -+ if (Adapter->in_cta_test) { -+ u32 v = rtw_read32(Adapter, REG_RCR); -+ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */ -+ rtw_write32(Adapter, REG_RCR, v); -+ } else { -+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN); -+ } -+ } -+ } -+ break; -+ case HW_VAR_MLME_JOIN: -+ { -+ u8 RetryLimit = 0x30; -+ u8 type = *((u8 *)val); -+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; -+ -+ if (type == 0) { /* prepare to join */ -+ /* enable to rx data frame.Accept all data frame */ -+ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); -+ -+ if (Adapter->in_cta_test) { -+ u32 v = rtw_read32(Adapter, REG_RCR); -+ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */ -+ rtw_write32(Adapter, REG_RCR, v); -+ } else { -+ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN); -+ } -+ -+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) -+ RetryLimit = (haldata->CustomerID == RT_CID_CCX) ? 7 : 48; -+ else /* Ad-hoc Mode */ -+ RetryLimit = 0x7; -+ } else if (type == 1) { -+ /* joinbss_event call back when join res < 0 */ -+ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); -+ } else if (type == 2) { -+ /* sta add event call back */ -+ /* enable update TSF */ -+ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4))); -+ -+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) -+ RetryLimit = 0x7; -+ } -+ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); -+ } -+ break; -+ case HW_VAR_BEACON_INTERVAL: -+ rtw_write16(Adapter, REG_BCN_INTERVAL, *((u16 *)val)); -+ break; -+ case HW_VAR_SLOT_TIME: -+ { -+ u8 u1bAIFS, aSifsTime; -+ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ -+ rtw_write8(Adapter, REG_SLOT, val[0]); -+ -+ if (pmlmeinfo->WMM_enable == 0) { -+ if (pmlmeext->cur_wireless_mode == WIRELESS_11B) -+ aSifsTime = 10; -+ else -+ aSifsTime = 16; -+ -+ u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime); -+ -+ /* Temporary removed, 2008.06.20. */ -+ rtw_write8(Adapter, REG_EDCA_VO_PARAM, u1bAIFS); -+ rtw_write8(Adapter, REG_EDCA_VI_PARAM, u1bAIFS); -+ rtw_write8(Adapter, REG_EDCA_BE_PARAM, u1bAIFS); -+ rtw_write8(Adapter, REG_EDCA_BK_PARAM, u1bAIFS); -+ } -+ } -+ break; -+ case HW_VAR_RESP_SIFS: -+ /* RESP_SIFS for CCK */ -+ rtw_write8(Adapter, REG_R2T_SIFS, val[0]); /* SIFS_T2T_CCK (0x08) */ -+ rtw_write8(Adapter, REG_R2T_SIFS+1, val[1]); /* SIFS_R2T_CCK(0x08) */ -+ /* RESP_SIFS for OFDM */ -+ rtw_write8(Adapter, REG_T2T_SIFS, val[2]); /* SIFS_T2T_OFDM (0x0a) */ -+ rtw_write8(Adapter, REG_T2T_SIFS+1, val[3]); /* SIFS_R2T_OFDM(0x0a) */ -+ break; -+ case HW_VAR_ACK_PREAMBLE: -+ { -+ u8 regTmp; -+ u8 bShortPreamble = *((bool *)val); -+ /* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */ -+ regTmp = (haldata->nCur40MhzPrimeSC)<<5; -+ if (bShortPreamble) -+ regTmp |= 0x80; -+ -+ rtw_write8(Adapter, REG_RRSR+2, regTmp); -+ } -+ break; -+ case HW_VAR_SEC_CFG: -+ rtw_write8(Adapter, REG_SECCFG, *((u8 *)val)); -+ break; -+ case HW_VAR_DM_FLAG: -+ podmpriv->SupportAbility = *((u8 *)val); -+ break; -+ case HW_VAR_DM_FUNC_OP: -+ if (val[0]) -+ podmpriv->BK_SupportAbility = podmpriv->SupportAbility; -+ else -+ podmpriv->SupportAbility = podmpriv->BK_SupportAbility; -+ break; -+ case HW_VAR_DM_FUNC_SET: -+ if (*((u32 *)val) == DYNAMIC_ALL_FUNC_ENABLE) { -+ pdmpriv->DMFlag = pdmpriv->InitDMFlag; -+ podmpriv->SupportAbility = pdmpriv->InitODMFlag; -+ } else { -+ podmpriv->SupportAbility |= *((u32 *)val); -+ } -+ break; -+ case HW_VAR_DM_FUNC_CLR: -+ podmpriv->SupportAbility &= *((u32 *)val); -+ break; -+ case HW_VAR_CAM_EMPTY_ENTRY: -+ { -+ u8 ucIndex = *((u8 *)val); -+ u8 i; -+ u32 ulCommand = 0; -+ u32 ulContent = 0; -+ u32 ulEncAlgo = CAM_AES; -+ -+ for (i = 0; i < CAM_CONTENT_COUNT; i++) { -+ /* filled id in CAM config 2 byte */ -+ if (i == 0) -+ ulContent |= (ucIndex & 0x03) | ((u16)(ulEncAlgo)<<2); -+ else -+ ulContent = 0; -+ /* polling bit, and No Write enable, and address */ -+ ulCommand = CAM_CONTENT_COUNT*ucIndex+i; -+ ulCommand = ulCommand | CAM_POLLINIG|CAM_WRITE; -+ /* write content 0 is equall to mark invalid */ -+ rtw_write32(Adapter, WCAMI, ulContent); /* delay_ms(40); */ -+ rtw_write32(Adapter, RWCAM, ulCommand); /* delay_ms(40); */ -+ } -+ } -+ break; -+ case HW_VAR_CAM_INVALID_ALL: -+ rtw_write32(Adapter, RWCAM, BIT(31)|BIT(30)); -+ break; -+ case HW_VAR_CAM_WRITE: -+ { -+ u32 cmd; -+ u32 *cam_val = (u32 *)val; -+ rtw_write32(Adapter, WCAMI, cam_val[0]); -+ -+ cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1]; -+ rtw_write32(Adapter, RWCAM, cmd); -+ } -+ break; -+ case HW_VAR_AC_PARAM_VO: -+ rtw_write32(Adapter, REG_EDCA_VO_PARAM, ((u32 *)(val))[0]); -+ break; -+ case HW_VAR_AC_PARAM_VI: -+ rtw_write32(Adapter, REG_EDCA_VI_PARAM, ((u32 *)(val))[0]); -+ break; -+ case HW_VAR_AC_PARAM_BE: -+ haldata->AcParam_BE = ((u32 *)(val))[0]; -+ rtw_write32(Adapter, REG_EDCA_BE_PARAM, ((u32 *)(val))[0]); -+ break; -+ case HW_VAR_AC_PARAM_BK: -+ rtw_write32(Adapter, REG_EDCA_BK_PARAM, ((u32 *)(val))[0]); -+ break; -+ case HW_VAR_ACM_CTRL: -+ { -+ u8 acm_ctrl = *((u8 *)val); -+ u8 AcmCtrl = rtw_read8(Adapter, REG_ACMHWCTRL); -+ -+ if (acm_ctrl > 1) -+ AcmCtrl = AcmCtrl | 0x1; -+ -+ if (acm_ctrl & BIT(3)) -+ AcmCtrl |= AcmHw_VoqEn; -+ else -+ AcmCtrl &= (~AcmHw_VoqEn); -+ -+ if (acm_ctrl & BIT(2)) -+ AcmCtrl |= AcmHw_ViqEn; -+ else -+ AcmCtrl &= (~AcmHw_ViqEn); -+ -+ if (acm_ctrl & BIT(1)) -+ AcmCtrl |= AcmHw_BeqEn; -+ else -+ AcmCtrl &= (~AcmHw_BeqEn); -+ -+ DBG_88E("[HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl); -+ rtw_write8(Adapter, REG_ACMHWCTRL, AcmCtrl); -+ } -+ break; -+ case HW_VAR_AMPDU_MIN_SPACE: -+ { -+ u8 MinSpacingToSet; -+ u8 SecMinSpace; -+ -+ MinSpacingToSet = *((u8 *)val); -+ if (MinSpacingToSet <= 7) { -+ switch (Adapter->securitypriv.dot11PrivacyAlgrthm) { -+ case _NO_PRIVACY_: -+ case _AES_: -+ SecMinSpace = 0; -+ break; -+ case _WEP40_: -+ case _WEP104_: -+ case _TKIP_: -+ case _TKIP_WTMIC_: -+ SecMinSpace = 6; -+ break; -+ default: -+ SecMinSpace = 7; -+ break; -+ } -+ if (MinSpacingToSet < SecMinSpace) -+ MinSpacingToSet = SecMinSpace; -+ rtw_write8(Adapter, REG_AMPDU_MIN_SPACE, (rtw_read8(Adapter, REG_AMPDU_MIN_SPACE) & 0xf8) | MinSpacingToSet); -+ } -+ } -+ break; -+ case HW_VAR_AMPDU_FACTOR: -+ { -+ u8 RegToSet_Normal[4] = {0x41, 0xa8, 0x72, 0xb9}; -+ u8 FactorToSet; -+ u8 *pRegToSet; -+ u8 index = 0; -+ -+ pRegToSet = RegToSet_Normal; /* 0xb972a841; */ -+ FactorToSet = *((u8 *)val); -+ if (FactorToSet <= 3) { -+ FactorToSet = (1<<(FactorToSet + 2)); -+ if (FactorToSet > 0xf) -+ FactorToSet = 0xf; -+ -+ for (index = 0; index < 4; index++) { -+ if ((pRegToSet[index] & 0xf0) > (FactorToSet<<4)) -+ pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet<<4); -+ -+ if ((pRegToSet[index] & 0x0f) > FactorToSet) -+ pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet); -+ -+ rtw_write8(Adapter, (REG_AGGLEN_LMT+index), pRegToSet[index]); -+ } -+ } -+ } -+ break; -+ case HW_VAR_RXDMA_AGG_PG_TH: -+ { -+ u8 threshold = *((u8 *)val); -+ if (threshold == 0) -+ threshold = haldata->UsbRxAggPageCount; -+ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, threshold); -+ } -+ break; -+ case HW_VAR_SET_RPWM: -+ break; -+ case HW_VAR_H2C_FW_PWRMODE: -+ { -+ u8 psmode = (*(u8 *)val); -+ -+ /* Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power */ -+ /* saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. */ -+ if ((psmode != PS_MODE_ACTIVE) && (!IS_92C_SERIAL(haldata->VersionID))) -+ ODM_RF_Saving(podmpriv, true); -+ rtl8188e_set_FwPwrMode_cmd(Adapter, psmode); -+ } -+ break; -+ case HW_VAR_H2C_FW_JOINBSSRPT: -+ { -+ u8 mstatus = (*(u8 *)val); -+ rtl8188e_set_FwJoinBssReport_cmd(Adapter, mstatus); -+ } -+ break; -+#ifdef CONFIG_88EU_P2P -+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: -+ { -+ u8 p2p_ps_state = (*(u8 *)val); -+ rtl8188e_set_p2p_ps_offload_cmd(Adapter, p2p_ps_state); -+ } -+ break; -+#endif -+ case HW_VAR_INITIAL_GAIN: -+ { -+ struct rtw_dig *pDigTable = &podmpriv->DM_DigTable; -+ u32 rx_gain = ((u32 *)(val))[0]; -+ -+ if (rx_gain == 0xff) {/* restore rx gain */ -+ ODM_Write_DIG(podmpriv, pDigTable->BackupIGValue); -+ } else { -+ pDigTable->BackupIGValue = pDigTable->CurIGValue; -+ ODM_Write_DIG(podmpriv, rx_gain); -+ } -+ } -+ break; -+ case HW_VAR_TRIGGER_GPIO_0: -+ rtl8192cu_trigger_gpio_0(Adapter); -+ break; -+ case HW_VAR_RPT_TIMER_SETTING: -+ { -+ u16 min_rpt_time = (*(u16 *)val); -+ ODM_RA_Set_TxRPT_Time(podmpriv, min_rpt_time); -+ } -+ break; -+ case HW_VAR_ANTENNA_DIVERSITY_SELECT: -+ { -+ u8 Optimum_antenna = (*(u8 *)val); -+ u8 Ant; -+ /* switch antenna to Optimum_antenna */ -+ if (haldata->CurAntenna != Optimum_antenna) { -+ Ant = (Optimum_antenna == 2) ? MAIN_ANT : AUX_ANT; -+ ODM_UpdateRxIdleAnt_88E(&haldata->odmpriv, Ant); -+ -+ haldata->CurAntenna = Optimum_antenna; -+ } -+ } -+ break; -+ case HW_VAR_EFUSE_BYTES: /* To set EFUE total used bytes, added by Roger, 2008.12.22. */ -+ haldata->EfuseUsedBytes = *((u16 *)val); -+ break; -+ case HW_VAR_FIFO_CLEARN_UP: -+ { -+ struct pwrctrl_priv *pwrpriv = &Adapter->pwrctrlpriv; -+ u8 trycnt = 100; -+ -+ /* pause tx */ -+ rtw_write8(Adapter, REG_TXPAUSE, 0xff); -+ -+ /* keep sn */ -+ Adapter->xmitpriv.nqos_ssn = rtw_read16(Adapter, REG_NQOS_SEQ); -+ -+ if (!pwrpriv->bkeepfwalive) { -+ /* RX DMA stop */ -+ rtw_write32(Adapter, REG_RXPKT_NUM, (rtw_read32(Adapter, REG_RXPKT_NUM)|RW_RELEASE_EN)); -+ do { -+ if (!(rtw_read32(Adapter, REG_RXPKT_NUM)&RXDMA_IDLE)) -+ break; -+ } while (trycnt--); -+ if (trycnt == 0) -+ DBG_88E("Stop RX DMA failed......\n"); -+ -+ /* RQPN Load 0 */ -+ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0); -+ rtw_write32(Adapter, REG_RQPN, 0x80000000); -+ rtw_mdelay_os(10); -+ } -+ } -+ break; -+ case HW_VAR_CHECK_TXBUF: -+ break; -+ case HW_VAR_APFM_ON_MAC: -+ haldata->bMacPwrCtrlOn = *val; -+ DBG_88E("%s: bMacPwrCtrlOn=%d\n", __func__, haldata->bMacPwrCtrlOn); -+ break; -+ case HW_VAR_TX_RPT_MAX_MACID: -+ { -+ u8 maxMacid = *val; -+ DBG_88E("### MacID(%d),Set Max Tx RPT MID(%d)\n", maxMacid, maxMacid+1); -+ rtw_write8(Adapter, REG_TX_RPT_CTRL+1, maxMacid+1); -+ } -+ break; -+ case HW_VAR_H2C_MEDIA_STATUS_RPT: -+ rtl8188e_set_FwMediaStatus_cmd(Adapter , (*(__le16 *)val)); -+ break; -+ case HW_VAR_BCN_VALID: -+ /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw */ -+ rtw_write8(Adapter, REG_TDECTRL+2, rtw_read8(Adapter, REG_TDECTRL+2) | BIT0); -+ break; -+ default: -+ break; -+ } -+ -+} -+ -+static void GetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ struct odm_dm_struct *podmpriv = &haldata->odmpriv; -+ -+ switch (variable) { -+ case HW_VAR_BASIC_RATE: -+ *((u16 *)(val)) = haldata->BasicRateSet; -+ case HW_VAR_TXPAUSE: -+ val[0] = rtw_read8(Adapter, REG_TXPAUSE); -+ break; -+ case HW_VAR_BCN_VALID: -+ /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */ -+ val[0] = (BIT0 & rtw_read8(Adapter, REG_TDECTRL+2)) ? true : false; -+ break; -+ case HW_VAR_DM_FLAG: -+ val[0] = podmpriv->SupportAbility; -+ break; -+ case HW_VAR_RF_TYPE: -+ val[0] = haldata->rf_type; -+ break; -+ case HW_VAR_FWLPS_RF_ON: -+ { -+ /* When we halt NIC, we should check if FW LPS is leave. */ -+ if (Adapter->pwrctrlpriv.rf_pwrstate == rf_off) { -+ /* If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */ -+ /* because Fw is unload. */ -+ val[0] = true; -+ } else { -+ u32 valRCR; -+ valRCR = rtw_read32(Adapter, REG_RCR); -+ valRCR &= 0x00070000; -+ if (valRCR) -+ val[0] = false; -+ else -+ val[0] = true; -+ } -+ } -+ break; -+ case HW_VAR_CURRENT_ANTENNA: -+ val[0] = haldata->CurAntenna; -+ break; -+ case HW_VAR_EFUSE_BYTES: /* To get EFUE total used bytes, added by Roger, 2008.12.22. */ -+ *((u16 *)(val)) = haldata->EfuseUsedBytes; -+ break; -+ case HW_VAR_APFM_ON_MAC: -+ *val = haldata->bMacPwrCtrlOn; -+ break; -+ case HW_VAR_CHK_HI_QUEUE_EMPTY: -+ *val = ((rtw_read32(Adapter, REG_HGQ_INFORMATION)&0x0000ff00) == 0) ? true : false; -+ break; -+ default: -+ break; -+ } -+ -+} -+ -+/* */ -+/* Description: */ -+/* Query setting of specified variable. */ -+/* */ -+static u8 -+GetHalDefVar8188EUsb( -+ struct adapter *Adapter, -+ enum hal_def_variable eVariable, -+ void *pValue -+ ) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ u8 bResult = _SUCCESS; -+ -+ switch (eVariable) { -+ case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: -+ { -+ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; -+ struct sta_priv *pstapriv = &Adapter->stapriv; -+ struct sta_info *psta; -+ psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress); -+ if (psta) -+ *((int *)pValue) = psta->rssi_stat.UndecoratedSmoothedPWDB; -+ } -+ break; -+ case HAL_DEF_IS_SUPPORT_ANT_DIV: -+ *((u8 *)pValue) = (haldata->AntDivCfg == 0) ? false : true; -+ break; -+ case HAL_DEF_CURRENT_ANTENNA: -+ *((u8 *)pValue) = haldata->CurAntenna; -+ break; -+ case HAL_DEF_DRVINFO_SZ: -+ *((u32 *)pValue) = DRVINFO_SZ; -+ break; -+ case HAL_DEF_MAX_RECVBUF_SZ: -+ *((u32 *)pValue) = MAX_RECVBUF_SZ; -+ break; -+ case HAL_DEF_RX_PACKET_OFFSET: -+ *((u32 *)pValue) = RXDESC_SIZE + DRVINFO_SZ; -+ break; -+ case HAL_DEF_DBG_DM_FUNC: -+ *((u32 *)pValue) = haldata->odmpriv.SupportAbility; -+ break; -+ case HAL_DEF_RA_DECISION_RATE: -+ { -+ u8 MacID = *((u8 *)pValue); -+ *((u8 *)pValue) = ODM_RA_GetDecisionRate_8188E(&(haldata->odmpriv), MacID); -+ } -+ break; -+ case HAL_DEF_RA_SGI: -+ { -+ u8 MacID = *((u8 *)pValue); -+ *((u8 *)pValue) = ODM_RA_GetShortGI_8188E(&(haldata->odmpriv), MacID); -+ } -+ break; -+ case HAL_DEF_PT_PWR_STATUS: -+ { -+ u8 MacID = *((u8 *)pValue); -+ *((u8 *)pValue) = ODM_RA_GetHwPwrStatus_8188E(&(haldata->odmpriv), MacID); -+ } -+ break; -+ case HW_VAR_MAX_RX_AMPDU_FACTOR: -+ *((u32 *)pValue) = MAX_AMPDU_FACTOR_64K; -+ break; -+ case HW_DEF_RA_INFO_DUMP: -+ { -+ u8 entry_id = *((u8 *)pValue); -+ if (check_fwstate(&Adapter->mlmepriv, _FW_LINKED)) { -+ DBG_88E("============ RA status check ===================\n"); -+ DBG_88E("Mac_id:%d , RateID = %d, RAUseRate = 0x%08x, RateSGI = %d, DecisionRate = 0x%02x ,PTStage = %d\n", -+ entry_id, -+ haldata->odmpriv.RAInfo[entry_id].RateID, -+ haldata->odmpriv.RAInfo[entry_id].RAUseRate, -+ haldata->odmpriv.RAInfo[entry_id].RateSGI, -+ haldata->odmpriv.RAInfo[entry_id].DecisionRate, -+ haldata->odmpriv.RAInfo[entry_id].PTStage); -+ } -+ } -+ break; -+ case HW_DEF_ODM_DBG_FLAG: -+ { -+ struct odm_dm_struct *dm_ocm = &(haldata->odmpriv); -+ pr_info("dm_ocm->DebugComponents = 0x%llx\n", dm_ocm->DebugComponents); -+ } -+ break; -+ case HAL_DEF_DBG_DUMP_RXPKT: -+ *((u8 *)pValue) = haldata->bDumpRxPkt; -+ break; -+ case HAL_DEF_DBG_DUMP_TXPKT: -+ *((u8 *)pValue) = haldata->bDumpTxPkt; -+ break; -+ default: -+ bResult = _FAIL; -+ break; -+ } -+ -+ return bResult; -+} -+ -+/* */ -+/* Description: */ -+/* Change default setting of specified variable. */ -+/* */ -+static u8 SetHalDefVar8188EUsb(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); -+ u8 bResult = _SUCCESS; -+ -+ switch (eVariable) { -+ case HAL_DEF_DBG_DM_FUNC: -+ { -+ u8 dm_func = *((u8 *)pValue); -+ struct odm_dm_struct *podmpriv = &haldata->odmpriv; -+ -+ if (dm_func == 0) { /* disable all dynamic func */ -+ podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE; -+ DBG_88E("==> Disable all dynamic function...\n"); -+ } else if (dm_func == 1) {/* disable DIG */ -+ podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG); -+ DBG_88E("==> Disable DIG...\n"); -+ } else if (dm_func == 2) {/* disable High power */ -+ podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); -+ } else if (dm_func == 3) {/* disable tx power tracking */ -+ podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); -+ DBG_88E("==> Disable tx power tracking...\n"); -+ } else if (dm_func == 5) {/* disable antenna diversity */ -+ podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); -+ } else if (dm_func == 6) {/* turn on all dynamic func */ -+ if (!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) { -+ struct rtw_dig *pDigTable = &podmpriv->DM_DigTable; -+ pDigTable->CurIGValue = rtw_read8(Adapter, 0xc50); -+ } -+ podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; -+ DBG_88E("==> Turn on all dynamic function...\n"); -+ } -+ } -+ break; -+ case HAL_DEF_DBG_DUMP_RXPKT: -+ haldata->bDumpRxPkt = *((u8 *)pValue); -+ break; -+ case HAL_DEF_DBG_DUMP_TXPKT: -+ haldata->bDumpTxPkt = *((u8 *)pValue); -+ break; -+ case HW_DEF_FA_CNT_DUMP: -+ { -+ u8 bRSSIDump = *((u8 *)pValue); -+ struct odm_dm_struct *dm_ocm = &(haldata->odmpriv); -+ if (bRSSIDump) -+ dm_ocm->DebugComponents = ODM_COMP_DIG|ODM_COMP_FA_CNT ; -+ else -+ dm_ocm->DebugComponents = 0; -+ } -+ break; -+ case HW_DEF_ODM_DBG_FLAG: -+ { -+ u64 DebugComponents = *((u64 *)pValue); -+ struct odm_dm_struct *dm_ocm = &(haldata->odmpriv); -+ dm_ocm->DebugComponents = DebugComponents; -+ } -+ break; -+ default: -+ bResult = _FAIL; -+ break; -+ } -+ -+ return bResult; -+} -+ -+static void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level) -+{ -+ u8 init_rate = 0; -+ u8 networkType, raid; -+ u32 mask, rate_bitmap; -+ u8 shortGIrate = false; -+ int supportRateNum = 0; -+ struct sta_info *psta; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); -+ -+ if (mac_id >= NUM_STA) /* CAM_SIZE */ -+ return; -+ psta = pmlmeinfo->FW_sta_info[mac_id].psta; -+ if (psta == NULL) -+ return; -+ switch (mac_id) { -+ case 0:/* for infra mode */ -+ supportRateNum = rtw_get_rateset_len(cur_network->SupportedRates); -+ networkType = judge_network_type(adapt, cur_network->SupportedRates, supportRateNum) & 0xf; -+ raid = networktype_to_raid(networkType); -+ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); -+ mask |= (pmlmeinfo->HT_enable) ? update_MSC_rate(&(pmlmeinfo->HT_caps)) : 0; -+ if (support_short_GI(adapt, &(pmlmeinfo->HT_caps))) -+ shortGIrate = true; -+ break; -+ case 1:/* for broadcast/multicast */ -+ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); -+ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) -+ networkType = WIRELESS_11B; -+ else -+ networkType = WIRELESS_11G; -+ raid = networktype_to_raid(networkType); -+ mask = update_basic_rate(cur_network->SupportedRates, supportRateNum); -+ break; -+ default: /* for each sta in IBSS */ -+ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); -+ networkType = judge_network_type(adapt, pmlmeinfo->FW_sta_info[mac_id].SupportedRates, supportRateNum) & 0xf; -+ raid = networktype_to_raid(networkType); -+ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); -+ -+ /* todo: support HT in IBSS */ -+ break; -+ } -+ -+ rate_bitmap = 0x0fffffff; -+ rate_bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, mac_id, mask, rssi_level); -+ DBG_88E("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n", -+ __func__, mac_id, networkType, mask, rssi_level, rate_bitmap); -+ -+ mask &= rate_bitmap; -+ -+ init_rate = get_highest_rate_idx(mask)&0x3f; -+ -+ if (haldata->fw_ractrl) { -+ u8 arg; -+ -+ arg = mac_id & 0x1f;/* MACID */ -+ arg |= BIT(7); -+ if (shortGIrate) -+ arg |= BIT(5); -+ mask |= ((raid << 28) & 0xf0000000); -+ DBG_88E("update raid entry, mask=0x%x, arg=0x%x\n", mask, arg); -+ psta->ra_mask = mask; -+ mask |= ((raid << 28) & 0xf0000000); -+ -+ /* to do ,for 8188E-SMIC */ -+ rtl8188e_set_raid_cmd(adapt, mask); -+ } else { -+ ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv), -+ mac_id, -+ raid, -+ mask, -+ shortGIrate -+ ); -+ } -+ /* set ra_id */ -+ psta->raid = raid; -+ psta->init_rate = init_rate; -+} -+ -+static void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt) -+{ -+ u32 value32; -+ struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv); -+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); -+ u32 bcn_ctrl_reg = REG_BCN_CTRL; -+ /* reset TSF, enable update TSF, correcting TSF On Beacon */ -+ -+ /* BCN interval */ -+ rtw_write16(adapt, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval); -+ rtw_write8(adapt, REG_ATIMWND, 0x02);/* 2ms */ -+ -+ _InitBeaconParameters(adapt); -+ -+ rtw_write8(adapt, REG_SLOT, 0x09); -+ -+ value32 = rtw_read32(adapt, REG_TCR); -+ value32 &= ~TSFRST; -+ rtw_write32(adapt, REG_TCR, value32); -+ -+ value32 |= TSFRST; -+ rtw_write32(adapt, REG_TCR, value32); -+ -+ /* NOTE: Fix test chip's bug (about contention windows's randomness) */ -+ rtw_write8(adapt, REG_RXTSF_OFFSET_CCK, 0x50); -+ rtw_write8(adapt, REG_RXTSF_OFFSET_OFDM, 0x50); -+ -+ _BeaconFunctionEnable(adapt, true, true); -+ -+ ResumeTxBeacon(adapt); -+ -+ rtw_write8(adapt, bcn_ctrl_reg, rtw_read8(adapt, bcn_ctrl_reg)|BIT(1)); -+} -+ -+static void rtl8188eu_init_default_value(struct adapter *adapt) -+{ -+ struct hal_data_8188e *haldata; -+ struct pwrctrl_priv *pwrctrlpriv; -+ u8 i; -+ -+ haldata = GET_HAL_DATA(adapt); -+ pwrctrlpriv = &adapt->pwrctrlpriv; -+ -+ /* init default value */ -+ haldata->fw_ractrl = false; -+ if (!pwrctrlpriv->bkeepfwalive) -+ haldata->LastHMEBoxNum = 0; -+ -+ /* init dm default value */ -+ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = false; -+ haldata->odmpriv.RFCalibrateInfo.TM_Trigger = 0;/* for IQK */ -+ haldata->pwrGroupCnt = 0; -+ haldata->PGMaxGroup = 13; -+ haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP_index = 0; -+ for (i = 0; i < HP_THERMAL_NUM; i++) -+ haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP[i] = 0; -+} -+ -+static u8 rtl8188eu_ps_func(struct adapter *Adapter, enum hal_intf_ps_func efunc_id, u8 *val) -+{ -+ u8 bResult = true; -+ return bResult; -+} -+ -+void rtl8188eu_set_hal_ops(struct adapter *adapt) -+{ -+ struct hal_ops *halfunc = &adapt->HalFunc; -+ -+ adapt->HalData = rtw_zmalloc(sizeof(struct hal_data_8188e)); -+ if (adapt->HalData == NULL) -+ DBG_88E("cant not alloc memory for HAL DATA\n"); -+ adapt->hal_data_sz = sizeof(struct hal_data_8188e); -+ -+ halfunc->hal_power_on = rtl8188eu_InitPowerOn; -+ halfunc->hal_init = &rtl8188eu_hal_init; -+ halfunc->hal_deinit = &rtl8188eu_hal_deinit; -+ -+ halfunc->inirp_init = &rtl8188eu_inirp_init; -+ halfunc->inirp_deinit = &rtl8188eu_inirp_deinit; -+ -+ halfunc->init_xmit_priv = &rtl8188eu_init_xmit_priv; -+ halfunc->free_xmit_priv = &rtl8188eu_free_xmit_priv; -+ -+ halfunc->init_recv_priv = &rtl8188eu_init_recv_priv; -+ halfunc->free_recv_priv = &rtl8188eu_free_recv_priv; -+ halfunc->InitSwLeds = &rtl8188eu_InitSwLeds; -+ halfunc->DeInitSwLeds = &rtl8188eu_DeInitSwLeds; -+ -+ halfunc->init_default_value = &rtl8188eu_init_default_value; -+ halfunc->intf_chip_configure = &rtl8188eu_interface_configure; -+ halfunc->read_adapter_info = &ReadAdapterInfo8188EU; -+ -+ halfunc->SetHwRegHandler = &SetHwReg8188EU; -+ halfunc->GetHwRegHandler = &GetHwReg8188EU; -+ halfunc->GetHalDefVarHandler = &GetHalDefVar8188EUsb; -+ halfunc->SetHalDefVarHandler = &SetHalDefVar8188EUsb; -+ -+ halfunc->UpdateRAMaskHandler = &UpdateHalRAMask8188EUsb; -+ halfunc->SetBeaconRelatedRegistersHandler = &SetBeaconRelatedRegisters8188EUsb; -+ -+ halfunc->hal_xmit = &rtl8188eu_hal_xmit; -+ halfunc->mgnt_xmit = &rtl8188eu_mgnt_xmit; -+ -+ halfunc->interface_ps_func = &rtl8188eu_ps_func; -+ -+ rtl8188e_set_hal_ops(halfunc); -+ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hal/usb_ops_linux.c b/drivers/net/wireless/rtl8188eu/hal/usb_ops_linux.c -new file mode 100644 -index 0000000000000..c89c067d434a6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hal/usb_ops_linux.c -@@ -0,0 +1,716 @@ -+/****************************************************************************** -+ * -+ * Copyright(c) 2007 - 2011 Realtek 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 -+ * -+ * -+ ******************************************************************************/ -+#define _HCI_OPS_OS_C_ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype) -+{ -+ struct adapter *adapt = pintfhdl->padapter; -+ struct dvobj_priv *dvobjpriv = adapter_to_dvobj(adapt); -+ struct usb_device *udev = dvobjpriv->pusbdev; -+ unsigned int pipe; -+ int status = 0; -+ u8 reqtype; -+ u8 *pIo_buf; -+ int vendorreq_times = 0; -+ -+ if ((adapt->bSurpriseRemoved) || (adapt->pwrctrlpriv.pnp_bstop_trx)) { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usbctrl_vendorreq:(adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); -+ status = -EPERM; -+ goto exit; -+ } -+ -+ if (len > MAX_VENDOR_REQ_CMD_SIZE) { -+ DBG_88E("[%s] Buffer len error ,vendor request failed\n", __func__); -+ status = -EINVAL; -+ goto exit; -+ } -+ -+ _enter_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL); -+ -+ /* Acquire IO memory for vendorreq */ -+ pIo_buf = dvobjpriv->usb_vendor_req_buf; -+ -+ if (pIo_buf == NULL) { -+ DBG_88E("[%s] pIo_buf == NULL\n", __func__); -+ status = -ENOMEM; -+ goto release_mutex; -+ } -+ -+ while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) { -+ memset(pIo_buf, 0, len); -+ -+ if (requesttype == 0x01) { -+ pipe = usb_rcvctrlpipe(udev, 0);/* read_in */ -+ reqtype = REALTEK_USB_VENQT_READ; -+ } else { -+ pipe = usb_sndctrlpipe(udev, 0);/* write_out */ -+ reqtype = REALTEK_USB_VENQT_WRITE; -+ memcpy(pIo_buf, pdata, len); -+ } -+ -+ status = rtw_usb_control_msg(udev, pipe, request, reqtype, value, index, pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT); -+ -+ if (status == len) { /* Success this control transfer. */ -+ rtw_reset_continual_urb_error(dvobjpriv); -+ if (requesttype == 0x01) -+ memcpy(pdata, pIo_buf, len); -+ } else { /* error cases */ -+ DBG_88E("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n", -+ value, (requesttype == 0x01) ? "read" : "write", -+ len, status, *(u32 *)pdata, vendorreq_times); -+ -+ if (status < 0) { -+ if (status == (-ESHUTDOWN) || status == -ENODEV) { -+ adapt->bSurpriseRemoved = true; -+ } else { -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ haldata->srestpriv.Wifi_Error_Status = USB_VEN_REQ_CMD_FAIL; -+ } -+ } else { /* status != len && status >= 0 */ -+ if (status > 0) { -+ if (requesttype == 0x01) { -+ /* For Control read transfer, we have to copy the read data from pIo_buf to pdata. */ -+ memcpy(pdata, pIo_buf, len); -+ } -+ } -+ } -+ -+ if (rtw_inc_and_chk_continual_urb_error(dvobjpriv)) { -+ adapt->bSurpriseRemoved = true; -+ break; -+ } -+ -+ } -+ -+ /* firmware download is checksumed, don't retry */ -+ if ((value >= FW_8188E_START_ADDRESS && value <= FW_8188E_END_ADDRESS) || status == len) -+ break; -+ } -+release_mutex: -+ _exit_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL); -+exit: -+ return status; -+} -+ -+static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) -+{ -+ u8 request; -+ u8 requesttype; -+ u16 wvalue; -+ u16 index; -+ u16 len; -+ u8 data = 0; -+ -+ -+ -+ request = 0x05; -+ requesttype = 0x01;/* read_in */ -+ index = 0;/* n/a */ -+ -+ wvalue = (u16)(addr&0x0000ffff); -+ len = 1; -+ -+ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); -+ -+ -+ -+ return data; -+ -+} -+ -+static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) -+{ -+ u8 request; -+ u8 requesttype; -+ u16 wvalue; -+ u16 index; -+ u16 len; -+ __le32 data; -+ -+ request = 0x05; -+ requesttype = 0x01;/* read_in */ -+ index = 0;/* n/a */ -+ wvalue = (u16)(addr&0x0000ffff); -+ len = 2; -+ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); -+ -+ return (u16)(le32_to_cpu(data)&0xffff); -+} -+ -+static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) -+{ -+ u8 request; -+ u8 requesttype; -+ u16 wvalue; -+ u16 index; -+ u16 len; -+ __le32 data; -+ -+ request = 0x05; -+ requesttype = 0x01;/* read_in */ -+ index = 0;/* n/a */ -+ -+ wvalue = (u16)(addr&0x0000ffff); -+ len = 4; -+ -+ usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); -+ -+ return le32_to_cpu(data); -+} -+ -+static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) -+{ -+ u8 request; -+ u8 requesttype; -+ u16 wvalue; -+ u16 index; -+ u16 len; -+ u8 data; -+ int ret; -+ -+ -+ request = 0x05; -+ requesttype = 0x00;/* write_out */ -+ index = 0;/* n/a */ -+ wvalue = (u16)(addr&0x0000ffff); -+ len = 1; -+ data = val; -+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); -+ -+ return ret; -+} -+ -+static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) -+{ -+ u8 request; -+ u8 requesttype; -+ u16 wvalue; -+ u16 index; -+ u16 len; -+ __le32 data; -+ int ret; -+ -+ -+ -+ request = 0x05; -+ requesttype = 0x00;/* write_out */ -+ index = 0;/* n/a */ -+ -+ wvalue = (u16)(addr&0x0000ffff); -+ len = 2; -+ -+ data = cpu_to_le32(val & 0x0000ffff); -+ -+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); -+ -+ -+ -+ return ret; -+} -+ -+static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) -+{ -+ u8 request; -+ u8 requesttype; -+ u16 wvalue; -+ u16 index; -+ u16 len; -+ __le32 data; -+ int ret; -+ -+ -+ -+ request = 0x05; -+ requesttype = 0x00;/* write_out */ -+ index = 0;/* n/a */ -+ -+ wvalue = (u16)(addr&0x0000ffff); -+ len = 4; -+ data = cpu_to_le32(val); -+ -+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype); -+ -+ -+ -+ return ret; -+} -+ -+static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata) -+{ -+ u8 request; -+ u8 requesttype; -+ u16 wvalue; -+ u16 index; -+ u16 len; -+ u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0}; -+ int ret; -+ -+ -+ -+ request = 0x05; -+ requesttype = 0x00;/* write_out */ -+ index = 0;/* n/a */ -+ -+ wvalue = (u16)(addr&0x0000ffff); -+ len = length; -+ memcpy(buf, pdata, len); -+ -+ ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype); -+ -+ -+ -+ return ret; -+} -+ -+static void interrupt_handler_8188eu(struct adapter *adapt, u16 pkt_len, u8 *pbuf) -+{ -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ -+ if (pkt_len != INTERRUPT_MSG_FORMAT_LEN) { -+ DBG_88E("%s Invalid interrupt content length (%d)!\n", __func__, pkt_len); -+ return; -+ } -+ -+ /* HISR */ -+ memcpy(&(haldata->IntArray[0]), &(pbuf[USB_INTR_CONTENT_HISR_OFFSET]), 4); -+ memcpy(&(haldata->IntArray[1]), &(pbuf[USB_INTR_CONTENT_HISRE_OFFSET]), 4); -+ -+ /* C2H Event */ -+ if (pbuf[0] != 0) -+ memcpy(&(haldata->C2hArray[0]), &(pbuf[USB_INTR_CONTENT_C2H_OFFSET]), 16); -+} -+ -+static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb) -+{ -+ u8 *pbuf; -+ u8 shift_sz = 0; -+ u16 pkt_cnt; -+ u32 pkt_offset, skb_len, alloc_sz; -+ s32 transfer_len; -+ struct recv_stat *prxstat; -+ struct phy_stat *pphy_status = NULL; -+ struct sk_buff *pkt_copy = NULL; -+ struct recv_frame *precvframe = NULL; -+ struct rx_pkt_attrib *pattrib = NULL; -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ struct recv_priv *precvpriv = &adapt->recvpriv; -+ struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue; -+ -+ transfer_len = (s32)pskb->len; -+ pbuf = pskb->data; -+ -+ prxstat = (struct recv_stat *)pbuf; -+ pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff; -+ -+ do { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, -+ ("recvbuf2recvframe: rxdesc=offsset 0:0x%08x, 4:0x%08x, 8:0x%08x, C:0x%08x\n", -+ prxstat->rxdw0, prxstat->rxdw1, prxstat->rxdw2, prxstat->rxdw4)); -+ -+ prxstat = (struct recv_stat *)pbuf; -+ -+ precvframe = rtw_alloc_recvframe(pfree_recv_queue); -+ if (precvframe == NULL) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvbuf2recvframe: precvframe==NULL\n")); -+ DBG_88E("%s()-%d: rtw_alloc_recvframe() failed! RX Drop!\n", __func__, __LINE__); -+ goto _exit_recvbuf2recvframe; -+ } -+ -+ INIT_LIST_HEAD(&precvframe->list); -+ precvframe->precvbuf = NULL; /* can't access the precvbuf for new arch. */ -+ precvframe->len = 0; -+ -+ update_recvframe_attrib_88e(precvframe, prxstat); -+ -+ pattrib = &precvframe->attrib; -+ -+ if ((pattrib->crc_err) || (pattrib->icv_err)) { -+ DBG_88E("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err); -+ -+ rtw_free_recvframe(precvframe, pfree_recv_queue); -+ goto _exit_recvbuf2recvframe; -+ } -+ -+ if ((pattrib->physt) && (pattrib->pkt_rpt_type == NORMAL_RX)) -+ pphy_status = (struct phy_stat *)(pbuf + RXDESC_OFFSET); -+ -+ pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->shift_sz + pattrib->pkt_len; -+ -+ if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recvbuf2recvframe: pkt_len<=0\n")); -+ DBG_88E("%s()-%d: RX Warning!,pkt_len<=0 or pkt_offset> transfoer_len\n", __func__, __LINE__); -+ rtw_free_recvframe(precvframe, pfree_recv_queue); -+ goto _exit_recvbuf2recvframe; -+ } -+ -+ /* Modified by Albert 20101213 */ -+ /* For 8 bytes IP header alignment. */ -+ if (pattrib->qos) /* Qos data, wireless lan header length is 26 */ -+ shift_sz = 6; -+ else -+ shift_sz = 0; -+ -+ skb_len = pattrib->pkt_len; -+ -+ /* for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. */ -+ /* modify alloc_sz for recvive crc error packet by thomas 2011-06-02 */ -+ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) { -+ if (skb_len <= 1650) -+ alloc_sz = 1664; -+ else -+ alloc_sz = skb_len + 14; -+ } else { -+ alloc_sz = skb_len; -+ /* 6 is for IP header 8 bytes alignment in QoS packet case. */ -+ /* 8 is for skb->data 4 bytes alignment. */ -+ alloc_sz += 14; -+ } -+ -+ pkt_copy = netdev_alloc_skb(adapt->pnetdev, alloc_sz); -+ if (pkt_copy) { -+ pkt_copy->dev = adapt->pnetdev; -+ precvframe->pkt = pkt_copy; -+ precvframe->rx_head = pkt_copy->data; -+ precvframe->rx_end = pkt_copy->data + alloc_sz; -+ skb_reserve(pkt_copy, 8 - ((size_t)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */ -+ skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */ -+ memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len); -+ precvframe->rx_tail = pkt_copy->data; -+ precvframe->rx_data = pkt_copy->data; -+ } else { -+ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) { -+ DBG_88E("recvbuf2recvframe: alloc_skb fail , drop frag frame\n"); -+ rtw_free_recvframe(precvframe, pfree_recv_queue); -+ goto _exit_recvbuf2recvframe; -+ } -+ precvframe->pkt = skb_clone(pskb, GFP_ATOMIC); -+ if (precvframe->pkt) { -+ precvframe->rx_tail = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE; -+ precvframe->rx_head = precvframe->rx_tail; -+ precvframe->rx_data = precvframe->rx_tail; -+ precvframe->rx_end = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE + alloc_sz; -+ } else { -+ DBG_88E("recvbuf2recvframe: skb_clone fail\n"); -+ rtw_free_recvframe(precvframe, pfree_recv_queue); -+ goto _exit_recvbuf2recvframe; -+ } -+ } -+ -+ recvframe_put(precvframe, skb_len); -+ -+ switch (haldata->UsbRxAggMode) { -+ case USB_RX_AGG_DMA: -+ case USB_RX_AGG_MIX: -+ pkt_offset = (u16)_RND128(pkt_offset); -+ break; -+ case USB_RX_AGG_USB: -+ pkt_offset = (u16)_RND4(pkt_offset); -+ break; -+ case USB_RX_AGG_DISABLE: -+ default: -+ break; -+ } -+ if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */ -+ if (pattrib->physt) -+ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat *)pphy_status); -+ if (rtw_recv_entry(precvframe) != _SUCCESS) { -+ RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, -+ ("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n")); -+ } -+ } else { -+ /* enqueue recvframe to txrtp queue */ -+ if (pattrib->pkt_rpt_type == TX_REPORT1) { -+ /* CCX-TXRPT ack for xmit mgmt frames. */ -+ handle_txrpt_ccx_88e(adapt, precvframe->rx_data); -+ } else if (pattrib->pkt_rpt_type == TX_REPORT2) { -+ ODM_RA_TxRPT2Handle_8188E( -+ &haldata->odmpriv, -+ precvframe->rx_data, -+ pattrib->pkt_len, -+ pattrib->MacIDValidEntry[0], -+ pattrib->MacIDValidEntry[1] -+ ); -+ } else if (pattrib->pkt_rpt_type == HIS_REPORT) { -+ interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->rx_data); -+ } -+ rtw_free_recvframe(precvframe, pfree_recv_queue); -+ } -+ pkt_cnt--; -+ transfer_len -= pkt_offset; -+ pbuf += pkt_offset; -+ precvframe = NULL; -+ pkt_copy = NULL; -+ -+ if (transfer_len > 0 && pkt_cnt == 0) -+ pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff; -+ -+ } while ((transfer_len > 0) && (pkt_cnt > 0)); -+ -+_exit_recvbuf2recvframe: -+ -+ return _SUCCESS; -+} -+ -+void rtl8188eu_recv_tasklet(void *priv) -+{ -+ struct sk_buff *pskb; -+ struct adapter *adapt = (struct adapter *)priv; -+ struct recv_priv *precvpriv = &adapt->recvpriv; -+ -+ while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) { -+ if ((adapt->bDriverStopped) || (adapt->bSurpriseRemoved)) { -+ DBG_88E("recv_tasklet => bDriverStopped or bSurpriseRemoved\n"); -+ dev_kfree_skb_any(pskb); -+ break; -+ } -+ recvbuf2recvframe(adapt, pskb); -+ skb_reset_tail_pointer(pskb); -+ pskb->len = 0; -+ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); -+ } -+} -+ -+static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) -+{ -+ struct recv_buf *precvbuf = (struct recv_buf *)purb->context; -+ struct adapter *adapt = (struct adapter *)precvbuf->adapter; -+ struct recv_priv *precvpriv = &adapt->recvpriv; -+ -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete!!!\n")); -+ -+ precvpriv->rx_pending_cnt--; -+ -+ if (adapt->bSurpriseRemoved || adapt->bDriverStopped || adapt->bReadPortCancel) { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, -+ ("usb_read_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n", -+ adapt->bDriverStopped, adapt->bSurpriseRemoved)); -+ -+ precvbuf->reuse = true; -+ DBG_88E("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n", -+ __func__, adapt->bDriverStopped, -+ adapt->bSurpriseRemoved, adapt->bReadPortCancel); -+ return; -+ } -+ -+ if (purb->status == 0) { /* SUCCESS */ -+ if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, -+ ("usb_read_port_complete: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n")); -+ precvbuf->reuse = true; -+ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); -+ DBG_88E("%s()-%d: RX Warning!\n", __func__, __LINE__); -+ } else { -+ rtw_reset_continual_urb_error(adapter_to_dvobj(adapt)); -+ -+ precvbuf->transfer_len = purb->actual_length; -+ skb_put(precvbuf->pskb, purb->actual_length); -+ skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb); -+ -+ if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1) -+ tasklet_schedule(&precvpriv->recv_tasklet); -+ -+ precvbuf->pskb = NULL; -+ precvbuf->reuse = false; -+ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); -+ } -+ } else { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete : purb->status(%d) != 0\n", purb->status)); -+ -+ DBG_88E("###=> usb_read_port_complete => urb status(%d)\n", purb->status); -+ skb_put(precvbuf->pskb, purb->actual_length); -+ precvbuf->pskb = NULL; -+ -+ if (rtw_inc_and_chk_continual_urb_error(adapter_to_dvobj(adapt))) -+ adapt->bSurpriseRemoved = true; -+ -+ switch (purb->status) { -+ case -EINVAL: -+ case -EPIPE: -+ case -ENODEV: -+ case -ESHUTDOWN: -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete:bSurpriseRemoved=true\n")); -+ case -ENOENT: -+ adapt->bDriverStopped = true; -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete:bDriverStopped=true\n")); -+ break; -+ case -EPROTO: -+ case -EOVERFLOW: -+ { -+ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); -+ haldata->srestpriv.Wifi_Error_Status = USB_READ_PORT_FAIL; -+ } -+ precvbuf->reuse = true; -+ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); -+ break; -+ case -EINPROGRESS: -+ DBG_88E("ERROR: URB IS IN PROGRESS!/n"); -+ break; -+ default: -+ break; -+ } -+ } -+} -+ -+static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) -+{ -+ struct urb *purb = NULL; -+ struct recv_buf *precvbuf = (struct recv_buf *)rmem; -+ struct adapter *adapter = pintfhdl->padapter; -+ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); -+ struct recv_priv *precvpriv = &adapter->recvpriv; -+ struct usb_device *pusbd = pdvobj->pusbdev; -+ int err; -+ unsigned int pipe; -+ size_t tmpaddr = 0; -+ size_t alignment = 0; -+ u32 ret = _SUCCESS; -+ -+ if (adapter->bDriverStopped || adapter->bSurpriseRemoved || -+ adapter->pwrctrlpriv.pnp_bstop_trx) { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, -+ ("usb_read_port:(adapt->bDriverStopped ||adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); -+ return _FAIL; -+ } -+ -+ if (!precvbuf) { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, -+ ("usb_read_port:precvbuf==NULL\n")); -+ return _FAIL; -+ } -+ -+ if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) { -+ precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); -+ if (NULL != precvbuf->pskb) -+ precvbuf->reuse = true; -+ } -+ -+ rtl8188eu_init_recvbuf(adapter, precvbuf); -+ -+ /* re-assign for linux based on skb */ -+ if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) { -+ precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); -+ if (precvbuf->pskb == NULL) { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n")); -+ DBG_88E("#### usb_read_port() alloc_skb fail!#####\n"); -+ return _FAIL; -+ } -+ -+ tmpaddr = (size_t)precvbuf->pskb->data; -+ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); -+ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); -+ -+ precvbuf->phead = precvbuf->pskb->head; -+ precvbuf->pdata = precvbuf->pskb->data; -+ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); -+ precvbuf->pend = skb_end_pointer(precvbuf->pskb); -+ precvbuf->pbuf = precvbuf->pskb->data; -+ } else { /* reuse skb */ -+ precvbuf->phead = precvbuf->pskb->head; -+ precvbuf->pdata = precvbuf->pskb->data; -+ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); -+ precvbuf->pend = skb_end_pointer(precvbuf->pskb); -+ precvbuf->pbuf = precvbuf->pskb->data; -+ -+ precvbuf->reuse = false; -+ } -+ -+ precvpriv->rx_pending_cnt++; -+ -+ purb = precvbuf->purb; -+ -+ /* translate DMA FIFO addr to pipehandle */ -+ pipe = ffaddr2pipehdl(pdvobj, addr); -+ -+ usb_fill_bulk_urb(purb, pusbd, pipe, -+ precvbuf->pbuf, -+ MAX_RECVBUF_SZ, -+ usb_read_port_complete, -+ precvbuf);/* context is precvbuf */ -+ -+ err = usb_submit_urb(purb, GFP_ATOMIC); -+ if ((err) && (err != (-EPERM))) { -+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, -+ ("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x", -+ err, purb->status)); -+ DBG_88E("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n", -+ err, purb->status); -+ ret = _FAIL; -+ } -+ -+ return ret; -+} -+ -+void rtl8188eu_xmit_tasklet(void *priv) -+{ -+ int ret = false; -+ struct adapter *adapt = (struct adapter *)priv; -+ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; -+ -+ if (check_fwstate(&adapt->mlmepriv, _FW_UNDER_SURVEY)) -+ return; -+ -+ while (1) { -+ if ((adapt->bDriverStopped) || -+ (adapt->bSurpriseRemoved) || -+ (adapt->bWritePortCancel)) { -+ DBG_88E("xmit_tasklet => bDriverStopped or bSurpriseRemoved or bWritePortCancel\n"); -+ break; -+ } -+ -+ ret = rtl8188eu_xmitframe_complete(adapt, pxmitpriv, NULL); -+ -+ if (!ret) -+ break; -+ } -+} -+ -+void rtl8188eu_set_intf_ops(struct _io_ops *pops) -+{ -+ -+ memset((u8 *)pops, 0, sizeof(struct _io_ops)); -+ pops->_read8 = &usb_read8; -+ pops->_read16 = &usb_read16; -+ pops->_read32 = &usb_read32; -+ pops->_read_mem = &usb_read_mem; -+ pops->_read_port = &usb_read_port; -+ pops->_write8 = &usb_write8; -+ pops->_write16 = &usb_write16; -+ pops->_write32 = &usb_write32; -+ pops->_writeN = &usb_writeN; -+ pops->_write_mem = &usb_write_mem; -+ pops->_write_port = &usb_write_port; -+ pops->_read_port_cancel = &usb_read_port_cancel; -+ pops->_write_port_cancel = &usb_write_port_cancel; -+ -+} -+ -+void rtl8188eu_set_hw_type(struct adapter *adapt) -+{ -+ adapt->chip_type = RTL8188E; -+ adapt->HardwareType = HARDWARE_TYPE_RTL8188EU; -+ DBG_88E("CHIP TYPE: RTL8188E\n"); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/COPYING b/drivers/net/wireless/rtl8188eu/hostapd-0.8/COPYING -new file mode 100644 -index 0000000000000..14f5453722a85 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/COPYING -@@ -0,0 +1,340 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 51 Franklin St, 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 Library 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) 19yy -+ -+ 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 St, 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) 19yy 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 Library General -+Public License instead of this License. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/README b/drivers/net/wireless/rtl8188eu/hostapd-0.8/README -new file mode 100644 -index 0000000000000..94ef1a74dbfbf ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/README -@@ -0,0 +1,72 @@ -+wpa_supplicant and hostapd -+-------------------------- -+ -+Copyright (c) 2002-2011, Jouni Malinen and contributors -+All Rights Reserved. -+ -+These programs are dual-licensed under both the GPL version 2 and BSD -+license (the one with advertisement clause removed). Either license -+may be used at your option. -+ -+ -+This package may include either wpa_supplicant, hostapd, or both. See -+README file respective subdirectories (wpa_supplicant/README or -+hostapd/README) for more details. -+ -+Source code files were moved around in v0.6.x releases and compared to -+earlier releases, the programs are now built by first going to a -+subdirectory (wpa_supplicant or hostapd) and creating build -+configuration (.config) and running 'make' there (for Linux/BSD/cygwin -+builds). -+ -+ -+License -+------- -+ -+GPL v2: -+ -+This program is free software; you can redistribute it and/or modify -+it under the terms of the GNU General Public License version 2 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 St, Fifth Floor, Boston, MA 02110-1301 USA -+ -+(this copy of the license is in COPYING file) -+ -+ -+Alternatively, this software may be distributed, used, and modified -+under the terms of BSD license: -+ -+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(s) of the above-listed copyright holder(s) 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. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Android.mk b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Android.mk -new file mode 100644 -index 0000000000000..aa9d5ba4351c3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Android.mk -@@ -0,0 +1,816 @@ -+LOCAL_PATH := $(call my-dir) -+ -+WPA_BUILD_HOSTAPD := false -+ifneq ($(TARGET_SIMULATOR),true) -+ ifneq ($(BOARD_HOSTAPD_DRIVER),) -+ WPA_BUILD_HOSTAPD := true -+ CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y -+ endif -+endif -+ -+include $(LOCAL_PATH)/.config -+ -+# To ignore possible wrong network configurations -+L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS -+ -+# To force sizeof(enum) = 4 -+ifeq ($(TARGET_ARCH),arm) -+L_CFLAGS += -mabi=aapcs-linux -+endif -+ -+# To allow non-ASCII characters in SSID -+L_CFLAGS += -DWPA_UNICODE_SSID -+ -+# OpenSSL is configured without engines on Android -+L_CFLAGS += -DOPENSSL_NO_ENGINE -+ -+INCLUDES = $(LOCAL_PATH) -+INCLUDES += $(LOCAL_PATH)/src -+INCLUDES += $(LOCAL_PATH)/src/utils -+INCLUDES += external/openssl/include -+INCLUDES += frameworks/base/cmds/keystore -+ifdef CONFIG_DRIVER_NL80211 -+INCLUDES += external/libnl_2/include -+endif -+ -+ -+ifndef CONFIG_OS -+ifdef CONFIG_NATIVE_WINDOWS -+CONFIG_OS=win32 -+else -+CONFIG_OS=unix -+endif -+endif -+ -+ifeq ($(CONFIG_OS), internal) -+L_CFLAGS += -DOS_NO_C_LIB_DEFINES -+endif -+ -+ifdef CONFIG_NATIVE_WINDOWS -+L_CFLAGS += -DCONFIG_NATIVE_WINDOWS -+LIBS += -lws2_32 -+endif -+ -+OBJS = main.c -+OBJS += config_file.c -+ -+OBJS += src/ap/hostapd.c -+OBJS += src/ap/wpa_auth_glue.c -+OBJS += src/ap/drv_callbacks.c -+OBJS += src/ap/ap_drv_ops.c -+OBJS += src/ap/utils.c -+OBJS += src/ap/authsrv.c -+OBJS += src/ap/ieee802_1x.c -+OBJS += src/ap/ap_config.c -+OBJS += src/ap/ieee802_11_auth.c -+OBJS += src/ap/sta_info.c -+OBJS += src/ap/wpa_auth.c -+OBJS += src/ap/tkip_countermeasures.c -+OBJS += src/ap/ap_mlme.c -+OBJS += src/ap/wpa_auth_ie.c -+OBJS += src/ap/preauth_auth.c -+OBJS += src/ap/pmksa_cache_auth.c -+OBJS_d = -+OBJS_p = -+LIBS = -+LIBS_c = -+HOBJS = -+LIBS_h = -+ -+NEED_RC4=y -+NEED_AES=y -+NEED_MD5=y -+NEED_SHA1=y -+ -+OBJS += src/drivers/drivers.c -+L_CFLAGS += -DHOSTAPD -+ -+ifdef CONFIG_WPA_TRACE -+L_CFLAGS += -DWPA_TRACE -+OBJS += src/utils/trace.c -+HOBJS += src/utils/trace.c -+LDFLAGS += -rdynamic -+L_CFLAGS += -funwind-tables -+ifdef CONFIG_WPA_TRACE_BFD -+L_CFLAGS += -DWPA_TRACE_BFD -+LIBS += -lbfd -+LIBS_c += -lbfd -+LIBS_h += -lbfd -+endif -+endif -+ -+OBJS += src/utils/eloop.c -+OBJS += src/utils/common.c -+OBJS += src/utils/wpa_debug.c -+OBJS += src/utils/wpabuf.c -+OBJS += src/utils/os_$(CONFIG_OS).c -+OBJS += src/utils/ip_addr.c -+ -+OBJS += src/common/ieee802_11_common.c -+OBJS += src/common/wpa_common.c -+ -+OBJS += src/eapol_auth/eapol_auth_sm.c -+ -+ -+ifndef CONFIG_NO_DUMP_STATE -+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to -+# a file (undefine it, if you want to save in binary size) -+L_CFLAGS += -DHOSTAPD_DUMP_STATE -+OBJS += dump_state.c -+OBJS += src/eapol_auth/eapol_auth_dump.c -+endif -+ -+ifdef CONFIG_NO_RADIUS -+L_CFLAGS += -DCONFIG_NO_RADIUS -+CONFIG_NO_ACCOUNTING=y -+else -+OBJS += src/radius/radius.c -+OBJS += src/radius/radius_client.c -+endif -+ -+ifdef CONFIG_NO_ACCOUNTING -+L_CFLAGS += -DCONFIG_NO_ACCOUNTING -+else -+OBJS += src/ap/accounting.c -+endif -+ -+ifdef CONFIG_NO_VLAN -+L_CFLAGS += -DCONFIG_NO_VLAN -+else -+OBJS += src/ap/vlan_init.c -+endif -+ -+ifdef CONFIG_NO_CTRL_IFACE -+L_CFLAGS += -DCONFIG_NO_CTRL_IFACE -+else -+OBJS += ctrl_iface.c -+OBJS += src/ap/ctrl_iface_ap.c -+endif -+ -+OBJS += src/crypto/md5.c -+ -+L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX -+ -+ifdef CONFIG_IAPP -+L_CFLAGS += -DCONFIG_IAPP -+OBJS += src/ap/iapp.c -+endif -+ -+ifdef CONFIG_RSN_PREAUTH -+L_CFLAGS += -DCONFIG_RSN_PREAUTH -+CONFIG_L2_PACKET=y -+endif -+ -+ifdef CONFIG_PEERKEY -+L_CFLAGS += -DCONFIG_PEERKEY -+OBJS += src/ap/peerkey_auth.c -+endif -+ -+ifdef CONFIG_IEEE80211W -+L_CFLAGS += -DCONFIG_IEEE80211W -+NEED_SHA256=y -+NEED_AES_OMAC1=y -+endif -+ -+ifdef CONFIG_IEEE80211R -+L_CFLAGS += -DCONFIG_IEEE80211R -+OBJS += src/ap/wpa_auth_ft.c -+NEED_SHA256=y -+NEED_AES_OMAC1=y -+NEED_AES_UNWRAP=y -+endif -+ -+ifdef CONFIG_IEEE80211N -+L_CFLAGS += -DCONFIG_IEEE80211N -+endif -+ -+include $(LOCAL_PATH)/src/drivers/drivers.mk -+ -+OBJS += $(DRV_AP_OBJS) -+L_CFLAGS += $(DRV_AP_CFLAGS) -+LDFLAGS += $(DRV_AP_LDFLAGS) -+LIBS += $(DRV_AP_LIBS) -+ -+ifdef CONFIG_L2_PACKET -+ifdef CONFIG_DNET_PCAP -+ifdef CONFIG_L2_FREEBSD -+LIBS += -lpcap -+OBJS += src/l2_packet/l2_packet_freebsd.c -+else -+LIBS += -ldnet -lpcap -+OBJS += src/l2_packet/l2_packet_pcap.c -+endif -+else -+OBJS += src/l2_packet/l2_packet_linux.c -+endif -+else -+OBJS += src/l2_packet/l2_packet_none.c -+endif -+ -+ -+ifdef CONFIG_EAP_MD5 -+L_CFLAGS += -DEAP_SERVER_MD5 -+OBJS += src/eap_server/eap_server_md5.c -+CHAP=y -+endif -+ -+ifdef CONFIG_EAP_TLS -+L_CFLAGS += -DEAP_SERVER_TLS -+OBJS += src/eap_server/eap_server_tls.c -+TLS_FUNCS=y -+endif -+ -+ifdef CONFIG_EAP_PEAP -+L_CFLAGS += -DEAP_SERVER_PEAP -+OBJS += src/eap_server/eap_server_peap.c -+OBJS += src/eap_common/eap_peap_common.c -+TLS_FUNCS=y -+CONFIG_EAP_MSCHAPV2=y -+endif -+ -+ifdef CONFIG_EAP_TTLS -+L_CFLAGS += -DEAP_SERVER_TTLS -+OBJS += src/eap_server/eap_server_ttls.c -+TLS_FUNCS=y -+CHAP=y -+endif -+ -+ifdef CONFIG_EAP_MSCHAPV2 -+L_CFLAGS += -DEAP_SERVER_MSCHAPV2 -+OBJS += src/eap_server/eap_server_mschapv2.c -+MS_FUNCS=y -+endif -+ -+ifdef CONFIG_EAP_GTC -+L_CFLAGS += -DEAP_SERVER_GTC -+OBJS += src/eap_server/eap_server_gtc.c -+endif -+ -+ifdef CONFIG_EAP_SIM -+L_CFLAGS += -DEAP_SERVER_SIM -+OBJS += src/eap_server/eap_server_sim.c -+CONFIG_EAP_SIM_COMMON=y -+NEED_AES_CBC=y -+endif -+ -+ifdef CONFIG_EAP_AKA -+L_CFLAGS += -DEAP_SERVER_AKA -+OBJS += src/eap_server/eap_server_aka.c -+CONFIG_EAP_SIM_COMMON=y -+NEED_SHA256=y -+NEED_AES_CBC=y -+endif -+ -+ifdef CONFIG_EAP_AKA_PRIME -+L_CFLAGS += -DEAP_SERVER_AKA_PRIME -+endif -+ -+ifdef CONFIG_EAP_SIM_COMMON -+OBJS += src/eap_common/eap_sim_common.c -+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be -+# replaced with another file implementating the interface specified in -+# eap_sim_db.h. -+OBJS += src/eap_server/eap_sim_db.c -+NEED_FIPS186_2_PRF=y -+endif -+ -+ifdef CONFIG_EAP_PAX -+L_CFLAGS += -DEAP_SERVER_PAX -+OBJS += src/eap_server/eap_server_pax.c src/eap_common/eap_pax_common.c -+endif -+ -+ifdef CONFIG_EAP_PSK -+L_CFLAGS += -DEAP_SERVER_PSK -+OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c -+NEED_AES_OMAC1=y -+NEED_AES_ENCBLOCK=y -+NEED_AES_EAX=y -+endif -+ -+ifdef CONFIG_EAP_SAKE -+L_CFLAGS += -DEAP_SERVER_SAKE -+OBJS += src/eap_server/eap_server_sake.c src/eap_common/eap_sake_common.c -+endif -+ -+ifdef CONFIG_EAP_GPSK -+L_CFLAGS += -DEAP_SERVER_GPSK -+OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c -+ifdef CONFIG_EAP_GPSK_SHA256 -+L_CFLAGS += -DEAP_SERVER_GPSK_SHA256 -+endif -+NEED_SHA256=y -+NEED_AES_OMAC1=y -+endif -+ -+ifdef CONFIG_EAP_PWD -+L_CFLAGS += -DEAP_SERVER_PWD -+OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c -+NEED_SHA256=y -+endif -+ -+ifdef CONFIG_EAP_VENDOR_TEST -+L_CFLAGS += -DEAP_SERVER_VENDOR_TEST -+OBJS += src/eap_server/eap_server_vendor_test.c -+endif -+ -+ifdef CONFIG_EAP_FAST -+L_CFLAGS += -DEAP_SERVER_FAST -+OBJS += src/eap_server/eap_server_fast.c -+OBJS += src/eap_common/eap_fast_common.c -+TLS_FUNCS=y -+NEED_T_PRF=y -+NEED_AES_UNWRAP=y -+endif -+ -+ifdef CONFIG_WPS -+ifdef CONFIG_WPS2 -+L_CFLAGS += -DCONFIG_WPS2 -+endif -+ -+L_CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC -+OBJS += src/utils/uuid.c -+OBJS += src/ap/wps_hostapd.c -+OBJS += src/eap_server/eap_server_wsc.c src/eap_common/eap_wsc_common.c -+OBJS += src/wps/wps.c -+OBJS += src/wps/wps_common.c -+OBJS += src/wps/wps_attr_parse.c -+OBJS += src/wps/wps_attr_build.c -+OBJS += src/wps/wps_attr_process.c -+OBJS += src/wps/wps_dev_attr.c -+OBJS += src/wps/wps_enrollee.c -+OBJS += src/wps/wps_registrar.c -+NEED_DH_GROUPS=y -+NEED_SHA256=y -+NEED_BASE64=y -+NEED_AES_CBC=y -+NEED_MODEXP=y -+CONFIG_EAP=y -+ -+ifdef CONFIG_WPS_UFD -+L_CFLAGS += -DCONFIG_WPS_UFD -+OBJS += src/wps/wps_ufd.c -+NEED_WPS_OOB=y -+endif -+ -+ifdef CONFIG_WPS_NFC -+L_CFLAGS += -DCONFIG_WPS_NFC -+OBJS += src/wps/ndef.c -+OBJS += src/wps/wps_nfc.c -+NEED_WPS_OOB=y -+ifdef CONFIG_WPS_NFC_PN531 -+PN531_PATH ?= /usr/local/src/nfc -+L_CFLAGS += -DCONFIG_WPS_NFC_PN531 -+L_CFLAGS += -I${PN531_PATH}/inc -+OBJS += src/wps/wps_nfc_pn531.c -+LIBS += ${PN531_PATH}/lib/wpsnfc.dll -+LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll -+endif -+endif -+ -+ifdef NEED_WPS_OOB -+L_CFLAGS += -DCONFIG_WPS_OOB -+endif -+ -+ifdef CONFIG_WPS_UPNP -+L_CFLAGS += -DCONFIG_WPS_UPNP -+OBJS += src/wps/wps_upnp.c -+OBJS += src/wps/wps_upnp_ssdp.c -+OBJS += src/wps/wps_upnp_web.c -+OBJS += src/wps/wps_upnp_event.c -+OBJS += src/wps/wps_upnp_ap.c -+OBJS += src/wps/upnp_xml.c -+OBJS += src/wps/httpread.c -+OBJS += src/wps/http_client.c -+OBJS += src/wps/http_server.c -+endif -+ -+ifdef CONFIG_WPS_STRICT -+L_CFLAGS += -DCONFIG_WPS_STRICT -+OBJS += src/wps/wps_validate.c -+endif -+ -+ifdef CONFIG_WPS_TESTING -+L_CFLAGS += -DCONFIG_WPS_TESTING -+endif -+ -+endif -+ -+ifdef CONFIG_EAP_IKEV2 -+L_CFLAGS += -DEAP_SERVER_IKEV2 -+OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c -+OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c -+NEED_DH_GROUPS=y -+NEED_DH_GROUPS_ALL=y -+NEED_MODEXP=y -+NEED_CIPHER=y -+endif -+ -+ifdef CONFIG_EAP_TNC -+L_CFLAGS += -DEAP_SERVER_TNC -+OBJS += src/eap_server/eap_server_tnc.c -+OBJS += src/eap_server/tncs.c -+NEED_BASE64=y -+ifndef CONFIG_DRIVER_BSD -+LIBS += -ldl -+endif -+endif -+ -+# Basic EAP functionality is needed for EAPOL -+OBJS += eap_register.c -+OBJS += src/eap_server/eap_server.c -+OBJS += src/eap_common/eap_common.c -+OBJS += src/eap_server/eap_server_methods.c -+OBJS += src/eap_server/eap_server_identity.c -+L_CFLAGS += -DEAP_SERVER_IDENTITY -+ -+ifdef CONFIG_EAP -+L_CFLAGS += -DEAP_SERVER -+endif -+ -+ifdef CONFIG_PKCS12 -+L_CFLAGS += -DPKCS12_FUNCS -+endif -+ -+ifdef MS_FUNCS -+OBJS += src/crypto/ms_funcs.c -+NEED_DES=y -+NEED_MD4=y -+endif -+ -+ifdef CHAP -+OBJS += src/eap_common/chap.c -+endif -+ -+ifdef TLS_FUNCS -+NEED_DES=y -+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) -+L_CFLAGS += -DEAP_TLS_FUNCS -+OBJS += src/eap_server/eap_server_tls_common.c -+NEED_TLS_PRF=y -+endif -+ -+ifndef CONFIG_TLS -+CONFIG_TLS=openssl -+endif -+ -+ifeq ($(CONFIG_TLS), openssl) -+ifdef TLS_FUNCS -+OBJS += src/crypto/tls_openssl.c -+LIBS += -lssl -+endif -+OBJS += src/crypto/crypto_openssl.c -+HOBJS += src/crypto/crypto_openssl.c -+ifdef NEED_FIPS186_2_PRF -+OBJS += src/crypto/fips_prf_openssl.c -+endif -+LIBS += -lcrypto -+LIBS_h += -lcrypto -+endif -+ -+ifeq ($(CONFIG_TLS), gnutls) -+ifdef TLS_FUNCS -+OBJS += src/crypto/tls_gnutls.c -+LIBS += -lgnutls -lgpg-error -+ifdef CONFIG_GNUTLS_EXTRA -+L_CFLAGS += -DCONFIG_GNUTLS_EXTRA -+LIBS += -lgnutls-extra -+endif -+endif -+OBJS += src/crypto/crypto_gnutls.c -+HOBJS += src/crypto/crypto_gnutls.c -+ifdef NEED_FIPS186_2_PRF -+OBJS += src/crypto/fips_prf_gnutls.c -+endif -+LIBS += -lgcrypt -+LIBS_h += -lgcrypt -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ -+ifeq ($(CONFIG_TLS), schannel) -+ifdef TLS_FUNCS -+OBJS += src/crypto/tls_schannel.c -+endif -+OBJS += src/crypto/crypto_cryptoapi.c -+OBJS_p += src/crypto/crypto_cryptoapi.c -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ -+ifeq ($(CONFIG_TLS), nss) -+ifdef TLS_FUNCS -+OBJS += src/crypto/tls_nss.c -+LIBS += -lssl3 -+endif -+OBJS += src/crypto/crypto_nss.c -+ifdef NEED_FIPS186_2_PRF -+OBJS += src/crypto/fips_prf_nss.c -+endif -+LIBS += -lnss3 -+LIBS_h += -lnss3 -+CONFIG_INTERNAL_MD4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ -+ifeq ($(CONFIG_TLS), internal) -+ifndef CONFIG_CRYPTO -+CONFIG_CRYPTO=internal -+endif -+ifdef TLS_FUNCS -+OBJS += src/crypto/crypto_internal-rsa.c -+OBJS += src/crypto/tls_internal.c -+OBJS += src/tls/tlsv1_common.c -+OBJS += src/tls/tlsv1_record.c -+OBJS += src/tls/tlsv1_cred.c -+OBJS += src/tls/tlsv1_server.c -+OBJS += src/tls/tlsv1_server_write.c -+OBJS += src/tls/tlsv1_server_read.c -+OBJS += src/tls/asn1.c -+OBJS += src/tls/rsa.c -+OBJS += src/tls/x509v3.c -+OBJS += src/tls/pkcs1.c -+OBJS += src/tls/pkcs5.c -+OBJS += src/tls/pkcs8.c -+NEED_SHA256=y -+NEED_BASE64=y -+NEED_TLS_PRF=y -+NEED_MODEXP=y -+NEED_CIPHER=y -+L_CFLAGS += -DCONFIG_TLS_INTERNAL -+L_CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER -+endif -+ifdef NEED_CIPHER -+NEED_DES=y -+OBJS += src/crypto/crypto_internal-cipher.c -+endif -+ifdef NEED_MODEXP -+OBJS += src/crypto/crypto_internal-modexp.c -+OBJS += src/tls/bignum.c -+endif -+ifeq ($(CONFIG_CRYPTO), libtomcrypt) -+OBJS += src/crypto/crypto_libtomcrypt.c -+LIBS += -ltomcrypt -ltfm -+LIBS_h += -ltomcrypt -ltfm -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ifeq ($(CONFIG_CRYPTO), internal) -+OBJS += src/crypto/crypto_internal.c -+NEED_AES_DEC=y -+L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL -+ifdef CONFIG_INTERNAL_LIBTOMMATH -+L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH -+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST -+L_CFLAGS += -DLTM_FAST -+endif -+else -+LIBS += -ltommath -+LIBS_h += -ltommath -+endif -+CONFIG_INTERNAL_AES=y -+CONFIG_INTERNAL_DES=y -+CONFIG_INTERNAL_SHA1=y -+CONFIG_INTERNAL_MD4=y -+CONFIG_INTERNAL_MD5=y -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ifeq ($(CONFIG_CRYPTO), cryptoapi) -+OBJS += src/crypto/crypto_cryptoapi.c -+OBJS_p += src/crypto/crypto_cryptoapi.c -+L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+endif -+endif -+ -+ifeq ($(CONFIG_TLS), none) -+ifdef TLS_FUNCS -+OBJS += src/crypto/tls_none.c -+L_CFLAGS += -DEAP_TLS_NONE -+CONFIG_INTERNAL_AES=y -+CONFIG_INTERNAL_SHA1=y -+CONFIG_INTERNAL_MD5=y -+endif -+OBJS += src/crypto/crypto_none.c -+OBJS_p += src/crypto/crypto_none.c -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+endif -+ -+ifndef TLS_FUNCS -+OBJS += src/crypto/tls_none.c -+ifeq ($(CONFIG_TLS), internal) -+CONFIG_INTERNAL_AES=y -+CONFIG_INTERNAL_SHA1=y -+CONFIG_INTERNAL_MD5=y -+CONFIG_INTERNAL_RC4=y -+endif -+endif -+ -+AESOBJS = # none so far -+ifdef CONFIG_INTERNAL_AES -+AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c -+endif -+ -+AESOBJS += src/crypto/aes-wrap.c -+ifdef NEED_AES_EAX -+AESOBJS += src/crypto/aes-eax.c -+NEED_AES_CTR=y -+endif -+ifdef NEED_AES_CTR -+AESOBJS += src/crypto/aes-ctr.c -+endif -+ifdef NEED_AES_ENCBLOCK -+AESOBJS += src/crypto/aes-encblock.c -+endif -+ifdef NEED_AES_OMAC1 -+AESOBJS += src/crypto/aes-omac1.c -+endif -+ifdef NEED_AES_UNWRAP -+NEED_AES_DEC=y -+AESOBJS += src/crypto/aes-unwrap.c -+endif -+ifdef NEED_AES_CBC -+NEED_AES_DEC=y -+AESOBJS += src/crypto/aes-cbc.c -+endif -+ifdef NEED_AES_DEC -+ifdef CONFIG_INTERNAL_AES -+AESOBJS += src/crypto/aes-internal-dec.c -+endif -+endif -+ifdef NEED_AES -+OBJS += $(AESOBJS) -+endif -+ -+SHA1OBJS = -+ifdef NEED_SHA1 -+SHA1OBJS += src/crypto/sha1.c -+ifdef CONFIG_INTERNAL_SHA1 -+SHA1OBJS += src/crypto/sha1-internal.c -+ifdef NEED_FIPS186_2_PRF -+SHA1OBJS += src/crypto/fips_prf_internal.c -+endif -+endif -+SHA1OBJS += src/crypto/sha1-pbkdf2.c -+ifdef NEED_T_PRF -+SHA1OBJS += src/crypto/sha1-tprf.c -+endif -+ifdef NEED_TLS_PRF -+SHA1OBJS += src/crypto/sha1-tlsprf.c -+endif -+endif -+ -+ifdef NEED_SHA1 -+OBJS += $(SHA1OBJS) -+endif -+ -+ifdef NEED_MD5 -+ifdef CONFIG_INTERNAL_MD5 -+OBJS += src/crypto/md5-internal.c -+HOBJS += src/crypto/md5-internal.c -+endif -+endif -+ -+ifdef NEED_MD4 -+ifdef CONFIG_INTERNAL_MD4 -+OBJS += src/crypto/md4-internal.c -+endif -+endif -+ -+ifdef NEED_DES -+ifdef CONFIG_INTERNAL_DES -+OBJS += src/crypto/des-internal.c -+endif -+endif -+ -+ifdef NEED_RC4 -+ifdef CONFIG_INTERNAL_RC4 -+OBJS += src/crypto/rc4.c -+endif -+endif -+ -+ifdef NEED_SHA256 -+OBJS += src/crypto/sha256.c -+ifdef CONFIG_INTERNAL_SHA256 -+OBJS += src/crypto/sha256-internal.c -+endif -+endif -+ -+ifdef NEED_DH_GROUPS -+OBJS += src/crypto/dh_groups.c -+endif -+ifdef NEED_DH_GROUPS_ALL -+L_CFLAGS += -DALL_DH_GROUPS -+endif -+ifdef CONFIG_INTERNAL_DH_GROUP5 -+ifdef NEED_DH_GROUPS -+OBJS += src/crypto/dh_group5.c -+endif -+endif -+ -+ifdef CONFIG_NO_RANDOM_POOL -+L_CFLAGS += -DCONFIG_NO_RANDOM_POOL -+else -+OBJS += src/crypto/random.c -+HOBJS += src/crypto/random.c -+HOBJS += $(SHA1OBJS) -+HOBJS += src/crypto/md5.c -+endif -+ -+ifdef CONFIG_RADIUS_SERVER -+L_CFLAGS += -DRADIUS_SERVER -+OBJS += src/radius/radius_server.c -+endif -+ -+ifdef CONFIG_IPV6 -+L_CFLAGS += -DCONFIG_IPV6 -+endif -+ -+ifdef CONFIG_DRIVER_RADIUS_ACL -+L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL -+endif -+ -+ifdef CONFIG_FULL_DYNAMIC_VLAN -+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges -+# and vlan interfaces for the vlan feature. -+L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN -+endif -+ -+ifdef NEED_BASE64 -+OBJS += src/utils/base64.c -+endif -+ -+ifdef NEED_AP_MLME -+OBJS += src/ap/beacon.c -+OBJS += src/ap/wmm.c -+OBJS += src/ap/ap_list.c -+OBJS += src/ap/ieee802_11.c -+OBJS += src/ap/hw_features.c -+L_CFLAGS += -DNEED_AP_MLME -+endif -+ifdef CONFIG_IEEE80211N -+OBJS += src/ap/ieee802_11_ht.c -+endif -+ -+ifdef CONFIG_P2P_MANAGER -+L_CFLAGS += -DCONFIG_P2P_MANAGER -+OBJS += src/ap/p2p_hostapd.c -+endif -+ -+ifdef CONFIG_NO_STDOUT_DEBUG -+L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG -+endif -+ -+ifdef CONFIG_DEBUG_FILE -+L_CFLAGS += -DCONFIG_DEBUG_FILE -+endif -+ -+ifdef CONFIG_ANDROID_LOG -+L_CFLAGS += -DCONFIG_ANDROID_LOG -+endif -+ -+OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c -+ifdef CONFIG_WPA_TRACE -+OBJS_c += src/utils/trace.c -+OBJS_c += src/utils/wpa_debug.c -+endif -+ -+ifeq ($(WPA_BUILD_HOSTAPD),true) -+ -+######################## -+ -+include $(CLEAR_VARS) -+LOCAL_MODULE := hostapd_cli -+LOCAL_MODULE_TAGS := debug -+LOCAL_SHARED_LIBRARIES := libc libcutils -+LOCAL_CFLAGS := $(L_CFLAGS) -+LOCAL_SRC_FILES := $(OBJS_c) -+LOCAL_C_INCLUDES := $(INCLUDES) -+include $(BUILD_EXECUTABLE) -+ -+######################## -+include $(CLEAR_VARS) -+LOCAL_MODULE := hostapd -+LOCAL_MODULE_TAGS := optional -+ifdef CONFIG_DRIVER_CUSTOM -+LOCAL_STATIC_LIBRARIES := libCustomWifi -+endif -+ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),) -+LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB) -+endif -+LOCAL_SHARED_LIBRARIES := libc libcutils libcrypto libssl -+ifdef CONFIG_DRIVER_NL80211 -+LOCAL_SHARED_LIBRARIES += libnl_2 -+endif -+LOCAL_CFLAGS := $(L_CFLAGS) -+LOCAL_SRC_FILES := $(OBJS) -+LOCAL_C_INCLUDES := $(INCLUDES) -+include $(BUILD_EXECUTABLE) -+ -+endif # ifeq ($(WPA_BUILD_HOSTAPD),true) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ChangeLog b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ChangeLog -new file mode 100644 -index 0000000000000..a8417d691f798 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ChangeLog -@@ -0,0 +1,647 @@ -+ChangeLog for hostapd -+ -+2010-04-18 - v0.7.2 -+ * fix WPS internal Registrar use when an external Registrar is also -+ active -+ * bsd: Cleaned up driver wrapper and added various low-level -+ configuration options -+ * TNC: fixed issues with fragmentation -+ * EAP-TNC: add Flags field into fragment acknowledgement (needed to -+ interoperate with other implementations; may potentially breaks -+ compatibility with older wpa_supplicant/hostapd versions) -+ * cleaned up driver wrapper API for multi-BSS operations -+ * nl80211: fix multi-BSS and VLAN operations -+ * fix number of issues with IEEE 802.11r/FT; this version is not -+ backwards compatible with old versions -+ * add SA Query Request processing in AP mode (IEEE 802.11w) -+ * fix IGTK PN in group rekeying (IEEE 802.11w) -+ * fix WPS PBC session overlap detection to use correct attribute -+ * hostapd_notif_Assoc() can now be called with all IEs to simplify -+ driver wrappers -+ * work around interoperability issue with some WPS External Registrar -+ implementations -+ * nl80211: fix WPS IE update -+ * hostapd_cli: add support for action script operations (run a script -+ on hostapd events) -+ * fix DH padding with internal crypto code (mainly, for WPS) -+ * fix WPS association with both WPS IE and WPA/RSN IE present with -+ driver wrappers that use hostapd MLME (e.g., nl80211) -+ -+2010-01-16 - v0.7.1 -+ * cleaned up driver wrapper API (struct wpa_driver_ops); the new API -+ is not fully backwards compatible, so out-of-tree driver wrappers -+ will need modifications -+ * cleaned up various module interfaces -+ * merge hostapd and wpa_supplicant developers' documentation into a -+ single document -+ * fixed HT Capabilities IE with nl80211 drivers -+ * moved generic AP functionality code into src/ap -+ * WPS: handle Selected Registrar as union of info from all Registrars -+ * remove obsolte Prism54.org driver wrapper -+ * added internal debugging mechanism with backtrace support and memory -+ allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y) -+ * EAP-FAST server: piggyback Phase 2 start with the end of Phase 1 -+ * WPS: add support for dynamically selecting whether to provision the -+ PSK as an ASCII passphrase or PSK -+ * added support for WDS (4-address frame) mode with per-station virtual -+ interfaces (wds_sta=1 in config file; only supported with -+ driver=nl80211 for now) -+ * fixed WPS Probe Request processing to handle missing required -+ attribute -+ * fixed PKCS#12 use with OpenSSL 1.0.0 -+ * detect bridge interface automatically so that bridge parameter in -+ hostapd.conf becomes optional (though, it may now be used to -+ automatically add then WLAN interface into a bridge with -+ driver=nl80211) -+ -+2009-11-21 - v0.7.0 -+ * increased hostapd_cli ping interval to 5 seconds and made this -+ configurable with a new command line options (-G) -+ * driver_nl80211: use Linux socket filter to improve performance -+ * added support for external Registrars with WPS (UPnP transport) -+ * 802.11n: scan for overlapping BSSes before starting 20/40 MHz channel -+ * driver_nl80211: fixed STA accounting data collection (TX/RX bytes -+ reported correctly; TX/RX packets not yet available from kernel) -+ * added support for WPS USBA out-of-band mechanism with USB Flash -+ Drives (UFD) (CONFIG_WPS_UFD=y) -+ * fixed EAPOL/EAP reauthentication when using an external RADIUS -+ authentication server -+ * fixed TNC with EAP-TTLS -+ * fixed IEEE 802.11r key derivation function to match with the standard -+ (note: this breaks interoperability with previous version) [Bug 303] -+ * fixed SHA-256 based key derivation function to match with the -+ standard when using CCMP (for IEEE 802.11r and IEEE 802.11w) -+ (note: this breaks interoperability with previous version) [Bug 307] -+ * added number of code size optimizations to remove unnecessary -+ functionality from the program binary based on build configuration -+ (part of this automatic; part configurable with CONFIG_NO_* build -+ options) -+ * use shared driver wrapper files with wpa_supplicant -+ * driver_nl80211: multiple updates to provide support for new Linux -+ nl80211/mac80211 functionality -+ * updated management frame protection to use IEEE Std 802.11w-2009 -+ * fixed number of small WPS issues and added workarounds to -+ interoperate with common deployed broken implementations -+ * added some IEEE 802.11n co-existance rules to disable 40 MHz channels -+ or modify primary/secondary channels if needed based on neighboring -+ networks -+ * added support for NFC out-of-band mechanism with WPS -+ * added preliminary support for IEEE 802.11r RIC processing -+ -+2009-01-06 - v0.6.7 -+ * added support for Wi-Fi Protected Setup (WPS) -+ (hostapd can now be configured to act as an integrated WPS Registrar -+ and provision credentials for WPS Enrollees using PIN and PBC -+ methods; external wireless Registrar can configure the AP, but -+ external WLAN Manager Registrars are not supported); WPS support can -+ be enabled by adding CONFIG_WPS=y into .config and setting the -+ runtime configuration variables in hostapd.conf (see WPS section in -+ the example configuration file); new hostapd_cli commands wps_pin and -+ wps_pbc are used to configure WPS negotiation; see README-WPS for -+ more details -+ * added IEEE 802.11n HT capability configuration (ht_capab) -+ * added support for generating Country IE based on nl80211 regulatory -+ information (added if ieee80211d=1 in configuration) -+ * fixed WEP authentication (both Open System and Shared Key) with -+ mac80211 -+ * added support for EAP-AKA' (draft-arkko-eap-aka-kdf) -+ * added support for using driver_test over UDP socket -+ * changed EAP-GPSK to use the IANA assigned EAP method type 51 -+ * updated management frame protection to use IEEE 802.11w/D7.0 -+ * fixed retransmission of EAP requests if no response is received -+ -+2008-11-23 - v0.6.6 -+ * added a new configuration option, wpa_ptk_rekey, that can be used to -+ enforce frequent PTK rekeying, e.g., to mitigate some attacks against -+ TKIP deficiencies -+ * updated OpenSSL code for EAP-FAST to use an updated version of the -+ session ticket overriding API that was included into the upstream -+ OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is -+ needed with that version anymore) -+ * changed channel flags configuration to read the information from -+ the driver (e.g., via driver_nl80211 when using mac80211) instead of -+ using hostapd as the source of the regulatory information (i.e., -+ information from CRDA is now used with mac80211); this allows 5 GHz -+ channels to be used with hostapd (if allowed in the current -+ regulatory domain) -+ * fixed EAP-TLS message processing for the last TLS message if it is -+ large enough to require fragmentation (e.g., if a large Session -+ Ticket data is included) -+ * fixed listen interval configuration for nl80211 drivers -+ -+2008-11-01 - v0.6.5 -+ * added support for SHA-256 as X.509 certificate digest when using the -+ internal X.509/TLSv1 implementation -+ * fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer -+ identity lengths) -+ * fixed internal TLSv1 implementation for abbreviated handshake (used -+ by EAP-FAST server) -+ * added support for setting VLAN ID for STAs based on local MAC ACL -+ (accept_mac_file) as an alternative for RADIUS server-based -+ configuration -+ * updated management frame protection to use IEEE 802.11w/D6.0 -+ (adds a new association ping to protect against unauthenticated -+ authenticate or (re)associate request frames dropping association) -+ * added support for using SHA256-based stronger key derivation for WPA2 -+ (IEEE 802.11w) -+ * added new "driver wrapper" for RADIUS-only configuration -+ (driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config) -+ * fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2) -+ is enabled in configuration -+ * changed EAP-FAST configuration to use separate fields for A-ID and -+ A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed -+ 16-octet len binary value for better interoperability with some peer -+ implementations; eap_fast_a_id is now configured as a hex string -+ * driver_nl80211: Updated to match the current Linux mac80211 AP mode -+ configuration (wireless-testing.git and Linux kernel releases -+ starting from 2.6.29) -+ -+2008-08-10 - v0.6.4 -+ * added peer identity into EAP-FAST PAC-Opaque and skip Phase 2 -+ Identity Request if identity is already known -+ * added support for EAP Sequences in EAP-FAST Phase 2 -+ * added support for EAP-TNC (Trusted Network Connect) -+ (this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST -+ changes needed to run two methods in sequence (IF-T) and the IF-IMV -+ and IF-TNCCS interfaces from TNCS) -+ * added support for optional cryptobinding with PEAPv0 -+ * added fragmentation support for EAP-TNC -+ * added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled) -+ data -+ * added support for opportunistic key caching (OKC) -+ -+2008-02-22 - v0.6.3 -+ * fixed Reassociation Response callback processing when using internal -+ MLME (driver_{hostap,nl80211,test}.c) -+ * updated FT support to use the latest draft, IEEE 802.11r/D9.0 -+ * copy optional Proxy-State attributes into RADIUS response when acting -+ as a RADIUS authentication server -+ * fixed EAPOL state machine to handle a case in which no response is -+ received from the RADIUS authentication server; previous version -+ could have triggered a crash in some cases after a timeout -+ * fixed EAP-SIM/AKA realm processing to allow decorated usernames to -+ be used -+ * added a workaround for EAP-SIM/AKA peers that include incorrect null -+ termination in the username -+ * fixed EAP-SIM/AKA protected result indication to include AT_COUNTER -+ attribute in notification messages only when using fast -+ reauthentication -+ * fixed EAP-SIM Start response processing for fast reauthentication -+ case -+ * added support for pending EAP processing in EAP-{PEAP,TTLS,FAST} -+ phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method -+ -+2008-01-01 - v0.6.2 -+ * fixed EAP-SIM and EAP-AKA message parser to validate attribute -+ lengths properly to avoid potential crash caused by invalid messages -+ * added data structure for storing allocated buffers (struct wpabuf); -+ this does not affect hostapd usage, but many of the APIs changed -+ and various interfaces (e.g., EAP) is not compatible with old -+ versions -+ * added support for protecting EAP-AKA/Identity messages with -+ AT_CHECKCODE (optional feature in RFC 4187) -+ * added support for protected result indication with AT_RESULT_IND for -+ EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1) -+ * added support for configuring EAP-TTLS phase 2 non-EAP methods in -+ EAP server configuration; previously all four were enabled for every -+ phase 2 user, now all four are disabled by default and need to be -+ enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP, -+ TTLS-MSCHAPV2 -+ * removed old debug printing mechanism and the related 'debug' -+ parameter in the configuration file; debug verbosity is now set with -+ -d (or -dd) command line arguments -+ * added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt); -+ only shared key/password authentication is supported in this version -+ -+2007-11-24 - v0.6.1 -+ * added experimental, integrated TLSv1 server implementation with the -+ needed X.509/ASN.1/RSA/bignum processing (this can be enabled by -+ setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in -+ .config); this can be useful, e.g., if the target system does not -+ have a suitable TLS library and a minimal code size is required -+ * added support for EAP-FAST server method to the integrated EAP -+ server -+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest -+ draft (draft-ietf-emu-eap-gpsk-07.txt) -+ * added a new configuration parameter, rsn_pairwise, to allow different -+ pairwise cipher suites to be enabled for WPA and RSN/WPA2 -+ (note: if wpa_pairwise differs from rsn_pairwise, the driver will -+ either need to support this or will have to use the WPA/RSN IEs from -+ hostapd; currently, the included madwifi and bsd driver interfaces do -+ not have support for this) -+ * updated FT support to use the latest draft, IEEE 802.11r/D8.0 -+ -+2007-05-28 - v0.6.0 -+ * added experimental IEEE 802.11r/D6.0 support -+ * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48 -+ * updated EAP-PSK to use the IANA-allocated EAP type 47 -+ * fixed EAP-PSK bit ordering of the Flags field -+ * fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs -+ by reading wpa_psk_file [Bug 181] -+ * fixed EAP-TTLS AVP parser processing for too short AVP lengths -+ * fixed IPv6 connection to RADIUS accounting server -+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest -+ draft (draft-ietf-emu-eap-gpsk-04.txt) -+ * hlr_auc_gw: read GSM triplet file into memory and rotate through the -+ entries instead of only using the same three triplets every time -+ (this does not work properly with tests using multiple clients, but -+ provides bit better triplet data for testing a single client; anyway, -+ if a better quality triplets are needed, GSM-Milenage should be used -+ instead of hardcoded triplet file) -+ * fixed EAP-MSCHAPv2 server to use a space between S and M parameters -+ in Success Request [Bug 203] -+ * added support for sending EAP-AKA Notifications in error cases -+ * updated to use IEEE 802.11w/D2.0 for management frame protection -+ (still experimental) -+ * RADIUS server: added support for processing duplicate messages -+ (retransmissions from RADIUS client) by replying with the previous -+ reply -+ -+2006-11-24 - v0.5.6 -+ * added support for configuring and controlling multiple BSSes per -+ radio interface (bss= in hostapd.conf); this is only -+ available with Devicescape and test driver interfaces -+ * fixed PMKSA cache update in the end of successful RSN -+ pre-authentication -+ * added support for dynamic VLAN configuration (i.e., selecting VLAN-ID -+ for each STA based on RADIUS Access-Accept attributes); this requires -+ VLAN support from the kernel driver/802.11 stack and this is -+ currently only available with Devicescape and test driver interfaces -+ * driver_madwifi: fixed configuration of unencrypted modes (plaintext -+ and IEEE 802.1X without WEP) -+ * removed STAKey handshake since PeerKey handshake has replaced it in -+ IEEE 802.11ma and there are no known deployments of STAKey -+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest -+ draft (draft-ietf-emu-eap-gpsk-01.txt) -+ * added preliminary implementation of IEEE 802.11w/D1.0 (management -+ frame protection) -+ (Note: this requires driver support to work properly.) -+ (Note2: IEEE 802.11w is an unapproved draft and subject to change.) -+ * hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM) -+ * hlr_auc_gw: added support for reading per-IMSI Milenage keys and -+ parameters from a text file to make it possible to implement proper -+ GSM/UMTS authentication server for multiple SIM/USIM cards using -+ EAP-SIM/EAP-AKA -+ * fixed session timeout processing with drivers that do not use -+ ieee802_11.c (e.g., madwifi) -+ -+2006-08-27 - v0.5.5 -+ * added 'hostapd_cli new_sta ' command for adding a new STA into -+ hostapd (e.g., to initialize wired network authentication based on an -+ external signal) -+ * fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when -+ using WPA2 even if PMKSA caching is not used -+ * added -P argument for hostapd to write the current process -+ id into a file -+ * added support for RADIUS Authentication Server MIB (RFC 2619) -+ -+2006-06-20 - v0.5.4 -+ * fixed nt_password_hash build [Bug 144] -+ * added PeerKey handshake implementation for IEEE 802.11e -+ direct link setup (DLS) to replace STAKey handshake -+ * added support for EAP Generalized Pre-Shared Key (EAP-GPSK, -+ draft-clancy-emu-eap-shared-secret-00.txt) -+ * fixed a segmentation fault when RSN pre-authentication was completed -+ successfully [Bug 152] -+ -+2006-04-27 - v0.5.3 -+ * do not build nt_password_hash and hlr_auc_gw by default to avoid -+ requiring a TLS library for a successful build; these programs can be -+ build with 'make nt_password_hash' and 'make hlr_auc_gw' -+ * added a new configuration option, eapol_version, that can be used to -+ set EAPOL version to 1 (default is 2) to work around broken client -+ implementations that drop EAPOL frames which use version number 2 -+ [Bug 89] -+ * added support for EAP-SAKE (no EAP method number allocated yet, so -+ this is using the same experimental type 255 as EAP-PSK) -+ * fixed EAP-MSCHAPv2 message length validation -+ -+2006-03-19 - v0.5.2 -+ * fixed stdarg use in hostapd_logger(): if both stdout and syslog -+ logging was enabled, hostapd could trigger a segmentation fault in -+ vsyslog on some CPU -- C library combinations -+ * moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external -+ program to make it easier to use for implementing real SS7 gateway; -+ eap_sim_db is not anymore used as a file name for GSM authentication -+ triplets; instead, it is path to UNIX domain socket that will be used -+ to communicate with the external gateway program (e.g., hlr_auc_gw) -+ * added example HLR/AuC gateway implementation, hlr_auc_gw, that uses -+ local information (GSM authentication triplets from a text file and -+ hardcoded AKA authentication data); this can be used to test EAP-SIM -+ and EAP-AKA -+ * added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw -+ to make it possible to test EAP-AKA with real USIM cards (this is -+ disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw -+ to enable this) -+ * driver_madwifi: added support for getting station RSN IE from -+ madwifi-ng svn r1453 and newer; this fixes RSN that was apparently -+ broken with earlier change (r1357) in the driver -+ * changed EAP method registration to use a dynamic list of methods -+ instead of a static list generated at build time -+ * fixed WPA message 3/4 not to encrypt Key Data field (WPA IE) -+ [Bug 125] -+ * added ap_max_inactivity configuration parameter -+ -+2006-01-29 - v0.5.1 -+ * driver_test: added better support for multiple APs and STAs by using -+ a directory with sockets that include MAC address for each device in -+ the name (test_socket=DIR:/tmp/test) -+ * added support for EAP expanded type (vendor specific EAP methods) -+ -+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases) -+ * added experimental STAKey handshake implementation for IEEE 802.11e -+ direct link setup (DLS); note: this is disabled by default in both -+ build and runtime configuration (can be enabled with CONFIG_STAKEY=y -+ and stakey=1) -+ * added support for EAP methods to use callbacks to external programs -+ by buffering a pending request and processing it after the EAP method -+ is ready to continue -+ * improved EAP-SIM database interface to allow external request to GSM -+ HLR/AuC without blocking hostapd process -+ * added support for using EAP-SIM pseudonyms and fast re-authentication -+ * added support for EAP-AKA in the integrated EAP authenticator -+ * added support for matching EAP identity prefixes (e.g., "1"*) in EAP -+ user database to allow EAP-SIM/AKA selection without extra roundtrip -+ for EAP-Nak negotiation -+ * added support for storing EAP user password as NtPasswordHash instead -+ of plaintext password when using MSCHAP or MSCHAPv2 for -+ authentication (hash:<16-octet hex value>); added nt_password_hash -+ tool for hashing password to generate NtPasswordHash -+ -+2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases) -+ * driver_wired: fixed EAPOL sending to optionally use PAE group address -+ as the destination instead of supplicant MAC address; this is -+ disabled by default, but should be enabled with use_pae_group_addr=1 -+ in configuration file if the wired interface is used by only one -+ device at the time (common switch configuration) -+ * driver_madwifi: configure driver to use TKIP countermeasures in order -+ to get correct behavior (IEEE 802.11 association failing; previously, -+ association succeeded, but hostpad forced disassociation immediately) -+ * driver_madwifi: added support for madwifi-ng -+ -+2005-10-27 - v0.4.6 -+ * added support for replacing user identity from EAP with RADIUS -+ User-Name attribute from Access-Accept message, if that is included, -+ for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get -+ tunneled identity into accounting messages when the RADIUS server -+ does not support better way of doing this with Class attribute) -+ * driver_madwifi: fixed EAPOL packet receive for configuration where -+ ath# is part of a bridge interface -+ * added a configuration file and log analyzer script for logwatch -+ * fixed EAPOL state machine step function to process all state -+ transitions before processing new events; this resolves a race -+ condition in which EAPOL-Start message could trigger hostapd to send -+ two EAP-Response/Identity frames to the authentication server -+ -+2005-09-25 - v0.4.5 -+ * added client CA list to the TLS certificate request in order to make -+ it easier for the client to select which certificate to use -+ * added experimental support for EAP-PSK -+ * added support for WE-19 (hostap, madwifi) -+ -+2005-08-21 - v0.4.4 -+ * fixed build without CONFIG_RSN_PREAUTH -+ * fixed FreeBSD build -+ -+2005-06-26 - v0.4.3 -+ * fixed PMKSA caching to copy User-Name and Class attributes so that -+ RADIUS accounting gets correct information -+ * start RADIUS accounting only after successful completion of WPA -+ 4-Way Handshake if WPA-PSK is used -+ * fixed PMKSA caching for the case where STA (re)associates without -+ first disassociating -+ -+2005-06-12 - v0.4.2 -+ * EAP-PAX is now registered as EAP type 46 -+ * fixed EAP-PAX MAC calculation -+ * fixed EAP-PAX CK and ICK key derivation -+ * renamed eap_authenticator configuration variable to eap_server to -+ better match with RFC 3748 (EAP) terminology -+ * driver_test: added support for testing hostapd with wpa_supplicant -+ by using test driver interface without any kernel drivers or network -+ cards -+ -+2005-05-22 - v0.4.1 -+ * fixed RADIUS server initialization when only auth or acct server -+ is configured and the other one is left empty -+ * driver_madwifi: added support for RADIUS accounting -+ * driver_madwifi: added preliminary support for compiling against 'BSD' -+ branch of madwifi CVS tree -+ * driver_madwifi: fixed pairwise key removal to allow WPA reauth -+ without disassociation -+ * added support for reading additional certificates from PKCS#12 files -+ and adding them to the certificate chain -+ * fixed RADIUS Class attribute processing to only use Access-Accept -+ packets to update Class; previously, other RADIUS authentication -+ packets could have cleared Class attribute -+ * added support for more than one Class attribute in RADIUS packets -+ * added support for verifying certificate revocation list (CRL) when -+ using integrated EAP authenticator for EAP-TLS; new hostapd.conf -+ options 'check_crl'; CRL must be included in the ca_cert file for now -+ -+2005-04-25 - v0.4.0 (beginning of 0.4.x development releases) -+ * added support for including network information into -+ EAP-Request/Identity message (ASCII-0 (nul) in eap_message) -+ (e.g., to implement draft-adrange-eap-network-discovery-07.txt) -+ * fixed a bug which caused some RSN pre-authentication cases to use -+ freed memory and potentially crash hostapd -+ * fixed private key loading for cases where passphrase is not set -+ * added support for sending TLS alerts and aborting authentication -+ when receiving a TLS alert -+ * fixed WPA2 to add PMKSA cache entry when using integrated EAP -+ authenticator -+ * fixed PMKSA caching (EAP authentication was not skipped correctly -+ with the new state machine changes from IEEE 802.1X draft) -+ * added support for RADIUS over IPv6; own_ip_addr, auth_server_addr, -+ and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs -+ to be added to .config to include IPv6 support); for RADIUS server, -+ radius_server_ipv6=1 needs to be set in hostapd.conf and addresses -+ in RADIUS clients file can then use IPv6 format -+ * added experimental support for EAP-PAX -+ * replaced hostapd control interface library (hostapd_ctrl.[ch]) with -+ the same implementation that wpa_supplicant is using (wpa_ctrl.[ch]) -+ -+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases) -+ -+2005-01-23 - v0.3.5 -+ * added support for configuring a forced PEAP version based on the -+ Phase 1 identity -+ * fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV -+ to terminate authentication -+ * fixed EAP identifier duplicate processing with the new IEEE 802.1X -+ draft -+ * clear accounting data in the driver when starting a new accounting -+ session -+ * driver_madwifi: filter wireless events based on ifindex to allow more -+ than one network interface to be used -+ * fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt -+ setting if the packet does not pass MIC verification (e.g., due to -+ incorrect PSK); previously, message 1/4 was not tried again if an -+ invalid message 2/4 was received -+ * fixed reconfiguration of RADIUS client retransmission timer when -+ adding a new message to the pending list; previously, timer was not -+ updated at this point and if there was a pending message with long -+ time for the next retry, the new message needed to wait that long for -+ its first retry, too -+ -+2005-01-09 - v0.3.4 -+ * added support for configuring multiple allowed EAP types for Phase 2 -+ authentication (EAP-PEAP, EAP-TTLS) -+ * fixed EAPOL-Start processing to trigger WPA reauthentication -+ (previously, only EAPOL authentication was done) -+ -+2005-01-02 - v0.3.3 -+ * added support for EAP-PEAP in the integrated EAP authenticator -+ * added support for EAP-GTC in the integrated EAP authenticator -+ * added support for configuring list of EAP methods for Phase 1 so that -+ the integrated EAP authenticator can, e.g., use the wildcard entry -+ for EAP-TLS and EAP-PEAP -+ * added support for EAP-TTLS in the integrated EAP authenticator -+ * added support for EAP-SIM in the integrated EAP authenticator -+ * added support for using hostapd as a RADIUS authentication server -+ with the integrated EAP authenticator taking care of EAP -+ authentication (new hostapd.conf options: radius_server_clients and -+ radius_server_auth_port); this is not included in default build; use -+ CONFIG_RADIUS_SERVER=y in .config to include -+ -+2004-12-19 - v0.3.2 -+ * removed 'daemonize' configuration file option since it has not really -+ been used at all for more than year -+ * driver_madwifi: fixed group key setup and added get_ssid method -+ * added support for EAP-MSCHAPv2 in the integrated EAP authenticator -+ -+2004-12-12 - v0.3.1 -+ * added support for integrated EAP-TLS authentication (new hostapd.conf -+ variables: ca_cert, server_cert, private_key, private_key_passwd); -+ this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without -+ external RADIUS server -+ * added support for reading PKCS#12 (PFX) files (as a replacement for -+ PEM/DER) to get certificate and private key (CONFIG_PKCS12) -+ -+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases) -+ * added support for Acct-{Input,Output}-Gigawords -+ * added support for Event-Timestamp (in RADIUS Accounting-Requests) -+ * added support for RADIUS Authentication Client MIB (RFC2618) -+ * added support for RADIUS Accounting Client MIB (RFC2620) -+ * made EAP re-authentication period configurable (eap_reauth_period) -+ * fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication -+ * fixed EAPOL state machine to stop if STA is removed during -+ eapol_sm_step(); this fixes at least one segfault triggering bug with -+ IEEE 802.11i pre-authentication -+ * added support for multiple WPA pre-shared keys (e.g., one for each -+ client MAC address or keys shared by a group of clients); -+ new hostapd.conf field wpa_psk_file for setting path to a text file -+ containing PSKs, see hostapd.wpa_psk for an example -+ * added support for multiple driver interfaces to allow hostapd to be -+ used with other drivers -+ * added wired authenticator driver interface (driver=wired in -+ hostapd.conf, see wired.conf for example configuration) -+ * added madwifi driver interface (driver=madwifi in hostapd.conf, see -+ madwifi.conf for example configuration; Note: include files from -+ madwifi project is needed for building and a configuration file, -+ .config, needs to be created in hostapd directory with -+ CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd -+ build) -+ * fixed an alignment issue that could cause SHA-1 to fail on some -+ platforms (e.g., Intel ixp425 with a compiler that does not 32-bit -+ align variables) -+ * fixed RADIUS reconnection after an error in sending interim -+ accounting packets -+ * added hostapd control interface for external programs and an example -+ CLI, hostapd_cli (like wpa_cli for wpa_supplicant) -+ * started adding dot11, dot1x, radius MIBs ('hostapd_cli mib', -+ 'hostapd_cli sta ') -+ * finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11) -+ * added support for strict GTK rekeying (wpa_strict_rekey in -+ hostapd.conf) -+ * updated IAPP to use UDP port 3517 and multicast address 224.0.1.178 -+ (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to -+ IEEE 802.11F-2003) -+ * added Prism54 driver interface (driver=prism54 in hostapd.conf; -+ note: .config needs to be created in hostapd directory with -+ CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd -+ build) -+ * dual-licensed hostapd (GPLv2 and BSD licenses) -+ * fixed RADIUS accounting to generate a new session id for cases where -+ a station reassociates without first being complete deauthenticated -+ * fixed STA disassociation handler to mark next timeout state to -+ deauthenticate the station, i.e., skip long wait for inactivity poll -+ and extra disassociation, if the STA disassociates without -+ deauthenticating -+ * added integrated EAP authenticator that can be used instead of -+ external RADIUS authentication server; currently, only EAP-MD5 is -+ supported, so this cannot yet be used for key distribution; the EAP -+ method interface is generic, though, so adding new EAP methods should -+ be straightforward; new hostapd.conf variables: 'eap_authenticator' -+ and 'eap_user_file'; this obsoletes "minimal authentication server" -+ ('minimal_eap' in hostapd.conf) which is now removed -+ * added support for FreeBSD and driver interface for the BSD net80211 -+ layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in -+ .config); please note that some of the required kernel mods have not -+ yet been committed -+ -+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases) -+ * fixed some accounting cases where Accounting-Start was sent when -+ IEEE 802.1X port was being deauthorized -+ -+2004-06-20 - v0.2.3 -+ * modified RADIUS client to re-connect the socket in case of certain -+ error codes that are generated when a network interface state is -+ changes (e.g., when IP address changes or the interface is set UP) -+ * fixed couple of cases where EAPOL state for a station was freed -+ twice causing a segfault for hostapd -+ * fixed couple of bugs in processing WPA deauthentication (freed data -+ was used) -+ -+2004-05-31 - v0.2.2 -+ * fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM) -+ * fixed group rekeying to send zero TSC in EAPOL-Key messages to fix -+ cases where STAs dropped multicast frames as replay attacks -+ * added support for copying RADIUS Attribute 'Class' from -+ authentication messages into accounting messages -+ * send canned EAP failure if RADIUS server sends Access-Reject without -+ EAP message (previously, Supplicant was not notified in this case) -+ * fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do -+ not start EAPOL state machines if the STA selected to use WPA-PSK) -+ -+2004-05-06 - v0.2.1 -+ * added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality -+ - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA -+ (i.e., IEEE 802.11i/D3.0) -+ - supports WPA-only, RSN-only, and mixed WPA/RSN mode -+ - both WPA-PSK and WPA-RADIUS/EAP are supported -+ - PMKSA caching and pre-authentication -+ - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase, -+ wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey, -+ rsn_preauth, rsn_preauth_interfaces -+ * fixed interim accounting to remove any pending accounting messages -+ to the STA before sending a new one -+ -+2004-02-15 - v0.2.0 -+ * added support for Acct-Interim-Interval: -+ - draft-ietf-radius-acct-interim-01.txt -+ - use Acct-Interim-Interval attribute from Access-Accept if local -+ 'radius_acct_interim_interval' is not set -+ - allow different update intervals for each STA -+ * fixed event loop to call signal handlers only after returning from -+ the real signal handler -+ * reset sta->timeout_next after successful association to make sure -+ that the previously registered inactivity timer will not remove the -+ STA immediately (e.g., if STA deauthenticates and re-associates -+ before the timer is triggered). -+ * added new hostapd.conf variable, nas_identifier, that can be used to -+ add an optional RADIUS Attribute, NAS-Identifier, into authentication -+ and accounting messages -+ * added support for Accounting-On and Accounting-Off messages -+ * fixed accounting session handling to send Accounting-Start only once -+ per session and not to send Accounting-Stop if the session was not -+ initialized properly -+ * fixed Accounting-Stop statistics in cases where the message was -+ previously sent after the kernel entry for the STA (and/or IEEE -+ 802.1X data) was removed -+ -+ -+Note: -+ -+Older changes up to and including v0.1.0 are included in the ChangeLog -+of the Host AP driver. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Makefile -new file mode 100644 -index 0000000000000..d05975b29e69e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/Makefile -@@ -0,0 +1,836 @@ -+ifndef CC -+CC=gcc -+endif -+ -+ifndef CFLAGS -+CFLAGS = -MMD -O2 -Wall -g -+endif -+ -+CFLAGS += -I../src -+CFLAGS += -I../src/utils -+ -+# Uncomment following line and set the path to your kernel tree include -+# directory if your C library does not include all header files. -+# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include -+ -+-include .config -+ -+ifndef CONFIG_OS -+ifdef CONFIG_NATIVE_WINDOWS -+CONFIG_OS=win32 -+else -+CONFIG_OS=unix -+endif -+endif -+ -+ifeq ($(CONFIG_OS), internal) -+CFLAGS += -DOS_NO_C_LIB_DEFINES -+endif -+ -+ifdef CONFIG_NATIVE_WINDOWS -+CFLAGS += -DCONFIG_NATIVE_WINDOWS -+LIBS += -lws2_32 -+endif -+ -+OBJS += main.o -+OBJS += config_file.o -+ -+OBJS += ../src/ap/hostapd.o -+OBJS += ../src/ap/wpa_auth_glue.o -+OBJS += ../src/ap/drv_callbacks.o -+OBJS += ../src/ap/ap_drv_ops.o -+OBJS += ../src/ap/utils.o -+OBJS += ../src/ap/authsrv.o -+OBJS += ../src/ap/ieee802_1x.o -+OBJS += ../src/ap/ap_config.o -+OBJS += ../src/ap/ieee802_11_auth.o -+OBJS += ../src/ap/sta_info.o -+OBJS += ../src/ap/wpa_auth.o -+OBJS += ../src/ap/tkip_countermeasures.o -+OBJS += ../src/ap/ap_mlme.o -+OBJS += ../src/ap/wpa_auth_ie.o -+OBJS += ../src/ap/preauth_auth.o -+OBJS += ../src/ap/pmksa_cache_auth.o -+ -+NEED_RC4=y -+NEED_AES=y -+NEED_MD5=y -+NEED_SHA1=y -+ -+OBJS += ../src/drivers/drivers.o -+CFLAGS += -DHOSTAPD -+ -+ifdef CONFIG_WPA_TRACE -+CFLAGS += -DWPA_TRACE -+OBJS += ../src/utils/trace.o -+HOBJS += ../src/utils/trace.o -+LDFLAGS += -rdynamic -+CFLAGS += -funwind-tables -+ifdef CONFIG_WPA_TRACE_BFD -+CFLAGS += -DWPA_TRACE_BFD -+LIBS += -lbfd -+LIBS_c += -lbfd -+LIBS_h += -lbfd -+endif -+endif -+ -+OBJS += ../src/utils/eloop.o -+OBJS += ../src/utils/common.o -+OBJS += ../src/utils/wpa_debug.o -+OBJS += ../src/utils/wpabuf.o -+OBJS += ../src/utils/os_$(CONFIG_OS).o -+OBJS += ../src/utils/ip_addr.o -+ -+OBJS += ../src/common/ieee802_11_common.o -+OBJS += ../src/common/wpa_common.o -+ -+OBJS += ../src/eapol_auth/eapol_auth_sm.o -+ -+ -+ifndef CONFIG_NO_DUMP_STATE -+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to -+# a file (undefine it, if you want to save in binary size) -+CFLAGS += -DHOSTAPD_DUMP_STATE -+OBJS += dump_state.o -+OBJS += ../src/eapol_auth/eapol_auth_dump.o -+endif -+ -+ifdef CONFIG_NO_RADIUS -+CFLAGS += -DCONFIG_NO_RADIUS -+CONFIG_NO_ACCOUNTING=y -+else -+OBJS += ../src/radius/radius.o -+OBJS += ../src/radius/radius_client.o -+endif -+ -+ifdef CONFIG_NO_ACCOUNTING -+CFLAGS += -DCONFIG_NO_ACCOUNTING -+else -+OBJS += ../src/ap/accounting.o -+endif -+ -+ifdef CONFIG_NO_VLAN -+CFLAGS += -DCONFIG_NO_VLAN -+else -+OBJS += ../src/ap/vlan_init.o -+endif -+ -+ifdef CONFIG_NO_CTRL_IFACE -+CFLAGS += -DCONFIG_NO_CTRL_IFACE -+else -+OBJS += ctrl_iface.o -+OBJS += ../src/ap/ctrl_iface_ap.o -+endif -+ -+OBJS += ../src/crypto/md5.o -+ -+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX -+ -+ifdef CONFIG_IAPP -+CFLAGS += -DCONFIG_IAPP -+OBJS += ../src/ap/iapp.o -+endif -+ -+ifdef CONFIG_RSN_PREAUTH -+CFLAGS += -DCONFIG_RSN_PREAUTH -+CONFIG_L2_PACKET=y -+endif -+ -+ifdef CONFIG_PEERKEY -+CFLAGS += -DCONFIG_PEERKEY -+OBJS += ../src/ap/peerkey_auth.o -+endif -+ -+ifdef CONFIG_IEEE80211W -+CFLAGS += -DCONFIG_IEEE80211W -+NEED_SHA256=y -+NEED_AES_OMAC1=y -+endif -+ -+ifdef CONFIG_IEEE80211R -+CFLAGS += -DCONFIG_IEEE80211R -+OBJS += ../src/ap/wpa_auth_ft.o -+NEED_SHA256=y -+NEED_AES_OMAC1=y -+NEED_AES_UNWRAP=y -+endif -+ -+ifdef CONFIG_IEEE80211N -+CFLAGS += -DCONFIG_IEEE80211N -+endif -+ -+include ../src/drivers/drivers.mak -+OBJS += $(DRV_AP_OBJS) -+CFLAGS += $(DRV_AP_CFLAGS) -+LDFLAGS += $(DRV_AP_LDFLAGS) -+LIBS += $(DRV_AP_LIBS) -+ -+ifdef CONFIG_L2_PACKET -+ifdef CONFIG_DNET_PCAP -+ifdef CONFIG_L2_FREEBSD -+LIBS += -lpcap -+OBJS += ../src/l2_packet/l2_packet_freebsd.o -+else -+LIBS += -ldnet -lpcap -+OBJS += ../src/l2_packet/l2_packet_pcap.o -+endif -+else -+OBJS += ../src/l2_packet/l2_packet_linux.o -+endif -+else -+OBJS += ../src/l2_packet/l2_packet_none.o -+endif -+ -+ -+ifdef CONFIG_EAP_MD5 -+CFLAGS += -DEAP_SERVER_MD5 -+OBJS += ../src/eap_server/eap_server_md5.o -+CHAP=y -+endif -+ -+ifdef CONFIG_EAP_TLS -+CFLAGS += -DEAP_SERVER_TLS -+OBJS += ../src/eap_server/eap_server_tls.o -+TLS_FUNCS=y -+endif -+ -+ifdef CONFIG_EAP_PEAP -+CFLAGS += -DEAP_SERVER_PEAP -+OBJS += ../src/eap_server/eap_server_peap.o -+OBJS += ../src/eap_common/eap_peap_common.o -+TLS_FUNCS=y -+CONFIG_EAP_MSCHAPV2=y -+endif -+ -+ifdef CONFIG_EAP_TTLS -+CFLAGS += -DEAP_SERVER_TTLS -+OBJS += ../src/eap_server/eap_server_ttls.o -+TLS_FUNCS=y -+CHAP=y -+endif -+ -+ifdef CONFIG_EAP_MSCHAPV2 -+CFLAGS += -DEAP_SERVER_MSCHAPV2 -+OBJS += ../src/eap_server/eap_server_mschapv2.o -+MS_FUNCS=y -+endif -+ -+ifdef CONFIG_EAP_GTC -+CFLAGS += -DEAP_SERVER_GTC -+OBJS += ../src/eap_server/eap_server_gtc.o -+endif -+ -+ifdef CONFIG_EAP_SIM -+CFLAGS += -DEAP_SERVER_SIM -+OBJS += ../src/eap_server/eap_server_sim.o -+CONFIG_EAP_SIM_COMMON=y -+NEED_AES_CBC=y -+endif -+ -+ifdef CONFIG_EAP_AKA -+CFLAGS += -DEAP_SERVER_AKA -+OBJS += ../src/eap_server/eap_server_aka.o -+CONFIG_EAP_SIM_COMMON=y -+NEED_SHA256=y -+NEED_AES_CBC=y -+endif -+ -+ifdef CONFIG_EAP_AKA_PRIME -+CFLAGS += -DEAP_SERVER_AKA_PRIME -+endif -+ -+ifdef CONFIG_EAP_SIM_COMMON -+OBJS += ../src/eap_common/eap_sim_common.o -+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be -+# replaced with another file implementating the interface specified in -+# eap_sim_db.h. -+OBJS += ../src/eap_server/eap_sim_db.o -+NEED_FIPS186_2_PRF=y -+endif -+ -+ifdef CONFIG_EAP_PAX -+CFLAGS += -DEAP_SERVER_PAX -+OBJS += ../src/eap_server/eap_server_pax.o ../src/eap_common/eap_pax_common.o -+endif -+ -+ifdef CONFIG_EAP_PSK -+CFLAGS += -DEAP_SERVER_PSK -+OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o -+NEED_AES_OMAC1=y -+NEED_AES_ENCBLOCK=y -+NEED_AES_EAX=y -+endif -+ -+ifdef CONFIG_EAP_SAKE -+CFLAGS += -DEAP_SERVER_SAKE -+OBJS += ../src/eap_server/eap_server_sake.o ../src/eap_common/eap_sake_common.o -+endif -+ -+ifdef CONFIG_EAP_GPSK -+CFLAGS += -DEAP_SERVER_GPSK -+OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o -+ifdef CONFIG_EAP_GPSK_SHA256 -+CFLAGS += -DEAP_SERVER_GPSK_SHA256 -+endif -+NEED_SHA256=y -+NEED_AES_OMAC1=y -+endif -+ -+ifdef CONFIG_EAP_PWD -+CFLAGS += -DEAP_SERVER_PWD -+OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o -+NEED_SHA256=y -+endif -+ -+ifdef CONFIG_EAP_VENDOR_TEST -+CFLAGS += -DEAP_SERVER_VENDOR_TEST -+OBJS += ../src/eap_server/eap_server_vendor_test.o -+endif -+ -+ifdef CONFIG_EAP_FAST -+CFLAGS += -DEAP_SERVER_FAST -+OBJS += ../src/eap_server/eap_server_fast.o -+OBJS += ../src/eap_common/eap_fast_common.o -+TLS_FUNCS=y -+NEED_T_PRF=y -+NEED_AES_UNWRAP=y -+endif -+ -+ifdef CONFIG_WPS -+ifdef CONFIG_WPS2 -+CFLAGS += -DCONFIG_WPS2 -+endif -+ -+CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC -+OBJS += ../src/utils/uuid.o -+OBJS += ../src/ap/wps_hostapd.o -+OBJS += ../src/eap_server/eap_server_wsc.o ../src/eap_common/eap_wsc_common.o -+OBJS += ../src/wps/wps.o -+OBJS += ../src/wps/wps_common.o -+OBJS += ../src/wps/wps_attr_parse.o -+OBJS += ../src/wps/wps_attr_build.o -+OBJS += ../src/wps/wps_attr_process.o -+OBJS += ../src/wps/wps_dev_attr.o -+OBJS += ../src/wps/wps_enrollee.o -+OBJS += ../src/wps/wps_registrar.o -+NEED_DH_GROUPS=y -+NEED_SHA256=y -+NEED_BASE64=y -+NEED_AES_CBC=y -+NEED_MODEXP=y -+CONFIG_EAP=y -+ -+ifdef CONFIG_WPS_UFD -+CFLAGS += -DCONFIG_WPS_UFD -+OBJS += ../src/wps/wps_ufd.o -+NEED_WPS_OOB=y -+endif -+ -+ifdef CONFIG_WPS_NFC -+CFLAGS += -DCONFIG_WPS_NFC -+OBJS += ../src/wps/ndef.o -+OBJS += ../src/wps/wps_nfc.o -+NEED_WPS_OOB=y -+ifdef CONFIG_WPS_NFC_PN531 -+PN531_PATH ?= /usr/local/src/nfc -+CFLAGS += -DCONFIG_WPS_NFC_PN531 -+CFLAGS += -I${PN531_PATH}/inc -+OBJS += ../src/wps/wps_nfc_pn531.o -+LIBS += ${PN531_PATH}/lib/wpsnfc.dll -+LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll -+endif -+endif -+ -+ifdef NEED_WPS_OOB -+CFLAGS += -DCONFIG_WPS_OOB -+endif -+ -+ifdef CONFIG_WPS_UPNP -+CFLAGS += -DCONFIG_WPS_UPNP -+OBJS += ../src/wps/wps_upnp.o -+OBJS += ../src/wps/wps_upnp_ssdp.o -+OBJS += ../src/wps/wps_upnp_web.o -+OBJS += ../src/wps/wps_upnp_event.o -+OBJS += ../src/wps/wps_upnp_ap.o -+OBJS += ../src/wps/upnp_xml.o -+OBJS += ../src/wps/httpread.o -+OBJS += ../src/wps/http_client.o -+OBJS += ../src/wps/http_server.o -+endif -+ -+ifdef CONFIG_WPS_STRICT -+CFLAGS += -DCONFIG_WPS_STRICT -+OBJS += ../src/wps/wps_validate.o -+endif -+ -+ifdef CONFIG_WPS_TESTING -+CFLAGS += -DCONFIG_WPS_TESTING -+endif -+ -+endif -+ -+ifdef CONFIG_EAP_IKEV2 -+CFLAGS += -DEAP_SERVER_IKEV2 -+OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o -+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o -+NEED_DH_GROUPS=y -+NEED_DH_GROUPS_ALL=y -+NEED_MODEXP=y -+NEED_CIPHER=y -+endif -+ -+ifdef CONFIG_EAP_TNC -+CFLAGS += -DEAP_SERVER_TNC -+OBJS += ../src/eap_server/eap_server_tnc.o -+OBJS += ../src/eap_server/tncs.o -+NEED_BASE64=y -+ifndef CONFIG_DRIVER_BSD -+LIBS += -ldl -+endif -+endif -+ -+# Basic EAP functionality is needed for EAPOL -+OBJS += eap_register.o -+OBJS += ../src/eap_server/eap_server.o -+OBJS += ../src/eap_common/eap_common.o -+OBJS += ../src/eap_server/eap_server_methods.o -+OBJS += ../src/eap_server/eap_server_identity.o -+CFLAGS += -DEAP_SERVER_IDENTITY -+ -+ifdef CONFIG_EAP -+CFLAGS += -DEAP_SERVER -+endif -+ -+ifdef CONFIG_PKCS12 -+CFLAGS += -DPKCS12_FUNCS -+endif -+ -+ifdef MS_FUNCS -+OBJS += ../src/crypto/ms_funcs.o -+NEED_DES=y -+NEED_MD4=y -+endif -+ -+ifdef CHAP -+OBJS += ../src/eap_common/chap.o -+endif -+ -+ifdef TLS_FUNCS -+NEED_DES=y -+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) -+CFLAGS += -DEAP_TLS_FUNCS -+OBJS += ../src/eap_server/eap_server_tls_common.o -+NEED_TLS_PRF=y -+endif -+ -+ifndef CONFIG_TLS -+CONFIG_TLS=openssl -+endif -+ -+ifeq ($(CONFIG_TLS), openssl) -+ifdef TLS_FUNCS -+OBJS += ../src/crypto/tls_openssl.o -+LIBS += -lssl -+endif -+OBJS += ../src/crypto/crypto_openssl.o -+HOBJS += ../src/crypto/crypto_openssl.o -+ifdef NEED_FIPS186_2_PRF -+OBJS += ../src/crypto/fips_prf_openssl.o -+endif -+LIBS += -lcrypto -+LIBS_h += -lcrypto -+endif -+ -+ifeq ($(CONFIG_TLS), gnutls) -+ifdef TLS_FUNCS -+OBJS += ../src/crypto/tls_gnutls.o -+LIBS += -lgnutls -lgpg-error -+ifdef CONFIG_GNUTLS_EXTRA -+CFLAGS += -DCONFIG_GNUTLS_EXTRA -+LIBS += -lgnutls-extra -+endif -+endif -+OBJS += ../src/crypto/crypto_gnutls.o -+HOBJS += ../src/crypto/crypto_gnutls.o -+ifdef NEED_FIPS186_2_PRF -+OBJS += ../src/crypto/fips_prf_gnutls.o -+endif -+LIBS += -lgcrypt -+LIBS_h += -lgcrypt -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ -+ifeq ($(CONFIG_TLS), schannel) -+ifdef TLS_FUNCS -+OBJS += ../src/crypto/tls_schannel.o -+endif -+OBJS += ../src/crypto/crypto_cryptoapi.o -+OBJS_p += ../src/crypto/crypto_cryptoapi.o -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ -+ifeq ($(CONFIG_TLS), nss) -+ifdef TLS_FUNCS -+OBJS += ../src/crypto/tls_nss.o -+LIBS += -lssl3 -+endif -+OBJS += ../src/crypto/crypto_nss.o -+ifdef NEED_FIPS186_2_PRF -+OBJS += ../src/crypto/fips_prf_nss.o -+endif -+LIBS += -lnss3 -+LIBS_h += -lnss3 -+CONFIG_INTERNAL_MD4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ -+ifeq ($(CONFIG_TLS), internal) -+ifndef CONFIG_CRYPTO -+CONFIG_CRYPTO=internal -+endif -+ifdef TLS_FUNCS -+OBJS += ../src/crypto/crypto_internal-rsa.o -+OBJS += ../src/crypto/tls_internal.o -+OBJS += ../src/tls/tlsv1_common.o -+OBJS += ../src/tls/tlsv1_record.o -+OBJS += ../src/tls/tlsv1_cred.o -+OBJS += ../src/tls/tlsv1_server.o -+OBJS += ../src/tls/tlsv1_server_write.o -+OBJS += ../src/tls/tlsv1_server_read.o -+OBJS += ../src/tls/asn1.o -+OBJS += ../src/tls/rsa.o -+OBJS += ../src/tls/x509v3.o -+OBJS += ../src/tls/pkcs1.o -+OBJS += ../src/tls/pkcs5.o -+OBJS += ../src/tls/pkcs8.o -+NEED_SHA256=y -+NEED_BASE64=y -+NEED_TLS_PRF=y -+NEED_MODEXP=y -+NEED_CIPHER=y -+CFLAGS += -DCONFIG_TLS_INTERNAL -+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER -+endif -+ifdef NEED_CIPHER -+NEED_DES=y -+OBJS += ../src/crypto/crypto_internal-cipher.o -+endif -+ifdef NEED_MODEXP -+OBJS += ../src/crypto/crypto_internal-modexp.o -+OBJS += ../src/tls/bignum.o -+endif -+ifeq ($(CONFIG_CRYPTO), libtomcrypt) -+OBJS += ../src/crypto/crypto_libtomcrypt.o -+LIBS += -ltomcrypt -ltfm -+LIBS_h += -ltomcrypt -ltfm -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ifeq ($(CONFIG_CRYPTO), internal) -+OBJS += ../src/crypto/crypto_internal.o -+NEED_AES_DEC=y -+CFLAGS += -DCONFIG_CRYPTO_INTERNAL -+ifdef CONFIG_INTERNAL_LIBTOMMATH -+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH -+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST -+CFLAGS += -DLTM_FAST -+endif -+else -+LIBS += -ltommath -+LIBS_h += -ltommath -+endif -+CONFIG_INTERNAL_AES=y -+CONFIG_INTERNAL_DES=y -+CONFIG_INTERNAL_SHA1=y -+CONFIG_INTERNAL_MD4=y -+CONFIG_INTERNAL_MD5=y -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+CONFIG_INTERNAL_DH_GROUP5=y -+endif -+ifeq ($(CONFIG_CRYPTO), cryptoapi) -+OBJS += ../src/crypto/crypto_cryptoapi.o -+OBJS_p += ../src/crypto/crypto_cryptoapi.o -+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+endif -+endif -+ -+ifeq ($(CONFIG_TLS), none) -+ifdef TLS_FUNCS -+OBJS += ../src/crypto/tls_none.o -+CFLAGS += -DEAP_TLS_NONE -+CONFIG_INTERNAL_AES=y -+CONFIG_INTERNAL_SHA1=y -+CONFIG_INTERNAL_MD5=y -+endif -+OBJS += ../src/crypto/crypto_none.o -+OBJS_p += ../src/crypto/crypto_none.o -+CONFIG_INTERNAL_SHA256=y -+CONFIG_INTERNAL_RC4=y -+endif -+ -+ifndef TLS_FUNCS -+OBJS += ../src/crypto/tls_none.o -+ifeq ($(CONFIG_TLS), internal) -+CONFIG_INTERNAL_AES=y -+CONFIG_INTERNAL_SHA1=y -+CONFIG_INTERNAL_MD5=y -+CONFIG_INTERNAL_RC4=y -+endif -+endif -+ -+AESOBJS = # none so far -+ifdef CONFIG_INTERNAL_AES -+AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o -+endif -+ -+AESOBJS += ../src/crypto/aes-wrap.o -+ifdef NEED_AES_EAX -+AESOBJS += ../src/crypto/aes-eax.o -+NEED_AES_CTR=y -+endif -+ifdef NEED_AES_CTR -+AESOBJS += ../src/crypto/aes-ctr.o -+endif -+ifdef NEED_AES_ENCBLOCK -+AESOBJS += ../src/crypto/aes-encblock.o -+endif -+ifdef NEED_AES_OMAC1 -+AESOBJS += ../src/crypto/aes-omac1.o -+endif -+ifdef NEED_AES_UNWRAP -+NEED_AES_DEC=y -+AESOBJS += ../src/crypto/aes-unwrap.o -+endif -+ifdef NEED_AES_CBC -+NEED_AES_DEC=y -+AESOBJS += ../src/crypto/aes-cbc.o -+endif -+ifdef NEED_AES_DEC -+ifdef CONFIG_INTERNAL_AES -+AESOBJS += ../src/crypto/aes-internal-dec.o -+endif -+endif -+ifdef NEED_AES -+OBJS += $(AESOBJS) -+endif -+ -+ifdef NEED_SHA1 -+SHA1OBJS += ../src/crypto/sha1.o -+ifdef CONFIG_INTERNAL_SHA1 -+SHA1OBJS += ../src/crypto/sha1-internal.o -+ifdef NEED_FIPS186_2_PRF -+SHA1OBJS += ../src/crypto/fips_prf_internal.o -+endif -+endif -+SHA1OBJS += ../src/crypto/sha1-pbkdf2.o -+ifdef NEED_T_PRF -+SHA1OBJS += ../src/crypto/sha1-tprf.o -+endif -+ifdef NEED_TLS_PRF -+SHA1OBJS += ../src/crypto/sha1-tlsprf.o -+endif -+endif -+ -+ifdef NEED_SHA1 -+OBJS += $(SHA1OBJS) -+endif -+ -+ifdef NEED_MD5 -+ifdef CONFIG_INTERNAL_MD5 -+OBJS += ../src/crypto/md5-internal.o -+HOBJS += ../src/crypto/md5-internal.o -+endif -+endif -+ -+ifdef NEED_MD4 -+ifdef CONFIG_INTERNAL_MD4 -+OBJS += ../src/crypto/md4-internal.o -+endif -+endif -+ -+ifdef NEED_DES -+ifdef CONFIG_INTERNAL_DES -+OBJS += ../src/crypto/des-internal.o -+endif -+endif -+ -+ifdef NEED_RC4 -+ifdef CONFIG_INTERNAL_RC4 -+OBJS += ../src/crypto/rc4.o -+endif -+endif -+ -+ifdef NEED_SHA256 -+OBJS += ../src/crypto/sha256.o -+ifdef CONFIG_INTERNAL_SHA256 -+OBJS += ../src/crypto/sha256-internal.o -+endif -+endif -+ -+ifdef NEED_DH_GROUPS -+OBJS += ../src/crypto/dh_groups.o -+endif -+ifdef NEED_DH_GROUPS_ALL -+CFLAGS += -DALL_DH_GROUPS -+endif -+ifdef CONFIG_INTERNAL_DH_GROUP5 -+ifdef NEED_DH_GROUPS -+OBJS += ../src/crypto/dh_group5.o -+endif -+endif -+ -+ifdef CONFIG_NO_RANDOM_POOL -+CFLAGS += -DCONFIG_NO_RANDOM_POOL -+else -+OBJS += ../src/crypto/random.o -+HOBJS += ../src/crypto/random.o -+HOBJS += $(SHA1OBJS) -+HOBJS += ../src/crypto/md5.o -+endif -+ -+ifdef CONFIG_RADIUS_SERVER -+CFLAGS += -DRADIUS_SERVER -+OBJS += ../src/radius/radius_server.o -+endif -+ -+ifdef CONFIG_IPV6 -+CFLAGS += -DCONFIG_IPV6 -+endif -+ -+ifdef CONFIG_DRIVER_RADIUS_ACL -+CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL -+endif -+ -+ifdef CONFIG_FULL_DYNAMIC_VLAN -+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges -+# and vlan interfaces for the vlan feature. -+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN -+endif -+ -+ifdef NEED_BASE64 -+OBJS += ../src/utils/base64.o -+endif -+ -+ifdef NEED_AP_MLME -+OBJS += ../src/ap/beacon.o -+OBJS += ../src/ap/wmm.o -+OBJS += ../src/ap/ap_list.o -+OBJS += ../src/ap/ieee802_11.o -+OBJS += ../src/ap/hw_features.o -+CFLAGS += -DNEED_AP_MLME -+endif -+ifdef CONFIG_IEEE80211N -+OBJS += ../src/ap/ieee802_11_ht.o -+endif -+ -+ifdef CONFIG_P2P_MANAGER -+CFLAGS += -DCONFIG_P2P_MANAGER -+OBJS += ../src/ap/p2p_hostapd.o -+endif -+ -+ifdef CONFIG_NO_STDOUT_DEBUG -+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG -+endif -+ -+ifdef CONFIG_DEBUG_FILE -+CFLAGS += -DCONFIG_DEBUG_FILE -+endif -+ -+ALL=hostapd hostapd_cli -+ -+all: verify_config $(ALL) -+ -+Q=@ -+E=echo -+ifeq ($(V), 1) -+Q= -+E=true -+endif -+ -+%.o: %.c -+ $(Q)$(CC) -c -o $@ $(CFLAGS) $< -+ @$(E) " CC " $< -+ -+verify_config: -+ @if [ ! -r .config ]; then \ -+ echo 'Building hostapd requires a configuration file'; \ -+ echo '(.config). See README for more instructions. You can'; \ -+ echo 'run "cp defconfig .config" to create an example'; \ -+ echo 'configuration.'; \ -+ exit 1; \ -+ fi -+ -+install: all -+ mkdir -p $(DESTDIR)/usr/local/bin -+ for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done -+ -+../src/drivers/build.hostapd: -+ @if [ -f ../src/drivers/build.wpa_supplicant ]; then \ -+ $(MAKE) -C ../src/drivers clean; \ -+ fi -+ @touch ../src/drivers/build.hostapd -+ -+BCHECK=../src/drivers/build.hostapd -+ -+hostapd: $(BCHECK) $(OBJS) -+ $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS) -+ @$(E) " LD " $@ -+ -+OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o -+ifdef CONFIG_WPA_TRACE -+OBJS_c += ../src/utils/trace.o -+OBJS_c += ../src/utils/wpa_debug.o -+endif -+hostapd_cli: $(OBJS_c) -+ $(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c) -+ @$(E) " LD " $@ -+ -+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o -+ifdef NEED_RC4 -+ifdef CONFIG_INTERNAL_RC4 -+NOBJS += ../src/crypto/rc4.o -+endif -+endif -+ifdef CONFIG_INTERNAL_MD5 -+NOBJS += ../src/crypto/md5-internal.o -+endif -+NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o -+NOBJS += ../src/utils/wpa_debug.o -+NOBJS += ../src/utils/wpabuf.o -+ifdef CONFIG_WPA_TRACE -+NOBJS += ../src/utils/trace.o -+LIBS_n += -lbfd -+endif -+ifdef TLS_FUNCS -+LIBS_n += -lcrypto -+endif -+ -+HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o -+HOBJS += ../src/crypto/aes-encblock.o -+ifdef CONFIG_INTERNAL_AES -+HOBJS += ../src/crypto/aes-internal.o -+HOBJS += ../src/crypto/aes-internal-enc.o -+endif -+ -+nt_password_hash: $(NOBJS) -+ $(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n) -+ @$(E) " LD " $@ -+ -+hlr_auc_gw: $(HOBJS) -+ $(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h) -+ @$(E) " LD " $@ -+ -+clean: -+ $(MAKE) -C ../src clean -+ rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw -+ rm -f *.d -+ -+-include $(OBJS:%.o=%.d) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README -new file mode 100644 -index 0000000000000..a211cdd200e9d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README -@@ -0,0 +1,387 @@ -+hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP -+ Authenticator and RADIUS authentication server -+================================================================ -+ -+Copyright (c) 2002-2011, Jouni Malinen and contributors -+All Rights Reserved. -+ -+This program is dual-licensed under both the GPL version 2 and BSD -+license. Either license may be used at your option. -+ -+ -+ -+License -+------- -+ -+GPL v2: -+ -+This program is free software; you can redistribute it and/or modify -+it under the terms of the GNU General Public License version 2 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 St, Fifth Floor, Boston, MA 02110-1301 USA -+ -+(this copy of the license is in COPYING file) -+ -+ -+Alternatively, this software may be distributed, used, and modified -+under the terms of BSD license: -+ -+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(s) of the above-listed copyright holder(s) 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. -+ -+ -+ -+Introduction -+============ -+ -+Originally, hostapd was an optional user space component for Host AP -+driver. It adds more features to the basic IEEE 802.11 management -+included in the kernel driver: using external RADIUS authentication -+server for MAC address based access control, IEEE 802.1X Authenticator -+and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN) -+Authenticator and dynamic TKIP/CCMP keying. -+ -+The current version includes support for other drivers, an integrated -+EAP server (i.e., allow full authentication without requiring -+an external RADIUS authentication server), and RADIUS authentication -+server for EAP authentication. -+ -+ -+Requirements -+------------ -+ -+Current hardware/software requirements: -+- drivers: -+ Host AP driver for Prism2/2.5/3. -+ (http://hostap.epitest.fi/) -+ Please note that station firmware version needs to be 1.7.0 or newer -+ to work in WPA mode. -+ -+ madwifi driver for cards based on Atheros chip set (ar521x) -+ (http://sourceforge.net/projects/madwifi/) -+ Please note that you will need to add the correct path for -+ madwifi driver root directory in .config (see defconfig file for -+ an example: CFLAGS += -I) -+ -+ mac80211-based drivers that support AP mode (with driver=nl80211). -+ This includes drivers for Atheros (ath9k) and Broadcom (b43) -+ chipsets. -+ -+ Any wired Ethernet driver for wired IEEE 802.1X authentication -+ (experimental code) -+ -+ FreeBSD -current (with some kernel mods that have not yet been -+ committed when hostapd v0.3.0 was released) -+ BSD net80211 layer (e.g., Atheros driver) -+ -+ -+Build configuration -+------------------- -+ -+In order to be able to build hostapd, you will need to create a build -+time configuration file, .config that selects which optional -+components are included. See defconfig file for example configuration -+and list of available options. -+ -+ -+ -+IEEE 802.1X -+=========== -+ -+IEEE Std 802.1X-2001 is a standard for port-based network access -+control. In case of IEEE 802.11 networks, a "virtual port" is used -+between each associated station and the AP. IEEE 802.11 specifies -+minimal authentication mechanism for stations, whereas IEEE 802.1X -+introduces a extensible mechanism for authenticating and authorizing -+users. -+ -+IEEE 802.1X uses elements called Supplicant, Authenticator, Port -+Access Entity, and Authentication Server. Supplicant is a component in -+a station and it performs the authentication with the Authentication -+Server. An access point includes an Authenticator that relays the packets -+between a Supplicant and an Authentication Server. In addition, it has a -+Port Access Entity (PAE) with Authenticator functionality for -+controlling the virtual port authorization, i.e., whether to accept -+packets from or to the station. -+ -+IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames -+between a Supplicant and an Authenticator are sent using EAP over LAN -+(EAPOL) and the Authenticator relays these frames to the Authentication -+Server (and similarly, relays the messages from the Authentication -+Server to the Supplicant). The Authentication Server can be colocated with the -+Authenticator, in which case there is no need for additional protocol -+for EAP frame transmission. However, a more common configuration is to -+use an external Authentication Server and encapsulate EAP frame in the -+frames used by that server. RADIUS is suitable for this, but IEEE -+802.1X would also allow other mechanisms. -+ -+Host AP driver includes PAE functionality in the kernel driver. It -+is a relatively simple mechanism for denying normal frames going to -+or coming from an unauthorized port. PAE allows IEEE 802.1X related -+frames to be passed between the Supplicant and the Authenticator even -+on an unauthorized port. -+ -+User space daemon, hostapd, includes Authenticator functionality. It -+receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap -+device that is also used with IEEE 802.11 management frames. The -+frames to the Supplicant are sent using the same device. -+ -+The normal configuration of the Authenticator would use an external -+Authentication Server. hostapd supports RADIUS encapsulation of EAP -+packets, so the Authentication Server should be a RADIUS server, like -+FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd -+relays the frames between the Supplicant and the Authentication -+Server. It also controls the PAE functionality in the kernel driver by -+controlling virtual port authorization, i.e., station-AP -+connection, based on the IEEE 802.1X state. -+ -+When a station would like to use the services of an access point, it -+will first perform IEEE 802.11 authentication. This is normally done -+with open systems authentication, so there is no security. After -+this, IEEE 802.11 association is performed. If IEEE 802.1X is -+configured to be used, the virtual port for the station is set in -+Unauthorized state and only IEEE 802.1X frames are accepted at this -+point. The Authenticator will then ask the Supplicant to authenticate -+with the Authentication Server. After this is completed successfully, -+the virtual port is set to Authorized state and frames from and to the -+station are accepted. -+ -+Host AP configuration for IEEE 802.1X -+------------------------------------- -+ -+The user space daemon has its own configuration file that can be used to -+define AP options. Distribution package contains an example -+configuration file (hostapd/hostapd.conf) that can be used as a basis -+for configuration. It includes examples of all supported configuration -+options and short description of each option. hostapd should be started -+with full path to the configuration file as the command line argument, -+e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless -+LAN card, you can use one hostapd process for multiple interfaces by -+giving a list of configuration files (one per interface) in the command -+line. -+ -+hostapd includes a minimal co-located IEEE 802.1X server which can be -+used to test IEEE 802.1X authentication. However, it should not be -+used in normal use since it does not provide any security. This can be -+configured by setting ieee8021x and minimal_eap options in the -+configuration file. -+ -+An external Authentication Server (RADIUS) is configured with -+auth_server_{addr,port,shared_secret} options. In addition, -+ieee8021x and own_ip_addr must be set for this mode. With such -+configuration, the co-located Authentication Server is not used and EAP -+frames will be relayed using EAPOL between the Supplicant and the -+Authenticator and RADIUS encapsulation between the Authenticator and -+the Authentication Server. Other than this, the functionality is similar -+to the case with the co-located Authentication Server. -+ -+Authentication Server and Supplicant -+------------------------------------ -+ -+Any RADIUS server supporting EAP should be usable as an IEEE 802.1X -+Authentication Server with hostapd Authenticator. FreeRADIUS -+(http://www.freeradius.org/) has been successfully tested with hostapd -+Authenticator and both Xsupplicant (http://www.open1x.org) and Windows -+XP Supplicants. EAP/TLS was used with Xsupplicant and -+EAP/MD5-Challenge with Windows XP. -+ -+http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information -+about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace -+Cisco access point with Host AP driver, hostapd daemon, and a Prism2 -+card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information -+about using EAP/MD5 with FreeRADIUS, including instructions for WinXP -+configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on -+EAP/TLS use with WinXP Supplicant. -+ -+Automatic WEP key configuration -+------------------------------- -+ -+EAP/TLS generates a session key that can be used to send WEP keys from -+an AP to authenticated stations. The Authenticator in hostapd can be -+configured to automatically select a random default/broadcast key -+(shared by all authenticated stations) with wep_key_len_broadcast -+option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition, -+wep_key_len_unicast option can be used to configure individual unicast -+keys for stations. This requires support for individual keys in the -+station driver. -+ -+WEP keys can be automatically updated by configuring rekeying. This -+will improve security of the network since same WEP key will only be -+used for a limited period of time. wep_rekey_period option sets the -+interval for rekeying in seconds. -+ -+ -+WPA/WPA2 -+======== -+ -+Features -+-------- -+ -+Supported WPA/IEEE 802.11i features: -+- WPA-PSK ("WPA-Personal") -+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise") -+- key management for CCMP, TKIP, WEP104, WEP40 -+- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication -+ -+WPA -+--- -+ -+The original security mechanism of IEEE 802.11 standard was not -+designed to be strong and has proved to be insufficient for most -+networks that require some kind of security. Task group I (Security) -+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked -+to address the flaws of the base standard and has in practice -+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE -+802.11 standard was approved in June 2004 and this amendment is likely -+to be published in July 2004. -+ -+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the -+IEEE 802.11i work (draft 3.0) to define a subset of the security -+enhancements that can be implemented with existing wlan hardware. This -+is called Wi-Fi Protected Access (WPA). This has now become a -+mandatory component of interoperability testing and certification done -+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web -+site (http://www.wi-fi.org/OpenSection/protected_access.asp). -+ -+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm -+for protecting wireless networks. WEP uses RC4 with 40-bit keys, -+24-bit initialization vector (IV), and CRC32 to protect against packet -+forgery. All these choices have proven to be insufficient: key space is -+too small against current attacks, RC4 key scheduling is insufficient -+(beginning of the pseudorandom stream should be skipped), IV space is -+too small and IV reuse makes attacks easier, there is no replay -+protection, and non-keyed authentication does not protect against bit -+flipping packet data. -+ -+WPA is an intermediate solution for the security issues. It uses -+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a -+compromise on strong security and possibility to use existing -+hardware. It still uses RC4 for the encryption like WEP, but with -+per-packet RC4 keys. In addition, it implements replay protection, -+keyed packet authentication mechanism (Michael MIC). -+ -+Keys can be managed using two different mechanisms. WPA can either use -+an external authentication server (e.g., RADIUS) and EAP just like -+IEEE 802.1X is using or pre-shared keys without need for additional -+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal", -+respectively. Both mechanisms will generate a master session key for -+the Authenticator (AP) and Supplicant (client station). -+ -+WPA implements a new key handshake (4-Way Handshake and Group Key -+Handshake) for generating and exchanging data encryption keys between -+the Authenticator and Supplicant. This handshake is also used to -+verify that both Authenticator and Supplicant know the master session -+key. These handshakes are identical regardless of the selected key -+management mechanism (only the method for generating master session -+key changes). -+ -+ -+IEEE 802.11i / WPA2 -+------------------- -+ -+The design for parts of IEEE 802.11i that were not included in WPA has -+finished (May 2004) and this amendment to IEEE 802.11 was approved in -+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new -+version of WPA called WPA2. This includes, e.g., support for more -+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC) -+to replace TKIP and optimizations for handoff (reduced number of -+messages in initial key handshake, pre-authentication, and PMKSA caching). -+ -+Some wireless LAN vendors are already providing support for CCMP in -+their WPA products. There is no "official" interoperability -+certification for CCMP and/or mixed modes using both TKIP and CCMP, so -+some interoperability issues can be expected even though many -+combinations seem to be working with equipment from different vendors. -+Testing for WPA2 is likely to start during the second half of 2004. -+ -+hostapd configuration for WPA/WPA2 -+---------------------------------- -+ -+TODO -+ -+# Enable WPA. Setting this variable configures the AP to require WPA (either -+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either -+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. -+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), -+# RADIUS authentication server must be configured, and WPA-EAP must be included -+# in wpa_key_mgmt. -+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) -+# and/or WPA2 (full IEEE 802.11i/RSN): -+# bit0 = WPA -+# bit1 = IEEE 802.11i/RSN (WPA2) -+#wpa=1 -+ -+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit -+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase -+# (8..63 characters) that will be converted to PSK. This conversion uses SSID -+# so the PSK changes when ASCII passphrase is used and the SSID is changed. -+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef -+#wpa_passphrase=secret passphrase -+ -+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The -+# entries are separated with a space. -+#wpa_key_mgmt=WPA-PSK WPA-EAP -+ -+# Set of accepted cipher suites (encryption algorithms) for pairwise keys -+# (unicast packets). This is a space separated list of algorithms: -+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i] -+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i] -+# Group cipher suite (encryption algorithm for broadcast and multicast frames) -+# is automatically selected based on this configuration. If only CCMP is -+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, -+# TKIP will be used as the group cipher. -+#wpa_pairwise=TKIP CCMP -+ -+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in -+# seconds. -+#wpa_group_rekey=600 -+ -+# Time interval for rekeying GMK (master key used internally to generate GTKs -+# (in seconds). -+#wpa_gmk_rekey=86400 -+ -+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up -+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN -+# authentication and key handshake before actually associating with a new AP. -+#rsn_preauth=1 -+# -+# Space separated list of interfaces from which pre-authentication frames are -+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all -+# interface that are used for connections to other APs. This could include -+# wired interfaces and WDS links. The normal wireless data interface towards -+# associated stations (e.g., wlan0) should not be added, since -+# pre-authentication is only used with APs other than the currently associated -+# one. -+#rsn_preauth_interfaces=eth0 -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README-WPS b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README-WPS -new file mode 100644 -index 0000000000000..17988d4724ca5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/README-WPS -@@ -0,0 +1,291 @@ -+hostapd and Wi-Fi Protected Setup (WPS) -+======================================= -+ -+This document describes how the WPS implementation in hostapd can be -+configured and how an external component on an AP (e.g., web UI) is -+used to enable enrollment of client devices. -+ -+ -+Introduction to WPS -+------------------- -+ -+Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a -+wireless network. It allows automated generation of random keys (WPA -+passphrase/PSK) and configuration of an access point and client -+devices. WPS includes number of methods for setting up connections -+with PIN method and push-button configuration (PBC) being the most -+commonly deployed options. -+ -+While WPS can enable more home networks to use encryption in the -+wireless network, it should be noted that the use of the PIN and -+especially PBC mechanisms for authenticating the initial key setup is -+not very secure. As such, use of WPS may not be suitable for -+environments that require secure network access without chance for -+allowing outsiders to gain access during the setup phase. -+ -+WPS uses following terms to describe the entities participating in the -+network setup: -+- access point: the WLAN access point -+- Registrar: a device that control a network and can authorize -+ addition of new devices); this may be either in the AP ("internal -+ Registrar") or in an external device, e.g., a laptop, ("external -+ Registrar") -+- Enrollee: a device that is being authorized to use the network -+ -+It should also be noted that the AP and a client device may change -+roles (i.e., AP acts as an Enrollee and client device as a Registrar) -+when WPS is used to configure the access point. -+ -+ -+More information about WPS is available from Wi-Fi Alliance: -+http://www.wi-fi.org/wifi-protected-setup -+ -+ -+hostapd implementation -+---------------------- -+ -+hostapd includes an optional WPS component that can be used as an -+internal WPS Registrar to manage addition of new WPS enabled clients -+to the network. In addition, WPS Enrollee functionality in hostapd can -+be used to allow external WPS Registrars to configure the access -+point, e.g., for initial network setup. In addition, hostapd can proxy a -+WPS registration between a wireless Enrollee and an external Registrar -+(e.g., Microsoft Vista or Atheros JumpStart) with UPnP. -+ -+ -+hostapd configuration -+--------------------- -+ -+WPS is an optional component that needs to be enabled in hostapd build -+configuration (.config). Here is an example configuration that -+includes WPS support and uses madwifi driver interface: -+ -+CONFIG_DRIVER_MADWIFI=y -+CFLAGS += -I/usr/src/madwifi-0.9.3 -+CONFIG_WPS=y -+CONFIG_WPS2=y -+CONFIG_WPS_UPNP=y -+ -+ -+Following section shows an example runtime configuration -+(hostapd.conf) that enables WPS: -+ -+# Configure the driver and network interface -+driver=madwifi -+interface=ath0 -+ -+# WPA2-Personal configuration for the AP -+ssid=wps-test -+wpa=2 -+wpa_key_mgmt=WPA-PSK -+wpa_pairwise=CCMP -+# Default WPA passphrase for legacy (non-WPS) clients -+wpa_passphrase=12345678 -+# Enable random per-device PSK generation for WPS clients -+# Please note that the file has to exists for hostapd to start (i.e., create an -+# empty file as a starting point). -+wpa_psk_file=/etc/hostapd.psk -+ -+# Enable control interface for PBC/PIN entry -+ctrl_interface=/var/run/hostapd -+ -+# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup) -+eap_server=1 -+ -+# WPS configuration (AP configured, do not allow external WPS Registrars) -+wps_state=2 -+ap_setup_locked=1 -+# If UUID is not configured, it will be generated based on local MAC address. -+uuid=87654321-9abc-def0-1234-56789abc0000 -+wps_pin_requests=/var/run/hostapd.pin-req -+device_name=Wireless AP -+manufacturer=Company -+model_name=WAP -+model_number=123 -+serial_number=12345 -+device_type=6-0050F204-1 -+os_version=01020300 -+config_methods=label display push_button keypad -+ -+# if external Registrars are allowed, UPnP support could be added: -+#upnp_iface=br0 -+#friendly_name=WPS Access Point -+ -+ -+External operations -+------------------- -+ -+WPS requires either a device PIN code (usually, 8-digit number) or a -+pushbutton event (for PBC) to allow a new WPS Enrollee to join the -+network. hostapd uses the control interface as an input channel for -+these events. -+ -+The PIN value used in the commands must be processed by an UI to -+remove non-digit characters and potentially, to verify the checksum -+digit. "hostapd_cli wps_check_pin " can be used to do such -+processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if -+the checksum digit is incorrect, or the processed PIN (non-digit -+characters removed) if the PIN is valid. -+ -+When a client device (WPS Enrollee) connects to hostapd (WPS -+Registrar) in order to start PIN mode negotiation for WPS, an -+identifier (Enrollee UUID) is sent. hostapd will need to be configured -+with a device password (PIN) for this Enrollee. This is an operation -+that requires user interaction (assuming there are no pre-configured -+PINs on the AP for a set of Enrollee). -+ -+The PIN request with information about the device is appended to the -+wps_pin_requests file (/var/run/hostapd.pin-req in this example). In -+addition, hostapd control interface event is sent as a notification of -+a new device. The AP could use, e.g., a web UI for showing active -+Enrollees to the user and request a PIN for an Enrollee. -+ -+The PIN request file has one line for every Enrollee that connected to -+the AP, but for which there was no PIN. Following information is -+provided for each Enrollee (separated with tabulators): -+- timestamp (seconds from 1970-01-01) -+- Enrollee UUID -+- MAC address -+- Device name -+- Manufacturer -+- Model Name -+- Model Number -+- Serial Number -+- Device category -+ -+Example line in the /var/run/hostapd.pin-req file: -+1200188391 53b63a98-d29e-4457-a2ed-094d7e6a669c Intel(R) Centrino(R) Intel Corporation Intel(R) Centrino(R) - - 1-0050F204-1 -+ -+Control interface data: -+WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category] -+For example: -+<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1] -+ -+When the user enters a PIN for a pending Enrollee, e.g., on the web -+UI), hostapd needs to be notified of the new PIN over the control -+interface. This can be done either by using the UNIX domain socket -+-based control interface directly (src/common/wpa_ctrl.c provides -+helper functions for using the interface) or by calling hostapd_cli. -+ -+Example command to add a PIN (12345670) for an Enrollee: -+ -+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670 -+ -+If the UUID-E is not available (e.g., Enrollee waits for the Registrar -+to be selected before connecting), wildcard UUID may be used to allow -+the PIN to be used once with any UUID: -+ -+hostapd_cli wps_pin any 12345670 -+ -+To reduce likelihood of PIN being used with other devices or of -+forgetting an active PIN available for potential attackers, expiration -+time in seconds can be set for the new PIN (value 0 indicates no -+expiration): -+ -+hostapd_cli wps_pin any 12345670 300 -+ -+If the MAC address of the enrollee is known, it should be configured -+to allow the AP to advertise list of authorized enrollees: -+ -+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \ -+ 12345670 300 00:11:22:33:44:55 -+ -+ -+After this, the Enrollee can connect to the AP again and complete WPS -+negotiation. At that point, a new, random WPA PSK is generated for the -+client device and the client can then use that key to connect to the -+AP to access the network. -+ -+ -+If the AP includes a pushbutton, WPS PBC mode can be used. It is -+enabled by pushing a button on both the AP and the client at about the -+same time (2 minute window). hostapd needs to be notified about the AP -+button pushed event over the control interface, e.g., by calling -+hostapd_cli: -+ -+hostapd_cli wps_pbc -+ -+At this point, the client has two minutes to complete WPS negotiation -+which will generate a new WPA PSK in the same way as the PIN method -+described above. -+ -+ -+When an external Registrar is used, the AP can act as an Enrollee and -+use its AP PIN. A static AP PIN (e.g., one one a label in the AP -+device) can be configured in hostapd.conf (ap_pin parameter). A more -+secure option is to use hostapd_cli wps_ap_pin command to enable the -+AP PIN only based on user action (and even better security by using a -+random AP PIN for each session, i.e., by using "wps_ap_pin random" -+command with a timeout value). Following commands are available for -+managing the dynamic AP PIN operations: -+ -+hostapd_cli wps_ap_pin disable -+- disable AP PIN (i.e., do not allow external Registrars to use it to -+ learn the current AP settings or to reconfigure the AP) -+ -+hostapd_cli wps_ap_pin random [timeout] -+- generate a random AP PIN and enable it -+- if the optional timeout parameter is given, the AP PIN will be enabled -+ for the specified number of seconds -+ -+hostapd_cli wps_ap_pin get -+- fetch the current AP PIN -+ -+hostapd_cli wps_ap_pin set [timeout] -+- set the AP PIN and enable it -+- if the optional timeout parameter is given, the AP PIN will be enabled -+ for the specified number of seconds -+ -+hostapd_cli get_config -+- display the current configuration -+ -+hostapd_cli wps_config -+examples: -+ hostapd_cli wps_config testing WPA2PSK CCMP 12345678 -+ hostapd_cli wps_config "no security" OPEN NONE "" -+ -+ must be one of the following: OPEN WPAPSK WPA2PSK -+ must be one of the following: NONE WEP TKIP CCMP -+ -+ -+Credential generation and configuration changes -+----------------------------------------------- -+ -+By default, hostapd generates credentials for Enrollees and processing -+AP configuration updates internally. However, it is possible to -+control these operations from external programs, if desired. -+ -+The internal credential generation can be disabled with -+skip_cred_build=1 option in the configuration. extra_cred option will -+then need to be used to provide pre-configured Credential attribute(s) -+for hostapd to use. The exact data from this binary file will be sent, -+i.e., it will have to include valid WPS attributes. extra_cred can -+also be used to add additional networks if the Registrar is used to -+configure credentials for multiple networks. -+ -+Processing of received configuration updates can be disabled with -+wps_cred_processing=1 option. When this is used, an external program -+is responsible for creating hostapd configuration files and processing -+configuration updates based on messages received from hostapd over -+control interface. This will also include the initial configuration on -+first successful registration if the AP is initially set in -+unconfigured state. -+ -+Following control interface messages are sent out for external programs: -+ -+WPS-REG-SUCCESS -+For example: -+<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333 -+ -+This can be used to trigger change from unconfigured to configured -+state (random configuration based on the first successful WPS -+registration). In addition, this can be used to update AP UI about the -+status of WPS registration progress. -+ -+ -+WPS-NEW-AP-SETTINGS -+For example: -+<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844 -+ -+This can be used to update the externally stored AP configuration and -+then update hostapd configuration (followed by restarting of hostapd). -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.c -new file mode 100644 -index 0000000000000..11c8bf018f0fb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.c -@@ -0,0 +1,2119 @@ -+/* -+ * hostapd / Configuration file parser -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+#ifndef CONFIG_NATIVE_WINDOWS -+#include -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+#include "utils/common.h" -+#include "utils/uuid.h" -+#include "common/ieee802_11_defs.h" -+#include "drivers/driver.h" -+#include "eap_server/eap.h" -+#include "radius/radius_client.h" -+#include "ap/wpa_auth.h" -+#include "ap/ap_config.h" -+#include "config_file.h" -+ -+ -+extern struct wpa_driver_ops *wpa_drivers[]; -+ -+ -+#ifndef CONFIG_NO_VLAN -+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, -+ const char *fname) -+{ -+ FILE *f; -+ char buf[128], *pos, *pos2; -+ int line = 0, vlan_id; -+ struct hostapd_vlan *vlan; -+ -+ f = fopen(fname, "r"); -+ if (!f) { -+ wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname); -+ return -1; -+ } -+ -+ while (fgets(buf, sizeof(buf), f)) { -+ line++; -+ -+ if (buf[0] == '#') -+ continue; -+ pos = buf; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ if (buf[0] == '\0') -+ continue; -+ -+ if (buf[0] == '*') { -+ vlan_id = VLAN_ID_WILDCARD; -+ pos = buf + 1; -+ } else { -+ vlan_id = strtol(buf, &pos, 10); -+ if (buf == pos || vlan_id < 1 || -+ vlan_id > MAX_VLAN_ID) { -+ wpa_printf(MSG_ERROR, "Invalid VLAN ID at " -+ "line %d in '%s'", line, fname); -+ fclose(f); -+ return -1; -+ } -+ } -+ -+ while (*pos == ' ' || *pos == '\t') -+ pos++; -+ pos2 = pos; -+ while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0') -+ pos2++; -+ *pos2 = '\0'; -+ if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) { -+ wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d " -+ "in '%s'", line, fname); -+ fclose(f); -+ return -1; -+ } -+ -+ vlan = os_malloc(sizeof(*vlan)); -+ if (vlan == NULL) { -+ wpa_printf(MSG_ERROR, "Out of memory while reading " -+ "VLAN interfaces from '%s'", fname); -+ fclose(f); -+ return -1; -+ } -+ -+ os_memset(vlan, 0, sizeof(*vlan)); -+ vlan->vlan_id = vlan_id; -+ os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname)); -+ if (bss->vlan_tail) -+ bss->vlan_tail->next = vlan; -+ else -+ bss->vlan = vlan; -+ bss->vlan_tail = vlan; -+ } -+ -+ fclose(f); -+ -+ return 0; -+} -+#endif /* CONFIG_NO_VLAN */ -+ -+ -+static int hostapd_acl_comp(const void *a, const void *b) -+{ -+ const struct mac_acl_entry *aa = a; -+ const struct mac_acl_entry *bb = b; -+ return os_memcmp(aa->addr, bb->addr, sizeof(macaddr)); -+} -+ -+ -+static int hostapd_config_read_maclist(const char *fname, -+ struct mac_acl_entry **acl, int *num) -+{ -+ FILE *f; -+ char buf[128], *pos; -+ int line = 0; -+ u8 addr[ETH_ALEN]; -+ struct mac_acl_entry *newacl; -+ int vlan_id; -+ -+ if (!fname) -+ return 0; -+ -+ f = fopen(fname, "r"); -+ if (!f) { -+ wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname); -+ return -1; -+ } -+ -+ while (fgets(buf, sizeof(buf), f)) { -+ line++; -+ -+ if (buf[0] == '#') -+ continue; -+ pos = buf; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ if (buf[0] == '\0') -+ continue; -+ -+ if (hwaddr_aton(buf, addr)) { -+ wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at " -+ "line %d in '%s'", buf, line, fname); -+ fclose(f); -+ return -1; -+ } -+ -+ vlan_id = 0; -+ pos = buf; -+ while (*pos != '\0' && *pos != ' ' && *pos != '\t') -+ pos++; -+ while (*pos == ' ' || *pos == '\t') -+ pos++; -+ if (*pos != '\0') -+ vlan_id = atoi(pos); -+ -+ newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl)); -+ if (newacl == NULL) { -+ wpa_printf(MSG_ERROR, "MAC list reallocation failed"); -+ fclose(f); -+ return -1; -+ } -+ -+ *acl = newacl; -+ os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); -+ (*acl)[*num].vlan_id = vlan_id; -+ (*num)++; -+ } -+ -+ fclose(f); -+ -+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); -+ -+ return 0; -+} -+ -+ -+#ifdef EAP_SERVER -+static int hostapd_config_read_eap_user(const char *fname, -+ struct hostapd_bss_config *conf) -+{ -+ FILE *f; -+ char buf[512], *pos, *start, *pos2; -+ int line = 0, ret = 0, num_methods; -+ struct hostapd_eap_user *user, *tail = NULL; -+ -+ if (!fname) -+ return 0; -+ -+ f = fopen(fname, "r"); -+ if (!f) { -+ wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname); -+ return -1; -+ } -+ -+ /* Lines: "user" METHOD,METHOD2 "password" (password optional) */ -+ while (fgets(buf, sizeof(buf), f)) { -+ line++; -+ -+ if (buf[0] == '#') -+ continue; -+ pos = buf; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ if (buf[0] == '\0') -+ continue; -+ -+ user = NULL; -+ -+ if (buf[0] != '"' && buf[0] != '*') { -+ wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in " -+ "start) on line %d in '%s'", line, fname); -+ goto failed; -+ } -+ -+ user = os_zalloc(sizeof(*user)); -+ if (user == NULL) { -+ wpa_printf(MSG_ERROR, "EAP user allocation failed"); -+ goto failed; -+ } -+ user->force_version = -1; -+ -+ if (buf[0] == '*') { -+ pos = buf; -+ } else { -+ pos = buf + 1; -+ start = pos; -+ while (*pos != '"' && *pos != '\0') -+ pos++; -+ if (*pos == '\0') { -+ wpa_printf(MSG_ERROR, "Invalid EAP identity " -+ "(no \" in end) on line %d in '%s'", -+ line, fname); -+ goto failed; -+ } -+ -+ user->identity = os_malloc(pos - start); -+ if (user->identity == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate " -+ "memory for EAP identity"); -+ goto failed; -+ } -+ os_memcpy(user->identity, start, pos - start); -+ user->identity_len = pos - start; -+ -+ if (pos[0] == '"' && pos[1] == '*') { -+ user->wildcard_prefix = 1; -+ pos++; -+ } -+ } -+ pos++; -+ while (*pos == ' ' || *pos == '\t') -+ pos++; -+ -+ if (*pos == '\0') { -+ wpa_printf(MSG_ERROR, "No EAP method on line %d in " -+ "'%s'", line, fname); -+ goto failed; -+ } -+ -+ start = pos; -+ while (*pos != ' ' && *pos != '\t' && *pos != '\0') -+ pos++; -+ if (*pos == '\0') { -+ pos = NULL; -+ } else { -+ *pos = '\0'; -+ pos++; -+ } -+ num_methods = 0; -+ while (*start) { -+ char *pos3 = os_strchr(start, ','); -+ if (pos3) { -+ *pos3++ = '\0'; -+ } -+ user->methods[num_methods].method = -+ eap_server_get_type( -+ start, -+ &user->methods[num_methods].vendor); -+ if (user->methods[num_methods].vendor == -+ EAP_VENDOR_IETF && -+ user->methods[num_methods].method == EAP_TYPE_NONE) -+ { -+ if (os_strcmp(start, "TTLS-PAP") == 0) { -+ user->ttls_auth |= EAP_TTLS_AUTH_PAP; -+ goto skip_eap; -+ } -+ if (os_strcmp(start, "TTLS-CHAP") == 0) { -+ user->ttls_auth |= EAP_TTLS_AUTH_CHAP; -+ goto skip_eap; -+ } -+ if (os_strcmp(start, "TTLS-MSCHAP") == 0) { -+ user->ttls_auth |= -+ EAP_TTLS_AUTH_MSCHAP; -+ goto skip_eap; -+ } -+ if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) { -+ user->ttls_auth |= -+ EAP_TTLS_AUTH_MSCHAPV2; -+ goto skip_eap; -+ } -+ wpa_printf(MSG_ERROR, "Unsupported EAP type " -+ "'%s' on line %d in '%s'", -+ start, line, fname); -+ goto failed; -+ } -+ -+ num_methods++; -+ if (num_methods >= EAP_USER_MAX_METHODS) -+ break; -+ skip_eap: -+ if (pos3 == NULL) -+ break; -+ start = pos3; -+ } -+ if (num_methods == 0 && user->ttls_auth == 0) { -+ wpa_printf(MSG_ERROR, "No EAP types configured on " -+ "line %d in '%s'", line, fname); -+ goto failed; -+ } -+ -+ if (pos == NULL) -+ goto done; -+ -+ while (*pos == ' ' || *pos == '\t') -+ pos++; -+ if (*pos == '\0') -+ goto done; -+ -+ if (os_strncmp(pos, "[ver=0]", 7) == 0) { -+ user->force_version = 0; -+ goto done; -+ } -+ -+ if (os_strncmp(pos, "[ver=1]", 7) == 0) { -+ user->force_version = 1; -+ goto done; -+ } -+ -+ if (os_strncmp(pos, "[2]", 3) == 0) { -+ user->phase2 = 1; -+ goto done; -+ } -+ -+ if (*pos == '"') { -+ pos++; -+ start = pos; -+ while (*pos != '"' && *pos != '\0') -+ pos++; -+ if (*pos == '\0') { -+ wpa_printf(MSG_ERROR, "Invalid EAP password " -+ "(no \" in end) on line %d in '%s'", -+ line, fname); -+ goto failed; -+ } -+ -+ user->password = os_malloc(pos - start); -+ if (user->password == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate " -+ "memory for EAP password"); -+ goto failed; -+ } -+ os_memcpy(user->password, start, pos - start); -+ user->password_len = pos - start; -+ -+ pos++; -+ } else if (os_strncmp(pos, "hash:", 5) == 0) { -+ pos += 5; -+ pos2 = pos; -+ while (*pos2 != '\0' && *pos2 != ' ' && -+ *pos2 != '\t' && *pos2 != '#') -+ pos2++; -+ if (pos2 - pos != 32) { -+ wpa_printf(MSG_ERROR, "Invalid password hash " -+ "on line %d in '%s'", line, fname); -+ goto failed; -+ } -+ user->password = os_malloc(16); -+ if (user->password == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate " -+ "memory for EAP password hash"); -+ goto failed; -+ } -+ if (hexstr2bin(pos, user->password, 16) < 0) { -+ wpa_printf(MSG_ERROR, "Invalid hash password " -+ "on line %d in '%s'", line, fname); -+ goto failed; -+ } -+ user->password_len = 16; -+ user->password_hash = 1; -+ pos = pos2; -+ } else { -+ pos2 = pos; -+ while (*pos2 != '\0' && *pos2 != ' ' && -+ *pos2 != '\t' && *pos2 != '#') -+ pos2++; -+ if ((pos2 - pos) & 1) { -+ wpa_printf(MSG_ERROR, "Invalid hex password " -+ "on line %d in '%s'", line, fname); -+ goto failed; -+ } -+ user->password = os_malloc((pos2 - pos) / 2); -+ if (user->password == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate " -+ "memory for EAP password"); -+ goto failed; -+ } -+ if (hexstr2bin(pos, user->password, -+ (pos2 - pos) / 2) < 0) { -+ wpa_printf(MSG_ERROR, "Invalid hex password " -+ "on line %d in '%s'", line, fname); -+ goto failed; -+ } -+ user->password_len = (pos2 - pos) / 2; -+ pos = pos2; -+ } -+ -+ while (*pos == ' ' || *pos == '\t') -+ pos++; -+ if (os_strncmp(pos, "[2]", 3) == 0) { -+ user->phase2 = 1; -+ } -+ -+ done: -+ if (tail == NULL) { -+ tail = conf->eap_user = user; -+ } else { -+ tail->next = user; -+ tail = user; -+ } -+ continue; -+ -+ failed: -+ if (user) { -+ os_free(user->password); -+ os_free(user->identity); -+ os_free(user); -+ } -+ ret = -1; -+ break; -+ } -+ -+ fclose(f); -+ -+ return ret; -+} -+#endif /* EAP_SERVER */ -+ -+ -+#ifndef CONFIG_NO_RADIUS -+static int -+hostapd_config_read_radius_addr(struct hostapd_radius_server **server, -+ int *num_server, const char *val, int def_port, -+ struct hostapd_radius_server **curr_serv) -+{ -+ struct hostapd_radius_server *nserv; -+ int ret; -+ static int server_index = 1; -+ -+ nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv)); -+ if (nserv == NULL) -+ return -1; -+ -+ *server = nserv; -+ nserv = &nserv[*num_server]; -+ (*num_server)++; -+ (*curr_serv) = nserv; -+ -+ os_memset(nserv, 0, sizeof(*nserv)); -+ nserv->port = def_port; -+ ret = hostapd_parse_ip_addr(val, &nserv->addr); -+ nserv->index = server_index++; -+ -+ return ret; -+} -+#endif /* CONFIG_NO_RADIUS */ -+ -+ -+static int hostapd_config_parse_key_mgmt(int line, const char *value) -+{ -+ int val = 0, last; -+ char *start, *end, *buf; -+ -+ buf = os_strdup(value); -+ if (buf == NULL) -+ return -1; -+ start = buf; -+ -+ while (*start != '\0') { -+ while (*start == ' ' || *start == '\t') -+ start++; -+ if (*start == '\0') -+ break; -+ end = start; -+ while (*end != ' ' && *end != '\t' && *end != '\0') -+ end++; -+ last = *end == '\0'; -+ *end = '\0'; -+ if (os_strcmp(start, "WPA-PSK") == 0) -+ val |= WPA_KEY_MGMT_PSK; -+ else if (os_strcmp(start, "WPA-EAP") == 0) -+ val |= WPA_KEY_MGMT_IEEE8021X; -+#ifdef CONFIG_IEEE80211R -+ else if (os_strcmp(start, "FT-PSK") == 0) -+ val |= WPA_KEY_MGMT_FT_PSK; -+ else if (os_strcmp(start, "FT-EAP") == 0) -+ val |= WPA_KEY_MGMT_FT_IEEE8021X; -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) -+ val |= WPA_KEY_MGMT_PSK_SHA256; -+ else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) -+ val |= WPA_KEY_MGMT_IEEE8021X_SHA256; -+#endif /* CONFIG_IEEE80211W */ -+ else { -+ wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", -+ line, start); -+ os_free(buf); -+ return -1; -+ } -+ -+ if (last) -+ break; -+ start = end + 1; -+ } -+ -+ os_free(buf); -+ if (val == 0) { -+ wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values " -+ "configured.", line); -+ return -1; -+ } -+ -+ return val; -+} -+ -+ -+static int hostapd_config_parse_cipher(int line, const char *value) -+{ -+ int val = 0, last; -+ char *start, *end, *buf; -+ -+ buf = os_strdup(value); -+ if (buf == NULL) -+ return -1; -+ start = buf; -+ -+ while (*start != '\0') { -+ while (*start == ' ' || *start == '\t') -+ start++; -+ if (*start == '\0') -+ break; -+ end = start; -+ while (*end != ' ' && *end != '\t' && *end != '\0') -+ end++; -+ last = *end == '\0'; -+ *end = '\0'; -+ if (os_strcmp(start, "CCMP") == 0) -+ val |= WPA_CIPHER_CCMP; -+ else if (os_strcmp(start, "TKIP") == 0) -+ val |= WPA_CIPHER_TKIP; -+ else if (os_strcmp(start, "WEP104") == 0) -+ val |= WPA_CIPHER_WEP104; -+ else if (os_strcmp(start, "WEP40") == 0) -+ val |= WPA_CIPHER_WEP40; -+ else if (os_strcmp(start, "NONE") == 0) -+ val |= WPA_CIPHER_NONE; -+ else { -+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", -+ line, start); -+ os_free(buf); -+ return -1; -+ } -+ -+ if (last) -+ break; -+ start = end + 1; -+ } -+ os_free(buf); -+ -+ if (val == 0) { -+ wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", -+ line); -+ return -1; -+ } -+ return val; -+} -+ -+ -+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx, -+ char *val) -+{ -+ size_t len = os_strlen(val); -+ -+ if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL) -+ return -1; -+ -+ if (val[0] == '"') { -+ if (len < 2 || val[len - 1] != '"') -+ return -1; -+ len -= 2; -+ wep->key[keyidx] = os_malloc(len); -+ if (wep->key[keyidx] == NULL) -+ return -1; -+ os_memcpy(wep->key[keyidx], val + 1, len); -+ wep->len[keyidx] = len; -+ } else { -+ if (len & 1) -+ return -1; -+ len /= 2; -+ wep->key[keyidx] = os_malloc(len); -+ if (wep->key[keyidx] == NULL) -+ return -1; -+ wep->len[keyidx] = len; -+ if (hexstr2bin(val, wep->key[keyidx], len) < 0) -+ return -1; -+ } -+ -+ wep->keys_set++; -+ -+ return 0; -+} -+ -+ -+static int hostapd_parse_rates(int **rate_list, char *val) -+{ -+ int *list; -+ int count; -+ char *pos, *end; -+ -+ os_free(*rate_list); -+ *rate_list = NULL; -+ -+ pos = val; -+ count = 0; -+ while (*pos != '\0') { -+ if (*pos == ' ') -+ count++; -+ pos++; -+ } -+ -+ list = os_malloc(sizeof(int) * (count + 2)); -+ if (list == NULL) -+ return -1; -+ pos = val; -+ count = 0; -+ while (*pos != '\0') { -+ end = os_strchr(pos, ' '); -+ if (end) -+ *end = '\0'; -+ -+ list[count++] = atoi(pos); -+ if (!end) -+ break; -+ pos = end + 1; -+ } -+ list[count] = -1; -+ -+ *rate_list = list; -+ return 0; -+} -+ -+ -+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname) -+{ -+ struct hostapd_bss_config *bss; -+ -+ if (*ifname == '\0') -+ return -1; -+ -+ bss = os_realloc(conf->bss, (conf->num_bss + 1) * -+ sizeof(struct hostapd_bss_config)); -+ if (bss == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate memory for " -+ "multi-BSS entry"); -+ return -1; -+ } -+ conf->bss = bss; -+ -+ bss = &(conf->bss[conf->num_bss]); -+ os_memset(bss, 0, sizeof(*bss)); -+ bss->radius = os_zalloc(sizeof(*bss->radius)); -+ if (bss->radius == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate memory for " -+ "multi-BSS RADIUS data"); -+ return -1; -+ } -+ -+ conf->num_bss++; -+ conf->last_bss = bss; -+ -+ hostapd_config_defaults_bss(bss); -+ os_strlcpy(bss->iface, ifname, sizeof(bss->iface)); -+ os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1); -+ -+ return 0; -+} -+ -+ -+/* convert floats with one decimal place to value*10 int, i.e., -+ * "1.5" will return 15 */ -+static int hostapd_config_read_int10(const char *value) -+{ -+ int i, d; -+ char *pos; -+ -+ i = atoi(value); -+ pos = os_strchr(value, '.'); -+ d = 0; -+ if (pos) { -+ pos++; -+ if (*pos >= '0' && *pos <= '9') -+ d = *pos - '0'; -+ } -+ -+ return i * 10 + d; -+} -+ -+ -+static int valid_cw(int cw) -+{ -+ return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 || -+ cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023); -+} -+ -+ -+enum { -+ IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */ -+ IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */ -+ IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */ -+ IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */ -+}; -+ -+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name, -+ char *val) -+{ -+ int num; -+ char *pos; -+ struct hostapd_tx_queue_params *queue; -+ -+ /* skip 'tx_queue_' prefix */ -+ pos = name + 9; -+ if (os_strncmp(pos, "data", 4) == 0 && -+ pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') { -+ num = pos[4] - '0'; -+ pos += 6; -+ } else if (os_strncmp(pos, "after_beacon_", 13) == 0 || -+ os_strncmp(pos, "beacon_", 7) == 0) { -+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); -+ return 0; -+ } else { -+ wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos); -+ return -1; -+ } -+ -+ if (num >= NUM_TX_QUEUES) { -+ /* for backwards compatibility, do not trigger failure */ -+ wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); -+ return 0; -+ } -+ -+ queue = &conf->tx_queue[num]; -+ -+ if (os_strcmp(pos, "aifs") == 0) { -+ queue->aifs = atoi(val); -+ if (queue->aifs < 0 || queue->aifs > 255) { -+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d", -+ queue->aifs); -+ return -1; -+ } -+ } else if (os_strcmp(pos, "cwmin") == 0) { -+ queue->cwmin = atoi(val); -+ if (!valid_cw(queue->cwmin)) { -+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d", -+ queue->cwmin); -+ return -1; -+ } -+ } else if (os_strcmp(pos, "cwmax") == 0) { -+ queue->cwmax = atoi(val); -+ if (!valid_cw(queue->cwmax)) { -+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d", -+ queue->cwmax); -+ return -1; -+ } -+ } else if (os_strcmp(pos, "burst") == 0) { -+ queue->burst = hostapd_config_read_int10(val); -+ } else { -+ wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name, -+ char *val) -+{ -+ int num, v; -+ char *pos; -+ struct hostapd_wmm_ac_params *ac; -+ -+ /* skip 'wme_ac_' or 'wmm_ac_' prefix */ -+ pos = name + 7; -+ if (os_strncmp(pos, "be_", 3) == 0) { -+ num = 0; -+ pos += 3; -+ } else if (os_strncmp(pos, "bk_", 3) == 0) { -+ num = 1; -+ pos += 3; -+ } else if (os_strncmp(pos, "vi_", 3) == 0) { -+ num = 2; -+ pos += 3; -+ } else if (os_strncmp(pos, "vo_", 3) == 0) { -+ num = 3; -+ pos += 3; -+ } else { -+ wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos); -+ return -1; -+ } -+ -+ ac = &conf->wmm_ac_params[num]; -+ -+ if (os_strcmp(pos, "aifs") == 0) { -+ v = atoi(val); -+ if (v < 1 || v > 255) { -+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v); -+ return -1; -+ } -+ ac->aifs = v; -+ } else if (os_strcmp(pos, "cwmin") == 0) { -+ v = atoi(val); -+ if (v < 0 || v > 12) { -+ wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v); -+ return -1; -+ } -+ ac->cwmin = v; -+ } else if (os_strcmp(pos, "cwmax") == 0) { -+ v = atoi(val); -+ if (v < 0 || v > 12) { -+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v); -+ return -1; -+ } -+ ac->cwmax = v; -+ } else if (os_strcmp(pos, "txop_limit") == 0) { -+ v = atoi(val); -+ if (v < 0 || v > 0xffff) { -+ wpa_printf(MSG_ERROR, "Invalid txop value %d", v); -+ return -1; -+ } -+ ac->txop_limit = v; -+ } else if (os_strcmp(pos, "acm") == 0) { -+ v = atoi(val); -+ if (v < 0 || v > 1) { -+ wpa_printf(MSG_ERROR, "Invalid acm value %d", v); -+ return -1; -+ } -+ ac->admission_control_mandatory = v; -+ } else { -+ wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+static int add_r0kh(struct hostapd_bss_config *bss, char *value) -+{ -+ struct ft_remote_r0kh *r0kh; -+ char *pos, *next; -+ -+ r0kh = os_zalloc(sizeof(*r0kh)); -+ if (r0kh == NULL) -+ return -1; -+ -+ /* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */ -+ pos = value; -+ next = os_strchr(pos, ' '); -+ if (next) -+ *next++ = '\0'; -+ if (next == NULL || hwaddr_aton(pos, r0kh->addr)) { -+ wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos); -+ os_free(r0kh); -+ return -1; -+ } -+ -+ pos = next; -+ next = os_strchr(pos, ' '); -+ if (next) -+ *next++ = '\0'; -+ if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) { -+ wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos); -+ os_free(r0kh); -+ return -1; -+ } -+ r0kh->id_len = next - pos - 1; -+ os_memcpy(r0kh->id, pos, r0kh->id_len); -+ -+ pos = next; -+ if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) { -+ wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos); -+ os_free(r0kh); -+ return -1; -+ } -+ -+ r0kh->next = bss->r0kh_list; -+ bss->r0kh_list = r0kh; -+ -+ return 0; -+} -+ -+ -+static int add_r1kh(struct hostapd_bss_config *bss, char *value) -+{ -+ struct ft_remote_r1kh *r1kh; -+ char *pos, *next; -+ -+ r1kh = os_zalloc(sizeof(*r1kh)); -+ if (r1kh == NULL) -+ return -1; -+ -+ /* 02:01:02:03:04:05 02:01:02:03:04:05 -+ * 000102030405060708090a0b0c0d0e0f */ -+ pos = value; -+ next = os_strchr(pos, ' '); -+ if (next) -+ *next++ = '\0'; -+ if (next == NULL || hwaddr_aton(pos, r1kh->addr)) { -+ wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos); -+ os_free(r1kh); -+ return -1; -+ } -+ -+ pos = next; -+ next = os_strchr(pos, ' '); -+ if (next) -+ *next++ = '\0'; -+ if (next == NULL || hwaddr_aton(pos, r1kh->id)) { -+ wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos); -+ os_free(r1kh); -+ return -1; -+ } -+ -+ pos = next; -+ if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) { -+ wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos); -+ os_free(r1kh); -+ return -1; -+ } -+ -+ r1kh->next = bss->r1kh_list; -+ bss->r1kh_list = r1kh; -+ -+ return 0; -+} -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+#ifdef CONFIG_IEEE80211N -+static int hostapd_config_ht_capab(struct hostapd_config *conf, -+ const char *capab) -+{ -+ if (os_strstr(capab, "[LDPC]")) -+ conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP; -+ if (os_strstr(capab, "[HT40-]")) { -+ conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; -+ conf->secondary_channel = -1; -+ } -+ if (os_strstr(capab, "[HT40+]")) { -+ conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; -+ conf->secondary_channel = 1; -+ } -+ if (os_strstr(capab, "[SMPS-STATIC]")) { -+ conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; -+ conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC; -+ } -+ if (os_strstr(capab, "[SMPS-DYNAMIC]")) { -+ conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; -+ conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC; -+ } -+ if (os_strstr(capab, "[GF]")) -+ conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD; -+ if (os_strstr(capab, "[SHORT-GI-20]")) -+ conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ; -+ if (os_strstr(capab, "[SHORT-GI-40]")) -+ conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ; -+ if (os_strstr(capab, "[TX-STBC]")) -+ conf->ht_capab |= HT_CAP_INFO_TX_STBC; -+ if (os_strstr(capab, "[RX-STBC1]")) { -+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; -+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_1; -+ } -+ if (os_strstr(capab, "[RX-STBC12]")) { -+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; -+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_12; -+ } -+ if (os_strstr(capab, "[RX-STBC123]")) { -+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK; -+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_123; -+ } -+ if (os_strstr(capab, "[DELAYED-BA]")) -+ conf->ht_capab |= HT_CAP_INFO_DELAYED_BA; -+ if (os_strstr(capab, "[MAX-AMSDU-7935]")) -+ conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE; -+ if (os_strstr(capab, "[DSSS_CCK-40]")) -+ conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ; -+ if (os_strstr(capab, "[PSMP]")) -+ conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP; -+ if (os_strstr(capab, "[LSIG-TXOP-PROT]")) -+ conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT; -+ -+ return 0; -+} -+#endif /* CONFIG_IEEE80211N */ -+ -+ -+static int hostapd_config_check_bss(struct hostapd_bss_config *bss, -+ struct hostapd_config *conf) -+{ -+ if (bss->ieee802_1x && !bss->eap_server && -+ !bss->radius->auth_servers) { -+ wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no " -+ "EAP authenticator configured)."); -+ return -1; -+ } -+ -+ if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) && -+ bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL && -+ bss->ssid.wpa_psk_file == NULL) { -+ wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase " -+ "is not configured."); -+ return -1; -+ } -+ -+ if (hostapd_mac_comp_empty(bss->bssid) != 0) { -+ size_t i; -+ -+ for (i = 0; i < conf->num_bss; i++) { -+ if ((&conf->bss[i] != bss) && -+ (hostapd_mac_comp(conf->bss[i].bssid, -+ bss->bssid) == 0)) { -+ wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR -+ " on interface '%s' and '%s'.", -+ MAC2STR(bss->bssid), -+ conf->bss[i].iface, bss->iface); -+ return -1; -+ } -+ } -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ if ((bss->wpa_key_mgmt & -+ (WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X)) && -+ (bss->nas_identifier == NULL || -+ os_strlen(bss->nas_identifier) < 1 || -+ os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) { -+ wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires " -+ "nas_identifier to be configured as a 1..48 octet " -+ "string"); -+ return -1; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+#ifdef CONFIG_IEEE80211N -+ if (conf->ieee80211n && -+ bss->ssid.security_policy == SECURITY_STATIC_WEP) { -+ bss->disable_11n = 1; -+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not " -+ "allowed, disabling HT capabilities"); -+ } -+ -+ if (conf->ieee80211n && bss->wpa && -+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && -+ !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) { -+ bss->disable_11n = 1; -+ wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 " -+ "requires CCMP to be enabled, disabling HT " -+ "capabilities"); -+ } -+#endif /* CONFIG_IEEE80211N */ -+ -+#ifdef CONFIG_WPS2 -+ if (bss->wps_state && bss->ignore_broadcast_ssid) { -+ wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid " -+ "configuration forced WPS to be disabled"); -+ bss->wps_state = 0; -+ } -+ -+ if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) { -+ wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be " -+ "disabled"); -+ bss->wps_state = 0; -+ } -+#endif /* CONFIG_WPS2 */ -+ -+ return 0; -+} -+ -+ -+static int hostapd_config_check(struct hostapd_config *conf) -+{ -+ size_t i; -+ -+ if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) { -+ wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without " -+ "setting the country_code"); -+ return -1; -+ } -+ -+ for (i = 0; i < conf->num_bss; i++) { -+ if (hostapd_config_check_bss(&conf->bss[i], conf)) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * hostapd_config_read - Read and parse a configuration file -+ * @fname: Configuration file name (including path, if needed) -+ * Returns: Allocated configuration data structure -+ */ -+struct hostapd_config * hostapd_config_read(const char *fname) -+{ -+ struct hostapd_config *conf; -+ struct hostapd_bss_config *bss; -+ FILE *f; -+ char buf[256], *pos; -+ int line = 0; -+ int errors = 0; -+ int pairwise; -+ size_t i; -+ -+ f = fopen(fname, "r"); -+ if (f == NULL) { -+ wpa_printf(MSG_ERROR, "Could not open configuration file '%s' " -+ "for reading.", fname); -+ return NULL; -+ } -+ -+ conf = hostapd_config_defaults(); -+ if (conf == NULL) { -+ fclose(f); -+ return NULL; -+ } -+ -+ /* set default driver based on configuration */ -+ conf->driver = wpa_drivers[0]; -+ if (conf->driver == NULL) { -+ wpa_printf(MSG_ERROR, "No driver wrappers registered!"); -+ hostapd_config_free(conf); -+ fclose(f); -+ return NULL; -+ } -+ -+ bss = conf->last_bss = conf->bss; -+ -+ while (fgets(buf, sizeof(buf), f)) { -+ bss = conf->last_bss; -+ line++; -+ -+ if (buf[0] == '#') -+ continue; -+ pos = buf; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ if (buf[0] == '\0') -+ continue; -+ -+ pos = os_strchr(buf, '='); -+ if (pos == NULL) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'", -+ line, buf); -+ errors++; -+ continue; -+ } -+ *pos = '\0'; -+ pos++; -+ -+ if (os_strcmp(buf, "interface") == 0) { -+ os_strlcpy(conf->bss[0].iface, pos, -+ sizeof(conf->bss[0].iface)); -+ } else if (os_strcmp(buf, "bridge") == 0) { -+ os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); -+ } else if (os_strcmp(buf, "wds_bridge") == 0) { -+ os_strlcpy(bss->wds_bridge, pos, -+ sizeof(bss->wds_bridge)); -+ } else if (os_strcmp(buf, "driver") == 0) { -+ int j; -+ /* clear to get error below if setting is invalid */ -+ conf->driver = NULL; -+ for (j = 0; wpa_drivers[j]; j++) { -+ if (os_strcmp(pos, wpa_drivers[j]->name) == 0) -+ { -+ conf->driver = wpa_drivers[j]; -+ break; -+ } -+ } -+ if (conf->driver == NULL) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid/" -+ "unknown driver '%s'", line, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "debug") == 0) { -+ wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' " -+ "configuration variable is not used " -+ "anymore", line); -+ } else if (os_strcmp(buf, "logger_syslog_level") == 0) { -+ bss->logger_syslog_level = atoi(pos); -+ } else if (os_strcmp(buf, "logger_stdout_level") == 0) { -+ bss->logger_stdout_level = atoi(pos); -+ } else if (os_strcmp(buf, "logger_syslog") == 0) { -+ bss->logger_syslog = atoi(pos); -+ } else if (os_strcmp(buf, "logger_stdout") == 0) { -+ bss->logger_stdout = atoi(pos); -+ } else if (os_strcmp(buf, "dump_file") == 0) { -+ bss->dump_log_name = os_strdup(pos); -+ } else if (os_strcmp(buf, "ssid") == 0) { -+ bss->ssid.ssid_len = os_strlen(pos); -+ if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN || -+ bss->ssid.ssid_len < 1) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID " -+ "'%s'", line, pos); -+ errors++; -+ } else { -+ os_memcpy(bss->ssid.ssid, pos, -+ bss->ssid.ssid_len); -+ bss->ssid.ssid[bss->ssid.ssid_len] = '\0'; -+ bss->ssid.ssid_set = 1; -+ } -+ } else if (os_strcmp(buf, "macaddr_acl") == 0) { -+ bss->macaddr_acl = atoi(pos); -+ if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED && -+ bss->macaddr_acl != DENY_UNLESS_ACCEPTED && -+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { -+ wpa_printf(MSG_ERROR, "Line %d: unknown " -+ "macaddr_acl %d", -+ line, bss->macaddr_acl); -+ } -+ } else if (os_strcmp(buf, "accept_mac_file") == 0) { -+ if (hostapd_config_read_maclist(pos, &bss->accept_mac, -+ &bss->num_accept_mac)) -+ { -+ wpa_printf(MSG_ERROR, "Line %d: Failed to " -+ "read accept_mac_file '%s'", -+ line, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "deny_mac_file") == 0) { -+ if (hostapd_config_read_maclist(pos, &bss->deny_mac, -+ &bss->num_deny_mac)) { -+ wpa_printf(MSG_ERROR, "Line %d: Failed to " -+ "read deny_mac_file '%s'", -+ line, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wds_sta") == 0) { -+ bss->wds_sta = atoi(pos); -+ } else if (os_strcmp(buf, "ap_isolate") == 0) { -+ bss->isolate = atoi(pos); -+ } else if (os_strcmp(buf, "ap_max_inactivity") == 0) { -+ bss->ap_max_inactivity = atoi(pos); -+ } else if (os_strcmp(buf, "country_code") == 0) { -+ os_memcpy(conf->country, pos, 2); -+ /* FIX: make this configurable */ -+ conf->country[2] = ' '; -+ } else if (os_strcmp(buf, "ieee80211d") == 0) { -+ conf->ieee80211d = atoi(pos); -+ } else if (os_strcmp(buf, "ieee8021x") == 0) { -+ bss->ieee802_1x = atoi(pos); -+ } else if (os_strcmp(buf, "eapol_version") == 0) { -+ bss->eapol_version = atoi(pos); -+ if (bss->eapol_version < 1 || -+ bss->eapol_version > 2) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL " -+ "version (%d): '%s'.", -+ line, bss->eapol_version, pos); -+ errors++; -+ } else -+ wpa_printf(MSG_DEBUG, "eapol_version=%d", -+ bss->eapol_version); -+#ifdef EAP_SERVER -+ } else if (os_strcmp(buf, "eap_authenticator") == 0) { -+ bss->eap_server = atoi(pos); -+ wpa_printf(MSG_ERROR, "Line %d: obsolete " -+ "eap_authenticator used; this has been " -+ "renamed to eap_server", line); -+ } else if (os_strcmp(buf, "eap_server") == 0) { -+ bss->eap_server = atoi(pos); -+ } else if (os_strcmp(buf, "eap_user_file") == 0) { -+ if (hostapd_config_read_eap_user(pos, bss)) -+ errors++; -+ } else if (os_strcmp(buf, "ca_cert") == 0) { -+ os_free(bss->ca_cert); -+ bss->ca_cert = os_strdup(pos); -+ } else if (os_strcmp(buf, "server_cert") == 0) { -+ os_free(bss->server_cert); -+ bss->server_cert = os_strdup(pos); -+ } else if (os_strcmp(buf, "private_key") == 0) { -+ os_free(bss->private_key); -+ bss->private_key = os_strdup(pos); -+ } else if (os_strcmp(buf, "private_key_passwd") == 0) { -+ os_free(bss->private_key_passwd); -+ bss->private_key_passwd = os_strdup(pos); -+ } else if (os_strcmp(buf, "check_crl") == 0) { -+ bss->check_crl = atoi(pos); -+ } else if (os_strcmp(buf, "dh_file") == 0) { -+ os_free(bss->dh_file); -+ bss->dh_file = os_strdup(pos); -+ } else if (os_strcmp(buf, "fragment_size") == 0) { -+ bss->fragment_size = atoi(pos); -+#ifdef EAP_SERVER_FAST -+ } else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) { -+ os_free(bss->pac_opaque_encr_key); -+ bss->pac_opaque_encr_key = os_malloc(16); -+ if (bss->pac_opaque_encr_key == NULL) { -+ wpa_printf(MSG_ERROR, "Line %d: No memory for " -+ "pac_opaque_encr_key", line); -+ errors++; -+ } else if (hexstr2bin(pos, bss->pac_opaque_encr_key, -+ 16)) { -+ wpa_printf(MSG_ERROR, "Line %d: Invalid " -+ "pac_opaque_encr_key", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "eap_fast_a_id") == 0) { -+ size_t idlen = os_strlen(pos); -+ if (idlen & 1) { -+ wpa_printf(MSG_ERROR, "Line %d: Invalid " -+ "eap_fast_a_id", line); -+ errors++; -+ } else { -+ os_free(bss->eap_fast_a_id); -+ bss->eap_fast_a_id = os_malloc(idlen / 2); -+ if (bss->eap_fast_a_id == NULL || -+ hexstr2bin(pos, bss->eap_fast_a_id, -+ idlen / 2)) { -+ wpa_printf(MSG_ERROR, "Line %d: " -+ "Failed to parse " -+ "eap_fast_a_id", line); -+ errors++; -+ } else -+ bss->eap_fast_a_id_len = idlen / 2; -+ } -+ } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) { -+ os_free(bss->eap_fast_a_id_info); -+ bss->eap_fast_a_id_info = os_strdup(pos); -+ } else if (os_strcmp(buf, "eap_fast_prov") == 0) { -+ bss->eap_fast_prov = atoi(pos); -+ } else if (os_strcmp(buf, "pac_key_lifetime") == 0) { -+ bss->pac_key_lifetime = atoi(pos); -+ } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) { -+ bss->pac_key_refresh_time = atoi(pos); -+#endif /* EAP_SERVER_FAST */ -+#ifdef EAP_SERVER_SIM -+ } else if (os_strcmp(buf, "eap_sim_db") == 0) { -+ os_free(bss->eap_sim_db); -+ bss->eap_sim_db = os_strdup(pos); -+ } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) { -+ bss->eap_sim_aka_result_ind = atoi(pos); -+#endif /* EAP_SERVER_SIM */ -+#ifdef EAP_SERVER_TNC -+ } else if (os_strcmp(buf, "tnc") == 0) { -+ bss->tnc = atoi(pos); -+#endif /* EAP_SERVER_TNC */ -+#ifdef EAP_SERVER_PWD -+ } else if (os_strcmp(buf, "pwd_group") == 0) { -+ bss->pwd_group = atoi(pos); -+#endif /* EAP_SERVER_PWD */ -+#endif /* EAP_SERVER */ -+ } else if (os_strcmp(buf, "eap_message") == 0) { -+ char *term; -+ bss->eap_req_id_text = os_strdup(pos); -+ if (bss->eap_req_id_text == NULL) { -+ wpa_printf(MSG_ERROR, "Line %d: Failed to " -+ "allocate memory for " -+ "eap_req_id_text", line); -+ errors++; -+ continue; -+ } -+ bss->eap_req_id_text_len = -+ os_strlen(bss->eap_req_id_text); -+ term = os_strstr(bss->eap_req_id_text, "\\0"); -+ if (term) { -+ *term++ = '\0'; -+ os_memmove(term, term + 1, -+ bss->eap_req_id_text_len - -+ (term - bss->eap_req_id_text) - 1); -+ bss->eap_req_id_text_len--; -+ } -+ } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) { -+ bss->default_wep_key_len = atoi(pos); -+ if (bss->default_wep_key_len > 13) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid WEP " -+ "key len %lu (= %lu bits)", line, -+ (unsigned long) -+ bss->default_wep_key_len, -+ (unsigned long) -+ bss->default_wep_key_len * 8); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wep_key_len_unicast") == 0) { -+ bss->individual_wep_key_len = atoi(pos); -+ if (bss->individual_wep_key_len < 0 || -+ bss->individual_wep_key_len > 13) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid WEP " -+ "key len %d (= %d bits)", line, -+ bss->individual_wep_key_len, -+ bss->individual_wep_key_len * 8); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wep_rekey_period") == 0) { -+ bss->wep_rekeying_period = atoi(pos); -+ if (bss->wep_rekeying_period < 0) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "period %d", -+ line, bss->wep_rekeying_period); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "eap_reauth_period") == 0) { -+ bss->eap_reauth_period = atoi(pos); -+ if (bss->eap_reauth_period < 0) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "period %d", -+ line, bss->eap_reauth_period); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) { -+ bss->eapol_key_index_workaround = atoi(pos); -+#ifdef CONFIG_IAPP -+ } else if (os_strcmp(buf, "iapp_interface") == 0) { -+ bss->ieee802_11f = 1; -+ os_strlcpy(bss->iapp_iface, pos, -+ sizeof(bss->iapp_iface)); -+#endif /* CONFIG_IAPP */ -+ } else if (os_strcmp(buf, "own_ip_addr") == 0) { -+ if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid IP " -+ "address '%s'", line, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "nas_identifier") == 0) { -+ bss->nas_identifier = os_strdup(pos); -+#ifndef CONFIG_NO_RADIUS -+ } else if (os_strcmp(buf, "auth_server_addr") == 0) { -+ if (hostapd_config_read_radius_addr( -+ &bss->radius->auth_servers, -+ &bss->radius->num_auth_servers, pos, 1812, -+ &bss->radius->auth_server)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid IP " -+ "address '%s'", line, pos); -+ errors++; -+ } -+ } else if (bss->radius->auth_server && -+ os_strcmp(buf, "auth_server_port") == 0) { -+ bss->radius->auth_server->port = atoi(pos); -+ } else if (bss->radius->auth_server && -+ os_strcmp(buf, "auth_server_shared_secret") == 0) { -+ int len = os_strlen(pos); -+ if (len == 0) { -+ /* RFC 2865, Ch. 3 */ -+ wpa_printf(MSG_ERROR, "Line %d: empty shared " -+ "secret is not allowed.", line); -+ errors++; -+ } -+ bss->radius->auth_server->shared_secret = -+ (u8 *) os_strdup(pos); -+ bss->radius->auth_server->shared_secret_len = len; -+ } else if (os_strcmp(buf, "acct_server_addr") == 0) { -+ if (hostapd_config_read_radius_addr( -+ &bss->radius->acct_servers, -+ &bss->radius->num_acct_servers, pos, 1813, -+ &bss->radius->acct_server)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid IP " -+ "address '%s'", line, pos); -+ errors++; -+ } -+ } else if (bss->radius->acct_server && -+ os_strcmp(buf, "acct_server_port") == 0) { -+ bss->radius->acct_server->port = atoi(pos); -+ } else if (bss->radius->acct_server && -+ os_strcmp(buf, "acct_server_shared_secret") == 0) { -+ int len = os_strlen(pos); -+ if (len == 0) { -+ /* RFC 2865, Ch. 3 */ -+ wpa_printf(MSG_ERROR, "Line %d: empty shared " -+ "secret is not allowed.", line); -+ errors++; -+ } -+ bss->radius->acct_server->shared_secret = -+ (u8 *) os_strdup(pos); -+ bss->radius->acct_server->shared_secret_len = len; -+ } else if (os_strcmp(buf, "radius_retry_primary_interval") == -+ 0) { -+ bss->radius->retry_primary_interval = atoi(pos); -+ } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) -+ { -+ bss->acct_interim_interval = atoi(pos); -+#endif /* CONFIG_NO_RADIUS */ -+ } else if (os_strcmp(buf, "auth_algs") == 0) { -+ bss->auth_algs = atoi(pos); -+ if (bss->auth_algs == 0) { -+ wpa_printf(MSG_ERROR, "Line %d: no " -+ "authentication algorithms allowed", -+ line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "max_num_sta") == 0) { -+ bss->max_num_sta = atoi(pos); -+ if (bss->max_num_sta < 0 || -+ bss->max_num_sta > MAX_STA_COUNT) { -+ wpa_printf(MSG_ERROR, "Line %d: Invalid " -+ "max_num_sta=%d; allowed range " -+ "0..%d", line, bss->max_num_sta, -+ MAX_STA_COUNT); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wpa") == 0) { -+ bss->wpa = atoi(pos); -+ } else if (os_strcmp(buf, "wpa_group_rekey") == 0) { -+ bss->wpa_group_rekey = atoi(pos); -+ } else if (os_strcmp(buf, "wpa_strict_rekey") == 0) { -+ bss->wpa_strict_rekey = atoi(pos); -+ } else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) { -+ bss->wpa_gmk_rekey = atoi(pos); -+ } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { -+ bss->wpa_ptk_rekey = atoi(pos); -+ } else if (os_strcmp(buf, "wpa_passphrase") == 0) { -+ int len = os_strlen(pos); -+ if (len < 8 || len > 63) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid WPA " -+ "passphrase length %d (expected " -+ "8..63)", line, len); -+ errors++; -+ } else { -+ os_free(bss->ssid.wpa_passphrase); -+ bss->ssid.wpa_passphrase = os_strdup(pos); -+ } -+ } else if (os_strcmp(buf, "wpa_psk") == 0) { -+ os_free(bss->ssid.wpa_psk); -+ bss->ssid.wpa_psk = -+ os_zalloc(sizeof(struct hostapd_wpa_psk)); -+ if (bss->ssid.wpa_psk == NULL) -+ errors++; -+ else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk, -+ PMK_LEN) || -+ pos[PMK_LEN * 2] != '\0') { -+ wpa_printf(MSG_ERROR, "Line %d: Invalid PSK " -+ "'%s'.", line, pos); -+ errors++; -+ } else { -+ bss->ssid.wpa_psk->group = 1; -+ } -+ } else if (os_strcmp(buf, "wpa_psk_file") == 0) { -+ os_free(bss->ssid.wpa_psk_file); -+ bss->ssid.wpa_psk_file = os_strdup(pos); -+ if (!bss->ssid.wpa_psk_file) { -+ wpa_printf(MSG_ERROR, "Line %d: allocation " -+ "failed", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wpa_key_mgmt") == 0) { -+ bss->wpa_key_mgmt = -+ hostapd_config_parse_key_mgmt(line, pos); -+ if (bss->wpa_key_mgmt == -1) -+ errors++; -+ } else if (os_strcmp(buf, "wpa_pairwise") == 0) { -+ bss->wpa_pairwise = -+ hostapd_config_parse_cipher(line, pos); -+ if (bss->wpa_pairwise == -1 || -+ bss->wpa_pairwise == 0) -+ errors++; -+ else if (bss->wpa_pairwise & -+ (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | -+ WPA_CIPHER_WEP104)) { -+ wpa_printf(MSG_ERROR, "Line %d: unsupported " -+ "pairwise cipher suite '%s'", -+ bss->wpa_pairwise, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "rsn_pairwise") == 0) { -+ bss->rsn_pairwise = -+ hostapd_config_parse_cipher(line, pos); -+ if (bss->rsn_pairwise == -1 || -+ bss->rsn_pairwise == 0) -+ errors++; -+ else if (bss->rsn_pairwise & -+ (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 | -+ WPA_CIPHER_WEP104)) { -+ wpa_printf(MSG_ERROR, "Line %d: unsupported " -+ "pairwise cipher suite '%s'", -+ bss->rsn_pairwise, pos); -+ errors++; -+ } -+#ifdef CONFIG_RSN_PREAUTH -+ } else if (os_strcmp(buf, "rsn_preauth") == 0) { -+ bss->rsn_preauth = atoi(pos); -+ } else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) { -+ bss->rsn_preauth_interfaces = os_strdup(pos); -+#endif /* CONFIG_RSN_PREAUTH */ -+#ifdef CONFIG_PEERKEY -+ } else if (os_strcmp(buf, "peerkey") == 0) { -+ bss->peerkey = atoi(pos); -+#endif /* CONFIG_PEERKEY */ -+#ifdef CONFIG_IEEE80211R -+ } else if (os_strcmp(buf, "mobility_domain") == 0) { -+ if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN || -+ hexstr2bin(pos, bss->mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "Line %d: Invalid " -+ "mobility_domain '%s'", line, pos); -+ errors++; -+ continue; -+ } -+ } else if (os_strcmp(buf, "r1_key_holder") == 0) { -+ if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN || -+ hexstr2bin(pos, bss->r1_key_holder, -+ FT_R1KH_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "Line %d: Invalid " -+ "r1_key_holder '%s'", line, pos); -+ errors++; -+ continue; -+ } -+ } else if (os_strcmp(buf, "r0_key_lifetime") == 0) { -+ bss->r0_key_lifetime = atoi(pos); -+ } else if (os_strcmp(buf, "reassociation_deadline") == 0) { -+ bss->reassociation_deadline = atoi(pos); -+ } else if (os_strcmp(buf, "r0kh") == 0) { -+ if (add_r0kh(bss, pos) < 0) { -+ wpa_printf(MSG_DEBUG, "Line %d: Invalid " -+ "r0kh '%s'", line, pos); -+ errors++; -+ continue; -+ } -+ } else if (os_strcmp(buf, "r1kh") == 0) { -+ if (add_r1kh(bss, pos) < 0) { -+ wpa_printf(MSG_DEBUG, "Line %d: Invalid " -+ "r1kh '%s'", line, pos); -+ errors++; -+ continue; -+ } -+ } else if (os_strcmp(buf, "pmk_r1_push") == 0) { -+ bss->pmk_r1_push = atoi(pos); -+ } else if (os_strcmp(buf, "ft_over_ds") == 0) { -+ bss->ft_over_ds = atoi(pos); -+#endif /* CONFIG_IEEE80211R */ -+#ifndef CONFIG_NO_CTRL_IFACE -+ } else if (os_strcmp(buf, "ctrl_interface") == 0) { -+ os_free(bss->ctrl_interface); -+ bss->ctrl_interface = os_strdup(pos); -+ } else if (os_strcmp(buf, "ctrl_interface_group") == 0) { -+#ifndef CONFIG_NATIVE_WINDOWS -+ struct group *grp; -+ char *endp; -+ const char *group = pos; -+ -+ grp = getgrnam(group); -+ if (grp) { -+ bss->ctrl_interface_gid = grp->gr_gid; -+ bss->ctrl_interface_gid_set = 1; -+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" -+ " (from group name '%s')", -+ bss->ctrl_interface_gid, group); -+ continue; -+ } -+ -+ /* Group name not found - try to parse this as gid */ -+ bss->ctrl_interface_gid = strtol(group, &endp, 10); -+ if (*group == '\0' || *endp != '\0') { -+ wpa_printf(MSG_DEBUG, "Line %d: Invalid group " -+ "'%s'", line, group); -+ errors++; -+ continue; -+ } -+ bss->ctrl_interface_gid_set = 1; -+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", -+ bss->ctrl_interface_gid); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+#endif /* CONFIG_NO_CTRL_IFACE */ -+#ifdef RADIUS_SERVER -+ } else if (os_strcmp(buf, "radius_server_clients") == 0) { -+ os_free(bss->radius_server_clients); -+ bss->radius_server_clients = os_strdup(pos); -+ } else if (os_strcmp(buf, "radius_server_auth_port") == 0) { -+ bss->radius_server_auth_port = atoi(pos); -+ } else if (os_strcmp(buf, "radius_server_ipv6") == 0) { -+ bss->radius_server_ipv6 = atoi(pos); -+#endif /* RADIUS_SERVER */ -+ } else if (os_strcmp(buf, "test_socket") == 0) { -+ os_free(bss->test_socket); -+ bss->test_socket = os_strdup(pos); -+ } else if (os_strcmp(buf, "use_pae_group_addr") == 0) { -+ bss->use_pae_group_addr = atoi(pos); -+ } else if (os_strcmp(buf, "hw_mode") == 0) { -+ if (os_strcmp(pos, "a") == 0) -+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A; -+ else if (os_strcmp(pos, "b") == 0) -+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B; -+ else if (os_strcmp(pos, "g") == 0) -+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G; -+ else { -+ wpa_printf(MSG_ERROR, "Line %d: unknown " -+ "hw_mode '%s'", line, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "channel") == 0) { -+ conf->channel = atoi(pos); -+ } else if (os_strcmp(buf, "beacon_int") == 0) { -+ int val = atoi(pos); -+ /* MIB defines range as 1..65535, but very small values -+ * cause problems with the current implementation. -+ * Since it is unlikely that this small numbers are -+ * useful in real life scenarios, do not allow beacon -+ * period to be set below 15 TU. */ -+ if (val < 15 || val > 65535) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "beacon_int %d (expected " -+ "15..65535)", line, val); -+ errors++; -+ } else -+ conf->beacon_int = val; -+ } else if (os_strcmp(buf, "dtim_period") == 0) { -+ bss->dtim_period = atoi(pos); -+ if (bss->dtim_period < 1 || bss->dtim_period > 255) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "dtim_period %d", -+ line, bss->dtim_period); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "rts_threshold") == 0) { -+ conf->rts_threshold = atoi(pos); -+ if (conf->rts_threshold < 0 || -+ conf->rts_threshold > 2347) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "rts_threshold %d", -+ line, conf->rts_threshold); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "fragm_threshold") == 0) { -+ conf->fragm_threshold = atoi(pos); -+ if (conf->fragm_threshold < 256 || -+ conf->fragm_threshold > 2346) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "fragm_threshold %d", -+ line, conf->fragm_threshold); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "send_probe_response") == 0) { -+ int val = atoi(pos); -+ if (val != 0 && val != 1) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "send_probe_response %d (expected " -+ "0 or 1)", line, val); -+ } else -+ conf->send_probe_response = val; -+ } else if (os_strcmp(buf, "supported_rates") == 0) { -+ if (hostapd_parse_rates(&conf->supported_rates, pos)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid rate " -+ "list", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "basic_rates") == 0) { -+ if (hostapd_parse_rates(&conf->basic_rates, pos)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid rate " -+ "list", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "preamble") == 0) { -+ if (atoi(pos)) -+ conf->preamble = SHORT_PREAMBLE; -+ else -+ conf->preamble = LONG_PREAMBLE; -+ } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) { -+ bss->ignore_broadcast_ssid = atoi(pos); -+ } else if (os_strcmp(buf, "wep_default_key") == 0) { -+ bss->ssid.wep.idx = atoi(pos); -+ if (bss->ssid.wep.idx > 3) { -+ wpa_printf(MSG_ERROR, "Invalid " -+ "wep_default_key index %d", -+ bss->ssid.wep.idx); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wep_key0") == 0 || -+ os_strcmp(buf, "wep_key1") == 0 || -+ os_strcmp(buf, "wep_key2") == 0 || -+ os_strcmp(buf, "wep_key3") == 0) { -+ if (hostapd_config_read_wep(&bss->ssid.wep, -+ buf[7] - '0', pos)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid WEP " -+ "key '%s'", line, buf); -+ errors++; -+ } -+#ifndef CONFIG_NO_VLAN -+ } else if (os_strcmp(buf, "dynamic_vlan") == 0) { -+ bss->ssid.dynamic_vlan = atoi(pos); -+ } else if (os_strcmp(buf, "vlan_file") == 0) { -+ if (hostapd_config_read_vlan_file(bss, pos)) { -+ wpa_printf(MSG_ERROR, "Line %d: failed to " -+ "read VLAN file '%s'", line, pos); -+ errors++; -+ } -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ } else if (os_strcmp(buf, "vlan_tagged_interface") == 0) { -+ bss->ssid.vlan_tagged_interface = os_strdup(pos); -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+#endif /* CONFIG_NO_VLAN */ -+ } else if (os_strcmp(buf, "ap_table_max_size") == 0) { -+ conf->ap_table_max_size = atoi(pos); -+ } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) { -+ conf->ap_table_expiration_time = atoi(pos); -+ } else if (os_strncmp(buf, "tx_queue_", 9) == 0) { -+ if (hostapd_config_tx_queue(conf, buf, pos)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid TX " -+ "queue item", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wme_enabled") == 0 || -+ os_strcmp(buf, "wmm_enabled") == 0) { -+ bss->wmm_enabled = atoi(pos); -+ } else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) { -+ bss->wmm_uapsd = atoi(pos); -+ } else if (os_strncmp(buf, "wme_ac_", 7) == 0 || -+ os_strncmp(buf, "wmm_ac_", 7) == 0) { -+ if (hostapd_config_wmm_ac(conf, buf, pos)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid WMM " -+ "ac item", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "bss") == 0) { -+ if (hostapd_config_bss(conf, pos)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid bss " -+ "item", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "bssid") == 0) { -+ if (hwaddr_aton(pos, bss->bssid)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid bssid " -+ "item", line); -+ errors++; -+ } -+#ifdef CONFIG_IEEE80211W -+ } else if (os_strcmp(buf, "ieee80211w") == 0) { -+ bss->ieee80211w = atoi(pos); -+ } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { -+ bss->assoc_sa_query_max_timeout = atoi(pos); -+ if (bss->assoc_sa_query_max_timeout == 0) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "assoc_sa_query_max_timeout", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0) -+ { -+ bss->assoc_sa_query_retry_timeout = atoi(pos); -+ if (bss->assoc_sa_query_retry_timeout == 0) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "assoc_sa_query_retry_timeout", -+ line); -+ errors++; -+ } -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_IEEE80211N -+ } else if (os_strcmp(buf, "ieee80211n") == 0) { -+ conf->ieee80211n = atoi(pos); -+ } else if (os_strcmp(buf, "ht_capab") == 0) { -+ if (hostapd_config_ht_capab(conf, pos) < 0) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "ht_capab", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "require_ht") == 0) { -+ conf->require_ht = atoi(pos); -+#endif /* CONFIG_IEEE80211N */ -+ } else if (os_strcmp(buf, "max_listen_interval") == 0) { -+ bss->max_listen_interval = atoi(pos); -+ } else if (os_strcmp(buf, "okc") == 0) { -+ bss->okc = atoi(pos); -+#ifdef CONFIG_WPS -+ } else if (os_strcmp(buf, "wps_state") == 0) { -+ bss->wps_state = atoi(pos); -+ if (bss->wps_state < 0 || bss->wps_state > 2) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "wps_state", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "ap_setup_locked") == 0) { -+ bss->ap_setup_locked = atoi(pos); -+ } else if (os_strcmp(buf, "uuid") == 0) { -+ if (uuid_str2bin(pos, bss->uuid)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid UUID", -+ line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wps_pin_requests") == 0) { -+ os_free(bss->wps_pin_requests); -+ bss->wps_pin_requests = os_strdup(pos); -+ } else if (os_strcmp(buf, "device_name") == 0) { -+ if (os_strlen(pos) > 32) { -+ wpa_printf(MSG_ERROR, "Line %d: Too long " -+ "device_name", line); -+ errors++; -+ } -+ os_free(bss->device_name); -+ bss->device_name = os_strdup(pos); -+ } else if (os_strcmp(buf, "manufacturer") == 0) { -+ if (os_strlen(pos) > 64) { -+ wpa_printf(MSG_ERROR, "Line %d: Too long " -+ "manufacturer", line); -+ errors++; -+ } -+ os_free(bss->manufacturer); -+ bss->manufacturer = os_strdup(pos); -+ } else if (os_strcmp(buf, "model_name") == 0) { -+ if (os_strlen(pos) > 32) { -+ wpa_printf(MSG_ERROR, "Line %d: Too long " -+ "model_name", line); -+ errors++; -+ } -+ os_free(bss->model_name); -+ bss->model_name = os_strdup(pos); -+ } else if (os_strcmp(buf, "model_number") == 0) { -+ if (os_strlen(pos) > 32) { -+ wpa_printf(MSG_ERROR, "Line %d: Too long " -+ "model_number", line); -+ errors++; -+ } -+ os_free(bss->model_number); -+ bss->model_number = os_strdup(pos); -+ } else if (os_strcmp(buf, "serial_number") == 0) { -+ if (os_strlen(pos) > 32) { -+ wpa_printf(MSG_ERROR, "Line %d: Too long " -+ "serial_number", line); -+ errors++; -+ } -+ os_free(bss->serial_number); -+ bss->serial_number = os_strdup(pos); -+ } else if (os_strcmp(buf, "device_type") == 0) { -+ if (wps_dev_type_str2bin(pos, bss->device_type)) -+ errors++; -+ } else if (os_strcmp(buf, "config_methods") == 0) { -+ os_free(bss->config_methods); -+ bss->config_methods = os_strdup(pos); -+ } else if (os_strcmp(buf, "os_version") == 0) { -+ if (hexstr2bin(pos, bss->os_version, 4)) { -+ wpa_printf(MSG_ERROR, "Line %d: invalid " -+ "os_version", line); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "ap_pin") == 0) { -+ os_free(bss->ap_pin); -+ bss->ap_pin = os_strdup(pos); -+ } else if (os_strcmp(buf, "skip_cred_build") == 0) { -+ bss->skip_cred_build = atoi(pos); -+ } else if (os_strcmp(buf, "extra_cred") == 0) { -+ os_free(bss->extra_cred); -+ bss->extra_cred = -+ (u8 *) os_readfile(pos, &bss->extra_cred_len); -+ if (bss->extra_cred == NULL) { -+ wpa_printf(MSG_ERROR, "Line %d: could not " -+ "read Credentials from '%s'", -+ line, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "wps_cred_processing") == 0) { -+ bss->wps_cred_processing = atoi(pos); -+ } else if (os_strcmp(buf, "ap_settings") == 0) { -+ os_free(bss->ap_settings); -+ bss->ap_settings = -+ (u8 *) os_readfile(pos, &bss->ap_settings_len); -+ if (bss->ap_settings == NULL) { -+ wpa_printf(MSG_ERROR, "Line %d: could not " -+ "read AP Settings from '%s'", -+ line, pos); -+ errors++; -+ } -+ } else if (os_strcmp(buf, "upnp_iface") == 0) { -+ bss->upnp_iface = os_strdup(pos); -+ } else if (os_strcmp(buf, "friendly_name") == 0) { -+ os_free(bss->friendly_name); -+ bss->friendly_name = os_strdup(pos); -+ } else if (os_strcmp(buf, "manufacturer_url") == 0) { -+ os_free(bss->manufacturer_url); -+ bss->manufacturer_url = os_strdup(pos); -+ } else if (os_strcmp(buf, "model_description") == 0) { -+ os_free(bss->model_description); -+ bss->model_description = os_strdup(pos); -+ } else if (os_strcmp(buf, "model_url") == 0) { -+ os_free(bss->model_url); -+ bss->model_url = os_strdup(pos); -+ } else if (os_strcmp(buf, "upc") == 0) { -+ os_free(bss->upc); -+ bss->upc = os_strdup(pos); -+#endif /* CONFIG_WPS */ -+#ifdef CONFIG_P2P_MANAGER -+ } else if (os_strcmp(buf, "manage_p2p") == 0) { -+ int manage = atoi(pos); -+ if (manage) -+ bss->p2p |= P2P_MANAGE; -+ else -+ bss->p2p &= ~P2P_MANAGE; -+ } else if (os_strcmp(buf, "allow_cross_connection") == 0) { -+ if (atoi(pos)) -+ bss->p2p |= P2P_ALLOW_CROSS_CONNECTION; -+ else -+ bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION; -+#endif /* CONFIG_P2P_MANAGER */ -+ } else if (os_strcmp(buf, "disassoc_low_ack") == 0) { -+ bss->disassoc_low_ack = atoi(pos); -+ } else if (os_strcmp(buf, "tdls_prohibit") == 0) { -+ int val = atoi(pos); -+ if (val) -+ bss->tdls |= TDLS_PROHIBIT; -+ else -+ bss->tdls &= ~TDLS_PROHIBIT; -+ } else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) { -+ int val = atoi(pos); -+ if (val) -+ bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH; -+ else -+ bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH; -+#ifdef CONFIG_RSN_TESTING -+ } else if (os_strcmp(buf, "rsn_testing") == 0) { -+ extern int rsn_testing; -+ rsn_testing = atoi(pos); -+#endif /* CONFIG_RSN_TESTING */ -+ } else { -+ wpa_printf(MSG_ERROR, "Line %d: unknown configuration " -+ "item '%s'", line, buf); -+ errors++; -+ } -+ } -+ -+ fclose(f); -+ -+ for (i = 0; i < conf->num_bss; i++) { -+ bss = &conf->bss[i]; -+ -+ if (bss->individual_wep_key_len == 0) { -+ /* individual keys are not use; can use key idx0 for -+ * broadcast keys */ -+ bss->broadcast_key_idx_min = 0; -+ } -+ -+ /* Select group cipher based on the enabled pairwise cipher -+ * suites */ -+ pairwise = 0; -+ if (bss->wpa & 1) -+ pairwise |= bss->wpa_pairwise; -+ if (bss->wpa & 2) { -+ if (bss->rsn_pairwise == 0) -+ bss->rsn_pairwise = bss->wpa_pairwise; -+ pairwise |= bss->rsn_pairwise; -+ } -+ if (pairwise & WPA_CIPHER_TKIP) -+ bss->wpa_group = WPA_CIPHER_TKIP; -+ else -+ bss->wpa_group = WPA_CIPHER_CCMP; -+ -+ bss->radius->auth_server = bss->radius->auth_servers; -+ bss->radius->acct_server = bss->radius->acct_servers; -+ -+ if (bss->wpa && bss->ieee802_1x) { -+ bss->ssid.security_policy = SECURITY_WPA; -+ } else if (bss->wpa) { -+ bss->ssid.security_policy = SECURITY_WPA_PSK; -+ } else if (bss->ieee802_1x) { -+ bss->ssid.security_policy = SECURITY_IEEE_802_1X; -+ bss->ssid.wep.default_len = bss->default_wep_key_len; -+ } else if (bss->ssid.wep.keys_set) -+ bss->ssid.security_policy = SECURITY_STATIC_WEP; -+ else -+ bss->ssid.security_policy = SECURITY_PLAINTEXT; -+ } -+ -+ if (hostapd_config_check(conf)) -+ errors++; -+ -+#ifndef WPA_IGNORE_CONFIG_ERRORS -+ if (errors) { -+ wpa_printf(MSG_ERROR, "%d errors found in configuration file " -+ "'%s'", errors, fname); -+ hostapd_config_free(conf); -+ conf = NULL; -+ } -+#endif /* WPA_IGNORE_CONFIG_ERRORS */ -+ -+ return conf; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.h -new file mode 100644 -index 0000000000000..7111a9a3167fd ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/config_file.h -@@ -0,0 +1,20 @@ -+/* -+ * hostapd / Configuration file parser -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef CONFIG_FILE_H -+#define CONFIG_FILE_H -+ -+struct hostapd_config * hostapd_config_read(const char *fname); -+ -+#endif /* CONFIG_FILE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.c -new file mode 100644 -index 0000000000000..195b8a73c737a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.c -@@ -0,0 +1,1131 @@ -+/* -+ * hostapd / UNIX domain socket -based control interface -+ * Copyright (c) 2004-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ -+#include -+#include -+#include -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "common/version.h" -+#include "common/ieee802_11_defs.h" -+#include "drivers/driver.h" -+#include "radius/radius_client.h" -+#include "ap/hostapd.h" -+#include "ap/ap_config.h" -+#include "ap/ieee802_1x.h" -+#include "ap/wpa_auth.h" -+#include "ap/ieee802_11.h" -+#include "ap/sta_info.h" -+#include "ap/accounting.h" -+#include "ap/wps_hostapd.h" -+#include "ap/ctrl_iface_ap.h" -+#include "ap/ap_drv_ops.h" -+#include "wps/wps_defs.h" -+#include "wps/wps.h" -+#include "ctrl_iface.h" -+ -+ -+struct wpa_ctrl_dst { -+ struct wpa_ctrl_dst *next; -+ struct sockaddr_un addr; -+ socklen_t addrlen; -+ int debug_level; -+ int errors; -+}; -+ -+ -+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, -+ const char *buf, size_t len); -+ -+ -+static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, -+ struct sockaddr_un *from, -+ socklen_t fromlen) -+{ -+ struct wpa_ctrl_dst *dst; -+ -+ dst = os_zalloc(sizeof(*dst)); -+ if (dst == NULL) -+ return -1; -+ os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); -+ dst->addrlen = fromlen; -+ dst->debug_level = MSG_INFO; -+ dst->next = hapd->ctrl_dst; -+ hapd->ctrl_dst = dst; -+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", -+ (u8 *) from->sun_path, -+ fromlen - offsetof(struct sockaddr_un, sun_path)); -+ return 0; -+} -+ -+ -+static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, -+ struct sockaddr_un *from, -+ socklen_t fromlen) -+{ -+ struct wpa_ctrl_dst *dst, *prev = NULL; -+ -+ dst = hapd->ctrl_dst; -+ while (dst) { -+ if (fromlen == dst->addrlen && -+ os_memcmp(from->sun_path, dst->addr.sun_path, -+ fromlen - offsetof(struct sockaddr_un, sun_path)) -+ == 0) { -+ if (prev == NULL) -+ hapd->ctrl_dst = dst->next; -+ else -+ prev->next = dst->next; -+ os_free(dst); -+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", -+ (u8 *) from->sun_path, -+ fromlen - -+ offsetof(struct sockaddr_un, sun_path)); -+ return 0; -+ } -+ prev = dst; -+ dst = dst->next; -+ } -+ return -1; -+} -+ -+ -+static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, -+ struct sockaddr_un *from, -+ socklen_t fromlen, -+ char *level) -+{ -+ struct wpa_ctrl_dst *dst; -+ -+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); -+ -+ dst = hapd->ctrl_dst; -+ while (dst) { -+ if (fromlen == dst->addrlen && -+ os_memcmp(from->sun_path, dst->addr.sun_path, -+ fromlen - offsetof(struct sockaddr_un, sun_path)) -+ == 0) { -+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " -+ "level", (u8 *) from->sun_path, fromlen - -+ offsetof(struct sockaddr_un, sun_path)); -+ dst->debug_level = atoi(level); -+ return 0; -+ } -+ dst = dst->next; -+ } -+ -+ return -1; -+} -+ -+ -+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, -+ const char *txtaddr) -+{ -+ u8 addr[ETH_ALEN]; -+ struct sta_info *sta; -+ -+ wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); -+ -+ if (hwaddr_aton(txtaddr, addr)) -+ return -1; -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " -+ "notification", MAC2STR(addr)); -+ sta = ap_sta_add(hapd, addr); -+ if (sta == NULL) -+ return -1; -+ -+ hostapd_new_assoc_sta(hapd, sta, 0); -+ return 0; -+} -+ -+ -+#ifdef CONFIG_P2P_MANAGER -+static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, -+ u8 minor_reason_code, const u8 *addr) -+{ -+ struct ieee80211_mgmt *mgmt; -+ int ret; -+ u8 *pos; -+ -+ if (hapd->driver->send_frame == NULL) -+ return -1; -+ -+ mgmt = os_zalloc(sizeof(*mgmt) + 100); -+ if (mgmt == NULL) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor " -+ "reason code %u (stype=%u)", -+ MAC2STR(addr), minor_reason_code, stype); -+ -+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); -+ os_memcpy(mgmt->da, addr, ETH_ALEN); -+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); -+ if (stype == WLAN_FC_STYPE_DEAUTH) { -+ mgmt->u.deauth.reason_code = -+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); -+ pos = (u8 *) (&mgmt->u.deauth.reason_code + 1); -+ } else { -+ mgmt->u.disassoc.reason_code = -+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); -+ pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1); -+ } -+ -+ *pos++ = WLAN_EID_VENDOR_SPECIFIC; -+ *pos++ = 4 + 3 + 1; -+ WPA_PUT_BE24(pos, OUI_WFA); -+ pos += 3; -+ *pos++ = P2P_OUI_TYPE; -+ -+ *pos++ = P2P_ATTR_MINOR_REASON_CODE; -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ *pos++ = minor_reason_code; -+ -+ ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt, -+ pos - (u8 *) mgmt, 1); -+ os_free(mgmt); -+ -+ return ret < 0 ? -1 : 0; -+} -+#endif /* CONFIG_P2P_MANAGER */ -+ -+ -+static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, -+ const char *txtaddr) -+{ -+ u8 addr[ETH_ALEN]; -+ struct sta_info *sta; -+ const char *pos; -+ -+ wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr); -+ -+ if (hwaddr_aton(txtaddr, addr)) -+ return -1; -+ -+ pos = os_strstr(txtaddr, " test="); -+ if (pos) { -+ struct ieee80211_mgmt mgmt; -+ int encrypt; -+ if (hapd->driver->send_frame == NULL) -+ return -1; -+ pos += 6; -+ encrypt = atoi(pos); -+ os_memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DEAUTH); -+ os_memcpy(mgmt.da, addr, ETH_ALEN); -+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); -+ mgmt.u.deauth.reason_code = -+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); -+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, -+ IEEE80211_HDRLEN + -+ sizeof(mgmt.u.deauth), -+ encrypt) < 0) -+ return -1; -+ return 0; -+ } -+ -+#ifdef CONFIG_P2P_MANAGER -+ pos = os_strstr(txtaddr, " p2p="); -+ if (pos) { -+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH, -+ atoi(pos + 5), addr); -+ } -+#endif /* CONFIG_P2P_MANAGER */ -+ -+ hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); -+ sta = ap_get_sta(hapd, addr); -+ if (sta) -+ ap_sta_deauthenticate(hapd, sta, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ else if (addr[0] == 0xff) -+ hostapd_free_stas(hapd); -+ -+ return 0; -+} -+ -+ -+static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, -+ const char *txtaddr) -+{ -+ u8 addr[ETH_ALEN]; -+ struct sta_info *sta; -+ const char *pos; -+ -+ wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr); -+ -+ if (hwaddr_aton(txtaddr, addr)) -+ return -1; -+ -+ pos = os_strstr(txtaddr, " test="); -+ if (pos) { -+ struct ieee80211_mgmt mgmt; -+ int encrypt; -+ if (hapd->driver->send_frame == NULL) -+ return -1; -+ pos += 6; -+ encrypt = atoi(pos); -+ os_memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DISASSOC); -+ os_memcpy(mgmt.da, addr, ETH_ALEN); -+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); -+ mgmt.u.disassoc.reason_code = -+ host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); -+ if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, -+ IEEE80211_HDRLEN + -+ sizeof(mgmt.u.deauth), -+ encrypt) < 0) -+ return -1; -+ return 0; -+ } -+ -+#ifdef CONFIG_P2P_MANAGER -+ pos = os_strstr(txtaddr, " p2p="); -+ if (pos) { -+ return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC, -+ atoi(pos + 5), addr); -+ } -+#endif /* CONFIG_P2P_MANAGER */ -+ -+ hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); -+ sta = ap_get_sta(hapd, addr); -+ if (sta) -+ ap_sta_disassociate(hapd, sta, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ else if (addr[0] == 0xff) -+ hostapd_free_stas(hapd); -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+#ifdef NEED_AP_MLME -+static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, -+ const char *txtaddr) -+{ -+ u8 addr[ETH_ALEN]; -+ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; -+ -+ wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); -+ -+ if (hwaddr_aton(txtaddr, addr) || -+ os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) -+ return -1; -+ -+ ieee802_11_send_sa_query_req(hapd, addr, trans_id); -+ -+ return 0; -+} -+#endif /* NEED_AP_MLME */ -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+#ifdef CONFIG_WPS -+static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) -+{ -+ char *pin = os_strchr(txt, ' '); -+ char *timeout_txt; -+ int timeout; -+ u8 addr_buf[ETH_ALEN], *addr = NULL; -+ char *pos; -+ -+ if (pin == NULL) -+ return -1; -+ *pin++ = '\0'; -+ -+ timeout_txt = os_strchr(pin, ' '); -+ if (timeout_txt) { -+ *timeout_txt++ = '\0'; -+ timeout = atoi(timeout_txt); -+ pos = os_strchr(timeout_txt, ' '); -+ if (pos) { -+ *pos++ = '\0'; -+ if (hwaddr_aton(pos, addr_buf) == 0) -+ addr = addr_buf; -+ } -+ } else -+ timeout = 0; -+ -+ return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout); -+} -+ -+ -+static int hostapd_ctrl_iface_wps_check_pin( -+ struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen) -+{ -+ char pin[9]; -+ size_t len; -+ char *pos; -+ int ret; -+ -+ wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", -+ (u8 *) cmd, os_strlen(cmd)); -+ for (pos = cmd, len = 0; *pos != '\0'; pos++) { -+ if (*pos < '0' || *pos > '9') -+ continue; -+ pin[len++] = *pos; -+ if (len == 9) { -+ wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); -+ return -1; -+ } -+ } -+ if (len != 4 && len != 8) { -+ wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); -+ return -1; -+ } -+ pin[len] = '\0'; -+ -+ if (len == 8) { -+ unsigned int pin_val; -+ pin_val = atoi(pin); -+ if (!wps_pin_valid(pin_val)) { -+ wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); -+ ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); -+ if (ret < 0 || (size_t) ret >= buflen) -+ return -1; -+ return ret; -+ } -+ } -+ -+ ret = os_snprintf(buf, buflen, "%s", pin); -+ if (ret < 0 || (size_t) ret >= buflen) -+ return -1; -+ -+ return ret; -+} -+ -+ -+#ifdef CONFIG_WPS_OOB -+static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt) -+{ -+ char *path, *method, *name; -+ -+ path = os_strchr(txt, ' '); -+ if (path == NULL) -+ return -1; -+ *path++ = '\0'; -+ -+ method = os_strchr(path, ' '); -+ if (method == NULL) -+ return -1; -+ *method++ = '\0'; -+ -+ name = os_strchr(method, ' '); -+ if (name != NULL) -+ *name++ = '\0'; -+ -+ return hostapd_wps_start_oob(hapd, txt, path, method, name); -+} -+#endif /* CONFIG_WPS_OOB */ -+ -+ -+static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt, -+ char *buf, size_t buflen) -+{ -+ int timeout = 300; -+ char *pos; -+ const char *pin_txt; -+ -+ pos = os_strchr(txt, ' '); -+ if (pos) -+ *pos++ = '\0'; -+ -+ if (os_strcmp(txt, "disable") == 0) { -+ hostapd_wps_ap_pin_disable(hapd); -+ return os_snprintf(buf, buflen, "OK\n"); -+ } -+ -+ if (os_strcmp(txt, "random") == 0) { -+ if (pos) -+ timeout = atoi(pos); -+ pin_txt = hostapd_wps_ap_pin_random(hapd, timeout); -+ if (pin_txt == NULL) -+ return -1; -+ return os_snprintf(buf, buflen, "%s", pin_txt); -+ } -+ -+ if (os_strcmp(txt, "get") == 0) { -+ pin_txt = hostapd_wps_ap_pin_get(hapd); -+ if (pin_txt == NULL) -+ return -1; -+ return os_snprintf(buf, buflen, "%s", pin_txt); -+ } -+ -+ if (os_strcmp(txt, "set") == 0) { -+ char *pin; -+ if (pos == NULL) -+ return -1; -+ pin = pos; -+ pos = os_strchr(pos, ' '); -+ if (pos) { -+ *pos++ = '\0'; -+ timeout = atoi(pos); -+ } -+ if (os_strlen(pin) > buflen) -+ return -1; -+ if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0) -+ return -1; -+ return os_snprintf(buf, buflen, "%s", pin); -+ } -+ -+ return -1; -+} -+ -+ -+static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) -+{ -+ char *pos; -+ char *ssid, *auth, *encr = NULL, *key = NULL; -+ -+ ssid = txt; -+ pos = os_strchr(txt, ' '); -+ if (!pos) -+ return -1; -+ *pos++ = '\0'; -+ -+ auth = pos; -+ pos = os_strchr(pos, ' '); -+ if (pos) { -+ *pos++ = '\0'; -+ encr = pos; -+ pos = os_strchr(pos, ' '); -+ if (pos) { -+ *pos++ = '\0'; -+ key = pos; -+ } -+ } -+ -+ return hostapd_wps_config_ap(hapd, ssid, auth, encr, key); -+} -+#endif /* CONFIG_WPS */ -+ -+ -+static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, -+ char *buf, size_t buflen) -+{ -+ int ret; -+ char *pos, *end; -+ -+ pos = buf; -+ end = buf + buflen; -+ -+ ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n" -+ "ssid=%s\n", -+ MAC2STR(hapd->own_addr), -+ hapd->conf->ssid.ssid); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+#ifdef CONFIG_WPS -+ ret = os_snprintf(pos, end - pos, "wps_state=%s\n", -+ hapd->conf->wps_state == 0 ? "disabled" : -+ (hapd->conf->wps_state == 1 ? "not configured" : -+ "configured")); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ if (hapd->conf->wps_state && hapd->conf->wpa && -+ hapd->conf->ssid.wpa_passphrase) { -+ ret = os_snprintf(pos, end - pos, "passphrase=%s\n", -+ hapd->conf->ssid.wpa_passphrase); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ if (hapd->conf->wps_state && hapd->conf->wpa && -+ hapd->conf->ssid.wpa_psk && -+ hapd->conf->ssid.wpa_psk->group) { -+ char hex[PMK_LEN * 2 + 1]; -+ wpa_snprintf_hex(hex, sizeof(hex), -+ hapd->conf->ssid.wpa_psk->psk, PMK_LEN); -+ ret = os_snprintf(pos, end - pos, "psk=%s\n", hex); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+#endif /* CONFIG_WPS */ -+ -+ if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) { -+ ret = os_snprintf(pos, end - pos, "key_mgmt="); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { -+ ret = os_snprintf(pos, end - pos, "WPA-PSK "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { -+ ret = os_snprintf(pos, end - pos, "WPA-EAP "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+#ifdef CONFIG_IEEE80211R -+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { -+ ret = os_snprintf(pos, end - pos, "FT-PSK "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { -+ ret = os_snprintf(pos, end - pos, "FT-EAP "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { -+ ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { -+ ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ ret = os_snprintf(pos, end - pos, "\n"); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) { -+ ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n"); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } else if (hapd->conf->wpa && -+ hapd->conf->wpa_group == WPA_CIPHER_TKIP) { -+ ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n"); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) { -+ ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher="); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) { -+ ret = os_snprintf(pos, end - pos, "CCMP "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) { -+ ret = os_snprintf(pos, end - pos, "TKIP "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ ret = os_snprintf(pos, end - pos, "\n"); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) { -+ ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher="); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) { -+ ret = os_snprintf(pos, end - pos, "CCMP "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) { -+ ret = os_snprintf(pos, end - pos, "TKIP "); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ ret = os_snprintf(pos, end - pos, "\n"); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ return pos - buf; -+} -+ -+ -+static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) -+{ -+ char *value; -+ int ret = 0; -+ -+ value = os_strchr(cmd, ' '); -+ if (value == NULL) -+ return -1; -+ *value++ = '\0'; -+ -+ wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); -+ if (0) { -+#ifdef CONFIG_WPS_TESTING -+ } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { -+ long int val; -+ val = strtol(value, NULL, 0); -+ if (val < 0 || val > 0xff) { -+ ret = -1; -+ wpa_printf(MSG_DEBUG, "WPS: Invalid " -+ "wps_version_number %ld", val); -+ } else { -+ wps_version_number = val; -+ wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " -+ "version %u.%u", -+ (wps_version_number & 0xf0) >> 4, -+ wps_version_number & 0x0f); -+ hostapd_wps_update_ie(hapd); -+ } -+ } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { -+ wps_testing_dummy_cred = atoi(value); -+ wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", -+ wps_testing_dummy_cred); -+#endif /* CONFIG_WPS_TESTING */ -+ } else { -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd, -+ char *buf, size_t buflen) -+{ -+ int res; -+ -+ wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); -+ -+ if (os_strcmp(cmd, "version") == 0) { -+ res = os_snprintf(buf, buflen, "%s", VERSION_STR); -+ if (res < 0 || (unsigned int) res >= buflen) -+ return -1; -+ return res; -+ } -+ -+ return -1; -+} -+ -+ -+static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, -+ void *sock_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ char buf[256]; -+ int res; -+ struct sockaddr_un from; -+ socklen_t fromlen = sizeof(from); -+ char *reply; -+ const int reply_size = 4096; -+ int reply_len; -+ int level = MSG_DEBUG; -+ -+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0, -+ (struct sockaddr *) &from, &fromlen); -+ if (res < 0) { -+ perror("recvfrom(ctrl_iface)"); -+ return; -+ } -+ buf[res] = '\0'; -+ if (os_strcmp(buf, "PING") == 0) -+ level = MSG_EXCESSIVE; -+ wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res); -+ -+ reply = os_malloc(reply_size); -+ if (reply == NULL) { -+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, -+ fromlen); -+ return; -+ } -+ -+ os_memcpy(reply, "OK\n", 3); -+ reply_len = 3; -+ -+ if (os_strcmp(buf, "PING") == 0) { -+ os_memcpy(reply, "PONG\n", 5); -+ reply_len = 5; -+ } else if (os_strncmp(buf, "RELOG", 5) == 0) { -+ if (wpa_debug_reopen_file() < 0) -+ reply_len = -1; -+ } else if (os_strcmp(buf, "MIB") == 0) { -+ reply_len = ieee802_11_get_mib(hapd, reply, reply_size); -+ if (reply_len >= 0) { -+ res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, -+ reply_size - reply_len); -+ if (res < 0) -+ reply_len = -1; -+ else -+ reply_len += res; -+ } -+ if (reply_len >= 0) { -+ res = ieee802_1x_get_mib(hapd, reply + reply_len, -+ reply_size - reply_len); -+ if (res < 0) -+ reply_len = -1; -+ else -+ reply_len += res; -+ } -+#ifndef CONFIG_NO_RADIUS -+ if (reply_len >= 0) { -+ res = radius_client_get_mib(hapd->radius, -+ reply + reply_len, -+ reply_size - reply_len); -+ if (res < 0) -+ reply_len = -1; -+ else -+ reply_len += res; -+ } -+#endif /* CONFIG_NO_RADIUS */ -+ } else if (os_strcmp(buf, "STA-FIRST") == 0) { -+ reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, -+ reply_size); -+ } else if (os_strncmp(buf, "STA ", 4) == 0) { -+ reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, -+ reply_size); -+ } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { -+ reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, -+ reply_size); -+ } else if (os_strcmp(buf, "ATTACH") == 0) { -+ if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) -+ reply_len = -1; -+ } else if (os_strcmp(buf, "DETACH") == 0) { -+ if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) -+ reply_len = -1; -+ } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { -+ if (hostapd_ctrl_iface_level(hapd, &from, fromlen, -+ buf + 6)) -+ reply_len = -1; -+ } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { -+ if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) -+ reply_len = -1; -+ } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { -+ if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15)) -+ reply_len = -1; -+ } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { -+ if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) -+ reply_len = -1; -+#ifdef CONFIG_IEEE80211W -+#ifdef NEED_AP_MLME -+ } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { -+ if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) -+ reply_len = -1; -+#endif /* NEED_AP_MLME */ -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_WPS -+ } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { -+ if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) -+ reply_len = -1; -+ } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { -+ reply_len = hostapd_ctrl_iface_wps_check_pin( -+ hapd, buf + 14, reply, reply_size); -+ } else if (os_strcmp(buf, "WPS_PBC") == 0) { -+ if (hostapd_wps_button_pushed(hapd, NULL)) -+ reply_len = -1; -+#ifdef CONFIG_WPS_OOB -+ } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) { -+ if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8)) -+ reply_len = -1; -+#endif /* CONFIG_WPS_OOB */ -+ } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { -+ reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11, -+ reply, reply_size); -+ } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) { -+ if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0) -+ reply_len = -1; -+#endif /* CONFIG_WPS */ -+ } else if (os_strcmp(buf, "GET_CONFIG") == 0) { -+ reply_len = hostapd_ctrl_iface_get_config(hapd, reply, -+ reply_size); -+ } else if (os_strncmp(buf, "SET ", 4) == 0) { -+ if (hostapd_ctrl_iface_set(hapd, buf + 4)) -+ reply_len = -1; -+ } else if (os_strncmp(buf, "GET ", 4) == 0) { -+ reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply, -+ reply_size); -+ } else { -+ os_memcpy(reply, "UNKNOWN COMMAND\n", 16); -+ reply_len = 16; -+ } -+ -+ if (reply_len < 0) { -+ os_memcpy(reply, "FAIL\n", 5); -+ reply_len = 5; -+ } -+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); -+ os_free(reply); -+} -+ -+ -+static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) -+{ -+ char *buf; -+ size_t len; -+ -+ if (hapd->conf->ctrl_interface == NULL) -+ return NULL; -+ -+ len = os_strlen(hapd->conf->ctrl_interface) + -+ os_strlen(hapd->conf->iface) + 2; -+ buf = os_malloc(len); -+ if (buf == NULL) -+ return NULL; -+ -+ os_snprintf(buf, len, "%s/%s", -+ hapd->conf->ctrl_interface, hapd->conf->iface); -+ buf[len - 1] = '\0'; -+ return buf; -+} -+ -+ -+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, -+ const char *txt, size_t len) -+{ -+ struct hostapd_data *hapd = ctx; -+ if (hapd == NULL) -+ return; -+ hostapd_ctrl_iface_send(hapd, level, txt, len); -+} -+ -+ -+int hostapd_ctrl_iface_init(struct hostapd_data *hapd) -+{ -+ struct sockaddr_un addr; -+ int s = -1; -+ char *fname = NULL; -+ -+ hapd->ctrl_sock = -1; -+ -+ if (hapd->conf->ctrl_interface == NULL) -+ return 0; -+ -+ if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { -+ if (errno == EEXIST) { -+ wpa_printf(MSG_DEBUG, "Using existing control " -+ "interface directory."); -+ } else { -+ perror("mkdir[ctrl_interface]"); -+ goto fail; -+ } -+ } -+ -+ if (hapd->conf->ctrl_interface_gid_set && -+ chown(hapd->conf->ctrl_interface, 0, -+ hapd->conf->ctrl_interface_gid) < 0) { -+ perror("chown[ctrl_interface]"); -+ return -1; -+ } -+ -+ if (os_strlen(hapd->conf->ctrl_interface) + 1 + -+ os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) -+ goto fail; -+ -+ s = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (s < 0) { -+ perror("socket(PF_UNIX)"); -+ goto fail; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+#ifdef __FreeBSD__ -+ addr.sun_len = sizeof(addr); -+#endif /* __FreeBSD__ */ -+ addr.sun_family = AF_UNIX; -+ fname = hostapd_ctrl_iface_path(hapd); -+ if (fname == NULL) -+ goto fail; -+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); -+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", -+ strerror(errno)); -+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" -+ " allow connections - assuming it was left" -+ "over from forced program termination"); -+ if (unlink(fname) < 0) { -+ perror("unlink[ctrl_iface]"); -+ wpa_printf(MSG_ERROR, "Could not unlink " -+ "existing ctrl_iface socket '%s'", -+ fname); -+ goto fail; -+ } -+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < -+ 0) { -+ perror("bind(PF_UNIX)"); -+ goto fail; -+ } -+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover " -+ "ctrl_iface socket '%s'", fname); -+ } else { -+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " -+ "be in use - cannot override it"); -+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is " -+ "not used anymore", fname); -+ os_free(fname); -+ fname = NULL; -+ goto fail; -+ } -+ } -+ -+ if (hapd->conf->ctrl_interface_gid_set && -+ chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) { -+ perror("chown[ctrl_interface/ifname]"); -+ goto fail; -+ } -+ -+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { -+ perror("chmod[ctrl_interface/ifname]"); -+ goto fail; -+ } -+ os_free(fname); -+ -+ hapd->ctrl_sock = s; -+ eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, -+ NULL); -+ hapd->msg_ctx = hapd; -+ wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); -+ -+ return 0; -+ -+fail: -+ if (s >= 0) -+ close(s); -+ if (fname) { -+ unlink(fname); -+ os_free(fname); -+ } -+ return -1; -+} -+ -+ -+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) -+{ -+ struct wpa_ctrl_dst *dst, *prev; -+ -+ if (hapd->ctrl_sock > -1) { -+ char *fname; -+ eloop_unregister_read_sock(hapd->ctrl_sock); -+ close(hapd->ctrl_sock); -+ hapd->ctrl_sock = -1; -+ fname = hostapd_ctrl_iface_path(hapd); -+ if (fname) -+ unlink(fname); -+ os_free(fname); -+ -+ if (hapd->conf->ctrl_interface && -+ rmdir(hapd->conf->ctrl_interface) < 0) { -+ if (errno == ENOTEMPTY) { -+ wpa_printf(MSG_DEBUG, "Control interface " -+ "directory not empty - leaving it " -+ "behind"); -+ } else { -+ perror("rmdir[ctrl_interface]"); -+ } -+ } -+ } -+ -+ dst = hapd->ctrl_dst; -+ while (dst) { -+ prev = dst; -+ dst = dst->next; -+ os_free(prev); -+ } -+} -+ -+ -+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, -+ const char *buf, size_t len) -+{ -+ struct wpa_ctrl_dst *dst, *next; -+ struct msghdr msg; -+ int idx; -+ struct iovec io[2]; -+ char levelstr[10]; -+ -+ dst = hapd->ctrl_dst; -+ if (hapd->ctrl_sock < 0 || dst == NULL) -+ return; -+ -+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); -+ io[0].iov_base = levelstr; -+ io[0].iov_len = os_strlen(levelstr); -+ io[1].iov_base = (char *) buf; -+ io[1].iov_len = len; -+ os_memset(&msg, 0, sizeof(msg)); -+ msg.msg_iov = io; -+ msg.msg_iovlen = 2; -+ -+ idx = 0; -+ while (dst) { -+ next = dst->next; -+ if (level >= dst->debug_level) { -+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", -+ (u8 *) dst->addr.sun_path, dst->addrlen - -+ offsetof(struct sockaddr_un, sun_path)); -+ msg.msg_name = &dst->addr; -+ msg.msg_namelen = dst->addrlen; -+ if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { -+ int _errno = errno; -+ wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " -+ "%d - %s", -+ idx, errno, strerror(errno)); -+ dst->errors++; -+ if (dst->errors > 10 || _errno == ENOENT) { -+ hostapd_ctrl_iface_detach( -+ hapd, &dst->addr, -+ dst->addrlen); -+ } -+ } else -+ dst->errors = 0; -+ } -+ idx++; -+ dst = next; -+ } -+} -+ -+#endif /* CONFIG_NATIVE_WINDOWS */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.h -new file mode 100644 -index 0000000000000..c997141a15105 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/ctrl_iface.h -@@ -0,0 +1,32 @@ -+/* -+ * hostapd / UNIX domain socket -based control interface -+ * Copyright (c) 2004, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef CTRL_IFACE_H -+#define CTRL_IFACE_H -+ -+#ifndef CONFIG_NO_CTRL_IFACE -+int hostapd_ctrl_iface_init(struct hostapd_data *hapd); -+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd); -+#else /* CONFIG_NO_CTRL_IFACE */ -+static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd) -+{ -+ return 0; -+} -+ -+static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) -+{ -+} -+#endif /* CONFIG_NO_CTRL_IFACE */ -+ -+#endif /* CTRL_IFACE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/defconfig b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/defconfig -new file mode 100644 -index 0000000000000..47d1a6f8175c1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/defconfig -@@ -0,0 +1,208 @@ -+# Example hostapd build time configuration -+# -+# This file lists the configuration options that are used when building the -+# hostapd binary. All lines starting with # are ignored. Configuration option -+# lines must be commented out complete, if they are not to be included, i.e., -+# just setting VARIABLE=n is not disabling that variable. -+# -+# This file is included in Makefile, so variables like CFLAGS and LIBS can also -+# be modified from here. In most cass, these lines should use += in order not -+# to override previous values of the variables. -+ -+# Driver interface for Host AP driver -+#CONFIG_DRIVER_HOSTAP=y -+CONFIG_DRIVER_RTW=y -+ -+# Driver interface for wired authenticator -+#CONFIG_DRIVER_WIRED=y -+ -+# Driver interface for madwifi driver -+#CONFIG_DRIVER_MADWIFI=y -+#CFLAGS += -I../../madwifi # change to the madwifi source directory -+ -+# Driver interface for drivers using the nl80211 kernel interface -+#CONFIG_DRIVER_NL80211=y -+ -+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) -+#CONFIG_DRIVER_BSD=y -+#CFLAGS += -I/usr/local/include -+#LIBS += -L/usr/local/lib -+#LIBS_p += -L/usr/local/lib -+#LIBS_c += -L/usr/local/lib -+ -+# Driver interface for no driver (e.g., RADIUS server only) -+#CONFIG_DRIVER_NONE=y -+ -+# IEEE 802.11F/IAPP -+#CONFIG_IAPP=y -+ -+# WPA2/IEEE 802.11i RSN pre-authentication -+#CONFIG_RSN_PREAUTH=y -+ -+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS) -+#CONFIG_PEERKEY=y -+ -+# IEEE 802.11w (management frame protection) -+# This version is an experimental implementation based on IEEE 802.11w/D1.0 -+# draft and is subject to change since the standard has not yet been finalized. -+# Driver support is also needed for IEEE 802.11w. -+#CONFIG_IEEE80211W=y -+ -+# Integrated EAP server -+CONFIG_EAP=y -+ -+# EAP-MD5 for the integrated EAP server -+#CONFIG_EAP_MD5=y -+ -+# EAP-TLS for the integrated EAP server -+#CONFIG_EAP_TLS=y -+ -+# EAP-MSCHAPv2 for the integrated EAP server -+#CONFIG_EAP_MSCHAPV2=y -+ -+# EAP-PEAP for the integrated EAP server -+#CONFIG_EAP_PEAP=y -+ -+# EAP-GTC for the integrated EAP server -+#CONFIG_EAP_GTC=y -+ -+# EAP-TTLS for the integrated EAP server -+#CONFIG_EAP_TTLS=y -+ -+# EAP-SIM for the integrated EAP server -+#CONFIG_EAP_SIM=y -+ -+# EAP-AKA for the integrated EAP server -+#CONFIG_EAP_AKA=y -+ -+# EAP-AKA' for the integrated EAP server -+# This requires CONFIG_EAP_AKA to be enabled, too. -+#CONFIG_EAP_AKA_PRIME=y -+ -+# EAP-PAX for the integrated EAP server -+#CONFIG_EAP_PAX=y -+ -+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK) -+#CONFIG_EAP_PSK=y -+ -+# EAP-SAKE for the integrated EAP server -+#CONFIG_EAP_SAKE=y -+ -+# EAP-GPSK for the integrated EAP server -+#CONFIG_EAP_GPSK=y -+# Include support for optional SHA256 cipher suite in EAP-GPSK -+#CONFIG_EAP_GPSK_SHA256=y -+ -+# EAP-FAST for the integrated EAP server -+# Note: Default OpenSSL package does not include support for all the -+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, -+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch) -+# to add the needed functions. -+#CONFIG_EAP_FAST=y -+ -+# Wi-Fi Protected Setup (WPS) -+CONFIG_WPS=y -+# Enable WSC 2.0 support -+CONFIG_WPS2=y -+# Enable UPnP support for external WPS Registrars -+#CONFIG_WPS_UPNP=y -+ -+CONFIG_TLS=internal -+CONFIG_INTERNAL_LIBTOMMATH=y -+ -+# EAP-IKEv2 -+#CONFIG_EAP_IKEV2=y -+ -+# Trusted Network Connect (EAP-TNC) -+#CONFIG_EAP_TNC=y -+ -+# PKCS#12 (PFX) support (used to read private key and certificate file from -+# a file that usually has extension .p12 or .pfx) -+#CONFIG_PKCS12=y -+ -+# RADIUS authentication server. This provides access to the integrated EAP -+# server from external hosts using RADIUS. -+#CONFIG_RADIUS_SERVER=y -+ -+# Build IPv6 support for RADIUS operations -+#CONFIG_IPV6=y -+ -+# IEEE Std 802.11r-2008 (Fast BSS Transition) -+#CONFIG_IEEE80211R=y -+ -+# Use the hostapd's IEEE 802.11 authentication (ACL), but without -+# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211) -+#CONFIG_DRIVER_RADIUS_ACL=y -+ -+# IEEE 802.11n (High Throughput) support -+CONFIG_IEEE80211N=y -+ -+# Remove debugging code that is printing out debug messages to stdout. -+# This can be used to reduce the size of the hostapd considerably if debugging -+# code is not needed. -+#CONFIG_NO_STDOUT_DEBUG=y -+ -+# Add support for writing debug log to a file: -f /tmp/hostapd.log -+# Disabled by default. -+#CONFIG_DEBUG_FILE=y -+ -+# Remove support for RADIUS accounting -+#CONFIG_NO_ACCOUNTING=y -+ -+# Remove support for RADIUS -+#CONFIG_NO_RADIUS=y -+ -+# Remove support for VLANs -+#CONFIG_NO_VLAN=y -+ -+# Enable support for fully dynamic VLANs. This enables hostapd to -+# automatically create bridge and VLAN interfaces if necessary. -+#CONFIG_FULL_DYNAMIC_VLAN=y -+ -+# Remove support for dumping state into a file on SIGUSR1 signal -+# This can be used to reduce binary size at the cost of disabling a debugging -+# option. -+#CONFIG_NO_DUMP_STATE=y -+ -+# Enable tracing code for developer debugging -+# This tracks use of memory allocations and other registrations and reports -+# incorrect use with a backtrace of call (or allocation) location. -+#CONFIG_WPA_TRACE=y -+# For BSD, comment out these. -+#LIBS += -lexecinfo -+#LIBS_p += -lexecinfo -+#LIBS_c += -lexecinfo -+ -+# Use libbfd to get more details for developer debugging -+# This enables use of libbfd to get more detailed symbols for the backtraces -+# generated by CONFIG_WPA_TRACE=y. -+#CONFIG_WPA_TRACE_BFD=y -+# For BSD, comment out these. -+#LIBS += -lbfd -liberty -lz -+#LIBS_p += -lbfd -liberty -lz -+#LIBS_c += -lbfd -liberty -lz -+ -+# hostapd depends on strong random number generation being available from the -+# operating system. os_get_random() function is used to fetch random data when -+# needed, e.g., for key generation. On Linux and BSD systems, this works by -+# reading /dev/urandom. It should be noted that the OS entropy pool needs to be -+# properly initialized before hostapd is started. This is important especially -+# on embedded devices that do not have a hardware random number generator and -+# may by default start up with minimal entropy available for random number -+# generation. -+# -+# As a safety net, hostapd is by default trying to internally collect -+# additional entropy for generating random data to mix in with the data -+# fetched from the OS. This by itself is not considered to be very strong, but -+# it may help in cases where the system pool is not initialized properly. -+# However, it is very strongly recommended that the system pool is initialized -+# with enough entropy either by using hardware assisted random number -+# generatior or by storing state over device reboots. -+# -+# If the os_get_random() is known to provide strong ramdom data (e.g., on -+# Linux/BSD, the board in question is known to have reliable source of random -+# data from /dev/urandom), the internal hostapd random pool can be disabled. -+# This will save some in binary size and CPU use. However, this should only be -+# considered for builds that are known to be used on devices that meet the -+# requirements described above. -+#CONFIG_NO_RANDOM_POOL=y -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.c -new file mode 100644 -index 0000000000000..73aa93dfbd599 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.c -@@ -0,0 +1,183 @@ -+/* -+ * hostapd / State dump -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "radius/radius_client.h" -+#include "radius/radius_server.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "eapol_auth/eapol_auth_sm_i.h" -+#include "eap_server/eap.h" -+#include "ap/hostapd.h" -+#include "ap/ap_config.h" -+#include "ap/sta_info.h" -+#include "dump_state.h" -+ -+ -+static void fprint_char(FILE *f, char c) -+{ -+ if (c >= 32 && c < 127) -+ fprintf(f, "%c", c); -+ else -+ fprintf(f, "<%02x>", c); -+} -+ -+ -+static void ieee802_1x_dump_state(FILE *f, const char *prefix, -+ struct sta_info *sta) -+{ -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ if (sm == NULL) -+ return; -+ -+ fprintf(f, "%sIEEE 802.1X:\n", prefix); -+ -+ if (sm->identity) { -+ size_t i; -+ fprintf(f, "%sidentity=", prefix); -+ for (i = 0; i < sm->identity_len; i++) -+ fprint_char(f, sm->identity[i]); -+ fprintf(f, "\n"); -+ } -+ -+ fprintf(f, "%slast EAP type: Authentication Server: %d (%s) " -+ "Supplicant: %d (%s)\n", prefix, -+ sm->eap_type_authsrv, -+ eap_server_get_name(0, sm->eap_type_authsrv), -+ sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp)); -+ -+ fprintf(f, "%scached_packets=%s\n", prefix, -+ sm->last_recv_radius ? "[RX RADIUS]" : ""); -+ -+ eapol_auth_dump_state(f, prefix, sm); -+} -+ -+ -+/** -+ * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file -+ */ -+static void hostapd_dump_state(struct hostapd_data *hapd) -+{ -+ FILE *f; -+ time_t now; -+ struct sta_info *sta; -+ int i; -+#ifndef CONFIG_NO_RADIUS -+ char *buf; -+#endif /* CONFIG_NO_RADIUS */ -+ -+ if (!hapd->conf->dump_log_name) { -+ wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump " -+ "request"); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'", -+ hapd->conf->dump_log_name); -+ f = fopen(hapd->conf->dump_log_name, "w"); -+ if (f == NULL) { -+ wpa_printf(MSG_WARNING, "Could not open dump file '%s' for " -+ "writing.", hapd->conf->dump_log_name); -+ return; -+ } -+ -+ time(&now); -+ fprintf(f, "hostapd state dump - %s", ctime(&now)); -+ fprintf(f, "num_sta=%d num_sta_non_erp=%d " -+ "num_sta_no_short_slot_time=%d\n" -+ "num_sta_no_short_preamble=%d\n", -+ hapd->num_sta, hapd->iface->num_sta_non_erp, -+ hapd->iface->num_sta_no_short_slot_time, -+ hapd->iface->num_sta_no_short_preamble); -+ -+ for (sta = hapd->sta_list; sta != NULL; sta = sta->next) { -+ fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr)); -+ -+ fprintf(f, -+ " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n" -+ " capability=0x%x listen_interval=%d\n", -+ sta->aid, -+ sta->flags, -+ (sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""), -+ (sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), -+ (sta->flags & WLAN_STA_PS ? "[PS]" : ""), -+ (sta->flags & WLAN_STA_TIM ? "[TIM]" : ""), -+ (sta->flags & WLAN_STA_PERM ? "[PERM]" : ""), -+ (ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""), -+ (sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : -+ ""), -+ (sta->flags & WLAN_STA_SHORT_PREAMBLE ? -+ "[SHORT_PREAMBLE]" : ""), -+ (sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), -+ (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""), -+ (sta->flags & WLAN_STA_MFP ? "[MFP]" : ""), -+ (sta->flags & WLAN_STA_WPS ? "[WPS]" : ""), -+ (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), -+ (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""), -+ (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""), -+ sta->capability, -+ sta->listen_interval); -+ -+ fprintf(f, " supported_rates="); -+ for (i = 0; i < sta->supported_rates_len; i++) -+ fprintf(f, "%02x ", sta->supported_rates[i]); -+ fprintf(f, "\n"); -+ -+ fprintf(f, -+ " timeout_next=%s\n", -+ (sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" : -+ (sta->timeout_next == STA_DISASSOC ? "DISASSOC" : -+ "DEAUTH"))); -+ -+ ieee802_1x_dump_state(f, " ", sta); -+ } -+ -+#ifndef CONFIG_NO_RADIUS -+ buf = os_malloc(4096); -+ if (buf) { -+ int count = radius_client_get_mib(hapd->radius, buf, 4096); -+ if (count < 0) -+ count = 0; -+ else if (count > 4095) -+ count = 4095; -+ buf[count] = '\0'; -+ fprintf(f, "%s", buf); -+ -+#ifdef RADIUS_SERVER -+ count = radius_server_get_mib(hapd->radius_srv, buf, 4096); -+ if (count < 0) -+ count = 0; -+ else if (count > 4095) -+ count = 4095; -+ buf[count] = '\0'; -+ fprintf(f, "%s", buf); -+#endif /* RADIUS_SERVER */ -+ -+ os_free(buf); -+ } -+#endif /* CONFIG_NO_RADIUS */ -+ fclose(f); -+} -+ -+ -+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx) -+{ -+ size_t i; -+ -+ for (i = 0; i < iface->num_bss; i++) -+ hostapd_dump_state(iface->bss[i]); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.h -new file mode 100644 -index 0000000000000..e14f08a4f5e13 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/dump_state.h -@@ -0,0 +1,20 @@ -+/* -+ * hostapd / State dump -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef DUMP_STATE_H -+#define DUMP_STATE_H -+ -+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx); -+ -+#endif /* DUMP_STATE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.c -new file mode 100644 -index 0000000000000..bab28715e6f99 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.c -@@ -0,0 +1,139 @@ -+/* -+ * EAP method registration -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_server/eap_methods.h" -+#include "eap_register.h" -+ -+ -+/** -+ * eap_server_register_methods - Register statically linked EAP server methods -+ * Returns: 0 on success, -1 or -2 on failure -+ * -+ * This function is called at program initialization to register all EAP -+ * methods that were linked in statically. -+ */ -+int eap_server_register_methods(void) -+{ -+ int ret = 0; -+ -+#ifdef EAP_SERVER_IDENTITY -+ if (ret == 0) -+ ret = eap_server_identity_register(); -+#endif /* EAP_SERVER_IDENTITY */ -+ -+#ifdef EAP_SERVER_MD5 -+ if (ret == 0) -+ ret = eap_server_md5_register(); -+#endif /* EAP_SERVER_MD5 */ -+ -+#ifdef EAP_SERVER_TLS -+ if (ret == 0) -+ ret = eap_server_tls_register(); -+#endif /* EAP_SERVER_TLS */ -+ -+#ifdef EAP_SERVER_MSCHAPV2 -+ if (ret == 0) -+ ret = eap_server_mschapv2_register(); -+#endif /* EAP_SERVER_MSCHAPV2 */ -+ -+#ifdef EAP_SERVER_PEAP -+ if (ret == 0) -+ ret = eap_server_peap_register(); -+#endif /* EAP_SERVER_PEAP */ -+ -+#ifdef EAP_SERVER_TLV -+ if (ret == 0) -+ ret = eap_server_tlv_register(); -+#endif /* EAP_SERVER_TLV */ -+ -+#ifdef EAP_SERVER_GTC -+ if (ret == 0) -+ ret = eap_server_gtc_register(); -+#endif /* EAP_SERVER_GTC */ -+ -+#ifdef EAP_SERVER_TTLS -+ if (ret == 0) -+ ret = eap_server_ttls_register(); -+#endif /* EAP_SERVER_TTLS */ -+ -+#ifdef EAP_SERVER_SIM -+ if (ret == 0) -+ ret = eap_server_sim_register(); -+#endif /* EAP_SERVER_SIM */ -+ -+#ifdef EAP_SERVER_AKA -+ if (ret == 0) -+ ret = eap_server_aka_register(); -+#endif /* EAP_SERVER_AKA */ -+ -+#ifdef EAP_SERVER_AKA_PRIME -+ if (ret == 0) -+ ret = eap_server_aka_prime_register(); -+#endif /* EAP_SERVER_AKA_PRIME */ -+ -+#ifdef EAP_SERVER_PAX -+ if (ret == 0) -+ ret = eap_server_pax_register(); -+#endif /* EAP_SERVER_PAX */ -+ -+#ifdef EAP_SERVER_PSK -+ if (ret == 0) -+ ret = eap_server_psk_register(); -+#endif /* EAP_SERVER_PSK */ -+ -+#ifdef EAP_SERVER_SAKE -+ if (ret == 0) -+ ret = eap_server_sake_register(); -+#endif /* EAP_SERVER_SAKE */ -+ -+#ifdef EAP_SERVER_GPSK -+ if (ret == 0) -+ ret = eap_server_gpsk_register(); -+#endif /* EAP_SERVER_GPSK */ -+ -+#ifdef EAP_SERVER_VENDOR_TEST -+ if (ret == 0) -+ ret = eap_server_vendor_test_register(); -+#endif /* EAP_SERVER_VENDOR_TEST */ -+ -+#ifdef EAP_SERVER_FAST -+ if (ret == 0) -+ ret = eap_server_fast_register(); -+#endif /* EAP_SERVER_FAST */ -+ -+#ifdef EAP_SERVER_WSC -+ if (ret == 0) -+ ret = eap_server_wsc_register(); -+#endif /* EAP_SERVER_WSC */ -+ -+#ifdef EAP_SERVER_IKEV2 -+ if (ret == 0) -+ ret = eap_server_ikev2_register(); -+#endif /* EAP_SERVER_IKEV2 */ -+ -+#ifdef EAP_SERVER_TNC -+ if (ret == 0) -+ ret = eap_server_tnc_register(); -+#endif /* EAP_SERVER_TNC */ -+ -+#ifdef EAP_SERVER_PWD -+ if (ret == 0) -+ ret = eap_server_pwd_register(); -+#endif /* EAP_SERVER_PWD */ -+ -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.h -new file mode 100644 -index 0000000000000..82e7171d6fde1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_register.h -@@ -0,0 +1,20 @@ -+/* -+ * EAP method registration -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_REGISTER_H -+#define EAP_REGISTER_H -+ -+int eap_server_register_methods(void); -+ -+#endif /* EAP_REGISTER_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_testing.txt b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_testing.txt -new file mode 100644 -index 0000000000000..04468c39f01ec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/eap_testing.txt -@@ -0,0 +1,77 @@ -+Interoperability testing of hostapd's IEEE 802.1X/EAPOL authentication -+ -+Test matrix -+ -++) tested successfully -+F) failed -+-) peer did not support -+?) not tested -+ -+XSupplicant --------------------------------. -+Intel PROSet ---------------------------. | -+Windows XP -------------------------. | | -+Mac OS X 10.4 ------------------. | | | -+Nokia S60 ------------------. | | | | -+wpa_supplicant ---------. | | | | | -+ | | | | | | -+ -+EAP-MD5 + - ? ? - -+EAP-GTC + - ? - - -+EAP-MSCHAPv2 + - ? - - -+EAP-TLS + + +1 + + -+EAP-PEAPv0/MSCHAPv2 + + + + + + -+EAP-PEAPv0/GTC + + + - + -+EAP-PEAPv0/MD5 + - + - - -+EAP-PEAPv0/TLS + F - + + -+EAP-PEAPv0/SIM + + - - - -+EAP-PEAPv0/AKA + + - - - -+EAP-PEAPv0/PSK + - - - - -+EAP-PEAPv0/PAX + - - - - -+EAP-PEAPv0/SAKE + - - - - -+EAP-PEAPv0/GPSK + - - - - -+EAP-PEAPv1/MSCHAPv2 + + + - + + -+EAP-PEAPv1/GTC + + + - + -+EAP-PEAPv1/MD5 + - + - - -+EAP-PEAPv1/TLS + F - - + -+EAP-PEAPv1/SIM + + - - - -+EAP-PEAPv1/AKA + + - - - -+EAP-PEAPv1/PSK + - - - - -+EAP-PEAPv1/PAX + - - - - -+EAP-PEAPv1/SAKE + - - - - -+EAP-PEAPv1/GPSK + - - - - -+EAP-TTLS/CHAP + - + - + + -+EAP-TTLS/MSCHAP + - + - + + -+EAP-TTLS/MSCHAPv2 + + + - + + -+EAP-TTLS/PAP + - + - + + -+EAP-TTLS/EAP-MD5 + - - - - + -+EAP-TTLS/EAP-GTC + + - - - -+EAP-TTLS/EAP-MSCHAPv2 + + - - - -+EAP-TTLS/EAP-TLS + F - - - -+EAP-TTLS/EAP-SIM + + - - - -+EAP-TTLS/EAP-AKA + + - - - -+EAP-TTLS + TNC + - - - - -+EAP-SIM + + - - + -+EAP-AKA + + - - - -+EAP-PAX + - - - - -+EAP-SAKE + - - - - -+EAP-GPSK + - - - - -+EAP-FAST/MSCHAPv2(prov) + - F - F -+EAP-FAST/GTC(auth) + - + - + -+EAP-FAST/MSCHAPv2(aprov)+ - F - F -+EAP-FAST/GTC(aprov) + - F - F -+EAP-FAST/MD5(aprov) + - - - - -+EAP-FAST/TLS(aprov) + - - - - -+EAP-FAST/SIM(aprov) + - - - - -+EAP-FAST/AKA(aprov) + - - - - -+EAP-FAST/MSCHAPv2(auth) + - + - + -+EAP-FAST/MD5(auth) + - + - - -+EAP-FAST/TLS(auth) + - - - - -+EAP-FAST/SIM(auth) + - - - - -+EAP-FAST/AKA(auth) + - - - - -+EAP-FAST + TNC + - - - - -+EAP-IKEv2 + - - - - -+EAP-TNC + - - - - -+ -+1) EAP-TLS itself worked, but peer certificate validation failed at -+ least when using the internal TLS server (peer included incorrect -+ certificates in the chain?) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.c -new file mode 100644 -index 0000000000000..2919122b2fb51 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.c -@@ -0,0 +1,715 @@ -+/* -+ * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This is an example implementation of the EAP-SIM/AKA database/authentication -+ * gateway interface to HLR/AuC. It is expected to be replaced with an -+ * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or -+ * a local implementation of SIM triplet and AKA authentication data generator. -+ * -+ * hostapd will send SIM/AKA authentication queries over a UNIX domain socket -+ * to and external program, e.g., this hlr_auc_gw. This interface uses simple -+ * text-based format: -+ * -+ * EAP-SIM / GSM triplet query/response: -+ * SIM-REQ-AUTH -+ * SIM-RESP-AUTH Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3] -+ * SIM-RESP-AUTH FAILURE -+ * -+ * EAP-AKA / UMTS query/response: -+ * AKA-REQ-AUTH -+ * AKA-RESP-AUTH -+ * AKA-RESP-AUTH FAILURE -+ * -+ * EAP-AKA / UMTS AUTS (re-synchronization): -+ * AKA-AUTS -+ * -+ * IMSI and max_chal are sent as an ASCII string, -+ * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings. -+ * -+ * The example implementation here reads GSM authentication triplets from a -+ * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex -+ * strings. This is used to simulate an HLR/AuC. As such, it is not very useful -+ * for real life authentication, but it is useful both as an example -+ * implementation and for EAP-SIM testing. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "crypto/milenage.h" -+#include "crypto/random.h" -+ -+static const char *default_socket_path = "/tmp/hlr_auc_gw.sock"; -+static const char *socket_path; -+static int serv_sock = -1; -+ -+/* GSM triplets */ -+struct gsm_triplet { -+ struct gsm_triplet *next; -+ char imsi[20]; -+ u8 kc[8]; -+ u8 sres[4]; -+ u8 _rand[16]; -+}; -+ -+static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL; -+ -+/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */ -+struct milenage_parameters { -+ struct milenage_parameters *next; -+ char imsi[20]; -+ u8 ki[16]; -+ u8 opc[16]; -+ u8 amf[2]; -+ u8 sqn[6]; -+}; -+ -+static struct milenage_parameters *milenage_db = NULL; -+ -+#define EAP_SIM_MAX_CHAL 3 -+ -+#define EAP_AKA_RAND_LEN 16 -+#define EAP_AKA_AUTN_LEN 16 -+#define EAP_AKA_AUTS_LEN 14 -+#define EAP_AKA_RES_MAX_LEN 16 -+#define EAP_AKA_IK_LEN 16 -+#define EAP_AKA_CK_LEN 16 -+ -+ -+static int open_socket(const char *path) -+{ -+ struct sockaddr_un addr; -+ int s; -+ -+ s = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (s < 0) { -+ perror("socket(PF_UNIX)"); -+ return -1; -+ } -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path)); -+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind(PF_UNIX)"); -+ close(s); -+ return -1; -+ } -+ -+ return s; -+} -+ -+ -+static int read_gsm_triplets(const char *fname) -+{ -+ FILE *f; -+ char buf[200], *pos, *pos2; -+ struct gsm_triplet *g = NULL; -+ int line, ret = 0; -+ -+ if (fname == NULL) -+ return -1; -+ -+ f = fopen(fname, "r"); -+ if (f == NULL) { -+ printf("Could not open GSM tripler data file '%s'\n", fname); -+ return -1; -+ } -+ -+ line = 0; -+ while (fgets(buf, sizeof(buf), f)) { -+ line++; -+ -+ /* Parse IMSI:Kc:SRES:RAND */ -+ buf[sizeof(buf) - 1] = '\0'; -+ if (buf[0] == '#') -+ continue; -+ pos = buf; -+ while (*pos != '\0' && *pos != '\n') -+ pos++; -+ if (*pos == '\n') -+ *pos = '\0'; -+ pos = buf; -+ if (*pos == '\0') -+ continue; -+ -+ g = os_zalloc(sizeof(*g)); -+ if (g == NULL) { -+ ret = -1; -+ break; -+ } -+ -+ /* IMSI */ -+ pos2 = strchr(pos, ':'); -+ if (pos2 == NULL) { -+ printf("%s:%d - Invalid IMSI (%s)\n", -+ fname, line, pos); -+ ret = -1; -+ break; -+ } -+ *pos2 = '\0'; -+ if (strlen(pos) >= sizeof(g->imsi)) { -+ printf("%s:%d - Too long IMSI (%s)\n", -+ fname, line, pos); -+ ret = -1; -+ break; -+ } -+ os_strlcpy(g->imsi, pos, sizeof(g->imsi)); -+ pos = pos2 + 1; -+ -+ /* Kc */ -+ pos2 = strchr(pos, ':'); -+ if (pos2 == NULL) { -+ printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ *pos2 = '\0'; -+ if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) { -+ printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ pos = pos2 + 1; -+ -+ /* SRES */ -+ pos2 = strchr(pos, ':'); -+ if (pos2 == NULL) { -+ printf("%s:%d - Invalid SRES (%s)\n", fname, line, -+ pos); -+ ret = -1; -+ break; -+ } -+ *pos2 = '\0'; -+ if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) { -+ printf("%s:%d - Invalid SRES (%s)\n", fname, line, -+ pos); -+ ret = -1; -+ break; -+ } -+ pos = pos2 + 1; -+ -+ /* RAND */ -+ pos2 = strchr(pos, ':'); -+ if (pos2) -+ *pos2 = '\0'; -+ if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) { -+ printf("%s:%d - Invalid RAND (%s)\n", fname, line, -+ pos); -+ ret = -1; -+ break; -+ } -+ pos = pos2 + 1; -+ -+ g->next = gsm_db; -+ gsm_db = g; -+ g = NULL; -+ } -+ free(g); -+ -+ fclose(f); -+ -+ return ret; -+} -+ -+ -+static struct gsm_triplet * get_gsm_triplet(const char *imsi) -+{ -+ struct gsm_triplet *g = gsm_db_pos; -+ -+ while (g) { -+ if (strcmp(g->imsi, imsi) == 0) { -+ gsm_db_pos = g->next; -+ return g; -+ } -+ g = g->next; -+ } -+ -+ g = gsm_db; -+ while (g && g != gsm_db_pos) { -+ if (strcmp(g->imsi, imsi) == 0) { -+ gsm_db_pos = g->next; -+ return g; -+ } -+ g = g->next; -+ } -+ -+ return NULL; -+} -+ -+ -+static int read_milenage(const char *fname) -+{ -+ FILE *f; -+ char buf[200], *pos, *pos2; -+ struct milenage_parameters *m = NULL; -+ int line, ret = 0; -+ -+ if (fname == NULL) -+ return -1; -+ -+ f = fopen(fname, "r"); -+ if (f == NULL) { -+ printf("Could not open Milenage data file '%s'\n", fname); -+ return -1; -+ } -+ -+ line = 0; -+ while (fgets(buf, sizeof(buf), f)) { -+ line++; -+ -+ /* Parse IMSI Ki OPc AMF SQN */ -+ buf[sizeof(buf) - 1] = '\0'; -+ if (buf[0] == '#') -+ continue; -+ pos = buf; -+ while (*pos != '\0' && *pos != '\n') -+ pos++; -+ if (*pos == '\n') -+ *pos = '\0'; -+ pos = buf; -+ if (*pos == '\0') -+ continue; -+ -+ m = os_zalloc(sizeof(*m)); -+ if (m == NULL) { -+ ret = -1; -+ break; -+ } -+ -+ /* IMSI */ -+ pos2 = strchr(pos, ' '); -+ if (pos2 == NULL) { -+ printf("%s:%d - Invalid IMSI (%s)\n", -+ fname, line, pos); -+ ret = -1; -+ break; -+ } -+ *pos2 = '\0'; -+ if (strlen(pos) >= sizeof(m->imsi)) { -+ printf("%s:%d - Too long IMSI (%s)\n", -+ fname, line, pos); -+ ret = -1; -+ break; -+ } -+ os_strlcpy(m->imsi, pos, sizeof(m->imsi)); -+ pos = pos2 + 1; -+ -+ /* Ki */ -+ pos2 = strchr(pos, ' '); -+ if (pos2 == NULL) { -+ printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ *pos2 = '\0'; -+ if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) { -+ printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ pos = pos2 + 1; -+ -+ /* OPc */ -+ pos2 = strchr(pos, ' '); -+ if (pos2 == NULL) { -+ printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ *pos2 = '\0'; -+ if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) { -+ printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ pos = pos2 + 1; -+ -+ /* AMF */ -+ pos2 = strchr(pos, ' '); -+ if (pos2 == NULL) { -+ printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ *pos2 = '\0'; -+ if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) { -+ printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ pos = pos2 + 1; -+ -+ /* SQN */ -+ pos2 = strchr(pos, ' '); -+ if (pos2) -+ *pos2 = '\0'; -+ if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) { -+ printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos); -+ ret = -1; -+ break; -+ } -+ pos = pos2 + 1; -+ -+ m->next = milenage_db; -+ milenage_db = m; -+ m = NULL; -+ } -+ free(m); -+ -+ fclose(f); -+ -+ return ret; -+} -+ -+ -+static struct milenage_parameters * get_milenage(const char *imsi) -+{ -+ struct milenage_parameters *m = milenage_db; -+ -+ while (m) { -+ if (strcmp(m->imsi, imsi) == 0) -+ break; -+ m = m->next; -+ } -+ -+ return m; -+} -+ -+ -+static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, -+ char *imsi) -+{ -+ int count, max_chal, ret; -+ char *pos; -+ char reply[1000], *rpos, *rend; -+ struct milenage_parameters *m; -+ struct gsm_triplet *g; -+ -+ reply[0] = '\0'; -+ -+ pos = strchr(imsi, ' '); -+ if (pos) { -+ *pos++ = '\0'; -+ max_chal = atoi(pos); -+ if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL) -+ max_chal = EAP_SIM_MAX_CHAL; -+ } else -+ max_chal = EAP_SIM_MAX_CHAL; -+ -+ rend = &reply[sizeof(reply)]; -+ rpos = reply; -+ ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi); -+ if (ret < 0 || ret >= rend - rpos) -+ return; -+ rpos += ret; -+ -+ m = get_milenage(imsi); -+ if (m) { -+ u8 _rand[16], sres[4], kc[8]; -+ for (count = 0; count < max_chal; count++) { -+ if (random_get_bytes(_rand, 16) < 0) -+ return; -+ gsm_milenage(m->opc, m->ki, _rand, sres, kc); -+ *rpos++ = ' '; -+ rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8); -+ *rpos++ = ':'; -+ rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4); -+ *rpos++ = ':'; -+ rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16); -+ } -+ *rpos = '\0'; -+ goto send; -+ } -+ -+ count = 0; -+ while (count < max_chal && (g = get_gsm_triplet(imsi))) { -+ if (strcmp(g->imsi, imsi) != 0) -+ continue; -+ -+ if (rpos < rend) -+ *rpos++ = ' '; -+ rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8); -+ if (rpos < rend) -+ *rpos++ = ':'; -+ rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4); -+ if (rpos < rend) -+ *rpos++ = ':'; -+ rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16); -+ count++; -+ } -+ -+ if (count == 0) { -+ printf("No GSM triplets found for %s\n", imsi); -+ ret = snprintf(rpos, rend - rpos, " FAILURE"); -+ if (ret < 0 || ret >= rend - rpos) -+ return; -+ rpos += ret; -+ } -+ -+send: -+ printf("Send: %s\n", reply); -+ if (sendto(s, reply, rpos - reply, 0, -+ (struct sockaddr *) from, fromlen) < 0) -+ perror("send"); -+} -+ -+ -+static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen, -+ char *imsi) -+{ -+ /* AKA-RESP-AUTH */ -+ char reply[1000], *pos, *end; -+ u8 _rand[EAP_AKA_RAND_LEN]; -+ u8 autn[EAP_AKA_AUTN_LEN]; -+ u8 ik[EAP_AKA_IK_LEN]; -+ u8 ck[EAP_AKA_CK_LEN]; -+ u8 res[EAP_AKA_RES_MAX_LEN]; -+ size_t res_len; -+ int ret; -+ struct milenage_parameters *m; -+ -+ m = get_milenage(imsi); -+ if (m) { -+ if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0) -+ return; -+ res_len = EAP_AKA_RES_MAX_LEN; -+ inc_byte_array(m->sqn, 6); -+ printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n", -+ m->sqn[0], m->sqn[1], m->sqn[2], -+ m->sqn[3], m->sqn[4], m->sqn[5]); -+ milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand, -+ autn, ik, ck, res, &res_len); -+ } else { -+ printf("Unknown IMSI: %s\n", imsi); -+#ifdef AKA_USE_FIXED_TEST_VALUES -+ printf("Using fixed test values for AKA\n"); -+ memset(_rand, '0', EAP_AKA_RAND_LEN); -+ memset(autn, '1', EAP_AKA_AUTN_LEN); -+ memset(ik, '3', EAP_AKA_IK_LEN); -+ memset(ck, '4', EAP_AKA_CK_LEN); -+ memset(res, '2', EAP_AKA_RES_MAX_LEN); -+ res_len = EAP_AKA_RES_MAX_LEN; -+#else /* AKA_USE_FIXED_TEST_VALUES */ -+ return; -+#endif /* AKA_USE_FIXED_TEST_VALUES */ -+ } -+ -+ pos = reply; -+ end = &reply[sizeof(reply)]; -+ ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN); -+ *pos++ = ' '; -+ pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN); -+ *pos++ = ' '; -+ pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN); -+ *pos++ = ' '; -+ pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN); -+ *pos++ = ' '; -+ pos += wpa_snprintf_hex(pos, end - pos, res, res_len); -+ -+ printf("Send: %s\n", reply); -+ -+ if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from, -+ fromlen) < 0) -+ perror("send"); -+} -+ -+ -+static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen, -+ char *imsi) -+{ -+ char *auts, *__rand; -+ u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6]; -+ struct milenage_parameters *m; -+ -+ /* AKA-AUTS */ -+ -+ auts = strchr(imsi, ' '); -+ if (auts == NULL) -+ return; -+ *auts++ = '\0'; -+ -+ __rand = strchr(auts, ' '); -+ if (__rand == NULL) -+ return; -+ *__rand++ = '\0'; -+ -+ printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand); -+ if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) || -+ hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) { -+ printf("Could not parse AUTS/RAND\n"); -+ return; -+ } -+ -+ m = get_milenage(imsi); -+ if (m == NULL) { -+ printf("Unknown IMSI: %s\n", imsi); -+ return; -+ } -+ -+ if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) { -+ printf("AKA-AUTS: Incorrect MAC-S\n"); -+ } else { -+ memcpy(m->sqn, sqn, 6); -+ printf("AKA-AUTS: Re-synchronized: " -+ "SQN=%02x%02x%02x%02x%02x%02x\n", -+ sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]); -+ } -+} -+ -+ -+static int process(int s) -+{ -+ char buf[1000]; -+ struct sockaddr_un from; -+ socklen_t fromlen; -+ ssize_t res; -+ -+ fromlen = sizeof(from); -+ res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from, -+ &fromlen); -+ if (res < 0) { -+ perror("recvfrom"); -+ return -1; -+ } -+ -+ if (res == 0) -+ return 0; -+ -+ if ((size_t) res >= sizeof(buf)) -+ res = sizeof(buf) - 1; -+ buf[res] = '\0'; -+ -+ printf("Received: %s\n", buf); -+ -+ if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0) -+ sim_req_auth(s, &from, fromlen, buf + 13); -+ else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0) -+ aka_req_auth(s, &from, fromlen, buf + 13); -+ else if (strncmp(buf, "AKA-AUTS ", 9) == 0) -+ aka_auts(s, &from, fromlen, buf + 9); -+ else -+ printf("Unknown request: %s\n", buf); -+ -+ return 0; -+} -+ -+ -+static void cleanup(void) -+{ -+ struct gsm_triplet *g, *gprev; -+ struct milenage_parameters *m, *prev; -+ -+ g = gsm_db; -+ while (g) { -+ gprev = g; -+ g = g->next; -+ free(gprev); -+ } -+ -+ m = milenage_db; -+ while (m) { -+ prev = m; -+ m = m->next; -+ free(prev); -+ } -+ -+ close(serv_sock); -+ unlink(socket_path); -+} -+ -+ -+static void handle_term(int sig) -+{ -+ printf("Signal %d - terminate\n", sig); -+ exit(0); -+} -+ -+ -+static void usage(void) -+{ -+ printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA " -+ "database/authenticator\n" -+ "Copyright (c) 2005-2007, Jouni Malinen \n" -+ "\n" -+ "usage:\n" -+ "hlr_auc_gw [-h] [-s] [-g] " -+ "[-m]\n" -+ "\n" -+ "options:\n" -+ " -h = show this usage help\n" -+ " -s = path for UNIX domain socket\n" -+ " (default: %s)\n" -+ " -g = path for GSM authentication triplets\n" -+ " -m = path for Milenage keys\n", -+ default_socket_path); -+} -+ -+ -+int main(int argc, char *argv[]) -+{ -+ int c; -+ char *milenage_file = NULL; -+ char *gsm_triplet_file = NULL; -+ -+ socket_path = default_socket_path; -+ -+ for (;;) { -+ c = getopt(argc, argv, "g:hm:s:"); -+ if (c < 0) -+ break; -+ switch (c) { -+ case 'g': -+ gsm_triplet_file = optarg; -+ break; -+ case 'h': -+ usage(); -+ return 0; -+ case 'm': -+ milenage_file = optarg; -+ break; -+ case 's': -+ socket_path = optarg; -+ break; -+ default: -+ usage(); -+ return -1; -+ } -+ } -+ -+ if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0) -+ return -1; -+ -+ if (milenage_file && read_milenage(milenage_file) < 0) -+ return -1; -+ -+ serv_sock = open_socket(socket_path); -+ if (serv_sock < 0) -+ return -1; -+ -+ printf("Listening for requests on %s\n", socket_path); -+ -+ atexit(cleanup); -+ signal(SIGTERM, handle_term); -+ signal(SIGINT, handle_term); -+ -+ for (;;) -+ process(serv_sock); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.milenage_db b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.milenage_db -new file mode 100644 -index 0000000000000..ecd06d72096d1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hlr_auc_gw.milenage_db -@@ -0,0 +1,13 @@ -+# Parameters for Milenage (Example algorithms for AKA). -+# The example Ki, OPc, and AMF values here are from 3GPP TS 35.208 v6.0.0 -+# 4.3.20 Test Set 20. SQN is the last used SQN value. -+# These values can be used for both UMTS (EAP-AKA) and GSM (EAP-SIM) -+# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but -+# dummy values will need to be included in this file. -+ -+# IMSI Ki OPc AMF SQN -+232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 -+ -+# These values are from Test Set 19 which has the AMF separation bit set to 1 -+# and as such, is suitable for EAP-AKA' test. -+555444333222111 5122250214c33e723a5dd523fc145fc0 981d464c7c52eb6e5036234984ad0bcf c3ab 16f3b3f70fc1 -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.8 b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.8 -new file mode 100644 -index 0000000000000..b4456bbcf3e65 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.8 -@@ -0,0 +1,59 @@ -+.TH HOSTAPD 8 "April 7, 2005" hostapd hostapd -+.SH NAME -+hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator -+.SH SYNOPSIS -+.B hostapd -+[\-hdBKtv] [\-P ] -+.SH DESCRIPTION -+This manual page documents briefly the -+.B hostapd -+daemon. -+.PP -+.B hostapd -+is a user space daemon for access point and authentication servers. -+It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server. -+The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211). -+ -+.B hostapd -+is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication. -+.B hostapd -+supports separate frontend programs and an example text-based frontend, -+.BR hostapd_cli , -+is included with -+.BR hostapd . -+.SH OPTIONS -+A summary of options is included below. -+For a complete description, run -+.BR hostapd -+from the command line. -+.TP -+.B \-h -+Show usage. -+.TP -+.B \-d -+Show more debug messages. -+.TP -+.B \-dd -+Show even more debug messages. -+.TP -+.B \-B -+Run daemon in the background. -+.TP -+.B \-P -+Path to PID file. -+.TP -+.B \-K -+Include key data in debug messages. -+.TP -+.B \-t -+Include timestamps in some debug messages. -+.TP -+.B \-v -+Show hostapd version. -+.SH SEE ALSO -+.BR hostapd_cli (1). -+.SH AUTHOR -+hostapd was written by Jouni Malinen . -+.PP -+This manual page was written by Faidon Liambotis , -+for the Debian project (but may be used by others). -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.accept b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.accept -new file mode 100644 -index 0000000000000..2d2a0a27efdc8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.accept -@@ -0,0 +1,6 @@ -+# List of MAC addresses that are allowed to authenticate (IEEE 802.11) -+# with the AP. Optional VLAN ID can be assigned for clients based on the -+# MAC address if dynamic VLANs (hostapd.conf dynamic_vlan option) are used. -+00:11:22:33:44:55 -+00:66:77:88:99:aa -+00:00:22:33:44:55 1 -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.conf b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.conf -new file mode 100644 -index 0000000000000..6d7263afd8a7b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.conf -@@ -0,0 +1,1040 @@ -+##### hostapd configuration file ############################################## -+# Empty lines and lines starting with # are ignored -+ -+# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for -+# management frames); ath0 for madwifi -+interface=wlan0 -+ -+# In case of madwifi, atheros, and nl80211 driver interfaces, an additional -+# configuration parameter, bridge, may be used to notify hostapd if the -+# interface is included in a bridge. This parameter is not used with Host AP -+# driver. If the bridge parameter is not set, the drivers will automatically -+# figure out the bridge interface (assuming sysfs is enabled and mounted to -+# /sys) and this parameter may not be needed. -+# -+# For nl80211, this parameter can be used to request the AP interface to be -+# added to the bridge automatically (brctl may refuse to do this before hostapd -+# has been started to change the interface mode). If needed, the bridge -+# interface is also created. -+#bridge=br0 -+ -+# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd); -+# default: hostap). nl80211 is used with all Linux mac80211 drivers. -+# Use driver=none if building hostapd as a standalone RADIUS server that does -+# not control any wireless/wired driver. -+# driver=hostap -+ -+# hostapd event logger configuration -+# -+# Two output method: syslog and stdout (only usable if not forking to -+# background). -+# -+# Module bitfield (ORed bitfield of modules that will be logged; -1 = all -+# modules): -+# bit 0 (1) = IEEE 802.11 -+# bit 1 (2) = IEEE 802.1X -+# bit 2 (4) = RADIUS -+# bit 3 (8) = WPA -+# bit 4 (16) = driver interface -+# bit 5 (32) = IAPP -+# bit 6 (64) = MLME -+# -+# Levels (minimum value for logged events): -+# 0 = verbose debugging -+# 1 = debugging -+# 2 = informational messages -+# 3 = notification -+# 4 = warning -+# -+logger_syslog=-1 -+logger_syslog_level=2 -+logger_stdout=-1 -+logger_stdout_level=2 -+ -+# Dump file for state information (on SIGUSR1) -+dump_file=/tmp/hostapd.dump -+ -+# Interface for separate control program. If this is specified, hostapd -+# will create this directory and a UNIX domain socket for listening to requests -+# from external programs (CLI/GUI, etc.) for status information and -+# configuration. The socket file will be named based on the interface name, so -+# multiple hostapd processes/interfaces can be run at the same time if more -+# than one interface is used. -+# /var/run/hostapd is the recommended directory for sockets and by default, -+# hostapd_cli will use it when trying to connect with hostapd. -+ctrl_interface=/var/run/hostapd -+ -+# Access control for the control interface can be configured by setting the -+# directory to allow only members of a group to use sockets. This way, it is -+# possible to run hostapd as root (since it needs to change network -+# configuration and open raw sockets) and still allow GUI/CLI components to be -+# run as non-root users. However, since the control interface can be used to -+# change the network configuration, this access needs to be protected in many -+# cases. By default, hostapd is configured to use gid 0 (root). If you -+# want to allow non-root users to use the contron interface, add a new group -+# and change this value to match with that group. Add users that should have -+# control interface access to this group. -+# -+# This variable can be a group name or gid. -+#ctrl_interface_group=wheel -+ctrl_interface_group=0 -+ -+ -+##### IEEE 802.11 related configuration ####################################### -+ -+# SSID to be used in IEEE 802.11 management frames -+ssid=test -+ -+# Country code (ISO/IEC 3166-1). Used to set regulatory domain. -+# Set as needed to indicate country in which device is operating. -+# This can limit available channels and transmit power. -+#country_code=US -+ -+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed -+# channels and transmit power levels based on the regulatory limits. The -+# country_code setting must be configured with the correct country for -+# IEEE 802.11d functions. -+# (default: 0 = disabled) -+#ieee80211d=1 -+ -+# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g, -+# Default: IEEE 802.11b -+hw_mode=a -+ -+# Channel number (IEEE 802.11) -+# (default: 0, i.e., not set) -+# Please note that some drivers (e.g., madwifi) do not use this value from -+# hostapd and the channel will need to be configuration separately with -+# iwconfig. -+channel=60 -+ -+# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) -+beacon_int=100 -+ -+# DTIM (delivery trafic information message) period (range 1..255): -+# number of beacons between DTIMs (1 = every beacon includes DTIM element) -+# (default: 2) -+dtim_period=2 -+ -+# Maximum number of stations allowed in station table. New stations will be -+# rejected after the station table is full. IEEE 802.11 has a limit of 2007 -+# different association IDs, so this number should not be larger than that. -+# (default: 2007) -+max_num_sta=255 -+ -+# RTS/CTS threshold; 2347 = disabled (default); range 0..2347 -+# If this field is not included in hostapd.conf, hostapd will not control -+# RTS threshold and 'iwconfig wlan# rts ' can be used to set it. -+rts_threshold=2347 -+ -+# Fragmentation threshold; 2346 = disabled (default); range 256..2346 -+# If this field is not included in hostapd.conf, hostapd will not control -+# fragmentation threshold and 'iwconfig wlan# frag ' can be used to set -+# it. -+fragm_threshold=2346 -+ -+# Rate configuration -+# Default is to enable all rates supported by the hardware. This configuration -+# item allows this list be filtered so that only the listed rates will be left -+# in the list. If the list is empty, all rates are used. This list can have -+# entries that are not in the list of rates the hardware supports (such entries -+# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110. -+# If this item is present, at least one rate have to be matching with the rates -+# hardware supports. -+# default: use the most common supported rate setting for the selected -+# hw_mode (i.e., this line can be removed from configuration file in most -+# cases) -+#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540 -+ -+# Basic rate set configuration -+# List of rates (in 100 kbps) that are included in the basic rate set. -+# If this item is not included, usually reasonable default set is used. -+#basic_rates=10 20 -+#basic_rates=10 20 55 110 -+#basic_rates=60 120 240 -+ -+# Short Preamble -+# This parameter can be used to enable optional use of short preamble for -+# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance. -+# This applies only to IEEE 802.11b-compatible networks and this should only be -+# enabled if the local hardware supports use of short preamble. If any of the -+# associated STAs do not support short preamble, use of short preamble will be -+# disabled (and enabled when such STAs disassociate) dynamically. -+# 0 = do not allow use of short preamble (default) -+# 1 = allow use of short preamble -+#preamble=1 -+ -+# Station MAC address -based authentication -+# Please note that this kind of access control requires a driver that uses -+# hostapd to take care of management frame processing and as such, this can be -+# used with driver=hostap or driver=nl80211, but not with driver=madwifi. -+# 0 = accept unless in deny list -+# 1 = deny unless in accept list -+# 2 = use external RADIUS server (accept/deny lists are searched first) -+macaddr_acl=0 -+ -+# Accept/deny lists are read from separate files (containing list of -+# MAC addresses, one per line). Use absolute path name to make sure that the -+# files can be read on SIGHUP configuration reloads. -+#accept_mac_file=/etc/hostapd.accept -+#deny_mac_file=/etc/hostapd.deny -+ -+# IEEE 802.11 specifies two authentication algorithms. hostapd can be -+# configured to allow both of these or only one. Open system authentication -+# should be used with IEEE 802.1X. -+# Bit fields of allowed authentication algorithms: -+# bit 0 = Open System Authentication -+# bit 1 = Shared Key Authentication (requires WEP) -+auth_algs=3 -+ -+# Send empty SSID in beacons and ignore probe request frames that do not -+# specify full SSID, i.e., require stations to know SSID. -+# default: disabled (0) -+# 1 = send empty (length=0) SSID in beacon and ignore probe request for -+# broadcast SSID -+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required -+# with some clients that do not support empty SSID) and ignore probe -+# requests for broadcast SSID -+ignore_broadcast_ssid=0 -+ -+# TX queue parameters (EDCF / bursting) -+# tx_queue__ -+# queues: data0, data1, data2, data3, after_beacon, beacon -+# (data0 is the highest priority queue) -+# parameters: -+# aifs: AIFS (default 2) -+# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023) -+# cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin -+# burst: maximum length (in milliseconds with precision of up to 0.1 ms) for -+# bursting -+# -+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): -+# These parameters are used by the access point when transmitting frames -+# to the clients. -+# -+# Low priority / AC_BK = background -+#tx_queue_data3_aifs=7 -+#tx_queue_data3_cwmin=15 -+#tx_queue_data3_cwmax=1023 -+#tx_queue_data3_burst=0 -+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0 -+# -+# Normal priority / AC_BE = best effort -+#tx_queue_data2_aifs=3 -+#tx_queue_data2_cwmin=15 -+#tx_queue_data2_cwmax=63 -+#tx_queue_data2_burst=0 -+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0 -+# -+# High priority / AC_VI = video -+#tx_queue_data1_aifs=1 -+#tx_queue_data1_cwmin=7 -+#tx_queue_data1_cwmax=15 -+#tx_queue_data1_burst=3.0 -+# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0 -+# -+# Highest priority / AC_VO = voice -+#tx_queue_data0_aifs=1 -+#tx_queue_data0_cwmin=3 -+#tx_queue_data0_cwmax=7 -+#tx_queue_data0_burst=1.5 -+# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3 -+ -+# 802.1D Tag (= UP) to AC mappings -+# WMM specifies following mapping of data frames to different ACs. This mapping -+# can be configured using Linux QoS/tc and sch_pktpri.o module. -+# 802.1D Tag 802.1D Designation Access Category WMM Designation -+# 1 BK AC_BK Background -+# 2 - AC_BK Background -+# 0 BE AC_BE Best Effort -+# 3 EE AC_BE Best Effort -+# 4 CL AC_VI Video -+# 5 VI AC_VI Video -+# 6 VO AC_VO Voice -+# 7 NC AC_VO Voice -+# Data frames with no priority information: AC_BE -+# Management frames: AC_VO -+# PS-Poll frames: AC_BE -+ -+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e): -+# for 802.11a or 802.11g networks -+# These parameters are sent to WMM clients when they associate. -+# The parameters will be used by WMM clients for frames transmitted to the -+# access point. -+# -+# note - txop_limit is in units of 32microseconds -+# note - acm is admission control mandatory flag. 0 = admission control not -+# required, 1 = mandatory -+# note - here cwMin and cmMax are in exponent form. the actual cw value used -+# will be (2^n)-1 where n is the value given here -+# -+wmm_enabled=1 -+# -+# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD] -+# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver) -+#uapsd_advertisement_enabled=1 -+# -+# Low priority / AC_BK = background -+wmm_ac_bk_cwmin=4 -+wmm_ac_bk_cwmax=10 -+wmm_ac_bk_aifs=7 -+wmm_ac_bk_txop_limit=0 -+wmm_ac_bk_acm=0 -+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10 -+# -+# Normal priority / AC_BE = best effort -+wmm_ac_be_aifs=3 -+wmm_ac_be_cwmin=4 -+wmm_ac_be_cwmax=10 -+wmm_ac_be_txop_limit=0 -+wmm_ac_be_acm=0 -+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7 -+# -+# High priority / AC_VI = video -+wmm_ac_vi_aifs=2 -+wmm_ac_vi_cwmin=3 -+wmm_ac_vi_cwmax=4 -+wmm_ac_vi_txop_limit=94 -+wmm_ac_vi_acm=0 -+# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188 -+# -+# Highest priority / AC_VO = voice -+wmm_ac_vo_aifs=2 -+wmm_ac_vo_cwmin=2 -+wmm_ac_vo_cwmax=3 -+wmm_ac_vo_txop_limit=47 -+wmm_ac_vo_acm=0 -+# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102 -+ -+# Static WEP key configuration -+# -+# The key number to use when transmitting. -+# It must be between 0 and 3, and the corresponding key must be set. -+# default: not set -+#wep_default_key=0 -+# The WEP keys to use. -+# A key may be a quoted string or unquoted hexadecimal digits. -+# The key length should be 5, 13, or 16 characters, or 10, 26, or 32 -+# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or -+# 128-bit (152-bit) WEP is used. -+# Only the default key must be supplied; the others are optional. -+# default: not set -+#wep_key0=123456789a -+#wep_key1="vwxyz" -+#wep_key2=0102030405060708090a0b0c0d -+#wep_key3=".2.4.6.8.0.23" -+ -+# Station inactivity limit -+# -+# If a station does not send anything in ap_max_inactivity seconds, an -+# empty data frame is sent to it in order to verify whether it is -+# still in range. If this frame is not ACKed, the station will be -+# disassociated and then deauthenticated. This feature is used to -+# clear station table of old entries when the STAs move out of the -+# range. -+# -+# The station can associate again with the AP if it is still in range; -+# this inactivity poll is just used as a nicer way of verifying -+# inactivity; i.e., client will not report broken connection because -+# disassociation frame is not sent immediately without first polling -+# the STA with a data frame. -+# default: 300 (i.e., 5 minutes) -+#ap_max_inactivity=300 -+ -+# Disassociate stations based on excessive transmission failures or other -+# indications of connection loss. This depends on the driver capabilities and -+# may not be available with all drivers. -+#disassoc_low_ack=1 -+ -+# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to -+# remain asleep). Default: 65535 (no limit apart from field size) -+#max_listen_interval=100 -+ -+# WDS (4-address frame) mode with per-station virtual interfaces -+# (only supported with driver=nl80211) -+# This mode allows associated stations to use 4-address frames to allow layer 2 -+# bridging to be used. -+#wds_sta=1 -+ -+# If bridge parameter is set, the WDS STA interface will be added to the same -+# bridge by default. This can be overridden with the wds_bridge parameter to -+# use a separate bridge. -+#wds_bridge=wds-br0 -+ -+# Client isolation can be used to prevent low-level bridging of frames between -+# associated stations in the BSS. By default, this bridging is allowed. -+#ap_isolate=1 -+ -+##### IEEE 802.11n related configuration ###################################### -+ -+# ieee80211n: Whether IEEE 802.11n (HT) is enabled -+# 0 = disabled (default) -+# 1 = enabled -+# Note: You will also need to enable WMM for full HT functionality. -+#ieee80211n=1 -+ -+# ht_capab: HT capabilities (list of flags) -+# LDPC coding capability: [LDPC] = supported -+# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary -+# channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz -+# with secondary channel below the primary channel -+# (20 MHz only if neither is set) -+# Note: There are limits on which channels can be used with HT40- and -+# HT40+. Following table shows the channels that may be available for -+# HT40- and HT40+ use per IEEE 802.11n Annex J: -+# freq HT40- HT40+ -+# 2.4 GHz 5-13 1-7 (1-9 in Europe/Japan) -+# 5 GHz 40,48,56,64 36,44,52,60 -+# (depending on the location, not all of these channels may be available -+# for use) -+# Please note that 40 MHz channels may switch their primary and secondary -+# channels if needed or creation of 40 MHz channel maybe rejected based -+# on overlapping BSSes. These changes are done automatically when hostapd -+# is setting up the 40 MHz channel. -+# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC] -+# (SMPS disabled if neither is set) -+# HT-greenfield: [GF] (disabled if not set) -+# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set) -+# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set) -+# Tx STBC: [TX-STBC] (disabled if not set) -+# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial -+# streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC -+# disabled if none of these set -+# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set) -+# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not -+# set) -+# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set) -+# PSMP support: [PSMP] (disabled if not set) -+# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set) -+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40] -+ -+# Require stations to support HT PHY (reject association if they do not) -+#require_ht=1 -+ -+##### IEEE 802.1X-2004 related configuration ################################## -+ -+# Require IEEE 802.1X authorization -+#ieee8021x=1 -+ -+# IEEE 802.1X/EAPOL version -+# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL -+# version 2. However, there are many client implementations that do not handle -+# the new version number correctly (they seem to drop the frames completely). -+# In order to make hostapd interoperate with these clients, the version number -+# can be set to the older version (1) with this configuration value. -+#eapol_version=2 -+ -+# Optional displayable message sent with EAP Request-Identity. The first \0 -+# in this string will be converted to ASCII-0 (nul). This can be used to -+# separate network info (comma separated list of attribute=value pairs); see, -+# e.g., RFC 4284. -+#eap_message=hello -+#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com -+ -+# WEP rekeying (disabled if key lengths are not set or are set to 0) -+# Key lengths for default/broadcast and individual/unicast keys: -+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits) -+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits) -+#wep_key_len_broadcast=5 -+#wep_key_len_unicast=5 -+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once) -+#wep_rekey_period=300 -+ -+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if -+# only broadcast keys are used) -+eapol_key_index_workaround=0 -+ -+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable -+# reauthentication). -+#eap_reauth_period=3600 -+ -+# Use PAE group address (01:80:c2:00:00:03) instead of individual target -+# address when sending EAPOL frames with driver=wired. This is the most common -+# mechanism used in wired authentication, but it also requires that the port -+# is only used by one station. -+#use_pae_group_addr=1 -+ -+##### Integrated EAP server ################################################### -+ -+# Optionally, hostapd can be configured to use an integrated EAP server -+# to process EAP authentication locally without need for an external RADIUS -+# server. This functionality can be used both as a local authentication server -+# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices. -+ -+# Use integrated EAP server instead of external RADIUS authentication -+# server. This is also needed if hostapd is configured to act as a RADIUS -+# authentication server. -+eap_server=0 -+ -+# Path for EAP server user database -+#eap_user_file=/etc/hostapd.eap_user -+ -+# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS -+#ca_cert=/etc/hostapd.ca.pem -+ -+# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS -+#server_cert=/etc/hostapd.server.pem -+ -+# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS -+# This may point to the same file as server_cert if both certificate and key -+# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be -+# used by commenting out server_cert and specifying the PFX file as the -+# private_key. -+#private_key=/etc/hostapd.server.prv -+ -+# Passphrase for private key -+#private_key_passwd=secret passphrase -+ -+# Enable CRL verification. -+# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a -+# valid CRL signed by the CA is required to be included in the ca_cert file. -+# This can be done by using PEM format for CA certificate and CRL and -+# concatenating these into one file. Whenever CRL changes, hostapd needs to be -+# restarted to take the new CRL into use. -+# 0 = do not verify CRLs (default) -+# 1 = check the CRL of the user certificate -+# 2 = check all CRLs in the certificate path -+#check_crl=1 -+ -+# dh_file: File path to DH/DSA parameters file (in PEM format) -+# This is an optional configuration file for setting parameters for an -+# ephemeral DH key exchange. In most cases, the default RSA authentication does -+# not use this configuration. However, it is possible setup RSA to use -+# ephemeral DH key exchange. In addition, ciphers with DSA keys always use -+# ephemeral DH keys. This can be used to achieve forward secrecy. If the file -+# is in DSA parameters format, it will be automatically converted into DH -+# params. This parameter is required if anonymous EAP-FAST is used. -+# You can generate DH parameters file with OpenSSL, e.g., -+# "openssl dhparam -out /etc/hostapd.dh.pem 1024" -+#dh_file=/etc/hostapd.dh.pem -+ -+# Fragment size for EAP methods -+#fragment_size=1400 -+ -+# Configuration data for EAP-SIM database/authentication gateway interface. -+# This is a text string in implementation specific format. The example -+# implementation in eap_sim_db.c uses this as the UNIX domain socket name for -+# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:" -+# prefix. -+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock -+ -+# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret, -+# random value. It is configured as a 16-octet value in hex format. It can be -+# generated, e.g., with the following command: -+# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' ' -+#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f -+ -+# EAP-FAST authority identity (A-ID) -+# A-ID indicates the identity of the authority that issues PACs. The A-ID -+# should be unique across all issuing servers. In theory, this is a variable -+# length field, but due to some existing implementations requiring A-ID to be -+# 16 octets in length, it is strongly recommended to use that length for the -+# field to provid interoperability with deployed peer implementations. This -+# field is configured in hex format. -+#eap_fast_a_id=101112131415161718191a1b1c1d1e1f -+ -+# EAP-FAST authority identifier information (A-ID-Info) -+# This is a user-friendly name for the A-ID. For example, the enterprise name -+# and server name in a human-readable format. This field is encoded as UTF-8. -+#eap_fast_a_id_info=test server -+ -+# Enable/disable different EAP-FAST provisioning modes: -+#0 = provisioning disabled -+#1 = only anonymous provisioning allowed -+#2 = only authenticated provisioning allowed -+#3 = both provisioning modes allowed (default) -+#eap_fast_prov=3 -+ -+# EAP-FAST PAC-Key lifetime in seconds (hard limit) -+#pac_key_lifetime=604800 -+ -+# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard -+# limit). The server will generate a new PAC-Key when this number of seconds -+# (or fewer) of the lifetime remains. -+#pac_key_refresh_time=86400 -+ -+# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND -+# (default: 0 = disabled). -+#eap_sim_aka_result_ind=1 -+ -+# Trusted Network Connect (TNC) -+# If enabled, TNC validation will be required before the peer is allowed to -+# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other -+# EAP method is enabled, the peer will be allowed to connect without TNC. -+#tnc=1 -+ -+ -+##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) ####################### -+ -+# Interface to be used for IAPP broadcast packets -+#iapp_interface=eth0 -+ -+ -+##### RADIUS client configuration ############################################# -+# for IEEE 802.1X with external Authentication Server, IEEE 802.11 -+# authentication with external ACL for MAC addresses, and accounting -+ -+# The own IP address of the access point (used as NAS-IP-Address) -+own_ip_addr=127.0.0.1 -+ -+# Optional NAS-Identifier string for RADIUS messages. When used, this should be -+# a unique to the NAS within the scope of the RADIUS server. For example, a -+# fully qualified domain name can be used here. -+# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and -+# 48 octets long. -+#nas_identifier=ap.example.com -+ -+# RADIUS authentication server -+#auth_server_addr=127.0.0.1 -+#auth_server_port=1812 -+#auth_server_shared_secret=secret -+ -+# RADIUS accounting server -+#acct_server_addr=127.0.0.1 -+#acct_server_port=1813 -+#acct_server_shared_secret=secret -+ -+# Secondary RADIUS servers; to be used if primary one does not reply to -+# RADIUS packets. These are optional and there can be more than one secondary -+# server listed. -+#auth_server_addr=127.0.0.2 -+#auth_server_port=1812 -+#auth_server_shared_secret=secret2 -+# -+#acct_server_addr=127.0.0.2 -+#acct_server_port=1813 -+#acct_server_shared_secret=secret2 -+ -+# Retry interval for trying to return to the primary RADIUS server (in -+# seconds). RADIUS client code will automatically try to use the next server -+# when the current server is not replying to requests. If this interval is set, -+# primary server will be retried after configured amount of time even if the -+# currently used secondary server is still working. -+#radius_retry_primary_interval=600 -+ -+ -+# Interim accounting update interval -+# If this is set (larger than 0) and acct_server is configured, hostapd will -+# send interim accounting updates every N seconds. Note: if set, this overrides -+# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this -+# value should not be configured in hostapd.conf, if RADIUS server is used to -+# control the interim interval. -+# This value should not be less 600 (10 minutes) and must not be less than -+# 60 (1 minute). -+#radius_acct_interim_interval=600 -+ -+# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN -+# is used for the stations. This information is parsed from following RADIUS -+# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN), -+# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value -+# VLANID as a string). vlan_file option below must be configured if dynamic -+# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be -+# used to set static client MAC address to VLAN ID mapping. -+# 0 = disabled (default) -+# 1 = option; use default interface if RADIUS server does not include VLAN ID -+# 2 = required; reject authentication if RADIUS server does not include VLAN ID -+#dynamic_vlan=0 -+ -+# VLAN interface list for dynamic VLAN mode is read from a separate text file. -+# This list is used to map VLAN ID from the RADIUS server to a network -+# interface. Each station is bound to one interface in the same way as with -+# multiple BSSIDs or SSIDs. Each line in this text file is defining a new -+# interface and the line must include VLAN ID and interface name separated by -+# white space (space or tab). -+#vlan_file=/etc/hostapd.vlan -+ -+# Interface where 802.1q tagged packets should appear when a RADIUS server is -+# used to determine which VLAN a station is on. hostapd creates a bridge for -+# each VLAN. Then hostapd adds a VLAN interface (associated with the interface -+# indicated by 'vlan_tagged_interface') and the appropriate wireless interface -+# to the bridge. -+#vlan_tagged_interface=eth0 -+ -+ -+##### RADIUS authentication server configuration ############################## -+ -+# hostapd can be used as a RADIUS authentication server for other hosts. This -+# requires that the integrated EAP server is also enabled and both -+# authentication services are sharing the same configuration. -+ -+# File name of the RADIUS clients configuration for the RADIUS server. If this -+# commented out, RADIUS server is disabled. -+#radius_server_clients=/etc/hostapd.radius_clients -+ -+# The UDP port number for the RADIUS authentication server -+#radius_server_auth_port=1812 -+ -+# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API) -+#radius_server_ipv6=1 -+ -+ -+##### WPA/IEEE 802.11i configuration ########################################## -+ -+# Enable WPA. Setting this variable configures the AP to require WPA (either -+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either -+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK. -+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys), -+# RADIUS authentication server must be configured, and WPA-EAP must be included -+# in wpa_key_mgmt. -+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0) -+# and/or WPA2 (full IEEE 802.11i/RSN): -+# bit0 = WPA -+# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled) -+#wpa=1 -+ -+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit -+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase -+# (8..63 characters) that will be converted to PSK. This conversion uses SSID -+# so the PSK changes when ASCII passphrase is used and the SSID is changed. -+# wpa_psk (dot11RSNAConfigPSKValue) -+# wpa_passphrase (dot11RSNAConfigPSKPassPhrase) -+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef -+#wpa_passphrase=secret passphrase -+ -+# Optionally, WPA PSKs can be read from a separate text file (containing list -+# of (PSK,MAC address) pairs. This allows more than one PSK to be configured. -+# Use absolute path name to make sure that the files can be read on SIGHUP -+# configuration reloads. -+#wpa_psk_file=/etc/hostapd.wpa_psk -+ -+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The -+# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be -+# added to enable SHA256-based stronger algorithms. -+# (dot11RSNAConfigAuthenticationSuitesTable) -+#wpa_key_mgmt=WPA-PSK WPA-EAP -+ -+# Set of accepted cipher suites (encryption algorithms) for pairwise keys -+# (unicast packets). This is a space separated list of algorithms: -+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] -+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] -+# Group cipher suite (encryption algorithm for broadcast and multicast frames) -+# is automatically selected based on this configuration. If only CCMP is -+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise, -+# TKIP will be used as the group cipher. -+# (dot11RSNAConfigPairwiseCiphersTable) -+# Pairwise cipher for WPA (v1) (default: TKIP) -+#wpa_pairwise=TKIP CCMP -+# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value) -+#rsn_pairwise=CCMP -+ -+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in -+# seconds. (dot11RSNAConfigGroupRekeyTime) -+#wpa_group_rekey=600 -+ -+# Rekey GTK when any STA that possesses the current GTK is leaving the BSS. -+# (dot11RSNAConfigGroupRekeyStrict) -+#wpa_strict_rekey=1 -+ -+# Time interval for rekeying GMK (master key used internally to generate GTKs -+# (in seconds). -+#wpa_gmk_rekey=86400 -+ -+# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of -+# PTK to mitigate some attacks against TKIP deficiencies. -+#wpa_ptk_rekey=600 -+ -+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up -+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN -+# authentication and key handshake before actually associating with a new AP. -+# (dot11RSNAPreauthenticationEnabled) -+#rsn_preauth=1 -+# -+# Space separated list of interfaces from which pre-authentication frames are -+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all -+# interface that are used for connections to other APs. This could include -+# wired interfaces and WDS links. The normal wireless data interface towards -+# associated stations (e.g., wlan0) should not be added, since -+# pre-authentication is only used with APs other than the currently associated -+# one. -+#rsn_preauth_interfaces=eth0 -+ -+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is -+# allowed. This is only used with RSN/WPA2. -+# 0 = disabled (default) -+# 1 = enabled -+#peerkey=1 -+ -+# ieee80211w: Whether management frame protection (MFP) is enabled -+# 0 = disabled (default) -+# 1 = optional -+# 2 = required -+#ieee80211w=0 -+ -+# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) -+# (maximum time to wait for a SA Query response) -+# dot11AssociationSAQueryMaximumTimeout, 1...4294967295 -+#assoc_sa_query_max_timeout=1000 -+ -+# Association SA Query retry timeout (in TU = 1.024 ms; for MFP) -+# (time between two subsequent SA Query requests) -+# dot11AssociationSAQueryRetryTimeout, 1...4294967295 -+#assoc_sa_query_retry_timeout=201 -+ -+ -+# okc: Opportunistic Key Caching (aka Proactive Key Caching) -+# Allow PMK cache to be shared opportunistically among configured interfaces -+# and BSSes (i.e., all configurations within a single hostapd process). -+# 0 = disabled (default) -+# 1 = enabled -+#okc=1 -+ -+ -+##### IEEE 802.11r configuration ############################################## -+ -+# Mobility Domain identifier (dot11FTMobilityDomainID, MDID) -+# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the -+# same SSID) between which a STA can use Fast BSS Transition. -+# 2-octet identifier as a hex string. -+#mobility_domain=a1b2 -+ -+# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID) -+# 1 to 48 octet identifier. -+# This is configured with nas_identifier (see RADIUS client section above). -+ -+# Default lifetime of the PMK-RO in minutes; range 1..65535 -+# (dot11FTR0KeyLifetime) -+#r0_key_lifetime=10000 -+ -+# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID) -+# 6-octet identifier as a hex string. -+#r1_key_holder=000102030405 -+ -+# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535) -+# (dot11FTReassociationDeadline) -+#reassociation_deadline=1000 -+ -+# List of R0KHs in the same Mobility Domain -+# format: <128-bit key as hex string> -+# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC -+# address when requesting PMK-R1 key from the R0KH that the STA used during the -+# Initial Mobility Domain Association. -+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f -+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff -+# And so on.. One line per R0KH. -+ -+# List of R1KHs in the same Mobility Domain -+# format: <128-bit key as hex string> -+# This list is used to map R1KH-ID to a destination MAC address when sending -+# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD -+# that can request PMK-R1 keys. -+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f -+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff -+# And so on.. One line per R1KH. -+ -+# Whether PMK-R1 push is enabled at R0KH -+# 0 = do not push PMK-R1 to all configured R1KHs (default) -+# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived -+#pmk_r1_push=1 -+ -+##### Neighbor table ########################################################## -+# Maximum number of entries kept in AP table (either for neigbor table or for -+# detecting Overlapping Legacy BSS Condition). The oldest entry will be -+# removed when adding a new entry that would make the list grow over this -+# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is -+# enabled, so this field should not be set to 0 when using IEEE 802.11g. -+# default: 255 -+#ap_table_max_size=255 -+ -+# Number of seconds of no frames received after which entries may be deleted -+# from the AP table. Since passive scanning is not usually performed frequently -+# this should not be set to very small value. In addition, there is no -+# guarantee that every scan cycle will receive beacon frames from the -+# neighboring APs. -+# default: 60 -+#ap_table_expiration_time=3600 -+ -+ -+##### Wi-Fi Protected Setup (WPS) ############################################# -+ -+# WPS state -+# 0 = WPS disabled (default) -+# 1 = WPS enabled, not configured -+# 2 = WPS enabled, configured -+#wps_state=2 -+ -+# AP can be configured into a locked state where new WPS Registrar are not -+# accepted, but previously authorized Registrars (including the internal one) -+# can continue to add new Enrollees. -+#ap_setup_locked=1 -+ -+# Universally Unique IDentifier (UUID; see RFC 4122) of the device -+# This value is used as the UUID for the internal WPS Registrar. If the AP -+# is also using UPnP, this value should be set to the device's UPnP UUID. -+# If not configured, UUID will be generated based on the local MAC address. -+#uuid=12345678-9abc-def0-1234-56789abcdef0 -+ -+# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs -+# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the -+# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of -+# per-device PSKs is recommended as the more secure option (i.e., make sure to -+# set wpa_psk_file when using WPS with WPA-PSK). -+ -+# When an Enrollee requests access to the network with PIN method, the Enrollee -+# PIN will need to be entered for the Registrar. PIN request notifications are -+# sent to hostapd ctrl_iface monitor. In addition, they can be written to a -+# text file that could be used, e.g., to populate the AP administration UI with -+# pending PIN requests. If the following variable is set, the PIN requests will -+# be written to the configured file. -+#wps_pin_requests=/var/run/hostapd_wps_pin_requests -+ -+# Device Name -+# User-friendly description of device; up to 32 octets encoded in UTF-8 -+#device_name=Wireless AP -+ -+# Manufacturer -+# The manufacturer of the device (up to 64 ASCII characters) -+#manufacturer=Company -+ -+# Model Name -+# Model of the device (up to 32 ASCII characters) -+#model_name=WAP -+ -+# Model Number -+# Additional device description (up to 32 ASCII characters) -+#model_number=123 -+ -+# Serial Number -+# Serial number of the device (up to 32 characters) -+#serial_number=12345 -+ -+# Primary Device Type -+# Used format: -- -+# categ = Category as an integer value -+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for -+# default WPS OUI -+# subcateg = OUI-specific Sub Category as an integer value -+# Examples: -+# 1-0050F204-1 (Computer / PC) -+# 1-0050F204-2 (Computer / Server) -+# 5-0050F204-1 (Storage / NAS) -+# 6-0050F204-1 (Network Infrastructure / AP) -+#device_type=6-0050F204-1 -+ -+# OS Version -+# 4-octet operating system version number (hex string) -+#os_version=01020300 -+ -+# Config Methods -+# List of the supported configuration methods -+# Available methods: usba ethernet label display ext_nfc_token int_nfc_token -+# nfc_interface push_button keypad virtual_display physical_display -+# virtual_push_button physical_push_button -+#config_methods=label virtual_display virtual_push_button keypad -+ -+# Static access point PIN for initial configuration and adding Registrars -+# If not set, hostapd will not allow external WPS Registrars to control the -+# access point. The AP PIN can also be set at runtime with hostapd_cli -+# wps_ap_pin command. Use of temporary (enabled by user action) and random -+# AP PIN is much more secure than configuring a static AP PIN here. As such, -+# use of the ap_pin parameter is not recommended if the AP device has means for -+# displaying a random PIN. -+#ap_pin=12345670 -+ -+# Skip building of automatic WPS credential -+# This can be used to allow the automatically generated Credential attribute to -+# be replaced with pre-configured Credential(s). -+#skip_cred_build=1 -+ -+# Additional Credential attribute(s) -+# This option can be used to add pre-configured Credential attributes into M8 -+# message when acting as a Registrar. If skip_cred_build=1, this data will also -+# be able to override the Credential attribute that would have otherwise been -+# automatically generated based on network configuration. This configuration -+# option points to an external file that much contain the WPS Credential -+# attribute(s) as binary data. -+#extra_cred=hostapd.cred -+ -+# Credential processing -+# 0 = process received credentials internally (default) -+# 1 = do not process received credentials; just pass them over ctrl_iface to -+# external program(s) -+# 2 = process received credentials internally and pass them over ctrl_iface -+# to external program(s) -+# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and -+# extra_cred be used to provide the Credential data for Enrollees. -+# -+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file -+# both for Credential processing and for marking AP Setup Locked based on -+# validation failures of AP PIN. An external program is responsible on updating -+# the configuration appropriately in this case. -+#wps_cred_processing=0 -+ -+# AP Settings Attributes for M7 -+# By default, hostapd generates the AP Settings Attributes for M7 based on the -+# current configuration. It is possible to override this by providing a file -+# with pre-configured attributes. This is similar to extra_cred file format, -+# but the AP Settings attributes are not encapsulated in a Credential -+# attribute. -+#ap_settings=hostapd.ap_settings -+ -+# WPS UPnP interface -+# If set, support for external Registrars is enabled. -+#upnp_iface=br0 -+ -+# Friendly Name (required for UPnP) -+# Short description for end use. Should be less than 64 characters. -+#friendly_name=WPS Access Point -+ -+# Manufacturer URL (optional for UPnP) -+#manufacturer_url=http://www.example.com/ -+ -+# Model Description (recommended for UPnP) -+# Long description for end user. Should be less than 128 characters. -+#model_description=Wireless Access Point -+ -+# Model URL (optional for UPnP) -+#model_url=http://www.example.com/model/ -+ -+# Universal Product Code (optional for UPnP) -+# 12-digit, all-numeric code that identifies the consumer package. -+#upc=123456789012 -+ -+##### Wi-Fi Direct (P2P) ###################################################### -+ -+# Enable P2P Device management -+#manage_p2p=1 -+ -+# Allow cross connection -+#allow_cross_connection=1 -+ -+#### TDLS (IEEE 802.11z-2010) ################################################# -+ -+# Prohibit use of TDLS in this BSS -+#tdls_prohibit=1 -+ -+# Prohibit use of TDLS Channel Switching in this BSS -+#tdls_prohibit_chan_switch=1 -+ -+##### Multiple BSSID support ################################################## -+# -+# Above configuration is using the default interface (wlan#, or multi-SSID VLAN -+# interfaces). Other BSSIDs can be added by using separator 'bss' with -+# default interface name to be allocated for the data packets of the new BSS. -+# -+# hostapd will generate BSSID mask based on the BSSIDs that are -+# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is -+# not the case, the MAC address of the radio must be changed before starting -+# hostapd (ifconfig wlan0 hw ether ). If a BSSID is configured for -+# every secondary BSS, this limitation is not applied at hostapd and other -+# masks may be used if the driver supports them (e.g., swap the locally -+# administered bit) -+# -+# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is -+# specified using the 'bssid' parameter. -+# If an explicit BSSID is specified, it must be chosen such that it: -+# - results in a valid MASK that covers it and the dev_addr -+# - is not the same as the MAC address of the radio -+# - is not the same as any other explicitly specified BSSID -+# -+# Please note that hostapd uses some of the values configured for the first BSS -+# as the defaults for the following BSSes. However, it is recommended that all -+# BSSes include explicit configuration of all relevant configuration items. -+# -+#bss=wlan0_0 -+#ssid=test2 -+# most of the above items can be used here (apart from radio interface specific -+# items, like channel) -+ -+#bss=wlan0_1 -+#bssid=00:13:10:95:fe:0b -+# ... -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.deny b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.deny -new file mode 100644 -index 0000000000000..1616678f579e3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.deny -@@ -0,0 +1,5 @@ -+# List of MAC addresses that are not allowed to authenticate (IEEE 802.11) -+# with the AP. -+00:20:30:40:50:60 -+00:ab:cd:ef:12:34 -+00:00:30:40:50:60 -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.eap_user b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.eap_user -new file mode 100644 -index 0000000000000..ac9a5d896a049 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.eap_user -@@ -0,0 +1,91 @@ -+# hostapd user database for integrated EAP server -+ -+# Each line must contain an identity, EAP method(s), and an optional password -+# separated with whitespace (space or tab). The identity and password must be -+# double quoted ("user"). Password can alternatively be stored as -+# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password -+# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means -+# that the plaintext password does not need to be included in the user file. -+# Password hash is stored as hash:<16-octets of hex data> without quotation -+# marks. -+ -+# [2] flag in the end of the line can be used to mark users for tunneled phase -+# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous -+# identity can be used in the unencrypted phase 1 and the real user identity -+# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous -+# access is needed, two user entries is needed, one for phase 1 and another -+# with the same username for phase 2. -+# -+# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use -+# password option. -+# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a -+# password. -+# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration. -+# -+# * can be used as a wildcard to match any user identity. The main purposes for -+# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to -+# avoid having to configure every certificate for EAP-TLS authentication. The -+# first matching entry is selected, so * should be used as the last phase 1 -+# user entry. -+# -+# "prefix"* can be used to match the given prefix and anything after this. The -+# main purpose for this is to be able to avoid EAP method negotiation when the -+# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This -+# is only allowed for phase 1 identities. -+# -+# Multiple methods can be configured to make the authenticator try them one by -+# one until the peer accepts one. The method names are separated with a -+# comma (,). -+# -+# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP -+# version based on the Phase 1 identity. Without this flag, the EAP -+# authenticator advertises the highest supported version and select the version -+# based on the first PEAP packet from the supplicant. -+# -+# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel. -+# Tunneled EAP methods are configured with standard EAP method name and [2] -+# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP, -+# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a -+# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password -+# hash. -+ -+# Phase 1 users -+"user" MD5 "password" -+"test user" MD5 "secret" -+"example user" TLS -+"DOMAIN\user" MSCHAPV2 "password" -+"gtc user" GTC "password" -+"pax user" PAX "unknown" -+"pax.user@example.com" PAX 0123456789abcdef0123456789abcdef -+"psk user" PSK "unknown" -+"psk.user@example.com" PSK 0123456789abcdef0123456789abcdef -+"sake.user@example.com" SAKE 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef -+"ttls" TTLS -+"not anonymous" PEAP -+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes -+"0"* AKA,TTLS,TLS,PEAP,SIM -+"1"* SIM,TTLS,TLS,PEAP,AKA -+"2"* AKA,TTLS,TLS,PEAP,SIM -+"3"* SIM,TTLS,TLS,PEAP,AKA -+"4"* AKA,TTLS,TLS,PEAP,SIM -+"5"* SIM,TTLS,TLS,PEAP,AKA -+ -+# Wildcard for all other identities -+* PEAP,TTLS,TLS,SIM,AKA -+ -+# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users -+"t-md5" MD5 "password" [2] -+"DOMAIN\t-mschapv2" MSCHAPV2 "password" [2] -+"t-gtc" GTC "password" [2] -+"not anonymous" MSCHAPV2 "password" [2] -+"user" MD5,GTC,MSCHAPV2 "password" [2] -+"test user" MSCHAPV2 hash:000102030405060708090a0b0c0d0e0f [2] -+"ttls-user" TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2 "password" [2] -+ -+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2 -+"0"* AKA [2] -+"1"* SIM [2] -+"2"* AKA [2] -+"3"* SIM [2] -+"4"* AKA [2] -+"5"* SIM [2] -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.radius_clients b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.radius_clients -new file mode 100644 -index 0000000000000..3980427253b4c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.radius_clients -@@ -0,0 +1,4 @@ -+# RADIUS client configuration for the RADIUS server -+10.1.2.3 secret passphrase -+192.168.1.0/24 another very secret passphrase -+0.0.0.0/0 radius -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.sim_db b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.sim_db -new file mode 100644 -index 0000000000000..01c593de8d2da ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.sim_db -@@ -0,0 +1,9 @@ -+# Example GSM authentication triplet file for EAP-SIM authenticator -+# IMSI:Kc:SRES:RAND -+# IMSI: ASCII string (numbers) -+# Kc: hex, 8 octets -+# SRES: hex, 4 octets -+# RAND: hex, 16 octets -+234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -+234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB -+234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.vlan b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.vlan -new file mode 100644 -index 0000000000000..98254fa84f016 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.vlan -@@ -0,0 +1,9 @@ -+# VLAN ID to network interface mapping -+1 vlan1 -+2 vlan2 -+3 vlan3 -+100 guest -+# Optional wildcard entry matching all VLAN IDs. The first # in the interface -+# name will be replaced with the VLAN ID. The network interfaces are created -+# (and removed) dynamically based on the use. -+* vlan# -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.wpa_psk b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.wpa_psk -new file mode 100644 -index 0000000000000..0a9499acd7366 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd.wpa_psk -@@ -0,0 +1,9 @@ -+# List of WPA PSKs. Each line, except for empty lines and lines starting -+# with #, must contain a MAC address and PSK separated with a space. -+# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that -+# anyone can use. PSK can be configured as an ASCII passphrase of 8..63 -+# characters or as a 256-bit hex PSK (64 hex digits). -+00:00:00:00:00:00 secret passphrase -+00:11:22:33:44:55 another passphrase -+00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef -+00:00:00:00:00:00 another passphrase for all STAs -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.1 b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.1 -new file mode 100644 -index 0000000000000..218ea1588a4a8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.1 -@@ -0,0 +1,89 @@ -+.TH HOSTAPD_CLI 1 "April 7, 2005" hostapd_cli "hostapd command-line interface" -+.SH NAME -+hostapd_cli \- hostapd command-line interface -+.SH SYNOPSIS -+.B hostapd_cli -+[\-p] [\-i] [\-a] [\-hvB] [command..] -+.SH DESCRIPTION -+This manual page documents briefly the -+.B hostapd_cli -+utility. -+.PP -+.B hostapd_cli -+is a command-line interface for the -+.B hostapd -+daemon. -+ -+.B hostapd -+is a user space daemon for access point and authentication servers. -+It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server. -+For more information about -+.B hostapd -+refer to the -+.BR hostapd (8) -+man page. -+.SH OPTIONS -+A summary of options is included below. -+For a complete description, run -+.BR hostapd_cli -+from the command line. -+.TP -+.B \-p -+Path to find control sockets. -+ -+Default: /var/run/hostapd -+.TP -+.B \-i -+Interface to listen on. -+ -+Default: first interface found in socket path. -+.TP -+.B \-a -+Run in daemon mode executing the action file based on events from hostapd. -+.TP -+.B \-B -+Run a daemon in the background. -+.TP -+.B \-h -+Show usage. -+.TP -+.B \-v -+Show hostapd_cli version. -+.SH COMMANDS -+A summary of commands is included below. -+For a complete description, run -+.BR hostapd_cli -+from the command line. -+.TP -+.B mib -+Get MIB variables (dot1x, dot11, radius). -+.TP -+.B sta -+Get MIB variables for one station. -+.TP -+.B all_sta -+Get MIB variables for all stations. -+.TP -+.B help -+Get usage help. -+.TP -+.B interface [ifname] -+Show interfaces/select interface. -+.TP -+.B level -+Change debug level. -+.TP -+.B license -+Show full -+.B hostapd_cli -+license. -+.TP -+.B quit -+Exit hostapd_cli. -+.SH SEE ALSO -+.BR hostapd (8). -+.SH AUTHOR -+hostapd_cli was written by Jouni Malinen . -+.PP -+This manual page was written by Faidon Liambotis , -+for the Debian project (but may be used by others). -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.c -new file mode 100644 -index 0000000000000..a48d773259e6c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/hostapd_cli.c -@@ -0,0 +1,1044 @@ -+/* -+ * hostapd - command line interface for hostapd daemon -+ * Copyright (c) 2004-2011, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common/wpa_ctrl.h" -+#include "common.h" -+#include "common/version.h" -+ -+ -+static const char *hostapd_cli_version = -+"hostapd_cli v" VERSION_STR "\n" -+"Copyright (c) 2004-2011, Jouni Malinen and contributors"; -+ -+ -+static const char *hostapd_cli_license = -+"This program is free software. You can distribute it and/or modify it\n" -+"under the terms of the GNU General Public License version 2.\n" -+"\n" -+"Alternatively, this software may be distributed under the terms of the\n" -+"BSD license. See README and COPYING for more details.\n"; -+ -+static const char *hostapd_cli_full_license = -+"This program is free software; you can redistribute it and/or modify\n" -+"it under the terms of the GNU General Public License version 2 as\n" -+"published by the Free Software Foundation.\n" -+"\n" -+"This program is distributed in the hope that it will be useful,\n" -+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" -+"GNU General Public License for more details.\n" -+"\n" -+"You should have received a copy of the GNU General Public License\n" -+"along with this program; if not, write to the Free Software\n" -+"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" -+"\n" -+"Alternatively, this software may be distributed under the terms of the\n" -+"BSD license.\n" -+"\n" -+"Redistribution and use in source and binary forms, with or without\n" -+"modification, are permitted provided that the following conditions are\n" -+"met:\n" -+"\n" -+"1. Redistributions of source code must retain the above copyright\n" -+" notice, this list of conditions and the following disclaimer.\n" -+"\n" -+"2. Redistributions in binary form must reproduce the above copyright\n" -+" notice, this list of conditions and the following disclaimer in the\n" -+" documentation and/or other materials provided with the distribution.\n" -+"\n" -+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" -+" names of its contributors may be used to endorse or promote products\n" -+" derived from this software without specific prior written permission.\n" -+"\n" -+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" -+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" -+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" -+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" -+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" -+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" -+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" -+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" -+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" -+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" -+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" -+"\n"; -+ -+static const char *commands_help = -+"Commands:\n" -+" mib get MIB variables (dot1x, dot11, radius)\n" -+" sta get MIB variables for one station\n" -+" all_sta get MIB variables for all stations\n" -+" new_sta add a new station\n" -+" deauthenticate deauthenticate a station\n" -+" disassociate disassociate a station\n" -+#ifdef CONFIG_IEEE80211W -+" sa_query send SA Query to a station\n" -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_WPS -+" wps_pin [timeout] [addr] add WPS Enrollee PIN\n" -+" wps_check_pin verify PIN checksum\n" -+" wps_pbc indicate button pushed to initiate PBC\n" -+#ifdef CONFIG_WPS_OOB -+" wps_oob use WPS with out-of-band (UFD)\n" -+#endif /* CONFIG_WPS_OOB */ -+" wps_ap_pin [params..] enable/disable AP PIN\n" -+" wps_config configure AP\n" -+#endif /* CONFIG_WPS */ -+" get_config show current configuration\n" -+" help show this usage help\n" -+" interface [ifname] show interfaces/select interface\n" -+" level change debug level\n" -+" license show full hostapd_cli license\n" -+" quit exit hostapd_cli\n"; -+ -+static struct wpa_ctrl *ctrl_conn; -+static int hostapd_cli_quit = 0; -+static int hostapd_cli_attached = 0; -+static const char *ctrl_iface_dir = "/var/run/hostapd"; -+static char *ctrl_ifname = NULL; -+static const char *pid_file = NULL; -+static const char *action_file = NULL; -+static int ping_interval = 5; -+ -+ -+static void usage(void) -+{ -+ fprintf(stderr, "%s\n", hostapd_cli_version); -+ fprintf(stderr, -+ "\n" -+ "usage: hostapd_cli [-p] [-i] [-hvB] " -+ "[-a] \\\n" -+ " [-G] [command..]\n" -+ "\n" -+ "Options:\n" -+ " -h help (show this usage text)\n" -+ " -v shown version information\n" -+ " -p path to find control sockets (default: " -+ "/var/run/hostapd)\n" -+ " -a run in daemon mode executing the action file " -+ "based on events\n" -+ " from hostapd\n" -+ " -B run a daemon in the background\n" -+ " -i Interface to listen on (default: first " -+ "interface found in the\n" -+ " socket path)\n\n" -+ "%s", -+ commands_help); -+} -+ -+ -+static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname) -+{ -+ char *cfile; -+ int flen; -+ -+ if (ifname == NULL) -+ return NULL; -+ -+ flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2; -+ cfile = malloc(flen); -+ if (cfile == NULL) -+ return NULL; -+ snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname); -+ -+ ctrl_conn = wpa_ctrl_open(cfile); -+ free(cfile); -+ return ctrl_conn; -+} -+ -+ -+static void hostapd_cli_close_connection(void) -+{ -+ if (ctrl_conn == NULL) -+ return; -+ -+ if (hostapd_cli_attached) { -+ wpa_ctrl_detach(ctrl_conn); -+ hostapd_cli_attached = 0; -+ } -+ wpa_ctrl_close(ctrl_conn); -+ ctrl_conn = NULL; -+} -+ -+ -+static void hostapd_cli_msg_cb(char *msg, size_t len) -+{ -+ printf("%s\n", msg); -+} -+ -+ -+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print) -+{ -+ char buf[4096]; -+ size_t len; -+ int ret; -+ -+ if (ctrl_conn == NULL) { -+ printf("Not connected to hostapd - command dropped.\n"); -+ return -1; -+ } -+ len = sizeof(buf) - 1; -+ ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, -+ hostapd_cli_msg_cb); -+ if (ret == -2) { -+ printf("'%s' command timed out.\n", cmd); -+ return -2; -+ } else if (ret < 0) { -+ printf("'%s' command failed.\n", cmd); -+ return -1; -+ } -+ if (print) { -+ buf[len] = '\0'; -+ printf("%s", buf); -+ } -+ return 0; -+} -+ -+ -+static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd) -+{ -+ return _wpa_ctrl_command(ctrl, cmd, 1); -+} -+ -+ -+static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ return wpa_ctrl_command(ctrl, "PING"); -+} -+ -+ -+static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ return wpa_ctrl_command(ctrl, "RELOG"); -+} -+ -+ -+static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ return wpa_ctrl_command(ctrl, "MIB"); -+} -+ -+ -+static int hostapd_cli_exec(const char *program, const char *arg1, -+ const char *arg2) -+{ -+ char *cmd; -+ size_t len; -+ int res; -+ int ret = 0; -+ -+ len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3; -+ cmd = os_malloc(len); -+ if (cmd == NULL) -+ return -1; -+ res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2); -+ if (res < 0 || (size_t) res >= len) { -+ os_free(cmd); -+ return -1; -+ } -+ cmd[len - 1] = '\0'; -+#ifndef _WIN32_WCE -+ if (system(cmd) < 0) -+ ret = -1; -+#endif /* _WIN32_WCE */ -+ os_free(cmd); -+ -+ return ret; -+} -+ -+ -+static void hostapd_cli_action_process(char *msg, size_t len) -+{ -+ const char *pos; -+ -+ pos = msg; -+ if (*pos == '<') { -+ pos = os_strchr(pos, '>'); -+ if (pos) -+ pos++; -+ else -+ pos = msg; -+ } -+ -+ hostapd_cli_exec(action_file, ctrl_ifname, pos); -+} -+ -+ -+static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ char buf[64]; -+ if (argc != 1) { -+ printf("Invalid 'sta' command - exactly one argument, STA " -+ "address, is required.\n"); -+ return -1; -+ } -+ snprintf(buf, sizeof(buf), "STA %s", argv[0]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+ -+ -+static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char buf[64]; -+ if (argc != 1) { -+ printf("Invalid 'new_sta' command - exactly one argument, STA " -+ "address, is required.\n"); -+ return -1; -+ } -+ snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+ -+ -+static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char buf[64]; -+ if (argc < 1) { -+ printf("Invalid 'deauthenticate' command - exactly one " -+ "argument, STA address, is required.\n"); -+ return -1; -+ } -+ if (argc > 1) -+ os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s", -+ argv[0], argv[1]); -+ else -+ os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+ -+ -+static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char buf[64]; -+ if (argc < 1) { -+ printf("Invalid 'disassociate' command - exactly one " -+ "argument, STA address, is required.\n"); -+ return -1; -+ } -+ if (argc > 1) -+ os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s", -+ argv[0], argv[1]); -+ else -+ os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char buf[64]; -+ if (argc != 1) { -+ printf("Invalid 'sa_query' command - exactly one argument, " -+ "STA address, is required.\n"); -+ return -1; -+ } -+ snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+#ifdef CONFIG_WPS -+static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char buf[256]; -+ if (argc < 2) { -+ printf("Invalid 'wps_pin' command - at least two arguments, " -+ "UUID and PIN, are required.\n"); -+ return -1; -+ } -+ if (argc > 3) -+ snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s", -+ argv[0], argv[1], argv[2], argv[3]); -+ else if (argc > 2) -+ snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s", -+ argv[0], argv[1], argv[2]); -+ else -+ snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+ -+ -+static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char cmd[256]; -+ int res; -+ -+ if (argc != 1 && argc != 2) { -+ printf("Invalid WPS_CHECK_PIN command: needs one argument:\n" -+ "- PIN to be verified\n"); -+ return -1; -+ } -+ -+ if (argc == 2) -+ res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s", -+ argv[0], argv[1]); -+ else -+ res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s", -+ argv[0]); -+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { -+ printf("Too long WPS_CHECK_PIN command.\n"); -+ return -1; -+ } -+ return wpa_ctrl_command(ctrl, cmd); -+} -+ -+ -+static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ return wpa_ctrl_command(ctrl, "WPS_PBC"); -+} -+ -+ -+#ifdef CONFIG_WPS_OOB -+static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char cmd[256]; -+ int res; -+ -+ if (argc != 3 && argc != 4) { -+ printf("Invalid WPS_OOB command: need three or four " -+ "arguments:\n" -+ "- DEV_TYPE: use 'ufd' or 'nfc'\n" -+ "- PATH: path of OOB device like '/mnt'\n" -+ "- METHOD: OOB method 'pin-e' or 'pin-r', " -+ "'cred'\n" -+ "- DEV_NAME: (only for NFC) device name like " -+ "'pn531'\n"); -+ return -1; -+ } -+ -+ if (argc == 3) -+ res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s", -+ argv[0], argv[1], argv[2]); -+ else -+ res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s", -+ argv[0], argv[1], argv[2], argv[3]); -+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { -+ printf("Too long WPS_OOB command.\n"); -+ return -1; -+ } -+ return wpa_ctrl_command(ctrl, cmd); -+} -+#endif /* CONFIG_WPS_OOB */ -+ -+ -+static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char buf[64]; -+ if (argc < 1) { -+ printf("Invalid 'wps_ap_pin' command - at least one argument " -+ "is required.\n"); -+ return -1; -+ } -+ if (argc > 2) -+ snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s", -+ argv[0], argv[1], argv[2]); -+ else if (argc > 1) -+ snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s", -+ argv[0], argv[1]); -+ else -+ snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+ -+ -+static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char buf[256]; -+ char ssid_hex[2 * 32 + 1]; -+ char key_hex[2 * 64 + 1]; -+ int i; -+ -+ if (argc < 1) { -+ printf("Invalid 'wps_config' command - at least two arguments " -+ "are required.\n"); -+ return -1; -+ } -+ -+ ssid_hex[0] = '\0'; -+ for (i = 0; i < 32; i++) { -+ if (argv[0][i] == '\0') -+ break; -+ os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]); -+ } -+ -+ key_hex[0] = '\0'; -+ if (argc > 3) { -+ for (i = 0; i < 64; i++) { -+ if (argv[3][i] == '\0') -+ break; -+ os_snprintf(&key_hex[i * 2], 3, "%02x", -+ argv[3][i]); -+ } -+ } -+ -+ if (argc > 3) -+ snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s", -+ ssid_hex, argv[1], argv[2], key_hex); -+ else if (argc > 2) -+ snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s", -+ ssid_hex, argv[1], argv[2]); -+ else -+ snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s", -+ ssid_hex, argv[1]); -+ return wpa_ctrl_command(ctrl, buf); -+} -+#endif /* CONFIG_WPS */ -+ -+ -+static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ return wpa_ctrl_command(ctrl, "GET_CONFIG"); -+} -+ -+ -+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd, -+ char *addr, size_t addr_len) -+{ -+ char buf[4096], *pos; -+ size_t len; -+ int ret; -+ -+ if (ctrl_conn == NULL) { -+ printf("Not connected to hostapd - command dropped.\n"); -+ return -1; -+ } -+ len = sizeof(buf) - 1; -+ ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, -+ hostapd_cli_msg_cb); -+ if (ret == -2) { -+ printf("'%s' command timed out.\n", cmd); -+ return -2; -+ } else if (ret < 0) { -+ printf("'%s' command failed.\n", cmd); -+ return -1; -+ } -+ -+ buf[len] = '\0'; -+ if (memcmp(buf, "FAIL", 4) == 0) -+ return -1; -+ printf("%s", buf); -+ -+ pos = buf; -+ while (*pos != '\0' && *pos != '\n') -+ pos++; -+ *pos = '\0'; -+ os_strlcpy(addr, buf, addr_len); -+ return 0; -+} -+ -+ -+static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ char addr[32], cmd[64]; -+ -+ if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr))) -+ return 0; -+ do { -+ snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr); -+ } while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0); -+ -+ return -1; -+} -+ -+ -+static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ printf("%s", commands_help); -+ return 0; -+} -+ -+ -+static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license); -+ return 0; -+} -+ -+ -+static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ hostapd_cli_quit = 1; -+ return 0; -+} -+ -+ -+static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ char cmd[256]; -+ if (argc != 1) { -+ printf("Invalid LEVEL command: needs one argument (debug " -+ "level)\n"); -+ return 0; -+ } -+ snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]); -+ return wpa_ctrl_command(ctrl, cmd); -+} -+ -+ -+static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) -+{ -+ struct dirent *dent; -+ DIR *dir; -+ -+ dir = opendir(ctrl_iface_dir); -+ if (dir == NULL) { -+ printf("Control interface directory '%s' could not be " -+ "openned.\n", ctrl_iface_dir); -+ return; -+ } -+ -+ printf("Available interfaces:\n"); -+ while ((dent = readdir(dir))) { -+ if (strcmp(dent->d_name, ".") == 0 || -+ strcmp(dent->d_name, "..") == 0) -+ continue; -+ printf("%s\n", dent->d_name); -+ } -+ closedir(dir); -+} -+ -+ -+static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, -+ char *argv[]) -+{ -+ if (argc < 1) { -+ hostapd_cli_list_interfaces(ctrl); -+ return 0; -+ } -+ -+ hostapd_cli_close_connection(); -+ free(ctrl_ifname); -+ ctrl_ifname = strdup(argv[0]); -+ -+ if (hostapd_cli_open_connection(ctrl_ifname)) { -+ printf("Connected to interface '%s.\n", ctrl_ifname); -+ if (wpa_ctrl_attach(ctrl_conn) == 0) { -+ hostapd_cli_attached = 1; -+ } else { -+ printf("Warning: Failed to attach to " -+ "hostapd.\n"); -+ } -+ } else { -+ printf("Could not connect to interface '%s' - re-trying\n", -+ ctrl_ifname); -+ } -+ return 0; -+} -+ -+ -+static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ char cmd[256]; -+ int res; -+ -+ if (argc != 2) { -+ printf("Invalid SET command: needs two arguments (variable " -+ "name and value)\n"); -+ return -1; -+ } -+ -+ res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]); -+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { -+ printf("Too long SET command.\n"); -+ return -1; -+ } -+ return wpa_ctrl_command(ctrl, cmd); -+} -+ -+ -+static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ char cmd[256]; -+ int res; -+ -+ if (argc != 1) { -+ printf("Invalid GET command: needs one argument (variable " -+ "name)\n"); -+ return -1; -+ } -+ -+ res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]); -+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { -+ printf("Too long GET command.\n"); -+ return -1; -+ } -+ return wpa_ctrl_command(ctrl, cmd); -+} -+ -+ -+struct hostapd_cli_cmd { -+ const char *cmd; -+ int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); -+}; -+ -+static struct hostapd_cli_cmd hostapd_cli_commands[] = { -+ { "ping", hostapd_cli_cmd_ping }, -+ { "mib", hostapd_cli_cmd_mib }, -+ { "relog", hostapd_cli_cmd_relog }, -+ { "sta", hostapd_cli_cmd_sta }, -+ { "all_sta", hostapd_cli_cmd_all_sta }, -+ { "new_sta", hostapd_cli_cmd_new_sta }, -+ { "deauthenticate", hostapd_cli_cmd_deauthenticate }, -+ { "disassociate", hostapd_cli_cmd_disassociate }, -+#ifdef CONFIG_IEEE80211W -+ { "sa_query", hostapd_cli_cmd_sa_query }, -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_WPS -+ { "wps_pin", hostapd_cli_cmd_wps_pin }, -+ { "wps_check_pin", hostapd_cli_cmd_wps_check_pin }, -+ { "wps_pbc", hostapd_cli_cmd_wps_pbc }, -+#ifdef CONFIG_WPS_OOB -+ { "wps_oob", hostapd_cli_cmd_wps_oob }, -+#endif /* CONFIG_WPS_OOB */ -+ { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin }, -+ { "wps_config", hostapd_cli_cmd_wps_config }, -+#endif /* CONFIG_WPS */ -+ { "get_config", hostapd_cli_cmd_get_config }, -+ { "help", hostapd_cli_cmd_help }, -+ { "interface", hostapd_cli_cmd_interface }, -+ { "level", hostapd_cli_cmd_level }, -+ { "license", hostapd_cli_cmd_license }, -+ { "quit", hostapd_cli_cmd_quit }, -+ { "set", hostapd_cli_cmd_set }, -+ { "get", hostapd_cli_cmd_get }, -+ { NULL, NULL } -+}; -+ -+ -+static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) -+{ -+ struct hostapd_cli_cmd *cmd, *match = NULL; -+ int count; -+ -+ count = 0; -+ cmd = hostapd_cli_commands; -+ while (cmd->cmd) { -+ if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) { -+ match = cmd; -+ if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { -+ /* we have an exact match */ -+ count = 1; -+ break; -+ } -+ count++; -+ } -+ cmd++; -+ } -+ -+ if (count > 1) { -+ printf("Ambiguous command '%s'; possible commands:", argv[0]); -+ cmd = hostapd_cli_commands; -+ while (cmd->cmd) { -+ if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == -+ 0) { -+ printf(" %s", cmd->cmd); -+ } -+ cmd++; -+ } -+ printf("\n"); -+ } else if (count == 0) { -+ printf("Unknown command '%s'\n", argv[0]); -+ } else { -+ match->handler(ctrl, argc - 1, &argv[1]); -+ } -+} -+ -+ -+static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, -+ int action_monitor) -+{ -+ int first = 1; -+ if (ctrl_conn == NULL) -+ return; -+ while (wpa_ctrl_pending(ctrl)) { -+ char buf[256]; -+ size_t len = sizeof(buf) - 1; -+ if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { -+ buf[len] = '\0'; -+ if (action_monitor) -+ hostapd_cli_action_process(buf, len); -+ else { -+ if (in_read && first) -+ printf("\n"); -+ first = 0; -+ printf("%s\n", buf); -+ } -+ } else { -+ printf("Could not read pending message.\n"); -+ break; -+ } -+ } -+} -+ -+ -+static void hostapd_cli_interactive(void) -+{ -+ const int max_args = 10; -+ char cmd[256], *res, *argv[max_args], *pos; -+ int argc; -+ -+ printf("\nInteractive mode\n\n"); -+ -+ do { -+ hostapd_cli_recv_pending(ctrl_conn, 0, 0); -+ printf("> "); -+ alarm(ping_interval); -+ res = fgets(cmd, sizeof(cmd), stdin); -+ alarm(0); -+ if (res == NULL) -+ break; -+ pos = cmd; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ argc = 0; -+ pos = cmd; -+ for (;;) { -+ while (*pos == ' ') -+ pos++; -+ if (*pos == '\0') -+ break; -+ argv[argc] = pos; -+ argc++; -+ if (argc == max_args) -+ break; -+ while (*pos != '\0' && *pos != ' ') -+ pos++; -+ if (*pos == ' ') -+ *pos++ = '\0'; -+ } -+ if (argc) -+ wpa_request(ctrl_conn, argc, argv); -+ } while (!hostapd_cli_quit); -+} -+ -+ -+static void hostapd_cli_cleanup(void) -+{ -+ hostapd_cli_close_connection(); -+ if (pid_file) -+ os_daemonize_terminate(pid_file); -+ -+ os_program_deinit(); -+} -+ -+ -+static void hostapd_cli_terminate(int sig) -+{ -+ hostapd_cli_cleanup(); -+ exit(0); -+} -+ -+ -+static void hostapd_cli_alarm(int sig) -+{ -+ if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) { -+ printf("Connection to hostapd lost - trying to reconnect\n"); -+ hostapd_cli_close_connection(); -+ } -+ if (!ctrl_conn) { -+ ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); -+ if (ctrl_conn) { -+ printf("Connection to hostapd re-established\n"); -+ if (wpa_ctrl_attach(ctrl_conn) == 0) { -+ hostapd_cli_attached = 1; -+ } else { -+ printf("Warning: Failed to attach to " -+ "hostapd.\n"); -+ } -+ } -+ } -+ if (ctrl_conn) -+ hostapd_cli_recv_pending(ctrl_conn, 1, 0); -+ alarm(ping_interval); -+} -+ -+ -+static void hostapd_cli_action(struct wpa_ctrl *ctrl) -+{ -+ fd_set rfds; -+ int fd, res; -+ struct timeval tv; -+ char buf[256]; -+ size_t len; -+ -+ fd = wpa_ctrl_get_fd(ctrl); -+ -+ while (!hostapd_cli_quit) { -+ FD_ZERO(&rfds); -+ FD_SET(fd, &rfds); -+ tv.tv_sec = ping_interval; -+ tv.tv_usec = 0; -+ res = select(fd + 1, &rfds, NULL, NULL, &tv); -+ if (res < 0 && errno != EINTR) { -+ perror("select"); -+ break; -+ } -+ -+ if (FD_ISSET(fd, &rfds)) -+ hostapd_cli_recv_pending(ctrl, 0, 1); -+ else { -+ len = sizeof(buf) - 1; -+ if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, -+ hostapd_cli_action_process) < 0 || -+ len < 4 || os_memcmp(buf, "PONG", 4) != 0) { -+ printf("hostapd did not reply to PING " -+ "command - exiting\n"); -+ break; -+ } -+ } -+ } -+} -+ -+ -+int main(int argc, char *argv[]) -+{ -+ int interactive; -+ int warning_displayed = 0; -+ int c; -+ int daemonize = 0; -+ -+ if (os_program_init()) -+ return -1; -+ -+ for (;;) { -+ c = getopt(argc, argv, "a:BhG:i:p:v"); -+ if (c < 0) -+ break; -+ switch (c) { -+ case 'a': -+ action_file = optarg; -+ break; -+ case 'B': -+ daemonize = 1; -+ break; -+ case 'G': -+ ping_interval = atoi(optarg); -+ break; -+ case 'h': -+ usage(); -+ return 0; -+ case 'v': -+ printf("%s\n", hostapd_cli_version); -+ return 0; -+ case 'i': -+ os_free(ctrl_ifname); -+ ctrl_ifname = os_strdup(optarg); -+ break; -+ case 'p': -+ ctrl_iface_dir = optarg; -+ break; -+ default: -+ usage(); -+ return -1; -+ } -+ } -+ -+ interactive = (argc == optind) && (action_file == NULL); -+ -+ if (interactive) { -+ printf("%s\n\n%s\n\n", hostapd_cli_version, -+ hostapd_cli_license); -+ } -+ -+ for (;;) { -+ if (ctrl_ifname == NULL) { -+ struct dirent *dent; -+ DIR *dir = opendir(ctrl_iface_dir); -+ if (dir) { -+ while ((dent = readdir(dir))) { -+ if (os_strcmp(dent->d_name, ".") == 0 -+ || -+ os_strcmp(dent->d_name, "..") == 0) -+ continue; -+ printf("Selected interface '%s'\n", -+ dent->d_name); -+ ctrl_ifname = os_strdup(dent->d_name); -+ break; -+ } -+ closedir(dir); -+ } -+ } -+ ctrl_conn = hostapd_cli_open_connection(ctrl_ifname); -+ if (ctrl_conn) { -+ if (warning_displayed) -+ printf("Connection established.\n"); -+ break; -+ } -+ -+ if (!interactive) { -+ perror("Failed to connect to hostapd - " -+ "wpa_ctrl_open"); -+ return -1; -+ } -+ -+ if (!warning_displayed) { -+ printf("Could not connect to hostapd - re-trying\n"); -+ warning_displayed = 1; -+ } -+ os_sleep(1, 0); -+ continue; -+ } -+ -+ signal(SIGINT, hostapd_cli_terminate); -+ signal(SIGTERM, hostapd_cli_terminate); -+ signal(SIGALRM, hostapd_cli_alarm); -+ -+ if (interactive || action_file) { -+ if (wpa_ctrl_attach(ctrl_conn) == 0) { -+ hostapd_cli_attached = 1; -+ } else { -+ printf("Warning: Failed to attach to hostapd.\n"); -+ if (action_file) -+ return -1; -+ } -+ } -+ -+ if (daemonize && os_daemonize(pid_file)) -+ return -1; -+ -+ if (interactive) -+ hostapd_cli_interactive(); -+ else if (action_file) -+ hostapd_cli_action(ctrl_conn); -+ else -+ wpa_request(ctrl_conn, argc - optind, &argv[optind]); -+ -+ os_free(ctrl_ifname); -+ hostapd_cli_cleanup(); -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/README b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/README -new file mode 100644 -index 0000000000000..3cba511909632 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/README -@@ -0,0 +1,9 @@ -+Logwatch is a utility for analyzing system logs and provide a human -+readable summary. This directory has a configuration file and a log -+analyzer script for parsing hostapd system log entries for logwatch. -+These files can be installed by copying them to following locations: -+ -+/etc/log.d/conf/services/hostapd.conf -+/etc/log.d/scripts/services/hostapd -+ -+More information about logwatch is available from http://www.logwatch.org/ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd -new file mode 100644 -index 0000000000000..97b24ef6e1b84 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd -@@ -0,0 +1,65 @@ -+#!/usr/bin/perl -w -+# -+# Logwatch script for hostapd -+# -+# Copyright 2005 Henrik Brix Andersen -+# Distributed under the terms of the GNU General Public License v2 -+# Alternatively, this file may be distributed under the terms of the BSD License -+ -+use strict; -+ -+my $debug = $ENV{'LOGWATCH_DEBUG'} || 0; -+my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; -+my $debugcounter = 1; -+ -+my %hostapd; -+my @unmatched; -+ -+if ($debug >= 5) { -+ print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n"; -+} -+ -+while (defined(my $line = )) { -+ if ($debug >= 5) { -+ print STDERR "DEBUG($debugcounter): $line"; -+ $debugcounter++; -+ } -+ chomp($line); -+ -+ if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) { -+ unless ($detail == 10) { -+ # collapse association events -+ $details =~ s/^(associated) .*$/$1/i; -+ } -+ $hostapd{$iface}->{$mac}->{$layer}->{$details}++; -+ } else { -+ push @unmatched, "$line\n"; -+ } -+} -+ -+if (keys %hostapd) { -+ foreach my $iface (sort keys %hostapd) { -+ print "Interface $iface:\n"; -+ foreach my $mac (sort keys %{$hostapd{$iface}}) { -+ print " Client MAC Address $mac:\n"; -+ foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) { -+ print " $layer:\n"; -+ foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) { -+ print " $details"; -+ my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details}; -+ if ($count > 1) { -+ print ": " . $count . " Times"; -+ } -+ print "\n"; -+ } -+ } -+ } -+ } -+} -+ -+if ($#unmatched >= 0) { -+ print "\n**Unmatched Entries**\n"; -+ print @unmatched; -+} -+ -+exit(0); -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd.conf b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd.conf -new file mode 100644 -index 0000000000000..5bebe6ad2c1b6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/logwatch/hostapd.conf -@@ -0,0 +1,10 @@ -+# Logwatch configuration for hostapd -+# -+# Copyright 2005 Henrik Brix Andersen -+# Distributed under the terms of the GNU General Public License v2 -+# Alternatively, this file may be distributed under the terms of the BSD License -+ -+Title = "hostapd" -+LogFile = messages -+*OnlyService = hostapd -+*RemoveHeaders -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/main.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/main.c -new file mode 100644 -index 0000000000000..7a4cfb0041b02 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/main.c -@@ -0,0 +1,599 @@ -+/* -+ * hostapd / main() -+ * Copyright (c) 2002-2011, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+#ifndef CONFIG_NATIVE_WINDOWS -+#include -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "crypto/random.h" -+#include "crypto/tls.h" -+#include "common/version.h" -+#include "drivers/driver.h" -+#include "eap_server/eap.h" -+#include "eap_server/tncs.h" -+#include "ap/hostapd.h" -+#include "ap/ap_config.h" -+#include "config_file.h" -+#include "eap_register.h" -+#include "dump_state.h" -+#include "ctrl_iface.h" -+ -+ -+extern int wpa_debug_level; -+extern int wpa_debug_show_keys; -+extern int wpa_debug_timestamp; -+ -+ -+struct hapd_interfaces { -+ size_t count; -+ struct hostapd_iface **iface; -+}; -+ -+ -+static int hostapd_for_each_interface(struct hapd_interfaces *interfaces, -+ int (*cb)(struct hostapd_iface *iface, -+ void *ctx), void *ctx) -+{ -+ size_t i; -+ int ret; -+ -+ for (i = 0; i < interfaces->count; i++) { -+ ret = cb(interfaces->iface[i], ctx); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+ -+#ifndef CONFIG_NO_HOSTAPD_LOGGER -+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, -+ int level, const char *txt, size_t len) -+{ -+ struct hostapd_data *hapd = ctx; -+ char *format, *module_str; -+ int maxlen; -+ int conf_syslog_level, conf_stdout_level; -+ unsigned int conf_syslog, conf_stdout; -+ -+ maxlen = len + 100; -+ format = os_malloc(maxlen); -+ if (!format) -+ return; -+ -+ if (hapd && hapd->conf) { -+ conf_syslog_level = hapd->conf->logger_syslog_level; -+ conf_stdout_level = hapd->conf->logger_stdout_level; -+ conf_syslog = hapd->conf->logger_syslog; -+ conf_stdout = hapd->conf->logger_stdout; -+ } else { -+ conf_syslog_level = conf_stdout_level = 0; -+ conf_syslog = conf_stdout = (unsigned int) -1; -+ } -+ -+ switch (module) { -+ case HOSTAPD_MODULE_IEEE80211: -+ module_str = "IEEE 802.11"; -+ break; -+ case HOSTAPD_MODULE_IEEE8021X: -+ module_str = "IEEE 802.1X"; -+ break; -+ case HOSTAPD_MODULE_RADIUS: -+ module_str = "RADIUS"; -+ break; -+ case HOSTAPD_MODULE_WPA: -+ module_str = "WPA"; -+ break; -+ case HOSTAPD_MODULE_DRIVER: -+ module_str = "DRIVER"; -+ break; -+ case HOSTAPD_MODULE_IAPP: -+ module_str = "IAPP"; -+ break; -+ case HOSTAPD_MODULE_MLME: -+ module_str = "MLME"; -+ break; -+ default: -+ module_str = NULL; -+ break; -+ } -+ -+ if (hapd && hapd->conf && addr) -+ os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", -+ hapd->conf->iface, MAC2STR(addr), -+ module_str ? " " : "", module_str, txt); -+ else if (hapd && hapd->conf) -+ os_snprintf(format, maxlen, "%s:%s%s %s", -+ hapd->conf->iface, module_str ? " " : "", -+ module_str, txt); -+ else if (addr) -+ os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", -+ MAC2STR(addr), module_str ? " " : "", -+ module_str, txt); -+ else -+ os_snprintf(format, maxlen, "%s%s%s", -+ module_str, module_str ? ": " : "", txt); -+ -+ if ((conf_stdout & module) && level >= conf_stdout_level) { -+ wpa_debug_print_timestamp(); -+ printf("%s\n", format); -+ } -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ if ((conf_syslog & module) && level >= conf_syslog_level) { -+ int priority; -+ switch (level) { -+ case HOSTAPD_LEVEL_DEBUG_VERBOSE: -+ case HOSTAPD_LEVEL_DEBUG: -+ priority = LOG_DEBUG; -+ break; -+ case HOSTAPD_LEVEL_INFO: -+ priority = LOG_INFO; -+ break; -+ case HOSTAPD_LEVEL_NOTICE: -+ priority = LOG_NOTICE; -+ break; -+ case HOSTAPD_LEVEL_WARNING: -+ priority = LOG_WARNING; -+ break; -+ default: -+ priority = LOG_INFO; -+ break; -+ } -+ syslog(priority, "%s", format); -+ } -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ os_free(format); -+} -+#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -+ -+ -+/** -+ * hostapd_init - Allocate and initialize per-interface data -+ * @config_file: Path to the configuration file -+ * Returns: Pointer to the allocated interface data or %NULL on failure -+ * -+ * This function is used to allocate main data structures for per-interface -+ * data. The allocated data buffer will be freed by calling -+ * hostapd_cleanup_iface(). -+ */ -+static struct hostapd_iface * hostapd_init(const char *config_file) -+{ -+ struct hostapd_iface *hapd_iface = NULL; -+ struct hostapd_config *conf = NULL; -+ struct hostapd_data *hapd; -+ size_t i; -+ -+ hapd_iface = os_zalloc(sizeof(*hapd_iface)); -+ if (hapd_iface == NULL) -+ goto fail; -+ -+ hapd_iface->reload_config = hostapd_reload_config; -+ hapd_iface->config_read_cb = hostapd_config_read; -+ hapd_iface->config_fname = os_strdup(config_file); -+ if (hapd_iface->config_fname == NULL) -+ goto fail; -+ hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init; -+ hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit; -+ hapd_iface->for_each_interface = hostapd_for_each_interface; -+ -+ conf = hostapd_config_read(hapd_iface->config_fname); -+ if (conf == NULL) -+ goto fail; -+ hapd_iface->conf = conf; -+ -+ hapd_iface->num_bss = conf->num_bss; -+ hapd_iface->bss = os_zalloc(conf->num_bss * -+ sizeof(struct hostapd_data *)); -+ if (hapd_iface->bss == NULL) -+ goto fail; -+ -+ for (i = 0; i < conf->num_bss; i++) { -+ hapd = hapd_iface->bss[i] = -+ hostapd_alloc_bss_data(hapd_iface, conf, -+ &conf->bss[i]); -+ if (hapd == NULL) -+ goto fail; -+ hapd->msg_ctx = hapd; -+ } -+ -+ return hapd_iface; -+ -+fail: -+ if (conf) -+ hostapd_config_free(conf); -+ if (hapd_iface) { -+ os_free(hapd_iface->config_fname); -+ os_free(hapd_iface->bss); -+ os_free(hapd_iface); -+ } -+ return NULL; -+} -+ -+ -+static int hostapd_driver_init(struct hostapd_iface *iface) -+{ -+ struct wpa_init_params params; -+ size_t i; -+ struct hostapd_data *hapd = iface->bss[0]; -+ struct hostapd_bss_config *conf = hapd->conf; -+ u8 *b = conf->bssid; -+ struct wpa_driver_capa capa; -+ -+ if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) { -+ wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); -+ return -1; -+ } -+ -+ /* Initialize the driver interface */ -+ if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) -+ b = NULL; -+ -+ os_memset(¶ms, 0, sizeof(params)); -+ params.bssid = b; -+ params.ifname = hapd->conf->iface; -+ params.ssid = (const u8 *) hapd->conf->ssid.ssid; -+ params.ssid_len = hapd->conf->ssid.ssid_len; -+ params.test_socket = hapd->conf->test_socket; -+ params.use_pae_group_addr = hapd->conf->use_pae_group_addr; -+ -+ params.num_bridge = hapd->iface->num_bss; -+ params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *)); -+ if (params.bridge == NULL) -+ return -1; -+ for (i = 0; i < hapd->iface->num_bss; i++) { -+ struct hostapd_data *bss = hapd->iface->bss[i]; -+ if (bss->conf->bridge[0]) -+ params.bridge[i] = bss->conf->bridge; -+ } -+ -+ params.own_addr = hapd->own_addr; -+ -+ hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms); -+ os_free(params.bridge); -+ if (hapd->drv_priv == NULL) { -+ wpa_printf(MSG_ERROR, "%s driver initialization failed.", -+ hapd->driver->name); -+ hapd->driver = NULL; -+ return -1; -+ } -+ -+ if (hapd->driver->get_capa && -+ hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) -+ iface->drv_flags = capa.flags; -+ -+ return 0; -+} -+ -+ -+static void hostapd_interface_deinit_free(struct hostapd_iface *iface) -+{ -+ const struct wpa_driver_ops *driver; -+ void *drv_priv; -+ if (iface == NULL) -+ return; -+ driver = iface->bss[0]->driver; -+ drv_priv = iface->bss[0]->drv_priv; -+ hostapd_interface_deinit(iface); -+ if (driver && driver->hapd_deinit) -+ driver->hapd_deinit(drv_priv); -+ hostapd_interface_free(iface); -+} -+ -+ -+static struct hostapd_iface * -+hostapd_interface_init(struct hapd_interfaces *interfaces, -+ const char *config_fname, int debug) -+{ -+ struct hostapd_iface *iface; -+ int k; -+ -+ wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); -+ iface = hostapd_init(config_fname); -+ if (!iface) -+ return NULL; -+ iface->interfaces = interfaces; -+ -+ for (k = 0; k < debug; k++) { -+ if (iface->bss[0]->conf->logger_stdout_level > 0) -+ iface->bss[0]->conf->logger_stdout_level--; -+ } -+ -+ if (hostapd_driver_init(iface) || -+ hostapd_setup_interface(iface)) { -+ hostapd_interface_deinit_free(iface); -+ return NULL; -+ } -+ -+ return iface; -+} -+ -+ -+/** -+ * handle_term - SIGINT and SIGTERM handler to terminate hostapd process -+ */ -+static void handle_term(int sig, void *signal_ctx) -+{ -+ wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); -+ eloop_terminate(); -+} -+ -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ -+static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) -+{ -+ if (hostapd_reload_config(iface) < 0) { -+ wpa_printf(MSG_WARNING, "Failed to read new configuration " -+ "file - continuing with old."); -+ } -+ return 0; -+} -+ -+ -+/** -+ * handle_reload - SIGHUP handler to reload configuration -+ */ -+static void handle_reload(int sig, void *signal_ctx) -+{ -+ struct hapd_interfaces *interfaces = signal_ctx; -+ wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", -+ sig); -+ hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); -+} -+ -+ -+static void handle_dump_state(int sig, void *signal_ctx) -+{ -+#ifdef HOSTAPD_DUMP_STATE -+ struct hapd_interfaces *interfaces = signal_ctx; -+ hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL); -+#endif /* HOSTAPD_DUMP_STATE */ -+} -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ -+static int hostapd_global_init(struct hapd_interfaces *interfaces) -+{ -+ hostapd_logger_register_cb(hostapd_logger_cb); -+ -+ if (eap_server_register_methods()) { -+ wpa_printf(MSG_ERROR, "Failed to register EAP methods"); -+ return -1; -+ } -+ -+ if (eloop_init()) { -+ wpa_printf(MSG_ERROR, "Failed to initialize event loop"); -+ return -1; -+ } -+ -+ random_init(); -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ eloop_register_signal(SIGHUP, handle_reload, interfaces); -+ eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ eloop_register_signal_terminate(handle_term, interfaces); -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ openlog("hostapd", 0, LOG_DAEMON); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ return 0; -+} -+ -+ -+static void hostapd_global_deinit(const char *pid_file) -+{ -+#ifdef EAP_SERVER_TNC -+ tncs_global_deinit(); -+#endif /* EAP_SERVER_TNC */ -+ -+ random_deinit(); -+ -+ eloop_destroy(); -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ closelog(); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ eap_server_unregister_methods(); -+ -+ os_daemonize_terminate(pid_file); -+} -+ -+ -+static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, -+ const char *pid_file) -+{ -+#ifdef EAP_SERVER_TNC -+ int tnc = 0; -+ size_t i, k; -+ -+ for (i = 0; !tnc && i < ifaces->count; i++) { -+ for (k = 0; k < ifaces->iface[i]->num_bss; k++) { -+ if (ifaces->iface[i]->bss[0]->conf->tnc) { -+ tnc++; -+ break; -+ } -+ } -+ } -+ -+ if (tnc && tncs_global_init() < 0) { -+ wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); -+ return -1; -+ } -+#endif /* EAP_SERVER_TNC */ -+ -+ if (daemonize && os_daemonize(pid_file)) { -+ perror("daemon"); -+ return -1; -+ } -+ -+ eloop_run(); -+ -+ return 0; -+} -+ -+ -+static void show_version(void) -+{ -+ fprintf(stderr, -+ "hostapd v" VERSION_STR "\n" -+ "User space daemon for IEEE 802.11 AP management,\n" -+ "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" -+ "Copyright (c) 2002-2011, Jouni Malinen " -+ "and contributors\n"); -+} -+ -+ -+static void usage(void) -+{ -+ show_version(); -+ fprintf(stderr, -+ "\n" -+ "usage: hostapd [-hdBKtv] [-P ] " -+ "\n" -+ "\n" -+ "options:\n" -+ " -h show this usage\n" -+ " -d show more debug messages (-dd for even more)\n" -+ " -B run daemon in the background\n" -+ " -P PID file\n" -+ " -K include key data in debug messages\n" -+#ifdef CONFIG_DEBUG_FILE -+ " -f log output to debug file instead of stdout\n" -+#endif /* CONFIG_DEBUG_FILE */ -+ " -t include timestamps in some debug messages\n" -+ " -v show hostapd version\n"); -+ -+ exit(1); -+} -+ -+ -+static const char * hostapd_msg_ifname_cb(void *ctx) -+{ -+ struct hostapd_data *hapd = ctx; -+ if (hapd && hapd->iconf && hapd->iconf->bss) -+ return hapd->iconf->bss->iface; -+ return NULL; -+} -+ -+ -+int main(int argc, char *argv[]) -+{ -+ struct hapd_interfaces interfaces; -+ int ret = 1; -+ size_t i; -+ int c, debug = 0, daemonize = 0; -+ char *pid_file = NULL; -+ const char *log_file = NULL; -+ -+ if (os_program_init()) -+ return -1; -+ -+ for (;;) { -+ c = getopt(argc, argv, "Bdf:hKP:tv"); -+ if (c < 0) -+ break; -+ switch (c) { -+ case 'h': -+ usage(); -+ break; -+ case 'd': -+ debug++; -+ if (wpa_debug_level > 0) -+ wpa_debug_level--; -+ break; -+ case 'B': -+ daemonize++; -+ break; -+ case 'f': -+ log_file = optarg; -+ break; -+ case 'K': -+ wpa_debug_show_keys++; -+ break; -+ case 'P': -+ os_free(pid_file); -+ pid_file = os_rel2abs_path(optarg); -+ break; -+ case 't': -+ wpa_debug_timestamp++; -+ break; -+ case 'v': -+ show_version(); -+ exit(1); -+ break; -+ -+ default: -+ usage(); -+ break; -+ } -+ } -+ -+ if (optind == argc) -+ usage(); -+ -+ wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); -+ -+ if (log_file) -+ wpa_debug_open_file(log_file); -+ -+ interfaces.count = argc - optind; -+ interfaces.iface = os_zalloc(interfaces.count * -+ sizeof(struct hostapd_iface *)); -+ if (interfaces.iface == NULL) { -+ wpa_printf(MSG_ERROR, "malloc failed"); -+ return -1; -+ } -+ -+ if (hostapd_global_init(&interfaces)) -+ return -1; -+ -+ /* Initialize interfaces */ -+ for (i = 0; i < interfaces.count; i++) { -+ interfaces.iface[i] = hostapd_interface_init(&interfaces, -+ argv[optind + i], -+ debug); -+ if (!interfaces.iface[i]) -+ goto out; -+ } -+ -+ if (hostapd_global_run(&interfaces, daemonize, pid_file)) -+ goto out; -+ -+ ret = 0; -+ -+ out: -+ /* Deinitialize all interfaces */ -+ for (i = 0; i < interfaces.count; i++) -+ hostapd_interface_deinit_free(interfaces.iface[i]); -+ os_free(interfaces.iface); -+ -+ hostapd_global_deinit(pid_file); -+ os_free(pid_file); -+ -+ if (log_file) -+ wpa_debug_close_file(); -+ -+ os_program_deinit(); -+ -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/nt_password_hash.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/nt_password_hash.c -new file mode 100644 -index 0000000000000..839802a744c5d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/nt_password_hash.c -@@ -0,0 +1,53 @@ -+/* -+ * hostapd - Plaintext password to NtPasswordHash -+ * Copyright (c) 2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/ms_funcs.h" -+ -+ -+int main(int argc, char *argv[]) -+{ -+ unsigned char password_hash[16]; -+ size_t i; -+ char *password, buf[64], *pos; -+ -+ if (argc > 1) -+ password = argv[1]; -+ else { -+ if (fgets(buf, sizeof(buf), stdin) == NULL) { -+ printf("Failed to read password\n"); -+ return 1; -+ } -+ buf[sizeof(buf) - 1] = '\0'; -+ pos = buf; -+ while (*pos != '\0') { -+ if (*pos == '\r' || *pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ password = buf; -+ } -+ -+ if (nt_password_hash((u8 *) password, strlen(password), password_hash)) -+ return -1; -+ for (i = 0; i < sizeof(password_hash); i++) -+ printf("%02x", password_hash[i]); -+ printf("\n"); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/wired.conf b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/wired.conf -new file mode 100644 -index 0000000000000..956f8c53c540f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/hostapd/wired.conf -@@ -0,0 +1,40 @@ -+##### hostapd configuration file ############################################## -+# Empty lines and lines starting with # are ignored -+ -+# Example configuration file for wired authenticator. See hostapd.conf for -+# more details. -+ -+interface=eth0 -+driver=wired -+logger_stdout=-1 -+logger_stdout_level=1 -+debug=2 -+dump_file=/tmp/hostapd.dump -+ -+ieee8021x=1 -+eap_reauth_period=3600 -+ -+use_pae_group_addr=1 -+ -+ -+##### RADIUS configuration #################################################### -+# for IEEE 802.1X with external Authentication Server, IEEE 802.11 -+# authentication with external ACL for MAC addresses, and accounting -+ -+# The own IP address of the access point (used as NAS-IP-Address) -+own_ip_addr=127.0.0.1 -+ -+# Optional NAS-Identifier string for RADIUS messages. When used, this should be -+# a unique to the NAS within the scope of the RADIUS server. For example, a -+# fully qualified domain name can be used here. -+nas_identifier=ap.example.com -+ -+# RADIUS authentication server -+auth_server_addr=127.0.0.1 -+auth_server_port=1812 -+auth_server_shared_secret=radius -+ -+# RADIUS accounting server -+acct_server_addr=127.0.0.1 -+acct_server_port=1813 -+acct_server_shared_secret=radius -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/Makefile -new file mode 100644 -index 0000000000000..d73a175abc866 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/Makefile -@@ -0,0 +1,11 @@ -+SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps -+ -+all: -+ for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done -+ -+clean: -+ for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done -+ rm -f *~ -+ -+install: -+ for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.c -new file mode 100644 -index 0000000000000..dbfb058af02fa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.c -@@ -0,0 +1,505 @@ -+/* -+ * hostapd / RADIUS Accounting -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "drivers/driver.h" -+#include "radius/radius.h" -+#include "radius/radius_client.h" -+#include "hostapd.h" -+#include "ieee802_1x.h" -+#include "ap_config.h" -+#include "sta_info.h" -+#include "ap_drv_ops.h" -+#include "accounting.h" -+ -+ -+/* Default interval in seconds for polling TX/RX octets from the driver if -+ * STA is not using interim accounting. This detects wrap arounds for -+ * input/output octets and updates Acct-{Input,Output}-Gigawords. */ -+#define ACCT_DEFAULT_UPDATE_INTERVAL 300 -+ -+static void accounting_sta_get_id(struct hostapd_data *hapd, -+ struct sta_info *sta); -+ -+ -+static struct radius_msg * accounting_msg(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ int status_type) -+{ -+ struct radius_msg *msg; -+ char buf[128]; -+ u8 *val; -+ size_t len; -+ int i; -+ -+ msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST, -+ radius_client_get_id(hapd->radius)); -+ if (msg == NULL) { -+ printf("Could not create net RADIUS packet\n"); -+ return NULL; -+ } -+ -+ if (sta) { -+ radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); -+ -+ os_snprintf(buf, sizeof(buf), "%08X-%08X", -+ sta->acct_session_id_hi, sta->acct_session_id_lo); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, -+ (u8 *) buf, os_strlen(buf))) { -+ printf("Could not add Acct-Session-Id\n"); -+ goto fail; -+ } -+ } else { -+ radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd)); -+ } -+ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE, -+ status_type)) { -+ printf("Could not add Acct-Status-Type\n"); -+ goto fail; -+ } -+ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC, -+ hapd->conf->ieee802_1x ? -+ RADIUS_ACCT_AUTHENTIC_RADIUS : -+ RADIUS_ACCT_AUTHENTIC_LOCAL)) { -+ printf("Could not add Acct-Authentic\n"); -+ goto fail; -+ } -+ -+ if (sta) { -+ val = ieee802_1x_get_identity(sta->eapol_sm, &len); -+ if (!val) { -+ os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, -+ MAC2STR(sta->addr)); -+ val = (u8 *) buf; -+ len = os_strlen(buf); -+ } -+ -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val, -+ len)) { -+ printf("Could not add User-Name\n"); -+ goto fail; -+ } -+ } -+ -+ if (hapd->conf->own_ip_addr.af == AF_INET && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, -+ (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { -+ printf("Could not add NAS-IP-Address\n"); -+ goto fail; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (hapd->conf->own_ip_addr.af == AF_INET6 && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, -+ (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { -+ printf("Could not add NAS-IPv6-Address\n"); -+ goto fail; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ if (hapd->conf->nas_identifier && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, -+ (u8 *) hapd->conf->nas_identifier, -+ os_strlen(hapd->conf->nas_identifier))) { -+ printf("Could not add NAS-Identifier\n"); -+ goto fail; -+ } -+ -+ if (sta && -+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { -+ printf("Could not add NAS-Port\n"); -+ goto fail; -+ } -+ -+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", -+ MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, -+ (u8 *) buf, os_strlen(buf))) { -+ printf("Could not add Called-Station-Id\n"); -+ goto fail; -+ } -+ -+ if (sta) { -+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, -+ MAC2STR(sta->addr)); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, -+ (u8 *) buf, os_strlen(buf))) { -+ printf("Could not add Calling-Station-Id\n"); -+ goto fail; -+ } -+ -+ if (!radius_msg_add_attr_int32( -+ msg, RADIUS_ATTR_NAS_PORT_TYPE, -+ RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { -+ printf("Could not add NAS-Port-Type\n"); -+ goto fail; -+ } -+ -+ os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", -+ radius_sta_rate(hapd, sta) / 2, -+ (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", -+ radius_mode_txt(hapd)); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, -+ (u8 *) buf, os_strlen(buf))) { -+ printf("Could not add Connect-Info\n"); -+ goto fail; -+ } -+ -+ for (i = 0; ; i++) { -+ val = ieee802_1x_get_radius_class(sta->eapol_sm, &len, -+ i); -+ if (val == NULL) -+ break; -+ -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS, -+ val, len)) { -+ printf("Could not add Class\n"); -+ goto fail; -+ } -+ } -+ } -+ -+ return msg; -+ -+ fail: -+ radius_msg_free(msg); -+ return NULL; -+} -+ -+ -+static int accounting_sta_update_stats(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ struct hostap_sta_driver_data *data) -+{ -+ if (hostapd_drv_read_sta_data(hapd, data, sta->addr)) -+ return -1; -+ -+ if (sta->last_rx_bytes > data->rx_bytes) -+ sta->acct_input_gigawords++; -+ if (sta->last_tx_bytes > data->tx_bytes) -+ sta->acct_output_gigawords++; -+ sta->last_rx_bytes = data->rx_bytes; -+ sta->last_tx_bytes = data->tx_bytes; -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: " -+ "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u " -+ "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u", -+ sta->last_rx_bytes, sta->acct_input_gigawords, -+ sta->last_tx_bytes, sta->acct_output_gigawords); -+ -+ return 0; -+} -+ -+ -+static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ struct sta_info *sta = timeout_ctx; -+ int interval; -+ -+ if (sta->acct_interim_interval) { -+ accounting_sta_interim(hapd, sta); -+ interval = sta->acct_interim_interval; -+ } else { -+ struct hostap_sta_driver_data data; -+ accounting_sta_update_stats(hapd, sta, &data); -+ interval = ACCT_DEFAULT_UPDATE_INTERVAL; -+ } -+ -+ eloop_register_timeout(interval, 0, accounting_interim_update, -+ hapd, sta); -+} -+ -+ -+/** -+ * accounting_sta_start - Start STA accounting -+ * @hapd: hostapd BSS data -+ * @sta: The station -+ */ -+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ struct radius_msg *msg; -+ int interval; -+ -+ if (sta->acct_session_started) -+ return; -+ -+ accounting_sta_get_id(hapd, sta); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, -+ "starting accounting session %08X-%08X", -+ sta->acct_session_id_hi, sta->acct_session_id_lo); -+ -+ time(&sta->acct_session_start); -+ sta->last_rx_bytes = sta->last_tx_bytes = 0; -+ sta->acct_input_gigawords = sta->acct_output_gigawords = 0; -+ hostapd_drv_sta_clear_stats(hapd, sta->addr); -+ -+ if (!hapd->conf->radius->acct_server) -+ return; -+ -+ if (sta->acct_interim_interval) -+ interval = sta->acct_interim_interval; -+ else -+ interval = ACCT_DEFAULT_UPDATE_INTERVAL; -+ eloop_register_timeout(interval, 0, accounting_interim_update, -+ hapd, sta); -+ -+ msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START); -+ if (msg) -+ radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr); -+ -+ sta->acct_session_started = 1; -+} -+ -+ -+static void accounting_sta_report(struct hostapd_data *hapd, -+ struct sta_info *sta, int stop) -+{ -+ struct radius_msg *msg; -+ int cause = sta->acct_terminate_cause; -+ struct hostap_sta_driver_data data; -+ struct os_time now; -+ u32 gigawords; -+ -+ if (!hapd->conf->radius->acct_server) -+ return; -+ -+ msg = accounting_msg(hapd, sta, -+ stop ? RADIUS_ACCT_STATUS_TYPE_STOP : -+ RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE); -+ if (!msg) { -+ printf("Could not create RADIUS Accounting message\n"); -+ return; -+ } -+ -+ os_get_time(&now); -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME, -+ now.sec - sta->acct_session_start)) { -+ printf("Could not add Acct-Session-Time\n"); -+ goto fail; -+ } -+ -+ if (accounting_sta_update_stats(hapd, sta, &data) == 0) { -+ if (!radius_msg_add_attr_int32(msg, -+ RADIUS_ATTR_ACCT_INPUT_PACKETS, -+ data.rx_packets)) { -+ printf("Could not add Acct-Input-Packets\n"); -+ goto fail; -+ } -+ if (!radius_msg_add_attr_int32(msg, -+ RADIUS_ATTR_ACCT_OUTPUT_PACKETS, -+ data.tx_packets)) { -+ printf("Could not add Acct-Output-Packets\n"); -+ goto fail; -+ } -+ if (!radius_msg_add_attr_int32(msg, -+ RADIUS_ATTR_ACCT_INPUT_OCTETS, -+ data.rx_bytes)) { -+ printf("Could not add Acct-Input-Octets\n"); -+ goto fail; -+ } -+ gigawords = sta->acct_input_gigawords; -+#if __WORDSIZE == 64 -+ gigawords += data.rx_bytes >> 32; -+#endif -+ if (gigawords && -+ !radius_msg_add_attr_int32( -+ msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, -+ gigawords)) { -+ printf("Could not add Acct-Input-Gigawords\n"); -+ goto fail; -+ } -+ if (!radius_msg_add_attr_int32(msg, -+ RADIUS_ATTR_ACCT_OUTPUT_OCTETS, -+ data.tx_bytes)) { -+ printf("Could not add Acct-Output-Octets\n"); -+ goto fail; -+ } -+ gigawords = sta->acct_output_gigawords; -+#if __WORDSIZE == 64 -+ gigawords += data.tx_bytes >> 32; -+#endif -+ if (gigawords && -+ !radius_msg_add_attr_int32( -+ msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, -+ gigawords)) { -+ printf("Could not add Acct-Output-Gigawords\n"); -+ goto fail; -+ } -+ } -+ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP, -+ now.sec)) { -+ printf("Could not add Event-Timestamp\n"); -+ goto fail; -+ } -+ -+ if (eloop_terminated()) -+ cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT; -+ -+ if (stop && cause && -+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE, -+ cause)) { -+ printf("Could not add Acct-Terminate-Cause\n"); -+ goto fail; -+ } -+ -+ radius_client_send(hapd->radius, msg, -+ stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM, -+ sta->addr); -+ return; -+ -+ fail: -+ radius_msg_free(msg); -+} -+ -+ -+/** -+ * accounting_sta_interim - Send a interim STA accounting report -+ * @hapd: hostapd BSS data -+ * @sta: The station -+ */ -+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ if (sta->acct_session_started) -+ accounting_sta_report(hapd, sta, 0); -+} -+ -+ -+/** -+ * accounting_sta_stop - Stop STA accounting -+ * @hapd: hostapd BSS data -+ * @sta: The station -+ */ -+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ if (sta->acct_session_started) { -+ accounting_sta_report(hapd, sta, 1); -+ eloop_cancel_timeout(accounting_interim_update, hapd, sta); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, -+ "stopped accounting session %08X-%08X", -+ sta->acct_session_id_hi, -+ sta->acct_session_id_lo); -+ sta->acct_session_started = 0; -+ } -+} -+ -+ -+static void accounting_sta_get_id(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+ sta->acct_session_id_lo = hapd->acct_session_id_lo++; -+ if (hapd->acct_session_id_lo == 0) { -+ hapd->acct_session_id_hi++; -+ } -+ sta->acct_session_id_hi = hapd->acct_session_id_hi; -+} -+ -+ -+/** -+ * accounting_receive - Process the RADIUS frames from Accounting Server -+ * @msg: RADIUS response message -+ * @req: RADIUS request message -+ * @shared_secret: RADIUS shared secret -+ * @shared_secret_len: Length of shared_secret in octets -+ * @data: Context data (struct hostapd_data *) -+ * Returns: Processing status -+ */ -+static RadiusRxResult -+accounting_receive(struct radius_msg *msg, struct radius_msg *req, -+ const u8 *shared_secret, size_t shared_secret_len, -+ void *data) -+{ -+ if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) { -+ printf("Unknown RADIUS message code\n"); -+ return RADIUS_RX_UNKNOWN; -+ } -+ -+ if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { -+ printf("Incoming RADIUS packet did not have correct " -+ "Authenticator - dropped\n"); -+ return RADIUS_RX_INVALID_AUTHENTICATOR; -+ } -+ -+ return RADIUS_RX_PROCESSED; -+} -+ -+ -+static void accounting_report_state(struct hostapd_data *hapd, int on) -+{ -+ struct radius_msg *msg; -+ -+ if (!hapd->conf->radius->acct_server || hapd->radius == NULL) -+ return; -+ -+ /* Inform RADIUS server that accounting will start/stop so that the -+ * server can close old accounting sessions. */ -+ msg = accounting_msg(hapd, NULL, -+ on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON : -+ RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF); -+ if (!msg) -+ return; -+ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE, -+ RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT)) -+ { -+ printf("Could not add Acct-Terminate-Cause\n"); -+ radius_msg_free(msg); -+ return; -+ } -+ -+ radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL); -+} -+ -+ -+/** -+ * accounting_init: Initialize accounting -+ * @hapd: hostapd BSS data -+ * Returns: 0 on success, -1 on failure -+ */ -+int accounting_init(struct hostapd_data *hapd) -+{ -+ struct os_time now; -+ -+ /* Acct-Session-Id should be unique over reboots. If reliable clock is -+ * not available, this could be replaced with reboot counter, etc. */ -+ os_get_time(&now); -+ hapd->acct_session_id_hi = now.sec; -+ -+ if (radius_client_register(hapd->radius, RADIUS_ACCT, -+ accounting_receive, hapd)) -+ return -1; -+ -+ accounting_report_state(hapd, 1); -+ -+ return 0; -+} -+ -+ -+/** -+ * accounting_deinit: Deinitilize accounting -+ * @hapd: hostapd BSS data -+ */ -+void accounting_deinit(struct hostapd_data *hapd) -+{ -+ accounting_report_state(hapd, 0); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.h -new file mode 100644 -index 0000000000000..f3d60f0155a64 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/accounting.h -@@ -0,0 +1,45 @@ -+/* -+ * hostapd / RADIUS Accounting -+ * Copyright (c) 2002-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef ACCOUNTING_H -+#define ACCOUNTING_H -+ -+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta); -+#ifdef CONFIG_NO_ACCOUNTING -+static inline void accounting_sta_start(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+} -+ -+static inline void accounting_sta_stop(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+} -+ -+static inline int accounting_init(struct hostapd_data *hapd) -+{ -+ return 0; -+} -+ -+static inline void accounting_deinit(struct hostapd_data *hapd) -+{ -+} -+#else /* CONFIG_NO_ACCOUNTING */ -+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta); -+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta); -+int accounting_init(struct hostapd_data *hapd); -+void accounting_deinit(struct hostapd_data *hapd); -+#endif /* CONFIG_NO_ACCOUNTING */ -+ -+#endif /* ACCOUNTING_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.c -new file mode 100644 -index 0000000000000..e77716bd3106b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.c -@@ -0,0 +1,627 @@ -+/* -+ * hostapd / Configuration helper functions -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "crypto/sha1.h" -+#include "radius/radius_client.h" -+#include "common/ieee802_11_defs.h" -+#include "common/eapol_common.h" -+#include "eap_common/eap_wsc_common.h" -+#include "eap_server/eap.h" -+#include "wpa_auth.h" -+#include "sta_info.h" -+#include "ap_config.h" -+ -+ -+static void hostapd_config_free_vlan(struct hostapd_bss_config *bss) -+{ -+ struct hostapd_vlan *vlan, *prev; -+ -+ vlan = bss->vlan; -+ prev = NULL; -+ while (vlan) { -+ prev = vlan; -+ vlan = vlan->next; -+ os_free(prev); -+ } -+ -+ bss->vlan = NULL; -+} -+ -+ -+void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) -+{ -+ bss->logger_syslog_level = HOSTAPD_LEVEL_INFO; -+ bss->logger_stdout_level = HOSTAPD_LEVEL_INFO; -+ bss->logger_syslog = (unsigned int) -1; -+ bss->logger_stdout = (unsigned int) -1; -+ -+ bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED; -+ -+ bss->wep_rekeying_period = 300; -+ /* use key0 in individual key and key1 in broadcast key */ -+ bss->broadcast_key_idx_min = 1; -+ bss->broadcast_key_idx_max = 2; -+ bss->eap_reauth_period = 3600; -+ -+ bss->wpa_group_rekey = 600; -+ bss->wpa_gmk_rekey = 86400; -+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; -+ bss->wpa_pairwise = WPA_CIPHER_TKIP; -+ bss->wpa_group = WPA_CIPHER_TKIP; -+ bss->rsn_pairwise = 0; -+ -+ bss->max_num_sta = MAX_STA_COUNT; -+ -+ bss->dtim_period = 2; -+ -+ bss->radius_server_auth_port = 1812; -+ bss->ap_max_inactivity = AP_MAX_INACTIVITY; -+ bss->eapol_version = EAPOL_VERSION; -+ -+ bss->max_listen_interval = 65535; -+ -+ bss->pwd_group = 19; /* ECC: GF(p=256) */ -+ -+#ifdef CONFIG_IEEE80211W -+ bss->assoc_sa_query_max_timeout = 1000; -+ bss->assoc_sa_query_retry_timeout = 201; -+#endif /* CONFIG_IEEE80211W */ -+#ifdef EAP_SERVER_FAST -+ /* both anonymous and authenticated provisioning */ -+ bss->eap_fast_prov = 3; -+ bss->pac_key_lifetime = 7 * 24 * 60 * 60; -+ bss->pac_key_refresh_time = 1 * 24 * 60 * 60; -+#endif /* EAP_SERVER_FAST */ -+ -+ /* Set to -1 as defaults depends on HT in setup */ -+ bss->wmm_enabled = -1; -+ -+#ifdef CONFIG_IEEE80211R -+ bss->ft_over_ds = 1; -+#endif /* CONFIG_IEEE80211R */ -+} -+ -+ -+struct hostapd_config * hostapd_config_defaults(void) -+{ -+#define ecw2cw(ecw) ((1 << (ecw)) - 1) -+ -+ struct hostapd_config *conf; -+ struct hostapd_bss_config *bss; -+ const int aCWmin = 4, aCWmax = 10; -+ const struct hostapd_wmm_ac_params ac_bk = -+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ -+ const struct hostapd_wmm_ac_params ac_be = -+ { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ -+ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ -+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 1 }; -+ const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ -+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 }; -+ const struct hostapd_tx_queue_params txq_bk = -+ { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 }; -+ const struct hostapd_tx_queue_params txq_be = -+ { 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0}; -+ const struct hostapd_tx_queue_params txq_vi = -+ { 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30}; -+ const struct hostapd_tx_queue_params txq_vo = -+ { 1, (ecw2cw(aCWmin) + 1) / 4 - 1, -+ (ecw2cw(aCWmin) + 1) / 2 - 1, 15}; -+ -+#undef ecw2cw -+ -+ conf = os_zalloc(sizeof(*conf)); -+ bss = os_zalloc(sizeof(*bss)); -+ if (conf == NULL || bss == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate memory for " -+ "configuration data."); -+ os_free(conf); -+ os_free(bss); -+ return NULL; -+ } -+ -+ bss->radius = os_zalloc(sizeof(*bss->radius)); -+ if (bss->radius == NULL) { -+ os_free(conf); -+ os_free(bss); -+ return NULL; -+ } -+ -+ hostapd_config_defaults_bss(bss); -+ -+ conf->num_bss = 1; -+ conf->bss = bss; -+ -+ conf->beacon_int = 100; -+ conf->rts_threshold = -1; /* use driver default: 2347 */ -+ conf->fragm_threshold = -1; /* user driver default: 2346 */ -+ conf->send_probe_response = 1; -+ -+ conf->wmm_ac_params[0] = ac_be; -+ conf->wmm_ac_params[1] = ac_bk; -+ conf->wmm_ac_params[2] = ac_vi; -+ conf->wmm_ac_params[3] = ac_vo; -+ -+ conf->tx_queue[0] = txq_vo; -+ conf->tx_queue[1] = txq_vi; -+ conf->tx_queue[2] = txq_be; -+ conf->tx_queue[3] = txq_bk; -+ -+ conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED; -+ -+ return conf; -+} -+ -+ -+int hostapd_mac_comp(const void *a, const void *b) -+{ -+ return os_memcmp(a, b, sizeof(macaddr)); -+} -+ -+ -+int hostapd_mac_comp_empty(const void *a) -+{ -+ macaddr empty = { 0 }; -+ return os_memcmp(a, empty, sizeof(macaddr)); -+} -+ -+ -+static int hostapd_config_read_wpa_psk(const char *fname, -+ struct hostapd_ssid *ssid) -+{ -+ FILE *f; -+ char buf[128], *pos; -+ int line = 0, ret = 0, len, ok; -+ u8 addr[ETH_ALEN]; -+ struct hostapd_wpa_psk *psk; -+ -+ if (!fname) -+ return 0; -+ -+ f = fopen(fname, "r"); -+ if (!f) { -+ wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname); -+ return -1; -+ } -+ -+ while (fgets(buf, sizeof(buf), f)) { -+ line++; -+ -+ if (buf[0] == '#') -+ continue; -+ pos = buf; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ if (buf[0] == '\0') -+ continue; -+ -+ if (hwaddr_aton(buf, addr)) { -+ wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on " -+ "line %d in '%s'", buf, line, fname); -+ ret = -1; -+ break; -+ } -+ -+ psk = os_zalloc(sizeof(*psk)); -+ if (psk == NULL) { -+ wpa_printf(MSG_ERROR, "WPA PSK allocation failed"); -+ ret = -1; -+ break; -+ } -+ if (is_zero_ether_addr(addr)) -+ psk->group = 1; -+ else -+ os_memcpy(psk->addr, addr, ETH_ALEN); -+ -+ pos = buf + 17; -+ if (*pos == '\0') { -+ wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'", -+ line, fname); -+ os_free(psk); -+ ret = -1; -+ break; -+ } -+ pos++; -+ -+ ok = 0; -+ len = os_strlen(pos); -+ if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0) -+ ok = 1; -+ else if (len >= 8 && len < 64) { -+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len, -+ 4096, psk->psk, PMK_LEN); -+ ok = 1; -+ } -+ if (!ok) { -+ wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in " -+ "'%s'", pos, line, fname); -+ os_free(psk); -+ ret = -1; -+ break; -+ } -+ -+ psk->next = ssid->wpa_psk; -+ ssid->wpa_psk = psk; -+ } -+ -+ fclose(f); -+ -+ return ret; -+} -+ -+ -+static int hostapd_derive_psk(struct hostapd_ssid *ssid) -+{ -+ ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk)); -+ if (ssid->wpa_psk == NULL) { -+ wpa_printf(MSG_ERROR, "Unable to alloc space for PSK"); -+ return -1; -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "SSID", -+ (u8 *) ssid->ssid, ssid->ssid_len); -+ wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)", -+ (u8 *) ssid->wpa_passphrase, -+ os_strlen(ssid->wpa_passphrase)); -+ pbkdf2_sha1(ssid->wpa_passphrase, -+ ssid->ssid, ssid->ssid_len, -+ 4096, ssid->wpa_psk->psk, PMK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)", -+ ssid->wpa_psk->psk, PMK_LEN); -+ return 0; -+} -+ -+ -+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf) -+{ -+ struct hostapd_ssid *ssid = &conf->ssid; -+ -+ if (ssid->wpa_passphrase != NULL) { -+ if (ssid->wpa_psk != NULL) { -+ wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK " -+ "instead of passphrase"); -+ } else { -+ wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on " -+ "passphrase"); -+ if (hostapd_derive_psk(ssid) < 0) -+ return -1; -+ } -+ ssid->wpa_psk->group = 1; -+ } -+ -+ if (ssid->wpa_psk_file) { -+ if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file, -+ &conf->ssid)) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b) -+{ -+ int i; -+ -+ if (a->idx != b->idx || a->default_len != b->default_len) -+ return 1; -+ for (i = 0; i < NUM_WEP_KEYS; i++) -+ if (a->len[i] != b->len[i] || -+ os_memcmp(a->key[i], b->key[i], a->len[i]) != 0) -+ return 1; -+ return 0; -+} -+ -+ -+static void hostapd_config_free_radius(struct hostapd_radius_server *servers, -+ int num_servers) -+{ -+ int i; -+ -+ for (i = 0; i < num_servers; i++) { -+ os_free(servers[i].shared_secret); -+ } -+ os_free(servers); -+} -+ -+ -+static void hostapd_config_free_eap_user(struct hostapd_eap_user *user) -+{ -+ os_free(user->identity); -+ os_free(user->password); -+ os_free(user); -+} -+ -+ -+static void hostapd_config_free_wep(struct hostapd_wep_keys *keys) -+{ -+ int i; -+ for (i = 0; i < NUM_WEP_KEYS; i++) { -+ os_free(keys->key[i]); -+ keys->key[i] = NULL; -+ } -+} -+ -+ -+static void hostapd_config_free_bss(struct hostapd_bss_config *conf) -+{ -+ struct hostapd_wpa_psk *psk, *prev; -+ struct hostapd_eap_user *user, *prev_user; -+ -+ if (conf == NULL) -+ return; -+ -+ psk = conf->ssid.wpa_psk; -+ while (psk) { -+ prev = psk; -+ psk = psk->next; -+ os_free(prev); -+ } -+ -+ os_free(conf->ssid.wpa_passphrase); -+ os_free(conf->ssid.wpa_psk_file); -+ hostapd_config_free_wep(&conf->ssid.wep); -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ os_free(conf->ssid.vlan_tagged_interface); -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ -+ user = conf->eap_user; -+ while (user) { -+ prev_user = user; -+ user = user->next; -+ hostapd_config_free_eap_user(prev_user); -+ } -+ -+ os_free(conf->dump_log_name); -+ os_free(conf->eap_req_id_text); -+ os_free(conf->accept_mac); -+ os_free(conf->deny_mac); -+ os_free(conf->nas_identifier); -+ hostapd_config_free_radius(conf->radius->auth_servers, -+ conf->radius->num_auth_servers); -+ hostapd_config_free_radius(conf->radius->acct_servers, -+ conf->radius->num_acct_servers); -+ os_free(conf->rsn_preauth_interfaces); -+ os_free(conf->ctrl_interface); -+ os_free(conf->ca_cert); -+ os_free(conf->server_cert); -+ os_free(conf->private_key); -+ os_free(conf->private_key_passwd); -+ os_free(conf->dh_file); -+ os_free(conf->pac_opaque_encr_key); -+ os_free(conf->eap_fast_a_id); -+ os_free(conf->eap_fast_a_id_info); -+ os_free(conf->eap_sim_db); -+ os_free(conf->radius_server_clients); -+ os_free(conf->test_socket); -+ os_free(conf->radius); -+ hostapd_config_free_vlan(conf); -+ if (conf->ssid.dyn_vlan_keys) { -+ struct hostapd_ssid *ssid = &conf->ssid; -+ size_t i; -+ for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) { -+ if (ssid->dyn_vlan_keys[i] == NULL) -+ continue; -+ hostapd_config_free_wep(ssid->dyn_vlan_keys[i]); -+ os_free(ssid->dyn_vlan_keys[i]); -+ } -+ os_free(ssid->dyn_vlan_keys); -+ ssid->dyn_vlan_keys = NULL; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ { -+ struct ft_remote_r0kh *r0kh, *r0kh_prev; -+ struct ft_remote_r1kh *r1kh, *r1kh_prev; -+ -+ r0kh = conf->r0kh_list; -+ conf->r0kh_list = NULL; -+ while (r0kh) { -+ r0kh_prev = r0kh; -+ r0kh = r0kh->next; -+ os_free(r0kh_prev); -+ } -+ -+ r1kh = conf->r1kh_list; -+ conf->r1kh_list = NULL; -+ while (r1kh) { -+ r1kh_prev = r1kh; -+ r1kh = r1kh->next; -+ os_free(r1kh_prev); -+ } -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+#ifdef CONFIG_WPS -+ os_free(conf->wps_pin_requests); -+ os_free(conf->device_name); -+ os_free(conf->manufacturer); -+ os_free(conf->model_name); -+ os_free(conf->model_number); -+ os_free(conf->serial_number); -+ os_free(conf->config_methods); -+ os_free(conf->ap_pin); -+ os_free(conf->extra_cred); -+ os_free(conf->ap_settings); -+ os_free(conf->upnp_iface); -+ os_free(conf->friendly_name); -+ os_free(conf->manufacturer_url); -+ os_free(conf->model_description); -+ os_free(conf->model_url); -+ os_free(conf->upc); -+#endif /* CONFIG_WPS */ -+} -+ -+ -+/** -+ * hostapd_config_free - Free hostapd configuration -+ * @conf: Configuration data from hostapd_config_read(). -+ */ -+void hostapd_config_free(struct hostapd_config *conf) -+{ -+ size_t i; -+ -+ if (conf == NULL) -+ return; -+ -+ for (i = 0; i < conf->num_bss; i++) -+ hostapd_config_free_bss(&conf->bss[i]); -+ os_free(conf->bss); -+ os_free(conf->supported_rates); -+ os_free(conf->basic_rates); -+ -+ os_free(conf); -+} -+ -+ -+/** -+ * hostapd_maclist_found - Find a MAC address from a list -+ * @list: MAC address list -+ * @num_entries: Number of addresses in the list -+ * @addr: Address to search for -+ * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed -+ * Returns: 1 if address is in the list or 0 if not. -+ * -+ * Perform a binary search for given MAC address from a pre-sorted list. -+ */ -+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, -+ const u8 *addr, int *vlan_id) -+{ -+ int start, end, middle, res; -+ -+ start = 0; -+ end = num_entries - 1; -+ -+ while (start <= end) { -+ middle = (start + end) / 2; -+ res = os_memcmp(list[middle].addr, addr, ETH_ALEN); -+ if (res == 0) { -+ if (vlan_id) -+ *vlan_id = list[middle].vlan_id; -+ return 1; -+ } -+ if (res < 0) -+ start = middle + 1; -+ else -+ end = middle - 1; -+ } -+ -+ return 0; -+} -+ -+ -+int hostapd_rate_found(int *list, int rate) -+{ -+ int i; -+ -+ if (list == NULL) -+ return 0; -+ -+ for (i = 0; list[i] >= 0; i++) -+ if (list[i] == rate) -+ return 1; -+ -+ return 0; -+} -+ -+ -+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id) -+{ -+ struct hostapd_vlan *v = vlan; -+ while (v) { -+ if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD) -+ return v->ifname; -+ v = v->next; -+ } -+ return NULL; -+} -+ -+ -+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, -+ const u8 *addr, const u8 *prev_psk) -+{ -+ struct hostapd_wpa_psk *psk; -+ int next_ok = prev_psk == NULL; -+ -+ for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) { -+ if (next_ok && -+ (psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0)) -+ return psk->psk; -+ -+ if (psk->psk == prev_psk) -+ next_ok = 1; -+ } -+ -+ return NULL; -+} -+ -+ -+const struct hostapd_eap_user * -+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity, -+ size_t identity_len, int phase2) -+{ -+ struct hostapd_eap_user *user = conf->eap_user; -+ -+#ifdef CONFIG_WPS -+ if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN && -+ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) { -+ static struct hostapd_eap_user wsc_enrollee; -+ os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee)); -+ wsc_enrollee.methods[0].method = eap_server_get_type( -+ "WSC", &wsc_enrollee.methods[0].vendor); -+ return &wsc_enrollee; -+ } -+ -+ if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN && -+ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) { -+ static struct hostapd_eap_user wsc_registrar; -+ os_memset(&wsc_registrar, 0, sizeof(wsc_registrar)); -+ wsc_registrar.methods[0].method = eap_server_get_type( -+ "WSC", &wsc_registrar.methods[0].vendor); -+ wsc_registrar.password = (u8 *) conf->ap_pin; -+ wsc_registrar.password_len = conf->ap_pin ? -+ os_strlen(conf->ap_pin) : 0; -+ return &wsc_registrar; -+ } -+#endif /* CONFIG_WPS */ -+ -+ while (user) { -+ if (!phase2 && user->identity == NULL) { -+ /* Wildcard match */ -+ break; -+ } -+ -+ if (user->phase2 == !!phase2 && user->wildcard_prefix && -+ identity_len >= user->identity_len && -+ os_memcmp(user->identity, identity, user->identity_len) == -+ 0) { -+ /* Wildcard prefix match */ -+ break; -+ } -+ -+ if (user->phase2 == !!phase2 && -+ user->identity_len == identity_len && -+ os_memcmp(user->identity, identity, identity_len) == 0) -+ break; -+ user = user->next; -+ } -+ -+ return user; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.h -new file mode 100644 -index 0000000000000..25720b84a3e88 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_config.h -@@ -0,0 +1,417 @@ -+/* -+ * hostapd / Configuration definitions and helpers functions -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef HOSTAPD_CONFIG_H -+#define HOSTAPD_CONFIG_H -+ -+#include "common/defs.h" -+#include "ip_addr.h" -+#include "common/wpa_common.h" -+#include "wps/wps.h" -+ -+#define MAX_STA_COUNT 2007 -+#define MAX_VLAN_ID 4094 -+ -+typedef u8 macaddr[ETH_ALEN]; -+ -+struct mac_acl_entry { -+ macaddr addr; -+ int vlan_id; -+}; -+ -+struct hostapd_radius_servers; -+struct ft_remote_r0kh; -+struct ft_remote_r1kh; -+ -+#define HOSTAPD_MAX_SSID_LEN 32 -+ -+#define NUM_WEP_KEYS 4 -+struct hostapd_wep_keys { -+ u8 idx; -+ u8 *key[NUM_WEP_KEYS]; -+ size_t len[NUM_WEP_KEYS]; -+ int keys_set; -+ size_t default_len; /* key length used for dynamic key generation */ -+}; -+ -+typedef enum hostap_security_policy { -+ SECURITY_PLAINTEXT = 0, -+ SECURITY_STATIC_WEP = 1, -+ SECURITY_IEEE_802_1X = 2, -+ SECURITY_WPA_PSK = 3, -+ SECURITY_WPA = 4 -+} secpolicy; -+ -+struct hostapd_ssid { -+ char ssid[HOSTAPD_MAX_SSID_LEN + 1]; -+ size_t ssid_len; -+ int ssid_set; -+ -+ char vlan[IFNAMSIZ + 1]; -+ secpolicy security_policy; -+ -+ struct hostapd_wpa_psk *wpa_psk; -+ char *wpa_passphrase; -+ char *wpa_psk_file; -+ -+ struct hostapd_wep_keys wep; -+ -+#define DYNAMIC_VLAN_DISABLED 0 -+#define DYNAMIC_VLAN_OPTIONAL 1 -+#define DYNAMIC_VLAN_REQUIRED 2 -+ int dynamic_vlan; -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ char *vlan_tagged_interface; -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ struct hostapd_wep_keys **dyn_vlan_keys; -+ size_t max_dyn_vlan_keys; -+}; -+ -+ -+#define VLAN_ID_WILDCARD -1 -+ -+struct hostapd_vlan { -+ struct hostapd_vlan *next; -+ int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */ -+ char ifname[IFNAMSIZ + 1]; -+ int dynamic_vlan; -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ -+#define DVLAN_CLEAN_BR 0x1 -+#define DVLAN_CLEAN_VLAN 0x2 -+#define DVLAN_CLEAN_VLAN_PORT 0x4 -+#define DVLAN_CLEAN_WLAN_PORT 0x8 -+ int clean; -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+}; -+ -+#define PMK_LEN 32 -+struct hostapd_wpa_psk { -+ struct hostapd_wpa_psk *next; -+ int group; -+ u8 psk[PMK_LEN]; -+ u8 addr[ETH_ALEN]; -+}; -+ -+#define EAP_USER_MAX_METHODS 8 -+struct hostapd_eap_user { -+ struct hostapd_eap_user *next; -+ u8 *identity; -+ size_t identity_len; -+ struct { -+ int vendor; -+ u32 method; -+ } methods[EAP_USER_MAX_METHODS]; -+ u8 *password; -+ size_t password_len; -+ int phase2; -+ int force_version; -+ unsigned int wildcard_prefix:1; -+ unsigned int password_hash:1; /* whether password is hashed with -+ * nt_password_hash() */ -+ int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ -+}; -+ -+ -+#define NUM_TX_QUEUES 4 -+ -+struct hostapd_tx_queue_params { -+ int aifs; -+ int cwmin; -+ int cwmax; -+ int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */ -+}; -+ -+struct hostapd_wmm_ac_params { -+ int cwmin; -+ int cwmax; -+ int aifs; -+ int txop_limit; /* in units of 32us */ -+ int admission_control_mandatory; -+}; -+ -+ -+/** -+ * struct hostapd_bss_config - Per-BSS configuration -+ */ -+struct hostapd_bss_config { -+ char iface[IFNAMSIZ + 1]; -+ char bridge[IFNAMSIZ + 1]; -+ char wds_bridge[IFNAMSIZ + 1]; -+ -+ enum hostapd_logger_level logger_syslog_level, logger_stdout_level; -+ -+ unsigned int logger_syslog; /* module bitfield */ -+ unsigned int logger_stdout; /* module bitfield */ -+ -+ char *dump_log_name; /* file name for state dump (SIGUSR1) */ -+ -+ int max_num_sta; /* maximum number of STAs in station table */ -+ -+ int dtim_period; -+ -+ int ieee802_1x; /* use IEEE 802.1X */ -+ int eapol_version; -+ int eap_server; /* Use internal EAP server instead of external -+ * RADIUS server */ -+ struct hostapd_eap_user *eap_user; -+ char *eap_sim_db; -+ struct hostapd_ip_addr own_ip_addr; -+ char *nas_identifier; -+ struct hostapd_radius_servers *radius; -+ int acct_interim_interval; -+ -+ struct hostapd_ssid ssid; -+ -+ char *eap_req_id_text; /* optional displayable message sent with -+ * EAP Request-Identity */ -+ size_t eap_req_id_text_len; -+ int eapol_key_index_workaround; -+ -+ size_t default_wep_key_len; -+ int individual_wep_key_len; -+ int wep_rekeying_period; -+ int broadcast_key_idx_min, broadcast_key_idx_max; -+ int eap_reauth_period; -+ -+ int ieee802_11f; /* use IEEE 802.11f (IAPP) */ -+ char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast -+ * frames */ -+ -+ enum { -+ ACCEPT_UNLESS_DENIED = 0, -+ DENY_UNLESS_ACCEPTED = 1, -+ USE_EXTERNAL_RADIUS_AUTH = 2 -+ } macaddr_acl; -+ struct mac_acl_entry *accept_mac; -+ int num_accept_mac; -+ struct mac_acl_entry *deny_mac; -+ int num_deny_mac; -+ int wds_sta; -+ int isolate; -+ -+ int auth_algs; /* bitfield of allowed IEEE 802.11 authentication -+ * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ -+ -+ int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ -+ int wpa_key_mgmt; -+#ifdef CONFIG_IEEE80211W -+ enum mfp_options ieee80211w; -+ /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ -+ unsigned int assoc_sa_query_max_timeout; -+ /* dot11AssociationSAQueryRetryTimeout (in TUs) */ -+ int assoc_sa_query_retry_timeout; -+#endif /* CONFIG_IEEE80211W */ -+ int wpa_pairwise; -+ int wpa_group; -+ int wpa_group_rekey; -+ int wpa_strict_rekey; -+ int wpa_gmk_rekey; -+ int wpa_ptk_rekey; -+ int rsn_pairwise; -+ int rsn_preauth; -+ char *rsn_preauth_interfaces; -+ int peerkey; -+ -+#ifdef CONFIG_IEEE80211R -+ /* IEEE 802.11r - Fast BSS Transition */ -+ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; -+ u8 r1_key_holder[FT_R1KH_ID_LEN]; -+ u32 r0_key_lifetime; -+ u32 reassociation_deadline; -+ struct ft_remote_r0kh *r0kh_list; -+ struct ft_remote_r1kh *r1kh_list; -+ int pmk_r1_push; -+ int ft_over_ds; -+#endif /* CONFIG_IEEE80211R */ -+ -+ char *ctrl_interface; /* directory for UNIX domain sockets */ -+#ifndef CONFIG_NATIVE_WINDOWS -+ gid_t ctrl_interface_gid; -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ int ctrl_interface_gid_set; -+ -+ char *ca_cert; -+ char *server_cert; -+ char *private_key; -+ char *private_key_passwd; -+ int check_crl; -+ char *dh_file; -+ u8 *pac_opaque_encr_key; -+ u8 *eap_fast_a_id; -+ size_t eap_fast_a_id_len; -+ char *eap_fast_a_id_info; -+ int eap_fast_prov; -+ int pac_key_lifetime; -+ int pac_key_refresh_time; -+ int eap_sim_aka_result_ind; -+ int tnc; -+ int fragment_size; -+ u16 pwd_group; -+ -+ char *radius_server_clients; -+ int radius_server_auth_port; -+ int radius_server_ipv6; -+ -+ char *test_socket; /* UNIX domain socket path for driver_test */ -+ -+ int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group -+ * address instead of individual address -+ * (for driver_wired.c). -+ */ -+ -+ int ap_max_inactivity; -+ int ignore_broadcast_ssid; -+ -+ int wmm_enabled; -+ int wmm_uapsd; -+ -+ struct hostapd_vlan *vlan, *vlan_tail; -+ -+ macaddr bssid; -+ -+ /* -+ * Maximum listen interval that STAs can use when associating with this -+ * BSS. If a STA tries to use larger value, the association will be -+ * denied with status code 51. -+ */ -+ u16 max_listen_interval; -+ -+ int okc; /* Opportunistic Key Caching */ -+ -+ int wps_state; -+#ifdef CONFIG_WPS -+ int ap_setup_locked; -+ u8 uuid[16]; -+ char *wps_pin_requests; -+ char *device_name; -+ char *manufacturer; -+ char *model_name; -+ char *model_number; -+ char *serial_number; -+ u8 device_type[WPS_DEV_TYPE_LEN]; -+ char *config_methods; -+ u8 os_version[4]; -+ char *ap_pin; -+ int skip_cred_build; -+ u8 *extra_cred; -+ size_t extra_cred_len; -+ int wps_cred_processing; -+ u8 *ap_settings; -+ size_t ap_settings_len; -+ char *upnp_iface; -+ char *friendly_name; -+ char *manufacturer_url; -+ char *model_description; -+ char *model_url; -+ char *upc; -+ struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; -+#endif /* CONFIG_WPS */ -+ -+#define P2P_ENABLED BIT(0) -+#define P2P_GROUP_OWNER BIT(1) -+#define P2P_GROUP_FORMATION BIT(2) -+#define P2P_MANAGE BIT(3) -+#define P2P_ALLOW_CROSS_CONNECTION BIT(4) -+ int p2p; -+ -+ int disassoc_low_ack; -+ -+#define TDLS_PROHIBIT BIT(0) -+#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) -+ int tdls; -+ int disable_11n; -+}; -+ -+ -+/** -+ * struct hostapd_config - Per-radio interface configuration -+ */ -+struct hostapd_config { -+ struct hostapd_bss_config *bss, *last_bss; -+ size_t num_bss; -+ -+ u16 beacon_int; -+ int rts_threshold; -+ int fragm_threshold; -+ u8 send_probe_response; -+ u8 channel; -+ enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ -+ enum { -+ LONG_PREAMBLE = 0, -+ SHORT_PREAMBLE = 1 -+ } preamble; -+ enum { -+ CTS_PROTECTION_AUTOMATIC = 0, -+ CTS_PROTECTION_FORCE_ENABLED = 1, -+ CTS_PROTECTION_FORCE_DISABLED = 2, -+ CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3, -+ } cts_protection_type; -+ -+ int *supported_rates; -+ int *basic_rates; -+ -+ const struct wpa_driver_ops *driver; -+ -+ int ap_table_max_size; -+ int ap_table_expiration_time; -+ -+ char country[3]; /* first two octets: country code as described in -+ * ISO/IEC 3166-1. Third octet: -+ * ' ' (ascii 32): all environments -+ * 'O': Outdoor environemnt only -+ * 'I': Indoor environment only -+ */ -+ -+ int ieee80211d; -+ -+ struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES]; -+ -+ /* -+ * WMM AC parameters, in same order as 802.1D, i.e. -+ * 0 = BE (best effort) -+ * 1 = BK (background) -+ * 2 = VI (video) -+ * 3 = VO (voice) -+ */ -+ struct hostapd_wmm_ac_params wmm_ac_params[4]; -+ -+ int ht_op_mode_fixed; -+ u16 ht_capab; -+ int ieee80211n; -+ int secondary_channel; -+ int require_ht; -+}; -+ -+ -+int hostapd_mac_comp(const void *a, const void *b); -+int hostapd_mac_comp_empty(const void *a); -+struct hostapd_config * hostapd_config_defaults(void); -+void hostapd_config_defaults_bss(struct hostapd_bss_config *bss); -+void hostapd_config_free(struct hostapd_config *conf); -+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, -+ const u8 *addr, int *vlan_id); -+int hostapd_rate_found(int *list, int rate); -+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, -+ struct hostapd_wep_keys *b); -+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, -+ const u8 *addr, const u8 *prev_psk); -+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf); -+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, -+ int vlan_id); -+const struct hostapd_eap_user * -+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity, -+ size_t identity_len, int phase2); -+ -+#endif /* HOSTAPD_CONFIG_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.c -new file mode 100644 -index 0000000000000..0b6836c11c1af ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.c -@@ -0,0 +1,632 @@ -+/* -+ * hostapd - Driver operations -+ * Copyright (c) 2009-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "drivers/driver.h" -+#include "common/ieee802_11_defs.h" -+#include "wps/wps.h" -+#include "hostapd.h" -+#include "ieee802_11.h" -+#include "sta_info.h" -+#include "ap_config.h" -+#include "p2p_hostapd.h" -+#include "ap_drv_ops.h" -+ -+ -+u32 hostapd_sta_flags_to_drv(u32 flags) -+{ -+ int res = 0; -+ if (flags & WLAN_STA_AUTHORIZED) -+ res |= WPA_STA_AUTHORIZED; -+ if (flags & WLAN_STA_WMM) -+ res |= WPA_STA_WMM; -+ if (flags & WLAN_STA_SHORT_PREAMBLE) -+ res |= WPA_STA_SHORT_PREAMBLE; -+ if (flags & WLAN_STA_MFP) -+ res |= WPA_STA_MFP; -+ return res; -+} -+ -+ -+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) -+{ -+ struct wpabuf *beacon, *proberesp, *assocresp = NULL; -+ int ret; -+ -+ if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL) -+ return 0; -+ -+ beacon = hapd->wps_beacon_ie; -+ proberesp = hapd->wps_probe_resp_ie; -+ -+#ifdef CONFIG_P2P -+ if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL) -+ beacon = NULL; -+ else { -+ beacon = wpabuf_alloc((hapd->wps_beacon_ie ? -+ wpabuf_len(hapd->wps_beacon_ie) : 0) + -+ (hapd->p2p_beacon_ie ? -+ wpabuf_len(hapd->p2p_beacon_ie) : 0)); -+ if (beacon == NULL) -+ return -1; -+ if (hapd->wps_beacon_ie) -+ wpabuf_put_buf(beacon, hapd->wps_beacon_ie); -+ if (hapd->p2p_beacon_ie) -+ wpabuf_put_buf(beacon, hapd->p2p_beacon_ie); -+ } -+ -+ if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL) -+ proberesp = NULL; -+ else { -+ proberesp = wpabuf_alloc( -+ (hapd->wps_probe_resp_ie ? -+ wpabuf_len(hapd->wps_probe_resp_ie) : 0) + -+ (hapd->p2p_probe_resp_ie ? -+ wpabuf_len(hapd->p2p_probe_resp_ie) : 0)); -+ if (proberesp == NULL) { -+ wpabuf_free(beacon); -+ return -1; -+ } -+ if (hapd->wps_probe_resp_ie) -+ wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie); -+ if (hapd->p2p_probe_resp_ie) -+ wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie); -+ } -+#endif /* CONFIG_P2P */ -+ -+#ifdef CONFIG_P2P_MANAGER -+ if (hapd->conf->p2p & P2P_MANAGE) { -+ struct wpabuf *a; -+ -+ a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0)); -+ if (a) { -+ u8 *start, *p; -+ if (beacon) -+ wpabuf_put_buf(a, beacon); -+ if (beacon != hapd->wps_beacon_ie) -+ wpabuf_free(beacon); -+ start = wpabuf_put(a, 0); -+ p = hostapd_eid_p2p_manage(hapd, start); -+ wpabuf_put(a, p - start); -+ beacon = a; -+ } -+ -+ a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) : -+ 0)); -+ if (a) { -+ u8 *start, *p; -+ if (proberesp) -+ wpabuf_put_buf(a, proberesp); -+ if (proberesp != hapd->wps_probe_resp_ie) -+ wpabuf_free(proberesp); -+ start = wpabuf_put(a, 0); -+ p = hostapd_eid_p2p_manage(hapd, start); -+ wpabuf_put(a, p - start); -+ proberesp = a; -+ } -+ } -+#endif /* CONFIG_P2P_MANAGER */ -+ -+#ifdef CONFIG_WPS2 -+ if (hapd->conf->wps_state) -+ assocresp = wps_build_assoc_resp_ie(); -+#endif /* CONFIG_WPS2 */ -+ -+#ifdef CONFIG_P2P_MANAGER -+ if (hapd->conf->p2p & P2P_MANAGE) { -+ struct wpabuf *a; -+ a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) : -+ 0)); -+ if (a) { -+ u8 *start, *p; -+ start = wpabuf_put(a, 0); -+ p = hostapd_eid_p2p_manage(hapd, start); -+ wpabuf_put(a, p - start); -+ if (assocresp) { -+ wpabuf_put_buf(a, assocresp); -+ wpabuf_free(assocresp); -+ } -+ assocresp = a; -+ } -+ } -+#endif /* CONFIG_P2P_MANAGER */ -+ -+ ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp, -+ assocresp); -+ -+ if (beacon != hapd->wps_beacon_ie) -+ wpabuf_free(beacon); -+ if (proberesp != hapd->wps_probe_resp_ie) -+ wpabuf_free(proberesp); -+ wpabuf_free(assocresp); -+ -+ return ret; -+} -+ -+ -+int hostapd_set_authorized(struct hostapd_data *hapd, -+ struct sta_info *sta, int authorized) -+{ -+ if (authorized) { -+ return hostapd_sta_set_flags(hapd, sta->addr, -+ hostapd_sta_flags_to_drv( -+ sta->flags), -+ WPA_STA_AUTHORIZED, ~0); -+ } -+ -+ return hostapd_sta_set_flags(hapd, sta->addr, -+ hostapd_sta_flags_to_drv(sta->flags), -+ 0, ~WPA_STA_AUTHORIZED); -+} -+ -+ -+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ int set_flags, total_flags, flags_and, flags_or; -+ total_flags = hostapd_sta_flags_to_drv(sta->flags); -+ set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP; -+ if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || -+ sta->auth_alg == WLAN_AUTH_FT) && -+ sta->flags & WLAN_STA_AUTHORIZED) -+ set_flags |= WPA_STA_AUTHORIZED; -+ flags_or = total_flags & set_flags; -+ flags_and = total_flags | ~set_flags; -+ return hostapd_sta_set_flags(hapd, sta->addr, total_flags, -+ flags_or, flags_and); -+} -+ -+ -+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, -+ int enabled) -+{ -+ struct wpa_bss_params params; -+ os_memset(¶ms, 0, sizeof(params)); -+ params.ifname = ifname; -+ params.enabled = enabled; -+ if (enabled) { -+ params.wpa = hapd->conf->wpa; -+ params.ieee802_1x = hapd->conf->ieee802_1x; -+ params.wpa_group = hapd->conf->wpa_group; -+ params.wpa_pairwise = hapd->conf->wpa_pairwise; -+ params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt; -+ params.rsn_preauth = hapd->conf->rsn_preauth; -+#ifdef CONFIG_IEEE80211W -+ params.ieee80211w = hapd->conf->ieee80211w; -+#endif /* CONFIG_IEEE80211W */ -+ } -+ return hostapd_set_ieee8021x(hapd, ¶ms); -+} -+ -+ -+static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL) -+ return 0; -+ return hapd->driver->set_intra_bss(hapd->drv_priv, !value); -+} -+ -+ -+int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection) -+{ -+ int ret = 0; -+ int preamble; -+#ifdef CONFIG_IEEE80211N -+ u8 buf[60], *ht_capab, *ht_oper, *pos; -+ -+ pos = buf; -+ ht_capab = pos; -+ pos = hostapd_eid_ht_capabilities(hapd, pos); -+ ht_oper = pos; -+ pos = hostapd_eid_ht_operation(hapd, pos); -+ if (pos > ht_oper && ht_oper > ht_capab && -+ hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1], -+ ht_oper + 2, ht_oper[1])) { -+ wpa_printf(MSG_ERROR, "Could not set HT capabilities " -+ "for kernel driver"); -+ ret = -1; -+ } -+ -+#endif /* CONFIG_IEEE80211N */ -+ -+ if (hostapd_set_cts_protect(hapd, use_protection)) { -+ wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel " -+ "driver"); -+ ret = -1; -+ } -+ -+ if (hapd->iface->current_mode && -+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && -+ hostapd_set_short_slot_time(hapd, -+ hapd->iface->num_sta_no_short_slot_time -+ > 0 ? 0 : 1)) { -+ wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option " -+ "in kernel driver"); -+ ret = -1; -+ } -+ -+ if (hapd->iface->num_sta_no_short_preamble == 0 && -+ hapd->iconf->preamble == SHORT_PREAMBLE) -+ preamble = SHORT_PREAMBLE; -+ else -+ preamble = LONG_PREAMBLE; -+ if (hostapd_set_preamble(hapd, preamble)) { -+ wpa_printf(MSG_ERROR, "Could not set preamble for kernel " -+ "driver"); -+ ret = -1; -+ } -+ -+ if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) && -+ hapd->conf->isolate) { -+ wpa_printf(MSG_ERROR, "Could not enable AP isolation in " -+ "kernel driver"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname) -+{ -+ char force_ifname[IFNAMSIZ]; -+ u8 if_addr[ETH_ALEN]; -+ return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr, -+ NULL, NULL, force_ifname, if_addr, NULL); -+} -+ -+ -+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname) -+{ -+ return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname); -+} -+ -+ -+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, -+ int val) -+{ -+ const char *bridge = NULL; -+ -+ if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL) -+ return 0; -+ if (hapd->conf->wds_bridge[0]) -+ bridge = hapd->conf->wds_bridge; -+ else if (hapd->conf->bridge[0]) -+ bridge = hapd->conf->bridge; -+ return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val, -+ bridge); -+} -+ -+ -+int hostapd_sta_add(struct hostapd_data *hapd, -+ const u8 *addr, u16 aid, u16 capability, -+ const u8 *supp_rates, size_t supp_rates_len, -+ u16 listen_interval, -+ const struct ieee80211_ht_capabilities *ht_capab) -+{ -+ struct hostapd_sta_add_params params; -+ -+ if (hapd->driver == NULL) -+ return 0; -+ if (hapd->driver->sta_add == NULL) -+ return 0; -+ -+ os_memset(¶ms, 0, sizeof(params)); -+ params.addr = addr; -+ params.aid = aid; -+ params.capability = capability; -+ params.supp_rates = supp_rates; -+ params.supp_rates_len = supp_rates_len; -+ params.listen_interval = listen_interval; -+ params.ht_capabilities = ht_capab; -+ return hapd->driver->sta_add(hapd->drv_priv, ¶ms); -+} -+ -+ -+int hostapd_set_privacy(struct hostapd_data *hapd, int enabled) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_privacy == NULL) -+ return 0; -+ return hapd->driver->set_privacy(hapd->drv_priv, enabled); -+} -+ -+ -+int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, -+ size_t elem_len) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL) -+ return 0; -+ return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len); -+} -+ -+ -+int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len) -+{ -+ if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL) -+ return 0; -+ return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len); -+} -+ -+ -+int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len) -+{ -+ if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL) -+ return 0; -+ return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len); -+} -+ -+ -+int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, -+ const char *ifname, const u8 *addr, void *bss_ctx, -+ void **drv_priv, char *force_ifname, u8 *if_addr, -+ const char *bridge) -+{ -+ if (hapd->driver == NULL || hapd->driver->if_add == NULL) -+ return -1; -+ return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr, -+ bss_ctx, drv_priv, force_ifname, if_addr, -+ bridge); -+} -+ -+ -+int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, -+ const char *ifname) -+{ -+ if (hapd->driver == NULL || hapd->driver->if_remove == NULL) -+ return -1; -+ return hapd->driver->if_remove(hapd->drv_priv, type, ifname); -+} -+ -+ -+int hostapd_set_ieee8021x(struct hostapd_data *hapd, -+ struct wpa_bss_params *params) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL) -+ return 0; -+ return hapd->driver->set_ieee8021x(hapd->drv_priv, params); -+} -+ -+ -+int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, -+ const u8 *addr, int idx, u8 *seq) -+{ -+ if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL) -+ return 0; -+ return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx, -+ seq); -+} -+ -+ -+int hostapd_flush(struct hostapd_data *hapd) -+{ -+ if (hapd->driver == NULL || hapd->driver->flush == NULL) -+ return 0; -+ return hapd->driver->flush(hapd->drv_priv); -+} -+ -+ -+int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, -+ int channel, int ht_enabled, int sec_channel_offset) -+{ -+ struct hostapd_freq_params data; -+ if (hapd->driver == NULL) -+ return 0; -+ if (hapd->driver->set_freq == NULL) -+ return 0; -+ os_memset(&data, 0, sizeof(data)); -+ data.mode = mode; -+ data.freq = freq; -+ data.channel = channel; -+ data.ht_enabled = ht_enabled; -+ data.sec_channel_offset = sec_channel_offset; -+ return hapd->driver->set_freq(hapd->drv_priv, &data); -+} -+ -+int hostapd_set_rts(struct hostapd_data *hapd, int rts) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_rts == NULL) -+ return 0; -+ return hapd->driver->set_rts(hapd->drv_priv, rts); -+} -+ -+ -+int hostapd_set_frag(struct hostapd_data *hapd, int frag) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_frag == NULL) -+ return 0; -+ return hapd->driver->set_frag(hapd->drv_priv, frag); -+} -+ -+ -+int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, -+ int total_flags, int flags_or, int flags_and) -+{ -+ if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL) -+ return 0; -+ return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags, -+ flags_or, flags_and); -+} -+ -+ -+int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates, -+ int *basic_rates, int mode) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL) -+ return 0; -+ return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates, -+ basic_rates, mode); -+} -+ -+ -+int hostapd_set_country(struct hostapd_data *hapd, const char *country) -+{ -+ if (hapd->driver == NULL || -+ hapd->driver->set_country == NULL) -+ return 0; -+ return hapd->driver->set_country(hapd->drv_priv, country); -+} -+ -+ -+int hostapd_set_cts_protect(struct hostapd_data *hapd, int value) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL) -+ return 0; -+ return hapd->driver->set_cts_protect(hapd->drv_priv, value); -+} -+ -+ -+int hostapd_set_preamble(struct hostapd_data *hapd, int value) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_preamble == NULL) -+ return 0; -+ return hapd->driver->set_preamble(hapd->drv_priv, value); -+} -+ -+ -+int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL) -+ return 0; -+ return hapd->driver->set_short_slot_time(hapd->drv_priv, value); -+} -+ -+ -+int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, -+ int cw_min, int cw_max, int burst_time) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL) -+ return 0; -+ return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs, -+ cw_min, cw_max, burst_time); -+} -+ -+ -+int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *mask) -+{ -+ if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL) -+ return 1; -+ return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask); -+} -+ -+ -+struct hostapd_hw_modes * -+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, -+ u16 *flags) -+{ -+ if (hapd->driver == NULL || -+ hapd->driver->get_hw_feature_data == NULL) -+ return NULL; -+ return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes, -+ flags); -+} -+ -+ -+int hostapd_driver_commit(struct hostapd_data *hapd) -+{ -+ if (hapd->driver == NULL || hapd->driver->commit == NULL) -+ return 0; -+ return hapd->driver->commit(hapd->drv_priv); -+} -+ -+ -+int hostapd_set_ht_params(struct hostapd_data *hapd, -+ const u8 *ht_capab, size_t ht_capab_len, -+ const u8 *ht_oper, size_t ht_oper_len) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL || -+ ht_capab == NULL || ht_oper == NULL) -+ return 0; -+ return hapd->driver->set_ht_params(hapd->drv_priv, -+ ht_capab, ht_capab_len, -+ ht_oper, ht_oper_len); -+} -+ -+ -+int hostapd_drv_none(struct hostapd_data *hapd) -+{ -+ return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0; -+} -+ -+ -+int hostapd_driver_scan(struct hostapd_data *hapd, -+ struct wpa_driver_scan_params *params) -+{ -+ if (hapd->driver && hapd->driver->scan2) -+ return hapd->driver->scan2(hapd->drv_priv, params); -+ return -1; -+} -+ -+ -+struct wpa_scan_results * hostapd_driver_get_scan_results( -+ struct hostapd_data *hapd) -+{ -+ if (hapd->driver && hapd->driver->get_scan_results2) -+ return hapd->driver->get_scan_results2(hapd->drv_priv); -+ return NULL; -+} -+ -+ -+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, -+ int duration) -+{ -+ if (hapd->driver && hapd->driver->set_noa) -+ return hapd->driver->set_noa(hapd->drv_priv, count, start, -+ duration); -+ return -1; -+} -+ -+ -+int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_key == NULL) -+ return 0; -+ return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr, -+ key_idx, set_tx, seq, seq_len, key, -+ key_len); -+} -+ -+ -+int hostapd_drv_send_mlme(struct hostapd_data *hapd, -+ const void *msg, size_t len) -+{ -+ if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) -+ return 0; -+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len); -+} -+ -+ -+int hostapd_drv_sta_deauth(struct hostapd_data *hapd, -+ const u8 *addr, int reason) -+{ -+ if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL) -+ return 0; -+ return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr, -+ reason); -+} -+ -+ -+int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, -+ const u8 *addr, int reason) -+{ -+ if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL) -+ return 0; -+ return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr, -+ reason); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.h -new file mode 100644 -index 0000000000000..36bb826db13e6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_drv_ops.h -@@ -0,0 +1,197 @@ -+/* -+ * hostapd - Driver operations -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef AP_DRV_OPS -+#define AP_DRV_OPS -+ -+enum wpa_driver_if_type; -+struct wpa_bss_params; -+struct wpa_driver_scan_params; -+struct ieee80211_ht_capabilities; -+ -+u32 hostapd_sta_flags_to_drv(u32 flags); -+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd); -+int hostapd_set_authorized(struct hostapd_data *hapd, -+ struct sta_info *sta, int authorized); -+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta); -+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, -+ int enabled); -+int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection); -+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname); -+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname); -+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, -+ int val); -+int hostapd_sta_add(struct hostapd_data *hapd, -+ const u8 *addr, u16 aid, u16 capability, -+ const u8 *supp_rates, size_t supp_rates_len, -+ u16 listen_interval, -+ const struct ieee80211_ht_capabilities *ht_capab); -+int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); -+int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, -+ size_t elem_len); -+int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len); -+int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len); -+int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, -+ const char *ifname, const u8 *addr, void *bss_ctx, -+ void **drv_priv, char *force_ifname, u8 *if_addr, -+ const char *bridge); -+int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, -+ const char *ifname); -+int hostapd_set_ieee8021x(struct hostapd_data *hapd, -+ struct wpa_bss_params *params); -+int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, -+ const u8 *addr, int idx, u8 *seq); -+int hostapd_flush(struct hostapd_data *hapd); -+int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, -+ int channel, int ht_enabled, int sec_channel_offset); -+int hostapd_set_rts(struct hostapd_data *hapd, int rts); -+int hostapd_set_frag(struct hostapd_data *hapd, int frag); -+int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, -+ int total_flags, int flags_or, int flags_and); -+int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates, -+ int *basic_rates, int mode); -+int hostapd_set_country(struct hostapd_data *hapd, const char *country); -+int hostapd_set_cts_protect(struct hostapd_data *hapd, int value); -+int hostapd_set_preamble(struct hostapd_data *hapd, int value); -+int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value); -+int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, -+ int cw_min, int cw_max, int burst_time); -+int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *mask); -+struct hostapd_hw_modes * -+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, -+ u16 *flags); -+int hostapd_driver_commit(struct hostapd_data *hapd); -+int hostapd_set_ht_params(struct hostapd_data *hapd, -+ const u8 *ht_capab, size_t ht_capab_len, -+ const u8 *ht_oper, size_t ht_oper_len); -+int hostapd_drv_none(struct hostapd_data *hapd); -+int hostapd_driver_scan(struct hostapd_data *hapd, -+ struct wpa_driver_scan_params *params); -+struct wpa_scan_results * hostapd_driver_get_scan_results( -+ struct hostapd_data *hapd); -+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, -+ int duration); -+int hostapd_drv_set_key(const char *ifname, -+ struct hostapd_data *hapd, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len); -+int hostapd_drv_send_mlme(struct hostapd_data *hapd, -+ const void *msg, size_t len); -+int hostapd_drv_sta_deauth(struct hostapd_data *hapd, -+ const u8 *addr, int reason); -+int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, -+ const u8 *addr, int reason); -+ -+ -+#include "drivers/driver.h" -+ -+static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd, -+ int enabled) -+{ -+ if (hapd->driver == NULL || -+ hapd->driver->hapd_set_countermeasures == NULL) -+ return 0; -+ return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled); -+} -+ -+static inline int hostapd_drv_set_sta_vlan(const char *ifname, -+ struct hostapd_data *hapd, -+ const u8 *addr, int vlan_id) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL) -+ return 0; -+ return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname, -+ vlan_id); -+} -+ -+static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd, -+ const u8 *addr) -+{ -+ if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL) -+ return 0; -+ return hapd->driver->get_inact_sec(hapd->drv_priv, addr); -+} -+ -+static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd, -+ const u8 *addr) -+{ -+ if (hapd->driver == NULL || hapd->driver->sta_remove == NULL) -+ return 0; -+ return hapd->driver->sta_remove(hapd->drv_priv, addr); -+} -+ -+static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd, -+ const u8 *addr, const u8 *data, -+ size_t data_len, int encrypt, -+ u32 flags) -+{ -+ if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL) -+ return 0; -+ return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data, -+ data_len, encrypt, -+ hapd->own_addr, flags); -+} -+ -+static inline int hostapd_drv_read_sta_data( -+ struct hostapd_data *hapd, struct hostap_sta_driver_data *data, -+ const u8 *addr) -+{ -+ if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL) -+ return -1; -+ return hapd->driver->read_sta_data(hapd->drv_priv, data, addr); -+} -+ -+static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd, -+ const u8 *addr) -+{ -+ if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL) -+ return 0; -+ return hapd->driver->sta_clear_stats(hapd->drv_priv, addr); -+} -+ -+static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd, -+ const u8 *head, size_t head_len, -+ const u8 *tail, size_t tail_len, -+ int dtim_period, int beacon_int) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_beacon == NULL) -+ return 0; -+ return hapd->driver->set_beacon(hapd->drv_priv, -+ head, head_len, tail, tail_len, -+ dtim_period, beacon_int); -+} -+ -+static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd, -+ const u8 *mac, int accepted, -+ u32 session_timeout) -+{ -+ if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL) -+ return 0; -+ return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted, -+ session_timeout); -+} -+ -+static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd, -+ const u8 *mac) -+{ -+ if (hapd->driver == NULL || -+ hapd->driver->set_radius_acl_expire == NULL) -+ return 0; -+ return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac); -+} -+ -+#endif /* AP_DRV_OPS */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.c -new file mode 100644 -index 0000000000000..9b9fc9ebf3c3d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.c -@@ -0,0 +1,399 @@ -+/* -+ * hostapd / AP table -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * Copyright (c) 2003-2004, Instant802 Networks, Inc. -+ * Copyright (c) 2006, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "drivers/driver.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ieee802_11.h" -+#include "sta_info.h" -+#include "beacon.h" -+#include "ap_list.h" -+ -+ -+/* AP list is a double linked list with head->prev pointing to the end of the -+ * list and tail->next = NULL. Entries are moved to the head of the list -+ * whenever a beacon has been received from the AP in question. The tail entry -+ * in this link will thus be the least recently used entry. */ -+ -+ -+static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap) -+{ -+ int i; -+ -+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G || -+ iface->conf->channel != ap->channel) -+ return 0; -+ -+ if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT)) -+ return 1; -+ -+ for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) { -+ int rate = (ap->supported_rates[i] & 0x7f) * 5; -+ if (rate == 60 || rate == 90 || rate > 110) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+ -+struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap) -+{ -+ struct ap_info *s; -+ -+ s = iface->ap_hash[STA_HASH(ap)]; -+ while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0) -+ s = s->hnext; -+ return s; -+} -+ -+ -+static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap) -+{ -+ if (iface->ap_list) { -+ ap->prev = iface->ap_list->prev; -+ iface->ap_list->prev = ap; -+ } else -+ ap->prev = ap; -+ ap->next = iface->ap_list; -+ iface->ap_list = ap; -+} -+ -+ -+static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap) -+{ -+ if (iface->ap_list == ap) -+ iface->ap_list = ap->next; -+ else -+ ap->prev->next = ap->next; -+ -+ if (ap->next) -+ ap->next->prev = ap->prev; -+ else if (iface->ap_list) -+ iface->ap_list->prev = ap->prev; -+} -+ -+ -+static void ap_ap_iter_list_add(struct hostapd_iface *iface, -+ struct ap_info *ap) -+{ -+ if (iface->ap_iter_list) { -+ ap->iter_prev = iface->ap_iter_list->iter_prev; -+ iface->ap_iter_list->iter_prev = ap; -+ } else -+ ap->iter_prev = ap; -+ ap->iter_next = iface->ap_iter_list; -+ iface->ap_iter_list = ap; -+} -+ -+ -+static void ap_ap_iter_list_del(struct hostapd_iface *iface, -+ struct ap_info *ap) -+{ -+ if (iface->ap_iter_list == ap) -+ iface->ap_iter_list = ap->iter_next; -+ else -+ ap->iter_prev->iter_next = ap->iter_next; -+ -+ if (ap->iter_next) -+ ap->iter_next->iter_prev = ap->iter_prev; -+ else if (iface->ap_iter_list) -+ iface->ap_iter_list->iter_prev = ap->iter_prev; -+} -+ -+ -+static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap) -+{ -+ ap->hnext = iface->ap_hash[STA_HASH(ap->addr)]; -+ iface->ap_hash[STA_HASH(ap->addr)] = ap; -+} -+ -+ -+static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap) -+{ -+ struct ap_info *s; -+ -+ s = iface->ap_hash[STA_HASH(ap->addr)]; -+ if (s == NULL) return; -+ if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) { -+ iface->ap_hash[STA_HASH(ap->addr)] = s->hnext; -+ return; -+ } -+ -+ while (s->hnext != NULL && -+ os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0) -+ s = s->hnext; -+ if (s->hnext != NULL) -+ s->hnext = s->hnext->hnext; -+ else -+ printf("AP: could not remove AP " MACSTR " from hash table\n", -+ MAC2STR(ap->addr)); -+} -+ -+ -+static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap) -+{ -+ ap_ap_hash_del(iface, ap); -+ ap_ap_list_del(iface, ap); -+ ap_ap_iter_list_del(iface, ap); -+ -+ iface->num_ap--; -+ os_free(ap); -+} -+ -+ -+static void hostapd_free_aps(struct hostapd_iface *iface) -+{ -+ struct ap_info *ap, *prev; -+ -+ ap = iface->ap_list; -+ -+ while (ap) { -+ prev = ap; -+ ap = ap->next; -+ ap_free_ap(iface, prev); -+ } -+ -+ iface->ap_list = NULL; -+} -+ -+ -+int ap_ap_for_each(struct hostapd_iface *iface, -+ int (*func)(struct ap_info *s, void *data), void *data) -+{ -+ struct ap_info *s; -+ int ret = 0; -+ -+ s = iface->ap_list; -+ -+ while (s) { -+ ret = func(s, data); -+ if (ret) -+ break; -+ s = s->next; -+ } -+ -+ return ret; -+} -+ -+ -+static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr) -+{ -+ struct ap_info *ap; -+ -+ ap = os_zalloc(sizeof(struct ap_info)); -+ if (ap == NULL) -+ return NULL; -+ -+ /* initialize AP info data */ -+ os_memcpy(ap->addr, addr, ETH_ALEN); -+ ap_ap_list_add(iface, ap); -+ iface->num_ap++; -+ ap_ap_hash_add(iface, ap); -+ ap_ap_iter_list_add(iface, ap); -+ -+ if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) { -+ wpa_printf(MSG_DEBUG, "Removing the least recently used AP " -+ MACSTR " from AP table", MAC2STR(ap->prev->addr)); -+ ap_free_ap(iface, ap->prev); -+ } -+ -+ return ap; -+} -+ -+ -+void ap_list_process_beacon(struct hostapd_iface *iface, -+ const struct ieee80211_mgmt *mgmt, -+ struct ieee802_11_elems *elems, -+ struct hostapd_frame_info *fi) -+{ -+ struct ap_info *ap; -+ struct os_time now; -+ int new_ap = 0; -+ size_t len; -+ int set_beacon = 0; -+ -+ if (iface->conf->ap_table_max_size < 1) -+ return; -+ -+ ap = ap_get_ap(iface, mgmt->bssid); -+ if (!ap) { -+ ap = ap_ap_add(iface, mgmt->bssid); -+ if (!ap) { -+ printf("Failed to allocate AP information entry\n"); -+ return; -+ } -+ new_ap = 1; -+ } -+ -+ ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int); -+ ap->capability = le_to_host16(mgmt->u.beacon.capab_info); -+ -+ if (elems->ssid) { -+ len = elems->ssid_len; -+ if (len >= sizeof(ap->ssid)) -+ len = sizeof(ap->ssid) - 1; -+ os_memcpy(ap->ssid, elems->ssid, len); -+ ap->ssid[len] = '\0'; -+ ap->ssid_len = len; -+ } -+ -+ os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX); -+ len = 0; -+ if (elems->supp_rates) { -+ len = elems->supp_rates_len; -+ if (len > WLAN_SUPP_RATES_MAX) -+ len = WLAN_SUPP_RATES_MAX; -+ os_memcpy(ap->supported_rates, elems->supp_rates, len); -+ } -+ if (elems->ext_supp_rates) { -+ int len2; -+ if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX) -+ len2 = WLAN_SUPP_RATES_MAX - len; -+ else -+ len2 = elems->ext_supp_rates_len; -+ os_memcpy(ap->supported_rates + len, elems->ext_supp_rates, -+ len2); -+ } -+ -+ ap->wpa = elems->wpa_ie != NULL; -+ -+ if (elems->erp_info && elems->erp_info_len == 1) -+ ap->erp = elems->erp_info[0]; -+ else -+ ap->erp = -1; -+ -+ if (elems->ds_params && elems->ds_params_len == 1) -+ ap->channel = elems->ds_params[0]; -+ else if (fi) -+ ap->channel = fi->channel; -+ -+ if (elems->ht_capabilities) -+ ap->ht_support = 1; -+ else -+ ap->ht_support = 0; -+ -+ ap->num_beacons++; -+ os_get_time(&now); -+ ap->last_beacon = now.sec; -+ if (fi) { -+ ap->ssi_signal = fi->ssi_signal; -+ ap->datarate = fi->datarate; -+ } -+ -+ if (!new_ap && ap != iface->ap_list) { -+ /* move AP entry into the beginning of the list so that the -+ * oldest entry is always in the end of the list */ -+ ap_ap_list_del(iface, ap); -+ ap_ap_list_add(iface, ap); -+ } -+ -+ if (!iface->olbc && -+ ap_list_beacon_olbc(iface, ap)) { -+ iface->olbc = 1; -+ wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable " -+ "protection", MAC2STR(ap->addr)); -+ set_beacon++; -+ } -+ -+#ifdef CONFIG_IEEE80211N -+ if (!iface->olbc_ht && !ap->ht_support) { -+ iface->olbc_ht = 1; -+ hostapd_ht_operation_update(iface); -+ wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR -+ " - enable protection", MAC2STR(ap->addr)); -+ set_beacon++; -+ } -+#endif /* CONFIG_IEEE80211N */ -+ -+ if (set_beacon) -+ ieee802_11_set_beacons(iface); -+} -+ -+ -+static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_iface *iface = eloop_ctx; -+ struct os_time now; -+ struct ap_info *ap; -+ int set_beacon = 0; -+ -+ eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); -+ -+ if (!iface->ap_list) -+ return; -+ -+ os_get_time(&now); -+ -+ while (iface->ap_list) { -+ ap = iface->ap_list->prev; -+ if (ap->last_beacon + iface->conf->ap_table_expiration_time >= -+ now.sec) -+ break; -+ -+ ap_free_ap(iface, ap); -+ } -+ -+ if (iface->olbc || iface->olbc_ht) { -+ int olbc = 0; -+ int olbc_ht = 0; -+ -+ ap = iface->ap_list; -+ while (ap && (olbc == 0 || olbc_ht == 0)) { -+ if (ap_list_beacon_olbc(iface, ap)) -+ olbc = 1; -+ if (!ap->ht_support) -+ olbc_ht = 1; -+ ap = ap->next; -+ } -+ if (!olbc && iface->olbc) { -+ wpa_printf(MSG_DEBUG, "OLBC not detected anymore"); -+ iface->olbc = 0; -+ set_beacon++; -+ } -+#ifdef CONFIG_IEEE80211N -+ if (!olbc_ht && iface->olbc_ht) { -+ wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore"); -+ iface->olbc_ht = 0; -+ hostapd_ht_operation_update(iface); -+ set_beacon++; -+ } -+#endif /* CONFIG_IEEE80211N */ -+ } -+ -+ if (set_beacon) -+ ieee802_11_set_beacons(iface); -+} -+ -+ -+int ap_list_init(struct hostapd_iface *iface) -+{ -+ eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); -+ return 0; -+} -+ -+ -+void ap_list_deinit(struct hostapd_iface *iface) -+{ -+ eloop_cancel_timeout(ap_list_timer, iface, NULL); -+ hostapd_free_aps(iface); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.h -new file mode 100644 -index 0000000000000..6df8981c58d2a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_list.h -@@ -0,0 +1,78 @@ -+/* -+ * hostapd / AP table -+ * Copyright (c) 2002-2003, Jouni Malinen -+ * Copyright (c) 2003-2004, Instant802 Networks, Inc. -+ * Copyright (c) 2006, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef AP_LIST_H -+#define AP_LIST_H -+ -+struct ap_info { -+ /* Note: next/prev pointers are updated whenever a new beacon is -+ * received because these are used to find the least recently used -+ * entries. iter_next/iter_prev are updated only when adding new BSSes -+ * and when removing old ones. These should be used when iterating -+ * through the table in a manner that allows beacons to be received -+ * during the iteration. */ -+ struct ap_info *next; /* next entry in AP list */ -+ struct ap_info *prev; /* previous entry in AP list */ -+ struct ap_info *hnext; /* next entry in hash table list */ -+ struct ap_info *iter_next; /* next entry in AP iteration list */ -+ struct ap_info *iter_prev; /* previous entry in AP iteration list */ -+ u8 addr[6]; -+ u16 beacon_int; -+ u16 capability; -+ u8 supported_rates[WLAN_SUPP_RATES_MAX]; -+ u8 ssid[33]; -+ size_t ssid_len; -+ int wpa; -+ int erp; /* ERP Info or -1 if ERP info element not present */ -+ -+ int channel; -+ int datarate; /* in 100 kbps */ -+ int ssi_signal; -+ -+ int ht_support; -+ -+ unsigned int num_beacons; /* number of beacon frames received */ -+ os_time_t last_beacon; -+ -+ int already_seen; /* whether API call AP-NEW has already fetched -+ * information about this AP */ -+}; -+ -+struct ieee802_11_elems; -+struct hostapd_frame_info; -+ -+struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta); -+int ap_ap_for_each(struct hostapd_iface *iface, -+ int (*func)(struct ap_info *s, void *data), void *data); -+void ap_list_process_beacon(struct hostapd_iface *iface, -+ const struct ieee80211_mgmt *mgmt, -+ struct ieee802_11_elems *elems, -+ struct hostapd_frame_info *fi); -+#ifdef NEED_AP_MLME -+int ap_list_init(struct hostapd_iface *iface); -+void ap_list_deinit(struct hostapd_iface *iface); -+#else /* NEED_AP_MLME */ -+static inline int ap_list_init(struct hostapd_iface *iface) -+{ -+ return 0; -+} -+ -+static inline void ap_list_deinit(struct hostapd_iface *iface) -+{ -+} -+#endif /* NEED_AP_MLME */ -+ -+#endif /* AP_LIST_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.c -new file mode 100644 -index 0000000000000..2b09b11e79c17 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.c -@@ -0,0 +1,184 @@ -+/* -+ * hostapd / IEEE 802.11 MLME -+ * Copyright 2003-2006, Jouni Malinen -+ * Copyright 2003-2004, Instant802 Networks, Inc. -+ * Copyright 2005-2006, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "ieee802_11.h" -+#include "wpa_auth.h" -+#include "sta_info.h" -+#include "ap_mlme.h" -+ -+ -+#ifndef CONFIG_NO_HOSTAPD_LOGGER -+static const char * mlme_auth_alg_str(int alg) -+{ -+ switch (alg) { -+ case WLAN_AUTH_OPEN: -+ return "OPEN_SYSTEM"; -+ case WLAN_AUTH_SHARED_KEY: -+ return "SHARED_KEY"; -+ case WLAN_AUTH_FT: -+ return "FT"; -+ } -+ -+ return "unknown"; -+} -+#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -+ -+ -+/** -+ * mlme_authenticate_indication - Report the establishment of an authentication -+ * relationship with a specific peer MAC entity -+ * @hapd: BSS data -+ * @sta: peer STA data -+ * -+ * MLME calls this function as a result of the establishment of an -+ * authentication relationship with a specific peer MAC entity that -+ * resulted from an authentication procedure that was initiated by -+ * that specific peer MAC entity. -+ * -+ * PeerSTAAddress = sta->addr -+ * AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY) -+ */ -+void mlme_authenticate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, -+ HOSTAPD_LEVEL_DEBUG, -+ "MLME-AUTHENTICATE.indication(" MACSTR ", %s)", -+ MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg)); -+ if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP)) -+ mlme_deletekeys_request(hapd, sta); -+} -+ -+ -+/** -+ * mlme_deauthenticate_indication - Report the invalidation of an -+ * authentication relationship with a specific peer MAC entity -+ * @hapd: BSS data -+ * @sta: Peer STA data -+ * @reason_code: ReasonCode from Deauthentication frame -+ * -+ * MLME calls this function as a result of the invalidation of an -+ * authentication relationship with a specific peer MAC entity. -+ * -+ * PeerSTAAddress = sta->addr -+ */ -+void mlme_deauthenticate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta, u16 reason_code) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, -+ HOSTAPD_LEVEL_DEBUG, -+ "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)", -+ MAC2STR(sta->addr), reason_code); -+ mlme_deletekeys_request(hapd, sta); -+} -+ -+ -+/** -+ * mlme_associate_indication - Report the establishment of an association with -+ * a specific peer MAC entity -+ * @hapd: BSS data -+ * @sta: peer STA data -+ * -+ * MLME calls this function as a result of the establishment of an -+ * association with a specific peer MAC entity that resulted from an -+ * association procedure that was initiated by that specific peer MAC entity. -+ * -+ * PeerSTAAddress = sta->addr -+ */ -+void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, -+ HOSTAPD_LEVEL_DEBUG, -+ "MLME-ASSOCIATE.indication(" MACSTR ")", -+ MAC2STR(sta->addr)); -+ if (sta->auth_alg != WLAN_AUTH_FT) -+ mlme_deletekeys_request(hapd, sta); -+} -+ -+ -+/** -+ * mlme_reassociate_indication - Report the establishment of an reassociation -+ * with a specific peer MAC entity -+ * @hapd: BSS data -+ * @sta: peer STA data -+ * -+ * MLME calls this function as a result of the establishment of an -+ * reassociation with a specific peer MAC entity that resulted from a -+ * reassociation procedure that was initiated by that specific peer MAC entity. -+ * -+ * PeerSTAAddress = sta->addr -+ * -+ * sta->previous_ap contains the "Current AP" information from ReassocReq. -+ */ -+void mlme_reassociate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, -+ HOSTAPD_LEVEL_DEBUG, -+ "MLME-REASSOCIATE.indication(" MACSTR ")", -+ MAC2STR(sta->addr)); -+ if (sta->auth_alg != WLAN_AUTH_FT) -+ mlme_deletekeys_request(hapd, sta); -+} -+ -+ -+/** -+ * mlme_disassociate_indication - Report disassociation with a specific peer -+ * MAC entity -+ * @hapd: BSS data -+ * @sta: Peer STA data -+ * @reason_code: ReasonCode from Disassociation frame -+ * -+ * MLME calls this function as a result of the invalidation of an association -+ * relationship with a specific peer MAC entity. -+ * -+ * PeerSTAAddress = sta->addr -+ */ -+void mlme_disassociate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta, u16 reason_code) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, -+ HOSTAPD_LEVEL_DEBUG, -+ "MLME-DISASSOCIATE.indication(" MACSTR ", %d)", -+ MAC2STR(sta->addr), reason_code); -+ mlme_deletekeys_request(hapd, sta); -+} -+ -+ -+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd, -+ const u8 *addr) -+{ -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME, -+ HOSTAPD_LEVEL_DEBUG, -+ "MLME-MichaelMICFailure.indication(" MACSTR ")", -+ MAC2STR(addr)); -+} -+ -+ -+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME, -+ HOSTAPD_LEVEL_DEBUG, -+ "MLME-DELETEKEYS.request(" MACSTR ")", -+ MAC2STR(sta->addr)); -+ -+ if (sta->wpa_sm) -+ wpa_remove_ptk(sta->wpa_sm); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.h -new file mode 100644 -index 0000000000000..c77a9390a8b63 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ap_mlme.h -@@ -0,0 +1,40 @@ -+/* -+ * hostapd / IEEE 802.11 MLME -+ * Copyright 2003, Jouni Malinen -+ * Copyright 2003-2004, Instant802 Networks, Inc. -+ * Copyright 2005-2006, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef MLME_H -+#define MLME_H -+ -+void mlme_authenticate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta); -+ -+void mlme_deauthenticate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta, u16 reason_code); -+ -+void mlme_associate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta); -+ -+void mlme_reassociate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta); -+ -+void mlme_disassociate_indication(struct hostapd_data *hapd, -+ struct sta_info *sta, u16 reason_code); -+ -+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd, -+ const u8 *addr); -+ -+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta); -+ -+#endif /* MLME_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.c -new file mode 100644 -index 0000000000000..7c87fde4154b9 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.c -@@ -0,0 +1,217 @@ -+/* -+ * Authentication server setup -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "crypto/tls.h" -+#include "eap_server/eap.h" -+#include "eap_server/eap_sim_db.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "radius/radius_server.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "sta_info.h" -+#include "authsrv.h" -+ -+ -+#if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA) -+#define EAP_SIM_DB -+#endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */ -+ -+ -+#ifdef EAP_SIM_DB -+static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd, -+ struct sta_info *sta, void *ctx) -+{ -+ if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0) -+ return 1; -+ return 0; -+} -+ -+ -+static void hostapd_sim_db_cb(void *ctx, void *session_ctx) -+{ -+ struct hostapd_data *hapd = ctx; -+ if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) { -+#ifdef RADIUS_SERVER -+ radius_server_eap_pending_cb(hapd->radius_srv, session_ctx); -+#endif /* RADIUS_SERVER */ -+ } -+} -+#endif /* EAP_SIM_DB */ -+ -+ -+#ifdef RADIUS_SERVER -+ -+static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, -+ size_t identity_len, int phase2, -+ struct eap_user *user) -+{ -+ const struct hostapd_eap_user *eap_user; -+ int i, count; -+ -+ eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); -+ if (eap_user == NULL) -+ return -1; -+ -+ if (user == NULL) -+ return 0; -+ -+ os_memset(user, 0, sizeof(*user)); -+ count = EAP_USER_MAX_METHODS; -+ if (count > EAP_MAX_METHODS) -+ count = EAP_MAX_METHODS; -+ for (i = 0; i < count; i++) { -+ user->methods[i].vendor = eap_user->methods[i].vendor; -+ user->methods[i].method = eap_user->methods[i].method; -+ } -+ -+ if (eap_user->password) { -+ user->password = os_malloc(eap_user->password_len); -+ if (user->password == NULL) -+ return -1; -+ os_memcpy(user->password, eap_user->password, -+ eap_user->password_len); -+ user->password_len = eap_user->password_len; -+ user->password_hash = eap_user->password_hash; -+ } -+ user->force_version = eap_user->force_version; -+ user->ttls_auth = eap_user->ttls_auth; -+ -+ return 0; -+} -+ -+ -+static int hostapd_setup_radius_srv(struct hostapd_data *hapd) -+{ -+ struct radius_server_conf srv; -+ struct hostapd_bss_config *conf = hapd->conf; -+ os_memset(&srv, 0, sizeof(srv)); -+ srv.client_file = conf->radius_server_clients; -+ srv.auth_port = conf->radius_server_auth_port; -+ srv.conf_ctx = conf; -+ srv.eap_sim_db_priv = hapd->eap_sim_db_priv; -+ srv.ssl_ctx = hapd->ssl_ctx; -+ srv.msg_ctx = hapd->msg_ctx; -+ srv.pac_opaque_encr_key = conf->pac_opaque_encr_key; -+ srv.eap_fast_a_id = conf->eap_fast_a_id; -+ srv.eap_fast_a_id_len = conf->eap_fast_a_id_len; -+ srv.eap_fast_a_id_info = conf->eap_fast_a_id_info; -+ srv.eap_fast_prov = conf->eap_fast_prov; -+ srv.pac_key_lifetime = conf->pac_key_lifetime; -+ srv.pac_key_refresh_time = conf->pac_key_refresh_time; -+ srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; -+ srv.tnc = conf->tnc; -+ srv.wps = hapd->wps; -+ srv.ipv6 = conf->radius_server_ipv6; -+ srv.get_eap_user = hostapd_radius_get_eap_user; -+ srv.eap_req_id_text = conf->eap_req_id_text; -+ srv.eap_req_id_text_len = conf->eap_req_id_text_len; -+ srv.pwd_group = conf->pwd_group; -+ -+ hapd->radius_srv = radius_server_init(&srv); -+ if (hapd->radius_srv == NULL) { -+ wpa_printf(MSG_ERROR, "RADIUS server initialization failed."); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+#endif /* RADIUS_SERVER */ -+ -+ -+int authsrv_init(struct hostapd_data *hapd) -+{ -+#ifdef EAP_TLS_FUNCS -+ if (hapd->conf->eap_server && -+ (hapd->conf->ca_cert || hapd->conf->server_cert || -+ hapd->conf->dh_file)) { -+ struct tls_connection_params params; -+ -+ hapd->ssl_ctx = tls_init(NULL); -+ if (hapd->ssl_ctx == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to initialize TLS"); -+ authsrv_deinit(hapd); -+ return -1; -+ } -+ -+ os_memset(¶ms, 0, sizeof(params)); -+ params.ca_cert = hapd->conf->ca_cert; -+ params.client_cert = hapd->conf->server_cert; -+ params.private_key = hapd->conf->private_key; -+ params.private_key_passwd = hapd->conf->private_key_passwd; -+ params.dh_file = hapd->conf->dh_file; -+ -+ if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) { -+ wpa_printf(MSG_ERROR, "Failed to set TLS parameters"); -+ authsrv_deinit(hapd); -+ return -1; -+ } -+ -+ if (tls_global_set_verify(hapd->ssl_ctx, -+ hapd->conf->check_crl)) { -+ wpa_printf(MSG_ERROR, "Failed to enable check_crl"); -+ authsrv_deinit(hapd); -+ return -1; -+ } -+ } -+#endif /* EAP_TLS_FUNCS */ -+ -+#ifdef EAP_SIM_DB -+ if (hapd->conf->eap_sim_db) { -+ hapd->eap_sim_db_priv = -+ eap_sim_db_init(hapd->conf->eap_sim_db, -+ hostapd_sim_db_cb, hapd); -+ if (hapd->eap_sim_db_priv == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM " -+ "database interface"); -+ authsrv_deinit(hapd); -+ return -1; -+ } -+ } -+#endif /* EAP_SIM_DB */ -+ -+#ifdef RADIUS_SERVER -+ if (hapd->conf->radius_server_clients && -+ hostapd_setup_radius_srv(hapd)) -+ return -1; -+#endif /* RADIUS_SERVER */ -+ -+ return 0; -+} -+ -+ -+void authsrv_deinit(struct hostapd_data *hapd) -+{ -+#ifdef RADIUS_SERVER -+ radius_server_deinit(hapd->radius_srv); -+ hapd->radius_srv = NULL; -+#endif /* RADIUS_SERVER */ -+ -+#ifdef EAP_TLS_FUNCS -+ if (hapd->ssl_ctx) { -+ tls_deinit(hapd->ssl_ctx); -+ hapd->ssl_ctx = NULL; -+ } -+#endif /* EAP_TLS_FUNCS */ -+ -+#ifdef EAP_SIM_DB -+ if (hapd->eap_sim_db_priv) { -+ eap_sim_db_deinit(hapd->eap_sim_db_priv); -+ hapd->eap_sim_db_priv = NULL; -+ } -+#endif /* EAP_SIM_DB */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.h -new file mode 100644 -index 0000000000000..be3051ebfa2ec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/authsrv.h -@@ -0,0 +1,21 @@ -+/* -+ * Authentication server setup -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef AUTHSRV_H -+#define AUTHSRV_H -+ -+int authsrv_init(struct hostapd_data *hapd); -+void authsrv_deinit(struct hostapd_data *hapd); -+ -+#endif /* AUTHSRV_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.c -new file mode 100644 -index 0000000000000..784f1344bc46b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.c -@@ -0,0 +1,540 @@ -+/* -+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response -+ * Copyright (c) 2002-2004, Instant802 Networks, Inc. -+ * Copyright (c) 2005-2006, Devicescape Software, Inc. -+ * Copyright (c) 2008-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "drivers/driver.h" -+#include "wps/wps_defs.h" -+#include "p2p/p2p.h" -+#include "hostapd.h" -+#include "ieee802_11.h" -+#include "wpa_auth.h" -+#include "wmm.h" -+#include "ap_config.h" -+#include "sta_info.h" -+#include "p2p_hostapd.h" -+#include "ap_drv_ops.h" -+#include "beacon.h" -+ -+ -+static u8 ieee802_11_erp_info(struct hostapd_data *hapd) -+{ -+ u8 erp = 0; -+ -+ if (hapd->iface->current_mode == NULL || -+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) -+ return 0; -+ -+ switch (hapd->iconf->cts_protection_type) { -+ case CTS_PROTECTION_FORCE_ENABLED: -+ erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION; -+ break; -+ case CTS_PROTECTION_FORCE_DISABLED: -+ erp = 0; -+ break; -+ case CTS_PROTECTION_AUTOMATIC: -+ if (hapd->iface->olbc) -+ erp |= ERP_INFO_USE_PROTECTION; -+ /* continue */ -+ case CTS_PROTECTION_AUTOMATIC_NO_OLBC: -+ if (hapd->iface->num_sta_non_erp > 0) { -+ erp |= ERP_INFO_NON_ERP_PRESENT | -+ ERP_INFO_USE_PROTECTION; -+ } -+ break; -+ } -+ if (hapd->iface->num_sta_no_short_preamble > 0 || -+ hapd->iconf->preamble == LONG_PREAMBLE) -+ erp |= ERP_INFO_BARKER_PREAMBLE_MODE; -+ -+ return erp; -+} -+ -+ -+static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid) -+{ -+ *eid++ = WLAN_EID_DS_PARAMS; -+ *eid++ = 1; -+ *eid++ = hapd->iconf->channel; -+ return eid; -+} -+ -+ -+static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid) -+{ -+ if (hapd->iface->current_mode == NULL || -+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) -+ return eid; -+ -+ /* Set NonERP_present and use_protection bits if there -+ * are any associated NonERP stations. */ -+ /* TODO: use_protection bit can be set to zero even if -+ * there are NonERP stations present. This optimization -+ * might be useful if NonERP stations are "quiet". -+ * See 802.11g/D6 E-1 for recommended practice. -+ * In addition, Non ERP present might be set, if AP detects Non ERP -+ * operation on other APs. */ -+ -+ /* Add ERP Information element */ -+ *eid++ = WLAN_EID_ERP_INFO; -+ *eid++ = 1; -+ *eid++ = ieee802_11_erp_info(hapd); -+ -+ return eid; -+} -+ -+ -+static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, -+ struct hostapd_channel_data *start, -+ struct hostapd_channel_data *prev) -+{ -+ if (end - pos < 3) -+ return pos; -+ -+ /* first channel number */ -+ *pos++ = start->chan; -+ /* number of channels */ -+ *pos++ = (prev->chan - start->chan) / chan_spacing + 1; -+ /* maximum transmit power level */ -+ *pos++ = start->max_tx_power; -+ -+ return pos; -+} -+ -+ -+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, -+ int max_len) -+{ -+ u8 *pos = eid; -+ u8 *end = eid + max_len; -+ int i; -+ struct hostapd_hw_modes *mode; -+ struct hostapd_channel_data *start, *prev; -+ int chan_spacing = 1; -+ -+ if (!hapd->iconf->ieee80211d || max_len < 6 || -+ hapd->iface->current_mode == NULL) -+ return eid; -+ -+ *pos++ = WLAN_EID_COUNTRY; -+ pos++; /* length will be set later */ -+ os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ -+ pos += 3; -+ -+ mode = hapd->iface->current_mode; -+ if (mode->mode == HOSTAPD_MODE_IEEE80211A) -+ chan_spacing = 4; -+ -+ start = prev = NULL; -+ for (i = 0; i < mode->num_channels; i++) { -+ struct hostapd_channel_data *chan = &mode->channels[i]; -+ if (chan->flag & HOSTAPD_CHAN_DISABLED) -+ continue; -+ if (start && prev && -+ prev->chan + chan_spacing == chan->chan && -+ start->max_tx_power == chan->max_tx_power) { -+ prev = chan; -+ continue; /* can use same entry */ -+ } -+ -+ if (start) { -+ pos = hostapd_eid_country_add(pos, end, chan_spacing, -+ start, prev); -+ start = NULL; -+ } -+ -+ /* Start new group */ -+ start = prev = chan; -+ } -+ -+ if (start) { -+ pos = hostapd_eid_country_add(pos, end, chan_spacing, -+ start, prev); -+ } -+ -+ if ((pos - eid) & 1) { -+ if (end - pos < 1) -+ return eid; -+ *pos++ = 0; /* pad for 16-bit alignment */ -+ } -+ -+ eid[1] = (pos - eid) - 2; -+ -+ return pos; -+} -+ -+ -+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len, -+ struct sta_info *sta) -+{ -+ const u8 *ie; -+ size_t ielen; -+ -+ ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); -+ if (ie == NULL || ielen > len) -+ return eid; -+ -+ os_memcpy(eid, ie, ielen); -+ return eid + ielen; -+} -+ -+ -+void handle_probe_req(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len) -+{ -+ struct ieee80211_mgmt *resp; -+ struct ieee802_11_elems elems; -+ char *ssid; -+ u8 *pos, *epos; -+ const u8 *ie; -+ size_t ssid_len, ie_len; -+ struct sta_info *sta = NULL; -+ size_t buflen; -+ size_t i; -+ -+ ie = mgmt->u.probe_req.variable; -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) -+ return; -+ ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); -+ -+ for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) -+ if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, -+ mgmt->sa, ie, ie_len) > 0) -+ return; -+ -+ if (!hapd->iconf->send_probe_response) -+ return; -+ -+ if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { -+ wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR, -+ MAC2STR(mgmt->sa)); -+ return; -+ } -+ -+ ssid = NULL; -+ ssid_len = 0; -+ -+ if ((!elems.ssid || !elems.supp_rates)) { -+ wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request " -+ "without SSID or supported rates element", -+ MAC2STR(mgmt->sa)); -+ return; -+ } -+ -+#ifdef CONFIG_P2P -+ if (hapd->p2p && elems.wps_ie) { -+ struct wpabuf *wps; -+ wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); -+ if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) { -+ wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request " -+ "due to mismatch with Requested Device " -+ "Type"); -+ wpabuf_free(wps); -+ return; -+ } -+ wpabuf_free(wps); -+ } -+#endif /* CONFIG_P2P */ -+ -+ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) { -+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " -+ "broadcast SSID ignored", MAC2STR(mgmt->sa)); -+ return; -+ } -+ -+ sta = ap_get_sta(hapd, mgmt->sa); -+ -+#ifdef CONFIG_P2P -+ if ((hapd->conf->p2p & P2P_GROUP_OWNER) && -+ elems.ssid_len == P2P_WILDCARD_SSID_LEN && -+ os_memcmp(elems.ssid, P2P_WILDCARD_SSID, -+ P2P_WILDCARD_SSID_LEN) == 0) { -+ /* Process P2P Wildcard SSID like Wildcard SSID */ -+ elems.ssid_len = 0; -+ } -+#endif /* CONFIG_P2P */ -+ -+ if (elems.ssid_len == 0 || -+ (elems.ssid_len == hapd->conf->ssid.ssid_len && -+ os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == -+ 0)) { -+ ssid = hapd->conf->ssid.ssid; -+ ssid_len = hapd->conf->ssid.ssid_len; -+ if (sta) -+ sta->ssid_probe = &hapd->conf->ssid; -+ } -+ -+ if (!ssid) { -+ if (!(mgmt->da[0] & 0x01)) { -+ char ssid_txt[33]; -+ ieee802_11_print_ssid(ssid_txt, elems.ssid, -+ elems.ssid_len); -+ wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR -+ " for foreign SSID '%s' (DA " MACSTR ")", -+ MAC2STR(mgmt->sa), ssid_txt, -+ MAC2STR(mgmt->da)); -+ } -+ return; -+ } -+ -+ /* TODO: verify that supp_rates contains at least one matching rate -+ * with AP configuration */ -+#define MAX_PROBERESP_LEN 768 -+ buflen = MAX_PROBERESP_LEN; -+#ifdef CONFIG_WPS -+ if (hapd->wps_probe_resp_ie) -+ buflen += wpabuf_len(hapd->wps_probe_resp_ie); -+#endif /* CONFIG_WPS */ -+#ifdef CONFIG_P2P -+ if (hapd->p2p_probe_resp_ie) -+ buflen += wpabuf_len(hapd->p2p_probe_resp_ie); -+#endif /* CONFIG_P2P */ -+ resp = os_zalloc(buflen); -+ if (resp == NULL) -+ return; -+ epos = ((u8 *) resp) + MAX_PROBERESP_LEN; -+ -+ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_PROBE_RESP); -+ os_memcpy(resp->da, mgmt->sa, ETH_ALEN); -+ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); -+ -+ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); -+ resp->u.probe_resp.beacon_int = -+ host_to_le16(hapd->iconf->beacon_int); -+ -+ /* hardware or low-level driver will setup seq_ctrl and timestamp */ -+ resp->u.probe_resp.capab_info = -+ host_to_le16(hostapd_own_capab_info(hapd, sta, 1)); -+ -+ pos = resp->u.probe_resp.variable; -+ *pos++ = WLAN_EID_SSID; -+ *pos++ = ssid_len; -+ os_memcpy(pos, ssid, ssid_len); -+ pos += ssid_len; -+ -+ /* Supported rates */ -+ pos = hostapd_eid_supp_rates(hapd, pos); -+ -+ /* DS Params */ -+ pos = hostapd_eid_ds_params(hapd, pos); -+ -+ pos = hostapd_eid_country(hapd, pos, epos - pos); -+ -+ /* ERP Information element */ -+ pos = hostapd_eid_erp_info(hapd, pos); -+ -+ /* Extended supported rates */ -+ pos = hostapd_eid_ext_supp_rates(hapd, pos); -+ -+ /* RSN, MDIE, WPA */ -+ pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta); -+ -+#ifdef CONFIG_IEEE80211N -+ pos = hostapd_eid_ht_capabilities(hapd, pos); -+ pos = hostapd_eid_ht_operation(hapd, pos); -+#endif /* CONFIG_IEEE80211N */ -+ -+ pos = hostapd_eid_ext_capab(hapd, pos); -+ -+ /* Wi-Fi Alliance WMM */ -+ pos = hostapd_eid_wmm(hapd, pos); -+ -+#ifdef CONFIG_WPS -+ if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) { -+ os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie), -+ wpabuf_len(hapd->wps_probe_resp_ie)); -+ pos += wpabuf_len(hapd->wps_probe_resp_ie); -+ } -+#endif /* CONFIG_WPS */ -+ -+#ifdef CONFIG_P2P -+ if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p && -+ hapd->p2p_probe_resp_ie) { -+ os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), -+ wpabuf_len(hapd->p2p_probe_resp_ie)); -+ pos += wpabuf_len(hapd->p2p_probe_resp_ie); -+ } -+#endif /* CONFIG_P2P */ -+#ifdef CONFIG_P2P_MANAGER -+ if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == -+ P2P_MANAGE) -+ pos = hostapd_eid_p2p_manage(hapd, pos); -+#endif /* CONFIG_P2P_MANAGER */ -+ -+ if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0) -+ perror("handle_probe_req: send"); -+ -+ os_free(resp); -+ -+ wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s " -+ "SSID", MAC2STR(mgmt->sa), -+ elems.ssid_len == 0 ? "broadcast" : "our"); -+} -+ -+ -+void ieee802_11_set_beacon(struct hostapd_data *hapd) -+{ -+ struct ieee80211_mgmt *head; -+ u8 *pos, *tail, *tailpos; -+ u16 capab_info; -+ size_t head_len, tail_len; -+ -+#ifdef CONFIG_P2P -+ if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED) -+ goto no_beacon; -+#endif /* CONFIG_P2P */ -+ -+#define BEACON_HEAD_BUF_SIZE 256 -+#define BEACON_TAIL_BUF_SIZE 512 -+ head = os_zalloc(BEACON_HEAD_BUF_SIZE); -+ tail_len = BEACON_TAIL_BUF_SIZE; -+#ifdef CONFIG_WPS -+ if (hapd->conf->wps_state && hapd->wps_beacon_ie) -+ tail_len += wpabuf_len(hapd->wps_beacon_ie); -+#endif /* CONFIG_WPS */ -+#ifdef CONFIG_P2P -+ if (hapd->p2p_beacon_ie) -+ tail_len += wpabuf_len(hapd->p2p_beacon_ie); -+#endif /* CONFIG_P2P */ -+ tailpos = tail = os_malloc(tail_len); -+ if (head == NULL || tail == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to set beacon data"); -+ os_free(head); -+ os_free(tail); -+ return; -+ } -+ -+ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_BEACON); -+ head->duration = host_to_le16(0); -+ os_memset(head->da, 0xff, ETH_ALEN); -+ -+ os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); -+ head->u.beacon.beacon_int = -+ host_to_le16(hapd->iconf->beacon_int); -+ -+ /* hardware or low-level driver will setup seq_ctrl and timestamp */ -+ capab_info = hostapd_own_capab_info(hapd, NULL, 0); -+ head->u.beacon.capab_info = host_to_le16(capab_info); -+ pos = &head->u.beacon.variable[0]; -+ -+ /* SSID */ -+ *pos++ = WLAN_EID_SSID; -+ if (hapd->conf->ignore_broadcast_ssid == 2) { -+ /* clear the data, but keep the correct length of the SSID */ -+ *pos++ = hapd->conf->ssid.ssid_len; -+ os_memset(pos, 0, hapd->conf->ssid.ssid_len); -+ pos += hapd->conf->ssid.ssid_len; -+ } else if (hapd->conf->ignore_broadcast_ssid) { -+ *pos++ = 0; /* empty SSID */ -+ } else { -+ *pos++ = hapd->conf->ssid.ssid_len; -+ os_memcpy(pos, hapd->conf->ssid.ssid, -+ hapd->conf->ssid.ssid_len); -+ pos += hapd->conf->ssid.ssid_len; -+ } -+ -+ /* Supported rates */ -+ pos = hostapd_eid_supp_rates(hapd, pos); -+ -+ /* DS Params */ -+ pos = hostapd_eid_ds_params(hapd, pos); -+ -+ head_len = pos - (u8 *) head; -+ -+ tailpos = hostapd_eid_country(hapd, tailpos, -+ tail + BEACON_TAIL_BUF_SIZE - tailpos); -+ -+ /* ERP Information element */ -+ tailpos = hostapd_eid_erp_info(hapd, tailpos); -+ -+ /* Extended supported rates */ -+ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); -+ -+ /* RSN, MDIE, WPA */ -+ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE - -+ tailpos, NULL); -+ -+#ifdef CONFIG_IEEE80211N -+ tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); -+ tailpos = hostapd_eid_ht_operation(hapd, tailpos); -+ -+ //DRIVER_RTW ADD -+ if(hapd->iconf->ieee80211n) -+ hapd->conf->wmm_enabled = 1; -+ -+#endif /* CONFIG_IEEE80211N */ -+ -+ tailpos = hostapd_eid_ext_capab(hapd, tailpos); -+ -+ /* Wi-Fi Alliance WMM */ -+ tailpos = hostapd_eid_wmm(hapd, tailpos); -+ -+#ifdef CONFIG_WPS -+ if (hapd->conf->wps_state && hapd->wps_beacon_ie) { -+ os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie), -+ wpabuf_len(hapd->wps_beacon_ie)); -+ tailpos += wpabuf_len(hapd->wps_beacon_ie); -+ } -+#endif /* CONFIG_WPS */ -+ -+#ifdef CONFIG_P2P -+ if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) { -+ os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie), -+ wpabuf_len(hapd->p2p_beacon_ie)); -+ tailpos += wpabuf_len(hapd->p2p_beacon_ie); -+ } -+#endif /* CONFIG_P2P */ -+#ifdef CONFIG_P2P_MANAGER -+ if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) == -+ P2P_MANAGE) -+ tailpos = hostapd_eid_p2p_manage(hapd, tailpos); -+#endif /* CONFIG_P2P_MANAGER */ -+ -+ tail_len = tailpos > tail ? tailpos - tail : 0; -+ -+ if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len, -+ tail, tail_len, hapd->conf->dtim_period, -+ hapd->iconf->beacon_int)) -+ wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM " -+ "period"); -+ -+ os_free(tail); -+ os_free(head); -+ -+#ifdef CONFIG_P2P -+no_beacon: -+#endif /* CONFIG_P2P */ -+ hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) & -+ ERP_INFO_USE_PROTECTION)); -+} -+ -+ -+void ieee802_11_set_beacons(struct hostapd_iface *iface) -+{ -+ size_t i; -+ for (i = 0; i < iface->num_bss; i++) -+ ieee802_11_set_beacon(iface->bss[i]); -+} -+ -+#endif /* CONFIG_NATIVE_WINDOWS */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.h -new file mode 100644 -index 0000000000000..c1510e1942540 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/beacon.h -@@ -0,0 +1,36 @@ -+/* -+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response -+ * Copyright (c) 2002-2004, Instant802 Networks, Inc. -+ * Copyright (c) 2005-2006, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef BEACON_H -+#define BEACON_H -+ -+struct ieee80211_mgmt; -+ -+void handle_probe_req(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len); -+#ifdef NEED_AP_MLME -+void ieee802_11_set_beacon(struct hostapd_data *hapd); -+void ieee802_11_set_beacons(struct hostapd_iface *iface); -+#else /* NEED_AP_MLME */ -+static inline void ieee802_11_set_beacon(struct hostapd_data *hapd) -+{ -+} -+ -+static inline void ieee802_11_set_beacons(struct hostapd_iface *iface) -+{ -+} -+#endif /* NEED_AP_MLME */ -+ -+#endif /* BEACON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.c -new file mode 100644 -index 0000000000000..d348dc1c48d60 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.c -@@ -0,0 +1,108 @@ -+/* -+ * Control interface for shared AP commands -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "hostapd.h" -+#include "ieee802_1x.h" -+#include "wpa_auth.h" -+#include "ieee802_11.h" -+#include "sta_info.h" -+#include "wps_hostapd.h" -+#include "p2p_hostapd.h" -+#include "ctrl_iface_ap.h" -+ -+ -+static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ char *buf, size_t buflen) -+{ -+ int len, res, ret; -+ -+ if (sta == NULL) { -+ ret = os_snprintf(buf, buflen, "FAIL\n"); -+ if (ret < 0 || (size_t) ret >= buflen) -+ return 0; -+ return ret; -+ } -+ -+ len = 0; -+ ret = os_snprintf(buf + len, buflen - len, MACSTR "\n", -+ MAC2STR(sta->addr)); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); -+ if (res >= 0) -+ len += res; -+ res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len); -+ if (res >= 0) -+ len += res; -+ res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); -+ if (res >= 0) -+ len += res; -+ res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len, -+ buflen - len); -+ if (res >= 0) -+ len += res; -+ res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len); -+ if (res >= 0) -+ len += res; -+ -+ return len; -+} -+ -+ -+int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, -+ char *buf, size_t buflen) -+{ -+ return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen); -+} -+ -+ -+int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, -+ char *buf, size_t buflen) -+{ -+ u8 addr[ETH_ALEN]; -+ int ret; -+ -+ if (hwaddr_aton(txtaddr, addr)) { -+ ret = os_snprintf(buf, buflen, "FAIL\n"); -+ if (ret < 0 || (size_t) ret >= buflen) -+ return 0; -+ return ret; -+ } -+ return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr), -+ buf, buflen); -+} -+ -+ -+int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, -+ char *buf, size_t buflen) -+{ -+ u8 addr[ETH_ALEN]; -+ struct sta_info *sta; -+ int ret; -+ -+ if (hwaddr_aton(txtaddr, addr) || -+ (sta = ap_get_sta(hapd, addr)) == NULL) { -+ ret = os_snprintf(buf, buflen, "FAIL\n"); -+ if (ret < 0 || (size_t) ret >= buflen) -+ return 0; -+ return ret; -+ } -+ return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.h -new file mode 100644 -index 0000000000000..8690beaad4557 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ctrl_iface_ap.h -@@ -0,0 +1,25 @@ -+/* -+ * Control interface for shared AP commands -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef CTRL_IFACE_AP_H -+#define CTRL_IFACE_AP_H -+ -+int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, -+ char *buf, size_t buflen); -+int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, -+ char *buf, size_t buflen); -+int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, -+ char *buf, size_t buflen); -+ -+#endif /* CTRL_IFACE_AP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/drv_callbacks.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/drv_callbacks.c -new file mode 100644 -index 0000000000000..02b7ecfb082f5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/drv_callbacks.c -@@ -0,0 +1,539 @@ -+/* -+ * hostapd / Callback functions for driver wrappers -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "radius/radius.h" -+#include "drivers/driver.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "common/wpa_ctrl.h" -+#include "crypto/random.h" -+#include "p2p/p2p.h" -+#include "wps/wps.h" -+#include "hostapd.h" -+#include "ieee802_11.h" -+#include "sta_info.h" -+#include "accounting.h" -+#include "tkip_countermeasures.h" -+#include "iapp.h" -+#include "ieee802_1x.h" -+#include "wpa_auth.h" -+#include "wmm.h" -+#include "wps_hostapd.h" -+#include "ap_drv_ops.h" -+#include "ap_config.h" -+ -+ -+int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *ie, size_t ielen, int reassoc) -+{ -+ struct sta_info *sta; -+ int new_assoc, res; -+ struct ieee802_11_elems elems; -+#ifdef CONFIG_P2P -+ const u8 *all_ies = ie; -+ size_t all_ies_len = ielen; -+#endif /* CONFIG_P2P */ -+ -+ if (addr == NULL) { -+ /* -+ * This could potentially happen with unexpected event from the -+ * driver wrapper. This was seen at least in one case where the -+ * driver ended up being set to station mode while hostapd was -+ * running, so better make sure we stop processing such an -+ * event here. -+ */ -+ wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " -+ "no address"); -+ return -1; -+ } -+ random_add_randomness(addr, ETH_ALEN); -+ -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "associated"); -+ -+ ieee802_11_parse_elems(ie, ielen, &elems, 0); -+ if (elems.wps_ie) { -+ ie = elems.wps_ie - 2; -+ ielen = elems.wps_ie_len + 2; -+ wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); -+ } else if (elems.rsn_ie) { -+ ie = elems.rsn_ie - 2; -+ ielen = elems.rsn_ie_len + 2; -+ wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); -+ } else if (elems.wpa_ie) { -+ ie = elems.wpa_ie - 2; -+ ielen = elems.wpa_ie_len + 2; -+ wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); -+ } else { -+ ie = NULL; -+ ielen = 0; -+ wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " -+ "(Re)AssocReq"); -+ } -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta) { -+ accounting_sta_stop(hapd, sta); -+ } else { -+ sta = ap_sta_add(hapd, addr); -+ if (sta == NULL) -+ return -1; -+ } -+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); -+ -+#ifdef CONFIG_P2P -+ if (elems.p2p) { -+ wpabuf_free(sta->p2p_ie); -+ sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len, -+ P2P_IE_VENDOR_TYPE); -+ } -+#endif /* CONFIG_P2P */ -+ -+ if (hapd->conf->wpa) { -+ if (ie == NULL || ielen == 0) { -+ if (hapd->conf->wps_state) { -+ wpa_printf(MSG_DEBUG, "STA did not include " -+ "WPA/RSN IE in (Re)Association " -+ "Request - possible WPS use"); -+ sta->flags |= WLAN_STA_MAYBE_WPS; -+ goto skip_wpa_check; -+ } -+ -+ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); -+ return -1; -+ } -+ if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && -+ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { -+ sta->flags |= WLAN_STA_WPS; -+ goto skip_wpa_check; -+ } -+ -+ if (sta->wpa_sm == NULL) -+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, -+ sta->addr); -+ if (sta->wpa_sm == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to initialize WPA state " -+ "machine"); -+ return -1; -+ } -+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, -+ ie, ielen, NULL, 0); -+ if (res != WPA_IE_OK) { -+ int resp; -+ wpa_printf(MSG_DEBUG, "WPA/RSN information element " -+ "rejected? (res %u)", res); -+ wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); -+ if (res == WPA_INVALID_GROUP) -+ resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; -+ else if (res == WPA_INVALID_PAIRWISE) -+ resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; -+ else if (res == WPA_INVALID_AKMP) -+ resp = WLAN_REASON_AKMP_NOT_VALID; -+#ifdef CONFIG_IEEE80211W -+ else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) -+ resp = WLAN_REASON_INVALID_IE; -+ else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) -+ resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID; -+#endif /* CONFIG_IEEE80211W */ -+ else -+ resp = WLAN_REASON_INVALID_IE; -+ hostapd_drv_sta_disassoc(hapd, sta->addr, resp); -+ ap_free_sta(hapd, sta); -+ return -1; -+ } -+ } else if (hapd->conf->wps_state) { -+#ifdef CONFIG_WPS_STRICT -+ if (ie) { -+ struct wpabuf *wps; -+ wps = ieee802_11_vendor_ie_concat(ie, ielen, -+ WPS_IE_VENDOR_TYPE); -+ if (wps && wps_validate_assoc_req(wps) < 0) { -+ hostapd_drv_sta_disassoc( -+ hapd, sta->addr, -+ WLAN_REASON_INVALID_IE); -+ ap_free_sta(hapd, sta); -+ wpabuf_free(wps); -+ return -1; -+ } -+ wpabuf_free(wps); -+ } -+#endif /* CONFIG_WPS_STRICT */ -+ if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && -+ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { -+ sta->flags |= WLAN_STA_WPS; -+ } else -+ sta->flags |= WLAN_STA_MAYBE_WPS; -+ } -+skip_wpa_check: -+ -+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; -+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; -+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); -+ -+ hostapd_new_assoc_sta(hapd, sta, !new_assoc); -+ -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); -+ -+#ifdef CONFIG_P2P -+ p2p_group_notif_assoc(hapd->p2p_group, sta->addr, -+ all_ies, all_ies_len); -+#endif /* CONFIG_P2P */ -+ -+ return 0; -+} -+ -+ -+void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) -+{ -+ struct sta_info *sta; -+ -+ if (addr == NULL) { -+ /* -+ * This could potentially happen with unexpected event from the -+ * driver wrapper. This was seen at least in one case where the -+ * driver ended up reporting a station mode event while hostapd -+ * was running, so better make sure we stop processing such an -+ * event here. -+ */ -+ wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event " -+ "with no address"); -+ return; -+ } -+ -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "disassociated"); -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta == NULL) { -+ wpa_printf(MSG_DEBUG, "Disassociation notification for " -+ "unknown STA " MACSTR, MAC2STR(addr)); -+ return; -+ } -+ -+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); -+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, -+ MAC2STR(sta->addr)); -+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); -+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); -+ ap_free_sta(hapd, sta); -+} -+ -+ -+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) -+{ -+ struct sta_info *sta = ap_get_sta(hapd, addr); -+ -+ if (!sta || !hapd->conf->disassoc_low_ack) -+ return; -+ -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "disconnected due to excessive " -+ "missing ACKs"); -+ hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); -+ if (sta) -+ ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); -+} -+ -+ -+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, -+ const u8 *ie, size_t ie_len) -+{ -+ size_t i; -+ int ret = 0; -+ -+ if (sa == NULL || ie == NULL) -+ return -1; -+ -+ random_add_randomness(sa, ETH_ALEN); -+ for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { -+ if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, -+ sa, ie, ie_len) > 0) { -+ ret = 1; -+ break; -+ } -+ } -+ return ret; -+} -+ -+ -+#ifdef HOSTAPD -+ -+#ifdef NEED_AP_MLME -+ -+static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len) -+{ -+ u16 fc, type, stype; -+ -+ /* -+ * PS-Poll frames are 16 bytes. All other frames are -+ * 24 bytes or longer. -+ */ -+ if (len < 16) -+ return NULL; -+ -+ fc = le_to_host16(hdr->frame_control); -+ type = WLAN_FC_GET_TYPE(fc); -+ stype = WLAN_FC_GET_STYPE(fc); -+ -+ switch (type) { -+ case WLAN_FC_TYPE_DATA: -+ if (len < 24) -+ return NULL; -+ switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) { -+ case WLAN_FC_FROMDS | WLAN_FC_TODS: -+ case WLAN_FC_TODS: -+ return hdr->addr1; -+ case WLAN_FC_FROMDS: -+ return hdr->addr2; -+ default: -+ return NULL; -+ } -+ case WLAN_FC_TYPE_CTRL: -+ if (stype != WLAN_FC_STYPE_PSPOLL) -+ return NULL; -+ return hdr->addr1; -+ case WLAN_FC_TYPE_MGMT: -+ return hdr->addr3; -+ default: -+ return NULL; -+ } -+} -+ -+ -+#define HAPD_BROADCAST ((struct hostapd_data *) -1) -+ -+static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, -+ const u8 *bssid) -+{ -+ size_t i; -+ -+ if (bssid == NULL) -+ return NULL; -+ if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && -+ bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) -+ return HAPD_BROADCAST; -+ -+ for (i = 0; i < iface->num_bss; i++) { -+ if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) -+ return iface->bss[i]; -+ } -+ -+ return NULL; -+} -+ -+ -+static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, -+ const u8 *frame, size_t len) -+{ -+ const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame; -+ u16 fc = le_to_host16(hdr->frame_control); -+ hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); -+ if (hapd == NULL || hapd == HAPD_BROADCAST) -+ return; -+ -+ ieee802_11_rx_from_unknown(hapd, hdr->addr2, -+ (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == -+ (WLAN_FC_TODS | WLAN_FC_FROMDS)); -+} -+ -+ -+static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) -+{ -+ struct hostapd_iface *iface = hapd->iface; -+ const struct ieee80211_hdr *hdr; -+ const u8 *bssid; -+ struct hostapd_frame_info fi; -+ -+ hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; -+ bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); -+ if (bssid == NULL) -+ return; -+ -+ hapd = get_hapd_bssid(iface, bssid); -+ if (hapd == NULL) { -+ u16 fc; -+ fc = le_to_host16(hdr->frame_control); -+ -+ /* -+ * Drop frames to unknown BSSIDs except for Beacon frames which -+ * could be used to update neighbor information. -+ */ -+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && -+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) -+ hapd = iface->bss[0]; -+ else -+ return; -+ } -+ -+ os_memset(&fi, 0, sizeof(fi)); -+ fi.datarate = rx_mgmt->datarate; -+ fi.ssi_signal = rx_mgmt->ssi_signal; -+ -+ if (hapd == HAPD_BROADCAST) { -+ size_t i; -+ for (i = 0; i < iface->num_bss; i++) -+ ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, -+ rx_mgmt->frame_len, &fi); -+ } else -+ ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi); -+ -+ random_add_randomness(&fi, sizeof(fi)); -+} -+ -+ -+static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, -+ size_t len, u16 stype, int ok) -+{ -+ struct ieee80211_hdr *hdr; -+ hdr = (struct ieee80211_hdr *) buf; -+ hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); -+ if (hapd == NULL || hapd == HAPD_BROADCAST) -+ return; -+ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); -+} -+ -+#endif /* NEED_AP_MLME */ -+ -+ -+static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) -+{ -+ struct sta_info *sta = ap_get_sta(hapd, addr); -+ if (sta) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR -+ " - adding a new STA", MAC2STR(addr)); -+ sta = ap_sta_add(hapd, addr); -+ if (sta) { -+ hostapd_new_assoc_sta(hapd, sta, 0); -+ } else { -+ wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, -+ MAC2STR(addr)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, -+ const u8 *data, size_t data_len) -+{ -+ struct hostapd_iface *iface = hapd->iface; -+ size_t j; -+ -+ for (j = 0; j < iface->num_bss; j++) { -+ if (ap_get_sta(iface->bss[j], src)) { -+ hapd = iface->bss[j]; -+ break; -+ } -+ } -+ -+ ieee802_1x_receive(hapd, src, data, data_len); -+} -+ -+ -+void wpa_supplicant_event(void *ctx, enum wpa_event_type event, -+ union wpa_event_data *data) -+{ -+ struct hostapd_data *hapd = ctx; -+ -+ switch (event) { -+ case EVENT_MICHAEL_MIC_FAILURE: -+ michael_mic_failure(hapd, data->michael_mic_failure.src, 1); -+ break; -+ case EVENT_SCAN_RESULTS: -+ if (hapd->iface->scan_cb) -+ hapd->iface->scan_cb(hapd->iface); -+ break; -+#ifdef CONFIG_IEEE80211R -+ case EVENT_FT_RRB_RX: -+ wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src, -+ data->ft_rrb_rx.data, data->ft_rrb_rx.data_len); -+ break; -+#endif /* CONFIG_IEEE80211R */ -+ case EVENT_WPS_BUTTON_PUSHED: -+ hostapd_wps_button_pushed(hapd, NULL); -+ break; -+#ifdef NEED_AP_MLME -+ case EVENT_TX_STATUS: -+ switch (data->tx_status.type) { -+ case WLAN_FC_TYPE_MGMT: -+ hostapd_mgmt_tx_cb(hapd, data->tx_status.data, -+ data->tx_status.data_len, -+ data->tx_status.stype, -+ data->tx_status.ack); -+ break; -+ case WLAN_FC_TYPE_DATA: -+ hostapd_tx_status(hapd, data->tx_status.dst, -+ data->tx_status.data, -+ data->tx_status.data_len, -+ data->tx_status.ack); -+ break; -+ } -+ break; -+ case EVENT_RX_FROM_UNKNOWN: -+ hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame, -+ data->rx_from_unknown.len); -+ break; -+ case EVENT_RX_MGMT: -+ hostapd_mgmt_rx(hapd, &data->rx_mgmt); -+ break; -+#endif /* NEED_AP_MLME */ -+ case EVENT_RX_PROBE_REQ: -+ if (data->rx_probe_req.sa == NULL || -+ data->rx_probe_req.ie == NULL) -+ break; -+ hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, -+ data->rx_probe_req.ie, -+ data->rx_probe_req.ie_len); -+ break; -+ case EVENT_NEW_STA: -+ hostapd_event_new_sta(hapd, data->new_sta.addr); -+ break; -+ case EVENT_EAPOL_RX: -+ hostapd_event_eapol_rx(hapd, data->eapol_rx.src, -+ data->eapol_rx.data, -+ data->eapol_rx.data_len); -+ break; -+ case EVENT_ASSOC: -+ hostapd_notif_assoc(hapd, data->assoc_info.addr, -+ data->assoc_info.req_ies, -+ data->assoc_info.req_ies_len, -+ data->assoc_info.reassoc); -+ break; -+ case EVENT_DISASSOC: -+ if (data) -+ hostapd_notif_disassoc(hapd, data->disassoc_info.addr); -+ break; -+ case EVENT_DEAUTH: -+ if (data) -+ hostapd_notif_disassoc(hapd, data->deauth_info.addr); -+ break; -+ case EVENT_STATION_LOW_ACK: -+ if (!data) -+ break; -+ hostapd_event_sta_low_ack(hapd, data->low_ack.addr); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "Unknown event %d", event); -+ break; -+ } -+} -+ -+#endif /* HOSTAPD */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.c -new file mode 100644 -index 0000000000000..4e5eb01996ad3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.c -@@ -0,0 +1,929 @@ -+/* -+ * hostapd / Initialization and configuration -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "radius/radius_client.h" -+#include "drivers/driver.h" -+#include "hostapd.h" -+#include "authsrv.h" -+#include "sta_info.h" -+#include "accounting.h" -+#include "ap_list.h" -+#include "beacon.h" -+#include "iapp.h" -+#include "ieee802_1x.h" -+#include "ieee802_11_auth.h" -+#include "vlan_init.h" -+#include "wpa_auth.h" -+#include "wps_hostapd.h" -+#include "hw_features.h" -+#include "wpa_auth_glue.h" -+#include "ap_drv_ops.h" -+#include "ap_config.h" -+#include "p2p_hostapd.h" -+ -+ -+static int hostapd_flush_old_stations(struct hostapd_data *hapd); -+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); -+ -+extern int wpa_debug_level; -+ -+ -+static void hostapd_reload_bss(struct hostapd_data *hapd) -+{ -+#ifndef CONFIG_NO_RADIUS -+ radius_client_reconfig(hapd->radius, hapd->conf->radius); -+#endif /* CONFIG_NO_RADIUS */ -+ -+ if (hostapd_setup_wpa_psk(hapd->conf)) { -+ wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " -+ "after reloading configuration"); -+ } -+ -+ if (hapd->conf->ieee802_1x || hapd->conf->wpa) -+ hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1); -+ else -+ hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); -+ -+ if (hapd->conf->wpa && hapd->wpa_auth == NULL) -+ hostapd_setup_wpa(hapd); -+ else if (hapd->conf->wpa) { -+ const u8 *wpa_ie; -+ size_t wpa_ie_len; -+ hostapd_reconfig_wpa(hapd); -+ wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); -+ if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) -+ wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " -+ "the kernel driver."); -+ } else if (hapd->wpa_auth) { -+ wpa_deinit(hapd->wpa_auth); -+ hapd->wpa_auth = NULL; -+ hostapd_set_privacy(hapd, 0); -+ hostapd_setup_encryption(hapd->conf->iface, hapd); -+ hostapd_set_generic_elem(hapd, (u8 *) "", 0); -+ } -+ -+ ieee802_11_set_beacon(hapd); -+ hostapd_update_wps(hapd); -+ -+ if (hapd->conf->ssid.ssid_set && -+ hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid, -+ hapd->conf->ssid.ssid_len)) { -+ wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); -+ /* try to continue */ -+ } -+ wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface); -+} -+ -+ -+int hostapd_reload_config(struct hostapd_iface *iface) -+{ -+ struct hostapd_data *hapd = iface->bss[0]; -+ struct hostapd_config *newconf, *oldconf; -+ size_t j; -+ -+ if (iface->config_read_cb == NULL) -+ return -1; -+ newconf = iface->config_read_cb(iface->config_fname); -+ if (newconf == NULL) -+ return -1; -+ -+ /* -+ * Deauthenticate all stations since the new configuration may not -+ * allow them to use the BSS anymore. -+ */ -+ for (j = 0; j < iface->num_bss; j++) { -+ hostapd_flush_old_stations(iface->bss[j]); -+ -+#ifndef CONFIG_NO_RADIUS -+ /* TODO: update dynamic data based on changed configuration -+ * items (e.g., open/close sockets, etc.) */ -+ radius_client_flush(iface->bss[j]->radius, 0); -+#endif /* CONFIG_NO_RADIUS */ -+ } -+ -+ oldconf = hapd->iconf; -+ iface->conf = newconf; -+ -+ for (j = 0; j < iface->num_bss; j++) { -+ hapd = iface->bss[j]; -+ hapd->iconf = newconf; -+ hapd->conf = &newconf->bss[j]; -+ hostapd_reload_bss(hapd); -+ } -+ -+ hostapd_config_free(oldconf); -+ -+ -+ return 0; -+} -+ -+ -+static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, -+ char *ifname) -+{ -+ int i; -+ -+ for (i = 0; i < NUM_WEP_KEYS; i++) { -+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, -+ 0, NULL, 0, NULL, 0)) { -+ wpa_printf(MSG_DEBUG, "Failed to clear default " -+ "encryption keys (ifname=%s keyidx=%d)", -+ ifname, i); -+ } -+ } -+#ifdef CONFIG_IEEE80211W -+ if (hapd->conf->ieee80211w) { -+ for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { -+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, -+ NULL, i, 0, NULL, -+ 0, NULL, 0)) { -+ wpa_printf(MSG_DEBUG, "Failed to clear " -+ "default mgmt encryption keys " -+ "(ifname=%s keyidx=%d)", ifname, i); -+ } -+ } -+ } -+#endif /* CONFIG_IEEE80211W */ -+} -+ -+ -+static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd) -+{ -+ hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface); -+ return 0; -+} -+ -+ -+static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) -+{ -+ int errors = 0, idx; -+ struct hostapd_ssid *ssid = &hapd->conf->ssid; -+ -+ idx = ssid->wep.idx; -+ if (ssid->wep.default_len && -+ hostapd_drv_set_key(hapd->conf->iface, -+ hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, -+ 1, NULL, 0, ssid->wep.key[idx], -+ ssid->wep.len[idx])) { -+ wpa_printf(MSG_WARNING, "Could not set WEP encryption."); -+ errors++; -+ } -+ -+ if (ssid->dyn_vlan_keys) { -+ size_t i; -+ for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) { -+ const char *ifname; -+ struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i]; -+ if (key == NULL) -+ continue; -+ ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, -+ i); -+ if (ifname == NULL) -+ continue; -+ -+ idx = key->idx; -+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP, -+ broadcast_ether_addr, idx, 1, -+ NULL, 0, key->key[idx], -+ key->len[idx])) { -+ wpa_printf(MSG_WARNING, "Could not set " -+ "dynamic VLAN WEP encryption."); -+ errors++; -+ } -+ } -+ } -+ -+ return errors; -+} -+ -+/** -+ * hostapd_cleanup - Per-BSS cleanup (deinitialization) -+ * @hapd: Pointer to BSS data -+ * -+ * This function is used to free all per-BSS data structures and resources. -+ * This gets called in a loop for each BSS between calls to -+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface -+ * is deinitialized. Most of the modules that are initialized in -+ * hostapd_setup_bss() are deinitialized here. -+ */ -+static void hostapd_cleanup(struct hostapd_data *hapd) -+{ -+ if (hapd->iface->ctrl_iface_deinit) -+ hapd->iface->ctrl_iface_deinit(hapd); -+ -+ iapp_deinit(hapd->iapp); -+ hapd->iapp = NULL; -+ accounting_deinit(hapd); -+ hostapd_deinit_wpa(hapd); -+ vlan_deinit(hapd); -+ hostapd_acl_deinit(hapd); -+#ifndef CONFIG_NO_RADIUS -+ radius_client_deinit(hapd->radius); -+ hapd->radius = NULL; -+#endif /* CONFIG_NO_RADIUS */ -+ -+ hostapd_deinit_wps(hapd); -+ -+ authsrv_deinit(hapd); -+ -+ if (hapd->interface_added && -+ hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) { -+ wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s", -+ hapd->conf->iface); -+ } -+ -+ os_free(hapd->probereq_cb); -+ hapd->probereq_cb = NULL; -+ -+#ifdef CONFIG_P2P -+ wpabuf_free(hapd->p2p_beacon_ie); -+ hapd->p2p_beacon_ie = NULL; -+ wpabuf_free(hapd->p2p_probe_resp_ie); -+ hapd->p2p_probe_resp_ie = NULL; -+#endif /* CONFIG_P2P */ -+} -+ -+ -+/** -+ * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup -+ * @iface: Pointer to interface data -+ * -+ * This function is called before per-BSS data structures are deinitialized -+ * with hostapd_cleanup(). -+ */ -+static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface) -+{ -+} -+ -+ -+/** -+ * hostapd_cleanup_iface - Complete per-interface cleanup -+ * @iface: Pointer to interface data -+ * -+ * This function is called after per-BSS data structures are deinitialized -+ * with hostapd_cleanup(). -+ */ -+static void hostapd_cleanup_iface(struct hostapd_iface *iface) -+{ -+ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); -+ iface->hw_features = NULL; -+ os_free(iface->current_rates); -+ iface->current_rates = NULL; -+ ap_list_deinit(iface); -+ hostapd_config_free(iface->conf); -+ iface->conf = NULL; -+ -+ os_free(iface->config_fname); -+ os_free(iface->bss); -+ os_free(iface); -+} -+ -+ -+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) -+{ -+ int i; -+ -+ hostapd_broadcast_wep_set(hapd); -+ -+ if (hapd->conf->ssid.wep.default_len) { -+ hostapd_set_privacy(hapd, 1); -+ return 0; -+ } -+ -+ for (i = 0; i < 4; i++) { -+ if (hapd->conf->ssid.wep.key[i] && -+ hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, -+ i == hapd->conf->ssid.wep.idx, NULL, 0, -+ hapd->conf->ssid.wep.key[i], -+ hapd->conf->ssid.wep.len[i])) { -+ wpa_printf(MSG_WARNING, "Could not set WEP " -+ "encryption."); -+ return -1; -+ } -+ if (hapd->conf->ssid.wep.key[i] && -+ i == hapd->conf->ssid.wep.idx) -+ hostapd_set_privacy(hapd, 1); -+ } -+ -+ return 0; -+} -+ -+ -+static int hostapd_flush_old_stations(struct hostapd_data *hapd) -+{ -+ int ret = 0; -+ u8 addr[ETH_ALEN]; -+ -+ if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "Flushing old station entries"); -+ if (hostapd_flush(hapd)) { -+ wpa_printf(MSG_WARNING, "Could not connect to kernel driver."); -+ ret = -1; -+ } -+ wpa_printf(MSG_DEBUG, "Deauthenticate all stations"); -+ os_memset(addr, 0xff, ETH_ALEN); -+ hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); -+ hostapd_free_stas(hapd); -+ -+ return ret; -+} -+ -+ -+/** -+ * hostapd_validate_bssid_configuration - Validate BSSID configuration -+ * @iface: Pointer to interface data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to validate that the configured BSSIDs are valid. -+ */ -+static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) -+{ -+ u8 mask[ETH_ALEN] = { 0 }; -+ struct hostapd_data *hapd = iface->bss[0]; -+ unsigned int i = iface->conf->num_bss, bits = 0, j; -+ int res; -+ int auto_addr = 0; -+ -+ if (hostapd_drv_none(hapd)) -+ return 0; -+ -+ /* Generate BSSID mask that is large enough to cover the BSSIDs. */ -+ -+ /* Determine the bits necessary to cover the number of BSSIDs. */ -+ for (i--; i; i >>= 1) -+ bits++; -+ -+ /* Determine the bits necessary to any configured BSSIDs, -+ if they are higher than the number of BSSIDs. */ -+ for (j = 0; j < iface->conf->num_bss; j++) { -+ if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) { -+ if (j) -+ auto_addr++; -+ continue; -+ } -+ -+ for (i = 0; i < ETH_ALEN; i++) { -+ mask[i] |= -+ iface->conf->bss[j].bssid[i] ^ -+ hapd->own_addr[i]; -+ } -+ } -+ -+ if (!auto_addr) -+ goto skip_mask_ext; -+ -+ for (i = 0; i < ETH_ALEN && mask[i] == 0; i++) -+ ; -+ j = 0; -+ if (i < ETH_ALEN) { -+ j = (5 - i) * 8; -+ -+ while (mask[i] != 0) { -+ mask[i] >>= 1; -+ j++; -+ } -+ } -+ -+ if (bits < j) -+ bits = j; -+ -+ if (bits > 40) { -+ wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)", -+ bits); -+ return -1; -+ } -+ -+ os_memset(mask, 0xff, ETH_ALEN); -+ j = bits / 8; -+ for (i = 5; i > 5 - j; i--) -+ mask[i] = 0; -+ j = bits % 8; -+ while (j--) -+ mask[i] <<= 1; -+ -+skip_mask_ext: -+ wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", -+ (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); -+ -+ res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask); -+ if (res == 0) -+ return 0; -+ -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask " -+ MACSTR " for start address " MACSTR ".", -+ MAC2STR(mask), MAC2STR(hapd->own_addr)); -+ return -1; -+ } -+ -+ if (!auto_addr) -+ return 0; -+ -+ for (i = 0; i < ETH_ALEN; i++) { -+ if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) { -+ wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR -+ " for start address " MACSTR ".", -+ MAC2STR(mask), MAC2STR(hapd->own_addr)); -+ wpa_printf(MSG_ERROR, "Start address must be the " -+ "first address in the block (i.e., addr " -+ "AND mask == addr)."); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int mac_in_conf(struct hostapd_config *conf, const void *a) -+{ -+ size_t i; -+ -+ for (i = 0; i < conf->num_bss; i++) { -+ if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) { -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+ -+ -+/** -+ * hostapd_setup_bss - Per-BSS setup (initialization) -+ * @hapd: Pointer to BSS data -+ * @first: Whether this BSS is the first BSS of an interface -+ * -+ * This function is used to initialize all per-BSS data structures and -+ * resources. This gets called in a loop for each BSS when an interface is -+ * initialized. Most of the modules that are initialized here will be -+ * deinitialized in hostapd_cleanup(). -+ */ -+static int hostapd_setup_bss(struct hostapd_data *hapd, int first) -+{ -+ struct hostapd_bss_config *conf = hapd->conf; -+ u8 ssid[HOSTAPD_MAX_SSID_LEN + 1]; -+ int ssid_len, set_ssid; -+ char force_ifname[IFNAMSIZ]; -+ u8 if_addr[ETH_ALEN]; -+ -+ if (!first) { -+ if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) { -+ /* Allocate the next available BSSID. */ -+ do { -+ inc_byte_array(hapd->own_addr, ETH_ALEN); -+ } while (mac_in_conf(hapd->iconf, hapd->own_addr)); -+ } else { -+ /* Allocate the configured BSSID. */ -+ os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN); -+ -+ if (hostapd_mac_comp(hapd->own_addr, -+ hapd->iface->bss[0]->own_addr) == -+ 0) { -+ wpa_printf(MSG_ERROR, "BSS '%s' may not have " -+ "BSSID set to the MAC address of " -+ "the radio", hapd->conf->iface); -+ return -1; -+ } -+ } -+ -+ hapd->interface_added = 1; -+ if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, -+ hapd->conf->iface, hapd->own_addr, hapd, -+ &hapd->drv_priv, force_ifname, if_addr, -+ hapd->conf->bridge[0] ? hapd->conf->bridge : -+ NULL)) { -+ wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" -+ MACSTR ")", MAC2STR(hapd->own_addr)); -+ return -1; -+ } -+ } -+ -+ if (conf->wmm_enabled < 0) -+ conf->wmm_enabled = hapd->iconf->ieee80211n; -+ -+ hostapd_flush_old_stations(hapd); -+ hostapd_set_privacy(hapd, 0); -+ -+ hostapd_broadcast_wep_clear(hapd); -+ if (hostapd_setup_encryption(hapd->conf->iface, hapd)) -+ return -1; -+ -+ /* -+ * Fetch the SSID from the system and use it or, -+ * if one was specified in the config file, verify they -+ * match. -+ */ -+ ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid)); -+ if (ssid_len < 0) { -+ wpa_printf(MSG_ERROR, "Could not read SSID from system"); -+ return -1; -+ } -+ if (conf->ssid.ssid_set) { -+ /* -+ * If SSID is specified in the config file and it differs -+ * from what is being used then force installation of the -+ * new SSID. -+ */ -+ set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len || -+ os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0); -+ } else { -+ /* -+ * No SSID in the config file; just use the one we got -+ * from the system. -+ */ -+ set_ssid = 0; -+ conf->ssid.ssid_len = ssid_len; -+ os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); -+ conf->ssid.ssid[conf->ssid.ssid_len] = '\0'; -+ } -+ -+ if (!hostapd_drv_none(hapd)) { -+ wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR -+ " and ssid '%s'", -+ hapd->conf->iface, MAC2STR(hapd->own_addr), -+ hapd->conf->ssid.ssid); -+ } -+ -+ if (hostapd_setup_wpa_psk(conf)) { -+ wpa_printf(MSG_ERROR, "WPA-PSK setup failed."); -+ return -1; -+ } -+ -+ /* Set SSID for the kernel driver (to be used in beacon and probe -+ * response frames) */ -+ if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid, -+ conf->ssid.ssid_len)) { -+ wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver"); -+ return -1; -+ } -+ -+ if (wpa_debug_level == MSG_MSGDUMP) -+ conf->radius->msg_dumps = 1; -+#ifndef CONFIG_NO_RADIUS -+ hapd->radius = radius_client_init(hapd, conf->radius); -+ if (hapd->radius == NULL) { -+ wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); -+ return -1; -+ } -+#endif /* CONFIG_NO_RADIUS */ -+ -+ if (hostapd_acl_init(hapd)) { -+ wpa_printf(MSG_ERROR, "ACL initialization failed."); -+ return -1; -+ } -+ if (hostapd_init_wps(hapd, conf)) -+ return -1; -+ -+ if (authsrv_init(hapd) < 0) -+ return -1; -+ -+ if (ieee802_1x_init(hapd)) { -+ wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed."); -+ return -1; -+ } -+ -+ if (hapd->conf->wpa && hostapd_setup_wpa(hapd)) -+ return -1; -+ -+ if (accounting_init(hapd)) { -+ wpa_printf(MSG_ERROR, "Accounting initialization failed."); -+ return -1; -+ } -+ -+ if (hapd->conf->ieee802_11f && -+ (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) { -+ wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization " -+ "failed."); -+ return -1; -+ } -+ -+ if (hapd->iface->ctrl_iface_init && -+ hapd->iface->ctrl_iface_init(hapd)) { -+ wpa_printf(MSG_ERROR, "Failed to setup control interface"); -+ return -1; -+ } -+ -+ if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { -+ wpa_printf(MSG_ERROR, "VLAN initialization failed."); -+ return -1; -+ } -+ -+ ieee802_11_set_beacon(hapd); -+ -+ if (hapd->driver && hapd->driver->set_operstate) -+ hapd->driver->set_operstate(hapd->drv_priv, 1); -+ -+ return 0; -+} -+ -+ -+static void hostapd_tx_queue_params(struct hostapd_iface *iface) -+{ -+ struct hostapd_data *hapd = iface->bss[0]; -+ int i; -+ struct hostapd_tx_queue_params *p; -+ -+ for (i = 0; i < NUM_TX_QUEUES; i++) { -+ p = &iface->conf->tx_queue[i]; -+ -+ if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin, -+ p->cwmax, p->burst)) { -+ wpa_printf(MSG_DEBUG, "Failed to set TX queue " -+ "parameters for queue %d.", i); -+ /* Continue anyway */ -+ } -+ } -+} -+ -+ -+static int setup_interface(struct hostapd_iface *iface) -+{ -+ struct hostapd_data *hapd = iface->bss[0]; -+ size_t i; -+ char country[4]; -+ -+ /* -+ * Make sure that all BSSes get configured with a pointer to the same -+ * driver interface. -+ */ -+ for (i = 1; i < iface->num_bss; i++) { -+ iface->bss[i]->driver = hapd->driver; -+ iface->bss[i]->drv_priv = hapd->drv_priv; -+ } -+ -+ if (hostapd_validate_bssid_configuration(iface)) -+ return -1; -+ -+ if (hapd->iconf->country[0] && hapd->iconf->country[1]) { -+ os_memcpy(country, hapd->iconf->country, 3); -+ country[3] = '\0'; -+ if (hostapd_set_country(hapd, country) < 0) { -+ wpa_printf(MSG_ERROR, "Failed to set country code"); -+ return -1; -+ } -+ } -+ -+ if (hostapd_get_hw_features(iface)) { -+ /* Not all drivers support this yet, so continue without hw -+ * feature data. */ -+ } else { -+ int ret = hostapd_select_hw_mode(iface); -+ if (ret < 0) { -+ wpa_printf(MSG_ERROR, "Could not select hw_mode and " -+ "channel. (%d)", ret); -+ return -1; -+ } -+ ret = hostapd_check_ht_capab(iface); -+ if (ret < 0) -+ return -1; -+ if (ret == 1) { -+ wpa_printf(MSG_DEBUG, "Interface initialization will " -+ "be completed in a callback"); -+ return 0; -+ } -+ } -+ return hostapd_setup_interface_complete(iface, 0); -+} -+ -+ -+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) -+{ -+ struct hostapd_data *hapd = iface->bss[0]; -+ size_t j; -+ u8 *prev_addr; -+ -+ if (err) { -+ wpa_printf(MSG_ERROR, "Interface initialization failed"); -+ eloop_terminate(); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "Completing interface initialization"); -+ if (hapd->iconf->channel) { -+ iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel); -+ wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d " -+ "Frequency: %d MHz", -+ hostapd_hw_mode_txt(hapd->iconf->hw_mode), -+ hapd->iconf->channel, iface->freq); -+ -+ if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, -+ hapd->iconf->channel, -+ hapd->iconf->ieee80211n, -+ hapd->iconf->secondary_channel)) { -+ wpa_printf(MSG_ERROR, "Could not set channel for " -+ "kernel driver"); -+ return -1; -+ } -+ } -+ -+ if (iface->current_mode) { -+ if (hostapd_prepare_rates(hapd, iface->current_mode)) { -+ wpa_printf(MSG_ERROR, "Failed to prepare rates " -+ "table."); -+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_WARNING, -+ "Failed to prepare rates table."); -+ return -1; -+ } -+ } -+ -+ if (hapd->iconf->rts_threshold > -1 && -+ hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { -+ wpa_printf(MSG_ERROR, "Could not set RTS threshold for " -+ "kernel driver"); -+ return -1; -+ } -+ -+ if (hapd->iconf->fragm_threshold > -1 && -+ hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) { -+ wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " -+ "for kernel driver"); -+ return -1; -+ } -+ -+ prev_addr = hapd->own_addr; -+ -+ for (j = 0; j < iface->num_bss; j++) { -+ hapd = iface->bss[j]; -+ if (j) -+ os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); -+ if (hostapd_setup_bss(hapd, j == 0)) -+ return -1; -+ if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) -+ prev_addr = hapd->own_addr; -+ } -+ -+ hostapd_tx_queue_params(iface); -+ -+ ap_list_init(iface); -+ -+ if (hostapd_driver_commit(hapd) < 0) { -+ wpa_printf(MSG_ERROR, "%s: Failed to commit driver " -+ "configuration", __func__); -+ return -1; -+ } -+ -+ if (hapd->setup_complete_cb) -+ hapd->setup_complete_cb(hapd->setup_complete_cb_ctx); -+ -+ wpa_printf(MSG_DEBUG, "%s: Setup of interface done.", -+ iface->bss[0]->conf->iface); -+ -+ return 0; -+} -+ -+ -+/** -+ * hostapd_setup_interface - Setup of an interface -+ * @iface: Pointer to interface data. -+ * Returns: 0 on success, -1 on failure -+ * -+ * Initializes the driver interface, validates the configuration, -+ * and sets driver parameters based on the configuration. -+ * Flushes old stations, sets the channel, encryption, -+ * beacons, and WDS links based on the configuration. -+ */ -+int hostapd_setup_interface(struct hostapd_iface *iface) -+{ -+ int ret; -+ -+ ret = setup_interface(iface); -+ if (ret) { -+ wpa_printf(MSG_ERROR, "%s: Unable to setup interface.", -+ iface->bss[0]->conf->iface); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * hostapd_alloc_bss_data - Allocate and initialize per-BSS data -+ * @hapd_iface: Pointer to interface data -+ * @conf: Pointer to per-interface configuration -+ * @bss: Pointer to per-BSS configuration for this BSS -+ * Returns: Pointer to allocated BSS data -+ * -+ * This function is used to allocate per-BSS data structure. This data will be -+ * freed after hostapd_cleanup() is called for it during interface -+ * deinitialization. -+ */ -+struct hostapd_data * -+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, -+ struct hostapd_config *conf, -+ struct hostapd_bss_config *bss) -+{ -+ struct hostapd_data *hapd; -+ -+ hapd = os_zalloc(sizeof(*hapd)); -+ if (hapd == NULL) -+ return NULL; -+ -+ hapd->new_assoc_sta_cb = hostapd_new_assoc_sta; -+ hapd->iconf = conf; -+ hapd->conf = bss; -+ hapd->iface = hapd_iface; -+ hapd->driver = hapd->iconf->driver; -+ -+ return hapd; -+} -+ -+ -+void hostapd_interface_deinit(struct hostapd_iface *iface) -+{ -+ size_t j; -+ -+ if (iface == NULL) -+ return; -+ -+ hostapd_cleanup_iface_pre(iface); -+ for (j = 0; j < iface->num_bss; j++) { -+ struct hostapd_data *hapd = iface->bss[j]; -+ hostapd_free_stas(hapd); -+ hostapd_flush_old_stations(hapd); -+ hostapd_cleanup(hapd); -+ } -+} -+ -+ -+void hostapd_interface_free(struct hostapd_iface *iface) -+{ -+ size_t j; -+ for (j = 0; j < iface->num_bss; j++) -+ os_free(iface->bss[j]); -+ hostapd_cleanup_iface(iface); -+} -+ -+ -+/** -+ * hostapd_new_assoc_sta - Notify that a new station associated with the AP -+ * @hapd: Pointer to BSS data -+ * @sta: Pointer to the associated STA data -+ * @reassoc: 1 to indicate this was a re-association; 0 = first association -+ * -+ * This function will be called whenever a station associates with the AP. It -+ * can be called from ieee802_11.c for drivers that export MLME to hostapd and -+ * from drv_callbacks.c based on driver events for drivers that take care of -+ * management frames (IEEE 802.11 authentication and association) internally. -+ */ -+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ int reassoc) -+{ -+ if (hapd->tkip_countermeasures) { -+ hostapd_drv_sta_deauth(hapd, sta->addr, -+ WLAN_REASON_MICHAEL_MIC_FAILURE); -+ return; -+ } -+ -+ hostapd_prune_associations(hapd, sta->addr); -+ -+ /* IEEE 802.11F (IAPP) */ -+ if (hapd->conf->ieee802_11f) -+ iapp_new_station(hapd->iapp, sta); -+ -+#ifdef CONFIG_P2P -+ if (sta->p2p_ie == NULL && !sta->no_p2p_set) { -+ sta->no_p2p_set = 1; -+ hapd->num_sta_no_p2p++; -+ if (hapd->num_sta_no_p2p == 1) -+ hostapd_p2p_non_p2p_sta_connected(hapd); -+ } -+#endif /* CONFIG_P2P */ -+ -+ /* Start accounting here, if IEEE 802.1X and WPA are not used. -+ * IEEE 802.1X/WPA code will start accounting after the station has -+ * been authorized. */ -+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) -+ accounting_sta_start(hapd, sta); -+ -+ /* Start IEEE 802.1X authentication process for new stations */ -+ ieee802_1x_new_station(hapd, sta); -+ if (reassoc) { -+ if (sta->auth_alg != WLAN_AUTH_FT && -+ !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) -+ wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); -+ } else -+ wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.h -new file mode 100644 -index 0000000000000..d4501a1bb16cb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hostapd.h -@@ -0,0 +1,262 @@ -+/* -+ * hostapd / Initialization and configuration -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef HOSTAPD_H -+#define HOSTAPD_H -+ -+#include "common/defs.h" -+ -+struct wpa_driver_ops; -+struct wpa_ctrl_dst; -+struct radius_server_data; -+struct upnp_wps_device_sm; -+struct hapd_interfaces; -+struct hostapd_data; -+struct sta_info; -+struct hostap_sta_driver_data; -+struct ieee80211_ht_capabilities; -+struct full_dynamic_vlan; -+enum wps_event; -+union wps_event_data; -+ -+struct hostapd_probereq_cb { -+ int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len); -+ void *ctx; -+}; -+ -+#define HOSTAPD_RATE_BASIC 0x00000001 -+ -+struct hostapd_rate_data { -+ int rate; /* rate in 100 kbps */ -+ int flags; /* HOSTAPD_RATE_ flags */ -+}; -+ -+struct hostapd_frame_info { -+ u32 channel; -+ u32 datarate; -+ u32 ssi_signal; -+}; -+ -+ -+/** -+ * struct hostapd_data - hostapd per-BSS data structure -+ */ -+struct hostapd_data { -+ struct hostapd_iface *iface; -+ struct hostapd_config *iconf; -+ struct hostapd_bss_config *conf; -+ int interface_added; /* virtual interface added for this BSS */ -+ -+ u8 own_addr[ETH_ALEN]; -+ -+ int num_sta; /* number of entries in sta_list */ -+ struct sta_info *sta_list; /* STA info list head */ -+#define STA_HASH_SIZE 256 -+#define STA_HASH(sta) (sta[5]) -+ struct sta_info *sta_hash[STA_HASH_SIZE]; -+ -+ /* -+ * Bitfield for indicating which AIDs are allocated. Only AID values -+ * 1-2007 are used and as such, the bit at index 0 corresponds to AID -+ * 1. -+ */ -+#define AID_WORDS ((2008 + 31) / 32) -+ u32 sta_aid[AID_WORDS]; -+ -+ const struct wpa_driver_ops *driver; -+ void *drv_priv; -+ -+ void (*new_assoc_sta_cb)(struct hostapd_data *hapd, -+ struct sta_info *sta, int reassoc); -+ -+ void *msg_ctx; /* ctx for wpa_msg() calls */ -+ -+ struct radius_client_data *radius; -+ u32 acct_session_id_hi, acct_session_id_lo; -+ -+ struct iapp_data *iapp; -+ -+ struct hostapd_cached_radius_acl *acl_cache; -+ struct hostapd_acl_query_data *acl_queries; -+ -+ struct wpa_authenticator *wpa_auth; -+ struct eapol_authenticator *eapol_auth; -+ -+ struct rsn_preauth_interface *preauth_iface; -+ time_t michael_mic_failure; -+ int michael_mic_failures; -+ int tkip_countermeasures; -+ -+ int ctrl_sock; -+ struct wpa_ctrl_dst *ctrl_dst; -+ -+ void *ssl_ctx; -+ void *eap_sim_db_priv; -+ struct radius_server_data *radius_srv; -+ -+ int parameter_set_count; -+ -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ struct full_dynamic_vlan *full_dynamic_vlan; -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ -+ struct l2_packet_data *l2; -+ struct wps_context *wps; -+ -+ struct wpabuf *wps_beacon_ie; -+ struct wpabuf *wps_probe_resp_ie; -+#ifdef CONFIG_WPS -+ unsigned int ap_pin_failures; -+ struct upnp_wps_device_sm *wps_upnp; -+ unsigned int ap_pin_lockout_time; -+#endif /* CONFIG_WPS */ -+ -+ struct hostapd_probereq_cb *probereq_cb; -+ size_t num_probereq_cb; -+ -+ void (*public_action_cb)(void *ctx, const u8 *buf, size_t len, -+ int freq); -+ void *public_action_cb_ctx; -+ -+ int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len, -+ int freq); -+ void *vendor_action_cb_ctx; -+ -+ void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr, -+ const u8 *uuid_e); -+ void *wps_reg_success_cb_ctx; -+ -+ void (*wps_event_cb)(void *ctx, enum wps_event event, -+ union wps_event_data *data); -+ void *wps_event_cb_ctx; -+ -+ void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, -+ int authorized); -+ void *sta_authorized_cb_ctx; -+ -+ void (*setup_complete_cb)(void *ctx); -+ void *setup_complete_cb_ctx; -+ -+#ifdef CONFIG_P2P -+ struct p2p_data *p2p; -+ struct p2p_group *p2p_group; -+ struct wpabuf *p2p_beacon_ie; -+ struct wpabuf *p2p_probe_resp_ie; -+ -+ /* Number of non-P2P association stations */ -+ int num_sta_no_p2p; -+ -+ /* Periodic NoA (used only when no non-P2P clients in the group) */ -+ int noa_enabled; -+ int noa_start; -+ int noa_duration; -+#endif /* CONFIG_P2P */ -+}; -+ -+ -+/** -+ * struct hostapd_iface - hostapd per-interface data structure -+ */ -+struct hostapd_iface { -+ struct hapd_interfaces *interfaces; -+ void *owner; -+ int (*reload_config)(struct hostapd_iface *iface); -+ struct hostapd_config * (*config_read_cb)(const char *config_fname); -+ char *config_fname; -+ struct hostapd_config *conf; -+ -+ size_t num_bss; -+ struct hostapd_data **bss; -+ -+ int num_ap; /* number of entries in ap_list */ -+ struct ap_info *ap_list; /* AP info list head */ -+ struct ap_info *ap_hash[STA_HASH_SIZE]; -+ struct ap_info *ap_iter_list; -+ -+ unsigned int drv_flags; -+ struct hostapd_hw_modes *hw_features; -+ int num_hw_features; -+ struct hostapd_hw_modes *current_mode; -+ /* Rates that are currently used (i.e., filtered copy of -+ * current_mode->channels */ -+ int num_rates; -+ struct hostapd_rate_data *current_rates; -+ int freq; -+ -+ u16 hw_flags; -+ -+ /* Number of associated Non-ERP stations (i.e., stations using 802.11b -+ * in 802.11g BSS) */ -+ int num_sta_non_erp; -+ -+ /* Number of associated stations that do not support Short Slot Time */ -+ int num_sta_no_short_slot_time; -+ -+ /* Number of associated stations that do not support Short Preamble */ -+ int num_sta_no_short_preamble; -+ -+ int olbc; /* Overlapping Legacy BSS Condition */ -+ -+ /* Number of HT associated stations that do not support greenfield */ -+ int num_sta_ht_no_gf; -+ -+ /* Number of associated non-HT stations */ -+ int num_sta_no_ht; -+ -+ /* Number of HT associated stations 20 MHz */ -+ int num_sta_ht_20mhz; -+ -+ /* Overlapping BSS information */ -+ int olbc_ht; -+ -+ u16 ht_op_mode; -+ void (*scan_cb)(struct hostapd_iface *iface); -+ -+ int (*ctrl_iface_init)(struct hostapd_data *hapd); -+ void (*ctrl_iface_deinit)(struct hostapd_data *hapd); -+ -+ int (*for_each_interface)(struct hapd_interfaces *interfaces, -+ int (*cb)(struct hostapd_iface *iface, -+ void *ctx), void *ctx); -+}; -+ -+/* hostapd.c */ -+int hostapd_reload_config(struct hostapd_iface *iface); -+struct hostapd_data * -+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, -+ struct hostapd_config *conf, -+ struct hostapd_bss_config *bss); -+int hostapd_setup_interface(struct hostapd_iface *iface); -+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err); -+void hostapd_interface_deinit(struct hostapd_iface *iface); -+void hostapd_interface_free(struct hostapd_iface *iface); -+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ int reassoc); -+ -+/* utils.c */ -+int hostapd_register_probereq_cb(struct hostapd_data *hapd, -+ int (*cb)(void *ctx, const u8 *sa, -+ const u8 *ie, size_t ie_len), -+ void *ctx); -+void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); -+ -+/* drv_callbacks.c (TODO: move to somewhere else?) */ -+int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *ie, size_t ielen, int reassoc); -+void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); -+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); -+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, -+ const u8 *ie, size_t ie_len); -+ -+#endif /* HOSTAPD_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.c -new file mode 100644 -index 0000000000000..30af9d2874276 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.c -@@ -0,0 +1,754 @@ -+/* -+ * hostapd / Hardware feature query and different modes -+ * Copyright 2002-2003, Instant802 Networks, Inc. -+ * Copyright 2005-2006, Devicescape Software, Inc. -+ * Copyright (c) 2008-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "drivers/driver.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ap_drv_ops.h" -+#include "hw_features.h" -+ -+ -+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, -+ size_t num_hw_features) -+{ -+ size_t i; -+ -+ if (hw_features == NULL) -+ return; -+ -+ for (i = 0; i < num_hw_features; i++) { -+ os_free(hw_features[i].channels); -+ os_free(hw_features[i].rates); -+ } -+ -+ os_free(hw_features); -+} -+ -+ -+int hostapd_get_hw_features(struct hostapd_iface *iface) -+{ -+ struct hostapd_data *hapd = iface->bss[0]; -+ int ret = 0, i, j; -+ u16 num_modes, flags; -+ struct hostapd_hw_modes *modes; -+ -+ if (hostapd_drv_none(hapd)) -+ return -1; -+ modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); -+ if (modes == NULL) { -+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "Fetching hardware channel/rate support not " -+ "supported."); -+ return -1; -+ } -+ -+ iface->hw_flags = flags; -+ -+ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); -+ iface->hw_features = modes; -+ iface->num_hw_features = num_modes; -+ -+ for (i = 0; i < num_modes; i++) { -+ struct hostapd_hw_modes *feature = &modes[i]; -+ /* set flag for channels we can use in current regulatory -+ * domain */ -+ for (j = 0; j < feature->num_channels; j++) { -+ /* -+ * Disable all channels that are marked not to allow -+ * IBSS operation or active scanning. In addition, -+ * disable all channels that require radar detection, -+ * since that (in addition to full DFS) is not yet -+ * supported. -+ */ -+ if (feature->channels[j].flag & -+ (HOSTAPD_CHAN_NO_IBSS | -+ HOSTAPD_CHAN_PASSIVE_SCAN | -+ HOSTAPD_CHAN_RADAR)) -+ feature->channels[j].flag |= -+ HOSTAPD_CHAN_DISABLED; -+ if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED) -+ continue; -+ wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d " -+ "chan=%d freq=%d MHz max_tx_power=%d dBm", -+ feature->mode, -+ feature->channels[j].chan, -+ feature->channels[j].freq, -+ feature->channels[j].max_tx_power); -+ } -+ } -+ -+ return ret; -+} -+ -+ -+int hostapd_prepare_rates(struct hostapd_data *hapd, -+ struct hostapd_hw_modes *mode) -+{ -+ int i, num_basic_rates = 0; -+ int basic_rates_a[] = { 60, 120, 240, -1 }; -+ int basic_rates_b[] = { 10, 20, -1 }; -+ int basic_rates_g[] = { 10, 20, 55, 110, -1 }; -+ int *basic_rates; -+ -+ if (hapd->iconf->basic_rates) -+ basic_rates = hapd->iconf->basic_rates; -+ else switch (mode->mode) { -+ case HOSTAPD_MODE_IEEE80211A: -+ basic_rates = basic_rates_a; -+ break; -+ case HOSTAPD_MODE_IEEE80211B: -+ basic_rates = basic_rates_b; -+ break; -+ case HOSTAPD_MODE_IEEE80211G: -+ basic_rates = basic_rates_g; -+ break; -+ default: -+ return -1; -+ } -+ -+ if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates, -+ basic_rates, mode->mode)) { -+ wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel " -+ "module"); -+ } -+ -+ os_free(hapd->iface->current_rates); -+ hapd->iface->num_rates = 0; -+ -+ hapd->iface->current_rates = -+ os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data)); -+ if (!hapd->iface->current_rates) { -+ wpa_printf(MSG_ERROR, "Failed to allocate memory for rate " -+ "table."); -+ return -1; -+ } -+ -+ for (i = 0; i < mode->num_rates; i++) { -+ struct hostapd_rate_data *rate; -+ -+ if (hapd->iconf->supported_rates && -+ !hostapd_rate_found(hapd->iconf->supported_rates, -+ mode->rates[i])) -+ continue; -+ -+ rate = &hapd->iface->current_rates[hapd->iface->num_rates]; -+ rate->rate = mode->rates[i]; -+ if (hostapd_rate_found(basic_rates, rate->rate)) { -+ rate->flags |= HOSTAPD_RATE_BASIC; -+ num_basic_rates++; -+ } -+ wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x", -+ hapd->iface->num_rates, rate->rate, rate->flags); -+ hapd->iface->num_rates++; -+ } -+ -+ if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) && -+ (!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) { -+ wpa_printf(MSG_ERROR, "No rates remaining in supported/basic " -+ "rate sets (%d,%d).", -+ hapd->iface->num_rates, num_basic_rates); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_IEEE80211N -+static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) -+{ -+ int sec_chan, ok, j, first; -+ int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, -+ 184, 192 }; -+ size_t k; -+ -+ if (!iface->conf->secondary_channel) -+ return 1; /* HT40 not used */ -+ -+ sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4; -+ wpa_printf(MSG_DEBUG, "HT40: control channel: %d " -+ "secondary channel: %d", -+ iface->conf->channel, sec_chan); -+ -+ /* Verify that HT40 secondary channel is an allowed 20 MHz -+ * channel */ -+ ok = 0; -+ for (j = 0; j < iface->current_mode->num_channels; j++) { -+ struct hostapd_channel_data *chan = -+ &iface->current_mode->channels[j]; -+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && -+ chan->chan == sec_chan) { -+ ok = 1; -+ break; -+ } -+ } -+ if (!ok) { -+ wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed", -+ sec_chan); -+ return 0; -+ } -+ -+ /* -+ * Verify that HT40 primary,secondary channel pair is allowed per -+ * IEEE 802.11n Annex J. This is only needed for 5 GHz band since -+ * 2.4 GHz rules allow all cases where the secondary channel fits into -+ * the list of allowed channels (already checked above). -+ */ -+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) -+ return 1; -+ -+ if (iface->conf->secondary_channel > 0) -+ first = iface->conf->channel; -+ else -+ first = sec_chan; -+ -+ ok = 0; -+ for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) { -+ if (first == allowed[k]) { -+ ok = 1; -+ break; -+ } -+ } -+ if (!ok) { -+ wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed", -+ iface->conf->channel, -+ iface->conf->secondary_channel); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+ -+static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface) -+{ -+ if (iface->conf->secondary_channel > 0) { -+ iface->conf->channel += 4; -+ iface->conf->secondary_channel = -1; -+ } else { -+ iface->conf->channel -= 4; -+ iface->conf->secondary_channel = 1; -+ } -+} -+ -+ -+static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss, -+ int *pri_chan, int *sec_chan) -+{ -+ struct ieee80211_ht_operation *oper; -+ struct ieee802_11_elems elems; -+ -+ *pri_chan = *sec_chan = 0; -+ -+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); -+ if (elems.ht_operation && -+ elems.ht_operation_len >= sizeof(*oper)) { -+ oper = (struct ieee80211_ht_operation *) elems.ht_operation; -+ *pri_chan = oper->control_chan; -+ if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) { -+ int sec = oper->ht_param & -+ HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK; -+ if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE) -+ *sec_chan = *pri_chan + 4; -+ else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) -+ *sec_chan = *pri_chan - 4; -+ } -+ } -+} -+ -+ -+static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, -+ struct wpa_scan_results *scan_res) -+{ -+ int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss; -+ int bss_pri_chan, bss_sec_chan; -+ size_t i; -+ int match; -+ -+ pri_chan = iface->conf->channel; -+ sec_chan = iface->conf->secondary_channel * 4; -+ pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); -+ if (iface->conf->secondary_channel > 0) -+ sec_freq = pri_freq + 20; -+ else -+ sec_freq = pri_freq - 20; -+ -+ /* -+ * Switch PRI/SEC channels if Beacons were detected on selected SEC -+ * channel, but not on selected PRI channel. -+ */ -+ pri_bss = sec_bss = 0; -+ for (i = 0; i < scan_res->num; i++) { -+ struct wpa_scan_res *bss = scan_res->res[i]; -+ if (bss->freq == pri_freq) -+ pri_bss++; -+ else if (bss->freq == sec_freq) -+ sec_bss++; -+ } -+ if (sec_bss && !pri_bss) { -+ wpa_printf(MSG_INFO, "Switch own primary and secondary " -+ "channel to get secondary channel with no Beacons " -+ "from other BSSes"); -+ ieee80211n_switch_pri_sec(iface); -+ } -+ -+ /* -+ * Match PRI/SEC channel with any existing HT40 BSS on the same -+ * channels that we are about to use (if already mixed order in -+ * existing BSSes, use own preference). -+ */ -+ match = 0; -+ for (i = 0; i < scan_res->num; i++) { -+ struct wpa_scan_res *bss = scan_res->res[i]; -+ ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan); -+ if (pri_chan == bss_pri_chan && -+ sec_chan == bss_sec_chan) { -+ match = 1; -+ break; -+ } -+ } -+ if (!match) { -+ for (i = 0; i < scan_res->num; i++) { -+ struct wpa_scan_res *bss = scan_res->res[i]; -+ ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, -+ &bss_sec_chan); -+ if (pri_chan == bss_sec_chan && -+ sec_chan == bss_pri_chan) { -+ wpa_printf(MSG_INFO, "Switch own primary and " -+ "secondary channel due to BSS " -+ "overlap with " MACSTR, -+ MAC2STR(bss->bssid)); -+ ieee80211n_switch_pri_sec(iface); -+ break; -+ } -+ } -+ } -+ -+ return 1; -+} -+ -+ -+static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface, -+ struct wpa_scan_results *scan_res) -+{ -+ int pri_freq, sec_freq; -+ int affected_start, affected_end; -+ size_t i; -+ -+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel); -+ if (iface->conf->secondary_channel > 0) -+ sec_freq = pri_freq + 20; -+ else -+ sec_freq = pri_freq - 20; -+ affected_start = (pri_freq + sec_freq) / 2 - 25; -+ affected_end = (pri_freq + sec_freq) / 2 + 25; -+ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz", -+ affected_start, affected_end); -+ for (i = 0; i < scan_res->num; i++) { -+ struct wpa_scan_res *bss = scan_res->res[i]; -+ int pri = bss->freq; -+ int sec = pri; -+ int sec_chan, pri_chan; -+ -+ ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan); -+ -+ if (sec_chan) { -+ if (sec_chan < pri_chan) -+ sec = pri - 20; -+ else -+ sec = pri + 20; -+ } -+ -+ if ((pri < affected_start || pri > affected_end) && -+ (sec < affected_start || sec > affected_end)) -+ continue; /* not within affected channel range */ -+ -+ wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR -+ " freq=%d pri=%d sec=%d", -+ MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan); -+ -+ if (sec_chan) { -+ if (pri_freq != pri || sec_freq != sec) { -+ wpa_printf(MSG_DEBUG, "40 MHz pri/sec " -+ "mismatch with BSS " MACSTR -+ " <%d,%d> (chan=%d%c) vs. <%d,%d>", -+ MAC2STR(bss->bssid), -+ pri, sec, pri_chan, -+ sec > pri ? '+' : '-', -+ pri_freq, sec_freq); -+ return 0; -+ } -+ } -+ -+ /* TODO: 40 MHz intolerant */ -+ } -+ -+ return 1; -+} -+ -+ -+static void wpa_scan_results_free(struct wpa_scan_results *res) -+{ -+ size_t i; -+ -+ if (res == NULL) -+ return; -+ -+ for (i = 0; i < res->num; i++) -+ os_free(res->res[i]); -+ os_free(res->res); -+ os_free(res); -+} -+ -+ -+static void ieee80211n_check_scan(struct hostapd_iface *iface) -+{ -+ struct wpa_scan_results *scan_res; -+ int oper40; -+ int res; -+ -+ /* Check list of neighboring BSSes (from scan) to see whether 40 MHz is -+ * allowed per IEEE 802.11n/D7.0, 11.14.3.2 */ -+ -+ iface->scan_cb = NULL; -+ -+ scan_res = hostapd_driver_get_scan_results(iface->bss[0]); -+ if (scan_res == NULL) { -+ hostapd_setup_interface_complete(iface, 1); -+ return; -+ } -+ -+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A) -+ oper40 = ieee80211n_check_40mhz_5g(iface, scan_res); -+ else -+ oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res); -+ wpa_scan_results_free(scan_res); -+ -+ if (!oper40) { -+ wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on " -+ "channel pri=%d sec=%d based on overlapping BSSes", -+ iface->conf->channel, -+ iface->conf->channel + -+ iface->conf->secondary_channel * 4); -+ iface->conf->secondary_channel = 0; -+ iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; -+ } -+ -+ res = ieee80211n_allowed_ht40_channel_pair(iface); -+ hostapd_setup_interface_complete(iface, !res); -+} -+ -+ -+static int ieee80211n_check_40mhz(struct hostapd_iface *iface) -+{ -+ struct wpa_driver_scan_params params; -+ -+ if (!iface->conf->secondary_channel) -+ return 0; /* HT40 not used */ -+ -+ wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " -+ "40 MHz channel"); -+ os_memset(¶ms, 0, sizeof(params)); -+ /* TODO: scan only the needed frequency */ -+ if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { -+ wpa_printf(MSG_ERROR, "Failed to request a scan of " -+ "neighboring BSSes"); -+ -+ //DRIVER_RTW Modify -+ //return -1; -+ return 0;//ignore this error -+ } -+ -+ iface->scan_cb = ieee80211n_check_scan; -+ return 1; -+} -+ -+ -+static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) -+{ -+ u16 hw = iface->current_mode->ht_capab; -+ u16 conf = iface->conf->ht_capab; -+ -+ if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) && -+ !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [LDPC]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) && -+ !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [HT40*]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) && -+ (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [SMPS-*]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_GREEN_FIELD) && -+ !(hw & HT_CAP_INFO_GREEN_FIELD)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [GF]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) && -+ !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [SHORT-GI-20]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) && -+ !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [SHORT-GI-40]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [TX-STBC]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_RX_STBC_MASK) > -+ (hw & HT_CAP_INFO_RX_STBC_MASK)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [RX-STBC*]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_DELAYED_BA) && -+ !(hw & HT_CAP_INFO_DELAYED_BA)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [DELAYED-BA]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) && -+ !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [MAX-AMSDU-7935]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) && -+ !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [DSSS_CCK-40]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [PSMP]"); -+ return 0; -+ } -+ -+ if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) && -+ !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) { -+ wpa_printf(MSG_ERROR, "Driver does not support configured " -+ "HT capability [LSIG-TXOP-PROT]"); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+#endif /* CONFIG_IEEE80211N */ -+ -+ -+int hostapd_check_ht_capab(struct hostapd_iface *iface) -+{ -+#ifdef CONFIG_IEEE80211N -+ int ret; -+ if (!iface->conf->ieee80211n) -+ return 0; -+ if (!ieee80211n_supported_ht_capab(iface)) -+ return -1; -+ ret = ieee80211n_check_40mhz(iface); -+ if (ret) -+ return ret; -+ if (!ieee80211n_allowed_ht40_channel_pair(iface)) -+ return -1; -+#endif /* CONFIG_IEEE80211N */ -+ -+ return 0; -+} -+ -+ -+/** -+ * hostapd_select_hw_mode - Select the hardware mode -+ * @iface: Pointer to interface data. -+ * Returns: 0 on success, -1 on failure -+ * -+ * Sets up the hardware mode, channel, rates, and passive scanning -+ * based on the configuration. -+ */ -+int hostapd_select_hw_mode(struct hostapd_iface *iface) -+{ -+ int i, j, ok; -+ -+ if (iface->num_hw_features < 1) -+ return -1; -+ -+ iface->current_mode = NULL; -+ for (i = 0; i < iface->num_hw_features; i++) { -+ struct hostapd_hw_modes *mode = &iface->hw_features[i]; -+ if (mode->mode == iface->conf->hw_mode) { -+ iface->current_mode = mode; -+ break; -+ } -+ } -+ -+ if (iface->current_mode == NULL) { -+ wpa_printf(MSG_ERROR, "Hardware does not support configured " -+ "mode"); -+ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_WARNING, -+ "Hardware does not support configured mode " -+ "(%d)", (int) iface->conf->hw_mode); -+ return -1; -+ } -+ -+ ok = 0; -+ for (j = 0; j < iface->current_mode->num_channels; j++) { -+ struct hostapd_channel_data *chan = -+ &iface->current_mode->channels[j]; -+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && -+ (chan->chan == iface->conf->channel)) { -+ ok = 1; -+ break; -+ } -+ } -+ if (ok && iface->conf->secondary_channel) { -+ int sec_ok = 0; -+ int sec_chan = iface->conf->channel + -+ iface->conf->secondary_channel * 4; -+ for (j = 0; j < iface->current_mode->num_channels; j++) { -+ struct hostapd_channel_data *chan = -+ &iface->current_mode->channels[j]; -+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && -+ (chan->chan == sec_chan)) { -+ sec_ok = 1; -+ break; -+ } -+ } -+ if (!sec_ok) { -+ hostapd_logger(iface->bss[0], NULL, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_WARNING, -+ "Configured HT40 secondary channel " -+ "(%d) not found from the channel list " -+ "of current mode (%d) %s", -+ sec_chan, iface->current_mode->mode, -+ hostapd_hw_mode_txt( -+ iface->current_mode->mode)); -+ ok = 0; -+ } -+ } -+ if (iface->conf->channel == 0) { -+ /* TODO: could request a scan of neighboring BSSes and select -+ * the channel automatically */ -+ wpa_printf(MSG_ERROR, "Channel not configured " -+ "(hw_mode/channel in hostapd.conf)"); -+ return -1; -+ } -+ if (ok == 0 && iface->conf->channel != 0) { -+ hostapd_logger(iface->bss[0], NULL, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_WARNING, -+ "Configured channel (%d) not found from the " -+ "channel list of current mode (%d) %s", -+ iface->conf->channel, -+ iface->current_mode->mode, -+ hostapd_hw_mode_txt(iface->current_mode->mode)); -+ iface->current_mode = NULL; -+ } -+ -+ if (iface->current_mode == NULL) { -+ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_WARNING, -+ "Hardware does not support configured channel"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+const char * hostapd_hw_mode_txt(int mode) -+{ -+ switch (mode) { -+ case HOSTAPD_MODE_IEEE80211A: -+ return "IEEE 802.11a"; -+ case HOSTAPD_MODE_IEEE80211B: -+ return "IEEE 802.11b"; -+ case HOSTAPD_MODE_IEEE80211G: -+ return "IEEE 802.11g"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+ -+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) -+{ -+ int i; -+ -+ if (!hapd->iface->current_mode) -+ return 0; -+ -+ for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { -+ struct hostapd_channel_data *ch = -+ &hapd->iface->current_mode->channels[i]; -+ if (ch->chan == chan) -+ return ch->freq; -+ } -+ -+ return 0; -+} -+ -+ -+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) -+{ -+ int i; -+ -+ if (!hapd->iface->current_mode) -+ return 0; -+ -+ for (i = 0; i < hapd->iface->current_mode->num_channels; i++) { -+ struct hostapd_channel_data *ch = -+ &hapd->iface->current_mode->channels[i]; -+ if (ch->freq == freq) -+ return ch->chan; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.h -new file mode 100644 -index 0000000000000..88c232215619a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/hw_features.h -@@ -0,0 +1,70 @@ -+/* -+ * hostapd / Hardware feature query and different modes -+ * Copyright 2002-2003, Instant802 Networks, Inc. -+ * Copyright 2005-2006, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef HW_FEATURES_H -+#define HW_FEATURES_H -+ -+#ifdef NEED_AP_MLME -+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, -+ size_t num_hw_features); -+int hostapd_get_hw_features(struct hostapd_iface *iface); -+int hostapd_select_hw_mode(struct hostapd_iface *iface); -+const char * hostapd_hw_mode_txt(int mode); -+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan); -+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq); -+int hostapd_check_ht_capab(struct hostapd_iface *iface); -+int hostapd_prepare_rates(struct hostapd_data *hapd, -+ struct hostapd_hw_modes *mode); -+#else /* NEED_AP_MLME */ -+static inline void -+hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, -+ size_t num_hw_features) -+{ -+} -+ -+static inline int hostapd_get_hw_features(struct hostapd_iface *iface) -+{ -+ return -1; -+} -+ -+static inline int hostapd_select_hw_mode(struct hostapd_iface *iface) -+{ -+ return -1; -+} -+ -+static inline const char * hostapd_hw_mode_txt(int mode) -+{ -+ return NULL; -+} -+ -+static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) -+{ -+ return -1; -+} -+ -+static inline int hostapd_check_ht_capab(struct hostapd_iface *iface) -+{ -+ return 0; -+} -+ -+static inline int hostapd_prepare_rates(struct hostapd_data *hapd, -+ struct hostapd_hw_modes *mode) -+{ -+ return 0; -+} -+ -+#endif /* NEED_AP_MLME */ -+ -+#endif /* HW_FEATURES_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.c -new file mode 100644 -index 0000000000000..115d91e8ce30c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.c -@@ -0,0 +1,535 @@ -+/* -+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP) -+ * Copyright (c) 2002-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired -+ * and IEEE has withdrawn it. In other words, it is likely better to look at -+ * using some other mechanism for AP-to-AP communication than extending the -+ * implementation here. -+ */ -+ -+/* TODO: -+ * Level 1: no administrative or security support -+ * (e.g., static BSSID to IP address mapping in each AP) -+ * Level 2: support for dynamic mapping of BSSID to IP address -+ * Level 3: support for encryption and authentication of IAPP messages -+ * - add support for MOVE-notify and MOVE-response (this requires support for -+ * finding out IP address for previous AP using RADIUS) -+ * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during -+ * reassociation to another AP -+ * - implement counters etc. for IAPP MIB -+ * - verify endianness of fields in IAPP messages; are they big-endian as -+ * used here? -+ * - RADIUS connection for AP registration and BSSID to IP address mapping -+ * - TCP connection for IAPP MOVE, CACHE -+ * - broadcast ESP for IAPP ADD-notify -+ * - ESP for IAPP MOVE messages -+ * - security block sending/processing -+ * - IEEE 802.11 context transfer -+ */ -+ -+#include "utils/includes.h" -+#include -+#include -+#ifdef USE_KERNEL_HEADERS -+#include -+#else /* USE_KERNEL_HEADERS */ -+#include -+#endif /* USE_KERNEL_HEADERS */ -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ieee802_11.h" -+#include "sta_info.h" -+#include "iapp.h" -+ -+ -+#define IAPP_MULTICAST "224.0.1.178" -+#define IAPP_UDP_PORT 3517 -+#define IAPP_TCP_PORT 3517 -+ -+struct iapp_hdr { -+ u8 version; -+ u8 command; -+ be16 identifier; -+ be16 length; -+ /* followed by length-6 octets of data */ -+} __attribute__ ((packed)); -+ -+#define IAPP_VERSION 0 -+ -+enum IAPP_COMMAND { -+ IAPP_CMD_ADD_notify = 0, -+ IAPP_CMD_MOVE_notify = 1, -+ IAPP_CMD_MOVE_response = 2, -+ IAPP_CMD_Send_Security_Block = 3, -+ IAPP_CMD_ACK_Security_Block = 4, -+ IAPP_CMD_CACHE_notify = 5, -+ IAPP_CMD_CACHE_response = 6, -+}; -+ -+ -+/* ADD-notify - multicast UDP on the local LAN */ -+struct iapp_add_notify { -+ u8 addr_len; /* ETH_ALEN */ -+ u8 reserved; -+ u8 mac_addr[ETH_ALEN]; -+ be16 seq_num; -+} __attribute__ ((packed)); -+ -+ -+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ -+struct iapp_layer2_update { -+ u8 da[ETH_ALEN]; /* broadcast */ -+ u8 sa[ETH_ALEN]; /* STA addr */ -+ be16 len; /* 6 */ -+ u8 dsap; /* null DSAP address */ -+ u8 ssap; /* null SSAP address, CR=Response */ -+ u8 control; -+ u8 xid_info[3]; -+} __attribute__ ((packed)); -+ -+ -+/* MOVE-notify - unicast TCP */ -+struct iapp_move_notify { -+ u8 addr_len; /* ETH_ALEN */ -+ u8 reserved; -+ u8 mac_addr[ETH_ALEN]; -+ u16 seq_num; -+ u16 ctx_block_len; -+ /* followed by ctx_block_len bytes */ -+} __attribute__ ((packed)); -+ -+ -+/* MOVE-response - unicast TCP */ -+struct iapp_move_response { -+ u8 addr_len; /* ETH_ALEN */ -+ u8 status; -+ u8 mac_addr[ETH_ALEN]; -+ u16 seq_num; -+ u16 ctx_block_len; -+ /* followed by ctx_block_len bytes */ -+} __attribute__ ((packed)); -+ -+enum { -+ IAPP_MOVE_SUCCESSFUL = 0, -+ IAPP_MOVE_DENIED = 1, -+ IAPP_MOVE_STALE_MOVE = 2, -+}; -+ -+ -+/* CACHE-notify */ -+struct iapp_cache_notify { -+ u8 addr_len; /* ETH_ALEN */ -+ u8 reserved; -+ u8 mac_addr[ETH_ALEN]; -+ u16 seq_num; -+ u8 current_ap[ETH_ALEN]; -+ u16 ctx_block_len; -+ /* ctx_block_len bytes of context block followed by 16-bit context -+ * timeout */ -+} __attribute__ ((packed)); -+ -+ -+/* CACHE-response - unicast TCP */ -+struct iapp_cache_response { -+ u8 addr_len; /* ETH_ALEN */ -+ u8 status; -+ u8 mac_addr[ETH_ALEN]; -+ u16 seq_num; -+} __attribute__ ((packed)); -+ -+enum { -+ IAPP_CACHE_SUCCESSFUL = 0, -+ IAPP_CACHE_STALE_CACHE = 1, -+}; -+ -+ -+/* Send-Security-Block - unicast TCP */ -+struct iapp_send_security_block { -+ u8 iv[8]; -+ u16 sec_block_len; -+ /* followed by sec_block_len bytes of security block */ -+} __attribute__ ((packed)); -+ -+ -+/* ACK-Security-Block - unicast TCP */ -+struct iapp_ack_security_block { -+ u8 iv[8]; -+ u8 new_ap_ack_authenticator[48]; -+} __attribute__ ((packed)); -+ -+ -+struct iapp_data { -+ struct hostapd_data *hapd; -+ u16 identifier; /* next IAPP identifier */ -+ struct in_addr own, multicast; -+ int udp_sock; -+ int packet_sock; -+}; -+ -+ -+static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num) -+{ -+ char buf[128]; -+ struct iapp_hdr *hdr; -+ struct iapp_add_notify *add; -+ struct sockaddr_in addr; -+ -+ /* Send IAPP ADD-notify to remove possible association from other APs -+ */ -+ -+ hdr = (struct iapp_hdr *) buf; -+ hdr->version = IAPP_VERSION; -+ hdr->command = IAPP_CMD_ADD_notify; -+ hdr->identifier = host_to_be16(iapp->identifier++); -+ hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add)); -+ -+ add = (struct iapp_add_notify *) (hdr + 1); -+ add->addr_len = ETH_ALEN; -+ add->reserved = 0; -+ os_memcpy(add->mac_addr, mac_addr, ETH_ALEN); -+ -+ add->seq_num = host_to_be16(seq_num); -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sin_family = AF_INET; -+ addr.sin_addr.s_addr = iapp->multicast.s_addr; -+ addr.sin_port = htons(IAPP_UDP_PORT); -+ if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0, -+ (struct sockaddr *) &addr, sizeof(addr)) < 0) -+ perror("sendto[IAPP-ADD]"); -+} -+ -+ -+static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr) -+{ -+ struct iapp_layer2_update msg; -+ -+ /* Send Level 2 Update Frame to update forwarding tables in layer 2 -+ * bridge devices */ -+ -+ /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) -+ * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ -+ -+ os_memset(msg.da, 0xff, ETH_ALEN); -+ os_memcpy(msg.sa, addr, ETH_ALEN); -+ msg.len = host_to_be16(6); -+ msg.dsap = 0; /* NULL DSAP address */ -+ msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */ -+ msg.control = 0xaf; /* XID response lsb.1111F101. -+ * F=0 (no poll command; unsolicited frame) */ -+ msg.xid_info[0] = 0x81; /* XID format identifier */ -+ msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ -+ msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW) -+ * FIX: what is correct RW with 802.11? */ -+ -+ if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0) -+ perror("send[L2 Update]"); -+} -+ -+ -+/** -+ * iapp_new_station - IAPP processing for a new STA -+ * @iapp: IAPP data -+ * @sta: The associated station -+ */ -+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta) -+{ -+ struct ieee80211_mgmt *assoc; -+ u16 seq; -+ -+ if (iapp == NULL) -+ return; -+ -+ assoc = sta->last_assoc_req; -+ seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0; -+ -+ /* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */ -+ hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP, -+ HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq); -+ iapp_send_layer2_update(iapp, sta->addr); -+ iapp_send_add(iapp, sta->addr, seq); -+ -+ if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) == -+ WLAN_FC_STYPE_REASSOC_REQ) { -+ /* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP, -+ * Context Block, Timeout) -+ */ -+ /* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to -+ * IP address */ -+ } -+} -+ -+ -+static void iapp_process_add_notify(struct iapp_data *iapp, -+ struct sockaddr_in *from, -+ struct iapp_hdr *hdr, int len) -+{ -+ struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1); -+ struct sta_info *sta; -+ -+ if (len != sizeof(*add)) { -+ printf("Invalid IAPP-ADD packet length %d (expected %lu)\n", -+ len, (unsigned long) sizeof(*add)); -+ return; -+ } -+ -+ sta = ap_get_sta(iapp->hapd, add->mac_addr); -+ -+ /* IAPP-ADD.indication(MAC Address, Sequence Number) */ -+ hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP, -+ HOSTAPD_LEVEL_INFO, -+ "Received IAPP ADD-notify (seq# %d) from %s:%d%s", -+ be_to_host16(add->seq_num), -+ inet_ntoa(from->sin_addr), ntohs(from->sin_port), -+ sta ? "" : " (STA not found)"); -+ -+ if (!sta) -+ return; -+ -+ /* TODO: could use seq_num to try to determine whether last association -+ * to this AP is newer than the one advertised in IAPP-ADD. Although, -+ * this is not really a reliable verification. */ -+ -+ hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP, -+ HOSTAPD_LEVEL_DEBUG, -+ "Removing STA due to IAPP ADD-notify"); -+ ap_sta_disconnect(iapp->hapd, sta, NULL, 0); -+} -+ -+ -+/** -+ * iapp_receive_udp - Process IAPP UDP frames -+ * @sock: File descriptor for the socket -+ * @eloop_ctx: IAPP data (struct iapp_data *) -+ * @sock_ctx: Not used -+ */ -+static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct iapp_data *iapp = eloop_ctx; -+ int len, hlen; -+ unsigned char buf[128]; -+ struct sockaddr_in from; -+ socklen_t fromlen; -+ struct iapp_hdr *hdr; -+ -+ /* Handle incoming IAPP frames (over UDP/IP) */ -+ -+ fromlen = sizeof(from); -+ len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0, -+ (struct sockaddr *) &from, &fromlen); -+ if (len < 0) { -+ perror("recvfrom"); -+ return; -+ } -+ -+ if (from.sin_addr.s_addr == iapp->own.s_addr) -+ return; /* ignore own IAPP messages */ -+ -+ hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP, -+ HOSTAPD_LEVEL_DEBUG, -+ "Received %d byte IAPP frame from %s%s\n", -+ len, inet_ntoa(from.sin_addr), -+ len < (int) sizeof(*hdr) ? " (too short)" : ""); -+ -+ if (len < (int) sizeof(*hdr)) -+ return; -+ -+ hdr = (struct iapp_hdr *) buf; -+ hlen = be_to_host16(hdr->length); -+ hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP, -+ HOSTAPD_LEVEL_DEBUG, -+ "RX: version=%d command=%d id=%d len=%d\n", -+ hdr->version, hdr->command, -+ be_to_host16(hdr->identifier), hlen); -+ if (hdr->version != IAPP_VERSION) { -+ printf("Dropping IAPP frame with unknown version %d\n", -+ hdr->version); -+ return; -+ } -+ if (hlen > len) { -+ printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len); -+ return; -+ } -+ if (hlen < len) { -+ printf("Ignoring %d extra bytes from IAPP frame\n", -+ len - hlen); -+ len = hlen; -+ } -+ -+ switch (hdr->command) { -+ case IAPP_CMD_ADD_notify: -+ iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr)); -+ break; -+ case IAPP_CMD_MOVE_notify: -+ /* TODO: MOVE is using TCP; so move this to TCP handler once it -+ * is implemented.. */ -+ /* IAPP-MOVE.indication(MAC Address, New BSSID, -+ * Sequence Number, AP Address, Context Block) */ -+ /* TODO: process */ -+ break; -+ default: -+ printf("Unknown IAPP command %d\n", hdr->command); -+ break; -+ } -+} -+ -+ -+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface) -+{ -+ struct ifreq ifr; -+ struct sockaddr_ll addr; -+ int ifindex; -+ struct sockaddr_in *paddr, uaddr; -+ struct iapp_data *iapp; -+ struct ip_mreqn mreq; -+ -+ iapp = os_zalloc(sizeof(*iapp)); -+ if (iapp == NULL) -+ return NULL; -+ iapp->hapd = hapd; -+ iapp->udp_sock = iapp->packet_sock = -1; -+ -+ /* TODO: -+ * open socket for sending and receiving IAPP frames over TCP -+ */ -+ -+ iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (iapp->udp_sock < 0) { -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); -+ if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) { -+ perror("ioctl(SIOCGIFINDEX)"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ ifindex = ifr.ifr_ifindex; -+ -+ if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) { -+ perror("ioctl(SIOCGIFADDR)"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ paddr = (struct sockaddr_in *) &ifr.ifr_addr; -+ if (paddr->sin_family != AF_INET) { -+ printf("Invalid address family %i (SIOCGIFADDR)\n", -+ paddr->sin_family); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ iapp->own.s_addr = paddr->sin_addr.s_addr; -+ -+ if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) { -+ perror("ioctl(SIOCGIFBRDADDR)"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ paddr = (struct sockaddr_in *) &ifr.ifr_addr; -+ if (paddr->sin_family != AF_INET) { -+ printf("Invalid address family %i (SIOCGIFBRDADDR)\n", -+ paddr->sin_family); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ inet_aton(IAPP_MULTICAST, &iapp->multicast); -+ -+ os_memset(&uaddr, 0, sizeof(uaddr)); -+ uaddr.sin_family = AF_INET; -+ uaddr.sin_port = htons(IAPP_UDP_PORT); -+ if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr, -+ sizeof(uaddr)) < 0) { -+ perror("bind[UDP]"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ -+ os_memset(&mreq, 0, sizeof(mreq)); -+ mreq.imr_multiaddr = iapp->multicast; -+ mreq.imr_address.s_addr = INADDR_ANY; -+ mreq.imr_ifindex = 0; -+ if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, -+ sizeof(mreq)) < 0) { -+ perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ -+ iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); -+ if (iapp->packet_sock < 0) { -+ perror("socket[PF_PACKET,SOCK_RAW]"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sll_family = AF_PACKET; -+ addr.sll_ifindex = ifindex; -+ if (bind(iapp->packet_sock, (struct sockaddr *) &addr, -+ sizeof(addr)) < 0) { -+ perror("bind[PACKET]"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ -+ if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp, -+ iapp, NULL)) { -+ printf("Could not register read socket for IAPP.\n"); -+ iapp_deinit(iapp); -+ return NULL; -+ } -+ -+ printf("IEEE 802.11F (IAPP) using interface %s\n", iface); -+ -+ /* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive -+ * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually -+ * be openned only after receiving Initiate-Accept. If Initiate-Reject -+ * is received, IAPP is not started. */ -+ -+ return iapp; -+} -+ -+ -+void iapp_deinit(struct iapp_data *iapp) -+{ -+ struct ip_mreqn mreq; -+ -+ if (iapp == NULL) -+ return; -+ -+ if (iapp->udp_sock >= 0) { -+ os_memset(&mreq, 0, sizeof(mreq)); -+ mreq.imr_multiaddr = iapp->multicast; -+ mreq.imr_address.s_addr = INADDR_ANY; -+ mreq.imr_ifindex = 0; -+ if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP, -+ &mreq, sizeof(mreq)) < 0) { -+ perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]"); -+ } -+ -+ eloop_unregister_read_sock(iapp->udp_sock); -+ close(iapp->udp_sock); -+ } -+ if (iapp->packet_sock >= 0) { -+ eloop_unregister_read_sock(iapp->packet_sock); -+ close(iapp->packet_sock); -+ } -+ os_free(iapp); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.h -new file mode 100644 -index 0000000000000..5fc01cb703550 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/iapp.h -@@ -0,0 +1,45 @@ -+/* -+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP) -+ * Copyright (c) 2002-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IAPP_H -+#define IAPP_H -+ -+struct iapp_data; -+ -+#ifdef CONFIG_IAPP -+ -+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta); -+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface); -+void iapp_deinit(struct iapp_data *iapp); -+ -+#else /* CONFIG_IAPP */ -+ -+static inline void iapp_new_station(struct iapp_data *iapp, -+ struct sta_info *sta) -+{ -+} -+ -+static inline struct iapp_data * iapp_init(struct hostapd_data *hapd, -+ const char *iface) -+{ -+ return NULL; -+} -+ -+static inline void iapp_deinit(struct iapp_data *iapp) -+{ -+} -+ -+#endif /* CONFIG_IAPP */ -+ -+#endif /* IAPP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.c -new file mode 100644 -index 0000000000000..1fd4dab16d6b3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.c -@@ -0,0 +1,1884 @@ -+/* -+ * hostapd / IEEE 802.11 Management -+ * Copyright (c) 2002-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "crypto/crypto.h" -+#include "drivers/driver.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "common/wpa_ctrl.h" -+#include "radius/radius.h" -+#include "radius/radius_client.h" -+#include "p2p/p2p.h" -+#include "wps/wps.h" -+#include "hostapd.h" -+#include "beacon.h" -+#include "ieee802_11_auth.h" -+#include "sta_info.h" -+#include "ieee802_1x.h" -+#include "wpa_auth.h" -+#include "wmm.h" -+#include "ap_list.h" -+#include "accounting.h" -+#include "ap_config.h" -+#include "ap_mlme.h" -+#include "p2p_hostapd.h" -+#include "ap_drv_ops.h" -+#include "ieee802_11.h" -+ -+ -+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) -+{ -+ u8 *pos = eid; -+ int i, num, count; -+ -+ if (hapd->iface->current_rates == NULL) -+ return eid; -+ -+ *pos++ = WLAN_EID_SUPP_RATES; -+ num = hapd->iface->num_rates; -+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) -+ num++; -+ if (num > 8) { -+ /* rest of the rates are encoded in Extended supported -+ * rates element */ -+ num = 8; -+ } -+ -+ *pos++ = num; -+ count = 0; -+ for (i = 0, count = 0; i < hapd->iface->num_rates && count < num; -+ i++) { -+ count++; -+ *pos = hapd->iface->current_rates[i].rate / 5; -+ if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) -+ *pos |= 0x80; -+ pos++; -+ } -+ -+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && -+ hapd->iface->num_rates < 8) -+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; -+ -+ return pos; -+} -+ -+ -+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) -+{ -+ u8 *pos = eid; -+ int i, num, count; -+ -+ if (hapd->iface->current_rates == NULL) -+ return eid; -+ -+ num = hapd->iface->num_rates; -+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) -+ num++; -+ if (num <= 8) -+ return eid; -+ num -= 8; -+ -+ *pos++ = WLAN_EID_EXT_SUPP_RATES; -+ *pos++ = num; -+ count = 0; -+ for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8; -+ i++) { -+ count++; -+ if (count <= 8) -+ continue; /* already in SuppRates IE */ -+ *pos = hapd->iface->current_rates[i].rate / 5; -+ if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) -+ *pos |= 0x80; -+ pos++; -+ } -+ -+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && -+ hapd->iface->num_rates >= 8) -+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; -+ -+ return pos; -+} -+ -+ -+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, -+ int probe) -+{ -+ int capab = WLAN_CAPABILITY_ESS; -+ int privacy; -+ -+ if (hapd->iface->num_sta_no_short_preamble == 0 && -+ hapd->iconf->preamble == SHORT_PREAMBLE) -+ capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; -+ -+ privacy = hapd->conf->ssid.wep.keys_set; -+ -+ if (hapd->conf->ieee802_1x && -+ (hapd->conf->default_wep_key_len || -+ hapd->conf->individual_wep_key_len)) -+ privacy = 1; -+ -+ if (hapd->conf->wpa) -+ privacy = 1; -+ -+ if (sta) { -+ int policy, def_klen; -+ if (probe && sta->ssid_probe) { -+ policy = sta->ssid_probe->security_policy; -+ def_klen = sta->ssid_probe->wep.default_len; -+ } else { -+ policy = sta->ssid->security_policy; -+ def_klen = sta->ssid->wep.default_len; -+ } -+ privacy = policy != SECURITY_PLAINTEXT; -+ if (policy == SECURITY_IEEE_802_1X && def_klen == 0) -+ privacy = 0; -+ } -+ -+ if (privacy) -+ capab |= WLAN_CAPABILITY_PRIVACY; -+ -+ if (hapd->iface->current_mode && -+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && -+ hapd->iface->num_sta_no_short_slot_time == 0) -+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; -+ -+ return capab; -+} -+ -+ -+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) -+{ -+ u8 *pos = eid; -+ -+ if ((hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) == -+ 0) -+ return eid; -+ -+ *pos++ = WLAN_EID_EXT_CAPAB; -+ *pos++ = 5; -+ *pos++ = 0x00; -+ *pos++ = 0x00; -+ *pos++ = 0x00; -+ *pos++ = 0x00; -+ *pos = 0x00; -+ if (hapd->conf->tdls & TDLS_PROHIBIT) -+ *pos |= 0x40; /* Bit 38 - TDLS Prohibited */ -+ if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) -+ *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */ -+ pos++; -+ -+ return pos; -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, -+ struct sta_info *sta, u8 *eid) -+{ -+ u8 *pos = eid; -+ u32 timeout, tu; -+ struct os_time now, passed; -+ -+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL; -+ *pos++ = 5; -+ *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; -+ os_get_time(&now); -+ os_time_sub(&now, &sta->sa_query_start, &passed); -+ tu = (passed.sec * 1000000 + passed.usec) / 1024; -+ if (hapd->conf->assoc_sa_query_max_timeout > tu) -+ timeout = hapd->conf->assoc_sa_query_max_timeout - tu; -+ else -+ timeout = 0; -+ if (timeout < hapd->conf->assoc_sa_query_max_timeout) -+ timeout++; /* add some extra time for local timers */ -+ WPA_PUT_LE32(pos, timeout); -+ pos += 4; -+ -+ return pos; -+} -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) -+{ -+ int i; -+ if (len > HOSTAPD_MAX_SSID_LEN) -+ len = HOSTAPD_MAX_SSID_LEN; -+ for (i = 0; i < len; i++) { -+ if (ssid[i] >= 32 && ssid[i] < 127) -+ buf[i] = ssid[i]; -+ else -+ buf[i] = '.'; -+ } -+ buf[len] = '\0'; -+} -+ -+ -+static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, -+ u16 auth_transaction, const u8 *challenge, -+ int iswep) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "authentication (shared key, transaction %d)", -+ auth_transaction); -+ -+ if (auth_transaction == 1) { -+ if (!sta->challenge) { -+ /* Generate a pseudo-random challenge */ -+ u8 key[8]; -+ struct os_time now; -+ int r; -+ sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN); -+ if (sta->challenge == NULL) -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ -+ os_get_time(&now); -+ r = os_random(); -+ os_memcpy(key, &now.sec, 4); -+ os_memcpy(key + 4, &r, 4); -+ rc4_skip(key, sizeof(key), 0, -+ sta->challenge, WLAN_AUTH_CHALLENGE_LEN); -+ } -+ return 0; -+ } -+ -+ if (auth_transaction != 3) -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ -+ /* Transaction 3 */ -+ if (!iswep || !sta->challenge || !challenge || -+ os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, -+ "shared key authentication - invalid " -+ "challenge-response"); -+ return WLAN_STATUS_CHALLENGE_FAIL; -+ } -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "authentication OK (shared key)"); -+#ifdef IEEE80211_REQUIRE_AUTH_ACK -+ /* Station will be marked authenticated if it ACKs the -+ * authentication reply. */ -+#else -+ sta->flags |= WLAN_STA_AUTH; -+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); -+#endif -+ os_free(sta->challenge); -+ sta->challenge = NULL; -+ -+ return 0; -+} -+ -+ -+static void send_auth_reply(struct hostapd_data *hapd, -+ const u8 *dst, const u8 *bssid, -+ u16 auth_alg, u16 auth_transaction, u16 resp, -+ const u8 *ies, size_t ies_len) -+{ -+ struct ieee80211_mgmt *reply; -+ u8 *buf; -+ size_t rlen; -+ -+ rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len; -+ buf = os_zalloc(rlen); -+ if (buf == NULL) -+ return; -+ -+ reply = (struct ieee80211_mgmt *) buf; -+ reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_AUTH); -+ os_memcpy(reply->da, dst, ETH_ALEN); -+ os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(reply->bssid, bssid, ETH_ALEN); -+ -+ reply->u.auth.auth_alg = host_to_le16(auth_alg); -+ reply->u.auth.auth_transaction = host_to_le16(auth_transaction); -+ reply->u.auth.status_code = host_to_le16(resp); -+ -+ if (ies && ies_len) -+ os_memcpy(reply->u.auth.variable, ies, ies_len); -+ -+ wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR -+ " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)", -+ MAC2STR(dst), auth_alg, auth_transaction, -+ resp, (unsigned long) ies_len); -+ if (hostapd_drv_send_mlme(hapd, reply, rlen) < 0) -+ perror("send_auth_reply: send"); -+ -+ os_free(buf); -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, -+ u16 auth_transaction, u16 status, -+ const u8 *ies, size_t ies_len) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta; -+ -+ send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction, -+ status, ies, ies_len); -+ -+ if (status != WLAN_STATUS_SUCCESS) -+ return; -+ -+ sta = ap_get_sta(hapd, dst); -+ if (sta == NULL) -+ return; -+ -+ hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); -+ sta->flags |= WLAN_STA_AUTH; -+ mlme_authenticate_indication(hapd, sta); -+} -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+static void handle_auth(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len) -+{ -+ u16 auth_alg, auth_transaction, status_code; -+ u16 resp = WLAN_STATUS_SUCCESS; -+ struct sta_info *sta = NULL; -+ int res; -+ u16 fc; -+ const u8 *challenge = NULL; -+ u32 session_timeout, acct_interim_interval; -+ int vlan_id = 0; -+ u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; -+ size_t resp_ies_len = 0; -+ -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { -+ printf("handle_auth - too short payload (len=%lu)\n", -+ (unsigned long) len); -+ return; -+ } -+ -+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg); -+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); -+ status_code = le_to_host16(mgmt->u.auth.status_code); -+ fc = le_to_host16(mgmt->frame_control); -+ -+ if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) + -+ 2 + WLAN_AUTH_CHALLENGE_LEN && -+ mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE && -+ mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN) -+ challenge = &mgmt->u.auth.variable[2]; -+ -+ wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d " -+ "auth_transaction=%d status_code=%d wep=%d%s", -+ MAC2STR(mgmt->sa), auth_alg, auth_transaction, -+ status_code, !!(fc & WLAN_FC_ISWEP), -+ challenge ? " challenge" : ""); -+ -+ if (hapd->tkip_countermeasures) { -+ resp = WLAN_REASON_MICHAEL_MIC_FAILURE; -+ goto fail; -+ } -+ -+ if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && -+ auth_alg == WLAN_AUTH_OPEN) || -+#ifdef CONFIG_IEEE80211R -+ (hapd->conf->wpa && -+ (hapd->conf->wpa_key_mgmt & -+ (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) && -+ auth_alg == WLAN_AUTH_FT) || -+#endif /* CONFIG_IEEE80211R */ -+ ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && -+ auth_alg == WLAN_AUTH_SHARED_KEY))) { -+ printf("Unsupported authentication algorithm (%d)\n", -+ auth_alg); -+ resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; -+ goto fail; -+ } -+ -+ if (!(auth_transaction == 1 || -+ (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { -+ printf("Unknown authentication transaction number (%d)\n", -+ auth_transaction); -+ resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; -+ goto fail; -+ } -+ -+ if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { -+ printf("Station " MACSTR " not allowed to authenticate.\n", -+ MAC2STR(mgmt->sa)); -+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE; -+ goto fail; -+ } -+ -+ res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, -+ &session_timeout, -+ &acct_interim_interval, &vlan_id); -+ if (res == HOSTAPD_ACL_REJECT) { -+ printf("Station " MACSTR " not allowed to authenticate.\n", -+ MAC2STR(mgmt->sa)); -+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE; -+ goto fail; -+ } -+ if (res == HOSTAPD_ACL_PENDING) { -+ wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR -+ " waiting for an external authentication", -+ MAC2STR(mgmt->sa)); -+ /* Authentication code will re-send the authentication frame -+ * after it has received (and cached) information from the -+ * external source. */ -+ return; -+ } -+ -+ sta = ap_sta_add(hapd, mgmt->sa); -+ if (!sta) { -+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE; -+ goto fail; -+ } -+ -+ if (vlan_id > 0) { -+ if (hostapd_get_vlan_id_ifname(hapd->conf->vlan, -+ vlan_id) == NULL) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, "Invalid VLAN ID " -+ "%d received from RADIUS server", -+ vlan_id); -+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE; -+ goto fail; -+ } -+ sta->vlan_id = vlan_id; -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); -+ } -+ -+ sta->flags &= ~WLAN_STA_PREAUTH; -+ ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); -+ -+ if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval) -+ sta->acct_interim_interval = acct_interim_interval; -+ if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) -+ ap_sta_session_timeout(hapd, sta, session_timeout); -+ else -+ ap_sta_no_session_timeout(hapd, sta); -+ -+ switch (auth_alg) { -+ case WLAN_AUTH_OPEN: -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "authentication OK (open system)"); -+#ifdef IEEE80211_REQUIRE_AUTH_ACK -+ /* Station will be marked authenticated if it ACKs the -+ * authentication reply. */ -+#else -+ sta->flags |= WLAN_STA_AUTH; -+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); -+ sta->auth_alg = WLAN_AUTH_OPEN; -+ mlme_authenticate_indication(hapd, sta); -+#endif -+ break; -+ case WLAN_AUTH_SHARED_KEY: -+ resp = auth_shared_key(hapd, sta, auth_transaction, challenge, -+ fc & WLAN_FC_ISWEP); -+ sta->auth_alg = WLAN_AUTH_SHARED_KEY; -+ mlme_authenticate_indication(hapd, sta); -+ if (sta->challenge && auth_transaction == 1) { -+ resp_ies[0] = WLAN_EID_CHALLENGE; -+ resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN; -+ os_memcpy(resp_ies + 2, sta->challenge, -+ WLAN_AUTH_CHALLENGE_LEN); -+ resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN; -+ } -+ break; -+#ifdef CONFIG_IEEE80211R -+ case WLAN_AUTH_FT: -+ sta->auth_alg = WLAN_AUTH_FT; -+ if (sta->wpa_sm == NULL) -+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, -+ sta->addr); -+ if (sta->wpa_sm == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " -+ "state machine"); -+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE; -+ goto fail; -+ } -+ wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid, -+ auth_transaction, mgmt->u.auth.variable, -+ len - IEEE80211_HDRLEN - -+ sizeof(mgmt->u.auth), -+ handle_auth_ft_finish, hapd); -+ /* handle_auth_ft_finish() callback will complete auth. */ -+ return; -+#endif /* CONFIG_IEEE80211R */ -+ } -+ -+ fail: -+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, -+ auth_transaction + 1, resp, resp_ies, resp_ies_len); -+} -+ -+ -+static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ int i, j = 32, aid; -+ -+ /* get a unique AID */ -+ if (sta->aid > 0) { -+ wpa_printf(MSG_DEBUG, " old AID %d", sta->aid); -+ return 0; -+ } -+ -+ for (i = 0; i < AID_WORDS; i++) { -+ if (hapd->sta_aid[i] == (u32) -1) -+ continue; -+ for (j = 0; j < 32; j++) { -+ if (!(hapd->sta_aid[i] & BIT(j))) -+ break; -+ } -+ if (j < 32) -+ break; -+ } -+ if (j == 32) -+ return -1; -+ aid = i * 32 + j + 1; -+ if (aid > 2007) -+ return -1; -+ -+ sta->aid = aid; -+ hapd->sta_aid[i] |= BIT(j); -+ wpa_printf(MSG_DEBUG, " new AID %d", sta->aid); -+ return 0; -+} -+ -+ -+static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *ssid_ie, size_t ssid_ie_len) -+{ -+ if (ssid_ie == NULL) -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ -+ if (ssid_ie_len != hapd->conf->ssid.ssid_len || -+ os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) { -+ char ssid_txt[33]; -+ ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, -+ "Station tried to associate with unknown SSID " -+ "'%s'", ssid_txt); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ return WLAN_STATUS_SUCCESS; -+} -+ -+ -+static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *wmm_ie, size_t wmm_ie_len) -+{ -+ sta->flags &= ~WLAN_STA_WMM; -+ if (wmm_ie && hapd->conf->wmm_enabled) { -+ if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_WPA, -+ HOSTAPD_LEVEL_DEBUG, -+ "invalid WMM element in association " -+ "request"); -+ else -+ sta->flags |= WLAN_STA_WMM; -+ } -+ return WLAN_STATUS_SUCCESS; -+} -+ -+ -+static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, -+ struct ieee802_11_elems *elems) -+{ -+ if (!elems->supp_rates) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "No supported rates element in AssocReq"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ if (elems->supp_rates_len > sizeof(sta->supported_rates)) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "Invalid supported rates element length %d", -+ elems->supp_rates_len); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); -+ os_memcpy(sta->supported_rates, elems->supp_rates, -+ elems->supp_rates_len); -+ sta->supported_rates_len = elems->supp_rates_len; -+ -+ if (elems->ext_supp_rates) { -+ if (elems->supp_rates_len + elems->ext_supp_rates_len > -+ sizeof(sta->supported_rates)) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "Invalid supported rates element length" -+ " %d+%d", elems->supp_rates_len, -+ elems->ext_supp_rates_len); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ os_memcpy(sta->supported_rates + elems->supp_rates_len, -+ elems->ext_supp_rates, elems->ext_supp_rates_len); -+ sta->supported_rates_len += elems->ext_supp_rates_len; -+ } -+ -+ return WLAN_STATUS_SUCCESS; -+} -+ -+ -+static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *ies, size_t ies_len, int reassoc) -+{ -+ struct ieee802_11_elems elems; -+ u16 resp; -+ const u8 *wpa_ie; -+ size_t wpa_ie_len; -+ -+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "Station sent an invalid " -+ "association request"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len); -+ if (resp != WLAN_STATUS_SUCCESS) -+ return resp; -+ resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len); -+ if (resp != WLAN_STATUS_SUCCESS) -+ return resp; -+ resp = copy_supp_rates(hapd, sta, &elems); -+ if (resp != WLAN_STATUS_SUCCESS) -+ return resp; -+#ifdef CONFIG_IEEE80211N -+ resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities, -+ elems.ht_capabilities_len); -+ if (resp != WLAN_STATUS_SUCCESS) -+ return resp; -+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && -+ !(sta->flags & WLAN_STA_HT)) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "Station does not support " -+ "mandatory HT PHY - reject association"); -+ return WLAN_STATUS_ASSOC_DENIED_NO_HT; -+ } -+#endif /* CONFIG_IEEE80211N */ -+ -+ if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) { -+ wpa_ie = elems.rsn_ie; -+ wpa_ie_len = elems.rsn_ie_len; -+ } else if ((hapd->conf->wpa & WPA_PROTO_WPA) && -+ elems.wpa_ie) { -+ wpa_ie = elems.wpa_ie; -+ wpa_ie_len = elems.wpa_ie_len; -+ } else { -+ wpa_ie = NULL; -+ wpa_ie_len = 0; -+ } -+ -+#ifdef CONFIG_WPS -+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); -+ if (hapd->conf->wps_state && elems.wps_ie) { -+ wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " -+ "Request - assume WPS is used"); -+ sta->flags |= WLAN_STA_WPS; -+ wpabuf_free(sta->wps_ie); -+ sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, -+ WPS_IE_VENDOR_TYPE); -+ wpa_ie = NULL; -+ wpa_ie_len = 0; -+ if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) { -+ wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in " -+ "(Re)Association Request - reject"); -+ return WLAN_STATUS_INVALID_IE; -+ } -+ } else if (hapd->conf->wps_state && wpa_ie == NULL) { -+ wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in " -+ "(Re)Association Request - possible WPS use"); -+ sta->flags |= WLAN_STA_MAYBE_WPS; -+ } else -+#endif /* CONFIG_WPS */ -+ if (hapd->conf->wpa && wpa_ie == NULL) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, -+ "No WPA/RSN IE in association request"); -+ return WLAN_STATUS_INVALID_IE; -+ } -+ -+ if (hapd->conf->wpa && wpa_ie) { -+ int res; -+ wpa_ie -= 2; -+ wpa_ie_len += 2; -+ if (sta->wpa_sm == NULL) -+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, -+ sta->addr); -+ if (sta->wpa_sm == NULL) { -+ wpa_printf(MSG_WARNING, "Failed to initialize WPA " -+ "state machine"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, -+ wpa_ie, wpa_ie_len, -+ elems.mdie, elems.mdie_len); -+ if (res == WPA_INVALID_GROUP) -+ resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; -+ else if (res == WPA_INVALID_PAIRWISE) -+ resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; -+ else if (res == WPA_INVALID_AKMP) -+ resp = WLAN_STATUS_AKMP_NOT_VALID; -+ else if (res == WPA_ALLOC_FAIL) -+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE; -+#ifdef CONFIG_IEEE80211W -+ else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) -+ resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; -+ else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) -+ resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; -+#endif /* CONFIG_IEEE80211W */ -+ else if (res == WPA_INVALID_MDIE) -+ resp = WLAN_STATUS_INVALID_MDIE; -+ else if (res != WPA_IE_OK) -+ resp = WLAN_STATUS_INVALID_IE; -+ if (resp != WLAN_STATUS_SUCCESS) -+ return resp; -+#ifdef CONFIG_IEEE80211W -+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && -+ sta->sa_query_count > 0) -+ ap_check_sa_query_timeout(hapd, sta); -+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && -+ (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) { -+ /* -+ * STA has already been associated with MFP and SA -+ * Query timeout has not been reached. Reject the -+ * association attempt temporarily and start SA Query, -+ * if one is not pending. -+ */ -+ -+ if (sta->sa_query_count == 0) -+ ap_sta_start_sa_query(hapd, sta); -+ -+ return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; -+ } -+ -+ if (wpa_auth_uses_mfp(sta->wpa_sm)) -+ sta->flags |= WLAN_STA_MFP; -+ else -+ sta->flags &= ~WLAN_STA_MFP; -+#endif /* CONFIG_IEEE80211W */ -+ -+#ifdef CONFIG_IEEE80211R -+ if (sta->auth_alg == WLAN_AUTH_FT) { -+ if (!reassoc) { -+ wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried " -+ "to use association (not " -+ "re-association) with FT auth_alg", -+ MAC2STR(sta->addr)); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies, -+ ies_len); -+ if (resp != WLAN_STATUS_SUCCESS) -+ return resp; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+#ifdef CONFIG_IEEE80211N -+ if ((sta->flags & WLAN_STA_HT) && -+ wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, -+ "Station tried to use TKIP with HT " -+ "association"); -+ return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; -+ } -+#endif /* CONFIG_IEEE80211N */ -+ } else -+ wpa_auth_sta_no_wpa(sta->wpa_sm); -+ -+#ifdef CONFIG_P2P -+ if (elems.p2p) { -+ wpabuf_free(sta->p2p_ie); -+ sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, -+ P2P_IE_VENDOR_TYPE); -+ -+ } else { -+ wpabuf_free(sta->p2p_ie); -+ sta->p2p_ie = NULL; -+ } -+ -+ p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len); -+#endif /* CONFIG_P2P */ -+ -+ return WLAN_STATUS_SUCCESS; -+} -+ -+ -+static void send_deauth(struct hostapd_data *hapd, const u8 *addr, -+ u16 reason_code) -+{ -+ int send_len; -+ struct ieee80211_mgmt reply; -+ -+ os_memset(&reply, 0, sizeof(reply)); -+ reply.frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); -+ os_memcpy(reply.da, addr, ETH_ALEN); -+ os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN); -+ -+ send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); -+ reply.u.deauth.reason_code = host_to_le16(reason_code); -+ -+ if (hostapd_drv_send_mlme(hapd, &reply, send_len) < 0) -+ wpa_printf(MSG_INFO, "Failed to send deauth: %s", -+ strerror(errno)); -+} -+ -+ -+static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, -+ u16 status_code, int reassoc, const u8 *ies, -+ size_t ies_len) -+{ -+ int send_len; -+ u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; -+ struct ieee80211_mgmt *reply; -+ u8 *p; -+ -+ os_memset(buf, 0, sizeof(buf)); -+ reply = (struct ieee80211_mgmt *) buf; -+ reply->frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : -+ WLAN_FC_STYPE_ASSOC_RESP)); -+ os_memcpy(reply->da, sta->addr, ETH_ALEN); -+ os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN); -+ -+ send_len = IEEE80211_HDRLEN; -+ send_len += sizeof(reply->u.assoc_resp); -+ reply->u.assoc_resp.capab_info = -+ host_to_le16(hostapd_own_capab_info(hapd, sta, 0)); -+ reply->u.assoc_resp.status_code = host_to_le16(status_code); -+ reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) -+ | BIT(14) | BIT(15)); -+ /* Supported rates */ -+ p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable); -+ /* Extended supported rates */ -+ p = hostapd_eid_ext_supp_rates(hapd, p); -+ -+#ifdef CONFIG_IEEE80211R -+ if (status_code == WLAN_STATUS_SUCCESS) { -+ /* IEEE 802.11r: Mobility Domain Information, Fast BSS -+ * Transition Information, RSN, [RIC Response] */ -+ p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, -+ buf + sizeof(buf) - p, -+ sta->auth_alg, ies, ies_len); -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+#ifdef CONFIG_IEEE80211W -+ if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) -+ p = hostapd_eid_assoc_comeback_time(hapd, sta, p); -+#endif /* CONFIG_IEEE80211W */ -+ -+#ifdef CONFIG_IEEE80211N -+ p = hostapd_eid_ht_capabilities(hapd, p); -+ p = hostapd_eid_ht_operation(hapd, p); -+#endif /* CONFIG_IEEE80211N */ -+ -+ p = hostapd_eid_ext_capab(hapd, p); -+ -+ if (sta->flags & WLAN_STA_WMM) -+ p = hostapd_eid_wmm(hapd, p); -+ -+#ifdef CONFIG_WPS -+ if (sta->flags & WLAN_STA_WPS) { -+ struct wpabuf *wps = wps_build_assoc_resp_ie(); -+ if (wps) { -+ os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); -+ p += wpabuf_len(wps); -+ wpabuf_free(wps); -+ } -+ } -+#endif /* CONFIG_WPS */ -+ -+#ifdef CONFIG_P2P -+ if (sta->p2p_ie) { -+ struct wpabuf *p2p_resp_ie; -+ enum p2p_status_code status; -+ switch (status_code) { -+ case WLAN_STATUS_SUCCESS: -+ status = P2P_SC_SUCCESS; -+ break; -+ case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA: -+ status = P2P_SC_FAIL_LIMIT_REACHED; -+ break; -+ default: -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ break; -+ } -+ p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status); -+ if (p2p_resp_ie) { -+ os_memcpy(p, wpabuf_head(p2p_resp_ie), -+ wpabuf_len(p2p_resp_ie)); -+ p += wpabuf_len(p2p_resp_ie); -+ wpabuf_free(p2p_resp_ie); -+ } -+ } -+#endif /* CONFIG_P2P */ -+ -+#ifdef CONFIG_P2P_MANAGER -+ if (hapd->conf->p2p & P2P_MANAGE) -+ p = hostapd_eid_p2p_manage(hapd, p); -+#endif /* CONFIG_P2P_MANAGER */ -+ -+ send_len += p - reply->u.assoc_resp.variable; -+ -+ if (hostapd_drv_send_mlme(hapd, reply, send_len) < 0) -+ wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", -+ strerror(errno)); -+} -+ -+ -+static void handle_assoc(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len, -+ int reassoc) -+{ -+ u16 capab_info, listen_interval; -+ u16 resp = WLAN_STATUS_SUCCESS; -+ const u8 *pos; -+ int left, i; -+ struct sta_info *sta; -+ -+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : -+ sizeof(mgmt->u.assoc_req))) { -+ printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)" -+ "\n", reassoc, (unsigned long) len); -+ return; -+ } -+ -+ if (reassoc) { -+ capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info); -+ listen_interval = le_to_host16( -+ mgmt->u.reassoc_req.listen_interval); -+ wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR -+ " capab_info=0x%02x listen_interval=%d current_ap=" -+ MACSTR, -+ MAC2STR(mgmt->sa), capab_info, listen_interval, -+ MAC2STR(mgmt->u.reassoc_req.current_ap)); -+ left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); -+ pos = mgmt->u.reassoc_req.variable; -+ } else { -+ capab_info = le_to_host16(mgmt->u.assoc_req.capab_info); -+ listen_interval = le_to_host16( -+ mgmt->u.assoc_req.listen_interval); -+ wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR -+ " capab_info=0x%02x listen_interval=%d", -+ MAC2STR(mgmt->sa), capab_info, listen_interval); -+ left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); -+ pos = mgmt->u.assoc_req.variable; -+ } -+ -+ sta = ap_get_sta(hapd, mgmt->sa); -+#ifdef CONFIG_IEEE80211R -+ if (sta && sta->auth_alg == WLAN_AUTH_FT && -+ (sta->flags & WLAN_STA_AUTH) == 0) { -+ wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate " -+ "prior to authentication since it is using " -+ "over-the-DS FT", MAC2STR(mgmt->sa)); -+ } else -+#endif /* CONFIG_IEEE80211R */ -+ if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "Station tried to " -+ "associate before authentication " -+ "(aid=%d flags=0x%x)", -+ sta ? sta->aid : -1, -+ sta ? sta->flags : 0); -+ send_deauth(hapd, mgmt->sa, -+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); -+ return; -+ } -+ -+ if (hapd->tkip_countermeasures) { -+ resp = WLAN_REASON_MICHAEL_MIC_FAILURE; -+ goto fail; -+ } -+ -+ if (listen_interval > hapd->conf->max_listen_interval) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "Too large Listen Interval (%d)", -+ listen_interval); -+ resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE; -+ goto fail; -+ } -+ -+ /* followed by SSID and Supported rates; and HT capabilities if 802.11n -+ * is used */ -+ resp = check_assoc_ies(hapd, sta, pos, left, reassoc); -+ if (resp != WLAN_STATUS_SUCCESS) -+ goto fail; -+ -+ if (hostapd_get_aid(hapd, sta) < 0) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "No room for more AIDs"); -+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; -+ goto fail; -+ } -+ -+ sta->capability = capab_info; -+ sta->listen_interval = listen_interval; -+ -+ if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) -+ sta->flags |= WLAN_STA_NONERP; -+ for (i = 0; i < sta->supported_rates_len; i++) { -+ if ((sta->supported_rates[i] & 0x7f) > 22) { -+ sta->flags &= ~WLAN_STA_NONERP; -+ break; -+ } -+ } -+ if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) { -+ sta->nonerp_set = 1; -+ hapd->iface->num_sta_non_erp++; -+ if (hapd->iface->num_sta_non_erp == 1) -+ ieee802_11_set_beacons(hapd->iface); -+ } -+ -+ if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) && -+ !sta->no_short_slot_time_set) { -+ sta->no_short_slot_time_set = 1; -+ hapd->iface->num_sta_no_short_slot_time++; -+ if (hapd->iface->current_mode->mode == -+ HOSTAPD_MODE_IEEE80211G && -+ hapd->iface->num_sta_no_short_slot_time == 1) -+ ieee802_11_set_beacons(hapd->iface); -+ } -+ -+ if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) -+ sta->flags |= WLAN_STA_SHORT_PREAMBLE; -+ else -+ sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; -+ -+ if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && -+ !sta->no_short_preamble_set) { -+ sta->no_short_preamble_set = 1; -+ hapd->iface->num_sta_no_short_preamble++; -+ if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G -+ && hapd->iface->num_sta_no_short_preamble == 1) -+ ieee802_11_set_beacons(hapd->iface); -+ } -+ -+#ifdef CONFIG_IEEE80211N -+ update_ht_state(hapd, sta); -+#endif /* CONFIG_IEEE80211N */ -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "association OK (aid %d)", sta->aid); -+ /* Station will be marked associated, after it acknowledges AssocResp -+ */ -+ sta->flags |= WLAN_STA_ASSOC_REQ_OK; -+ -+#ifdef CONFIG_IEEE80211W -+ if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) { -+ wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out " -+ "SA Query procedure", reassoc ? "re" : ""); -+ /* TODO: Send a protected Disassociate frame to the STA using -+ * the old key and Reason Code "Previous Authentication no -+ * longer valid". Make sure this is only sent protected since -+ * unprotected frame would be received by the STA that is now -+ * trying to associate. -+ */ -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ if (reassoc) { -+ os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap, -+ ETH_ALEN); -+ } -+ -+ if (sta->last_assoc_req) -+ os_free(sta->last_assoc_req); -+ sta->last_assoc_req = os_malloc(len); -+ if (sta->last_assoc_req) -+ os_memcpy(sta->last_assoc_req, mgmt, len); -+ -+ /* Make sure that the previously registered inactivity timer will not -+ * remove the STA immediately. */ -+ sta->timeout_next = STA_NULLFUNC; -+ -+ fail: -+ send_assoc_resp(hapd, sta, resp, reassoc, pos, left); -+} -+ -+ -+static void handle_disassoc(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len) -+{ -+ struct sta_info *sta; -+ -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { -+ printf("handle_disassoc - too short payload (len=%lu)\n", -+ (unsigned long) len); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", -+ MAC2STR(mgmt->sa), -+ le_to_host16(mgmt->u.disassoc.reason_code)); -+ -+ sta = ap_get_sta(hapd, mgmt->sa); -+ if (sta == NULL) { -+ printf("Station " MACSTR " trying to disassociate, but it " -+ "is not associated.\n", MAC2STR(mgmt->sa)); -+ return; -+ } -+ -+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); -+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, -+ MAC2STR(sta->addr)); -+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "disassociated"); -+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); -+ /* Stop Accounting and IEEE 802.1X sessions, but leave the STA -+ * authenticated. */ -+ accounting_sta_stop(hapd, sta); -+ ieee802_1x_free_station(sta); -+ hostapd_drv_sta_remove(hapd, sta->addr); -+ -+ if (sta->timeout_next == STA_NULLFUNC || -+ sta->timeout_next == STA_DISASSOC) { -+ sta->timeout_next = STA_DEAUTH; -+ eloop_cancel_timeout(ap_handle_timer, hapd, sta); -+ eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, -+ hapd, sta); -+ } -+ -+ mlme_disassociate_indication( -+ hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code)); -+} -+ -+ -+static void handle_deauth(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len) -+{ -+ struct sta_info *sta; -+ -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { -+ wpa_msg(hapd, MSG_DEBUG, "handle_deauth - too short payload " -+ "(len=%lu)", (unsigned long) len); -+ return; -+ } -+ -+ wpa_msg(hapd, MSG_DEBUG, "deauthentication: STA=" MACSTR -+ " reason_code=%d", -+ MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); -+ -+ sta = ap_get_sta(hapd, mgmt->sa); -+ if (sta == NULL) { -+ wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " trying to " -+ "deauthenticate, but it is not authenticated", -+ MAC2STR(mgmt->sa)); -+ return; -+ } -+ -+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | -+ WLAN_STA_ASSOC_REQ_OK); -+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, -+ MAC2STR(sta->addr)); -+ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "deauthenticated"); -+ mlme_deauthenticate_indication( -+ hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); -+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); -+ ap_free_sta(hapd, sta); -+} -+ -+ -+static void handle_beacon(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len, -+ struct hostapd_frame_info *fi) -+{ -+ struct ieee802_11_elems elems; -+ -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) { -+ printf("handle_beacon - too short payload (len=%lu)\n", -+ (unsigned long) len); -+ return; -+ } -+ -+ (void) ieee802_11_parse_elems(mgmt->u.beacon.variable, -+ len - (IEEE80211_HDRLEN + -+ sizeof(mgmt->u.beacon)), &elems, -+ 0); -+ -+ ap_list_process_beacon(hapd->iface, mgmt, &elems, fi); -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+ -+/* MLME-SAQuery.request */ -+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, -+ const u8 *addr, const u8 *trans_id) -+{ -+ struct ieee80211_mgmt mgmt; -+ u8 *end; -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " -+ MACSTR, MAC2STR(addr)); -+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", -+ trans_id, WLAN_SA_QUERY_TR_ID_LEN); -+ -+ os_memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_ACTION); -+ os_memcpy(mgmt.da, addr, ETH_ALEN); -+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); -+ mgmt.u.action.category = WLAN_ACTION_SA_QUERY; -+ mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; -+ os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, -+ WLAN_SA_QUERY_TR_ID_LEN); -+ end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; -+ if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt) < 0) -+ perror("ieee802_11_send_sa_query_req: send"); -+} -+ -+ -+static void hostapd_sa_query_request(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt) -+{ -+ struct sta_info *sta; -+ struct ieee80211_mgmt resp; -+ u8 *end; -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " -+ MACSTR, MAC2STR(mgmt->sa)); -+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", -+ mgmt->u.action.u.sa_query_resp.trans_id, -+ WLAN_SA_QUERY_TR_ID_LEN); -+ -+ sta = ap_get_sta(hapd, mgmt->sa); -+ if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " -+ "from unassociated STA " MACSTR, MAC2STR(mgmt->sa)); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " -+ MACSTR, MAC2STR(mgmt->sa)); -+ -+ os_memset(&resp, 0, sizeof(resp)); -+ resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_ACTION); -+ os_memcpy(resp.da, mgmt->sa, ETH_ALEN); -+ os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); -+ resp.u.action.category = WLAN_ACTION_SA_QUERY; -+ resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; -+ os_memcpy(resp.u.action.u.sa_query_req.trans_id, -+ mgmt->u.action.u.sa_query_req.trans_id, -+ WLAN_SA_QUERY_TR_ID_LEN); -+ end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; -+ if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp) < 0) -+ perror("hostapd_sa_query_request: send"); -+} -+ -+ -+static void hostapd_sa_query_action(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, -+ size_t len) -+{ -+ struct sta_info *sta; -+ const u8 *end; -+ int i; -+ -+ end = mgmt->u.action.u.sa_query_resp.trans_id + -+ WLAN_SA_QUERY_TR_ID_LEN; -+ if (((u8 *) mgmt) + len < end) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action " -+ "frame (len=%lu)", (unsigned long) len); -+ return; -+ } -+ -+ if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) { -+ hostapd_sa_query_request(hapd, mgmt); -+ return; -+ } -+ -+ if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " -+ "Action %d", mgmt->u.action.u.sa_query_resp.action); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " -+ MACSTR, MAC2STR(mgmt->sa)); -+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", -+ mgmt->u.action.u.sa_query_resp.trans_id, -+ WLAN_SA_QUERY_TR_ID_LEN); -+ -+ /* MLME-SAQuery.confirm */ -+ -+ sta = ap_get_sta(hapd, mgmt->sa); -+ if (sta == NULL || sta->sa_query_trans_id == NULL) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " -+ "pending SA Query request found"); -+ return; -+ } -+ -+ for (i = 0; i < sta->sa_query_count; i++) { -+ if (os_memcmp(sta->sa_query_trans_id + -+ i * WLAN_SA_QUERY_TR_ID_LEN, -+ mgmt->u.action.u.sa_query_resp.trans_id, -+ WLAN_SA_QUERY_TR_ID_LEN) == 0) -+ break; -+ } -+ -+ if (i >= sta->sa_query_count) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " -+ "transaction identifier found"); -+ return; -+ } -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "Reply to pending SA Query received"); -+ ap_sta_stop_sa_query(hapd, sta); -+} -+ -+ -+static int robust_action_frame(u8 category) -+{ -+ return category != WLAN_ACTION_PUBLIC && -+ category != WLAN_ACTION_HT; -+} -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+static void handle_action(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len) -+{ -+#ifdef CONFIG_IEEE80211W -+ struct sta_info *sta; -+#endif -+ -+ if (len < IEEE80211_HDRLEN + 1) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "handle_action - too short payload (len=%lu)", -+ (unsigned long) len); -+ return; -+ } -+ -+#ifdef CONFIG_IEEE80211W -+ sta = ap_get_sta(hapd, mgmt->sa); -+ if (sta && (sta->flags & WLAN_STA_MFP) && -+ !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) && -+ robust_action_frame(mgmt->u.action.category))) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "Dropped unprotected Robust Action frame from " -+ "an MFP STA"); -+ return; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ switch (mgmt->u.action.category) { -+#ifdef CONFIG_IEEE80211R -+ case WLAN_ACTION_FT: -+ { -+ if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action " -+ "frame from unassociated STA " MACSTR, -+ MAC2STR(mgmt->sa)); -+ return; -+ } -+ -+ if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, -+ len - IEEE80211_HDRLEN)) -+ break; -+ -+ return; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ case WLAN_ACTION_WMM: -+ hostapd_wmm_action(hapd, mgmt, len); -+ return; -+#ifdef CONFIG_IEEE80211W -+ case WLAN_ACTION_SA_QUERY: -+ hostapd_sa_query_action(hapd, mgmt, len); -+ return; -+#endif /* CONFIG_IEEE80211W */ -+ case WLAN_ACTION_PUBLIC: -+ if (hapd->public_action_cb) { -+ hapd->public_action_cb(hapd->public_action_cb_ctx, -+ (u8 *) mgmt, len, -+ hapd->iface->freq); -+ return; -+ } -+ break; -+ case WLAN_ACTION_VENDOR_SPECIFIC: -+ if (hapd->vendor_action_cb) { -+ if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, -+ (u8 *) mgmt, len, -+ hapd->iface->freq) == 0) -+ return; -+ } -+ break; -+ } -+ -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "handle_action - unknown action category %d or invalid " -+ "frame", -+ mgmt->u.action.category); -+ if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) && -+ !(mgmt->sa[0] & 0x01)) { -+ struct ieee80211_mgmt *resp; -+ -+ /* -+ * IEEE 802.11-REVma/D9.0 - 7.3.1.11 -+ * Return the Action frame to the source without change -+ * except that MSB of the Category set to 1. -+ */ -+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action " -+ "frame back to sender"); -+ resp = os_malloc(len); -+ if (resp == NULL) -+ return; -+ os_memcpy(resp, mgmt, len); -+ os_memcpy(resp->da, resp->sa, ETH_ALEN); -+ os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); -+ resp->u.action.category |= 0x80; -+ -+ hostapd_drv_send_mlme(hapd, resp, len); -+ os_free(resp); -+ } -+} -+ -+ -+/** -+ * ieee802_11_mgmt - process incoming IEEE 802.11 management frames -+ * @hapd: hostapd BSS data structure (the BSS to which the management frame was -+ * sent to) -+ * @buf: management frame data (starting from IEEE 802.11 header) -+ * @len: length of frame data in octets -+ * @fi: meta data about received frame (signal level, etc.) -+ * -+ * Process all incoming IEEE 802.11 management frames. This will be called for -+ * each frame received from the kernel driver through wlan#ap interface. In -+ * addition, it can be called to re-inserted pending frames (e.g., when using -+ * external RADIUS server as an MAC ACL). -+ */ -+void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, -+ struct hostapd_frame_info *fi) -+{ -+ struct ieee80211_mgmt *mgmt; -+ int broadcast; -+ u16 fc, stype; -+ -+ if (len < 24) -+ return; -+ -+ mgmt = (struct ieee80211_mgmt *) buf; -+ fc = le_to_host16(mgmt->frame_control); -+ stype = WLAN_FC_GET_STYPE(fc); -+ -+ if (stype == WLAN_FC_STYPE_BEACON) { -+ handle_beacon(hapd, mgmt, len, fi); -+ return; -+ } -+ -+ broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff && -+ mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff && -+ mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff; -+ -+ if (!broadcast && -+ os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { -+ printf("MGMT: BSSID=" MACSTR " not our address\n", -+ MAC2STR(mgmt->bssid)); -+ return; -+ } -+ -+ -+ if (stype == WLAN_FC_STYPE_PROBE_REQ) { -+ handle_probe_req(hapd, mgmt, len); -+ return; -+ } -+ -+ if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "MGMT: DA=" MACSTR " not our address", -+ MAC2STR(mgmt->da)); -+ return; -+ } -+ -+ switch (stype) { -+ case WLAN_FC_STYPE_AUTH: -+ wpa_printf(MSG_DEBUG, "mgmt::auth"); -+ handle_auth(hapd, mgmt, len); -+ break; -+ case WLAN_FC_STYPE_ASSOC_REQ: -+ wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); -+ handle_assoc(hapd, mgmt, len, 0); -+ break; -+ case WLAN_FC_STYPE_REASSOC_REQ: -+ wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); -+ handle_assoc(hapd, mgmt, len, 1); -+ break; -+ case WLAN_FC_STYPE_DISASSOC: -+ wpa_printf(MSG_DEBUG, "mgmt::disassoc"); -+ handle_disassoc(hapd, mgmt, len); -+ break; -+ case WLAN_FC_STYPE_DEAUTH: -+ wpa_msg(hapd, MSG_DEBUG, "mgmt::deauth"); -+ handle_deauth(hapd, mgmt, len); -+ break; -+ case WLAN_FC_STYPE_ACTION: -+ wpa_printf(MSG_DEBUG, "mgmt::action"); -+ handle_action(hapd, mgmt, len); -+ break; -+ default: -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "unknown mgmt frame subtype %d", stype); -+ break; -+ } -+} -+ -+ -+static void handle_auth_cb(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, -+ size_t len, int ok) -+{ -+ u16 auth_alg, auth_transaction, status_code; -+ struct sta_info *sta; -+ -+ if (!ok) { -+ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_NOTICE, -+ "did not acknowledge authentication response"); -+ return; -+ } -+ -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { -+ printf("handle_auth_cb - too short payload (len=%lu)\n", -+ (unsigned long) len); -+ return; -+ } -+ -+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg); -+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); -+ status_code = le_to_host16(mgmt->u.auth.status_code); -+ -+ sta = ap_get_sta(hapd, mgmt->da); -+ if (!sta) { -+ printf("handle_auth_cb: STA " MACSTR " not found\n", -+ MAC2STR(mgmt->da)); -+ return; -+ } -+ -+ if (status_code == WLAN_STATUS_SUCCESS && -+ ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || -+ (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "authenticated"); -+ sta->flags |= WLAN_STA_AUTH; -+ } -+} -+ -+ -+static void handle_assoc_cb(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, -+ size_t len, int reassoc, int ok) -+{ -+ u16 status; -+ struct sta_info *sta; -+ int new_assoc = 1; -+ struct ieee80211_ht_capabilities ht_cap; -+ -+ if (!ok) { -+ hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "did not acknowledge association response"); -+ return; -+ } -+ -+ if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : -+ sizeof(mgmt->u.assoc_resp))) { -+ printf("handle_assoc_cb(reassoc=%d) - too short payload " -+ "(len=%lu)\n", reassoc, (unsigned long) len); -+ return; -+ } -+ -+ if (reassoc) -+ status = le_to_host16(mgmt->u.reassoc_resp.status_code); -+ else -+ status = le_to_host16(mgmt->u.assoc_resp.status_code); -+ -+ sta = ap_get_sta(hapd, mgmt->da); -+ if (!sta) { -+ printf("handle_assoc_cb: STA " MACSTR " not found\n", -+ MAC2STR(mgmt->da)); -+ return; -+ } -+ -+ if (status != WLAN_STATUS_SUCCESS) -+ goto fail; -+ -+ /* Stop previous accounting session, if one is started, and allocate -+ * new session id for the new session. */ -+ accounting_sta_stop(hapd, sta); -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, -+ "associated (aid %d)", -+ sta->aid); -+ -+ if (sta->flags & WLAN_STA_ASSOC) -+ new_assoc = 0; -+ sta->flags |= WLAN_STA_ASSOC; -+ if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || -+ sta->auth_alg == WLAN_AUTH_FT) { -+ /* -+ * Open, static WEP, or FT protocol; no separate authorization -+ * step. -+ */ -+ ap_sta_set_authorized(hapd, sta, 1); -+ wpa_msg(hapd->msg_ctx, MSG_INFO, -+ AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); -+ } -+ -+ if (reassoc) -+ mlme_reassociate_indication(hapd, sta); -+ else -+ mlme_associate_indication(hapd, sta); -+ -+#ifdef CONFIG_IEEE80211W -+ sta->sa_query_timed_out = 0; -+#endif /* CONFIG_IEEE80211W */ -+ -+ /* -+ * Remove the STA entry in order to make sure the STA PS state gets -+ * cleared and configuration gets updated in case of reassociation back -+ * to the same AP. -+ */ -+ hostapd_drv_sta_remove(hapd, sta->addr); -+ -+#ifdef CONFIG_IEEE80211N -+ if (sta->flags & WLAN_STA_HT) -+ hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); -+#endif /* CONFIG_IEEE80211N */ -+ -+ if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, -+ sta->supported_rates, sta->supported_rates_len, -+ sta->listen_interval, -+ sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_NOTICE, -+ "Could not add STA to kernel driver"); -+ } -+ -+ if (sta->flags & WLAN_STA_WDS) -+ hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1); -+ -+ if (sta->eapol_sm == NULL) { -+ /* -+ * This STA does not use RADIUS server for EAP authentication, -+ * so bind it to the selected VLAN interface now, since the -+ * interface selection is not going to change anymore. -+ */ -+ if (ap_sta_bind_vlan(hapd, sta, 0) < 0) -+ goto fail; -+ } else if (sta->vlan_id) { -+ /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ -+ if (ap_sta_bind_vlan(hapd, sta, 0) < 0) -+ goto fail; -+ } -+ -+ hostapd_set_sta_flags(hapd, sta); -+ -+ if (sta->auth_alg == WLAN_AUTH_FT) -+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); -+ else -+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); -+ hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); -+ -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); -+ -+ fail: -+ /* Copy of the association request is not needed anymore */ -+ if (sta->last_assoc_req) { -+ os_free(sta->last_assoc_req); -+ sta->last_assoc_req = NULL; -+ } -+} -+ -+ -+/** -+ * ieee802_11_mgmt_cb - Process management frame TX status callback -+ * @hapd: hostapd BSS data structure (the BSS from which the management frame -+ * was sent from) -+ * @buf: management frame data (starting from IEEE 802.11 header) -+ * @len: length of frame data in octets -+ * @stype: management frame subtype from frame control field -+ * @ok: Whether the frame was ACK'ed -+ */ -+void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, -+ u16 stype, int ok) -+{ -+ const struct ieee80211_mgmt *mgmt; -+ mgmt = (const struct ieee80211_mgmt *) buf; -+ -+ switch (stype) { -+ case WLAN_FC_STYPE_AUTH: -+ wpa_printf(MSG_DEBUG, "mgmt::auth cb"); -+ handle_auth_cb(hapd, mgmt, len, ok); -+ break; -+ case WLAN_FC_STYPE_ASSOC_RESP: -+ wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb"); -+ handle_assoc_cb(hapd, mgmt, len, 0, ok); -+ break; -+ case WLAN_FC_STYPE_REASSOC_RESP: -+ wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb"); -+ handle_assoc_cb(hapd, mgmt, len, 1, ok); -+ break; -+ case WLAN_FC_STYPE_PROBE_RESP: -+ wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb"); -+ break; -+ case WLAN_FC_STYPE_DEAUTH: -+ /* ignore */ -+ break; -+ case WLAN_FC_STYPE_ACTION: -+ wpa_printf(MSG_DEBUG, "mgmt::action cb"); -+ break; -+ default: -+ printf("unknown mgmt cb frame subtype %d\n", stype); -+ break; -+ } -+} -+ -+ -+int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) -+{ -+ /* TODO */ -+ return 0; -+} -+ -+ -+int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ char *buf, size_t buflen) -+{ -+ /* TODO */ -+ return 0; -+} -+ -+ -+void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *buf, size_t len, int ack) -+{ -+ struct sta_info *sta; -+ struct hostapd_iface *iface = hapd->iface; -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta == NULL && iface->num_bss > 1) { -+ size_t j; -+ for (j = 0; j < iface->num_bss; j++) { -+ hapd = iface->bss[j]; -+ sta = ap_get_sta(hapd, addr); -+ if (sta) -+ break; -+ } -+ } -+ if (sta == NULL) -+ return; -+ if (sta->flags & WLAN_STA_PENDING_POLL) { -+ wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " -+ "activity poll", MAC2STR(sta->addr), -+ ack ? "ACKed" : "did not ACK"); -+ if (ack) -+ sta->flags &= ~WLAN_STA_PENDING_POLL; -+ } -+ -+ ieee802_1x_tx_status(hapd, sta, buf, len, ack); -+} -+ -+ -+void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, -+ int wds) -+{ -+ struct sta_info *sta; -+ -+ sta = ap_get_sta(hapd, src); -+ if (sta && (sta->flags & WLAN_STA_ASSOC)) { -+ if (wds && !(sta->flags & WLAN_STA_WDS)) { -+ wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " -+ "STA " MACSTR " (aid %u)", -+ MAC2STR(sta->addr), sta->aid); -+ sta->flags |= WLAN_STA_WDS; -+ hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1); -+ } -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " -+ MACSTR, MAC2STR(src)); -+ if (src[0] & 0x01) { -+ /* Broadcast bit set in SA?! Ignore the frame silently. */ -+ return; -+ } -+ -+ if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) { -+ wpa_printf(MSG_DEBUG, "Association Response to the STA has " -+ "already been sent, but no TX status yet known - " -+ "ignore Class 3 frame issue with " MACSTR, -+ MAC2STR(src)); -+ return; -+ } -+ -+ if (sta && (sta->flags & WLAN_STA_AUTH)) -+ hostapd_drv_sta_disassoc( -+ hapd, src, -+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); -+ else -+ hostapd_drv_sta_deauth( -+ hapd, src, -+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); -+} -+ -+ -+#endif /* CONFIG_NATIVE_WINDOWS */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.h -new file mode 100644 -index 0000000000000..157198c826075 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11.h -@@ -0,0 +1,68 @@ -+/* -+ * hostapd / IEEE 802.11 Management -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IEEE802_11_H -+#define IEEE802_11_H -+ -+struct hostapd_iface; -+struct hostapd_data; -+struct sta_info; -+struct hostapd_frame_info; -+struct ieee80211_ht_capabilities; -+ -+void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, -+ struct hostapd_frame_info *fi); -+void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, -+ u16 stype, int ok); -+void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len); -+#ifdef NEED_AP_MLME -+int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); -+int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ char *buf, size_t buflen); -+#else /* NEED_AP_MLME */ -+static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, -+ size_t buflen) -+{ -+ return 0; -+} -+ -+static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ char *buf, size_t buflen) -+{ -+ return 0; -+} -+#endif /* NEED_AP_MLME */ -+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, -+ int probe); -+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid); -+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid); -+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid); -+u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid); -+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid); -+int hostapd_ht_operation_update(struct hostapd_iface *iface); -+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, -+ const u8 *addr, const u8 *trans_id); -+void hostapd_get_ht_capab(struct hostapd_data *hapd, -+ struct ieee80211_ht_capabilities *ht_cap, -+ struct ieee80211_ht_capabilities *neg_ht_cap); -+u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *ht_capab, size_t ht_capab_len); -+void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); -+void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *buf, size_t len, int ack); -+void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, -+ int wds); -+ -+#endif /* IEEE802_11_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.c -new file mode 100644 -index 0000000000000..b933263b07145 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.c -@@ -0,0 +1,524 @@ -+/* -+ * hostapd / IEEE 802.11 authentication (ACL) -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * Access control list for IEEE 802.11 authentication can uses statically -+ * configured ACL from configuration files or an external RADIUS server. -+ * Results from external RADIUS queries are cached to allow faster -+ * authentication frame processing. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "radius/radius.h" -+#include "radius/radius_client.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ap_drv_ops.h" -+#include "ieee802_11.h" -+#include "ieee802_11_auth.h" -+ -+#define RADIUS_ACL_TIMEOUT 30 -+ -+ -+struct hostapd_cached_radius_acl { -+ os_time_t timestamp; -+ macaddr addr; -+ int accepted; /* HOSTAPD_ACL_* */ -+ struct hostapd_cached_radius_acl *next; -+ u32 session_timeout; -+ u32 acct_interim_interval; -+ int vlan_id; -+}; -+ -+ -+struct hostapd_acl_query_data { -+ os_time_t timestamp; -+ u8 radius_id; -+ macaddr addr; -+ u8 *auth_msg; /* IEEE 802.11 authentication frame from station */ -+ size_t auth_msg_len; -+ struct hostapd_acl_query_data *next; -+}; -+ -+ -+#ifndef CONFIG_NO_RADIUS -+static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) -+{ -+ struct hostapd_cached_radius_acl *prev; -+ -+ while (acl_cache) { -+ prev = acl_cache; -+ acl_cache = acl_cache->next; -+ os_free(prev); -+ } -+} -+ -+ -+static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, -+ u32 *session_timeout, -+ u32 *acct_interim_interval, int *vlan_id) -+{ -+ struct hostapd_cached_radius_acl *entry; -+ struct os_time now; -+ -+ os_get_time(&now); -+ entry = hapd->acl_cache; -+ -+ while (entry) { -+ if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { -+ if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT) -+ return -1; /* entry has expired */ -+ if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT) -+ if (session_timeout) -+ *session_timeout = -+ entry->session_timeout; -+ if (acct_interim_interval) -+ *acct_interim_interval = -+ entry->acct_interim_interval; -+ if (vlan_id) -+ *vlan_id = entry->vlan_id; -+ return entry->accepted; -+ } -+ -+ entry = entry->next; -+ } -+ -+ return -1; -+} -+#endif /* CONFIG_NO_RADIUS */ -+ -+ -+static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) -+{ -+ if (query == NULL) -+ return; -+ os_free(query->auth_msg); -+ os_free(query); -+} -+ -+ -+#ifndef CONFIG_NO_RADIUS -+static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, -+ struct hostapd_acl_query_data *query) -+{ -+ struct radius_msg *msg; -+ char buf[128]; -+ -+ query->radius_id = radius_client_get_id(hapd->radius); -+ msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); -+ if (msg == NULL) -+ return -1; -+ -+ radius_msg_make_authenticator(msg, addr, ETH_ALEN); -+ -+ os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, -+ os_strlen(buf))) { -+ wpa_printf(MSG_DEBUG, "Could not add User-Name"); -+ goto fail; -+ } -+ -+ if (!radius_msg_add_attr_user_password( -+ msg, (u8 *) buf, os_strlen(buf), -+ hapd->conf->radius->auth_server->shared_secret, -+ hapd->conf->radius->auth_server->shared_secret_len)) { -+ wpa_printf(MSG_DEBUG, "Could not add User-Password"); -+ goto fail; -+ } -+ -+ if (hapd->conf->own_ip_addr.af == AF_INET && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, -+ (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { -+ wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address"); -+ goto fail; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (hapd->conf->own_ip_addr.af == AF_INET6 && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, -+ (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { -+ wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address"); -+ goto fail; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ if (hapd->conf->nas_identifier && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, -+ (u8 *) hapd->conf->nas_identifier, -+ os_strlen(hapd->conf->nas_identifier))) { -+ wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier"); -+ goto fail; -+ } -+ -+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", -+ MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, -+ (u8 *) buf, os_strlen(buf))) { -+ wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id"); -+ goto fail; -+ } -+ -+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, -+ MAC2STR(addr)); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, -+ (u8 *) buf, os_strlen(buf))) { -+ wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id"); -+ goto fail; -+ } -+ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, -+ RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { -+ wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type"); -+ goto fail; -+ } -+ -+ os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, -+ (u8 *) buf, os_strlen(buf))) { -+ wpa_printf(MSG_DEBUG, "Could not add Connect-Info"); -+ goto fail; -+ } -+ -+ radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr); -+ return 0; -+ -+ fail: -+ radius_msg_free(msg); -+ return -1; -+} -+#endif /* CONFIG_NO_RADIUS */ -+ -+ -+/** -+ * hostapd_allowed_address - Check whether a specified STA can be authenticated -+ * @hapd: hostapd BSS data -+ * @addr: MAC address of the STA -+ * @msg: Authentication message -+ * @len: Length of msg in octets -+ * @session_timeout: Buffer for returning session timeout (from RADIUS) -+ * @acct_interim_interval: Buffer for returning account interval (from RADIUS) -+ * @vlan_id: Buffer for returning VLAN ID -+ * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING -+ */ -+int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *msg, size_t len, u32 *session_timeout, -+ u32 *acct_interim_interval, int *vlan_id) -+{ -+ if (session_timeout) -+ *session_timeout = 0; -+ if (acct_interim_interval) -+ *acct_interim_interval = 0; -+ if (vlan_id) -+ *vlan_id = 0; -+ -+ if (hostapd_maclist_found(hapd->conf->accept_mac, -+ hapd->conf->num_accept_mac, addr, vlan_id)) -+ return HOSTAPD_ACL_ACCEPT; -+ -+ if (hostapd_maclist_found(hapd->conf->deny_mac, -+ hapd->conf->num_deny_mac, addr, vlan_id)) -+ return HOSTAPD_ACL_REJECT; -+ -+ if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED) -+ return HOSTAPD_ACL_ACCEPT; -+ if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED) -+ return HOSTAPD_ACL_REJECT; -+ -+ if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) { -+#ifdef CONFIG_NO_RADIUS -+ return HOSTAPD_ACL_REJECT; -+#else /* CONFIG_NO_RADIUS */ -+ struct hostapd_acl_query_data *query; -+ -+ /* Check whether ACL cache has an entry for this station */ -+ int res = hostapd_acl_cache_get(hapd, addr, session_timeout, -+ acct_interim_interval, -+ vlan_id); -+ if (res == HOSTAPD_ACL_ACCEPT || -+ res == HOSTAPD_ACL_ACCEPT_TIMEOUT) -+ return res; -+ if (res == HOSTAPD_ACL_REJECT) -+ return HOSTAPD_ACL_REJECT; -+ -+ query = hapd->acl_queries; -+ while (query) { -+ if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) { -+ /* pending query in RADIUS retransmit queue; -+ * do not generate a new one */ -+ return HOSTAPD_ACL_PENDING; -+ } -+ query = query->next; -+ } -+ -+ if (!hapd->conf->radius->auth_server) -+ return HOSTAPD_ACL_REJECT; -+ -+ /* No entry in the cache - query external RADIUS server */ -+ query = os_zalloc(sizeof(*query)); -+ if (query == NULL) { -+ wpa_printf(MSG_ERROR, "malloc for query data failed"); -+ return HOSTAPD_ACL_REJECT; -+ } -+ time(&query->timestamp); -+ os_memcpy(query->addr, addr, ETH_ALEN); -+ if (hostapd_radius_acl_query(hapd, addr, query)) { -+ wpa_printf(MSG_DEBUG, "Failed to send Access-Request " -+ "for ACL query."); -+ hostapd_acl_query_free(query); -+ return HOSTAPD_ACL_REJECT; -+ } -+ -+ query->auth_msg = os_malloc(len); -+ if (query->auth_msg == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to allocate memory for " -+ "auth frame."); -+ hostapd_acl_query_free(query); -+ return HOSTAPD_ACL_REJECT; -+ } -+ os_memcpy(query->auth_msg, msg, len); -+ query->auth_msg_len = len; -+ query->next = hapd->acl_queries; -+ hapd->acl_queries = query; -+ -+ /* Queued data will be processed in hostapd_acl_recv_radius() -+ * when RADIUS server replies to the sent Access-Request. */ -+ return HOSTAPD_ACL_PENDING; -+#endif /* CONFIG_NO_RADIUS */ -+ } -+ -+ return HOSTAPD_ACL_REJECT; -+} -+ -+ -+#ifndef CONFIG_NO_RADIUS -+static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now) -+{ -+ struct hostapd_cached_radius_acl *prev, *entry, *tmp; -+ -+ prev = NULL; -+ entry = hapd->acl_cache; -+ -+ while (entry) { -+ if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { -+ wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR -+ " has expired.", MAC2STR(entry->addr)); -+ if (prev) -+ prev->next = entry->next; -+ else -+ hapd->acl_cache = entry->next; -+ hostapd_drv_set_radius_acl_expire(hapd, entry->addr); -+ tmp = entry; -+ entry = entry->next; -+ os_free(tmp); -+ continue; -+ } -+ -+ prev = entry; -+ entry = entry->next; -+ } -+} -+ -+ -+static void hostapd_acl_expire_queries(struct hostapd_data *hapd, -+ os_time_t now) -+{ -+ struct hostapd_acl_query_data *prev, *entry, *tmp; -+ -+ prev = NULL; -+ entry = hapd->acl_queries; -+ -+ while (entry) { -+ if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { -+ wpa_printf(MSG_DEBUG, "ACL query for " MACSTR -+ " has expired.", MAC2STR(entry->addr)); -+ if (prev) -+ prev->next = entry->next; -+ else -+ hapd->acl_queries = entry->next; -+ -+ tmp = entry; -+ entry = entry->next; -+ hostapd_acl_query_free(tmp); -+ continue; -+ } -+ -+ prev = entry; -+ entry = entry->next; -+ } -+} -+ -+ -+/** -+ * hostapd_acl_expire - ACL cache expiration callback -+ * @eloop_ctx: struct hostapd_data * -+ * @timeout_ctx: Not used -+ */ -+static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ struct os_time now; -+ -+ os_get_time(&now); -+ hostapd_acl_expire_cache(hapd, now.sec); -+ hostapd_acl_expire_queries(hapd, now.sec); -+ -+ eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); -+} -+ -+ -+/** -+ * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages -+ * @msg: RADIUS response message -+ * @req: RADIUS request message -+ * @shared_secret: RADIUS shared secret -+ * @shared_secret_len: Length of shared_secret in octets -+ * @data: Context data (struct hostapd_data *) -+ * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and -+ * was processed here) or RADIUS_RX_UNKNOWN if not. -+ */ -+static RadiusRxResult -+hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, -+ const u8 *shared_secret, size_t shared_secret_len, -+ void *data) -+{ -+ struct hostapd_data *hapd = data; -+ struct hostapd_acl_query_data *query, *prev; -+ struct hostapd_cached_radius_acl *cache; -+ struct radius_hdr *hdr = radius_msg_get_hdr(msg); -+ -+ query = hapd->acl_queries; -+ prev = NULL; -+ while (query) { -+ if (query->radius_id == hdr->identifier) -+ break; -+ prev = query; -+ query = query->next; -+ } -+ if (query == NULL) -+ return RADIUS_RX_UNKNOWN; -+ -+ wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " -+ "message (id=%d)", query->radius_id); -+ -+ if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { -+ wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " -+ "correct authenticator - dropped\n"); -+ return RADIUS_RX_INVALID_AUTHENTICATOR; -+ } -+ -+ if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && -+ hdr->code != RADIUS_CODE_ACCESS_REJECT) { -+ wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " -+ "query", hdr->code); -+ return RADIUS_RX_UNKNOWN; -+ } -+ -+ /* Insert Accept/Reject info into ACL cache */ -+ cache = os_zalloc(sizeof(*cache)); -+ if (cache == NULL) { -+ wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); -+ goto done; -+ } -+ time(&cache->timestamp); -+ os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); -+ if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { -+ if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, -+ &cache->session_timeout) == 0) -+ cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; -+ else -+ cache->accepted = HOSTAPD_ACL_ACCEPT; -+ -+ if (radius_msg_get_attr_int32( -+ msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, -+ &cache->acct_interim_interval) == 0 && -+ cache->acct_interim_interval < 60) { -+ wpa_printf(MSG_DEBUG, "Ignored too small " -+ "Acct-Interim-Interval %d for STA " MACSTR, -+ cache->acct_interim_interval, -+ MAC2STR(query->addr)); -+ cache->acct_interim_interval = 0; -+ } -+ -+ cache->vlan_id = radius_msg_get_vlanid(msg); -+ } else -+ cache->accepted = HOSTAPD_ACL_REJECT; -+ cache->next = hapd->acl_cache; -+ hapd->acl_cache = cache; -+ -+#ifdef CONFIG_DRIVER_RADIUS_ACL -+ hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, -+ cache->session_timeout); -+#else /* CONFIG_DRIVER_RADIUS_ACL */ -+#ifdef NEED_AP_MLME -+ /* Re-send original authentication frame for 802.11 processing */ -+ wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " -+ "successful RADIUS ACL query"); -+ ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); -+#endif /* NEED_AP_MLME */ -+#endif /* CONFIG_DRIVER_RADIUS_ACL */ -+ -+ done: -+ if (prev == NULL) -+ hapd->acl_queries = query->next; -+ else -+ prev->next = query->next; -+ -+ hostapd_acl_query_free(query); -+ -+ return RADIUS_RX_PROCESSED; -+} -+#endif /* CONFIG_NO_RADIUS */ -+ -+ -+/** -+ * hostapd_acl_init: Initialize IEEE 802.11 ACL -+ * @hapd: hostapd BSS data -+ * Returns: 0 on success, -1 on failure -+ */ -+int hostapd_acl_init(struct hostapd_data *hapd) -+{ -+#ifndef CONFIG_NO_RADIUS -+ if (radius_client_register(hapd->radius, RADIUS_AUTH, -+ hostapd_acl_recv_radius, hapd)) -+ return -1; -+ -+ eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); -+#endif /* CONFIG_NO_RADIUS */ -+ -+ return 0; -+} -+ -+ -+/** -+ * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL -+ * @hapd: hostapd BSS data -+ */ -+void hostapd_acl_deinit(struct hostapd_data *hapd) -+{ -+ struct hostapd_acl_query_data *query, *prev; -+ -+#ifndef CONFIG_NO_RADIUS -+ eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL); -+ -+ hostapd_acl_cache_free(hapd->acl_cache); -+#endif /* CONFIG_NO_RADIUS */ -+ -+ query = hapd->acl_queries; -+ while (query) { -+ prev = query; -+ query = query->next; -+ hostapd_acl_query_free(prev); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.h -new file mode 100644 -index 0000000000000..b2971e5092b52 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_auth.h -@@ -0,0 +1,31 @@ -+/* -+ * hostapd / IEEE 802.11 authentication (ACL) -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IEEE802_11_AUTH_H -+#define IEEE802_11_AUTH_H -+ -+enum { -+ HOSTAPD_ACL_REJECT = 0, -+ HOSTAPD_ACL_ACCEPT = 1, -+ HOSTAPD_ACL_PENDING = 2, -+ HOSTAPD_ACL_ACCEPT_TIMEOUT = 3 -+}; -+ -+int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *msg, size_t len, u32 *session_timeout, -+ u32 *acct_interim_interval, int *vlan_id); -+int hostapd_acl_init(struct hostapd_data *hapd); -+void hostapd_acl_deinit(struct hostapd_data *hapd); -+ -+#endif /* IEEE802_11_AUTH_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_ht.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_ht.c -new file mode 100644 -index 0000000000000..3dce5cbe4eeec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_11_ht.c -@@ -0,0 +1,267 @@ -+/* -+ * hostapd / IEEE 802.11n HT -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * Copyright (c) 2007-2008, Intel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "drivers/driver.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "sta_info.h" -+#include "beacon.h" -+#include "ieee802_11.h" -+ -+ -+u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) -+{ -+ struct ieee80211_ht_capabilities *cap; -+ u8 *pos = eid; -+ -+ if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode || -+ hapd->conf->disable_11n) -+ return eid; -+ -+ *pos++ = WLAN_EID_HT_CAP; -+ *pos++ = sizeof(*cap); -+ -+ cap = (struct ieee80211_ht_capabilities *) pos; -+ os_memset(cap, 0, sizeof(*cap)); -+ cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab); -+ cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params; -+ os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set, -+ 16); -+ -+ /* TODO: ht_extended_capabilities (now fully disabled) */ -+ /* TODO: tx_bf_capability_info (now fully disabled) */ -+ /* TODO: asel_capabilities (now fully disabled) */ -+ -+ pos += sizeof(*cap); -+ -+ return pos; -+} -+ -+ -+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) -+{ -+ struct ieee80211_ht_operation *oper; -+ u8 *pos = eid; -+ -+ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n) -+ return eid; -+ -+ *pos++ = WLAN_EID_HT_OPERATION; -+ *pos++ = sizeof(*oper); -+ -+ oper = (struct ieee80211_ht_operation *) pos; -+ os_memset(oper, 0, sizeof(*oper)); -+ -+ oper->control_chan = hapd->iconf->channel; -+ oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode); -+ if (hapd->iconf->secondary_channel == 1) -+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | -+ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; -+ if (hapd->iconf->secondary_channel == -1) -+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | -+ HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; -+ -+ pos += sizeof(*oper); -+ -+ return pos; -+} -+ -+ -+/* -+op_mode -+Set to 0 (HT pure) under the followign conditions -+ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or -+ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS -+Set to 1 (HT non-member protection) if there may be non-HT STAs -+ in both the primary and the secondary channel -+Set to 2 if only HT STAs are associated in BSS, -+ however and at least one 20 MHz HT STA is associated -+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated -+*/ -+int hostapd_ht_operation_update(struct hostapd_iface *iface) -+{ -+ u16 cur_op_mode, new_op_mode; -+ int op_mode_changes = 0; -+ -+ if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X", -+ __func__, iface->ht_op_mode); -+ -+ if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) -+ && iface->num_sta_ht_no_gf) { -+ iface->ht_op_mode |= -+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; -+ op_mode_changes++; -+ } else if ((iface->ht_op_mode & -+ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && -+ iface->num_sta_ht_no_gf == 0) { -+ iface->ht_op_mode &= -+ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; -+ op_mode_changes++; -+ } -+ -+ if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && -+ (iface->num_sta_no_ht || iface->olbc_ht)) { -+ iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; -+ op_mode_changes++; -+ } else if ((iface->ht_op_mode & -+ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && -+ (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) { -+ iface->ht_op_mode &= -+ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; -+ op_mode_changes++; -+ } -+ -+ new_op_mode = 0; -+ if (iface->num_sta_no_ht) -+ new_op_mode = OP_MODE_MIXED; -+ else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) -+ && iface->num_sta_ht_20mhz) -+ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; -+ else if (iface->olbc_ht) -+ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; -+ else -+ new_op_mode = OP_MODE_PURE; -+ -+ cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; -+ if (cur_op_mode != new_op_mode) { -+ iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; -+ iface->ht_op_mode |= new_op_mode; -+ op_mode_changes++; -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d", -+ __func__, iface->ht_op_mode, op_mode_changes); -+ -+ return op_mode_changes; -+} -+ -+ -+u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *ht_capab, size_t ht_capab_len) -+{ -+ /* Disable HT caps for STAs associated to no-HT BSSes. */ -+ if (!ht_capab || -+ ht_capab_len < sizeof(struct ieee80211_ht_capabilities) || -+ hapd->conf->disable_11n) { -+ sta->flags &= ~WLAN_STA_HT; -+ os_free(sta->ht_capabilities); -+ sta->ht_capabilities = NULL; -+ return WLAN_STATUS_SUCCESS; -+ } -+ -+ if (sta->ht_capabilities == NULL) { -+ sta->ht_capabilities = -+ os_zalloc(sizeof(struct ieee80211_ht_capabilities)); -+ if (sta->ht_capabilities == NULL) -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ sta->flags |= WLAN_STA_HT; -+ os_memcpy(sta->ht_capabilities, ht_capab, -+ sizeof(struct ieee80211_ht_capabilities)); -+ -+ return WLAN_STATUS_SUCCESS; -+} -+ -+ -+static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ u16 ht_capab; -+ -+ ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info); -+ wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: " -+ "0x%04x", MAC2STR(sta->addr), ht_capab); -+ if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) { -+ if (!sta->no_ht_gf_set) { -+ sta->no_ht_gf_set = 1; -+ hapd->iface->num_sta_ht_no_gf++; -+ } -+ wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num " -+ "of non-gf stations %d", -+ __func__, MAC2STR(sta->addr), -+ hapd->iface->num_sta_ht_no_gf); -+ } -+ if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) { -+ if (!sta->ht_20mhz_set) { -+ sta->ht_20mhz_set = 1; -+ hapd->iface->num_sta_ht_20mhz++; -+ } -+ wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of " -+ "20MHz HT STAs %d", -+ __func__, MAC2STR(sta->addr), -+ hapd->iface->num_sta_ht_20mhz); -+ } -+} -+ -+ -+static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ if (!sta->no_ht_set) { -+ sta->no_ht_set = 1; -+ hapd->iface->num_sta_no_ht++; -+ } -+ if (hapd->iconf->ieee80211n) { -+ wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of " -+ "non-HT stations %d", -+ __func__, MAC2STR(sta->addr), -+ hapd->iface->num_sta_no_ht); -+ } -+} -+ -+ -+void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) -+ update_sta_ht(hapd, sta); -+ else -+ update_sta_no_ht(hapd, sta); -+ -+ if (hostapd_ht_operation_update(hapd->iface) > 0) -+ ieee802_11_set_beacons(hapd->iface); -+} -+ -+ -+void hostapd_get_ht_capab(struct hostapd_data *hapd, -+ struct ieee80211_ht_capabilities *ht_cap, -+ struct ieee80211_ht_capabilities *neg_ht_cap) -+{ -+ u16 cap; -+ -+ if (ht_cap == NULL) -+ return; -+ os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap)); -+ cap = le_to_host16(neg_ht_cap->ht_capabilities_info); -+ cap &= hapd->iconf->ht_capab; -+ cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED); -+ -+ /* -+ * STBC needs to be handled specially -+ * if we don't support RX STBC, mask out TX STBC in the STA's HT caps -+ * if we don't support TX STBC, mask out RX STBC in the STA's HT caps -+ */ -+ if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK)) -+ cap &= ~HT_CAP_INFO_TX_STBC; -+ if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC)) -+ cap &= ~HT_CAP_INFO_RX_STBC_MASK; -+ -+ neg_ht_cap->ht_capabilities_info = host_to_le16(cap); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.c -new file mode 100644 -index 0000000000000..ac0c127001087 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.c -@@ -0,0 +1,2085 @@ -+/* -+ * hostapd / IEEE 802.1X-2004 Authenticator -+ * Copyright (c) 2002-2011, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "crypto/md5.h" -+#include "crypto/crypto.h" -+#include "crypto/random.h" -+#include "common/ieee802_11_defs.h" -+#include "common/wpa_ctrl.h" -+#include "radius/radius.h" -+#include "radius/radius_client.h" -+#include "eap_server/eap.h" -+#include "eap_common/eap_wsc_common.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "eapol_auth/eapol_auth_sm_i.h" -+#include "hostapd.h" -+#include "accounting.h" -+#include "sta_info.h" -+#include "wpa_auth.h" -+#include "preauth_auth.h" -+#include "pmksa_cache_auth.h" -+#include "ap_config.h" -+#include "ap_drv_ops.h" -+#include "ieee802_1x.h" -+ -+ -+static void ieee802_1x_finished(struct hostapd_data *hapd, -+ struct sta_info *sta, int success); -+ -+ -+static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, -+ u8 type, const u8 *data, size_t datalen) -+{ -+ u8 *buf; -+ struct ieee802_1x_hdr *xhdr; -+ size_t len; -+ int encrypt = 0; -+ -+ len = sizeof(*xhdr) + datalen; -+ buf = os_zalloc(len); -+ if (buf == NULL) { -+ wpa_printf(MSG_ERROR, "malloc() failed for " -+ "ieee802_1x_send(len=%lu)", -+ (unsigned long) len); -+ return; -+ } -+ -+ xhdr = (struct ieee802_1x_hdr *) buf; -+ xhdr->version = hapd->conf->eapol_version; -+ xhdr->type = type; -+ xhdr->length = host_to_be16(datalen); -+ -+ if (datalen > 0 && data != NULL) -+ os_memcpy(xhdr + 1, data, datalen); -+ -+ if (wpa_auth_pairwise_set(sta->wpa_sm)) -+ encrypt = 1; -+ if (sta->flags & WLAN_STA_PREAUTH) { -+ rsn_preauth_send(hapd, sta, buf, len); -+ } else { -+ hostapd_drv_hapd_send_eapol(hapd, sta->addr, buf, len, -+ encrypt, sta->flags); -+ } -+ -+ os_free(buf); -+} -+ -+ -+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, -+ struct sta_info *sta, int authorized) -+{ -+ int res; -+ -+ if (sta->flags & WLAN_STA_PREAUTH) -+ return; -+ -+ if (authorized) { -+ if (!ap_sta_is_authorized(sta)) -+ wpa_msg(hapd->msg_ctx, MSG_INFO, -+ AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); -+ ap_sta_set_authorized(hapd, sta, 1); -+ res = hostapd_set_authorized(hapd, sta, 1); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "authorizing port"); -+ } else { -+ if (ap_sta_is_authorized(sta) && (sta->flags & WLAN_STA_ASSOC)) -+ wpa_msg(hapd->msg_ctx, MSG_INFO, -+ AP_STA_DISCONNECTED MACSTR, -+ MAC2STR(sta->addr)); -+ ap_sta_set_authorized(hapd, sta, 0); -+ res = hostapd_set_authorized(hapd, sta, 0); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); -+ } -+ -+ if (res && errno != ENOENT) { -+ printf("Could not set station " MACSTR " flags for kernel " -+ "driver (errno=%d).\n", MAC2STR(sta->addr), errno); -+ } -+ -+ if (authorized) -+ accounting_sta_start(hapd, sta); -+} -+ -+ -+static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ int idx, int broadcast, -+ u8 *key_data, size_t key_len) -+{ -+ u8 *buf, *ekey; -+ struct ieee802_1x_hdr *hdr; -+ struct ieee802_1x_eapol_key *key; -+ size_t len, ekey_len; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ if (sm == NULL) -+ return; -+ -+ len = sizeof(*key) + key_len; -+ buf = os_zalloc(sizeof(*hdr) + len); -+ if (buf == NULL) -+ return; -+ -+ hdr = (struct ieee802_1x_hdr *) buf; -+ key = (struct ieee802_1x_eapol_key *) (hdr + 1); -+ key->type = EAPOL_KEY_TYPE_RC4; -+ key->key_length = htons(key_len); -+ wpa_get_ntp_timestamp(key->replay_counter); -+ -+ if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { -+ wpa_printf(MSG_ERROR, "Could not get random numbers"); -+ os_free(buf); -+ return; -+ } -+ -+ key->key_index = idx | (broadcast ? 0 : BIT(7)); -+ if (hapd->conf->eapol_key_index_workaround) { -+ /* According to some information, WinXP Supplicant seems to -+ * interpret bit7 as an indication whether the key is to be -+ * activated, so make it possible to enable workaround that -+ * sets this bit for all keys. */ -+ key->key_index |= BIT(7); -+ } -+ -+ /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and -+ * MSK[32..63] is used to sign the message. */ -+ if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { -+ wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " -+ "and signing EAPOL-Key"); -+ os_free(buf); -+ return; -+ } -+ os_memcpy((u8 *) (key + 1), key_data, key_len); -+ ekey_len = sizeof(key->key_iv) + 32; -+ ekey = os_malloc(ekey_len); -+ if (ekey == NULL) { -+ wpa_printf(MSG_ERROR, "Could not encrypt key"); -+ os_free(buf); -+ return; -+ } -+ os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); -+ os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); -+ rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); -+ os_free(ekey); -+ -+ /* This header is needed here for HMAC-MD5, but it will be regenerated -+ * in ieee802_1x_send() */ -+ hdr->version = hapd->conf->eapol_version; -+ hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; -+ hdr->length = host_to_be16(len); -+ hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, -+ key->key_signature); -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR -+ " (%s index=%d)", MAC2STR(sm->addr), -+ broadcast ? "broadcast" : "unicast", idx); -+ ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); -+ if (sta->eapol_sm) -+ sta->eapol_sm->dot1xAuthEapolFramesTx++; -+ os_free(buf); -+} -+ -+ -+#ifndef CONFIG_NO_VLAN -+static struct hostapd_wep_keys * -+ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname) -+{ -+ struct hostapd_wep_keys *key; -+ -+ key = os_zalloc(sizeof(*key)); -+ if (key == NULL) -+ return NULL; -+ -+ key->default_len = hapd->conf->default_wep_key_len; -+ -+ if (key->idx >= hapd->conf->broadcast_key_idx_max || -+ key->idx < hapd->conf->broadcast_key_idx_min) -+ key->idx = hapd->conf->broadcast_key_idx_min; -+ else -+ key->idx++; -+ -+ if (!key->key[key->idx]) -+ key->key[key->idx] = os_malloc(key->default_len); -+ if (key->key[key->idx] == NULL || -+ random_get_bytes(key->key[key->idx], key->default_len)) { -+ printf("Could not generate random WEP key (dynamic VLAN).\n"); -+ os_free(key->key[key->idx]); -+ key->key[key->idx] = NULL; -+ os_free(key); -+ return NULL; -+ } -+ key->len[key->idx] = key->default_len; -+ -+ wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n", -+ ifname, key->idx); -+ wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)", -+ key->key[key->idx], key->len[key->idx]); -+ -+ if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP, -+ broadcast_ether_addr, key->idx, 1, -+ NULL, 0, key->key[key->idx], -+ key->len[key->idx])) -+ printf("Could not set dynamic VLAN WEP encryption key.\n"); -+ -+ hostapd_set_drv_ieee8021x(hapd, ifname, 1); -+ -+ return key; -+} -+ -+ -+static struct hostapd_wep_keys * -+ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid, -+ size_t vlan_id) -+{ -+ const char *ifname; -+ -+ if (vlan_id == 0) -+ return &ssid->wep; -+ -+ if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys && -+ ssid->dyn_vlan_keys[vlan_id]) -+ return ssid->dyn_vlan_keys[vlan_id]; -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group " -+ "state machine for VLAN ID %lu", -+ (unsigned long) vlan_id); -+ -+ ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); -+ if (ifname == NULL) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - " -+ "cannot create group key state machine", -+ (unsigned long) vlan_id); -+ return NULL; -+ } -+ -+ if (ssid->dyn_vlan_keys == NULL) { -+ int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]); -+ ssid->dyn_vlan_keys = os_zalloc(size); -+ if (ssid->dyn_vlan_keys == NULL) -+ return NULL; -+ ssid->max_dyn_vlan_keys = vlan_id; -+ } -+ -+ if (ssid->max_dyn_vlan_keys < vlan_id) { -+ struct hostapd_wep_keys **na; -+ int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]); -+ na = os_realloc(ssid->dyn_vlan_keys, size); -+ if (na == NULL) -+ return NULL; -+ ssid->dyn_vlan_keys = na; -+ os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0, -+ (vlan_id - ssid->max_dyn_vlan_keys) * -+ sizeof(ssid->dyn_vlan_keys[0])); -+ ssid->max_dyn_vlan_keys = vlan_id; -+ } -+ -+ ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname); -+ -+ return ssid->dyn_vlan_keys[vlan_id]; -+} -+#endif /* CONFIG_NO_VLAN */ -+ -+ -+void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ struct eapol_authenticator *eapol = hapd->eapol_auth; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+#ifndef CONFIG_NO_VLAN -+ struct hostapd_wep_keys *key = NULL; -+ int vlan_id; -+#endif /* CONFIG_NO_VLAN */ -+ -+ if (sm == NULL || !sm->eap_if->eapKeyData) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, -+ MAC2STR(sta->addr)); -+ -+#ifndef CONFIG_NO_VLAN -+ vlan_id = sta->vlan_id; -+ if (vlan_id < 0 || vlan_id > MAX_VLAN_ID) -+ vlan_id = 0; -+ -+ if (vlan_id) { -+ key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id); -+ if (key && key->key[key->idx]) -+ ieee802_1x_tx_key_one(hapd, sta, key->idx, 1, -+ key->key[key->idx], -+ key->len[key->idx]); -+ } else -+#endif /* CONFIG_NO_VLAN */ -+ if (eapol->default_wep_key) { -+ ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, -+ eapol->default_wep_key, -+ hapd->conf->default_wep_key_len); -+ } -+ -+ if (hapd->conf->individual_wep_key_len > 0) { -+ u8 *ikey; -+ ikey = os_malloc(hapd->conf->individual_wep_key_len); -+ if (ikey == NULL || -+ random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) -+ { -+ wpa_printf(MSG_ERROR, "Could not generate random " -+ "individual WEP key."); -+ os_free(ikey); -+ return; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", -+ ikey, hapd->conf->individual_wep_key_len); -+ -+ ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, -+ hapd->conf->individual_wep_key_len); -+ -+ /* TODO: set encryption in TX callback, i.e., only after STA -+ * has ACKed EAPOL-Key frame */ -+ if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, -+ sta->addr, 0, 1, NULL, 0, ikey, -+ hapd->conf->individual_wep_key_len)) { -+ wpa_printf(MSG_ERROR, "Could not set individual WEP " -+ "encryption."); -+ } -+ -+ os_free(ikey); -+ } -+} -+ -+ -+const char *radius_mode_txt(struct hostapd_data *hapd) -+{ -+ switch (hapd->iface->conf->hw_mode) { -+ case HOSTAPD_MODE_IEEE80211A: -+ return "802.11a"; -+ case HOSTAPD_MODE_IEEE80211G: -+ return "802.11g"; -+ case HOSTAPD_MODE_IEEE80211B: -+ default: -+ return "802.11b"; -+ } -+} -+ -+ -+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ int i; -+ u8 rate = 0; -+ -+ for (i = 0; i < sta->supported_rates_len; i++) -+ if ((sta->supported_rates[i] & 0x7f) > rate) -+ rate = sta->supported_rates[i] & 0x7f; -+ -+ return rate; -+} -+ -+ -+#ifndef CONFIG_NO_RADIUS -+static void ieee802_1x_learn_identity(struct hostapd_data *hapd, -+ struct eapol_state_machine *sm, -+ const u8 *eap, size_t len) -+{ -+ const u8 *identity; -+ size_t identity_len; -+ -+ if (len <= sizeof(struct eap_hdr) || -+ eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) -+ return; -+ -+ identity = eap_get_identity(sm->eap, &identity_len); -+ if (identity == NULL) -+ return; -+ -+ /* Save station identity for future RADIUS packets */ -+ os_free(sm->identity); -+ sm->identity = os_malloc(identity_len + 1); -+ if (sm->identity == NULL) { -+ sm->identity_len = 0; -+ return; -+ } -+ -+ os_memcpy(sm->identity, identity, identity_len); -+ sm->identity_len = identity_len; -+ sm->identity[identity_len] = '\0'; -+ hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); -+ sm->dot1xAuthEapolRespIdFramesRx++; -+} -+ -+ -+static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ const u8 *eap, size_t len) -+{ -+ struct radius_msg *msg; -+ char buf[128]; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ if (sm == NULL) -+ return; -+ -+ ieee802_1x_learn_identity(hapd, sm, eap, len); -+ -+ wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " -+ "packet"); -+ -+ sm->radius_identifier = radius_client_get_id(hapd->radius); -+ msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, -+ sm->radius_identifier); -+ if (msg == NULL) { -+ printf("Could not create net RADIUS packet\n"); -+ return; -+ } -+ -+ radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); -+ -+ if (sm->identity && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, -+ sm->identity, sm->identity_len)) { -+ printf("Could not add User-Name\n"); -+ goto fail; -+ } -+ -+ if (hapd->conf->own_ip_addr.af == AF_INET && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, -+ (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { -+ printf("Could not add NAS-IP-Address\n"); -+ goto fail; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (hapd->conf->own_ip_addr.af == AF_INET6 && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, -+ (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { -+ printf("Could not add NAS-IPv6-Address\n"); -+ goto fail; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ if (hapd->conf->nas_identifier && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, -+ (u8 *) hapd->conf->nas_identifier, -+ os_strlen(hapd->conf->nas_identifier))) { -+ printf("Could not add NAS-Identifier\n"); -+ goto fail; -+ } -+ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { -+ printf("Could not add NAS-Port\n"); -+ goto fail; -+ } -+ -+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", -+ MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); -+ buf[sizeof(buf) - 1] = '\0'; -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, -+ (u8 *) buf, os_strlen(buf))) { -+ printf("Could not add Called-Station-Id\n"); -+ goto fail; -+ } -+ -+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, -+ MAC2STR(sta->addr)); -+ buf[sizeof(buf) - 1] = '\0'; -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, -+ (u8 *) buf, os_strlen(buf))) { -+ printf("Could not add Calling-Station-Id\n"); -+ goto fail; -+ } -+ -+ /* TODO: should probably check MTU from driver config; 2304 is max for -+ * IEEE 802.11, but use 1400 to avoid problems with too large packets -+ */ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { -+ printf("Could not add Framed-MTU\n"); -+ goto fail; -+ } -+ -+ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, -+ RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { -+ printf("Could not add NAS-Port-Type\n"); -+ goto fail; -+ } -+ -+ if (sta->flags & WLAN_STA_PREAUTH) { -+ os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", -+ sizeof(buf)); -+ } else { -+ os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", -+ radius_sta_rate(hapd, sta) / 2, -+ (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", -+ radius_mode_txt(hapd)); -+ buf[sizeof(buf) - 1] = '\0'; -+ } -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, -+ (u8 *) buf, os_strlen(buf))) { -+ printf("Could not add Connect-Info\n"); -+ goto fail; -+ } -+ -+ if (eap && !radius_msg_add_eap(msg, eap, len)) { -+ printf("Could not add EAP-Message\n"); -+ goto fail; -+ } -+ -+ /* State attribute must be copied if and only if this packet is -+ * Access-Request reply to the previous Access-Challenge */ -+ if (sm->last_recv_radius && -+ radius_msg_get_hdr(sm->last_recv_radius)->code == -+ RADIUS_CODE_ACCESS_CHALLENGE) { -+ int res = radius_msg_copy_attr(msg, sm->last_recv_radius, -+ RADIUS_ATTR_STATE); -+ if (res < 0) { -+ printf("Could not copy State attribute from previous " -+ "Access-Challenge\n"); -+ goto fail; -+ } -+ if (res > 0) { -+ wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); -+ } -+ } -+ -+ if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) -+ goto fail; -+ -+ return; -+ -+ fail: -+ radius_msg_free(msg); -+} -+#endif /* CONFIG_NO_RADIUS */ -+ -+ -+static void handle_eap_response(struct hostapd_data *hapd, -+ struct sta_info *sta, struct eap_hdr *eap, -+ size_t len) -+{ -+ u8 type, *data; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ if (sm == NULL) -+ return; -+ -+ data = (u8 *) (eap + 1); -+ -+ if (len < sizeof(*eap) + 1) { -+ printf("handle_eap_response: too short response data\n"); -+ return; -+ } -+ -+ sm->eap_type_supp = type = data[0]; -+ -+ hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " -+ "id=%d len=%d) from STA: EAP Response-%s (%d)", -+ eap->code, eap->identifier, be_to_host16(eap->length), -+ eap_server_get_name(0, type), type); -+ -+ sm->dot1xAuthEapolRespFramesRx++; -+ -+ wpabuf_free(sm->eap_if->eapRespData); -+ sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); -+ sm->eapolEap = TRUE; -+} -+ -+ -+/* Process incoming EAP packet from Supplicant */ -+static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, -+ u8 *buf, size_t len) -+{ -+ struct eap_hdr *eap; -+ u16 eap_len; -+ -+ if (len < sizeof(*eap)) { -+ printf(" too short EAP packet\n"); -+ return; -+ } -+ -+ eap = (struct eap_hdr *) buf; -+ -+ eap_len = be_to_host16(eap->length); -+ wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", -+ eap->code, eap->identifier, eap_len); -+ if (eap_len < sizeof(*eap)) { -+ wpa_printf(MSG_DEBUG, " Invalid EAP length"); -+ return; -+ } else if (eap_len > len) { -+ wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " -+ "packet"); -+ return; -+ } else if (eap_len < len) { -+ wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " -+ "packet", (unsigned long) len - eap_len); -+ } -+ -+ switch (eap->code) { -+ case EAP_CODE_REQUEST: -+ wpa_printf(MSG_DEBUG, " (request)"); -+ return; -+ case EAP_CODE_RESPONSE: -+ wpa_printf(MSG_DEBUG, " (response)"); -+ handle_eap_response(hapd, sta, eap, eap_len); -+ break; -+ case EAP_CODE_SUCCESS: -+ wpa_printf(MSG_DEBUG, " (success)"); -+ return; -+ case EAP_CODE_FAILURE: -+ wpa_printf(MSG_DEBUG, " (failure)"); -+ return; -+ default: -+ wpa_printf(MSG_DEBUG, " (unknown code)"); -+ return; -+ } -+} -+ -+ -+static struct eapol_state_machine * -+ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ int flags = 0; -+ if (sta->flags & WLAN_STA_PREAUTH) -+ flags |= EAPOL_SM_PREAUTH; -+ if (sta->wpa_sm) { -+ flags |= EAPOL_SM_USES_WPA; -+ if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) -+ flags |= EAPOL_SM_FROM_PMKSA_CACHE; -+ } -+ return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, -+ sta->wps_ie, sta->p2p_ie, sta); -+} -+ -+ -+/** -+ * ieee802_1x_receive - Process the EAPOL frames from the Supplicant -+ * @hapd: hostapd BSS data -+ * @sa: Source address (sender of the EAPOL frame) -+ * @buf: EAPOL frame -+ * @len: Length of buf in octets -+ * -+ * This function is called for each incoming EAPOL frame from the interface -+ */ -+void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, -+ size_t len) -+{ -+ struct sta_info *sta; -+ struct ieee802_1x_hdr *hdr; -+ struct ieee802_1x_eapol_key *key; -+ u16 datalen; -+ struct rsn_pmksa_cache_entry *pmksa; -+ int key_mgmt; -+ -+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && -+ !hapd->conf->wps_state) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, -+ (unsigned long) len, MAC2STR(sa)); -+ sta = ap_get_sta(hapd, sa); -+ if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " -+ "associated/Pre-authenticating STA"); -+ return; -+ } -+ -+ if (len < sizeof(*hdr)) { -+ printf(" too short IEEE 802.1X packet\n"); -+ return; -+ } -+ -+ hdr = (struct ieee802_1x_hdr *) buf; -+ datalen = be_to_host16(hdr->length); -+ wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", -+ hdr->version, hdr->type, datalen); -+ -+ if (len - sizeof(*hdr) < datalen) { -+ printf(" frame too short for this IEEE 802.1X packet\n"); -+ if (sta->eapol_sm) -+ sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; -+ return; -+ } -+ if (len - sizeof(*hdr) > datalen) { -+ wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " -+ "IEEE 802.1X packet", -+ (unsigned long) len - sizeof(*hdr) - datalen); -+ } -+ -+ if (sta->eapol_sm) { -+ sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; -+ sta->eapol_sm->dot1xAuthEapolFramesRx++; -+ } -+ -+ key = (struct ieee802_1x_eapol_key *) (hdr + 1); -+ if (datalen >= sizeof(struct ieee802_1x_eapol_key) && -+ hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && -+ (key->type == EAPOL_KEY_TYPE_WPA || -+ key->type == EAPOL_KEY_TYPE_RSN)) { -+ wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, -+ sizeof(*hdr) + datalen); -+ return; -+ } -+ -+ if (!hapd->conf->ieee802_1x && -+ !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " -+ "802.1X not enabled and WPS not used"); -+ return; -+ } -+ -+ key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); -+ if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " -+ "STA is using PSK"); -+ return; -+ } -+ -+ if (!sta->eapol_sm) { -+ sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); -+ if (!sta->eapol_sm) -+ return; -+ -+#ifdef CONFIG_WPS -+ if (!hapd->conf->ieee802_1x && -+ ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == -+ WLAN_STA_MAYBE_WPS)) { -+ /* -+ * Delay EAPOL frame transmission until a possible WPS -+ * STA initiates the handshake with EAPOL-Start. -+ */ -+ sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; -+ } -+#endif /* CONFIG_WPS */ -+ -+ sta->eapol_sm->eap_if->portEnabled = TRUE; -+ } -+ -+ /* since we support version 1, we can ignore version field and proceed -+ * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ -+ /* TODO: actually, we are not version 1 anymore.. However, Version 2 -+ * does not change frame contents, so should be ok to process frames -+ * more or less identically. Some changes might be needed for -+ * verification of fields. */ -+ -+ switch (hdr->type) { -+ case IEEE802_1X_TYPE_EAP_PACKET: -+ handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); -+ break; -+ -+ case IEEE802_1X_TYPE_EAPOL_START: -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " -+ "from STA"); -+ sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; -+ pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); -+ if (pmksa) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, -+ HOSTAPD_LEVEL_DEBUG, "cached PMKSA " -+ "available - ignore it since " -+ "STA sent EAPOL-Start"); -+ wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); -+ } -+ sta->eapol_sm->eapolStart = TRUE; -+ sta->eapol_sm->dot1xAuthEapolStartFramesRx++; -+ eap_server_clear_identity(sta->eapol_sm->eap); -+ wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); -+ break; -+ -+ case IEEE802_1X_TYPE_EAPOL_LOGOFF: -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " -+ "from STA"); -+ sta->acct_terminate_cause = -+ RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; -+ accounting_sta_stop(hapd, sta); -+ sta->eapol_sm->eapolLogoff = TRUE; -+ sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; -+ eap_server_clear_identity(sta->eapol_sm->eap); -+ break; -+ -+ case IEEE802_1X_TYPE_EAPOL_KEY: -+ wpa_printf(MSG_DEBUG, " EAPOL-Key"); -+ if (!ap_sta_is_authorized(sta)) { -+ wpa_printf(MSG_DEBUG, " Dropped key data from " -+ "unauthorized Supplicant"); -+ break; -+ } -+ break; -+ -+ case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: -+ wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); -+ /* TODO: implement support for this; show data */ -+ break; -+ -+ default: -+ wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); -+ sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; -+ break; -+ } -+ -+ eapol_auth_step(sta->eapol_sm); -+} -+ -+ -+/** -+ * ieee802_1x_new_station - Start IEEE 802.1X authentication -+ * @hapd: hostapd BSS data -+ * @sta: The station -+ * -+ * This function is called to start IEEE 802.1X authentication when a new -+ * station completes IEEE 802.11 association. -+ */ -+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ struct rsn_pmksa_cache_entry *pmksa; -+ int reassoc = 1; -+ int force_1x = 0; -+ int key_mgmt; -+ -+#ifdef CONFIG_WPS -+ if (hapd->conf->wps_state && hapd->conf->wpa && -+ (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { -+ /* -+ * Need to enable IEEE 802.1X/EAPOL state machines for possible -+ * WPS handshake even if IEEE 802.1X/EAPOL is not used for -+ * authentication in this BSS. -+ */ -+ force_1x = 1; -+ } -+#endif /* CONFIG_WPS */ -+ -+ if (!force_1x && !hapd->conf->ieee802_1x) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " -+ "802.1X not enabled or forced for WPS"); -+ return; -+ } -+ -+ key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); -+ if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); -+ return; -+ } -+ -+ if (sta->eapol_sm == NULL) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "start authentication"); -+ sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); -+ if (sta->eapol_sm == NULL) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_INFO, -+ "failed to allocate state machine"); -+ return; -+ } -+ reassoc = 0; -+ } -+ -+#ifdef CONFIG_WPS -+ sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; -+ if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) { -+ /* -+ * Delay EAPOL frame transmission until a possible WPS -+ * initiates the handshake with EAPOL-Start. -+ */ -+ sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; -+ } -+#endif /* CONFIG_WPS */ -+ -+ sta->eapol_sm->eap_if->portEnabled = TRUE; -+ -+#ifdef CONFIG_IEEE80211R -+ if (sta->auth_alg == WLAN_AUTH_FT) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, -+ "PMK from FT - skip IEEE 802.1X/EAP"); -+ /* Setup EAPOL state machines to already authenticated state -+ * because of existing FT information from R0KH. */ -+ sta->eapol_sm->keyRun = TRUE; -+ sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; -+ sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; -+ sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; -+ sta->eapol_sm->authSuccess = TRUE; -+ if (sta->eapol_sm->eap) -+ eap_sm_notify_cached(sta->eapol_sm->eap); -+ /* TODO: get vlan_id from R0KH using RRB message */ -+ return; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); -+ if (pmksa) { -+ int old_vlanid; -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, -+ "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); -+ /* Setup EAPOL state machines to already authenticated state -+ * because of existing PMKSA information in the cache. */ -+ sta->eapol_sm->keyRun = TRUE; -+ sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; -+ sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; -+ sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; -+ sta->eapol_sm->authSuccess = TRUE; -+ if (sta->eapol_sm->eap) -+ eap_sm_notify_cached(sta->eapol_sm->eap); -+ old_vlanid = sta->vlan_id; -+ pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm); -+ if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) -+ sta->vlan_id = 0; -+ ap_sta_bind_vlan(hapd, sta, old_vlanid); -+ } else { -+ if (reassoc) { -+ /* -+ * Force EAPOL state machines to start -+ * re-authentication without having to wait for the -+ * Supplicant to send EAPOL-Start. -+ */ -+ sta->eapol_sm->reAuthenticate = TRUE; -+ } -+ eapol_auth_step(sta->eapol_sm); -+ } -+} -+ -+ -+void ieee802_1x_free_station(struct sta_info *sta) -+{ -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ if (sm == NULL) -+ return; -+ -+ sta->eapol_sm = NULL; -+ -+#ifndef CONFIG_NO_RADIUS -+ radius_msg_free(sm->last_recv_radius); -+ radius_free_class(&sm->radius_class); -+#endif /* CONFIG_NO_RADIUS */ -+ -+ os_free(sm->identity); -+ eapol_auth_free(sm); -+} -+ -+ -+#ifndef CONFIG_NO_RADIUS -+static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+ u8 *eap; -+ size_t len; -+ struct eap_hdr *hdr; -+ int eap_type = -1; -+ char buf[64]; -+ struct radius_msg *msg; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ if (sm == NULL || sm->last_recv_radius == NULL) { -+ if (sm) -+ sm->eap_if->aaaEapNoReq = TRUE; -+ return; -+ } -+ -+ msg = sm->last_recv_radius; -+ -+ eap = radius_msg_get_eap(msg, &len); -+ if (eap == NULL) { -+ /* RFC 3579, Chap. 2.6.3: -+ * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message -+ * attribute */ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_WARNING, "could not extract " -+ "EAP-Message from RADIUS message"); -+ sm->eap_if->aaaEapNoReq = TRUE; -+ return; -+ } -+ -+ if (len < sizeof(*hdr)) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_WARNING, "too short EAP packet " -+ "received from authentication server"); -+ os_free(eap); -+ sm->eap_if->aaaEapNoReq = TRUE; -+ return; -+ } -+ -+ if (len > sizeof(*hdr)) -+ eap_type = eap[sizeof(*hdr)]; -+ -+ hdr = (struct eap_hdr *) eap; -+ switch (hdr->code) { -+ case EAP_CODE_REQUEST: -+ if (eap_type >= 0) -+ sm->eap_type_authsrv = eap_type; -+ os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", -+ eap_type >= 0 ? eap_server_get_name(0, eap_type) : -+ "??", -+ eap_type); -+ break; -+ case EAP_CODE_RESPONSE: -+ os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", -+ eap_type >= 0 ? eap_server_get_name(0, eap_type) : -+ "??", -+ eap_type); -+ break; -+ case EAP_CODE_SUCCESS: -+ os_strlcpy(buf, "EAP Success", sizeof(buf)); -+ break; -+ case EAP_CODE_FAILURE: -+ os_strlcpy(buf, "EAP Failure", sizeof(buf)); -+ break; -+ default: -+ os_strlcpy(buf, "unknown EAP code", sizeof(buf)); -+ break; -+ } -+ buf[sizeof(buf) - 1] = '\0'; -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " -+ "id=%d len=%d) from RADIUS server: %s", -+ hdr->code, hdr->identifier, be_to_host16(hdr->length), -+ buf); -+ sm->eap_if->aaaEapReq = TRUE; -+ -+ wpabuf_free(sm->eap_if->aaaEapReqData); -+ sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len); -+} -+ -+ -+static void ieee802_1x_get_keys(struct hostapd_data *hapd, -+ struct sta_info *sta, struct radius_msg *msg, -+ struct radius_msg *req, -+ const u8 *shared_secret, -+ size_t shared_secret_len) -+{ -+ struct radius_ms_mppe_keys *keys; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ if (sm == NULL) -+ return; -+ -+ keys = radius_msg_get_ms_keys(msg, req, shared_secret, -+ shared_secret_len); -+ -+ if (keys && keys->send && keys->recv) { -+ size_t len = keys->send_len + keys->recv_len; -+ wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", -+ keys->send, keys->send_len); -+ wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", -+ keys->recv, keys->recv_len); -+ -+ os_free(sm->eap_if->aaaEapKeyData); -+ sm->eap_if->aaaEapKeyData = os_malloc(len); -+ if (sm->eap_if->aaaEapKeyData) { -+ os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, -+ keys->recv_len); -+ os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, -+ keys->send, keys->send_len); -+ sm->eap_if->aaaEapKeyDataLen = len; -+ sm->eap_if->aaaEapKeyAvailable = TRUE; -+ } -+ } -+ -+ if (keys) { -+ os_free(keys->send); -+ os_free(keys->recv); -+ os_free(keys); -+ } -+} -+ -+ -+static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ struct radius_msg *msg) -+{ -+ u8 *class; -+ size_t class_len; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ int count, i; -+ struct radius_attr_data *nclass; -+ size_t nclass_count; -+ -+ if (!hapd->conf->radius->acct_server || hapd->radius == NULL || -+ sm == NULL) -+ return; -+ -+ radius_free_class(&sm->radius_class); -+ count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); -+ if (count <= 0) -+ return; -+ -+ nclass = os_zalloc(count * sizeof(struct radius_attr_data)); -+ if (nclass == NULL) -+ return; -+ -+ nclass_count = 0; -+ -+ class = NULL; -+ for (i = 0; i < count; i++) { -+ do { -+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, -+ &class, &class_len, -+ class) < 0) { -+ i = count; -+ break; -+ } -+ } while (class_len < 1); -+ -+ nclass[nclass_count].data = os_malloc(class_len); -+ if (nclass[nclass_count].data == NULL) -+ break; -+ -+ os_memcpy(nclass[nclass_count].data, class, class_len); -+ nclass[nclass_count].len = class_len; -+ nclass_count++; -+ } -+ -+ sm->radius_class.attr = nclass; -+ sm->radius_class.count = nclass_count; -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " -+ "attributes for " MACSTR, -+ (unsigned long) sm->radius_class.count, -+ MAC2STR(sta->addr)); -+} -+ -+ -+/* Update sta->identity based on User-Name attribute in Access-Accept */ -+static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ struct radius_msg *msg) -+{ -+ u8 *buf, *identity; -+ size_t len; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ if (sm == NULL) -+ return; -+ -+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, -+ NULL) < 0) -+ return; -+ -+ identity = os_malloc(len + 1); -+ if (identity == NULL) -+ return; -+ -+ os_memcpy(identity, buf, len); -+ identity[len] = '\0'; -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " -+ "User-Name from Access-Accept '%s'", -+ sm->identity ? (char *) sm->identity : "N/A", -+ (char *) identity); -+ -+ os_free(sm->identity); -+ sm->identity = identity; -+ sm->identity_len = len; -+} -+ -+ -+struct sta_id_search { -+ u8 identifier; -+ struct eapol_state_machine *sm; -+}; -+ -+ -+static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ void *ctx) -+{ -+ struct sta_id_search *id_search = ctx; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ if (sm && sm->radius_identifier >= 0 && -+ sm->radius_identifier == id_search->identifier) { -+ id_search->sm = sm; -+ return 1; -+ } -+ return 0; -+} -+ -+ -+static struct eapol_state_machine * -+ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) -+{ -+ struct sta_id_search id_search; -+ id_search.identifier = identifier; -+ id_search.sm = NULL; -+ ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); -+ return id_search.sm; -+} -+ -+ -+/** -+ * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server -+ * @msg: RADIUS response message -+ * @req: RADIUS request message -+ * @shared_secret: RADIUS shared secret -+ * @shared_secret_len: Length of shared_secret in octets -+ * @data: Context data (struct hostapd_data *) -+ * Returns: Processing status -+ */ -+static RadiusRxResult -+ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, -+ const u8 *shared_secret, size_t shared_secret_len, -+ void *data) -+{ -+ struct hostapd_data *hapd = data; -+ struct sta_info *sta; -+ u32 session_timeout = 0, termination_action, acct_interim_interval; -+ int session_timeout_set, old_vlanid = 0; -+ struct eapol_state_machine *sm; -+ int override_eapReq = 0; -+ struct radius_hdr *hdr = radius_msg_get_hdr(msg); -+ -+ sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); -+ if (sm == NULL) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " -+ "station for this RADIUS message"); -+ return RADIUS_RX_UNKNOWN; -+ } -+ sta = sm->sta; -+ -+ /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be -+ * present when packet contains an EAP-Message attribute */ -+ if (hdr->code == RADIUS_CODE_ACCESS_REJECT && -+ radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, -+ 0) < 0 && -+ radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { -+ wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " -+ "Message-Authenticator since it does not include " -+ "EAP-Message"); -+ } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, -+ req, 1)) { -+ printf("Incoming RADIUS packet did not have correct " -+ "Message-Authenticator - dropped\n"); -+ return RADIUS_RX_INVALID_AUTHENTICATOR; -+ } -+ -+ if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && -+ hdr->code != RADIUS_CODE_ACCESS_REJECT && -+ hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { -+ printf("Unknown RADIUS message code\n"); -+ return RADIUS_RX_UNKNOWN; -+ } -+ -+ sm->radius_identifier = -1; -+ wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, -+ MAC2STR(sta->addr)); -+ -+ radius_msg_free(sm->last_recv_radius); -+ sm->last_recv_radius = msg; -+ -+ session_timeout_set = -+ !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, -+ &session_timeout); -+ if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, -+ &termination_action)) -+ termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; -+ -+ if (hapd->conf->acct_interim_interval == 0 && -+ hdr->code == RADIUS_CODE_ACCESS_ACCEPT && -+ radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, -+ &acct_interim_interval) == 0) { -+ if (acct_interim_interval < 60) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_INFO, -+ "ignored too small " -+ "Acct-Interim-Interval %d", -+ acct_interim_interval); -+ } else -+ sta->acct_interim_interval = acct_interim_interval; -+ } -+ -+ -+ switch (hdr->code) { -+ case RADIUS_CODE_ACCESS_ACCEPT: -+ if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) -+ sta->vlan_id = 0; -+#ifndef CONFIG_NO_VLAN -+ else { -+ old_vlanid = sta->vlan_id; -+ sta->vlan_id = radius_msg_get_vlanid(msg); -+ } -+ if (sta->vlan_id > 0 && -+ hostapd_get_vlan_id_ifname(hapd->conf->vlan, -+ sta->vlan_id)) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, -+ "VLAN ID %d", sta->vlan_id); -+ } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) { -+ sta->eapol_sm->authFail = TRUE; -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_INFO, "authentication " -+ "server did not include required VLAN " -+ "ID in Access-Accept"); -+ break; -+ } -+#endif /* CONFIG_NO_VLAN */ -+ -+ if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) -+ break; -+ -+ /* RFC 3580, Ch. 3.17 */ -+ if (session_timeout_set && termination_action == -+ RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) { -+ sm->reAuthPeriod = session_timeout; -+ } else if (session_timeout_set) -+ ap_sta_session_timeout(hapd, sta, session_timeout); -+ -+ sm->eap_if->aaaSuccess = TRUE; -+ override_eapReq = 1; -+ ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, -+ shared_secret_len); -+ ieee802_1x_store_radius_class(hapd, sta, msg); -+ ieee802_1x_update_sta_identity(hapd, sta, msg); -+ if (sm->eap_if->eapKeyAvailable && -+ wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt, -+ session_timeout_set ? -+ (int) session_timeout : -1, sm) == 0) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, -+ HOSTAPD_LEVEL_DEBUG, -+ "Added PMKSA cache entry"); -+ } -+ break; -+ case RADIUS_CODE_ACCESS_REJECT: -+ sm->eap_if->aaaFail = TRUE; -+ override_eapReq = 1; -+ break; -+ case RADIUS_CODE_ACCESS_CHALLENGE: -+ sm->eap_if->aaaEapReq = TRUE; -+ if (session_timeout_set) { -+ /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ -+ sm->eap_if->aaaMethodTimeout = session_timeout; -+ hostapd_logger(hapd, sm->addr, -+ HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, -+ "using EAP timeout of %d seconds (from " -+ "RADIUS)", -+ sm->eap_if->aaaMethodTimeout); -+ } else { -+ /* -+ * Use dynamic retransmission behavior per EAP -+ * specification. -+ */ -+ sm->eap_if->aaaMethodTimeout = 0; -+ } -+ break; -+ } -+ -+ ieee802_1x_decapsulate_radius(hapd, sta); -+ if (override_eapReq) -+ sm->eap_if->aaaEapReq = FALSE; -+ -+ eapol_auth_step(sm); -+ -+ return RADIUS_RX_QUEUED; -+} -+#endif /* CONFIG_NO_RADIUS */ -+ -+ -+void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ if (sm == NULL) -+ return; -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "aborting authentication"); -+ -+#ifndef CONFIG_NO_RADIUS -+ radius_msg_free(sm->last_recv_radius); -+ sm->last_recv_radius = NULL; -+#endif /* CONFIG_NO_RADIUS */ -+ -+ if (sm->eap_if->eapTimeout) { -+ /* -+ * Disconnect the STA since it did not reply to the last EAP -+ * request and we cannot continue EAP processing (EAP-Failure -+ * could only be sent if the EAP peer actually replied). -+ */ -+ sm->eap_if->portEnabled = FALSE; -+ ap_sta_disconnect(hapd, sta, sta->addr, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ } -+} -+ -+ -+static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) -+{ -+ struct eapol_authenticator *eapol = hapd->eapol_auth; -+ -+ if (hapd->conf->default_wep_key_len < 1) -+ return 0; -+ -+ os_free(eapol->default_wep_key); -+ eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); -+ if (eapol->default_wep_key == NULL || -+ random_get_bytes(eapol->default_wep_key, -+ hapd->conf->default_wep_key_len)) { -+ printf("Could not generate random WEP key.\n"); -+ os_free(eapol->default_wep_key); -+ eapol->default_wep_key = NULL; -+ return -1; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", -+ eapol->default_wep_key, -+ hapd->conf->default_wep_key_len); -+ -+ return 0; -+} -+ -+ -+static int ieee802_1x_sta_key_available(struct hostapd_data *hapd, -+ struct sta_info *sta, void *ctx) -+{ -+ if (sta->eapol_sm) { -+ sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; -+ eapol_auth_step(sta->eapol_sm); -+ } -+ return 0; -+} -+ -+ -+static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ struct eapol_authenticator *eapol = hapd->eapol_auth; -+ -+ if (eapol->default_wep_key_idx >= 3) -+ eapol->default_wep_key_idx = -+ hapd->conf->individual_wep_key_len > 0 ? 1 : 0; -+ else -+ eapol->default_wep_key_idx++; -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", -+ eapol->default_wep_key_idx); -+ -+ if (ieee802_1x_rekey_broadcast(hapd)) { -+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_WARNING, "failed to generate a " -+ "new broadcast key"); -+ os_free(eapol->default_wep_key); -+ eapol->default_wep_key = NULL; -+ return; -+ } -+ -+ /* TODO: Could setup key for RX here, but change default TX keyid only -+ * after new broadcast key has been sent to all stations. */ -+ if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, -+ broadcast_ether_addr, -+ eapol->default_wep_key_idx, 1, NULL, 0, -+ eapol->default_wep_key, -+ hapd->conf->default_wep_key_len)) { -+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_WARNING, "failed to configure a " -+ "new broadcast key"); -+ os_free(eapol->default_wep_key); -+ eapol->default_wep_key = NULL; -+ return; -+ } -+ -+ ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); -+ -+ if (hapd->conf->wep_rekeying_period > 0) { -+ eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, -+ ieee802_1x_rekey, hapd, NULL); -+ } -+} -+ -+ -+static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, -+ const u8 *data, size_t datalen) -+{ -+#ifdef CONFIG_WPS -+ struct sta_info *sta = sta_ctx; -+ -+ if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == -+ WLAN_STA_MAYBE_WPS) { -+ const u8 *identity; -+ size_t identity_len; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ identity = eap_get_identity(sm->eap, &identity_len); -+ if (identity && -+ ((identity_len == WSC_ID_ENROLLEE_LEN && -+ os_memcmp(identity, WSC_ID_ENROLLEE, -+ WSC_ID_ENROLLEE_LEN) == 0) || -+ (identity_len == WSC_ID_REGISTRAR_LEN && -+ os_memcmp(identity, WSC_ID_REGISTRAR, -+ WSC_ID_REGISTRAR_LEN) == 0))) { -+ wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " -+ "WLAN_STA_WPS"); -+ sta->flags |= WLAN_STA_WPS; -+ } -+ } -+#endif /* CONFIG_WPS */ -+ -+ ieee802_1x_send(ctx, sta_ctx, type, data, datalen); -+} -+ -+ -+static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, -+ const u8 *data, size_t datalen) -+{ -+#ifndef CONFIG_NO_RADIUS -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta = sta_ctx; -+ -+ ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); -+#endif /* CONFIG_NO_RADIUS */ -+} -+ -+ -+static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, -+ int preauth) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta = sta_ctx; -+ if (preauth) -+ rsn_preauth_finished(hapd, sta, success); -+ else -+ ieee802_1x_finished(hapd, sta, success); -+} -+ -+ -+static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, -+ size_t identity_len, int phase2, -+ struct eap_user *user) -+{ -+ struct hostapd_data *hapd = ctx; -+ const struct hostapd_eap_user *eap_user; -+ int i, count; -+ -+ eap_user = hostapd_get_eap_user(hapd->conf, identity, -+ identity_len, phase2); -+ if (eap_user == NULL) -+ return -1; -+ -+ os_memset(user, 0, sizeof(*user)); -+ user->phase2 = phase2; -+ count = EAP_USER_MAX_METHODS; -+ if (count > EAP_MAX_METHODS) -+ count = EAP_MAX_METHODS; -+ for (i = 0; i < count; i++) { -+ user->methods[i].vendor = eap_user->methods[i].vendor; -+ user->methods[i].method = eap_user->methods[i].method; -+ } -+ -+ if (eap_user->password) { -+ user->password = os_malloc(eap_user->password_len); -+ if (user->password == NULL) -+ return -1; -+ os_memcpy(user->password, eap_user->password, -+ eap_user->password_len); -+ user->password_len = eap_user->password_len; -+ } -+ user->force_version = eap_user->force_version; -+ user->ttls_auth = eap_user->ttls_auth; -+ -+ return 0; -+} -+ -+ -+static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta; -+ sta = ap_get_sta(hapd, addr); -+ if (sta == NULL || sta->eapol_sm == NULL) -+ return 0; -+ return 1; -+} -+ -+ -+static void ieee802_1x_logger(void *ctx, const u8 *addr, -+ eapol_logger_level level, const char *txt) -+{ -+#ifndef CONFIG_NO_HOSTAPD_LOGGER -+ struct hostapd_data *hapd = ctx; -+ int hlevel; -+ -+ switch (level) { -+ case EAPOL_LOGGER_WARNING: -+ hlevel = HOSTAPD_LEVEL_WARNING; -+ break; -+ case EAPOL_LOGGER_INFO: -+ hlevel = HOSTAPD_LEVEL_INFO; -+ break; -+ case EAPOL_LOGGER_DEBUG: -+ default: -+ hlevel = HOSTAPD_LEVEL_DEBUG; -+ break; -+ } -+ -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", -+ txt); -+#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -+} -+ -+ -+static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, -+ int authorized) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta = sta_ctx; -+ ieee802_1x_set_sta_authorized(hapd, sta, authorized); -+} -+ -+ -+static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta = sta_ctx; -+ ieee802_1x_abort_auth(hapd, sta); -+} -+ -+ -+static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta = sta_ctx; -+ ieee802_1x_tx_key(hapd, sta); -+} -+ -+ -+static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, -+ enum eapol_event type) -+{ -+ /* struct hostapd_data *hapd = ctx; */ -+ struct sta_info *sta = sta_ctx; -+ switch (type) { -+ case EAPOL_AUTH_SM_CHANGE: -+ wpa_auth_sm_notify(sta->wpa_sm); -+ break; -+ case EAPOL_AUTH_REAUTHENTICATE: -+ wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); -+ break; -+ } -+} -+ -+ -+int ieee802_1x_init(struct hostapd_data *hapd) -+{ -+ int i; -+ struct eapol_auth_config conf; -+ struct eapol_auth_cb cb; -+ -+ os_memset(&conf, 0, sizeof(conf)); -+ conf.ctx = hapd; -+ conf.eap_reauth_period = hapd->conf->eap_reauth_period; -+ conf.wpa = hapd->conf->wpa; -+ conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; -+ conf.eap_server = hapd->conf->eap_server; -+ conf.ssl_ctx = hapd->ssl_ctx; -+ conf.msg_ctx = hapd->msg_ctx; -+ conf.eap_sim_db_priv = hapd->eap_sim_db_priv; -+ conf.eap_req_id_text = hapd->conf->eap_req_id_text; -+ conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; -+ conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; -+ conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; -+ conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; -+ conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; -+ conf.eap_fast_prov = hapd->conf->eap_fast_prov; -+ conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; -+ conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; -+ conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; -+ conf.tnc = hapd->conf->tnc; -+ conf.wps = hapd->wps; -+ conf.fragment_size = hapd->conf->fragment_size; -+ conf.pwd_group = hapd->conf->pwd_group; -+ -+ os_memset(&cb, 0, sizeof(cb)); -+ cb.eapol_send = ieee802_1x_eapol_send; -+ cb.aaa_send = ieee802_1x_aaa_send; -+ cb.finished = _ieee802_1x_finished; -+ cb.get_eap_user = ieee802_1x_get_eap_user; -+ cb.sta_entry_alive = ieee802_1x_sta_entry_alive; -+ cb.logger = ieee802_1x_logger; -+ cb.set_port_authorized = ieee802_1x_set_port_authorized; -+ cb.abort_auth = _ieee802_1x_abort_auth; -+ cb.tx_key = _ieee802_1x_tx_key; -+ cb.eapol_event = ieee802_1x_eapol_event; -+ -+ hapd->eapol_auth = eapol_auth_init(&conf, &cb); -+ if (hapd->eapol_auth == NULL) -+ return -1; -+ -+ if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && -+ hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) -+ return -1; -+ -+#ifndef CONFIG_NO_RADIUS -+ if (radius_client_register(hapd->radius, RADIUS_AUTH, -+ ieee802_1x_receive_auth, hapd)) -+ return -1; -+#endif /* CONFIG_NO_RADIUS */ -+ -+ if (hapd->conf->default_wep_key_len) { -+ for (i = 0; i < 4; i++) -+ hostapd_drv_set_key(hapd->conf->iface, hapd, -+ WPA_ALG_NONE, NULL, i, 0, NULL, 0, -+ NULL, 0); -+ -+ ieee802_1x_rekey(hapd, NULL); -+ -+ if (hapd->eapol_auth->default_wep_key == NULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void ieee802_1x_deinit(struct hostapd_data *hapd) -+{ -+ eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); -+ -+ if (hapd->driver != NULL && -+ (hapd->conf->ieee802_1x || hapd->conf->wpa)) -+ hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); -+ -+ eapol_auth_deinit(hapd->eapol_auth); -+ hapd->eapol_auth = NULL; -+} -+ -+ -+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *buf, size_t len, int ack) -+{ -+ struct ieee80211_hdr *hdr; -+ struct ieee802_1x_hdr *xhdr; -+ struct ieee802_1x_eapol_key *key; -+ u8 *pos; -+ const unsigned char rfc1042_hdr[ETH_ALEN] = -+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -+ -+ if (sta == NULL) -+ return -1; -+ if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr)) -+ return 0; -+ -+ hdr = (struct ieee80211_hdr *) buf; -+ pos = (u8 *) (hdr + 1); -+ if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) -+ return 0; -+ pos += sizeof(rfc1042_hdr); -+ if (WPA_GET_BE16(pos) != ETH_P_PAE) -+ return 0; -+ pos += 2; -+ -+ xhdr = (struct ieee802_1x_hdr *) pos; -+ pos += sizeof(*xhdr); -+ -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " -+ "type=%d length=%d - ack=%d", -+ MAC2STR(sta->addr), xhdr->version, xhdr->type, -+ be_to_host16(xhdr->length), ack); -+ -+ if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && -+ pos + sizeof(struct wpa_eapol_key) <= buf + len) { -+ const struct wpa_eapol_key *wpa; -+ wpa = (const struct wpa_eapol_key *) pos; -+ if (wpa->type == EAPOL_KEY_TYPE_RSN || -+ wpa->type == EAPOL_KEY_TYPE_WPA) -+ wpa_auth_eapol_key_tx_status(hapd->wpa_auth, -+ sta->wpa_sm, ack); -+ } -+ -+ /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant -+ * or Authenticator state machines, but EAPOL-Key packets are not -+ * retransmitted in case of failure. Try to re-sent failed EAPOL-Key -+ * packets couple of times because otherwise STA keys become -+ * unsynchronized with AP. */ -+ if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack && -+ pos + sizeof(*key) <= buf + len) { -+ key = (struct ieee802_1x_eapol_key *) pos; -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, -+ HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " -+ "frame (%scast index=%d)", -+ key->key_index & BIT(7) ? "uni" : "broad", -+ key->key_index & ~BIT(7)); -+ /* TODO: re-send EAPOL-Key couple of times (with short delay -+ * between them?). If all attempt fail, report error and -+ * deauthenticate STA so that it will get new keys when -+ * authenticating again (e.g., after returning in range). -+ * Separate limit/transmit state needed both for unicast and -+ * broadcast keys(?) */ -+ } -+ /* TODO: could move unicast key configuration from ieee802_1x_tx_key() -+ * to here and change the key only if the EAPOL-Key packet was Acked. -+ */ -+ -+ return 1; -+} -+ -+ -+u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) -+{ -+ if (sm == NULL || sm->identity == NULL) -+ return NULL; -+ -+ *len = sm->identity_len; -+ return sm->identity; -+} -+ -+ -+u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, -+ int idx) -+{ -+ if (sm == NULL || sm->radius_class.attr == NULL || -+ idx >= (int) sm->radius_class.count) -+ return NULL; -+ -+ *len = sm->radius_class.attr[idx].len; -+ return sm->radius_class.attr[idx].data; -+} -+ -+ -+const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) -+{ -+ if (sm == NULL) -+ return NULL; -+ -+ *len = sm->eap_if->eapKeyDataLen; -+ return sm->eap_if->eapKeyData; -+} -+ -+ -+void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, -+ int enabled) -+{ -+ if (sm == NULL) -+ return; -+ sm->eap_if->portEnabled = enabled ? TRUE : FALSE; -+ eapol_auth_step(sm); -+} -+ -+ -+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, -+ int valid) -+{ -+ if (sm == NULL) -+ return; -+ sm->portValid = valid ? TRUE : FALSE; -+ eapol_auth_step(sm); -+} -+ -+ -+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) -+{ -+ if (sm == NULL) -+ return; -+ if (pre_auth) -+ sm->flags |= EAPOL_SM_PREAUTH; -+ else -+ sm->flags &= ~EAPOL_SM_PREAUTH; -+} -+ -+ -+static const char * bool_txt(Boolean bool) -+{ -+ return bool ? "TRUE" : "FALSE"; -+} -+ -+ -+int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) -+{ -+ /* TODO */ -+ return 0; -+} -+ -+ -+int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ char *buf, size_t buflen) -+{ -+ int len = 0, ret; -+ struct eapol_state_machine *sm = sta->eapol_sm; -+ -+ if (sm == NULL) -+ return 0; -+ -+ ret = os_snprintf(buf + len, buflen - len, -+ "dot1xPaePortNumber=%d\n" -+ "dot1xPaePortProtocolVersion=%d\n" -+ "dot1xPaePortCapabilities=1\n" -+ "dot1xPaePortInitialize=%d\n" -+ "dot1xPaePortReauthenticate=FALSE\n", -+ sta->aid, -+ EAPOL_VERSION, -+ sm->initialize); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ /* dot1xAuthConfigTable */ -+ ret = os_snprintf(buf + len, buflen - len, -+ "dot1xAuthPaeState=%d\n" -+ "dot1xAuthBackendAuthState=%d\n" -+ "dot1xAuthAdminControlledDirections=%d\n" -+ "dot1xAuthOperControlledDirections=%d\n" -+ "dot1xAuthAuthControlledPortStatus=%d\n" -+ "dot1xAuthAuthControlledPortControl=%d\n" -+ "dot1xAuthQuietPeriod=%u\n" -+ "dot1xAuthServerTimeout=%u\n" -+ "dot1xAuthReAuthPeriod=%u\n" -+ "dot1xAuthReAuthEnabled=%s\n" -+ "dot1xAuthKeyTxEnabled=%s\n", -+ sm->auth_pae_state + 1, -+ sm->be_auth_state + 1, -+ sm->adminControlledDirections, -+ sm->operControlledDirections, -+ sm->authPortStatus, -+ sm->portControl, -+ sm->quietPeriod, -+ sm->serverTimeout, -+ sm->reAuthPeriod, -+ bool_txt(sm->reAuthEnabled), -+ bool_txt(sm->keyTxEnabled)); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ /* dot1xAuthStatsTable */ -+ ret = os_snprintf(buf + len, buflen - len, -+ "dot1xAuthEapolFramesRx=%u\n" -+ "dot1xAuthEapolFramesTx=%u\n" -+ "dot1xAuthEapolStartFramesRx=%u\n" -+ "dot1xAuthEapolLogoffFramesRx=%u\n" -+ "dot1xAuthEapolRespIdFramesRx=%u\n" -+ "dot1xAuthEapolRespFramesRx=%u\n" -+ "dot1xAuthEapolReqIdFramesTx=%u\n" -+ "dot1xAuthEapolReqFramesTx=%u\n" -+ "dot1xAuthInvalidEapolFramesRx=%u\n" -+ "dot1xAuthEapLengthErrorFramesRx=%u\n" -+ "dot1xAuthLastEapolFrameVersion=%u\n" -+ "dot1xAuthLastEapolFrameSource=" MACSTR "\n", -+ sm->dot1xAuthEapolFramesRx, -+ sm->dot1xAuthEapolFramesTx, -+ sm->dot1xAuthEapolStartFramesRx, -+ sm->dot1xAuthEapolLogoffFramesRx, -+ sm->dot1xAuthEapolRespIdFramesRx, -+ sm->dot1xAuthEapolRespFramesRx, -+ sm->dot1xAuthEapolReqIdFramesTx, -+ sm->dot1xAuthEapolReqFramesTx, -+ sm->dot1xAuthInvalidEapolFramesRx, -+ sm->dot1xAuthEapLengthErrorFramesRx, -+ sm->dot1xAuthLastEapolFrameVersion, -+ MAC2STR(sm->addr)); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ /* dot1xAuthDiagTable */ -+ ret = os_snprintf(buf + len, buflen - len, -+ "dot1xAuthEntersConnecting=%u\n" -+ "dot1xAuthEapLogoffsWhileConnecting=%u\n" -+ "dot1xAuthEntersAuthenticating=%u\n" -+ "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" -+ "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" -+ "dot1xAuthAuthFailWhileAuthenticating=%u\n" -+ "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" -+ "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" -+ "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" -+ "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" -+ "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" -+ "dot1xAuthBackendResponses=%u\n" -+ "dot1xAuthBackendAccessChallenges=%u\n" -+ "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" -+ "dot1xAuthBackendAuthSuccesses=%u\n" -+ "dot1xAuthBackendAuthFails=%u\n", -+ sm->authEntersConnecting, -+ sm->authEapLogoffsWhileConnecting, -+ sm->authEntersAuthenticating, -+ sm->authAuthSuccessesWhileAuthenticating, -+ sm->authAuthTimeoutsWhileAuthenticating, -+ sm->authAuthFailWhileAuthenticating, -+ sm->authAuthEapStartsWhileAuthenticating, -+ sm->authAuthEapLogoffWhileAuthenticating, -+ sm->authAuthReauthsWhileAuthenticated, -+ sm->authAuthEapStartsWhileAuthenticated, -+ sm->authAuthEapLogoffWhileAuthenticated, -+ sm->backendResponses, -+ sm->backendAccessChallenges, -+ sm->backendOtherRequestsToSupplicant, -+ sm->backendAuthSuccesses, -+ sm->backendAuthFails); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ /* dot1xAuthSessionStatsTable */ -+ ret = os_snprintf(buf + len, buflen - len, -+ /* TODO: dot1xAuthSessionOctetsRx */ -+ /* TODO: dot1xAuthSessionOctetsTx */ -+ /* TODO: dot1xAuthSessionFramesRx */ -+ /* TODO: dot1xAuthSessionFramesTx */ -+ "dot1xAuthSessionId=%08X-%08X\n" -+ "dot1xAuthSessionAuthenticMethod=%d\n" -+ "dot1xAuthSessionTime=%u\n" -+ "dot1xAuthSessionTerminateCause=999\n" -+ "dot1xAuthSessionUserName=%s\n", -+ sta->acct_session_id_hi, sta->acct_session_id_lo, -+ (wpa_key_mgmt_wpa_ieee8021x( -+ wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? -+ 1 : 2, -+ (unsigned int) (time(NULL) - -+ sta->acct_session_start), -+ sm->identity); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ return len; -+} -+ -+ -+static void ieee802_1x_finished(struct hostapd_data *hapd, -+ struct sta_info *sta, int success) -+{ -+ const u8 *key; -+ size_t len; -+ /* TODO: get PMKLifetime from WPA parameters */ -+ static const int dot11RSNAConfigPMKLifetime = 43200; -+ -+ key = ieee802_1x_get_key(sta->eapol_sm, &len); -+ if (success && key && len >= PMK_LEN && -+ wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime, -+ sta->eapol_sm) == 0) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, -+ HOSTAPD_LEVEL_DEBUG, -+ "Added PMKSA cache entry (IEEE 802.1X)"); -+ } -+ -+#ifdef CONFIG_WPS -+ if (!success && (sta->flags & WLAN_STA_WPS)) { -+ /* -+ * Many devices require deauthentication after WPS provisioning -+ * and some may not be be able to do that themselves, so -+ * disconnect the client here. -+ */ -+ wpa_printf(MSG_DEBUG, "WPS: Force disconnection after " -+ "EAP-Failure"); -+ /* Add a small sleep to increase likelihood of previously -+ * requested EAP-Failure TX getting out before this should the -+ * driver reorder operations. -+ */ -+ os_sleep(0, 10000); -+ ap_sta_disconnect(hapd, sta, sta->addr, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ } -+#endif /* CONFIG_WPS */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.h -new file mode 100644 -index 0000000000000..1a4d2eb0f2c10 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/ieee802_1x.h -@@ -0,0 +1,89 @@ -+/* -+ * hostapd / IEEE 802.1X-2004 Authenticator -+ * Copyright (c) 2002-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IEEE802_1X_H -+#define IEEE802_1X_H -+ -+struct hostapd_data; -+struct sta_info; -+struct eapol_state_machine; -+struct hostapd_config; -+struct hostapd_bss_config; -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+/* RFC 3580, 4. RC4 EAPOL-Key Frame */ -+ -+struct ieee802_1x_eapol_key { -+ u8 type; -+ u16 key_length; -+ u8 replay_counter[8]; /* does not repeat within the life of the keying -+ * material used to encrypt the Key field; -+ * 64-bit NTP timestamp MAY be used here */ -+ u8 key_iv[16]; /* cryptographically random number */ -+ u8 key_index; /* key flag in the most significant bit: -+ * 0 = broadcast (default key), -+ * 1 = unicast (key mapping key); key index is in the -+ * 7 least significant bits */ -+ u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with -+ * MS-MPPE-Send-Key as the key */ -+ -+ /* followed by key: if packet body length = 44 + key length, then the -+ * key field (of key_length bytes) contains the key in encrypted form; -+ * if packet body length = 44, key field is absent and key_length -+ * represents the number of least significant octets from -+ * MS-MPPE-Send-Key attribute to be used as the keying material; -+ * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */ -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, -+ size_t len); -+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta); -+void ieee802_1x_free_station(struct sta_info *sta); -+ -+void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta); -+void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta); -+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, -+ struct sta_info *sta, int authorized); -+void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta); -+int ieee802_1x_init(struct hostapd_data *hapd); -+void ieee802_1x_deinit(struct hostapd_data *hapd); -+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *buf, size_t len, int ack); -+u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len); -+u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, -+ int idx); -+const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len); -+void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, -+ int enabled); -+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, -+ int valid); -+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth); -+int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen); -+int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ char *buf, size_t buflen); -+void hostapd_get_ntp_timestamp(u8 *buf); -+char *eap_type_text(u8 type); -+ -+const char *radius_mode_txt(struct hostapd_data *hapd); -+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta); -+ -+#endif /* IEEE802_1X_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.c -new file mode 100644 -index 0000000000000..6f8b778b55b1a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.c -@@ -0,0 +1,120 @@ -+/* -+ * hostapd / P2P integration -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "p2p/p2p.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ap_drv_ops.h" -+#include "sta_info.h" -+#include "p2p_hostapd.h" -+ -+ -+#ifdef CONFIG_P2P -+ -+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ char *buf, size_t buflen) -+{ -+ if (sta->p2p_ie == NULL) -+ return 0; -+ -+ return p2p_ie_text(sta->p2p_ie, buf, buf + buflen); -+} -+ -+ -+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start, -+ int duration) -+{ -+ wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d " -+ "duration=%d", count, start, duration); -+ -+ if (count == 0) { -+ hapd->noa_enabled = 0; -+ hapd->noa_start = 0; -+ hapd->noa_duration = 0; -+ } -+ -+ if (count != 255) { -+ wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set " -+ "NoA parameters"); -+ return hostapd_driver_set_noa(hapd, count, start, duration); -+ } -+ -+ hapd->noa_enabled = 1; -+ hapd->noa_start = start; -+ hapd->noa_duration = duration; -+ -+ if (hapd->num_sta_no_p2p == 0) { -+ wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update " -+ "periodic NoA parameters"); -+ return hostapd_driver_set_noa(hapd, count, start, duration); -+ } -+ -+ wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable " -+ "periodic NoA"); -+ -+ return 0; -+} -+ -+ -+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd) -+{ -+ wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected"); -+ -+ if (hapd->noa_enabled) { -+ wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA"); -+ hostapd_driver_set_noa(hapd, 0, 0, 0); -+ } -+} -+ -+ -+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd) -+{ -+ wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected"); -+ -+ if (hapd->noa_enabled) { -+ wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA"); -+ hostapd_driver_set_noa(hapd, 255, hapd->noa_start, -+ hapd->noa_duration); -+ } -+} -+ -+#endif /* CONFIG_P2P */ -+ -+ -+#ifdef CONFIG_P2P_MANAGER -+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid) -+{ -+ u8 bitmap; -+ *eid++ = WLAN_EID_VENDOR_SPECIFIC; -+ *eid++ = 4 + 3 + 1; -+ WPA_PUT_BE24(eid, OUI_WFA); -+ eid += 3; -+ *eid++ = P2P_OUI_TYPE; -+ -+ *eid++ = P2P_ATTR_MANAGEABILITY; -+ WPA_PUT_LE16(eid, 1); -+ eid += 2; -+ bitmap = P2P_MAN_DEVICE_MANAGEMENT; -+ if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION) -+ bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED; -+ bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL; -+ *eid++ = bitmap; -+ -+ return eid; -+} -+#endif /* CONFIG_P2P_MANAGER */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.h -new file mode 100644 -index 0000000000000..95b31d9bf1282 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/p2p_hostapd.h -@@ -0,0 +1,41 @@ -+/* -+ * hostapd / P2P integration -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef P2P_HOSTAPD_H -+#define P2P_HOSTAPD_H -+ -+#ifdef CONFIG_P2P -+ -+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, -+ char *buf, size_t buflen); -+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start, -+ int duration); -+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd); -+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd); -+ -+ -+#else /* CONFIG_P2P */ -+ -+static inline int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ char *buf, size_t buflen) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_P2P */ -+ -+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid); -+ -+#endif /* P2P_HOSTAPD_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/peerkey_auth.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/peerkey_auth.c -new file mode 100644 -index 0000000000000..b8fa5a9023a2e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/peerkey_auth.c -@@ -0,0 +1,402 @@ -+/* -+ * hostapd - PeerKey for Direct Link Setup (DLS) -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "crypto/sha1.h" -+#include "crypto/sha256.h" -+#include "crypto/random.h" -+#include "wpa_auth.h" -+#include "wpa_auth_i.h" -+#include "wpa_auth_ie.h" -+ -+#ifdef CONFIG_PEERKEY -+ -+static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx) -+{ -+#if 0 -+ struct wpa_authenticator *wpa_auth = eloop_ctx; -+ struct wpa_stsl_negotiation *neg = timeout_ctx; -+#endif -+ -+ /* TODO: ? */ -+} -+ -+ -+struct wpa_stsl_search { -+ const u8 *addr; -+ struct wpa_state_machine *sm; -+}; -+ -+ -+static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx) -+{ -+ struct wpa_stsl_search *search = ctx; -+ if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) { -+ search->sm = sm; -+ return 1; -+ } -+ return 0; -+} -+ -+ -+static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, const u8 *peer, -+ u16 mui, u16 error_type) -+{ -+ u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN + -+ 2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)]; -+ u8 *pos; -+ struct rsn_error_kde error; -+ -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "Sending SMK Error"); -+ -+ pos = kde; -+ -+ if (peer) { -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, -+ NULL, 0); -+ } -+ -+ error.mui = host_to_be16(mui); -+ error.error_type = host_to_be16(error_type); -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR, -+ (u8 *) &error, sizeof(error), NULL, 0); -+ -+ __wpa_send_eapol(wpa_auth, sm, -+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR, -+ NULL, NULL, kde, pos - kde, 0, 0, 0); -+} -+ -+ -+void wpa_smk_m1(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, struct wpa_eapol_key *key) -+{ -+ struct wpa_eapol_ie_parse kde; -+ struct wpa_stsl_search search; -+ u8 *buf, *pos; -+ size_t buf_len; -+ -+ if (wpa_parse_kde_ies((const u8 *) (key + 1), -+ WPA_GET_BE16(key->key_data_length), &kde) < 0) { -+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1"); -+ return; -+ } -+ -+ if (kde.rsn_ie == NULL || kde.mac_addr == NULL || -+ kde.mac_addr_len < ETH_ALEN) { -+ wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " -+ "SMK M1"); -+ return; -+ } -+ -+ /* Initiator = sm->addr; Peer = kde.mac_addr */ -+ -+ search.addr = kde.mac_addr; -+ search.sm = NULL; -+ if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == -+ 0 || search.sm == NULL) { -+ wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR -+ " aborted - STA not associated anymore", -+ MAC2STR(kde.mac_addr)); -+ wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK, -+ STK_ERR_STA_NR); -+ /* FIX: wpa_stsl_remove(wpa_auth, neg); */ -+ return; -+ } -+ -+ buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; -+ buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return; -+ /* Initiator RSN IE */ -+ os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len); -+ pos = buf + kde.rsn_ie_len; -+ /* Initiator MAC Address */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN, -+ NULL, 0); -+ -+ /* SMK M2: -+ * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, -+ * MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE) -+ */ -+ -+ wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG, -+ "Sending SMK M2"); -+ -+ __wpa_send_eapol(wpa_auth, search.sm, -+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE, -+ NULL, key->key_nonce, buf, pos - buf, 0, 0, 0); -+ -+ os_free(buf); -+} -+ -+ -+static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, -+ struct wpa_eapol_key *key, -+ struct wpa_eapol_ie_parse *kde, -+ const u8 *smk) -+{ -+ u8 *buf, *pos; -+ size_t buf_len; -+ u32 lifetime; -+ -+ /* SMK M4: -+ * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce, -+ * MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE, -+ * Lifetime KDE) -+ */ -+ -+ buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN + -+ 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN + -+ 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN + -+ 2 + RSN_SELECTOR_LEN + sizeof(lifetime); -+ pos = buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return; -+ -+ /* Initiator MAC Address */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN, -+ NULL, 0); -+ -+ /* Initiator Nonce */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN, -+ NULL, 0); -+ -+ /* SMK with PNonce */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN, -+ key->key_nonce, WPA_NONCE_LEN); -+ -+ /* Lifetime */ -+ lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, -+ (u8 *) &lifetime, sizeof(lifetime), NULL, 0); -+ -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "Sending SMK M4"); -+ -+ __wpa_send_eapol(wpa_auth, sm, -+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE, -+ NULL, key->key_nonce, buf, pos - buf, 0, 1, 0); -+ -+ os_free(buf); -+} -+ -+ -+static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, -+ struct wpa_eapol_key *key, -+ struct wpa_eapol_ie_parse *kde, -+ const u8 *smk, const u8 *peer) -+{ -+ u8 *buf, *pos; -+ size_t buf_len; -+ u32 lifetime; -+ -+ /* SMK M5: -+ * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, -+ * MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE, -+ * Lifetime KDE)) -+ */ -+ -+ buf_len = kde->rsn_ie_len + -+ 2 + RSN_SELECTOR_LEN + ETH_ALEN + -+ 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN + -+ 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN + -+ 2 + RSN_SELECTOR_LEN + sizeof(lifetime); -+ pos = buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return; -+ -+ /* Peer RSN IE */ -+ os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len); -+ pos = buf + kde->rsn_ie_len; -+ -+ /* Peer MAC Address */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0); -+ -+ /* PNonce */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce, -+ WPA_NONCE_LEN, NULL, 0); -+ -+ /* SMK and INonce */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN, -+ kde->nonce, WPA_NONCE_LEN); -+ -+ /* Lifetime */ -+ lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, -+ (u8 *) &lifetime, sizeof(lifetime), NULL, 0); -+ -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "Sending SMK M5"); -+ -+ __wpa_send_eapol(wpa_auth, sm, -+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_SMK_MESSAGE, -+ NULL, kde->nonce, buf, pos - buf, 0, 1, 0); -+ -+ os_free(buf); -+} -+ -+ -+void wpa_smk_m3(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, struct wpa_eapol_key *key) -+{ -+ struct wpa_eapol_ie_parse kde; -+ struct wpa_stsl_search search; -+ u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos; -+ -+ if (wpa_parse_kde_ies((const u8 *) (key + 1), -+ WPA_GET_BE16(key->key_data_length), &kde) < 0) { -+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3"); -+ return; -+ } -+ -+ if (kde.rsn_ie == NULL || -+ kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || -+ kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) { -+ wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or " -+ "Nonce KDE in SMK M3"); -+ return; -+ } -+ -+ /* Peer = sm->addr; Initiator = kde.mac_addr; -+ * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */ -+ -+ search.addr = kde.mac_addr; -+ search.sm = NULL; -+ if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == -+ 0 || search.sm == NULL) { -+ wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR -+ " aborted - STA not associated anymore", -+ MAC2STR(kde.mac_addr)); -+ wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK, -+ STK_ERR_STA_NR); -+ /* FIX: wpa_stsl_remove(wpa_auth, neg); */ -+ return; -+ } -+ -+ if (random_get_bytes(smk, PMK_LEN)) { -+ wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK"); -+ return; -+ } -+ -+ /* SMK = PRF-256(Random number, "SMK Derivation", -+ * AA || Time || INonce || PNonce) -+ */ -+ os_memcpy(buf, wpa_auth->addr, ETH_ALEN); -+ pos = buf + ETH_ALEN; -+ wpa_get_ntp_timestamp(pos); -+ pos += 8; -+ os_memcpy(pos, kde.nonce, WPA_NONCE_LEN); -+ pos += WPA_NONCE_LEN; -+ os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN); -+#ifdef CONFIG_IEEE80211W -+ sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf), -+ smk, PMK_LEN); -+#else /* CONFIG_IEEE80211W */ -+ sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf), -+ smk, PMK_LEN); -+#endif /* CONFIG_IEEE80211W */ -+ -+ wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN); -+ -+ wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk); -+ wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr); -+ -+ /* Authenticator does not need SMK anymore and it is required to forget -+ * it. */ -+ os_memset(smk, 0, sizeof(*smk)); -+} -+ -+ -+void wpa_smk_error(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, struct wpa_eapol_key *key) -+{ -+ struct wpa_eapol_ie_parse kde; -+ struct wpa_stsl_search search; -+ struct rsn_error_kde error; -+ u16 mui, error_type; -+ -+ if (wpa_parse_kde_ies((const u8 *) (key + 1), -+ WPA_GET_BE16(key->key_data_length), &kde) < 0) { -+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error"); -+ return; -+ } -+ -+ if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || -+ kde.error == NULL || kde.error_len < sizeof(error)) { -+ wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in " -+ "SMK Error"); -+ return; -+ } -+ -+ search.addr = kde.mac_addr; -+ search.sm = NULL; -+ if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == -+ 0 || search.sm == NULL) { -+ wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not " -+ "associated for SMK Error message from " MACSTR, -+ MAC2STR(kde.mac_addr), MAC2STR(sm->addr)); -+ return; -+ } -+ -+ os_memcpy(&error, kde.error, sizeof(error)); -+ mui = be_to_host16(error.mui); -+ error_type = be_to_host16(error.error_type); -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, -+ "STA reported SMK Error: Peer " MACSTR -+ " MUI %d Error Type %d", -+ MAC2STR(kde.mac_addr), mui, error_type); -+ -+ wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type); -+} -+ -+ -+int wpa_stsl_remove(struct wpa_authenticator *wpa_auth, -+ struct wpa_stsl_negotiation *neg) -+{ -+ struct wpa_stsl_negotiation *pos, *prev; -+ -+ if (wpa_auth == NULL) -+ return -1; -+ pos = wpa_auth->stsl_negotiations; -+ prev = NULL; -+ while (pos) { -+ if (pos == neg) { -+ if (prev) -+ prev->next = pos->next; -+ else -+ wpa_auth->stsl_negotiations = pos->next; -+ -+ eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos); -+ os_free(pos); -+ return 0; -+ } -+ prev = pos; -+ pos = pos->next; -+ } -+ -+ return -1; -+} -+ -+#endif /* CONFIG_PEERKEY */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.c -new file mode 100644 -index 0000000000000..22f44b78464a6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.c -@@ -0,0 +1,425 @@ -+/* -+ * hostapd - PMKSA cache for IEEE 802.11i RSN -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "eapol_auth/eapol_auth_sm_i.h" -+#include "sta_info.h" -+#include "ap_config.h" -+#include "pmksa_cache_auth.h" -+ -+ -+static const int pmksa_cache_max_entries = 1024; -+static const int dot11RSNAConfigPMKLifetime = 43200; -+ -+struct rsn_pmksa_cache { -+#define PMKID_HASH_SIZE 128 -+#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f) -+ struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE]; -+ struct rsn_pmksa_cache_entry *pmksa; -+ int pmksa_count; -+ -+ void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx); -+ void *ctx; -+}; -+ -+ -+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); -+ -+ -+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) -+{ -+ if (entry == NULL) -+ return; -+ os_free(entry->identity); -+#ifndef CONFIG_NO_RADIUS -+ radius_free_class(&entry->radius_class); -+#endif /* CONFIG_NO_RADIUS */ -+ os_free(entry); -+} -+ -+ -+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, -+ struct rsn_pmksa_cache_entry *entry) -+{ -+ struct rsn_pmksa_cache_entry *pos, *prev; -+ -+ pmksa->pmksa_count--; -+ pmksa->free_cb(entry, pmksa->ctx); -+ pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; -+ prev = NULL; -+ while (pos) { -+ if (pos == entry) { -+ if (prev != NULL) { -+ prev->hnext = pos->hnext; -+ } else { -+ pmksa->pmkid[PMKID_HASH(entry->pmkid)] = -+ pos->hnext; -+ } -+ break; -+ } -+ prev = pos; -+ pos = pos->hnext; -+ } -+ -+ pos = pmksa->pmksa; -+ prev = NULL; -+ while (pos) { -+ if (pos == entry) { -+ if (prev != NULL) -+ prev->next = pos->next; -+ else -+ pmksa->pmksa = pos->next; -+ break; -+ } -+ prev = pos; -+ pos = pos->next; -+ } -+ _pmksa_cache_free_entry(entry); -+} -+ -+ -+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct rsn_pmksa_cache *pmksa = eloop_ctx; -+ struct os_time now; -+ -+ os_get_time(&now); -+ while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { -+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; -+ pmksa->pmksa = entry->next; -+ wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " -+ MACSTR, MAC2STR(entry->spa)); -+ pmksa_cache_free_entry(pmksa, entry); -+ } -+ -+ pmksa_cache_set_expiration(pmksa); -+} -+ -+ -+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) -+{ -+ int sec; -+ struct os_time now; -+ -+ eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); -+ if (pmksa->pmksa == NULL) -+ return; -+ os_get_time(&now); -+ sec = pmksa->pmksa->expiration - now.sec; -+ if (sec < 0) -+ sec = 0; -+ eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); -+} -+ -+ -+static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry, -+ struct eapol_state_machine *eapol) -+{ -+ if (eapol == NULL) -+ return; -+ -+ if (eapol->identity) { -+ entry->identity = os_malloc(eapol->identity_len); -+ if (entry->identity) { -+ entry->identity_len = eapol->identity_len; -+ os_memcpy(entry->identity, eapol->identity, -+ eapol->identity_len); -+ } -+ } -+ -+#ifndef CONFIG_NO_RADIUS -+ radius_copy_class(&entry->radius_class, &eapol->radius_class); -+#endif /* CONFIG_NO_RADIUS */ -+ -+ entry->eap_type_authsrv = eapol->eap_type_authsrv; -+ entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id; -+} -+ -+ -+void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, -+ struct eapol_state_machine *eapol) -+{ -+ if (entry == NULL || eapol == NULL) -+ return; -+ -+ if (entry->identity) { -+ os_free(eapol->identity); -+ eapol->identity = os_malloc(entry->identity_len); -+ if (eapol->identity) { -+ eapol->identity_len = entry->identity_len; -+ os_memcpy(eapol->identity, entry->identity, -+ entry->identity_len); -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA", -+ eapol->identity, eapol->identity_len); -+ } -+ -+#ifndef CONFIG_NO_RADIUS -+ radius_free_class(&eapol->radius_class); -+ radius_copy_class(&eapol->radius_class, &entry->radius_class); -+#endif /* CONFIG_NO_RADIUS */ -+ if (eapol->radius_class.attr) { -+ wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from " -+ "PMKSA", (unsigned long) eapol->radius_class.count); -+ } -+ -+ eapol->eap_type_authsrv = entry->eap_type_authsrv; -+ ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id; -+} -+ -+ -+static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, -+ struct rsn_pmksa_cache_entry *entry) -+{ -+ struct rsn_pmksa_cache_entry *pos, *prev; -+ -+ /* Add the new entry; order by expiration time */ -+ pos = pmksa->pmksa; -+ prev = NULL; -+ while (pos) { -+ if (pos->expiration > entry->expiration) -+ break; -+ prev = pos; -+ pos = pos->next; -+ } -+ if (prev == NULL) { -+ entry->next = pmksa->pmksa; -+ pmksa->pmksa = entry; -+ } else { -+ entry->next = prev->next; -+ prev->next = entry; -+ } -+ entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; -+ pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry; -+ -+ pmksa->pmksa_count++; -+ wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR, -+ MAC2STR(entry->spa)); -+ wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN); -+} -+ -+ -+/** -+ * pmksa_cache_auth_add - Add a PMKSA cache entry -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() -+ * @pmk: The new pairwise master key -+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32) -+ * @aa: Authenticator address -+ * @spa: Supplicant address -+ * @session_timeout: Session timeout -+ * @eapol: Pointer to EAPOL state machine data -+ * @akmp: WPA_KEY_MGMT_* used in key derivation -+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error -+ * -+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA -+ * cache. If an old entry is already in the cache for the same Supplicant, -+ * this entry will be replaced with the new entry. PMKID will be calculated -+ * based on the PMK. -+ */ -+struct rsn_pmksa_cache_entry * -+pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, -+ const u8 *pmk, size_t pmk_len, -+ const u8 *aa, const u8 *spa, int session_timeout, -+ struct eapol_state_machine *eapol, int akmp) -+{ -+ struct rsn_pmksa_cache_entry *entry, *pos; -+ struct os_time now; -+ -+ if (pmk_len > PMK_LEN) -+ return NULL; -+ -+ entry = os_zalloc(sizeof(*entry)); -+ if (entry == NULL) -+ return NULL; -+ os_memcpy(entry->pmk, pmk, pmk_len); -+ entry->pmk_len = pmk_len; -+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, -+ wpa_key_mgmt_sha256(akmp)); -+ os_get_time(&now); -+ entry->expiration = now.sec; -+ if (session_timeout > 0) -+ entry->expiration += session_timeout; -+ else -+ entry->expiration += dot11RSNAConfigPMKLifetime; -+ entry->akmp = akmp; -+ os_memcpy(entry->spa, spa, ETH_ALEN); -+ pmksa_cache_from_eapol_data(entry, eapol); -+ -+ /* Replace an old entry for the same STA (if found) with the new entry -+ */ -+ pos = pmksa_cache_auth_get(pmksa, spa, NULL); -+ if (pos) -+ pmksa_cache_free_entry(pmksa, pos); -+ -+ if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { -+ /* Remove the oldest entry to make room for the new entry */ -+ wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " -+ "entry (for " MACSTR ") to make room for new one", -+ MAC2STR(pmksa->pmksa->spa)); -+ pmksa_cache_free_entry(pmksa, pmksa->pmksa); -+ } -+ -+ pmksa_cache_link_entry(pmksa, entry); -+ -+ return entry; -+} -+ -+ -+struct rsn_pmksa_cache_entry * -+pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, -+ const struct rsn_pmksa_cache_entry *old_entry, -+ const u8 *aa, const u8 *pmkid) -+{ -+ struct rsn_pmksa_cache_entry *entry; -+ -+ entry = os_zalloc(sizeof(*entry)); -+ if (entry == NULL) -+ return NULL; -+ os_memcpy(entry->pmkid, pmkid, PMKID_LEN); -+ os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len); -+ entry->pmk_len = old_entry->pmk_len; -+ entry->expiration = old_entry->expiration; -+ entry->akmp = old_entry->akmp; -+ os_memcpy(entry->spa, old_entry->spa, ETH_ALEN); -+ entry->opportunistic = 1; -+ if (old_entry->identity) { -+ entry->identity = os_malloc(old_entry->identity_len); -+ if (entry->identity) { -+ entry->identity_len = old_entry->identity_len; -+ os_memcpy(entry->identity, old_entry->identity, -+ old_entry->identity_len); -+ } -+ } -+#ifndef CONFIG_NO_RADIUS -+ radius_copy_class(&entry->radius_class, &old_entry->radius_class); -+#endif /* CONFIG_NO_RADIUS */ -+ entry->eap_type_authsrv = old_entry->eap_type_authsrv; -+ entry->vlan_id = old_entry->vlan_id; -+ entry->opportunistic = 1; -+ -+ pmksa_cache_link_entry(pmksa, entry); -+ -+ return entry; -+} -+ -+ -+/** -+ * pmksa_cache_auth_deinit - Free all entries in PMKSA cache -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() -+ */ -+void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa) -+{ -+ struct rsn_pmksa_cache_entry *entry, *prev; -+ int i; -+ -+ if (pmksa == NULL) -+ return; -+ -+ entry = pmksa->pmksa; -+ while (entry) { -+ prev = entry; -+ entry = entry->next; -+ _pmksa_cache_free_entry(prev); -+ } -+ eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); -+ for (i = 0; i < PMKID_HASH_SIZE; i++) -+ pmksa->pmkid[i] = NULL; -+ os_free(pmksa); -+} -+ -+ -+/** -+ * pmksa_cache_auth_get - Fetch a PMKSA cache entry -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() -+ * @spa: Supplicant address or %NULL to match any -+ * @pmkid: PMKID or %NULL to match any -+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found -+ */ -+struct rsn_pmksa_cache_entry * -+pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, -+ const u8 *spa, const u8 *pmkid) -+{ -+ struct rsn_pmksa_cache_entry *entry; -+ -+ if (pmkid) -+ entry = pmksa->pmkid[PMKID_HASH(pmkid)]; -+ else -+ entry = pmksa->pmksa; -+ while (entry) { -+ if ((spa == NULL || -+ os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && -+ (pmkid == NULL || -+ os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) -+ return entry; -+ entry = pmkid ? entry->hnext : entry->next; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() -+ * @aa: Authenticator address -+ * @spa: Supplicant address -+ * @pmkid: PMKID -+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found -+ * -+ * Use opportunistic key caching (OKC) to find a PMK for a supplicant. -+ */ -+struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( -+ struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, -+ const u8 *pmkid) -+{ -+ struct rsn_pmksa_cache_entry *entry; -+ u8 new_pmkid[PMKID_LEN]; -+ -+ entry = pmksa->pmksa; -+ while (entry) { -+ if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0) -+ continue; -+ rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid, -+ wpa_key_mgmt_sha256(entry->akmp)); -+ if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) -+ return entry; -+ entry = entry->next; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * pmksa_cache_auth_init - Initialize PMKSA cache -+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed -+ * @ctx: Context pointer for free_cb function -+ * Returns: Pointer to PMKSA cache data or %NULL on failure -+ */ -+struct rsn_pmksa_cache * -+pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, -+ void *ctx), void *ctx) -+{ -+ struct rsn_pmksa_cache *pmksa; -+ -+ pmksa = os_zalloc(sizeof(*pmksa)); -+ if (pmksa) { -+ pmksa->free_cb = free_cb; -+ pmksa->ctx = ctx; -+ } -+ -+ return pmksa; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.h -new file mode 100644 -index 0000000000000..9628b13da0299 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/pmksa_cache_auth.h -@@ -0,0 +1,64 @@ -+/* -+ * hostapd - PMKSA cache for IEEE 802.11i RSN -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PMKSA_CACHE_H -+#define PMKSA_CACHE_H -+ -+#include "radius/radius.h" -+ -+/** -+ * struct rsn_pmksa_cache_entry - PMKSA cache entry -+ */ -+struct rsn_pmksa_cache_entry { -+ struct rsn_pmksa_cache_entry *next, *hnext; -+ u8 pmkid[PMKID_LEN]; -+ u8 pmk[PMK_LEN]; -+ size_t pmk_len; -+ os_time_t expiration; -+ int akmp; /* WPA_KEY_MGMT_* */ -+ u8 spa[ETH_ALEN]; -+ -+ u8 *identity; -+ size_t identity_len; -+ struct radius_class_data radius_class; -+ u8 eap_type_authsrv; -+ int vlan_id; -+ int opportunistic; -+}; -+ -+struct rsn_pmksa_cache; -+ -+struct rsn_pmksa_cache * -+pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, -+ void *ctx), void *ctx); -+void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa); -+struct rsn_pmksa_cache_entry * -+pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, -+ const u8 *spa, const u8 *pmkid); -+struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( -+ struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa, -+ const u8 *pmkid); -+struct rsn_pmksa_cache_entry * -+pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, -+ const u8 *pmk, size_t pmk_len, -+ const u8 *aa, const u8 *spa, int session_timeout, -+ struct eapol_state_machine *eapol, int akmp); -+struct rsn_pmksa_cache_entry * -+pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, -+ const struct rsn_pmksa_cache_entry *old_entry, -+ const u8 *aa, const u8 *pmkid); -+void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, -+ struct eapol_state_machine *eapol); -+ -+#endif /* PMKSA_CACHE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.c -new file mode 100644 -index 0000000000000..8e133158a9763 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.c -@@ -0,0 +1,279 @@ -+/* -+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#ifdef CONFIG_RSN_PREAUTH -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "l2_packet/l2_packet.h" -+#include "common/wpa_common.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "eapol_auth/eapol_auth_sm_i.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ieee802_1x.h" -+#include "sta_info.h" -+#include "wpa_auth.h" -+#include "preauth_auth.h" -+ -+#ifndef ETH_P_PREAUTH -+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ -+#endif /* ETH_P_PREAUTH */ -+ -+static const int dot11RSNAConfigPMKLifetime = 43200; -+ -+struct rsn_preauth_interface { -+ struct rsn_preauth_interface *next; -+ struct hostapd_data *hapd; -+ struct l2_packet_data *l2; -+ char *ifname; -+ int ifindex; -+}; -+ -+ -+static void rsn_preauth_receive(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct rsn_preauth_interface *piface = ctx; -+ struct hostapd_data *hapd = piface->hapd; -+ struct ieee802_1x_hdr *hdr; -+ struct sta_info *sta; -+ struct l2_ethhdr *ethhdr; -+ -+ wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet " -+ "from interface '%s'", piface->ifname); -+ if (len < sizeof(*ethhdr) + sizeof(*hdr)) { -+ wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet " -+ "(len=%lu)", (unsigned long) len); -+ return; -+ } -+ -+ ethhdr = (struct l2_ethhdr *) buf; -+ hdr = (struct ieee802_1x_hdr *) (ethhdr + 1); -+ -+ if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) { -+ wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address " -+ MACSTR, MAC2STR(ethhdr->h_dest)); -+ return; -+ } -+ -+ sta = ap_get_sta(hapd, ethhdr->h_source); -+ if (sta && (sta->flags & WLAN_STA_ASSOC)) { -+ wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association " -+ "STA " MACSTR, MAC2STR(sta->addr)); -+ return; -+ } -+ if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) { -+ sta = ap_sta_add(hapd, ethhdr->h_source); -+ if (sta == NULL) -+ return; -+ sta->flags = WLAN_STA_PREAUTH; -+ -+ ieee802_1x_new_station(hapd, sta); -+ if (sta->eapol_sm == NULL) { -+ ap_free_sta(hapd, sta); -+ sta = NULL; -+ } else { -+ sta->eapol_sm->radius_identifier = -1; -+ sta->eapol_sm->portValid = TRUE; -+ sta->eapol_sm->flags |= EAPOL_SM_PREAUTH; -+ } -+ } -+ if (sta == NULL) -+ return; -+ sta->preauth_iface = piface; -+ ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1), -+ len - sizeof(*ethhdr)); -+} -+ -+ -+static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname) -+{ -+ struct rsn_preauth_interface *piface; -+ -+ wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname); -+ -+ piface = os_zalloc(sizeof(*piface)); -+ if (piface == NULL) -+ return -1; -+ piface->hapd = hapd; -+ -+ piface->ifname = os_strdup(ifname); -+ if (piface->ifname == NULL) { -+ goto fail1; -+ } -+ -+ piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH, -+ rsn_preauth_receive, piface, 1); -+ if (piface->l2 == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to open register layer 2 access " -+ "to ETH_P_PREAUTH"); -+ goto fail2; -+ } -+ -+ piface->next = hapd->preauth_iface; -+ hapd->preauth_iface = piface; -+ return 0; -+ -+fail2: -+ os_free(piface->ifname); -+fail1: -+ os_free(piface); -+ return -1; -+} -+ -+ -+void rsn_preauth_iface_deinit(struct hostapd_data *hapd) -+{ -+ struct rsn_preauth_interface *piface, *prev; -+ -+ piface = hapd->preauth_iface; -+ hapd->preauth_iface = NULL; -+ while (piface) { -+ prev = piface; -+ piface = piface->next; -+ l2_packet_deinit(prev->l2); -+ os_free(prev->ifname); -+ os_free(prev); -+ } -+} -+ -+ -+int rsn_preauth_iface_init(struct hostapd_data *hapd) -+{ -+ char *tmp, *start, *end; -+ -+ if (hapd->conf->rsn_preauth_interfaces == NULL) -+ return 0; -+ -+ tmp = os_strdup(hapd->conf->rsn_preauth_interfaces); -+ if (tmp == NULL) -+ return -1; -+ start = tmp; -+ for (;;) { -+ while (*start == ' ') -+ start++; -+ if (*start == '\0') -+ break; -+ end = os_strchr(start, ' '); -+ if (end) -+ *end = '\0'; -+ -+ if (rsn_preauth_iface_add(hapd, start)) { -+ rsn_preauth_iface_deinit(hapd); -+ os_free(tmp); -+ return -1; -+ } -+ -+ if (end) -+ start = end + 1; -+ else -+ break; -+ } -+ os_free(tmp); -+ return 0; -+} -+ -+ -+static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ struct sta_info *sta = timeout_ctx; -+ wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for " -+ MACSTR, MAC2STR(sta->addr)); -+ ap_free_sta(hapd, sta); -+} -+ -+ -+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta, -+ int success) -+{ -+ const u8 *key; -+ size_t len; -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, -+ HOSTAPD_LEVEL_INFO, "pre-authentication %s", -+ success ? "succeeded" : "failed"); -+ -+ key = ieee802_1x_get_key(sta->eapol_sm, &len); -+ if (len > PMK_LEN) -+ len = PMK_LEN; -+ if (success && key) { -+ if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len, -+ sta->addr, -+ dot11RSNAConfigPMKLifetime, -+ sta->eapol_sm) == 0) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, -+ HOSTAPD_LEVEL_DEBUG, -+ "added PMKSA cache entry (pre-auth)"); -+ } else { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, -+ HOSTAPD_LEVEL_DEBUG, -+ "failed to add PMKSA cache entry " -+ "(pre-auth)"); -+ } -+ } -+ -+ /* -+ * Finish STA entry removal from timeout in order to avoid freeing -+ * STA data before the caller has finished processing. -+ */ -+ eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta); -+} -+ -+ -+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, -+ u8 *buf, size_t len) -+{ -+ struct rsn_preauth_interface *piface; -+ struct l2_ethhdr *ethhdr; -+ -+ piface = hapd->preauth_iface; -+ while (piface) { -+ if (piface == sta->preauth_iface) -+ break; -+ piface = piface->next; -+ } -+ -+ if (piface == NULL) { -+ wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication " -+ "interface for " MACSTR, MAC2STR(sta->addr)); -+ return; -+ } -+ -+ ethhdr = os_malloc(sizeof(*ethhdr) + len); -+ if (ethhdr == NULL) -+ return; -+ -+ os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN); -+ os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN); -+ ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH); -+ os_memcpy(ethhdr + 1, buf, len); -+ -+ if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr, -+ sizeof(*ethhdr) + len) < 0) { -+ wpa_printf(MSG_ERROR, "Failed to send preauth packet using " -+ "l2_packet_send\n"); -+ } -+ os_free(ethhdr); -+} -+ -+ -+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta); -+} -+ -+#endif /* CONFIG_RSN_PREAUTH */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.h -new file mode 100644 -index 0000000000000..5348bee9bf72e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/preauth_auth.h -@@ -0,0 +1,58 @@ -+/* -+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication -+ * Copyright (c) 2004-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PREAUTH_H -+#define PREAUTH_H -+ -+#ifdef CONFIG_RSN_PREAUTH -+ -+int rsn_preauth_iface_init(struct hostapd_data *hapd); -+void rsn_preauth_iface_deinit(struct hostapd_data *hapd); -+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta, -+ int success); -+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, -+ u8 *buf, size_t len); -+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta); -+ -+#else /* CONFIG_RSN_PREAUTH */ -+ -+static inline int rsn_preauth_iface_init(struct hostapd_data *hapd) -+{ -+ return 0; -+} -+ -+static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd) -+{ -+} -+ -+static inline void rsn_preauth_finished(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ int success) -+{ -+} -+ -+static inline void rsn_preauth_send(struct hostapd_data *hapd, -+ struct sta_info *sta, -+ u8 *buf, size_t len) -+{ -+} -+ -+static inline void rsn_preauth_free_station(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+} -+ -+#endif /* CONFIG_RSN_PREAUTH */ -+ -+#endif /* PREAUTH_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.c -new file mode 100644 -index 0000000000000..e829447da991a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.c -@@ -0,0 +1,796 @@ -+/* -+ * hostapd / Station table -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "radius/radius.h" -+#include "radius/radius_client.h" -+#include "drivers/driver.h" -+#include "p2p/p2p.h" -+#include "hostapd.h" -+#include "accounting.h" -+#include "ieee802_1x.h" -+#include "ieee802_11.h" -+#include "wpa_auth.h" -+#include "preauth_auth.h" -+#include "ap_config.h" -+#include "beacon.h" -+#include "ap_mlme.h" -+#include "vlan_init.h" -+#include "p2p_hostapd.h" -+#include "ap_drv_ops.h" -+#include "sta_info.h" -+ -+static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, -+ struct sta_info *sta); -+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); -+#ifdef CONFIG_IEEE80211W -+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx); -+#endif /* CONFIG_IEEE80211W */ -+ -+int ap_for_each_sta(struct hostapd_data *hapd, -+ int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, -+ void *ctx), -+ void *ctx) -+{ -+ struct sta_info *sta; -+ -+ for (sta = hapd->sta_list; sta; sta = sta->next) { -+ if (cb(hapd, sta, ctx)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) -+{ -+ struct sta_info *s; -+ -+ s = hapd->sta_hash[STA_HASH(sta)]; -+ while (s != NULL && os_memcmp(s->addr, sta, 6) != 0) -+ s = s->hnext; -+ return s; -+} -+ -+ -+static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ struct sta_info *tmp; -+ -+ if (hapd->sta_list == sta) { -+ hapd->sta_list = sta->next; -+ return; -+ } -+ -+ tmp = hapd->sta_list; -+ while (tmp != NULL && tmp->next != sta) -+ tmp = tmp->next; -+ if (tmp == NULL) { -+ wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from " -+ "list.", MAC2STR(sta->addr)); -+ } else -+ tmp->next = sta->next; -+} -+ -+ -+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)]; -+ hapd->sta_hash[STA_HASH(sta->addr)] = sta; -+} -+ -+ -+static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ struct sta_info *s; -+ -+ s = hapd->sta_hash[STA_HASH(sta->addr)]; -+ if (s == NULL) return; -+ if (os_memcmp(s->addr, sta->addr, 6) == 0) { -+ hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext; -+ return; -+ } -+ -+ while (s->hnext != NULL && -+ os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) -+ s = s->hnext; -+ if (s->hnext != NULL) -+ s->hnext = s->hnext->hnext; -+ else -+ wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR -+ " from hash table", MAC2STR(sta->addr)); -+} -+ -+ -+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ int set_beacon = 0; -+ -+ accounting_sta_stop(hapd, sta); -+ -+ /* just in case */ -+ ap_sta_set_authorized(hapd, sta, 0); -+ -+ if (sta->flags & WLAN_STA_WDS) -+ hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0); -+ -+ if (!(sta->flags & WLAN_STA_PREAUTH)) -+ hostapd_drv_sta_remove(hapd, sta->addr); -+ -+ ap_sta_hash_del(hapd, sta); -+ ap_sta_list_del(hapd, sta); -+ -+ if (sta->aid > 0) -+ hapd->sta_aid[(sta->aid - 1) / 32] &= -+ ~BIT((sta->aid - 1) % 32); -+ -+ hapd->num_sta--; -+ if (sta->nonerp_set) { -+ sta->nonerp_set = 0; -+ hapd->iface->num_sta_non_erp--; -+ if (hapd->iface->num_sta_non_erp == 0) -+ set_beacon++; -+ } -+ -+ if (sta->no_short_slot_time_set) { -+ sta->no_short_slot_time_set = 0; -+ hapd->iface->num_sta_no_short_slot_time--; -+ if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G -+ && hapd->iface->num_sta_no_short_slot_time == 0) -+ set_beacon++; -+ } -+ -+ if (sta->no_short_preamble_set) { -+ sta->no_short_preamble_set = 0; -+ hapd->iface->num_sta_no_short_preamble--; -+ if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G -+ && hapd->iface->num_sta_no_short_preamble == 0) -+ set_beacon++; -+ } -+ -+ if (sta->no_ht_gf_set) { -+ sta->no_ht_gf_set = 0; -+ hapd->iface->num_sta_ht_no_gf--; -+ } -+ -+ if (sta->no_ht_set) { -+ sta->no_ht_set = 0; -+ hapd->iface->num_sta_no_ht--; -+ } -+ -+ if (sta->ht_20mhz_set) { -+ sta->ht_20mhz_set = 0; -+ hapd->iface->num_sta_ht_20mhz--; -+ } -+ -+#ifdef CONFIG_P2P -+ if (sta->no_p2p_set) { -+ sta->no_p2p_set = 0; -+ hapd->num_sta_no_p2p--; -+ if (hapd->num_sta_no_p2p == 0) -+ hostapd_p2p_non_p2p_sta_disconnected(hapd); -+ } -+#endif /* CONFIG_P2P */ -+ -+#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N) -+ if (hostapd_ht_operation_update(hapd->iface) > 0) -+ set_beacon++; -+#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */ -+ -+ if (set_beacon) -+ ieee802_11_set_beacons(hapd->iface); -+ -+ eloop_cancel_timeout(ap_handle_timer, hapd, sta); -+ eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); -+ -+ ieee802_1x_free_station(sta); -+ wpa_auth_sta_deinit(sta->wpa_sm); -+ rsn_preauth_free_station(hapd, sta); -+#ifndef CONFIG_NO_RADIUS -+ radius_client_flush_auth(hapd->radius, sta->addr); -+#endif /* CONFIG_NO_RADIUS */ -+ -+ os_free(sta->last_assoc_req); -+ os_free(sta->challenge); -+ -+#ifdef CONFIG_IEEE80211W -+ os_free(sta->sa_query_trans_id); -+ eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); -+#endif /* CONFIG_IEEE80211W */ -+ -+#ifdef CONFIG_P2P -+ p2p_group_notif_disassoc(hapd->p2p_group, sta->addr); -+#endif /* CONFIG_P2P */ -+ -+ wpabuf_free(sta->wps_ie); -+ wpabuf_free(sta->p2p_ie); -+ -+ os_free(sta->ht_capabilities); -+ -+ os_free(sta); -+} -+ -+ -+void hostapd_free_stas(struct hostapd_data *hapd) -+{ -+ struct sta_info *sta, *prev; -+ -+ sta = hapd->sta_list; -+ -+ while (sta) { -+ prev = sta; -+ if (sta->flags & WLAN_STA_AUTH) { -+ mlme_deauthenticate_indication( -+ hapd, sta, WLAN_REASON_UNSPECIFIED); -+ } -+ sta = sta->next; -+ wpa_printf(MSG_DEBUG, "Removing station " MACSTR, -+ MAC2STR(prev->addr)); -+ ap_free_sta(hapd, prev); -+ } -+} -+ -+ -+/** -+ * ap_handle_timer - Per STA timer handler -+ * @eloop_ctx: struct hostapd_data * -+ * @timeout_ctx: struct sta_info * -+ * -+ * This function is called to check station activity and to remove inactive -+ * stations. -+ */ -+void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ struct sta_info *sta = timeout_ctx; -+ unsigned long next_time = 0; -+ -+ if (sta->timeout_next == STA_REMOVE) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "deauthenticated due to " -+ "local deauth request"); -+ ap_free_sta(hapd, sta); -+ return; -+ } -+ -+ if ((sta->flags & WLAN_STA_ASSOC) && -+ (sta->timeout_next == STA_NULLFUNC || -+ sta->timeout_next == STA_DISASSOC)) { -+ int inactive_sec; -+ inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); -+ if (inactive_sec == -1) { -+ wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not " -+ "get station info rom kernel driver for " -+ MACSTR, MAC2STR(sta->addr)); -+ } else if (inactive_sec < hapd->conf->ap_max_inactivity && -+ sta->flags & WLAN_STA_ASSOC) { -+ /* station activity detected; reset timeout state */ -+ wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been " -+ "active %is ago", -+ MAC2STR(sta->addr), inactive_sec); -+ sta->timeout_next = STA_NULLFUNC; -+ next_time = hapd->conf->ap_max_inactivity - -+ inactive_sec; -+ } else { -+ wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been " -+ "inactive too long: %d sec, max allowed: %d", -+ MAC2STR(sta->addr), inactive_sec, -+ hapd->conf->ap_max_inactivity); -+ } -+ } -+ -+ if ((sta->flags & WLAN_STA_ASSOC) && -+ sta->timeout_next == STA_DISASSOC && -+ !(sta->flags & WLAN_STA_PENDING_POLL)) { -+ wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data " -+ "poll", MAC2STR(sta->addr)); -+ /* data nullfunc frame poll did not produce TX errors; assume -+ * station ACKed it */ -+ sta->timeout_next = STA_NULLFUNC; -+ next_time = hapd->conf->ap_max_inactivity; -+ } -+ -+ if (next_time) { -+ eloop_register_timeout(next_time, 0, ap_handle_timer, hapd, -+ sta); -+ return; -+ } -+ -+ if (sta->timeout_next == STA_NULLFUNC && -+ (sta->flags & WLAN_STA_ASSOC)) { -+#ifndef CONFIG_NATIVE_WINDOWS -+ /* send data frame to poll STA and check whether this frame -+ * is ACKed */ -+ struct ieee80211_hdr hdr; -+ -+ wpa_printf(MSG_DEBUG, " Polling STA with data frame"); -+ sta->flags |= WLAN_STA_PENDING_POLL; -+ -+ os_memset(&hdr, 0, sizeof(hdr)); -+ if (hapd->driver && -+ os_strcmp(hapd->driver->name, "hostap") == 0) { -+ /* -+ * WLAN_FC_STYPE_NULLFUNC would be more appropriate, -+ * but it is apparently not retried so TX Exc events -+ * are not received for it. -+ */ -+ hdr.frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_DATA, -+ WLAN_FC_STYPE_DATA); -+ } else { -+ hdr.frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_DATA, -+ WLAN_FC_STYPE_NULLFUNC); -+ } -+ -+ hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS); -+ os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN); -+ os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr, -+ ETH_ALEN); -+ os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN); -+ -+ if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0) -+ perror("ap_handle_timer: send"); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ } else if (sta->timeout_next != STA_REMOVE) { -+ int deauth = sta->timeout_next == STA_DEAUTH; -+ -+ wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR, -+ deauth ? "deauthentication" : "disassociation", -+ MAC2STR(sta->addr)); -+ -+ if (deauth) { -+ hostapd_drv_sta_deauth( -+ hapd, sta->addr, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ } else { -+ hostapd_drv_sta_disassoc( -+ hapd, sta->addr, -+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); -+ } -+ } -+ -+ switch (sta->timeout_next) { -+ case STA_NULLFUNC: -+ sta->timeout_next = STA_DISASSOC; -+ eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer, -+ hapd, sta); -+ break; -+ case STA_DISASSOC: -+ sta->flags &= ~WLAN_STA_ASSOC; -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); -+ if (!sta->acct_terminate_cause) -+ sta->acct_terminate_cause = -+ RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; -+ accounting_sta_stop(hapd, sta); -+ ieee802_1x_free_station(sta); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "disassociated due to " -+ "inactivity"); -+ sta->timeout_next = STA_DEAUTH; -+ eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, -+ hapd, sta); -+ mlme_disassociate_indication( -+ hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); -+ break; -+ case STA_DEAUTH: -+ case STA_REMOVE: -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "deauthenticated due to " -+ "inactivity"); -+ if (!sta->acct_terminate_cause) -+ sta->acct_terminate_cause = -+ RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; -+ mlme_deauthenticate_indication( -+ hapd, sta, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ ap_free_sta(hapd, sta); -+ break; -+ } -+} -+ -+ -+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ struct sta_info *sta = timeout_ctx; -+ u8 addr[ETH_ALEN]; -+ -+ if (!(sta->flags & WLAN_STA_AUTH)) -+ return; -+ -+ mlme_deauthenticate_indication(hapd, sta, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "deauthenticated due to " -+ "session timeout"); -+ sta->acct_terminate_cause = -+ RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT; -+ os_memcpy(addr, sta->addr, ETH_ALEN); -+ ap_free_sta(hapd, sta); -+ hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); -+} -+ -+ -+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, -+ u32 session_timeout) -+{ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d " -+ "seconds", session_timeout); -+ eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); -+ eloop_register_timeout(session_timeout, 0, ap_handle_session_timer, -+ hapd, sta); -+} -+ -+ -+void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); -+} -+ -+ -+struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) -+{ -+ struct sta_info *sta; -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta) -+ return sta; -+ -+ wpa_printf(MSG_DEBUG, " New STA"); -+ if (hapd->num_sta >= hapd->conf->max_num_sta) { -+ /* FIX: might try to remove some old STAs first? */ -+ wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)", -+ hapd->num_sta, hapd->conf->max_num_sta); -+ return NULL; -+ } -+ -+ sta = os_zalloc(sizeof(struct sta_info)); -+ if (sta == NULL) { -+ wpa_printf(MSG_ERROR, "malloc failed"); -+ return NULL; -+ } -+ sta->acct_interim_interval = hapd->conf->acct_interim_interval; -+ -+ /* initialize STA info data */ -+ eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, -+ ap_handle_timer, hapd, sta); -+ os_memcpy(sta->addr, addr, ETH_ALEN); -+ sta->next = hapd->sta_list; -+ hapd->sta_list = sta; -+ hapd->num_sta++; -+ ap_sta_hash_add(hapd, sta); -+ sta->ssid = &hapd->conf->ssid; -+ ap_sta_remove_in_other_bss(hapd, sta); -+ -+ return sta; -+} -+ -+ -+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); -+ -+ wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver", -+ MAC2STR(sta->addr)); -+ if (hostapd_drv_sta_remove(hapd, sta->addr) && -+ sta->flags & WLAN_STA_ASSOC) { -+ wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR -+ " from kernel driver.", MAC2STR(sta->addr)); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, -+ struct sta_info *sta) -+{ -+ struct hostapd_iface *iface = hapd->iface; -+ size_t i; -+ -+ for (i = 0; i < iface->num_bss; i++) { -+ struct hostapd_data *bss = iface->bss[i]; -+ struct sta_info *sta2; -+ /* bss should always be set during operation, but it may be -+ * NULL during reconfiguration. Assume the STA is not -+ * associated to another BSS in that case to avoid NULL pointer -+ * dereferences. */ -+ if (bss == hapd || bss == NULL) -+ continue; -+ sta2 = ap_get_sta(bss, sta->addr); -+ if (!sta2) -+ continue; -+ -+ ap_sta_disconnect(bss, sta2, sta2->addr, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ } -+} -+ -+ -+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, -+ u16 reason) -+{ -+ wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, -+ hapd->conf->iface, MAC2STR(sta->addr)); -+ sta->flags &= ~WLAN_STA_ASSOC; -+ ap_sta_remove(hapd, sta); -+ sta->timeout_next = STA_DEAUTH; -+ eloop_cancel_timeout(ap_handle_timer, hapd, sta); -+ eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, -+ ap_handle_timer, hapd, sta); -+ accounting_sta_stop(hapd, sta); -+ ieee802_1x_free_station(sta); -+ -+ mlme_disassociate_indication(hapd, sta, reason); -+} -+ -+ -+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, -+ u16 reason) -+{ -+ wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, -+ hapd->conf->iface, MAC2STR(sta->addr)); -+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); -+ ap_sta_remove(hapd, sta); -+ sta->timeout_next = STA_REMOVE; -+ eloop_cancel_timeout(ap_handle_timer, hapd, sta); -+ eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, -+ ap_handle_timer, hapd, sta); -+ accounting_sta_stop(hapd, sta); -+ ieee802_1x_free_station(sta); -+ -+ mlme_deauthenticate_indication(hapd, sta, reason); -+} -+ -+ -+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, -+ int old_vlanid) -+{ -+#ifndef CONFIG_NO_VLAN -+ const char *iface; -+ struct hostapd_vlan *vlan = NULL; -+ int ret; -+ -+ /* -+ * Do not proceed furthur if the vlan id remains same. We do not want -+ * duplicate dynamic vlan entries. -+ */ -+ if (sta->vlan_id == old_vlanid) -+ return 0; -+ -+ /* -+ * During 1x reauth, if the vlan id changes, then remove the old id and -+ * proceed furthur to add the new one. -+ */ -+ if (old_vlanid > 0) -+ vlan_remove_dynamic(hapd, old_vlanid); -+ -+ iface = hapd->conf->iface; -+ if (sta->ssid->vlan[0]) -+ iface = sta->ssid->vlan; -+ -+ if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) -+ sta->vlan_id = 0; -+ else if (sta->vlan_id > 0) { -+ vlan = hapd->conf->vlan; -+ while (vlan) { -+ if (vlan->vlan_id == sta->vlan_id || -+ vlan->vlan_id == VLAN_ID_WILDCARD) { -+ iface = vlan->ifname; -+ break; -+ } -+ vlan = vlan->next; -+ } -+ } -+ -+ if (sta->vlan_id > 0 && vlan == NULL) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " -+ "binding station to (vlan_id=%d)", -+ sta->vlan_id); -+ return -1; -+ } else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) { -+ vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id); -+ if (vlan == NULL) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "could not add " -+ "dynamic VLAN interface for vlan_id=%d", -+ sta->vlan_id); -+ return -1; -+ } -+ -+ iface = vlan->ifname; -+ if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "could not " -+ "configure encryption for dynamic VLAN " -+ "interface for vlan_id=%d", -+ sta->vlan_id); -+ } -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN " -+ "interface '%s'", iface); -+ } else if (vlan && vlan->vlan_id == sta->vlan_id) { -+ if (sta->vlan_id > 0) { -+ vlan->dynamic_vlan++; -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "updated existing " -+ "dynamic VLAN interface '%s'", iface); -+ } -+ -+ /* -+ * Update encryption configuration for statically generated -+ * VLAN interface. This is only used for static WEP -+ * configuration for the case where hostapd did not yet know -+ * which keys are to be used when the interface was added. -+ */ -+ if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "could not " -+ "configure encryption for VLAN " -+ "interface for vlan_id=%d", -+ sta->vlan_id); -+ } -+ } -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "binding station to interface " -+ "'%s'", iface); -+ -+ if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) -+ wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); -+ -+ ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); -+ if (ret < 0) { -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, "could not bind the STA " -+ "entry to vlan_id=%d", sta->vlan_id); -+ } -+ return ret; -+#else /* CONFIG_NO_VLAN */ -+ return 0; -+#endif /* CONFIG_NO_VLAN */ -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+ -+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ u32 tu; -+ struct os_time now, passed; -+ os_get_time(&now); -+ os_time_sub(&now, &sta->sa_query_start, &passed); -+ tu = (passed.sec * 1000000 + passed.usec) / 1024; -+ if (hapd->conf->assoc_sa_query_max_timeout < tu) { -+ hostapd_logger(hapd, sta->addr, -+ HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "association SA Query timed out"); -+ sta->sa_query_timed_out = 1; -+ os_free(sta->sa_query_trans_id); -+ sta->sa_query_trans_id = NULL; -+ sta->sa_query_count = 0; -+ eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ struct sta_info *sta = timeout_ctx; -+ unsigned int timeout, sec, usec; -+ u8 *trans_id, *nbuf; -+ -+ if (sta->sa_query_count > 0 && -+ ap_check_sa_query_timeout(hapd, sta)) -+ return; -+ -+ nbuf = os_realloc(sta->sa_query_trans_id, -+ (sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN); -+ if (nbuf == NULL) -+ return; -+ if (sta->sa_query_count == 0) { -+ /* Starting a new SA Query procedure */ -+ os_get_time(&sta->sa_query_start); -+ } -+ trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; -+ sta->sa_query_trans_id = nbuf; -+ sta->sa_query_count++; -+ -+ os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN); -+ -+ timeout = hapd->conf->assoc_sa_query_retry_timeout; -+ sec = ((timeout / 1000) * 1024) / 1000; -+ usec = (timeout % 1000) * 1024; -+ eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); -+ -+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "association SA Query attempt %d", sta->sa_query_count); -+ -+#ifdef NEED_AP_MLME -+ ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); -+#endif /* NEED_AP_MLME */ -+} -+ -+ -+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ ap_sa_query_timer(hapd, sta); -+} -+ -+ -+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) -+{ -+ eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); -+ os_free(sta->sa_query_trans_id); -+ sta->sa_query_trans_id = NULL; -+ sta->sa_query_count = 0; -+} -+ -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, -+ int authorized) -+{ -+ if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) -+ return; -+ -+ if (authorized) -+ sta->flags |= WLAN_STA_AUTHORIZED; -+ else -+ sta->flags &= ~WLAN_STA_AUTHORIZED; -+ -+ if (hapd->sta_authorized_cb) -+ hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, -+ sta->addr, authorized); -+} -+ -+ -+void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *addr, u16 reason) -+{ -+ -+ if (sta == NULL && addr) -+ sta = ap_get_sta(hapd, addr); -+ -+ if (addr) -+ hostapd_drv_sta_deauth(hapd, addr, reason); -+ -+ if (sta == NULL) -+ return; -+ ap_sta_set_authorized(hapd, sta, 0); -+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); -+ eloop_cancel_timeout(ap_handle_timer, hapd, sta); -+ eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta); -+ sta->timeout_next = STA_REMOVE; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.h -new file mode 100644 -index 0000000000000..9ec4fe33e40ee ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/sta_info.h -@@ -0,0 +1,165 @@ -+/* -+ * hostapd / Station table -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef STA_INFO_H -+#define STA_INFO_H -+ -+/* STA flags */ -+#define WLAN_STA_AUTH BIT(0) -+#define WLAN_STA_ASSOC BIT(1) -+#define WLAN_STA_PS BIT(2) -+#define WLAN_STA_TIM BIT(3) -+#define WLAN_STA_PERM BIT(4) -+#define WLAN_STA_AUTHORIZED BIT(5) -+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ -+#define WLAN_STA_SHORT_PREAMBLE BIT(7) -+#define WLAN_STA_PREAUTH BIT(8) -+#define WLAN_STA_WMM BIT(9) -+#define WLAN_STA_MFP BIT(10) -+#define WLAN_STA_HT BIT(11) -+#define WLAN_STA_WPS BIT(12) -+#define WLAN_STA_MAYBE_WPS BIT(13) -+#define WLAN_STA_WDS BIT(14) -+#define WLAN_STA_ASSOC_REQ_OK BIT(15) -+#define WLAN_STA_NONERP BIT(31) -+ -+/* Maximum number of supported rates (from both Supported Rates and Extended -+ * Supported Rates IEs). */ -+#define WLAN_SUPP_RATES_MAX 32 -+ -+ -+struct sta_info { -+ struct sta_info *next; /* next entry in sta list */ -+ struct sta_info *hnext; /* next entry in hash table list */ -+ u8 addr[6]; -+ u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ -+ u32 flags; /* Bitfield of WLAN_STA_* */ -+ u16 capability; -+ u16 listen_interval; /* or beacon_int for APs */ -+ u8 supported_rates[WLAN_SUPP_RATES_MAX]; -+ int supported_rates_len; -+ -+ unsigned int nonerp_set:1; -+ unsigned int no_short_slot_time_set:1; -+ unsigned int no_short_preamble_set:1; -+ unsigned int no_ht_gf_set:1; -+ unsigned int no_ht_set:1; -+ unsigned int ht_20mhz_set:1; -+ unsigned int no_p2p_set:1; -+ -+ u16 auth_alg; -+ u8 previous_ap[6]; -+ -+ enum { -+ STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE -+ } timeout_next; -+ -+ /* IEEE 802.1X related data */ -+ struct eapol_state_machine *eapol_sm; -+ -+ /* IEEE 802.11f (IAPP) related data */ -+ struct ieee80211_mgmt *last_assoc_req; -+ -+ u32 acct_session_id_hi; -+ u32 acct_session_id_lo; -+ time_t acct_session_start; -+ int acct_session_started; -+ int acct_terminate_cause; /* Acct-Terminate-Cause */ -+ int acct_interim_interval; /* Acct-Interim-Interval */ -+ -+ unsigned long last_rx_bytes; -+ unsigned long last_tx_bytes; -+ u32 acct_input_gigawords; /* Acct-Input-Gigawords */ -+ u32 acct_output_gigawords; /* Acct-Output-Gigawords */ -+ -+ u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */ -+ -+ struct wpa_state_machine *wpa_sm; -+ struct rsn_preauth_interface *preauth_iface; -+ -+ struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */ -+ struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */ -+ -+ int vlan_id; -+ -+ struct ieee80211_ht_capabilities *ht_capabilities; -+ -+#ifdef CONFIG_IEEE80211W -+ int sa_query_count; /* number of pending SA Query requests; -+ * 0 = no SA Query in progress */ -+ int sa_query_timed_out; -+ u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN * -+ * sa_query_count octets of pending SA Query -+ * transaction identifiers */ -+ struct os_time sa_query_start; -+#endif /* CONFIG_IEEE80211W */ -+ -+ struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */ -+ struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */ -+}; -+ -+ -+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has -+ * passed since last received frame from the station, a nullfunc data frame is -+ * sent to the station. If this frame is not acknowledged and no other frames -+ * have been received, the station will be disassociated after -+ * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated -+ * after AP_DEAUTH_DELAY seconds has passed after disassociation. */ -+#define AP_MAX_INACTIVITY (5 * 60) -+#define AP_DISASSOC_DELAY (1) -+#define AP_DEAUTH_DELAY (1) -+/* Number of seconds to keep STA entry with Authenticated flag after it has -+ * been disassociated. */ -+#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30) -+/* Number of seconds to keep STA entry after it has been deauthenticated. */ -+#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5) -+ -+ -+struct hostapd_data; -+ -+int ap_for_each_sta(struct hostapd_data *hapd, -+ int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, -+ void *ctx), -+ void *ctx); -+struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta); -+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta); -+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta); -+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta); -+void hostapd_free_stas(struct hostapd_data *hapd); -+void ap_handle_timer(void *eloop_ctx, void *timeout_ctx); -+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, -+ u32 session_timeout); -+void ap_sta_no_session_timeout(struct hostapd_data *hapd, -+ struct sta_info *sta); -+struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr); -+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, -+ u16 reason); -+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, -+ u16 reason); -+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, -+ int old_vlanid); -+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta); -+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); -+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); -+void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, -+ const u8 *addr, u16 reason); -+ -+void ap_sta_set_authorized(struct hostapd_data *hapd, -+ struct sta_info *sta, int authorized); -+static inline int ap_sta_is_authorized(struct sta_info *sta) -+{ -+ return sta->flags & WLAN_STA_AUTHORIZED; -+} -+ -+#endif /* STA_INFO_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.c -new file mode 100644 -index 0000000000000..19252171715fc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.c -@@ -0,0 +1,94 @@ -+/* -+ * hostapd / TKIP countermeasures -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "hostapd.h" -+#include "sta_info.h" -+#include "ap_mlme.h" -+#include "wpa_auth.h" -+#include "ap_drv_ops.h" -+#include "tkip_countermeasures.h" -+ -+ -+static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx, -+ void *timeout_ctx) -+{ -+ struct hostapd_data *hapd = eloop_ctx; -+ hapd->tkip_countermeasures = 0; -+ hostapd_drv_set_countermeasures(hapd, 0); -+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended"); -+} -+ -+ -+static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd) -+{ -+ struct sta_info *sta; -+ -+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated"); -+ -+ wpa_auth_countermeasures_start(hapd->wpa_auth); -+ hapd->tkip_countermeasures = 1; -+ hostapd_drv_set_countermeasures(hapd, 1); -+ wpa_gtk_rekey(hapd->wpa_auth); -+ eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL); -+ eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop, -+ hapd, NULL); -+ for (sta = hapd->sta_list; sta != NULL; sta = sta->next) { -+ hostapd_drv_sta_deauth(hapd, sta->addr, -+ WLAN_REASON_MICHAEL_MIC_FAILURE); -+ ap_sta_set_authorized(hapd, sta, 0); -+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); -+ hostapd_drv_sta_remove(hapd, sta->addr); -+ } -+} -+ -+ -+void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local) -+{ -+ time_t now; -+ -+ if (addr && local) { -+ struct sta_info *sta = ap_get_sta(hapd, addr); -+ if (sta != NULL) { -+ wpa_auth_sta_local_mic_failure_report(sta->wpa_sm); -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_INFO, -+ "Michael MIC failure detected in " -+ "received frame"); -+ mlme_michaelmicfailure_indication(hapd, addr); -+ } else { -+ wpa_printf(MSG_DEBUG, -+ "MLME-MICHAELMICFAILURE.indication " -+ "for not associated STA (" MACSTR -+ ") ignored", MAC2STR(addr)); -+ return; -+ } -+ } -+ -+ time(&now); -+ if (now > hapd->michael_mic_failure + 60) { -+ hapd->michael_mic_failures = 1; -+ } else { -+ hapd->michael_mic_failures++; -+ if (hapd->michael_mic_failures > 1) -+ ieee80211_tkip_countermeasures_start(hapd); -+ } -+ hapd->michael_mic_failure = now; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.h -new file mode 100644 -index 0000000000000..5a1afceb03148 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/tkip_countermeasures.h -@@ -0,0 +1,20 @@ -+/* -+ * hostapd / TKIP countermeasures -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TKIP_COUNTERMEASURES_H -+#define TKIP_COUNTERMEASURES_H -+ -+void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local); -+ -+#endif /* TKIP_COUNTERMEASURES_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/utils.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/utils.c -new file mode 100644 -index 0000000000000..0ff48aeb37dee ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/utils.c -@@ -0,0 +1,88 @@ -+/* -+ * AP mode helper functions -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "sta_info.h" -+#include "hostapd.h" -+ -+ -+int hostapd_register_probereq_cb(struct hostapd_data *hapd, -+ int (*cb)(void *ctx, const u8 *sa, -+ const u8 *ie, size_t ie_len), -+ void *ctx) -+{ -+ struct hostapd_probereq_cb *n; -+ -+ n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) * -+ sizeof(struct hostapd_probereq_cb)); -+ if (n == NULL) -+ return -1; -+ -+ hapd->probereq_cb = n; -+ n = &hapd->probereq_cb[hapd->num_probereq_cb]; -+ hapd->num_probereq_cb++; -+ -+ n->cb = cb; -+ n->ctx = ctx; -+ -+ return 0; -+} -+ -+ -+struct prune_data { -+ struct hostapd_data *hapd; -+ const u8 *addr; -+}; -+ -+static int prune_associations(struct hostapd_iface *iface, void *ctx) -+{ -+ struct prune_data *data = ctx; -+ struct sta_info *osta; -+ struct hostapd_data *ohapd; -+ size_t j; -+ -+ for (j = 0; j < iface->num_bss; j++) { -+ ohapd = iface->bss[j]; -+ if (ohapd == data->hapd) -+ continue; -+ osta = ap_get_sta(ohapd, data->addr); -+ if (!osta) -+ continue; -+ -+ ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED); -+ } -+ -+ return 0; -+} -+ -+/** -+ * hostapd_prune_associations - Remove extraneous associations -+ * @hapd: Pointer to BSS data for the most recent association -+ * @addr: Associated STA address -+ * -+ * This function looks through all radios and BSS's for previous -+ * (stale) associations of STA. If any are found they are removed. -+ */ -+void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr) -+{ -+ struct prune_data data; -+ data.hapd = hapd; -+ data.addr = addr; -+ if (hapd->iface->for_each_interface) -+ hapd->iface->for_each_interface(hapd->iface->interfaces, -+ prune_associations, &data); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.c -new file mode 100644 -index 0000000000000..f2f766f22cf31 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.c -@@ -0,0 +1,905 @@ -+/* -+ * hostapd / VLAN initialization -+ * Copyright 2003, Instant802 Networks, Inc. -+ * Copyright 2005-2006, Devicescape Software, Inc. -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ap_drv_ops.h" -+#include "vlan_init.h" -+ -+ -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "drivers/priv_netlink.h" -+#include "utils/eloop.h" -+ -+ -+struct full_dynamic_vlan { -+ int s; /* socket on which to listen for new/removed interfaces. */ -+}; -+ -+ -+static int ifconfig_helper(const char *if_name, int up) -+{ -+ int fd; -+ struct ifreq ifr; -+ -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ); -+ -+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed " -+ "for interface %s: %s", -+ __func__, if_name, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ if (up) -+ ifr.ifr_flags |= IFF_UP; -+ else -+ ifr.ifr_flags &= ~IFF_UP; -+ -+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed " -+ "for interface %s (up=%d): %s", -+ __func__, if_name, up, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+static int ifconfig_up(const char *if_name) -+{ -+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name); -+ return ifconfig_helper(if_name, 1); -+} -+ -+ -+static int ifconfig_down(const char *if_name) -+{ -+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name); -+ return ifconfig_helper(if_name, 0); -+} -+ -+ -+/* -+ * These are only available in recent linux headers (without the leading -+ * underscore). -+ */ -+#define _GET_VLAN_REALDEV_NAME_CMD 8 -+#define _GET_VLAN_VID_CMD 9 -+ -+/* This value should be 256 ONLY. If it is something else, then hostapd -+ * might crash!, as this value has been hard-coded in 2.4.x kernel -+ * bridging code. -+ */ -+#define MAX_BR_PORTS 256 -+ -+static int br_delif(const char *br_name, const char *if_name) -+{ -+ int fd; -+ struct ifreq ifr; -+ unsigned long args[2]; -+ int if_index; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name); -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ if_index = if_nametoindex(if_name); -+ -+ if (if_index == 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " -+ "interface index for '%s'", -+ __func__, if_name); -+ close(fd); -+ return -1; -+ } -+ -+ args[0] = BRCTL_DEL_IF; -+ args[1] = if_index; -+ -+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); -+ ifr.ifr_data = (__caddr_t) args; -+ -+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) { -+ /* No error if interface already removed. */ -+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," -+ "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: " -+ "%s", __func__, br_name, if_name, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+/* -+ Add interface 'if_name' to the bridge 'br_name' -+ -+ returns -1 on error -+ returns 1 if the interface is already part of the bridge -+ returns 0 otherwise -+*/ -+static int br_addif(const char *br_name, const char *if_name) -+{ -+ int fd; -+ struct ifreq ifr; -+ unsigned long args[2]; -+ int if_index; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name); -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ if_index = if_nametoindex(if_name); -+ -+ if (if_index == 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining " -+ "interface index for '%s'", -+ __func__, if_name); -+ close(fd); -+ return -1; -+ } -+ -+ args[0] = BRCTL_ADD_IF; -+ args[1] = if_index; -+ -+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); -+ ifr.ifr_data = (__caddr_t) args; -+ -+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { -+ if (errno == EBUSY) { -+ /* The interface is already added. */ -+ close(fd); -+ return 1; -+ } -+ -+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE," -+ "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: " -+ "%s", __func__, br_name, if_name, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+static int br_delbr(const char *br_name) -+{ -+ int fd; -+ unsigned long arg[2]; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name); -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ arg[0] = BRCTL_DEL_BRIDGE; -+ arg[1] = (unsigned long) br_name; -+ -+ if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) { -+ /* No error if bridge already removed. */ -+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for " -+ "%s: %s", __func__, br_name, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+/* -+ Add a bridge with the name 'br_name'. -+ -+ returns -1 on error -+ returns 1 if the bridge already exists -+ returns 0 otherwise -+*/ -+static int br_addbr(const char *br_name) -+{ -+ int fd; -+ unsigned long arg[4]; -+ struct ifreq ifr; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name); -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ arg[0] = BRCTL_ADD_BRIDGE; -+ arg[1] = (unsigned long) br_name; -+ -+ if (ioctl(fd, SIOCGIFBR, arg) < 0) { -+ if (errno == EEXIST) { -+ /* The bridge is already added. */ -+ close(fd); -+ return 1; -+ } else { -+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE " -+ "failed for %s: %s", -+ __func__, br_name, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ } -+ -+ /* Decrease forwarding delay to avoid EAPOL timeouts. */ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ); -+ arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY; -+ arg[1] = 1; -+ arg[2] = 0; -+ arg[3] = 0; -+ ifr.ifr_data = (char *) &arg; -+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: " -+ "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for " -+ "%s: %s", __func__, br_name, strerror(errno)); -+ /* Continue anyway */ -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+static int br_getnumports(const char *br_name) -+{ -+ int fd; -+ int i; -+ int port_cnt = 0; -+ unsigned long arg[4]; -+ int ifindices[MAX_BR_PORTS]; -+ struct ifreq ifr; -+ -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ arg[0] = BRCTL_GET_PORT_LIST; -+ arg[1] = (unsigned long) ifindices; -+ arg[2] = MAX_BR_PORTS; -+ arg[3] = 0; -+ -+ os_memset(ifindices, 0, sizeof(ifindices)); -+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name)); -+ ifr.ifr_data = (__caddr_t) arg; -+ -+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST " -+ "failed for %s: %s", -+ __func__, br_name, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ for (i = 1; i < MAX_BR_PORTS; i++) { -+ if (ifindices[i] > 0) { -+ port_cnt++; -+ } -+ } -+ -+ close(fd); -+ return port_cnt; -+} -+ -+ -+static int vlan_rem(const char *if_name) -+{ -+ int fd; -+ struct vlan_ioctl_args if_request; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name); -+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { -+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", -+ if_name); -+ return -1; -+ } -+ -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ os_memset(&if_request, 0, sizeof(if_request)); -+ -+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); -+ if_request.cmd = DEL_VLAN_CMD; -+ -+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: " -+ "%s", __func__, if_name, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+/* -+ Add a vlan interface with VLAN ID 'vid' and tagged interface -+ 'if_name'. -+ -+ returns -1 on error -+ returns 1 if the interface already exists -+ returns 0 otherwise -+*/ -+static int vlan_add(const char *if_name, int vid) -+{ -+ int fd; -+ struct vlan_ioctl_args if_request; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)", -+ if_name, vid); -+ ifconfig_up(if_name); -+ -+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { -+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", -+ if_name); -+ return -1; -+ } -+ -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ os_memset(&if_request, 0, sizeof(if_request)); -+ -+ /* Determine if a suitable vlan device already exists. */ -+ -+ os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d", -+ vid); -+ -+ if_request.cmd = _GET_VLAN_VID_CMD; -+ -+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) { -+ -+ if (if_request.u.VID == vid) { -+ if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD; -+ -+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 && -+ os_strncmp(if_request.u.device2, if_name, -+ sizeof(if_request.u.device2)) == 0) { -+ close(fd); -+ wpa_printf(MSG_DEBUG, "VLAN: vlan_add: " -+ "if_name %s exists already", -+ if_request.device1); -+ return 1; -+ } -+ } -+ } -+ -+ /* A suitable vlan device does not already exist, add one. */ -+ -+ os_memset(&if_request, 0, sizeof(if_request)); -+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); -+ if_request.u.VID = vid; -+ if_request.cmd = ADD_VLAN_CMD; -+ -+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: " -+ "%s", -+ __func__, if_request.device1, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+static int vlan_set_name_type(unsigned int name_type) -+{ -+ int fd; -+ struct vlan_ioctl_args if_request; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)", -+ name_type); -+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " -+ "failed: %s", __func__, strerror(errno)); -+ return -1; -+ } -+ -+ os_memset(&if_request, 0, sizeof(if_request)); -+ -+ if_request.u.name_type = name_type; -+ if_request.cmd = SET_VLAN_NAME_TYPE_CMD; -+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD " -+ "name_type=%u failed: %s", -+ __func__, name_type, strerror(errno)); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+ -+static void vlan_newlink(char *ifname, struct hostapd_data *hapd) -+{ -+ char vlan_ifname[IFNAMSIZ]; -+ char br_name[IFNAMSIZ]; -+ struct hostapd_vlan *vlan = hapd->conf->vlan; -+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname); -+ -+ while (vlan) { -+ if (os_strcmp(ifname, vlan->ifname) == 0) { -+ -+ os_snprintf(br_name, sizeof(br_name), "brvlan%d", -+ vlan->vlan_id); -+ -+ if (!br_addbr(br_name)) -+ vlan->clean |= DVLAN_CLEAN_BR; -+ -+ ifconfig_up(br_name); -+ -+ if (tagged_interface) { -+ -+ if (!vlan_add(tagged_interface, vlan->vlan_id)) -+ vlan->clean |= DVLAN_CLEAN_VLAN; -+ -+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), -+ "vlan%d", vlan->vlan_id); -+ -+ if (!br_addif(br_name, vlan_ifname)) -+ vlan->clean |= DVLAN_CLEAN_VLAN_PORT; -+ -+ ifconfig_up(vlan_ifname); -+ } -+ -+ if (!br_addif(br_name, ifname)) -+ vlan->clean |= DVLAN_CLEAN_WLAN_PORT; -+ -+ ifconfig_up(ifname); -+ -+ break; -+ } -+ vlan = vlan->next; -+ } -+} -+ -+ -+static void vlan_dellink(char *ifname, struct hostapd_data *hapd) -+{ -+ char vlan_ifname[IFNAMSIZ]; -+ char br_name[IFNAMSIZ]; -+ struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan; -+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname); -+ -+ first = prev = vlan; -+ -+ while (vlan) { -+ if (os_strcmp(ifname, vlan->ifname) == 0) { -+ os_snprintf(br_name, sizeof(br_name), "brvlan%d", -+ vlan->vlan_id); -+ -+ if (vlan->clean & DVLAN_CLEAN_WLAN_PORT) -+ br_delif(br_name, vlan->ifname); -+ -+ if (tagged_interface) { -+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), -+ "vlan%d", vlan->vlan_id); -+ if (vlan->clean & DVLAN_CLEAN_VLAN_PORT) -+ br_delif(br_name, vlan_ifname); -+ ifconfig_down(vlan_ifname); -+ -+ if (vlan->clean & DVLAN_CLEAN_VLAN) -+ vlan_rem(vlan_ifname); -+ } -+ -+ if ((vlan->clean & DVLAN_CLEAN_BR) && -+ br_getnumports(br_name) == 0) { -+ ifconfig_down(br_name); -+ br_delbr(br_name); -+ } -+ -+ if (vlan == first) { -+ hapd->conf->vlan = vlan->next; -+ } else { -+ prev->next = vlan->next; -+ } -+ os_free(vlan); -+ -+ break; -+ } -+ prev = vlan; -+ vlan = vlan->next; -+ } -+} -+ -+ -+static void -+vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del, -+ struct hostapd_data *hapd) -+{ -+ struct ifinfomsg *ifi; -+ int attrlen, nlmsg_len, rta_len; -+ struct rtattr *attr; -+ -+ if (len < sizeof(*ifi)) -+ return; -+ -+ ifi = NLMSG_DATA(h); -+ -+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); -+ -+ attrlen = h->nlmsg_len - nlmsg_len; -+ if (attrlen < 0) -+ return; -+ -+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ char ifname[IFNAMSIZ + 1]; -+ -+ if (attr->rta_type == IFLA_IFNAME) { -+ int n = attr->rta_len - rta_len; -+ if (n < 0) -+ break; -+ -+ os_memset(ifname, 0, sizeof(ifname)); -+ -+ if ((size_t) n > sizeof(ifname)) -+ n = sizeof(ifname); -+ os_memcpy(ifname, ((char *) attr) + rta_len, n); -+ -+ if (del) -+ vlan_dellink(ifname, hapd); -+ else -+ vlan_newlink(ifname, hapd); -+ } -+ -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+ -+ -+static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ char buf[8192]; -+ int left; -+ struct sockaddr_nl from; -+ socklen_t fromlen; -+ struct nlmsghdr *h; -+ struct hostapd_data *hapd = eloop_ctx; -+ -+ fromlen = sizeof(from); -+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, -+ (struct sockaddr *) &from, &fromlen); -+ if (left < 0) { -+ if (errno != EINTR && errno != EAGAIN) -+ wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s", -+ __func__, strerror(errno)); -+ return; -+ } -+ -+ h = (struct nlmsghdr *) buf; -+ while (left >= (int) sizeof(*h)) { -+ int len, plen; -+ -+ len = h->nlmsg_len; -+ plen = len - sizeof(*h); -+ if (len > left || plen < 0) { -+ wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink " -+ "message: len=%d left=%d plen=%d", -+ len, left, plen); -+ break; -+ } -+ -+ switch (h->nlmsg_type) { -+ case RTM_NEWLINK: -+ vlan_read_ifnames(h, plen, 0, hapd); -+ break; -+ case RTM_DELLINK: -+ vlan_read_ifnames(h, plen, 1, hapd); -+ break; -+ } -+ -+ len = NLMSG_ALIGN(len); -+ left -= len; -+ h = (struct nlmsghdr *) ((char *) h + len); -+ } -+ -+ if (left > 0) { -+ wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of " -+ "netlink message", __func__, left); -+ } -+} -+ -+ -+static struct full_dynamic_vlan * -+full_dynamic_vlan_init(struct hostapd_data *hapd) -+{ -+ struct sockaddr_nl local; -+ struct full_dynamic_vlan *priv; -+ -+ priv = os_zalloc(sizeof(*priv)); -+ if (priv == NULL) -+ return NULL; -+ -+ vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD); -+ -+ priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); -+ if (priv->s < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW," -+ "NETLINK_ROUTE) failed: %s", -+ __func__, strerror(errno)); -+ os_free(priv); -+ return NULL; -+ } -+ -+ os_memset(&local, 0, sizeof(local)); -+ local.nl_family = AF_NETLINK; -+ local.nl_groups = RTMGRP_LINK; -+ if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) { -+ wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s", -+ __func__, strerror(errno)); -+ close(priv->s); -+ os_free(priv); -+ return NULL; -+ } -+ -+ if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL)) -+ { -+ close(priv->s); -+ os_free(priv); -+ return NULL; -+ } -+ -+ return priv; -+} -+ -+ -+static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv) -+{ -+ if (priv == NULL) -+ return; -+ eloop_unregister_read_sock(priv->s); -+ close(priv->s); -+ os_free(priv); -+} -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ -+ -+int vlan_setup_encryption_dyn(struct hostapd_data *hapd, -+ struct hostapd_ssid *mssid, const char *dyn_vlan) -+{ -+ int i; -+ -+ if (dyn_vlan == NULL) -+ return 0; -+ -+ /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own -+ * functions for setting up dynamic broadcast keys. */ -+ for (i = 0; i < 4; i++) { -+ if (mssid->wep.key[i] && -+ hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i, -+ i == mssid->wep.idx, NULL, 0, -+ mssid->wep.key[i], mssid->wep.len[i])) -+ { -+ wpa_printf(MSG_ERROR, "VLAN: Could not set WEP " -+ "encryption for dynamic VLAN"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int vlan_dynamic_add(struct hostapd_data *hapd, -+ struct hostapd_vlan *vlan) -+{ -+ while (vlan) { -+ if (vlan->vlan_id != VLAN_ID_WILDCARD) { -+ if (hostapd_vlan_if_add(hapd, vlan->ifname)) { -+ if (errno != EEXIST) { -+ wpa_printf(MSG_ERROR, "VLAN: Could " -+ "not add VLAN %s: %s", -+ vlan->ifname, -+ strerror(errno)); -+ return -1; -+ } -+ } -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ ifconfig_up(vlan->ifname); -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ } -+ -+ vlan = vlan->next; -+ } -+ -+ return 0; -+} -+ -+ -+static void vlan_dynamic_remove(struct hostapd_data *hapd, -+ struct hostapd_vlan *vlan) -+{ -+ struct hostapd_vlan *next; -+ -+ while (vlan) { -+ next = vlan->next; -+ -+ if (vlan->vlan_id != VLAN_ID_WILDCARD && -+ hostapd_vlan_if_remove(hapd, vlan->ifname)) { -+ wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN " -+ "iface: %s: %s", -+ vlan->ifname, strerror(errno)); -+ } -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ if (vlan->clean) -+ vlan_dellink(vlan->ifname, hapd); -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ -+ vlan = next; -+ } -+} -+ -+ -+int vlan_init(struct hostapd_data *hapd) -+{ -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd); -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ -+ if (vlan_dynamic_add(hapd, hapd->conf->vlan)) -+ return -1; -+ -+ return 0; -+} -+ -+ -+void vlan_deinit(struct hostapd_data *hapd) -+{ -+ vlan_dynamic_remove(hapd, hapd->conf->vlan); -+ -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ full_dynamic_vlan_deinit(hapd->full_dynamic_vlan); -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+} -+ -+ -+struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, -+ struct hostapd_vlan *vlan, -+ int vlan_id) -+{ -+ struct hostapd_vlan *n; -+ char *ifname, *pos; -+ -+ if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID || -+ vlan->vlan_id != VLAN_ID_WILDCARD) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)", -+ __func__, vlan_id, vlan->ifname); -+ ifname = os_strdup(vlan->ifname); -+ if (ifname == NULL) -+ return NULL; -+ pos = os_strchr(ifname, '#'); -+ if (pos == NULL) { -+ os_free(ifname); -+ return NULL; -+ } -+ *pos++ = '\0'; -+ -+ n = os_zalloc(sizeof(*n)); -+ if (n == NULL) { -+ os_free(ifname); -+ return NULL; -+ } -+ -+ n->vlan_id = vlan_id; -+ n->dynamic_vlan = 1; -+ -+ os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, -+ pos); -+ os_free(ifname); -+ -+ if (hostapd_vlan_if_add(hapd, n->ifname)) { -+ os_free(n); -+ return NULL; -+ } -+ -+ n->next = hapd->conf->vlan; -+ hapd->conf->vlan = n; -+ -+#ifdef CONFIG_FULL_DYNAMIC_VLAN -+ ifconfig_up(n->ifname); -+#endif /* CONFIG_FULL_DYNAMIC_VLAN */ -+ -+ return n; -+} -+ -+ -+int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) -+{ -+ struct hostapd_vlan *vlan; -+ -+ if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID) -+ return 1; -+ -+ wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id); -+ -+ vlan = hapd->conf->vlan; -+ while (vlan) { -+ if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) { -+ vlan->dynamic_vlan--; -+ break; -+ } -+ vlan = vlan->next; -+ } -+ -+ if (vlan == NULL) -+ return 1; -+ -+ if (vlan->dynamic_vlan == 0) -+ hostapd_vlan_if_remove(hapd, vlan->ifname); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.h -new file mode 100644 -index 0000000000000..382d5dee4f806 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/vlan_init.h -@@ -0,0 +1,59 @@ -+/* -+ * hostapd / VLAN initialization -+ * Copyright 2003, Instant802 Networks, Inc. -+ * Copyright 2005, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef VLAN_INIT_H -+#define VLAN_INIT_H -+ -+#ifndef CONFIG_NO_VLAN -+int vlan_init(struct hostapd_data *hapd); -+void vlan_deinit(struct hostapd_data *hapd); -+struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, -+ struct hostapd_vlan *vlan, -+ int vlan_id); -+int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id); -+int vlan_setup_encryption_dyn(struct hostapd_data *hapd, -+ struct hostapd_ssid *mssid, -+ const char *dyn_vlan); -+#else /* CONFIG_NO_VLAN */ -+static inline int vlan_init(struct hostapd_data *hapd) -+{ -+ return 0; -+} -+ -+static inline void vlan_deinit(struct hostapd_data *hapd) -+{ -+} -+ -+static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd, -+ struct hostapd_vlan *vlan, -+ int vlan_id) -+{ -+ return NULL; -+} -+ -+static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id) -+{ -+ return -1; -+} -+ -+static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd, -+ struct hostapd_ssid *mssid, -+ const char *dyn_vlan) -+{ -+ return -1; -+} -+#endif /* CONFIG_NO_VLAN */ -+ -+#endif /* VLAN_INIT_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.c -new file mode 100644 -index 0000000000000..a6d9b89855a1e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.c -@@ -0,0 +1,327 @@ -+/* -+ * hostapd / WMM (Wi-Fi Multimedia) -+ * Copyright 2002-2003, Instant802 Networks, Inc. -+ * Copyright 2005-2006, Devicescape Software, Inc. -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "hostapd.h" -+#include "ieee802_11.h" -+#include "sta_info.h" -+#include "ap_config.h" -+#include "ap_drv_ops.h" -+#include "wmm.h" -+ -+ -+/* TODO: maintain separate sequence and fragment numbers for each AC -+ * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA -+ * if only WMM stations are receiving a certain group */ -+ -+ -+static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci) -+{ -+ u8 ret; -+ ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK; -+ if (acm) -+ ret |= WMM_AC_ACM; -+ ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK; -+ return ret; -+} -+ -+ -+static inline u8 wmm_ecw(int ecwmin, int ecwmax) -+{ -+ return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) | -+ ((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK); -+} -+ -+ -+/* -+ * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association -+ * Response frames. -+ */ -+u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) -+{ -+ u8 *pos = eid; -+ struct wmm_parameter_element *wmm = -+ (struct wmm_parameter_element *) (pos + 2); -+ int e; -+ -+ if (!hapd->conf->wmm_enabled) -+ return eid; -+ eid[0] = WLAN_EID_VENDOR_SPECIFIC; -+ wmm->oui[0] = 0x00; -+ wmm->oui[1] = 0x50; -+ wmm->oui[2] = 0xf2; -+ wmm->oui_type = WMM_OUI_TYPE; -+ wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT; -+ wmm->version = WMM_VERSION; -+ wmm->qos_info = hapd->parameter_set_count & 0xf; -+ -+ if (hapd->conf->wmm_uapsd) -+ wmm->qos_info |= 0x80; -+ -+ wmm->reserved = 0; -+ -+ /* fill in a parameter set record for each AC */ -+ for (e = 0; e < 4; e++) { -+ struct wmm_ac_parameter *ac = &wmm->ac[e]; -+ struct hostapd_wmm_ac_params *acp = -+ &hapd->iconf->wmm_ac_params[e]; -+ -+ ac->aci_aifsn = wmm_aci_aifsn(acp->aifs, -+ acp->admission_control_mandatory, -+ e); -+ ac->cw = wmm_ecw(acp->cwmin, acp->cwmax); -+ ac->txop_limit = host_to_le16(acp->txop_limit); -+ } -+ -+ pos = (u8 *) (wmm + 1); -+ eid[1] = pos - eid - 2; /* element length */ -+ -+ return pos; -+} -+ -+ -+/* This function is called when a station sends an association request with -+ * WMM info element. The function returns zero on success or non-zero on any -+ * error in WMM element. eid does not include Element ID and Length octets. */ -+int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len) -+{ -+ struct wmm_information_element *wmm; -+ -+ wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len); -+ -+ if (len < sizeof(struct wmm_information_element)) { -+ wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)", -+ (unsigned long) len); -+ return -1; -+ } -+ -+ wmm = (struct wmm_information_element *) eid; -+ wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x " -+ "OUI type %d OUI sub-type %d version %d QoS info 0x%x", -+ wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type, -+ wmm->oui_subtype, wmm->version, wmm->qos_info); -+ if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT || -+ wmm->version != WMM_VERSION) { -+ wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, -+ const struct wmm_tspec_element *tspec, -+ u8 action_code, u8 dialogue_token, u8 status_code) -+{ -+ u8 buf[256]; -+ struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf; -+ struct wmm_tspec_element *t = (struct wmm_tspec_element *) -+ m->u.action.u.wmm_action.variable; -+ int len; -+ -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "action response - reason %d", status_code); -+ os_memset(buf, 0, sizeof(buf)); -+ m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_ACTION); -+ os_memcpy(m->da, addr, ETH_ALEN); -+ os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); -+ m->u.action.category = WLAN_ACTION_WMM; -+ m->u.action.u.wmm_action.action_code = action_code; -+ m->u.action.u.wmm_action.dialog_token = dialogue_token; -+ m->u.action.u.wmm_action.status_code = status_code; -+ os_memcpy(t, tspec, sizeof(struct wmm_tspec_element)); -+ len = ((u8 *) (t + 1)) - buf; -+ -+ if (hostapd_drv_send_mlme(hapd, m, len) < 0) -+ perror("wmm_send_action: send"); -+} -+ -+ -+int wmm_process_tspec(struct wmm_tspec_element *tspec) -+{ -+ int medium_time, pps, duration; -+ int up, psb, dir, tid; -+ u16 val, surplus; -+ -+ up = (tspec->ts_info[1] >> 3) & 0x07; -+ psb = (tspec->ts_info[1] >> 2) & 0x01; -+ dir = (tspec->ts_info[0] >> 5) & 0x03; -+ tid = (tspec->ts_info[0] >> 1) & 0x0f; -+ wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d", -+ up, psb, dir, tid); -+ val = le_to_host16(tspec->nominal_msdu_size); -+ wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s", -+ val & 0x7fff, val & 0x8000 ? " (fixed)" : ""); -+ wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps", -+ le_to_host32(tspec->mean_data_rate)); -+ wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps", -+ le_to_host32(tspec->minimum_phy_rate)); -+ val = le_to_host16(tspec->surplus_bandwidth_allowance); -+ wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u", -+ val >> 13, 10000 * (val & 0x1fff) / 0x2000); -+ -+ val = le_to_host16(tspec->nominal_msdu_size); -+ if (val == 0) { -+ wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)"); -+ return WMM_ADDTS_STATUS_INVALID_PARAMETERS; -+ } -+ /* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */ -+ pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val; -+ wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d", -+ pps); -+ -+ if (le_to_host32(tspec->minimum_phy_rate) < 1000000) { -+ wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate"); -+ return WMM_ADDTS_STATUS_INVALID_PARAMETERS; -+ } -+ -+ duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 / -+ (le_to_host32(tspec->minimum_phy_rate) / 1000000) + -+ 50 /* FIX: proper SIFS + ACK duration */; -+ -+ /* unsigned binary number with an implicit binary point after the -+ * leftmost 3 bits, i.e., 0x2000 = 1.0 */ -+ surplus = le_to_host16(tspec->surplus_bandwidth_allowance); -+ if (surplus <= 0x2000) { -+ wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not " -+ "greater than unity"); -+ return WMM_ADDTS_STATUS_INVALID_PARAMETERS; -+ } -+ -+ medium_time = surplus * pps * duration / 0x2000; -+ wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time); -+ -+ /* -+ * TODO: store list of granted (and still active) TSPECs and check -+ * whether there is available medium time for this request. For now, -+ * just refuse requests that would by themselves take very large -+ * portion of the available bandwidth. -+ */ -+ if (medium_time > 750000) { -+ wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over " -+ "75%% of available bandwidth"); -+ return WMM_ADDTS_STATUS_REFUSED; -+ } -+ -+ /* Convert to 32 microseconds per second unit */ -+ tspec->medium_time = host_to_le16(medium_time / 32); -+ -+ return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED; -+} -+ -+ -+static void wmm_addts_req(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, -+ struct wmm_tspec_element *tspec, size_t len) -+{ -+ const u8 *end = ((const u8 *) mgmt) + len; -+ int res; -+ -+ if ((const u8 *) (tspec + 1) > end) { -+ wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request"); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC " -+ "from " MACSTR, -+ mgmt->u.action.u.wmm_action.dialog_token, -+ MAC2STR(mgmt->sa)); -+ -+ res = wmm_process_tspec(tspec); -+ wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res); -+ -+ wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP, -+ mgmt->u.action.u.wmm_action.dialog_token, res); -+} -+ -+ -+void hostapd_wmm_action(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len) -+{ -+ int action_code; -+ int left = len - IEEE80211_HDRLEN - 4; -+ const u8 *pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 4; -+ struct ieee802_11_elems elems; -+ struct sta_info *sta = ap_get_sta(hapd, mgmt->sa); -+ -+ /* check that the request comes from a valid station */ -+ if (!sta || -+ (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) != -+ (WLAN_STA_ASSOC | WLAN_STA_WMM)) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "wmm action received is not from associated wmm" -+ " station"); -+ /* TODO: respond with action frame refused status code */ -+ return; -+ } -+ -+ /* extract the tspec info element */ -+ if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "hostapd_wmm_action - could not parse wmm " -+ "action"); -+ /* TODO: respond with action frame invalid parameters status -+ * code */ -+ return; -+ } -+ -+ if (!elems.wmm_tspec || -+ elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) { -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "hostapd_wmm_action - missing or wrong length " -+ "tspec"); -+ /* TODO: respond with action frame invalid parameters status -+ * code */ -+ return; -+ } -+ -+ /* TODO: check the request is for an AC with ACM set, if not, refuse -+ * request */ -+ -+ action_code = mgmt->u.action.u.wmm_action.action_code; -+ switch (action_code) { -+ case WMM_ACTION_CODE_ADDTS_REQ: -+ wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *) -+ (elems.wmm_tspec - 2), len); -+ return; -+#if 0 -+ /* TODO: needed for client implementation */ -+ case WMM_ACTION_CODE_ADDTS_RESP: -+ wmm_setup_request(hapd, mgmt, len); -+ return; -+ /* TODO: handle station teardown requests */ -+ case WMM_ACTION_CODE_DELTS: -+ wmm_teardown(hapd, mgmt, len); -+ return; -+#endif -+ } -+ -+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, -+ HOSTAPD_LEVEL_DEBUG, -+ "hostapd_wmm_action - unknown action code %d", -+ action_code); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.h -new file mode 100644 -index 0000000000000..96b04e8909634 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wmm.h -@@ -0,0 +1,29 @@ -+/* -+ * hostapd / WMM (Wi-Fi Multimedia) -+ * Copyright 2002-2003, Instant802 Networks, Inc. -+ * Copyright 2005-2006, Devicescape Software, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WME_H -+#define WME_H -+ -+struct ieee80211_mgmt; -+struct wmm_tspec_element; -+ -+u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid); -+int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, -+ size_t len); -+void hostapd_wmm_action(struct hostapd_data *hapd, -+ const struct ieee80211_mgmt *mgmt, size_t len); -+int wmm_process_tspec(struct wmm_tspec_element *tspec); -+ -+#endif /* WME_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.c -new file mode 100644 -index 0000000000000..cfb2cada464b0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.c -@@ -0,0 +1,2838 @@ -+/* -+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "utils/state_machine.h" -+#include "common/ieee802_11_defs.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/crypto.h" -+#include "crypto/sha1.h" -+#include "crypto/sha256.h" -+#include "crypto/random.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "ap_config.h" -+#include "ieee802_11.h" -+#include "wpa_auth.h" -+#include "pmksa_cache_auth.h" -+#include "wpa_auth_i.h" -+#include "wpa_auth_ie.h" -+ -+#define STATE_MACHINE_DATA struct wpa_state_machine -+#define STATE_MACHINE_DEBUG_PREFIX "WPA" -+#define STATE_MACHINE_ADDR sm->addr -+ -+ -+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx); -+static int wpa_sm_step(struct wpa_state_machine *sm); -+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len); -+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx); -+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group); -+static void wpa_request_new_ptk(struct wpa_state_machine *sm); -+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group); -+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group); -+ -+static const u32 dot11RSNAConfigGroupUpdateCount = 4; -+static const u32 dot11RSNAConfigPairwiseUpdateCount = 4; -+static const u32 eapol_key_timeout_first = 100; /* ms */ -+static const u32 eapol_key_timeout_subseq = 1000; /* ms */ -+ -+/* TODO: make these configurable */ -+static const int dot11RSNAConfigPMKLifetime = 43200; -+static const int dot11RSNAConfigPMKReauthThreshold = 70; -+static const int dot11RSNAConfigSATimeout = 60; -+ -+ -+static inline void wpa_auth_mic_failure_report( -+ struct wpa_authenticator *wpa_auth, const u8 *addr) -+{ -+ if (wpa_auth->cb.mic_failure_report) -+ wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr); -+} -+ -+ -+static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth, -+ const u8 *addr, wpa_eapol_variable var, -+ int value) -+{ -+ if (wpa_auth->cb.set_eapol) -+ wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value); -+} -+ -+ -+static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, -+ const u8 *addr, wpa_eapol_variable var) -+{ -+ if (wpa_auth->cb.get_eapol == NULL) -+ return -1; -+ return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var); -+} -+ -+ -+static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, -+ const u8 *addr, const u8 *prev_psk) -+{ -+ if (wpa_auth->cb.get_psk == NULL) -+ return NULL; -+ return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk); -+} -+ -+ -+static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, -+ const u8 *addr, u8 *msk, size_t *len) -+{ -+ if (wpa_auth->cb.get_msk == NULL) -+ return -1; -+ return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len); -+} -+ -+ -+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, -+ int vlan_id, -+ enum wpa_alg alg, const u8 *addr, int idx, -+ u8 *key, size_t key_len) -+{ -+ if (wpa_auth->cb.set_key == NULL) -+ return -1; -+ return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx, -+ key, key_len); -+} -+ -+ -+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, -+ const u8 *addr, int idx, u8 *seq) -+{ -+ if (wpa_auth->cb.get_seqnum == NULL) -+ return -1; -+ return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq); -+} -+ -+ -+static inline int -+wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, -+ const u8 *data, size_t data_len, int encrypt) -+{ -+ if (wpa_auth->cb.send_eapol == NULL) -+ return -1; -+ return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len, -+ encrypt); -+} -+ -+ -+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, -+ int (*cb)(struct wpa_state_machine *sm, void *ctx), -+ void *cb_ctx) -+{ -+ if (wpa_auth->cb.for_each_sta == NULL) -+ return 0; -+ return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx); -+} -+ -+ -+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, -+ int (*cb)(struct wpa_authenticator *a, void *ctx), -+ void *cb_ctx) -+{ -+ if (wpa_auth->cb.for_each_auth == NULL) -+ return 0; -+ return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx); -+} -+ -+ -+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, -+ logger_level level, const char *txt) -+{ -+ if (wpa_auth->cb.logger == NULL) -+ return; -+ wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt); -+} -+ -+ -+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, -+ logger_level level, const char *fmt, ...) -+{ -+ char *format; -+ int maxlen; -+ va_list ap; -+ -+ if (wpa_auth->cb.logger == NULL) -+ return; -+ -+ maxlen = os_strlen(fmt) + 100; -+ format = os_malloc(maxlen); -+ if (!format) -+ return; -+ -+ va_start(ap, fmt); -+ vsnprintf(format, maxlen, fmt, ap); -+ va_end(ap); -+ -+ wpa_auth_logger(wpa_auth, addr, level, format); -+ -+ os_free(format); -+} -+ -+ -+static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, -+ const u8 *addr) -+{ -+ if (wpa_auth->cb.disconnect == NULL) -+ return; -+ wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+} -+ -+ -+static int wpa_use_aes_cmac(struct wpa_state_machine *sm) -+{ -+ int ret = 0; -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) -+ ret = 1; -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt)) -+ ret = 1; -+#endif /* CONFIG_IEEE80211W */ -+ return ret; -+} -+ -+ -+static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_authenticator *wpa_auth = eloop_ctx; -+ -+ if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) { -+ wpa_printf(MSG_ERROR, "Failed to get random data for WPA " -+ "initialization."); -+ } else { -+ wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd"); -+ wpa_hexdump_key(MSG_DEBUG, "GMK", -+ wpa_auth->group->GMK, WPA_GMK_LEN); -+ } -+ -+ if (wpa_auth->conf.wpa_gmk_rekey) { -+ eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0, -+ wpa_rekey_gmk, wpa_auth, NULL); -+ } -+} -+ -+ -+static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_authenticator *wpa_auth = eloop_ctx; -+ struct wpa_group *group; -+ -+ wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK"); -+ for (group = wpa_auth->group; group; group = group->next) { -+ group->GTKReKey = TRUE; -+ do { -+ group->changed = FALSE; -+ wpa_group_sm_step(wpa_auth, group); -+ } while (group->changed); -+ } -+ -+ if (wpa_auth->conf.wpa_group_rekey) { -+ eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, -+ 0, wpa_rekey_gtk, wpa_auth, NULL); -+ } -+} -+ -+ -+static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_authenticator *wpa_auth = eloop_ctx; -+ struct wpa_state_machine *sm = timeout_ctx; -+ -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK"); -+ wpa_request_new_ptk(sm); -+ wpa_sm_step(sm); -+} -+ -+ -+static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx) -+{ -+ if (sm->pmksa == ctx) -+ sm->pmksa = NULL; -+ return 0; -+} -+ -+ -+static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, -+ void *ctx) -+{ -+ struct wpa_authenticator *wpa_auth = ctx; -+ wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry); -+} -+ -+ -+static void wpa_group_set_key_len(struct wpa_group *group, int cipher) -+{ -+ switch (cipher) { -+ case WPA_CIPHER_CCMP: -+ group->GTK_len = 16; -+ break; -+ case WPA_CIPHER_TKIP: -+ group->GTK_len = 32; -+ break; -+ case WPA_CIPHER_WEP104: -+ group->GTK_len = 13; -+ break; -+ case WPA_CIPHER_WEP40: -+ group->GTK_len = 5; -+ break; -+ } -+} -+ -+ -+static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ u8 buf[ETH_ALEN + 8 + sizeof(group)]; -+ u8 rkey[32]; -+ -+ if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0) -+ return -1; -+ wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN); -+ -+ /* -+ * Counter = PRF-256(Random number, "Init Counter", -+ * Local MAC Address || Time) -+ */ -+ os_memcpy(buf, wpa_auth->addr, ETH_ALEN); -+ wpa_get_ntp_timestamp(buf + ETH_ALEN); -+ os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group)); -+ if (random_get_bytes(rkey, sizeof(rkey)) < 0) -+ return -1; -+ -+ if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf), -+ group->Counter, WPA_NONCE_LEN) < 0) -+ return -1; -+ wpa_hexdump_key(MSG_DEBUG, "Key Counter", -+ group->Counter, WPA_NONCE_LEN); -+ -+ return 0; -+} -+ -+ -+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, -+ int vlan_id) -+{ -+ struct wpa_group *group; -+ -+ group = os_zalloc(sizeof(struct wpa_group)); -+ if (group == NULL) -+ return NULL; -+ -+ group->GTKAuthenticator = TRUE; -+ group->vlan_id = vlan_id; -+ -+ wpa_group_set_key_len(group, wpa_auth->conf.wpa_group); -+ -+ if (random_pool_ready() != 1) { -+ wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " -+ "for secure operations - update keys later when " -+ "the first station connects"); -+ } -+ -+ /* -+ * Set initial GMK/Counter value here. The actual values that will be -+ * used in negotiations will be set once the first station tries to -+ * connect. This allows more time for collecting additional randomness -+ * on embedded devices. -+ */ -+ if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) { -+ wpa_printf(MSG_ERROR, "Failed to get random data for WPA " -+ "initialization."); -+ os_free(group); -+ return NULL; -+ } -+ -+ group->GInit = TRUE; -+ wpa_group_sm_step(wpa_auth, group); -+ group->GInit = FALSE; -+ wpa_group_sm_step(wpa_auth, group); -+ -+ return group; -+} -+ -+ -+/** -+ * wpa_init - Initialize WPA authenticator -+ * @addr: Authenticator address -+ * @conf: Configuration for WPA authenticator -+ * @cb: Callback functions for WPA authenticator -+ * Returns: Pointer to WPA authenticator data or %NULL on failure -+ */ -+struct wpa_authenticator * wpa_init(const u8 *addr, -+ struct wpa_auth_config *conf, -+ struct wpa_auth_callbacks *cb) -+{ -+ struct wpa_authenticator *wpa_auth; -+ -+ wpa_auth = os_zalloc(sizeof(struct wpa_authenticator)); -+ if (wpa_auth == NULL) -+ return NULL; -+ os_memcpy(wpa_auth->addr, addr, ETH_ALEN); -+ os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); -+ os_memcpy(&wpa_auth->cb, cb, sizeof(*cb)); -+ -+ if (wpa_auth_gen_wpa_ie(wpa_auth)) { -+ wpa_printf(MSG_ERROR, "Could not generate WPA IE."); -+ os_free(wpa_auth); -+ return NULL; -+ } -+ -+ wpa_auth->group = wpa_group_init(wpa_auth, 0); -+ if (wpa_auth->group == NULL) { -+ os_free(wpa_auth->wpa_ie); -+ os_free(wpa_auth); -+ return NULL; -+ } -+ -+ wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb, -+ wpa_auth); -+ if (wpa_auth->pmksa == NULL) { -+ wpa_printf(MSG_ERROR, "PMKSA cache initialization failed."); -+ os_free(wpa_auth->wpa_ie); -+ os_free(wpa_auth); -+ return NULL; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init(); -+ if (wpa_auth->ft_pmk_cache == NULL) { -+ wpa_printf(MSG_ERROR, "FT PMK cache initialization failed."); -+ os_free(wpa_auth->wpa_ie); -+ pmksa_cache_auth_deinit(wpa_auth->pmksa); -+ os_free(wpa_auth); -+ return NULL; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ if (wpa_auth->conf.wpa_gmk_rekey) { -+ eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0, -+ wpa_rekey_gmk, wpa_auth, NULL); -+ } -+ -+ if (wpa_auth->conf.wpa_group_rekey) { -+ eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0, -+ wpa_rekey_gtk, wpa_auth, NULL); -+ } -+ -+ return wpa_auth; -+} -+ -+ -+/** -+ * wpa_deinit - Deinitialize WPA authenticator -+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init() -+ */ -+void wpa_deinit(struct wpa_authenticator *wpa_auth) -+{ -+ struct wpa_group *group, *prev; -+ -+ eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL); -+ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); -+ -+#ifdef CONFIG_PEERKEY -+ while (wpa_auth->stsl_negotiations) -+ wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations); -+#endif /* CONFIG_PEERKEY */ -+ -+ pmksa_cache_auth_deinit(wpa_auth->pmksa); -+ -+#ifdef CONFIG_IEEE80211R -+ wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache); -+ wpa_auth->ft_pmk_cache = NULL; -+#endif /* CONFIG_IEEE80211R */ -+ -+ os_free(wpa_auth->wpa_ie); -+ -+ group = wpa_auth->group; -+ while (group) { -+ prev = group; -+ group = group->next; -+ os_free(prev); -+ } -+ -+ os_free(wpa_auth); -+} -+ -+ -+/** -+ * wpa_reconfig - Update WPA authenticator configuration -+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init() -+ * @conf: Configuration for WPA authenticator -+ */ -+int wpa_reconfig(struct wpa_authenticator *wpa_auth, -+ struct wpa_auth_config *conf) -+{ -+ struct wpa_group *group; -+ if (wpa_auth == NULL) -+ return 0; -+ -+ os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); -+ if (wpa_auth_gen_wpa_ie(wpa_auth)) { -+ wpa_printf(MSG_ERROR, "Could not generate WPA IE."); -+ return -1; -+ } -+ -+ /* -+ * Reinitialize GTK to make sure it is suitable for the new -+ * configuration. -+ */ -+ group = wpa_auth->group; -+ wpa_group_set_key_len(group, wpa_auth->conf.wpa_group); -+ group->GInit = TRUE; -+ wpa_group_sm_step(wpa_auth, group); -+ group->GInit = FALSE; -+ wpa_group_sm_step(wpa_auth, group); -+ -+ return 0; -+} -+ -+ -+struct wpa_state_machine * -+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr) -+{ -+ struct wpa_state_machine *sm; -+ -+ sm = os_zalloc(sizeof(struct wpa_state_machine)); -+ if (sm == NULL) -+ return NULL; -+ os_memcpy(sm->addr, addr, ETH_ALEN); -+ -+ sm->wpa_auth = wpa_auth; -+ sm->group = wpa_auth->group; -+ -+ return sm; -+} -+ -+ -+int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm) -+{ -+ if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) -+ return -1; -+ -+#ifdef CONFIG_IEEE80211R -+ if (sm->ft_completed) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "FT authentication already completed - do not " -+ "start 4-way handshake"); -+ return 0; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ if (sm->started) { -+ os_memset(&sm->key_replay, 0, sizeof(sm->key_replay)); -+ sm->ReAuthenticationRequest = TRUE; -+ return wpa_sm_step(sm); -+ } -+ -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "start authentication"); -+ sm->started = 1; -+ -+ sm->Init = TRUE; -+ if (wpa_sm_step(sm) == 1) -+ return 1; /* should not really happen */ -+ sm->Init = FALSE; -+ sm->AuthenticationRequest = TRUE; -+ return wpa_sm_step(sm); -+} -+ -+ -+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm) -+{ -+ /* WPA/RSN was not used - clear WPA state. This is needed if the STA -+ * reassociates back to the same AP while the previous entry for the -+ * STA has not yet been removed. */ -+ if (sm == NULL) -+ return; -+ -+ sm->wpa_key_mgmt = 0; -+} -+ -+ -+static void wpa_free_sta_sm(struct wpa_state_machine *sm) -+{ -+ if (sm->GUpdateStationKeys) { -+ sm->group->GKeyDoneStations--; -+ sm->GUpdateStationKeys = FALSE; -+ } -+#ifdef CONFIG_IEEE80211R -+ os_free(sm->assoc_resp_ftie); -+#endif /* CONFIG_IEEE80211R */ -+ os_free(sm->last_rx_eapol_key); -+ os_free(sm->wpa_ie); -+ os_free(sm); -+} -+ -+ -+void wpa_auth_sta_deinit(struct wpa_state_machine *sm) -+{ -+ if (sm == NULL) -+ return; -+ -+ if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) { -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "strict rekeying - force GTK rekey since STA " -+ "is leaving"); -+ eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL); -+ eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth, -+ NULL); -+ } -+ -+ eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); -+ sm->pending_1_of_4_timeout = 0; -+ eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); -+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); -+ if (sm->in_step_loop) { -+ /* Must not free state machine while wpa_sm_step() is running. -+ * Freeing will be completed in the end of wpa_sm_step(). */ -+ wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state " -+ "machine deinit for " MACSTR, MAC2STR(sm->addr)); -+ sm->pending_deinit = 1; -+ } else -+ wpa_free_sta_sm(sm); -+} -+ -+ -+static void wpa_request_new_ptk(struct wpa_state_machine *sm) -+{ -+ if (sm == NULL) -+ return; -+ -+ sm->PTKRequest = TRUE; -+ sm->PTK_valid = 0; -+} -+ -+ -+static int wpa_replay_counter_valid(struct wpa_state_machine *sm, -+ const u8 *replay_counter) -+{ -+ int i; -+ for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { -+ if (!sm->key_replay[i].valid) -+ break; -+ if (os_memcmp(replay_counter, sm->key_replay[i].counter, -+ WPA_REPLAY_COUNTER_LEN) == 0) -+ return 1; -+ } -+ return 0; -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, -+ struct wpa_eapol_ie_parse *kde) -+{ -+ struct wpa_ie_data ie; -+ struct rsn_mdie *mdie; -+ -+ if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 || -+ ie.num_pmkid != 1 || ie.pmkid == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in " -+ "FT 4-way handshake message 2/4"); -+ return -1; -+ } -+ -+ os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant", -+ sm->sup_pmk_r1_name, PMKID_LEN); -+ -+ if (!kde->mdie || !kde->ftie) { -+ wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake " -+ "message 2/4", kde->mdie ? "FTIE" : "MDIE"); -+ return -1; -+ } -+ -+ mdie = (struct rsn_mdie *) (kde->mdie + 2); -+ if (kde->mdie[1] < sizeof(struct rsn_mdie) || -+ os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: MDIE mismatch"); -+ return -1; -+ } -+ -+ if (sm->assoc_resp_ftie && -+ (kde->ftie[1] != sm->assoc_resp_ftie[1] || -+ os_memcmp(kde->ftie, sm->assoc_resp_ftie, -+ 2 + sm->assoc_resp_ftie[1]) != 0)) { -+ wpa_printf(MSG_DEBUG, "FT: FTIE mismatch"); -+ wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4", -+ kde->ftie, kde->ftie_len); -+ wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp", -+ sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]); -+ return -1; -+ } -+ -+ return 0; -+} -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+void wpa_receive(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, -+ u8 *data, size_t data_len) -+{ -+ struct ieee802_1x_hdr *hdr; -+ struct wpa_eapol_key *key; -+ u16 key_info, key_data_length; -+ enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST, -+ SMK_M1, SMK_M3, SMK_ERROR } msg; -+ char *msgtxt; -+ struct wpa_eapol_ie_parse kde; -+ int ft; -+ const u8 *eapol_key_ie; -+ size_t eapol_key_ie_len; -+ -+ if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) -+ return; -+ -+ if (data_len < sizeof(*hdr) + sizeof(*key)) -+ return; -+ -+ hdr = (struct ieee802_1x_hdr *) data; -+ key = (struct wpa_eapol_key *) (hdr + 1); -+ key_info = WPA_GET_BE16(key->key_info); -+ key_data_length = WPA_GET_BE16(key->key_data_length); -+ if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) { -+ wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - " -+ "key_data overflow (%d > %lu)", -+ key_data_length, -+ (unsigned long) (data_len - sizeof(*hdr) - -+ sizeof(*key))); -+ return; -+ } -+ -+ if (sm->wpa == WPA_VERSION_WPA2) { -+ if (key->type != EAPOL_KEY_TYPE_RSN) { -+ wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " -+ "unexpected type %d in RSN mode", -+ key->type); -+ return; -+ } -+ } else { -+ if (key->type != EAPOL_KEY_TYPE_WPA) { -+ wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " -+ "unexpected type %d in WPA mode", -+ key->type); -+ return; -+ } -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce, -+ WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter", -+ key->replay_counter, WPA_REPLAY_COUNTER_LEN); -+ -+ /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys -+ * are set */ -+ -+ if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) == -+ (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) { -+ if (key_info & WPA_KEY_INFO_ERROR) { -+ msg = SMK_ERROR; -+ msgtxt = "SMK Error"; -+ } else { -+ msg = SMK_M1; -+ msgtxt = "SMK M1"; -+ } -+ } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { -+ msg = SMK_M3; -+ msgtxt = "SMK M3"; -+ } else if (key_info & WPA_KEY_INFO_REQUEST) { -+ msg = REQUEST; -+ msgtxt = "Request"; -+ } else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) { -+ msg = GROUP_2; -+ msgtxt = "2/2 Group"; -+ } else if (key_data_length == 0) { -+ msg = PAIRWISE_4; -+ msgtxt = "4/4 Pairwise"; -+ } else { -+ msg = PAIRWISE_2; -+ msgtxt = "2/4 Pairwise"; -+ } -+ -+ /* TODO: key_info type validation for PeerKey */ -+ if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 || -+ msg == GROUP_2) { -+ u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK; -+ if (sm->pairwise == WPA_CIPHER_CCMP) { -+ if (wpa_use_aes_cmac(sm) && -+ ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { -+ wpa_auth_logger(wpa_auth, sm->addr, -+ LOGGER_WARNING, -+ "advertised support for " -+ "AES-128-CMAC, but did not " -+ "use it"); -+ return; -+ } -+ -+ if (!wpa_use_aes_cmac(sm) && -+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { -+ wpa_auth_logger(wpa_auth, sm->addr, -+ LOGGER_WARNING, -+ "did not use HMAC-SHA1-AES " -+ "with CCMP"); -+ return; -+ } -+ } -+ } -+ -+ if (key_info & WPA_KEY_INFO_REQUEST) { -+ if (sm->req_replay_counter_used && -+ os_memcmp(key->replay_counter, sm->req_replay_counter, -+ WPA_REPLAY_COUNTER_LEN) <= 0) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, -+ "received EAPOL-Key request with " -+ "replayed counter"); -+ return; -+ } -+ } -+ -+ if (!(key_info & WPA_KEY_INFO_REQUEST) && -+ !wpa_replay_counter_valid(sm, key->replay_counter)) { -+ int i; -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key %s with unexpected " -+ "replay counter", msgtxt); -+ for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { -+ if (!sm->key_replay[i].valid) -+ break; -+ wpa_hexdump(MSG_DEBUG, "pending replay counter", -+ sm->key_replay[i].counter, -+ WPA_REPLAY_COUNTER_LEN); -+ } -+ wpa_hexdump(MSG_DEBUG, "received replay counter", -+ key->replay_counter, WPA_REPLAY_COUNTER_LEN); -+ return; -+ } -+ -+ switch (msg) { -+ case PAIRWISE_2: -+ if (sm->wpa_ptk_state != WPA_PTK_PTKSTART && -+ sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING) { -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key msg 2/4 in " -+ "invalid state (%d) - dropped", -+ sm->wpa_ptk_state); -+ return; -+ } -+ random_add_randomness(key->key_nonce, WPA_NONCE_LEN); -+ if (sm->group->reject_4way_hs_for_entropy) { -+ /* -+ * The system did not have enough entropy to generate -+ * strong random numbers. Reject the first 4-way -+ * handshake(s) and collect some entropy based on the -+ * information from it. Once enough entropy is -+ * available, the next atempt will trigger GMK/Key -+ * Counter update and the station will be allowed to -+ * continue. -+ */ -+ wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to " -+ "collect more entropy for random number " -+ "generation"); -+ sm->group->reject_4way_hs_for_entropy = FALSE; -+ random_mark_pool_ready(); -+ sm->group->first_sta_seen = FALSE; -+ wpa_sta_disconnect(wpa_auth, sm->addr); -+ return; -+ } -+ if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length, -+ &kde) < 0) { -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key msg 2/4 with " -+ "invalid Key Data contents"); -+ return; -+ } -+ if (kde.rsn_ie) { -+ eapol_key_ie = kde.rsn_ie; -+ eapol_key_ie_len = kde.rsn_ie_len; -+ } else { -+ eapol_key_ie = kde.wpa_ie; -+ eapol_key_ie_len = kde.wpa_ie_len; -+ } -+ ft = sm->wpa == WPA_VERSION_WPA2 && -+ wpa_key_mgmt_ft(sm->wpa_key_mgmt); -+ if (sm->wpa_ie == NULL || -+ wpa_compare_rsn_ie(ft, -+ sm->wpa_ie, sm->wpa_ie_len, -+ eapol_key_ie, eapol_key_ie_len)) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "WPA IE from (Re)AssocReq did not " -+ "match with msg 2/4"); -+ if (sm->wpa_ie) { -+ wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq", -+ sm->wpa_ie, sm->wpa_ie_len); -+ } -+ wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4", -+ eapol_key_ie, eapol_key_ie_len); -+ /* MLME-DEAUTHENTICATE.request */ -+ wpa_sta_disconnect(wpa_auth, sm->addr); -+ return; -+ } -+#ifdef CONFIG_IEEE80211R -+ if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { -+ wpa_sta_disconnect(wpa_auth, sm->addr); -+ return; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ break; -+ case PAIRWISE_4: -+ if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || -+ !sm->PTK_valid) { -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key msg 4/4 in " -+ "invalid state (%d) - dropped", -+ sm->wpa_ptk_state); -+ return; -+ } -+ break; -+ case GROUP_2: -+ if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING -+ || !sm->PTK_valid) { -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key msg 2/2 in " -+ "invalid state (%d) - dropped", -+ sm->wpa_ptk_group_state); -+ return; -+ } -+ break; -+#ifdef CONFIG_PEERKEY -+ case SMK_M1: -+ case SMK_M3: -+ case SMK_ERROR: -+ if (!wpa_auth->conf.peerkey) { -+ wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but " -+ "PeerKey use disabled - ignoring message"); -+ return; -+ } -+ if (!sm->PTK_valid) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key msg SMK in " -+ "invalid state - dropped"); -+ return; -+ } -+ break; -+#else /* CONFIG_PEERKEY */ -+ case SMK_M1: -+ case SMK_M3: -+ case SMK_ERROR: -+ return; /* STSL disabled - ignore SMK messages */ -+#endif /* CONFIG_PEERKEY */ -+ case REQUEST: -+ break; -+ } -+ -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "received EAPOL-Key frame (%s)", msgtxt); -+ -+ if (key_info & WPA_KEY_INFO_ACK) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received invalid EAPOL-Key: Key Ack set"); -+ return; -+ } -+ -+ if (!(key_info & WPA_KEY_INFO_MIC)) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received invalid EAPOL-Key: Key MIC not set"); -+ return; -+ } -+ -+ sm->MICVerified = FALSE; -+ if (sm->PTK_valid) { -+ if (wpa_verify_key_mic(&sm->PTK, data, data_len)) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key with invalid MIC"); -+ return; -+ } -+ sm->MICVerified = TRUE; -+ eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); -+ sm->pending_1_of_4_timeout = 0; -+ } -+ -+ if (key_info & WPA_KEY_INFO_REQUEST) { -+ if (sm->MICVerified) { -+ sm->req_replay_counter_used = 1; -+ os_memcpy(sm->req_replay_counter, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ } else { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key request with " -+ "invalid MIC"); -+ return; -+ } -+ -+ /* -+ * TODO: should decrypt key data field if encryption was used; -+ * even though MAC address KDE is not normally encrypted, -+ * supplicant is allowed to encrypt it. -+ */ -+ if (msg == SMK_ERROR) { -+#ifdef CONFIG_PEERKEY -+ wpa_smk_error(wpa_auth, sm, key); -+#endif /* CONFIG_PEERKEY */ -+ return; -+ } else if (key_info & WPA_KEY_INFO_ERROR) { -+ /* Supplicant reported a Michael MIC error */ -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key Error Request " -+ "(STA detected Michael MIC failure)"); -+ wpa_auth_mic_failure_report(wpa_auth, sm->addr); -+ sm->dot11RSNAStatsTKIPRemoteMICFailures++; -+ wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++; -+ /* Error report is not a request for a new key -+ * handshake, but since Authenticator may do it, let's -+ * change the keys now anyway. */ -+ wpa_request_new_ptk(sm); -+ } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key Request for new " -+ "4-Way Handshake"); -+ wpa_request_new_ptk(sm); -+#ifdef CONFIG_PEERKEY -+ } else if (msg == SMK_M1) { -+ wpa_smk_m1(wpa_auth, sm, key); -+#endif /* CONFIG_PEERKEY */ -+ } else if (key_data_length > 0 && -+ wpa_parse_kde_ies((const u8 *) (key + 1), -+ key_data_length, &kde) == 0 && -+ kde.mac_addr) { -+ } else { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, -+ "received EAPOL-Key Request for GTK " -+ "rekeying"); -+ /* FIX: why was this triggering PTK rekeying for the -+ * STA that requested Group Key rekeying?? */ -+ /* wpa_request_new_ptk(sta->wpa_sm); */ -+ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); -+ wpa_rekey_gtk(wpa_auth, NULL); -+ } -+ } else { -+ /* Do not allow the same key replay counter to be reused. This -+ * does also invalidate all other pending replay counters if -+ * retransmissions were used, i.e., we will only process one of -+ * the pending replies and ignore rest if more than one is -+ * received. */ -+ sm->key_replay[0].valid = FALSE; -+ } -+ -+#ifdef CONFIG_PEERKEY -+ if (msg == SMK_M3) { -+ wpa_smk_m3(wpa_auth, sm, key); -+ return; -+ } -+#endif /* CONFIG_PEERKEY */ -+ -+ os_free(sm->last_rx_eapol_key); -+ sm->last_rx_eapol_key = os_malloc(data_len); -+ if (sm->last_rx_eapol_key == NULL) -+ return; -+ os_memcpy(sm->last_rx_eapol_key, data, data_len); -+ sm->last_rx_eapol_key_len = data_len; -+ -+ sm->EAPOLKeyReceived = TRUE; -+ sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); -+ sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); -+ os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); -+ wpa_sm_step(sm); -+} -+ -+ -+static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr, -+ const u8 *gnonce, u8 *gtk, size_t gtk_len) -+{ -+ u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16]; -+ u8 *pos; -+ int ret = 0; -+ -+ /* GTK = PRF-X(GMK, "Group key expansion", -+ * AA || GNonce || Time || random data) -+ * The example described in the IEEE 802.11 standard uses only AA and -+ * GNonce as inputs here. Add some more entropy since this derivation -+ * is done only at the Authenticator and as such, does not need to be -+ * exactly same. -+ */ -+ os_memcpy(data, addr, ETH_ALEN); -+ os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN); -+ pos = data + ETH_ALEN + WPA_NONCE_LEN; -+ wpa_get_ntp_timestamp(pos); -+ pos += 8; -+ if (random_get_bytes(pos, 16) < 0) -+ ret = -1; -+ -+#ifdef CONFIG_IEEE80211W -+ sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len); -+#else /* CONFIG_IEEE80211W */ -+ if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len) -+ < 0) -+ ret = -1; -+#endif /* CONFIG_IEEE80211W */ -+ -+ return ret; -+} -+ -+ -+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_authenticator *wpa_auth = eloop_ctx; -+ struct wpa_state_machine *sm = timeout_ctx; -+ -+ sm->pending_1_of_4_timeout = 0; -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout"); -+ sm->TimeoutEvt = TRUE; -+ wpa_sm_step(sm); -+} -+ -+ -+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, int key_info, -+ const u8 *key_rsc, const u8 *nonce, -+ const u8 *kde, size_t kde_len, -+ int keyidx, int encr, int force_version) -+{ -+ struct ieee802_1x_hdr *hdr; -+ struct wpa_eapol_key *key; -+ size_t len; -+ int alg; -+ int key_data_len, pad_len = 0; -+ u8 *buf, *pos; -+ int version, pairwise; -+ int i; -+ -+ len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key); -+ -+ if (force_version) -+ version = force_version; -+ else if (wpa_use_aes_cmac(sm)) -+ version = WPA_KEY_INFO_TYPE_AES_128_CMAC; -+ else if (sm->pairwise == WPA_CIPHER_CCMP) -+ version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; -+ else -+ version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; -+ -+ pairwise = key_info & WPA_KEY_INFO_KEY_TYPE; -+ -+ wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d " -+ "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d " -+ "encr=%d)", -+ version, -+ (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0, -+ (key_info & WPA_KEY_INFO_MIC) ? 1 : 0, -+ (key_info & WPA_KEY_INFO_ACK) ? 1 : 0, -+ (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0, -+ pairwise, (unsigned long) kde_len, keyidx, encr); -+ -+ key_data_len = kde_len; -+ -+ if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || -+ version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) { -+ pad_len = key_data_len % 8; -+ if (pad_len) -+ pad_len = 8 - pad_len; -+ key_data_len += pad_len + 8; -+ } -+ -+ len += key_data_len; -+ -+ hdr = os_zalloc(len); -+ if (hdr == NULL) -+ return; -+ hdr->version = wpa_auth->conf.eapol_version; -+ hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; -+ hdr->length = host_to_be16(len - sizeof(*hdr)); -+ key = (struct wpa_eapol_key *) (hdr + 1); -+ -+ key->type = sm->wpa == WPA_VERSION_WPA2 ? -+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; -+ key_info |= version; -+ if (encr && sm->wpa == WPA_VERSION_WPA2) -+ key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; -+ if (sm->wpa != WPA_VERSION_WPA2) -+ key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT; -+ WPA_PUT_BE16(key->key_info, key_info); -+ -+ alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group; -+ switch (alg) { -+ case WPA_CIPHER_CCMP: -+ WPA_PUT_BE16(key->key_length, 16); -+ break; -+ case WPA_CIPHER_TKIP: -+ WPA_PUT_BE16(key->key_length, 32); -+ break; -+ case WPA_CIPHER_WEP40: -+ WPA_PUT_BE16(key->key_length, 5); -+ break; -+ case WPA_CIPHER_WEP104: -+ WPA_PUT_BE16(key->key_length, 13); -+ break; -+ } -+ if (key_info & WPA_KEY_INFO_SMK_MESSAGE) -+ WPA_PUT_BE16(key->key_length, 0); -+ -+ /* FIX: STSL: what to use as key_replay_counter? */ -+ for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) { -+ sm->key_replay[i].valid = sm->key_replay[i - 1].valid; -+ os_memcpy(sm->key_replay[i].counter, -+ sm->key_replay[i - 1].counter, -+ WPA_REPLAY_COUNTER_LEN); -+ } -+ inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN); -+ os_memcpy(key->replay_counter, sm->key_replay[0].counter, -+ WPA_REPLAY_COUNTER_LEN); -+ sm->key_replay[0].valid = TRUE; -+ -+ if (nonce) -+ os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN); -+ -+ if (key_rsc) -+ os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN); -+ -+ if (kde && !encr) { -+ os_memcpy(key + 1, kde, kde_len); -+ WPA_PUT_BE16(key->key_data_length, kde_len); -+ } else if (encr && kde) { -+ buf = os_zalloc(key_data_len); -+ if (buf == NULL) { -+ os_free(hdr); -+ return; -+ } -+ pos = buf; -+ os_memcpy(pos, kde, kde_len); -+ pos += kde_len; -+ -+ if (pad_len) -+ *pos++ = 0xdd; -+ -+ wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data", -+ buf, key_data_len); -+ if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || -+ version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { -+ if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, -+ (u8 *) (key + 1))) { -+ os_free(hdr); -+ os_free(buf); -+ return; -+ } -+ WPA_PUT_BE16(key->key_data_length, key_data_len); -+ } else { -+ u8 ek[32]; -+ os_memcpy(key->key_iv, -+ sm->group->Counter + WPA_NONCE_LEN - 16, 16); -+ inc_byte_array(sm->group->Counter, WPA_NONCE_LEN); -+ os_memcpy(ek, key->key_iv, 16); -+ os_memcpy(ek + 16, sm->PTK.kek, 16); -+ os_memcpy(key + 1, buf, key_data_len); -+ rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len); -+ WPA_PUT_BE16(key->key_data_length, key_data_len); -+ } -+ os_free(buf); -+ } -+ -+ if (key_info & WPA_KEY_INFO_MIC) { -+ if (!sm->PTK_valid) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "PTK not valid when sending EAPOL-Key " -+ "frame"); -+ os_free(hdr); -+ return; -+ } -+ wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len, -+ key->key_mic); -+ } -+ -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, -+ 1); -+ wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len, -+ sm->pairwise_set); -+ os_free(hdr); -+} -+ -+ -+static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, int key_info, -+ const u8 *key_rsc, const u8 *nonce, -+ const u8 *kde, size_t kde_len, -+ int keyidx, int encr) -+{ -+ int timeout_ms; -+ int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE; -+ int ctr; -+ -+ if (sm == NULL) -+ return; -+ -+ __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len, -+ keyidx, encr, 0); -+ -+ ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; -+ if (ctr == 1 && wpa_auth->conf.tx_status) -+ timeout_ms = eapol_key_timeout_first; -+ else -+ timeout_ms = eapol_key_timeout_subseq; -+ if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC)) -+ sm->pending_1_of_4_timeout = 1; -+ wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry " -+ "counter %d)", timeout_ms, ctr); -+ eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000, -+ wpa_send_eapol_timeout, wpa_auth, sm); -+} -+ -+ -+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len) -+{ -+ struct ieee802_1x_hdr *hdr; -+ struct wpa_eapol_key *key; -+ u16 key_info; -+ int ret = 0; -+ u8 mic[16]; -+ -+ if (data_len < sizeof(*hdr) + sizeof(*key)) -+ return -1; -+ -+ hdr = (struct ieee802_1x_hdr *) data; -+ key = (struct wpa_eapol_key *) (hdr + 1); -+ key_info = WPA_GET_BE16(key->key_info); -+ os_memcpy(mic, key->key_mic, 16); -+ os_memset(key->key_mic, 0, 16); -+ if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK, -+ data, data_len, key->key_mic) || -+ os_memcmp(mic, key->key_mic, 16) != 0) -+ ret = -1; -+ os_memcpy(key->key_mic, mic, 16); -+ return ret; -+} -+ -+ -+void wpa_remove_ptk(struct wpa_state_machine *sm) -+{ -+ sm->PTK_valid = FALSE; -+ os_memset(&sm->PTK, 0, sizeof(sm->PTK)); -+ wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0); -+ sm->pairwise_set = FALSE; -+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); -+} -+ -+ -+int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event) -+{ -+ int remove_ptk = 1; -+ -+ if (sm == NULL) -+ return -1; -+ -+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "event %d notification", event); -+ -+ switch (event) { -+ case WPA_AUTH: -+ case WPA_ASSOC: -+ break; -+ case WPA_DEAUTH: -+ case WPA_DISASSOC: -+ sm->DeauthenticationRequest = TRUE; -+ break; -+ case WPA_REAUTH: -+ case WPA_REAUTH_EAPOL: -+ if (!sm->started) { -+ /* -+ * When using WPS, we may end up here if the STA -+ * manages to re-associate without the previous STA -+ * entry getting removed. Consequently, we need to make -+ * sure that the WPA state machines gets initialized -+ * properly at this point. -+ */ -+ wpa_printf(MSG_DEBUG, "WPA state machine had not been " -+ "started - initialize now"); -+ sm->started = 1; -+ sm->Init = TRUE; -+ if (wpa_sm_step(sm) == 1) -+ return 1; /* should not really happen */ -+ sm->Init = FALSE; -+ sm->AuthenticationRequest = TRUE; -+ break; -+ } -+ if (sm->GUpdateStationKeys) { -+ /* -+ * Reauthentication cancels the pending group key -+ * update for this STA. -+ */ -+ sm->group->GKeyDoneStations--; -+ sm->GUpdateStationKeys = FALSE; -+ sm->PtkGroupInit = TRUE; -+ } -+ sm->ReAuthenticationRequest = TRUE; -+ break; -+ case WPA_ASSOC_FT: -+#ifdef CONFIG_IEEE80211R -+ wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration " -+ "after association"); -+ wpa_ft_install_ptk(sm); -+ -+ /* Using FT protocol, not WPA auth state machine */ -+ sm->ft_completed = 1; -+ return 0; -+#else /* CONFIG_IEEE80211R */ -+ break; -+#endif /* CONFIG_IEEE80211R */ -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ sm->ft_completed = 0; -+#endif /* CONFIG_IEEE80211R */ -+ -+#ifdef CONFIG_IEEE80211W -+ if (sm->mgmt_frame_prot && event == WPA_AUTH) -+ remove_ptk = 0; -+#endif /* CONFIG_IEEE80211W */ -+ -+ if (remove_ptk) { -+ sm->PTK_valid = FALSE; -+ os_memset(&sm->PTK, 0, sizeof(sm->PTK)); -+ -+ if (event != WPA_REAUTH_EAPOL) -+ wpa_remove_ptk(sm); -+ } -+ -+ return wpa_sm_step(sm); -+} -+ -+ -+static enum wpa_alg wpa_alg_enum(int alg) -+{ -+ switch (alg) { -+ case WPA_CIPHER_CCMP: -+ return WPA_ALG_CCMP; -+ case WPA_CIPHER_TKIP: -+ return WPA_ALG_TKIP; -+ case WPA_CIPHER_WEP104: -+ case WPA_CIPHER_WEP40: -+ return WPA_ALG_WEP; -+ default: -+ return WPA_ALG_NONE; -+ } -+} -+ -+ -+SM_STATE(WPA_PTK, INITIALIZE) -+{ -+ SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk); -+ if (sm->Init) { -+ /* Init flag is not cleared here, so avoid busy -+ * loop by claiming nothing changed. */ -+ sm->changed = FALSE; -+ } -+ -+ sm->keycount = 0; -+ if (sm->GUpdateStationKeys) -+ sm->group->GKeyDoneStations--; -+ sm->GUpdateStationKeys = FALSE; -+ if (sm->wpa == WPA_VERSION_WPA) -+ sm->PInitAKeys = FALSE; -+ if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and -+ * Local AA > Remote AA)) */) { -+ sm->Pair = TRUE; -+ } -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0); -+ wpa_remove_ptk(sm); -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0); -+ sm->TimeoutCtr = 0; -+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, -+ WPA_EAPOL_authorized, 0); -+ } -+} -+ -+ -+SM_STATE(WPA_PTK, DISCONNECT) -+{ -+ SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk); -+ sm->Disconnect = FALSE; -+ wpa_sta_disconnect(sm->wpa_auth, sm->addr); -+} -+ -+ -+SM_STATE(WPA_PTK, DISCONNECTED) -+{ -+ SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk); -+ sm->DeauthenticationRequest = FALSE; -+} -+ -+ -+SM_STATE(WPA_PTK, AUTHENTICATION) -+{ -+ SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk); -+ os_memset(&sm->PTK, 0, sizeof(sm->PTK)); -+ sm->PTK_valid = FALSE; -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto, -+ 1); -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1); -+ sm->AuthenticationRequest = FALSE; -+} -+ -+ -+static void wpa_group_first_station(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ /* -+ * System has run bit further than at the time hostapd was started -+ * potentially very early during boot up. This provides better chances -+ * of collecting more randomness on embedded systems. Re-initialize the -+ * GMK and Counter here to improve their strength if there was not -+ * enough entropy available immediately after system startup. -+ */ -+ wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first " -+ "station"); -+ if (random_pool_ready() != 1) { -+ wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " -+ "to proceed - reject first 4-way handshake"); -+ group->reject_4way_hs_for_entropy = TRUE; -+ } -+ wpa_group_init_gmk_and_counter(wpa_auth, group); -+ wpa_gtk_update(wpa_auth, group); -+ wpa_group_config_group_keys(wpa_auth, group); -+} -+ -+ -+SM_STATE(WPA_PTK, AUTHENTICATION2) -+{ -+ SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk); -+ -+ if (!sm->group->first_sta_seen) { -+ wpa_group_first_station(sm->wpa_auth, sm->group); -+ sm->group->first_sta_seen = TRUE; -+ } -+ -+ os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce, -+ WPA_NONCE_LEN); -+ inc_byte_array(sm->group->Counter, WPA_NONCE_LEN); -+ sm->ReAuthenticationRequest = FALSE; -+ /* IEEE 802.11i does not clear TimeoutCtr here, but this is more -+ * logical place than INITIALIZE since AUTHENTICATION2 can be -+ * re-entered on ReAuthenticationRequest without going through -+ * INITIALIZE. */ -+ sm->TimeoutCtr = 0; -+} -+ -+ -+SM_STATE(WPA_PTK, INITPMK) -+{ -+ u8 msk[2 * PMK_LEN]; -+ size_t len = 2 * PMK_LEN; -+ -+ SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk); -+#ifdef CONFIG_IEEE80211R -+ sm->xxkey_len = 0; -+#endif /* CONFIG_IEEE80211R */ -+ if (sm->pmksa) { -+ wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache"); -+ os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN); -+ } else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) { -+ wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine " -+ "(len=%lu)", (unsigned long) len); -+ os_memcpy(sm->PMK, msk, PMK_LEN); -+#ifdef CONFIG_IEEE80211R -+ if (len >= 2 * PMK_LEN) { -+ os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN); -+ sm->xxkey_len = PMK_LEN; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ } else { -+ wpa_printf(MSG_DEBUG, "WPA: Could not get PMK"); -+ } -+ -+ sm->req_replay_counter_used = 0; -+ /* IEEE 802.11i does not set keyRun to FALSE, but not doing this -+ * will break reauthentication since EAPOL state machines may not be -+ * get into AUTHENTICATING state that clears keyRun before WPA state -+ * machine enters AUTHENTICATION2 state and goes immediately to INITPMK -+ * state and takes PMK from the previously used AAA Key. This will -+ * eventually fail in 4-Way Handshake because Supplicant uses PMK -+ * derived from the new AAA Key. Setting keyRun = FALSE here seems to -+ * be good workaround for this issue. */ -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0); -+} -+ -+ -+SM_STATE(WPA_PTK, INITPSK) -+{ -+ const u8 *psk; -+ SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk); -+ psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL); -+ if (psk) { -+ os_memcpy(sm->PMK, psk, PMK_LEN); -+#ifdef CONFIG_IEEE80211R -+ os_memcpy(sm->xxkey, psk, PMK_LEN); -+ sm->xxkey_len = PMK_LEN; -+#endif /* CONFIG_IEEE80211R */ -+ } -+ sm->req_replay_counter_used = 0; -+} -+ -+ -+SM_STATE(WPA_PTK, PTKSTART) -+{ -+ u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL; -+ size_t pmkid_len = 0; -+ -+ SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk); -+ sm->PTKRequest = FALSE; -+ sm->TimeoutEvt = FALSE; -+ -+ sm->TimeoutCtr++; -+ if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { -+ /* No point in sending the EAPOL-Key - we will disconnect -+ * immediately following this. */ -+ return; -+ } -+ -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "sending 1/4 msg of 4-Way Handshake"); -+ /* -+ * TODO: Could add PMKID even with WPA2-PSK, but only if there is only -+ * one possible PSK for this STA. -+ */ -+ if (sm->wpa == WPA_VERSION_WPA2 && -+ wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) { -+ pmkid = buf; -+ pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; -+ pmkid[0] = WLAN_EID_VENDOR_SPECIFIC; -+ pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN; -+ RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID); -+ if (sm->pmksa) -+ os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN], -+ sm->pmksa->pmkid, PMKID_LEN); -+ else { -+ /* -+ * Calculate PMKID since no PMKSA cache entry was -+ * available with pre-calculated PMKID. -+ */ -+ rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr, -+ sm->addr, &pmkid[2 + RSN_SELECTOR_LEN], -+ wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); -+ } -+ } -+ wpa_send_eapol(sm->wpa_auth, sm, -+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL, -+ sm->ANonce, pmkid, pmkid_len, 0, 0); -+} -+ -+ -+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk, -+ struct wpa_ptk *ptk) -+{ -+ size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64; -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) -+ return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len); -+#endif /* CONFIG_IEEE80211R */ -+ -+ wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion", -+ sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce, -+ (u8 *) ptk, ptk_len, -+ wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); -+ -+ return 0; -+} -+ -+ -+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) -+{ -+ struct wpa_ptk PTK; -+ int ok = 0; -+ const u8 *pmk = NULL; -+ -+ SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); -+ sm->EAPOLKeyReceived = FALSE; -+ -+ /* WPA with IEEE 802.1X: use the derived PMK from EAP -+ * WPA-PSK: iterate through possible PSKs and select the one matching -+ * the packet */ -+ for (;;) { -+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { -+ pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk); -+ if (pmk == NULL) -+ break; -+ } else -+ pmk = sm->PMK; -+ -+ wpa_derive_ptk(sm, pmk, &PTK); -+ -+ if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key, -+ sm->last_rx_eapol_key_len) == 0) { -+ ok = 1; -+ break; -+ } -+ -+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) -+ break; -+ } -+ -+ if (!ok) { -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "invalid MIC in msg 2/4 of 4-Way Handshake"); -+ return; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { -+ /* -+ * Verify that PMKR1Name from EAPOL-Key message 2/4 matches -+ * with the value we derived. -+ */ -+ if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name, -+ WPA_PMK_NAME_LEN) != 0) { -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "PMKR1Name mismatch in FT 4-way " -+ "handshake"); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from " -+ "Supplicant", -+ sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", -+ sm->pmk_r1_name, WPA_PMK_NAME_LEN); -+ return; -+ } -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ sm->pending_1_of_4_timeout = 0; -+ eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); -+ -+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { -+ /* PSK may have changed from the previous choice, so update -+ * state machine data based on whatever PSK was selected here. -+ */ -+ os_memcpy(sm->PMK, pmk, PMK_LEN); -+ } -+ -+ sm->MICVerified = TRUE; -+ -+ os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); -+ sm->PTK_valid = TRUE; -+} -+ -+ -+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2) -+{ -+ SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk); -+ sm->TimeoutCtr = 0; -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+ -+static int ieee80211w_kde_len(struct wpa_state_machine *sm) -+{ -+ if (sm->mgmt_frame_prot) { -+ return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde); -+ } -+ -+ return 0; -+} -+ -+ -+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) -+{ -+ struct wpa_igtk_kde igtk; -+ struct wpa_group *gsm = sm->group; -+ -+ if (!sm->mgmt_frame_prot) -+ return pos; -+ -+ igtk.keyid[0] = gsm->GN_igtk; -+ igtk.keyid[1] = 0; -+ if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || -+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0) -+ os_memset(igtk.pn, 0, sizeof(igtk.pn)); -+ os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK, -+ (const u8 *) &igtk, sizeof(igtk), NULL, 0); -+ -+ return pos; -+} -+ -+#else /* CONFIG_IEEE80211W */ -+ -+static int ieee80211w_kde_len(struct wpa_state_machine *sm) -+{ -+ return 0; -+} -+ -+ -+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) -+{ -+ return pos; -+} -+ -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+SM_STATE(WPA_PTK, PTKINITNEGOTIATING) -+{ -+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos; -+ size_t gtk_len, kde_len; -+ struct wpa_group *gsm = sm->group; -+ u8 *wpa_ie; -+ int wpa_ie_len, secure, keyidx, encr = 0; -+ -+ SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); -+ sm->TimeoutEvt = FALSE; -+ -+ sm->TimeoutCtr++; -+ if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) { -+ /* No point in sending the EAPOL-Key - we will disconnect -+ * immediately following this. */ -+ return; -+ } -+ -+ /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], -+ GTK[GN], IGTK, [FTIE], [TIE * 2]) -+ */ -+ os_memset(rsc, 0, WPA_KEY_RSC_LEN); -+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); -+ /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */ -+ wpa_ie = sm->wpa_auth->wpa_ie; -+ wpa_ie_len = sm->wpa_auth->wpa_ie_len; -+ if (sm->wpa == WPA_VERSION_WPA && -+ (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) && -+ wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) { -+ /* WPA-only STA, remove RSN IE */ -+ wpa_ie = wpa_ie + wpa_ie[1] + 2; -+ wpa_ie_len = wpa_ie[1] + 2; -+ } -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "sending 3/4 msg of 4-Way Handshake"); -+ if (sm->wpa == WPA_VERSION_WPA2) { -+ /* WPA2 send GTK in the 4-way handshake */ -+ secure = 1; -+ gtk = gsm->GTK[gsm->GN - 1]; -+ gtk_len = gsm->GTK_len; -+ keyidx = gsm->GN; -+ _rsc = rsc; -+ encr = 1; -+ } else { -+ /* WPA does not include GTK in msg 3/4 */ -+ secure = 0; -+ gtk = NULL; -+ gtk_len = 0; -+ keyidx = 0; -+ _rsc = NULL; -+ } -+ -+ kde_len = wpa_ie_len + ieee80211w_kde_len(sm); -+ if (gtk) -+ kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { -+ kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */ -+ kde_len += 300; /* FTIE + 2 * TIE */ -+ } -+#endif /* CONFIG_IEEE80211R */ -+ kde = os_malloc(kde_len); -+ if (kde == NULL) -+ return; -+ -+ pos = kde; -+ os_memcpy(pos, wpa_ie, wpa_ie_len); -+ pos += wpa_ie_len; -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { -+ int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name); -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "FT: Failed to insert " -+ "PMKR1Name into RSN IE in EAPOL-Key data"); -+ os_free(kde); -+ return; -+ } -+ pos += res; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ if (gtk) { -+ u8 hdr[2]; -+ hdr[0] = keyidx & 0x03; -+ hdr[1] = 0; -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, -+ gtk, gtk_len); -+ } -+ pos = ieee80211w_kde_add(sm, pos); -+ -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { -+ int res; -+ struct wpa_auth_config *conf; -+ -+ conf = &sm->wpa_auth->conf; -+ res = wpa_write_ftie(conf, conf->r0_key_holder, -+ conf->r0_key_holder_len, -+ NULL, NULL, pos, kde + kde_len - pos, -+ NULL, 0); -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " -+ "into EAPOL-Key Key Data"); -+ os_free(kde); -+ return; -+ } -+ pos += res; -+ -+ /* TIE[ReassociationDeadline] (TU) */ -+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL; -+ *pos++ = 5; -+ *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE; -+ WPA_PUT_LE32(pos, conf->reassociation_deadline); -+ pos += 4; -+ -+ /* TIE[KeyLifetime] (seconds) */ -+ *pos++ = WLAN_EID_TIMEOUT_INTERVAL; -+ *pos++ = 5; -+ *pos++ = WLAN_TIMEOUT_KEY_LIFETIME; -+ WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60); -+ pos += 4; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ wpa_send_eapol(sm->wpa_auth, sm, -+ (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | -+ WPA_KEY_INFO_KEY_TYPE, -+ _rsc, sm->ANonce, kde, pos - kde, keyidx, encr); -+ os_free(kde); -+} -+ -+ -+SM_STATE(WPA_PTK, PTKINITDONE) -+{ -+ SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk); -+ sm->EAPOLKeyReceived = FALSE; -+ if (sm->Pair) { -+ enum wpa_alg alg; -+ int klen; -+ if (sm->pairwise == WPA_CIPHER_TKIP) { -+ alg = WPA_ALG_TKIP; -+ klen = 32; -+ } else { -+ alg = WPA_ALG_CCMP; -+ klen = 16; -+ } -+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, -+ sm->PTK.tk1, klen)) { -+ wpa_sta_disconnect(sm->wpa_auth, sm->addr); -+ return; -+ } -+ /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ -+ sm->pairwise_set = TRUE; -+ -+ if (sm->wpa_auth->conf.wpa_ptk_rekey) { -+ eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); -+ eloop_register_timeout(sm->wpa_auth->conf. -+ wpa_ptk_rekey, 0, wpa_rekey_ptk, -+ sm->wpa_auth, sm); -+ } -+ -+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) { -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, -+ WPA_EAPOL_authorized, 1); -+ } -+ } -+ -+ if (0 /* IBSS == TRUE */) { -+ sm->keycount++; -+ if (sm->keycount == 2) { -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, -+ WPA_EAPOL_portValid, 1); -+ } -+ } else { -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, -+ 1); -+ } -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0); -+ wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1); -+ if (sm->wpa == WPA_VERSION_WPA) -+ sm->PInitAKeys = TRUE; -+ else -+ sm->has_GTK = TRUE; -+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO, -+ "pairwise key handshake completed (%s)", -+ sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN"); -+ -+#ifdef CONFIG_IEEE80211R -+ wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr); -+#endif /* CONFIG_IEEE80211R */ -+} -+ -+ -+SM_STEP(WPA_PTK) -+{ -+ struct wpa_authenticator *wpa_auth = sm->wpa_auth; -+ -+ if (sm->Init) -+ SM_ENTER(WPA_PTK, INITIALIZE); -+ else if (sm->Disconnect -+ /* || FIX: dot11RSNAConfigSALifetime timeout */) { -+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "WPA_PTK: sm->Disconnect"); -+ SM_ENTER(WPA_PTK, DISCONNECT); -+ } -+ else if (sm->DeauthenticationRequest) -+ SM_ENTER(WPA_PTK, DISCONNECTED); -+ else if (sm->AuthenticationRequest) -+ SM_ENTER(WPA_PTK, AUTHENTICATION); -+ else if (sm->ReAuthenticationRequest) -+ SM_ENTER(WPA_PTK, AUTHENTICATION2); -+ else if (sm->PTKRequest) -+ SM_ENTER(WPA_PTK, PTKSTART); -+ else switch (sm->wpa_ptk_state) { -+ case WPA_PTK_INITIALIZE: -+ break; -+ case WPA_PTK_DISCONNECT: -+ SM_ENTER(WPA_PTK, DISCONNECTED); -+ break; -+ case WPA_PTK_DISCONNECTED: -+ SM_ENTER(WPA_PTK, INITIALIZE); -+ break; -+ case WPA_PTK_AUTHENTICATION: -+ SM_ENTER(WPA_PTK, AUTHENTICATION2); -+ break; -+ case WPA_PTK_AUTHENTICATION2: -+ if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) && -+ wpa_auth_get_eapol(sm->wpa_auth, sm->addr, -+ WPA_EAPOL_keyRun) > 0) -+ SM_ENTER(WPA_PTK, INITPMK); -+ else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) -+ /* FIX: && 802.1X::keyRun */) -+ SM_ENTER(WPA_PTK, INITPSK); -+ break; -+ case WPA_PTK_INITPMK: -+ if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr, -+ WPA_EAPOL_keyAvailable) > 0) -+ SM_ENTER(WPA_PTK, PTKSTART); -+ else { -+ wpa_auth->dot11RSNA4WayHandshakeFailures++; -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, -+ "INITPMK - keyAvailable = false"); -+ SM_ENTER(WPA_PTK, DISCONNECT); -+ } -+ break; -+ case WPA_PTK_INITPSK: -+ if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL)) -+ SM_ENTER(WPA_PTK, PTKSTART); -+ else { -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, -+ "no PSK configured for the STA"); -+ wpa_auth->dot11RSNA4WayHandshakeFailures++; -+ SM_ENTER(WPA_PTK, DISCONNECT); -+ } -+ break; -+ case WPA_PTK_PTKSTART: -+ if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && -+ sm->EAPOLKeyPairwise) -+ SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); -+ else if (sm->TimeoutCtr > -+ (int) dot11RSNAConfigPairwiseUpdateCount) { -+ wpa_auth->dot11RSNA4WayHandshakeFailures++; -+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "PTKSTART: Retry limit %d reached", -+ dot11RSNAConfigPairwiseUpdateCount); -+ SM_ENTER(WPA_PTK, DISCONNECT); -+ } else if (sm->TimeoutEvt) -+ SM_ENTER(WPA_PTK, PTKSTART); -+ break; -+ case WPA_PTK_PTKCALCNEGOTIATING: -+ if (sm->MICVerified) -+ SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2); -+ else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && -+ sm->EAPOLKeyPairwise) -+ SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); -+ else if (sm->TimeoutEvt) -+ SM_ENTER(WPA_PTK, PTKSTART); -+ break; -+ case WPA_PTK_PTKCALCNEGOTIATING2: -+ SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); -+ break; -+ case WPA_PTK_PTKINITNEGOTIATING: -+ if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && -+ sm->EAPOLKeyPairwise && sm->MICVerified) -+ SM_ENTER(WPA_PTK, PTKINITDONE); -+ else if (sm->TimeoutCtr > -+ (int) dot11RSNAConfigPairwiseUpdateCount) { -+ wpa_auth->dot11RSNA4WayHandshakeFailures++; -+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "PTKINITNEGOTIATING: Retry limit %d " -+ "reached", -+ dot11RSNAConfigPairwiseUpdateCount); -+ SM_ENTER(WPA_PTK, DISCONNECT); -+ } else if (sm->TimeoutEvt) -+ SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); -+ break; -+ case WPA_PTK_PTKINITDONE: -+ break; -+ } -+} -+ -+ -+SM_STATE(WPA_PTK_GROUP, IDLE) -+{ -+ SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group); -+ if (sm->Init) { -+ /* Init flag is not cleared here, so avoid busy -+ * loop by claiming nothing changed. */ -+ sm->changed = FALSE; -+ } -+ sm->GTimeoutCtr = 0; -+} -+ -+ -+SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) -+{ -+ u8 rsc[WPA_KEY_RSC_LEN]; -+ struct wpa_group *gsm = sm->group; -+ u8 *kde, *pos, hdr[2]; -+ size_t kde_len; -+ -+ SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group); -+ -+ sm->GTimeoutCtr++; -+ if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) { -+ /* No point in sending the EAPOL-Key - we will disconnect -+ * immediately following this. */ -+ return; -+ } -+ -+ if (sm->wpa == WPA_VERSION_WPA) -+ sm->PInitAKeys = FALSE; -+ sm->TimeoutEvt = FALSE; -+ /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ -+ os_memset(rsc, 0, WPA_KEY_RSC_LEN); -+ if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE) -+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "sending 1/2 msg of Group Key Handshake"); -+ -+ if (sm->wpa == WPA_VERSION_WPA2) { -+ kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + -+ ieee80211w_kde_len(sm); -+ kde = os_malloc(kde_len); -+ if (kde == NULL) -+ return; -+ -+ pos = kde; -+ hdr[0] = gsm->GN & 0x03; -+ hdr[1] = 0; -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, -+ gsm->GTK[gsm->GN - 1], gsm->GTK_len); -+ pos = ieee80211w_kde_add(sm, pos); -+ } else { -+ kde = gsm->GTK[gsm->GN - 1]; -+ pos = kde + gsm->GTK_len; -+ } -+ -+ wpa_send_eapol(sm->wpa_auth, sm, -+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_ACK | -+ (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), -+ rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1); -+ if (sm->wpa == WPA_VERSION_WPA2) -+ os_free(kde); -+} -+ -+ -+SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) -+{ -+ SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group); -+ sm->EAPOLKeyReceived = FALSE; -+ if (sm->GUpdateStationKeys) -+ sm->group->GKeyDoneStations--; -+ sm->GUpdateStationKeys = FALSE; -+ sm->GTimeoutCtr = 0; -+ /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */ -+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO, -+ "group key handshake completed (%s)", -+ sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN"); -+ sm->has_GTK = TRUE; -+} -+ -+ -+SM_STATE(WPA_PTK_GROUP, KEYERROR) -+{ -+ SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group); -+ if (sm->GUpdateStationKeys) -+ sm->group->GKeyDoneStations--; -+ sm->GUpdateStationKeys = FALSE; -+ sm->Disconnect = TRUE; -+} -+ -+ -+SM_STEP(WPA_PTK_GROUP) -+{ -+ if (sm->Init || sm->PtkGroupInit) { -+ SM_ENTER(WPA_PTK_GROUP, IDLE); -+ sm->PtkGroupInit = FALSE; -+ } else switch (sm->wpa_ptk_group_state) { -+ case WPA_PTK_GROUP_IDLE: -+ if (sm->GUpdateStationKeys || -+ (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys)) -+ SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING); -+ break; -+ case WPA_PTK_GROUP_REKEYNEGOTIATING: -+ if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && -+ !sm->EAPOLKeyPairwise && sm->MICVerified) -+ SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED); -+ else if (sm->GTimeoutCtr > -+ (int) dot11RSNAConfigGroupUpdateCount) -+ SM_ENTER(WPA_PTK_GROUP, KEYERROR); -+ else if (sm->TimeoutEvt) -+ SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING); -+ break; -+ case WPA_PTK_GROUP_KEYERROR: -+ SM_ENTER(WPA_PTK_GROUP, IDLE); -+ break; -+ case WPA_PTK_GROUP_REKEYESTABLISHED: -+ SM_ENTER(WPA_PTK_GROUP, IDLE); -+ break; -+ } -+} -+ -+ -+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ int ret = 0; -+ -+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); -+ inc_byte_array(group->Counter, WPA_NONCE_LEN); -+ if (wpa_gmk_to_gtk(group->GMK, "Group key expansion", -+ wpa_auth->addr, group->GNonce, -+ group->GTK[group->GN - 1], group->GTK_len) < 0) -+ ret = -1; -+ wpa_hexdump_key(MSG_DEBUG, "GTK", -+ group->GTK[group->GN - 1], group->GTK_len); -+ -+#ifdef CONFIG_IEEE80211W -+ if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { -+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); -+ inc_byte_array(group->Counter, WPA_NONCE_LEN); -+ if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion", -+ wpa_auth->addr, group->GNonce, -+ group->IGTK[group->GN_igtk - 4], -+ WPA_IGTK_LEN) < 0) -+ ret = -1; -+ wpa_hexdump_key(MSG_DEBUG, "IGTK", -+ group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN); -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ return ret; -+} -+ -+ -+static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " -+ "GTK_INIT (VLAN-ID %d)", group->vlan_id); -+ group->changed = FALSE; /* GInit is not cleared here; avoid loop */ -+ group->wpa_group_state = WPA_GROUP_GTK_INIT; -+ -+ /* GTK[0..N] = 0 */ -+ os_memset(group->GTK, 0, sizeof(group->GTK)); -+ group->GN = 1; -+ group->GM = 2; -+#ifdef CONFIG_IEEE80211W -+ group->GN_igtk = 4; -+ group->GM_igtk = 5; -+#endif /* CONFIG_IEEE80211W */ -+ /* GTK[GN] = CalcGTK() */ -+ wpa_gtk_update(wpa_auth, group); -+} -+ -+ -+static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) -+{ -+ if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) { -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "Not in PTKINITDONE; skip Group Key update"); -+ sm->GUpdateStationKeys = FALSE; -+ return 0; -+ } -+ if (sm->GUpdateStationKeys) { -+ /* -+ * This should not really happen, so add a debug log entry. -+ * Since we clear the GKeyDoneStations before the loop, the -+ * station needs to be counted here anyway. -+ */ -+ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, -+ "GUpdateStationKeys was already set when " -+ "marking station for GTK rekeying"); -+ } -+ -+ sm->group->GKeyDoneStations++; -+ sm->GUpdateStationKeys = TRUE; -+ -+ wpa_sm_step(sm); -+ return 0; -+} -+ -+ -+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ int tmp; -+ -+ wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " -+ "SETKEYS (VLAN-ID %d)", group->vlan_id); -+ group->changed = TRUE; -+ group->wpa_group_state = WPA_GROUP_SETKEYS; -+ group->GTKReKey = FALSE; -+ tmp = group->GM; -+ group->GM = group->GN; -+ group->GN = tmp; -+#ifdef CONFIG_IEEE80211W -+ tmp = group->GM_igtk; -+ group->GM_igtk = group->GN_igtk; -+ group->GN_igtk = tmp; -+#endif /* CONFIG_IEEE80211W */ -+ /* "GKeyDoneStations = GNoStations" is done in more robust way by -+ * counting the STAs that are marked with GUpdateStationKeys instead of -+ * including all STAs that could be in not-yet-completed state. */ -+ wpa_gtk_update(wpa_auth, group); -+ -+ if (group->GKeyDoneStations) { -+ wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected " -+ "GKeyDoneStations=%d when starting new GTK rekey", -+ group->GKeyDoneStations); -+ group->GKeyDoneStations = 0; -+ } -+ wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL); -+ wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d", -+ group->GKeyDoneStations); -+} -+ -+ -+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ int ret = 0; -+ -+ if (wpa_auth_set_key(wpa_auth, group->vlan_id, -+ wpa_alg_enum(wpa_auth->conf.wpa_group), -+ broadcast_ether_addr, group->GN, -+ group->GTK[group->GN - 1], group->GTK_len) < 0) -+ ret = -1; -+ -+#ifdef CONFIG_IEEE80211W -+ if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION && -+ wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK, -+ broadcast_ether_addr, group->GN_igtk, -+ group->IGTK[group->GN_igtk - 4], -+ WPA_IGTK_LEN) < 0) -+ ret = -1; -+#endif /* CONFIG_IEEE80211W */ -+ -+ return ret; -+} -+ -+ -+static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " -+ "SETKEYSDONE (VLAN-ID %d)", group->vlan_id); -+ group->changed = TRUE; -+ group->wpa_group_state = WPA_GROUP_SETKEYSDONE; -+ -+ if (wpa_group_config_group_keys(wpa_auth, group) < 0) -+ return -1; -+ -+ return 0; -+} -+ -+ -+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, -+ struct wpa_group *group) -+{ -+ if (group->GInit) { -+ wpa_group_gtk_init(wpa_auth, group); -+ } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT && -+ group->GTKAuthenticator) { -+ wpa_group_setkeysdone(wpa_auth, group); -+ } else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE && -+ group->GTKReKey) { -+ wpa_group_setkeys(wpa_auth, group); -+ } else if (group->wpa_group_state == WPA_GROUP_SETKEYS) { -+ if (group->GKeyDoneStations == 0) -+ wpa_group_setkeysdone(wpa_auth, group); -+ else if (group->GTKReKey) -+ wpa_group_setkeys(wpa_auth, group); -+ } -+} -+ -+ -+static int wpa_sm_step(struct wpa_state_machine *sm) -+{ -+ if (sm == NULL) -+ return 0; -+ -+ if (sm->in_step_loop) { -+ /* This should not happen, but if it does, make sure we do not -+ * end up freeing the state machine too early by exiting the -+ * recursive call. */ -+ wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively"); -+ return 0; -+ } -+ -+ sm->in_step_loop = 1; -+ do { -+ if (sm->pending_deinit) -+ break; -+ -+ sm->changed = FALSE; -+ sm->wpa_auth->group->changed = FALSE; -+ -+ SM_STEP_RUN(WPA_PTK); -+ if (sm->pending_deinit) -+ break; -+ SM_STEP_RUN(WPA_PTK_GROUP); -+ if (sm->pending_deinit) -+ break; -+ wpa_group_sm_step(sm->wpa_auth, sm->group); -+ } while (sm->changed || sm->wpa_auth->group->changed); -+ sm->in_step_loop = 0; -+ -+ if (sm->pending_deinit) { -+ wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state " -+ "machine deinit for " MACSTR, MAC2STR(sm->addr)); -+ wpa_free_sta_sm(sm); -+ return 1; -+ } -+ return 0; -+} -+ -+ -+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_state_machine *sm = eloop_ctx; -+ wpa_sm_step(sm); -+} -+ -+ -+void wpa_auth_sm_notify(struct wpa_state_machine *sm) -+{ -+ if (sm == NULL) -+ return; -+ eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL); -+} -+ -+ -+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) -+{ -+ int tmp, i; -+ struct wpa_group *group; -+ -+ if (wpa_auth == NULL) -+ return; -+ -+ group = wpa_auth->group; -+ -+ for (i = 0; i < 2; i++) { -+ tmp = group->GM; -+ group->GM = group->GN; -+ group->GN = tmp; -+#ifdef CONFIG_IEEE80211W -+ tmp = group->GM_igtk; -+ group->GM_igtk = group->GN_igtk; -+ group->GN_igtk = tmp; -+#endif /* CONFIG_IEEE80211W */ -+ wpa_gtk_update(wpa_auth, group); -+ } -+} -+ -+ -+static const char * wpa_bool_txt(int bool) -+{ -+ return bool ? "TRUE" : "FALSE"; -+} -+ -+ -+static int wpa_cipher_bits(int cipher) -+{ -+ switch (cipher) { -+ case WPA_CIPHER_CCMP: -+ return 128; -+ case WPA_CIPHER_TKIP: -+ return 256; -+ case WPA_CIPHER_WEP104: -+ return 104; -+ case WPA_CIPHER_WEP40: -+ return 40; -+ default: -+ return 0; -+ } -+} -+ -+ -+#define RSN_SUITE "%02x-%02x-%02x-%d" -+#define RSN_SUITE_ARG(s) \ -+((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff -+ -+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen) -+{ -+ int len = 0, ret; -+ char pmkid_txt[PMKID_LEN * 2 + 1]; -+#ifdef CONFIG_RSN_PREAUTH -+ const int preauth = 1; -+#else /* CONFIG_RSN_PREAUTH */ -+ const int preauth = 0; -+#endif /* CONFIG_RSN_PREAUTH */ -+ -+ if (wpa_auth == NULL) -+ return len; -+ -+ ret = os_snprintf(buf + len, buflen - len, -+ "dot11RSNAOptionImplemented=TRUE\n" -+ "dot11RSNAPreauthenticationImplemented=%s\n" -+ "dot11RSNAEnabled=%s\n" -+ "dot11RSNAPreauthenticationEnabled=%s\n", -+ wpa_bool_txt(preauth), -+ wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN), -+ wpa_bool_txt(wpa_auth->conf.rsn_preauth)); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt), -+ wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN); -+ -+ ret = os_snprintf( -+ buf + len, buflen - len, -+ "dot11RSNAConfigVersion=%u\n" -+ "dot11RSNAConfigPairwiseKeysSupported=9999\n" -+ /* FIX: dot11RSNAConfigGroupCipher */ -+ /* FIX: dot11RSNAConfigGroupRekeyMethod */ -+ /* FIX: dot11RSNAConfigGroupRekeyTime */ -+ /* FIX: dot11RSNAConfigGroupRekeyPackets */ -+ "dot11RSNAConfigGroupRekeyStrict=%u\n" -+ "dot11RSNAConfigGroupUpdateCount=%u\n" -+ "dot11RSNAConfigPairwiseUpdateCount=%u\n" -+ "dot11RSNAConfigGroupCipherSize=%u\n" -+ "dot11RSNAConfigPMKLifetime=%u\n" -+ "dot11RSNAConfigPMKReauthThreshold=%u\n" -+ "dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n" -+ "dot11RSNAConfigSATimeout=%u\n" -+ "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n" -+ "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n" -+ "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n" -+ "dot11RSNAPMKIDUsed=%s\n" -+ "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n" -+ "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n" -+ "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n" -+ "dot11RSNATKIPCounterMeasuresInvoked=%u\n" -+ "dot11RSNA4WayHandshakeFailures=%u\n" -+ "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n", -+ RSN_VERSION, -+ !!wpa_auth->conf.wpa_strict_rekey, -+ dot11RSNAConfigGroupUpdateCount, -+ dot11RSNAConfigPairwiseUpdateCount, -+ wpa_cipher_bits(wpa_auth->conf.wpa_group), -+ dot11RSNAConfigPMKLifetime, -+ dot11RSNAConfigPMKReauthThreshold, -+ dot11RSNAConfigSATimeout, -+ RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected), -+ RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected), -+ RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected), -+ pmkid_txt, -+ RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested), -+ RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested), -+ RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested), -+ wpa_auth->dot11RSNATKIPCounterMeasuresInvoked, -+ wpa_auth->dot11RSNA4WayHandshakeFailures); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ /* TODO: dot11RSNAConfigPairwiseCiphersTable */ -+ /* TODO: dot11RSNAConfigAuthenticationSuitesTable */ -+ -+ /* Private MIB */ -+ ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n", -+ wpa_auth->group->wpa_group_state); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ return len; -+} -+ -+ -+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen) -+{ -+ int len = 0, ret; -+ u32 pairwise = 0; -+ -+ if (sm == NULL) -+ return 0; -+ -+ /* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */ -+ -+ /* dot11RSNAStatsEntry */ -+ -+ if (sm->wpa == WPA_VERSION_WPA) { -+ if (sm->pairwise == WPA_CIPHER_CCMP) -+ pairwise = WPA_CIPHER_SUITE_CCMP; -+ else if (sm->pairwise == WPA_CIPHER_TKIP) -+ pairwise = WPA_CIPHER_SUITE_TKIP; -+ else if (sm->pairwise == WPA_CIPHER_WEP104) -+ pairwise = WPA_CIPHER_SUITE_WEP104; -+ else if (sm->pairwise == WPA_CIPHER_WEP40) -+ pairwise = WPA_CIPHER_SUITE_WEP40; -+ else if (sm->pairwise == WPA_CIPHER_NONE) -+ pairwise = WPA_CIPHER_SUITE_NONE; -+ } else if (sm->wpa == WPA_VERSION_WPA2) { -+ if (sm->pairwise == WPA_CIPHER_CCMP) -+ pairwise = RSN_CIPHER_SUITE_CCMP; -+ else if (sm->pairwise == WPA_CIPHER_TKIP) -+ pairwise = RSN_CIPHER_SUITE_TKIP; -+ else if (sm->pairwise == WPA_CIPHER_WEP104) -+ pairwise = RSN_CIPHER_SUITE_WEP104; -+ else if (sm->pairwise == WPA_CIPHER_WEP40) -+ pairwise = RSN_CIPHER_SUITE_WEP40; -+ else if (sm->pairwise == WPA_CIPHER_NONE) -+ pairwise = RSN_CIPHER_SUITE_NONE; -+ } else -+ return 0; -+ -+ ret = os_snprintf( -+ buf + len, buflen - len, -+ /* TODO: dot11RSNAStatsIndex */ -+ "dot11RSNAStatsSTAAddress=" MACSTR "\n" -+ "dot11RSNAStatsVersion=1\n" -+ "dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n" -+ /* TODO: dot11RSNAStatsTKIPICVErrors */ -+ "dot11RSNAStatsTKIPLocalMICFailures=%u\n" -+ "dot11RSNAStatsTKIPRemoteMICFailures=%u\n" -+ /* TODO: dot11RSNAStatsCCMPReplays */ -+ /* TODO: dot11RSNAStatsCCMPDecryptErrors */ -+ /* TODO: dot11RSNAStatsTKIPReplays */, -+ MAC2STR(sm->addr), -+ RSN_SUITE_ARG(pairwise), -+ sm->dot11RSNAStatsTKIPLocalMICFailures, -+ sm->dot11RSNAStatsTKIPRemoteMICFailures); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ /* Private MIB */ -+ ret = os_snprintf(buf + len, buflen - len, -+ "hostapdWPAPTKState=%d\n" -+ "hostapdWPAPTKGroupState=%d\n", -+ sm->wpa_ptk_state, -+ sm->wpa_ptk_group_state); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ return len; -+} -+ -+ -+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth) -+{ -+ if (wpa_auth) -+ wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++; -+} -+ -+ -+int wpa_auth_pairwise_set(struct wpa_state_machine *sm) -+{ -+ return sm && sm->pairwise_set; -+} -+ -+ -+int wpa_auth_get_pairwise(struct wpa_state_machine *sm) -+{ -+ return sm->pairwise; -+} -+ -+ -+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm) -+{ -+ if (sm == NULL) -+ return -1; -+ return sm->wpa_key_mgmt; -+} -+ -+ -+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm) -+{ -+ if (sm == NULL) -+ return 0; -+ return sm->wpa; -+} -+ -+ -+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, -+ struct rsn_pmksa_cache_entry *entry) -+{ -+ if (sm == NULL || sm->pmksa != entry) -+ return -1; -+ sm->pmksa = NULL; -+ return 0; -+} -+ -+ -+struct rsn_pmksa_cache_entry * -+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm) -+{ -+ return sm ? sm->pmksa : NULL; -+} -+ -+ -+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm) -+{ -+ if (sm) -+ sm->dot11RSNAStatsTKIPLocalMICFailures++; -+} -+ -+ -+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len) -+{ -+ if (wpa_auth == NULL) -+ return NULL; -+ *len = wpa_auth->wpa_ie_len; -+ return wpa_auth->wpa_ie; -+} -+ -+ -+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, -+ int session_timeout, struct eapol_state_machine *eapol) -+{ -+ if (sm == NULL || sm->wpa != WPA_VERSION_WPA2) -+ return -1; -+ -+ if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN, -+ sm->wpa_auth->addr, sm->addr, session_timeout, -+ eapol, sm->wpa_key_mgmt)) -+ return 0; -+ -+ return -1; -+} -+ -+ -+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, -+ const u8 *pmk, size_t len, const u8 *sta_addr, -+ int session_timeout, -+ struct eapol_state_machine *eapol) -+{ -+ if (wpa_auth == NULL) -+ return -1; -+ -+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr, -+ sta_addr, session_timeout, eapol, -+ WPA_KEY_MGMT_IEEE8021X)) -+ return 0; -+ -+ return -1; -+} -+ -+ -+static struct wpa_group * -+wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) -+{ -+ struct wpa_group *group; -+ -+ if (wpa_auth == NULL || wpa_auth->group == NULL) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d", -+ vlan_id); -+ group = wpa_group_init(wpa_auth, vlan_id); -+ if (group == NULL) -+ return NULL; -+ -+ group->next = wpa_auth->group->next; -+ wpa_auth->group->next = group; -+ -+ return group; -+} -+ -+ -+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) -+{ -+ struct wpa_group *group; -+ -+ if (sm == NULL || sm->wpa_auth == NULL) -+ return 0; -+ -+ group = sm->wpa_auth->group; -+ while (group) { -+ if (group->vlan_id == vlan_id) -+ break; -+ group = group->next; -+ } -+ -+ if (group == NULL) { -+ group = wpa_auth_add_group(sm->wpa_auth, vlan_id); -+ if (group == NULL) -+ return -1; -+ } -+ -+ if (sm->group == group) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state " -+ "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id); -+ -+ sm->group = group; -+ return 0; -+} -+ -+ -+void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, int ack) -+{ -+ if (wpa_auth == NULL || sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR -+ " ack=%d", MAC2STR(sm->addr), ack); -+ if (sm->pending_1_of_4_timeout && ack) { -+ /* -+ * Some deployed supplicant implementations update their SNonce -+ * for each EAPOL-Key 2/4 message even within the same 4-way -+ * handshake and then fail to use the first SNonce when -+ * deriving the PTK. This results in unsuccessful 4-way -+ * handshake whenever the relatively short initial timeout is -+ * reached and EAPOL-Key 1/4 is retransmitted. Try to work -+ * around this by increasing the timeout now that we know that -+ * the station has received the frame. -+ */ -+ int timeout_ms = eapol_key_timeout_subseq; -+ wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 " -+ "timeout by %u ms because of acknowledged frame", -+ timeout_ms); -+ eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); -+ eloop_register_timeout(timeout_ms / 1000, -+ (timeout_ms % 1000) * 1000, -+ wpa_send_eapol_timeout, wpa_auth, sm); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.h -new file mode 100644 -index 0000000000000..b3e1ff027e062 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth.h -@@ -0,0 +1,285 @@ -+/* -+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_AUTH_H -+#define WPA_AUTH_H -+ -+#include "common/defs.h" -+#include "common/eapol_common.h" -+#include "common/wpa_common.h" -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition -+ */ -+struct ft_rrb_frame { -+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ -+ u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */ -+ le16 action_length; /* little endian length of action_frame */ -+ u8 ap_address[ETH_ALEN]; -+ /* -+ * Followed by action_length bytes of FT Action frame (from Category -+ * field to the end of Action Frame body. -+ */ -+} STRUCT_PACKED; -+ -+#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1 -+ -+#define FT_PACKET_REQUEST 0 -+#define FT_PACKET_RESPONSE 1 -+/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */ -+#define FT_PACKET_R0KH_R1KH_PULL 200 -+#define FT_PACKET_R0KH_R1KH_RESP 201 -+#define FT_PACKET_R0KH_R1KH_PUSH 202 -+ -+#define FT_R0KH_R1KH_PULL_DATA_LEN 44 -+#define FT_R0KH_R1KH_RESP_DATA_LEN 76 -+#define FT_R0KH_R1KH_PUSH_DATA_LEN 88 -+ -+struct ft_r0kh_r1kh_pull_frame { -+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ -+ u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */ -+ le16 data_length; /* little endian length of data (44) */ -+ u8 ap_address[ETH_ALEN]; -+ -+ u8 nonce[16]; -+ u8 pmk_r0_name[WPA_PMK_NAME_LEN]; -+ u8 r1kh_id[FT_R1KH_ID_LEN]; -+ u8 s1kh_id[ETH_ALEN]; -+ u8 pad[4]; /* 8-octet boundary for AES key wrap */ -+ u8 key_wrap_extra[8]; -+} STRUCT_PACKED; -+ -+struct ft_r0kh_r1kh_resp_frame { -+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ -+ u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */ -+ le16 data_length; /* little endian length of data (76) */ -+ u8 ap_address[ETH_ALEN]; -+ -+ u8 nonce[16]; /* copied from pull */ -+ u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */ -+ u8 s1kh_id[ETH_ALEN]; /* copied from pull */ -+ u8 pmk_r1[PMK_LEN]; -+ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; -+ le16 pairwise; -+ u8 pad[2]; /* 8-octet boundary for AES key wrap */ -+ u8 key_wrap_extra[8]; -+} STRUCT_PACKED; -+ -+struct ft_r0kh_r1kh_push_frame { -+ u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */ -+ u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */ -+ le16 data_length; /* little endian length of data (88) */ -+ u8 ap_address[ETH_ALEN]; -+ -+ /* Encrypted with AES key-wrap */ -+ u8 timestamp[4]; /* current time in seconds since unix epoch, little -+ * endian */ -+ u8 r1kh_id[FT_R1KH_ID_LEN]; -+ u8 s1kh_id[ETH_ALEN]; -+ u8 pmk_r0_name[WPA_PMK_NAME_LEN]; -+ u8 pmk_r1[PMK_LEN]; -+ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; -+ le16 pairwise; -+ u8 pad[6]; /* 8-octet boundary for AES key wrap */ -+ u8 key_wrap_extra[8]; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+/* per STA state machine data */ -+ -+struct wpa_authenticator; -+struct wpa_state_machine; -+struct rsn_pmksa_cache_entry; -+struct eapol_state_machine; -+ -+ -+struct ft_remote_r0kh { -+ struct ft_remote_r0kh *next; -+ u8 addr[ETH_ALEN]; -+ u8 id[FT_R0KH_ID_MAX_LEN]; -+ size_t id_len; -+ u8 key[16]; -+}; -+ -+ -+struct ft_remote_r1kh { -+ struct ft_remote_r1kh *next; -+ u8 addr[ETH_ALEN]; -+ u8 id[FT_R1KH_ID_LEN]; -+ u8 key[16]; -+}; -+ -+ -+struct wpa_auth_config { -+ int wpa; -+ int wpa_key_mgmt; -+ int wpa_pairwise; -+ int wpa_group; -+ int wpa_group_rekey; -+ int wpa_strict_rekey; -+ int wpa_gmk_rekey; -+ int wpa_ptk_rekey; -+ int rsn_pairwise; -+ int rsn_preauth; -+ int eapol_version; -+ int peerkey; -+ int wmm_enabled; -+ int wmm_uapsd; -+ int okc; -+ int tx_status; -+#ifdef CONFIG_IEEE80211W -+ enum mfp_options ieee80211w; -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_IEEE80211R -+#define SSID_LEN 32 -+ u8 ssid[SSID_LEN]; -+ size_t ssid_len; -+ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; -+ u8 r0_key_holder[FT_R0KH_ID_MAX_LEN]; -+ size_t r0_key_holder_len; -+ u8 r1_key_holder[FT_R1KH_ID_LEN]; -+ u32 r0_key_lifetime; -+ u32 reassociation_deadline; -+ struct ft_remote_r0kh *r0kh_list; -+ struct ft_remote_r1kh *r1kh_list; -+ int pmk_r1_push; -+ int ft_over_ds; -+#endif /* CONFIG_IEEE80211R */ -+}; -+ -+typedef enum { -+ LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING -+} logger_level; -+ -+typedef enum { -+ WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized, -+ WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable, -+ WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx -+} wpa_eapol_variable; -+ -+struct wpa_auth_callbacks { -+ void *ctx; -+ void (*logger)(void *ctx, const u8 *addr, logger_level level, -+ const char *txt); -+ void (*disconnect)(void *ctx, const u8 *addr, u16 reason); -+ void (*mic_failure_report)(void *ctx, const u8 *addr); -+ void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var, -+ int value); -+ int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var); -+ const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk); -+ int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len); -+ int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, -+ const u8 *addr, int idx, u8 *key, size_t key_len); -+ int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq); -+ int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data, -+ size_t data_len, int encrypt); -+ int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm, -+ void *ctx), void *cb_ctx); -+ int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a, -+ void *ctx), void *cb_ctx); -+ int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data, -+ size_t data_len); -+#ifdef CONFIG_IEEE80211R -+ struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); -+ int (*send_ft_action)(void *ctx, const u8 *dst, -+ const u8 *data, size_t data_len); -+#endif /* CONFIG_IEEE80211R */ -+}; -+ -+struct wpa_authenticator * wpa_init(const u8 *addr, -+ struct wpa_auth_config *conf, -+ struct wpa_auth_callbacks *cb); -+void wpa_deinit(struct wpa_authenticator *wpa_auth); -+int wpa_reconfig(struct wpa_authenticator *wpa_auth, -+ struct wpa_auth_config *conf); -+ -+enum { -+ WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE, -+ WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL, -+ WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER, -+ WPA_INVALID_MDIE, WPA_INVALID_PROTO -+}; -+ -+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, -+ const u8 *wpa_ie, size_t wpa_ie_len, -+ const u8 *mdie, size_t mdie_len); -+int wpa_auth_uses_mfp(struct wpa_state_machine *sm); -+struct wpa_state_machine * -+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr); -+int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm); -+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm); -+void wpa_auth_sta_deinit(struct wpa_state_machine *sm); -+void wpa_receive(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, -+ u8 *data, size_t data_len); -+typedef enum { -+ WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH, -+ WPA_REAUTH_EAPOL, WPA_ASSOC_FT -+} wpa_event; -+void wpa_remove_ptk(struct wpa_state_machine *sm); -+int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event); -+void wpa_auth_sm_notify(struct wpa_state_machine *sm); -+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth); -+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen); -+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen); -+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth); -+int wpa_auth_pairwise_set(struct wpa_state_machine *sm); -+int wpa_auth_get_pairwise(struct wpa_state_machine *sm); -+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); -+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); -+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, -+ struct rsn_pmksa_cache_entry *entry); -+struct rsn_pmksa_cache_entry * -+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm); -+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm); -+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, -+ size_t *len); -+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, -+ int session_timeout, struct eapol_state_machine *eapol); -+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, -+ const u8 *pmk, size_t len, const u8 *sta_addr, -+ int session_timeout, -+ struct eapol_state_machine *eapol); -+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id); -+void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, int ack); -+ -+#ifdef CONFIG_IEEE80211R -+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, -+ size_t max_len, int auth_alg, -+ const u8 *req_ies, size_t req_ies_len); -+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, -+ u16 auth_transaction, const u8 *ies, size_t ies_len, -+ void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, -+ u16 auth_transaction, u16 resp, -+ const u8 *ies, size_t ies_len), -+ void *ctx); -+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, -+ size_t ies_len); -+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len); -+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, -+ const u8 *data, size_t data_len); -+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); -+#endif /* CONFIG_IEEE80211R */ -+ -+#endif /* WPA_AUTH_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ft.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ft.c -new file mode 100644 -index 0000000000000..65f5f4caa7f57 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ft.c -@@ -0,0 +1,1779 @@ -+/* -+ * hostapd - IEEE 802.11r - Fast BSS Transition -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/random.h" -+#include "ap_config.h" -+#include "ieee802_11.h" -+#include "wmm.h" -+#include "wpa_auth.h" -+#include "wpa_auth_i.h" -+#include "wpa_auth_ie.h" -+ -+ -+#ifdef CONFIG_IEEE80211R -+ -+struct wpa_ft_ies { -+ const u8 *mdie; -+ size_t mdie_len; -+ const u8 *ftie; -+ size_t ftie_len; -+ const u8 *r1kh_id; -+ const u8 *gtk; -+ size_t gtk_len; -+ const u8 *r0kh_id; -+ size_t r0kh_id_len; -+ const u8 *rsn; -+ size_t rsn_len; -+ const u8 *rsn_pmkid; -+ const u8 *ric; -+ size_t ric_len; -+}; -+ -+ -+static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, -+ struct wpa_ft_ies *parse); -+ -+ -+static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst, -+ const u8 *data, size_t data_len) -+{ -+ if (wpa_auth->cb.send_ether == NULL) -+ return -1; -+ wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst)); -+ return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB, -+ data, data_len); -+} -+ -+ -+static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth, -+ const u8 *dst, const u8 *data, size_t data_len) -+{ -+ if (wpa_auth->cb.send_ft_action == NULL) -+ return -1; -+ return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst, -+ data, data_len); -+} -+ -+ -+static struct wpa_state_machine * -+wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr) -+{ -+ if (wpa_auth->cb.add_sta == NULL) -+ return NULL; -+ return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr); -+} -+ -+ -+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len) -+{ -+ u8 *pos = buf; -+ u8 capab; -+ if (len < 2 + sizeof(struct rsn_mdie)) -+ return -1; -+ -+ *pos++ = WLAN_EID_MOBILITY_DOMAIN; -+ *pos++ = MOBILITY_DOMAIN_ID_LEN + 1; -+ os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN); -+ pos += MOBILITY_DOMAIN_ID_LEN; -+ capab = 0; -+ if (conf->ft_over_ds) -+ capab |= RSN_FT_CAPAB_FT_OVER_DS; -+ *pos++ = capab; -+ -+ return pos - buf; -+} -+ -+ -+int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, -+ size_t r0kh_id_len, -+ const u8 *anonce, const u8 *snonce, -+ u8 *buf, size_t len, const u8 *subelem, -+ size_t subelem_len) -+{ -+ u8 *pos = buf, *ielen; -+ struct rsn_ftie *hdr; -+ -+ if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len + -+ subelem_len) -+ return -1; -+ -+ *pos++ = WLAN_EID_FAST_BSS_TRANSITION; -+ ielen = pos++; -+ -+ hdr = (struct rsn_ftie *) pos; -+ os_memset(hdr, 0, sizeof(*hdr)); -+ pos += sizeof(*hdr); -+ WPA_PUT_LE16(hdr->mic_control, 0); -+ if (anonce) -+ os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); -+ if (snonce) -+ os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN); -+ -+ /* Optional Parameters */ -+ *pos++ = FTIE_SUBELEM_R1KH_ID; -+ *pos++ = FT_R1KH_ID_LEN; -+ os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN); -+ pos += FT_R1KH_ID_LEN; -+ -+ if (r0kh_id) { -+ *pos++ = FTIE_SUBELEM_R0KH_ID; -+ *pos++ = r0kh_id_len; -+ os_memcpy(pos, r0kh_id, r0kh_id_len); -+ pos += r0kh_id_len; -+ } -+ -+ if (subelem) { -+ os_memcpy(pos, subelem, subelem_len); -+ pos += subelem_len; -+ } -+ -+ *ielen = pos - buf - 2; -+ -+ return pos - buf; -+} -+ -+ -+struct wpa_ft_pmk_r0_sa { -+ struct wpa_ft_pmk_r0_sa *next; -+ u8 pmk_r0[PMK_LEN]; -+ u8 pmk_r0_name[WPA_PMK_NAME_LEN]; -+ u8 spa[ETH_ALEN]; -+ int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ -+ /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ -+ int pmk_r1_pushed; -+}; -+ -+struct wpa_ft_pmk_r1_sa { -+ struct wpa_ft_pmk_r1_sa *next; -+ u8 pmk_r1[PMK_LEN]; -+ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; -+ u8 spa[ETH_ALEN]; -+ int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ -+ /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */ -+}; -+ -+struct wpa_ft_pmk_cache { -+ struct wpa_ft_pmk_r0_sa *pmk_r0; -+ struct wpa_ft_pmk_r1_sa *pmk_r1; -+}; -+ -+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void) -+{ -+ struct wpa_ft_pmk_cache *cache; -+ -+ cache = os_zalloc(sizeof(*cache)); -+ -+ return cache; -+} -+ -+ -+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache) -+{ -+ struct wpa_ft_pmk_r0_sa *r0, *r0prev; -+ struct wpa_ft_pmk_r1_sa *r1, *r1prev; -+ -+ r0 = cache->pmk_r0; -+ while (r0) { -+ r0prev = r0; -+ r0 = r0->next; -+ os_memset(r0prev->pmk_r0, 0, PMK_LEN); -+ os_free(r0prev); -+ } -+ -+ r1 = cache->pmk_r1; -+ while (r1) { -+ r1prev = r1; -+ r1 = r1->next; -+ os_memset(r1prev->pmk_r1, 0, PMK_LEN); -+ os_free(r1prev); -+ } -+ -+ os_free(cache); -+} -+ -+ -+static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth, -+ const u8 *spa, const u8 *pmk_r0, -+ const u8 *pmk_r0_name, int pairwise) -+{ -+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; -+ struct wpa_ft_pmk_r0_sa *r0; -+ -+ /* TODO: add expiration and limit on number of entries in cache */ -+ -+ r0 = os_zalloc(sizeof(*r0)); -+ if (r0 == NULL) -+ return -1; -+ -+ os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN); -+ os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN); -+ os_memcpy(r0->spa, spa, ETH_ALEN); -+ r0->pairwise = pairwise; -+ -+ r0->next = cache->pmk_r0; -+ cache->pmk_r0 = r0; -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, -+ const u8 *spa, const u8 *pmk_r0_name, -+ u8 *pmk_r0, int *pairwise) -+{ -+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; -+ struct wpa_ft_pmk_r0_sa *r0; -+ -+ r0 = cache->pmk_r0; -+ while (r0) { -+ if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 && -+ os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN) -+ == 0) { -+ os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN); -+ if (pairwise) -+ *pairwise = r0->pairwise; -+ return 0; -+ } -+ -+ r0 = r0->next; -+ } -+ -+ return -1; -+} -+ -+ -+static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth, -+ const u8 *spa, const u8 *pmk_r1, -+ const u8 *pmk_r1_name, int pairwise) -+{ -+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; -+ struct wpa_ft_pmk_r1_sa *r1; -+ -+ /* TODO: add expiration and limit on number of entries in cache */ -+ -+ r1 = os_zalloc(sizeof(*r1)); -+ if (r1 == NULL) -+ return -1; -+ -+ os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN); -+ os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN); -+ os_memcpy(r1->spa, spa, ETH_ALEN); -+ r1->pairwise = pairwise; -+ -+ r1->next = cache->pmk_r1; -+ cache->pmk_r1 = r1; -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, -+ const u8 *spa, const u8 *pmk_r1_name, -+ u8 *pmk_r1, int *pairwise) -+{ -+ struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache; -+ struct wpa_ft_pmk_r1_sa *r1; -+ -+ r1 = cache->pmk_r1; -+ while (r1) { -+ if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 && -+ os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN) -+ == 0) { -+ os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN); -+ if (pairwise) -+ *pairwise = r1->pairwise; -+ return 0; -+ } -+ -+ r1 = r1->next; -+ } -+ -+ return -1; -+} -+ -+ -+static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth, -+ const u8 *s1kh_id, const u8 *r0kh_id, -+ size_t r0kh_id_len, const u8 *pmk_r0_name) -+{ -+ struct ft_remote_r0kh *r0kh; -+ struct ft_r0kh_r1kh_pull_frame frame, f; -+ -+ r0kh = wpa_auth->conf.r0kh_list; -+ while (r0kh) { -+ if (r0kh->id_len == r0kh_id_len && -+ os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0) -+ break; -+ r0kh = r0kh->next; -+ } -+ if (r0kh == NULL) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH " -+ "address " MACSTR, MAC2STR(r0kh->addr)); -+ -+ os_memset(&frame, 0, sizeof(frame)); -+ frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; -+ frame.packet_type = FT_PACKET_R0KH_R1KH_PULL; -+ frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN); -+ os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN); -+ -+ /* aes_wrap() does not support inplace encryption, so use a temporary -+ * buffer for the data. */ -+ if (random_get_bytes(f.nonce, sizeof(f.nonce))) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " -+ "nonce"); -+ return -1; -+ } -+ os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN); -+ os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN); -+ os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN); -+ -+ if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, -+ f.nonce, frame.nonce) < 0) -+ return -1; -+ -+ wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame)); -+ -+ return 0; -+} -+ -+ -+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, -+ struct wpa_ptk *ptk, size_t ptk_len) -+{ -+ u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN]; -+ u8 pmk_r1[PMK_LEN]; -+ u8 ptk_name[WPA_PMK_NAME_LEN]; -+ const u8 *mdid = sm->wpa_auth->conf.mobility_domain; -+ const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder; -+ size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len; -+ const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder; -+ const u8 *ssid = sm->wpa_auth->conf.ssid; -+ size_t ssid_len = sm->wpa_auth->conf.ssid_len; -+ -+ -+ if (sm->xxkey_len == 0) { -+ wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " -+ "derivation"); -+ return -1; -+ } -+ -+ wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid, -+ r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN); -+ wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name, -+ sm->pairwise); -+ -+ wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr, -+ pmk_r1, sm->pmk_r1_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, -+ WPA_PMK_NAME_LEN); -+ wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name, -+ sm->pairwise); -+ -+ wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, -+ sm->wpa_auth->addr, sm->pmk_r1_name, -+ (u8 *) ptk, ptk_len, ptk_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); -+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); -+ -+ return 0; -+} -+ -+ -+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, -+ const u8 *addr, int idx, u8 *seq) -+{ -+ if (wpa_auth->cb.get_seqnum == NULL) -+ return -1; -+ return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq); -+} -+ -+ -+static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) -+{ -+ u8 *subelem; -+ struct wpa_group *gsm = sm->group; -+ size_t subelem_len, pad_len; -+ const u8 *key; -+ size_t key_len; -+ u8 keybuf[32]; -+ -+ key_len = gsm->GTK_len; -+ if (key_len > sizeof(keybuf)) -+ return NULL; -+ -+ /* -+ * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less -+ * than 16 bytes. -+ */ -+ pad_len = key_len % 8; -+ if (pad_len) -+ pad_len = 8 - pad_len; -+ if (key_len + pad_len < 16) -+ pad_len += 8; -+ if (pad_len) { -+ os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len); -+ os_memset(keybuf + key_len, 0, pad_len); -+ keybuf[key_len] = 0xdd; -+ key_len += pad_len; -+ key = keybuf; -+ } else -+ key = gsm->GTK[gsm->GN - 1]; -+ -+ /* -+ * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | -+ * Key[5..32]. -+ */ -+ subelem_len = 13 + key_len + 8; -+ subelem = os_zalloc(subelem_len); -+ if (subelem == NULL) -+ return NULL; -+ -+ subelem[0] = FTIE_SUBELEM_GTK; -+ subelem[1] = 11 + key_len + 8; -+ /* Key ID in B0-B1 of Key Info */ -+ WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03); -+ subelem[4] = gsm->GTK_len; -+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5); -+ if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) { -+ os_free(subelem); -+ return NULL; -+ } -+ -+ *len = subelem_len; -+ return subelem; -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) -+{ -+ u8 *subelem, *pos; -+ struct wpa_group *gsm = sm->group; -+ size_t subelem_len; -+ -+ /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] | -+ * Key[16+8] */ -+ subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8; -+ subelem = os_zalloc(subelem_len); -+ if (subelem == NULL) -+ return NULL; -+ -+ pos = subelem; -+ *pos++ = FTIE_SUBELEM_IGTK; -+ *pos++ = subelem_len - 2; -+ WPA_PUT_LE16(pos, gsm->GN_igtk); -+ pos += 2; -+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos); -+ pos += 6; -+ *pos++ = WPA_IGTK_LEN; -+ if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8, -+ gsm->IGTK[gsm->GN_igtk - 4], pos)) { -+ os_free(subelem); -+ return NULL; -+ } -+ -+ *len = subelem_len; -+ return subelem; -+} -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count, -+ const u8 *ies, size_t ies_len) -+{ -+ struct ieee802_11_elems parse; -+ struct rsn_rdie *rdie; -+ -+ wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d", -+ id, descr_count); -+ wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)", -+ ies, ies_len); -+ -+ if (end - pos < (int) sizeof(*rdie)) { -+ wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE"); -+ return pos; -+ } -+ -+ *pos++ = WLAN_EID_RIC_DATA; -+ *pos++ = sizeof(*rdie); -+ rdie = (struct rsn_rdie *) pos; -+ rdie->id = id; -+ rdie->descr_count = 0; -+ rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS); -+ pos += sizeof(*rdie); -+ -+ if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) == -+ ParseFailed) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs"); -+ rdie->status_code = -+ host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); -+ return pos; -+ } -+ -+#ifdef NEED_AP_MLME -+ if (parse.wmm_tspec) { -+ struct wmm_tspec_element *tspec; -+ int res; -+ -+ if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) { -+ wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE " -+ "(%d)", (int) parse.wmm_tspec_len); -+ rdie->status_code = -+ host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); -+ return pos; -+ } -+ if (end - pos < (int) sizeof(*tspec)) { -+ wpa_printf(MSG_ERROR, "FT: Not enough room for " -+ "response TSPEC"); -+ rdie->status_code = -+ host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); -+ return pos; -+ } -+ tspec = (struct wmm_tspec_element *) pos; -+ os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec)); -+ res = wmm_process_tspec(tspec); -+ wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res); -+ if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS) -+ rdie->status_code = -+ host_to_le16(WLAN_STATUS_INVALID_PARAMETERS); -+ else if (res == WMM_ADDTS_STATUS_REFUSED) -+ rdie->status_code = -+ host_to_le16(WLAN_STATUS_REQUEST_DECLINED); -+ else { -+ /* TSPEC accepted; include updated TSPEC in response */ -+ rdie->descr_count = 1; -+ pos += sizeof(*tspec); -+ } -+ return pos; -+ } -+#endif /* NEED_AP_MLME */ -+ -+ wpa_printf(MSG_DEBUG, "FT: No supported resource requested"); -+ rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); -+ return pos; -+} -+ -+ -+static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len) -+{ -+ const u8 *rpos, *start; -+ const struct rsn_rdie *rdie; -+ -+ wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len); -+ -+ rpos = ric; -+ while (rpos + sizeof(*rdie) < ric + ric_len) { -+ if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) || -+ rpos + 2 + rpos[1] > ric + ric_len) -+ break; -+ rdie = (const struct rsn_rdie *) (rpos + 2); -+ rpos += 2 + rpos[1]; -+ start = rpos; -+ -+ while (rpos + 2 <= ric + ric_len && -+ rpos + 2 + rpos[1] <= ric + ric_len) { -+ if (rpos[0] == WLAN_EID_RIC_DATA) -+ break; -+ rpos += 2 + rpos[1]; -+ } -+ pos = wpa_ft_process_rdie(pos, end, rdie->id, -+ rdie->descr_count, -+ start, rpos - start); -+ } -+ -+ return pos; -+} -+ -+ -+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, -+ size_t max_len, int auth_alg, -+ const u8 *req_ies, size_t req_ies_len) -+{ -+ u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL; -+ size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0; -+ int res; -+ struct wpa_auth_config *conf; -+ struct rsn_ftie *_ftie; -+ struct wpa_ft_ies parse; -+ u8 *ric_start; -+ u8 *anonce, *snonce; -+ -+ if (sm == NULL) -+ return pos; -+ -+ conf = &sm->wpa_auth->conf; -+ -+ if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && -+ sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK) -+ return pos; -+ -+ end = pos + max_len; -+ -+ if (auth_alg == WLAN_AUTH_FT) { -+ /* -+ * RSN (only present if this is a Reassociation Response and -+ * part of a fast BSS transition) -+ */ -+ res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name); -+ if (res < 0) -+ return pos; -+ rsnie = pos; -+ rsnie_len = res; -+ pos += res; -+ } -+ -+ /* Mobility Domain Information */ -+ res = wpa_write_mdie(conf, pos, end - pos); -+ if (res < 0) -+ return pos; -+ mdie = pos; -+ mdie_len = res; -+ pos += res; -+ -+ /* Fast BSS Transition Information */ -+ if (auth_alg == WLAN_AUTH_FT) { -+ subelem = wpa_ft_gtk_subelem(sm, &subelem_len); -+ r0kh_id = sm->r0kh_id; -+ r0kh_id_len = sm->r0kh_id_len; -+ anonce = sm->ANonce; -+ snonce = sm->SNonce; -+#ifdef CONFIG_IEEE80211W -+ if (sm->mgmt_frame_prot) { -+ u8 *igtk; -+ size_t igtk_len; -+ u8 *nbuf; -+ igtk = wpa_ft_igtk_subelem(sm, &igtk_len); -+ if (igtk == NULL) { -+ os_free(subelem); -+ return pos; -+ } -+ nbuf = os_realloc(subelem, subelem_len + igtk_len); -+ if (nbuf == NULL) { -+ os_free(subelem); -+ os_free(igtk); -+ return pos; -+ } -+ subelem = nbuf; -+ os_memcpy(subelem + subelem_len, igtk, igtk_len); -+ subelem_len += igtk_len; -+ os_free(igtk); -+ } -+#endif /* CONFIG_IEEE80211W */ -+ } else { -+ r0kh_id = conf->r0_key_holder; -+ r0kh_id_len = conf->r0_key_holder_len; -+ anonce = NULL; -+ snonce = NULL; -+ } -+ res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos, -+ end - pos, subelem, subelem_len); -+ os_free(subelem); -+ if (res < 0) -+ return pos; -+ ftie = pos; -+ ftie_len = res; -+ pos += res; -+ -+ os_free(sm->assoc_resp_ftie); -+ sm->assoc_resp_ftie = os_malloc(ftie_len); -+ if (sm->assoc_resp_ftie) -+ os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len); -+ -+ _ftie = (struct rsn_ftie *) (ftie + 2); -+ if (auth_alg == WLAN_AUTH_FT) -+ _ftie->mic_control[1] = 3; /* Information element count */ -+ -+ ric_start = pos; -+ if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) { -+ pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len); -+ if (auth_alg == WLAN_AUTH_FT) -+ _ftie->mic_control[1] += -+ ieee802_11_ie_count(ric_start, -+ pos - ric_start); -+ } -+ if (ric_start == pos) -+ ric_start = NULL; -+ -+ if (auth_alg == WLAN_AUTH_FT && -+ wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6, -+ mdie, mdie_len, ftie, ftie_len, -+ rsnie, rsnie_len, -+ ric_start, ric_start ? pos - ric_start : 0, -+ _ftie->mic) < 0) -+ wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); -+ -+ return pos; -+} -+ -+ -+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, -+ struct wpa_ft_ies *parse) -+{ -+ const u8 *end, *pos; -+ -+ parse->ftie = ie; -+ parse->ftie_len = ie_len; -+ -+ pos = ie + sizeof(struct rsn_ftie); -+ end = ie + ie_len; -+ -+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) { -+ switch (pos[0]) { -+ case FTIE_SUBELEM_R1KH_ID: -+ if (pos[1] != FT_R1KH_ID_LEN) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " -+ "length in FTIE: %d", pos[1]); -+ return -1; -+ } -+ parse->r1kh_id = pos + 2; -+ break; -+ case FTIE_SUBELEM_GTK: -+ parse->gtk = pos + 2; -+ parse->gtk_len = pos[1]; -+ break; -+ case FTIE_SUBELEM_R0KH_ID: -+ if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " -+ "length in FTIE: %d", pos[1]); -+ return -1; -+ } -+ parse->r0kh_id = pos + 2; -+ parse->r0kh_id_len = pos[1]; -+ break; -+ } -+ -+ pos += 2 + pos[1]; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, -+ struct wpa_ft_ies *parse) -+{ -+ const u8 *end, *pos; -+ struct wpa_ie_data data; -+ int ret; -+ const struct rsn_ftie *ftie; -+ int prot_ie_count = 0; -+ -+ os_memset(parse, 0, sizeof(*parse)); -+ if (ies == NULL) -+ return 0; -+ -+ pos = ies; -+ end = ies + ies_len; -+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) { -+ switch (pos[0]) { -+ case WLAN_EID_RSN: -+ parse->rsn = pos + 2; -+ parse->rsn_len = pos[1]; -+ ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, -+ parse->rsn_len + 2, -+ &data); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to parse " -+ "RSN IE: %d", ret); -+ return -1; -+ } -+ if (data.num_pmkid == 1 && data.pmkid) -+ parse->rsn_pmkid = data.pmkid; -+ break; -+ case WLAN_EID_MOBILITY_DOMAIN: -+ parse->mdie = pos + 2; -+ parse->mdie_len = pos[1]; -+ break; -+ case WLAN_EID_FAST_BSS_TRANSITION: -+ if (pos[1] < sizeof(*ftie)) -+ return -1; -+ ftie = (const struct rsn_ftie *) (pos + 2); -+ prot_ie_count = ftie->mic_control[1]; -+ if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) -+ return -1; -+ break; -+ case WLAN_EID_RIC_DATA: -+ if (parse->ric == NULL) -+ parse->ric = pos; -+ } -+ -+ pos += 2 + pos[1]; -+ } -+ -+ if (prot_ie_count == 0) -+ return 0; /* no MIC */ -+ -+ /* -+ * Check that the protected IE count matches with IEs included in the -+ * frame. -+ */ -+ if (parse->rsn) -+ prot_ie_count--; -+ if (parse->mdie) -+ prot_ie_count--; -+ if (parse->ftie) -+ prot_ie_count--; -+ if (prot_ie_count < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " -+ "the protected IE count"); -+ return -1; -+ } -+ -+ if (prot_ie_count == 0 && parse->ric) { -+ wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " -+ "included in protected IE count"); -+ return -1; -+ } -+ -+ /* Determine the end of the RIC IE(s) */ -+ pos = parse->ric; -+ while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && -+ prot_ie_count) { -+ prot_ie_count--; -+ pos += 2 + pos[1]; -+ } -+ parse->ric_len = pos - parse->ric; -+ if (prot_ie_count) { -+ wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " -+ "frame", (int) prot_ie_count); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, -+ int vlan_id, -+ enum wpa_alg alg, const u8 *addr, int idx, -+ u8 *key, size_t key_len) -+{ -+ if (wpa_auth->cb.set_key == NULL) -+ return -1; -+ return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx, -+ key, key_len); -+} -+ -+ -+void wpa_ft_install_ptk(struct wpa_state_machine *sm) -+{ -+ enum wpa_alg alg; -+ int klen; -+ -+ /* MLME-SETKEYS.request(PTK) */ -+ if (sm->pairwise == WPA_CIPHER_TKIP) { -+ alg = WPA_ALG_TKIP; -+ klen = 32; -+ } else if (sm->pairwise == WPA_CIPHER_CCMP) { -+ alg = WPA_ALG_CCMP; -+ klen = 16; -+ } else { -+ wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip " -+ "PTK configuration", sm->pairwise); -+ return; -+ } -+ -+ /* FIX: add STA entry to kernel/driver here? The set_key will fail -+ * most likely without this.. At the moment, STA entry is added only -+ * after association has been completed. This function will be called -+ * again after association to get the PTK configured, but that could be -+ * optimized by adding the STA entry earlier. -+ */ -+ if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, -+ sm->PTK.tk1, klen)) -+ return; -+ -+ /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ -+ sm->pairwise_set = TRUE; -+} -+ -+ -+static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm, -+ const u8 *ies, size_t ies_len, -+ u8 **resp_ies, size_t *resp_ies_len) -+{ -+ struct rsn_mdie *mdie; -+ struct rsn_ftie *ftie; -+ u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN]; -+ u8 ptk_name[WPA_PMK_NAME_LEN]; -+ struct wpa_auth_config *conf; -+ struct wpa_ft_ies parse; -+ size_t buflen, ptk_len; -+ int ret; -+ u8 *pos, *end; -+ int pairwise; -+ -+ *resp_ies = NULL; -+ *resp_ies_len = 0; -+ -+ sm->pmk_r1_name_valid = 0; -+ conf = &sm->wpa_auth->conf; -+ -+ wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs", -+ ies, ies_len); -+ -+ if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ mdie = (struct rsn_mdie *) parse.mdie; -+ if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || -+ os_memcmp(mdie->mobility_domain, -+ sm->wpa_auth->conf.mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); -+ return WLAN_STATUS_INVALID_MDIE; -+ } -+ -+ ftie = (struct rsn_ftie *) parse.ftie; -+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); -+ return WLAN_STATUS_INVALID_FTIE; -+ } -+ -+ os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); -+ -+ if (parse.r0kh_id == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID"); -+ return WLAN_STATUS_INVALID_FTIE; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID", -+ parse.r0kh_id, parse.r0kh_id_len); -+ os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len); -+ sm->r0kh_id_len = parse.r0kh_id_len; -+ -+ if (parse.rsn_pmkid == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE"); -+ return WLAN_STATUS_INVALID_PMKID; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name", -+ parse.rsn_pmkid, WPA_PMK_NAME_LEN); -+ wpa_derive_pmk_r1_name(parse.rsn_pmkid, -+ sm->wpa_auth->conf.r1_key_holder, sm->addr, -+ pmk_r1_name); -+ wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name", -+ pmk_r1_name, WPA_PMK_NAME_LEN); -+ -+ if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1, -+ &pairwise) < 0) { -+ if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id, -+ sm->r0kh_id_len, parse.rsn_pmkid) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Did not have matching " -+ "PMK-R1 and unknown R0KH-ID"); -+ return WLAN_STATUS_INVALID_PMKID; -+ } -+ -+ /* -+ * TODO: Should return "status pending" (and the caller should -+ * not send out response now). The real response will be sent -+ * once the response from R0KH is received. -+ */ -+ return WLAN_STATUS_INVALID_PMKID; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN); -+ sm->pmk_r1_name_valid = 1; -+ os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN); -+ -+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " -+ "ANonce"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", -+ sm->SNonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce", -+ sm->ANonce, WPA_NONCE_LEN); -+ -+ ptk_len = pairwise != WPA_CIPHER_CCMP ? 64 : 48; -+ wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, -+ sm->wpa_auth->addr, pmk_r1_name, -+ (u8 *) &sm->PTK, ptk_len, ptk_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", -+ (u8 *) &sm->PTK, ptk_len); -+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); -+ -+ sm->pairwise = pairwise; -+ wpa_ft_install_ptk(sm); -+ -+ buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + -+ 2 + FT_R1KH_ID_LEN + 200; -+ *resp_ies = os_zalloc(buflen); -+ if (*resp_ies == NULL) { -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ pos = *resp_ies; -+ end = *resp_ies + buflen; -+ -+ ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid); -+ if (ret < 0) { -+ os_free(*resp_ies); -+ *resp_ies = NULL; -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ pos += ret; -+ -+ ret = wpa_write_mdie(conf, pos, end - pos); -+ if (ret < 0) { -+ os_free(*resp_ies); -+ *resp_ies = NULL; -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ pos += ret; -+ -+ ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len, -+ sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0); -+ if (ret < 0) { -+ os_free(*resp_ies); -+ *resp_ies = NULL; -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ pos += ret; -+ -+ *resp_ies_len = pos - *resp_ies; -+ -+ return WLAN_STATUS_SUCCESS; -+} -+ -+ -+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, -+ u16 auth_transaction, const u8 *ies, size_t ies_len, -+ void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, -+ u16 auth_transaction, u16 status, -+ const u8 *ies, size_t ies_len), -+ void *ctx) -+{ -+ u16 status; -+ u8 *resp_ies; -+ size_t resp_ies_len; -+ -+ if (sm == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but " -+ "WPA SM not available"); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR -+ " BSSID=" MACSTR " transaction=%d", -+ MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction); -+ status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies, -+ &resp_ies_len); -+ -+ wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR -+ " auth_transaction=%d status=%d", -+ MAC2STR(sm->addr), auth_transaction + 1, status); -+ wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); -+ cb(ctx, sm->addr, bssid, auth_transaction + 1, status, -+ resp_ies, resp_ies_len); -+ os_free(resp_ies); -+} -+ -+ -+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, -+ size_t ies_len) -+{ -+ struct wpa_ft_ies parse; -+ struct rsn_mdie *mdie; -+ struct rsn_ftie *ftie; -+ u8 mic[16]; -+ unsigned int count; -+ -+ if (sm == NULL) -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ -+ wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len); -+ -+ if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ if (parse.rsn == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ if (parse.rsn_pmkid == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE"); -+ return WLAN_STATUS_INVALID_PMKID; -+ } -+ -+ if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) -+ { -+ wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match " -+ "with the PMKR1Name derived from auth request"); -+ return WLAN_STATUS_INVALID_PMKID; -+ } -+ -+ mdie = (struct rsn_mdie *) parse.mdie; -+ if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || -+ os_memcmp(mdie->mobility_domain, -+ sm->wpa_auth->conf.mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); -+ return WLAN_STATUS_INVALID_MDIE; -+ } -+ -+ ftie = (struct rsn_ftie *) parse.ftie; -+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); -+ return WLAN_STATUS_INVALID_FTIE; -+ } -+ -+ if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); -+ wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", -+ ftie->snonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", -+ sm->SNonce, WPA_NONCE_LEN); -+ return -1; -+ } -+ -+ if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); -+ wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", -+ ftie->anonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", -+ sm->ANonce, WPA_NONCE_LEN); -+ return -1; -+ } -+ -+ -+ if (parse.r0kh_id == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); -+ return -1; -+ } -+ -+ if (parse.r0kh_id_len != sm->r0kh_id_len || -+ os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " -+ "the current R0KH-ID"); -+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", -+ parse.r0kh_id, parse.r0kh_id_len); -+ wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", -+ sm->r0kh_id, sm->r0kh_id_len); -+ return -1; -+ } -+ -+ if (parse.r1kh_id == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); -+ return -1; -+ } -+ -+ if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder, -+ FT_R1KH_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " -+ "ReassocReq"); -+ wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE", -+ parse.r1kh_id, FT_R1KH_ID_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID", -+ sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN); -+ return -1; -+ } -+ -+ if (parse.rsn_pmkid == NULL || -+ os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { -+ wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " -+ "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); -+ return -1; -+ } -+ -+ count = 3; -+ if (parse.ric) -+ count++; -+ if (ftie->mic_control[1] != count) { -+ wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " -+ "Control: received %u expected %u", -+ ftie->mic_control[1], count); -+ return -1; -+ } -+ -+ if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5, -+ parse.mdie - 2, parse.mdie_len + 2, -+ parse.ftie - 2, parse.ftie_len + 2, -+ parse.rsn - 2, parse.rsn_len + 2, -+ parse.ric, parse.ric_len, -+ mic) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); -+ return WLAN_STATUS_UNSPECIFIED_FAILURE; -+ } -+ -+ if (os_memcmp(mic, ftie->mic, 16) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); -+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); -+ wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); -+ return WLAN_STATUS_INVALID_FTIE; -+ } -+ -+ return WLAN_STATUS_SUCCESS; -+} -+ -+ -+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len) -+{ -+ const u8 *sta_addr, *target_ap; -+ const u8 *ies; -+ size_t ies_len; -+ u8 action; -+ struct ft_rrb_frame *frame; -+ -+ if (sm == NULL) -+ return -1; -+ -+ /* -+ * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6] -+ * FT Request action frame body[variable] -+ */ -+ -+ if (len < 14) { -+ wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame " -+ "(len=%lu)", (unsigned long) len); -+ return -1; -+ } -+ -+ action = data[1]; -+ sta_addr = data + 2; -+ target_ap = data + 8; -+ ies = data + 14; -+ ies_len = len - 14; -+ -+ wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR -+ " Target AP=" MACSTR " Action=%d)", -+ MAC2STR(sta_addr), MAC2STR(target_ap), action); -+ -+ if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: " -+ "STA=" MACSTR " STA-Address=" MACSTR, -+ MAC2STR(sm->addr), MAC2STR(sta_addr)); -+ return -1; -+ } -+ -+ /* -+ * Do some sanity checking on the target AP address (not own and not -+ * broadcast. This could be extended to filter based on a list of known -+ * APs in the MD (if such a list were configured). -+ */ -+ if ((target_ap[0] & 0x01) || -+ os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action " -+ "frame"); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len); -+ -+ /* RRB - Forward action frame to the target AP */ -+ frame = os_malloc(sizeof(*frame) + len); -+ frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; -+ frame->packet_type = FT_PACKET_REQUEST; -+ frame->action_length = host_to_le16(len); -+ os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN); -+ os_memcpy(frame + 1, data, len); -+ -+ wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame, -+ sizeof(*frame) + len); -+ os_free(frame); -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, -+ const u8 *current_ap, const u8 *sta_addr, -+ const u8 *body, size_t len) -+{ -+ struct wpa_state_machine *sm; -+ u16 status; -+ u8 *resp_ies, *pos; -+ size_t resp_ies_len, rlen; -+ struct ft_rrb_frame *frame; -+ -+ sm = wpa_ft_add_sta(wpa_auth, sta_addr); -+ if (sm == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on " -+ "RRB Request"); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len); -+ -+ status = wpa_ft_process_auth_req(sm, body, len, &resp_ies, -+ &resp_ies_len); -+ -+ wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR -+ " CurrentAP=" MACSTR " status=%d", -+ MAC2STR(sm->addr), MAC2STR(current_ap), status); -+ wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); -+ -+ /* RRB - Forward action frame response to the Current AP */ -+ -+ /* -+ * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6] -+ * Status_Code[2] FT Request action frame body[variable] -+ */ -+ rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len; -+ -+ frame = os_malloc(sizeof(*frame) + rlen); -+ frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; -+ frame->packet_type = FT_PACKET_RESPONSE; -+ frame->action_length = host_to_le16(rlen); -+ os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN); -+ pos = (u8 *) (frame + 1); -+ *pos++ = WLAN_ACTION_FT; -+ *pos++ = 2; /* Action: Response */ -+ os_memcpy(pos, sta_addr, ETH_ALEN); -+ pos += ETH_ALEN; -+ os_memcpy(pos, wpa_auth->addr, ETH_ALEN); -+ pos += ETH_ALEN; -+ WPA_PUT_LE16(pos, status); -+ pos += 2; -+ if (resp_ies) { -+ os_memcpy(pos, resp_ies, resp_ies_len); -+ os_free(resp_ies); -+ } -+ -+ wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame, -+ sizeof(*frame) + rlen); -+ os_free(frame); -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, -+ const u8 *src_addr, -+ const u8 *data, size_t data_len) -+{ -+ struct ft_r0kh_r1kh_pull_frame *frame, f; -+ struct ft_remote_r1kh *r1kh; -+ struct ft_r0kh_r1kh_resp_frame resp, r; -+ u8 pmk_r0[PMK_LEN]; -+ int pairwise; -+ -+ wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull"); -+ -+ if (data_len < sizeof(*frame)) -+ return -1; -+ -+ r1kh = wpa_auth->conf.r1kh_list; -+ while (r1kh) { -+ if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ r1kh = r1kh->next; -+ } -+ if (r1kh == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for " -+ "PMK-R1 pull source address " MACSTR, -+ MAC2STR(src_addr)); -+ return -1; -+ } -+ -+ frame = (struct ft_r0kh_r1kh_pull_frame *) data; -+ /* aes_unwrap() does not support inplace decryption, so use a temporary -+ * buffer for the data. */ -+ if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, -+ frame->nonce, f.nonce) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull " -+ "request from " MACSTR, MAC2STR(src_addr)); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce", -+ f.nonce, sizeof(f.nonce)); -+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name", -+ f.pmk_r0_name, WPA_PMK_NAME_LEN); -+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID=" -+ MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id)); -+ -+ os_memset(&resp, 0, sizeof(resp)); -+ resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; -+ resp.packet_type = FT_PACKET_R0KH_R1KH_RESP; -+ resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN); -+ os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN); -+ -+ /* aes_wrap() does not support inplace encryption, so use a temporary -+ * buffer for the data. */ -+ os_memcpy(r.nonce, f.nonce, sizeof(f.nonce)); -+ os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN); -+ os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN); -+ if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0, -+ &pairwise) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for " -+ "PMK-R1 pull"); -+ return -1; -+ } -+ -+ wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id, -+ r.pmk_r1, r.pmk_r1_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name, -+ WPA_PMK_NAME_LEN); -+ r.pairwise = host_to_le16(pairwise); -+ -+ if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, -+ r.nonce, resp.nonce) < 0) { -+ os_memset(pmk_r0, 0, PMK_LEN); -+ return -1; -+ } -+ -+ os_memset(pmk_r0, 0, PMK_LEN); -+ -+ wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp)); -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, -+ const u8 *src_addr, -+ const u8 *data, size_t data_len) -+{ -+ struct ft_r0kh_r1kh_resp_frame *frame, f; -+ struct ft_remote_r0kh *r0kh; -+ int pairwise; -+ -+ wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response"); -+ -+ if (data_len < sizeof(*frame)) -+ return -1; -+ -+ r0kh = wpa_auth->conf.r0kh_list; -+ while (r0kh) { -+ if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ r0kh = r0kh->next; -+ } -+ if (r0kh == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for " -+ "PMK-R0 pull response source address " MACSTR, -+ MAC2STR(src_addr)); -+ return -1; -+ } -+ -+ frame = (struct ft_r0kh_r1kh_resp_frame *) data; -+ /* aes_unwrap() does not support inplace decryption, so use a temporary -+ * buffer for the data. */ -+ if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, -+ frame->nonce, f.nonce) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull " -+ "response from " MACSTR, MAC2STR(src_addr)); -+ return -1; -+ } -+ -+ if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN) -+ != 0) { -+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a " -+ "matching R1KH-ID"); -+ return -1; -+ } -+ -+ /* TODO: verify that matches with a pending request -+ * and call this requests callback function to finish request -+ * processing */ -+ -+ pairwise = le_to_host16(f.pairwise); -+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce", -+ f.nonce, sizeof(f.nonce)); -+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID=" -+ MACSTR " pairwise=0x%x", -+ MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1", -+ f.pmk_r1, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name", -+ f.pmk_r1_name, WPA_PMK_NAME_LEN); -+ -+ wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, -+ pairwise); -+ os_memset(f.pmk_r1, 0, PMK_LEN); -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, -+ const u8 *src_addr, -+ const u8 *data, size_t data_len) -+{ -+ struct ft_r0kh_r1kh_push_frame *frame, f; -+ struct ft_remote_r0kh *r0kh; -+ struct os_time now; -+ os_time_t tsend; -+ int pairwise; -+ -+ wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push"); -+ -+ if (data_len < sizeof(*frame)) -+ return -1; -+ -+ r0kh = wpa_auth->conf.r0kh_list; -+ while (r0kh) { -+ if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ r0kh = r0kh->next; -+ } -+ if (r0kh == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for " -+ "PMK-R0 push source address " MACSTR, -+ MAC2STR(src_addr)); -+ return -1; -+ } -+ -+ frame = (struct ft_r0kh_r1kh_push_frame *) data; -+ /* aes_unwrap() does not support inplace decryption, so use a temporary -+ * buffer for the data. */ -+ if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, -+ frame->timestamp, f.timestamp) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from " -+ MACSTR, MAC2STR(src_addr)); -+ return -1; -+ } -+ -+ os_get_time(&now); -+ tsend = WPA_GET_LE32(f.timestamp); -+ if ((now.sec > tsend && now.sec - tsend > 60) || -+ (now.sec < tsend && tsend - now.sec > 60)) { -+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid " -+ "timestamp: sender time %d own time %d\n", -+ (int) tsend, (int) now.sec); -+ return -1; -+ } -+ -+ if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN) -+ != 0) { -+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching " -+ "R1KH-ID (received " MACSTR " own " MACSTR ")", -+ MAC2STR(f.r1kh_id), -+ MAC2STR(wpa_auth->conf.r1_key_holder)); -+ return -1; -+ } -+ -+ pairwise = le_to_host16(f.pairwise); -+ wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID=" -+ MACSTR " pairwise=0x%x", -+ MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1", -+ f.pmk_r1, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name", -+ f.pmk_r1_name, WPA_PMK_NAME_LEN); -+ -+ wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, -+ pairwise); -+ os_memset(f.pmk_r1, 0, PMK_LEN); -+ -+ return 0; -+} -+ -+ -+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, -+ const u8 *data, size_t data_len) -+{ -+ struct ft_rrb_frame *frame; -+ u16 alen; -+ const u8 *pos, *end, *start; -+ u8 action; -+ const u8 *sta_addr, *target_ap_addr; -+ -+ wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR, -+ MAC2STR(src_addr)); -+ -+ if (data_len < sizeof(*frame)) { -+ wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)", -+ (unsigned long) data_len); -+ return -1; -+ } -+ -+ pos = data; -+ frame = (struct ft_rrb_frame *) pos; -+ pos += sizeof(*frame); -+ -+ alen = le_to_host16(frame->action_length); -+ wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d " -+ "action_length=%d ap_address=" MACSTR, -+ frame->frame_type, frame->packet_type, alen, -+ MAC2STR(frame->ap_address)); -+ -+ if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) { -+ /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */ -+ wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with " -+ "unrecognized type %d", frame->frame_type); -+ return -1; -+ } -+ -+ if (alen > data_len - sizeof(*frame)) { -+ wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action " -+ "frame"); -+ return -1; -+ } -+ -+ if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL) -+ return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len); -+ if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP) -+ return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len); -+ if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH) -+ return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len); -+ -+ wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen); -+ -+ if (alen < 1 + 1 + 2 * ETH_ALEN) { -+ wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough " -+ "room for Action Frame body); alen=%lu", -+ (unsigned long) alen); -+ return -1; -+ } -+ start = pos; -+ end = pos + alen; -+ -+ if (*pos != WLAN_ACTION_FT) { -+ wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category " -+ "%d", *pos); -+ return -1; -+ } -+ -+ pos++; -+ action = *pos++; -+ sta_addr = pos; -+ pos += ETH_ALEN; -+ target_ap_addr = pos; -+ pos += ETH_ALEN; -+ wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr=" -+ MACSTR " target_ap_addr=" MACSTR, -+ action, MAC2STR(sta_addr), MAC2STR(target_ap_addr)); -+ -+ if (frame->packet_type == FT_PACKET_REQUEST) { -+ wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request"); -+ -+ if (action != 1) { -+ wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in " -+ "RRB Request", action); -+ return -1; -+ } -+ -+ if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Target AP address in the " -+ "RRB Request does not match with own " -+ "address"); -+ return -1; -+ } -+ -+ if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address, -+ sta_addr, pos, end - pos) < 0) -+ return -1; -+ } else if (frame->packet_type == FT_PACKET_RESPONSE) { -+ u16 status_code; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "FT: Not enough room for status " -+ "code in RRB Response"); -+ return -1; -+ } -+ status_code = WPA_GET_LE16(pos); -+ pos += 2; -+ -+ wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response " -+ "(status_code=%d)", status_code); -+ -+ if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0) -+ return -1; -+ } else { -+ wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown " -+ "packet_type %d", frame->packet_type); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth, -+ struct wpa_ft_pmk_r0_sa *pmk_r0, -+ struct ft_remote_r1kh *r1kh, -+ const u8 *s1kh_id, int pairwise) -+{ -+ struct ft_r0kh_r1kh_push_frame frame, f; -+ struct os_time now; -+ -+ os_memset(&frame, 0, sizeof(frame)); -+ frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB; -+ frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH; -+ frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN); -+ os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN); -+ -+ /* aes_wrap() does not support inplace encryption, so use a temporary -+ * buffer for the data. */ -+ os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN); -+ os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN); -+ os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN); -+ wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id, -+ s1kh_id, f.pmk_r1, f.pmk_r1_name); -+ wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id)); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name, -+ WPA_PMK_NAME_LEN); -+ os_get_time(&now); -+ WPA_PUT_LE32(f.timestamp, now.sec); -+ f.pairwise = host_to_le16(pairwise); -+ if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, -+ f.timestamp, frame.timestamp) < 0) -+ return; -+ -+ wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame)); -+} -+ -+ -+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) -+{ -+ struct wpa_ft_pmk_r0_sa *r0; -+ struct ft_remote_r1kh *r1kh; -+ -+ if (!wpa_auth->conf.pmk_r1_push) -+ return; -+ -+ r0 = wpa_auth->ft_pmk_cache->pmk_r0; -+ while (r0) { -+ if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) -+ break; -+ r0 = r0->next; -+ } -+ -+ if (r0 == NULL || r0->pmk_r1_pushed) -+ return; -+ r0->pmk_r1_pushed = 1; -+ -+ wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs " -+ "for STA " MACSTR, MAC2STR(addr)); -+ -+ r1kh = wpa_auth->conf.r1kh_list; -+ while (r1kh) { -+ wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise); -+ r1kh = r1kh->next; -+ } -+} -+ -+#endif /* CONFIG_IEEE80211R */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.c -new file mode 100644 -index 0000000000000..bdb3ed254cdd1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.c -@@ -0,0 +1,571 @@ -+/* -+ * hostapd / WPA authenticator glue code -+ * Copyright (c) 2002-2011, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "eapol_auth/eapol_auth_sm_i.h" -+#include "eap_server/eap.h" -+#include "l2_packet/l2_packet.h" -+#include "drivers/driver.h" -+#include "hostapd.h" -+#include "ieee802_1x.h" -+#include "preauth_auth.h" -+#include "sta_info.h" -+#include "tkip_countermeasures.h" -+#include "ap_drv_ops.h" -+#include "ap_config.h" -+#include "wpa_auth.h" -+ -+ -+static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, -+ struct wpa_auth_config *wconf) -+{ -+ wconf->wpa = conf->wpa; -+ wconf->wpa_key_mgmt = conf->wpa_key_mgmt; -+ wconf->wpa_pairwise = conf->wpa_pairwise; -+ wconf->wpa_group = conf->wpa_group; -+ wconf->wpa_group_rekey = conf->wpa_group_rekey; -+ wconf->wpa_strict_rekey = conf->wpa_strict_rekey; -+ wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey; -+ wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey; -+ wconf->rsn_pairwise = conf->rsn_pairwise; -+ wconf->rsn_preauth = conf->rsn_preauth; -+ wconf->eapol_version = conf->eapol_version; -+ wconf->peerkey = conf->peerkey; -+ wconf->wmm_enabled = conf->wmm_enabled; -+ wconf->wmm_uapsd = conf->wmm_uapsd; -+ wconf->okc = conf->okc; -+#ifdef CONFIG_IEEE80211W -+ wconf->ieee80211w = conf->ieee80211w; -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_IEEE80211R -+ wconf->ssid_len = conf->ssid.ssid_len; -+ if (wconf->ssid_len > SSID_LEN) -+ wconf->ssid_len = SSID_LEN; -+ os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); -+ os_memcpy(wconf->mobility_domain, conf->mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN); -+ if (conf->nas_identifier && -+ os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) { -+ wconf->r0_key_holder_len = os_strlen(conf->nas_identifier); -+ os_memcpy(wconf->r0_key_holder, conf->nas_identifier, -+ wconf->r0_key_holder_len); -+ } -+ os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); -+ wconf->r0_key_lifetime = conf->r0_key_lifetime; -+ wconf->reassociation_deadline = conf->reassociation_deadline; -+ wconf->r0kh_list = conf->r0kh_list; -+ wconf->r1kh_list = conf->r1kh_list; -+ wconf->pmk_r1_push = conf->pmk_r1_push; -+ wconf->ft_over_ds = conf->ft_over_ds; -+#endif /* CONFIG_IEEE80211R */ -+} -+ -+ -+static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr, -+ logger_level level, const char *txt) -+{ -+#ifndef CONFIG_NO_HOSTAPD_LOGGER -+ struct hostapd_data *hapd = ctx; -+ int hlevel; -+ -+ switch (level) { -+ case LOGGER_WARNING: -+ hlevel = HOSTAPD_LEVEL_WARNING; -+ break; -+ case LOGGER_INFO: -+ hlevel = HOSTAPD_LEVEL_INFO; -+ break; -+ case LOGGER_DEBUG: -+ default: -+ hlevel = HOSTAPD_LEVEL_DEBUG; -+ break; -+ } -+ -+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt); -+#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -+} -+ -+ -+static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr, -+ u16 reason) -+{ -+ struct hostapd_data *hapd = ctx; -+ wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: " -+ "STA " MACSTR " reason %d", -+ __func__, MAC2STR(addr), reason); -+ ap_sta_disconnect(hapd, NULL, addr, reason); -+} -+ -+ -+static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) -+{ -+ struct hostapd_data *hapd = ctx; -+ michael_mic_failure(hapd, addr, 0); -+} -+ -+ -+static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr, -+ wpa_eapol_variable var, int value) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta = ap_get_sta(hapd, addr); -+ if (sta == NULL) -+ return; -+ switch (var) { -+ case WPA_EAPOL_portEnabled: -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, value); -+ break; -+ case WPA_EAPOL_portValid: -+ ieee802_1x_notify_port_valid(sta->eapol_sm, value); -+ break; -+ case WPA_EAPOL_authorized: -+ ieee802_1x_set_sta_authorized(hapd, sta, value); -+ break; -+ case WPA_EAPOL_portControl_Auto: -+ if (sta->eapol_sm) -+ sta->eapol_sm->portControl = Auto; -+ break; -+ case WPA_EAPOL_keyRun: -+ if (sta->eapol_sm) -+ sta->eapol_sm->keyRun = value ? TRUE : FALSE; -+ break; -+ case WPA_EAPOL_keyAvailable: -+ if (sta->eapol_sm) -+ sta->eapol_sm->eap_if->eapKeyAvailable = -+ value ? TRUE : FALSE; -+ break; -+ case WPA_EAPOL_keyDone: -+ if (sta->eapol_sm) -+ sta->eapol_sm->keyDone = value ? TRUE : FALSE; -+ break; -+ case WPA_EAPOL_inc_EapolFramesTx: -+ if (sta->eapol_sm) -+ sta->eapol_sm->dot1xAuthEapolFramesTx++; -+ break; -+ } -+} -+ -+ -+static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, -+ wpa_eapol_variable var) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta = ap_get_sta(hapd, addr); -+ if (sta == NULL || sta->eapol_sm == NULL) -+ return -1; -+ switch (var) { -+ case WPA_EAPOL_keyRun: -+ return sta->eapol_sm->keyRun; -+ case WPA_EAPOL_keyAvailable: -+ return sta->eapol_sm->eap_if->eapKeyAvailable; -+ default: -+ return -1; -+ } -+} -+ -+ -+static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, -+ const u8 *prev_psk) -+{ -+ struct hostapd_data *hapd = ctx; -+ return hostapd_get_psk(hapd->conf, addr, prev_psk); -+} -+ -+ -+static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, -+ size_t *len) -+{ -+ struct hostapd_data *hapd = ctx; -+ const u8 *key; -+ size_t keylen; -+ struct sta_info *sta; -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta == NULL) -+ return -1; -+ -+ key = ieee802_1x_get_key(sta->eapol_sm, &keylen); -+ if (key == NULL) -+ return -1; -+ -+ if (keylen > *len) -+ keylen = *len; -+ os_memcpy(msk, key, keylen); -+ *len = keylen; -+ -+ return 0; -+} -+ -+ -+static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, -+ const u8 *addr, int idx, u8 *key, -+ size_t key_len) -+{ -+ struct hostapd_data *hapd = ctx; -+ const char *ifname = hapd->conf->iface; -+ -+ if (vlan_id > 0) { -+ ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); -+ if (ifname == NULL) -+ return -1; -+ } -+ -+ return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, -+ key, key_len); -+} -+ -+ -+static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, -+ u8 *seq) -+{ -+ struct hostapd_data *hapd = ctx; -+ return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq); -+} -+ -+ -+static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, -+ const u8 *data, size_t data_len, -+ int encrypt) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta; -+ u32 flags = 0; -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta) -+ flags = hostapd_sta_flags_to_drv(sta->flags); -+ -+ return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len, -+ encrypt, flags); -+} -+ -+ -+static int hostapd_wpa_auth_for_each_sta( -+ void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), -+ void *cb_ctx) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta; -+ -+ for (sta = hapd->sta_list; sta; sta = sta->next) { -+ if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) -+ return 1; -+ } -+ return 0; -+} -+ -+ -+struct wpa_auth_iface_iter_data { -+ int (*cb)(struct wpa_authenticator *sm, void *ctx); -+ void *cb_ctx; -+}; -+ -+static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx) -+{ -+ struct wpa_auth_iface_iter_data *data = ctx; -+ size_t i; -+ for (i = 0; i < iface->num_bss; i++) { -+ if (iface->bss[i]->wpa_auth && -+ data->cb(iface->bss[i]->wpa_auth, data->cb_ctx)) -+ return 1; -+ } -+ return 0; -+} -+ -+ -+static int hostapd_wpa_auth_for_each_auth( -+ void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx), -+ void *cb_ctx) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct wpa_auth_iface_iter_data data; -+ if (hapd->iface->for_each_interface == NULL) -+ return -1; -+ data.cb = cb; -+ data.cb_ctx = cb_ctx; -+ return hapd->iface->for_each_interface(hapd->iface->interfaces, -+ wpa_auth_iface_iter, &data); -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+ -+struct wpa_auth_ft_iface_iter_data { -+ struct hostapd_data *src_hapd; -+ const u8 *dst; -+ const u8 *data; -+ size_t data_len; -+}; -+ -+ -+static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx) -+{ -+ struct wpa_auth_ft_iface_iter_data *idata = ctx; -+ struct hostapd_data *hapd; -+ size_t j; -+ -+ for (j = 0; j < iface->num_bss; j++) { -+ hapd = iface->bss[j]; -+ if (hapd == idata->src_hapd) -+ continue; -+ if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) { -+ wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to " -+ "locally managed BSS " MACSTR "@%s -> " -+ MACSTR "@%s", -+ MAC2STR(idata->src_hapd->own_addr), -+ idata->src_hapd->conf->iface, -+ MAC2STR(hapd->own_addr), hapd->conf->iface); -+ wpa_ft_rrb_rx(hapd->wpa_auth, -+ idata->src_hapd->own_addr, -+ idata->data, idata->data_len); -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, -+ const u8 *data, size_t data_len) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct l2_ethhdr *buf; -+ int ret; -+ -+#ifdef CONFIG_IEEE80211R -+ if (proto == ETH_P_RRB && hapd->iface->for_each_interface) { -+ int res; -+ struct wpa_auth_ft_iface_iter_data idata; -+ idata.src_hapd = hapd; -+ idata.dst = dst; -+ idata.data = data; -+ idata.data_len = data_len; -+ res = hapd->iface->for_each_interface(hapd->iface->interfaces, -+ hostapd_wpa_auth_ft_iter, -+ &idata); -+ if (res == 1) -+ return data_len; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ if (hapd->driver && hapd->driver->send_ether) -+ return hapd->driver->send_ether(hapd->drv_priv, dst, -+ hapd->own_addr, proto, -+ data, data_len); -+ if (hapd->l2 == NULL) -+ return -1; -+ -+ buf = os_malloc(sizeof(*buf) + data_len); -+ if (buf == NULL) -+ return -1; -+ os_memcpy(buf->h_dest, dst, ETH_ALEN); -+ os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN); -+ buf->h_proto = host_to_be16(proto); -+ os_memcpy(buf + 1, data, data_len); -+ ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf, -+ sizeof(*buf) + data_len); -+ os_free(buf); -+ return ret; -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+ -+static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, -+ const u8 *data, size_t data_len) -+{ -+ struct hostapd_data *hapd = ctx; -+ int res; -+ struct ieee80211_mgmt *m; -+ size_t mlen; -+ struct sta_info *sta; -+ -+ sta = ap_get_sta(hapd, dst); -+ if (sta == NULL || sta->wpa_sm == NULL) -+ return -1; -+ -+ m = os_zalloc(sizeof(*m) + data_len); -+ if (m == NULL) -+ return -1; -+ mlen = ((u8 *) &m->u - (u8 *) m) + data_len; -+ m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_ACTION); -+ os_memcpy(m->da, dst, ETH_ALEN); -+ os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); -+ os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); -+ os_memcpy(&m->u, data, data_len); -+ -+ res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen); -+ os_free(m); -+ return res; -+} -+ -+ -+static struct wpa_state_machine * -+hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct sta_info *sta; -+ -+ sta = ap_sta_add(hapd, sta_addr); -+ if (sta == NULL) -+ return NULL; -+ if (sta->wpa_sm) { -+ sta->auth_alg = WLAN_AUTH_FT; -+ return sta->wpa_sm; -+ } -+ -+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr); -+ if (sta->wpa_sm == NULL) { -+ ap_free_sta(hapd, sta); -+ return NULL; -+ } -+ sta->auth_alg = WLAN_AUTH_FT; -+ -+ return sta->wpa_sm; -+} -+ -+ -+static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, -+ size_t len) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct l2_ethhdr *ethhdr; -+ if (len < sizeof(*ethhdr)) -+ return; -+ ethhdr = (struct l2_ethhdr *) buf; -+ wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " -+ MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest)); -+ wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr), -+ len - sizeof(*ethhdr)); -+} -+ -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+int hostapd_setup_wpa(struct hostapd_data *hapd) -+{ -+ struct wpa_auth_config _conf; -+ struct wpa_auth_callbacks cb; -+ const u8 *wpa_ie; -+ size_t wpa_ie_len; -+ -+ hostapd_wpa_auth_conf(hapd->conf, &_conf); -+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS) -+ _conf.tx_status = 1; -+ os_memset(&cb, 0, sizeof(cb)); -+ cb.ctx = hapd; -+ cb.logger = hostapd_wpa_auth_logger; -+ cb.disconnect = hostapd_wpa_auth_disconnect; -+ cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report; -+ cb.set_eapol = hostapd_wpa_auth_set_eapol; -+ cb.get_eapol = hostapd_wpa_auth_get_eapol; -+ cb.get_psk = hostapd_wpa_auth_get_psk; -+ cb.get_msk = hostapd_wpa_auth_get_msk; -+ cb.set_key = hostapd_wpa_auth_set_key; -+ cb.get_seqnum = hostapd_wpa_auth_get_seqnum; -+ cb.send_eapol = hostapd_wpa_auth_send_eapol; -+ cb.for_each_sta = hostapd_wpa_auth_for_each_sta; -+ cb.for_each_auth = hostapd_wpa_auth_for_each_auth; -+ cb.send_ether = hostapd_wpa_auth_send_ether; -+#ifdef CONFIG_IEEE80211R -+ cb.send_ft_action = hostapd_wpa_auth_send_ft_action; -+ cb.add_sta = hostapd_wpa_auth_add_sta; -+#endif /* CONFIG_IEEE80211R */ -+ hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb); -+ if (hapd->wpa_auth == NULL) { -+ wpa_printf(MSG_ERROR, "WPA initialization failed."); -+ return -1; -+ } -+ -+ if (hostapd_set_privacy(hapd, 1)) { -+ wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked " -+ "for interface %s", hapd->conf->iface); -+ return -1; -+ } -+ -+ wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); -+ if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) { -+ wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " -+ "the kernel driver."); -+ return -1; -+ } -+ -+ if (rsn_preauth_iface_init(hapd)) { -+ wpa_printf(MSG_ERROR, "Initialization of RSN " -+ "pre-authentication failed."); -+ return -1; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ if (!hostapd_drv_none(hapd)) { -+ hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ? -+ hapd->conf->bridge : -+ hapd->conf->iface, NULL, ETH_P_RRB, -+ hostapd_rrb_receive, hapd, 1); -+ if (hapd->l2 == NULL && -+ (hapd->driver == NULL || -+ hapd->driver->send_ether == NULL)) { -+ wpa_printf(MSG_ERROR, "Failed to open l2_packet " -+ "interface"); -+ return -1; -+ } -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ return 0; -+ -+} -+ -+ -+void hostapd_reconfig_wpa(struct hostapd_data *hapd) -+{ -+ struct wpa_auth_config wpa_auth_conf; -+ hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf); -+ wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf); -+} -+ -+ -+void hostapd_deinit_wpa(struct hostapd_data *hapd) -+{ -+ rsn_preauth_iface_deinit(hapd); -+ if (hapd->wpa_auth) { -+ wpa_deinit(hapd->wpa_auth); -+ hapd->wpa_auth = NULL; -+ -+ if (hostapd_set_privacy(hapd, 0)) { -+ wpa_printf(MSG_DEBUG, "Could not disable " -+ "PrivacyInvoked for interface %s", -+ hapd->conf->iface); -+ } -+ -+ if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) { -+ wpa_printf(MSG_DEBUG, "Could not remove generic " -+ "information element from interface %s", -+ hapd->conf->iface); -+ } -+ } -+ ieee802_1x_deinit(hapd); -+ -+#ifdef CONFIG_IEEE80211R -+ l2_packet_deinit(hapd->l2); -+#endif /* CONFIG_IEEE80211R */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.h -new file mode 100644 -index 0000000000000..79d7e05c40550 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_glue.h -@@ -0,0 +1,22 @@ -+/* -+ * hostapd / WPA authenticator glue code -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_AUTH_GLUE_H -+#define WPA_AUTH_GLUE_H -+ -+int hostapd_setup_wpa(struct hostapd_data *hapd); -+void hostapd_reconfig_wpa(struct hostapd_data *hapd); -+void hostapd_deinit_wpa(struct hostapd_data *hapd); -+ -+#endif /* WPA_AUTH_GLUE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_i.h -new file mode 100644 -index 0000000000000..67a5c3bf45ae6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_i.h -@@ -0,0 +1,234 @@ -+/* -+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_AUTH_I_H -+#define WPA_AUTH_I_H -+ -+/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */ -+#define RSNA_MAX_EAPOL_RETRIES 4 -+ -+struct wpa_group; -+ -+struct wpa_stsl_negotiation { -+ struct wpa_stsl_negotiation *next; -+ u8 initiator[ETH_ALEN]; -+ u8 peer[ETH_ALEN]; -+}; -+ -+ -+struct wpa_state_machine { -+ struct wpa_authenticator *wpa_auth; -+ struct wpa_group *group; -+ -+ u8 addr[ETH_ALEN]; -+ -+ enum { -+ WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED, -+ WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2, -+ WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART, -+ WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2, -+ WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE -+ } wpa_ptk_state; -+ -+ enum { -+ WPA_PTK_GROUP_IDLE = 0, -+ WPA_PTK_GROUP_REKEYNEGOTIATING, -+ WPA_PTK_GROUP_REKEYESTABLISHED, -+ WPA_PTK_GROUP_KEYERROR -+ } wpa_ptk_group_state; -+ -+ Boolean Init; -+ Boolean DeauthenticationRequest; -+ Boolean AuthenticationRequest; -+ Boolean ReAuthenticationRequest; -+ Boolean Disconnect; -+ int TimeoutCtr; -+ int GTimeoutCtr; -+ Boolean TimeoutEvt; -+ Boolean EAPOLKeyReceived; -+ Boolean EAPOLKeyPairwise; -+ Boolean EAPOLKeyRequest; -+ Boolean MICVerified; -+ Boolean GUpdateStationKeys; -+ u8 ANonce[WPA_NONCE_LEN]; -+ u8 SNonce[WPA_NONCE_LEN]; -+ u8 PMK[PMK_LEN]; -+ struct wpa_ptk PTK; -+ Boolean PTK_valid; -+ Boolean pairwise_set; -+ int keycount; -+ Boolean Pair; -+ struct { -+ u8 counter[WPA_REPLAY_COUNTER_LEN]; -+ Boolean valid; -+ } key_replay[RSNA_MAX_EAPOL_RETRIES]; -+ Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */ -+ Boolean PTKRequest; /* not in IEEE 802.11i state machine */ -+ Boolean has_GTK; -+ Boolean PtkGroupInit; /* init request for PTK Group state machine */ -+ -+ u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */ -+ size_t last_rx_eapol_key_len; -+ -+ unsigned int changed:1; -+ unsigned int in_step_loop:1; -+ unsigned int pending_deinit:1; -+ unsigned int started:1; -+ unsigned int mgmt_frame_prot:1; -+#ifdef CONFIG_IEEE80211R -+ unsigned int ft_completed:1; -+ unsigned int pmk_r1_name_valid:1; -+#endif /* CONFIG_IEEE80211R */ -+ -+ u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN]; -+ int req_replay_counter_used; -+ -+ u8 *wpa_ie; -+ size_t wpa_ie_len; -+ -+ enum { -+ WPA_VERSION_NO_WPA = 0 /* WPA not used */, -+ WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */, -+ WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */ -+ } wpa; -+ int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */ -+ int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */ -+ struct rsn_pmksa_cache_entry *pmksa; -+ -+ u32 dot11RSNAStatsTKIPLocalMICFailures; -+ u32 dot11RSNAStatsTKIPRemoteMICFailures; -+ -+#ifdef CONFIG_IEEE80211R -+ u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ -+ size_t xxkey_len; -+ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth -+ * Request */ -+ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */ -+ size_t r0kh_id_len; -+ u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key -+ * message 2/4 */ -+ u8 *assoc_resp_ftie; -+#endif /* CONFIG_IEEE80211R */ -+ -+ int pending_1_of_4_timeout; -+}; -+ -+ -+/* per group key state machine data */ -+struct wpa_group { -+ struct wpa_group *next; -+ int vlan_id; -+ -+ Boolean GInit; -+ int GKeyDoneStations; -+ Boolean GTKReKey; -+ int GTK_len; -+ int GN, GM; -+ Boolean GTKAuthenticator; -+ u8 Counter[WPA_NONCE_LEN]; -+ -+ enum { -+ WPA_GROUP_GTK_INIT = 0, -+ WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE -+ } wpa_group_state; -+ -+ u8 GMK[WPA_GMK_LEN]; -+ u8 GTK[2][WPA_GTK_MAX_LEN]; -+ u8 GNonce[WPA_NONCE_LEN]; -+ Boolean changed; -+ Boolean first_sta_seen; -+ Boolean reject_4way_hs_for_entropy; -+#ifdef CONFIG_IEEE80211W -+ u8 IGTK[2][WPA_IGTK_LEN]; -+ int GN_igtk, GM_igtk; -+#endif /* CONFIG_IEEE80211W */ -+}; -+ -+ -+struct wpa_ft_pmk_cache; -+ -+/* per authenticator data */ -+struct wpa_authenticator { -+ struct wpa_group *group; -+ -+ unsigned int dot11RSNAStatsTKIPRemoteMICFailures; -+ u32 dot11RSNAAuthenticationSuiteSelected; -+ u32 dot11RSNAPairwiseCipherSelected; -+ u32 dot11RSNAGroupCipherSelected; -+ u8 dot11RSNAPMKIDUsed[PMKID_LEN]; -+ u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */ -+ u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */ -+ u32 dot11RSNAGroupCipherRequested; /* FIX: update */ -+ unsigned int dot11RSNATKIPCounterMeasuresInvoked; -+ unsigned int dot11RSNA4WayHandshakeFailures; -+ -+ struct wpa_stsl_negotiation *stsl_negotiations; -+ -+ struct wpa_auth_config conf; -+ struct wpa_auth_callbacks cb; -+ -+ u8 *wpa_ie; -+ size_t wpa_ie_len; -+ -+ u8 addr[ETH_ALEN]; -+ -+ struct rsn_pmksa_cache *pmksa; -+ struct wpa_ft_pmk_cache *ft_pmk_cache; -+}; -+ -+ -+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, -+ const u8 *pmkid); -+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, -+ logger_level level, const char *txt); -+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, -+ logger_level level, const char *fmt, ...); -+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, int key_info, -+ const u8 *key_rsc, const u8 *nonce, -+ const u8 *kde, size_t kde_len, -+ int keyidx, int encr, int force_version); -+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, -+ int (*cb)(struct wpa_state_machine *sm, void *ctx), -+ void *cb_ctx); -+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, -+ int (*cb)(struct wpa_authenticator *a, void *ctx), -+ void *cb_ctx); -+ -+#ifdef CONFIG_PEERKEY -+int wpa_stsl_remove(struct wpa_authenticator *wpa_auth, -+ struct wpa_stsl_negotiation *neg); -+void wpa_smk_error(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, struct wpa_eapol_key *key); -+void wpa_smk_m1(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, struct wpa_eapol_key *key); -+void wpa_smk_m3(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, struct wpa_eapol_key *key); -+#endif /* CONFIG_PEERKEY */ -+ -+#ifdef CONFIG_IEEE80211R -+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); -+int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, -+ size_t r0kh_id_len, -+ const u8 *anonce, const u8 *snonce, -+ u8 *buf, size_t len, const u8 *subelem, -+ size_t subelem_len); -+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, -+ struct wpa_ptk *ptk, size_t ptk_len); -+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); -+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); -+void wpa_ft_install_ptk(struct wpa_state_machine *sm); -+#endif /* CONFIG_IEEE80211R */ -+ -+#endif /* WPA_AUTH_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.c -new file mode 100644 -index 0000000000000..5e8d1349b1dec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.c -@@ -0,0 +1,824 @@ -+/* -+ * hostapd - WPA/RSN IE and KDE definitions -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "common/ieee802_11_defs.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "ap_config.h" -+#include "ieee802_11.h" -+#include "wpa_auth.h" -+#include "pmksa_cache_auth.h" -+#include "wpa_auth_ie.h" -+#include "wpa_auth_i.h" -+ -+ -+#ifdef CONFIG_RSN_TESTING -+int rsn_testing = 0; -+#endif /* CONFIG_RSN_TESTING */ -+ -+ -+static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len) -+{ -+ struct wpa_ie_hdr *hdr; -+ int num_suites; -+ u8 *pos, *count; -+ -+ hdr = (struct wpa_ie_hdr *) buf; -+ hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; -+ RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); -+ WPA_PUT_LE16(hdr->version, WPA_VERSION); -+ pos = (u8 *) (hdr + 1); -+ -+ if (conf->wpa_group == WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); -+ } else if (conf->wpa_group == WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); -+ } else if (conf->wpa_group == WPA_CIPHER_WEP104) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); -+ } else if (conf->wpa_group == WPA_CIPHER_WEP40) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); -+ } else { -+ wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", -+ conf->wpa_group); -+ return -1; -+ } -+ pos += WPA_SELECTOR_LEN; -+ -+ num_suites = 0; -+ count = pos; -+ pos += 2; -+ -+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); -+ pos += WPA_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); -+ pos += WPA_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->wpa_pairwise & WPA_CIPHER_NONE) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); -+ pos += WPA_SELECTOR_LEN; -+ num_suites++; -+ } -+ -+ if (num_suites == 0) { -+ wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", -+ conf->wpa_pairwise); -+ return -1; -+ } -+ WPA_PUT_LE16(count, num_suites); -+ -+ num_suites = 0; -+ count = pos; -+ pos += 2; -+ -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { -+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); -+ pos += WPA_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { -+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); -+ pos += WPA_SELECTOR_LEN; -+ num_suites++; -+ } -+ -+ if (num_suites == 0) { -+ wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", -+ conf->wpa_key_mgmt); -+ return -1; -+ } -+ WPA_PUT_LE16(count, num_suites); -+ -+ /* WPA Capabilities; use defaults, so no need to include it */ -+ -+ hdr->len = (pos - buf) - 2; -+ -+ return pos - buf; -+} -+ -+ -+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, -+ const u8 *pmkid) -+{ -+ struct rsn_ie_hdr *hdr; -+ int num_suites; -+ u8 *pos, *count; -+ u16 capab; -+ -+ hdr = (struct rsn_ie_hdr *) buf; -+ hdr->elem_id = WLAN_EID_RSN; -+ WPA_PUT_LE16(hdr->version, RSN_VERSION); -+ pos = (u8 *) (hdr + 1); -+ -+ if (conf->wpa_group == WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ } else if (conf->wpa_group == WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ } else if (conf->wpa_group == WPA_CIPHER_WEP104) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); -+ } else if (conf->wpa_group == WPA_CIPHER_WEP40) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); -+ } else { -+ wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).", -+ conf->wpa_group); -+ return -1; -+ } -+ pos += RSN_SELECTOR_LEN; -+ -+ num_suites = 0; -+ count = pos; -+ pos += 2; -+ -+#ifdef CONFIG_RSN_TESTING -+ if (rsn_testing) { -+ RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+#endif /* CONFIG_RSN_TESTING */ -+ -+ if (conf->rsn_pairwise & WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->rsn_pairwise & WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->rsn_pairwise & WPA_CIPHER_NONE) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+ -+#ifdef CONFIG_RSN_TESTING -+ if (rsn_testing) { -+ RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+#endif /* CONFIG_RSN_TESTING */ -+ -+ if (num_suites == 0) { -+ wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).", -+ conf->rsn_pairwise); -+ return -1; -+ } -+ WPA_PUT_LE16(count, num_suites); -+ -+ num_suites = 0; -+ count = pos; -+ pos += 2; -+ -+#ifdef CONFIG_RSN_TESTING -+ if (rsn_testing) { -+ RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1)); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+#endif /* CONFIG_RSN_TESTING */ -+ -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+#ifdef CONFIG_IEEE80211R -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+#ifdef CONFIG_RSN_TESTING -+ if (rsn_testing) { -+ RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2)); -+ pos += RSN_SELECTOR_LEN; -+ num_suites++; -+ } -+#endif /* CONFIG_RSN_TESTING */ -+ -+ if (num_suites == 0) { -+ wpa_printf(MSG_DEBUG, "Invalid key management type (%d).", -+ conf->wpa_key_mgmt); -+ return -1; -+ } -+ WPA_PUT_LE16(count, num_suites); -+ -+ /* RSN Capabilities */ -+ capab = 0; -+ if (conf->rsn_preauth) -+ capab |= WPA_CAPABILITY_PREAUTH; -+ if (conf->peerkey) -+ capab |= WPA_CAPABILITY_PEERKEY_ENABLED; -+ if (conf->wmm_enabled) { -+ /* 4 PTKSA replay counters when using WMM */ -+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); -+ } -+#ifdef CONFIG_IEEE80211W -+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { -+ capab |= WPA_CAPABILITY_MFPC; -+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) -+ capab |= WPA_CAPABILITY_MFPR; -+ } -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_RSN_TESTING -+ if (rsn_testing) -+ capab |= BIT(8) | BIT(14) | BIT(15); -+#endif /* CONFIG_RSN_TESTING */ -+ WPA_PUT_LE16(pos, capab); -+ pos += 2; -+ -+ if (pmkid) { -+ if (pos + 2 + PMKID_LEN > buf + len) -+ return -1; -+ /* PMKID Count */ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ os_memcpy(pos, pmkid, PMKID_LEN); -+ pos += PMKID_LEN; -+ } -+ -+#ifdef CONFIG_IEEE80211W -+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { -+ if (pos + 2 + 4 > buf + len) -+ return -1; -+ if (pmkid == NULL) { -+ /* PMKID Count */ -+ WPA_PUT_LE16(pos, 0); -+ pos += 2; -+ } -+ -+ /* Management Group Cipher Suite */ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); -+ pos += RSN_SELECTOR_LEN; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+#ifdef CONFIG_RSN_TESTING -+ if (rsn_testing) { -+ /* -+ * Fill in any defined fields and add extra data to the end of -+ * the element. -+ */ -+ int pmkid_count_set = pmkid != NULL; -+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) -+ pmkid_count_set = 1; -+ /* PMKID Count */ -+ WPA_PUT_LE16(pos, 0); -+ pos += 2; -+ if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) { -+ /* Management Group Cipher Suite */ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); -+ pos += RSN_SELECTOR_LEN; -+ } -+ -+ os_memset(pos, 0x12, 17); -+ pos += 17; -+ } -+#endif /* CONFIG_RSN_TESTING */ -+ -+ hdr->len = (pos - buf) - 2; -+ -+ return pos - buf; -+} -+ -+ -+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth) -+{ -+ u8 *pos, buf[128]; -+ int res; -+ -+ pos = buf; -+ -+ if (wpa_auth->conf.wpa & WPA_PROTO_RSN) { -+ res = wpa_write_rsn_ie(&wpa_auth->conf, -+ pos, buf + sizeof(buf) - pos, NULL); -+ if (res < 0) -+ return res; -+ pos += res; -+ } -+#ifdef CONFIG_IEEE80211R -+ if (wpa_auth->conf.wpa_key_mgmt & -+ (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) { -+ res = wpa_write_mdie(&wpa_auth->conf, pos, -+ buf + sizeof(buf) - pos); -+ if (res < 0) -+ return res; -+ pos += res; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ if (wpa_auth->conf.wpa & WPA_PROTO_WPA) { -+ res = wpa_write_wpa_ie(&wpa_auth->conf, -+ pos, buf + sizeof(buf) - pos); -+ if (res < 0) -+ return res; -+ pos += res; -+ } -+ -+ os_free(wpa_auth->wpa_ie); -+ wpa_auth->wpa_ie = os_malloc(pos - buf); -+ if (wpa_auth->wpa_ie == NULL) -+ return -1; -+ os_memcpy(wpa_auth->wpa_ie, buf, pos - buf); -+ wpa_auth->wpa_ie_len = pos - buf; -+ -+ return 0; -+} -+ -+ -+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, -+ const u8 *data2, size_t data2_len) -+{ -+ *pos++ = WLAN_EID_VENDOR_SPECIFIC; -+ *pos++ = RSN_SELECTOR_LEN + data_len + data2_len; -+ RSN_SELECTOR_PUT(pos, kde); -+ pos += RSN_SELECTOR_LEN; -+ os_memcpy(pos, data, data_len); -+ pos += data_len; -+ if (data2) { -+ os_memcpy(pos, data2, data2_len); -+ pos += data2_len; -+ } -+ return pos; -+} -+ -+ -+struct wpa_auth_okc_iter_data { -+ struct rsn_pmksa_cache_entry *pmksa; -+ const u8 *aa; -+ const u8 *spa; -+ const u8 *pmkid; -+}; -+ -+ -+static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) -+{ -+ struct wpa_auth_okc_iter_data *data = ctx; -+ data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa, -+ data->pmkid); -+ if (data->pmksa) -+ return 1; -+ return 0; -+} -+ -+ -+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, -+ struct wpa_state_machine *sm, -+ const u8 *wpa_ie, size_t wpa_ie_len, -+ const u8 *mdie, size_t mdie_len) -+{ -+ struct wpa_ie_data data; -+ int ciphers, key_mgmt, res, version; -+ u32 selector; -+ size_t i; -+ const u8 *pmkid = NULL; -+ -+ if (wpa_auth == NULL || sm == NULL) -+ return WPA_NOT_ENABLED; -+ -+ if (wpa_ie == NULL || wpa_ie_len < 1) -+ return WPA_INVALID_IE; -+ -+ if (wpa_ie[0] == WLAN_EID_RSN) -+ version = WPA_PROTO_RSN; -+ else -+ version = WPA_PROTO_WPA; -+ -+ if (!(wpa_auth->conf.wpa & version)) { -+ wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR, -+ version, MAC2STR(sm->addr)); -+ return WPA_INVALID_PROTO; -+ } -+ -+ if (version == WPA_PROTO_RSN) { -+ res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data); -+ -+ selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; -+ if (0) { -+ } -+#ifdef CONFIG_IEEE80211R -+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) -+ selector = RSN_AUTH_KEY_MGMT_FT_802_1X; -+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) -+ selector = RSN_AUTH_KEY_MGMT_FT_PSK; -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) -+ selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256; -+ else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) -+ selector = RSN_AUTH_KEY_MGMT_PSK_SHA256; -+#endif /* CONFIG_IEEE80211W */ -+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) -+ selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; -+ else if (data.key_mgmt & WPA_KEY_MGMT_PSK) -+ selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; -+ wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; -+ -+ selector = RSN_CIPHER_SUITE_CCMP; -+ if (data.pairwise_cipher & WPA_CIPHER_CCMP) -+ selector = RSN_CIPHER_SUITE_CCMP; -+ else if (data.pairwise_cipher & WPA_CIPHER_TKIP) -+ selector = RSN_CIPHER_SUITE_TKIP; -+ else if (data.pairwise_cipher & WPA_CIPHER_WEP104) -+ selector = RSN_CIPHER_SUITE_WEP104; -+ else if (data.pairwise_cipher & WPA_CIPHER_WEP40) -+ selector = RSN_CIPHER_SUITE_WEP40; -+ else if (data.pairwise_cipher & WPA_CIPHER_NONE) -+ selector = RSN_CIPHER_SUITE_NONE; -+ wpa_auth->dot11RSNAPairwiseCipherSelected = selector; -+ -+ selector = RSN_CIPHER_SUITE_CCMP; -+ if (data.group_cipher & WPA_CIPHER_CCMP) -+ selector = RSN_CIPHER_SUITE_CCMP; -+ else if (data.group_cipher & WPA_CIPHER_TKIP) -+ selector = RSN_CIPHER_SUITE_TKIP; -+ else if (data.group_cipher & WPA_CIPHER_WEP104) -+ selector = RSN_CIPHER_SUITE_WEP104; -+ else if (data.group_cipher & WPA_CIPHER_WEP40) -+ selector = RSN_CIPHER_SUITE_WEP40; -+ else if (data.group_cipher & WPA_CIPHER_NONE) -+ selector = RSN_CIPHER_SUITE_NONE; -+ wpa_auth->dot11RSNAGroupCipherSelected = selector; -+ } else { -+ res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data); -+ -+ selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; -+ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) -+ selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X; -+ else if (data.key_mgmt & WPA_KEY_MGMT_PSK) -+ selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X; -+ wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; -+ -+ selector = WPA_CIPHER_SUITE_TKIP; -+ if (data.pairwise_cipher & WPA_CIPHER_CCMP) -+ selector = WPA_CIPHER_SUITE_CCMP; -+ else if (data.pairwise_cipher & WPA_CIPHER_TKIP) -+ selector = WPA_CIPHER_SUITE_TKIP; -+ else if (data.pairwise_cipher & WPA_CIPHER_WEP104) -+ selector = WPA_CIPHER_SUITE_WEP104; -+ else if (data.pairwise_cipher & WPA_CIPHER_WEP40) -+ selector = WPA_CIPHER_SUITE_WEP40; -+ else if (data.pairwise_cipher & WPA_CIPHER_NONE) -+ selector = WPA_CIPHER_SUITE_NONE; -+ wpa_auth->dot11RSNAPairwiseCipherSelected = selector; -+ -+ selector = WPA_CIPHER_SUITE_TKIP; -+ if (data.group_cipher & WPA_CIPHER_CCMP) -+ selector = WPA_CIPHER_SUITE_CCMP; -+ else if (data.group_cipher & WPA_CIPHER_TKIP) -+ selector = WPA_CIPHER_SUITE_TKIP; -+ else if (data.group_cipher & WPA_CIPHER_WEP104) -+ selector = WPA_CIPHER_SUITE_WEP104; -+ else if (data.group_cipher & WPA_CIPHER_WEP40) -+ selector = WPA_CIPHER_SUITE_WEP40; -+ else if (data.group_cipher & WPA_CIPHER_NONE) -+ selector = WPA_CIPHER_SUITE_NONE; -+ wpa_auth->dot11RSNAGroupCipherSelected = selector; -+ } -+ if (res) { -+ wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from " -+ MACSTR " (res=%d)", MAC2STR(sm->addr), res); -+ wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len); -+ return WPA_INVALID_IE; -+ } -+ -+ if (data.group_cipher != wpa_auth->conf.wpa_group) { -+ wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from " -+ MACSTR, data.group_cipher, MAC2STR(sm->addr)); -+ return WPA_INVALID_GROUP; -+ } -+ -+ key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt; -+ if (!key_mgmt) { -+ wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from " -+ MACSTR, data.key_mgmt, MAC2STR(sm->addr)); -+ return WPA_INVALID_AKMP; -+ } -+ if (0) { -+ } -+#ifdef CONFIG_IEEE80211R -+ else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) -+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; -+ else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) -+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) -+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; -+ else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) -+ sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256; -+#endif /* CONFIG_IEEE80211W */ -+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) -+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; -+ else -+ sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK; -+ -+ if (version == WPA_PROTO_RSN) -+ ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise; -+ else -+ ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise; -+ if (!ciphers) { -+ wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) " -+ "from " MACSTR, -+ version == WPA_PROTO_RSN ? "RSN" : "WPA", -+ data.pairwise_cipher, MAC2STR(sm->addr)); -+ return WPA_INVALID_PAIRWISE; -+ } -+ -+#ifdef CONFIG_IEEE80211W -+ if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) { -+ if (!(data.capabilities & WPA_CAPABILITY_MFPC)) { -+ wpa_printf(MSG_DEBUG, "Management frame protection " -+ "required, but client did not enable it"); -+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION; -+ } -+ -+ if (ciphers & WPA_CIPHER_TKIP) { -+ wpa_printf(MSG_DEBUG, "Management frame protection " -+ "cannot use TKIP"); -+ return WPA_MGMT_FRAME_PROTECTION_VIOLATION; -+ } -+ -+ if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { -+ wpa_printf(MSG_DEBUG, "Unsupported management group " -+ "cipher %d", data.mgmt_group_cipher); -+ return WPA_INVALID_MGMT_GROUP_CIPHER; -+ } -+ } -+ -+ if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION || -+ !(data.capabilities & WPA_CAPABILITY_MFPC)) -+ sm->mgmt_frame_prot = 0; -+ else -+ sm->mgmt_frame_prot = 1; -+#endif /* CONFIG_IEEE80211W */ -+ -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { -+ if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { -+ wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but " -+ "MDIE not included"); -+ return WPA_INVALID_MDIE; -+ } -+ if (os_memcmp(mdie, wpa_auth->conf.mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown " -+ "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN); -+ return WPA_INVALID_MDIE; -+ } -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ if (ciphers & WPA_CIPHER_CCMP) -+ sm->pairwise = WPA_CIPHER_CCMP; -+ else -+ sm->pairwise = WPA_CIPHER_TKIP; -+ -+ /* TODO: clear WPA/WPA2 state if STA changes from one to another */ -+ if (wpa_ie[0] == WLAN_EID_RSN) -+ sm->wpa = WPA_VERSION_WPA2; -+ else -+ sm->wpa = WPA_VERSION_WPA; -+ -+ sm->pmksa = NULL; -+ for (i = 0; i < data.num_pmkid; i++) { -+ wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID", -+ &data.pmkid[i * PMKID_LEN], PMKID_LEN); -+ sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr, -+ &data.pmkid[i * PMKID_LEN]); -+ if (sm->pmksa) { -+ pmkid = sm->pmksa->pmkid; -+ break; -+ } -+ } -+ for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc && -+ i < data.num_pmkid; i++) { -+ struct wpa_auth_okc_iter_data idata; -+ idata.pmksa = NULL; -+ idata.aa = wpa_auth->addr; -+ idata.spa = sm->addr; -+ idata.pmkid = &data.pmkid[i * PMKID_LEN]; -+ wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata); -+ if (idata.pmksa) { -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "OKC match for PMKID"); -+ sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa, -+ idata.pmksa, -+ wpa_auth->addr, -+ idata.pmkid); -+ pmkid = idata.pmkid; -+ break; -+ } -+ } -+ if (sm->pmksa) { -+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, -+ "PMKID found from PMKSA cache " -+ "eap_type=%d vlan_id=%d", -+ sm->pmksa->eap_type_authsrv, -+ sm->pmksa->vlan_id); -+ os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN); -+ } -+ -+ if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { -+ os_free(sm->wpa_ie); -+ sm->wpa_ie = os_malloc(wpa_ie_len); -+ if (sm->wpa_ie == NULL) -+ return WPA_ALLOC_FAIL; -+ } -+ os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len); -+ sm->wpa_ie_len = wpa_ie_len; -+ -+ return WPA_IE_OK; -+} -+ -+ -+/** -+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs -+ * @pos: Pointer to the IE header -+ * @end: Pointer to the end of the Key Data buffer -+ * @ie: Pointer to parsed IE data -+ * Returns: 0 on success, 1 if end mark is found, -1 on failure -+ */ -+static int wpa_parse_generic(const u8 *pos, const u8 *end, -+ struct wpa_eapol_ie_parse *ie) -+{ -+ if (pos[1] == 0) -+ return 1; -+ -+ if (pos[1] >= 6 && -+ RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && -+ pos[2 + WPA_SELECTOR_LEN] == 1 && -+ pos[2 + WPA_SELECTOR_LEN + 1] == 0) { -+ ie->wpa_ie = pos; -+ ie->wpa_ie_len = pos[1] + 2; -+ return 0; -+ } -+ -+ if (pos + 1 + RSN_SELECTOR_LEN < end && -+ pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { -+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { -+ ie->gtk = pos + 2 + RSN_SELECTOR_LEN; -+ ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { -+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; -+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; -+ return 0; -+ } -+ -+#ifdef CONFIG_PEERKEY -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { -+ ie->smk = pos + 2 + RSN_SELECTOR_LEN; -+ ie->smk_len = pos[1] - RSN_SELECTOR_LEN; -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { -+ ie->nonce = pos + 2 + RSN_SELECTOR_LEN; -+ ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { -+ ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; -+ ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { -+ ie->error = pos + 2 + RSN_SELECTOR_LEN; -+ ie->error_len = pos[1] - RSN_SELECTOR_LEN; -+ return 0; -+ } -+#endif /* CONFIG_PEERKEY */ -+ -+#ifdef CONFIG_IEEE80211W -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { -+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN; -+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; -+ return 0; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs -+ * @buf: Pointer to the Key Data buffer -+ * @len: Key Data Length -+ * @ie: Pointer to parsed IE data -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) -+{ -+ const u8 *pos, *end; -+ int ret = 0; -+ -+ os_memset(ie, 0, sizeof(*ie)); -+ for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { -+ if (pos[0] == 0xdd && -+ ((pos == buf + len - 1) || pos[1] == 0)) { -+ /* Ignore padding */ -+ break; -+ } -+ if (pos + 2 + pos[1] > end) { -+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " -+ "underflow (ie=%d len=%d pos=%d)", -+ pos[0], pos[1], (int) (pos - buf)); -+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", -+ buf, len); -+ ret = -1; -+ break; -+ } -+ if (*pos == WLAN_EID_RSN) { -+ ie->rsn_ie = pos; -+ ie->rsn_ie_len = pos[1] + 2; -+#ifdef CONFIG_IEEE80211R -+ } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { -+ ie->mdie = pos; -+ ie->mdie_len = pos[1] + 2; -+ } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { -+ ie->ftie = pos; -+ ie->ftie_len = pos[1] + 2; -+#endif /* CONFIG_IEEE80211R */ -+ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { -+ ret = wpa_parse_generic(pos, end, ie); -+ if (ret < 0) -+ break; -+ if (ret > 0) { -+ ret = 0; -+ break; -+ } -+ } else { -+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " -+ "Key Data IE", pos, 2 + pos[1]); -+ } -+ } -+ -+ return ret; -+} -+ -+ -+int wpa_auth_uses_mfp(struct wpa_state_machine *sm) -+{ -+ return sm ? sm->mgmt_frame_prot : 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.h -new file mode 100644 -index 0000000000000..61d4cb4075fec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wpa_auth_ie.h -@@ -0,0 +1,56 @@ -+/* -+ * hostapd - WPA/RSN IE and KDE definitions -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_AUTH_IE_H -+#define WPA_AUTH_IE_H -+ -+struct wpa_eapol_ie_parse { -+ const u8 *wpa_ie; -+ size_t wpa_ie_len; -+ const u8 *rsn_ie; -+ size_t rsn_ie_len; -+ const u8 *pmkid; -+ const u8 *gtk; -+ size_t gtk_len; -+ const u8 *mac_addr; -+ size_t mac_addr_len; -+#ifdef CONFIG_PEERKEY -+ const u8 *smk; -+ size_t smk_len; -+ const u8 *nonce; -+ size_t nonce_len; -+ const u8 *lifetime; -+ size_t lifetime_len; -+ const u8 *error; -+ size_t error_len; -+#endif /* CONFIG_PEERKEY */ -+#ifdef CONFIG_IEEE80211W -+ const u8 *igtk; -+ size_t igtk_len; -+#endif /* CONFIG_IEEE80211W */ -+#ifdef CONFIG_IEEE80211R -+ const u8 *mdie; -+ size_t mdie_len; -+ const u8 *ftie; -+ size_t ftie_len; -+#endif /* CONFIG_IEEE80211R */ -+}; -+ -+int wpa_parse_kde_ies(const u8 *buf, size_t len, -+ struct wpa_eapol_ie_parse *ie); -+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len, -+ const u8 *data2, size_t data2_len); -+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth); -+ -+#endif /* WPA_AUTH_IE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.c -new file mode 100644 -index 0000000000000..fcbd89b9cff54 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.c -@@ -0,0 +1,1380 @@ -+/* -+ * hostapd / WPS integration -+ * Copyright (c) 2008-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "utils/uuid.h" -+#include "crypto/dh_groups.h" -+#include "common/wpa_ctrl.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "eapol_auth/eapol_auth_sm.h" -+#include "eapol_auth/eapol_auth_sm_i.h" -+#include "wps/wps.h" -+#include "wps/wps_defs.h" -+#include "wps/wps_dev_attr.h" -+#include "hostapd.h" -+#include "ap_config.h" -+#include "ap_drv_ops.h" -+#include "beacon.h" -+#include "sta_info.h" -+#include "wps_hostapd.h" -+ -+ -+#ifdef CONFIG_WPS_UPNP -+#include "wps/wps_upnp.h" -+static int hostapd_wps_upnp_init(struct hostapd_data *hapd, -+ struct wps_context *wps); -+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd); -+#endif /* CONFIG_WPS_UPNP */ -+ -+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, -+ const u8 *ie, size_t ie_len); -+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); -+ -+ -+struct wps_for_each_data { -+ int (*func)(struct hostapd_data *h, void *ctx); -+ void *ctx; -+}; -+ -+ -+static int wps_for_each(struct hostapd_iface *iface, void *ctx) -+{ -+ struct wps_for_each_data *data = ctx; -+ size_t j; -+ -+ if (iface == NULL) -+ return 0; -+ for (j = 0; j < iface->num_bss; j++) { -+ struct hostapd_data *hapd = iface->bss[j]; -+ int ret = data->func(hapd, data->ctx); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+ -+static int hostapd_wps_for_each(struct hostapd_data *hapd, -+ int (*func)(struct hostapd_data *h, void *ctx), -+ void *ctx) -+{ -+ struct hostapd_iface *iface = hapd->iface; -+ struct wps_for_each_data data; -+ data.func = func; -+ data.ctx = ctx; -+ if (iface->for_each_interface == NULL) -+ return wps_for_each(iface, &data); -+ return iface->for_each_interface(iface->interfaces, wps_for_each, -+ &data); -+} -+ -+ -+static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk, -+ size_t psk_len) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct hostapd_wpa_psk *p; -+ struct hostapd_ssid *ssid = &hapd->conf->ssid; -+ -+ wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA " -+ MACSTR, MAC2STR(mac_addr)); -+ wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len); -+ -+ if (psk_len != PMK_LEN) { -+ wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu", -+ (unsigned long) psk_len); -+ return -1; -+ } -+ -+ /* Add the new PSK to runtime PSK list */ -+ p = os_zalloc(sizeof(*p)); -+ if (p == NULL) -+ return -1; -+ os_memcpy(p->addr, mac_addr, ETH_ALEN); -+ os_memcpy(p->psk, psk, PMK_LEN); -+ -+ p->next = ssid->wpa_psk; -+ ssid->wpa_psk = p; -+ -+ if (ssid->wpa_psk_file) { -+ FILE *f; -+ char hex[PMK_LEN * 2 + 1]; -+ /* Add the new PSK to PSK list file */ -+ f = fopen(ssid->wpa_psk_file, "a"); -+ if (f == NULL) { -+ wpa_printf(MSG_DEBUG, "Failed to add the PSK to " -+ "'%s'", ssid->wpa_psk_file); -+ return -1; -+ } -+ -+ wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len); -+ fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex); -+ fclose(f); -+ } -+ -+ return 0; -+} -+ -+ -+static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie, -+ struct wpabuf *probe_resp_ie) -+{ -+ struct hostapd_data *hapd = ctx; -+ wpabuf_free(hapd->wps_beacon_ie); -+ hapd->wps_beacon_ie = beacon_ie; -+ wpabuf_free(hapd->wps_probe_resp_ie); -+ hapd->wps_probe_resp_ie = probe_resp_ie; -+ ieee802_11_set_beacon(hapd); -+ return hostapd_set_ap_wps_ie(hapd); -+} -+ -+ -+static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e, -+ const struct wps_device_data *dev) -+{ -+ struct hostapd_data *hapd = ctx; -+ char uuid[40], txt[400]; -+ int len; -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) -+ return; -+ wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid); -+ len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED -+ "%s " MACSTR " [%s|%s|%s|%s|%s|%s]", -+ uuid, MAC2STR(dev->mac_addr), dev->device_name, -+ dev->manufacturer, dev->model_name, -+ dev->model_number, dev->serial_number, -+ wps_dev_type_bin2str(dev->pri_dev_type, devtype, -+ sizeof(devtype))); -+ if (len > 0 && len < (int) sizeof(txt)) -+ wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt); -+ -+ if (hapd->conf->wps_pin_requests) { -+ FILE *f; -+ struct os_time t; -+ f = fopen(hapd->conf->wps_pin_requests, "a"); -+ if (f == NULL) -+ return; -+ os_get_time(&t); -+ fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s" -+ "\t%s\n", -+ t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name, -+ dev->manufacturer, dev->model_name, dev->model_number, -+ dev->serial_number, -+ wps_dev_type_bin2str(dev->pri_dev_type, devtype, -+ sizeof(devtype))); -+ fclose(f); -+ } -+} -+ -+ -+static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr, -+ const u8 *uuid_e) -+{ -+ struct hostapd_data *hapd = ctx; -+ char uuid[40]; -+ if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) -+ return; -+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s", -+ MAC2STR(mac_addr), uuid); -+ if (hapd->wps_reg_success_cb) -+ hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx, -+ mac_addr, uuid_e); -+} -+ -+ -+static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, -+ const u8 *uuid_e, -+ const u8 *pri_dev_type, -+ u16 config_methods, -+ u16 dev_password_id, u8 request_type, -+ const char *dev_name) -+{ -+ struct hostapd_data *hapd = ctx; -+ char uuid[40]; -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ if (uuid_bin2str(uuid_e, uuid, sizeof(uuid))) -+ return; -+ if (dev_name == NULL) -+ dev_name = ""; -+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR -+ " %s %s 0x%x %u %u [%s]", -+ MAC2STR(addr), uuid, -+ wps_dev_type_bin2str(pri_dev_type, devtype, -+ sizeof(devtype)), -+ config_methods, dev_password_id, request_type, dev_name); -+} -+ -+ -+static int str_starts(const char *str, const char *start) -+{ -+ return os_strncmp(str, start, os_strlen(start)) == 0; -+} -+ -+ -+static void wps_reload_config(void *eloop_data, void *user_ctx) -+{ -+ struct hostapd_iface *iface = eloop_data; -+ -+ wpa_printf(MSG_DEBUG, "WPS: Reload configuration data"); -+ if (iface->reload_config(iface) < 0) { -+ wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated " -+ "configuration"); -+ } -+} -+ -+ -+static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) -+{ -+ const struct wps_credential *cred = ctx; -+ FILE *oconf, *nconf; -+ size_t len, i; -+ char *tmp_fname; -+ char buf[1024]; -+ int multi_bss; -+ int wpa; -+ -+ if (hapd->wps == NULL) -+ return 0; -+ -+ wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", -+ cred->cred_attr, cred->cred_attr_len); -+ -+ wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings"); -+ wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len); -+ wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x", -+ cred->auth_type); -+ wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type); -+ wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx); -+ wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", -+ cred->key, cred->key_len); -+ wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, -+ MAC2STR(cred->mac_addr)); -+ -+ if ((hapd->conf->wps_cred_processing == 1 || -+ hapd->conf->wps_cred_processing == 2) && cred->cred_attr) { -+ size_t blen = cred->cred_attr_len * 2 + 1; -+ char *_buf = os_malloc(blen); -+ if (_buf) { -+ wpa_snprintf_hex(_buf, blen, -+ cred->cred_attr, cred->cred_attr_len); -+ wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s", -+ WPS_EVENT_NEW_AP_SETTINGS, _buf); -+ os_free(_buf); -+ } -+ } else -+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS); -+ -+ if (hapd->conf->wps_cred_processing == 1) -+ return 0; -+ -+ os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len); -+ hapd->wps->ssid_len = cred->ssid_len; -+ hapd->wps->encr_types = cred->encr_type; -+ hapd->wps->auth_types = cred->auth_type; -+ if (cred->key_len == 0) { -+ os_free(hapd->wps->network_key); -+ hapd->wps->network_key = NULL; -+ hapd->wps->network_key_len = 0; -+ } else { -+ if (hapd->wps->network_key == NULL || -+ hapd->wps->network_key_len < cred->key_len) { -+ hapd->wps->network_key_len = 0; -+ os_free(hapd->wps->network_key); -+ hapd->wps->network_key = os_malloc(cred->key_len); -+ if (hapd->wps->network_key == NULL) -+ return -1; -+ } -+ hapd->wps->network_key_len = cred->key_len; -+ os_memcpy(hapd->wps->network_key, cred->key, cred->key_len); -+ } -+ hapd->wps->wps_state = WPS_STATE_CONFIGURED; -+ -+ len = os_strlen(hapd->iface->config_fname) + 5; -+ tmp_fname = os_malloc(len); -+ if (tmp_fname == NULL) -+ return -1; -+ os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname); -+ -+ oconf = fopen(hapd->iface->config_fname, "r"); -+ if (oconf == NULL) { -+ wpa_printf(MSG_WARNING, "WPS: Could not open current " -+ "configuration file"); -+ os_free(tmp_fname); -+ return -1; -+ } -+ -+ nconf = fopen(tmp_fname, "w"); -+ if (nconf == NULL) { -+ wpa_printf(MSG_WARNING, "WPS: Could not write updated " -+ "configuration file"); -+ os_free(tmp_fname); -+ fclose(oconf); -+ return -1; -+ } -+ -+ fprintf(nconf, "# WPS configuration - START\n"); -+ -+ fprintf(nconf, "wps_state=2\n"); -+ -+ fprintf(nconf, "ssid="); -+ for (i = 0; i < cred->ssid_len; i++) -+ fputc(cred->ssid[i], nconf); -+ fprintf(nconf, "\n"); -+ -+ if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) && -+ (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))) -+ wpa = 3; -+ else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) -+ wpa = 2; -+ else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)) -+ wpa = 1; -+ else -+ wpa = 0; -+ -+ if (wpa) { -+ char *prefix; -+ fprintf(nconf, "wpa=%d\n", wpa); -+ -+ fprintf(nconf, "wpa_key_mgmt="); -+ prefix = ""; -+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) { -+ fprintf(nconf, "WPA-EAP"); -+ prefix = " "; -+ } -+ if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) -+ fprintf(nconf, "%sWPA-PSK", prefix); -+ fprintf(nconf, "\n"); -+ -+ fprintf(nconf, "wpa_pairwise="); -+ prefix = ""; -+ if (cred->encr_type & WPS_ENCR_AES) { -+ fprintf(nconf, "CCMP"); -+ prefix = " "; -+ } -+ if (cred->encr_type & WPS_ENCR_TKIP) { -+ fprintf(nconf, "%sTKIP", prefix); -+ } -+ fprintf(nconf, "\n"); -+ -+ if (cred->key_len >= 8 && cred->key_len < 64) { -+ fprintf(nconf, "wpa_passphrase="); -+ for (i = 0; i < cred->key_len; i++) -+ fputc(cred->key[i], nconf); -+ fprintf(nconf, "\n"); -+ } else if (cred->key_len == 64) { -+ fprintf(nconf, "wpa_psk="); -+ for (i = 0; i < cred->key_len; i++) -+ fputc(cred->key[i], nconf); -+ fprintf(nconf, "\n"); -+ } else { -+ wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu " -+ "for WPA/WPA2", -+ (unsigned long) cred->key_len); -+ } -+ -+ fprintf(nconf, "auth_algs=1\n"); -+ } else { -+ if ((cred->auth_type & WPS_AUTH_OPEN) && -+ (cred->auth_type & WPS_AUTH_SHARED)) -+ fprintf(nconf, "auth_algs=3\n"); -+ else if (cred->auth_type & WPS_AUTH_SHARED) -+ fprintf(nconf, "auth_algs=2\n"); -+ else -+ fprintf(nconf, "auth_algs=1\n"); -+ -+ if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) { -+ int key_idx = cred->key_idx; -+ if (key_idx) -+ key_idx--; -+ fprintf(nconf, "wep_default_key=%d\n", key_idx); -+ fprintf(nconf, "wep_key%d=", key_idx); -+ if (cred->key_len == 10 || cred->key_len == 26) { -+ /* WEP key as a hex string */ -+ for (i = 0; i < cred->key_len; i++) -+ fputc(cred->key[i], nconf); -+ } else { -+ /* Raw WEP key; convert to hex */ -+ for (i = 0; i < cred->key_len; i++) -+ fprintf(nconf, "%02x", cred->key[i]); -+ } -+ fprintf(nconf, "\n"); -+ } -+ } -+ -+ fprintf(nconf, "# WPS configuration - END\n"); -+ -+ multi_bss = 0; -+ while (fgets(buf, sizeof(buf), oconf)) { -+ if (os_strncmp(buf, "bss=", 4) == 0) -+ multi_bss = 1; -+ if (!multi_bss && -+ (str_starts(buf, "ssid=") || -+ str_starts(buf, "auth_algs=") || -+ str_starts(buf, "wep_default_key=") || -+ str_starts(buf, "wep_key") || -+ str_starts(buf, "wps_state=") || -+ str_starts(buf, "wpa=") || -+ str_starts(buf, "wpa_psk=") || -+ str_starts(buf, "wpa_pairwise=") || -+ str_starts(buf, "rsn_pairwise=") || -+ str_starts(buf, "wpa_key_mgmt=") || -+ str_starts(buf, "wpa_passphrase="))) { -+ fprintf(nconf, "#WPS# %s", buf); -+ } else -+ fprintf(nconf, "%s", buf); -+ } -+ -+ fclose(nconf); -+ fclose(oconf); -+ -+ if (rename(tmp_fname, hapd->iface->config_fname) < 0) { -+ wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated " -+ "configuration file: %s", strerror(errno)); -+ os_free(tmp_fname); -+ return -1; -+ } -+ -+ os_free(tmp_fname); -+ -+ /* Schedule configuration reload after short period of time to allow -+ * EAP-WSC to be finished. -+ */ -+ eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface, -+ NULL); -+ -+ wpa_printf(MSG_DEBUG, "WPS: AP configuration updated"); -+ -+ return 0; -+} -+ -+ -+static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred) -+{ -+ struct hostapd_data *hapd = ctx; -+ return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred); -+} -+ -+ -+static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) -+{ -+ struct hostapd_data *hapd = eloop_data; -+ -+ if (hapd->conf->ap_setup_locked) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN"); -+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); -+ hapd->wps->ap_setup_locked = 0; -+ wps_registrar_update_ie(hapd->wps->registrar); -+} -+ -+ -+static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx) -+{ -+ struct wps_event_pwd_auth_fail *data = ctx; -+ -+ if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL) -+ return 0; -+ -+ /* -+ * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup -+ * for some time if this happens multiple times to slow down brute -+ * force attacks. -+ */ -+ hapd->ap_pin_failures++; -+ wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u", -+ hapd->ap_pin_failures); -+ if (hapd->ap_pin_failures < 3) -+ return 0; -+ -+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED); -+ hapd->wps->ap_setup_locked = 1; -+ -+ wps_registrar_update_ie(hapd->wps->registrar); -+ -+ if (!hapd->conf->ap_setup_locked) { -+ if (hapd->ap_pin_lockout_time == 0) -+ hapd->ap_pin_lockout_time = 60; -+ else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 && -+ (hapd->ap_pin_failures % 3) == 0) -+ hapd->ap_pin_lockout_time *= 2; -+ -+ wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds", -+ hapd->ap_pin_lockout_time); -+ eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); -+ eloop_register_timeout(hapd->ap_pin_lockout_time, 0, -+ hostapd_wps_reenable_ap_pin, hapd, -+ NULL); -+ } -+ -+ return 0; -+} -+ -+ -+static void hostapd_pwd_auth_fail(struct hostapd_data *hapd, -+ struct wps_event_pwd_auth_fail *data) -+{ -+ hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data); -+} -+ -+ -+static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = { -+ "No Error", /* WPS_EI_NO_ERROR */ -+ "TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */ -+ "WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */ -+}; -+ -+static void hostapd_wps_event_fail(struct hostapd_data *hapd, -+ struct wps_event_fail *fail) -+{ -+ if (fail->error_indication > 0 && -+ fail->error_indication < NUM_WPS_EI_VALUES) { -+ wpa_msg(hapd->msg_ctx, MSG_INFO, -+ WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)", -+ fail->msg, fail->config_error, fail->error_indication, -+ wps_event_fail_reason[fail->error_indication]); -+ } else { -+ wpa_msg(hapd->msg_ctx, MSG_INFO, -+ WPS_EVENT_FAIL "msg=%d config_error=%d", -+ fail->msg, fail->config_error); -+ } -+} -+ -+ -+static void hostapd_wps_event_cb(void *ctx, enum wps_event event, -+ union wps_event_data *data) -+{ -+ struct hostapd_data *hapd = ctx; -+ -+ switch (event) { -+ case WPS_EV_M2D: -+ break; -+ case WPS_EV_FAIL: -+ hostapd_wps_event_fail(hapd, &data->fail); -+ break; -+ case WPS_EV_SUCCESS: -+ break; -+ case WPS_EV_PWD_AUTH_FAIL: -+ hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail); -+ break; -+ case WPS_EV_PBC_OVERLAP: -+ break; -+ case WPS_EV_PBC_TIMEOUT: -+ break; -+ case WPS_EV_ER_AP_ADD: -+ break; -+ case WPS_EV_ER_AP_REMOVE: -+ break; -+ case WPS_EV_ER_ENROLLEE_ADD: -+ break; -+ case WPS_EV_ER_ENROLLEE_REMOVE: -+ break; -+ case WPS_EV_ER_AP_SETTINGS: -+ break; -+ case WPS_EV_ER_SET_SELECTED_REGISTRAR: -+ break; -+ } -+ if (hapd->wps_event_cb) -+ hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data); -+} -+ -+ -+static void hostapd_wps_clear_ies(struct hostapd_data *hapd) -+{ -+ wpabuf_free(hapd->wps_beacon_ie); -+ hapd->wps_beacon_ie = NULL; -+ -+ wpabuf_free(hapd->wps_probe_resp_ie); -+ hapd->wps_probe_resp_ie = NULL; -+ -+ hostapd_set_ap_wps_ie(hapd); -+} -+ -+ -+static int get_uuid_cb(struct hostapd_iface *iface, void *ctx) -+{ -+ const u8 **uuid = ctx; -+ size_t j; -+ -+ if (iface == NULL) -+ return 0; -+ for (j = 0; j < iface->num_bss; j++) { -+ struct hostapd_data *hapd = iface->bss[j]; -+ if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) { -+ *uuid = hapd->wps->uuid; -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static const u8 * get_own_uuid(struct hostapd_iface *iface) -+{ -+ const u8 *uuid; -+ if (iface->for_each_interface == NULL) -+ return NULL; -+ uuid = NULL; -+ iface->for_each_interface(iface->interfaces, get_uuid_cb, &uuid); -+ return uuid; -+} -+ -+ -+static int count_interface_cb(struct hostapd_iface *iface, void *ctx) -+{ -+ int *count= ctx; -+ (*count)++; -+ return 0; -+} -+ -+ -+static int interface_count(struct hostapd_iface *iface) -+{ -+ int count = 0; -+ if (iface->for_each_interface == NULL) -+ return 0; -+ iface->for_each_interface(iface->interfaces, count_interface_cb, -+ &count); -+ return count; -+} -+ -+ -+static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd, -+ struct wps_context *wps) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { -+ wpabuf_free(wps->dev.vendor_ext[i]); -+ wps->dev.vendor_ext[i] = NULL; -+ -+ if (hapd->conf->wps_vendor_ext[i] == NULL) -+ continue; -+ -+ wps->dev.vendor_ext[i] = -+ wpabuf_dup(hapd->conf->wps_vendor_ext[i]); -+ if (wps->dev.vendor_ext[i] == NULL) { -+ while (--i >= 0) -+ wpabuf_free(wps->dev.vendor_ext[i]); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+int hostapd_init_wps(struct hostapd_data *hapd, -+ struct hostapd_bss_config *conf) -+{ -+ struct wps_context *wps; -+ struct wps_registrar_config cfg; -+ -+ if (conf->wps_state == 0) { -+ hostapd_wps_clear_ies(hapd); -+ return 0; -+ } -+ -+ wps = os_zalloc(sizeof(*wps)); -+ if (wps == NULL) -+ return -1; -+ -+ wps->cred_cb = hostapd_wps_cred_cb; -+ wps->event_cb = hostapd_wps_event_cb; -+ wps->cb_ctx = hapd; -+ -+ os_memset(&cfg, 0, sizeof(cfg)); -+ wps->wps_state = hapd->conf->wps_state; -+ wps->ap_setup_locked = hapd->conf->ap_setup_locked; -+ if (is_nil_uuid(hapd->conf->uuid)) { -+ const u8 *uuid; -+ uuid = get_own_uuid(hapd->iface); -+ if (uuid) { -+ os_memcpy(wps->uuid, uuid, UUID_LEN); -+ wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another " -+ "interface", wps->uuid, UUID_LEN); -+ } else { -+ uuid_gen_mac_addr(hapd->own_addr, wps->uuid); -+ wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC " -+ "address", wps->uuid, UUID_LEN); -+ } -+ } else { -+ os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN); -+ wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID", -+ wps->uuid, UUID_LEN); -+ } -+ wps->ssid_len = hapd->conf->ssid.ssid_len; -+ os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len); -+ wps->ap = 1; -+ os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN); -+ wps->dev.device_name = hapd->conf->device_name ? -+ os_strdup(hapd->conf->device_name) : NULL; -+ wps->dev.manufacturer = hapd->conf->manufacturer ? -+ os_strdup(hapd->conf->manufacturer) : NULL; -+ wps->dev.model_name = hapd->conf->model_name ? -+ os_strdup(hapd->conf->model_name) : NULL; -+ wps->dev.model_number = hapd->conf->model_number ? -+ os_strdup(hapd->conf->model_number) : NULL; -+ wps->dev.serial_number = hapd->conf->serial_number ? -+ os_strdup(hapd->conf->serial_number) : NULL; -+ wps->config_methods = -+ wps_config_methods_str2bin(hapd->conf->config_methods); -+#ifdef CONFIG_WPS2 -+ if ((wps->config_methods & -+ (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY | -+ WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) { -+ wpa_printf(MSG_INFO, "WPS: Converting display to " -+ "virtual_display for WPS 2.0 compliance"); -+ wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY; -+ } -+ if ((wps->config_methods & -+ (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON | -+ WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) { -+ wpa_printf(MSG_INFO, "WPS: Converting push_button to " -+ "virtual_push_button for WPS 2.0 compliance"); -+ wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON; -+ } -+#endif /* CONFIG_WPS2 */ -+ os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type, -+ WPS_DEV_TYPE_LEN); -+ -+ if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) { -+ os_free(wps); -+ return -1; -+ } -+ -+ wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); -+ wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ? -+ WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */ -+ -+ if (conf->wpa & WPA_PROTO_RSN) { -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) -+ wps->auth_types |= WPS_AUTH_WPA2PSK; -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) -+ wps->auth_types |= WPS_AUTH_WPA2; -+ -+ if (conf->rsn_pairwise & WPA_CIPHER_CCMP) -+ wps->encr_types |= WPS_ENCR_AES; -+ if (conf->rsn_pairwise & WPA_CIPHER_TKIP) -+ wps->encr_types |= WPS_ENCR_TKIP; -+ } -+ -+ if (conf->wpa & WPA_PROTO_WPA) { -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) -+ wps->auth_types |= WPS_AUTH_WPAPSK; -+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) -+ wps->auth_types |= WPS_AUTH_WPA; -+ -+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP) -+ wps->encr_types |= WPS_ENCR_AES; -+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP) -+ wps->encr_types |= WPS_ENCR_TKIP; -+ } -+ -+ if (conf->ssid.security_policy == SECURITY_PLAINTEXT) { -+ wps->encr_types |= WPS_ENCR_NONE; -+ wps->auth_types |= WPS_AUTH_OPEN; -+ } else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) { -+ wps->encr_types |= WPS_ENCR_WEP; -+ if (conf->auth_algs & WPA_AUTH_ALG_OPEN) -+ wps->auth_types |= WPS_AUTH_OPEN; -+ if (conf->auth_algs & WPA_AUTH_ALG_SHARED) -+ wps->auth_types |= WPS_AUTH_SHARED; -+ } else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) { -+ wps->auth_types |= WPS_AUTH_OPEN; -+ if (conf->default_wep_key_len) -+ wps->encr_types |= WPS_ENCR_WEP; -+ else -+ wps->encr_types |= WPS_ENCR_NONE; -+ } -+ -+ if (conf->ssid.wpa_psk_file) { -+ /* Use per-device PSKs */ -+ } else if (conf->ssid.wpa_passphrase) { -+ wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase); -+ wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase); -+ } else if (conf->ssid.wpa_psk) { -+ wps->network_key = os_malloc(2 * PMK_LEN + 1); -+ if (wps->network_key == NULL) { -+ os_free(wps); -+ return -1; -+ } -+ wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1, -+ conf->ssid.wpa_psk->psk, PMK_LEN); -+ wps->network_key_len = 2 * PMK_LEN; -+ } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) { -+ wps->network_key = os_malloc(conf->ssid.wep.len[0]); -+ if (wps->network_key == NULL) { -+ os_free(wps); -+ return -1; -+ } -+ os_memcpy(wps->network_key, conf->ssid.wep.key[0], -+ conf->ssid.wep.len[0]); -+ wps->network_key_len = conf->ssid.wep.len[0]; -+ } -+ -+ if (conf->ssid.wpa_psk) { -+ os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN); -+ wps->psk_set = 1; -+ } -+ -+ if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) { -+ /* Override parameters to enable security by default */ -+ wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK; -+ wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP; -+ } -+ -+ wps->ap_settings = conf->ap_settings; -+ wps->ap_settings_len = conf->ap_settings_len; -+ -+ cfg.new_psk_cb = hostapd_wps_new_psk_cb; -+ cfg.set_ie_cb = hostapd_wps_set_ie_cb; -+ cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; -+ cfg.reg_success_cb = hostapd_wps_reg_success_cb; -+ cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; -+ cfg.cb_ctx = hapd; -+ cfg.skip_cred_build = conf->skip_cred_build; -+ cfg.extra_cred = conf->extra_cred; -+ cfg.extra_cred_len = conf->extra_cred_len; -+ cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) && -+ conf->skip_cred_build; -+ if (conf->ssid.security_policy == SECURITY_STATIC_WEP) -+ cfg.static_wep_only = 1; -+ cfg.dualband = interface_count(hapd->iface) > 1; -+ if (cfg.dualband) -+ wpa_printf(MSG_DEBUG, "WPS: Dualband AP"); -+ -+ wps->registrar = wps_registrar_init(wps, &cfg); -+ if (wps->registrar == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar"); -+ os_free(wps->network_key); -+ os_free(wps); -+ return -1; -+ } -+ -+#ifdef CONFIG_WPS_UPNP -+ wps->friendly_name = hapd->conf->friendly_name; -+ wps->manufacturer_url = hapd->conf->manufacturer_url; -+ wps->model_description = hapd->conf->model_description; -+ wps->model_url = hapd->conf->model_url; -+ wps->upc = hapd->conf->upc; -+ -+ if (hostapd_wps_upnp_init(hapd, wps) < 0) { -+ wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP"); -+ wps_registrar_deinit(wps->registrar); -+ os_free(wps->network_key); -+ os_free(wps); -+ return -1; -+ } -+#endif /* CONFIG_WPS_UPNP */ -+ -+ hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd); -+ -+ hapd->wps = wps; -+ -+ return 0; -+} -+ -+ -+void hostapd_deinit_wps(struct hostapd_data *hapd) -+{ -+ eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL); -+ eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); -+ if (hapd->wps == NULL) -+ return; -+#ifdef CONFIG_WPS_UPNP -+ hostapd_wps_upnp_deinit(hapd); -+#endif /* CONFIG_WPS_UPNP */ -+ wps_registrar_deinit(hapd->wps->registrar); -+ os_free(hapd->wps->network_key); -+ wps_device_data_free(&hapd->wps->dev); -+ wpabuf_free(hapd->wps->dh_pubkey); -+ wpabuf_free(hapd->wps->dh_privkey); -+ wpabuf_free(hapd->wps->oob_conf.pubkey_hash); -+ wpabuf_free(hapd->wps->oob_conf.dev_password); -+ wps_free_pending_msgs(hapd->wps->upnp_msgs); -+ os_free(hapd->wps); -+ hapd->wps = NULL; -+ hostapd_wps_clear_ies(hapd); -+} -+ -+ -+void hostapd_update_wps(struct hostapd_data *hapd) -+{ -+ if (hapd->wps == NULL) -+ return; -+ -+#ifdef CONFIG_WPS_UPNP -+ hapd->wps->friendly_name = hapd->conf->friendly_name; -+ hapd->wps->manufacturer_url = hapd->conf->manufacturer_url; -+ hapd->wps->model_description = hapd->conf->model_description; -+ hapd->wps->model_url = hapd->conf->model_url; -+ hapd->wps->upc = hapd->conf->upc; -+#endif /* CONFIG_WPS_UPNP */ -+ -+ hostapd_wps_set_vendor_ext(hapd, hapd->wps); -+ -+ if (hapd->conf->wps_state) -+ wps_registrar_update_ie(hapd->wps->registrar); -+ else -+ hostapd_deinit_wps(hapd); -+} -+ -+ -+struct wps_add_pin_data { -+ const u8 *addr; -+ const u8 *uuid; -+ const u8 *pin; -+ size_t pin_len; -+ int timeout; -+ int added; -+}; -+ -+ -+static int wps_add_pin(struct hostapd_data *hapd, void *ctx) -+{ -+ struct wps_add_pin_data *data = ctx; -+ int ret; -+ -+ if (hapd->wps == NULL) -+ return 0; -+ ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr, -+ data->uuid, data->pin, data->pin_len, -+ data->timeout); -+ if (ret == 0) -+ data->added++; -+ return ret; -+} -+ -+ -+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, -+ const char *uuid, const char *pin, int timeout) -+{ -+ u8 u[UUID_LEN]; -+ struct wps_add_pin_data data; -+ -+ data.addr = addr; -+ data.uuid = u; -+ data.pin = (const u8 *) pin; -+ data.pin_len = os_strlen(pin); -+ data.timeout = timeout; -+ data.added = 0; -+ -+ if (os_strcmp(uuid, "any") == 0) -+ data.uuid = NULL; -+ else { -+ if (uuid_str2bin(uuid, u)) -+ return -1; -+ data.uuid = u; -+ } -+ if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0) -+ return -1; -+ return data.added ? 0 : -1; -+} -+ -+ -+static int wps_button_pushed(struct hostapd_data *hapd, void *ctx) -+{ -+ const u8 *p2p_dev_addr = ctx; -+ if (hapd->wps == NULL) -+ return 0; -+ return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr); -+} -+ -+ -+int hostapd_wps_button_pushed(struct hostapd_data *hapd, -+ const u8 *p2p_dev_addr) -+{ -+ return hostapd_wps_for_each(hapd, wps_button_pushed, -+ (void *) p2p_dev_addr); -+} -+ -+ -+#ifdef CONFIG_WPS_OOB -+int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, -+ char *path, char *method, char *name) -+{ -+ struct wps_context *wps = hapd->wps; -+ struct oob_device_data *oob_dev; -+ -+ oob_dev = wps_get_oob_device(device_type); -+ if (oob_dev == NULL) -+ return -1; -+ oob_dev->device_path = path; -+ oob_dev->device_name = name; -+ wps->oob_conf.oob_method = wps_get_oob_method(method); -+ -+ if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) { -+ /* -+ * Use pre-configured DH keys in order to be able to write the -+ * key hash into the OOB file. -+ */ -+ wpabuf_free(wps->dh_pubkey); -+ wpabuf_free(wps->dh_privkey); -+ wps->dh_privkey = NULL; -+ wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), -+ &wps->dh_privkey); -+ wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192); -+ if (wps->dh_pubkey == NULL) { -+ wpa_printf(MSG_ERROR, "WPS: Failed to initialize " -+ "Diffie-Hellman handshake"); -+ return -1; -+ } -+ } -+ -+ if (wps_process_oob(wps, oob_dev, 1) < 0) -+ goto error; -+ -+ if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E || -+ wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) && -+ hostapd_wps_add_pin(hapd, NULL, "any", -+ wpabuf_head(wps->oob_conf.dev_password), 0) < -+ 0) -+ goto error; -+ -+ return 0; -+ -+error: -+ wpabuf_free(wps->dh_pubkey); -+ wps->dh_pubkey = NULL; -+ wpabuf_free(wps->dh_privkey); -+ wps->dh_privkey = NULL; -+ return -1; -+} -+#endif /* CONFIG_WPS_OOB */ -+ -+ -+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, -+ const u8 *ie, size_t ie_len) -+{ -+ struct hostapd_data *hapd = ctx; -+ struct wpabuf *wps_ie; -+ struct ieee802_11_elems elems; -+ -+ if (hapd->wps == NULL) -+ return 0; -+ -+ if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) { -+ wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from " -+ MACSTR, MAC2STR(addr)); -+ return 0; -+ } -+ -+ if (elems.ssid && elems.ssid_len > 0 && -+ (elems.ssid_len != hapd->conf->ssid.ssid_len || -+ os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != -+ 0)) -+ return 0; /* Not for us */ -+ -+ wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); -+ if (wps_ie == NULL) -+ return 0; -+ if (wps_validate_probe_req(wps_ie, addr) < 0) { -+ wpabuf_free(wps_ie); -+ return 0; -+ } -+ -+ if (wpabuf_len(wps_ie) > 0) { -+ int p2p_wildcard = 0; -+#ifdef CONFIG_P2P -+ if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN && -+ os_memcmp(elems.ssid, P2P_WILDCARD_SSID, -+ P2P_WILDCARD_SSID_LEN) == 0) -+ p2p_wildcard = 1; -+#endif /* CONFIG_P2P */ -+ wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie, -+ p2p_wildcard); -+#ifdef CONFIG_WPS_UPNP -+ /* FIX: what exactly should be included in the WLANEvent? -+ * WPS attributes? Full ProbeReq frame? */ -+ if (!p2p_wildcard) -+ upnp_wps_device_send_wlan_event( -+ hapd->wps_upnp, addr, -+ UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie); -+#endif /* CONFIG_WPS_UPNP */ -+ } -+ -+ wpabuf_free(wps_ie); -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_WPS_UPNP -+ -+static int hostapd_rx_req_put_wlan_response( -+ void *priv, enum upnp_wps_wlanevent_type ev_type, -+ const u8 *mac_addr, const struct wpabuf *msg, -+ enum wps_msg_type msg_type) -+{ -+ struct hostapd_data *hapd = priv; -+ struct sta_info *sta; -+ struct upnp_pending_message *p; -+ -+ wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr=" -+ MACSTR, ev_type, MAC2STR(mac_addr)); -+ wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage", -+ wpabuf_head(msg), wpabuf_len(msg)); -+ if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) { -+ wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected " -+ "PutWLANResponse WLANEventType %d", ev_type); -+ return -1; -+ } -+ -+ /* -+ * EAP response to ongoing to WPS Registration. Send it to EAP-WSC -+ * server implementation for delivery to the peer. -+ */ -+ -+ sta = ap_get_sta(hapd, mac_addr); -+#ifndef CONFIG_WPS_STRICT -+ if (!sta) { -+ /* -+ * Workaround - Intel wsccmd uses bogus NewWLANEventMAC: -+ * Pick STA that is in an ongoing WPS registration without -+ * checking the MAC address. -+ */ -+ wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based " -+ "on NewWLANEventMAC; try wildcard match"); -+ for (sta = hapd->sta_list; sta; sta = sta->next) { -+ if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS)) -+ break; -+ } -+ } -+#endif /* CONFIG_WPS_STRICT */ -+ -+ if (!sta) { -+ wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found"); -+ return 0; -+ } -+ -+ p = os_zalloc(sizeof(*p)); -+ if (p == NULL) -+ return -1; -+ os_memcpy(p->addr, sta->addr, ETH_ALEN); -+ p->msg = wpabuf_dup(msg); -+ p->type = msg_type; -+ p->next = hapd->wps->upnp_msgs; -+ hapd->wps->upnp_msgs = p; -+ -+ return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap); -+} -+ -+ -+static int hostapd_wps_upnp_init(struct hostapd_data *hapd, -+ struct wps_context *wps) -+{ -+ struct upnp_wps_device_ctx *ctx; -+ -+ if (!hapd->conf->upnp_iface) -+ return 0; -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return -1; -+ -+ ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response; -+ if (hapd->conf->ap_pin) -+ ctx->ap_pin = os_strdup(hapd->conf->ap_pin); -+ -+ hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd, -+ hapd->conf->upnp_iface); -+ if (hapd->wps_upnp == NULL) -+ return -1; -+ wps->wps_upnp = hapd->wps_upnp; -+ -+ return 0; -+} -+ -+ -+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) -+{ -+ upnp_wps_device_deinit(hapd->wps_upnp, hapd); -+} -+ -+#endif /* CONFIG_WPS_UPNP */ -+ -+ -+int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, -+ char *buf, size_t buflen) -+{ -+ if (hapd->wps == NULL) -+ return 0; -+ return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen); -+} -+ -+ -+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx) -+{ -+ struct hostapd_data *hapd = eloop_data; -+ wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out"); -+ hostapd_wps_ap_pin_disable(hapd); -+} -+ -+ -+static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout) -+{ -+ wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout); -+ hapd->ap_pin_failures = 0; -+ hapd->conf->ap_setup_locked = 0; -+ if (hapd->wps->ap_setup_locked) { -+ wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED); -+ hapd->wps->ap_setup_locked = 0; -+ wps_registrar_update_ie(hapd->wps->registrar); -+ } -+ eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); -+ if (timeout > 0) -+ eloop_register_timeout(timeout, 0, -+ hostapd_wps_ap_pin_timeout, hapd, NULL); -+} -+ -+ -+static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx) -+{ -+ os_free(hapd->conf->ap_pin); -+ hapd->conf->ap_pin = NULL; -+#ifdef CONFIG_WPS_UPNP -+ upnp_wps_set_ap_pin(hapd->wps_upnp, NULL); -+#endif /* CONFIG_WPS_UPNP */ -+ eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL); -+ return 0; -+} -+ -+ -+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd) -+{ -+ wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN"); -+ hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL); -+} -+ -+ -+struct wps_ap_pin_data { -+ char pin_txt[9]; -+ int timeout; -+}; -+ -+ -+static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx) -+{ -+ struct wps_ap_pin_data *data = ctx; -+ os_free(hapd->conf->ap_pin); -+ hapd->conf->ap_pin = os_strdup(data->pin_txt); -+#ifdef CONFIG_WPS_UPNP -+ upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt); -+#endif /* CONFIG_WPS_UPNP */ -+ hostapd_wps_ap_pin_enable(hapd, data->timeout); -+ return 0; -+} -+ -+ -+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout) -+{ -+ unsigned int pin; -+ struct wps_ap_pin_data data; -+ -+ pin = wps_generate_pin(); -+ os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin); -+ data.timeout = timeout; -+ hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); -+ return hapd->conf->ap_pin; -+} -+ -+ -+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd) -+{ -+ return hapd->conf->ap_pin; -+} -+ -+ -+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, -+ int timeout) -+{ -+ struct wps_ap_pin_data data; -+ int ret; -+ -+ ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin); -+ if (ret < 0 || ret >= (int) sizeof(data.pin_txt)) -+ return -1; -+ data.timeout = timeout; -+ return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data); -+} -+ -+ -+static int wps_update_ie(struct hostapd_data *hapd, void *ctx) -+{ -+ if (hapd->wps) -+ wps_registrar_update_ie(hapd->wps->registrar); -+ return 0; -+} -+ -+ -+void hostapd_wps_update_ie(struct hostapd_data *hapd) -+{ -+ hostapd_wps_for_each(hapd, wps_update_ie, NULL); -+} -+ -+ -+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, -+ const char *auth, const char *encr, const char *key) -+{ -+ struct wps_credential cred; -+ size_t len; -+ -+ os_memset(&cred, 0, sizeof(cred)); -+ -+ len = os_strlen(ssid); -+ if ((len & 1) || len > 2 * sizeof(cred.ssid) || -+ hexstr2bin(ssid, cred.ssid, len / 2)) -+ return -1; -+ cred.ssid_len = len / 2; -+ -+ if (os_strncmp(auth, "OPEN", 4) == 0) -+ cred.auth_type = WPS_AUTH_OPEN; -+ else if (os_strncmp(auth, "WPAPSK", 6) == 0) -+ cred.auth_type = WPS_AUTH_WPAPSK; -+ else if (os_strncmp(auth, "WPA2PSK", 7) == 0) -+ cred.auth_type = WPS_AUTH_WPA2PSK; -+ else -+ return -1; -+ -+ if (encr) { -+ if (os_strncmp(encr, "NONE", 4) == 0) -+ cred.encr_type = WPS_ENCR_NONE; -+ else if (os_strncmp(encr, "WEP", 3) == 0) -+ cred.encr_type = WPS_ENCR_WEP; -+ else if (os_strncmp(encr, "TKIP", 4) == 0) -+ cred.encr_type = WPS_ENCR_TKIP; -+ else if (os_strncmp(encr, "CCMP", 4) == 0) -+ cred.encr_type = WPS_ENCR_AES; -+ else -+ return -1; -+ } else -+ cred.encr_type = WPS_ENCR_NONE; -+ -+ if (key) { -+ len = os_strlen(key); -+ if ((len & 1) || len > 2 * sizeof(cred.key) || -+ hexstr2bin(key, cred.key, len / 2)) -+ return -1; -+ cred.key_len = len / 2; -+ } -+ -+ return wps_registrar_config_ap(hapd->wps->registrar, &cred); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.h -new file mode 100644 -index 0000000000000..338a220885007 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/ap/wps_hostapd.h -@@ -0,0 +1,72 @@ -+/* -+ * hostapd / WPS integration -+ * Copyright (c) 2008-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPS_HOSTAPD_H -+#define WPS_HOSTAPD_H -+ -+#ifdef CONFIG_WPS -+ -+int hostapd_init_wps(struct hostapd_data *hapd, -+ struct hostapd_bss_config *conf); -+void hostapd_deinit_wps(struct hostapd_data *hapd); -+void hostapd_update_wps(struct hostapd_data *hapd); -+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, -+ const char *uuid, const char *pin, int timeout); -+int hostapd_wps_button_pushed(struct hostapd_data *hapd, -+ const u8 *p2p_dev_addr); -+int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, -+ char *path, char *method, char *name); -+int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, -+ char *buf, size_t buflen); -+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd); -+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout); -+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd); -+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin, -+ int timeout); -+void hostapd_wps_update_ie(struct hostapd_data *hapd); -+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid, -+ const char *auth, const char *encr, const char *key); -+ -+#else /* CONFIG_WPS */ -+ -+static inline int hostapd_init_wps(struct hostapd_data *hapd, -+ struct hostapd_bss_config *conf) -+{ -+ return 0; -+} -+ -+static inline void hostapd_deinit_wps(struct hostapd_data *hapd) -+{ -+} -+ -+static inline void hostapd_update_wps(struct hostapd_data *hapd) -+{ -+} -+ -+static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, -+ const u8 *addr, -+ char *buf, size_t buflen) -+{ -+ return 0; -+} -+ -+static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd, -+ const u8 *p2p_dev_addr) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_WPS */ -+ -+#endif /* WPS_HOSTAPD_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/defs.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/defs.h -new file mode 100644 -index 0000000000000..8abec07ffa9f5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/defs.h -@@ -0,0 +1,270 @@ -+/* -+ * WPA Supplicant - Common definitions -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef DEFS_H -+#define DEFS_H -+ -+#ifdef FALSE -+#undef FALSE -+#endif -+#ifdef TRUE -+#undef TRUE -+#endif -+typedef enum { FALSE = 0, TRUE = 1 } Boolean; -+ -+ -+#define WPA_CIPHER_NONE BIT(0) -+#define WPA_CIPHER_WEP40 BIT(1) -+#define WPA_CIPHER_WEP104 BIT(2) -+#define WPA_CIPHER_TKIP BIT(3) -+#define WPA_CIPHER_CCMP BIT(4) -+#ifdef CONFIG_IEEE80211W -+#define WPA_CIPHER_AES_128_CMAC BIT(5) -+#endif /* CONFIG_IEEE80211W */ -+ -+#define WPA_KEY_MGMT_IEEE8021X BIT(0) -+#define WPA_KEY_MGMT_PSK BIT(1) -+#define WPA_KEY_MGMT_NONE BIT(2) -+#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3) -+#define WPA_KEY_MGMT_WPA_NONE BIT(4) -+#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5) -+#define WPA_KEY_MGMT_FT_PSK BIT(6) -+#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7) -+#define WPA_KEY_MGMT_PSK_SHA256 BIT(8) -+#define WPA_KEY_MGMT_WPS BIT(9) -+ -+static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) -+{ -+ return !!(akm & (WPA_KEY_MGMT_IEEE8021X | -+ WPA_KEY_MGMT_FT_IEEE8021X | -+ WPA_KEY_MGMT_IEEE8021X_SHA256)); -+} -+ -+static inline int wpa_key_mgmt_wpa_psk(int akm) -+{ -+ return !!(akm & (WPA_KEY_MGMT_PSK | -+ WPA_KEY_MGMT_FT_PSK | -+ WPA_KEY_MGMT_PSK_SHA256)); -+} -+ -+static inline int wpa_key_mgmt_ft(int akm) -+{ -+ return !!(akm & (WPA_KEY_MGMT_FT_PSK | -+ WPA_KEY_MGMT_FT_IEEE8021X)); -+} -+ -+static inline int wpa_key_mgmt_sha256(int akm) -+{ -+ return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 | -+ WPA_KEY_MGMT_IEEE8021X_SHA256)); -+} -+ -+static inline int wpa_key_mgmt_wpa(int akm) -+{ -+ return wpa_key_mgmt_wpa_ieee8021x(akm) || -+ wpa_key_mgmt_wpa_psk(akm); -+} -+ -+ -+#define WPA_PROTO_WPA BIT(0) -+#define WPA_PROTO_RSN BIT(1) -+ -+#define WPA_AUTH_ALG_OPEN BIT(0) -+#define WPA_AUTH_ALG_SHARED BIT(1) -+#define WPA_AUTH_ALG_LEAP BIT(2) -+#define WPA_AUTH_ALG_FT BIT(3) -+ -+ -+enum wpa_alg { -+ WPA_ALG_NONE, -+ WPA_ALG_WEP, -+ WPA_ALG_TKIP, -+ WPA_ALG_CCMP, -+ WPA_ALG_IGTK, -+ WPA_ALG_PMK -+}; -+ -+/** -+ * enum wpa_cipher - Cipher suites -+ */ -+enum wpa_cipher { -+ CIPHER_NONE, -+ CIPHER_WEP40, -+ CIPHER_TKIP, -+ CIPHER_CCMP, -+ CIPHER_WEP104 -+}; -+ -+/** -+ * enum wpa_key_mgmt - Key management suites -+ */ -+enum wpa_key_mgmt { -+ KEY_MGMT_802_1X, -+ KEY_MGMT_PSK, -+ KEY_MGMT_NONE, -+ KEY_MGMT_802_1X_NO_WPA, -+ KEY_MGMT_WPA_NONE, -+ KEY_MGMT_FT_802_1X, -+ KEY_MGMT_FT_PSK, -+ KEY_MGMT_802_1X_SHA256, -+ KEY_MGMT_PSK_SHA256, -+ KEY_MGMT_WPS -+}; -+ -+/** -+ * enum wpa_states - wpa_supplicant state -+ * -+ * These enumeration values are used to indicate the current wpa_supplicant -+ * state (wpa_s->wpa_state). The current state can be retrieved with -+ * wpa_supplicant_get_state() function and the state can be changed by calling -+ * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the -+ * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used -+ * to access the state variable. -+ */ -+enum wpa_states { -+ /** -+ * WPA_DISCONNECTED - Disconnected state -+ * -+ * This state indicates that client is not associated, but is likely to -+ * start looking for an access point. This state is entered when a -+ * connection is lost. -+ */ -+ WPA_DISCONNECTED, -+ -+ /** -+ * WPA_INTERFACE_DISABLED - Interface disabled -+ * -+ * This stat eis entered if the network interface is disabled, e.g., -+ * due to rfkill. wpa_supplicant refuses any new operations that would -+ * use the radio until the interface has been enabled. -+ */ -+ WPA_INTERFACE_DISABLED, -+ -+ /** -+ * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) -+ * -+ * This state is entered if there are no enabled networks in the -+ * configuration. wpa_supplicant is not trying to associate with a new -+ * network and external interaction (e.g., ctrl_iface call to add or -+ * enable a network) is needed to start association. -+ */ -+ WPA_INACTIVE, -+ -+ /** -+ * WPA_SCANNING - Scanning for a network -+ * -+ * This state is entered when wpa_supplicant starts scanning for a -+ * network. -+ */ -+ WPA_SCANNING, -+ -+ /** -+ * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID -+ * -+ * This state is entered when wpa_supplicant has found a suitable BSS -+ * to authenticate with and the driver is configured to try to -+ * authenticate with this BSS. This state is used only with drivers -+ * that use wpa_supplicant as the SME. -+ */ -+ WPA_AUTHENTICATING, -+ -+ /** -+ * WPA_ASSOCIATING - Trying to associate with a BSS/SSID -+ * -+ * This state is entered when wpa_supplicant has found a suitable BSS -+ * to associate with and the driver is configured to try to associate -+ * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this -+ * state is entered when the driver is configured to try to associate -+ * with a network using the configured SSID and security policy. -+ */ -+ WPA_ASSOCIATING, -+ -+ /** -+ * WPA_ASSOCIATED - Association completed -+ * -+ * This state is entered when the driver reports that association has -+ * been successfully completed with an AP. If IEEE 802.1X is used -+ * (with or without WPA/WPA2), wpa_supplicant remains in this state -+ * until the IEEE 802.1X/EAPOL authentication has been completed. -+ */ -+ WPA_ASSOCIATED, -+ -+ /** -+ * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress -+ * -+ * This state is entered when WPA/WPA2 4-Way Handshake is started. In -+ * case of WPA-PSK, this happens when receiving the first EAPOL-Key -+ * frame after association. In case of WPA-EAP, this state is entered -+ * when the IEEE 802.1X/EAPOL authentication has been completed. -+ */ -+ WPA_4WAY_HANDSHAKE, -+ -+ /** -+ * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress -+ * -+ * This state is entered when 4-Way Key Handshake has been completed -+ * (i.e., when the supplicant sends out message 4/4) and when Group -+ * Key rekeying is started by the AP (i.e., when supplicant receives -+ * message 1/2). -+ */ -+ WPA_GROUP_HANDSHAKE, -+ -+ /** -+ * WPA_COMPLETED - All authentication completed -+ * -+ * This state is entered when the full authentication process is -+ * completed. In case of WPA2, this happens when the 4-Way Handshake is -+ * successfully completed. With WPA, this state is entered after the -+ * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is -+ * completed after dynamic keys are received (or if not used, after -+ * the EAP authentication has been completed). With static WEP keys and -+ * plaintext connections, this state is entered when an association -+ * has been completed. -+ * -+ * This state indicates that the supplicant has completed its -+ * processing for the association phase and that data connection is -+ * fully configured. -+ */ -+ WPA_COMPLETED -+}; -+ -+#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0 -+#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1 -+#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2 -+#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3 -+ -+#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0 -+#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1 -+ -+ -+/** -+ * enum mfp_options - Management frame protection (IEEE 802.11w) options -+ */ -+enum mfp_options { -+ NO_MGMT_FRAME_PROTECTION = 0, -+ MGMT_FRAME_PROTECTION_OPTIONAL = 1, -+ MGMT_FRAME_PROTECTION_REQUIRED = 2 -+}; -+ -+/** -+ * enum hostapd_hw_mode - Hardware mode -+ */ -+enum hostapd_hw_mode { -+ HOSTAPD_MODE_IEEE80211B, -+ HOSTAPD_MODE_IEEE80211G, -+ HOSTAPD_MODE_IEEE80211A, -+ NUM_HOSTAPD_MODES -+}; -+ -+#endif /* DEFS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/eapol_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/eapol_common.h -new file mode 100644 -index 0000000000000..d70e62d2f6487 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/eapol_common.h -@@ -0,0 +1,47 @@ -+/* -+ * EAPOL definitions shared between hostapd and wpa_supplicant -+ * Copyright (c) 2002-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAPOL_COMMON_H -+#define EAPOL_COMMON_H -+ -+/* IEEE Std 802.1X-2004 */ -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct ieee802_1x_hdr { -+ u8 version; -+ u8 type; -+ be16 length; -+ /* followed by length octets of data */ -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+#define EAPOL_VERSION 2 -+ -+enum { IEEE802_1X_TYPE_EAP_PACKET = 0, -+ IEEE802_1X_TYPE_EAPOL_START = 1, -+ IEEE802_1X_TYPE_EAPOL_LOGOFF = 2, -+ IEEE802_1X_TYPE_EAPOL_KEY = 3, -+ IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4 -+}; -+ -+enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2, -+ EAPOL_KEY_TYPE_WPA = 254 }; -+ -+#endif /* EAPOL_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.c -new file mode 100644 -index 0000000000000..ee41b3a6e7e06 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.c -@@ -0,0 +1,347 @@ -+/* -+ * IEEE 802.11 Common routines -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "ieee802_11_defs.h" -+#include "ieee802_11_common.h" -+ -+ -+static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, -+ struct ieee802_11_elems *elems, -+ int show_errors) -+{ -+ unsigned int oui; -+ -+ /* first 3 bytes in vendor specific information element are the IEEE -+ * OUI of the vendor. The following byte is used a vendor specific -+ * sub-type. */ -+ if (elen < 4) { -+ if (show_errors) { -+ wpa_printf(MSG_MSGDUMP, "short vendor specific " -+ "information element ignored (len=%lu)", -+ (unsigned long) elen); -+ } -+ return -1; -+ } -+ -+ oui = WPA_GET_BE24(pos); -+ switch (oui) { -+ case OUI_MICROSOFT: -+ /* Microsoft/Wi-Fi information elements are further typed and -+ * subtyped */ -+ switch (pos[3]) { -+ case 1: -+ /* Microsoft OUI (00:50:F2) with OUI Type 1: -+ * real WPA information element */ -+ elems->wpa_ie = pos; -+ elems->wpa_ie_len = elen; -+ break; -+ case WMM_OUI_TYPE: -+ /* WMM information element */ -+ if (elen < 5) { -+ wpa_printf(MSG_MSGDUMP, "short WMM " -+ "information element ignored " -+ "(len=%lu)", -+ (unsigned long) elen); -+ return -1; -+ } -+ switch (pos[4]) { -+ case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT: -+ case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT: -+ /* -+ * Share same pointer since only one of these -+ * is used and they start with same data. -+ * Length field can be used to distinguish the -+ * IEs. -+ */ -+ elems->wmm = pos; -+ elems->wmm_len = elen; -+ break; -+ case WMM_OUI_SUBTYPE_TSPEC_ELEMENT: -+ elems->wmm_tspec = pos; -+ elems->wmm_tspec_len = elen; -+ break; -+ default: -+ wpa_printf(MSG_EXCESSIVE, "unknown WMM " -+ "information element ignored " -+ "(subtype=%d len=%lu)", -+ pos[4], (unsigned long) elen); -+ return -1; -+ } -+ break; -+ case 4: -+ /* Wi-Fi Protected Setup (WPS) IE */ -+ elems->wps_ie = pos; -+ elems->wps_ie_len = elen; -+ break; -+ default: -+ wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft " -+ "information element ignored " -+ "(type=%d len=%lu)", -+ pos[3], (unsigned long) elen); -+ return -1; -+ } -+ break; -+ -+ case OUI_WFA: -+ switch (pos[3]) { -+ case P2P_OUI_TYPE: -+ /* Wi-Fi Alliance - P2P IE */ -+ elems->p2p = pos; -+ elems->p2p_len = elen; -+ break; -+ default: -+ wpa_printf(MSG_MSGDUMP, "Unknown WFA " -+ "information element ignored " -+ "(type=%d len=%lu)\n", -+ pos[3], (unsigned long) elen); -+ return -1; -+ } -+ break; -+ -+ case OUI_BROADCOM: -+ switch (pos[3]) { -+ case VENDOR_HT_CAPAB_OUI_TYPE: -+ elems->vendor_ht_cap = pos; -+ elems->vendor_ht_cap_len = elen; -+ break; -+ default: -+ wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom " -+ "information element ignored " -+ "(type=%d len=%lu)", -+ pos[3], (unsigned long) elen); -+ return -1; -+ } -+ break; -+ -+ default: -+ wpa_printf(MSG_EXCESSIVE, "unknown vendor specific " -+ "information element ignored (vendor OUI " -+ "%02x:%02x:%02x len=%lu)", -+ pos[0], pos[1], pos[2], (unsigned long) elen); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * ieee802_11_parse_elems - Parse information elements in management frames -+ * @start: Pointer to the start of IEs -+ * @len: Length of IE buffer in octets -+ * @elems: Data structure for parsed elements -+ * @show_errors: Whether to show parsing errors in debug log -+ * Returns: Parsing result -+ */ -+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, -+ struct ieee802_11_elems *elems, -+ int show_errors) -+{ -+ size_t left = len; -+ const u8 *pos = start; -+ int unknown = 0; -+ -+ os_memset(elems, 0, sizeof(*elems)); -+ -+ while (left >= 2) { -+ u8 id, elen; -+ -+ id = *pos++; -+ elen = *pos++; -+ left -= 2; -+ -+ if (elen > left) { -+ if (show_errors) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.11 element " -+ "parse failed (id=%d elen=%d " -+ "left=%lu)", -+ id, elen, (unsigned long) left); -+ wpa_hexdump(MSG_MSGDUMP, "IEs", start, len); -+ } -+ return ParseFailed; -+ } -+ -+ switch (id) { -+ case WLAN_EID_SSID: -+ elems->ssid = pos; -+ elems->ssid_len = elen; -+ break; -+ case WLAN_EID_SUPP_RATES: -+ elems->supp_rates = pos; -+ elems->supp_rates_len = elen; -+ break; -+ case WLAN_EID_FH_PARAMS: -+ elems->fh_params = pos; -+ elems->fh_params_len = elen; -+ break; -+ case WLAN_EID_DS_PARAMS: -+ elems->ds_params = pos; -+ elems->ds_params_len = elen; -+ break; -+ case WLAN_EID_CF_PARAMS: -+ elems->cf_params = pos; -+ elems->cf_params_len = elen; -+ break; -+ case WLAN_EID_TIM: -+ elems->tim = pos; -+ elems->tim_len = elen; -+ break; -+ case WLAN_EID_IBSS_PARAMS: -+ elems->ibss_params = pos; -+ elems->ibss_params_len = elen; -+ break; -+ case WLAN_EID_CHALLENGE: -+ elems->challenge = pos; -+ elems->challenge_len = elen; -+ break; -+ case WLAN_EID_ERP_INFO: -+ elems->erp_info = pos; -+ elems->erp_info_len = elen; -+ break; -+ case WLAN_EID_EXT_SUPP_RATES: -+ elems->ext_supp_rates = pos; -+ elems->ext_supp_rates_len = elen; -+ break; -+ case WLAN_EID_VENDOR_SPECIFIC: -+ if (ieee802_11_parse_vendor_specific(pos, elen, -+ elems, -+ show_errors)) -+ unknown++; -+ break; -+ case WLAN_EID_RSN: -+ elems->rsn_ie = pos; -+ elems->rsn_ie_len = elen; -+ break; -+ case WLAN_EID_PWR_CAPABILITY: -+ elems->power_cap = pos; -+ elems->power_cap_len = elen; -+ break; -+ case WLAN_EID_SUPPORTED_CHANNELS: -+ elems->supp_channels = pos; -+ elems->supp_channels_len = elen; -+ break; -+ case WLAN_EID_MOBILITY_DOMAIN: -+ elems->mdie = pos; -+ elems->mdie_len = elen; -+ break; -+ case WLAN_EID_FAST_BSS_TRANSITION: -+ elems->ftie = pos; -+ elems->ftie_len = elen; -+ break; -+ case WLAN_EID_TIMEOUT_INTERVAL: -+ elems->timeout_int = pos; -+ elems->timeout_int_len = elen; -+ break; -+ case WLAN_EID_HT_CAP: -+ elems->ht_capabilities = pos; -+ elems->ht_capabilities_len = elen; -+ break; -+ case WLAN_EID_HT_OPERATION: -+ elems->ht_operation = pos; -+ elems->ht_operation_len = elen; -+ break; -+ case WLAN_EID_LINK_ID: -+ if (elen < 18) -+ break; -+ elems->link_id = pos; -+ break; -+ default: -+ unknown++; -+ if (!show_errors) -+ break; -+ wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse " -+ "ignored unknown element (id=%d elen=%d)", -+ id, elen); -+ break; -+ } -+ -+ left -= elen; -+ pos += elen; -+ } -+ -+ if (left) -+ return ParseFailed; -+ -+ return unknown ? ParseUnknown : ParseOK; -+} -+ -+ -+int ieee802_11_ie_count(const u8 *ies, size_t ies_len) -+{ -+ int count = 0; -+ const u8 *pos, *end; -+ -+ if (ies == NULL) -+ return 0; -+ -+ pos = ies; -+ end = ies + ies_len; -+ -+ while (pos + 2 <= end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ count++; -+ pos += 2 + pos[1]; -+ } -+ -+ return count; -+} -+ -+ -+struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, -+ u32 oui_type) -+{ -+ struct wpabuf *buf; -+ const u8 *end, *pos, *ie; -+ -+ pos = ies; -+ end = ies + ies_len; -+ ie = NULL; -+ -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ return NULL; -+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && -+ WPA_GET_BE32(&pos[2]) == oui_type) { -+ ie = pos; -+ break; -+ } -+ pos += 2 + pos[1]; -+ } -+ -+ if (ie == NULL) -+ return NULL; /* No specified vendor IE found */ -+ -+ buf = wpabuf_alloc(ies_len); -+ if (buf == NULL) -+ return NULL; -+ -+ /* -+ * There may be multiple vendor IEs in the message, so need to -+ * concatenate their data fields. -+ */ -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && -+ WPA_GET_BE32(&pos[2]) == oui_type) -+ wpabuf_put_data(buf, pos + 6, pos[1] - 4); -+ pos += 2 + pos[1]; -+ } -+ -+ return buf; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.h -new file mode 100644 -index 0000000000000..0c90fa47c3666 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_common.h -@@ -0,0 +1,81 @@ -+/* -+ * IEEE 802.11 Common routines -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IEEE802_11_COMMON_H -+#define IEEE802_11_COMMON_H -+ -+/* Parsed Information Elements */ -+struct ieee802_11_elems { -+ const u8 *ssid; -+ const u8 *supp_rates; -+ const u8 *fh_params; -+ const u8 *ds_params; -+ const u8 *cf_params; -+ const u8 *tim; -+ const u8 *ibss_params; -+ const u8 *challenge; -+ const u8 *erp_info; -+ const u8 *ext_supp_rates; -+ const u8 *wpa_ie; -+ const u8 *rsn_ie; -+ const u8 *wmm; /* WMM Information or Parameter Element */ -+ const u8 *wmm_tspec; -+ const u8 *wps_ie; -+ const u8 *power_cap; -+ const u8 *supp_channels; -+ const u8 *mdie; -+ const u8 *ftie; -+ const u8 *timeout_int; -+ const u8 *ht_capabilities; -+ const u8 *ht_operation; -+ const u8 *vendor_ht_cap; -+ const u8 *p2p; -+ const u8 *link_id; -+ -+ u8 ssid_len; -+ u8 supp_rates_len; -+ u8 fh_params_len; -+ u8 ds_params_len; -+ u8 cf_params_len; -+ u8 tim_len; -+ u8 ibss_params_len; -+ u8 challenge_len; -+ u8 erp_info_len; -+ u8 ext_supp_rates_len; -+ u8 wpa_ie_len; -+ u8 rsn_ie_len; -+ u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */ -+ u8 wmm_tspec_len; -+ u8 wps_ie_len; -+ u8 power_cap_len; -+ u8 supp_channels_len; -+ u8 mdie_len; -+ u8 ftie_len; -+ u8 timeout_int_len; -+ u8 ht_capabilities_len; -+ u8 ht_operation_len; -+ u8 vendor_ht_cap_len; -+ u8 p2p_len; -+}; -+ -+typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; -+ -+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, -+ struct ieee802_11_elems *elems, -+ int show_errors); -+int ieee802_11_ie_count(const u8 *ies, size_t ies_len); -+struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, -+ u32 oui_type); -+ -+#endif /* IEEE802_11_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_defs.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_defs.h -new file mode 100644 -index 0000000000000..86868c0d7f363 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/ieee802_11_defs.h -@@ -0,0 +1,800 @@ -+/* -+ * IEEE 802.11 Frame type definitions -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * Copyright (c) 2007-2008 Intel Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IEEE802_11_DEFS_H -+#define IEEE802_11_DEFS_H -+ -+/* IEEE 802.11 defines */ -+ -+#define WLAN_FC_PVER 0x0003 -+#define WLAN_FC_TODS 0x0100 -+#define WLAN_FC_FROMDS 0x0200 -+#define WLAN_FC_MOREFRAG 0x0400 -+#define WLAN_FC_RETRY 0x0800 -+#define WLAN_FC_PWRMGT 0x1000 -+#define WLAN_FC_MOREDATA 0x2000 -+#define WLAN_FC_ISWEP 0x4000 -+#define WLAN_FC_ORDER 0x8000 -+ -+#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) -+#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) -+ -+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0))) -+#define WLAN_GET_SEQ_SEQ(seq) \ -+ (((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4) -+ -+#define WLAN_FC_TYPE_MGMT 0 -+#define WLAN_FC_TYPE_CTRL 1 -+#define WLAN_FC_TYPE_DATA 2 -+ -+/* management */ -+#define WLAN_FC_STYPE_ASSOC_REQ 0 -+#define WLAN_FC_STYPE_ASSOC_RESP 1 -+#define WLAN_FC_STYPE_REASSOC_REQ 2 -+#define WLAN_FC_STYPE_REASSOC_RESP 3 -+#define WLAN_FC_STYPE_PROBE_REQ 4 -+#define WLAN_FC_STYPE_PROBE_RESP 5 -+#define WLAN_FC_STYPE_BEACON 8 -+#define WLAN_FC_STYPE_ATIM 9 -+#define WLAN_FC_STYPE_DISASSOC 10 -+#define WLAN_FC_STYPE_AUTH 11 -+#define WLAN_FC_STYPE_DEAUTH 12 -+#define WLAN_FC_STYPE_ACTION 13 -+ -+/* control */ -+#define WLAN_FC_STYPE_PSPOLL 10 -+#define WLAN_FC_STYPE_RTS 11 -+#define WLAN_FC_STYPE_CTS 12 -+#define WLAN_FC_STYPE_ACK 13 -+#define WLAN_FC_STYPE_CFEND 14 -+#define WLAN_FC_STYPE_CFENDACK 15 -+ -+/* data */ -+#define WLAN_FC_STYPE_DATA 0 -+#define WLAN_FC_STYPE_DATA_CFACK 1 -+#define WLAN_FC_STYPE_DATA_CFPOLL 2 -+#define WLAN_FC_STYPE_DATA_CFACKPOLL 3 -+#define WLAN_FC_STYPE_NULLFUNC 4 -+#define WLAN_FC_STYPE_CFACK 5 -+#define WLAN_FC_STYPE_CFPOLL 6 -+#define WLAN_FC_STYPE_CFACKPOLL 7 -+#define WLAN_FC_STYPE_QOS_DATA 8 -+#define WLAN_FC_STYPE_QOS_DATA_CFACK 9 -+#define WLAN_FC_STYPE_QOS_DATA_CFPOLL 10 -+#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL 11 -+#define WLAN_FC_STYPE_QOS_NULL 12 -+#define WLAN_FC_STYPE_QOS_CFPOLL 14 -+#define WLAN_FC_STYPE_QOS_CFACKPOLL 15 -+ -+/* Authentication algorithms */ -+#define WLAN_AUTH_OPEN 0 -+#define WLAN_AUTH_SHARED_KEY 1 -+#define WLAN_AUTH_FT 2 -+#define WLAN_AUTH_LEAP 128 -+ -+#define WLAN_AUTH_CHALLENGE_LEN 128 -+ -+#define WLAN_CAPABILITY_ESS BIT(0) -+#define WLAN_CAPABILITY_IBSS BIT(1) -+#define WLAN_CAPABILITY_CF_POLLABLE BIT(2) -+#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3) -+#define WLAN_CAPABILITY_PRIVACY BIT(4) -+#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5) -+#define WLAN_CAPABILITY_PBCC BIT(6) -+#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7) -+#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8) -+#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10) -+#define WLAN_CAPABILITY_DSSS_OFDM BIT(13) -+ -+/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */ -+#define WLAN_STATUS_SUCCESS 0 -+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 -+#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2 -+#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3 -+#define WLAN_STATUS_SECURITY_DISABLED 5 -+#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6 -+#define WLAN_STATUS_NOT_IN_SAME_BSS 7 -+#define WLAN_STATUS_CAPS_UNSUPPORTED 10 -+#define WLAN_STATUS_REASSOC_NO_ASSOC 11 -+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 -+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 -+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 -+#define WLAN_STATUS_CHALLENGE_FAIL 15 -+#define WLAN_STATUS_AUTH_TIMEOUT 16 -+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 -+#define WLAN_STATUS_ASSOC_DENIED_RATES 18 -+/* IEEE 802.11b */ -+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 -+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 -+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 -+/* IEEE 802.11h */ -+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 -+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 -+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 -+/* IEEE 802.11g */ -+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 -+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26 -+#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27 -+#define WLAN_STATUS_R0KH_UNREACHABLE 28 -+#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29 -+/* IEEE 802.11w */ -+#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 -+#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 -+#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32 -+#define WLAN_STATUS_REQUEST_DECLINED 37 -+#define WLAN_STATUS_INVALID_PARAMETERS 38 -+/* IEEE 802.11i */ -+#define WLAN_STATUS_INVALID_IE 40 -+#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 -+#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 -+#define WLAN_STATUS_AKMP_NOT_VALID 43 -+#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 -+#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 -+#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 -+#define WLAN_STATUS_TS_NOT_CREATED 47 -+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 -+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 -+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 -+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 -+/* IEEE 802.11r */ -+#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 -+#define WLAN_STATUS_INVALID_PMKID 53 -+#define WLAN_STATUS_INVALID_MDIE 54 -+#define WLAN_STATUS_INVALID_FTIE 55 -+#define WLAN_STATUS_INVALID_RSNIE 72 -+ -+/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */ -+#define WLAN_REASON_UNSPECIFIED 1 -+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 -+#define WLAN_REASON_DEAUTH_LEAVING 3 -+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 -+#define WLAN_REASON_DISASSOC_AP_BUSY 5 -+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 -+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 -+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 -+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 -+/* IEEE 802.11h */ -+#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 -+#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 -+/* IEEE 802.11i */ -+#define WLAN_REASON_INVALID_IE 13 -+#define WLAN_REASON_MICHAEL_MIC_FAILURE 14 -+#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 -+#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 -+#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 -+#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 -+#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 -+#define WLAN_REASON_AKMP_NOT_VALID 20 -+#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 -+#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 -+#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 -+#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 -+#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25 -+#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26 -+/* IEEE 802.11e */ -+#define WLAN_REASON_DISASSOC_LOW_ACK 34 -+ -+ -+/* Information Element IDs */ -+#define WLAN_EID_SSID 0 -+#define WLAN_EID_SUPP_RATES 1 -+#define WLAN_EID_FH_PARAMS 2 -+#define WLAN_EID_DS_PARAMS 3 -+#define WLAN_EID_CF_PARAMS 4 -+#define WLAN_EID_TIM 5 -+#define WLAN_EID_IBSS_PARAMS 6 -+#define WLAN_EID_COUNTRY 7 -+#define WLAN_EID_CHALLENGE 16 -+/* EIDs defined by IEEE 802.11h - START */ -+#define WLAN_EID_PWR_CONSTRAINT 32 -+#define WLAN_EID_PWR_CAPABILITY 33 -+#define WLAN_EID_TPC_REQUEST 34 -+#define WLAN_EID_TPC_REPORT 35 -+#define WLAN_EID_SUPPORTED_CHANNELS 36 -+#define WLAN_EID_CHANNEL_SWITCH 37 -+#define WLAN_EID_MEASURE_REQUEST 38 -+#define WLAN_EID_MEASURE_REPORT 39 -+#define WLAN_EID_QUITE 40 -+#define WLAN_EID_IBSS_DFS 41 -+/* EIDs defined by IEEE 802.11h - END */ -+#define WLAN_EID_ERP_INFO 42 -+#define WLAN_EID_HT_CAP 45 -+#define WLAN_EID_RSN 48 -+#define WLAN_EID_EXT_SUPP_RATES 50 -+#define WLAN_EID_MOBILITY_DOMAIN 54 -+#define WLAN_EID_FAST_BSS_TRANSITION 55 -+#define WLAN_EID_TIMEOUT_INTERVAL 56 -+#define WLAN_EID_RIC_DATA 57 -+#define WLAN_EID_HT_OPERATION 61 -+#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 -+#define WLAN_EID_20_40_BSS_COEXISTENCE 72 -+#define WLAN_EID_20_40_BSS_INTOLERANT 73 -+#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 -+#define WLAN_EID_MMIE 76 -+#define WLAN_EID_LINK_ID 101 -+#define WLAN_EID_ADV_PROTO 108 -+#define WLAN_EID_EXT_CAPAB 127 -+#define WLAN_EID_VENDOR_SPECIFIC 221 -+ -+ -+/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */ -+#define WLAN_ACTION_SPECTRUM_MGMT 0 -+#define WLAN_ACTION_QOS 1 -+#define WLAN_ACTION_DLS 2 -+#define WLAN_ACTION_BLOCK_ACK 3 -+#define WLAN_ACTION_PUBLIC 4 -+#define WLAN_ACTION_RADIO_MEASUREMENT 5 -+#define WLAN_ACTION_FT 6 -+#define WLAN_ACTION_HT 7 -+#define WLAN_ACTION_SA_QUERY 8 -+#define WLAN_ACTION_TDLS 12 -+#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */ -+#define WLAN_ACTION_VENDOR_SPECIFIC 127 -+ -+/* Public action codes */ -+#define WLAN_PA_VENDOR_SPECIFIC 9 -+#define WLAN_PA_GAS_INITIAL_REQ 10 -+#define WLAN_PA_GAS_INITIAL_RESP 11 -+#define WLAN_PA_GAS_COMEBACK_REQ 12 -+#define WLAN_PA_GAS_COMEBACK_RESP 13 -+ -+/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ -+#define WLAN_SA_QUERY_REQUEST 0 -+#define WLAN_SA_QUERY_RESPONSE 1 -+ -+#define WLAN_SA_QUERY_TR_ID_LEN 2 -+ -+/* TDLS action codes */ -+#define WLAN_TDLS_SETUP_REQUEST 0 -+#define WLAN_TDLS_SETUP_RESPONSE 1 -+#define WLAN_TDLS_SETUP_CONFIRM 2 -+#define WLAN_TDLS_TEARDOWN 3 -+#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4 -+#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5 -+#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6 -+#define WLAN_TDLS_PEER_PSM_REQUEST 7 -+#define WLAN_TDLS_PEER_PSM_RESPONSE 8 -+#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9 -+#define WLAN_TDLS_DISCOVERY_REQUEST 10 -+ -+/* Timeout Interval Type */ -+#define WLAN_TIMEOUT_REASSOC_DEADLINE 1 -+#define WLAN_TIMEOUT_KEY_LIFETIME 2 -+#define WLAN_TIMEOUT_ASSOC_COMEBACK 3 -+ -+/* Advertisement Protocol ID definitions (IEEE 802.11u) */ -+enum adv_proto_id { -+ NATIVE_QUERY_PROTOCOL = 0, -+ MIH_INFO_SERVICE = 1, -+ MIH_CMD_AND_EVENT_DISCOVERY = 2, -+ EMERGENCY_ALERT_SYSTEM = 3, -+ LOCATION_TO_SERVICE = 4, -+ ADV_PROTO_VENDOR_SPECIFIC = 221 -+}; -+ -+/* Native Query Protocol info ID definitions (IEEE 802.11u) */ -+enum nqp_info_id { -+ NQP_CAPABILITY_LIST = 256, -+ NQP_VENUE_NAME = 257, -+ NQP_EMERGENCY_CALL_NUMBER = 258, -+ NQP_NETWORK_AUTH_TYPE = 259, -+ NQP_ROAMING_CONSORTIUM = 260, -+ NQP_IP_ADDR_TYPE_AVAILABILITY = 261, -+ NQP_NAI_REALM = 262, -+ NQP_3GPP_CELLULAR_NETWORK = 263, -+ NQP_AP_GEOSPATIAL_LOCATION = 264, -+ NQP_AP_CIVIC_LOCATION = 265, -+ NQP_DOMAIN_NAME = 266, -+ NQP_EMERGENCY_ALERT_URI = 267, -+ NQP_VENDOR_SPECIFIC = 56797 -+}; -+ -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct ieee80211_hdr { -+ le16 frame_control; -+ le16 duration_id; -+ u8 addr1[6]; -+ u8 addr2[6]; -+ u8 addr3[6]; -+ le16 seq_ctrl; -+ /* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame -+ */ -+} STRUCT_PACKED; -+ -+#define IEEE80211_DA_FROMDS addr1 -+#define IEEE80211_BSSID_FROMDS addr2 -+#define IEEE80211_SA_FROMDS addr3 -+ -+#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) -+ -+#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) -+ -+struct ieee80211_mgmt { -+ le16 frame_control; -+ le16 duration; -+ u8 da[6]; -+ u8 sa[6]; -+ u8 bssid[6]; -+ le16 seq_ctrl; -+ union { -+ struct { -+ le16 auth_alg; -+ le16 auth_transaction; -+ le16 status_code; -+ /* possibly followed by Challenge text */ -+ u8 variable[0]; -+ } STRUCT_PACKED auth; -+ struct { -+ le16 reason_code; -+ u8 variable[0]; -+ } STRUCT_PACKED deauth; -+ struct { -+ le16 capab_info; -+ le16 listen_interval; -+ /* followed by SSID and Supported rates */ -+ u8 variable[0]; -+ } STRUCT_PACKED assoc_req; -+ struct { -+ le16 capab_info; -+ le16 status_code; -+ le16 aid; -+ /* followed by Supported rates */ -+ u8 variable[0]; -+ } STRUCT_PACKED assoc_resp, reassoc_resp; -+ struct { -+ le16 capab_info; -+ le16 listen_interval; -+ u8 current_ap[6]; -+ /* followed by SSID and Supported rates */ -+ u8 variable[0]; -+ } STRUCT_PACKED reassoc_req; -+ struct { -+ le16 reason_code; -+ u8 variable[0]; -+ } STRUCT_PACKED disassoc; -+ struct { -+ u8 timestamp[8]; -+ le16 beacon_int; -+ le16 capab_info; -+ /* followed by some of SSID, Supported rates, -+ * FH Params, DS Params, CF Params, IBSS Params, TIM */ -+ u8 variable[0]; -+ } STRUCT_PACKED beacon; -+ struct { -+ /* only variable items: SSID, Supported rates */ -+ u8 variable[0]; -+ } STRUCT_PACKED probe_req; -+ struct { -+ u8 timestamp[8]; -+ le16 beacon_int; -+ le16 capab_info; -+ /* followed by some of SSID, Supported rates, -+ * FH Params, DS Params, CF Params, IBSS Params */ -+ u8 variable[0]; -+ } STRUCT_PACKED probe_resp; -+ struct { -+ u8 category; -+ union { -+ struct { -+ u8 action_code; -+ u8 dialog_token; -+ u8 status_code; -+ u8 variable[0]; -+ } STRUCT_PACKED wmm_action; -+ struct{ -+ u8 action_code; -+ u8 element_id; -+ u8 length; -+ u8 switch_mode; -+ u8 new_chan; -+ u8 switch_count; -+ } STRUCT_PACKED chan_switch; -+ struct { -+ u8 action; -+ u8 sta_addr[ETH_ALEN]; -+ u8 target_ap_addr[ETH_ALEN]; -+ u8 variable[0]; /* FT Request */ -+ } STRUCT_PACKED ft_action_req; -+ struct { -+ u8 action; -+ u8 sta_addr[ETH_ALEN]; -+ u8 target_ap_addr[ETH_ALEN]; -+ le16 status_code; -+ u8 variable[0]; /* FT Request */ -+ } STRUCT_PACKED ft_action_resp; -+ struct { -+ u8 action; -+ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; -+ } STRUCT_PACKED sa_query_req; -+ struct { -+ u8 action; /* */ -+ u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; -+ } STRUCT_PACKED sa_query_resp; -+ struct { -+ u8 action; -+ u8 variable[0]; -+ } STRUCT_PACKED public_action; -+ struct { -+ u8 action; /* 9 */ -+ u8 oui[3]; -+ /* Vendor-specific content */ -+ u8 variable[0]; -+ } STRUCT_PACKED vs_public_action; -+ } u; -+ } STRUCT_PACKED action; -+ } u; -+} STRUCT_PACKED; -+ -+ -+struct ieee80211_ht_capabilities { -+ le16 ht_capabilities_info; -+ u8 a_mpdu_params; -+ u8 supported_mcs_set[16]; -+ le16 ht_extended_capabilities; -+ le32 tx_bf_capability_info; -+ u8 asel_capabilities; -+} STRUCT_PACKED; -+ -+ -+struct ieee80211_ht_operation { -+ u8 control_chan; -+ u8 ht_param; -+ le16 operation_mode; -+ le16 stbc_param; -+ u8 basic_set[16]; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+#define ERP_INFO_NON_ERP_PRESENT BIT(0) -+#define ERP_INFO_USE_PROTECTION BIT(1) -+#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) -+ -+ -+#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) -+#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) -+#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) -+#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) -+#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) -+#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) -+#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) -+#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) -+#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) -+#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) -+#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) -+#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) -+#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) -+#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) -+#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) -+#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) -+#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) -+#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) -+#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) -+#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) -+ -+ -+#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0)) -+#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1 -+#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8 -+#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10)) -+#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11)) -+ -+ -+#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0)) -+#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1)) -+#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2)) -+#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3)) -+#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4)) -+#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5)) -+#define TX_BEAMFORM_CAP_CALIB_OFFSET 6 -+#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8)) -+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9)) -+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10)) -+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11 -+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13 -+#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15 -+#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17 -+#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19 -+#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21 -+#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23 -+#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25 -+ -+ -+#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0)) -+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1)) -+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2)) -+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3)) -+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4)) -+#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5)) -+#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6)) -+ -+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) -+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) -+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) -+#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) -+#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) -+#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) -+#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) -+ -+ -+#define OP_MODE_PURE 0 -+#define OP_MODE_MAY_BE_LEGACY_STAS 1 -+#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 -+#define OP_MODE_MIXED 3 -+ -+#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ -+ ((le16) (0x0001 | 0x0002)) -+#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 -+#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) -+#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) -+#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) -+ -+#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) -+#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) -+#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8)) -+#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) -+#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) -+#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) -+ -+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 -+ -+#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) -+ * 00:50:F2 */ -+#define WPA_IE_VENDOR_TYPE 0x0050f201 -+#define WPS_IE_VENDOR_TYPE 0x0050f204 -+#define OUI_WFA 0x506f9a -+#define P2P_IE_VENDOR_TYPE 0x506f9a09 -+ -+#define WMM_OUI_TYPE 2 -+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 -+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 -+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2 -+#define WMM_VERSION 1 -+ -+#define WMM_ACTION_CODE_ADDTS_REQ 0 -+#define WMM_ACTION_CODE_ADDTS_RESP 1 -+#define WMM_ACTION_CODE_DELTS 2 -+ -+#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0 -+#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1 -+/* 2 - Reserved */ -+#define WMM_ADDTS_STATUS_REFUSED 3 -+/* 4-255 - Reserved */ -+ -+/* WMM TSPEC Direction Field Values */ -+#define WMM_TSPEC_DIRECTION_UPLINK 0 -+#define WMM_TSPEC_DIRECTION_DOWNLINK 1 -+/* 2 - Reserved */ -+#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3 -+ -+/* -+ * WMM Information Element (used in (Re)Association Request frames; may also be -+ * used in Beacon frames) -+ */ -+struct wmm_information_element { -+ /* Element ID: 221 (0xdd); Length: 7 */ -+ /* required fields for WMM version 1 */ -+ u8 oui[3]; /* 00:50:f2 */ -+ u8 oui_type; /* 2 */ -+ u8 oui_subtype; /* 0 */ -+ u8 version; /* 1 for WMM version 1.0 */ -+ u8 qos_info; /* AP/STA specific QoS info */ -+ -+} STRUCT_PACKED; -+ -+#define WMM_AC_AIFSN_MASK 0x0f -+#define WMM_AC_AIFNS_SHIFT 0 -+#define WMM_AC_ACM 0x10 -+#define WMM_AC_ACI_MASK 0x60 -+#define WMM_AC_ACI_SHIFT 5 -+ -+#define WMM_AC_ECWMIN_MASK 0x0f -+#define WMM_AC_ECWMIN_SHIFT 0 -+#define WMM_AC_ECWMAX_MASK 0xf0 -+#define WMM_AC_ECWMAX_SHIFT 4 -+ -+struct wmm_ac_parameter { -+ u8 aci_aifsn; /* AIFSN, ACM, ACI */ -+ u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ -+ le16 txop_limit; -+} STRUCT_PACKED; -+ -+/* -+ * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association -+ * Response frmaes) -+ */ -+struct wmm_parameter_element { -+ /* Element ID: 221 (0xdd); Length: 24 */ -+ /* required fields for WMM version 1 */ -+ u8 oui[3]; /* 00:50:f2 */ -+ u8 oui_type; /* 2 */ -+ u8 oui_subtype; /* 1 */ -+ u8 version; /* 1 for WMM version 1.0 */ -+ u8 qos_info; /* AP/STA specif QoS info */ -+ u8 reserved; /* 0 */ -+ struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */ -+ -+} STRUCT_PACKED; -+ -+/* WMM TSPEC Element */ -+struct wmm_tspec_element { -+ u8 eid; /* 221 = 0xdd */ -+ u8 length; /* 6 + 55 = 61 */ -+ u8 oui[3]; /* 00:50:f2 */ -+ u8 oui_type; /* 2 */ -+ u8 oui_subtype; /* 2 */ -+ u8 version; /* 1 */ -+ /* WMM TSPEC body (55 octets): */ -+ u8 ts_info[3]; -+ le16 nominal_msdu_size; -+ le16 maximum_msdu_size; -+ le32 minimum_service_interval; -+ le32 maximum_service_interval; -+ le32 inactivity_interval; -+ le32 suspension_interval; -+ le32 service_start_time; -+ le32 minimum_data_rate; -+ le32 mean_data_rate; -+ le32 peak_data_rate; -+ le32 maximum_burst_size; -+ le32 delay_bound; -+ le32 minimum_phy_rate; -+ le16 surplus_bandwidth_allowance; -+ le16 medium_time; -+} STRUCT_PACKED; -+ -+ -+/* Access Categories / ACI to AC coding */ -+enum { -+ WMM_AC_BE = 0 /* Best Effort */, -+ WMM_AC_BK = 1 /* Background */, -+ WMM_AC_VI = 2 /* Video */, -+ WMM_AC_VO = 3 /* Voice */ -+}; -+ -+ -+/* Wi-Fi Direct (P2P) */ -+ -+#define P2P_OUI_TYPE 9 -+ -+enum p2p_attr_id { -+ P2P_ATTR_STATUS = 0, -+ P2P_ATTR_MINOR_REASON_CODE = 1, -+ P2P_ATTR_CAPABILITY = 2, -+ P2P_ATTR_DEVICE_ID = 3, -+ P2P_ATTR_GROUP_OWNER_INTENT = 4, -+ P2P_ATTR_CONFIGURATION_TIMEOUT = 5, -+ P2P_ATTR_LISTEN_CHANNEL = 6, -+ P2P_ATTR_GROUP_BSSID = 7, -+ P2P_ATTR_EXT_LISTEN_TIMING = 8, -+ P2P_ATTR_INTENDED_INTERFACE_ADDR = 9, -+ P2P_ATTR_MANAGEABILITY = 10, -+ P2P_ATTR_CHANNEL_LIST = 11, -+ P2P_ATTR_NOTICE_OF_ABSENCE = 12, -+ P2P_ATTR_DEVICE_INFO = 13, -+ P2P_ATTR_GROUP_INFO = 14, -+ P2P_ATTR_GROUP_ID = 15, -+ P2P_ATTR_INTERFACE = 16, -+ P2P_ATTR_OPERATING_CHANNEL = 17, -+ P2P_ATTR_INVITATION_FLAGS = 18, -+ P2P_ATTR_VENDOR_SPECIFIC = 221 -+}; -+ -+#define P2P_MAX_GO_INTENT 15 -+ -+/* P2P Capability - Device Capability bitmap */ -+#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0) -+#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1) -+#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2) -+#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3) -+#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4) -+#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5) -+ -+/* P2P Capability - Group Capability bitmap */ -+#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0) -+#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1) -+#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2) -+#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3) -+#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4) -+#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5) -+#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6) -+ -+/* Invitation Flags */ -+#define P2P_INVITATION_FLAGS_TYPE BIT(0) -+ -+/* P2P Manageability */ -+#define P2P_MAN_DEVICE_MANAGEMENT BIT(0) -+#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1) -+#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2) -+ -+enum p2p_status_code { -+ P2P_SC_SUCCESS = 0, -+ P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1, -+ P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2, -+ P2P_SC_FAIL_LIMIT_REACHED = 3, -+ P2P_SC_FAIL_INVALID_PARAMS = 4, -+ P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5, -+ P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6, -+ P2P_SC_FAIL_NO_COMMON_CHANNELS = 7, -+ P2P_SC_FAIL_UNKNOWN_GROUP = 8, -+ P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9, -+ P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10, -+ P2P_SC_FAIL_REJECTED_BY_USER = 11, -+}; -+ -+#define P2P_WILDCARD_SSID "DIRECT-" -+#define P2P_WILDCARD_SSID_LEN 7 -+ -+/* P2P action frames */ -+enum p2p_act_frame_type { -+ P2P_NOA = 0, -+ P2P_PRESENCE_REQ = 1, -+ P2P_PRESENCE_RESP = 2, -+ P2P_GO_DISC_REQ = 3 -+}; -+ -+/* P2P public action frames */ -+enum p2p_action_frame_type { -+ P2P_GO_NEG_REQ = 0, -+ P2P_GO_NEG_RESP = 1, -+ P2P_GO_NEG_CONF = 2, -+ P2P_INVITATION_REQ = 3, -+ P2P_INVITATION_RESP = 4, -+ P2P_DEV_DISC_REQ = 5, -+ P2P_DEV_DISC_RESP = 6, -+ P2P_PROV_DISC_REQ = 7, -+ P2P_PROV_DISC_RESP = 8 -+}; -+ -+enum p2p_service_protocol_type { -+ P2P_SERV_ALL_SERVICES = 0, -+ P2P_SERV_BONJOUR = 1, -+ P2P_SERV_UPNP = 2, -+ P2P_SERV_WS_DISCOVERY = 3, -+ P2P_SERV_VENDOR_SPECIFIC = 255 -+}; -+ -+enum p2p_sd_status { -+ P2P_SD_SUCCESS = 0, -+ P2P_SD_PROTO_NOT_AVAILABLE = 1, -+ P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2, -+ P2P_SD_BAD_REQUEST = 3 -+}; -+ -+ -+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ -+ -+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ -+ -+/* cipher suite selectors */ -+#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 -+#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 -+#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 -+/* reserved: 0x000FAC03 */ -+#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 -+#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 -+#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 -+ -+/* AKM suite selectors */ -+#define WLAN_AKM_SUITE_8021X 0x000FAC01 -+#define WLAN_AKM_SUITE_PSK 0x000FAC02 -+ -+#endif /* IEEE802_11_DEFS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/privsep_commands.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/privsep_commands.h -new file mode 100644 -index 0000000000000..cc900be9d20ed ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/privsep_commands.h -@@ -0,0 +1,75 @@ -+/* -+ * WPA Supplicant - privilege separation commands -+ * Copyright (c) 2007-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PRIVSEP_COMMANDS_H -+#define PRIVSEP_COMMANDS_H -+ -+enum privsep_cmd { -+ PRIVSEP_CMD_REGISTER, -+ PRIVSEP_CMD_UNREGISTER, -+ PRIVSEP_CMD_SCAN, -+ PRIVSEP_CMD_GET_SCAN_RESULTS, -+ PRIVSEP_CMD_ASSOCIATE, -+ PRIVSEP_CMD_GET_BSSID, -+ PRIVSEP_CMD_GET_SSID, -+ PRIVSEP_CMD_SET_KEY, -+ PRIVSEP_CMD_GET_CAPA, -+ PRIVSEP_CMD_L2_REGISTER, -+ PRIVSEP_CMD_L2_UNREGISTER, -+ PRIVSEP_CMD_L2_NOTIFY_AUTH_START, -+ PRIVSEP_CMD_L2_SEND, -+ PRIVSEP_CMD_SET_COUNTRY, -+}; -+ -+struct privsep_cmd_associate -+{ -+ u8 bssid[ETH_ALEN]; -+ u8 ssid[32]; -+ size_t ssid_len; -+ int freq; -+ int pairwise_suite; -+ int group_suite; -+ int key_mgmt_suite; -+ int auth_alg; -+ int mode; -+ size_t wpa_ie_len; -+ /* followed by wpa_ie_len bytes of wpa_ie */ -+}; -+ -+struct privsep_cmd_set_key -+{ -+ int alg; -+ u8 addr[ETH_ALEN]; -+ int key_idx; -+ int set_tx; -+ u8 seq[8]; -+ size_t seq_len; -+ u8 key[32]; -+ size_t key_len; -+}; -+ -+enum privsep_event { -+ PRIVSEP_EVENT_SCAN_RESULTS, -+ PRIVSEP_EVENT_ASSOC, -+ PRIVSEP_EVENT_DISASSOC, -+ PRIVSEP_EVENT_ASSOCINFO, -+ PRIVSEP_EVENT_MICHAEL_MIC_FAILURE, -+ PRIVSEP_EVENT_INTERFACE_STATUS, -+ PRIVSEP_EVENT_PMKID_CANDIDATE, -+ PRIVSEP_EVENT_STKSTART, -+ PRIVSEP_EVENT_FT_RESPONSE, -+ PRIVSEP_EVENT_RX_EAPOL, -+}; -+ -+#endif /* PRIVSEP_COMMANDS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/version.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/version.h -new file mode 100644 -index 0000000000000..ba2d2c0321efa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/version.h -@@ -0,0 +1,10 @@ -+#ifndef VERSION_H -+#define VERSION_H -+ -+#ifndef VERSION_STR_POSTFIX -+#define VERSION_STR_POSTFIX "" -+#endif /* VERSION_STR_POSTFIX */ -+ -+#define VERSION_STR "0.8.x" VERSION_STR_POSTFIX -+ -+#endif /* VERSION_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.c -new file mode 100644 -index 0000000000000..eb2745e4e69f1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.c -@@ -0,0 +1,927 @@ -+/* -+ * WPA/RSN - Shared functions for supplicant and authenticator -+ * Copyright (c) 2002-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/md5.h" -+#include "crypto/sha1.h" -+#include "crypto/sha256.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/crypto.h" -+#include "ieee802_11_defs.h" -+#include "defs.h" -+#include "wpa_common.h" -+ -+ -+/** -+ * wpa_eapol_key_mic - Calculate EAPOL-Key MIC -+ * @key: EAPOL-Key Key Confirmation Key (KCK) -+ * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) -+ * @buf: Pointer to the beginning of the EAPOL header (version field) -+ * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) -+ * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written -+ * Returns: 0 on success, -1 on failure -+ * -+ * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has -+ * to be cleared (all zeroes) when calling this function. -+ * -+ * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the -+ * description of the Key MIC calculation. It includes packet data from the -+ * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change -+ * happened during final editing of the standard and the correct behavior is -+ * defined in the last draft (IEEE 802.11i/D10). -+ */ -+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, -+ u8 *mic) -+{ -+ u8 hash[SHA1_MAC_LEN]; -+ -+ switch (ver) { -+ case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: -+ return hmac_md5(key, 16, buf, len, mic); -+ case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: -+ if (hmac_sha1(key, 16, buf, len, hash)) -+ return -1; -+ os_memcpy(mic, hash, MD5_MAC_LEN); -+ break; -+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) -+ case WPA_KEY_INFO_TYPE_AES_128_CMAC: -+ return omac1_aes_128(key, buf, len, mic); -+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ -+ default: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces -+ * @pmk: Pairwise master key -+ * @pmk_len: Length of PMK -+ * @label: Label to use in derivation -+ * @addr1: AA or SA -+ * @addr2: SA or AA -+ * @nonce1: ANonce or SNonce -+ * @nonce2: SNonce or ANonce -+ * @ptk: Buffer for pairwise transient key -+ * @ptk_len: Length of PTK -+ * @use_sha256: Whether to use SHA256-based KDF -+ * -+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy -+ * PTK = PRF-X(PMK, "Pairwise key expansion", -+ * Min(AA, SA) || Max(AA, SA) || -+ * Min(ANonce, SNonce) || Max(ANonce, SNonce)) -+ * -+ * STK = PRF-X(SMK, "Peer key expansion", -+ * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) || -+ * Min(INonce, PNonce) || Max(INonce, PNonce)) -+ */ -+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, -+ const u8 *addr1, const u8 *addr2, -+ const u8 *nonce1, const u8 *nonce2, -+ u8 *ptk, size_t ptk_len, int use_sha256) -+{ -+ u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN]; -+ -+ if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) { -+ os_memcpy(data, addr1, ETH_ALEN); -+ os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN); -+ } else { -+ os_memcpy(data, addr2, ETH_ALEN); -+ os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN); -+ } -+ -+ if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) { -+ os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN); -+ os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2, -+ WPA_NONCE_LEN); -+ } else { -+ os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN); -+ os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1, -+ WPA_NONCE_LEN); -+ } -+ -+#ifdef CONFIG_IEEE80211W -+ if (use_sha256) -+ sha256_prf(pmk, pmk_len, label, data, sizeof(data), -+ ptk, ptk_len); -+ else -+#endif /* CONFIG_IEEE80211W */ -+ sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, -+ ptk_len); -+ -+ wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR, -+ MAC2STR(addr1), MAC2STR(addr2)); -+ wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len); -+ wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len); -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, -+ u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, -+ const u8 *ftie, size_t ftie_len, -+ const u8 *rsnie, size_t rsnie_len, -+ const u8 *ric, size_t ric_len, u8 *mic) -+{ -+ u8 *buf, *pos; -+ size_t buf_len; -+ -+ buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; -+ buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return -1; -+ -+ pos = buf; -+ os_memcpy(pos, sta_addr, ETH_ALEN); -+ pos += ETH_ALEN; -+ os_memcpy(pos, ap_addr, ETH_ALEN); -+ pos += ETH_ALEN; -+ *pos++ = transaction_seqnum; -+ if (rsnie) { -+ os_memcpy(pos, rsnie, rsnie_len); -+ pos += rsnie_len; -+ } -+ if (mdie) { -+ os_memcpy(pos, mdie, mdie_len); -+ pos += mdie_len; -+ } -+ if (ftie) { -+ struct rsn_ftie *_ftie; -+ os_memcpy(pos, ftie, ftie_len); -+ if (ftie_len < 2 + sizeof(*_ftie)) { -+ os_free(buf); -+ return -1; -+ } -+ _ftie = (struct rsn_ftie *) (pos + 2); -+ os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); -+ pos += ftie_len; -+ } -+ if (ric) { -+ os_memcpy(pos, ric, ric_len); -+ pos += ric_len; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); -+ if (omac1_aes_128(kck, buf, pos - buf, mic)) { -+ os_free(buf); -+ return -1; -+ } -+ -+ os_free(buf); -+ -+ return 0; -+} -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+#ifndef CONFIG_NO_WPA2 -+static int rsn_selector_to_bitfield(const u8 *s) -+{ -+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE) -+ return WPA_CIPHER_NONE; -+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40) -+ return WPA_CIPHER_WEP40; -+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP) -+ return WPA_CIPHER_TKIP; -+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP) -+ return WPA_CIPHER_CCMP; -+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104) -+ return WPA_CIPHER_WEP104; -+#ifdef CONFIG_IEEE80211W -+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC) -+ return WPA_CIPHER_AES_128_CMAC; -+#endif /* CONFIG_IEEE80211W */ -+ return 0; -+} -+ -+ -+static int rsn_key_mgmt_to_bitfield(const u8 *s) -+{ -+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X) -+ return WPA_KEY_MGMT_IEEE8021X; -+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X) -+ return WPA_KEY_MGMT_PSK; -+#ifdef CONFIG_IEEE80211R -+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X) -+ return WPA_KEY_MGMT_FT_IEEE8021X; -+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK) -+ return WPA_KEY_MGMT_FT_PSK; -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) -+ return WPA_KEY_MGMT_IEEE8021X_SHA256; -+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) -+ return WPA_KEY_MGMT_PSK_SHA256; -+#endif /* CONFIG_IEEE80211W */ -+ return 0; -+} -+#endif /* CONFIG_NO_WPA2 */ -+ -+ -+/** -+ * wpa_parse_wpa_ie_rsn - Parse RSN IE -+ * @rsn_ie: Buffer containing RSN IE -+ * @rsn_ie_len: RSN IE buffer length (including IE number and length octets) -+ * @data: Pointer to structure that will be filled in with parsed data -+ * Returns: 0 on success, <0 on failure -+ */ -+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, -+ struct wpa_ie_data *data) -+{ -+#ifndef CONFIG_NO_WPA2 -+ const struct rsn_ie_hdr *hdr; -+ const u8 *pos; -+ int left; -+ int i, count; -+ -+ os_memset(data, 0, sizeof(*data)); -+ data->proto = WPA_PROTO_RSN; -+ data->pairwise_cipher = WPA_CIPHER_CCMP; -+ data->group_cipher = WPA_CIPHER_CCMP; -+ data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; -+ data->capabilities = 0; -+ data->pmkid = NULL; -+ data->num_pmkid = 0; -+#ifdef CONFIG_IEEE80211W -+ data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; -+#else /* CONFIG_IEEE80211W */ -+ data->mgmt_group_cipher = 0; -+#endif /* CONFIG_IEEE80211W */ -+ -+ if (rsn_ie_len == 0) { -+ /* No RSN IE - fail silently */ -+ return -1; -+ } -+ -+ if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) { -+ wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", -+ __func__, (unsigned long) rsn_ie_len); -+ return -1; -+ } -+ -+ hdr = (const struct rsn_ie_hdr *) rsn_ie; -+ -+ if (hdr->elem_id != WLAN_EID_RSN || -+ hdr->len != rsn_ie_len - 2 || -+ WPA_GET_LE16(hdr->version) != RSN_VERSION) { -+ wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", -+ __func__); -+ return -2; -+ } -+ -+ pos = (const u8 *) (hdr + 1); -+ left = rsn_ie_len - sizeof(*hdr); -+ -+ if (left >= RSN_SELECTOR_LEN) { -+ data->group_cipher = rsn_selector_to_bitfield(pos); -+#ifdef CONFIG_IEEE80211W -+ if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { -+ wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " -+ "cipher", __func__); -+ return -1; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ pos += RSN_SELECTOR_LEN; -+ left -= RSN_SELECTOR_LEN; -+ } else if (left > 0) { -+ wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", -+ __func__, left); -+ return -3; -+ } -+ -+ if (left >= 2) { -+ data->pairwise_cipher = 0; -+ count = WPA_GET_LE16(pos); -+ pos += 2; -+ left -= 2; -+ if (count == 0 || left < count * RSN_SELECTOR_LEN) { -+ wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " -+ "count %u left %u", __func__, count, left); -+ return -4; -+ } -+ for (i = 0; i < count; i++) { -+ data->pairwise_cipher |= rsn_selector_to_bitfield(pos); -+ pos += RSN_SELECTOR_LEN; -+ left -= RSN_SELECTOR_LEN; -+ } -+#ifdef CONFIG_IEEE80211W -+ if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) { -+ wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as " -+ "pairwise cipher", __func__); -+ return -1; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ } else if (left == 1) { -+ wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", -+ __func__); -+ return -5; -+ } -+ -+ if (left >= 2) { -+ data->key_mgmt = 0; -+ count = WPA_GET_LE16(pos); -+ pos += 2; -+ left -= 2; -+ if (count == 0 || left < count * RSN_SELECTOR_LEN) { -+ wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " -+ "count %u left %u", __func__, count, left); -+ return -6; -+ } -+ for (i = 0; i < count; i++) { -+ data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos); -+ pos += RSN_SELECTOR_LEN; -+ left -= RSN_SELECTOR_LEN; -+ } -+ } else if (left == 1) { -+ wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", -+ __func__); -+ return -7; -+ } -+ -+ if (left >= 2) { -+ data->capabilities = WPA_GET_LE16(pos); -+ pos += 2; -+ left -= 2; -+ } -+ -+ if (left >= 2) { -+ data->num_pmkid = WPA_GET_LE16(pos); -+ pos += 2; -+ left -= 2; -+ if (left < (int) data->num_pmkid * PMKID_LEN) { -+ wpa_printf(MSG_DEBUG, "%s: PMKID underflow " -+ "(num_pmkid=%lu left=%d)", -+ __func__, (unsigned long) data->num_pmkid, -+ left); -+ data->num_pmkid = 0; -+ return -9; -+ } else { -+ data->pmkid = pos; -+ pos += data->num_pmkid * PMKID_LEN; -+ left -= data->num_pmkid * PMKID_LEN; -+ } -+ } -+ -+#ifdef CONFIG_IEEE80211W -+ if (left >= 4) { -+ data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); -+ if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { -+ wpa_printf(MSG_DEBUG, "%s: Unsupported management " -+ "group cipher 0x%x", __func__, -+ data->mgmt_group_cipher); -+ return -10; -+ } -+ pos += RSN_SELECTOR_LEN; -+ left -= RSN_SELECTOR_LEN; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ if (left > 0) { -+ wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", -+ __func__, left); -+ } -+ -+ return 0; -+#else /* CONFIG_NO_WPA2 */ -+ return -1; -+#endif /* CONFIG_NO_WPA2 */ -+} -+ -+ -+static int wpa_selector_to_bitfield(const u8 *s) -+{ -+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE) -+ return WPA_CIPHER_NONE; -+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40) -+ return WPA_CIPHER_WEP40; -+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP) -+ return WPA_CIPHER_TKIP; -+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP) -+ return WPA_CIPHER_CCMP; -+ if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104) -+ return WPA_CIPHER_WEP104; -+ return 0; -+} -+ -+ -+static int wpa_key_mgmt_to_bitfield(const u8 *s) -+{ -+ if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X) -+ return WPA_KEY_MGMT_IEEE8021X; -+ if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X) -+ return WPA_KEY_MGMT_PSK; -+ if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE) -+ return WPA_KEY_MGMT_WPA_NONE; -+ return 0; -+} -+ -+ -+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, -+ struct wpa_ie_data *data) -+{ -+ const struct wpa_ie_hdr *hdr; -+ const u8 *pos; -+ int left; -+ int i, count; -+ -+ os_memset(data, 0, sizeof(*data)); -+ data->proto = WPA_PROTO_WPA; -+ data->pairwise_cipher = WPA_CIPHER_TKIP; -+ data->group_cipher = WPA_CIPHER_TKIP; -+ data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; -+ data->capabilities = 0; -+ data->pmkid = NULL; -+ data->num_pmkid = 0; -+ data->mgmt_group_cipher = 0; -+ -+ if (wpa_ie_len == 0) { -+ /* No WPA IE - fail silently */ -+ return -1; -+ } -+ -+ if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { -+ wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", -+ __func__, (unsigned long) wpa_ie_len); -+ return -1; -+ } -+ -+ hdr = (const struct wpa_ie_hdr *) wpa_ie; -+ -+ if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || -+ hdr->len != wpa_ie_len - 2 || -+ RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || -+ WPA_GET_LE16(hdr->version) != WPA_VERSION) { -+ wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", -+ __func__); -+ return -2; -+ } -+ -+ pos = (const u8 *) (hdr + 1); -+ left = wpa_ie_len - sizeof(*hdr); -+ -+ if (left >= WPA_SELECTOR_LEN) { -+ data->group_cipher = wpa_selector_to_bitfield(pos); -+ pos += WPA_SELECTOR_LEN; -+ left -= WPA_SELECTOR_LEN; -+ } else if (left > 0) { -+ wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", -+ __func__, left); -+ return -3; -+ } -+ -+ if (left >= 2) { -+ data->pairwise_cipher = 0; -+ count = WPA_GET_LE16(pos); -+ pos += 2; -+ left -= 2; -+ if (count == 0 || left < count * WPA_SELECTOR_LEN) { -+ wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " -+ "count %u left %u", __func__, count, left); -+ return -4; -+ } -+ for (i = 0; i < count; i++) { -+ data->pairwise_cipher |= wpa_selector_to_bitfield(pos); -+ pos += WPA_SELECTOR_LEN; -+ left -= WPA_SELECTOR_LEN; -+ } -+ } else if (left == 1) { -+ wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", -+ __func__); -+ return -5; -+ } -+ -+ if (left >= 2) { -+ data->key_mgmt = 0; -+ count = WPA_GET_LE16(pos); -+ pos += 2; -+ left -= 2; -+ if (count == 0 || left < count * WPA_SELECTOR_LEN) { -+ wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " -+ "count %u left %u", __func__, count, left); -+ return -6; -+ } -+ for (i = 0; i < count; i++) { -+ data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); -+ pos += WPA_SELECTOR_LEN; -+ left -= WPA_SELECTOR_LEN; -+ } -+ } else if (left == 1) { -+ wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", -+ __func__); -+ return -7; -+ } -+ -+ if (left >= 2) { -+ data->capabilities = WPA_GET_LE16(pos); -+ pos += 2; -+ left -= 2; -+ } -+ -+ if (left > 0) { -+ wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", -+ __func__, left); -+ } -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+ -+/** -+ * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name -+ * -+ * IEEE Std 802.11r-2008 - 8.5.1.5.3 -+ */ -+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, -+ const u8 *ssid, size_t ssid_len, -+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, -+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name) -+{ -+ u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + -+ FT_R0KH_ID_MAX_LEN + ETH_ALEN]; -+ u8 *pos, r0_key_data[48], hash[32]; -+ const u8 *addr[2]; -+ size_t len[2]; -+ -+ /* -+ * R0-Key-Data = KDF-384(XXKey, "FT-R0", -+ * SSIDlength || SSID || MDID || R0KHlength || -+ * R0KH-ID || S0KH-ID) -+ * XXKey is either the second 256 bits of MSK or PSK. -+ * PMK-R0 = L(R0-Key-Data, 0, 256) -+ * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128) -+ */ -+ if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) -+ return; -+ pos = buf; -+ *pos++ = ssid_len; -+ os_memcpy(pos, ssid, ssid_len); -+ pos += ssid_len; -+ os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN); -+ pos += MOBILITY_DOMAIN_ID_LEN; -+ *pos++ = r0kh_id_len; -+ os_memcpy(pos, r0kh_id, r0kh_id_len); -+ pos += r0kh_id_len; -+ os_memcpy(pos, s0kh_id, ETH_ALEN); -+ pos += ETH_ALEN; -+ -+ sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, -+ r0_key_data, sizeof(r0_key_data)); -+ os_memcpy(pmk_r0, r0_key_data, PMK_LEN); -+ -+ /* -+ * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt) -+ */ -+ addr[0] = (const u8 *) "FT-R0N"; -+ len[0] = 6; -+ addr[1] = r0_key_data + PMK_LEN; -+ len[1] = 16; -+ -+ sha256_vector(2, addr, len, hash); -+ os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); -+} -+ -+ -+/** -+ * wpa_derive_pmk_r1_name - Derive PMKR1Name -+ * -+ * IEEE Std 802.11r-2008 - 8.5.1.5.4 -+ */ -+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, -+ const u8 *s1kh_id, u8 *pmk_r1_name) -+{ -+ u8 hash[32]; -+ const u8 *addr[4]; -+ size_t len[4]; -+ -+ /* -+ * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name || -+ * R1KH-ID || S1KH-ID)) -+ */ -+ addr[0] = (const u8 *) "FT-R1N"; -+ len[0] = 6; -+ addr[1] = pmk_r0_name; -+ len[1] = WPA_PMK_NAME_LEN; -+ addr[2] = r1kh_id; -+ len[2] = FT_R1KH_ID_LEN; -+ addr[3] = s1kh_id; -+ len[3] = ETH_ALEN; -+ -+ sha256_vector(4, addr, len, hash); -+ os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); -+} -+ -+ -+/** -+ * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0 -+ * -+ * IEEE Std 802.11r-2008 - 8.5.1.5.4 -+ */ -+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, -+ const u8 *r1kh_id, const u8 *s1kh_id, -+ u8 *pmk_r1, u8 *pmk_r1_name) -+{ -+ u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; -+ u8 *pos; -+ -+ /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ -+ pos = buf; -+ os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN); -+ pos += FT_R1KH_ID_LEN; -+ os_memcpy(pos, s1kh_id, ETH_ALEN); -+ pos += ETH_ALEN; -+ -+ sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN); -+ -+ wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name); -+} -+ -+ -+/** -+ * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1 -+ * -+ * IEEE Std 802.11r-2008 - 8.5.1.5.5 -+ */ -+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, -+ const u8 *sta_addr, const u8 *bssid, -+ const u8 *pmk_r1_name, -+ u8 *ptk, size_t ptk_len, u8 *ptk_name) -+{ -+ u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN]; -+ u8 *pos, hash[32]; -+ const u8 *addr[6]; -+ size_t len[6]; -+ -+ /* -+ * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || -+ * BSSID || STA-ADDR) -+ */ -+ pos = buf; -+ os_memcpy(pos, snonce, WPA_NONCE_LEN); -+ pos += WPA_NONCE_LEN; -+ os_memcpy(pos, anonce, WPA_NONCE_LEN); -+ pos += WPA_NONCE_LEN; -+ os_memcpy(pos, bssid, ETH_ALEN); -+ pos += ETH_ALEN; -+ os_memcpy(pos, sta_addr, ETH_ALEN); -+ pos += ETH_ALEN; -+ -+ sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len); -+ -+ /* -+ * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce || -+ * ANonce || BSSID || STA-ADDR)) -+ */ -+ addr[0] = pmk_r1_name; -+ len[0] = WPA_PMK_NAME_LEN; -+ addr[1] = (const u8 *) "FT-PTKN"; -+ len[1] = 7; -+ addr[2] = snonce; -+ len[2] = WPA_NONCE_LEN; -+ addr[3] = anonce; -+ len[3] = WPA_NONCE_LEN; -+ addr[4] = bssid; -+ len[4] = ETH_ALEN; -+ addr[5] = sta_addr; -+ len[5] = ETH_ALEN; -+ -+ sha256_vector(6, addr, len, hash); -+ os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); -+} -+ -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+/** -+ * rsn_pmkid - Calculate PMK identifier -+ * @pmk: Pairwise master key -+ * @pmk_len: Length of pmk in bytes -+ * @aa: Authenticator address -+ * @spa: Supplicant address -+ * @pmkid: Buffer for PMKID -+ * @use_sha256: Whether to use SHA256-based KDF -+ * -+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy -+ * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) -+ */ -+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, -+ u8 *pmkid, int use_sha256) -+{ -+ char *title = "PMK Name"; -+ const u8 *addr[3]; -+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; -+ unsigned char hash[SHA256_MAC_LEN]; -+ -+ addr[0] = (u8 *) title; -+ addr[1] = aa; -+ addr[2] = spa; -+ -+#ifdef CONFIG_IEEE80211W -+ if (use_sha256) -+ hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); -+ else -+#endif /* CONFIG_IEEE80211W */ -+ hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); -+ os_memcpy(pmkid, hash, PMKID_LEN); -+} -+ -+ -+/** -+ * wpa_cipher_txt - Convert cipher suite to a text string -+ * @cipher: Cipher suite (WPA_CIPHER_* enum) -+ * Returns: Pointer to a text string of the cipher suite name -+ */ -+const char * wpa_cipher_txt(int cipher) -+{ -+ switch (cipher) { -+ case WPA_CIPHER_NONE: -+ return "NONE"; -+ case WPA_CIPHER_WEP40: -+ return "WEP-40"; -+ case WPA_CIPHER_WEP104: -+ return "WEP-104"; -+ case WPA_CIPHER_TKIP: -+ return "TKIP"; -+ case WPA_CIPHER_CCMP: -+ return "CCMP"; -+ case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP: -+ return "CCMP+TKIP"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+ -+/** -+ * wpa_key_mgmt_txt - Convert key management suite to a text string -+ * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum) -+ * @proto: WPA/WPA2 version (WPA_PROTO_*) -+ * Returns: Pointer to a text string of the key management suite name -+ */ -+const char * wpa_key_mgmt_txt(int key_mgmt, int proto) -+{ -+ switch (key_mgmt) { -+ case WPA_KEY_MGMT_IEEE8021X: -+ if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) -+ return "WPA2+WPA/IEEE 802.1X/EAP"; -+ return proto == WPA_PROTO_RSN ? -+ "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP"; -+ case WPA_KEY_MGMT_PSK: -+ if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA)) -+ return "WPA2-PSK+WPA-PSK"; -+ return proto == WPA_PROTO_RSN ? -+ "WPA2-PSK" : "WPA-PSK"; -+ case WPA_KEY_MGMT_NONE: -+ return "NONE"; -+ case WPA_KEY_MGMT_IEEE8021X_NO_WPA: -+ return "IEEE 802.1X (no WPA)"; -+#ifdef CONFIG_IEEE80211R -+ case WPA_KEY_MGMT_FT_IEEE8021X: -+ return "FT-EAP"; -+ case WPA_KEY_MGMT_FT_PSK: -+ return "FT-PSK"; -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ case WPA_KEY_MGMT_IEEE8021X_SHA256: -+ return "WPA2-EAP-SHA256"; -+ case WPA_KEY_MGMT_PSK_SHA256: -+ return "WPA2-PSK-SHA256"; -+#endif /* CONFIG_IEEE80211W */ -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+ -+int wpa_compare_rsn_ie(int ft_initial_assoc, -+ const u8 *ie1, size_t ie1len, -+ const u8 *ie2, size_t ie2len) -+{ -+ if (ie1 == NULL || ie2 == NULL) -+ return -1; -+ -+ if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0) -+ return 0; /* identical IEs */ -+ -+#ifdef CONFIG_IEEE80211R -+ if (ft_initial_assoc) { -+ struct wpa_ie_data ie1d, ie2d; -+ /* -+ * The PMKID-List in RSN IE is different between Beacon/Probe -+ * Response/(Re)Association Request frames and EAPOL-Key -+ * messages in FT initial mobility domain association. Allow -+ * for this, but verify that other parts of the RSN IEs are -+ * identical. -+ */ -+ if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 || -+ wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0) -+ return -1; -+ if (ie1d.proto == ie2d.proto && -+ ie1d.pairwise_cipher == ie2d.pairwise_cipher && -+ ie1d.group_cipher == ie2d.group_cipher && -+ ie1d.key_mgmt == ie2d.key_mgmt && -+ ie1d.capabilities == ie2d.capabilities && -+ ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher) -+ return 0; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ return -1; -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) -+{ -+ u8 *start, *end, *rpos, *rend; -+ int added = 0; -+ -+ start = ies; -+ end = ies + ies_len; -+ -+ while (start < end) { -+ if (*start == WLAN_EID_RSN) -+ break; -+ start += 2 + start[1]; -+ } -+ if (start >= end) { -+ wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in " -+ "IEs data"); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification", -+ start, 2 + start[1]); -+ -+ /* Find start of PMKID-Count */ -+ rpos = start + 2; -+ rend = rpos + start[1]; -+ -+ /* Skip Version and Group Data Cipher Suite */ -+ rpos += 2 + 4; -+ /* Skip Pairwise Cipher Suite Count and List */ -+ rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; -+ /* Skip AKM Suite Count and List */ -+ rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN; -+ -+ if (rpos == rend) { -+ /* Add RSN Capabilities */ -+ os_memmove(rpos + 2, rpos, end - rpos); -+ *rpos++ = 0; -+ *rpos++ = 0; -+ } else { -+ /* Skip RSN Capabilities */ -+ rpos += 2; -+ if (rpos > rend) { -+ wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in " -+ "IEs data"); -+ return -1; -+ } -+ } -+ -+ if (rpos == rend) { -+ /* No PMKID-Count field included; add it */ -+ os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos); -+ WPA_PUT_LE16(rpos, 1); -+ rpos += 2; -+ os_memcpy(rpos, pmkid, PMKID_LEN); -+ added += 2 + PMKID_LEN; -+ start[1] += 2 + PMKID_LEN; -+ } else { -+ /* PMKID-Count was included; use it */ -+ if (WPA_GET_LE16(rpos) != 0) { -+ wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " -+ "in RSN IE in EAPOL-Key data"); -+ return -1; -+ } -+ WPA_PUT_LE16(rpos, 1); -+ rpos += 2; -+ os_memmove(rpos + PMKID_LEN, rpos, end - rpos); -+ os_memcpy(rpos, pmkid, PMKID_LEN); -+ added += PMKID_LEN; -+ start[1] += PMKID_LEN; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " -+ "(PMKID inserted)", start, 2 + start[1]); -+ -+ return added; -+} -+#endif /* CONFIG_IEEE80211R */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.h -new file mode 100644 -index 0000000000000..fe79cee114dd2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_common.h -@@ -0,0 +1,361 @@ -+/* -+ * WPA definitions shared between hostapd and wpa_supplicant -+ * Copyright (c) 2002-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_COMMON_H -+#define WPA_COMMON_H -+ -+#define WPA_MAX_SSID_LEN 32 -+ -+/* IEEE 802.11i */ -+#define PMKID_LEN 16 -+#define PMK_LEN 32 -+#define WPA_REPLAY_COUNTER_LEN 8 -+#define WPA_NONCE_LEN 32 -+#define WPA_KEY_RSC_LEN 8 -+#define WPA_GMK_LEN 32 -+#define WPA_GTK_MAX_LEN 32 -+ -+#define WPA_SELECTOR_LEN 4 -+#define WPA_VERSION 1 -+#define RSN_SELECTOR_LEN 4 -+#define RSN_VERSION 1 -+ -+#define RSN_SELECTOR(a, b, c, d) \ -+ ((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \ -+ (u32) (d)) -+ -+#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) -+#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1) -+#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2) -+#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0) -+#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1) -+#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2) -+#if 0 -+#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3) -+#endif -+#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4) -+#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5) -+ -+ -+#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1) -+#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -+#ifdef CONFIG_IEEE80211R -+#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3) -+#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4) -+#endif /* CONFIG_IEEE80211R */ -+#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) -+#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6) -+#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7) -+ -+#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0) -+#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1) -+#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -+#if 0 -+#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3) -+#endif -+#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) -+#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) -+#ifdef CONFIG_IEEE80211W -+#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) -+#endif /* CONFIG_IEEE80211W */ -+#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) -+ -+/* EAPOL-Key Key Data Encapsulation -+ * GroupKey and PeerKey require encryption, otherwise, encryption is optional. -+ */ -+#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1) -+#if 0 -+#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2) -+#endif -+#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3) -+#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4) -+#ifdef CONFIG_PEERKEY -+#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5) -+#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6) -+#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7) -+#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8) -+#endif /* CONFIG_PEERKEY */ -+#ifdef CONFIG_IEEE80211W -+#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9) -+#endif /* CONFIG_IEEE80211W */ -+ -+#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1) -+ -+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val)) -+#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a)) -+ -+#define RSN_NUM_REPLAY_COUNTERS_1 0 -+#define RSN_NUM_REPLAY_COUNTERS_2 1 -+#define RSN_NUM_REPLAY_COUNTERS_4 2 -+#define RSN_NUM_REPLAY_COUNTERS_16 3 -+ -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+#ifdef CONFIG_IEEE80211W -+#define WPA_IGTK_LEN 16 -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */ -+#define WPA_CAPABILITY_PREAUTH BIT(0) -+#define WPA_CAPABILITY_NO_PAIRWISE BIT(1) -+/* B2-B3: PTKSA Replay Counter */ -+/* B4-B5: GTKSA Replay Counter */ -+#define WPA_CAPABILITY_MFPR BIT(6) -+#define WPA_CAPABILITY_MFPC BIT(7) -+/* B8: Reserved */ -+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9) -+#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10) -+#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11) -+#define WPA_CAPABILITY_PBAC BIT(12) -+#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13) -+/* B14-B15: Reserved */ -+ -+ -+/* IEEE 802.11r */ -+#define MOBILITY_DOMAIN_ID_LEN 2 -+#define FT_R0KH_ID_MAX_LEN 48 -+#define FT_R1KH_ID_LEN 6 -+#define WPA_PMK_NAME_LEN 16 -+ -+ -+/* IEEE 802.11, 8.5.2 EAPOL-Key frames */ -+#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) -+#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) -+#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) -+#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3 -+#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ -+/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ -+#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5)) -+#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 -+#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ -+#define WPA_KEY_INFO_TXRX BIT(6) /* group */ -+#define WPA_KEY_INFO_ACK BIT(7) -+#define WPA_KEY_INFO_MIC BIT(8) -+#define WPA_KEY_INFO_SECURE BIT(9) -+#define WPA_KEY_INFO_ERROR BIT(10) -+#define WPA_KEY_INFO_REQUEST BIT(11) -+#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ -+#define WPA_KEY_INFO_SMK_MESSAGE BIT(13) -+ -+ -+struct wpa_eapol_key { -+ u8 type; -+ /* Note: key_info, key_length, and key_data_length are unaligned */ -+ u8 key_info[2]; /* big endian */ -+ u8 key_length[2]; /* big endian */ -+ u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; -+ u8 key_nonce[WPA_NONCE_LEN]; -+ u8 key_iv[16]; -+ u8 key_rsc[WPA_KEY_RSC_LEN]; -+ u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */ -+ u8 key_mic[16]; -+ u8 key_data_length[2]; /* big endian */ -+ /* followed by key_data_length bytes of key_data */ -+} STRUCT_PACKED; -+ -+/** -+ * struct wpa_ptk - WPA Pairwise Transient Key -+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy -+ */ -+struct wpa_ptk { -+ u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */ -+ u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */ -+ u8 tk1[16]; /* Temporal Key 1 (TK1) */ -+ union { -+ u8 tk2[16]; /* Temporal Key 2 (TK2) */ -+ struct { -+ u8 tx_mic_key[8]; -+ u8 rx_mic_key[8]; -+ } auth; -+ } u; -+} STRUCT_PACKED; -+ -+ -+/* WPA IE version 1 -+ * 00-50-f2:1 (OUI:OUI type) -+ * 0x01 0x00 (version; little endian) -+ * (all following fields are optional:) -+ * Group Suite Selector (4 octets) (default: TKIP) -+ * Pairwise Suite Count (2 octets, little endian) (default: 1) -+ * Pairwise Suite List (4 * n octets) (default: TKIP) -+ * Authenticated Key Management Suite Count (2 octets, little endian) -+ * (default: 1) -+ * Authenticated Key Management Suite List (4 * n octets) -+ * (default: unspec 802.1X) -+ * WPA Capabilities (2 octets, little endian) (default: 0) -+ */ -+ -+struct wpa_ie_hdr { -+ u8 elem_id; -+ u8 len; -+ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */ -+ u8 version[2]; /* little endian */ -+} STRUCT_PACKED; -+ -+ -+/* 1/4: PMKID -+ * 2/4: RSN IE -+ * 3/4: one or two RSN IEs + GTK IE (encrypted) -+ * 4/4: empty -+ * 1/2: GTK IE (encrypted) -+ * 2/2: empty -+ */ -+ -+/* RSN IE version 1 -+ * 0x01 0x00 (version; little endian) -+ * (all following fields are optional:) -+ * Group Suite Selector (4 octets) (default: CCMP) -+ * Pairwise Suite Count (2 octets, little endian) (default: 1) -+ * Pairwise Suite List (4 * n octets) (default: CCMP) -+ * Authenticated Key Management Suite Count (2 octets, little endian) -+ * (default: 1) -+ * Authenticated Key Management Suite List (4 * n octets) -+ * (default: unspec 802.1X) -+ * RSN Capabilities (2 octets, little endian) (default: 0) -+ * PMKID Count (2 octets) (default: 0) -+ * PMKID List (16 * n octets) -+ * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC) -+ */ -+ -+struct rsn_ie_hdr { -+ u8 elem_id; /* WLAN_EID_RSN */ -+ u8 len; -+ u8 version[2]; /* little endian */ -+} STRUCT_PACKED; -+ -+ -+#ifdef CONFIG_PEERKEY -+enum { -+ STK_MUI_4WAY_STA_AP = 1, -+ STK_MUI_4WAY_STAT_STA = 2, -+ STK_MUI_GTK = 3, -+ STK_MUI_SMK = 4 -+}; -+ -+enum { -+ STK_ERR_STA_NR = 1, -+ STK_ERR_STA_NRSN = 2, -+ STK_ERR_CPHR_NS = 3, -+ STK_ERR_NO_STSL = 4 -+}; -+#endif /* CONFIG_PEERKEY */ -+ -+struct rsn_error_kde { -+ be16 mui; -+ be16 error_type; -+} STRUCT_PACKED; -+ -+#ifdef CONFIG_IEEE80211W -+struct wpa_igtk_kde { -+ u8 keyid[2]; -+ u8 pn[6]; -+ u8 igtk[WPA_IGTK_LEN]; -+} STRUCT_PACKED; -+#endif /* CONFIG_IEEE80211W */ -+ -+#ifdef CONFIG_IEEE80211R -+struct rsn_mdie { -+ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; -+ u8 ft_capab; -+} STRUCT_PACKED; -+ -+#define RSN_FT_CAPAB_FT_OVER_DS BIT(0) -+#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1) -+ -+struct rsn_ftie { -+ u8 mic_control[2]; -+ u8 mic[16]; -+ u8 anonce[WPA_NONCE_LEN]; -+ u8 snonce[WPA_NONCE_LEN]; -+ /* followed by optional parameters */ -+} STRUCT_PACKED; -+ -+#define FTIE_SUBELEM_R1KH_ID 1 -+#define FTIE_SUBELEM_GTK 2 -+#define FTIE_SUBELEM_R0KH_ID 3 -+#define FTIE_SUBELEM_IGTK 4 -+ -+struct rsn_rdie { -+ u8 id; -+ u8 descr_count; -+ le16 status_code; -+} STRUCT_PACKED; -+ -+#endif /* CONFIG_IEEE80211R */ -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, -+ u8 *mic); -+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, -+ const u8 *addr1, const u8 *addr2, -+ const u8 *nonce1, const u8 *nonce2, -+ u8 *ptk, size_t ptk_len, int use_sha256); -+ -+#ifdef CONFIG_IEEE80211R -+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, -+ u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, -+ const u8 *ftie, size_t ftie_len, -+ const u8 *rsnie, size_t rsnie_len, -+ const u8 *ric, size_t ric_len, u8 *mic); -+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, -+ const u8 *ssid, size_t ssid_len, -+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, -+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name); -+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, -+ const u8 *s1kh_id, u8 *pmk_r1_name); -+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, -+ const u8 *r1kh_id, const u8 *s1kh_id, -+ u8 *pmk_r1, u8 *pmk_r1_name); -+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, -+ const u8 *sta_addr, const u8 *bssid, -+ const u8 *pmk_r1_name, -+ u8 *ptk, size_t ptk_len, u8 *ptk_name); -+#endif /* CONFIG_IEEE80211R */ -+ -+struct wpa_ie_data { -+ int proto; -+ int pairwise_cipher; -+ int group_cipher; -+ int key_mgmt; -+ int capabilities; -+ size_t num_pmkid; -+ const u8 *pmkid; -+ int mgmt_group_cipher; -+}; -+ -+ -+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, -+ struct wpa_ie_data *data); -+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, -+ struct wpa_ie_data *data); -+ -+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, -+ u8 *pmkid, int use_sha256); -+ -+const char * wpa_cipher_txt(int cipher); -+const char * wpa_key_mgmt_txt(int key_mgmt, int proto); -+int wpa_compare_rsn_ie(int ft_initial_assoc, -+ const u8 *ie1, size_t ie1len, -+ const u8 *ie2, size_t ie2len); -+int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid); -+ -+#endif /* WPA_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.c -new file mode 100644 -index 0000000000000..88d3a026484cb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.c -@@ -0,0 +1,500 @@ -+/* -+ * wpa_supplicant/hostapd control interface library -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#ifdef CONFIG_CTRL_IFACE -+ -+#ifdef CONFIG_CTRL_IFACE_UNIX -+#include -+#endif /* CONFIG_CTRL_IFACE_UNIX */ -+ -+#ifdef ANDROID -+#include -+#include "private/android_filesystem_config.h" -+#endif /* ANDROID */ -+ -+#include "wpa_ctrl.h" -+#include "common.h" -+ -+ -+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) -+#define CTRL_IFACE_SOCKET -+#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */ -+ -+ -+/** -+ * struct wpa_ctrl - Internal structure for control interface library -+ * -+ * This structure is used by the wpa_supplicant/hostapd control interface -+ * library to store internal data. Programs using the library should not touch -+ * this data directly. They can only use the pointer to the data structure as -+ * an identifier for the control interface connection and use this as one of -+ * the arguments for most of the control interface library functions. -+ */ -+struct wpa_ctrl { -+#ifdef CONFIG_CTRL_IFACE_UDP -+ int s; -+ struct sockaddr_in local; -+ struct sockaddr_in dest; -+ char *cookie; -+#endif /* CONFIG_CTRL_IFACE_UDP */ -+#ifdef CONFIG_CTRL_IFACE_UNIX -+ int s; -+ struct sockaddr_un local; -+ struct sockaddr_un dest; -+#endif /* CONFIG_CTRL_IFACE_UNIX */ -+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE -+ HANDLE pipe; -+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ -+}; -+ -+ -+#ifdef CONFIG_CTRL_IFACE_UNIX -+ -+#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR -+#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp" -+#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */ -+#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX -+#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_" -+#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */ -+ -+ -+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) -+{ -+ struct wpa_ctrl *ctrl; -+ static int counter = 0; -+ int ret; -+ size_t res; -+ int tries = 0; -+ -+ ctrl = os_malloc(sizeof(*ctrl)); -+ if (ctrl == NULL) -+ return NULL; -+ os_memset(ctrl, 0, sizeof(*ctrl)); -+ -+ ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (ctrl->s < 0) { -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ ctrl->local.sun_family = AF_UNIX; -+ counter++; -+try_again: -+ ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), -+ CONFIG_CTRL_IFACE_CLIENT_DIR "/" -+ CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", -+ (int) getpid(), counter); -+ if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) { -+ close(ctrl->s); -+ os_free(ctrl); -+ return NULL; -+ } -+ tries++; -+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, -+ sizeof(ctrl->local)) < 0) { -+ if (errno == EADDRINUSE && tries < 2) { -+ /* -+ * getpid() returns unique identifier for this instance -+ * of wpa_ctrl, so the existing socket file must have -+ * been left by unclean termination of an earlier run. -+ * Remove the file and try again. -+ */ -+ unlink(ctrl->local.sun_path); -+ goto try_again; -+ } -+ close(ctrl->s); -+ os_free(ctrl); -+ return NULL; -+ } -+ -+#ifdef ANDROID -+ chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); -+ chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI); -+ /* -+ * If the ctrl_path isn't an absolute pathname, assume that -+ * it's the name of a socket in the Android reserved namespace. -+ * Otherwise, it's a normal UNIX domain socket appearing in the -+ * filesystem. -+ */ -+ if (ctrl_path != NULL && *ctrl_path != '/') { -+ char buf[21]; -+ os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path); -+ if (socket_local_client_connect( -+ ctrl->s, buf, -+ ANDROID_SOCKET_NAMESPACE_RESERVED, -+ SOCK_DGRAM) < 0) { -+ close(ctrl->s); -+ unlink(ctrl->local.sun_path); -+ os_free(ctrl); -+ return NULL; -+ } -+ return ctrl; -+ } -+#endif /* ANDROID */ -+ -+ ctrl->dest.sun_family = AF_UNIX; -+ res = os_strlcpy(ctrl->dest.sun_path, ctrl_path, -+ sizeof(ctrl->dest.sun_path)); -+ if (res >= sizeof(ctrl->dest.sun_path)) { -+ close(ctrl->s); -+ os_free(ctrl); -+ return NULL; -+ } -+ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, -+ sizeof(ctrl->dest)) < 0) { -+ close(ctrl->s); -+ unlink(ctrl->local.sun_path); -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ return ctrl; -+} -+ -+ -+void wpa_ctrl_close(struct wpa_ctrl *ctrl) -+{ -+ if (ctrl == NULL) -+ return; -+ unlink(ctrl->local.sun_path); -+ if (ctrl->s >= 0) -+ close(ctrl->s); -+ os_free(ctrl); -+} -+ -+#endif /* CONFIG_CTRL_IFACE_UNIX */ -+ -+ -+#ifdef CONFIG_CTRL_IFACE_UDP -+ -+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) -+{ -+ struct wpa_ctrl *ctrl; -+ char buf[128]; -+ size_t len; -+ -+ ctrl = os_malloc(sizeof(*ctrl)); -+ if (ctrl == NULL) -+ return NULL; -+ os_memset(ctrl, 0, sizeof(*ctrl)); -+ -+ ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); -+ if (ctrl->s < 0) { -+ perror("socket"); -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ ctrl->local.sin_family = AF_INET; -+ ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); -+ if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, -+ sizeof(ctrl->local)) < 0) { -+ close(ctrl->s); -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ ctrl->dest.sin_family = AF_INET; -+ ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); -+ ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); -+ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, -+ sizeof(ctrl->dest)) < 0) { -+ perror("connect"); -+ close(ctrl->s); -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ len = sizeof(buf) - 1; -+ if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) { -+ buf[len] = '\0'; -+ ctrl->cookie = os_strdup(buf); -+ } -+ -+ return ctrl; -+} -+ -+ -+void wpa_ctrl_close(struct wpa_ctrl *ctrl) -+{ -+ close(ctrl->s); -+ os_free(ctrl->cookie); -+ os_free(ctrl); -+} -+ -+#endif /* CONFIG_CTRL_IFACE_UDP */ -+ -+ -+#ifdef CTRL_IFACE_SOCKET -+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, -+ char *reply, size_t *reply_len, -+ void (*msg_cb)(char *msg, size_t len)) -+{ -+ struct timeval tv; -+ int res; -+ fd_set rfds; -+ const char *_cmd; -+ char *cmd_buf = NULL; -+ size_t _cmd_len; -+ -+#ifdef CONFIG_CTRL_IFACE_UDP -+ if (ctrl->cookie) { -+ char *pos; -+ _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; -+ cmd_buf = os_malloc(_cmd_len); -+ if (cmd_buf == NULL) -+ return -1; -+ _cmd = cmd_buf; -+ pos = cmd_buf; -+ os_strlcpy(pos, ctrl->cookie, _cmd_len); -+ pos += os_strlen(ctrl->cookie); -+ *pos++ = ' '; -+ os_memcpy(pos, cmd, cmd_len); -+ } else -+#endif /* CONFIG_CTRL_IFACE_UDP */ -+ { -+ _cmd = cmd; -+ _cmd_len = cmd_len; -+ } -+ -+ if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { -+ os_free(cmd_buf); -+ return -1; -+ } -+ os_free(cmd_buf); -+ -+ for (;;) { -+ tv.tv_sec = 10; -+ tv.tv_usec = 0; -+ FD_ZERO(&rfds); -+ FD_SET(ctrl->s, &rfds); -+ res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); -+ if (res < 0) -+ return res; -+ if (FD_ISSET(ctrl->s, &rfds)) { -+ res = recv(ctrl->s, reply, *reply_len, 0); -+ if (res < 0) -+ return res; -+ if (res > 0 && reply[0] == '<') { -+ /* This is an unsolicited message from -+ * wpa_supplicant, not the reply to the -+ * request. Use msg_cb to report this to the -+ * caller. */ -+ if (msg_cb) { -+ /* Make sure the message is nul -+ * terminated. */ -+ if ((size_t) res == *reply_len) -+ res = (*reply_len) - 1; -+ reply[res] = '\0'; -+ msg_cb(reply, res); -+ } -+ continue; -+ } -+ *reply_len = res; -+ break; -+ } else { -+ return -2; -+ } -+ } -+ return 0; -+} -+#endif /* CTRL_IFACE_SOCKET */ -+ -+ -+static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) -+{ -+ char buf[10]; -+ int ret; -+ size_t len = 10; -+ -+ ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, -+ buf, &len, NULL); -+ if (ret < 0) -+ return ret; -+ if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0) -+ return 0; -+ return -1; -+} -+ -+ -+int wpa_ctrl_attach(struct wpa_ctrl *ctrl) -+{ -+ return wpa_ctrl_attach_helper(ctrl, 1); -+} -+ -+ -+int wpa_ctrl_detach(struct wpa_ctrl *ctrl) -+{ -+ return wpa_ctrl_attach_helper(ctrl, 0); -+} -+ -+ -+#ifdef CTRL_IFACE_SOCKET -+ -+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) -+{ -+ int res; -+ -+ res = recv(ctrl->s, reply, *reply_len, 0); -+ if (res < 0) -+ return res; -+ *reply_len = res; -+ return 0; -+} -+ -+ -+int wpa_ctrl_pending(struct wpa_ctrl *ctrl) -+{ -+ struct timeval tv; -+ fd_set rfds; -+ tv.tv_sec = 0; -+ tv.tv_usec = 0; -+ FD_ZERO(&rfds); -+ FD_SET(ctrl->s, &rfds); -+ select(ctrl->s + 1, &rfds, NULL, NULL, &tv); -+ return FD_ISSET(ctrl->s, &rfds); -+} -+ -+ -+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) -+{ -+ return ctrl->s; -+} -+ -+#endif /* CTRL_IFACE_SOCKET */ -+ -+ -+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE -+ -+#ifndef WPA_SUPPLICANT_NAMED_PIPE -+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant" -+#endif -+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE) -+ -+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) -+{ -+ struct wpa_ctrl *ctrl; -+ DWORD mode; -+ TCHAR name[256]; -+ int i, ret; -+ -+ ctrl = os_malloc(sizeof(*ctrl)); -+ if (ctrl == NULL) -+ return NULL; -+ os_memset(ctrl, 0, sizeof(*ctrl)); -+ -+#ifdef UNICODE -+ if (ctrl_path == NULL) -+ ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX); -+ else -+ ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"), -+ ctrl_path); -+#else /* UNICODE */ -+ if (ctrl_path == NULL) -+ ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX); -+ else -+ ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s", -+ ctrl_path); -+#endif /* UNICODE */ -+ if (ret < 0 || ret >= 256) { -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ for (i = 0; i < 10; i++) { -+ ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, -+ NULL, OPEN_EXISTING, 0, NULL); -+ /* -+ * Current named pipe server side in wpa_supplicant is -+ * re-opening the pipe for new clients only after the previous -+ * one is taken into use. This leaves a small window for race -+ * conditions when two connections are being opened at almost -+ * the same time. Retry if that was the case. -+ */ -+ if (ctrl->pipe != INVALID_HANDLE_VALUE || -+ GetLastError() != ERROR_PIPE_BUSY) -+ break; -+ WaitNamedPipe(name, 1000); -+ } -+ if (ctrl->pipe == INVALID_HANDLE_VALUE) { -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ mode = PIPE_READMODE_MESSAGE; -+ if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) { -+ CloseHandle(ctrl->pipe); -+ os_free(ctrl); -+ return NULL; -+ } -+ -+ return ctrl; -+} -+ -+ -+void wpa_ctrl_close(struct wpa_ctrl *ctrl) -+{ -+ CloseHandle(ctrl->pipe); -+ os_free(ctrl); -+} -+ -+ -+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, -+ char *reply, size_t *reply_len, -+ void (*msg_cb)(char *msg, size_t len)) -+{ -+ DWORD written; -+ DWORD readlen = *reply_len; -+ -+ if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL)) -+ return -1; -+ -+ if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL)) -+ return -1; -+ *reply_len = readlen; -+ -+ return 0; -+} -+ -+ -+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) -+{ -+ DWORD len = *reply_len; -+ if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL)) -+ return -1; -+ *reply_len = len; -+ return 0; -+} -+ -+ -+int wpa_ctrl_pending(struct wpa_ctrl *ctrl) -+{ -+ DWORD left; -+ -+ if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL)) -+ return -1; -+ return left ? 1 : 0; -+} -+ -+ -+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) -+{ -+ return -1; -+} -+ -+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ -+ -+#endif /* CONFIG_CTRL_IFACE */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.h -new file mode 100644 -index 0000000000000..528cc1602c519 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/common/wpa_ctrl.h -@@ -0,0 +1,274 @@ -+/* -+ * wpa_supplicant/hostapd control interface library -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_CTRL_H -+#define WPA_CTRL_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* wpa_supplicant control interface - fixed message prefixes */ -+ -+/** Interactive request for identity/password/pin */ -+#define WPA_CTRL_REQ "CTRL-REQ-" -+ -+/** Response to identity/password/pin request */ -+#define WPA_CTRL_RSP "CTRL-RSP-" -+ -+/* Event messages with fixed prefix */ -+/** Authentication completed successfully and data connection enabled */ -+#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED " -+/** Disconnected, data connection is not available */ -+#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED " -+/** Association rejected during connection attempt */ -+#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT " -+/** wpa_supplicant is exiting */ -+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " -+/** Password change was completed successfully */ -+#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED " -+/** EAP-Request/Notification received */ -+#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " -+/** EAP authentication started (EAP-Request/Identity received) */ -+#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " -+/** EAP method proposed by the server */ -+#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD " -+/** EAP method selected */ -+#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " -+/** EAP peer certificate from TLS */ -+#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT " -+/** EAP TLS certificate chain validation error */ -+#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR " -+/** EAP authentication completed successfully */ -+#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " -+/** EAP authentication failed (EAP-Failure received) */ -+#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " -+/** New scan results available */ -+#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " -+/** wpa_supplicant state change */ -+#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE " -+/** A new BSS entry was added (followed by BSS entry id and BSSID) */ -+#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED " -+/** A BSS entry was removed (followed by BSS entry id and BSSID) */ -+#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED " -+ -+/** WPS overlap detected in PBC mode */ -+#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED " -+/** Available WPS AP with active PBC found in scan results */ -+#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC " -+/** Available WPS AP with our address as authorized in scan results */ -+#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH " -+/** Available WPS AP with recently selected PIN registrar found in scan results -+ */ -+#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN " -+/** Available WPS AP found in scan results */ -+#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE " -+/** A new credential received */ -+#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED " -+/** M2D received */ -+#define WPS_EVENT_M2D "WPS-M2D " -+/** WPS registration failed after M2/M2D */ -+#define WPS_EVENT_FAIL "WPS-FAIL " -+/** WPS registration completed successfully */ -+#define WPS_EVENT_SUCCESS "WPS-SUCCESS " -+/** WPS enrollment attempt timed out and was terminated */ -+#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT " -+ -+#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN " -+ -+#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK " -+ -+/* WPS ER events */ -+#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD " -+#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE " -+#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD " -+#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE " -+#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS " -+#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG " -+ -+/** P2P device found */ -+#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND " -+/** A P2P device requested GO negotiation, but we were not ready to start the -+ * negotiation */ -+#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST " -+#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS " -+#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE " -+#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS " -+#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE " -+#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED " -+#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED " -+#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE " -+#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE " -+/* parameters: */ -+#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN " -+/* parameters: */ -+#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN " -+/* parameters: */ -+#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ " -+/* parameters: */ -+#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP " -+/* parameters: */ -+#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ " -+/* parameters: */ -+#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP " -+#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED " -+#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT " -+ -+/* hostapd control interface - fixed message prefixes */ -+#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED " -+#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS " -+#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS " -+#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED " -+#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED " -+#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED " -+#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED " -+#define AP_STA_CONNECTED "AP-STA-CONNECTED " -+#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED " -+ -+ -+/* wpa_supplicant/hostapd control interface access */ -+ -+/** -+ * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd -+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. -+ * Returns: Pointer to abstract control interface data or %NULL on failure -+ * -+ * This function is used to open a control interface to wpa_supplicant/hostapd. -+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path -+ * is configured in wpa_supplicant/hostapd and other programs using the control -+ * interface need to use matching path configuration. -+ */ -+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path); -+ -+ -+/** -+ * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd -+ * @ctrl: Control interface data from wpa_ctrl_open() -+ * -+ * This function is used to close a control interface. -+ */ -+void wpa_ctrl_close(struct wpa_ctrl *ctrl); -+ -+ -+/** -+ * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd -+ * @ctrl: Control interface data from wpa_ctrl_open() -+ * @cmd: Command; usually, ASCII text, e.g., "PING" -+ * @cmd_len: Length of the cmd in bytes -+ * @reply: Buffer for the response -+ * @reply_len: Reply buffer length -+ * @msg_cb: Callback function for unsolicited messages or %NULL if not used -+ * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout -+ * -+ * This function is used to send commands to wpa_supplicant/hostapd. Received -+ * response will be written to reply and reply_len is set to the actual length -+ * of the reply. This function will block for up to two seconds while waiting -+ * for the reply. If unsolicited messages are received, the blocking time may -+ * be longer. -+ * -+ * msg_cb can be used to register a callback function that will be called for -+ * unsolicited messages received while waiting for the command response. These -+ * messages may be received if wpa_ctrl_request() is called at the same time as -+ * wpa_supplicant/hostapd is sending such a message. This can happen only if -+ * the program has used wpa_ctrl_attach() to register itself as a monitor for -+ * event messages. Alternatively to msg_cb, programs can register two control -+ * interface connections and use one of them for commands and the other one for -+ * receiving event messages, in other words, call wpa_ctrl_attach() only for -+ * the control interface connection that will be used for event messages. -+ */ -+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, -+ char *reply, size_t *reply_len, -+ void (*msg_cb)(char *msg, size_t len)); -+ -+ -+/** -+ * wpa_ctrl_attach - Register as an event monitor for the control interface -+ * @ctrl: Control interface data from wpa_ctrl_open() -+ * Returns: 0 on success, -1 on failure, -2 on timeout -+ * -+ * This function registers the control interface connection as a monitor for -+ * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the -+ * control interface connection starts receiving event messages that can be -+ * read with wpa_ctrl_recv(). -+ */ -+int wpa_ctrl_attach(struct wpa_ctrl *ctrl); -+ -+ -+/** -+ * wpa_ctrl_detach - Unregister event monitor from the control interface -+ * @ctrl: Control interface data from wpa_ctrl_open() -+ * Returns: 0 on success, -1 on failure, -2 on timeout -+ * -+ * This function unregisters the control interface connection as a monitor for -+ * wpa_supplicant/hostapd events, i.e., cancels the registration done with -+ * wpa_ctrl_attach(). -+ */ -+int wpa_ctrl_detach(struct wpa_ctrl *ctrl); -+ -+ -+/** -+ * wpa_ctrl_recv - Receive a pending control interface message -+ * @ctrl: Control interface data from wpa_ctrl_open() -+ * @reply: Buffer for the message data -+ * @reply_len: Length of the reply buffer -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function will receive a pending control interface message. This -+ * function will block if no messages are available. The received response will -+ * be written to reply and reply_len is set to the actual length of the reply. -+ * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach() -+ * must have been used to register the control interface as an event monitor. -+ */ -+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); -+ -+ -+/** -+ * wpa_ctrl_pending - Check whether there are pending event messages -+ * @ctrl: Control interface data from wpa_ctrl_open() -+ * Returns: 1 if there are pending messages, 0 if no, or -1 on error -+ * -+ * This function will check whether there are any pending control interface -+ * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is -+ * only used for event messages, i.e., wpa_ctrl_attach() must have been used to -+ * register the control interface as an event monitor. -+ */ -+int wpa_ctrl_pending(struct wpa_ctrl *ctrl); -+ -+ -+/** -+ * wpa_ctrl_get_fd - Get file descriptor used by the control interface -+ * @ctrl: Control interface data from wpa_ctrl_open() -+ * Returns: File descriptor used for the connection -+ * -+ * This function can be used to get the file descriptor that is used for the -+ * control interface connection. The returned value can be used, e.g., with -+ * select() while waiting for multiple events. -+ * -+ * The returned file descriptor must not be used directly for sending or -+ * receiving packets; instead, the library functions wpa_ctrl_request() and -+ * wpa_ctrl_recv() must be used for this. -+ */ -+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); -+ -+#ifdef CONFIG_CTRL_IFACE_UDP -+#define WPA_CTRL_IFACE_PORT 9877 -+#define WPA_GLOBAL_CTRL_IFACE_PORT 9878 -+#endif /* CONFIG_CTRL_IFACE_UDP */ -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* WPA_CTRL_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/.gitignore b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/.gitignore -new file mode 100644 -index 0000000000000..ee606048c4179 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/.gitignore -@@ -0,0 +1 @@ -+libcrypto.a -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/Makefile -new file mode 100644 -index 0000000000000..69aa16ac66b0c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/Makefile -@@ -0,0 +1,56 @@ -+all: libcrypto.a -+ -+clean: -+ rm -f *~ *.o *.d libcrypto.a -+ -+install: -+ @echo Nothing to be made. -+ -+ -+include ../lib.rules -+ -+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT -+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER -+#CFLAGS += -DALL_DH_GROUPS -+ -+LIB_OBJS= \ -+ aes-cbc.o \ -+ aes-ctr.o \ -+ aes-eax.o \ -+ aes-encblock.o \ -+ aes-internal.o \ -+ aes-internal-dec.o \ -+ aes-internal-enc.o \ -+ aes-omac1.o \ -+ aes-unwrap.o \ -+ aes-wrap.o \ -+ des-internal.o \ -+ dh_group5.o \ -+ dh_groups.o \ -+ md4-internal.o \ -+ md5.o \ -+ md5-internal.o \ -+ md5-non-fips.o \ -+ milenage.o \ -+ ms_funcs.o \ -+ rc4.o \ -+ sha1.o \ -+ sha1-internal.o \ -+ sha1-pbkdf2.o \ -+ sha1-tlsprf.o \ -+ sha1-tprf.o \ -+ sha256.o \ -+ sha256-internal.o -+ -+LIB_OBJS += crypto_internal.o -+LIB_OBJS += crypto_internal-cipher.o -+LIB_OBJS += crypto_internal-modexp.o -+LIB_OBJS += crypto_internal-rsa.o -+LIB_OBJS += tls_internal.o -+LIB_OBJS += fips_prf_internal.o -+ -+ -+libcrypto.a: $(LIB_OBJS) -+ $(AR) crT $@ $? -+ -+-include $(OBJS:%.o=%.d) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-cbc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-cbc.c -new file mode 100644 -index 0000000000000..bd74769905e14 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-cbc.c -@@ -0,0 +1,86 @@ -+/* -+ * AES-128 CBC -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "aes.h" -+#include "aes_wrap.h" -+ -+/** -+ * aes_128_cbc_encrypt - AES-128 CBC encryption -+ * @key: Encryption key -+ * @iv: Encryption IV for CBC mode (16 bytes) -+ * @data: Data to encrypt in-place -+ * @data_len: Length of data in bytes (must be divisible by 16) -+ * Returns: 0 on success, -1 on failure -+ */ -+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) -+{ -+ void *ctx; -+ u8 cbc[AES_BLOCK_SIZE]; -+ u8 *pos = data; -+ int i, j, blocks; -+ -+ ctx = aes_encrypt_init(key, 16); -+ if (ctx == NULL) -+ return -1; -+ os_memcpy(cbc, iv, AES_BLOCK_SIZE); -+ -+ blocks = data_len / AES_BLOCK_SIZE; -+ for (i = 0; i < blocks; i++) { -+ for (j = 0; j < AES_BLOCK_SIZE; j++) -+ cbc[j] ^= pos[j]; -+ aes_encrypt(ctx, cbc, cbc); -+ os_memcpy(pos, cbc, AES_BLOCK_SIZE); -+ pos += AES_BLOCK_SIZE; -+ } -+ aes_encrypt_deinit(ctx); -+ return 0; -+} -+ -+ -+/** -+ * aes_128_cbc_decrypt - AES-128 CBC decryption -+ * @key: Decryption key -+ * @iv: Decryption IV for CBC mode (16 bytes) -+ * @data: Data to decrypt in-place -+ * @data_len: Length of data in bytes (must be divisible by 16) -+ * Returns: 0 on success, -1 on failure -+ */ -+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) -+{ -+ void *ctx; -+ u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; -+ u8 *pos = data; -+ int i, j, blocks; -+ -+ ctx = aes_decrypt_init(key, 16); -+ if (ctx == NULL) -+ return -1; -+ os_memcpy(cbc, iv, AES_BLOCK_SIZE); -+ -+ blocks = data_len / AES_BLOCK_SIZE; -+ for (i = 0; i < blocks; i++) { -+ os_memcpy(tmp, pos, AES_BLOCK_SIZE); -+ aes_decrypt(ctx, pos, pos); -+ for (j = 0; j < AES_BLOCK_SIZE; j++) -+ pos[j] ^= cbc[j]; -+ os_memcpy(cbc, tmp, AES_BLOCK_SIZE); -+ pos += AES_BLOCK_SIZE; -+ } -+ aes_decrypt_deinit(ctx); -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-ctr.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-ctr.c -new file mode 100644 -index 0000000000000..468f877411997 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-ctr.c -@@ -0,0 +1,61 @@ -+/* -+ * AES-128 CTR -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "aes.h" -+#include "aes_wrap.h" -+ -+/** -+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption -+ * @key: Key for encryption (16 bytes) -+ * @nonce: Nonce for counter mode (16 bytes) -+ * @data: Data to encrypt in-place -+ * @data_len: Length of data in bytes -+ * Returns: 0 on success, -1 on failure -+ */ -+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, -+ u8 *data, size_t data_len) -+{ -+ void *ctx; -+ size_t j, len, left = data_len; -+ int i; -+ u8 *pos = data; -+ u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE]; -+ -+ ctx = aes_encrypt_init(key, 16); -+ if (ctx == NULL) -+ return -1; -+ os_memcpy(counter, nonce, AES_BLOCK_SIZE); -+ -+ while (left > 0) { -+ aes_encrypt(ctx, counter, buf); -+ -+ len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE; -+ for (j = 0; j < len; j++) -+ pos[j] ^= buf[j]; -+ pos += len; -+ left -= len; -+ -+ for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) { -+ counter[i]++; -+ if (counter[i]) -+ break; -+ } -+ } -+ aes_encrypt_deinit(ctx); -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-eax.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-eax.c -new file mode 100644 -index 0000000000000..d5c397151d2e2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-eax.c -@@ -0,0 +1,151 @@ -+/* -+ * AES-128 EAX -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "aes.h" -+#include "aes_wrap.h" -+ -+/** -+ * aes_128_eax_encrypt - AES-128 EAX mode encryption -+ * @key: Key for encryption (16 bytes) -+ * @nonce: Nonce for counter mode -+ * @nonce_len: Nonce length in bytes -+ * @hdr: Header data to be authenticity protected -+ * @hdr_len: Length of the header data bytes -+ * @data: Data to encrypt in-place -+ * @data_len: Length of data in bytes -+ * @tag: 16-byte tag value -+ * Returns: 0 on success, -1 on failure -+ */ -+int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, -+ const u8 *hdr, size_t hdr_len, -+ u8 *data, size_t data_len, u8 *tag) -+{ -+ u8 *buf; -+ size_t buf_len; -+ u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], -+ data_mac[AES_BLOCK_SIZE]; -+ int i, ret = -1; -+ -+ if (nonce_len > data_len) -+ buf_len = nonce_len; -+ else -+ buf_len = data_len; -+ if (hdr_len > buf_len) -+ buf_len = hdr_len; -+ buf_len += 16; -+ -+ buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return -1; -+ -+ os_memset(buf, 0, 15); -+ -+ buf[15] = 0; -+ os_memcpy(buf + 16, nonce, nonce_len); -+ if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) -+ goto fail; -+ -+ buf[15] = 1; -+ os_memcpy(buf + 16, hdr, hdr_len); -+ if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) -+ goto fail; -+ -+ if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len)) -+ goto fail; -+ buf[15] = 2; -+ os_memcpy(buf + 16, data, data_len); -+ if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) -+ goto fail; -+ -+ for (i = 0; i < AES_BLOCK_SIZE; i++) -+ tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]; -+ -+ ret = 0; -+fail: -+ os_free(buf); -+ -+ return ret; -+} -+ -+ -+/** -+ * aes_128_eax_decrypt - AES-128 EAX mode decryption -+ * @key: Key for decryption (16 bytes) -+ * @nonce: Nonce for counter mode -+ * @nonce_len: Nonce length in bytes -+ * @hdr: Header data to be authenticity protected -+ * @hdr_len: Length of the header data bytes -+ * @data: Data to encrypt in-place -+ * @data_len: Length of data in bytes -+ * @tag: 16-byte tag value -+ * Returns: 0 on success, -1 on failure, -2 if tag does not match -+ */ -+int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, -+ const u8 *hdr, size_t hdr_len, -+ u8 *data, size_t data_len, const u8 *tag) -+{ -+ u8 *buf; -+ size_t buf_len; -+ u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], -+ data_mac[AES_BLOCK_SIZE]; -+ int i; -+ -+ if (nonce_len > data_len) -+ buf_len = nonce_len; -+ else -+ buf_len = data_len; -+ if (hdr_len > buf_len) -+ buf_len = hdr_len; -+ buf_len += 16; -+ -+ buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return -1; -+ -+ os_memset(buf, 0, 15); -+ -+ buf[15] = 0; -+ os_memcpy(buf + 16, nonce, nonce_len); -+ if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) { -+ os_free(buf); -+ return -1; -+ } -+ -+ buf[15] = 1; -+ os_memcpy(buf + 16, hdr, hdr_len); -+ if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) { -+ os_free(buf); -+ return -1; -+ } -+ -+ buf[15] = 2; -+ os_memcpy(buf + 16, data, data_len); -+ if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) { -+ os_free(buf); -+ return -1; -+ } -+ -+ os_free(buf); -+ -+ for (i = 0; i < AES_BLOCK_SIZE; i++) { -+ if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i])) -+ return -2; -+ } -+ -+ return aes_128_ctr_encrypt(key, nonce_mac, data, data_len); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-encblock.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-encblock.c -new file mode 100644 -index 0000000000000..8f35caa221e25 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-encblock.c -@@ -0,0 +1,38 @@ -+/* -+ * AES encrypt_block -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "aes.h" -+#include "aes_wrap.h" -+ -+/** -+ * aes_128_encrypt_block - Perform one AES 128-bit block operation -+ * @key: Key for AES -+ * @in: Input data (16 bytes) -+ * @out: Output of the AES block operation (16 bytes) -+ * Returns: 0 on success, -1 on failure -+ */ -+int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) -+{ -+ void *ctx; -+ ctx = aes_encrypt_init(key, 16); -+ if (ctx == NULL) -+ return -1; -+ aes_encrypt(ctx, in, out); -+ aes_encrypt_deinit(ctx); -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-dec.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-dec.c -new file mode 100644 -index 0000000000000..2d32c03fbf4cb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-dec.c -@@ -0,0 +1,151 @@ -+/* -+ * AES (Rijndael) cipher - decrypt -+ * -+ * Modifications to public domain implementation: -+ * - support only 128-bit keys -+ * - cleanup -+ * - use C pre-processor to make it easier to change S table access -+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at -+ * cost of reduced throughput (quite small difference on Pentium 4, -+ * 10-25% when using -O1 or -O2 optimization) -+ * -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "aes_i.h" -+ -+/** -+ * Expand the cipher key into the decryption key schedule. -+ * -+ * @return the number of rounds for the given cipher key size. -+ */ -+void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[]) -+{ -+ int Nr = 10, i, j; -+ u32 temp; -+ -+ /* expand the cipher key: */ -+ rijndaelKeySetupEnc(rk, cipherKey); -+ /* 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; -+ for (j = 0; j < 4; j++) { -+ rk[j] = TD0_(TE4((rk[j] >> 24) )) ^ -+ TD1_(TE4((rk[j] >> 16) & 0xff)) ^ -+ TD2_(TE4((rk[j] >> 8) & 0xff)) ^ -+ TD3_(TE4((rk[j] ) & 0xff)); -+ } -+ } -+} -+ -+void * aes_decrypt_init(const u8 *key, size_t len) -+{ -+ u32 *rk; -+ if (len != 16) -+ return NULL; -+ rk = os_malloc(AES_PRIV_SIZE); -+ if (rk == NULL) -+ return NULL; -+ rijndaelKeySetupDec(rk, key); -+ return rk; -+} -+ -+static void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16]) -+{ -+ u32 s0, s1, s2, s3, t0, t1, t2, t3; -+ const int Nr = 10; -+#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]; -+ -+#define ROUND(i,d,s) \ -+d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \ -+d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \ -+d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \ -+d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3] -+ -+#ifdef FULL_UNROLL -+ -+ ROUND(1,t,s); -+ ROUND(2,s,t); -+ ROUND(3,t,s); -+ ROUND(4,s,t); -+ ROUND(5,t,s); -+ ROUND(6,s,t); -+ ROUND(7,t,s); -+ ROUND(8,s,t); -+ ROUND(9,t,s); -+ -+ rk += Nr << 2; -+ -+#else /* !FULL_UNROLL */ -+ -+ /* Nr - 1 full rounds: */ -+ r = Nr >> 1; -+ for (;;) { -+ ROUND(1,t,s); -+ rk += 8; -+ if (--r == 0) -+ break; -+ ROUND(0,s,t); -+ } -+ -+#endif /* ?FULL_UNROLL */ -+ -+#undef ROUND -+ -+ /* -+ * apply last round and -+ * map cipher state to byte array block: -+ */ -+ s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0]; -+ PUTU32(pt , s0); -+ s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1]; -+ PUTU32(pt + 4, s1); -+ s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2]; -+ PUTU32(pt + 8, s2); -+ s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3]; -+ PUTU32(pt + 12, s3); -+} -+ -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -+{ -+ rijndaelDecrypt(ctx, crypt, plain); -+} -+ -+ -+void aes_decrypt_deinit(void *ctx) -+{ -+ os_memset(ctx, 0, AES_PRIV_SIZE); -+ os_free(ctx); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-enc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-enc.c -new file mode 100644 -index 0000000000000..2f198263bb84a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal-enc.c -@@ -0,0 +1,121 @@ -+/* -+ * AES (Rijndael) cipher - encrypt -+ * -+ * Modifications to public domain implementation: -+ * - support only 128-bit keys -+ * - cleanup -+ * - use C pre-processor to make it easier to change S table access -+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at -+ * cost of reduced throughput (quite small difference on Pentium 4, -+ * 10-25% when using -O1 or -O2 optimization) -+ * -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "aes_i.h" -+ -+void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16]) -+{ -+ u32 s0, s1, s2, s3, t0, t1, t2, t3; -+ const int Nr = 10; -+#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]; -+ -+#define ROUND(i,d,s) \ -+d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ -+d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ -+d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ -+d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] -+ -+#ifdef FULL_UNROLL -+ -+ ROUND(1,t,s); -+ ROUND(2,s,t); -+ ROUND(3,t,s); -+ ROUND(4,s,t); -+ ROUND(5,t,s); -+ ROUND(6,s,t); -+ ROUND(7,t,s); -+ ROUND(8,s,t); -+ ROUND(9,t,s); -+ -+ rk += Nr << 2; -+ -+#else /* !FULL_UNROLL */ -+ -+ /* Nr - 1 full rounds: */ -+ r = Nr >> 1; -+ for (;;) { -+ ROUND(1,t,s); -+ rk += 8; -+ if (--r == 0) -+ break; -+ ROUND(0,s,t); -+ } -+ -+#endif /* ?FULL_UNROLL */ -+ -+#undef ROUND -+ -+ /* -+ * apply last round and -+ * map cipher state to byte array block: -+ */ -+ s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; -+ PUTU32(ct , s0); -+ s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; -+ PUTU32(ct + 4, s1); -+ s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; -+ PUTU32(ct + 8, s2); -+ s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; -+ PUTU32(ct + 12, s3); -+} -+ -+ -+void * aes_encrypt_init(const u8 *key, size_t len) -+{ -+ u32 *rk; -+ if (len != 16) -+ return NULL; -+ rk = os_malloc(AES_PRIV_SIZE); -+ if (rk == NULL) -+ return NULL; -+ rijndaelKeySetupEnc(rk, key); -+ return rk; -+} -+ -+ -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -+{ -+ rijndaelEncrypt(ctx, plain, crypt); -+} -+ -+ -+void aes_encrypt_deinit(void *ctx) -+{ -+ os_memset(ctx, 0, AES_PRIV_SIZE); -+ os_free(ctx); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal.c -new file mode 100644 -index 0000000000000..4161220220665 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-internal.c -@@ -0,0 +1,805 @@ -+/* -+ * AES (Rijndael) cipher -+ * -+ * Modifications to public domain implementation: -+ * - support only 128-bit keys -+ * - cleanup -+ * - use C pre-processor to make it easier to change S table access -+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at -+ * cost of reduced throughput (quite small difference on Pentium 4, -+ * 10-25% when using -O1 or -O2 optimization) -+ * -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "aes_i.h" -+ -+/* -+ * 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. -+ */ -+ -+ -+/* -+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]; -+Te4[x] = S [x].[01, 01, 01, 01]; -+ -+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, 01, 01, 01]; -+*/ -+ -+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, -+}; -+#ifndef AES_SMALL_TABLES -+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, -+}; -+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, -+}; -+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, -+}; -+const u32 Te4[256] = { -+ 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, -+ 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, -+ 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, -+ 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, -+ 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, -+ 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, -+ 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, -+ 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, -+ 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, -+ 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, -+ 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, -+ 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, -+ 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, -+ 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, -+ 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, -+ 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, -+ 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, -+ 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, -+ 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, -+ 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, -+ 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, -+ 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, -+ 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, -+ 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, -+ 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, -+ 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, -+ 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, -+ 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, -+ 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, -+ 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, -+ 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, -+ 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, -+ 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, -+ 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, -+ 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, -+ 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, -+ 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, -+ 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, -+ 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, -+ 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, -+ 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, -+ 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, -+ 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, -+ 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, -+ 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, -+ 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, -+ 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, -+ 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, -+ 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, -+ 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, -+ 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, -+ 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, -+ 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, -+ 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, -+ 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, -+ 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, -+ 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, -+ 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, -+ 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, -+ 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, -+ 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, -+ 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, -+ 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, -+ 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, -+}; -+#endif /* AES_SMALL_TABLES */ -+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, -+}; -+#ifndef AES_SMALL_TABLES -+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, -+}; -+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, -+}; -+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, -+}; -+const u32 Td4[256] = { -+ 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, -+ 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, -+ 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, -+ 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, -+ 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, -+ 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, -+ 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, -+ 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, -+ 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, -+ 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, -+ 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, -+ 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, -+ 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, -+ 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, -+ 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, -+ 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, -+ 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, -+ 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, -+ 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, -+ 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, -+ 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, -+ 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, -+ 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, -+ 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, -+ 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, -+ 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, -+ 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, -+ 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, -+ 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, -+ 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, -+ 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, -+ 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, -+ 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, -+ 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, -+ 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, -+ 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, -+ 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, -+ 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, -+ 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, -+ 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, -+ 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, -+ 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, -+ 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, -+ 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, -+ 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, -+ 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, -+ 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, -+ 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, -+ 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, -+ 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, -+ 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, -+ 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, -+ 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, -+ 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, -+ 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, -+ 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, -+ 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, -+ 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, -+ 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, -+ 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, -+ 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, -+ 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, -+ 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, -+ 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, -+}; -+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 */ -+}; -+#else /* AES_SMALL_TABLES */ -+const u8 Td4s[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, -+}; -+const u8 rcons[] = { -+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 -+ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -+}; -+#endif /* AES_SMALL_TABLES */ -+/** -+ * Expand the cipher key into the encryption key schedule. -+ * -+ * @return the number of rounds for the given cipher key size. -+ */ -+void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]) -+{ -+ int i; -+ u32 temp; -+ -+ rk[0] = GETU32(cipherKey ); -+ rk[1] = GETU32(cipherKey + 4); -+ rk[2] = GETU32(cipherKey + 8); -+ rk[3] = GETU32(cipherKey + 12); -+ for (i = 0; i < 10; i++) { -+ temp = rk[3]; -+ rk[4] = rk[0] ^ -+ TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^ -+ RCON(i); -+ rk[5] = rk[1] ^ rk[4]; -+ rk[6] = rk[2] ^ rk[5]; -+ rk[7] = rk[3] ^ rk[6]; -+ rk += 4; -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-omac1.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-omac1.c -new file mode 100644 -index 0000000000000..f77529617a31c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-omac1.c -@@ -0,0 +1,124 @@ -+/* -+ * One-key CBC MAC (OMAC1) hash with AES-128 -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "aes.h" -+#include "aes_wrap.h" -+ -+static void gf_mulx(u8 *pad) -+{ -+ int i, carry; -+ -+ carry = pad[0] & 0x80; -+ for (i = 0; i < AES_BLOCK_SIZE - 1; i++) -+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); -+ pad[AES_BLOCK_SIZE - 1] <<= 1; -+ if (carry) -+ pad[AES_BLOCK_SIZE - 1] ^= 0x87; -+} -+ -+ -+/** -+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 -+ * @key: 128-bit key for the hash operation -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is a mode for using block cipher (AES in this case) for authentication. -+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication -+ * (SP) 800-38B. -+ */ -+int omac1_aes_128_vector(const u8 *key, size_t num_elem, -+ const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ void *ctx; -+ u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; -+ const u8 *pos, *end; -+ size_t i, e, left, total_len; -+ -+ ctx = aes_encrypt_init(key, 16); -+ if (ctx == NULL) -+ return -1; -+ os_memset(cbc, 0, AES_BLOCK_SIZE); -+ -+ total_len = 0; -+ for (e = 0; e < num_elem; e++) -+ total_len += len[e]; -+ left = total_len; -+ -+ e = 0; -+ pos = addr[0]; -+ end = pos + len[0]; -+ -+ while (left >= AES_BLOCK_SIZE) { -+ for (i = 0; i < AES_BLOCK_SIZE; i++) { -+ cbc[i] ^= *pos++; -+ if (pos >= end) { -+ e++; -+ pos = addr[e]; -+ end = pos + len[e]; -+ } -+ } -+ if (left > AES_BLOCK_SIZE) -+ aes_encrypt(ctx, cbc, cbc); -+ left -= AES_BLOCK_SIZE; -+ } -+ -+ os_memset(pad, 0, AES_BLOCK_SIZE); -+ aes_encrypt(ctx, pad, pad); -+ gf_mulx(pad); -+ -+ if (left || total_len == 0) { -+ for (i = 0; i < left; i++) { -+ cbc[i] ^= *pos++; -+ if (pos >= end) { -+ e++; -+ pos = addr[e]; -+ end = pos + len[e]; -+ } -+ } -+ cbc[left] ^= 0x80; -+ gf_mulx(pad); -+ } -+ -+ for (i = 0; i < AES_BLOCK_SIZE; i++) -+ pad[i] ^= cbc[i]; -+ aes_encrypt(ctx, pad, mac); -+ aes_encrypt_deinit(ctx); -+ return 0; -+} -+ -+ -+/** -+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) -+ * @key: 128-bit key for the hash operation -+ * @data: Data buffer for which a MAC is determined -+ * @data_len: Length of data buffer in bytes -+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is a mode for using block cipher (AES in this case) for authentication. -+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication -+ * (SP) 800-38B. -+ */ -+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) -+{ -+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-unwrap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-unwrap.c -new file mode 100644 -index 0000000000000..f233ffa4c04cd ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-unwrap.c -@@ -0,0 +1,79 @@ -+/* -+ * AES key unwrap (128-bit KEK, RFC3394) -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "aes.h" -+#include "aes_wrap.h" -+ -+/** -+ * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) -+ * @kek: Key encryption key (KEK) -+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 -+ * bytes -+ * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits -+ * @plain: Plaintext key, n * 64 bits -+ * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) -+ */ -+int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) -+{ -+ u8 a[8], *r, b[16]; -+ int i, j; -+ void *ctx; -+ -+ /* 1) Initialize variables. */ -+ os_memcpy(a, cipher, 8); -+ r = plain; -+ os_memcpy(r, cipher + 8, 8 * n); -+ -+ ctx = aes_decrypt_init(kek, 16); -+ if (ctx == NULL) -+ return -1; -+ -+ /* 2) Compute intermediate values. -+ * For j = 5 to 0 -+ * For i = n to 1 -+ * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i -+ * A = MSB(64, B) -+ * R[i] = LSB(64, B) -+ */ -+ for (j = 5; j >= 0; j--) { -+ r = plain + (n - 1) * 8; -+ for (i = n; i >= 1; i--) { -+ os_memcpy(b, a, 8); -+ b[7] ^= n * j + i; -+ -+ os_memcpy(b + 8, r, 8); -+ aes_decrypt(ctx, b, b); -+ os_memcpy(a, b, 8); -+ os_memcpy(r, b + 8, 8); -+ r -= 8; -+ } -+ } -+ aes_decrypt_deinit(ctx); -+ -+ /* 3) Output results. -+ * -+ * These are already in @plain due to the location of temporary -+ * variables. Just verify that the IV matches with the expected value. -+ */ -+ for (i = 0; i < 8; i++) { -+ if (a[i] != 0xa6) -+ return -1; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-wrap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-wrap.c -new file mode 100644 -index 0000000000000..28d0c89e88f01 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes-wrap.c -@@ -0,0 +1,76 @@ -+/* -+ * AES Key Wrap Algorithm (128-bit KEK) (RFC3394) -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "aes.h" -+#include "aes_wrap.h" -+ -+/** -+ * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) -+ * @kek: 16-octet Key encryption key (KEK) -+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 -+ * bytes -+ * @plain: Plaintext key to be wrapped, n * 64 bits -+ * @cipher: Wrapped key, (n + 1) * 64 bits -+ * Returns: 0 on success, -1 on failure -+ */ -+int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) -+{ -+ u8 *a, *r, b[16]; -+ int i, j; -+ void *ctx; -+ -+ a = cipher; -+ r = cipher + 8; -+ -+ /* 1) Initialize variables. */ -+ os_memset(a, 0xa6, 8); -+ os_memcpy(r, plain, 8 * n); -+ -+ ctx = aes_encrypt_init(kek, 16); -+ if (ctx == NULL) -+ return -1; -+ -+ /* 2) Calculate intermediate values. -+ * For j = 0 to 5 -+ * For i=1 to n -+ * B = AES(K, A | R[i]) -+ * A = MSB(64, B) ^ t where t = (n*j)+i -+ * R[i] = LSB(64, B) -+ */ -+ for (j = 0; j <= 5; j++) { -+ r = cipher + 8; -+ for (i = 1; i <= n; i++) { -+ os_memcpy(b, a, 8); -+ os_memcpy(b + 8, r, 8); -+ aes_encrypt(ctx, b, b); -+ os_memcpy(a, b, 8); -+ a[7] ^= n * j + i; -+ os_memcpy(r, b + 8, 8); -+ r += 8; -+ } -+ } -+ aes_encrypt_deinit(ctx); -+ -+ /* 3) Output the results. -+ * -+ * These are already in @cipher due to the location of temporary -+ * variables. -+ */ -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes.h -new file mode 100644 -index 0000000000000..ba384a9dae374 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes.h -@@ -0,0 +1,27 @@ -+/* -+ * AES functions -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef AES_H -+#define AES_H -+ -+#define AES_BLOCK_SIZE 16 -+ -+void * aes_encrypt_init(const u8 *key, size_t len); -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); -+void aes_encrypt_deinit(void *ctx); -+void * aes_decrypt_init(const u8 *key, size_t len); -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); -+void aes_decrypt_deinit(void *ctx); -+ -+#endif /* AES_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_i.h -new file mode 100644 -index 0000000000000..6b40bc7816516 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_i.h -@@ -0,0 +1,122 @@ -+/* -+ * AES (Rijndael) cipher -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef AES_I_H -+#define AES_I_H -+ -+#include "aes.h" -+ -+/* #define FULL_UNROLL */ -+#define AES_SMALL_TABLES -+ -+extern const u32 Te0[256]; -+extern const u32 Te1[256]; -+extern const u32 Te2[256]; -+extern const u32 Te3[256]; -+extern const u32 Te4[256]; -+extern const u32 Td0[256]; -+extern const u32 Td1[256]; -+extern const u32 Td2[256]; -+extern const u32 Td3[256]; -+extern const u32 Td4[256]; -+extern const u32 rcon[10]; -+extern const u8 Td4s[256]; -+extern const u8 rcons[10]; -+ -+#ifndef AES_SMALL_TABLES -+ -+#define RCON(i) rcon[(i)] -+ -+#define TE0(i) Te0[((i) >> 24) & 0xff] -+#define TE1(i) Te1[((i) >> 16) & 0xff] -+#define TE2(i) Te2[((i) >> 8) & 0xff] -+#define TE3(i) Te3[(i) & 0xff] -+#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) -+#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) -+#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) -+#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) -+#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) -+#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) -+#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) -+#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) -+#define TE4(i) (Te4[(i)] & 0x000000ff) -+ -+#define TD0(i) Td0[((i) >> 24) & 0xff] -+#define TD1(i) Td1[((i) >> 16) & 0xff] -+#define TD2(i) Td2[((i) >> 8) & 0xff] -+#define TD3(i) Td3[(i) & 0xff] -+#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) -+#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) -+#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) -+#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) -+#define TD0_(i) Td0[(i) & 0xff] -+#define TD1_(i) Td1[(i) & 0xff] -+#define TD2_(i) Td2[(i) & 0xff] -+#define TD3_(i) Td3[(i) & 0xff] -+ -+#else /* AES_SMALL_TABLES */ -+ -+#define RCON(i) (rcons[(i)] << 24) -+ -+static inline u32 rotr(u32 val, int bits) -+{ -+ return (val >> bits) | (val << (32 - bits)); -+} -+ -+#define TE0(i) Te0[((i) >> 24) & 0xff] -+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) -+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) -+#define TE3(i) rotr(Te0[(i) & 0xff], 24) -+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) -+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) -+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) -+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) -+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) -+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) -+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) -+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) -+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) -+ -+#define TD0(i) Td0[((i) >> 24) & 0xff] -+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) -+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) -+#define TD3(i) rotr(Td0[(i) & 0xff], 24) -+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) -+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) -+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) -+#define TD44(i) (Td4s[(i) & 0xff]) -+#define TD0_(i) Td0[(i) & 0xff] -+#define TD1_(i) rotr(Td0[(i) & 0xff], 8) -+#define TD2_(i) rotr(Td0[(i) & 0xff], 16) -+#define TD3_(i) rotr(Td0[(i) & 0xff], 24) -+ -+#endif /* AES_SMALL_TABLES */ -+ -+#ifdef _MSC_VER -+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) -+#define GETU32(p) SWAP(*((u32 *)(p))) -+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } -+#else -+#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); } -+#endif -+ -+#define AES_PRIV_SIZE (4 * 44) -+ -+void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]); -+ -+#endif /* AES_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_wrap.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_wrap.h -new file mode 100644 -index 0000000000000..4b1c7b083b334 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/aes_wrap.h -@@ -0,0 +1,48 @@ -+/* -+ * AES-based functions -+ * -+ * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) -+ * - One-Key CBC MAC (OMAC1) hash with AES-128 -+ * - AES-128 CTR mode encryption -+ * - AES-128 EAX mode encryption/decryption -+ * - AES-128 CBC -+ * -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef AES_WRAP_H -+#define AES_WRAP_H -+ -+int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); -+int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); -+int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, -+ const u8 *addr[], const size_t *len, -+ u8 *mac); -+int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, -+ u8 *mac); -+int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); -+int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, -+ u8 *data, size_t data_len); -+int __must_check aes_128_eax_encrypt(const u8 *key, -+ const u8 *nonce, size_t nonce_len, -+ const u8 *hdr, size_t hdr_len, -+ u8 *data, size_t data_len, u8 *tag); -+int __must_check aes_128_eax_decrypt(const u8 *key, -+ const u8 *nonce, size_t nonce_len, -+ const u8 *hdr, size_t hdr_len, -+ u8 *data, size_t data_len, const u8 *tag); -+int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, -+ size_t data_len); -+int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, -+ size_t data_len); -+ -+#endif /* AES_WRAP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto.h -new file mode 100644 -index 0000000000000..587b5a95747fc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto.h -@@ -0,0 +1,469 @@ -+/* -+ * WPA Supplicant / wrapper functions for crypto libraries -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file defines the cryptographic functions that need to be implemented -+ * for wpa_supplicant and hostapd. When TLS is not used, internal -+ * implementation of MD5, SHA1, and AES is used and no external libraries are -+ * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the -+ * crypto library used by the TLS implementation is expected to be used for -+ * non-TLS needs, too, in order to save space by not implementing these -+ * functions twice. -+ * -+ * Wrapper code for using each crypto library is in its own file (crypto*.c) -+ * and one of these files is build and linked in to provide the functions -+ * defined here. -+ */ -+ -+#ifndef CRYPTO_H -+#define CRYPTO_H -+ -+/** -+ * md4_vector - MD4 hash for data vector -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 on failure -+ */ -+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); -+ -+/** -+ * md5_vector - MD5 hash for data vector -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 on failure -+ */ -+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); -+ -+#ifdef CONFIG_FIPS -+/** -+ * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed) -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 on failure -+ */ -+int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], -+ const size_t *len, u8 *mac); -+#else /* CONFIG_FIPS */ -+#define md5_vector_non_fips_allow md5_vector -+#endif /* CONFIG_FIPS */ -+ -+ -+/** -+ * sha1_vector - SHA-1 hash for data vector -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 on failure -+ */ -+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *mac); -+ -+/** -+ * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF -+ * @seed: Seed/key for the PRF -+ * @seed_len: Seed length in bytes -+ * @x: Buffer for PRF output -+ * @xlen: Output length in bytes -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function implements random number generation specified in NIST FIPS -+ * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to -+ * SHA-1, but has different message padding. -+ */ -+int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, -+ size_t xlen); -+ -+/** -+ * sha256_vector - SHA256 hash for data vector -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 on failure -+ */ -+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *mac); -+ -+/** -+ * des_encrypt - Encrypt one block with DES -+ * @clear: 8 octets (in) -+ * @key: 7 octets (in) (no parity bits included) -+ * @cypher: 8 octets (out) -+ */ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher); -+ -+/** -+ * aes_encrypt_init - Initialize AES for encryption -+ * @key: Encryption key -+ * @len: Key length in bytes (usually 16, i.e., 128 bits) -+ * Returns: Pointer to context data or %NULL on failure -+ */ -+void * aes_encrypt_init(const u8 *key, size_t len); -+ -+/** -+ * aes_encrypt - Encrypt one AES block -+ * @ctx: Context pointer from aes_encrypt_init() -+ * @plain: Plaintext data to be encrypted (16 bytes) -+ * @crypt: Buffer for the encrypted data (16 bytes) -+ */ -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); -+ -+/** -+ * aes_encrypt_deinit - Deinitialize AES encryption -+ * @ctx: Context pointer from aes_encrypt_init() -+ */ -+void aes_encrypt_deinit(void *ctx); -+ -+/** -+ * aes_decrypt_init - Initialize AES for decryption -+ * @key: Decryption key -+ * @len: Key length in bytes (usually 16, i.e., 128 bits) -+ * Returns: Pointer to context data or %NULL on failure -+ */ -+void * aes_decrypt_init(const u8 *key, size_t len); -+ -+/** -+ * aes_decrypt - Decrypt one AES block -+ * @ctx: Context pointer from aes_encrypt_init() -+ * @crypt: Encrypted data (16 bytes) -+ * @plain: Buffer for the decrypted data (16 bytes) -+ */ -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); -+ -+/** -+ * aes_decrypt_deinit - Deinitialize AES decryption -+ * @ctx: Context pointer from aes_encrypt_init() -+ */ -+void aes_decrypt_deinit(void *ctx); -+ -+ -+enum crypto_hash_alg { -+ CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1, -+ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1 -+}; -+ -+struct crypto_hash; -+ -+/** -+ * crypto_hash_init - Initialize hash/HMAC function -+ * @alg: Hash algorithm -+ * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed -+ * @key_len: Length of the key in bytes -+ * Returns: Pointer to hash context to use with other hash functions or %NULL -+ * on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, -+ size_t key_len); -+ -+/** -+ * crypto_hash_update - Add data to hash calculation -+ * @ctx: Context pointer from crypto_hash_init() -+ * @data: Data buffer to add -+ * @len: Length of the buffer -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len); -+ -+/** -+ * crypto_hash_finish - Complete hash calculation -+ * @ctx: Context pointer from crypto_hash_init() -+ * @hash: Buffer for hash value or %NULL if caller is just freeing the hash -+ * context -+ * @len: Pointer to length of the buffer or %NULL if caller is just freeing the -+ * hash context; on return, this is set to the actual length of the hash value -+ * Returns: 0 on success, -1 if buffer is too small (len set to needed length), -+ * or -2 on other failures (including failed crypto_hash_update() operations) -+ * -+ * This function calculates the hash value and frees the context buffer that -+ * was used for hash calculation. -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len); -+ -+ -+enum crypto_cipher_alg { -+ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES, -+ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4 -+}; -+ -+struct crypto_cipher; -+ -+/** -+ * crypto_cipher_init - Initialize block/stream cipher function -+ * @alg: Cipher algorithm -+ * @iv: Initialization vector for block ciphers or %NULL for stream ciphers -+ * @key: Cipher key -+ * @key_len: Length of key in bytes -+ * Returns: Pointer to cipher context to use with other cipher functions or -+ * %NULL on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, -+ const u8 *iv, const u8 *key, -+ size_t key_len); -+ -+/** -+ * crypto_cipher_encrypt - Cipher encrypt -+ * @ctx: Context pointer from crypto_cipher_init() -+ * @plain: Plaintext to cipher -+ * @crypt: Resulting ciphertext -+ * @len: Length of the plaintext -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx, -+ const u8 *plain, u8 *crypt, size_t len); -+ -+/** -+ * crypto_cipher_decrypt - Cipher decrypt -+ * @ctx: Context pointer from crypto_cipher_init() -+ * @crypt: Ciphertext to decrypt -+ * @plain: Resulting plaintext -+ * @len: Length of the cipher text -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx, -+ const u8 *crypt, u8 *plain, size_t len); -+ -+/** -+ * crypto_cipher_decrypt - Free cipher context -+ * @ctx: Context pointer from crypto_cipher_init() -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+void crypto_cipher_deinit(struct crypto_cipher *ctx); -+ -+ -+struct crypto_public_key; -+struct crypto_private_key; -+ -+/** -+ * crypto_public_key_import - Import an RSA public key -+ * @key: Key buffer (DER encoded RSA public key) -+ * @len: Key buffer length in bytes -+ * Returns: Pointer to the public key or %NULL on failure -+ * -+ * This function can just return %NULL if the crypto library supports X.509 -+ * parsing. In that case, crypto_public_key_from_cert() is used to import the -+ * public key from a certificate. -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); -+ -+/** -+ * crypto_private_key_import - Import an RSA private key -+ * @key: Key buffer (DER encoded RSA private key) -+ * @len: Key buffer length in bytes -+ * @passwd: Key encryption password or %NULL if key is not encrypted -+ * Returns: Pointer to the private key or %NULL on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+struct crypto_private_key * crypto_private_key_import(const u8 *key, -+ size_t len, -+ const char *passwd); -+ -+/** -+ * crypto_public_key_from_cert - Import an RSA public key from a certificate -+ * @buf: DER encoded X.509 certificate -+ * @len: Certificate buffer length in bytes -+ * Returns: Pointer to public key or %NULL on failure -+ * -+ * This function can just return %NULL if the crypto library does not support -+ * X.509 parsing. In that case, internal code will be used to parse the -+ * certificate and public key is imported using crypto_public_key_import(). -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, -+ size_t len); -+ -+/** -+ * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5) -+ * @key: Public key -+ * @in: Plaintext buffer -+ * @inlen: Length of plaintext buffer in bytes -+ * @out: Output buffer for encrypted data -+ * @outlen: Length of output buffer in bytes; set to used length on success -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int __must_check crypto_public_key_encrypt_pkcs1_v15( -+ struct crypto_public_key *key, const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen); -+ -+/** -+ * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5) -+ * @key: Private key -+ * @in: Encrypted buffer -+ * @inlen: Length of encrypted buffer in bytes -+ * @out: Output buffer for encrypted data -+ * @outlen: Length of output buffer in bytes; set to used length on success -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int __must_check crypto_private_key_decrypt_pkcs1_v15( -+ struct crypto_private_key *key, const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen); -+ -+/** -+ * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1) -+ * @key: Private key from crypto_private_key_import() -+ * @in: Plaintext buffer -+ * @inlen: Length of plaintext buffer in bytes -+ * @out: Output buffer for encrypted (signed) data -+ * @outlen: Length of output buffer in bytes; set to used length on success -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen); -+ -+/** -+ * crypto_public_key_free - Free public key -+ * @key: Public key -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+void crypto_public_key_free(struct crypto_public_key *key); -+ -+/** -+ * crypto_private_key_free - Free private key -+ * @key: Private key from crypto_private_key_import() -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+void crypto_private_key_free(struct crypto_private_key *key); -+ -+/** -+ * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature -+ * @key: Public key -+ * @crypt: Encrypted signature data (using the private key) -+ * @crypt_len: Encrypted signature data length -+ * @plain: Buffer for plaintext (at least crypt_len bytes) -+ * @plain_len: Plaintext length (max buffer size on input, real len on output); -+ * Returns: 0 on success, -1 on failure -+ */ -+int __must_check crypto_public_key_decrypt_pkcs1( -+ struct crypto_public_key *key, const u8 *crypt, size_t crypt_len, -+ u8 *plain, size_t *plain_len); -+ -+/** -+ * crypto_global_init - Initialize crypto wrapper -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int __must_check crypto_global_init(void); -+ -+/** -+ * crypto_global_deinit - Deinitialize crypto wrapper -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+void crypto_global_deinit(void); -+ -+/** -+ * crypto_mod_exp - Modular exponentiation of large integers -+ * @base: Base integer (big endian byte array) -+ * @base_len: Length of base integer in bytes -+ * @power: Power integer (big endian byte array) -+ * @power_len: Length of power integer in bytes -+ * @modulus: Modulus integer (big endian byte array) -+ * @modulus_len: Length of modulus integer in bytes -+ * @result: Buffer for the result -+ * @result_len: Result length (max buffer size on input, real len on output) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function calculates result = base ^ power mod modulus. modules_len is -+ * used as the maximum size of modulus buffer. It is set to the used size on -+ * success. -+ * -+ * This function is only used with internal TLSv1 implementation -+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need -+ * to implement this. -+ */ -+int __must_check crypto_mod_exp(const u8 *base, size_t base_len, -+ const u8 *power, size_t power_len, -+ const u8 *modulus, size_t modulus_len, -+ u8 *result, size_t *result_len); -+ -+/** -+ * rc4_skip - XOR RC4 stream to given data with skip-stream-start -+ * @key: RC4 key -+ * @keylen: RC4 key length -+ * @skip: number of bytes to skip from the beginning of the RC4 stream -+ * @data: data to be XOR'ed with RC4 stream -+ * @data_len: buf length -+ * Returns: 0 on success, -1 on failure -+ * -+ * Generate RC4 pseudo random stream for the given key, skip beginning of the -+ * stream, and XOR the end result with the data buffer to perform RC4 -+ * encryption/decryption. -+ */ -+int rc4_skip(const u8 *key, size_t keylen, size_t skip, -+ u8 *data, size_t data_len); -+ -+#endif /* CRYPTO_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_cryptoapi.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_cryptoapi.c -new file mode 100644 -index 0000000000000..2a8d2001b1732 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_cryptoapi.c -@@ -0,0 +1,789 @@ -+/* -+ * Crypto wrapper for Microsoft CryptoAPI -+ * Copyright (c) 2005-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+ -+#include "common.h" -+#include "crypto.h" -+ -+#ifndef MS_ENH_RSA_AES_PROV -+#ifdef UNICODE -+#define MS_ENH_RSA_AES_PROV \ -+L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" -+#else -+#define MS_ENH_RSA_AES_PROV \ -+"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" -+#endif -+#endif /* MS_ENH_RSA_AES_PROV */ -+ -+#ifndef CALG_HMAC -+#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) -+#endif -+ -+#ifdef __MINGW32_VERSION -+/* -+ * MinGW does not yet include all the needed definitions for CryptoAPI, so -+ * define here whatever extra is needed. -+ */ -+ -+static BOOL WINAPI -+(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType, -+ PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey) -+= NULL; /* to be loaded from crypt32.dll */ -+ -+ -+static int mingw_load_crypto_func(void) -+{ -+ HINSTANCE dll; -+ -+ /* MinGW does not yet have full CryptoAPI support, so load the needed -+ * function here. */ -+ -+ if (CryptImportPublicKeyInfo) -+ return 0; -+ -+ dll = LoadLibrary("crypt32"); -+ if (dll == NULL) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 " -+ "library"); -+ return -1; -+ } -+ -+ CryptImportPublicKeyInfo = GetProcAddress( -+ dll, "CryptImportPublicKeyInfo"); -+ if (CryptImportPublicKeyInfo == NULL) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get " -+ "CryptImportPublicKeyInfo() address from " -+ "crypt32 library"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+#else /* __MINGW32_VERSION */ -+ -+static int mingw_load_crypto_func(void) -+{ -+ return 0; -+} -+ -+#endif /* __MINGW32_VERSION */ -+ -+ -+static void cryptoapi_report_error(const char *msg) -+{ -+ char *s, *pos; -+ DWORD err = GetLastError(); -+ -+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | -+ FORMAT_MESSAGE_FROM_SYSTEM, -+ NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err); -+ } -+ -+ pos = s; -+ while (*pos) { -+ if (*pos == '\n' || *pos == '\r') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ -+ wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s); -+ LocalFree(s); -+} -+ -+ -+int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem, -+ const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ HCRYPTPROV prov; -+ HCRYPTHASH hash; -+ size_t i; -+ DWORD hlen; -+ int ret = 0; -+ -+ if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) { -+ cryptoapi_report_error("CryptAcquireContext"); -+ return -1; -+ } -+ -+ if (!CryptCreateHash(prov, alg, 0, 0, &hash)) { -+ cryptoapi_report_error("CryptCreateHash"); -+ CryptReleaseContext(prov, 0); -+ return -1; -+ } -+ -+ for (i = 0; i < num_elem; i++) { -+ if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) { -+ cryptoapi_report_error("CryptHashData"); -+ CryptDestroyHash(hash); -+ CryptReleaseContext(prov, 0); -+ } -+ } -+ -+ hlen = hash_len; -+ if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) { -+ cryptoapi_report_error("CryptGetHashParam"); -+ ret = -1; -+ } -+ -+ CryptDestroyHash(hash); -+ CryptReleaseContext(prov, 0); -+ -+ return ret; -+} -+ -+ -+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac); -+} -+ -+ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -+{ -+ u8 next, tmp; -+ int i; -+ HCRYPTPROV prov; -+ HCRYPTKEY ckey; -+ DWORD dlen; -+ struct { -+ BLOBHEADER hdr; -+ DWORD len; -+ BYTE key[8]; -+ } key_blob; -+ DWORD mode = CRYPT_MODE_ECB; -+ -+ key_blob.hdr.bType = PLAINTEXTKEYBLOB; -+ key_blob.hdr.bVersion = CUR_BLOB_VERSION; -+ key_blob.hdr.reserved = 0; -+ key_blob.hdr.aiKeyAlg = CALG_DES; -+ key_blob.len = 8; -+ -+ /* Add parity bits to the key */ -+ next = 0; -+ for (i = 0; i < 7; i++) { -+ tmp = key[i]; -+ key_blob.key[i] = (tmp >> i) | next | 1; -+ next = tmp << (7 - i); -+ } -+ key_blob.key[i] = next | 1; -+ -+ if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, -+ CRYPT_VERIFYCONTEXT)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " -+ "%d", (int) GetLastError()); -+ return; -+ } -+ -+ if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0, -+ &ckey)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", -+ (int) GetLastError()); -+ CryptReleaseContext(prov, 0); -+ return; -+ } -+ -+ if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " -+ "failed: %d", (int) GetLastError()); -+ CryptDestroyKey(ckey); -+ CryptReleaseContext(prov, 0); -+ return; -+ } -+ -+ os_memcpy(cypher, clear, 8); -+ dlen = 8; -+ if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", -+ (int) GetLastError()); -+ os_memset(cypher, 0, 8); -+ } -+ -+ CryptDestroyKey(ckey); -+ CryptReleaseContext(prov, 0); -+} -+ -+ -+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac); -+} -+ -+ -+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac); -+} -+ -+ -+struct aes_context { -+ HCRYPTPROV prov; -+ HCRYPTKEY ckey; -+}; -+ -+ -+void * aes_encrypt_init(const u8 *key, size_t len) -+{ -+ struct aes_context *akey; -+ struct { -+ BLOBHEADER hdr; -+ DWORD len; -+ BYTE key[16]; -+ } key_blob; -+ DWORD mode = CRYPT_MODE_ECB; -+ -+ if (len != 16) -+ return NULL; -+ -+ key_blob.hdr.bType = PLAINTEXTKEYBLOB; -+ key_blob.hdr.bVersion = CUR_BLOB_VERSION; -+ key_blob.hdr.reserved = 0; -+ key_blob.hdr.aiKeyAlg = CALG_AES_128; -+ key_blob.len = len; -+ os_memcpy(key_blob.key, key, len); -+ -+ akey = os_zalloc(sizeof(*akey)); -+ if (akey == NULL) -+ return NULL; -+ -+ if (!CryptAcquireContext(&akey->prov, NULL, -+ MS_ENH_RSA_AES_PROV, PROV_RSA_AES, -+ CRYPT_VERIFYCONTEXT)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: " -+ "%d", (int) GetLastError()); -+ os_free(akey); -+ return NULL; -+ } -+ -+ if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob), -+ 0, 0, &akey->ckey)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d", -+ (int) GetLastError()); -+ CryptReleaseContext(akey->prov, 0); -+ os_free(akey); -+ return NULL; -+ } -+ -+ if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) " -+ "failed: %d", (int) GetLastError()); -+ CryptDestroyKey(akey->ckey); -+ CryptReleaseContext(akey->prov, 0); -+ os_free(akey); -+ return NULL; -+ } -+ -+ return akey; -+} -+ -+ -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -+{ -+ struct aes_context *akey = ctx; -+ DWORD dlen; -+ -+ os_memcpy(crypt, plain, 16); -+ dlen = 16; -+ if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d", -+ (int) GetLastError()); -+ os_memset(crypt, 0, 16); -+ } -+} -+ -+ -+void aes_encrypt_deinit(void *ctx) -+{ -+ struct aes_context *akey = ctx; -+ if (akey) { -+ CryptDestroyKey(akey->ckey); -+ CryptReleaseContext(akey->prov, 0); -+ os_free(akey); -+ } -+} -+ -+ -+void * aes_decrypt_init(const u8 *key, size_t len) -+{ -+ return aes_encrypt_init(key, len); -+} -+ -+ -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -+{ -+ struct aes_context *akey = ctx; -+ DWORD dlen; -+ -+ os_memcpy(plain, crypt, 16); -+ dlen = 16; -+ -+ if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d", -+ (int) GetLastError()); -+ } -+} -+ -+ -+void aes_decrypt_deinit(void *ctx) -+{ -+ aes_encrypt_deinit(ctx); -+} -+ -+ -+struct crypto_hash { -+ enum crypto_hash_alg alg; -+ int error; -+ HCRYPTPROV prov; -+ HCRYPTHASH hash; -+ HCRYPTKEY key; -+}; -+ -+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_hash *ctx; -+ ALG_ID calg; -+ struct { -+ BLOBHEADER hdr; -+ DWORD len; -+ BYTE key[32]; -+ } key_blob; -+ -+ os_memset(&key_blob, 0, sizeof(key_blob)); -+ switch (alg) { -+ case CRYPTO_HASH_ALG_MD5: -+ calg = CALG_MD5; -+ break; -+ case CRYPTO_HASH_ALG_SHA1: -+ calg = CALG_SHA; -+ break; -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ calg = CALG_HMAC; -+ key_blob.hdr.bType = PLAINTEXTKEYBLOB; -+ key_blob.hdr.bVersion = CUR_BLOB_VERSION; -+ key_blob.hdr.reserved = 0; -+ /* -+ * Note: RC2 is not really used, but that can be used to -+ * import HMAC keys of up to 16 byte long. -+ * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to -+ * be able to import longer keys (HMAC-SHA1 uses 20-byte key). -+ */ -+ key_blob.hdr.aiKeyAlg = CALG_RC2; -+ key_blob.len = key_len; -+ if (key_len > sizeof(key_blob.key)) -+ return NULL; -+ os_memcpy(key_blob.key, key, key_len); -+ break; -+ default: -+ return NULL; -+ } -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ ctx->alg = alg; -+ -+ if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) { -+ cryptoapi_report_error("CryptAcquireContext"); -+ os_free(ctx); -+ return NULL; -+ } -+ -+ if (calg == CALG_HMAC) { -+#ifndef CRYPT_IPSEC_HMAC_KEY -+#define CRYPT_IPSEC_HMAC_KEY 0x00000100 -+#endif -+ if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, -+ sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY, -+ &ctx->key)) { -+ cryptoapi_report_error("CryptImportKey"); -+ CryptReleaseContext(ctx->prov, 0); -+ os_free(ctx); -+ return NULL; -+ } -+ } -+ -+ if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) { -+ cryptoapi_report_error("CryptCreateHash"); -+ CryptReleaseContext(ctx->prov, 0); -+ os_free(ctx); -+ return NULL; -+ } -+ -+ if (calg == CALG_HMAC) { -+ HMAC_INFO info; -+ os_memset(&info, 0, sizeof(info)); -+ switch (alg) { -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ info.HashAlgid = CALG_MD5; -+ break; -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ info.HashAlgid = CALG_SHA; -+ break; -+ default: -+ /* unreachable */ -+ break; -+ } -+ -+ if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info, -+ 0)) { -+ cryptoapi_report_error("CryptSetHashParam"); -+ CryptDestroyHash(ctx->hash); -+ CryptReleaseContext(ctx->prov, 0); -+ os_free(ctx); -+ return NULL; -+ } -+ } -+ -+ return ctx; -+} -+ -+ -+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -+{ -+ if (ctx == NULL || ctx->error) -+ return; -+ -+ if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) { -+ cryptoapi_report_error("CryptHashData"); -+ ctx->error = 1; -+ } -+} -+ -+ -+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -+{ -+ int ret = 0; -+ DWORD hlen; -+ -+ if (ctx == NULL) -+ return -2; -+ -+ if (mac == NULL || len == NULL) -+ goto done; -+ -+ if (ctx->error) { -+ ret = -2; -+ goto done; -+ } -+ -+ hlen = *len; -+ if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) { -+ cryptoapi_report_error("CryptGetHashParam"); -+ ret = -2; -+ } -+ *len = hlen; -+ -+done: -+ if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 || -+ ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5) -+ CryptDestroyKey(ctx->key); -+ -+ os_free(ctx); -+ -+ return ret; -+} -+ -+ -+struct crypto_cipher { -+ HCRYPTPROV prov; -+ HCRYPTKEY key; -+}; -+ -+ -+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, -+ const u8 *iv, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_cipher *ctx; -+ struct { -+ BLOBHEADER hdr; -+ DWORD len; -+ BYTE key[32]; -+ } key_blob; -+ DWORD mode = CRYPT_MODE_CBC; -+ -+ key_blob.hdr.bType = PLAINTEXTKEYBLOB; -+ key_blob.hdr.bVersion = CUR_BLOB_VERSION; -+ key_blob.hdr.reserved = 0; -+ key_blob.len = key_len; -+ if (key_len > sizeof(key_blob.key)) -+ return NULL; -+ os_memcpy(key_blob.key, key, key_len); -+ -+ switch (alg) { -+ case CRYPTO_CIPHER_ALG_AES: -+ if (key_len == 32) -+ key_blob.hdr.aiKeyAlg = CALG_AES_256; -+ else if (key_len == 24) -+ key_blob.hdr.aiKeyAlg = CALG_AES_192; -+ else -+ key_blob.hdr.aiKeyAlg = CALG_AES_128; -+ break; -+ case CRYPTO_CIPHER_ALG_3DES: -+ key_blob.hdr.aiKeyAlg = CALG_3DES; -+ break; -+ case CRYPTO_CIPHER_ALG_DES: -+ key_blob.hdr.aiKeyAlg = CALG_DES; -+ break; -+ case CRYPTO_CIPHER_ALG_RC2: -+ key_blob.hdr.aiKeyAlg = CALG_RC2; -+ break; -+ case CRYPTO_CIPHER_ALG_RC4: -+ key_blob.hdr.aiKeyAlg = CALG_RC4; -+ break; -+ default: -+ return NULL; -+ } -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV, -+ PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { -+ cryptoapi_report_error("CryptAcquireContext"); -+ goto fail1; -+ } -+ -+ if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob, -+ sizeof(key_blob), 0, 0, &ctx->key)) { -+ cryptoapi_report_error("CryptImportKey"); -+ goto fail2; -+ } -+ -+ if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) { -+ cryptoapi_report_error("CryptSetKeyParam(KP_MODE)"); -+ goto fail3; -+ } -+ -+ if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) { -+ cryptoapi_report_error("CryptSetKeyParam(KP_IV)"); -+ goto fail3; -+ } -+ -+ return ctx; -+ -+fail3: -+ CryptDestroyKey(ctx->key); -+fail2: -+ CryptReleaseContext(ctx->prov, 0); -+fail1: -+ os_free(ctx); -+ return NULL; -+} -+ -+ -+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, -+ u8 *crypt, size_t len) -+{ -+ DWORD dlen; -+ -+ os_memcpy(crypt, plain, len); -+ dlen = len; -+ if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) { -+ cryptoapi_report_error("CryptEncrypt"); -+ os_memset(crypt, 0, len); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, -+ u8 *plain, size_t len) -+{ -+ DWORD dlen; -+ -+ os_memcpy(plain, crypt, len); -+ dlen = len; -+ if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) { -+ cryptoapi_report_error("CryptDecrypt"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void crypto_cipher_deinit(struct crypto_cipher *ctx) -+{ -+ CryptDestroyKey(ctx->key); -+ CryptReleaseContext(ctx->prov, 0); -+ os_free(ctx); -+} -+ -+ -+struct crypto_public_key { -+ HCRYPTPROV prov; -+ HCRYPTKEY rsa; -+}; -+ -+struct crypto_private_key { -+ HCRYPTPROV prov; -+ HCRYPTKEY rsa; -+}; -+ -+ -+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) -+{ -+ /* Use crypto_public_key_from_cert() instead. */ -+ return NULL; -+} -+ -+ -+struct crypto_private_key * crypto_private_key_import(const u8 *key, -+ size_t len, -+ const char *passwd) -+{ -+ /* TODO */ -+ return NULL; -+} -+ -+ -+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, -+ size_t len) -+{ -+ struct crypto_public_key *pk; -+ PCCERT_CONTEXT cc; -+ -+ pk = os_zalloc(sizeof(*pk)); -+ if (pk == NULL) -+ return NULL; -+ -+ cc = CertCreateCertificateContext(X509_ASN_ENCODING | -+ PKCS_7_ASN_ENCODING, buf, len); -+ if (!cc) { -+ cryptoapi_report_error("CryptCreateCertificateContext"); -+ os_free(pk); -+ return NULL; -+ } -+ -+ if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, -+ 0)) { -+ cryptoapi_report_error("CryptAcquireContext"); -+ os_free(pk); -+ CertFreeCertificateContext(cc); -+ return NULL; -+ } -+ -+ if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING | -+ PKCS_7_ASN_ENCODING, -+ &cc->pCertInfo->SubjectPublicKeyInfo, -+ &pk->rsa)) { -+ cryptoapi_report_error("CryptImportPublicKeyInfo"); -+ CryptReleaseContext(pk->prov, 0); -+ os_free(pk); -+ CertFreeCertificateContext(cc); -+ return NULL; -+ } -+ -+ CertFreeCertificateContext(cc); -+ -+ return pk; -+} -+ -+ -+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ DWORD clen; -+ u8 *tmp; -+ size_t i; -+ -+ if (*outlen < inlen) -+ return -1; -+ tmp = malloc(*outlen); -+ if (tmp == NULL) -+ return -1; -+ -+ os_memcpy(tmp, in, inlen); -+ clen = inlen; -+ if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) { -+ wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using " -+ "public key: %d", (int) GetLastError()); -+ os_free(tmp); -+ return -1; -+ } -+ -+ *outlen = clen; -+ -+ /* Reverse the output */ -+ for (i = 0; i < *outlen; i++) -+ out[i] = tmp[*outlen - 1 - i]; -+ -+ os_free(tmp); -+ -+ return 0; -+} -+ -+ -+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ /* TODO */ -+ return -1; -+} -+ -+ -+void crypto_public_key_free(struct crypto_public_key *key) -+{ -+ if (key) { -+ CryptDestroyKey(key->rsa); -+ CryptReleaseContext(key->prov, 0); -+ os_free(key); -+ } -+} -+ -+ -+void crypto_private_key_free(struct crypto_private_key *key) -+{ -+ if (key) { -+ CryptDestroyKey(key->rsa); -+ CryptReleaseContext(key->prov, 0); -+ os_free(key); -+ } -+} -+ -+ -+int crypto_global_init(void) -+{ -+ return mingw_load_crypto_func(); -+} -+ -+ -+void crypto_global_deinit(void) -+{ -+} -+ -+ -+int crypto_mod_exp(const u8 *base, size_t base_len, -+ const u8 *power, size_t power_len, -+ const u8 *modulus, size_t modulus_len, -+ u8 *result, size_t *result_len) -+{ -+ /* TODO */ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_gnutls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_gnutls.c -new file mode 100644 -index 0000000000000..0998cca546721 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_gnutls.c -@@ -0,0 +1,305 @@ -+/* -+ * WPA Supplicant / wrapper functions for libgcrypt -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "crypto.h" -+ -+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ gcry_md_hd_t hd; -+ unsigned char *p; -+ size_t i; -+ -+ if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR) -+ return -1; -+ for (i = 0; i < num_elem; i++) -+ gcry_md_write(hd, addr[i], len[i]); -+ p = gcry_md_read(hd, GCRY_MD_MD4); -+ if (p) -+ memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4)); -+ gcry_md_close(hd); -+ return 0; -+} -+ -+ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -+{ -+ gcry_cipher_hd_t hd; -+ u8 pkey[8], next, tmp; -+ int i; -+ -+ /* Add parity bits to the key */ -+ next = 0; -+ for (i = 0; i < 7; i++) { -+ tmp = key[i]; -+ pkey[i] = (tmp >> i) | next | 1; -+ next = tmp << (7 - i); -+ } -+ pkey[i] = next | 1; -+ -+ gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); -+ gcry_err_code(gcry_cipher_setkey(hd, pkey, 8)); -+ gcry_cipher_encrypt(hd, cypher, 8, clear, 8); -+ gcry_cipher_close(hd); -+} -+ -+ -+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ gcry_md_hd_t hd; -+ unsigned char *p; -+ size_t i; -+ -+ if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR) -+ return -1; -+ for (i = 0; i < num_elem; i++) -+ gcry_md_write(hd, addr[i], len[i]); -+ p = gcry_md_read(hd, GCRY_MD_MD5); -+ if (p) -+ memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5)); -+ gcry_md_close(hd); -+ return 0; -+} -+ -+ -+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ gcry_md_hd_t hd; -+ unsigned char *p; -+ size_t i; -+ -+ if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR) -+ return -1; -+ for (i = 0; i < num_elem; i++) -+ gcry_md_write(hd, addr[i], len[i]); -+ p = gcry_md_read(hd, GCRY_MD_SHA1); -+ if (p) -+ memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1)); -+ gcry_md_close(hd); -+ return 0; -+} -+ -+ -+void * aes_encrypt_init(const u8 *key, size_t len) -+{ -+ gcry_cipher_hd_t hd; -+ -+ if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) != -+ GPG_ERR_NO_ERROR) { -+ printf("cipher open failed\n"); -+ return NULL; -+ } -+ if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) { -+ printf("setkey failed\n"); -+ gcry_cipher_close(hd); -+ return NULL; -+ } -+ -+ return hd; -+} -+ -+ -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -+{ -+ gcry_cipher_hd_t hd = ctx; -+ gcry_cipher_encrypt(hd, crypt, 16, plain, 16); -+} -+ -+ -+void aes_encrypt_deinit(void *ctx) -+{ -+ gcry_cipher_hd_t hd = ctx; -+ gcry_cipher_close(hd); -+} -+ -+ -+void * aes_decrypt_init(const u8 *key, size_t len) -+{ -+ gcry_cipher_hd_t hd; -+ -+ if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) != -+ GPG_ERR_NO_ERROR) -+ return NULL; -+ if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) { -+ gcry_cipher_close(hd); -+ return NULL; -+ } -+ -+ return hd; -+} -+ -+ -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -+{ -+ gcry_cipher_hd_t hd = ctx; -+ gcry_cipher_decrypt(hd, plain, 16, crypt, 16); -+} -+ -+ -+void aes_decrypt_deinit(void *ctx) -+{ -+ gcry_cipher_hd_t hd = ctx; -+ gcry_cipher_close(hd); -+} -+ -+ -+int crypto_mod_exp(const u8 *base, size_t base_len, -+ const u8 *power, size_t power_len, -+ const u8 *modulus, size_t modulus_len, -+ u8 *result, size_t *result_len) -+{ -+ gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL, -+ bn_result = NULL; -+ int ret = -1; -+ -+ if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) != -+ GPG_ERR_NO_ERROR || -+ gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) != -+ GPG_ERR_NO_ERROR || -+ gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len, -+ NULL) != GPG_ERR_NO_ERROR) -+ goto error; -+ bn_result = gcry_mpi_new(modulus_len * 8); -+ -+ gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus); -+ -+ if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len, -+ bn_result) != GPG_ERR_NO_ERROR) -+ goto error; -+ -+ ret = 0; -+ -+error: -+ gcry_mpi_release(bn_base); -+ gcry_mpi_release(bn_exp); -+ gcry_mpi_release(bn_modulus); -+ gcry_mpi_release(bn_result); -+ return ret; -+} -+ -+ -+struct crypto_cipher { -+ gcry_cipher_hd_t enc; -+ gcry_cipher_hd_t dec; -+}; -+ -+ -+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, -+ const u8 *iv, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_cipher *ctx; -+ gcry_error_t res; -+ enum gcry_cipher_algos a; -+ int ivlen; -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ switch (alg) { -+ case CRYPTO_CIPHER_ALG_RC4: -+ a = GCRY_CIPHER_ARCFOUR; -+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM, -+ 0); -+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0); -+ break; -+ case CRYPTO_CIPHER_ALG_AES: -+ if (key_len == 24) -+ a = GCRY_CIPHER_AES192; -+ else if (key_len == 32) -+ a = GCRY_CIPHER_AES256; -+ else -+ a = GCRY_CIPHER_AES; -+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); -+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); -+ break; -+ case CRYPTO_CIPHER_ALG_3DES: -+ a = GCRY_CIPHER_3DES; -+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); -+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); -+ break; -+ case CRYPTO_CIPHER_ALG_DES: -+ a = GCRY_CIPHER_DES; -+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); -+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); -+ break; -+ case CRYPTO_CIPHER_ALG_RC2: -+ if (key_len == 5) -+ a = GCRY_CIPHER_RFC2268_40; -+ else -+ a = GCRY_CIPHER_RFC2268_128; -+ res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0); -+ gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0); -+ break; -+ default: -+ os_free(ctx); -+ return NULL; -+ } -+ -+ if (res != GPG_ERR_NO_ERROR) { -+ os_free(ctx); -+ return NULL; -+ } -+ -+ if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR || -+ gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) { -+ gcry_cipher_close(ctx->enc); -+ gcry_cipher_close(ctx->dec); -+ os_free(ctx); -+ return NULL; -+ } -+ -+ ivlen = gcry_cipher_get_algo_blklen(a); -+ if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR || -+ gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) { -+ gcry_cipher_close(ctx->enc); -+ gcry_cipher_close(ctx->dec); -+ os_free(ctx); -+ return NULL; -+ } -+ -+ return ctx; -+} -+ -+ -+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, -+ u8 *crypt, size_t len) -+{ -+ if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) != -+ GPG_ERR_NO_ERROR) -+ return -1; -+ return 0; -+} -+ -+ -+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, -+ u8 *plain, size_t len) -+{ -+ if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) != -+ GPG_ERR_NO_ERROR) -+ return -1; -+ return 0; -+} -+ -+ -+void crypto_cipher_deinit(struct crypto_cipher *ctx) -+{ -+ gcry_cipher_close(ctx->enc); -+ gcry_cipher_close(ctx->dec); -+ os_free(ctx); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-cipher.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-cipher.c -new file mode 100644 -index 0000000000000..75134f09a403f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-cipher.c -@@ -0,0 +1,256 @@ -+/* -+ * Crypto wrapper for internal crypto implementation - Cipher wrappers -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "aes.h" -+#include "des_i.h" -+ -+ -+struct crypto_cipher { -+ enum crypto_cipher_alg alg; -+ union { -+ struct { -+ size_t used_bytes; -+ u8 key[16]; -+ size_t keylen; -+ } rc4; -+ struct { -+ u8 cbc[32]; -+ size_t block_size; -+ void *ctx_enc; -+ void *ctx_dec; -+ } aes; -+ struct { -+ struct des3_key_s key; -+ u8 cbc[8]; -+ } des3; -+ struct { -+ u32 ek[32]; -+ u32 dk[32]; -+ u8 cbc[8]; -+ } des; -+ } u; -+}; -+ -+ -+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, -+ const u8 *iv, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_cipher *ctx; -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ ctx->alg = alg; -+ -+ switch (alg) { -+ case CRYPTO_CIPHER_ALG_RC4: -+ if (key_len > sizeof(ctx->u.rc4.key)) { -+ os_free(ctx); -+ return NULL; -+ } -+ ctx->u.rc4.keylen = key_len; -+ os_memcpy(ctx->u.rc4.key, key, key_len); -+ break; -+ case CRYPTO_CIPHER_ALG_AES: -+ if (key_len > sizeof(ctx->u.aes.cbc)) { -+ os_free(ctx); -+ return NULL; -+ } -+ ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len); -+ if (ctx->u.aes.ctx_enc == NULL) { -+ os_free(ctx); -+ return NULL; -+ } -+ ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len); -+ if (ctx->u.aes.ctx_dec == NULL) { -+ aes_encrypt_deinit(ctx->u.aes.ctx_enc); -+ os_free(ctx); -+ return NULL; -+ } -+ ctx->u.aes.block_size = key_len; -+ os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size); -+ break; -+ case CRYPTO_CIPHER_ALG_3DES: -+ if (key_len != 24) { -+ os_free(ctx); -+ return NULL; -+ } -+ des3_key_setup(key, &ctx->u.des3.key); -+ os_memcpy(ctx->u.des3.cbc, iv, 8); -+ break; -+ case CRYPTO_CIPHER_ALG_DES: -+ if (key_len != 8) { -+ os_free(ctx); -+ return NULL; -+ } -+ des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk); -+ os_memcpy(ctx->u.des.cbc, iv, 8); -+ break; -+ default: -+ os_free(ctx); -+ return NULL; -+ } -+ -+ return ctx; -+} -+ -+ -+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, -+ u8 *crypt, size_t len) -+{ -+ size_t i, j, blocks; -+ -+ switch (ctx->alg) { -+ case CRYPTO_CIPHER_ALG_RC4: -+ if (plain != crypt) -+ os_memcpy(crypt, plain, len); -+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, -+ ctx->u.rc4.used_bytes, crypt, len); -+ ctx->u.rc4.used_bytes += len; -+ break; -+ case CRYPTO_CIPHER_ALG_AES: -+ if (len % ctx->u.aes.block_size) -+ return -1; -+ blocks = len / ctx->u.aes.block_size; -+ for (i = 0; i < blocks; i++) { -+ for (j = 0; j < ctx->u.aes.block_size; j++) -+ ctx->u.aes.cbc[j] ^= plain[j]; -+ aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc, -+ ctx->u.aes.cbc); -+ os_memcpy(crypt, ctx->u.aes.cbc, -+ ctx->u.aes.block_size); -+ plain += ctx->u.aes.block_size; -+ crypt += ctx->u.aes.block_size; -+ } -+ break; -+ case CRYPTO_CIPHER_ALG_3DES: -+ if (len % 8) -+ return -1; -+ blocks = len / 8; -+ for (i = 0; i < blocks; i++) { -+ for (j = 0; j < 8; j++) -+ ctx->u.des3.cbc[j] ^= plain[j]; -+ des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key, -+ ctx->u.des3.cbc); -+ os_memcpy(crypt, ctx->u.des3.cbc, 8); -+ plain += 8; -+ crypt += 8; -+ } -+ break; -+ case CRYPTO_CIPHER_ALG_DES: -+ if (len % 8) -+ return -1; -+ blocks = len / 8; -+ for (i = 0; i < blocks; i++) { -+ for (j = 0; j < 8; j++) -+ ctx->u.des3.cbc[j] ^= plain[j]; -+ des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek, -+ ctx->u.des.cbc); -+ os_memcpy(crypt, ctx->u.des.cbc, 8); -+ plain += 8; -+ crypt += 8; -+ } -+ break; -+ default: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, -+ u8 *plain, size_t len) -+{ -+ size_t i, j, blocks; -+ u8 tmp[32]; -+ -+ switch (ctx->alg) { -+ case CRYPTO_CIPHER_ALG_RC4: -+ if (plain != crypt) -+ os_memcpy(plain, crypt, len); -+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, -+ ctx->u.rc4.used_bytes, plain, len); -+ ctx->u.rc4.used_bytes += len; -+ break; -+ case CRYPTO_CIPHER_ALG_AES: -+ if (len % ctx->u.aes.block_size) -+ return -1; -+ blocks = len / ctx->u.aes.block_size; -+ for (i = 0; i < blocks; i++) { -+ os_memcpy(tmp, crypt, ctx->u.aes.block_size); -+ aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain); -+ for (j = 0; j < ctx->u.aes.block_size; j++) -+ plain[j] ^= ctx->u.aes.cbc[j]; -+ os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size); -+ plain += ctx->u.aes.block_size; -+ crypt += ctx->u.aes.block_size; -+ } -+ break; -+ case CRYPTO_CIPHER_ALG_3DES: -+ if (len % 8) -+ return -1; -+ blocks = len / 8; -+ for (i = 0; i < blocks; i++) { -+ os_memcpy(tmp, crypt, 8); -+ des3_decrypt(crypt, &ctx->u.des3.key, plain); -+ for (j = 0; j < 8; j++) -+ plain[j] ^= ctx->u.des3.cbc[j]; -+ os_memcpy(ctx->u.des3.cbc, tmp, 8); -+ plain += 8; -+ crypt += 8; -+ } -+ break; -+ case CRYPTO_CIPHER_ALG_DES: -+ if (len % 8) -+ return -1; -+ blocks = len / 8; -+ for (i = 0; i < blocks; i++) { -+ os_memcpy(tmp, crypt, 8); -+ des_block_decrypt(crypt, ctx->u.des.dk, plain); -+ for (j = 0; j < 8; j++) -+ plain[j] ^= ctx->u.des.cbc[j]; -+ os_memcpy(ctx->u.des.cbc, tmp, 8); -+ plain += 8; -+ crypt += 8; -+ } -+ break; -+ default: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void crypto_cipher_deinit(struct crypto_cipher *ctx) -+{ -+ switch (ctx->alg) { -+ case CRYPTO_CIPHER_ALG_AES: -+ aes_encrypt_deinit(ctx->u.aes.ctx_enc); -+ aes_decrypt_deinit(ctx->u.aes.ctx_dec); -+ break; -+ case CRYPTO_CIPHER_ALG_3DES: -+ break; -+ default: -+ break; -+ } -+ os_free(ctx); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-modexp.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-modexp.c -new file mode 100644 -index 0000000000000..3124742e87cd4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-modexp.c -@@ -0,0 +1,55 @@ -+/* -+ * Crypto wrapper for internal crypto implementation - modexp -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "tls/bignum.h" -+#include "crypto.h" -+ -+ -+int crypto_mod_exp(const u8 *base, size_t base_len, -+ const u8 *power, size_t power_len, -+ const u8 *modulus, size_t modulus_len, -+ u8 *result, size_t *result_len) -+{ -+ struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; -+ int ret = -1; -+ -+ bn_base = bignum_init(); -+ bn_exp = bignum_init(); -+ bn_modulus = bignum_init(); -+ bn_result = bignum_init(); -+ -+ if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || -+ bn_result == NULL) -+ goto error; -+ -+ if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || -+ bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || -+ bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) -+ goto error; -+ -+ if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) -+ goto error; -+ -+ ret = bignum_get_unsigned_bin(bn_result, result, result_len); -+ -+error: -+ bignum_deinit(bn_base); -+ bignum_deinit(bn_exp); -+ bignum_deinit(bn_modulus); -+ bignum_deinit(bn_result); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-rsa.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-rsa.c -new file mode 100644 -index 0000000000000..205042cf36311 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal-rsa.c -@@ -0,0 +1,115 @@ -+/* -+ * Crypto wrapper for internal crypto implementation - RSA parts -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "tls/rsa.h" -+#include "tls/bignum.h" -+#include "tls/pkcs1.h" -+#include "tls/pkcs8.h" -+ -+/* Dummy structures; these are just typecast to struct crypto_rsa_key */ -+struct crypto_public_key; -+struct crypto_private_key; -+ -+ -+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) -+{ -+ return (struct crypto_public_key *) -+ crypto_rsa_import_public_key(key, len); -+} -+ -+ -+struct crypto_private_key * crypto_private_key_import(const u8 *key, -+ size_t len, -+ const char *passwd) -+{ -+ struct crypto_private_key *res; -+ -+ /* First, check for possible PKCS #8 encoding */ -+ res = pkcs8_key_import(key, len); -+ if (res) -+ return res; -+ -+ if (passwd) { -+ /* Try to parse as encrypted PKCS #8 */ -+ res = pkcs8_enc_key_import(key, len, passwd); -+ if (res) -+ return res; -+ } -+ -+ /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */ -+ wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private " -+ "key"); -+ return (struct crypto_private_key *) -+ crypto_rsa_import_private_key(key, len); -+} -+ -+ -+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, -+ size_t len) -+{ -+ /* No X.509 support in crypto_internal.c */ -+ return NULL; -+} -+ -+ -+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ return pkcs1_encrypt(2, (struct crypto_rsa_key *) key, -+ 0, in, inlen, out, outlen); -+} -+ -+ -+int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key, -+ in, inlen, out, outlen); -+} -+ -+ -+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ return pkcs1_encrypt(1, (struct crypto_rsa_key *) key, -+ 1, in, inlen, out, outlen); -+} -+ -+ -+void crypto_public_key_free(struct crypto_public_key *key) -+{ -+ crypto_rsa_free((struct crypto_rsa_key *) key); -+} -+ -+ -+void crypto_private_key_free(struct crypto_private_key *key) -+{ -+ crypto_rsa_free((struct crypto_rsa_key *) key); -+} -+ -+ -+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, -+ const u8 *crypt, size_t crypt_len, -+ u8 *plain, size_t *plain_len) -+{ -+ return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key, -+ crypt, crypt_len, plain, plain_len); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal.c -new file mode 100644 -index 0000000000000..8fdba65802750 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_internal.c -@@ -0,0 +1,205 @@ -+/* -+ * Crypto wrapper for internal crypto implementation -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "sha1_i.h" -+#include "md5_i.h" -+ -+struct crypto_hash { -+ enum crypto_hash_alg alg; -+ union { -+ struct MD5Context md5; -+ struct SHA1Context sha1; -+ } u; -+ u8 key[64]; -+ size_t key_len; -+}; -+ -+ -+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_hash *ctx; -+ u8 k_pad[64]; -+ u8 tk[20]; -+ size_t i; -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ ctx->alg = alg; -+ -+ switch (alg) { -+ case CRYPTO_HASH_ALG_MD5: -+ MD5Init(&ctx->u.md5); -+ break; -+ case CRYPTO_HASH_ALG_SHA1: -+ SHA1Init(&ctx->u.sha1); -+ break; -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ if (key_len > sizeof(k_pad)) { -+ MD5Init(&ctx->u.md5); -+ MD5Update(&ctx->u.md5, key, key_len); -+ MD5Final(tk, &ctx->u.md5); -+ key = tk; -+ key_len = 16; -+ } -+ os_memcpy(ctx->key, key, key_len); -+ ctx->key_len = key_len; -+ -+ os_memcpy(k_pad, key, key_len); -+ os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); -+ for (i = 0; i < sizeof(k_pad); i++) -+ k_pad[i] ^= 0x36; -+ MD5Init(&ctx->u.md5); -+ MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); -+ break; -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ if (key_len > sizeof(k_pad)) { -+ SHA1Init(&ctx->u.sha1); -+ SHA1Update(&ctx->u.sha1, key, key_len); -+ SHA1Final(tk, &ctx->u.sha1); -+ key = tk; -+ key_len = 20; -+ } -+ os_memcpy(ctx->key, key, key_len); -+ ctx->key_len = key_len; -+ -+ os_memcpy(k_pad, key, key_len); -+ os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len); -+ for (i = 0; i < sizeof(k_pad); i++) -+ k_pad[i] ^= 0x36; -+ SHA1Init(&ctx->u.sha1); -+ SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); -+ break; -+ default: -+ os_free(ctx); -+ return NULL; -+ } -+ -+ return ctx; -+} -+ -+ -+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -+{ -+ if (ctx == NULL) -+ return; -+ -+ switch (ctx->alg) { -+ case CRYPTO_HASH_ALG_MD5: -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ MD5Update(&ctx->u.md5, data, len); -+ break; -+ case CRYPTO_HASH_ALG_SHA1: -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ SHA1Update(&ctx->u.sha1, data, len); -+ break; -+ } -+} -+ -+ -+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -+{ -+ u8 k_pad[64]; -+ size_t i; -+ -+ if (ctx == NULL) -+ return -2; -+ -+ if (mac == NULL || len == NULL) { -+ os_free(ctx); -+ return 0; -+ } -+ -+ switch (ctx->alg) { -+ case CRYPTO_HASH_ALG_MD5: -+ if (*len < 16) { -+ *len = 16; -+ os_free(ctx); -+ return -1; -+ } -+ *len = 16; -+ MD5Final(mac, &ctx->u.md5); -+ break; -+ case CRYPTO_HASH_ALG_SHA1: -+ if (*len < 20) { -+ *len = 20; -+ os_free(ctx); -+ return -1; -+ } -+ *len = 20; -+ SHA1Final(mac, &ctx->u.sha1); -+ break; -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ if (*len < 16) { -+ *len = 16; -+ os_free(ctx); -+ return -1; -+ } -+ *len = 16; -+ -+ MD5Final(mac, &ctx->u.md5); -+ -+ os_memcpy(k_pad, ctx->key, ctx->key_len); -+ os_memset(k_pad + ctx->key_len, 0, -+ sizeof(k_pad) - ctx->key_len); -+ for (i = 0; i < sizeof(k_pad); i++) -+ k_pad[i] ^= 0x5c; -+ MD5Init(&ctx->u.md5); -+ MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad)); -+ MD5Update(&ctx->u.md5, mac, 16); -+ MD5Final(mac, &ctx->u.md5); -+ break; -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ if (*len < 20) { -+ *len = 20; -+ os_free(ctx); -+ return -1; -+ } -+ *len = 20; -+ -+ SHA1Final(mac, &ctx->u.sha1); -+ -+ os_memcpy(k_pad, ctx->key, ctx->key_len); -+ os_memset(k_pad + ctx->key_len, 0, -+ sizeof(k_pad) - ctx->key_len); -+ for (i = 0; i < sizeof(k_pad); i++) -+ k_pad[i] ^= 0x5c; -+ SHA1Init(&ctx->u.sha1); -+ SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad)); -+ SHA1Update(&ctx->u.sha1, mac, 20); -+ SHA1Final(mac, &ctx->u.sha1); -+ break; -+ } -+ -+ os_free(ctx); -+ -+ return 0; -+} -+ -+ -+int crypto_global_init(void) -+{ -+ return 0; -+} -+ -+ -+void crypto_global_deinit(void) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_libtomcrypt.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_libtomcrypt.c -new file mode 100644 -index 0000000000000..52b67a713d699 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_libtomcrypt.c -@@ -0,0 +1,732 @@ -+/* -+ * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1) -+ * Copyright (c) 2005-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "crypto.h" -+ -+#ifndef mp_init_multi -+#define mp_init_multi ltc_init_multi -+#define mp_clear_multi ltc_deinit_multi -+#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a) -+#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b) -+#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c) -+#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d) -+#endif -+ -+ -+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ hash_state md; -+ size_t i; -+ -+ md4_init(&md); -+ for (i = 0; i < num_elem; i++) -+ md4_process(&md, addr[i], len[i]); -+ md4_done(&md, mac); -+ return 0; -+} -+ -+ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -+{ -+ u8 pkey[8], next, tmp; -+ int i; -+ symmetric_key skey; -+ -+ /* Add parity bits to the key */ -+ next = 0; -+ for (i = 0; i < 7; i++) { -+ tmp = key[i]; -+ pkey[i] = (tmp >> i) | next | 1; -+ next = tmp << (7 - i); -+ } -+ pkey[i] = next | 1; -+ -+ des_setup(pkey, 8, 0, &skey); -+ des_ecb_encrypt(clear, cypher, &skey); -+ des_done(&skey); -+} -+ -+ -+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ hash_state md; -+ size_t i; -+ -+ md5_init(&md); -+ for (i = 0; i < num_elem; i++) -+ md5_process(&md, addr[i], len[i]); -+ md5_done(&md, mac); -+ return 0; -+} -+ -+ -+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ hash_state md; -+ size_t i; -+ -+ sha1_init(&md); -+ for (i = 0; i < num_elem; i++) -+ sha1_process(&md, addr[i], len[i]); -+ sha1_done(&md, mac); -+ return 0; -+} -+ -+ -+void * aes_encrypt_init(const u8 *key, size_t len) -+{ -+ symmetric_key *skey; -+ skey = os_malloc(sizeof(*skey)); -+ if (skey == NULL) -+ return NULL; -+ if (aes_setup(key, len, 0, skey) != CRYPT_OK) { -+ os_free(skey); -+ return NULL; -+ } -+ return skey; -+} -+ -+ -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -+{ -+ symmetric_key *skey = ctx; -+ aes_ecb_encrypt(plain, crypt, skey); -+} -+ -+ -+void aes_encrypt_deinit(void *ctx) -+{ -+ symmetric_key *skey = ctx; -+ aes_done(skey); -+ os_free(skey); -+} -+ -+ -+void * aes_decrypt_init(const u8 *key, size_t len) -+{ -+ symmetric_key *skey; -+ skey = os_malloc(sizeof(*skey)); -+ if (skey == NULL) -+ return NULL; -+ if (aes_setup(key, len, 0, skey) != CRYPT_OK) { -+ os_free(skey); -+ return NULL; -+ } -+ return skey; -+} -+ -+ -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -+{ -+ symmetric_key *skey = ctx; -+ aes_ecb_encrypt(plain, (u8 *) crypt, skey); -+} -+ -+ -+void aes_decrypt_deinit(void *ctx) -+{ -+ symmetric_key *skey = ctx; -+ aes_done(skey); -+ os_free(skey); -+} -+ -+ -+struct crypto_hash { -+ enum crypto_hash_alg alg; -+ int error; -+ union { -+ hash_state md; -+ hmac_state hmac; -+ } u; -+}; -+ -+ -+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_hash *ctx; -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ ctx->alg = alg; -+ -+ switch (alg) { -+ case CRYPTO_HASH_ALG_MD5: -+ if (md5_init(&ctx->u.md) != CRYPT_OK) -+ goto fail; -+ break; -+ case CRYPTO_HASH_ALG_SHA1: -+ if (sha1_init(&ctx->u.md) != CRYPT_OK) -+ goto fail; -+ break; -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) != -+ CRYPT_OK) -+ goto fail; -+ break; -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) != -+ CRYPT_OK) -+ goto fail; -+ break; -+ default: -+ goto fail; -+ } -+ -+ return ctx; -+ -+fail: -+ os_free(ctx); -+ return NULL; -+} -+ -+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) -+{ -+ if (ctx == NULL || ctx->error) -+ return; -+ -+ switch (ctx->alg) { -+ case CRYPTO_HASH_ALG_MD5: -+ ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK; -+ break; -+ case CRYPTO_HASH_ALG_SHA1: -+ ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK; -+ break; -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK; -+ break; -+ } -+} -+ -+ -+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) -+{ -+ int ret = 0; -+ unsigned long clen; -+ -+ if (ctx == NULL) -+ return -2; -+ -+ if (mac == NULL || len == NULL) { -+ os_free(ctx); -+ return 0; -+ } -+ -+ if (ctx->error) { -+ os_free(ctx); -+ return -2; -+ } -+ -+ switch (ctx->alg) { -+ case CRYPTO_HASH_ALG_MD5: -+ if (*len < 16) { -+ *len = 16; -+ os_free(ctx); -+ return -1; -+ } -+ *len = 16; -+ if (md5_done(&ctx->u.md, mac) != CRYPT_OK) -+ ret = -2; -+ break; -+ case CRYPTO_HASH_ALG_SHA1: -+ if (*len < 20) { -+ *len = 20; -+ os_free(ctx); -+ return -1; -+ } -+ *len = 20; -+ if (sha1_done(&ctx->u.md, mac) != CRYPT_OK) -+ ret = -2; -+ break; -+ case CRYPTO_HASH_ALG_HMAC_SHA1: -+ if (*len < 20) { -+ *len = 20; -+ os_free(ctx); -+ return -1; -+ } -+ /* continue */ -+ case CRYPTO_HASH_ALG_HMAC_MD5: -+ if (*len < 16) { -+ *len = 16; -+ os_free(ctx); -+ return -1; -+ } -+ clen = *len; -+ if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) { -+ os_free(ctx); -+ return -1; -+ } -+ *len = clen; -+ break; -+ default: -+ ret = -2; -+ break; -+ } -+ -+ os_free(ctx); -+ -+ return ret; -+} -+ -+ -+struct crypto_cipher { -+ int rc4; -+ union { -+ symmetric_CBC cbc; -+ struct { -+ size_t used_bytes; -+ u8 key[16]; -+ size_t keylen; -+ } rc4; -+ } u; -+}; -+ -+ -+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, -+ const u8 *iv, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_cipher *ctx; -+ int idx, res, rc4 = 0; -+ -+ switch (alg) { -+ case CRYPTO_CIPHER_ALG_AES: -+ idx = find_cipher("aes"); -+ break; -+ case CRYPTO_CIPHER_ALG_3DES: -+ idx = find_cipher("3des"); -+ break; -+ case CRYPTO_CIPHER_ALG_DES: -+ idx = find_cipher("des"); -+ break; -+ case CRYPTO_CIPHER_ALG_RC2: -+ idx = find_cipher("rc2"); -+ break; -+ case CRYPTO_CIPHER_ALG_RC4: -+ idx = -1; -+ rc4 = 1; -+ break; -+ default: -+ return NULL; -+ } -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ if (rc4) { -+ ctx->rc4 = 1; -+ if (key_len > sizeof(ctx->u.rc4.key)) { -+ os_free(ctx); -+ return NULL; -+ } -+ ctx->u.rc4.keylen = key_len; -+ os_memcpy(ctx->u.rc4.key, key, key_len); -+ } else { -+ res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc); -+ if (res != CRYPT_OK) { -+ wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start " -+ "failed: %s", error_to_string(res)); -+ os_free(ctx); -+ return NULL; -+ } -+ } -+ -+ return ctx; -+} -+ -+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, -+ u8 *crypt, size_t len) -+{ -+ int res; -+ -+ if (ctx->rc4) { -+ if (plain != crypt) -+ os_memcpy(crypt, plain, len); -+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, -+ ctx->u.rc4.used_bytes, crypt, len); -+ ctx->u.rc4.used_bytes += len; -+ return 0; -+ } -+ -+ res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc); -+ if (res != CRYPT_OK) { -+ wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption " -+ "failed: %s", error_to_string(res)); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, -+ u8 *plain, size_t len) -+{ -+ int res; -+ -+ if (ctx->rc4) { -+ if (plain != crypt) -+ os_memcpy(plain, crypt, len); -+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen, -+ ctx->u.rc4.used_bytes, plain, len); -+ ctx->u.rc4.used_bytes += len; -+ return 0; -+ } -+ -+ res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc); -+ if (res != CRYPT_OK) { -+ wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption " -+ "failed: %s", error_to_string(res)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void crypto_cipher_deinit(struct crypto_cipher *ctx) -+{ -+ if (!ctx->rc4) -+ cbc_done(&ctx->u.cbc); -+ os_free(ctx); -+} -+ -+ -+struct crypto_public_key { -+ rsa_key rsa; -+}; -+ -+struct crypto_private_key { -+ rsa_key rsa; -+}; -+ -+ -+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len) -+{ -+ int res; -+ struct crypto_public_key *pk; -+ -+ pk = os_zalloc(sizeof(*pk)); -+ if (pk == NULL) -+ return NULL; -+ -+ res = rsa_import(key, len, &pk->rsa); -+ if (res != CRYPT_OK) { -+ wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " -+ "public key (res=%d '%s')", -+ res, error_to_string(res)); -+ os_free(pk); -+ return NULL; -+ } -+ -+ if (pk->rsa.type != PK_PUBLIC) { -+ wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of " -+ "correct type"); -+ rsa_free(&pk->rsa); -+ os_free(pk); -+ return NULL; -+ } -+ -+ return pk; -+} -+ -+ -+struct crypto_private_key * crypto_private_key_import(const u8 *key, -+ size_t len, -+ const char *passwd) -+{ -+ int res; -+ struct crypto_private_key *pk; -+ -+ pk = os_zalloc(sizeof(*pk)); -+ if (pk == NULL) -+ return NULL; -+ -+ res = rsa_import(key, len, &pk->rsa); -+ if (res != CRYPT_OK) { -+ wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import " -+ "private key (res=%d '%s')", -+ res, error_to_string(res)); -+ os_free(pk); -+ return NULL; -+ } -+ -+ if (pk->rsa.type != PK_PRIVATE) { -+ wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of " -+ "correct type"); -+ rsa_free(&pk->rsa); -+ os_free(pk); -+ return NULL; -+ } -+ -+ return pk; -+} -+ -+ -+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, -+ size_t len) -+{ -+ /* No X.509 support in LibTomCrypt */ -+ return NULL; -+} -+ -+ -+static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ size_t ps_len; -+ u8 *pos; -+ -+ /* -+ * PKCS #1 v1.5, 8.1: -+ * -+ * EB = 00 || BT || PS || 00 || D -+ * BT = 00 or 01 for private-key operation; 02 for public-key operation -+ * PS = k-3-||D||; at least eight octets -+ * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) -+ * k = length of modulus in octets (modlen) -+ */ -+ -+ if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { -+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " -+ "lengths (modlen=%lu outlen=%lu inlen=%lu)", -+ __func__, (unsigned long) modlen, -+ (unsigned long) *outlen, -+ (unsigned long) inlen); -+ return -1; -+ } -+ -+ pos = out; -+ *pos++ = 0x00; -+ *pos++ = block_type; /* BT */ -+ ps_len = modlen - inlen - 3; -+ switch (block_type) { -+ case 0: -+ os_memset(pos, 0x00, ps_len); -+ pos += ps_len; -+ break; -+ case 1: -+ os_memset(pos, 0xff, ps_len); -+ pos += ps_len; -+ break; -+ case 2: -+ if (os_get_random(pos, ps_len) < 0) { -+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " -+ "random data for PS", __func__); -+ return -1; -+ } -+ while (ps_len--) { -+ if (*pos == 0x00) -+ *pos = 0x01; -+ pos++; -+ } -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " -+ "%d", __func__, block_type); -+ return -1; -+ } -+ *pos++ = 0x00; -+ os_memcpy(pos, in, inlen); /* D */ -+ -+ return 0; -+} -+ -+ -+static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ unsigned long len, modlen; -+ int res; -+ -+ modlen = mp_unsigned_bin_size(key->N); -+ -+ if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, -+ out, outlen) < 0) -+ return -1; -+ -+ len = *outlen; -+ res = rsa_exptmod(out, modlen, out, &len, key_type, key); -+ if (res != CRYPT_OK) { -+ wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", -+ error_to_string(res)); -+ return -1; -+ } -+ *outlen = len; -+ -+ return 0; -+} -+ -+ -+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen, -+ out, outlen); -+} -+ -+ -+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen, -+ out, outlen); -+} -+ -+ -+void crypto_public_key_free(struct crypto_public_key *key) -+{ -+ if (key) { -+ rsa_free(&key->rsa); -+ os_free(key); -+ } -+} -+ -+ -+void crypto_private_key_free(struct crypto_private_key *key) -+{ -+ if (key) { -+ rsa_free(&key->rsa); -+ os_free(key); -+ } -+} -+ -+ -+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key, -+ const u8 *crypt, size_t crypt_len, -+ u8 *plain, size_t *plain_len) -+{ -+ int res; -+ unsigned long len; -+ u8 *pos; -+ -+ len = *plain_len; -+ res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC, -+ &key->rsa); -+ if (res != CRYPT_OK) { -+ wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s", -+ error_to_string(res)); -+ return -1; -+ } -+ -+ /* -+ * PKCS #1 v1.5, 8.1: -+ * -+ * EB = 00 || BT || PS || 00 || D -+ * BT = 01 -+ * PS = k-3-||D|| times FF -+ * k = length of modulus in octets -+ */ -+ -+ if (len < 3 + 8 + 16 /* min hash len */ || -+ plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) { -+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " -+ "structure"); -+ return -1; -+ } -+ -+ pos = plain + 3; -+ while (pos < plain + len && *pos == 0xff) -+ pos++; -+ if (pos - plain - 2 < 8) { -+ /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ -+ wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " -+ "padding"); -+ return -1; -+ } -+ -+ if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { -+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " -+ "structure (2)"); -+ return -1; -+ } -+ pos++; -+ len -= pos - plain; -+ -+ /* Strip PKCS #1 header */ -+ os_memmove(plain, pos, len); -+ *plain_len = len; -+ -+ return 0; -+} -+ -+ -+int crypto_global_init(void) -+{ -+ ltc_mp = tfm_desc; -+ /* TODO: only register algorithms that are really needed */ -+ if (register_hash(&md4_desc) < 0 || -+ register_hash(&md5_desc) < 0 || -+ register_hash(&sha1_desc) < 0 || -+ register_cipher(&aes_desc) < 0 || -+ register_cipher(&des_desc) < 0 || -+ register_cipher(&des3_desc) < 0) { -+ wpa_printf(MSG_ERROR, "TLSv1: Failed to register " -+ "hash/cipher functions"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void crypto_global_deinit(void) -+{ -+} -+ -+ -+#ifdef CONFIG_MODEXP -+ -+int crypto_mod_exp(const u8 *base, size_t base_len, -+ const u8 *power, size_t power_len, -+ const u8 *modulus, size_t modulus_len, -+ u8 *result, size_t *result_len) -+{ -+ void *b, *p, *m, *r; -+ -+ if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK) -+ return -1; -+ -+ if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK || -+ mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK || -+ mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK) -+ goto fail; -+ -+ if (mp_exptmod(b, p, m, r) != CRYPT_OK) -+ goto fail; -+ -+ *result_len = mp_unsigned_bin_size(r); -+ if (mp_to_unsigned_bin(r, result) != CRYPT_OK) -+ goto fail; -+ -+ mp_clear_multi(b, p, m, r, NULL); -+ return 0; -+ -+fail: -+ mp_clear_multi(b, p, m, r, NULL); -+ return -1; -+} -+ -+#endif /* CONFIG_MODEXP */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_none.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_none.c -new file mode 100644 -index 0000000000000..9f43775a64622 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_none.c -@@ -0,0 +1,29 @@ -+/* -+ * WPA Supplicant / Empty template functions for crypto wrapper -+ * Copyright (c) 2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+ -+ -+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return 0; -+} -+ -+ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_nss.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_nss.c -new file mode 100644 -index 0000000000000..fee4195ca4e3a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_nss.c -@@ -0,0 +1,213 @@ -+/* -+ * Crypto wrapper functions for NSS -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "crypto.h" -+ -+ -+static int nss_hash(HASH_HashType type, unsigned int max_res_len, -+ size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *mac) -+{ -+ HASHContext *ctx; -+ size_t i; -+ unsigned int reslen; -+ -+ ctx = HASH_Create(type); -+ if (ctx == NULL) -+ return -1; -+ -+ HASH_Begin(ctx); -+ for (i = 0; i < num_elem; i++) -+ HASH_Update(ctx, addr[i], len[i]); -+ HASH_End(ctx, mac, &reslen, max_res_len); -+ HASH_Destroy(ctx); -+ -+ return 0; -+} -+ -+ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -+{ -+ PK11Context *ctx = NULL; -+ PK11SlotInfo *slot; -+ SECItem *param = NULL; -+ PK11SymKey *symkey = NULL; -+ SECItem item; -+ int olen; -+ u8 pkey[8], next, tmp; -+ int i; -+ -+ /* Add parity bits to the key */ -+ next = 0; -+ for (i = 0; i < 7; i++) { -+ tmp = key[i]; -+ pkey[i] = (tmp >> i) | next | 1; -+ next = tmp << (7 - i); -+ } -+ pkey[i] = next | 1; -+ -+ slot = PK11_GetBestSlot(CKM_DES_ECB, NULL); -+ if (slot == NULL) { -+ wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed"); -+ goto out; -+ } -+ -+ item.type = siBuffer; -+ item.data = pkey; -+ item.len = 8; -+ symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive, -+ CKA_ENCRYPT, &item, NULL); -+ if (symkey == NULL) { -+ wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed"); -+ goto out; -+ } -+ -+ param = PK11_GenerateNewParam(CKM_DES_ECB, symkey); -+ if (param == NULL) { -+ wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed"); -+ goto out; -+ } -+ -+ ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT, -+ symkey, param); -+ if (ctx == NULL) { -+ wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey(" -+ "CKM_DES_ECB) failed"); -+ goto out; -+ } -+ -+ if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) != -+ SECSuccess) { -+ wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed"); -+ goto out; -+ } -+ -+out: -+ if (ctx) -+ PK11_DestroyContext(ctx, PR_TRUE); -+ if (symkey) -+ PK11_FreeSymKey(symkey); -+ if (param) -+ SECITEM_FreeItem(param, PR_TRUE); -+} -+ -+ -+int rc4_skip(const u8 *key, size_t keylen, size_t skip, -+ u8 *data, size_t data_len) -+{ -+ return -1; -+} -+ -+ -+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac); -+} -+ -+ -+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac); -+} -+ -+ -+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *mac) -+{ -+ return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac); -+} -+ -+ -+void * aes_encrypt_init(const u8 *key, size_t len) -+{ -+ return NULL; -+} -+ -+ -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -+{ -+} -+ -+ -+void aes_encrypt_deinit(void *ctx) -+{ -+} -+ -+ -+void * aes_decrypt_init(const u8 *key, size_t len) -+{ -+ return NULL; -+} -+ -+ -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -+{ -+} -+ -+ -+void aes_decrypt_deinit(void *ctx) -+{ -+} -+ -+ -+int crypto_mod_exp(const u8 *base, size_t base_len, -+ const u8 *power, size_t power_len, -+ const u8 *modulus, size_t modulus_len, -+ u8 *result, size_t *result_len) -+{ -+ return -1; -+} -+ -+ -+struct crypto_cipher { -+}; -+ -+ -+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, -+ const u8 *iv, const u8 *key, -+ size_t key_len) -+{ -+ return NULL; -+} -+ -+ -+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, -+ u8 *crypt, size_t len) -+{ -+ return -1; -+} -+ -+ -+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, -+ u8 *plain, size_t len) -+{ -+ return -1; -+} -+ -+ -+void crypto_cipher_deinit(struct crypto_cipher *ctx) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_openssl.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_openssl.c -new file mode 100644 -index 0000000000000..08c98aff4ba1f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/crypto_openssl.c -@@ -0,0 +1,505 @@ -+/* -+ * WPA Supplicant / wrapper functions for libcrypto -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "wpabuf.h" -+#include "dh_group5.h" -+#include "crypto.h" -+ -+#if OPENSSL_VERSION_NUMBER < 0x00907000 -+#define DES_key_schedule des_key_schedule -+#define DES_cblock des_cblock -+#define DES_set_key(key, schedule) des_set_key((key), *(schedule)) -+#define DES_ecb_encrypt(input, output, ks, enc) \ -+ des_ecb_encrypt((input), (output), *(ks), (enc)) -+#endif /* openssl < 0.9.7 */ -+ -+static BIGNUM * get_group5_prime(void) -+{ -+#if OPENSSL_VERSION_NUMBER < 0x00908000 -+ static const unsigned char RFC3526_PRIME_1536[] = { -+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, -+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, -+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6, -+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, -+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D, -+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45, -+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9, -+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED, -+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11, -+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D, -+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36, -+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F, -+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56, -+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D, -+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08, -+ 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, -+ }; -+ return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL); -+#else /* openssl < 0.9.8 */ -+ return get_rfc3526_prime_1536(NULL); -+#endif /* openssl < 0.9.8 */ -+} -+ -+#if OPENSSL_VERSION_NUMBER < 0x00908000 -+#ifndef OPENSSL_NO_SHA256 -+#ifndef OPENSSL_FIPS -+#define NO_SHA256_WRAPPER -+#endif -+#endif -+ -+#endif /* openssl < 0.9.8 */ -+ -+#ifdef OPENSSL_NO_SHA256 -+#define NO_SHA256_WRAPPER -+#endif -+ -+static int openssl_digest_vector(const EVP_MD *type, int non_fips, -+ size_t num_elem, const u8 *addr[], -+ const size_t *len, u8 *mac) -+{ -+ EVP_MD_CTX ctx; -+ size_t i; -+ unsigned int mac_len; -+ -+ EVP_MD_CTX_init(&ctx); -+#ifdef CONFIG_FIPS -+#ifdef OPENSSL_FIPS -+ if (non_fips) -+ EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); -+#endif /* OPENSSL_FIPS */ -+#endif /* CONFIG_FIPS */ -+ if (!EVP_DigestInit_ex(&ctx, type, NULL)) { -+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s", -+ ERR_error_string(ERR_get_error(), NULL)); -+ return -1; -+ } -+ for (i = 0; i < num_elem; i++) { -+ if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) { -+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate " -+ "failed: %s", -+ ERR_error_string(ERR_get_error(), NULL)); -+ return -1; -+ } -+ } -+ if (!EVP_DigestFinal(&ctx, mac, &mac_len)) { -+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s", -+ ERR_error_string(ERR_get_error(), NULL)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac); -+} -+ -+ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -+{ -+ u8 pkey[8], next, tmp; -+ int i; -+ DES_key_schedule ks; -+ -+ /* Add parity bits to the key */ -+ next = 0; -+ for (i = 0; i < 7; i++) { -+ tmp = key[i]; -+ pkey[i] = (tmp >> i) | next | 1; -+ next = tmp << (7 - i); -+ } -+ pkey[i] = next | 1; -+ -+ DES_set_key(&pkey, &ks); -+ DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks, -+ DES_ENCRYPT); -+} -+ -+ -+int rc4_skip(const u8 *key, size_t keylen, size_t skip, -+ u8 *data, size_t data_len) -+{ -+#ifdef OPENSSL_NO_RC4 -+ return -1; -+#else /* OPENSSL_NO_RC4 */ -+ EVP_CIPHER_CTX ctx; -+ int outl; -+ int res = -1; -+ unsigned char skip_buf[16]; -+ -+ EVP_CIPHER_CTX_init(&ctx); -+ if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) || -+ !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) || -+ !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) || -+ !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1)) -+ goto out; -+ -+ while (skip >= sizeof(skip_buf)) { -+ size_t len = skip; -+ if (len > sizeof(skip_buf)) -+ len = sizeof(skip_buf); -+ if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len)) -+ goto out; -+ skip -= len; -+ } -+ -+ if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len)) -+ res = 0; -+ -+out: -+ EVP_CIPHER_CTX_cleanup(&ctx); -+ return res; -+#endif /* OPENSSL_NO_RC4 */ -+} -+ -+ -+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac); -+} -+ -+ -+#ifdef CONFIG_FIPS -+int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], -+ const size_t *len, u8 *mac) -+{ -+ return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac); -+} -+#endif /* CONFIG_FIPS */ -+ -+ -+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac); -+} -+ -+ -+#ifndef NO_SHA256_WRAPPER -+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *mac) -+{ -+ return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len, -+ mac); -+} -+#endif /* NO_SHA256_WRAPPER */ -+ -+ -+void * aes_encrypt_init(const u8 *key, size_t len) -+{ -+ AES_KEY *ak; -+ ak = os_malloc(sizeof(*ak)); -+ if (ak == NULL) -+ return NULL; -+ if (AES_set_encrypt_key(key, 8 * len, ak) < 0) { -+ os_free(ak); -+ return NULL; -+ } -+ return ak; -+} -+ -+ -+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -+{ -+ AES_encrypt(plain, crypt, ctx); -+} -+ -+ -+void aes_encrypt_deinit(void *ctx) -+{ -+ os_free(ctx); -+} -+ -+ -+void * aes_decrypt_init(const u8 *key, size_t len) -+{ -+ AES_KEY *ak; -+ ak = os_malloc(sizeof(*ak)); -+ if (ak == NULL) -+ return NULL; -+ if (AES_set_decrypt_key(key, 8 * len, ak) < 0) { -+ os_free(ak); -+ return NULL; -+ } -+ return ak; -+} -+ -+ -+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) -+{ -+ AES_decrypt(crypt, plain, ctx); -+} -+ -+ -+void aes_decrypt_deinit(void *ctx) -+{ -+ os_free(ctx); -+} -+ -+ -+int crypto_mod_exp(const u8 *base, size_t base_len, -+ const u8 *power, size_t power_len, -+ const u8 *modulus, size_t modulus_len, -+ u8 *result, size_t *result_len) -+{ -+ BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result; -+ int ret = -1; -+ BN_CTX *ctx; -+ -+ ctx = BN_CTX_new(); -+ if (ctx == NULL) -+ return -1; -+ -+ bn_base = BN_bin2bn(base, base_len, NULL); -+ bn_exp = BN_bin2bn(power, power_len, NULL); -+ bn_modulus = BN_bin2bn(modulus, modulus_len, NULL); -+ bn_result = BN_new(); -+ -+ if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || -+ bn_result == NULL) -+ goto error; -+ -+ if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1) -+ goto error; -+ -+ *result_len = BN_bn2bin(bn_result, result); -+ ret = 0; -+ -+error: -+ BN_free(bn_base); -+ BN_free(bn_exp); -+ BN_free(bn_modulus); -+ BN_free(bn_result); -+ BN_CTX_free(ctx); -+ return ret; -+} -+ -+ -+struct crypto_cipher { -+ EVP_CIPHER_CTX enc; -+ EVP_CIPHER_CTX dec; -+}; -+ -+ -+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, -+ const u8 *iv, const u8 *key, -+ size_t key_len) -+{ -+ struct crypto_cipher *ctx; -+ const EVP_CIPHER *cipher; -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) -+ return NULL; -+ -+ switch (alg) { -+#ifndef OPENSSL_NO_RC4 -+ case CRYPTO_CIPHER_ALG_RC4: -+ cipher = EVP_rc4(); -+ break; -+#endif /* OPENSSL_NO_RC4 */ -+#ifndef OPENSSL_NO_AES -+ case CRYPTO_CIPHER_ALG_AES: -+ switch (key_len) { -+ case 16: -+ cipher = EVP_aes_128_cbc(); -+ break; -+ case 24: -+ cipher = EVP_aes_192_cbc(); -+ break; -+ case 32: -+ cipher = EVP_aes_256_cbc(); -+ break; -+ default: -+ os_free(ctx); -+ return NULL; -+ } -+ break; -+#endif /* OPENSSL_NO_AES */ -+#ifndef OPENSSL_NO_DES -+ case CRYPTO_CIPHER_ALG_3DES: -+ cipher = EVP_des_ede3_cbc(); -+ break; -+ case CRYPTO_CIPHER_ALG_DES: -+ cipher = EVP_des_cbc(); -+ break; -+#endif /* OPENSSL_NO_DES */ -+#ifndef OPENSSL_NO_RC2 -+ case CRYPTO_CIPHER_ALG_RC2: -+ cipher = EVP_rc2_ecb(); -+ break; -+#endif /* OPENSSL_NO_RC2 */ -+ default: -+ os_free(ctx); -+ return NULL; -+ } -+ -+ EVP_CIPHER_CTX_init(&ctx->enc); -+ EVP_CIPHER_CTX_set_padding(&ctx->enc, 0); -+ if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) || -+ !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) || -+ !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) { -+ EVP_CIPHER_CTX_cleanup(&ctx->enc); -+ os_free(ctx); -+ return NULL; -+ } -+ -+ EVP_CIPHER_CTX_init(&ctx->dec); -+ EVP_CIPHER_CTX_set_padding(&ctx->dec, 0); -+ if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) || -+ !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) || -+ !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) { -+ EVP_CIPHER_CTX_cleanup(&ctx->enc); -+ EVP_CIPHER_CTX_cleanup(&ctx->dec); -+ os_free(ctx); -+ return NULL; -+ } -+ -+ return ctx; -+} -+ -+ -+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain, -+ u8 *crypt, size_t len) -+{ -+ int outl; -+ if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len)) -+ return -1; -+ return 0; -+} -+ -+ -+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt, -+ u8 *plain, size_t len) -+{ -+ int outl; -+ outl = len; -+ if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len)) -+ return -1; -+ return 0; -+} -+ -+ -+void crypto_cipher_deinit(struct crypto_cipher *ctx) -+{ -+ EVP_CIPHER_CTX_cleanup(&ctx->enc); -+ EVP_CIPHER_CTX_cleanup(&ctx->dec); -+ os_free(ctx); -+} -+ -+ -+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) -+{ -+ DH *dh; -+ struct wpabuf *pubkey = NULL, *privkey = NULL; -+ size_t publen, privlen; -+ -+ *priv = NULL; -+ *publ = NULL; -+ -+ dh = DH_new(); -+ if (dh == NULL) -+ return NULL; -+ -+ dh->g = BN_new(); -+ if (dh->g == NULL || BN_set_word(dh->g, 2) != 1) -+ goto err; -+ -+ dh->p = get_group5_prime(); -+ if (dh->p == NULL) -+ goto err; -+ -+ if (DH_generate_key(dh) != 1) -+ goto err; -+ -+ publen = BN_num_bytes(dh->pub_key); -+ pubkey = wpabuf_alloc(publen); -+ if (pubkey == NULL) -+ goto err; -+ privlen = BN_num_bytes(dh->priv_key); -+ privkey = wpabuf_alloc(privlen); -+ if (privkey == NULL) -+ goto err; -+ -+ BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen)); -+ BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen)); -+ -+ *priv = privkey; -+ *publ = pubkey; -+ return dh; -+ -+err: -+ wpabuf_free(pubkey); -+ wpabuf_free(privkey); -+ DH_free(dh); -+ return NULL; -+} -+ -+ -+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, -+ const struct wpabuf *own_private) -+{ -+ BIGNUM *pub_key; -+ struct wpabuf *res = NULL; -+ size_t rlen; -+ DH *dh = ctx; -+ int keylen; -+ -+ if (ctx == NULL) -+ return NULL; -+ -+ pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public), -+ NULL); -+ if (pub_key == NULL) -+ return NULL; -+ -+ rlen = DH_size(dh); -+ res = wpabuf_alloc(rlen); -+ if (res == NULL) -+ goto err; -+ -+ keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh); -+ if (keylen < 0) -+ goto err; -+ wpabuf_put(res, keylen); -+ BN_free(pub_key); -+ -+ return res; -+ -+err: -+ BN_free(pub_key); -+ wpabuf_free(res); -+ return NULL; -+} -+ -+ -+void dh5_free(void *ctx) -+{ -+ DH *dh; -+ if (ctx == NULL) -+ return; -+ dh = ctx; -+ DH_free(dh); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des-internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des-internal.c -new file mode 100644 -index 0000000000000..ccea9503216ea ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des-internal.c -@@ -0,0 +1,499 @@ -+/* -+ * DES and 3DES-EDE ciphers -+ * -+ * Modifications to LibTomCrypt implementation: -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "des_i.h" -+ -+/* -+ * This implementation is based on a DES implementation included in -+ * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd -+ * coding style. -+ */ -+ -+/* LibTomCrypt, modular cryptographic library -- Tom St Denis -+ * -+ * LibTomCrypt is a library that provides various cryptographic -+ * algorithms in a highly modular and flexible manner. -+ * -+ * The library is free for all purposes without any express -+ * guarantee it works. -+ * -+ * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com -+ */ -+ -+/** -+ DES code submitted by Dobes Vandermeer -+*/ -+ -+#define ROLc(x, y) \ -+ ((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \ -+ (((unsigned long) (x) & 0xFFFFFFFFUL) >> \ -+ (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) -+#define RORc(x, y) \ -+ (((((unsigned long) (x) & 0xFFFFFFFFUL) >> \ -+ (unsigned long) ((y) & 31)) | \ -+ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \ -+ 0xFFFFFFFFUL) -+ -+ -+static const u32 bytebit[8] = -+{ -+ 0200, 0100, 040, 020, 010, 04, 02, 01 -+}; -+ -+static const u32 bigbyte[24] = -+{ -+ 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL, -+ 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL, -+ 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL, -+ 0x800UL, 0x400UL, 0x200UL, 0x100UL, -+ 0x80UL, 0x40UL, 0x20UL, 0x10UL, -+ 0x8UL, 0x4UL, 0x2UL, 0x1L -+}; -+ -+/* Use the key schedule specific in the standard (ANSI X3.92-1981) */ -+ -+static const u8 pc1[56] = { -+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, -+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, -+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, -+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 -+}; -+ -+static const u8 totrot[16] = { -+ 1, 2, 4, 6, -+ 8, 10, 12, 14, -+ 15, 17, 19, 21, -+ 23, 25, 27, 28 -+}; -+ -+static const u8 pc2[48] = { -+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, -+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, -+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, -+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 -+}; -+ -+ -+static const u32 SP1[64] = -+{ -+ 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, -+ 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, -+ 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, -+ 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, -+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, -+ 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, -+ 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, -+ 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, -+ 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, -+ 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, -+ 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, -+ 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, -+ 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, -+ 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, -+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, -+ 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL -+}; -+ -+static const u32 SP2[64] = -+{ -+ 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, -+ 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, -+ 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, -+ 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, -+ 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, -+ 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, -+ 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, -+ 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, -+ 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, -+ 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, -+ 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, -+ 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, -+ 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, -+ 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, -+ 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, -+ 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL -+}; -+ -+static const u32 SP3[64] = -+{ -+ 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, -+ 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, -+ 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, -+ 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, -+ 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, -+ 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, -+ 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, -+ 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, -+ 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, -+ 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, -+ 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, -+ 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, -+ 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, -+ 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, -+ 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, -+ 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL -+}; -+ -+static const u32 SP4[64] = -+{ -+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, -+ 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, -+ 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, -+ 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, -+ 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, -+ 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, -+ 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, -+ 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, -+ 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, -+ 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, -+ 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, -+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, -+ 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, -+ 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, -+ 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, -+ 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL -+}; -+ -+static const u32 SP5[64] = -+{ -+ 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, -+ 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, -+ 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, -+ 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, -+ 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, -+ 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, -+ 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, -+ 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, -+ 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, -+ 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, -+ 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, -+ 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, -+ 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, -+ 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, -+ 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, -+ 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL -+}; -+ -+static const u32 SP6[64] = -+{ -+ 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, -+ 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, -+ 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, -+ 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, -+ 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, -+ 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, -+ 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, -+ 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, -+ 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, -+ 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, -+ 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, -+ 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, -+ 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, -+ 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, -+ 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, -+ 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL -+}; -+ -+static const u32 SP7[64] = -+{ -+ 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, -+ 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, -+ 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, -+ 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, -+ 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, -+ 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, -+ 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, -+ 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, -+ 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, -+ 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, -+ 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, -+ 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, -+ 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, -+ 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, -+ 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, -+ 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL -+}; -+ -+static const u32 SP8[64] = -+{ -+ 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, -+ 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, -+ 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, -+ 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, -+ 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, -+ 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, -+ 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, -+ 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, -+ 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, -+ 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, -+ 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, -+ 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, -+ 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, -+ 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, -+ 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, -+ 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL -+}; -+ -+ -+static void cookey(const u32 *raw1, u32 *keyout) -+{ -+ u32 *cook; -+ const u32 *raw0; -+ u32 dough[32]; -+ int i; -+ -+ cook = dough; -+ for (i = 0; i < 16; i++, raw1++) { -+ raw0 = raw1++; -+ *cook = (*raw0 & 0x00fc0000L) << 6; -+ *cook |= (*raw0 & 0x00000fc0L) << 10; -+ *cook |= (*raw1 & 0x00fc0000L) >> 10; -+ *cook++ |= (*raw1 & 0x00000fc0L) >> 6; -+ *cook = (*raw0 & 0x0003f000L) << 12; -+ *cook |= (*raw0 & 0x0000003fL) << 16; -+ *cook |= (*raw1 & 0x0003f000L) >> 4; -+ *cook++ |= (*raw1 & 0x0000003fL); -+ } -+ -+ os_memcpy(keyout, dough, sizeof(dough)); -+} -+ -+ -+static void deskey(const u8 *key, int decrypt, u32 *keyout) -+{ -+ u32 i, j, l, m, n, kn[32]; -+ u8 pc1m[56], pcr[56]; -+ -+ for (j = 0; j < 56; j++) { -+ l = (u32) pc1[j]; -+ m = l & 7; -+ pc1m[j] = (u8) -+ ((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0); -+ } -+ -+ for (i = 0; i < 16; i++) { -+ if (decrypt) -+ m = (15 - i) << 1; -+ else -+ m = i << 1; -+ n = m + 1; -+ kn[m] = kn[n] = 0L; -+ for (j = 0; j < 28; j++) { -+ l = j + (u32) totrot[i]; -+ if (l < 28) -+ pcr[j] = pc1m[l]; -+ else -+ pcr[j] = pc1m[l - 28]; -+ } -+ for (/* j = 28 */; j < 56; j++) { -+ l = j + (u32) totrot[i]; -+ if (l < 56) -+ pcr[j] = pc1m[l]; -+ else -+ pcr[j] = pc1m[l - 28]; -+ } -+ for (j = 0; j < 24; j++) { -+ if ((int) pcr[(int) pc2[j]] != 0) -+ kn[m] |= bigbyte[j]; -+ if ((int) pcr[(int) pc2[j + 24]] != 0) -+ kn[n] |= bigbyte[j]; -+ } -+ } -+ -+ cookey(kn, keyout); -+} -+ -+ -+static void desfunc(u32 *block, const u32 *keys) -+{ -+ u32 work, right, leftt; -+ int cur_round; -+ -+ leftt = block[0]; -+ right = block[1]; -+ -+ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; -+ right ^= work; -+ leftt ^= (work << 4); -+ -+ work = ((leftt >> 16) ^ right) & 0x0000ffffL; -+ right ^= work; -+ leftt ^= (work << 16); -+ -+ work = ((right >> 2) ^ leftt) & 0x33333333L; -+ leftt ^= work; -+ right ^= (work << 2); -+ -+ work = ((right >> 8) ^ leftt) & 0x00ff00ffL; -+ leftt ^= work; -+ right ^= (work << 8); -+ -+ right = ROLc(right, 1); -+ work = (leftt ^ right) & 0xaaaaaaaaL; -+ -+ leftt ^= work; -+ right ^= work; -+ leftt = ROLc(leftt, 1); -+ -+ for (cur_round = 0; cur_round < 8; cur_round++) { -+ work = RORc(right, 4) ^ *keys++; -+ leftt ^= SP7[work & 0x3fL] -+ ^ SP5[(work >> 8) & 0x3fL] -+ ^ SP3[(work >> 16) & 0x3fL] -+ ^ SP1[(work >> 24) & 0x3fL]; -+ work = right ^ *keys++; -+ leftt ^= SP8[ work & 0x3fL] -+ ^ SP6[(work >> 8) & 0x3fL] -+ ^ SP4[(work >> 16) & 0x3fL] -+ ^ SP2[(work >> 24) & 0x3fL]; -+ -+ work = RORc(leftt, 4) ^ *keys++; -+ right ^= SP7[ work & 0x3fL] -+ ^ SP5[(work >> 8) & 0x3fL] -+ ^ SP3[(work >> 16) & 0x3fL] -+ ^ SP1[(work >> 24) & 0x3fL]; -+ work = leftt ^ *keys++; -+ right ^= SP8[ work & 0x3fL] -+ ^ SP6[(work >> 8) & 0x3fL] -+ ^ SP4[(work >> 16) & 0x3fL] -+ ^ SP2[(work >> 24) & 0x3fL]; -+ } -+ -+ right = RORc(right, 1); -+ work = (leftt ^ right) & 0xaaaaaaaaL; -+ leftt ^= work; -+ right ^= work; -+ leftt = RORc(leftt, 1); -+ work = ((leftt >> 8) ^ right) & 0x00ff00ffL; -+ right ^= work; -+ leftt ^= (work << 8); -+ /* -- */ -+ work = ((leftt >> 2) ^ right) & 0x33333333L; -+ right ^= work; -+ leftt ^= (work << 2); -+ work = ((right >> 16) ^ leftt) & 0x0000ffffL; -+ leftt ^= work; -+ right ^= (work << 16); -+ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; -+ leftt ^= work; -+ right ^= (work << 4); -+ -+ block[0] = right; -+ block[1] = leftt; -+} -+ -+ -+/* wpa_supplicant/hostapd specific wrapper */ -+ -+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) -+{ -+ u8 pkey[8], next, tmp; -+ int i; -+ u32 ek[32], work[2]; -+ -+ /* Add parity bits to the key */ -+ next = 0; -+ for (i = 0; i < 7; i++) { -+ tmp = key[i]; -+ pkey[i] = (tmp >> i) | next | 1; -+ next = tmp << (7 - i); -+ } -+ pkey[i] = next | 1; -+ -+ deskey(pkey, 0, ek); -+ -+ work[0] = WPA_GET_BE32(clear); -+ work[1] = WPA_GET_BE32(clear + 4); -+ desfunc(work, ek); -+ WPA_PUT_BE32(cypher, work[0]); -+ WPA_PUT_BE32(cypher + 4, work[1]); -+ -+ os_memset(pkey, 0, sizeof(pkey)); -+ os_memset(ek, 0, sizeof(ek)); -+} -+ -+ -+void des_key_setup(const u8 *key, u32 *ek, u32 *dk) -+{ -+ deskey(key, 0, ek); -+ deskey(key, 1, dk); -+} -+ -+ -+void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt) -+{ -+ u32 work[2]; -+ work[0] = WPA_GET_BE32(plain); -+ work[1] = WPA_GET_BE32(plain + 4); -+ desfunc(work, ek); -+ WPA_PUT_BE32(crypt, work[0]); -+ WPA_PUT_BE32(crypt + 4, work[1]); -+} -+ -+ -+void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain) -+{ -+ u32 work[2]; -+ work[0] = WPA_GET_BE32(crypt); -+ work[1] = WPA_GET_BE32(crypt + 4); -+ desfunc(work, dk); -+ WPA_PUT_BE32(plain, work[0]); -+ WPA_PUT_BE32(plain + 4, work[1]); -+} -+ -+ -+void des3_key_setup(const u8 *key, struct des3_key_s *dkey) -+{ -+ deskey(key, 0, dkey->ek[0]); -+ deskey(key + 8, 1, dkey->ek[1]); -+ deskey(key + 16, 0, dkey->ek[2]); -+ -+ deskey(key, 1, dkey->dk[2]); -+ deskey(key + 8, 0, dkey->dk[1]); -+ deskey(key + 16, 1, dkey->dk[0]); -+} -+ -+ -+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt) -+{ -+ u32 work[2]; -+ -+ work[0] = WPA_GET_BE32(plain); -+ work[1] = WPA_GET_BE32(plain + 4); -+ desfunc(work, key->ek[0]); -+ desfunc(work, key->ek[1]); -+ desfunc(work, key->ek[2]); -+ WPA_PUT_BE32(crypt, work[0]); -+ WPA_PUT_BE32(crypt + 4, work[1]); -+} -+ -+ -+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain) -+{ -+ u32 work[2]; -+ -+ work[0] = WPA_GET_BE32(crypt); -+ work[1] = WPA_GET_BE32(crypt + 4); -+ desfunc(work, key->dk[0]); -+ desfunc(work, key->dk[1]); -+ desfunc(work, key->dk[2]); -+ WPA_PUT_BE32(plain, work[0]); -+ WPA_PUT_BE32(plain + 4, work[1]); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des_i.h -new file mode 100644 -index 0000000000000..6f274144a0e61 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/des_i.h -@@ -0,0 +1,31 @@ -+/* -+ * DES and 3DES-EDE ciphers -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef DES_I_H -+#define DES_I_H -+ -+struct des3_key_s { -+ u32 ek[3][32]; -+ u32 dk[3][32]; -+}; -+ -+void des_key_setup(const u8 *key, u32 *ek, u32 *dk); -+void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt); -+void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain); -+ -+void des3_key_setup(const u8 *key, struct des3_key_s *dkey); -+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); -+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); -+ -+#endif /* DES_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.c -new file mode 100644 -index 0000000000000..8c475bf94ae9f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.c -@@ -0,0 +1,40 @@ -+/* -+ * Diffie-Hellman group 5 operations -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "dh_groups.h" -+#include "dh_group5.h" -+ -+ -+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) -+{ -+ *publ = dh_init(dh_groups_get(5), priv); -+ if (*publ == 0) -+ return NULL; -+ return (void *) 1; -+} -+ -+ -+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, -+ const struct wpabuf *own_private) -+{ -+ return dh_derive_shared(peer_public, own_private, dh_groups_get(5)); -+} -+ -+ -+void dh5_free(void *ctx) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.h -new file mode 100644 -index 0000000000000..595f1114fe2be ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_group5.h -@@ -0,0 +1,23 @@ -+/* -+ * Diffie-Hellman group 5 operations -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef DH_GROUP5_H -+#define DH_GROUP5_H -+ -+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ); -+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, -+ const struct wpabuf *own_private); -+void dh5_free(void *ctx); -+ -+#endif /* DH_GROUP5_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.c -new file mode 100644 -index 0000000000000..e5b7d4c7a38aa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.c -@@ -0,0 +1,633 @@ -+/* -+ * Diffie-Hellman groups -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+#include "random.h" -+#include "dh_groups.h" -+ -+ -+#ifdef ALL_DH_GROUPS -+ -+/* RFC 4306, B.1. Group 1 - 768 Bit MODP -+ * Generator: 2 -+ * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } -+ */ -+static const u8 dh_group1_generator[1] = { 0x02 }; -+static const u8 dh_group1_prime[96] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+/* RFC 4306, B.2. Group 2 - 1024 Bit MODP -+ * Generator: 2 -+ * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } -+ */ -+static const u8 dh_group2_generator[1] = { 0x02 }; -+static const u8 dh_group2_prime[128] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, -+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, -+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, -+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, -+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+#endif /* ALL_DH_GROUPS */ -+ -+/* RFC 3526, 2. Group 5 - 1536 Bit MODP -+ * Generator: 2 -+ * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } -+ */ -+static const u8 dh_group5_generator[1] = { 0x02 }; -+static const u8 dh_group5_prime[192] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, -+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, -+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, -+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, -+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, -+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, -+ 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, -+ 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, -+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, -+ 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, -+ 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, -+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, -+ 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+#ifdef ALL_DH_GROUPS -+ -+/* RFC 3526, 3. Group 14 - 2048 Bit MODP -+ * Generator: 2 -+ * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } -+ */ -+static const u8 dh_group14_generator[1] = { 0x02 }; -+static const u8 dh_group14_prime[256] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, -+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, -+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, -+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, -+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, -+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, -+ 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, -+ 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, -+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, -+ 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, -+ 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, -+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, -+ 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, -+ 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, -+ 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, -+ 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, -+ 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, -+ 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, -+ 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, -+ 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, -+ 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+/* RFC 3526, 4. Group 15 - 3072 Bit MODP -+ * Generator: 2 -+ * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } -+ */ -+static const u8 dh_group15_generator[1] = { 0x02 }; -+static const u8 dh_group15_prime[384] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, -+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, -+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, -+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, -+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, -+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, -+ 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, -+ 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, -+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, -+ 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, -+ 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, -+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, -+ 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, -+ 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, -+ 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, -+ 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, -+ 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, -+ 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, -+ 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, -+ 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, -+ 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, -+ 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, -+ 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, -+ 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, -+ 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, -+ 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, -+ 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, -+ 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, -+ 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, -+ 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, -+ 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, -+ 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, -+ 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, -+ 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, -+ 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, -+ 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, -+ 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+/* RFC 3526, 5. Group 16 - 4096 Bit MODP -+ * Generator: 2 -+ * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } -+ */ -+static const u8 dh_group16_generator[1] = { 0x02 }; -+static const u8 dh_group16_prime[512] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, -+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, -+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, -+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, -+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, -+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, -+ 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, -+ 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, -+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, -+ 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, -+ 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, -+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, -+ 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, -+ 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, -+ 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, -+ 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, -+ 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, -+ 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, -+ 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, -+ 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, -+ 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, -+ 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, -+ 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, -+ 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, -+ 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, -+ 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, -+ 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, -+ 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, -+ 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, -+ 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, -+ 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, -+ 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, -+ 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, -+ 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, -+ 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, -+ 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, -+ 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, -+ 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, -+ 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, -+ 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, -+ 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, -+ 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, -+ 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, -+ 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, -+ 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, -+ 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, -+ 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, -+ 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, -+ 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, -+ 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, -+ 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, -+ 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, -+ 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+/* RFC 3526, 6. Group 17 - 6144 Bit MODP -+ * Generator: 2 -+ * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } -+ */ -+static const u8 dh_group17_generator[1] = { 0x02 }; -+static const u8 dh_group17_prime[768] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, -+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, -+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, -+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, -+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, -+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, -+ 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, -+ 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, -+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, -+ 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, -+ 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, -+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, -+ 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, -+ 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, -+ 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, -+ 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, -+ 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, -+ 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, -+ 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, -+ 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, -+ 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, -+ 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, -+ 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, -+ 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, -+ 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, -+ 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, -+ 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, -+ 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, -+ 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, -+ 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, -+ 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, -+ 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, -+ 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, -+ 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, -+ 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, -+ 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, -+ 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, -+ 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, -+ 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, -+ 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, -+ 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, -+ 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, -+ 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, -+ 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, -+ 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, -+ 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, -+ 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, -+ 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, -+ 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, -+ 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, -+ 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, -+ 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, -+ 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, -+ 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, -+ 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, -+ 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, -+ 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, -+ 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, -+ 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, -+ 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, -+ 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, -+ 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, -+ 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, -+ 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, -+ 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, -+ 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, -+ 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, -+ 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, -+ 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, -+ 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, -+ 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, -+ 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, -+ 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, -+ 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, -+ 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, -+ 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, -+ 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, -+ 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, -+ 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, -+ 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, -+ 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, -+ 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, -+ 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, -+ 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, -+ 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+/* RFC 3526, 7. Group 18 - 8192 Bit MODP -+ * Generator: 2 -+ * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } -+ */ -+static const u8 dh_group18_generator[1] = { 0x02 }; -+static const u8 dh_group18_prime[1024] = { -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -+ 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, -+ 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, -+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, -+ 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, -+ 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, -+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, -+ 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, -+ 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, -+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, -+ 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, -+ 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, -+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, -+ 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, -+ 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, -+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, -+ 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, -+ 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, -+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, -+ 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, -+ 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, -+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, -+ 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, -+ 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, -+ 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, -+ 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, -+ 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, -+ 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, -+ 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, -+ 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, -+ 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, -+ 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, -+ 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, -+ 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, -+ 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, -+ 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, -+ 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, -+ 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, -+ 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, -+ 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, -+ 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, -+ 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, -+ 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, -+ 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, -+ 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, -+ 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, -+ 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, -+ 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, -+ 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, -+ 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, -+ 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, -+ 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, -+ 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, -+ 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, -+ 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, -+ 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, -+ 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, -+ 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, -+ 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, -+ 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, -+ 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, -+ 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, -+ 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, -+ 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, -+ 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, -+ 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, -+ 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, -+ 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, -+ 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, -+ 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, -+ 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, -+ 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, -+ 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, -+ 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, -+ 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, -+ 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, -+ 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, -+ 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, -+ 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, -+ 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, -+ 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, -+ 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, -+ 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, -+ 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, -+ 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, -+ 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, -+ 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, -+ 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, -+ 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, -+ 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, -+ 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, -+ 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, -+ 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, -+ 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, -+ 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, -+ 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, -+ 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, -+ 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, -+ 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, -+ 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, -+ 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, -+ 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, -+ 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, -+ 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, -+ 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, -+ 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, -+ 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, -+ 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, -+ 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, -+ 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, -+ 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, -+ 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, -+ 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, -+ 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, -+ 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, -+ 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, -+ 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, -+ 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, -+ 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, -+ 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, -+ 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, -+ 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, -+ 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, -+ 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, -+ 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, -+ 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, -+ 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, -+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -+}; -+ -+#endif /* ALL_DH_GROUPS */ -+ -+ -+#define DH_GROUP(id) \ -+{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \ -+dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) } -+ -+ -+static struct dh_group dh_groups[] = { -+ DH_GROUP(5), -+#ifdef ALL_DH_GROUPS -+ DH_GROUP(1), -+ DH_GROUP(2), -+ DH_GROUP(14), -+ DH_GROUP(15), -+ DH_GROUP(16), -+ DH_GROUP(17), -+ DH_GROUP(18) -+#endif /* ALL_DH_GROUPS */ -+}; -+ -+#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0])) -+ -+ -+const struct dh_group * dh_groups_get(int id) -+{ -+ size_t i; -+ -+ for (i = 0; i < NUM_DH_GROUPS; i++) { -+ if (dh_groups[i].id == id) -+ return &dh_groups[i]; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * dh_init - Initialize Diffie-Hellman handshake -+ * @dh: Selected Diffie-Hellman group -+ * @priv: Pointer for returning Diffie-Hellman private key -+ * Returns: Diffie-Hellman public value -+ */ -+struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv) -+{ -+ struct wpabuf *pv; -+ size_t pv_len; -+ -+ if (dh == NULL) -+ return NULL; -+ -+ wpabuf_free(*priv); -+ *priv = wpabuf_alloc(dh->prime_len); -+ if (*priv == NULL) -+ return NULL; -+ -+ if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) -+ { -+ wpabuf_free(*priv); -+ *priv = NULL; -+ return NULL; -+ } -+ -+ if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) { -+ /* Make sure private value is smaller than prime */ -+ *(wpabuf_mhead_u8(*priv)) = 0; -+ } -+ wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv); -+ -+ pv_len = dh->prime_len; -+ pv = wpabuf_alloc(pv_len); -+ if (pv == NULL) -+ return NULL; -+ if (crypto_mod_exp(dh->generator, dh->generator_len, -+ wpabuf_head(*priv), wpabuf_len(*priv), -+ dh->prime, dh->prime_len, wpabuf_mhead(pv), -+ &pv_len) < 0) { -+ wpabuf_free(pv); -+ wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); -+ return NULL; -+ } -+ wpabuf_put(pv, pv_len); -+ wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv); -+ -+ return pv; -+} -+ -+ -+/** -+ * dh_derive_shared - Derive shared Diffie-Hellman key -+ * @peer_public: Diffie-Hellman public value from peer -+ * @own_private: Diffie-Hellman private key from dh_init() -+ * @dh: Selected Diffie-Hellman group -+ * Returns: Diffie-Hellman shared key -+ */ -+struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, -+ const struct wpabuf *own_private, -+ const struct dh_group *dh) -+{ -+ struct wpabuf *shared; -+ size_t shared_len; -+ -+ if (dh == NULL || peer_public == NULL || own_private == NULL) -+ return NULL; -+ -+ shared_len = dh->prime_len; -+ shared = wpabuf_alloc(shared_len); -+ if (shared == NULL) -+ return NULL; -+ if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), -+ wpabuf_head(own_private), wpabuf_len(own_private), -+ dh->prime, dh->prime_len, -+ wpabuf_mhead(shared), &shared_len) < 0) { -+ wpabuf_free(shared); -+ wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); -+ return NULL; -+ } -+ wpabuf_put(shared, shared_len); -+ wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared); -+ -+ return shared; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.h -new file mode 100644 -index 0000000000000..5c61539b70029 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/dh_groups.h -@@ -0,0 +1,32 @@ -+/* -+ * Diffie-Hellman groups -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef DH_GROUPS_H -+#define DH_GROUPS_H -+ -+struct dh_group { -+ int id; -+ const u8 *generator; -+ size_t generator_len; -+ const u8 *prime; -+ size_t prime_len; -+}; -+ -+const struct dh_group * dh_groups_get(int id); -+struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv); -+struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public, -+ const struct wpabuf *own_private, -+ const struct dh_group *dh); -+ -+#endif /* DH_GROUPS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_cryptoapi.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_cryptoapi.c -new file mode 100644 -index 0000000000000..17d3116e8b579 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_cryptoapi.c -@@ -0,0 +1,25 @@ -+/* -+ * FIPS 186-2 PRF for Microsoft CryptoAPI -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+ -+ -+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -+{ -+ /* FIX: how to do this with CryptoAPI? */ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_gnutls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_gnutls.c -new file mode 100644 -index 0000000000000..f742e98589f28 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_gnutls.c -@@ -0,0 +1,26 @@ -+/* -+ * FIPS 186-2 PRF for libgcrypt -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "crypto.h" -+ -+ -+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -+{ -+ /* FIX: how to do this with libgcrypt? */ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_internal.c -new file mode 100644 -index 0000000000000..a85cb14d7424a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_internal.c -@@ -0,0 +1,74 @@ -+/* -+ * FIPS 186-2 PRF for internal crypto implementation -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha1.h" -+#include "sha1_i.h" -+#include "crypto.h" -+ -+ -+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -+{ -+ u8 xkey[64]; -+ u32 t[5], _t[5]; -+ int i, j, m, k; -+ u8 *xpos = x; -+ u32 carry; -+ -+ if (seed_len > sizeof(xkey)) -+ seed_len = sizeof(xkey); -+ -+ /* FIPS 186-2 + change notice 1 */ -+ -+ os_memcpy(xkey, seed, seed_len); -+ os_memset(xkey + seed_len, 0, 64 - seed_len); -+ t[0] = 0x67452301; -+ t[1] = 0xEFCDAB89; -+ t[2] = 0x98BADCFE; -+ t[3] = 0x10325476; -+ t[4] = 0xC3D2E1F0; -+ -+ m = xlen / 40; -+ for (j = 0; j < m; j++) { -+ /* XSEED_j = 0 */ -+ for (i = 0; i < 2; i++) { -+ /* XVAL = (XKEY + XSEED_j) mod 2^b */ -+ -+ /* w_i = G(t, XVAL) */ -+ os_memcpy(_t, t, 20); -+ SHA1Transform(_t, xkey); -+ _t[0] = host_to_be32(_t[0]); -+ _t[1] = host_to_be32(_t[1]); -+ _t[2] = host_to_be32(_t[2]); -+ _t[3] = host_to_be32(_t[3]); -+ _t[4] = host_to_be32(_t[4]); -+ os_memcpy(xpos, _t, 20); -+ -+ /* XKEY = (1 + XKEY + w_i) mod 2^b */ -+ carry = 1; -+ for (k = 19; k >= 0; k--) { -+ carry += xkey[k] + xpos[k]; -+ xkey[k] = carry & 0xff; -+ carry >>= 8; -+ } -+ -+ xpos += SHA1_MAC_LEN; -+ } -+ /* x_j = w_0|w_1 */ -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_nss.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_nss.c -new file mode 100644 -index 0000000000000..f941983c43c3c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_nss.c -@@ -0,0 +1,25 @@ -+/* -+ * FIPS 186-2 PRF for NSS -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "crypto.h" -+ -+ -+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -+{ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_openssl.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_openssl.c -new file mode 100644 -index 0000000000000..d0af98355f658 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/fips_prf_openssl.c -@@ -0,0 +1,83 @@ -+/* -+ * FIPS 186-2 PRF for libcrypto -+ * Copyright (c) 2004-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "crypto.h" -+ -+ -+static void sha1_transform(u8 *state, const u8 data[64]) -+{ -+ SHA_CTX context; -+ os_memset(&context, 0, sizeof(context)); -+ os_memcpy(&context.h0, state, 5 * 4); -+ SHA1_Transform(&context, data); -+ os_memcpy(state, &context.h0, 5 * 4); -+} -+ -+ -+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) -+{ -+ u8 xkey[64]; -+ u32 t[5], _t[5]; -+ int i, j, m, k; -+ u8 *xpos = x; -+ u32 carry; -+ -+ if (seed_len > sizeof(xkey)) -+ seed_len = sizeof(xkey); -+ -+ /* FIPS 186-2 + change notice 1 */ -+ -+ os_memcpy(xkey, seed, seed_len); -+ os_memset(xkey + seed_len, 0, 64 - seed_len); -+ t[0] = 0x67452301; -+ t[1] = 0xEFCDAB89; -+ t[2] = 0x98BADCFE; -+ t[3] = 0x10325476; -+ t[4] = 0xC3D2E1F0; -+ -+ m = xlen / 40; -+ for (j = 0; j < m; j++) { -+ /* XSEED_j = 0 */ -+ for (i = 0; i < 2; i++) { -+ /* XVAL = (XKEY + XSEED_j) mod 2^b */ -+ -+ /* w_i = G(t, XVAL) */ -+ os_memcpy(_t, t, 20); -+ sha1_transform((u8 *) _t, xkey); -+ _t[0] = host_to_be32(_t[0]); -+ _t[1] = host_to_be32(_t[1]); -+ _t[2] = host_to_be32(_t[2]); -+ _t[3] = host_to_be32(_t[3]); -+ _t[4] = host_to_be32(_t[4]); -+ os_memcpy(xpos, _t, 20); -+ -+ /* XKEY = (1 + XKEY + w_i) mod 2^b */ -+ carry = 1; -+ for (k = 19; k >= 0; k--) { -+ carry += xkey[k] + xpos[k]; -+ xkey[k] = carry & 0xff; -+ carry >>= 8; -+ } -+ -+ xpos += 20; -+ } -+ /* x_j = w_0|w_1 */ -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md4-internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md4-internal.c -new file mode 100644 -index 0000000000000..d9f499f1d07b9 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md4-internal.c -@@ -0,0 +1,278 @@ -+/* -+ * MD4 hash implementation -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+ -+#define MD4_BLOCK_LENGTH 64 -+#define MD4_DIGEST_LENGTH 16 -+ -+typedef struct MD4Context { -+ u32 state[4]; /* state */ -+ u64 count; /* number of bits, mod 2^64 */ -+ u8 buffer[MD4_BLOCK_LENGTH]; /* input buffer */ -+} MD4_CTX; -+ -+ -+static void MD4Init(MD4_CTX *ctx); -+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len); -+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx); -+ -+ -+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ MD4_CTX ctx; -+ size_t i; -+ -+ MD4Init(&ctx); -+ for (i = 0; i < num_elem; i++) -+ MD4Update(&ctx, addr[i], len[i]); -+ MD4Final(mac, &ctx); -+ return 0; -+} -+ -+ -+/* ===== start - public domain MD4 implementation ===== */ -+/* $OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $ */ -+ -+/* -+ * This code implements the MD4 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. -+ * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186. -+ * -+ * 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 -+ * MD4Context structure, pass it to MD4Init, call MD4Update as -+ * needed on buffers full of bytes, and then call MD4Final, which -+ * will fill a supplied 16-byte array with the digest. -+ */ -+ -+#define MD4_DIGEST_STRING_LENGTH (MD4_DIGEST_LENGTH * 2 + 1) -+ -+ -+static void -+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]); -+ -+#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 u8 PADDING[MD4_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 MD4 accumulation. -+ * Set bit count to 0 and buffer to mysterious initialization constants. -+ */ -+static void MD4Init(MD4_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. -+ */ -+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len) -+{ -+ size_t have, need; -+ -+ /* Check how many bytes we already have and how many more we need. */ -+ have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1)); -+ need = MD4_BLOCK_LENGTH - have; -+ -+ /* Update bitcount */ -+ ctx->count += (u64)len << 3; -+ -+ if (len >= need) { -+ if (have != 0) { -+ os_memcpy(ctx->buffer + have, input, need); -+ MD4Transform(ctx->state, ctx->buffer); -+ input += need; -+ len -= need; -+ have = 0; -+ } -+ -+ /* Process data in MD4_BLOCK_LENGTH-byte chunks. */ -+ while (len >= MD4_BLOCK_LENGTH) { -+ MD4Transform(ctx->state, input); -+ input += MD4_BLOCK_LENGTH; -+ len -= MD4_BLOCK_LENGTH; -+ } -+ } -+ -+ /* Handle any remaining bytes of data. */ -+ if (len != 0) -+ os_memcpy(ctx->buffer + have, input, len); -+} -+ -+/* -+ * Pad pad to 64-byte boundary with the bit pattern -+ * 1 0* (64-bit count of bits processed, MSB-first) -+ */ -+static void MD4Pad(MD4_CTX *ctx) -+{ -+ u8 count[8]; -+ size_t padlen; -+ -+ /* Convert count to 8 bytes in little endian order. */ -+ PUT_64BIT_LE(count, ctx->count); -+ -+ /* Pad out to 56 mod 64. */ -+ padlen = MD4_BLOCK_LENGTH - -+ ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1)); -+ if (padlen < 1 + 8) -+ padlen += MD4_BLOCK_LENGTH; -+ MD4Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ -+ MD4Update(ctx, count, 8); -+} -+ -+/* -+ * Final wrapup--call MD4Pad, fill in digest and zero out ctx. -+ */ -+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx) -+{ -+ int i; -+ -+ MD4Pad(ctx); -+ if (digest != NULL) { -+ for (i = 0; i < 4; i++) -+ PUT_32BIT_LE(digest + i * 4, ctx->state[i]); -+ os_memset(ctx, 0, sizeof(*ctx)); -+ } -+} -+ -+ -+/* The three 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) ((x & y) | (x & z) | (y & z)) -+#define F3(x, y, z) (x ^ y ^ z) -+ -+/* This is the central step in the MD4 algorithm. */ -+#define MD4STEP(f, w, x, y, z, data, s) \ -+ ( w += f(x, y, z) + data, w = w<>(32-s) ) -+ -+/* -+ * The core of the MD4 algorithm, this alters an existing MD4 hash to -+ * reflect the addition of 16 longwords of new data. MD4Update blocks -+ * the data and converts bytes into longwords for this routine. -+ */ -+static void -+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]) -+{ -+ u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4]; -+ -+#if BYTE_ORDER == LITTLE_ENDIAN -+ os_memcpy(in, block, sizeof(in)); -+#else -+ for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) { -+ in[a] = (u32)( -+ (u32)(block[a * 4 + 0]) | -+ (u32)(block[a * 4 + 1]) << 8 | -+ (u32)(block[a * 4 + 2]) << 16 | -+ (u32)(block[a * 4 + 3]) << 24); -+ } -+#endif -+ -+ a = state[0]; -+ b = state[1]; -+ c = state[2]; -+ d = state[3]; -+ -+ MD4STEP(F1, a, b, c, d, in[ 0], 3); -+ MD4STEP(F1, d, a, b, c, in[ 1], 7); -+ MD4STEP(F1, c, d, a, b, in[ 2], 11); -+ MD4STEP(F1, b, c, d, a, in[ 3], 19); -+ MD4STEP(F1, a, b, c, d, in[ 4], 3); -+ MD4STEP(F1, d, a, b, c, in[ 5], 7); -+ MD4STEP(F1, c, d, a, b, in[ 6], 11); -+ MD4STEP(F1, b, c, d, a, in[ 7], 19); -+ MD4STEP(F1, a, b, c, d, in[ 8], 3); -+ MD4STEP(F1, d, a, b, c, in[ 9], 7); -+ MD4STEP(F1, c, d, a, b, in[10], 11); -+ MD4STEP(F1, b, c, d, a, in[11], 19); -+ MD4STEP(F1, a, b, c, d, in[12], 3); -+ MD4STEP(F1, d, a, b, c, in[13], 7); -+ MD4STEP(F1, c, d, a, b, in[14], 11); -+ MD4STEP(F1, b, c, d, a, in[15], 19); -+ -+ MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999, 3); -+ MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999, 5); -+ MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999, 9); -+ MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13); -+ MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999, 3); -+ MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999, 5); -+ MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999, 9); -+ MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13); -+ MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999, 3); -+ MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999, 5); -+ MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999, 9); -+ MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13); -+ MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999, 3); -+ MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999, 5); -+ MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999, 9); -+ MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13); -+ -+ MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1, 3); -+ MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1, 9); -+ MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11); -+ MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15); -+ MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1, 3); -+ MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1, 9); -+ MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11); -+ MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15); -+ MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1, 3); -+ MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1, 9); -+ MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11); -+ MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15); -+ MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1, 3); -+ MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1, 9); -+ MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11); -+ MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15); -+ -+ state[0] += a; -+ state[1] += b; -+ state[2] += c; -+ state[3] += d; -+} -+/* ===== end - public domain MD4 implementation ===== */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-internal.c -new file mode 100644 -index 0000000000000..05f4fc2423b5f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-internal.c -@@ -0,0 +1,293 @@ -+/* -+ * MD5 hash implementation and interface functions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "md5.h" -+#include "md5_i.h" -+#include "crypto.h" -+ -+ -+static void MD5Transform(u32 buf[4], u32 const in[16]); -+ -+ -+typedef struct MD5Context MD5_CTX; -+ -+ -+/** -+ * md5_vector - MD5 hash for data vector -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 of failure -+ */ -+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ MD5_CTX ctx; -+ size_t i; -+ -+ MD5Init(&ctx); -+ for (i = 0; i < num_elem; i++) -+ MD5Update(&ctx, addr[i], len[i]); -+ MD5Final(mac, &ctx); -+ return 0; -+} -+ -+ -+/* ===== start - public domain MD5 implementation ===== */ -+/* -+ * 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. -+ */ -+ -+#ifndef WORDS_BIGENDIAN -+#define byteReverse(buf, len) /* Nothing */ -+#else -+/* -+ * Note: this code is harmless on little-endian machines. -+ */ -+static void byteReverse(unsigned char *buf, unsigned longs) -+{ -+ u32 t; -+ do { -+ t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | -+ ((unsigned) buf[1] << 8 | buf[0]); -+ *(u32 *) buf = t; -+ buf += 4; -+ } while (--longs); -+} -+#endif -+ -+/* -+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious -+ * initialization constants. -+ */ -+void MD5Init(struct MD5Context *ctx) -+{ -+ ctx->buf[0] = 0x67452301; -+ ctx->buf[1] = 0xefcdab89; -+ ctx->buf[2] = 0x98badcfe; -+ ctx->buf[3] = 0x10325476; -+ -+ ctx->bits[0] = 0; -+ ctx->bits[1] = 0; -+} -+ -+/* -+ * Update context to reflect the concatenation of another buffer full -+ * of bytes. -+ */ -+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) -+{ -+ u32 t; -+ -+ /* Update bitcount */ -+ -+ t = ctx->bits[0]; -+ if ((ctx->bits[0] = t + ((u32) len << 3)) < t) -+ ctx->bits[1]++; /* Carry from low to high */ -+ ctx->bits[1] += len >> 29; -+ -+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ -+ -+ /* Handle any leading odd-sized chunks */ -+ -+ if (t) { -+ unsigned char *p = (unsigned char *) ctx->in + t; -+ -+ t = 64 - t; -+ if (len < t) { -+ os_memcpy(p, buf, len); -+ return; -+ } -+ os_memcpy(p, buf, t); -+ byteReverse(ctx->in, 16); -+ MD5Transform(ctx->buf, (u32 *) ctx->in); -+ buf += t; -+ len -= t; -+ } -+ /* Process data in 64-byte chunks */ -+ -+ while (len >= 64) { -+ os_memcpy(ctx->in, buf, 64); -+ byteReverse(ctx->in, 16); -+ MD5Transform(ctx->buf, (u32 *) ctx->in); -+ buf += 64; -+ len -= 64; -+ } -+ -+ /* Handle any remaining bytes of data. */ -+ -+ os_memcpy(ctx->in, buf, 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[16], struct MD5Context *ctx) -+{ -+ unsigned count; -+ unsigned char *p; -+ -+ /* Compute number of bytes mod 64 */ -+ count = (ctx->bits[0] >> 3) & 0x3F; -+ -+ /* Set the first char of padding to 0x80. This is safe since there is -+ always at least one byte free */ -+ p = ctx->in + count; -+ *p++ = 0x80; -+ -+ /* Bytes of padding needed to make 64 bytes */ -+ count = 64 - 1 - count; -+ -+ /* Pad out to 56 mod 64 */ -+ if (count < 8) { -+ /* Two lots of padding: Pad the first block to 64 bytes */ -+ os_memset(p, 0, count); -+ byteReverse(ctx->in, 16); -+ MD5Transform(ctx->buf, (u32 *) ctx->in); -+ -+ /* Now fill the next block with 56 bytes */ -+ os_memset(ctx->in, 0, 56); -+ } else { -+ /* Pad block to 56 bytes */ -+ os_memset(p, 0, count - 8); -+ } -+ byteReverse(ctx->in, 14); -+ -+ /* Append length in bits and transform */ -+ ((u32 *) ctx->in)[14] = ctx->bits[0]; -+ ((u32 *) ctx->in)[15] = ctx->bits[1]; -+ -+ MD5Transform(ctx->buf, (u32 *) ctx->in); -+ byteReverse((unsigned char *) ctx->buf, 4); -+ os_memcpy(digest, ctx->buf, 16); -+ os_memset(ctx, 0, sizeof(struct MD5Context)); /* 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. -+ */ -+static void MD5Transform(u32 buf[4], u32 const in[16]) -+{ -+ register u32 a, b, c, d; -+ -+ a = buf[0]; -+ b = buf[1]; -+ c = buf[2]; -+ d = buf[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); -+ -+ buf[0] += a; -+ buf[1] += b; -+ buf[2] += c; -+ buf[3] += d; -+} -+/* ===== end - public domain MD5 implementation ===== */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-non-fips.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-non-fips.c -new file mode 100644 -index 0000000000000..6f2920145a1ec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5-non-fips.c -@@ -0,0 +1,113 @@ -+/* -+ * MD5 hash implementation and interface functions (non-FIPS allowed cases) -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "md5.h" -+#include "crypto.h" -+ -+ -+/** -+ * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash (16 bytes) -+ * Returns: 0 on success, -1 on failure -+ */ -+int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len, -+ size_t num_elem, const u8 *addr[], -+ const size_t *len, u8 *mac) -+{ -+ u8 k_pad[64]; /* padding - key XORd with ipad/opad */ -+ u8 tk[16]; -+ const u8 *_addr[6]; -+ size_t i, _len[6]; -+ -+ if (num_elem > 5) { -+ /* -+ * Fixed limit on the number of fragments to avoid having to -+ * allocate memory (which could fail). -+ */ -+ return -1; -+ } -+ -+ /* if key is longer than 64 bytes reset it to key = MD5(key) */ -+ if (key_len > 64) { -+ if (md5_vector_non_fips_allow(1, &key, &key_len, tk)) -+ return -1; -+ key = tk; -+ key_len = 16; -+ } -+ -+ /* the HMAC_MD5 transform looks like: -+ * -+ * MD5(K XOR opad, MD5(K XOR ipad, text)) -+ * -+ * where K is an n byte key -+ * ipad is the byte 0x36 repeated 64 times -+ * opad is the byte 0x5c repeated 64 times -+ * and text is the data being protected */ -+ -+ /* start out by storing key in ipad */ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ -+ /* XOR key with ipad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x36; -+ -+ /* perform inner MD5 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ for (i = 0; i < num_elem; i++) { -+ _addr[i + 1] = addr[i]; -+ _len[i + 1] = len[i]; -+ } -+ if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac)) -+ return -1; -+ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ /* XOR key with opad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x5c; -+ -+ /* perform outer MD5 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ _addr[1] = mac; -+ _len[1] = MD5_MAC_LEN; -+ return md5_vector_non_fips_allow(2, _addr, _len, mac); -+} -+ -+ -+/** -+ * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @data: Pointers to the data area -+ * @data_len: Length of the data area -+ * @mac: Buffer for the hash (16 bytes) -+ * Returns: 0 on success, -1 on failure -+ */ -+int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data, -+ size_t data_len, u8 *mac) -+{ -+ return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data, -+ &data_len, mac); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.c -new file mode 100644 -index 0000000000000..7f14e9b2ec16b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.c -@@ -0,0 +1,111 @@ -+/* -+ * MD5 hash implementation and interface functions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "md5.h" -+#include "crypto.h" -+ -+ -+/** -+ * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash (16 bytes) -+ * Returns: 0 on success, -1 on failure -+ */ -+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, -+ const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ u8 k_pad[64]; /* padding - key XORd with ipad/opad */ -+ u8 tk[16]; -+ const u8 *_addr[6]; -+ size_t i, _len[6]; -+ -+ if (num_elem > 5) { -+ /* -+ * Fixed limit on the number of fragments to avoid having to -+ * allocate memory (which could fail). -+ */ -+ return -1; -+ } -+ -+ /* if key is longer than 64 bytes reset it to key = MD5(key) */ -+ if (key_len > 64) { -+ if (md5_vector(1, &key, &key_len, tk)) -+ return -1; -+ key = tk; -+ key_len = 16; -+ } -+ -+ /* the HMAC_MD5 transform looks like: -+ * -+ * MD5(K XOR opad, MD5(K XOR ipad, text)) -+ * -+ * where K is an n byte key -+ * ipad is the byte 0x36 repeated 64 times -+ * opad is the byte 0x5c repeated 64 times -+ * and text is the data being protected */ -+ -+ /* start out by storing key in ipad */ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ -+ /* XOR key with ipad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x36; -+ -+ /* perform inner MD5 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ for (i = 0; i < num_elem; i++) { -+ _addr[i + 1] = addr[i]; -+ _len[i + 1] = len[i]; -+ } -+ if (md5_vector(1 + num_elem, _addr, _len, mac)) -+ return -1; -+ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ /* XOR key with opad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x5c; -+ -+ /* perform outer MD5 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ _addr[1] = mac; -+ _len[1] = MD5_MAC_LEN; -+ return md5_vector(2, _addr, _len, mac); -+} -+ -+ -+/** -+ * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @data: Pointers to the data area -+ * @data_len: Length of the data area -+ * @mac: Buffer for the hash (16 bytes) -+ * Returns: 0 on success, -1 on failure -+ */ -+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, -+ u8 *mac) -+{ -+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.h -new file mode 100644 -index 0000000000000..8952590782a3f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5.h -@@ -0,0 +1,35 @@ -+/* -+ * MD5 hash implementation and interface functions -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef MD5_H -+#define MD5_H -+ -+#define MD5_MAC_LEN 16 -+ -+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, -+ const u8 *addr[], const size_t *len, u8 *mac); -+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, -+ u8 *mac); -+#ifdef CONFIG_FIPS -+int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len, -+ size_t num_elem, const u8 *addr[], -+ const size_t *len, u8 *mac); -+int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data, -+ size_t data_len, u8 *mac); -+#else /* CONFIG_FIPS */ -+#define hmac_md5_vector_non_fips_allow hmac_md5_vector -+#define hmac_md5_non_fips_allow hmac_md5 -+#endif /* CONFIG_FIPS */ -+ -+#endif /* MD5_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5_i.h -new file mode 100644 -index 0000000000000..b7f6596052a6b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/md5_i.h -@@ -0,0 +1,29 @@ -+/* -+ * MD5 internal definitions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef MD5_I_H -+#define MD5_I_H -+ -+struct MD5Context { -+ u32 buf[4]; -+ u32 bits[2]; -+ u8 in[64]; -+}; -+ -+void MD5Init(struct MD5Context *context); -+void MD5Update(struct MD5Context *context, unsigned char const *buf, -+ unsigned len); -+void MD5Final(unsigned char digest[16], struct MD5Context *context); -+ -+#endif /* MD5_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.c -new file mode 100644 -index 0000000000000..cf0c60e5510fa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.c -@@ -0,0 +1,329 @@ -+/* -+ * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) -+ * Copyright (c) 2006-2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file implements an example authentication algorithm defined for 3GPP -+ * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow -+ * EAP-AKA to be tested properly with real USIM cards. -+ * -+ * This implementations assumes that the r1..r5 and c1..c5 constants defined in -+ * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, -+ * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to -+ * be AES (Rijndael). -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "milenage.h" -+ -+ -+/** -+ * milenage_f1 - Milenage f1 and f1* algorithms -+ * @opc: OPc = 128-bit value derived from OP and K -+ * @k: K = 128-bit subscriber key -+ * @_rand: RAND = 128-bit random challenge -+ * @sqn: SQN = 48-bit sequence number -+ * @amf: AMF = 16-bit authentication management field -+ * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL -+ * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL -+ * Returns: 0 on success, -1 on failure -+ */ -+int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, -+ const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) -+{ -+ u8 tmp1[16], tmp2[16], tmp3[16]; -+ int i; -+ -+ /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ -+ for (i = 0; i < 16; i++) -+ tmp1[i] = _rand[i] ^ opc[i]; -+ if (aes_128_encrypt_block(k, tmp1, tmp1)) -+ return -1; -+ -+ /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ -+ os_memcpy(tmp2, sqn, 6); -+ os_memcpy(tmp2 + 6, amf, 2); -+ os_memcpy(tmp2 + 8, tmp2, 8); -+ -+ /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ -+ -+ /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ -+ for (i = 0; i < 16; i++) -+ tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; -+ /* XOR with TEMP = E_K(RAND XOR OP_C) */ -+ for (i = 0; i < 16; i++) -+ tmp3[i] ^= tmp1[i]; -+ /* XOR with c1 (= ..00, i.e., NOP) */ -+ -+ /* f1 || f1* = E_K(tmp3) XOR OP_c */ -+ if (aes_128_encrypt_block(k, tmp3, tmp1)) -+ return -1; -+ for (i = 0; i < 16; i++) -+ tmp1[i] ^= opc[i]; -+ if (mac_a) -+ os_memcpy(mac_a, tmp1, 8); /* f1 */ -+ if (mac_s) -+ os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ -+ return 0; -+} -+ -+ -+/** -+ * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms -+ * @opc: OPc = 128-bit value derived from OP and K -+ * @k: K = 128-bit subscriber key -+ * @_rand: RAND = 128-bit random challenge -+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL -+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL -+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL -+ * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL -+ * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL -+ * Returns: 0 on success, -1 on failure -+ */ -+int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, -+ u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) -+{ -+ u8 tmp1[16], tmp2[16], tmp3[16]; -+ int i; -+ -+ /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ -+ for (i = 0; i < 16; i++) -+ tmp1[i] = _rand[i] ^ opc[i]; -+ if (aes_128_encrypt_block(k, tmp1, tmp2)) -+ return -1; -+ -+ /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ -+ /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ -+ /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ -+ /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ -+ -+ /* f2 and f5 */ -+ /* rotate by r2 (= 0, i.e., NOP) */ -+ for (i = 0; i < 16; i++) -+ tmp1[i] = tmp2[i] ^ opc[i]; -+ tmp1[15] ^= 1; /* XOR c2 (= ..01) */ -+ /* f5 || f2 = E_K(tmp1) XOR OP_c */ -+ if (aes_128_encrypt_block(k, tmp1, tmp3)) -+ return -1; -+ for (i = 0; i < 16; i++) -+ tmp3[i] ^= opc[i]; -+ if (res) -+ os_memcpy(res, tmp3 + 8, 8); /* f2 */ -+ if (ak) -+ os_memcpy(ak, tmp3, 6); /* f5 */ -+ -+ /* f3 */ -+ if (ck) { -+ /* rotate by r3 = 0x20 = 4 bytes */ -+ for (i = 0; i < 16; i++) -+ tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; -+ tmp1[15] ^= 2; /* XOR c3 (= ..02) */ -+ if (aes_128_encrypt_block(k, tmp1, ck)) -+ return -1; -+ for (i = 0; i < 16; i++) -+ ck[i] ^= opc[i]; -+ } -+ -+ /* f4 */ -+ if (ik) { -+ /* rotate by r4 = 0x40 = 8 bytes */ -+ for (i = 0; i < 16; i++) -+ tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; -+ tmp1[15] ^= 4; /* XOR c4 (= ..04) */ -+ if (aes_128_encrypt_block(k, tmp1, ik)) -+ return -1; -+ for (i = 0; i < 16; i++) -+ ik[i] ^= opc[i]; -+ } -+ -+ /* f5* */ -+ if (akstar) { -+ /* rotate by r5 = 0x60 = 12 bytes */ -+ for (i = 0; i < 16; i++) -+ tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; -+ tmp1[15] ^= 8; /* XOR c5 (= ..08) */ -+ if (aes_128_encrypt_block(k, tmp1, tmp1)) -+ return -1; -+ for (i = 0; i < 6; i++) -+ akstar[i] = tmp1[i] ^ opc[i]; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * milenage_generate - Generate AKA AUTN,IK,CK,RES -+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) -+ * @amf: AMF = 16-bit authentication management field -+ * @k: K = 128-bit subscriber key -+ * @sqn: SQN = 48-bit sequence number -+ * @_rand: RAND = 128-bit random challenge -+ * @autn: Buffer for AUTN = 128-bit authentication token -+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL -+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL -+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL -+ * @res_len: Max length for res; set to used length or 0 on failure -+ */ -+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, -+ const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, -+ u8 *ck, u8 *res, size_t *res_len) -+{ -+ int i; -+ u8 mac_a[8], ak[6]; -+ -+ if (*res_len < 8) { -+ *res_len = 0; -+ return; -+ } -+ if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || -+ milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { -+ *res_len = 0; -+ return; -+ } -+ *res_len = 8; -+ -+ /* AUTN = (SQN ^ AK) || AMF || MAC */ -+ for (i = 0; i < 6; i++) -+ autn[i] = sqn[i] ^ ak[i]; -+ os_memcpy(autn + 6, amf, 2); -+ os_memcpy(autn + 8, mac_a, 8); -+} -+ -+ -+/** -+ * milenage_auts - Milenage AUTS validation -+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) -+ * @k: K = 128-bit subscriber key -+ * @_rand: RAND = 128-bit random challenge -+ * @auts: AUTS = 112-bit authentication token from client -+ * @sqn: Buffer for SQN = 48-bit sequence number -+ * Returns: 0 = success (sqn filled), -1 on failure -+ */ -+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, -+ u8 *sqn) -+{ -+ u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ -+ u8 ak[6], mac_s[8]; -+ int i; -+ -+ if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) -+ return -1; -+ for (i = 0; i < 6; i++) -+ sqn[i] = auts[i] ^ ak[i]; -+ if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || -+ memcmp(mac_s, auts + 6, 8) != 0) -+ return -1; -+ return 0; -+} -+ -+ -+/** -+ * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet -+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) -+ * @k: K = 128-bit subscriber key -+ * @_rand: RAND = 128-bit random challenge -+ * @sres: Buffer for SRES = 32-bit SRES -+ * @kc: Buffer for Kc = 64-bit Kc -+ * Returns: 0 on success, -1 on failure -+ */ -+int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) -+{ -+ u8 res[8], ck[16], ik[16]; -+ int i; -+ -+ if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) -+ return -1; -+ -+ for (i = 0; i < 8; i++) -+ kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; -+ -+#ifdef GSM_MILENAGE_ALT_SRES -+ os_memcpy(sres, res, 4); -+#else /* GSM_MILENAGE_ALT_SRES */ -+ for (i = 0; i < 4; i++) -+ sres[i] = res[i] ^ res[i + 4]; -+#endif /* GSM_MILENAGE_ALT_SRES */ -+ return 0; -+} -+ -+ -+/** -+ * milenage_generate - Generate AKA AUTN,IK,CK,RES -+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) -+ * @k: K = 128-bit subscriber key -+ * @sqn: SQN = 48-bit sequence number -+ * @_rand: RAND = 128-bit random challenge -+ * @autn: AUTN = 128-bit authentication token -+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL -+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL -+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL -+ * @res_len: Variable that will be set to RES length -+ * @auts: 112-bit buffer for AUTS -+ * Returns: 0 on success, -1 on failure, or -2 on synchronization failure -+ */ -+int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, -+ const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, -+ u8 *auts) -+{ -+ int i; -+ u8 mac_a[8], ak[6], rx_sqn[6]; -+ const u8 *amf; -+ -+ wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); -+ wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); -+ -+ if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) -+ return -1; -+ -+ *res_len = 8; -+ wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); -+ wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); -+ wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); -+ wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); -+ -+ /* AUTN = (SQN ^ AK) || AMF || MAC */ -+ for (i = 0; i < 6; i++) -+ rx_sqn[i] = autn[i] ^ ak[i]; -+ wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); -+ -+ if (os_memcmp(rx_sqn, sqn, 6) <= 0) { -+ u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ -+ if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) -+ return -1; -+ wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); -+ for (i = 0; i < 6; i++) -+ auts[i] = sqn[i] ^ ak[i]; -+ if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) -+ return -1; -+ wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); -+ return -2; -+ } -+ -+ amf = autn + 6; -+ wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); -+ if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) -+ return -1; -+ -+ wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); -+ -+ if (os_memcmp(mac_a, autn + 8, 8) != 0) { -+ wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); -+ wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", -+ autn + 8, 8); -+ return -1; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.h -new file mode 100644 -index 0000000000000..d5054d6dcca6e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/milenage.h -@@ -0,0 +1,33 @@ -+/* -+ * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) -+ * Copyright (c) 2006-2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef MILENAGE_H -+#define MILENAGE_H -+ -+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, -+ const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, -+ u8 *ck, u8 *res, size_t *res_len); -+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, -+ u8 *sqn); -+int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, -+ u8 *kc); -+int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, -+ const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, -+ u8 *auts); -+int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, -+ const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s); -+int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, -+ u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar); -+ -+#endif /* MILENAGE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.c -new file mode 100644 -index 0000000000000..dae15ab915fe7 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.c -@@ -0,0 +1,476 @@ -+/* -+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha1.h" -+#include "ms_funcs.h" -+#include "crypto.h" -+ -+ -+/** -+ * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2 -+ * @peer_challenge: 16-octet PeerChallenge (IN) -+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN) -+ * @username: 0-to-256-char UserName (IN) -+ * @username_len: Length of username -+ * @challenge: 8-octet Challenge (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, -+ const u8 *username, size_t username_len, -+ u8 *challenge) -+{ -+ u8 hash[SHA1_MAC_LEN]; -+ const unsigned char *addr[3]; -+ size_t len[3]; -+ -+ addr[0] = peer_challenge; -+ len[0] = 16; -+ addr[1] = auth_challenge; -+ len[1] = 16; -+ addr[2] = username; -+ len[2] = username_len; -+ -+ if (sha1_vector(3, addr, len, hash)) -+ return -1; -+ os_memcpy(challenge, hash, 8); -+ return 0; -+} -+ -+ -+/** -+ * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3 -+ * @password: 0-to-256-unicode-char Password (IN; ASCII) -+ * @password_len: Length of password -+ * @password_hash: 16-octet PasswordHash (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int nt_password_hash(const u8 *password, size_t password_len, -+ u8 *password_hash) -+{ -+ u8 buf[512], *pos; -+ size_t i, len; -+ -+ if (password_len > 256) -+ password_len = 256; -+ -+ /* Convert password into unicode */ -+ for (i = 0; i < password_len; i++) { -+ buf[2 * i] = password[i]; -+ buf[2 * i + 1] = 0; -+ } -+ -+ len = password_len * 2; -+ pos = buf; -+ return md4_vector(1, (const u8 **) &pos, &len, password_hash); -+} -+ -+ -+/** -+ * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4 -+ * @password_hash: 16-octet PasswordHash (IN) -+ * @password_hash_hash: 16-octet PasswordHashHash (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash) -+{ -+ size_t len = 16; -+ return md4_vector(1, &password_hash, &len, password_hash_hash); -+} -+ -+ -+/** -+ * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5 -+ * @challenge: 8-octet Challenge (IN) -+ * @password_hash: 16-octet PasswordHash (IN) -+ * @response: 24-octet Response (OUT) -+ */ -+void challenge_response(const u8 *challenge, const u8 *password_hash, -+ u8 *response) -+{ -+ u8 zpwd[7]; -+ des_encrypt(challenge, password_hash, response); -+ des_encrypt(challenge, password_hash + 7, response + 8); -+ zpwd[0] = password_hash[14]; -+ zpwd[1] = password_hash[15]; -+ os_memset(zpwd + 2, 0, 5); -+ des_encrypt(challenge, zpwd, response + 16); -+} -+ -+ -+/** -+ * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1 -+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN) -+ * @peer_challenge: 16-octet PeerChallenge (IN) -+ * @username: 0-to-256-char UserName (IN) -+ * @username_len: Length of username -+ * @password: 0-to-256-unicode-char Password (IN; ASCII) -+ * @password_len: Length of password -+ * @response: 24-octet Response (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *password, size_t password_len, -+ u8 *response) -+{ -+ u8 challenge[8]; -+ u8 password_hash[16]; -+ -+ challenge_hash(peer_challenge, auth_challenge, username, username_len, -+ challenge); -+ if (nt_password_hash(password, password_len, password_hash)) -+ return -1; -+ challenge_response(challenge, password_hash, response); -+ return 0; -+} -+ -+ -+/** -+ * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1 -+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN) -+ * @peer_challenge: 16-octet PeerChallenge (IN) -+ * @username: 0-to-256-char UserName (IN) -+ * @username_len: Length of username -+ * @password_hash: 16-octet PasswordHash (IN) -+ * @response: 24-octet Response (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int generate_nt_response_pwhash(const u8 *auth_challenge, -+ const u8 *peer_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *password_hash, -+ u8 *response) -+{ -+ u8 challenge[8]; -+ -+ if (challenge_hash(peer_challenge, auth_challenge, -+ username, username_len, -+ challenge)) -+ return -1; -+ challenge_response(challenge, password_hash, response); -+ return 0; -+} -+ -+ -+/** -+ * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 -+ * @password_hash: 16-octet PasswordHash (IN) -+ * @nt_response: 24-octet NT-Response (IN) -+ * @peer_challenge: 16-octet PeerChallenge (IN) -+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN) -+ * @username: 0-to-256-char UserName (IN) -+ * @username_len: Length of username -+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually -+ * encoded as a 42-octet ASCII string (S=hexdump_of_response) -+ * Returns: 0 on success, -1 on failure -+ */ -+int generate_authenticator_response_pwhash( -+ const u8 *password_hash, -+ const u8 *peer_challenge, const u8 *auth_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *nt_response, u8 *response) -+{ -+ static const u8 magic1[39] = { -+ 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, -+ 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, -+ 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, -+ 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 -+ }; -+ static const u8 magic2[41] = { -+ 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, -+ 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, -+ 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, -+ 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, -+ 0x6E -+ }; -+ -+ u8 password_hash_hash[16], challenge[8]; -+ const unsigned char *addr1[3]; -+ const size_t len1[3] = { 16, 24, sizeof(magic1) }; -+ const unsigned char *addr2[3]; -+ const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) }; -+ -+ addr1[0] = password_hash_hash; -+ addr1[1] = nt_response; -+ addr1[2] = magic1; -+ -+ addr2[0] = response; -+ addr2[1] = challenge; -+ addr2[2] = magic2; -+ -+ if (hash_nt_password_hash(password_hash, password_hash_hash)) -+ return -1; -+ if (sha1_vector(3, addr1, len1, response)) -+ return -1; -+ -+ challenge_hash(peer_challenge, auth_challenge, username, username_len, -+ challenge); -+ return sha1_vector(3, addr2, len2, response); -+} -+ -+ -+/** -+ * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7 -+ * @password: 0-to-256-unicode-char Password (IN; ASCII) -+ * @password_len: Length of password -+ * @nt_response: 24-octet NT-Response (IN) -+ * @peer_challenge: 16-octet PeerChallenge (IN) -+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN) -+ * @username: 0-to-256-char UserName (IN) -+ * @username_len: Length of username -+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually -+ * encoded as a 42-octet ASCII string (S=hexdump_of_response) -+ * Returns: 0 on success, -1 on failure -+ */ -+int generate_authenticator_response(const u8 *password, size_t password_len, -+ const u8 *peer_challenge, -+ const u8 *auth_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *nt_response, u8 *response) -+{ -+ u8 password_hash[16]; -+ if (nt_password_hash(password, password_len, password_hash)) -+ return -1; -+ return generate_authenticator_response_pwhash( -+ password_hash, peer_challenge, auth_challenge, -+ username, username_len, nt_response, response); -+} -+ -+ -+/** -+ * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5 -+ * @challenge: 8-octet Challenge (IN) -+ * @password: 0-to-256-unicode-char Password (IN; ASCII) -+ * @password_len: Length of password -+ * @response: 24-octet Response (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int nt_challenge_response(const u8 *challenge, const u8 *password, -+ size_t password_len, u8 *response) -+{ -+ u8 password_hash[16]; -+ if (nt_password_hash(password, password_len, password_hash)) -+ return -1; -+ challenge_response(challenge, password_hash, response); -+ return 0; -+} -+ -+ -+/** -+ * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4 -+ * @password_hash_hash: 16-octet PasswordHashHash (IN) -+ * @nt_response: 24-octet NTResponse (IN) -+ * @master_key: 16-octet MasterKey (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, -+ u8 *master_key) -+{ -+ static const u8 magic1[27] = { -+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, -+ 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, -+ 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 -+ }; -+ const unsigned char *addr[3]; -+ const size_t len[3] = { 16, 24, sizeof(magic1) }; -+ u8 hash[SHA1_MAC_LEN]; -+ -+ addr[0] = password_hash_hash; -+ addr[1] = nt_response; -+ addr[2] = magic1; -+ -+ if (sha1_vector(3, addr, len, hash)) -+ return -1; -+ os_memcpy(master_key, hash, 16); -+ return 0; -+} -+ -+ -+/** -+ * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4 -+ * @master_key: 16-octet MasterKey (IN) -+ * @session_key: 8-to-16 octet SessionKey (OUT) -+ * @session_key_len: SessionKeyLength (Length of session_key) (IN) -+ * @is_send: IsSend (IN, BOOLEAN) -+ * @is_server: IsServer (IN, BOOLEAN) -+ * Returns: 0 on success, -1 on failure -+ */ -+int get_asymetric_start_key(const u8 *master_key, u8 *session_key, -+ size_t session_key_len, int is_send, -+ int is_server) -+{ -+ static const u8 magic2[84] = { -+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, -+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, -+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, -+ 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, -+ 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, -+ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, -+ 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, -+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, -+ 0x6b, 0x65, 0x79, 0x2e -+ }; -+ static const u8 magic3[84] = { -+ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, -+ 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, -+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, -+ 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, -+ 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, -+ 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, -+ 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, -+ 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, -+ 0x6b, 0x65, 0x79, 0x2e -+ }; -+ static const u8 shs_pad1[40] = { -+ 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 u8 shs_pad2[40] = { -+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, -+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, -+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, -+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 -+ }; -+ u8 digest[SHA1_MAC_LEN]; -+ const unsigned char *addr[4]; -+ const size_t len[4] = { 16, 40, 84, 40 }; -+ -+ addr[0] = master_key; -+ addr[1] = shs_pad1; -+ if (is_send) { -+ addr[2] = is_server ? magic3 : magic2; -+ } else { -+ addr[2] = is_server ? magic2 : magic3; -+ } -+ addr[3] = shs_pad2; -+ -+ if (sha1_vector(4, addr, len, digest)) -+ return -1; -+ -+ if (session_key_len > SHA1_MAC_LEN) -+ session_key_len = SHA1_MAC_LEN; -+ os_memcpy(session_key, digest, session_key_len); -+ return 0; -+} -+ -+ -+#define PWBLOCK_LEN 516 -+ -+/** -+ * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10 -+ * @password: 0-to-256-unicode-char Password (IN; ASCII) -+ * @password_len: Length of password -+ * @password_hash: 16-octet PasswordHash (IN) -+ * @pw_block: 516-byte PwBlock (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int encrypt_pw_block_with_password_hash( -+ const u8 *password, size_t password_len, -+ const u8 *password_hash, u8 *pw_block) -+{ -+ size_t i, offset; -+ u8 *pos; -+ -+ if (password_len > 256) -+ return -1; -+ -+ os_memset(pw_block, 0, PWBLOCK_LEN); -+ offset = (256 - password_len) * 2; -+ if (os_get_random(pw_block, offset) < 0) -+ return -1; -+ for (i = 0; i < password_len; i++) -+ pw_block[offset + i * 2] = password[i]; -+ /* -+ * PasswordLength is 4 octets, but since the maximum password length is -+ * 256, only first two (in little endian byte order) can be non-zero. -+ */ -+ pos = &pw_block[2 * 256]; -+ WPA_PUT_LE16(pos, password_len * 2); -+ rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN); -+ return 0; -+} -+ -+ -+/** -+ * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9 -+ * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) -+ * @new_password_len: Length of new_password -+ * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) -+ * @old_password_len: Length of old_password -+ * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int new_password_encrypted_with_old_nt_password_hash( -+ const u8 *new_password, size_t new_password_len, -+ const u8 *old_password, size_t old_password_len, -+ u8 *encrypted_pw_block) -+{ -+ u8 password_hash[16]; -+ -+ if (nt_password_hash(old_password, old_password_len, password_hash)) -+ return -1; -+ if (encrypt_pw_block_with_password_hash(new_password, new_password_len, -+ password_hash, -+ encrypted_pw_block)) -+ return -1; -+ return 0; -+} -+ -+ -+/** -+ * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13 -+ * @password_hash: 16-octer PasswordHash (IN) -+ * @block: 16-octet Block (IN) -+ * @cypher: 16-octer Cypher (OUT) -+ */ -+void nt_password_hash_encrypted_with_block(const u8 *password_hash, -+ const u8 *block, u8 *cypher) -+{ -+ des_encrypt(password_hash, block, cypher); -+ des_encrypt(password_hash + 8, block + 7, cypher + 8); -+} -+ -+ -+/** -+ * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12 -+ * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII) -+ * @new_password_len: Length of new_password -+ * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII) -+ * @old_password_len: Length of old_password -+ * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT) -+ * Returns: 0 on success, -1 on failure -+ */ -+int old_nt_password_hash_encrypted_with_new_nt_password_hash( -+ const u8 *new_password, size_t new_password_len, -+ const u8 *old_password, size_t old_password_len, -+ u8 *encrypted_password_hash) -+{ -+ u8 old_password_hash[16], new_password_hash[16]; -+ -+ if (nt_password_hash(old_password, old_password_len, -+ old_password_hash) || -+ nt_password_hash(new_password, new_password_len, -+ new_password_hash)) -+ return -1; -+ nt_password_hash_encrypted_with_block(old_password_hash, -+ new_password_hash, -+ encrypted_password_hash); -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.h -new file mode 100644 -index 0000000000000..298dbcf4fee34 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/ms_funcs.h -@@ -0,0 +1,64 @@ -+/* -+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759 -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef MS_FUNCS_H -+#define MS_FUNCS_H -+ -+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *password, size_t password_len, -+ u8 *response); -+int generate_nt_response_pwhash(const u8 *auth_challenge, -+ const u8 *peer_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *password_hash, -+ u8 *response); -+int generate_authenticator_response(const u8 *password, size_t password_len, -+ const u8 *peer_challenge, -+ const u8 *auth_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *nt_response, u8 *response); -+int generate_authenticator_response_pwhash( -+ const u8 *password_hash, -+ const u8 *peer_challenge, const u8 *auth_challenge, -+ const u8 *username, size_t username_len, -+ const u8 *nt_response, u8 *response); -+int nt_challenge_response(const u8 *challenge, const u8 *password, -+ size_t password_len, u8 *response); -+ -+void challenge_response(const u8 *challenge, const u8 *password_hash, -+ u8 *response); -+int nt_password_hash(const u8 *password, size_t password_len, -+ u8 *password_hash); -+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash); -+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response, -+ u8 *master_key); -+int get_asymetric_start_key(const u8 *master_key, u8 *session_key, -+ size_t session_key_len, int is_send, -+ int is_server); -+int __must_check encrypt_pw_block_with_password_hash( -+ const u8 *password, size_t password_len, -+ const u8 *password_hash, u8 *pw_block); -+int __must_check new_password_encrypted_with_old_nt_password_hash( -+ const u8 *new_password, size_t new_password_len, -+ const u8 *old_password, size_t old_password_len, -+ u8 *encrypted_pw_block); -+void nt_password_hash_encrypted_with_block(const u8 *password_hash, -+ const u8 *block, u8 *cypher); -+int old_nt_password_hash_encrypted_with_new_nt_password_hash( -+ const u8 *new_password, size_t new_password_len, -+ const u8 *old_password, size_t old_password_len, -+ u8 *encrypted_password_hash); -+ -+#endif /* MS_FUNCS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.c -new file mode 100644 -index 0000000000000..a30afde1156e5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.c -@@ -0,0 +1,337 @@ -+/* -+ * Random number generator -+ * Copyright (c) 2010-2011, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This random number generator is used to provide additional entropy to the -+ * one provided by the operating system (os_get_random()) for session key -+ * generation. The os_get_random() output is expected to be secure and the -+ * implementation here is expected to provide only limited protection against -+ * cases where os_get_random() cannot provide strong randomness. This -+ * implementation shall not be assumed to be secure as the sole source of -+ * randomness. The random_get_bytes() function mixes in randomness from -+ * os_get_random() and as such, calls to os_get_random() can be replaced with -+ * calls to random_get_bytes() without reducing security. -+ * -+ * The design here follows partially the design used in the Linux -+ * drivers/char/random.c, but the implementation here is simpler and not as -+ * strong. This is a compromise to reduce duplicated CPU effort and to avoid -+ * extra code/memory size. As pointed out above, os_get_random() needs to be -+ * guaranteed to be secure for any of the security assumptions to hold. -+ */ -+ -+#include "utils/includes.h" -+#ifdef __linux__ -+#include -+#endif /* __linux__ */ -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "sha1.h" -+#include "random.h" -+ -+#define POOL_WORDS 32 -+#define POOL_WORDS_MASK (POOL_WORDS - 1) -+#define POOL_TAP1 26 -+#define POOL_TAP2 20 -+#define POOL_TAP3 14 -+#define POOL_TAP4 7 -+#define POOL_TAP5 1 -+#define EXTRACT_LEN 16 -+#define MIN_READY_MARK 2 -+ -+static u32 pool[POOL_WORDS]; -+static unsigned int input_rotate = 0; -+static unsigned int pool_pos = 0; -+static u8 dummy_key[20]; -+#ifdef __linux__ -+static size_t dummy_key_avail = 0; -+static int random_fd = -1; -+#endif /* __linux__ */ -+static unsigned int own_pool_ready = 0; -+ -+#define MIN_COLLECT_ENTROPY 1000 -+static unsigned int entropy = 0; -+static unsigned int total_collected = 0; -+ -+ -+static u32 __ROL32(u32 x, u32 y) -+{ -+ return (x << (y & 31)) | (x >> (32 - (y & 31))); -+} -+ -+ -+static void random_mix_pool(const void *buf, size_t len) -+{ -+ static const u32 twist[8] = { -+ 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, -+ 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 -+ }; -+ const u8 *pos = buf; -+ u32 w; -+ -+ wpa_hexdump_key(MSG_EXCESSIVE, "random_mix_pool", buf, len); -+ -+ while (len--) { -+ w = __ROL32(*pos++, input_rotate & 31); -+ input_rotate += pool_pos ? 7 : 14; -+ pool_pos = (pool_pos - 1) & POOL_WORDS_MASK; -+ w ^= pool[pool_pos]; -+ w ^= pool[(pool_pos + POOL_TAP1) & POOL_WORDS_MASK]; -+ w ^= pool[(pool_pos + POOL_TAP2) & POOL_WORDS_MASK]; -+ w ^= pool[(pool_pos + POOL_TAP3) & POOL_WORDS_MASK]; -+ w ^= pool[(pool_pos + POOL_TAP4) & POOL_WORDS_MASK]; -+ w ^= pool[(pool_pos + POOL_TAP5) & POOL_WORDS_MASK]; -+ pool[pool_pos] = (w >> 3) ^ twist[w & 7]; -+ } -+} -+ -+ -+static void random_extract(u8 *out) -+{ -+ unsigned int i; -+ u8 hash[SHA1_MAC_LEN]; -+ u32 *hash_ptr; -+ u32 buf[POOL_WORDS / 2]; -+ -+ /* First, add hash back to pool to make backtracking more difficult. */ -+ hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool, -+ sizeof(pool), hash); -+ random_mix_pool(hash, sizeof(hash)); -+ /* Hash half the pool to extra data */ -+ for (i = 0; i < POOL_WORDS / 2; i++) -+ buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK]; -+ hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf, -+ sizeof(buf), hash); -+ /* -+ * Fold the hash to further reduce any potential output pattern. -+ * Though, compromise this to reduce CPU use for the most common output -+ * length (32) and return 16 bytes from instead of only half. -+ */ -+ hash_ptr = (u32 *) hash; -+ hash_ptr[0] ^= hash_ptr[4]; -+ os_memcpy(out, hash, EXTRACT_LEN); -+} -+ -+ -+void random_add_randomness(const void *buf, size_t len) -+{ -+ struct os_time t; -+ static unsigned int count = 0; -+ -+ count++; -+ wpa_printf(MSG_MSGDUMP, "Add randomness: count=%u entropy=%u", -+ count, entropy); -+ if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) { -+ /* -+ * No need to add more entropy at this point, so save CPU and -+ * skip the update. -+ */ -+ return; -+ } -+ -+ os_get_time(&t); -+ wpa_hexdump_key(MSG_EXCESSIVE, "random pool", -+ (const u8 *) pool, sizeof(pool)); -+ random_mix_pool(&t, sizeof(t)); -+ random_mix_pool(buf, len); -+ wpa_hexdump_key(MSG_EXCESSIVE, "random pool", -+ (const u8 *) pool, sizeof(pool)); -+ entropy++; -+ total_collected++; -+} -+ -+ -+int random_get_bytes(void *buf, size_t len) -+{ -+ int ret; -+ u8 *bytes = buf; -+ size_t left; -+ -+ wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u", -+ (unsigned int) len, entropy); -+ -+ /* Start with assumed strong randomness from OS */ -+ ret = os_get_random(buf, len); -+ wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random", -+ buf, len); -+ -+ /* Mix in additional entropy extracted from the internal pool */ -+ left = len; -+ while (left) { -+ size_t siz, i; -+ u8 tmp[EXTRACT_LEN]; -+ random_extract(tmp); -+ wpa_hexdump_key(MSG_EXCESSIVE, "random from internal pool", -+ tmp, sizeof(tmp)); -+ siz = left > EXTRACT_LEN ? EXTRACT_LEN : left; -+ for (i = 0; i < siz; i++) -+ *bytes++ ^= tmp[i]; -+ left -= siz; -+ } -+ wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len); -+ -+ if (entropy < len) -+ entropy = 0; -+ else -+ entropy -= len; -+ -+ return ret; -+} -+ -+ -+int random_pool_ready(void) -+{ -+#ifdef __linux__ -+ int fd; -+ ssize_t res; -+ -+ /* -+ * Make sure that there is reasonable entropy available before allowing -+ * some key derivation operations to proceed. -+ */ -+ -+ if (dummy_key_avail == sizeof(dummy_key)) -+ return 1; /* Already initialized - good to continue */ -+ -+ /* -+ * Try to fetch some more data from the kernel high quality -+ * /dev/random. There may not be enough data available at this point, -+ * so use non-blocking read to avoid blocking the application -+ * completely. -+ */ -+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK); -+ if (fd < 0) { -+#ifndef CONFIG_NO_STDOUT_DEBUG -+ int error = errno; -+ perror("open(/dev/random)"); -+ wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s", -+ strerror(error)); -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ return -1; -+ } -+ -+ res = read(fd, dummy_key + dummy_key_avail, -+ sizeof(dummy_key) - dummy_key_avail); -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: " -+ "%s", strerror(errno)); -+ res = 0; -+ } -+ wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from " -+ "/dev/random", (unsigned) res, -+ (unsigned) (sizeof(dummy_key) - dummy_key_avail)); -+ dummy_key_avail += res; -+ close(fd); -+ -+ if (dummy_key_avail == sizeof(dummy_key)) -+ return 1; -+ -+ wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong " -+ "random data available from /dev/random", -+ (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key)); -+ -+ if (own_pool_ready >= MIN_READY_MARK || -+ total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) { -+ wpa_printf(MSG_INFO, "random: Allow operation to proceed " -+ "based on internal entropy"); -+ return 1; -+ } -+ -+ wpa_printf(MSG_INFO, "random: Not enough entropy pool available for " -+ "secure operations"); -+ return 0; -+#else /* __linux__ */ -+ /* TODO: could do similar checks on non-Linux platforms */ -+ return 1; -+#endif /* __linux__ */ -+} -+ -+ -+void random_mark_pool_ready(void) -+{ -+ own_pool_ready++; -+ wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be " -+ "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK); -+} -+ -+ -+#ifdef __linux__ -+ -+static void random_close_fd(void) -+{ -+ if (random_fd >= 0) { -+ eloop_unregister_read_sock(random_fd); -+ close(random_fd); -+ random_fd = -1; -+ } -+} -+ -+ -+static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ ssize_t res; -+ -+ if (dummy_key_avail == sizeof(dummy_key)) { -+ random_close_fd(); -+ return; -+ } -+ -+ res = read(sock, dummy_key + dummy_key_avail, -+ sizeof(dummy_key) - dummy_key_avail); -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: " -+ "%s", strerror(errno)); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random", -+ (unsigned) res, -+ (unsigned) (sizeof(dummy_key) - dummy_key_avail)); -+ dummy_key_avail += res; -+ -+ if (dummy_key_avail == sizeof(dummy_key)) -+ random_close_fd(); -+} -+ -+#endif /* __linux__ */ -+ -+ -+void random_init(void) -+{ -+#ifdef __linux__ -+ if (random_fd >= 0) -+ return; -+ -+ random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK); -+ if (random_fd < 0) { -+#ifndef CONFIG_NO_STDOUT_DEBUG -+ int error = errno; -+ perror("open(/dev/random)"); -+ wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s", -+ strerror(error)); -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "random: Trying to read entropy from " -+ "/dev/random"); -+ -+ eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL); -+#endif /* __linux__ */ -+} -+ -+ -+void random_deinit(void) -+{ -+#ifdef __linux__ -+ random_close_fd(); -+#endif /* __linux__ */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.h -new file mode 100644 -index 0000000000000..5dabd2b02f502 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/random.h -@@ -0,0 +1,34 @@ -+/* -+ * Random number generator -+ * Copyright (c) 2010-2011, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef RANDOM_H -+#define RANDOM_H -+ -+#ifdef CONFIG_NO_RANDOM_POOL -+#define random_init() do { } while (0) -+#define random_deinit() do { } while (0) -+#define random_add_randomness(b, l) do { } while (0) -+#define random_get_bytes(b, l) os_get_random((b), (l)) -+#define random_pool_ready() 1 -+#define random_mark_pool_ready() do { } while (0) -+#else /* CONFIG_NO_RANDOM_POOL */ -+void random_init(void); -+void random_deinit(void); -+void random_add_randomness(const void *buf, size_t len); -+int random_get_bytes(void *buf, size_t len); -+int random_pool_ready(void); -+void random_mark_pool_ready(void); -+#endif /* CONFIG_NO_RANDOM_POOL */ -+ -+#endif /* RANDOM_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/rc4.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/rc4.c -new file mode 100644 -index 0000000000000..5ab1be191e9a5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/rc4.c -@@ -0,0 +1,60 @@ -+/* -+ * RC4 stream cipher -+ * Copyright (c) 2002-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto.h" -+ -+#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) -+ -+int rc4_skip(const u8 *key, size_t keylen, size_t skip, -+ u8 *data, size_t data_len) -+{ -+ u32 i, j, k; -+ u8 S[256], *pos; -+ size_t kpos; -+ -+ /* Setup RC4 state */ -+ for (i = 0; i < 256; i++) -+ S[i] = i; -+ j = 0; -+ kpos = 0; -+ for (i = 0; i < 256; i++) { -+ j = (j + S[i] + key[kpos]) & 0xff; -+ kpos++; -+ if (kpos >= keylen) -+ kpos = 0; -+ S_SWAP(i, j); -+ } -+ -+ /* Skip the start of the stream */ -+ i = j = 0; -+ for (k = 0; k < skip; k++) { -+ i = (i + 1) & 0xff; -+ j = (j + S[i]) & 0xff; -+ S_SWAP(i, j); -+ } -+ -+ /* Apply RC4 to data */ -+ pos = data; -+ for (k = 0; k < data_len; k++) { -+ i = (i + 1) & 0xff; -+ j = (j + S[i]) & 0xff; -+ S_SWAP(i, j); -+ *pos++ ^= S[(S[i] + S[j]) & 0xff]; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-internal.c -new file mode 100644 -index 0000000000000..3f05ca113125d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-internal.c -@@ -0,0 +1,308 @@ -+/* -+ * SHA1 hash implementation and interface functions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha1.h" -+#include "sha1_i.h" -+#include "md5.h" -+#include "crypto.h" -+ -+typedef struct SHA1Context SHA1_CTX; -+ -+void SHA1Transform(u32 state[5], const unsigned char buffer[64]); -+ -+ -+/** -+ * sha1_vector - SHA-1 hash for data vector -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 of failure -+ */ -+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ SHA1_CTX ctx; -+ size_t i; -+ -+ SHA1Init(&ctx); -+ for (i = 0; i < num_elem; i++) -+ SHA1Update(&ctx, addr[i], len[i]); -+ SHA1Final(mac, &ctx); -+ return 0; -+} -+ -+ -+/* ===== start - public domain SHA1 implementation ===== */ -+ -+/* -+SHA-1 in C -+By Steve Reid -+100% Public Domain -+ -+----------------- -+Modified 7/98 -+By James H. Brown -+Still 100% Public Domain -+ -+Corrected a problem which generated improper hash values on 16 bit machines -+Routine SHA1Update changed from -+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int -+len) -+to -+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned -+long len) -+ -+The 'len' parameter was declared an int which works fine on 32 bit machines. -+However, on 16 bit machines an int is too small for the shifts being done -+against -+it. This caused the hash function to generate incorrect values if len was -+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). -+ -+Since the file IO in main() reads 16K at a time, any file 8K or larger would -+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million -+"a"s). -+ -+I also changed the declaration of variables i & j in SHA1Update to -+unsigned long from unsigned int for the same reason. -+ -+These changes should make no difference to any 32 bit implementations since -+an -+int and a long are the same size in those environments. -+ -+-- -+I also corrected a few compiler warnings generated by Borland C. -+1. Added #include for exit() prototype -+2. Removed unused variable 'j' in SHA1Final -+3. Changed exit(0) to return(0) at end of main. -+ -+ALL changes I made can be located by searching for comments containing 'JHB' -+----------------- -+Modified 8/98 -+By Steve Reid -+Still 100% public domain -+ -+1- Removed #include and used return() instead of exit() -+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) -+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net -+ -+----------------- -+Modified 4/01 -+By Saul Kravitz -+Still 100% PD -+Modified to run on Compaq Alpha hardware. -+ -+----------------- -+Modified 4/01 -+By Jouni Malinen -+Minor changes to match the coding style used in Dynamics. -+ -+Modified September 24, 2004 -+By Jouni Malinen -+Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined. -+ -+*/ -+ -+/* -+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 SHA1HANDSOFF -+ -+#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 */ -+#ifndef WORDS_BIGENDIAN -+#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); -+ -+ -+#ifdef VERBOSE /* SAK */ -+void SHAPrintContext(SHA1_CTX *context, char *msg) -+{ -+ printf("%s (%d,%d) %x %x %x %x %x\n", -+ msg, -+ context->count[0], context->count[1], -+ context->state[0], -+ context->state[1], -+ context->state[2], -+ context->state[3], -+ context->state[4]); -+} -+#endif -+ -+/* Hash a single 512-bit block. This is the core of the algorithm. */ -+ -+void SHA1Transform(u32 state[5], const unsigned char buffer[64]) -+{ -+ u32 a, b, c, d, e; -+ typedef union { -+ unsigned char c[64]; -+ u32 l[16]; -+ } CHAR64LONG16; -+ CHAR64LONG16* block; -+#ifdef SHA1HANDSOFF -+ CHAR64LONG16 workspace; -+ block = &workspace; -+ os_memcpy(block, buffer, 64); -+#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; -+#ifdef SHA1HANDSOFF -+ os_memset(block, 0, 64); -+#endif -+} -+ -+ -+/* SHA1Init - Initialize new context */ -+ -+void SHA1Init(SHA1_CTX* context) -+{ -+ /* SHA1 initialization constants */ -+ context->state[0] = 0x67452301; -+ context->state[1] = 0xEFCDAB89; -+ context->state[2] = 0x98BADCFE; -+ context->state[3] = 0x10325476; -+ context->state[4] = 0xC3D2E1F0; -+ context->count[0] = context->count[1] = 0; -+} -+ -+ -+/* Run your data through this. */ -+ -+void SHA1Update(SHA1_CTX* context, const void *_data, u32 len) -+{ -+ u32 i, j; -+ const unsigned char *data = _data; -+ -+#ifdef VERBOSE -+ SHAPrintContext(context, "before"); -+#endif -+ j = (context->count[0] >> 3) & 63; -+ if ((context->count[0] += len << 3) < (len << 3)) -+ context->count[1]++; -+ context->count[1] += (len >> 29); -+ if ((j + len) > 63) { -+ os_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; -+ os_memcpy(&context->buffer[j], &data[i], len - i); -+#ifdef VERBOSE -+ SHAPrintContext(context, "after "); -+#endif -+} -+ -+ -+/* Add padding and return the message digest. */ -+ -+void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -+{ -+ u32 i; -+ unsigned char finalcount[8]; -+ -+ for (i = 0; i < 8; i++) { -+ finalcount[i] = (unsigned char) -+ ((context->count[(i >= 4 ? 0 : 1)] >> -+ ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ -+ } -+ SHA1Update(context, (unsigned char *) "\200", 1); -+ while ((context->count[0] & 504) != 448) { -+ SHA1Update(context, (unsigned char *) "\0", 1); -+ } -+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() -+ */ -+ for (i = 0; i < 20; i++) { -+ digest[i] = (unsigned char) -+ ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & -+ 255); -+ } -+ /* Wipe variables */ -+ i = 0; -+ os_memset(context->buffer, 0, 64); -+ os_memset(context->state, 0, 20); -+ os_memset(context->count, 0, 8); -+ os_memset(finalcount, 0, 8); -+} -+ -+/* ===== end - public domain SHA1 implementation ===== */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-pbkdf2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-pbkdf2.c -new file mode 100644 -index 0000000000000..11323de7a01e2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-pbkdf2.c -@@ -0,0 +1,100 @@ -+/* -+ * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha1.h" -+#include "md5.h" -+#include "crypto.h" -+ -+static int pbkdf2_sha1_f(const char *passphrase, const char *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 = os_strlen(passphrase); -+ -+ addr[0] = (u8 *) 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; -+ os_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; -+ os_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 char *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; -+ os_memcpy(pos, digest, plen); -+ pos += plen; -+ left -= plen; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tlsprf.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tlsprf.c -new file mode 100644 -index 0000000000000..2c8c029ecf495 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tlsprf.c -@@ -0,0 +1,109 @@ -+/* -+ * TLS PRF (SHA1 + MD5) -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha1.h" -+#include "md5.h" -+#include "crypto.h" -+ -+ -+/** -+ * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246) -+ * @secret: Key for PRF -+ * @secret_len: Length of the key in bytes -+ * @label: A unique label for each purpose of the PRF -+ * @seed: Seed value to bind into the key -+ * @seed_len: Length of the seed -+ * @out: Buffer for the generated pseudo-random key -+ * @outlen: Number of bytes of key to generate -+ * Returns: 0 on success, -1 on failure. -+ * -+ * This function is used to derive new, cryptographically separate keys from a -+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5. -+ */ -+int tls_prf(const u8 *secret, size_t secret_len, const char *label, -+ const u8 *seed, size_t seed_len, u8 *out, size_t outlen) -+{ -+ size_t L_S1, L_S2, i; -+ const u8 *S1, *S2; -+ u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; -+ u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; -+ int MD5_pos, SHA1_pos; -+ const u8 *MD5_addr[3]; -+ size_t MD5_len[3]; -+ const unsigned char *SHA1_addr[3]; -+ size_t SHA1_len[3]; -+ -+ if (secret_len & 1) -+ return -1; -+ -+ MD5_addr[0] = A_MD5; -+ MD5_len[0] = MD5_MAC_LEN; -+ MD5_addr[1] = (unsigned char *) label; -+ MD5_len[1] = os_strlen(label); -+ MD5_addr[2] = seed; -+ MD5_len[2] = seed_len; -+ -+ SHA1_addr[0] = A_SHA1; -+ SHA1_len[0] = SHA1_MAC_LEN; -+ SHA1_addr[1] = (unsigned char *) label; -+ SHA1_len[1] = os_strlen(label); -+ SHA1_addr[2] = seed; -+ SHA1_len[2] = seed_len; -+ -+ /* RFC 2246, Chapter 5 -+ * A(0) = seed, A(i) = HMAC(secret, A(i-1)) -+ * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. -+ * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) -+ */ -+ -+ L_S1 = L_S2 = (secret_len + 1) / 2; -+ S1 = secret; -+ S2 = secret + L_S1; -+ if (secret_len & 1) { -+ /* The last byte of S1 will be shared with S2 */ -+ S2--; -+ } -+ -+ hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], -+ A_MD5); -+ hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); -+ -+ MD5_pos = MD5_MAC_LEN; -+ SHA1_pos = SHA1_MAC_LEN; -+ for (i = 0; i < outlen; i++) { -+ if (MD5_pos == MD5_MAC_LEN) { -+ hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr, -+ MD5_len, P_MD5); -+ MD5_pos = 0; -+ hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN, -+ A_MD5); -+ } -+ if (SHA1_pos == SHA1_MAC_LEN) { -+ hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, -+ P_SHA1); -+ SHA1_pos = 0; -+ hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); -+ } -+ -+ out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; -+ -+ MD5_pos++; -+ SHA1_pos++; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tprf.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tprf.c -new file mode 100644 -index 0000000000000..4a80e96f0193c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1-tprf.c -@@ -0,0 +1,76 @@ -+/* -+ * SHA1 T-PRF for EAP-FAST -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha1.h" -+#include "crypto.h" -+ -+/** -+ * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF) -+ * @key: Key for PRF -+ * @key_len: Length of the key in bytes -+ * @label: A unique label for each purpose of the PRF -+ * @seed: Seed value to bind into the key -+ * @seed_len: Length of the seed -+ * @buf: Buffer for the generated pseudo-random key -+ * @buf_len: Number of bytes of key to generate -+ * Returns: 0 on success, -1 of failure -+ * -+ * This function is used to derive new, cryptographically separate keys from a -+ * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5. -+ */ -+int sha1_t_prf(const u8 *key, size_t key_len, const char *label, -+ const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len) -+{ -+ unsigned char counter = 0; -+ size_t pos, plen; -+ u8 hash[SHA1_MAC_LEN]; -+ size_t label_len = os_strlen(label); -+ u8 output_len[2]; -+ const unsigned char *addr[5]; -+ size_t len[5]; -+ -+ addr[0] = hash; -+ len[0] = 0; -+ addr[1] = (unsigned char *) label; -+ len[1] = label_len + 1; -+ addr[2] = seed; -+ len[2] = seed_len; -+ addr[3] = output_len; -+ len[3] = 2; -+ addr[4] = &counter; -+ len[4] = 1; -+ -+ output_len[0] = (buf_len >> 8) & 0xff; -+ output_len[1] = buf_len & 0xff; -+ pos = 0; -+ while (pos < buf_len) { -+ counter++; -+ plen = buf_len - pos; -+ if (hmac_sha1_vector(key, key_len, 5, addr, len, hash)) -+ return -1; -+ if (plen >= SHA1_MAC_LEN) { -+ os_memcpy(&buf[pos], hash, SHA1_MAC_LEN); -+ pos += SHA1_MAC_LEN; -+ } else { -+ os_memcpy(&buf[pos], hash, plen); -+ break; -+ } -+ len[0] = SHA1_MAC_LEN; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.c -new file mode 100644 -index 0000000000000..fe00bdbc58699 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.c -@@ -0,0 +1,163 @@ -+/* -+ * SHA1 hash implementation and interface functions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha1.h" -+#include "crypto.h" -+ -+ -+/** -+ * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash (20 bytes) -+ * Returns: 0 on success, -1 on failure -+ */ -+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, -+ const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ -+ unsigned char tk[20]; -+ const u8 *_addr[6]; -+ size_t _len[6], i; -+ -+ if (num_elem > 5) { -+ /* -+ * Fixed limit on the number of fragments to avoid having to -+ * allocate memory (which could fail). -+ */ -+ return -1; -+ } -+ -+ /* if key is longer than 64 bytes reset it to key = SHA1(key) */ -+ if (key_len > 64) { -+ if (sha1_vector(1, &key, &key_len, tk)) -+ return -1; -+ key = tk; -+ key_len = 20; -+ } -+ -+ /* the HMAC_SHA1 transform looks like: -+ * -+ * SHA1(K XOR opad, SHA1(K XOR ipad, text)) -+ * -+ * where K is an n byte key -+ * ipad is the byte 0x36 repeated 64 times -+ * opad is the byte 0x5c repeated 64 times -+ * and text is the data being protected */ -+ -+ /* start out by storing key in ipad */ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ /* XOR key with ipad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x36; -+ -+ /* perform inner SHA1 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ for (i = 0; i < num_elem; i++) { -+ _addr[i + 1] = addr[i]; -+ _len[i + 1] = len[i]; -+ } -+ if (sha1_vector(1 + num_elem, _addr, _len, mac)) -+ return -1; -+ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ /* XOR key with opad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x5c; -+ -+ /* perform outer SHA1 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ _addr[1] = mac; -+ _len[1] = SHA1_MAC_LEN; -+ return sha1_vector(2, _addr, _len, mac); -+} -+ -+ -+/** -+ * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @data: Pointers to the data area -+ * @data_len: Length of the data area -+ * @mac: Buffer for the hash (20 bytes) -+ * Returns: 0 on success, -1 of failure -+ */ -+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); -+} -+ -+ -+/** -+ * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) -+ * @key: Key for PRF -+ * @key_len: Length of the key in bytes -+ * @label: A unique label for each purpose of the PRF -+ * @data: Extra data to bind into the key -+ * @data_len: Length of the data -+ * @buf: Buffer for the generated pseudo-random key -+ * @buf_len: Number of bytes of key to generate -+ * Returns: 0 on success, -1 of failure -+ * -+ * This function is used to derive new, cryptographically separate keys from a -+ * given key (e.g., PMK in IEEE 802.11i). -+ */ -+int sha1_prf(const u8 *key, size_t key_len, const char *label, -+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len) -+{ -+ u8 counter = 0; -+ size_t pos, plen; -+ u8 hash[SHA1_MAC_LEN]; -+ size_t label_len = os_strlen(label) + 1; -+ const unsigned char *addr[3]; -+ size_t len[3]; -+ -+ addr[0] = (u8 *) label; -+ len[0] = label_len; -+ addr[1] = data; -+ len[1] = data_len; -+ addr[2] = &counter; -+ len[2] = 1; -+ -+ pos = 0; -+ while (pos < buf_len) { -+ plen = buf_len - pos; -+ if (plen >= SHA1_MAC_LEN) { -+ if (hmac_sha1_vector(key, key_len, 3, addr, len, -+ &buf[pos])) -+ return -1; -+ pos += SHA1_MAC_LEN; -+ } else { -+ if (hmac_sha1_vector(key, key_len, 3, addr, len, -+ hash)) -+ return -1; -+ os_memcpy(&buf[pos], hash, plen); -+ break; -+ } -+ counter++; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.h -new file mode 100644 -index 0000000000000..c1a6233bb0fb5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1.h -@@ -0,0 +1,33 @@ -+/* -+ * SHA1 hash implementation and interface functions -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef SHA1_H -+#define SHA1_H -+ -+#define SHA1_MAC_LEN 20 -+ -+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 sha1_prf(const u8 *key, size_t key_len, const char *label, -+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len); -+int sha1_t_prf(const u8 *key, size_t key_len, const char *label, -+ const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len); -+int __must_check tls_prf(const u8 *secret, size_t secret_len, -+ const char *label, const u8 *seed, size_t seed_len, -+ u8 *out, size_t outlen); -+int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, -+ int iterations, u8 *buf, size_t buflen); -+#endif /* SHA1_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1_i.h -new file mode 100644 -index 0000000000000..ec2f82f75b969 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha1_i.h -@@ -0,0 +1,29 @@ -+/* -+ * SHA1 internal definitions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef SHA1_I_H -+#define SHA1_I_H -+ -+struct SHA1Context { -+ u32 state[5]; -+ u32 count[2]; -+ unsigned char buffer[64]; -+}; -+ -+void SHA1Init(struct SHA1Context *context); -+void SHA1Update(struct SHA1Context *context, const void *data, u32 len); -+void SHA1Final(unsigned char digest[20], struct SHA1Context *context); -+void SHA1Transform(u32 state[5], const unsigned char buffer[64]); -+ -+#endif /* SHA1_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256-internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256-internal.c -new file mode 100644 -index 0000000000000..b0613739fbc65 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256-internal.c -@@ -0,0 +1,243 @@ -+/* -+ * SHA-256 hash implementation and interface functions -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha256.h" -+#include "crypto.h" -+ -+struct sha256_state { -+ u64 length; -+ u32 state[8], curlen; -+ u8 buf[64]; -+}; -+ -+static void sha256_init(struct sha256_state *md); -+static int sha256_process(struct sha256_state *md, const unsigned char *in, -+ unsigned long inlen); -+static int sha256_done(struct sha256_state *md, unsigned char *out); -+ -+ -+/** -+ * sha256_vector - SHA256 hash for data vector -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash -+ * Returns: 0 on success, -1 of failure -+ */ -+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *mac) -+{ -+ struct sha256_state ctx; -+ size_t i; -+ -+ sha256_init(&ctx); -+ for (i = 0; i < num_elem; i++) -+ if (sha256_process(&ctx, addr[i], len[i])) -+ return -1; -+ if (sha256_done(&ctx, mac)) -+ return -1; -+ return 0; -+} -+ -+ -+/* ===== start - public domain SHA256 implementation ===== */ -+ -+/* This is based on SHA256 implementation in LibTomCrypt that was released into -+ * public domain by Tom St Denis. */ -+ -+/* the K array */ -+static const unsigned long K[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 -+}; -+ -+ -+/* Various logical functions */ -+#define RORc(x, y) \ -+( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ -+ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) -+#define Ch(x,y,z) (z ^ (x & (y ^ z))) -+#define Maj(x,y,z) (((x | y) & z) | (x & y)) -+#define S(x, n) RORc((x), (n)) -+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) -+#ifndef MIN -+#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -+#endif -+ -+/* compress 512-bits */ -+static int sha256_compress(struct sha256_state *md, unsigned char *buf) -+{ -+ u32 S[8], W[64], t0, t1; -+ u32 t; -+ int i; -+ -+ /* copy state into S */ -+ for (i = 0; i < 8; i++) { -+ S[i] = md->state[i]; -+ } -+ -+ /* copy the state into 512-bits into W[0..15] */ -+ for (i = 0; i < 16; i++) -+ W[i] = WPA_GET_BE32(buf + (4 * i)); -+ -+ /* fill W[16..63] */ -+ for (i = 16; i < 64; i++) { -+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + -+ W[i - 16]; -+ } -+ -+ /* Compress */ -+#define RND(a,b,c,d,e,f,g,h,i) \ -+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ -+ t1 = Sigma0(a) + Maj(a, b, c); \ -+ d += t0; \ -+ h = t0 + t1; -+ -+ for (i = 0; i < 64; ++i) { -+ RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); -+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; -+ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; -+ } -+ -+ /* feedback */ -+ for (i = 0; i < 8; i++) { -+ md->state[i] = md->state[i] + S[i]; -+ } -+ return 0; -+} -+ -+ -+/* Initialize the hash state */ -+static void sha256_init(struct sha256_state *md) -+{ -+ md->curlen = 0; -+ md->length = 0; -+ md->state[0] = 0x6A09E667UL; -+ md->state[1] = 0xBB67AE85UL; -+ md->state[2] = 0x3C6EF372UL; -+ md->state[3] = 0xA54FF53AUL; -+ md->state[4] = 0x510E527FUL; -+ md->state[5] = 0x9B05688CUL; -+ md->state[6] = 0x1F83D9ABUL; -+ md->state[7] = 0x5BE0CD19UL; -+} -+ -+/** -+ Process a block of memory though the hash -+ @param md The hash state -+ @param in The data to hash -+ @param inlen The length of the data (octets) -+ @return CRYPT_OK if successful -+*/ -+static int sha256_process(struct sha256_state *md, const unsigned char *in, -+ unsigned long inlen) -+{ -+ unsigned long n; -+#define block_size 64 -+ -+ if (md->curlen > sizeof(md->buf)) -+ return -1; -+ -+ while (inlen > 0) { -+ if (md->curlen == 0 && inlen >= block_size) { -+ if (sha256_compress(md, (unsigned char *) in) < 0) -+ return -1; -+ md->length += block_size * 8; -+ in += block_size; -+ inlen -= block_size; -+ } else { -+ n = MIN(inlen, (block_size - md->curlen)); -+ os_memcpy(md->buf + md->curlen, in, n); -+ md->curlen += n; -+ in += n; -+ inlen -= n; -+ if (md->curlen == block_size) { -+ if (sha256_compress(md, md->buf) < 0) -+ return -1; -+ md->length += 8 * block_size; -+ md->curlen = 0; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ Terminate the hash to get the digest -+ @param md The hash state -+ @param out [out] The destination of the hash (32 bytes) -+ @return CRYPT_OK if successful -+*/ -+static int sha256_done(struct sha256_state *md, unsigned char *out) -+{ -+ int i; -+ -+ if (md->curlen >= sizeof(md->buf)) -+ return -1; -+ -+ /* increase the length of the message */ -+ md->length += md->curlen * 8; -+ -+ /* append the '1' bit */ -+ md->buf[md->curlen++] = (unsigned char) 0x80; -+ -+ /* if the length is currently above 56 bytes we append zeros -+ * then compress. Then we can fall back to padding zeros and length -+ * encoding like normal. -+ */ -+ if (md->curlen > 56) { -+ while (md->curlen < 64) { -+ md->buf[md->curlen++] = (unsigned char) 0; -+ } -+ sha256_compress(md, md->buf); -+ md->curlen = 0; -+ } -+ -+ /* pad upto 56 bytes of zeroes */ -+ while (md->curlen < 56) { -+ md->buf[md->curlen++] = (unsigned char) 0; -+ } -+ -+ /* store length */ -+ WPA_PUT_BE64(md->buf + 56, md->length); -+ sha256_compress(md, md->buf); -+ -+ /* copy output */ -+ for (i = 0; i < 8; i++) -+ WPA_PUT_BE32(out + (4 * i), md->state[i]); -+ -+ return 0; -+} -+ -+/* ===== end - public domain SHA256 implementation ===== */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.c -new file mode 100644 -index 0000000000000..7f320f9bfea5e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.c -@@ -0,0 +1,157 @@ -+/* -+ * SHA-256 hash implementation and interface functions -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "sha256.h" -+#include "crypto.h" -+ -+ -+/** -+ * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @num_elem: Number of elements in the data vector -+ * @addr: Pointers to the data areas -+ * @len: Lengths of the data blocks -+ * @mac: Buffer for the hash (32 bytes) -+ */ -+void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, -+ const u8 *addr[], const size_t *len, u8 *mac) -+{ -+ unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ -+ unsigned char tk[32]; -+ const u8 *_addr[6]; -+ size_t _len[6], i; -+ -+ if (num_elem > 5) { -+ /* -+ * Fixed limit on the number of fragments to avoid having to -+ * allocate memory (which could fail). -+ */ -+ return; -+ } -+ -+ /* if key is longer than 64 bytes reset it to key = SHA256(key) */ -+ if (key_len > 64) { -+ sha256_vector(1, &key, &key_len, tk); -+ key = tk; -+ key_len = 32; -+ } -+ -+ /* the HMAC_SHA256 transform looks like: -+ * -+ * SHA256(K XOR opad, SHA256(K XOR ipad, text)) -+ * -+ * where K is an n byte key -+ * ipad is the byte 0x36 repeated 64 times -+ * opad is the byte 0x5c repeated 64 times -+ * and text is the data being protected */ -+ -+ /* start out by storing key in ipad */ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ /* XOR key with ipad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x36; -+ -+ /* perform inner SHA256 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ for (i = 0; i < num_elem; i++) { -+ _addr[i + 1] = addr[i]; -+ _len[i + 1] = len[i]; -+ } -+ sha256_vector(1 + num_elem, _addr, _len, mac); -+ -+ os_memset(k_pad, 0, sizeof(k_pad)); -+ os_memcpy(k_pad, key, key_len); -+ /* XOR key with opad values */ -+ for (i = 0; i < 64; i++) -+ k_pad[i] ^= 0x5c; -+ -+ /* perform outer SHA256 */ -+ _addr[0] = k_pad; -+ _len[0] = 64; -+ _addr[1] = mac; -+ _len[1] = SHA256_MAC_LEN; -+ sha256_vector(2, _addr, _len, mac); -+} -+ -+ -+/** -+ * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) -+ * @key: Key for HMAC operations -+ * @key_len: Length of the key in bytes -+ * @data: Pointers to the data area -+ * @data_len: Length of the data area -+ * @mac: Buffer for the hash (20 bytes) -+ */ -+void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, -+ size_t data_len, u8 *mac) -+{ -+ hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); -+} -+ -+ -+/** -+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) -+ * @key: Key for PRF -+ * @key_len: Length of the key in bytes -+ * @label: A unique label for each purpose of the PRF -+ * @data: Extra data to bind into the key -+ * @data_len: Length of the data -+ * @buf: Buffer for the generated pseudo-random key -+ * @buf_len: Number of bytes of key to generate -+ * -+ * This function is used to derive new, cryptographically separate keys from a -+ * given key. -+ */ -+void sha256_prf(const u8 *key, size_t key_len, const char *label, -+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len) -+{ -+ u16 counter = 1; -+ size_t pos, plen; -+ u8 hash[SHA256_MAC_LEN]; -+ const u8 *addr[4]; -+ size_t len[4]; -+ u8 counter_le[2], length_le[2]; -+ -+ addr[0] = counter_le; -+ len[0] = 2; -+ addr[1] = (u8 *) label; -+ len[1] = os_strlen(label); -+ addr[2] = data; -+ len[2] = data_len; -+ addr[3] = length_le; -+ len[3] = sizeof(length_le); -+ -+ WPA_PUT_LE16(length_le, buf_len * 8); -+ pos = 0; -+ while (pos < buf_len) { -+ plen = buf_len - pos; -+ WPA_PUT_LE16(counter_le, counter); -+ if (plen >= SHA256_MAC_LEN) { -+ hmac_sha256_vector(key, key_len, 4, addr, len, -+ &buf[pos]); -+ pos += SHA256_MAC_LEN; -+ } else { -+ hmac_sha256_vector(key, key_len, 4, addr, len, hash); -+ os_memcpy(&buf[pos], hash, plen); -+ break; -+ } -+ counter++; -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.h -new file mode 100644 -index 0000000000000..dc597f09b53ae ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/sha256.h -@@ -0,0 +1,27 @@ -+/* -+ * SHA256 hash implementation and interface functions -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef SHA256_H -+#define SHA256_H -+ -+#define SHA256_MAC_LEN 32 -+ -+void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, -+ const u8 *addr[], const size_t *len, u8 *mac); -+void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, -+ size_t data_len, u8 *mac); -+void sha256_prf(const u8 *key, size_t key_len, const char *label, -+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len); -+ -+#endif /* SHA256_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls.h -new file mode 100644 -index 0000000000000..0928b5ba43b74 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls.h -@@ -0,0 +1,569 @@ -+/* -+ * SSL/TLS interface definition -+ * Copyright (c) 2004-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLS_H -+#define TLS_H -+ -+struct tls_connection; -+ -+struct tls_keys { -+ const u8 *master_key; /* TLS master secret */ -+ size_t master_key_len; -+ const u8 *client_random; -+ size_t client_random_len; -+ const u8 *server_random; -+ size_t server_random_len; -+ const u8 *inner_secret; /* TLS/IA inner secret */ -+ size_t inner_secret_len; -+}; -+ -+enum tls_event { -+ TLS_CERT_CHAIN_FAILURE, -+ TLS_PEER_CERTIFICATE -+}; -+ -+/* -+ * Note: These are used as identifier with external programs and as such, the -+ * values must not be changed. -+ */ -+enum tls_fail_reason { -+ TLS_FAIL_UNSPECIFIED = 0, -+ TLS_FAIL_UNTRUSTED = 1, -+ TLS_FAIL_REVOKED = 2, -+ TLS_FAIL_NOT_YET_VALID = 3, -+ TLS_FAIL_EXPIRED = 4, -+ TLS_FAIL_SUBJECT_MISMATCH = 5, -+ TLS_FAIL_ALTSUBJECT_MISMATCH = 6, -+ TLS_FAIL_BAD_CERTIFICATE = 7, -+ TLS_FAIL_SERVER_CHAIN_PROBE = 8 -+}; -+ -+union tls_event_data { -+ struct { -+ int depth; -+ const char *subject; -+ enum tls_fail_reason reason; -+ const char *reason_txt; -+ const struct wpabuf *cert; -+ } cert_fail; -+ -+ struct { -+ int depth; -+ const char *subject; -+ const struct wpabuf *cert; -+ const u8 *hash; -+ size_t hash_len; -+ } peer_cert; -+}; -+ -+struct tls_config { -+ const char *opensc_engine_path; -+ const char *pkcs11_engine_path; -+ const char *pkcs11_module_path; -+ int fips_mode; -+ -+ void (*event_cb)(void *ctx, enum tls_event ev, -+ union tls_event_data *data); -+ void *cb_ctx; -+}; -+ -+#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0) -+#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1) -+ -+/** -+ * struct tls_connection_params - Parameters for TLS connection -+ * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER -+ * format -+ * @ca_cert_blob: ca_cert as inlined data or %NULL if not used -+ * @ca_cert_blob_len: ca_cert_blob length -+ * @ca_path: Path to CA certificates (OpenSSL specific) -+ * @subject_match: String to match in the subject of the peer certificate or -+ * %NULL to allow all subjects -+ * @altsubject_match: String to match in the alternative subject of the peer -+ * certificate or %NULL to allow all alternative subjects -+ * @client_cert: File or reference name for client X.509 certificate in PEM or -+ * DER format -+ * @client_cert_blob: client_cert as inlined data or %NULL if not used -+ * @client_cert_blob_len: client_cert_blob length -+ * @private_key: File or reference name for client private key in PEM or DER -+ * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY) -+ * @private_key_blob: private_key as inlined data or %NULL if not used -+ * @private_key_blob_len: private_key_blob length -+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no -+ * passphrase is used. -+ * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used -+ * @dh_blob: dh_file as inlined data or %NULL if not used -+ * @dh_blob_len: dh_blob length -+ * @engine: 1 = use engine (e.g., a smartcard) for private key operations -+ * (this is OpenSSL specific for now) -+ * @engine_id: engine id string (this is OpenSSL specific for now) -+ * @ppin: pointer to the pin variable in the configuration -+ * (this is OpenSSL specific for now) -+ * @key_id: the private key's id when using engine (this is OpenSSL -+ * specific for now) -+ * @cert_id: the certificate's id when using engine -+ * @ca_cert_id: the CA certificate's id when using engine -+ * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1) -+ * @flags: Parameter options (TLS_CONN_*) -+ * -+ * TLS connection parameters to be configured with tls_connection_set_params() -+ * and tls_global_set_params(). -+ * -+ * Certificates and private key can be configured either as a reference name -+ * (file path or reference to certificate store) or by providing the same data -+ * as a pointer to the data in memory. Only one option will be used for each -+ * field. -+ */ -+struct tls_connection_params { -+ const char *ca_cert; -+ const u8 *ca_cert_blob; -+ size_t ca_cert_blob_len; -+ const char *ca_path; -+ const char *subject_match; -+ const char *altsubject_match; -+ const char *client_cert; -+ const u8 *client_cert_blob; -+ size_t client_cert_blob_len; -+ const char *private_key; -+ const u8 *private_key_blob; -+ size_t private_key_blob_len; -+ const char *private_key_passwd; -+ const char *dh_file; -+ const u8 *dh_blob; -+ size_t dh_blob_len; -+ int tls_ia; -+ -+ /* OpenSSL specific variables */ -+ int engine; -+ const char *engine_id; -+ const char *pin; -+ const char *key_id; -+ const char *cert_id; -+ const char *ca_cert_id; -+ -+ unsigned int flags; -+}; -+ -+ -+/** -+ * tls_init - Initialize TLS library -+ * @conf: Configuration data for TLS library -+ * Returns: Context data to be used as tls_ctx in calls to other functions, -+ * or %NULL on failure. -+ * -+ * Called once during program startup and once for each RSN pre-authentication -+ * session. In other words, there can be two concurrent TLS contexts. If global -+ * library initialization is needed (i.e., one that is shared between both -+ * authentication types), the TLS library wrapper should maintain a reference -+ * counter and do global initialization only when moving from 0 to 1 reference. -+ */ -+void * tls_init(const struct tls_config *conf); -+ -+/** -+ * tls_deinit - Deinitialize TLS library -+ * @tls_ctx: TLS context data from tls_init() -+ * -+ * Called once during program shutdown and once for each RSN pre-authentication -+ * session. If global library deinitialization is needed (i.e., one that is -+ * shared between both authentication types), the TLS library wrapper should -+ * maintain a reference counter and do global deinitialization only when moving -+ * from 1 to 0 references. -+ */ -+void tls_deinit(void *tls_ctx); -+ -+/** -+ * tls_get_errors - Process pending errors -+ * @tls_ctx: TLS context data from tls_init() -+ * Returns: Number of found error, 0 if no errors detected. -+ * -+ * Process all pending TLS errors. -+ */ -+int tls_get_errors(void *tls_ctx); -+ -+/** -+ * tls_connection_init - Initialize a new TLS connection -+ * @tls_ctx: TLS context data from tls_init() -+ * Returns: Connection context data, conn for other function calls -+ */ -+struct tls_connection * tls_connection_init(void *tls_ctx); -+ -+/** -+ * tls_connection_deinit - Free TLS connection data -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * -+ * Release all resources allocated for TLS connection. -+ */ -+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn); -+ -+/** -+ * tls_connection_established - Has the TLS connection been completed? -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: 1 if TLS connection has been completed, 0 if not. -+ */ -+int tls_connection_established(void *tls_ctx, struct tls_connection *conn); -+ -+/** -+ * tls_connection_shutdown - Shutdown TLS connection -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: 0 on success, -1 on failure -+ * -+ * Shutdown current TLS connection without releasing all resources. New -+ * connection can be started by using the same conn without having to call -+ * tls_connection_init() or setting certificates etc. again. The new -+ * connection should try to use session resumption. -+ */ -+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn); -+ -+enum { -+ TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3, -+ TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2 -+}; -+ -+/** -+ * tls_connection_set_params - Set TLS connection parameters -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @params: Connection parameters -+ * Returns: 0 on success, -1 on failure, -+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing -+ * PKCS#11 engine failure, or -+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the -+ * PKCS#11 engine private key. -+ */ -+int __must_check -+tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, -+ const struct tls_connection_params *params); -+ -+/** -+ * tls_global_set_params - Set TLS parameters for all TLS connection -+ * @tls_ctx: TLS context data from tls_init() -+ * @params: Global TLS parameters -+ * Returns: 0 on success, -1 on failure, -+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing -+ * PKCS#11 engine failure, or -+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the -+ * PKCS#11 engine private key. -+ */ -+int __must_check tls_global_set_params( -+ void *tls_ctx, const struct tls_connection_params *params); -+ -+/** -+ * tls_global_set_verify - Set global certificate verification options -+ * @tls_ctx: TLS context data from tls_init() -+ * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate, -+ * 2 = verify CRL for all certificates -+ * Returns: 0 on success, -1 on failure -+ */ -+int __must_check tls_global_set_verify(void *tls_ctx, int check_crl); -+ -+/** -+ * tls_connection_set_verify - Set certificate verification options -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @verify_peer: 1 = verify peer certificate -+ * Returns: 0 on success, -1 on failure -+ */ -+int __must_check tls_connection_set_verify(void *tls_ctx, -+ struct tls_connection *conn, -+ int verify_peer); -+ -+/** -+ * tls_connection_set_ia - Set TLS/IA parameters -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @tls_ia: 1 = enable TLS/IA -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to configure TLS/IA in server mode where -+ * tls_connection_set_params() is not used. -+ */ -+int __must_check tls_connection_set_ia(void *tls_ctx, -+ struct tls_connection *conn, -+ int tls_ia); -+ -+/** -+ * tls_connection_get_keys - Get master key and random data from TLS connection -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @keys: Structure of key/random data (filled on success) -+ * Returns: 0 on success, -1 on failure -+ */ -+int __must_check tls_connection_get_keys(void *tls_ctx, -+ struct tls_connection *conn, -+ struct tls_keys *keys); -+ -+/** -+ * tls_connection_prf - Use TLS-PRF to derive keying material -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @label: Label (e.g., description of the key) for PRF -+ * @server_random_first: seed is 0 = client_random|server_random, -+ * 1 = server_random|client_random -+ * @out: Buffer for output data from TLS-PRF -+ * @out_len: Length of the output buffer -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is optional to implement if tls_connection_get_keys() provides -+ * access to master secret and server/client random values. If these values are -+ * not exported from the TLS library, tls_connection_prf() is required so that -+ * further keying material can be derived from the master secret. If not -+ * implemented, the function will still need to be defined, but it can just -+ * return -1. Example implementation of this function is in tls_prf() function -+ * when it is called with seed set to client_random|server_random (or -+ * server_random|client_random). -+ */ -+int __must_check tls_connection_prf(void *tls_ctx, -+ struct tls_connection *conn, -+ const char *label, -+ int server_random_first, -+ u8 *out, size_t out_len); -+ -+/** -+ * tls_connection_handshake - Process TLS handshake (client side) -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @in_data: Input data from TLS server -+ * @appl_data: Pointer to application data pointer, or %NULL if dropped -+ * Returns: Output data, %NULL on failure -+ * -+ * The caller is responsible for freeing the returned output data. If the final -+ * handshake message includes application data, this is decrypted and -+ * appl_data (if not %NULL) is set to point this data. The caller is -+ * responsible for freeing appl_data. -+ * -+ * This function is used during TLS handshake. The first call is done with -+ * in_data == %NULL and the library is expected to return ClientHello packet. -+ * This packet is then send to the server and a response from server is given -+ * to TLS library by calling this function again with in_data pointing to the -+ * TLS message from the server. -+ * -+ * If the TLS handshake fails, this function may return %NULL. However, if the -+ * TLS library has a TLS alert to send out, that should be returned as the -+ * output data. In this case, tls_connection_get_failed() must return failure -+ * (> 0). -+ * -+ * tls_connection_established() should return 1 once the TLS handshake has been -+ * completed successfully. -+ */ -+struct wpabuf * tls_connection_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data); -+ -+/** -+ * tls_connection_server_handshake - Process TLS handshake (server side) -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @in_data: Input data from TLS peer -+ * @appl_data: Pointer to application data pointer, or %NULL if dropped -+ * Returns: Output data, %NULL on failure -+ * -+ * The caller is responsible for freeing the returned output data. -+ */ -+struct wpabuf * tls_connection_server_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data); -+ -+/** -+ * tls_connection_encrypt - Encrypt data into TLS tunnel -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @in_data: Plaintext data to be encrypted -+ * Returns: Encrypted TLS data or %NULL on failure -+ * -+ * This function is used after TLS handshake has been completed successfully to -+ * send data in the encrypted tunnel. The caller is responsible for freeing the -+ * returned output data. -+ */ -+struct wpabuf * tls_connection_encrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data); -+ -+/** -+ * tls_connection_decrypt - Decrypt data from TLS tunnel -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @in_data: Encrypted TLS data -+ * Returns: Decrypted TLS data or %NULL on failure -+ * -+ * This function is used after TLS handshake has been completed successfully to -+ * receive data from the encrypted tunnel. The caller is responsible for -+ * freeing the returned output data. -+ */ -+struct wpabuf * tls_connection_decrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data); -+ -+/** -+ * tls_connection_resumed - Was session resumption used -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: 1 if current session used session resumption, 0 if not -+ */ -+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn); -+ -+enum { -+ TLS_CIPHER_NONE, -+ TLS_CIPHER_RC4_SHA /* 0x0005 */, -+ TLS_CIPHER_AES128_SHA /* 0x002f */, -+ TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */, -+ TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */ -+}; -+ -+/** -+ * tls_connection_set_cipher_list - Configure acceptable cipher suites -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers -+ * (TLS_CIPHER_*). -+ * Returns: 0 on success, -1 on failure -+ */ -+int __must_check tls_connection_set_cipher_list(void *tls_ctx, -+ struct tls_connection *conn, -+ u8 *ciphers); -+ -+/** -+ * tls_get_cipher - Get current cipher name -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @buf: Buffer for the cipher name -+ * @buflen: buf size -+ * Returns: 0 on success, -1 on failure -+ * -+ * Get the name of the currently used cipher. -+ */ -+int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn, -+ char *buf, size_t buflen); -+ -+/** -+ * tls_connection_enable_workaround - Enable TLS workaround options -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to enable connection-specific workaround options for -+ * buffer SSL/TLS implementations. -+ */ -+int __must_check tls_connection_enable_workaround(void *tls_ctx, -+ struct tls_connection *conn); -+ -+/** -+ * tls_connection_client_hello_ext - Set TLS extension for ClientHello -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @ext_type: Extension type -+ * @data: Extension payload (%NULL to remove extension) -+ * @data_len: Extension payload length -+ * Returns: 0 on success, -1 on failure -+ */ -+int __must_check tls_connection_client_hello_ext(void *tls_ctx, -+ struct tls_connection *conn, -+ int ext_type, const u8 *data, -+ size_t data_len); -+ -+/** -+ * tls_connection_get_failed - Get connection failure status -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * -+ * Returns >0 if connection has failed, 0 if not. -+ */ -+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn); -+ -+/** -+ * tls_connection_get_read_alerts - Get connection read alert status -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: Number of times a fatal read (remote end reported error) has -+ * happened during this connection. -+ */ -+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn); -+ -+/** -+ * tls_connection_get_write_alerts - Get connection write alert status -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: Number of times a fatal write (locally detected error) has happened -+ * during this connection. -+ */ -+int tls_connection_get_write_alerts(void *tls_ctx, -+ struct tls_connection *conn); -+ -+/** -+ * tls_connection_get_keyblock_size - Get TLS key_block size -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on -+ * failure -+ */ -+int tls_connection_get_keyblock_size(void *tls_ctx, -+ struct tls_connection *conn); -+ -+#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */ -+/** -+ * tls_capabilities - Get supported TLS capabilities -+ * @tls_ctx: TLS context data from tls_init() -+ * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*) -+ */ -+unsigned int tls_capabilities(void *tls_ctx); -+ -+/** -+ * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished -+ * Returns: Encrypted TLS/IA data, %NULL on failure -+ * -+ * This function is used to send the TLS/IA end phase message, e.g., when the -+ * EAP server completes EAP-TTLSv1. -+ */ -+struct wpabuf * tls_connection_ia_send_phase_finished( -+ void *tls_ctx, struct tls_connection *conn, int final); -+ -+/** -+ * tls_connection_ia_final_phase_finished - Has final phase been completed -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1 -+ * on failure -+ */ -+int __must_check tls_connection_ia_final_phase_finished( -+ void *tls_ctx, struct tls_connection *conn); -+ -+/** -+ * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret -+ * @tls_ctx: TLS context data from tls_init() -+ * @conn: Connection context data from tls_connection_init() -+ * @key: Session key material (session_key vectors with 2-octet length), or -+ * %NULL if no session key was generating in the current phase -+ * @key_len: Length of session key material -+ * Returns: 0 on success, -1 on failure -+ */ -+int __must_check tls_connection_ia_permute_inner_secret( -+ void *tls_ctx, struct tls_connection *conn, -+ const u8 *key, size_t key_len); -+ -+typedef int (*tls_session_ticket_cb) -+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, -+ const u8 *server_random, u8 *master_secret); -+ -+int __must_check tls_connection_set_session_ticket_cb( -+ void *tls_ctx, struct tls_connection *conn, -+ tls_session_ticket_cb cb, void *ctx); -+ -+#endif /* TLS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_gnutls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_gnutls.c -new file mode 100644 -index 0000000000000..c3a7358c0e77b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_gnutls.c -@@ -0,0 +1,1457 @@ -+/* -+ * SSL/TLS interface functions for GnuTLS -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#ifdef PKCS12_FUNCS -+#include -+#endif /* PKCS12_FUNCS */ -+ -+#ifdef CONFIG_GNUTLS_EXTRA -+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 -+#define GNUTLS_IA -+#include -+#if LIBGNUTLS_VERSION_NUMBER == 0x010302 -+/* This function is not included in the current gnutls/extra.h even though it -+ * should be, so define it here as a workaround for the time being. */ -+int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum); -+#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */ -+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -+#endif /* CONFIG_GNUTLS_EXTRA */ -+ -+#include "common.h" -+#include "tls.h" -+ -+ -+#ifndef TLS_RANDOM_SIZE -+#define TLS_RANDOM_SIZE 32 -+#endif -+#ifndef TLS_MASTER_SIZE -+#define TLS_MASTER_SIZE 48 -+#endif -+ -+ -+#if LIBGNUTLS_VERSION_NUMBER < 0x010302 -+/* GnuTLS 1.3.2 added functions for using master secret. Older versions require -+ * use of internal structures to get the master_secret and -+ * {server,client}_random. -+ */ -+#define GNUTLS_INTERNAL_STRUCTURE_HACK -+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ -+ -+ -+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK -+/* -+ * It looks like gnutls does not provide access to client/server_random and -+ * master_key. This is somewhat unfortunate since these are needed for key -+ * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible -+ * hack that copies the gnutls_session_int definition from gnutls_int.h so that -+ * we can get the needed information. -+ */ -+ -+typedef u8 uint8; -+typedef unsigned char opaque; -+typedef struct { -+ uint8 suite[2]; -+} cipher_suite_st; -+ -+typedef struct { -+ gnutls_connection_end_t entity; -+ gnutls_kx_algorithm_t kx_algorithm; -+ gnutls_cipher_algorithm_t read_bulk_cipher_algorithm; -+ gnutls_mac_algorithm_t read_mac_algorithm; -+ gnutls_compression_method_t read_compression_algorithm; -+ gnutls_cipher_algorithm_t write_bulk_cipher_algorithm; -+ gnutls_mac_algorithm_t write_mac_algorithm; -+ gnutls_compression_method_t write_compression_algorithm; -+ cipher_suite_st current_cipher_suite; -+ opaque master_secret[TLS_MASTER_SIZE]; -+ opaque client_random[TLS_RANDOM_SIZE]; -+ opaque server_random[TLS_RANDOM_SIZE]; -+ /* followed by stuff we are not interested in */ -+} security_parameters_st; -+ -+struct gnutls_session_int { -+ security_parameters_st security_parameters; -+ /* followed by things we are not interested in */ -+}; -+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ -+ -+static int tls_gnutls_ref_count = 0; -+ -+struct tls_global { -+ /* Data for session resumption */ -+ void *session_data; -+ size_t session_data_size; -+ -+ int server; -+ -+ int params_set; -+ gnutls_certificate_credentials_t xcred; -+}; -+ -+struct tls_connection { -+ gnutls_session session; -+ char *subject_match, *altsubject_match; -+ int read_alerts, write_alerts, failed; -+ -+ u8 *pre_shared_secret; -+ size_t pre_shared_secret_len; -+ int established; -+ int verify_peer; -+ -+ struct wpabuf *push_buf; -+ struct wpabuf *pull_buf; -+ const u8 *pull_buf_offset; -+ -+ int params_set; -+ gnutls_certificate_credentials_t xcred; -+ -+ int tls_ia; -+ int final_phase_finished; -+ -+#ifdef GNUTLS_IA -+ gnutls_ia_server_credentials_t iacred_srv; -+ gnutls_ia_client_credentials_t iacred_cli; -+ -+ /* Session keys generated in the current phase for inner secret -+ * permutation before generating/verifying PhaseFinished. */ -+ u8 *session_keys; -+ size_t session_keys_len; -+ -+ u8 inner_secret[TLS_MASTER_SIZE]; -+#endif /* GNUTLS_IA */ -+}; -+ -+ -+static void tls_log_func(int level, const char *msg) -+{ -+ char *s, *pos; -+ if (level == 6 || level == 7) { -+ /* These levels seem to be mostly I/O debug and msg dumps */ -+ return; -+ } -+ -+ s = os_strdup(msg); -+ if (s == NULL) -+ return; -+ -+ pos = s; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG, -+ "gnutls<%d> %s", level, s); -+ os_free(s); -+} -+ -+ -+extern int wpa_debug_show_keys; -+ -+void * tls_init(const struct tls_config *conf) -+{ -+ struct tls_global *global; -+ -+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK -+ /* Because of the horrible hack to get master_secret and client/server -+ * random, we need to make sure that the gnutls version is something -+ * that is expected to have same structure definition for the session -+ * data.. */ -+ const char *ver; -+ const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9", -+ "1.3.2", -+ NULL }; -+ int i; -+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ -+ -+ global = os_zalloc(sizeof(*global)); -+ if (global == NULL) -+ return NULL; -+ -+ if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) { -+ os_free(global); -+ return NULL; -+ } -+ tls_gnutls_ref_count++; -+ -+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK -+ ver = gnutls_check_version(NULL); -+ if (ver == NULL) { -+ tls_deinit(global); -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver); -+ for (i = 0; ok_ver[i]; i++) { -+ if (strcmp(ok_ver[i], ver) == 0) -+ break; -+ } -+ if (ok_ver[i] == NULL) { -+ wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs " -+ "to be tested and enabled in tls_gnutls.c", ver); -+ tls_deinit(global); -+ return NULL; -+ } -+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ -+ -+ gnutls_global_set_log_function(tls_log_func); -+ if (wpa_debug_show_keys) -+ gnutls_global_set_log_level(11); -+ return global; -+} -+ -+ -+void tls_deinit(void *ssl_ctx) -+{ -+ struct tls_global *global = ssl_ctx; -+ if (global) { -+ if (global->params_set) -+ gnutls_certificate_free_credentials(global->xcred); -+ os_free(global->session_data); -+ os_free(global); -+ } -+ -+ tls_gnutls_ref_count--; -+ if (tls_gnutls_ref_count == 0) -+ gnutls_global_deinit(); -+} -+ -+ -+int tls_get_errors(void *ssl_ctx) -+{ -+ return 0; -+} -+ -+ -+static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf, -+ size_t len) -+{ -+ struct tls_connection *conn = (struct tls_connection *) ptr; -+ const u8 *end; -+ if (conn->pull_buf == NULL) { -+ errno = EWOULDBLOCK; -+ return -1; -+ } -+ -+ end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf); -+ if ((size_t) (end - conn->pull_buf_offset) < len) -+ len = end - conn->pull_buf_offset; -+ os_memcpy(buf, conn->pull_buf_offset, len); -+ conn->pull_buf_offset += len; -+ if (conn->pull_buf_offset == end) { -+ wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); -+ wpabuf_free(conn->pull_buf); -+ conn->pull_buf = NULL; -+ conn->pull_buf_offset = NULL; -+ } else { -+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", -+ __func__, -+ (unsigned long) (end - conn->pull_buf_offset)); -+ } -+ return len; -+} -+ -+ -+static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, -+ size_t len) -+{ -+ struct tls_connection *conn = (struct tls_connection *) ptr; -+ -+ if (wpabuf_resize(&conn->push_buf, len) < 0) { -+ errno = ENOMEM; -+ return -1; -+ } -+ wpabuf_put_data(conn->push_buf, buf, len); -+ -+ return len; -+} -+ -+ -+static int tls_gnutls_init_session(struct tls_global *global, -+ struct tls_connection *conn) -+{ -+ const int cert_types[2] = { GNUTLS_CRT_X509, 0 }; -+ const int protos[2] = { GNUTLS_TLS1, 0 }; -+ int ret; -+ -+ ret = gnutls_init(&conn->session, -+ global->server ? GNUTLS_SERVER : GNUTLS_CLIENT); -+ if (ret < 0) { -+ wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS " -+ "connection: %s", gnutls_strerror(ret)); -+ return -1; -+ } -+ -+ ret = gnutls_set_default_priority(conn->session); -+ if (ret < 0) -+ goto fail; -+ -+ ret = gnutls_certificate_type_set_priority(conn->session, cert_types); -+ if (ret < 0) -+ goto fail; -+ -+ ret = gnutls_protocol_set_priority(conn->session, protos); -+ if (ret < 0) -+ goto fail; -+ -+ gnutls_transport_set_pull_function(conn->session, tls_pull_func); -+ gnutls_transport_set_push_function(conn->session, tls_push_func); -+ gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn); -+ -+ return 0; -+ -+fail: -+ wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s", -+ gnutls_strerror(ret)); -+ gnutls_deinit(conn->session); -+ return -1; -+} -+ -+ -+struct tls_connection * tls_connection_init(void *ssl_ctx) -+{ -+ struct tls_global *global = ssl_ctx; -+ struct tls_connection *conn; -+ int ret; -+ -+ conn = os_zalloc(sizeof(*conn)); -+ if (conn == NULL) -+ return NULL; -+ -+ if (tls_gnutls_init_session(global, conn)) { -+ os_free(conn); -+ return NULL; -+ } -+ -+ if (global->params_set) { -+ ret = gnutls_credentials_set(conn->session, -+ GNUTLS_CRD_CERTIFICATE, -+ global->xcred); -+ if (ret < 0) { -+ wpa_printf(MSG_INFO, "Failed to configure " -+ "credentials: %s", gnutls_strerror(ret)); -+ os_free(conn); -+ return NULL; -+ } -+ } -+ -+ if (gnutls_certificate_allocate_credentials(&conn->xcred)) { -+ os_free(conn); -+ return NULL; -+ } -+ -+ return conn; -+} -+ -+ -+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return; -+ -+#ifdef GNUTLS_IA -+ if (conn->iacred_srv) -+ gnutls_ia_free_server_credentials(conn->iacred_srv); -+ if (conn->iacred_cli) -+ gnutls_ia_free_client_credentials(conn->iacred_cli); -+ if (conn->session_keys) { -+ os_memset(conn->session_keys, 0, conn->session_keys_len); -+ os_free(conn->session_keys); -+ } -+#endif /* GNUTLS_IA */ -+ -+ gnutls_certificate_free_credentials(conn->xcred); -+ gnutls_deinit(conn->session); -+ os_free(conn->pre_shared_secret); -+ os_free(conn->subject_match); -+ os_free(conn->altsubject_match); -+ wpabuf_free(conn->push_buf); -+ wpabuf_free(conn->pull_buf); -+ os_free(conn); -+} -+ -+ -+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) -+{ -+ return conn ? conn->established : 0; -+} -+ -+ -+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) -+{ -+ struct tls_global *global = ssl_ctx; -+ int ret; -+ -+ if (conn == NULL) -+ return -1; -+ -+ /* Shutdown previous TLS connection without notifying the peer -+ * because the connection was already terminated in practice -+ * and "close notify" shutdown alert would confuse AS. */ -+ gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); -+ wpabuf_free(conn->push_buf); -+ conn->push_buf = NULL; -+ conn->established = 0; -+ conn->final_phase_finished = 0; -+#ifdef GNUTLS_IA -+ if (conn->session_keys) { -+ os_memset(conn->session_keys, 0, conn->session_keys_len); -+ os_free(conn->session_keys); -+ } -+ conn->session_keys_len = 0; -+#endif /* GNUTLS_IA */ -+ -+ gnutls_deinit(conn->session); -+ if (tls_gnutls_init_session(global, conn)) { -+ wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session " -+ "for session resumption use"); -+ return -1; -+ } -+ -+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, -+ conn->params_set ? conn->xcred : -+ global->xcred); -+ if (ret < 0) { -+ wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials " -+ "for session resumption: %s", gnutls_strerror(ret)); -+ return -1; -+ } -+ -+ if (global->session_data) { -+ ret = gnutls_session_set_data(conn->session, -+ global->session_data, -+ global->session_data_size); -+ if (ret < 0) { -+ wpa_printf(MSG_INFO, "GnuTLS: Failed to set session " -+ "data: %s", gnutls_strerror(ret)); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+#if 0 -+static int tls_match_altsubject(X509 *cert, const char *match) -+{ -+ GENERAL_NAME *gen; -+ char *field, *tmp; -+ void *ext; -+ int i, found = 0; -+ size_t len; -+ -+ ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); -+ -+ for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { -+ gen = sk_GENERAL_NAME_value(ext, i); -+ switch (gen->type) { -+ case GEN_EMAIL: -+ field = "EMAIL"; -+ break; -+ case GEN_DNS: -+ field = "DNS"; -+ break; -+ case GEN_URI: -+ field = "URI"; -+ break; -+ default: -+ field = NULL; -+ wpa_printf(MSG_DEBUG, "TLS: altSubjectName: " -+ "unsupported type=%d", gen->type); -+ break; -+ } -+ -+ if (!field) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s", -+ field, gen->d.ia5->data); -+ len = os_strlen(field) + 1 + -+ strlen((char *) gen->d.ia5->data) + 1; -+ tmp = os_malloc(len); -+ if (tmp == NULL) -+ continue; -+ snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data); -+ if (strstr(tmp, match)) -+ found++; -+ os_free(tmp); -+ } -+ -+ return found; -+} -+#endif -+ -+ -+#if 0 -+static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) -+{ -+ char buf[256]; -+ X509 *err_cert; -+ int err, depth; -+ SSL *ssl; -+ struct tls_connection *conn; -+ char *match, *altmatch; -+ -+ err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); -+ err = X509_STORE_CTX_get_error(x509_ctx); -+ depth = X509_STORE_CTX_get_error_depth(x509_ctx); -+ ssl = X509_STORE_CTX_get_ex_data(x509_ctx, -+ SSL_get_ex_data_X509_STORE_CTX_idx()); -+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); -+ -+ conn = SSL_get_app_data(ssl); -+ match = conn ? conn->subject_match : NULL; -+ altmatch = conn ? conn->altsubject_match : NULL; -+ -+ if (!preverify_ok) { -+ wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," -+ " error %d (%s) depth %d for '%s'", err, -+ X509_verify_cert_error_string(err), depth, buf); -+ } else { -+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " -+ "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", -+ preverify_ok, err, -+ X509_verify_cert_error_string(err), depth, buf); -+ if (depth == 0 && match && strstr(buf, match) == NULL) { -+ wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " -+ "match with '%s'", buf, match); -+ preverify_ok = 0; -+ } else if (depth == 0 && altmatch && -+ !tls_match_altsubject(err_cert, altmatch)) { -+ wpa_printf(MSG_WARNING, "TLS: altSubjectName match " -+ "'%s' not found", altmatch); -+ preverify_ok = 0; -+ } -+ } -+ -+ return preverify_ok; -+} -+#endif -+ -+ -+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, -+ const struct tls_connection_params *params) -+{ -+ int ret; -+ -+ if (conn == NULL || params == NULL) -+ return -1; -+ -+ os_free(conn->subject_match); -+ conn->subject_match = NULL; -+ if (params->subject_match) { -+ conn->subject_match = os_strdup(params->subject_match); -+ if (conn->subject_match == NULL) -+ return -1; -+ } -+ -+ os_free(conn->altsubject_match); -+ conn->altsubject_match = NULL; -+ if (params->altsubject_match) { -+ conn->altsubject_match = os_strdup(params->altsubject_match); -+ if (conn->altsubject_match == NULL) -+ return -1; -+ } -+ -+ /* TODO: gnutls_certificate_set_verify_flags(xcred, flags); -+ * to force peer validation(?) */ -+ -+ if (params->ca_cert) { -+ conn->verify_peer = 1; -+ ret = gnutls_certificate_set_x509_trust_file( -+ conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " -+ "in PEM format: %s", params->ca_cert, -+ gnutls_strerror(ret)); -+ ret = gnutls_certificate_set_x509_trust_file( -+ conn->xcred, params->ca_cert, -+ GNUTLS_X509_FMT_DER); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read CA cert " -+ "'%s' in DER format: %s", -+ params->ca_cert, -+ gnutls_strerror(ret)); -+ return -1; -+ } -+ } -+ -+ if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { -+ gnutls_certificate_set_verify_flags( -+ conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); -+ } -+ -+ if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { -+ gnutls_certificate_set_verify_flags( -+ conn->xcred, -+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS); -+ } -+ } -+ -+ if (params->client_cert && params->private_key) { -+ /* TODO: private_key_passwd? */ -+ ret = gnutls_certificate_set_x509_key_file( -+ conn->xcred, params->client_cert, params->private_key, -+ GNUTLS_X509_FMT_PEM); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read client cert/key " -+ "in PEM format: %s", gnutls_strerror(ret)); -+ ret = gnutls_certificate_set_x509_key_file( -+ conn->xcred, params->client_cert, -+ params->private_key, GNUTLS_X509_FMT_DER); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read client " -+ "cert/key in DER format: %s", -+ gnutls_strerror(ret)); -+ return ret; -+ } -+ } -+ } else if (params->private_key) { -+ int pkcs12_ok = 0; -+#ifdef PKCS12_FUNCS -+ /* Try to load in PKCS#12 format */ -+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 -+ ret = gnutls_certificate_set_x509_simple_pkcs12_file( -+ conn->xcred, params->private_key, GNUTLS_X509_FMT_DER, -+ params->private_key_passwd); -+ if (ret != 0) { -+ wpa_printf(MSG_DEBUG, "Failed to load private_key in " -+ "PKCS#12 format: %s", gnutls_strerror(ret)); -+ return -1; -+ } else -+ pkcs12_ok = 1; -+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -+#endif /* PKCS12_FUNCS */ -+ -+ if (!pkcs12_ok) { -+ wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " -+ "included"); -+ return -1; -+ } -+ } -+ -+ conn->tls_ia = params->tls_ia; -+ conn->params_set = 1; -+ -+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, -+ conn->xcred); -+ if (ret < 0) { -+ wpa_printf(MSG_INFO, "Failed to configure credentials: %s", -+ gnutls_strerror(ret)); -+ } -+ -+#ifdef GNUTLS_IA -+ if (conn->iacred_cli) -+ gnutls_ia_free_client_credentials(conn->iacred_cli); -+ -+ ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli); -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", -+ gnutls_strerror(ret)); -+ return -1; -+ } -+ -+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, -+ conn->iacred_cli); -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", -+ gnutls_strerror(ret)); -+ gnutls_ia_free_client_credentials(conn->iacred_cli); -+ conn->iacred_cli = NULL; -+ return -1; -+ } -+#endif /* GNUTLS_IE */ -+ -+ return ret; -+} -+ -+ -+int tls_global_set_params(void *tls_ctx, -+ const struct tls_connection_params *params) -+{ -+ struct tls_global *global = tls_ctx; -+ int ret; -+ -+ /* Currently, global parameters are only set when running in server -+ * mode. */ -+ global->server = 1; -+ -+ if (global->params_set) { -+ gnutls_certificate_free_credentials(global->xcred); -+ global->params_set = 0; -+ } -+ -+ ret = gnutls_certificate_allocate_credentials(&global->xcred); -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "Failed to allocate global credentials " -+ "%s", gnutls_strerror(ret)); -+ return -1; -+ } -+ -+ if (params->ca_cert) { -+ ret = gnutls_certificate_set_x509_trust_file( -+ global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " -+ "in PEM format: %s", params->ca_cert, -+ gnutls_strerror(ret)); -+ ret = gnutls_certificate_set_x509_trust_file( -+ global->xcred, params->ca_cert, -+ GNUTLS_X509_FMT_DER); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read CA cert " -+ "'%s' in DER format: %s", -+ params->ca_cert, -+ gnutls_strerror(ret)); -+ goto fail; -+ } -+ } -+ -+ if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { -+ gnutls_certificate_set_verify_flags( -+ global->xcred, -+ GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); -+ } -+ -+ if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { -+ gnutls_certificate_set_verify_flags( -+ global->xcred, -+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS); -+ } -+ } -+ -+ if (params->client_cert && params->private_key) { -+ /* TODO: private_key_passwd? */ -+ ret = gnutls_certificate_set_x509_key_file( -+ global->xcred, params->client_cert, -+ params->private_key, GNUTLS_X509_FMT_PEM); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read client cert/key " -+ "in PEM format: %s", gnutls_strerror(ret)); -+ ret = gnutls_certificate_set_x509_key_file( -+ global->xcred, params->client_cert, -+ params->private_key, GNUTLS_X509_FMT_DER); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to read client " -+ "cert/key in DER format: %s", -+ gnutls_strerror(ret)); -+ goto fail; -+ } -+ } -+ } else if (params->private_key) { -+ int pkcs12_ok = 0; -+#ifdef PKCS12_FUNCS -+ /* Try to load in PKCS#12 format */ -+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 -+ ret = gnutls_certificate_set_x509_simple_pkcs12_file( -+ global->xcred, params->private_key, -+ GNUTLS_X509_FMT_DER, params->private_key_passwd); -+ if (ret != 0) { -+ wpa_printf(MSG_DEBUG, "Failed to load private_key in " -+ "PKCS#12 format: %s", gnutls_strerror(ret)); -+ goto fail; -+ } else -+ pkcs12_ok = 1; -+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -+#endif /* PKCS12_FUNCS */ -+ -+ if (!pkcs12_ok) { -+ wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " -+ "included"); -+ goto fail; -+ } -+ } -+ -+ global->params_set = 1; -+ -+ return 0; -+ -+fail: -+ gnutls_certificate_free_credentials(global->xcred); -+ return -1; -+} -+ -+ -+int tls_global_set_verify(void *ssl_ctx, int check_crl) -+{ -+ /* TODO */ -+ return 0; -+} -+ -+ -+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, -+ int verify_peer) -+{ -+ if (conn == NULL || conn->session == NULL) -+ return -1; -+ -+ conn->verify_peer = verify_peer; -+ gnutls_certificate_server_set_request(conn->session, -+ verify_peer ? GNUTLS_CERT_REQUIRE -+ : GNUTLS_CERT_REQUEST); -+ -+ return 0; -+} -+ -+ -+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, -+ struct tls_keys *keys) -+{ -+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK -+ security_parameters_st *sec; -+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ -+ -+ if (conn == NULL || conn->session == NULL || keys == NULL) -+ return -1; -+ -+ os_memset(keys, 0, sizeof(*keys)); -+ -+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK -+ sec = &conn->session->security_parameters; -+ keys->master_key = sec->master_secret; -+ keys->master_key_len = TLS_MASTER_SIZE; -+ keys->client_random = sec->client_random; -+ keys->server_random = sec->server_random; -+#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */ -+ keys->client_random = -+ (u8 *) gnutls_session_get_client_random(conn->session); -+ keys->server_random = -+ (u8 *) gnutls_session_get_server_random(conn->session); -+ /* No access to master_secret */ -+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ -+ -+#ifdef GNUTLS_IA -+ gnutls_ia_extract_inner_secret(conn->session, -+ (char *) conn->inner_secret); -+ keys->inner_secret = conn->inner_secret; -+ keys->inner_secret_len = TLS_MASTER_SIZE; -+#endif /* GNUTLS_IA */ -+ -+ keys->client_random_len = TLS_RANDOM_SIZE; -+ keys->server_random_len = TLS_RANDOM_SIZE; -+ -+ return 0; -+} -+ -+ -+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, -+ const char *label, int server_random_first, -+ u8 *out, size_t out_len) -+{ -+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 -+ if (conn == NULL || conn->session == NULL) -+ return -1; -+ -+ return gnutls_prf(conn->session, os_strlen(label), label, -+ server_random_first, 0, NULL, out_len, (char *) out); -+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -+ return -1; -+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ -+} -+ -+ -+static int tls_connection_verify_peer(struct tls_connection *conn, -+ gnutls_alert_description_t *err) -+{ -+ unsigned int status, num_certs, i; -+ struct os_time now; -+ const gnutls_datum_t *certs; -+ gnutls_x509_crt_t cert; -+ -+ if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) { -+ wpa_printf(MSG_INFO, "TLS: Failed to verify peer " -+ "certificate chain"); -+ *err = GNUTLS_A_INTERNAL_ERROR; -+ return -1; -+ } -+ -+ if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) { -+ wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted"); -+ if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { -+ wpa_printf(MSG_INFO, "TLS: Certificate uses insecure " -+ "algorithm"); -+ *err = GNUTLS_A_INSUFFICIENT_SECURITY; -+ } -+ if (status & GNUTLS_CERT_NOT_ACTIVATED) { -+ wpa_printf(MSG_INFO, "TLS: Certificate not yet " -+ "activated"); -+ *err = GNUTLS_A_CERTIFICATE_EXPIRED; -+ } -+ if (status & GNUTLS_CERT_EXPIRED) { -+ wpa_printf(MSG_INFO, "TLS: Certificate expired"); -+ *err = GNUTLS_A_CERTIFICATE_EXPIRED; -+ } -+ return -1; -+ } -+ -+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { -+ wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a " -+ "known issuer"); -+ *err = GNUTLS_A_UNKNOWN_CA; -+ return -1; -+ } -+ -+ if (status & GNUTLS_CERT_REVOKED) { -+ wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked"); -+ *err = GNUTLS_A_CERTIFICATE_REVOKED; -+ return -1; -+ } -+ -+ os_get_time(&now); -+ -+ certs = gnutls_certificate_get_peers(conn->session, &num_certs); -+ if (certs == NULL) { -+ wpa_printf(MSG_INFO, "TLS: No peer certificate chain " -+ "received"); -+ *err = GNUTLS_A_UNKNOWN_CA; -+ return -1; -+ } -+ -+ for (i = 0; i < num_certs; i++) { -+ char *buf; -+ size_t len; -+ if (gnutls_x509_crt_init(&cert) < 0) { -+ wpa_printf(MSG_INFO, "TLS: Certificate initialization " -+ "failed"); -+ *err = GNUTLS_A_BAD_CERTIFICATE; -+ return -1; -+ } -+ -+ if (gnutls_x509_crt_import(cert, &certs[i], -+ GNUTLS_X509_FMT_DER) < 0) { -+ wpa_printf(MSG_INFO, "TLS: Could not parse peer " -+ "certificate %d/%d", i + 1, num_certs); -+ gnutls_x509_crt_deinit(cert); -+ *err = GNUTLS_A_BAD_CERTIFICATE; -+ return -1; -+ } -+ -+ gnutls_x509_crt_get_dn(cert, NULL, &len); -+ len++; -+ buf = os_malloc(len + 1); -+ if (buf) { -+ buf[0] = buf[len] = '\0'; -+ gnutls_x509_crt_get_dn(cert, buf, &len); -+ } -+ wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s", -+ i + 1, num_certs, buf); -+ -+ if (i == 0) { -+ /* TODO: validate subject_match and altsubject_match */ -+ } -+ -+ os_free(buf); -+ -+ if (gnutls_x509_crt_get_expiration_time(cert) < now.sec || -+ gnutls_x509_crt_get_activation_time(cert) > now.sec) { -+ wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is " -+ "not valid at this time", -+ i + 1, num_certs); -+ gnutls_x509_crt_deinit(cert); -+ *err = GNUTLS_A_CERTIFICATE_EXPIRED; -+ return -1; -+ } -+ -+ gnutls_x509_crt_deinit(cert); -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) -+{ -+ int res; -+ struct wpabuf *ad; -+ wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data"); -+ ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3); -+ if (ad == NULL) -+ return NULL; -+ -+ res = gnutls_record_recv(conn->session, wpabuf_mhead(ad), -+ wpabuf_size(ad)); -+ wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " -+ "(%s)", __func__, (int) res, -+ gnutls_strerror(res)); -+ wpabuf_free(ad); -+ return NULL; -+ } -+ -+ wpabuf_put(ad, res); -+ wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data", -+ res); -+ return ad; -+} -+ -+ -+struct wpabuf * tls_connection_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ struct tls_global *global = tls_ctx; -+ struct wpabuf *out_data; -+ int ret; -+ -+ if (appl_data) -+ *appl_data = NULL; -+ -+ if (in_data && wpabuf_len(in_data) > 0) { -+ if (conn->pull_buf) { -+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " -+ "pull_buf", __func__, -+ (unsigned long) wpabuf_len(conn->pull_buf)); -+ wpabuf_free(conn->pull_buf); -+ } -+ conn->pull_buf = wpabuf_dup(in_data); -+ if (conn->pull_buf == NULL) -+ return NULL; -+ conn->pull_buf_offset = wpabuf_head(conn->pull_buf); -+ } -+ -+ ret = gnutls_handshake(conn->session); -+ if (ret < 0) { -+ switch (ret) { -+ case GNUTLS_E_AGAIN: -+ if (global->server && conn->established && -+ conn->push_buf == NULL) { -+ /* Need to return something to trigger -+ * completion of EAP-TLS. */ -+ conn->push_buf = wpabuf_alloc(0); -+ } -+ break; -+ case GNUTLS_E_FATAL_ALERT_RECEIVED: -+ wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", -+ __func__, gnutls_alert_get_name( -+ gnutls_alert_get(conn->session))); -+ conn->read_alerts++; -+ /* continue */ -+ default: -+ wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " -+ "-> %s", __func__, gnutls_strerror(ret)); -+ conn->failed++; -+ } -+ } else { -+ size_t size; -+ gnutls_alert_description_t err; -+ -+ if (conn->verify_peer && -+ tls_connection_verify_peer(conn, &err)) { -+ wpa_printf(MSG_INFO, "TLS: Peer certificate chain " -+ "failed validation"); -+ conn->failed++; -+ gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err); -+ goto out; -+ } -+ -+#ifdef CONFIG_GNUTLS_EXTRA -+ if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) { -+ wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation"); -+ conn->failed++; -+ return NULL; -+ } -+#endif /* CONFIG_GNUTLS_EXTRA */ -+ -+ if (conn->tls_ia) -+ wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake"); -+ else { -+ wpa_printf(MSG_DEBUG, "TLS: Handshake completed " -+ "successfully"); -+ } -+ conn->established = 1; -+ if (conn->push_buf == NULL) { -+ /* Need to return something to get final TLS ACK. */ -+ conn->push_buf = wpabuf_alloc(0); -+ } -+ -+ gnutls_session_get_data(conn->session, NULL, &size); -+ if (global->session_data == NULL || -+ global->session_data_size < size) { -+ os_free(global->session_data); -+ global->session_data = os_malloc(size); -+ } -+ if (global->session_data) { -+ global->session_data_size = size; -+ gnutls_session_get_data(conn->session, -+ global->session_data, -+ &global->session_data_size); -+ } -+ -+ if (conn->pull_buf && appl_data) -+ *appl_data = gnutls_get_appl_data(conn); -+ } -+ -+out: -+ out_data = conn->push_buf; -+ conn->push_buf = NULL; -+ return out_data; -+} -+ -+ -+struct wpabuf * tls_connection_server_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); -+} -+ -+ -+struct wpabuf * tls_connection_encrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ ssize_t res; -+ struct wpabuf *buf; -+ -+#ifdef GNUTLS_IA -+ if (conn->tls_ia) -+ res = gnutls_ia_send(conn->session, wpabuf_head(in_data), -+ wpabuf_len(in_data)); -+ else -+#endif /* GNUTLS_IA */ -+ res = gnutls_record_send(conn->session, wpabuf_head(in_data), -+ wpabuf_len(in_data)); -+ if (res < 0) { -+ wpa_printf(MSG_INFO, "%s: Encryption failed: %s", -+ __func__, gnutls_strerror(res)); -+ return NULL; -+ } -+ -+ buf = conn->push_buf; -+ conn->push_buf = NULL; -+ return buf; -+} -+ -+ -+struct wpabuf * tls_connection_decrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ ssize_t res; -+ struct wpabuf *out; -+ -+ if (conn->pull_buf) { -+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " -+ "pull_buf", __func__, -+ (unsigned long) wpabuf_len(conn->pull_buf)); -+ wpabuf_free(conn->pull_buf); -+ } -+ conn->pull_buf = wpabuf_dup(in_data); -+ if (conn->pull_buf == NULL) -+ return NULL; -+ conn->pull_buf_offset = wpabuf_head(conn->pull_buf); -+ -+ /* -+ * Even though we try to disable TLS compression, it is possible that -+ * this cannot be done with all TLS libraries. Add extra buffer space -+ * to handle the possibility of the decrypted data being longer than -+ * input data. -+ */ -+ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); -+ if (out == NULL) -+ return NULL; -+ -+#ifdef GNUTLS_IA -+ if (conn->tls_ia) { -+ res = gnutls_ia_recv(conn->session, wpabuf_mhead(out), -+ wpabuf_size(out)); -+ if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || -+ res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { -+ int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED; -+ wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished", -+ __func__, final ? "Final" : "Intermediate"); -+ -+ res = gnutls_ia_permute_inner_secret( -+ conn->session, conn->session_keys_len, -+ (char *) conn->session_keys); -+ if (conn->session_keys) { -+ os_memset(conn->session_keys, 0, -+ conn->session_keys_len); -+ os_free(conn->session_keys); -+ } -+ conn->session_keys = NULL; -+ conn->session_keys_len = 0; -+ if (res) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to permute " -+ "inner secret: %s", -+ __func__, gnutls_strerror(res)); -+ wpabuf_free(out); -+ return NULL; -+ } -+ -+ res = gnutls_ia_verify_endphase(conn->session, -+ wpabuf_head(out)); -+ if (res == 0) { -+ wpa_printf(MSG_DEBUG, "%s: Correct endphase " -+ "checksum", __func__); -+ } else { -+ wpa_printf(MSG_INFO, "%s: Endphase " -+ "verification failed: %s", -+ __func__, gnutls_strerror(res)); -+ wpabuf_free(out); -+ return NULL; -+ } -+ -+ if (final) -+ conn->final_phase_finished = 1; -+ -+ return out; -+ } -+ -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " -+ "(%s)", __func__, (int) res, -+ gnutls_strerror(res)); -+ wpabuf_free(out); -+ return NULL; -+ } -+ wpabuf_put(out, res); -+ return out; -+ } -+#endif /* GNUTLS_IA */ -+ -+ res = gnutls_record_recv(conn->session, wpabuf_mhead(out), -+ wpabuf_size(out)); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " -+ "(%s)", __func__, (int) res, gnutls_strerror(res)); -+ wpabuf_free(out); -+ return NULL; -+ } -+ wpabuf_put(out, res); -+ -+ return out; -+} -+ -+ -+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return 0; -+ return gnutls_session_is_resumed(conn->session); -+} -+ -+ -+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, -+ u8 *ciphers) -+{ -+ /* TODO */ -+ return -1; -+} -+ -+ -+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, -+ char *buf, size_t buflen) -+{ -+ /* TODO */ -+ buf[0] = '\0'; -+ return 0; -+} -+ -+ -+int tls_connection_enable_workaround(void *ssl_ctx, -+ struct tls_connection *conn) -+{ -+ gnutls_record_disable_padding(conn->session); -+ return 0; -+} -+ -+ -+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, -+ int ext_type, const u8 *data, -+ size_t data_len) -+{ -+ /* TODO */ -+ return -1; -+} -+ -+ -+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->failed; -+} -+ -+ -+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->read_alerts; -+} -+ -+ -+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->write_alerts; -+} -+ -+ -+int tls_connection_get_keyblock_size(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ /* TODO */ -+ return -1; -+} -+ -+ -+unsigned int tls_capabilities(void *tls_ctx) -+{ -+ unsigned int capa = 0; -+ -+#ifdef GNUTLS_IA -+ capa |= TLS_CAPABILITY_IA; -+#endif /* GNUTLS_IA */ -+ -+ return capa; -+} -+ -+ -+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, -+ int tls_ia) -+{ -+#ifdef GNUTLS_IA -+ int ret; -+ -+ if (conn == NULL) -+ return -1; -+ -+ conn->tls_ia = tls_ia; -+ if (!tls_ia) -+ return 0; -+ -+ ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv); -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", -+ gnutls_strerror(ret)); -+ return -1; -+ } -+ -+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, -+ conn->iacred_srv); -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", -+ gnutls_strerror(ret)); -+ gnutls_ia_free_server_credentials(conn->iacred_srv); -+ conn->iacred_srv = NULL; -+ return -1; -+ } -+ -+ return 0; -+#else /* GNUTLS_IA */ -+ return -1; -+#endif /* GNUTLS_IA */ -+} -+ -+ -+struct wpabuf * tls_connection_ia_send_phase_finished( -+ void *tls_ctx, struct tls_connection *conn, int final) -+{ -+#ifdef GNUTLS_IA -+ int ret; -+ struct wpabuf *buf; -+ -+ if (conn == NULL || conn->session == NULL || !conn->tls_ia) -+ return NULL; -+ -+ ret = gnutls_ia_permute_inner_secret(conn->session, -+ conn->session_keys_len, -+ (char *) conn->session_keys); -+ if (conn->session_keys) { -+ os_memset(conn->session_keys, 0, conn->session_keys_len); -+ os_free(conn->session_keys); -+ } -+ conn->session_keys = NULL; -+ conn->session_keys_len = 0; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s", -+ __func__, gnutls_strerror(ret)); -+ return NULL; -+ } -+ -+ ret = gnutls_ia_endphase_send(conn->session, final); -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s", -+ __func__, gnutls_strerror(ret)); -+ return NULL; -+ } -+ -+ buf = conn->push_buf; -+ conn->push_buf = NULL; -+ return buf; -+#else /* GNUTLS_IA */ -+ return NULL; -+#endif /* GNUTLS_IA */ -+} -+ -+ -+int tls_connection_ia_final_phase_finished(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ -+ return conn->final_phase_finished; -+} -+ -+ -+int tls_connection_ia_permute_inner_secret(void *tls_ctx, -+ struct tls_connection *conn, -+ const u8 *key, size_t key_len) -+{ -+#ifdef GNUTLS_IA -+ if (conn == NULL || !conn->tls_ia) -+ return -1; -+ -+ if (conn->session_keys) { -+ os_memset(conn->session_keys, 0, conn->session_keys_len); -+ os_free(conn->session_keys); -+ } -+ conn->session_keys_len = 0; -+ -+ if (key) { -+ conn->session_keys = os_malloc(key_len); -+ if (conn->session_keys == NULL) -+ return -1; -+ os_memcpy(conn->session_keys, key, key_len); -+ conn->session_keys_len = key_len; -+ } else { -+ conn->session_keys = NULL; -+ conn->session_keys_len = 0; -+ } -+ -+ return 0; -+#else /* GNUTLS_IA */ -+ return -1; -+#endif /* GNUTLS_IA */ -+} -+ -+ -+int tls_connection_set_session_ticket_cb(void *tls_ctx, -+ struct tls_connection *conn, -+ tls_session_ticket_cb cb, void *ctx) -+{ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_internal.c -new file mode 100644 -index 0000000000000..64124d8a8e3ef ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_internal.c -@@ -0,0 +1,651 @@ -+/* -+ * TLS interface functions and an internal TLS implementation -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file interface functions for hostapd/wpa_supplicant to use the -+ * integrated TLSv1 implementation. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "tls.h" -+#include "tls/tlsv1_client.h" -+#include "tls/tlsv1_server.h" -+ -+ -+static int tls_ref_count = 0; -+ -+struct tls_global { -+ int server; -+ struct tlsv1_credentials *server_cred; -+ int check_crl; -+}; -+ -+struct tls_connection { -+ struct tlsv1_client *client; -+ struct tlsv1_server *server; -+}; -+ -+ -+void * tls_init(const struct tls_config *conf) -+{ -+ struct tls_global *global; -+ -+ if (tls_ref_count == 0) { -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (tlsv1_client_global_init()) -+ return NULL; -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (tlsv1_server_global_init()) -+ return NULL; -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ } -+ tls_ref_count++; -+ -+ global = os_zalloc(sizeof(*global)); -+ if (global == NULL) -+ return NULL; -+ -+ return global; -+} -+ -+void tls_deinit(void *ssl_ctx) -+{ -+ struct tls_global *global = ssl_ctx; -+ tls_ref_count--; -+ if (tls_ref_count == 0) { -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ tlsv1_client_global_deinit(); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ tlsv1_cred_free(global->server_cred); -+ tlsv1_server_global_deinit(); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ } -+ os_free(global); -+} -+ -+ -+int tls_get_errors(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+struct tls_connection * tls_connection_init(void *tls_ctx) -+{ -+ struct tls_connection *conn; -+ struct tls_global *global = tls_ctx; -+ -+ conn = os_zalloc(sizeof(*conn)); -+ if (conn == NULL) -+ return NULL; -+ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (!global->server) { -+ conn->client = tlsv1_client_init(); -+ if (conn->client == NULL) { -+ os_free(conn); -+ return NULL; -+ } -+ } -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (global->server) { -+ conn->server = tlsv1_server_init(global->server_cred); -+ if (conn->server == NULL) { -+ os_free(conn); -+ return NULL; -+ } -+ } -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ -+ return conn; -+} -+ -+ -+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return; -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ tlsv1_client_deinit(conn->client); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ tlsv1_server_deinit(conn->server); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ os_free(conn); -+} -+ -+ -+int tls_connection_established(void *tls_ctx, struct tls_connection *conn) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ return tlsv1_client_established(conn->client); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_established(conn->server); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return 0; -+} -+ -+ -+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ return tlsv1_client_shutdown(conn->client); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_shutdown(conn->server); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, -+ const struct tls_connection_params *params) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ struct tlsv1_credentials *cred; -+ -+ if (conn->client == NULL) -+ return -1; -+ -+ cred = tlsv1_cred_alloc(); -+ if (cred == NULL) -+ return -1; -+ -+ if (tlsv1_set_ca_cert(cred, params->ca_cert, -+ params->ca_cert_blob, params->ca_cert_blob_len, -+ params->ca_path)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA " -+ "certificates"); -+ tlsv1_cred_free(cred); -+ return -1; -+ } -+ -+ if (tlsv1_set_cert(cred, params->client_cert, -+ params->client_cert_blob, -+ params->client_cert_blob_len)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to configure client " -+ "certificate"); -+ tlsv1_cred_free(cred); -+ return -1; -+ } -+ -+ if (tlsv1_set_private_key(cred, params->private_key, -+ params->private_key_passwd, -+ params->private_key_blob, -+ params->private_key_blob_len)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load private key"); -+ tlsv1_cred_free(cred); -+ return -1; -+ } -+ -+ if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, -+ params->dh_blob_len)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); -+ tlsv1_cred_free(cred); -+ return -1; -+ } -+ -+ if (tlsv1_client_set_cred(conn->client, cred) < 0) { -+ tlsv1_cred_free(cred); -+ return -1; -+ } -+ -+ return 0; -+#else /* CONFIG_TLS_INTERNAL_CLIENT */ -+ return -1; -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+} -+ -+ -+int tls_global_set_params(void *tls_ctx, -+ const struct tls_connection_params *params) -+{ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ struct tls_global *global = tls_ctx; -+ struct tlsv1_credentials *cred; -+ -+ /* Currently, global parameters are only set when running in server -+ * mode. */ -+ global->server = 1; -+ tlsv1_cred_free(global->server_cred); -+ global->server_cred = cred = tlsv1_cred_alloc(); -+ if (cred == NULL) -+ return -1; -+ -+ if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob, -+ params->ca_cert_blob_len, params->ca_path)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA " -+ "certificates"); -+ return -1; -+ } -+ -+ if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob, -+ params->client_cert_blob_len)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to configure server " -+ "certificate"); -+ return -1; -+ } -+ -+ if (tlsv1_set_private_key(cred, params->private_key, -+ params->private_key_passwd, -+ params->private_key_blob, -+ params->private_key_blob_len)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load private key"); -+ return -1; -+ } -+ -+ if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, -+ params->dh_blob_len)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); -+ return -1; -+ } -+ -+ return 0; -+#else /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+} -+ -+ -+int tls_global_set_verify(void *tls_ctx, int check_crl) -+{ -+ struct tls_global *global = tls_ctx; -+ global->check_crl = check_crl; -+ return 0; -+} -+ -+ -+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, -+ int verify_peer) -+{ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_set_verify(conn->server, verify_peer); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, -+ int tls_ia) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, -+ struct tls_keys *keys) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ return tlsv1_client_get_keys(conn->client, keys); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_get_keys(conn->server, keys); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, -+ const char *label, int server_random_first, -+ u8 *out, size_t out_len) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) { -+ return tlsv1_client_prf(conn->client, label, -+ server_random_first, -+ out, out_len); -+ } -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) { -+ return tlsv1_server_prf(conn->server, label, -+ server_random_first, -+ out, out_len); -+ } -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+struct wpabuf * tls_connection_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ u8 *res, *ad; -+ size_t res_len, ad_len; -+ struct wpabuf *out; -+ -+ if (conn->client == NULL) -+ return NULL; -+ -+ ad = NULL; -+ res = tlsv1_client_handshake(conn->client, -+ in_data ? wpabuf_head(in_data) : NULL, -+ in_data ? wpabuf_len(in_data) : 0, -+ &res_len, &ad, &ad_len); -+ if (res == NULL) -+ return NULL; -+ out = wpabuf_alloc_ext_data(res, res_len); -+ if (out == NULL) { -+ os_free(res); -+ os_free(ad); -+ return NULL; -+ } -+ if (appl_data) { -+ if (ad) { -+ *appl_data = wpabuf_alloc_ext_data(ad, ad_len); -+ if (*appl_data == NULL) -+ os_free(ad); -+ } else -+ *appl_data = NULL; -+ } else -+ os_free(ad); -+ -+ return out; -+#else /* CONFIG_TLS_INTERNAL_CLIENT */ -+ return NULL; -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+} -+ -+ -+struct wpabuf * tls_connection_server_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ u8 *res; -+ size_t res_len; -+ struct wpabuf *out; -+ -+ if (conn->server == NULL) -+ return NULL; -+ -+ if (appl_data) -+ *appl_data = NULL; -+ -+ res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data), -+ wpabuf_len(in_data), &res_len); -+ if (res == NULL && tlsv1_server_established(conn->server)) -+ return wpabuf_alloc(0); -+ if (res == NULL) -+ return NULL; -+ out = wpabuf_alloc_ext_data(res, res_len); -+ if (out == NULL) { -+ os_free(res); -+ return NULL; -+ } -+ -+ return out; -+#else /* CONFIG_TLS_INTERNAL_SERVER */ -+ return NULL; -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+} -+ -+ -+struct wpabuf * tls_connection_encrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) { -+ struct wpabuf *buf; -+ int res; -+ buf = wpabuf_alloc(wpabuf_len(in_data) + 300); -+ if (buf == NULL) -+ return NULL; -+ res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data), -+ wpabuf_len(in_data), -+ wpabuf_mhead(buf), -+ wpabuf_size(buf)); -+ if (res < 0) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ wpabuf_put(buf, res); -+ return buf; -+ } -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) { -+ struct wpabuf *buf; -+ int res; -+ buf = wpabuf_alloc(wpabuf_len(in_data) + 300); -+ if (buf == NULL) -+ return NULL; -+ res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data), -+ wpabuf_len(in_data), -+ wpabuf_mhead(buf), -+ wpabuf_size(buf)); -+ if (res < 0) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ wpabuf_put(buf, res); -+ return buf; -+ } -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return NULL; -+} -+ -+ -+struct wpabuf * tls_connection_decrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) { -+ struct wpabuf *buf; -+ int res; -+ buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); -+ if (buf == NULL) -+ return NULL; -+ res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data), -+ wpabuf_len(in_data), -+ wpabuf_mhead(buf), -+ wpabuf_size(buf)); -+ if (res < 0) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ wpabuf_put(buf, res); -+ return buf; -+ } -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) { -+ struct wpabuf *buf; -+ int res; -+ buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); -+ if (buf == NULL) -+ return NULL; -+ res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data), -+ wpabuf_len(in_data), -+ wpabuf_mhead(buf), -+ wpabuf_size(buf)); -+ if (res < 0) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ wpabuf_put(buf, res); -+ return buf; -+ } -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return NULL; -+} -+ -+ -+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ return tlsv1_client_resumed(conn->client); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_resumed(conn->server); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, -+ u8 *ciphers) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ return tlsv1_client_set_cipher_list(conn->client, ciphers); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_set_cipher_list(conn->server, ciphers); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, -+ char *buf, size_t buflen) -+{ -+ if (conn == NULL) -+ return -1; -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ return tlsv1_client_get_cipher(conn->client, buf, buflen); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_get_cipher(conn->server, buf, buflen); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+int tls_connection_enable_workaround(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, -+ int ext_type, const u8 *data, -+ size_t data_len) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) { -+ return tlsv1_client_hello_ext(conn->client, ext_type, -+ data, data_len); -+ } -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+ return -1; -+} -+ -+ -+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_write_alerts(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_keyblock_size(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) -+ return tlsv1_client_get_keyblock_size(conn->client); -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) -+ return tlsv1_server_get_keyblock_size(conn->server); -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -+ -+ -+unsigned int tls_capabilities(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+struct wpabuf * tls_connection_ia_send_phase_finished( -+ void *tls_ctx, struct tls_connection *conn, int final) -+{ -+ return NULL; -+} -+ -+ -+int tls_connection_ia_final_phase_finished(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_ia_permute_inner_secret(void *tls_ctx, -+ struct tls_connection *conn, -+ const u8 *key, size_t key_len) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_session_ticket_cb(void *tls_ctx, -+ struct tls_connection *conn, -+ tls_session_ticket_cb cb, -+ void *ctx) -+{ -+#ifdef CONFIG_TLS_INTERNAL_CLIENT -+ if (conn->client) { -+ tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx); -+ return 0; -+ } -+#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -+#ifdef CONFIG_TLS_INTERNAL_SERVER -+ if (conn->server) { -+ tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx); -+ return 0; -+ } -+#endif /* CONFIG_TLS_INTERNAL_SERVER */ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_none.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_none.c -new file mode 100644 -index 0000000000000..0c836bb631873 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_none.c -@@ -0,0 +1,229 @@ -+/* -+ * SSL/TLS interface functions for no TLS case -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "tls.h" -+ -+void * tls_init(const struct tls_config *conf) -+{ -+ return (void *) 1; -+} -+ -+ -+void tls_deinit(void *ssl_ctx) -+{ -+} -+ -+ -+int tls_get_errors(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+struct tls_connection * tls_connection_init(void *tls_ctx) -+{ -+ return NULL; -+} -+ -+ -+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) -+{ -+} -+ -+ -+int tls_connection_established(void *tls_ctx, struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, -+ const struct tls_connection_params *params) -+{ -+ return -1; -+} -+ -+ -+int tls_global_set_params(void *tls_ctx, -+ const struct tls_connection_params *params) -+{ -+ return -1; -+} -+ -+ -+int tls_global_set_verify(void *tls_ctx, int check_crl) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, -+ int verify_peer) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, -+ int tls_ia) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, -+ struct tls_keys *keys) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, -+ const char *label, int server_random_first, -+ u8 *out, size_t out_len) -+{ -+ return -1; -+} -+ -+ -+struct wpabuf * tls_connection_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ return NULL; -+} -+ -+ -+struct wpabuf * tls_connection_server_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ return NULL; -+} -+ -+ -+struct wpabuf * tls_connection_encrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ return NULL; -+} -+ -+ -+struct wpabuf * tls_connection_decrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ return NULL; -+} -+ -+ -+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, -+ u8 *ciphers) -+{ -+ return -1; -+} -+ -+ -+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, -+ char *buf, size_t buflen) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_enable_workaround(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, -+ int ext_type, const u8 *data, -+ size_t data_len) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_write_alerts(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_keyblock_size(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+unsigned int tls_capabilities(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+struct wpabuf * tls_connection_ia_send_phase_finished( -+ void *tls_ctx, struct tls_connection *conn, int final) -+{ -+ return NULL; -+} -+ -+ -+int tls_connection_ia_final_phase_finished(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_ia_permute_inner_secret(void *tls_ctx, -+ struct tls_connection *conn, -+ const u8 *key, size_t key_len) -+{ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_nss.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_nss.c -new file mode 100644 -index 0000000000000..ad834b6493372 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_nss.c -@@ -0,0 +1,680 @@ -+/* -+ * SSL/TLS interface functions for NSS -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "tls.h" -+ -+static int tls_nss_ref_count = 0; -+ -+static PRDescIdentity nss_layer_id; -+ -+ -+struct tls_connection { -+ PRFileDesc *fd; -+ -+ int established; -+ int verify_peer; -+ u8 *push_buf, *pull_buf, *pull_buf_offset; -+ size_t push_buf_len, pull_buf_len; -+}; -+ -+ -+static PRStatus nss_io_close(PRFileDesc *fd) -+{ -+ wpa_printf(MSG_DEBUG, "NSS: I/O close"); -+ return PR_SUCCESS; -+} -+ -+ -+static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount) -+{ -+ wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount); -+ return PR_FAILURE; -+} -+ -+ -+static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount) -+{ -+ wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount); -+ return PR_FAILURE; -+} -+ -+ -+static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov, -+ PRInt32 iov_size, PRIntervalTime timeout) -+{ -+ wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size); -+ return PR_FAILURE; -+} -+ -+ -+static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, -+ PRIntn flags, PRIntervalTime timeout) -+{ -+ struct tls_connection *conn = (struct tls_connection *) fd->secret; -+ u8 *end; -+ -+ wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount); -+ -+ if (conn->pull_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet"); -+ return PR_FAILURE; -+ } -+ -+ end = conn->pull_buf + conn->pull_buf_len; -+ if (end - conn->pull_buf_offset < amount) -+ amount = end - conn->pull_buf_offset; -+ os_memcpy(buf, conn->pull_buf_offset, amount); -+ conn->pull_buf_offset += amount; -+ if (conn->pull_buf_offset == end) { -+ wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); -+ os_free(conn->pull_buf); -+ conn->pull_buf = conn->pull_buf_offset = NULL; -+ conn->pull_buf_len = 0; -+ } else { -+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", -+ __func__, -+ (unsigned long) (end - conn->pull_buf_offset)); -+ } -+ return amount; -+} -+ -+ -+static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, -+ PRIntn flags, PRIntervalTime timeout) -+{ -+ struct tls_connection *conn = (struct tls_connection *) fd->secret; -+ u8 *nbuf; -+ -+ wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); -+ wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount); -+ -+ nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount); -+ if (nbuf == NULL) { -+ wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the " -+ "data to be sent"); -+ return PR_FAILURE; -+ } -+ os_memcpy(nbuf + conn->push_buf_len, buf, amount); -+ conn->push_buf = nbuf; -+ conn->push_buf_len += amount; -+ -+ return amount; -+} -+ -+ -+static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, -+ PRIntn flags, PRNetAddr *addr, -+ PRIntervalTime timeout) -+{ -+ wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); -+ return PR_FAILURE; -+} -+ -+ -+static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, -+ PRIntn flags, const PRNetAddr *addr, -+ PRIntervalTime timeout) -+{ -+ wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__); -+ return PR_FAILURE; -+} -+ -+ -+static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr) -+{ -+ wpa_printf(MSG_DEBUG, "NSS: I/O getpeername"); -+ -+ /* -+ * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a -+ * fake IPv4 address to work around this even though we are not really -+ * using TCP. -+ */ -+ os_memset(addr, 0, sizeof(*addr)); -+ addr->inet.family = PR_AF_INET; -+ -+ return PR_SUCCESS; -+} -+ -+ -+static PRStatus nss_io_getsocketoption(PRFileDesc *fd, -+ PRSocketOptionData *data) -+{ -+ switch (data->option) { -+ case PR_SockOpt_Nonblocking: -+ wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)"); -+ data->value.non_blocking = PR_TRUE; -+ return PR_SUCCESS; -+ default: -+ wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)", -+ data->option); -+ return PR_FAILURE; -+ } -+} -+ -+ -+static const PRIOMethods nss_io = { -+ PR_DESC_LAYERED, -+ nss_io_close, -+ nss_io_read, -+ nss_io_write, -+ NULL /* available */, -+ NULL /* available64 */, -+ NULL /* fsync */, -+ NULL /* fseek */, -+ NULL /* fseek64 */, -+ NULL /* fileinfo */, -+ NULL /* fileinfo64 */, -+ nss_io_writev, -+ NULL /* connect */, -+ NULL /* accept */, -+ NULL /* bind */, -+ NULL /* listen */, -+ NULL /* shutdown */, -+ nss_io_recv, -+ nss_io_send, -+ nss_io_recvfrom, -+ nss_io_sendto, -+ NULL /* poll */, -+ NULL /* acceptread */, -+ NULL /* transmitfile */, -+ NULL /* getsockname */, -+ nss_io_getpeername, -+ NULL /* reserved_fn_6 */, -+ NULL /* reserved_fn_5 */, -+ nss_io_getsocketoption, -+ NULL /* setsocketoption */, -+ NULL /* sendfile */, -+ NULL /* connectcontinue */, -+ NULL /* reserved_fn_3 */, -+ NULL /* reserved_fn_2 */, -+ NULL /* reserved_fn_1 */, -+ NULL /* reserved_fn_0 */ -+}; -+ -+ -+static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg) -+{ -+ wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); -+ return NULL; -+} -+ -+ -+void * tls_init(const struct tls_config *conf) -+{ -+ char *dir; -+ -+ tls_nss_ref_count++; -+ if (tls_nss_ref_count > 1) -+ return (void *) 1; -+ -+ PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); -+ -+ nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant"); -+ -+ PK11_SetPasswordFunc(nss_password_cb); -+ -+ dir = getenv("SSL_DIR"); -+ if (dir) { -+ if (NSS_Init(dir) != SECSuccess) { -+ wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) " -+ "failed", dir); -+ return NULL; -+ } -+ } else { -+ if (NSS_NoDB_Init(NULL) != SECSuccess) { -+ wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) " -+ "failed"); -+ return NULL; -+ } -+ } -+ -+ if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != -+ SECSuccess || -+ SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess || -+ SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess || -+ SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) { -+ wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed"); -+ return NULL; -+ } -+ -+ if (NSS_SetDomesticPolicy() != SECSuccess) { -+ wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed"); -+ return NULL; -+ } -+ -+ return (void *) 1; -+} -+ -+void tls_deinit(void *ssl_ctx) -+{ -+ tls_nss_ref_count--; -+ if (tls_nss_ref_count == 0) { -+ if (NSS_Shutdown() != SECSuccess) -+ wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed"); -+ } -+} -+ -+ -+int tls_get_errors(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd) -+{ -+ struct tls_connection *conn = arg; -+ SECStatus res = SECSuccess; -+ PRErrorCode err; -+ CERTCertificate *cert; -+ char *subject, *issuer; -+ -+ err = PR_GetError(); -+ if (IS_SEC_ERROR(err)) -+ wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err " -+ "%d)", err - SEC_ERROR_BASE); -+ else -+ wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)", -+ err); -+ cert = SSL_PeerCertificate(fd); -+ subject = CERT_NameToAscii(&cert->subject); -+ issuer = CERT_NameToAscii(&cert->issuer); -+ wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'", -+ subject, issuer); -+ CERT_DestroyCertificate(cert); -+ PR_Free(subject); -+ PR_Free(issuer); -+ if (conn->verify_peer) -+ res = SECFailure; -+ -+ return res; -+} -+ -+ -+static void nss_handshake_cb(PRFileDesc *fd, void *client_data) -+{ -+ struct tls_connection *conn = client_data; -+ wpa_printf(MSG_DEBUG, "NSS: Handshake completed"); -+ conn->established = 1; -+} -+ -+ -+struct tls_connection * tls_connection_init(void *tls_ctx) -+{ -+ struct tls_connection *conn; -+ -+ conn = os_zalloc(sizeof(*conn)); -+ if (conn == NULL) -+ return NULL; -+ -+ conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io); -+ if (conn->fd == NULL) { -+ os_free(conn); -+ return NULL; -+ } -+ conn->fd->secret = (void *) conn; -+ -+ conn->fd = SSL_ImportFD(NULL, conn->fd); -+ if (conn->fd == NULL) { -+ os_free(conn); -+ return NULL; -+ } -+ -+ if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess || -+ SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != -+ SECSuccess || -+ SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != -+ SECSuccess || -+ SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess || -+ SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess || -+ SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) != -+ SECSuccess) { -+ wpa_printf(MSG_ERROR, "NSS: Failed to set options"); -+ PR_Close(conn->fd); -+ os_free(conn); -+ return NULL; -+ } -+ -+ SSL_ResetHandshake(conn->fd, PR_FALSE); -+ -+ return conn; -+} -+ -+ -+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) -+{ -+ PR_Close(conn->fd); -+ os_free(conn->push_buf); -+ os_free(conn->pull_buf); -+ os_free(conn); -+} -+ -+ -+int tls_connection_established(void *tls_ctx, struct tls_connection *conn) -+{ -+ return conn->established; -+} -+ -+ -+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, -+ const struct tls_connection_params *params) -+{ -+ wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__); -+ return 0; -+} -+ -+ -+int tls_global_set_params(void *tls_ctx, -+ const struct tls_connection_params *params) -+{ -+ return -1; -+} -+ -+ -+int tls_global_set_verify(void *tls_ctx, int check_crl) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn, -+ int verify_peer) -+{ -+ conn->verify_peer = verify_peer; -+ return 0; -+} -+ -+ -+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, -+ int tls_ia) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, -+ struct tls_keys *keys) -+{ -+ /* NSS does not export master secret or client/server random. */ -+ return -1; -+} -+ -+ -+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, -+ const char *label, int server_random_first, -+ u8 *out, size_t out_len) -+{ -+ if (conn == NULL || server_random_first) { -+ wpa_printf(MSG_INFO, "NSS: Unsupported PRF request " -+ "(server_random_first=%d)", -+ server_random_first); -+ return -1; -+ } -+ -+ if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) != -+ SECSuccess) { -+ wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor " -+ "(label='%s' out_len=%d", label, (int) out_len); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+struct wpabuf * tls_connection_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ struct wpabuf *out_data; -+ -+ wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u", -+ in_data ? (unsigned int) wpabuf_len(in_data) : 0); -+ -+ if (appl_data) -+ *appl_data = NULL; -+ -+ if (in_data && wpabuf_len(in_data) > 0) { -+ if (conn->pull_buf) { -+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " -+ "pull_buf", __func__, -+ (unsigned long) conn->pull_buf_len); -+ os_free(conn->pull_buf); -+ } -+ conn->pull_buf = os_malloc(wpabuf_len(in_data)); -+ if (conn->pull_buf == NULL) -+ return NULL; -+ os_memcpy(conn->pull_buf, wpabuf_head(in_data), -+ wpabuf_len(in_data)); -+ conn->pull_buf_offset = conn->pull_buf; -+ conn->pull_buf_len = wpabuf_len(in_data); -+ } -+ -+ SSL_ForceHandshake(conn->fd); -+ -+ if (conn->established && conn->push_buf == NULL) { -+ /* Need to return something to get final TLS ACK. */ -+ conn->push_buf = os_malloc(1); -+ } -+ -+ if (conn->push_buf == NULL) -+ return NULL; -+ out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); -+ if (out_data == NULL) -+ os_free(conn->push_buf); -+ conn->push_buf = NULL; -+ conn->push_buf_len = 0; -+ return out_data; -+} -+ -+ -+struct wpabuf * tls_connection_server_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ return NULL; -+} -+ -+ -+struct wpabuf * tls_connection_encrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ PRInt32 res; -+ struct wpabuf *buf; -+ -+ wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", -+ (int) wpabuf_len(in_data)); -+ res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0, -+ 0); -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "NSS: Encryption failed"); -+ return NULL; -+ } -+ if (conn->push_buf == NULL) -+ return NULL; -+ buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); -+ if (buf == NULL) -+ os_free(conn->push_buf); -+ conn->push_buf = NULL; -+ conn->push_buf_len = 0; -+ return buf; -+} -+ -+ -+struct wpabuf * tls_connection_decrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ PRInt32 res; -+ struct wpabuf *out; -+ -+ wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", -+ (int) wpabuf_len(in_data)); -+ if (conn->pull_buf) { -+ wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " -+ "pull_buf", __func__, -+ (unsigned long) conn->pull_buf_len); -+ os_free(conn->pull_buf); -+ } -+ conn->pull_buf = os_malloc(wpabuf_len(in_data)); -+ if (conn->pull_buf == NULL) -+ return NULL; -+ os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); -+ conn->pull_buf_offset = conn->pull_buf; -+ conn->pull_buf_len = wpabuf_len(in_data); -+ -+ /* -+ * Even though we try to disable TLS compression, it is possible that -+ * this cannot be done with all TLS libraries. Add extra buffer space -+ * to handle the possibility of the decrypted data being longer than -+ * input data. -+ */ -+ out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); -+ if (out == NULL) -+ return NULL; -+ -+ res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0); -+ wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res); -+ if (res < 0) { -+ wpabuf_free(out); -+ return NULL; -+ } -+ wpabuf_put(out, res); -+ -+ return out; -+} -+ -+ -+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, -+ u8 *ciphers) -+{ -+ return -1; -+} -+ -+ -+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn, -+ char *buf, size_t buflen) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_enable_workaround(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn, -+ int ext_type, const u8 *data, -+ size_t data_len) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_write_alerts(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_get_keyblock_size(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+unsigned int tls_capabilities(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+struct wpabuf * tls_connection_ia_send_phase_finished( -+ void *tls_ctx, struct tls_connection *conn, int final) -+{ -+ return NULL; -+} -+ -+ -+int tls_connection_ia_final_phase_finished(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_ia_permute_inner_secret(void *tls_ctx, -+ struct tls_connection *conn, -+ const u8 *key, size_t key_len) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_session_ticket_cb(void *tls_ctx, -+ struct tls_connection *conn, -+ tls_session_ticket_cb cb, -+ void *ctx) -+{ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_openssl.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_openssl.c -new file mode 100644 -index 0000000000000..bf92a1133d862 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_openssl.c -@@ -0,0 +1,2992 @@ -+/* -+ * SSL/TLS interface functions for OpenSSL -+ * Copyright (c) 2004-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#ifndef CONFIG_SMARTCARD -+#ifndef OPENSSL_NO_ENGINE -+#define OPENSSL_NO_ENGINE -+#endif -+#endif -+ -+#include -+#include -+#include -+#include -+#ifndef OPENSSL_NO_ENGINE -+#include -+#endif /* OPENSSL_NO_ENGINE */ -+ -+#ifdef ANDROID -+#include -+#include "keystore_get.h" -+#endif /* ANDROID */ -+ -+#include "common.h" -+#include "crypto.h" -+#include "tls.h" -+ -+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL -+#define OPENSSL_d2i_TYPE const unsigned char ** -+#else -+#define OPENSSL_d2i_TYPE unsigned char ** -+#endif -+ -+#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT -+#ifdef SSL_OP_NO_TICKET -+/* -+ * Session ticket override patch was merged into OpenSSL 0.9.9 tree on -+ * 2008-11-15. This version uses a bit different API compared to the old patch. -+ */ -+#define CONFIG_OPENSSL_TICKET_OVERRIDE -+#endif -+#endif -+ -+static int tls_openssl_ref_count = 0; -+ -+struct tls_global { -+ void (*event_cb)(void *ctx, enum tls_event ev, -+ union tls_event_data *data); -+ void *cb_ctx; -+}; -+ -+static struct tls_global *tls_global = NULL; -+ -+ -+struct tls_connection { -+ SSL *ssl; -+ BIO *ssl_in, *ssl_out; -+#ifndef OPENSSL_NO_ENGINE -+ ENGINE *engine; /* functional reference to the engine */ -+ EVP_PKEY *private_key; /* the private key if using engine */ -+#endif /* OPENSSL_NO_ENGINE */ -+ char *subject_match, *altsubject_match; -+ int read_alerts, write_alerts, failed; -+ -+ tls_session_ticket_cb session_ticket_cb; -+ void *session_ticket_cb_ctx; -+ -+ /* SessionTicket received from OpenSSL hello_extension_cb (server) */ -+ u8 *session_ticket; -+ size_t session_ticket_len; -+ -+ unsigned int ca_cert_verify:1; -+ unsigned int cert_probe:1; -+ unsigned int server_cert_only:1; -+ -+ u8 srv_cert_hash[32]; -+}; -+ -+ -+#ifdef CONFIG_NO_STDOUT_DEBUG -+ -+static void _tls_show_errors(void) -+{ -+ unsigned long err; -+ -+ while ((err = ERR_get_error())) { -+ /* Just ignore the errors, since stdout is disabled */ -+ } -+} -+#define tls_show_errors(l, f, t) _tls_show_errors() -+ -+#else /* CONFIG_NO_STDOUT_DEBUG */ -+ -+static void tls_show_errors(int level, const char *func, const char *txt) -+{ -+ unsigned long err; -+ -+ wpa_printf(level, "OpenSSL: %s - %s %s", -+ func, txt, ERR_error_string(ERR_get_error(), NULL)); -+ -+ while ((err = ERR_get_error())) { -+ wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", -+ ERR_error_string(err, NULL)); -+ } -+} -+ -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+#ifdef CONFIG_NATIVE_WINDOWS -+ -+/* Windows CryptoAPI and access to certificate stores */ -+#include -+ -+#ifdef __MINGW32_VERSION -+/* -+ * MinGW does not yet include all the needed definitions for CryptoAPI, so -+ * define here whatever extra is needed. -+ */ -+#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) -+#define CERT_STORE_READONLY_FLAG 0x00008000 -+#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 -+ -+#endif /* __MINGW32_VERSION */ -+ -+ -+struct cryptoapi_rsa_data { -+ const CERT_CONTEXT *cert; -+ HCRYPTPROV crypt_prov; -+ DWORD key_spec; -+ BOOL free_crypt_prov; -+}; -+ -+ -+static void cryptoapi_error(const char *msg) -+{ -+ wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", -+ msg, (unsigned int) GetLastError()); -+} -+ -+ -+static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, int padding) -+{ -+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); -+ return 0; -+} -+ -+ -+static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, int padding) -+{ -+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); -+ return 0; -+} -+ -+ -+static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, int padding) -+{ -+ struct cryptoapi_rsa_data *priv = -+ (struct cryptoapi_rsa_data *) rsa->meth->app_data; -+ HCRYPTHASH hash; -+ DWORD hash_size, len, i; -+ unsigned char *buf = NULL; -+ int ret = 0; -+ -+ if (priv == NULL) { -+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, -+ ERR_R_PASSED_NULL_PARAMETER); -+ return 0; -+ } -+ -+ if (padding != RSA_PKCS1_PADDING) { -+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, -+ RSA_R_UNKNOWN_PADDING_TYPE); -+ return 0; -+ } -+ -+ if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { -+ wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", -+ __func__); -+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, -+ RSA_R_INVALID_MESSAGE_LENGTH); -+ return 0; -+ } -+ -+ if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) -+ { -+ cryptoapi_error("CryptCreateHash failed"); -+ return 0; -+ } -+ -+ len = sizeof(hash_size); -+ if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, -+ 0)) { -+ cryptoapi_error("CryptGetHashParam failed"); -+ goto err; -+ } -+ -+ if ((int) hash_size != flen) { -+ wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", -+ (unsigned) hash_size, flen); -+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, -+ RSA_R_INVALID_MESSAGE_LENGTH); -+ goto err; -+ } -+ if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { -+ cryptoapi_error("CryptSetHashParam failed"); -+ goto err; -+ } -+ -+ len = RSA_size(rsa); -+ buf = os_malloc(len); -+ if (buf == NULL) { -+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); -+ goto err; -+ } -+ -+ if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { -+ cryptoapi_error("CryptSignHash failed"); -+ goto err; -+ } -+ -+ for (i = 0; i < len; i++) -+ to[i] = buf[len - i - 1]; -+ ret = len; -+ -+err: -+ os_free(buf); -+ CryptDestroyHash(hash); -+ -+ return ret; -+} -+ -+ -+static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, int padding) -+{ -+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); -+ return 0; -+} -+ -+ -+static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) -+{ -+ if (priv == NULL) -+ return; -+ if (priv->crypt_prov && priv->free_crypt_prov) -+ CryptReleaseContext(priv->crypt_prov, 0); -+ if (priv->cert) -+ CertFreeCertificateContext(priv->cert); -+ os_free(priv); -+} -+ -+ -+static int cryptoapi_finish(RSA *rsa) -+{ -+ cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); -+ os_free((void *) rsa->meth); -+ rsa->meth = NULL; -+ return 1; -+} -+ -+ -+static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) -+{ -+ HCERTSTORE cs; -+ const CERT_CONTEXT *ret = NULL; -+ -+ cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, -+ store | CERT_STORE_OPEN_EXISTING_FLAG | -+ CERT_STORE_READONLY_FLAG, L"MY"); -+ if (cs == NULL) { -+ cryptoapi_error("Failed to open 'My system store'"); -+ return NULL; -+ } -+ -+ if (strncmp(name, "cert://", 7) == 0) { -+ unsigned short wbuf[255]; -+ MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); -+ ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | -+ PKCS_7_ASN_ENCODING, -+ 0, CERT_FIND_SUBJECT_STR, -+ wbuf, NULL); -+ } else if (strncmp(name, "hash://", 7) == 0) { -+ CRYPT_HASH_BLOB blob; -+ int len; -+ const char *hash = name + 7; -+ unsigned char *buf; -+ -+ len = os_strlen(hash) / 2; -+ buf = os_malloc(len); -+ if (buf && hexstr2bin(hash, buf, len) == 0) { -+ blob.cbData = len; -+ blob.pbData = buf; -+ ret = CertFindCertificateInStore(cs, -+ X509_ASN_ENCODING | -+ PKCS_7_ASN_ENCODING, -+ 0, CERT_FIND_HASH, -+ &blob, NULL); -+ } -+ os_free(buf); -+ } -+ -+ CertCloseStore(cs, 0); -+ -+ return ret; -+} -+ -+ -+static int tls_cryptoapi_cert(SSL *ssl, const char *name) -+{ -+ X509 *cert = NULL; -+ RSA *rsa = NULL, *pub_rsa; -+ struct cryptoapi_rsa_data *priv; -+ RSA_METHOD *rsa_meth; -+ -+ if (name == NULL || -+ (strncmp(name, "cert://", 7) != 0 && -+ strncmp(name, "hash://", 7) != 0)) -+ return -1; -+ -+ priv = os_zalloc(sizeof(*priv)); -+ rsa_meth = os_zalloc(sizeof(*rsa_meth)); -+ if (priv == NULL || rsa_meth == NULL) { -+ wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " -+ "for CryptoAPI RSA method"); -+ os_free(priv); -+ os_free(rsa_meth); -+ return -1; -+ } -+ -+ priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); -+ if (priv->cert == NULL) { -+ priv->cert = cryptoapi_find_cert( -+ name, CERT_SYSTEM_STORE_LOCAL_MACHINE); -+ } -+ if (priv->cert == NULL) { -+ wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " -+ "'%s'", name); -+ goto err; -+ } -+ -+ cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded, -+ priv->cert->cbCertEncoded); -+ if (cert == NULL) { -+ wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " -+ "encoding"); -+ goto err; -+ } -+ -+ if (!CryptAcquireCertificatePrivateKey(priv->cert, -+ CRYPT_ACQUIRE_COMPARE_KEY_FLAG, -+ NULL, &priv->crypt_prov, -+ &priv->key_spec, -+ &priv->free_crypt_prov)) { -+ cryptoapi_error("Failed to acquire a private key for the " -+ "certificate"); -+ goto err; -+ } -+ -+ rsa_meth->name = "Microsoft CryptoAPI RSA Method"; -+ rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; -+ rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; -+ rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; -+ rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; -+ rsa_meth->finish = cryptoapi_finish; -+ rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; -+ rsa_meth->app_data = (char *) priv; -+ -+ rsa = RSA_new(); -+ if (rsa == NULL) { -+ SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, -+ ERR_R_MALLOC_FAILURE); -+ goto err; -+ } -+ -+ if (!SSL_use_certificate(ssl, cert)) { -+ RSA_free(rsa); -+ rsa = NULL; -+ goto err; -+ } -+ pub_rsa = cert->cert_info->key->pkey->pkey.rsa; -+ X509_free(cert); -+ cert = NULL; -+ -+ rsa->n = BN_dup(pub_rsa->n); -+ rsa->e = BN_dup(pub_rsa->e); -+ if (!RSA_set_method(rsa, rsa_meth)) -+ goto err; -+ -+ if (!SSL_use_RSAPrivateKey(ssl, rsa)) -+ goto err; -+ RSA_free(rsa); -+ -+ return 0; -+ -+err: -+ if (cert) -+ X509_free(cert); -+ if (rsa) -+ RSA_free(rsa); -+ else { -+ os_free(rsa_meth); -+ cryptoapi_free_data(priv); -+ } -+ return -1; -+} -+ -+ -+static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) -+{ -+ HCERTSTORE cs; -+ PCCERT_CONTEXT ctx = NULL; -+ X509 *cert; -+ char buf[128]; -+ const char *store; -+#ifdef UNICODE -+ WCHAR *wstore; -+#endif /* UNICODE */ -+ -+ if (name == NULL || strncmp(name, "cert_store://", 13) != 0) -+ return -1; -+ -+ store = name + 13; -+#ifdef UNICODE -+ wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); -+ if (wstore == NULL) -+ return -1; -+ wsprintf(wstore, L"%S", store); -+ cs = CertOpenSystemStore(0, wstore); -+ os_free(wstore); -+#else /* UNICODE */ -+ cs = CertOpenSystemStore(0, store); -+#endif /* UNICODE */ -+ if (cs == NULL) { -+ wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " -+ "'%s': error=%d", __func__, store, -+ (int) GetLastError()); -+ return -1; -+ } -+ -+ while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { -+ cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded, -+ ctx->cbCertEncoded); -+ if (cert == NULL) { -+ wpa_printf(MSG_INFO, "CryptoAPI: Could not process " -+ "X509 DER encoding for CA cert"); -+ continue; -+ } -+ -+ X509_NAME_oneline(X509_get_subject_name(cert), buf, -+ sizeof(buf)); -+ wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " -+ "system certificate store: subject='%s'", buf); -+ -+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed to add ca_cert to OpenSSL " -+ "certificate store"); -+ } -+ -+ X509_free(cert); -+ } -+ -+ if (!CertCloseStore(cs, 0)) { -+ wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " -+ "'%s': error=%d", __func__, name + 13, -+ (int) GetLastError()); -+ } -+ -+ return 0; -+} -+ -+ -+#else /* CONFIG_NATIVE_WINDOWS */ -+ -+static int tls_cryptoapi_cert(SSL *ssl, const char *name) -+{ -+ return -1; -+} -+ -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ -+static void ssl_info_cb(const SSL *ssl, int where, int ret) -+{ -+ const char *str; -+ int w; -+ -+ wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); -+ w = where & ~SSL_ST_MASK; -+ if (w & SSL_ST_CONNECT) -+ str = "SSL_connect"; -+ else if (w & SSL_ST_ACCEPT) -+ str = "SSL_accept"; -+ else -+ str = "undefined"; -+ -+ if (where & SSL_CB_LOOP) { -+ wpa_printf(MSG_DEBUG, "SSL: %s:%s", -+ str, SSL_state_string_long(ssl)); -+ } else if (where & SSL_CB_ALERT) { -+ wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", -+ where & SSL_CB_READ ? -+ "read (remote end reported an error)" : -+ "write (local SSL3 detected an error)", -+ SSL_alert_type_string_long(ret), -+ SSL_alert_desc_string_long(ret)); -+ if ((ret >> 8) == SSL3_AL_FATAL) { -+ struct tls_connection *conn = -+ SSL_get_app_data((SSL *) ssl); -+ if (where & SSL_CB_READ) -+ conn->read_alerts++; -+ else -+ conn->write_alerts++; -+ } -+ } else if (where & SSL_CB_EXIT && ret <= 0) { -+ wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", -+ str, ret == 0 ? "failed" : "error", -+ SSL_state_string_long(ssl)); -+ } -+} -+ -+ -+#ifndef OPENSSL_NO_ENGINE -+/** -+ * tls_engine_load_dynamic_generic - load any openssl engine -+ * @pre: an array of commands and values that load an engine initialized -+ * in the engine specific function -+ * @post: an array of commands and values that initialize an already loaded -+ * engine (or %NULL if not required) -+ * @id: the engine id of the engine to load (only required if post is not %NULL -+ * -+ * This function is a generic function that loads any openssl engine. -+ * -+ * Returns: 0 on success, -1 on failure -+ */ -+static int tls_engine_load_dynamic_generic(const char *pre[], -+ const char *post[], const char *id) -+{ -+ ENGINE *engine; -+ const char *dynamic_id = "dynamic"; -+ -+ engine = ENGINE_by_id(id); -+ if (engine) { -+ ENGINE_free(engine); -+ wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " -+ "available", id); -+ return 0; -+ } -+ ERR_clear_error(); -+ -+ engine = ENGINE_by_id(dynamic_id); -+ if (engine == NULL) { -+ wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", -+ dynamic_id, -+ ERR_error_string(ERR_get_error(), NULL)); -+ return -1; -+ } -+ -+ /* Perform the pre commands. This will load the engine. */ -+ while (pre && pre[0]) { -+ wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); -+ if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { -+ wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " -+ "%s %s [%s]", pre[0], pre[1], -+ ERR_error_string(ERR_get_error(), NULL)); -+ ENGINE_free(engine); -+ return -1; -+ } -+ pre += 2; -+ } -+ -+ /* -+ * Free the reference to the "dynamic" engine. The loaded engine can -+ * now be looked up using ENGINE_by_id(). -+ */ -+ ENGINE_free(engine); -+ -+ engine = ENGINE_by_id(id); -+ if (engine == NULL) { -+ wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", -+ id, ERR_error_string(ERR_get_error(), NULL)); -+ return -1; -+ } -+ -+ while (post && post[0]) { -+ wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); -+ if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { -+ wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" -+ " %s %s [%s]", post[0], post[1], -+ ERR_error_string(ERR_get_error(), NULL)); -+ ENGINE_remove(engine); -+ ENGINE_free(engine); -+ return -1; -+ } -+ post += 2; -+ } -+ ENGINE_free(engine); -+ -+ return 0; -+} -+ -+ -+/** -+ * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc -+ * @pkcs11_so_path: pksc11_so_path from the configuration -+ * @pcks11_module_path: pkcs11_module_path from the configuration -+ */ -+static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, -+ const char *pkcs11_module_path) -+{ -+ char *engine_id = "pkcs11"; -+ const char *pre_cmd[] = { -+ "SO_PATH", NULL /* pkcs11_so_path */, -+ "ID", NULL /* engine_id */, -+ "LIST_ADD", "1", -+ /* "NO_VCHECK", "1", */ -+ "LOAD", NULL, -+ NULL, NULL -+ }; -+ const char *post_cmd[] = { -+ "MODULE_PATH", NULL /* pkcs11_module_path */, -+ NULL, NULL -+ }; -+ -+ if (!pkcs11_so_path || !pkcs11_module_path) -+ return 0; -+ -+ pre_cmd[1] = pkcs11_so_path; -+ pre_cmd[3] = engine_id; -+ post_cmd[1] = pkcs11_module_path; -+ -+ wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s", -+ pkcs11_so_path); -+ -+ return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id); -+} -+ -+ -+/** -+ * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc -+ * @opensc_so_path: opensc_so_path from the configuration -+ */ -+static int tls_engine_load_dynamic_opensc(const char *opensc_so_path) -+{ -+ char *engine_id = "opensc"; -+ const char *pre_cmd[] = { -+ "SO_PATH", NULL /* opensc_so_path */, -+ "ID", NULL /* engine_id */, -+ "LIST_ADD", "1", -+ "LOAD", NULL, -+ NULL, NULL -+ }; -+ -+ if (!opensc_so_path) -+ return 0; -+ -+ pre_cmd[1] = opensc_so_path; -+ pre_cmd[3] = engine_id; -+ -+ wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s", -+ opensc_so_path); -+ -+ return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id); -+} -+#endif /* OPENSSL_NO_ENGINE */ -+ -+ -+void * tls_init(const struct tls_config *conf) -+{ -+ SSL_CTX *ssl; -+ -+ if (tls_openssl_ref_count == 0) { -+ tls_global = os_zalloc(sizeof(*tls_global)); -+ if (tls_global == NULL) -+ return NULL; -+ if (conf) { -+ tls_global->event_cb = conf->event_cb; -+ tls_global->cb_ctx = conf->cb_ctx; -+ } -+ -+#ifdef CONFIG_FIPS -+#ifdef OPENSSL_FIPS -+ if (conf && conf->fips_mode) { -+ if (!FIPS_mode_set(1)) { -+ wpa_printf(MSG_ERROR, "Failed to enable FIPS " -+ "mode"); -+ ERR_load_crypto_strings(); -+ ERR_print_errors_fp(stderr); -+ return NULL; -+ } else -+ wpa_printf(MSG_INFO, "Running in FIPS mode"); -+ } -+#else /* OPENSSL_FIPS */ -+ if (conf && conf->fips_mode) { -+ wpa_printf(MSG_ERROR, "FIPS mode requested, but not " -+ "supported"); -+ return NULL; -+ } -+#endif /* OPENSSL_FIPS */ -+#endif /* CONFIG_FIPS */ -+ SSL_load_error_strings(); -+ SSL_library_init(); -+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) -+ EVP_add_digest(EVP_sha256()); -+#endif /* OPENSSL_NO_SHA256 */ -+ /* TODO: if /dev/urandom is available, PRNG is seeded -+ * automatically. If this is not the case, random data should -+ * be added here. */ -+ -+#ifdef PKCS12_FUNCS -+#ifndef OPENSSL_NO_RC2 -+ /* -+ * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. -+ * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 -+ * versions, but it looks like OpenSSL 1.0.0 does not do that -+ * anymore. -+ */ -+ EVP_add_cipher(EVP_rc2_40_cbc()); -+#endif /* OPENSSL_NO_RC2 */ -+ PKCS12_PBE_add(); -+#endif /* PKCS12_FUNCS */ -+ } -+ tls_openssl_ref_count++; -+ -+ ssl = SSL_CTX_new(TLSv1_method()); -+ if (ssl == NULL) -+ return NULL; -+ -+ SSL_CTX_set_info_callback(ssl, ssl_info_cb); -+ -+#ifndef OPENSSL_NO_ENGINE -+ if (conf && -+ (conf->opensc_engine_path || conf->pkcs11_engine_path || -+ conf->pkcs11_module_path)) { -+ wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); -+ ERR_load_ENGINE_strings(); -+ ENGINE_load_dynamic(); -+ -+ if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) || -+ tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path, -+ conf->pkcs11_module_path)) { -+ tls_deinit(ssl); -+ return NULL; -+ } -+ } -+#endif /* OPENSSL_NO_ENGINE */ -+ -+ return ssl; -+} -+ -+ -+void tls_deinit(void *ssl_ctx) -+{ -+ SSL_CTX *ssl = ssl_ctx; -+ SSL_CTX_free(ssl); -+ -+ tls_openssl_ref_count--; -+ if (tls_openssl_ref_count == 0) { -+#ifndef OPENSSL_NO_ENGINE -+ ENGINE_cleanup(); -+#endif /* OPENSSL_NO_ENGINE */ -+ CRYPTO_cleanup_all_ex_data(); -+ ERR_remove_state(0); -+ ERR_free_strings(); -+ EVP_cleanup(); -+ os_free(tls_global); -+ tls_global = NULL; -+ } -+} -+ -+ -+static int tls_engine_init(struct tls_connection *conn, const char *engine_id, -+ const char *pin, const char *key_id, -+ const char *cert_id, const char *ca_cert_id) -+{ -+#ifndef OPENSSL_NO_ENGINE -+ int ret = -1; -+ if (engine_id == NULL) { -+ wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); -+ return -1; -+ } -+ if (pin == NULL) { -+ wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); -+ return -1; -+ } -+ if (key_id == NULL) { -+ wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); -+ return -1; -+ } -+ -+ ERR_clear_error(); -+ conn->engine = ENGINE_by_id(engine_id); -+ if (!conn->engine) { -+ wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]", -+ engine_id, ERR_error_string(ERR_get_error(), NULL)); -+ goto err; -+ } -+ if (ENGINE_init(conn->engine) != 1) { -+ wpa_printf(MSG_ERROR, "ENGINE: engine init failed " -+ "(engine: %s) [%s]", engine_id, -+ ERR_error_string(ERR_get_error(), NULL)); -+ goto err; -+ } -+ wpa_printf(MSG_DEBUG, "ENGINE: engine initialized"); -+ -+ if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { -+ wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]", -+ ERR_error_string(ERR_get_error(), NULL)); -+ goto err; -+ } -+ /* load private key first in-case PIN is required for cert */ -+ conn->private_key = ENGINE_load_private_key(conn->engine, -+ key_id, NULL, NULL); -+ if (!conn->private_key) { -+ wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id" -+ " '%s' [%s]", key_id, -+ ERR_error_string(ERR_get_error(), NULL)); -+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; -+ goto err; -+ } -+ -+ /* handle a certificate and/or CA certificate */ -+ if (cert_id || ca_cert_id) { -+ const char *cmd_name = "LOAD_CERT_CTRL"; -+ -+ /* test if the engine supports a LOAD_CERT_CTRL */ -+ if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, -+ 0, (void *)cmd_name, NULL)) { -+ wpa_printf(MSG_ERROR, "ENGINE: engine does not support" -+ " loading certificates"); -+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; -+ goto err; -+ } -+ } -+ -+ return 0; -+ -+err: -+ if (conn->engine) { -+ ENGINE_free(conn->engine); -+ conn->engine = NULL; -+ } -+ -+ if (conn->private_key) { -+ EVP_PKEY_free(conn->private_key); -+ conn->private_key = NULL; -+ } -+ -+ return ret; -+#else /* OPENSSL_NO_ENGINE */ -+ return 0; -+#endif /* OPENSSL_NO_ENGINE */ -+} -+ -+ -+static void tls_engine_deinit(struct tls_connection *conn) -+{ -+#ifndef OPENSSL_NO_ENGINE -+ wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); -+ if (conn->private_key) { -+ EVP_PKEY_free(conn->private_key); -+ conn->private_key = NULL; -+ } -+ if (conn->engine) { -+ ENGINE_finish(conn->engine); -+ conn->engine = NULL; -+ } -+#endif /* OPENSSL_NO_ENGINE */ -+} -+ -+ -+int tls_get_errors(void *ssl_ctx) -+{ -+ int count = 0; -+ unsigned long err; -+ -+ while ((err = ERR_get_error())) { -+ wpa_printf(MSG_INFO, "TLS - SSL error: %s", -+ ERR_error_string(err, NULL)); -+ count++; -+ } -+ -+ return count; -+} -+ -+struct tls_connection * tls_connection_init(void *ssl_ctx) -+{ -+ SSL_CTX *ssl = ssl_ctx; -+ struct tls_connection *conn; -+ long options; -+ -+ conn = os_zalloc(sizeof(*conn)); -+ if (conn == NULL) -+ return NULL; -+ conn->ssl = SSL_new(ssl); -+ if (conn->ssl == NULL) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to initialize new SSL connection"); -+ os_free(conn); -+ return NULL; -+ } -+ -+ SSL_set_app_data(conn->ssl, conn); -+ options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | -+ SSL_OP_SINGLE_DH_USE; -+#ifdef SSL_OP_NO_COMPRESSION -+ options |= SSL_OP_NO_COMPRESSION; -+#endif /* SSL_OP_NO_COMPRESSION */ -+ SSL_set_options(conn->ssl, options); -+ -+ conn->ssl_in = BIO_new(BIO_s_mem()); -+ if (!conn->ssl_in) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to create a new BIO for ssl_in"); -+ SSL_free(conn->ssl); -+ os_free(conn); -+ return NULL; -+ } -+ -+ conn->ssl_out = BIO_new(BIO_s_mem()); -+ if (!conn->ssl_out) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to create a new BIO for ssl_out"); -+ SSL_free(conn->ssl); -+ BIO_free(conn->ssl_in); -+ os_free(conn); -+ return NULL; -+ } -+ -+ SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); -+ -+ return conn; -+} -+ -+ -+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return; -+ SSL_free(conn->ssl); -+ tls_engine_deinit(conn); -+ os_free(conn->subject_match); -+ os_free(conn->altsubject_match); -+ os_free(conn->session_ticket); -+ os_free(conn); -+} -+ -+ -+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) -+{ -+ return conn ? SSL_is_init_finished(conn->ssl) : 0; -+} -+ -+ -+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ -+ /* Shutdown previous TLS connection without notifying the peer -+ * because the connection was already terminated in practice -+ * and "close notify" shutdown alert would confuse AS. */ -+ SSL_set_quiet_shutdown(conn->ssl, 1); -+ SSL_shutdown(conn->ssl); -+ return 0; -+} -+ -+ -+static int tls_match_altsubject_component(X509 *cert, int type, -+ const char *value, size_t len) -+{ -+ GENERAL_NAME *gen; -+ void *ext; -+ int i, found = 0; -+ -+ ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); -+ -+ for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { -+ gen = sk_GENERAL_NAME_value(ext, i); -+ if (gen->type != type) -+ continue; -+ if (os_strlen((char *) gen->d.ia5->data) == len && -+ os_memcmp(value, gen->d.ia5->data, len) == 0) -+ found++; -+ } -+ -+ return found; -+} -+ -+ -+static int tls_match_altsubject(X509 *cert, const char *match) -+{ -+ int type; -+ const char *pos, *end; -+ size_t len; -+ -+ pos = match; -+ do { -+ if (os_strncmp(pos, "EMAIL:", 6) == 0) { -+ type = GEN_EMAIL; -+ pos += 6; -+ } else if (os_strncmp(pos, "DNS:", 4) == 0) { -+ type = GEN_DNS; -+ pos += 4; -+ } else if (os_strncmp(pos, "URI:", 4) == 0) { -+ type = GEN_URI; -+ pos += 4; -+ } else { -+ wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " -+ "match '%s'", pos); -+ return 0; -+ } -+ end = os_strchr(pos, ';'); -+ while (end) { -+ if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || -+ os_strncmp(end + 1, "DNS:", 4) == 0 || -+ os_strncmp(end + 1, "URI:", 4) == 0) -+ break; -+ end = os_strchr(end + 1, ';'); -+ } -+ if (end) -+ len = end - pos; -+ else -+ len = os_strlen(pos); -+ if (tls_match_altsubject_component(cert, type, pos, len) > 0) -+ return 1; -+ pos = end + 1; -+ } while (end); -+ -+ return 0; -+} -+ -+ -+static enum tls_fail_reason openssl_tls_fail_reason(int err) -+{ -+ switch (err) { -+ case X509_V_ERR_CERT_REVOKED: -+ return TLS_FAIL_REVOKED; -+ case X509_V_ERR_CERT_NOT_YET_VALID: -+ case X509_V_ERR_CRL_NOT_YET_VALID: -+ return TLS_FAIL_NOT_YET_VALID; -+ case X509_V_ERR_CERT_HAS_EXPIRED: -+ case X509_V_ERR_CRL_HAS_EXPIRED: -+ return TLS_FAIL_EXPIRED; -+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: -+ case X509_V_ERR_UNABLE_TO_GET_CRL: -+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: -+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: -+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: -+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: -+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: -+ case X509_V_ERR_CERT_CHAIN_TOO_LONG: -+ case X509_V_ERR_PATH_LENGTH_EXCEEDED: -+ case X509_V_ERR_INVALID_CA: -+ return TLS_FAIL_UNTRUSTED; -+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: -+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: -+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: -+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: -+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: -+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: -+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: -+ case X509_V_ERR_CERT_UNTRUSTED: -+ case X509_V_ERR_CERT_REJECTED: -+ return TLS_FAIL_BAD_CERTIFICATE; -+ default: -+ return TLS_FAIL_UNSPECIFIED; -+ } -+} -+ -+ -+static struct wpabuf * get_x509_cert(X509 *cert) -+{ -+ struct wpabuf *buf; -+ u8 *tmp; -+ -+ int cert_len = i2d_X509(cert, NULL); -+ if (cert_len <= 0) -+ return NULL; -+ -+ buf = wpabuf_alloc(cert_len); -+ if (buf == NULL) -+ return NULL; -+ -+ tmp = wpabuf_put(buf, cert_len); -+ i2d_X509(cert, &tmp); -+ return buf; -+} -+ -+ -+static void openssl_tls_fail_event(struct tls_connection *conn, -+ X509 *err_cert, int err, int depth, -+ const char *subject, const char *err_str, -+ enum tls_fail_reason reason) -+{ -+ union tls_event_data ev; -+ struct wpabuf *cert = NULL; -+ -+ if (tls_global->event_cb == NULL) -+ return; -+ -+ cert = get_x509_cert(err_cert); -+ os_memset(&ev, 0, sizeof(ev)); -+ ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ? -+ reason : openssl_tls_fail_reason(err); -+ ev.cert_fail.depth = depth; -+ ev.cert_fail.subject = subject; -+ ev.cert_fail.reason_txt = err_str; -+ ev.cert_fail.cert = cert; -+ tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); -+ wpabuf_free(cert); -+} -+ -+ -+static void openssl_tls_cert_event(struct tls_connection *conn, -+ X509 *err_cert, int depth, -+ const char *subject) -+{ -+ struct wpabuf *cert = NULL; -+ union tls_event_data ev; -+#ifdef CONFIG_SHA256 -+ u8 hash[32]; -+#endif /* CONFIG_SHA256 */ -+ -+ if (tls_global->event_cb == NULL) -+ return; -+ -+ os_memset(&ev, 0, sizeof(ev)); -+ if (conn->cert_probe) { -+ cert = get_x509_cert(err_cert); -+ ev.peer_cert.cert = cert; -+ } -+#ifdef CONFIG_SHA256 -+ if (cert) { -+ const u8 *addr[1]; -+ size_t len[1]; -+ addr[0] = wpabuf_head(cert); -+ len[0] = wpabuf_len(cert); -+ if (sha256_vector(1, addr, len, hash) == 0) { -+ ev.peer_cert.hash = hash; -+ ev.peer_cert.hash_len = sizeof(hash); -+ } -+ } -+#endif /* CONFIG_SHA256 */ -+ ev.peer_cert.depth = depth; -+ ev.peer_cert.subject = subject; -+ tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev); -+ wpabuf_free(cert); -+} -+ -+ -+static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) -+{ -+ char buf[256]; -+ X509 *err_cert; -+ int err, depth; -+ SSL *ssl; -+ struct tls_connection *conn; -+ char *match, *altmatch; -+ const char *err_str; -+ -+ err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); -+ err = X509_STORE_CTX_get_error(x509_ctx); -+ depth = X509_STORE_CTX_get_error_depth(x509_ctx); -+ ssl = X509_STORE_CTX_get_ex_data(x509_ctx, -+ SSL_get_ex_data_X509_STORE_CTX_idx()); -+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); -+ -+ conn = SSL_get_app_data(ssl); -+ if (conn == NULL) -+ return 0; -+ match = conn->subject_match; -+ altmatch = conn->altsubject_match; -+ -+ if (!preverify_ok && !conn->ca_cert_verify) -+ preverify_ok = 1; -+ if (!preverify_ok && depth > 0 && conn->server_cert_only) -+ preverify_ok = 1; -+ -+ err_str = X509_verify_cert_error_string(err); -+ -+#ifdef CONFIG_SHA256 -+ if (preverify_ok && depth == 0 && conn->server_cert_only) { -+ struct wpabuf *cert; -+ cert = get_x509_cert(err_cert); -+ if (!cert) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " -+ "server certificate data"); -+ preverify_ok = 0; -+ } else { -+ u8 hash[32]; -+ const u8 *addr[1]; -+ size_t len[1]; -+ addr[0] = wpabuf_head(cert); -+ len[0] = wpabuf_len(cert); -+ if (sha256_vector(1, addr, len, hash) < 0 || -+ os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { -+ err_str = "Server certificate mismatch"; -+ err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; -+ preverify_ok = 0; -+ } -+ wpabuf_free(cert); -+ } -+ } -+#endif /* CONFIG_SHA256 */ -+ -+ if (!preverify_ok) { -+ wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," -+ " error %d (%s) depth %d for '%s'", err, err_str, -+ depth, buf); -+ openssl_tls_fail_event(conn, err_cert, err, depth, buf, -+ err_str, TLS_FAIL_UNSPECIFIED); -+ return preverify_ok; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " -+ "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", -+ preverify_ok, err, err_str, -+ conn->ca_cert_verify, depth, buf); -+ if (depth == 0 && match && os_strstr(buf, match) == NULL) { -+ wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " -+ "match with '%s'", buf, match); -+ preverify_ok = 0; -+ openssl_tls_fail_event(conn, err_cert, err, depth, buf, -+ "Subject mismatch", -+ TLS_FAIL_SUBJECT_MISMATCH); -+ } else if (depth == 0 && altmatch && -+ !tls_match_altsubject(err_cert, altmatch)) { -+ wpa_printf(MSG_WARNING, "TLS: altSubjectName match " -+ "'%s' not found", altmatch); -+ preverify_ok = 0; -+ openssl_tls_fail_event(conn, err_cert, err, depth, buf, -+ "AltSubject mismatch", -+ TLS_FAIL_ALTSUBJECT_MISMATCH); -+ } else -+ openssl_tls_cert_event(conn, err_cert, depth, buf); -+ -+ if (conn->cert_probe && preverify_ok && depth == 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " -+ "on probe-only run"); -+ preverify_ok = 0; -+ openssl_tls_fail_event(conn, err_cert, err, depth, buf, -+ "Server certificate chain probe", -+ TLS_FAIL_SERVER_CHAIN_PROBE); -+ } -+ -+ return preverify_ok; -+} -+ -+ -+#ifndef OPENSSL_NO_STDIO -+static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert) -+{ -+ SSL_CTX *ssl_ctx = _ssl_ctx; -+ X509_LOOKUP *lookup; -+ int ret = 0; -+ -+ lookup = X509_STORE_add_lookup(ssl_ctx->cert_store, -+ X509_LOOKUP_file()); -+ if (lookup == NULL) { -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed add lookup for X509 store"); -+ return -1; -+ } -+ -+ if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) { -+ unsigned long err = ERR_peek_error(); -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed load CA in DER format"); -+ if (ERR_GET_LIB(err) == ERR_LIB_X509 && -+ ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " -+ "cert already in hash table error", -+ __func__); -+ } else -+ ret = -1; -+ } -+ -+ return ret; -+} -+#endif /* OPENSSL_NO_STDIO */ -+ -+ -+#ifdef ANDROID -+static BIO * BIO_from_keystore(const char *key) -+{ -+ BIO *bio = NULL; -+ char value[KEYSTORE_MESSAGE_SIZE]; -+ int length = keystore_get(key, strlen(key), value); -+ if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) -+ BIO_write(bio, value, length); -+ return bio; -+} -+#endif /* ANDROID */ -+ -+ -+static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, -+ const char *ca_cert, const u8 *ca_cert_blob, -+ size_t ca_cert_blob_len, const char *ca_path) -+{ -+ SSL_CTX *ssl_ctx = _ssl_ctx; -+ -+ /* -+ * Remove previously configured trusted CA certificates before adding -+ * new ones. -+ */ -+ X509_STORE_free(ssl_ctx->cert_store); -+ ssl_ctx->cert_store = X509_STORE_new(); -+ if (ssl_ctx->cert_store == NULL) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " -+ "certificate store", __func__); -+ return -1; -+ } -+ -+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); -+ conn->ca_cert_verify = 1; -+ -+ if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " -+ "chain"); -+ conn->cert_probe = 1; -+ conn->ca_cert_verify = 0; -+ return 0; -+ } -+ -+ if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { -+#ifdef CONFIG_SHA256 -+ const char *pos = ca_cert + 7; -+ if (os_strncmp(pos, "server/sha256/", 14) != 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " -+ "hash value '%s'", ca_cert); -+ return -1; -+ } -+ pos += 14; -+ if (os_strlen(pos) != 32 * 2) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " -+ "hash length in ca_cert '%s'", ca_cert); -+ return -1; -+ } -+ if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " -+ "value in ca_cert '%s'", ca_cert); -+ return -1; -+ } -+ conn->server_cert_only = 1; -+ wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " -+ "certificate match"); -+ return 0; -+#else /* CONFIG_SHA256 */ -+ wpa_printf(MSG_INFO, "No SHA256 included in the build - " -+ "cannot validate server certificate hash"); -+ return -1; -+#endif /* CONFIG_SHA256 */ -+ } -+ -+ if (ca_cert_blob) { -+ X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob, -+ ca_cert_blob_len); -+ if (cert == NULL) { -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed to parse ca_cert_blob"); -+ return -1; -+ } -+ -+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { -+ unsigned long err = ERR_peek_error(); -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed to add ca_cert_blob to " -+ "certificate store"); -+ if (ERR_GET_LIB(err) == ERR_LIB_X509 && -+ ERR_GET_REASON(err) == -+ X509_R_CERT_ALREADY_IN_HASH_TABLE) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " -+ "cert already in hash table error", -+ __func__); -+ } else { -+ X509_free(cert); -+ return -1; -+ } -+ } -+ X509_free(cert); -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " -+ "to certificate store", __func__); -+ return 0; -+ } -+ -+#ifdef ANDROID -+ if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) { -+ BIO *bio = BIO_from_keystore(&ca_cert[11]); -+ STACK_OF(X509_INFO) *stack = NULL; -+ int i; -+ -+ if (bio) { -+ stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); -+ BIO_free(bio); -+ } -+ if (!stack) -+ return -1; -+ -+ for (i = 0; i < sk_X509_INFO_num(stack); ++i) { -+ X509_INFO *info = sk_X509_INFO_value(stack, i); -+ if (info->x509) { -+ X509_STORE_add_cert(ssl_ctx->cert_store, -+ info->x509); -+ } -+ if (info->crl) { -+ X509_STORE_add_crl(ssl_ctx->cert_store, -+ info->crl); -+ } -+ } -+ sk_X509_INFO_pop_free(stack, X509_INFO_free); -+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); -+ return 0; -+ } -+#endif /* ANDROID */ -+ -+#ifdef CONFIG_NATIVE_WINDOWS -+ if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == -+ 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " -+ "system certificate store"); -+ return 0; -+ } -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ if (ca_cert || ca_path) { -+#ifndef OPENSSL_NO_STDIO -+ if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != -+ 1) { -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed to load root certificates"); -+ if (ca_cert && -+ tls_load_ca_der(ssl_ctx, ca_cert) == 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded " -+ "DER format CA certificate", -+ __func__); -+ } else -+ return -1; -+ } else { -+ wpa_printf(MSG_DEBUG, "TLS: Trusted root " -+ "certificate(s) loaded"); -+ tls_get_errors(ssl_ctx); -+ } -+#else /* OPENSSL_NO_STDIO */ -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", -+ __func__); -+ return -1; -+#endif /* OPENSSL_NO_STDIO */ -+ } else { -+ /* No ca_cert configured - do not try to verify server -+ * certificate */ -+ conn->ca_cert_verify = 0; -+ } -+ -+ return 0; -+} -+ -+ -+static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert) -+{ -+ if (ca_cert) { -+ if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1) -+ { -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed to load root certificates"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLS: Trusted root " -+ "certificate(s) loaded"); -+ -+#ifndef OPENSSL_NO_STDIO -+ /* Add the same CAs to the client certificate requests */ -+ SSL_CTX_set_client_CA_list(ssl_ctx, -+ SSL_load_client_CA_file(ca_cert)); -+#endif /* OPENSSL_NO_STDIO */ -+ } -+ -+ return 0; -+} -+ -+ -+int tls_global_set_verify(void *ssl_ctx, int check_crl) -+{ -+ int flags; -+ -+ if (check_crl) { -+ X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx); -+ if (cs == NULL) { -+ tls_show_errors(MSG_INFO, __func__, "Failed to get " -+ "certificate store when enabling " -+ "check_crl"); -+ return -1; -+ } -+ flags = X509_V_FLAG_CRL_CHECK; -+ if (check_crl == 2) -+ flags |= X509_V_FLAG_CRL_CHECK_ALL; -+ X509_STORE_set_flags(cs, flags); -+ } -+ return 0; -+} -+ -+ -+static int tls_connection_set_subject_match(struct tls_connection *conn, -+ const char *subject_match, -+ const char *altsubject_match) -+{ -+ os_free(conn->subject_match); -+ conn->subject_match = NULL; -+ if (subject_match) { -+ conn->subject_match = os_strdup(subject_match); -+ if (conn->subject_match == NULL) -+ return -1; -+ } -+ -+ os_free(conn->altsubject_match); -+ conn->altsubject_match = NULL; -+ if (altsubject_match) { -+ conn->altsubject_match = os_strdup(altsubject_match); -+ if (conn->altsubject_match == NULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, -+ int verify_peer) -+{ -+ static int counter = 0; -+ -+ if (conn == NULL) -+ return -1; -+ -+ if (verify_peer) { -+ conn->ca_cert_verify = 1; -+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | -+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT | -+ SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); -+ } else { -+ conn->ca_cert_verify = 0; -+ SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); -+ } -+ -+ SSL_set_accept_state(conn->ssl); -+ -+ /* -+ * Set session id context in order to avoid fatal errors when client -+ * tries to resume a session. However, set the context to a unique -+ * value in order to effectively disable session resumption for now -+ * since not all areas of the server code are ready for it (e.g., -+ * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS -+ * handshake). -+ */ -+ counter++; -+ SSL_set_session_id_context(conn->ssl, -+ (const unsigned char *) &counter, -+ sizeof(counter)); -+ -+ return 0; -+} -+ -+ -+static int tls_connection_client_cert(struct tls_connection *conn, -+ const char *client_cert, -+ const u8 *client_cert_blob, -+ size_t client_cert_blob_len) -+{ -+ if (client_cert == NULL && client_cert_blob == NULL) -+ return 0; -+ -+ if (client_cert_blob && -+ SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, -+ client_cert_blob_len) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " -+ "OK"); -+ return 0; -+ } else if (client_cert_blob) { -+ tls_show_errors(MSG_DEBUG, __func__, -+ "SSL_use_certificate_ASN1 failed"); -+ } -+ -+ if (client_cert == NULL) -+ return -1; -+ -+#ifdef ANDROID -+ if (os_strncmp("keystore://", client_cert, 11) == 0) { -+ BIO *bio = BIO_from_keystore(&client_cert[11]); -+ X509 *x509 = NULL; -+ int ret = -1; -+ if (bio) { -+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); -+ BIO_free(bio); -+ } -+ if (x509) { -+ if (SSL_use_certificate(conn->ssl, x509) == 1) -+ ret = 0; -+ X509_free(x509); -+ } -+ return ret; -+ } -+#endif /* ANDROID */ -+ -+#ifndef OPENSSL_NO_STDIO -+ if (SSL_use_certificate_file(conn->ssl, client_cert, -+ SSL_FILETYPE_ASN1) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" -+ " --> OK"); -+ return 0; -+ } -+ -+ if (SSL_use_certificate_file(conn->ssl, client_cert, -+ SSL_FILETYPE_PEM) == 1) { -+ ERR_clear_error(); -+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" -+ " --> OK"); -+ return 0; -+ } -+ -+ tls_show_errors(MSG_DEBUG, __func__, -+ "SSL_use_certificate_file failed"); -+#else /* OPENSSL_NO_STDIO */ -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); -+#endif /* OPENSSL_NO_STDIO */ -+ -+ return -1; -+} -+ -+ -+static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert) -+{ -+#ifndef OPENSSL_NO_STDIO -+ if (client_cert == NULL) -+ return 0; -+ -+ if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert, -+ SSL_FILETYPE_ASN1) != 1 && -+ SSL_CTX_use_certificate_file(ssl_ctx, client_cert, -+ SSL_FILETYPE_PEM) != 1) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to load client certificate"); -+ return -1; -+ } -+ return 0; -+#else /* OPENSSL_NO_STDIO */ -+ if (client_cert == NULL) -+ return 0; -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__); -+ return -1; -+#endif /* OPENSSL_NO_STDIO */ -+} -+ -+ -+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password) -+{ -+ if (password == NULL) { -+ return 0; -+ } -+ os_strlcpy(buf, (char *) password, size); -+ return os_strlen(buf); -+} -+ -+ -+#ifdef PKCS12_FUNCS -+static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12, -+ const char *passwd) -+{ -+ EVP_PKEY *pkey; -+ X509 *cert; -+ STACK_OF(X509) *certs; -+ int res = 0; -+ char buf[256]; -+ -+ pkey = NULL; -+ cert = NULL; -+ certs = NULL; -+ if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) { -+ tls_show_errors(MSG_DEBUG, __func__, -+ "Failed to parse PKCS12 file"); -+ PKCS12_free(p12); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data"); -+ -+ if (cert) { -+ X509_NAME_oneline(X509_get_subject_name(cert), buf, -+ sizeof(buf)); -+ wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: " -+ "subject='%s'", buf); -+ if (ssl) { -+ if (SSL_use_certificate(ssl, cert) != 1) -+ res = -1; -+ } else { -+ if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1) -+ res = -1; -+ } -+ X509_free(cert); -+ } -+ -+ if (pkey) { -+ wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); -+ if (ssl) { -+ if (SSL_use_PrivateKey(ssl, pkey) != 1) -+ res = -1; -+ } else { -+ if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) -+ res = -1; -+ } -+ EVP_PKEY_free(pkey); -+ } -+ -+ if (certs) { -+ while ((cert = sk_X509_pop(certs)) != NULL) { -+ X509_NAME_oneline(X509_get_subject_name(cert), buf, -+ sizeof(buf)); -+ wpa_printf(MSG_DEBUG, "TLS: additional certificate" -+ " from PKCS12: subject='%s'", buf); -+ /* -+ * There is no SSL equivalent for the chain cert - so -+ * always add it to the context... -+ */ -+ if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) { -+ res = -1; -+ break; -+ } -+ } -+ sk_X509_free(certs); -+ } -+ -+ PKCS12_free(p12); -+ -+ if (res < 0) -+ tls_get_errors(ssl_ctx); -+ -+ return res; -+} -+#endif /* PKCS12_FUNCS */ -+ -+ -+static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key, -+ const char *passwd) -+{ -+#ifdef PKCS12_FUNCS -+ FILE *f; -+ PKCS12 *p12; -+ -+ f = fopen(private_key, "rb"); -+ if (f == NULL) -+ return -1; -+ -+ p12 = d2i_PKCS12_fp(f, NULL); -+ fclose(f); -+ -+ if (p12 == NULL) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to use PKCS#12 file"); -+ return -1; -+ } -+ -+ return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); -+ -+#else /* PKCS12_FUNCS */ -+ wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read " -+ "p12/pfx files"); -+ return -1; -+#endif /* PKCS12_FUNCS */ -+} -+ -+ -+static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl, -+ const u8 *blob, size_t len, const char *passwd) -+{ -+#ifdef PKCS12_FUNCS -+ PKCS12 *p12; -+ -+ p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len); -+ if (p12 == NULL) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to use PKCS#12 blob"); -+ return -1; -+ } -+ -+ return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); -+ -+#else /* PKCS12_FUNCS */ -+ wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse " -+ "p12/pfx blobs"); -+ return -1; -+#endif /* PKCS12_FUNCS */ -+} -+ -+ -+#ifndef OPENSSL_NO_ENGINE -+static int tls_engine_get_cert(struct tls_connection *conn, -+ const char *cert_id, -+ X509 **cert) -+{ -+ /* this runs after the private key is loaded so no PIN is required */ -+ struct { -+ const char *cert_id; -+ X509 *cert; -+ } params; -+ params.cert_id = cert_id; -+ params.cert = NULL; -+ -+ if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL", -+ 0, ¶ms, NULL, 1)) { -+ wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id" -+ " '%s' [%s]", cert_id, -+ ERR_error_string(ERR_get_error(), NULL)); -+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; -+ } -+ if (!params.cert) { -+ wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id" -+ " '%s'", cert_id); -+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; -+ } -+ *cert = params.cert; -+ return 0; -+} -+#endif /* OPENSSL_NO_ENGINE */ -+ -+ -+static int tls_connection_engine_client_cert(struct tls_connection *conn, -+ const char *cert_id) -+{ -+#ifndef OPENSSL_NO_ENGINE -+ X509 *cert; -+ -+ if (tls_engine_get_cert(conn, cert_id, &cert)) -+ return -1; -+ -+ if (!SSL_use_certificate(conn->ssl, cert)) { -+ tls_show_errors(MSG_ERROR, __func__, -+ "SSL_use_certificate failed"); -+ X509_free(cert); -+ return -1; -+ } -+ X509_free(cert); -+ wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> " -+ "OK"); -+ return 0; -+ -+#else /* OPENSSL_NO_ENGINE */ -+ return -1; -+#endif /* OPENSSL_NO_ENGINE */ -+} -+ -+ -+static int tls_connection_engine_ca_cert(void *_ssl_ctx, -+ struct tls_connection *conn, -+ const char *ca_cert_id) -+{ -+#ifndef OPENSSL_NO_ENGINE -+ X509 *cert; -+ SSL_CTX *ssl_ctx = _ssl_ctx; -+ -+ if (tls_engine_get_cert(conn, ca_cert_id, &cert)) -+ return -1; -+ -+ /* start off the same as tls_connection_ca_cert */ -+ X509_STORE_free(ssl_ctx->cert_store); -+ ssl_ctx->cert_store = X509_STORE_new(); -+ if (ssl_ctx->cert_store == NULL) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " -+ "certificate store", __func__); -+ X509_free(cert); -+ return -1; -+ } -+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { -+ unsigned long err = ERR_peek_error(); -+ tls_show_errors(MSG_WARNING, __func__, -+ "Failed to add CA certificate from engine " -+ "to certificate store"); -+ if (ERR_GET_LIB(err) == ERR_LIB_X509 && -+ ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" -+ " already in hash table error", -+ __func__); -+ } else { -+ X509_free(cert); -+ return -1; -+ } -+ } -+ X509_free(cert); -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " -+ "to certificate store", __func__); -+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); -+ return 0; -+ -+#else /* OPENSSL_NO_ENGINE */ -+ return -1; -+#endif /* OPENSSL_NO_ENGINE */ -+} -+ -+ -+static int tls_connection_engine_private_key(struct tls_connection *conn) -+{ -+#ifndef OPENSSL_NO_ENGINE -+ if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { -+ tls_show_errors(MSG_ERROR, __func__, -+ "ENGINE: cannot use private key for TLS"); -+ return -1; -+ } -+ if (!SSL_check_private_key(conn->ssl)) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Private key failed verification"); -+ return -1; -+ } -+ return 0; -+#else /* OPENSSL_NO_ENGINE */ -+ wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " -+ "engine support was not compiled in"); -+ return -1; -+#endif /* OPENSSL_NO_ENGINE */ -+} -+ -+ -+static int tls_connection_private_key(void *_ssl_ctx, -+ struct tls_connection *conn, -+ const char *private_key, -+ const char *private_key_passwd, -+ const u8 *private_key_blob, -+ size_t private_key_blob_len) -+{ -+ SSL_CTX *ssl_ctx = _ssl_ctx; -+ char *passwd; -+ int ok; -+ -+ if (private_key == NULL && private_key_blob == NULL) -+ return 0; -+ -+ if (private_key_passwd) { -+ passwd = os_strdup(private_key_passwd); -+ if (passwd == NULL) -+ return -1; -+ } else -+ passwd = NULL; -+ -+ SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); -+ SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); -+ -+ ok = 0; -+ while (private_key_blob) { -+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, -+ (u8 *) private_key_blob, -+ private_key_blob_len) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" -+ "ASN1(EVP_PKEY_RSA) --> OK"); -+ ok = 1; -+ break; -+ } -+ -+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, -+ (u8 *) private_key_blob, -+ private_key_blob_len) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" -+ "ASN1(EVP_PKEY_DSA) --> OK"); -+ ok = 1; -+ break; -+ } -+ -+ if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, -+ (u8 *) private_key_blob, -+ private_key_blob_len) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: " -+ "SSL_use_RSAPrivateKey_ASN1 --> OK"); -+ ok = 1; -+ break; -+ } -+ -+ if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob, -+ private_key_blob_len, passwd) == 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " -+ "OK"); -+ ok = 1; -+ break; -+ } -+ -+ break; -+ } -+ -+#ifdef ANDROID -+ if (!ok && private_key && -+ os_strncmp("keystore://", private_key, 11) == 0) { -+ BIO *bio = BIO_from_keystore(&private_key[11]); -+ EVP_PKEY *pkey = NULL; -+ if (bio) { -+ pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); -+ BIO_free(bio); -+ } -+ if (pkey) { -+ if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Private key " -+ "from keystore"); -+ ok = 1; -+ } -+ EVP_PKEY_free(pkey); -+ } -+ } -+#endif /* ANDROID */ -+ -+ while (!ok && private_key) { -+#ifndef OPENSSL_NO_STDIO -+ if (SSL_use_PrivateKey_file(conn->ssl, private_key, -+ SSL_FILETYPE_ASN1) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: " -+ "SSL_use_PrivateKey_File (DER) --> OK"); -+ ok = 1; -+ break; -+ } -+ -+ if (SSL_use_PrivateKey_file(conn->ssl, private_key, -+ SSL_FILETYPE_PEM) == 1) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: " -+ "SSL_use_PrivateKey_File (PEM) --> OK"); -+ ok = 1; -+ break; -+ } -+#else /* OPENSSL_NO_STDIO */ -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", -+ __func__); -+#endif /* OPENSSL_NO_STDIO */ -+ -+ if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd) -+ == 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file " -+ "--> OK"); -+ ok = 1; -+ break; -+ } -+ -+ if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) { -+ wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to " -+ "access certificate store --> OK"); -+ ok = 1; -+ break; -+ } -+ -+ break; -+ } -+ -+ if (!ok) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to load private key"); -+ os_free(passwd); -+ return -1; -+ } -+ ERR_clear_error(); -+ SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); -+ os_free(passwd); -+ -+ if (!SSL_check_private_key(conn->ssl)) { -+ tls_show_errors(MSG_INFO, __func__, "Private key failed " -+ "verification"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully"); -+ return 0; -+} -+ -+ -+static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key, -+ const char *private_key_passwd) -+{ -+ char *passwd; -+ -+ if (private_key == NULL) -+ return 0; -+ -+ if (private_key_passwd) { -+ passwd = os_strdup(private_key_passwd); -+ if (passwd == NULL) -+ return -1; -+ } else -+ passwd = NULL; -+ -+ SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); -+ SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); -+ if ( -+#ifndef OPENSSL_NO_STDIO -+ SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, -+ SSL_FILETYPE_ASN1) != 1 && -+ SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key, -+ SSL_FILETYPE_PEM) != 1 && -+#endif /* OPENSSL_NO_STDIO */ -+ tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to load private key"); -+ os_free(passwd); -+ ERR_clear_error(); -+ return -1; -+ } -+ os_free(passwd); -+ ERR_clear_error(); -+ SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL); -+ -+ if (!SSL_CTX_check_private_key(ssl_ctx)) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Private key failed verification"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) -+{ -+#ifdef OPENSSL_NO_DH -+ if (dh_file == NULL) -+ return 0; -+ wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " -+ "dh_file specified"); -+ return -1; -+#else /* OPENSSL_NO_DH */ -+ DH *dh; -+ BIO *bio; -+ -+ /* TODO: add support for dh_blob */ -+ if (dh_file == NULL) -+ return 0; -+ if (conn == NULL) -+ return -1; -+ -+ bio = BIO_new_file(dh_file, "r"); -+ if (bio == NULL) { -+ wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", -+ dh_file, ERR_error_string(ERR_get_error(), NULL)); -+ return -1; -+ } -+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); -+ BIO_free(bio); -+#ifndef OPENSSL_NO_DSA -+ while (dh == NULL) { -+ DSA *dsa; -+ wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" -+ " trying to parse as DSA params", dh_file, -+ ERR_error_string(ERR_get_error(), NULL)); -+ bio = BIO_new_file(dh_file, "r"); -+ if (bio == NULL) -+ break; -+ dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); -+ BIO_free(bio); -+ if (!dsa) { -+ wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " -+ "'%s': %s", dh_file, -+ ERR_error_string(ERR_get_error(), NULL)); -+ break; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); -+ dh = DSA_dup_DH(dsa); -+ DSA_free(dsa); -+ if (dh == NULL) { -+ wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " -+ "params into DH params"); -+ break; -+ } -+ break; -+ } -+#endif /* !OPENSSL_NO_DSA */ -+ if (dh == NULL) { -+ wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " -+ "'%s'", dh_file); -+ return -1; -+ } -+ -+ if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { -+ wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " -+ "%s", dh_file, -+ ERR_error_string(ERR_get_error(), NULL)); -+ DH_free(dh); -+ return -1; -+ } -+ DH_free(dh); -+ return 0; -+#endif /* OPENSSL_NO_DH */ -+} -+ -+ -+static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file) -+{ -+#ifdef OPENSSL_NO_DH -+ if (dh_file == NULL) -+ return 0; -+ wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " -+ "dh_file specified"); -+ return -1; -+#else /* OPENSSL_NO_DH */ -+ DH *dh; -+ BIO *bio; -+ -+ /* TODO: add support for dh_blob */ -+ if (dh_file == NULL) -+ return 0; -+ if (ssl_ctx == NULL) -+ return -1; -+ -+ bio = BIO_new_file(dh_file, "r"); -+ if (bio == NULL) { -+ wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", -+ dh_file, ERR_error_string(ERR_get_error(), NULL)); -+ return -1; -+ } -+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); -+ BIO_free(bio); -+#ifndef OPENSSL_NO_DSA -+ while (dh == NULL) { -+ DSA *dsa; -+ wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" -+ " trying to parse as DSA params", dh_file, -+ ERR_error_string(ERR_get_error(), NULL)); -+ bio = BIO_new_file(dh_file, "r"); -+ if (bio == NULL) -+ break; -+ dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); -+ BIO_free(bio); -+ if (!dsa) { -+ wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " -+ "'%s': %s", dh_file, -+ ERR_error_string(ERR_get_error(), NULL)); -+ break; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); -+ dh = DSA_dup_DH(dsa); -+ DSA_free(dsa); -+ if (dh == NULL) { -+ wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " -+ "params into DH params"); -+ break; -+ } -+ break; -+ } -+#endif /* !OPENSSL_NO_DSA */ -+ if (dh == NULL) { -+ wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " -+ "'%s'", dh_file); -+ return -1; -+ } -+ -+ if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) { -+ wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " -+ "%s", dh_file, -+ ERR_error_string(ERR_get_error(), NULL)); -+ DH_free(dh); -+ return -1; -+ } -+ DH_free(dh); -+ return 0; -+#endif /* OPENSSL_NO_DH */ -+} -+ -+ -+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, -+ struct tls_keys *keys) -+{ -+ SSL *ssl; -+ -+ if (conn == NULL || keys == NULL) -+ return -1; -+ ssl = conn->ssl; -+ if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) -+ return -1; -+ -+ os_memset(keys, 0, sizeof(*keys)); -+ keys->master_key = ssl->session->master_key; -+ keys->master_key_len = ssl->session->master_key_length; -+ keys->client_random = ssl->s3->client_random; -+ keys->client_random_len = SSL3_RANDOM_SIZE; -+ keys->server_random = ssl->s3->server_random; -+ keys->server_random_len = SSL3_RANDOM_SIZE; -+ -+ return 0; -+} -+ -+ -+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, -+ const char *label, int server_random_first, -+ u8 *out, size_t out_len) -+{ -+ return -1; -+} -+ -+ -+static struct wpabuf * -+openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, -+ int server) -+{ -+ int res; -+ struct wpabuf *out_data; -+ -+ /* -+ * Give TLS handshake data from the server (if available) to OpenSSL -+ * for processing. -+ */ -+ if (in_data && -+ BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) -+ < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Handshake failed - BIO_write"); -+ return NULL; -+ } -+ -+ /* Initiate TLS handshake or continue the existing handshake */ -+ if (server) -+ res = SSL_accept(conn->ssl); -+ else -+ res = SSL_connect(conn->ssl); -+ if (res != 1) { -+ int err = SSL_get_error(conn->ssl, res); -+ if (err == SSL_ERROR_WANT_READ) -+ wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " -+ "more data"); -+ else if (err == SSL_ERROR_WANT_WRITE) -+ wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " -+ "write"); -+ else { -+ tls_show_errors(MSG_INFO, __func__, "SSL_connect"); -+ conn->failed++; -+ } -+ } -+ -+ /* Get the TLS handshake data to be sent to the server */ -+ res = BIO_ctrl_pending(conn->ssl_out); -+ wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); -+ out_data = wpabuf_alloc(res); -+ if (out_data == NULL) { -+ wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " -+ "handshake output (%d bytes)", res); -+ if (BIO_reset(conn->ssl_out) < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "BIO_reset failed"); -+ } -+ return NULL; -+ } -+ res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), -+ res); -+ if (res < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Handshake failed - BIO_read"); -+ if (BIO_reset(conn->ssl_out) < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "BIO_reset failed"); -+ } -+ wpabuf_free(out_data); -+ return NULL; -+ } -+ wpabuf_put(out_data, res); -+ -+ return out_data; -+} -+ -+ -+static struct wpabuf * -+openssl_get_appl_data(struct tls_connection *conn, size_t max_len) -+{ -+ struct wpabuf *appl_data; -+ int res; -+ -+ appl_data = wpabuf_alloc(max_len + 100); -+ if (appl_data == NULL) -+ return NULL; -+ -+ res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), -+ wpabuf_size(appl_data)); -+ if (res < 0) { -+ int err = SSL_get_error(conn->ssl, res); -+ if (err == SSL_ERROR_WANT_READ || -+ err == SSL_ERROR_WANT_WRITE) { -+ wpa_printf(MSG_DEBUG, "SSL: No Application Data " -+ "included"); -+ } else { -+ tls_show_errors(MSG_INFO, __func__, -+ "Failed to read possible " -+ "Application Data"); -+ } -+ wpabuf_free(appl_data); -+ return NULL; -+ } -+ -+ wpabuf_put(appl_data, res); -+ wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " -+ "message", appl_data); -+ -+ return appl_data; -+} -+ -+ -+static struct wpabuf * -+openssl_connection_handshake(struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data, int server) -+{ -+ struct wpabuf *out_data; -+ -+ if (appl_data) -+ *appl_data = NULL; -+ -+ out_data = openssl_handshake(conn, in_data, server); -+ if (out_data == NULL) -+ return NULL; -+ -+ if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) -+ *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); -+ -+ return out_data; -+} -+ -+ -+struct wpabuf * -+tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ return openssl_connection_handshake(conn, in_data, appl_data, 0); -+} -+ -+ -+struct wpabuf * tls_connection_server_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ return openssl_connection_handshake(conn, in_data, appl_data, 1); -+} -+ -+ -+struct wpabuf * tls_connection_encrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ int res; -+ struct wpabuf *buf; -+ -+ if (conn == NULL) -+ return NULL; -+ -+ /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ -+ if ((res = BIO_reset(conn->ssl_in)) < 0 || -+ (res = BIO_reset(conn->ssl_out)) < 0) { -+ tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); -+ return NULL; -+ } -+ res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); -+ if (res < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Encryption failed - SSL_write"); -+ return NULL; -+ } -+ -+ /* Read encrypted data to be sent to the server */ -+ buf = wpabuf_alloc(wpabuf_len(in_data) + 300); -+ if (buf == NULL) -+ return NULL; -+ res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); -+ if (res < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Encryption failed - BIO_read"); -+ wpabuf_free(buf); -+ return NULL; -+ } -+ wpabuf_put(buf, res); -+ -+ return buf; -+} -+ -+ -+struct wpabuf * tls_connection_decrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ int res; -+ struct wpabuf *buf; -+ -+ /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ -+ res = BIO_write(conn->ssl_in, wpabuf_head(in_data), -+ wpabuf_len(in_data)); -+ if (res < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Decryption failed - BIO_write"); -+ return NULL; -+ } -+ if (BIO_reset(conn->ssl_out) < 0) { -+ tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); -+ return NULL; -+ } -+ -+ /* Read decrypted data for further processing */ -+ /* -+ * Even though we try to disable TLS compression, it is possible that -+ * this cannot be done with all TLS libraries. Add extra buffer space -+ * to handle the possibility of the decrypted data being longer than -+ * input data. -+ */ -+ buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); -+ if (buf == NULL) -+ return NULL; -+ res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); -+ if (res < 0) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Decryption failed - SSL_read"); -+ wpabuf_free(buf); -+ return NULL; -+ } -+ wpabuf_put(buf, res); -+ -+ return buf; -+} -+ -+ -+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) -+{ -+ return conn ? conn->ssl->hit : 0; -+} -+ -+ -+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, -+ u8 *ciphers) -+{ -+ char buf[100], *pos, *end; -+ u8 *c; -+ int ret; -+ -+ if (conn == NULL || conn->ssl == NULL || ciphers == NULL) -+ return -1; -+ -+ buf[0] = '\0'; -+ pos = buf; -+ end = pos + sizeof(buf); -+ -+ c = ciphers; -+ while (*c != TLS_CIPHER_NONE) { -+ const char *suite; -+ -+ switch (*c) { -+ case TLS_CIPHER_RC4_SHA: -+ suite = "RC4-SHA"; -+ break; -+ case TLS_CIPHER_AES128_SHA: -+ suite = "AES128-SHA"; -+ break; -+ case TLS_CIPHER_RSA_DHE_AES128_SHA: -+ suite = "DHE-RSA-AES128-SHA"; -+ break; -+ case TLS_CIPHER_ANON_DH_AES128_SHA: -+ suite = "ADH-AES128-SHA"; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "TLS: Unsupported " -+ "cipher selection: %d", *c); -+ return -1; -+ } -+ ret = os_snprintf(pos, end - pos, ":%s", suite); -+ if (ret < 0 || ret >= end - pos) -+ break; -+ pos += ret; -+ -+ c++; -+ } -+ -+ wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); -+ -+ if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { -+ tls_show_errors(MSG_INFO, __func__, -+ "Cipher suite configuration failed"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, -+ char *buf, size_t buflen) -+{ -+ const char *name; -+ if (conn == NULL || conn->ssl == NULL) -+ return -1; -+ -+ name = SSL_get_cipher(conn->ssl); -+ if (name == NULL) -+ return -1; -+ -+ os_strlcpy(buf, name, buflen); -+ return 0; -+} -+ -+ -+int tls_connection_enable_workaround(void *ssl_ctx, -+ struct tls_connection *conn) -+{ -+ SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); -+ -+ return 0; -+} -+ -+ -+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) -+/* ClientHello TLS extensions require a patch to openssl, so this function is -+ * commented out unless explicitly needed for EAP-FAST in order to be able to -+ * build this file with unmodified openssl. */ -+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, -+ int ext_type, const u8 *data, -+ size_t data_len) -+{ -+ if (conn == NULL || conn->ssl == NULL || ext_type != 35) -+ return -1; -+ -+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE -+ if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, -+ data_len) != 1) -+ return -1; -+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+ if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data, -+ data_len) != 1) -+ return -1; -+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+ -+ return 0; -+} -+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ -+ -+ -+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->failed; -+} -+ -+ -+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->read_alerts; -+} -+ -+ -+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->write_alerts; -+} -+ -+ -+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, -+ const struct tls_connection_params *params) -+{ -+ int ret; -+ unsigned long err; -+ -+ if (conn == NULL) -+ return -1; -+ -+ while ((err = ERR_get_error())) { -+ wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", -+ __func__, ERR_error_string(err, NULL)); -+ } -+ -+ if (params->engine) { -+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); -+ ret = tls_engine_init(conn, params->engine_id, params->pin, -+ params->key_id, params->cert_id, -+ params->ca_cert_id); -+ if (ret) -+ return ret; -+ } -+ if (tls_connection_set_subject_match(conn, -+ params->subject_match, -+ params->altsubject_match)) -+ return -1; -+ -+ if (params->engine && params->ca_cert_id) { -+ if (tls_connection_engine_ca_cert(tls_ctx, conn, -+ params->ca_cert_id)) -+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; -+ } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert, -+ params->ca_cert_blob, -+ params->ca_cert_blob_len, -+ params->ca_path)) -+ return -1; -+ -+ if (params->engine && params->cert_id) { -+ if (tls_connection_engine_client_cert(conn, params->cert_id)) -+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; -+ } else if (tls_connection_client_cert(conn, params->client_cert, -+ params->client_cert_blob, -+ params->client_cert_blob_len)) -+ return -1; -+ -+ if (params->engine && params->key_id) { -+ wpa_printf(MSG_DEBUG, "TLS: Using private key from engine"); -+ if (tls_connection_engine_private_key(conn)) -+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; -+ } else if (tls_connection_private_key(tls_ctx, conn, -+ params->private_key, -+ params->private_key_passwd, -+ params->private_key_blob, -+ params->private_key_blob_len)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'", -+ params->private_key); -+ return -1; -+ } -+ -+ if (tls_connection_dh(conn, params->dh_file)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", -+ params->dh_file); -+ return -1; -+ } -+ -+ tls_get_errors(tls_ctx); -+ -+ return 0; -+} -+ -+ -+int tls_global_set_params(void *tls_ctx, -+ const struct tls_connection_params *params) -+{ -+ SSL_CTX *ssl_ctx = tls_ctx; -+ unsigned long err; -+ -+ while ((err = ERR_get_error())) { -+ wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", -+ __func__, ERR_error_string(err, NULL)); -+ } -+ -+ if (tls_global_ca_cert(ssl_ctx, params->ca_cert)) -+ return -1; -+ -+ if (tls_global_client_cert(ssl_ctx, params->client_cert)) -+ return -1; -+ -+ if (tls_global_private_key(ssl_ctx, params->private_key, -+ params->private_key_passwd)) -+ return -1; -+ -+ if (tls_global_dh(ssl_ctx, params->dh_file)) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", -+ params->dh_file); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int tls_connection_get_keyblock_size(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ const EVP_CIPHER *c; -+ const EVP_MD *h; -+ -+ if (conn == NULL || conn->ssl == NULL || -+ conn->ssl->enc_read_ctx == NULL || -+ conn->ssl->enc_read_ctx->cipher == NULL || -+ conn->ssl->read_hash == NULL) -+ return -1; -+ -+ c = conn->ssl->enc_read_ctx->cipher; -+#if OPENSSL_VERSION_NUMBER >= 0x00909000L -+ h = EVP_MD_CTX_md(conn->ssl->read_hash); -+#else -+ h = conn->ssl->read_hash; -+#endif -+ -+ return 2 * (EVP_CIPHER_key_length(c) + -+ EVP_MD_size(h) + -+ EVP_CIPHER_iv_length(c)); -+} -+ -+ -+unsigned int tls_capabilities(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, -+ int tls_ia) -+{ -+ return -1; -+} -+ -+ -+struct wpabuf * tls_connection_ia_send_phase_finished( -+ void *tls_ctx, struct tls_connection *conn, int final) -+{ -+ return NULL; -+} -+ -+ -+int tls_connection_ia_final_phase_finished(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_ia_permute_inner_secret(void *tls_ctx, -+ struct tls_connection *conn, -+ const u8 *key, size_t key_len) -+{ -+ return -1; -+} -+ -+ -+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) -+/* Pre-shared secred requires a patch to openssl, so this function is -+ * commented out unless explicitly needed for EAP-FAST in order to be able to -+ * build this file with unmodified openssl. */ -+ -+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, -+ STACK_OF(SSL_CIPHER) *peer_ciphers, -+ SSL_CIPHER **cipher, void *arg) -+{ -+ struct tls_connection *conn = arg; -+ int ret; -+ -+ if (conn == NULL || conn->session_ticket_cb == NULL) -+ return 0; -+ -+ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, -+ conn->session_ticket, -+ conn->session_ticket_len, -+ s->s3->client_random, -+ s->s3->server_random, secret); -+ os_free(conn->session_ticket); -+ conn->session_ticket = NULL; -+ -+ if (ret <= 0) -+ return 0; -+ -+ *secret_len = SSL_MAX_MASTER_KEY_LENGTH; -+ return 1; -+} -+ -+ -+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE -+static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, -+ int len, void *arg) -+{ -+ struct tls_connection *conn = arg; -+ -+ if (conn == NULL || conn->session_ticket_cb == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); -+ -+ os_free(conn->session_ticket); -+ conn->session_ticket = NULL; -+ -+ wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " -+ "extension", data, len); -+ -+ conn->session_ticket = os_malloc(len); -+ if (conn->session_ticket == NULL) -+ return 0; -+ -+ os_memcpy(conn->session_ticket, data, len); -+ conn->session_ticket_len = len; -+ -+ return 1; -+} -+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+#ifdef SSL_OP_NO_TICKET -+static void tls_hello_ext_cb(SSL *s, int client_server, int type, -+ unsigned char *data, int len, void *arg) -+{ -+ struct tls_connection *conn = arg; -+ -+ if (conn == NULL || conn->session_ticket_cb == NULL) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, -+ type, len); -+ -+ if (type == TLSEXT_TYPE_session_ticket && !client_server) { -+ os_free(conn->session_ticket); -+ conn->session_ticket = NULL; -+ -+ wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " -+ "extension", data, len); -+ conn->session_ticket = os_malloc(len); -+ if (conn->session_ticket == NULL) -+ return; -+ -+ os_memcpy(conn->session_ticket, data, len); -+ conn->session_ticket_len = len; -+ } -+} -+#else /* SSL_OP_NO_TICKET */ -+static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) -+{ -+ struct tls_connection *conn = arg; -+ -+ if (conn == NULL || conn->session_ticket_cb == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, -+ ext->type, ext->length); -+ -+ os_free(conn->session_ticket); -+ conn->session_ticket = NULL; -+ -+ if (ext->type == 35) { -+ wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " -+ "extension", ext->data, ext->length); -+ conn->session_ticket = os_malloc(ext->length); -+ if (conn->session_ticket == NULL) -+ return SSL_AD_INTERNAL_ERROR; -+ -+ os_memcpy(conn->session_ticket, ext->data, ext->length); -+ conn->session_ticket_len = ext->length; -+ } -+ -+ return 0; -+} -+#endif /* SSL_OP_NO_TICKET */ -+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ -+ -+ -+int tls_connection_set_session_ticket_cb(void *tls_ctx, -+ struct tls_connection *conn, -+ tls_session_ticket_cb cb, -+ void *ctx) -+{ -+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) -+ conn->session_ticket_cb = cb; -+ conn->session_ticket_cb_ctx = ctx; -+ -+ if (cb) { -+ if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb, -+ conn) != 1) -+ return -1; -+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE -+ SSL_set_session_ticket_ext_cb(conn->ssl, -+ tls_session_ticket_ext_cb, conn); -+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+#ifdef SSL_OP_NO_TICKET -+ SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb); -+ SSL_set_tlsext_debug_arg(conn->ssl, conn); -+#else /* SSL_OP_NO_TICKET */ -+ if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb, -+ conn) != 1) -+ return -1; -+#endif /* SSL_OP_NO_TICKET */ -+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+ } else { -+ if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) -+ return -1; -+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE -+ SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); -+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+#ifdef SSL_OP_NO_TICKET -+ SSL_set_tlsext_debug_callback(conn->ssl, NULL); -+ SSL_set_tlsext_debug_arg(conn->ssl, conn); -+#else /* SSL_OP_NO_TICKET */ -+ if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1) -+ return -1; -+#endif /* SSL_OP_NO_TICKET */ -+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ -+ } -+ -+ return 0; -+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ -+ return -1; -+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_schannel.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_schannel.c -new file mode 100644 -index 0000000000000..4a94e99119821 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/crypto/tls_schannel.c -@@ -0,0 +1,767 @@ -+/* -+ * SSL/TLS interface functions for Microsoft Schannel -+ * Copyright (c) 2005-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+/* -+ * FIX: Go through all SSPI functions and verify what needs to be freed -+ * FIX: session resumption -+ * TODO: add support for server cert chain validation -+ * TODO: add support for CA cert validation -+ * TODO: add support for EAP-TLS (client cert/key conf) -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+#define SECURITY_WIN32 -+#include -+#include -+ -+#include "common.h" -+#include "tls.h" -+ -+ -+struct tls_global { -+ HMODULE hsecurity; -+ PSecurityFunctionTable sspi; -+ HCERTSTORE my_cert_store; -+}; -+ -+struct tls_connection { -+ int established, start; -+ int failed, read_alerts, write_alerts; -+ -+ SCHANNEL_CRED schannel_cred; -+ CredHandle creds; -+ CtxtHandle context; -+ -+ u8 eap_tls_prf[128]; -+ int eap_tls_prf_set; -+}; -+ -+ -+static int schannel_load_lib(struct tls_global *global) -+{ -+ INIT_SECURITY_INTERFACE pInitSecurityInterface; -+ -+ global->hsecurity = LoadLibrary(TEXT("Secur32.dll")); -+ if (global->hsecurity == NULL) { -+ wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x", -+ __func__, (unsigned int) GetLastError()); -+ return -1; -+ } -+ -+ pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress( -+ global->hsecurity, "InitSecurityInterfaceA"); -+ if (pInitSecurityInterface == NULL) { -+ wpa_printf(MSG_ERROR, "%s: Could not find " -+ "InitSecurityInterfaceA from Secur32.dll", -+ __func__); -+ FreeLibrary(global->hsecurity); -+ global->hsecurity = NULL; -+ return -1; -+ } -+ -+ global->sspi = pInitSecurityInterface(); -+ if (global->sspi == NULL) { -+ wpa_printf(MSG_ERROR, "%s: Could not read security " -+ "interface - 0x%x", -+ __func__, (unsigned int) GetLastError()); -+ FreeLibrary(global->hsecurity); -+ global->hsecurity = NULL; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void * tls_init(const struct tls_config *conf) -+{ -+ struct tls_global *global; -+ -+ global = os_zalloc(sizeof(*global)); -+ if (global == NULL) -+ return NULL; -+ if (schannel_load_lib(global)) { -+ os_free(global); -+ return NULL; -+ } -+ return global; -+} -+ -+ -+void tls_deinit(void *ssl_ctx) -+{ -+ struct tls_global *global = ssl_ctx; -+ -+ if (global->my_cert_store) -+ CertCloseStore(global->my_cert_store, 0); -+ FreeLibrary(global->hsecurity); -+ os_free(global); -+} -+ -+ -+int tls_get_errors(void *ssl_ctx) -+{ -+ return 0; -+} -+ -+ -+struct tls_connection * tls_connection_init(void *ssl_ctx) -+{ -+ struct tls_connection *conn; -+ -+ conn = os_zalloc(sizeof(*conn)); -+ if (conn == NULL) -+ return NULL; -+ conn->start = 1; -+ -+ return conn; -+} -+ -+ -+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return; -+ -+ os_free(conn); -+} -+ -+ -+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) -+{ -+ return conn ? conn->established : 0; -+} -+ -+ -+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) -+{ -+ struct tls_global *global = ssl_ctx; -+ if (conn == NULL) -+ return -1; -+ -+ conn->eap_tls_prf_set = 0; -+ conn->established = conn->failed = 0; -+ conn->read_alerts = conn->write_alerts = 0; -+ global->sspi->DeleteSecurityContext(&conn->context); -+ /* FIX: what else needs to be reseted? */ -+ -+ return 0; -+} -+ -+ -+int tls_global_set_params(void *tls_ctx, -+ const struct tls_connection_params *params) -+{ -+ return -1; -+} -+ -+ -+int tls_global_set_verify(void *ssl_ctx, int check_crl) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, -+ int verify_peer) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, -+ struct tls_keys *keys) -+{ -+ /* Schannel does not export master secret or client/server random. */ -+ return -1; -+} -+ -+ -+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, -+ const char *label, int server_random_first, -+ u8 *out, size_t out_len) -+{ -+ /* -+ * Cannot get master_key from Schannel, but EapKeyBlock can be used to -+ * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and -+ * EAP-TTLS cannot use this, though, since they are using different -+ * labels. The only option could be to implement TLSv1 completely here -+ * and just use Schannel or CryptoAPI for low-level crypto -+ * functionality.. -+ */ -+ -+ if (conn == NULL || !conn->eap_tls_prf_set || server_random_first || -+ os_strcmp(label, "client EAP encryption") != 0 || -+ out_len > sizeof(conn->eap_tls_prf)) -+ return -1; -+ -+ os_memcpy(out, conn->eap_tls_prf, out_len); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global, -+ struct tls_connection *conn) -+{ -+ DWORD sspi_flags, sspi_flags_out; -+ SecBufferDesc outbuf; -+ SecBuffer outbufs[1]; -+ SECURITY_STATUS status; -+ TimeStamp ts_expiry; -+ -+ sspi_flags = ISC_REQ_REPLAY_DETECT | -+ ISC_REQ_CONFIDENTIALITY | -+ ISC_RET_EXTENDED_ERROR | -+ ISC_REQ_ALLOCATE_MEMORY | -+ ISC_REQ_MANUAL_CRED_VALIDATION; -+ -+ wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__); -+ -+ outbufs[0].pvBuffer = NULL; -+ outbufs[0].BufferType = SECBUFFER_TOKEN; -+ outbufs[0].cbBuffer = 0; -+ -+ outbuf.cBuffers = 1; -+ outbuf.pBuffers = outbufs; -+ outbuf.ulVersion = SECBUFFER_VERSION; -+ -+#ifdef UNICODE -+ status = global->sspi->InitializeSecurityContextW( -+ &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, -+ SECURITY_NATIVE_DREP, NULL, 0, &conn->context, -+ &outbuf, &sspi_flags_out, &ts_expiry); -+#else /* UNICODE */ -+ status = global->sspi->InitializeSecurityContextA( -+ &conn->creds, NULL, NULL /* server name */, sspi_flags, 0, -+ SECURITY_NATIVE_DREP, NULL, 0, &conn->context, -+ &outbuf, &sspi_flags_out, &ts_expiry); -+#endif /* UNICODE */ -+ if (status != SEC_I_CONTINUE_NEEDED) { -+ wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA " -+ "failed - 0x%x", -+ __func__, (unsigned int) status); -+ return NULL; -+ } -+ -+ if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { -+ struct wpabuf *buf; -+ wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello", -+ outbufs[0].pvBuffer, outbufs[0].cbBuffer); -+ conn->start = 0; -+ buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, -+ outbufs[0].cbBuffer); -+ if (buf == NULL) -+ return NULL; -+ global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); -+ return buf; -+ } -+ -+ wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello"); -+ -+ return NULL; -+} -+ -+ -+#ifndef SECPKG_ATTR_EAP_KEY_BLOCK -+#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b -+ -+typedef struct _SecPkgContext_EapKeyBlock { -+ BYTE rgbKeys[128]; -+ BYTE rgbIVs[64]; -+} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock; -+#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */ -+ -+static int tls_get_eap(struct tls_global *global, struct tls_connection *conn) -+{ -+ SECURITY_STATUS status; -+ SecPkgContext_EapKeyBlock kb; -+ -+ /* Note: Windows NT and Windows Me/98/95 do not support getting -+ * EapKeyBlock */ -+ -+ status = global->sspi->QueryContextAttributes( -+ &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb); -+ if (status != SEC_E_OK) { -+ wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes(" -+ "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)", -+ __func__, (int) status); -+ return -1; -+ } -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys", -+ kb.rgbKeys, sizeof(kb.rgbKeys)); -+ wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs", -+ kb.rgbIVs, sizeof(kb.rgbIVs)); -+ -+ os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys)); -+ conn->eap_tls_prf_set = 1; -+ return 0; -+} -+ -+ -+struct wpabuf * tls_connection_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ struct tls_global *global = tls_ctx; -+ DWORD sspi_flags, sspi_flags_out; -+ SecBufferDesc inbuf, outbuf; -+ SecBuffer inbufs[2], outbufs[1]; -+ SECURITY_STATUS status; -+ TimeStamp ts_expiry; -+ struct wpabuf *out_buf = NULL; -+ -+ if (appl_data) -+ *appl_data = NULL; -+ -+ if (conn->start) -+ return tls_conn_hs_clienthello(global, conn); -+ -+ wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process", -+ (int) wpabuf_len(in_data)); -+ -+ sspi_flags = ISC_REQ_REPLAY_DETECT | -+ ISC_REQ_CONFIDENTIALITY | -+ ISC_RET_EXTENDED_ERROR | -+ ISC_REQ_ALLOCATE_MEMORY | -+ ISC_REQ_MANUAL_CRED_VALIDATION; -+ -+ /* Input buffer for Schannel */ -+ inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data); -+ inbufs[0].cbBuffer = wpabuf_len(in_data); -+ inbufs[0].BufferType = SECBUFFER_TOKEN; -+ -+ /* Place for leftover data from Schannel */ -+ inbufs[1].pvBuffer = NULL; -+ inbufs[1].cbBuffer = 0; -+ inbufs[1].BufferType = SECBUFFER_EMPTY; -+ -+ inbuf.cBuffers = 2; -+ inbuf.pBuffers = inbufs; -+ inbuf.ulVersion = SECBUFFER_VERSION; -+ -+ /* Output buffer for Schannel */ -+ outbufs[0].pvBuffer = NULL; -+ outbufs[0].cbBuffer = 0; -+ outbufs[0].BufferType = SECBUFFER_TOKEN; -+ -+ outbuf.cBuffers = 1; -+ outbuf.pBuffers = outbufs; -+ outbuf.ulVersion = SECBUFFER_VERSION; -+ -+#ifdef UNICODE -+ status = global->sspi->InitializeSecurityContextW( -+ &conn->creds, &conn->context, NULL, sspi_flags, 0, -+ SECURITY_NATIVE_DREP, &inbuf, 0, NULL, -+ &outbuf, &sspi_flags_out, &ts_expiry); -+#else /* UNICODE */ -+ status = global->sspi->InitializeSecurityContextA( -+ &conn->creds, &conn->context, NULL, sspi_flags, 0, -+ SECURITY_NATIVE_DREP, &inbuf, 0, NULL, -+ &outbuf, &sspi_flags_out, &ts_expiry); -+#endif /* UNICODE */ -+ -+ wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> " -+ "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d " -+ "intype[1]=%d outlen[0]=%d", -+ (int) status, (int) inbufs[0].cbBuffer, -+ (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer, -+ (int) inbufs[1].BufferType, -+ (int) outbufs[0].cbBuffer); -+ if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED || -+ (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) { -+ if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { -+ wpa_hexdump(MSG_MSGDUMP, "SChannel - output", -+ outbufs[0].pvBuffer, outbufs[0].cbBuffer); -+ out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, -+ outbufs[0].cbBuffer); -+ global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); -+ outbufs[0].pvBuffer = NULL; -+ if (out_buf == NULL) -+ return NULL; -+ } -+ } -+ -+ switch (status) { -+ case SEC_E_INCOMPLETE_MESSAGE: -+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE"); -+ break; -+ case SEC_I_CONTINUE_NEEDED: -+ wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED"); -+ break; -+ case SEC_E_OK: -+ /* TODO: verify server certificate chain */ -+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake " -+ "completed successfully"); -+ conn->established = 1; -+ tls_get_eap(global, conn); -+ -+ /* Need to return something to get final TLS ACK. */ -+ if (out_buf == NULL) -+ out_buf = wpabuf_alloc(0); -+ -+ if (inbufs[1].BufferType == SECBUFFER_EXTRA) { -+ wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted " -+ "application data", -+ inbufs[1].pvBuffer, inbufs[1].cbBuffer); -+ if (appl_data) { -+ *appl_data = wpabuf_alloc_copy( -+ outbufs[1].pvBuffer, -+ outbufs[1].cbBuffer); -+ } -+ global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); -+ inbufs[1].pvBuffer = NULL; -+ } -+ break; -+ case SEC_I_INCOMPLETE_CREDENTIALS: -+ wpa_printf(MSG_DEBUG, -+ "Schannel: SEC_I_INCOMPLETE_CREDENTIALS"); -+ break; -+ case SEC_E_WRONG_PRINCIPAL: -+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL"); -+ break; -+ case SEC_E_INTERNAL_ERROR: -+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR"); -+ break; -+ } -+ -+ if (FAILED(status)) { -+ wpa_printf(MSG_DEBUG, "Schannel: Handshake failed " -+ "(out_buf=%p)", out_buf); -+ conn->failed++; -+ global->sspi->DeleteSecurityContext(&conn->context); -+ return out_buf; -+ } -+ -+ if (inbufs[1].BufferType == SECBUFFER_EXTRA) { -+ /* TODO: Can this happen? What to do with this data? */ -+ wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data", -+ inbufs[1].pvBuffer, inbufs[1].cbBuffer); -+ global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); -+ inbufs[1].pvBuffer = NULL; -+ } -+ -+ return out_buf; -+} -+ -+ -+struct wpabuf * tls_connection_server_handshake(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data, -+ struct wpabuf **appl_data) -+{ -+ return NULL; -+} -+ -+ -+struct wpabuf * tls_connection_encrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ struct tls_global *global = tls_ctx; -+ SECURITY_STATUS status; -+ SecBufferDesc buf; -+ SecBuffer bufs[4]; -+ SecPkgContext_StreamSizes sizes; -+ int i; -+ struct wpabuf *out; -+ -+ status = global->sspi->QueryContextAttributes(&conn->context, -+ SECPKG_ATTR_STREAM_SIZES, -+ &sizes); -+ if (status != SEC_E_OK) { -+ wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed", -+ __func__); -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u", -+ __func__, -+ (unsigned int) sizes.cbHeader, -+ (unsigned int) sizes.cbTrailer); -+ -+ out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) + -+ sizes.cbTrailer); -+ -+ os_memset(&bufs, 0, sizeof(bufs)); -+ bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader); -+ bufs[0].cbBuffer = sizes.cbHeader; -+ bufs[0].BufferType = SECBUFFER_STREAM_HEADER; -+ -+ bufs[1].pvBuffer = wpabuf_put(out, 0); -+ wpabuf_put_buf(out, in_data); -+ bufs[1].cbBuffer = wpabuf_len(in_data); -+ bufs[1].BufferType = SECBUFFER_DATA; -+ -+ bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer); -+ bufs[2].cbBuffer = sizes.cbTrailer; -+ bufs[2].BufferType = SECBUFFER_STREAM_TRAILER; -+ -+ buf.ulVersion = SECBUFFER_VERSION; -+ buf.cBuffers = 3; -+ buf.pBuffers = bufs; -+ -+ status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0); -+ -+ wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> " -+ "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " -+ "len[2]=%d type[2]=%d", -+ (int) status, -+ (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, -+ (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, -+ (int) bufs[2].cbBuffer, (int) bufs[2].BufferType); -+ wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: " -+ "out_data=%p bufs %p %p %p", -+ wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer, -+ bufs[2].pvBuffer); -+ -+ for (i = 0; i < 3; i++) { -+ if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY) -+ { -+ wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs", -+ bufs[i].pvBuffer, bufs[i].cbBuffer); -+ } -+ } -+ -+ if (status == SEC_E_OK) { -+ wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); -+ wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data " -+ "from EncryptMessage", out); -+ return out; -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", -+ __func__, (int) status); -+ wpabuf_free(out); -+ return NULL; -+} -+ -+ -+struct wpabuf * tls_connection_decrypt(void *tls_ctx, -+ struct tls_connection *conn, -+ const struct wpabuf *in_data) -+{ -+ struct tls_global *global = tls_ctx; -+ SECURITY_STATUS status; -+ SecBufferDesc buf; -+ SecBuffer bufs[4]; -+ int i; -+ struct wpabuf *out, *tmp; -+ -+ wpa_hexdump_buf(MSG_MSGDUMP, -+ "Schannel: Encrypted data to DecryptMessage", in_data); -+ os_memset(&bufs, 0, sizeof(bufs)); -+ tmp = wpabuf_dup(in_data); -+ if (tmp == NULL) -+ return NULL; -+ bufs[0].pvBuffer = wpabuf_mhead(tmp); -+ bufs[0].cbBuffer = wpabuf_len(in_data); -+ bufs[0].BufferType = SECBUFFER_DATA; -+ -+ bufs[1].BufferType = SECBUFFER_EMPTY; -+ bufs[2].BufferType = SECBUFFER_EMPTY; -+ bufs[3].BufferType = SECBUFFER_EMPTY; -+ -+ buf.ulVersion = SECBUFFER_VERSION; -+ buf.cBuffers = 4; -+ buf.pBuffers = bufs; -+ -+ status = global->sspi->DecryptMessage(&conn->context, &buf, 0, -+ NULL); -+ wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> " -+ "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d " -+ "len[2]=%d type[2]=%d len[3]=%d type[3]=%d", -+ (int) status, -+ (int) bufs[0].cbBuffer, (int) bufs[0].BufferType, -+ (int) bufs[1].cbBuffer, (int) bufs[1].BufferType, -+ (int) bufs[2].cbBuffer, (int) bufs[2].BufferType, -+ (int) bufs[3].cbBuffer, (int) bufs[3].BufferType); -+ wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: " -+ "out_data=%p bufs %p %p %p %p", -+ wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer, -+ bufs[2].pvBuffer, bufs[3].pvBuffer); -+ -+ switch (status) { -+ case SEC_E_INCOMPLETE_MESSAGE: -+ wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE", -+ __func__); -+ break; -+ case SEC_E_OK: -+ wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); -+ for (i = 0; i < 4; i++) { -+ if (bufs[i].BufferType == SECBUFFER_DATA) -+ break; -+ } -+ if (i == 4) { -+ wpa_printf(MSG_DEBUG, "%s: No output data from " -+ "DecryptMessage", __func__); -+ wpabuf_free(tmp); -+ return NULL; -+ } -+ wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from " -+ "DecryptMessage", -+ bufs[i].pvBuffer, bufs[i].cbBuffer); -+ out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer); -+ wpabuf_free(tmp); -+ return out; -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", -+ __func__, (int) status); -+ wpabuf_free(tmp); -+ return NULL; -+} -+ -+ -+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, -+ u8 *ciphers) -+{ -+ return -1; -+} -+ -+ -+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, -+ char *buf, size_t buflen) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_enable_workaround(void *ssl_ctx, -+ struct tls_connection *conn) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, -+ int ext_type, const u8 *data, -+ size_t data_len) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->failed; -+} -+ -+ -+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->read_alerts; -+} -+ -+ -+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) -+{ -+ if (conn == NULL) -+ return -1; -+ return conn->write_alerts; -+} -+ -+ -+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, -+ const struct tls_connection_params *params) -+{ -+ struct tls_global *global = tls_ctx; -+ ALG_ID algs[1]; -+ SECURITY_STATUS status; -+ TimeStamp ts_expiry; -+ -+ if (conn == NULL) -+ return -1; -+ -+ if (global->my_cert_store == NULL && -+ (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) == -+ NULL) { -+ wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x", -+ __func__, (unsigned int) GetLastError()); -+ return -1; -+ } -+ -+ os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred)); -+ conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; -+ conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1; -+ algs[0] = CALG_RSA_KEYX; -+ conn->schannel_cred.cSupportedAlgs = 1; -+ conn->schannel_cred.palgSupportedAlgs = algs; -+ conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; -+#ifdef UNICODE -+ status = global->sspi->AcquireCredentialsHandleW( -+ NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, -+ &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); -+#else /* UNICODE */ -+ status = global->sspi->AcquireCredentialsHandleA( -+ NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, -+ &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry); -+#endif /* UNICODE */ -+ if (status != SEC_E_OK) { -+ wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - " -+ "0x%x", __func__, (unsigned int) status); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+unsigned int tls_capabilities(void *tls_ctx) -+{ -+ return 0; -+} -+ -+ -+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, -+ int tls_ia) -+{ -+ return -1; -+} -+ -+ -+struct wpabuf * tls_connection_ia_send_phase_finished( -+ void *tls_ctx, struct tls_connection *conn, int final); -+{ -+ return NULL; -+} -+ -+ -+int tls_connection_ia_final_phase_finished(void *tls_ctx, -+ struct tls_connection *conn) -+{ -+ return -1; -+} -+ -+ -+int tls_connection_ia_permute_inner_secret(void *tls_ctx, -+ struct tls_connection *conn, -+ const u8 *key, size_t key_len) -+{ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/.gitignore b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/.gitignore -new file mode 100644 -index 0000000000000..1d9e0e661afee ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/.gitignore -@@ -0,0 +1,2 @@ -+build.wpa_supplicant -+build.hostapd -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Apple80211.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Apple80211.h -new file mode 100644 -index 0000000000000..2a612e73083a6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Apple80211.h -@@ -0,0 +1,156 @@ -+#ifndef APPLE80211_H -+#define APPLE80211_H -+ -+/* -+ * Apple80211 framework definitions -+ * This is an undocumented interface and the definitions here are based on -+ * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and -+ * whatever related information can be found with google and experiments ;-). -+ */ -+ -+typedef struct __WirelessRef *WirelessRef; -+typedef SInt32 WirelessError; -+#define errWirelessNoError 0 -+ -+typedef struct WirelessInfo { -+ UInt16 link_qual; -+ UInt16 comms_qual; -+ UInt16 signal; -+ UInt16 noise; -+ UInt16 port_stat; -+ UInt16 client_mode; -+ UInt16 res1; -+ UInt16 power; -+ UInt16 res2; -+ UInt8 bssID[6]; -+ UInt8 ssid[34]; -+} WirelessInfo; -+ -+typedef struct WirelessInfo2 { -+ /* TODO - these are probably not in correct order or complete */ -+ WirelessInfo info1; -+ UInt8 macAddress[6]; -+} WirelessInfo2; -+ -+typedef struct WirelessNetworkInfo { -+ UInt16 channel; -+ UInt16 noise; -+ UInt16 signal; -+ UInt8 bssid[6]; -+ UInt16 beacon_int; -+ UInt16 capability; -+ UInt16 ssid_len; -+ UInt8 ssid[32]; -+} WirelessNetworkInfo; -+ -+typedef int wirelessKeyType; /* TODO */ -+ -+int WirelessIsAvailable(void); -+WirelessError WirelessAttach(WirelessRef *ref, UInt32 res); -+WirelessError WirelessDetach(WirelessRef ref); -+WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes, -+ void *out_ptr, int out_bytes); -+WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled); -+WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled); -+WirelessError WirelessSetPower(WirelessRef ref, UInt8 power); -+WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power); -+WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info); -+WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info); -+WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results, -+ UInt32 strip_dups); -+WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results, -+ CFArrayRef *ibss_results, UInt32 strip_dups); -+WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results, -+ UInt32 strip_dups, CFStringRef ssid); -+WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid, -+ UInt32 strip_dups, CFArrayRef *results); -+WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid); -+WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid, -+ CFStringRef passwd); -+WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid); -+/* -+ * Set WEP key -+ * ref: wireless reference from WirelessAttach() -+ * type: ? -+ * key_idx: 0..3 -+ * key_len: 13 for WEP-104 or 0 for clearing the key -+ * key: Pointer to the key or %NULL if key_len = 0 -+ */ -+WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type, -+ int key_idx, int key_len, -+ const unsigned char *key); -+/* -+ * Set WPA key (e.g., PMK for 4-way handshake) -+ * ref: wireless reference from WirelessAttach() -+ * type: 0..4; 1 = PMK -+ * key_len: 16, 32, or 0 -+ * key: Pointer to the key or %NULL if key_len = 0 -+ */ -+WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type, -+ int key_len, const unsigned char *key); -+WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid, -+ CFStringRef key); -+WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res, -+ CFStringRef key); -+WirelessError WirelessDisassociate(WirelessRef ref); -+ -+/* -+ * Get a copy of scan results for the given SSID -+ * The returned dictionary includes following entries: -+ * beaconInterval: CFNumber(kCFNumberSInt32Type) -+ * SSID: CFData buffer of the SSID -+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2 -+ * name: Name of the network (SSID string) -+ * BSSID: CFData buffer of the BSSID -+ * channel: CFNumber(kCFNumberSInt32Type) -+ * signal: CFNumber(kCFNumberSInt32Type) -+ * appleIE: CFData -+ * WPSNOPINRequired: CFBoolean -+ * noise: CFNumber(kCFNumberSInt32Type) -+ * capability: CFNumber(kCFNumberSInt32Type) -+ * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type) -+ * appleIE_Version: CFNumber(kCFNumberSInt32Type) -+ * appleIE_Robust: CFBoolean -+ * WPSConfigured: CFBoolean -+ * scanWasDirected: CFBoolean -+ * appleIE_Product: CFNumber(kCFNumberSInt32Type) -+ * authModes: CFArray of CFNumber(kCFNumberSInt32Type) -+ * multiCipher: CFNumber(kCFNumberSInt32Type) -+ */ -+CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid); -+ -+/* -+ * Get information about the current association -+ * The returned dictionary includes following entries: -+ * keyData: CFData buffer of the key (e.g., 32-octet PSK) -+ * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP? -+ * channel: CFNumber(kCFNumberSInt32Type) -+ * isIBSS: CFBoolean -+ * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open, -+ * 129 = WPA2-Enterprise -+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2 -+ * SSID: CFData buffer of the SSID -+ * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP? -+ */ -+CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref); -+ -+WirelessError WirelessConfigure(WirelessRef ref); -+ -+/* -+ * Get ASP information -+ * The returned dictionary includes following entries: -+ * Version: version number (e.g., 3.0) -+ * Channel: channel (e.g., 1) -+ * Vendor: vendor (e.g., 2) -+ */ -+CFDictionaryRef WirelessGetInfoASP(void); -+ -+/* -+ * Get a copy of the interface dictionary -+ * The returned dictionary has a key,value pairs for wireless interfaces. -+ * The key is the interface name and the value is the driver identifier, e.g., -+ * en1: com.apple.driver.AirPort.Atheros -+ */ -+CFDictionaryRef WirelessCopyInterfaceDict(void); -+ -+#endif /* APPLE80211_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Makefile -new file mode 100644 -index 0000000000000..07600e52c2fde ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/Makefile -@@ -0,0 +1,9 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ rm -f build.wpa_supplicant build.hostapd -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.c -new file mode 100644 -index 0000000000000..ce004fe4c96f5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.c -@@ -0,0 +1,189 @@ -+#include "includes.h" -+#include -+ -+#include "common.h" -+ -+#include -+#include "MobileApple80211.h" -+ -+/* -+ * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid -+ * having to link with full Preferences.framework. -+ */ -+ -+static void *aeropuerto = NULL; -+ -+ -+int _Apple80211Initialized(void) -+{ -+ return aeropuerto ? 1 : 0; -+} -+ -+ -+static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL; -+ -+int Apple80211Open(Apple80211Ref *ctx) -+{ -+ return __Apple80211Open(ctx); -+} -+ -+ -+static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL; -+ -+int Apple80211Close(Apple80211Ref ctx) -+{ -+ return __Apple80211Close(ctx); -+} -+ -+ -+static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list) -+ = NULL; -+ -+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list) -+{ -+ return __Apple80211GetIfListCopy(handle, list); -+} -+ -+ -+static int (*__Apple80211BindToInterface)(Apple80211Ref handle, -+ CFStringRef interface) = NULL; -+ -+int Apple80211BindToInterface(Apple80211Ref handle, -+ CFStringRef interface) -+{ -+ return __Apple80211BindToInterface(handle, interface); -+} -+ -+ -+static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle, -+ CFStringRef *name) = NULL; -+ -+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle, -+ CFStringRef *name) -+{ -+ return __Apple80211GetInterfaceNameCopy(handle, name); -+} -+ -+ -+static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle, -+ CFDictionaryRef *info) = NULL; -+ -+int Apple80211GetInfoCopy(Apple80211Ref handle, -+ CFDictionaryRef *info) -+{ -+ return __Apple80211GetInfoCopy(handle, info); -+} -+ -+ -+static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL; -+ -+int Apple80211GetPower(Apple80211Ref handle, char *pwr) -+{ -+ return __Apple80211GetPower(handle, pwr); -+} -+ -+ -+static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL; -+ -+int Apple80211SetPower(Apple80211Ref handle, char pwr) -+{ -+ return __Apple80211SetPower(handle, pwr); -+} -+ -+ -+static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list, -+ CFDictionaryRef parameters) = NULL; -+ -+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list, -+ CFDictionaryRef parameters) -+{ -+ return __Apple80211Scan(handle, list, parameters); -+} -+ -+ -+static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss, -+ CFStringRef password) = NULL; -+ -+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss, -+ CFStringRef password) -+{ -+ return __Apple80211Associate(handle, bss, password); -+} -+ -+ -+static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle, -+ CFDictionaryRef bss, -+ CFStringRef password, -+ CFDictionaryRef *info) = -+ NULL; -+ -+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss, -+ CFStringRef password, CFDictionaryRef *info) -+{ -+ return __Apple80211AssociateAndCopyInfo(handle, bss, password, info); -+} -+ -+ -+static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field, -+ CFDictionaryRef arg2, void *value) = NULL; -+ -+int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2, -+ void *value) -+{ -+ return __Apple80211CopyValue(handle, field, arg2, value); -+} -+ -+ -+#define DLSYM(s) \ -+do { \ -+ __ ## s = dlsym(aeropuerto, #s); \ -+ if (__ ## s == NULL) { \ -+ wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \ -+ "symbol '" #s "' (%s)", dlerror()); \ -+ err = 1; \ -+ } \ -+} while (0) -+ -+ -+__attribute__ ((constructor)) -+void _Apple80211_constructor(void) -+{ -+ const char *fname = "/System/Library/SystemConfiguration/" -+ "Aeropuerto.bundle/Aeropuerto"; -+ int err = 0; -+ -+ aeropuerto = dlopen(fname, RTLD_LAZY); -+ if (!aeropuerto) { -+ wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s " -+ "for symbols", fname); -+ return; -+ } -+ -+ DLSYM(Apple80211Open); -+ DLSYM(Apple80211Close); -+ DLSYM(Apple80211GetIfListCopy); -+ DLSYM(Apple80211BindToInterface); -+ DLSYM(Apple80211GetInterfaceNameCopy); -+ DLSYM(Apple80211GetInfoCopy); -+ DLSYM(Apple80211GetPower); -+ DLSYM(Apple80211SetPower); -+ DLSYM(Apple80211Scan); -+ DLSYM(Apple80211Associate); -+ DLSYM(Apple80211AssociateAndCopyInfo); -+ DLSYM(Apple80211CopyValue); -+ -+ if (err) { -+ dlclose(aeropuerto); -+ aeropuerto = NULL; -+ } -+} -+ -+ -+__attribute__ ((destructor)) -+void _Apple80211_destructor(void) -+{ -+ if (aeropuerto) { -+ dlclose(aeropuerto); -+ aeropuerto = NULL; -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.h -new file mode 100644 -index 0000000000000..64d439d660c8d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/MobileApple80211.h -@@ -0,0 +1,43 @@ -+#ifndef MOBILEAPPLE80211_H -+#define MOBILEAPPLE80211_H -+ -+/* -+ * MobileApple80211 interface for iPhone/iPod touch -+ * These functions are available from Aeropuerto. -+ */ -+ -+struct Apple80211; -+typedef struct Apple80211 *Apple80211Ref; -+ -+int Apple80211Open(Apple80211Ref *ctx); -+int Apple80211Close(Apple80211Ref ctx); -+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list); -+int Apple80211BindToInterface(Apple80211Ref handle, -+ CFStringRef interface); -+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle, -+ CFStringRef *name); -+int Apple80211GetInfoCopy(Apple80211Ref handle, -+ CFDictionaryRef *info); -+int Apple80211GetPower(Apple80211Ref handle, char *pwr); -+int Apple80211SetPower(Apple80211Ref handle, char pwr); -+ -+/* parameters can be NULL; returns scan results in CFArrayRef *list; -+ * caller will need to free with CFRelease() */ -+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list, -+ CFDictionaryRef parameters); -+ -+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss, -+ CFStringRef password); -+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss, -+ CFStringRef password, -+ CFDictionaryRef *info); -+ -+enum { -+ APPLE80211_VALUE_SSID = 1, -+ APPLE80211_VALUE_BSSID = 9 -+}; -+ -+int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2, -+ void *value); -+ -+#endif /* MOBILEAPPLE80211_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver.h -new file mode 100644 -index 0000000000000..8efd697ad778a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver.h -@@ -0,0 +1,3230 @@ -+/* -+ * Driver interface definition -+ * Copyright (c) 2003-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file defines a driver interface used by both %wpa_supplicant and -+ * hostapd. The first part of the file defines data structures used in various -+ * driver operations. This is followed by the struct wpa_driver_ops that each -+ * driver wrapper will beed to define with callback functions for requesting -+ * driver operations. After this, there are definitions for driver event -+ * reporting with wpa_supplicant_event() and some convenience helper functions -+ * that can be used to report events. -+ */ -+ -+#ifndef DRIVER_H -+#define DRIVER_H -+ -+#define WPA_SUPPLICANT_DRIVER_VERSION 4 -+ -+#include "common/defs.h" -+ -+#define HOSTAPD_CHAN_DISABLED 0x00000001 -+#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002 -+#define HOSTAPD_CHAN_NO_IBSS 0x00000004 -+#define HOSTAPD_CHAN_RADAR 0x00000008 -+#define HOSTAPD_CHAN_HT40PLUS 0x00000010 -+#define HOSTAPD_CHAN_HT40MINUS 0x00000020 -+#define HOSTAPD_CHAN_HT40 0x00000040 -+ -+/** -+ * struct hostapd_channel_data - Channel information -+ */ -+struct hostapd_channel_data { -+ /** -+ * chan - Channel number (IEEE 802.11) -+ */ -+ short chan; -+ -+ /** -+ * freq - Frequency in MHz -+ */ -+ short freq; -+ -+ /** -+ * flag - Channel flags (HOSTAPD_CHAN_*) -+ */ -+ int flag; -+ -+ /** -+ * max_tx_power - maximum transmit power in dBm -+ */ -+ u8 max_tx_power; -+}; -+ -+/** -+ * struct hostapd_hw_modes - Supported hardware mode information -+ */ -+struct hostapd_hw_modes { -+ /** -+ * mode - Hardware mode -+ */ -+ enum hostapd_hw_mode mode; -+ -+ /** -+ * num_channels - Number of entries in the channels array -+ */ -+ int num_channels; -+ -+ /** -+ * channels - Array of supported channels -+ */ -+ struct hostapd_channel_data *channels; -+ -+ /** -+ * num_rates - Number of entries in the rates array -+ */ -+ int num_rates; -+ -+ /** -+ * rates - Array of supported rates in 100 kbps units -+ */ -+ int *rates; -+ -+ /** -+ * ht_capab - HT (IEEE 802.11n) capabilities -+ */ -+ u16 ht_capab; -+ -+ /** -+ * mcs_set - MCS (IEEE 802.11n) rate parameters -+ */ -+ u8 mcs_set[16]; -+ -+ /** -+ * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters -+ */ -+ u8 a_mpdu_params; -+}; -+ -+ -+#define IEEE80211_MODE_INFRA 0 -+#define IEEE80211_MODE_IBSS 1 -+#define IEEE80211_MODE_AP 2 -+ -+#define IEEE80211_CAP_ESS 0x0001 -+#define IEEE80211_CAP_IBSS 0x0002 -+#define IEEE80211_CAP_PRIVACY 0x0010 -+ -+#define WPA_SCAN_QUAL_INVALID BIT(0) -+#define WPA_SCAN_NOISE_INVALID BIT(1) -+#define WPA_SCAN_LEVEL_INVALID BIT(2) -+#define WPA_SCAN_LEVEL_DBM BIT(3) -+#define WPA_SCAN_AUTHENTICATED BIT(4) -+#define WPA_SCAN_ASSOCIATED BIT(5) -+ -+/** -+ * struct wpa_scan_res - Scan result for an BSS/IBSS -+ * @flags: information flags about the BSS/IBSS (WPA_SCAN_*) -+ * @bssid: BSSID -+ * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1) -+ * @beacon_int: beacon interval in TUs (host byte order) -+ * @caps: capability information field in host byte order -+ * @qual: signal quality -+ * @noise: noise level -+ * @level: signal level -+ * @tsf: Timestamp -+ * @age: Age of the information in milliseconds (i.e., how many milliseconds -+ * ago the last Beacon or Probe Response frame was received) -+ * @ie_len: length of the following IE field in octets -+ * @beacon_ie_len: length of the following Beacon IE field in octets -+ * -+ * This structure is used as a generic format for scan results from the -+ * driver. Each driver interface implementation is responsible for converting -+ * the driver or OS specific scan results into this format. -+ * -+ * If the driver does not support reporting all IEs, the IE data structure is -+ * constructed of the IEs that are available. This field will also need to -+ * include SSID in IE format. All drivers are encouraged to be extended to -+ * report all IEs to make it easier to support future additions. -+ */ -+struct wpa_scan_res { -+ unsigned int flags; -+ u8 bssid[ETH_ALEN]; -+ int freq; -+ u16 beacon_int; -+ u16 caps; -+ int qual; -+ int noise; -+ int level; -+ u64 tsf; -+ unsigned int age; -+ size_t ie_len; -+ size_t beacon_ie_len; -+ /* -+ * Followed by ie_len octets of IEs from Probe Response frame (or if -+ * the driver does not indicate source of IEs, these may also be from -+ * Beacon frame). After the first set of IEs, another set of IEs may -+ * follow (with beacon_ie_len octets of data) if the driver provides -+ * both IE sets. -+ */ -+}; -+ -+/** -+ * struct wpa_scan_results - Scan results -+ * @res: Array of pointers to allocated variable length scan result entries -+ * @num: Number of entries in the scan result array -+ */ -+struct wpa_scan_results { -+ struct wpa_scan_res **res; -+ size_t num; -+}; -+ -+/** -+ * struct wpa_interface_info - Network interface information -+ * @next: Pointer to the next interface or NULL if this is the last one -+ * @ifname: Interface name that can be used with init() or init2() -+ * @desc: Human readable adapter description (e.g., vendor/model) or NULL if -+ * not available -+ * @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one -+ * is not an allocated copy, i.e., get_interfaces() caller will not free -+ * this) -+ */ -+struct wpa_interface_info { -+ struct wpa_interface_info *next; -+ char *ifname; -+ char *desc; -+ const char *drv_name; -+}; -+ -+#define WPAS_MAX_SCAN_SSIDS 4 -+ -+/** -+ * struct wpa_driver_scan_params - Scan parameters -+ * Data for struct wpa_driver_ops::scan2(). -+ */ -+struct wpa_driver_scan_params { -+ /** -+ * ssids - SSIDs to scan for -+ */ -+ struct wpa_driver_scan_ssid { -+ /** -+ * ssid - specific SSID to scan for (ProbeReq) -+ * %NULL or zero-length SSID is used to indicate active scan -+ * with wildcard SSID. -+ */ -+ const u8 *ssid; -+ /** -+ * ssid_len: Length of the SSID in octets -+ */ -+ size_t ssid_len; -+ } ssids[WPAS_MAX_SCAN_SSIDS]; -+ -+ /** -+ * num_ssids - Number of entries in ssids array -+ * Zero indicates a request for a passive scan. -+ */ -+ size_t num_ssids; -+ -+ /** -+ * extra_ies - Extra IE(s) to add into Probe Request or %NULL -+ */ -+ const u8 *extra_ies; -+ -+ /** -+ * extra_ies_len - Length of extra_ies in octets -+ */ -+ size_t extra_ies_len; -+ -+ /** -+ * freqs - Array of frequencies to scan or %NULL for all frequencies -+ * -+ * The frequency is set in MHz. The array is zero-terminated. -+ */ -+ int *freqs; -+ -+ /** -+ * filter_ssids - Filter for reporting SSIDs -+ * -+ * This optional parameter can be used to request the driver wrapper to -+ * filter scan results to include only the specified SSIDs. %NULL -+ * indicates that no filtering is to be done. This can be used to -+ * reduce memory needs for scan results in environments that have large -+ * number of APs with different SSIDs. -+ * -+ * The driver wrapper is allowed to take this allocated buffer into its -+ * own use by setting the pointer to %NULL. In that case, the driver -+ * wrapper is responsible for freeing the buffer with os_free() once it -+ * is not needed anymore. -+ */ -+ struct wpa_driver_scan_filter { -+ u8 ssid[32]; -+ size_t ssid_len; -+ } *filter_ssids; -+ -+ /** -+ * num_filter_ssids - Number of entries in filter_ssids array -+ */ -+ size_t num_filter_ssids; -+}; -+ -+/** -+ * struct wpa_driver_auth_params - Authentication parameters -+ * Data for struct wpa_driver_ops::authenticate(). -+ */ -+struct wpa_driver_auth_params { -+ int freq; -+ const u8 *bssid; -+ const u8 *ssid; -+ size_t ssid_len; -+ int auth_alg; -+ const u8 *ie; -+ size_t ie_len; -+ const u8 *wep_key[4]; -+ size_t wep_key_len[4]; -+ int wep_tx_keyidx; -+ int local_state_change; -+}; -+ -+enum wps_mode { -+ WPS_MODE_NONE /* no WPS provisioning being used */, -+ WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */, -+ WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection -+ */ -+}; -+ -+/** -+ * struct wpa_driver_associate_params - Association parameters -+ * Data for struct wpa_driver_ops::associate(). -+ */ -+struct wpa_driver_associate_params { -+ /** -+ * bssid - BSSID of the selected AP -+ * This can be %NULL, if ap_scan=2 mode is used and the driver is -+ * responsible for selecting with which BSS to associate. */ -+ const u8 *bssid; -+ -+ /** -+ * ssid - The selected SSID -+ */ -+ const u8 *ssid; -+ -+ /** -+ * ssid_len - Length of the SSID (1..32) -+ */ -+ size_t ssid_len; -+ -+ /** -+ * freq - Frequency of the channel the selected AP is using -+ * Frequency that the selected AP is using (in MHz as -+ * reported in the scan results) -+ */ -+ int freq; -+ -+ /** -+ * wpa_ie - WPA information element for (Re)Association Request -+ * WPA information element to be included in (Re)Association -+ * Request (including information element id and length). Use -+ * of this WPA IE is optional. If the driver generates the WPA -+ * IE, it can use pairwise_suite, group_suite, and -+ * key_mgmt_suite to select proper algorithms. In this case, -+ * the driver has to notify wpa_supplicant about the used WPA -+ * IE by generating an event that the interface code will -+ * convert into EVENT_ASSOCINFO data (see below). -+ * -+ * When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE -+ * instead. The driver can determine which version is used by -+ * looking at the first byte of the IE (0xdd for WPA, 0x30 for -+ * WPA2/RSN). -+ * -+ * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE. -+ */ -+ const u8 *wpa_ie; -+ -+ /** -+ * wpa_ie_len - length of the wpa_ie -+ */ -+ size_t wpa_ie_len; -+ -+ /** -+ * pairwise_suite - Selected pairwise cipher suite -+ * -+ * This is usually ignored if @wpa_ie is used. -+ */ -+ enum wpa_cipher pairwise_suite; -+ -+ /** -+ * group_suite - Selected group cipher suite -+ * -+ * This is usually ignored if @wpa_ie is used. -+ */ -+ enum wpa_cipher group_suite; -+ -+ /** -+ * key_mgmt_suite - Selected key management suite -+ * -+ * This is usually ignored if @wpa_ie is used. -+ */ -+ enum wpa_key_mgmt key_mgmt_suite; -+ -+ /** -+ * auth_alg - Allowed authentication algorithms -+ * Bit field of WPA_AUTH_ALG_* -+ */ -+ int auth_alg; -+ -+ /** -+ * mode - Operation mode (infra/ibss) IEEE80211_MODE_* -+ */ -+ int mode; -+ -+ /** -+ * wep_key - WEP keys for static WEP configuration -+ */ -+ const u8 *wep_key[4]; -+ -+ /** -+ * wep_key_len - WEP key length for static WEP configuration -+ */ -+ size_t wep_key_len[4]; -+ -+ /** -+ * wep_tx_keyidx - WEP TX key index for static WEP configuration -+ */ -+ int wep_tx_keyidx; -+ -+ /** -+ * mgmt_frame_protection - IEEE 802.11w management frame protection -+ */ -+ enum mfp_options mgmt_frame_protection; -+ -+ /** -+ * ft_ies - IEEE 802.11r / FT information elements -+ * If the supplicant is using IEEE 802.11r (FT) and has the needed keys -+ * for fast transition, this parameter is set to include the IEs that -+ * are to be sent in the next FT Authentication Request message. -+ * update_ft_ies() handler is called to update the IEs for further -+ * FT messages in the sequence. -+ * -+ * The driver should use these IEs only if the target AP is advertising -+ * the same mobility domain as the one included in the MDIE here. -+ * -+ * In ap_scan=2 mode, the driver can use these IEs when moving to a new -+ * AP after the initial association. These IEs can only be used if the -+ * target AP is advertising support for FT and is using the same MDIE -+ * and SSID as the current AP. -+ * -+ * The driver is responsible for reporting the FT IEs received from the -+ * AP's response using wpa_supplicant_event() with EVENT_FT_RESPONSE -+ * type. update_ft_ies() handler will then be called with the FT IEs to -+ * include in the next frame in the authentication sequence. -+ */ -+ const u8 *ft_ies; -+ -+ /** -+ * ft_ies_len - Length of ft_ies in bytes -+ */ -+ size_t ft_ies_len; -+ -+ /** -+ * ft_md - FT Mobility domain (6 octets) (also included inside ft_ies) -+ * -+ * This value is provided to allow the driver interface easier access -+ * to the current mobility domain. This value is set to %NULL if no -+ * mobility domain is currently active. -+ */ -+ const u8 *ft_md; -+ -+ /** -+ * passphrase - RSN passphrase for PSK -+ * -+ * This value is made available only for WPA/WPA2-Personal (PSK) and -+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is -+ * the 8..63 character ASCII passphrase, if available. Please note that -+ * this can be %NULL if passphrase was not used to generate the PSK. In -+ * that case, the psk field must be used to fetch the PSK. -+ */ -+ const char *passphrase; -+ -+ /** -+ * psk - RSN PSK (alternative for passphrase for PSK) -+ * -+ * This value is made available only for WPA/WPA2-Personal (PSK) and -+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is -+ * the 32-octet (256-bit) PSK, if available. The driver wrapper should -+ * be prepared to handle %NULL value as an error. -+ */ -+ const u8 *psk; -+ -+ /** -+ * drop_unencrypted - Enable/disable unencrypted frame filtering -+ * -+ * Configure the driver to drop all non-EAPOL frames (both receive and -+ * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must -+ * still be allowed for key negotiation. -+ */ -+ int drop_unencrypted; -+ -+ /** -+ * prev_bssid - Previously used BSSID in this ESS -+ * -+ * When not %NULL, this is a request to use reassociation instead of -+ * association. -+ */ -+ const u8 *prev_bssid; -+ -+ /** -+ * wps - WPS mode -+ * -+ * If the driver needs to do special configuration for WPS association, -+ * this variable provides more information on what type of association -+ * is being requested. Most drivers should not need ot use this. -+ */ -+ enum wps_mode wps; -+ -+ /** -+ * p2p - Whether this connection is a P2P group -+ */ -+ int p2p; -+ -+ /** -+ * uapsd - UAPSD parameters for the network -+ * -1 = do not change defaults -+ * AP mode: 1 = enabled, 0 = disabled -+ * STA mode: bits 0..3 UAPSD enabled for VO,VI,BK,BE -+ */ -+ int uapsd; -+}; -+ -+/** -+ * struct wpa_driver_capa - Driver capability information -+ */ -+struct wpa_driver_capa { -+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA 0x00000001 -+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2 0x00000002 -+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK 0x00000004 -+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK 0x00000008 -+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE 0x00000010 -+#define WPA_DRIVER_CAPA_KEY_MGMT_FT 0x00000020 -+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK 0x00000040 -+ unsigned int key_mgmt; -+ -+#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001 -+#define WPA_DRIVER_CAPA_ENC_WEP104 0x00000002 -+#define WPA_DRIVER_CAPA_ENC_TKIP 0x00000004 -+#define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008 -+ unsigned int enc; -+ -+#define WPA_DRIVER_AUTH_OPEN 0x00000001 -+#define WPA_DRIVER_AUTH_SHARED 0x00000002 -+#define WPA_DRIVER_AUTH_LEAP 0x00000004 -+ unsigned int auth; -+ -+/* Driver generated WPA/RSN IE */ -+#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001 -+/* Driver needs static WEP key setup after association command */ -+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002 -+#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004 -+/* Driver takes care of RSN 4-way handshake internally; PMK is configured with -+ * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */ -+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008 -+#define WPA_DRIVER_FLAGS_WIRED 0x00000010 -+/* Driver provides separate commands for authentication and association (SME in -+ * wpa_supplicant). */ -+#define WPA_DRIVER_FLAGS_SME 0x00000020 -+/* Driver supports AP mode */ -+#define WPA_DRIVER_FLAGS_AP 0x00000040 -+/* Driver needs static WEP key setup after association has been completed */ -+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080 -+/* Driver takes care of P2P management operations */ -+#define WPA_DRIVER_FLAGS_P2P_MGMT 0x00000100 -+/* Driver supports concurrent P2P operations */ -+#define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200 -+/* -+ * Driver uses the initial interface as a dedicated management interface, i.e., -+ * it cannot be used for P2P group operations or non-P2P purposes. -+ */ -+#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400 -+/* This interface is P2P capable (P2P Device, GO, or P2P Client */ -+#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800 -+/* Driver supports concurrent operations on multiple channels */ -+#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT 0x00001000 -+/* -+ * Driver uses the initial interface for P2P management interface and non-P2P -+ * purposes (e.g., connect to infra AP), but this interface cannot be used for -+ * P2P group operations. -+ */ -+#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 0x00002000 -+/* -+ * Driver is known to use sane error codes, i.e., when it indicates that -+ * something (e.g., association) fails, there was indeed a failure and the -+ * operation does not end up getting completed successfully later. -+ */ -+#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000 -+/* Driver supports off-channel TX */ -+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000 -+/* Driver indicates TX status events for EAPOL Data frames */ -+#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000 -+ unsigned int flags; -+ -+ int max_scan_ssids; -+ -+ /** -+ * max_remain_on_chan - Maximum remain-on-channel duration in msec -+ */ -+ unsigned int max_remain_on_chan; -+ -+ /** -+ * max_stations - Maximum number of associated stations the driver -+ * supports in AP mode -+ */ -+ unsigned int max_stations; -+}; -+ -+ -+struct hostapd_data; -+ -+struct hostap_sta_driver_data { -+ unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes; -+ unsigned long current_tx_rate; -+ unsigned long inactive_msec; -+ unsigned long flags; -+ unsigned long num_ps_buf_frames; -+ unsigned long tx_retry_failed; -+ unsigned long tx_retry_count; -+ int last_rssi; -+ int last_ack_rssi; -+}; -+ -+struct hostapd_sta_add_params { -+ const u8 *addr; -+ u16 aid; -+ u16 capability; -+ const u8 *supp_rates; -+ size_t supp_rates_len; -+ u16 listen_interval; -+ const struct ieee80211_ht_capabilities *ht_capabilities; -+}; -+ -+struct hostapd_freq_params { -+ int mode; -+ int freq; -+ int channel; -+ int ht_enabled; -+ int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled, -+ * secondary channel below primary, 1 = HT40 -+ * enabled, secondary channel above primary */ -+}; -+ -+enum wpa_driver_if_type { -+ /** -+ * WPA_IF_STATION - Station mode interface -+ */ -+ WPA_IF_STATION, -+ -+ /** -+ * WPA_IF_AP_VLAN - AP mode VLAN interface -+ * -+ * This interface shares its address and Beacon frame with the main -+ * BSS. -+ */ -+ WPA_IF_AP_VLAN, -+ -+ /** -+ * WPA_IF_AP_BSS - AP mode BSS interface -+ * -+ * This interface has its own address and Beacon frame. -+ */ -+ WPA_IF_AP_BSS, -+ -+ /** -+ * WPA_IF_P2P_GO - P2P Group Owner -+ */ -+ WPA_IF_P2P_GO, -+ -+ /** -+ * WPA_IF_P2P_CLIENT - P2P Client -+ */ -+ WPA_IF_P2P_CLIENT, -+ -+ /** -+ * WPA_IF_P2P_GROUP - P2P Group interface (will become either -+ * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known) -+ */ -+ WPA_IF_P2P_GROUP -+}; -+ -+struct wpa_init_params { -+ const u8 *bssid; -+ const char *ifname; -+ const u8 *ssid; -+ size_t ssid_len; -+ const char *test_socket; -+ int use_pae_group_addr; -+ char **bridge; -+ size_t num_bridge; -+ -+ u8 *own_addr; /* buffer for writing own MAC address */ -+}; -+ -+ -+struct wpa_bss_params { -+ /** Interface name (for multi-SSID/VLAN support) */ -+ const char *ifname; -+ /** Whether IEEE 802.1X or WPA/WPA2 is enabled */ -+ int enabled; -+ -+ int wpa; -+ int ieee802_1x; -+ int wpa_group; -+ int wpa_pairwise; -+ int wpa_key_mgmt; -+ int rsn_preauth; -+ enum mfp_options ieee80211w; -+}; -+ -+#define WPA_STA_AUTHORIZED BIT(0) -+#define WPA_STA_WMM BIT(1) -+#define WPA_STA_SHORT_PREAMBLE BIT(2) -+#define WPA_STA_MFP BIT(3) -+ -+/** -+ * struct p2p_params - P2P parameters for driver-based P2P management -+ */ -+struct p2p_params { -+ const char *dev_name; -+ u8 pri_dev_type[8]; -+#define DRV_MAX_SEC_DEV_TYPES 5 -+ u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8]; -+ size_t num_sec_dev_types; -+}; -+ -+enum tdls_oper { -+ TDLS_DISCOVERY_REQ, -+ TDLS_SETUP, -+ TDLS_TEARDOWN, -+ TDLS_ENABLE_LINK, -+ TDLS_DISABLE_LINK, -+ TDLS_ENABLE, -+ TDLS_DISABLE -+}; -+ -+/** -+ * struct wpa_signal_info - Information about channel signal quality -+ */ -+struct wpa_signal_info { -+ u32 frequency; -+ int above_threshold; -+ int current_signal; -+ int current_noise; -+ int current_txrate; -+}; -+ -+/** -+ * struct wpa_driver_ops - Driver interface API definition -+ * -+ * This structure defines the API that each driver interface needs to implement -+ * for core wpa_supplicant code. All driver specific functionality is captured -+ * in this wrapper. -+ */ -+struct wpa_driver_ops { -+ /** Name of the driver interface */ -+ const char *name; -+ /** One line description of the driver interface */ -+ const char *desc; -+ -+ /** -+ * get_bssid - Get the current BSSID -+ * @priv: private driver interface data -+ * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes) -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * Query kernel driver for the current BSSID and copy it to bssid. -+ * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not -+ * associated. -+ */ -+ int (*get_bssid)(void *priv, u8 *bssid); -+ -+ /** -+ * get_ssid - Get the current SSID -+ * @priv: private driver interface data -+ * @ssid: buffer for SSID (at least 32 bytes) -+ * -+ * Returns: Length of the SSID on success, -1 on failure -+ * -+ * Query kernel driver for the current SSID and copy it to ssid. -+ * Returning zero is recommended if the STA is not associated. -+ * -+ * Note: SSID is an array of octets, i.e., it is not nul terminated and -+ * can, at least in theory, contain control characters (including nul) -+ * and as such, should be processed as binary data, not a printable -+ * string. -+ */ -+ int (*get_ssid)(void *priv, u8 *ssid); -+ -+ /** -+ * set_key - Configure encryption key -+ * @ifname: Interface name (for multi-SSID/VLAN support) -+ * @priv: private driver interface data -+ * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, -+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK); -+ * %WPA_ALG_NONE clears the key. -+ * @addr: Address of the peer STA (BSSID of the current AP when setting -+ * pairwise key in station mode), ff:ff:ff:ff:ff:ff for -+ * broadcast keys, %NULL for default keys that are used both for -+ * broadcast and unicast; when clearing keys, %NULL is used to -+ * indicate that both the broadcast-only and default key of the -+ * specified key index is to be cleared -+ * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for -+ * IGTK -+ * @set_tx: configure this key as the default Tx key (only used when -+ * driver does not support separate unicast/individual key -+ * @seq: sequence number/packet number, seq_len octets, the next -+ * packet number to be used for in replay protection; configured -+ * for Rx keys (in most cases, this is only used with broadcast -+ * keys and set to zero for unicast keys); %NULL if not set -+ * @seq_len: length of the seq, depends on the algorithm: -+ * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets -+ * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, -+ * 8-byte Rx Mic Key -+ * @key_len: length of the key buffer in octets (WEP: 5 or 13, -+ * TKIP: 32, CCMP: 16, IGTK: 16) -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * Configure the given key for the kernel driver. If the driver -+ * supports separate individual keys (4 default keys + 1 individual), -+ * addr can be used to determine whether the key is default or -+ * individual. If only 4 keys are supported, the default key with key -+ * index 0 is used as the individual key. STA must be configured to use -+ * it as the default Tx key (set_tx is set) and accept Rx for all the -+ * key indexes. In most cases, WPA uses only key indexes 1 and 2 for -+ * broadcast keys, so key index 0 is available for this kind of -+ * configuration. -+ * -+ * Please note that TKIP keys include separate TX and RX MIC keys and -+ * some drivers may expect them in different order than wpa_supplicant -+ * is using. If the TX/RX keys are swapped, all TKIP encrypted packets -+ * will trigger Michael MIC errors. This can be fixed by changing the -+ * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key -+ * in driver_*.c set_key() implementation, see driver_ndis.c for an -+ * example on how this can be done. -+ */ -+ int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg, -+ const u8 *addr, int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len); -+ -+ /** -+ * init - Initialize driver interface -+ * @ctx: context to be used when calling wpa_supplicant functions, -+ * e.g., wpa_supplicant_event() -+ * @ifname: interface name, e.g., wlan0 -+ * -+ * Returns: Pointer to private data, %NULL on failure -+ * -+ * Initialize driver interface, including event processing for kernel -+ * driver events (e.g., associated, scan results, Michael MIC failure). -+ * This function can allocate a private configuration data area for -+ * @ctx, file descriptor, interface name, etc. information that may be -+ * needed in future driver operations. If this is not used, non-NULL -+ * value will need to be returned because %NULL is used to indicate -+ * failure. The returned value will be used as 'void *priv' data for -+ * all other driver_ops functions. -+ * -+ * The main event loop (eloop.c) of wpa_supplicant can be used to -+ * register callback for read sockets (eloop_register_read_sock()). -+ * -+ * See below for more information about events and -+ * wpa_supplicant_event() function. -+ */ -+ void * (*init)(void *ctx, const char *ifname); -+ -+ /** -+ * deinit - Deinitialize driver interface -+ * @priv: private driver interface data from init() -+ * -+ * Shut down driver interface and processing of driver events. Free -+ * private data buffer if one was allocated in init() handler. -+ */ -+ void (*deinit)(void *priv); -+ -+ /** -+ * set_param - Set driver configuration parameters -+ * @priv: private driver interface data from init() -+ * @param: driver specific configuration parameters -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * Optional handler for notifying driver interface about configuration -+ * parameters (driver_param). -+ */ -+ int (*set_param)(void *priv, const char *param); -+ -+ /** -+ * set_countermeasures - Enable/disable TKIP countermeasures -+ * @priv: private driver interface data -+ * @enabled: 1 = countermeasures enabled, 0 = disabled -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * Configure TKIP countermeasures. When these are enabled, the driver -+ * should drop all received and queued frames that are using TKIP. -+ */ -+ int (*set_countermeasures)(void *priv, int enabled); -+ -+ /** -+ * deauthenticate - Request driver to deauthenticate -+ * @priv: private driver interface data -+ * @addr: peer address (BSSID of the AP) -+ * @reason_code: 16-bit reason code to be sent in the deauthentication -+ * frame -+ * -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*deauthenticate)(void *priv, const u8 *addr, int reason_code); -+ -+ /** -+ * disassociate - Request driver to disassociate -+ * @priv: private driver interface data -+ * @addr: peer address (BSSID of the AP) -+ * @reason_code: 16-bit reason code to be sent in the disassociation -+ * frame -+ * -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*disassociate)(void *priv, const u8 *addr, int reason_code); -+ -+ /** -+ * associate - Request driver to associate -+ * @priv: private driver interface data -+ * @params: association parameters -+ * -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*associate)(void *priv, -+ struct wpa_driver_associate_params *params); -+ -+ /** -+ * add_pmkid - Add PMKSA cache entry to the driver -+ * @priv: private driver interface data -+ * @bssid: BSSID for the PMKSA cache entry -+ * @pmkid: PMKID for the PMKSA cache entry -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is called when a new PMK is received, as a result of -+ * either normal authentication or RSN pre-authentication. -+ * -+ * If the driver generates RSN IE, i.e., it does not use wpa_ie in -+ * associate(), add_pmkid() can be used to add new PMKSA cache entries -+ * in the driver. If the driver uses wpa_ie from wpa_supplicant, this -+ * driver_ops function does not need to be implemented. Likewise, if -+ * the driver does not support WPA, this function is not needed. -+ */ -+ int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid); -+ -+ /** -+ * remove_pmkid - Remove PMKSA cache entry to the driver -+ * @priv: private driver interface data -+ * @bssid: BSSID for the PMKSA cache entry -+ * @pmkid: PMKID for the PMKSA cache entry -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is called when the supplicant drops a PMKSA cache -+ * entry for any reason. -+ * -+ * If the driver generates RSN IE, i.e., it does not use wpa_ie in -+ * associate(), remove_pmkid() can be used to synchronize PMKSA caches -+ * between the driver and wpa_supplicant. If the driver uses wpa_ie -+ * from wpa_supplicant, this driver_ops function does not need to be -+ * implemented. Likewise, if the driver does not support WPA, this -+ * function is not needed. -+ */ -+ int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid); -+ -+ /** -+ * flush_pmkid - Flush PMKSA cache -+ * @priv: private driver interface data -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is called when the supplicant drops all PMKSA cache -+ * entries for any reason. -+ * -+ * If the driver generates RSN IE, i.e., it does not use wpa_ie in -+ * associate(), remove_pmkid() can be used to synchronize PMKSA caches -+ * between the driver and wpa_supplicant. If the driver uses wpa_ie -+ * from wpa_supplicant, this driver_ops function does not need to be -+ * implemented. Likewise, if the driver does not support WPA, this -+ * function is not needed. -+ */ -+ int (*flush_pmkid)(void *priv); -+ -+ /** -+ * get_capa - Get driver capabilities -+ * @priv: private driver interface data -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * Get driver/firmware/hardware capabilities. -+ */ -+ int (*get_capa)(void *priv, struct wpa_driver_capa *capa); -+ -+ /** -+ * poll - Poll driver for association information -+ * @priv: private driver interface data -+ * -+ * This is an option callback that can be used when the driver does not -+ * provide event mechanism for association events. This is called when -+ * receiving WPA EAPOL-Key messages that require association -+ * information. The driver interface is supposed to generate associnfo -+ * event before returning from this callback function. In addition, the -+ * driver interface should generate an association event after having -+ * sent out associnfo. -+ */ -+ void (*poll)(void *priv); -+ -+ /** -+ * get_ifname - Get interface name -+ * @priv: private driver interface data -+ * -+ * Returns: Pointer to the interface name. This can differ from the -+ * interface name used in init() call. Init() is called first. -+ * -+ * This optional function can be used to allow the driver interface to -+ * replace the interface name with something else, e.g., based on an -+ * interface mapping from a more descriptive name. -+ */ -+ const char * (*get_ifname)(void *priv); -+ -+ /** -+ * get_mac_addr - Get own MAC address -+ * @priv: private driver interface data -+ * -+ * Returns: Pointer to own MAC address or %NULL on failure -+ * -+ * This optional function can be used to get the own MAC address of the -+ * device from the driver interface code. This is only needed if the -+ * l2_packet implementation for the OS does not provide easy access to -+ * a MAC address. */ -+ const u8 * (*get_mac_addr)(void *priv); -+ -+ /** -+ * send_eapol - Optional function for sending EAPOL packets -+ * @priv: private driver interface data -+ * @dest: Destination MAC address -+ * @proto: Ethertype -+ * @data: EAPOL packet starting with IEEE 802.1X header -+ * @data_len: Size of the EAPOL packet -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * This optional function can be used to override l2_packet operations -+ * with driver specific functionality. If this function pointer is set, -+ * l2_packet module is not used at all and the driver interface code is -+ * responsible for receiving and sending all EAPOL packets. The -+ * received EAPOL packets are sent to core code with EVENT_EAPOL_RX -+ * event. The driver interface is required to implement get_mac_addr() -+ * handler if send_eapol() is used. -+ */ -+ int (*send_eapol)(void *priv, const u8 *dest, u16 proto, -+ const u8 *data, size_t data_len); -+ -+ /** -+ * set_operstate - Sets device operating state to DORMANT or UP -+ * @priv: private driver interface data -+ * @state: 0 = dormant, 1 = up -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is an optional function that can be used on operating systems -+ * that support a concept of controlling network device state from user -+ * space applications. This function, if set, gets called with -+ * state = 1 when authentication has been completed and with state = 0 -+ * when connection is lost. -+ */ -+ int (*set_operstate)(void *priv, int state); -+ -+ /** -+ * mlme_setprotection - MLME-SETPROTECTION.request primitive -+ * @priv: Private driver interface data -+ * @addr: Address of the station for which to set protection (may be -+ * %NULL for group keys) -+ * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_* -+ * @key_type: MLME_SETPROTECTION_KEY_TYPE_* -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is an optional function that can be used to set the driver to -+ * require protection for Tx and/or Rx frames. This uses the layer -+ * interface defined in IEEE 802.11i-2004 clause 10.3.22.1 -+ * (MLME-SETPROTECTION.request). Many drivers do not use explicit -+ * set protection operation; instead, they set protection implicitly -+ * based on configured keys. -+ */ -+ int (*mlme_setprotection)(void *priv, const u8 *addr, int protect_type, -+ int key_type); -+ -+ /** -+ * get_hw_feature_data - Get hardware support data (channels and rates) -+ * @priv: Private driver interface data -+ * @num_modes: Variable for returning the number of returned modes -+ * flags: Variable for returning hardware feature flags -+ * Returns: Pointer to allocated hardware data on success or %NULL on -+ * failure. Caller is responsible for freeing this. -+ * -+ * This function is only needed for drivers that export MLME -+ * (management frame processing) to %wpa_supplicant or hostapd. -+ */ -+ struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv, -+ u16 *num_modes, -+ u16 *flags); -+ -+ /** -+ * set_channel - Set channel -+ * @priv: Private driver interface data -+ * @phymode: HOSTAPD_MODE_IEEE80211B, .. -+ * @chan: IEEE 802.11 channel number -+ * @freq: Frequency of the channel in MHz -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only needed for drivers that export MLME -+ * (management frame processing) to wpa_supplicant. -+ */ -+ int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan, -+ int freq); -+ -+ /** -+ * set_ssid - Set SSID -+ * @priv: Private driver interface data -+ * @ssid: SSID -+ * @ssid_len: SSID length -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only needed for drivers that export MLME -+ * (management frame processing) to wpa_supplicant. -+ */ -+ int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len); -+ -+ /** -+ * set_bssid - Set BSSID -+ * @priv: Private driver interface data -+ * @bssid: BSSID -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only needed for drivers that export MLME -+ * (management frame processing) to wpa_supplicant. -+ */ -+ int (*set_bssid)(void *priv, const u8 *bssid); -+ -+ /** -+ * send_mlme - Send management frame from MLME -+ * @priv: Private driver interface data -+ * @data: IEEE 802.11 management frame with IEEE 802.11 header -+ * @data_len: Size of the management frame -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only needed for drivers that export MLME -+ * (management frame processing) to wpa_supplicant. -+ */ -+ int (*send_mlme)(void *priv, const u8 *data, size_t data_len); -+ -+ /** -+ * mlme_add_sta - Add a STA entry into the driver/netstack -+ * @priv: Private driver interface data -+ * @addr: MAC address of the STA (e.g., BSSID of the AP) -+ * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11 -+ * format (one octet per rate, 1 = 0.5 Mbps) -+ * @supp_rates_len: Number of entries in supp_rates -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only needed for drivers that export MLME -+ * (management frame processing) to wpa_supplicant. When the MLME code -+ * completes association with an AP, this function is called to -+ * configure the driver/netstack with a STA entry for data frame -+ * processing (TX rate control, encryption/decryption). -+ */ -+ int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates, -+ size_t supp_rates_len); -+ -+ /** -+ * mlme_remove_sta - Remove a STA entry from the driver/netstack -+ * @priv: Private driver interface data -+ * @addr: MAC address of the STA (e.g., BSSID of the AP) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only needed for drivers that export MLME -+ * (management frame processing) to wpa_supplicant. -+ */ -+ int (*mlme_remove_sta)(void *priv, const u8 *addr); -+ -+ /** -+ * update_ft_ies - Update FT (IEEE 802.11r) IEs -+ * @priv: Private driver interface data -+ * @md: Mobility domain (2 octets) (also included inside ies) -+ * @ies: FT IEs (MDIE, FTIE, ...) or %NULL to remove IEs -+ * @ies_len: Length of FT IEs in bytes -+ * Returns: 0 on success, -1 on failure -+ * -+ * The supplicant uses this callback to let the driver know that keying -+ * material for FT is available and that the driver can use the -+ * provided IEs in the next message in FT authentication sequence. -+ * -+ * This function is only needed for driver that support IEEE 802.11r -+ * (Fast BSS Transition). -+ */ -+ int (*update_ft_ies)(void *priv, const u8 *md, const u8 *ies, -+ size_t ies_len); -+ -+ /** -+ * send_ft_action - Send FT Action frame (IEEE 802.11r) -+ * @priv: Private driver interface data -+ * @action: Action field value -+ * @target_ap: Target AP address -+ * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body) -+ * @ies_len: Length of FT IEs in bytes -+ * Returns: 0 on success, -1 on failure -+ * -+ * The supplicant uses this callback to request the driver to transmit -+ * an FT Action frame (action category 6) for over-the-DS fast BSS -+ * transition. -+ */ -+ int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap, -+ const u8 *ies, size_t ies_len); -+ -+ /** -+ * get_scan_results2 - Fetch the latest scan results -+ * @priv: private driver interface data -+ * -+ * Returns: Allocated buffer of scan results (caller is responsible for -+ * freeing the data structure) on success, NULL on failure -+ */ -+ struct wpa_scan_results * (*get_scan_results2)(void *priv); -+ -+ /** -+ * set_country - Set country -+ * @priv: Private driver interface data -+ * @alpha2: country to which to switch to -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is for drivers which support some form -+ * of setting a regulatory domain. -+ */ -+ int (*set_country)(void *priv, const char *alpha2); -+ -+ /** -+ * global_init - Global driver initialization -+ * Returns: Pointer to private data (global), %NULL on failure -+ * -+ * This optional function is called to initialize the driver wrapper -+ * for global data, i.e., data that applies to all interfaces. If this -+ * function is implemented, global_deinit() will also need to be -+ * implemented to free the private data. The driver will also likely -+ * use init2() function instead of init() to get the pointer to global -+ * data available to per-interface initializer. -+ */ -+ void * (*global_init)(void); -+ -+ /** -+ * global_deinit - Global driver deinitialization -+ * @priv: private driver global data from global_init() -+ * -+ * Terminate any global driver related functionality and free the -+ * global data structure. -+ */ -+ void (*global_deinit)(void *priv); -+ -+ /** -+ * init2 - Initialize driver interface (with global data) -+ * @ctx: context to be used when calling wpa_supplicant functions, -+ * e.g., wpa_supplicant_event() -+ * @ifname: interface name, e.g., wlan0 -+ * @global_priv: private driver global data from global_init() -+ * Returns: Pointer to private data, %NULL on failure -+ * -+ * This function can be used instead of init() if the driver wrapper -+ * uses global data. -+ */ -+ void * (*init2)(void *ctx, const char *ifname, void *global_priv); -+ -+ /** -+ * get_interfaces - Get information about available interfaces -+ * @global_priv: private driver global data from global_init() -+ * Returns: Allocated buffer of interface information (caller is -+ * responsible for freeing the data structure) on success, NULL on -+ * failure -+ */ -+ struct wpa_interface_info * (*get_interfaces)(void *global_priv); -+ -+ /** -+ * scan2 - Request the driver to initiate scan -+ * @priv: private driver interface data -+ * @params: Scan parameters -+ * -+ * Returns: 0 on success, -1 on failure -+ * -+ * Once the scan results are ready, the driver should report scan -+ * results event for wpa_supplicant which will eventually request the -+ * results with wpa_driver_get_scan_results2(). -+ */ -+ int (*scan2)(void *priv, struct wpa_driver_scan_params *params); -+ -+ /** -+ * authenticate - Request driver to authenticate -+ * @priv: private driver interface data -+ * @params: authentication parameters -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is an optional function that can be used with drivers that -+ * support separate authentication and association steps, i.e., when -+ * wpa_supplicant can act as the SME. If not implemented, associate() -+ * function is expected to take care of IEEE 802.11 authentication, -+ * too. -+ */ -+ int (*authenticate)(void *priv, -+ struct wpa_driver_auth_params *params); -+ -+ /** -+ * set_beacon - Set Beacon frame template -+ * @priv: Private driver interface data -+ * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE -+ * @head_len: Length of the head buffer in octets -+ * @tail: Beacon tail following TIM IE -+ * @tail_len: Length of the tail buffer in octets -+ * @dtim_period: DTIM period -+ * @beacon_int: Beacon interval -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to configure Beacon template for the driver in -+ * AP mode. The driver is responsible for building the full Beacon -+ * frame by concatenating the head part with TIM IE generated by the -+ * driver/firmware and finishing with the tail part. -+ */ -+ int (*set_beacon)(void *priv, const u8 *head, size_t head_len, -+ const u8 *tail, size_t tail_len, int dtim_period, -+ int beacon_int); -+ -+ /** -+ * hapd_init - Initialize driver interface (hostapd only) -+ * @hapd: Pointer to hostapd context -+ * @params: Configuration for the driver wrapper -+ * Returns: Pointer to private data, %NULL on failure -+ * -+ * This function is used instead of init() or init2() when the driver -+ * wrapper is used withh hostapd. -+ */ -+ void * (*hapd_init)(struct hostapd_data *hapd, -+ struct wpa_init_params *params); -+ -+ /** -+ * hapd_deinit - Deinitialize driver interface (hostapd only) -+ * @priv: Private driver interface data from hapd_init() -+ */ -+ void (*hapd_deinit)(void *priv); -+ -+ /** -+ * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only) -+ * @priv: Private driver interface data -+ * @params: BSS parameters -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is an optional function to configure the kernel driver to -+ * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This -+ * can be left undefined (set to %NULL) if IEEE 802.1X support is -+ * always enabled and the driver uses set_beacon() to set WPA/RSN IE -+ * for Beacon frames. -+ */ -+ int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params); -+ -+ /** -+ * set_privacy - Enable/disable privacy (AP only) -+ * @priv: Private driver interface data -+ * @enabled: 1 = privacy enabled, 0 = disabled -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is an optional function to configure privacy field in the -+ * kernel driver for Beacon frames. This can be left undefined (set to -+ * %NULL) if the driver uses the Beacon template from set_beacon(). -+ */ -+ int (*set_privacy)(void *priv, int enabled); -+ -+ /** -+ * get_seqnum - Fetch the current TSC/packet number (AP only) -+ * @ifname: The interface name (main or virtual) -+ * @priv: Private driver interface data -+ * @addr: MAC address of the station or %NULL for group keys -+ * @idx: Key index -+ * @seq: Buffer for returning the latest used TSC/packet number -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to fetch the last used TSC/packet number for -+ * a TKIP, CCMP, or BIP/IGTK key. It is mainly used with group keys, so -+ * there is no strict requirement on implementing support for unicast -+ * keys (i.e., addr != %NULL). -+ */ -+ int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr, -+ int idx, u8 *seq); -+ -+ /** -+ * flush - Flush all association stations (AP only) -+ * @priv: Private driver interface data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function requests the driver to disassociate all associated -+ * stations. This function does not need to be implemented if the -+ * driver does not process association frames internally. -+ */ -+ int (*flush)(void *priv); -+ -+ /** -+ * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP) -+ * @priv: Private driver interface data -+ * @elem: Information elements -+ * @elem_len: Length of the elem buffer in octets -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is an optional function to add information elements in the -+ * kernel driver for Beacon and Probe Response frames. This can be left -+ * undefined (set to %NULL) if the driver uses the Beacon template from -+ * set_beacon(). -+ */ -+ int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len); -+ -+ /** -+ * read_sta_data - Fetch station data (AP only) -+ * @priv: Private driver interface data -+ * @data: Buffer for returning station information -+ * @addr: MAC address of the station -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data, -+ const u8 *addr); -+ -+ /** -+ * hapd_send_eapol - Send an EAPOL packet (AP only) -+ * @priv: private driver interface data -+ * @addr: Destination MAC address -+ * @data: EAPOL packet starting with IEEE 802.1X header -+ * @data_len: Length of the EAPOL packet in octets -+ * @encrypt: Whether the frame should be encrypted -+ * @own_addr: Source MAC address -+ * @flags: WPA_STA_* flags for the destination station -+ * -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data, -+ size_t data_len, int encrypt, -+ const u8 *own_addr, u32 flags); -+ -+ /** -+ * sta_deauth - Deauthenticate a station (AP only) -+ * @priv: Private driver interface data -+ * @own_addr: Source address and BSSID for the Deauthentication frame -+ * @addr: MAC address of the station to deauthenticate -+ * @reason: Reason code for the Deauthentiation frame -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function requests a specific station to be deauthenticated and -+ * a Deauthentication frame to be sent to it. -+ */ -+ int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason); -+ -+ /** -+ * sta_disassoc - Disassociate a station (AP only) -+ * @priv: Private driver interface data -+ * @own_addr: Source address and BSSID for the Disassociation frame -+ * @addr: MAC address of the station to disassociate -+ * @reason: Reason code for the Disassociation frame -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function requests a specific station to be disassociated and -+ * a Disassociation frame to be sent to it. -+ */ -+ int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason); -+ -+ /** -+ * sta_remove - Remove a station entry (AP only) -+ * @priv: Private driver interface data -+ * @addr: MAC address of the station to be removed -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*sta_remove)(void *priv, const u8 *addr); -+ -+ /** -+ * hapd_get_ssid - Get the current SSID (AP only) -+ * @priv: Private driver interface data -+ * @buf: Buffer for returning the SSID -+ * @len: Maximum length of the buffer -+ * Returns: Length of the SSID on success, -1 on failure -+ * -+ * This function need not be implemented if the driver uses Beacon -+ * template from set_beacon() and does not reply to Probe Request -+ * frames. -+ */ -+ int (*hapd_get_ssid)(void *priv, u8 *buf, int len); -+ -+ /** -+ * hapd_set_ssid - Set SSID (AP only) -+ * @priv: Private driver interface data -+ * @buf: SSID -+ * @len: Length of the SSID in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*hapd_set_ssid)(void *priv, const u8 *buf, int len); -+ -+ /** -+ * hapd_set_countermeasures - Enable/disable TKIP countermeasures (AP) -+ * @priv: Private driver interface data -+ * @enabled: 1 = countermeasures enabled, 0 = disabled -+ * Returns: 0 on success, -1 on failure -+ * -+ * This need not be implemented if the driver does not take care of -+ * association processing. -+ */ -+ int (*hapd_set_countermeasures)(void *priv, int enabled); -+ -+ /** -+ * sta_add - Add a station entry -+ * @priv: Private driver interface data -+ * @params: Station parameters -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to add a station entry to the driver once the -+ * station has completed association. This is only used if the driver -+ * does not take care of association processing. -+ */ -+ int (*sta_add)(void *priv, struct hostapd_sta_add_params *params); -+ -+ /** -+ * get_inact_sec - Get station inactivity duration (AP only) -+ * @priv: Private driver interface data -+ * @addr: Station address -+ * Returns: Number of seconds station has been inactive, -1 on failure -+ */ -+ int (*get_inact_sec)(void *priv, const u8 *addr); -+ -+ /** -+ * sta_clear_stats - Clear station statistics (AP only) -+ * @priv: Private driver interface data -+ * @addr: Station address -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*sta_clear_stats)(void *priv, const u8 *addr); -+ -+ /** -+ * set_freq - Set channel/frequency (AP only) -+ * @priv: Private driver interface data -+ * @freq: Channel parameters -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_freq)(void *priv, struct hostapd_freq_params *freq); -+ -+ /** -+ * set_rts - Set RTS threshold -+ * @priv: Private driver interface data -+ * @rts: RTS threshold in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_rts)(void *priv, int rts); -+ -+ /** -+ * set_frag - Set fragmentation threshold -+ * @priv: Private driver interface data -+ * @frag: Fragmentation threshold in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_frag)(void *priv, int frag); -+ -+ /** -+ * sta_set_flags - Set station flags (AP only) -+ * @priv: Private driver interface data -+ * @addr: Station address -+ * @total_flags: Bitmap of all WPA_STA_* flags currently set -+ * @flags_or: Bitmap of WPA_STA_* flags to add -+ * @flags_and: Bitmap of WPA_STA_* flags to us as a mask -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*sta_set_flags)(void *priv, const u8 *addr, -+ int total_flags, int flags_or, int flags_and); -+ -+ /** -+ * set_rate_sets - Set supported and basic rate sets (AP only) -+ * @priv: Private driver interface data -+ * @supp_rates: -1 terminated array of supported rates in 100 kbps -+ * @basic_rates: -1 terminated array of basic rates in 100 kbps -+ * @mode: hardware mode (HOSTAPD_MODE_*) -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates, -+ int mode); -+ -+ /** -+ * set_cts_protect - Set CTS protection mode (AP only) -+ * @priv: Private driver interface data -+ * @value: Whether CTS protection is enabled -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_cts_protect)(void *priv, int value); -+ -+ /** -+ * set_preamble - Set preamble mode (AP only) -+ * @priv: Private driver interface data -+ * @value: Whether short preamble is enabled -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_preamble)(void *priv, int value); -+ -+ /** -+ * set_short_slot_time - Set short slot time (AP only) -+ * @priv: Private driver interface data -+ * @value: Whether short slot time is enabled -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_short_slot_time)(void *priv, int value); -+ -+ /** -+ * set_tx_queue_params - Set TX queue parameters -+ * @priv: Private driver interface data -+ * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK) -+ * @aifs: AIFS -+ * @cw_min: cwMin -+ * @cw_max: cwMax -+ * @burst_time: Maximum length for bursting in 0.1 msec units -+ */ -+ int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min, -+ int cw_max, int burst_time); -+ -+ /** -+ * valid_bss_mask - Validate BSSID mask -+ * @priv: Private driver interface data -+ * @addr: Address -+ * @mask: Mask -+ * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can -+ * be used, but the main interface address must be the first address in -+ * the block if mask is applied -+ */ -+ int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask); -+ -+ /** -+ * if_add - Add a virtual interface -+ * @priv: Private driver interface data -+ * @type: Interface type -+ * @ifname: Interface name for the new virtual interface -+ * @addr: Local address to use for the interface or %NULL to use the -+ * parent interface address -+ * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces -+ * @drv_priv: Pointer for overwriting the driver context or %NULL if -+ * not allowed (applies only to %WPA_IF_AP_BSS type) -+ * @force_ifname: Buffer for returning an interface name that the -+ * driver ended up using if it differs from the requested ifname -+ * @if_addr: Buffer for returning the allocated interface address -+ * (this may differ from the requested addr if the driver cannot -+ * change interface address) -+ * @bridge: Bridge interface to use or %NULL if no bridge configured -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*if_add)(void *priv, enum wpa_driver_if_type type, -+ const char *ifname, const u8 *addr, void *bss_ctx, -+ void **drv_priv, char *force_ifname, u8 *if_addr, -+ const char *bridge); -+ -+ /** -+ * if_remove - Remove a virtual interface -+ * @priv: Private driver interface data -+ * @type: Interface type -+ * @ifname: Interface name of the virtual interface to be removed -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*if_remove)(void *priv, enum wpa_driver_if_type type, -+ const char *ifname); -+ -+ /** -+ * set_sta_vlan - Bind a station into a specific interface (AP only) -+ * @priv: Private driver interface data -+ * @ifname: Interface (main or virtual BSS or VLAN) -+ * @addr: MAC address of the associated station -+ * @vlan_id: VLAN ID -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to bind a station to a specific virtual -+ * interface. It is only used if when virtual interfaces are supported, -+ * e.g., to assign stations to different VLAN interfaces based on -+ * information from a RADIUS server. This allows separate broadcast -+ * domains to be used with a single BSS. -+ */ -+ int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname, -+ int vlan_id); -+ -+ /** -+ * commit - Optional commit changes handler (AP only) -+ * @priv: driver private data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This optional handler function can be registered if the driver -+ * interface implementation needs to commit changes (e.g., by setting -+ * network interface up) at the end of initial configuration. If set, -+ * this handler will be called after initial setup has been completed. -+ */ -+ int (*commit)(void *priv); -+ -+ /** -+ * send_ether - Send an ethernet packet (AP only) -+ * @priv: private driver interface data -+ * @dst: Destination MAC address -+ * @src: Source MAC address -+ * @proto: Ethertype -+ * @data: EAPOL packet starting with IEEE 802.1X header -+ * @data_len: Length of the EAPOL packet in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto, -+ const u8 *data, size_t data_len); -+ -+ /** -+ * set_radius_acl_auth - Notification of RADIUS ACL change -+ * @priv: Private driver interface data -+ * @mac: MAC address of the station -+ * @accepted: Whether the station was accepted -+ * @session_timeout: Session timeout for the station -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, -+ u32 session_timeout); -+ -+ /** -+ * set_radius_acl_expire - Notification of RADIUS ACL expiration -+ * @priv: Private driver interface data -+ * @mac: MAC address of the station -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_radius_acl_expire)(void *priv, const u8 *mac); -+ -+ /** -+ * set_ht_params - Set HT parameters (AP only) -+ * @priv: Private driver interface data -+ * @ht_capab: HT Capabilities IE -+ * @ht_capab_len: Length of ht_capab in octets -+ * @ht_oper: HT Operation IE -+ * @ht_oper_len: Length of ht_oper in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_ht_params)(void *priv, -+ const u8 *ht_capab, size_t ht_capab_len, -+ const u8 *ht_oper, size_t ht_oper_len); -+ -+ /** -+ * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP) -+ * @priv: Private driver interface data -+ * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s) -+ * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove -+ * extra IE(s) -+ * @assocresp: WPS IE(s) for (Re)Association Response frames or %NULL -+ * to remove extra IE(s) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is an optional function to add WPS IE in the kernel driver for -+ * Beacon and Probe Response frames. This can be left undefined (set -+ * to %NULL) if the driver uses the Beacon template from set_beacon() -+ * and does not process Probe Request frames. If the driver takes care -+ * of (Re)Association frame processing, the assocresp buffer includes -+ * WPS IE(s) that need to be added to (Re)Association Response frames -+ * whenever a (Re)Association Request frame indicated use of WPS. -+ * -+ * This will also be used to add P2P IE(s) into Beacon/Probe Response -+ * frames when operating as a GO. The driver is responsible for adding -+ * timing related attributes (e.g., NoA) in addition to the IEs -+ * included here by appending them after these buffers. This call is -+ * also used to provide Probe Response IEs for P2P Listen state -+ * operations for drivers that generate the Probe Response frames -+ * internally. -+ */ -+ int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon, -+ const struct wpabuf *proberesp, -+ const struct wpabuf *assocresp); -+ -+ /** -+ * set_supp_port - Set IEEE 802.1X Supplicant Port status -+ * @priv: Private driver interface data -+ * @authorized: Whether the port is authorized -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_supp_port)(void *priv, int authorized); -+ -+ /** -+ * set_wds_sta - Bind a station into a 4-address WDS (AP only) -+ * @priv: Private driver interface data -+ * @addr: MAC address of the associated station -+ * @aid: Association ID -+ * @val: 1 = bind to 4-address WDS; 0 = unbind -+ * @bridge_ifname: Bridge interface to use for the WDS station or %NULL -+ * to indicate that bridge is not to be used -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val, -+ const char *bridge_ifname); -+ -+ /** -+ * send_action - Transmit an Action frame -+ * @priv: Private driver interface data -+ * @freq: Frequency (in MHz) of the channel -+ * @wait: Time to wait off-channel for a response (in ms), or zero -+ * @dst: Destination MAC address (Address 1) -+ * @src: Source MAC address (Address 2) -+ * @bssid: BSSID (Address 3) -+ * @data: Frame body -+ * @data_len: data length in octets -+ * Returns: 0 on success, -1 on failure -+ * -+ * This command can be used to request the driver to transmit an action -+ * frame to the specified destination. -+ * -+ * If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will -+ * be transmitted on the given channel and the device will wait for a -+ * response on that channel for the given wait time. -+ * -+ * If the flag is not set, the wait time will be ignored. In this case, -+ * if a remain-on-channel duration is in progress, the frame must be -+ * transmitted on that channel; alternatively the frame may be sent on -+ * the current operational channel (if in associated state in station -+ * mode or while operating as an AP.) -+ */ -+ int (*send_action)(void *priv, unsigned int freq, unsigned int wait, -+ const u8 *dst, const u8 *src, const u8 *bssid, -+ const u8 *data, size_t data_len); -+ -+ /** -+ * send_action_cancel_wait - Cancel action frame TX wait -+ * @priv: Private driver interface data -+ * -+ * This command cancels the wait time associated with sending an action -+ * frame. It is only available when %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is -+ * set in the driver flags. -+ */ -+ void (*send_action_cancel_wait)(void *priv); -+ -+ /** -+ * remain_on_channel - Remain awake on a channel -+ * @priv: Private driver interface data -+ * @freq: Frequency (in MHz) of the channel -+ * @duration: Duration in milliseconds -+ * Returns: 0 on success, -1 on failure -+ * -+ * This command is used to request the driver to remain awake on the -+ * specified channel for the specified duration and report received -+ * Action frames with EVENT_RX_ACTION events. Optionally, received -+ * Probe Request frames may also be requested to be reported by calling -+ * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ. -+ * -+ * The driver may not be at the requested channel when this function -+ * returns, i.e., the return code is only indicating whether the -+ * request was accepted. The caller will need to wait until the -+ * EVENT_REMAIN_ON_CHANNEL event indicates that the driver has -+ * completed the channel change. This may take some time due to other -+ * need for the radio and the caller should be prepared to timing out -+ * its wait since there are no guarantees on when this request can be -+ * executed. -+ */ -+ int (*remain_on_channel)(void *priv, unsigned int freq, -+ unsigned int duration); -+ -+ /** -+ * cancel_remain_on_channel - Cancel remain-on-channel operation -+ * @priv: Private driver interface data -+ * -+ * This command can be used to cancel a remain-on-channel operation -+ * before its originally requested duration has passed. This could be -+ * used, e.g., when remain_on_channel() is used to request extra time -+ * to receive a response to an Action frame and the response is -+ * received when there is still unneeded time remaining on the -+ * remain-on-channel operation. -+ */ -+ int (*cancel_remain_on_channel)(void *priv); -+ -+ /** -+ * probe_req_report - Request Probe Request frames to be indicated -+ * @priv: Private driver interface data -+ * @report: Whether to report received Probe Request frames -+ * Returns: 0 on success, -1 on failure (or if not supported) -+ * -+ * This command can be used to request the driver to indicate when -+ * Probe Request frames are received with EVENT_RX_PROBE_REQ events. -+ * Since this operation may require extra resources, e.g., due to less -+ * optimal hardware/firmware RX filtering, many drivers may disable -+ * Probe Request reporting at least in station mode. This command is -+ * used to notify the driver when the Probe Request frames need to be -+ * reported, e.g., during remain-on-channel operations. -+ */ -+ int (*probe_req_report)(void *priv, int report); -+ -+ /** -+ * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX -+ * @priv: Private driver interface data -+ * @disabled: Whether IEEE 802.11b rates are disabled -+ * Returns: 0 on success, -1 on failure (or if not supported) -+ * -+ * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and -+ * 11 Mbps) as TX rates for data and management frames. This can be -+ * used to optimize channel use when there is no need to support IEEE -+ * 802.11b-only devices. -+ */ -+ int (*disable_11b_rates)(void *priv, int disabled); -+ -+ /** -+ * deinit_ap - Deinitialize AP mode -+ * @priv: Private driver interface data -+ * Returns: 0 on success, -1 on failure (or if not supported) -+ * -+ * This optional function can be used to disable AP mode related -+ * configuration and change the driver mode to station mode to allow -+ * normal station operations like scanning to be completed. -+ */ -+ int (*deinit_ap)(void *priv); -+ -+ /** -+ * suspend - Notification on system suspend/hibernate event -+ * @priv: Private driver interface data -+ */ -+ void (*suspend)(void *priv); -+ -+ /** -+ * resume - Notification on system resume/thaw event -+ * @priv: Private driver interface data -+ */ -+ void (*resume)(void *priv); -+ -+ /** -+ * signal_monitor - Set signal monitoring parameters -+ * @priv: Private driver interface data -+ * @threshold: Threshold value for signal change events; 0 = disabled -+ * @hysteresis: Minimum change in signal strength before indicating a -+ * new event -+ * Returns: 0 on success, -1 on failure (or if not supported) -+ * -+ * This function can be used to configure monitoring of signal strength -+ * with the current AP. Whenever signal strength drops below the -+ * %threshold value or increases above it, EVENT_SIGNAL_CHANGE event -+ * should be generated assuming the signal strength has changed at -+ * least %hysteresis from the previously indicated signal change event. -+ */ -+ int (*signal_monitor)(void *priv, int threshold, int hysteresis); -+ -+ /** -+ * send_frame - Send IEEE 802.11 frame (testing use only) -+ * @priv: Private driver interface data -+ * @data: IEEE 802.11 frame with IEEE 802.11 header -+ * @data_len: Size of the frame -+ * @encrypt: Whether to encrypt the frame (if keys are set) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used for debugging purposes and is not -+ * required to be implemented for normal operations. -+ */ -+ int (*send_frame)(void *priv, const u8 *data, size_t data_len, -+ int encrypt); -+ -+ /** -+ * shared_freq - Get operating frequency of shared interface(s) -+ * @priv: Private driver interface data -+ * Returns: Operating frequency in MHz, 0 if no shared operation in -+ * use, or -1 on failure -+ * -+ * This command can be used to request the current operating frequency -+ * of any virtual interface that shares the same radio to provide -+ * information for channel selection for other virtual interfaces. -+ */ -+ int (*shared_freq)(void *priv); -+ -+ /** -+ * get_noa - Get current Notice of Absence attribute payload -+ * @priv: Private driver interface data -+ * @buf: Buffer for returning NoA -+ * @buf_len: Buffer length in octets -+ * Returns: Number of octets used in buf, 0 to indicate no NoA is being -+ * advertized, or -1 on failure -+ * -+ * This function is used to fetch the current Notice of Absence -+ * attribute value from GO. -+ */ -+ int (*get_noa)(void *priv, u8 *buf, size_t buf_len); -+ -+ /** -+ * set_noa - Set Notice of Absence parameters for GO (testing) -+ * @priv: Private driver interface data -+ * @count: Count -+ * @start: Start time in ms from next TBTT -+ * @duration: Duration in ms -+ * Returns: 0 on success or -1 on failure -+ * -+ * This function is used to set Notice of Absence parameters for GO. It -+ * is used only for testing. To disable NoA, all parameters are set to -+ * 0. -+ */ -+ int (*set_noa)(void *priv, u8 count, int start, int duration); -+ -+ /** -+ * set_p2p_powersave - Set P2P power save options -+ * @priv: Private driver interface data -+ * @legacy_ps: 0 = disable, 1 = enable, 2 = maximum PS, -1 = no change -+ * @opp_ps: 0 = disable, 1 = enable, -1 = no change -+ * @ctwindow: 0.. = change (msec), -1 = no change -+ * Returns: 0 on success or -1 on failure -+ */ -+ int (*set_p2p_powersave)(void *priv, int legacy_ps, int opp_ps, -+ int ctwindow); -+ -+ /** -+ * ampdu - Enable/disable aggregation -+ * @priv: Private driver interface data -+ * @ampdu: 1/0 = enable/disable A-MPDU aggregation -+ * Returns: 0 on success or -1 on failure -+ */ -+ int (*ampdu)(void *priv, int ampdu); -+ -+ /** -+ * set_intra_bss - Enables/Disables intra BSS bridging -+ */ -+ int (*set_intra_bss)(void *priv, int enabled); -+ -+ /** -+ * get_radio_name - Get physical radio name for the device -+ * @priv: Private driver interface data -+ * Returns: Radio name or %NULL if not known -+ * -+ * The returned data must not be modified by the caller. It is assumed -+ * that any interface that has the same radio name as another is -+ * sharing the same physical radio. This information can be used to -+ * share scan results etc. information between the virtual interfaces -+ * to speed up various operations. -+ */ -+ const char * (*get_radio_name)(void *priv); -+ -+ /** -+ * p2p_find - Start P2P Device Discovery -+ * @priv: Private driver interface data -+ * @timeout: Timeout for find operation in seconds or 0 for no timeout -+ * @type: Device Discovery type (enum p2p_discovery_type) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_find)(void *priv, unsigned int timeout, int type); -+ -+ /** -+ * p2p_stop_find - Stop P2P Device Discovery -+ * @priv: Private driver interface data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_stop_find)(void *priv); -+ -+ /** -+ * p2p_listen - Start P2P Listen state for specified duration -+ * @priv: Private driver interface data -+ * @timeout: Listen state duration in milliseconds -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to request the P2P module to keep the -+ * device discoverable on the listen channel for an extended set of -+ * time. At least in its current form, this is mainly used for testing -+ * purposes and may not be of much use for normal P2P operations. -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_listen)(void *priv, unsigned int timeout); -+ -+ /** -+ * p2p_connect - Start P2P group formation (GO negotiation) -+ * @priv: Private driver interface data -+ * @peer_addr: MAC address of the peer P2P client -+ * @wps_method: enum p2p_wps_method value indicating config method -+ * @go_intent: Local GO intent value (1..15) -+ * @own_interface_addr: Intended interface address to use with the -+ * group -+ * @force_freq: The only allowed channel frequency in MHz or 0 -+ * @persistent_group: Whether to create persistent group -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method, -+ int go_intent, const u8 *own_interface_addr, -+ unsigned int force_freq, int persistent_group); -+ -+ /** -+ * wps_success_cb - Report successfully completed WPS provisioning -+ * @priv: Private driver interface data -+ * @peer_addr: Peer address -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to report successfully completed WPS -+ * provisioning during group formation in both GO/Registrar and -+ * client/Enrollee roles. -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*wps_success_cb)(void *priv, const u8 *peer_addr); -+ -+ /** -+ * p2p_group_formation_failed - Report failed WPS provisioning -+ * @priv: Private driver interface data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to report failed group formation. This can -+ * happen either due to failed WPS provisioning or due to 15 second -+ * timeout during the provisioning phase. -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_group_formation_failed)(void *priv); -+ -+ /** -+ * p2p_set_params - Set P2P parameters -+ * @priv: Private driver interface data -+ * @params: P2P parameters -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_set_params)(void *priv, const struct p2p_params *params); -+ -+ /** -+ * p2p_prov_disc_req - Send Provision Discovery Request -+ * @priv: Private driver interface data -+ * @peer_addr: MAC address of the peer P2P client -+ * @config_methods: WPS Config Methods value (only one bit set) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to request a discovered P2P peer to -+ * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared -+ * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The -+ * Provision Discovery Request frame is transmitted once immediately -+ * and if no response is received, the frame will be sent again -+ * whenever the target device is discovered during device dsicovery -+ * (start with a p2p_find() call). Response from the peer is indicated -+ * with the EVENT_P2P_PROV_DISC_RESPONSE event. -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr, -+ u16 config_methods); -+ -+ /** -+ * p2p_sd_request - Schedule a service discovery query -+ * @priv: Private driver interface data -+ * @dst: Destination peer or %NULL to apply for all peers -+ * @tlvs: P2P Service Query TLV(s) -+ * Returns: Reference to the query or 0 on failure -+ * -+ * Response to the query is indicated with the -+ * EVENT_P2P_SD_RESPONSE driver event. -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ u64 (*p2p_sd_request)(void *priv, const u8 *dst, -+ const struct wpabuf *tlvs); -+ -+ /** -+ * p2p_sd_cancel_request - Cancel a pending service discovery query -+ * @priv: Private driver interface data -+ * @req: Query reference from p2p_sd_request() -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_sd_cancel_request)(void *priv, u64 req); -+ -+ /** -+ * p2p_sd_response - Send response to a service discovery query -+ * @priv: Private driver interface data -+ * @freq: Frequency from EVENT_P2P_SD_REQUEST event -+ * @dst: Destination address from EVENT_P2P_SD_REQUEST event -+ * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event -+ * @resp_tlvs: P2P Service Response TLV(s) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is called as a response to the request indicated with -+ * the EVENT_P2P_SD_REQUEST driver event. -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_sd_response)(void *priv, int freq, const u8 *dst, -+ u8 dialog_token, -+ const struct wpabuf *resp_tlvs); -+ -+ /** -+ * p2p_service_update - Indicate a change in local services -+ * @priv: Private driver interface data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function needs to be called whenever there is a change in -+ * availability of the local services. This will increment the -+ * Service Update Indicator value which will be used in SD Request and -+ * Response frames. -+ * -+ * This function is only used if the driver implements P2P management, -+ * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in -+ * struct wpa_driver_capa. -+ */ -+ int (*p2p_service_update)(void *priv); -+ -+ /** -+ * p2p_reject - Reject peer device (explicitly block connections) -+ * @priv: Private driver interface data -+ * @addr: MAC address of the peer -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*p2p_reject)(void *priv, const u8 *addr); -+ -+ /** -+ * p2p_invite - Invite a P2P Device into a group -+ * @priv: Private driver interface data -+ * @peer: Device Address of the peer P2P Device -+ * @role: Local role in the group -+ * @bssid: Group BSSID or %NULL if not known -+ * @ssid: Group SSID -+ * @ssid_len: Length of ssid in octets -+ * @go_dev_addr: Forced GO Device Address or %NULL if none -+ * @persistent_group: Whether this is to reinvoke a persistent group -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*p2p_invite)(void *priv, const u8 *peer, int role, -+ const u8 *bssid, const u8 *ssid, size_t ssid_len, -+ const u8 *go_dev_addr, int persistent_group); -+ -+ /** -+ * send_tdls_mgmt - for sending TDLS management packets -+ * @priv: private driver interface data -+ * @dst: Destination (peer) MAC address -+ * @action_code: TDLS action code for the mssage -+ * @dialog_token: Dialog Token to use in the message (if needed) -+ * @status_code: Status Code or Reason Code to use (if needed) -+ * @buf: TDLS IEs to add to the message -+ * @len: Length of buf in octets -+ * Returns: 0 on success, -1 on failure -+ * -+ * This optional function can be used to send packet to driver which is -+ * responsible for receiving and sending all TDLS packets. -+ */ -+ int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code, -+ u8 dialog_token, u16 status_code, -+ const u8 *buf, size_t len); -+ -+ int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer); -+ -+ /** -+ * signal_poll - Get current connection information -+ * @priv: Private driver interface data -+ * @signal_info: Connection info structure -+ */ -+ int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info); -+}; -+ -+ -+/** -+ * enum wpa_event_type - Event type for wpa_supplicant_event() calls -+ */ -+enum wpa_event_type { -+ /** -+ * EVENT_ASSOC - Association completed -+ * -+ * This event needs to be delivered when the driver completes IEEE -+ * 802.11 association or reassociation successfully. -+ * wpa_driver_ops::get_bssid() is expected to provide the current BSSID -+ * after this event has been generated. In addition, optional -+ * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide -+ * more information about the association. If the driver interface gets -+ * both of these events at the same time, it can also include the -+ * assoc_info data in EVENT_ASSOC call. -+ */ -+ EVENT_ASSOC, -+ -+ /** -+ * EVENT_DISASSOC - Association lost -+ * -+ * This event should be called when association is lost either due to -+ * receiving deauthenticate or disassociate frame from the AP or when -+ * sending either of these frames to the current AP. If the driver -+ * supports separate deauthentication event, EVENT_DISASSOC should only -+ * be used for disassociation and EVENT_DEAUTH for deauthentication. -+ * In AP mode, union wpa_event_data::disassoc_info is required. -+ */ -+ EVENT_DISASSOC, -+ -+ /** -+ * EVENT_MICHAEL_MIC_FAILURE - Michael MIC (TKIP) detected -+ * -+ * This event must be delivered when a Michael MIC error is detected by -+ * the local driver. Additional data for event processing is -+ * provided with union wpa_event_data::michael_mic_failure. This -+ * information is used to request new encyption key and to initiate -+ * TKIP countermeasures if needed. -+ */ -+ EVENT_MICHAEL_MIC_FAILURE, -+ -+ /** -+ * EVENT_SCAN_RESULTS - Scan results available -+ * -+ * This event must be called whenever scan results are available to be -+ * fetched with struct wpa_driver_ops::get_scan_results(). This event -+ * is expected to be used some time after struct wpa_driver_ops::scan() -+ * is called. If the driver provides an unsolicited event when the scan -+ * has been completed, this event can be used to trigger -+ * EVENT_SCAN_RESULTS call. If such event is not available from the -+ * driver, the driver wrapper code is expected to use a registered -+ * timeout to generate EVENT_SCAN_RESULTS call after the time that the -+ * scan is expected to be completed. Optional information about -+ * completed scan can be provided with union wpa_event_data::scan_info. -+ */ -+ EVENT_SCAN_RESULTS, -+ -+ /** -+ * EVENT_ASSOCINFO - Report optional extra information for association -+ * -+ * This event can be used to report extra association information for -+ * EVENT_ASSOC processing. This extra information includes IEs from -+ * association frames and Beacon/Probe Response frames in union -+ * wpa_event_data::assoc_info. EVENT_ASSOCINFO must be send just before -+ * EVENT_ASSOC. Alternatively, the driver interface can include -+ * assoc_info data in the EVENT_ASSOC call if it has all the -+ * information available at the same point. -+ */ -+ EVENT_ASSOCINFO, -+ -+ /** -+ * EVENT_INTERFACE_STATUS - Report interface status changes -+ * -+ * This optional event can be used to report changes in interface -+ * status (interface added/removed) using union -+ * wpa_event_data::interface_status. This can be used to trigger -+ * wpa_supplicant to stop and re-start processing for the interface, -+ * e.g., when a cardbus card is ejected/inserted. -+ */ -+ EVENT_INTERFACE_STATUS, -+ -+ /** -+ * EVENT_PMKID_CANDIDATE - Report a candidate AP for pre-authentication -+ * -+ * This event can be used to inform wpa_supplicant about candidates for -+ * RSN (WPA2) pre-authentication. If wpa_supplicant is not responsible -+ * for scan request (ap_scan=2 mode), this event is required for -+ * pre-authentication. If wpa_supplicant is performing scan request -+ * (ap_scan=1), this event is optional since scan results can be used -+ * to add pre-authentication candidates. union -+ * wpa_event_data::pmkid_candidate is used to report the BSSID of the -+ * candidate and priority of the candidate, e.g., based on the signal -+ * strength, in order to try to pre-authenticate first with candidates -+ * that are most likely targets for re-association. -+ * -+ * EVENT_PMKID_CANDIDATE can be called whenever the driver has updates -+ * on the candidate list. In addition, it can be called for the current -+ * AP and APs that have existing PMKSA cache entries. wpa_supplicant -+ * will automatically skip pre-authentication in cases where a valid -+ * PMKSA exists. When more than one candidate exists, this event should -+ * be generated once for each candidate. -+ * -+ * Driver will be notified about successful pre-authentication with -+ * struct wpa_driver_ops::add_pmkid() calls. -+ */ -+ EVENT_PMKID_CANDIDATE, -+ -+ /** -+ * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request) -+ * -+ * This event can be used to inform wpa_supplicant about desire to set -+ * up secure direct link connection between two stations as defined in -+ * IEEE 802.11e with a new PeerKey mechanism that replaced the original -+ * STAKey negotiation. The caller will need to set peer address for the -+ * event. -+ */ -+ EVENT_STKSTART, -+ -+ /** -+ * EVENT_TDLS - Request TDLS operation -+ * -+ * This event can be used to request a TDLS operation to be performed. -+ */ -+ EVENT_TDLS, -+ -+ /** -+ * EVENT_FT_RESPONSE - Report FT (IEEE 802.11r) response IEs -+ * -+ * The driver is expected to report the received FT IEs from -+ * FT authentication sequence from the AP. The FT IEs are included in -+ * the extra information in union wpa_event_data::ft_ies. -+ */ -+ EVENT_FT_RESPONSE, -+ -+ /** -+ * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS -+ * -+ * The driver can use this event to inform wpa_supplicant about a STA -+ * in an IBSS with which protected frames could be exchanged. This -+ * event starts RSN authentication with the other STA to authenticate -+ * the STA and set up encryption keys with it. -+ */ -+ EVENT_IBSS_RSN_START, -+ -+ /** -+ * EVENT_AUTH - Authentication result -+ * -+ * This event should be called when authentication attempt has been -+ * completed. This is only used if the driver supports separate -+ * authentication step (struct wpa_driver_ops::authenticate). -+ * Information about authentication result is included in -+ * union wpa_event_data::auth. -+ */ -+ EVENT_AUTH, -+ -+ /** -+ * EVENT_DEAUTH - Authentication lost -+ * -+ * This event should be called when authentication is lost either due -+ * to receiving deauthenticate frame from the AP or when sending that -+ * frame to the current AP. -+ * In AP mode, union wpa_event_data::deauth_info is required. -+ */ -+ EVENT_DEAUTH, -+ -+ /** -+ * EVENT_ASSOC_REJECT - Association rejected -+ * -+ * This event should be called when (re)association attempt has been -+ * rejected by the AP. Information about the association response is -+ * included in union wpa_event_data::assoc_reject. -+ */ -+ EVENT_ASSOC_REJECT, -+ -+ /** -+ * EVENT_AUTH_TIMED_OUT - Authentication timed out -+ */ -+ EVENT_AUTH_TIMED_OUT, -+ -+ /** -+ * EVENT_ASSOC_TIMED_OUT - Association timed out -+ */ -+ EVENT_ASSOC_TIMED_OUT, -+ -+ /** -+ * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received -+ */ -+ EVENT_FT_RRB_RX, -+ -+ /** -+ * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS -+ */ -+ EVENT_WPS_BUTTON_PUSHED, -+ -+ /** -+ * EVENT_TX_STATUS - Report TX status -+ */ -+ EVENT_TX_STATUS, -+ -+ /** -+ * EVENT_RX_FROM_UNKNOWN - Report RX from unknown STA -+ */ -+ EVENT_RX_FROM_UNKNOWN, -+ -+ /** -+ * EVENT_RX_MGMT - Report RX of a management frame -+ */ -+ EVENT_RX_MGMT, -+ -+ /** -+ * EVENT_RX_ACTION - Action frame received -+ * -+ * This event is used to indicate when an Action frame has been -+ * received. Information about the received frame is included in -+ * union wpa_event_data::rx_action. -+ */ -+ EVENT_RX_ACTION, -+ -+ /** -+ * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started -+ * -+ * This event is used to indicate when the driver has started the -+ * requested remain-on-channel duration. Information about the -+ * operation is included in union wpa_event_data::remain_on_channel. -+ */ -+ EVENT_REMAIN_ON_CHANNEL, -+ -+ /** -+ * EVENT_CANCEL_REMAIN_ON_CHANNEL - Remain-on-channel timed out -+ * -+ * This event is used to indicate when the driver has completed -+ * remain-on-channel duration, i.e., may noot be available on the -+ * requested channel anymore. Information about the -+ * operation is included in union wpa_event_data::remain_on_channel. -+ */ -+ EVENT_CANCEL_REMAIN_ON_CHANNEL, -+ -+ /** -+ * EVENT_MLME_RX - Report reception of frame for MLME (test use only) -+ * -+ * This event is used only by driver_test.c and userspace MLME. -+ */ -+ EVENT_MLME_RX, -+ -+ /** -+ * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame -+ * -+ * This event is used to indicate when a Probe Request frame has been -+ * received. Information about the received frame is included in -+ * union wpa_event_data::rx_probe_req. The driver is required to report -+ * these events only after successfully completed probe_req_report() -+ * commands to request the events (i.e., report parameter is non-zero) -+ * in station mode. In AP mode, Probe Request frames should always be -+ * reported. -+ */ -+ EVENT_RX_PROBE_REQ, -+ -+ /** -+ * EVENT_NEW_STA - New wired device noticed -+ * -+ * This event is used to indicate that a new device has been detected -+ * in a network that does not use association-like functionality (i.e., -+ * mainly wired Ethernet). This can be used to start EAPOL -+ * authenticator when receiving a frame from a device. The address of -+ * the device is included in union wpa_event_data::new_sta. -+ */ -+ EVENT_NEW_STA, -+ -+ /** -+ * EVENT_EAPOL_RX - Report received EAPOL frame -+ * -+ * When in AP mode with hostapd, this event is required to be used to -+ * deliver the receive EAPOL frames from the driver. With -+ * %wpa_supplicant, this event is used only if the send_eapol() handler -+ * is used to override the use of l2_packet for EAPOL frame TX. -+ */ -+ EVENT_EAPOL_RX, -+ -+ /** -+ * EVENT_SIGNAL_CHANGE - Indicate change in signal strength -+ * -+ * This event is used to indicate changes in the signal strength -+ * observed in frames received from the current AP if signal strength -+ * monitoring has been enabled with signal_monitor(). -+ */ -+ EVENT_SIGNAL_CHANGE, -+ -+ /** -+ * EVENT_INTERFACE_ENABLED - Notify that interface was enabled -+ * -+ * This event is used to indicate that the interface was enabled after -+ * having been previously disabled, e.g., due to rfkill. -+ */ -+ EVENT_INTERFACE_ENABLED, -+ -+ /** -+ * EVENT_INTERFACE_DISABLED - Notify that interface was disabled -+ * -+ * This event is used to indicate that the interface was disabled, -+ * e.g., due to rfkill. -+ */ -+ EVENT_INTERFACE_DISABLED, -+ -+ /** -+ * EVENT_CHANNEL_LIST_CHANGED - Channel list changed -+ * -+ * This event is used to indicate that the channel list has changed, -+ * e.g., because of a regulatory domain change triggered by scan -+ * results including an AP advertising a country code. -+ */ -+ EVENT_CHANNEL_LIST_CHANGED, -+ -+ /** -+ * EVENT_INTERFACE_UNAVAILABLE - Notify that interface is unavailable -+ * -+ * This event is used to indicate that the driver cannot maintain this -+ * interface in its operation mode anymore. The most likely use for -+ * this is to indicate that AP mode operation is not available due to -+ * operating channel would need to be changed to a DFS channel when -+ * the driver does not support radar detection and another virtual -+ * interfaces caused the operating channel to change. Other similar -+ * resource conflicts could also trigger this for station mode -+ * interfaces. -+ */ -+ EVENT_INTERFACE_UNAVAILABLE, -+ -+ /** -+ * EVENT_BEST_CHANNEL -+ * -+ * Driver generates this event whenever it detects a better channel -+ * (e.g., based on RSSI or channel use). This information can be used -+ * to improve channel selection for a new AP/P2P group. -+ */ -+ EVENT_BEST_CHANNEL, -+ -+ /** -+ * EVENT_UNPROT_DEAUTH - Unprotected Deauthentication frame received -+ * -+ * This event should be called when a Deauthentication frame is dropped -+ * due to it not being protected (MFP/IEEE 802.11w). -+ * union wpa_event_data::unprot_deauth is required to provide more -+ * details of the frame. -+ */ -+ EVENT_UNPROT_DEAUTH, -+ -+ /** -+ * EVENT_UNPROT_DISASSOC - Unprotected Disassociation frame received -+ * -+ * This event should be called when a Disassociation frame is dropped -+ * due to it not being protected (MFP/IEEE 802.11w). -+ * union wpa_event_data::unprot_disassoc is required to provide more -+ * details of the frame. -+ */ -+ EVENT_UNPROT_DISASSOC, -+ -+ /** -+ * EVENT_STATION_LOW_ACK -+ * -+ * Driver generates this event whenever it detected that a particular -+ * station was lost. Detection can be through massive transmission -+ * failures for example. -+ */ -+ EVENT_STATION_LOW_ACK, -+ -+ /** -+ * EVENT_P2P_DEV_FOUND - Report a discovered P2P device -+ * -+ * This event is used only if the driver implements P2P management -+ * internally. Event data is stored in -+ * union wpa_event_data::p2p_dev_found. -+ */ -+ EVENT_P2P_DEV_FOUND, -+ -+ /** -+ * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request -+ * -+ * This event is used only if the driver implements P2P management -+ * internally. Event data is stored in -+ * union wpa_event_data::p2p_go_neg_req_rx. -+ */ -+ EVENT_P2P_GO_NEG_REQ_RX, -+ -+ /** -+ * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation -+ * -+ * This event is used only if the driver implements P2P management -+ * internally. Event data is stored in -+ * union wpa_event_data::p2p_go_neg_completed. -+ */ -+ EVENT_P2P_GO_NEG_COMPLETED, -+ -+ EVENT_P2P_PROV_DISC_REQUEST, -+ EVENT_P2P_PROV_DISC_RESPONSE, -+ EVENT_P2P_SD_REQUEST, -+ EVENT_P2P_SD_RESPONSE, -+ -+ /** -+ * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore -+ */ -+ EVENT_IBSS_PEER_LOST -+}; -+ -+ -+/** -+ * union wpa_event_data - Additional data for wpa_supplicant_event() calls -+ */ -+union wpa_event_data { -+ /** -+ * struct assoc_info - Data for EVENT_ASSOC and EVENT_ASSOCINFO events -+ * -+ * This structure is optional for EVENT_ASSOC calls and required for -+ * EVENT_ASSOCINFO calls. By using EVENT_ASSOC with this data, the -+ * driver interface does not need to generate separate EVENT_ASSOCINFO -+ * calls. -+ */ -+ struct assoc_info { -+ /** -+ * reassoc - Flag to indicate association or reassociation -+ */ -+ int reassoc; -+ -+ /** -+ * req_ies - (Re)Association Request IEs -+ * -+ * If the driver generates WPA/RSN IE, this event data must be -+ * returned for WPA handshake to have needed information. If -+ * wpa_supplicant-generated WPA/RSN IE is used, this -+ * information event is optional. -+ * -+ * This should start with the first IE (fixed fields before IEs -+ * are not included). -+ */ -+ const u8 *req_ies; -+ -+ /** -+ * req_ies_len - Length of req_ies in bytes -+ */ -+ size_t req_ies_len; -+ -+ /** -+ * resp_ies - (Re)Association Response IEs -+ * -+ * Optional association data from the driver. This data is not -+ * required WPA, but may be useful for some protocols and as -+ * such, should be reported if this is available to the driver -+ * interface. -+ * -+ * This should start with the first IE (fixed fields before IEs -+ * are not included). -+ */ -+ const u8 *resp_ies; -+ -+ /** -+ * resp_ies_len - Length of resp_ies in bytes -+ */ -+ size_t resp_ies_len; -+ -+ /** -+ * beacon_ies - Beacon or Probe Response IEs -+ * -+ * Optional Beacon/ProbeResp data: IEs included in Beacon or -+ * Probe Response frames from the current AP (i.e., the one -+ * that the client just associated with). This information is -+ * used to update WPA/RSN IE for the AP. If this field is not -+ * set, the results from previous scan will be used. If no -+ * data for the new AP is found, scan results will be requested -+ * again (without scan request). At this point, the driver is -+ * expected to provide WPA/RSN IE for the AP (if WPA/WPA2 is -+ * used). -+ * -+ * This should start with the first IE (fixed fields before IEs -+ * are not included). -+ */ -+ const u8 *beacon_ies; -+ -+ /** -+ * beacon_ies_len - Length of beacon_ies */ -+ size_t beacon_ies_len; -+ -+ /** -+ * freq - Frequency of the operational channel in MHz -+ */ -+ unsigned int freq; -+ -+ /** -+ * addr - Station address (for AP mode) -+ */ -+ const u8 *addr; -+ } assoc_info; -+ -+ /** -+ * struct disassoc_info - Data for EVENT_DISASSOC events -+ */ -+ struct disassoc_info { -+ /** -+ * addr - Station address (for AP mode) -+ */ -+ const u8 *addr; -+ -+ /** -+ * reason_code - Reason Code (host byte order) used in -+ * Deauthentication frame -+ */ -+ u16 reason_code; -+ -+ /** -+ * ie - Optional IE(s) in Disassociation frame -+ */ -+ const u8 *ie; -+ -+ /** -+ * ie_len - Length of ie buffer in octets -+ */ -+ size_t ie_len; -+ } disassoc_info; -+ -+ /** -+ * struct deauth_info - Data for EVENT_DEAUTH events -+ */ -+ struct deauth_info { -+ /** -+ * addr - Station address (for AP mode) -+ */ -+ const u8 *addr; -+ -+ /** -+ * reason_code - Reason Code (host byte order) used in -+ * Deauthentication frame -+ */ -+ u16 reason_code; -+ -+ /** -+ * ie - Optional IE(s) in Deauthentication frame -+ */ -+ const u8 *ie; -+ -+ /** -+ * ie_len - Length of ie buffer in octets -+ */ -+ size_t ie_len; -+ } deauth_info; -+ -+ /** -+ * struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE -+ */ -+ struct michael_mic_failure { -+ int unicast; -+ const u8 *src; -+ } michael_mic_failure; -+ -+ /** -+ * struct interface_status - Data for EVENT_INTERFACE_STATUS -+ */ -+ struct interface_status { -+ char ifname[100]; -+ enum { -+ EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED -+ } ievent; -+ } interface_status; -+ -+ /** -+ * struct pmkid_candidate - Data for EVENT_PMKID_CANDIDATE -+ */ -+ struct pmkid_candidate { -+ /** BSSID of the PMKID candidate */ -+ u8 bssid[ETH_ALEN]; -+ /** Smaller the index, higher the priority */ -+ int index; -+ /** Whether RSN IE includes pre-authenticate flag */ -+ int preauth; -+ } pmkid_candidate; -+ -+ /** -+ * struct stkstart - Data for EVENT_STKSTART -+ */ -+ struct stkstart { -+ u8 peer[ETH_ALEN]; -+ } stkstart; -+ -+ /** -+ * struct tdls - Data for EVENT_TDLS -+ */ -+ struct tdls { -+ u8 peer[ETH_ALEN]; -+ enum { -+ TDLS_REQUEST_SETUP, -+ TDLS_REQUEST_TEARDOWN -+ } oper; -+ u16 reason_code; /* for teardown */ -+ } tdls; -+ -+ /** -+ * struct ft_ies - FT information elements (EVENT_FT_RESPONSE) -+ * -+ * During FT (IEEE 802.11r) authentication sequence, the driver is -+ * expected to use this event to report received FT IEs (MDIE, FTIE, -+ * RSN IE, TIE, possible resource request) to the supplicant. The FT -+ * IEs for the next message will be delivered through the -+ * struct wpa_driver_ops::update_ft_ies() callback. -+ */ -+ struct ft_ies { -+ const u8 *ies; -+ size_t ies_len; -+ int ft_action; -+ u8 target_ap[ETH_ALEN]; -+ /** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */ -+ const u8 *ric_ies; -+ /** Length of ric_ies buffer in octets */ -+ size_t ric_ies_len; -+ } ft_ies; -+ -+ /** -+ * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START -+ */ -+ struct ibss_rsn_start { -+ u8 peer[ETH_ALEN]; -+ } ibss_rsn_start; -+ -+ /** -+ * struct auth_info - Data for EVENT_AUTH events -+ */ -+ struct auth_info { -+ u8 peer[ETH_ALEN]; -+ u16 auth_type; -+ u16 status_code; -+ const u8 *ies; -+ size_t ies_len; -+ } auth; -+ -+ /** -+ * struct assoc_reject - Data for EVENT_ASSOC_REJECT events -+ */ -+ struct assoc_reject { -+ /** -+ * bssid - BSSID of the AP that rejected association -+ */ -+ const u8 *bssid; -+ -+ /** -+ * resp_ies - (Re)Association Response IEs -+ * -+ * Optional association data from the driver. This data is not -+ * required WPA, but may be useful for some protocols and as -+ * such, should be reported if this is available to the driver -+ * interface. -+ * -+ * This should start with the first IE (fixed fields before IEs -+ * are not included). -+ */ -+ const u8 *resp_ies; -+ -+ /** -+ * resp_ies_len - Length of resp_ies in bytes -+ */ -+ size_t resp_ies_len; -+ -+ /** -+ * status_code - Status Code from (Re)association Response -+ */ -+ u16 status_code; -+ } assoc_reject; -+ -+ struct timeout_event { -+ u8 addr[ETH_ALEN]; -+ } timeout_event; -+ -+ /** -+ * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events -+ */ -+ struct ft_rrb_rx { -+ const u8 *src; -+ const u8 *data; -+ size_t data_len; -+ } ft_rrb_rx; -+ -+ /** -+ * struct tx_status - Data for EVENT_TX_STATUS events -+ */ -+ struct tx_status { -+ u16 type; -+ u16 stype; -+ const u8 *dst; -+ const u8 *data; -+ size_t data_len; -+ int ack; -+ } tx_status; -+ -+ /** -+ * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events -+ */ -+ struct rx_from_unknown { -+ const u8 *frame; -+ size_t len; -+ } rx_from_unknown; -+ -+ /** -+ * struct rx_mgmt - Data for EVENT_RX_MGMT events -+ */ -+ struct rx_mgmt { -+ const u8 *frame; -+ size_t frame_len; -+ u32 datarate; -+ u32 ssi_signal; -+ } rx_mgmt; -+ -+ /** -+ * struct rx_action - Data for EVENT_RX_ACTION events -+ */ -+ struct rx_action { -+ /** -+ * da - Destination address of the received Action frame -+ */ -+ const u8 *da; -+ -+ /** -+ * sa - Source address of the received Action frame -+ */ -+ const u8 *sa; -+ -+ /** -+ * bssid - Address 3 of the received Action frame -+ */ -+ const u8 *bssid; -+ -+ /** -+ * category - Action frame category -+ */ -+ u8 category; -+ -+ /** -+ * data - Action frame body after category field -+ */ -+ const u8 *data; -+ -+ /** -+ * len - Length of data in octets -+ */ -+ size_t len; -+ -+ /** -+ * freq - Frequency (in MHz) on which the frame was received -+ */ -+ int freq; -+ } rx_action; -+ -+ /** -+ * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events -+ * -+ * This is also used with EVENT_CANCEL_REMAIN_ON_CHANNEL events. -+ */ -+ struct remain_on_channel { -+ /** -+ * freq - Channel frequency in MHz -+ */ -+ unsigned int freq; -+ -+ /** -+ * duration - Duration to remain on the channel in milliseconds -+ */ -+ unsigned int duration; -+ } remain_on_channel; -+ -+ /** -+ * struct scan_info - Optional data for EVENT_SCAN_RESULTS events -+ * @aborted: Whether the scan was aborted -+ * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned) -+ * @num_freqs: Number of entries in freqs array -+ * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard -+ * SSID) -+ * @num_ssids: Number of entries in ssids array -+ */ -+ struct scan_info { -+ int aborted; -+ const int *freqs; -+ size_t num_freqs; -+ struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS]; -+ size_t num_ssids; -+ } scan_info; -+ -+ /** -+ * struct mlme_rx - Data for EVENT_MLME_RX events -+ */ -+ struct mlme_rx { -+ const u8 *buf; -+ size_t len; -+ int freq; -+ int channel; -+ int ssi; -+ } mlme_rx; -+ -+ /** -+ * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events -+ */ -+ struct rx_probe_req { -+ /** -+ * sa - Source address of the received Probe Request frame -+ */ -+ const u8 *sa; -+ -+ /** -+ * ie - IEs from the Probe Request body -+ */ -+ const u8 *ie; -+ -+ /** -+ * ie_len - Length of ie buffer in octets -+ */ -+ size_t ie_len; -+ } rx_probe_req; -+ -+ /** -+ * struct new_sta - Data for EVENT_NEW_STA events -+ */ -+ struct new_sta { -+ const u8 *addr; -+ } new_sta; -+ -+ /** -+ * struct eapol_rx - Data for EVENT_EAPOL_RX events -+ */ -+ struct eapol_rx { -+ const u8 *src; -+ const u8 *data; -+ size_t data_len; -+ } eapol_rx; -+ -+ /** -+ * signal_change - Data for EVENT_SIGNAL_CHANGE events -+ */ -+ struct wpa_signal_info signal_change; -+ -+ /** -+ * struct best_channel - Data for EVENT_BEST_CHANNEL events -+ * @freq_24: Best 2.4 GHz band channel frequency in MHz -+ * @freq_5: Best 5 GHz band channel frequency in MHz -+ * @freq_overall: Best channel frequency in MHz -+ * -+ * 0 can be used to indicate no preference in either band. -+ */ -+ struct best_channel { -+ int freq_24; -+ int freq_5; -+ int freq_overall; -+ } best_chan; -+ -+ struct unprot_deauth { -+ const u8 *sa; -+ const u8 *da; -+ u16 reason_code; -+ } unprot_deauth; -+ -+ struct unprot_disassoc { -+ const u8 *sa; -+ const u8 *da; -+ u16 reason_code; -+ } unprot_disassoc; -+ -+ /** -+ * struct low_ack - Data for EVENT_STATION_LOW_ACK events -+ * @addr: station address -+ */ -+ struct low_ack { -+ u8 addr[ETH_ALEN]; -+ } low_ack; -+ -+ /** -+ * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND -+ */ -+ struct p2p_dev_found { -+ const u8 *addr; -+ const u8 *dev_addr; -+ const u8 *pri_dev_type; -+ const char *dev_name; -+ u16 config_methods; -+ u8 dev_capab; -+ u8 group_capab; -+ } p2p_dev_found; -+ -+ /** -+ * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX -+ */ -+ struct p2p_go_neg_req_rx { -+ const u8 *src; -+ u16 dev_passwd_id; -+ } p2p_go_neg_req_rx; -+ -+ /** -+ * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED -+ */ -+ struct p2p_go_neg_completed { -+ struct p2p_go_neg_results *res; -+ } p2p_go_neg_completed; -+ -+ struct p2p_prov_disc_req { -+ const u8 *peer; -+ u16 config_methods; -+ const u8 *dev_addr; -+ const u8 *pri_dev_type; -+ const char *dev_name; -+ u16 supp_config_methods; -+ u8 dev_capab; -+ u8 group_capab; -+ } p2p_prov_disc_req; -+ -+ struct p2p_prov_disc_resp { -+ const u8 *peer; -+ u16 config_methods; -+ } p2p_prov_disc_resp; -+ -+ struct p2p_sd_req { -+ int freq; -+ const u8 *sa; -+ u8 dialog_token; -+ u16 update_indic; -+ const u8 *tlvs; -+ size_t tlvs_len; -+ } p2p_sd_req; -+ -+ struct p2p_sd_resp { -+ const u8 *sa; -+ u16 update_indic; -+ const u8 *tlvs; -+ size_t tlvs_len; -+ } p2p_sd_resp; -+ -+ /** -+ * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST -+ */ -+ struct ibss_peer_lost { -+ u8 peer[ETH_ALEN]; -+ } ibss_peer_lost; -+}; -+ -+/** -+ * wpa_supplicant_event - Report a driver event for wpa_supplicant -+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered -+ * with struct wpa_driver_ops::init() -+ * @event: event type (defined above) -+ * @data: possible extra data for the event -+ * -+ * Driver wrapper code should call this function whenever an event is received -+ * from the driver. -+ */ -+void wpa_supplicant_event(void *ctx, enum wpa_event_type event, -+ union wpa_event_data *data); -+ -+ -+/* -+ * The following inline functions are provided for convenience to simplify -+ * event indication for some of the common events. -+ */ -+ -+static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie, -+ size_t ielen, int reassoc) -+{ -+ union wpa_event_data event; -+ os_memset(&event, 0, sizeof(event)); -+ event.assoc_info.reassoc = reassoc; -+ event.assoc_info.req_ies = ie; -+ event.assoc_info.req_ies_len = ielen; -+ event.assoc_info.addr = addr; -+ wpa_supplicant_event(ctx, EVENT_ASSOC, &event); -+} -+ -+static inline void drv_event_disassoc(void *ctx, const u8 *addr) -+{ -+ union wpa_event_data event; -+ os_memset(&event, 0, sizeof(event)); -+ event.disassoc_info.addr = addr; -+ wpa_supplicant_event(ctx, EVENT_DISASSOC, &event); -+} -+ -+static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data, -+ size_t data_len) -+{ -+ union wpa_event_data event; -+ os_memset(&event, 0, sizeof(event)); -+ event.eapol_rx.src = src; -+ event.eapol_rx.data = data; -+ event.eapol_rx.data_len = data_len; -+ wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event); -+} -+ -+#endif /* DRIVER_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_atheros.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_atheros.c -new file mode 100644 -index 0000000000000..6ac1cea686224 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_atheros.c -@@ -0,0 +1,1381 @@ -+/* -+ * hostapd / Driver interaction with Atheros driver -+ * Copyright (c) 2004, Sam Leffler -+ * Copyright (c) 2004, Video54 Technologies -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * Copyright (c) 2009, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+ -+#include "common.h" -+#ifndef _BYTE_ORDER -+#ifdef WORDS_BIGENDIAN -+#define _BYTE_ORDER _BIG_ENDIAN -+#else -+#define _BYTE_ORDER _LITTLE_ENDIAN -+#endif -+#endif /* _BYTE_ORDER */ -+ -+/* -+ * Note, the ATH_WPS_IE setting must match with the driver build.. If the -+ * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail. -+ */ -+#define ATH_WPS_IE -+ -+#include "os/linux/include/ieee80211_external.h" -+ -+ -+#ifdef CONFIG_WPS -+#include -+ -+#ifndef ETH_P_80211_RAW -+#define ETH_P_80211_RAW 0x0019 -+#endif -+#endif /* CONFIG_WPS */ -+ -+#include "wireless_copy.h" -+ -+#include "driver.h" -+#include "eloop.h" -+#include "priv_netlink.h" -+#include "l2_packet/l2_packet.h" -+#include "common/ieee802_11_defs.h" -+#include "netlink.h" -+#include "linux_ioctl.h" -+ -+ -+struct atheros_driver_data { -+ struct hostapd_data *hapd; /* back pointer */ -+ -+ char iface[IFNAMSIZ + 1]; -+ int ifindex; -+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ -+ struct l2_packet_data *sock_recv; /* raw packet recv socket */ -+ int ioctl_sock; /* socket for ioctl() use */ -+ struct netlink_data *netlink; -+ int we_version; -+ u8 acct_mac[ETH_ALEN]; -+ struct hostap_sta_driver_data acct_data; -+ -+ struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ -+ struct wpabuf *wpa_ie; -+ struct wpabuf *wps_beacon_ie; -+ struct wpabuf *wps_probe_resp_ie; -+}; -+ -+static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code); -+static int atheros_set_privacy(void *priv, int enabled); -+ -+static const char * athr_get_ioctl_name(int op) -+{ -+ switch (op) { -+ case IEEE80211_IOCTL_SETPARAM: -+ return "SETPARAM"; -+ case IEEE80211_IOCTL_GETPARAM: -+ return "GETPARAM"; -+ case IEEE80211_IOCTL_SETKEY: -+ return "SETKEY"; -+ case IEEE80211_IOCTL_SETWMMPARAMS: -+ return "SETWMMPARAMS"; -+ case IEEE80211_IOCTL_DELKEY: -+ return "DELKEY"; -+ case IEEE80211_IOCTL_GETWMMPARAMS: -+ return "GETWMMPARAMS"; -+ case IEEE80211_IOCTL_SETMLME: -+ return "SETMLME"; -+ case IEEE80211_IOCTL_GETCHANINFO: -+ return "GETCHANINFO"; -+ case IEEE80211_IOCTL_SETOPTIE: -+ return "SETOPTIE"; -+ case IEEE80211_IOCTL_GETOPTIE: -+ return "GETOPTIE"; -+ case IEEE80211_IOCTL_ADDMAC: -+ return "ADDMAC"; -+ case IEEE80211_IOCTL_DELMAC: -+ return "DELMAC"; -+ case IEEE80211_IOCTL_GETCHANLIST: -+ return "GETCHANLIST"; -+ case IEEE80211_IOCTL_SETCHANLIST: -+ return "SETCHANLIST"; -+ case IEEE80211_IOCTL_KICKMAC: -+ return "KICKMAC"; -+ case IEEE80211_IOCTL_CHANSWITCH: -+ return "CHANSWITCH"; -+ case IEEE80211_IOCTL_GETMODE: -+ return "GETMODE"; -+ case IEEE80211_IOCTL_SETMODE: -+ return "SETMODE"; -+ case IEEE80211_IOCTL_GET_APPIEBUF: -+ return "GET_APPIEBUF"; -+ case IEEE80211_IOCTL_SET_APPIEBUF: -+ return "SET_APPIEBUF"; -+ case IEEE80211_IOCTL_SET_ACPARAMS: -+ return "SET_ACPARAMS"; -+ case IEEE80211_IOCTL_FILTERFRAME: -+ return "FILTERFRAME"; -+ case IEEE80211_IOCTL_SET_RTPARAMS: -+ return "SET_RTPARAMS"; -+ case IEEE80211_IOCTL_SET_MEDENYENTRY: -+ return "SET_MEDENYENTRY"; -+ case IEEE80211_IOCTL_GET_MACADDR: -+ return "GET_MACADDR"; -+ case IEEE80211_IOCTL_SET_HBRPARAMS: -+ return "SET_HBRPARAMS"; -+ case IEEE80211_IOCTL_SET_RXTIMEOUT: -+ return "SET_RXTIMEOUT"; -+ case IEEE80211_IOCTL_STA_STATS: -+ return "STA_STATS"; -+ case IEEE80211_IOCTL_GETWPAIE: -+ return "GETWPAIE"; -+ default: -+ return "??"; -+ } -+} -+ -+ -+static const char * athr_get_param_name(int op) -+{ -+ switch (op) { -+ case IEEE80211_IOC_MCASTCIPHER: -+ return "MCASTCIPHER"; -+ case IEEE80211_PARAM_MCASTKEYLEN: -+ return "MCASTKEYLEN"; -+ case IEEE80211_PARAM_UCASTCIPHERS: -+ return "UCASTCIPHERS"; -+ case IEEE80211_PARAM_KEYMGTALGS: -+ return "KEYMGTALGS"; -+ case IEEE80211_PARAM_RSNCAPS: -+ return "RSNCAPS"; -+ case IEEE80211_PARAM_WPA: -+ return "WPA"; -+ case IEEE80211_PARAM_AUTHMODE: -+ return "AUTHMODE"; -+ case IEEE80211_PARAM_PRIVACY: -+ return "PRIVACY"; -+ case IEEE80211_PARAM_COUNTERMEASURES: -+ return "COUNTERMEASURES"; -+ default: -+ return "??"; -+ } -+} -+ -+ -+static int -+set80211priv(struct atheros_driver_data *drv, int op, void *data, int len) -+{ -+ struct iwreq iwr; -+ int do_inline = len < IFNAMSIZ; -+ -+ /* Certain ioctls must use the non-inlined method */ -+ if (op == IEEE80211_IOCTL_SET_APPIEBUF || -+ op == IEEE80211_IOCTL_FILTERFRAME) -+ do_inline = 0; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ if (do_inline) { -+ /* -+ * Argument data fits inline; put it there. -+ */ -+ memcpy(iwr.u.name, data, len); -+ } else { -+ /* -+ * Argument data too big for inline transfer; setup a -+ * parameter block instead; the kernel will transfer -+ * the data for the driver. -+ */ -+ iwr.u.data.pointer = data; -+ iwr.u.data.length = len; -+ } -+ -+ if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { -+ wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x " -+ "(%s) len=%d failed: %d (%s)", -+ __func__, drv->iface, op, -+ athr_get_ioctl_name(op), -+ len, errno, strerror(errno)); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+set80211param(struct atheros_driver_data *drv, int op, int arg) -+{ -+ struct iwreq iwr; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.mode = op; -+ memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); -+ -+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { -+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); -+ wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d " -+ "(%s) arg %d)", __func__, drv->iface, op, -+ athr_get_param_name(op), arg); -+ return -1; -+ } -+ return 0; -+} -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+static const char * -+ether_sprintf(const u8 *addr) -+{ -+ static char buf[sizeof(MACSTR)]; -+ -+ if (addr != NULL) -+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); -+ else -+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); -+ return buf; -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+/* -+ * Configure WPA parameters. -+ */ -+static int -+atheros_configure_wpa(struct atheros_driver_data *drv, -+ struct wpa_bss_params *params) -+{ -+ int v; -+ -+ switch (params->wpa_group) { -+ case WPA_CIPHER_CCMP: -+ v = IEEE80211_CIPHER_AES_CCM; -+ break; -+ case WPA_CIPHER_TKIP: -+ v = IEEE80211_CIPHER_TKIP; -+ break; -+ case WPA_CIPHER_WEP104: -+ v = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_CIPHER_WEP40: -+ v = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_CIPHER_NONE: -+ v = IEEE80211_CIPHER_NONE; -+ break; -+ default: -+ wpa_printf(MSG_ERROR, "Unknown group key cipher %u", -+ params->wpa_group); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); -+ if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { -+ printf("Unable to set group key cipher to %u\n", v); -+ return -1; -+ } -+ if (v == IEEE80211_CIPHER_WEP) { -+ /* key length is done only for specific ciphers */ -+ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); -+ if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { -+ printf("Unable to set group key length to %u\n", v); -+ return -1; -+ } -+ } -+ -+ v = 0; -+ if (params->wpa_pairwise & WPA_CIPHER_CCMP) -+ v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) -+ v |= 1<wpa_pairwise & WPA_CIPHER_NONE) -+ v |= 1<wpa_key_mgmt); -+ if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, -+ params->wpa_key_mgmt)) { -+ printf("Unable to set key management algorithms to 0x%x\n", -+ params->wpa_key_mgmt); -+ return -1; -+ } -+ -+ v = 0; -+ if (params->rsn_preauth) -+ v |= BIT(0); -+#ifdef CONFIG_IEEE80211W -+ if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) { -+ v |= BIT(7); -+ if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) -+ v |= BIT(6); -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", -+ __func__, params->rsn_preauth); -+ if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { -+ printf("Unable to set RSN capabilities to 0x%x\n", v); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); -+ if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { -+ printf("Unable to set WPA to %u\n", params->wpa); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params) -+{ -+ struct atheros_driver_data *drv = priv; -+ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); -+ -+ if (!params->enabled) { -+ /* XXX restore state */ -+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, -+ IEEE80211_AUTH_AUTO) < 0) -+ return -1; -+ /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */ -+ return atheros_set_privacy(drv, 0); -+ } -+ if (!params->wpa && !params->ieee802_1x) { -+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, -+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); -+ return -1; -+ } -+ if (params->wpa && atheros_configure_wpa(drv, params) != 0) { -+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, -+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); -+ return -1; -+ } -+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, -+ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { -+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, -+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+atheros_set_privacy(void *priv, int enabled) -+{ -+ struct atheros_driver_data *drv = priv; -+ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); -+ -+ return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); -+} -+ -+static int -+atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", -+ __func__, ether_sprintf(addr), authorized); -+ -+ if (authorized) -+ mlme.im_op = IEEE80211_MLME_AUTHORIZE; -+ else -+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; -+ mlme.im_reason = 0; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, -+ __func__, authorized ? "" : "un", MAC2STR(addr)); -+ } -+ -+ return ret; -+} -+ -+static int -+atheros_sta_set_flags(void *priv, const u8 *addr, -+ int total_flags, int flags_or, int flags_and) -+{ -+ /* For now, only support setting Authorized flag */ -+ if (flags_or & WPA_STA_AUTHORIZED) -+ return atheros_set_sta_authorized(priv, addr, 1); -+ if (!(flags_and & WPA_STA_AUTHORIZED)) -+ return atheros_set_sta_authorized(priv, addr, 0); -+ return 0; -+} -+ -+static int -+atheros_del_key(void *priv, const u8 *addr, int key_idx) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_del_key wk; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", -+ __func__, ether_sprintf(addr), key_idx); -+ -+ memset(&wk, 0, sizeof(wk)); -+ if (addr != NULL) { -+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; -+ } else { -+ wk.idk_keyix = key_idx; -+ } -+ -+ ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" -+ " key_idx %d)", __func__, ether_sprintf(addr), -+ key_idx); -+ } -+ -+ return ret; -+} -+ -+static int -+atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg, -+ const u8 *addr, int key_idx, int set_tx, const u8 *seq, -+ size_t seq_len, const u8 *key, size_t key_len) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_key wk; -+ u_int8_t cipher; -+ int ret; -+ -+ if (alg == WPA_ALG_NONE) -+ return atheros_del_key(drv, addr, key_idx); -+ -+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", -+ __func__, alg, ether_sprintf(addr), key_idx); -+ -+ switch (alg) { -+ case WPA_ALG_WEP: -+ cipher = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_ALG_TKIP: -+ cipher = IEEE80211_CIPHER_TKIP; -+ break; -+ case WPA_ALG_CCMP: -+ cipher = IEEE80211_CIPHER_AES_CCM; -+ break; -+#ifdef CONFIG_IEEE80211W -+ case WPA_ALG_IGTK: -+ cipher = IEEE80211_CIPHER_AES_CMAC; -+ break; -+#endif /* CONFIG_IEEE80211W */ -+ default: -+ printf("%s: unknown/unsupported algorithm %d\n", -+ __func__, alg); -+ return -1; -+ } -+ -+ if (key_len > sizeof(wk.ik_keydata)) { -+ printf("%s: key length %lu too big\n", __func__, -+ (unsigned long) key_len); -+ return -3; -+ } -+ -+ memset(&wk, 0, sizeof(wk)); -+ wk.ik_type = cipher; -+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; -+ if (addr == NULL || is_broadcast_ether_addr(addr)) { -+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = key_idx; -+ if (set_tx) -+ wk.ik_flags |= IEEE80211_KEY_DEFAULT; -+ } else { -+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = IEEE80211_KEYIX_NONE; -+ } -+ wk.ik_keylen = key_len; -+ memcpy(wk.ik_keydata, key, key_len); -+ -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" -+ " key_idx %d alg %d key_len %lu set_tx %d)", -+ __func__, ether_sprintf(wk.ik_macaddr), key_idx, -+ alg, (unsigned long) key_len, set_tx); -+ } -+ -+ return ret; -+} -+ -+ -+static int -+atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, -+ u8 *seq) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_key wk; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", -+ __func__, ether_sprintf(addr), idx); -+ -+ memset(&wk, 0, sizeof(wk)); -+ if (addr == NULL) -+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); -+ else -+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = idx; -+ -+ if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " -+ "(addr " MACSTR " key_idx %d)", -+ __func__, MAC2STR(wk.ik_macaddr), idx); -+ return -1; -+ } -+ -+#ifdef WORDS_BIGENDIAN -+ { -+ /* -+ * wk.ik_keytsc is in host byte order (big endian), need to -+ * swap it to match with the byte order used in WPA. -+ */ -+ int i; -+#ifndef WPA_KEY_RSC_LEN -+#define WPA_KEY_RSC_LEN 8 -+#endif -+ u8 tmp[WPA_KEY_RSC_LEN]; -+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) { -+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; -+ } -+ } -+#else /* WORDS_BIGENDIAN */ -+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -+#endif /* WORDS_BIGENDIAN */ -+ return 0; -+} -+ -+ -+static int -+atheros_flush(void *priv) -+{ -+ u8 allsta[IEEE80211_ADDR_LEN]; -+ memset(allsta, 0xff, IEEE80211_ADDR_LEN); -+ return atheros_sta_deauth(priv, NULL, allsta, -+ IEEE80211_REASON_AUTH_LEAVE); -+} -+ -+ -+static int -+atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, -+ const u8 *addr) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_sta_stats stats; -+ -+ memset(data, 0, sizeof(*data)); -+ -+ /* -+ * Fetch statistics for station from the system. -+ */ -+ memset(&stats, 0, sizeof(stats)); -+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); -+ if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS, -+ &stats, sizeof(stats))) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " -+ MACSTR ")", __func__, MAC2STR(addr)); -+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { -+ memcpy(data, &drv->acct_data, sizeof(*data)); -+ return 0; -+ } -+ -+ printf("Failed to get station stats information element.\n"); -+ return -1; -+ } -+ -+ data->rx_packets = stats.is_stats.ns_rx_data; -+ data->rx_bytes = stats.is_stats.ns_rx_bytes; -+ data->tx_packets = stats.is_stats.ns_tx_data; -+ data->tx_bytes = stats.is_stats.ns_tx_bytes; -+ return 0; -+} -+ -+ -+static int -+atheros_sta_clear_stats(void *priv, const u8 *addr) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); -+ -+ mlme.im_op = IEEE80211_MLME_CLEAR_STATS; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, -+ sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " -+ MACSTR ")", __func__, MAC2STR(addr)); -+ } -+ -+ return ret; -+} -+ -+ -+static int -+atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) -+{ -+ struct atheros_driver_data *drv = priv; -+ u8 buf[512]; -+ struct ieee80211req_getset_appiebuf *app_ie; -+ -+ wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, -+ (unsigned long) ie_len); -+ -+ wpabuf_free(drv->wpa_ie); -+ drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len); -+ -+ app_ie = (struct ieee80211req_getset_appiebuf *) buf; -+ os_memcpy(&(app_ie->app_buf[0]), ie, ie_len); -+ app_ie->app_buflen = ie_len; -+ -+ app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON; -+ -+ /* append WPS IE for Beacon */ -+ if (drv->wps_beacon_ie != NULL) { -+ os_memcpy(&(app_ie->app_buf[ie_len]), -+ wpabuf_head(drv->wps_beacon_ie), -+ wpabuf_len(drv->wps_beacon_ie)); -+ app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie); -+ } -+ set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, -+ sizeof(struct ieee80211req_getset_appiebuf) + -+ app_ie->app_buflen); -+ -+ /* append WPS IE for Probe Response */ -+ app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP; -+ if (drv->wps_probe_resp_ie != NULL) { -+ os_memcpy(&(app_ie->app_buf[ie_len]), -+ wpabuf_head(drv->wps_probe_resp_ie), -+ wpabuf_len(drv->wps_probe_resp_ie)); -+ app_ie->app_buflen = ie_len + -+ wpabuf_len(drv->wps_probe_resp_ie); -+ } else -+ app_ie->app_buflen = ie_len; -+ set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie, -+ sizeof(struct ieee80211req_getset_appiebuf) + -+ app_ie->app_buflen); -+ return 0; -+} -+ -+static int -+atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", -+ __func__, ether_sprintf(addr), reason_code); -+ -+ mlme.im_op = IEEE80211_MLME_DEAUTH; -+ mlme.im_reason = reason_code; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR -+ " reason %d)", -+ __func__, MAC2STR(addr), reason_code); -+ } -+ -+ return ret; -+} -+ -+static int -+atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", -+ __func__, ether_sprintf(addr), reason_code); -+ -+ mlme.im_op = IEEE80211_MLME_DISASSOC; -+ mlme.im_reason = reason_code; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " -+ MACSTR " reason %d)", -+ __func__, MAC2STR(addr), reason_code); -+ } -+ -+ return ret; -+} -+ -+#ifdef CONFIG_WPS -+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, -+ size_t len) -+{ -+ struct atheros_driver_data *drv = ctx; -+ const struct ieee80211_mgmt *mgmt; -+ u16 fc; -+ union wpa_event_data event; -+ -+ /* Send Probe Request information to WPS processing */ -+ -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) -+ return; -+ mgmt = (const struct ieee80211_mgmt *) buf; -+ -+ fc = le_to_host16(mgmt->frame_control); -+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || -+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) -+ return; -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_probe_req.sa = mgmt->sa; -+ event.rx_probe_req.ie = mgmt->u.probe_req.variable; -+ event.rx_probe_req.ie_len = -+ len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); -+ wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); -+} -+#endif /* CONFIG_WPS */ -+ -+static int atheros_receive_probe_req(struct atheros_driver_data *drv) -+{ -+ int ret = 0; -+#ifdef CONFIG_WPS -+ struct ieee80211req_set_filter filt; -+ -+ wpa_printf(MSG_DEBUG, "%s Enter", __func__); -+ filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ; -+ -+ ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, -+ sizeof(struct ieee80211req_set_filter)); -+ if (ret) -+ return ret; -+ -+ drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, -+ atheros_raw_receive, drv, 1); -+ if (drv->sock_raw == NULL) -+ return -1; -+#endif /* CONFIG_WPS */ -+ return ret; -+} -+ -+#ifdef CONFIG_WPS -+static int -+atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) -+{ -+ struct atheros_driver_data *drv = priv; -+ u8 buf[512]; -+ struct ieee80211req_getset_appiebuf *beac_ie; -+ -+ wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, -+ (unsigned long) len); -+ -+ beac_ie = (struct ieee80211req_getset_appiebuf *) buf; -+ beac_ie->app_frmtype = frametype; -+ beac_ie->app_buflen = len; -+ os_memcpy(&(beac_ie->app_buf[0]), ie, len); -+ -+ /* append the WPA/RSN IE if it is set already */ -+ if (((frametype == IEEE80211_APPIE_FRAME_BEACON) || -+ (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) && -+ (drv->wpa_ie != NULL)) { -+ os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie), -+ wpabuf_len(drv->wpa_ie)); -+ beac_ie->app_buflen += wpabuf_len(drv->wpa_ie); -+ } -+ -+ return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, -+ sizeof(struct ieee80211req_getset_appiebuf) + -+ beac_ie->app_buflen); -+} -+ -+static int -+atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, -+ const struct wpabuf *proberesp, -+ const struct wpabuf *assocresp) -+{ -+ struct atheros_driver_data *drv = priv; -+ -+ wpabuf_free(drv->wps_beacon_ie); -+ drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL; -+ wpabuf_free(drv->wps_probe_resp_ie); -+ drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL; -+ -+ atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL, -+ assocresp ? wpabuf_len(assocresp) : 0, -+ IEEE80211_APPIE_FRAME_ASSOC_RESP); -+ if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, -+ beacon ? wpabuf_len(beacon) : 0, -+ IEEE80211_APPIE_FRAME_BEACON)) -+ return -1; -+ return atheros_set_wps_ie(priv, -+ proberesp ? wpabuf_head(proberesp) : NULL, -+ proberesp ? wpabuf_len(proberesp): 0, -+ IEEE80211_APPIE_FRAME_PROBE_RESP); -+} -+#else /* CONFIG_WPS */ -+#define atheros_set_ap_wps_ie NULL -+#endif /* CONFIG_WPS */ -+ -+static void -+atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) -+{ -+ struct hostapd_data *hapd = drv->hapd; -+ struct ieee80211req_wpaie ie; -+ int ielen = 0; -+ u8 *iebuf = NULL; -+ -+ /* -+ * Fetch negotiated WPA/RSN parameters from the system. -+ */ -+ memset(&ie, 0, sizeof(ie)); -+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); -+ if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { -+ /* -+ * See ATH_WPS_IE comment in the beginning of the file for a -+ * possible cause for the failure.. -+ */ -+ wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", -+ __func__, strerror(errno)); -+ goto no_ie; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE", -+ ie.wpa_ie, IEEE80211_MAX_OPT_IE); -+ wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE", -+ ie.rsn_ie, IEEE80211_MAX_OPT_IE); -+#ifdef ATH_WPS_IE -+ wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE", -+ ie.wps_ie, IEEE80211_MAX_OPT_IE); -+#endif /* ATH_WPS_IE */ -+ iebuf = ie.wpa_ie; -+ /* atheros seems to return some random data if WPA/RSN IE is not set. -+ * Assume the IE was not included if the IE type is unknown. */ -+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) -+ iebuf[1] = 0; -+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { -+ /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not -+ * set. This is needed for WPA2. */ -+ iebuf = ie.rsn_ie; -+ if (iebuf[0] != WLAN_EID_RSN) -+ iebuf[1] = 0; -+ } -+ -+ ielen = iebuf[1]; -+ -+#ifdef ATH_WPS_IE -+ /* if WPS IE is present, preference is given to WPS */ -+ if (ie.wps_ie && -+ (ie.wps_ie[1] > 0 && (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) { -+ iebuf = ie.wps_ie; -+ ielen = ie.wps_ie[1]; -+ } -+#endif /* ATH_WPS_IE */ -+ -+ if (ielen == 0) -+ iebuf = NULL; -+ else -+ ielen += 2; -+ -+no_ie: -+ drv_event_assoc(hapd, addr, iebuf, ielen, 0); -+ -+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { -+ /* Cached accounting data is not valid anymore. */ -+ memset(drv->acct_mac, 0, ETH_ALEN); -+ memset(&drv->acct_data, 0, sizeof(drv->acct_data)); -+ } -+} -+ -+static void -+atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, -+ char *custom, char *end) -+{ -+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); -+ -+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { -+ char *pos; -+ u8 addr[ETH_ALEN]; -+ pos = strstr(custom, "addr="); -+ if (pos == NULL) { -+ wpa_printf(MSG_DEBUG, -+ "MLME-MICHAELMICFAILURE.indication " -+ "without sender address ignored"); -+ return; -+ } -+ pos += 5; -+ if (hwaddr_aton(pos, addr) == 0) { -+ union wpa_event_data data; -+ os_memset(&data, 0, sizeof(data)); -+ data.michael_mic_failure.unicast = 1; -+ data.michael_mic_failure.src = addr; -+ wpa_supplicant_event(drv->hapd, -+ EVENT_MICHAEL_MIC_FAILURE, &data); -+ } else { -+ wpa_printf(MSG_DEBUG, -+ "MLME-MICHAELMICFAILURE.indication " -+ "with invalid MAC address"); -+ } -+ } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { -+ char *key, *value; -+ u32 val; -+ key = custom; -+ while ((key = strchr(key, '\n')) != NULL) { -+ key++; -+ value = strchr(key, '='); -+ if (value == NULL) -+ continue; -+ *value++ = '\0'; -+ val = strtoul(value, NULL, 10); -+ if (strcmp(key, "mac") == 0) -+ hwaddr_aton(value, drv->acct_mac); -+ else if (strcmp(key, "rx_packets") == 0) -+ drv->acct_data.rx_packets = val; -+ else if (strcmp(key, "tx_packets") == 0) -+ drv->acct_data.tx_packets = val; -+ else if (strcmp(key, "rx_bytes") == 0) -+ drv->acct_data.rx_bytes = val; -+ else if (strcmp(key, "tx_bytes") == 0) -+ drv->acct_data.tx_bytes = val; -+ key = value; -+ } -+#ifdef CONFIG_WPS -+ } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) { -+ /* Some atheros kernels send push button as a wireless event */ -+ /* PROBLEM! this event is received for ALL BSSs ... -+ * so all are enabled for WPS... ugh. -+ */ -+ wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); -+ } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) { -+ /* -+ * Atheros driver uses a hack to pass Probe Request frames as a -+ * binary data in the custom wireless event. The old way (using -+ * packet sniffing) didn't work when bridging. -+ * Format: "Manage.prob_req " | zero padding | frame -+ */ -+#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */ -+ int len = atoi(custom + 16); -+ if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) { -+ wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event " -+ "length %d", len); -+ return; -+ } -+ atheros_raw_receive(drv, NULL, -+ (u8 *) custom + WPS_FRAM_TAG_SIZE, len); -+#endif /* CONFIG_WPS */ -+ } -+} -+ -+static void -+atheros_wireless_event_wireless(struct atheros_driver_data *drv, -+ char *data, int len) -+{ -+ struct iw_event iwe_buf, *iwe = &iwe_buf; -+ char *pos, *end, *custom, *buf; -+ -+ pos = data; -+ end = data + len; -+ -+ while (pos + IW_EV_LCP_LEN <= end) { -+ /* Event data may be unaligned, so make a local, aligned copy -+ * before processing. */ -+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); -+ wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", -+ iwe->cmd, iwe->len); -+ if (iwe->len <= IW_EV_LCP_LEN) -+ return; -+ -+ custom = pos + IW_EV_POINT_LEN; -+ if (drv->we_version > 18 && -+ (iwe->cmd == IWEVMICHAELMICFAILURE || -+ iwe->cmd == IWEVASSOCREQIE || -+ iwe->cmd == IWEVCUSTOM)) { -+ /* WE-19 removed the pointer from struct iw_point */ -+ char *dpos = (char *) &iwe_buf.u.data.length; -+ int dlen = dpos - (char *) &iwe_buf; -+ memcpy(dpos, pos + IW_EV_LCP_LEN, -+ sizeof(struct iw_event) - dlen); -+ } else { -+ memcpy(&iwe_buf, pos, sizeof(struct iw_event)); -+ custom += IW_EV_POINT_OFF; -+ } -+ -+ switch (iwe->cmd) { -+ case IWEVEXPIRED: -+ drv_event_disassoc(drv->hapd, -+ (u8 *) iwe->u.addr.sa_data); -+ break; -+ case IWEVREGISTERED: -+ atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data); -+ break; -+ case IWEVASSOCREQIE: -+ /* Driver hack.. Use IWEVASSOCREQIE to bypass -+ * IWEVCUSTOM size limitations. Need to handle this -+ * just like IWEVCUSTOM. -+ */ -+ case IWEVCUSTOM: -+ if (custom + iwe->u.data.length > end) -+ return; -+ buf = malloc(iwe->u.data.length + 1); -+ if (buf == NULL) -+ return; /* XXX */ -+ memcpy(buf, custom, iwe->u.data.length); -+ buf[iwe->u.data.length] = '\0'; -+ atheros_wireless_event_wireless_custom( -+ drv, buf, buf + iwe->u.data.length); -+ free(buf); -+ break; -+ } -+ -+ pos += iwe->len; -+ } -+} -+ -+ -+static void -+atheros_wireless_event_rtm_newlink(void *ctx, -+ struct ifinfomsg *ifi, u8 *buf, size_t len) -+{ -+ struct atheros_driver_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ if (ifi->ifi_index != drv->ifindex) -+ return; -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_WIRELESS) { -+ atheros_wireless_event_wireless( -+ drv, ((char *) attr) + rta_len, -+ attr->rta_len - rta_len); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+ -+ -+static int -+atheros_get_we_version(struct atheros_driver_data *drv) -+{ -+ struct iw_range *range; -+ struct iwreq iwr; -+ int minlen; -+ size_t buflen; -+ -+ drv->we_version = 0; -+ -+ /* -+ * Use larger buffer than struct iw_range in order to allow the -+ * structure to grow in the future. -+ */ -+ buflen = sizeof(struct iw_range) + 500; -+ range = os_zalloc(buflen); -+ if (range == NULL) -+ return -1; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) range; -+ iwr.u.data.length = buflen; -+ -+ minlen = ((char *) &range->enc_capa) - (char *) range + -+ sizeof(range->enc_capa); -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { -+ perror("ioctl[SIOCGIWRANGE]"); -+ free(range); -+ return -1; -+ } else if (iwr.u.data.length >= minlen && -+ range->we_version_compiled >= 18) { -+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " -+ "WE(source)=%d enc_capa=0x%x", -+ range->we_version_compiled, -+ range->we_version_source, -+ range->enc_capa); -+ drv->we_version = range->we_version_compiled; -+ } -+ -+ free(range); -+ return 0; -+} -+ -+ -+static int -+atheros_wireless_event_init(struct atheros_driver_data *drv) -+{ -+ struct netlink_config *cfg; -+ -+ atheros_get_we_version(drv); -+ -+ cfg = os_zalloc(sizeof(*cfg)); -+ if (cfg == NULL) -+ return -1; -+ cfg->ctx = drv; -+ cfg->newlink_cb = atheros_wireless_event_rtm_newlink; -+ drv->netlink = netlink_init(cfg); -+ if (drv->netlink == NULL) { -+ os_free(cfg); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int -+atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, -+ int encrypt, const u8 *own_addr, u32 flags) -+{ -+ struct atheros_driver_data *drv = priv; -+ unsigned char buf[3000]; -+ unsigned char *bp = buf; -+ struct l2_ethhdr *eth; -+ size_t len; -+ int status; -+ -+ /* -+ * Prepend the Ethernet header. If the caller left us -+ * space at the front we could just insert it but since -+ * we don't know we copy to a local buffer. Given the frequency -+ * and size of frames this probably doesn't matter. -+ */ -+ len = data_len + sizeof(struct l2_ethhdr); -+ if (len > sizeof(buf)) { -+ bp = malloc(len); -+ if (bp == NULL) { -+ printf("EAPOL frame discarded, cannot malloc temp " -+ "buffer of size %lu!\n", (unsigned long) len); -+ return -1; -+ } -+ } -+ eth = (struct l2_ethhdr *) bp; -+ memcpy(eth->h_dest, addr, ETH_ALEN); -+ memcpy(eth->h_source, own_addr, ETH_ALEN); -+ eth->h_proto = host_to_be16(ETH_P_EAPOL); -+ memcpy(eth+1, data, data_len); -+ -+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); -+ -+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); -+ -+ if (bp != buf) -+ free(bp); -+ return status; -+} -+ -+static void -+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -+{ -+ struct atheros_driver_data *drv = ctx; -+ drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), -+ len - sizeof(struct l2_ethhdr)); -+} -+ -+static void * -+atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) -+{ -+ struct atheros_driver_data *drv; -+ struct ifreq ifr; -+ struct iwreq iwr; -+ char brname[IFNAMSIZ]; -+ -+ drv = os_zalloc(sizeof(struct atheros_driver_data)); -+ if (drv == NULL) { -+ printf("Could not allocate memory for atheros driver data\n"); -+ return NULL; -+ } -+ -+ drv->hapd = hapd; -+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->ioctl_sock < 0) { -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ goto bad; -+ } -+ memcpy(drv->iface, params->ifname, sizeof(drv->iface)); -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); -+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { -+ perror("ioctl(SIOCGIFINDEX)"); -+ goto bad; -+ } -+ drv->ifindex = ifr.ifr_ifindex; -+ -+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, -+ handle_read, drv, 1); -+ if (drv->sock_xmit == NULL) -+ goto bad; -+ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) -+ goto bad; -+ if (params->bridge[0]) { -+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", -+ params->bridge[0]); -+ drv->sock_recv = l2_packet_init(params->bridge[0], NULL, -+ ETH_P_EAPOL, handle_read, drv, -+ 1); -+ if (drv->sock_recv == NULL) -+ goto bad; -+ } else if (linux_br_get(brname, drv->iface) == 0) { -+ wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " -+ "EAPOL receive", brname); -+ drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, -+ handle_read, drv, 1); -+ if (drv->sock_recv == NULL) -+ goto bad; -+ } else -+ drv->sock_recv = drv->sock_xmit; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ -+ iwr.u.mode = IW_MODE_MASTER; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMODE]"); -+ printf("Could not set interface to master mode!\n"); -+ goto bad; -+ } -+ -+ /* mark down during setup */ -+ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); -+ atheros_set_privacy(drv, 0); /* default to no privacy */ -+ -+ atheros_receive_probe_req(drv); -+ -+ if (atheros_wireless_event_init(drv)) -+ goto bad; -+ -+ return drv; -+bad: -+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) -+ l2_packet_deinit(drv->sock_recv); -+ if (drv->sock_xmit != NULL) -+ l2_packet_deinit(drv->sock_xmit); -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ if (drv != NULL) -+ free(drv); -+ return NULL; -+} -+ -+ -+static void -+atheros_deinit(void *priv) -+{ -+ struct atheros_driver_data *drv = priv; -+ -+ netlink_deinit(drv->netlink); -+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) -+ l2_packet_deinit(drv->sock_recv); -+ if (drv->sock_xmit != NULL) -+ l2_packet_deinit(drv->sock_xmit); -+ if (drv->sock_raw) -+ l2_packet_deinit(drv->sock_raw); -+ wpabuf_free(drv->wpa_ie); -+ wpabuf_free(drv->wps_beacon_ie); -+ wpabuf_free(drv->wps_probe_resp_ie); -+ free(drv); -+} -+ -+static int -+atheros_set_ssid(void *priv, const u8 *buf, int len) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct iwreq iwr; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.essid.flags = 1; /* SSID active */ -+ iwr.u.essid.pointer = (caddr_t) buf; -+ iwr.u.essid.length = len + 1; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCSIWESSID]"); -+ printf("len=%d\n", len); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+atheros_get_ssid(void *priv, u8 *buf, int len) -+{ -+ struct atheros_driver_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.essid.pointer = (caddr_t) buf; -+ iwr.u.essid.length = len; -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCGIWESSID]"); -+ ret = -1; -+ } else -+ ret = iwr.u.essid.length; -+ -+ return ret; -+} -+ -+static int -+atheros_set_countermeasures(void *priv, int enabled) -+{ -+ struct atheros_driver_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); -+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); -+} -+ -+static int -+atheros_commit(void *priv) -+{ -+ struct atheros_driver_data *drv = priv; -+ return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); -+} -+ -+const struct wpa_driver_ops wpa_driver_atheros_ops = { -+ .name = "atheros", -+ .hapd_init = atheros_init, -+ .hapd_deinit = atheros_deinit, -+ .set_ieee8021x = atheros_set_ieee8021x, -+ .set_privacy = atheros_set_privacy, -+ .set_key = atheros_set_key, -+ .get_seqnum = atheros_get_seqnum, -+ .flush = atheros_flush, -+ .set_generic_elem = atheros_set_opt_ie, -+ .sta_set_flags = atheros_sta_set_flags, -+ .read_sta_data = atheros_read_sta_driver_data, -+ .hapd_send_eapol = atheros_send_eapol, -+ .sta_disassoc = atheros_sta_disassoc, -+ .sta_deauth = atheros_sta_deauth, -+ .hapd_set_ssid = atheros_set_ssid, -+ .hapd_get_ssid = atheros_get_ssid, -+ .set_countermeasures = atheros_set_countermeasures, -+ .sta_clear_stats = atheros_sta_clear_stats, -+ .commit = atheros_commit, -+ .set_ap_wps_ie = atheros_set_ap_wps_ie, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_broadcom.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_broadcom.c -new file mode 100644 -index 0000000000000..cb88543c2c36a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_broadcom.c -@@ -0,0 +1,599 @@ -+/* -+ * WPA Supplicant - driver interaction with old Broadcom wl.o driver -+ * Copyright (c) 2004, Nikki Chumkov -+ * Copyright (c) 2004, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * Please note that the newer Broadcom driver ("hybrid Linux driver") supports -+ * Linux wireless extensions and does not need (or even work) with this old -+ * driver wrapper. Use driver_wext.c with that driver. -+ */ -+ -+#include "includes.h" -+ -+#include -+ -+#include "common.h" -+ -+#if 0 -+#include -+#include /* the L2 protocols */ -+#else -+#include -+#include /* The L2 protocols */ -+#endif -+#include -+#include -+ -+/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys -+ * WRT54G GPL tarball. */ -+#include -+ -+#include "driver.h" -+#include "eloop.h" -+ -+struct wpa_driver_broadcom_data { -+ void *ctx; -+ int ioctl_sock; -+ int event_sock; -+ char ifname[IFNAMSIZ + 1]; -+}; -+ -+ -+#ifndef WLC_DEAUTHENTICATE -+#define WLC_DEAUTHENTICATE 143 -+#endif -+#ifndef WLC_DEAUTHENTICATE_WITH_REASON -+#define WLC_DEAUTHENTICATE_WITH_REASON 201 -+#endif -+#ifndef WLC_SET_TKIP_COUNTERMEASURES -+#define WLC_SET_TKIP_COUNTERMEASURES 202 -+#endif -+ -+#if !defined(PSK_ENABLED) /* NEW driver interface */ -+#define WL_VERSION 360130 -+/* wireless authentication bit vector */ -+#define WPA_ENABLED 1 -+#define PSK_ENABLED 2 -+ -+#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED) -+#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED) -+#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED)) -+ -+#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY -+ -+typedef wl_wsec_key_t wsec_key_t; -+#endif -+ -+typedef struct { -+ uint32 val; -+ struct ether_addr ea; -+ uint16 res; -+} wlc_deauth_t; -+ -+ -+static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx, -+ void *timeout_ctx); -+ -+static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd, -+ void *buf, int len) -+{ -+ struct ifreq ifr; -+ wl_ioctl_t ioc; -+ int ret = 0; -+ -+ wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)", -+ drv->ifname, cmd, len, buf); -+ /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */ -+ -+ ioc.cmd = cmd; -+ ioc.buf = buf; -+ ioc.len = len; -+ os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ); -+ ifr.ifr_data = (caddr_t) &ioc; -+ if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) { -+ if (cmd != WLC_GET_MAGIC) -+ perror(ifr.ifr_name); -+ wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d", -+ cmd, ret); -+ } -+ -+ return ret; -+} -+ -+static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0) -+ return 0; -+ -+ os_memset(bssid, 0, ETH_ALEN); -+ return -1; -+} -+ -+static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ wlc_ssid_t s; -+ -+ if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1) -+ return -1; -+ -+ os_memcpy(ssid, s.SSID, s.SSID_len); -+ return s.SSID_len; -+} -+ -+static int wpa_driver_broadcom_set_wpa(void *priv, int enable) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ unsigned int wauth, wsec; -+ struct ether_addr ea; -+ -+ os_memset(&ea, enable ? 0xff : 0, sizeof(ea)); -+ if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) == -+ -1 || -+ broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1) -+ return -1; -+ -+ if (enable) { -+ wauth = PSK_ENABLED; -+ wsec = TKIP_ENABLED; -+ } else { -+ wauth = 255; -+ wsec &= ~(TKIP_ENABLED | AES_ENABLED); -+ } -+ -+ if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) == -+ -1 || -+ broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1) -+ return -1; -+ -+ /* FIX: magic number / error handling? */ -+ broadcom_ioctl(drv, 122, &ea, sizeof(ea)); -+ -+ return 0; -+} -+ -+static int wpa_driver_broadcom_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, -+ const u8 *addr, int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ int ret; -+ wsec_key_t wkt; -+ -+ os_memset(&wkt, 0, sizeof wkt); -+ wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d", -+ set_tx ? "PRIMARY " : "", key_idx, alg); -+ if (key && key_len > 0) -+ wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len); -+ -+ switch (alg) { -+ case WPA_ALG_NONE: -+ wkt.algo = CRYPTO_ALGO_OFF; -+ break; -+ case WPA_ALG_WEP: -+ wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */ -+ break; -+ case WPA_ALG_TKIP: -+ wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */ -+ break; -+ case WPA_ALG_CCMP: -+ wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM; -+ * AES_OCB_MSDU, AES_OCB_MPDU? */ -+ break; -+ default: -+ wkt.algo = CRYPTO_ALGO_NALG; -+ break; -+ } -+ -+ if (seq && seq_len > 0) -+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len); -+ -+ if (addr) -+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN); -+ -+ wkt.index = key_idx; -+ wkt.len = key_len; -+ if (key && key_len > 0) { -+ os_memcpy(wkt.data, key, key_len); -+ if (key_len == 32) { -+ /* hack hack hack XXX */ -+ os_memcpy(&wkt.data[16], &key[24], 8); -+ os_memcpy(&wkt.data[24], &key[16], 8); -+ } -+ } -+ /* wkt.algo = CRYPTO_ALGO_...; */ -+ wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY; -+ if (addr && set_tx) -+ os_memcpy(&wkt.ea, addr, sizeof(wkt.ea)); -+ ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt)); -+ if (addr && set_tx) { -+ /* FIX: magic number / error handling? */ -+ broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea)); -+ } -+ return ret; -+} -+ -+ -+static void wpa_driver_broadcom_event_receive(int sock, void *ctx, -+ void *sock_ctx) -+{ -+ char buf[8192]; -+ int left; -+ wl_wpa_header_t *wwh; -+ union wpa_event_data data; -+ u8 *resp_ies = NULL; -+ -+ if ((left = recv(sock, buf, sizeof buf, 0)) < 0) -+ return; -+ -+ wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left); -+ -+ if ((size_t) left < sizeof(wl_wpa_header_t)) -+ return; -+ -+ wwh = (wl_wpa_header_t *) buf; -+ -+ if (wwh->snap.type != WL_WPA_ETHER_TYPE) -+ return; -+ if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ -+ switch (wwh->type) { -+ case WLC_ASSOC_MSG: -+ left -= WL_WPA_HEADER_LEN; -+ wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)", -+ left); -+ if (left > 0) { -+ resp_ies = os_malloc(left); -+ if (resp_ies == NULL) -+ return; -+ os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left); -+ data.assoc_info.resp_ies = resp_ies; -+ data.assoc_info.resp_ies_len = left; -+ } -+ -+ wpa_supplicant_event(ctx, EVENT_ASSOC, &data); -+ os_free(resp_ies); -+ break; -+ case WLC_DISASSOC_MSG: -+ wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE"); -+ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); -+ break; -+ case WLC_PTK_MIC_MSG: -+ wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE"); -+ data.michael_mic_failure.unicast = 1; -+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -+ break; -+ case WLC_GTK_MIC_MSG: -+ wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE"); -+ data.michael_mic_failure.unicast = 0; -+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)", -+ wwh->type); -+ break; -+ } -+} -+ -+static void * wpa_driver_broadcom_init(void *ctx, const char *ifname) -+{ -+ int s; -+ struct sockaddr_ll ll; -+ struct wpa_driver_broadcom_data *drv; -+ struct ifreq ifr; -+ -+ /* open socket to kernel */ -+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { -+ perror("socket"); -+ return NULL; -+ } -+ /* do it */ -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { -+ perror(ifr.ifr_name); -+ return NULL; -+ } -+ -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->ctx = ctx; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ drv->ioctl_sock = s; -+ -+ s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2)); -+ if (s < 0) { -+ perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))"); -+ close(drv->ioctl_sock); -+ os_free(drv); -+ return NULL; -+ } -+ -+ os_memset(&ll, 0, sizeof(ll)); -+ ll.sll_family = AF_PACKET; -+ ll.sll_protocol = ntohs(ETH_P_802_2); -+ ll.sll_ifindex = ifr.ifr_ifindex; -+ ll.sll_hatype = 0; -+ ll.sll_pkttype = PACKET_HOST; -+ ll.sll_halen = 0; -+ -+ if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) { -+ perror("bind(netlink)"); -+ close(s); -+ close(drv->ioctl_sock); -+ os_free(drv); -+ return NULL; -+ } -+ -+ eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx, -+ NULL); -+ drv->event_sock = s; -+ wpa_driver_broadcom_set_wpa(drv, 1); -+ -+ return drv; -+} -+ -+static void wpa_driver_broadcom_deinit(void *priv) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ wpa_driver_broadcom_set_wpa(drv, 0); -+ eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx); -+ eloop_unregister_read_sock(drv->event_sock); -+ close(drv->event_sock); -+ close(drv->ioctl_sock); -+ os_free(drv); -+} -+ -+static int wpa_driver_broadcom_set_countermeasures(void *priv, -+ int enabled) -+{ -+#if 0 -+ struct wpa_driver_broadcom_data *drv = priv; -+ /* FIX: ? */ -+ return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled, -+ sizeof(enabled)); -+#else -+ return 0; -+#endif -+} -+ -+static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */ -+ int _restrict = (enabled ? 1 : 0); -+ -+ if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT, -+ &_restrict, sizeof(_restrict)) < 0 || -+ broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT, -+ &_restrict, sizeof(_restrict)) < 0) -+ return -1; -+ -+ return 0; -+} -+ -+static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx, -+ void *timeout_ctx) -+{ -+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+} -+ -+static int wpa_driver_broadcom_scan(void *priv, -+ struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ wlc_ssid_t wst = { 0, "" }; -+ const u8 *ssid = params->ssids[0].ssid; -+ size_t ssid_len = params->ssids[0].ssid_len; -+ -+ if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) { -+ wst.SSID_len = ssid_len; -+ os_memcpy(wst.SSID, ssid, ssid_len); -+ } -+ -+ if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0) -+ return -1; -+ -+ eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx); -+ eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv, -+ drv->ctx); -+ return 0; -+} -+ -+ -+static const int frequency_list[] = { -+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, -+ 2447, 2452, 2457, 2462, 2467, 2472, 2484 -+}; -+ -+struct bss_ie_hdr { -+ u8 elem_id; -+ u8 len; -+ u8 oui[3]; -+ /* u8 oui_type; */ -+ /* u16 version; */ -+} __attribute__ ((packed)); -+ -+static struct wpa_scan_results * -+wpa_driver_broadcom_get_scan_results(void *priv) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ char *buf; -+ wl_scan_results_t *wsr; -+ wl_bss_info_t *wbi; -+ size_t ap_num; -+ struct wpa_scan_results *res; -+ -+ buf = os_malloc(WLC_IOCTL_MAXLEN); -+ if (buf == NULL) -+ return NULL; -+ -+ wsr = (wl_scan_results_t *) buf; -+ -+ wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr); -+ wsr->version = 107; -+ wsr->count = 0; -+ -+ if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) { -+ os_free(buf); -+ return NULL; -+ } -+ -+ res = os_zalloc(sizeof(*res)); -+ if (res == NULL) { -+ os_free(buf); -+ return NULL; -+ } -+ -+ res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *)); -+ if (res->res == NULL) { -+ os_free(res); -+ os_free(buf); -+ return NULL; -+ } -+ -+ for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) { -+ struct wpa_scan_res *r; -+ r = os_malloc(sizeof(*r) + wbi->ie_length); -+ if (r == NULL) -+ break; -+ res->res[res->num++] = r; -+ -+ os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN); -+ r->freq = frequency_list[wbi->channel - 1]; -+ /* get ie's */ -+ os_memcpy(r + 1, wbi + 1, wbi->ie_length); -+ r->ie_len = wbi->ie_length; -+ -+ wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length); -+ } -+ -+ wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu " -+ "BSSes)", -+ wsr->buflen, (unsigned long) ap_num); -+ -+ os_free(buf); -+ return res; -+ } -+ -+static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ wlc_deauth_t wdt; -+ wdt.val = reason_code; -+ os_memcpy(&wdt.ea, addr, sizeof wdt.ea); -+ wdt.res = 0x7fff; -+ return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt, -+ sizeof(wdt)); -+} -+ -+static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0); -+} -+ -+static int -+wpa_driver_broadcom_associate(void *priv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_broadcom_data *drv = priv; -+ wlc_ssid_t s; -+ int infra = 1; -+ int auth = 0; -+ int wsec = 4; -+ int dummy; -+ int wpa_auth; -+ int ret; -+ -+ ret = wpa_driver_broadcom_set_drop_unencrypted( -+ drv, params->drop_unencrypted); -+ -+ s.SSID_len = params->ssid_len; -+ os_memcpy(s.SSID, params->ssid, params->ssid_len); -+ -+ switch (params->pairwise_suite) { -+ case CIPHER_WEP40: -+ case CIPHER_WEP104: -+ wsec = 1; -+ break; -+ -+ case CIPHER_TKIP: -+ wsec = 2; -+ break; -+ -+ case CIPHER_CCMP: -+ wsec = 4; -+ break; -+ -+ default: -+ wsec = 0; -+ break; -+ } -+ -+ switch (params->key_mgmt_suite) { -+ case KEY_MGMT_802_1X: -+ wpa_auth = 1; -+ break; -+ -+ case KEY_MGMT_PSK: -+ wpa_auth = 2; -+ break; -+ -+ default: -+ wpa_auth = 255; -+ break; -+ } -+ -+ /* printf("broadcom_associate: %u %u %u\n", pairwise_suite, -+ * group_suite, key_mgmt_suite); -+ * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec)); -+ * wl join uses wlc_sec_wep here, not wlc_set_wsec */ -+ -+ if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 || -+ broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth, -+ sizeof(wpa_auth)) < 0 || -+ broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 || -+ broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 || -+ broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 || -+ broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 || -+ broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0) -+ return -1; -+ -+ return ret; -+} -+ -+const struct wpa_driver_ops wpa_driver_broadcom_ops = { -+ .name = "broadcom", -+ .desc = "Broadcom wl.o driver", -+ .get_bssid = wpa_driver_broadcom_get_bssid, -+ .get_ssid = wpa_driver_broadcom_get_ssid, -+ .set_key = wpa_driver_broadcom_set_key, -+ .init = wpa_driver_broadcom_init, -+ .deinit = wpa_driver_broadcom_deinit, -+ .set_countermeasures = wpa_driver_broadcom_set_countermeasures, -+ .scan2 = wpa_driver_broadcom_scan, -+ .get_scan_results2 = wpa_driver_broadcom_get_scan_results, -+ .deauthenticate = wpa_driver_broadcom_deauthenticate, -+ .disassociate = wpa_driver_broadcom_disassociate, -+ .associate = wpa_driver_broadcom_associate, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_bsd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_bsd.c -new file mode 100644 -index 0000000000000..1b52865eaedb0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_bsd.c -@@ -0,0 +1,1573 @@ -+/* -+ * WPA Supplicant - driver interaction with BSD net80211 layer -+ * Copyright (c) 2004, Sam Leffler -+ * Copyright (c) 2004, 2Wire, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+ -+#include "common.h" -+#include "driver.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "common/wpa_common.h" -+ -+#include -+#include -+ -+#ifdef __NetBSD__ -+#include -+#else -+#include -+#endif -+#include -+ -+#ifdef __DragonFly__ -+#include -+#include -+#else /* __DragonFly__ */ -+#ifdef __GLIBC__ -+#include -+#endif /* __GLIBC__ */ -+#include -+#include -+#include -+#endif /* __DragonFly__ || __GLIBC__ */ -+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -+#include -+#endif -+#if __NetBSD__ -+#include -+#endif -+ -+#include "l2_packet/l2_packet.h" -+ -+struct bsd_driver_data { -+ struct hostapd_data *hapd; /* back pointer */ -+ -+ int sock; /* open socket for 802.11 ioctls */ -+ struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ -+ int route; /* routing socket for events */ -+ char ifname[IFNAMSIZ+1]; /* interface name */ -+ unsigned int ifindex; /* interface index */ -+ void *ctx; -+ struct wpa_driver_capa capa; /* driver capability */ -+ int is_ap; /* Access point mode */ -+ int prev_roaming; /* roaming state to restore on deinit */ -+ int prev_privacy; /* privacy state to restore on deinit */ -+ int prev_wpa; /* wpa state to restore on deinit */ -+}; -+ -+/* Generic functions for hostapd and wpa_supplicant */ -+ -+static int -+bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) -+{ -+ struct bsd_driver_data *drv = priv; -+ struct ieee80211req ireq; -+ -+ os_memset(&ireq, 0, sizeof(ireq)); -+ os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); -+ ireq.i_type = op; -+ ireq.i_val = val; -+ ireq.i_data = (void *) arg; -+ ireq.i_len = arg_len; -+ -+ if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { -+ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " -+ "arg_len=%u]: %s", op, val, arg_len, -+ strerror(errno)); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+bsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, -+ int arg_len) -+{ -+ struct bsd_driver_data *drv = priv; -+ -+ os_memset(ireq, 0, sizeof(*ireq)); -+ os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name)); -+ ireq->i_type = op; -+ ireq->i_len = arg_len; -+ ireq->i_data = arg; -+ -+ if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { -+ wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " -+ "arg_len=%u]: %s", op, arg_len, strerror(errno)); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) -+{ -+ struct ieee80211req ireq; -+ -+ if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0) -+ return -1; -+ return ireq.i_len; -+} -+ -+static int -+set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) -+{ -+ return bsd_set80211(drv, op, 0, arg, arg_len); -+} -+ -+static int -+set80211param(struct bsd_driver_data *drv, int op, int arg) -+{ -+ return bsd_set80211(drv, op, arg, NULL, 0); -+} -+ -+static int -+bsd_get_ssid(void *priv, u8 *ssid, int len) -+{ -+ struct bsd_driver_data *drv = priv; -+#ifdef SIOCG80211NWID -+ struct ieee80211_nwid nwid; -+ struct ifreq ifr; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); -+ ifr.ifr_data = (void *)&nwid; -+ if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || -+ nwid.i_len > IEEE80211_NWID_LEN) -+ return -1; -+ os_memcpy(ssid, nwid.i_nwid, nwid.i_len); -+ return nwid.i_len; -+#else -+ return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); -+#endif -+} -+ -+static int -+bsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) -+{ -+ struct bsd_driver_data *drv = priv; -+#ifdef SIOCS80211NWID -+ struct ieee80211_nwid nwid; -+ struct ifreq ifr; -+ -+ os_memcpy(nwid.i_nwid, ssid, ssid_len); -+ nwid.i_len = ssid_len; -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); -+ ifr.ifr_data = (void *)&nwid; -+ return ioctl(drv->sock, SIOCS80211NWID, &ifr); -+#else -+ return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); -+#endif -+} -+ -+static int -+bsd_get_if_media(void *priv) -+{ -+ struct bsd_driver_data *drv = priv; -+ struct ifmediareq ifmr; -+ -+ os_memset(&ifmr, 0, sizeof(ifmr)); -+ os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); -+ -+ if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { -+ wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, -+ strerror(errno)); -+ return -1; -+ } -+ -+ return ifmr.ifm_current; -+} -+ -+static int -+bsd_set_if_media(void *priv, int media) -+{ -+ struct bsd_driver_data *drv = priv; -+ struct ifreq ifr; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); -+ ifr.ifr_media = media; -+ -+ if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { -+ wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, -+ strerror(errno)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+bsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode) -+{ -+ int media = bsd_get_if_media(priv); -+ -+ if (media < 0) -+ return -1; -+ media &= ~mask; -+ media |= mode; -+ if (bsd_set_if_media(priv, media) < 0) -+ return -1; -+ return 0; -+} -+ -+static int -+bsd_del_key(void *priv, const u8 *addr, int key_idx) -+{ -+ struct ieee80211req_del_key wk; -+ -+ os_memset(&wk, 0, sizeof(wk)); -+ if (addr == NULL) { -+ wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx); -+ wk.idk_keyix = key_idx; -+ } else { -+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, -+ MAC2STR(addr)); -+ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ -+ } -+ -+ return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); -+} -+ -+static int -+bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) -+{ -+ struct ieee80211req_mlme mlme; -+ -+ os_memset(&mlme, 0, sizeof(mlme)); -+ mlme.im_op = op; -+ mlme.im_reason = reason; -+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); -+} -+ -+static int -+bsd_ctrl_iface(void *priv, int enable) -+{ -+ struct bsd_driver_data *drv = priv; -+ struct ifreq ifr; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); -+ -+ if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { -+ perror("ioctl[SIOCGIFFLAGS]"); -+ return -1; -+ } -+ -+ if (enable) -+ ifr.ifr_flags |= IFF_UP; -+ else -+ ifr.ifr_flags &= ~IFF_UP; -+ -+ if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { -+ perror("ioctl[SIOCSIFFLAGS]"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, -+ const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, -+ size_t seq_len, const u8 *key, size_t key_len) -+{ -+ struct ieee80211req_key wk; -+ -+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " -+ "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, -+ set_tx, seq_len, key_len); -+ -+ if (alg == WPA_ALG_NONE) { -+#ifndef HOSTAPD -+ if (addr == NULL || is_broadcast_ether_addr(addr)) -+ return bsd_del_key(priv, NULL, key_idx); -+ else -+#endif /* HOSTAPD */ -+ return bsd_del_key(priv, addr, key_idx); -+ } -+ -+ os_memset(&wk, 0, sizeof(wk)); -+ switch (alg) { -+ case WPA_ALG_WEP: -+ wk.ik_type = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_ALG_TKIP: -+ wk.ik_type = IEEE80211_CIPHER_TKIP; -+ break; -+ case WPA_ALG_CCMP: -+ wk.ik_type = IEEE80211_CIPHER_AES_CCM; -+ break; -+ default: -+ wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg); -+ return -1; -+ } -+ -+ wk.ik_flags = IEEE80211_KEY_RECV; -+ if (set_tx) -+ wk.ik_flags |= IEEE80211_KEY_XMIT; -+ -+ if (addr == NULL) { -+ os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = key_idx; -+ } else { -+ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); -+ /* -+ * Deduce whether group/global or unicast key by checking -+ * the address (yech). Note also that we can only mark global -+ * keys default; doing this for a unicast key is an error. -+ */ -+ if (is_broadcast_ether_addr(addr)) { -+ wk.ik_flags |= IEEE80211_KEY_GROUP; -+ wk.ik_keyix = key_idx; -+ } else { -+ wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE : -+ key_idx; -+ } -+ } -+ if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) -+ wk.ik_flags |= IEEE80211_KEY_DEFAULT; -+ wk.ik_keylen = key_len; -+ if (seq) -+ os_memcpy(&wk.ik_keyrsc, seq, seq_len); -+ os_memcpy(wk.ik_keydata, key, key_len); -+ -+ return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); -+} -+ -+static int -+bsd_configure_wpa(void *priv, struct wpa_bss_params *params) -+{ -+#ifndef IEEE80211_IOC_APPIE -+ static const char *ciphernames[] = -+ { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; -+ int v; -+ -+ switch (params->wpa_group) { -+ case WPA_CIPHER_CCMP: -+ v = IEEE80211_CIPHER_AES_CCM; -+ break; -+ case WPA_CIPHER_TKIP: -+ v = IEEE80211_CIPHER_TKIP; -+ break; -+ case WPA_CIPHER_WEP104: -+ v = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_CIPHER_WEP40: -+ v = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_CIPHER_NONE: -+ v = IEEE80211_CIPHER_NONE; -+ break; -+ default: -+ printf("Unknown group key cipher %u\n", -+ params->wpa_group); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", -+ __func__, ciphernames[v], v); -+ if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) { -+ printf("Unable to set group key cipher to %u (%s)\n", -+ v, ciphernames[v]); -+ return -1; -+ } -+ if (v == IEEE80211_CIPHER_WEP) { -+ /* key length is done only for specific ciphers */ -+ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); -+ if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) { -+ printf("Unable to set group key length to %u\n", v); -+ return -1; -+ } -+ } -+ -+ v = 0; -+ if (params->wpa_pairwise & WPA_CIPHER_CCMP) -+ v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) -+ v |= 1<wpa_pairwise & WPA_CIPHER_NONE) -+ v |= 1<wpa_key_mgmt); -+ if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS, -+ params->wpa_key_mgmt)) { -+ printf("Unable to set key management algorithms to 0x%x\n", -+ params->wpa_key_mgmt); -+ return -1; -+ } -+ -+ v = 0; -+ if (params->rsn_preauth) -+ v |= BIT(0); -+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", -+ __func__, params->rsn_preauth); -+ if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) { -+ printf("Unable to set RSN capabilities to 0x%x\n", v); -+ return -1; -+ } -+#endif /* IEEE80211_IOC_APPIE */ -+ -+ wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa); -+ if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) { -+ printf("Unable to set WPA to %u\n", params->wpa); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) -+{ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); -+ -+ if (!params->enabled) { -+ /* XXX restore state */ -+ return set80211param(priv, IEEE80211_IOC_AUTHMODE, -+ IEEE80211_AUTH_AUTO); -+ } -+ if (!params->wpa && !params->ieee802_1x) { -+ wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled", -+ __func__); -+ return -1; -+ } -+ if (params->wpa && bsd_configure_wpa(priv, params) != 0) { -+ wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state", -+ __func__); -+ return -1; -+ } -+ if (set80211param(priv, IEEE80211_IOC_AUTHMODE, -+ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { -+ wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X", -+ __func__); -+ return -1; -+ } -+ return bsd_ctrl_iface(priv, 1); -+} -+ -+static int -+bsd_set_sta_authorized(void *priv, const u8 *addr, -+ int total_flags, int flags_or, int flags_and) -+{ -+ int authorized = -1; -+ -+ /* For now, only support setting Authorized flag */ -+ if (flags_or & WPA_STA_AUTHORIZED) -+ authorized = 1; -+ if (!(flags_and & WPA_STA_AUTHORIZED)) -+ authorized = 0; -+ -+ if (authorized < 0) -+ return 0; -+ -+ return bsd_send_mlme_param(priv, authorized ? -+ IEEE80211_MLME_AUTHORIZE : -+ IEEE80211_MLME_UNAUTHORIZE, 0, addr); -+} -+ -+static void -+bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) -+{ -+ struct ieee80211req_wpaie ie; -+ int ielen = 0; -+ u8 *iebuf = NULL; -+ -+ /* -+ * Fetch and validate any negotiated WPA/RSN parameters. -+ */ -+ memset(&ie, 0, sizeof(ie)); -+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); -+ if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { -+ printf("Failed to get WPA/RSN information element.\n"); -+ goto no_ie; -+ } -+ iebuf = ie.wpa_ie; -+ ielen = ie.wpa_ie[1]; -+ if (ielen == 0) -+ iebuf = NULL; -+ else -+ ielen += 2; -+ -+no_ie: -+ drv_event_assoc(ctx, addr, iebuf, ielen, 0); -+} -+ -+static int -+bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, -+ int encrypt, const u8 *own_addr, u32 flags) -+{ -+ struct bsd_driver_data *drv = priv; -+ -+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len); -+ -+ return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data, -+ data_len); -+} -+ -+static int -+bsd_set_freq(void *priv, struct hostapd_freq_params *freq) -+{ -+ struct bsd_driver_data *drv = priv; -+#ifdef SIOCS80211CHANNEL -+ struct ieee80211chanreq creq; -+#endif /* SIOCS80211CHANNEL */ -+ u32 mode; -+ int channel = freq->channel; -+ -+ if (channel < 14) { -+ mode = -+#ifdef CONFIG_IEEE80211N -+ freq->ht_enabled ? IFM_IEEE80211_11NG : -+#endif /* CONFIG_IEEE80211N */ -+ IFM_IEEE80211_11G; -+ } else if (channel == 14) { -+ mode = IFM_IEEE80211_11B; -+ } else { -+ mode = -+#ifdef CONFIG_IEEE80211N -+ freq->ht_enabled ? IFM_IEEE80211_11NA : -+#endif /* CONFIG_IEEE80211N */ -+ IFM_IEEE80211_11A; -+ } -+ if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { -+ wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", -+ __func__); -+ return -1; -+ } -+ -+#ifdef SIOCS80211CHANNEL -+ os_memset(&creq, 0, sizeof(creq)); -+ os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); -+ creq.i_channel = (u_int16_t)channel; -+ return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); -+#else /* SIOCS80211CHANNEL */ -+ return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); -+#endif /* SIOCS80211CHANNEL */ -+} -+ -+static int -+bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) -+{ -+#ifdef IEEE80211_IOC_APPIE -+ wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, -+ (unsigned long)ie_len); -+ return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, -+ ie, ie_len); -+#endif /* IEEE80211_IOC_APPIE */ -+ return 0; -+} -+ -+static int -+rtbuf_len(void) -+{ -+ size_t len; -+ -+ int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; -+ -+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { -+ wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__, -+ strerror(errno)); -+ len = 2048; -+ } -+ -+ return len; -+} -+ -+#ifdef HOSTAPD -+ -+/* -+ * Avoid conflicts with hostapd definitions by undefining couple of defines -+ * from net80211 header files. -+ */ -+#undef RSN_VERSION -+#undef WPA_VERSION -+#undef WPA_OUI_TYPE -+ -+static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code); -+ -+static const char * -+ether_sprintf(const u8 *addr) -+{ -+ static char buf[sizeof(MACSTR)]; -+ -+ if (addr != NULL) -+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); -+ else -+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); -+ return buf; -+} -+ -+static int -+bsd_set_privacy(void *priv, int enabled) -+{ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); -+ -+ return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); -+} -+ -+static int -+bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, -+ u8 *seq) -+{ -+ struct ieee80211req_key wk; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", -+ __func__, ether_sprintf(addr), idx); -+ -+ memset(&wk, 0, sizeof(wk)); -+ if (addr == NULL) -+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); -+ else -+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = idx; -+ -+ if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { -+ printf("Failed to get encryption.\n"); -+ return -1; -+ } -+ -+#ifdef WORDS_BIGENDIAN -+ { -+ /* -+ * wk.ik_keytsc is in host byte order (big endian), need to -+ * swap it to match with the byte order used in WPA. -+ */ -+ int i; -+ u8 tmp[WPA_KEY_RSC_LEN]; -+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) { -+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; -+ } -+ } -+#else /* WORDS_BIGENDIAN */ -+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -+#endif /* WORDS_BIGENDIAN */ -+ return 0; -+} -+ -+ -+static int -+bsd_flush(void *priv) -+{ -+ u8 allsta[IEEE80211_ADDR_LEN]; -+ -+ memset(allsta, 0xff, IEEE80211_ADDR_LEN); -+ return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); -+} -+ -+ -+static int -+bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, -+ const u8 *addr) -+{ -+ struct ieee80211req_sta_stats stats; -+ -+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); -+ if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) -+ > 0) { -+ /* XXX? do packets counts include non-data frames? */ -+ data->rx_packets = stats.is_stats.ns_rx_data; -+ data->rx_bytes = stats.is_stats.ns_rx_bytes; -+ data->tx_packets = stats.is_stats.ns_tx_data; -+ data->tx_bytes = stats.is_stats.ns_tx_bytes; -+ } -+ return 0; -+} -+ -+static int -+bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) -+{ -+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, -+ addr); -+} -+ -+static int -+bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code) -+{ -+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, -+ addr); -+} -+ -+static void -+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) -+{ -+ struct bsd_driver_data *drv = ctx; -+ char *buf; -+ struct if_announcemsghdr *ifan; -+ struct rt_msghdr *rtm; -+ struct ieee80211_michael_event *mic; -+ struct ieee80211_join_event *join; -+ struct ieee80211_leave_event *leave; -+ int n, len; -+ union wpa_event_data data; -+ -+ len = rtbuf_len(); -+ -+ buf = os_malloc(len); -+ if (buf == NULL) { -+ wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__); -+ return; -+ } -+ -+ n = read(sock, buf, len); -+ if (n < 0) { -+ if (errno != EINTR && errno != EAGAIN) -+ wpa_printf(MSG_ERROR, "%s read() failed: %s\n", -+ __func__, strerror(errno)); -+ os_free(buf); -+ return; -+ } -+ -+ rtm = (struct rt_msghdr *) buf; -+ if (rtm->rtm_version != RTM_VERSION) { -+ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", -+ rtm->rtm_version); -+ os_free(buf); -+ return; -+ } -+ ifan = (struct if_announcemsghdr *) rtm; -+ switch (rtm->rtm_type) { -+ case RTM_IEEE80211: -+ switch (ifan->ifan_what) { -+ case RTM_IEEE80211_ASSOC: -+ case RTM_IEEE80211_REASSOC: -+ case RTM_IEEE80211_DISASSOC: -+ case RTM_IEEE80211_SCAN: -+ break; -+ case RTM_IEEE80211_LEAVE: -+ leave = (struct ieee80211_leave_event *) &ifan[1]; -+ drv_event_disassoc(drv->hapd, leave->iev_addr); -+ break; -+ case RTM_IEEE80211_JOIN: -+#ifdef RTM_IEEE80211_REJOIN -+ case RTM_IEEE80211_REJOIN: -+#endif -+ join = (struct ieee80211_join_event *) &ifan[1]; -+ bsd_new_sta(drv, drv->hapd, join->iev_addr); -+ break; -+ case RTM_IEEE80211_REPLAY: -+ /* ignore */ -+ break; -+ case RTM_IEEE80211_MICHAEL: -+ mic = (struct ieee80211_michael_event *) &ifan[1]; -+ wpa_printf(MSG_DEBUG, -+ "Michael MIC failure wireless event: " -+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix, -+ MAC2STR(mic->iev_src)); -+ os_memset(&data, 0, sizeof(data)); -+ data.michael_mic_failure.unicast = 1; -+ data.michael_mic_failure.src = mic->iev_src; -+ wpa_supplicant_event(drv->hapd, -+ EVENT_MICHAEL_MIC_FAILURE, &data); -+ break; -+ } -+ break; -+ } -+ os_free(buf); -+} -+ -+static void -+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -+{ -+ struct bsd_driver_data *drv = ctx; -+ drv_event_eapol_rx(drv->hapd, src_addr, buf, len); -+} -+ -+static void * -+bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) -+{ -+ struct bsd_driver_data *drv; -+ -+ drv = os_zalloc(sizeof(struct bsd_driver_data)); -+ if (drv == NULL) { -+ printf("Could not allocate memory for bsd driver data\n"); -+ goto bad; -+ } -+ -+ drv->hapd = hapd; -+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->sock < 0) { -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ goto bad; -+ } -+ os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); -+ -+ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, -+ handle_read, drv, 0); -+ if (drv->sock_xmit == NULL) -+ goto bad; -+ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) -+ goto bad; -+ -+ /* mark down during setup */ -+ if (bsd_ctrl_iface(drv, 0) < 0) -+ goto bad; -+ -+ drv->route = socket(PF_ROUTE, SOCK_RAW, 0); -+ if (drv->route < 0) { -+ perror("socket(PF_ROUTE,SOCK_RAW)"); -+ goto bad; -+ } -+ eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, -+ NULL); -+ -+ if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { -+ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", -+ __func__); -+ goto bad; -+ } -+ -+ return drv; -+bad: -+ if (drv->sock_xmit != NULL) -+ l2_packet_deinit(drv->sock_xmit); -+ if (drv->sock >= 0) -+ close(drv->sock); -+ if (drv != NULL) -+ os_free(drv); -+ return NULL; -+} -+ -+ -+static void -+bsd_deinit(void *priv) -+{ -+ struct bsd_driver_data *drv = priv; -+ -+ if (drv->route >= 0) { -+ eloop_unregister_read_sock(drv->route); -+ close(drv->route); -+ } -+ bsd_ctrl_iface(drv, 0); -+ if (drv->sock >= 0) -+ close(drv->sock); -+ if (drv->sock_xmit != NULL) -+ l2_packet_deinit(drv->sock_xmit); -+ os_free(drv); -+} -+ -+#else /* HOSTAPD */ -+ -+static int -+get80211param(struct bsd_driver_data *drv, int op) -+{ -+ struct ieee80211req ireq; -+ -+ if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0) -+ return -1; -+ return ireq.i_val; -+} -+ -+static int -+wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) -+{ -+ struct bsd_driver_data *drv = priv; -+#ifdef SIOCG80211BSSID -+ struct ieee80211_bssid bs; -+ -+ os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); -+ if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) -+ return -1; -+ os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); -+ return 0; -+#else -+ return get80211var(drv, IEEE80211_IOC_BSSID, -+ bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; -+#endif -+} -+ -+static int -+wpa_driver_bsd_get_ssid(void *priv, u8 *ssid) -+{ -+ struct bsd_driver_data *drv = priv; -+ return bsd_get_ssid(drv, ssid, 0); -+} -+ -+static int -+wpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie, -+ size_t wpa_ie_len) -+{ -+#ifdef IEEE80211_IOC_APPIE -+ return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len); -+#else /* IEEE80211_IOC_APPIE */ -+ return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len); -+#endif /* IEEE80211_IOC_APPIE */ -+} -+ -+static int -+wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) -+{ -+ int ret = 0; -+ -+ wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", -+ __FUNCTION__, wpa, privacy); -+ -+ if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) -+ ret = -1; -+ if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0) -+ ret = -1; -+ if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0) -+ ret = -1; -+ -+ return ret; -+} -+ -+static int -+wpa_driver_bsd_set_wpa(void *priv, int enabled) -+{ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); -+ -+ return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); -+} -+ -+static int -+wpa_driver_bsd_set_countermeasures(void *priv, int enabled) -+{ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); -+ return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled); -+} -+ -+ -+static int -+wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled) -+{ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); -+ return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); -+} -+ -+static int -+wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code) -+{ -+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, -+ addr); -+} -+ -+static int -+wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code) -+{ -+ return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, -+ addr); -+} -+ -+static int -+wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) -+{ -+ int authmode; -+ -+ if ((auth_alg & WPA_AUTH_ALG_OPEN) && -+ (auth_alg & WPA_AUTH_ALG_SHARED)) -+ authmode = IEEE80211_AUTH_AUTO; -+ else if (auth_alg & WPA_AUTH_ALG_SHARED) -+ authmode = IEEE80211_AUTH_SHARED; -+ else -+ authmode = IEEE80211_AUTH_OPEN; -+ -+ return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode); -+} -+ -+static void -+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -+{ -+ struct bsd_driver_data *drv = ctx; -+ -+ drv_event_eapol_rx(drv->ctx, src_addr, buf, len); -+} -+ -+static int -+wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) -+{ -+ struct bsd_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ u32 mode; -+ int privacy; -+ int ret = 0; -+ -+ wpa_printf(MSG_DEBUG, -+ "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u" -+ , __func__ -+ , (unsigned int) params->ssid_len, params->ssid -+ , (unsigned int) params->wpa_ie_len -+ , params->pairwise_suite -+ , params->group_suite -+ , params->key_mgmt_suite -+ ); -+ -+ switch (params->mode) { -+ case IEEE80211_MODE_INFRA: -+ mode = 0 /* STA */; -+ break; -+ case IEEE80211_MODE_IBSS: -+ mode = IFM_IEEE80211_IBSS; -+ break; -+ case IEEE80211_MODE_AP: -+ mode = IFM_IEEE80211_HOSTAP; -+ break; -+ default: -+ wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__); -+ return -1; -+ } -+ if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) { -+ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", -+ __func__); -+ return -1; -+ } -+ -+ if (params->mode == IEEE80211_MODE_AP) { -+ drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, -+ handle_read, drv, 0); -+ if (drv->sock_xmit == NULL) -+ return -1; -+ drv->is_ap = 1; -+ return 0; -+ } -+ -+ if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted) -+ < 0) -+ ret = -1; -+ if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0) -+ ret = -1; -+ /* XXX error handling is wrong but unclear what to do... */ -+ if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) -+ return -1; -+ -+ privacy = !(params->pairwise_suite == CIPHER_NONE && -+ params->group_suite == CIPHER_NONE && -+ params->key_mgmt_suite == KEY_MGMT_NONE && -+ params->wpa_ie_len == 0); -+ wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); -+ -+ if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0) -+ return -1; -+ -+ if (params->wpa_ie_len && -+ set80211param(drv, IEEE80211_IOC_WPA, -+ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0) -+ return -1; -+ -+ os_memset(&mlme, 0, sizeof(mlme)); -+ mlme.im_op = IEEE80211_MLME_ASSOC; -+ if (params->ssid != NULL) -+ os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len); -+ mlme.im_ssid_len = params->ssid_len; -+ if (params->bssid != NULL) -+ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); -+ if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0) -+ return -1; -+ return ret; -+} -+ -+static int -+wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) -+{ -+ struct bsd_driver_data *drv = priv; -+#ifdef IEEE80211_IOC_SCAN_MAX_SSID -+ struct ieee80211_scan_req sr; -+ int i; -+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ -+ -+ if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) { -+ wpa_printf(MSG_ERROR, "%s: failed to set operation mode", -+ __func__); -+ return -1; -+ } -+ -+ if (set80211param(drv, IEEE80211_IOC_ROAMING, -+ IEEE80211_ROAMING_MANUAL) < 0) { -+ wpa_printf(MSG_ERROR, "%s: failed to set " -+ "wpa_supplicant-based roaming: %s", __func__, -+ strerror(errno)); -+ return -1; -+ } -+ -+ if (wpa_driver_bsd_set_wpa(drv, 1) < 0) { -+ wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__, -+ strerror(errno)); -+ return -1; -+ } -+ -+ /* NB: interface must be marked UP to do a scan */ -+ if (bsd_ctrl_iface(drv, 1) < 0) -+ return -1; -+ -+#ifdef IEEE80211_IOC_SCAN_MAX_SSID -+ os_memset(&sr, 0, sizeof(sr)); -+ sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE | -+ IEEE80211_IOC_SCAN_NOJOIN; -+ sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; -+ if (params->num_ssids > 0) { -+ sr.sr_nssid = params->num_ssids; -+#if 0 -+ /* Boundary check is done by upper layer */ -+ if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID) -+ sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID; -+#endif -+ -+ /* NB: check scan cache first */ -+ sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK; -+ } -+ for (i = 0; i < sr.sr_nssid; i++) { -+ sr.sr_ssid[i].len = params->ssids[i].ssid_len; -+ os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid, -+ sr.sr_ssid[i].len); -+ } -+ -+ /* NB: net80211 delivers a scan complete event so no need to poll */ -+ return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr)); -+#else /* IEEE80211_IOC_SCAN_MAX_SSID */ -+ /* set desired ssid before scan */ -+ if (bsd_set_ssid(drv, params->ssids[0].ssid, -+ params->ssids[0].ssid_len) < 0) -+ return -1; -+ -+ /* NB: net80211 delivers a scan complete event so no need to poll */ -+ return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0); -+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ -+} -+ -+static void -+wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) -+{ -+ struct bsd_driver_data *drv = sock_ctx; -+ char *buf; -+ struct if_announcemsghdr *ifan; -+ struct if_msghdr *ifm; -+ struct rt_msghdr *rtm; -+ union wpa_event_data event; -+ struct ieee80211_michael_event *mic; -+ struct ieee80211_leave_event *leave; -+ struct ieee80211_join_event *join; -+ int n, len; -+ -+ len = rtbuf_len(); -+ -+ buf = os_malloc(len); -+ if (buf == NULL) { -+ wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__); -+ return; -+ } -+ -+ n = read(sock, buf, len); -+ if (n < 0) { -+ if (errno != EINTR && errno != EAGAIN) -+ wpa_printf(MSG_ERROR, "%s read() failed: %s\n", -+ __func__, strerror(errno)); -+ os_free(buf); -+ return; -+ } -+ -+ rtm = (struct rt_msghdr *) buf; -+ if (rtm->rtm_version != RTM_VERSION) { -+ wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", -+ rtm->rtm_version); -+ os_free(buf); -+ return; -+ } -+ os_memset(&event, 0, sizeof(event)); -+ switch (rtm->rtm_type) { -+ case RTM_IFANNOUNCE: -+ ifan = (struct if_announcemsghdr *) rtm; -+ if (ifan->ifan_index != drv->ifindex) -+ break; -+ os_strlcpy(event.interface_status.ifname, drv->ifname, -+ sizeof(event.interface_status.ifname)); -+ switch (ifan->ifan_what) { -+ case IFAN_DEPARTURE: -+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED; -+ default: -+ os_free(buf); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", -+ event.interface_status.ifname, -+ ifan->ifan_what == IFAN_DEPARTURE ? -+ "removed" : "added"); -+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); -+ break; -+ case RTM_IEEE80211: -+ ifan = (struct if_announcemsghdr *) rtm; -+ if (ifan->ifan_index != drv->ifindex) -+ break; -+ switch (ifan->ifan_what) { -+ case RTM_IEEE80211_ASSOC: -+ case RTM_IEEE80211_REASSOC: -+ if (drv->is_ap) -+ break; -+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); -+ break; -+ case RTM_IEEE80211_DISASSOC: -+ if (drv->is_ap) -+ break; -+ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); -+ break; -+ case RTM_IEEE80211_SCAN: -+ if (drv->is_ap) -+ break; -+ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); -+ break; -+ case RTM_IEEE80211_LEAVE: -+ leave = (struct ieee80211_leave_event *) &ifan[1]; -+ drv_event_disassoc(ctx, leave->iev_addr); -+ break; -+ case RTM_IEEE80211_JOIN: -+#ifdef RTM_IEEE80211_REJOIN -+ case RTM_IEEE80211_REJOIN: -+#endif -+ join = (struct ieee80211_join_event *) &ifan[1]; -+ bsd_new_sta(drv, ctx, join->iev_addr); -+ break; -+ case RTM_IEEE80211_REPLAY: -+ /* ignore */ -+ break; -+ case RTM_IEEE80211_MICHAEL: -+ mic = (struct ieee80211_michael_event *) &ifan[1]; -+ wpa_printf(MSG_DEBUG, -+ "Michael MIC failure wireless event: " -+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix, -+ MAC2STR(mic->iev_src)); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.michael_mic_failure.unicast = -+ !IEEE80211_IS_MULTICAST(mic->iev_dst); -+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, -+ &event); -+ break; -+ } -+ break; -+ case RTM_IFINFO: -+ ifm = (struct if_msghdr *) rtm; -+ if (ifm->ifm_index != drv->ifindex) -+ break; -+ if ((rtm->rtm_flags & RTF_UP) == 0) { -+ os_strlcpy(event.interface_status.ifname, drv->ifname, -+ sizeof(event.interface_status.ifname)); -+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED; -+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", -+ event.interface_status.ifname); -+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); -+ } -+ break; -+ } -+ os_free(buf); -+} -+ -+static void -+wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, -+ struct ieee80211req_scan_result *sr) -+{ -+ struct wpa_scan_res *result, **tmp; -+ size_t extra_len; -+ u8 *pos; -+ -+ extra_len = 2 + sr->isr_ssid_len; -+ extra_len += 2 + sr->isr_nrates; -+ extra_len += 3; /* ERP IE */ -+ extra_len += sr->isr_ie_len; -+ -+ result = os_zalloc(sizeof(*result) + extra_len); -+ if (result == NULL) -+ return; -+ os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN); -+ result->freq = sr->isr_freq; -+ result->beacon_int = sr->isr_intval; -+ result->caps = sr->isr_capinfo; -+ result->qual = sr->isr_rssi; -+ result->noise = sr->isr_noise; -+ -+ pos = (u8 *)(result + 1); -+ -+ *pos++ = WLAN_EID_SSID; -+ *pos++ = sr->isr_ssid_len; -+ os_memcpy(pos, sr + 1, sr->isr_ssid_len); -+ pos += sr->isr_ssid_len; -+ -+ /* -+ * Deal all rates as supported rate. -+ * Because net80211 doesn't report extended supported rate or not. -+ */ -+ *pos++ = WLAN_EID_SUPP_RATES; -+ *pos++ = sr->isr_nrates; -+ os_memcpy(pos, sr->isr_rates, sr->isr_nrates); -+ pos += sr->isr_nrates; -+ -+ *pos++ = WLAN_EID_ERP_INFO; -+ *pos++ = 1; -+ *pos++ = sr->isr_erp; -+ -+ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len); -+ pos += sr->isr_ie_len; -+ -+ result->ie_len = pos - (u8 *)(result + 1); -+ -+ tmp = os_realloc(res->res, -+ (res->num + 1) * sizeof(struct wpa_scan_res *)); -+ if (tmp == NULL) { -+ os_free(result); -+ return; -+ } -+ tmp[res->num++] = result; -+ res->res = tmp; -+} -+ -+struct wpa_scan_results * -+wpa_driver_bsd_get_scan_results2(void *priv) -+{ -+ struct ieee80211req_scan_result *sr; -+ struct wpa_scan_results *res; -+ int len, rest; -+ uint8_t buf[24*1024], *pos; -+ -+ len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); -+ if (len < 0) -+ return NULL; -+ -+ res = os_zalloc(sizeof(*res)); -+ if (res == NULL) -+ return NULL; -+ -+ pos = buf; -+ rest = len; -+ while (rest >= sizeof(struct ieee80211req_scan_result)) { -+ sr = (struct ieee80211req_scan_result *)pos; -+ wpa_driver_bsd_add_scan_entry(res, sr); -+ pos += sr->isr_len; -+ rest -= sr->isr_len; -+ } -+ -+ wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", -+ len, (unsigned long)res->num); -+ -+ return res; -+} -+ -+static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) -+{ -+#ifdef IEEE80211_IOC_DEVCAPS -+/* kernel definitions copied from net80211/ieee80211_var.h */ -+#define IEEE80211_CIPHER_WEP 0 -+#define IEEE80211_CIPHER_TKIP 1 -+#define IEEE80211_CIPHER_AES_CCM 3 -+#define IEEE80211_CRYPTO_WEP (1<capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; -+ if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) -+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -+ -+ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | -+ WPA_DRIVER_CAPA_ENC_WEP104; -+ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; -+ if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; -+ -+ if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) -+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP; -+#undef IEEE80211_CIPHER_WEP -+#undef IEEE80211_CIPHER_TKIP -+#undef IEEE80211_CIPHER_AES_CCM -+#undef IEEE80211_CRYPTO_WEP -+#undef IEEE80211_CRYPTO_TKIP -+#undef IEEE80211_CRYPTO_AES_CCM -+#undef IEEE80211_C_HOSTAP -+#undef IEEE80211_C_WPA1 -+#undef IEEE80211_C_WPA2 -+#else /* IEEE80211_IOC_DEVCAPS */ -+ /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ -+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -+ drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | -+ WPA_DRIVER_CAPA_ENC_WEP104 | -+ WPA_DRIVER_CAPA_ENC_TKIP | -+ WPA_DRIVER_CAPA_ENC_CCMP; -+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP; -+#endif /* IEEE80211_IOC_DEVCAPS */ -+#ifdef IEEE80211_IOC_SCAN_MAX_SSID -+ drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; -+#else /* IEEE80211_IOC_SCAN_MAX_SSID */ -+ drv->capa.max_scan_ssids = 1; -+#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ -+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | -+ WPA_DRIVER_AUTH_SHARED | -+ WPA_DRIVER_AUTH_LEAP; -+ return 0; -+} -+ -+static void * -+wpa_driver_bsd_init(void *ctx, const char *ifname) -+{ -+#define GETPARAM(drv, param, v) \ -+ (((v) = get80211param(drv, param)) != -1) -+ struct bsd_driver_data *drv; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ /* -+ * NB: We require the interface name be mappable to an index. -+ * This implies we do not support having wpa_supplicant -+ * wait for an interface to appear. This seems ok; that -+ * doesn't belong here; it's really the job of devd. -+ */ -+ drv->ifindex = if_nametoindex(ifname); -+ if (drv->ifindex == 0) { -+ wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", -+ __func__, ifname); -+ goto fail1; -+ } -+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->sock < 0) -+ goto fail1; -+ drv->route = socket(PF_ROUTE, SOCK_RAW, 0); -+ if (drv->route < 0) -+ goto fail; -+ eloop_register_read_sock(drv->route, -+ wpa_driver_bsd_event_receive, ctx, drv); -+ -+ drv->ctx = ctx; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ -+ /* Down interface during setup. */ -+ if (bsd_ctrl_iface(drv, 0) < 0) -+ goto fail; -+ -+ if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { -+ wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", -+ __func__, strerror(errno)); -+ goto fail; -+ } -+ if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) { -+ wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s", -+ __func__, strerror(errno)); -+ goto fail; -+ } -+ if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) { -+ wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s", -+ __func__, strerror(errno)); -+ goto fail; -+ } -+ -+ if (wpa_driver_bsd_capa(drv)) -+ goto fail; -+ -+ return drv; -+fail: -+ close(drv->sock); -+fail1: -+ os_free(drv); -+ return NULL; -+#undef GETPARAM -+} -+ -+static void -+wpa_driver_bsd_deinit(void *priv) -+{ -+ struct bsd_driver_data *drv = priv; -+ -+ wpa_driver_bsd_set_wpa(drv, 0); -+ eloop_unregister_read_sock(drv->route); -+ -+ /* NB: mark interface down */ -+ bsd_ctrl_iface(drv, 0); -+ -+ wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); -+ if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) -+ wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", -+ __func__); -+ -+ if (drv->sock_xmit != NULL) -+ l2_packet_deinit(drv->sock_xmit); -+ (void) close(drv->route); /* ioctl socket */ -+ (void) close(drv->sock); /* event socket */ -+ os_free(drv); -+} -+ -+static int -+wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) -+{ -+ struct bsd_driver_data *drv = priv; -+ -+ os_memcpy(capa, &drv->capa, sizeof(*capa)); -+ return 0; -+} -+#endif /* HOSTAPD */ -+ -+ -+const struct wpa_driver_ops wpa_driver_bsd_ops = { -+ .name = "bsd", -+ .desc = "BSD 802.11 support", -+#ifdef HOSTAPD -+ .hapd_init = bsd_init, -+ .hapd_deinit = bsd_deinit, -+ .set_privacy = bsd_set_privacy, -+ .get_seqnum = bsd_get_seqnum, -+ .flush = bsd_flush, -+ .read_sta_data = bsd_read_sta_driver_data, -+ .sta_disassoc = bsd_sta_disassoc, -+ .sta_deauth = bsd_sta_deauth, -+#else /* HOSTAPD */ -+ .init = wpa_driver_bsd_init, -+ .deinit = wpa_driver_bsd_deinit, -+ .get_bssid = wpa_driver_bsd_get_bssid, -+ .get_ssid = wpa_driver_bsd_get_ssid, -+ .set_countermeasures = wpa_driver_bsd_set_countermeasures, -+ .scan2 = wpa_driver_bsd_scan, -+ .get_scan_results2 = wpa_driver_bsd_get_scan_results2, -+ .deauthenticate = wpa_driver_bsd_deauthenticate, -+ .disassociate = wpa_driver_bsd_disassociate, -+ .associate = wpa_driver_bsd_associate, -+ .get_capa = wpa_driver_bsd_get_capa, -+#endif /* HOSTAPD */ -+ .set_freq = bsd_set_freq, -+ .set_key = bsd_set_key, -+ .set_ieee8021x = bsd_set_ieee8021x, -+ .hapd_set_ssid = bsd_set_ssid, -+ .hapd_get_ssid = bsd_get_ssid, -+ .hapd_send_eapol = bsd_send_eapol, -+ .sta_set_flags = bsd_set_sta_authorized, -+ .set_generic_elem = bsd_set_opt_ie, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.c -new file mode 100644 -index 0000000000000..e855c1bf633ca ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.c -@@ -0,0 +1,1648 @@ -+/* -+ * Driver interaction with Linux Host AP driver -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "wireless_copy.h" -+#include "common.h" -+#include "driver.h" -+#include "driver_wext.h" -+#include "eloop.h" -+#include "driver_hostap.h" -+ -+ -+#ifdef HOSTAPD -+ -+#include -+#include -+ -+#include "priv_netlink.h" -+#include "netlink.h" -+#include "linux_ioctl.h" -+#include "common/ieee802_11_defs.h" -+ -+ -+/* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X -+ * frames that might be longer than normal default MTU and they are not -+ * fragmented */ -+#define HOSTAPD_MTU 2290 -+ -+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -+ -+struct hostap_driver_data { -+ struct hostapd_data *hapd; -+ -+ char iface[IFNAMSIZ + 1]; -+ int sock; /* raw packet socket for driver access */ -+ int ioctl_sock; /* socket for ioctl() use */ -+ struct netlink_data *netlink; -+ -+ int we_version; -+ -+ u8 *generic_ie; -+ size_t generic_ie_len; -+ u8 *wps_ie; -+ size_t wps_ie_len; -+}; -+ -+ -+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, -+ int len); -+static int hostap_set_iface_flags(void *priv, int dev_up); -+ -+static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len, -+ u16 stype) -+{ -+ struct ieee80211_hdr *hdr; -+ u16 fc, ethertype; -+ u8 *pos, *sa; -+ size_t left; -+ union wpa_event_data event; -+ -+ if (len < sizeof(struct ieee80211_hdr)) -+ return; -+ -+ hdr = (struct ieee80211_hdr *) buf; -+ fc = le_to_host16(hdr->frame_control); -+ -+ if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) { -+ printf("Not ToDS data frame (fc=0x%04x)\n", fc); -+ return; -+ } -+ -+ sa = hdr->addr2; -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_from_unknown.frame = buf; -+ event.rx_from_unknown.len = len; -+ wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event); -+ -+ pos = (u8 *) (hdr + 1); -+ left = len - sizeof(*hdr); -+ -+ if (left < sizeof(rfc1042_header)) { -+ printf("Too short data frame\n"); -+ return; -+ } -+ -+ if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) { -+ printf("Data frame with no RFC1042 header\n"); -+ return; -+ } -+ pos += sizeof(rfc1042_header); -+ left -= sizeof(rfc1042_header); -+ -+ if (left < 2) { -+ printf("No ethertype in data frame\n"); -+ return; -+ } -+ -+ ethertype = WPA_GET_BE16(pos); -+ pos += 2; -+ left -= 2; -+ switch (ethertype) { -+ case ETH_P_PAE: -+ drv_event_eapol_rx(drv->hapd, sa, pos, left); -+ break; -+ -+ default: -+ printf("Unknown ethertype 0x%04x in data frame\n", ethertype); -+ break; -+ } -+} -+ -+ -+static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf, -+ size_t len, int ok) -+{ -+ struct ieee80211_hdr *hdr; -+ u16 fc; -+ union wpa_event_data event; -+ -+ hdr = (struct ieee80211_hdr *) buf; -+ fc = le_to_host16(hdr->frame_control); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.tx_status.type = WLAN_FC_GET_TYPE(fc); -+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc); -+ event.tx_status.dst = hdr->addr1; -+ event.tx_status.data = buf; -+ event.tx_status.data_len = len; -+ event.tx_status.ack = ok; -+ wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event); -+} -+ -+ -+static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) -+{ -+ struct ieee80211_hdr *hdr; -+ u16 fc, extra_len, type, stype; -+ unsigned char *extra = NULL; -+ size_t data_len = len; -+ int ver; -+ union wpa_event_data event; -+ -+ /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass -+ * these to user space */ -+ if (len < 24) { -+ wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)", -+ (unsigned long) len); -+ return; -+ } -+ -+ hdr = (struct ieee80211_hdr *) buf; -+ fc = le_to_host16(hdr->frame_control); -+ type = WLAN_FC_GET_TYPE(fc); -+ stype = WLAN_FC_GET_STYPE(fc); -+ -+ if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) { -+ wpa_hexdump(MSG_MSGDUMP, "Received management frame", -+ buf, len); -+ } -+ -+ ver = fc & WLAN_FC_PVER; -+ -+ /* protocol version 3 is reserved for indicating extra data after the -+ * payload, version 2 for indicating ACKed frame (TX callbacks), and -+ * version 1 for indicating failed frame (no ACK, TX callbacks) */ -+ if (ver == 3) { -+ u8 *pos = buf + len - 2; -+ extra_len = WPA_GET_LE16(pos); -+ printf("extra data in frame (elen=%d)\n", extra_len); -+ if ((size_t) extra_len + 2 > len) { -+ printf(" extra data overflow\n"); -+ return; -+ } -+ len -= extra_len + 2; -+ extra = buf + len; -+ } else if (ver == 1 || ver == 2) { -+ handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0); -+ return; -+ } else if (ver != 0) { -+ printf("unknown protocol version %d\n", ver); -+ return; -+ } -+ -+ switch (type) { -+ case WLAN_FC_TYPE_MGMT: -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_mgmt.frame = buf; -+ event.rx_mgmt.frame_len = data_len; -+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event); -+ break; -+ case WLAN_FC_TYPE_CTRL: -+ wpa_printf(MSG_DEBUG, "CTRL"); -+ break; -+ case WLAN_FC_TYPE_DATA: -+ wpa_printf(MSG_DEBUG, "DATA"); -+ handle_data(drv, buf, data_len, stype); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "unknown frame type %d", type); -+ break; -+ } -+} -+ -+ -+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct hostap_driver_data *drv = eloop_ctx; -+ int len; -+ unsigned char buf[3000]; -+ -+ len = recv(sock, buf, sizeof(buf), 0); -+ if (len < 0) { -+ perror("recv"); -+ return; -+ } -+ -+ handle_frame(drv, buf, len); -+} -+ -+ -+static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) -+{ -+ struct ifreq ifr; -+ struct sockaddr_ll addr; -+ -+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); -+ if (drv->sock < 0) { -+ perror("socket[PF_PACKET,SOCK_RAW]"); -+ return -1; -+ } -+ -+ if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) { -+ printf("Could not register read socket\n"); -+ return -1; -+ } -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); -+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { -+ perror("ioctl(SIOCGIFINDEX)"); -+ return -1; -+ } -+ -+ if (hostap_set_iface_flags(drv, 1)) { -+ return -1; -+ } -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.sll_family = AF_PACKET; -+ addr.sll_ifindex = ifr.ifr_ifindex; -+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", -+ addr.sll_ifindex); -+ -+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind"); -+ return -1; -+ } -+ -+ return linux_get_ifhwaddr(drv->sock, drv->iface, own_addr); -+} -+ -+ -+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; -+ int res; -+ -+ /* Request TX callback */ -+ hdr->frame_control |= host_to_le16(BIT(1)); -+ res = send(drv->sock, msg, len, 0); -+ hdr->frame_control &= ~host_to_le16(BIT(1)); -+ -+ return res; -+} -+ -+ -+static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, -+ size_t data_len, int encrypt, const u8 *own_addr, -+ u32 flags) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct ieee80211_hdr *hdr; -+ size_t len; -+ u8 *pos; -+ int res; -+ -+ len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len; -+ hdr = os_zalloc(len); -+ if (hdr == NULL) { -+ printf("malloc() failed for hostapd_send_data(len=%lu)\n", -+ (unsigned long) len); -+ return -1; -+ } -+ -+ hdr->frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); -+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); -+ if (encrypt) -+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); -+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); -+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); -+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); -+ -+ pos = (u8 *) (hdr + 1); -+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); -+ pos += sizeof(rfc1042_header); -+ *((u16 *) pos) = htons(ETH_P_PAE); -+ pos += 2; -+ memcpy(pos, data, data_len); -+ -+ res = hostap_send_mlme(drv, (u8 *) hdr, len); -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " -+ "failed: %d (%s)", -+ (unsigned long) len, errno, strerror(errno)); -+ } -+ free(hdr); -+ -+ return res; -+} -+ -+ -+static int hostap_sta_set_flags(void *priv, const u8 *addr, -+ int total_flags, int flags_or, int flags_and) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param param; -+ -+ if (flags_or & WPA_STA_AUTHORIZED) -+ flags_or = BIT(5); /* WLAN_STA_AUTHORIZED */ -+ if (!(flags_and & WPA_STA_AUTHORIZED)) -+ flags_and = ~BIT(5); -+ else -+ flags_and = ~0; -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA; -+ memcpy(param.sta_addr, addr, ETH_ALEN); -+ param.u.set_flags_sta.flags_or = flags_or; -+ param.u.set_flags_sta.flags_and = flags_and; -+ return hostapd_ioctl(drv, ¶m, sizeof(param)); -+} -+ -+ -+static int hostap_set_iface_flags(void *priv, int dev_up) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct ifreq ifr; -+ char ifname[IFNAMSIZ]; -+ -+ os_snprintf(ifname, IFNAMSIZ, "%sap", drv->iface); -+ if (linux_set_iface_flags(drv->ioctl_sock, ifname, dev_up) < 0) -+ return -1; -+ -+ if (dev_up) { -+ memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ ifr.ifr_mtu = HOSTAPD_MTU; -+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { -+ perror("ioctl[SIOCSIFMTU]"); -+ printf("Setting MTU failed - trying to survive with " -+ "current value\n"); -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, -+ int len) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct iwreq iwr; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) param; -+ iwr.u.data.length = len; -+ -+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { -+ perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_hostap_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param *param; -+ u8 *buf; -+ size_t blen; -+ int ret = 0; -+ -+ blen = sizeof(*param) + key_len; -+ buf = os_zalloc(blen); -+ if (buf == NULL) -+ return -1; -+ -+ param = (struct prism2_hostapd_param *) buf; -+ param->cmd = PRISM2_SET_ENCRYPTION; -+ if (addr == NULL) -+ memset(param->sta_addr, 0xff, ETH_ALEN); -+ else -+ memcpy(param->sta_addr, addr, ETH_ALEN); -+ switch (alg) { -+ case WPA_ALG_NONE: -+ os_strlcpy((char *) param->u.crypt.alg, "NONE", -+ HOSTAP_CRYPT_ALG_NAME_LEN); -+ break; -+ case WPA_ALG_WEP: -+ os_strlcpy((char *) param->u.crypt.alg, "WEP", -+ HOSTAP_CRYPT_ALG_NAME_LEN); -+ break; -+ case WPA_ALG_TKIP: -+ os_strlcpy((char *) param->u.crypt.alg, "TKIP", -+ HOSTAP_CRYPT_ALG_NAME_LEN); -+ break; -+ case WPA_ALG_CCMP: -+ os_strlcpy((char *) param->u.crypt.alg, "CCMP", -+ HOSTAP_CRYPT_ALG_NAME_LEN); -+ break; -+ default: -+ os_free(buf); -+ return -1; -+ } -+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; -+ param->u.crypt.idx = key_idx; -+ param->u.crypt.key_len = key_len; -+ memcpy((u8 *) (param + 1), key, key_len); -+ -+ if (hostapd_ioctl(drv, param, blen)) { -+ printf("Failed to set encryption.\n"); -+ ret = -1; -+ } -+ free(buf); -+ -+ return ret; -+} -+ -+ -+static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr, -+ int idx, u8 *seq) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param *param; -+ u8 *buf; -+ size_t blen; -+ int ret = 0; -+ -+ blen = sizeof(*param) + 32; -+ buf = os_zalloc(blen); -+ if (buf == NULL) -+ return -1; -+ -+ param = (struct prism2_hostapd_param *) buf; -+ param->cmd = PRISM2_GET_ENCRYPTION; -+ if (addr == NULL) -+ memset(param->sta_addr, 0xff, ETH_ALEN); -+ else -+ memcpy(param->sta_addr, addr, ETH_ALEN); -+ param->u.crypt.idx = idx; -+ -+ if (hostapd_ioctl(drv, param, blen)) { -+ printf("Failed to get encryption.\n"); -+ ret = -1; -+ } else { -+ memcpy(seq, param->u.crypt.seq, 8); -+ } -+ free(buf); -+ -+ return ret; -+} -+ -+ -+static int hostap_ioctl_prism2param(void *priv, int param, int value) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct iwreq iwr; -+ int *i; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ i = (int *) iwr.u.name; -+ *i++ = param; -+ *i++ = value; -+ -+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { -+ perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int hostap_set_ieee8021x(void *priv, struct wpa_bss_params *params) -+{ -+ struct hostap_driver_data *drv = priv; -+ int enabled = params->enabled; -+ -+ /* enable kernel driver support for IEEE 802.1X */ -+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) { -+ printf("Could not setup IEEE 802.1X support in kernel driver." -+ "\n"); -+ return -1; -+ } -+ -+ if (!enabled) -+ return 0; -+ -+ /* use host driver implementation of encryption to allow -+ * individual keys and passing plaintext EAPOL frames */ -+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) || -+ hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) { -+ printf("Could not setup host-based encryption in kernel " -+ "driver.\n"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int hostap_set_privacy(void *priv, int enabled) -+{ -+ struct hostap_drvier_data *drv = priv; -+ -+ return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, -+ enabled); -+} -+ -+ -+static int hostap_set_ssid(void *priv, const u8 *buf, int len) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct iwreq iwr; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.essid.flags = 1; /* SSID active */ -+ iwr.u.essid.pointer = (caddr_t) buf; -+ iwr.u.essid.length = len + 1; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCSIWESSID]"); -+ printf("len=%d\n", len); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int hostap_flush(void *priv) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param param; -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_FLUSH; -+ return hostapd_ioctl(drv, ¶m, sizeof(param)); -+} -+ -+ -+static int hostap_read_sta_data(void *priv, -+ struct hostap_sta_driver_data *data, -+ const u8 *addr) -+{ -+ struct hostap_driver_data *drv = priv; -+ char buf[1024], line[128], *pos; -+ FILE *f; -+ unsigned long val; -+ -+ memset(data, 0, sizeof(*data)); -+ snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR, -+ drv->iface, MAC2STR(addr)); -+ -+ f = fopen(buf, "r"); -+ if (!f) -+ return -1; -+ /* Need to read proc file with in one piece, so use large enough -+ * buffer. */ -+ setbuffer(f, buf, sizeof(buf)); -+ -+ while (fgets(line, sizeof(line), f)) { -+ pos = strchr(line, '='); -+ if (!pos) -+ continue; -+ *pos++ = '\0'; -+ val = strtoul(pos, NULL, 10); -+ if (strcmp(line, "rx_packets") == 0) -+ data->rx_packets = val; -+ else if (strcmp(line, "tx_packets") == 0) -+ data->tx_packets = val; -+ else if (strcmp(line, "rx_bytes") == 0) -+ data->rx_bytes = val; -+ else if (strcmp(line, "tx_bytes") == 0) -+ data->tx_bytes = val; -+ } -+ -+ fclose(f); -+ -+ return 0; -+} -+ -+ -+static int hostap_sta_add(void *priv, struct hostapd_sta_add_params *params) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param param; -+ int tx_supp_rates = 0; -+ size_t i; -+ -+#define WLAN_RATE_1M BIT(0) -+#define WLAN_RATE_2M BIT(1) -+#define WLAN_RATE_5M5 BIT(2) -+#define WLAN_RATE_11M BIT(3) -+ -+ for (i = 0; i < params->supp_rates_len; i++) { -+ if ((params->supp_rates[i] & 0x7f) == 2) -+ tx_supp_rates |= WLAN_RATE_1M; -+ if ((params->supp_rates[i] & 0x7f) == 4) -+ tx_supp_rates |= WLAN_RATE_2M; -+ if ((params->supp_rates[i] & 0x7f) == 11) -+ tx_supp_rates |= WLAN_RATE_5M5; -+ if ((params->supp_rates[i] & 0x7f) == 22) -+ tx_supp_rates |= WLAN_RATE_11M; -+ } -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_ADD_STA; -+ memcpy(param.sta_addr, params->addr, ETH_ALEN); -+ param.u.add_sta.aid = params->aid; -+ param.u.add_sta.capability = params->capability; -+ param.u.add_sta.tx_supp_rates = tx_supp_rates; -+ return hostapd_ioctl(drv, ¶m, sizeof(param)); -+} -+ -+ -+static int hostap_sta_remove(void *priv, const u8 *addr) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param param; -+ -+ hostap_sta_set_flags(drv, addr, 0, 0, ~WPA_STA_AUTHORIZED); -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_REMOVE_STA; -+ memcpy(param.sta_addr, addr, ETH_ALEN); -+ if (hostapd_ioctl(drv, ¶m, sizeof(param))) { -+ printf("Could not remove station from kernel driver.\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int hostap_get_inact_sec(void *priv, const u8 *addr) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param param; -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; -+ memcpy(param.sta_addr, addr, ETH_ALEN); -+ if (hostapd_ioctl(drv, ¶m, sizeof(param))) { -+ return -1; -+ } -+ -+ return param.u.get_info_sta.inactive_sec; -+} -+ -+ -+static int hostap_sta_clear_stats(void *priv, const u8 *addr) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param param; -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS; -+ memcpy(param.sta_addr, addr, ETH_ALEN); -+ if (hostapd_ioctl(drv, ¶m, sizeof(param))) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv) -+{ -+ struct prism2_hostapd_param *param; -+ int res; -+ size_t blen, elem_len; -+ -+ elem_len = drv->generic_ie_len + drv->wps_ie_len; -+ blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len; -+ if (blen < sizeof(*param)) -+ blen = sizeof(*param); -+ -+ param = os_zalloc(blen); -+ if (param == NULL) -+ return -1; -+ -+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; -+ param->u.generic_elem.len = elem_len; -+ if (drv->generic_ie) { -+ os_memcpy(param->u.generic_elem.data, drv->generic_ie, -+ drv->generic_ie_len); -+ } -+ if (drv->wps_ie) { -+ os_memcpy(¶m->u.generic_elem.data[drv->generic_ie_len], -+ drv->wps_ie, drv->wps_ie_len); -+ } -+ wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE", -+ param->u.generic_elem.data, elem_len); -+ res = hostapd_ioctl(drv, param, blen); -+ -+ os_free(param); -+ -+ return res; -+} -+ -+ -+static int hostap_set_generic_elem(void *priv, -+ const u8 *elem, size_t elem_len) -+{ -+ struct hostap_driver_data *drv = priv; -+ -+ os_free(drv->generic_ie); -+ drv->generic_ie = NULL; -+ drv->generic_ie_len = 0; -+ if (elem) { -+ drv->generic_ie = os_malloc(elem_len); -+ if (drv->generic_ie == NULL) -+ return -1; -+ os_memcpy(drv->generic_ie, elem, elem_len); -+ drv->generic_ie_len = elem_len; -+ } -+ -+ return hostapd_ioctl_set_generic_elem(drv); -+} -+ -+ -+static int hostap_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, -+ const struct wpabuf *proberesp, -+ const struct wpabuf *assocresp) -+{ -+ struct hostap_driver_data *drv = priv; -+ -+ /* -+ * Host AP driver supports only one set of extra IEs, so we need to -+ * use the Probe Response IEs also for Beacon frames since they include -+ * more information. -+ */ -+ -+ os_free(drv->wps_ie); -+ drv->wps_ie = NULL; -+ drv->wps_ie_len = 0; -+ if (proberesp) { -+ drv->wps_ie = os_malloc(wpabuf_len(proberesp)); -+ if (drv->wps_ie == NULL) -+ return -1; -+ os_memcpy(drv->wps_ie, wpabuf_head(proberesp), -+ wpabuf_len(proberesp)); -+ drv->wps_ie_len = wpabuf_len(proberesp); -+ } -+ -+ return hostapd_ioctl_set_generic_elem(drv); -+} -+ -+ -+static void -+hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv, -+ char *custom) -+{ -+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); -+ -+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { -+ char *pos; -+ u8 addr[ETH_ALEN]; -+ pos = strstr(custom, "addr="); -+ if (pos == NULL) { -+ wpa_printf(MSG_DEBUG, -+ "MLME-MICHAELMICFAILURE.indication " -+ "without sender address ignored"); -+ return; -+ } -+ pos += 5; -+ if (hwaddr_aton(pos, addr) == 0) { -+ union wpa_event_data data; -+ os_memset(&data, 0, sizeof(data)); -+ data.michael_mic_failure.unicast = 1; -+ data.michael_mic_failure.src = addr; -+ wpa_supplicant_event(drv->hapd, -+ EVENT_MICHAEL_MIC_FAILURE, &data); -+ } else { -+ wpa_printf(MSG_DEBUG, -+ "MLME-MICHAELMICFAILURE.indication " -+ "with invalid MAC address"); -+ } -+ } -+} -+ -+ -+static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv, -+ char *data, int len) -+{ -+ struct iw_event iwe_buf, *iwe = &iwe_buf; -+ char *pos, *end, *custom, *buf; -+ -+ pos = data; -+ end = data + len; -+ -+ while (pos + IW_EV_LCP_LEN <= end) { -+ /* Event data may be unaligned, so make a local, aligned copy -+ * before processing. */ -+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); -+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", -+ iwe->cmd, iwe->len); -+ if (iwe->len <= IW_EV_LCP_LEN) -+ return; -+ -+ custom = pos + IW_EV_POINT_LEN; -+ if (drv->we_version > 18 && -+ (iwe->cmd == IWEVMICHAELMICFAILURE || -+ iwe->cmd == IWEVCUSTOM)) { -+ /* WE-19 removed the pointer from struct iw_point */ -+ char *dpos = (char *) &iwe_buf.u.data.length; -+ int dlen = dpos - (char *) &iwe_buf; -+ memcpy(dpos, pos + IW_EV_LCP_LEN, -+ sizeof(struct iw_event) - dlen); -+ } else { -+ memcpy(&iwe_buf, pos, sizeof(struct iw_event)); -+ custom += IW_EV_POINT_OFF; -+ } -+ -+ switch (iwe->cmd) { -+ case IWEVCUSTOM: -+ if (custom + iwe->u.data.length > end) -+ return; -+ buf = malloc(iwe->u.data.length + 1); -+ if (buf == NULL) -+ return; -+ memcpy(buf, custom, iwe->u.data.length); -+ buf[iwe->u.data.length] = '\0'; -+ hostapd_wireless_event_wireless_custom(drv, buf); -+ free(buf); -+ break; -+ } -+ -+ pos += iwe->len; -+ } -+} -+ -+ -+static void hostapd_wireless_event_rtm_newlink(void *ctx, -+ struct ifinfomsg *ifi, -+ u8 *buf, size_t len) -+{ -+ struct hostap_driver_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ /* TODO: use ifi->ifi_index to filter out wireless events from other -+ * interfaces */ -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_WIRELESS) { -+ hostapd_wireless_event_wireless( -+ drv, ((char *) attr) + rta_len, -+ attr->rta_len - rta_len); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+ -+ -+static int hostap_get_we_version(struct hostap_driver_data *drv) -+{ -+ struct iw_range *range; -+ struct iwreq iwr; -+ int minlen; -+ size_t buflen; -+ -+ drv->we_version = 0; -+ -+ /* -+ * Use larger buffer than struct iw_range in order to allow the -+ * structure to grow in the future. -+ */ -+ buflen = sizeof(struct iw_range) + 500; -+ range = os_zalloc(buflen); -+ if (range == NULL) -+ return -1; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) range; -+ iwr.u.data.length = buflen; -+ -+ minlen = ((char *) &range->enc_capa) - (char *) range + -+ sizeof(range->enc_capa); -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { -+ perror("ioctl[SIOCGIWRANGE]"); -+ free(range); -+ return -1; -+ } else if (iwr.u.data.length >= minlen && -+ range->we_version_compiled >= 18) { -+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " -+ "WE(source)=%d enc_capa=0x%x", -+ range->we_version_compiled, -+ range->we_version_source, -+ range->enc_capa); -+ drv->we_version = range->we_version_compiled; -+ } -+ -+ free(range); -+ return 0; -+} -+ -+ -+static int hostap_wireless_event_init(struct hostap_driver_data *drv) -+{ -+ struct netlink_config *cfg; -+ -+ hostap_get_we_version(drv); -+ -+ cfg = os_zalloc(sizeof(*cfg)); -+ if (cfg == NULL) -+ return -1; -+ cfg->ctx = drv; -+ cfg->newlink_cb = hostapd_wireless_event_rtm_newlink; -+ drv->netlink = netlink_init(cfg); -+ if (drv->netlink == NULL) { -+ os_free(cfg); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void * hostap_init(struct hostapd_data *hapd, -+ struct wpa_init_params *params) -+{ -+ struct hostap_driver_data *drv; -+ -+ drv = os_zalloc(sizeof(struct hostap_driver_data)); -+ if (drv == NULL) { -+ printf("Could not allocate memory for hostapd driver data\n"); -+ return NULL; -+ } -+ -+ drv->hapd = hapd; -+ drv->ioctl_sock = drv->sock = -1; -+ memcpy(drv->iface, params->ifname, sizeof(drv->iface)); -+ -+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->ioctl_sock < 0) { -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ free(drv); -+ return NULL; -+ } -+ -+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) { -+ printf("Could not enable hostapd mode for interface %s\n", -+ drv->iface); -+ close(drv->ioctl_sock); -+ free(drv); -+ return NULL; -+ } -+ -+ if (hostap_init_sockets(drv, params->own_addr) || -+ hostap_wireless_event_init(drv)) { -+ close(drv->ioctl_sock); -+ free(drv); -+ return NULL; -+ } -+ -+ return drv; -+} -+ -+ -+static void hostap_driver_deinit(void *priv) -+{ -+ struct hostap_driver_data *drv = priv; -+ -+ netlink_deinit(drv->netlink); -+ (void) hostap_set_iface_flags(drv, 0); -+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0); -+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0); -+ -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ -+ if (drv->sock >= 0) -+ close(drv->sock); -+ -+ os_free(drv->generic_ie); -+ os_free(drv->wps_ie); -+ -+ free(drv); -+} -+ -+ -+static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct ieee80211_mgmt mgmt; -+ -+ if (is_broadcast_ether_addr(addr)) { -+ /* -+ * New Prism2.5/3 STA firmware versions seem to have issues -+ * with this broadcast deauth frame. This gets the firmware in -+ * odd state where nothing works correctly, so let's skip -+ * sending this for the hostap driver. -+ */ -+ return 0; -+ } -+ -+ memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DEAUTH); -+ memcpy(mgmt.da, addr, ETH_ALEN); -+ memcpy(mgmt.sa, own_addr, ETH_ALEN); -+ memcpy(mgmt.bssid, own_addr, ETH_ALEN); -+ mgmt.u.deauth.reason_code = host_to_le16(reason); -+ return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + -+ sizeof(mgmt.u.deauth)); -+} -+ -+ -+static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason) -+{ -+ struct hostap_driver_data *drv = priv; -+ struct ieee80211_mgmt mgmt; -+ -+ memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DISASSOC); -+ memcpy(mgmt.da, addr, ETH_ALEN); -+ memcpy(mgmt.sa, own_addr, ETH_ALEN); -+ memcpy(mgmt.bssid, own_addr, ETH_ALEN); -+ mgmt.u.disassoc.reason_code = host_to_le16(reason); -+ return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + -+ sizeof(mgmt.u.disassoc)); -+} -+ -+ -+static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv, -+ u16 *num_modes, -+ u16 *flags) -+{ -+ struct hostapd_hw_modes *mode; -+ int i, clen, rlen; -+ const short chan2freq[14] = { -+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, -+ 2447, 2452, 2457, 2462, 2467, 2472, 2484 -+ }; -+ -+ mode = os_zalloc(sizeof(struct hostapd_hw_modes)); -+ if (mode == NULL) -+ return NULL; -+ -+ *num_modes = 1; -+ *flags = 0; -+ -+ mode->mode = HOSTAPD_MODE_IEEE80211B; -+ mode->num_channels = 14; -+ mode->num_rates = 4; -+ -+ clen = mode->num_channels * sizeof(struct hostapd_channel_data); -+ rlen = mode->num_rates * sizeof(int); -+ -+ mode->channels = os_zalloc(clen); -+ mode->rates = os_zalloc(rlen); -+ if (mode->channels == NULL || mode->rates == NULL) { -+ os_free(mode->channels); -+ os_free(mode->rates); -+ os_free(mode); -+ return NULL; -+ } -+ -+ for (i = 0; i < 14; i++) { -+ mode->channels[i].chan = i + 1; -+ mode->channels[i].freq = chan2freq[i]; -+ /* TODO: Get allowed channel list from the driver */ -+ if (i >= 11) -+ mode->channels[i].flag = HOSTAPD_CHAN_DISABLED; -+ } -+ -+ mode->rates[0] = 10; -+ mode->rates[1] = 20; -+ mode->rates[2] = 55; -+ mode->rates[3] = 110; -+ -+ return mode; -+} -+ -+#else /* HOSTAPD */ -+ -+struct wpa_driver_hostap_data { -+ void *wext; /* private data for driver_wext */ -+ void *ctx; -+ char ifname[IFNAMSIZ + 1]; -+ int sock; -+ int current_mode; /* infra/adhoc */ -+}; -+ -+ -+static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg); -+ -+ -+static int hostapd_ioctl(struct wpa_driver_hostap_data *drv, -+ struct prism2_hostapd_param *param, -+ int len, int show_err) -+{ -+ struct iwreq iwr; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) param; -+ iwr.u.data.length = len; -+ -+ if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { -+ int ret = errno; -+ if (show_err) -+ perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv, -+ const u8 *wpa_ie, size_t wpa_ie_len) -+{ -+ struct prism2_hostapd_param *param; -+ int res; -+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len; -+ if (blen < sizeof(*param)) -+ blen = sizeof(*param); -+ -+ param = os_zalloc(blen); -+ if (param == NULL) -+ return -1; -+ -+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; -+ param->u.generic_elem.len = wpa_ie_len; -+ os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len); -+ res = hostapd_ioctl(drv, param, blen, 1); -+ -+ os_free(param); -+ -+ return res; -+} -+ -+ -+static int prism2param(struct wpa_driver_hostap_data *drv, int param, -+ int value) -+{ -+ struct iwreq iwr; -+ int *i, ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ i = (int *) iwr.u.name; -+ *i++ = param; -+ *i++ = value; -+ -+ if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { -+ perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); -+ ret = -1; -+ } -+ return ret; -+} -+ -+ -+static int wpa_driver_hostap_set_wpa(void *priv, int enabled) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ int ret = 0; -+ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); -+ -+ if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0) -+ ret = -1; -+ if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0) -+ ret = -1; -+ if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0) -+ ret = -1; -+ -+ return ret; -+} -+ -+ -+static void show_set_key_error(struct prism2_hostapd_param *param) -+{ -+ switch (param->u.crypt.err) { -+ case HOSTAP_CRYPT_ERR_UNKNOWN_ALG: -+ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.", -+ param->u.crypt.alg); -+ wpa_printf(MSG_INFO, "You may need to load kernel module to " -+ "register that algorithm."); -+ wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for " -+ "WEP."); -+ break; -+ case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR: -+ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".", -+ MAC2STR(param->sta_addr)); -+ break; -+ case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED: -+ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed."); -+ break; -+ case HOSTAP_CRYPT_ERR_KEY_SET_FAILED: -+ wpa_printf(MSG_INFO, "Key setting failed."); -+ break; -+ case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED: -+ wpa_printf(MSG_INFO, "TX key index setting failed."); -+ break; -+ case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED: -+ wpa_printf(MSG_INFO, "Card configuration failed."); -+ break; -+ } -+} -+ -+ -+static int wpa_driver_hostap_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ struct prism2_hostapd_param *param; -+ u8 *buf; -+ size_t blen; -+ int ret = 0; -+ char *alg_name; -+ -+ switch (alg) { -+ case WPA_ALG_NONE: -+ alg_name = "none"; -+ break; -+ case WPA_ALG_WEP: -+ alg_name = "WEP"; -+ break; -+ case WPA_ALG_TKIP: -+ alg_name = "TKIP"; -+ break; -+ case WPA_ALG_CCMP: -+ alg_name = "CCMP"; -+ break; -+ default: -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu " -+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx, -+ (unsigned long) seq_len, (unsigned long) key_len); -+ -+ if (seq_len > 8) -+ return -2; -+ -+ blen = sizeof(*param) + key_len; -+ buf = os_zalloc(blen); -+ if (buf == NULL) -+ return -1; -+ -+ param = (struct prism2_hostapd_param *) buf; -+ param->cmd = PRISM2_SET_ENCRYPTION; -+ /* TODO: In theory, STA in client mode can use five keys; four default -+ * keys for receiving (with keyidx 0..3) and one individual key for -+ * both transmitting and receiving (keyidx 0) _unicast_ packets. Now, -+ * keyidx 0 is reserved for this unicast use and default keys can only -+ * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported). -+ * This should be fine for more or less all cases, but for completeness -+ * sake, the driver could be enhanced to support the missing key. */ -+#if 0 -+ if (addr == NULL) -+ os_memset(param->sta_addr, 0xff, ETH_ALEN); -+ else -+ os_memcpy(param->sta_addr, addr, ETH_ALEN); -+#else -+ os_memset(param->sta_addr, 0xff, ETH_ALEN); -+#endif -+ os_strlcpy((char *) param->u.crypt.alg, alg_name, -+ HOSTAP_CRYPT_ALG_NAME_LEN); -+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; -+ param->u.crypt.idx = key_idx; -+ if (seq) -+ os_memcpy(param->u.crypt.seq, seq, seq_len); -+ param->u.crypt.key_len = key_len; -+ os_memcpy((u8 *) (param + 1), key, key_len); -+ -+ if (hostapd_ioctl(drv, param, blen, 1)) { -+ wpa_printf(MSG_WARNING, "Failed to set encryption."); -+ show_set_key_error(param); -+ ret = -1; -+ } -+ os_free(buf); -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); -+ return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled); -+} -+ -+ -+static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv, -+ int type) -+{ -+ struct iwreq iwr; -+ int *i, ret = 0; -+ -+ wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ i = (int *) iwr.u.name; -+ *i++ = type; -+ -+ if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) { -+ perror("ioctl[PRISM2_IOCTL_RESET]"); -+ ret = -1; -+ } -+ return ret; -+} -+ -+ -+static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv, -+ const u8 *addr, int cmd, int reason_code) -+{ -+ struct prism2_hostapd_param param; -+ int ret; -+ -+ /* There does not seem to be a better way of deauthenticating or -+ * disassociating with Prism2/2.5/3 than sending the management frame -+ * and then resetting the Port0 to make sure both the AP and the STA -+ * end up in disconnected state. */ -+ os_memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_MLME; -+ os_memcpy(param.sta_addr, addr, ETH_ALEN); -+ param.u.mlme.cmd = cmd; -+ param.u.mlme.reason_code = reason_code; -+ ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1); -+ if (ret == 0) { -+ os_sleep(0, 100000); -+ ret = wpa_driver_hostap_reset(drv, 2); -+ } -+ return ret; -+} -+ -+ -+static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH, -+ reason_code); -+} -+ -+ -+static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC, -+ reason_code); -+} -+ -+ -+static int -+wpa_driver_hostap_associate(void *priv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ int ret = 0; -+ int allow_unencrypted_eapol; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, -+ params->drop_unencrypted) < 0) -+ ret = -1; -+ if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0) -+ ret = -1; -+ if (params->mode != drv->current_mode) { -+ /* At the moment, Host AP driver requires host_roaming=2 for -+ * infrastructure mode and host_roaming=0 for adhoc. */ -+ if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, -+ params->mode == IEEE80211_MODE_IBSS ? 0 : 2) < -+ 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming", -+ __func__); -+ } -+ drv->current_mode = params->mode; -+ } -+ -+ if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, -+ params->key_mgmt_suite != KEY_MGMT_NONE) < 0) -+ ret = -1; -+ if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie, -+ params->wpa_ie_len) < 0) -+ ret = -1; -+ if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0) -+ ret = -1; -+ if (params->freq && -+ wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) -+ ret = -1; -+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len) -+ < 0) -+ ret = -1; -+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) -+ ret = -1; -+ -+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when -+ * not using WPA. IEEE 802.1X specifies that these frames are not -+ * encrypted, but WPA encrypts them when pairwise keys are in use. */ -+ if (params->key_mgmt_suite == KEY_MGMT_802_1X || -+ params->key_mgmt_suite == KEY_MGMT_PSK) -+ allow_unencrypted_eapol = 0; -+ else -+ allow_unencrypted_eapol = 1; -+ -+ if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X, -+ allow_unencrypted_eapol) < 0) { -+ wpa_printf(MSG_DEBUG, "hostap: Failed to configure " -+ "ieee_802_1x param"); -+ /* Ignore this error.. driver_hostap.c can also be used with -+ * other drivers that do not support this prism2_param. */ -+ } -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_hostap_scan(void *priv, -+ struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ struct prism2_hostapd_param param; -+ int ret; -+ const u8 *ssid = params->ssids[0].ssid; -+ size_t ssid_len = params->ssids[0].ssid_len; -+ -+ if (ssid == NULL) { -+ /* Use standard Linux Wireless Extensions ioctl if possible -+ * because some drivers using hostap code in wpa_supplicant -+ * might not support Host AP specific scan request (with SSID -+ * info). */ -+ return wpa_driver_wext_scan(drv->wext, params); -+ } -+ -+ if (ssid_len > 32) -+ ssid_len = 32; -+ -+ os_memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_SCAN_REQ; -+ param.u.scan_req.ssid_len = ssid_len; -+ os_memcpy(param.u.scan_req.ssid, ssid, ssid_len); -+ ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1); -+ -+ /* Not all drivers generate "scan completed" wireless event, so try to -+ * read results after a timeout. */ -+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext, -+ drv->ctx); -+ eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext, -+ drv->ctx); -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ int algs = 0; -+ -+ if (auth_alg & WPA_AUTH_ALG_OPEN) -+ algs |= 1; -+ if (auth_alg & WPA_AUTH_ALG_SHARED) -+ algs |= 2; -+ if (auth_alg & WPA_AUTH_ALG_LEAP) -+ algs |= 4; -+ if (algs == 0) -+ algs = 1; /* at least one algorithm should be set */ -+ -+ return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs); -+} -+ -+ -+static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ return wpa_driver_wext_get_bssid(drv->wext, bssid); -+} -+ -+ -+static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ return wpa_driver_wext_get_ssid(drv->wext, ssid); -+} -+ -+ -+static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ return wpa_driver_wext_get_scan_results(drv->wext); -+} -+ -+ -+static int wpa_driver_hostap_set_operstate(void *priv, int state) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ return wpa_driver_wext_set_operstate(drv->wext, state); -+} -+ -+ -+static void * wpa_driver_hostap_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_hostap_data *drv; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->wext = wpa_driver_wext_init(ctx, ifname); -+ if (drv->wext == NULL) { -+ os_free(drv); -+ return NULL; -+ } -+ -+ drv->ctx = ctx; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->sock < 0) { -+ perror("socket"); -+ wpa_driver_wext_deinit(drv->wext); -+ os_free(drv); -+ return NULL; -+ } -+ -+ if (os_strncmp(ifname, "wlan", 4) == 0) { -+ /* -+ * Host AP driver may use both wlan# and wifi# interface in -+ * wireless events. -+ */ -+ char ifname2[IFNAMSIZ + 1]; -+ os_strlcpy(ifname2, ifname, sizeof(ifname2)); -+ os_memcpy(ifname2, "wifi", 4); -+ wpa_driver_wext_alternative_ifindex(drv->wext, ifname2); -+ } -+ -+ wpa_driver_hostap_set_wpa(drv, 1); -+ -+ return drv; -+} -+ -+ -+static void wpa_driver_hostap_deinit(void *priv) -+{ -+ struct wpa_driver_hostap_data *drv = priv; -+ wpa_driver_hostap_set_wpa(drv, 0); -+ wpa_driver_wext_deinit(drv->wext); -+ close(drv->sock); -+ os_free(drv); -+} -+ -+#endif /* HOSTAPD */ -+ -+ -+const struct wpa_driver_ops wpa_driver_hostap_ops = { -+ .name = "hostap", -+ .desc = "Host AP driver (Intersil Prism2/2.5/3)", -+ .set_key = wpa_driver_hostap_set_key, -+#ifdef HOSTAPD -+ .hapd_init = hostap_init, -+ .hapd_deinit = hostap_driver_deinit, -+ .set_ieee8021x = hostap_set_ieee8021x, -+ .set_privacy = hostap_set_privacy, -+ .get_seqnum = hostap_get_seqnum, -+ .flush = hostap_flush, -+ .set_generic_elem = hostap_set_generic_elem, -+ .read_sta_data = hostap_read_sta_data, -+ .hapd_send_eapol = hostap_send_eapol, -+ .sta_set_flags = hostap_sta_set_flags, -+ .sta_deauth = hostap_sta_deauth, -+ .sta_disassoc = hostap_sta_disassoc, -+ .sta_remove = hostap_sta_remove, -+ .hapd_set_ssid = hostap_set_ssid, -+ .send_mlme = hostap_send_mlme, -+ .sta_add = hostap_sta_add, -+ .get_inact_sec = hostap_get_inact_sec, -+ .sta_clear_stats = hostap_sta_clear_stats, -+ .get_hw_feature_data = hostap_get_hw_feature_data, -+ .set_ap_wps_ie = hostap_set_ap_wps_ie, -+#else /* HOSTAPD */ -+ .get_bssid = wpa_driver_hostap_get_bssid, -+ .get_ssid = wpa_driver_hostap_get_ssid, -+ .set_countermeasures = wpa_driver_hostap_set_countermeasures, -+ .scan2 = wpa_driver_hostap_scan, -+ .get_scan_results2 = wpa_driver_hostap_get_scan_results, -+ .deauthenticate = wpa_driver_hostap_deauthenticate, -+ .disassociate = wpa_driver_hostap_disassociate, -+ .associate = wpa_driver_hostap_associate, -+ .init = wpa_driver_hostap_init, -+ .deinit = wpa_driver_hostap_deinit, -+ .set_operstate = wpa_driver_hostap_set_operstate, -+#endif /* HOSTAPD */ -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.h -new file mode 100644 -index 0000000000000..66b2bb39b849c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_hostap.h -@@ -0,0 +1,216 @@ -+/* -+ * Driver interaction with Linux Host AP driver -+ * Copyright (c) 2002-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef HOSTAP_DRIVER_H -+#define HOSTAP_DRIVER_H -+ -+/* netdevice private ioctls (used, e.g., with iwpriv from user space) */ -+ -+/* New wireless extensions API - SET/GET convention (even ioctl numbers are -+ * root only) -+ */ -+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -+#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) -+#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) -+#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) -+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) -+#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) -+#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) -+#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) -+#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) -+#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) -+#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) -+#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) -+#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) -+ -+/* following are not in SIOCGIWPRIV list; check permission in the driver code -+ */ -+#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) -+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) -+ -+ -+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ -+enum { -+ /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ -+ PRISM2_PARAM_TXRATECTRL = 2, -+ PRISM2_PARAM_BEACON_INT = 3, -+ PRISM2_PARAM_PSEUDO_IBSS = 4, -+ PRISM2_PARAM_ALC = 5, -+ /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ -+ PRISM2_PARAM_DUMP = 7, -+ PRISM2_PARAM_OTHER_AP_POLICY = 8, -+ PRISM2_PARAM_AP_MAX_INACTIVITY = 9, -+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, -+ PRISM2_PARAM_DTIM_PERIOD = 11, -+ PRISM2_PARAM_AP_NULLFUNC_ACK = 12, -+ PRISM2_PARAM_MAX_WDS = 13, -+ PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, -+ PRISM2_PARAM_AP_AUTH_ALGS = 15, -+ PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, -+ PRISM2_PARAM_HOST_ENCRYPT = 17, -+ PRISM2_PARAM_HOST_DECRYPT = 18, -+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, -+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, -+ PRISM2_PARAM_HOST_ROAMING = 21, -+ PRISM2_PARAM_BCRX_STA_KEY = 22, -+ PRISM2_PARAM_IEEE_802_1X = 23, -+ PRISM2_PARAM_ANTSEL_TX = 24, -+ PRISM2_PARAM_ANTSEL_RX = 25, -+ PRISM2_PARAM_MONITOR_TYPE = 26, -+ PRISM2_PARAM_WDS_TYPE = 27, -+ PRISM2_PARAM_HOSTSCAN = 28, -+ PRISM2_PARAM_AP_SCAN = 29, -+ PRISM2_PARAM_ENH_SEC = 30, -+ PRISM2_PARAM_IO_DEBUG = 31, -+ PRISM2_PARAM_BASIC_RATES = 32, -+ PRISM2_PARAM_OPER_RATES = 33, -+ PRISM2_PARAM_HOSTAPD = 34, -+ PRISM2_PARAM_HOSTAPD_STA = 35, -+ PRISM2_PARAM_WPA = 36, -+ PRISM2_PARAM_PRIVACY_INVOKED = 37, -+ PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, -+ PRISM2_PARAM_DROP_UNENCRYPTED = 39, -+ PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, -+}; -+ -+enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, -+ HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; -+ -+ -+/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ -+enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, -+ AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, -+ AP_MAC_CMD_KICKALL = 4 }; -+ -+ -+/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ -+enum { -+ PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, -+ /* Note! Old versions of prism2_srec have a fatal error in CRC-16 -+ * calculation, which will corrupt all non-volatile downloads. -+ * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to -+ * prevent use of old versions of prism2_srec for non-volatile -+ * download. */ -+ PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, -+ PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, -+ /* Persistent versions of volatile download commands (keep firmware -+ * data in memory and automatically re-download after hw_reset */ -+ PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, -+ PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, -+}; -+ -+struct prism2_download_param { -+ u32 dl_cmd; -+ u32 start_addr; -+ u32 num_areas; -+ struct prism2_download_area { -+ u32 addr; /* wlan card address */ -+ u32 len; -+ caddr_t ptr; /* pointer to data in user space */ -+ } data[0]; -+}; -+ -+#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 -+#define PRISM2_MAX_DOWNLOAD_LEN 262144 -+ -+ -+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ -+enum { -+ PRISM2_HOSTAPD_FLUSH = 1, -+ PRISM2_HOSTAPD_ADD_STA = 2, -+ PRISM2_HOSTAPD_REMOVE_STA = 3, -+ PRISM2_HOSTAPD_GET_INFO_STA = 4, -+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ -+ PRISM2_SET_ENCRYPTION = 6, -+ PRISM2_GET_ENCRYPTION = 7, -+ PRISM2_HOSTAPD_SET_FLAGS_STA = 8, -+ PRISM2_HOSTAPD_GET_RID = 9, -+ PRISM2_HOSTAPD_SET_RID = 10, -+ PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, -+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, -+ PRISM2_HOSTAPD_MLME = 13, -+ PRISM2_HOSTAPD_SCAN_REQ = 14, -+ PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, -+}; -+ -+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 -+#define PRISM2_HOSTAPD_RID_HDR_LEN \ -+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) -+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ -+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) -+ -+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl() -+ */ -+#define HOSTAP_CRYPT_ALG_NAME_LEN 16 -+ -+ -+struct prism2_hostapd_param { -+ u32 cmd; -+ u8 sta_addr[ETH_ALEN]; -+ union { -+ struct { -+ u16 aid; -+ u16 capability; -+ u8 tx_supp_rates; -+ } add_sta; -+ struct { -+ u32 inactive_sec; -+ } get_info_sta; -+ struct { -+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; -+ u32 flags; -+ u32 err; -+ u8 idx; -+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ -+ u16 key_len; -+ u8 key[0]; -+ } crypt; -+ struct { -+ u32 flags_and; -+ u32 flags_or; -+ } set_flags_sta; -+ struct { -+ u16 rid; -+ u16 len; -+ u8 data[0]; -+ } rid; -+ struct { -+ u8 len; -+ u8 data[0]; -+ } generic_elem; -+ struct { -+#define MLME_STA_DEAUTH 0 -+#define MLME_STA_DISASSOC 1 -+ u16 cmd; -+ u16 reason_code; -+ } mlme; -+ struct { -+ u8 ssid_len; -+ u8 ssid[32]; -+ } scan_req; -+ } u; -+}; -+ -+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) -+#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) -+ -+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 -+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 -+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 -+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 -+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 -+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 -+ -+#endif /* HOSTAP_DRIVER_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_iphone.m b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_iphone.m -new file mode 100644 -index 0000000000000..8213fdacc32e8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_iphone.m -@@ -0,0 +1,466 @@ -+/* -+ * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#define Boolean __DummyBoolean -+#include -+#undef Boolean -+ -+#include "common.h" -+#include "driver.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+ -+#include "MobileApple80211.h" -+ -+struct wpa_driver_iphone_data { -+ void *ctx; -+ Apple80211Ref wireless_ctx; -+ CFArrayRef scan_results; -+ int ctrl_power; -+}; -+ -+ -+static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key) -+{ -+ const void *res; -+ CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key, -+ kCFStringEncodingMacRoman); -+ if (str == NULL) -+ return NULL; -+ -+ res = CFDictionaryGetValue(dict, str); -+ CFRelease(str); -+ return res; -+} -+ -+ -+static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_iphone_data *drv = priv; -+ CFDataRef data; -+ int err, len; -+ -+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0, -+ &data); -+ if (err != 0) { -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) " -+ "failed: %d", err); -+ return -1; -+ } -+ -+ len = CFDataGetLength(data); -+ if (len > 32) { -+ CFRelease(data); -+ return -1; -+ } -+ os_memcpy(ssid, CFDataGetBytePtr(data), len); -+ CFRelease(data); -+ -+ return len; -+} -+ -+ -+static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_iphone_data *drv = priv; -+ CFStringRef data; -+ int err; -+ int a1, a2, a3, a4, a5, a6; -+ -+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0, -+ &data); -+ if (err != 0) { -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) " -+ "failed: %d", err); -+ return -1; -+ } -+ -+ sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman), -+ "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6); -+ bssid[0] = a1; -+ bssid[1] = a2; -+ bssid[2] = a3; -+ bssid[3] = a4; -+ bssid[4] = a5; -+ bssid[5] = a6; -+ -+ CFRelease(data); -+ -+ return 0; -+} -+ -+ -+static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+} -+ -+ -+static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len) -+{ -+ struct wpa_driver_iphone_data *drv = priv; -+ int err; -+ -+ if (drv->scan_results) { -+ CFRelease(drv->scan_results); -+ drv->scan_results = NULL; -+ } -+ -+ err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d", -+ err); -+ return -1; -+ } -+ -+ eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv, -+ drv->ctx); -+ return 0; -+} -+ -+ -+static int wpa_driver_iphone_get_scan_results(void *priv, -+ struct wpa_scan_result *results, -+ size_t max_size) -+{ -+ struct wpa_driver_iphone_data *drv = priv; -+ size_t i, num; -+ -+ if (drv->scan_results == NULL) -+ return 0; -+ -+ num = CFArrayGetCount(drv->scan_results); -+ if (num > max_size) -+ num = max_size; -+ os_memset(results, 0, num * sizeof(struct wpa_scan_result)); -+ -+ for (i = 0; i < num; i++) { -+ struct wpa_scan_result *res = &results[i]; -+ CFDictionaryRef dict = -+ CFArrayGetValueAtIndex(drv->scan_results, i); -+ CFDataRef data; -+ CFStringRef str; -+ CFNumberRef num; -+ int val; -+ -+ data = cfdict_get_key_str(dict, "SSID"); -+ if (data) { -+ res->ssid_len = CFDataGetLength(data); -+ if (res->ssid_len > 32) -+ res->ssid_len = 32; -+ os_memcpy(res->ssid, CFDataGetBytePtr(data), -+ res->ssid_len); -+ } -+ -+ str = cfdict_get_key_str(dict, "BSSID"); -+ if (str) { -+ int a1, a2, a3, a4, a5, a6; -+ sscanf(CFStringGetCStringPtr( -+ str, kCFStringEncodingMacRoman), -+ "%x:%x:%x:%x:%x:%x", -+ &a1, &a2, &a3, &a4, &a5, &a6); -+ res->bssid[0] = a1; -+ res->bssid[1] = a2; -+ res->bssid[2] = a3; -+ res->bssid[3] = a4; -+ res->bssid[4] = a5; -+ res->bssid[5] = a6; -+ } -+ -+ num = cfdict_get_key_str(dict, "CAPABILITIES"); -+ if (num) { -+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) -+ res->caps = val; -+ } -+ -+ num = cfdict_get_key_str(dict, "CHANNEL"); -+ if (num) { -+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) -+ res->freq = 2407 + val * 5; -+ } -+ -+ num = cfdict_get_key_str(dict, "RSSI"); -+ if (num) { -+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) -+ res->level = val; -+ } -+ -+ num = cfdict_get_key_str(dict, "NOISE"); -+ if (num) { -+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) -+ res->noise = val; -+ } -+ -+ data = cfdict_get_key_str(dict, "IE"); -+ if (data) { -+ u8 *ptr = (u8 *) CFDataGetBytePtr(data); -+ int len = CFDataGetLength(data); -+ u8 *pos = ptr, *end = ptr + len; -+ -+ while (pos + 2 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == WLAN_EID_RSN && -+ pos[1] <= SSID_MAX_WPA_IE_LEN) { -+ os_memcpy(res->rsn_ie, pos, -+ 2 + pos[1]); -+ res->rsn_ie_len = 2 + pos[1]; -+ } -+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && -+ pos[1] > 4 && pos[2] == 0x00 && -+ pos[3] == 0x50 && pos[4] == 0xf2 && -+ pos[5] == 0x01) { -+ os_memcpy(res->wpa_ie, pos, -+ 2 + pos[1]); -+ res->wpa_ie_len = 2 + pos[1]; -+ } -+ -+ pos = pos + 2 + pos[1]; -+ } -+ } -+ } -+ -+ return num; -+} -+ -+ -+static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_iphone_data *drv = eloop_ctx; -+ u8 bssid[ETH_ALEN]; -+ -+ if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) { -+ eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout, -+ drv, drv->ctx); -+ return; -+ } -+ -+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL); -+} -+ -+ -+static int wpa_driver_iphone_associate( -+ void *priv, struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_iphone_data *drv = priv; -+ int i, num, err; -+ size_t ssid_len; -+ CFDictionaryRef bss = NULL; -+ -+ /* -+ * TODO: Consider generating parameters instead of just using an entry -+ * from scan results in order to support ap_scan=2. -+ */ -+ -+ if (drv->scan_results == NULL) { -+ wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot " -+ "associate"); -+ return -1; -+ } -+ -+ num = CFArrayGetCount(drv->scan_results); -+ -+ for (i = 0; i < num; i++) { -+ CFDictionaryRef dict = -+ CFArrayGetValueAtIndex(drv->scan_results, i); -+ CFDataRef data; -+ -+ data = cfdict_get_key_str(dict, "SSID"); -+ if (data == NULL) -+ continue; -+ -+ ssid_len = CFDataGetLength(data); -+ if (ssid_len != params->ssid_len || -+ os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len) -+ != 0) -+ continue; -+ -+ bss = dict; -+ break; -+ } -+ -+ if (bss == NULL) { -+ wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan " -+ "results - cannot associate"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found " -+ "from scan results"); -+ -+ err = Apple80211Associate(drv->wireless_ctx, bss, NULL); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: " -+ "%d", err); -+ return -1; -+ } -+ -+ /* -+ * Driver is actually already associated; report association from an -+ * eloop callback. -+ */ -+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx); -+ eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv, -+ drv->ctx); -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, const u8 *seq, -+ size_t seq_len, const u8 *key, -+ size_t key_len) -+{ -+ /* -+ * TODO: Need to either support configuring PMK for 4-way handshake or -+ * PTK for TKIP/CCMP. -+ */ -+ return -1; -+} -+ -+ -+static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa) -+{ -+ os_memset(capa, 0, sizeof(*capa)); -+ -+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | -+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; -+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | -+ WPA_DRIVER_AUTH_LEAP; -+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; -+ -+ return 0; -+} -+ -+ -+static void * wpa_driver_iphone_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_iphone_data *drv; -+ int err; -+ char power; -+ CFStringRef name; -+ CFDictionaryRef dict; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->ctx = ctx; -+ err = Apple80211Open(&drv->wireless_ctx); -+ if (err) { -+ wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d", -+ err); -+ os_free(drv); -+ return NULL; -+ } -+ -+ name = CFStringCreateWithCString(kCFAllocatorDefault, ifname, -+ kCFStringEncodingISOLatin1); -+ if (name == NULL) { -+ wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed"); -+ Apple80211Close(drv->wireless_ctx); -+ os_free(drv); -+ return NULL; -+ } -+ -+ err = Apple80211BindToInterface(drv->wireless_ctx, name); -+ CFRelease(name); -+ -+ if (err) { -+ wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface " -+ "failed: %d", err); -+ Apple80211Close(drv->wireless_ctx); -+ os_free(drv); -+ return NULL; -+ } -+ -+ err = Apple80211GetPower(drv->wireless_ctx, &power); -+ if (err) -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d", -+ err); -+ -+ wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power); -+ -+ if (!power) { -+ drv->ctrl_power = 1; -+ err = Apple80211SetPower(drv->wireless_ctx, 1); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower " -+ "failed: %d", err); -+ Apple80211Close(drv->wireless_ctx); -+ os_free(drv); -+ return NULL; -+ } -+ } -+ -+ err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict); -+ if (err == 0) { -+ CFShow(dict); -+ CFRelease(dict); -+ } else { -+ printf("Apple80211GetInfoCopy: %d\n", err); -+ } -+ -+ return drv; -+} -+ -+ -+static void wpa_driver_iphone_deinit(void *priv) -+{ -+ struct wpa_driver_iphone_data *drv = priv; -+ int err; -+ -+ eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx); -+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx); -+ -+ if (drv->ctrl_power) { -+ wpa_printf(MSG_DEBUG, "iPhone: Power down the interface"); -+ err = Apple80211SetPower(drv->wireless_ctx, 0); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) " -+ "failed: %d", err); -+ } -+ } -+ -+ err = Apple80211Close(drv->wireless_ctx); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d", -+ err); -+ } -+ -+ if (drv->scan_results) -+ CFRelease(drv->scan_results); -+ -+ os_free(drv); -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_iphone_ops = { -+ .name = "iphone", -+ .desc = "iPhone/iPod touch Apple80211 driver", -+ .get_ssid = wpa_driver_iphone_get_ssid, -+ .get_bssid = wpa_driver_iphone_get_bssid, -+ .init = wpa_driver_iphone_init, -+ .deinit = wpa_driver_iphone_deinit, -+ .scan = wpa_driver_iphone_scan, -+ .get_scan_results = wpa_driver_iphone_get_scan_results, -+ .associate = wpa_driver_iphone_associate, -+ .set_key = wpa_driver_iphone_set_key, -+ .get_capa = wpa_driver_iphone_get_capa, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_madwifi.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_madwifi.c -new file mode 100644 -index 0000000000000..630fbf4c53bca ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_madwifi.c -@@ -0,0 +1,1856 @@ -+/* -+ * WPA Supplicant - driver interaction with MADWIFI 802.11 driver -+ * Copyright (c) 2004, Sam Leffler -+ * Copyright (c) 2004, Video54 Technologies -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * While this driver wrapper supports both AP (hostapd) and station -+ * (wpa_supplicant) operations, the station side is deprecated and -+ * driver_wext.c should be used instead. This driver wrapper should only be -+ * used with hostapd for AP mode functionality. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "driver.h" -+#include "driver_wext.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "wireless_copy.h" -+ -+/* -+ * Avoid conflicts with wpa_supplicant definitions by undefining a definition. -+ */ -+#undef WME_OUI_TYPE -+ -+#include -+#include -+#ifdef WME_NUM_AC -+/* Assume this is built against BSD branch of madwifi driver. */ -+#define MADWIFI_BSD -+#include -+#endif /* WME_NUM_AC */ -+#include -+#include -+ -+#ifdef CONFIG_WPS -+#ifdef IEEE80211_IOCTL_FILTERFRAME -+#include -+ -+#ifndef ETH_P_80211_RAW -+#define ETH_P_80211_RAW 0x0019 -+#endif -+#endif /* IEEE80211_IOCTL_FILTERFRAME */ -+#endif /* CONFIG_WPS */ -+ -+/* -+ * Avoid conflicts with hostapd definitions by undefining couple of defines -+ * from madwifi header files. -+ */ -+#undef RSN_VERSION -+#undef WPA_VERSION -+#undef WPA_OUI_TYPE -+#undef WME_OUI_TYPE -+ -+ -+#ifdef IEEE80211_IOCTL_SETWMMPARAMS -+/* Assume this is built against madwifi-ng */ -+#define MADWIFI_NG -+#endif /* IEEE80211_IOCTL_SETWMMPARAMS */ -+ -+#define WPA_KEY_RSC_LEN 8 -+ -+#ifdef HOSTAPD -+ -+#include "priv_netlink.h" -+#include "netlink.h" -+#include "linux_ioctl.h" -+#include "l2_packet/l2_packet.h" -+ -+ -+struct madwifi_driver_data { -+ struct hostapd_data *hapd; /* back pointer */ -+ -+ char iface[IFNAMSIZ + 1]; -+ int ifindex; -+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */ -+ struct l2_packet_data *sock_recv; /* raw packet recv socket */ -+ int ioctl_sock; /* socket for ioctl() use */ -+ struct netlink_data *netlink; -+ int we_version; -+ u8 acct_mac[ETH_ALEN]; -+ struct hostap_sta_driver_data acct_data; -+ -+ struct l2_packet_data *sock_raw; /* raw 802.11 management frames */ -+}; -+ -+static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code); -+ -+static int -+set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len) -+{ -+ struct iwreq iwr; -+ int do_inline = len < IFNAMSIZ; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+#ifdef IEEE80211_IOCTL_FILTERFRAME -+ /* FILTERFRAME must be NOT inline, regardless of size. */ -+ if (op == IEEE80211_IOCTL_FILTERFRAME) -+ do_inline = 0; -+#endif /* IEEE80211_IOCTL_FILTERFRAME */ -+ if (op == IEEE80211_IOCTL_SET_APPIEBUF) -+ do_inline = 0; -+ if (do_inline) { -+ /* -+ * Argument data fits inline; put it there. -+ */ -+ memcpy(iwr.u.name, data, len); -+ } else { -+ /* -+ * Argument data too big for inline transfer; setup a -+ * parameter block instead; the kernel will transfer -+ * the data for the driver. -+ */ -+ iwr.u.data.pointer = data; -+ iwr.u.data.length = len; -+ } -+ -+ if (ioctl(drv->ioctl_sock, op, &iwr) < 0) { -+#ifdef MADWIFI_NG -+ int first = IEEE80211_IOCTL_SETPARAM; -+ static const char *opnames[] = { -+ "ioctl[IEEE80211_IOCTL_SETPARAM]", -+ "ioctl[IEEE80211_IOCTL_GETPARAM]", -+ "ioctl[IEEE80211_IOCTL_SETMODE]", -+ "ioctl[IEEE80211_IOCTL_GETMODE]", -+ "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]", -+ "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]", -+ "ioctl[IEEE80211_IOCTL_SETCHANLIST]", -+ "ioctl[IEEE80211_IOCTL_GETCHANLIST]", -+ "ioctl[IEEE80211_IOCTL_CHANSWITCH]", -+ "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]", -+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]", -+ "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]", -+ "ioctl[IEEE80211_IOCTL_FILTERFRAME]", -+ "ioctl[IEEE80211_IOCTL_GETCHANINFO]", -+ "ioctl[IEEE80211_IOCTL_SETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_GETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_SETMLME]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_SETKEY]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_DELKEY]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_ADDMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_DELMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_WDSMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_WDSDELMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_KICKMAC]", -+ }; -+#else /* MADWIFI_NG */ -+ int first = IEEE80211_IOCTL_SETPARAM; -+ static const char *opnames[] = { -+ "ioctl[IEEE80211_IOCTL_SETPARAM]", -+ "ioctl[IEEE80211_IOCTL_GETPARAM]", -+ "ioctl[IEEE80211_IOCTL_SETKEY]", -+ "ioctl[SIOCIWFIRSTPRIV+3]", -+ "ioctl[IEEE80211_IOCTL_DELKEY]", -+ "ioctl[SIOCIWFIRSTPRIV+5]", -+ "ioctl[IEEE80211_IOCTL_SETMLME]", -+ "ioctl[SIOCIWFIRSTPRIV+7]", -+ "ioctl[IEEE80211_IOCTL_SETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_GETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_ADDMAC]", -+ "ioctl[SIOCIWFIRSTPRIV+11]", -+ "ioctl[IEEE80211_IOCTL_DELMAC]", -+ "ioctl[SIOCIWFIRSTPRIV+13]", -+ "ioctl[IEEE80211_IOCTL_CHANLIST]", -+ "ioctl[SIOCIWFIRSTPRIV+15]", -+ "ioctl[IEEE80211_IOCTL_GETRSN]", -+ "ioctl[SIOCIWFIRSTPRIV+17]", -+ "ioctl[IEEE80211_IOCTL_GETKEY]", -+ }; -+#endif /* MADWIFI_NG */ -+ int idx = op - first; -+ if (first <= op && -+ idx < (int) (sizeof(opnames) / sizeof(opnames[0])) && -+ opnames[idx]) -+ perror(opnames[idx]); -+ else -+ perror("ioctl[unknown???]"); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+set80211param(struct madwifi_driver_data *drv, int op, int arg) -+{ -+ struct iwreq iwr; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.mode = op; -+ memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg)); -+ -+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { -+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); -+ wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d " -+ "arg %d)", __func__, op, arg); -+ return -1; -+ } -+ return 0; -+} -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+static const char * -+ether_sprintf(const u8 *addr) -+{ -+ static char buf[sizeof(MACSTR)]; -+ -+ if (addr != NULL) -+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); -+ else -+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); -+ return buf; -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+/* -+ * Configure WPA parameters. -+ */ -+static int -+madwifi_configure_wpa(struct madwifi_driver_data *drv, -+ struct wpa_bss_params *params) -+{ -+ int v; -+ -+ switch (params->wpa_group) { -+ case WPA_CIPHER_CCMP: -+ v = IEEE80211_CIPHER_AES_CCM; -+ break; -+ case WPA_CIPHER_TKIP: -+ v = IEEE80211_CIPHER_TKIP; -+ break; -+ case WPA_CIPHER_WEP104: -+ v = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_CIPHER_WEP40: -+ v = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_CIPHER_NONE: -+ v = IEEE80211_CIPHER_NONE; -+ break; -+ default: -+ wpa_printf(MSG_ERROR, "Unknown group key cipher %u", -+ params->wpa_group); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v); -+ if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) { -+ printf("Unable to set group key cipher to %u\n", v); -+ return -1; -+ } -+ if (v == IEEE80211_CIPHER_WEP) { -+ /* key length is done only for specific ciphers */ -+ v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); -+ if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) { -+ printf("Unable to set group key length to %u\n", v); -+ return -1; -+ } -+ } -+ -+ v = 0; -+ if (params->wpa_pairwise & WPA_CIPHER_CCMP) -+ v |= 1<wpa_pairwise & WPA_CIPHER_TKIP) -+ v |= 1<wpa_pairwise & WPA_CIPHER_NONE) -+ v |= 1<wpa_key_mgmt); -+ if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, -+ params->wpa_key_mgmt)) { -+ printf("Unable to set key management algorithms to 0x%x\n", -+ params->wpa_key_mgmt); -+ return -1; -+ } -+ -+ v = 0; -+ if (params->rsn_preauth) -+ v |= BIT(0); -+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", -+ __func__, params->rsn_preauth); -+ if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) { -+ printf("Unable to set RSN capabilities to 0x%x\n", v); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa); -+ if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) { -+ printf("Unable to set WPA to %u\n", params->wpa); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params) -+{ -+ struct madwifi_driver_data *drv = priv; -+ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); -+ -+ if (!params->enabled) { -+ /* XXX restore state */ -+ return set80211param(priv, IEEE80211_PARAM_AUTHMODE, -+ IEEE80211_AUTH_AUTO); -+ } -+ if (!params->wpa && !params->ieee802_1x) { -+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, -+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!"); -+ return -1; -+ } -+ if (params->wpa && madwifi_configure_wpa(drv, params) != 0) { -+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, -+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); -+ return -1; -+ } -+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE, -+ (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { -+ hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER, -+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+madwifi_set_privacy(void *priv, int enabled) -+{ -+ struct madwifi_driver_data *drv = priv; -+ -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); -+ -+ return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled); -+} -+ -+static int -+madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d", -+ __func__, ether_sprintf(addr), authorized); -+ -+ if (authorized) -+ mlme.im_op = IEEE80211_MLME_AUTHORIZE; -+ else -+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE; -+ mlme.im_reason = 0; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR, -+ __func__, authorized ? "" : "un", MAC2STR(addr)); -+ } -+ -+ return ret; -+} -+ -+static int -+madwifi_sta_set_flags(void *priv, const u8 *addr, -+ int total_flags, int flags_or, int flags_and) -+{ -+ /* For now, only support setting Authorized flag */ -+ if (flags_or & WPA_STA_AUTHORIZED) -+ return madwifi_set_sta_authorized(priv, addr, 1); -+ if (!(flags_and & WPA_STA_AUTHORIZED)) -+ return madwifi_set_sta_authorized(priv, addr, 0); -+ return 0; -+} -+ -+static int -+madwifi_del_key(void *priv, const u8 *addr, int key_idx) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct ieee80211req_del_key wk; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d", -+ __func__, ether_sprintf(addr), key_idx); -+ -+ memset(&wk, 0, sizeof(wk)); -+ if (addr != NULL) { -+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE; -+ } else { -+ wk.idk_keyix = key_idx; -+ } -+ -+ ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s" -+ " key_idx %d)", __func__, ether_sprintf(addr), -+ key_idx); -+ } -+ -+ return ret; -+} -+ -+static int -+wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, -+ const u8 *addr, int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct ieee80211req_key wk; -+ u_int8_t cipher; -+ int ret; -+ -+ if (alg == WPA_ALG_NONE) -+ return madwifi_del_key(drv, addr, key_idx); -+ -+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d", -+ __func__, alg, ether_sprintf(addr), key_idx); -+ -+ if (alg == WPA_ALG_WEP) -+ cipher = IEEE80211_CIPHER_WEP; -+ else if (alg == WPA_ALG_TKIP) -+ cipher = IEEE80211_CIPHER_TKIP; -+ else if (alg == WPA_ALG_CCMP) -+ cipher = IEEE80211_CIPHER_AES_CCM; -+ else { -+ printf("%s: unknown/unsupported algorithm %d\n", -+ __func__, alg); -+ return -1; -+ } -+ -+ if (key_len > sizeof(wk.ik_keydata)) { -+ printf("%s: key length %lu too big\n", __func__, -+ (unsigned long) key_len); -+ return -3; -+ } -+ -+ memset(&wk, 0, sizeof(wk)); -+ wk.ik_type = cipher; -+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; -+ if (addr == NULL || is_broadcast_ether_addr(addr)) { -+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = key_idx; -+ wk.ik_flags |= IEEE80211_KEY_DEFAULT; -+ } else { -+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = IEEE80211_KEYIX_NONE; -+ } -+ wk.ik_keylen = key_len; -+ memcpy(wk.ik_keydata, key, key_len); -+ -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s" -+ " key_idx %d alg %d key_len %lu set_tx %d)", -+ __func__, ether_sprintf(wk.ik_macaddr), key_idx, -+ alg, (unsigned long) key_len, set_tx); -+ } -+ -+ return ret; -+} -+ -+ -+static int -+madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, -+ u8 *seq) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct ieee80211req_key wk; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", -+ __func__, ether_sprintf(addr), idx); -+ -+ memset(&wk, 0, sizeof(wk)); -+ if (addr == NULL) -+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); -+ else -+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = idx; -+ -+ if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data " -+ "(addr " MACSTR " key_idx %d)", -+ __func__, MAC2STR(wk.ik_macaddr), idx); -+ return -1; -+ } -+ -+#ifdef WORDS_BIGENDIAN -+ { -+ /* -+ * wk.ik_keytsc is in host byte order (big endian), need to -+ * swap it to match with the byte order used in WPA. -+ */ -+ int i; -+ u8 tmp[WPA_KEY_RSC_LEN]; -+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) { -+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; -+ } -+ } -+#else /* WORDS_BIGENDIAN */ -+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); -+#endif /* WORDS_BIGENDIAN */ -+ return 0; -+} -+ -+ -+static int -+madwifi_flush(void *priv) -+{ -+#ifdef MADWIFI_BSD -+ u8 allsta[IEEE80211_ADDR_LEN]; -+ memset(allsta, 0xff, IEEE80211_ADDR_LEN); -+ return madwifi_sta_deauth(priv, NULL, allsta, -+ IEEE80211_REASON_AUTH_LEAVE); -+#else /* MADWIFI_BSD */ -+ return 0; /* XXX */ -+#endif /* MADWIFI_BSD */ -+} -+ -+ -+static int -+madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, -+ const u8 *addr) -+{ -+ struct madwifi_driver_data *drv = priv; -+ -+#ifdef MADWIFI_BSD -+ struct ieee80211req_sta_stats stats; -+ -+ memset(data, 0, sizeof(*data)); -+ -+ /* -+ * Fetch statistics for station from the system. -+ */ -+ memset(&stats, 0, sizeof(stats)); -+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); -+ if (set80211priv(drv, -+#ifdef MADWIFI_NG -+ IEEE80211_IOCTL_STA_STATS, -+#else /* MADWIFI_NG */ -+ IEEE80211_IOCTL_GETSTASTATS, -+#endif /* MADWIFI_NG */ -+ &stats, sizeof(stats))) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " -+ MACSTR ")", __func__, MAC2STR(addr)); -+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { -+ memcpy(data, &drv->acct_data, sizeof(*data)); -+ return 0; -+ } -+ -+ printf("Failed to get station stats information element.\n"); -+ return -1; -+ } -+ -+ data->rx_packets = stats.is_stats.ns_rx_data; -+ data->rx_bytes = stats.is_stats.ns_rx_bytes; -+ data->tx_packets = stats.is_stats.ns_tx_data; -+ data->tx_bytes = stats.is_stats.ns_tx_bytes; -+ return 0; -+ -+#else /* MADWIFI_BSD */ -+ -+ char buf[1024], line[128], *pos; -+ FILE *f; -+ unsigned long val; -+ -+ memset(data, 0, sizeof(*data)); -+ snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR, -+ drv->iface, MAC2STR(addr)); -+ -+ f = fopen(buf, "r"); -+ if (!f) { -+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0) -+ return -1; -+ memcpy(data, &drv->acct_data, sizeof(*data)); -+ return 0; -+ } -+ /* Need to read proc file with in one piece, so use large enough -+ * buffer. */ -+ setbuffer(f, buf, sizeof(buf)); -+ -+ while (fgets(line, sizeof(line), f)) { -+ pos = strchr(line, '='); -+ if (!pos) -+ continue; -+ *pos++ = '\0'; -+ val = strtoul(pos, NULL, 10); -+ if (strcmp(line, "rx_packets") == 0) -+ data->rx_packets = val; -+ else if (strcmp(line, "tx_packets") == 0) -+ data->tx_packets = val; -+ else if (strcmp(line, "rx_bytes") == 0) -+ data->rx_bytes = val; -+ else if (strcmp(line, "tx_bytes") == 0) -+ data->tx_bytes = val; -+ } -+ -+ fclose(f); -+ -+ return 0; -+#endif /* MADWIFI_BSD */ -+} -+ -+ -+static int -+madwifi_sta_clear_stats(void *priv, const u8 *addr) -+{ -+#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS) -+ struct madwifi_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr)); -+ -+ mlme.im_op = IEEE80211_MLME_CLEAR_STATS; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, -+ sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr " -+ MACSTR ")", __func__, MAC2STR(addr)); -+ } -+ -+ return ret; -+#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ -+ return 0; /* FIX */ -+#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */ -+} -+ -+ -+static int -+madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) -+{ -+ /* -+ * Do nothing; we setup parameters at startup that define the -+ * contents of the beacon information element. -+ */ -+ return 0; -+} -+ -+static int -+madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", -+ __func__, ether_sprintf(addr), reason_code); -+ -+ mlme.im_op = IEEE80211_MLME_DEAUTH; -+ mlme.im_reason = reason_code; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR -+ " reason %d)", -+ __func__, MAC2STR(addr), reason_code); -+ } -+ -+ return ret; -+} -+ -+static int -+madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason_code) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d", -+ __func__, ether_sprintf(addr), reason_code); -+ -+ mlme.im_op = IEEE80211_MLME_DISASSOC; -+ mlme.im_reason = reason_code; -+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme)); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr " -+ MACSTR " reason %d)", -+ __func__, MAC2STR(addr), reason_code); -+ } -+ -+ return ret; -+} -+ -+#ifdef CONFIG_WPS -+#ifdef IEEE80211_IOCTL_FILTERFRAME -+static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, -+ size_t len) -+{ -+ struct madwifi_driver_data *drv = ctx; -+ const struct ieee80211_mgmt *mgmt; -+ u16 fc; -+ union wpa_event_data event; -+ -+ /* Send Probe Request information to WPS processing */ -+ -+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)) -+ return; -+ mgmt = (const struct ieee80211_mgmt *) buf; -+ -+ fc = le_to_host16(mgmt->frame_control); -+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || -+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ) -+ return; -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_probe_req.sa = mgmt->sa; -+ event.rx_probe_req.ie = mgmt->u.probe_req.variable; -+ event.rx_probe_req.ie_len = -+ len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); -+ wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event); -+} -+#endif /* IEEE80211_IOCTL_FILTERFRAME */ -+#endif /* CONFIG_WPS */ -+ -+static int madwifi_receive_probe_req(struct madwifi_driver_data *drv) -+{ -+ int ret = 0; -+#ifdef CONFIG_WPS -+#ifdef IEEE80211_IOCTL_FILTERFRAME -+ struct ieee80211req_set_filter filt; -+ -+ wpa_printf(MSG_DEBUG, "%s Enter", __func__); -+ filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ; -+ -+ ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt, -+ sizeof(struct ieee80211req_set_filter)); -+ if (ret) -+ return ret; -+ -+ drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW, -+ madwifi_raw_receive, drv, 1); -+ if (drv->sock_raw == NULL) -+ return -1; -+#endif /* IEEE80211_IOCTL_FILTERFRAME */ -+#endif /* CONFIG_WPS */ -+ return ret; -+} -+ -+#ifdef CONFIG_WPS -+static int -+madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype) -+{ -+ struct madwifi_driver_data *drv = priv; -+ u8 buf[256]; -+ struct ieee80211req_getset_appiebuf *beac_ie; -+ -+ wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__, -+ (unsigned long) len); -+ -+ beac_ie = (struct ieee80211req_getset_appiebuf *) buf; -+ beac_ie->app_frmtype = frametype; -+ beac_ie->app_buflen = len; -+ memcpy(&(beac_ie->app_buf[0]), ie, len); -+ -+ return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie, -+ sizeof(struct ieee80211req_getset_appiebuf) + len); -+} -+ -+static int -+madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, -+ const struct wpabuf *proberesp, -+ const struct wpabuf *assocresp) -+{ -+ if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL, -+ beacon ? wpabuf_len(beacon) : 0, -+ IEEE80211_APPIE_FRAME_BEACON) < 0) -+ return -1; -+ return madwifi_set_wps_ie(priv, -+ proberesp ? wpabuf_head(proberesp) : NULL, -+ proberesp ? wpabuf_len(proberesp) : 0, -+ IEEE80211_APPIE_FRAME_PROBE_RESP); -+} -+#else /* CONFIG_WPS */ -+#define madwifi_set_ap_wps_ie NULL -+#endif /* CONFIG_WPS */ -+ -+static void -+madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) -+{ -+ struct hostapd_data *hapd = drv->hapd; -+ struct ieee80211req_wpaie ie; -+ int ielen = 0; -+ u8 *iebuf = NULL; -+ -+ /* -+ * Fetch negotiated WPA/RSN parameters from the system. -+ */ -+ memset(&ie, 0, sizeof(ie)); -+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); -+ if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE", -+ __func__); -+ goto no_ie; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE", -+ ie.wpa_ie, IEEE80211_MAX_OPT_IE); -+ iebuf = ie.wpa_ie; -+ /* madwifi seems to return some random data if WPA/RSN IE is not set. -+ * Assume the IE was not included if the IE type is unknown. */ -+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) -+ iebuf[1] = 0; -+#ifdef MADWIFI_NG -+ wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE", -+ ie.rsn_ie, IEEE80211_MAX_OPT_IE); -+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { -+ /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not -+ * set. This is needed for WPA2. */ -+ iebuf = ie.rsn_ie; -+ if (iebuf[0] != WLAN_EID_RSN) -+ iebuf[1] = 0; -+ } -+#endif /* MADWIFI_NG */ -+ -+ ielen = iebuf[1]; -+ if (ielen == 0) -+ iebuf = NULL; -+ else -+ ielen += 2; -+ -+no_ie: -+ drv_event_assoc(hapd, addr, iebuf, ielen, 0); -+ -+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { -+ /* Cached accounting data is not valid anymore. */ -+ memset(drv->acct_mac, 0, ETH_ALEN); -+ memset(&drv->acct_data, 0, sizeof(drv->acct_data)); -+ } -+} -+ -+static void -+madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv, -+ char *custom) -+{ -+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); -+ -+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { -+ char *pos; -+ u8 addr[ETH_ALEN]; -+ pos = strstr(custom, "addr="); -+ if (pos == NULL) { -+ wpa_printf(MSG_DEBUG, -+ "MLME-MICHAELMICFAILURE.indication " -+ "without sender address ignored"); -+ return; -+ } -+ pos += 5; -+ if (hwaddr_aton(pos, addr) == 0) { -+ union wpa_event_data data; -+ os_memset(&data, 0, sizeof(data)); -+ data.michael_mic_failure.unicast = 1; -+ data.michael_mic_failure.src = addr; -+ wpa_supplicant_event(drv->hapd, -+ EVENT_MICHAEL_MIC_FAILURE, &data); -+ } else { -+ wpa_printf(MSG_DEBUG, -+ "MLME-MICHAELMICFAILURE.indication " -+ "with invalid MAC address"); -+ } -+ } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) { -+ char *key, *value; -+ u32 val; -+ key = custom; -+ while ((key = strchr(key, '\n')) != NULL) { -+ key++; -+ value = strchr(key, '='); -+ if (value == NULL) -+ continue; -+ *value++ = '\0'; -+ val = strtoul(value, NULL, 10); -+ if (strcmp(key, "mac") == 0) -+ hwaddr_aton(value, drv->acct_mac); -+ else if (strcmp(key, "rx_packets") == 0) -+ drv->acct_data.rx_packets = val; -+ else if (strcmp(key, "tx_packets") == 0) -+ drv->acct_data.tx_packets = val; -+ else if (strcmp(key, "rx_bytes") == 0) -+ drv->acct_data.rx_bytes = val; -+ else if (strcmp(key, "tx_bytes") == 0) -+ drv->acct_data.tx_bytes = val; -+ key = value; -+ } -+ } -+} -+ -+static void -+madwifi_wireless_event_wireless(struct madwifi_driver_data *drv, -+ char *data, int len) -+{ -+ struct iw_event iwe_buf, *iwe = &iwe_buf; -+ char *pos, *end, *custom, *buf; -+ -+ pos = data; -+ end = data + len; -+ -+ while (pos + IW_EV_LCP_LEN <= end) { -+ /* Event data may be unaligned, so make a local, aligned copy -+ * before processing. */ -+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); -+ wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", -+ iwe->cmd, iwe->len); -+ if (iwe->len <= IW_EV_LCP_LEN) -+ return; -+ -+ custom = pos + IW_EV_POINT_LEN; -+ if (drv->we_version > 18 && -+ (iwe->cmd == IWEVMICHAELMICFAILURE || -+ iwe->cmd == IWEVCUSTOM)) { -+ /* WE-19 removed the pointer from struct iw_point */ -+ char *dpos = (char *) &iwe_buf.u.data.length; -+ int dlen = dpos - (char *) &iwe_buf; -+ memcpy(dpos, pos + IW_EV_LCP_LEN, -+ sizeof(struct iw_event) - dlen); -+ } else { -+ memcpy(&iwe_buf, pos, sizeof(struct iw_event)); -+ custom += IW_EV_POINT_OFF; -+ } -+ -+ switch (iwe->cmd) { -+ case IWEVEXPIRED: -+ drv_event_disassoc(drv->hapd, -+ (u8 *) iwe->u.addr.sa_data); -+ break; -+ case IWEVREGISTERED: -+ madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data); -+ break; -+ case IWEVCUSTOM: -+ if (custom + iwe->u.data.length > end) -+ return; -+ buf = malloc(iwe->u.data.length + 1); -+ if (buf == NULL) -+ return; /* XXX */ -+ memcpy(buf, custom, iwe->u.data.length); -+ buf[iwe->u.data.length] = '\0'; -+ madwifi_wireless_event_wireless_custom(drv, buf); -+ free(buf); -+ break; -+ } -+ -+ pos += iwe->len; -+ } -+} -+ -+ -+static void -+madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, -+ u8 *buf, size_t len) -+{ -+ struct madwifi_driver_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ if (ifi->ifi_index != drv->ifindex) -+ return; -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_WIRELESS) { -+ madwifi_wireless_event_wireless( -+ drv, ((char *) attr) + rta_len, -+ attr->rta_len - rta_len); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+ -+ -+static int -+madwifi_get_we_version(struct madwifi_driver_data *drv) -+{ -+ struct iw_range *range; -+ struct iwreq iwr; -+ int minlen; -+ size_t buflen; -+ -+ drv->we_version = 0; -+ -+ /* -+ * Use larger buffer than struct iw_range in order to allow the -+ * structure to grow in the future. -+ */ -+ buflen = sizeof(struct iw_range) + 500; -+ range = os_zalloc(buflen); -+ if (range == NULL) -+ return -1; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) range; -+ iwr.u.data.length = buflen; -+ -+ minlen = ((char *) &range->enc_capa) - (char *) range + -+ sizeof(range->enc_capa); -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { -+ perror("ioctl[SIOCGIWRANGE]"); -+ free(range); -+ return -1; -+ } else if (iwr.u.data.length >= minlen && -+ range->we_version_compiled >= 18) { -+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " -+ "WE(source)=%d enc_capa=0x%x", -+ range->we_version_compiled, -+ range->we_version_source, -+ range->enc_capa); -+ drv->we_version = range->we_version_compiled; -+ } -+ -+ free(range); -+ return 0; -+} -+ -+ -+static int -+madwifi_wireless_event_init(struct madwifi_driver_data *drv) -+{ -+ struct netlink_config *cfg; -+ -+ madwifi_get_we_version(drv); -+ -+ cfg = os_zalloc(sizeof(*cfg)); -+ if (cfg == NULL) -+ return -1; -+ cfg->ctx = drv; -+ cfg->newlink_cb = madwifi_wireless_event_rtm_newlink; -+ drv->netlink = netlink_init(cfg); -+ if (drv->netlink == NULL) { -+ os_free(cfg); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int -+madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, -+ int encrypt, const u8 *own_addr, u32 flags) -+{ -+ struct madwifi_driver_data *drv = priv; -+ unsigned char buf[3000]; -+ unsigned char *bp = buf; -+ struct l2_ethhdr *eth; -+ size_t len; -+ int status; -+ -+ /* -+ * Prepend the Ethernet header. If the caller left us -+ * space at the front we could just insert it but since -+ * we don't know we copy to a local buffer. Given the frequency -+ * and size of frames this probably doesn't matter. -+ */ -+ len = data_len + sizeof(struct l2_ethhdr); -+ if (len > sizeof(buf)) { -+ bp = malloc(len); -+ if (bp == NULL) { -+ printf("EAPOL frame discarded, cannot malloc temp " -+ "buffer of size %lu!\n", (unsigned long) len); -+ return -1; -+ } -+ } -+ eth = (struct l2_ethhdr *) bp; -+ memcpy(eth->h_dest, addr, ETH_ALEN); -+ memcpy(eth->h_source, own_addr, ETH_ALEN); -+ eth->h_proto = host_to_be16(ETH_P_EAPOL); -+ memcpy(eth+1, data, data_len); -+ -+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); -+ -+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len); -+ -+ if (bp != buf) -+ free(bp); -+ return status; -+} -+ -+static void -+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -+{ -+ struct madwifi_driver_data *drv = ctx; -+ drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), -+ len - sizeof(struct l2_ethhdr)); -+} -+ -+static void * -+madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params) -+{ -+ struct madwifi_driver_data *drv; -+ struct ifreq ifr; -+ struct iwreq iwr; -+ char brname[IFNAMSIZ]; -+ -+ drv = os_zalloc(sizeof(struct madwifi_driver_data)); -+ if (drv == NULL) { -+ printf("Could not allocate memory for madwifi driver data\n"); -+ return NULL; -+ } -+ -+ drv->hapd = hapd; -+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->ioctl_sock < 0) { -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ goto bad; -+ } -+ memcpy(drv->iface, params->ifname, sizeof(drv->iface)); -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); -+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { -+ perror("ioctl(SIOCGIFINDEX)"); -+ goto bad; -+ } -+ drv->ifindex = ifr.ifr_ifindex; -+ -+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, -+ handle_read, drv, 1); -+ if (drv->sock_xmit == NULL) -+ goto bad; -+ if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) -+ goto bad; -+ if (params->bridge[0]) { -+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", -+ params->bridge[0]); -+ drv->sock_recv = l2_packet_init(params->bridge[0], NULL, -+ ETH_P_EAPOL, handle_read, drv, -+ 1); -+ if (drv->sock_recv == NULL) -+ goto bad; -+ } else if (linux_br_get(brname, drv->iface) == 0) { -+ wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " -+ "EAPOL receive", brname); -+ drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, -+ handle_read, drv, 1); -+ if (drv->sock_recv == NULL) -+ goto bad; -+ } else -+ drv->sock_recv = drv->sock_xmit; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ -+ iwr.u.mode = IW_MODE_MASTER; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMODE]"); -+ printf("Could not set interface to master mode!\n"); -+ goto bad; -+ } -+ -+ /* mark down during setup */ -+ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); -+ madwifi_set_privacy(drv, 0); /* default to no privacy */ -+ -+ madwifi_receive_probe_req(drv); -+ -+ if (madwifi_wireless_event_init(drv)) -+ goto bad; -+ -+ return drv; -+bad: -+ if (drv->sock_xmit != NULL) -+ l2_packet_deinit(drv->sock_xmit); -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ if (drv != NULL) -+ free(drv); -+ return NULL; -+} -+ -+ -+static void -+madwifi_deinit(void *priv) -+{ -+ struct madwifi_driver_data *drv = priv; -+ -+ netlink_deinit(drv->netlink); -+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit) -+ l2_packet_deinit(drv->sock_recv); -+ if (drv->sock_xmit != NULL) -+ l2_packet_deinit(drv->sock_xmit); -+ if (drv->sock_raw) -+ l2_packet_deinit(drv->sock_raw); -+ free(drv); -+} -+ -+static int -+madwifi_set_ssid(void *priv, const u8 *buf, int len) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct iwreq iwr; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.essid.flags = 1; /* SSID active */ -+ iwr.u.essid.pointer = (caddr_t) buf; -+ iwr.u.essid.length = len + 1; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCSIWESSID]"); -+ printf("len=%d\n", len); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+madwifi_get_ssid(void *priv, u8 *buf, int len) -+{ -+ struct madwifi_driver_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.essid.pointer = (caddr_t) buf; -+ iwr.u.essid.length = len; -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCGIWESSID]"); -+ ret = -1; -+ } else -+ ret = iwr.u.essid.length; -+ -+ return ret; -+} -+ -+static int -+madwifi_set_countermeasures(void *priv, int enabled) -+{ -+ struct madwifi_driver_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); -+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled); -+} -+ -+static int -+madwifi_commit(void *priv) -+{ -+ struct madwifi_driver_data *drv = priv; -+ return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1); -+} -+ -+#else /* HOSTAPD */ -+ -+struct wpa_driver_madwifi_data { -+ void *wext; /* private data for driver_wext */ -+ void *ctx; -+ char ifname[IFNAMSIZ + 1]; -+ int sock; -+}; -+ -+static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg); -+static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies, -+ size_t ies_len); -+ -+ -+static int -+set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len, -+ int show_err) -+{ -+ struct iwreq iwr; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ if (len < IFNAMSIZ && -+ op != IEEE80211_IOCTL_SET_APPIEBUF) { -+ /* -+ * Argument data fits inline; put it there. -+ */ -+ os_memcpy(iwr.u.name, data, len); -+ } else { -+ /* -+ * Argument data too big for inline transfer; setup a -+ * parameter block instead; the kernel will transfer -+ * the data for the driver. -+ */ -+ iwr.u.data.pointer = data; -+ iwr.u.data.length = len; -+ } -+ -+ if (ioctl(drv->sock, op, &iwr) < 0) { -+ if (show_err) { -+#ifdef MADWIFI_NG -+ int first = IEEE80211_IOCTL_SETPARAM; -+ int last = IEEE80211_IOCTL_KICKMAC; -+ static const char *opnames[] = { -+ "ioctl[IEEE80211_IOCTL_SETPARAM]", -+ "ioctl[IEEE80211_IOCTL_GETPARAM]", -+ "ioctl[IEEE80211_IOCTL_SETMODE]", -+ "ioctl[IEEE80211_IOCTL_GETMODE]", -+ "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]", -+ "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]", -+ "ioctl[IEEE80211_IOCTL_SETCHANLIST]", -+ "ioctl[IEEE80211_IOCTL_GETCHANLIST]", -+ "ioctl[IEEE80211_IOCTL_CHANSWITCH]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]", -+ "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_GETCHANINFO]", -+ "ioctl[IEEE80211_IOCTL_SETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_GETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_SETMLME]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_SETKEY]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_DELKEY]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_ADDMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_DELMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_WDSMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_WDSDELMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_KICKMAC]", -+ }; -+#else /* MADWIFI_NG */ -+ int first = IEEE80211_IOCTL_SETPARAM; -+ int last = IEEE80211_IOCTL_CHANLIST; -+ static const char *opnames[] = { -+ "ioctl[IEEE80211_IOCTL_SETPARAM]", -+ "ioctl[IEEE80211_IOCTL_GETPARAM]", -+ "ioctl[IEEE80211_IOCTL_SETKEY]", -+ "ioctl[IEEE80211_IOCTL_GETKEY]", -+ "ioctl[IEEE80211_IOCTL_DELKEY]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_SETMLME]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_SETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_GETOPTIE]", -+ "ioctl[IEEE80211_IOCTL_ADDMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_DELMAC]", -+ NULL, -+ "ioctl[IEEE80211_IOCTL_CHANLIST]", -+ }; -+#endif /* MADWIFI_NG */ -+ int idx = op - first; -+ if (first <= op && op <= last && -+ idx < (int) (sizeof(opnames) / sizeof(opnames[0])) -+ && opnames[idx]) -+ perror(opnames[idx]); -+ else -+ perror("ioctl[unknown???]"); -+ } -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg, -+ int show_err) -+{ -+ struct iwreq iwr; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.mode = op; -+ os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg)); -+ -+ if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) { -+ if (show_err) -+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]"); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv, -+ const u8 *wpa_ie, size_t wpa_ie_len) -+{ -+ struct iwreq iwr; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ /* NB: SETOPTIE is not fixed-size so must not be inlined */ -+ iwr.u.data.pointer = (void *) wpa_ie; -+ iwr.u.data.length = wpa_ie_len; -+ -+ if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) { -+ perror("ioctl[IEEE80211_IOCTL_SETOPTIE]"); -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx, -+ const u8 *addr) -+{ -+ struct ieee80211req_del_key wk; -+ -+ wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx); -+ os_memset(&wk, 0, sizeof(wk)); -+ wk.idk_keyix = key_idx; -+ if (addr != NULL) -+ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); -+ -+ return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1); -+} -+ -+static int -+wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg, -+ const u8 *addr, int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ struct ieee80211req_key wk; -+ char *alg_name; -+ u_int8_t cipher; -+ -+ if (alg == WPA_ALG_NONE) -+ return wpa_driver_madwifi_del_key(drv, key_idx, addr); -+ -+ switch (alg) { -+ case WPA_ALG_WEP: -+ if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", -+ ETH_ALEN) == 0) { -+ /* -+ * madwifi did not seem to like static WEP key -+ * configuration with IEEE80211_IOCTL_SETKEY, so use -+ * Linux wireless extensions ioctl for this. -+ */ -+ return wpa_driver_wext_set_key(ifname, drv->wext, alg, -+ addr, key_idx, set_tx, -+ seq, seq_len, -+ key, key_len); -+ } -+ alg_name = "WEP"; -+ cipher = IEEE80211_CIPHER_WEP; -+ break; -+ case WPA_ALG_TKIP: -+ alg_name = "TKIP"; -+ cipher = IEEE80211_CIPHER_TKIP; -+ break; -+ case WPA_ALG_CCMP: -+ alg_name = "CCMP"; -+ cipher = IEEE80211_CIPHER_AES_CCM; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d", -+ __FUNCTION__, alg); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu " -+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx, -+ (unsigned long) seq_len, (unsigned long) key_len); -+ -+ if (seq_len > sizeof(u_int64_t)) { -+ wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big", -+ __FUNCTION__, (unsigned long) seq_len); -+ return -2; -+ } -+ if (key_len > sizeof(wk.ik_keydata)) { -+ wpa_printf(MSG_DEBUG, "%s: key length %lu too big", -+ __FUNCTION__, (unsigned long) key_len); -+ return -3; -+ } -+ -+ os_memset(&wk, 0, sizeof(wk)); -+ wk.ik_type = cipher; -+ wk.ik_flags = IEEE80211_KEY_RECV; -+ if (addr == NULL || -+ os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) -+ wk.ik_flags |= IEEE80211_KEY_GROUP; -+ if (set_tx) { -+ wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT; -+ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); -+ } else -+ os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN); -+ wk.ik_keyix = key_idx; -+ wk.ik_keylen = key_len; -+#ifdef WORDS_BIGENDIAN -+ if (seq) { -+ size_t i; -+ u8 tmp[WPA_KEY_RSC_LEN]; -+ os_memset(tmp, 0, sizeof(tmp)); -+ for (i = 0; i < seq_len; i++) -+ tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i]; -+ os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN); -+ } -+#else /* WORDS_BIGENDIAN */ -+ if (seq) -+ os_memcpy(&wk.ik_keyrsc, seq, seq_len); -+#endif /* WORDS_BIGENDIAN */ -+ os_memcpy(wk.ik_keydata, key, key_len); -+ -+ return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1); -+} -+ -+static int -+wpa_driver_madwifi_set_countermeasures(void *priv, int enabled) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); -+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1); -+} -+ -+static int -+wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ mlme.im_op = IEEE80211_MLME_DEAUTH; -+ mlme.im_reason = reason_code; -+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1); -+} -+ -+static int -+wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ mlme.im_op = IEEE80211_MLME_DISASSOC; -+ mlme.im_reason = reason_code; -+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); -+ return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1); -+} -+ -+static int -+wpa_driver_madwifi_associate(void *priv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ struct ieee80211req_mlme mlme; -+ int ret = 0, privacy = 1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, -+ params->drop_unencrypted, 1) < 0) -+ ret = -1; -+ if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0) -+ ret = -1; -+ -+ /* -+ * NB: Don't need to set the freq or cipher-related state as -+ * this is implied by the bssid which is used to locate -+ * the scanned node state which holds it. The ssid is -+ * needed to disambiguate an AP that broadcasts multiple -+ * ssid's but uses the same bssid. -+ */ -+ /* XXX error handling is wrong but unclear what to do... */ -+ if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie, -+ params->wpa_ie_len) < 0) -+ ret = -1; -+ -+ if (params->pairwise_suite == CIPHER_NONE && -+ params->group_suite == CIPHER_NONE && -+ params->key_mgmt_suite == KEY_MGMT_NONE && -+ params->wpa_ie_len == 0) -+ privacy = 0; -+ -+ if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0) -+ ret = -1; -+ -+ if (params->wpa_ie_len && -+ set80211param(drv, IEEE80211_PARAM_WPA, -+ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0) -+ ret = -1; -+ -+ if (params->bssid == NULL) { -+ /* ap_scan=2 mode - driver takes care of AP selection and -+ * roaming */ -+ /* FIX: this does not seem to work; would probably need to -+ * change something in the driver */ -+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) -+ ret = -1; -+ -+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, -+ params->ssid_len) < 0) -+ ret = -1; -+ } else { -+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) -+ ret = -1; -+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, -+ params->ssid_len) < 0) -+ ret = -1; -+ os_memset(&mlme, 0, sizeof(mlme)); -+ mlme.im_op = IEEE80211_MLME_ASSOC; -+ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); -+ if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, -+ sizeof(mlme), 1) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed", -+ __func__); -+ ret = -1; -+ } -+ } -+ -+ return ret; -+} -+ -+static int -+wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ int authmode; -+ -+ if ((auth_alg & WPA_AUTH_ALG_OPEN) && -+ (auth_alg & WPA_AUTH_ALG_SHARED)) -+ authmode = IEEE80211_AUTH_AUTO; -+ else if (auth_alg & WPA_AUTH_ALG_SHARED) -+ authmode = IEEE80211_AUTH_SHARED; -+ else -+ authmode = IEEE80211_AUTH_OPEN; -+ -+ return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1); -+} -+ -+static int -+wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ const u8 *ssid = params->ssids[0].ssid; -+ size_t ssid_len = params->ssids[0].ssid_len; -+ -+ wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies, -+ params->extra_ies_len); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ /* set desired ssid before scan */ -+ /* FIX: scan should not break the current association, so using -+ * set_ssid may not be the best way of doing this.. */ -+ if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0) -+ ret = -1; -+ -+ if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) { -+ perror("ioctl[SIOCSIWSCAN]"); -+ ret = -1; -+ } -+ -+ /* -+ * madwifi delivers a scan complete event so no need to poll, but -+ * register a backup timeout anyway to make sure that we recover even -+ * if the driver does not send this event for any reason. This timeout -+ * will only be used if the event is not delivered (event handler will -+ * cancel the timeout). -+ */ -+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext, -+ drv->ctx); -+ eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext, -+ drv->ctx); -+ -+ return ret; -+} -+ -+static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ return wpa_driver_wext_get_bssid(drv->wext, bssid); -+} -+ -+ -+static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ return wpa_driver_wext_get_ssid(drv->wext, ssid); -+} -+ -+ -+static struct wpa_scan_results * -+wpa_driver_madwifi_get_scan_results(void *priv) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ return wpa_driver_wext_get_scan_results(drv->wext); -+} -+ -+ -+static int wpa_driver_madwifi_set_operstate(void *priv, int state) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ return wpa_driver_wext_set_operstate(drv->wext, state); -+} -+ -+ -+static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies, -+ size_t ies_len) -+{ -+ struct ieee80211req_getset_appiebuf *probe_req_ie; -+ int ret; -+ -+ probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len); -+ if (probe_req_ie == NULL) -+ return -1; -+ -+ probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ; -+ probe_req_ie->app_buflen = ies_len; -+ os_memcpy(probe_req_ie->app_buf, ies, ies_len); -+ -+ ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie, -+ sizeof(struct ieee80211req_getset_appiebuf) + -+ ies_len, 1); -+ -+ os_free(probe_req_ie); -+ -+ return ret; -+} -+ -+ -+static void * wpa_driver_madwifi_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_madwifi_data *drv; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->wext = wpa_driver_wext_init(ctx, ifname); -+ if (drv->wext == NULL) -+ goto fail; -+ -+ drv->ctx = ctx; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->sock < 0) -+ goto fail2; -+ -+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based " -+ "roaming", __FUNCTION__); -+ goto fail3; -+ } -+ -+ if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support", -+ __FUNCTION__); -+ goto fail3; -+ } -+ -+ return drv; -+ -+fail3: -+ close(drv->sock); -+fail2: -+ wpa_driver_wext_deinit(drv->wext); -+fail: -+ os_free(drv); -+ return NULL; -+} -+ -+ -+static void wpa_driver_madwifi_deinit(void *priv) -+{ -+ struct wpa_driver_madwifi_data *drv = priv; -+ -+ if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE", -+ __FUNCTION__); -+ } -+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based " -+ "roaming", __FUNCTION__); -+ } -+ if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy " -+ "flag", __FUNCTION__); -+ } -+ if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed to disable WPA", -+ __FUNCTION__); -+ } -+ -+ wpa_driver_wext_deinit(drv->wext); -+ -+ close(drv->sock); -+ os_free(drv); -+} -+ -+#endif /* HOSTAPD */ -+ -+ -+const struct wpa_driver_ops wpa_driver_madwifi_ops = { -+ .name = "madwifi", -+ .desc = "MADWIFI 802.11 support (Atheros, etc.)", -+ .set_key = wpa_driver_madwifi_set_key, -+#ifdef HOSTAPD -+ .hapd_init = madwifi_init, -+ .hapd_deinit = madwifi_deinit, -+ .set_ieee8021x = madwifi_set_ieee8021x, -+ .set_privacy = madwifi_set_privacy, -+ .get_seqnum = madwifi_get_seqnum, -+ .flush = madwifi_flush, -+ .set_generic_elem = madwifi_set_opt_ie, -+ .sta_set_flags = madwifi_sta_set_flags, -+ .read_sta_data = madwifi_read_sta_driver_data, -+ .hapd_send_eapol = madwifi_send_eapol, -+ .sta_disassoc = madwifi_sta_disassoc, -+ .sta_deauth = madwifi_sta_deauth, -+ .hapd_set_ssid = madwifi_set_ssid, -+ .hapd_get_ssid = madwifi_get_ssid, -+ .hapd_set_countermeasures = madwifi_set_countermeasures, -+ .sta_clear_stats = madwifi_sta_clear_stats, -+ .commit = madwifi_commit, -+ .set_ap_wps_ie = madwifi_set_ap_wps_ie, -+#else /* HOSTAPD */ -+ .get_bssid = wpa_driver_madwifi_get_bssid, -+ .get_ssid = wpa_driver_madwifi_get_ssid, -+ .init = wpa_driver_madwifi_init, -+ .deinit = wpa_driver_madwifi_deinit, -+ .set_countermeasures = wpa_driver_madwifi_set_countermeasures, -+ .scan2 = wpa_driver_madwifi_scan, -+ .get_scan_results2 = wpa_driver_madwifi_get_scan_results, -+ .deauthenticate = wpa_driver_madwifi_deauthenticate, -+ .disassociate = wpa_driver_madwifi_disassociate, -+ .associate = wpa_driver_madwifi_associate, -+ .set_operstate = wpa_driver_madwifi_set_operstate, -+#endif /* HOSTAPD */ -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.c -new file mode 100644 -index 0000000000000..aeb7304133e45 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.c -@@ -0,0 +1,3331 @@ -+/* -+ * WPA Supplicant - Windows/NDIS driver interface -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifdef __CYGWIN__ -+/* Avoid some header file conflicts by not including standard headers for -+ * cygwin builds when Packet32.h is included. */ -+#include "build_config.h" -+int close(int fd); -+#else /* __CYGWIN__ */ -+#include "includes.h" -+#endif /* __CYGWIN__ */ -+#ifdef CONFIG_USE_NDISUIO -+#include -+#else /* CONFIG_USE_NDISUIO */ -+#include -+#endif /* CONFIG_USE_NDISUIO */ -+#ifdef __MINGW32_VERSION -+#include -+#else /* __MINGW32_VERSION */ -+#include -+#endif /* __MINGW32_VERSION */ -+ -+#ifdef _WIN32_WCE -+#include -+#include -+#include -+#endif /* _WIN32_WCE */ -+ -+#include "common.h" -+#include "driver.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "driver_ndis.h" -+ -+int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv); -+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED -+void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data); -+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ -+ -+static void wpa_driver_ndis_deinit(void *priv); -+static void wpa_driver_ndis_poll(void *drv); -+static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx); -+static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv); -+static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv); -+static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv); -+ -+ -+static const u8 pae_group_addr[ETH_ALEN] = -+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; -+ -+ -+/* FIX: to be removed once this can be compiled with the complete NDIS -+ * header files */ -+#ifndef OID_802_11_BSSID -+#define OID_802_11_BSSID 0x0d010101 -+#define OID_802_11_SSID 0x0d010102 -+#define OID_802_11_INFRASTRUCTURE_MODE 0x0d010108 -+#define OID_802_11_ADD_WEP 0x0D010113 -+#define OID_802_11_REMOVE_WEP 0x0D010114 -+#define OID_802_11_DISASSOCIATE 0x0D010115 -+#define OID_802_11_BSSID_LIST 0x0d010217 -+#define OID_802_11_AUTHENTICATION_MODE 0x0d010118 -+#define OID_802_11_PRIVACY_FILTER 0x0d010119 -+#define OID_802_11_BSSID_LIST_SCAN 0x0d01011A -+#define OID_802_11_WEP_STATUS 0x0d01011B -+#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS -+#define OID_802_11_ADD_KEY 0x0d01011D -+#define OID_802_11_REMOVE_KEY 0x0d01011E -+#define OID_802_11_ASSOCIATION_INFORMATION 0x0d01011F -+#define OID_802_11_TEST 0x0d010120 -+#define OID_802_11_CAPABILITY 0x0d010122 -+#define OID_802_11_PMKID 0x0d010123 -+ -+#define NDIS_802_11_LENGTH_SSID 32 -+#define NDIS_802_11_LENGTH_RATES 8 -+#define NDIS_802_11_LENGTH_RATES_EX 16 -+ -+typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; -+ -+typedef struct NDIS_802_11_SSID { -+ ULONG SsidLength; -+ UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; -+} NDIS_802_11_SSID; -+ -+typedef LONG NDIS_802_11_RSSI; -+ -+typedef enum NDIS_802_11_NETWORK_TYPE { -+ Ndis802_11FH, -+ Ndis802_11DS, -+ Ndis802_11OFDM5, -+ Ndis802_11OFDM24, -+ Ndis802_11NetworkTypeMax -+} NDIS_802_11_NETWORK_TYPE; -+ -+typedef struct NDIS_802_11_CONFIGURATION_FH { -+ ULONG Length; -+ ULONG HopPattern; -+ ULONG HopSet; -+ ULONG DwellTime; -+} NDIS_802_11_CONFIGURATION_FH; -+ -+typedef struct NDIS_802_11_CONFIGURATION { -+ ULONG Length; -+ ULONG BeaconPeriod; -+ ULONG ATIMWindow; -+ ULONG DSConfig; -+ NDIS_802_11_CONFIGURATION_FH FHConfig; -+} NDIS_802_11_CONFIGURATION; -+ -+typedef enum NDIS_802_11_NETWORK_INFRASTRUCTURE { -+ Ndis802_11IBSS, -+ Ndis802_11Infrastructure, -+ Ndis802_11AutoUnknown, -+ Ndis802_11InfrastructureMax -+} NDIS_802_11_NETWORK_INFRASTRUCTURE; -+ -+typedef enum NDIS_802_11_AUTHENTICATION_MODE { -+ Ndis802_11AuthModeOpen, -+ Ndis802_11AuthModeShared, -+ Ndis802_11AuthModeAutoSwitch, -+ Ndis802_11AuthModeWPA, -+ Ndis802_11AuthModeWPAPSK, -+ Ndis802_11AuthModeWPANone, -+ Ndis802_11AuthModeWPA2, -+ Ndis802_11AuthModeWPA2PSK, -+ Ndis802_11AuthModeMax -+} NDIS_802_11_AUTHENTICATION_MODE; -+ -+typedef enum NDIS_802_11_WEP_STATUS { -+ Ndis802_11WEPEnabled, -+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, -+ Ndis802_11WEPDisabled, -+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, -+ Ndis802_11WEPKeyAbsent, -+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, -+ Ndis802_11WEPNotSupported, -+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, -+ Ndis802_11Encryption2Enabled, -+ Ndis802_11Encryption2KeyAbsent, -+ Ndis802_11Encryption3Enabled, -+ Ndis802_11Encryption3KeyAbsent -+} NDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS; -+ -+typedef enum NDIS_802_11_PRIVACY_FILTER { -+ Ndis802_11PrivFilterAcceptAll, -+ Ndis802_11PrivFilter8021xWEP -+} NDIS_802_11_PRIVACY_FILTER; -+ -+typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; -+typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; -+ -+typedef struct NDIS_WLAN_BSSID_EX { -+ ULONG Length; -+ NDIS_802_11_MAC_ADDRESS MacAddress; /* BSSID */ -+ UCHAR Reserved[2]; -+ NDIS_802_11_SSID Ssid; -+ ULONG Privacy; -+ NDIS_802_11_RSSI Rssi; -+ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; -+ NDIS_802_11_CONFIGURATION Configuration; -+ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; -+ NDIS_802_11_RATES_EX SupportedRates; -+ ULONG IELength; -+ UCHAR IEs[1]; -+} NDIS_WLAN_BSSID_EX; -+ -+typedef struct NDIS_802_11_BSSID_LIST_EX { -+ ULONG NumberOfItems; -+ NDIS_WLAN_BSSID_EX Bssid[1]; -+} NDIS_802_11_BSSID_LIST_EX; -+ -+typedef struct NDIS_802_11_FIXED_IEs { -+ UCHAR Timestamp[8]; -+ USHORT BeaconInterval; -+ USHORT Capabilities; -+} NDIS_802_11_FIXED_IEs; -+ -+typedef struct NDIS_802_11_WEP { -+ ULONG Length; -+ ULONG KeyIndex; -+ ULONG KeyLength; -+ UCHAR KeyMaterial[1]; -+} NDIS_802_11_WEP; -+ -+typedef ULONG NDIS_802_11_KEY_INDEX; -+typedef ULONGLONG NDIS_802_11_KEY_RSC; -+ -+typedef struct NDIS_802_11_KEY { -+ ULONG Length; -+ ULONG KeyIndex; -+ ULONG KeyLength; -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ NDIS_802_11_KEY_RSC KeyRSC; -+ UCHAR KeyMaterial[1]; -+} NDIS_802_11_KEY; -+ -+typedef struct NDIS_802_11_REMOVE_KEY { -+ ULONG Length; -+ ULONG KeyIndex; -+ NDIS_802_11_MAC_ADDRESS BSSID; -+} NDIS_802_11_REMOVE_KEY; -+ -+typedef struct NDIS_802_11_AI_REQFI { -+ USHORT Capabilities; -+ USHORT ListenInterval; -+ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; -+} NDIS_802_11_AI_REQFI; -+ -+typedef struct NDIS_802_11_AI_RESFI { -+ USHORT Capabilities; -+ USHORT StatusCode; -+ USHORT AssociationId; -+} NDIS_802_11_AI_RESFI; -+ -+typedef struct NDIS_802_11_ASSOCIATION_INFORMATION { -+ ULONG Length; -+ USHORT AvailableRequestFixedIEs; -+ NDIS_802_11_AI_REQFI RequestFixedIEs; -+ ULONG RequestIELength; -+ ULONG OffsetRequestIEs; -+ USHORT AvailableResponseFixedIEs; -+ NDIS_802_11_AI_RESFI ResponseFixedIEs; -+ ULONG ResponseIELength; -+ ULONG OffsetResponseIEs; -+} NDIS_802_11_ASSOCIATION_INFORMATION; -+ -+typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION { -+ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; -+ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; -+} NDIS_802_11_AUTHENTICATION_ENCRYPTION; -+ -+typedef struct NDIS_802_11_CAPABILITY { -+ ULONG Length; -+ ULONG Version; -+ ULONG NoOfPMKIDs; -+ ULONG NoOfAuthEncryptPairsSupported; -+ NDIS_802_11_AUTHENTICATION_ENCRYPTION -+ AuthenticationEncryptionSupported[1]; -+} NDIS_802_11_CAPABILITY; -+ -+typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; -+ -+typedef struct BSSID_INFO { -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ NDIS_802_11_PMKID_VALUE PMKID; -+} BSSID_INFO; -+ -+typedef struct NDIS_802_11_PMKID { -+ ULONG Length; -+ ULONG BSSIDInfoCount; -+ BSSID_INFO BSSIDInfo[1]; -+} NDIS_802_11_PMKID; -+ -+typedef enum NDIS_802_11_STATUS_TYPE { -+ Ndis802_11StatusType_Authentication, -+ Ndis802_11StatusType_PMKID_CandidateList = 2, -+ Ndis802_11StatusTypeMax -+} NDIS_802_11_STATUS_TYPE; -+ -+typedef struct NDIS_802_11_STATUS_INDICATION { -+ NDIS_802_11_STATUS_TYPE StatusType; -+} NDIS_802_11_STATUS_INDICATION; -+ -+typedef struct PMKID_CANDIDATE { -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ ULONG Flags; -+} PMKID_CANDIDATE; -+ -+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 -+ -+typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST { -+ ULONG Version; -+ ULONG NumCandidates; -+ PMKID_CANDIDATE CandidateList[1]; -+} NDIS_802_11_PMKID_CANDIDATE_LIST; -+ -+typedef struct NDIS_802_11_AUTHENTICATION_REQUEST { -+ ULONG Length; -+ NDIS_802_11_MAC_ADDRESS Bssid; -+ ULONG Flags; -+} NDIS_802_11_AUTHENTICATION_REQUEST; -+ -+#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 -+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 -+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 -+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E -+ -+#endif /* OID_802_11_BSSID */ -+ -+ -+#ifndef OID_802_11_PMKID -+/* Platform SDK for XP did not include WPA2, so add needed definitions */ -+ -+#define OID_802_11_CAPABILITY 0x0d010122 -+#define OID_802_11_PMKID 0x0d010123 -+ -+#define Ndis802_11AuthModeWPA2 6 -+#define Ndis802_11AuthModeWPA2PSK 7 -+ -+#define Ndis802_11StatusType_PMKID_CandidateList 2 -+ -+typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION { -+ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; -+ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; -+} NDIS_802_11_AUTHENTICATION_ENCRYPTION; -+ -+typedef struct NDIS_802_11_CAPABILITY { -+ ULONG Length; -+ ULONG Version; -+ ULONG NoOfPMKIDs; -+ ULONG NoOfAuthEncryptPairsSupported; -+ NDIS_802_11_AUTHENTICATION_ENCRYPTION -+ AuthenticationEncryptionSupported[1]; -+} NDIS_802_11_CAPABILITY; -+ -+typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; -+ -+typedef struct BSSID_INFO { -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ NDIS_802_11_PMKID_VALUE PMKID; -+} BSSID_INFO; -+ -+typedef struct NDIS_802_11_PMKID { -+ ULONG Length; -+ ULONG BSSIDInfoCount; -+ BSSID_INFO BSSIDInfo[1]; -+} NDIS_802_11_PMKID; -+ -+typedef struct PMKID_CANDIDATE { -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ ULONG Flags; -+} PMKID_CANDIDATE; -+ -+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 -+ -+typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST { -+ ULONG Version; -+ ULONG NumCandidates; -+ PMKID_CANDIDATE CandidateList[1]; -+} NDIS_802_11_PMKID_CANDIDATE_LIST; -+ -+#endif /* OID_802_11_CAPABILITY */ -+ -+ -+#ifndef OID_DOT11_CURRENT_OPERATION_MODE -+/* Native 802.11 OIDs */ -+#define OID_DOT11_NDIS_START 0x0D010300 -+#define OID_DOT11_CURRENT_OPERATION_MODE (OID_DOT11_NDIS_START + 8) -+#define OID_DOT11_SCAN_REQUEST (OID_DOT11_NDIS_START + 11) -+ -+typedef enum _DOT11_BSS_TYPE { -+ dot11_BSS_type_infrastructure = 1, -+ dot11_BSS_type_independent = 2, -+ dot11_BSS_type_any = 3 -+} DOT11_BSS_TYPE, * PDOT11_BSS_TYPE; -+ -+typedef UCHAR DOT11_MAC_ADDRESS[6]; -+typedef DOT11_MAC_ADDRESS * PDOT11_MAC_ADDRESS; -+ -+typedef enum _DOT11_SCAN_TYPE { -+ dot11_scan_type_active = 1, -+ dot11_scan_type_passive = 2, -+ dot11_scan_type_auto = 3, -+ dot11_scan_type_forced = 0x80000000 -+} DOT11_SCAN_TYPE, * PDOT11_SCAN_TYPE; -+ -+typedef struct _DOT11_SCAN_REQUEST_V2 { -+ DOT11_BSS_TYPE dot11BSSType; -+ DOT11_MAC_ADDRESS dot11BSSID; -+ DOT11_SCAN_TYPE dot11ScanType; -+ BOOLEAN bRestrictedScan; -+ ULONG udot11SSIDsOffset; -+ ULONG uNumOfdot11SSIDs; -+ BOOLEAN bUseRequestIE; -+ ULONG uRequestIDsOffset; -+ ULONG uNumOfRequestIDs; -+ ULONG uPhyTypeInfosOffset; -+ ULONG uNumOfPhyTypeInfos; -+ ULONG uIEsOffset; -+ ULONG uIEsLength; -+ UCHAR ucBuffer[1]; -+} DOT11_SCAN_REQUEST_V2, * PDOT11_SCAN_REQUEST_V2; -+ -+#endif /* OID_DOT11_CURRENT_OPERATION_MODE */ -+ -+#ifdef CONFIG_USE_NDISUIO -+#ifndef _WIN32_WCE -+#ifdef __MINGW32_VERSION -+typedef ULONG NDIS_OID; -+#endif /* __MINGW32_VERSION */ -+/* from nuiouser.h */ -+#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK -+ -+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \ -+ CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access) -+ -+#define IOCTL_NDISUIO_OPEN_DEVICE \ -+ _NDISUIO_CTL_CODE(0x200, METHOD_BUFFERED, \ -+ FILE_READ_ACCESS | FILE_WRITE_ACCESS) -+ -+#define IOCTL_NDISUIO_QUERY_OID_VALUE \ -+ _NDISUIO_CTL_CODE(0x201, METHOD_BUFFERED, \ -+ FILE_READ_ACCESS | FILE_WRITE_ACCESS) -+ -+#define IOCTL_NDISUIO_SET_OID_VALUE \ -+ _NDISUIO_CTL_CODE(0x205, METHOD_BUFFERED, \ -+ FILE_READ_ACCESS | FILE_WRITE_ACCESS) -+ -+#define IOCTL_NDISUIO_SET_ETHER_TYPE \ -+ _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \ -+ FILE_READ_ACCESS | FILE_WRITE_ACCESS) -+ -+#define IOCTL_NDISUIO_QUERY_BINDING \ -+ _NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \ -+ FILE_READ_ACCESS | FILE_WRITE_ACCESS) -+ -+#define IOCTL_NDISUIO_BIND_WAIT \ -+ _NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \ -+ FILE_READ_ACCESS | FILE_WRITE_ACCESS) -+ -+typedef struct _NDISUIO_QUERY_OID -+{ -+ NDIS_OID Oid; -+ UCHAR Data[sizeof(ULONG)]; -+} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID; -+ -+typedef struct _NDISUIO_SET_OID -+{ -+ NDIS_OID Oid; -+ UCHAR Data[sizeof(ULONG)]; -+} NDISUIO_SET_OID, *PNDISUIO_SET_OID; -+ -+typedef struct _NDISUIO_QUERY_BINDING -+{ -+ ULONG BindingIndex; -+ ULONG DeviceNameOffset; -+ ULONG DeviceNameLength; -+ ULONG DeviceDescrOffset; -+ ULONG DeviceDescrLength; -+} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING; -+#endif /* _WIN32_WCE */ -+#endif /* CONFIG_USE_NDISUIO */ -+ -+ -+static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid, -+ char *data, size_t len) -+{ -+#ifdef CONFIG_USE_NDISUIO -+ NDISUIO_QUERY_OID *o; -+ size_t buflen = sizeof(*o) + len; -+ DWORD written; -+ int ret; -+ size_t hdrlen; -+ -+ o = os_zalloc(buflen); -+ if (o == NULL) -+ return -1; -+ o->Oid = oid; -+#ifdef _WIN32_WCE -+ o->ptcDeviceName = drv->adapter_name; -+#endif /* _WIN32_WCE */ -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_OID_VALUE, -+ o, sizeof(NDISUIO_QUERY_OID), o, buflen, &written, -+ NULL)) { -+ wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_QUERY_OID_VALUE " -+ "failed (oid=%08x): %d", oid, (int) GetLastError()); -+ os_free(o); -+ return -1; -+ } -+ hdrlen = sizeof(NDISUIO_QUERY_OID) - sizeof(o->Data); -+ if (written < hdrlen) { -+ wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d); " -+ "too short", oid, (unsigned int) written); -+ os_free(o); -+ return -1; -+ } -+ written -= hdrlen; -+ if (written > len) { -+ wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d) > " -+ "len (%d)",oid, (unsigned int) written, len); -+ os_free(o); -+ return -1; -+ } -+ os_memcpy(data, o->Data, written); -+ ret = written; -+ os_free(o); -+ return ret; -+#else /* CONFIG_USE_NDISUIO */ -+ char *buf; -+ PACKET_OID_DATA *o; -+ int ret; -+ -+ buf = os_zalloc(sizeof(*o) + len); -+ if (buf == NULL) -+ return -1; -+ o = (PACKET_OID_DATA *) buf; -+ o->Oid = oid; -+ o->Length = len; -+ -+ if (!PacketRequest(drv->adapter, FALSE, o)) { -+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed", -+ __func__, oid, len); -+ os_free(buf); -+ return -1; -+ } -+ if (o->Length > len) { -+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)", -+ __func__, oid, (unsigned int) o->Length, len); -+ os_free(buf); -+ return -1; -+ } -+ os_memcpy(data, o->Data, o->Length); -+ ret = o->Length; -+ os_free(buf); -+ return ret; -+#endif /* CONFIG_USE_NDISUIO */ -+} -+ -+ -+static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid, -+ const char *data, size_t len) -+{ -+#ifdef CONFIG_USE_NDISUIO -+ NDISUIO_SET_OID *o; -+ size_t buflen, reallen; -+ DWORD written; -+ char txt[50]; -+ -+ os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid); -+ wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len); -+ -+ buflen = sizeof(*o) + len; -+ reallen = buflen - sizeof(o->Data); -+ o = os_zalloc(buflen); -+ if (o == NULL) -+ return -1; -+ o->Oid = oid; -+#ifdef _WIN32_WCE -+ o->ptcDeviceName = drv->adapter_name; -+#endif /* _WIN32_WCE */ -+ if (data) -+ os_memcpy(o->Data, data, len); -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_SET_OID_VALUE, -+ o, reallen, NULL, 0, &written, NULL)) { -+ wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_SET_OID_VALUE " -+ "(oid=%08x) failed: %d", oid, (int) GetLastError()); -+ os_free(o); -+ return -1; -+ } -+ os_free(o); -+ return 0; -+#else /* CONFIG_USE_NDISUIO */ -+ char *buf; -+ PACKET_OID_DATA *o; -+ char txt[50]; -+ -+ os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid); -+ wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len); -+ -+ buf = os_zalloc(sizeof(*o) + len); -+ if (buf == NULL) -+ return -1; -+ o = (PACKET_OID_DATA *) buf; -+ o->Oid = oid; -+ o->Length = len; -+ if (data) -+ os_memcpy(o->Data, data, len); -+ -+ if (!PacketRequest(drv->adapter, TRUE, o)) { -+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed", -+ __func__, oid, len); -+ os_free(buf); -+ return -1; -+ } -+ os_free(buf); -+ return 0; -+#endif /* CONFIG_USE_NDISUIO */ -+} -+ -+ -+static int ndis_set_auth_mode(struct wpa_driver_ndis_data *drv, int mode) -+{ -+ u32 auth_mode = mode; -+ if (ndis_set_oid(drv, OID_802_11_AUTHENTICATION_MODE, -+ (char *) &auth_mode, sizeof(auth_mode)) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to set " -+ "OID_802_11_AUTHENTICATION_MODE (%d)", -+ (int) auth_mode); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int ndis_get_auth_mode(struct wpa_driver_ndis_data *drv) -+{ -+ u32 auth_mode; -+ int res; -+ res = ndis_get_oid(drv, OID_802_11_AUTHENTICATION_MODE, -+ (char *) &auth_mode, sizeof(auth_mode)); -+ if (res != sizeof(auth_mode)) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to get " -+ "OID_802_11_AUTHENTICATION_MODE"); -+ return -1; -+ } -+ return auth_mode; -+} -+ -+ -+static int ndis_set_encr_status(struct wpa_driver_ndis_data *drv, int encr) -+{ -+ u32 encr_status = encr; -+ if (ndis_set_oid(drv, OID_802_11_ENCRYPTION_STATUS, -+ (char *) &encr_status, sizeof(encr_status)) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to set " -+ "OID_802_11_ENCRYPTION_STATUS (%d)", encr); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int ndis_get_encr_status(struct wpa_driver_ndis_data *drv) -+{ -+ u32 encr; -+ int res; -+ res = ndis_get_oid(drv, OID_802_11_ENCRYPTION_STATUS, -+ (char *) &encr, sizeof(encr)); -+ if (res != sizeof(encr)) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to get " -+ "OID_802_11_ENCRYPTION_STATUS"); -+ return -1; -+ } -+ return encr; -+} -+ -+ -+static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ -+ if (drv->wired) { -+ /* -+ * Report PAE group address as the "BSSID" for wired -+ * connection. -+ */ -+ os_memcpy(bssid, pae_group_addr, ETH_ALEN); -+ return 0; -+ } -+ -+ return ndis_get_oid(drv, OID_802_11_BSSID, (char *) bssid, ETH_ALEN) < -+ 0 ? -1 : 0; -+} -+ -+ -+static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ NDIS_802_11_SSID buf; -+ int res; -+ -+ res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf)); -+ if (res < 4) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID"); -+ if (drv->wired) { -+ wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure " -+ "with a wired interface"); -+ return 0; -+ } -+ return -1; -+ } -+ os_memcpy(ssid, buf.Ssid, buf.SsidLength); -+ return buf.SsidLength; -+} -+ -+ -+static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv, -+ const u8 *ssid, size_t ssid_len) -+{ -+ NDIS_802_11_SSID buf; -+ -+ os_memset(&buf, 0, sizeof(buf)); -+ buf.SsidLength = ssid_len; -+ os_memcpy(buf.Ssid, ssid, ssid_len); -+ /* -+ * Make sure radio is marked enabled here so that scan request will not -+ * force SSID to be changed to a random one in order to enable radio at -+ * that point. -+ */ -+ drv->radio_enabled = 1; -+ return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf)); -+} -+ -+ -+/* Disconnect using OID_802_11_DISASSOCIATE. This will also turn the radio off. -+ */ -+static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv) -+{ -+ drv->radio_enabled = 0; -+ return ndis_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4); -+} -+ -+ -+/* Disconnect by setting SSID to random (i.e., likely not used). */ -+static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv) -+{ -+ char ssid[32]; -+ int i; -+ for (i = 0; i < 32; i++) -+ ssid[i] = rand() & 0xff; -+ return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32); -+} -+ -+ -+static int wpa_driver_ndis_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ return wpa_driver_ndis_disconnect(drv); -+} -+ -+ -+static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ return wpa_driver_ndis_disconnect(drv); -+} -+ -+ -+static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+} -+ -+ -+static int wpa_driver_ndis_scan_native80211( -+ struct wpa_driver_ndis_data *drv, -+ struct wpa_driver_scan_params *params) -+{ -+ DOT11_SCAN_REQUEST_V2 req; -+ int res; -+ -+ os_memset(&req, 0, sizeof(req)); -+ req.dot11BSSType = dot11_BSS_type_any; -+ os_memset(req.dot11BSSID, 0xff, ETH_ALEN); -+ req.dot11ScanType = dot11_scan_type_auto; -+ res = ndis_set_oid(drv, OID_DOT11_SCAN_REQUEST, (char *) &req, -+ sizeof(req)); -+ eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx); -+ eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv, -+ drv->ctx); -+ return res; -+} -+ -+ -+static int wpa_driver_ndis_scan(void *priv, -+ struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ int res; -+ -+ if (drv->native80211) -+ return wpa_driver_ndis_scan_native80211(drv, params); -+ -+ if (!drv->radio_enabled) { -+ wpa_printf(MSG_DEBUG, "NDIS: turning radio on before the first" -+ " scan"); -+ if (wpa_driver_ndis_disconnect(drv) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: failed to enable radio"); -+ } -+ drv->radio_enabled = 1; -+ } -+ -+ res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, " ", 4); -+ eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx); -+ eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv, -+ drv->ctx); -+ return res; -+} -+ -+ -+static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) -+{ -+ const u8 *end, *pos; -+ -+ pos = (const u8 *) (res + 1); -+ end = pos + res->ie_len; -+ -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == ie) -+ return pos; -+ pos += 2 + pos[1]; -+ } -+ -+ return NULL; -+} -+ -+ -+static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid( -+ struct wpa_scan_res *r, NDIS_802_11_SSID *ssid) -+{ -+ struct wpa_scan_res *nr; -+ u8 *pos; -+ -+ if (wpa_scan_get_ie(r, WLAN_EID_SSID)) -+ return r; /* SSID IE already present */ -+ -+ if (ssid->SsidLength == 0 || ssid->SsidLength > 32) -+ return r; /* No valid SSID inside scan data */ -+ -+ nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength); -+ if (nr == NULL) -+ return r; -+ -+ pos = ((u8 *) (nr + 1)) + nr->ie_len; -+ *pos++ = WLAN_EID_SSID; -+ *pos++ = ssid->SsidLength; -+ os_memcpy(pos, ssid->Ssid, ssid->SsidLength); -+ nr->ie_len += 2 + ssid->SsidLength; -+ -+ return nr; -+} -+ -+ -+static struct wpa_scan_results * wpa_driver_ndis_get_scan_results(void *priv) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ NDIS_802_11_BSSID_LIST_EX *b; -+ size_t blen, count, i; -+ int len; -+ char *pos; -+ struct wpa_scan_results *results; -+ struct wpa_scan_res *r; -+ -+ blen = 65535; -+ b = os_zalloc(blen); -+ if (b == NULL) -+ return NULL; -+ len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen); -+ if (len < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results"); -+ os_free(b); -+ return NULL; -+ } -+ count = b->NumberOfItems; -+ -+ results = os_zalloc(sizeof(*results)); -+ if (results == NULL) { -+ os_free(b); -+ return NULL; -+ } -+ results->res = os_zalloc(count * sizeof(struct wpa_scan_res *)); -+ if (results->res == NULL) { -+ os_free(results); -+ os_free(b); -+ return NULL; -+ } -+ -+ pos = (char *) &b->Bssid[0]; -+ for (i = 0; i < count; i++) { -+ NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos; -+ NDIS_802_11_FIXED_IEs *fixed; -+ -+ if (bss->IELength < sizeof(NDIS_802_11_FIXED_IEs)) { -+ wpa_printf(MSG_DEBUG, "NDIS: too small IELength=%d", -+ (int) bss->IELength); -+ break; -+ } -+ if (((char *) bss->IEs) + bss->IELength > (char *) b + blen) { -+ /* -+ * Some NDIS drivers have been reported to include an -+ * entry with an invalid IELength in scan results and -+ * this has crashed wpa_supplicant, so validate the -+ * returned value before using it. -+ */ -+ wpa_printf(MSG_DEBUG, "NDIS: skipped invalid scan " -+ "result IE (BSSID=" MACSTR ") IELength=%d", -+ MAC2STR(bss->MacAddress), -+ (int) bss->IELength); -+ break; -+ } -+ -+ r = os_zalloc(sizeof(*r) + bss->IELength - -+ sizeof(NDIS_802_11_FIXED_IEs)); -+ if (r == NULL) -+ break; -+ -+ os_memcpy(r->bssid, bss->MacAddress, ETH_ALEN); -+ r->level = (int) bss->Rssi; -+ r->freq = bss->Configuration.DSConfig / 1000; -+ fixed = (NDIS_802_11_FIXED_IEs *) bss->IEs; -+ r->beacon_int = WPA_GET_LE16((u8 *) &fixed->BeaconInterval); -+ r->caps = WPA_GET_LE16((u8 *) &fixed->Capabilities); -+ r->tsf = WPA_GET_LE64(fixed->Timestamp); -+ os_memcpy(r + 1, bss->IEs + sizeof(NDIS_802_11_FIXED_IEs), -+ bss->IELength - sizeof(NDIS_802_11_FIXED_IEs)); -+ r->ie_len = bss->IELength - sizeof(NDIS_802_11_FIXED_IEs); -+ r = wpa_driver_ndis_add_scan_ssid(r, &bss->Ssid); -+ -+ results->res[results->num++] = r; -+ -+ pos += bss->Length; -+ if (pos > (char *) b + blen) -+ break; -+ } -+ -+ os_free(b); -+ -+ return results; -+} -+ -+ -+static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv, -+ int key_idx, const u8 *addr, -+ const u8 *bssid, int pairwise) -+{ -+ NDIS_802_11_REMOVE_KEY rkey; -+ NDIS_802_11_KEY_INDEX index; -+ int res, res2; -+ -+ os_memset(&rkey, 0, sizeof(rkey)); -+ -+ rkey.Length = sizeof(rkey); -+ rkey.KeyIndex = key_idx; -+ if (pairwise) -+ rkey.KeyIndex |= 1 << 30; -+ os_memcpy(rkey.BSSID, bssid, ETH_ALEN); -+ -+ res = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey, -+ sizeof(rkey)); -+ if (!pairwise) { -+ index = key_idx; -+ res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP, -+ (char *) &index, sizeof(index)); -+ } else -+ res2 = 0; -+ -+ if (res < 0 && res2 < 0) -+ return -1; -+ return 0; -+} -+ -+ -+static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv, -+ int pairwise, int key_idx, int set_tx, -+ const u8 *key, size_t key_len) -+{ -+ NDIS_802_11_WEP *wep; -+ size_t len; -+ int res; -+ -+ len = 12 + key_len; -+ wep = os_zalloc(len); -+ if (wep == NULL) -+ return -1; -+ wep->Length = len; -+ wep->KeyIndex = key_idx; -+ if (set_tx) -+ wep->KeyIndex |= 1 << 31; -+#if 0 /* Setting bit30 does not seem to work with some NDIS drivers */ -+ if (pairwise) -+ wep->KeyIndex |= 1 << 30; -+#endif -+ wep->KeyLength = key_len; -+ os_memcpy(wep->KeyMaterial, key, key_len); -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP", -+ (u8 *) wep, len); -+ res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len); -+ -+ os_free(wep); -+ -+ return res; -+} -+ -+ -+static int wpa_driver_ndis_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ size_t len, i; -+ NDIS_802_11_KEY *nkey; -+ int res, pairwise; -+ u8 bssid[ETH_ALEN]; -+ -+ if (addr == NULL || is_broadcast_ether_addr(addr)) { -+ /* Group Key */ -+ pairwise = 0; -+ if (wpa_driver_ndis_get_bssid(drv, bssid) < 0) -+ os_memset(bssid, 0xff, ETH_ALEN); -+ } else { -+ /* Pairwise Key */ -+ pairwise = 1; -+ os_memcpy(bssid, addr, ETH_ALEN); -+ } -+ -+ if (alg == WPA_ALG_NONE || key_len == 0) { -+ return wpa_driver_ndis_remove_key(drv, key_idx, addr, bssid, -+ pairwise); -+ } -+ -+ if (alg == WPA_ALG_WEP) { -+ return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx, -+ key, key_len); -+ } -+ -+ len = 12 + 6 + 6 + 8 + key_len; -+ -+ nkey = os_zalloc(len); -+ if (nkey == NULL) -+ return -1; -+ -+ nkey->Length = len; -+ nkey->KeyIndex = key_idx; -+ if (set_tx) -+ nkey->KeyIndex |= 1 << 31; -+ if (pairwise) -+ nkey->KeyIndex |= 1 << 30; -+ if (seq && seq_len) -+ nkey->KeyIndex |= 1 << 29; -+ nkey->KeyLength = key_len; -+ os_memcpy(nkey->BSSID, bssid, ETH_ALEN); -+ if (seq && seq_len) { -+ for (i = 0; i < seq_len; i++) -+ nkey->KeyRSC |= (ULONGLONG) seq[i] << (i * 8); -+ } -+ if (alg == WPA_ALG_TKIP && key_len == 32) { -+ os_memcpy(nkey->KeyMaterial, key, 16); -+ os_memcpy(nkey->KeyMaterial + 16, key + 24, 8); -+ os_memcpy(nkey->KeyMaterial + 24, key + 16, 8); -+ } else { -+ os_memcpy(nkey->KeyMaterial, key, key_len); -+ } -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY", -+ (u8 *) nkey, len); -+ res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len); -+ os_free(nkey); -+ -+ return res; -+} -+ -+ -+static int -+wpa_driver_ndis_associate(void *priv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ u32 auth_mode, encr, priv_mode, mode; -+ u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -+ -+ drv->mode = params->mode; -+ -+ /* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys, -+ * so static WEP keys needs to be set again after this. */ -+ if (params->mode == IEEE80211_MODE_IBSS) { -+ mode = Ndis802_11IBSS; -+ /* Need to make sure that BSSID polling is enabled for -+ * IBSS mode. */ -+ eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL); -+ eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, -+ drv, NULL); -+ } else -+ mode = Ndis802_11Infrastructure; -+ if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE, -+ (char *) &mode, sizeof(mode)) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to set " -+ "OID_802_11_INFRASTRUCTURE_MODE (%d)", -+ (int) mode); -+ /* Try to continue anyway */ -+ } -+ -+ if (params->key_mgmt_suite == KEY_MGMT_NONE || -+ params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) { -+ /* Re-set WEP keys if static WEP configuration is used. */ -+ int i; -+ for (i = 0; i < 4; i++) { -+ if (!params->wep_key[i]) -+ continue; -+ wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP " -+ "key %d", i); -+ wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP, -+ bcast, i, -+ i == params->wep_tx_keyidx, -+ NULL, 0, params->wep_key[i], -+ params->wep_key_len[i]); -+ } -+ } -+ -+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { -+ if (params->auth_alg & WPA_AUTH_ALG_SHARED) { -+ if (params->auth_alg & WPA_AUTH_ALG_OPEN) -+ auth_mode = Ndis802_11AuthModeAutoSwitch; -+ else -+ auth_mode = Ndis802_11AuthModeShared; -+ } else -+ auth_mode = Ndis802_11AuthModeOpen; -+ priv_mode = Ndis802_11PrivFilterAcceptAll; -+ } else if (params->wpa_ie[0] == WLAN_EID_RSN) { -+ priv_mode = Ndis802_11PrivFilter8021xWEP; -+ if (params->key_mgmt_suite == KEY_MGMT_PSK) -+ auth_mode = Ndis802_11AuthModeWPA2PSK; -+ else -+ auth_mode = Ndis802_11AuthModeWPA2; -+#ifdef CONFIG_WPS -+ } else if (params->key_mgmt_suite == KEY_MGMT_WPS) { -+ auth_mode = Ndis802_11AuthModeOpen; -+ priv_mode = Ndis802_11PrivFilterAcceptAll; -+ if (params->wps == WPS_MODE_PRIVACY) { -+ u8 dummy_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 }; -+ /* -+ * Some NDIS drivers refuse to associate in open mode -+ * configuration due to Privacy field mismatch, so use -+ * a workaround to make the configuration look like -+ * matching one for WPS provisioning. -+ */ -+ wpa_printf(MSG_DEBUG, "NDIS: Set dummy WEP key as a " -+ "workaround to allow driver to associate " -+ "for WPS"); -+ wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP, -+ bcast, 0, 1, -+ NULL, 0, dummy_key, -+ sizeof(dummy_key)); -+ } -+#endif /* CONFIG_WPS */ -+ } else { -+ priv_mode = Ndis802_11PrivFilter8021xWEP; -+ if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE) -+ auth_mode = Ndis802_11AuthModeWPANone; -+ else if (params->key_mgmt_suite == KEY_MGMT_PSK) -+ auth_mode = Ndis802_11AuthModeWPAPSK; -+ else -+ auth_mode = Ndis802_11AuthModeWPA; -+ } -+ -+ switch (params->pairwise_suite) { -+ case CIPHER_CCMP: -+ encr = Ndis802_11Encryption3Enabled; -+ break; -+ case CIPHER_TKIP: -+ encr = Ndis802_11Encryption2Enabled; -+ break; -+ case CIPHER_WEP40: -+ case CIPHER_WEP104: -+ encr = Ndis802_11Encryption1Enabled; -+ break; -+ case CIPHER_NONE: -+#ifdef CONFIG_WPS -+ if (params->wps == WPS_MODE_PRIVACY) { -+ encr = Ndis802_11Encryption1Enabled; -+ break; -+ } -+#endif /* CONFIG_WPS */ -+ if (params->group_suite == CIPHER_CCMP) -+ encr = Ndis802_11Encryption3Enabled; -+ else if (params->group_suite == CIPHER_TKIP) -+ encr = Ndis802_11Encryption2Enabled; -+ else -+ encr = Ndis802_11EncryptionDisabled; -+ break; -+ default: -+#ifdef CONFIG_WPS -+ if (params->wps == WPS_MODE_PRIVACY) { -+ encr = Ndis802_11Encryption1Enabled; -+ break; -+ } -+#endif /* CONFIG_WPS */ -+ encr = Ndis802_11EncryptionDisabled; -+ break; -+ }; -+ -+ if (ndis_set_oid(drv, OID_802_11_PRIVACY_FILTER, -+ (char *) &priv_mode, sizeof(priv_mode)) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to set " -+ "OID_802_11_PRIVACY_FILTER (%d)", -+ (int) priv_mode); -+ /* Try to continue anyway */ -+ } -+ -+ ndis_set_auth_mode(drv, auth_mode); -+ ndis_set_encr_status(drv, encr); -+ -+ if (params->bssid) { -+ ndis_set_oid(drv, OID_802_11_BSSID, (char *) params->bssid, -+ ETH_ALEN); -+ drv->oid_bssid_set = 1; -+ } else if (drv->oid_bssid_set) { -+ ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff", -+ ETH_ALEN); -+ drv->oid_bssid_set = 0; -+ } -+ -+ return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len); -+} -+ -+ -+static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv) -+{ -+ int len, count, i, ret; -+ struct ndis_pmkid_entry *entry; -+ NDIS_802_11_PMKID *p; -+ -+ count = 0; -+ entry = drv->pmkid; -+ while (entry) { -+ count++; -+ if (count >= drv->no_of_pmkid) -+ break; -+ entry = entry->next; -+ } -+ len = 8 + count * sizeof(BSSID_INFO); -+ p = os_zalloc(len); -+ if (p == NULL) -+ return -1; -+ -+ p->Length = len; -+ p->BSSIDInfoCount = count; -+ entry = drv->pmkid; -+ for (i = 0; i < count; i++) { -+ os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN); -+ os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16); -+ entry = entry->next; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (u8 *) p, len); -+ ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len); -+ os_free(p); -+ return ret; -+} -+ -+ -+static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ struct ndis_pmkid_entry *entry, *prev; -+ -+ if (drv->no_of_pmkid == 0) -+ return 0; -+ -+ prev = NULL; -+ entry = drv->pmkid; -+ while (entry) { -+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0) -+ break; -+ prev = entry; -+ entry = entry->next; -+ } -+ -+ if (entry) { -+ /* Replace existing entry for this BSSID and move it into the -+ * beginning of the list. */ -+ os_memcpy(entry->pmkid, pmkid, 16); -+ if (prev) { -+ prev->next = entry->next; -+ entry->next = drv->pmkid; -+ drv->pmkid = entry; -+ } -+ } else { -+ entry = os_malloc(sizeof(*entry)); -+ if (entry) { -+ os_memcpy(entry->bssid, bssid, ETH_ALEN); -+ os_memcpy(entry->pmkid, pmkid, 16); -+ entry->next = drv->pmkid; -+ drv->pmkid = entry; -+ } -+ } -+ -+ return wpa_driver_ndis_set_pmkid(drv); -+} -+ -+ -+static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ struct ndis_pmkid_entry *entry, *prev; -+ -+ if (drv->no_of_pmkid == 0) -+ return 0; -+ -+ entry = drv->pmkid; -+ prev = NULL; -+ while (entry) { -+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 && -+ os_memcmp(entry->pmkid, pmkid, 16) == 0) { -+ if (prev) -+ prev->next = entry->next; -+ else -+ drv->pmkid = entry->next; -+ os_free(entry); -+ break; -+ } -+ prev = entry; -+ entry = entry->next; -+ } -+ return wpa_driver_ndis_set_pmkid(drv); -+} -+ -+ -+static int wpa_driver_ndis_flush_pmkid(void *priv) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ NDIS_802_11_PMKID p; -+ struct ndis_pmkid_entry *pmkid, *prev; -+ int prev_authmode, ret; -+ -+ if (drv->no_of_pmkid == 0) -+ return 0; -+ -+ pmkid = drv->pmkid; -+ drv->pmkid = NULL; -+ while (pmkid) { -+ prev = pmkid; -+ pmkid = pmkid->next; -+ os_free(prev); -+ } -+ -+ /* -+ * Some drivers may refuse OID_802_11_PMKID if authMode is not set to -+ * WPA2, so change authMode temporarily, if needed. -+ */ -+ prev_authmode = ndis_get_auth_mode(drv); -+ if (prev_authmode != Ndis802_11AuthModeWPA2) -+ ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA2); -+ -+ os_memset(&p, 0, sizeof(p)); -+ p.Length = 8; -+ p.BSSIDInfoCount = 0; -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)", -+ (u8 *) &p, 8); -+ ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8); -+ -+ if (prev_authmode != Ndis802_11AuthModeWPA2) -+ ndis_set_auth_mode(drv, prev_authmode); -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv) -+{ -+ char buf[512], *pos; -+ NDIS_802_11_ASSOCIATION_INFORMATION *ai; -+ int len; -+ union wpa_event_data data; -+ NDIS_802_11_BSSID_LIST_EX *b; -+ size_t blen, i; -+ -+ len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf, -+ sizeof(buf)); -+ if (len < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: failed to get association " -+ "information"); -+ return -1; -+ } -+ if (len > sizeof(buf)) { -+ /* Some drivers seem to be producing incorrect length for this -+ * data. Limit the length to the current buffer size to avoid -+ * crashing in hexdump. The data seems to be otherwise valid, -+ * so better try to use it. */ -+ wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association " -+ "information length %d", len); -+ len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, -+ buf, sizeof(buf)); -+ if (len < -1) { -+ wpa_printf(MSG_DEBUG, "NDIS: re-reading association " -+ "information failed"); -+ return -1; -+ } -+ if (len > sizeof(buf)) { -+ wpa_printf(MSG_DEBUG, "NDIS: ignored bogus association" -+ " information length %d (re-read)", len); -+ len = sizeof(buf); -+ } -+ } -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: association information", -+ (u8 *) buf, len); -+ if (len < sizeof(*ai)) { -+ wpa_printf(MSG_DEBUG, "NDIS: too short association " -+ "information"); -+ return -1; -+ } -+ ai = (NDIS_802_11_ASSOCIATION_INFORMATION *) buf; -+ wpa_printf(MSG_DEBUG, "NDIS: ReqFixed=0x%x RespFixed=0x%x off_req=%d " -+ "off_resp=%d len_req=%d len_resp=%d", -+ ai->AvailableRequestFixedIEs, ai->AvailableResponseFixedIEs, -+ (int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs, -+ (int) ai->RequestIELength, (int) ai->ResponseIELength); -+ -+ if (ai->OffsetRequestIEs + ai->RequestIELength > (unsigned) len || -+ ai->OffsetResponseIEs + ai->ResponseIELength > (unsigned) len) { -+ wpa_printf(MSG_DEBUG, "NDIS: association information - " -+ "IE overflow"); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs", -+ (u8 *) buf + ai->OffsetRequestIEs, ai->RequestIELength); -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs", -+ (u8 *) buf + ai->OffsetResponseIEs, ai->ResponseIELength); -+ -+ os_memset(&data, 0, sizeof(data)); -+ data.assoc_info.req_ies = (u8 *) buf + ai->OffsetRequestIEs; -+ data.assoc_info.req_ies_len = ai->RequestIELength; -+ data.assoc_info.resp_ies = (u8 *) buf + ai->OffsetResponseIEs; -+ data.assoc_info.resp_ies_len = ai->ResponseIELength; -+ -+ blen = 65535; -+ b = os_zalloc(blen); -+ if (b == NULL) -+ goto skip_scan_results; -+ len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen); -+ if (len < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results"); -+ os_free(b); -+ b = NULL; -+ goto skip_scan_results; -+ } -+ wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo", -+ (unsigned int) b->NumberOfItems); -+ -+ pos = (char *) &b->Bssid[0]; -+ for (i = 0; i < b->NumberOfItems; i++) { -+ NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos; -+ if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 && -+ bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) { -+ data.assoc_info.beacon_ies = -+ ((u8 *) bss->IEs) + -+ sizeof(NDIS_802_11_FIXED_IEs); -+ data.assoc_info.beacon_ies_len = -+ bss->IELength - sizeof(NDIS_802_11_FIXED_IEs); -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs", -+ data.assoc_info.beacon_ies, -+ data.assoc_info.beacon_ies_len); -+ break; -+ } -+ pos += bss->Length; -+ if (pos > (char *) b + blen) -+ break; -+ } -+ -+skip_scan_results: -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); -+ -+ os_free(b); -+ -+ return 0; -+} -+ -+ -+static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_ndis_data *drv = eloop_ctx; -+ u8 bssid[ETH_ALEN]; -+ int poll; -+ -+ if (drv->wired) -+ return; -+ -+ if (wpa_driver_ndis_get_bssid(drv, bssid)) { -+ /* Disconnected */ -+ if (!is_zero_ether_addr(drv->bssid)) { -+ os_memset(drv->bssid, 0, ETH_ALEN); -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -+ } -+ } else { -+ /* Connected */ -+ if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) { -+ os_memcpy(drv->bssid, bssid, ETH_ALEN); -+ wpa_driver_ndis_get_associnfo(drv); -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -+ } -+ } -+ -+ /* When using integrated NDIS event receiver, we can skip BSSID -+ * polling when using infrastructure network. However, when using -+ * IBSS mode, many driver do not seem to generate connection event, -+ * so we need to enable BSSID polling to figure out when IBSS network -+ * has been formed. -+ */ -+ poll = drv->mode == IEEE80211_MODE_IBSS; -+#ifndef CONFIG_NDIS_EVENTS_INTEGRATED -+#ifndef _WIN32_WCE -+ poll = 1; -+#endif /* _WIN32_WCE */ -+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ -+ -+ if (poll) { -+ eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, -+ drv, NULL); -+ } -+} -+ -+ -+static void wpa_driver_ndis_poll(void *priv) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL); -+ wpa_driver_ndis_poll_timeout(drv, NULL); -+} -+ -+ -+/* Called when driver generates Media Connect Event by calling -+ * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_CONNECT */ -+void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv) -+{ -+ wpa_printf(MSG_DEBUG, "NDIS: Media Connect Event"); -+ if (wpa_driver_ndis_get_bssid(drv, drv->bssid) == 0) { -+ wpa_driver_ndis_get_associnfo(drv); -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -+ } -+} -+ -+ -+/* Called when driver generates Media Disconnect Event by calling -+ * NdisMIndicateStatus() with NDIS_STATUS_MEDIA_DISCONNECT */ -+void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv) -+{ -+ wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event"); -+ os_memset(drv->bssid, 0, ETH_ALEN); -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -+} -+ -+ -+static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv, -+ const u8 *data, size_t data_len) -+{ -+ NDIS_802_11_AUTHENTICATION_REQUEST *req; -+ int pairwise = 0, group = 0; -+ union wpa_event_data event; -+ -+ if (data_len < sizeof(*req)) { -+ wpa_printf(MSG_DEBUG, "NDIS: Too short Authentication Request " -+ "Event (len=%d)", data_len); -+ return; -+ } -+ req = (NDIS_802_11_AUTHENTICATION_REQUEST *) data; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Authentication Request Event: " -+ "Bssid " MACSTR " Flags 0x%x", -+ MAC2STR(req->Bssid), (int) req->Flags); -+ -+ if ((req->Flags & NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) == -+ NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR) -+ pairwise = 1; -+ else if ((req->Flags & NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) == -+ NDIS_802_11_AUTH_REQUEST_GROUP_ERROR) -+ group = 1; -+ -+ if (pairwise || group) { -+ os_memset(&event, 0, sizeof(event)); -+ event.michael_mic_failure.unicast = pairwise; -+ wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, -+ &event); -+ } -+} -+ -+ -+static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv, -+ const u8 *data, size_t data_len) -+{ -+ NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid; -+ size_t i; -+ union wpa_event_data event; -+ -+ if (data_len < 8) { -+ wpa_printf(MSG_DEBUG, "NDIS: Too short PMKID Candidate List " -+ "Event (len=%d)", data_len); -+ return; -+ } -+ pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data; -+ wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List Event - Version %d " -+ "NumCandidates %d", -+ (int) pmkid->Version, (int) pmkid->NumCandidates); -+ -+ if (pmkid->Version != 1) { -+ wpa_printf(MSG_DEBUG, "NDIS: Unsupported PMKID Candidate List " -+ "Version %d", (int) pmkid->Version); -+ return; -+ } -+ -+ if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) { -+ wpa_printf(MSG_DEBUG, "NDIS: PMKID Candidate List underflow"); -+ return; -+ } -+ -+ os_memset(&event, 0, sizeof(event)); -+ for (i = 0; i < pmkid->NumCandidates; i++) { -+ PMKID_CANDIDATE *p = &pmkid->CandidateList[i]; -+ wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x", -+ i, MAC2STR(p->BSSID), (int) p->Flags); -+ os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN); -+ event.pmkid_candidate.index = i; -+ event.pmkid_candidate.preauth = -+ p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED; -+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, -+ &event); -+ } -+} -+ -+ -+/* Called when driver calls NdisMIndicateStatus() with -+ * NDIS_STATUS_MEDIA_SPECIFIC_INDICATION */ -+void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv, -+ const u8 *data, size_t data_len) -+{ -+ NDIS_802_11_STATUS_INDICATION *status; -+ -+ if (data == NULL || data_len < sizeof(*status)) -+ return; -+ -+ wpa_hexdump(MSG_DEBUG, "NDIS: Media Specific Indication", -+ data, data_len); -+ -+ status = (NDIS_802_11_STATUS_INDICATION *) data; -+ data += sizeof(status); -+ data_len -= sizeof(status); -+ -+ switch (status->StatusType) { -+ case Ndis802_11StatusType_Authentication: -+ wpa_driver_ndis_event_auth(drv, data, data_len); -+ break; -+ case Ndis802_11StatusType_PMKID_CandidateList: -+ wpa_driver_ndis_event_pmkid(drv, data, data_len); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "NDIS: Unknown StatusType %d", -+ (int) status->StatusType); -+ break; -+ } -+} -+ -+ -+/* Called when an adapter is added */ -+void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv) -+{ -+ union wpa_event_data event; -+ int i; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Arrival"); -+ -+ for (i = 0; i < 30; i++) { -+ /* Re-open Packet32/NDISUIO connection */ -+ wpa_driver_ndis_adapter_close(drv); -+ if (wpa_driver_ndis_adapter_init(drv) < 0 || -+ wpa_driver_ndis_adapter_open(drv) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialization " -+ "(%d) failed", i); -+ os_sleep(1, 0); -+ } else { -+ wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialized"); -+ break; -+ } -+ } -+ -+ os_memset(&event, 0, sizeof(event)); -+ os_strlcpy(event.interface_status.ifname, drv->ifname, -+ sizeof(event.interface_status.ifname)); -+ event.interface_status.ievent = EVENT_INTERFACE_ADDED; -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -+} -+ -+ -+/* Called when an adapter is removed */ -+void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv) -+{ -+ union wpa_event_data event; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Removal"); -+ os_memset(&event, 0, sizeof(event)); -+ os_strlcpy(event.interface_status.ifname, drv->ifname, -+ sizeof(event.interface_status.ifname)); -+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED; -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -+} -+ -+ -+static void -+wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv) -+{ -+ wpa_printf(MSG_DEBUG, "NDIS: verifying driver WPA capability"); -+ -+ if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPA) == 0 && -+ ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPA) { -+ wpa_printf(MSG_DEBUG, "NDIS: WPA key management supported"); -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA; -+ } -+ -+ if (ndis_set_auth_mode(drv, Ndis802_11AuthModeWPAPSK) == 0 && -+ ndis_get_auth_mode(drv) == Ndis802_11AuthModeWPAPSK) { -+ wpa_printf(MSG_DEBUG, "NDIS: WPA-PSK key management " -+ "supported"); -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; -+ } -+ -+ if (ndis_set_encr_status(drv, Ndis802_11Encryption3Enabled) == 0 && -+ ndis_get_encr_status(drv) == Ndis802_11Encryption3KeyAbsent) { -+ wpa_printf(MSG_DEBUG, "NDIS: CCMP encryption supported"); -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; -+ } -+ -+ if (ndis_set_encr_status(drv, Ndis802_11Encryption2Enabled) == 0 && -+ ndis_get_encr_status(drv) == Ndis802_11Encryption2KeyAbsent) { -+ wpa_printf(MSG_DEBUG, "NDIS: TKIP encryption supported"); -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; -+ } -+ -+ if (ndis_set_encr_status(drv, Ndis802_11Encryption1Enabled) == 0 && -+ ndis_get_encr_status(drv) == Ndis802_11Encryption1KeyAbsent) { -+ wpa_printf(MSG_DEBUG, "NDIS: WEP encryption supported"); -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | -+ WPA_DRIVER_CAPA_ENC_WEP104; -+ } -+ -+ if (ndis_set_auth_mode(drv, Ndis802_11AuthModeShared) == 0 && -+ ndis_get_auth_mode(drv) == Ndis802_11AuthModeShared) { -+ drv->capa.auth |= WPA_DRIVER_AUTH_SHARED; -+ } -+ -+ if (ndis_set_auth_mode(drv, Ndis802_11AuthModeOpen) == 0 && -+ ndis_get_auth_mode(drv) == Ndis802_11AuthModeOpen) { -+ drv->capa.auth |= WPA_DRIVER_AUTH_OPEN; -+ } -+ -+ ndis_set_encr_status(drv, Ndis802_11EncryptionDisabled); -+ -+ /* Could also verify OID_802_11_ADD_KEY error reporting and -+ * support for OID_802_11_ASSOCIATION_INFORMATION. */ -+ -+ if (drv->capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA && -+ drv->capa.enc & (WPA_DRIVER_CAPA_ENC_TKIP | -+ WPA_DRIVER_CAPA_ENC_CCMP)) { -+ wpa_printf(MSG_DEBUG, "NDIS: driver supports WPA"); -+ drv->has_capability = 1; -+ } else { -+ wpa_printf(MSG_DEBUG, "NDIS: no WPA support found"); -+ } -+ -+ wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x " -+ "enc 0x%x auth 0x%x", -+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth); -+} -+ -+ -+static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv) -+{ -+ char buf[512]; -+ int len; -+ size_t i; -+ NDIS_802_11_CAPABILITY *c; -+ -+ drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE; -+ -+ len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf)); -+ if (len < 0) { -+ wpa_driver_ndis_get_wpa_capability(drv); -+ return; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", (u8 *) buf, len); -+ c = (NDIS_802_11_CAPABILITY *) buf; -+ if (len < sizeof(*c) || c->Version != 2) { -+ wpa_printf(MSG_DEBUG, "NDIS: unsupported " -+ "OID_802_11_CAPABILITY data"); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - " -+ "NoOfPMKIDs %d NoOfAuthEncrPairs %d", -+ (int) c->NoOfPMKIDs, -+ (int) c->NoOfAuthEncryptPairsSupported); -+ drv->has_capability = 1; -+ drv->no_of_pmkid = c->NoOfPMKIDs; -+ for (i = 0; i < c->NoOfAuthEncryptPairsSupported; i++) { -+ NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae; -+ ae = &c->AuthenticationEncryptionSupported[i]; -+ if ((char *) (ae + 1) > buf + len) { -+ wpa_printf(MSG_DEBUG, "NDIS: auth/encr pair list " -+ "overflow"); -+ break; -+ } -+ wpa_printf(MSG_MSGDUMP, "NDIS: %d - auth %d encr %d", -+ i, (int) ae->AuthModeSupported, -+ (int) ae->EncryptStatusSupported); -+ switch (ae->AuthModeSupported) { -+ case Ndis802_11AuthModeOpen: -+ drv->capa.auth |= WPA_DRIVER_AUTH_OPEN; -+ break; -+ case Ndis802_11AuthModeShared: -+ drv->capa.auth |= WPA_DRIVER_AUTH_SHARED; -+ break; -+ case Ndis802_11AuthModeWPA: -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA; -+ break; -+ case Ndis802_11AuthModeWPAPSK: -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; -+ break; -+ case Ndis802_11AuthModeWPA2: -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2; -+ break; -+ case Ndis802_11AuthModeWPA2PSK: -+ drv->capa.key_mgmt |= -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -+ break; -+ case Ndis802_11AuthModeWPANone: -+ drv->capa.key_mgmt |= -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE; -+ break; -+ default: -+ break; -+ } -+ switch (ae->EncryptStatusSupported) { -+ case Ndis802_11Encryption1Enabled: -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40; -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP104; -+ break; -+ case Ndis802_11Encryption2Enabled: -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; -+ break; -+ case Ndis802_11Encryption3Enabled: -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "NDIS: driver capabilities: key_mgmt 0x%x " -+ "enc 0x%x auth 0x%x", -+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth); -+} -+ -+ -+static int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ if (!drv->has_capability) -+ return -1; -+ os_memcpy(capa, &drv->capa, sizeof(*capa)); -+ return 0; -+} -+ -+ -+static const char * wpa_driver_ndis_get_ifname(void *priv) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ return drv->ifname; -+} -+ -+ -+static const u8 * wpa_driver_ndis_get_mac_addr(void *priv) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ return drv->own_addr; -+} -+ -+ -+#ifdef _WIN32_WCE -+ -+#define NDISUIO_MSG_SIZE (sizeof(NDISUIO_DEVICE_NOTIFICATION) + 512) -+ -+static void ndisuio_notification_receive(void *eloop_data, void *user_ctx) -+{ -+ struct wpa_driver_ndis_data *drv = eloop_data; -+ NDISUIO_DEVICE_NOTIFICATION *hdr; -+ u8 buf[NDISUIO_MSG_SIZE]; -+ DWORD len, flags; -+ -+ if (!ReadMsgQueue(drv->event_queue, buf, NDISUIO_MSG_SIZE, &len, 0, -+ &flags)) { -+ wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: " -+ "ReadMsgQueue failed: %d", (int) GetLastError()); -+ return; -+ } -+ -+ if (len < sizeof(NDISUIO_DEVICE_NOTIFICATION)) { -+ wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: " -+ "Too short message (len=%d)", (int) len); -+ return; -+ } -+ -+ hdr = (NDISUIO_DEVICE_NOTIFICATION *) buf; -+ wpa_printf(MSG_DEBUG, "NDIS: Notification received: len=%d type=0x%x", -+ (int) len, hdr->dwNotificationType); -+ -+ switch (hdr->dwNotificationType) { -+#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL -+ case NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL: -+ wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_ARRIVAL"); -+ wpa_driver_ndis_event_adapter_arrival(drv); -+ break; -+#endif -+#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL -+ case NDISUIO_NOTIFICATION_ADAPTER_REMOVAL: -+ wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_REMOVAL"); -+ wpa_driver_ndis_event_adapter_removal(drv); -+ break; -+#endif -+ case NDISUIO_NOTIFICATION_MEDIA_CONNECT: -+ wpa_printf(MSG_DEBUG, "NDIS: MEDIA_CONNECT"); -+ SetEvent(drv->connected_event); -+ wpa_driver_ndis_event_connect(drv); -+ break; -+ case NDISUIO_NOTIFICATION_MEDIA_DISCONNECT: -+ ResetEvent(drv->connected_event); -+ wpa_printf(MSG_DEBUG, "NDIS: MEDIA_DISCONNECT"); -+ wpa_driver_ndis_event_disconnect(drv); -+ break; -+ case NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION: -+ wpa_printf(MSG_DEBUG, "NDIS: MEDIA_SPECIFIC_NOTIFICATION"); -+#if _WIN32_WCE == 420 || _WIN32_WCE == 0x420 -+ wpa_driver_ndis_event_media_specific( -+ drv, hdr->pvStatusBuffer, hdr->uiStatusBufferSize); -+#else -+ wpa_driver_ndis_event_media_specific( -+ drv, ((const u8 *) hdr) + hdr->uiOffsetToStatusBuffer, -+ (size_t) hdr->uiStatusBufferSize); -+#endif -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "NDIS: Unknown notification type 0x%x", -+ hdr->dwNotificationType); -+ break; -+ } -+} -+ -+ -+static void ndisuio_notification_deinit(struct wpa_driver_ndis_data *drv) -+{ -+ NDISUIO_REQUEST_NOTIFICATION req; -+ -+ memset(&req, 0, sizeof(req)); -+ req.hMsgQueue = drv->event_queue; -+ req.dwNotificationTypes = 0; -+ -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION, -+ &req, sizeof(req), NULL, 0, NULL, NULL)) { -+ wpa_printf(MSG_INFO, "ndisuio_notification_deinit: " -+ "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d", -+ (int) GetLastError()); -+ } -+ -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_CANCEL_NOTIFICATION, -+ NULL, 0, NULL, 0, NULL, NULL)) { -+ wpa_printf(MSG_INFO, "ndisuio_notification_deinit: " -+ "IOCTL_NDISUIO_CANCEL_NOTIFICATION failed: %d", -+ (int) GetLastError()); -+ } -+ -+ if (drv->event_queue) { -+ eloop_unregister_event(drv->event_queue, -+ sizeof(drv->event_queue)); -+ CloseHandle(drv->event_queue); -+ drv->event_queue = NULL; -+ } -+ -+ if (drv->connected_event) { -+ CloseHandle(drv->connected_event); -+ drv->connected_event = NULL; -+ } -+} -+ -+ -+static int ndisuio_notification_init(struct wpa_driver_ndis_data *drv) -+{ -+ MSGQUEUEOPTIONS opt; -+ NDISUIO_REQUEST_NOTIFICATION req; -+ -+ drv->connected_event = -+ CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected")); -+ if (drv->connected_event == NULL) { -+ wpa_printf(MSG_INFO, "ndisuio_notification_init: " -+ "CreateEvent failed: %d", -+ (int) GetLastError()); -+ return -1; -+ } -+ -+ memset(&opt, 0, sizeof(opt)); -+ opt.dwSize = sizeof(opt); -+ opt.dwMaxMessages = 5; -+ opt.cbMaxMessage = NDISUIO_MSG_SIZE; -+ opt.bReadAccess = TRUE; -+ -+ drv->event_queue = CreateMsgQueue(NULL, &opt); -+ if (drv->event_queue == NULL) { -+ wpa_printf(MSG_INFO, "ndisuio_notification_init: " -+ "CreateMsgQueue failed: %d", -+ (int) GetLastError()); -+ ndisuio_notification_deinit(drv); -+ return -1; -+ } -+ -+ memset(&req, 0, sizeof(req)); -+ req.hMsgQueue = drv->event_queue; -+ req.dwNotificationTypes = -+#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL -+ NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL | -+#endif -+#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL -+ NDISUIO_NOTIFICATION_ADAPTER_REMOVAL | -+#endif -+ NDISUIO_NOTIFICATION_MEDIA_CONNECT | -+ NDISUIO_NOTIFICATION_MEDIA_DISCONNECT | -+ NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION; -+ -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION, -+ &req, sizeof(req), NULL, 0, NULL, NULL)) { -+ wpa_printf(MSG_INFO, "ndisuio_notification_init: " -+ "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d", -+ (int) GetLastError()); -+ ndisuio_notification_deinit(drv); -+ return -1; -+ } -+ -+ eloop_register_event(drv->event_queue, sizeof(drv->event_queue), -+ ndisuio_notification_receive, drv, NULL); -+ -+ return 0; -+} -+#endif /* _WIN32_WCE */ -+ -+ -+static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv) -+{ -+#ifdef CONFIG_USE_NDISUIO -+ NDISUIO_QUERY_BINDING *b; -+ size_t blen = sizeof(*b) + 1024; -+ int i, error, found = 0; -+ DWORD written; -+ char name[256], desc[256], *dpos; -+ WCHAR *pos; -+ size_t j, len, dlen; -+ -+ b = os_malloc(blen); -+ if (b == NULL) -+ return -1; -+ -+ for (i = 0; ; i++) { -+ os_memset(b, 0, blen); -+ b->BindingIndex = i; -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_BINDING, -+ b, sizeof(NDISUIO_QUERY_BINDING), b, blen, -+ &written, NULL)) { -+ error = (int) GetLastError(); -+ if (error == ERROR_NO_MORE_ITEMS) -+ break; -+ wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING " -+ "failed: %d", error); -+ break; -+ } -+ -+ pos = (WCHAR *) ((char *) b + b->DeviceNameOffset); -+ len = b->DeviceNameLength; -+ if (len >= sizeof(name)) -+ len = sizeof(name) - 1; -+ for (j = 0; j < len; j++) -+ name[j] = (char) pos[j]; -+ name[len] = '\0'; -+ -+ pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset); -+ len = b->DeviceDescrLength; -+ if (len >= sizeof(desc)) -+ len = sizeof(desc) - 1; -+ for (j = 0; j < len; j++) -+ desc[j] = (char) pos[j]; -+ desc[len] = '\0'; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc); -+ -+ if (os_strstr(name, drv->ifname)) { -+ wpa_printf(MSG_DEBUG, "NDIS: Interface name match"); -+ found = 1; -+ break; -+ } -+ -+ if (os_strncmp(desc, drv->ifname, os_strlen(drv->ifname)) == 0) -+ { -+ wpa_printf(MSG_DEBUG, "NDIS: Interface description " -+ "match"); -+ found = 1; -+ break; -+ } -+ } -+ -+ if (!found) { -+ wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'", -+ drv->ifname); -+ os_free(b); -+ return -1; -+ } -+ -+ os_strlcpy(drv->ifname, -+ os_strncmp(name, "\\DEVICE\\", 8) == 0 ? name + 8 : name, -+ sizeof(drv->ifname)); -+#ifdef _WIN32_WCE -+ drv->adapter_name = wpa_strdup_tchar(drv->ifname); -+ if (drv->adapter_name == NULL) { -+ wpa_printf(MSG_ERROR, "NDIS: Failed to allocate memory for " -+ "adapter name"); -+ os_free(b); -+ return -1; -+ } -+#endif /* _WIN32_WCE */ -+ -+ dpos = os_strstr(desc, " - "); -+ if (dpos) -+ dlen = dpos - desc; -+ else -+ dlen = os_strlen(desc); -+ drv->adapter_desc = os_malloc(dlen + 1); -+ if (drv->adapter_desc) { -+ os_memcpy(drv->adapter_desc, desc, dlen); -+ drv->adapter_desc[dlen] = '\0'; -+ } -+ -+ os_free(b); -+ -+ if (drv->adapter_desc == NULL) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'", -+ drv->adapter_desc); -+ -+ return 0; -+#else /* CONFIG_USE_NDISUIO */ -+ PTSTR _names; -+ char *names, *pos, *pos2; -+ ULONG len; -+ BOOLEAN res; -+#define MAX_ADAPTERS 32 -+ char *name[MAX_ADAPTERS]; -+ char *desc[MAX_ADAPTERS]; -+ int num_name, num_desc, i, found_name, found_desc; -+ size_t dlen; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s", -+ PacketGetVersion()); -+ -+ len = 8192; -+ _names = os_zalloc(len); -+ if (_names == NULL) -+ return -1; -+ -+ res = PacketGetAdapterNames(_names, &len); -+ if (!res && len > 8192) { -+ os_free(_names); -+ _names = os_zalloc(len); -+ if (_names == NULL) -+ return -1; -+ res = PacketGetAdapterNames(_names, &len); -+ } -+ -+ if (!res) { -+ wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list " -+ "(PacketGetAdapterNames)"); -+ os_free(_names); -+ return -1; -+ } -+ -+ names = (char *) _names; -+ if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') { -+ wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in " -+ "UNICODE"); -+ /* Convert to ASCII */ -+ pos2 = pos = names; -+ while (pos2 < names + len) { -+ if (pos2[0] == '\0' && pos2[1] == '\0' && -+ pos2[2] == '\0' && pos2[3] == '\0') { -+ pos2 += 4; -+ break; -+ } -+ *pos++ = pos2[0]; -+ pos2 += 2; -+ } -+ os_memcpy(pos + 2, names, pos - names); -+ pos += 2; -+ } else -+ pos = names; -+ -+ num_name = 0; -+ while (pos < names + len) { -+ name[num_name] = pos; -+ while (*pos && pos < names + len) -+ pos++; -+ if (pos + 1 >= names + len) { -+ os_free(names); -+ return -1; -+ } -+ pos++; -+ num_name++; -+ if (num_name >= MAX_ADAPTERS) { -+ wpa_printf(MSG_DEBUG, "NDIS: Too many adapters"); -+ os_free(names); -+ return -1; -+ } -+ if (*pos == '\0') { -+ wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found", -+ num_name); -+ pos++; -+ break; -+ } -+ } -+ -+ num_desc = 0; -+ while (pos < names + len) { -+ desc[num_desc] = pos; -+ while (*pos && pos < names + len) -+ pos++; -+ if (pos + 1 >= names + len) { -+ os_free(names); -+ return -1; -+ } -+ pos++; -+ num_desc++; -+ if (num_desc >= MAX_ADAPTERS) { -+ wpa_printf(MSG_DEBUG, "NDIS: Too many adapter " -+ "descriptions"); -+ os_free(names); -+ return -1; -+ } -+ if (*pos == '\0') { -+ wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions " -+ "found", num_name); -+ pos++; -+ break; -+ } -+ } -+ -+ /* -+ * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter -+ * descriptions. Fill in dummy descriptors to work around this. -+ */ -+ while (num_desc < num_name) -+ desc[num_desc++] = "dummy description"; -+ -+ if (num_name != num_desc) { -+ wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and " -+ "description counts (%d != %d)", -+ num_name, num_desc); -+ os_free(names); -+ return -1; -+ } -+ -+ found_name = found_desc = -1; -+ for (i = 0; i < num_name; i++) { -+ wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", -+ i, name[i], desc[i]); -+ if (found_name == -1 && os_strstr(name[i], drv->ifname)) -+ found_name = i; -+ if (found_desc == -1 && -+ os_strncmp(desc[i], drv->ifname, os_strlen(drv->ifname)) == -+ 0) -+ found_desc = i; -+ } -+ -+ if (found_name < 0 && found_desc >= 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Matched interface '%s' based on " -+ "description '%s'", -+ name[found_desc], desc[found_desc]); -+ found_name = found_desc; -+ os_strlcpy(drv->ifname, -+ os_strncmp(name[found_desc], "\\Device\\NPF_", 12) -+ == 0 ? name[found_desc] + 12 : name[found_desc], -+ sizeof(drv->ifname)); -+ } -+ -+ if (found_name < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'", -+ drv->ifname); -+ os_free(names); -+ return -1; -+ } -+ -+ i = found_name; -+ pos = os_strrchr(desc[i], '('); -+ if (pos) { -+ dlen = pos - desc[i]; -+ pos--; -+ if (pos > desc[i] && *pos == ' ') -+ dlen--; -+ } else { -+ dlen = os_strlen(desc[i]); -+ } -+ drv->adapter_desc = os_malloc(dlen + 1); -+ if (drv->adapter_desc) { -+ os_memcpy(drv->adapter_desc, desc[i], dlen); -+ drv->adapter_desc[dlen] = '\0'; -+ } -+ -+ os_free(names); -+ -+ if (drv->adapter_desc == NULL) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'", -+ drv->adapter_desc); -+ -+ return 0; -+#endif /* CONFIG_USE_NDISUIO */ -+} -+ -+ -+#if defined(CONFIG_NATIVE_WINDOWS) || defined(__CYGWIN__) -+#ifndef _WIN32_WCE -+/* -+ * These structures are undocumented for WinXP; only WinCE version is -+ * documented. These would be included wzcsapi.h if it were available. Some -+ * changes here have been needed to make the structures match with WinXP SP2. -+ * It is unclear whether these work with any other version. -+ */ -+ -+typedef struct { -+ LPWSTR wszGuid; -+} INTF_KEY_ENTRY, *PINTF_KEY_ENTRY; -+ -+typedef struct { -+ DWORD dwNumIntfs; -+ PINTF_KEY_ENTRY pIntfs; -+} INTFS_KEY_TABLE, *PINTFS_KEY_TABLE; -+ -+typedef struct { -+ DWORD dwDataLen; -+ LPBYTE pData; -+} RAW_DATA, *PRAW_DATA; -+ -+typedef struct { -+ LPWSTR wszGuid; -+ LPWSTR wszDescr; -+ ULONG ulMediaState; -+ ULONG ulMediaType; -+ ULONG ulPhysicalMediaType; -+ INT nInfraMode; -+ INT nAuthMode; -+ INT nWepStatus; -+#ifndef _WIN32_WCE -+ u8 pad[2]; /* why is this needed? */ -+#endif /* _WIN32_WCE */ -+ DWORD dwCtlFlags; -+ DWORD dwCapabilities; /* something added for WinXP SP2(?) */ -+ RAW_DATA rdSSID; -+ RAW_DATA rdBSSID; -+ RAW_DATA rdBSSIDList; -+ RAW_DATA rdStSSIDList; -+ RAW_DATA rdCtrlData; -+#ifdef UNDER_CE -+ BOOL bInitialized; -+#endif -+ DWORD nWPAMCastCipher; -+ /* add some extra buffer for later additions since this interface is -+ * far from stable */ -+ u8 later_additions[100]; -+} INTF_ENTRY, *PINTF_ENTRY; -+ -+#define INTF_ALL 0xffffffff -+#define INTF_ALL_FLAGS 0x0000ffff -+#define INTF_CTLFLAGS 0x00000010 -+#define INTFCTL_ENABLED 0x8000 -+#endif /* _WIN32_WCE */ -+ -+ -+#ifdef _WIN32_WCE -+static int wpa_driver_ndis_rebind_adapter(struct wpa_driver_ndis_data *drv) -+{ -+ HANDLE ndis; -+ TCHAR multi[100]; -+ int len; -+ -+ len = _tcslen(drv->adapter_name); -+ if (len > 80) -+ return -1; -+ -+ ndis = CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, -+ 0, NULL, OPEN_EXISTING, 0, NULL); -+ if (ndis == INVALID_HANDLE_VALUE) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to open file to NDIS " -+ "device: %d", (int) GetLastError()); -+ return -1; -+ } -+ -+ len++; -+ memcpy(multi, drv->adapter_name, len * sizeof(TCHAR)); -+ memcpy(&multi[len], TEXT("NDISUIO\0"), 9 * sizeof(TCHAR)); -+ len += 9; -+ -+ if (!DeviceIoControl(ndis, IOCTL_NDIS_REBIND_ADAPTER, -+ multi, len * sizeof(TCHAR), NULL, 0, NULL, NULL)) -+ { -+ wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDIS_REBIND_ADAPTER " -+ "failed: 0x%x", (int) GetLastError()); -+ wpa_hexdump_ascii(MSG_DEBUG, "NDIS: rebind multi_sz", -+ (u8 *) multi, len * sizeof(TCHAR)); -+ CloseHandle(ndis); -+ return -1; -+ } -+ -+ CloseHandle(ndis); -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Requested NDIS rebind of NDISUIO " -+ "protocol"); -+ -+ return 0; -+} -+#endif /* _WIN32_WCE */ -+ -+ -+static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv, -+ int enable) -+{ -+#ifdef _WIN32_WCE -+ HKEY hk, hk2; -+ LONG ret; -+ DWORD i, hnd, len; -+ TCHAR keyname[256], devname[256]; -+ -+#define WZC_DRIVER TEXT("Drivers\\BuiltIn\\ZeroConfig") -+ -+ if (enable) { -+ HANDLE h; -+ h = ActivateDeviceEx(WZC_DRIVER, NULL, 0, NULL); -+ if (h == INVALID_HANDLE_VALUE || h == 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to re-enable WZC " -+ "- ActivateDeviceEx failed: %d", -+ (int) GetLastError()); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "NDIS: WZC re-enabled"); -+ return wpa_driver_ndis_rebind_adapter(drv); -+ } -+ -+ /* -+ * Unfortunately, just disabling the WZC for an interface is not enough -+ * to free NDISUIO for us, so need to disable and unload WZC completely -+ * for now when using WinCE with NDISUIO. In addition, must request -+ * NDISUIO protocol to be rebound to the adapter in order to free the -+ * NDISUIO binding that WZC hold before us. -+ */ -+ -+ /* Enumerate HKLM\Drivers\Active\* to find a handle to WZC. */ -+ ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEVLOAD_ACTIVE_KEY, 0, 0, &hk); -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(DEVLOAD_ACTIVE_KEY) " -+ "failed: %d %d", (int) ret, (int) GetLastError()); -+ return -1; -+ } -+ -+ for (i = 0; ; i++) { -+ len = sizeof(keyname); -+ ret = RegEnumKeyEx(hk, i, keyname, &len, NULL, NULL, NULL, -+ NULL); -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "NDIS: Could not find active " -+ "WZC - assuming it is not running."); -+ RegCloseKey(hk); -+ return -1; -+ } -+ -+ ret = RegOpenKeyEx(hk, keyname, 0, 0, &hk2); -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(active dev) " -+ "failed: %d %d", -+ (int) ret, (int) GetLastError()); -+ continue; -+ } -+ -+ len = sizeof(devname); -+ ret = RegQueryValueEx(hk2, DEVLOAD_DEVKEY_VALNAME, NULL, NULL, -+ (LPBYTE) devname, &len); -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(" -+ "DEVKEY_VALNAME) failed: %d %d", -+ (int) ret, (int) GetLastError()); -+ RegCloseKey(hk2); -+ continue; -+ } -+ -+ if (_tcscmp(devname, WZC_DRIVER) == 0) -+ break; -+ -+ RegCloseKey(hk2); -+ } -+ -+ RegCloseKey(hk); -+ -+ /* Found WZC - get handle to it. */ -+ len = sizeof(hnd); -+ ret = RegQueryValueEx(hk2, DEVLOAD_HANDLE_VALNAME, NULL, NULL, -+ (PUCHAR) &hnd, &len); -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(HANDLE_VALNAME) " -+ "failed: %d %d", (int) ret, (int) GetLastError()); -+ RegCloseKey(hk2); -+ return -1; -+ } -+ -+ RegCloseKey(hk2); -+ -+ /* Deactivate WZC */ -+ if (!DeactivateDevice((HANDLE) hnd)) { -+ wpa_printf(MSG_DEBUG, "NDIS: DeactivateDevice failed: %d", -+ (int) GetLastError()); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily"); -+ drv->wzc_disabled = 1; -+ return wpa_driver_ndis_rebind_adapter(drv); -+ -+#else /* _WIN32_WCE */ -+ -+ HMODULE hm; -+ DWORD (WINAPI *wzc_enum_interf)(LPWSTR pSrvAddr, -+ PINTFS_KEY_TABLE pIntfs); -+ DWORD (WINAPI *wzc_query_interf)(LPWSTR pSrvAddr, DWORD dwInFlags, -+ PINTF_ENTRY pIntf, -+ LPDWORD pdwOutFlags); -+ DWORD (WINAPI *wzc_set_interf)(LPWSTR pSrvAddr, DWORD dwInFlags, -+ PINTF_ENTRY pIntf, LPDWORD pdwOutFlags); -+ int ret = -1, j; -+ DWORD res; -+ INTFS_KEY_TABLE guids; -+ INTF_ENTRY intf; -+ char guid[128]; -+ WCHAR *pos; -+ DWORD flags, i; -+ -+ hm = LoadLibrary(TEXT("wzcsapi.dll")); -+ if (hm == NULL) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to load wzcsapi.dll (%u) " -+ "- WZC probably not running", -+ (unsigned int) GetLastError()); -+ return -1; -+ } -+ -+#ifdef _WIN32_WCE -+ wzc_enum_interf = (void *) GetProcAddressA(hm, "WZCEnumInterfaces"); -+ wzc_query_interf = (void *) GetProcAddressA(hm, "WZCQueryInterface"); -+ wzc_set_interf = (void *) GetProcAddressA(hm, "WZCSetInterface"); -+#else /* _WIN32_WCE */ -+ wzc_enum_interf = (void *) GetProcAddress(hm, "WZCEnumInterfaces"); -+ wzc_query_interf = (void *) GetProcAddress(hm, "WZCQueryInterface"); -+ wzc_set_interf = (void *) GetProcAddress(hm, "WZCSetInterface"); -+#endif /* _WIN32_WCE */ -+ -+ if (wzc_enum_interf == NULL || wzc_query_interf == NULL || -+ wzc_set_interf == NULL) { -+ wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces, " -+ "WZCQueryInterface, or WZCSetInterface not found " -+ "in wzcsapi.dll"); -+ goto fail; -+ } -+ -+ os_memset(&guids, 0, sizeof(guids)); -+ res = wzc_enum_interf(NULL, &guids); -+ if (res != 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces failed: %d; " -+ "WZC service is apparently not running", -+ (int) res); -+ goto fail; -+ } -+ -+ wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces: %d interfaces", -+ (int) guids.dwNumIntfs); -+ -+ for (i = 0; i < guids.dwNumIntfs; i++) { -+ pos = guids.pIntfs[i].wszGuid; -+ for (j = 0; j < sizeof(guid); j++) { -+ guid[j] = (char) *pos; -+ if (*pos == 0) -+ break; -+ pos++; -+ } -+ guid[sizeof(guid) - 1] = '\0'; -+ wpa_printf(MSG_DEBUG, "NDIS: intfs %d GUID '%s'", -+ (int) i, guid); -+ if (os_strstr(drv->ifname, guid) == NULL) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Current interface found from " -+ "WZC"); -+ break; -+ } -+ -+ if (i >= guids.dwNumIntfs) { -+ wpa_printf(MSG_DEBUG, "NDIS: Current interface not found from " -+ "WZC"); -+ goto fail; -+ } -+ -+ os_memset(&intf, 0, sizeof(intf)); -+ intf.wszGuid = guids.pIntfs[i].wszGuid; -+ /* Set flags to verify that the structure has not changed. */ -+ intf.dwCtlFlags = -1; -+ flags = 0; -+ res = wzc_query_interf(NULL, INTFCTL_ENABLED, &intf, &flags); -+ if (res != 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Could not query flags for the " -+ "WZC interface: %d (0x%x)", -+ (int) res, (int) res); -+ wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u", -+ (unsigned int) GetLastError()); -+ goto fail; -+ } -+ -+ wpa_printf(MSG_DEBUG, "NDIS: WZC interface flags 0x%x dwCtlFlags 0x%x", -+ (int) flags, (int) intf.dwCtlFlags); -+ -+ if (intf.dwCtlFlags == -1) { -+ wpa_printf(MSG_DEBUG, "NDIS: Looks like wzcsapi has changed " -+ "again - could not disable WZC"); -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: intf", -+ (u8 *) &intf, sizeof(intf)); -+ goto fail; -+ } -+ -+ if (enable) { -+ if (!(intf.dwCtlFlags & INTFCTL_ENABLED)) { -+ wpa_printf(MSG_DEBUG, "NDIS: Enabling WZC for this " -+ "interface"); -+ intf.dwCtlFlags |= INTFCTL_ENABLED; -+ res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf, -+ &flags); -+ if (res != 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to enable " -+ "WZC: %d (0x%x)", -+ (int) res, (int) res); -+ wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u", -+ (unsigned int) GetLastError()); -+ goto fail; -+ } -+ wpa_printf(MSG_DEBUG, "NDIS: Re-enabled WZC for this " -+ "interface"); -+ drv->wzc_disabled = 0; -+ } -+ } else { -+ if (intf.dwCtlFlags & INTFCTL_ENABLED) { -+ wpa_printf(MSG_DEBUG, "NDIS: Disabling WZC for this " -+ "interface"); -+ intf.dwCtlFlags &= ~INTFCTL_ENABLED; -+ res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf, -+ &flags); -+ if (res != 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to " -+ "disable WZC: %d (0x%x)", -+ (int) res, (int) res); -+ wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u", -+ (unsigned int) GetLastError()); -+ goto fail; -+ } -+ wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily " -+ "for this interface"); -+ drv->wzc_disabled = 1; -+ } else { -+ wpa_printf(MSG_DEBUG, "NDIS: WZC was not enabled for " -+ "this interface"); -+ } -+ } -+ -+ ret = 0; -+ -+fail: -+ FreeLibrary(hm); -+ -+ return ret; -+#endif /* _WIN32_WCE */ -+} -+ -+#else /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */ -+ -+static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv, -+ int enable) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */ -+ -+ -+#ifdef CONFIG_USE_NDISUIO -+/* -+ * l2_packet_ndis.c is sharing the same handle to NDISUIO, so we must be able -+ * to export this handle. This is somewhat ugly, but there is no better -+ * mechanism available to pass data from driver interface to l2_packet wrapper. -+ */ -+static HANDLE driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE; -+ -+HANDLE driver_ndis_get_ndisuio_handle(void) -+{ -+ return driver_ndis_ndisuio_handle; -+} -+#endif /* CONFIG_USE_NDISUIO */ -+ -+ -+static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv) -+{ -+#ifdef CONFIG_USE_NDISUIO -+#ifndef _WIN32_WCE -+#define NDISUIO_DEVICE_NAME TEXT("\\\\.\\\\Ndisuio") -+ DWORD written; -+#endif /* _WIN32_WCE */ -+ drv->ndisuio = CreateFile(NDISUIO_DEVICE_NAME, -+ GENERIC_READ | GENERIC_WRITE, 0, NULL, -+ OPEN_EXISTING, -+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, -+ INVALID_HANDLE_VALUE); -+ if (drv->ndisuio == INVALID_HANDLE_VALUE) { -+ wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to " -+ "NDISUIO: %d", (int) GetLastError()); -+ return -1; -+ } -+ driver_ndis_ndisuio_handle = drv->ndisuio; -+ -+#ifndef _WIN32_WCE -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, -+ NULL, 0, &written, NULL)) { -+ wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: " -+ "%d", (int) GetLastError()); -+ CloseHandle(drv->ndisuio); -+ drv->ndisuio = INVALID_HANDLE_VALUE; -+ return -1; -+ } -+#endif /* _WIN32_WCE */ -+ -+ return 0; -+#else /* CONFIG_USE_NDISUIO */ -+ return 0; -+#endif /* CONFIG_USE_NDISUIO */ -+} -+ -+ -+static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv) -+{ -+#ifdef CONFIG_USE_NDISUIO -+ DWORD written; -+#define MAX_NDIS_DEVICE_NAME_LEN 256 -+ WCHAR ifname[MAX_NDIS_DEVICE_NAME_LEN]; -+ size_t len, i, pos; -+ const char *prefix = "\\DEVICE\\"; -+ -+#ifdef _WIN32_WCE -+ pos = 0; -+#else /* _WIN32_WCE */ -+ pos = 8; -+#endif /* _WIN32_WCE */ -+ len = pos + os_strlen(drv->ifname); -+ if (len >= MAX_NDIS_DEVICE_NAME_LEN) -+ return -1; -+ for (i = 0; i < pos; i++) -+ ifname[i] = (WCHAR) prefix[i]; -+ for (i = pos; i < len; i++) -+ ifname[i] = (WCHAR) drv->ifname[i - pos]; -+ ifname[i] = L'\0'; -+ -+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_OPEN_DEVICE, -+ ifname, len * sizeof(WCHAR), NULL, 0, &written, -+ NULL)) { -+ wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_OPEN_DEVICE " -+ "failed: %d", (int) GetLastError()); -+ wpa_hexdump_ascii(MSG_DEBUG, "NDIS: ifname", -+ (const u8 *) ifname, len * sizeof(WCHAR)); -+ CloseHandle(drv->ndisuio); -+ drv->ndisuio = INVALID_HANDLE_VALUE; -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Opened NDISUIO device successfully"); -+ -+ return 0; -+#else /* CONFIG_USE_NDISUIO */ -+ char ifname[128]; -+ os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", drv->ifname); -+ drv->adapter = PacketOpenAdapter(ifname); -+ if (drv->adapter == NULL) { -+ wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for " -+ "'%s'", ifname); -+ return -1; -+ } -+ return 0; -+#endif /* CONFIG_USE_NDISUIO */ -+} -+ -+ -+static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv) -+{ -+#ifdef CONFIG_USE_NDISUIO -+ driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE; -+ if (drv->ndisuio != INVALID_HANDLE_VALUE) -+ CloseHandle(drv->ndisuio); -+#else /* CONFIG_USE_NDISUIO */ -+ if (drv->adapter) -+ PacketCloseAdapter(drv->adapter); -+#endif /* CONFIG_USE_NDISUIO */ -+} -+ -+ -+static int ndis_add_multicast(struct wpa_driver_ndis_data *drv) -+{ -+ if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST, -+ (const char *) pae_group_addr, ETH_ALEN) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address " -+ "to the multicast list"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void * wpa_driver_ndis_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_ndis_data *drv; -+ u32 mode; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->ctx = ctx; -+ /* -+ * Compatibility code to strip possible prefix from the GUID. Previous -+ * versions include \Device\NPF_ prefix for all names, but the internal -+ * interface name is now only the GUI. Both Packet32 and NDISUIO -+ * prefixes are supported. -+ */ -+ if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0) -+ ifname += 12; -+ else if (os_strncmp(ifname, "\\DEVICE\\", 8) == 0) -+ ifname += 8; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ -+ if (wpa_driver_ndis_adapter_init(drv) < 0) { -+ os_free(drv); -+ return NULL; -+ } -+ -+ if (wpa_driver_ndis_get_names(drv) < 0) { -+ wpa_driver_ndis_adapter_close(drv); -+ os_free(drv); -+ return NULL; -+ } -+ -+ wpa_driver_ndis_set_wzc(drv, 0); -+ -+ if (wpa_driver_ndis_adapter_open(drv) < 0) { -+ wpa_driver_ndis_adapter_close(drv); -+ os_free(drv); -+ return NULL; -+ } -+ -+ if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS, -+ (char *) drv->own_addr, ETH_ALEN) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS " -+ "failed"); -+ wpa_driver_ndis_adapter_close(drv); -+ os_free(drv); -+ return NULL; -+ } -+ wpa_driver_ndis_get_capability(drv); -+ -+ /* Make sure that the driver does not have any obsolete PMKID entries. -+ */ -+ wpa_driver_ndis_flush_pmkid(drv); -+ -+ /* -+ * Disconnect to make sure that driver re-associates if it was -+ * connected. -+ */ -+ wpa_driver_ndis_disconnect(drv); -+ -+ eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL); -+ -+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED -+ drv->events = ndis_events_init(&drv->events_pipe, &drv->event_avail, -+ drv->ifname, drv->adapter_desc); -+ if (drv->events == NULL) { -+ wpa_driver_ndis_deinit(drv); -+ return NULL; -+ } -+ eloop_register_event(drv->event_avail, sizeof(drv->event_avail), -+ wpa_driver_ndis_event_pipe_cb, drv, NULL); -+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ -+ -+#ifdef _WIN32_WCE -+ if (ndisuio_notification_init(drv) < 0) { -+ wpa_driver_ndis_deinit(drv); -+ return NULL; -+ } -+#endif /* _WIN32_WCE */ -+ -+ /* Set mode here in case card was configured for ad-hoc mode -+ * previously. */ -+ mode = Ndis802_11Infrastructure; -+ if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE, -+ (char *) &mode, sizeof(mode)) < 0) { -+ char buf[8]; -+ int res; -+ wpa_printf(MSG_DEBUG, "NDIS: Failed to set " -+ "OID_802_11_INFRASTRUCTURE_MODE (%d)", -+ (int) mode); -+ /* Try to continue anyway */ -+ -+ res = ndis_get_oid(drv, OID_DOT11_CURRENT_OPERATION_MODE, buf, -+ sizeof(buf)); -+ if (res > 0) { -+ wpa_printf(MSG_INFO, "NDIS: The driver seems to use " -+ "Native 802.11 OIDs. These are not yet " -+ "fully supported."); -+ drv->native80211 = 1; -+ } else if (!drv->has_capability || drv->capa.enc == 0) { -+ /* -+ * Note: This will also happen with NDIS 6 drivers with -+ * Vista. -+ */ -+ wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide " -+ "any wireless capabilities - assume it is " -+ "a wired interface"); -+ drv->wired = 1; -+ drv->capa.flags |= WPA_DRIVER_FLAGS_WIRED; -+ drv->has_capability = 1; -+ ndis_add_multicast(drv); -+ } -+ } -+ -+ return drv; -+} -+ -+ -+static void wpa_driver_ndis_deinit(void *priv) -+{ -+ struct wpa_driver_ndis_data *drv = priv; -+ -+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED -+ if (drv->events) { -+ eloop_unregister_event(drv->event_avail, -+ sizeof(drv->event_avail)); -+ ndis_events_deinit(drv->events); -+ } -+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ -+ -+#ifdef _WIN32_WCE -+ ndisuio_notification_deinit(drv); -+#endif /* _WIN32_WCE */ -+ -+ eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx); -+ eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL); -+ wpa_driver_ndis_flush_pmkid(drv); -+ wpa_driver_ndis_disconnect(drv); -+ if (wpa_driver_ndis_radio_off(drv) < 0) { -+ wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn " -+ "radio off"); -+ } -+ -+ wpa_driver_ndis_adapter_close(drv); -+ -+ if (drv->wzc_disabled) -+ wpa_driver_ndis_set_wzc(drv, 1); -+ -+#ifdef _WIN32_WCE -+ os_free(drv->adapter_name); -+#endif /* _WIN32_WCE */ -+ os_free(drv->adapter_desc); -+ os_free(drv); -+} -+ -+ -+static struct wpa_interface_info * -+wpa_driver_ndis_get_interfaces(void *global_priv) -+{ -+ struct wpa_interface_info *iface = NULL, *niface; -+ -+#ifdef CONFIG_USE_NDISUIO -+ NDISUIO_QUERY_BINDING *b; -+ size_t blen = sizeof(*b) + 1024; -+ int i, error; -+ DWORD written; -+ char name[256], desc[256]; -+ WCHAR *pos; -+ size_t j, len; -+ HANDLE ndisuio; -+ -+ ndisuio = CreateFile(NDISUIO_DEVICE_NAME, -+ GENERIC_READ | GENERIC_WRITE, 0, NULL, -+ OPEN_EXISTING, -+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, -+ INVALID_HANDLE_VALUE); -+ if (ndisuio == INVALID_HANDLE_VALUE) { -+ wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to " -+ "NDISUIO: %d", (int) GetLastError()); -+ return NULL; -+ } -+ -+#ifndef _WIN32_WCE -+ if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, -+ NULL, 0, &written, NULL)) { -+ wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: " -+ "%d", (int) GetLastError()); -+ CloseHandle(ndisuio); -+ return NULL; -+ } -+#endif /* _WIN32_WCE */ -+ -+ b = os_malloc(blen); -+ if (b == NULL) { -+ CloseHandle(ndisuio); -+ return NULL; -+ } -+ -+ for (i = 0; ; i++) { -+ os_memset(b, 0, blen); -+ b->BindingIndex = i; -+ if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING, -+ b, sizeof(NDISUIO_QUERY_BINDING), b, blen, -+ &written, NULL)) { -+ error = (int) GetLastError(); -+ if (error == ERROR_NO_MORE_ITEMS) -+ break; -+ wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING " -+ "failed: %d", error); -+ break; -+ } -+ -+ pos = (WCHAR *) ((char *) b + b->DeviceNameOffset); -+ len = b->DeviceNameLength; -+ if (len >= sizeof(name)) -+ len = sizeof(name) - 1; -+ for (j = 0; j < len; j++) -+ name[j] = (char) pos[j]; -+ name[len] = '\0'; -+ -+ pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset); -+ len = b->DeviceDescrLength; -+ if (len >= sizeof(desc)) -+ len = sizeof(desc) - 1; -+ for (j = 0; j < len; j++) -+ desc[j] = (char) pos[j]; -+ desc[len] = '\0'; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc); -+ -+ niface = os_zalloc(sizeof(*niface)); -+ if (niface == NULL) -+ break; -+ niface->drv_name = "ndis"; -+ if (os_strncmp(name, "\\DEVICE\\", 8) == 0) -+ niface->ifname = os_strdup(name + 8); -+ else -+ niface->ifname = os_strdup(name); -+ if (niface->ifname == NULL) { -+ os_free(niface); -+ break; -+ } -+ niface->desc = os_strdup(desc); -+ niface->next = iface; -+ iface = niface; -+ } -+ -+ os_free(b); -+ CloseHandle(ndisuio); -+#else /* CONFIG_USE_NDISUIO */ -+ PTSTR _names; -+ char *names, *pos, *pos2; -+ ULONG len; -+ BOOLEAN res; -+ char *name[MAX_ADAPTERS]; -+ char *desc[MAX_ADAPTERS]; -+ int num_name, num_desc, i; -+ -+ wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s", -+ PacketGetVersion()); -+ -+ len = 8192; -+ _names = os_zalloc(len); -+ if (_names == NULL) -+ return NULL; -+ -+ res = PacketGetAdapterNames(_names, &len); -+ if (!res && len > 8192) { -+ os_free(_names); -+ _names = os_zalloc(len); -+ if (_names == NULL) -+ return NULL; -+ res = PacketGetAdapterNames(_names, &len); -+ } -+ -+ if (!res) { -+ wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list " -+ "(PacketGetAdapterNames)"); -+ os_free(_names); -+ return NULL; -+ } -+ -+ names = (char *) _names; -+ if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') { -+ wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in " -+ "UNICODE"); -+ /* Convert to ASCII */ -+ pos2 = pos = names; -+ while (pos2 < names + len) { -+ if (pos2[0] == '\0' && pos2[1] == '\0' && -+ pos2[2] == '\0' && pos2[3] == '\0') { -+ pos2 += 4; -+ break; -+ } -+ *pos++ = pos2[0]; -+ pos2 += 2; -+ } -+ os_memcpy(pos + 2, names, pos - names); -+ pos += 2; -+ } else -+ pos = names; -+ -+ num_name = 0; -+ while (pos < names + len) { -+ name[num_name] = pos; -+ while (*pos && pos < names + len) -+ pos++; -+ if (pos + 1 >= names + len) { -+ os_free(names); -+ return NULL; -+ } -+ pos++; -+ num_name++; -+ if (num_name >= MAX_ADAPTERS) { -+ wpa_printf(MSG_DEBUG, "NDIS: Too many adapters"); -+ os_free(names); -+ return NULL; -+ } -+ if (*pos == '\0') { -+ wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found", -+ num_name); -+ pos++; -+ break; -+ } -+ } -+ -+ num_desc = 0; -+ while (pos < names + len) { -+ desc[num_desc] = pos; -+ while (*pos && pos < names + len) -+ pos++; -+ if (pos + 1 >= names + len) { -+ os_free(names); -+ return NULL; -+ } -+ pos++; -+ num_desc++; -+ if (num_desc >= MAX_ADAPTERS) { -+ wpa_printf(MSG_DEBUG, "NDIS: Too many adapter " -+ "descriptions"); -+ os_free(names); -+ return NULL; -+ } -+ if (*pos == '\0') { -+ wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions " -+ "found", num_name); -+ pos++; -+ break; -+ } -+ } -+ -+ /* -+ * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter -+ * descriptions. Fill in dummy descriptors to work around this. -+ */ -+ while (num_desc < num_name) -+ desc[num_desc++] = "dummy description"; -+ -+ if (num_name != num_desc) { -+ wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and " -+ "description counts (%d != %d)", -+ num_name, num_desc); -+ os_free(names); -+ return NULL; -+ } -+ -+ for (i = 0; i < num_name; i++) { -+ niface = os_zalloc(sizeof(*niface)); -+ if (niface == NULL) -+ break; -+ niface->drv_name = "ndis"; -+ if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0) -+ niface->ifname = os_strdup(name[i] + 12); -+ else -+ niface->ifname = os_strdup(name[i]); -+ if (niface->ifname == NULL) { -+ os_free(niface); -+ break; -+ } -+ niface->desc = os_strdup(desc[i]); -+ niface->next = iface; -+ iface = niface; -+ } -+ -+#endif /* CONFIG_USE_NDISUIO */ -+ -+ return iface; -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_ndis_ops = { -+ "ndis", -+ "Windows NDIS driver", -+ wpa_driver_ndis_get_bssid, -+ wpa_driver_ndis_get_ssid, -+ wpa_driver_ndis_set_key, -+ wpa_driver_ndis_init, -+ wpa_driver_ndis_deinit, -+ NULL /* set_param */, -+ NULL /* set_countermeasures */, -+ wpa_driver_ndis_deauthenticate, -+ wpa_driver_ndis_disassociate, -+ wpa_driver_ndis_associate, -+ wpa_driver_ndis_add_pmkid, -+ wpa_driver_ndis_remove_pmkid, -+ wpa_driver_ndis_flush_pmkid, -+ wpa_driver_ndis_get_capa, -+ wpa_driver_ndis_poll, -+ wpa_driver_ndis_get_ifname, -+ wpa_driver_ndis_get_mac_addr, -+ NULL /* send_eapol */, -+ NULL /* set_operstate */, -+ NULL /* mlme_setprotection */, -+ NULL /* get_hw_feature_data */, -+ NULL /* set_channel */, -+ NULL /* set_ssid */, -+ NULL /* set_bssid */, -+ NULL /* send_mlme */, -+ NULL /* mlme_add_sta */, -+ NULL /* mlme_remove_sta */, -+ NULL /* update_ft_ies */, -+ NULL /* send_ft_action */, -+ wpa_driver_ndis_get_scan_results, -+ NULL /* set_country */, -+ NULL /* global_init */, -+ NULL /* global_deinit */, -+ NULL /* init2 */, -+ wpa_driver_ndis_get_interfaces, -+ wpa_driver_ndis_scan, -+ NULL /* authenticate */, -+ NULL /* set_beacon */, -+ NULL /* hapd_init */, -+ NULL /* hapd_deinit */, -+ NULL /* set_ieee8021x */, -+ NULL /* set_privacy */, -+ NULL /* get_seqnum */, -+ NULL /* flush */, -+ NULL /* set_generic_elem */, -+ NULL /* read_sta_data */, -+ NULL /* hapd_send_eapol */, -+ NULL /* sta_deauth */, -+ NULL /* sta_disassoc */, -+ NULL /* sta_remove */, -+ NULL /* hapd_get_ssid */, -+ NULL /* hapd_set_ssid */, -+ NULL /* hapd_set_countermeasures */, -+ NULL /* sta_add */, -+ NULL /* get_inact_sec */, -+ NULL /* sta_clear_stats */, -+ NULL /* set_freq */, -+ NULL /* set_rts */, -+ NULL /* set_frag */, -+ NULL /* sta_set_flags */, -+ NULL /* set_rate_sets */, -+ NULL /* set_cts_protect */, -+ NULL /* set_preamble */, -+ NULL /* set_short_slot_time */, -+ NULL /* set_tx_queue_params */, -+ NULL /* valid_bss_mask */, -+ NULL /* if_add */, -+ NULL /* if_remove */, -+ NULL /* set_sta_vlan */, -+ NULL /* commit */, -+ NULL /* send_ether */, -+ NULL /* set_radius_acl_auth */, -+ NULL /* set_radius_acl_expire */, -+ NULL /* set_ht_params */, -+ NULL /* set_ap_wps_ie */, -+ NULL /* set_supp_port */, -+ NULL /* set_wds_sta */, -+ NULL /* send_action */, -+ NULL /* send_action_cancel_wait */, -+ NULL /* remain_on_channel */, -+ NULL /* cancel_remain_on_channel */, -+ NULL /* probe_req_report */, -+ NULL /* disable_11b_rates */, -+ NULL /* deinit_ap */, -+ NULL /* suspend */, -+ NULL /* resume */, -+ NULL /* signal_monitor */, -+ NULL /* send_frame */, -+ NULL /* shared_freq */, -+ NULL /* get_noa */, -+ NULL /* set_noa */, -+ NULL /* set_p2p_powersave */, -+ NULL /* ampdu */, -+ NULL /* set_intra_bss */, -+ NULL /* get_radio_name */, -+ NULL /* p2p_find */, -+ NULL /* p2p_stop_find */, -+ NULL /* p2p_listen */, -+ NULL /* p2p_connect */, -+ NULL /* wps_success_cb */, -+ NULL /* p2p_group_formation_failed */, -+ NULL /* p2p_set_params */, -+ NULL /* p2p_prov_disc_req */, -+ NULL /* p2p_sd_request */, -+ NULL /* p2p_sd_cancel_request */, -+ NULL /* p2p_sd_response */, -+ NULL /* p2p_service_update */, -+ NULL /* p2p_reject */, -+ NULL /* p2p_invite */, -+ NULL /* send_tdls_mgmt */, -+ NULL /* tdls_oper */, -+ NULL /* signal_poll */ -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.h -new file mode 100644 -index 0000000000000..f263f0e435858 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis.h -@@ -0,0 +1,65 @@ -+/* -+ * WPA Supplicant - Windows/NDIS driver interface -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef DRIVER_NDIS_H -+#define DRIVER_NDIS_H -+ -+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED -+struct ndis_events_data; -+struct ndis_events_data * ndis_events_init(HANDLE *read_pipe, HANDLE *event, -+ const char *ifname, -+ const char *desc); -+void ndis_events_deinit(struct ndis_events_data *events); -+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ -+ -+struct ndis_pmkid_entry { -+ struct ndis_pmkid_entry *next; -+ u8 bssid[ETH_ALEN]; -+ u8 pmkid[16]; -+}; -+ -+struct wpa_driver_ndis_data { -+ void *ctx; -+ char ifname[100]; /* GUID: {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D} */ -+#ifdef _WIN32_WCE -+ TCHAR *adapter_name; -+ HANDLE event_queue; /* NDISUIO notifier MsgQueue */ -+ HANDLE connected_event; /* WpaSupplicantConnected event */ -+#endif /* _WIN32_WCE */ -+ u8 own_addr[ETH_ALEN]; -+#ifdef CONFIG_USE_NDISUIO -+ HANDLE ndisuio; -+#else /* CONFIG_USE_NDISUIO */ -+ LPADAPTER adapter; -+#endif /* CONFIG_USE_NDISUIO */ -+ u8 bssid[ETH_ALEN]; -+ -+ int has_capability; -+ int no_of_pmkid; -+ int radio_enabled; -+ struct wpa_driver_capa capa; -+ struct ndis_pmkid_entry *pmkid; -+ char *adapter_desc; -+ int wired; -+ int native80211; -+ int mode; -+ int wzc_disabled; -+ int oid_bssid_set; -+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED -+ HANDLE events_pipe, event_avail; -+ struct ndis_events_data *events; -+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */ -+}; -+ -+#endif /* DRIVER_NDIS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis_.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis_.c -new file mode 100644 -index 0000000000000..4bee9aa543eb5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ndis_.c -@@ -0,0 +1,105 @@ -+/* -+ * WPA Supplicant - Windows/NDIS driver interface - event processing -+ * Copyright (c) 2004-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "driver.h" -+#include "eloop.h" -+ -+/* Keep this event processing in a separate file and without WinPcap headers to -+ * avoid conflicts with some of the header files. */ -+struct _ADAPTER; -+typedef struct _ADAPTER * LPADAPTER; -+#include "driver_ndis.h" -+ -+ -+void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv); -+void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv); -+void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv, -+ const u8 *data, size_t data_len); -+void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv); -+void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv); -+ -+ -+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, -+ EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL, -+ EVENT_ADAPTER_REMOVAL }; -+ -+/* Event data: -+ * enum event_types (as int, i.e., 4 octets) -+ * data length (2 octets (big endian), optional) -+ * data (variable len, optional) -+ */ -+ -+ -+static void wpa_driver_ndis_event_process(struct wpa_driver_ndis_data *drv, -+ u8 *buf, size_t len) -+{ -+ u8 *pos, *data = NULL; -+ enum event_types type; -+ size_t data_len = 0; -+ -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: received event data", buf, len); -+ if (len < sizeof(int)) -+ return; -+ type = *((int *) buf); -+ pos = buf + sizeof(int); -+ wpa_printf(MSG_DEBUG, "NDIS: event - type %d", type); -+ -+ if (buf + len - pos > 2) { -+ data_len = (int) *pos++ << 8; -+ data_len += *pos++; -+ if (data_len > (size_t) (buf + len - pos)) { -+ wpa_printf(MSG_DEBUG, "NDIS: event data overflow"); -+ return; -+ } -+ data = pos; -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: event data", data, data_len); -+ } -+ -+ switch (type) { -+ case EVENT_CONNECT: -+ wpa_driver_ndis_event_connect(drv); -+ break; -+ case EVENT_DISCONNECT: -+ wpa_driver_ndis_event_disconnect(drv); -+ break; -+ case EVENT_MEDIA_SPECIFIC: -+ wpa_driver_ndis_event_media_specific(drv, data, data_len); -+ break; -+ case EVENT_ADAPTER_ARRIVAL: -+ wpa_driver_ndis_event_adapter_arrival(drv); -+ break; -+ case EVENT_ADAPTER_REMOVAL: -+ wpa_driver_ndis_event_adapter_removal(drv); -+ break; -+ } -+} -+ -+ -+void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data) -+{ -+ struct wpa_driver_ndis_data *drv = eloop_data; -+ u8 buf[512]; -+ DWORD len; -+ -+ ResetEvent(drv->event_avail); -+ if (ReadFile(drv->events_pipe, buf, sizeof(buf), &len, NULL)) -+ wpa_driver_ndis_event_process(drv, buf, len); -+ else { -+ wpa_printf(MSG_DEBUG, "%s: ReadFile() failed: %d", __func__, -+ (int) GetLastError()); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_nl80211.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_nl80211.c -new file mode 100644 -index 0000000000000..90b3f209b1ccb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_nl80211.c -@@ -0,0 +1,6550 @@ -+/* -+ * Driver interaction with Linux nl80211/cfg80211 -+ * Copyright (c) 2002-2010, Jouni Malinen -+ * Copyright (c) 2003-2004, Instant802 Networks, Inc. -+ * Copyright (c) 2005-2006, Devicescape Software, Inc. -+ * Copyright (c) 2007, Johannes Berg -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "nl80211_copy.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "utils/list.h" -+#include "common/ieee802_11_defs.h" -+#include "netlink.h" -+#include "linux_ioctl.h" -+#include "radiotap.h" -+#include "radiotap_iter.h" -+#include "rfkill.h" -+#include "driver.h" -+ -+#ifdef CONFIG_LIBNL20 -+/* libnl 2.0 compatibility code */ -+#define nl_handle nl_sock -+#define nl80211_handle_alloc nl_socket_alloc_cb -+#define nl80211_handle_destroy nl_socket_free -+#else -+/* -+ * libnl 1.1 has a bug, it tries to allocate socket numbers densely -+ * but when you free a socket again it will mess up its bitmap and -+ * and use the wrong number the next time it needs a socket ID. -+ * Therefore, we wrap the handle alloc/destroy and add our own pid -+ * accounting. -+ */ -+static uint32_t port_bitmap[32] = { 0 }; -+ -+static struct nl_handle *nl80211_handle_alloc(void *cb) -+{ -+ struct nl_handle *handle; -+ uint32_t pid = getpid() & 0x3FFFFF; -+ int i; -+ -+ handle = nl_handle_alloc_cb(cb); -+ -+ for (i = 0; i < 1024; i++) { -+ if (port_bitmap[i / 32] & (1 << (i % 32))) -+ continue; -+ port_bitmap[i / 32] |= 1 << (i % 32); -+ pid += i << 22; -+ break; -+ } -+ -+ nl_socket_set_local_port(handle, pid); -+ -+ return handle; -+} -+ -+static void nl80211_handle_destroy(struct nl_handle *handle) -+{ -+ uint32_t port = nl_socket_get_local_port(handle); -+ -+ port >>= 22; -+ port_bitmap[port / 32] &= ~(1 << (port % 32)); -+ -+ nl_handle_destroy(handle); -+} -+#endif /* CONFIG_LIBNL20 */ -+ -+ -+#ifndef IFF_LOWER_UP -+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ -+#endif -+#ifndef IFF_DORMANT -+#define IFF_DORMANT 0x20000 /* driver signals dormant */ -+#endif -+ -+#ifndef IF_OPER_DORMANT -+#define IF_OPER_DORMANT 5 -+#endif -+#ifndef IF_OPER_UP -+#define IF_OPER_UP 6 -+#endif -+ -+struct nl80211_global { -+ struct dl_list interfaces; -+}; -+ -+struct i802_bss { -+ struct wpa_driver_nl80211_data *drv; -+ struct i802_bss *next; -+ int ifindex; -+ char ifname[IFNAMSIZ + 1]; -+ char brname[IFNAMSIZ]; -+ unsigned int beacon_set:1; -+ unsigned int added_if_into_bridge:1; -+ unsigned int added_bridge:1; -+}; -+ -+struct wpa_driver_nl80211_data { -+ struct nl80211_global *global; -+ struct dl_list list; -+ u8 addr[ETH_ALEN]; -+ char phyname[32]; -+ void *ctx; -+ struct netlink_data *netlink; -+ int ioctl_sock; /* socket for ioctl() use */ -+ int ifindex; -+ int if_removed; -+ int if_disabled; -+ struct rfkill_data *rfkill; -+ struct wpa_driver_capa capa; -+ int has_capability; -+ -+ int operstate; -+ -+ int scan_complete_events; -+ -+ struct nl_handle *nl_handle; -+ struct nl_handle *nl_handle_event; -+ struct nl_handle *nl_handle_preq; -+ struct nl_cache *nl_cache; -+ struct nl_cache *nl_cache_event; -+ struct nl_cache *nl_cache_preq; -+ struct nl_cb *nl_cb; -+ struct genl_family *nl80211; -+ -+ u8 auth_bssid[ETH_ALEN]; -+ u8 bssid[ETH_ALEN]; -+ int associated; -+ u8 ssid[32]; -+ size_t ssid_len; -+ int nlmode; -+ int ap_scan_as_station; -+ unsigned int assoc_freq; -+ -+ int monitor_sock; -+ int monitor_ifidx; -+ int disable_11b_rates; -+ -+ unsigned int pending_remain_on_chan:1; -+ -+ u64 remain_on_chan_cookie; -+ u64 send_action_cookie; -+ -+ unsigned int last_mgmt_freq; -+ -+ struct wpa_driver_scan_filter *filter_ssids; -+ size_t num_filter_ssids; -+ -+ struct i802_bss first_bss; -+ -+#ifdef HOSTAPD -+ int eapol_sock; /* socket for EAPOL frames */ -+ -+ int default_if_indices[16]; -+ int *if_indices; -+ int num_if_indices; -+ -+ int last_freq; -+ int last_freq_ht; -+#endif /* HOSTAPD */ -+}; -+ -+ -+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, -+ void *timeout_ctx); -+static int wpa_driver_nl80211_set_mode(void *priv, int mode); -+static int -+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv); -+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, -+ const u8 *addr, int cmd, u16 reason_code, -+ int local_state_change); -+static void nl80211_remove_monitor_interface( -+ struct wpa_driver_nl80211_data *drv); -+static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, -+ unsigned int freq, unsigned int wait, -+ const u8 *buf, size_t buf_len, u64 *cookie); -+static int wpa_driver_nl80211_probe_req_report(void *priv, int report); -+ -+#ifdef HOSTAPD -+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); -+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); -+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx); -+static int wpa_driver_nl80211_if_remove(void *priv, -+ enum wpa_driver_if_type type, -+ const char *ifname); -+#else /* HOSTAPD */ -+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) -+{ -+ return 0; -+} -+#endif /* HOSTAPD */ -+ -+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq); -+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, -+ int ifindex, int disabled); -+ -+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv); -+ -+ -+/* nl80211 code */ -+static int ack_handler(struct nl_msg *msg, void *arg) -+{ -+ int *err = arg; -+ *err = 0; -+ return NL_STOP; -+} -+ -+static int finish_handler(struct nl_msg *msg, void *arg) -+{ -+ int *ret = arg; -+ *ret = 0; -+ return NL_SKIP; -+} -+ -+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, -+ void *arg) -+{ -+ int *ret = arg; -+ *ret = err->error; -+ return NL_SKIP; -+} -+ -+ -+static int no_seq_check(struct nl_msg *msg, void *arg) -+{ -+ return NL_OK; -+} -+ -+ -+static int send_and_recv(struct wpa_driver_nl80211_data *drv, -+ struct nl_handle *nl_handle, struct nl_msg *msg, -+ int (*valid_handler)(struct nl_msg *, void *), -+ void *valid_data) -+{ -+ struct nl_cb *cb; -+ int err = -ENOMEM; -+ -+ cb = nl_cb_clone(drv->nl_cb); -+ if (!cb) -+ goto out; -+ -+ err = nl_send_auto_complete(nl_handle, msg); -+ if (err < 0) -+ goto out; -+ -+ err = 1; -+ -+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); -+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err); -+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err); -+ -+ if (valid_handler) -+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, -+ valid_handler, valid_data); -+ -+ while (err > 0) -+ nl_recvmsgs(nl_handle, cb); -+ out: -+ nl_cb_put(cb); -+ nlmsg_free(msg); -+ return err; -+} -+ -+ -+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, -+ struct nl_msg *msg, -+ int (*valid_handler)(struct nl_msg *, void *), -+ void *valid_data) -+{ -+ return send_and_recv(drv, drv->nl_handle, msg, valid_handler, -+ valid_data); -+} -+ -+ -+struct family_data { -+ const char *group; -+ int id; -+}; -+ -+ -+static int family_handler(struct nl_msg *msg, void *arg) -+{ -+ struct family_data *res = arg; -+ struct nlattr *tb[CTRL_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct nlattr *mcgrp; -+ int i; -+ -+ nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ if (!tb[CTRL_ATTR_MCAST_GROUPS]) -+ return NL_SKIP; -+ -+ nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { -+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; -+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp), -+ nla_len(mcgrp), NULL); -+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || -+ !tb2[CTRL_ATTR_MCAST_GRP_ID] || -+ os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]), -+ res->group, -+ nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0) -+ continue; -+ res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); -+ break; -+ }; -+ -+ return NL_SKIP; -+} -+ -+ -+static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv, -+ const char *family, const char *group) -+{ -+ struct nl_msg *msg; -+ int ret = -1; -+ struct family_data res = { group, -ENOENT }; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"), -+ 0, 0, CTRL_CMD_GETFAMILY, 0); -+ NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family); -+ -+ ret = send_and_recv_msgs(drv, msg, family_handler, &res); -+ msg = NULL; -+ if (ret == 0) -+ ret = res.id; -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ if (!drv->associated) -+ return -1; -+ os_memcpy(bssid, drv->bssid, ETH_ALEN); -+ return 0; -+} -+ -+ -+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ if (!drv->associated) -+ return -1; -+ os_memcpy(ssid, drv->ssid, drv->ssid_len); -+ return drv->ssid_len; -+} -+ -+ -+static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, -+ char *buf, size_t len, int del) -+{ -+ union wpa_event_data event; -+ -+ os_memset(&event, 0, sizeof(event)); -+ if (len > sizeof(event.interface_status.ifname)) -+ len = sizeof(event.interface_status.ifname) - 1; -+ os_memcpy(event.interface_status.ifname, buf, len); -+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : -+ EVENT_INTERFACE_ADDED; -+ -+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", -+ del ? "DEL" : "NEW", -+ event.interface_status.ifname, -+ del ? "removed" : "added"); -+ -+ if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) { -+ if (del) -+ drv->if_removed = 1; -+ else -+ drv->if_removed = 0; -+ } -+ -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -+} -+ -+ -+static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv, -+ u8 *buf, size_t len) -+{ -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_IFNAME) { -+ if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname) -+ == 0) -+ return 1; -+ else -+ break; -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, -+ int ifindex, u8 *buf, size_t len) -+{ -+ if (drv->ifindex == ifindex) -+ return 1; -+ -+ if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) { -+ drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname); -+ wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed " -+ "interface"); -+ wpa_driver_nl80211_finish_drv_init(drv); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, -+ struct ifinfomsg *ifi, -+ u8 *buf, size_t len) -+{ -+ struct wpa_driver_nl80211_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ u32 brid = 0; -+ -+ if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) && -+ !have_ifidx(drv, ifi->ifi_index)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign " -+ "ifindex %d", ifi->ifi_index); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " -+ "(%s%s%s%s)", -+ drv->operstate, ifi->ifi_flags, -+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", -+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", -+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", -+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); -+ -+ if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Interface down"); -+ drv->if_disabled = 1; -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); -+ } -+ -+ if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Interface up"); -+ drv->if_disabled = 0; -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); -+ } -+ -+ /* -+ * Some drivers send the association event before the operup event--in -+ * this case, lifting operstate in wpa_driver_nl80211_set_operstate() -+ * fails. This will hit us when wpa_supplicant does not need to do -+ * IEEE 802.1X authentication -+ */ -+ if (drv->operstate == 1 && -+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && -+ !(ifi->ifi_flags & IFF_RUNNING)) -+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, -+ -1, IF_OPER_UP); -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_IFNAME) { -+ wpa_driver_nl80211_event_link( -+ drv, -+ ((char *) attr) + rta_len, -+ attr->rta_len - rta_len, 0); -+ } else if (attr->rta_type == IFLA_MASTER) -+ brid = nla_get_u32((struct nlattr *) attr); -+ attr = RTA_NEXT(attr, attrlen); -+ } -+ -+#ifdef HOSTAPD -+ if (ifi->ifi_family == AF_BRIDGE && brid) { -+ /* device has been added to bridge */ -+ char namebuf[IFNAMSIZ]; -+ if_indextoname(brid, namebuf); -+ wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s", -+ brid, namebuf); -+ add_ifidx(drv, brid); -+ } -+#endif /* HOSTAPD */ -+} -+ -+ -+static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, -+ struct ifinfomsg *ifi, -+ u8 *buf, size_t len) -+{ -+ struct wpa_driver_nl80211_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ u32 brid = 0; -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_IFNAME) { -+ wpa_driver_nl80211_event_link( -+ drv, -+ ((char *) attr) + rta_len, -+ attr->rta_len - rta_len, 1); -+ } else if (attr->rta_type == IFLA_MASTER) -+ brid = nla_get_u32((struct nlattr *) attr); -+ attr = RTA_NEXT(attr, attrlen); -+ } -+ -+#ifdef HOSTAPD -+ if (ifi->ifi_family == AF_BRIDGE && brid) { -+ /* device has been removed from bridge */ -+ char namebuf[IFNAMSIZ]; -+ if_indextoname(brid, namebuf); -+ wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge " -+ "%s", brid, namebuf); -+ del_ifidx(drv, brid); -+ } -+#endif /* HOSTAPD */ -+} -+ -+ -+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv, -+ const u8 *frame, size_t len) -+{ -+ const struct ieee80211_mgmt *mgmt; -+ union wpa_event_data event; -+ -+ mgmt = (const struct ieee80211_mgmt *) frame; -+ if (len < 24 + sizeof(mgmt->u.auth)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event " -+ "frame"); -+ return; -+ } -+ -+ os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN); -+ os_memset(&event, 0, sizeof(event)); -+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN); -+ event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg); -+ event.auth.status_code = le_to_host16(mgmt->u.auth.status_code); -+ if (len > 24 + sizeof(mgmt->u.auth)) { -+ event.auth.ies = mgmt->u.auth.variable; -+ event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth); -+ } -+ -+ wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event); -+} -+ -+ -+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, -+ const u8 *frame, size_t len) -+{ -+ const struct ieee80211_mgmt *mgmt; -+ union wpa_event_data event; -+ u16 status; -+ -+ mgmt = (const struct ieee80211_mgmt *) frame; -+ if (len < 24 + sizeof(mgmt->u.assoc_resp)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event " -+ "frame"); -+ return; -+ } -+ -+ status = le_to_host16(mgmt->u.assoc_resp.status_code); -+ if (status != WLAN_STATUS_SUCCESS) { -+ os_memset(&event, 0, sizeof(event)); -+ event.assoc_reject.bssid = mgmt->bssid; -+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) { -+ event.assoc_reject.resp_ies = -+ (u8 *) mgmt->u.assoc_resp.variable; -+ event.assoc_reject.resp_ies_len = -+ len - 24 - sizeof(mgmt->u.assoc_resp); -+ } -+ event.assoc_reject.status_code = status; -+ -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); -+ return; -+ } -+ -+ drv->associated = 1; -+ os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN); -+ -+ os_memset(&event, 0, sizeof(event)); -+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) { -+ event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; -+ event.assoc_info.resp_ies_len = -+ len - 24 - sizeof(mgmt->u.assoc_resp); -+ } -+ -+ event.assoc_info.freq = drv->assoc_freq; -+ -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); -+} -+ -+ -+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, -+ enum nl80211_commands cmd, struct nlattr *status, -+ struct nlattr *addr, struct nlattr *req_ie, -+ struct nlattr *resp_ie) -+{ -+ union wpa_event_data event; -+ -+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { -+ /* -+ * Avoid reporting two association events that would confuse -+ * the core code. -+ */ -+ wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) " -+ "when using userspace SME", cmd); -+ return; -+ } -+ -+ os_memset(&event, 0, sizeof(event)); -+ if (cmd == NL80211_CMD_CONNECT && -+ nla_get_u16(status) != WLAN_STATUS_SUCCESS) { -+ if (addr) -+ event.assoc_reject.bssid = nla_data(addr); -+ if (resp_ie) { -+ event.assoc_reject.resp_ies = nla_data(resp_ie); -+ event.assoc_reject.resp_ies_len = nla_len(resp_ie); -+ } -+ event.assoc_reject.status_code = nla_get_u16(status); -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); -+ return; -+ } -+ -+ drv->associated = 1; -+ if (addr) -+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); -+ -+ if (req_ie) { -+ event.assoc_info.req_ies = nla_data(req_ie); -+ event.assoc_info.req_ies_len = nla_len(req_ie); -+ } -+ if (resp_ie) { -+ event.assoc_info.resp_ies = nla_data(resp_ie); -+ event.assoc_info.resp_ies_len = nla_len(resp_ie); -+ } -+ -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); -+} -+ -+ -+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, -+ enum nl80211_commands cmd, struct nlattr *addr) -+{ -+ union wpa_event_data event; -+ enum wpa_event_type ev; -+ -+ if (nla_len(addr) != ETH_ALEN) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR, -+ cmd, MAC2STR((u8 *) nla_data(addr))); -+ -+ if (cmd == NL80211_CMD_AUTHENTICATE) -+ ev = EVENT_AUTH_TIMED_OUT; -+ else if (cmd == NL80211_CMD_ASSOCIATE) -+ ev = EVENT_ASSOC_TIMED_OUT; -+ else -+ return; -+ -+ os_memset(&event, 0, sizeof(event)); -+ os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN); -+ wpa_supplicant_event(drv->ctx, ev, &event); -+} -+ -+ -+static void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv, -+ struct nlattr *freq, const u8 *frame, size_t len) -+{ -+ const struct ieee80211_mgmt *mgmt; -+ union wpa_event_data event; -+ u16 fc, stype; -+ -+ mgmt = (const struct ieee80211_mgmt *) frame; -+ if (len < 24) { -+ wpa_printf(MSG_DEBUG, "nl80211: Too short action frame"); -+ return; -+ } -+ -+ fc = le_to_host16(mgmt->frame_control); -+ stype = WLAN_FC_GET_STYPE(fc); -+ -+ os_memset(&event, 0, sizeof(event)); -+ if (freq) { -+ event.rx_action.freq = nla_get_u32(freq); -+ drv->last_mgmt_freq = event.rx_action.freq; -+ } -+ if (stype == WLAN_FC_STYPE_ACTION) { -+ event.rx_action.da = mgmt->da; -+ event.rx_action.sa = mgmt->sa; -+ event.rx_action.bssid = mgmt->bssid; -+ event.rx_action.category = mgmt->u.action.category; -+ event.rx_action.data = &mgmt->u.action.category + 1; -+ event.rx_action.len = frame + len - event.rx_action.data; -+ wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event); -+ } else { -+ event.rx_mgmt.frame = frame; -+ event.rx_mgmt.frame_len = len; -+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); -+ } -+} -+ -+ -+static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv, -+ struct nlattr *cookie, const u8 *frame, -+ size_t len, struct nlattr *ack) -+{ -+ union wpa_event_data event; -+ const struct ieee80211_hdr *hdr; -+ u16 fc; -+ u64 cookie_val; -+ -+ if (!cookie) -+ return; -+ -+ cookie_val = nla_get_u64(cookie); -+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s " -+ "(ack=%d)", -+ (long long unsigned int) cookie_val, -+ cookie_val == drv->send_action_cookie ? -+ " (match)" : " (unknown)", ack != NULL); -+ if (cookie_val != drv->send_action_cookie) -+ return; -+ -+ hdr = (const struct ieee80211_hdr *) frame; -+ fc = le_to_host16(hdr->frame_control); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.tx_status.type = WLAN_FC_GET_TYPE(fc); -+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc); -+ event.tx_status.dst = hdr->addr1; -+ event.tx_status.data = frame; -+ event.tx_status.data_len = len; -+ event.tx_status.ack = ack != NULL; -+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); -+} -+ -+ -+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, -+ enum wpa_event_type type, -+ const u8 *frame, size_t len) -+{ -+ const struct ieee80211_mgmt *mgmt; -+ union wpa_event_data event; -+ const u8 *bssid = NULL; -+ u16 reason_code = 0; -+ -+ mgmt = (const struct ieee80211_mgmt *) frame; -+ if (len >= 24) { -+ bssid = mgmt->bssid; -+ -+ if (drv->associated != 0 && -+ os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && -+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { -+ /* -+ * We have presumably received this deauth as a -+ * response to a clear_state_mismatch() outgoing -+ * deauth. Don't let it take us offline! -+ */ -+ wpa_printf(MSG_DEBUG, "nl80211: Deauth received " -+ "from Unknown BSSID " MACSTR " -- ignoring", -+ MAC2STR(bssid)); -+ return; -+ } -+ } -+ -+ drv->associated = 0; -+ os_memset(&event, 0, sizeof(event)); -+ -+ /* Note: Same offset for Reason Code in both frame subtypes */ -+ if (len >= 24 + sizeof(mgmt->u.deauth)) -+ reason_code = le_to_host16(mgmt->u.deauth.reason_code); -+ -+ if (type == EVENT_DISASSOC) { -+ event.disassoc_info.addr = bssid; -+ event.disassoc_info.reason_code = reason_code; -+ if (frame + len > mgmt->u.disassoc.variable) { -+ event.disassoc_info.ie = mgmt->u.disassoc.variable; -+ event.disassoc_info.ie_len = frame + len - -+ mgmt->u.disassoc.variable; -+ } -+ } else { -+ event.deauth_info.addr = bssid; -+ event.deauth_info.reason_code = reason_code; -+ if (frame + len > mgmt->u.deauth.variable) { -+ event.deauth_info.ie = mgmt->u.deauth.variable; -+ event.deauth_info.ie_len = frame + len - -+ mgmt->u.deauth.variable; -+ } -+ } -+ -+ wpa_supplicant_event(drv->ctx, type, &event); -+} -+ -+ -+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv, -+ enum wpa_event_type type, -+ const u8 *frame, size_t len) -+{ -+ const struct ieee80211_mgmt *mgmt; -+ union wpa_event_data event; -+ u16 reason_code = 0; -+ -+ if (len < 24) -+ return; -+ -+ mgmt = (const struct ieee80211_mgmt *) frame; -+ -+ os_memset(&event, 0, sizeof(event)); -+ /* Note: Same offset for Reason Code in both frame subtypes */ -+ if (len >= 24 + sizeof(mgmt->u.deauth)) -+ reason_code = le_to_host16(mgmt->u.deauth.reason_code); -+ -+ if (type == EVENT_UNPROT_DISASSOC) { -+ event.unprot_disassoc.sa = mgmt->sa; -+ event.unprot_disassoc.da = mgmt->da; -+ event.unprot_disassoc.reason_code = reason_code; -+ } else { -+ event.unprot_deauth.sa = mgmt->sa; -+ event.unprot_deauth.da = mgmt->da; -+ event.unprot_deauth.reason_code = reason_code; -+ } -+ -+ wpa_supplicant_event(drv->ctx, type, &event); -+} -+ -+ -+static void mlme_event(struct wpa_driver_nl80211_data *drv, -+ enum nl80211_commands cmd, struct nlattr *frame, -+ struct nlattr *addr, struct nlattr *timed_out, -+ struct nlattr *freq, struct nlattr *ack, -+ struct nlattr *cookie) -+{ -+ if (timed_out && addr) { -+ mlme_timeout_event(drv, cmd, addr); -+ return; -+ } -+ -+ if (frame == NULL) { -+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame " -+ "data", cmd); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd); -+ wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame", -+ nla_data(frame), nla_len(frame)); -+ -+ switch (cmd) { -+ case NL80211_CMD_AUTHENTICATE: -+ mlme_event_auth(drv, nla_data(frame), nla_len(frame)); -+ break; -+ case NL80211_CMD_ASSOCIATE: -+ mlme_event_assoc(drv, nla_data(frame), nla_len(frame)); -+ break; -+ case NL80211_CMD_DEAUTHENTICATE: -+ mlme_event_deauth_disassoc(drv, EVENT_DEAUTH, -+ nla_data(frame), nla_len(frame)); -+ break; -+ case NL80211_CMD_DISASSOCIATE: -+ mlme_event_deauth_disassoc(drv, EVENT_DISASSOC, -+ nla_data(frame), nla_len(frame)); -+ break; -+ case NL80211_CMD_FRAME: -+ mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame)); -+ break; -+ case NL80211_CMD_FRAME_TX_STATUS: -+ mlme_event_action_tx_status(drv, cookie, nla_data(frame), -+ nla_len(frame), ack); -+ break; -+ case NL80211_CMD_UNPROT_DEAUTHENTICATE: -+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH, -+ nla_data(frame), nla_len(frame)); -+ break; -+ case NL80211_CMD_UNPROT_DISASSOCIATE: -+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC, -+ nla_data(frame), nla_len(frame)); -+ break; -+ default: -+ break; -+ } -+} -+ -+ -+static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv, -+ struct nlattr *tb[]) -+{ -+ union wpa_event_data data; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure"); -+ os_memset(&data, 0, sizeof(data)); -+ if (tb[NL80211_ATTR_MAC]) { -+ wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address", -+ nla_data(tb[NL80211_ATTR_MAC]), -+ nla_len(tb[NL80211_ATTR_MAC])); -+ data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]); -+ } -+ if (tb[NL80211_ATTR_KEY_SEQ]) { -+ wpa_hexdump(MSG_DEBUG, "nl80211: TSC", -+ nla_data(tb[NL80211_ATTR_KEY_SEQ]), -+ nla_len(tb[NL80211_ATTR_KEY_SEQ])); -+ } -+ if (tb[NL80211_ATTR_KEY_TYPE]) { -+ enum nl80211_key_type key_type = -+ nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]); -+ wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type); -+ if (key_type == NL80211_KEYTYPE_PAIRWISE) -+ data.michael_mic_failure.unicast = 1; -+ } else -+ data.michael_mic_failure.unicast = 1; -+ -+ if (tb[NL80211_ATTR_KEY_IDX]) { -+ u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]); -+ wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id); -+ } -+ -+ wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -+} -+ -+ -+static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, -+ struct nlattr *tb[]) -+{ -+ if (tb[NL80211_ATTR_MAC] == NULL) { -+ wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined " -+ "event"); -+ return; -+ } -+ os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); -+ drv->associated = 1; -+ wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined", -+ MAC2STR(drv->bssid)); -+ -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -+} -+ -+ -+static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv, -+ int cancel_event, struct nlattr *tb[]) -+{ -+ unsigned int freq, chan_type, duration; -+ union wpa_event_data data; -+ u64 cookie; -+ -+ if (tb[NL80211_ATTR_WIPHY_FREQ]) -+ freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); -+ else -+ freq = 0; -+ -+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) -+ chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); -+ else -+ chan_type = 0; -+ -+ if (tb[NL80211_ATTR_DURATION]) -+ duration = nla_get_u32(tb[NL80211_ATTR_DURATION]); -+ else -+ duration = 0; -+ -+ if (tb[NL80211_ATTR_COOKIE]) -+ cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); -+ else -+ cookie = 0; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d " -+ "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))", -+ cancel_event, freq, chan_type, duration, -+ (long long unsigned int) cookie, -+ cookie == drv->remain_on_chan_cookie ? "match" : "unknown"); -+ -+ if (cookie != drv->remain_on_chan_cookie) -+ return; /* not for us */ -+ -+ drv->pending_remain_on_chan = !cancel_event; -+ -+ os_memset(&data, 0, sizeof(data)); -+ data.remain_on_channel.freq = freq; -+ data.remain_on_channel.duration = duration; -+ wpa_supplicant_event(drv->ctx, cancel_event ? -+ EVENT_CANCEL_REMAIN_ON_CHANNEL : -+ EVENT_REMAIN_ON_CHANNEL, &data); -+} -+ -+ -+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, -+ struct nlattr *tb[]) -+{ -+ union wpa_event_data event; -+ struct nlattr *nl; -+ int rem; -+ struct scan_info *info; -+#define MAX_REPORT_FREQS 50 -+ int freqs[MAX_REPORT_FREQS]; -+ int num_freqs = 0; -+ -+ os_memset(&event, 0, sizeof(event)); -+ info = &event.scan_info; -+ info->aborted = aborted; -+ -+ if (tb[NL80211_ATTR_SCAN_SSIDS]) { -+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) { -+ struct wpa_driver_scan_ssid *s = -+ &info->ssids[info->num_ssids]; -+ s->ssid = nla_data(nl); -+ s->ssid_len = nla_len(nl); -+ info->num_ssids++; -+ if (info->num_ssids == WPAS_MAX_SCAN_SSIDS) -+ break; -+ } -+ } -+ if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { -+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem) -+ { -+ freqs[num_freqs] = nla_get_u32(nl); -+ num_freqs++; -+ if (num_freqs == MAX_REPORT_FREQS - 1) -+ break; -+ } -+ info->freqs = freqs; -+ info->num_freqs = num_freqs; -+ } -+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); -+} -+ -+ -+static int get_link_signal(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; -+ static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = { -+ [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, -+ }; -+ struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; -+ static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { -+ [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, -+ [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, -+ [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, -+ [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, -+ }; -+ struct wpa_signal_info *sig_change = arg; -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ if (!tb[NL80211_ATTR_STA_INFO] || -+ nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, -+ tb[NL80211_ATTR_STA_INFO], policy)) -+ return NL_SKIP; -+ if (!sinfo[NL80211_STA_INFO_SIGNAL]) -+ return NL_SKIP; -+ -+ sig_change->current_signal = -+ (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); -+ -+ if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { -+ if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, -+ sinfo[NL80211_STA_INFO_TX_BITRATE], -+ rate_policy)) { -+ sig_change->current_txrate = 0; -+ } else { -+ if (rinfo[NL80211_RATE_INFO_BITRATE]) { -+ sig_change->current_txrate = -+ nla_get_u16(rinfo[ -+ NL80211_RATE_INFO_BITRATE]) * 100; -+ } -+ } -+ } -+ -+ return NL_SKIP; -+} -+ -+ -+static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, -+ struct wpa_signal_info *sig) -+{ -+ struct nl_msg *msg; -+ -+ sig->current_signal = -9999; -+ sig->current_txrate = 0; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); -+ -+ return send_and_recv_msgs(drv, msg, get_link_signal, sig); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int get_link_noise(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; -+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { -+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, -+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, -+ }; -+ struct wpa_signal_info *sig_change = arg; -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ if (!tb[NL80211_ATTR_SURVEY_INFO]) { -+ wpa_printf(MSG_DEBUG, "nl80211: survey data missing!"); -+ return NL_SKIP; -+ } -+ -+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, -+ tb[NL80211_ATTR_SURVEY_INFO], -+ survey_policy)) { -+ wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested " -+ "attributes!"); -+ return NL_SKIP; -+ } -+ -+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) -+ return NL_SKIP; -+ -+ if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != -+ sig_change->frequency) -+ return NL_SKIP; -+ -+ if (!sinfo[NL80211_SURVEY_INFO_NOISE]) -+ return NL_SKIP; -+ -+ sig_change->current_noise = -+ (s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); -+ -+ return NL_SKIP; -+} -+ -+ -+static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv, -+ struct wpa_signal_info *sig_change) -+{ -+ struct nl_msg *msg; -+ -+ sig_change->current_noise = 9999; -+ sig_change->frequency = drv->assoc_freq; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ -+ return send_and_recv_msgs(drv, msg, get_link_noise, sig_change); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, -+ struct nlattr *tb[]) -+{ -+ static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { -+ [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, -+ [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 }, -+ [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, -+ [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 }, -+ }; -+ struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; -+ enum nl80211_cqm_rssi_threshold_event event; -+ union wpa_event_data ed; -+ struct wpa_signal_info sig; -+ int res; -+ -+ if (tb[NL80211_ATTR_CQM] == NULL || -+ nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM], -+ cqm_policy)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event"); -+ return; -+ } -+ -+ os_memset(&ed, 0, sizeof(ed)); -+ -+ if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) { -+ if (!tb[NL80211_ATTR_MAC]) -+ return; -+ os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]), -+ ETH_ALEN); -+ wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed); -+ return; -+ } -+ -+ if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL) -+ return; -+ event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); -+ -+ if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) { -+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " -+ "event: RSSI high"); -+ ed.signal_change.above_threshold = 1; -+ } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) { -+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor " -+ "event: RSSI low"); -+ ed.signal_change.above_threshold = 0; -+ } else -+ return; -+ -+ res = nl80211_get_link_signal(drv, &sig); -+ if (res == 0) { -+ ed.signal_change.current_signal = sig.current_signal; -+ ed.signal_change.current_txrate = sig.current_txrate; -+ wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d", -+ sig.current_signal, sig.current_txrate); -+ } -+ -+ res = nl80211_get_link_noise(drv, &sig); -+ if (res == 0) { -+ ed.signal_change.current_noise = sig.current_noise; -+ wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm", -+ sig.current_noise); -+ } -+ -+ wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed); -+} -+ -+ -+static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, -+ struct nlattr **tb) -+{ -+ u8 *addr; -+ union wpa_event_data data; -+ -+ if (tb[NL80211_ATTR_MAC] == NULL) -+ return; -+ addr = nla_data(tb[NL80211_ATTR_MAC]); -+ wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr)); -+ if (drv->nlmode != NL80211_IFTYPE_ADHOC) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); -+ wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data); -+} -+ -+ -+static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv, -+ struct nlattr **tb) -+{ -+ u8 *addr; -+ union wpa_event_data data; -+ -+ if (tb[NL80211_ATTR_MAC] == NULL) -+ return; -+ addr = nla_data(tb[NL80211_ATTR_MAC]); -+ wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR, -+ MAC2STR(addr)); -+ if (drv->nlmode != NL80211_IFTYPE_ADHOC) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN); -+ wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data); -+} -+ -+ -+static int process_event(struct nl_msg *msg, void *arg) -+{ -+ struct wpa_driver_nl80211_data *drv = arg; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ union wpa_event_data data; -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ if (tb[NL80211_ATTR_IFINDEX]) { -+ int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); -+ if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)" -+ " for foreign interface (ifindex %d)", -+ gnlh->cmd, ifindex); -+ return NL_SKIP; -+ } -+ } -+ -+ if (drv->ap_scan_as_station && -+ (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS || -+ gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) { -+ wpa_driver_nl80211_set_mode(&drv->first_bss, -+ IEEE80211_MODE_AP); -+ drv->ap_scan_as_station = 0; -+ } -+ -+ switch (gnlh->cmd) { -+ case NL80211_CMD_TRIGGER_SCAN: -+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger"); -+ break; -+ case NL80211_CMD_NEW_SCAN_RESULTS: -+ wpa_printf(MSG_DEBUG, "nl80211: New scan results available"); -+ drv->scan_complete_events = 1; -+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, -+ drv->ctx); -+ send_scan_event(drv, 0, tb); -+ break; -+ case NL80211_CMD_SCAN_ABORTED: -+ wpa_printf(MSG_DEBUG, "nl80211: Scan aborted"); -+ /* -+ * Need to indicate that scan results are available in order -+ * not to make wpa_supplicant stop its scanning. -+ */ -+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, -+ drv->ctx); -+ send_scan_event(drv, 1, tb); -+ break; -+ case NL80211_CMD_AUTHENTICATE: -+ case NL80211_CMD_ASSOCIATE: -+ case NL80211_CMD_DEAUTHENTICATE: -+ case NL80211_CMD_DISASSOCIATE: -+ case NL80211_CMD_FRAME: -+ case NL80211_CMD_FRAME_TX_STATUS: -+ case NL80211_CMD_UNPROT_DEAUTHENTICATE: -+ case NL80211_CMD_UNPROT_DISASSOCIATE: -+ mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME], -+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT], -+ tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], -+ tb[NL80211_ATTR_COOKIE]); -+ break; -+ case NL80211_CMD_CONNECT: -+ case NL80211_CMD_ROAM: -+ mlme_event_connect(drv, gnlh->cmd, -+ tb[NL80211_ATTR_STATUS_CODE], -+ tb[NL80211_ATTR_MAC], -+ tb[NL80211_ATTR_REQ_IE], -+ tb[NL80211_ATTR_RESP_IE]); -+ break; -+ case NL80211_CMD_DISCONNECT: -+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { -+ /* -+ * Avoid reporting two disassociation events that could -+ * confuse the core code. -+ */ -+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect " -+ "event when using userspace SME"); -+ break; -+ } -+ drv->associated = 0; -+ os_memset(&data, 0, sizeof(data)); -+ if (tb[NL80211_ATTR_REASON_CODE]) -+ data.disassoc_info.reason_code = -+ nla_get_u16(tb[NL80211_ATTR_REASON_CODE]); -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data); -+ break; -+ case NL80211_CMD_MICHAEL_MIC_FAILURE: -+ mlme_event_michael_mic_failure(drv, tb); -+ break; -+ case NL80211_CMD_JOIN_IBSS: -+ mlme_event_join_ibss(drv, tb); -+ break; -+ case NL80211_CMD_REMAIN_ON_CHANNEL: -+ mlme_event_remain_on_channel(drv, 0, tb); -+ break; -+ case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: -+ mlme_event_remain_on_channel(drv, 1, tb); -+ break; -+ case NL80211_CMD_NOTIFY_CQM: -+ nl80211_cqm_event(drv, tb); -+ break; -+ case NL80211_CMD_REG_CHANGE: -+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change"); -+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, -+ NULL); -+ break; -+ case NL80211_CMD_REG_BEACON_HINT: -+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint"); -+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, -+ NULL); -+ break; -+ case NL80211_CMD_NEW_STATION: -+ nl80211_new_station_event(drv, tb); -+ break; -+ case NL80211_CMD_DEL_STATION: -+ nl80211_del_station_event(drv, tb); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " -+ "(cmd=%d)", gnlh->cmd); -+ break; -+ } -+ -+ return NL_SKIP; -+} -+ -+ -+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx, -+ void *handle) -+{ -+ struct nl_cb *cb; -+ struct wpa_driver_nl80211_data *drv = eloop_ctx; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Event message available"); -+ -+ cb = nl_cb_clone(drv->nl_cb); -+ if (!cb) -+ return; -+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); -+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv); -+ nl_recvmsgs(handle, cb); -+ nl_cb_put(cb); -+} -+ -+ -+/** -+ * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain -+ * @priv: driver_nl80211 private data -+ * @alpha2_arg: country to which to switch to -+ * Returns: 0 on success, -1 on failure -+ * -+ * This asks nl80211 to set the regulatory domain for given -+ * country ISO / IEC alpha2. -+ */ -+static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ char alpha2[3]; -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ alpha2[0] = alpha2_arg[0]; -+ alpha2[1] = alpha2_arg[1]; -+ alpha2[2] = '\0'; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_REQ_SET_REG, 0); -+ -+ NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2); -+ if (send_and_recv_msgs(drv, msg, NULL, NULL)) -+ return -EINVAL; -+ return 0; -+nla_put_failure: -+ return -EINVAL; -+} -+ -+ -+struct wiphy_info_data { -+ int max_scan_ssids; -+ int ap_supported; -+ int p2p_supported; -+ int auth_supported; -+ int connect_supported; -+ int offchan_tx_supported; -+ int max_remain_on_chan; -+}; -+ -+ -+static int wiphy_info_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct wiphy_info_data *info = arg; -+ int p2p_go_supported = 0, p2p_client_supported = 0; -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) -+ info->max_scan_ssids = -+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); -+ -+ if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { -+ struct nlattr *nl_mode; -+ int i; -+ nla_for_each_nested(nl_mode, -+ tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { -+ switch (nla_type(nl_mode)) { -+ case NL80211_IFTYPE_AP: -+ info->ap_supported = 1; -+ break; -+ case NL80211_IFTYPE_P2P_GO: -+ p2p_go_supported = 1; -+ break; -+ case NL80211_IFTYPE_P2P_CLIENT: -+ p2p_client_supported = 1; -+ break; -+ } -+ } -+ } -+ -+ info->p2p_supported = p2p_go_supported && p2p_client_supported; -+ -+ if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { -+ struct nlattr *nl_cmd; -+ int i; -+ -+ nla_for_each_nested(nl_cmd, -+ tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { -+ u32 cmd = nla_get_u32(nl_cmd); -+ if (cmd == NL80211_CMD_AUTHENTICATE) -+ info->auth_supported = 1; -+ else if (cmd == NL80211_CMD_CONNECT) -+ info->connect_supported = 1; -+ } -+ } -+ -+ if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) -+ info->offchan_tx_supported = 1; -+ -+ if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]) -+ info->max_remain_on_chan = -+ nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]); -+ -+ return NL_SKIP; -+} -+ -+ -+static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, -+ struct wiphy_info_data *info) -+{ -+ struct nl_msg *msg; -+ -+ os_memset(info, 0, sizeof(*info)); -+ -+ /* default to 5000 since early versions of mac80211 don't set it */ -+ info->max_remain_on_chan = 5000; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_WIPHY, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex); -+ -+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0) -+ return 0; -+ msg = NULL; -+nla_put_failure: -+ nlmsg_free(msg); -+ return -1; -+} -+ -+ -+static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) -+{ -+ struct wiphy_info_data info; -+ if (wpa_driver_nl80211_get_info(drv, &info)) -+ return -1; -+ drv->has_capability = 1; -+ /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ -+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -+ drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | -+ WPA_DRIVER_CAPA_ENC_WEP104 | -+ WPA_DRIVER_CAPA_ENC_TKIP | -+ WPA_DRIVER_CAPA_ENC_CCMP; -+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | -+ WPA_DRIVER_AUTH_SHARED | -+ WPA_DRIVER_AUTH_LEAP; -+ -+ drv->capa.max_scan_ssids = info.max_scan_ssids; -+ if (info.ap_supported) -+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP; -+ -+ if (info.auth_supported) -+ drv->capa.flags |= WPA_DRIVER_FLAGS_SME; -+ else if (!info.connect_supported) { -+ wpa_printf(MSG_INFO, "nl80211: Driver does not support " -+ "authentication/association or connect commands"); -+ return -1; -+ } -+ -+ if (info.offchan_tx_supported) { -+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based " -+ "off-channel TX"); -+ drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX; -+ } -+ -+ drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES; -+ drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE; -+ if (info.p2p_supported) -+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; -+ drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS; -+ drv->capa.max_remain_on_chan = info.max_remain_on_chan; -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv) -+{ -+ int ret; -+ -+ /* Initialize generic netlink and nl80211 */ -+ -+ drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); -+ if (drv->nl_cb == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " -+ "callbacks"); -+ goto err1; -+ } -+ -+ drv->nl_handle = nl80211_handle_alloc(drv->nl_cb); -+ if (drv->nl_handle == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " -+ "callbacks"); -+ goto err2; -+ } -+ -+ drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb); -+ if (drv->nl_handle_event == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " -+ "callbacks (event)"); -+ goto err2b; -+ } -+ -+ if (genl_connect(drv->nl_handle)) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " -+ "netlink"); -+ goto err3; -+ } -+ -+ if (genl_connect(drv->nl_handle_event)) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " -+ "netlink (event)"); -+ goto err3; -+ } -+ -+#ifdef CONFIG_LIBNL20 -+ if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " -+ "netlink cache"); -+ goto err3; -+ } -+ if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) < -+ 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " -+ "netlink cache (event)"); -+ goto err3b; -+ } -+#else /* CONFIG_LIBNL20 */ -+ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle); -+ if (drv->nl_cache == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " -+ "netlink cache"); -+ goto err3; -+ } -+ drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event); -+ if (drv->nl_cache_event == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " -+ "netlink cache (event)"); -+ goto err3b; -+ } -+#endif /* CONFIG_LIBNL20 */ -+ -+ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211"); -+ if (drv->nl80211 == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not " -+ "found"); -+ goto err4; -+ } -+ -+ ret = nl_get_multicast_id(drv, "nl80211", "scan"); -+ if (ret >= 0) -+ ret = nl_socket_add_membership(drv->nl_handle_event, ret); -+ if (ret < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " -+ "membership for scan events: %d (%s)", -+ ret, strerror(-ret)); -+ goto err4; -+ } -+ -+ ret = nl_get_multicast_id(drv, "nl80211", "mlme"); -+ if (ret >= 0) -+ ret = nl_socket_add_membership(drv->nl_handle_event, ret); -+ if (ret < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " -+ "membership for mlme events: %d (%s)", -+ ret, strerror(-ret)); -+ goto err4; -+ } -+ -+ ret = nl_get_multicast_id(drv, "nl80211", "regulatory"); -+ if (ret >= 0) -+ ret = nl_socket_add_membership(drv->nl_handle_event, ret); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " -+ "membership for regulatory events: %d (%s)", -+ ret, strerror(-ret)); -+ /* Continue without regulatory events */ -+ } -+ -+ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event), -+ wpa_driver_nl80211_event_receive, drv, -+ drv->nl_handle_event); -+ -+ return 0; -+ -+err4: -+ nl_cache_free(drv->nl_cache_event); -+err3b: -+ nl_cache_free(drv->nl_cache); -+err3: -+ nl80211_handle_destroy(drv->nl_handle_event); -+err2b: -+ nl80211_handle_destroy(drv->nl_handle); -+err2: -+ nl_cb_put(drv->nl_cb); -+err1: -+ return -1; -+} -+ -+ -+static void wpa_driver_nl80211_rfkill_blocked(void *ctx) -+{ -+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked"); -+ /* -+ * This may be for any interface; use ifdown event to disable -+ * interface. -+ */ -+} -+ -+ -+static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) -+{ -+ struct wpa_driver_nl80211_data *drv = ctx; -+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked"); -+ if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " -+ "after rfkill unblock"); -+ return; -+ } -+ /* rtnetlink ifup handler will report interface as enabled */ -+} -+ -+ -+static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv) -+{ -+ /* Find phy (radio) to which this interface belongs */ -+ char buf[90], *pos; -+ int f, rv; -+ -+ drv->phyname[0] = '\0'; -+ snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name", -+ drv->first_bss.ifname); -+ f = open(buf, O_RDONLY); -+ if (f < 0) { -+ wpa_printf(MSG_DEBUG, "Could not open file %s: %s", -+ buf, strerror(errno)); -+ return; -+ } -+ -+ rv = read(f, drv->phyname, sizeof(drv->phyname) - 1); -+ close(f); -+ if (rv < 0) { -+ wpa_printf(MSG_DEBUG, "Could not read file %s: %s", -+ buf, strerror(errno)); -+ return; -+ } -+ -+ drv->phyname[rv] = '\0'; -+ pos = os_strchr(drv->phyname, '\n'); -+ if (pos) -+ *pos = '\0'; -+ wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s", -+ drv->first_bss.ifname, drv->phyname); -+} -+ -+ -+/** -+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface -+ * @ctx: context to be used when calling wpa_supplicant functions, -+ * e.g., wpa_supplicant_event() -+ * @ifname: interface name, e.g., wlan0 -+ * @global_priv: private driver global data from global_init() -+ * Returns: Pointer to private data, %NULL on failure -+ */ -+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, -+ void *global_priv) -+{ -+ struct wpa_driver_nl80211_data *drv; -+ struct netlink_config *cfg; -+ struct rfkill_config *rcfg; -+ struct i802_bss *bss; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->global = global_priv; -+ drv->ctx = ctx; -+ bss = &drv->first_bss; -+ bss->drv = drv; -+ os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname)); -+ drv->monitor_ifidx = -1; -+ drv->monitor_sock = -1; -+ drv->ioctl_sock = -1; -+ -+ if (wpa_driver_nl80211_init_nl(drv)) { -+ os_free(drv); -+ return NULL; -+ } -+ -+ nl80211_get_phy_name(drv); -+ -+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->ioctl_sock < 0) { -+ perror("socket(PF_INET,SOCK_DGRAM)"); -+ goto failed; -+ } -+ -+ cfg = os_zalloc(sizeof(*cfg)); -+ if (cfg == NULL) -+ goto failed; -+ cfg->ctx = drv; -+ cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; -+ cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; -+ drv->netlink = netlink_init(cfg); -+ if (drv->netlink == NULL) { -+ os_free(cfg); -+ goto failed; -+ } -+ -+ rcfg = os_zalloc(sizeof(*rcfg)); -+ if (rcfg == NULL) -+ goto failed; -+ rcfg->ctx = drv; -+ os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); -+ rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked; -+ rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked; -+ drv->rfkill = rfkill_init(rcfg); -+ if (drv->rfkill == NULL) { -+ wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available"); -+ os_free(rcfg); -+ } -+ -+ if (wpa_driver_nl80211_finish_drv_init(drv)) -+ goto failed; -+ -+ if (drv->global) -+ dl_list_add(&drv->global->interfaces, &drv->list); -+ -+ return bss; -+ -+failed: -+ rfkill_deinit(drv->rfkill); -+ netlink_deinit(drv->netlink); -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ -+ genl_family_put(drv->nl80211); -+ nl_cache_free(drv->nl_cache); -+ nl80211_handle_destroy(drv->nl_handle); -+ nl_cb_put(drv->nl_cb); -+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); -+ -+ os_free(drv); -+ return NULL; -+} -+ -+ -+static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv, -+ struct nl_handle *nl_handle, -+ u16 type, const u8 *match, size_t match_len) -+{ -+ struct nl_msg *msg; -+ int ret = -1; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_REGISTER_ACTION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type); -+ NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match); -+ -+ ret = send_and_recv(drv, nl_handle, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Register frame command " -+ "failed (type=%u): ret=%d (%s)", -+ type, ret, strerror(-ret)); -+ wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match", -+ match, match_len); -+ goto nla_put_failure; -+ } -+ ret = 0; -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv, -+ const u8 *match, size_t match_len) -+{ -+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); -+ return nl80211_register_frame(drv, drv->nl_handle_event, -+ type, match, match_len); -+} -+ -+ -+static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv) -+{ -+#ifdef CONFIG_P2P -+ /* GAS Initial Request */ -+ if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0) -+ return -1; -+ /* GAS Initial Response */ -+ if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0) -+ return -1; -+ /* GAS Comeback Request */ -+ if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0) -+ return -1; -+ /* GAS Comeback Response */ -+ if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0) -+ return -1; -+ /* P2P Public Action */ -+ if (nl80211_register_action_frame(drv, -+ (u8 *) "\x04\x09\x50\x6f\x9a\x09", -+ 6) < 0) -+ return -1; -+ /* P2P Action */ -+ if (nl80211_register_action_frame(drv, -+ (u8 *) "\x7f\x50\x6f\x9a\x09", -+ 5) < 0) -+ return -1; -+#endif /* CONFIG_P2P */ -+#ifdef CONFIG_IEEE80211W -+ /* SA Query Response */ -+ if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0) -+ return -1; -+#endif /* CONFIG_IEEE80211W */ -+ -+ /* FT Action frames */ -+ if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0) -+ return -1; -+ else -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT | -+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; -+ -+ return 0; -+} -+ -+ -+static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx) -+{ -+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); -+} -+ -+ -+static int -+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) -+{ -+ struct i802_bss *bss = &drv->first_bss; -+ int send_rfkill_event = 0; -+ -+ drv->ifindex = if_nametoindex(bss->ifname); -+ drv->first_bss.ifindex = drv->ifindex; -+ -+#ifndef HOSTAPD -+ if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to " -+ "use managed mode"); -+ } -+ -+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { -+ if (rfkill_is_blocked(drv->rfkill)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable " -+ "interface '%s' due to rfkill", -+ bss->ifname); -+ drv->if_disabled = 1; -+ send_rfkill_event = 1; -+ } else { -+ wpa_printf(MSG_ERROR, "nl80211: Could not set " -+ "interface '%s' UP", bss->ifname); -+ return -1; -+ } -+ } -+ -+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, -+ 1, IF_OPER_DORMANT); -+#endif /* HOSTAPD */ -+ -+ if (wpa_driver_nl80211_capa(drv)) -+ return -1; -+ -+ if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr)) -+ return -1; -+ -+ if (nl80211_register_action_frames(drv) < 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action " -+ "frame processing - ignore for now"); -+ /* -+ * Older kernel versions did not support this, so ignore the -+ * error for now. Some functionality may not be available -+ * because of this. -+ */ -+ } -+ -+ if (send_rfkill_event) { -+ eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, -+ drv, drv->ctx); -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv) -+{ -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_DEL_BEACON, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ -+ return send_and_recv_msgs(drv, msg, NULL, NULL); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+/** -+ * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface -+ * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init() -+ * -+ * Shut down driver interface and processing of driver events. Free -+ * private data buffer if one was allocated in wpa_driver_nl80211_init(). -+ */ -+static void wpa_driver_nl80211_deinit(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ -+ if (drv->nl_handle_preq) -+ wpa_driver_nl80211_probe_req_report(bss, 0); -+ if (bss->added_if_into_bridge) { -+ if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname) -+ < 0) -+ wpa_printf(MSG_INFO, "nl80211: Failed to remove " -+ "interface %s from bridge %s: %s", -+ bss->ifname, bss->brname, strerror(errno)); -+ } -+ if (bss->added_bridge) { -+ if (linux_br_del(drv->ioctl_sock, bss->brname) < 0) -+ wpa_printf(MSG_INFO, "nl80211: Failed to remove " -+ "bridge %s: %s", -+ bss->brname, strerror(errno)); -+ } -+ -+ nl80211_remove_monitor_interface(drv); -+ -+ if (drv->nlmode == NL80211_IFTYPE_AP) -+ wpa_driver_nl80211_del_beacon(drv); -+ -+#ifdef HOSTAPD -+ if (drv->last_freq_ht) { -+ /* Clear HT flags from the driver */ -+ struct hostapd_freq_params freq; -+ os_memset(&freq, 0, sizeof(freq)); -+ freq.freq = drv->last_freq; -+ i802_set_freq(priv, &freq); -+ } -+ -+ if (drv->eapol_sock >= 0) { -+ eloop_unregister_read_sock(drv->eapol_sock); -+ close(drv->eapol_sock); -+ } -+ -+ if (drv->if_indices != drv->default_if_indices) -+ os_free(drv->if_indices); -+#endif /* HOSTAPD */ -+ -+ if (drv->disable_11b_rates) -+ nl80211_disable_11b_rates(drv, drv->ifindex, 0); -+ -+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); -+ netlink_deinit(drv->netlink); -+ rfkill_deinit(drv->rfkill); -+ -+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); -+ -+ (void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0); -+ wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA); -+ -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ -+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); -+ genl_family_put(drv->nl80211); -+ nl_cache_free(drv->nl_cache); -+ nl_cache_free(drv->nl_cache_event); -+ nl80211_handle_destroy(drv->nl_handle); -+ nl80211_handle_destroy(drv->nl_handle_event); -+ nl_cb_put(drv->nl_cb); -+ -+ os_free(drv->filter_ssids); -+ -+ if (drv->global) -+ dl_list_del(&drv->list); -+ -+ os_free(drv); -+} -+ -+ -+/** -+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion -+ * @eloop_ctx: Driver private data -+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init() -+ * -+ * This function can be used as registered timeout when starting a scan to -+ * generate a scan completed event if the driver does not report this. -+ */ -+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_nl80211_data *drv = eloop_ctx; -+ if (drv->ap_scan_as_station) { -+ wpa_driver_nl80211_set_mode(&drv->first_bss, -+ IEEE80211_MODE_AP); -+ drv->ap_scan_as_station = 0; -+ } -+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+} -+ -+ -+/** -+ * wpa_driver_nl80211_scan - Request the driver to initiate scan -+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init() -+ * @params: Scan parameters -+ * Returns: 0 on success, -1 on failure -+ */ -+static int wpa_driver_nl80211_scan(void *priv, -+ struct wpa_driver_scan_params *params) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ret = 0, timeout; -+ struct nl_msg *msg, *ssids, *freqs; -+ size_t i; -+ -+ msg = nlmsg_alloc(); -+ ssids = nlmsg_alloc(); -+ freqs = nlmsg_alloc(); -+ if (!msg || !ssids || !freqs) { -+ nlmsg_free(msg); -+ nlmsg_free(ssids); -+ nlmsg_free(freqs); -+ return -1; -+ } -+ -+ os_free(drv->filter_ssids); -+ drv->filter_ssids = params->filter_ssids; -+ params->filter_ssids = NULL; -+ drv->num_filter_ssids = params->num_filter_ssids; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_TRIGGER_SCAN, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ -+ for (i = 0; i < params->num_ssids; i++) { -+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID", -+ params->ssids[i].ssid, -+ params->ssids[i].ssid_len); -+ NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len, -+ params->ssids[i].ssid); -+ } -+ if (params->num_ssids) -+ nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); -+ -+ if (params->extra_ies) { -+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs", -+ params->extra_ies, params->extra_ies_len); -+ NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len, -+ params->extra_ies); -+ } -+ -+ if (params->freqs) { -+ for (i = 0; params->freqs[i]; i++) { -+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u " -+ "MHz", params->freqs[i]); -+ NLA_PUT_U32(freqs, i + 1, params->freqs[i]); -+ } -+ nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); -+ } -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+#ifdef HOSTAPD -+ if (drv->nlmode == NL80211_IFTYPE_AP) { -+ /* -+ * mac80211 does not allow scan requests in AP mode, so -+ * try to do this in station mode. -+ */ -+ if (wpa_driver_nl80211_set_mode(bss, -+ IEEE80211_MODE_INFRA)) -+ goto nla_put_failure; -+ -+ if (wpa_driver_nl80211_scan(drv, params)) { -+ wpa_driver_nl80211_set_mode(bss, -+ IEEE80211_MODE_AP); -+ goto nla_put_failure; -+ } -+ -+ /* Restore AP mode when processing scan results */ -+ drv->ap_scan_as_station = 1; -+ ret = 0; -+ } else -+ goto nla_put_failure; -+#else /* HOSTAPD */ -+ goto nla_put_failure; -+#endif /* HOSTAPD */ -+ } -+ -+ /* Not all drivers generate "scan completed" wireless event, so try to -+ * read results after a timeout. */ -+ timeout = 10; -+ if (drv->scan_complete_events) { -+ /* -+ * The driver seems to deliver events to notify when scan is -+ * complete, so use longer timeout to avoid race conditions -+ * with scanning and following association request. -+ */ -+ timeout = 30; -+ } -+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " -+ "seconds", ret, timeout); -+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); -+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, -+ drv, drv->ctx); -+ -+nla_put_failure: -+ nlmsg_free(ssids); -+ nlmsg_free(msg); -+ nlmsg_free(freqs); -+ return ret; -+} -+ -+ -+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie) -+{ -+ const u8 *end, *pos; -+ -+ if (ies == NULL) -+ return NULL; -+ -+ pos = ies; -+ end = ies + ies_len; -+ -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == ie) -+ return pos; -+ pos += 2 + pos[1]; -+ } -+ -+ return NULL; -+} -+ -+ -+static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv, -+ const u8 *ie, size_t ie_len) -+{ -+ const u8 *ssid; -+ size_t i; -+ -+ if (drv->filter_ssids == NULL) -+ return 0; -+ -+ ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID); -+ if (ssid == NULL) -+ return 1; -+ -+ for (i = 0; i < drv->num_filter_ssids; i++) { -+ if (ssid[1] == drv->filter_ssids[i].ssid_len && -+ os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) == -+ 0) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+ -+struct nl80211_bss_info_arg { -+ struct wpa_driver_nl80211_data *drv; -+ struct wpa_scan_results *res; -+}; -+ -+static int bss_info_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct nlattr *bss[NL80211_BSS_MAX + 1]; -+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { -+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC }, -+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, -+ [NL80211_BSS_TSF] = { .type = NLA_U64 }, -+ [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, -+ [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, -+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, -+ [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, -+ [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, -+ [NL80211_BSS_STATUS] = { .type = NLA_U32 }, -+ [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, -+ [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, -+ }; -+ struct nl80211_bss_info_arg *_arg = arg; -+ struct wpa_scan_results *res = _arg->res; -+ struct wpa_scan_res **tmp; -+ struct wpa_scan_res *r; -+ const u8 *ie, *beacon_ie; -+ size_t ie_len, beacon_ie_len; -+ u8 *pos; -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ if (!tb[NL80211_ATTR_BSS]) -+ return NL_SKIP; -+ if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], -+ bss_policy)) -+ return NL_SKIP; -+ if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { -+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); -+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); -+ } else { -+ ie = NULL; -+ ie_len = 0; -+ } -+ if (bss[NL80211_BSS_BEACON_IES]) { -+ beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]); -+ beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]); -+ } else { -+ beacon_ie = NULL; -+ beacon_ie_len = 0; -+ } -+ -+ if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie, -+ ie ? ie_len : beacon_ie_len)) -+ return NL_SKIP; -+ -+ r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len); -+ if (r == NULL) -+ return NL_SKIP; -+ if (bss[NL80211_BSS_BSSID]) -+ os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]), -+ ETH_ALEN); -+ if (bss[NL80211_BSS_FREQUENCY]) -+ r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); -+ if (bss[NL80211_BSS_BEACON_INTERVAL]) -+ r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]); -+ if (bss[NL80211_BSS_CAPABILITY]) -+ r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); -+ r->flags |= WPA_SCAN_NOISE_INVALID; -+ if (bss[NL80211_BSS_SIGNAL_MBM]) { -+ r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]); -+ r->level /= 100; /* mBm to dBm */ -+ r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID; -+ } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) { -+ r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); -+ r->flags |= WPA_SCAN_LEVEL_INVALID; -+ } else -+ r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; -+ if (bss[NL80211_BSS_TSF]) -+ r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); -+ if (bss[NL80211_BSS_SEEN_MS_AGO]) -+ r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); -+ r->ie_len = ie_len; -+ pos = (u8 *) (r + 1); -+ if (ie) { -+ os_memcpy(pos, ie, ie_len); -+ pos += ie_len; -+ } -+ r->beacon_ie_len = beacon_ie_len; -+ if (beacon_ie) -+ os_memcpy(pos, beacon_ie, beacon_ie_len); -+ -+ if (bss[NL80211_BSS_STATUS]) { -+ enum nl80211_bss_status status; -+ status = nla_get_u32(bss[NL80211_BSS_STATUS]); -+ switch (status) { -+ case NL80211_BSS_STATUS_AUTHENTICATED: -+ r->flags |= WPA_SCAN_AUTHENTICATED; -+ break; -+ case NL80211_BSS_STATUS_ASSOCIATED: -+ r->flags |= WPA_SCAN_ASSOCIATED; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ tmp = os_realloc(res->res, -+ (res->num + 1) * sizeof(struct wpa_scan_res *)); -+ if (tmp == NULL) { -+ os_free(r); -+ return NL_SKIP; -+ } -+ tmp[res->num++] = r; -+ res->res = tmp; -+ -+ return NL_SKIP; -+} -+ -+ -+static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv, -+ const u8 *addr) -+{ -+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { -+ wpa_printf(MSG_DEBUG, "nl80211: Clear possible state " -+ "mismatch (" MACSTR ")", MAC2STR(addr)); -+ wpa_driver_nl80211_mlme(drv, addr, -+ NL80211_CMD_DEAUTHENTICATE, -+ WLAN_REASON_PREV_AUTH_NOT_VALID, 1); -+ } -+} -+ -+ -+static void wpa_driver_nl80211_check_bss_status( -+ struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res) -+{ -+ size_t i; -+ -+ for (i = 0; i < res->num; i++) { -+ struct wpa_scan_res *r = res->res[i]; -+ if (r->flags & WPA_SCAN_AUTHENTICATED) { -+ wpa_printf(MSG_DEBUG, "nl80211: Scan results " -+ "indicates BSS status with " MACSTR -+ " as authenticated", -+ MAC2STR(r->bssid)); -+ if (drv->nlmode == NL80211_IFTYPE_STATION && -+ os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 && -+ os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) != -+ 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID" -+ " in local state (auth=" MACSTR -+ " assoc=" MACSTR ")", -+ MAC2STR(drv->auth_bssid), -+ MAC2STR(drv->bssid)); -+ clear_state_mismatch(drv, r->bssid); -+ } -+ } -+ -+ if (r->flags & WPA_SCAN_ASSOCIATED) { -+ wpa_printf(MSG_DEBUG, "nl80211: Scan results " -+ "indicate BSS status with " MACSTR -+ " as associated", -+ MAC2STR(r->bssid)); -+ if (drv->nlmode == NL80211_IFTYPE_STATION && -+ !drv->associated) { -+ wpa_printf(MSG_DEBUG, "nl80211: Local state " -+ "(not associated) does not match " -+ "with BSS state"); -+ clear_state_mismatch(drv, r->bssid); -+ } else if (drv->nlmode == NL80211_IFTYPE_STATION && -+ os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != -+ 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Local state " -+ "(associated with " MACSTR ") does " -+ "not match with BSS state", -+ MAC2STR(drv->bssid)); -+ clear_state_mismatch(drv, r->bssid); -+ clear_state_mismatch(drv, drv->bssid); -+ } -+ } -+ } -+} -+ -+ -+static void wpa_scan_results_free(struct wpa_scan_results *res) -+{ -+ size_t i; -+ -+ if (res == NULL) -+ return; -+ -+ for (i = 0; i < res->num; i++) -+ os_free(res->res[i]); -+ os_free(res->res); -+ os_free(res); -+} -+ -+ -+static struct wpa_scan_results * -+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) -+{ -+ struct nl_msg *msg; -+ struct wpa_scan_results *res; -+ int ret; -+ struct nl80211_bss_info_arg arg; -+ -+ res = os_zalloc(sizeof(*res)); -+ if (res == NULL) -+ return NULL; -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto nla_put_failure; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP, -+ NL80211_CMD_GET_SCAN, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ -+ arg.drv = drv; -+ arg.res = res; -+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); -+ msg = NULL; -+ if (ret == 0) { -+ wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)", -+ (unsigned long) res->num); -+ return res; -+ } -+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+nla_put_failure: -+ nlmsg_free(msg); -+ wpa_scan_results_free(res); -+ return NULL; -+} -+ -+ -+/** -+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results -+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init() -+ * Returns: Scan results on success, -1 on failure -+ */ -+static struct wpa_scan_results * -+wpa_driver_nl80211_get_scan_results(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct wpa_scan_results *res; -+ -+ res = nl80211_get_scan_results(drv); -+ if (res) -+ wpa_driver_nl80211_check_bss_status(drv, res); -+ return res; -+} -+ -+ -+static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv) -+{ -+ struct wpa_scan_results *res; -+ size_t i; -+ -+ res = nl80211_get_scan_results(drv); -+ if (res == NULL) { -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results"); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Scan result dump"); -+ for (i = 0; i < res->num; i++) { -+ struct wpa_scan_res *r = res->res[i]; -+ wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s", -+ (int) i, (int) res->num, MAC2STR(r->bssid), -+ r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "", -+ r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : ""); -+ } -+ -+ wpa_scan_results_free(res); -+} -+ -+ -+static int wpa_driver_nl80211_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ifindex = if_nametoindex(ifname); -+ struct nl_msg *msg; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d " -+ "set_tx=%d seq_len=%lu key_len=%lu", -+ __func__, ifindex, alg, addr, key_idx, set_tx, -+ (unsigned long) seq_len, (unsigned long) key_len); -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ if (alg == WPA_ALG_NONE) { -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_DEL_KEY, 0); -+ } else { -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_NEW_KEY, 0); -+ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key); -+ switch (alg) { -+ case WPA_ALG_WEP: -+ if (key_len == 5) -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_WEP40); -+ else -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_WEP104); -+ break; -+ case WPA_ALG_TKIP: -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_TKIP); -+ break; -+ case WPA_ALG_CCMP: -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_CCMP); -+ break; -+ case WPA_ALG_IGTK: -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_AES_CMAC); -+ break; -+ default: -+ wpa_printf(MSG_ERROR, "%s: Unsupported encryption " -+ "algorithm %d", __func__, alg); -+ nlmsg_free(msg); -+ return -1; -+ } -+ } -+ -+ if (seq && seq_len) -+ NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq); -+ -+ if (addr && !is_broadcast_ether_addr(addr)) { -+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ -+ if (alg != WPA_ALG_WEP && key_idx && !set_tx) { -+ wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK"); -+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, -+ NL80211_KEYTYPE_GROUP); -+ } -+ } else if (addr && is_broadcast_ether_addr(addr)) { -+ struct nl_msg *types; -+ int err; -+ wpa_printf(MSG_DEBUG, " broadcast key"); -+ types = nlmsg_alloc(); -+ if (!types) -+ goto nla_put_failure; -+ NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); -+ err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, -+ types); -+ nlmsg_free(types); -+ if (err) -+ goto nla_put_failure; -+ } -+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) -+ ret = 0; -+ if (ret) -+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)", -+ ret, strerror(-ret)); -+ -+ /* -+ * If we failed or don't need to set the default TX key (below), -+ * we're done here. -+ */ -+ if (ret || !set_tx || alg == WPA_ALG_NONE) -+ return ret; -+ if (drv->nlmode == NL80211_IFTYPE_AP && addr && -+ !is_broadcast_ether_addr(addr)) -+ return ret; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_KEY, 0); -+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); -+ if (alg == WPA_ALG_IGTK) -+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT); -+ else -+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT); -+ if (addr && is_broadcast_ether_addr(addr)) { -+ struct nl_msg *types; -+ int err; -+ types = nlmsg_alloc(); -+ if (!types) -+ goto nla_put_failure; -+ NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST); -+ err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, -+ types); -+ nlmsg_free(types); -+ if (err) -+ goto nla_put_failure; -+ } else if (addr) { -+ struct nl_msg *types; -+ int err; -+ types = nlmsg_alloc(); -+ if (!types) -+ goto nla_put_failure; -+ NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST); -+ err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES, -+ types); -+ nlmsg_free(types); -+ if (err) -+ goto nla_put_failure; -+ } -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret == -ENOENT) -+ ret = 0; -+ if (ret) -+ wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; " -+ "err=%d %s)", ret, strerror(-ret)); -+ return ret; -+ -+nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, -+ int key_idx, int defkey, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY); -+ if (!key_attr) -+ return -1; -+ -+ if (defkey && alg == WPA_ALG_IGTK) -+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT); -+ else if (defkey) -+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); -+ -+ NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx); -+ -+ switch (alg) { -+ case WPA_ALG_WEP: -+ if (key_len == 5) -+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_WEP40); -+ else -+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_WEP104); -+ break; -+ case WPA_ALG_TKIP: -+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP); -+ break; -+ case WPA_ALG_CCMP: -+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP); -+ break; -+ case WPA_ALG_IGTK: -+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_AES_CMAC); -+ break; -+ default: -+ wpa_printf(MSG_ERROR, "%s: Unsupported encryption " -+ "algorithm %d", __func__, alg); -+ return -1; -+ } -+ -+ if (seq && seq_len) -+ NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq); -+ -+ NLA_PUT(msg, NL80211_KEY_DATA, key_len, key); -+ -+ nla_nest_end(msg, key_attr); -+ -+ return 0; -+ nla_put_failure: -+ return -1; -+} -+ -+ -+static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params, -+ struct nl_msg *msg) -+{ -+ int i, privacy = 0; -+ struct nlattr *nl_keys, *nl_key; -+ -+ for (i = 0; i < 4; i++) { -+ if (!params->wep_key[i]) -+ continue; -+ privacy = 1; -+ break; -+ } -+ if (params->wps == WPS_MODE_PRIVACY) -+ privacy = 1; -+ if (params->pairwise_suite && -+ params->pairwise_suite != WPA_CIPHER_NONE) -+ privacy = 1; -+ -+ if (!privacy) -+ return 0; -+ -+ NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); -+ -+ nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS); -+ if (!nl_keys) -+ goto nla_put_failure; -+ -+ for (i = 0; i < 4; i++) { -+ if (!params->wep_key[i]) -+ continue; -+ -+ nl_key = nla_nest_start(msg, i); -+ if (!nl_key) -+ goto nla_put_failure; -+ -+ NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i], -+ params->wep_key[i]); -+ if (params->wep_key_len[i] == 5) -+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_WEP40); -+ else -+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, -+ WLAN_CIPHER_SUITE_WEP104); -+ -+ NLA_PUT_U8(msg, NL80211_KEY_IDX, i); -+ -+ if (i == params->wep_tx_keyidx) -+ NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); -+ -+ nla_nest_end(msg, nl_key); -+ } -+ nla_nest_end(msg, nl_keys); -+ -+ return 0; -+ -+nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, -+ const u8 *addr, int cmd, u16 reason_code, -+ int local_state_change) -+{ -+ int ret = -1; -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ if (local_state_change) -+ NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ goto nla_put_failure; -+ } -+ ret = 0; -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, -+ const u8 *addr, int reason_code) -+{ -+ wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", -+ __func__, MAC2STR(addr), reason_code); -+ drv->associated = 0; -+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT, -+ reason_code, 0); -+} -+ -+ -+static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) -+ return wpa_driver_nl80211_disconnect(drv, addr, reason_code); -+ wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)", -+ __func__, MAC2STR(addr), reason_code); -+ drv->associated = 0; -+ if (drv->nlmode == NL80211_IFTYPE_ADHOC) -+ return nl80211_leave_ibss(drv); -+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, -+ reason_code, 0); -+} -+ -+ -+static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) -+ return wpa_driver_nl80211_disconnect(drv, addr, reason_code); -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ drv->associated = 0; -+ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE, -+ reason_code, 0); -+} -+ -+ -+static int wpa_driver_nl80211_authenticate( -+ void *priv, struct wpa_driver_auth_params *params) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ret = -1, i; -+ struct nl_msg *msg; -+ enum nl80211_auth_type type; -+ int count = 0; -+ -+ drv->associated = 0; -+ os_memset(drv->auth_bssid, 0, ETH_ALEN); -+ /* FIX: IBSS mode */ -+ if (drv->nlmode != NL80211_IFTYPE_STATION && -+ wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0) -+ return -1; -+ -+retry: -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)", -+ drv->ifindex); -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_AUTHENTICATE, 0); -+ -+ for (i = 0; i < 4; i++) { -+ if (!params->wep_key[i]) -+ continue; -+ wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP, -+ NULL, i, -+ i == params->wep_tx_keyidx, NULL, 0, -+ params->wep_key[i], -+ params->wep_key_len[i]); -+ if (params->wep_tx_keyidx != i) -+ continue; -+ if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0, -+ params->wep_key[i], params->wep_key_len[i])) { -+ nlmsg_free(msg); -+ return -1; -+ } -+ } -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ if (params->bssid) { -+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, -+ MAC2STR(params->bssid)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); -+ } -+ if (params->freq) { -+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); -+ } -+ if (params->ssid) { -+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID", -+ params->ssid, params->ssid_len); -+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, -+ params->ssid); -+ } -+ wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len); -+ if (params->ie) -+ NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie); -+ if (params->auth_alg & WPA_AUTH_ALG_OPEN) -+ type = NL80211_AUTHTYPE_OPEN_SYSTEM; -+ else if (params->auth_alg & WPA_AUTH_ALG_SHARED) -+ type = NL80211_AUTHTYPE_SHARED_KEY; -+ else if (params->auth_alg & WPA_AUTH_ALG_LEAP) -+ type = NL80211_AUTHTYPE_NETWORK_EAP; -+ else if (params->auth_alg & WPA_AUTH_ALG_FT) -+ type = NL80211_AUTHTYPE_FT; -+ else -+ goto nla_put_failure; -+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type); -+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); -+ if (params->local_state_change) { -+ wpa_printf(MSG_DEBUG, " * Local state change only"); -+ NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE); -+ } -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ count++; -+ if (ret == -EALREADY && count == 1 && params->bssid && -+ !params->local_state_change) { -+ /* -+ * mac80211 does not currently accept new -+ * authentication if we are already authenticated. As a -+ * workaround, force deauthentication and try again. -+ */ -+ wpa_printf(MSG_DEBUG, "nl80211: Retry authentication " -+ "after forced deauthentication"); -+ wpa_driver_nl80211_deauthenticate( -+ bss, params->bssid, -+ WLAN_REASON_PREV_AUTH_NOT_VALID); -+ nlmsg_free(msg); -+ goto retry; -+ } -+ goto nla_put_failure; -+ } -+ ret = 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Authentication request send " -+ "successfully"); -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+struct phy_info_arg { -+ u16 *num_modes; -+ struct hostapd_hw_modes *modes; -+}; -+ -+static int phy_info_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct phy_info_arg *phy_info = arg; -+ -+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; -+ -+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; -+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { -+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, -+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, -+ [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, -+ [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, -+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, -+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, -+ }; -+ -+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; -+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { -+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, -+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, -+ }; -+ -+ struct nlattr *nl_band; -+ struct nlattr *nl_freq; -+ struct nlattr *nl_rate; -+ int rem_band, rem_freq, rem_rate; -+ struct hostapd_hw_modes *mode; -+ int idx, mode_is_set; -+ -+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) -+ return NL_SKIP; -+ -+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) { -+ mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode)); -+ if (!mode) -+ return NL_SKIP; -+ phy_info->modes = mode; -+ -+ mode_is_set = 0; -+ -+ mode = &phy_info->modes[*(phy_info->num_modes)]; -+ memset(mode, 0, sizeof(*mode)); -+ *(phy_info->num_modes) += 1; -+ -+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), -+ nla_len(nl_band), NULL); -+ -+ if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { -+ mode->ht_capab = nla_get_u16( -+ tb_band[NL80211_BAND_ATTR_HT_CAPA]); -+ } -+ -+ if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { -+ mode->a_mpdu_params |= nla_get_u8( -+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) & -+ 0x03; -+ } -+ -+ if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { -+ mode->a_mpdu_params |= nla_get_u8( -+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) << -+ 2; -+ } -+ -+ if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && -+ nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) { -+ u8 *mcs; -+ mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); -+ os_memcpy(mode->mcs_set, mcs, 16); -+ } -+ -+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { -+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), -+ nla_len(nl_freq), freq_policy); -+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) -+ continue; -+ mode->num_channels++; -+ } -+ -+ mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data)); -+ if (!mode->channels) -+ return NL_SKIP; -+ -+ idx = 0; -+ -+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { -+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), -+ nla_len(nl_freq), freq_policy); -+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) -+ continue; -+ -+ mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); -+ mode->channels[idx].flag = 0; -+ -+ if (!mode_is_set) { -+ /* crude heuristic */ -+ if (mode->channels[idx].freq < 4000) -+ mode->mode = HOSTAPD_MODE_IEEE80211B; -+ else -+ mode->mode = HOSTAPD_MODE_IEEE80211A; -+ mode_is_set = 1; -+ } -+ -+ /* crude heuristic */ -+ if (mode->channels[idx].freq < 4000) -+ if (mode->channels[idx].freq == 2484) -+ mode->channels[idx].chan = 14; -+ else -+ mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5; -+ else -+ mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000; -+ -+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) -+ mode->channels[idx].flag |= -+ HOSTAPD_CHAN_DISABLED; -+ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) -+ mode->channels[idx].flag |= -+ HOSTAPD_CHAN_PASSIVE_SCAN; -+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) -+ mode->channels[idx].flag |= -+ HOSTAPD_CHAN_NO_IBSS; -+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) -+ mode->channels[idx].flag |= -+ HOSTAPD_CHAN_RADAR; -+ -+ if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] && -+ !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) -+ mode->channels[idx].max_tx_power = -+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100; -+ -+ idx++; -+ } -+ -+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { -+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), -+ nla_len(nl_rate), rate_policy); -+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) -+ continue; -+ mode->num_rates++; -+ } -+ -+ mode->rates = os_zalloc(mode->num_rates * sizeof(int)); -+ if (!mode->rates) -+ return NL_SKIP; -+ -+ idx = 0; -+ -+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { -+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), -+ nla_len(nl_rate), rate_policy); -+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) -+ continue; -+ mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); -+ -+ /* crude heuristic */ -+ if (mode->mode == HOSTAPD_MODE_IEEE80211B && -+ mode->rates[idx] > 200) -+ mode->mode = HOSTAPD_MODE_IEEE80211G; -+ -+ idx++; -+ } -+ } -+ -+ return NL_SKIP; -+} -+ -+static struct hostapd_hw_modes * -+wpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes) -+{ -+ u16 m; -+ struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode; -+ int i, mode11g_idx = -1; -+ -+ /* If only 802.11g mode is included, use it to construct matching -+ * 802.11b mode data. */ -+ -+ for (m = 0; m < *num_modes; m++) { -+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211B) -+ return modes; /* 802.11b already included */ -+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211G) -+ mode11g_idx = m; -+ } -+ -+ if (mode11g_idx < 0) -+ return modes; /* 2.4 GHz band not supported at all */ -+ -+ nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes)); -+ if (nmodes == NULL) -+ return modes; /* Could not add 802.11b mode */ -+ -+ mode = &nmodes[*num_modes]; -+ os_memset(mode, 0, sizeof(*mode)); -+ (*num_modes)++; -+ modes = nmodes; -+ -+ mode->mode = HOSTAPD_MODE_IEEE80211B; -+ -+ mode11g = &modes[mode11g_idx]; -+ mode->num_channels = mode11g->num_channels; -+ mode->channels = os_malloc(mode11g->num_channels * -+ sizeof(struct hostapd_channel_data)); -+ if (mode->channels == NULL) { -+ (*num_modes)--; -+ return modes; /* Could not add 802.11b mode */ -+ } -+ os_memcpy(mode->channels, mode11g->channels, -+ mode11g->num_channels * sizeof(struct hostapd_channel_data)); -+ -+ mode->num_rates = 0; -+ mode->rates = os_malloc(4 * sizeof(int)); -+ if (mode->rates == NULL) { -+ os_free(mode->channels); -+ (*num_modes)--; -+ return modes; /* Could not add 802.11b mode */ -+ } -+ -+ for (i = 0; i < mode11g->num_rates; i++) { -+ if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 && -+ mode11g->rates[i] != 55 && mode11g->rates[i] != 110) -+ continue; -+ mode->rates[mode->num_rates] = mode11g->rates[i]; -+ mode->num_rates++; -+ if (mode->num_rates == 4) -+ break; -+ } -+ -+ if (mode->num_rates == 0) { -+ os_free(mode->channels); -+ os_free(mode->rates); -+ (*num_modes)--; -+ return modes; /* No 802.11b rates */ -+ } -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g " -+ "information"); -+ -+ return modes; -+} -+ -+ -+static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start, -+ int end) -+{ -+ int c; -+ -+ for (c = 0; c < mode->num_channels; c++) { -+ struct hostapd_channel_data *chan = &mode->channels[c]; -+ if (chan->freq - 10 >= start && chan->freq + 10 <= end) -+ chan->flag |= HOSTAPD_CHAN_HT40; -+ } -+} -+ -+ -+static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start, -+ int end) -+{ -+ int c; -+ -+ for (c = 0; c < mode->num_channels; c++) { -+ struct hostapd_channel_data *chan = &mode->channels[c]; -+ if (!(chan->flag & HOSTAPD_CHAN_HT40)) -+ continue; -+ if (chan->freq - 30 >= start && chan->freq - 10 <= end) -+ chan->flag |= HOSTAPD_CHAN_HT40MINUS; -+ if (chan->freq + 10 >= start && chan->freq + 30 <= end) -+ chan->flag |= HOSTAPD_CHAN_HT40PLUS; -+ } -+} -+ -+ -+static void nl80211_reg_rule_ht40(struct nlattr *tb[], -+ struct phy_info_arg *results) -+{ -+ u32 start, end, max_bw; -+ u16 m; -+ -+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || -+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || -+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) -+ return; -+ -+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; -+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; -+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz", -+ start, end, max_bw); -+ if (max_bw < 40) -+ return; -+ -+ for (m = 0; m < *results->num_modes; m++) { -+ if (!(results->modes[m].ht_capab & -+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) -+ continue; -+ nl80211_set_ht40_mode(&results->modes[m], start, end); -+ } -+} -+ -+ -+static void nl80211_reg_rule_sec(struct nlattr *tb[], -+ struct phy_info_arg *results) -+{ -+ u32 start, end, max_bw; -+ u16 m; -+ -+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL || -+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL || -+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL) -+ return; -+ -+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; -+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; -+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; -+ -+ if (max_bw < 20) -+ return; -+ -+ for (m = 0; m < *results->num_modes; m++) { -+ if (!(results->modes[m].ht_capab & -+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) -+ continue; -+ nl80211_set_ht40_mode_sec(&results->modes[m], start, end); -+ } -+} -+ -+ -+static int nl80211_get_reg(struct nl_msg *msg, void *arg) -+{ -+ struct phy_info_arg *results = arg; -+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct nlattr *nl_rule; -+ struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1]; -+ int rem_rule; -+ static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { -+ [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, -+ [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, -+ [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, -+ [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, -+ [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, -+ [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, -+ }; -+ -+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ if (!tb_msg[NL80211_ATTR_REG_ALPHA2] || -+ !tb_msg[NL80211_ATTR_REG_RULES]) { -+ wpa_printf(MSG_DEBUG, "nl80211: No regulatory information " -+ "available"); -+ return NL_SKIP; -+ } -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s", -+ (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2])); -+ -+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) -+ { -+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, -+ nla_data(nl_rule), nla_len(nl_rule), reg_policy); -+ nl80211_reg_rule_ht40(tb_rule, results); -+ } -+ -+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) -+ { -+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, -+ nla_data(nl_rule), nla_len(nl_rule), reg_policy); -+ nl80211_reg_rule_sec(tb_rule, results); -+ } -+ -+ return NL_SKIP; -+} -+ -+ -+static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv, -+ struct phy_info_arg *results) -+{ -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_REG, 0); -+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results); -+} -+ -+ -+static struct hostapd_hw_modes * -+wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ struct phy_info_arg result = { -+ .num_modes = num_modes, -+ .modes = NULL, -+ }; -+ -+ *num_modes = 0; -+ *flags = 0; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return NULL; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_WIPHY, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ -+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) { -+ nl80211_set_ht40_flags(drv, &result); -+ return wpa_driver_nl80211_add_11b(result.modes, num_modes); -+ } -+ nla_put_failure: -+ return NULL; -+} -+ -+ -+static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv, -+ const void *data, size_t len, -+ int encrypt) -+{ -+ __u8 rtap_hdr[] = { -+ 0x00, 0x00, /* radiotap version */ -+ 0x0e, 0x00, /* radiotap length */ -+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */ -+ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */ -+ 0x00, /* padding */ -+ 0x00, 0x00, /* RX and TX flags to indicate that */ -+ 0x00, 0x00, /* this is the injected frame directly */ -+ }; -+ struct iovec iov[2] = { -+ { -+ .iov_base = &rtap_hdr, -+ .iov_len = sizeof(rtap_hdr), -+ }, -+ { -+ .iov_base = (void *) data, -+ .iov_len = len, -+ } -+ }; -+ struct msghdr msg = { -+ .msg_name = NULL, -+ .msg_namelen = 0, -+ .msg_iov = iov, -+ .msg_iovlen = 2, -+ .msg_control = NULL, -+ .msg_controllen = 0, -+ .msg_flags = 0, -+ }; -+ int res; -+ -+ if (encrypt) -+ rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP; -+ -+ res = sendmsg(drv->monitor_sock, &msg, 0); -+ if (res < 0) { -+ wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno)); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data, -+ size_t data_len) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct ieee80211_mgmt *mgmt; -+ int encrypt = 1; -+ u16 fc; -+ -+ mgmt = (struct ieee80211_mgmt *) data; -+ fc = le_to_host16(mgmt->frame_control); -+ -+ if (drv->nlmode == NL80211_IFTYPE_STATION && -+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && -+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { -+ /* -+ * The use of last_mgmt_freq is a bit of a hack, -+ * but it works due to the single-threaded nature -+ * of wpa_supplicant. -+ */ -+ return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0, -+ data, data_len, NULL); -+ } -+ -+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && -+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { -+ /* -+ * Only one of the authentication frame types is encrypted. -+ * In order for static WEP encryption to work properly (i.e., -+ * to not encrypt the frame), we need to tell mac80211 about -+ * the frames that must not be encrypted. -+ */ -+ u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); -+ u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); -+ if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3) -+ encrypt = 0; -+ } -+ -+ return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); -+} -+ -+ -+static int wpa_driver_nl80211_set_beacon(void *priv, -+ const u8 *head, size_t head_len, -+ const u8 *tail, size_t tail_len, -+ int dtim_period, int beacon_int) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ u8 cmd = NL80211_CMD_NEW_BEACON; -+ int ret; -+ int beacon_set; -+ int ifindex = if_nametoindex(bss->ifname); -+ -+ beacon_set = bss->beacon_set; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)", -+ beacon_set); -+ if (beacon_set) -+ cmd = NL80211_CMD_SET_BEACON; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, cmd, 0); -+ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); -+ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); -+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int); -+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", -+ ret, strerror(-ret)); -+ } else { -+ bss->beacon_set = 1; -+ } -+ return ret; -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv, -+ int freq, int ht_enabled, -+ int sec_channel_offset) -+{ -+ struct nl_msg *msg; -+ int ret; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_SET_WIPHY, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); -+ if (ht_enabled) { -+ switch (sec_channel_offset) { -+ case -1: -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, -+ NL80211_CHAN_HT40MINUS); -+ break; -+ case 1: -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, -+ NL80211_CHAN_HT40PLUS); -+ break; -+ default: -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, -+ NL80211_CHAN_HT20); -+ break; -+ } -+ } -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret == 0) -+ return 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): " -+ "%d (%s)", freq, ret, strerror(-ret)); -+nla_put_failure: -+ return -1; -+} -+ -+ -+static int wpa_driver_nl80211_sta_add(void *priv, -+ struct hostapd_sta_add_params *params) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret = -ENOBUFS; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_NEW_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr); -+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid); -+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len, -+ params->supp_rates); -+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, -+ params->listen_interval); -+ if (params->ht_capabilities) { -+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, -+ sizeof(*params->ht_capabilities), -+ params->ht_capabilities); -+ } -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret) -+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION " -+ "result: %d (%s)", ret, strerror(-ret)); -+ if (ret == -EEXIST) -+ ret = 0; -+ nla_put_failure: -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_DEL_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(bss->ifname)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret == -ENOENT) -+ return 0; -+ return ret; -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, -+ int ifidx) -+{ -+ struct nl_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx); -+ -+#ifdef HOSTAPD -+ /* stop listening for EAPOL on this interface */ -+ del_ifidx(drv, ifidx); -+#endif /* HOSTAPD */ -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ goto nla_put_failure; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_DEL_INTERFACE, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx); -+ -+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) -+ return; -+ nla_put_failure: -+ wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); -+} -+ -+ -+static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, -+ const char *ifname, -+ enum nl80211_iftype iftype, -+ const u8 *addr, int wds) -+{ -+ struct nl_msg *msg, *flags = NULL; -+ int ifidx; -+ int ret = -ENOBUFS; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_NEW_INTERFACE, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); -+ -+ if (iftype == NL80211_IFTYPE_MONITOR) { -+ int err; -+ -+ flags = nlmsg_alloc(); -+ if (!flags) -+ goto nla_put_failure; -+ -+ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES); -+ -+ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); -+ -+ nlmsg_free(flags); -+ -+ if (err) -+ goto nla_put_failure; -+ } else if (wds) { -+ NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds); -+ } -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret) { -+ nla_put_failure: -+ wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)", -+ ifname, ret, strerror(-ret)); -+ return ret; -+ } -+ -+ ifidx = if_nametoindex(ifname); -+ wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d", -+ ifname, ifidx); -+ -+ if (ifidx <= 0) -+ return -1; -+ -+#ifdef HOSTAPD -+ /* start listening for EAPOL on this interface */ -+ add_ifidx(drv, ifidx); -+#endif /* HOSTAPD */ -+ -+ if (addr && iftype != NL80211_IFTYPE_MONITOR && -+ linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) { -+ nl80211_remove_iface(drv, ifidx); -+ return -1; -+ } -+ -+ return ifidx; -+} -+ -+ -+static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, -+ const char *ifname, enum nl80211_iftype iftype, -+ const u8 *addr, int wds) -+{ -+ int ret; -+ -+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds); -+ -+ /* if error occured and interface exists already */ -+ if (ret == -ENFILE && if_nametoindex(ifname)) { -+ wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname); -+ -+ /* Try to remove the interface that was already there. */ -+ nl80211_remove_iface(drv, if_nametoindex(ifname)); -+ -+ /* Try to create the interface again */ -+ ret = nl80211_create_iface_once(drv, ifname, iftype, addr, -+ wds); -+ } -+ -+ if (ret >= 0 && drv->disable_11b_rates) -+ nl80211_disable_11b_rates(drv, ret, 1); -+ -+ return ret; -+} -+ -+ -+static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok) -+{ -+ struct ieee80211_hdr *hdr; -+ u16 fc; -+ union wpa_event_data event; -+ -+ hdr = (struct ieee80211_hdr *) buf; -+ fc = le_to_host16(hdr->frame_control); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.tx_status.type = WLAN_FC_GET_TYPE(fc); -+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc); -+ event.tx_status.dst = hdr->addr1; -+ event.tx_status.data = buf; -+ event.tx_status.data_len = len; -+ event.tx_status.ack = ok; -+ wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event); -+} -+ -+ -+static void from_unknown_sta(struct wpa_driver_nl80211_data *drv, -+ u8 *buf, size_t len) -+{ -+ union wpa_event_data event; -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_from_unknown.frame = buf; -+ event.rx_from_unknown.len = len; -+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event); -+} -+ -+ -+static void handle_frame(struct wpa_driver_nl80211_data *drv, -+ u8 *buf, size_t len, int datarate, int ssi_signal) -+{ -+ struct ieee80211_hdr *hdr; -+ u16 fc; -+ union wpa_event_data event; -+ -+ hdr = (struct ieee80211_hdr *) buf; -+ fc = le_to_host16(hdr->frame_control); -+ -+ switch (WLAN_FC_GET_TYPE(fc)) { -+ case WLAN_FC_TYPE_MGMT: -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_mgmt.frame = buf; -+ event.rx_mgmt.frame_len = len; -+ event.rx_mgmt.datarate = datarate; -+ event.rx_mgmt.ssi_signal = ssi_signal; -+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); -+ break; -+ case WLAN_FC_TYPE_CTRL: -+ /* can only get here with PS-Poll frames */ -+ wpa_printf(MSG_DEBUG, "CTRL"); -+ from_unknown_sta(drv, buf, len); -+ break; -+ case WLAN_FC_TYPE_DATA: -+ from_unknown_sta(drv, buf, len); -+ break; -+ } -+} -+ -+ -+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct wpa_driver_nl80211_data *drv = eloop_ctx; -+ int len; -+ unsigned char buf[3000]; -+ struct ieee80211_radiotap_iterator iter; -+ int ret; -+ int datarate = 0, ssi_signal = 0; -+ int injected = 0, failed = 0, rxflags = 0; -+ -+ len = recv(sock, buf, sizeof(buf), 0); -+ if (len < 0) { -+ perror("recv"); -+ return; -+ } -+ -+ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) { -+ printf("received invalid radiotap frame\n"); -+ return; -+ } -+ -+ while (1) { -+ ret = ieee80211_radiotap_iterator_next(&iter); -+ if (ret == -ENOENT) -+ break; -+ if (ret) { -+ printf("received invalid radiotap frame (%d)\n", ret); -+ return; -+ } -+ switch (iter.this_arg_index) { -+ case IEEE80211_RADIOTAP_FLAGS: -+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS) -+ len -= 4; -+ break; -+ case IEEE80211_RADIOTAP_RX_FLAGS: -+ rxflags = 1; -+ break; -+ case IEEE80211_RADIOTAP_TX_FLAGS: -+ injected = 1; -+ failed = le_to_host16((*(uint16_t *) iter.this_arg)) & -+ IEEE80211_RADIOTAP_F_TX_FAIL; -+ break; -+ case IEEE80211_RADIOTAP_DATA_RETRIES: -+ break; -+ case IEEE80211_RADIOTAP_CHANNEL: -+ /* TODO: convert from freq/flags to channel number */ -+ break; -+ case IEEE80211_RADIOTAP_RATE: -+ datarate = *iter.this_arg * 5; -+ break; -+ case IEEE80211_RADIOTAP_DB_ANTSIGNAL: -+ ssi_signal = *iter.this_arg; -+ break; -+ } -+ } -+ -+ if (rxflags && injected) -+ return; -+ -+ if (!injected) -+ handle_frame(drv, buf + iter.max_length, -+ len - iter.max_length, datarate, ssi_signal); -+ else -+ handle_tx_callback(drv->ctx, buf + iter.max_length, -+ len - iter.max_length, !failed); -+} -+ -+ -+/* -+ * we post-process the filter code later and rewrite -+ * this to the offset to the last instruction -+ */ -+#define PASS 0xFF -+#define FAIL 0xFE -+ -+static struct sock_filter msock_filter_insns[] = { -+ /* -+ * do a little-endian load of the radiotap length field -+ */ -+ /* load lower byte into A */ -+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2), -+ /* put it into X (== index register) */ -+ BPF_STMT(BPF_MISC| BPF_TAX, 0), -+ /* load upper byte into A */ -+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3), -+ /* left-shift it by 8 */ -+ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8), -+ /* or with X */ -+ BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0), -+ /* put result into X */ -+ BPF_STMT(BPF_MISC| BPF_TAX, 0), -+ -+ /* -+ * Allow management frames through, this also gives us those -+ * management frames that we sent ourselves with status -+ */ -+ /* load the lower byte of the IEEE 802.11 frame control field */ -+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), -+ /* mask off frame type and version */ -+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF), -+ /* accept frame if it's both 0, fall through otherwise */ -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0), -+ -+ /* -+ * TODO: add a bit to radiotap RX flags that indicates -+ * that the sending station is not associated, then -+ * add a filter here that filters on our DA and that flag -+ * to allow us to deauth frames to that bad station. -+ * -+ * For now allow all To DS data frames through. -+ */ -+ /* load the IEEE 802.11 frame control field */ -+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0), -+ /* mask off frame type, version and DS status */ -+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03), -+ /* accept frame if version 0, type 2 and To DS, fall through otherwise -+ */ -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0), -+ -+#if 0 -+ /* -+ * drop non-data frames -+ */ -+ /* load the lower byte of the frame control field */ -+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), -+ /* mask off QoS bit */ -+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c), -+ /* drop non-data frames */ -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL), -+#endif -+ /* load the upper byte of the frame control field */ -+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1), -+ /* mask off toDS/fromDS */ -+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03), -+ /* accept WDS frames */ -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0), -+ -+ /* -+ * add header length to index -+ */ -+ /* load the lower byte of the frame control field */ -+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), -+ /* mask off QoS bit */ -+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80), -+ /* right shift it by 6 to give 0 or 2 */ -+ BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6), -+ /* add data frame header length */ -+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24), -+ /* add index, was start of 802.11 header */ -+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0), -+ /* move to index, now start of LL header */ -+ BPF_STMT(BPF_MISC | BPF_TAX, 0), -+ -+ /* -+ * Accept empty data frames, we use those for -+ * polling activity. -+ */ -+ BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0), -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0), -+ -+ /* -+ * Accept EAPOL frames -+ */ -+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0), -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL), -+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4), -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL), -+ -+ /* keep these last two statements or change the code below */ -+ /* return 0 == "DROP" */ -+ BPF_STMT(BPF_RET | BPF_K, 0), -+ /* return ~0 == "keep all" */ -+ BPF_STMT(BPF_RET | BPF_K, ~0), -+}; -+ -+static struct sock_fprog msock_filter = { -+ .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]), -+ .filter = msock_filter_insns, -+}; -+ -+ -+static int add_monitor_filter(int s) -+{ -+ int idx; -+ -+ /* rewrite all PASS/FAIL jump offsets */ -+ for (idx = 0; idx < msock_filter.len; idx++) { -+ struct sock_filter *insn = &msock_filter_insns[idx]; -+ -+ if (BPF_CLASS(insn->code) == BPF_JMP) { -+ if (insn->code == (BPF_JMP|BPF_JA)) { -+ if (insn->k == PASS) -+ insn->k = msock_filter.len - idx - 2; -+ else if (insn->k == FAIL) -+ insn->k = msock_filter.len - idx - 3; -+ } -+ -+ if (insn->jt == PASS) -+ insn->jt = msock_filter.len - idx - 2; -+ else if (insn->jt == FAIL) -+ insn->jt = msock_filter.len - idx - 3; -+ -+ if (insn->jf == PASS) -+ insn->jf = msock_filter.len - idx - 2; -+ else if (insn->jf == FAIL) -+ insn->jf = msock_filter.len - idx - 3; -+ } -+ } -+ -+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, -+ &msock_filter, sizeof(msock_filter))) { -+ perror("SO_ATTACH_FILTER"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void nl80211_remove_monitor_interface( -+ struct wpa_driver_nl80211_data *drv) -+{ -+ if (drv->monitor_ifidx >= 0) { -+ nl80211_remove_iface(drv, drv->monitor_ifidx); -+ drv->monitor_ifidx = -1; -+ } -+ if (drv->monitor_sock >= 0) { -+ eloop_unregister_read_sock(drv->monitor_sock); -+ close(drv->monitor_sock); -+ drv->monitor_sock = -1; -+ } -+} -+ -+ -+static int -+nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) -+{ -+ char buf[IFNAMSIZ]; -+ struct sockaddr_ll ll; -+ int optval; -+ socklen_t optlen; -+ -+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); -+ buf[IFNAMSIZ - 1] = '\0'; -+ -+ drv->monitor_ifidx = -+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, -+ 0); -+ -+ if (drv->monitor_ifidx < 0) -+ return -1; -+ -+ if (linux_set_iface_flags(drv->ioctl_sock, buf, 1)) -+ goto error; -+ -+ memset(&ll, 0, sizeof(ll)); -+ ll.sll_family = AF_PACKET; -+ ll.sll_ifindex = drv->monitor_ifidx; -+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); -+ if (drv->monitor_sock < 0) { -+ perror("socket[PF_PACKET,SOCK_RAW]"); -+ goto error; -+ } -+ -+ if (add_monitor_filter(drv->monitor_sock)) { -+ wpa_printf(MSG_INFO, "Failed to set socket filter for monitor " -+ "interface; do filtering in user space"); -+ /* This works, but will cost in performance. */ -+ } -+ -+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) { -+ perror("monitor socket bind"); -+ goto error; -+ } -+ -+ optlen = sizeof(optval); -+ optval = 20; -+ if (setsockopt -+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) { -+ perror("Failed to set socket priority"); -+ goto error; -+ } -+ -+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read, -+ drv, NULL)) { -+ printf("Could not register monitor read socket\n"); -+ goto error; -+ } -+ -+ return 0; -+ error: -+ nl80211_remove_monitor_interface(drv); -+ return -1; -+} -+ -+ -+static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -+ -+static int wpa_driver_nl80211_hapd_send_eapol( -+ void *priv, const u8 *addr, const u8 *data, -+ size_t data_len, int encrypt, const u8 *own_addr, u32 flags) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct ieee80211_hdr *hdr; -+ size_t len; -+ u8 *pos; -+ int res; -+ int qos = flags & WPA_STA_WMM; -+ -+ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 + -+ data_len; -+ hdr = os_zalloc(len); -+ if (hdr == NULL) { -+ printf("malloc() failed for i802_send_data(len=%lu)\n", -+ (unsigned long) len); -+ return -1; -+ } -+ -+ hdr->frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA); -+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS); -+ if (encrypt) -+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); -+ if (qos) { -+ hdr->frame_control |= -+ host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4); -+ } -+ -+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN); -+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); -+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); -+ pos = (u8 *) (hdr + 1); -+ -+ if (qos) { -+ /* add an empty QoS header if needed */ -+ pos[0] = 0; -+ pos[1] = 0; -+ pos += 2; -+ } -+ -+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); -+ pos += sizeof(rfc1042_header); -+ WPA_PUT_BE16(pos, ETH_P_PAE); -+ pos += 2; -+ memcpy(pos, data, data_len); -+ -+ res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt); -+ if (res < 0) { -+ wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " -+ "failed: %d (%s)", -+ (unsigned long) len, errno, strerror(errno)); -+ } -+ os_free(hdr); -+ -+ return res; -+} -+ -+ -+static u32 sta_flags_nl80211(int flags) -+{ -+ u32 f = 0; -+ -+ if (flags & WPA_STA_AUTHORIZED) -+ f |= BIT(NL80211_STA_FLAG_AUTHORIZED); -+ if (flags & WPA_STA_WMM) -+ f |= BIT(NL80211_STA_FLAG_WME); -+ if (flags & WPA_STA_SHORT_PREAMBLE) -+ f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); -+ if (flags & WPA_STA_MFP) -+ f |= BIT(NL80211_STA_FLAG_MFP); -+ -+ return f; -+} -+ -+ -+static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, -+ int total_flags, -+ int flags_or, int flags_and) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg, *flags = NULL; -+ struct nl80211_sta_flag_update upd; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ flags = nlmsg_alloc(); -+ if (!flags) { -+ nlmsg_free(msg); -+ return -ENOMEM; -+ } -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(bss->ifname)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ -+ /* -+ * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This -+ * can be removed eventually. -+ */ -+ if (total_flags & WPA_STA_AUTHORIZED) -+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED); -+ -+ if (total_flags & WPA_STA_WMM) -+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME); -+ -+ if (total_flags & WPA_STA_SHORT_PREAMBLE) -+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE); -+ -+ if (total_flags & WPA_STA_MFP) -+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP); -+ -+ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags)) -+ goto nla_put_failure; -+ -+ os_memset(&upd, 0, sizeof(upd)); -+ upd.mask = sta_flags_nl80211(flags_or | ~flags_and); -+ upd.set = sta_flags_nl80211(flags_or); -+ NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); -+ -+ nlmsg_free(flags); -+ -+ return send_and_recv_msgs(drv, msg, NULL, NULL); -+ nla_put_failure: -+ nlmsg_free(flags); -+ return -ENOBUFS; -+} -+ -+ -+static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, -+ struct wpa_driver_associate_params *params) -+{ -+ if (params->p2p) -+ wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P " -+ "group (GO)"); -+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) || -+ wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) { -+ nl80211_remove_monitor_interface(drv); -+ return -1; -+ } -+ -+ /* TODO: setup monitor interface (and add code somewhere to remove this -+ * when AP mode is stopped; associate with mode != 2 or drv_deinit) */ -+ -+ return 0; -+} -+ -+ -+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv) -+{ -+ struct nl_msg *msg; -+ int ret = -1; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_LEAVE_IBSS, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ goto nla_put_failure; -+ } -+ -+ ret = 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully"); -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct nl_msg *msg; -+ int ret = -1; -+ int count = 0; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); -+ -+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) { -+ wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " -+ "IBSS mode"); -+ return -1; -+ } -+ -+retry: -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_JOIN_IBSS, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ -+ if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid)) -+ goto nla_put_failure; -+ -+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID", -+ params->ssid, params->ssid_len); -+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, -+ params->ssid); -+ os_memcpy(drv->ssid, params->ssid, params->ssid_len); -+ drv->ssid_len = params->ssid_len; -+ -+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); -+ -+ ret = nl80211_set_conn_keys(params, msg); -+ if (ret) -+ goto nla_put_failure; -+ -+ if (params->wpa_ie) { -+ wpa_hexdump(MSG_DEBUG, -+ " * Extra IEs for Beacon/Probe Response frames", -+ params->wpa_ie, params->wpa_ie_len); -+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, -+ params->wpa_ie); -+ } -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)", -+ ret, strerror(-ret)); -+ count++; -+ if (ret == -EALREADY && count == 1) { -+ wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after " -+ "forced leave"); -+ nl80211_leave_ibss(drv); -+ nlmsg_free(msg); -+ goto retry; -+ } -+ -+ goto nla_put_failure; -+ } -+ ret = 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully"); -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_connect( -+ struct wpa_driver_nl80211_data *drv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct nl_msg *msg; -+ enum nl80211_auth_type type; -+ int ret = 0; -+ int algs; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex); -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_CONNECT, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ if (params->bssid) { -+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, -+ MAC2STR(params->bssid)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); -+ } -+ if (params->freq) { -+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); -+ } -+ if (params->ssid) { -+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID", -+ params->ssid, params->ssid_len); -+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, -+ params->ssid); -+ if (params->ssid_len > sizeof(drv->ssid)) -+ goto nla_put_failure; -+ os_memcpy(drv->ssid, params->ssid, params->ssid_len); -+ drv->ssid_len = params->ssid_len; -+ } -+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); -+ if (params->wpa_ie) -+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, -+ params->wpa_ie); -+ -+ algs = 0; -+ if (params->auth_alg & WPA_AUTH_ALG_OPEN) -+ algs++; -+ if (params->auth_alg & WPA_AUTH_ALG_SHARED) -+ algs++; -+ if (params->auth_alg & WPA_AUTH_ALG_LEAP) -+ algs++; -+ if (algs > 1) { -+ wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " -+ "selection"); -+ goto skip_auth_type; -+ } -+ -+ if (params->auth_alg & WPA_AUTH_ALG_OPEN) -+ type = NL80211_AUTHTYPE_OPEN_SYSTEM; -+ else if (params->auth_alg & WPA_AUTH_ALG_SHARED) -+ type = NL80211_AUTHTYPE_SHARED_KEY; -+ else if (params->auth_alg & WPA_AUTH_ALG_LEAP) -+ type = NL80211_AUTHTYPE_NETWORK_EAP; -+ else if (params->auth_alg & WPA_AUTH_ALG_FT) -+ type = NL80211_AUTHTYPE_FT; -+ else -+ goto nla_put_failure; -+ -+ wpa_printf(MSG_DEBUG, " * Auth Type %d", type); -+ NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type); -+ -+skip_auth_type: -+ if (params->wpa_ie && params->wpa_ie_len) { -+ enum nl80211_wpa_versions ver; -+ -+ if (params->wpa_ie[0] == WLAN_EID_RSN) -+ ver = NL80211_WPA_VERSION_2; -+ else -+ ver = NL80211_WPA_VERSION_1; -+ -+ wpa_printf(MSG_DEBUG, " * WPA Version %d", ver); -+ NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver); -+ } -+ -+ if (params->pairwise_suite != CIPHER_NONE) { -+ int cipher; -+ -+ switch (params->pairwise_suite) { -+ case CIPHER_WEP40: -+ cipher = WLAN_CIPHER_SUITE_WEP40; -+ break; -+ case CIPHER_WEP104: -+ cipher = WLAN_CIPHER_SUITE_WEP104; -+ break; -+ case CIPHER_CCMP: -+ cipher = WLAN_CIPHER_SUITE_CCMP; -+ break; -+ case CIPHER_TKIP: -+ default: -+ cipher = WLAN_CIPHER_SUITE_TKIP; -+ break; -+ } -+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); -+ } -+ -+ if (params->group_suite != CIPHER_NONE) { -+ int cipher; -+ -+ switch (params->group_suite) { -+ case CIPHER_WEP40: -+ cipher = WLAN_CIPHER_SUITE_WEP40; -+ break; -+ case CIPHER_WEP104: -+ cipher = WLAN_CIPHER_SUITE_WEP104; -+ break; -+ case CIPHER_CCMP: -+ cipher = WLAN_CIPHER_SUITE_CCMP; -+ break; -+ case CIPHER_TKIP: -+ default: -+ cipher = WLAN_CIPHER_SUITE_TKIP; -+ break; -+ } -+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); -+ } -+ -+ if (params->key_mgmt_suite == KEY_MGMT_802_1X || -+ params->key_mgmt_suite == KEY_MGMT_PSK) { -+ int mgmt = WLAN_AKM_SUITE_PSK; -+ -+ switch (params->key_mgmt_suite) { -+ case KEY_MGMT_802_1X: -+ mgmt = WLAN_AKM_SUITE_8021X; -+ break; -+ case KEY_MGMT_PSK: -+ default: -+ mgmt = WLAN_AKM_SUITE_PSK; -+ break; -+ } -+ NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt); -+ } -+ -+ ret = nl80211_set_conn_keys(params, msg); -+ if (ret) -+ goto nla_put_failure; -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ goto nla_put_failure; -+ } -+ ret = 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully"); -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+ -+} -+ -+ -+static int wpa_driver_nl80211_associate( -+ void *priv, struct wpa_driver_associate_params *params) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ret = -1; -+ struct nl_msg *msg; -+ -+ if (params->mode == IEEE80211_MODE_AP) -+ return wpa_driver_nl80211_ap(drv, params); -+ -+ if (params->mode == IEEE80211_MODE_IBSS) -+ return wpa_driver_nl80211_ibss(drv, params); -+ -+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { -+ if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0) -+ return -1; -+ return wpa_driver_nl80211_connect(drv, params); -+ } -+ -+ drv->associated = 0; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)", -+ drv->ifindex); -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_ASSOCIATE, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ if (params->bssid) { -+ wpa_printf(MSG_DEBUG, " * bssid=" MACSTR, -+ MAC2STR(params->bssid)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid); -+ } -+ if (params->freq) { -+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); -+ drv->assoc_freq = params->freq; -+ } else -+ drv->assoc_freq = 0; -+ if (params->ssid) { -+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID", -+ params->ssid, params->ssid_len); -+ NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, -+ params->ssid); -+ if (params->ssid_len > sizeof(drv->ssid)) -+ goto nla_put_failure; -+ os_memcpy(drv->ssid, params->ssid, params->ssid_len); -+ drv->ssid_len = params->ssid_len; -+ } -+ wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); -+ if (params->wpa_ie) -+ NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len, -+ params->wpa_ie); -+ -+ if (params->pairwise_suite != CIPHER_NONE) { -+ int cipher; -+ -+ switch (params->pairwise_suite) { -+ case CIPHER_WEP40: -+ cipher = WLAN_CIPHER_SUITE_WEP40; -+ break; -+ case CIPHER_WEP104: -+ cipher = WLAN_CIPHER_SUITE_WEP104; -+ break; -+ case CIPHER_CCMP: -+ cipher = WLAN_CIPHER_SUITE_CCMP; -+ break; -+ case CIPHER_TKIP: -+ default: -+ cipher = WLAN_CIPHER_SUITE_TKIP; -+ break; -+ } -+ wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher); -+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher); -+ } -+ -+ if (params->group_suite != CIPHER_NONE) { -+ int cipher; -+ -+ switch (params->group_suite) { -+ case CIPHER_WEP40: -+ cipher = WLAN_CIPHER_SUITE_WEP40; -+ break; -+ case CIPHER_WEP104: -+ cipher = WLAN_CIPHER_SUITE_WEP104; -+ break; -+ case CIPHER_CCMP: -+ cipher = WLAN_CIPHER_SUITE_CCMP; -+ break; -+ case CIPHER_TKIP: -+ default: -+ cipher = WLAN_CIPHER_SUITE_TKIP; -+ break; -+ } -+ wpa_printf(MSG_DEBUG, " * group=0x%x", cipher); -+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher); -+ } -+ -+#ifdef CONFIG_IEEE80211W -+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED) -+ NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED); -+#endif /* CONFIG_IEEE80211W */ -+ -+ NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT); -+ -+ if (params->prev_bssid) { -+ wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR, -+ MAC2STR(params->prev_bssid)); -+ NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN, -+ params->prev_bssid); -+ } -+ -+ if (params->p2p) -+ wpa_printf(MSG_DEBUG, " * P2P group"); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ nl80211_dump_scan(drv); -+ goto nla_put_failure; -+ } -+ ret = 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Association request send " -+ "successfully"); -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, -+ int ifindex, int mode) -+{ -+ struct nl_msg *msg; -+ int ret = -ENOBUFS; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_INTERFACE, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (!ret) -+ return 0; -+nla_put_failure: -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:" -+ " %d (%s)", ifindex, mode, ret, strerror(-ret)); -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_set_mode(void *priv, int mode) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ret = -1; -+ int nlmode; -+ int i; -+ -+ switch (mode) { -+ case 0: -+ nlmode = NL80211_IFTYPE_STATION; -+ break; -+ case 1: -+ nlmode = NL80211_IFTYPE_ADHOC; -+ break; -+ case 2: -+ nlmode = NL80211_IFTYPE_AP; -+ break; -+ default: -+ return -1; -+ } -+ -+ if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) { -+ drv->nlmode = nlmode; -+ ret = 0; -+ goto done; -+ } -+ -+ if (nlmode == drv->nlmode) { -+ wpa_printf(MSG_DEBUG, "nl80211: Interface already in " -+ "requested mode - ignore error"); -+ ret = 0; -+ goto done; /* Already in the requested mode */ -+ } -+ -+ /* mac80211 doesn't allow mode changes while the device is up, so -+ * take the device down, try to set the mode again, and bring the -+ * device back up. -+ */ -+ wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting " -+ "interface down"); -+ for (i = 0; i < 10; i++) { -+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) == -+ 0) { -+ /* Try to set the mode again while the interface is -+ * down */ -+ ret = nl80211_set_mode(drv, drv->ifindex, nlmode); -+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, -+ 1)) -+ ret = -1; -+ if (!ret) -+ break; -+ } else -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set " -+ "interface down"); -+ os_sleep(0, 100000); -+ } -+ -+ if (!ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while " -+ "interface is down"); -+ drv->nlmode = nlmode; -+ } -+ -+done: -+ if (!ret && nlmode == NL80211_IFTYPE_AP) { -+ /* Setup additional AP mode functionality if needed */ -+ if (drv->monitor_ifidx < 0 && -+ nl80211_create_monitor_interface(drv)) -+ return -1; -+ } else if (!ret && nlmode != NL80211_IFTYPE_AP) { -+ /* Remove additional AP mode functionality */ -+ nl80211_remove_monitor_interface(drv); -+ bss->beacon_set = 0; -+ } -+ -+ if (ret) -+ wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " -+ "from %d failed", nlmode, drv->nlmode); -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_get_capa(void *priv, -+ struct wpa_driver_capa *capa) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ if (!drv->has_capability) -+ return -1; -+ os_memcpy(capa, &drv->capa, sizeof(*capa)); -+ return 0; -+} -+ -+ -+static int wpa_driver_nl80211_set_operstate(void *priv, int state) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ -+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", -+ __func__, drv->operstate, state, state ? "UP" : "DORMANT"); -+ drv->operstate = state; -+ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, -+ state ? IF_OPER_UP : IF_OPER_DORMANT); -+} -+ -+ -+static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ struct nl80211_sta_flag_update upd; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(bss->ifname)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid); -+ -+ os_memset(&upd, 0, sizeof(upd)); -+ upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED); -+ if (authorized) -+ upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); -+ NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd); -+ -+ return send_and_recv_msgs(drv, msg, NULL, NULL); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+#ifdef HOSTAPD -+ -+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) -+{ -+ int i; -+ int *old; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d", -+ ifidx); -+ for (i = 0; i < drv->num_if_indices; i++) { -+ if (drv->if_indices[i] == 0) { -+ drv->if_indices[i] = ifidx; -+ return; -+ } -+ } -+ -+ if (drv->if_indices != drv->default_if_indices) -+ old = drv->if_indices; -+ else -+ old = NULL; -+ -+ drv->if_indices = os_realloc(old, -+ sizeof(int) * (drv->num_if_indices + 1)); -+ if (!drv->if_indices) { -+ if (!old) -+ drv->if_indices = drv->default_if_indices; -+ else -+ drv->if_indices = old; -+ wpa_printf(MSG_ERROR, "Failed to reallocate memory for " -+ "interfaces"); -+ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx); -+ return; -+ } else if (!old) -+ os_memcpy(drv->if_indices, drv->default_if_indices, -+ sizeof(drv->default_if_indices)); -+ drv->if_indices[drv->num_if_indices] = ifidx; -+ drv->num_if_indices++; -+} -+ -+ -+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) -+{ -+ int i; -+ -+ for (i = 0; i < drv->num_if_indices; i++) { -+ if (drv->if_indices[i] == ifidx) { -+ drv->if_indices[i] = 0; -+ break; -+ } -+ } -+} -+ -+ -+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx) -+{ -+ int i; -+ -+ for (i = 0; i < drv->num_if_indices; i++) -+ if (drv->if_indices[i] == ifidx) -+ return 1; -+ -+ return 0; -+} -+ -+ -+static inline int min_int(int a, int b) -+{ -+ if (a < b) -+ return a; -+ return b; -+} -+ -+ -+static int get_key_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ /* -+ * TODO: validate the key index and mac address! -+ * Otherwise, there's a race condition as soon as -+ * the kernel starts sending key notifications. -+ */ -+ -+ if (tb[NL80211_ATTR_KEY_SEQ]) -+ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]), -+ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6)); -+ return NL_SKIP; -+} -+ -+ -+static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, -+ int idx, u8 *seq) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_KEY, 0); -+ -+ if (addr) -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface)); -+ -+ memset(seq, 0, 6); -+ -+ return send_and_recv_msgs(drv, msg, get_key_handler, seq); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates, -+ int mode) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ u8 rates[NL80211_MAX_SUPP_RATES]; -+ u8 rates_len = 0; -+ int i; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_SET_BSS, 0); -+ -+ for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++) -+ rates[rates_len++] = basic_rates[i] / 5; -+ -+ NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); -+ -+ return send_and_recv_msgs(drv, msg, NULL, NULL); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+#endif /* HOSTAPD */ -+ -+ -+/* Set kernel driver on given frequency (MHz) */ -+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled, -+ freq->sec_channel_offset); -+} -+ -+ -+#ifdef HOSTAPD -+ -+static int i802_set_rts(void *priv, int rts) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret = -ENOBUFS; -+ u32 val; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ if (rts >= 2347) -+ val = (u32) -1; -+ else -+ val = rts; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_WIPHY, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (!ret) -+ return 0; -+nla_put_failure: -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: " -+ "%d (%s)", rts, ret, strerror(-ret)); -+ return ret; -+} -+ -+ -+static int i802_set_frag(void *priv, int frag) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret = -ENOBUFS; -+ u32 val; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ if (frag >= 2346) -+ val = (u32) -1; -+ else -+ val = frag; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_WIPHY, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (!ret) -+ return 0; -+nla_put_failure: -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold " -+ "%d: %d (%s)", frag, ret, strerror(-ret)); -+ return ret; -+} -+ -+ -+static int i802_flush(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_DEL_STATION, 0); -+ -+ /* -+ * XXX: FIX! this needs to flush all VLANs too -+ */ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(bss->ifname)); -+ -+ return send_and_recv_msgs(drv, msg, NULL, NULL); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int get_sta_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ struct hostap_sta_driver_data *data = arg; -+ struct nlattr *stats[NL80211_STA_INFO_MAX + 1]; -+ static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { -+ [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, -+ [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, -+ [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, -+ [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, -+ [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, -+ }; -+ -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ -+ /* -+ * TODO: validate the interface and mac address! -+ * Otherwise, there's a race condition as soon as -+ * the kernel starts sending station notifications. -+ */ -+ -+ if (!tb[NL80211_ATTR_STA_INFO]) { -+ wpa_printf(MSG_DEBUG, "sta stats missing!"); -+ return NL_SKIP; -+ } -+ if (nla_parse_nested(stats, NL80211_STA_INFO_MAX, -+ tb[NL80211_ATTR_STA_INFO], -+ stats_policy)) { -+ wpa_printf(MSG_DEBUG, "failed to parse nested attributes!"); -+ return NL_SKIP; -+ } -+ -+ if (stats[NL80211_STA_INFO_INACTIVE_TIME]) -+ data->inactive_msec = -+ nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]); -+ if (stats[NL80211_STA_INFO_RX_BYTES]) -+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]); -+ if (stats[NL80211_STA_INFO_TX_BYTES]) -+ data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]); -+ if (stats[NL80211_STA_INFO_RX_PACKETS]) -+ data->rx_packets = -+ nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); -+ if (stats[NL80211_STA_INFO_TX_PACKETS]) -+ data->tx_packets = -+ nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); -+ -+ return NL_SKIP; -+} -+ -+static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data, -+ const u8 *addr) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ -+ os_memset(data, 0, sizeof(*data)); -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_GET_STATION, 0); -+ -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); -+ -+ return send_and_recv_msgs(drv, msg, get_sta_handler, data); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int i802_set_tx_queue_params(void *priv, int queue, int aifs, -+ int cw_min, int cw_max, int burst_time) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ struct nlattr *txq, *params; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_WIPHY, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); -+ -+ txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS); -+ if (!txq) -+ goto nla_put_failure; -+ -+ /* We are only sending parameters for a single TXQ at a time */ -+ params = nla_nest_start(msg, 1); -+ if (!params) -+ goto nla_put_failure; -+ -+ switch (queue) { -+ case 0: -+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO); -+ break; -+ case 1: -+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI); -+ break; -+ case 2: -+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE); -+ break; -+ case 3: -+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK); -+ break; -+ } -+ /* Burst time is configured in units of 0.1 msec and TXOP parameter in -+ * 32 usec, so need to convert the value here. */ -+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32); -+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min); -+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max); -+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs); -+ -+ nla_nest_end(msg, params); -+ -+ nla_nest_end(msg, txq); -+ -+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) -+ return 0; -+ nla_put_failure: -+ return -1; -+} -+ -+ -+static int i802_set_bss(void *priv, int cts, int preamble, int slot, -+ int ht_opmode) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_SET_BSS, 0); -+ -+ if (cts >= 0) -+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); -+ if (preamble >= 0) -+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); -+ if (slot >= 0) -+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); -+ if (ht_opmode >= 0) -+ NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); -+ -+ return send_and_recv_msgs(drv, msg, NULL, NULL); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int i802_set_cts_protect(void *priv, int value) -+{ -+ return i802_set_bss(priv, value, -1, -1, -1); -+} -+ -+ -+static int i802_set_preamble(void *priv, int value) -+{ -+ return i802_set_bss(priv, -1, value, -1, -1); -+} -+ -+ -+static int i802_set_short_slot_time(void *priv, int value) -+{ -+ return i802_set_bss(priv, -1, -1, value, -1); -+} -+ -+ -+static int i802_set_sta_vlan(void *priv, const u8 *addr, -+ const char *ifname, int vlan_id) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret = -ENOBUFS; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_STATION, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, -+ if_nametoindex(bss->ifname)); -+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); -+ NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, -+ if_nametoindex(ifname)); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr=" -+ MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)", -+ MAC2STR(addr), ifname, vlan_id, ret, -+ strerror(-ret)); -+ } -+ nla_put_failure: -+ return ret; -+} -+ -+ -+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, -+ const char *bridge_ifname) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ char name[IFNAMSIZ + 1]; -+ -+ os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid); -+ wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR -+ " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name); -+ if (val) { -+ if (!if_nametoindex(name)) { -+ if (nl80211_create_iface(drv, name, -+ NL80211_IFTYPE_AP_VLAN, -+ NULL, 1) < 0) -+ return -1; -+ if (bridge_ifname && -+ linux_br_add_if(drv->ioctl_sock, bridge_ifname, -+ name) < 0) -+ return -1; -+ } -+ linux_set_iface_flags(drv->ioctl_sock, name, 1); -+ return i802_set_sta_vlan(priv, addr, name, 0); -+ } else { -+ i802_set_sta_vlan(priv, addr, bss->ifname, 0); -+ return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN, -+ name); -+ } -+} -+ -+ -+static int i802_set_ht_params(void *priv, const u8 *ht_capab, -+ size_t ht_capab_len, const u8 *ht_oper, -+ size_t ht_oper_len) -+{ -+ if (ht_oper_len >= 6) { -+ /* ht opmode uses 16bit in octet 5 & 6 */ -+ u16 ht_opmode = le_to_host16(((u16 *) ht_oper)[2]); -+ return i802_set_bss(priv, -1, -1, -1, ht_opmode); -+ } else -+ return -1; -+} -+ -+ -+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct wpa_driver_nl80211_data *drv = eloop_ctx; -+ struct sockaddr_ll lladdr; -+ unsigned char buf[3000]; -+ int len; -+ socklen_t fromlen = sizeof(lladdr); -+ -+ len = recvfrom(sock, buf, sizeof(buf), 0, -+ (struct sockaddr *)&lladdr, &fromlen); -+ if (len < 0) { -+ perror("recv"); -+ return; -+ } -+ -+ if (have_ifidx(drv, lladdr.sll_ifindex)) -+ drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len); -+} -+ -+ -+static int i802_get_inact_sec(void *priv, const u8 *addr) -+{ -+ struct hostap_sta_driver_data data; -+ int ret; -+ -+ data.inactive_msec = (unsigned long) -1; -+ ret = i802_read_sta_data(priv, &data, addr); -+ if (ret || data.inactive_msec == (unsigned long) -1) -+ return -1; -+ return data.inactive_msec / 1000; -+} -+ -+ -+static int i802_sta_clear_stats(void *priv, const u8 *addr) -+{ -+#if 0 -+ /* TODO */ -+#endif -+ return 0; -+} -+ -+#endif /* HOSTAPD */ -+ -+#if defined(HOSTAPD) || defined(CONFIG_AP) -+ -+static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason) -+{ -+ struct i802_bss *bss = priv; -+ struct ieee80211_mgmt mgmt; -+ -+ memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DEAUTH); -+ memcpy(mgmt.da, addr, ETH_ALEN); -+ memcpy(mgmt.sa, own_addr, ETH_ALEN); -+ memcpy(mgmt.bssid, own_addr, ETH_ALEN); -+ mgmt.u.deauth.reason_code = host_to_le16(reason); -+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, -+ IEEE80211_HDRLEN + -+ sizeof(mgmt.u.deauth)); -+} -+ -+ -+static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason) -+{ -+ struct i802_bss *bss = priv; -+ struct ieee80211_mgmt mgmt; -+ -+ memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DISASSOC); -+ memcpy(mgmt.da, addr, ETH_ALEN); -+ memcpy(mgmt.sa, own_addr, ETH_ALEN); -+ memcpy(mgmt.bssid, own_addr, ETH_ALEN); -+ mgmt.u.disassoc.reason_code = host_to_le16(reason); -+ return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, -+ IEEE80211_HDRLEN + -+ sizeof(mgmt.u.disassoc)); -+} -+ -+#endif /* HOSTAPD || CONFIG_AP */ -+ -+#ifdef HOSTAPD -+ -+static int i802_check_bridge(struct wpa_driver_nl80211_data *drv, -+ struct i802_bss *bss, -+ const char *brname, const char *ifname) -+{ -+ int ifindex; -+ char in_br[IFNAMSIZ]; -+ -+ os_strlcpy(bss->brname, brname, IFNAMSIZ); -+ ifindex = if_nametoindex(brname); -+ if (ifindex == 0) { -+ /* -+ * Bridge was configured, but the bridge device does -+ * not exist. Try to add it now. -+ */ -+ if (linux_br_add(drv->ioctl_sock, brname) < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the " -+ "bridge interface %s: %s", -+ brname, strerror(errno)); -+ return -1; -+ } -+ bss->added_bridge = 1; -+ add_ifidx(drv, if_nametoindex(brname)); -+ } -+ -+ if (linux_br_get(in_br, ifname) == 0) { -+ if (os_strcmp(in_br, brname) == 0) -+ return 0; /* already in the bridge */ -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from " -+ "bridge %s", ifname, in_br); -+ if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to " -+ "remove interface %s from bridge " -+ "%s: %s", -+ ifname, brname, strerror(errno)); -+ return -1; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s", -+ ifname, brname); -+ if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s " -+ "into bridge %s: %s", -+ ifname, brname, strerror(errno)); -+ return -1; -+ } -+ bss->added_if_into_bridge = 1; -+ -+ return 0; -+} -+ -+ -+static void *i802_init(struct hostapd_data *hapd, -+ struct wpa_init_params *params) -+{ -+ struct wpa_driver_nl80211_data *drv; -+ struct i802_bss *bss; -+ size_t i; -+ char brname[IFNAMSIZ]; -+ int ifindex, br_ifindex; -+ int br_added = 0; -+ -+ bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL); -+ if (bss == NULL) -+ return NULL; -+ -+ drv = bss->drv; -+ drv->nlmode = NL80211_IFTYPE_AP; -+ if (linux_br_get(brname, params->ifname) == 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s", -+ params->ifname, brname); -+ br_ifindex = if_nametoindex(brname); -+ } else { -+ brname[0] = '\0'; -+ br_ifindex = 0; -+ } -+ -+ drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int); -+ drv->if_indices = drv->default_if_indices; -+ for (i = 0; i < params->num_bridge; i++) { -+ if (params->bridge[i]) { -+ ifindex = if_nametoindex(params->bridge[i]); -+ if (ifindex) -+ add_ifidx(drv, ifindex); -+ if (ifindex == br_ifindex) -+ br_added = 1; -+ } -+ } -+ if (!br_added && br_ifindex && -+ (params->num_bridge == 0 || !params->bridge[0])) -+ add_ifidx(drv, br_ifindex); -+ -+ /* start listening for EAPOL on the default AP interface */ -+ add_ifidx(drv, drv->ifindex); -+ -+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0)) -+ goto failed; -+ -+ if (params->bssid) { -+ if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname, -+ params->bssid)) -+ goto failed; -+ } -+ -+ if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s " -+ "into AP mode", bss->ifname); -+ goto failed; -+ } -+ -+ if (params->num_bridge && params->bridge[0] && -+ i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) -+ goto failed; -+ -+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) -+ goto failed; -+ -+ drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); -+ if (drv->eapol_sock < 0) { -+ perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)"); -+ goto failed; -+ } -+ -+ if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL)) -+ { -+ printf("Could not register read socket for eapol\n"); -+ goto failed; -+ } -+ -+ if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr)) -+ goto failed; -+ -+ return bss; -+ -+failed: -+ nl80211_remove_monitor_interface(drv); -+ rfkill_deinit(drv->rfkill); -+ netlink_deinit(drv->netlink); -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ -+ genl_family_put(drv->nl80211); -+ nl_cache_free(drv->nl_cache); -+ nl80211_handle_destroy(drv->nl_handle); -+ nl_cb_put(drv->nl_cb); -+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event)); -+ -+ os_free(drv); -+ return NULL; -+} -+ -+ -+static void i802_deinit(void *priv) -+{ -+ wpa_driver_nl80211_deinit(priv); -+} -+ -+#endif /* HOSTAPD */ -+ -+ -+static enum nl80211_iftype wpa_driver_nl80211_if_type( -+ enum wpa_driver_if_type type) -+{ -+ switch (type) { -+ case WPA_IF_STATION: -+ return NL80211_IFTYPE_STATION; -+ case WPA_IF_P2P_CLIENT: -+ case WPA_IF_P2P_GROUP: -+ return NL80211_IFTYPE_P2P_CLIENT; -+ case WPA_IF_AP_VLAN: -+ return NL80211_IFTYPE_AP_VLAN; -+ case WPA_IF_AP_BSS: -+ return NL80211_IFTYPE_AP; -+ case WPA_IF_P2P_GO: -+ return NL80211_IFTYPE_P2P_GO; -+ } -+ return -1; -+} -+ -+ -+#ifdef CONFIG_P2P -+ -+static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr) -+{ -+ struct wpa_driver_nl80211_data *drv; -+ dl_list_for_each(drv, &global->interfaces, -+ struct wpa_driver_nl80211_data, list) { -+ if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0) -+ return 1; -+ } -+ return 0; -+} -+ -+ -+static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv, -+ u8 *new_addr) -+{ -+ unsigned int idx; -+ -+ if (!drv->global) -+ return -1; -+ -+ os_memcpy(new_addr, drv->addr, ETH_ALEN); -+ for (idx = 0; idx < 64; idx++) { -+ new_addr[0] = drv->addr[0] | 0x02; -+ new_addr[0] ^= idx << 2; -+ if (!nl80211_addr_in_use(drv->global, new_addr)) -+ break; -+ } -+ if (idx == 64) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address " -+ MACSTR, MAC2STR(new_addr)); -+ -+ return 0; -+} -+ -+#endif /* CONFIG_P2P */ -+ -+ -+static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, -+ const char *ifname, const u8 *addr, -+ void *bss_ctx, void **drv_priv, -+ char *force_ifname, u8 *if_addr, -+ const char *bridge) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ifidx; -+#ifdef HOSTAPD -+ struct i802_bss *new_bss = NULL; -+ -+ if (type == WPA_IF_AP_BSS) { -+ new_bss = os_zalloc(sizeof(*new_bss)); -+ if (new_bss == NULL) -+ return -1; -+ } -+#endif /* HOSTAPD */ -+ -+ if (addr) -+ os_memcpy(if_addr, addr, ETH_ALEN); -+ ifidx = nl80211_create_iface(drv, ifname, -+ wpa_driver_nl80211_if_type(type), addr, -+ 0); -+ if (ifidx < 0) { -+#ifdef HOSTAPD -+ os_free(new_bss); -+#endif /* HOSTAPD */ -+ return -1; -+ } -+ -+ if (!addr && -+ linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) { -+ nl80211_remove_iface(drv, ifidx); -+ return -1; -+ } -+ -+#ifdef CONFIG_P2P -+ if (!addr && -+ (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP || -+ type == WPA_IF_P2P_GO)) { -+ /* Enforce unique P2P Interface Address */ -+ u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN]; -+ -+ if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) -+ < 0 || -+ linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0) -+ { -+ nl80211_remove_iface(drv, ifidx); -+ return -1; -+ } -+ if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Allocate new address " -+ "for P2P group interface"); -+ if (nl80211_p2p_interface_addr(drv, new_addr) < 0) { -+ nl80211_remove_iface(drv, ifidx); -+ return -1; -+ } -+ if (linux_set_ifhwaddr(drv->ioctl_sock, ifname, -+ new_addr) < 0) { -+ nl80211_remove_iface(drv, ifidx); -+ return -1; -+ } -+ os_memcpy(if_addr, new_addr, ETH_ALEN); -+ } -+ } -+#endif /* CONFIG_P2P */ -+ -+#ifdef HOSTAPD -+ if (bridge && -+ i802_check_bridge(drv, new_bss, bridge, ifname) < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the new " -+ "interface %s to a bridge %s", ifname, bridge); -+ nl80211_remove_iface(drv, ifidx); -+ os_free(new_bss); -+ return -1; -+ } -+ -+ if (type == WPA_IF_AP_BSS) { -+ if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) { -+ nl80211_remove_iface(drv, ifidx); -+ os_free(new_bss); -+ return -1; -+ } -+ os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ); -+ new_bss->ifindex = ifidx; -+ new_bss->drv = drv; -+ new_bss->next = drv->first_bss.next; -+ drv->first_bss.next = new_bss; -+ if (drv_priv) -+ *drv_priv = new_bss; -+ } -+#endif /* HOSTAPD */ -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_nl80211_if_remove(void *priv, -+ enum wpa_driver_if_type type, -+ const char *ifname) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ifindex = if_nametoindex(ifname); -+ -+ wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d", -+ __func__, type, ifname, ifindex); -+ if (ifindex <= 0) -+ return -1; -+ -+#ifdef HOSTAPD -+ if (bss->added_if_into_bridge) { -+ if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname) -+ < 0) -+ wpa_printf(MSG_INFO, "nl80211: Failed to remove " -+ "interface %s from bridge %s: %s", -+ bss->ifname, bss->brname, strerror(errno)); -+ } -+ if (bss->added_bridge) { -+ if (linux_br_del(drv->ioctl_sock, bss->brname) < 0) -+ wpa_printf(MSG_INFO, "nl80211: Failed to remove " -+ "bridge %s: %s", -+ bss->brname, strerror(errno)); -+ } -+#endif /* HOSTAPD */ -+ -+ nl80211_remove_iface(drv, ifindex); -+ -+#ifdef HOSTAPD -+ if (type != WPA_IF_AP_BSS) -+ return 0; -+ -+ if (bss != &drv->first_bss) { -+ struct i802_bss *tbss; -+ -+ for (tbss = &drv->first_bss; tbss; tbss = tbss->next) { -+ if (tbss->next == bss) { -+ tbss->next = bss->next; -+ os_free(bss); -+ bss = NULL; -+ break; -+ } -+ } -+ if (bss) -+ wpa_printf(MSG_INFO, "nl80211: %s - could not find " -+ "BSS %p in the list", __func__, bss); -+ } -+#endif /* HOSTAPD */ -+ -+ return 0; -+} -+ -+ -+static int cookie_handler(struct nl_msg *msg, void *arg) -+{ -+ struct nlattr *tb[NL80211_ATTR_MAX + 1]; -+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); -+ u64 *cookie = arg; -+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), -+ genlmsg_attrlen(gnlh, 0), NULL); -+ if (tb[NL80211_ATTR_COOKIE]) -+ *cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); -+ return NL_SKIP; -+} -+ -+ -+static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv, -+ unsigned int freq, unsigned int wait, -+ const u8 *buf, size_t buf_len, -+ u64 *cookie_out) -+{ -+ struct nl_msg *msg; -+ u64 cookie; -+ int ret = -1; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_FRAME, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); -+ NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait); -+ NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); -+ NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf); -+ -+ cookie = 0; -+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ goto nla_put_failure; -+ } -+ wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; " -+ "cookie 0x%llx", (long long unsigned int) cookie); -+ -+ if (cookie_out) -+ *cookie_out = cookie; -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return ret; -+} -+ -+ -+static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq, -+ unsigned int wait_time, -+ const u8 *dst, const u8 *src, -+ const u8 *bssid, -+ const u8 *data, size_t data_len) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ret = -1; -+ u8 *buf; -+ struct ieee80211_hdr *hdr; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, " -+ "wait=%d ms)", drv->ifindex, wait_time); -+ -+ buf = os_zalloc(24 + data_len); -+ if (buf == NULL) -+ return ret; -+ os_memcpy(buf + 24, data, data_len); -+ hdr = (struct ieee80211_hdr *) buf; -+ hdr->frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); -+ os_memcpy(hdr->addr1, dst, ETH_ALEN); -+ os_memcpy(hdr->addr2, src, ETH_ALEN); -+ os_memcpy(hdr->addr3, bssid, ETH_ALEN); -+ -+ if (drv->nlmode == NL80211_IFTYPE_AP) -+ ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len); -+ else -+ ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf, -+ 24 + data_len, -+ &drv->send_action_cookie); -+ -+ os_free(buf); -+ return ret; -+} -+ -+ -+static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_FRAME_WAIT_CANCEL, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) -+ wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ -+ nla_put_failure: -+ nlmsg_free(msg); -+} -+ -+ -+static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, -+ unsigned int duration) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret; -+ u64 cookie; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_REMAIN_ON_CHANNEL, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); -+ NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); -+ -+ cookie = 0; -+ ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie); -+ if (ret == 0) { -+ wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie " -+ "0x%llx for freq=%u MHz duration=%u", -+ (long long unsigned int) cookie, freq, duration); -+ drv->remain_on_chan_cookie = cookie; -+ return 0; -+ } -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel " -+ "(freq=%d duration=%u): %d (%s)", -+ freq, duration, ret, strerror(-ret)); -+nla_put_failure: -+ return -1; -+} -+ -+ -+static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ int ret; -+ -+ if (!drv->pending_remain_on_chan) { -+ wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel " -+ "to cancel"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie " -+ "0x%llx", -+ (long long unsigned int) drv->remain_on_chan_cookie); -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); -+ NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ if (ret == 0) -+ return 0; -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: " -+ "%d (%s)", ret, strerror(-ret)); -+nla_put_failure: -+ return -1; -+} -+ -+ -+static int wpa_driver_nl80211_probe_req_report(void *priv, int report) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ -+ if (drv->nlmode != NL80211_IFTYPE_STATION) { -+ wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only " -+ "allowed in station mode (iftype=%d)", -+ drv->nlmode); -+ return -1; -+ } -+ -+ if (!report) { -+ if (drv->nl_handle_preq) { -+ eloop_unregister_read_sock( -+ nl_socket_get_fd(drv->nl_handle_preq)); -+ nl_cache_free(drv->nl_cache_preq); -+ nl80211_handle_destroy(drv->nl_handle_preq); -+ drv->nl_handle_preq = NULL; -+ } -+ return 0; -+ } -+ -+ if (drv->nl_handle_preq) { -+ wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting " -+ "already on!"); -+ return 0; -+ } -+ -+ drv->nl_handle_preq = nl80211_handle_alloc(drv->nl_cb); -+ if (drv->nl_handle_preq == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate " -+ "netlink callbacks (preq)"); -+ goto out_err1; -+ } -+ -+ if (genl_connect(drv->nl_handle_preq)) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to " -+ "generic netlink (preq)"); -+ goto out_err2; -+ return -1; -+ } -+ -+#ifdef CONFIG_LIBNL20 -+ if (genl_ctrl_alloc_cache(drv->nl_handle_preq, -+ &drv->nl_cache_preq) < 0) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " -+ "netlink cache (preq)"); -+ goto out_err2; -+ } -+#else /* CONFIG_LIBNL20 */ -+ drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->nl_handle_preq); -+ if (drv->nl_cache_preq == NULL) { -+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " -+ "netlink cache (preq)"); -+ goto out_err2; -+ } -+#endif /* CONFIG_LIBNL20 */ -+ -+ if (nl80211_register_frame(drv, drv->nl_handle_preq, -+ (WLAN_FC_TYPE_MGMT << 2) | -+ (WLAN_FC_STYPE_PROBE_REQ << 4), -+ NULL, 0) < 0) { -+ goto out_err3; -+ } -+ -+ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_preq), -+ wpa_driver_nl80211_event_receive, drv, -+ drv->nl_handle_preq); -+ -+ return 0; -+ -+ out_err3: -+ nl_cache_free(drv->nl_cache_preq); -+ out_err2: -+ nl80211_handle_destroy(drv->nl_handle_preq); -+ drv->nl_handle_preq = NULL; -+ out_err1: -+ return -1; -+} -+ -+ -+static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv, -+ int ifindex, int disabled) -+{ -+ struct nl_msg *msg; -+ struct nlattr *bands, *band; -+ int ret; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_SET_TX_BITRATE_MASK, 0); -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); -+ -+ bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES); -+ if (!bands) -+ goto nla_put_failure; -+ -+ /* -+ * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything -+ * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS -+ * rates. All 5 GHz rates are left enabled. -+ */ -+ band = nla_nest_start(msg, NL80211_BAND_2GHZ); -+ if (!band) -+ goto nla_put_failure; -+ NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8, -+ "\x0c\x12\x18\x24\x30\x48\x60\x6c"); -+ nla_nest_end(msg, band); -+ -+ nla_nest_end(msg, bands); -+ -+ ret = send_and_recv_msgs(drv, msg, NULL, NULL); -+ msg = NULL; -+ if (ret) { -+ wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d " -+ "(%s)", ret, strerror(-ret)); -+ } -+ -+ return ret; -+ -+nla_put_failure: -+ nlmsg_free(msg); -+ return -1; -+} -+ -+ -+static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ drv->disable_11b_rates = disabled; -+ return nl80211_disable_11b_rates(drv, drv->ifindex, disabled); -+} -+ -+ -+static int wpa_driver_nl80211_deinit_ap(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ if (drv->nlmode != NL80211_IFTYPE_AP) -+ return -1; -+ wpa_driver_nl80211_del_beacon(drv); -+ return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA); -+} -+ -+ -+static void wpa_driver_nl80211_resume(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) { -+ wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on " -+ "resume event"); -+ } -+} -+ -+ -+static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap, -+ const u8 *ies, size_t ies_len) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int ret; -+ u8 *data, *pos; -+ size_t data_len; -+ u8 own_addr[ETH_ALEN]; -+ -+ if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0) -+ return -1; -+ -+ if (action != 1) { -+ wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action " -+ "action %d", action); -+ return -1; -+ } -+ -+ /* -+ * Action frame payload: -+ * Category[1] = 6 (Fast BSS Transition) -+ * Action[1] = 1 (Fast BSS Transition Request) -+ * STA Address -+ * Target AP Address -+ * FT IEs -+ */ -+ -+ data_len = 2 + 2 * ETH_ALEN + ies_len; -+ data = os_malloc(data_len); -+ if (data == NULL) -+ return -1; -+ pos = data; -+ *pos++ = 0x06; /* FT Action category */ -+ *pos++ = action; -+ os_memcpy(pos, own_addr, ETH_ALEN); -+ pos += ETH_ALEN; -+ os_memcpy(pos, target_ap, ETH_ALEN); -+ pos += ETH_ALEN; -+ os_memcpy(pos, ies, ies_len); -+ -+ ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0, -+ drv->bssid, own_addr, drv->bssid, -+ data, data_len); -+ os_free(data); -+ -+ return ret; -+} -+ -+ -+static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg, *cqm = NULL; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d " -+ "hysteresis=%d", threshold, hysteresis); -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -1; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, -+ 0, NL80211_CMD_SET_CQM, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); -+ -+ cqm = nlmsg_alloc(); -+ if (cqm == NULL) -+ return -1; -+ -+ NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold); -+ NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis); -+ nla_put_nested(msg, NL80211_ATTR_CQM, cqm); -+ -+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0) -+ return 0; -+ msg = NULL; -+ -+nla_put_failure: -+ if (cqm) -+ nlmsg_free(cqm); -+ nlmsg_free(msg); -+ return -1; -+} -+ -+ -+static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ int res; -+ -+ os_memset(si, 0, sizeof(*si)); -+ res = nl80211_get_link_signal(drv, si); -+ if (res != 0) -+ return res; -+ -+ return nl80211_get_link_noise(drv, si); -+} -+ -+ -+static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, -+ int encrypt) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt); -+} -+ -+ -+static int nl80211_set_intra_bss(void *priv, int enabled) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ struct nl_msg *msg; -+ -+ msg = nlmsg_alloc(); -+ if (!msg) -+ return -ENOMEM; -+ -+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, -+ NL80211_CMD_SET_BSS, 0); -+ -+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname)); -+ NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, !enabled); -+ -+ return send_and_recv_msgs(drv, msg, NULL, NULL); -+ nla_put_failure: -+ return -ENOBUFS; -+} -+ -+ -+static int nl80211_set_param(void *priv, const char *param) -+{ -+ wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param); -+ if (param == NULL) -+ return 0; -+ -+#ifdef CONFIG_P2P -+ if (os_strstr(param, "use_p2p_group_interface=1")) { -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ -+ wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group " -+ "interface"); -+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; -+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P; -+ } -+#endif /* CONFIG_P2P */ -+ -+ return 0; -+} -+ -+ -+static void * nl80211_global_init(void) -+{ -+ struct nl80211_global *global; -+ global = os_zalloc(sizeof(*global)); -+ if (global == NULL) -+ return NULL; -+ dl_list_init(&global->interfaces); -+ return global; -+} -+ -+ -+static void nl80211_global_deinit(void *priv) -+{ -+ struct nl80211_global *global = priv; -+ if (global == NULL) -+ return; -+ if (!dl_list_empty(&global->interfaces)) { -+ wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at " -+ "nl80211_global_deinit", -+ dl_list_len(&global->interfaces)); -+ } -+ os_free(global); -+} -+ -+ -+static const char * nl80211_get_radio_name(void *priv) -+{ -+ struct i802_bss *bss = priv; -+ struct wpa_driver_nl80211_data *drv = bss->drv; -+ return drv->phyname; -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_nl80211_ops = { -+ .name = "nl80211", -+ .desc = "Linux nl80211/cfg80211", -+ .get_bssid = wpa_driver_nl80211_get_bssid, -+ .get_ssid = wpa_driver_nl80211_get_ssid, -+ .set_key = wpa_driver_nl80211_set_key, -+ .scan2 = wpa_driver_nl80211_scan, -+ .get_scan_results2 = wpa_driver_nl80211_get_scan_results, -+ .deauthenticate = wpa_driver_nl80211_deauthenticate, -+ .disassociate = wpa_driver_nl80211_disassociate, -+ .authenticate = wpa_driver_nl80211_authenticate, -+ .associate = wpa_driver_nl80211_associate, -+ .global_init = nl80211_global_init, -+ .global_deinit = nl80211_global_deinit, -+ .init2 = wpa_driver_nl80211_init, -+ .deinit = wpa_driver_nl80211_deinit, -+ .get_capa = wpa_driver_nl80211_get_capa, -+ .set_operstate = wpa_driver_nl80211_set_operstate, -+ .set_supp_port = wpa_driver_nl80211_set_supp_port, -+ .set_country = wpa_driver_nl80211_set_country, -+ .set_beacon = wpa_driver_nl80211_set_beacon, -+ .if_add = wpa_driver_nl80211_if_add, -+ .if_remove = wpa_driver_nl80211_if_remove, -+ .send_mlme = wpa_driver_nl80211_send_mlme, -+ .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data, -+ .sta_add = wpa_driver_nl80211_sta_add, -+ .sta_remove = wpa_driver_nl80211_sta_remove, -+ .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol, -+ .sta_set_flags = wpa_driver_nl80211_sta_set_flags, -+#ifdef HOSTAPD -+ .hapd_init = i802_init, -+ .hapd_deinit = i802_deinit, -+ .get_seqnum = i802_get_seqnum, -+ .flush = i802_flush, -+ .read_sta_data = i802_read_sta_data, -+ .get_inact_sec = i802_get_inact_sec, -+ .sta_clear_stats = i802_sta_clear_stats, -+ .set_rts = i802_set_rts, -+ .set_frag = i802_set_frag, -+ .set_rate_sets = i802_set_rate_sets, -+ .set_cts_protect = i802_set_cts_protect, -+ .set_preamble = i802_set_preamble, -+ .set_short_slot_time = i802_set_short_slot_time, -+ .set_tx_queue_params = i802_set_tx_queue_params, -+ .set_sta_vlan = i802_set_sta_vlan, -+ .set_wds_sta = i802_set_wds_sta, -+ .set_ht_params = i802_set_ht_params, -+#endif /* HOSTAPD */ -+#if defined(HOSTAPD) || defined(CONFIG_AP) -+ .sta_deauth = i802_sta_deauth, -+ .sta_disassoc = i802_sta_disassoc, -+#endif /* HOSTAPD || CONFIG_AP */ -+ .set_freq = i802_set_freq, -+ .send_action = wpa_driver_nl80211_send_action, -+ .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait, -+ .remain_on_channel = wpa_driver_nl80211_remain_on_channel, -+ .cancel_remain_on_channel = -+ wpa_driver_nl80211_cancel_remain_on_channel, -+ .probe_req_report = wpa_driver_nl80211_probe_req_report, -+ .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates, -+ .deinit_ap = wpa_driver_nl80211_deinit_ap, -+ .resume = wpa_driver_nl80211_resume, -+ .send_ft_action = nl80211_send_ft_action, -+ .signal_monitor = nl80211_signal_monitor, -+ .signal_poll = nl80211_signal_poll, -+ .send_frame = nl80211_send_frame, -+ .set_intra_bss = nl80211_set_intra_bss, -+ .set_param = nl80211_set_param, -+ .get_radio_name = nl80211_get_radio_name, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_none.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_none.c -new file mode 100644 -index 0000000000000..aaeacd66435dd ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_none.c -@@ -0,0 +1,99 @@ -+/* -+ * Driver interface for RADIUS server or WPS ER only (no driver) -+ * Copyright (c) 2008, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "driver.h" -+ -+ -+struct none_driver_data { -+ struct hostapd_data *hapd; -+ void *ctx; -+}; -+ -+ -+static void * none_driver_hapd_init(struct hostapd_data *hapd, -+ struct wpa_init_params *params) -+{ -+ struct none_driver_data *drv; -+ -+ drv = os_zalloc(sizeof(struct none_driver_data)); -+ if (drv == NULL) { -+ wpa_printf(MSG_ERROR, "Could not allocate memory for none " -+ "driver data"); -+ return NULL; -+ } -+ drv->hapd = hapd; -+ -+ return drv; -+} -+ -+ -+static void none_driver_hapd_deinit(void *priv) -+{ -+ struct none_driver_data *drv = priv; -+ -+ os_free(drv); -+} -+ -+ -+static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src, -+ u16 proto, const u8 *data, size_t data_len) -+{ -+ return 0; -+} -+ -+ -+static void * none_driver_init(void *ctx, const char *ifname) -+{ -+ struct none_driver_data *drv; -+ -+ drv = os_zalloc(sizeof(struct none_driver_data)); -+ if (drv == NULL) { -+ wpa_printf(MSG_ERROR, "Could not allocate memory for none " -+ "driver data"); -+ return NULL; -+ } -+ drv->ctx = ctx; -+ -+ return drv; -+} -+ -+ -+static void none_driver_deinit(void *priv) -+{ -+ struct none_driver_data *drv = priv; -+ -+ os_free(drv); -+} -+ -+ -+static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto, -+ const u8 *data, size_t data_len) -+{ -+ return -1; -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_none_ops = { -+ .name = "none", -+ .desc = "no driver (RADIUS server/WPS ER)", -+ .hapd_init = none_driver_hapd_init, -+ .hapd_deinit = none_driver_hapd_deinit, -+ .send_ether = none_driver_send_ether, -+ .init = none_driver_init, -+ .deinit = none_driver_deinit, -+ .send_eapol = none_driver_send_eapol, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_osx.m b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_osx.m -new file mode 100644 -index 0000000000000..69ca4b576c3c0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_osx.m -@@ -0,0 +1,459 @@ -+/* -+ * WPA Supplicant - Mac OS X Apple80211 driver interface -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#define Boolean __DummyBoolean -+#include -+#undef Boolean -+ -+#include "common.h" -+#include "driver.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+ -+#include "Apple80211.h" -+ -+struct wpa_driver_osx_data { -+ void *ctx; -+ WirelessRef wireless_ctx; -+ CFArrayRef scan_results; -+}; -+ -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+extern int wpa_debug_level; -+ -+static void dump_dict_cb(const void *key, const void *value, void *context) -+{ -+ if (MSG_DEBUG < wpa_debug_level) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "Key:"); -+ CFShow(key); -+ wpa_printf(MSG_DEBUG, "Value:"); -+ CFShow(value); -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title) -+{ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+ wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries", -+ title, (unsigned int) CFDictionaryGetCount(dict)); -+ CFDictionaryApplyFunction(dict, dump_dict_cb, NULL); -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+} -+ -+ -+static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_osx_data *drv = priv; -+ WirelessError err; -+ WirelessInfo info; -+ int len; -+ -+ err = WirelessGetInfo(drv->wireless_ctx, &info); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d", -+ (int) err); -+ return -1; -+ } -+ if (!info.power) { -+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off"); -+ return -1; -+ } -+ -+ for (len = 0; len < 32; len++) -+ if (info.ssid[len] == 0) -+ break; -+ -+ os_memcpy(ssid, info.ssid, len); -+ return len; -+} -+ -+ -+static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_osx_data *drv = priv; -+ WirelessError err; -+ WirelessInfo info; -+ -+ err = WirelessGetInfo(drv->wireless_ctx, &info); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d", -+ (int) err); -+ return -1; -+ } -+ if (!info.power) { -+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off"); -+ return -1; -+ } -+ -+ os_memcpy(bssid, info.bssID, ETH_ALEN); -+ return 0; -+} -+ -+ -+static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+} -+ -+ -+static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_osx_data *drv = priv; -+ WirelessError err; -+ const u8 *ssid = params->ssids[0].ssid; -+ size_t ssid_len = params->ssids[0].ssid_len; -+ -+ if (drv->scan_results) { -+ CFRelease(drv->scan_results); -+ drv->scan_results = NULL; -+ } -+ -+ if (ssid) { -+ CFStringRef data; -+ data = CFStringCreateWithBytes(kCFAllocatorDefault, -+ ssid, ssid_len, -+ kCFStringEncodingISOLatin1, -+ FALSE); -+ if (data == NULL) { -+ wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes " -+ "failed"); -+ return -1; -+ } -+ -+ err = WirelessDirectedScan(drv->wireless_ctx, -+ &drv->scan_results, 0, data); -+ CFRelease(data); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan " -+ "failed: 0x%08x", (unsigned int) err); -+ return -1; -+ } -+ } else { -+ err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: " -+ "0x%08x", (unsigned int) err); -+ return -1; -+ } -+ } -+ -+ eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv, -+ drv->ctx); -+ return 0; -+} -+ -+ -+static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res, -+ WirelessNetworkInfo *info) -+{ -+ struct wpa_scan_res *result, **tmp; -+ size_t extra_len; -+ u8 *pos; -+ -+ extra_len = 2 + info->ssid_len; -+ -+ result = os_zalloc(sizeof(*result) + extra_len); -+ if (result == NULL) -+ return; -+ os_memcpy(result->bssid, info->bssid, ETH_ALEN); -+ result->freq = 2407 + info->channel * 5; -+ //result->beacon_int =; -+ result->caps = info->capability; -+ //result->qual = info->signal; -+ result->noise = info->noise; -+ -+ pos = (u8 *)(result + 1); -+ -+ *pos++ = WLAN_EID_SSID; -+ *pos++ = info->ssid_len; -+ os_memcpy(pos, info->ssid, info->ssid_len); -+ pos += info->ssid_len; -+ -+ result->ie_len = pos - (u8 *)(result + 1); -+ -+ tmp = os_realloc(res->res, -+ (res->num + 1) * sizeof(struct wpa_scan_res *)); -+ if (tmp == NULL) { -+ os_free(result); -+ return; -+ } -+ tmp[res->num++] = result; -+ res->res = tmp; -+} -+ -+ -+static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv) -+{ -+ struct wpa_driver_osx_data *drv = priv; -+ struct wpa_scan_results *res; -+ size_t i, num; -+ -+ if (drv->scan_results == NULL) -+ return 0; -+ -+ num = CFArrayGetCount(drv->scan_results); -+ -+ res = os_zalloc(sizeof(*res)); -+ if (res == NULL) -+ return NULL; -+ -+ for (i = 0; i < num; i++) -+ wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *) -+ CFDataGetBytePtr(CFArrayGetValueAtIndex( -+ drv->scan_results, i))); -+ -+ return res; -+} -+ -+ -+static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_osx_data *drv = eloop_ctx; -+ u8 bssid[ETH_ALEN]; -+ CFDictionaryRef ai; -+ -+ if (wpa_driver_osx_get_bssid(drv, bssid) != 0) { -+ eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout, -+ drv, drv->ctx); -+ return; -+ } -+ -+ ai = WirelessGetAssociationInfo(drv->wireless_ctx); -+ if (ai) { -+ wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo"); -+ CFRelease(ai); -+ } else { -+ wpa_printf(MSG_DEBUG, "OSX: Failed to get association info"); -+ } -+ -+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL); -+} -+ -+ -+static int wpa_driver_osx_associate(void *priv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_osx_data *drv = priv; -+ WirelessError err; -+ CFDataRef ssid; -+ CFStringRef key; -+ int assoc_type; -+ -+ ssid = CFDataCreate(kCFAllocatorDefault, params->ssid, -+ params->ssid_len); -+ if (ssid == NULL) -+ return -1; -+ -+ /* TODO: support for WEP */ -+ if (params->key_mgmt_suite == KEY_MGMT_PSK) { -+ if (params->passphrase == NULL) -+ return -1; -+ key = CFStringCreateWithCString(kCFAllocatorDefault, -+ params->passphrase, -+ kCFStringEncodingISOLatin1); -+ if (key == NULL) { -+ CFRelease(ssid); -+ return -1; -+ } -+ } else -+ key = NULL; -+ -+ if (params->key_mgmt_suite == KEY_MGMT_NONE) -+ assoc_type = 0; -+ else -+ assoc_type = 4; -+ -+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)", -+ assoc_type, key); -+ err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key); -+ CFRelease(ssid); -+ if (key) -+ CFRelease(key); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x", -+ (unsigned int) err); -+ return -1; -+ } -+ -+ /* -+ * Driver is actually already associated; report association from an -+ * eloop callback. -+ */ -+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx); -+ eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv, -+ drv->ctx); -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_osx_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, const u8 *seq, -+ size_t seq_len, const u8 *key, -+ size_t key_len) -+{ -+ struct wpa_driver_osx_data *drv = priv; -+ WirelessError err; -+ -+ if (alg == WPA_ALG_WEP) { -+ err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len, -+ key); -+ if (err != 0) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: " -+ "0x%08x", (unsigned int) err); -+ return -1; -+ } -+ -+ return 0; -+ } -+ -+ if (alg == WPA_ALG_PMK) { -+ err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key); -+ if (err != 0) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: " -+ "0x%08x", (unsigned int) err); -+ return -1; -+ } -+ return 0; -+ } -+ -+ wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg); -+ return -1; -+} -+ -+ -+static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa) -+{ -+ os_memset(capa, 0, sizeof(*capa)); -+ -+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | -+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; -+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | -+ WPA_DRIVER_AUTH_LEAP; -+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; -+ -+ return 0; -+} -+ -+ -+static void * wpa_driver_osx_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_osx_data *drv; -+ WirelessError err; -+ u8 enabled, power; -+ -+ if (!WirelessIsAvailable()) { -+ wpa_printf(MSG_ERROR, "OSX: No wireless interface available"); -+ return NULL; -+ } -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->ctx = ctx; -+ err = WirelessAttach(&drv->wireless_ctx, 0); -+ if (err) { -+ wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d", -+ (int) err); -+ os_free(drv); -+ return NULL; -+ } -+ -+ err = WirelessGetEnabled(drv->wireless_ctx, &enabled); -+ if (err) -+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x", -+ (unsigned int) err); -+ err = WirelessGetPower(drv->wireless_ctx, &power); -+ if (err) -+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x", -+ (unsigned int) err); -+ -+ wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power); -+ -+ if (!enabled) { -+ err = WirelessSetEnabled(drv->wireless_ctx, 1); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:" -+ " 0x%08x", (unsigned int) err); -+ WirelessDetach(drv->wireless_ctx); -+ os_free(drv); -+ return NULL; -+ } -+ } -+ -+ if (!power) { -+ err = WirelessSetPower(drv->wireless_ctx, 1); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: " -+ "0x%08x", (unsigned int) err); -+ WirelessDetach(drv->wireless_ctx); -+ os_free(drv); -+ return NULL; -+ } -+ } -+ -+ return drv; -+} -+ -+ -+static void wpa_driver_osx_deinit(void *priv) -+{ -+ struct wpa_driver_osx_data *drv = priv; -+ WirelessError err; -+ -+ eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx); -+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx); -+ -+ err = WirelessSetPower(drv->wireless_ctx, 0); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: " -+ "0x%08x", (unsigned int) err); -+ } -+ -+ err = WirelessDetach(drv->wireless_ctx); -+ if (err) { -+ wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x", -+ (unsigned int) err); -+ } -+ -+ if (drv->scan_results) -+ CFRelease(drv->scan_results); -+ -+ os_free(drv); -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_osx_ops = { -+ .name = "osx", -+ .desc = "Mac OS X Apple80211 driver", -+ .get_ssid = wpa_driver_osx_get_ssid, -+ .get_bssid = wpa_driver_osx_get_bssid, -+ .init = wpa_driver_osx_init, -+ .deinit = wpa_driver_osx_deinit, -+ .scan2 = wpa_driver_osx_scan, -+ .get_scan_results2 = wpa_driver_osx_get_scan_results, -+ .associate = wpa_driver_osx_associate, -+ .set_key = wpa_driver_osx_set_key, -+ .get_capa = wpa_driver_osx_get_capa, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_privsep.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_privsep.c -new file mode 100644 -index 0000000000000..28485215e2b28 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_privsep.c -@@ -0,0 +1,758 @@ -+/* -+ * WPA Supplicant - privilege separated driver interface -+ * Copyright (c) 2007-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "driver.h" -+#include "eloop.h" -+#include "common/privsep_commands.h" -+ -+ -+struct wpa_driver_privsep_data { -+ void *ctx; -+ u8 own_addr[ETH_ALEN]; -+ int priv_socket; -+ char *own_socket_path; -+ int cmd_socket; -+ char *own_cmd_path; -+ struct sockaddr_un priv_addr; -+ char ifname[16]; -+}; -+ -+ -+static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd) -+{ -+ int res; -+ -+ res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0, -+ (struct sockaddr *) &drv->priv_addr, -+ sizeof(drv->priv_addr)); -+ if (res < 0) -+ perror("sendto"); -+ return res < 0 ? -1 : 0; -+} -+ -+ -+static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd, -+ const void *data, size_t data_len, -+ void *reply, size_t *reply_len) -+{ -+ struct msghdr msg; -+ struct iovec io[2]; -+ -+ io[0].iov_base = &cmd; -+ io[0].iov_len = sizeof(cmd); -+ io[1].iov_base = (u8 *) data; -+ io[1].iov_len = data_len; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ msg.msg_iov = io; -+ msg.msg_iovlen = data ? 2 : 1; -+ msg.msg_name = &drv->priv_addr; -+ msg.msg_namelen = sizeof(drv->priv_addr); -+ -+ if (sendmsg(drv->cmd_socket, &msg, 0) < 0) { -+ perror("sendmsg(cmd_socket)"); -+ return -1; -+ } -+ -+ if (reply) { -+ fd_set rfds; -+ struct timeval tv; -+ int res; -+ -+ FD_ZERO(&rfds); -+ FD_SET(drv->cmd_socket, &rfds); -+ tv.tv_sec = 5; -+ tv.tv_usec = 0; -+ res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv); -+ if (res < 0 && errno != EINTR) { -+ perror("select"); -+ return -1; -+ } -+ -+ if (FD_ISSET(drv->cmd_socket, &rfds)) { -+ res = recv(drv->cmd_socket, reply, *reply_len, 0); -+ if (res < 0) { -+ perror("recv"); -+ return -1; -+ } -+ *reply_len = res; -+ } else { -+ wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting " -+ "for reply (cmd=%d)", cmd); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_privsep_scan(void *priv, -+ struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ const u8 *ssid = params->ssids[0].ssid; -+ size_t ssid_len = params->ssids[0].ssid_len; -+ wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); -+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len, -+ NULL, NULL); -+} -+ -+ -+static struct wpa_scan_results * -+wpa_driver_privsep_get_scan_results2(void *priv) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ int res, num; -+ u8 *buf, *pos, *end; -+ size_t reply_len = 60000; -+ struct wpa_scan_results *results; -+ struct wpa_scan_res *r; -+ -+ buf = os_malloc(reply_len); -+ if (buf == NULL) -+ return NULL; -+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS, -+ NULL, 0, buf, &reply_len); -+ if (res < 0) { -+ os_free(buf); -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results", -+ (unsigned long) reply_len); -+ if (reply_len < sizeof(int)) { -+ wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu", -+ (unsigned long) reply_len); -+ os_free(buf); -+ return NULL; -+ } -+ -+ pos = buf; -+ end = buf + reply_len; -+ os_memcpy(&num, pos, sizeof(int)); -+ if (num < 0 || num > 1000) { -+ os_free(buf); -+ return NULL; -+ } -+ pos += sizeof(int); -+ -+ results = os_zalloc(sizeof(*results)); -+ if (results == NULL) { -+ os_free(buf); -+ return NULL; -+ } -+ -+ results->res = os_zalloc(num * sizeof(struct wpa_scan_res *)); -+ if (results->res == NULL) { -+ os_free(results); -+ os_free(buf); -+ return NULL; -+ } -+ -+ while (results->num < (size_t) num && pos + sizeof(int) < end) { -+ int len; -+ os_memcpy(&len, pos, sizeof(int)); -+ pos += sizeof(int); -+ if (len < 0 || len > 10000 || pos + len > end) -+ break; -+ -+ r = os_malloc(len); -+ if (r == NULL) -+ break; -+ os_memcpy(r, pos, len); -+ pos += len; -+ if (sizeof(*r) + r->ie_len > (size_t) len) { -+ os_free(r); -+ break; -+ } -+ -+ results->res[results->num++] = r; -+ } -+ -+ os_free(buf); -+ return results; -+} -+ -+ -+static int wpa_driver_privsep_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ struct privsep_cmd_set_key cmd; -+ -+ wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d", -+ __func__, priv, alg, key_idx, set_tx); -+ -+ os_memset(&cmd, 0, sizeof(cmd)); -+ cmd.alg = alg; -+ if (addr) -+ os_memcpy(cmd.addr, addr, ETH_ALEN); -+ else -+ os_memset(cmd.addr, 0xff, ETH_ALEN); -+ cmd.key_idx = key_idx; -+ cmd.set_tx = set_tx; -+ if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) { -+ os_memcpy(cmd.seq, seq, seq_len); -+ cmd.seq_len = seq_len; -+ } -+ if (key && key_len > 0 && key_len < sizeof(cmd.key)) { -+ os_memcpy(cmd.key, key, key_len); -+ cmd.key_len = key_len; -+ } -+ -+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd), -+ NULL, NULL); -+} -+ -+ -+static int wpa_driver_privsep_associate( -+ void *priv, struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ struct privsep_cmd_associate *data; -+ int res; -+ size_t buflen; -+ -+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " -+ "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", -+ __func__, priv, params->freq, params->pairwise_suite, -+ params->group_suite, params->key_mgmt_suite, -+ params->auth_alg, params->mode); -+ -+ buflen = sizeof(*data) + params->wpa_ie_len; -+ data = os_zalloc(buflen); -+ if (data == NULL) -+ return -1; -+ -+ if (params->bssid) -+ os_memcpy(data->bssid, params->bssid, ETH_ALEN); -+ os_memcpy(data->ssid, params->ssid, params->ssid_len); -+ data->ssid_len = params->ssid_len; -+ data->freq = params->freq; -+ data->pairwise_suite = params->pairwise_suite; -+ data->group_suite = params->group_suite; -+ data->key_mgmt_suite = params->key_mgmt_suite; -+ data->auth_alg = params->auth_alg; -+ data->mode = params->mode; -+ data->wpa_ie_len = params->wpa_ie_len; -+ if (params->wpa_ie) -+ os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len); -+ /* TODO: add support for other assoc parameters */ -+ -+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen, -+ NULL, NULL); -+ os_free(data); -+ -+ return res; -+} -+ -+ -+static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ int res; -+ size_t len = ETH_ALEN; -+ -+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len); -+ if (res < 0 || len != ETH_ALEN) -+ return -1; -+ return 0; -+} -+ -+ -+static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ int res, ssid_len; -+ u8 reply[sizeof(int) + 32]; -+ size_t len = sizeof(reply); -+ -+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len); -+ if (res < 0 || len < sizeof(int)) -+ return -1; -+ os_memcpy(&ssid_len, reply, sizeof(int)); -+ if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) { -+ wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply"); -+ return -1; -+ } -+ os_memcpy(ssid, &reply[sizeof(int)], ssid_len); -+ return ssid_len; -+} -+ -+ -+static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ //struct wpa_driver_privsep_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", -+ __func__, MAC2STR(addr), reason_code); -+ wpa_printf(MSG_DEBUG, "%s - TODO", __func__); -+ return 0; -+} -+ -+ -+static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ //struct wpa_driver_privsep_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", -+ __func__, MAC2STR(addr), reason_code); -+ wpa_printf(MSG_DEBUG, "%s - TODO", __func__); -+ return 0; -+} -+ -+ -+static void wpa_driver_privsep_event_assoc(void *ctx, -+ enum wpa_event_type event, -+ u8 *buf, size_t len) -+{ -+ union wpa_event_data data; -+ int inc_data = 0; -+ u8 *pos, *end; -+ int ie_len; -+ -+ os_memset(&data, 0, sizeof(data)); -+ -+ pos = buf; -+ end = buf + len; -+ -+ if (end - pos < (int) sizeof(int)) -+ return; -+ os_memcpy(&ie_len, pos, sizeof(int)); -+ pos += sizeof(int); -+ if (ie_len < 0 || ie_len > end - pos) -+ return; -+ if (ie_len) { -+ data.assoc_info.req_ies = pos; -+ data.assoc_info.req_ies_len = ie_len; -+ pos += ie_len; -+ inc_data = 1; -+ } -+ -+ wpa_supplicant_event(ctx, event, inc_data ? &data : NULL); -+} -+ -+ -+static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf, -+ size_t len) -+{ -+ union wpa_event_data data; -+ int ievent; -+ -+ if (len < sizeof(int) || -+ len - sizeof(int) > sizeof(data.interface_status.ifname)) -+ return; -+ -+ os_memcpy(&ievent, buf, sizeof(int)); -+ -+ os_memset(&data, 0, sizeof(data)); -+ data.interface_status.ievent = ievent; -+ os_memcpy(data.interface_status.ifname, buf + sizeof(int), -+ len - sizeof(int)); -+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data); -+} -+ -+ -+static void wpa_driver_privsep_event_michael_mic_failure( -+ void *ctx, u8 *buf, size_t len) -+{ -+ union wpa_event_data data; -+ -+ if (len != sizeof(int)) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int)); -+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -+} -+ -+ -+static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf, -+ size_t len) -+{ -+ union wpa_event_data data; -+ -+ if (len != sizeof(struct pmkid_candidate)) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(&data.pmkid_candidate, buf, len); -+ wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data); -+} -+ -+ -+static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len) -+{ -+ union wpa_event_data data; -+ -+ if (len != ETH_ALEN) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(data.stkstart.peer, buf, ETH_ALEN); -+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data); -+} -+ -+ -+static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf, -+ size_t len) -+{ -+ union wpa_event_data data; -+ -+ if (len < sizeof(int) + ETH_ALEN) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int)); -+ os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN); -+ data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN; -+ data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN; -+ wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data); -+} -+ -+ -+static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len) -+{ -+ if (len < ETH_ALEN) -+ return; -+ drv_event_eapol_rx(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN); -+} -+ -+ -+static void wpa_driver_privsep_receive(int sock, void *eloop_ctx, -+ void *sock_ctx) -+{ -+ struct wpa_driver_privsep_data *drv = eloop_ctx; -+ u8 *buf, *event_buf; -+ size_t event_len; -+ int res, event; -+ enum privsep_event e; -+ struct sockaddr_un from; -+ socklen_t fromlen = sizeof(from); -+ const size_t buflen = 2000; -+ -+ buf = os_malloc(buflen); -+ if (buf == NULL) -+ return; -+ res = recvfrom(sock, buf, buflen, 0, -+ (struct sockaddr *) &from, &fromlen); -+ if (res < 0) { -+ perror("recvfrom(priv_socket)"); -+ os_free(buf); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res); -+ -+ if (res < (int) sizeof(int)) { -+ wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res); -+ return; -+ } -+ -+ os_memcpy(&event, buf, sizeof(int)); -+ event_buf = &buf[sizeof(int)]; -+ event_len = res - sizeof(int); -+ wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)", -+ event, (unsigned long) event_len); -+ -+ e = event; -+ switch (e) { -+ case PRIVSEP_EVENT_SCAN_RESULTS: -+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); -+ break; -+ case PRIVSEP_EVENT_ASSOC: -+ wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC, -+ event_buf, event_len); -+ break; -+ case PRIVSEP_EVENT_DISASSOC: -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -+ break; -+ case PRIVSEP_EVENT_ASSOCINFO: -+ wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO, -+ event_buf, event_len); -+ break; -+ case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE: -+ wpa_driver_privsep_event_michael_mic_failure( -+ drv->ctx, event_buf, event_len); -+ break; -+ case PRIVSEP_EVENT_INTERFACE_STATUS: -+ wpa_driver_privsep_event_interface_status(drv->ctx, event_buf, -+ event_len); -+ break; -+ case PRIVSEP_EVENT_PMKID_CANDIDATE: -+ wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf, -+ event_len); -+ break; -+ case PRIVSEP_EVENT_STKSTART: -+ wpa_driver_privsep_event_stkstart(drv->ctx, event_buf, -+ event_len); -+ break; -+ case PRIVSEP_EVENT_FT_RESPONSE: -+ wpa_driver_privsep_event_ft_response(drv->ctx, event_buf, -+ event_len); -+ break; -+ case PRIVSEP_EVENT_RX_EAPOL: -+ wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf, -+ event_len); -+ break; -+ } -+ -+ os_free(buf); -+} -+ -+ -+static void * wpa_driver_privsep_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_privsep_data *drv; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->ctx = ctx; -+ drv->priv_socket = -1; -+ drv->cmd_socket = -1; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ -+ return drv; -+} -+ -+ -+static void wpa_driver_privsep_deinit(void *priv) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ -+ if (drv->priv_socket >= 0) { -+ wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER); -+ eloop_unregister_read_sock(drv->priv_socket); -+ close(drv->priv_socket); -+ } -+ -+ if (drv->own_socket_path) { -+ unlink(drv->own_socket_path); -+ os_free(drv->own_socket_path); -+ } -+ -+ if (drv->cmd_socket >= 0) { -+ eloop_unregister_read_sock(drv->cmd_socket); -+ close(drv->cmd_socket); -+ } -+ -+ if (drv->own_cmd_path) { -+ unlink(drv->own_cmd_path); -+ os_free(drv->own_cmd_path); -+ } -+ -+ os_free(drv); -+} -+ -+ -+static int wpa_driver_privsep_set_param(void *priv, const char *param) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ const char *pos; -+ char *own_dir, *priv_dir; -+ static unsigned int counter = 0; -+ size_t len; -+ struct sockaddr_un addr; -+ -+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); -+ if (param == NULL) -+ pos = NULL; -+ else -+ pos = os_strstr(param, "own_dir="); -+ if (pos) { -+ char *end; -+ own_dir = os_strdup(pos + 8); -+ if (own_dir == NULL) -+ return -1; -+ end = os_strchr(own_dir, ' '); -+ if (end) -+ *end = '\0'; -+ } else { -+ own_dir = os_strdup("/tmp"); -+ if (own_dir == NULL) -+ return -1; -+ } -+ -+ if (param == NULL) -+ pos = NULL; -+ else -+ pos = os_strstr(param, "priv_dir="); -+ if (pos) { -+ char *end; -+ priv_dir = os_strdup(pos + 9); -+ if (priv_dir == NULL) { -+ os_free(own_dir); -+ return -1; -+ } -+ end = os_strchr(priv_dir, ' '); -+ if (end) -+ *end = '\0'; -+ } else { -+ priv_dir = os_strdup("/var/run/wpa_priv"); -+ if (priv_dir == NULL) { -+ os_free(own_dir); -+ return -1; -+ } -+ } -+ -+ len = os_strlen(own_dir) + 50; -+ drv->own_socket_path = os_malloc(len); -+ if (drv->own_socket_path == NULL) { -+ os_free(priv_dir); -+ os_free(own_dir); -+ return -1; -+ } -+ os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d", -+ own_dir, getpid(), counter++); -+ -+ len = os_strlen(own_dir) + 50; -+ drv->own_cmd_path = os_malloc(len); -+ if (drv->own_cmd_path == NULL) { -+ os_free(drv->own_socket_path); -+ drv->own_socket_path = NULL; -+ os_free(priv_dir); -+ os_free(own_dir); -+ return -1; -+ } -+ os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d", -+ own_dir, getpid(), counter++); -+ -+ os_free(own_dir); -+ -+ drv->priv_addr.sun_family = AF_UNIX; -+ os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path), -+ "%s/%s", priv_dir, drv->ifname); -+ os_free(priv_dir); -+ -+ drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (drv->priv_socket < 0) { -+ perror("socket(PF_UNIX)"); -+ os_free(drv->own_socket_path); -+ drv->own_socket_path = NULL; -+ return -1; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path)); -+ if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) < -+ 0) { -+ perror("bind(PF_UNIX)"); -+ close(drv->priv_socket); -+ drv->priv_socket = -1; -+ unlink(drv->own_socket_path); -+ os_free(drv->own_socket_path); -+ drv->own_socket_path = NULL; -+ return -1; -+ } -+ -+ eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive, -+ drv, NULL); -+ -+ drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (drv->cmd_socket < 0) { -+ perror("socket(PF_UNIX)"); -+ os_free(drv->own_cmd_path); -+ drv->own_cmd_path = NULL; -+ return -1; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path)); -+ if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) -+ { -+ perror("bind(PF_UNIX)"); -+ close(drv->cmd_socket); -+ drv->cmd_socket = -1; -+ unlink(drv->own_cmd_path); -+ os_free(drv->own_cmd_path); -+ drv->own_cmd_path = NULL; -+ return -1; -+ } -+ -+ if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) { -+ wpa_printf(MSG_ERROR, "Failed to register with wpa_priv"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_privsep_get_capa(void *priv, -+ struct wpa_driver_capa *capa) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ int res; -+ size_t len = sizeof(*capa); -+ -+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len); -+ if (res < 0 || len != sizeof(*capa)) -+ return -1; -+ return 0; -+} -+ -+ -+static const u8 * wpa_driver_privsep_get_mac_addr(void *priv) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ return drv->own_addr; -+} -+ -+ -+static int wpa_driver_privsep_set_country(void *priv, const char *alpha2) -+{ -+ struct wpa_driver_privsep_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2); -+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2, -+ os_strlen(alpha2), NULL, NULL); -+} -+ -+ -+struct wpa_driver_ops wpa_driver_privsep_ops = { -+ "privsep", -+ "wpa_supplicant privilege separated driver", -+ .get_bssid = wpa_driver_privsep_get_bssid, -+ .get_ssid = wpa_driver_privsep_get_ssid, -+ .set_key = wpa_driver_privsep_set_key, -+ .init = wpa_driver_privsep_init, -+ .deinit = wpa_driver_privsep_deinit, -+ .set_param = wpa_driver_privsep_set_param, -+ .scan2 = wpa_driver_privsep_scan, -+ .deauthenticate = wpa_driver_privsep_deauthenticate, -+ .disassociate = wpa_driver_privsep_disassociate, -+ .associate = wpa_driver_privsep_associate, -+ .get_capa = wpa_driver_privsep_get_capa, -+ .get_mac_addr = wpa_driver_privsep_get_mac_addr, -+ .get_scan_results2 = wpa_driver_privsep_get_scan_results2, -+ .set_country = wpa_driver_privsep_set_country, -+}; -+ -+ -+struct wpa_driver_ops *wpa_drivers[] = -+{ -+ &wpa_driver_privsep_ops, -+ NULL -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.c -new file mode 100644 -index 0000000000000..a1e27beda849b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.c -@@ -0,0 +1,1498 @@ -+/* -+ * WPA Supplicant - driver interaction with Ralink Wireless Client -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * Copyright (c) 2007, Snowpin Lee -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "wireless_copy.h" -+#include "common.h" -+#include "driver.h" -+#include "l2_packet/l2_packet.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "priv_netlink.h" -+#include "netlink.h" -+#include "linux_ioctl.h" -+#include "driver_ralink.h" -+ -+static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx); -+ -+#define MAX_SSID_LEN 32 -+ -+struct wpa_driver_ralink_data { -+ void *ctx; -+ int ioctl_sock; -+ struct netlink_data *netlink; -+ char ifname[IFNAMSIZ + 1]; -+ u8 *assoc_req_ies; -+ size_t assoc_req_ies_len; -+ u8 *assoc_resp_ies; -+ size_t assoc_resp_ies_len; -+ int no_of_pmkid; -+ struct ndis_pmkid_entry *pmkid; -+ int we_version_compiled; -+ int ap_scan; -+ int scanning_done; -+ u8 g_driver_down; -+ BOOLEAN bAddWepKey; -+}; -+ -+static int ralink_set_oid(struct wpa_driver_ralink_data *drv, -+ unsigned short oid, char *data, int len) -+{ -+ char *buf; -+ struct iwreq iwr; -+ -+ buf = os_zalloc(len); -+ if (buf == NULL) -+ return -1; -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.flags = oid; -+ iwr.u.data.flags |= OID_GET_SET_TOGGLE; -+ -+ if (data) -+ os_memcpy(buf, data, len); -+ -+ iwr.u.data.pointer = (caddr_t) buf; -+ iwr.u.data.length = len; -+ -+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed", -+ __func__, oid, len); -+ os_free(buf); -+ return -1; -+ } -+ os_free(buf); -+ return 0; -+} -+ -+static int -+ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv) -+{ -+ struct iwreq iwr; -+ UCHAR enabled = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (UCHAR*) &enabled; -+ iwr.u.data.flags = RT_OID_NEW_DRIVER; -+ -+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed", __func__); -+ return 0; -+ } -+ -+ return (enabled == 1) ? 1 : 0; -+} -+ -+static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { -+ perror("ioctl[SIOCGIWAP]"); -+ ret = -1; -+ } -+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); -+ -+ return ret; -+} -+ -+static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+#if 0 -+ struct wpa_supplicant *wpa_s = drv->ctx; -+ struct wpa_ssid *entry; -+#endif -+ int ssid_len; -+ u8 bssid[ETH_ALEN]; -+ u8 ssid_str[MAX_SSID_LEN]; -+ struct iwreq iwr; -+#if 0 -+ int result = 0; -+#endif -+ int ret = 0; -+#if 0 -+ BOOLEAN ieee8021x_mode = FALSE; -+ BOOLEAN ieee8021x_required_key = FALSE; -+#endif -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.essid.pointer = (caddr_t) ssid; -+ iwr.u.essid.length = 32; -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCGIWESSID]"); -+ ret = -1; -+ } else -+ ret = iwr.u.essid.length; -+ -+ if (ret <= 0) -+ return ret; -+ -+ ssid_len = ret; -+ os_memset(ssid_str, 0, MAX_SSID_LEN); -+ os_memcpy(ssid_str, ssid, ssid_len); -+ -+ if (drv->ap_scan == 0) { -+ /* Read BSSID form driver */ -+ if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) { -+ wpa_printf(MSG_WARNING, "Could not read BSSID from " -+ "driver."); -+ return ret; -+ } -+ -+#if 0 -+ entry = wpa_s->conf->ssid; -+ while (entry) { -+ if (!entry->disabled && ssid_len == entry->ssid_len && -+ os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 && -+ (!entry->bssid_set || -+ os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) { -+ /* match the config of driver */ -+ result = 1; -+ break; -+ } -+ entry = entry->next; -+ } -+ -+ if (result) { -+ wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and " -+ "ieee_required_keys parameters to driver"); -+ -+ /* set 802.1x mode and ieee_required_keys parameter */ -+ if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { -+ if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) -+ ieee8021x_required_key = TRUE; -+ ieee8021x_mode = TRUE; -+ } -+ -+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0) -+ { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode); -+ } -+ else -+ { -+ wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE"); -+ } -+ -+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0) -+ { -+ wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key); -+ } -+ else -+ { -+ wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE", -+ entry->eapol_flags); -+ } -+ } -+#endif -+ } -+ -+ return ret; -+} -+ -+static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv, -+ const u8 *ssid, size_t ssid_len) -+{ -+ NDIS_802_11_SSID *buf; -+ int ret = 0; -+ struct iwreq iwr; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ buf = os_zalloc(sizeof(NDIS_802_11_SSID)); -+ if (buf == NULL) -+ return -1; -+ os_memset(buf, 0, sizeof(buf)); -+ buf->SsidLength = ssid_len; -+ os_memcpy(buf->Ssid, ssid, ssid_len); -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ iwr.u.data.flags = OID_802_11_SSID; -+ iwr.u.data.flags |= OID_GET_SET_TOGGLE; -+ iwr.u.data.pointer = (caddr_t) buf; -+ iwr.u.data.length = sizeof(NDIS_802_11_SSID); -+ -+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { -+ perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID"); -+ ret = -1; -+ } -+ os_free(buf); -+ return ret; -+} -+ -+static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv, -+ const u8 *data, size_t data_len) -+{ -+ NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid; -+ size_t i; -+ union wpa_event_data event; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (data_len < 8) { -+ wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List " -+ "Event (len=%lu)", (unsigned long) data_len); -+ return; -+ } -+ pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data; -+ wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d" -+ " NumCandidates %d", -+ (int) pmkid->Version, (int) pmkid->NumCandidates); -+ -+ if (pmkid->Version != 1) { -+ wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate " -+ "List Version %d", (int) pmkid->Version); -+ return; -+ } -+ -+ if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) { -+ wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List " -+ "underflow"); -+ -+ return; -+ } -+ -+ -+ -+ os_memset(&event, 0, sizeof(event)); -+ for (i = 0; i < pmkid->NumCandidates; i++) { -+ PMKID_CANDIDATE *p = &pmkid->CandidateList[i]; -+ wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x", -+ (unsigned long) i, MAC2STR(p->BSSID), -+ (int) p->Flags); -+ os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN); -+ event.pmkid_candidate.index = i; -+ event.pmkid_candidate.preauth = -+ p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED; -+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, -+ &event); -+ } -+} -+ -+static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv) -+{ -+ int len, count, i, ret; -+ struct ndis_pmkid_entry *entry; -+ NDIS_802_11_PMKID *p; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ count = 0; -+ entry = drv->pmkid; -+ while (entry) { -+ count++; -+ if (count >= drv->no_of_pmkid) -+ break; -+ entry = entry->next; -+ } -+ len = 8 + count * sizeof(BSSID_INFO); -+ p = os_zalloc(len); -+ if (p == NULL) -+ return -1; -+ p->Length = len; -+ p->BSSIDInfoCount = count; -+ entry = drv->pmkid; -+ for (i = 0; i < count; i++) { -+ os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN); -+ os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16); -+ entry = entry->next; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", -+ (const u8 *) p, len); -+ ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len); -+ os_free(p); -+ return ret; -+} -+ -+static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ struct ndis_pmkid_entry *entry, *prev; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (drv->no_of_pmkid == 0) -+ return 0; -+ -+ prev = NULL; -+ entry = drv->pmkid; -+ while (entry) { -+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0) -+ break; -+ prev = entry; -+ entry = entry->next; -+ } -+ -+ if (entry) { -+ /* Replace existing entry for this BSSID and move it into the -+ * beginning of the list. */ -+ os_memcpy(entry->pmkid, pmkid, 16); -+ if (prev) { -+ prev->next = entry->next; -+ entry->next = drv->pmkid; -+ drv->pmkid = entry; -+ } -+ } else { -+ entry = os_malloc(sizeof(*entry)); -+ if (entry) { -+ os_memcpy(entry->bssid, bssid, ETH_ALEN); -+ os_memcpy(entry->pmkid, pmkid, 16); -+ entry->next = drv->pmkid; -+ drv->pmkid = entry; -+ } -+ } -+ -+ return wpa_driver_ralink_set_pmkid(drv); -+} -+ -+ -+static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ struct ndis_pmkid_entry *entry, *prev; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (drv->no_of_pmkid == 0) -+ return 0; -+ -+ entry = drv->pmkid; -+ prev = NULL; -+ drv->pmkid = NULL; -+ while (entry) { -+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 && -+ os_memcmp(entry->pmkid, pmkid, 16) == 0) { -+ if (prev) -+ prev->next = entry->next; -+ else -+ drv->pmkid = entry->next; -+ os_free(entry); -+ break; -+ } -+ prev = entry; -+ entry = entry->next; -+ } -+ return wpa_driver_ralink_set_pmkid(drv); -+} -+ -+ -+static int wpa_driver_ralink_flush_pmkid(void *priv) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ NDIS_802_11_PMKID p; -+ struct ndis_pmkid_entry *pmkid, *prev; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (drv->no_of_pmkid == 0) -+ return 0; -+ -+ pmkid = drv->pmkid; -+ drv->pmkid = NULL; -+ while (pmkid) { -+ prev = pmkid; -+ pmkid = pmkid->next; -+ os_free(prev); -+ } -+ -+ os_memset(&p, 0, sizeof(p)); -+ p.Length = 8; -+ p.BSSIDInfoCount = 0; -+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)", -+ (const u8 *) &p, 8); -+ return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8); -+} -+ -+static void -+wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv, -+ void *ctx, char *custom) -+{ -+ union wpa_event_data data; -+ u8 *req_ies = NULL, *resp_ies = NULL; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); -+ -+ os_memset(&data, 0, sizeof(data)); -+ /* Host AP driver */ -+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { -+ /* receive a MICFAILURE report */ -+ data.michael_mic_failure.unicast = -+ os_strstr(custom, " unicast") != NULL; -+ /* TODO: parse parameters(?) */ -+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -+ } else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) { -+ /* receive assoc. req. IEs */ -+ char *spos; -+ int bytes; -+ -+ spos = custom + 17; -+ /*get IE's length */ -+ /* -+ * bytes = strlen(spos); ==> bug, bytes may less than original -+ * size by using this way to get size. snowpin 20070312 -+ * if (!bytes) -+ * return; -+ */ -+ bytes = drv->assoc_req_ies_len; -+ -+ req_ies = os_malloc(bytes); -+ if (req_ies == NULL) -+ return; -+ os_memcpy(req_ies, spos, bytes); -+ data.assoc_info.req_ies = req_ies; -+ data.assoc_info.req_ies_len = bytes; -+ -+ /* skip the '\0' byte */ -+ spos += bytes + 1; -+ -+ data.assoc_info.resp_ies = NULL; -+ data.assoc_info.resp_ies_len = 0; -+ -+ if (os_strncmp(spos, " RespIEs=", 9) == 0) { -+ /* receive assoc. resp. IEs */ -+ spos += 9; -+ /* get IE's length */ -+ bytes = os_strlen(spos); -+ if (!bytes) -+ goto done; -+ -+ resp_ies = os_malloc(bytes); -+ if (resp_ies == NULL) -+ goto done; -+ os_memcpy(resp_ies, spos, bytes); -+ data.assoc_info.resp_ies = resp_ies; -+ data.assoc_info.resp_ies_len = bytes; -+ } -+ -+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); -+ -+ done: -+ /* free allocated memory */ -+ os_free(resp_ies); -+ os_free(req_ies); -+ } -+} -+ -+static void ralink_interface_up(struct wpa_driver_ralink_data *drv) -+{ -+ union wpa_event_data event; -+ int enable_wpa_supplicant = 0; -+ drv->g_driver_down = 0; -+ os_memset(&event, 0, sizeof(event)); -+ os_snprintf(event.interface_status.ifname, -+ sizeof(event.interface_status.ifname), "%s", drv->ifname); -+ -+ event.interface_status.ievent = EVENT_INTERFACE_ADDED; -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -+ -+ if (drv->ap_scan == 1) -+ enable_wpa_supplicant = 1; -+ else -+ enable_wpa_supplicant = 2; -+ /* trigger driver support wpa_supplicant */ -+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, -+ (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0) -+ { -+ wpa_printf(MSG_INFO, "RALINK: Failed to set " -+ "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)", -+ (int) enable_wpa_supplicant); -+ wpa_printf(MSG_ERROR, "ralink. Driver does not support " -+ "wpa_supplicant"); -+ } -+} -+ -+static void -+wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv, -+ void *ctx, char *data, int len) -+{ -+ struct iw_event iwe_buf, *iwe = &iwe_buf; -+ char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos; -+#if 0 -+ BOOLEAN ieee8021x_required_key = FALSE; -+#endif -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ assoc_info_buf = info_pos = NULL; -+ pos = data; -+ end = data + len; -+ -+ while (pos + IW_EV_LCP_LEN <= end) { -+ /* Event data may be unaligned, so make a local, aligned copy -+ * before processing. */ -+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); -+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", -+ iwe->cmd, iwe->len); -+ if (iwe->len <= IW_EV_LCP_LEN) -+ return; -+ -+ custom = pos + IW_EV_POINT_LEN; -+ -+ if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) { -+ /* WE-19 removed the pointer from struct iw_point */ -+ char *dpos = (char *) &iwe_buf.u.data.length; -+ int dlen = dpos - (char *) &iwe_buf; -+ os_memcpy(dpos, pos + IW_EV_LCP_LEN, -+ sizeof(struct iw_event) - dlen); -+ } else { -+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); -+ custom += IW_EV_POINT_OFF; -+ } -+ -+ switch (iwe->cmd) { -+ case IWEVCUSTOM: -+ if (custom + iwe->u.data.length > end) -+ return; -+ buf = os_malloc(iwe->u.data.length + 1); -+ if (buf == NULL) -+ return; -+ os_memcpy(buf, custom, iwe->u.data.length); -+ buf[iwe->u.data.length] = '\0'; -+ -+ if (drv->ap_scan == 1) { -+ if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) -+ || (iwe->u.data.flags == -+ RT_REQIE_EVENT_FLAG) || -+ (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) -+ || (iwe->u.data.flags == -+ RT_ASSOCINFO_EVENT_FLAG)) { -+ if (drv->scanning_done == 0) { -+ os_free(buf); -+ return; -+ } -+ } -+ } -+ -+ if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) { -+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); -+ wpa_printf(MSG_DEBUG, "Custom wireless event: " -+ "receive ASSOCIATED_EVENT !!!"); -+ } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) { -+ wpa_printf(MSG_DEBUG, "Custom wireless event: " -+ "receive ReqIEs !!!"); -+ drv->assoc_req_ies = -+ os_malloc(iwe->u.data.length); -+ if (drv->assoc_req_ies == NULL) { -+ os_free(buf); -+ return; -+ } -+ -+ drv->assoc_req_ies_len = iwe->u.data.length; -+ os_memcpy(drv->assoc_req_ies, custom, -+ iwe->u.data.length); -+ } else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) { -+ wpa_printf(MSG_DEBUG, "Custom wireless event: " -+ "receive RespIEs !!!"); -+ drv->assoc_resp_ies = -+ os_malloc(iwe->u.data.length); -+ if (drv->assoc_resp_ies == NULL) { -+ os_free(drv->assoc_req_ies); -+ drv->assoc_req_ies = NULL; -+ os_free(buf); -+ return; -+ } -+ -+ drv->assoc_resp_ies_len = iwe->u.data.length; -+ os_memcpy(drv->assoc_resp_ies, custom, -+ iwe->u.data.length); -+ } else if (iwe->u.data.flags == -+ RT_ASSOCINFO_EVENT_FLAG) { -+ wpa_printf(MSG_DEBUG, "Custom wireless event: " -+ "receive ASSOCINFO_EVENT !!!"); -+ -+ assoc_info_buf = -+ os_zalloc(drv->assoc_req_ies_len + -+ drv->assoc_resp_ies_len + 1); -+ -+ if (assoc_info_buf == NULL) { -+ os_free(drv->assoc_req_ies); -+ drv->assoc_req_ies = NULL; -+ os_free(drv->assoc_resp_ies); -+ drv->assoc_resp_ies = NULL; -+ os_free(buf); -+ return; -+ } -+ -+ if (drv->assoc_req_ies) { -+ os_memcpy(assoc_info_buf, -+ drv->assoc_req_ies, -+ drv->assoc_req_ies_len); -+ } -+ info_pos = assoc_info_buf + -+ drv->assoc_req_ies_len; -+ if (drv->assoc_resp_ies) { -+ os_memcpy(info_pos, -+ drv->assoc_resp_ies, -+ drv->assoc_resp_ies_len); -+ } -+ assoc_info_buf[drv->assoc_req_ies_len + -+ drv->assoc_resp_ies_len] = '\0'; -+ wpa_driver_ralink_event_wireless_custom( -+ drv, ctx, assoc_info_buf); -+ os_free(drv->assoc_req_ies); -+ drv->assoc_req_ies = NULL; -+ os_free(drv->assoc_resp_ies); -+ drv->assoc_resp_ies = NULL; -+ os_free(assoc_info_buf); -+ } else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG) -+ { -+ wpa_printf(MSG_DEBUG, "Custom wireless event: " -+ "receive DISASSOCIATED_EVENT !!!"); -+ wpa_supplicant_event(ctx, EVENT_DISASSOC, -+ NULL); -+ } else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) { -+ wpa_printf(MSG_DEBUG, "Custom wireless event: " -+ "receive PMKIDCAND_EVENT !!!"); -+ wpa_driver_ralink_event_pmkid( -+ drv, (const u8 *) custom, -+ iwe->u.data.length); -+ } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) { -+ drv->g_driver_down = 1; -+ eloop_terminate(); -+ } else if (iwe->u.data.flags == RT_INTERFACE_UP) { -+ ralink_interface_up(drv); -+ } else { -+ wpa_driver_ralink_event_wireless_custom( -+ drv, ctx, buf); -+ } -+ os_free(buf); -+ break; -+ } -+ -+ pos += iwe->len; -+ } -+} -+ -+static void -+wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, -+ u8 *buf, size_t len) -+{ -+ struct wpa_driver_ralink_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg)); -+ -+ attrlen = len; -+ wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen); -+ attr = (struct rtattr *) buf; -+ wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr)); -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len); -+ while (RTA_OK(attr, attrlen)) { -+ wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type); -+ if (attr->rta_type == IFLA_WIRELESS) { -+ wpa_driver_ralink_event_wireless( -+ drv, ctx, -+ ((char *) attr) + rta_len, -+ attr->rta_len - rta_len); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ wpa_hexdump(MSG_DEBUG, "attr3: ", -+ (u8 *) attr, sizeof(struct rtattr)); -+ } -+} -+ -+static int -+ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv) -+{ -+ struct iwreq iwr; -+ UINT we_version_compiled = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) &we_version_compiled; -+ iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED; -+ -+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: failed", __func__); -+ return -1; -+ } -+ -+ drv->we_version_compiled = we_version_compiled; -+ -+ return 0; -+} -+ -+static void * wpa_driver_ralink_init(void *ctx, const char *ifname) -+{ -+ int s; -+ struct wpa_driver_ralink_data *drv; -+ struct ifreq ifr; -+ UCHAR enable_wpa_supplicant = 0; -+ struct netlink_config *cfg; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ /* open socket to kernel */ -+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { -+ perror("socket"); -+ return NULL; -+ } -+ /* do it */ -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ -+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { -+ perror(ifr.ifr_name); -+ return NULL; -+ } -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ -+ drv->scanning_done = 1; -+ drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */ -+ drv->ctx = ctx; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ drv->ioctl_sock = s; -+ drv->g_driver_down = 0; -+ -+ cfg = os_zalloc(sizeof(*cfg)); -+ if (cfg == NULL) { -+ close(drv->ioctl_sock); -+ os_free(drv); -+ return NULL; -+ } -+ cfg->ctx = drv; -+ cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink; -+ drv->netlink = netlink_init(cfg); -+ if (drv->netlink == NULL) { -+ os_free(cfg); -+ close(drv->ioctl_sock); -+ os_free(drv); -+ return NULL; -+ } -+ -+ drv->no_of_pmkid = 4; /* Number of PMKID saved supported */ -+ -+ linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); -+ ralink_get_we_version_compiled(drv); -+ wpa_driver_ralink_flush_pmkid(drv); -+ -+ if (drv->ap_scan == 1) -+ enable_wpa_supplicant = 1; -+ else -+ enable_wpa_supplicant = 2; -+ /* trigger driver support wpa_supplicant */ -+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, -+ (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0) -+ { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)", -+ (int) enable_wpa_supplicant); -+ wpa_printf(MSG_ERROR, "RALINK: Driver does not support " -+ "wpa_supplicant"); -+ close(s); -+ close(drv->ioctl_sock); -+ os_free(drv); -+ return NULL; -+ } -+ -+ if (drv->ap_scan == 1) -+ drv->scanning_done = 0; -+ -+ return drv; -+} -+ -+static void wpa_driver_ralink_deinit(void *priv) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ UCHAR enable_wpa_supplicant; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ enable_wpa_supplicant = 0; -+ -+ if (drv->g_driver_down == 0) { -+ /* trigger driver disable wpa_supplicant support */ -+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, -+ (char *) &enable_wpa_supplicant, -+ sizeof(BOOLEAN)) < 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)", -+ (int) enable_wpa_supplicant); -+ } -+ -+ wpa_driver_ralink_flush_pmkid(drv); -+ -+ sleep(1); -+ /* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */ -+ } -+ -+ eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx); -+ netlink_deinit(drv->netlink); -+ close(drv->ioctl_sock); -+ os_free(drv); -+} -+ -+static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_ralink_data *drv = eloop_ctx; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+ -+ drv->scanning_done = 1; -+ -+} -+ -+static int wpa_driver_ralink_scan(void *priv, -+ struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+#if 0 -+ if (ssid_len > IW_ESSID_MAX_SIZE) { -+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", -+ __FUNCTION__, (unsigned long) ssid_len); -+ return -1; -+ } -+ -+ /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */ -+#endif -+ -+ if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE, -+ (char *) params->extra_ies, params->extra_ies_len) < -+ 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "RT_OID_WPS_PROBE_REQ_IE"); -+ } -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { -+ perror("ioctl[SIOCSIWSCAN]"); -+ ret = -1; -+ } -+ -+ /* Not all drivers generate "scan completed" wireless event, so try to -+ * read results after a timeout. */ -+ eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx); -+ eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv, -+ drv->ctx); -+ -+ drv->scanning_done = 0; -+ -+ return ret; -+} -+ -+static struct wpa_scan_results * -+wpa_driver_ralink_get_scan_results(void *priv) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ UCHAR *buf = NULL; -+ size_t buf_len; -+ NDIS_802_11_BSSID_LIST_EX *wsr; -+ NDIS_WLAN_BSSID_EX *wbi; -+ struct iwreq iwr; -+ size_t ap_num; -+ u8 *pos; -+ struct wpa_scan_results *res; -+ -+ if (drv->g_driver_down == 1) -+ return NULL; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (drv->we_version_compiled >= 17) -+ buf_len = 8192; -+ else -+ buf_len = 4096; -+ -+ for (;;) { -+ buf = os_zalloc(buf_len); -+ iwr.u.data.length = buf_len; -+ if (buf == NULL) -+ return NULL; -+ -+ wsr = (NDIS_802_11_BSSID_LIST_EX *) buf; -+ -+ wsr->NumberOfItems = 0; -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (void *) buf; -+ iwr.u.data.flags = OID_802_11_BSSID_LIST; -+ -+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0) -+ break; -+ -+ if (errno == E2BIG && buf_len < 65535) { -+ os_free(buf); -+ buf = NULL; -+ buf_len *= 2; -+ if (buf_len > 65535) -+ buf_len = 65535; /* 16-bit length field */ -+ wpa_printf(MSG_DEBUG, "Scan results did not fit - " -+ "trying larger buffer (%lu bytes)", -+ (unsigned long) buf_len); -+ } else { -+ perror("ioctl[RT_PRIV_IOCTL]"); -+ os_free(buf); -+ return NULL; -+ } -+ } -+ -+ res = os_zalloc(sizeof(*res)); -+ if (res == NULL) { -+ os_free(buf); -+ return NULL; -+ } -+ -+ res->res = os_zalloc(wsr->NumberOfItems * -+ sizeof(struct wpa_scan_res *)); -+ if (res->res == NULL) { -+ os_free(res); -+ os_free(buf); -+ return NULL; -+ } -+ -+ for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems; -+ ++ap_num) { -+ struct wpa_scan_res *r = NULL; -+ size_t extra_len = 0, var_ie_len = 0; -+ u8 *pos2; -+ -+ /* SSID data element */ -+ extra_len += 2 + wbi->Ssid.SsidLength; -+ var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs); -+ r = os_zalloc(sizeof(*r) + extra_len + var_ie_len); -+ if (r == NULL) -+ break; -+ res->res[res->num++] = r; -+ -+ wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid); -+ /* get ie's */ -+ wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs", -+ (u8 *) &wbi->IEs[0], wbi->IELength); -+ -+ os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN); -+ -+ extra_len += (2 + wbi->Ssid.SsidLength); -+ r->ie_len = extra_len + var_ie_len; -+ pos2 = (u8 *) (r + 1); -+ -+ /* -+ * Generate a fake SSID IE since the driver did not report -+ * a full IE list. -+ */ -+ *pos2++ = WLAN_EID_SSID; -+ *pos2++ = wbi->Ssid.SsidLength; -+ os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength); -+ pos2 += wbi->Ssid.SsidLength; -+ -+ r->freq = (wbi->Configuration.DSConfig / 1000); -+ -+ pos = (u8 *) wbi + sizeof(*wbi) - 1; -+ -+ pos += sizeof(NDIS_802_11_FIXED_IEs) - 2; -+ os_memcpy(&(r->caps), pos, 2); -+ pos += 2; -+ -+ if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs)) -+ os_memcpy(pos2, pos, var_ie_len); -+ -+ wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length); -+ } -+ -+ os_free(buf); -+ return res; -+} -+ -+static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv, -+ NDIS_802_11_AUTHENTICATION_MODE mode) -+{ -+ NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE, -+ (char *) &auth_mode, sizeof(auth_mode)) < 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "OID_802_11_AUTHENTICATION_MODE (%d)", -+ (int) auth_mode); -+ return -1; -+ } -+ return 0; -+} -+ -+static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv, -+ NDIS_802_11_WEP_STATUS encr_type) -+{ -+ NDIS_802_11_WEP_STATUS wep_status = encr_type; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (ralink_set_oid(drv, OID_802_11_WEP_STATUS, -+ (char *) &wep_status, sizeof(wep_status)) < 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "OID_802_11_WEP_STATUS (%d)", -+ (int) wep_status); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv, -+ int key_idx, const u8 *addr, -+ const u8 *bssid, int pairwise) -+{ -+ NDIS_802_11_REMOVE_KEY rkey; -+ NDIS_802_11_KEY_INDEX _index; -+ int res, res2; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ os_memset(&rkey, 0, sizeof(rkey)); -+ -+ rkey.Length = sizeof(rkey); -+ rkey.KeyIndex = key_idx; -+ -+ if (pairwise) -+ rkey.KeyIndex |= 1 << 30; -+ -+ os_memcpy(rkey.BSSID, bssid, ETH_ALEN); -+ -+ res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey, -+ sizeof(rkey)); -+ -+ /* AlbertY@20060210 removed it */ -+ if (0 /* !pairwise */) { -+ res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP, -+ (char *) &_index, sizeof(_index)); -+ } else -+ res2 = 0; -+ -+ if (res < 0 && res2 < 0) -+ return res; -+ return 0; -+} -+ -+static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv, -+ int pairwise, int key_idx, int set_tx, -+ const u8 *key, size_t key_len) -+{ -+ NDIS_802_11_WEP *wep; -+ size_t len; -+ int res; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ len = 12 + key_len; -+ wep = os_zalloc(len); -+ if (wep == NULL) -+ return -1; -+ -+ wep->Length = len; -+ wep->KeyIndex = key_idx; -+ -+ if (set_tx) -+ wep->KeyIndex |= 0x80000000; -+ -+ wep->KeyLength = key_len; -+ os_memcpy(wep->KeyMaterial, key, key_len); -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP", -+ (const u8 *) wep, len); -+ res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len); -+ -+ os_free(wep); -+ -+ return res; -+} -+ -+static int wpa_driver_ralink_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ size_t len, i; -+ NDIS_802_11_KEY *nkey; -+ int res, pairwise; -+ u8 bssid[ETH_ALEN]; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ drv->bAddWepKey = FALSE; -+ -+ if (addr == NULL || is_broadcast_ether_addr(addr)) { -+ /* Group Key */ -+ pairwise = 0; -+ wpa_driver_ralink_get_bssid(drv, bssid); -+ } else { -+ /* Pairwise Key */ -+ pairwise = 1; -+ os_memcpy(bssid, addr, ETH_ALEN); -+ } -+ -+ if (alg == WPA_ALG_NONE || key_len == 0) { -+ return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid, -+ pairwise); -+ } -+ -+ if (alg == WPA_ALG_WEP) { -+ drv->bAddWepKey = TRUE; -+ return wpa_driver_ralink_add_wep(drv, pairwise, key_idx, -+ set_tx, key, key_len); -+ } -+ -+ len = 12 + 6 + 6 + 8 + key_len; -+ -+ nkey = os_zalloc(len); -+ if (nkey == NULL) -+ return -1; -+ -+ nkey->Length = len; -+ nkey->KeyIndex = key_idx; -+ -+ if (set_tx) -+ nkey->KeyIndex |= 1 << 31; -+ -+ if (pairwise) -+ nkey->KeyIndex |= 1 << 30; -+ -+ if (seq && seq_len) -+ nkey->KeyIndex |= 1 << 29; -+ -+ nkey->KeyLength = key_len; -+ os_memcpy(nkey->BSSID, bssid, ETH_ALEN); -+ -+ if (seq && seq_len) { -+ for (i = 0; i < seq_len; i++) -+ nkey->KeyRSC |= seq[i] << (i * 8); -+ } -+ if (alg == WPA_ALG_TKIP && key_len == 32) { -+ os_memcpy(nkey->KeyMaterial, key, 16); -+ os_memcpy(nkey->KeyMaterial + 16, key + 24, 8); -+ os_memcpy(nkey->KeyMaterial + 24, key + 16, 8); -+ } else { -+ os_memcpy(nkey->KeyMaterial, key, key_len); -+ } -+ -+ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu " -+ "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx, -+ (unsigned long) seq_len, (unsigned long) key_len); -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY", -+ (const u8 *) nkey, len); -+ res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len); -+ os_free(nkey); -+ -+ return res; -+} -+ -+static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4) < 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "OID_802_11_DISASSOCIATE"); -+ } -+ -+ return 0; -+} -+ -+static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ -+ wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down); -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ if (ralink_get_new_driver_flag(drv) == 0) { -+ return wpa_driver_ralink_disassociate(priv, addr, reason_code); -+ } else { -+ MLME_DEAUTH_REQ_STRUCT mlme; -+ os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT)); -+ mlme.Reason = reason_code; -+ os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN); -+ return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION, -+ (char *) &mlme, -+ sizeof(MLME_DEAUTH_REQ_STRUCT)); -+ } -+} -+ -+static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie, -+ size_t ie_len) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) ie; -+ iwr.u.data.length = ie_len; -+ -+ wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ", -+ (u8 *) ie, ie_len); -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWGENIE]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+static int -+wpa_driver_ralink_associate(void *priv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ -+ NDIS_802_11_NETWORK_INFRASTRUCTURE mode; -+ NDIS_802_11_AUTHENTICATION_MODE auth_mode; -+ NDIS_802_11_WEP_STATUS encr; -+ BOOLEAN ieee8021xMode; -+ BOOLEAN ieee8021x_required_key = TRUE; -+ -+ if (drv->g_driver_down == 1) -+ return -1; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (params->mode == IEEE80211_MODE_IBSS) -+ mode = Ndis802_11IBSS; -+ else -+ mode = Ndis802_11Infrastructure; -+ -+ if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE, -+ (char *) &mode, sizeof(mode)) < 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "OID_802_11_INFRASTRUCTURE_MODE (%d)", -+ (int) mode); -+ /* Try to continue anyway */ -+ } -+ -+ if (params->key_mgmt_suite == KEY_MGMT_WPS) { -+ UCHAR enable_wps = 0x80; -+ /* trigger driver support wpa_supplicant */ -+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, -+ (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) { -+ wpa_printf(MSG_INFO, "RALINK: Failed to set " -+ "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)", -+ (int) enable_wps); -+ } -+ -+ wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie, -+ params->wpa_ie_len); -+ -+ ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen); -+ -+ ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled); -+ } else { -+#ifdef CONFIG_WPS -+ UCHAR enable_wpa_supplicant; -+ -+ if (drv->ap_scan == 1) -+ enable_wpa_supplicant = 0x01; -+ else -+ enable_wpa_supplicant = 0x02; -+ -+ /* trigger driver support wpa_supplicant */ -+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT, -+ (PCHAR) &enable_wpa_supplicant, -+ sizeof(UCHAR)) < 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)", -+ (int) enable_wpa_supplicant); -+ } -+ -+ wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0); -+#endif /* CONFIG_WPS */ -+ -+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { -+ if (params->auth_alg & WPA_AUTH_ALG_SHARED) { -+ if (params->auth_alg & WPA_AUTH_ALG_OPEN) -+ auth_mode = Ndis802_11AuthModeAutoSwitch; -+ else -+ auth_mode = Ndis802_11AuthModeShared; -+ } else -+ auth_mode = Ndis802_11AuthModeOpen; -+ } else if (params->wpa_ie[0] == WLAN_EID_RSN) { -+ if (params->key_mgmt_suite == KEY_MGMT_PSK) -+ auth_mode = Ndis802_11AuthModeWPA2PSK; -+ else -+ auth_mode = Ndis802_11AuthModeWPA2; -+ } else { -+ if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE) -+ auth_mode = Ndis802_11AuthModeWPANone; -+ else if (params->key_mgmt_suite == KEY_MGMT_PSK) -+ auth_mode = Ndis802_11AuthModeWPAPSK; -+ else -+ auth_mode = Ndis802_11AuthModeWPA; -+ } -+ -+ switch (params->pairwise_suite) { -+ case CIPHER_CCMP: -+ encr = Ndis802_11Encryption3Enabled; -+ break; -+ case CIPHER_TKIP: -+ encr = Ndis802_11Encryption2Enabled; -+ break; -+ case CIPHER_WEP40: -+ case CIPHER_WEP104: -+ encr = Ndis802_11Encryption1Enabled; -+ break; -+ case CIPHER_NONE: -+ if (params->group_suite == CIPHER_CCMP) -+ encr = Ndis802_11Encryption3Enabled; -+ else if (params->group_suite == CIPHER_TKIP) -+ encr = Ndis802_11Encryption2Enabled; -+ else -+ encr = Ndis802_11EncryptionDisabled; -+ break; -+ default: -+ encr = Ndis802_11EncryptionDisabled; -+ break; -+ } -+ -+ ralink_set_auth_mode(drv, auth_mode); -+ -+ /* notify driver that IEEE8021x mode is enabled */ -+ if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) { -+ ieee8021xMode = TRUE; -+ if (drv->bAddWepKey) -+ ieee8021x_required_key = FALSE; -+ } else -+ ieee8021xMode = FALSE; -+ -+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, -+ (char *) &ieee8021x_required_key, -+ sizeof(BOOLEAN)) < 0) { -+ wpa_printf(MSG_DEBUG, "ERROR: Failed to set " -+ "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", -+ (int) ieee8021x_required_key); -+ } else { -+ wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s", -+ ieee8021x_required_key ? "TRUE" : "FALSE"); -+ } -+ -+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, -+ (char *) &ieee8021xMode, sizeof(BOOLEAN)) < -+ 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "OID_802_11_SET_IEEE8021X(%d)", -+ (int) ieee8021xMode); -+ } -+ -+ ralink_set_encr_type(drv, encr); -+ -+ if ((ieee8021xMode == FALSE) && -+ (encr == Ndis802_11Encryption1Enabled)) { -+ /* static WEP */ -+ int enabled = 0; -+ if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED, -+ (char *) &enabled, sizeof(enabled)) -+ < 0) { -+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set " -+ "OID_802_11_DROP_UNENCRYPTED(%d)", -+ (int) encr); -+ } -+ } -+ } -+ -+ return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len); -+} -+ -+static int -+wpa_driver_ralink_set_countermeasures(void *priv, int enabled) -+{ -+ struct wpa_driver_ralink_data *drv = priv; -+ if (drv->g_driver_down == 1) -+ return -1; -+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); -+ return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled, -+ sizeof(int)); -+} -+ -+const struct wpa_driver_ops wpa_driver_ralink_ops = { -+ .name = "ralink", -+ .desc = "Ralink Wireless Client driver", -+ .get_bssid = wpa_driver_ralink_get_bssid, -+ .get_ssid = wpa_driver_ralink_get_ssid, -+ .set_key = wpa_driver_ralink_set_key, -+ .init = wpa_driver_ralink_init, -+ .deinit = wpa_driver_ralink_deinit, -+ .set_countermeasures = wpa_driver_ralink_set_countermeasures, -+ .scan2 = wpa_driver_ralink_scan, -+ .get_scan_results2 = wpa_driver_ralink_get_scan_results, -+ .deauthenticate = wpa_driver_ralink_deauthenticate, -+ .disassociate = wpa_driver_ralink_disassociate, -+ .associate = wpa_driver_ralink_associate, -+ .add_pmkid = wpa_driver_ralink_add_pmkid, -+ .remove_pmkid = wpa_driver_ralink_remove_pmkid, -+ .flush_pmkid = wpa_driver_ralink_flush_pmkid, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.h -new file mode 100644 -index 0000000000000..d13df28de4564 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_ralink.h -@@ -0,0 +1,383 @@ -+/* -+ * WPA Supplicant - driver_ralink exported functions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * Copyright (c) 2007, Snowpin Lee -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+// Ralink defined OIDs -+#if WIRELESS_EXT <= 11 -+#ifndef SIOCDEVPRIVATE -+#define SIOCDEVPRIVATE 0x8BE0 -+#endif -+#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -+#endif -+ -+#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E) -+#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02) -+ -+// IEEE 802.11 OIDs & Ralink defined OIDs ****** -+ -+// (RaConfig Set/QueryInform) ==> -+#define OID_GET_SET_TOGGLE 0x8000 -+ -+#define OID_802_11_ADD_WEP 0x0112 -+#define OID_802_11_REMOVE_WEP 0x0113 -+#define OID_802_11_DISASSOCIATE 0x0114 -+#define OID_802_11_PRIVACY_FILTER 0x0118 -+#define OID_802_11_ASSOCIATION_INFORMATION 0x011E -+#define OID_802_11_BSSID_LIST_SCAN 0x0508 -+#define OID_802_11_SSID 0x0509 -+#define OID_802_11_BSSID 0x050A -+#define OID_802_11_WEP_STATUS 0x0510 -+#define OID_802_11_AUTHENTICATION_MODE 0x0511 -+#define OID_802_11_INFRASTRUCTURE_MODE 0x0512 -+#define OID_802_11_TX_POWER_LEVEL 0x0517 -+#define OID_802_11_REMOVE_KEY 0x0519 -+#define OID_802_11_ADD_KEY 0x0520 -+#define OID_802_11_DEAUTHENTICATION 0x0526 -+#define OID_802_11_DROP_UNENCRYPTED 0x0527 -+#define OID_802_11_BSSID_LIST 0x0609 -+#define OID_802_3_CURRENT_ADDRESS 0x060A -+#define OID_SET_COUNTERMEASURES 0x0616 -+#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode -+#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode -+#define OID_802_11_PMKID 0x0620 -+#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support -+#define RT_OID_WE_VERSION_COMPILED 0x0622 -+#define RT_OID_NEW_DRIVER 0x0623 -+#define RT_OID_WPS_PROBE_REQ_IE 0x0625 -+ -+#define PACKED __attribute__ ((packed)) -+ -+//wpa_supplicant event flags -+#define RT_ASSOC_EVENT_FLAG 0x0101 -+#define RT_DISASSOC_EVENT_FLAG 0x0102 -+#define RT_REQIE_EVENT_FLAG 0x0103 -+#define RT_RESPIE_EVENT_FLAG 0x0104 -+#define RT_ASSOCINFO_EVENT_FLAG 0x0105 -+#define RT_PMKIDCAND_FLAG 0x0106 -+#define RT_INTERFACE_DOWN 0x0107 -+#define RT_INTERFACE_UP 0x0108 -+ -+// -+// IEEE 802.11 Structures and definitions -+// -+// new types for Media Specific Indications -+ -+#ifndef ULONG -+#define CHAR char -+#define INT int -+#define SHORT int -+#define UINT u32 -+#undef ULONG -+//#define ULONG u32 -+#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */ -+#define USHORT unsigned short -+#define UCHAR unsigned char -+ -+#define uint32 u32 -+#define uint8 u8 -+ -+ -+#define BOOLEAN u8 -+//#define LARGE_INTEGER s64 -+#define VOID void -+#define LONG long -+#define LONGLONG s64 -+#define ULONGLONG u64 -+typedef VOID *PVOID; -+typedef CHAR *PCHAR; -+typedef UCHAR *PUCHAR; -+typedef USHORT *PUSHORT; -+typedef LONG *PLONG; -+typedef ULONG *PULONG; -+ -+typedef union _LARGE_INTEGER { -+ struct { -+ ULONG LowPart; -+ LONG HighPart; -+ }vv; -+ struct { -+ ULONG LowPart; -+ LONG HighPart; -+ } u; -+ s64 QuadPart; -+} LARGE_INTEGER; -+ -+#endif -+ -+#define NDIS_802_11_LENGTH_SSID 32 -+#define NDIS_802_11_LENGTH_RATES 8 -+#define NDIS_802_11_LENGTH_RATES_EX 16 -+#define MAX_LEN_OF_SSID 32 -+#define MAC_ADDR_LEN 6 -+ -+typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; -+ -+// mask for authentication/integrity fields -+#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f -+ -+#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 -+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 -+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 -+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E -+ -+// Added new types for OFDM 5G and 2.4G -+typedef enum _NDIS_802_11_NETWORK_TYPE -+{ -+ Ndis802_11FH, -+ Ndis802_11DS, -+ Ndis802_11OFDM5, -+ Ndis802_11OFDM24, -+ Ndis802_11Automode, -+ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound -+} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE; -+ -+// -+// Received Signal Strength Indication -+// -+typedef LONG NDIS_802_11_RSSI; // in dBm -+ -+typedef struct _NDIS_802_11_CONFIGURATION_FH -+{ -+ ULONG Length; // Length of structure -+ ULONG HopPattern; // As defined by 802.11, MSB set -+ ULONG HopSet; // to one if non-802.11 -+ ULONG DwellTime; // units are Kusec -+} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH; -+ -+typedef struct _NDIS_802_11_CONFIGURATION -+{ -+ ULONG Length; // Length of structure -+ ULONG BeaconPeriod; // units are Kusec -+ ULONG ATIMWindow; // units are Kusec -+ ULONG DSConfig; // Frequency, units are kHz -+ NDIS_802_11_CONFIGURATION_FH FHConfig; -+} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION; -+ -+typedef ULONG NDIS_802_11_KEY_INDEX; -+typedef ULONGLONG NDIS_802_11_KEY_RSC; -+ -+// Key mapping keys require a BSSID -+typedef struct _NDIS_802_11_KEY -+{ -+ UINT Length; // Length of this structure -+ UINT KeyIndex; -+ UINT KeyLength; // length of key in bytes -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ NDIS_802_11_KEY_RSC KeyRSC; -+ UCHAR KeyMaterial[1]; // variable length depending on above field -+} NDIS_802_11_KEY, *PNDIS_802_11_KEY; -+ -+typedef struct _NDIS_802_11_REMOVE_KEY -+{ -+ UINT Length; // Length of this structure -+ UINT KeyIndex; -+ NDIS_802_11_MAC_ADDRESS BSSID; -+} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY; -+ -+typedef struct PACKED _NDIS_802_11_WEP -+{ -+ UINT Length; // Length of this structure -+ UINT KeyIndex; // 0 is the per-client key, 1-N are the -+ // global keys -+ UINT KeyLength; // length of key in bytes -+ UCHAR KeyMaterial[1];// variable length depending on above field -+} NDIS_802_11_WEP, *PNDIS_802_11_WEP; -+ -+ -+typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE -+{ -+ Ndis802_11IBSS, -+ Ndis802_11Infrastructure, -+ Ndis802_11AutoUnknown, -+ Ndis802_11InfrastructureMax // Not a real value, defined as upper bound -+} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE; -+ -+// PMKID Structures -+typedef UCHAR NDIS_802_11_PMKID_VALUE[16]; -+ -+typedef struct _BSSID_INFO -+{ -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ NDIS_802_11_PMKID_VALUE PMKID; -+} BSSID_INFO, *PBSSID_INFO; -+ -+typedef struct _NDIS_802_11_PMKID -+{ -+ ULONG Length; -+ ULONG BSSIDInfoCount; -+ BSSID_INFO BSSIDInfo[1]; -+} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID; -+ -+//Added new types for PMKID Candidate lists. -+typedef struct _PMKID_CANDIDATE { -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ ULONG Flags; -+} PMKID_CANDIDATE, *PPMKID_CANDIDATE; -+ -+typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST -+{ -+ ULONG Version; // Version of the structure -+ ULONG NumCandidates; // No. of pmkid candidates -+ PMKID_CANDIDATE CandidateList[1]; -+} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; -+ -+//Flags for PMKID Candidate list structure -+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 -+ -+// Add new authentication modes -+typedef enum _NDIS_802_11_AUTHENTICATION_MODE -+{ -+ Ndis802_11AuthModeOpen, -+ Ndis802_11AuthModeShared, -+ Ndis802_11AuthModeAutoSwitch, -+ Ndis802_11AuthModeWPA, -+ Ndis802_11AuthModeWPAPSK, -+ Ndis802_11AuthModeWPANone, -+ Ndis802_11AuthModeWPA2, -+ Ndis802_11AuthModeWPA2PSK, -+ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound -+} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE; -+ -+typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates -+typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates -+ -+typedef struct PACKED _NDIS_802_11_SSID -+{ -+ INT SsidLength; // length of SSID field below, in bytes; -+ // this can be zero. -+ UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field -+} NDIS_802_11_SSID, *PNDIS_802_11_SSID; -+ -+ -+typedef struct PACKED _NDIS_WLAN_BSSID -+{ -+ ULONG Length; // Length of this structure -+ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID -+ UCHAR Reserved[2]; -+ NDIS_802_11_SSID Ssid; // SSID -+ ULONG Privacy; // WEP encryption requirement -+ NDIS_802_11_RSSI Rssi; // receive signal -+ // strength in dBm -+ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; -+ NDIS_802_11_CONFIGURATION Configuration; -+ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; -+ NDIS_802_11_RATES SupportedRates; -+} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID; -+ -+typedef struct PACKED _NDIS_802_11_BSSID_LIST -+{ -+ UINT NumberOfItems; // in list below, at least 1 -+ NDIS_WLAN_BSSID Bssid[1]; -+} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST; -+ -+// Added Capabilities, IELength and IEs for each BSSID -+typedef struct PACKED _NDIS_WLAN_BSSID_EX -+{ -+ ULONG Length; // Length of this structure -+ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID -+ UCHAR Reserved[2]; -+ NDIS_802_11_SSID Ssid; // SSID -+ UINT Privacy; // WEP encryption requirement -+ NDIS_802_11_RSSI Rssi; // receive signal -+ // strength in dBm -+ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; -+ NDIS_802_11_CONFIGURATION Configuration; -+ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; -+ NDIS_802_11_RATES_EX SupportedRates; -+ ULONG IELength; -+ UCHAR IEs[1]; -+} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX; -+ -+typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX -+{ -+ UINT NumberOfItems; // in list below, at least 1 -+ NDIS_WLAN_BSSID_EX Bssid[1]; -+} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX; -+ -+typedef struct PACKED _NDIS_802_11_FIXED_IEs -+{ -+ UCHAR Timestamp[8]; -+ USHORT BeaconInterval; -+ USHORT Capabilities; -+} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs; -+ -+// Added new encryption types -+// Also aliased typedef to new name -+typedef enum _NDIS_802_11_WEP_STATUS -+{ -+ Ndis802_11WEPEnabled, -+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, -+ Ndis802_11WEPDisabled, -+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, -+ Ndis802_11WEPKeyAbsent, -+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, -+ Ndis802_11WEPNotSupported, -+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, -+ Ndis802_11Encryption2Enabled, -+ Ndis802_11Encryption2KeyAbsent, -+ Ndis802_11Encryption3Enabled, -+ Ndis802_11Encryption3KeyAbsent -+} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS, -+ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS; -+ -+typedef enum _NDIS_802_11_RELOAD_DEFAULTS -+{ -+ Ndis802_11ReloadWEPKeys -+} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS; -+ -+#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 -+#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 -+#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 -+ -+#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 -+#define NDIS_802_11_AI_RESFI_STATUSCODE 2 -+#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 -+ -+typedef struct _NDIS_802_11_AI_REQFI -+{ -+ USHORT Capabilities; -+ USHORT ListenInterval; -+ NDIS_802_11_MAC_ADDRESS CurrentAPAddress; -+} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI; -+ -+typedef struct _NDIS_802_11_AI_RESFI -+{ -+ USHORT Capabilities; -+ USHORT StatusCode; -+ USHORT AssociationId; -+} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI; -+ -+typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION -+{ -+ ULONG Length; -+ USHORT AvailableRequestFixedIEs; -+ NDIS_802_11_AI_REQFI RequestFixedIEs; -+ ULONG RequestIELength; -+ ULONG OffsetRequestIEs; -+ USHORT AvailableResponseFixedIEs; -+ NDIS_802_11_AI_RESFI ResponseFixedIEs; -+ ULONG ResponseIELength; -+ ULONG OffsetResponseIEs; -+} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION; -+ -+struct ndis_pmkid_entry { -+ struct ndis_pmkid_entry *next; -+ u8 bssid[ETH_ALEN]; -+ u8 pmkid[16]; -+}; -+ -+typedef struct _MLME_DEAUTH_REQ_STRUCT { -+ UCHAR Addr[MAC_ADDR_LEN]; -+ USHORT Reason; -+} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_roboswitch.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_roboswitch.c -new file mode 100644 -index 0000000000000..c014b962f477c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_roboswitch.c -@@ -0,0 +1,480 @@ -+/* -+ * WPA Supplicant - roboswitch driver interface -+ * Copyright (c) 2008-2009 Jouke Witteveen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "driver.h" -+#include "l2_packet/l2_packet.h" -+ -+#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */ -+ -+/* MII access registers */ -+#define ROBO_MII_PAGE 0x10 /* MII page register */ -+#define ROBO_MII_ADDR 0x11 /* MII address register */ -+#define ROBO_MII_DATA_OFFSET 0x18 /* Start of MII data registers */ -+ -+#define ROBO_MII_PAGE_ENABLE 0x01 /* MII page op code */ -+#define ROBO_MII_ADDR_WRITE 0x01 /* MII address write op code */ -+#define ROBO_MII_ADDR_READ 0x02 /* MII address read op code */ -+#define ROBO_MII_DATA_MAX 4 /* Consecutive MII data registers */ -+#define ROBO_MII_RETRY_MAX 10 /* Read attempts before giving up */ -+ -+/* Page numbers */ -+#define ROBO_ARLCTRL_PAGE 0x04 /* ARL control page */ -+#define ROBO_VLAN_PAGE 0x34 /* VLAN page */ -+ -+/* ARL control page registers */ -+#define ROBO_ARLCTRL_CONF 0x00 /* ARL configuration register */ -+#define ROBO_ARLCTRL_ADDR_1 0x10 /* Multiport address 1 */ -+#define ROBO_ARLCTRL_VEC_1 0x16 /* Multiport vector 1 */ -+#define ROBO_ARLCTRL_ADDR_2 0x20 /* Multiport address 2 */ -+#define ROBO_ARLCTRL_VEC_2 0x26 /* Multiport vector 2 */ -+ -+/* VLAN page registers */ -+#define ROBO_VLAN_ACCESS 0x08 /* VLAN table access register */ -+#define ROBO_VLAN_ACCESS_5350 0x06 /* VLAN table access register (5350) */ -+#define ROBO_VLAN_READ 0x0c /* VLAN read register */ -+#define ROBO_VLAN_MAX 0xff /* Maximum number of VLANs */ -+ -+ -+static const u8 pae_group_addr[ETH_ALEN] = -+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; -+ -+ -+struct wpa_driver_roboswitch_data { -+ void *ctx; -+ struct l2_packet_data *l2; -+ char ifname[IFNAMSIZ + 1]; -+ u8 own_addr[ETH_ALEN]; -+ struct ifreq ifr; -+ int fd, is_5350; -+ u16 ports; -+}; -+ -+ -+/* Copied from the kernel-only part of mii.h. */ -+static inline struct mii_ioctl_data *if_mii(struct ifreq *rq) -+{ -+ return (struct mii_ioctl_data *) &rq->ifr_ifru; -+} -+ -+ -+/* -+ * RoboSwitch uses 16-bit Big Endian addresses. -+ * The ordering of the words is reversed in the MII registers. -+ */ -+static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be) -+{ -+ int i; -+ for (i = 0; i < ETH_ALEN; i += 2) -+ be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i); -+} -+ -+ -+static u16 wpa_driver_roboswitch_mdio_read( -+ struct wpa_driver_roboswitch_data *drv, u8 reg) -+{ -+ struct mii_ioctl_data *mii = if_mii(&drv->ifr); -+ -+ mii->phy_id = ROBO_PHY_ADDR; -+ mii->reg_num = reg; -+ -+ if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) { -+ perror("ioctl[SIOCGMIIREG]"); -+ return 0x00; -+ } -+ return mii->val_out; -+} -+ -+ -+static void wpa_driver_roboswitch_mdio_write( -+ struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val) -+{ -+ struct mii_ioctl_data *mii = if_mii(&drv->ifr); -+ -+ mii->phy_id = ROBO_PHY_ADDR; -+ mii->reg_num = reg; -+ mii->val_in = val; -+ -+ if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) { -+ perror("ioctl[SIOCSMIIREG"); -+ } -+} -+ -+ -+static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv, -+ u8 page, u8 reg, u8 op) -+{ -+ int i; -+ -+ /* set page number */ -+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE, -+ (page << 8) | ROBO_MII_PAGE_ENABLE); -+ /* set register address */ -+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op); -+ -+ /* check if operation completed */ -+ for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) { -+ if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3) -+ == 0) -+ return 0; -+ } -+ /* timeout */ -+ return -1; -+} -+ -+ -+static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv, -+ u8 page, u8 reg, u16 *val, int len) -+{ -+ int i; -+ -+ if (len > ROBO_MII_DATA_MAX || -+ wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0) -+ return -1; -+ -+ for (i = 0; i < len; ++i) { -+ val[i] = wpa_driver_roboswitch_mdio_read( -+ drv, ROBO_MII_DATA_OFFSET + i); -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv, -+ u8 page, u8 reg, u16 *val, int len) -+{ -+ int i; -+ -+ if (len > ROBO_MII_DATA_MAX) return -1; -+ for (i = 0; i < len; ++i) { -+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i, -+ val[i]); -+ } -+ return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE); -+} -+ -+ -+static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct wpa_driver_roboswitch_data *drv = priv; -+ -+ if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL && -+ os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) -+ drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14); -+} -+ -+ -+static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid) -+{ -+ ssid[0] = 0; -+ return 0; -+} -+ -+ -+static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid) -+{ -+ /* Report PAE group address as the "BSSID" for wired connection. */ -+ os_memcpy(bssid, pae_group_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+static int wpa_driver_roboswitch_get_capa(void *priv, -+ struct wpa_driver_capa *capa) -+{ -+ os_memset(capa, 0, sizeof(*capa)); -+ capa->flags = WPA_DRIVER_FLAGS_WIRED; -+ return 0; -+} -+ -+ -+static int wpa_driver_roboswitch_set_param(void *priv, const char *param) -+{ -+ struct wpa_driver_roboswitch_data *drv = priv; -+ char *sep; -+ -+ if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) { -+ sep = drv->ifname + os_strlen(drv->ifname); -+ *sep = '.'; -+ drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL, -+ wpa_driver_roboswitch_receive, drv, -+ 1); -+ if (drv->l2 == NULL) { -+ wpa_printf(MSG_INFO, "%s: Unable to listen on %s", -+ __func__, drv->ifname); -+ return -1; -+ } -+ *sep = '\0'; -+ l2_packet_get_own_addr(drv->l2, drv->own_addr); -+ } else { -+ wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__); -+ drv->l2 = NULL; -+ } -+ return 0; -+} -+ -+ -+static const char * wpa_driver_roboswitch_get_ifname(void *priv) -+{ -+ struct wpa_driver_roboswitch_data *drv = priv; -+ return drv->ifname; -+} -+ -+ -+static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv, -+ u16 ports, const u8 *addr) -+{ -+ u16 read1[3], read2[3], addr_be16[3]; -+ -+ wpa_driver_roboswitch_addr_be16(addr, addr_be16); -+ -+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_CONF, read1, 1) < 0) -+ return -1; -+ if (!(read1[0] & (1 << 4))) { -+ /* multiport addresses are not yet enabled */ -+ read1[0] |= 1 << 4; -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_1, &ports, 1); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_2, addr_be16, 3); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_2, &ports, 1); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_CONF, read1, 1); -+ } else { -+ /* if both multiport addresses are the same we can add */ -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_1, read1, 3); -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_2, read2, 3); -+ if (os_memcmp(read1, read2, 6) != 0) -+ return -1; -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_1, read1, 1); -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_2, read2, 1); -+ if (read1[0] != read2[0]) -+ return -1; -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_1, &ports, 1); -+ } -+ return 0; -+} -+ -+ -+static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv, -+ u16 ports, const u8 *addr) -+{ -+ u16 _read, addr_be16[3], addr_read[3], ports_read; -+ -+ wpa_driver_roboswitch_addr_be16(addr, addr_be16); -+ -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF, -+ &_read, 1); -+ /* If ARL control is disabled, there is nothing to leave. */ -+ if (!(_read & (1 << 4))) return -1; -+ -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_1, addr_read, 3); -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1, -+ &ports_read, 1); -+ /* check if we occupy multiport address 1 */ -+ if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) { -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_2, addr_read, 3); -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_2, &ports_read, 1); -+ /* and multiport address 2 */ -+ if (os_memcmp(addr_read, addr_be16, 6) == 0 && -+ ports_read == ports) { -+ _read &= ~(1 << 4); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_CONF, &_read, -+ 1); -+ } else { -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_1, -+ addr_read, 3); -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_1, -+ &ports_read, 1); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_2, -+ addr_read, 3); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_2, -+ &ports_read, 1); -+ } -+ } else { -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_2, addr_read, 3); -+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_2, &ports_read, 1); -+ /* or multiport address 2 */ -+ if (os_memcmp(addr_read, addr_be16, 6) == 0 && -+ ports_read == ports) { -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_ADDR_1, -+ addr_read, 3); -+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE, -+ ROBO_ARLCTRL_VEC_1, -+ &ports_read, 1); -+ } else return -1; -+ } -+ return 0; -+} -+ -+ -+static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_roboswitch_data *drv; -+ char *sep; -+ u16 vlan = 0, _read[2]; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) return NULL; -+ drv->ctx = ctx; -+ drv->own_addr[0] = '\0'; -+ -+ /* copy ifname and take a pointer to the second to last character */ -+ sep = drv->ifname + -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2; -+ /* find the '.' seperating and */ -+ while (sep > drv->ifname && *sep != '.') sep--; -+ if (sep <= drv->ifname) { -+ wpa_printf(MSG_INFO, "%s: No . pair in " -+ "interface name %s", __func__, drv->ifname); -+ os_free(drv); -+ return NULL; -+ } -+ *sep = '\0'; -+ while (*++sep) { -+ if (*sep < '0' || *sep > '9') { -+ wpa_printf(MSG_INFO, "%s: Invalid vlan specification " -+ "in interface name %s", __func__, ifname); -+ os_free(drv); -+ return NULL; -+ } -+ vlan *= 10; -+ vlan += *sep - '0'; -+ if (vlan > ROBO_VLAN_MAX) { -+ wpa_printf(MSG_INFO, "%s: VLAN out of range in " -+ "interface name %s", __func__, ifname); -+ os_free(drv); -+ return NULL; -+ } -+ } -+ -+ drv->fd = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->fd < 0) { -+ wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__); -+ os_free(drv); -+ return NULL; -+ } -+ -+ os_memset(&drv->ifr, 0, sizeof(drv->ifr)); -+ os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ); -+ if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) { -+ perror("ioctl[SIOCGMIIPHY]"); -+ os_free(drv); -+ return NULL; -+ } -+ if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) { -+ wpa_printf(MSG_INFO, "%s: Invalid phy address (not a " -+ "RoboSwitch?)", __func__); -+ os_free(drv); -+ return NULL; -+ } -+ -+ /* set and read back to see if the register can be used */ -+ _read[0] = ROBO_VLAN_MAX; -+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350, -+ _read, 1); -+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350, -+ _read + 1, 1); -+ drv->is_5350 = _read[0] == _read[1]; -+ -+ /* set the read bit */ -+ vlan |= 1 << 13; -+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, -+ drv->is_5350 ? ROBO_VLAN_ACCESS_5350 -+ : ROBO_VLAN_ACCESS, -+ &vlan, 1); -+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read, -+ drv->is_5350 ? 2 : 1); -+ if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) { -+ wpa_printf(MSG_INFO, "%s: Could not get port information for " -+ "VLAN %d", __func__, vlan & ~(1 << 13)); -+ os_free(drv); -+ return NULL; -+ } -+ drv->ports = _read[0] & 0x001F; -+ /* add the MII port */ -+ drv->ports |= 1 << 8; -+ if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) { -+ wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__); -+ os_free(drv); -+ return NULL; -+ } else { -+ wpa_printf(MSG_DEBUG, "%s: Added PAE group address to " -+ "RoboSwitch ARL", __func__); -+ } -+ -+ return drv; -+} -+ -+ -+static void wpa_driver_roboswitch_deinit(void *priv) -+{ -+ struct wpa_driver_roboswitch_data *drv = priv; -+ -+ if (drv->l2) { -+ l2_packet_deinit(drv->l2); -+ drv->l2 = NULL; -+ } -+ if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group", -+ __func__); -+ } -+ -+ close(drv->fd); -+ os_free(drv); -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_roboswitch_ops = { -+ .name = "roboswitch", -+ .desc = "wpa_supplicant roboswitch driver", -+ .get_ssid = wpa_driver_roboswitch_get_ssid, -+ .get_bssid = wpa_driver_roboswitch_get_bssid, -+ .get_capa = wpa_driver_roboswitch_get_capa, -+ .init = wpa_driver_roboswitch_init, -+ .deinit = wpa_driver_roboswitch_deinit, -+ .set_param = wpa_driver_roboswitch_set_param, -+ .get_ifname = wpa_driver_roboswitch_get_ifname, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtl.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtl.h -new file mode 100644 -index 0000000000000..c68052c460db8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtl.h -@@ -0,0 +1,113 @@ -+ -+#ifndef _DRIVER_RTL_H_ -+#define _DRIVER_RTL_H_ -+ -+ -+#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28) -+ -+#define IEEE_CRYPT_ALG_NAME_LEN (16) -+ -+/* RTL871X_IOCTL_HOSTAPD ioctl() cmd: */ -+enum { -+ RTL871X_HOSTAPD_FLUSH = 1, -+ RTL871X_HOSTAPD_ADD_STA = 2, -+ RTL871X_HOSTAPD_REMOVE_STA = 3, -+ RTL871X_HOSTAPD_GET_INFO_STA = 4, -+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ -+ RTL871X_HOSTAPD_GET_WPAIE_STA = 5, -+ RTL871X_SET_ENCRYPTION = 6, -+ RTL871X_GET_ENCRYPTION = 7, -+ RTL871X_HOSTAPD_SET_FLAGS_STA = 8, -+ RTL871X_HOSTAPD_GET_RID = 9, -+ RTL871X_HOSTAPD_SET_RID = 10, -+ RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR = 11, -+ RTL871X_HOSTAPD_SET_GENERIC_ELEMENT = 12, -+ RTL871X_HOSTAPD_MLME = 13, -+ RTL871X_HOSTAPD_SCAN_REQ = 14, -+ RTL871X_HOSTAPD_STA_CLEAR_STATS = 15, -+ RTL871X_HOSTAPD_SET_BEACON = 16, -+ RTL871X_HOSTAPD_SET_WPS_BEACON = 17, -+ RTL871X_HOSTAPD_SET_WPS_PROBE_RESP = 18, -+ RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP = 19, -+}; -+ -+typedef struct ieee_param { -+ u32 cmd; -+ u8 sta_addr[ETH_ALEN]; -+ union { -+ struct { -+ u8 name; -+ u32 value; -+ } wpa_param; -+ struct { -+ u32 len; -+ u8 reserved[32]; -+ u8 data[0]; -+ } wpa_ie; -+ struct{ -+ int command; -+ int reason_code; -+ } mlme; -+ struct { -+ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; -+ u8 set_tx; -+ u32 err; -+ u8 idx; -+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ -+ u16 key_len; -+ u8 key[0]; -+ } crypt; -+ struct { -+ u16 aid; -+ u16 capability; -+ int flags; -+ u8 tx_supp_rates[16]; -+ //struct ieee80211_ht_capability ht_cap; -+ struct ieee80211_ht_capabilities ht_cap; -+ } add_sta; -+ struct { -+ u8 reserved[2];//for set max_num_sta -+ u8 buf[0]; -+ } bcn_ie; -+ -+ } u; -+ -+} ieee_param; -+ -+ -+ -+#define IEEE80211_CCK_RATE_LEN 4 -+#define IEEE80211_OFDM_RATE_LEN 8 -+ -+#define IEEE80211_CCK_RATE_1MB 0x02 -+#define IEEE80211_CCK_RATE_2MB 0x04 -+#define IEEE80211_CCK_RATE_5MB 0x0B -+#define IEEE80211_CCK_RATE_11MB 0x16 -+#define IEEE80211_OFDM_RATE_6MB 0x0C -+#define IEEE80211_OFDM_RATE_9MB 0x12 -+#define IEEE80211_OFDM_RATE_12MB 0x18 -+#define IEEE80211_OFDM_RATE_18MB 0x24 -+#define IEEE80211_OFDM_RATE_24MB 0x30 -+#define IEEE80211_OFDM_RATE_36MB 0x48 -+#define IEEE80211_OFDM_RATE_48MB 0x60 -+#define IEEE80211_OFDM_RATE_54MB 0x6C -+#define IEEE80211_BASIC_RATE_MASK 0x80 -+ -+#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) -+#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) -+#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) -+#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) -+#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) -+#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) -+#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) -+#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) -+#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) -+#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) -+#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) -+#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) -+ -+#define IEEE80211_CCK_RATES_MASK 0x0000000F -+#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 -+ -+#endif -+ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtw.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtw.c -new file mode 100644 -index 0000000000000..0c0c777f15a3d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_rtw.c -@@ -0,0 +1,1902 @@ -+/* -+ * hostapd / Driver interface for rtl871x driver -+ * Copyright (c) 2010, -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+//#define CONFIG_MGNT_L2SOCK 1 -+#define CONFIG_MLME_OFFLOAD 1 -+ -+ -+#include "includes.h" -+#include -+#include -+ -+#include "common.h" -+ -+#include "wireless_copy.h" -+ -+#include "driver.h" -+#include "eloop.h" -+#include "priv_netlink.h" -+#include "l2_packet/l2_packet.h" -+#include "common/ieee802_11_defs.h" -+#include "netlink.h" -+#include "linux_ioctl.h" -+ -+//#include "../src/ap/hostapd.h" -+//#include "../src/ap/ap_config.h" -+#include "ap/hostapd.h" -+#include "ap/ap_config.h" -+ -+#ifdef USE_KERNEL_HEADERS -+/* compat-wireless does not include linux/compiler.h to define __user, so -+ * define it here */ -+#ifndef __user -+#define __user -+#endif /* __user */ -+#include -+#include -+#include /* The L2 protocols */ -+#include -+#include -+#else /* USE_KERNEL_HEADERS */ -+#include -+#include -+//#include "wireless_copy.h" -+#endif /* USE_KERNEL_HEADERS */ -+ -+//#include -+ -+ -+#ifndef ETH_P_80211_RAW -+#define ETH_P_80211_RAW 0x0019 -+#endif -+ -+#if 0 -+#include "hostapd.h" -+#include "driver.h" -+#include "ieee802_1x.h" -+#include "eloop.h" -+#include "priv_netlink.h" -+#include "sta_info.h" -+#include "l2_packet/l2_packet.h" -+ -+#include "wpa.h" -+#include "accounting.h" -+#include "ieee802_11.h" -+#include "hw_features.h" -+#include "radius/radius.h" -+#endif -+ -+#include "driver_rtl.h" -+ -+ -+//static int rtl871x_sta_remove_ops(void *priv, const u8 *addr); -+ -+struct rtl871x_driver_data { -+ struct hostapd_data *hapd; -+ -+ char iface[IFNAMSIZ + 1]; -+ int ifindex; -+ struct l2_packet_data *l2_sock;/* socket for sending eapol frames*/ -+ struct l2_packet_data *l2_sock_recv;/* raw packet recv socket from bridge interface*/ -+#ifdef CONFIG_MGNT_L2SOCK -+ struct l2_packet_data *mgnt_l2_sock; /* socket for tx/rx management frames*/ -+#else -+ int mgnt_sock;/* socket for tx/rx management frames*/ -+#endif -+ int ioctl_sock; /* socket for ioctl() use */ -+ int wext_sock; /* socket for wireless events */ -+ -+ struct netlink_data *netlink; -+ -+ int we_version; -+ -+ u8 hw_mac[ETH_ALEN]; -+ -+ u8 acct_mac[ETH_ALEN]; -+ -+ struct hostap_sta_driver_data acct_data; -+ -+}; -+ -+/* -+static const char *ether_sprintf(const u8 *addr) -+{ -+ static char buf[sizeof(MACSTR)]; -+ -+ if (addr != NULL) -+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); -+ else -+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); -+ -+ return buf; -+} -+*/ -+ -+#ifndef CONFIG_MLME_OFFLOAD -+static int rtl871x_set_iface_flags(void *priv, int dev_up) -+{ -+ struct rtl871x_driver_data *drv = priv; -+ struct ifreq ifr; -+ -+ wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up); -+ -+ if (drv->mgnt_sock < 0) -+ return -1; -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ //os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); -+ //os_strlcpy(ifr.ifr_name, "mgnt.wlan", IFNAMSIZ); -+ snprintf(ifr.ifr_name, IFNAMSIZ, "mgnt.%s", "wlan0"); -+ -+ if (ioctl(drv->mgnt_sock, SIOCGIFFLAGS, &ifr) != 0) { -+ perror("ioctl[SIOCGIFFLAGS]"); -+ return -1; -+ } -+ -+ if (dev_up) -+ ifr.ifr_flags |= IFF_UP; -+ else -+ ifr.ifr_flags &= ~IFF_UP; -+ -+ if (ioctl(drv->mgnt_sock, SIOCSIFFLAGS, &ifr) != 0) { -+ perror("ioctl[SIOCSIFFLAGS]"); -+ return -1; -+ } -+ -+#if 0 -+ if (dev_up) { -+ memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ); -+ ifr.ifr_mtu = HOSTAPD_MTU; -+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) { -+ perror("ioctl[SIOCSIFMTU]"); -+ printf("Setting MTU failed - trying to survive with " -+ "current value\n"); -+ } -+ } -+#endif -+ -+ return 0; -+} -+#endif -+ -+static int rtl871x_hostapd_ioctl(struct rtl871x_driver_data *drv, ieee_param *param, int len) -+{ -+ struct iwreq iwr; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) param; -+ iwr.u.data.length = len; -+ -+ if (ioctl(drv->ioctl_sock, RTL_IOCTL_HOSTAPD, &iwr) < 0) { -+ perror("ioctl[RTL_IOCTL_HOSTAPD]"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int rtl871x_set_mode(struct rtl871x_driver_data *drv, u32 mode) -+{ -+ struct iwreq iwr; -+ -+ if (drv->ioctl_sock < 0) -+ return -1; -+ -+ memset(&iwr, 0, sizeof(iwr)); -+ -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ -+ //iwr.u.mode = IW_MODE_MASTER; -+ iwr.u.mode = mode; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMODE]"); -+ printf("Could not set interface to mode(%d)!\n", mode); -+ return -1; -+ } -+ -+ return 0; -+ -+} -+ -+/* -+static int rtl871x_notif_assoc(struct hostapd_data *hapd, const u8 *addr, -+ const u8 *ie, size_t ielen) -+{ -+ struct sta_info *sta; -+ int new_assoc, res; -+ -+ //hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, -+ // HOSTAPD_LEVEL_INFO, "associated"); -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta) { -+ accounting_sta_stop(hapd, sta); -+ } else { -+ sta = ap_sta_add(hapd, addr); -+ if (sta == NULL) -+ { -+ rtl871x_sta_remove_ops(hapd->drv_priv, addr); -+ return -1; -+ } -+ } -+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); -+ -+ if (hapd->conf->wpa) { -+ if (ie == NULL || ielen == 0) { -+ if (hapd->conf->wps_state) { -+ wpa_printf(MSG_DEBUG, "STA did not include " -+ "WPA/RSN IE in (Re)Association " -+ "Request - possible WPS use"); -+ sta->flags |= WLAN_STA_MAYBE_WPS; -+ goto skip_wpa_check; -+ } -+ -+ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); -+ return -1; -+ } -+ if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && -+ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { -+ sta->flags |= WLAN_STA_WPS; -+ goto skip_wpa_check; -+ } -+ -+ if (sta->wpa_sm == NULL) -+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, -+ sta->addr); -+ if (sta->wpa_sm == NULL) { -+ wpa_printf(MSG_ERROR, "Failed to initialize WPA state " -+ "machine"); -+ return -1; -+ } -+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, -+ ie, ielen, NULL, 0); -+ if (res != WPA_IE_OK) { -+ wpa_printf(MSG_DEBUG, "WPA/RSN information element " -+ "rejected? (res %u)", res); -+ wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); -+ return -1; -+ } -+ } else if (hapd->conf->wps_state) { -+ if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && -+ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { -+ sta->flags |= WLAN_STA_WPS; -+ } else -+ sta->flags |= WLAN_STA_MAYBE_WPS; -+ } -+skip_wpa_check: -+ -+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; -+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; -+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); -+ -+ hostapd_new_assoc_sta(hapd, sta, !new_assoc); -+ -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); -+ -+ return 0; -+} -+*/ -+ -+static int rtl871x_get_sta_wpaie(struct rtl871x_driver_data *drv, u8 *iebuf, u8 *addr) -+{ -+ struct ieee_param param; -+ -+ printf("+%s, " MACSTR " is sta's address\n", __func__, MAC2STR(addr)); -+ -+ memset(¶m, 0, sizeof(param)); -+ -+ param.cmd = RTL871X_HOSTAPD_GET_WPAIE_STA; -+ -+ memcpy(param.sta_addr, addr, ETH_ALEN); -+ -+ if (rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param))) { -+ printf("Could not get sta wpaie from kernel driver.\n"); -+ return -1; -+ } -+ -+ -+ if(param.u.wpa_ie.len > 32) -+ return -1; -+ -+ memcpy(iebuf, param.u.wpa_ie.reserved, param.u.wpa_ie.len); -+ -+ return 0; -+ -+} -+ -+static int rtl871x_del_sta(struct rtl871x_driver_data *drv, u8 *addr) -+{ -+ struct hostapd_data *hapd = drv->hapd; -+ -+#if 1 -+ -+ //union wpa_event_data event; -+ //os_memset(&event, 0, sizeof(event)); -+ //event.disassoc_info.addr = addr; -+ //wpa_supplicant_event(hapd, EVENT_DISASSOC, &event); -+ -+ drv_event_disassoc(hapd, addr); -+ -+#else -+ -+ struct sta_info *sta; -+ -+ //hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, -+ // HOSTAPD_LEVEL_INFO, "disassociated"); -+ -+ sta = ap_get_sta(hapd, addr); -+ if (sta != NULL) -+ { -+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); -+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); -+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; -+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); -+ ap_free_sta(hapd, sta); -+ } -+ else -+ { -+ wpa_printf(MSG_DEBUG, "Disassociation notification for " -+ "unknown STA " MACSTR, MAC2STR(addr)); -+ } -+#endif -+ -+ return 0; -+ -+} -+ -+static int rtl871x_new_sta(struct rtl871x_driver_data *drv, u8 *addr) -+{ -+ struct hostapd_data *hapd = drv->hapd; -+ //struct ieee80211req_wpaie ie; -+ int ielen = 0, res=0; -+ //u8 *iebuf = NULL; -+ u8 iebuf[32], *piebuf=NULL; -+ -+ /* -+ * Fetch negotiated WPA/RSN parameters from the driver. -+ */ -+ //memset(&ie, 0, sizeof(ie)); -+ //memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); -+ memset(iebuf, 0 , sizeof(iebuf)); -+ if (rtl871x_get_sta_wpaie(drv, iebuf, addr)) { -+ //if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) { -+ -+ wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s", -+ __func__, strerror(errno)); -+ goto no_ie; -+ } -+ -+ //wpa_hexdump(MSG_MSGDUMP, "req WPA IE", -+ // ie.wpa_ie, IEEE80211_MAX_OPT_IE); -+ -+ //wpa_hexdump(MSG_MSGDUMP, "req RSN IE", -+ // ie.rsn_ie, IEEE80211_MAX_OPT_IE); -+ -+ //iebuf = ie.wpa_ie; -+ -+/* -+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC) -+ iebuf[1] = 0; -+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) { -+ iebuf = ie.rsn_ie; -+ if (iebuf[0] != WLAN_EID_RSN) -+ iebuf[1] = 0; -+ } -+*/ -+ -+ if ((iebuf[0] == WLAN_EID_VENDOR_SPECIFIC) || (iebuf[0] == WLAN_EID_RSN) ) -+ { -+ piebuf = iebuf; -+ ielen = iebuf[1]; -+ -+ if (ielen == 0) -+ piebuf = NULL; -+ else -+ ielen += 2; -+ } -+ -+no_ie: -+ -+ //res = rtl871x_notif_assoc(hapd, addr, piebuf, ielen); -+ //drv_event_assoc(hapd, addr, piebuf, ielen); -+ drv_event_assoc(hapd, addr, piebuf, ielen, 0); -+ -+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { -+ /* Cached accounting data is not valid anymore. */ -+ memset(drv->acct_mac, 0, ETH_ALEN); -+ memset(&drv->acct_data, 0, sizeof(drv->acct_data)); -+ } -+ -+ return res; -+ -+} -+ -+static void rtl871x_wireless_event_wireless(struct rtl871x_driver_data *drv, -+ char *data, int len) -+{ -+ struct iw_event iwe_buf, *iwe = &iwe_buf; -+ char *pos, *end, *custom, *buf; -+ -+ pos = data; -+ end = data + len; -+ -+ while (pos + IW_EV_LCP_LEN <= end) { -+ /* Event data may be unaligned, so make a local, aligned copy -+ * before processing. */ -+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); -+ wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d", -+ iwe->cmd, iwe->len); -+ if (iwe->len <= IW_EV_LCP_LEN) -+ return; -+ -+ custom = pos + IW_EV_POINT_LEN; -+ if (drv->we_version > 18 && -+ (iwe->cmd == IWEVMICHAELMICFAILURE || -+ iwe->cmd == IWEVCUSTOM)) { -+ /* WE-19 removed the pointer from struct iw_point */ -+ char *dpos = (char *) &iwe_buf.u.data.length; -+ int dlen = dpos - (char *) &iwe_buf; -+ memcpy(dpos, pos + IW_EV_LCP_LEN, -+ sizeof(struct iw_event) - dlen); -+ } else { -+ memcpy(&iwe_buf, pos, sizeof(struct iw_event)); -+ custom += IW_EV_POINT_OFF; -+ } -+ -+ //printf("got wireless event, iwe->cmd=%d\n", iwe->cmd); -+ -+ switch (iwe->cmd) { -+ case IWEVEXPIRED: -+ rtl871x_del_sta(drv, (u8 *)iwe->u.addr.sa_data); -+ break; -+ case IWEVREGISTERED: -+ if(rtl871x_new_sta(drv, (u8 *)iwe->u.addr.sa_data)) -+ { -+ printf("Failed to add new sta: "MACSTR" \n", MAC2STR((u8 *)iwe->u.addr.sa_data)); -+ } -+ break; -+ case IWEVCUSTOM: -+ if (custom + iwe->u.data.length > end) -+ return; -+ buf = malloc(iwe->u.data.length + 1); -+ if (buf == NULL) -+ return; /* XXX */ -+ memcpy(buf, custom, iwe->u.data.length); -+ buf[iwe->u.data.length] = '\0'; -+ //madwifi_wireless_event_wireless_custom(drv, buf); -+ free(buf); -+ break; -+ } -+ -+ pos += iwe->len; -+ } -+ -+} -+ -+#if 1 -+static void rtl871x_wireless_event_rtm_newlink(void *ctx, -+ struct ifinfomsg *ifi, u8 *buf, size_t len) -+{ -+ struct rtl871x_driver_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ if (ifi->ifi_index != drv->ifindex) -+ return; -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_WIRELESS) { -+ rtl871x_wireless_event_wireless( -+ drv, ((char *) attr) + rta_len, -+ attr->rta_len - rta_len); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+ -+#else -+static void rtl871x_wireless_event_rtm_newlink(struct rtl871x_driver_data *drv, -+ struct nlmsghdr *h, int len) -+{ -+ struct ifinfomsg *ifi; -+ int attrlen, nlmsg_len, rta_len; -+ struct rtattr * attr; -+ -+ if (len < (int) sizeof(*ifi)) -+ return; -+ -+ ifi = NLMSG_DATA(h); -+ -+ if (ifi->ifi_index != drv->ifindex) -+ return; -+ -+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg)); -+ -+ attrlen = h->nlmsg_len - nlmsg_len; -+ if (attrlen < 0) -+ return; -+ -+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_WIRELESS) { -+ rtl871x_wireless_event_wireless( -+ drv, ((char *) attr) + rta_len, -+ attr->rta_len - rta_len); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+#endif -+ -+/* -+static void rtl871x_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ char buf[256];//!!! -+ int left; -+ struct sockaddr_nl from; -+ socklen_t fromlen; -+ struct nlmsghdr *h; -+ struct rtl871x_driver_data *drv = eloop_ctx; -+ -+ //printf("+rtl871x_wireless_event_receive\n"); -+ -+ fromlen = sizeof(from); -+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, -+ (struct sockaddr *) &from, &fromlen); -+ if (left < 0) { -+ if (errno != EINTR && errno != EAGAIN) -+ perror("recvfrom(netlink)"); -+ return; -+ } -+ -+ h = (struct nlmsghdr *)buf; -+ while (left >= (int) sizeof(*h)) { -+ int len, plen; -+ -+ len = h->nlmsg_len; -+ plen = len - sizeof(*h);//payload len -+ if (len > left || plen < 0) { -+ printf("Malformed netlink message: " -+ "len=%d left=%d plen=%d\n", -+ len, left, plen); -+ break; -+ } -+ -+ switch (h->nlmsg_type) { -+ case RTM_NEWLINK: -+ rtl871x_wireless_event_rtm_newlink(drv, h, plen); -+ break; -+ } -+ -+ len = NLMSG_ALIGN(len); -+ left -= len; -+ h = (struct nlmsghdr *) ((char *) h + len); -+ } -+ -+ if (left > 0) { -+ printf("%d extra bytes in the end of netlink message\n", left); -+ } -+ -+} -+*/ -+ -+static int rtl871x_wireless_event_init(struct rtl871x_driver_data *drv) -+{ -+ struct netlink_config *cfg; -+ -+ //madwifi_get_we_version(drv); -+ -+ cfg = os_zalloc(sizeof(*cfg)); -+ if (cfg == NULL) -+ return -1; -+ cfg->ctx = drv; -+ cfg->newlink_cb = rtl871x_wireless_event_rtm_newlink; -+ drv->netlink = netlink_init(cfg); -+ if (drv->netlink == NULL) { -+ os_free(cfg); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/* -+static int rtl871x_wireless_event_init_ops(void *priv) -+{ -+ int s; -+ struct sockaddr_nl local; -+ struct rtl871x_driver_data *drv = priv; -+ -+ //madwifi_get_we_version(drv); -+ -+ drv->wext_sock = -1; -+ -+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); -+ if (s < 0) { -+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)"); -+ return -1; -+ } -+ -+ memset(&local, 0, sizeof(local)); -+ local.nl_family = AF_NETLINK; -+ local.nl_groups = RTMGRP_LINK; -+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) { -+ perror("bind(netlink)"); -+ close(s); -+ return -1; -+ } -+ -+ eloop_register_read_sock(s, rtl871x_wireless_event_receive, drv, NULL); -+ drv->wext_sock = s; -+ -+ return 0; -+ -+} -+ -+static void rtl871x_wireless_event_deinit_ops(void *priv) -+{ -+ struct rtl871x_driver_data *drv = priv; -+ -+ if (drv != NULL) { -+ if (drv->wext_sock < 0) -+ return; -+ eloop_unregister_read_sock(drv->wext_sock); -+ close(drv->wext_sock); -+ } -+} -+*/ -+ -+#if 1 -+static void rtl871x_handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -+{ -+ struct rtl871x_driver_data *drv = ctx; -+ drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr), -+ len - sizeof(struct l2_ethhdr)); -+} -+#else -+static void rtl871x_handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) -+{ -+ struct rtl871x_driver_data *drv = ctx; -+ struct hostapd_data *hapd = drv->hapd; -+ struct sta_info *sta; -+ -+ sta = ap_get_sta(hapd, src_addr); -+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { -+ printf("Data frame from not associated STA %s\n", -+ ether_sprintf(src_addr)); -+ /* XXX cannot happen */ -+ return; -+ } -+ ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr), -+ len - sizeof(struct l2_ethhdr)); -+} -+#endif -+ -+static int rtl871x_send_eapol_ops(void *priv, const u8 *addr, const u8 *data, size_t data_len, -+ int encrypt, const u8 *own_addr, u32 flags) -+{ -+ struct rtl871x_driver_data *drv = priv; -+ unsigned char buf[3000]; -+ unsigned char *bp = buf; -+ struct l2_ethhdr *eth; -+ size_t len; -+ int status; -+ -+ printf("+rtl871x_send_eapol\n"); -+ -+ /* -+ * Prepend the Ethernet header. If the caller left us -+ * space at the front we could just insert it but since -+ * we don't know we copy to a local buffer. Given the frequency -+ * and size of frames this probably doesn't matter. -+ */ -+ len = data_len + sizeof(struct l2_ethhdr); -+ if (len > sizeof(buf)) { -+ bp = malloc(len); -+ if (bp == NULL) { -+ printf("EAPOL frame discarded, cannot malloc temp " -+ "buffer of size %lu!\n", (unsigned long) len); -+ return -1; -+ } -+ } -+ -+ eth = (struct l2_ethhdr *) bp; -+ memcpy(eth->h_dest, addr, ETH_ALEN); -+ memcpy(eth->h_source, own_addr, ETH_ALEN); -+ eth->h_proto = htons(ETH_P_EAPOL); -+ memcpy(eth+1, data, data_len); -+ -+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len); -+ -+ status = l2_packet_send(drv->l2_sock, addr, ETH_P_EAPOL, bp, len); -+ -+ if (bp != buf) -+ free(bp); -+ -+ return status; -+ -+} -+ -+#ifndef CONFIG_MLME_OFFLOAD -+static void rtl871x_receive_mgnt(struct rtl871x_driver_data *drv , const u8 *buf, size_t len) -+{ -+ const struct ieee80211_mgmt *mgmt; -+ //const u8 *end, *ie; -+ u16 fc, type, stype; -+ //size_t ie_len; -+ struct hostapd_data *hapd = drv->hapd; -+ -+ //printf("+rtl871x_receive_mgnt, " MACSTR " is our address\n", MAC2STR(hapd->own_addr)); -+ -+ -+#if 0 -+ { -+ int i; -+ for(i=0; iu.probe_req)) -+ return; -+ -+ mgmt = (const struct ieee80211_mgmt *)buf; -+ -+ fc = le_to_host16(mgmt->frame_control); -+ type = WLAN_FC_GET_TYPE(fc); -+ stype = WLAN_FC_GET_STYPE(fc); -+ -+#if 1 -+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && -+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) -+ { -+ //printf("MGNT Frame - PROBE_RESP Frame\n"); -+ } -+#endif -+ -+ //end = buf + len; -+ //ie = mgmt->u.probe_req.variable; -+ //ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req)); -+ //hostapd_wps_probe_req_rx(drv->hapd, mgmt->sa, ie, ie_len); -+ -+ switch (type) { -+ case WLAN_FC_TYPE_MGMT: -+ if (stype != WLAN_FC_STYPE_BEACON) -+ wpa_printf(MSG_MSGDUMP, "MGMT"); -+ -+ -+ -+ if (stype == WLAN_FC_STYPE_PROBE_REQ) -+ { -+ -+ } -+ else -+ { -+ //printf("rtl871x_receive_mgnt, type=0x%x, stype=0x%x\n", type, stype); -+ } -+ -+ -+ //ieee802_11_mgmt(hapd, (u8 *)buf, len, stype, NULL); -+ -+ break; -+ case WLAN_FC_TYPE_CTRL: -+ printf("rtl871x_receive_mgnt, CTRL\n"); -+ break; -+ case WLAN_FC_TYPE_DATA: -+ printf("rtl871x_receive_mgnt, DATA\n"); -+ //handle_data(hapd, buf, data_len, stype); -+ break; -+ default: -+ printf("unknown frame type %d\n", type); -+ break; -+ } -+ -+ -+} -+ -+#ifdef CONFIG_MGNT_L2SOCK -+static void rtl871x_recvive_mgmt_frame(void *ctx, const u8 *src_addr, const u8 *buf, -+ size_t len) -+{ -+ struct rtl871x_driver_data *drv = ctx; -+ -+ rtl871x_receive_mgnt(drv, buf, len); -+} -+#else -+static void rtl871x_recvive_mgmt_frame(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+#if 0 -+ int len; -+ unsigned char buf[1024]; -+ struct hostapd_data *hapd = (struct hostapd_data *)eloop_ctx; -+ struct rtl871x_driver_data *drv = (struct rtl871x_driver_data *)hapd->drv_priv; -+ -+ len = recv(sock, buf, sizeof(buf), 0); -+ if (len < 0) { -+ perror("recv"); -+ return; -+ } -+ -+ rtl871x_receive_mgnt(drv, buf, len); -+#endif -+} -+ -+static int rtl871x_mgnt_sock_init(struct rtl871x_driver_data *drv, const char *name) -+{ -+ int sock; -+ struct ifreq ifr; -+ struct sockaddr_ll addr; -+ -+ sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); -+ if (sock < 0) { -+ perror("socket[PF_PACKET,SOCK_RAW]"); -+ return -1; -+ } -+ -+ if (eloop_register_read_sock(sock, rtl871x_recvive_mgmt_frame, drv->hapd, NULL)) -+ { -+ printf("Could not register read socket\n"); -+ return -1; -+ } -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ //snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); -+ os_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); -+ if (ioctl(sock, SIOCGIFINDEX, &ifr) != 0) { -+ perror("ioctl(SIOCGIFINDEX)"); -+ return -1; -+ } -+ -+ //if (rtl871x_set_iface_flags(drv, 1)) { -+ // return -1; -+ //} -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.sll_family = AF_PACKET; -+ addr.sll_ifindex = ifr.ifr_ifindex; -+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", -+ addr.sll_ifindex); -+ -+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind"); -+ return -1; -+ } -+ -+ memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); -+ if (ioctl(sock, SIOCGIFHWADDR, &ifr) != 0) { -+ perror("ioctl(SIOCGIFHWADDR)"); -+ return -1; -+ } -+ -+ -+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { -+ printf("Invalid HW-addr family 0x%04x\n", -+ ifr.ifr_hwaddr.sa_family); -+ return -1; -+ } -+ -+ //memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); -+ -+ return sock; -+ -+} -+#endif -+#endif -+ -+static void rtl871x_handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len, -+ int ok) -+{ -+#if 0 -+ struct ieee80211_hdr *hdr; -+ u16 fc, type, stype; -+ struct sta_info *sta; -+ -+ //printf("%s\n", __func__); -+ -+ hdr = (struct ieee80211_hdr *) buf; -+ fc = le_to_host16(hdr->frame_control); -+ -+ type = WLAN_FC_GET_TYPE(fc); -+ stype = WLAN_FC_GET_STYPE(fc); -+ -+ switch (type) { -+ case WLAN_FC_TYPE_MGMT: -+ //printf("MGMT (TX callback) %s\n", -+ // ok ? "ACK" : "fail"); -+ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); -+ break; -+ case WLAN_FC_TYPE_CTRL: -+ printf("CTRL (TX callback) %s\n", -+ ok ? "ACK" : "fail"); -+ break; -+ case WLAN_FC_TYPE_DATA: -+ printf("DATA (TX callback) %s\n", -+ ok ? "ACK" : "fail"); -+ sta = ap_get_sta(hapd, hdr->addr1); -+ if (sta && sta->flags & WLAN_STA_PENDING_POLL) { -+ wpa_printf(MSG_DEBUG, "STA " MACSTR -+ " %s pending activity poll", -+ MAC2STR(sta->addr), -+ ok ? "ACKed" : "did not ACK"); -+ if (ok) -+ sta->flags &= ~WLAN_STA_PENDING_POLL; -+ } -+ if (sta) -+ ieee802_1x_tx_status(hapd, sta, buf, len, ok); -+ break; -+ default: -+ printf("unknown TX callback frame type %d\n", type); -+ break; -+ } -+#endif -+} -+ -+static int rtl871x_send_mgnt(struct rtl871x_driver_data *drv, const void *msg, size_t len) -+{ -+ int res=0; -+ -+ return res; -+} -+ -+static int rtl871x_send_mgmt_frame_ops(void *priv, const void *msg, size_t len, -+ int flags) -+{ -+ struct rtl871x_driver_data *drv = priv; -+ //struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msg; -+ int res=0; -+ -+ //printf("%s\n", __func__); -+ -+ -+ //hdr->frame_control |= host_to_le16(BIT(1));/* Request TX callback */ -+#ifdef CONFIG_MGNT_L2SOCK -+ //res = send(drv->mgnt_l2_sock, msg, len, flags); -+ //res = l2_packet_send(drv->mgnt_l2_sock, addr, ETH_P_EAPOL, msg, len); -+ if(drv->mgnt_l2_sock == NULL) -+ return res; -+ -+ res = l2_packet_send(drv->mgnt_l2_sock, NULL, ETH_P_80211_RAW, msg, len); -+#else -+ -+ if(drv->mgnt_sock < 0) -+ return res; -+ -+ res = send(drv->mgnt_sock, msg, len, flags); -+#endif -+ //hdr->frame_control &= ~host_to_le16(BIT(1)); -+ -+ -+ rtl871x_send_mgnt(drv, msg, len); -+ -+ rtl871x_handle_tx_callback(drv->hapd, (u8*)msg, len, 1); -+ -+ return res; -+ -+} -+ -+/* -+static int rtl871x_driver_send_ether_ops(void *priv, const u8 *dst, const u8 *src, -+ u16 proto, const u8 *data, size_t data_len) -+{ -+ return 0; -+} -+*/ -+ -+static struct hostapd_hw_modes *rtl871x_get_hw_feature_data_ops(void *priv, -+ u16 *num_modes, -+ u16 *flags) -+{ -+ -+#define MAX_NUM_CHANNEL (14) -+#define MAX_NUM_CHANNEL_5G (24) -+ -+ struct hostapd_hw_modes *modes; -+ size_t i; -+ int k; -+ -+ *num_modes = 3; -+ *flags = 0; -+ -+ modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); -+ if (modes == NULL) -+ return NULL; -+ -+ //.1 -+ modes[0].mode = HOSTAPD_MODE_IEEE80211G; -+ modes[0].num_channels = MAX_NUM_CHANNEL; -+ modes[0].num_rates = 12; -+ modes[0].channels = -+ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); -+ modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int)); -+ if (modes[0].channels == NULL || modes[0].rates == NULL) -+ goto fail; -+ for (i = 0; i < MAX_NUM_CHANNEL; i++) { -+ modes[0].channels[i].chan = i + 1; -+ modes[0].channels[i].freq = 2412 + 5 * i; -+ modes[0].channels[i].flag = 0; -+ if (i >= 13) -+ modes[0].channels[i].flag = HOSTAPD_CHAN_DISABLED; -+ } -+ modes[0].rates[0] = 10; -+ modes[0].rates[1] = 20; -+ modes[0].rates[2] = 55; -+ modes[0].rates[3] = 110; -+ modes[0].rates[4] = 60; -+ modes[0].rates[5] = 90; -+ modes[0].rates[6] = 120; -+ modes[0].rates[7] = 180; -+ modes[0].rates[8] = 240; -+ modes[0].rates[9] = 360; -+ modes[0].rates[10] = 480; -+ modes[0].rates[11] = 540; -+ -+ -+ //.2 -+ modes[1].mode = HOSTAPD_MODE_IEEE80211B; -+ modes[1].num_channels = MAX_NUM_CHANNEL; -+ modes[1].num_rates = 4; -+ modes[1].channels = -+ os_zalloc(MAX_NUM_CHANNEL * sizeof(struct hostapd_channel_data)); -+ modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int)); -+ if (modes[1].channels == NULL || modes[1].rates == NULL) -+ goto fail; -+ for (i = 0; i < MAX_NUM_CHANNEL; i++) { -+ modes[1].channels[i].chan = i + 1; -+ modes[1].channels[i].freq = 2412 + 5 * i; -+ modes[1].channels[i].flag = 0; -+ if (i >= 11) -+ modes[1].channels[i].flag = HOSTAPD_CHAN_DISABLED; -+ } -+ modes[1].rates[0] = 10; -+ modes[1].rates[1] = 20; -+ modes[1].rates[2] = 55; -+ modes[1].rates[3] = 110; -+ -+ -+ //.3 -+ modes[2].mode = HOSTAPD_MODE_IEEE80211A; -+#ifdef CONFIG_DRIVER_RTL_DFS -+ modes[2].num_channels = MAX_NUM_CHANNEL_5G; -+#else /* CONFIG_DRIVER_RTL_DFS */ -+ modes[2].num_channels = 9; -+#endif /* CONFIG_DRIVER_RTL_DFS */ -+ -+ modes[2].num_rates = 8; -+ modes[2].channels = os_zalloc(modes[2].num_channels * sizeof(struct hostapd_channel_data)); -+ modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int)); -+ if (modes[2].channels == NULL || modes[2].rates == NULL) -+ goto fail; -+ -+ -+ k = 0; -+ // 5G band1 Channel: 36, 40, 44, 48 -+ for (i=0; i < 4; i++) { -+ modes[2].channels[k].chan = 36+(i*4); -+ modes[2].channels[k].freq = 5180+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+ -+#ifdef CONFIG_DRIVER_RTL_DFS -+ // 5G band2 Channel: 52, 56, 60, 64 -+ for (i=0; i < 4; i++) { -+ modes[2].channels[k].chan = 52+(i*4); -+ modes[2].channels[k].freq = 5260+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+ -+ // 5G band3 Channel: 100, 104, 108. 112, 116, 120, 124, 128, 132, 136, 140 -+ for (i=0; i < 11; i++) { -+ modes[2].channels[k].chan = 100+(i*4); -+ modes[2].channels[k].freq = 5500+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+#endif /* CONFIG_DRIVER_RTL_DFS */ -+ -+ // 5G band4 Channel: 149, 153, 157, 161, 165 -+ for (i=0; i < 5; i++) { -+ modes[2].channels[k].chan = 149+(i*4); -+ modes[2].channels[k].freq = 5745+(i*20); -+ modes[2].channels[k].flag = 0; -+ k++; -+ } -+ -+ modes[2].rates[0] = 60; -+ modes[2].rates[1] = 90; -+ modes[2].rates[2] = 120; -+ modes[2].rates[3] = 180; -+ modes[2].rates[4] = 240; -+ modes[2].rates[5] = 360; -+ modes[2].rates[6] = 480; -+ modes[2].rates[7] = 540; -+ -+ -+ // -+#if 0 -+#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0)) -+#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1)) -+#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3))) -+#define HT_CAP_INFO_SMPS_STATIC ((u16) 0) -+#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2)) -+#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3))) -+#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4)) -+#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5)) -+#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6)) -+#define HT_CAP_INFO_TX_STBC ((u16) BIT(7)) -+#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9))) -+#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8)) -+#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9)) -+#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9))) -+#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10)) -+#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11)) -+#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12)) -+#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13)) -+#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14)) -+#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15)) -+#endif -+ -+ //HOSTAPD_MODE_IEEE80211G -+ modes[0].ht_capab = HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET|HT_CAP_INFO_SHORT_GI20MHZ| -+ HT_CAP_INFO_SHORT_GI40MHZ|HT_CAP_INFO_MAX_AMSDU_SIZE|HT_CAP_INFO_DSSS_CCK40MHZ; -+ -+ modes[0].mcs_set[0]= 0xff; -+ modes[0].mcs_set[1]= 0xff; -+ -+ //HOSTAPD_MODE_IEEE80211B -+ modes[1].ht_capab = 0; -+ -+ //HOSTAPD_MODE_IEEE80211A -+ modes[2].ht_capab = modes[0].ht_capab; -+ -+ modes[2].mcs_set[0]= 0xff; -+ modes[2].mcs_set[1]= 0xff; -+ -+ return modes; -+ -+fail: -+ if (modes) { -+ for (i = 0; i < *num_modes; i++) { -+ os_free(modes[i].channels); -+ os_free(modes[i].rates); -+ } -+ os_free(modes); -+ } -+ -+ return NULL; -+ -+} -+ -+#if 0 -+static int rtl871x_sta_add_ops(const char *ifname, void *priv, const u8 *addr, -+ u16 aid, u16 capability, u8 *supp_rates, -+ size_t supp_rates_len, int flags, -+ u16 listen_interval) -+{ -+ -+#if 1 -+ printf("+%s, " MACSTR " is new sta address added\n", __func__, MAC2STR(addr)); -+ return 0; -+#else -+ struct hostap_driver_data *drv = priv; -+ struct prism2_hostapd_param param; -+ int tx_supp_rates = 0; -+ size_t i; -+ -+#define WLAN_RATE_1M BIT(0) -+#define WLAN_RATE_2M BIT(1) -+#define WLAN_RATE_5M5 BIT(2) -+#define WLAN_RATE_11M BIT(3) -+ -+ for (i = 0; i < supp_rates_len; i++) { -+ if ((supp_rates[i] & 0x7f) == 2) -+ tx_supp_rates |= WLAN_RATE_1M; -+ if ((supp_rates[i] & 0x7f) == 4) -+ tx_supp_rates |= WLAN_RATE_2M; -+ if ((supp_rates[i] & 0x7f) == 11) -+ tx_supp_rates |= WLAN_RATE_5M5; -+ if ((supp_rates[i] & 0x7f) == 22) -+ tx_supp_rates |= WLAN_RATE_11M; -+ } -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = PRISM2_HOSTAPD_ADD_STA; -+ memcpy(param.sta_addr, addr, ETH_ALEN); -+ param.u.add_sta.aid = aid; -+ param.u.add_sta.capability = capability; -+ param.u.add_sta.tx_supp_rates = tx_supp_rates; -+ return hostapd_ioctl(drv, ¶m, sizeof(param)); -+#endif -+} -+ -+static int rtl871x_sta_add2_ops(const char *ifname, void *priv, -+ struct hostapd_sta_add_params *params) -+{ -+#if 0 -+ ieee_param param; -+ //int i, tx_supp_rates = 0; -+ struct rtl871x_driver_data *drv = priv; -+ -+ printf("%s\n", __func__); -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = RTL871X_HOSTAPD_ADD_STA; -+ memcpy(param.sta_addr, params->addr, ETH_ALEN); -+ param.u.add_sta.aid = params->aid; -+ param.u.add_sta.capability = params->capability; -+ param.u.add_sta.flags = params->flags; -+ -+ memcpy(param.u.add_sta.tx_supp_rates, params->supp_rates, params->supp_rates_len); -+ -+/* -+ for (i = 0; i < params->supp_rates_len; i++) -+ { -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_1MB) -+ tx_supp_rates |= IEEE80211_CCK_RATE_1MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_2MB) -+ tx_supp_rates |= IEEE80211_CCK_RATE_2MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_5MB) -+ tx_supp_rates |= IEEE80211_CCK_RATE_5MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_CCK_RATE_11MB) -+ tx_supp_rates |= IEEE80211_CCK_RATE_11MB_MASK; -+ -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_6MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_6MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_9MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_9MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_12MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_12MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_18MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_18MB_MASK; -+ -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_24MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_24MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_36MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_36MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_48MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_48MB_MASK; -+ if ((params->supp_rates[i] & 0x7f) == IEEE80211_OFDM_RATE_54MB) -+ tx_supp_rates |= IEEE80211_OFDM_RATE_54MB_MASK; -+ -+ } -+ -+ param.u.add_sta.tx_supp_rates = tx_supp_rates; -+*/ -+ -+#ifdef CONFIG_IEEE80211N -+ if (params->ht_capabilities && params->ht_capabilities->length>0) -+ { -+ struct ieee80211_ht_capability *pht_cap = (struct ieee80211_ht_capability *)¶ms->ht_capabilities->data; -+ memcpy((u8*)¶m.u.add_sta.ht_cap, (u8*)pht_cap, sizeof(struct ieee80211_ht_capability)); -+ -+ } -+#endif /* CONFIG_IEEE80211N */ -+ -+ return rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param)); -+#else -+ return 0; -+#endif -+} -+#endif -+ -+static int rtl871x_sta_remove_ops(void *priv, const u8 *addr) -+{ -+ struct rtl871x_driver_data *drv = priv; -+ struct ieee_param param; -+ -+ printf("+%s, " MACSTR " is sta address removed\n", __func__, MAC2STR(addr)); -+ -+ //hostap_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED); -+ -+ memset(¶m, 0, sizeof(param)); -+ param.cmd = RTL871X_HOSTAPD_REMOVE_STA; -+ memcpy(param.sta_addr, addr, ETH_ALEN); -+ if (rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param))) { -+ printf("Could not remove station from kernel driver.\n"); -+ return -1; -+ } -+ -+ return 0; -+ -+} -+ -+ -+//static int rtl871x_set_beacon_ops(const char *iface, void *priv, -+// u8 *head, size_t head_len, -+// u8 *tail, size_t tail_len) -+int rtl871x_set_beacon_ops(void *priv, const u8 *head, size_t head_len, -+ const u8 *tail, size_t tail_len, int dtim_period, -+ int beacon_int) -+{ -+ int ret; -+ size_t sz; -+ ieee_param *pparam; -+ struct rtl871x_driver_data *drv = priv; -+ struct hostapd_data *hapd = drv->hapd; -+ -+ if((head_len<24) ||(!head)) -+ return -1; -+ -+ printf("%s\n", __func__); -+ -+ sz = head_len+tail_len+12-24 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed -+ pparam = os_zalloc(sz); -+ if (pparam == NULL) { -+ return -ENOMEM; -+ } -+ -+ pparam->cmd = RTL871X_HOSTAPD_SET_BEACON; -+ -+ memcpy(pparam->u.bcn_ie.reserved, &hapd->conf->max_num_sta, 2);//for set max_num_sta -+ -+ memcpy(pparam->u.bcn_ie.buf, (head+24), (head_len-24));// 24=beacon header len. -+ -+ memcpy(&pparam->u.bcn_ie.buf[head_len-24], tail, tail_len); -+ -+ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); -+ -+ os_free(pparam); -+ -+ //rtl871x_set_max_num_sta(drv); -+ -+ return ret; -+ -+} -+ -+/* -+enum wpa_alg { -+ WPA_ALG_NONE, -+ WPA_ALG_WEP, -+ WPA_ALG_TKIP, -+ WPA_ALG_CCMP, -+ WPA_ALG_IGTK, -+ WPA_ALG_PMK -+}; -+*/ -+static int rtl871x_set_key_ops(const char *ifname, void *priv, enum wpa_alg alg, -+ const u8 *addr, int idx, int txkey, const u8 *seq, -+ size_t seq_len, const u8 *key, size_t key_len) -+{ -+ ieee_param *param; -+ u8 *buf; -+ char *alg_str; -+ size_t blen; -+ int ret = 0; -+ struct rtl871x_driver_data *drv = priv; -+ -+ printf("%s\n", __func__); -+ -+ blen = sizeof(*param) + key_len; -+ buf = os_zalloc(blen); -+ if (buf == NULL) -+ return -1; -+ -+ param = (ieee_param *)buf; -+ param->cmd = RTL871X_SET_ENCRYPTION; -+ if (addr == NULL) -+ memset(param->sta_addr, 0xff, ETH_ALEN); -+ else -+ memcpy(param->sta_addr, addr, ETH_ALEN); -+ -+ -+ switch (alg) { -+ case WPA_ALG_NONE: -+ alg_str = "none"; -+ break; -+ case WPA_ALG_WEP: -+ //cipher = IEEE80211_CIPHER_WEP; -+ alg_str = "WEP"; -+ break; -+ case WPA_ALG_TKIP: -+ //cipher = IEEE80211_CIPHER_TKIP; -+ alg_str = "TKIP"; -+ break; -+ case WPA_ALG_CCMP: -+ //cipher = IEEE80211_CIPHER_AES_CCM; -+ alg_str = "CCMP"; -+ break; -+ default: -+ printf("%s: unknown/unsupported algorithm %d\n", -+ __func__, alg); -+ return -1; -+ } -+ -+ os_strlcpy((char *) param->u.crypt.alg, alg_str, -+ IEEE_CRYPT_ALG_NAME_LEN); -+ -+ //param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; -+ param->u.crypt.set_tx = txkey ? 1 : 0; -+ param->u.crypt.idx = idx; -+ param->u.crypt.key_len = key_len; -+ -+ //memcpy((u8 *) (param + 1), key, key_len); -+ memcpy(param->u.crypt.key, key, key_len); -+ -+ if (rtl871x_hostapd_ioctl(drv, param, blen)) { -+ printf("Failed to set encryption.\n"); -+ ret = -1; -+ } -+ -+ os_free(buf); -+ -+ return ret; -+ -+} -+ -+/* -+static int rtl871x_set_encryption_ops(const char *ifname, void *priv, -+ const char *alg, const u8 *addr, -+ int idx, const u8 *key, size_t key_len, -+ int txkey) -+{ -+ ieee_param *param; -+ u8 *buf; -+ size_t blen; -+ int ret = 0; -+ struct rtl871x_driver_data *drv = priv; -+ -+ printf("%s\n", __func__); -+#if 0 -+ blen = sizeof(*param) + key_len; -+ buf = os_zalloc(blen); -+ if (buf == NULL) -+ return -1; -+ -+ param = (ieee_param *)buf; -+ param->cmd = RTL871X_SET_ENCRYPTION; -+ if (addr == NULL) -+ memset(param->sta_addr, 0xff, ETH_ALEN); -+ else -+ memcpy(param->sta_addr, addr, ETH_ALEN); -+ -+ os_strlcpy((char *) param->u.crypt.alg, alg, -+ IEEE_CRYPT_ALG_NAME_LEN); -+ -+ //param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; -+ param->u.crypt.set_tx = txkey ? 1 : 0; -+ param->u.crypt.idx = idx; -+ param->u.crypt.key_len = key_len; -+ -+ //memcpy((u8 *) (param + 1), key, key_len); -+ memcpy(param->u.crypt.key, key, key_len); -+ -+ if (rtl871x_hostapd_ioctl(drv, param, blen)) { -+ printf("Failed to set encryption.\n"); -+ ret = -1; -+ } -+ -+ os_free(buf); -+#endif -+ return ret; -+ -+} -+*/ -+ -+//static int rtl871x_sta_deauth_ops(void *priv, const u8 *addr, int reason) -+static int rtl871x_sta_deauth_ops(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason) -+{ -+ printf("+%s, " MACSTR " is deauth, reason=%d\n", __func__, MAC2STR(addr), reason); -+ -+ //struct hostap_driver_data *drv = priv; -+ struct rtl871x_driver_data *drv = priv; -+ struct ieee80211_mgmt mgmt; -+ -+ memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DEAUTH); -+ -+ memcpy(mgmt.da, addr, ETH_ALEN); -+ //memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); -+ //memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); -+ memcpy(mgmt.sa, own_addr, ETH_ALEN); -+ memcpy(mgmt.bssid, own_addr, ETH_ALEN); -+ mgmt.u.deauth.reason_code = host_to_le16(reason); -+ -+ return rtl871x_send_mgmt_frame_ops(drv, &mgmt, IEEE80211_HDRLEN + -+ sizeof(mgmt.u.deauth), 0); -+ -+} -+ -+ -+//static int rtl871x_sta_disassoc_ops(void *priv, const u8 *addr, int reason) -+static int rtl871x_sta_disassoc_ops(void *priv, const u8 *own_addr, const u8 *addr, -+ int reason) -+{ -+ printf("+%s, " MACSTR " is disassoc, reason=%d\n", __func__, MAC2STR(addr), reason); -+ -+ struct rtl871x_driver_data *drv = priv; -+ struct ieee80211_mgmt mgmt; -+ -+ memset(&mgmt, 0, sizeof(mgmt)); -+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, -+ WLAN_FC_STYPE_DISASSOC); -+ -+ memcpy(mgmt.da, addr, ETH_ALEN); -+ //memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN); -+ //memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN); -+ memcpy(mgmt.sa, own_addr, ETH_ALEN); -+ memcpy(mgmt.bssid, own_addr, ETH_ALEN); -+ -+ mgmt.u.disassoc.reason_code = host_to_le16(reason); -+ -+ return rtl871x_send_mgmt_frame_ops(drv, &mgmt, IEEE80211_HDRLEN + -+ sizeof(mgmt.u.disassoc), 0); -+ -+} -+ -+static int rtl871x_set_wps_assoc_resp_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) -+{ -+ int ret; -+ size_t sz; -+ ieee_param *pparam; -+ -+ -+ printf("%s\n", __func__); -+ -+ sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed -+ pparam = os_zalloc(sz); -+ if (pparam == NULL) { -+ return -ENOMEM; -+ } -+ -+ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP; -+ -+ if(ie && len>0) -+ { -+ memcpy(pparam->u.bcn_ie.buf, ie, len); -+ } -+ -+ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); -+ -+ os_free(pparam); -+ -+ return ret; -+ -+} -+ -+static int rtl871x_set_wps_beacon_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) -+{ -+ int ret; -+ size_t sz; -+ ieee_param *pparam; -+ -+ -+ printf("%s\n", __func__); -+ -+ sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed -+ pparam = os_zalloc(sz); -+ if (pparam == NULL) { -+ return -ENOMEM; -+ } -+ -+ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_BEACON; -+ -+ if(ie && len>0) -+ { -+ memcpy(pparam->u.bcn_ie.buf, ie, len); -+ } -+ -+ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); -+ -+ os_free(pparam); -+ -+ return ret; -+ -+} -+ -+static int rtl871x_set_wps_probe_resp_ie(struct rtl871x_driver_data *drv, const void *ie, size_t len) -+{ -+ int ret; -+ size_t sz; -+ ieee_param *pparam; -+ -+ -+ printf("%s\n", __func__); -+ -+ sz = len + 12 + 2;// 12+2 = cmd+sta_addr+reserved, sizeof(ieee_param)=64, no packed -+ pparam = os_zalloc(sz); -+ if (pparam == NULL) { -+ return -ENOMEM; -+ } -+ -+ pparam->cmd = RTL871X_HOSTAPD_SET_WPS_PROBE_RESP; -+ -+ if(ie && len>0) -+ { -+ memcpy(pparam->u.bcn_ie.buf, ie, len); -+ } -+ -+ ret = rtl871x_hostapd_ioctl(drv, pparam, sz); -+ -+ os_free(pparam); -+ -+ return ret; -+ -+} -+ -+static int rtl871x_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, -+ const struct wpabuf *proberesp, const struct wpabuf *assocresp) -+{ -+ struct rtl871x_driver_data *drv = priv; -+ -+ if (rtl871x_set_wps_assoc_resp_ie(drv, assocresp ? wpabuf_head(assocresp) : NULL, -+ assocresp ? wpabuf_len(assocresp) : 0)) -+ return -1; -+ -+ if (rtl871x_set_wps_beacon_ie(drv, beacon ? wpabuf_head(beacon) : NULL, -+ beacon ? wpabuf_len(beacon) : 0)) -+ return -1; -+ -+ return rtl871x_set_wps_probe_resp_ie(drv, -+ proberesp ? wpabuf_head(proberesp) : NULL, -+ proberesp ? wpabuf_len(proberesp): 0); -+ -+} -+ -+static int rtl871x_sta_flush_ops(void *priv) -+{ -+ ieee_param param; -+ struct rtl871x_driver_data *drv = priv; -+ -+ memset(¶m, 0, sizeof(param)); -+ -+ param.cmd = RTL871X_HOSTAPD_FLUSH; -+ -+ return rtl871x_hostapd_ioctl(drv, ¶m, sizeof(param)); -+} -+ -+static void *rtl871x_driver_init_ops(struct hostapd_data *hapd, struct wpa_init_params *params) -+{ -+ struct rtl871x_driver_data *drv; -+ struct ifreq ifr; -+ //struct iwreq iwr; -+ char ifrn_name[IFNAMSIZ + 1];//for mgnt_l2_sock/mgnt_sock -+ char brname[IFNAMSIZ]; -+ -+ drv = os_zalloc(sizeof(struct rtl871x_driver_data)); -+ if (drv == NULL) { -+ printf("Could not allocate memory for rtl871x driver data\n"); -+ return NULL; -+ } -+ -+ drv->hapd = hapd; -+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->ioctl_sock < 0) { -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ goto bad; -+ } -+ os_memcpy(drv->iface, params->ifname, sizeof(drv->iface)); -+ -+ linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);/*set interface up*/ -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name)); -+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) { -+ perror("ioctl(SIOCGIFINDEX)"); -+ goto bad; -+ } -+ drv->ifindex = ifr.ifr_ifindex; -+ printf("drv->ifindex=%d\n", drv->ifindex); -+ -+ drv->l2_sock = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, -+ rtl871x_handle_read, drv, 1); -+ -+ if (drv->l2_sock == NULL) -+ goto bad; -+ -+ if (l2_packet_get_own_addr(drv->l2_sock, params->own_addr)) -+ goto bad; -+ -+ -+ if (params->bridge[0]) { -+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.", -+ params->bridge[0]); -+ drv->l2_sock_recv = l2_packet_init(params->bridge[0], NULL, -+ ETH_P_EAPOL, rtl871x_handle_read, drv, -+ 1); -+ if (drv->l2_sock_recv == NULL) -+ { -+ //goto bad; -+ drv->l2_sock_recv = drv->l2_sock; -+ printf("no br0 interface , let l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); -+ } -+ -+ } else if (linux_br_get(brname, drv->iface) == 0) { -+ wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for " -+ "EAPOL receive", brname); -+ drv->l2_sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL, -+ rtl871x_handle_read, drv, 1); -+ if (drv->l2_sock_recv == NULL) -+ goto bad; -+ } -+ else -+ { -+ drv->l2_sock_recv = drv->l2_sock; -+ printf("l2_sock_recv==l2_sock_xmit=0x%p\n", drv->l2_sock); -+ } -+ -+ -+ os_memset(ifrn_name, 0, sizeof(ifrn_name)); -+ //snprintf(ifrn_name, sizeof(ifrn_name), "mgnt.%s_rena", drv->iface); -+ snprintf(ifrn_name, sizeof(ifrn_name), "mgnt.%s", "wlan0"/*drv->iface*/); -+#ifdef CONFIG_MGNT_L2SOCK -+ drv->mgnt_l2_sock = NULL; -+ drv->mgnt_l2_sock = l2_packet_init(ifrn_name, NULL, ETH_P_80211_RAW, -+ rtl871x_recvive_mgmt_frame, drv, 1); -+ if (drv->mgnt_l2_sock == NULL) -+ goto bad; -+ -+#else -+ -+#ifdef CONFIG_MLME_OFFLOAD -+ drv->mgnt_sock = -1; -+#else -+ drv->mgnt_sock = rtl871x_mgnt_sock_init(drv, ifrn_name); -+ if (drv->mgnt_sock < 0) { -+ goto bad; -+ } -+#endif -+ -+#endif -+ -+ -+ //madwifi_set_iface_flags(drv, 0); /* mark down during setup */ -+ //madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */ -+ -+ -+ //linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);/*set interface up*/ -+ -+ -+ //enter MASTER MODE when init. -+ if(rtl871x_set_mode(drv, IW_MODE_MASTER)<0) -+ { -+ printf("Could not set interface to master mode!\n"); -+ goto bad; -+ } -+ -+/* -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.mode = IW_MODE_MASTER; -+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMODE]"); -+ printf("Could not set interface to master mode!\n"); -+ goto bad; -+ } -+*/ -+ -+#ifndef CONFIG_MLME_OFFLOAD -+ rtl871x_set_iface_flags(drv, 1); /*set mgnt interface up*/ -+#endif -+ -+ -+ if (rtl871x_wireless_event_init(drv)) -+ goto bad; -+ -+ -+ os_memcpy(drv->hw_mac, params->own_addr, ETH_ALEN); -+ -+ return drv; -+ -+bad: -+ -+ if (drv->l2_sock_recv != NULL && drv->l2_sock_recv != drv->l2_sock) -+ l2_packet_deinit(drv->l2_sock_recv); -+ -+ if (drv->l2_sock != NULL) -+ l2_packet_deinit(drv->l2_sock); -+ -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ -+#ifdef CONFIG_MGNT_L2SOCK -+ if ( drv->mgnt_l2_sock != NULL) -+ l2_packet_deinit(drv->mgnt_l2_sock); -+#else -+ if (drv->mgnt_sock >= 0) -+ close(drv->mgnt_sock); -+#endif -+ -+ if (drv != NULL) -+ free(drv); -+ -+ return NULL; -+ -+} -+ -+static void rtl871x_driver_deinit_ops(void *priv) -+{ -+ //struct iwreq iwr; -+ struct rtl871x_driver_data *drv = priv; -+ -+ //back to INFRA MODE when exit. -+/* -+ memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ); -+ iwr.u.mode = IW_MODE_INFRA; -+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMODE]"); -+ } -+*/ -+ rtl871x_set_mode(drv, IW_MODE_INFRA); -+ -+ -+ if (drv->ioctl_sock >= 0) -+ close(drv->ioctl_sock); -+ -+ -+ if (drv->l2_sock_recv != NULL && drv->l2_sock_recv != drv->l2_sock) -+ l2_packet_deinit(drv->l2_sock_recv); -+ -+ if(drv->l2_sock) -+ l2_packet_deinit(drv->l2_sock); -+ -+ //if (drv->sock_xmit != NULL) -+ // l2_packet_deinit(drv->sock_xmit); -+ -+#ifdef CONFIG_MGNT_L2SOCK -+ if (drv->mgnt_l2_sock) -+ l2_packet_deinit(drv->mgnt_l2_sock); -+#else -+ if (drv->mgnt_sock >= 0) -+ close(drv->mgnt_sock); -+#endif -+ -+ os_free(drv); -+ -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_rtw_ops = { -+ .name = "rtl871xdrv", -+ //.init = rtl871x_driver_init_ops, -+ //.deinit = rtl871x_driver_deinit_ops, -+ .hapd_init = rtl871x_driver_init_ops, -+ .hapd_deinit = rtl871x_driver_deinit_ops, -+ //.wireless_event_init = rtl871x_wireless_event_init_ops, -+ //.wireless_event_deinit = rtl871x_wireless_event_deinit_ops, -+ //.send_eapol = rtl871x_send_eapol_ops, -+ .hapd_send_eapol = rtl871x_send_eapol_ops, -+ //.send_ether = rtl871x_driver_send_ether_ops, -+ //.send_mgmt_frame = rtl871x_send_mgmt_frame_ops, -+ .get_hw_feature_data = rtl871x_get_hw_feature_data_ops, -+ //.sta_add = rtl871x_sta_add_ops, -+ //.sta_add2 = rtl871x_sta_add2_ops, -+ .sta_remove = rtl871x_sta_remove_ops, -+ .set_beacon = rtl871x_set_beacon_ops, -+ //.set_encryption = rtl871x_set_encryption_ops, -+ .set_key = rtl871x_set_key_ops, -+ .sta_deauth = rtl871x_sta_deauth_ops, -+ .sta_disassoc = rtl871x_sta_disassoc_ops, -+ //.set_wps_beacon_ie = rtl871x_set_wps_beacon_ie_ops, -+ //.set_wps_probe_resp_ie = rtl871x_set_wps_probe_resp_ie_ops, -+ .set_ap_wps_ie = rtl871x_set_ap_wps_ie, -+ .flush = rtl871x_sta_flush_ops, -+}; -+ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_test.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_test.c -new file mode 100644 -index 0000000000000..6bfa46dbc654a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_test.c -@@ -0,0 +1,3391 @@ -+/* -+ * Testing driver interface for a simulated network driver -+ * Copyright (c) 2004-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */ -+#include "build_config.h" -+#ifdef CONFIG_NATIVE_WINDOWS -+#include -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+#include "utils/includes.h" -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+#include -+#include -+#include -+#define DRIVER_TEST_UNIX -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "utils/list.h" -+#include "utils/trace.h" -+#include "common/ieee802_11_defs.h" -+#include "crypto/sha1.h" -+#include "l2_packet/l2_packet.h" -+#include "p2p/p2p.h" -+#include "wps/wps.h" -+#include "driver.h" -+ -+ -+struct test_client_socket { -+ struct test_client_socket *next; -+ u8 addr[ETH_ALEN]; -+ struct sockaddr_un un; -+ socklen_t unlen; -+ struct test_driver_bss *bss; -+}; -+ -+struct test_driver_bss { -+ struct wpa_driver_test_data *drv; -+ struct dl_list list; -+ void *bss_ctx; -+ char ifname[IFNAMSIZ]; -+ u8 bssid[ETH_ALEN]; -+ u8 *ie; -+ size_t ielen; -+ u8 *wps_beacon_ie; -+ size_t wps_beacon_ie_len; -+ u8 *wps_probe_resp_ie; -+ size_t wps_probe_resp_ie_len; -+ u8 ssid[32]; -+ size_t ssid_len; -+ int privacy; -+}; -+ -+struct wpa_driver_test_global { -+ int bss_add_used; -+ u8 req_addr[ETH_ALEN]; -+}; -+ -+struct wpa_driver_test_data { -+ struct wpa_driver_test_global *global; -+ void *ctx; -+ WPA_TRACE_REF(ctx); -+ u8 own_addr[ETH_ALEN]; -+ int test_socket; -+#ifdef DRIVER_TEST_UNIX -+ struct sockaddr_un hostapd_addr; -+#endif /* DRIVER_TEST_UNIX */ -+ int hostapd_addr_set; -+ struct sockaddr_in hostapd_addr_udp; -+ int hostapd_addr_udp_set; -+ char *own_socket_path; -+ char *test_dir; -+#define MAX_SCAN_RESULTS 30 -+ struct wpa_scan_res *scanres[MAX_SCAN_RESULTS]; -+ size_t num_scanres; -+ int use_associnfo; -+ u8 assoc_wpa_ie[80]; -+ size_t assoc_wpa_ie_len; -+ int use_mlme; -+ int associated; -+ u8 *probe_req_ie; -+ size_t probe_req_ie_len; -+ u8 probe_req_ssid[32]; -+ size_t probe_req_ssid_len; -+ int ibss; -+ int ap; -+ -+ struct test_client_socket *cli; -+ struct dl_list bss; -+ int udp_port; -+ -+ int alloc_iface_idx; -+ -+ int probe_req_report; -+ unsigned int remain_on_channel_freq; -+ unsigned int remain_on_channel_duration; -+ -+ int current_freq; -+ -+ struct p2p_data *p2p; -+ unsigned int off_channel_freq; -+ struct wpabuf *pending_action_tx; -+ u8 pending_action_src[ETH_ALEN]; -+ u8 pending_action_dst[ETH_ALEN]; -+ u8 pending_action_bssid[ETH_ALEN]; -+ unsigned int pending_action_freq; -+ unsigned int pending_listen_freq; -+ unsigned int pending_listen_duration; -+ int pending_p2p_scan; -+ struct sockaddr *probe_from; -+ socklen_t probe_from_len; -+}; -+ -+ -+static void wpa_driver_test_deinit(void *priv); -+static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, -+ const char *dir, int ap); -+static void wpa_driver_test_close_test_socket( -+ struct wpa_driver_test_data *drv); -+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx); -+static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv); -+ -+ -+static void test_driver_free_bss(struct test_driver_bss *bss) -+{ -+ os_free(bss->ie); -+ os_free(bss->wps_beacon_ie); -+ os_free(bss->wps_probe_resp_ie); -+ os_free(bss); -+} -+ -+ -+static void test_driver_free_bsses(struct wpa_driver_test_data *drv) -+{ -+ struct test_driver_bss *bss, *tmp; -+ -+ dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss, -+ list) { -+ dl_list_del(&bss->list); -+ test_driver_free_bss(bss); -+ } -+} -+ -+ -+static struct test_client_socket * -+test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from, -+ socklen_t fromlen) -+{ -+ struct test_client_socket *cli = drv->cli; -+ -+ while (cli) { -+ if (cli->unlen == fromlen && -+ strncmp(cli->un.sun_path, from->sun_path, -+ fromlen - sizeof(cli->un.sun_family)) == 0) -+ return cli; -+ cli = cli->next; -+ } -+ -+ return NULL; -+} -+ -+ -+static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data, -+ size_t data_len, int encrypt, -+ const u8 *own_addr, u32 flags) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct test_client_socket *cli; -+ struct msghdr msg; -+ struct iovec io[3]; -+ struct l2_ethhdr eth; -+ -+ if (drv->test_socket < 0) -+ return -1; -+ -+ cli = drv->cli; -+ while (cli) { -+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0) -+ break; -+ cli = cli->next; -+ } -+ -+ if (!cli) { -+ wpa_printf(MSG_DEBUG, "%s: no destination client entry", -+ __func__); -+ return -1; -+ } -+ -+ memcpy(eth.h_dest, addr, ETH_ALEN); -+ memcpy(eth.h_source, own_addr, ETH_ALEN); -+ eth.h_proto = host_to_be16(ETH_P_EAPOL); -+ -+ io[0].iov_base = "EAPOL "; -+ io[0].iov_len = 6; -+ io[1].iov_base = ð -+ io[1].iov_len = sizeof(eth); -+ io[2].iov_base = (u8 *) data; -+ io[2].iov_len = data_len; -+ -+ memset(&msg, 0, sizeof(msg)); -+ msg.msg_iov = io; -+ msg.msg_iovlen = 3; -+ msg.msg_name = &cli->un; -+ msg.msg_namelen = cli->unlen; -+ return sendmsg(drv->test_socket, &msg, 0); -+} -+ -+ -+static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src, -+ u16 proto, const u8 *data, size_t data_len) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct msghdr msg; -+ struct iovec io[3]; -+ struct l2_ethhdr eth; -+ char desttxt[30]; -+ struct sockaddr_un addr; -+ struct dirent *dent; -+ DIR *dir; -+ int ret = 0, broadcast = 0, count = 0; -+ -+ if (drv->test_socket < 0 || drv->test_dir == NULL) { -+ wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d " -+ "test_dir=%p)", -+ __func__, drv->test_socket, drv->test_dir); -+ return -1; -+ } -+ -+ broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; -+ snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst)); -+ -+ memcpy(eth.h_dest, dst, ETH_ALEN); -+ memcpy(eth.h_source, src, ETH_ALEN); -+ eth.h_proto = host_to_be16(proto); -+ -+ io[0].iov_base = "ETHER "; -+ io[0].iov_len = 6; -+ io[1].iov_base = ð -+ io[1].iov_len = sizeof(eth); -+ io[2].iov_base = (u8 *) data; -+ io[2].iov_len = data_len; -+ -+ memset(&msg, 0, sizeof(msg)); -+ msg.msg_iov = io; -+ msg.msg_iovlen = 3; -+ -+ dir = opendir(drv->test_dir); -+ if (dir == NULL) { -+ perror("test_driver: opendir"); -+ return -1; -+ } -+ while ((dent = readdir(dir))) { -+#ifdef _DIRENT_HAVE_D_TYPE -+ /* Skip the file if it is not a socket. Also accept -+ * DT_UNKNOWN (0) in case the C library or underlying file -+ * system does not support d_type. */ -+ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) -+ continue; -+#endif /* _DIRENT_HAVE_D_TYPE */ -+ if (strcmp(dent->d_name, ".") == 0 || -+ strcmp(dent->d_name, "..") == 0) -+ continue; -+ -+ memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", -+ drv->test_dir, dent->d_name); -+ -+ if (strcmp(addr.sun_path, drv->own_socket_path) == 0) -+ continue; -+ if (!broadcast && strstr(dent->d_name, desttxt) == NULL) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s", -+ __func__, dent->d_name); -+ -+ msg.msg_name = &addr; -+ msg.msg_namelen = sizeof(addr); -+ ret = sendmsg(drv->test_socket, &msg, 0); -+ if (ret < 0) -+ perror("driver_test: sendmsg"); -+ count++; -+ } -+ closedir(dir); -+ -+ if (!broadcast && count == 0) { -+ wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found", -+ __func__, MAC2STR(dst)); -+ return -1; -+ } -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_test_send_mlme(void *priv, const u8 *data, -+ size_t data_len) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct msghdr msg; -+ struct iovec io[2]; -+ const u8 *dest; -+ struct sockaddr_un addr; -+ struct dirent *dent; -+ DIR *dir; -+ int broadcast; -+ int ret = 0; -+ struct ieee80211_hdr *hdr; -+ u16 fc; -+ char cmd[50]; -+ int freq; -+#ifdef HOSTAPD -+ char desttxt[30]; -+#endif /* HOSTAPD */ -+ union wpa_event_data event; -+ -+ wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len); -+ if (drv->test_socket < 0 || data_len < 10) { -+ wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu" -+ " test_dir=%p)", -+ __func__, drv->test_socket, -+ (unsigned long) data_len, -+ drv->test_dir); -+ return -1; -+ } -+ -+ dest = data + 4; -+ broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0; -+ -+#ifdef HOSTAPD -+ snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest)); -+#endif /* HOSTAPD */ -+ -+ if (drv->remain_on_channel_freq) -+ freq = drv->remain_on_channel_freq; -+ else -+ freq = drv->current_freq; -+ wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz", -+ dbss->ifname, freq); -+ os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq); -+ io[0].iov_base = cmd; -+ io[0].iov_len = os_strlen(cmd); -+ io[1].iov_base = (void *) data; -+ io[1].iov_len = data_len; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ msg.msg_iov = io; -+ msg.msg_iovlen = 2; -+ -+#ifdef HOSTAPD -+ if (drv->test_dir == NULL) { -+ wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__); -+ return -1; -+ } -+ -+ dir = opendir(drv->test_dir); -+ if (dir == NULL) { -+ perror("test_driver: opendir"); -+ return -1; -+ } -+ while ((dent = readdir(dir))) { -+#ifdef _DIRENT_HAVE_D_TYPE -+ /* Skip the file if it is not a socket. Also accept -+ * DT_UNKNOWN (0) in case the C library or underlying file -+ * system does not support d_type. */ -+ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) -+ continue; -+#endif /* _DIRENT_HAVE_D_TYPE */ -+ if (os_strcmp(dent->d_name, ".") == 0 || -+ os_strcmp(dent->d_name, "..") == 0) -+ continue; -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", -+ drv->test_dir, dent->d_name); -+ -+ if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0) -+ continue; -+ if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "%s: Send management frame to %s", -+ __func__, dent->d_name); -+ -+ msg.msg_name = &addr; -+ msg.msg_namelen = sizeof(addr); -+ ret = sendmsg(drv->test_socket, &msg, 0); -+ if (ret < 0) -+ perror("driver_test: sendmsg(test_socket)"); -+ } -+ closedir(dir); -+#else /* HOSTAPD */ -+ -+ if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 || -+ drv->test_dir == NULL) { -+ if (drv->hostapd_addr_udp_set) { -+ msg.msg_name = &drv->hostapd_addr_udp; -+ msg.msg_namelen = sizeof(drv->hostapd_addr_udp); -+ } else { -+#ifdef DRIVER_TEST_UNIX -+ msg.msg_name = &drv->hostapd_addr; -+ msg.msg_namelen = sizeof(drv->hostapd_addr); -+#endif /* DRIVER_TEST_UNIX */ -+ } -+ } else if (broadcast) { -+ dir = opendir(drv->test_dir); -+ if (dir == NULL) -+ return -1; -+ while ((dent = readdir(dir))) { -+#ifdef _DIRENT_HAVE_D_TYPE -+ /* Skip the file if it is not a socket. -+ * Also accept DT_UNKNOWN (0) in case -+ * the C library or underlying file -+ * system does not support d_type. */ -+ if (dent->d_type != DT_SOCK && -+ dent->d_type != DT_UNKNOWN) -+ continue; -+#endif /* _DIRENT_HAVE_D_TYPE */ -+ if (os_strcmp(dent->d_name, ".") == 0 || -+ os_strcmp(dent->d_name, "..") == 0) -+ continue; -+ wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s", -+ __func__, dent->d_name); -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), -+ "%s/%s", drv->test_dir, dent->d_name); -+ -+ msg.msg_name = &addr; -+ msg.msg_namelen = sizeof(addr); -+ -+ ret = sendmsg(drv->test_socket, &msg, 0); -+ if (ret < 0) -+ perror("driver_test: sendmsg(test_socket)"); -+ } -+ closedir(dir); -+ return ret; -+ } else { -+ struct stat st; -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), -+ "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest)); -+ if (stat(addr.sun_path, &st) < 0) { -+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), -+ "%s/STA-" MACSTR, -+ drv->test_dir, MAC2STR(dest)); -+ } -+ msg.msg_name = &addr; -+ msg.msg_namelen = sizeof(addr); -+ } -+ -+ if (sendmsg(drv->test_socket, &msg, 0) < 0) { -+ perror("sendmsg(test_socket)"); -+ return -1; -+ } -+#endif /* HOSTAPD */ -+ -+ hdr = (struct ieee80211_hdr *) data; -+ fc = le_to_host16(hdr->frame_control); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.tx_status.type = WLAN_FC_GET_TYPE(fc); -+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc); -+ event.tx_status.dst = hdr->addr1; -+ event.tx_status.data = data; -+ event.tx_status.data_len = data_len; -+ event.tx_status.ack = ret >= 0; -+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); -+ -+#ifdef CONFIG_P2P -+ if (drv->p2p && -+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && -+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { -+ if (drv->pending_action_tx == NULL) { -+ wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " -+ "no pending operation"); -+ return ret; -+ } -+ -+ if (os_memcmp(hdr->addr1, drv->pending_action_dst, ETH_ALEN) != -+ 0) { -+ wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " -+ "unknown destination address"); -+ return ret; -+ } -+ -+ wpabuf_free(drv->pending_action_tx); -+ drv->pending_action_tx = NULL; -+ -+ p2p_send_action_cb(drv->p2p, drv->pending_action_freq, -+ drv->pending_action_dst, -+ drv->pending_action_src, -+ drv->pending_action_bssid, -+ ret >= 0); -+ } -+#endif /* CONFIG_P2P */ -+ -+ return ret; -+} -+ -+ -+static void test_driver_scan(struct wpa_driver_test_data *drv, -+ struct sockaddr_un *from, socklen_t fromlen, -+ char *data) -+{ -+ char buf[512], *pos, *end; -+ int ret; -+ struct test_driver_bss *bss; -+ u8 sa[ETH_ALEN]; -+ u8 ie[512]; -+ size_t ielen; -+ union wpa_event_data event; -+ -+ /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */ -+ -+ wpa_printf(MSG_DEBUG, "test_driver: SCAN"); -+ -+ if (*data) { -+ if (*data != ' ' || -+ hwaddr_aton(data + 1, sa)) { -+ wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN " -+ "command format"); -+ return; -+ } -+ -+ data += 18; -+ while (*data == ' ') -+ data++; -+ ielen = os_strlen(data) / 2; -+ if (ielen > sizeof(ie)) -+ ielen = sizeof(ie); -+ if (hexstr2bin(data, ie, ielen) < 0) -+ ielen = 0; -+ -+ wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR, -+ MAC2STR(sa)); -+ wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_probe_req.sa = sa; -+ event.rx_probe_req.ie = ie; -+ event.rx_probe_req.ie_len = ielen; -+ wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); -+#ifdef CONFIG_P2P -+ if (drv->p2p) -+ p2p_probe_req_rx(drv->p2p, sa, ie, ielen); -+#endif /* CONFIG_P2P */ -+ } -+ -+ dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { -+ pos = buf; -+ end = buf + sizeof(buf); -+ -+ /* reply: SCANRESP BSSID SSID IEs */ -+ ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", -+ MAC2STR(bss->bssid)); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, -+ bss->ssid, bss->ssid_len); -+ ret = snprintf(pos, end - pos, " "); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen); -+ pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie, -+ bss->wps_probe_resp_ie_len); -+ -+ if (bss->privacy) { -+ ret = snprintf(pos, end - pos, " PRIVACY"); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ } -+ -+ sendto(drv->test_socket, buf, pos - buf, 0, -+ (struct sockaddr *) from, fromlen); -+ } -+} -+ -+ -+static void test_driver_assoc(struct wpa_driver_test_data *drv, -+ struct sockaddr_un *from, socklen_t fromlen, -+ char *data) -+{ -+ struct test_client_socket *cli; -+ u8 ie[256], ssid[32]; -+ size_t ielen, ssid_len = 0; -+ char *pos, *pos2, cmd[50]; -+ struct test_driver_bss *bss, *tmp; -+ -+ /* data: STA-addr SSID(hex) IEs(hex) */ -+ -+ cli = os_zalloc(sizeof(*cli)); -+ if (cli == NULL) -+ return; -+ -+ if (hwaddr_aton(data, cli->addr)) { -+ printf("test_socket: Invalid MAC address '%s' in ASSOC\n", -+ data); -+ os_free(cli); -+ return; -+ } -+ pos = data + 17; -+ while (*pos == ' ') -+ pos++; -+ pos2 = strchr(pos, ' '); -+ ielen = 0; -+ if (pos2) { -+ ssid_len = (pos2 - pos) / 2; -+ if (hexstr2bin(pos, ssid, ssid_len) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__); -+ os_free(cli); -+ return; -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID", -+ ssid, ssid_len); -+ -+ pos = pos2 + 1; -+ ielen = strlen(pos) / 2; -+ if (ielen > sizeof(ie)) -+ ielen = sizeof(ie); -+ if (hexstr2bin(pos, ie, ielen) < 0) -+ ielen = 0; -+ } -+ -+ bss = NULL; -+ dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) { -+ if (tmp->ssid_len == ssid_len && -+ os_memcmp(tmp->ssid, ssid, ssid_len) == 0) { -+ bss = tmp; -+ break; -+ } -+ } -+ if (bss == NULL) { -+ wpa_printf(MSG_DEBUG, "%s: No matching SSID found from " -+ "configured BSSes", __func__); -+ os_free(cli); -+ return; -+ } -+ -+ cli->bss = bss; -+ memcpy(&cli->un, from, sizeof(cli->un)); -+ cli->unlen = fromlen; -+ cli->next = drv->cli; -+ drv->cli = cli; -+ wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path", -+ (const u8 *) cli->un.sun_path, -+ cli->unlen - sizeof(cli->un.sun_family)); -+ -+ snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0", -+ MAC2STR(bss->bssid)); -+ sendto(drv->test_socket, cmd, strlen(cmd), 0, -+ (struct sockaddr *) from, fromlen); -+ -+ drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen, 0); -+} -+ -+ -+static void test_driver_disassoc(struct wpa_driver_test_data *drv, -+ struct sockaddr_un *from, socklen_t fromlen) -+{ -+ struct test_client_socket *cli; -+ -+ cli = test_driver_get_cli(drv, from, fromlen); -+ if (!cli) -+ return; -+ -+ drv_event_disassoc(drv->ctx, cli->addr); -+} -+ -+ -+static void test_driver_eapol(struct wpa_driver_test_data *drv, -+ struct sockaddr_un *from, socklen_t fromlen, -+ u8 *data, size_t datalen) -+{ -+#ifdef HOSTAPD -+ struct test_client_socket *cli; -+#endif /* HOSTAPD */ -+ const u8 *src = NULL; -+ -+ if (datalen > 14) { -+ /* Skip Ethernet header */ -+ src = data + ETH_ALEN; -+ wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src=" -+ MACSTR " proto=%04x", -+ MAC2STR(data), MAC2STR(src), -+ WPA_GET_BE16(data + 2 * ETH_ALEN)); -+ data += 14; -+ datalen -= 14; -+ } -+ -+#ifdef HOSTAPD -+ cli = test_driver_get_cli(drv, from, fromlen); -+ if (cli) { -+ drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data, -+ datalen); -+ } else { -+ wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown " -+ "client"); -+ } -+#else /* HOSTAPD */ -+ if (src) -+ drv_event_eapol_rx(drv->ctx, src, data, datalen); -+#endif /* HOSTAPD */ -+} -+ -+ -+static void test_driver_ether(struct wpa_driver_test_data *drv, -+ struct sockaddr_un *from, socklen_t fromlen, -+ u8 *data, size_t datalen) -+{ -+ struct l2_ethhdr *eth; -+ -+ if (datalen < sizeof(*eth)) -+ return; -+ -+ eth = (struct l2_ethhdr *) data; -+ wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src=" -+ MACSTR " proto=%04x", -+ MAC2STR(eth->h_dest), MAC2STR(eth->h_source), -+ be_to_host16(eth->h_proto)); -+ -+#ifdef CONFIG_IEEE80211R -+ if (be_to_host16(eth->h_proto) == ETH_P_RRB) { -+ union wpa_event_data ev; -+ os_memset(&ev, 0, sizeof(ev)); -+ ev.ft_rrb_rx.src = eth->h_source; -+ ev.ft_rrb_rx.data = data + sizeof(*eth); -+ ev.ft_rrb_rx.data_len = datalen - sizeof(*eth); -+ } -+#endif /* CONFIG_IEEE80211R */ -+} -+ -+ -+static void test_driver_mlme(struct wpa_driver_test_data *drv, -+ struct sockaddr_un *from, socklen_t fromlen, -+ u8 *data, size_t datalen) -+{ -+ struct ieee80211_hdr *hdr; -+ u16 fc; -+ union wpa_event_data event; -+ int freq = 0, own_freq; -+ struct test_driver_bss *bss; -+ -+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list); -+ -+ if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) { -+ size_t pos; -+ for (pos = 5; pos < datalen; pos++) { -+ if (data[pos] == ' ') -+ break; -+ } -+ if (pos < datalen) { -+ freq = atoi((const char *) &data[5]); -+ wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on " -+ "freq %d MHz", bss->ifname, freq); -+ pos++; -+ data += pos; -+ datalen -= pos; -+ } -+ } -+ -+ if (drv->remain_on_channel_freq) -+ own_freq = drv->remain_on_channel_freq; -+ else -+ own_freq = drv->current_freq; -+ -+ if (freq && own_freq && freq != own_freq) { -+ wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on " -+ "another frequency %d MHz (own %d MHz)", -+ bss->ifname, freq, own_freq); -+ return; -+ } -+ -+ hdr = (struct ieee80211_hdr *) data; -+ -+ if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) { -+ struct test_client_socket *cli; -+ cli = os_zalloc(sizeof(*cli)); -+ if (cli == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR, -+ MAC2STR(hdr->addr2)); -+ memcpy(cli->addr, hdr->addr2, ETH_ALEN); -+ memcpy(&cli->un, from, sizeof(cli->un)); -+ cli->unlen = fromlen; -+ cli->next = drv->cli; -+ drv->cli = cli; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame", -+ data, datalen); -+ fc = le_to_host16(hdr->frame_control); -+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) { -+ wpa_printf(MSG_ERROR, "%s: received non-mgmt frame", -+ __func__); -+ return; -+ } -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_mgmt.frame = data; -+ event.rx_mgmt.frame_len = datalen; -+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); -+} -+ -+ -+static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct wpa_driver_test_data *drv = eloop_ctx; -+ char buf[2000]; -+ int res; -+ struct sockaddr_un from; -+ socklen_t fromlen = sizeof(from); -+ -+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0, -+ (struct sockaddr *) &from, &fromlen); -+ if (res < 0) { -+ perror("recvfrom(test_socket)"); -+ return; -+ } -+ buf[res] = '\0'; -+ -+ wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); -+ -+ if (strncmp(buf, "SCAN", 4) == 0) { -+ test_driver_scan(drv, &from, fromlen, buf + 4); -+ } else if (strncmp(buf, "ASSOC ", 6) == 0) { -+ test_driver_assoc(drv, &from, fromlen, buf + 6); -+ } else if (strcmp(buf, "DISASSOC") == 0) { -+ test_driver_disassoc(drv, &from, fromlen); -+ } else if (strncmp(buf, "EAPOL ", 6) == 0) { -+ test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6, -+ res - 6); -+ } else if (strncmp(buf, "ETHER ", 6) == 0) { -+ test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6, -+ res - 6); -+ } else if (strncmp(buf, "MLME ", 5) == 0) { -+ test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5); -+ } else { -+ wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", -+ (u8 *) buf, res); -+ } -+} -+ -+ -+static int test_driver_set_generic_elem(void *priv, -+ const u8 *elem, size_t elem_len) -+{ -+ struct test_driver_bss *bss = priv; -+ -+ os_free(bss->ie); -+ -+ if (elem == NULL) { -+ bss->ie = NULL; -+ bss->ielen = 0; -+ return 0; -+ } -+ -+ bss->ie = os_malloc(elem_len); -+ if (bss->ie == NULL) { -+ bss->ielen = 0; -+ return -1; -+ } -+ -+ memcpy(bss->ie, elem, elem_len); -+ bss->ielen = elem_len; -+ return 0; -+} -+ -+ -+static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, -+ const struct wpabuf *proberesp, -+ const struct wpabuf *assocresp) -+{ -+ struct test_driver_bss *bss = priv; -+ -+ if (beacon == NULL) -+ wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE"); -+ else -+ wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE", -+ beacon); -+ -+ os_free(bss->wps_beacon_ie); -+ -+ if (beacon == NULL) { -+ bss->wps_beacon_ie = NULL; -+ bss->wps_beacon_ie_len = 0; -+ } else { -+ bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon)); -+ if (bss->wps_beacon_ie == NULL) { -+ bss->wps_beacon_ie_len = 0; -+ return -1; -+ } -+ -+ os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon), -+ wpabuf_len(beacon)); -+ bss->wps_beacon_ie_len = wpabuf_len(beacon); -+ } -+ -+ if (proberesp == NULL) -+ wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS " -+ "IE"); -+ else -+ wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS " -+ "IE", proberesp); -+ -+ os_free(bss->wps_probe_resp_ie); -+ -+ if (proberesp == NULL) { -+ bss->wps_probe_resp_ie = NULL; -+ bss->wps_probe_resp_ie_len = 0; -+ } else { -+ bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp)); -+ if (bss->wps_probe_resp_ie == NULL) { -+ bss->wps_probe_resp_ie_len = 0; -+ return -1; -+ } -+ -+ os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp), -+ wpabuf_len(proberesp)); -+ bss->wps_probe_resp_ie_len = wpabuf_len(proberesp); -+ } -+ -+ return 0; -+} -+ -+ -+static int test_driver_sta_deauth(void *priv, const u8 *own_addr, -+ const u8 *addr, int reason) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct test_client_socket *cli; -+ -+ if (drv->test_socket < 0) -+ return -1; -+ -+ cli = drv->cli; -+ while (cli) { -+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0) -+ break; -+ cli = cli->next; -+ } -+ -+ if (!cli) -+ return -1; -+ -+ return sendto(drv->test_socket, "DEAUTH", 6, 0, -+ (struct sockaddr *) &cli->un, cli->unlen); -+} -+ -+ -+static int test_driver_sta_disassoc(void *priv, const u8 *own_addr, -+ const u8 *addr, int reason) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct test_client_socket *cli; -+ -+ if (drv->test_socket < 0) -+ return -1; -+ -+ cli = drv->cli; -+ while (cli) { -+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0) -+ break; -+ cli = cli->next; -+ } -+ -+ if (!cli) -+ return -1; -+ -+ return sendto(drv->test_socket, "DISASSOC", 8, 0, -+ (struct sockaddr *) &cli->un, cli->unlen); -+} -+ -+ -+static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid, -+ void *bss_ctx, void **drv_priv) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct test_driver_bss *bss; -+ -+ wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")", -+ __func__, ifname, MAC2STR(bssid)); -+ -+ bss = os_zalloc(sizeof(*bss)); -+ if (bss == NULL) -+ return -1; -+ -+ bss->bss_ctx = bss_ctx; -+ bss->drv = drv; -+ os_strlcpy(bss->ifname, ifname, IFNAMSIZ); -+ os_memcpy(bss->bssid, bssid, ETH_ALEN); -+ -+ dl_list_add(&drv->bss, &bss->list); -+ if (drv->global) { -+ drv->global->bss_add_used = 1; -+ os_memcpy(drv->global->req_addr, bssid, ETH_ALEN); -+ } -+ -+ if (drv_priv) -+ *drv_priv = bss; -+ -+ return 0; -+} -+ -+ -+static int test_driver_bss_remove(void *priv, const char *ifname) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct test_driver_bss *bss; -+ struct test_client_socket *cli, *prev_c; -+ -+ wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname); -+ -+ dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { -+ if (strcmp(bss->ifname, ifname) != 0) -+ continue; -+ -+ for (prev_c = NULL, cli = drv->cli; cli; -+ prev_c = cli, cli = cli->next) { -+ if (cli->bss != bss) -+ continue; -+ if (prev_c) -+ prev_c->next = cli->next; -+ else -+ drv->cli = cli->next; -+ os_free(cli); -+ break; -+ } -+ -+ dl_list_del(&bss->list); -+ test_driver_free_bss(bss); -+ return 0; -+ } -+ -+ return -1; -+} -+ -+ -+static int test_driver_if_add(void *priv, enum wpa_driver_if_type type, -+ const char *ifname, const u8 *addr, -+ void *bss_ctx, void **drv_priv, -+ char *force_ifname, u8 *if_addr, -+ const char *bridge) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ -+ wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)", -+ __func__, type, ifname, bss_ctx); -+ if (addr) -+ os_memcpy(if_addr, addr, ETH_ALEN); -+ else { -+ drv->alloc_iface_idx++; -+ if_addr[0] = 0x02; /* locally administered */ -+ sha1_prf(drv->own_addr, ETH_ALEN, -+ "hostapd test addr generation", -+ (const u8 *) &drv->alloc_iface_idx, -+ sizeof(drv->alloc_iface_idx), -+ if_addr + 1, ETH_ALEN - 1); -+ } -+ if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO || -+ type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP) -+ return test_driver_bss_add(priv, ifname, if_addr, bss_ctx, -+ drv_priv); -+ return 0; -+} -+ -+ -+static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type, -+ const char *ifname) -+{ -+ wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname); -+ if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO || -+ type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP) -+ return test_driver_bss_remove(priv, ifname); -+ return 0; -+} -+ -+ -+static int test_driver_valid_bss_mask(void *priv, const u8 *addr, -+ const u8 *mask) -+{ -+ return 0; -+} -+ -+ -+static int test_driver_set_ssid(void *priv, const u8 *buf, int len) -+{ -+ struct test_driver_bss *bss = priv; -+ -+ wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname); -+ if (len < 0) -+ return -1; -+ wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len); -+ -+ if ((size_t) len > sizeof(bss->ssid)) -+ return -1; -+ -+ os_memcpy(bss->ssid, buf, len); -+ bss->ssid_len = len; -+ -+ return 0; -+} -+ -+ -+static int test_driver_set_privacy(void *priv, int enabled) -+{ -+ struct test_driver_bss *dbss = priv; -+ -+ wpa_printf(MSG_DEBUG, "%s(enabled=%d)", __func__, enabled); -+ dbss->privacy = enabled; -+ -+ return 0; -+} -+ -+ -+static int test_driver_set_sta_vlan(void *priv, const u8 *addr, -+ const char *ifname, int vlan_id) -+{ -+ wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)", -+ __func__, MAC2STR(addr), ifname, vlan_id); -+ return 0; -+} -+ -+ -+static int test_driver_sta_add(void *priv, -+ struct hostapd_sta_add_params *params) -+{ -+ struct test_driver_bss *bss = priv; -+ struct wpa_driver_test_data *drv = bss->drv; -+ struct test_client_socket *cli; -+ -+ wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d " -+ "capability=0x%x listen_interval=%d)", -+ __func__, bss->ifname, MAC2STR(params->addr), params->aid, -+ params->capability, params->listen_interval); -+ wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates", -+ params->supp_rates, params->supp_rates_len); -+ -+ cli = drv->cli; -+ while (cli) { -+ if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0) -+ break; -+ cli = cli->next; -+ } -+ if (!cli) { -+ wpa_printf(MSG_DEBUG, "%s: no matching client entry", -+ __func__); -+ return -1; -+ } -+ -+ cli->bss = bss; -+ -+ return 0; -+} -+ -+ -+static struct wpa_driver_test_data * test_alloc_data(void *ctx, -+ const char *ifname) -+{ -+ struct wpa_driver_test_data *drv; -+ struct test_driver_bss *bss; -+ -+ drv = os_zalloc(sizeof(struct wpa_driver_test_data)); -+ if (drv == NULL) { -+ wpa_printf(MSG_ERROR, "Could not allocate memory for test " -+ "driver data"); -+ return NULL; -+ } -+ -+ bss = os_zalloc(sizeof(struct test_driver_bss)); -+ if (bss == NULL) { -+ os_free(drv); -+ return NULL; -+ } -+ -+ drv->ctx = ctx; -+ wpa_trace_add_ref(drv, ctx, ctx); -+ dl_list_init(&drv->bss); -+ dl_list_add(&drv->bss, &bss->list); -+ os_strlcpy(bss->ifname, ifname, IFNAMSIZ); -+ bss->bss_ctx = ctx; -+ bss->drv = drv; -+ -+ /* Generate a MAC address to help testing with multiple STAs */ -+ drv->own_addr[0] = 0x02; /* locally administered */ -+ sha1_prf((const u8 *) ifname, os_strlen(ifname), -+ "test mac addr generation", -+ NULL, 0, drv->own_addr + 1, ETH_ALEN - 1); -+ -+ return drv; -+} -+ -+ -+static void * test_driver_init(struct hostapd_data *hapd, -+ struct wpa_init_params *params) -+{ -+ struct wpa_driver_test_data *drv; -+ struct sockaddr_un addr_un; -+ struct sockaddr_in addr_in; -+ struct sockaddr *addr; -+ socklen_t alen; -+ struct test_driver_bss *bss; -+ -+ drv = test_alloc_data(hapd, params->ifname); -+ if (drv == NULL) -+ return NULL; -+ drv->ap = 1; -+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list); -+ -+ bss->bss_ctx = hapd; -+ os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN); -+ os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN); -+ -+ if (params->test_socket) { -+ if (os_strlen(params->test_socket) >= -+ sizeof(addr_un.sun_path)) { -+ printf("Too long test_socket path\n"); -+ wpa_driver_test_deinit(bss); -+ return NULL; -+ } -+ if (strncmp(params->test_socket, "DIR:", 4) == 0) { -+ size_t len = strlen(params->test_socket) + 30; -+ drv->test_dir = os_strdup(params->test_socket + 4); -+ drv->own_socket_path = os_malloc(len); -+ if (drv->own_socket_path) { -+ snprintf(drv->own_socket_path, len, -+ "%s/AP-" MACSTR, -+ params->test_socket + 4, -+ MAC2STR(params->own_addr)); -+ } -+ } else if (strncmp(params->test_socket, "UDP:", 4) == 0) { -+ drv->udp_port = atoi(params->test_socket + 4); -+ } else { -+ drv->own_socket_path = os_strdup(params->test_socket); -+ } -+ if (drv->own_socket_path == NULL && drv->udp_port == 0) { -+ wpa_driver_test_deinit(bss); -+ return NULL; -+ } -+ -+ drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX, -+ SOCK_DGRAM, 0); -+ if (drv->test_socket < 0) { -+ perror("socket"); -+ wpa_driver_test_deinit(bss); -+ return NULL; -+ } -+ -+ if (drv->udp_port) { -+ os_memset(&addr_in, 0, sizeof(addr_in)); -+ addr_in.sin_family = AF_INET; -+ addr_in.sin_port = htons(drv->udp_port); -+ addr = (struct sockaddr *) &addr_in; -+ alen = sizeof(addr_in); -+ } else { -+ os_memset(&addr_un, 0, sizeof(addr_un)); -+ addr_un.sun_family = AF_UNIX; -+ os_strlcpy(addr_un.sun_path, drv->own_socket_path, -+ sizeof(addr_un.sun_path)); -+ addr = (struct sockaddr *) &addr_un; -+ alen = sizeof(addr_un); -+ } -+ if (bind(drv->test_socket, addr, alen) < 0) { -+ perror("bind(PF_UNIX)"); -+ close(drv->test_socket); -+ if (drv->own_socket_path) -+ unlink(drv->own_socket_path); -+ wpa_driver_test_deinit(bss); -+ return NULL; -+ } -+ eloop_register_read_sock(drv->test_socket, -+ test_driver_receive_unix, drv, NULL); -+ } else -+ drv->test_socket = -1; -+ -+ return bss; -+} -+ -+ -+static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_test_data *drv = eloop_ctx; -+ -+#ifdef DRIVER_TEST_UNIX -+ if (drv->associated && drv->hostapd_addr_set) { -+ struct stat st; -+ if (stat(drv->hostapd_addr.sun_path, &st) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s", -+ __func__, strerror(errno)); -+ drv->associated = 0; -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -+ } -+ } -+#endif /* DRIVER_TEST_UNIX */ -+ -+ eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); -+} -+ -+ -+static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_test_data *drv = eloop_ctx; -+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); -+ if (drv->pending_p2p_scan && drv->p2p) { -+#ifdef CONFIG_P2P -+ size_t i; -+ for (i = 0; i < drv->num_scanres; i++) { -+ struct wpa_scan_res *bss = drv->scanres[i]; -+ if (p2p_scan_res_handler(drv->p2p, bss->bssid, -+ bss->freq, bss->level, -+ (const u8 *) (bss + 1), -+ bss->ie_len) > 0) -+ return; -+ } -+ p2p_scan_res_handled(drv->p2p); -+#endif /* CONFIG_P2P */ -+ return; -+ } -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+} -+ -+ -+#ifdef DRIVER_TEST_UNIX -+static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv, -+ const char *path) -+{ -+ struct dirent *dent; -+ DIR *dir; -+ struct sockaddr_un addr; -+ char cmd[512], *pos, *end; -+ int ret; -+ -+ dir = opendir(path); -+ if (dir == NULL) -+ return; -+ -+ end = cmd + sizeof(cmd); -+ pos = cmd; -+ ret = os_snprintf(pos, end - pos, "SCAN " MACSTR, -+ MAC2STR(drv->own_addr)); -+ if (ret >= 0 && ret < end - pos) -+ pos += ret; -+ if (drv->probe_req_ie) { -+ ret = os_snprintf(pos, end - pos, " "); -+ if (ret >= 0 && ret < end - pos) -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie, -+ drv->probe_req_ie_len); -+ } -+ if (drv->probe_req_ssid_len) { -+ /* Add SSID IE */ -+ ret = os_snprintf(pos, end - pos, "%02x%02x", -+ WLAN_EID_SSID, -+ (unsigned int) drv->probe_req_ssid_len); -+ if (ret >= 0 && ret < end - pos) -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid, -+ drv->probe_req_ssid_len); -+ } -+ end[-1] = '\0'; -+ -+ while ((dent = readdir(dir))) { -+ if (os_strncmp(dent->d_name, "AP-", 3) != 0 && -+ os_strncmp(dent->d_name, "STA-", 4) != 0) -+ continue; -+ if (drv->own_socket_path) { -+ size_t olen, dlen; -+ olen = os_strlen(drv->own_socket_path); -+ dlen = os_strlen(dent->d_name); -+ if (olen >= dlen && -+ os_strcmp(dent->d_name, -+ drv->own_socket_path + olen - dlen) == 0) -+ continue; -+ } -+ wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name); -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", -+ path, dent->d_name); -+ -+ if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0, -+ (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("sendto(test_socket)"); -+ } -+ } -+ closedir(dir); -+} -+#endif /* DRIVER_TEST_UNIX */ -+ -+ -+static int wpa_driver_test_scan(void *priv, -+ struct wpa_driver_scan_params *params) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ size_t i; -+ -+ wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); -+ -+ os_free(drv->probe_req_ie); -+ if (params->extra_ies) { -+ drv->probe_req_ie = os_malloc(params->extra_ies_len); -+ if (drv->probe_req_ie == NULL) { -+ drv->probe_req_ie_len = 0; -+ return -1; -+ } -+ os_memcpy(drv->probe_req_ie, params->extra_ies, -+ params->extra_ies_len); -+ drv->probe_req_ie_len = params->extra_ies_len; -+ } else { -+ drv->probe_req_ie = NULL; -+ drv->probe_req_ie_len = 0; -+ } -+ -+ for (i = 0; i < params->num_ssids; i++) -+ wpa_hexdump(MSG_DEBUG, "Scan SSID", -+ params->ssids[i].ssid, params->ssids[i].ssid_len); -+ drv->probe_req_ssid_len = 0; -+ if (params->num_ssids) { -+ os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid, -+ params->ssids[0].ssid_len); -+ drv->probe_req_ssid_len = params->ssids[0].ssid_len; -+ } -+ wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)", -+ params->extra_ies, params->extra_ies_len); -+ -+ drv->num_scanres = 0; -+ -+#ifdef DRIVER_TEST_UNIX -+ if (drv->test_socket >= 0 && drv->test_dir) -+ wpa_driver_scan_dir(drv, drv->test_dir); -+ -+ if (drv->test_socket >= 0 && drv->hostapd_addr_set && -+ sendto(drv->test_socket, "SCAN", 4, 0, -+ (struct sockaddr *) &drv->hostapd_addr, -+ sizeof(drv->hostapd_addr)) < 0) { -+ perror("sendto(test_socket)"); -+ } -+#endif /* DRIVER_TEST_UNIX */ -+ -+ if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set && -+ sendto(drv->test_socket, "SCAN", 4, 0, -+ (struct sockaddr *) &drv->hostapd_addr_udp, -+ sizeof(drv->hostapd_addr_udp)) < 0) { -+ perror("sendto(test_socket)"); -+ } -+ -+ eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx); -+ eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv, -+ drv->ctx); -+ return 0; -+} -+ -+ -+static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct wpa_scan_results *res; -+ size_t i; -+ -+ res = os_zalloc(sizeof(*res)); -+ if (res == NULL) -+ return NULL; -+ -+ res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *)); -+ if (res->res == NULL) { -+ os_free(res); -+ return NULL; -+ } -+ -+ for (i = 0; i < drv->num_scanres; i++) { -+ struct wpa_scan_res *r; -+ if (drv->scanres[i] == NULL) -+ continue; -+ r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len); -+ if (r == NULL) -+ break; -+ os_memcpy(r, drv->scanres[i], -+ sizeof(*r) + drv->scanres[i]->ie_len); -+ res->res[res->num++] = r; -+ } -+ -+ return res; -+} -+ -+ -+static int wpa_driver_test_set_key(const char *ifname, void *priv, -+ enum wpa_alg alg, const u8 *addr, -+ int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d " -+ "set_tx=%d", -+ __func__, ifname, priv, alg, key_idx, set_tx); -+ if (addr) -+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); -+ if (seq) -+ wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len); -+ if (key) -+ wpa_hexdump_key(MSG_DEBUG, " key", key, key_len); -+ return 0; -+} -+ -+ -+static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap) -+{ -+ if (ap && !drv->ap) { -+ wpa_driver_test_close_test_socket(drv); -+ wpa_driver_test_attach(drv, drv->test_dir, 1); -+ drv->ap = 1; -+ } else if (!ap && drv->ap) { -+ wpa_driver_test_close_test_socket(drv); -+ wpa_driver_test_attach(drv, drv->test_dir, 0); -+ drv->ap = 0; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_test_associate( -+ void *priv, struct wpa_driver_associate_params *params) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " -+ "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", -+ __func__, priv, params->freq, params->pairwise_suite, -+ params->group_suite, params->key_mgmt_suite, -+ params->auth_alg, params->mode); -+ wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP); -+ if (params->bssid) { -+ wpa_printf(MSG_DEBUG, " bssid=" MACSTR, -+ MAC2STR(params->bssid)); -+ } -+ if (params->ssid) { -+ wpa_hexdump_ascii(MSG_DEBUG, " ssid", -+ params->ssid, params->ssid_len); -+ } -+ if (params->wpa_ie) { -+ wpa_hexdump(MSG_DEBUG, " wpa_ie", -+ params->wpa_ie, params->wpa_ie_len); -+ drv->assoc_wpa_ie_len = params->wpa_ie_len; -+ if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie)) -+ drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie); -+ os_memcpy(drv->assoc_wpa_ie, params->wpa_ie, -+ drv->assoc_wpa_ie_len); -+ } else -+ drv->assoc_wpa_ie_len = 0; -+ -+ wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP); -+ -+ drv->ibss = params->mode == IEEE80211_MODE_IBSS; -+ dbss->privacy = params->key_mgmt_suite & -+ (WPA_KEY_MGMT_IEEE8021X | -+ WPA_KEY_MGMT_PSK | -+ WPA_KEY_MGMT_WPA_NONE | -+ WPA_KEY_MGMT_FT_IEEE8021X | -+ WPA_KEY_MGMT_FT_PSK | -+ WPA_KEY_MGMT_IEEE8021X_SHA256 | -+ WPA_KEY_MGMT_PSK_SHA256); -+ if (params->wep_key_len[params->wep_tx_keyidx]) -+ dbss->privacy = 1; -+ -+#ifdef DRIVER_TEST_UNIX -+ if (drv->test_dir && params->bssid && -+ params->mode != IEEE80211_MODE_IBSS) { -+ os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); -+ drv->hostapd_addr.sun_family = AF_UNIX; -+ os_snprintf(drv->hostapd_addr.sun_path, -+ sizeof(drv->hostapd_addr.sun_path), -+ "%s/AP-" MACSTR, -+ drv->test_dir, MAC2STR(params->bssid)); -+ drv->hostapd_addr_set = 1; -+ } -+#endif /* DRIVER_TEST_UNIX */ -+ -+ if (params->mode == IEEE80211_MODE_AP) { -+ os_memcpy(dbss->ssid, params->ssid, params->ssid_len); -+ dbss->ssid_len = params->ssid_len; -+ os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN); -+ if (params->wpa_ie && params->wpa_ie_len) { -+ dbss->ie = os_malloc(params->wpa_ie_len); -+ if (dbss->ie) { -+ os_memcpy(dbss->ie, params->wpa_ie, -+ params->wpa_ie_len); -+ dbss->ielen = params->wpa_ie_len; -+ } -+ } -+ } else if (drv->test_socket >= 0 && -+ (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) { -+ char cmd[200], *pos, *end; -+ int ret; -+ end = cmd + sizeof(cmd); -+ pos = cmd; -+ ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ", -+ MAC2STR(drv->own_addr)); -+ if (ret >= 0 && ret < end - pos) -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, params->ssid, -+ params->ssid_len); -+ ret = os_snprintf(pos, end - pos, " "); -+ if (ret >= 0 && ret < end - pos) -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie, -+ params->wpa_ie_len); -+ end[-1] = '\0'; -+#ifdef DRIVER_TEST_UNIX -+ if (drv->hostapd_addr_set && -+ sendto(drv->test_socket, cmd, os_strlen(cmd), 0, -+ (struct sockaddr *) &drv->hostapd_addr, -+ sizeof(drv->hostapd_addr)) < 0) { -+ perror("sendto(test_socket)"); -+ return -1; -+ } -+#endif /* DRIVER_TEST_UNIX */ -+ if (drv->hostapd_addr_udp_set && -+ sendto(drv->test_socket, cmd, os_strlen(cmd), 0, -+ (struct sockaddr *) &drv->hostapd_addr_udp, -+ sizeof(drv->hostapd_addr_udp)) < 0) { -+ perror("sendto(test_socket)"); -+ return -1; -+ } -+ -+ os_memcpy(dbss->ssid, params->ssid, params->ssid_len); -+ dbss->ssid_len = params->ssid_len; -+ } else { -+ drv->associated = 1; -+ if (params->mode == IEEE80211_MODE_IBSS) { -+ os_memcpy(dbss->ssid, params->ssid, params->ssid_len); -+ dbss->ssid_len = params->ssid_len; -+ if (params->bssid) -+ os_memcpy(dbss->bssid, params->bssid, -+ ETH_ALEN); -+ else { -+ os_get_random(dbss->bssid, ETH_ALEN); -+ dbss->bssid[0] &= ~0x01; -+ dbss->bssid[0] |= 0x02; -+ } -+ } -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_test_get_bssid(void *priv, u8 *bssid) -+{ -+ struct test_driver_bss *dbss = priv; -+ os_memcpy(bssid, dbss->bssid, ETH_ALEN); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_get_ssid(void *priv, u8 *ssid) -+{ -+ struct test_driver_bss *dbss = priv; -+ os_memcpy(ssid, dbss->ssid, 32); -+ return dbss->ssid_len; -+} -+ -+ -+static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv) -+{ -+#ifdef DRIVER_TEST_UNIX -+ if (drv->test_socket >= 0 && -+ sendto(drv->test_socket, "DISASSOC", 8, 0, -+ (struct sockaddr *) &drv->hostapd_addr, -+ sizeof(drv->hostapd_addr)) < 0) { -+ perror("sendto(test_socket)"); -+ return -1; -+ } -+#endif /* DRIVER_TEST_UNIX */ -+ if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set && -+ sendto(drv->test_socket, "DISASSOC", 8, 0, -+ (struct sockaddr *) &drv->hostapd_addr_udp, -+ sizeof(drv->hostapd_addr_udp)) < 0) { -+ perror("sendto(test_socket)"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", -+ __func__, MAC2STR(addr), reason_code); -+ os_memset(dbss->bssid, 0, ETH_ALEN); -+ drv->associated = 0; -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -+ return wpa_driver_test_send_disassoc(drv); -+} -+ -+ -+static int wpa_driver_test_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", -+ __func__, MAC2STR(addr), reason_code); -+ os_memset(dbss->bssid, 0, ETH_ALEN); -+ drv->associated = 0; -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -+ return wpa_driver_test_send_disassoc(drv); -+} -+ -+ -+static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) -+{ -+ const u8 *end, *pos; -+ -+ pos = (const u8 *) (res + 1); -+ end = pos + res->ie_len; -+ -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == ie) -+ return pos; -+ pos += 2 + pos[1]; -+ } -+ -+ return NULL; -+} -+ -+ -+static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv, -+ struct sockaddr *from, -+ socklen_t fromlen, -+ const char *data) -+{ -+ struct wpa_scan_res *res; -+ const char *pos, *pos2; -+ size_t len; -+ u8 *ie_pos, *ie_start, *ie_end; -+#define MAX_IE_LEN 1000 -+ const u8 *ds_params; -+ -+ wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data); -+ if (drv->num_scanres >= MAX_SCAN_RESULTS) { -+ wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan " -+ "result"); -+ return; -+ } -+ -+ /* SCANRESP BSSID SSID IEs */ -+ -+ res = os_zalloc(sizeof(*res) + MAX_IE_LEN); -+ if (res == NULL) -+ return; -+ ie_start = ie_pos = (u8 *) (res + 1); -+ ie_end = ie_pos + MAX_IE_LEN; -+ -+ if (hwaddr_aton(data, res->bssid)) { -+ wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres"); -+ os_free(res); -+ return; -+ } -+ -+ pos = data + 17; -+ while (*pos == ' ') -+ pos++; -+ pos2 = os_strchr(pos, ' '); -+ if (pos2 == NULL) { -+ wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination " -+ "in scanres"); -+ os_free(res); -+ return; -+ } -+ len = (pos2 - pos) / 2; -+ if (len > 32) -+ len = 32; -+ /* -+ * Generate SSID IE from the SSID field since this IE is not included -+ * in the main IE field. -+ */ -+ *ie_pos++ = WLAN_EID_SSID; -+ *ie_pos++ = len; -+ if (hexstr2bin(pos, ie_pos, len) < 0) { -+ wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres"); -+ os_free(res); -+ return; -+ } -+ ie_pos += len; -+ -+ pos = pos2 + 1; -+ pos2 = os_strchr(pos, ' '); -+ if (pos2 == NULL) -+ len = os_strlen(pos) / 2; -+ else -+ len = (pos2 - pos) / 2; -+ if ((int) len > ie_end - ie_pos) -+ len = ie_end - ie_pos; -+ if (hexstr2bin(pos, ie_pos, len) < 0) { -+ wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres"); -+ os_free(res); -+ return; -+ } -+ ie_pos += len; -+ res->ie_len = ie_pos - ie_start; -+ -+ if (pos2) { -+ pos = pos2 + 1; -+ while (*pos == ' ') -+ pos++; -+ if (os_strstr(pos, "PRIVACY")) -+ res->caps |= IEEE80211_CAP_PRIVACY; -+ if (os_strstr(pos, "IBSS")) -+ res->caps |= IEEE80211_CAP_IBSS; -+ } -+ -+ ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS); -+ if (ds_params && ds_params[1] > 0) { -+ if (ds_params[2] >= 1 && ds_params[2] <= 13) -+ res->freq = 2407 + ds_params[2] * 5; -+ } -+ -+ os_free(drv->scanres[drv->num_scanres]); -+ drv->scanres[drv->num_scanres++] = res; -+} -+ -+ -+static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv, -+ struct sockaddr *from, -+ socklen_t fromlen, -+ const char *data) -+{ -+ struct test_driver_bss *bss; -+ -+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list); -+ -+ /* ASSOCRESP BSSID */ -+ if (hwaddr_aton(data, bss->bssid)) { -+ wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in " -+ "assocresp"); -+ } -+ if (drv->use_associnfo) { -+ union wpa_event_data event; -+ os_memset(&event, 0, sizeof(event)); -+ event.assoc_info.req_ies = drv->assoc_wpa_ie; -+ event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len; -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event); -+ } -+ drv->associated = 1; -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); -+} -+ -+ -+static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv, -+ struct sockaddr *from, -+ socklen_t fromlen) -+{ -+ drv->associated = 0; -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); -+} -+ -+ -+static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv, -+ struct sockaddr *from, -+ socklen_t fromlen, -+ const u8 *data, size_t data_len) -+{ -+ const u8 *src; -+ struct test_driver_bss *bss; -+ -+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list); -+ -+ if (data_len > 14) { -+ /* Skip Ethernet header */ -+ src = data + ETH_ALEN; -+ data += 14; -+ data_len -= 14; -+ } else -+ src = bss->bssid; -+ -+ drv_event_eapol_rx(drv->ctx, src, data, data_len); -+} -+ -+ -+static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, -+ struct sockaddr *from, -+ socklen_t fromlen, -+ const u8 *data, size_t data_len) -+{ -+ int freq = 0, own_freq; -+ union wpa_event_data event; -+ const struct ieee80211_mgmt *mgmt; -+ u16 fc; -+ struct test_driver_bss *bss; -+ -+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list); -+ if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) { -+ size_t pos; -+ for (pos = 5; pos < data_len; pos++) { -+ if (data[pos] == ' ') -+ break; -+ } -+ if (pos < data_len) { -+ freq = atoi((const char *) &data[5]); -+ wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on " -+ "freq %d MHz", bss->ifname, freq); -+ pos++; -+ data += pos; -+ data_len -= pos; -+ } -+ } -+ -+ if (drv->remain_on_channel_freq) -+ own_freq = drv->remain_on_channel_freq; -+ else -+ own_freq = drv->current_freq; -+ -+ if (freq && own_freq && freq != own_freq) { -+ wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on " -+ "another frequency %d MHz (own %d MHz)", -+ bss->ifname, freq, own_freq); -+ return; -+ } -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.mlme_rx.buf = data; -+ event.mlme_rx.len = data_len; -+ event.mlme_rx.freq = freq; -+ wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event); -+ -+ mgmt = (const struct ieee80211_mgmt *) data; -+ fc = le_to_host16(mgmt->frame_control); -+ -+ if (drv->probe_req_report && data_len >= 24) { -+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && -+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) { -+ os_memset(&event, 0, sizeof(event)); -+ event.rx_probe_req.sa = mgmt->sa; -+ event.rx_probe_req.ie = mgmt->u.probe_req.variable; -+ event.rx_probe_req.ie_len = -+ data_len - (mgmt->u.probe_req.variable - data); -+ wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, -+ &event); -+#ifdef CONFIG_P2P -+ if (drv->p2p) -+ p2p_probe_req_rx(drv->p2p, mgmt->sa, -+ event.rx_probe_req.ie, -+ event.rx_probe_req.ie_len); -+#endif /* CONFIG_P2P */ -+ } -+ } -+ -+#ifdef CONFIG_P2P -+ if (drv->p2p && -+ WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && -+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { -+ size_t hdr_len; -+ hdr_len = (const u8 *) -+ &mgmt->u.action.u.vs_public_action.action - data; -+ p2p_rx_action(drv->p2p, mgmt->da, mgmt->sa, mgmt->bssid, -+ mgmt->u.action.category, -+ &mgmt->u.action.u.vs_public_action.action, -+ data_len - hdr_len, freq); -+ } -+#endif /* CONFIG_P2P */ -+ -+} -+ -+ -+static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, -+ struct sockaddr *from, -+ socklen_t fromlen, -+ const u8 *data, size_t data_len) -+{ -+ char buf[512], *pos, *end; -+ int ret; -+ struct test_driver_bss *bss; -+ -+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list); -+ -+ /* data: optional [ STA-addr | ' ' | IEs(hex) ] */ -+#ifdef CONFIG_P2P -+ if (drv->probe_req_report && drv->p2p && data_len) { -+ const char *d = (const char *) data; -+ u8 sa[ETH_ALEN]; -+ u8 ie[512]; -+ size_t ielen; -+ -+ if (hwaddr_aton(d, sa)) -+ return; -+ d += 18; -+ while (*d == ' ') -+ d++; -+ ielen = os_strlen(d) / 2; -+ if (ielen > sizeof(ie)) -+ ielen = sizeof(ie); -+ if (hexstr2bin(d, ie, ielen) < 0) -+ ielen = 0; -+ drv->probe_from = from; -+ drv->probe_from_len = fromlen; -+ p2p_probe_req_rx(drv->p2p, sa, ie, ielen); -+ drv->probe_from = NULL; -+ } -+#endif /* CONFIG_P2P */ -+ -+ if (!drv->ibss) -+ return; -+ -+ pos = buf; -+ end = buf + sizeof(buf); -+ -+ /* reply: SCANRESP BSSID SSID IEs */ -+ ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", -+ MAC2STR(bss->bssid)); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, -+ bss->ssid, bss->ssid_len); -+ ret = snprintf(pos, end - pos, " "); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie, -+ drv->assoc_wpa_ie_len); -+ -+ if (bss->privacy) { -+ ret = snprintf(pos, end - pos, " PRIVACY"); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ } -+ -+ ret = snprintf(pos, end - pos, " IBSS"); -+ if (ret < 0 || ret >= end - pos) -+ return; -+ pos += ret; -+ -+ sendto(drv->test_socket, buf, pos - buf, 0, -+ (struct sockaddr *) from, fromlen); -+} -+ -+ -+static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx, -+ void *sock_ctx) -+{ -+ struct wpa_driver_test_data *drv = eloop_ctx; -+ char *buf; -+ int res; -+ struct sockaddr_storage from; -+ socklen_t fromlen = sizeof(from); -+ const size_t buflen = 2000; -+ -+ if (drv->ap) { -+ test_driver_receive_unix(sock, eloop_ctx, sock_ctx); -+ return; -+ } -+ -+ buf = os_malloc(buflen); -+ if (buf == NULL) -+ return; -+ res = recvfrom(sock, buf, buflen - 1, 0, -+ (struct sockaddr *) &from, &fromlen); -+ if (res < 0) { -+ perror("recvfrom(test_socket)"); -+ os_free(buf); -+ return; -+ } -+ buf[res] = '\0'; -+ -+ wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); -+ -+ if (os_strncmp(buf, "SCANRESP ", 9) == 0) { -+ wpa_driver_test_scanresp(drv, (struct sockaddr *) &from, -+ fromlen, buf + 9); -+ } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) { -+ wpa_driver_test_assocresp(drv, (struct sockaddr *) &from, -+ fromlen, buf + 10); -+ } else if (os_strcmp(buf, "DISASSOC") == 0) { -+ wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, -+ fromlen); -+ } else if (os_strcmp(buf, "DEAUTH") == 0) { -+ wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, -+ fromlen); -+ } else if (os_strncmp(buf, "EAPOL ", 6) == 0) { -+ wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen, -+ (const u8 *) buf + 6, res - 6); -+ } else if (os_strncmp(buf, "MLME ", 5) == 0) { -+ wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen, -+ (const u8 *) buf + 5, res - 5); -+ } else if (os_strncmp(buf, "SCAN ", 5) == 0) { -+ wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from, -+ fromlen, -+ (const u8 *) buf + 5, res - 5); -+ } else { -+ wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", -+ (u8 *) buf, res); -+ } -+ os_free(buf); -+} -+ -+ -+static void * wpa_driver_test_init2(void *ctx, const char *ifname, -+ void *global_priv) -+{ -+ struct wpa_driver_test_data *drv; -+ struct wpa_driver_test_global *global = global_priv; -+ struct test_driver_bss *bss; -+ -+ drv = test_alloc_data(ctx, ifname); -+ if (drv == NULL) -+ return NULL; -+ bss = dl_list_first(&drv->bss, struct test_driver_bss, list); -+ drv->global = global_priv; -+ drv->test_socket = -1; -+ -+ /* Set dummy BSSID and SSID for testing. */ -+ bss->bssid[0] = 0x02; -+ bss->bssid[1] = 0x00; -+ bss->bssid[2] = 0x00; -+ bss->bssid[3] = 0x00; -+ bss->bssid[4] = 0x00; -+ bss->bssid[5] = 0x01; -+ os_memcpy(bss->ssid, "test", 5); -+ bss->ssid_len = 4; -+ -+ if (global->bss_add_used) { -+ os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN); -+ global->bss_add_used = 0; -+ } -+ -+ eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); -+ -+ return bss; -+} -+ -+ -+static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv) -+{ -+ if (drv->test_socket >= 0) { -+ eloop_unregister_read_sock(drv->test_socket); -+ close(drv->test_socket); -+ drv->test_socket = -1; -+ } -+ -+ if (drv->own_socket_path) { -+ unlink(drv->own_socket_path); -+ os_free(drv->own_socket_path); -+ drv->own_socket_path = NULL; -+ } -+} -+ -+ -+static void wpa_driver_test_deinit(void *priv) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ struct test_client_socket *cli, *prev; -+ int i; -+ -+#ifdef CONFIG_P2P -+ if (drv->p2p) -+ p2p_deinit(drv->p2p); -+ wpabuf_free(drv->pending_action_tx); -+#endif /* CONFIG_P2P */ -+ -+ cli = drv->cli; -+ while (cli) { -+ prev = cli; -+ cli = cli->next; -+ os_free(prev); -+ } -+ -+#ifdef HOSTAPD -+ /* There should be only one BSS remaining at this point. */ -+ if (dl_list_len(&drv->bss) != 1) -+ wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries", -+ __func__, dl_list_len(&drv->bss)); -+#endif /* HOSTAPD */ -+ -+ test_driver_free_bsses(drv); -+ -+ wpa_driver_test_close_test_socket(drv); -+ eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx); -+ eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL); -+ eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); -+ os_free(drv->test_dir); -+ for (i = 0; i < MAX_SCAN_RESULTS; i++) -+ os_free(drv->scanres[i]); -+ os_free(drv->probe_req_ie); -+ wpa_trace_remove_ref(drv, ctx, drv->ctx); -+ os_free(drv); -+} -+ -+ -+static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, -+ const char *dir, int ap) -+{ -+#ifdef DRIVER_TEST_UNIX -+ static unsigned int counter = 0; -+ struct sockaddr_un addr; -+ size_t len; -+ -+ os_free(drv->own_socket_path); -+ if (dir) { -+ len = os_strlen(dir) + 30; -+ drv->own_socket_path = os_malloc(len); -+ if (drv->own_socket_path == NULL) -+ return -1; -+ os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR, -+ dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr)); -+ } else { -+ drv->own_socket_path = os_malloc(100); -+ if (drv->own_socket_path == NULL) -+ return -1; -+ os_snprintf(drv->own_socket_path, 100, -+ "/tmp/wpa_supplicant_test-%d-%d", -+ getpid(), counter++); -+ } -+ -+ drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (drv->test_socket < 0) { -+ perror("socket(PF_UNIX)"); -+ os_free(drv->own_socket_path); -+ drv->own_socket_path = NULL; -+ return -1; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path)); -+ if (bind(drv->test_socket, (struct sockaddr *) &addr, -+ sizeof(addr)) < 0) { -+ perror("bind(PF_UNIX)"); -+ close(drv->test_socket); -+ unlink(drv->own_socket_path); -+ os_free(drv->own_socket_path); -+ drv->own_socket_path = NULL; -+ return -1; -+ } -+ -+ eloop_register_read_sock(drv->test_socket, -+ wpa_driver_test_receive_unix, drv, NULL); -+ -+ return 0; -+#else /* DRIVER_TEST_UNIX */ -+ return -1; -+#endif /* DRIVER_TEST_UNIX */ -+} -+ -+ -+static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv, -+ char *dst) -+{ -+ char *pos; -+ -+ pos = os_strchr(dst, ':'); -+ if (pos == NULL) -+ return -1; -+ *pos++ = '\0'; -+ wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos); -+ -+ drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->test_socket < 0) { -+ perror("socket(PF_INET)"); -+ return -1; -+ } -+ -+ os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp)); -+ drv->hostapd_addr_udp.sin_family = AF_INET; -+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA) -+ { -+ int a[4]; -+ u8 *pos; -+ sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); -+ pos = (u8 *) &drv->hostapd_addr_udp.sin_addr; -+ *pos++ = a[0]; -+ *pos++ = a[1]; -+ *pos++ = a[2]; -+ *pos++ = a[3]; -+ } -+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ -+ inet_aton(dst, &drv->hostapd_addr_udp.sin_addr); -+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ -+ drv->hostapd_addr_udp.sin_port = htons(atoi(pos)); -+ -+ drv->hostapd_addr_udp_set = 1; -+ -+ eloop_register_read_sock(drv->test_socket, -+ wpa_driver_test_receive_unix, drv, NULL); -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_test_set_param(void *priv, const char *param) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ const char *pos; -+ -+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); -+ if (param == NULL) -+ return 0; -+ -+ wpa_driver_test_close_test_socket(drv); -+ -+#ifdef DRIVER_TEST_UNIX -+ pos = os_strstr(param, "test_socket="); -+ if (pos) { -+ const char *pos2; -+ size_t len; -+ -+ pos += 12; -+ pos2 = os_strchr(pos, ' '); -+ if (pos2) -+ len = pos2 - pos; -+ else -+ len = os_strlen(pos); -+ if (len > sizeof(drv->hostapd_addr.sun_path)) -+ return -1; -+ os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); -+ drv->hostapd_addr.sun_family = AF_UNIX; -+ os_memcpy(drv->hostapd_addr.sun_path, pos, len); -+ drv->hostapd_addr_set = 1; -+ } -+#endif /* DRIVER_TEST_UNIX */ -+ -+ pos = os_strstr(param, "test_dir="); -+ if (pos) { -+ char *end; -+ os_free(drv->test_dir); -+ drv->test_dir = os_strdup(pos + 9); -+ if (drv->test_dir == NULL) -+ return -1; -+ end = os_strchr(drv->test_dir, ' '); -+ if (end) -+ *end = '\0'; -+ if (wpa_driver_test_attach(drv, drv->test_dir, 0)) -+ return -1; -+ } else { -+ pos = os_strstr(param, "test_udp="); -+ if (pos) { -+ char *dst, *epos; -+ dst = os_strdup(pos + 9); -+ if (dst == NULL) -+ return -1; -+ epos = os_strchr(dst, ' '); -+ if (epos) -+ *epos = '\0'; -+ if (wpa_driver_test_attach_udp(drv, dst)) -+ return -1; -+ os_free(dst); -+ } else if (wpa_driver_test_attach(drv, NULL, 0)) -+ return -1; -+ } -+ -+ if (os_strstr(param, "use_associnfo=1")) { -+ wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events"); -+ drv->use_associnfo = 1; -+ } -+ -+#ifdef CONFIG_CLIENT_MLME -+ if (os_strstr(param, "use_mlme=1")) { -+ wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME"); -+ drv->use_mlme = 1; -+ } -+#endif /* CONFIG_CLIENT_MLME */ -+ -+ if (os_strstr(param, "p2p_mgmt=1")) { -+ wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P " -+ "management"); -+ if (wpa_driver_test_init_p2p(drv) < 0) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static const u8 * wpa_driver_test_get_mac_addr(void *priv) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ return drv->own_addr; -+} -+ -+ -+static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, -+ const u8 *data, size_t data_len) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ char *msg; -+ size_t msg_len; -+ struct l2_ethhdr eth; -+ struct sockaddr *addr; -+ socklen_t alen; -+#ifdef DRIVER_TEST_UNIX -+ struct sockaddr_un addr_un; -+#endif /* DRIVER_TEST_UNIX */ -+ -+ wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len); -+ -+ os_memset(ð, 0, sizeof(eth)); -+ os_memcpy(eth.h_dest, dest, ETH_ALEN); -+ os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN); -+ eth.h_proto = host_to_be16(proto); -+ -+ msg_len = 6 + sizeof(eth) + data_len; -+ msg = os_malloc(msg_len); -+ if (msg == NULL) -+ return -1; -+ os_memcpy(msg, "EAPOL ", 6); -+ os_memcpy(msg + 6, ð, sizeof(eth)); -+ os_memcpy(msg + 6 + sizeof(eth), data, data_len); -+ -+ if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 || -+ drv->test_dir == NULL) { -+ if (drv->hostapd_addr_udp_set) { -+ addr = (struct sockaddr *) &drv->hostapd_addr_udp; -+ alen = sizeof(drv->hostapd_addr_udp); -+ } else { -+#ifdef DRIVER_TEST_UNIX -+ addr = (struct sockaddr *) &drv->hostapd_addr; -+ alen = sizeof(drv->hostapd_addr); -+#else /* DRIVER_TEST_UNIX */ -+ os_free(msg); -+ return -1; -+#endif /* DRIVER_TEST_UNIX */ -+ } -+ } else { -+#ifdef DRIVER_TEST_UNIX -+ struct stat st; -+ os_memset(&addr_un, 0, sizeof(addr_un)); -+ addr_un.sun_family = AF_UNIX; -+ os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), -+ "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest)); -+ if (stat(addr_un.sun_path, &st) < 0) { -+ os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), -+ "%s/AP-" MACSTR, -+ drv->test_dir, MAC2STR(dest)); -+ } -+ addr = (struct sockaddr *) &addr_un; -+ alen = sizeof(addr_un); -+#else /* DRIVER_TEST_UNIX */ -+ os_free(msg); -+ return -1; -+#endif /* DRIVER_TEST_UNIX */ -+ } -+ -+ if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) { -+ perror("sendmsg(test_socket)"); -+ os_free(msg); -+ return -1; -+ } -+ -+ os_free(msg); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ os_memset(capa, 0, sizeof(*capa)); -+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE | -+ WPA_DRIVER_CAPA_KEY_MGMT_FT | -+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; -+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | -+ WPA_DRIVER_CAPA_ENC_WEP104 | -+ WPA_DRIVER_CAPA_ENC_TKIP | -+ WPA_DRIVER_CAPA_ENC_CCMP; -+ capa->auth = WPA_DRIVER_AUTH_OPEN | -+ WPA_DRIVER_AUTH_SHARED | -+ WPA_DRIVER_AUTH_LEAP; -+ if (drv->use_mlme) -+ capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME; -+ if (drv->p2p) -+ capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT; -+ capa->flags |= WPA_DRIVER_FLAGS_AP; -+ capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; -+ capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE; -+ capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE; -+ capa->max_scan_ssids = 2; -+ capa->max_remain_on_chan = 60000; -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr, -+ int protect_type, -+ int key_type) -+{ -+ wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d", -+ __func__, protect_type, key_type); -+ -+ if (addr) { -+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, -+ __func__, MAC2STR(addr)); -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_test_set_channel(void *priv, -+ enum hostapd_hw_mode phymode, -+ int chan, int freq) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d", -+ __func__, phymode, chan, freq); -+ drv->current_freq = freq; -+ return 0; -+} -+ -+ -+static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr, -+ const u8 *supp_rates, -+ size_t supp_rates_len) -+{ -+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr) -+{ -+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid, -+ size_t ssid_len) -+{ -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid) -+{ -+ wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid)); -+ return 0; -+} -+ -+ -+static void * wpa_driver_test_global_init(void) -+{ -+ struct wpa_driver_test_global *global; -+ -+ global = os_zalloc(sizeof(*global)); -+ return global; -+} -+ -+ -+static void wpa_driver_test_global_deinit(void *priv) -+{ -+ struct wpa_driver_test_global *global = priv; -+ os_free(global); -+} -+ -+ -+static struct wpa_interface_info * -+wpa_driver_test_get_interfaces(void *global_priv) -+{ -+ /* struct wpa_driver_test_global *global = priv; */ -+ struct wpa_interface_info *iface; -+ -+ iface = os_zalloc(sizeof(*iface)); -+ if (iface == NULL) -+ return iface; -+ iface->ifname = os_strdup("sta0"); -+ iface->desc = os_strdup("test interface 0"); -+ iface->drv_name = "test"; -+ iface->next = os_zalloc(sizeof(*iface)); -+ if (iface->next) { -+ iface->next->ifname = os_strdup("sta1"); -+ iface->next->desc = os_strdup("test interface 1"); -+ iface->next->drv_name = "test"; -+ } -+ -+ return iface; -+} -+ -+ -+static struct hostapd_hw_modes * -+wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) -+{ -+ struct hostapd_hw_modes *modes; -+ size_t i; -+ -+ *num_modes = 3; -+ *flags = 0; -+ modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes)); -+ if (modes == NULL) -+ return NULL; -+ modes[0].mode = HOSTAPD_MODE_IEEE80211G; -+ modes[0].num_channels = 11; -+ modes[0].num_rates = 12; -+ modes[0].channels = -+ os_zalloc(11 * sizeof(struct hostapd_channel_data)); -+ modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int)); -+ if (modes[0].channels == NULL || modes[0].rates == NULL) -+ goto fail; -+ for (i = 0; i < 11; i++) { -+ modes[0].channels[i].chan = i + 1; -+ modes[0].channels[i].freq = 2412 + 5 * i; -+ modes[0].channels[i].flag = 0; -+ } -+ modes[0].rates[0] = 10; -+ modes[0].rates[1] = 20; -+ modes[0].rates[2] = 55; -+ modes[0].rates[3] = 110; -+ modes[0].rates[4] = 60; -+ modes[0].rates[5] = 90; -+ modes[0].rates[6] = 120; -+ modes[0].rates[7] = 180; -+ modes[0].rates[8] = 240; -+ modes[0].rates[9] = 360; -+ modes[0].rates[10] = 480; -+ modes[0].rates[11] = 540; -+ -+ modes[1].mode = HOSTAPD_MODE_IEEE80211B; -+ modes[1].num_channels = 11; -+ modes[1].num_rates = 4; -+ modes[1].channels = -+ os_zalloc(11 * sizeof(struct hostapd_channel_data)); -+ modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int)); -+ if (modes[1].channels == NULL || modes[1].rates == NULL) -+ goto fail; -+ for (i = 0; i < 11; i++) { -+ modes[1].channels[i].chan = i + 1; -+ modes[1].channels[i].freq = 2412 + 5 * i; -+ modes[1].channels[i].flag = 0; -+ } -+ modes[1].rates[0] = 10; -+ modes[1].rates[1] = 20; -+ modes[1].rates[2] = 55; -+ modes[1].rates[3] = 110; -+ -+ modes[2].mode = HOSTAPD_MODE_IEEE80211A; -+ modes[2].num_channels = 1; -+ modes[2].num_rates = 8; -+ modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data)); -+ modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int)); -+ if (modes[2].channels == NULL || modes[2].rates == NULL) -+ goto fail; -+ modes[2].channels[0].chan = 60; -+ modes[2].channels[0].freq = 5300; -+ modes[2].channels[0].flag = 0; -+ modes[2].rates[0] = 60; -+ modes[2].rates[1] = 90; -+ modes[2].rates[2] = 120; -+ modes[2].rates[3] = 180; -+ modes[2].rates[4] = 240; -+ modes[2].rates[5] = 360; -+ modes[2].rates[6] = 480; -+ modes[2].rates[7] = 540; -+ -+ return modes; -+ -+fail: -+ if (modes) { -+ for (i = 0; i < *num_modes; i++) { -+ os_free(modes[i].channels); -+ os_free(modes[i].rates); -+ } -+ os_free(modes); -+ } -+ return NULL; -+} -+ -+ -+static int wpa_driver_test_set_freq(void *priv, -+ struct hostapd_freq_params *freq) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq); -+ drv->current_freq = freq->freq; -+ return 0; -+} -+ -+ -+static int wpa_driver_test_send_action(void *priv, unsigned int freq, -+ unsigned int wait, -+ const u8 *dst, const u8 *src, -+ const u8 *bssid, -+ const u8 *data, size_t data_len) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ int ret = -1; -+ u8 *buf; -+ struct ieee80211_hdr *hdr; -+ -+ wpa_printf(MSG_DEBUG, "test: Send Action frame"); -+ -+ if ((drv->remain_on_channel_freq && -+ freq != drv->remain_on_channel_freq) || -+ (drv->remain_on_channel_freq == 0 && -+ freq != (unsigned int) drv->current_freq)) { -+ wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on " -+ "unexpected channel: freq=%u MHz (current_freq=%u " -+ "MHz, remain-on-channel freq=%u MHz)", -+ freq, drv->current_freq, -+ drv->remain_on_channel_freq); -+ return -1; -+ } -+ -+ buf = os_zalloc(24 + data_len); -+ if (buf == NULL) -+ return ret; -+ os_memcpy(buf + 24, data, data_len); -+ hdr = (struct ieee80211_hdr *) buf; -+ hdr->frame_control = -+ IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); -+ os_memcpy(hdr->addr1, dst, ETH_ALEN); -+ os_memcpy(hdr->addr2, src, ETH_ALEN); -+ os_memcpy(hdr->addr3, bssid, ETH_ALEN); -+ -+ ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len); -+ os_free(buf); -+ return ret; -+} -+ -+ -+#ifdef CONFIG_P2P -+static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_test_data *drv = eloop_ctx; -+ int res; -+ -+ if (drv->pending_action_tx == NULL) -+ return; -+ -+ if (drv->off_channel_freq != drv->pending_action_freq) { -+ wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX " -+ "waiting for another freq=%u", -+ drv->pending_action_freq); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to " -+ MACSTR, MAC2STR(drv->pending_action_dst)); -+ res = wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, -+ drv->pending_action_dst, -+ drv->pending_action_src, -+ drv->pending_action_bssid, -+ wpabuf_head(drv->pending_action_tx), -+ wpabuf_len(drv->pending_action_tx)); -+} -+#endif /* CONFIG_P2P */ -+ -+ -+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_driver_test_data *drv = eloop_ctx; -+ union wpa_event_data data; -+ -+ wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout"); -+ -+ os_memset(&data, 0, sizeof(data)); -+ data.remain_on_channel.freq = drv->remain_on_channel_freq; -+ data.remain_on_channel.duration = drv->remain_on_channel_duration; -+ -+ if (drv->p2p) -+ drv->off_channel_freq = 0; -+ -+ drv->remain_on_channel_freq = 0; -+ -+ wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data); -+} -+ -+ -+static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq, -+ unsigned int duration) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ union wpa_event_data data; -+ -+ wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)", -+ __func__, freq, duration); -+ if (drv->remain_on_channel_freq && -+ drv->remain_on_channel_freq != freq) { -+ wpa_printf(MSG_DEBUG, "test: Refuse concurrent " -+ "remain_on_channel request"); -+ return -1; -+ } -+ -+ drv->remain_on_channel_freq = freq; -+ drv->remain_on_channel_duration = duration; -+ eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); -+ eloop_register_timeout(duration / 1000, (duration % 1000) * 1000, -+ test_remain_on_channel_timeout, drv, NULL); -+ -+ os_memset(&data, 0, sizeof(data)); -+ data.remain_on_channel.freq = freq; -+ data.remain_on_channel.duration = duration; -+ wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data); -+ -+#ifdef CONFIG_P2P -+ if (drv->p2p) { -+ drv->off_channel_freq = drv->remain_on_channel_freq; -+ test_send_action_cb(drv, NULL); -+ if (drv->off_channel_freq == drv->pending_listen_freq) { -+ p2p_listen_cb(drv->p2p, drv->pending_listen_freq, -+ drv->pending_listen_duration); -+ drv->pending_listen_freq = 0; -+ } -+ } -+#endif /* CONFIG_P2P */ -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_test_cancel_remain_on_channel(void *priv) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ if (!drv->remain_on_channel_freq) -+ return -1; -+ drv->remain_on_channel_freq = 0; -+ eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_probe_req_report(void *priv, int report) -+{ -+ struct test_driver_bss *dbss = priv; -+ struct wpa_driver_test_data *drv = dbss->drv; -+ wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report); -+ drv->probe_req_report = report; -+ return 0; -+} -+ -+ -+#ifdef CONFIG_P2P -+ -+static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type) -+{ -+ struct wpa_driver_test_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); -+ if (!drv->p2p) -+ return -1; -+ return p2p_find(drv->p2p, timeout, type, 0, NULL); -+} -+ -+ -+static int wpa_driver_test_p2p_stop_find(void *priv) -+{ -+ struct wpa_driver_test_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ if (!drv->p2p) -+ return -1; -+ p2p_stop_find(drv->p2p); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout) -+{ -+ struct wpa_driver_test_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); -+ if (!drv->p2p) -+ return -1; -+ return p2p_listen(drv->p2p, timeout); -+} -+ -+ -+static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr, -+ int wps_method, int go_intent, -+ const u8 *own_interface_addr, -+ unsigned int force_freq, -+ int persistent_group) -+{ -+ struct wpa_driver_test_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d " -+ "go_intent=%d " -+ "own_interface_addr=" MACSTR " force_freq=%u " -+ "persistent_group=%d)", -+ __func__, MAC2STR(peer_addr), wps_method, go_intent, -+ MAC2STR(own_interface_addr), force_freq, persistent_group); -+ if (!drv->p2p) -+ return -1; -+ return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent, -+ own_interface_addr, force_freq, persistent_group); -+} -+ -+ -+static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr) -+{ -+ struct wpa_driver_test_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")", -+ __func__, MAC2STR(peer_addr)); -+ if (!drv->p2p) -+ return -1; -+ p2p_wps_success_cb(drv->p2p, peer_addr); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_p2p_group_formation_failed(void *priv) -+{ -+ struct wpa_driver_test_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ if (!drv->p2p) -+ return -1; -+ p2p_group_formation_failed(drv->p2p); -+ return 0; -+} -+ -+ -+static int wpa_driver_test_p2p_set_params(void *priv, -+ const struct p2p_params *params) -+{ -+ struct wpa_driver_test_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ if (!drv->p2p) -+ return -1; -+ if (p2p_set_dev_name(drv->p2p, params->dev_name) < 0 || -+ p2p_set_pri_dev_type(drv->p2p, params->pri_dev_type) < 0 || -+ p2p_set_sec_dev_types(drv->p2p, params->sec_dev_type, -+ params->num_sec_dev_types) < 0) -+ return -1; -+ return 0; -+} -+ -+ -+static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, -+ unsigned int num_req_dev_types, -+ const u8 *req_dev_types) -+{ -+ struct wpa_driver_test_data *drv = ctx; -+ struct wpa_driver_scan_params params; -+ int ret; -+ struct wpabuf *wps_ie, *ies; -+ int social_channels[] = { 2412, 2437, 2462, 0, 0 }; -+ -+ wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)", -+ __func__, type, freq); -+ -+ os_memset(¶ms, 0, sizeof(params)); -+ -+ /* P2P Wildcard SSID */ -+ params.num_ssids = 1; -+ params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; -+ params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; -+ -+#if 0 /* TODO: WPS IE */ -+ wpa_s->wps->dev.p2p = 1; -+ wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid, -+ WPS_REQ_ENROLLEE); -+#else -+ wps_ie = wpabuf_alloc(1); -+#endif -+ if (wps_ie == NULL) -+ return -1; -+ -+ ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100); -+ if (ies == NULL) { -+ wpabuf_free(wps_ie); -+ return -1; -+ } -+ wpabuf_put_buf(ies, wps_ie); -+ wpabuf_free(wps_ie); -+ -+ p2p_scan_ie(drv->p2p, ies); -+ -+ params.extra_ies = wpabuf_head(ies); -+ params.extra_ies_len = wpabuf_len(ies); -+ -+ switch (type) { -+ case P2P_SCAN_SOCIAL: -+ params.freqs = social_channels; -+ break; -+ case P2P_SCAN_FULL: -+ break; -+ case P2P_SCAN_SPECIFIC: -+ social_channels[0] = freq; -+ social_channels[1] = 0; -+ params.freqs = social_channels; -+ break; -+ case P2P_SCAN_SOCIAL_PLUS_ONE: -+ social_channels[3] = freq; -+ params.freqs = social_channels; -+ break; -+ } -+ -+ drv->pending_p2p_scan = 1; -+ ret = wpa_driver_test_scan(drv, ¶ms); -+ -+ wpabuf_free(ies); -+ -+ return ret; -+} -+ -+ -+static int test_send_action(void *ctx, unsigned int freq, const u8 *dst, -+ const u8 *src, const u8 *bssid, const u8 *buf, -+ size_t len, unsigned int wait_time) -+{ -+ struct wpa_driver_test_data *drv = ctx; -+ -+ wpa_printf(MSG_DEBUG, "%s(freq=%u dst=" MACSTR " src=" MACSTR -+ " bssid=" MACSTR " len=%d", -+ __func__, freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), -+ (int) len); -+ if (freq <= 0) { -+ wpa_printf(MSG_WARNING, "P2P: No frequency specified for " -+ "action frame TX"); -+ return -1; -+ } -+ -+ if (drv->pending_action_tx) { -+ wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX " -+ "to " MACSTR, MAC2STR(drv->pending_action_dst)); -+ wpabuf_free(drv->pending_action_tx); -+ } -+ drv->pending_action_tx = wpabuf_alloc(len); -+ if (drv->pending_action_tx == NULL) -+ return -1; -+ wpabuf_put_data(drv->pending_action_tx, buf, len); -+ os_memcpy(drv->pending_action_src, src, ETH_ALEN); -+ os_memcpy(drv->pending_action_dst, dst, ETH_ALEN); -+ os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN); -+ drv->pending_action_freq = freq; -+ -+ if (drv->off_channel_freq == freq) { -+ /* Already on requested channel; send immediately */ -+ /* TODO: Would there ever be need to extend the current -+ * duration on the channel? */ -+ eloop_cancel_timeout(test_send_action_cb, drv, NULL); -+ eloop_register_timeout(0, 0, test_send_action_cb, drv, NULL); -+ return 0; -+ } -+ -+ wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted " -+ "once the driver gets to the requested channel"); -+ if (wpa_driver_test_remain_on_channel(drv, freq, wait_time) < 0) { -+ wpa_printf(MSG_DEBUG, "P2P: Failed to request driver " -+ "to remain on channel (%u MHz) for Action " -+ "Frame TX", freq); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void test_send_action_done(void *ctx) -+{ -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ /* TODO */ -+} -+ -+ -+static void test_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) -+{ -+ struct wpa_driver_test_data *drv = ctx; -+ union wpa_event_data event; -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ os_memset(&event, 0, sizeof(event)); -+ event.p2p_go_neg_completed.res = res; -+ wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_COMPLETED, &event); -+} -+ -+ -+static void test_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) -+{ -+ struct wpa_driver_test_data *drv = ctx; -+ union wpa_event_data event; -+ wpa_printf(MSG_DEBUG, "%s(src=" MACSTR ")", __func__, MAC2STR(src)); -+ os_memset(&event, 0, sizeof(event)); -+ event.p2p_go_neg_req_rx.src = src; -+ event.p2p_go_neg_req_rx.dev_passwd_id = dev_passwd_id; -+ wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_REQ_RX, &event); -+} -+ -+ -+static void test_dev_found(void *ctx, const u8 *addr, -+ const struct p2p_peer_info *info, int new_device) -+{ -+ struct wpa_driver_test_data *drv = ctx; -+ union wpa_event_data event; -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ wpa_printf(MSG_DEBUG, "%s(" MACSTR " p2p_dev_addr=" MACSTR -+ " pri_dev_type=%s name='%s' config_methods=0x%x " -+ "dev_capab=0x%x group_capab=0x%x)", -+ __func__, MAC2STR(addr), MAC2STR(info->p2p_device_addr), -+ wps_dev_type_bin2str(info->pri_dev_type, devtype, -+ sizeof(devtype)), -+ info->device_name, info->config_methods, info->dev_capab, -+ info->group_capab); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.p2p_dev_found.addr = addr; -+ event.p2p_dev_found.dev_addr = info->p2p_device_addr; -+ event.p2p_dev_found.pri_dev_type = info->pri_dev_type; -+ event.p2p_dev_found.dev_name = info->device_name; -+ event.p2p_dev_found.config_methods = info->config_methods; -+ event.p2p_dev_found.dev_capab = info->dev_capab; -+ event.p2p_dev_found.group_capab = info->group_capab; -+ wpa_supplicant_event(drv->ctx, EVENT_P2P_DEV_FOUND, &event); -+} -+ -+ -+static int test_start_listen(void *ctx, unsigned int freq, -+ unsigned int duration, -+ const struct wpabuf *probe_resp_ie) -+{ -+ struct wpa_driver_test_data *drv = ctx; -+ -+ wpa_printf(MSG_DEBUG, "%s(freq=%u duration=%u)", -+ __func__, freq, duration); -+ -+ if (wpa_driver_test_probe_req_report(drv, 1) < 0) -+ return -1; -+ -+ drv->pending_listen_freq = freq; -+ drv->pending_listen_duration = duration; -+ -+ if (wpa_driver_test_remain_on_channel(drv, freq, duration) < 0) { -+ drv->pending_listen_freq = 0; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void test_stop_listen(void *ctx) -+{ -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ /* TODO */ -+} -+ -+ -+static int test_send_probe_resp(void *ctx, const struct wpabuf *buf) -+{ -+ struct wpa_driver_test_data *drv = ctx; -+ char resp[512], *pos, *end; -+ int ret; -+ const struct ieee80211_mgmt *mgmt; -+ const u8 *ie, *ie_end; -+ -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ wpa_hexdump_buf(MSG_MSGDUMP, "Probe Response", buf); -+ if (wpabuf_len(buf) < 24) -+ return -1; -+ if (!drv->probe_from) { -+ wpa_printf(MSG_DEBUG, "%s: probe_from not set", __func__); -+ return -1; -+ } -+ -+ pos = resp; -+ end = resp + sizeof(resp); -+ -+ mgmt = wpabuf_head(buf); -+ -+ /* reply: SCANRESP BSSID SSID IEs */ -+ ret = os_snprintf(pos, end - pos, "SCANRESP " MACSTR " ", -+ MAC2STR(mgmt->bssid)); -+ if (ret < 0 || ret >= end - pos) -+ return -1; -+ pos += ret; -+ -+ ie = mgmt->u.probe_resp.variable; -+ ie_end = wpabuf_head_u8(buf) + wpabuf_len(buf); -+ if (ie_end - ie < 2 || ie[0] != WLAN_EID_SSID || -+ ie + 2 + ie[1] > ie_end) -+ return -1; -+ pos += wpa_snprintf_hex(pos, end - pos, ie + 2, ie[1]); -+ -+ ret = os_snprintf(pos, end - pos, " "); -+ if (ret < 0 || ret >= end - pos) -+ return -1; -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, end - pos, ie, ie_end - ie); -+ -+ sendto(drv->test_socket, resp, pos - resp, 0, -+ drv->probe_from, drv->probe_from_len); -+ -+ return 0; -+} -+ -+ -+static void test_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, -+ u16 update_indic, const u8 *tlvs, size_t tlvs_len) -+{ -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ /* TODO */ -+} -+ -+ -+static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic, -+ const u8 *tlvs, size_t tlvs_len) -+{ -+ wpa_printf(MSG_DEBUG, "%s", __func__); -+ /* TODO */ -+} -+ -+ -+static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, -+ const u8 *dev_addr, const u8 *pri_dev_type, -+ const char *dev_name, u16 supp_config_methods, -+ u8 dev_capab, u8 group_capab) -+{ -+ wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", -+ __func__, MAC2STR(peer), config_methods); -+ /* TODO */ -+} -+ -+ -+static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) -+{ -+ wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", -+ __func__, MAC2STR(peer), config_methods); -+ /* TODO */ -+} -+ -+#endif /* CONFIG_P2P */ -+ -+ -+static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv) -+{ -+#ifdef CONFIG_P2P -+ struct p2p_config p2p; -+ unsigned int r; -+ int i; -+ -+ os_memset(&p2p, 0, sizeof(p2p)); -+ p2p.msg_ctx = drv->ctx; -+ p2p.cb_ctx = drv; -+ p2p.p2p_scan = test_p2p_scan; -+ p2p.send_action = test_send_action; -+ p2p.send_action_done = test_send_action_done; -+ p2p.go_neg_completed = test_go_neg_completed; -+ p2p.go_neg_req_rx = test_go_neg_req_rx; -+ p2p.dev_found = test_dev_found; -+ p2p.start_listen = test_start_listen; -+ p2p.stop_listen = test_stop_listen; -+ p2p.send_probe_resp = test_send_probe_resp; -+ p2p.sd_request = test_sd_request; -+ p2p.sd_response = test_sd_response; -+ p2p.prov_disc_req = test_prov_disc_req; -+ p2p.prov_disc_resp = test_prov_disc_resp; -+ -+ os_memcpy(p2p.dev_addr, drv->own_addr, ETH_ALEN); -+ -+ p2p.reg_class = 12; /* TODO: change depending on location */ -+ /* -+ * Pick one of the social channels randomly as the listen -+ * channel. -+ */ -+ os_get_random((u8 *) &r, sizeof(r)); -+ p2p.channel = 1 + (r % 3) * 5; -+ -+ /* TODO: change depending on location */ -+ p2p.op_reg_class = 12; -+ /* -+ * For initial tests, pick the operation channel randomly. -+ * TODO: Use scan results (etc.) to select the best channel. -+ */ -+ p2p.op_channel = 1 + r % 11; -+ -+ os_memcpy(p2p.country, "US ", 3); -+ -+ /* FIX: fetch available channels from the driver */ -+ p2p.channels.reg_classes = 1; -+ p2p.channels.reg_class[0].reg_class = 12; /* US/12 = 2.4 GHz band */ -+ p2p.channels.reg_class[0].channels = 11; -+ for (i = 0; i < 11; i++) -+ p2p.channels.reg_class[0].channel[i] = i + 1; -+ -+ p2p.max_peers = 100; -+ -+ drv->p2p = p2p_init(&p2p); -+ if (drv->p2p == NULL) -+ return -1; -+ return 0; -+#else /* CONFIG_P2P */ -+ wpa_printf(MSG_INFO, "driver_test: P2P support not included"); -+ return -1; -+#endif /* CONFIG_P2P */ -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_test_ops = { -+ "test", -+ "wpa_supplicant test driver", -+ .hapd_init = test_driver_init, -+ .hapd_deinit = wpa_driver_test_deinit, -+ .hapd_send_eapol = test_driver_send_eapol, -+ .send_mlme = wpa_driver_test_send_mlme, -+ .set_generic_elem = test_driver_set_generic_elem, -+ .sta_deauth = test_driver_sta_deauth, -+ .sta_disassoc = test_driver_sta_disassoc, -+ .get_hw_feature_data = wpa_driver_test_get_hw_feature_data, -+ .if_add = test_driver_if_add, -+ .if_remove = test_driver_if_remove, -+ .valid_bss_mask = test_driver_valid_bss_mask, -+ .hapd_set_ssid = test_driver_set_ssid, -+ .set_privacy = test_driver_set_privacy, -+ .set_sta_vlan = test_driver_set_sta_vlan, -+ .sta_add = test_driver_sta_add, -+ .send_ether = test_driver_send_ether, -+ .set_ap_wps_ie = test_driver_set_ap_wps_ie, -+ .get_bssid = wpa_driver_test_get_bssid, -+ .get_ssid = wpa_driver_test_get_ssid, -+ .set_key = wpa_driver_test_set_key, -+ .deinit = wpa_driver_test_deinit, -+ .set_param = wpa_driver_test_set_param, -+ .deauthenticate = wpa_driver_test_deauthenticate, -+ .disassociate = wpa_driver_test_disassociate, -+ .associate = wpa_driver_test_associate, -+ .get_capa = wpa_driver_test_get_capa, -+ .get_mac_addr = wpa_driver_test_get_mac_addr, -+ .send_eapol = wpa_driver_test_send_eapol, -+ .mlme_setprotection = wpa_driver_test_mlme_setprotection, -+ .set_channel = wpa_driver_test_set_channel, -+ .set_ssid = wpa_driver_test_set_ssid, -+ .set_bssid = wpa_driver_test_set_bssid, -+ .mlme_add_sta = wpa_driver_test_mlme_add_sta, -+ .mlme_remove_sta = wpa_driver_test_mlme_remove_sta, -+ .get_scan_results2 = wpa_driver_test_get_scan_results2, -+ .global_init = wpa_driver_test_global_init, -+ .global_deinit = wpa_driver_test_global_deinit, -+ .init2 = wpa_driver_test_init2, -+ .get_interfaces = wpa_driver_test_get_interfaces, -+ .scan2 = wpa_driver_test_scan, -+ .set_freq = wpa_driver_test_set_freq, -+ .send_action = wpa_driver_test_send_action, -+ .remain_on_channel = wpa_driver_test_remain_on_channel, -+ .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel, -+ .probe_req_report = wpa_driver_test_probe_req_report, -+#ifdef CONFIG_P2P -+ .p2p_find = wpa_driver_test_p2p_find, -+ .p2p_stop_find = wpa_driver_test_p2p_stop_find, -+ .p2p_listen = wpa_driver_test_p2p_listen, -+ .p2p_connect = wpa_driver_test_p2p_connect, -+ .wps_success_cb = wpa_driver_test_wps_success_cb, -+ .p2p_group_formation_failed = -+ wpa_driver_test_p2p_group_formation_failed, -+ .p2p_set_params = wpa_driver_test_p2p_set_params, -+#endif /* CONFIG_P2P */ -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.c -new file mode 100644 -index 0000000000000..d9f12bc7e17bc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.c -@@ -0,0 +1,2356 @@ -+/* -+ * Driver interaction with generic Linux Wireless Extensions -+ * Copyright (c) 2003-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file implements a driver interface for the Linux Wireless Extensions. -+ * When used with WE-18 or newer, this interface can be used as-is with number -+ * of drivers. In addition to this, some of the common functions in this file -+ * can be used by other driver interface implementations that use generic WE -+ * ioctls, but require private ioctls for some of the functionality. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+#include -+#include -+ -+#include "wireless_copy.h" -+#include "common.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "common/wpa_common.h" -+#include "priv_netlink.h" -+#include "netlink.h" -+#include "linux_ioctl.h" -+#include "rfkill.h" -+#include "driver.h" -+#include "driver_wext.h" -+ -+ -+static int wpa_driver_wext_flush_pmkid(void *priv); -+static int wpa_driver_wext_get_range(void *priv); -+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv); -+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv); -+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg); -+ -+ -+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, -+ int idx, u32 value) -+{ -+ struct iwreq iwr; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.param.flags = idx & IW_AUTH_INDEX; -+ iwr.u.param.value = value; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) { -+ if (errno != EOPNOTSUPP) { -+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d " -+ "value 0x%x) failed: %s)", -+ idx, value, strerror(errno)); -+ } -+ ret = errno == EOPNOTSUPP ? -2 : -1; -+ } -+ -+ return ret; -+} -+ -+ -+/** -+ * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @bssid: Buffer for BSSID -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { -+ perror("ioctl[SIOCGIWAP]"); -+ ret = -1; -+ } -+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); -+ -+ return ret; -+} -+ -+ -+/** -+ * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @bssid: BSSID -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.ap_addr.sa_family = ARPHRD_ETHER; -+ if (bssid) -+ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); -+ else -+ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { -+ perror("ioctl[SIOCSIWAP]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+/** -+ * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @ssid: Buffer for the SSID; must be at least 32 bytes long -+ * Returns: SSID length on success, -1 on failure -+ */ -+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.essid.pointer = (caddr_t) ssid; -+ iwr.u.essid.length = 32; -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCGIWESSID]"); -+ ret = -1; -+ } else { -+ ret = iwr.u.essid.length; -+ if (ret > 32) -+ ret = 32; -+ /* Some drivers include nul termination in the SSID, so let's -+ * remove it here before further processing. WE-21 changes this -+ * to explicitly require the length _not_ to include nul -+ * termination. */ -+ if (ret > 0 && ssid[ret - 1] == '\0' && -+ drv->we_version_compiled < 21) -+ ret--; -+ } -+ -+ return ret; -+} -+ -+ -+/** -+ * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @ssid: SSID -+ * @ssid_len: Length of SSID (0..32) -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ char buf[33]; -+ -+ if (ssid_len > 32) -+ return -1; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ -+ iwr.u.essid.flags = (ssid_len != 0); -+ os_memset(buf, 0, sizeof(buf)); -+ os_memcpy(buf, ssid, ssid_len); -+ iwr.u.essid.pointer = (caddr_t) buf; -+ if (drv->we_version_compiled < 21) { -+ /* For historic reasons, set SSID length to include one extra -+ * character, C string nul termination, even though SSID is -+ * really an octet string that should not be presented as a C -+ * string. Some Linux drivers decrement the length by one and -+ * can thus end up missing the last octet of the SSID if the -+ * length is not incremented here. WE-21 changes this to -+ * explicitly require the length _not_ to include nul -+ * termination. */ -+ if (ssid_len) -+ ssid_len++; -+ } -+ iwr.u.essid.length = ssid_len; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { -+ perror("ioctl[SIOCSIWESSID]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+/** -+ * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @freq: Frequency in MHz -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_driver_wext_set_freq(void *priv, int freq) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.freq.m = freq * 100000; -+ iwr.u.freq.e = 1; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { -+ perror("ioctl[SIOCSIWFREQ]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+static void -+wpa_driver_wext_event_wireless_custom(void *ctx, char *custom) -+{ -+ union wpa_event_data data; -+ -+ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", -+ custom); -+ -+ os_memset(&data, 0, sizeof(data)); -+ /* Host AP driver */ -+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { -+ data.michael_mic_failure.unicast = -+ os_strstr(custom, " unicast ") != NULL; -+ /* TODO: parse parameters(?) */ -+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -+ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { -+ char *spos; -+ int bytes; -+ u8 *req_ies = NULL, *resp_ies = NULL; -+ -+ spos = custom + 17; -+ -+ bytes = strspn(spos, "0123456789abcdefABCDEF"); -+ if (!bytes || (bytes & 1)) -+ return; -+ bytes /= 2; -+ -+ req_ies = os_malloc(bytes); -+ if (req_ies == NULL || -+ hexstr2bin(spos, req_ies, bytes) < 0) -+ goto done; -+ data.assoc_info.req_ies = req_ies; -+ data.assoc_info.req_ies_len = bytes; -+ -+ spos += bytes * 2; -+ -+ data.assoc_info.resp_ies = NULL; -+ data.assoc_info.resp_ies_len = 0; -+ -+ if (os_strncmp(spos, " RespIEs=", 9) == 0) { -+ spos += 9; -+ -+ bytes = strspn(spos, "0123456789abcdefABCDEF"); -+ if (!bytes || (bytes & 1)) -+ goto done; -+ bytes /= 2; -+ -+ resp_ies = os_malloc(bytes); -+ if (resp_ies == NULL || -+ hexstr2bin(spos, resp_ies, bytes) < 0) -+ goto done; -+ data.assoc_info.resp_ies = resp_ies; -+ data.assoc_info.resp_ies_len = bytes; -+ } -+ -+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); -+ -+ done: -+ os_free(resp_ies); -+ os_free(req_ies); -+#ifdef CONFIG_PEERKEY -+ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { -+ if (hwaddr_aton(custom + 17, data.stkstart.peer)) { -+ wpa_printf(MSG_DEBUG, "WEXT: unrecognized " -+ "STKSTART.request '%s'", custom + 17); -+ return; -+ } -+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data); -+#endif /* CONFIG_PEERKEY */ -+ } -+} -+ -+ -+static int wpa_driver_wext_event_wireless_michaelmicfailure( -+ void *ctx, const char *ev, size_t len) -+{ -+ const struct iw_michaelmicfailure *mic; -+ union wpa_event_data data; -+ -+ if (len < sizeof(*mic)) -+ return -1; -+ -+ mic = (const struct iw_michaelmicfailure *) ev; -+ -+ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " -+ "flags=0x%x src_addr=" MACSTR, mic->flags, -+ MAC2STR(mic->src_addr.sa_data)); -+ -+ os_memset(&data, 0, sizeof(data)); -+ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); -+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_wext_event_wireless_pmkidcand( -+ struct wpa_driver_wext_data *drv, const char *ev, size_t len) -+{ -+ const struct iw_pmkid_cand *cand; -+ union wpa_event_data data; -+ const u8 *addr; -+ -+ if (len < sizeof(*cand)) -+ return -1; -+ -+ cand = (const struct iw_pmkid_cand *) ev; -+ addr = (const u8 *) cand->bssid.sa_data; -+ -+ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " -+ "flags=0x%x index=%d bssid=" MACSTR, cand->flags, -+ cand->index, MAC2STR(addr)); -+ -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); -+ data.pmkid_candidate.index = cand->index; -+ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; -+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_wext_event_wireless_assocreqie( -+ struct wpa_driver_wext_data *drv, const char *ev, int len) -+{ -+ if (len < 0) -+ return -1; -+ -+ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, -+ len); -+ os_free(drv->assoc_req_ies); -+ drv->assoc_req_ies = os_malloc(len); -+ if (drv->assoc_req_ies == NULL) { -+ drv->assoc_req_ies_len = 0; -+ return -1; -+ } -+ os_memcpy(drv->assoc_req_ies, ev, len); -+ drv->assoc_req_ies_len = len; -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_wext_event_wireless_assocrespie( -+ struct wpa_driver_wext_data *drv, const char *ev, int len) -+{ -+ if (len < 0) -+ return -1; -+ -+ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, -+ len); -+ os_free(drv->assoc_resp_ies); -+ drv->assoc_resp_ies = os_malloc(len); -+ if (drv->assoc_resp_ies == NULL) { -+ drv->assoc_resp_ies_len = 0; -+ return -1; -+ } -+ os_memcpy(drv->assoc_resp_ies, ev, len); -+ drv->assoc_resp_ies_len = len; -+ -+ return 0; -+} -+ -+ -+static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv) -+{ -+ union wpa_event_data data; -+ -+ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) -+ return; -+ -+ os_memset(&data, 0, sizeof(data)); -+ if (drv->assoc_req_ies) { -+ data.assoc_info.req_ies = drv->assoc_req_ies; -+ data.assoc_info.req_ies_len = drv->assoc_req_ies_len; -+ } -+ if (drv->assoc_resp_ies) { -+ data.assoc_info.resp_ies = drv->assoc_resp_ies; -+ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; -+ } -+ -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); -+ -+ os_free(drv->assoc_req_ies); -+ drv->assoc_req_ies = NULL; -+ os_free(drv->assoc_resp_ies); -+ drv->assoc_resp_ies = NULL; -+} -+ -+ -+static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, -+ char *data, int len) -+{ -+ struct iw_event iwe_buf, *iwe = &iwe_buf; -+ char *pos, *end, *custom, *buf; -+ -+ pos = data; -+ end = data + len; -+ -+ while (pos + IW_EV_LCP_LEN <= end) { -+ /* Event data may be unaligned, so make a local, aligned copy -+ * before processing. */ -+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); -+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", -+ iwe->cmd, iwe->len); -+ if (iwe->len <= IW_EV_LCP_LEN) -+ return; -+ -+ custom = pos + IW_EV_POINT_LEN; -+ if (drv->we_version_compiled > 18 && -+ (iwe->cmd == IWEVMICHAELMICFAILURE || -+ iwe->cmd == IWEVCUSTOM || -+ iwe->cmd == IWEVASSOCREQIE || -+ iwe->cmd == IWEVASSOCRESPIE || -+ iwe->cmd == IWEVPMKIDCAND)) { -+ /* WE-19 removed the pointer from struct iw_point */ -+ char *dpos = (char *) &iwe_buf.u.data.length; -+ int dlen = dpos - (char *) &iwe_buf; -+ os_memcpy(dpos, pos + IW_EV_LCP_LEN, -+ sizeof(struct iw_event) - dlen); -+ } else { -+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); -+ custom += IW_EV_POINT_OFF; -+ } -+ -+ switch (iwe->cmd) { -+ case SIOCGIWAP: -+ wpa_printf(MSG_DEBUG, "Wireless event: new AP: " -+ MACSTR, -+ MAC2STR((u8 *) iwe->u.ap_addr.sa_data)); -+ if (is_zero_ether_addr( -+ (const u8 *) iwe->u.ap_addr.sa_data) || -+ os_memcmp(iwe->u.ap_addr.sa_data, -+ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == -+ 0) { -+ os_free(drv->assoc_req_ies); -+ drv->assoc_req_ies = NULL; -+ os_free(drv->assoc_resp_ies); -+ drv->assoc_resp_ies = NULL; -+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, -+ NULL); -+ -+ } else { -+ wpa_driver_wext_event_assoc_ies(drv); -+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, -+ NULL); -+ } -+ break; -+ case IWEVMICHAELMICFAILURE: -+ if (custom + iwe->u.data.length > end) { -+ wpa_printf(MSG_DEBUG, "WEXT: Invalid " -+ "IWEVMICHAELMICFAILURE length"); -+ return; -+ } -+ wpa_driver_wext_event_wireless_michaelmicfailure( -+ drv->ctx, custom, iwe->u.data.length); -+ break; -+ case IWEVCUSTOM: -+ if (custom + iwe->u.data.length > end) { -+ wpa_printf(MSG_DEBUG, "WEXT: Invalid " -+ "IWEVCUSTOM length"); -+ return; -+ } -+ buf = os_malloc(iwe->u.data.length + 1); -+ if (buf == NULL) -+ return; -+ os_memcpy(buf, custom, iwe->u.data.length); -+ buf[iwe->u.data.length] = '\0'; -+ wpa_driver_wext_event_wireless_custom(drv->ctx, buf); -+ os_free(buf); -+ break; -+ case SIOCGIWSCAN: -+ drv->scan_complete_events = 1; -+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, -+ drv, drv->ctx); -+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, -+ NULL); -+ break; -+ case IWEVASSOCREQIE: -+ if (custom + iwe->u.data.length > end) { -+ wpa_printf(MSG_DEBUG, "WEXT: Invalid " -+ "IWEVASSOCREQIE length"); -+ return; -+ } -+ wpa_driver_wext_event_wireless_assocreqie( -+ drv, custom, iwe->u.data.length); -+ break; -+ case IWEVASSOCRESPIE: -+ if (custom + iwe->u.data.length > end) { -+ wpa_printf(MSG_DEBUG, "WEXT: Invalid " -+ "IWEVASSOCRESPIE length"); -+ return; -+ } -+ wpa_driver_wext_event_wireless_assocrespie( -+ drv, custom, iwe->u.data.length); -+ break; -+ case IWEVPMKIDCAND: -+ if (custom + iwe->u.data.length > end) { -+ wpa_printf(MSG_DEBUG, "WEXT: Invalid " -+ "IWEVPMKIDCAND length"); -+ return; -+ } -+ wpa_driver_wext_event_wireless_pmkidcand( -+ drv, custom, iwe->u.data.length); -+ break; -+ } -+ -+ pos += iwe->len; -+ } -+} -+ -+ -+static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv, -+ char *buf, size_t len, int del) -+{ -+ union wpa_event_data event; -+ -+ os_memset(&event, 0, sizeof(event)); -+ if (len > sizeof(event.interface_status.ifname)) -+ len = sizeof(event.interface_status.ifname) - 1; -+ os_memcpy(event.interface_status.ifname, buf, len); -+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED : -+ EVENT_INTERFACE_ADDED; -+ -+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s", -+ del ? "DEL" : "NEW", -+ event.interface_status.ifname, -+ del ? "removed" : "added"); -+ -+ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) { -+ if (del) -+ drv->if_removed = 1; -+ else -+ drv->if_removed = 0; -+ } -+ -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event); -+} -+ -+ -+static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv, -+ u8 *buf, size_t len) -+{ -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_IFNAME) { -+ if (os_strcmp(((char *) attr) + rta_len, drv->ifname) -+ == 0) -+ return 1; -+ else -+ break; -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv, -+ int ifindex, u8 *buf, size_t len) -+{ -+ if (drv->ifindex == ifindex || drv->ifindex2 == ifindex) -+ return 1; -+ -+ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, buf, len)) { -+ drv->ifindex = if_nametoindex(drv->ifname); -+ wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed " -+ "interface"); -+ wpa_driver_wext_finish_drv_init(drv); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void wpa_driver_wext_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, -+ u8 *buf, size_t len) -+{ -+ struct wpa_driver_wext_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, buf, len)) { -+ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d", -+ ifi->ifi_index); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x " -+ "(%s%s%s%s)", -+ drv->operstate, ifi->ifi_flags, -+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", -+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", -+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", -+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); -+ -+ if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { -+ wpa_printf(MSG_DEBUG, "WEXT: Interface down"); -+ drv->if_disabled = 1; -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL); -+ } -+ -+ if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { -+ wpa_printf(MSG_DEBUG, "WEXT: Interface up"); -+ drv->if_disabled = 0; -+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL); -+ } -+ -+ /* -+ * Some drivers send the association event before the operup event--in -+ * this case, lifting operstate in wpa_driver_wext_set_operstate() -+ * fails. This will hit us when wpa_supplicant does not need to do -+ * IEEE 802.1X authentication -+ */ -+ if (drv->operstate == 1 && -+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP && -+ !(ifi->ifi_flags & IFF_RUNNING)) -+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, -+ -1, IF_OPER_UP); -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_WIRELESS) { -+ wpa_driver_wext_event_wireless( -+ drv, ((char *) attr) + rta_len, -+ attr->rta_len - rta_len); -+ } else if (attr->rta_type == IFLA_IFNAME) { -+ wpa_driver_wext_event_link(drv, -+ ((char *) attr) + rta_len, -+ attr->rta_len - rta_len, 0); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+ -+ -+static void wpa_driver_wext_event_rtm_dellink(void *ctx, struct ifinfomsg *ifi, -+ u8 *buf, size_t len) -+{ -+ struct wpa_driver_wext_data *drv = ctx; -+ int attrlen, rta_len; -+ struct rtattr *attr; -+ -+ attrlen = len; -+ attr = (struct rtattr *) buf; -+ -+ rta_len = RTA_ALIGN(sizeof(struct rtattr)); -+ while (RTA_OK(attr, attrlen)) { -+ if (attr->rta_type == IFLA_IFNAME) { -+ wpa_driver_wext_event_link(drv, -+ ((char *) attr) + rta_len, -+ attr->rta_len - rta_len, 1); -+ } -+ attr = RTA_NEXT(attr, attrlen); -+ } -+} -+ -+ -+static void wpa_driver_wext_rfkill_blocked(void *ctx) -+{ -+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL blocked"); -+ /* -+ * This may be for any interface; use ifdown event to disable -+ * interface. -+ */ -+} -+ -+ -+static void wpa_driver_wext_rfkill_unblocked(void *ctx) -+{ -+ struct wpa_driver_wext_data *drv = ctx; -+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL unblocked"); -+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) { -+ wpa_printf(MSG_DEBUG, "WEXT: Could not set interface UP " -+ "after rfkill unblock"); -+ return; -+ } -+ /* rtnetlink ifup handler will report interface as enabled */ -+} -+ -+ -+static void wext_get_phy_name(struct wpa_driver_wext_data *drv) -+{ -+ /* Find phy (radio) to which this interface belongs */ -+ char buf[90], *pos; -+ int f, rv; -+ -+ drv->phyname[0] = '\0'; -+ snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name", -+ drv->ifname); -+ f = open(buf, O_RDONLY); -+ if (f < 0) { -+ wpa_printf(MSG_DEBUG, "Could not open file %s: %s", -+ buf, strerror(errno)); -+ return; -+ } -+ -+ rv = read(f, drv->phyname, sizeof(drv->phyname) - 1); -+ close(f); -+ if (rv < 0) { -+ wpa_printf(MSG_DEBUG, "Could not read file %s: %s", -+ buf, strerror(errno)); -+ return; -+ } -+ -+ drv->phyname[rv] = '\0'; -+ pos = os_strchr(drv->phyname, '\n'); -+ if (pos) -+ *pos = '\0'; -+ wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s", -+ drv->ifname, drv->phyname); -+} -+ -+ -+/** -+ * wpa_driver_wext_init - Initialize WE driver interface -+ * @ctx: context to be used when calling wpa_supplicant functions, -+ * e.g., wpa_supplicant_event() -+ * @ifname: interface name, e.g., wlan0 -+ * Returns: Pointer to private data, %NULL on failure -+ */ -+void * wpa_driver_wext_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_wext_data *drv; -+ struct netlink_config *cfg; -+ struct rfkill_config *rcfg; -+ char path[128]; -+ struct stat buf; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ drv->ctx = ctx; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ -+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname); -+ if (stat(path, &buf) == 0) { -+ wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected"); -+ drv->cfg80211 = 1; -+ wext_get_phy_name(drv); -+ } -+ -+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (drv->ioctl_sock < 0) { -+ perror("socket(PF_INET,SOCK_DGRAM)"); -+ goto err1; -+ } -+ -+ cfg = os_zalloc(sizeof(*cfg)); -+ if (cfg == NULL) -+ goto err1; -+ cfg->ctx = drv; -+ cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; -+ cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; -+ drv->netlink = netlink_init(cfg); -+ if (drv->netlink == NULL) { -+ os_free(cfg); -+ goto err2; -+ } -+ -+ rcfg = os_zalloc(sizeof(*rcfg)); -+ if (rcfg == NULL) -+ goto err3; -+ rcfg->ctx = drv; -+ os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); -+ rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked; -+ rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked; -+ drv->rfkill = rfkill_init(rcfg); -+ if (drv->rfkill == NULL) { -+ wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available"); -+ os_free(rcfg); -+ } -+ -+ drv->mlme_sock = -1; -+ -+ if (wpa_driver_wext_finish_drv_init(drv) < 0) -+ goto err3; -+ -+ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); -+ -+ return drv; -+ -+err3: -+ rfkill_deinit(drv->rfkill); -+ netlink_deinit(drv->netlink); -+err2: -+ close(drv->ioctl_sock); -+err1: -+ os_free(drv); -+ return NULL; -+} -+ -+ -+static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) -+{ -+ wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL); -+} -+ -+ -+static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) -+{ -+ int send_rfkill_event = 0; -+ -+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1) < 0) { -+ if (rfkill_is_blocked(drv->rfkill)) { -+ wpa_printf(MSG_DEBUG, "WEXT: Could not yet enable " -+ "interface '%s' due to rfkill", -+ drv->ifname); -+ drv->if_disabled = 1; -+ send_rfkill_event = 1; -+ } else { -+ wpa_printf(MSG_ERROR, "WEXT: Could not set " -+ "interface '%s' UP", drv->ifname); -+ return -1; -+ } -+ } -+ -+ /* -+ * Make sure that the driver does not have any obsolete PMKID entries. -+ */ -+ wpa_driver_wext_flush_pmkid(drv); -+ -+ if (wpa_driver_wext_set_mode(drv, 0) < 0) { -+ wpa_printf(MSG_DEBUG, "Could not configure driver to use " -+ "managed mode"); -+ /* Try to use it anyway */ -+ } -+ -+ wpa_driver_wext_get_range(drv); -+ -+ /* -+ * Unlock the driver's BSSID and force to a random SSID to clear any -+ * previous association the driver might have when the supplicant -+ * starts up. -+ */ -+ wpa_driver_wext_disconnect(drv); -+ -+ drv->ifindex = if_nametoindex(drv->ifname); -+ -+ if (os_strncmp(drv->ifname, "wlan", 4) == 0) { -+ /* -+ * Host AP driver may use both wlan# and wifi# interface in -+ * wireless events. Since some of the versions included WE-18 -+ * support, let's add the alternative ifindex also from -+ * driver_wext.c for the time being. This may be removed at -+ * some point once it is believed that old versions of the -+ * driver are not in use anymore. -+ */ -+ char ifname2[IFNAMSIZ + 1]; -+ os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); -+ os_memcpy(ifname2, "wifi", 4); -+ wpa_driver_wext_alternative_ifindex(drv, ifname2); -+ } -+ -+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, -+ 1, IF_OPER_DORMANT); -+ -+ if (send_rfkill_event) { -+ eloop_register_timeout(0, 0, wpa_driver_wext_send_rfkill, -+ drv, drv->ctx); -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_driver_wext_deinit - Deinitialize WE driver interface -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * -+ * Shut down driver interface and processing of driver events. Free -+ * private data buffer if one was allocated in wpa_driver_wext_init(). -+ */ -+void wpa_driver_wext_deinit(void *priv) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ -+ wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 0); -+ -+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); -+ -+ /* -+ * Clear possibly configured driver parameters in order to make it -+ * easier to use the driver after wpa_supplicant has been terminated. -+ */ -+ wpa_driver_wext_disconnect(drv); -+ -+ netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP); -+ netlink_deinit(drv->netlink); -+ rfkill_deinit(drv->rfkill); -+ -+ if (drv->mlme_sock >= 0) -+ eloop_unregister_read_sock(drv->mlme_sock); -+ -+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); -+ -+ close(drv->ioctl_sock); -+ if (drv->mlme_sock >= 0) -+ close(drv->mlme_sock); -+ os_free(drv->assoc_req_ies); -+ os_free(drv->assoc_resp_ies); -+ os_free(drv); -+} -+ -+ -+/** -+ * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion -+ * @eloop_ctx: Unused -+ * @timeout_ctx: ctx argument given to wpa_driver_wext_init() -+ * -+ * This function can be used as registered timeout when starting a scan to -+ * generate a scan completed event if the driver does not report this. -+ */ -+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); -+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); -+} -+ -+ -+//added for wps2.0 @20110519 -+static int wpa_driver_wext_set_probe_req_ie(struct wpa_driver_wext_data *drv, const u8 *extra_ies, -+ size_t extra_ies_len) -+{ -+ unsigned char *pbuf; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ pbuf = os_malloc(extra_ies_len); -+ os_memset(pbuf, 0, extra_ies_len); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ os_memcpy(pbuf, extra_ies, extra_ies_len); -+ -+ iwr.u.data.pointer = (caddr_t)pbuf; -+ iwr.u.data.length = extra_ies_len; -+ iwr.u.data.flags = 0x8766;//magic number -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMLME]"); -+ ret = -1; -+ } -+ -+ if(pbuf) -+ os_free(pbuf); -+ -+ return ret; -+ -+} -+ -+/** -+ * wpa_driver_wext_scan - Request the driver to initiate scan -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.) -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0, timeout; -+ struct iw_scan_req req; -+ const u8 *ssid = params->ssids[0].ssid; -+ size_t ssid_len = params->ssids[0].ssid_len; -+ -+ if (ssid_len > IW_ESSID_MAX_SIZE) { -+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)", -+ __FUNCTION__, (unsigned long) ssid_len); -+ return -1; -+ } -+ -+ //added for wps2.0 @20110519 -+ wpa_driver_wext_set_probe_req_ie(drv, params->extra_ies, -+ params->extra_ies_len); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ if (ssid && ssid_len) { -+ os_memset(&req, 0, sizeof(req)); -+ req.essid_len = ssid_len; -+ req.bssid.sa_family = ARPHRD_ETHER; -+ os_memset(req.bssid.sa_data, 0xff, ETH_ALEN); -+ os_memcpy(req.essid, ssid, ssid_len); -+ iwr.u.data.pointer = (caddr_t) &req; -+ iwr.u.data.length = sizeof(req); -+ iwr.u.data.flags = IW_SCAN_THIS_ESSID; -+ } -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) { -+ perror("ioctl[SIOCSIWSCAN]"); -+ ret = -1; -+ } -+ -+ /* Not all drivers generate "scan completed" wireless event, so try to -+ * read results after a timeout. */ -+ timeout = 5; -+ if (drv->scan_complete_events) { -+ /* -+ * The driver seems to deliver SIOCGIWSCAN events to notify -+ * when scan is complete, so use longer timeout to avoid race -+ * conditions with scanning and following association request. -+ */ -+ timeout = 30; -+ } -+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d " -+ "seconds", ret, timeout); -+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); -+ eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv, -+ drv->ctx); -+ -+ return ret; -+} -+ -+ -+static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv, -+ size_t *len) -+{ -+ struct iwreq iwr; -+ u8 *res_buf; -+ size_t res_buf_len; -+ -+ res_buf_len = IW_SCAN_MAX_DATA; -+ for (;;) { -+ res_buf = os_malloc(res_buf_len); -+ if (res_buf == NULL) -+ return NULL; -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = res_buf; -+ iwr.u.data.length = res_buf_len; -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0) -+ break; -+ -+ if (errno == E2BIG && res_buf_len < 65535) { -+ os_free(res_buf); -+ res_buf = NULL; -+ res_buf_len *= 2; -+ if (res_buf_len > 65535) -+ res_buf_len = 65535; /* 16-bit length field */ -+ wpa_printf(MSG_DEBUG, "Scan results did not fit - " -+ "trying larger buffer (%lu bytes)", -+ (unsigned long) res_buf_len); -+ } else { -+ perror("ioctl[SIOCGIWSCAN]"); -+ os_free(res_buf); -+ return NULL; -+ } -+ } -+ -+ if (iwr.u.data.length > res_buf_len) { -+ os_free(res_buf); -+ return NULL; -+ } -+ *len = iwr.u.data.length; -+ -+ return res_buf; -+} -+ -+ -+/* -+ * Data structure for collecting WEXT scan results. This is needed to allow -+ * the various methods of reporting IEs to be combined into a single IE buffer. -+ */ -+struct wext_scan_data { -+ struct wpa_scan_res res; -+ u8 *ie; -+ size_t ie_len; -+ u8 ssid[32]; -+ size_t ssid_len; -+ int maxrate; -+}; -+ -+ -+static void wext_get_scan_mode(struct iw_event *iwe, -+ struct wext_scan_data *res) -+{ -+ if (iwe->u.mode == IW_MODE_ADHOC) -+ res->res.caps |= IEEE80211_CAP_IBSS; -+ else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA) -+ res->res.caps |= IEEE80211_CAP_ESS; -+} -+ -+ -+static void wext_get_scan_ssid(struct iw_event *iwe, -+ struct wext_scan_data *res, char *custom, -+ char *end) -+{ -+ int ssid_len = iwe->u.essid.length; -+ if (custom + ssid_len > end) -+ return; -+ if (iwe->u.essid.flags && -+ ssid_len > 0 && -+ ssid_len <= IW_ESSID_MAX_SIZE) { -+ os_memcpy(res->ssid, custom, ssid_len); -+ res->ssid_len = ssid_len; -+ } -+} -+ -+ -+static void wext_get_scan_freq(struct iw_event *iwe, -+ struct wext_scan_data *res) -+{ -+ int divi = 1000000, i; -+ -+ if (iwe->u.freq.e == 0) { -+ /* -+ * Some drivers do not report frequency, but a channel. -+ * Try to map this to frequency by assuming they are using -+ * IEEE 802.11b/g. But don't overwrite a previously parsed -+ * frequency if the driver sends both frequency and channel, -+ * since the driver may be sending an A-band channel that we -+ * don't handle here. -+ */ -+ -+ if (res->res.freq) -+ return; -+ -+ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) { -+ res->res.freq = 2407 + 5 * iwe->u.freq.m; -+ return; -+ } else if (iwe->u.freq.m == 14) { -+ res->res.freq = 2484; -+ return; -+ } -+ } -+ -+ if (iwe->u.freq.e > 6) { -+ wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID=" -+ MACSTR " m=%d e=%d)", -+ MAC2STR(res->res.bssid), iwe->u.freq.m, -+ iwe->u.freq.e); -+ return; -+ } -+ -+ for (i = 0; i < iwe->u.freq.e; i++) -+ divi /= 10; -+ res->res.freq = iwe->u.freq.m / divi; -+} -+ -+ -+static void wext_get_scan_qual(struct wpa_driver_wext_data *drv, -+ struct iw_event *iwe, -+ struct wext_scan_data *res) -+{ -+ res->res.qual = iwe->u.qual.qual; -+ res->res.noise = iwe->u.qual.noise; -+ res->res.level = iwe->u.qual.level; -+ if (iwe->u.qual.updated & IW_QUAL_QUAL_INVALID) -+ res->res.flags |= WPA_SCAN_QUAL_INVALID; -+ if (iwe->u.qual.updated & IW_QUAL_LEVEL_INVALID) -+ res->res.flags |= WPA_SCAN_LEVEL_INVALID; -+ if (iwe->u.qual.updated & IW_QUAL_NOISE_INVALID) -+ res->res.flags |= WPA_SCAN_NOISE_INVALID; -+ if (iwe->u.qual.updated & IW_QUAL_DBM) -+ res->res.flags |= WPA_SCAN_LEVEL_DBM; -+ if ((iwe->u.qual.updated & IW_QUAL_DBM) || -+ ((iwe->u.qual.level != 0) && -+ (iwe->u.qual.level > drv->max_level))) { -+ if (iwe->u.qual.level >= 64) -+ res->res.level -= 0x100; -+ if (iwe->u.qual.noise >= 64) -+ res->res.noise -= 0x100; -+ } -+} -+ -+ -+static void wext_get_scan_encode(struct iw_event *iwe, -+ struct wext_scan_data *res) -+{ -+ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED)) -+ res->res.caps |= IEEE80211_CAP_PRIVACY; -+} -+ -+ -+static void wext_get_scan_rate(struct iw_event *iwe, -+ struct wext_scan_data *res, char *pos, -+ char *end) -+{ -+ int maxrate; -+ char *custom = pos + IW_EV_LCP_LEN; -+ struct iw_param p; -+ size_t clen; -+ -+ clen = iwe->len; -+ if (custom + clen > end) -+ return; -+ maxrate = 0; -+ while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) { -+ /* Note: may be misaligned, make a local, aligned copy */ -+ os_memcpy(&p, custom, sizeof(struct iw_param)); -+ if (p.value > maxrate) -+ maxrate = p.value; -+ clen -= sizeof(struct iw_param); -+ custom += sizeof(struct iw_param); -+ } -+ -+ /* Convert the maxrate from WE-style (b/s units) to -+ * 802.11 rates (500000 b/s units). -+ */ -+ res->maxrate = maxrate / 500000; -+} -+ -+ -+static void wext_get_scan_iwevgenie(struct iw_event *iwe, -+ struct wext_scan_data *res, char *custom, -+ char *end) -+{ -+ char *genie, *gpos, *gend; -+ u8 *tmp; -+ -+ if (iwe->u.data.length == 0) -+ return; -+ -+ gpos = genie = custom; -+ gend = genie + iwe->u.data.length; -+ if (gend > end) { -+ wpa_printf(MSG_INFO, "IWEVGENIE overflow"); -+ return; -+ } -+ -+ tmp = os_realloc(res->ie, res->ie_len + gend - gpos); -+ if (tmp == NULL) -+ return; -+ os_memcpy(tmp + res->ie_len, gpos, gend - gpos); -+ res->ie = tmp; -+ res->ie_len += gend - gpos; -+} -+ -+ -+static void wext_get_scan_custom(struct iw_event *iwe, -+ struct wext_scan_data *res, char *custom, -+ char *end) -+{ -+ size_t clen; -+ u8 *tmp; -+ -+ clen = iwe->u.data.length; -+ if (custom + clen > end) -+ return; -+ -+ if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) { -+ char *spos; -+ int bytes; -+ spos = custom + 7; -+ bytes = custom + clen - spos; -+ if (bytes & 1 || bytes == 0) -+ return; -+ bytes /= 2; -+ tmp = os_realloc(res->ie, res->ie_len + bytes); -+ if (tmp == NULL) -+ return; -+ res->ie = tmp; -+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) -+ return; -+ res->ie_len += bytes; -+ } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) { -+ char *spos; -+ int bytes; -+ spos = custom + 7; -+ bytes = custom + clen - spos; -+ if (bytes & 1 || bytes == 0) -+ return; -+ bytes /= 2; -+ tmp = os_realloc(res->ie, res->ie_len + bytes); -+ if (tmp == NULL) -+ return; -+ res->ie = tmp; -+ if (hexstr2bin(spos, tmp + res->ie_len, bytes) < 0) -+ return; -+ res->ie_len += bytes; -+ } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) { -+ char *spos; -+ int bytes; -+ u8 bin[8]; -+ spos = custom + 4; -+ bytes = custom + clen - spos; -+ if (bytes != 16) { -+ wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes); -+ return; -+ } -+ bytes /= 2; -+ if (hexstr2bin(spos, bin, bytes) < 0) { -+ wpa_printf(MSG_DEBUG, "WEXT: Invalid TSF value"); -+ return; -+ } -+ res->res.tsf += WPA_GET_BE64(bin); -+ } -+} -+ -+ -+static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd) -+{ -+ return drv->we_version_compiled > 18 && -+ (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE || -+ cmd == IWEVGENIE || cmd == IWEVCUSTOM); -+} -+ -+ -+static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res, -+ struct wext_scan_data *data) -+{ -+ struct wpa_scan_res **tmp; -+ struct wpa_scan_res *r; -+ size_t extra_len; -+ u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL; -+ -+ /* Figure out whether we need to fake any IEs */ -+ pos = data->ie; -+ end = pos + data->ie_len; -+ while (pos && pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == WLAN_EID_SSID) -+ ssid_ie = pos; -+ else if (pos[0] == WLAN_EID_SUPP_RATES) -+ rate_ie = pos; -+ else if (pos[0] == WLAN_EID_EXT_SUPP_RATES) -+ rate_ie = pos; -+ pos += 2 + pos[1]; -+ } -+ -+ extra_len = 0; -+ if (ssid_ie == NULL) -+ extra_len += 2 + data->ssid_len; -+ if (rate_ie == NULL && data->maxrate) -+ extra_len += 3; -+ -+ r = os_zalloc(sizeof(*r) + extra_len + data->ie_len); -+ if (r == NULL) -+ return; -+ os_memcpy(r, &data->res, sizeof(*r)); -+ r->ie_len = extra_len + data->ie_len; -+ pos = (u8 *) (r + 1); -+ if (ssid_ie == NULL) { -+ /* -+ * Generate a fake SSID IE since the driver did not report -+ * a full IE list. -+ */ -+ *pos++ = WLAN_EID_SSID; -+ *pos++ = data->ssid_len; -+ os_memcpy(pos, data->ssid, data->ssid_len); -+ pos += data->ssid_len; -+ } -+ if (rate_ie == NULL && data->maxrate) { -+ /* -+ * Generate a fake Supported Rates IE since the driver did not -+ * report a full IE list. -+ */ -+ *pos++ = WLAN_EID_SUPP_RATES; -+ *pos++ = 1; -+ *pos++ = data->maxrate; -+ } -+ if (data->ie) -+ os_memcpy(pos, data->ie, data->ie_len); -+ -+ tmp = os_realloc(res->res, -+ (res->num + 1) * sizeof(struct wpa_scan_res *)); -+ if (tmp == NULL) { -+ os_free(r); -+ return; -+ } -+ tmp[res->num++] = r; -+ res->res = tmp; -+} -+ -+ -+/** -+ * wpa_driver_wext_get_scan_results - Fetch the latest scan results -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * Returns: Scan results on success, -1 on failure -+ */ -+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ size_t ap_num = 0, len; -+ int first; -+ u8 *res_buf; -+ struct iw_event iwe_buf, *iwe = &iwe_buf; -+ char *pos, *end, *custom; -+ struct wpa_scan_results *res; -+ struct wext_scan_data data; -+ -+ res_buf = wpa_driver_wext_giwscan(drv, &len); -+ if (res_buf == NULL) -+ return NULL; -+ -+ ap_num = 0; -+ first = 1; -+ -+ res = os_zalloc(sizeof(*res)); -+ if (res == NULL) { -+ os_free(res_buf); -+ return NULL; -+ } -+ -+ pos = (char *) res_buf; -+ end = (char *) res_buf + len; -+ os_memset(&data, 0, sizeof(data)); -+ -+ while (pos + IW_EV_LCP_LEN <= end) { -+ /* Event data may be unaligned, so make a local, aligned copy -+ * before processing. */ -+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); -+ if (iwe->len <= IW_EV_LCP_LEN) -+ break; -+ -+ custom = pos + IW_EV_POINT_LEN; -+ if (wext_19_iw_point(drv, iwe->cmd)) { -+ /* WE-19 removed the pointer from struct iw_point */ -+ char *dpos = (char *) &iwe_buf.u.data.length; -+ int dlen = dpos - (char *) &iwe_buf; -+ os_memcpy(dpos, pos + IW_EV_LCP_LEN, -+ sizeof(struct iw_event) - dlen); -+ } else { -+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); -+ custom += IW_EV_POINT_OFF; -+ } -+ -+ switch (iwe->cmd) { -+ case SIOCGIWAP: -+ if (!first) -+ wpa_driver_wext_add_scan_entry(res, &data); -+ first = 0; -+ os_free(data.ie); -+ os_memset(&data, 0, sizeof(data)); -+ os_memcpy(data.res.bssid, -+ iwe->u.ap_addr.sa_data, ETH_ALEN); -+ break; -+ case SIOCGIWMODE: -+ wext_get_scan_mode(iwe, &data); -+ break; -+ case SIOCGIWESSID: -+ wext_get_scan_ssid(iwe, &data, custom, end); -+ break; -+ case SIOCGIWFREQ: -+ wext_get_scan_freq(iwe, &data); -+ break; -+ case IWEVQUAL: -+ wext_get_scan_qual(drv, iwe, &data); -+ break; -+ case SIOCGIWENCODE: -+ wext_get_scan_encode(iwe, &data); -+ break; -+ case SIOCGIWRATE: -+ wext_get_scan_rate(iwe, &data, pos, end); -+ break; -+ case IWEVGENIE: -+ wext_get_scan_iwevgenie(iwe, &data, custom, end); -+ break; -+ case IWEVCUSTOM: -+ wext_get_scan_custom(iwe, &data, custom, end); -+ break; -+ } -+ -+ pos += iwe->len; -+ } -+ os_free(res_buf); -+ res_buf = NULL; -+ if (!first) -+ wpa_driver_wext_add_scan_entry(res, &data); -+ os_free(data.ie); -+ -+ wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)", -+ (unsigned long) len, (unsigned long) res->num); -+ -+ return res; -+} -+ -+ -+static int wpa_driver_wext_get_range(void *priv) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iw_range *range; -+ struct iwreq iwr; -+ int minlen; -+ size_t buflen; -+ -+ /* -+ * Use larger buffer than struct iw_range in order to allow the -+ * structure to grow in the future. -+ */ -+ buflen = sizeof(struct iw_range) + 500; -+ range = os_zalloc(buflen); -+ if (range == NULL) -+ return -1; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) range; -+ iwr.u.data.length = buflen; -+ -+ minlen = ((char *) &range->enc_capa) - (char *) range + -+ sizeof(range->enc_capa); -+ -+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { -+ perror("ioctl[SIOCGIWRANGE]"); -+ os_free(range); -+ return -1; -+ } else if (iwr.u.data.length >= minlen && -+ range->we_version_compiled >= 18) { -+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " -+ "WE(source)=%d enc_capa=0x%x", -+ range->we_version_compiled, -+ range->we_version_source, -+ range->enc_capa); -+ drv->has_capability = 1; -+ drv->we_version_compiled = range->we_version_compiled; -+ if (range->enc_capa & IW_ENC_CAPA_WPA) { -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; -+ } -+ if (range->enc_capa & IW_ENC_CAPA_WPA2) { -+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | -+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; -+ } -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | -+ WPA_DRIVER_CAPA_ENC_WEP104; -+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; -+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) -+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; -+ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE) -+ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; -+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | -+ WPA_DRIVER_AUTH_SHARED | -+ WPA_DRIVER_AUTH_LEAP; -+ drv->capa.max_scan_ssids = 1; -+ -+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " -+ "flags 0x%x", -+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags); -+ } else { -+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " -+ "assuming WPA is not supported"); -+ } -+ -+ drv->max_level = range->max_qual.level; -+ -+ os_free(range); -+ return 0; -+} -+ -+ -+static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv, -+ const u8 *psk) -+{ -+ struct iw_encode_ext *ext; -+ struct iwreq iwr; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) -+ return 0; -+ -+ if (!psk) -+ return 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ -+ ext = os_zalloc(sizeof(*ext) + PMK_LEN); -+ if (ext == NULL) -+ return -1; -+ -+ iwr.u.encoding.pointer = (caddr_t) ext; -+ iwr.u.encoding.length = sizeof(*ext) + PMK_LEN; -+ ext->key_len = PMK_LEN; -+ os_memcpy(&ext->key, psk, ext->key_len); -+ ext->alg = IW_ENCODE_ALG_PMK; -+ -+ ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr); -+ if (ret < 0) -+ perror("ioctl[SIOCSIWENCODEEXT] PMK"); -+ os_free(ext); -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, -+ const u8 *addr, int key_idx, -+ int set_tx, const u8 *seq, -+ size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ struct iw_encode_ext *ext; -+ -+ if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) { -+ wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu", -+ __FUNCTION__, (unsigned long) seq_len); -+ return -1; -+ } -+ -+ ext = os_zalloc(sizeof(*ext) + key_len); -+ if (ext == NULL) -+ return -1; -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.encoding.flags = key_idx + 1; -+ iwr.u.encoding.flags |= IW_ENCODE_TEMP; -+ if (alg == WPA_ALG_NONE) -+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; -+ iwr.u.encoding.pointer = (caddr_t) ext; -+ iwr.u.encoding.length = sizeof(*ext) + key_len; -+ -+ if (addr == NULL || is_broadcast_ether_addr(addr)) -+ ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY; -+ if (set_tx) -+ ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY; -+ -+ ext->addr.sa_family = ARPHRD_ETHER; -+ if (addr) -+ os_memcpy(ext->addr.sa_data, addr, ETH_ALEN); -+ else -+ os_memset(ext->addr.sa_data, 0xff, ETH_ALEN); -+ if (key && key_len) { -+ os_memcpy(ext + 1, key, key_len); -+ ext->key_len = key_len; -+ } -+ switch (alg) { -+ case WPA_ALG_NONE: -+ ext->alg = IW_ENCODE_ALG_NONE; -+ break; -+ case WPA_ALG_WEP: -+ ext->alg = IW_ENCODE_ALG_WEP; -+ break; -+ case WPA_ALG_TKIP: -+ ext->alg = IW_ENCODE_ALG_TKIP; -+ break; -+ case WPA_ALG_CCMP: -+ ext->alg = IW_ENCODE_ALG_CCMP; -+ break; -+ case WPA_ALG_PMK: -+ ext->alg = IW_ENCODE_ALG_PMK; -+ break; -+#ifdef CONFIG_IEEE80211W -+ case WPA_ALG_IGTK: -+ ext->alg = IW_ENCODE_ALG_AES_CMAC; -+ break; -+#endif /* CONFIG_IEEE80211W */ -+ default: -+ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", -+ __FUNCTION__, alg); -+ os_free(ext); -+ return -1; -+ } -+ -+ if (seq && seq_len) { -+ ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID; -+ os_memcpy(ext->rx_seq, seq, seq_len); -+ } -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) { -+ ret = errno == EOPNOTSUPP ? -2 : -1; -+ if (errno == ENODEV) { -+ /* -+ * ndiswrapper seems to be returning incorrect error -+ * code.. */ -+ ret = -2; -+ } -+ -+ perror("ioctl[SIOCSIWENCODEEXT]"); -+ } -+ -+ os_free(ext); -+ return ret; -+} -+ -+ -+/** -+ * wpa_driver_wext_set_key - Configure encryption key -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @priv: Private driver interface data -+ * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, -+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key. -+ * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for -+ * broadcast/default keys -+ * @key_idx: key index (0..3), usually 0 for unicast keys -+ * @set_tx: Configure this key as the default Tx key (only used when -+ * driver does not support separate unicast/individual key -+ * @seq: Sequence number/packet number, seq_len octets, the next -+ * packet number to be used for in replay protection; configured -+ * for Rx keys (in most cases, this is only used with broadcast -+ * keys and set to zero for unicast keys) -+ * @seq_len: Length of the seq, depends on the algorithm: -+ * TKIP: 6 octets, CCMP: 6 octets -+ * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, -+ * 8-byte Rx Mic Key -+ * @key_len: Length of the key buffer in octets (WEP: 5 or 13, -+ * TKIP: 32, CCMP: 16) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function uses SIOCSIWENCODEEXT by default, but tries to use -+ * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key. -+ */ -+int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, -+ const u8 *addr, int key_idx, -+ int set_tx, const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu " -+ "key_len=%lu", -+ __FUNCTION__, alg, key_idx, set_tx, -+ (unsigned long) seq_len, (unsigned long) key_len); -+ -+ ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx, -+ seq, seq_len, key, key_len); -+ if (ret == 0) -+ return 0; -+ -+ if (ret == -2 && -+ (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) { -+ wpa_printf(MSG_DEBUG, "Driver did not support " -+ "SIOCSIWENCODEEXT, trying SIOCSIWENCODE"); -+ ret = 0; -+ } else { -+ wpa_printf(MSG_DEBUG, "Driver did not support " -+ "SIOCSIWENCODEEXT"); -+ return ret; -+ } -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.encoding.flags = key_idx + 1; -+ iwr.u.encoding.flags |= IW_ENCODE_TEMP; -+ if (alg == WPA_ALG_NONE) -+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; -+ iwr.u.encoding.pointer = (caddr_t) key; -+ iwr.u.encoding.length = key_len; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWENCODE]"); -+ ret = -1; -+ } -+ -+ if (set_tx && alg != WPA_ALG_NONE) { -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.encoding.flags = key_idx + 1; -+ iwr.u.encoding.flags |= IW_ENCODE_TEMP; -+ iwr.u.encoding.pointer = (caddr_t) NULL; -+ iwr.u.encoding.length = 0; -+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWENCODE] (set_tx)"); -+ ret = -1; -+ } -+ } -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_wext_set_countermeasures(void *priv, -+ int enabled) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ return wpa_driver_wext_set_auth_param(drv, -+ IW_AUTH_TKIP_COUNTERMEASURES, -+ enabled); -+} -+ -+ -+static int wpa_driver_wext_set_drop_unencrypted(void *priv, -+ int enabled) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ drv->use_crypt = enabled; -+ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, -+ enabled); -+} -+ -+ -+static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv, -+ const u8 *addr, int cmd, int reason_code) -+{ -+ struct iwreq iwr; -+ struct iw_mlme mlme; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ os_memset(&mlme, 0, sizeof(mlme)); -+ mlme.cmd = cmd; -+ mlme.reason_code = reason_code; -+ mlme.addr.sa_family = ARPHRD_ETHER; -+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN); -+ iwr.u.data.pointer = (caddr_t) &mlme; -+ iwr.u.data.length = sizeof(mlme); -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) { -+ perror("ioctl[SIOCSIWMLME]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) -+{ -+ struct iwreq iwr; -+ const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; -+ u8 ssid[32]; -+ int i; -+ -+ /* -+ * Only force-disconnect when the card is in infrastructure mode, -+ * otherwise the driver might interpret the cleared BSSID and random -+ * SSID as an attempt to create a new ad-hoc network. -+ */ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { -+ perror("ioctl[SIOCGIWMODE]"); -+ iwr.u.mode = IW_MODE_INFRA; -+ } -+ -+ if (iwr.u.mode == IW_MODE_INFRA) { -+ if (drv->cfg80211) { -+ /* -+ * cfg80211 supports SIOCSIWMLME commands, so there is -+ * no need for the random SSID hack, but clear the -+ * BSSID and SSID. -+ */ -+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || -+ wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { -+ wpa_printf(MSG_DEBUG, "WEXT: Failed to clear " -+ "to disconnect"); -+ } -+ return; -+ } -+ /* -+ * Clear the BSSID selection and set a random SSID to make sure -+ * the driver will not be trying to associate with something -+ * even if it does not understand SIOCSIWMLME commands (or -+ * tries to associate automatically after deauth/disassoc). -+ */ -+ for (i = 0; i < 32; i++) -+ ssid[i] = rand() & 0xFF; -+ if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 || -+ wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) { -+ wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " -+ "BSSID/SSID to disconnect"); -+ } -+ } -+} -+ -+ -+static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ int ret; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code); -+ wpa_driver_wext_disconnect(drv); -+ return ret; -+} -+ -+ -+static int wpa_driver_wext_disassociate(void *priv, const u8 *addr, -+ int reason_code) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ int ret; -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code); -+ wpa_driver_wext_disconnect(drv); -+ return ret; -+} -+ -+ -+static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie, -+ size_t ie_len) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.data.pointer = (caddr_t) ie; -+ iwr.u.data.length = ie_len; -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWGENIE]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+int wpa_driver_wext_cipher2wext(int cipher) -+{ -+ switch (cipher) { -+ case CIPHER_NONE: -+ return IW_AUTH_CIPHER_NONE; -+ case CIPHER_WEP40: -+ return IW_AUTH_CIPHER_WEP40; -+ case CIPHER_TKIP: -+ return IW_AUTH_CIPHER_TKIP; -+ case CIPHER_CCMP: -+ return IW_AUTH_CIPHER_CCMP; -+ case CIPHER_WEP104: -+ return IW_AUTH_CIPHER_WEP104; -+ default: -+ return 0; -+ } -+} -+ -+ -+int wpa_driver_wext_keymgmt2wext(int keymgmt) -+{ -+ switch (keymgmt) { -+ case KEY_MGMT_802_1X: -+ case KEY_MGMT_802_1X_NO_WPA: -+ return IW_AUTH_KEY_MGMT_802_1X; -+ case KEY_MGMT_PSK: -+ return IW_AUTH_KEY_MGMT_PSK; -+ default: -+ return 0; -+ } -+} -+ -+ -+static int -+wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct iwreq iwr; -+ int ret = 0; -+ -+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support " -+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE"); -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ /* Just changing mode, not actual keys */ -+ iwr.u.encoding.flags = 0; -+ iwr.u.encoding.pointer = (caddr_t) NULL; -+ iwr.u.encoding.length = 0; -+ -+ /* -+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two -+ * different things. Here they are used to indicate Open System vs. -+ * Shared Key authentication algorithm. However, some drivers may use -+ * them to select between open/restricted WEP encrypted (open = allow -+ * both unencrypted and encrypted frames; restricted = only allow -+ * encrypted frames). -+ */ -+ -+ if (!drv->use_crypt) { -+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED; -+ } else { -+ if (params->auth_alg & WPA_AUTH_ALG_OPEN) -+ iwr.u.encoding.flags |= IW_ENCODE_OPEN; -+ if (params->auth_alg & WPA_AUTH_ALG_SHARED) -+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; -+ } -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { -+ perror("ioctl[SIOCSIWENCODE]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+int wpa_driver_wext_associate(void *priv, -+ struct wpa_driver_associate_params *params) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ int ret = 0; -+ int allow_unencrypted_eapol; -+ int value; -+ -+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -+ -+ if (drv->cfg80211) { -+ /* -+ * Stop cfg80211 from trying to associate before we are done -+ * with all parameters. -+ */ -+ wpa_driver_wext_set_ssid(drv, (u8 *) "", 0); -+ } -+ -+ if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted) -+ < 0) -+ ret = -1; -+ if (wpa_driver_wext_set_auth_alg(drv, params->auth_alg) < 0) -+ ret = -1; -+ if (wpa_driver_wext_set_mode(drv, params->mode) < 0) -+ ret = -1; -+ -+ /* -+ * If the driver did not support SIOCSIWAUTH, fallback to -+ * SIOCSIWENCODE here. -+ */ -+ if (drv->auth_alg_fallback && -+ wpa_driver_wext_auth_alg_fallback(drv, params) < 0) -+ ret = -1; -+ -+ if (!params->bssid && -+ wpa_driver_wext_set_bssid(drv, NULL) < 0) -+ ret = -1; -+ -+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites -+ * from configuration, not from here, where only the selected suite is -+ * available */ -+ if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) -+ < 0) -+ ret = -1; -+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0) -+ value = IW_AUTH_WPA_VERSION_DISABLED; -+ else if (params->wpa_ie[0] == WLAN_EID_RSN) -+ value = IW_AUTH_WPA_VERSION_WPA2; -+ else -+ value = IW_AUTH_WPA_VERSION_WPA; -+ if (wpa_driver_wext_set_auth_param(drv, -+ IW_AUTH_WPA_VERSION, value) < 0) -+ ret = -1; -+ value = wpa_driver_wext_cipher2wext(params->pairwise_suite); -+ if (wpa_driver_wext_set_auth_param(drv, -+ IW_AUTH_CIPHER_PAIRWISE, value) < 0) -+ ret = -1; -+ value = wpa_driver_wext_cipher2wext(params->group_suite); -+ if (wpa_driver_wext_set_auth_param(drv, -+ IW_AUTH_CIPHER_GROUP, value) < 0) -+ ret = -1; -+ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite); -+ if (wpa_driver_wext_set_auth_param(drv, -+ IW_AUTH_KEY_MGMT, value) < 0) -+ ret = -1; -+ value = params->key_mgmt_suite != KEY_MGMT_NONE || -+ params->pairwise_suite != CIPHER_NONE || -+ params->group_suite != CIPHER_NONE || -+ params->wpa_ie_len; -+ if (wpa_driver_wext_set_auth_param(drv, -+ IW_AUTH_PRIVACY_INVOKED, value) < 0) -+ ret = -1; -+ -+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when -+ * not using WPA. IEEE 802.1X specifies that these frames are not -+ * encrypted, but WPA encrypts them when pairwise keys are in use. */ -+ if (params->key_mgmt_suite == KEY_MGMT_802_1X || -+ params->key_mgmt_suite == KEY_MGMT_PSK) -+ allow_unencrypted_eapol = 0; -+ else -+ allow_unencrypted_eapol = 1; -+ -+ if (wpa_driver_wext_set_psk(drv, params->psk) < 0) -+ ret = -1; -+ if (wpa_driver_wext_set_auth_param(drv, -+ IW_AUTH_RX_UNENCRYPTED_EAPOL, -+ allow_unencrypted_eapol) < 0) -+ ret = -1; -+#ifdef CONFIG_IEEE80211W -+ switch (params->mgmt_frame_protection) { -+ case NO_MGMT_FRAME_PROTECTION: -+ value = IW_AUTH_MFP_DISABLED; -+ break; -+ case MGMT_FRAME_PROTECTION_OPTIONAL: -+ value = IW_AUTH_MFP_OPTIONAL; -+ break; -+ case MGMT_FRAME_PROTECTION_REQUIRED: -+ value = IW_AUTH_MFP_REQUIRED; -+ break; -+ }; -+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0) -+ ret = -1; -+#endif /* CONFIG_IEEE80211W */ -+ if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0) -+ ret = -1; -+ if (!drv->cfg80211 && -+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) -+ ret = -1; -+ if (params->bssid && -+ wpa_driver_wext_set_bssid(drv, params->bssid) < 0) -+ ret = -1; -+ if (drv->cfg80211 && -+ wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) -+ ret = -1; -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ int algs = 0, res; -+ -+ if (auth_alg & WPA_AUTH_ALG_OPEN) -+ algs |= IW_AUTH_ALG_OPEN_SYSTEM; -+ if (auth_alg & WPA_AUTH_ALG_SHARED) -+ algs |= IW_AUTH_ALG_SHARED_KEY; -+ if (auth_alg & WPA_AUTH_ALG_LEAP) -+ algs |= IW_AUTH_ALG_LEAP; -+ if (algs == 0) { -+ /* at least one algorithm should be set */ -+ algs = IW_AUTH_ALG_OPEN_SYSTEM; -+ } -+ -+ res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, -+ algs); -+ drv->auth_alg_fallback = res == -2; -+ return res; -+} -+ -+ -+/** -+ * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE -+ * @priv: Pointer to private wext data from wpa_driver_wext_init() -+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_driver_wext_set_mode(void *priv, int mode) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ struct iwreq iwr; -+ int ret = -1; -+ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ iwr.u.mode = new_mode; -+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) { -+ ret = 0; -+ goto done; -+ } -+ -+ if (errno != EBUSY) { -+ perror("ioctl[SIOCSIWMODE]"); -+ goto done; -+ } -+ -+ /* mac80211 doesn't allow mode changes while the device is up, so if -+ * the device isn't in the mode we're about to change to, take device -+ * down, try to set the mode again, and bring it back up. -+ */ -+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) { -+ perror("ioctl[SIOCGIWMODE]"); -+ goto done; -+ } -+ -+ if (iwr.u.mode == new_mode) { -+ ret = 0; -+ goto done; -+ } -+ -+ if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0) == 0) { -+ /* Try to set the mode again while the interface is down */ -+ iwr.u.mode = new_mode; -+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) -+ perror("ioctl[SIOCSIWMODE]"); -+ else -+ ret = 0; -+ -+ (void) linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1); -+ } -+ -+done: -+ return ret; -+} -+ -+ -+static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv, -+ u32 cmd, const u8 *bssid, const u8 *pmkid) -+{ -+ struct iwreq iwr; -+ struct iw_pmksa pmksa; -+ int ret = 0; -+ -+ os_memset(&iwr, 0, sizeof(iwr)); -+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); -+ os_memset(&pmksa, 0, sizeof(pmksa)); -+ pmksa.cmd = cmd; -+ pmksa.bssid.sa_family = ARPHRD_ETHER; -+ if (bssid) -+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN); -+ if (pmkid) -+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN); -+ iwr.u.data.pointer = (caddr_t) &pmksa; -+ iwr.u.data.length = sizeof(pmksa); -+ -+ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) { -+ if (errno != EOPNOTSUPP) -+ perror("ioctl[SIOCSIWPMKSA]"); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+ -+static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid); -+} -+ -+ -+static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid); -+} -+ -+ -+static int wpa_driver_wext_flush_pmkid(void *priv) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL); -+} -+ -+ -+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ if (!drv->has_capability) -+ return -1; -+ os_memcpy(capa, &drv->capa, sizeof(*capa)); -+ return 0; -+} -+ -+ -+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, -+ const char *ifname) -+{ -+ if (ifname == NULL) { -+ drv->ifindex2 = -1; -+ return 0; -+ } -+ -+ drv->ifindex2 = if_nametoindex(ifname); -+ if (drv->ifindex2 <= 0) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for " -+ "wireless events", drv->ifindex2, ifname); -+ -+ return 0; -+} -+ -+ -+int wpa_driver_wext_set_operstate(void *priv, int state) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ -+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)", -+ __func__, drv->operstate, state, state ? "UP" : "DORMANT"); -+ drv->operstate = state; -+ return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1, -+ state ? IF_OPER_UP : IF_OPER_DORMANT); -+} -+ -+ -+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv) -+{ -+ return drv->we_version_compiled; -+} -+ -+ -+static const char * wext_get_radio_name(void *priv) -+{ -+ struct wpa_driver_wext_data *drv = priv; -+ return drv->phyname; -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_wext_ops = { -+ .name = "wext", -+ .desc = "Linux wireless extensions (generic)", -+ .get_bssid = wpa_driver_wext_get_bssid, -+ .get_ssid = wpa_driver_wext_get_ssid, -+ .set_key = wpa_driver_wext_set_key, -+ .set_countermeasures = wpa_driver_wext_set_countermeasures, -+ .scan2 = wpa_driver_wext_scan, -+ .get_scan_results2 = wpa_driver_wext_get_scan_results, -+ .deauthenticate = wpa_driver_wext_deauthenticate, -+ .disassociate = wpa_driver_wext_disassociate, -+ .associate = wpa_driver_wext_associate, -+ .init = wpa_driver_wext_init, -+ .deinit = wpa_driver_wext_deinit, -+ .add_pmkid = wpa_driver_wext_add_pmkid, -+ .remove_pmkid = wpa_driver_wext_remove_pmkid, -+ .flush_pmkid = wpa_driver_wext_flush_pmkid, -+ .get_capa = wpa_driver_wext_get_capa, -+ .set_operstate = wpa_driver_wext_set_operstate, -+ .get_radio_name = wext_get_radio_name, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.h -new file mode 100644 -index 0000000000000..89c13eb758e82 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wext.h -@@ -0,0 +1,87 @@ -+/* -+ * WPA Supplicant - driver_wext exported functions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef DRIVER_WEXT_H -+#define DRIVER_WEXT_H -+ -+#include -+ -+struct wpa_driver_wext_data { -+ void *ctx; -+ struct netlink_data *netlink; -+ int ioctl_sock; -+ int mlme_sock; -+ char ifname[IFNAMSIZ + 1]; -+ char phyname[32]; -+ int ifindex; -+ int ifindex2; -+ int if_removed; -+ int if_disabled; -+ struct rfkill_data *rfkill; -+ u8 *assoc_req_ies; -+ size_t assoc_req_ies_len; -+ u8 *assoc_resp_ies; -+ size_t assoc_resp_ies_len; -+ struct wpa_driver_capa capa; -+ int has_capability; -+ int we_version_compiled; -+ -+ /* for set_auth_alg fallback */ -+ int use_crypt; -+ int auth_alg_fallback; -+ -+ int operstate; -+ -+ char mlmedev[IFNAMSIZ + 1]; -+ -+ int scan_complete_events; -+ -+ int cfg80211; /* whether driver is using cfg80211 */ -+ -+ u8 max_level; -+}; -+ -+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid); -+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid); -+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid); -+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len); -+int wpa_driver_wext_set_freq(void *priv, int freq); -+int wpa_driver_wext_set_mode(void *priv, int mode); -+int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, -+ const u8 *addr, int key_idx, -+ int set_tx, const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len); -+int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params); -+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv); -+ -+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx); -+ -+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, -+ const char *ifname); -+ -+void * wpa_driver_wext_init(void *ctx, const char *ifname); -+void wpa_driver_wext_deinit(void *priv); -+ -+int wpa_driver_wext_set_operstate(void *priv, int state); -+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv); -+ -+int wpa_driver_wext_associate(void *priv, -+ struct wpa_driver_associate_params *params); -+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa); -+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv, -+ int idx, u32 value); -+int wpa_driver_wext_cipher2wext(int cipher); -+int wpa_driver_wext_keymgmt2wext(int keymgmt); -+ -+#endif /* DRIVER_WEXT_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wired.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wired.c -new file mode 100644 -index 0000000000000..618db2648f99c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/driver_wired.c -@@ -0,0 +1,629 @@ -+/* -+ * Wired Ethernet driver interface -+ * Copyright (c) 2005-2009, Jouni Malinen -+ * Copyright (c) 2004, Gunter Burchardt -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#ifdef __linux__ -+#include -+#include -+#include -+#endif /* __linux__ */ -+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) -+#include -+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) */ -+#ifdef __sun__ -+#include -+#endif /* __sun__ */ -+ -+#include "common.h" -+#include "eloop.h" -+#include "driver.h" -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct ieee8023_hdr { -+ u8 dest[6]; -+ u8 src[6]; -+ u16 ethertype; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+static const u8 pae_group_addr[ETH_ALEN] = -+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; -+ -+ -+struct wpa_driver_wired_data { -+ char ifname[IFNAMSIZ + 1]; -+ void *ctx; -+ -+ int sock; /* raw packet socket for driver access */ -+ int dhcp_sock; /* socket for dhcp packets */ -+ int use_pae_group_addr; -+ -+ int pf_sock; -+ int membership, multi, iff_allmulti, iff_up; -+}; -+ -+ -+/* TODO: detecting new devices should eventually be changed from using DHCP -+ * snooping to trigger on any packet from a new layer 2 MAC address, e.g., -+ * based on ebtables, etc. */ -+ -+struct dhcp_message { -+ u_int8_t op; -+ u_int8_t htype; -+ u_int8_t hlen; -+ u_int8_t hops; -+ u_int32_t xid; -+ u_int16_t secs; -+ u_int16_t flags; -+ u_int32_t ciaddr; -+ u_int32_t yiaddr; -+ u_int32_t siaddr; -+ u_int32_t giaddr; -+ u_int8_t chaddr[16]; -+ u_int8_t sname[64]; -+ u_int8_t file[128]; -+ u_int32_t cookie; -+ u_int8_t options[308]; /* 312 - cookie */ -+}; -+ -+ -+static int wired_multicast_membership(int sock, int ifindex, -+ const u8 *addr, int add) -+{ -+#ifdef __linux__ -+ struct packet_mreq mreq; -+ -+ if (sock < 0) -+ return -1; -+ -+ os_memset(&mreq, 0, sizeof(mreq)); -+ mreq.mr_ifindex = ifindex; -+ mreq.mr_type = PACKET_MR_MULTICAST; -+ mreq.mr_alen = ETH_ALEN; -+ os_memcpy(mreq.mr_address, addr, ETH_ALEN); -+ -+ if (setsockopt(sock, SOL_PACKET, -+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP, -+ &mreq, sizeof(mreq)) < 0) { -+ perror("setsockopt"); -+ return -1; -+ } -+ return 0; -+#else /* __linux__ */ -+ return -1; -+#endif /* __linux__ */ -+} -+ -+ -+#ifdef __linux__ -+static void handle_data(void *ctx, unsigned char *buf, size_t len) -+{ -+#ifdef HOSTAPD -+ struct ieee8023_hdr *hdr; -+ u8 *pos, *sa; -+ size_t left; -+ union wpa_event_data event; -+ -+ /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest, -+ * 2 byte ethertype */ -+ if (len < 14) { -+ wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)", -+ (unsigned long) len); -+ return; -+ } -+ -+ hdr = (struct ieee8023_hdr *) buf; -+ -+ switch (ntohs(hdr->ethertype)) { -+ case ETH_P_PAE: -+ wpa_printf(MSG_MSGDUMP, "Received EAPOL packet"); -+ sa = hdr->src; -+ os_memset(&event, 0, sizeof(event)); -+ event.new_sta.addr = sa; -+ wpa_supplicant_event(ctx, EVENT_NEW_STA, &event); -+ -+ pos = (u8 *) (hdr + 1); -+ left = len - sizeof(*hdr); -+ drv_event_eapol_rx(ctx, sa, pos, left); -+ break; -+ -+ default: -+ wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame", -+ ntohs(hdr->ethertype)); -+ break; -+ } -+#endif /* HOSTAPD */ -+} -+ -+ -+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ int len; -+ unsigned char buf[3000]; -+ -+ len = recv(sock, buf, sizeof(buf), 0); -+ if (len < 0) { -+ perror("recv"); -+ return; -+ } -+ -+ handle_data(eloop_ctx, buf, len); -+} -+ -+ -+static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ int len; -+ unsigned char buf[3000]; -+ struct dhcp_message *msg; -+ u8 *mac_address; -+ union wpa_event_data event; -+ -+ len = recv(sock, buf, sizeof(buf), 0); -+ if (len < 0) { -+ perror("recv"); -+ return; -+ } -+ -+ /* must contain at least dhcp_message->chaddr */ -+ if (len < 44) { -+ wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len); -+ return; -+ } -+ -+ msg = (struct dhcp_message *) buf; -+ mac_address = (u8 *) &(msg->chaddr); -+ -+ wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR, -+ MAC2STR(mac_address)); -+ -+ os_memset(&event, 0, sizeof(event)); -+ event.new_sta.addr = mac_address; -+ wpa_supplicant_event(eloop_ctx, EVENT_NEW_STA, &event); -+} -+#endif /* __linux__ */ -+ -+ -+static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) -+{ -+#ifdef __linux__ -+ struct ifreq ifr; -+ struct sockaddr_ll addr; -+ struct sockaddr_in addr2; -+ int n = 1; -+ -+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE)); -+ if (drv->sock < 0) { -+ perror("socket[PF_PACKET,SOCK_RAW]"); -+ return -1; -+ } -+ -+ if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) { -+ printf("Could not register read socket\n"); -+ return -1; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); -+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { -+ perror("ioctl(SIOCGIFINDEX)"); -+ return -1; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sll_family = AF_PACKET; -+ addr.sll_ifindex = ifr.ifr_ifindex; -+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d", -+ addr.sll_ifindex); -+ -+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind"); -+ return -1; -+ } -+ -+ /* filter multicast address */ -+ if (wired_multicast_membership(drv->sock, ifr.ifr_ifindex, -+ pae_group_addr, 1) < 0) { -+ wpa_printf(MSG_ERROR, "wired: Failed to add multicast group " -+ "membership"); -+ return -1; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); -+ if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { -+ perror("ioctl(SIOCGIFHWADDR)"); -+ return -1; -+ } -+ -+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { -+ printf("Invalid HW-addr family 0x%04x\n", -+ ifr.ifr_hwaddr.sa_family); -+ return -1; -+ } -+ os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); -+ -+ /* setup dhcp listen socket for sta detection */ -+ if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { -+ perror("socket call failed for dhcp"); -+ return -1; -+ } -+ -+ if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx, -+ NULL)) { -+ printf("Could not register read socket\n"); -+ return -1; -+ } -+ -+ os_memset(&addr2, 0, sizeof(addr2)); -+ addr2.sin_family = AF_INET; -+ addr2.sin_port = htons(67); -+ addr2.sin_addr.s_addr = INADDR_ANY; -+ -+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n, -+ sizeof(n)) == -1) { -+ perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]"); -+ return -1; -+ } -+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n, -+ sizeof(n)) == -1) { -+ perror("setsockopt[SOL_SOCKET,SO_BROADCAST]"); -+ return -1; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ); -+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE, -+ (char *) &ifr, sizeof(ifr)) < 0) { -+ perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]"); -+ return -1; -+ } -+ -+ if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2, -+ sizeof(struct sockaddr)) == -1) { -+ perror("bind"); -+ return -1; -+ } -+ -+ return 0; -+#else /* __linux__ */ -+ return -1; -+#endif /* __linux__ */ -+} -+ -+ -+static int wired_send_eapol(void *priv, const u8 *addr, -+ const u8 *data, size_t data_len, int encrypt, -+ const u8 *own_addr, u32 flags) -+{ -+ struct wpa_driver_wired_data *drv = priv; -+ struct ieee8023_hdr *hdr; -+ size_t len; -+ u8 *pos; -+ int res; -+ -+ len = sizeof(*hdr) + data_len; -+ hdr = os_zalloc(len); -+ if (hdr == NULL) { -+ printf("malloc() failed for wired_send_eapol(len=%lu)\n", -+ (unsigned long) len); -+ return -1; -+ } -+ -+ os_memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr, -+ ETH_ALEN); -+ os_memcpy(hdr->src, own_addr, ETH_ALEN); -+ hdr->ethertype = htons(ETH_P_PAE); -+ -+ pos = (u8 *) (hdr + 1); -+ os_memcpy(pos, data, data_len); -+ -+ res = send(drv->sock, (u8 *) hdr, len, 0); -+ os_free(hdr); -+ -+ if (res < 0) { -+ perror("wired_send_eapol: send"); -+ printf("wired_send_eapol - packet len: %lu - failed\n", -+ (unsigned long) len); -+ } -+ -+ return res; -+} -+ -+ -+static void * wired_driver_hapd_init(struct hostapd_data *hapd, -+ struct wpa_init_params *params) -+{ -+ struct wpa_driver_wired_data *drv; -+ -+ drv = os_zalloc(sizeof(struct wpa_driver_wired_data)); -+ if (drv == NULL) { -+ printf("Could not allocate memory for wired driver data\n"); -+ return NULL; -+ } -+ -+ drv->ctx = hapd; -+ os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); -+ drv->use_pae_group_addr = params->use_pae_group_addr; -+ -+ if (wired_init_sockets(drv, params->own_addr)) { -+ os_free(drv); -+ return NULL; -+ } -+ -+ return drv; -+} -+ -+ -+static void wired_driver_hapd_deinit(void *priv) -+{ -+ struct wpa_driver_wired_data *drv = priv; -+ -+ if (drv->sock >= 0) -+ close(drv->sock); -+ -+ if (drv->dhcp_sock >= 0) -+ close(drv->dhcp_sock); -+ -+ os_free(drv); -+} -+ -+ -+static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid) -+{ -+ ssid[0] = 0; -+ return 0; -+} -+ -+ -+static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid) -+{ -+ /* Report PAE group address as the "BSSID" for wired connection. */ -+ os_memcpy(bssid, pae_group_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+static int wpa_driver_wired_get_capa(void *priv, struct wpa_driver_capa *capa) -+{ -+ os_memset(capa, 0, sizeof(*capa)); -+ capa->flags = WPA_DRIVER_FLAGS_WIRED; -+ return 0; -+} -+ -+ -+static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags) -+{ -+ struct ifreq ifr; -+ int s; -+ -+ s = socket(PF_INET, SOCK_DGRAM, 0); -+ if (s < 0) { -+ perror("socket"); -+ return -1; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { -+ perror("ioctl[SIOCGIFFLAGS]"); -+ close(s); -+ return -1; -+ } -+ close(s); -+ *flags = ifr.ifr_flags & 0xffff; -+ return 0; -+} -+ -+ -+static int wpa_driver_wired_set_ifflags(const char *ifname, int flags) -+{ -+ struct ifreq ifr; -+ int s; -+ -+ s = socket(PF_INET, SOCK_DGRAM, 0); -+ if (s < 0) { -+ perror("socket"); -+ return -1; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ ifr.ifr_flags = flags & 0xffff; -+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { -+ perror("ioctl[SIOCSIFFLAGS]"); -+ close(s); -+ return -1; -+ } -+ close(s); -+ return 0; -+} -+ -+ -+static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add) -+{ -+ struct ifreq ifr; -+ int s; -+ -+#ifdef __sun__ -+ return -1; -+#endif /* __sun__ */ -+ -+ s = socket(PF_INET, SOCK_DGRAM, 0); -+ if (s < 0) { -+ perror("socket"); -+ return -1; -+ } -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+#ifdef __linux__ -+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC; -+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); -+#endif /* __linux__ */ -+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) -+ { -+ struct sockaddr_dl *dlp; -+ dlp = (struct sockaddr_dl *) &ifr.ifr_addr; -+ dlp->sdl_len = sizeof(struct sockaddr_dl); -+ dlp->sdl_family = AF_LINK; -+ dlp->sdl_index = 0; -+ dlp->sdl_nlen = 0; -+ dlp->sdl_alen = ETH_ALEN; -+ dlp->sdl_slen = 0; -+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN); -+ } -+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) || defined(FreeBSD_kernel__) */ -+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) -+ { -+ struct sockaddr *sap; -+ sap = (struct sockaddr *) &ifr.ifr_addr; -+ sap->sa_len = sizeof(struct sockaddr); -+ sap->sa_family = AF_UNSPEC; -+ os_memcpy(sap->sa_data, addr, ETH_ALEN); -+ } -+#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */ -+ -+ if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) { -+ perror("ioctl[SIOC{ADD/DEL}MULTI]"); -+ close(s); -+ return -1; -+ } -+ close(s); -+ return 0; -+} -+ -+ -+static void * wpa_driver_wired_init(void *ctx, const char *ifname) -+{ -+ struct wpa_driver_wired_data *drv; -+ int flags; -+ -+ drv = os_zalloc(sizeof(*drv)); -+ if (drv == NULL) -+ return NULL; -+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); -+ drv->ctx = ctx; -+ -+#ifdef __linux__ -+ drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0); -+ if (drv->pf_sock < 0) -+ perror("socket(PF_PACKET)"); -+#else /* __linux__ */ -+ drv->pf_sock = -1; -+#endif /* __linux__ */ -+ -+ if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 && -+ !(flags & IFF_UP) && -+ wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) { -+ drv->iff_up = 1; -+ } -+ -+ if (wired_multicast_membership(drv->pf_sock, -+ if_nametoindex(drv->ifname), -+ pae_group_addr, 1) == 0) { -+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " -+ "packet socket", __func__); -+ drv->membership = 1; -+ } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) { -+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with " -+ "SIOCADDMULTI", __func__); -+ drv->multi = 1; -+ } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) { -+ wpa_printf(MSG_INFO, "%s: Could not get interface " -+ "flags", __func__); -+ os_free(drv); -+ return NULL; -+ } else if (flags & IFF_ALLMULTI) { -+ wpa_printf(MSG_DEBUG, "%s: Interface is already configured " -+ "for multicast", __func__); -+ } else if (wpa_driver_wired_set_ifflags(ifname, -+ flags | IFF_ALLMULTI) < 0) { -+ wpa_printf(MSG_INFO, "%s: Failed to enable allmulti", -+ __func__); -+ os_free(drv); -+ return NULL; -+ } else { -+ wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode", -+ __func__); -+ drv->iff_allmulti = 1; -+ } -+ -+ return drv; -+} -+ -+ -+static void wpa_driver_wired_deinit(void *priv) -+{ -+ struct wpa_driver_wired_data *drv = priv; -+ int flags; -+ -+ if (drv->membership && -+ wired_multicast_membership(drv->pf_sock, -+ if_nametoindex(drv->ifname), -+ pae_group_addr, 0) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " -+ "group (PACKET)", __func__); -+ } -+ -+ if (drv->multi && -+ wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast " -+ "group (SIOCDELMULTI)", __func__); -+ } -+ -+ if (drv->iff_allmulti && -+ (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 || -+ wpa_driver_wired_set_ifflags(drv->ifname, -+ flags & ~IFF_ALLMULTI) < 0)) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode", -+ __func__); -+ } -+ -+ if (drv->iff_up && -+ wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 && -+ (flags & IFF_UP) && -+ wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) { -+ wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down", -+ __func__); -+ } -+ -+ if (drv->pf_sock != -1) -+ close(drv->pf_sock); -+ -+ os_free(drv); -+} -+ -+ -+const struct wpa_driver_ops wpa_driver_wired_ops = { -+ .name = "wired", -+ .desc = "Wired Ethernet driver", -+ .hapd_init = wired_driver_hapd_init, -+ .hapd_deinit = wired_driver_hapd_deinit, -+ .hapd_send_eapol = wired_send_eapol, -+ .get_ssid = wpa_driver_wired_get_ssid, -+ .get_bssid = wpa_driver_wired_get_bssid, -+ .get_capa = wpa_driver_wired_get_capa, -+ .init = wpa_driver_wired_init, -+ .deinit = wpa_driver_wired_deinit, -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.c -new file mode 100644 -index 0000000000000..2d29452f44216 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.c -@@ -0,0 +1,120 @@ -+/* -+ * Driver interface list -+ * Copyright (c) 2004-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+ -+#ifdef CONFIG_DRIVER_WEXT -+extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */ -+#endif /* CONFIG_DRIVER_WEXT */ -+#ifdef CONFIG_DRIVER_NL80211 -+extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */ -+#endif /* CONFIG_DRIVER_NL80211 */ -+#ifdef CONFIG_DRIVER_HOSTAP -+extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */ -+#endif /* CONFIG_DRIVER_HOSTAP */ -+#ifdef CONFIG_DRIVER_MADWIFI -+extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */ -+#endif /* CONFIG_DRIVER_MADWIFI */ -+#ifdef CONFIG_DRIVER_BROADCOM -+extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */ -+#endif /* CONFIG_DRIVER_BROADCOM */ -+#ifdef CONFIG_DRIVER_BSD -+extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */ -+#endif /* CONFIG_DRIVER_BSD */ -+#ifdef CONFIG_DRIVER_NDIS -+extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */ -+#endif /* CONFIG_DRIVER_NDIS */ -+#ifdef CONFIG_DRIVER_WIRED -+extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */ -+#endif /* CONFIG_DRIVER_WIRED */ -+#ifdef CONFIG_DRIVER_TEST -+extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */ -+#endif /* CONFIG_DRIVER_TEST */ -+#ifdef CONFIG_DRIVER_RALINK -+extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */ -+#endif /* CONFIG_DRIVER_RALINK */ -+#ifdef CONFIG_DRIVER_OSX -+extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */ -+#endif /* CONFIG_DRIVER_OSX */ -+#ifdef CONFIG_DRIVER_IPHONE -+extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */ -+#endif /* CONFIG_DRIVER_IPHONE */ -+#ifdef CONFIG_DRIVER_ROBOSWITCH -+/* driver_roboswitch.c */ -+extern struct wpa_driver_ops wpa_driver_roboswitch_ops; -+#endif /* CONFIG_DRIVER_ROBOSWITCH */ -+#ifdef CONFIG_DRIVER_ATHEROS -+extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */ -+#endif /* CONFIG_DRIVER_ATHEROS */ -+#ifdef CONFIG_DRIVER_NONE -+extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ -+#endif /* CONFIG_DRIVER_NONE */ -+#ifdef CONFIG_DRIVER_RTW -+extern struct wpa_driver_ops wpa_driver_rtw_ops; /* driver_rtw.c */ -+#endif /* CONFIG_DRIVER_RTW */ -+ -+ -+struct wpa_driver_ops *wpa_drivers[] = -+{ -+#ifdef CONFIG_DRIVER_WEXT -+ &wpa_driver_wext_ops, -+#endif /* CONFIG_DRIVER_WEXT */ -+#ifdef CONFIG_DRIVER_NL80211 -+ &wpa_driver_nl80211_ops, -+#endif /* CONFIG_DRIVER_NL80211 */ -+#ifdef CONFIG_DRIVER_HOSTAP -+ &wpa_driver_hostap_ops, -+#endif /* CONFIG_DRIVER_HOSTAP */ -+#ifdef CONFIG_DRIVER_MADWIFI -+ &wpa_driver_madwifi_ops, -+#endif /* CONFIG_DRIVER_MADWIFI */ -+#ifdef CONFIG_DRIVER_BROADCOM -+ &wpa_driver_broadcom_ops, -+#endif /* CONFIG_DRIVER_BROADCOM */ -+#ifdef CONFIG_DRIVER_BSD -+ &wpa_driver_bsd_ops, -+#endif /* CONFIG_DRIVER_BSD */ -+#ifdef CONFIG_DRIVER_NDIS -+ &wpa_driver_ndis_ops, -+#endif /* CONFIG_DRIVER_NDIS */ -+#ifdef CONFIG_DRIVER_WIRED -+ &wpa_driver_wired_ops, -+#endif /* CONFIG_DRIVER_WIRED */ -+#ifdef CONFIG_DRIVER_TEST -+ &wpa_driver_test_ops, -+#endif /* CONFIG_DRIVER_TEST */ -+#ifdef CONFIG_DRIVER_RALINK -+ &wpa_driver_ralink_ops, -+#endif /* CONFIG_DRIVER_RALINK */ -+#ifdef CONFIG_DRIVER_OSX -+ &wpa_driver_osx_ops, -+#endif /* CONFIG_DRIVER_OSX */ -+#ifdef CONFIG_DRIVER_IPHONE -+ &wpa_driver_iphone_ops, -+#endif /* CONFIG_DRIVER_IPHONE */ -+#ifdef CONFIG_DRIVER_ROBOSWITCH -+ &wpa_driver_roboswitch_ops, -+#endif /* CONFIG_DRIVER_ROBOSWITCH */ -+#ifdef CONFIG_DRIVER_ATHEROS -+ &wpa_driver_atheros_ops, -+#endif /* CONFIG_DRIVER_ATHEROS */ -+#ifdef CONFIG_DRIVER_NONE -+ &wpa_driver_none_ops, -+#endif /* CONFIG_DRIVER_NONE */ -+#ifdef CONFIG_DRIVER_RTW -+ &wpa_driver_rtw_ops, -+#endif /* CONFIG_DRIVER_RTW */ -+ NULL -+}; -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mak b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mak -new file mode 100644 -index 0000000000000..98d4079938bb0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mak -@@ -0,0 +1,191 @@ -+##### CLEAR VARS -+ -+DRV_CFLAGS = -+DRV_WPA_CFLAGS = -+DRV_AP_CFLAGS = -+DRV_OBJS = -+DRV_WPA_OBJS = -+DRV_AP_OBJS = -+DRV_LIBS = -+DRV_WPA_LIBS = -+DRV_AP_LIBS = -+ -+##### COMMON DRIVERS -+ -+ifdef CONFIG_DRIVER_HOSTAP -+DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP -+DRV_OBJS += ../src/drivers/driver_hostap.o -+CONFIG_WIRELESS_EXTENSION=y -+NEED_AP_MLME=y -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+ifdef CONFIG_DRIVER_WIRED -+DRV_CFLAGS += -DCONFIG_DRIVER_WIRED -+DRV_OBJS += ../src/drivers/driver_wired.o -+endif -+ -+ifdef CONFIG_DRIVER_MADWIFI -+DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI -+DRV_OBJS += ../src/drivers/driver_madwifi.o -+CONFIG_WIRELESS_EXTENSION=y -+CONFIG_L2_PACKET=linux -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+ifdef CONFIG_DRIVER_NL80211 -+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 -+DRV_OBJS += ../src/drivers/driver_nl80211.o -+DRV_OBJS += ../src/utils/radiotap.o -+NEED_SME=y -+NEED_AP_MLME=y -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+NEED_RFKILL=y -+ifdef CONFIG_LIBNL_TINY -+DRV_LIBS += -lnl-tiny -+else -+DRV_LIBS += -lnl -+endif -+ -+ifdef CONFIG_LIBNL20 -+DRV_LIBS += -lnl-genl -+DRV_CFLAGS += -DCONFIG_LIBNL20 -+endif -+endif -+ -+ifdef CONFIG_DRIVER_BSD -+ifndef CONFIG_L2_PACKET -+CONFIG_L2_PACKET=freebsd -+endif -+DRV_CFLAGS += -DCONFIG_DRIVER_BSD -+DRV_OBJS += ../src/drivers/driver_bsd.o -+CONFIG_L2_FREEBSD=y -+CONFIG_DNET_PCAP=y -+endif -+ -+ifdef CONFIG_DRIVER_TEST -+DRV_CFLAGS += -DCONFIG_DRIVER_TEST -+DRV_OBJS += ../src/drivers/driver_test.o -+NEED_AP_MLME=y -+endif -+ -+ifdef CONFIG_DRIVER_NONE -+DRV_CFLAGS += -DCONFIG_DRIVER_NONE -+DRV_OBJS += ../src/drivers/driver_none.o -+endif -+ -+##### PURE AP DRIVERS -+ -+ifdef CONFIG_DRIVER_ATHEROS -+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS -+DRV_AP_OBJS += ../src/drivers/driver_atheros.o -+CONFIG_L2_PACKET=linux -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+ifdef CONFIG_DRIVER_RTW -+#CFLAGS += -DCONFIG_DRIVER_RTL -+#OBJS += driver_rtl.o -+DRV_AP_CFLAGS += -DCONFIG_DRIVER_RTW -+DRV_AP_OBJS += ../src/drivers/driver_rtw.o -+CONFIG_L2_PACKET=linux -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+NEED_AP_MLME=y -+endif -+ -+##### PURE CLIENT DRIVERS -+ -+ifdef CONFIG_DRIVER_WEXT -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT -+CONFIG_WIRELESS_EXTENSION=y -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+NEED_RFKILL=y -+endif -+ -+ifdef CONFIG_DRIVER_RALINK -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK -+DRV_WPA_OBJS += ../src/drivers/driver_ralink.o -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+ifdef CONFIG_DRIVER_BROADCOM -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM -+DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o -+endif -+ -+ifdef CONFIG_DRIVER_NDIS -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS -+DRV_WPA_OBJS += ../src/drivers/driver_ndis.o -+ifdef CONFIG_NDIS_EVENTS_INTEGRATED -+DRV_WPA_OBJS += ../src/drivers/driver_ndis_.o -+endif -+ifndef CONFIG_L2_PACKET -+CONFIG_L2_PACKET=pcap -+endif -+CONFIG_WINPCAP=y -+ifdef CONFIG_USE_NDISUIO -+DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO -+endif -+endif -+ -+ifdef CONFIG_DRIVER_OSX -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX -+DRV_WPA_OBJS += ../src/drivers/driver_osx.o -+DRV_WPA_LDFLAGS += -framework CoreFoundation -+DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 -+endif -+ -+ifdef CONFIG_DRIVER_IPHONE -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE -+DRV_WPA_OBJS += ../src/drivers/driver_iphone.o -+DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o -+DRV_WPA_LDFLAGS += -framework CoreFoundation -+endif -+ -+ifdef CONFIG_DRIVER_ROBOSWITCH -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH -+DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o -+endif -+ -+ifdef CONFIG_WIRELESS_EXTENSION -+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION -+DRV_WPA_OBJS += ../src/drivers/driver_wext.o -+NEED_RFKILL=y -+endif -+ -+ifdef NEED_NETLINK -+DRV_OBJS += ../src/drivers/netlink.o -+endif -+ -+ifdef NEED_LINUX_IOCTL -+DRV_OBJS += ../src/drivers/linux_ioctl.o -+endif -+ -+ifdef NEED_RFKILL -+DRV_OBJS += ../src/drivers/rfkill.o -+endif -+ -+ -+##### COMMON VARS -+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS) -+DRV_WPA_CFLAGS += $(DRV_CFLAGS) -+DRV_AP_CFLAGS += $(DRV_CFLAGS) -+ -+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS) -+DRV_WPA_LIBS += $(DRV_LIBS) -+DRV_AP_LIBS += $(DRV_LIBS) -+ -+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS) -+DRV_WPA_OBJS += $(DRV_OBJS) -+DRV_AP_OBJS += $(DRV_OBJS) -+ -+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS) -+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS) -+DRV_AP_LDFLAGS += $(DRV_LDFLAGS) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mk b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mk -new file mode 100644 -index 0000000000000..c690e1cc201f2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/drivers.mk -@@ -0,0 +1,183 @@ -+##### CLEAR VARS -+ -+DRV_CFLAGS = -+DRV_WPA_CFLAGS = -+DRV_AP_CFLAGS = -+DRV_OBJS = -+DRV_WPA_OBJS = -+DRV_AP_OBJS = -+DRV_LIBS = -+DRV_WPA_LIBS = -+DRV_AP_LIBS = -+ -+##### COMMON DRIVERS -+ -+ifdef CONFIG_DRIVER_HOSTAP -+DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP -+DRV_OBJS += src/drivers/driver_hostap.c -+CONFIG_WIRELESS_EXTENSION=y -+NEED_AP_MLME=y -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+ifdef CONFIG_DRIVER_WIRED -+DRV_CFLAGS += -DCONFIG_DRIVER_WIRED -+DRV_OBJS += src/drivers/driver_wired.c -+endif -+ -+ifdef CONFIG_DRIVER_MADWIFI -+DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI -+DRV_OBJS += src/drivers/driver_madwifi.c -+CONFIG_WIRELESS_EXTENSION=y -+CONFIG_L2_PACKET=linux -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+ifdef CONFIG_DRIVER_NL80211 -+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211 -+DRV_OBJS += src/drivers/driver_nl80211.c -+DRV_OBJS += src/utils/radiotap.c -+NEED_SME=y -+NEED_AP_MLME=y -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+NEED_RFKILL=y -+ifdef CONFIG_LIBNL_TINY -+DRV_LIBS += -lnl-tiny -+else -+DRV_LIBS += -lnl -+endif -+ -+ifdef CONFIG_LIBNL20 -+DRV_LIBS += -lnl-genl -+DRV_CFLAGS += -DCONFIG_LIBNL20 -+endif -+endif -+ -+ifdef CONFIG_DRIVER_BSD -+ifndef CONFIG_L2_PACKET -+CONFIG_L2_PACKET=freebsd -+endif -+DRV_CFLAGS += -DCONFIG_DRIVER_BSD -+DRV_OBJS += src/drivers/driver_bsd.c -+CONFIG_L2_FREEBSD=y -+CONFIG_DNET_PCAP=y -+endif -+ -+ifdef CONFIG_DRIVER_TEST -+DRV_CFLAGS += -DCONFIG_DRIVER_TEST -+DRV_OBJS += src/drivers/driver_test.c -+NEED_AP_MLME=y -+endif -+ -+ifdef CONFIG_DRIVER_NONE -+DRV_CFLAGS += -DCONFIG_DRIVER_NONE -+DRV_OBJS += src/drivers/driver_none.c -+endif -+ -+##### PURE AP DRIVERS -+ -+ifdef CONFIG_DRIVER_ATHEROS -+DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS -+DRV_AP_OBJS += src/drivers/driver_atheros.c -+CONFIG_L2_PACKET=linux -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+##### PURE CLIENT DRIVERS -+ -+ifdef CONFIG_DRIVER_WEXT -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_WEXT -+CONFIG_WIRELESS_EXTENSION=y -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+NEED_RFKILL=y -+endif -+ -+ifdef CONFIG_DRIVER_RALINK -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK -+DRV_WPA_OBJS += src/drivers/driver_ralink.c -+NEED_NETLINK=y -+NEED_LINUX_IOCTL=y -+endif -+ -+ifdef CONFIG_DRIVER_BROADCOM -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM -+DRV_WPA_OBJS += src/drivers/driver_broadcom.c -+endif -+ -+ifdef CONFIG_DRIVER_NDIS -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS -+DRV_WPA_OBJS += src/drivers/driver_ndis.c -+ifdef CONFIG_NDIS_EVENTS_INTEGRATED -+DRV_WPA_OBJS += src/drivers/driver_ndis_.c -+endif -+ifndef CONFIG_L2_PACKET -+CONFIG_L2_PACKET=pcap -+endif -+CONFIG_WINPCAP=y -+ifdef CONFIG_USE_NDISUIO -+DRV_WPA_CFLAGS += -DCONFIG_USE_NDISUIO -+endif -+endif -+ -+ifdef CONFIG_DRIVER_OSX -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX -+DRV_WPA_OBJS += src/drivers/driver_osx.c -+DRV_WPA_LDFLAGS += -framework CoreFoundation -+DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211 -+endif -+ -+ifdef CONFIG_DRIVER_IPHONE -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE -+DRV_WPA_OBJS += src/drivers/driver_iphone.c -+DRV_WPA_OBJS += src/drivers/MobileApple80211.c -+DRV_WPA_LDFLAGS += -framework CoreFoundation -+endif -+ -+ifdef CONFIG_DRIVER_ROBOSWITCH -+DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH -+DRV_WPA_OBJS += src/drivers/driver_roboswitch.c -+endif -+ -+ifdef CONFIG_WIRELESS_EXTENSION -+DRV_WPA_CFLAGS += -DCONFIG_WIRELESS_EXTENSION -+DRV_WPA_OBJS += src/drivers/driver_wext.c -+NEED_RFKILL=y -+endif -+ -+ifdef NEED_NETLINK -+DRV_OBJS += src/drivers/netlink.c -+endif -+ -+ifdef NEED_LINUX_IOCTL -+DRV_OBJS += src/drivers/linux_ioctl.c -+endif -+ -+ifdef NEED_RFKILL -+DRV_OBJS += src/drivers/rfkill.c -+endif -+ -+ifdef CONFIG_DRIVER_CUSTOM -+DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM -+endif -+ -+##### COMMON VARS -+DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS) -+DRV_WPA_CFLAGS += $(DRV_CFLAGS) -+DRV_AP_CFLAGS += $(DRV_CFLAGS) -+ -+DRV_BOTH_LIBS := $(DRV_LIBS) $(DRV_WPA_LIBS) $(DRV_AP_LIBS) -+DRV_WPA_LIBS += $(DRV_LIBS) -+DRV_AP_LIBS += $(DRV_LIBS) -+ -+DRV_BOTH_OBJS := $(DRV_OBJS) $(DRV_WPA_OBJS) $(DRV_AP_OBJS) -+DRV_WPA_OBJS += $(DRV_OBJS) -+DRV_AP_OBJS += $(DRV_OBJS) -+ -+DRV_BOTH_LDFLAGS := $(DRV_LDFLAGS) $(DRV_WPA_LDFLAGS) $(DRV_AP_LDFLAGS) -+DRV_WPA_LDFLAGS += $(DRV_LDFLAGS) -+DRV_AP_LDFLAGS += $(DRV_LDFLAGS) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.c -new file mode 100644 -index 0000000000000..0d6cf5416beec ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.c -@@ -0,0 +1,198 @@ -+/* -+ * Linux ioctl helper functions for driver wrappers -+ * Copyright (c) 2002-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+#include -+#include -+#include -+ -+#include "utils/common.h" -+#include "linux_ioctl.h" -+ -+ -+int linux_set_iface_flags(int sock, const char *ifname, int dev_up) -+{ -+ struct ifreq ifr; -+ -+ if (sock < 0) -+ return -1; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ -+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { -+ wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", -+ ifname, strerror(errno)); -+ return -1; -+ } -+ -+ if (dev_up) { -+ if (ifr.ifr_flags & IFF_UP) -+ return 0; -+ ifr.ifr_flags |= IFF_UP; -+ } else { -+ if (!(ifr.ifr_flags & IFF_UP)) -+ return 0; -+ ifr.ifr_flags &= ~IFF_UP; -+ } -+ -+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) { -+ wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s", -+ ifname, strerror(errno)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr) -+{ -+ struct ifreq ifr; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ if (ioctl(sock, SIOCGIFHWADDR, &ifr)) { -+ wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s", -+ ifname, strerror(errno)); -+ return -1; -+ } -+ -+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { -+ wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x", -+ ifname, ifr.ifr_hwaddr.sa_family); -+ return -1; -+ } -+ os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); -+ -+ return 0; -+} -+ -+ -+int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr) -+{ -+ struct ifreq ifr; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); -+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); -+ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; -+ -+ if (ioctl(sock, SIOCSIFHWADDR, &ifr)) { -+ wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s", -+ ifname, strerror(errno)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+#ifndef SIOCBRADDBR -+#define SIOCBRADDBR 0x89a0 -+#endif -+#ifndef SIOCBRDELBR -+#define SIOCBRDELBR 0x89a1 -+#endif -+#ifndef SIOCBRADDIF -+#define SIOCBRADDIF 0x89a2 -+#endif -+#ifndef SIOCBRDELIF -+#define SIOCBRDELIF 0x89a3 -+#endif -+ -+ -+int linux_br_add(int sock, const char *brname) -+{ -+ if (ioctl(sock, SIOCBRADDBR, brname) < 0) { -+ wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s", -+ brname, strerror(errno)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int linux_br_del(int sock, const char *brname) -+{ -+ if (ioctl(sock, SIOCBRDELBR, brname) < 0) { -+ wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s", -+ brname, strerror(errno)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int linux_br_add_if(int sock, const char *brname, const char *ifname) -+{ -+ struct ifreq ifr; -+ int ifindex; -+ -+ ifindex = if_nametoindex(ifname); -+ if (ifindex == 0) -+ return -1; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); -+ ifr.ifr_ifindex = ifindex; -+ if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) { -+ wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge " -+ "%s: %s", ifname, brname, strerror(errno)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int linux_br_del_if(int sock, const char *brname, const char *ifname) -+{ -+ struct ifreq ifr; -+ int ifindex; -+ -+ ifindex = if_nametoindex(ifname); -+ if (ifindex == 0) -+ return -1; -+ -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); -+ ifr.ifr_ifindex = ifindex; -+ if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) { -+ wpa_printf(MSG_DEBUG, "Could not remove interface %s from " -+ "bridge %s: %s", ifname, brname, strerror(errno)); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int linux_br_get(char *brname, const char *ifname) -+{ -+ char path[128], brlink[128], *pos; -+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge", -+ ifname); -+ os_memset(brlink, 0, sizeof(brlink)); -+ if (readlink(path, brlink, sizeof(brlink) - 1) < 0) -+ return -1; -+ pos = os_strrchr(brlink, '/'); -+ if (pos == NULL) -+ return -1; -+ pos++; -+ os_strlcpy(brname, pos, IFNAMSIZ); -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.h -new file mode 100644 -index 0000000000000..a5557383d8fe1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/linux_ioctl.h -@@ -0,0 +1,27 @@ -+/* -+ * Linux ioctl helper functions for driver wrappers -+ * Copyright (c) 2002-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef LINUX_IOCTL_H -+#define LINUX_IOCTL_H -+ -+int linux_set_iface_flags(int sock, const char *ifname, int dev_up); -+int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr); -+int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr); -+int linux_br_add(int sock, const char *brname); -+int linux_br_del(int sock, const char *brname); -+int linux_br_add_if(int sock, const char *brname, const char *ifname); -+int linux_br_del_if(int sock, const char *brname, const char *ifname); -+int linux_br_get(char *brname, const char *ifname); -+ -+#endif /* LINUX_IOCTL_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/ndis_events.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/ndis_events.c -new file mode 100644 -index 0000000000000..f6eaa7c9f7ee2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/ndis_events.c -@@ -0,0 +1,808 @@ -+/* -+ * ndis_events - Receive NdisMIndicateStatus() events using WMI -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#define _WIN32_WINNT 0x0400 -+ -+#include "includes.h" -+ -+#ifndef COBJMACROS -+#define COBJMACROS -+#endif /* COBJMACROS */ -+#include -+ -+#include "common.h" -+ -+ -+static int wmi_refcnt = 0; -+static int wmi_first = 1; -+ -+struct ndis_events_data { -+ IWbemObjectSink sink; -+ IWbemObjectSinkVtbl sink_vtbl; -+ -+ IWbemServices *pSvc; -+ IWbemLocator *pLoc; -+ -+ HANDLE read_pipe, write_pipe, event_avail; -+ UINT ref; -+ int terminating; -+ char *ifname; /* {GUID..} */ -+ WCHAR *adapter_desc; -+}; -+ -+#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL -+#define BstrFree(x) if (x) SysFreeString(x) -+ -+/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to -+ * BSTRs */ -+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery( -+ IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery, -+ long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum) -+{ -+ BSTR bsQueryLanguage, bsQuery; -+ HRESULT hr; -+ -+ bsQueryLanguage = BstrAlloc(strQueryLanguage); -+ bsQuery = BstrAlloc(strQuery); -+ -+ hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags, -+ pCtx, ppEnum); -+ -+ BstrFree(bsQueryLanguage); -+ BstrFree(bsQuery); -+ -+ return hr; -+} -+ -+ -+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync( -+ IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery, -+ long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler) -+{ -+ BSTR bsQueryLanguage, bsQuery; -+ HRESULT hr; -+ -+ bsQueryLanguage = BstrAlloc(strQueryLanguage); -+ bsQuery = BstrAlloc(strQuery); -+ -+ hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage, -+ bsQuery, lFlags, pCtx, -+ pResponseHandler); -+ -+ BstrFree(bsQueryLanguage); -+ BstrFree(bsQuery); -+ -+ return hr; -+} -+ -+ -+HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer( -+ IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser, -+ LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags, -+ LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace) -+{ -+ BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority; -+ HRESULT hr; -+ -+ bsNetworkResource = BstrAlloc(strNetworkResource); -+ bsUser = BstrAlloc(strUser); -+ bsPassword = BstrAlloc(strPassword); -+ bsLocale = BstrAlloc(strLocale); -+ bsAuthority = BstrAlloc(strAuthority); -+ -+ hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser, -+ bsPassword, bsLocale, lSecurityFlags, -+ bsAuthority, pCtx, ppNamespace); -+ -+ BstrFree(bsNetworkResource); -+ BstrFree(bsUser); -+ BstrFree(bsPassword); -+ BstrFree(bsLocale); -+ BstrFree(bsAuthority); -+ -+ return hr; -+} -+ -+ -+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC, -+ EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL }; -+ -+static int ndis_events_get_adapter(struct ndis_events_data *events, -+ const char *ifname, const char *desc); -+ -+ -+static int ndis_events_constructor(struct ndis_events_data *events) -+{ -+ events->ref = 1; -+ -+ if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) { -+ wpa_printf(MSG_ERROR, "CreatePipe() failed: %d", -+ (int) GetLastError()); -+ return -1; -+ } -+ events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL); -+ if (events->event_avail == NULL) { -+ wpa_printf(MSG_ERROR, "CreateEvent() failed: %d", -+ (int) GetLastError()); -+ CloseHandle(events->read_pipe); -+ CloseHandle(events->write_pipe); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void ndis_events_destructor(struct ndis_events_data *events) -+{ -+ CloseHandle(events->read_pipe); -+ CloseHandle(events->write_pipe); -+ CloseHandle(events->event_avail); -+ IWbemServices_Release(events->pSvc); -+ IWbemLocator_Release(events->pLoc); -+ if (--wmi_refcnt == 0) -+ CoUninitialize(); -+} -+ -+ -+static HRESULT STDMETHODCALLTYPE -+ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj) -+{ -+ *obj = NULL; -+ -+ if (IsEqualIID(riid, &IID_IUnknown) || -+ IsEqualIID(riid, &IID_IWbemObjectSink)) { -+ *obj = this; -+ IWbemObjectSink_AddRef(this); -+ return NOERROR; -+ } -+ -+ return E_NOINTERFACE; -+} -+ -+ -+static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this) -+{ -+ struct ndis_events_data *events = (struct ndis_events_data *) this; -+ return ++events->ref; -+} -+ -+ -+static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this) -+{ -+ struct ndis_events_data *events = (struct ndis_events_data *) this; -+ -+ if (--events->ref != 0) -+ return events->ref; -+ -+ ndis_events_destructor(events); -+ wpa_printf(MSG_DEBUG, "ndis_events: terminated"); -+ os_free(events->adapter_desc); -+ os_free(events->ifname); -+ os_free(events); -+ return 0; -+} -+ -+ -+static int ndis_events_send_event(struct ndis_events_data *events, -+ enum event_types type, -+ char *data, size_t data_len) -+{ -+ char buf[512], *pos, *end; -+ int _type; -+ DWORD written; -+ -+ end = buf + sizeof(buf); -+ _type = (int) type; -+ os_memcpy(buf, &_type, sizeof(_type)); -+ pos = buf + sizeof(_type); -+ -+ if (data) { -+ if (2 + data_len > (size_t) (end - pos)) { -+ wpa_printf(MSG_DEBUG, "Not enough room for send_event " -+ "data (%d)", data_len); -+ return -1; -+ } -+ *pos++ = data_len >> 8; -+ *pos++ = data_len & 0xff; -+ os_memcpy(pos, data, data_len); -+ pos += data_len; -+ } -+ -+ if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) { -+ SetEvent(events->event_avail); -+ return 0; -+ } -+ wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError()); -+ return -1; -+} -+ -+ -+static void ndis_events_media_connect(struct ndis_events_data *events) -+{ -+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect"); -+ ndis_events_send_event(events, EVENT_CONNECT, NULL, 0); -+} -+ -+ -+static void ndis_events_media_disconnect(struct ndis_events_data *events) -+{ -+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect"); -+ ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0); -+} -+ -+ -+static void ndis_events_media_specific(struct ndis_events_data *events, -+ IWbemClassObject *pObj) -+{ -+ VARIANT vt; -+ HRESULT hr; -+ LONG lower, upper, k; -+ UCHAR ch; -+ char *data, *pos; -+ size_t data_len; -+ -+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication"); -+ -+ /* This is the StatusBuffer from NdisMIndicateStatus() call */ -+ hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication", -+ 0, &vt, NULL, NULL); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_DEBUG, "Could not get " -+ "NdisStatusMediaSpecificIndication from " -+ "the object?!"); -+ return; -+ } -+ -+ SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower); -+ SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper); -+ data_len = upper - lower + 1; -+ data = os_malloc(data_len); -+ if (data == NULL) { -+ wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event " -+ "data"); -+ VariantClear(&vt); -+ return; -+ } -+ -+ pos = data; -+ for (k = lower; k <= upper; k++) { -+ SafeArrayGetElement(V_ARRAY(&vt), &k, &ch); -+ *pos++ = ch; -+ } -+ wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len); -+ -+ VariantClear(&vt); -+ -+ ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len); -+ -+ os_free(data); -+} -+ -+ -+static void ndis_events_adapter_arrival(struct ndis_events_data *events) -+{ -+ wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival"); -+ ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0); -+} -+ -+ -+static void ndis_events_adapter_removal(struct ndis_events_data *events) -+{ -+ wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval"); -+ ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0); -+} -+ -+ -+static HRESULT STDMETHODCALLTYPE -+ndis_events_indicate(IWbemObjectSink *this, long lObjectCount, -+ IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray) -+{ -+ struct ndis_events_data *events = (struct ndis_events_data *) this; -+ long i; -+ -+ if (events->terminating) { -+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore " -+ "indication - terminating"); -+ return WBEM_NO_ERROR; -+ } -+ /* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)", -+ lObjectCount); */ -+ -+ for (i = 0; i < lObjectCount; i++) { -+ IWbemClassObject *pObj = ppObjArray[i]; -+ HRESULT hr; -+ VARIANT vtClass, vt; -+ -+ hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL, -+ NULL); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_DEBUG, "Failed to get __CLASS from " -+ "event."); -+ break; -+ } -+ /* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */ -+ -+ hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL, -+ NULL); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_DEBUG, "Failed to get InstanceName " -+ "from event."); -+ VariantClear(&vtClass); -+ break; -+ } -+ -+ if (wcscmp(vtClass.bstrVal, -+ L"MSNdis_NotifyAdapterArrival") == 0) { -+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to " -+ "update adapter description since it may " -+ "have changed with new adapter instance"); -+ ndis_events_get_adapter(events, events->ifname, NULL); -+ } -+ -+ if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) { -+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore " -+ "indication for foreign adapter: " -+ "InstanceName: '%S' __CLASS: '%S'", -+ vt.bstrVal, vtClass.bstrVal); -+ VariantClear(&vtClass); -+ VariantClear(&vt); -+ continue; -+ } -+ VariantClear(&vt); -+ -+ if (wcscmp(vtClass.bstrVal, -+ L"MSNdis_StatusMediaSpecificIndication") == 0) { -+ ndis_events_media_specific(events, pObj); -+ } else if (wcscmp(vtClass.bstrVal, -+ L"MSNdis_StatusMediaConnect") == 0) { -+ ndis_events_media_connect(events); -+ } else if (wcscmp(vtClass.bstrVal, -+ L"MSNdis_StatusMediaDisconnect") == 0) { -+ ndis_events_media_disconnect(events); -+ } else if (wcscmp(vtClass.bstrVal, -+ L"MSNdis_NotifyAdapterArrival") == 0) { -+ ndis_events_adapter_arrival(events); -+ } else if (wcscmp(vtClass.bstrVal, -+ L"MSNdis_NotifyAdapterRemoval") == 0) { -+ ndis_events_adapter_removal(events); -+ } else { -+ wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: " -+ "'%S'", vtClass.bstrVal); -+ } -+ -+ VariantClear(&vtClass); -+ } -+ -+ return WBEM_NO_ERROR; -+} -+ -+ -+static HRESULT STDMETHODCALLTYPE -+ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult, -+ BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam) -+{ -+ return WBEM_NO_ERROR; -+} -+ -+ -+static int notification_query(IWbemObjectSink *pDestSink, -+ IWbemServices *pSvc, const char *class_name) -+{ -+ HRESULT hr; -+ WCHAR query[256]; -+ -+ _snwprintf(query, 256, -+ L"SELECT * FROM %S", class_name); -+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); -+ hr = call_IWbemServices_ExecNotificationQueryAsync( -+ pSvc, L"WQL", query, 0, 0, pDestSink); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s " -+ "failed with hresult of 0x%x", -+ class_name, (int) hr); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int register_async_notification(IWbemObjectSink *pDestSink, -+ IWbemServices *pSvc) -+{ -+ int i; -+ const char *class_list[] = { -+ "MSNdis_StatusMediaConnect", -+ "MSNdis_StatusMediaDisconnect", -+ "MSNdis_StatusMediaSpecificIndication", -+ "MSNdis_NotifyAdapterArrival", -+ "MSNdis_NotifyAdapterRemoval", -+ NULL -+ }; -+ -+ for (i = 0; class_list[i]; i++) { -+ if (notification_query(pDestSink, pSvc, class_list[i]) < 0) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void ndis_events_deinit(struct ndis_events_data *events) -+{ -+ events->terminating = 1; -+ IWbemServices_CancelAsyncCall(events->pSvc, &events->sink); -+ IWbemObjectSink_Release(&events->sink); -+ /* -+ * Rest of deinitialization is done in ndis_events_destructor() once -+ * all reference count drops to zero. -+ */ -+} -+ -+ -+static int ndis_events_use_desc(struct ndis_events_data *events, -+ const char *desc) -+{ -+ char *tmp, *pos; -+ size_t len; -+ -+ if (desc == NULL) { -+ if (events->adapter_desc == NULL) -+ return -1; -+ /* Continue using old description */ -+ return 0; -+ } -+ -+ tmp = os_strdup(desc); -+ if (tmp == NULL) -+ return -1; -+ -+ pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)"); -+ if (pos) -+ *pos = '\0'; -+ -+ len = os_strlen(tmp); -+ events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR)); -+ if (events->adapter_desc == NULL) { -+ os_free(tmp); -+ return -1; -+ } -+ _snwprintf(events->adapter_desc, len + 1, L"%S", tmp); -+ os_free(tmp); -+ return 0; -+} -+ -+ -+static int ndis_events_get_adapter(struct ndis_events_data *events, -+ const char *ifname, const char *desc) -+{ -+ HRESULT hr; -+ IWbemServices *pSvc; -+#define MAX_QUERY_LEN 256 -+ WCHAR query[MAX_QUERY_LEN]; -+ IEnumWbemClassObject *pEnumerator; -+ IWbemClassObject *pObj; -+ ULONG uReturned; -+ VARIANT vt; -+ int len, pos; -+ -+ /* -+ * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter -+ * to have better probability of matching with InstanceName from -+ * MSNdis events. If this fails, use the provided description. -+ */ -+ -+ os_free(events->adapter_desc); -+ events->adapter_desc = NULL; -+ -+ hr = call_IWbemLocator_ConnectServer( -+ events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI " -+ "server (ROOT\\CIMV2) - error 0x%x", (int) hr); -+ return ndis_events_use_desc(events, desc); -+ } -+ wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2."); -+ -+ _snwprintf(query, MAX_QUERY_LEN, -+ L"SELECT Index FROM Win32_NetworkAdapterConfiguration " -+ L"WHERE SettingID='%S'", ifname); -+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); -+ -+ hr = call_IWbemServices_ExecQuery( -+ pSvc, L"WQL", query, -+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, -+ NULL, &pEnumerator); -+ if (!SUCCEEDED(hr)) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface " -+ "GUID from Win32_NetworkAdapterConfiguration: " -+ "0x%x", (int) hr); -+ IWbemServices_Release(pSvc); -+ return ndis_events_use_desc(events, desc); -+ } -+ -+ uReturned = 0; -+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, -+ &pObj, &uReturned); -+ if (!SUCCEEDED(hr) || uReturned == 0) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface " -+ "GUID from Win32_NetworkAdapterConfiguration: " -+ "0x%x", (int) hr); -+ IEnumWbemClassObject_Release(pEnumerator); -+ IWbemServices_Release(pSvc); -+ return ndis_events_use_desc(events, desc); -+ } -+ IEnumWbemClassObject_Release(pEnumerator); -+ -+ VariantInit(&vt); -+ hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL); -+ if (!SUCCEEDED(hr)) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from " -+ "Win32_NetworkAdapterConfiguration: 0x%x", -+ (int) hr); -+ IWbemServices_Release(pSvc); -+ return ndis_events_use_desc(events, desc); -+ } -+ -+ _snwprintf(query, MAX_QUERY_LEN, -+ L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE " -+ L"Index=%d", -+ vt.uintVal); -+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); -+ VariantClear(&vt); -+ IWbemClassObject_Release(pObj); -+ -+ hr = call_IWbemServices_ExecQuery( -+ pSvc, L"WQL", query, -+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, -+ NULL, &pEnumerator); -+ if (!SUCCEEDED(hr)) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface " -+ "from Win32_NetworkAdapter: 0x%x", (int) hr); -+ IWbemServices_Release(pSvc); -+ return ndis_events_use_desc(events, desc); -+ } -+ -+ uReturned = 0; -+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, -+ &pObj, &uReturned); -+ if (!SUCCEEDED(hr) || uReturned == 0) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface " -+ "from Win32_NetworkAdapter: 0x%x", (int) hr); -+ IEnumWbemClassObject_Release(pEnumerator); -+ IWbemServices_Release(pSvc); -+ return ndis_events_use_desc(events, desc); -+ } -+ IEnumWbemClassObject_Release(pEnumerator); -+ -+ hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL); -+ if (!SUCCEEDED(hr)) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from " -+ "Win32_NetworkAdapter: 0x%x", (int) hr); -+ IWbemClassObject_Release(pObj); -+ IWbemServices_Release(pSvc); -+ return ndis_events_use_desc(events, desc); -+ } -+ -+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'", -+ vt.bstrVal); -+ events->adapter_desc = _wcsdup(vt.bstrVal); -+ VariantClear(&vt); -+ -+ /* -+ * Try to get even better candidate for matching with InstanceName -+ * from Win32_PnPEntity. This is needed at least for some USB cards -+ * that can change the InstanceName whenever being unplugged and -+ * plugged again. -+ */ -+ -+ hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL); -+ if (!SUCCEEDED(hr)) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID " -+ "from Win32_NetworkAdapter: 0x%x", (int) hr); -+ IWbemClassObject_Release(pObj); -+ IWbemServices_Release(pSvc); -+ if (events->adapter_desc == NULL) -+ return ndis_events_use_desc(events, desc); -+ return 0; /* use Win32_NetworkAdapter::Name */ -+ } -+ -+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID=" -+ "'%S'", vt.bstrVal); -+ -+ len = _snwprintf(query, MAX_QUERY_LEN, -+ L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='"); -+ if (len < 0 || len >= MAX_QUERY_LEN - 1) { -+ VariantClear(&vt); -+ IWbemClassObject_Release(pObj); -+ IWbemServices_Release(pSvc); -+ if (events->adapter_desc == NULL) -+ return ndis_events_use_desc(events, desc); -+ return 0; /* use Win32_NetworkAdapter::Name */ -+ } -+ -+ /* Escape \ as \\ */ -+ for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) { -+ if (vt.bstrVal[pos] == '\\') { -+ if (len >= MAX_QUERY_LEN - 3) -+ break; -+ query[len++] = '\\'; -+ } -+ query[len++] = vt.bstrVal[pos]; -+ } -+ query[len++] = L'\''; -+ query[len] = L'\0'; -+ VariantClear(&vt); -+ IWbemClassObject_Release(pObj); -+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query); -+ -+ hr = call_IWbemServices_ExecQuery( -+ pSvc, L"WQL", query, -+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, -+ NULL, &pEnumerator); -+ if (!SUCCEEDED(hr)) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface " -+ "Name from Win32_PnPEntity: 0x%x", (int) hr); -+ IWbemServices_Release(pSvc); -+ if (events->adapter_desc == NULL) -+ return ndis_events_use_desc(events, desc); -+ return 0; /* use Win32_NetworkAdapter::Name */ -+ } -+ -+ uReturned = 0; -+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1, -+ &pObj, &uReturned); -+ if (!SUCCEEDED(hr) || uReturned == 0) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface " -+ "from Win32_PnPEntity: 0x%x", (int) hr); -+ IEnumWbemClassObject_Release(pEnumerator); -+ IWbemServices_Release(pSvc); -+ if (events->adapter_desc == NULL) -+ return ndis_events_use_desc(events, desc); -+ return 0; /* use Win32_NetworkAdapter::Name */ -+ } -+ IEnumWbemClassObject_Release(pEnumerator); -+ -+ hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL); -+ if (!SUCCEEDED(hr)) { -+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from " -+ "Win32_PnPEntity: 0x%x", (int) hr); -+ IWbemClassObject_Release(pObj); -+ IWbemServices_Release(pSvc); -+ if (events->adapter_desc == NULL) -+ return ndis_events_use_desc(events, desc); -+ return 0; /* use Win32_NetworkAdapter::Name */ -+ } -+ -+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'", -+ vt.bstrVal); -+ os_free(events->adapter_desc); -+ events->adapter_desc = _wcsdup(vt.bstrVal); -+ VariantClear(&vt); -+ -+ IWbemClassObject_Release(pObj); -+ -+ IWbemServices_Release(pSvc); -+ -+ if (events->adapter_desc == NULL) -+ return ndis_events_use_desc(events, desc); -+ -+ return 0; -+} -+ -+ -+struct ndis_events_data * -+ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail, -+ const char *ifname, const char *desc) -+{ -+ HRESULT hr; -+ IWbemObjectSink *pSink; -+ struct ndis_events_data *events; -+ -+ events = os_zalloc(sizeof(*events)); -+ if (events == NULL) { -+ wpa_printf(MSG_ERROR, "Could not allocate sink for events."); -+ return NULL; -+ } -+ events->ifname = os_strdup(ifname); -+ if (events->ifname == NULL) { -+ os_free(events); -+ return NULL; -+ } -+ -+ if (wmi_refcnt++ == 0) { -+ hr = CoInitializeEx(0, COINIT_MULTITHREADED); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_ERROR, "CoInitializeEx() failed - " -+ "returned 0x%x", (int) hr); -+ os_free(events); -+ return NULL; -+ } -+ } -+ -+ if (wmi_first) { -+ /* CoInitializeSecurity() must be called once and only once -+ * per process, so let's use wmi_first flag to protect against -+ * multiple calls. */ -+ wmi_first = 0; -+ -+ hr = CoInitializeSecurity(NULL, -1, NULL, NULL, -+ RPC_C_AUTHN_LEVEL_PKT_PRIVACY, -+ RPC_C_IMP_LEVEL_IMPERSONATE, -+ NULL, EOAC_SECURE_REFS, NULL); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed " -+ "- returned 0x%x", (int) hr); -+ os_free(events); -+ return NULL; -+ } -+ } -+ -+ hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, -+ &IID_IWbemLocator, -+ (LPVOID *) (void *) &events->pLoc); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned " -+ "0x%x", (int) hr); -+ CoUninitialize(); -+ os_free(events); -+ return NULL; -+ } -+ -+ if (ndis_events_get_adapter(events, ifname, desc) < 0) { -+ CoUninitialize(); -+ os_free(events); -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'", -+ events->adapter_desc); -+ -+ hr = call_IWbemLocator_ConnectServer( -+ events->pLoc, L"ROOT\\WMI", NULL, NULL, -+ 0, 0, 0, 0, &events->pSvc); -+ if (FAILED(hr)) { -+ wpa_printf(MSG_ERROR, "Could not connect to server - error " -+ "0x%x", (int) hr); -+ CoUninitialize(); -+ os_free(events->adapter_desc); -+ os_free(events); -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI."); -+ -+ ndis_events_constructor(events); -+ pSink = &events->sink; -+ pSink->lpVtbl = &events->sink_vtbl; -+ events->sink_vtbl.QueryInterface = ndis_events_query_interface; -+ events->sink_vtbl.AddRef = ndis_events_add_ref; -+ events->sink_vtbl.Release = ndis_events_release; -+ events->sink_vtbl.Indicate = ndis_events_indicate; -+ events->sink_vtbl.SetStatus = ndis_events_set_status; -+ -+ if (register_async_notification(pSink, events->pSvc) < 0) { -+ wpa_printf(MSG_DEBUG, "Failed to register async " -+ "notifications"); -+ ndis_events_destructor(events); -+ os_free(events->adapter_desc); -+ os_free(events); -+ return NULL; -+ } -+ -+ *read_pipe = events->read_pipe; -+ *event_avail = events->event_avail; -+ -+ return events; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.c -new file mode 100644 -index 0000000000000..ad15b1d62a8d8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.c -@@ -0,0 +1,204 @@ -+/* -+ * Netlink helper functions for driver wrappers -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "priv_netlink.h" -+#include "netlink.h" -+ -+ -+struct netlink_data { -+ struct netlink_config *cfg; -+ int sock; -+}; -+ -+ -+static void netlink_receive_link(struct netlink_data *netlink, -+ void (*cb)(void *ctx, struct ifinfomsg *ifi, -+ u8 *buf, size_t len), -+ struct nlmsghdr *h) -+{ -+ if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg)) -+ return; -+ cb(netlink->cfg->ctx, NLMSG_DATA(h), -+ NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)), -+ NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg))); -+} -+ -+ -+static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct netlink_data *netlink = eloop_ctx; -+ char buf[8192]; -+ int left; -+ struct sockaddr_nl from; -+ socklen_t fromlen; -+ struct nlmsghdr *h; -+ int max_events = 10; -+ -+try_again: -+ fromlen = sizeof(from); -+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, -+ (struct sockaddr *) &from, &fromlen); -+ if (left < 0) { -+ if (errno != EINTR && errno != EAGAIN) -+ wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s", -+ strerror(errno)); -+ return; -+ } -+ -+ h = (struct nlmsghdr *) buf; -+ while (NLMSG_OK(h, left)) { -+ switch (h->nlmsg_type) { -+ case RTM_NEWLINK: -+ netlink_receive_link(netlink, netlink->cfg->newlink_cb, -+ h); -+ break; -+ case RTM_DELLINK: -+ netlink_receive_link(netlink, netlink->cfg->dellink_cb, -+ h); -+ break; -+ } -+ -+ h = NLMSG_NEXT(h, left); -+ } -+ -+ if (left > 0) { -+ wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of " -+ "netlink message", left); -+ } -+ -+ if (--max_events > 0) { -+ /* -+ * Try to receive all events in one eloop call in order to -+ * limit race condition on cases where AssocInfo event, Assoc -+ * event, and EAPOL frames are received more or less at the -+ * same time. We want to process the event messages first -+ * before starting EAPOL processing. -+ */ -+ goto try_again; -+ } -+} -+ -+ -+struct netlink_data * netlink_init(struct netlink_config *cfg) -+{ -+ struct netlink_data *netlink; -+ struct sockaddr_nl local; -+ -+ netlink = os_zalloc(sizeof(*netlink)); -+ if (netlink == NULL) -+ return NULL; -+ -+ netlink->cfg = cfg; -+ -+ netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); -+ if (netlink->sock < 0) { -+ wpa_printf(MSG_ERROR, "netlink: Failed to open netlink " -+ "socket: %s", strerror(errno)); -+ netlink_deinit(netlink); -+ return NULL; -+ } -+ -+ os_memset(&local, 0, sizeof(local)); -+ local.nl_family = AF_NETLINK; -+ local.nl_groups = RTMGRP_LINK; -+ if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0) -+ { -+ wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink " -+ "socket: %s", strerror(errno)); -+ netlink_deinit(netlink); -+ return NULL; -+ } -+ -+ eloop_register_read_sock(netlink->sock, netlink_receive, netlink, -+ NULL); -+ -+ return netlink; -+} -+ -+ -+void netlink_deinit(struct netlink_data *netlink) -+{ -+ if (netlink == NULL) -+ return; -+ if (netlink->sock >= 0) { -+ eloop_unregister_read_sock(netlink->sock); -+ close(netlink->sock); -+ } -+ os_free(netlink->cfg); -+ os_free(netlink); -+} -+ -+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, -+ int linkmode, int operstate) -+{ -+ struct { -+ struct nlmsghdr hdr; -+ struct ifinfomsg ifinfo; -+ char opts[16]; -+ } req; -+ struct rtattr *rta; -+ static int nl_seq; -+ ssize_t ret; -+ -+ os_memset(&req, 0, sizeof(req)); -+ -+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); -+ req.hdr.nlmsg_type = RTM_SETLINK; -+ req.hdr.nlmsg_flags = NLM_F_REQUEST; -+ req.hdr.nlmsg_seq = ++nl_seq; -+ req.hdr.nlmsg_pid = 0; -+ -+ req.ifinfo.ifi_family = AF_UNSPEC; -+ req.ifinfo.ifi_type = 0; -+ req.ifinfo.ifi_index = ifindex; -+ req.ifinfo.ifi_flags = 0; -+ req.ifinfo.ifi_change = 0; -+ -+ if (linkmode != -1) { -+ rta = aliasing_hide_typecast( -+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), -+ struct rtattr); -+ rta->rta_type = IFLA_LINKMODE; -+ rta->rta_len = RTA_LENGTH(sizeof(char)); -+ *((char *) RTA_DATA(rta)) = linkmode; -+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + -+ RTA_LENGTH(sizeof(char)); -+ } -+ if (operstate != -1) { -+ rta = aliasing_hide_typecast( -+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)), -+ struct rtattr); -+ rta->rta_type = IFLA_OPERSTATE; -+ rta->rta_len = RTA_LENGTH(sizeof(char)); -+ *((char *) RTA_DATA(rta)) = operstate; -+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + -+ RTA_LENGTH(sizeof(char)); -+ } -+ -+ wpa_printf(MSG_DEBUG, "netlink: Operstate: linkmode=%d, operstate=%d", -+ linkmode, operstate); -+ -+ ret = send(netlink->sock, &req, req.hdr.nlmsg_len, 0); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "netlink: Sending operstate IFLA " -+ "failed: %s (assume operstate is not supported)", -+ strerror(errno)); -+ } -+ -+ return ret < 0 ? -1 : 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.h -new file mode 100644 -index 0000000000000..ccf12a52dfe80 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/netlink.h -@@ -0,0 +1,34 @@ -+/* -+ * Netlink helper functions for driver wrappers -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef NETLINK_H -+#define NETLINK_H -+ -+struct netlink_data; -+struct ifinfomsg; -+ -+struct netlink_config { -+ void *ctx; -+ void (*newlink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, -+ size_t len); -+ void (*dellink_cb)(void *ctx, struct ifinfomsg *ifi, u8 *buf, -+ size_t len); -+}; -+ -+struct netlink_data * netlink_init(struct netlink_config *cfg); -+void netlink_deinit(struct netlink_data *netlink); -+int netlink_send_oper_ifla(struct netlink_data *netlink, int ifindex, -+ int linkmode, int operstate); -+ -+#endif /* NETLINK_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/nl80211_copy.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/nl80211_copy.h -new file mode 100644 -index 0000000000000..7483a89cee8f5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/nl80211_copy.h -@@ -0,0 +1,1939 @@ -+#ifndef __LINUX_NL80211_H -+#define __LINUX_NL80211_H -+/* -+ * 802.11 netlink interface public header -+ * -+ * Copyright 2006-2010 Johannes Berg -+ * Copyright 2008 Michael Wu -+ * Copyright 2008 Luis Carlos Cobo -+ * Copyright 2008 Michael Buesch -+ * Copyright 2008, 2009 Luis R. Rodriguez -+ * Copyright 2008 Jouni Malinen -+ * Copyright 2008 Colin McCabe -+ * -+ * Permission to use, copy, modify, and/or 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 -+ -+/** -+ * DOC: Station handling -+ * -+ * Stations are added per interface, but a special case exists with VLAN -+ * interfaces. When a station is bound to an AP interface, it may be moved -+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). -+ * The station is still assumed to belong to the AP interface it was added -+ * to. -+ * -+ * TODO: need more info? -+ */ -+ -+/** -+ * DOC: Frame transmission/registration support -+ * -+ * Frame transmission and registration support exists to allow userspace -+ * management entities such as wpa_supplicant react to management frames -+ * that are not being handled by the kernel. This includes, for example, -+ * certain classes of action frames that cannot be handled in the kernel -+ * for various reasons. -+ * -+ * Frame registration is done on a per-interface basis and registrations -+ * cannot be removed other than by closing the socket. It is possible to -+ * specify a registration filter to register, for example, only for a -+ * certain type of action frame. In particular with action frames, those -+ * that userspace registers for will not be returned as unhandled by the -+ * driver, so that the registered application has to take responsibility -+ * for doing that. -+ * -+ * The type of frame that can be registered for is also dependent on the -+ * driver and interface type. The frame types are advertised in wiphy -+ * attributes so applications know what to expect. -+ * -+ * NOTE: When an interface changes type while registrations are active, -+ * these registrations are ignored until the interface type is -+ * changed again. This means that changing the interface type can -+ * lead to a situation that couldn't otherwise be produced, but -+ * any such registrations will be dormant in the sense that they -+ * will not be serviced, i.e. they will not receive any frames. -+ * -+ * Frame transmission allows userspace to send for example the required -+ * responses to action frames. It is subject to some sanity checking, -+ * but many frames can be transmitted. When a frame was transmitted, its -+ * status is indicated to the sending socket. -+ * -+ * For more technical details, see the corresponding command descriptions -+ * below. -+ */ -+ -+/** -+ * enum nl80211_commands - supported nl80211 commands -+ * -+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors -+ * -+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request -+ * to get a list of all present wiphys. -+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or -+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, -+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, -+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT, -+ * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, -+ * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. -+ * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL -+ * instead, the support here is for backward compatibility only. -+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request -+ * or rename notification. Has attributes %NL80211_ATTR_WIPHY and -+ * %NL80211_ATTR_WIPHY_NAME. -+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes -+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. -+ * -+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; -+ * either a dump request on a %NL80211_ATTR_WIPHY or a specific get -+ * on an %NL80211_ATTR_IFINDEX is supported. -+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires -+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. -+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response -+ * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX, -+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also -+ * be sent from userspace to request creation of a new virtual interface, -+ * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and -+ * %NL80211_ATTR_IFNAME. -+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes -+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from -+ * userspace to request deletion of a virtual interface, then requires -+ * attribute %NL80211_ATTR_IFINDEX. -+ * -+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified -+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. -+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, -+ * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. -+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, -+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER, -+ * and %NL80211_ATTR_KEY_SEQ attributes. -+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX -+ * or %NL80211_ATTR_MAC. -+ * -+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a -+ * %NL80222_CMD_NEW_BEACON message) -+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface -+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, -+ * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes. -+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, -+ * parameters are like for %NL80211_CMD_SET_BEACON. -+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it -+ * -+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by -+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by -+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the -+ * the interface identified by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC -+ * or, if no MAC address given, all stations, on the interface identified -+ * by %NL80211_ATTR_IFINDEX. -+ * -+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to -+ * destination %NL80211_ATTR_MAC on the interface identified by -+ * %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to -+ * destination %NL80211_ATTR_MAC on the interface identified by -+ * %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the -+ * the interface identified by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC -+ * or, if no MAC address given, all mesh paths, on the interface identified -+ * by %NL80211_ATTR_IFINDEX. -+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by -+ * %NL80211_ATTR_IFINDEX. -+ * -+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set -+ * regulatory domain. -+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command -+ * after being queried by the kernel. CRDA replies by sending a regulatory -+ * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our -+ * current alpha2 if it found a match. It also provides -+ * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each -+ * regulatory rule is a nested set of attributes given by -+ * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and -+ * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by -+ * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and -+ * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP. -+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain -+ * to the specified ISO/IEC 3166-1 alpha2 country code. The core will -+ * store this as a valid request and then query userspace for it. -+ * -+ * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the -+ * interface identified by %NL80211_ATTR_IFINDEX -+ * -+ * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the -+ * interface identified by %NL80211_ATTR_IFINDEX -+ * -+ * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The -+ * interface is identified with %NL80211_ATTR_IFINDEX and the management -+ * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be -+ * added to the end of the specified management frame is specified with -+ * %NL80211_ATTR_IE. If the command succeeds, the requested data will be -+ * added to all specified management frames generated by -+ * kernel/firmware/driver. -+ * Note: This command has been removed and it is only reserved at this -+ * point to avoid re-using existing command number. The functionality this -+ * command was planned for has been provided with cleaner design with the -+ * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN, -+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE, -+ * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE. -+ * -+ * @NL80211_CMD_GET_SCAN: get scan results -+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters -+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to -+ * NL80211_CMD_GET_SCAN and on the "scan" multicast group) -+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, -+ * partial scan results may be available -+ * -+ * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation -+ * or noise level -+ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to -+ * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) -+ * -+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain -+ * has been changed and provides details of the request information -+ * that caused the change such as who initiated the regulatory request -+ * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx -+ * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if -+ * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or -+ * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain -+ * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is -+ * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on -+ * to (%NL80211_ATTR_REG_ALPHA2). -+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon -+ * has been found while world roaming thus enabling active scan or -+ * any mode of operation that initiates TX (beacons) on a channel -+ * where we would not have been able to do either before. As an example -+ * if you are world roaming (regulatory domain set to world or if your -+ * driver is using a custom world roaming regulatory domain) and while -+ * doing a passive scan on the 5 GHz band you find an AP there (if not -+ * on a DFS channel) you will now be able to actively scan for that AP -+ * or use AP mode on your card on that same channel. Note that this will -+ * never be used for channels 1-11 on the 2 GHz band as they are always -+ * enabled world wide. This beacon hint is only sent if your device had -+ * either disabled active scanning or beaconing on a channel. We send to -+ * userspace the wiphy on which we removed a restriction from -+ * (%NL80211_ATTR_WIPHY) and the channel on which this occurred -+ * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER) -+ * the beacon hint was processed. -+ * -+ * @NL80211_CMD_AUTHENTICATE: authentication request and notification. -+ * This command is used both as a command (request to authenticate) and -+ * as an event on the "mlme" multicast group indicating completion of the -+ * authentication process. -+ * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the -+ * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and -+ * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify -+ * the SSID (mainly for association, but is included in authentication -+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used -+ * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE -+ * is used to specify the authentication type. %NL80211_ATTR_IE is used to -+ * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs) -+ * to be added to the frame. -+ * When used as an event, this reports reception of an Authentication -+ * frame in station and IBSS modes when the local MLME processed the -+ * frame, i.e., it was for the local STA and was received in correct -+ * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the -+ * MLME SAP interface (kernel providing MLME, userspace SME). The -+ * included %NL80211_ATTR_FRAME attribute contains the management frame -+ * (including both the header and frame body, but not FCS). This event is -+ * also used to indicate if the authentication attempt timed out. In that -+ * case the %NL80211_ATTR_FRAME attribute is replaced with a -+ * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which -+ * pending authentication timed out). -+ * @NL80211_CMD_ASSOCIATE: association request and notification; like -+ * NL80211_CMD_AUTHENTICATE but for Association and Reassociation -+ * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request, -+ * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives). -+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like -+ * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to -+ * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication -+ * primitives). -+ * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like -+ * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to -+ * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives). -+ * -+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael -+ * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the -+ * event includes %NL80211_ATTR_MAC to describe the source MAC address of -+ * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key -+ * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and -+ * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this -+ * event matches with MLME-MICHAELMICFAILURE.indication() primitive -+ * -+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a -+ * FREQ attribute (for the initial frequency if no peer can be found) -+ * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those -+ * should be fixed rather than automatically determined. Can only be -+ * executed on a network interface that is UP, and fixed BSSID/FREQ -+ * may be rejected. Another optional parameter is the beacon interval, -+ * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not -+ * given defaults to 100 TU (102.4ms). -+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is -+ * determined by the network interface. -+ * -+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute -+ * to identify the device, and the TESTDATA blob attribute to pass through -+ * to the driver. -+ * -+ * @NL80211_CMD_CONNECT: connection request and notification; this command -+ * requests to connect to a specified network but without separating -+ * auth and assoc steps. For this, you need to specify the SSID in a -+ * %NL80211_ATTR_SSID attribute, and can optionally specify the association -+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC, -+ * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, -+ * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and -+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. -+ * It is also sent as an event, with the BSSID and response IEs when the -+ * connection is established or failed to be established. This can be -+ * determined by the STATUS_CODE attribute. -+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), -+ * sent as an event when the card/driver roamed by itself. -+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify -+ * userspace that a connection was dropped by the AP or due to other -+ * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and -+ * %NL80211_ATTR_REASON_CODE attributes are used. -+ * -+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices -+ * associated with this wiphy must be down and will follow. -+ * -+ * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified -+ * channel for the specified amount of time. This can be used to do -+ * off-channel operations like transmit a Public Action frame and wait for -+ * a response while being associated to an AP on another channel. -+ * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus -+ * radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the -+ * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be -+ * optionally used to specify additional channel parameters. -+ * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds -+ * to remain on the channel. This command is also used as an event to -+ * notify when the requested duration starts (it may take a while for the -+ * driver to schedule this time due to other concurrent needs for the -+ * radio). -+ * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) -+ * that will be included with any events pertaining to this request; -+ * the cookie is also used to cancel the request. -+ * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a -+ * pending remain-on-channel duration if the desired operation has been -+ * completed prior to expiration of the originally requested duration. -+ * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the -+ * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to -+ * uniquely identify the request. -+ * This command is also used as an event to notify when a requested -+ * remain-on-channel duration has expired. -+ * -+ * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX -+ * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface -+ * and @NL80211_ATTR_TX_RATES the set of allowed rates. -+ * -+ * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames -+ * (via @NL80211_CMD_FRAME) for processing in userspace. This command -+ * requires an interface index, a frame type attribute (optional for -+ * backward compatibility reasons, if not given assumes action frames) -+ * and a match attribute containing the first few bytes of the frame -+ * that should match, e.g. a single byte for only a category match or -+ * four bytes for vendor frames including the OUI. The registration -+ * cannot be dropped, but is removed automatically when the netlink -+ * socket is closed. Multiple registrations can be made. -+ * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for -+ * backward compatibility -+ * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This -+ * command is used both as a request to transmit a management frame and -+ * as an event indicating reception of a frame that was not processed in -+ * kernel code, but is for us (i.e., which may need to be processed in a -+ * user space application). %NL80211_ATTR_FRAME is used to specify the -+ * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and -+ * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on -+ * which channel the frame is to be transmitted or was received. If this -+ * channel is not the current channel (remain-on-channel or the -+ * operational channel) the device will switch to the given channel and -+ * transmit the frame, optionally waiting for a response for the time -+ * specified using %NL80211_ATTR_DURATION. When called, this operation -+ * returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the -+ * TX status event pertaining to the TX request. -+ * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this -+ * command may be used with the corresponding cookie to cancel the wait -+ * time if it is known that it is no longer necessary. -+ * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility. -+ * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame -+ * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies -+ * the TX command and %NL80211_ATTR_FRAME includes the contents of the -+ * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged -+ * the frame. -+ * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for -+ * backward compatibility. -+ * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command -+ * is used to configure connection quality monitoring notification trigger -+ * levels. -+ * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This -+ * command is used as an event to indicate the that a trigger level was -+ * reached. -+ * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ -+ * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed -+ * by %NL80211_ATTR_IFINDEX) shall operate on. -+ * In case multiple channels are supported by the device, the mechanism -+ * with which it switches channels is implementation-defined. -+ * When a monitor interface is given, it can only switch channel while -+ * no other interfaces are operating to avoid disturbing the operation -+ * of any other interfaces, and other interfaces will again take -+ * precedence when they are used. -+ * -+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. -+ * -+ * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial -+ * mesh config parameters may be given. -+ * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the -+ * network is determined by the network interface. -+ * -+ * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame -+ * notification. This event is used to indicate that an unprotected -+ * deauthentication frame was dropped when MFP is in use. -+ * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame -+ * notification. This event is used to indicate that an unprotected -+ * disassociation frame was dropped when MFP is in use. -+ * -+ * @NL80211_CMD_MAX: highest used command number -+ * @__NL80211_CMD_AFTER_LAST: internal use -+ */ -+enum nl80211_commands { -+/* don't change the order or add anything inbetween, this is ABI! */ -+ NL80211_CMD_UNSPEC, -+ -+ NL80211_CMD_GET_WIPHY, /* can dump */ -+ NL80211_CMD_SET_WIPHY, -+ NL80211_CMD_NEW_WIPHY, -+ NL80211_CMD_DEL_WIPHY, -+ -+ NL80211_CMD_GET_INTERFACE, /* can dump */ -+ NL80211_CMD_SET_INTERFACE, -+ NL80211_CMD_NEW_INTERFACE, -+ NL80211_CMD_DEL_INTERFACE, -+ -+ NL80211_CMD_GET_KEY, -+ NL80211_CMD_SET_KEY, -+ NL80211_CMD_NEW_KEY, -+ NL80211_CMD_DEL_KEY, -+ -+ NL80211_CMD_GET_BEACON, -+ NL80211_CMD_SET_BEACON, -+ NL80211_CMD_NEW_BEACON, -+ NL80211_CMD_DEL_BEACON, -+ -+ NL80211_CMD_GET_STATION, -+ NL80211_CMD_SET_STATION, -+ NL80211_CMD_NEW_STATION, -+ NL80211_CMD_DEL_STATION, -+ -+ NL80211_CMD_GET_MPATH, -+ NL80211_CMD_SET_MPATH, -+ NL80211_CMD_NEW_MPATH, -+ NL80211_CMD_DEL_MPATH, -+ -+ NL80211_CMD_SET_BSS, -+ -+ NL80211_CMD_SET_REG, -+ NL80211_CMD_REQ_SET_REG, -+ -+ NL80211_CMD_GET_MESH_PARAMS, -+ NL80211_CMD_SET_MESH_PARAMS, -+ -+ NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */, -+ -+ NL80211_CMD_GET_REG, -+ -+ NL80211_CMD_GET_SCAN, -+ NL80211_CMD_TRIGGER_SCAN, -+ NL80211_CMD_NEW_SCAN_RESULTS, -+ NL80211_CMD_SCAN_ABORTED, -+ -+ NL80211_CMD_REG_CHANGE, -+ -+ NL80211_CMD_AUTHENTICATE, -+ NL80211_CMD_ASSOCIATE, -+ NL80211_CMD_DEAUTHENTICATE, -+ NL80211_CMD_DISASSOCIATE, -+ -+ NL80211_CMD_MICHAEL_MIC_FAILURE, -+ -+ NL80211_CMD_REG_BEACON_HINT, -+ -+ NL80211_CMD_JOIN_IBSS, -+ NL80211_CMD_LEAVE_IBSS, -+ -+ NL80211_CMD_TESTMODE, -+ -+ NL80211_CMD_CONNECT, -+ NL80211_CMD_ROAM, -+ NL80211_CMD_DISCONNECT, -+ -+ NL80211_CMD_SET_WIPHY_NETNS, -+ -+ NL80211_CMD_GET_SURVEY, -+ NL80211_CMD_NEW_SURVEY_RESULTS, -+ -+ NL80211_CMD_SET_PMKSA, -+ NL80211_CMD_DEL_PMKSA, -+ NL80211_CMD_FLUSH_PMKSA, -+ -+ NL80211_CMD_REMAIN_ON_CHANNEL, -+ NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, -+ -+ NL80211_CMD_SET_TX_BITRATE_MASK, -+ -+ NL80211_CMD_REGISTER_FRAME, -+ NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME, -+ NL80211_CMD_FRAME, -+ NL80211_CMD_ACTION = NL80211_CMD_FRAME, -+ NL80211_CMD_FRAME_TX_STATUS, -+ NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS, -+ -+ NL80211_CMD_SET_POWER_SAVE, -+ NL80211_CMD_GET_POWER_SAVE, -+ -+ NL80211_CMD_SET_CQM, -+ NL80211_CMD_NOTIFY_CQM, -+ -+ NL80211_CMD_SET_CHANNEL, -+ NL80211_CMD_SET_WDS_PEER, -+ -+ NL80211_CMD_FRAME_WAIT_CANCEL, -+ -+ NL80211_CMD_JOIN_MESH, -+ NL80211_CMD_LEAVE_MESH, -+ -+ NL80211_CMD_UNPROT_DEAUTHENTICATE, -+ NL80211_CMD_UNPROT_DISASSOCIATE, -+ -+ /* add new commands above here */ -+ -+ /* used to define NL80211_CMD_MAX below */ -+ __NL80211_CMD_AFTER_LAST, -+ NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 -+}; -+ -+/* -+ * Allow user space programs to use #ifdef on new commands by defining them -+ * here -+ */ -+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS -+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE -+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE -+#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE -+#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE -+#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE -+#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE -+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT -+ -+/** -+ * enum nl80211_attrs - nl80211 netlink attributes -+ * -+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors -+ * -+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. -+ * /sys/class/ieee80211//index -+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) -+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters -+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz -+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ -+ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): -+ * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including -+ * this attribute) -+ * NL80211_CHAN_HT20 = HT20 only -+ * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel -+ * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel -+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is -+ * less than or equal to the RTS threshold; allowed range: 1..255; -+ * dot11ShortRetryLimit; u8 -+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is -+ * greater than the RTS threshold; allowed range: 1..255; -+ * dot11ShortLongLimit; u8 -+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum -+ * length in octets for frames; allowed range: 256..8000, disable -+ * fragmentation with (u32)-1; dot11FragmentationThreshold; u32 -+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length -+ * larger than or equal to this use RTS/CTS handshake); allowed range: -+ * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 -+ * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 -+ * section 7.3.2.9; dot11CoverageClass; u8 -+ * -+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on -+ * @NL80211_ATTR_IFNAME: network interface name -+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype -+ * -+ * @NL80211_ATTR_MAC: MAC address (various uses) -+ * -+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of -+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC -+ * keys -+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) -+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 -+ * section 7.3.2.25.1, e.g. 0x000FAC04) -+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and -+ * CCMP keys, each six bytes in little endian -+ * -+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU -+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing -+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE -+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE -+ * -+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16) -+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of -+ * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2) -+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by -+ * IEEE 802.11 7.3.1.6 (u16). -+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported -+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length -+ * restriction (at most %NL80211_MAX_SUPP_RATES). -+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station -+ * to, or the AP interface the station was originally added to to. -+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info -+ * given for %NL80211_CMD_GET_STATION, nested attribute containing -+ * info as possible, see &enum nl80211_sta_info. -+ * -+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, -+ * consisting of a nested array. -+ * -+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). -+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. -+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. -+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path -+ * info given for %NL80211_CMD_GET_MPATH, nested attribute described at -+ * &enum nl80211_mpath_info. -+ * -+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of -+ * &enum nl80211_mntr_flags. -+ * -+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the -+ * current regulatory domain should be set to or is already set to. -+ * For example, 'CR', for Costa Rica. This attribute is used by the kernel -+ * to query the CRDA to retrieve one regulatory domain. This attribute can -+ * also be used by userspace to query the kernel for the currently set -+ * regulatory domain. We chose an alpha2 as that is also used by the -+ * IEEE-802.11d country information element to identify a country. -+ * Users can also simply ask the wireless core to set regulatory domain -+ * to a specific alpha2. -+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory -+ * rules. -+ * -+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) -+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled -+ * (u8, 0 or 1) -+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled -+ * (u8, 0 or 1) -+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic -+ * rates in format defined by IEEE 802.11 7.3.2.2 but without the length -+ * restriction (at most %NL80211_MAX_SUPP_RATES). -+ * -+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from -+ * association request when used with NL80211_CMD_NEW_STATION) -+ * -+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all -+ * supported interface types, each a flag attribute with the number -+ * of the interface mode. -+ * -+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for -+ * %NL80211_CMD_SET_MGMT_EXTRA_IE. -+ * -+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with -+ * %NL80211_CMD_SET_MGMT_EXTRA_IE). -+ * -+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with -+ * a single scan request, a wiphy attribute. -+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements -+ * that can be added to a scan request -+ * -+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) -+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive -+ * scanning and include a zero-length SSID (wildcard) for wildcard scan -+ * @NL80211_ATTR_BSS: scan result BSS -+ * -+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain -+ * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_* -+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently -+ * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*) -+ * -+ * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies -+ * an array of command numbers (i.e. a mapping index to command number) -+ * that the driver for the given wiphy supports. -+ * -+ * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header -+ * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and -+ * NL80211_CMD_ASSOCIATE events -+ * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets) -+ * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type, -+ * represented as a u32 -+ * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and -+ * %NL80211_CMD_DISASSOCIATE, u16 -+ * -+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as -+ * a u32 -+ * -+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change -+ * due to considerations from a beacon hint. This attribute reflects -+ * the state of the channel _before_ the beacon hint processing. This -+ * attributes consists of a nested attribute containing -+ * NL80211_FREQUENCY_ATTR_* -+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change -+ * due to considerations from a beacon hint. This attribute reflects -+ * the state of the channel _after_ the beacon hint processing. This -+ * attributes consists of a nested attribute containing -+ * NL80211_FREQUENCY_ATTR_* -+ * -+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported -+ * cipher suites -+ * -+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look -+ * for other networks on different channels -+ * -+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this -+ * is used, e.g., with %NL80211_CMD_AUTHENTICATE event -+ * -+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is -+ * used for the association (&enum nl80211_mfp, represented as a u32); -+ * this attribute can be used -+ * with %NL80211_CMD_ASSOCIATE request -+ * -+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a -+ * &struct nl80211_sta_flag_update. -+ * -+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls -+ * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in -+ * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE -+ * request, the driver will assume that the port is unauthorized until -+ * authorized by user space. Otherwise, port is marked authorized by -+ * default in station mode. -+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the -+ * ethertype that will be used for key negotiation. It can be -+ * specified with the associate and connect commands. If it is not -+ * specified, the value defaults to 0x888E (PAE, 802.1X). This -+ * attribute is also used as a flag in the wiphy information to -+ * indicate that protocols other than PAE are supported. -+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with -+ * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom -+ * ethertype frames used for key negotiation must not be encrypted. -+ * -+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. -+ * We recommend using nested, driver-specific attributes within this. -+ * -+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT -+ * event was due to the AP disconnecting the station, and not due to -+ * a local disconnect request. -+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT -+ * event (u16) -+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating -+ * that protected APs should be used. -+ * -+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to -+ * indicate which unicast key ciphers will be used with the connection -+ * (an array of u32). -+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate -+ * which group key cipher will be used with the connection (a u32). -+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate -+ * which WPA version(s) the AP we want to associate with is using -+ * (a u32 with flags from &enum nl80211_wpa_versions). -+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate -+ * which key management algorithm(s) to use (an array of u32). -+ * -+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as -+ * sent out by the card, for ROAM and successful CONNECT events. -+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as -+ * sent by peer, for ROAM and successful CONNECT events. -+ * -+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE -+ * commands to specify using a reassociate frame -+ * -+ * @NL80211_ATTR_KEY: key information in a nested attribute with -+ * %NL80211_KEY_* sub-attributes -+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect() -+ * and join_ibss(), key information is in a nested attribute each -+ * with %NL80211_KEY_* sub-attributes -+ * -+ * @NL80211_ATTR_PID: Process ID of a network namespace. -+ * -+ * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for -+ * dumps. This number increases whenever the object list being -+ * dumped changes, and as such userspace can verify that it has -+ * obtained a complete and consistent snapshot by verifying that -+ * all dump messages contain the same generation number. If it -+ * changed then the list changed and the dump should be repeated -+ * completely from scratch. -+ * -+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface -+ * -+ * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of -+ * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute -+ * containing info as possible, see &enum survey_info. -+ * -+ * @NL80211_ATTR_PMKID: PMK material for PMKSA caching. -+ * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can -+ * cache, a wiphy attribute. -+ * -+ * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. -+ * @NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION: Device attribute that -+ * specifies the maximum duration that can be requested with the -+ * remain-on-channel operation, in milliseconds, u32. -+ * -+ * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. -+ * -+ * @NL80211_ATTR_TX_RATES: Nested set of attributes -+ * (enum nl80211_tx_rate_attributes) describing TX rates per band. The -+ * enum nl80211_band value is used as the index (nla_type() of the nested -+ * data. If a band is not included, it will be configured to allow all -+ * rates based on negotiated supported rates information. This attribute -+ * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. -+ * -+ * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain -+ * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. -+ * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the -+ * @NL80211_CMD_REGISTER_FRAME command. -+ * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a -+ * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing -+ * information about which frame types can be transmitted with -+ * %NL80211_CMD_FRAME. -+ * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a -+ * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing -+ * information about which frame types can be registered for RX. -+ * -+ * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was -+ * acknowledged by the recipient. -+ * -+ * @NL80211_ATTR_CQM: connection quality monitor configuration in a -+ * nested attribute with %NL80211_ATTR_CQM_* sub-attributes. -+ * -+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command -+ * is requesting a local authentication/association state change without -+ * invoking actual management frame exchange. This can be used with -+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE, -+ * NL80211_CMD_DISASSOCIATE. -+ * -+ * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations -+ * connected to this BSS. -+ * -+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See -+ * &enum nl80211_tx_power_setting for possible values. -+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units. -+ * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING -+ * for non-automatic settings. -+ * -+ * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly -+ * means support for per-station GTKs. -+ * -+ * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting. -+ * This can be used to mask out antennas which are not attached or should -+ * not be used for transmitting. If an antenna is not selected in this -+ * bitmap the hardware is not allowed to transmit on this antenna. -+ * -+ * Each bit represents one antenna, starting with antenna 1 at the first -+ * bit. Depending on which antennas are selected in the bitmap, 802.11n -+ * drivers can derive which chainmasks to use (if all antennas belonging to -+ * a particular chain are disabled this chain should be disabled) and if -+ * a chain has diversity antennas wether diversity should be used or not. -+ * HT capabilities (STBC, TX Beamforming, Antenna selection) can be -+ * derived from the available chains after applying the antenna mask. -+ * Non-802.11n drivers can derive wether to use diversity or not. -+ * Drivers may reject configurations or RX/TX mask combinations they cannot -+ * support by returning -EINVAL. -+ * -+ * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving. -+ * This can be used to mask out antennas which are not attached or should -+ * not be used for receiving. If an antenna is not selected in this bitmap -+ * the hardware should not be configured to receive on this antenna. -+ * For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX. -+ * -+ * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS -+ * -+ * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be -+ * transmitted on another channel when the channel given doesn't match -+ * the current channel. If the current channel doesn't match and this -+ * flag isn't set, the frame will be rejected. This is also used as an -+ * nl80211 capability flag. -+ * -+ * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16) -+ * -+ * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags -+ * attributes, specifying what a key should be set as default as. -+ * See &enum nl80211_key_default_types. -+ * -+ * @NL80211_ATTR_MAX: highest attribute number currently defined -+ * @__NL80211_ATTR_AFTER_LAST: internal use -+ */ -+enum nl80211_attrs { -+/* don't change the order or add anything inbetween, this is ABI! */ -+ NL80211_ATTR_UNSPEC, -+ -+ NL80211_ATTR_WIPHY, -+ NL80211_ATTR_WIPHY_NAME, -+ -+ NL80211_ATTR_IFINDEX, -+ NL80211_ATTR_IFNAME, -+ NL80211_ATTR_IFTYPE, -+ -+ NL80211_ATTR_MAC, -+ -+ NL80211_ATTR_KEY_DATA, -+ NL80211_ATTR_KEY_IDX, -+ NL80211_ATTR_KEY_CIPHER, -+ NL80211_ATTR_KEY_SEQ, -+ NL80211_ATTR_KEY_DEFAULT, -+ -+ NL80211_ATTR_BEACON_INTERVAL, -+ NL80211_ATTR_DTIM_PERIOD, -+ NL80211_ATTR_BEACON_HEAD, -+ NL80211_ATTR_BEACON_TAIL, -+ -+ NL80211_ATTR_STA_AID, -+ NL80211_ATTR_STA_FLAGS, -+ NL80211_ATTR_STA_LISTEN_INTERVAL, -+ NL80211_ATTR_STA_SUPPORTED_RATES, -+ NL80211_ATTR_STA_VLAN, -+ NL80211_ATTR_STA_INFO, -+ -+ NL80211_ATTR_WIPHY_BANDS, -+ -+ NL80211_ATTR_MNTR_FLAGS, -+ -+ NL80211_ATTR_MESH_ID, -+ NL80211_ATTR_STA_PLINK_ACTION, -+ NL80211_ATTR_MPATH_NEXT_HOP, -+ NL80211_ATTR_MPATH_INFO, -+ -+ NL80211_ATTR_BSS_CTS_PROT, -+ NL80211_ATTR_BSS_SHORT_PREAMBLE, -+ NL80211_ATTR_BSS_SHORT_SLOT_TIME, -+ -+ NL80211_ATTR_HT_CAPABILITY, -+ -+ NL80211_ATTR_SUPPORTED_IFTYPES, -+ -+ NL80211_ATTR_REG_ALPHA2, -+ NL80211_ATTR_REG_RULES, -+ -+ NL80211_ATTR_MESH_PARAMS, -+ -+ NL80211_ATTR_BSS_BASIC_RATES, -+ -+ NL80211_ATTR_WIPHY_TXQ_PARAMS, -+ NL80211_ATTR_WIPHY_FREQ, -+ NL80211_ATTR_WIPHY_CHANNEL_TYPE, -+ -+ NL80211_ATTR_KEY_DEFAULT_MGMT, -+ -+ NL80211_ATTR_MGMT_SUBTYPE, -+ NL80211_ATTR_IE, -+ -+ NL80211_ATTR_MAX_NUM_SCAN_SSIDS, -+ -+ NL80211_ATTR_SCAN_FREQUENCIES, -+ NL80211_ATTR_SCAN_SSIDS, -+ NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */ -+ NL80211_ATTR_BSS, -+ -+ NL80211_ATTR_REG_INITIATOR, -+ NL80211_ATTR_REG_TYPE, -+ -+ NL80211_ATTR_SUPPORTED_COMMANDS, -+ -+ NL80211_ATTR_FRAME, -+ NL80211_ATTR_SSID, -+ NL80211_ATTR_AUTH_TYPE, -+ NL80211_ATTR_REASON_CODE, -+ -+ NL80211_ATTR_KEY_TYPE, -+ -+ NL80211_ATTR_MAX_SCAN_IE_LEN, -+ NL80211_ATTR_CIPHER_SUITES, -+ -+ NL80211_ATTR_FREQ_BEFORE, -+ NL80211_ATTR_FREQ_AFTER, -+ -+ NL80211_ATTR_FREQ_FIXED, -+ -+ -+ NL80211_ATTR_WIPHY_RETRY_SHORT, -+ NL80211_ATTR_WIPHY_RETRY_LONG, -+ NL80211_ATTR_WIPHY_FRAG_THRESHOLD, -+ NL80211_ATTR_WIPHY_RTS_THRESHOLD, -+ -+ NL80211_ATTR_TIMED_OUT, -+ -+ NL80211_ATTR_USE_MFP, -+ -+ NL80211_ATTR_STA_FLAGS2, -+ -+ NL80211_ATTR_CONTROL_PORT, -+ -+ NL80211_ATTR_TESTDATA, -+ -+ NL80211_ATTR_PRIVACY, -+ -+ NL80211_ATTR_DISCONNECTED_BY_AP, -+ NL80211_ATTR_STATUS_CODE, -+ -+ NL80211_ATTR_CIPHER_SUITES_PAIRWISE, -+ NL80211_ATTR_CIPHER_SUITE_GROUP, -+ NL80211_ATTR_WPA_VERSIONS, -+ NL80211_ATTR_AKM_SUITES, -+ -+ NL80211_ATTR_REQ_IE, -+ NL80211_ATTR_RESP_IE, -+ -+ NL80211_ATTR_PREV_BSSID, -+ -+ NL80211_ATTR_KEY, -+ NL80211_ATTR_KEYS, -+ -+ NL80211_ATTR_PID, -+ -+ NL80211_ATTR_4ADDR, -+ -+ NL80211_ATTR_SURVEY_INFO, -+ -+ NL80211_ATTR_PMKID, -+ NL80211_ATTR_MAX_NUM_PMKIDS, -+ -+ NL80211_ATTR_DURATION, -+ -+ NL80211_ATTR_COOKIE, -+ -+ NL80211_ATTR_WIPHY_COVERAGE_CLASS, -+ -+ NL80211_ATTR_TX_RATES, -+ -+ NL80211_ATTR_FRAME_MATCH, -+ -+ NL80211_ATTR_ACK, -+ -+ NL80211_ATTR_PS_STATE, -+ -+ NL80211_ATTR_CQM, -+ -+ NL80211_ATTR_LOCAL_STATE_CHANGE, -+ -+ NL80211_ATTR_AP_ISOLATE, -+ -+ NL80211_ATTR_WIPHY_TX_POWER_SETTING, -+ NL80211_ATTR_WIPHY_TX_POWER_LEVEL, -+ -+ NL80211_ATTR_TX_FRAME_TYPES, -+ NL80211_ATTR_RX_FRAME_TYPES, -+ NL80211_ATTR_FRAME_TYPE, -+ -+ NL80211_ATTR_CONTROL_PORT_ETHERTYPE, -+ NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, -+ -+ NL80211_ATTR_SUPPORT_IBSS_RSN, -+ -+ NL80211_ATTR_WIPHY_ANTENNA_TX, -+ NL80211_ATTR_WIPHY_ANTENNA_RX, -+ -+ NL80211_ATTR_MCAST_RATE, -+ -+ NL80211_ATTR_OFFCHANNEL_TX_OK, -+ -+ NL80211_ATTR_BSS_HT_OPMODE, -+ -+ NL80211_ATTR_KEY_DEFAULT_TYPES, -+ -+ NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, -+ -+ /* add attributes here, update the policy in nl80211.c */ -+ -+ __NL80211_ATTR_AFTER_LAST, -+ NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 -+}; -+ -+/* source-level API compatibility */ -+#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION -+ -+/* -+ * Allow user space programs to use #ifdef on new attributes by defining them -+ * here -+ */ -+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT -+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY -+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES -+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS -+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ -+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE -+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE -+#define NL80211_ATTR_IE NL80211_ATTR_IE -+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR -+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE -+#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME -+#define NL80211_ATTR_SSID NL80211_ATTR_SSID -+#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE -+#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE -+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE -+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP -+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS -+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES -+#define NL80211_ATTR_KEY NL80211_ATTR_KEY -+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS -+ -+#define NL80211_MAX_SUPP_RATES 32 -+#define NL80211_MAX_SUPP_REG_RULES 32 -+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 -+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 -+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 -+#define NL80211_HT_CAPABILITY_LEN 26 -+ -+#define NL80211_MAX_NR_CIPHER_SUITES 5 -+#define NL80211_MAX_NR_AKM_SUITES 2 -+ -+/** -+ * enum nl80211_iftype - (virtual) interface types -+ * -+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides -+ * @NL80211_IFTYPE_ADHOC: independent BSS member -+ * @NL80211_IFTYPE_STATION: managed BSS member -+ * @NL80211_IFTYPE_AP: access point -+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points -+ * @NL80211_IFTYPE_WDS: wireless distribution interface -+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames -+ * @NL80211_IFTYPE_MESH_POINT: mesh point -+ * @NL80211_IFTYPE_P2P_CLIENT: P2P client -+ * @NL80211_IFTYPE_P2P_GO: P2P group owner -+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined -+ * @NUM_NL80211_IFTYPES: number of defined interface types -+ * -+ * These values are used with the %NL80211_ATTR_IFTYPE -+ * to set the type of an interface. -+ * -+ */ -+enum nl80211_iftype { -+ NL80211_IFTYPE_UNSPECIFIED, -+ NL80211_IFTYPE_ADHOC, -+ NL80211_IFTYPE_STATION, -+ NL80211_IFTYPE_AP, -+ NL80211_IFTYPE_AP_VLAN, -+ NL80211_IFTYPE_WDS, -+ NL80211_IFTYPE_MONITOR, -+ NL80211_IFTYPE_MESH_POINT, -+ NL80211_IFTYPE_P2P_CLIENT, -+ NL80211_IFTYPE_P2P_GO, -+ -+ /* keep last */ -+ NUM_NL80211_IFTYPES, -+ NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1 -+}; -+ -+/** -+ * enum nl80211_sta_flags - station flags -+ * -+ * Station flags. When a station is added to an AP interface, it is -+ * assumed to be already associated (and hence authenticated.) -+ * -+ * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved -+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) -+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames -+ * with short barker preamble -+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable -+ * @NL80211_STA_FLAG_MFP: station uses management frame protection -+ * @NL80211_STA_FLAG_MAX: highest station flag number currently defined -+ * @__NL80211_STA_FLAG_AFTER_LAST: internal use -+ */ -+enum nl80211_sta_flags { -+ __NL80211_STA_FLAG_INVALID, -+ NL80211_STA_FLAG_AUTHORIZED, -+ NL80211_STA_FLAG_SHORT_PREAMBLE, -+ NL80211_STA_FLAG_WME, -+ NL80211_STA_FLAG_MFP, -+ -+ /* keep last */ -+ __NL80211_STA_FLAG_AFTER_LAST, -+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 -+}; -+ -+/** -+ * struct nl80211_sta_flag_update - station flags mask/set -+ * @mask: mask of station flags to set -+ * @set: which values to set them to -+ * -+ * Both mask and set contain bits as per &enum nl80211_sta_flags. -+ */ -+struct nl80211_sta_flag_update { -+ __u32 mask; -+ __u32 set; -+} __attribute__((packed)); -+ -+/** -+ * enum nl80211_rate_info - bitrate information -+ * -+ * These attribute types are used with %NL80211_STA_INFO_TXRATE -+ * when getting information about the bitrate of a station. -+ * -+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved -+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) -+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) -+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate -+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval -+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined -+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use -+ */ -+enum nl80211_rate_info { -+ __NL80211_RATE_INFO_INVALID, -+ NL80211_RATE_INFO_BITRATE, -+ NL80211_RATE_INFO_MCS, -+ NL80211_RATE_INFO_40_MHZ_WIDTH, -+ NL80211_RATE_INFO_SHORT_GI, -+ -+ /* keep last */ -+ __NL80211_RATE_INFO_AFTER_LAST, -+ NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_sta_info - station information -+ * -+ * These attribute types are used with %NL80211_ATTR_STA_INFO -+ * when getting information about a station. -+ * -+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved -+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) -+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) -+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) -+ * @__NL80211_STA_INFO_AFTER_LAST: internal -+ * @NL80211_STA_INFO_MAX: highest possible station info attribute -+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) -+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute -+ * containing info as possible, see &enum nl80211_sta_info_txrate. -+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) -+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this -+ * station) -+ * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station) -+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station) -+ * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) -+ */ -+enum nl80211_sta_info { -+ __NL80211_STA_INFO_INVALID, -+ NL80211_STA_INFO_INACTIVE_TIME, -+ NL80211_STA_INFO_RX_BYTES, -+ NL80211_STA_INFO_TX_BYTES, -+ NL80211_STA_INFO_LLID, -+ NL80211_STA_INFO_PLID, -+ NL80211_STA_INFO_PLINK_STATE, -+ NL80211_STA_INFO_SIGNAL, -+ NL80211_STA_INFO_TX_BITRATE, -+ NL80211_STA_INFO_RX_PACKETS, -+ NL80211_STA_INFO_TX_PACKETS, -+ NL80211_STA_INFO_TX_RETRIES, -+ NL80211_STA_INFO_TX_FAILED, -+ NL80211_STA_INFO_SIGNAL_AVG, -+ -+ /* keep last */ -+ __NL80211_STA_INFO_AFTER_LAST, -+ NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_mpath_flags - nl80211 mesh path flags -+ * -+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active -+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running -+ * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN -+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set -+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded -+ */ -+enum nl80211_mpath_flags { -+ NL80211_MPATH_FLAG_ACTIVE = 1<<0, -+ NL80211_MPATH_FLAG_RESOLVING = 1<<1, -+ NL80211_MPATH_FLAG_SN_VALID = 1<<2, -+ NL80211_MPATH_FLAG_FIXED = 1<<3, -+ NL80211_MPATH_FLAG_RESOLVED = 1<<4, -+}; -+ -+/** -+ * enum nl80211_mpath_info - mesh path information -+ * -+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting -+ * information about a mesh path. -+ * -+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved -+ * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination -+ * @NL80211_MPATH_INFO_SN: destination sequence number -+ * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path -+ * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now -+ * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in -+ * &enum nl80211_mpath_flags; -+ * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec -+ * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries -+ * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number -+ * currently defind -+ * @__NL80211_MPATH_INFO_AFTER_LAST: internal use -+ */ -+enum nl80211_mpath_info { -+ __NL80211_MPATH_INFO_INVALID, -+ NL80211_MPATH_INFO_FRAME_QLEN, -+ NL80211_MPATH_INFO_SN, -+ NL80211_MPATH_INFO_METRIC, -+ NL80211_MPATH_INFO_EXPTIME, -+ NL80211_MPATH_INFO_FLAGS, -+ NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, -+ NL80211_MPATH_INFO_DISCOVERY_RETRIES, -+ -+ /* keep last */ -+ __NL80211_MPATH_INFO_AFTER_LAST, -+ NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_band_attr - band attributes -+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved -+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, -+ * an array of nested frequency attributes -+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, -+ * an array of nested bitrate attributes -+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as -+ * defined in 802.11n -+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE -+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n -+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n -+ * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined -+ * @__NL80211_BAND_ATTR_AFTER_LAST: internal use -+ */ -+enum nl80211_band_attr { -+ __NL80211_BAND_ATTR_INVALID, -+ NL80211_BAND_ATTR_FREQS, -+ NL80211_BAND_ATTR_RATES, -+ -+ NL80211_BAND_ATTR_HT_MCS_SET, -+ NL80211_BAND_ATTR_HT_CAPA, -+ NL80211_BAND_ATTR_HT_AMPDU_FACTOR, -+ NL80211_BAND_ATTR_HT_AMPDU_DENSITY, -+ -+ /* keep last */ -+ __NL80211_BAND_ATTR_AFTER_LAST, -+ NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 -+}; -+ -+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA -+ -+/** -+ * enum nl80211_frequency_attr - frequency attributes -+ * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved -+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz -+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current -+ * regulatory domain. -+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is -+ * permitted on this channel in current regulatory domain. -+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted -+ * on this channel in current regulatory domain. -+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory -+ * on this channel in current regulatory domain. -+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm -+ * (100 * dBm). -+ * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number -+ * currently defined -+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use -+ */ -+enum nl80211_frequency_attr { -+ __NL80211_FREQUENCY_ATTR_INVALID, -+ NL80211_FREQUENCY_ATTR_FREQ, -+ NL80211_FREQUENCY_ATTR_DISABLED, -+ NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, -+ NL80211_FREQUENCY_ATTR_NO_IBSS, -+ NL80211_FREQUENCY_ATTR_RADAR, -+ NL80211_FREQUENCY_ATTR_MAX_TX_POWER, -+ -+ /* keep last */ -+ __NL80211_FREQUENCY_ATTR_AFTER_LAST, -+ NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 -+}; -+ -+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER -+ -+/** -+ * enum nl80211_bitrate_attr - bitrate attributes -+ * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved -+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps -+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported -+ * in 2.4 GHz band. -+ * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number -+ * currently defined -+ * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use -+ */ -+enum nl80211_bitrate_attr { -+ __NL80211_BITRATE_ATTR_INVALID, -+ NL80211_BITRATE_ATTR_RATE, -+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, -+ -+ /* keep last */ -+ __NL80211_BITRATE_ATTR_AFTER_LAST, -+ NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_initiator - Indicates the initiator of a reg domain request -+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world -+ * regulatory domain. -+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the -+ * regulatory domain. -+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the -+ * wireless core it thinks its knows the regulatory domain we should be in. -+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an -+ * 802.11 country information element with regulatory information it -+ * thinks we should consider. cfg80211 only processes the country -+ * code from the IE, and relies on the regulatory domain information -+ * structure pased by userspace (CRDA) from our wireless-regdb. -+ * If a channel is enabled but the country code indicates it should -+ * be disabled we disable the channel and re-enable it upon disassociation. -+ */ -+enum nl80211_reg_initiator { -+ NL80211_REGDOM_SET_BY_CORE, -+ NL80211_REGDOM_SET_BY_USER, -+ NL80211_REGDOM_SET_BY_DRIVER, -+ NL80211_REGDOM_SET_BY_COUNTRY_IE, -+}; -+ -+/** -+ * enum nl80211_reg_type - specifies the type of regulatory domain -+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains -+ * to a specific country. When this is set you can count on the -+ * ISO / IEC 3166 alpha2 country code being valid. -+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory -+ * domain. -+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom -+ * driver specific world regulatory domain. These do not apply system-wide -+ * and are only applicable to the individual devices which have requested -+ * them to be applied. -+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product -+ * of an intersection between two regulatory domains -- the previously -+ * set regulatory domain on the system and the last accepted regulatory -+ * domain request to be processed. -+ */ -+enum nl80211_reg_type { -+ NL80211_REGDOM_TYPE_COUNTRY, -+ NL80211_REGDOM_TYPE_WORLD, -+ NL80211_REGDOM_TYPE_CUSTOM_WORLD, -+ NL80211_REGDOM_TYPE_INTERSECTION, -+}; -+ -+/** -+ * enum nl80211_reg_rule_attr - regulatory rule attributes -+ * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved -+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional -+ * considerations for a given frequency range. These are the -+ * &enum nl80211_reg_rule_flags. -+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory -+ * rule in KHz. This is not a center of frequency but an actual regulatory -+ * band edge. -+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule -+ * in KHz. This is not a center a frequency but an actual regulatory -+ * band edge. -+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this -+ * frequency range, in KHz. -+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain -+ * for a given frequency range. The value is in mBi (100 * dBi). -+ * If you don't have one then don't send this. -+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for -+ * a given frequency range. The value is in mBm (100 * dBm). -+ * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number -+ * currently defined -+ * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use -+ */ -+enum nl80211_reg_rule_attr { -+ __NL80211_REG_RULE_ATTR_INVALID, -+ NL80211_ATTR_REG_RULE_FLAGS, -+ -+ NL80211_ATTR_FREQ_RANGE_START, -+ NL80211_ATTR_FREQ_RANGE_END, -+ NL80211_ATTR_FREQ_RANGE_MAX_BW, -+ -+ NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, -+ NL80211_ATTR_POWER_RULE_MAX_EIRP, -+ -+ /* keep last */ -+ __NL80211_REG_RULE_ATTR_AFTER_LAST, -+ NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_reg_rule_flags - regulatory rule flags -+ * -+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed -+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed -+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed -+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed -+ * @NL80211_RRF_DFS: DFS support is required to be used -+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links -+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links -+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required -+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed -+ */ -+enum nl80211_reg_rule_flags { -+ NL80211_RRF_NO_OFDM = 1<<0, -+ NL80211_RRF_NO_CCK = 1<<1, -+ NL80211_RRF_NO_INDOOR = 1<<2, -+ NL80211_RRF_NO_OUTDOOR = 1<<3, -+ NL80211_RRF_DFS = 1<<4, -+ NL80211_RRF_PTP_ONLY = 1<<5, -+ NL80211_RRF_PTMP_ONLY = 1<<6, -+ NL80211_RRF_PASSIVE_SCAN = 1<<7, -+ NL80211_RRF_NO_IBSS = 1<<8, -+}; -+ -+/** -+ * enum nl80211_survey_info - survey information -+ * -+ * These attribute types are used with %NL80211_ATTR_SURVEY_INFO -+ * when getting information about a survey. -+ * -+ * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved -+ * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel -+ * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) -+ * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used -+ * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio -+ * spent on this channel -+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary -+ * channel was sensed busy (either due to activity or energy detect) -+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension -+ * channel was sensed busy -+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent -+ * receiving data -+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent -+ * transmitting data -+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number -+ * currently defined -+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use -+ */ -+enum nl80211_survey_info { -+ __NL80211_SURVEY_INFO_INVALID, -+ NL80211_SURVEY_INFO_FREQUENCY, -+ NL80211_SURVEY_INFO_NOISE, -+ NL80211_SURVEY_INFO_IN_USE, -+ NL80211_SURVEY_INFO_CHANNEL_TIME, -+ NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, -+ NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, -+ NL80211_SURVEY_INFO_CHANNEL_TIME_RX, -+ NL80211_SURVEY_INFO_CHANNEL_TIME_TX, -+ -+ /* keep last */ -+ __NL80211_SURVEY_INFO_AFTER_LAST, -+ NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_mntr_flags - monitor configuration flags -+ * -+ * Monitor configuration flags. -+ * -+ * @__NL80211_MNTR_FLAG_INVALID: reserved -+ * -+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS -+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP -+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames -+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering -+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. -+ * overrides all other flags. -+ * -+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use -+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag -+ */ -+enum nl80211_mntr_flags { -+ __NL80211_MNTR_FLAG_INVALID, -+ NL80211_MNTR_FLAG_FCSFAIL, -+ NL80211_MNTR_FLAG_PLCPFAIL, -+ NL80211_MNTR_FLAG_CONTROL, -+ NL80211_MNTR_FLAG_OTHER_BSS, -+ NL80211_MNTR_FLAG_COOK_FRAMES, -+ -+ /* keep last */ -+ __NL80211_MNTR_FLAG_AFTER_LAST, -+ NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_meshconf_params - mesh configuration parameters -+ * -+ * Mesh configuration parameters -+ * -+ * @__NL80211_MESHCONF_INVALID: internal use -+ * -+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in -+ * millisecond units, used by the Peer Link Open message -+ * -+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in -+ * millisecond units, used by the peer link management to close a peer link -+ * -+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in -+ * millisecond units -+ * -+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed -+ * on this mesh interface -+ * -+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link -+ * open retries that can be sent to establish a new peer link instance in a -+ * mesh -+ * -+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh -+ * point. -+ * -+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a -+ * source mesh point for path selection elements. -+ * -+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically -+ * open peer links when we detect compatible mesh peers. -+ * -+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames -+ * containing a PREQ that an MP can send to a particular destination (path -+ * target) -+ * -+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths -+ * (in milliseconds) -+ * -+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait -+ * until giving up on a path discovery (in milliseconds) -+ * -+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh -+ * points receiving a PREQ shall consider the forwarding information from the -+ * root to be valid. (TU = time unit) -+ * -+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in -+ * TUs) during which an MP can send only one action frame containing a PREQ -+ * reference element -+ * -+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) -+ * that it takes for an HWMP information element to propagate across the mesh -+ * -+ * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not -+ * -+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute -+ * -+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use -+ */ -+enum nl80211_meshconf_params { -+ __NL80211_MESHCONF_INVALID, -+ NL80211_MESHCONF_RETRY_TIMEOUT, -+ NL80211_MESHCONF_CONFIRM_TIMEOUT, -+ NL80211_MESHCONF_HOLDING_TIMEOUT, -+ NL80211_MESHCONF_MAX_PEER_LINKS, -+ NL80211_MESHCONF_MAX_RETRIES, -+ NL80211_MESHCONF_TTL, -+ NL80211_MESHCONF_AUTO_OPEN_PLINKS, -+ NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, -+ NL80211_MESHCONF_PATH_REFRESH_TIME, -+ NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, -+ NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, -+ NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, -+ NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, -+ NL80211_MESHCONF_HWMP_ROOTMODE, -+ NL80211_MESHCONF_ELEMENT_TTL, -+ -+ /* keep last */ -+ __NL80211_MESHCONF_ATTR_AFTER_LAST, -+ NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_txq_attr - TX queue parameter attributes -+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved -+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) -+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning -+ * disabled -+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form -+ * 2^n-1 in the range 1..32767] -+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form -+ * 2^n-1 in the range 1..32767] -+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] -+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal -+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number -+ */ -+enum nl80211_txq_attr { -+ __NL80211_TXQ_ATTR_INVALID, -+ NL80211_TXQ_ATTR_QUEUE, -+ NL80211_TXQ_ATTR_TXOP, -+ NL80211_TXQ_ATTR_CWMIN, -+ NL80211_TXQ_ATTR_CWMAX, -+ NL80211_TXQ_ATTR_AIFS, -+ -+ /* keep last */ -+ __NL80211_TXQ_ATTR_AFTER_LAST, -+ NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 -+}; -+ -+enum nl80211_txq_q { -+ NL80211_TXQ_Q_VO, -+ NL80211_TXQ_Q_VI, -+ NL80211_TXQ_Q_BE, -+ NL80211_TXQ_Q_BK -+}; -+ -+enum nl80211_channel_type { -+ NL80211_CHAN_NO_HT, -+ NL80211_CHAN_HT20, -+ NL80211_CHAN_HT40MINUS, -+ NL80211_CHAN_HT40PLUS -+}; -+ -+/** -+ * enum nl80211_bss - netlink attributes for a BSS -+ * -+ * @__NL80211_BSS_INVALID: invalid -+ * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets) -+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32) -+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64) -+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) -+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) -+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the -+ * raw information elements from the probe response/beacon (bin); -+ * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are -+ * from a Probe Response frame; otherwise they are from a Beacon frame. -+ * However, if the driver does not indicate the source of the IEs, these -+ * IEs may be from either frame subtype. -+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon -+ * in mBm (100 * dBm) (s32) -+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon -+ * in unspecified units, scaled to 0..100 (u8) -+ * @NL80211_BSS_STATUS: status, if this BSS is "used" -+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms -+ * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information -+ * elements from a Beacon frame (bin); not present if no Beacon frame has -+ * yet been received -+ * @__NL80211_BSS_AFTER_LAST: internal -+ * @NL80211_BSS_MAX: highest BSS attribute -+ */ -+enum nl80211_bss { -+ __NL80211_BSS_INVALID, -+ NL80211_BSS_BSSID, -+ NL80211_BSS_FREQUENCY, -+ NL80211_BSS_TSF, -+ NL80211_BSS_BEACON_INTERVAL, -+ NL80211_BSS_CAPABILITY, -+ NL80211_BSS_INFORMATION_ELEMENTS, -+ NL80211_BSS_SIGNAL_MBM, -+ NL80211_BSS_SIGNAL_UNSPEC, -+ NL80211_BSS_STATUS, -+ NL80211_BSS_SEEN_MS_AGO, -+ NL80211_BSS_BEACON_IES, -+ -+ /* keep last */ -+ __NL80211_BSS_AFTER_LAST, -+ NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_bss_status - BSS "status" -+ * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS. -+ * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS. -+ * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS. -+ * -+ * The BSS status is a BSS attribute in scan dumps, which -+ * indicates the status the interface has wrt. this BSS. -+ */ -+enum nl80211_bss_status { -+ NL80211_BSS_STATUS_AUTHENTICATED, -+ NL80211_BSS_STATUS_ASSOCIATED, -+ NL80211_BSS_STATUS_IBSS_JOINED, -+}; -+ -+/** -+ * enum nl80211_auth_type - AuthenticationType -+ * -+ * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication -+ * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) -+ * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) -+ * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) -+ * @__NL80211_AUTHTYPE_NUM: internal -+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm -+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by -+ * trying multiple times); this is invalid in netlink -- leave out -+ * the attribute for this on CONNECT commands. -+ */ -+enum nl80211_auth_type { -+ NL80211_AUTHTYPE_OPEN_SYSTEM, -+ NL80211_AUTHTYPE_SHARED_KEY, -+ NL80211_AUTHTYPE_FT, -+ NL80211_AUTHTYPE_NETWORK_EAP, -+ -+ /* keep last */ -+ __NL80211_AUTHTYPE_NUM, -+ NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1, -+ NL80211_AUTHTYPE_AUTOMATIC -+}; -+ -+/** -+ * enum nl80211_key_type - Key Type -+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key -+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key -+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS) -+ * @NUM_NL80211_KEYTYPES: number of defined key types -+ */ -+enum nl80211_key_type { -+ NL80211_KEYTYPE_GROUP, -+ NL80211_KEYTYPE_PAIRWISE, -+ NL80211_KEYTYPE_PEERKEY, -+ -+ NUM_NL80211_KEYTYPES -+}; -+ -+/** -+ * enum nl80211_mfp - Management frame protection state -+ * @NL80211_MFP_NO: Management frame protection not used -+ * @NL80211_MFP_REQUIRED: Management frame protection required -+ */ -+enum nl80211_mfp { -+ NL80211_MFP_NO, -+ NL80211_MFP_REQUIRED, -+}; -+ -+enum nl80211_wpa_versions { -+ NL80211_WPA_VERSION_1 = 1 << 0, -+ NL80211_WPA_VERSION_2 = 1 << 1, -+}; -+ -+/** -+ * enum nl80211_key_default_types - key default types -+ * @__NL80211_KEY_DEFAULT_TYPE_INVALID: invalid -+ * @NL80211_KEY_DEFAULT_TYPE_UNICAST: key should be used as default -+ * unicast key -+ * @NL80211_KEY_DEFAULT_TYPE_MULTICAST: key should be used as default -+ * multicast key -+ * @NUM_NL80211_KEY_DEFAULT_TYPES: number of default types -+ */ -+enum nl80211_key_default_types { -+ __NL80211_KEY_DEFAULT_TYPE_INVALID, -+ NL80211_KEY_DEFAULT_TYPE_UNICAST, -+ NL80211_KEY_DEFAULT_TYPE_MULTICAST, -+ -+ NUM_NL80211_KEY_DEFAULT_TYPES -+}; -+ -+/** -+ * enum nl80211_key_attributes - key attributes -+ * @__NL80211_KEY_INVALID: invalid -+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of -+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC -+ * keys -+ * @NL80211_KEY_IDX: key ID (u8, 0-3) -+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 -+ * section 7.3.2.25.1, e.g. 0x000FAC04) -+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and -+ * CCMP keys, each six bytes in little endian -+ * @NL80211_KEY_DEFAULT: flag indicating default key -+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key -+ * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not -+ * specified the default depends on whether a MAC address was -+ * given with the command using the key or not (u32) -+ * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags -+ * attributes, specifying what a key should be set as default as. -+ * See &enum nl80211_key_default_types. -+ * @__NL80211_KEY_AFTER_LAST: internal -+ * @NL80211_KEY_MAX: highest key attribute -+ */ -+enum nl80211_key_attributes { -+ __NL80211_KEY_INVALID, -+ NL80211_KEY_DATA, -+ NL80211_KEY_IDX, -+ NL80211_KEY_CIPHER, -+ NL80211_KEY_SEQ, -+ NL80211_KEY_DEFAULT, -+ NL80211_KEY_DEFAULT_MGMT, -+ NL80211_KEY_TYPE, -+ NL80211_KEY_DEFAULT_TYPES, -+ -+ /* keep last */ -+ __NL80211_KEY_AFTER_LAST, -+ NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_tx_rate_attributes - TX rate set attributes -+ * @__NL80211_TXRATE_INVALID: invalid -+ * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection -+ * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with -+ * 1 = 500 kbps) but without the IE length restriction (at most -+ * %NL80211_MAX_SUPP_RATES in a single array). -+ * @__NL80211_TXRATE_AFTER_LAST: internal -+ * @NL80211_TXRATE_MAX: highest TX rate attribute -+ */ -+enum nl80211_tx_rate_attributes { -+ __NL80211_TXRATE_INVALID, -+ NL80211_TXRATE_LEGACY, -+ -+ /* keep last */ -+ __NL80211_TXRATE_AFTER_LAST, -+ NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 -+}; -+ -+/** -+ * 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) -+ */ -+enum nl80211_band { -+ NL80211_BAND_2GHZ, -+ NL80211_BAND_5GHZ, -+}; -+ -+enum nl80211_ps_state { -+ NL80211_PS_DISABLED, -+ NL80211_PS_ENABLED, -+}; -+ -+/** -+ * enum nl80211_attr_cqm - connection quality monitor attributes -+ * @__NL80211_ATTR_CQM_INVALID: invalid -+ * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies -+ * the threshold for the RSSI level at which an event will be sent. Zero -+ * to disable. -+ * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies -+ * the minimum amount the RSSI level must change after an event before a -+ * new event may be issued (to reduce effects of RSSI oscillation). -+ * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event -+ * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many -+ * consecutive packets were not acknowledged by the peer -+ * @__NL80211_ATTR_CQM_AFTER_LAST: internal -+ * @NL80211_ATTR_CQM_MAX: highest key attribute -+ */ -+enum nl80211_attr_cqm { -+ __NL80211_ATTR_CQM_INVALID, -+ NL80211_ATTR_CQM_RSSI_THOLD, -+ NL80211_ATTR_CQM_RSSI_HYST, -+ NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, -+ NL80211_ATTR_CQM_PKT_LOSS_EVENT, -+ -+ /* keep last */ -+ __NL80211_ATTR_CQM_AFTER_LAST, -+ NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1 -+}; -+ -+/** -+ * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event -+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the -+ * configured threshold -+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the -+ * configured threshold -+ */ -+enum nl80211_cqm_rssi_threshold_event { -+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, -+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, -+}; -+ -+ -+/** -+ * enum nl80211_tx_power_setting - TX power adjustment -+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power -+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter -+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter -+ */ -+enum nl80211_tx_power_setting { -+ NL80211_TX_POWER_AUTOMATIC, -+ NL80211_TX_POWER_LIMITED, -+ NL80211_TX_POWER_FIXED, -+}; -+ -+#endif /* __LINUX_NL80211_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/priv_netlink.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/priv_netlink.h -new file mode 100644 -index 0000000000000..23eff83fadd43 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/priv_netlink.h -@@ -0,0 +1,113 @@ -+/* -+ * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions. -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PRIV_NETLINK_H -+#define PRIV_NETLINK_H -+ -+/* -+ * This should be replaced with user space header once one is available with C -+ * library, etc.. -+ */ -+ -+#ifndef IFF_LOWER_UP -+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ -+#endif -+#ifndef IFF_DORMANT -+#define IFF_DORMANT 0x20000 /* driver signals dormant */ -+#endif -+ -+#ifndef IFLA_IFNAME -+#define IFLA_IFNAME 3 -+#endif -+#ifndef IFLA_WIRELESS -+#define IFLA_WIRELESS 11 -+#endif -+#ifndef IFLA_OPERSTATE -+#define IFLA_OPERSTATE 16 -+#endif -+#ifndef IFLA_LINKMODE -+#define IFLA_LINKMODE 17 -+#define IF_OPER_DORMANT 5 -+#define IF_OPER_UP 6 -+#endif -+ -+#define NLM_F_REQUEST 1 -+ -+#define NETLINK_ROUTE 0 -+#define RTMGRP_LINK 1 -+#define RTM_BASE 0x10 -+#define RTM_NEWLINK (RTM_BASE + 0) -+#define RTM_DELLINK (RTM_BASE + 1) -+#define RTM_SETLINK (RTM_BASE + 3) -+ -+#define NLMSG_ALIGNTO 4 -+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1)) -+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) -+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr))) -+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) -+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0))) -+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ -+ (struct nlmsghdr *) \ -+ (((char *)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) -+#define NLMSG_OK(nlh,len) ((len) >= (int) sizeof(struct nlmsghdr) && \ -+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ -+ (int) (nlh)->nlmsg_len <= (len)) -+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) -+ -+#define RTA_ALIGNTO 4 -+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1)) -+#define RTA_OK(rta,len) \ -+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \ -+(rta)->rta_len <= (len)) -+#define RTA_NEXT(rta,attrlen) \ -+((attrlen) -= RTA_ALIGN((rta)->rta_len), \ -+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len))) -+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) -+#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0))) -+ -+ -+struct sockaddr_nl -+{ -+ sa_family_t nl_family; -+ unsigned short nl_pad; -+ u32 nl_pid; -+ u32 nl_groups; -+}; -+ -+struct nlmsghdr -+{ -+ u32 nlmsg_len; -+ u16 nlmsg_type; -+ u16 nlmsg_flags; -+ u32 nlmsg_seq; -+ u32 nlmsg_pid; -+}; -+ -+struct ifinfomsg -+{ -+ unsigned char ifi_family; -+ unsigned char __ifi_pad; -+ unsigned short ifi_type; -+ int ifi_index; -+ unsigned ifi_flags; -+ unsigned ifi_change; -+}; -+ -+struct rtattr -+{ -+ unsigned short rta_len; -+ unsigned short rta_type; -+}; -+ -+#endif /* PRIV_NETLINK_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.c -new file mode 100644 -index 0000000000000..88183110f7099 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.c -@@ -0,0 +1,194 @@ -+/* -+ * Linux rfkill helper functions for driver wrappers -+ * Copyright (c) 2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "rfkill.h" -+ -+#define RFKILL_EVENT_SIZE_V1 8 -+ -+struct rfkill_event { -+ u32 idx; -+ u8 type; -+ u8 op; -+ u8 soft; -+ u8 hard; -+} STRUCT_PACKED; -+ -+enum rfkill_operation { -+ RFKILL_OP_ADD = 0, -+ RFKILL_OP_DEL, -+ RFKILL_OP_CHANGE, -+ RFKILL_OP_CHANGE_ALL, -+}; -+ -+enum rfkill_type { -+ RFKILL_TYPE_ALL = 0, -+ RFKILL_TYPE_WLAN, -+ RFKILL_TYPE_BLUETOOTH, -+ RFKILL_TYPE_UWB, -+ RFKILL_TYPE_WIMAX, -+ RFKILL_TYPE_WWAN, -+ RFKILL_TYPE_GPS, -+ RFKILL_TYPE_FM, -+ NUM_RFKILL_TYPES, -+}; -+ -+ -+struct rfkill_data { -+ struct rfkill_config *cfg; -+ int fd; -+ int blocked; -+}; -+ -+ -+static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct rfkill_data *rfkill = eloop_ctx; -+ struct rfkill_event event; -+ ssize_t len; -+ int new_blocked; -+ -+ len = read(rfkill->fd, &event, sizeof(event)); -+ if (len < 0) { -+ wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", -+ strerror(errno)); -+ return; -+ } -+ if (len != RFKILL_EVENT_SIZE_V1) { -+ wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " -+ "%d (expected %d)", -+ (int) len, RFKILL_EVENT_SIZE_V1); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d " -+ "op=%u soft=%u hard=%u", -+ event.idx, event.type, event.op, event.soft, -+ event.hard); -+ if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN) -+ return; -+ -+ if (event.hard) { -+ wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); -+ new_blocked = 1; -+ } else if (event.soft) { -+ wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); -+ new_blocked = 1; -+ } else { -+ wpa_printf(MSG_INFO, "rfkill: WLAN unblocked"); -+ new_blocked = 0; -+ } -+ -+ if (new_blocked != rfkill->blocked) { -+ rfkill->blocked = new_blocked; -+ if (new_blocked) -+ rfkill->cfg->blocked_cb(rfkill->cfg->ctx); -+ else -+ rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); -+ } -+} -+ -+ -+struct rfkill_data * rfkill_init(struct rfkill_config *cfg) -+{ -+ struct rfkill_data *rfkill; -+ struct rfkill_event event; -+ ssize_t len; -+ -+ rfkill = os_zalloc(sizeof(*rfkill)); -+ if (rfkill == NULL) -+ return NULL; -+ -+ rfkill->cfg = cfg; -+ rfkill->fd = open("/dev/rfkill", O_RDONLY); -+ if (rfkill->fd < 0) { -+ wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control " -+ "device"); -+ goto fail; -+ } -+ -+ if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) { -+ wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: " -+ "%s", strerror(errno)); -+ goto fail2; -+ } -+ -+ for (;;) { -+ len = read(rfkill->fd, &event, sizeof(event)); -+ if (len < 0) { -+ if (errno == EAGAIN) -+ break; /* No more entries */ -+ wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", -+ strerror(errno)); -+ break; -+ } -+ if (len != RFKILL_EVENT_SIZE_V1) { -+ wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " -+ "%d (expected %d)", -+ (int) len, RFKILL_EVENT_SIZE_V1); -+ continue; -+ } -+ wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d " -+ "op=%u soft=%u hard=%u", -+ event.idx, event.type, event.op, event.soft, -+ event.hard); -+ if (event.op != RFKILL_OP_ADD || -+ event.type != RFKILL_TYPE_WLAN) -+ continue; -+ if (event.hard) { -+ wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); -+ rfkill->blocked = 1; -+ } else if (event.soft) { -+ wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); -+ rfkill->blocked = 1; -+ } -+ } -+ -+ eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); -+ -+ return rfkill; -+ -+fail2: -+ close(rfkill->fd); -+fail: -+ os_free(rfkill); -+ return NULL; -+} -+ -+ -+void rfkill_deinit(struct rfkill_data *rfkill) -+{ -+ if (rfkill == NULL) -+ return; -+ -+ if (rfkill->fd >= 0) { -+ eloop_unregister_read_sock(rfkill->fd); -+ close(rfkill->fd); -+ } -+ -+ os_free(rfkill->cfg); -+ os_free(rfkill); -+} -+ -+ -+int rfkill_is_blocked(struct rfkill_data *rfkill) -+{ -+ if (rfkill == NULL) -+ return 0; -+ -+ return rfkill->blocked; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.h -new file mode 100644 -index 0000000000000..7a984a63187f2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/rfkill.h -@@ -0,0 +1,31 @@ -+/* -+ * Linux rfkill helper functions for driver wrappers -+ * Copyright (c) 2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef RFKILL_H -+#define RFKILL_H -+ -+struct rfkill_data; -+ -+struct rfkill_config { -+ void *ctx; -+ char ifname[IFNAMSIZ]; -+ void (*blocked_cb)(void *ctx); -+ void (*unblocked_cb)(void *ctx); -+}; -+ -+struct rfkill_data * rfkill_init(struct rfkill_config *cfg); -+void rfkill_deinit(struct rfkill_data *rfkill); -+int rfkill_is_blocked(struct rfkill_data *rfkill); -+ -+#endif /* RFKILL_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/wireless_copy.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/wireless_copy.h -new file mode 100644 -index 0000000000000..201719b642c87 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/drivers/wireless_copy.h -@@ -0,0 +1,1185 @@ -+/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 22. -+ * I have just removed kernel related headers and added some typedefs etc. to -+ * make this easier to include into user space programs. -+ * Jouni Malinen, 2005-03-12. -+ */ -+ -+ -+/* -+ * This file define a set of standard wireless extensions -+ * -+ * Version : 22 16.3.07 -+ * -+ * Authors : Jean Tourrilhes - HPL - -+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. -+ */ -+ -+#ifndef _LINUX_WIRELESS_H -+#define _LINUX_WIRELESS_H -+ -+/************************** DOCUMENTATION **************************/ -+/* -+ * Initial APIs (1996 -> onward) : -+ * ----------------------------- -+ * Basically, the wireless extensions are for now a set of standard ioctl -+ * call + /proc/net/wireless -+ * -+ * The entry /proc/net/wireless give statistics and information on the -+ * driver. -+ * This is better than having each driver having its entry because -+ * its centralised and we may remove the driver module safely. -+ * -+ * Ioctl are used to configure the driver and issue commands. This is -+ * better than command line options of insmod because we may want to -+ * change dynamically (while the driver is running) some parameters. -+ * -+ * The ioctl mechanimsm are copied from standard devices ioctl. -+ * We have the list of command plus a structure descibing the -+ * data exchanged... -+ * Note that to add these ioctl, I was obliged to modify : -+ * # net/core/dev.c (two place + add include) -+ * # net/ipv4/af_inet.c (one place + add include) -+ * -+ * /proc/net/wireless is a copy of /proc/net/dev. -+ * We have a structure for data passed from the driver to /proc/net/wireless -+ * Too add this, I've modified : -+ * # net/core/dev.c (two other places) -+ * # include/linux/netdevice.h (one place) -+ * # include/linux/proc_fs.h (one place) -+ * -+ * New driver API (2002 -> onward) : -+ * ------------------------------- -+ * This file is only concerned with the user space API and common definitions. -+ * The new driver API is defined and documented in : -+ * # include/net/iw_handler.h -+ * -+ * Note as well that /proc/net/wireless implementation has now moved in : -+ * # net/core/wireless.c -+ * -+ * Wireless Events (2002 -> onward) : -+ * -------------------------------- -+ * Events are defined at the end of this file, and implemented in : -+ * # net/core/wireless.c -+ * -+ * Other comments : -+ * -------------- -+ * Do not add here things that are redundant with other mechanisms -+ * (drivers init, ifconfig, /proc/net/dev, ...) and with are not -+ * wireless specific. -+ * -+ * These wireless extensions are not magic : each driver has to provide -+ * support for them... -+ * -+ * IMPORTANT NOTE : As everything in the kernel, this is very much a -+ * work in progress. Contact me if you have ideas of improvements... -+ */ -+ -+/***************************** INCLUDES *****************************/ -+ -+ /* jkm - replaced linux headers with C library headers, added typedefs */ -+#if 0 -+#include /* for __u* and __s* typedefs */ -+#include /* for "struct sockaddr" et al */ -+#include /* for IFNAMSIZ and co... */ -+#else -+#include -+#include -+#ifndef ANDROID -+typedef __uint32_t __u32; -+typedef __int32_t __s32; -+typedef __uint16_t __u16; -+typedef __int16_t __s16; -+typedef __uint8_t __u8; -+#endif /* ANDROID */ -+#ifndef __user -+#define __user -+#endif /* __user */ -+#endif -+ -+/***************************** VERSION *****************************/ -+/* -+ * This constant is used to know the availability of the wireless -+ * extensions and to know which version of wireless extensions it is -+ * (there is some stuff that will be added in the future...) -+ * I just plan to increment with each new version. -+ */ -+#define WIRELESS_EXT 22 -+ -+/* -+ * Changes : -+ * -+ * V2 to V3 -+ * -------- -+ * Alan Cox start some incompatibles changes. I've integrated a bit more. -+ * - Encryption renamed to Encode to avoid US regulation problems -+ * - Frequency changed from float to struct to avoid problems on old 386 -+ * -+ * V3 to V4 -+ * -------- -+ * - Add sensitivity -+ * -+ * V4 to V5 -+ * -------- -+ * - Missing encoding definitions in range -+ * - Access points stuff -+ * -+ * V5 to V6 -+ * -------- -+ * - 802.11 support (ESSID ioctls) -+ * -+ * V6 to V7 -+ * -------- -+ * - define IW_ESSID_MAX_SIZE and IW_MAX_AP -+ * -+ * V7 to V8 -+ * -------- -+ * - Changed my e-mail address -+ * - More 802.11 support (nickname, rate, rts, frag) -+ * - List index in frequencies -+ * -+ * V8 to V9 -+ * -------- -+ * - Support for 'mode of operation' (ad-hoc, managed...) -+ * - Support for unicast and multicast power saving -+ * - Change encoding to support larger tokens (>64 bits) -+ * - Updated iw_params (disable, flags) and use it for NWID -+ * - Extracted iw_point from iwreq for clarity -+ * -+ * V9 to V10 -+ * --------- -+ * - Add PM capability to range structure -+ * - Add PM modifier : MAX/MIN/RELATIVE -+ * - Add encoding option : IW_ENCODE_NOKEY -+ * - Add TxPower ioctls (work like TxRate) -+ * -+ * V10 to V11 -+ * ---------- -+ * - Add WE version in range (help backward/forward compatibility) -+ * - Add retry ioctls (work like PM) -+ * -+ * V11 to V12 -+ * ---------- -+ * - Add SIOCSIWSTATS to get /proc/net/wireless programatically -+ * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space -+ * - Add new statistics (frag, retry, beacon) -+ * - Add average quality (for user space calibration) -+ * -+ * V12 to V13 -+ * ---------- -+ * - Document creation of new driver API. -+ * - Extract union iwreq_data from struct iwreq (for new driver API). -+ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT -+ * -+ * V13 to V14 -+ * ---------- -+ * - Wireless Events support : define struct iw_event -+ * - Define additional specific event numbers -+ * - Add "addr" and "param" fields in union iwreq_data -+ * - AP scanning stuff (SIOCSIWSCAN and friends) -+ * -+ * V14 to V15 -+ * ---------- -+ * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg -+ * - Make struct iw_freq signed (both m & e), add explicit padding -+ * - Add IWEVCUSTOM for driver specific event/scanning token -+ * - Add IW_MAX_GET_SPY for driver returning a lot of addresses -+ * - Add IW_TXPOW_RANGE for range of Tx Powers -+ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points -+ * - Add IW_MODE_MONITOR for passive monitor -+ * -+ * V15 to V16 -+ * ---------- -+ * - Increase the number of bitrates in iw_range to 32 (for 802.11g) -+ * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) -+ * - Reshuffle struct iw_range for increases, add filler -+ * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses -+ * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support -+ * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" -+ * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index -+ * -+ * V16 to V17 -+ * ---------- -+ * - Add flags to frequency -> auto/fixed -+ * - Document (struct iw_quality *)->updated, add new flags (INVALID) -+ * - Wireless Event capability in struct iw_range -+ * - Add support for relative TxPower (yick !) -+ * -+ * V17 to V18 (From Jouni Malinen ) -+ * ---------- -+ * - Add support for WPA/WPA2 -+ * - Add extended encoding configuration (SIOCSIWENCODEEXT and -+ * SIOCGIWENCODEEXT) -+ * - Add SIOCSIWGENIE/SIOCGIWGENIE -+ * - Add SIOCSIWMLME -+ * - Add SIOCSIWPMKSA -+ * - Add struct iw_range bit field for supported encoding capabilities -+ * - Add optional scan request parameters for SIOCSIWSCAN -+ * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA -+ * related parameters (extensible up to 4096 parameter values) -+ * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, -+ * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND -+ * -+ * V18 to V19 -+ * ---------- -+ * - Remove (struct iw_point *)->pointer from events and streams -+ * - Remove header includes to help user space -+ * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 -+ * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros -+ * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM -+ * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros -+ * -+ * V19 to V20 -+ * ---------- -+ * - RtNetlink requests support (SET/GET) -+ * -+ * V20 to V21 -+ * ---------- -+ * - Remove (struct net_device *)->get_wireless_stats() -+ * - Change length in ESSID and NICK to strlen() instead of strlen()+1 -+ * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers -+ * - Power/Retry relative values no longer * 100000 -+ * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI -+ * -+ * V21 to V22 -+ * ---------- -+ * - Prevent leaking of kernel space in stream on 64 bits. -+ */ -+ -+/**************************** CONSTANTS ****************************/ -+ -+/* -------------------------- IOCTL LIST -------------------------- */ -+ -+/* Wireless Identification */ -+#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ -+#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ -+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. -+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... -+ * Don't put the name of your driver there, it's useless. */ -+ -+/* Basic operations */ -+#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ -+#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ -+#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ -+#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ -+#define SIOCSIWMODE 0x8B06 /* set operation mode */ -+#define SIOCGIWMODE 0x8B07 /* get operation mode */ -+#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ -+#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ -+ -+/* Informative stuff */ -+#define SIOCSIWRANGE 0x8B0A /* Unused */ -+#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ -+#define SIOCSIWPRIV 0x8B0C /* Unused */ -+#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ -+#define SIOCSIWSTATS 0x8B0E /* Unused */ -+#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ -+/* SIOCGIWSTATS is strictly used between user space and the kernel, and -+ * is never passed to the driver (i.e. the driver will never see it). */ -+ -+/* Spy support (statistics per MAC address - used for Mobile IP support) */ -+#define SIOCSIWSPY 0x8B10 /* set spy addresses */ -+#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ -+#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ -+#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ -+ -+/* Access Point manipulation */ -+#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ -+#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ -+#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ -+#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ -+#define SIOCGIWSCAN 0x8B19 /* get scanning results */ -+ -+/* 802.11 specific support */ -+#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ -+#define SIOCGIWESSID 0x8B1B /* get ESSID */ -+#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ -+#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ -+/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit -+ * within the 'iwreq' structure, so we need to use the 'data' member to -+ * point to a string in user space, like it is done for RANGE... */ -+ -+/* Other parameters useful in 802.11 and some other devices */ -+#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ -+#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ -+#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ -+#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ -+#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ -+#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ -+#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ -+#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ -+#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ -+#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ -+ -+/* Encoding stuff (scrambling, hardware security, WEP...) */ -+#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ -+#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ -+/* Power saving stuff (power management, unicast and multicast) */ -+#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ -+#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ -+ -+/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). -+ * This ioctl uses struct iw_point and data buffer that includes IE id and len -+ * fields. More than one IE may be included in the request. Setting the generic -+ * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers -+ * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers -+ * are required to report the used IE as a wireless event, e.g., when -+ * associating with an AP. */ -+#define SIOCSIWGENIE 0x8B30 /* set generic IE */ -+#define SIOCGIWGENIE 0x8B31 /* get generic IE */ -+ -+/* WPA : IEEE 802.11 MLME requests */ -+#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses -+ * struct iw_mlme */ -+/* WPA : Authentication mode parameters */ -+#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ -+#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ -+ -+/* WPA : Extended version of encoding configuration */ -+#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ -+#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ -+ -+/* WPA2 : PMKSA cache management */ -+#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ -+ -+/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ -+ -+/* These 32 ioctl are wireless device private, for 16 commands. -+ * Each driver is free to use them for whatever purpose it chooses, -+ * however the driver *must* export the description of those ioctls -+ * with SIOCGIWPRIV and *must* use arguments as defined below. -+ * If you don't follow those rules, DaveM is going to hate you (reason : -+ * it make mixed 32/64bit operation impossible). -+ */ -+#define SIOCIWFIRSTPRIV 0x8BE0 -+#define SIOCIWLASTPRIV 0x8BFF -+/* Previously, we were using SIOCDEVPRIVATE, but we now have our -+ * separate range because of collisions with other tools such as -+ * 'mii-tool'. -+ * We now have 32 commands, so a bit more space ;-). -+ * Also, all 'even' commands are only usable by root and don't return the -+ * content of ifr/iwr to user (but you are not obliged to use the set/get -+ * convention, just use every other two command). More details in iwpriv.c. -+ * And I repeat : you are not forced to use them with iwpriv, but you -+ * must be compliant with it. -+ */ -+ -+/* ------------------------- IOCTL STUFF ------------------------- */ -+ -+/* The first and the last (range) */ -+#define SIOCIWFIRST 0x8B00 -+#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ -+#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) -+#define IW_HANDLER(id, func) \ -+ [IW_IOCTL_IDX(id)] = func -+ -+/* Odd : get (world access), even : set (root access) */ -+#define IW_IS_SET(cmd) (!((cmd) & 0x1)) -+#define IW_IS_GET(cmd) ((cmd) & 0x1) -+ -+/* ----------------------- WIRELESS EVENTS ----------------------- */ -+/* Those are *NOT* ioctls, do not issue request on them !!! */ -+/* Most events use the same identifier as ioctl requests */ -+ -+#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ -+#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ -+#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ -+#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ -+#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ -+#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) -+ * (scan results); This includes id and -+ * length fields. One IWEVGENIE may -+ * contain more than one IE. Scan -+ * results may contain one or more -+ * IWEVGENIE events. */ -+#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure -+ * (struct iw_michaelmicfailure) -+ */ -+#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. -+ * The data includes id and length -+ * fields and may contain more than one -+ * IE. This event is required in -+ * Managed mode if the driver -+ * generates its own WPA/RSN IE. This -+ * should be sent just before -+ * IWEVREGISTERED event for the -+ * association. */ -+#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association -+ * Response. The data includes id and -+ * length fields and may contain more -+ * than one IE. This may be sent -+ * between IWEVASSOCREQIE and -+ * IWEVREGISTERED events for the -+ * association. */ -+#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN -+ * pre-authentication -+ * (struct iw_pmkid_cand) */ -+ -+#define IWEVFIRST 0x8C00 -+#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) -+ -+/* ------------------------- PRIVATE INFO ------------------------- */ -+/* -+ * The following is used with SIOCGIWPRIV. It allow a driver to define -+ * the interface (name, type of data) for its private ioctl. -+ * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV -+ */ -+ -+#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ -+#define IW_PRIV_TYPE_NONE 0x0000 -+#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ -+#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ -+#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ -+#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ -+#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ -+ -+#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ -+ -+#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ -+ -+/* -+ * Note : if the number of args is fixed and the size < 16 octets, -+ * instead of passing a pointer we will put args in the iwreq struct... -+ */ -+ -+/* ----------------------- OTHER CONSTANTS ----------------------- */ -+ -+/* Maximum frequencies in the range struct */ -+#define IW_MAX_FREQUENCIES 32 -+/* Note : if you have something like 80 frequencies, -+ * don't increase this constant and don't fill the frequency list. -+ * The user will be able to set by channel anyway... */ -+ -+/* Maximum bit rates in the range struct */ -+#define IW_MAX_BITRATES 32 -+ -+/* Maximum tx powers in the range struct */ -+#define IW_MAX_TXPOWER 8 -+/* Note : if you more than 8 TXPowers, just set the max and min or -+ * a few of them in the struct iw_range. */ -+ -+/* Maximum of address that you may set with SPY */ -+#define IW_MAX_SPY 8 -+ -+/* Maximum of address that you may get in the -+ list of access points in range */ -+#define IW_MAX_AP 64 -+ -+/* Maximum size of the ESSID and NICKN strings */ -+#define IW_ESSID_MAX_SIZE 32 -+ -+/* Modes of operation */ -+#define IW_MODE_AUTO 0 /* Let the driver decides */ -+#define IW_MODE_ADHOC 1 /* Single cell network */ -+#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ -+#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ -+#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ -+#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ -+#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ -+#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */ -+ -+/* Statistics flags (bitmask in updated) */ -+#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ -+#define IW_QUAL_LEVEL_UPDATED 0x02 -+#define IW_QUAL_NOISE_UPDATED 0x04 -+#define IW_QUAL_ALL_UPDATED 0x07 -+#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ -+#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ -+#define IW_QUAL_LEVEL_INVALID 0x20 -+#define IW_QUAL_NOISE_INVALID 0x40 -+#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ -+#define IW_QUAL_ALL_INVALID 0x70 -+ -+/* Frequency flags */ -+#define IW_FREQ_AUTO 0x00 /* Let the driver decides */ -+#define IW_FREQ_FIXED 0x01 /* Force a specific value */ -+ -+/* Maximum number of size of encoding token available -+ * they are listed in the range structure */ -+#define IW_MAX_ENCODING_SIZES 8 -+ -+/* Maximum size of the encoding token in bytes */ -+#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ -+ -+/* Flags for encoding (along with the token) */ -+#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ -+#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ -+#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ -+#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ -+#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ -+#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ -+#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ -+#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ -+#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ -+ -+/* Power management flags available (along with the value, if any) */ -+#define IW_POWER_ON 0x0000 /* No details... */ -+#define IW_POWER_TYPE 0xF000 /* Type of parameter */ -+#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ -+#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ -+#define IW_POWER_MODE 0x0F00 /* Power Management mode */ -+#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ -+#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ -+#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ -+#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ -+#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ -+#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ -+#define IW_POWER_MIN 0x0001 /* Value is a minimum */ -+#define IW_POWER_MAX 0x0002 /* Value is a maximum */ -+#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ -+ -+/* Transmit Power flags available */ -+#define IW_TXPOW_TYPE 0x00FF /* Type of value */ -+#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ -+#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ -+#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ -+#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ -+ -+/* Retry limits and lifetime flags available */ -+#define IW_RETRY_ON 0x0000 /* No details... */ -+#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ -+#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ -+#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ -+#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ -+#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ -+#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ -+#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ -+#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ -+#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ -+ -+/* Scanning request flags */ -+#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ -+#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ -+#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ -+#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ -+#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ -+#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ -+#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ -+#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ -+#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ -+/* struct iw_scan_req scan_type */ -+#define IW_SCAN_TYPE_ACTIVE 0 -+#define IW_SCAN_TYPE_PASSIVE 1 -+/* Maximum size of returned data */ -+#define IW_SCAN_MAX_DATA 4096 /* In bytes */ -+ -+/* Scan capability flags - in (struct iw_range *)->scan_capa */ -+#define IW_SCAN_CAPA_NONE 0x00 -+#define IW_SCAN_CAPA_ESSID 0x01 -+#define IW_SCAN_CAPA_BSSID 0x02 -+#define IW_SCAN_CAPA_CHANNEL 0x04 -+#define IW_SCAN_CAPA_MODE 0x08 -+#define IW_SCAN_CAPA_RATE 0x10 -+#define IW_SCAN_CAPA_TYPE 0x20 -+#define IW_SCAN_CAPA_TIME 0x40 -+ -+/* Max number of char in custom event - use multiple of them if needed */ -+#define IW_CUSTOM_MAX 256 /* In bytes */ -+ -+/* Generic information element */ -+#define IW_GENERIC_IE_MAX 1024 -+ -+/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ -+#define IW_MLME_DEAUTH 0 -+#define IW_MLME_DISASSOC 1 -+#define IW_MLME_AUTH 2 -+#define IW_MLME_ASSOC 3 -+ -+/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ -+#define IW_AUTH_INDEX 0x0FFF -+#define IW_AUTH_FLAGS 0xF000 -+/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) -+ * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the -+ * parameter that is being set/get to; value will be read/written to -+ * struct iw_param value field) */ -+#define IW_AUTH_WPA_VERSION 0 -+#define IW_AUTH_CIPHER_PAIRWISE 1 -+#define IW_AUTH_CIPHER_GROUP 2 -+#define IW_AUTH_KEY_MGMT 3 -+#define IW_AUTH_TKIP_COUNTERMEASURES 4 -+#define IW_AUTH_DROP_UNENCRYPTED 5 -+#define IW_AUTH_80211_AUTH_ALG 6 -+#define IW_AUTH_WPA_ENABLED 7 -+#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 -+#define IW_AUTH_ROAMING_CONTROL 9 -+#define IW_AUTH_PRIVACY_INVOKED 10 -+#define IW_AUTH_CIPHER_GROUP_MGMT 11 -+#define IW_AUTH_MFP 12 -+ -+/* IW_AUTH_WPA_VERSION values (bit field) */ -+#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 -+#define IW_AUTH_WPA_VERSION_WPA 0x00000002 -+#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 -+ -+/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT -+ * values (bit field) */ -+#define IW_AUTH_CIPHER_NONE 0x00000001 -+#define IW_AUTH_CIPHER_WEP40 0x00000002 -+#define IW_AUTH_CIPHER_TKIP 0x00000004 -+#define IW_AUTH_CIPHER_CCMP 0x00000008 -+#define IW_AUTH_CIPHER_WEP104 0x00000010 -+#define IW_AUTH_CIPHER_AES_CMAC 0x00000020 -+ -+/* IW_AUTH_KEY_MGMT values (bit field) */ -+#define IW_AUTH_KEY_MGMT_802_1X 1 -+#define IW_AUTH_KEY_MGMT_PSK 2 -+ -+/* IW_AUTH_80211_AUTH_ALG values (bit field) */ -+#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 -+#define IW_AUTH_ALG_SHARED_KEY 0x00000002 -+#define IW_AUTH_ALG_LEAP 0x00000004 -+ -+/* IW_AUTH_ROAMING_CONTROL values */ -+#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ -+#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming -+ * control */ -+ -+/* IW_AUTH_MFP (management frame protection) values */ -+#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ -+#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ -+#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ -+ -+/* SIOCSIWENCODEEXT definitions */ -+#define IW_ENCODE_SEQ_MAX_SIZE 8 -+/* struct iw_encode_ext ->alg */ -+#define IW_ENCODE_ALG_NONE 0 -+#define IW_ENCODE_ALG_WEP 1 -+#define IW_ENCODE_ALG_TKIP 2 -+#define IW_ENCODE_ALG_CCMP 3 -+#define IW_ENCODE_ALG_PMK 4 -+#define IW_ENCODE_ALG_AES_CMAC 5 -+/* struct iw_encode_ext ->ext_flags */ -+#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 -+#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 -+#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 -+#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 -+ -+/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ -+#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ -+#define IW_MICFAILURE_GROUP 0x00000004 -+#define IW_MICFAILURE_PAIRWISE 0x00000008 -+#define IW_MICFAILURE_STAKEY 0x00000010 -+#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) -+ */ -+ -+/* Bit field values for enc_capa in struct iw_range */ -+#define IW_ENC_CAPA_WPA 0x00000001 -+#define IW_ENC_CAPA_WPA2 0x00000002 -+#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 -+#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 -+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 -+ -+/* Event capability macros - in (struct iw_range *)->event_capa -+ * Because we have more than 32 possible events, we use an array of -+ * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ -+#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ -+ (cmd - SIOCIWFIRSTPRIV + 0x60) : \ -+ (cmd - SIOCIWFIRST)) -+#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) -+#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) -+/* Event capability constants - event autogenerated by the kernel -+ * This list is valid for most 802.11 devices, customise as needed... */ -+#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ -+ IW_EVENT_CAPA_MASK(0x8B06) | \ -+ IW_EVENT_CAPA_MASK(0x8B1A)) -+#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) -+/* "Easy" macro to set events in iw_range (less efficient) */ -+#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) -+#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } -+ -+ -+/****************************** TYPES ******************************/ -+ -+/* --------------------------- SUBTYPES --------------------------- */ -+/* -+ * Generic format for most parameters that fit in an int -+ */ -+struct iw_param -+{ -+ __s32 value; /* The value of the parameter itself */ -+ __u8 fixed; /* Hardware should not use auto select */ -+ __u8 disabled; /* Disable the feature */ -+ __u16 flags; /* Various specifc flags (if any) */ -+}; -+ -+/* -+ * For all data larger than 16 octets, we need to use a -+ * pointer to memory allocated in user space. -+ */ -+struct iw_point -+{ -+ void __user *pointer; /* Pointer to the data (in user space) */ -+ __u16 length; /* number of fields or size in bytes */ -+ __u16 flags; /* Optional params */ -+}; -+ -+#ifdef __KERNEL__ -+#ifdef CONFIG_COMPAT -+ -+#include -+ -+struct compat_iw_point { -+ compat_caddr_t pointer; -+ __u16 length; -+ __u16 flags; -+}; -+#endif -+#endif -+ -+/* -+ * A frequency -+ * For numbers lower than 10^9, we encode the number in 'm' and -+ * set 'e' to 0 -+ * For number greater than 10^9, we divide it by the lowest power -+ * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... -+ * The power of 10 is in 'e', the result of the division is in 'm'. -+ */ -+struct iw_freq -+{ -+ __s32 m; /* Mantissa */ -+ __s16 e; /* Exponent */ -+ __u8 i; /* List index (when in range struct) */ -+ __u8 flags; /* Flags (fixed/auto) */ -+}; -+ -+/* -+ * Quality of the link -+ */ -+struct iw_quality -+{ -+ __u8 qual; /* link quality (%retries, SNR, -+ %missed beacons or better...) */ -+ __u8 level; /* signal level (dBm) */ -+ __u8 noise; /* noise level (dBm) */ -+ __u8 updated; /* Flags to know if updated */ -+}; -+ -+/* -+ * Packet discarded in the wireless adapter due to -+ * "wireless" specific problems... -+ * Note : the list of counter and statistics in net_device_stats -+ * is already pretty exhaustive, and you should use that first. -+ * This is only additional stats... -+ */ -+struct iw_discarded -+{ -+ __u32 nwid; /* Rx : Wrong nwid/essid */ -+ __u32 code; /* Rx : Unable to code/decode (WEP) */ -+ __u32 fragment; /* Rx : Can't perform MAC reassembly */ -+ __u32 retries; /* Tx : Max MAC retries num reached */ -+ __u32 misc; /* Others cases */ -+}; -+ -+/* -+ * Packet/Time period missed in the wireless adapter due to -+ * "wireless" specific problems... -+ */ -+struct iw_missed -+{ -+ __u32 beacon; /* Missed beacons/superframe */ -+}; -+ -+/* -+ * Quality range (for spy threshold) -+ */ -+struct iw_thrspy -+{ -+ struct sockaddr addr; /* Source address (hw/mac) */ -+ struct iw_quality qual; /* Quality of the link */ -+ struct iw_quality low; /* Low threshold */ -+ struct iw_quality high; /* High threshold */ -+}; -+ -+/* -+ * Optional data for scan request -+ * -+ * Note: these optional parameters are controlling parameters for the -+ * scanning behavior, these do not apply to getting scan results -+ * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and -+ * provide a merged results with all BSSes even if the previous scan -+ * request limited scanning to a subset, e.g., by specifying an SSID. -+ * Especially, scan results are required to include an entry for the -+ * current BSS if the driver is in Managed mode and associated with an AP. -+ */ -+struct iw_scan_req -+{ -+ __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ -+ __u8 essid_len; -+ __u8 num_channels; /* num entries in channel_list; -+ * 0 = scan all allowed channels */ -+ __u8 flags; /* reserved as padding; use zero, this may -+ * be used in the future for adding flags -+ * to request different scan behavior */ -+ struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or -+ * individual address of a specific BSS */ -+ -+ /* -+ * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using -+ * the current ESSID. This allows scan requests for specific ESSID -+ * without having to change the current ESSID and potentially breaking -+ * the current association. -+ */ -+ __u8 essid[IW_ESSID_MAX_SIZE]; -+ -+ /* -+ * Optional parameters for changing the default scanning behavior. -+ * These are based on the MLME-SCAN.request from IEEE Std 802.11. -+ * TU is 1.024 ms. If these are set to 0, driver is expected to use -+ * reasonable default values. min_channel_time defines the time that -+ * will be used to wait for the first reply on each channel. If no -+ * replies are received, next channel will be scanned after this. If -+ * replies are received, total time waited on the channel is defined by -+ * max_channel_time. -+ */ -+ __u32 min_channel_time; /* in TU */ -+ __u32 max_channel_time; /* in TU */ -+ -+ struct iw_freq channel_list[IW_MAX_FREQUENCIES]; -+}; -+ -+/* ------------------------- WPA SUPPORT ------------------------- */ -+ -+/* -+ * Extended data structure for get/set encoding (this is used with -+ * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* -+ * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and -+ * only the data contents changes (key data -> this structure, including -+ * key data). -+ * -+ * If the new key is the first group key, it will be set as the default -+ * TX key. Otherwise, default TX key index is only changed if -+ * IW_ENCODE_EXT_SET_TX_KEY flag is set. -+ * -+ * Key will be changed with SIOCSIWENCODEEXT in all cases except for -+ * special "change TX key index" operation which is indicated by setting -+ * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. -+ * -+ * tx_seq/rx_seq are only used when respective -+ * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal -+ * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start -+ * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally -+ * used only by an Authenticator (AP or an IBSS station) to get the -+ * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and -+ * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for -+ * debugging/testing. -+ */ -+struct iw_encode_ext -+{ -+ __u32 ext_flags; /* IW_ENCODE_EXT_* */ -+ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ -+ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ -+ struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast -+ * (group) keys or unicast address for -+ * individual keys */ -+ __u16 alg; /* IW_ENCODE_ALG_* */ -+ __u16 key_len; -+ __u8 key[0]; -+}; -+ -+/* SIOCSIWMLME data */ -+struct iw_mlme -+{ -+ __u16 cmd; /* IW_MLME_* */ -+ __u16 reason_code; -+ struct sockaddr addr; -+}; -+ -+/* SIOCSIWPMKSA data */ -+#define IW_PMKSA_ADD 1 -+#define IW_PMKSA_REMOVE 2 -+#define IW_PMKSA_FLUSH 3 -+ -+#define IW_PMKID_LEN 16 -+ -+struct iw_pmksa -+{ -+ __u32 cmd; /* IW_PMKSA_* */ -+ struct sockaddr bssid; -+ __u8 pmkid[IW_PMKID_LEN]; -+}; -+ -+/* IWEVMICHAELMICFAILURE data */ -+struct iw_michaelmicfailure -+{ -+ __u32 flags; -+ struct sockaddr src_addr; -+ __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ -+}; -+ -+/* IWEVPMKIDCAND data */ -+#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ -+struct iw_pmkid_cand -+{ -+ __u32 flags; /* IW_PMKID_CAND_* */ -+ __u32 index; /* the smaller the index, the higher the -+ * priority */ -+ struct sockaddr bssid; -+}; -+ -+/* ------------------------ WIRELESS STATS ------------------------ */ -+/* -+ * Wireless statistics (used for /proc/net/wireless) -+ */ -+struct iw_statistics -+{ -+ __u16 status; /* Status -+ * - device dependent for now */ -+ -+ struct iw_quality qual; /* Quality of the link -+ * (instant/mean/max) */ -+ struct iw_discarded discard; /* Packet discarded counts */ -+ struct iw_missed miss; /* Packet missed counts */ -+}; -+ -+/* ------------------------ IOCTL REQUEST ------------------------ */ -+/* -+ * This structure defines the payload of an ioctl, and is used -+ * below. -+ * -+ * Note that this structure should fit on the memory footprint -+ * of iwreq (which is the same as ifreq), which mean a max size of -+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... -+ * You should check this when increasing the structures defined -+ * above in this file... -+ */ -+union iwreq_data -+{ -+ /* Config - generic */ -+ char name[IFNAMSIZ]; -+ /* Name : used to verify the presence of wireless extensions. -+ * Name of the protocol/provider... */ -+ -+ struct iw_point essid; /* Extended network name */ -+ struct iw_param nwid; /* network id (or domain - the cell) */ -+ struct iw_freq freq; /* frequency or channel : -+ * 0-1000 = channel -+ * > 1000 = frequency in Hz */ -+ -+ struct iw_param sens; /* signal level threshold */ -+ struct iw_param bitrate; /* default bit rate */ -+ struct iw_param txpower; /* default transmit power */ -+ struct iw_param rts; /* RTS threshold threshold */ -+ struct iw_param frag; /* Fragmentation threshold */ -+ __u32 mode; /* Operation mode */ -+ struct iw_param retry; /* Retry limits & lifetime */ -+ -+ struct iw_point encoding; /* Encoding stuff : tokens */ -+ struct iw_param power; /* PM duration/timeout */ -+ struct iw_quality qual; /* Quality part of statistics */ -+ -+ struct sockaddr ap_addr; /* Access point address */ -+ struct sockaddr addr; /* Destination address (hw/mac) */ -+ -+ struct iw_param param; /* Other small parameters */ -+ struct iw_point data; /* Other large parameters */ -+}; -+ -+/* -+ * The structure to exchange data for ioctl. -+ * This structure is the same as 'struct ifreq', but (re)defined for -+ * convenience... -+ * Do I need to remind you about structure size (32 octets) ? -+ */ -+struct iwreq -+{ -+ union -+ { -+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ -+ } ifr_ifrn; -+ -+ /* Data part (defined just above) */ -+ union iwreq_data u; -+}; -+ -+/* -------------------------- IOCTL DATA -------------------------- */ -+/* -+ * For those ioctl which want to exchange mode data that what could -+ * fit in the above structure... -+ */ -+ -+/* -+ * Range of parameters -+ */ -+ -+struct iw_range -+{ -+ /* Informative stuff (to choose between different interface) */ -+ __u32 throughput; /* To give an idea... */ -+ /* In theory this value should be the maximum benchmarked -+ * TCP/IP throughput, because with most of these devices the -+ * bit rate is meaningless (overhead an co) to estimate how -+ * fast the connection will go and pick the fastest one. -+ * I suggest people to play with Netperf or any benchmark... -+ */ -+ -+ /* NWID (or domain id) */ -+ __u32 min_nwid; /* Minimal NWID we are able to set */ -+ __u32 max_nwid; /* Maximal NWID we are able to set */ -+ -+ /* Old Frequency (backward compat - moved lower ) */ -+ __u16 old_num_channels; -+ __u8 old_num_frequency; -+ -+ /* Scan capabilities */ -+ __u8 scan_capa; /* IW_SCAN_CAPA_* bit field */ -+ -+ /* Wireless event capability bitmasks */ -+ __u32 event_capa[6]; -+ -+ /* signal level threshold range */ -+ __s32 sensitivity; -+ -+ /* Quality of link & SNR stuff */ -+ /* Quality range (link, level, noise) -+ * If the quality is absolute, it will be in the range [0 ; max_qual], -+ * if the quality is dBm, it will be in the range [max_qual ; 0]. -+ * Don't forget that we use 8 bit arithmetics... */ -+ struct iw_quality max_qual; /* Quality of the link */ -+ /* This should contain the average/typical values of the quality -+ * indicator. This should be the threshold between a "good" and -+ * a "bad" link (example : monitor going from green to orange). -+ * Currently, user space apps like quality monitors don't have any -+ * way to calibrate the measurement. With this, they can split -+ * the range between 0 and max_qual in different quality level -+ * (using a geometric subdivision centered on the average). -+ * I expect that people doing the user space apps will feedback -+ * us on which value we need to put in each driver... */ -+ struct iw_quality avg_qual; /* Quality of the link */ -+ -+ /* Rates */ -+ __u8 num_bitrates; /* Number of entries in the list */ -+ __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ -+ -+ /* RTS threshold */ -+ __s32 min_rts; /* Minimal RTS threshold */ -+ __s32 max_rts; /* Maximal RTS threshold */ -+ -+ /* Frag threshold */ -+ __s32 min_frag; /* Minimal frag threshold */ -+ __s32 max_frag; /* Maximal frag threshold */ -+ -+ /* Power Management duration & timeout */ -+ __s32 min_pmp; /* Minimal PM period */ -+ __s32 max_pmp; /* Maximal PM period */ -+ __s32 min_pmt; /* Minimal PM timeout */ -+ __s32 max_pmt; /* Maximal PM timeout */ -+ __u16 pmp_flags; /* How to decode max/min PM period */ -+ __u16 pmt_flags; /* How to decode max/min PM timeout */ -+ __u16 pm_capa; /* What PM options are supported */ -+ -+ /* Encoder stuff */ -+ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ -+ __u8 num_encoding_sizes; /* Number of entry in the list */ -+ __u8 max_encoding_tokens; /* Max number of tokens */ -+ /* For drivers that need a "login/passwd" form */ -+ __u8 encoding_login_index; /* token index for login token */ -+ -+ /* Transmit power */ -+ __u16 txpower_capa; /* What options are supported */ -+ __u8 num_txpower; /* Number of entries in the list */ -+ __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ -+ -+ /* Wireless Extension version info */ -+ __u8 we_version_compiled; /* Must be WIRELESS_EXT */ -+ __u8 we_version_source; /* Last update of source */ -+ -+ /* Retry limits and lifetime */ -+ __u16 retry_capa; /* What retry options are supported */ -+ __u16 retry_flags; /* How to decode max/min retry limit */ -+ __u16 r_time_flags; /* How to decode max/min retry life */ -+ __s32 min_retry; /* Minimal number of retries */ -+ __s32 max_retry; /* Maximal number of retries */ -+ __s32 min_r_time; /* Minimal retry lifetime */ -+ __s32 max_r_time; /* Maximal retry lifetime */ -+ -+ /* Frequency */ -+ __u16 num_channels; /* Number of channels [0; num - 1] */ -+ __u8 num_frequency; /* Number of entry in the list */ -+ struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ -+ /* Note : this frequency list doesn't need to fit channel numbers, -+ * because each entry contain its channel index */ -+ -+ __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ -+}; -+ -+/* -+ * Private ioctl interface information -+ */ -+ -+struct iw_priv_args -+{ -+ __u32 cmd; /* Number of the ioctl to issue */ -+ __u16 set_args; /* Type and number of args */ -+ __u16 get_args; /* Type and number of args */ -+ char name[IFNAMSIZ]; /* Name of the extension */ -+}; -+ -+/* ----------------------- WIRELESS EVENTS ----------------------- */ -+/* -+ * Wireless events are carried through the rtnetlink socket to user -+ * space. They are encapsulated in the IFLA_WIRELESS field of -+ * a RTM_NEWLINK message. -+ */ -+ -+/* -+ * A Wireless Event. Contains basically the same data as the ioctl... -+ */ -+struct iw_event -+{ -+ __u16 len; /* Real length of this stuff */ -+ __u16 cmd; /* Wireless IOCTL */ -+ union iwreq_data u; /* IOCTL fixed payload */ -+}; -+ -+/* Size of the Event prefix (including padding and alignement junk) */ -+#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) -+/* Size of the various events */ -+#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) -+#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) -+#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) -+#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) -+#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) -+#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) -+ -+/* iw_point events are special. First, the payload (extra data) come at -+ * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, -+ * we omit the pointer, so start at an offset. */ -+#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ -+ (char *) NULL) -+#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ -+ IW_EV_POINT_OFF) -+ -+#ifdef __KERNEL__ -+#ifdef CONFIG_COMPAT -+struct __compat_iw_event { -+ __u16 len; /* Real length of this stuff */ -+ __u16 cmd; /* Wireless IOCTL */ -+ compat_caddr_t pointer; -+}; -+#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer) -+#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length) -+ -+/* Size of the various events for compat */ -+#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ) -+#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32)) -+#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq)) -+#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param)) -+#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr)) -+#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality)) -+#define IW_EV_COMPAT_POINT_LEN \ -+ (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \ -+ IW_EV_COMPAT_POINT_OFF) -+#endif -+#endif -+ -+/* Size of the Event prefix when packed in stream */ -+#define IW_EV_LCP_PK_LEN (4) -+/* Size of the various events when packed in stream */ -+#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ) -+#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32)) -+#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq)) -+#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param)) -+#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr)) -+#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality)) -+#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4) -+ -+#endif /* _LINUX_WIRELESS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.c -new file mode 100644 -index 0000000000000..60bfc1c8168fb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.c -@@ -0,0 +1,34 @@ -+/* -+ * CHAP-MD5 (RFC 1994) -+ * Copyright (c) 2007-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/crypto.h" -+#include "chap.h" -+ -+int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, -+ size_t challenge_len, u8 *response) -+{ -+ const u8 *addr[3]; -+ size_t len[3]; -+ -+ addr[0] = &id; -+ len[0] = 1; -+ addr[1] = secret; -+ len[1] = secret_len; -+ addr[2] = challenge; -+ len[2] = challenge_len; -+ return md5_vector(3, addr, len, response); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.h -new file mode 100644 -index 0000000000000..b9c400c7c7f41 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/chap.h -@@ -0,0 +1,23 @@ -+/* -+ * CHAP-MD5 (RFC 1994) -+ * Copyright (c) 2007-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef CHAP_H -+#define CHAP_H -+ -+#define CHAP_MD5_LEN 16 -+ -+int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge, -+ size_t challenge_len, u8 *response); -+ -+#endif /* CHAP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.c -new file mode 100644 -index 0000000000000..4afa1ddb2acb3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.c -@@ -0,0 +1,184 @@ -+/* -+ * EAP common peer/server definitions -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_defs.h" -+#include "eap_common.h" -+ -+/** -+ * eap_hdr_validate - Validate EAP header -+ * @vendor: Expected EAP Vendor-Id (0 = IETF) -+ * @eap_type: Expected EAP type number -+ * @msg: EAP frame (starting with EAP header) -+ * @plen: Pointer to variable to contain the returned payload length -+ * Returns: Pointer to EAP payload (after type field), or %NULL on failure -+ * -+ * This is a helper function for EAP method implementations. This is usually -+ * called in the beginning of struct eap_method::process() function to verify -+ * that the received EAP request packet has a valid header. This function is -+ * able to process both legacy and expanded EAP headers and in most cases, the -+ * caller can just use the returned payload pointer (into *plen) for processing -+ * the payload regardless of whether the packet used the expanded EAP header or -+ * not. -+ */ -+const u8 * eap_hdr_validate(int vendor, EapType eap_type, -+ const struct wpabuf *msg, size_t *plen) -+{ -+ const struct eap_hdr *hdr; -+ const u8 *pos; -+ size_t len; -+ -+ hdr = wpabuf_head(msg); -+ -+ if (wpabuf_len(msg) < sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "EAP: Too short EAP frame"); -+ return NULL; -+ } -+ -+ len = be_to_host16(hdr->length); -+ if (len < sizeof(*hdr) + 1 || len > wpabuf_len(msg)) { -+ wpa_printf(MSG_INFO, "EAP: Invalid EAP length"); -+ return NULL; -+ } -+ -+ pos = (const u8 *) (hdr + 1); -+ -+ if (*pos == EAP_TYPE_EXPANDED) { -+ int exp_vendor; -+ u32 exp_type; -+ if (len < sizeof(*hdr) + 8) { -+ wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP " -+ "length"); -+ return NULL; -+ } -+ pos++; -+ exp_vendor = WPA_GET_BE24(pos); -+ pos += 3; -+ exp_type = WPA_GET_BE32(pos); -+ pos += 4; -+ if (exp_vendor != vendor || exp_type != (u32) eap_type) { -+ wpa_printf(MSG_INFO, "EAP: Invalid expanded frame " -+ "type"); -+ return NULL; -+ } -+ -+ *plen = len - sizeof(*hdr) - 8; -+ return pos; -+ } else { -+ if (vendor != EAP_VENDOR_IETF || *pos != eap_type) { -+ wpa_printf(MSG_INFO, "EAP: Invalid frame type"); -+ return NULL; -+ } -+ *plen = len - sizeof(*hdr) - 1; -+ return pos + 1; -+ } -+} -+ -+ -+/** -+ * eap_msg_alloc - Allocate a buffer for an EAP message -+ * @vendor: Vendor-Id (0 = IETF) -+ * @type: EAP type -+ * @payload_len: Payload length in bytes (data after Type) -+ * @code: Message Code (EAP_CODE_*) -+ * @identifier: Identifier -+ * Returns: Pointer to the allocated message buffer or %NULL on error -+ * -+ * This function can be used to allocate a buffer for an EAP message and fill -+ * in the EAP header. This function is automatically using expanded EAP header -+ * if the selected Vendor-Id is not IETF. In other words, most EAP methods do -+ * not need to separately select which header type to use when using this -+ * function to allocate the message buffers. The returned buffer has room for -+ * payload_len bytes and has the EAP header and Type field already filled in. -+ */ -+struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, -+ u8 code, u8 identifier) -+{ -+ struct wpabuf *buf; -+ struct eap_hdr *hdr; -+ size_t len; -+ -+ len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) + -+ payload_len; -+ buf = wpabuf_alloc(len); -+ if (buf == NULL) -+ return NULL; -+ -+ hdr = wpabuf_put(buf, sizeof(*hdr)); -+ hdr->code = code; -+ hdr->identifier = identifier; -+ hdr->length = host_to_be16(len); -+ -+ if (vendor == EAP_VENDOR_IETF) { -+ wpabuf_put_u8(buf, type); -+ } else { -+ wpabuf_put_u8(buf, EAP_TYPE_EXPANDED); -+ wpabuf_put_be24(buf, vendor); -+ wpabuf_put_be32(buf, type); -+ } -+ -+ return buf; -+} -+ -+ -+/** -+ * eap_update_len - Update EAP header length -+ * @msg: EAP message from eap_msg_alloc -+ * -+ * This function updates the length field in the EAP header to match with the -+ * current length for the buffer. This allows eap_msg_alloc() to be used to -+ * allocate a larger buffer than the exact message length (e.g., if exact -+ * message length is not yet known). -+ */ -+void eap_update_len(struct wpabuf *msg) -+{ -+ struct eap_hdr *hdr; -+ hdr = wpabuf_mhead(msg); -+ if (wpabuf_len(msg) < sizeof(*hdr)) -+ return; -+ hdr->length = host_to_be16(wpabuf_len(msg)); -+} -+ -+ -+/** -+ * eap_get_id - Get EAP Identifier from wpabuf -+ * @msg: Buffer starting with an EAP header -+ * Returns: The Identifier field from the EAP header -+ */ -+u8 eap_get_id(const struct wpabuf *msg) -+{ -+ const struct eap_hdr *eap; -+ -+ if (wpabuf_len(msg) < sizeof(*eap)) -+ return 0; -+ -+ eap = wpabuf_head(msg); -+ return eap->identifier; -+} -+ -+ -+/** -+ * eap_get_id - Get EAP Type from wpabuf -+ * @msg: Buffer starting with an EAP header -+ * Returns: The EAP Type after the EAP header -+ */ -+EapType eap_get_type(const struct wpabuf *msg) -+{ -+ if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1) -+ return EAP_TYPE_NONE; -+ -+ return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)]; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.h -new file mode 100644 -index 0000000000000..b95e76b94f5c3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_common.h -@@ -0,0 +1,28 @@ -+/* -+ * EAP common peer/server definitions -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_COMMON_H -+#define EAP_COMMON_H -+ -+#include "wpabuf.h" -+ -+const u8 * eap_hdr_validate(int vendor, EapType eap_type, -+ const struct wpabuf *msg, size_t *plen); -+struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, -+ u8 code, u8 identifier); -+void eap_update_len(struct wpabuf *msg); -+u8 eap_get_id(const struct wpabuf *msg); -+EapType eap_get_type(const struct wpabuf *msg); -+ -+#endif /* EAP_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_defs.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_defs.h -new file mode 100644 -index 0000000000000..303530109cc59 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_defs.h -@@ -0,0 +1,86 @@ -+/* -+ * EAP server/peer: Shared EAP definitions -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_DEFS_H -+#define EAP_DEFS_H -+ -+/* RFC 3748 - Extensible Authentication Protocol (EAP) */ -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct eap_hdr { -+ u8 code; -+ u8 identifier; -+ be16 length; /* including code and identifier; network byte order */ -+ /* followed by length-4 octets of data */ -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, -+ EAP_CODE_FAILURE = 4 }; -+ -+/* EAP Request and Response data begins with one octet Type. Success and -+ * Failure do not have additional data. */ -+ -+/* -+ * EAP Method Types as allocated by IANA: -+ * http://www.iana.org/assignments/eap-numbers -+ */ -+typedef enum { -+ EAP_TYPE_NONE = 0, -+ EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, -+ EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, -+ EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, -+ EAP_TYPE_MD5 = 4, /* RFC 3748 */ -+ EAP_TYPE_OTP = 5 /* RFC 3748 */, -+ EAP_TYPE_GTC = 6, /* RFC 3748 */ -+ EAP_TYPE_TLS = 13 /* RFC 2716 */, -+ EAP_TYPE_LEAP = 17 /* Cisco proprietary */, -+ EAP_TYPE_SIM = 18 /* RFC 4186 */, -+ EAP_TYPE_TTLS = 21 /* RFC 5281 */, -+ EAP_TYPE_AKA = 23 /* RFC 4187 */, -+ EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */, -+ EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */, -+ EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */, -+ EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment; -+ * type 38 has previously been allocated for -+ * EAP-HTTP Digest, (funk.com) */, -+ EAP_TYPE_FAST = 43 /* RFC 4851 */, -+ EAP_TYPE_PAX = 46 /* RFC 4746 */, -+ EAP_TYPE_PSK = 47 /* RFC 4764 */, -+ EAP_TYPE_SAKE = 48 /* RFC 4763 */, -+ EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, -+ EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */, -+ EAP_TYPE_GPSK = 51 /* RFC 5433 */, -+ EAP_TYPE_PWD = 52 /* RFC 5931 */, -+ EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ -+} EapType; -+ -+ -+/* SMI Network Management Private Enterprise Code for vendor specific types */ -+enum { -+ EAP_VENDOR_IETF = 0, -+ EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, -+ EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */ -+}; -+ -+#define EAP_MSK_LEN 64 -+#define EAP_EMSK_LEN 64 -+ -+#endif /* EAP_DEFS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.c -new file mode 100644 -index 0000000000000..4de34a87b611d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.c -@@ -0,0 +1,304 @@ -+/* -+ * EAP-FAST common helper functions (RFC 4851) -+ * Copyright (c) 2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "eap_defs.h" -+#include "eap_tlv_common.h" -+#include "eap_fast_common.h" -+ -+ -+void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len) -+{ -+ struct pac_tlv_hdr hdr; -+ hdr.type = host_to_be16(type); -+ hdr.len = host_to_be16(len); -+ wpabuf_put_data(buf, &hdr, sizeof(hdr)); -+} -+ -+ -+void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, -+ u16 len) -+{ -+ eap_fast_put_tlv_hdr(buf, type, len); -+ wpabuf_put_data(buf, data, len); -+} -+ -+ -+void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, -+ const struct wpabuf *data) -+{ -+ eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data)); -+ wpabuf_put_buf(buf, data); -+} -+ -+ -+struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf) -+{ -+ struct wpabuf *e; -+ -+ if (buf == NULL) -+ return NULL; -+ -+ /* Encapsulate EAP packet in EAP-Payload TLV */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV"); -+ e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf)); -+ if (e == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory " -+ "for TLV encapsulation"); -+ wpabuf_free(buf); -+ return NULL; -+ } -+ eap_fast_put_tlv_buf(e, -+ EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV, -+ buf); -+ wpabuf_free(buf); -+ return e; -+} -+ -+ -+void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, -+ const u8 *client_random, u8 *master_secret) -+{ -+#define TLS_RANDOM_LEN 32 -+#define TLS_MASTER_SECRET_LEN 48 -+ u8 seed[2 * TLS_RANDOM_LEN]; -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random", -+ client_random, TLS_RANDOM_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random", -+ server_random, TLS_RANDOM_LEN); -+ -+ /* -+ * RFC 4851, Section 5.1: -+ * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", -+ * server_random + client_random, 48) -+ */ -+ os_memcpy(seed, server_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN); -+ sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN, -+ "PAC to master secret label hash", -+ seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret", -+ master_secret, TLS_MASTER_SECRET_LEN); -+} -+ -+ -+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, -+ const char *label, size_t len) -+{ -+ struct tls_keys keys; -+ u8 *rnd = NULL, *out; -+ int block_size; -+ -+ block_size = tls_connection_get_keyblock_size(ssl_ctx, conn); -+ if (block_size < 0) -+ return NULL; -+ -+ out = os_malloc(block_size + len); -+ if (out == NULL) -+ return NULL; -+ -+ if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len) -+ == 0) { -+ os_memmove(out, out + block_size, len); -+ return out; -+ } -+ -+ if (tls_connection_get_keys(ssl_ctx, conn, &keys)) -+ goto fail; -+ -+ rnd = os_malloc(keys.client_random_len + keys.server_random_len); -+ if (rnd == NULL) -+ goto fail; -+ -+ os_memcpy(rnd, keys.server_random, keys.server_random_len); -+ os_memcpy(rnd + keys.server_random_len, keys.client_random, -+ keys.client_random_len); -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key " -+ "expansion", keys.master_key, keys.master_key_len); -+ if (tls_prf(keys.master_key, keys.master_key_len, -+ label, rnd, keys.client_random_len + -+ keys.server_random_len, out, block_size + len)) -+ goto fail; -+ os_free(rnd); -+ os_memmove(out, out + block_size, len); -+ return out; -+ -+fail: -+ os_free(rnd); -+ os_free(out); -+ return NULL; -+} -+ -+ -+void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk) -+{ -+ /* -+ * RFC 4851, Section 5.4: EAP Master Session Key Generation -+ * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64) -+ */ -+ -+ sha1_t_prf(simck, EAP_FAST_SIMCK_LEN, -+ "Session Key Generating Function", (u8 *) "", 0, -+ msk, EAP_FAST_KEY_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)", -+ msk, EAP_FAST_KEY_LEN); -+} -+ -+ -+void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk) -+{ -+ /* -+ * RFC 4851, Section 5.4: EAP Master Session Key Genreration -+ * EMSK = T-PRF(S-IMCK[j], -+ * "Extended Session Key Generating Function", 64) -+ */ -+ -+ sha1_t_prf(simck, EAP_FAST_SIMCK_LEN, -+ "Extended Session Key Generating Function", (u8 *) "", 0, -+ emsk, EAP_EMSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)", -+ emsk, EAP_EMSK_LEN); -+} -+ -+ -+int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, -+ int tlv_type, u8 *pos, int len) -+{ -+ switch (tlv_type) { -+ case EAP_TLV_EAP_PAYLOAD_TLV: -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV", -+ pos, len); -+ if (tlv->eap_payload_tlv) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " -+ "EAP-Payload TLV in the message"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ return -2; -+ } -+ tlv->eap_payload_tlv = pos; -+ tlv->eap_payload_tlv_len = len; -+ break; -+ case EAP_TLV_RESULT_TLV: -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len); -+ if (tlv->result) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " -+ "Result TLV in the message"); -+ tlv->result = EAP_TLV_RESULT_FAILURE; -+ return -2; -+ } -+ if (len < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " -+ "Result TLV"); -+ tlv->result = EAP_TLV_RESULT_FAILURE; -+ break; -+ } -+ tlv->result = WPA_GET_BE16(pos); -+ if (tlv->result != EAP_TLV_RESULT_SUCCESS && -+ tlv->result != EAP_TLV_RESULT_FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d", -+ tlv->result); -+ tlv->result = EAP_TLV_RESULT_FAILURE; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s", -+ tlv->result == EAP_TLV_RESULT_SUCCESS ? -+ "Success" : "Failure"); -+ break; -+ case EAP_TLV_INTERMEDIATE_RESULT_TLV: -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV", -+ pos, len); -+ if (len < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " -+ "Intermediate-Result TLV"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ break; -+ } -+ if (tlv->iresult) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " -+ "Intermediate-Result TLV in the message"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ return -2; -+ } -+ tlv->iresult = WPA_GET_BE16(pos); -+ if (tlv->iresult != EAP_TLV_RESULT_SUCCESS && -+ tlv->iresult != EAP_TLV_RESULT_FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate " -+ "Result %d", tlv->iresult); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s", -+ tlv->iresult == EAP_TLV_RESULT_SUCCESS ? -+ "Success" : "Failure"); -+ break; -+ case EAP_TLV_CRYPTO_BINDING_TLV: -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV", -+ pos, len); -+ if (tlv->crypto_binding) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " -+ "Crypto-Binding TLV in the message"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ return -2; -+ } -+ tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len; -+ if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " -+ "Crypto-Binding TLV"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ return -2; -+ } -+ tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *) -+ (pos - sizeof(struct eap_tlv_hdr)); -+ break; -+ case EAP_TLV_REQUEST_ACTION_TLV: -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV", -+ pos, len); -+ if (tlv->request_action) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " -+ "Request-Action TLV in the message"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ return -2; -+ } -+ if (len < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short " -+ "Request-Action TLV"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ break; -+ } -+ tlv->request_action = WPA_GET_BE16(pos); -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d", -+ tlv->request_action); -+ break; -+ case EAP_TLV_PAC_TLV: -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len); -+ if (tlv->pac) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one " -+ "PAC TLV in the message"); -+ tlv->iresult = EAP_TLV_RESULT_FAILURE; -+ return -2; -+ } -+ tlv->pac = pos; -+ tlv->pac_len = len; -+ break; -+ default: -+ /* Unknown TLV */ -+ return -1; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.h -new file mode 100644 -index 0000000000000..c85fd37fd469c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_fast_common.h -@@ -0,0 +1,113 @@ -+/* -+ * EAP-FAST definitions (RFC 4851) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_FAST_H -+#define EAP_FAST_H -+ -+#define EAP_FAST_VERSION 1 -+#define EAP_FAST_KEY_LEN 64 -+#define EAP_FAST_SIMCK_LEN 40 -+#define EAP_FAST_SKS_LEN 40 -+#define EAP_FAST_CMK_LEN 20 -+ -+#define TLS_EXT_PAC_OPAQUE 35 -+ -+/* -+ * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field -+ * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined -+ * in the general PAC TLV format (Section 4.2). -+ */ -+#define PAC_TYPE_PAC_KEY 1 -+#define PAC_TYPE_PAC_OPAQUE 2 -+#define PAC_TYPE_CRED_LIFETIME 3 -+#define PAC_TYPE_A_ID 4 -+#define PAC_TYPE_I_ID 5 -+/* -+ * 6 was previous assigned for SERVER_PROTECTED_DATA, but -+ * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved. -+ */ -+#define PAC_TYPE_A_ID_INFO 7 -+#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8 -+#define PAC_TYPE_PAC_INFO 9 -+#define PAC_TYPE_PAC_TYPE 10 -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct pac_tlv_hdr { -+ be16 type; -+ be16 len; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+#define EAP_FAST_PAC_KEY_LEN 32 -+ -+/* RFC 5422: 4.2.6 PAC-Type TLV */ -+#define PAC_TYPE_TUNNEL_PAC 1 -+/* Application Specific Short Lived PACs (only in volatile storage) */ -+/* User Authorization PAC */ -+#define PAC_TYPE_USER_AUTHORIZATION 3 -+/* Application Specific Long Lived PACs */ -+/* Machine Authentication PAC */ -+#define PAC_TYPE_MACHINE_AUTHENTICATION 2 -+ -+ -+/* -+ * RFC 5422: -+ * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange -+ */ -+struct eap_fast_key_block_provisioning { -+ /* Extra key material after TLS key_block */ -+ u8 session_key_seed[EAP_FAST_SKS_LEN]; -+ u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */ -+ u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */ -+}; -+ -+ -+struct wpabuf; -+struct tls_connection; -+ -+struct eap_fast_tlv_parse { -+ u8 *eap_payload_tlv; -+ size_t eap_payload_tlv_len; -+ struct eap_tlv_crypto_binding_tlv *crypto_binding; -+ size_t crypto_binding_len; -+ int iresult; -+ int result; -+ int request_action; -+ u8 *pac; -+ size_t pac_len; -+}; -+ -+void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len); -+void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, -+ u16 len); -+void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, -+ const struct wpabuf *data); -+struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf); -+void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, -+ const u8 *client_random, u8 *master_secret); -+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, -+ const char *label, size_t len); -+void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk); -+void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk); -+int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, -+ int tlv_type, u8 *pos, int len); -+ -+#endif /* EAP_FAST_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.c -new file mode 100644 -index 0000000000000..4076262880613 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.c -@@ -0,0 +1,423 @@ -+/* -+ * EAP server/peer: EAP-GPSK shared routines -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/sha256.h" -+#include "eap_defs.h" -+#include "eap_gpsk_common.h" -+ -+ -+/** -+ * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported -+ * @vendor: CSuite/Vendor -+ * @specifier: CSuite/Specifier -+ * Returns: 1 if ciphersuite is support, or 0 if not -+ */ -+int eap_gpsk_supported_ciphersuite(int vendor, int specifier) -+{ -+ if (vendor == EAP_GPSK_VENDOR_IETF && -+ specifier == EAP_GPSK_CIPHER_AES) -+ return 1; -+#ifdef EAP_GPSK_SHA256 -+ if (vendor == EAP_GPSK_VENDOR_IETF && -+ specifier == EAP_GPSK_CIPHER_SHA256) -+ return 1; -+#endif /* EAP_GPSK_SHA256 */ -+ return 0; -+} -+ -+ -+static int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */, -+ const u8 *data /* Z */, size_t data_len, -+ u8 *buf, size_t len /* X */) -+{ -+ u8 *opos; -+ size_t i, n, hashlen, left, clen; -+ u8 ibuf[2], hash[16]; -+ const u8 *addr[2]; -+ size_t vlen[2]; -+ -+ hashlen = sizeof(hash); -+ /* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */ -+ addr[0] = ibuf; -+ vlen[0] = sizeof(ibuf); -+ addr[1] = data; -+ vlen[1] = data_len; -+ -+ opos = buf; -+ left = len; -+ n = (len + hashlen - 1) / hashlen; -+ for (i = 1; i <= n; i++) { -+ WPA_PUT_BE16(ibuf, i); -+ if (omac1_aes_128_vector(psk, 2, addr, vlen, hash)) -+ return -1; -+ clen = left > hashlen ? hashlen : left; -+ os_memcpy(opos, hash, clen); -+ opos += clen; -+ left -= clen; -+ } -+ -+ return 0; -+} -+ -+ -+#ifdef EAP_GPSK_SHA256 -+static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, -+ const u8 *data /* Z */, size_t data_len, -+ u8 *buf, size_t len /* X */) -+{ -+ u8 *opos; -+ size_t i, n, hashlen, left, clen; -+ u8 ibuf[2], hash[SHA256_MAC_LEN]; -+ const u8 *addr[2]; -+ size_t vlen[2]; -+ -+ hashlen = SHA256_MAC_LEN; -+ /* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */ -+ addr[0] = ibuf; -+ vlen[0] = sizeof(ibuf); -+ addr[1] = data; -+ vlen[1] = data_len; -+ -+ opos = buf; -+ left = len; -+ n = (len + hashlen - 1) / hashlen; -+ for (i = 1; i <= n; i++) { -+ WPA_PUT_BE16(ibuf, i); -+ hmac_sha256_vector(psk, 32, 2, addr, vlen, hash); -+ clen = left > hashlen ? hashlen : left; -+ os_memcpy(opos, hash, clen); -+ opos += clen; -+ left -= clen; -+ } -+ -+ return 0; -+} -+#endif /* EAP_GPSK_SHA256 */ -+ -+ -+static int eap_gpsk_derive_keys_helper(u32 csuite_specifier, -+ u8 *kdf_out, size_t kdf_out_len, -+ const u8 *psk, size_t psk_len, -+ const u8 *seed, size_t seed_len, -+ u8 *msk, u8 *emsk, -+ u8 *sk, size_t sk_len, -+ u8 *pk, size_t pk_len) -+{ -+ u8 mk[32], *pos, *data; -+ size_t data_len, mk_len; -+ int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len, -+ u8 *buf, size_t len); -+ -+ gkdf = NULL; -+ switch (csuite_specifier) { -+ case EAP_GPSK_CIPHER_AES: -+ gkdf = eap_gpsk_gkdf_cmac; -+ mk_len = 16; -+ break; -+#ifdef EAP_GPSK_SHA256 -+ case EAP_GPSK_CIPHER_SHA256: -+ gkdf = eap_gpsk_gkdf_sha256; -+ mk_len = SHA256_MAC_LEN; -+ break; -+#endif /* EAP_GPSK_SHA256 */ -+ default: -+ return -1; -+ } -+ -+ if (psk_len < mk_len) -+ return -1; -+ -+ data_len = 2 + psk_len + 6 + seed_len; -+ data = os_malloc(data_len); -+ if (data == NULL) -+ return -1; -+ pos = data; -+ WPA_PUT_BE16(pos, psk_len); -+ pos += 2; -+ os_memcpy(pos, psk, psk_len); -+ pos += psk_len; -+ WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */ -+ pos += 4; -+ WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */ -+ pos += 2; -+ os_memcpy(pos, seed, seed_len); /* inputString */ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation", -+ data, data_len); -+ -+ if (gkdf(psk, data, data_len, mk, mk_len) < 0) { -+ os_free(data); -+ return -1; -+ } -+ os_free(data); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len); -+ -+ if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0) -+ return -1; -+ -+ pos = kdf_out; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN); -+ os_memcpy(msk, pos, EAP_MSK_LEN); -+ pos += EAP_MSK_LEN; -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN); -+ os_memcpy(emsk, pos, EAP_EMSK_LEN); -+ pos += EAP_EMSK_LEN; -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, sk_len); -+ os_memcpy(sk, pos, sk_len); -+ pos += sk_len; -+ -+ if (pk) { -+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, pk_len); -+ os_memcpy(pk, pos, pk_len); -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len, -+ const u8 *seed, size_t seed_len, -+ u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, -+ u8 *pk, size_t *pk_len) -+{ -+#define EAP_GPSK_SK_LEN_AES 16 -+#define EAP_GPSK_PK_LEN_AES 16 -+ u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES + -+ EAP_GPSK_PK_LEN_AES]; -+ -+ /* -+ * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server -+ * (= seed) -+ * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001 -+ * MK = GKDF-16 (PSK[0..15], PL || PSK || CSuite_Sel || inputString) -+ * MSK = GKDF-160 (MK, inputString)[0..63] -+ * EMSK = GKDF-160 (MK, inputString)[64..127] -+ * SK = GKDF-160 (MK, inputString)[128..143] -+ * PK = GKDF-160 (MK, inputString)[144..159] -+ * zero = 0x00 || 0x00 || ... || 0x00 (16 times) -+ * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || -+ * CSuite_Sel || inputString) -+ */ -+ -+ *sk_len = EAP_GPSK_SK_LEN_AES; -+ *pk_len = EAP_GPSK_PK_LEN_AES; -+ -+ return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_AES, -+ kdf_out, sizeof(kdf_out), -+ psk, psk_len, seed, seed_len, -+ msk, emsk, sk, *sk_len, -+ pk, *pk_len); -+} -+ -+ -+#ifdef EAP_GPSK_SHA256 -+static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len, -+ const u8 *seed, size_t seed_len, -+ u8 *msk, u8 *emsk, -+ u8 *sk, size_t *sk_len) -+{ -+#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN -+#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN -+ u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 + -+ EAP_GPSK_PK_LEN_SHA256]; -+ -+ /* -+ * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server -+ * (= seed) -+ * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002 -+ * MK = GKDF-32 (PSK[0..31], PL || PSK || CSuite_Sel || inputString) -+ * MSK = GKDF-160 (MK, inputString)[0..63] -+ * EMSK = GKDF-160 (MK, inputString)[64..127] -+ * SK = GKDF-160 (MK, inputString)[128..159] -+ * zero = 0x00 || 0x00 || ... || 0x00 (32 times) -+ * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || -+ * CSuite_Sel || inputString) -+ */ -+ -+ *sk_len = EAP_GPSK_SK_LEN_SHA256; -+ -+ return eap_gpsk_derive_keys_helper(EAP_GPSK_CIPHER_SHA256, -+ kdf_out, sizeof(kdf_out), -+ psk, psk_len, seed, seed_len, -+ msk, emsk, sk, *sk_len, -+ NULL, 0); -+} -+#endif /* EAP_GPSK_SHA256 */ -+ -+ -+/** -+ * eap_gpsk_derive_keys - Derive EAP-GPSK keys -+ * @psk: Pre-shared key -+ * @psk_len: Length of psk in bytes -+ * @vendor: CSuite/Vendor -+ * @specifier: CSuite/Specifier -+ * @rand_peer: 32-byte RAND_Peer -+ * @rand_server: 32-byte RAND_Server -+ * @id_peer: ID_Peer -+ * @id_peer_len: Length of ID_Peer -+ * @id_server: ID_Server -+ * @id_server_len: Length of ID_Server -+ * @msk: Buffer for 64-byte MSK -+ * @emsk: Buffer for 64-byte EMSK -+ * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes) -+ * @sk_len: Buffer for returning length of SK -+ * @pk: Buffer for PK (at least EAP_GPSK_MAX_PK_LEN bytes) -+ * @pk_len: Buffer for returning length of PK -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, -+ int specifier, -+ const u8 *rand_peer, const u8 *rand_server, -+ const u8 *id_peer, size_t id_peer_len, -+ const u8 *id_server, size_t id_server_len, -+ u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, -+ u8 *pk, size_t *pk_len) -+{ -+ u8 *seed, *pos; -+ size_t seed_len; -+ int ret; -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)", -+ vendor, specifier); -+ -+ if (vendor != EAP_GPSK_VENDOR_IETF) -+ return -1; -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); -+ -+ /* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */ -+ seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len; -+ seed = os_malloc(seed_len); -+ if (seed == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " -+ "for key derivation"); -+ return -1; -+ } -+ -+ pos = seed; -+ os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN); -+ pos += EAP_GPSK_RAND_LEN; -+ os_memcpy(pos, id_peer, id_peer_len); -+ pos += id_peer_len; -+ os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN); -+ pos += EAP_GPSK_RAND_LEN; -+ os_memcpy(pos, id_server, id_server_len); -+ pos += id_server_len; -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len); -+ -+ switch (specifier) { -+ case EAP_GPSK_CIPHER_AES: -+ ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len, -+ msk, emsk, sk, sk_len, -+ pk, pk_len); -+ break; -+#ifdef EAP_GPSK_SHA256 -+ case EAP_GPSK_CIPHER_SHA256: -+ ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len, -+ msk, emsk, sk, sk_len); -+ break; -+#endif /* EAP_GPSK_SHA256 */ -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " -+ "key derivation", vendor, specifier); -+ ret = -1; -+ break; -+ } -+ -+ os_free(seed); -+ -+ return ret; -+} -+ -+ -+/** -+ * eap_gpsk_mic_len - Get the length of the MIC -+ * @vendor: CSuite/Vendor -+ * @specifier: CSuite/Specifier -+ * Returns: MIC length in bytes -+ */ -+size_t eap_gpsk_mic_len(int vendor, int specifier) -+{ -+ if (vendor != EAP_GPSK_VENDOR_IETF) -+ return 0; -+ -+ switch (specifier) { -+ case EAP_GPSK_CIPHER_AES: -+ return 16; -+#ifdef EAP_GPSK_SHA256 -+ case EAP_GPSK_CIPHER_SHA256: -+ return 32; -+#endif /* EAP_GPSK_SHA256 */ -+ default: -+ return 0; -+ } -+} -+ -+ -+static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len, -+ const u8 *data, size_t len, u8 *mic) -+{ -+ if (sk_len != 16) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for " -+ "AES-CMAC MIC", (unsigned long) sk_len); -+ return -1; -+ } -+ -+ return omac1_aes_128(sk, data, len, mic); -+} -+ -+ -+/** -+ * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet -+ * @sk: Session key SK from eap_gpsk_derive_keys() -+ * @sk_len: SK length in bytes from eap_gpsk_derive_keys() -+ * @vendor: CSuite/Vendor -+ * @specifier: CSuite/Specifier -+ * @data: Input data to MIC -+ * @len: Input data length in bytes -+ * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, -+ int specifier, const u8 *data, size_t len, u8 *mic) -+{ -+ int ret; -+ -+ if (vendor != EAP_GPSK_VENDOR_IETF) -+ return -1; -+ -+ switch (specifier) { -+ case EAP_GPSK_CIPHER_AES: -+ ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic); -+ break; -+#ifdef EAP_GPSK_SHA256 -+ case EAP_GPSK_CIPHER_SHA256: -+ hmac_sha256(sk, sk_len, data, len, mic); -+ ret = 0; -+ break; -+#endif /* EAP_GPSK_SHA256 */ -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in " -+ "MIC computation", vendor, specifier); -+ ret = -1; -+ break; -+ } -+ -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.h -new file mode 100644 -index 0000000000000..a30ab97ffa07f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_gpsk_common.h -@@ -0,0 +1,66 @@ -+/* -+ * EAP server/peer: EAP-GPSK shared routines -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_GPSK_COMMON_H -+#define EAP_GPSK_COMMON_H -+ -+#define EAP_GPSK_OPCODE_GPSK_1 1 -+#define EAP_GPSK_OPCODE_GPSK_2 2 -+#define EAP_GPSK_OPCODE_GPSK_3 3 -+#define EAP_GPSK_OPCODE_GPSK_4 4 -+#define EAP_GPSK_OPCODE_FAIL 5 -+#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6 -+ -+/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */ -+#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001 -+#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002 -+#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003 -+ -+#define EAP_GPSK_RAND_LEN 32 -+#define EAP_GPSK_MAX_SK_LEN 32 -+#define EAP_GPSK_MAX_PK_LEN 32 -+#define EAP_GPSK_MAX_MIC_LEN 32 -+ -+#define EAP_GPSK_VENDOR_IETF 0x00000000 -+#define EAP_GPSK_CIPHER_RESERVED 0x000000 -+#define EAP_GPSK_CIPHER_AES 0x000001 -+#define EAP_GPSK_CIPHER_SHA256 0x000002 -+ -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct eap_gpsk_csuite { -+ u8 vendor[4]; -+ u8 specifier[2]; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+int eap_gpsk_supported_ciphersuite(int vendor, int specifier); -+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, -+ int specifier, -+ const u8 *rand_client, const u8 *rand_server, -+ const u8 *id_client, size_t id_client_len, -+ const u8 *id_server, size_t id_server_len, -+ u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, -+ u8 *pk, size_t *pk_len); -+size_t eap_gpsk_mic_len(int vendor, int specifier); -+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, -+ int specifier, const u8 *data, size_t len, u8 *mic); -+ -+#endif /* EAP_GPSK_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.c -new file mode 100644 -index 0000000000000..e9a9c55eb3018 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.c -@@ -0,0 +1,132 @@ -+/* -+ * EAP-IKEv2 common routines -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_defs.h" -+#include "eap_common.h" -+#include "ikev2_common.h" -+#include "eap_ikev2_common.h" -+ -+ -+int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, -+ const u8 *i_nonce, size_t i_nonce_len, -+ const u8 *r_nonce, size_t r_nonce_len, -+ u8 *keymat) -+{ -+ u8 *nonces; -+ size_t nlen; -+ -+ /* KEYMAT = prf+(SK_d, Ni | Nr) */ -+ if (keys->SK_d == NULL || i_nonce == NULL || r_nonce == NULL) -+ return -1; -+ -+ nlen = i_nonce_len + r_nonce_len; -+ nonces = os_malloc(nlen); -+ if (nonces == NULL) -+ return -1; -+ os_memcpy(nonces, i_nonce, i_nonce_len); -+ os_memcpy(nonces + i_nonce_len, r_nonce, r_nonce_len); -+ -+ if (ikev2_prf_plus(prf, keys->SK_d, keys->SK_d_len, nonces, nlen, -+ keymat, EAP_MSK_LEN + EAP_EMSK_LEN)) { -+ os_free(nonces); -+ return -1; -+ } -+ os_free(nonces); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-IKEV2: KEYMAT", -+ keymat, EAP_MSK_LEN + EAP_EMSK_LEN); -+ -+ return 0; -+} -+ -+ -+struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code) -+{ -+ struct wpabuf *msg; -+ -+#ifdef CCNS_PL -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " -+ "for fragment ack"); -+ return NULL; -+ } -+ wpabuf_put_u8(msg, 0); /* Flags */ -+#else /* CCNS_PL */ -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " -+ "for fragment ack"); -+ return NULL; -+ } -+#endif /* CCNS_PL */ -+ -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack"); -+ -+ return msg; -+} -+ -+ -+int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, -+ int initiator, const struct wpabuf *msg, -+ const u8 *pos, const u8 *end) -+{ -+ const struct ikev2_integ_alg *integ; -+ size_t icv_len; -+ u8 icv[IKEV2_MAX_HASH_LEN]; -+ const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; -+ -+ integ = ikev2_get_integ(integ_alg); -+ if (integ == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " -+ "transform / cannot validate ICV"); -+ return -1; -+ } -+ icv_len = integ->hash_len; -+ -+ if (end - pos < (int) icv_len) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Not enough room in the " -+ "message for Integrity Checksum Data"); -+ return -1; -+ } -+ -+ if (SK_a == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: No SK_a for ICV validation"); -+ return -1; -+ } -+ -+ if (ikev2_integ_hash(integ_alg, SK_a, keys->SK_integ_len, -+ wpabuf_head(msg), -+ wpabuf_len(msg) - icv_len, icv) < 0) { -+ wpa_printf(MSG_INFO, "EAP-IKEV2: Could not calculate ICV"); -+ return -1; -+ } -+ -+ if (os_memcmp(icv, end - icv_len, icv_len) != 0) { -+ wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV"); -+ wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV", -+ icv, icv_len); -+ wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Received ICV", -+ end - icv_len, icv_len); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Valid Integrity Checksum Data in " -+ "the received message"); -+ -+ return icv_len; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.h -new file mode 100644 -index 0000000000000..a9fc2caae7269 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ikev2_common.h -@@ -0,0 +1,42 @@ -+/* -+ * EAP-IKEv2 definitions -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_IKEV2_COMMON_H -+#define EAP_IKEV2_COMMON_H -+ -+#ifdef CCNS_PL -+/* incorrect bit order */ -+#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01 -+#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02 -+#define IKEV2_FLAGS_ICV_INCLUDED 0x04 -+#else /* CCNS_PL */ -+#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80 -+#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40 -+#define IKEV2_FLAGS_ICV_INCLUDED 0x20 -+#endif /* CCNS_PL */ -+ -+#define IKEV2_FRAGMENT_SIZE 1400 -+ -+struct ikev2_keys; -+ -+int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, -+ const u8 *i_nonce, size_t i_nonce_len, -+ const u8 *r_nonce, size_t r_nonce_len, -+ u8 *keymat); -+struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code); -+int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, -+ int initiator, const struct wpabuf *msg, -+ const u8 *pos, const u8 *end); -+ -+#endif /* EAP_IKEV2_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.c -new file mode 100644 -index 0000000000000..32dc80c74dc5b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.c -@@ -0,0 +1,150 @@ -+/* -+ * EAP server/peer: EAP-PAX shared routines -+ * Copyright (c) 2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "eap_pax_common.h" -+ -+ -+/** -+ * eap_pax_kdf - PAX Key Derivation Function -+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported -+ * @key: Secret key (X) -+ * @key_len: Length of the secret key in bytes -+ * @identifier: Public identifier for the key (Y) -+ * @entropy: Exchanged entropy to seed the KDF (Z) -+ * @entropy_len: Length of the entropy in bytes -+ * @output_len: Output len in bytes (W) -+ * @output: Buffer for the derived key -+ * Returns: 0 on success, -1 failed -+ * -+ * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z) -+ */ -+int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, -+ const char *identifier, -+ const u8 *entropy, size_t entropy_len, -+ size_t output_len, u8 *output) -+{ -+ u8 mac[SHA1_MAC_LEN]; -+ u8 counter, *pos; -+ const u8 *addr[3]; -+ size_t len[3]; -+ size_t num_blocks, left; -+ -+ num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN; -+ if (identifier == NULL || num_blocks >= 255) -+ return -1; -+ -+ /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */ -+ if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128) -+ return -1; -+ -+ addr[0] = (const u8 *) identifier; -+ len[0] = os_strlen(identifier); -+ addr[1] = entropy; -+ len[1] = entropy_len; -+ addr[2] = &counter; -+ len[2] = 1; -+ -+ pos = output; -+ left = output_len; -+ for (counter = 1; counter <= (u8) num_blocks; counter++) { -+ size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left; -+ hmac_sha1_vector(key, key_len, 3, addr, len, mac); -+ os_memcpy(pos, mac, clen); -+ pos += clen; -+ left -= clen; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_pax_mac - EAP-PAX MAC -+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported -+ * @key: Secret key -+ * @key_len: Length of the secret key in bytes -+ * @data1: Optional data, first block; %NULL if not used -+ * @data1_len: Length of data1 in bytes -+ * @data2: Optional data, second block; %NULL if not used -+ * @data2_len: Length of data2 in bytes -+ * @data3: Optional data, third block; %NULL if not used -+ * @data3_len: Length of data3 in bytes -+ * @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Wrapper function to calculate EAP-PAX MAC. -+ */ -+int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, -+ const u8 *data1, size_t data1_len, -+ const u8 *data2, size_t data2_len, -+ const u8 *data3, size_t data3_len, -+ u8 *mac) -+{ -+ u8 hash[SHA1_MAC_LEN]; -+ const u8 *addr[3]; -+ size_t len[3]; -+ size_t count; -+ -+ /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */ -+ if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128) -+ return -1; -+ -+ addr[0] = data1; -+ len[0] = data1_len; -+ addr[1] = data2; -+ len[1] = data2_len; -+ addr[2] = data3; -+ len[2] = data3_len; -+ -+ count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0); -+ hmac_sha1_vector(key, key_len, count, addr, len, hash); -+ os_memcpy(mac, hash, EAP_PAX_MAC_LEN); -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_pax_initial_key_derivation - EAP-PAX initial key derivation -+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported -+ * @ak: Authentication Key -+ * @e: Entropy -+ * @mk: Buffer for the derived Master Key -+ * @ck: Buffer for the derived Confirmation Key -+ * @ick: Buffer for the derived Integrity Check Key -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e, -+ u8 *mk, u8 *ck, u8 *ick) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation"); -+ if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key", -+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MK_LEN, mk) || -+ eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key", -+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) || -+ eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key", -+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick)) -+ return -1; -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.h -new file mode 100644 -index 0000000000000..dcc171ec2c0c4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pax_common.h -@@ -0,0 +1,97 @@ -+/* -+ * EAP server/peer: EAP-PAX shared routines -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_PAX_COMMON_H -+#define EAP_PAX_COMMON_H -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct eap_pax_hdr { -+ u8 op_code; -+ u8 flags; -+ u8 mac_id; -+ u8 dh_group_id; -+ u8 public_key_id; -+ /* Followed by variable length payload and ICV */ -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+/* op_code: */ -+enum { -+ EAP_PAX_OP_STD_1 = 0x01, -+ EAP_PAX_OP_STD_2 = 0x02, -+ EAP_PAX_OP_STD_3 = 0x03, -+ EAP_PAX_OP_SEC_1 = 0x11, -+ EAP_PAX_OP_SEC_2 = 0x12, -+ EAP_PAX_OP_SEC_3 = 0x13, -+ EAP_PAX_OP_SEC_4 = 0x14, -+ EAP_PAX_OP_SEC_5 = 0x15, -+ EAP_PAX_OP_ACK = 0x21 -+}; -+ -+/* flags: */ -+#define EAP_PAX_FLAGS_MF 0x01 -+#define EAP_PAX_FLAGS_CE 0x02 -+#define EAP_PAX_FLAGS_AI 0x04 -+ -+/* mac_id: */ -+#define EAP_PAX_MAC_HMAC_SHA1_128 0x01 -+#define EAP_PAX_HMAC_SHA256_128 0x02 -+ -+/* dh_group_id: */ -+#define EAP_PAX_DH_GROUP_NONE 0x00 -+#define EAP_PAX_DH_GROUP_2048_MODP 0x01 -+#define EAP_PAX_DH_GROUP_3072_MODP 0x02 -+#define EAP_PAX_DH_GROUP_NIST_ECC_P_256 0x03 -+ -+/* public_key_id: */ -+#define EAP_PAX_PUBLIC_KEY_NONE 0x00 -+#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP 0x01 -+#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 0x02 -+#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC 0x03 -+ -+/* ADE type: */ -+#define EAP_PAX_ADE_VENDOR_SPECIFIC 0x01 -+#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING 0x02 -+#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING 0x03 -+ -+ -+#define EAP_PAX_RAND_LEN 32 -+#define EAP_PAX_MAC_LEN 16 -+#define EAP_PAX_ICV_LEN 16 -+#define EAP_PAX_AK_LEN 16 -+#define EAP_PAX_MK_LEN 16 -+#define EAP_PAX_CK_LEN 16 -+#define EAP_PAX_ICK_LEN 16 -+ -+ -+int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, -+ const char *identifier, -+ const u8 *entropy, size_t entropy_len, -+ size_t output_len, u8 *output); -+int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, -+ const u8 *data1, size_t data1_len, -+ const u8 *data2, size_t data2_len, -+ const u8 *data3, size_t data3_len, -+ u8 *mac); -+int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e, -+ u8 *mk, u8 *ck, u8 *ick); -+ -+#endif /* EAP_PAX_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.c -new file mode 100644 -index 0000000000000..3a64b8ecc44c3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.c -@@ -0,0 +1,88 @@ -+/* -+ * EAP-PEAP common routines -+ * Copyright (c) 2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "eap_peap_common.h" -+ -+void peap_prfplus(int version, const u8 *key, size_t key_len, -+ const char *label, const u8 *seed, size_t seed_len, -+ u8 *buf, size_t buf_len) -+{ -+ unsigned char counter = 0; -+ size_t pos, plen; -+ u8 hash[SHA1_MAC_LEN]; -+ size_t label_len = os_strlen(label); -+ u8 extra[2]; -+ const unsigned char *addr[5]; -+ size_t len[5]; -+ -+ addr[0] = hash; -+ len[0] = 0; -+ addr[1] = (unsigned char *) label; -+ len[1] = label_len; -+ addr[2] = seed; -+ len[2] = seed_len; -+ -+ if (version == 0) { -+ /* -+ * PRF+(K, S, LEN) = T1 | T2 | ... | Tn -+ * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00) -+ * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00) -+ * ... -+ * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00) -+ */ -+ -+ extra[0] = 0; -+ extra[1] = 0; -+ -+ addr[3] = &counter; -+ len[3] = 1; -+ addr[4] = extra; -+ len[4] = 2; -+ } else { -+ /* -+ * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where: -+ * T1 = HMAC-SHA1(K, S | LEN | 0x01) -+ * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02) -+ * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03) -+ * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04) -+ * ... -+ */ -+ -+ extra[0] = buf_len & 0xff; -+ -+ addr[3] = extra; -+ len[3] = 1; -+ addr[4] = &counter; -+ len[4] = 1; -+ } -+ -+ pos = 0; -+ while (pos < buf_len) { -+ counter++; -+ plen = buf_len - pos; -+ hmac_sha1_vector(key, key_len, 5, addr, len, hash); -+ if (plen >= SHA1_MAC_LEN) { -+ os_memcpy(&buf[pos], hash, SHA1_MAC_LEN); -+ pos += SHA1_MAC_LEN; -+ } else { -+ os_memcpy(&buf[pos], hash, plen); -+ break; -+ } -+ len[0] = SHA1_MAC_LEN; -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.h -new file mode 100644 -index 0000000000000..f59afb07d098d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_peap_common.h -@@ -0,0 +1,22 @@ -+/* -+ * EAP-PEAP common routines -+ * Copyright (c) 2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_PEAP_COMMON_H -+#define EAP_PEAP_COMMON_H -+ -+void peap_prfplus(int version, const u8 *key, size_t key_len, -+ const char *label, const u8 *seed, size_t seed_len, -+ u8 *buf, size_t buf_len); -+ -+#endif /* EAP_PEAP_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.c -new file mode 100644 -index 0000000000000..7417d5c73df5e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.c -@@ -0,0 +1,74 @@ -+/* -+ * EAP server/peer: EAP-PSK shared routines -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "eap_defs.h" -+#include "eap_psk_common.h" -+ -+#define aes_block_size 16 -+ -+ -+int eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk) -+{ -+ os_memset(ak, 0, aes_block_size); -+ if (aes_128_encrypt_block(psk, ak, ak)) -+ return -1; -+ os_memcpy(kdk, ak, aes_block_size); -+ ak[aes_block_size - 1] ^= 0x01; -+ kdk[aes_block_size - 1] ^= 0x02; -+ if (aes_128_encrypt_block(psk, ak, ak) || -+ aes_128_encrypt_block(psk, kdk, kdk)) -+ return -1; -+ return 0; -+} -+ -+ -+int eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk, -+ u8 *emsk) -+{ -+ u8 hash[aes_block_size]; -+ u8 counter = 1; -+ int i; -+ -+ if (aes_128_encrypt_block(kdk, rand_p, hash)) -+ return -1; -+ -+ hash[aes_block_size - 1] ^= counter; -+ if (aes_128_encrypt_block(kdk, hash, tek)) -+ return -1; -+ hash[aes_block_size - 1] ^= counter; -+ counter++; -+ -+ for (i = 0; i < EAP_MSK_LEN / aes_block_size; i++) { -+ hash[aes_block_size - 1] ^= counter; -+ if (aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size])) -+ return -1; -+ hash[aes_block_size - 1] ^= counter; -+ counter++; -+ } -+ -+ for (i = 0; i < EAP_EMSK_LEN / aes_block_size; i++) { -+ hash[aes_block_size - 1] ^= counter; -+ if (aes_128_encrypt_block(kdk, hash, -+ &emsk[i * aes_block_size])) -+ return -1; -+ hash[aes_block_size - 1] ^= counter; -+ counter++; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.h -new file mode 100644 -index 0000000000000..8adc0541ee03a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_psk_common.h -@@ -0,0 +1,78 @@ -+/* -+ * EAP server/peer: EAP-PSK shared routines -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_PSK_COMMON_H -+#define EAP_PSK_COMMON_H -+ -+ -+#define EAP_PSK_RAND_LEN 16 -+#define EAP_PSK_MAC_LEN 16 -+#define EAP_PSK_TEK_LEN 16 -+#define EAP_PSK_PSK_LEN 16 -+#define EAP_PSK_AK_LEN 16 -+#define EAP_PSK_KDK_LEN 16 -+ -+#define EAP_PSK_R_FLAG_CONT 1 -+#define EAP_PSK_R_FLAG_DONE_SUCCESS 2 -+#define EAP_PSK_R_FLAG_DONE_FAILURE 3 -+#define EAP_PSK_E_FLAG 0x20 -+ -+#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6) -+#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6) -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+/* EAP-PSK First Message (AS -> Supplicant) */ -+struct eap_psk_hdr_1 { -+ u8 flags; -+ u8 rand_s[EAP_PSK_RAND_LEN]; -+ /* Followed by variable length ID_S */ -+} STRUCT_PACKED; -+ -+/* EAP-PSK Second Message (Supplicant -> AS) */ -+struct eap_psk_hdr_2 { -+ u8 flags; -+ u8 rand_s[EAP_PSK_RAND_LEN]; -+ u8 rand_p[EAP_PSK_RAND_LEN]; -+ u8 mac_p[EAP_PSK_MAC_LEN]; -+ /* Followed by variable length ID_P */ -+} STRUCT_PACKED; -+ -+/* EAP-PSK Third Message (AS -> Supplicant) */ -+struct eap_psk_hdr_3 { -+ u8 flags; -+ u8 rand_s[EAP_PSK_RAND_LEN]; -+ u8 mac_s[EAP_PSK_MAC_LEN]; -+ /* Followed by variable length PCHANNEL */ -+} STRUCT_PACKED; -+ -+/* EAP-PSK Fourth Message (Supplicant -> AS) */ -+struct eap_psk_hdr_4 { -+ u8 flags; -+ u8 rand_s[EAP_PSK_RAND_LEN]; -+ /* Followed by variable length PCHANNEL */ -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk); -+int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, -+ u8 *msk, u8 *emsk); -+ -+#endif /* EAP_PSK_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.c -new file mode 100644 -index 0000000000000..c24b146cf894e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.c -@@ -0,0 +1,312 @@ -+/* -+ * EAP server/peer: EAP-pwd shared routines -+ * Copyright (c) 2010, Dan Harkins -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the BSD license. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include "common.h" -+#include "eap_defs.h" -+#include "eap_pwd_common.h" -+ -+/* The random function H(x) = HMAC-SHA256(0^32, x) */ -+void H_Init(HMAC_CTX *ctx) -+{ -+ u8 allzero[SHA256_DIGEST_LENGTH]; -+ -+ os_memset(allzero, 0, SHA256_DIGEST_LENGTH); -+ HMAC_Init(ctx, allzero, SHA256_DIGEST_LENGTH, EVP_sha256()); -+} -+ -+ -+void H_Update(HMAC_CTX *ctx, const u8 *data, int len) -+{ -+ HMAC_Update(ctx, data, len); -+} -+ -+ -+void H_Final(HMAC_CTX *ctx, u8 *digest) -+{ -+ unsigned int mdlen = SHA256_DIGEST_LENGTH; -+ -+ HMAC_Final(ctx, digest, &mdlen); -+ HMAC_CTX_cleanup(ctx); -+} -+ -+ -+/* a counter-based KDF based on NIST SP800-108 */ -+void eap_pwd_kdf(u8 *key, int keylen, u8 *label, int labellen, -+ u8 *result, int resultbitlen) -+{ -+ HMAC_CTX hctx; -+ unsigned char digest[SHA256_DIGEST_LENGTH]; -+ u16 i, ctr, L; -+ int resultbytelen, len = 0; -+ unsigned int mdlen = SHA256_DIGEST_LENGTH; -+ unsigned char mask = 0xff; -+ -+ resultbytelen = (resultbitlen + 7)/8; -+ ctr = 0; -+ L = htons(resultbitlen); -+ while (len < resultbytelen) { -+ ctr++; i = htons(ctr); -+ HMAC_Init(&hctx, key, keylen, EVP_sha256()); -+ if (ctr > 1) -+ HMAC_Update(&hctx, digest, mdlen); -+ HMAC_Update(&hctx, (u8 *) &i, sizeof(u16)); -+ HMAC_Update(&hctx, label, labellen); -+ HMAC_Update(&hctx, (u8 *) &L, sizeof(u16)); -+ HMAC_Final(&hctx, digest, &mdlen); -+ if ((len + (int) mdlen) > resultbytelen) -+ os_memcpy(result + len, digest, resultbytelen - len); -+ else -+ os_memcpy(result + len, digest, mdlen); -+ len += mdlen; -+ HMAC_CTX_cleanup(&hctx); -+ } -+ -+ /* since we're expanding to a bit length, mask off the excess */ -+ if (resultbitlen % 8) { -+ mask >>= ((resultbytelen * 8) - resultbitlen); -+ result[0] &= mask; -+ } -+} -+ -+ -+/* -+ * compute a "random" secret point on an elliptic curve based -+ * on the password and identities. -+ */ -+int compute_password_element(EAP_PWD_group *grp, u16 num, -+ u8 *password, int password_len, -+ u8 *id_server, int id_server_len, -+ u8 *id_peer, int id_peer_len, u8 *token) -+{ -+ BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; -+ HMAC_CTX ctx; -+ unsigned char pwe_digest[SHA256_DIGEST_LENGTH], *prfbuf = NULL, ctr; -+ int nid, is_odd, primebitlen, primebytelen, ret = 0; -+ -+ switch (num) { /* from IANA registry for IKE D-H groups */ -+ case 19: -+ nid = NID_X9_62_prime256v1; -+ break; -+ case 20: -+ nid = NID_secp384r1; -+ break; -+ case 21: -+ nid = NID_secp521r1; -+ break; -+ case 25: -+ nid = NID_X9_62_prime192v1; -+ break; -+ case 26: -+ nid = NID_secp224r1; -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-pwd: unsupported group %d", num); -+ return -1; -+ } -+ -+ grp->pwe = NULL; -+ grp->order = NULL; -+ grp->prime = NULL; -+ -+ if ((grp->group = EC_GROUP_new_by_curve_name(nid)) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create EC_GROUP"); -+ goto fail; -+ } -+ -+ if (((rnd = BN_new()) == NULL) || -+ ((cofactor = BN_new()) == NULL) || -+ ((grp->pwe = EC_POINT_new(grp->group)) == NULL) || -+ ((grp->order = BN_new()) == NULL) || -+ ((grp->prime = BN_new()) == NULL) || -+ ((x_candidate = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: unable to create bignums"); -+ goto fail; -+ } -+ -+ if (!EC_GROUP_get_curve_GFp(grp->group, grp->prime, NULL, NULL, NULL)) -+ { -+ wpa_printf(MSG_INFO, "EAP-pwd: unable to get prime for GFp " -+ "curve"); -+ goto fail; -+ } -+ if (!EC_GROUP_get_order(grp->group, grp->order, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: unable to get order for curve"); -+ goto fail; -+ } -+ if (!EC_GROUP_get_cofactor(grp->group, cofactor, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: unable to get cofactor for " -+ "curve"); -+ goto fail; -+ } -+ primebitlen = BN_num_bits(grp->prime); -+ primebytelen = BN_num_bytes(grp->prime); -+ if ((prfbuf = os_malloc(primebytelen)) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-pwd: unable to malloc space for prf " -+ "buffer"); -+ goto fail; -+ } -+ os_memset(prfbuf, 0, primebytelen); -+ ctr = 0; -+ while (1) { -+ if (ctr > 10) { -+ wpa_printf(MSG_INFO, "EAP-pwd: unable to find random " -+ "point on curve for group %d, something's " -+ "fishy", num); -+ goto fail; -+ } -+ ctr++; -+ -+ /* -+ * compute counter-mode password value and stretch to prime -+ * pwd-seed = H(token | peer-id | server-id | password | -+ * counter) -+ */ -+ H_Init(&ctx); -+ H_Update(&ctx, token, sizeof(u32)); -+ H_Update(&ctx, id_peer, id_peer_len); -+ H_Update(&ctx, id_server, id_server_len); -+ H_Update(&ctx, password, password_len); -+ H_Update(&ctx, &ctr, sizeof(ctr)); -+ H_Final(&ctx, pwe_digest); -+ -+ BN_bin2bn(pwe_digest, SHA256_DIGEST_LENGTH, rnd); -+ -+ eap_pwd_kdf(pwe_digest, SHA256_DIGEST_LENGTH, -+ (unsigned char *) "EAP-pwd Hunting And Pecking", -+ os_strlen("EAP-pwd Hunting And Pecking"), -+ prfbuf, primebitlen); -+ -+ BN_bin2bn(prfbuf, primebytelen, x_candidate); -+ if (BN_ucmp(x_candidate, grp->prime) >= 0) -+ continue; -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-pwd: x_candidate", -+ prfbuf, primebytelen); -+ -+ /* -+ * need to unambiguously identify the solution, if there is -+ * one... -+ */ -+ if (BN_is_odd(rnd)) -+ is_odd = 1; -+ else -+ is_odd = 0; -+ -+ /* -+ * solve the quadratic equation, if it's not solvable then we -+ * don't have a point -+ */ -+ if (!EC_POINT_set_compressed_coordinates_GFp(grp->group, -+ grp->pwe, -+ x_candidate, -+ is_odd, NULL)) -+ continue; -+ /* -+ * If there's a solution to the equation then the point must be -+ * on the curve so why check again explicitly? OpenSSL code -+ * says this is required by X9.62. We're not X9.62 but it can't -+ * hurt just to be sure. -+ */ -+ if (!EC_POINT_is_on_curve(grp->group, grp->pwe, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: point is not on curve"); -+ continue; -+ } -+ -+ if (BN_cmp(cofactor, BN_value_one())) { -+ /* make sure the point is not in a small sub-group */ -+ if (!EC_POINT_mul(grp->group, grp->pwe, NULL, grp->pwe, -+ cofactor, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: cannot " -+ "multiply generator by order"); -+ continue; -+ } -+ if (EC_POINT_is_at_infinity(grp->group, grp->pwe)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: point is at " -+ "infinity"); -+ continue; -+ } -+ } -+ /* if we got here then we have a new generator. */ -+ break; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-pwd: found a PWE in %d tries", ctr); -+ grp->group_num = num; -+ if (0) { -+ fail: -+ EC_GROUP_free(grp->group); -+ EC_POINT_free(grp->pwe); -+ BN_free(grp->order); -+ BN_free(grp->prime); -+ os_free(grp); -+ grp = NULL; -+ ret = 1; -+ } -+ /* cleanliness and order.... */ -+ BN_free(cofactor); -+ BN_free(x_candidate); -+ BN_free(rnd); -+ os_free(prfbuf); -+ -+ return ret; -+} -+ -+ -+int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k, -+ BIGNUM *peer_scalar, BIGNUM *server_scalar, -+ u8 *commit_peer, u8 *commit_server, -+ u32 *ciphersuite, u8 *msk, u8 *emsk) -+{ -+ HMAC_CTX ctx; -+ u8 mk[SHA256_DIGEST_LENGTH], *cruft; -+ u8 session_id[SHA256_DIGEST_LENGTH + 1]; -+ u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN]; -+ -+ if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL) -+ return -1; -+ -+ /* -+ * first compute the session-id = TypeCode | H(ciphersuite | scal_p | -+ * scal_s) -+ */ -+ session_id[0] = EAP_TYPE_PWD; -+ H_Init(&ctx); -+ H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32)); -+ BN_bn2bin(peer_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(grp->order)); -+ BN_bn2bin(server_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(grp->order)); -+ H_Final(&ctx, &session_id[1]); -+ -+ /* then compute MK = H(k | commit-peer | commit-server) */ -+ H_Init(&ctx); -+ os_memset(cruft, 0, BN_num_bytes(grp->prime)); -+ BN_bn2bin(k, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(grp->prime)); -+ H_Update(&ctx, commit_peer, SHA256_DIGEST_LENGTH); -+ H_Update(&ctx, commit_server, SHA256_DIGEST_LENGTH); -+ H_Final(&ctx, mk); -+ -+ /* stretch the mk with the session-id to get MSK | EMSK */ -+ eap_pwd_kdf(mk, SHA256_DIGEST_LENGTH, -+ session_id, SHA256_DIGEST_LENGTH+1, -+ msk_emsk, (EAP_MSK_LEN + EAP_EMSK_LEN) * 8); -+ -+ os_memcpy(msk, msk_emsk, EAP_MSK_LEN); -+ os_memcpy(emsk, msk_emsk + EAP_MSK_LEN, EAP_EMSK_LEN); -+ -+ os_free(cruft); -+ -+ return 1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.h -new file mode 100644 -index 0000000000000..971386d740898 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_pwd_common.h -@@ -0,0 +1,79 @@ -+/* -+ * EAP server/peer: EAP-pwd shared definitions -+ * Copyright (c) 2009, Dan Harkins -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the BSD license. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_PWD_COMMON_H -+#define EAP_PWD_COMMON_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * definition of a finite cyclic group -+ * TODO: support one based on a prime field -+ */ -+typedef struct group_definition_ { -+ u16 group_num; -+ EC_GROUP *group; -+ EC_POINT *pwe; -+ BIGNUM *order; -+ BIGNUM *prime; -+} EAP_PWD_group; -+ -+/* -+ * EAP-pwd header, included on all payloads -+ */ -+struct eap_pwd_hdr { -+ u8 l_bit:1; -+ u8 m_bit:1; -+ u8 exch:6; -+ u8 total_length[0]; /* included when l_bit is set */ -+} STRUCT_PACKED; -+ -+#define EAP_PWD_OPCODE_ID_EXCH 1 -+#define EAP_PWD_OPCODE_COMMIT_EXCH 2 -+#define EAP_PWD_OPCODE_CONFIRM_EXCH 3 -+#define EAP_PWD_GET_LENGTH_BIT(x) ((x)->lm_exch & 0x80) -+#define EAP_PWD_SET_LENGTH_BIT(x) ((x)->lm_exch |= 0x80) -+#define EAP_PWD_GET_MORE_BIT(x) ((x)->lm_exch & 0x40) -+#define EAP_PWD_SET_MORE_BIT(x) ((x)->lm_exch |= 0x40) -+#define EAP_PWD_GET_EXCHANGE(x) ((x)->lm_exch & 0x3f) -+#define EAP_PWD_SET_EXCHANGE(x,y) ((x)->lm_exch |= (y)) -+ -+/* EAP-pwd-ID payload */ -+struct eap_pwd_id { -+ be16 group_num; -+ u8 random_function; -+#define EAP_PWD_DEFAULT_RAND_FUNC 1 -+ u8 prf; -+#define EAP_PWD_DEFAULT_PRF 1 -+ u8 token[4]; -+ u8 prep; -+#define EAP_PWD_PREP_NONE 0 -+#define EAP_PWD_PREP_MS 1 -+ u8 identity[0]; /* length inferred from payload */ -+} STRUCT_PACKED; -+ -+/* common routines */ -+int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *, -+ int, u8 *); -+int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *, -+ u8 *, u8 *, u32 *, u8 *, u8 *); -+void H_Init(HMAC_CTX *); -+void H_Update(HMAC_CTX *, const u8 *, int); -+void H_Final(HMAC_CTX *, u8 *); -+ -+#endif /* EAP_PWD_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.c -new file mode 100644 -index 0000000000000..9002b0ca328a4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.c -@@ -0,0 +1,393 @@ -+/* -+ * EAP server/peer: EAP-SAKE shared routines -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "wpabuf.h" -+#include "crypto/sha1.h" -+#include "eap_defs.h" -+#include "eap_sake_common.h" -+ -+ -+static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr, -+ const u8 *pos) -+{ -+ size_t i; -+ -+ switch (pos[0]) { -+ case EAP_SAKE_AT_RAND_S: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S"); -+ if (pos[1] != 2 + EAP_SAKE_RAND_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with " -+ "invalid length %d", pos[1]); -+ return -1; -+ } -+ attr->rand_s = pos + 2; -+ break; -+ case EAP_SAKE_AT_RAND_P: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P"); -+ if (pos[1] != 2 + EAP_SAKE_RAND_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with " -+ "invalid length %d", pos[1]); -+ return -1; -+ } -+ attr->rand_p = pos + 2; -+ break; -+ case EAP_SAKE_AT_MIC_S: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S"); -+ if (pos[1] != 2 + EAP_SAKE_MIC_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with " -+ "invalid length %d", pos[1]); -+ return -1; -+ } -+ attr->mic_s = pos + 2; -+ break; -+ case EAP_SAKE_AT_MIC_P: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P"); -+ if (pos[1] != 2 + EAP_SAKE_MIC_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with " -+ "invalid length %d", pos[1]); -+ return -1; -+ } -+ attr->mic_p = pos + 2; -+ break; -+ case EAP_SAKE_AT_SERVERID: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID"); -+ attr->serverid = pos + 2; -+ attr->serverid_len = pos[1] - 2; -+ break; -+ case EAP_SAKE_AT_PEERID: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID"); -+ attr->peerid = pos + 2; -+ attr->peerid_len = pos[1] - 2; -+ break; -+ case EAP_SAKE_AT_SPI_S: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S"); -+ attr->spi_s = pos + 2; -+ attr->spi_s_len = pos[1] - 2; -+ break; -+ case EAP_SAKE_AT_SPI_P: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P"); -+ attr->spi_p = pos + 2; -+ attr->spi_p_len = pos[1] - 2; -+ break; -+ case EAP_SAKE_AT_ANY_ID_REQ: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ"); -+ if (pos[1] != 4) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ" -+ " length %d", pos[1]); -+ return -1; -+ } -+ attr->any_id_req = pos + 2; -+ break; -+ case EAP_SAKE_AT_PERM_ID_REQ: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ"); -+ if (pos[1] != 4) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid " -+ "AT_PERM_ID_REQ length %d", pos[1]); -+ return -1; -+ } -+ attr->perm_id_req = pos + 2; -+ break; -+ case EAP_SAKE_AT_ENCR_DATA: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA"); -+ attr->encr_data = pos + 2; -+ attr->encr_data_len = pos[1] - 2; -+ break; -+ case EAP_SAKE_AT_IV: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV"); -+ attr->iv = pos + 2; -+ attr->iv_len = pos[1] - 2; -+ break; -+ case EAP_SAKE_AT_PADDING: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING"); -+ for (i = 2; i < pos[1]; i++) { -+ if (pos[i]) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING " -+ "with non-zero pad byte"); -+ return -1; -+ } -+ } -+ break; -+ case EAP_SAKE_AT_NEXT_TMPID: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID"); -+ attr->next_tmpid = pos + 2; -+ attr->next_tmpid_len = pos[1] - 2; -+ break; -+ case EAP_SAKE_AT_MSK_LIFE: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV"); -+ if (pos[1] != 6) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid " -+ "AT_MSK_LIFE length %d", pos[1]); -+ return -1; -+ } -+ attr->msk_life = pos + 2; -+ break; -+ default: -+ if (pos[0] < 128) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable" -+ " attribute %d", pos[0]); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable " -+ "attribute %d", pos[0]); -+ break; -+ } -+ -+ if (attr->iv && !attr->encr_data) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without " -+ "AT_ENCR_DATA"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_sake_parse_attributes - Parse EAP-SAKE attributes -+ * @buf: Packet payload (starting with the first attribute) -+ * @len: Payload length -+ * @attr: Structure to be filled with found attributes -+ * Returns: 0 on success or -1 on failure -+ */ -+int eap_sake_parse_attributes(const u8 *buf, size_t len, -+ struct eap_sake_parse_attr *attr) -+{ -+ const u8 *pos = buf, *end = buf + len; -+ -+ os_memset(attr, 0, sizeof(*attr)); -+ while (pos < end) { -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute"); -+ return -1; -+ } -+ -+ if (pos[1] < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute " -+ "length (%d)", pos[1]); -+ return -1; -+ } -+ -+ if (pos + pos[1] > end) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow"); -+ return -1; -+ } -+ -+ if (eap_sake_parse_add_attr(attr, pos)) -+ return -1; -+ -+ pos += pos[1]; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF) -+ * @key: Key for KDF -+ * @key_len: Length of the key in bytes -+ * @label: A unique label for each purpose of the KDF -+ * @data: Extra data (start) to bind into the key -+ * @data_len: Length of the data -+ * @data2: Extra data (end) to bind into the key -+ * @data2_len: Length of the data2 -+ * @buf: Buffer for the generated pseudo-random key -+ * @buf_len: Number of bytes of key to generate -+ * -+ * This function is used to derive new, cryptographically separate keys from a -+ * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i. -+ */ -+static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label, -+ const u8 *data, size_t data_len, -+ const u8 *data2, size_t data2_len, -+ u8 *buf, size_t buf_len) -+{ -+ u8 counter = 0; -+ size_t pos, plen; -+ u8 hash[SHA1_MAC_LEN]; -+ size_t label_len = os_strlen(label) + 1; -+ const unsigned char *addr[4]; -+ size_t len[4]; -+ -+ addr[0] = (u8 *) label; /* Label | Y */ -+ len[0] = label_len; -+ addr[1] = data; /* Msg[start] */ -+ len[1] = data_len; -+ addr[2] = data2; /* Msg[end] */ -+ len[2] = data2_len; -+ addr[3] = &counter; /* Length */ -+ len[3] = 1; -+ -+ pos = 0; -+ while (pos < buf_len) { -+ plen = buf_len - pos; -+ if (plen >= SHA1_MAC_LEN) { -+ hmac_sha1_vector(key, key_len, 4, addr, len, -+ &buf[pos]); -+ pos += SHA1_MAC_LEN; -+ } else { -+ hmac_sha1_vector(key, key_len, 4, addr, len, -+ hash); -+ os_memcpy(&buf[pos], hash, plen); -+ break; -+ } -+ counter++; -+ } -+} -+ -+ -+/** -+ * eap_sake_derive_keys - Derive EAP-SAKE keys -+ * @root_secret_a: 16-byte Root-Secret-A -+ * @root_secret_b: 16-byte Root-Secret-B -+ * @rand_s: 16-byte RAND_S -+ * @rand_p: 16-byte RAND_P -+ * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16]) -+ * @msk: Buffer for 64-byte MSK -+ * @emsk: Buffer for 64-byte EMSK -+ * -+ * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6. -+ */ -+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b, -+ const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk, -+ u8 *emsk) -+{ -+ u8 sms_a[EAP_SAKE_SMS_LEN]; -+ u8 sms_b[EAP_SAKE_SMS_LEN]; -+ u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys"); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A", -+ root_secret_a, EAP_SAKE_ROOT_SECRET_LEN); -+ eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN, -+ "SAKE Master Secret A", -+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN, -+ sms_a, EAP_SAKE_SMS_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN); -+ eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key", -+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN, -+ tek, EAP_SAKE_TEK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth", -+ tek, EAP_SAKE_TEK_AUTH_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher", -+ tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B", -+ root_secret_b, EAP_SAKE_ROOT_SECRET_LEN); -+ eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN, -+ "SAKE Master Secret B", -+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN, -+ sms_b, EAP_SAKE_SMS_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN); -+ eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key", -+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN, -+ key_buf, sizeof(key_buf)); -+ os_memcpy(msk, key_buf, EAP_MSK_LEN); -+ os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN); -+} -+ -+ -+/** -+ * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet -+ * @tek_auth: 16-byte TEK-Auth -+ * @rand_s: 16-byte RAND_S -+ * @rand_p: 16-byte RAND_P -+ * @serverid: SERVERID -+ * @serverid_len: SERVERID length -+ * @peerid: PEERID -+ * @peerid_len: PEERID length -+ * @peer: MIC calculation for 0 = Server, 1 = Peer message -+ * @eap: EAP packet -+ * @eap_len: EAP packet length -+ * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len]) -+ * @mic: Buffer for the computed 16-byte MIC -+ */ -+int eap_sake_compute_mic(const u8 *tek_auth, -+ const u8 *rand_s, const u8 *rand_p, -+ const u8 *serverid, size_t serverid_len, -+ const u8 *peerid, size_t peerid_len, -+ int peer, const u8 *eap, size_t eap_len, -+ const u8 *mic_pos, u8 *mic) -+{ -+ u8 _rand[2 * EAP_SAKE_RAND_LEN]; -+ u8 *tmp, *pos; -+ size_t tmplen; -+ -+ tmplen = serverid_len + 1 + peerid_len + 1 + eap_len; -+ tmp = os_malloc(tmplen); -+ if (tmp == NULL) -+ return -1; -+ pos = tmp; -+ if (peer) { -+ if (peerid) { -+ os_memcpy(pos, peerid, peerid_len); -+ pos += peerid_len; -+ } -+ *pos++ = 0x00; -+ if (serverid) { -+ os_memcpy(pos, serverid, serverid_len); -+ pos += serverid_len; -+ } -+ *pos++ = 0x00; -+ -+ os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN); -+ os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p, -+ EAP_SAKE_RAND_LEN); -+ } else { -+ if (serverid) { -+ os_memcpy(pos, serverid, serverid_len); -+ pos += serverid_len; -+ } -+ *pos++ = 0x00; -+ if (peerid) { -+ os_memcpy(pos, peerid, peerid_len); -+ pos += peerid_len; -+ } -+ *pos++ = 0x00; -+ -+ os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN); -+ os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s, -+ EAP_SAKE_RAND_LEN); -+ } -+ -+ os_memcpy(pos, eap, eap_len); -+ os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN); -+ -+ eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN, -+ peer ? "Peer MIC" : "Server MIC", -+ _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen, -+ mic, EAP_SAKE_MIC_LEN); -+ -+ os_free(tmp); -+ -+ return 0; -+} -+ -+ -+void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data, -+ size_t len) -+{ -+ wpabuf_put_u8(buf, type); -+ wpabuf_put_u8(buf, 2 + len); /* Length; including attr header */ -+ if (data) -+ wpabuf_put_data(buf, data, len); -+ else -+ os_memset(wpabuf_put(buf, len), 0, len); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.h -new file mode 100644 -index 0000000000000..201e20729cb0e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sake_common.h -@@ -0,0 +1,102 @@ -+/* -+ * EAP server/peer: EAP-SAKE shared routines -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_SAKE_COMMON_H -+#define EAP_SAKE_COMMON_H -+ -+#define EAP_SAKE_VERSION 2 -+ -+#define EAP_SAKE_SUBTYPE_CHALLENGE 1 -+#define EAP_SAKE_SUBTYPE_CONFIRM 2 -+#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3 -+#define EAP_SAKE_SUBTYPE_IDENTITY 4 -+ -+#define EAP_SAKE_AT_RAND_S 1 -+#define EAP_SAKE_AT_RAND_P 2 -+#define EAP_SAKE_AT_MIC_S 3 -+#define EAP_SAKE_AT_MIC_P 4 -+#define EAP_SAKE_AT_SERVERID 5 -+#define EAP_SAKE_AT_PEERID 6 -+#define EAP_SAKE_AT_SPI_S 7 -+#define EAP_SAKE_AT_SPI_P 8 -+#define EAP_SAKE_AT_ANY_ID_REQ 9 -+#define EAP_SAKE_AT_PERM_ID_REQ 10 -+#define EAP_SAKE_AT_ENCR_DATA 128 -+#define EAP_SAKE_AT_IV 129 -+#define EAP_SAKE_AT_PADDING 130 -+#define EAP_SAKE_AT_NEXT_TMPID 131 -+#define EAP_SAKE_AT_MSK_LIFE 132 -+ -+#define EAP_SAKE_RAND_LEN 16 -+#define EAP_SAKE_MIC_LEN 16 -+#define EAP_SAKE_ROOT_SECRET_LEN 16 -+#define EAP_SAKE_SMS_LEN 16 -+#define EAP_SAKE_TEK_AUTH_LEN 16 -+#define EAP_SAKE_TEK_CIPHER_LEN 16 -+#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN) -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct eap_sake_hdr { -+ u8 version; /* EAP_SAKE_VERSION */ -+ u8 session_id; -+ u8 subtype; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+struct eap_sake_parse_attr { -+ const u8 *rand_s; -+ const u8 *rand_p; -+ const u8 *mic_s; -+ const u8 *mic_p; -+ const u8 *serverid; -+ size_t serverid_len; -+ const u8 *peerid; -+ size_t peerid_len; -+ const u8 *spi_s; -+ size_t spi_s_len; -+ const u8 *spi_p; -+ size_t spi_p_len; -+ const u8 *any_id_req; -+ const u8 *perm_id_req; -+ const u8 *encr_data; -+ size_t encr_data_len; -+ const u8 *iv; -+ size_t iv_len; -+ const u8 *next_tmpid; -+ size_t next_tmpid_len; -+ const u8 *msk_life; -+}; -+ -+int eap_sake_parse_attributes(const u8 *buf, size_t len, -+ struct eap_sake_parse_attr *attr); -+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b, -+ const u8 *rand_s, const u8 *rand_p, -+ u8 *tek, u8 *msk, u8 *emsk); -+int eap_sake_compute_mic(const u8 *tek_auth, -+ const u8 *rand_s, const u8 *rand_p, -+ const u8 *serverid, size_t serverid_len, -+ const u8 *peerid, size_t peerid_len, -+ int peer, const u8 *eap, size_t eap_len, -+ const u8 *mic_pos, u8 *mic); -+void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data, -+ size_t len); -+ -+#endif /* EAP_SAKE_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.c -new file mode 100644 -index 0000000000000..0b37b0b93c2aa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.c -@@ -0,0 +1,1215 @@ -+/* -+ * EAP peer/server: EAP-SIM/AKA/AKA' shared routines -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "wpabuf.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/crypto.h" -+#include "crypto/sha1.h" -+#include "crypto/sha256.h" -+#include "crypto/random.h" -+#include "eap_common/eap_defs.h" -+#include "eap_common/eap_sim_common.h" -+ -+ -+static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen) -+{ -+ return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen); -+} -+ -+ -+void eap_sim_derive_mk(const u8 *identity, size_t identity_len, -+ const u8 *nonce_mt, u16 selected_version, -+ const u8 *ver_list, size_t ver_list_len, -+ int num_chal, const u8 *kc, u8 *mk) -+{ -+ u8 sel_ver[2]; -+ const unsigned char *addr[5]; -+ size_t len[5]; -+ -+ addr[0] = identity; -+ len[0] = identity_len; -+ addr[1] = kc; -+ len[1] = num_chal * EAP_SIM_KC_LEN; -+ addr[2] = nonce_mt; -+ len[2] = EAP_SIM_NONCE_MT_LEN; -+ addr[3] = ver_list; -+ len[3] = ver_list_len; -+ addr[4] = sel_ver; -+ len[4] = 2; -+ -+ WPA_PUT_BE16(sel_ver, selected_version); -+ -+ /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */ -+ sha1_vector(5, addr, len, mk); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN); -+} -+ -+ -+void eap_aka_derive_mk(const u8 *identity, size_t identity_len, -+ const u8 *ik, const u8 *ck, u8 *mk) -+{ -+ const u8 *addr[3]; -+ size_t len[3]; -+ -+ addr[0] = identity; -+ len[0] = identity_len; -+ addr[1] = ik; -+ len[1] = EAP_AKA_IK_LEN; -+ addr[2] = ck; -+ len[2] = EAP_AKA_CK_LEN; -+ -+ /* MK = SHA1(Identity|IK|CK) */ -+ sha1_vector(3, addr, len, mk); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN); -+} -+ -+ -+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk) -+{ -+ u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN + -+ EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos; -+ if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys"); -+ return -1; -+ } -+ pos = buf; -+ os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN); -+ pos += EAP_SIM_K_ENCR_LEN; -+ os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN); -+ pos += EAP_SIM_K_AUT_LEN; -+ os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN); -+ pos += EAP_SIM_KEYING_DATA_LEN; -+ os_memcpy(emsk, pos, EAP_EMSK_LEN); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr", -+ k_encr, EAP_SIM_K_ENCR_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut", -+ k_aut, EAP_SIM_K_AUT_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)", -+ msk, EAP_SIM_KEYING_DATA_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN); -+ os_memset(buf, 0, sizeof(buf)); -+ -+ return 0; -+} -+ -+ -+int eap_sim_derive_keys_reauth(u16 _counter, -+ const u8 *identity, size_t identity_len, -+ const u8 *nonce_s, const u8 *mk, u8 *msk, -+ u8 *emsk) -+{ -+ u8 xkey[SHA1_MAC_LEN]; -+ u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32]; -+ u8 counter[2]; -+ const u8 *addr[4]; -+ size_t len[4]; -+ -+ while (identity_len > 0 && identity[identity_len - 1] == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop null " -+ "character from the end of identity"); -+ identity_len--; -+ } -+ addr[0] = identity; -+ len[0] = identity_len; -+ addr[1] = counter; -+ len[1] = 2; -+ addr[2] = nonce_s; -+ len[2] = EAP_SIM_NONCE_S_LEN; -+ addr[3] = mk; -+ len[3] = EAP_SIM_MK_LEN; -+ -+ WPA_PUT_BE16(counter, _counter); -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth"); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", -+ identity, identity_len); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: counter", counter, 2); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: NONCE_S", nonce_s, -+ EAP_SIM_NONCE_S_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN); -+ -+ /* XKEY' = SHA1(Identity|counter|NONCE_S|MK) */ -+ sha1_vector(4, addr, len, xkey); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN); -+ -+ if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys"); -+ return -1; -+ } -+ if (msk) { -+ os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)", -+ msk, EAP_SIM_KEYING_DATA_LEN); -+ } -+ if (emsk) { -+ os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN); -+ } -+ os_memset(buf, 0, sizeof(buf)); -+ -+ return 0; -+} -+ -+ -+int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, -+ const u8 *mac, const u8 *extra, size_t extra_len) -+{ -+ unsigned char hmac[SHA1_MAC_LEN]; -+ const u8 *addr[2]; -+ size_t len[2]; -+ u8 *tmp; -+ -+ if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || -+ mac < wpabuf_head_u8(req) || -+ mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) -+ return -1; -+ -+ tmp = os_malloc(wpabuf_len(req)); -+ if (tmp == NULL) -+ return -1; -+ -+ addr[0] = tmp; -+ len[0] = wpabuf_len(req); -+ addr[1] = extra; -+ len[1] = extra_len; -+ -+ /* HMAC-SHA1-128 */ -+ os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); -+ os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", -+ tmp, wpabuf_len(req)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data", -+ extra, extra_len); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut", -+ k_aut, EAP_SIM_K_AUT_LEN); -+ hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC", -+ hmac, EAP_SIM_MAC_LEN); -+ os_free(tmp); -+ -+ return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; -+} -+ -+ -+void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, -+ const u8 *extra, size_t extra_len) -+{ -+ unsigned char hmac[SHA1_MAC_LEN]; -+ const u8 *addr[2]; -+ size_t len[2]; -+ -+ addr[0] = msg; -+ len[0] = msg_len; -+ addr[1] = extra; -+ len[1] = extra_len; -+ -+ /* HMAC-SHA1-128 */ -+ os_memset(mac, 0, EAP_SIM_MAC_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data", -+ extra, extra_len); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut", -+ k_aut, EAP_SIM_K_AUT_LEN); -+ hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac); -+ os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC", -+ mac, EAP_SIM_MAC_LEN); -+} -+ -+ -+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) -+static void prf_prime(const u8 *k, const char *seed1, -+ const u8 *seed2, size_t seed2_len, -+ const u8 *seed3, size_t seed3_len, -+ u8 *res, size_t res_len) -+{ -+ const u8 *addr[5]; -+ size_t len[5]; -+ u8 hash[SHA256_MAC_LEN]; -+ u8 iter; -+ -+ /* -+ * PRF'(K,S) = T1 | T2 | T3 | T4 | ... -+ * T1 = HMAC-SHA-256 (K, S | 0x01) -+ * T2 = HMAC-SHA-256 (K, T1 | S | 0x02) -+ * T3 = HMAC-SHA-256 (K, T2 | S | 0x03) -+ * T4 = HMAC-SHA-256 (K, T3 | S | 0x04) -+ * ... -+ */ -+ -+ addr[0] = hash; -+ len[0] = 0; -+ addr[1] = (const u8 *) seed1; -+ len[1] = os_strlen(seed1); -+ addr[2] = seed2; -+ len[2] = seed2_len; -+ addr[3] = seed3; -+ len[3] = seed3_len; -+ addr[4] = &iter; -+ len[4] = 1; -+ -+ iter = 0; -+ while (res_len) { -+ size_t hlen; -+ iter++; -+ hmac_sha256_vector(k, 32, 5, addr, len, hash); -+ len[0] = SHA256_MAC_LEN; -+ hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len; -+ os_memcpy(res, hash, hlen); -+ res += hlen; -+ res_len -= hlen; -+ } -+} -+ -+ -+void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, -+ const u8 *ik, const u8 *ck, u8 *k_encr, -+ u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk) -+{ -+ u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN]; -+ u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN + -+ EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN]; -+ u8 *pos; -+ -+ /* -+ * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity) -+ * K_encr = MK[0..127] -+ * K_aut = MK[128..383] -+ * K_re = MK[384..639] -+ * MSK = MK[640..1151] -+ * EMSK = MK[1152..1663] -+ */ -+ -+ os_memcpy(key, ik, EAP_AKA_IK_LEN); -+ os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN); -+ -+ prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0, -+ keys, sizeof(keys)); -+ -+ pos = keys; -+ os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr", -+ k_encr, EAP_SIM_K_ENCR_LEN); -+ pos += EAP_SIM_K_ENCR_LEN; -+ -+ os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut", -+ k_aut, EAP_AKA_PRIME_K_AUT_LEN); -+ pos += EAP_AKA_PRIME_K_AUT_LEN; -+ -+ os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re", -+ k_re, EAP_AKA_PRIME_K_RE_LEN); -+ pos += EAP_AKA_PRIME_K_RE_LEN; -+ -+ os_memcpy(msk, pos, EAP_MSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN); -+ pos += EAP_MSK_LEN; -+ -+ os_memcpy(emsk, pos, EAP_EMSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN); -+} -+ -+ -+int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, -+ const u8 *identity, size_t identity_len, -+ const u8 *nonce_s, u8 *msk, u8 *emsk) -+{ -+ u8 seed3[2 + EAP_SIM_NONCE_S_LEN]; -+ u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN]; -+ u8 *pos; -+ -+ /* -+ * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S) -+ * MSK = MK[0..511] -+ * EMSK = MK[512..1023] -+ */ -+ -+ WPA_PUT_BE16(seed3, counter); -+ os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN); -+ -+ prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len, -+ seed3, sizeof(seed3), -+ keys, sizeof(keys)); -+ -+ pos = keys; -+ os_memcpy(msk, pos, EAP_MSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN); -+ pos += EAP_MSK_LEN; -+ -+ os_memcpy(emsk, pos, EAP_EMSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN); -+ -+ os_memset(keys, 0, sizeof(keys)); -+ -+ return 0; -+} -+ -+ -+int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, -+ const u8 *mac, const u8 *extra, size_t extra_len) -+{ -+ unsigned char hmac[SHA256_MAC_LEN]; -+ const u8 *addr[2]; -+ size_t len[2]; -+ u8 *tmp; -+ -+ if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || -+ mac < wpabuf_head_u8(req) || -+ mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) -+ return -1; -+ -+ tmp = os_malloc(wpabuf_len(req)); -+ if (tmp == NULL) -+ return -1; -+ -+ addr[0] = tmp; -+ len[0] = wpabuf_len(req); -+ addr[1] = extra; -+ len[1] = extra_len; -+ -+ /* HMAC-SHA-256-128 */ -+ os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); -+ os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg", -+ tmp, wpabuf_len(req)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data", -+ extra, extra_len); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut", -+ k_aut, EAP_AKA_PRIME_K_AUT_LEN); -+ hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC", -+ hmac, EAP_SIM_MAC_LEN); -+ os_free(tmp); -+ -+ return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; -+} -+ -+ -+void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, -+ u8 *mac, const u8 *extra, size_t extra_len) -+{ -+ unsigned char hmac[SHA256_MAC_LEN]; -+ const u8 *addr[2]; -+ size_t len[2]; -+ -+ addr[0] = msg; -+ len[0] = msg_len; -+ addr[1] = extra; -+ len[1] = extra_len; -+ -+ /* HMAC-SHA-256-128 */ -+ os_memset(mac, 0, EAP_SIM_MAC_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data", -+ extra, extra_len); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut", -+ k_aut, EAP_AKA_PRIME_K_AUT_LEN); -+ hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); -+ os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC", -+ mac, EAP_SIM_MAC_LEN); -+} -+ -+ -+void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, -+ const u8 *network_name, -+ size_t network_name_len) -+{ -+ u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN]; -+ u8 hash[SHA256_MAC_LEN]; -+ const u8 *addr[5]; -+ size_t len[5]; -+ u8 fc; -+ u8 l0[2], l1[2]; -+ -+ /* 3GPP TS 33.402 V8.0.0 -+ * (CK', IK') = F(CK, IK, ) -+ */ -+ /* TODO: CK', IK' generation should really be moved into the actual -+ * AKA procedure with network name passed in there and option to use -+ * AMF separation bit = 1 (3GPP TS 33.401). */ -+ -+ /* Change Request 33.402 CR 0033 to version 8.1.1 from -+ * 3GPP TSG-SA WG3 Meeting #53 in September 2008: -+ * -+ * CK' || IK' = HMAC-SHA-256(Key, S) -+ * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln -+ * Key = CK || IK -+ * FC = 0x20 -+ * P0 = access network identity (3GPP TS 24.302) -+ * L0 = length of acceess network identity (2 octets, big endian) -+ * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0 -+ * L1 = 0x00 0x06 -+ */ -+ -+ fc = 0x20; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)"); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN); -+ wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity", -+ network_name, network_name_len); -+ wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6); -+ -+ os_memcpy(key, ck, EAP_AKA_CK_LEN); -+ os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK", -+ key, sizeof(key)); -+ -+ addr[0] = &fc; -+ len[0] = 1; -+ addr[1] = network_name; -+ len[1] = network_name_len; -+ WPA_PUT_BE16(l0, network_name_len); -+ addr[2] = l0; -+ len[2] = 2; -+ addr[3] = sqn_ak; -+ len[3] = 6; -+ WPA_PUT_BE16(l1, 6); -+ addr[4] = l1; -+ len[4] = 2; -+ -+ hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')", -+ hash, sizeof(hash)); -+ -+ os_memcpy(ck, hash, EAP_AKA_CK_LEN); -+ os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN); -+} -+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ -+ -+ -+int eap_sim_parse_attr(const u8 *start, const u8 *end, -+ struct eap_sim_attrs *attr, int aka, int encr) -+{ -+ const u8 *pos = start, *apos; -+ size_t alen, plen, i, list_len; -+ -+ os_memset(attr, 0, sizeof(*attr)); -+ attr->id_req = NO_ID_REQ; -+ attr->notification = -1; -+ attr->counter = -1; -+ attr->selected_version = -1; -+ attr->client_error_code = -1; -+ -+ while (pos < end) { -+ if (pos + 2 > end) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow(1)"); -+ return -1; -+ } -+ wpa_printf(MSG_MSGDUMP, "EAP-SIM: Attribute: Type=%d Len=%d", -+ pos[0], pos[1] * 4); -+ if (pos + pos[1] * 4 > end) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Attribute overflow " -+ "(pos=%p len=%d end=%p)", -+ pos, pos[1] * 4, end); -+ return -1; -+ } -+ if (pos[1] == 0) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Attribute underflow"); -+ return -1; -+ } -+ apos = pos + 2; -+ alen = pos[1] * 4 - 2; -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Attribute data", -+ apos, alen); -+ -+ switch (pos[0]) { -+ case EAP_SIM_AT_RAND: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RAND"); -+ apos += 2; -+ alen -= 2; -+ if ((!aka && (alen % GSM_RAND_LEN)) || -+ (aka && alen != EAP_AKA_RAND_LEN)) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND" -+ " (len %lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->rand = apos; -+ attr->num_chal = alen / GSM_RAND_LEN; -+ break; -+ case EAP_SIM_AT_AUTN: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTN"); -+ if (!aka) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: " -+ "Unexpected AT_AUTN"); -+ return -1; -+ } -+ apos += 2; -+ alen -= 2; -+ if (alen != EAP_AKA_AUTN_LEN) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN" -+ " (len %lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->autn = apos; -+ break; -+ case EAP_SIM_AT_PADDING: -+ if (!encr) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " -+ "AT_PADDING"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_PADDING"); -+ for (i = 2; i < alen; i++) { -+ if (apos[i] != 0) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) " -+ "AT_PADDING used a non-zero" -+ " padding byte"); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: " -+ "(encr) padding bytes", -+ apos + 2, alen - 2); -+ return -1; -+ } -+ } -+ break; -+ case EAP_SIM_AT_NONCE_MT: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NONCE_MT"); -+ if (alen != 2 + EAP_SIM_NONCE_MT_LEN) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid " -+ "AT_NONCE_MT length"); -+ return -1; -+ } -+ attr->nonce_mt = apos + 2; -+ break; -+ case EAP_SIM_AT_PERMANENT_ID_REQ: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_PERMANENT_ID_REQ"); -+ attr->id_req = PERMANENT_ID; -+ break; -+ case EAP_SIM_AT_MAC: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_MAC"); -+ if (alen != 2 + EAP_SIM_MAC_LEN) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_MAC " -+ "length"); -+ return -1; -+ } -+ attr->mac = apos + 2; -+ break; -+ case EAP_SIM_AT_NOTIFICATION: -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid " -+ "AT_NOTIFICATION length %lu", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->notification = apos[0] * 256 + apos[1]; -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_NOTIFICATION %d", -+ attr->notification); -+ break; -+ case EAP_SIM_AT_ANY_ID_REQ: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ANY_ID_REQ"); -+ attr->id_req = ANY_ID; -+ break; -+ case EAP_SIM_AT_IDENTITY: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY"); -+ plen = WPA_GET_BE16(apos); -+ apos += 2; -+ alen -= 2; -+ if (plen > alen) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid " -+ "AT_IDENTITY (Actual Length %lu, " -+ "remaining length %lu)", -+ (unsigned long) plen, -+ (unsigned long) alen); -+ return -1; -+ } -+ -+ attr->identity = apos; -+ attr->identity_len = plen; -+ break; -+ case EAP_SIM_AT_VERSION_LIST: -+ if (aka) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: " -+ "Unexpected AT_VERSION_LIST"); -+ return -1; -+ } -+ list_len = apos[0] * 256 + apos[1]; -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST"); -+ if (list_len < 2 || list_len > alen - 2) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Invalid " -+ "AT_VERSION_LIST (list_len=%lu " -+ "attr_len=%lu)", -+ (unsigned long) list_len, -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->version_list = apos + 2; -+ attr->version_list_len = list_len; -+ break; -+ case EAP_SIM_AT_SELECTED_VERSION: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION"); -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid " -+ "AT_SELECTED_VERSION length %lu", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->selected_version = apos[0] * 256 + apos[1]; -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_SELECTED_VERSION " -+ "%d", attr->selected_version); -+ break; -+ case EAP_SIM_AT_FULLAUTH_ID_REQ: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_FULLAUTH_ID_REQ"); -+ attr->id_req = FULLAUTH_ID; -+ break; -+ case EAP_SIM_AT_COUNTER: -+ if (!encr) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " -+ "AT_COUNTER"); -+ return -1; -+ } -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " -+ "AT_COUNTER (alen=%lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->counter = apos[0] * 256 + apos[1]; -+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d", -+ attr->counter); -+ break; -+ case EAP_SIM_AT_COUNTER_TOO_SMALL: -+ if (!encr) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " -+ "AT_COUNTER_TOO_SMALL"); -+ return -1; -+ } -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " -+ "AT_COUNTER_TOO_SMALL (alen=%lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " -+ "AT_COUNTER_TOO_SMALL"); -+ attr->counter_too_small = 1; -+ break; -+ case EAP_SIM_AT_NONCE_S: -+ if (!encr) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " -+ "AT_NONCE_S"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " -+ "AT_NONCE_S"); -+ if (alen != 2 + EAP_SIM_NONCE_S_LEN) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid " -+ "AT_NONCE_S (alen=%lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->nonce_s = apos + 2; -+ break; -+ case EAP_SIM_AT_CLIENT_ERROR_CODE: -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid " -+ "AT_CLIENT_ERROR_CODE length %lu", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->client_error_code = apos[0] * 256 + apos[1]; -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_CLIENT_ERROR_CODE " -+ "%d", attr->client_error_code); -+ break; -+ case EAP_SIM_AT_IV: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IV"); -+ if (alen != 2 + EAP_SIM_MAC_LEN) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_IV " -+ "length %lu", (unsigned long) alen); -+ return -1; -+ } -+ attr->iv = apos + 2; -+ break; -+ case EAP_SIM_AT_ENCR_DATA: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_ENCR_DATA"); -+ attr->encr_data = apos + 2; -+ attr->encr_data_len = alen - 2; -+ if (attr->encr_data_len % 16) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid " -+ "AT_ENCR_DATA length %lu", -+ (unsigned long) -+ attr->encr_data_len); -+ return -1; -+ } -+ break; -+ case EAP_SIM_AT_NEXT_PSEUDONYM: -+ if (!encr) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " -+ "AT_NEXT_PSEUDONYM"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " -+ "AT_NEXT_PSEUDONYM"); -+ plen = apos[0] * 256 + apos[1]; -+ if (plen > alen - 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid" -+ " AT_NEXT_PSEUDONYM (actual" -+ " len %lu, attr len %lu)", -+ (unsigned long) plen, -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->next_pseudonym = pos + 4; -+ attr->next_pseudonym_len = plen; -+ break; -+ case EAP_SIM_AT_NEXT_REAUTH_ID: -+ if (!encr) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted " -+ "AT_NEXT_REAUTH_ID"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) " -+ "AT_NEXT_REAUTH_ID"); -+ plen = apos[0] * 256 + apos[1]; -+ if (plen > alen - 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid" -+ " AT_NEXT_REAUTH_ID (actual" -+ " len %lu, attr len %lu)", -+ (unsigned long) plen, -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->next_reauth_id = pos + 4; -+ attr->next_reauth_id_len = plen; -+ break; -+ case EAP_SIM_AT_RES: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES"); -+ attr->res_len_bits = WPA_GET_BE16(apos); -+ apos += 2; -+ alen -= 2; -+ if (!aka || alen < EAP_AKA_MIN_RES_LEN || -+ alen > EAP_AKA_MAX_RES_LEN) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES " -+ "(len %lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->res = apos; -+ attr->res_len = alen; -+ break; -+ case EAP_SIM_AT_AUTS: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS"); -+ if (!aka) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: " -+ "Unexpected AT_AUTS"); -+ return -1; -+ } -+ if (alen != EAP_AKA_AUTS_LEN) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS" -+ " (len %lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->auts = apos; -+ break; -+ case EAP_SIM_AT_CHECKCODE: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_CHECKCODE"); -+ if (!aka) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: " -+ "Unexpected AT_CHECKCODE"); -+ return -1; -+ } -+ apos += 2; -+ alen -= 2; -+ if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN && -+ alen != EAP_AKA_PRIME_CHECKCODE_LEN) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid " -+ "AT_CHECKCODE (len %lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->checkcode = apos; -+ attr->checkcode_len = alen; -+ break; -+ case EAP_SIM_AT_RESULT_IND: -+ if (encr) { -+ wpa_printf(MSG_ERROR, "EAP-SIM: Encrypted " -+ "AT_RESULT_IND"); -+ return -1; -+ } -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid " -+ "AT_RESULT_IND (alen=%lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND"); -+ attr->result_ind = 1; -+ break; -+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) -+ case EAP_SIM_AT_KDF_INPUT: -+ if (aka != 2) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected " -+ "AT_KDF_INPUT"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT"); -+ plen = WPA_GET_BE16(apos); -+ apos += 2; -+ alen -= 2; -+ if (plen > alen) { -+ wpa_printf(MSG_INFO, "EAP-AKA': Invalid " -+ "AT_KDF_INPUT (Actual Length %lu, " -+ "remaining length %lu)", -+ (unsigned long) plen, -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->kdf_input = apos; -+ attr->kdf_input_len = plen; -+ break; -+ case EAP_SIM_AT_KDF: -+ if (aka != 2) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected " -+ "AT_KDF"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF"); -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-AKA': Invalid " -+ "AT_KDF (len %lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA': Too many " -+ "AT_KDF attributes - ignore this"); -+ continue; -+ } -+ attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos); -+ attr->kdf_count++; -+ break; -+ case EAP_SIM_AT_BIDDING: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING"); -+ if (alen != 2) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid " -+ "AT_BIDDING (len %lu)", -+ (unsigned long) alen); -+ return -1; -+ } -+ attr->bidding = apos; -+ break; -+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ -+ default: -+ if (pos[0] < 128) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized " -+ "non-skippable attribute %d", -+ pos[0]); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized skippable" -+ " attribute %d ignored", pos[0]); -+ break; -+ } -+ -+ pos += pos[1] * 4; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Attributes parsed successfully " -+ "(aka=%d encr=%d)", aka, encr); -+ -+ return 0; -+} -+ -+ -+u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, -+ size_t encr_data_len, const u8 *iv, -+ struct eap_sim_attrs *attr, int aka) -+{ -+ u8 *decrypted; -+ -+ if (!iv) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV"); -+ return NULL; -+ } -+ -+ decrypted = os_malloc(encr_data_len); -+ if (decrypted == NULL) -+ return NULL; -+ os_memcpy(decrypted, encr_data, encr_data_len); -+ -+ if (aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len)) { -+ os_free(decrypted); -+ return NULL; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA", -+ decrypted, encr_data_len); -+ -+ if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr, -+ aka, 1)) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse " -+ "decrypted AT_ENCR_DATA"); -+ os_free(decrypted); -+ return NULL; -+ } -+ -+ return decrypted; -+} -+ -+ -+#define EAP_SIM_INIT_LEN 128 -+ -+struct eap_sim_msg { -+ struct wpabuf *buf; -+ size_t mac, iv, encr; /* index from buf */ -+ int type; -+}; -+ -+ -+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype) -+{ -+ struct eap_sim_msg *msg; -+ struct eap_hdr *eap; -+ u8 *pos; -+ -+ msg = os_zalloc(sizeof(*msg)); -+ if (msg == NULL) -+ return NULL; -+ -+ msg->type = type; -+ msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN); -+ if (msg->buf == NULL) { -+ os_free(msg); -+ return NULL; -+ } -+ eap = wpabuf_put(msg->buf, sizeof(*eap)); -+ eap->code = code; -+ eap->identifier = id; -+ -+ pos = wpabuf_put(msg->buf, 4); -+ *pos++ = type; -+ *pos++ = subtype; -+ *pos++ = 0; /* Reserved */ -+ *pos++ = 0; /* Reserved */ -+ -+ return msg; -+} -+ -+ -+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, -+ const u8 *extra, size_t extra_len) -+{ -+ struct eap_hdr *eap; -+ struct wpabuf *buf; -+ -+ if (msg == NULL) -+ return NULL; -+ -+ eap = wpabuf_mhead(msg->buf); -+ eap->length = host_to_be16(wpabuf_len(msg->buf)); -+ -+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) -+ if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) { -+ eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf), -+ wpabuf_len(msg->buf), -+ (u8 *) wpabuf_mhead(msg->buf) + -+ msg->mac, extra, extra_len); -+ } else -+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ -+ if (k_aut && msg->mac) { -+ eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf), -+ wpabuf_len(msg->buf), -+ (u8 *) wpabuf_mhead(msg->buf) + msg->mac, -+ extra, extra_len); -+ } -+ -+ buf = msg->buf; -+ os_free(msg); -+ return buf; -+} -+ -+ -+void eap_sim_msg_free(struct eap_sim_msg *msg) -+{ -+ if (msg) { -+ wpabuf_free(msg->buf); -+ os_free(msg); -+ } -+} -+ -+ -+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, -+ const u8 *data, size_t len) -+{ -+ int attr_len = 2 + len; -+ int pad_len; -+ u8 *start; -+ -+ if (msg == NULL) -+ return NULL; -+ -+ pad_len = (4 - attr_len % 4) % 4; -+ attr_len += pad_len; -+ if (wpabuf_resize(&msg->buf, attr_len)) -+ return NULL; -+ start = wpabuf_put(msg->buf, 0); -+ wpabuf_put_u8(msg->buf, attr); -+ wpabuf_put_u8(msg->buf, attr_len / 4); -+ wpabuf_put_data(msg->buf, data, len); -+ if (pad_len) -+ os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len); -+ return start; -+} -+ -+ -+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value, -+ const u8 *data, size_t len) -+{ -+ int attr_len = 4 + len; -+ int pad_len; -+ u8 *start; -+ -+ if (msg == NULL) -+ return NULL; -+ -+ pad_len = (4 - attr_len % 4) % 4; -+ attr_len += pad_len; -+ if (wpabuf_resize(&msg->buf, attr_len)) -+ return NULL; -+ start = wpabuf_put(msg->buf, 0); -+ wpabuf_put_u8(msg->buf, attr); -+ wpabuf_put_u8(msg->buf, attr_len / 4); -+ wpabuf_put_be16(msg->buf, value); -+ if (data) -+ wpabuf_put_data(msg->buf, data, len); -+ else -+ wpabuf_put(msg->buf, len); -+ if (pad_len) -+ os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len); -+ return start; -+} -+ -+ -+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr) -+{ -+ u8 *pos = eap_sim_msg_add(msg, attr, 0, NULL, EAP_SIM_MAC_LEN); -+ if (pos) -+ msg->mac = (pos - wpabuf_head_u8(msg->buf)) + 4; -+ return pos; -+} -+ -+ -+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, -+ u8 attr_encr) -+{ -+ u8 *pos = eap_sim_msg_add(msg, attr_iv, 0, NULL, EAP_SIM_IV_LEN); -+ if (pos == NULL) -+ return -1; -+ msg->iv = (pos - wpabuf_head_u8(msg->buf)) + 4; -+ if (random_get_bytes(wpabuf_mhead_u8(msg->buf) + msg->iv, -+ EAP_SIM_IV_LEN)) { -+ msg->iv = 0; -+ return -1; -+ } -+ -+ pos = eap_sim_msg_add(msg, attr_encr, 0, NULL, 0); -+ if (pos == NULL) { -+ msg->iv = 0; -+ return -1; -+ } -+ msg->encr = pos - wpabuf_head_u8(msg->buf); -+ -+ return 0; -+} -+ -+ -+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad) -+{ -+ size_t encr_len; -+ -+ if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0) -+ return -1; -+ -+ encr_len = wpabuf_len(msg->buf) - msg->encr - 4; -+ if (encr_len % 16) { -+ u8 *pos; -+ int pad_len = 16 - (encr_len % 16); -+ if (pad_len < 4) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: " -+ "eap_sim_msg_add_encr_end - invalid pad_len" -+ " %d", pad_len); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, " *AT_PADDING"); -+ pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4); -+ if (pos == NULL) -+ return -1; -+ os_memset(pos + 4, 0, pad_len - 4); -+ encr_len += pad_len; -+ } -+ wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)", -+ (unsigned long) encr_len); -+ wpabuf_mhead_u8(msg->buf)[msg->encr + 1] = encr_len / 4 + 1; -+ return aes_128_cbc_encrypt(k_encr, wpabuf_head_u8(msg->buf) + msg->iv, -+ wpabuf_mhead_u8(msg->buf) + msg->encr + 4, -+ encr_len); -+} -+ -+ -+void eap_sim_report_notification(void *msg_ctx, int notification, int aka) -+{ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+ const char *type = aka ? "AKA" : "SIM"; -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ switch (notification) { -+ case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH: -+ wpa_printf(MSG_WARNING, "EAP-%s: General failure " -+ "notification (after authentication)", type); -+ break; -+ case EAP_SIM_TEMPORARILY_DENIED: -+ wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: " -+ "User has been temporarily denied access to the " -+ "requested service", type); -+ break; -+ case EAP_SIM_NOT_SUBSCRIBED: -+ wpa_printf(MSG_WARNING, "EAP-%s: Failure notification: " -+ "User has not subscribed to the requested service", -+ type); -+ break; -+ case EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH: -+ wpa_printf(MSG_WARNING, "EAP-%s: General failure " -+ "notification (before authentication)", type); -+ break; -+ case EAP_SIM_SUCCESS: -+ wpa_printf(MSG_INFO, "EAP-%s: Successful authentication " -+ "notification", type); -+ break; -+ default: -+ if (notification >= 32768) { -+ wpa_printf(MSG_INFO, "EAP-%s: Unrecognized " -+ "non-failure notification %d", -+ type, notification); -+ } else { -+ wpa_printf(MSG_WARNING, "EAP-%s: Unrecognized " -+ "failure notification %d", -+ type, notification); -+ } -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.h -new file mode 100644 -index 0000000000000..48c8eaac0a097 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_sim_common.h -@@ -0,0 +1,235 @@ -+/* -+ * EAP peer/server: EAP-SIM/AKA/AKA' shared routines -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_SIM_COMMON_H -+#define EAP_SIM_COMMON_H -+ -+#define EAP_SIM_NONCE_S_LEN 16 -+#define EAP_SIM_NONCE_MT_LEN 16 -+#define EAP_SIM_MAC_LEN 16 -+#define EAP_SIM_MK_LEN 20 -+#define EAP_SIM_K_AUT_LEN 16 -+#define EAP_SIM_K_ENCR_LEN 16 -+#define EAP_SIM_KEYING_DATA_LEN 64 -+#define EAP_SIM_IV_LEN 16 -+#define EAP_SIM_KC_LEN 8 -+#define EAP_SIM_SRES_LEN 4 -+ -+#define GSM_RAND_LEN 16 -+ -+#define EAP_SIM_VERSION 1 -+ -+/* EAP-SIM Subtypes */ -+#define EAP_SIM_SUBTYPE_START 10 -+#define EAP_SIM_SUBTYPE_CHALLENGE 11 -+#define EAP_SIM_SUBTYPE_NOTIFICATION 12 -+#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13 -+#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14 -+ -+/* AT_CLIENT_ERROR_CODE error codes */ -+#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0 -+#define EAP_SIM_UNSUPPORTED_VERSION 1 -+#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2 -+#define EAP_SIM_RAND_NOT_FRESH 3 -+ -+#define EAP_SIM_MAX_FAST_REAUTHS 1000 -+ -+#define EAP_SIM_MAX_CHAL 3 -+ -+ -+/* EAP-AKA Subtypes */ -+#define EAP_AKA_SUBTYPE_CHALLENGE 1 -+#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2 -+#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4 -+#define EAP_AKA_SUBTYPE_IDENTITY 5 -+#define EAP_AKA_SUBTYPE_NOTIFICATION 12 -+#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13 -+#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14 -+ -+/* AT_CLIENT_ERROR_CODE error codes */ -+#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0 -+ -+#define EAP_AKA_RAND_LEN 16 -+#define EAP_AKA_AUTN_LEN 16 -+#define EAP_AKA_AUTS_LEN 14 -+#define EAP_AKA_RES_MAX_LEN 16 -+#define EAP_AKA_IK_LEN 16 -+#define EAP_AKA_CK_LEN 16 -+#define EAP_AKA_MAX_FAST_REAUTHS 1000 -+#define EAP_AKA_MIN_RES_LEN 4 -+#define EAP_AKA_MAX_RES_LEN 16 -+#define EAP_AKA_CHECKCODE_LEN 20 -+ -+#define EAP_AKA_PRIME_K_AUT_LEN 32 -+#define EAP_AKA_PRIME_CHECKCODE_LEN 32 -+#define EAP_AKA_PRIME_K_RE_LEN 32 -+ -+struct wpabuf; -+ -+void eap_sim_derive_mk(const u8 *identity, size_t identity_len, -+ const u8 *nonce_mt, u16 selected_version, -+ const u8 *ver_list, size_t ver_list_len, -+ int num_chal, const u8 *kc, u8 *mk); -+void eap_aka_derive_mk(const u8 *identity, size_t identity_len, -+ const u8 *ik, const u8 *ck, u8 *mk); -+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, -+ u8 *emsk); -+int eap_sim_derive_keys_reauth(u16 _counter, -+ const u8 *identity, size_t identity_len, -+ const u8 *nonce_s, const u8 *mk, u8 *msk, -+ u8 *emsk); -+int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, -+ const u8 *mac, const u8 *extra, size_t extra_len); -+void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, -+ const u8 *extra, size_t extra_len); -+ -+#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) -+void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, -+ const u8 *ik, const u8 *ck, u8 *k_encr, -+ u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk); -+int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, -+ const u8 *identity, size_t identity_len, -+ const u8 *nonce_s, u8 *msk, u8 *emsk); -+int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, -+ const u8 *mac, const u8 *extra, -+ size_t extra_len); -+void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, -+ u8 *mac, const u8 *extra, size_t extra_len); -+ -+void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, -+ const u8 *network_name, -+ size_t network_name_len); -+#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ -+static inline void eap_aka_prime_derive_keys(const u8 *identity, -+ size_t identity_len, -+ const u8 *ik, const u8 *ck, -+ u8 *k_encr, u8 *k_aut, u8 *k_re, -+ u8 *msk, u8 *emsk) -+{ -+} -+ -+static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, -+ const u8 *identity, -+ size_t identity_len, -+ const u8 *nonce_s, u8 *msk, -+ u8 *emsk) -+{ -+ return -1; -+} -+ -+static inline int eap_sim_verify_mac_sha256(const u8 *k_aut, -+ const struct wpabuf *req, -+ const u8 *mac, const u8 *extra, -+ size_t extra_len) -+{ -+ return -1; -+} -+#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ -+ -+ -+/* EAP-SIM/AKA Attributes (0..127 non-skippable) */ -+#define EAP_SIM_AT_RAND 1 -+#define EAP_SIM_AT_AUTN 2 /* only AKA */ -+#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */ -+#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */ -+#define EAP_SIM_AT_PADDING 6 /* only encrypted */ -+#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */ -+#define EAP_SIM_AT_PERMANENT_ID_REQ 10 -+#define EAP_SIM_AT_MAC 11 -+#define EAP_SIM_AT_NOTIFICATION 12 -+#define EAP_SIM_AT_ANY_ID_REQ 13 -+#define EAP_SIM_AT_IDENTITY 14 /* only send */ -+#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */ -+#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */ -+#define EAP_SIM_AT_FULLAUTH_ID_REQ 17 -+#define EAP_SIM_AT_COUNTER 19 /* only encrypted */ -+#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */ -+#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */ -+#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */ -+#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */ -+#define EAP_SIM_AT_KDF 24 /* only AKA' */ -+#define EAP_SIM_AT_IV 129 -+#define EAP_SIM_AT_ENCR_DATA 130 -+#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */ -+#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */ -+#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */ -+#define EAP_SIM_AT_RESULT_IND 135 -+#define EAP_SIM_AT_BIDDING 136 -+ -+/* AT_NOTIFICATION notification code values */ -+#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0 -+#define EAP_SIM_TEMPORARILY_DENIED 1026 -+#define EAP_SIM_NOT_SUBSCRIBED 1031 -+#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384 -+#define EAP_SIM_SUCCESS 32768 -+ -+/* EAP-AKA' AT_KDF Key Derivation Function values */ -+#define EAP_AKA_PRIME_KDF 1 -+ -+/* AT_BIDDING flags */ -+#define EAP_AKA_BIDDING_FLAG_D 0x8000 -+ -+ -+enum eap_sim_id_req { -+ NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID -+}; -+ -+ -+struct eap_sim_attrs { -+ const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s; -+ const u8 *next_pseudonym, *next_reauth_id; -+ const u8 *nonce_mt, *identity, *res, *auts; -+ const u8 *checkcode; -+ const u8 *kdf_input; -+ const u8 *bidding; -+ size_t num_chal, version_list_len, encr_data_len; -+ size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len; -+ size_t res_len_bits; -+ size_t checkcode_len; -+ size_t kdf_input_len; -+ enum eap_sim_id_req id_req; -+ int notification, counter, selected_version, client_error_code; -+ int counter_too_small; -+ int result_ind; -+#define EAP_AKA_PRIME_KDF_MAX 10 -+ u16 kdf[EAP_AKA_PRIME_KDF_MAX]; -+ size_t kdf_count; -+}; -+ -+int eap_sim_parse_attr(const u8 *start, const u8 *end, -+ struct eap_sim_attrs *attr, int aka, int encr); -+u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, -+ size_t encr_data_len, const u8 *iv, -+ struct eap_sim_attrs *attr, int aka); -+ -+ -+struct eap_sim_msg; -+ -+struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype); -+struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, -+ const u8 *extra, size_t extra_len); -+void eap_sim_msg_free(struct eap_sim_msg *msg); -+u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, -+ const u8 *data, size_t len); -+u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, -+ u16 value, const u8 *data, size_t len); -+u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr); -+int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, -+ u8 attr_encr); -+int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, -+ int attr_pad); -+ -+void eap_sim_report_notification(void *msg_ctx, int notification, int aka); -+ -+#endif /* EAP_SIM_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_tlv_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_tlv_common.h -new file mode 100644 -index 0000000000000..f86015d1795a7 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_tlv_common.h -@@ -0,0 +1,118 @@ -+/* -+ * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_TLV_COMMON_H -+#define EAP_TLV_COMMON_H -+ -+/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */ -+#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */ -+#define EAP_TLV_NAK_TLV 4 -+#define EAP_TLV_ERROR_CODE_TLV 5 -+#define EAP_TLV_CONNECTION_BINDING_TLV 6 -+#define EAP_TLV_VENDOR_SPECIFIC_TLV 7 -+#define EAP_TLV_URI_TLV 8 -+#define EAP_TLV_EAP_PAYLOAD_TLV 9 -+#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10 -+#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */ -+#define EAP_TLV_CRYPTO_BINDING_TLV 12 -+#define EAP_TLV_CALLING_STATION_ID_TLV 13 -+#define EAP_TLV_CALLED_STATION_ID_TLV 14 -+#define EAP_TLV_NAS_PORT_TYPE_TLV 15 -+#define EAP_TLV_SERVER_IDENTIFIER_TLV 16 -+#define EAP_TLV_IDENTITY_TYPE_TLV 17 -+#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18 -+#define EAP_TLV_REQUEST_ACTION_TLV 19 -+#define EAP_TLV_PKCS7_TLV 20 -+ -+#define EAP_TLV_RESULT_SUCCESS 1 -+#define EAP_TLV_RESULT_FAILURE 2 -+ -+#define EAP_TLV_TYPE_MANDATORY 0x8000 -+#define EAP_TLV_TYPE_MASK 0x3fff -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct eap_tlv_hdr { -+ be16 tlv_type; -+ be16 length; -+} STRUCT_PACKED; -+ -+struct eap_tlv_nak_tlv { -+ be16 tlv_type; -+ be16 length; -+ be32 vendor_id; -+ be16 nak_type; -+} STRUCT_PACKED; -+ -+struct eap_tlv_result_tlv { -+ be16 tlv_type; -+ be16 length; -+ be16 status; -+} STRUCT_PACKED; -+ -+/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */ -+struct eap_tlv_intermediate_result_tlv { -+ be16 tlv_type; -+ be16 length; -+ be16 status; -+ /* Followed by optional TLVs */ -+} STRUCT_PACKED; -+ -+/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */ -+struct eap_tlv_crypto_binding_tlv { -+ be16 tlv_type; -+ be16 length; -+ u8 reserved; -+ u8 version; -+ u8 received_version; -+ u8 subtype; -+ u8 nonce[32]; -+ u8 compound_mac[20]; -+} STRUCT_PACKED; -+ -+struct eap_tlv_pac_ack_tlv { -+ be16 tlv_type; -+ be16 length; -+ be16 pac_type; -+ be16 pac_len; -+ be16 result; -+} STRUCT_PACKED; -+ -+/* RFC 4851, Section 4.2.9 - Request-Action TLV */ -+struct eap_tlv_request_action_tlv { -+ be16 tlv_type; -+ be16 length; -+ be16 action; -+} STRUCT_PACKED; -+ -+/* RFC 5422, Section 4.2.6 - PAC-Type TLV */ -+struct eap_tlv_pac_type_tlv { -+ be16 tlv_type; /* PAC_TYPE_PAC_TYPE */ -+ be16 length; -+ be16 pac_type; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0 -+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1 -+ -+#define EAP_TLV_ACTION_PROCESS_TLV 1 -+#define EAP_TLV_ACTION_NEGOTIATE_EAP 2 -+ -+#endif /* EAP_TLV_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ttls.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ttls.h -new file mode 100644 -index 0000000000000..797d084786f3d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_ttls.h -@@ -0,0 +1,71 @@ -+/* -+ * EAP server/peer: EAP-TTLS (RFC 5281) -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_TTLS_H -+#define EAP_TTLS_H -+ -+struct ttls_avp { -+ be32 avp_code; -+ be32 avp_length; /* 8-bit flags, 24-bit length; -+ * length includes AVP header */ -+ /* optional 32-bit Vendor-ID */ -+ /* Data */ -+}; -+ -+struct ttls_avp_vendor { -+ be32 avp_code; -+ be32 avp_length; /* 8-bit flags, 24-bit length; -+ * length includes AVP header */ -+ be32 vendor_id; -+ /* Data */ -+}; -+ -+#define AVP_FLAGS_VENDOR 0x80 -+#define AVP_FLAGS_MANDATORY 0x40 -+ -+#define AVP_PAD(start, pos) \ -+do { \ -+ int __pad; \ -+ __pad = (4 - (((pos) - (start)) & 3)) & 3; \ -+ os_memset((pos), 0, __pad); \ -+ pos += __pad; \ -+} while (0) -+ -+ -+/* RFC 2865 */ -+#define RADIUS_ATTR_USER_NAME 1 -+#define RADIUS_ATTR_USER_PASSWORD 2 -+#define RADIUS_ATTR_CHAP_PASSWORD 3 -+#define RADIUS_ATTR_REPLY_MESSAGE 18 -+#define RADIUS_ATTR_CHAP_CHALLENGE 60 -+#define RADIUS_ATTR_EAP_MESSAGE 79 -+ -+/* RFC 2548 */ -+#define RADIUS_VENDOR_ID_MICROSOFT 311 -+#define RADIUS_ATTR_MS_CHAP_RESPONSE 1 -+#define RADIUS_ATTR_MS_CHAP_ERROR 2 -+#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6 -+#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11 -+#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25 -+#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26 -+#define RADIUS_ATTR_MS_CHAP2_CPW 27 -+ -+#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16 -+#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50 -+#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8 -+#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50 -+#define EAP_TTLS_CHAP_CHALLENGE_LEN 16 -+#define EAP_TTLS_CHAP_PASSWORD_LEN 16 -+ -+#endif /* EAP_TTLS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.c -new file mode 100644 -index 0000000000000..5d4e8cc1140cf ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.c -@@ -0,0 +1,39 @@ -+/* -+ * EAP-WSC common routines for Wi-Fi Protected Setup -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_defs.h" -+#include "eap_common.h" -+#include "wps/wps.h" -+#include "eap_wsc_common.h" -+ -+struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code) -+{ -+ struct wpabuf *msg; -+ -+ msg = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, code, id); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " -+ "FRAG_ACK"); -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/FRAG_ACK"); -+ wpabuf_put_u8(msg, WSC_FRAG_ACK); /* Op-Code */ -+ wpabuf_put_u8(msg, 0); /* Flags */ -+ -+ return msg; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.h -new file mode 100644 -index 0000000000000..fdf61d317de60 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/eap_wsc_common.h -@@ -0,0 +1,33 @@ -+/* -+ * EAP-WSC definitions for Wi-Fi Protected Setup -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_WSC_COMMON_H -+#define EAP_WSC_COMMON_H -+ -+#define EAP_VENDOR_TYPE_WSC 1 -+ -+#define WSC_FLAGS_MF 0x01 -+#define WSC_FLAGS_LF 0x02 -+ -+#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0" -+#define WSC_ID_REGISTRAR_LEN 30 -+#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0" -+#define WSC_ID_ENROLLEE_LEN 29 -+ -+#define WSC_FRAGMENT_SIZE 1400 -+ -+ -+struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code); -+ -+#endif /* EAP_WSC_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.c -new file mode 100644 -index 0000000000000..003c288dfac74 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.c -@@ -0,0 +1,797 @@ -+/* -+ * IKEv2 common routines for initiator and responder -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/crypto.h" -+#include "crypto/md5.h" -+#include "crypto/sha1.h" -+#include "crypto/random.h" -+#include "ikev2_common.h" -+ -+ -+static struct ikev2_integ_alg ikev2_integ_algs[] = { -+ { AUTH_HMAC_SHA1_96, 20, 12 }, -+ { AUTH_HMAC_MD5_96, 16, 12 } -+}; -+ -+#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0])) -+ -+ -+static struct ikev2_prf_alg ikev2_prf_algs[] = { -+ { PRF_HMAC_SHA1, 20, 20 }, -+ { PRF_HMAC_MD5, 16, 16 } -+}; -+ -+#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0])) -+ -+ -+static struct ikev2_encr_alg ikev2_encr_algs[] = { -+ { ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */ -+ { ENCR_3DES, 24, 8 } -+}; -+ -+#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0])) -+ -+ -+const struct ikev2_integ_alg * ikev2_get_integ(int id) -+{ -+ size_t i; -+ -+ for (i = 0; i < NUM_INTEG_ALGS; i++) { -+ if (ikev2_integ_algs[i].id == id) -+ return &ikev2_integ_algs[i]; -+ } -+ -+ return NULL; -+} -+ -+ -+int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, -+ size_t data_len, u8 *hash) -+{ -+ u8 tmphash[IKEV2_MAX_HASH_LEN]; -+ -+ switch (alg) { -+ case AUTH_HMAC_SHA1_96: -+ if (key_len != 20) -+ return -1; -+ hmac_sha1(key, key_len, data, data_len, tmphash); -+ os_memcpy(hash, tmphash, 12); -+ break; -+ case AUTH_HMAC_MD5_96: -+ if (key_len != 16) -+ return -1; -+ hmac_md5(key, key_len, data, data_len, tmphash); -+ os_memcpy(hash, tmphash, 12); -+ break; -+ default: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+const struct ikev2_prf_alg * ikev2_get_prf(int id) -+{ -+ size_t i; -+ -+ for (i = 0; i < NUM_PRF_ALGS; i++) { -+ if (ikev2_prf_algs[i].id == id) -+ return &ikev2_prf_algs[i]; -+ } -+ -+ return NULL; -+} -+ -+ -+int ikev2_prf_hash(int alg, const u8 *key, size_t key_len, -+ size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *hash) -+{ -+ switch (alg) { -+ case PRF_HMAC_SHA1: -+ hmac_sha1_vector(key, key_len, num_elem, addr, len, hash); -+ break; -+ case PRF_HMAC_MD5: -+ hmac_md5_vector(key, key_len, num_elem, addr, len, hash); -+ break; -+ default: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int ikev2_prf_plus(int alg, const u8 *key, size_t key_len, -+ const u8 *data, size_t data_len, -+ u8 *out, size_t out_len) -+{ -+ u8 hash[IKEV2_MAX_HASH_LEN]; -+ size_t hash_len; -+ u8 iter, *pos, *end; -+ const u8 *addr[3]; -+ size_t len[3]; -+ const struct ikev2_prf_alg *prf; -+ int res; -+ -+ prf = ikev2_get_prf(alg); -+ if (prf == NULL) -+ return -1; -+ hash_len = prf->hash_len; -+ -+ addr[0] = hash; -+ len[0] = hash_len; -+ addr[1] = data; -+ len[1] = data_len; -+ addr[2] = &iter; -+ len[2] = 1; -+ -+ pos = out; -+ end = out + out_len; -+ iter = 1; -+ while (pos < end) { -+ size_t clen; -+ if (iter == 1) -+ res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1], -+ &len[1], hash); -+ else -+ res = ikev2_prf_hash(alg, key, key_len, 3, addr, len, -+ hash); -+ if (res < 0) -+ return -1; -+ clen = hash_len; -+ if ((int) clen > end - pos) -+ clen = end - pos; -+ os_memcpy(pos, hash, clen); -+ pos += clen; -+ iter++; -+ } -+ -+ return 0; -+} -+ -+ -+const struct ikev2_encr_alg * ikev2_get_encr(int id) -+{ -+ size_t i; -+ -+ for (i = 0; i < NUM_ENCR_ALGS; i++) { -+ if (ikev2_encr_algs[i].id == id) -+ return &ikev2_encr_algs[i]; -+ } -+ -+ return NULL; -+} -+ -+ -+#ifdef CCNS_PL -+/* from des.c */ -+struct des3_key_s { -+ u32 ek[3][32]; -+ u32 dk[3][32]; -+}; -+ -+void des3_key_setup(const u8 *key, struct des3_key_s *dkey); -+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); -+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); -+#endif /* CCNS_PL */ -+ -+ -+int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, -+ const u8 *plain, u8 *crypt, size_t len) -+{ -+ struct crypto_cipher *cipher; -+ int encr_alg; -+ -+#ifdef CCNS_PL -+ if (alg == ENCR_3DES) { -+ struct des3_key_s des3key; -+ size_t i, blocks; -+ u8 *pos; -+ -+ /* ECB mode is used incorrectly for 3DES!? */ -+ if (key_len != 24) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); -+ return -1; -+ } -+ des3_key_setup(key, &des3key); -+ -+ blocks = len / 8; -+ pos = crypt; -+ for (i = 0; i < blocks; i++) { -+ des3_encrypt(pos, &des3key, pos); -+ pos += 8; -+ } -+ } else { -+#endif /* CCNS_PL */ -+ switch (alg) { -+ case ENCR_3DES: -+ encr_alg = CRYPTO_CIPHER_ALG_3DES; -+ break; -+ case ENCR_AES_CBC: -+ encr_alg = CRYPTO_CIPHER_ALG_AES; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); -+ return -1; -+ } -+ -+ cipher = crypto_cipher_init(encr_alg, iv, key, key_len); -+ if (cipher == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); -+ return -1; -+ } -+ -+ if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Encryption failed"); -+ crypto_cipher_deinit(cipher); -+ return -1; -+ } -+ crypto_cipher_deinit(cipher); -+#ifdef CCNS_PL -+ } -+#endif /* CCNS_PL */ -+ -+ return 0; -+} -+ -+ -+int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, -+ const u8 *crypt, u8 *plain, size_t len) -+{ -+ struct crypto_cipher *cipher; -+ int encr_alg; -+ -+#ifdef CCNS_PL -+ if (alg == ENCR_3DES) { -+ struct des3_key_s des3key; -+ size_t i, blocks; -+ -+ /* ECB mode is used incorrectly for 3DES!? */ -+ if (key_len != 24) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); -+ return -1; -+ } -+ des3_key_setup(key, &des3key); -+ -+ if (len % 8) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted " -+ "length"); -+ return -1; -+ } -+ blocks = len / 8; -+ for (i = 0; i < blocks; i++) { -+ des3_decrypt(crypt, &des3key, plain); -+ plain += 8; -+ crypt += 8; -+ } -+ } else { -+#endif /* CCNS_PL */ -+ switch (alg) { -+ case ENCR_3DES: -+ encr_alg = CRYPTO_CIPHER_ALG_3DES; -+ break; -+ case ENCR_AES_CBC: -+ encr_alg = CRYPTO_CIPHER_ALG_AES; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); -+ return -1; -+ } -+ -+ cipher = crypto_cipher_init(encr_alg, iv, key, key_len); -+ if (cipher == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); -+ return -1; -+ } -+ -+ if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); -+ crypto_cipher_deinit(cipher); -+ return -1; -+ } -+ crypto_cipher_deinit(cipher); -+#ifdef CCNS_PL -+ } -+#endif /* CCNS_PL */ -+ -+ return 0; -+} -+ -+ -+int ikev2_parse_payloads(struct ikev2_payloads *payloads, -+ u8 next_payload, const u8 *pos, const u8 *end) -+{ -+ const struct ikev2_payload_hdr *phdr; -+ -+ os_memset(payloads, 0, sizeof(*payloads)); -+ -+ while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) { -+ int plen, pdatalen; -+ const u8 *pdata; -+ wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u", -+ next_payload); -+ if (end - pos < (int) sizeof(*phdr)) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short message for " -+ "payload header (left=%ld)", -+ (long) (end - pos)); -+ } -+ phdr = (const struct ikev2_payload_hdr *) pos; -+ plen = WPA_GET_BE16(phdr->payload_length); -+ if (plen < (int) sizeof(*phdr) || pos + plen > end) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid payload header " -+ "length %d", plen); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x" -+ " Payload Length: %d", -+ phdr->next_payload, phdr->flags, plen); -+ -+ pdata = (const u8 *) (phdr + 1); -+ pdatalen = plen - sizeof(*phdr); -+ -+ switch (next_payload) { -+ case IKEV2_PAYLOAD_SA: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: Security " -+ "Association"); -+ payloads->sa = pdata; -+ payloads->sa_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_KEY_EXCHANGE: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: Key " -+ "Exchange"); -+ payloads->ke = pdata; -+ payloads->ke_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_IDi: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDi"); -+ payloads->idi = pdata; -+ payloads->idi_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_IDr: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDr"); -+ payloads->idr = pdata; -+ payloads->idr_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_CERTIFICATE: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: Certificate"); -+ payloads->cert = pdata; -+ payloads->cert_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_AUTHENTICATION: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: " -+ "Authentication"); -+ payloads->auth = pdata; -+ payloads->auth_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_NONCE: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: Nonce"); -+ payloads->nonce = pdata; -+ payloads->nonce_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_ENCRYPTED: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: Encrypted"); -+ payloads->encrypted = pdata; -+ payloads->encrypted_len = pdatalen; -+ break; -+ case IKEV2_PAYLOAD_NOTIFICATION: -+ wpa_printf(MSG_DEBUG, "IKEV2: Payload: " -+ "Notification"); -+ payloads->notification = pdata; -+ payloads->notification_len = pdatalen; -+ break; -+ default: -+ if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported " -+ "critical payload %u - reject the " -+ "entire message", next_payload); -+ return -1; -+ } else { -+ wpa_printf(MSG_DEBUG, "IKEV2: Skipped " -+ "unsupported payload %u", -+ next_payload); -+ } -+ } -+ -+ if (next_payload == IKEV2_PAYLOAD_ENCRYPTED && -+ pos + plen == end) { -+ /* -+ * Next Payload in the case of Encrypted Payload is -+ * actually the payload type for the first embedded -+ * payload. -+ */ -+ payloads->encr_next_payload = phdr->next_payload; -+ next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD; -+ } else -+ next_payload = phdr->next_payload; -+ -+ pos += plen; -+ } -+ -+ if (pos != end) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after " -+ "payloads"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg, -+ const u8 *ID, size_t ID_len, u8 ID_type, -+ struct ikev2_keys *keys, int initiator, -+ const u8 *shared_secret, size_t shared_secret_len, -+ const u8 *nonce, size_t nonce_len, -+ const u8 *key_pad, size_t key_pad_len, -+ u8 *auth_data) -+{ -+ size_t sign_len, buf_len; -+ u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN]; -+ const struct ikev2_prf_alg *prf; -+ const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr; -+ -+ prf = ikev2_get_prf(prf_alg); -+ if (sign_msg == NULL || ID == NULL || SK_p == NULL || -+ shared_secret == NULL || nonce == NULL || prf == NULL) -+ return -1; -+ -+ /* prf(SK_pi/r,IDi/r') */ -+ buf_len = 4 + ID_len; -+ buf = os_zalloc(buf_len); -+ if (buf == NULL) -+ return -1; -+ buf[0] = ID_type; -+ os_memcpy(buf + 4, ID, ID_len); -+ if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len, -+ 1, (const u8 **) &buf, &buf_len, hash) < 0) { -+ os_free(buf); -+ return -1; -+ } -+ os_free(buf); -+ -+ /* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */ -+ sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len; -+ sign_data = os_malloc(sign_len); -+ if (sign_data == NULL) -+ return -1; -+ pos = sign_data; -+ os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg)); -+ pos += wpabuf_len(sign_msg); -+ os_memcpy(pos, nonce, nonce_len); -+ pos += nonce_len; -+ os_memcpy(pos, hash, prf->hash_len); -+ -+ /* AUTH = prf(prf(Shared Secret, key pad, sign_data) */ -+ if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1, -+ &key_pad, &key_pad_len, hash) < 0 || -+ ikev2_prf_hash(prf->id, hash, prf->hash_len, 1, -+ (const u8 **) &sign_data, &sign_len, auth_data) < 0) -+ { -+ os_free(sign_data); -+ return -1; -+ } -+ os_free(sign_data); -+ -+ return 0; -+} -+ -+ -+u8 * ikev2_decrypt_payload(int encr_id, int integ_id, -+ struct ikev2_keys *keys, int initiator, -+ const struct ikev2_hdr *hdr, -+ const u8 *encrypted, size_t encrypted_len, -+ size_t *res_len) -+{ -+ size_t iv_len; -+ const u8 *pos, *end, *iv, *integ; -+ u8 hash[IKEV2_MAX_HASH_LEN], *decrypted; -+ size_t decrypted_len, pad_len; -+ const struct ikev2_integ_alg *integ_alg; -+ const struct ikev2_encr_alg *encr_alg; -+ const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; -+ const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; -+ -+ if (encrypted == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH"); -+ return NULL; -+ } -+ -+ encr_alg = ikev2_get_encr(encr_id); -+ if (encr_alg == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); -+ return NULL; -+ } -+ iv_len = encr_alg->block_size; -+ -+ integ_alg = ikev2_get_integ(integ_id); -+ if (integ_alg == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); -+ return NULL; -+ } -+ -+ if (encrypted_len < iv_len + 1 + integ_alg->hash_len) { -+ wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity " -+ "Checksum"); -+ return NULL; -+ } -+ -+ iv = encrypted; -+ pos = iv + iv_len; -+ end = encrypted + encrypted_len; -+ integ = end - integ_alg->hash_len; -+ -+ if (SK_a == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); -+ return NULL; -+ } -+ if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, -+ (const u8 *) hdr, -+ integ - (const u8 *) hdr, hash) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity " -+ "hash"); -+ return NULL; -+ } -+ if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum " -+ "Data"); -+ return NULL; -+ } -+ -+ if (SK_e == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); -+ return NULL; -+ } -+ -+ decrypted_len = integ - pos; -+ decrypted = os_malloc(decrypted_len); -+ if (decrypted == NULL) -+ return NULL; -+ -+ if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos, -+ decrypted, decrypted_len) < 0) { -+ os_free(decrypted); -+ return NULL; -+ } -+ -+ pad_len = decrypted[decrypted_len - 1]; -+ if (decrypted_len < pad_len + 1) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted " -+ "payload"); -+ os_free(decrypted); -+ return NULL; -+ } -+ -+ decrypted_len -= pad_len + 1; -+ -+ *res_len = decrypted_len; -+ return decrypted; -+} -+ -+ -+void ikev2_update_hdr(struct wpabuf *msg) -+{ -+ struct ikev2_hdr *hdr; -+ -+ /* Update lenth field in HDR */ -+ hdr = wpabuf_mhead(msg); -+ WPA_PUT_BE32(hdr->length, wpabuf_len(msg)); -+} -+ -+ -+int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, -+ int initiator, struct wpabuf *msg, -+ struct wpabuf *plain, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ size_t iv_len, pad_len; -+ u8 *icv, *iv; -+ const struct ikev2_integ_alg *integ_alg; -+ const struct ikev2_encr_alg *encr_alg; -+ const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; -+ const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload"); -+ -+ /* Encr - RFC 4306, Sect. 3.14 */ -+ -+ encr_alg = ikev2_get_encr(encr_id); -+ if (encr_alg == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); -+ return -1; -+ } -+ iv_len = encr_alg->block_size; -+ -+ integ_alg = ikev2_get_integ(integ_id); -+ if (integ_alg == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); -+ return -1; -+ } -+ -+ if (SK_e == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); -+ return -1; -+ } -+ -+ if (SK_a == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); -+ return -1; -+ } -+ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ -+ iv = wpabuf_put(msg, iv_len); -+ if (random_get_bytes(iv, iv_len)) { -+ wpa_printf(MSG_INFO, "IKEV2: Could not generate IV"); -+ return -1; -+ } -+ -+ pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len; -+ if (pad_len == iv_len) -+ pad_len = 0; -+ wpabuf_put(plain, pad_len); -+ wpabuf_put_u8(plain, pad_len); -+ -+ if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, -+ wpabuf_head(plain), wpabuf_mhead(plain), -+ wpabuf_len(plain)) < 0) -+ return -1; -+ -+ wpabuf_put_buf(msg, plain); -+ -+ /* Need to update all headers (Length fields) prior to hash func */ -+ icv = wpabuf_put(msg, integ_alg->hash_len); -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ -+ ikev2_update_hdr(msg); -+ -+ return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, -+ wpabuf_head(msg), -+ wpabuf_len(msg) - integ_alg->hash_len, icv); -+ -+ return 0; -+} -+ -+ -+int ikev2_keys_set(struct ikev2_keys *keys) -+{ -+ return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei && -+ keys->SK_er && keys->SK_pi && keys->SK_pr; -+} -+ -+ -+void ikev2_free_keys(struct ikev2_keys *keys) -+{ -+ os_free(keys->SK_d); -+ os_free(keys->SK_ai); -+ os_free(keys->SK_ar); -+ os_free(keys->SK_ei); -+ os_free(keys->SK_er); -+ os_free(keys->SK_pi); -+ os_free(keys->SK_pr); -+ keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er = -+ keys->SK_pi = keys->SK_pr = NULL; -+} -+ -+ -+int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, -+ const struct ikev2_integ_alg *integ, -+ const struct ikev2_encr_alg *encr, -+ const u8 *skeyseed, const u8 *data, size_t data_len, -+ struct ikev2_keys *keys) -+{ -+ u8 *keybuf, *pos; -+ size_t keybuf_len; -+ -+ /* -+ * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = -+ * prf+(SKEYSEED, Ni | Nr | SPIi | SPIr ) -+ */ -+ ikev2_free_keys(keys); -+ keys->SK_d_len = prf->key_len; -+ keys->SK_integ_len = integ->key_len; -+ keys->SK_encr_len = encr->key_len; -+ keys->SK_prf_len = prf->key_len; -+#ifdef CCNS_PL -+ /* Uses encryption key length for SK_d; should be PRF length */ -+ keys->SK_d_len = keys->SK_encr_len; -+#endif /* CCNS_PL */ -+ -+ keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len + -+ 2 * keys->SK_encr_len + 2 * keys->SK_prf_len; -+ keybuf = os_malloc(keybuf_len); -+ if (keybuf == NULL) -+ return -1; -+ -+ if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len, -+ data, data_len, keybuf, keybuf_len)) { -+ os_free(keybuf); -+ return -1; -+ } -+ -+ pos = keybuf; -+ -+ keys->SK_d = os_malloc(keys->SK_d_len); -+ if (keys->SK_d) { -+ os_memcpy(keys->SK_d, pos, keys->SK_d_len); -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d", -+ keys->SK_d, keys->SK_d_len); -+ } -+ pos += keys->SK_d_len; -+ -+ keys->SK_ai = os_malloc(keys->SK_integ_len); -+ if (keys->SK_ai) { -+ os_memcpy(keys->SK_ai, pos, keys->SK_integ_len); -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai", -+ keys->SK_ai, keys->SK_integ_len); -+ } -+ pos += keys->SK_integ_len; -+ -+ keys->SK_ar = os_malloc(keys->SK_integ_len); -+ if (keys->SK_ar) { -+ os_memcpy(keys->SK_ar, pos, keys->SK_integ_len); -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar", -+ keys->SK_ar, keys->SK_integ_len); -+ } -+ pos += keys->SK_integ_len; -+ -+ keys->SK_ei = os_malloc(keys->SK_encr_len); -+ if (keys->SK_ei) { -+ os_memcpy(keys->SK_ei, pos, keys->SK_encr_len); -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei", -+ keys->SK_ei, keys->SK_encr_len); -+ } -+ pos += keys->SK_encr_len; -+ -+ keys->SK_er = os_malloc(keys->SK_encr_len); -+ if (keys->SK_er) { -+ os_memcpy(keys->SK_er, pos, keys->SK_encr_len); -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er", -+ keys->SK_er, keys->SK_encr_len); -+ } -+ pos += keys->SK_encr_len; -+ -+ keys->SK_pi = os_malloc(keys->SK_prf_len); -+ if (keys->SK_pi) { -+ os_memcpy(keys->SK_pi, pos, keys->SK_prf_len); -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi", -+ keys->SK_pi, keys->SK_prf_len); -+ } -+ pos += keys->SK_prf_len; -+ -+ keys->SK_pr = os_malloc(keys->SK_prf_len); -+ if (keys->SK_pr) { -+ os_memcpy(keys->SK_pr, pos, keys->SK_prf_len); -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr", -+ keys->SK_pr, keys->SK_prf_len); -+ } -+ -+ os_free(keybuf); -+ -+ if (!ikev2_keys_set(keys)) { -+ ikev2_free_keys(keys); -+ return -1; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.h -new file mode 100644 -index 0000000000000..c96a070d5bcb8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_common/ikev2_common.h -@@ -0,0 +1,344 @@ -+/* -+ * IKEv2 definitions -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IKEV2_COMMON_H -+#define IKEV2_COMMON_H -+ -+/* -+ * Nonce length must be at least 16 octets. It must also be at least half the -+ * key size of the negotiated PRF. -+ */ -+#define IKEV2_NONCE_MIN_LEN 16 -+#define IKEV2_NONCE_MAX_LEN 256 -+ -+/* IKE Header - RFC 4306, Sect. 3.1 */ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+#define IKEV2_SPI_LEN 8 -+ -+struct ikev2_hdr { -+ u8 i_spi[IKEV2_SPI_LEN]; /* IKE_SA Initiator's SPI */ -+ u8 r_spi[IKEV2_SPI_LEN]; /* IKE_SA Responder's SPI */ -+ u8 next_payload; -+ u8 version; /* MjVer | MnVer */ -+ u8 exchange_type; -+ u8 flags; -+ u8 message_id[4]; -+ u8 length[4]; /* total length of HDR + payloads */ -+} STRUCT_PACKED; -+ -+struct ikev2_payload_hdr { -+ u8 next_payload; -+ u8 flags; -+ u8 payload_length[2]; /* this payload, including the payload header */ -+} STRUCT_PACKED; -+ -+struct ikev2_proposal { -+ u8 type; /* 0 (last) or 2 (more) */ -+ u8 reserved; -+ u8 proposal_length[2]; /* including all transform and attributes */ -+ u8 proposal_num; -+ u8 protocol_id; /* IKEV2_PROTOCOL_* */ -+ u8 spi_size; -+ u8 num_transforms; -+ /* SPI of spi_size octets */ -+ /* Transforms */ -+} STRUCT_PACKED; -+ -+struct ikev2_transform { -+ u8 type; /* 0 (last) or 3 (more) */ -+ u8 reserved; -+ u8 transform_length[2]; /* including Header and Attributes */ -+ u8 transform_type; -+ u8 reserved2; -+ u8 transform_id[2]; -+ /* Transform Attributes */ -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+/* Current IKEv2 version from RFC 4306 */ -+#define IKEV2_MjVer 2 -+#define IKEV2_MnVer 0 -+#ifdef CCNS_PL -+#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4)) -+#else /* CCNS_PL */ -+#define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer)) -+#endif /* CCNS_PL */ -+ -+/* IKEv2 Exchange Types */ -+enum { -+ /* 0-33 RESERVED */ -+ IKE_SA_INIT = 34, -+ IKE_SA_AUTH = 35, -+ CREATE_CHILD_SA = 36, -+ INFORMATION = 37 -+ /* 38-239 RESERVED TO IANA */ -+ /* 240-255 Reserved for private use */ -+}; -+ -+/* IKEv2 Flags */ -+#define IKEV2_HDR_INITIATOR 0x08 -+#define IKEV2_HDR_VERSION 0x10 -+#define IKEV2_HDR_RESPONSE 0x20 -+ -+/* Payload Header Flags */ -+#define IKEV2_PAYLOAD_FLAGS_CRITICAL 0x01 -+ -+ -+/* EAP-IKEv2 Payload Types (in Next Payload Type field) -+ * http://www.iana.org/assignments/eap-ikev2-payloads */ -+enum { -+ IKEV2_PAYLOAD_NO_NEXT_PAYLOAD = 0, -+ IKEV2_PAYLOAD_SA = 33, -+ IKEV2_PAYLOAD_KEY_EXCHANGE = 34, -+ IKEV2_PAYLOAD_IDi = 35, -+ IKEV2_PAYLOAD_IDr = 36, -+ IKEV2_PAYLOAD_CERTIFICATE = 37, -+ IKEV2_PAYLOAD_CERT_REQ = 38, -+ IKEV2_PAYLOAD_AUTHENTICATION = 39, -+ IKEV2_PAYLOAD_NONCE = 40, -+ IKEV2_PAYLOAD_NOTIFICATION = 41, -+ IKEV2_PAYLOAD_VENDOD_ID = 43, -+ IKEV2_PAYLOAD_ENCRYPTED = 46, -+ IKEV2_PAYLOAD_NEXT_FAST_ID = 121 -+}; -+ -+ -+/* IKEv2 Proposal - Protocol ID */ -+enum { -+ IKEV2_PROTOCOL_RESERVED = 0, -+ IKEV2_PROTOCOL_IKE = 1, /* IKE is the only one allowed for EAP-IKEv2 */ -+ IKEV2_PROTOCOL_AH = 2, -+ IKEV2_PROTOCOL_ESP = 3 -+}; -+ -+ -+/* IKEv2 Transform Types */ -+enum { -+ IKEV2_TRANSFORM_ENCR = 1, -+ IKEV2_TRANSFORM_PRF = 2, -+ IKEV2_TRANSFORM_INTEG = 3, -+ IKEV2_TRANSFORM_DH = 4, -+ IKEV2_TRANSFORM_ESN = 5 -+}; -+ -+/* IKEv2 Tranform Type 1 (Encryption Algorithm) */ -+enum { -+ ENCR_DES_IV64 = 1, -+ ENCR_DES = 2, -+ ENCR_3DES = 3, -+ ENCR_RC5 = 4, -+ ENCR_IDEA = 5, -+ ENCR_CAST = 6, -+ ENCR_BLOWFISH = 7, -+ ENCR_3IDEA = 8, -+ ENCR_DES_IV32 = 9, -+ ENCR_NULL = 11, -+ ENCR_AES_CBC = 12, -+ ENCR_AES_CTR = 13 -+}; -+ -+/* IKEv2 Transform Type 2 (Pseudo-random Function) */ -+enum { -+ PRF_HMAC_MD5 = 1, -+ PRF_HMAC_SHA1 = 2, -+ PRF_HMAC_TIGER = 3, -+ PRF_AES128_XCBC = 4 -+}; -+ -+/* IKEv2 Transform Type 3 (Integrity Algorithm) */ -+enum { -+ AUTH_HMAC_MD5_96 = 1, -+ AUTH_HMAC_SHA1_96 = 2, -+ AUTH_DES_MAC = 3, -+ AUTH_KPDK_MD5 = 4, -+ AUTH_AES_XCBC_96 = 5 -+}; -+ -+/* IKEv2 Transform Type 4 (Diffie-Hellman Group) */ -+enum { -+ DH_GROUP1_768BIT_MODP = 1, /* RFC 4306 */ -+ DH_GROUP2_1024BIT_MODP = 2, /* RFC 4306 */ -+ DH_GROUP5_1536BIT_MODP = 5, /* RFC 3526 */ -+ DH_GROUP5_2048BIT_MODP = 14, /* RFC 3526 */ -+ DH_GROUP5_3072BIT_MODP = 15, /* RFC 3526 */ -+ DH_GROUP5_4096BIT_MODP = 16, /* RFC 3526 */ -+ DH_GROUP5_6144BIT_MODP = 17, /* RFC 3526 */ -+ DH_GROUP5_8192BIT_MODP = 18 /* RFC 3526 */ -+}; -+ -+ -+/* Identification Data Types (RFC 4306, Sect. 3.5) */ -+enum { -+ ID_IPV4_ADDR = 1, -+ ID_FQDN = 2, -+ ID_RFC822_ADDR = 3, -+ ID_IPV6_ADDR = 5, -+ ID_DER_ASN1_DN = 9, -+ ID_DER_ASN1_GN= 10, -+ ID_KEY_ID = 11 -+}; -+ -+ -+/* Certificate Encoding (RFC 4306, Sect. 3.6) */ -+enum { -+ CERT_ENCODING_PKCS7_X509 = 1, -+ CERT_ENCODING_PGP_CERT = 2, -+ CERT_ENCODING_DNS_SIGNED_KEY = 3, -+ /* X.509 Certificate - Signature: DER encoded X.509 certificate whose -+ * public key is used to validate the sender's AUTH payload */ -+ CERT_ENCODING_X509_CERT_SIGN = 4, -+ CERT_ENCODING_KERBEROS_TOKEN = 6, -+ /* DER encoded X.509 certificate revocation list */ -+ CERT_ENCODING_CRL = 7, -+ CERT_ENCODING_ARL = 8, -+ CERT_ENCODING_SPKI_CERT = 9, -+ CERT_ENCODING_X509_CERT_ATTR = 10, -+ /* PKCS #1 encoded RSA key */ -+ CERT_ENCODING_RAW_RSA_KEY = 11, -+ CERT_ENCODING_HASH_AND_URL_X509_CERT = 12, -+ CERT_ENCODING_HASH_AND_URL_X509_BUNDLE = 13 -+}; -+ -+ -+/* Authentication Method (RFC 4306, Sect. 3.8) */ -+enum { -+ AUTH_RSA_SIGN = 1, -+ AUTH_SHARED_KEY_MIC = 2, -+ AUTH_DSS_SIGN = 3 -+}; -+ -+ -+/* Notify Message Types (RFC 4306, Sect. 3.10.1) */ -+enum { -+ UNSUPPORTED_CRITICAL_PAYLOAD = 1, -+ INVALID_IKE_SPI = 4, -+ INVALID_MAJOR_VERSION = 5, -+ INVALID_SYNTAX = 7, -+ INVALID_MESSAGE_ID = 9, -+ INVALID_SPI = 11, -+ NO_PROPOSAL_CHOSEN = 14, -+ INVALID_KE_PAYLOAD = 17, -+ AUTHENTICATION_FAILED = 24, -+ SINGLE_PAIR_REQUIRED = 34, -+ NO_ADDITIONAL_SAS = 35, -+ INTERNAL_ADDRESS_FAILURE = 36, -+ FAILED_CP_REQUIRED = 37, -+ TS_UNACCEPTABLE = 38, -+ INVALID_SELECTORS = 39 -+}; -+ -+ -+struct ikev2_keys { -+ u8 *SK_d, *SK_ai, *SK_ar, *SK_ei, *SK_er, *SK_pi, *SK_pr; -+ size_t SK_d_len, SK_integ_len, SK_encr_len, SK_prf_len; -+}; -+ -+ -+int ikev2_keys_set(struct ikev2_keys *keys); -+void ikev2_free_keys(struct ikev2_keys *keys); -+ -+ -+/* Maximum hash length for supported hash algorithms */ -+#define IKEV2_MAX_HASH_LEN 20 -+ -+struct ikev2_integ_alg { -+ int id; -+ size_t key_len; -+ size_t hash_len; -+}; -+ -+struct ikev2_prf_alg { -+ int id; -+ size_t key_len; -+ size_t hash_len; -+}; -+ -+struct ikev2_encr_alg { -+ int id; -+ size_t key_len; -+ size_t block_size; -+}; -+ -+const struct ikev2_integ_alg * ikev2_get_integ(int id); -+int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, -+ size_t data_len, u8 *hash); -+const struct ikev2_prf_alg * ikev2_get_prf(int id); -+int ikev2_prf_hash(int alg, const u8 *key, size_t key_len, -+ size_t num_elem, const u8 *addr[], const size_t *len, -+ u8 *hash); -+int ikev2_prf_plus(int alg, const u8 *key, size_t key_len, -+ const u8 *data, size_t data_len, -+ u8 *out, size_t out_len); -+const struct ikev2_encr_alg * ikev2_get_encr(int id); -+int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, -+ const u8 *plain, u8 *crypt, size_t len); -+int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, -+ const u8 *crypt, u8 *plain, size_t len); -+ -+int ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg, -+ const u8 *ID, size_t ID_len, u8 ID_type, -+ struct ikev2_keys *keys, int initiator, -+ const u8 *shared_secret, size_t shared_secret_len, -+ const u8 *nonce, size_t nonce_len, -+ const u8 *key_pad, size_t key_pad_len, -+ u8 *auth_data); -+ -+ -+struct ikev2_payloads { -+ const u8 *sa; -+ size_t sa_len; -+ const u8 *ke; -+ size_t ke_len; -+ const u8 *idi; -+ size_t idi_len; -+ const u8 *idr; -+ size_t idr_len; -+ const u8 *cert; -+ size_t cert_len; -+ const u8 *auth; -+ size_t auth_len; -+ const u8 *nonce; -+ size_t nonce_len; -+ const u8 *encrypted; -+ size_t encrypted_len; -+ u8 encr_next_payload; -+ const u8 *notification; -+ size_t notification_len; -+}; -+ -+int ikev2_parse_payloads(struct ikev2_payloads *payloads, -+ u8 next_payload, const u8 *pos, const u8 *end); -+ -+u8 * ikev2_decrypt_payload(int encr_id, int integ_id, struct ikev2_keys *keys, -+ int initiator, const struct ikev2_hdr *hdr, -+ const u8 *encrypted, size_t encrypted_len, -+ size_t *res_len); -+void ikev2_update_hdr(struct wpabuf *msg); -+int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, -+ int initiator, struct wpabuf *msg, -+ struct wpabuf *plain, u8 next_payload); -+int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, -+ const struct ikev2_integ_alg *integ, -+ const struct ikev2_encr_alg *encr, -+ const u8 *skeyseed, const u8 *data, size_t data_len, -+ struct ikev2_keys *keys); -+ -+#endif /* IKEV2_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/Makefile -new file mode 100644 -index 0000000000000..3651056110493 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/Makefile -@@ -0,0 +1,11 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.so *.d -+ -+install: -+ if ls *.so >/dev/null 2>&1; then \ -+ install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \ -+ cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \ -+ ; fi -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.c -new file mode 100644 -index 0000000000000..8a9826f1bd200 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.c -@@ -0,0 +1,2159 @@ -+/* -+ * EAP peer state machines (RFC 4137) -+ * Copyright (c) 2004-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file implements the Peer State Machine as defined in RFC 4137. The used -+ * states and state transitions match mostly with the RFC. However, there are -+ * couple of additional transitions for working around small issues noticed -+ * during testing. These exceptions are explained in comments within the -+ * functions in this file. The method functions, m.func(), are similar to the -+ * ones used in RFC 4137, but some small changes have used here to optimize -+ * operations and to add functionality needed for fast re-authentication -+ * (session resumption). -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "pcsc_funcs.h" -+#include "state_machine.h" -+#include "crypto/crypto.h" -+#include "crypto/tls.h" -+#include "common/wpa_ctrl.h" -+#include "eap_common/eap_wsc_common.h" -+#include "eap_i.h" -+#include "eap_config.h" -+ -+#define STATE_MACHINE_DATA struct eap_sm -+#define STATE_MACHINE_DEBUG_PREFIX "EAP" -+ -+#define EAP_MAX_AUTH_ROUNDS 50 -+#define EAP_CLIENT_TIMEOUT_DEFAULT 60 -+ -+ -+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor, -+ EapType method); -+static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id); -+static void eap_sm_processIdentity(struct eap_sm *sm, -+ const struct wpabuf *req); -+static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req); -+static struct wpabuf * eap_sm_buildNotify(int id); -+static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req); -+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -+static const char * eap_sm_method_state_txt(EapMethodState state); -+static const char * eap_sm_decision_txt(EapDecision decision); -+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+ -+static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var) -+{ -+ return sm->eapol_cb->get_bool(sm->eapol_ctx, var); -+} -+ -+ -+static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var, -+ Boolean value) -+{ -+ sm->eapol_cb->set_bool(sm->eapol_ctx, var, value); -+} -+ -+ -+static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var) -+{ -+ return sm->eapol_cb->get_int(sm->eapol_ctx, var); -+} -+ -+ -+static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var, -+ unsigned int value) -+{ -+ sm->eapol_cb->set_int(sm->eapol_ctx, var, value); -+} -+ -+ -+static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm) -+{ -+ return sm->eapol_cb->get_eapReqData(sm->eapol_ctx); -+} -+ -+ -+static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) -+{ -+ if (sm->m == NULL || sm->eap_method_priv == NULL) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method " -+ "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt); -+ sm->m->deinit(sm, sm->eap_method_priv); -+ sm->eap_method_priv = NULL; -+ sm->m = NULL; -+} -+ -+ -+/** -+ * eap_allowed_method - Check whether EAP method is allowed -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types -+ * @method: EAP type -+ * Returns: 1 = allowed EAP method, 0 = not allowed -+ */ -+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ int i; -+ struct eap_method_type *m; -+ -+ if (config == NULL || config->eap_methods == NULL) -+ return 1; -+ -+ m = config->eap_methods; -+ for (i = 0; m[i].vendor != EAP_VENDOR_IETF || -+ m[i].method != EAP_TYPE_NONE; i++) { -+ if (m[i].vendor == vendor && m[i].method == method) -+ return 1; -+ } -+ return 0; -+} -+ -+ -+/* -+ * This state initializes state machine variables when the machine is -+ * activated (portEnabled = TRUE). This is also used when re-starting -+ * authentication (eapRestart == TRUE). -+ */ -+SM_STATE(EAP, INITIALIZE) -+{ -+ SM_ENTRY(EAP, INITIALIZE); -+ if (sm->fast_reauth && sm->m && sm->m->has_reauth_data && -+ sm->m->has_reauth_data(sm, sm->eap_method_priv) && -+ !sm->prev_failure) { -+ wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for " -+ "fast reauthentication"); -+ sm->m->deinit_for_reauth(sm, sm->eap_method_priv); -+ } else { -+ eap_deinit_prev_method(sm, "INITIALIZE"); -+ } -+ sm->selectedMethod = EAP_TYPE_NONE; -+ sm->methodState = METHOD_NONE; -+ sm->allowNotifications = TRUE; -+ sm->decision = DECISION_FAIL; -+ eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); -+ eapol_set_bool(sm, EAPOL_eapSuccess, FALSE); -+ eapol_set_bool(sm, EAPOL_eapFail, FALSE); -+ os_free(sm->eapKeyData); -+ sm->eapKeyData = NULL; -+ sm->eapKeyAvailable = FALSE; -+ eapol_set_bool(sm, EAPOL_eapRestart, FALSE); -+ sm->lastId = -1; /* new session - make sure this does not match with -+ * the first EAP-Packet */ -+ /* -+ * RFC 4137 does not reset eapResp and eapNoResp here. However, this -+ * seemed to be able to trigger cases where both were set and if EAPOL -+ * state machine uses eapNoResp first, it may end up not sending a real -+ * reply correctly. This occurred when the workaround in FAIL state set -+ * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do -+ * something else(?) -+ */ -+ eapol_set_bool(sm, EAPOL_eapResp, FALSE); -+ eapol_set_bool(sm, EAPOL_eapNoResp, FALSE); -+ sm->num_rounds = 0; -+ sm->prev_failure = 0; -+} -+ -+ -+/* -+ * This state is reached whenever service from the lower layer is interrupted -+ * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE -+ * occurs when the port becomes enabled. -+ */ -+SM_STATE(EAP, DISABLED) -+{ -+ SM_ENTRY(EAP, DISABLED); -+ sm->num_rounds = 0; -+} -+ -+ -+/* -+ * The state machine spends most of its time here, waiting for something to -+ * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and -+ * SEND_RESPONSE states. -+ */ -+SM_STATE(EAP, IDLE) -+{ -+ SM_ENTRY(EAP, IDLE); -+} -+ -+ -+/* -+ * This state is entered when an EAP packet is received (eapReq == TRUE) to -+ * parse the packet header. -+ */ -+SM_STATE(EAP, RECEIVED) -+{ -+ const struct wpabuf *eapReqData; -+ -+ SM_ENTRY(EAP, RECEIVED); -+ eapReqData = eapol_get_eapReqData(sm); -+ /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */ -+ eap_sm_parseEapReq(sm, eapReqData); -+ sm->num_rounds++; -+} -+ -+ -+/* -+ * This state is entered when a request for a new type comes in. Either the -+ * correct method is started, or a Nak response is built. -+ */ -+SM_STATE(EAP, GET_METHOD) -+{ -+ int reinit; -+ EapType method; -+ -+ SM_ENTRY(EAP, GET_METHOD); -+ -+ if (sm->reqMethod == EAP_TYPE_EXPANDED) -+ method = sm->reqVendorMethod; -+ else -+ method = sm->reqMethod; -+ -+ if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) { -+ wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed", -+ sm->reqVendor, method); -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD -+ "vendor=%u method=%u -> NAK", -+ sm->reqVendor, method); -+ goto nak; -+ } -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD -+ "vendor=%u method=%u", sm->reqVendor, method); -+ -+ /* -+ * RFC 4137 does not define specific operation for fast -+ * re-authentication (session resumption). The design here is to allow -+ * the previously used method data to be maintained for -+ * re-authentication if the method support session resumption. -+ * Otherwise, the previously used method data is freed and a new method -+ * is allocated here. -+ */ -+ if (sm->fast_reauth && -+ sm->m && sm->m->vendor == sm->reqVendor && -+ sm->m->method == method && -+ sm->m->has_reauth_data && -+ sm->m->has_reauth_data(sm, sm->eap_method_priv)) { -+ wpa_printf(MSG_DEBUG, "EAP: Using previous method data" -+ " for fast re-authentication"); -+ reinit = 1; -+ } else { -+ eap_deinit_prev_method(sm, "GET_METHOD"); -+ reinit = 0; -+ } -+ -+ sm->selectedMethod = sm->reqMethod; -+ if (sm->m == NULL) -+ sm->m = eap_peer_get_eap_method(sm->reqVendor, method); -+ if (!sm->m) { -+ wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: " -+ "vendor %d method %d", -+ sm->reqVendor, method); -+ goto nak; -+ } -+ -+ sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT; -+ -+ wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: " -+ "vendor %u method %u (%s)", -+ sm->reqVendor, method, sm->m->name); -+ if (reinit) -+ sm->eap_method_priv = sm->m->init_for_reauth( -+ sm, sm->eap_method_priv); -+ else -+ sm->eap_method_priv = sm->m->init(sm); -+ -+ if (sm->eap_method_priv == NULL) { -+ struct eap_peer_config *config = eap_get_config(sm); -+ wpa_msg(sm->msg_ctx, MSG_INFO, -+ "EAP: Failed to initialize EAP method: vendor %u " -+ "method %u (%s)", -+ sm->reqVendor, method, sm->m->name); -+ sm->m = NULL; -+ sm->methodState = METHOD_NONE; -+ sm->selectedMethod = EAP_TYPE_NONE; -+ if (sm->reqMethod == EAP_TYPE_TLS && config && -+ (config->pending_req_pin || -+ config->pending_req_passphrase)) { -+ /* -+ * Return without generating Nak in order to allow -+ * entering of PIN code or passphrase to retry the -+ * current EAP packet. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase " -+ "request - skip Nak"); -+ return; -+ } -+ -+ goto nak; -+ } -+ -+ sm->methodState = METHOD_INIT; -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD -+ "EAP vendor %u method %u (%s) selected", -+ sm->reqVendor, method, sm->m->name); -+ return; -+ -+nak: -+ wpabuf_free(sm->eapRespData); -+ sm->eapRespData = NULL; -+ sm->eapRespData = eap_sm_buildNak(sm, sm->reqId); -+} -+ -+ -+/* -+ * The method processing happens here. The request from the authenticator is -+ * processed, and an appropriate response packet is built. -+ */ -+SM_STATE(EAP, METHOD) -+{ -+ struct wpabuf *eapReqData; -+ struct eap_method_ret ret; -+ -+ SM_ENTRY(EAP, METHOD); -+ if (sm->m == NULL) { -+ wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected"); -+ return; -+ } -+ -+ eapReqData = eapol_get_eapReqData(sm); -+ -+ /* -+ * Get ignore, methodState, decision, allowNotifications, and -+ * eapRespData. RFC 4137 uses three separate method procedure (check, -+ * process, and buildResp) in this state. These have been combined into -+ * a single function call to m->process() in order to optimize EAP -+ * method implementation interface a bit. These procedures are only -+ * used from within this METHOD state, so there is no need to keep -+ * these as separate C functions. -+ * -+ * The RFC 4137 procedures return values as follows: -+ * ignore = m.check(eapReqData) -+ * (methodState, decision, allowNotifications) = m.process(eapReqData) -+ * eapRespData = m.buildResp(reqId) -+ */ -+ os_memset(&ret, 0, sizeof(ret)); -+ ret.ignore = sm->ignore; -+ ret.methodState = sm->methodState; -+ ret.decision = sm->decision; -+ ret.allowNotifications = sm->allowNotifications; -+ wpabuf_free(sm->eapRespData); -+ sm->eapRespData = NULL; -+ sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret, -+ eapReqData); -+ wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s " -+ "methodState=%s decision=%s", -+ ret.ignore ? "TRUE" : "FALSE", -+ eap_sm_method_state_txt(ret.methodState), -+ eap_sm_decision_txt(ret.decision)); -+ -+ sm->ignore = ret.ignore; -+ if (sm->ignore) -+ return; -+ sm->methodState = ret.methodState; -+ sm->decision = ret.decision; -+ sm->allowNotifications = ret.allowNotifications; -+ -+ if (sm->m->isKeyAvailable && sm->m->getKey && -+ sm->m->isKeyAvailable(sm, sm->eap_method_priv)) { -+ os_free(sm->eapKeyData); -+ sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, -+ &sm->eapKeyDataLen); -+ } -+} -+ -+ -+/* -+ * This state signals the lower layer that a response packet is ready to be -+ * sent. -+ */ -+SM_STATE(EAP, SEND_RESPONSE) -+{ -+ SM_ENTRY(EAP, SEND_RESPONSE); -+ wpabuf_free(sm->lastRespData); -+ if (sm->eapRespData) { -+ if (sm->workaround) -+ os_memcpy(sm->last_md5, sm->req_md5, 16); -+ sm->lastId = sm->reqId; -+ sm->lastRespData = wpabuf_dup(sm->eapRespData); -+ eapol_set_bool(sm, EAPOL_eapResp, TRUE); -+ } else -+ sm->lastRespData = NULL; -+ eapol_set_bool(sm, EAPOL_eapReq, FALSE); -+ eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); -+} -+ -+ -+/* -+ * This state signals the lower layer that the request was discarded, and no -+ * response packet will be sent at this time. -+ */ -+SM_STATE(EAP, DISCARD) -+{ -+ SM_ENTRY(EAP, DISCARD); -+ eapol_set_bool(sm, EAPOL_eapReq, FALSE); -+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE); -+} -+ -+ -+/* -+ * Handles requests for Identity method and builds a response. -+ */ -+SM_STATE(EAP, IDENTITY) -+{ -+ const struct wpabuf *eapReqData; -+ -+ SM_ENTRY(EAP, IDENTITY); -+ eapReqData = eapol_get_eapReqData(sm); -+ eap_sm_processIdentity(sm, eapReqData); -+ wpabuf_free(sm->eapRespData); -+ sm->eapRespData = NULL; -+ sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0); -+} -+ -+ -+/* -+ * Handles requests for Notification method and builds a response. -+ */ -+SM_STATE(EAP, NOTIFICATION) -+{ -+ const struct wpabuf *eapReqData; -+ -+ SM_ENTRY(EAP, NOTIFICATION); -+ eapReqData = eapol_get_eapReqData(sm); -+ eap_sm_processNotify(sm, eapReqData); -+ wpabuf_free(sm->eapRespData); -+ sm->eapRespData = NULL; -+ sm->eapRespData = eap_sm_buildNotify(sm->reqId); -+} -+ -+ -+/* -+ * This state retransmits the previous response packet. -+ */ -+SM_STATE(EAP, RETRANSMIT) -+{ -+ SM_ENTRY(EAP, RETRANSMIT); -+ wpabuf_free(sm->eapRespData); -+ if (sm->lastRespData) -+ sm->eapRespData = wpabuf_dup(sm->lastRespData); -+ else -+ sm->eapRespData = NULL; -+} -+ -+ -+/* -+ * This state is entered in case of a successful completion of authentication -+ * and state machine waits here until port is disabled or EAP authentication is -+ * restarted. -+ */ -+SM_STATE(EAP, SUCCESS) -+{ -+ SM_ENTRY(EAP, SUCCESS); -+ if (sm->eapKeyData != NULL) -+ sm->eapKeyAvailable = TRUE; -+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE); -+ -+ /* -+ * RFC 4137 does not clear eapReq here, but this seems to be required -+ * to avoid processing the same request twice when state machine is -+ * initialized. -+ */ -+ eapol_set_bool(sm, EAPOL_eapReq, FALSE); -+ -+ /* -+ * RFC 4137 does not set eapNoResp here, but this seems to be required -+ * to get EAPOL Supplicant backend state machine into SUCCESS state. In -+ * addition, either eapResp or eapNoResp is required to be set after -+ * processing the received EAP frame. -+ */ -+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE); -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS -+ "EAP authentication completed successfully"); -+} -+ -+ -+/* -+ * This state is entered in case of a failure and state machine waits here -+ * until port is disabled or EAP authentication is restarted. -+ */ -+SM_STATE(EAP, FAILURE) -+{ -+ SM_ENTRY(EAP, FAILURE); -+ eapol_set_bool(sm, EAPOL_eapFail, TRUE); -+ -+ /* -+ * RFC 4137 does not clear eapReq here, but this seems to be required -+ * to avoid processing the same request twice when state machine is -+ * initialized. -+ */ -+ eapol_set_bool(sm, EAPOL_eapReq, FALSE); -+ -+ /* -+ * RFC 4137 does not set eapNoResp here. However, either eapResp or -+ * eapNoResp is required to be set after processing the received EAP -+ * frame. -+ */ -+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE); -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE -+ "EAP authentication failed"); -+ -+ sm->prev_failure = 1; -+} -+ -+ -+static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId) -+{ -+ /* -+ * At least Microsoft IAS and Meetinghouse Aegis seem to be sending -+ * EAP-Success/Failure with lastId + 1 even though RFC 3748 and -+ * RFC 4137 require that reqId == lastId. In addition, it looks like -+ * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success. -+ * -+ * Accept this kind of Id if EAP workarounds are enabled. These are -+ * unauthenticated plaintext messages, so this should have minimal -+ * security implications (bit easier to fake EAP-Success/Failure). -+ */ -+ if (sm->workaround && (reqId == ((lastId + 1) & 0xff) || -+ reqId == ((lastId + 2) & 0xff))) { -+ wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected " -+ "identifier field in EAP Success: " -+ "reqId=%d lastId=%d (these are supposed to be " -+ "same)", reqId, lastId); -+ return 1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d " -+ "lastId=%d", reqId, lastId); -+ return 0; -+} -+ -+ -+/* -+ * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions -+ */ -+ -+static void eap_peer_sm_step_idle(struct eap_sm *sm) -+{ -+ /* -+ * The first three transitions are from RFC 4137. The last two are -+ * local additions to handle special cases with LEAP and PEAP server -+ * not sending EAP-Success in some cases. -+ */ -+ if (eapol_get_bool(sm, EAPOL_eapReq)) -+ SM_ENTER(EAP, RECEIVED); -+ else if ((eapol_get_bool(sm, EAPOL_altAccept) && -+ sm->decision != DECISION_FAIL) || -+ (eapol_get_int(sm, EAPOL_idleWhile) == 0 && -+ sm->decision == DECISION_UNCOND_SUCC)) -+ SM_ENTER(EAP, SUCCESS); -+ else if (eapol_get_bool(sm, EAPOL_altReject) || -+ (eapol_get_int(sm, EAPOL_idleWhile) == 0 && -+ sm->decision != DECISION_UNCOND_SUCC) || -+ (eapol_get_bool(sm, EAPOL_altAccept) && -+ sm->methodState != METHOD_CONT && -+ sm->decision == DECISION_FAIL)) -+ SM_ENTER(EAP, FAILURE); -+ else if (sm->selectedMethod == EAP_TYPE_LEAP && -+ sm->leap_done && sm->decision != DECISION_FAIL && -+ sm->methodState == METHOD_DONE) -+ SM_ENTER(EAP, SUCCESS); -+ else if (sm->selectedMethod == EAP_TYPE_PEAP && -+ sm->peap_done && sm->decision != DECISION_FAIL && -+ sm->methodState == METHOD_DONE) -+ SM_ENTER(EAP, SUCCESS); -+} -+ -+ -+static int eap_peer_req_is_duplicate(struct eap_sm *sm) -+{ -+ int duplicate; -+ -+ duplicate = (sm->reqId == sm->lastId) && sm->rxReq; -+ if (sm->workaround && duplicate && -+ os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) { -+ /* -+ * RFC 4137 uses (reqId == lastId) as the only verification for -+ * duplicate EAP requests. However, this misses cases where the -+ * AS is incorrectly using the same id again; and -+ * unfortunately, such implementations exist. Use MD5 hash as -+ * an extra verification for the packets being duplicate to -+ * workaround these issues. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but " -+ "EAP packets were not identical"); -+ wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a " -+ "duplicate packet"); -+ duplicate = 0; -+ } -+ -+ return duplicate; -+} -+ -+ -+static void eap_peer_sm_step_received(struct eap_sm *sm) -+{ -+ int duplicate = eap_peer_req_is_duplicate(sm); -+ -+ /* -+ * Two special cases below for LEAP are local additions to work around -+ * odd LEAP behavior (EAP-Success in the middle of authentication and -+ * then swapped roles). Other transitions are based on RFC 4137. -+ */ -+ if (sm->rxSuccess && sm->decision != DECISION_FAIL && -+ (sm->reqId == sm->lastId || -+ eap_success_workaround(sm, sm->reqId, sm->lastId))) -+ SM_ENTER(EAP, SUCCESS); -+ else if (sm->methodState != METHOD_CONT && -+ ((sm->rxFailure && -+ sm->decision != DECISION_UNCOND_SUCC) || -+ (sm->rxSuccess && sm->decision == DECISION_FAIL && -+ (sm->selectedMethod != EAP_TYPE_LEAP || -+ sm->methodState != METHOD_MAY_CONT))) && -+ (sm->reqId == sm->lastId || -+ eap_success_workaround(sm, sm->reqId, sm->lastId))) -+ SM_ENTER(EAP, FAILURE); -+ else if (sm->rxReq && duplicate) -+ SM_ENTER(EAP, RETRANSMIT); -+ else if (sm->rxReq && !duplicate && -+ sm->reqMethod == EAP_TYPE_NOTIFICATION && -+ sm->allowNotifications) -+ SM_ENTER(EAP, NOTIFICATION); -+ else if (sm->rxReq && !duplicate && -+ sm->selectedMethod == EAP_TYPE_NONE && -+ sm->reqMethod == EAP_TYPE_IDENTITY) -+ SM_ENTER(EAP, IDENTITY); -+ else if (sm->rxReq && !duplicate && -+ sm->selectedMethod == EAP_TYPE_NONE && -+ sm->reqMethod != EAP_TYPE_IDENTITY && -+ sm->reqMethod != EAP_TYPE_NOTIFICATION) -+ SM_ENTER(EAP, GET_METHOD); -+ else if (sm->rxReq && !duplicate && -+ sm->reqMethod == sm->selectedMethod && -+ sm->methodState != METHOD_DONE) -+ SM_ENTER(EAP, METHOD); -+ else if (sm->selectedMethod == EAP_TYPE_LEAP && -+ (sm->rxSuccess || sm->rxResp)) -+ SM_ENTER(EAP, METHOD); -+ else -+ SM_ENTER(EAP, DISCARD); -+} -+ -+ -+static void eap_peer_sm_step_local(struct eap_sm *sm) -+{ -+ switch (sm->EAP_state) { -+ case EAP_INITIALIZE: -+ SM_ENTER(EAP, IDLE); -+ break; -+ case EAP_DISABLED: -+ if (eapol_get_bool(sm, EAPOL_portEnabled) && -+ !sm->force_disabled) -+ SM_ENTER(EAP, INITIALIZE); -+ break; -+ case EAP_IDLE: -+ eap_peer_sm_step_idle(sm); -+ break; -+ case EAP_RECEIVED: -+ eap_peer_sm_step_received(sm); -+ break; -+ case EAP_GET_METHOD: -+ if (sm->selectedMethod == sm->reqMethod) -+ SM_ENTER(EAP, METHOD); -+ else -+ SM_ENTER(EAP, SEND_RESPONSE); -+ break; -+ case EAP_METHOD: -+ if (sm->ignore) -+ SM_ENTER(EAP, DISCARD); -+ else -+ SM_ENTER(EAP, SEND_RESPONSE); -+ break; -+ case EAP_SEND_RESPONSE: -+ SM_ENTER(EAP, IDLE); -+ break; -+ case EAP_DISCARD: -+ SM_ENTER(EAP, IDLE); -+ break; -+ case EAP_IDENTITY: -+ SM_ENTER(EAP, SEND_RESPONSE); -+ break; -+ case EAP_NOTIFICATION: -+ SM_ENTER(EAP, SEND_RESPONSE); -+ break; -+ case EAP_RETRANSMIT: -+ SM_ENTER(EAP, SEND_RESPONSE); -+ break; -+ case EAP_SUCCESS: -+ break; -+ case EAP_FAILURE: -+ break; -+ } -+} -+ -+ -+SM_STEP(EAP) -+{ -+ /* Global transitions */ -+ if (eapol_get_bool(sm, EAPOL_eapRestart) && -+ eapol_get_bool(sm, EAPOL_portEnabled)) -+ SM_ENTER_GLOBAL(EAP, INITIALIZE); -+ else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled) -+ SM_ENTER_GLOBAL(EAP, DISABLED); -+ else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { -+ /* RFC 4137 does not place any limit on number of EAP messages -+ * in an authentication session. However, some error cases have -+ * ended up in a state were EAP messages were sent between the -+ * peer and server in a loop (e.g., TLS ACK frame in both -+ * direction). Since this is quite undesired outcome, limit the -+ * total number of EAP round-trips and abort authentication if -+ * this limit is exceeded. -+ */ -+ if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { -+ wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d " -+ "authentication rounds - abort", -+ EAP_MAX_AUTH_ROUNDS); -+ sm->num_rounds++; -+ SM_ENTER_GLOBAL(EAP, FAILURE); -+ } -+ } else { -+ /* Local transitions */ -+ eap_peer_sm_step_local(sm); -+ } -+} -+ -+ -+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor, -+ EapType method) -+{ -+ if (!eap_allowed_method(sm, vendor, method)) { -+ wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: " -+ "vendor %u method %u", vendor, method); -+ return FALSE; -+ } -+ if (eap_peer_get_eap_method(vendor, method)) -+ return TRUE; -+ wpa_printf(MSG_DEBUG, "EAP: not included in build: " -+ "vendor %u method %u", vendor, method); -+ return FALSE; -+} -+ -+ -+static struct wpabuf * eap_sm_build_expanded_nak( -+ struct eap_sm *sm, int id, const struct eap_method *methods, -+ size_t count) -+{ -+ struct wpabuf *resp; -+ int found = 0; -+ const struct eap_method *m; -+ -+ wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak"); -+ -+ /* RFC 3748 - 5.3.2: Expanded Nak */ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED, -+ 8 + 8 * (count + 1), EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_be24(resp, EAP_VENDOR_IETF); -+ wpabuf_put_be32(resp, EAP_TYPE_NAK); -+ -+ for (m = methods; m; m = m->next) { -+ if (sm->reqVendor == m->vendor && -+ sm->reqVendorMethod == m->method) -+ continue; /* do not allow the current method again */ -+ if (eap_allowed_method(sm, m->vendor, m->method)) { -+ wpa_printf(MSG_DEBUG, "EAP: allowed type: " -+ "vendor=%u method=%u", -+ m->vendor, m->method); -+ wpabuf_put_u8(resp, EAP_TYPE_EXPANDED); -+ wpabuf_put_be24(resp, m->vendor); -+ wpabuf_put_be32(resp, m->method); -+ -+ found++; -+ } -+ } -+ if (!found) { -+ wpa_printf(MSG_DEBUG, "EAP: no more allowed methods"); -+ wpabuf_put_u8(resp, EAP_TYPE_EXPANDED); -+ wpabuf_put_be24(resp, EAP_VENDOR_IETF); -+ wpabuf_put_be32(resp, EAP_TYPE_NONE); -+ } -+ -+ eap_update_len(resp); -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id) -+{ -+ struct wpabuf *resp; -+ u8 *start; -+ int found = 0, expanded_found = 0; -+ size_t count; -+ const struct eap_method *methods, *m; -+ -+ wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u " -+ "vendor=%u method=%u not allowed)", sm->reqMethod, -+ sm->reqVendor, sm->reqVendorMethod); -+ methods = eap_peer_get_methods(&count); -+ if (methods == NULL) -+ return NULL; -+ if (sm->reqMethod == EAP_TYPE_EXPANDED) -+ return eap_sm_build_expanded_nak(sm, id, methods, count); -+ -+ /* RFC 3748 - 5.3.1: Legacy Nak */ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, -+ sizeof(struct eap_hdr) + 1 + count + 1, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ start = wpabuf_put(resp, 0); -+ for (m = methods; m; m = m->next) { -+ if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod) -+ continue; /* do not allow the current method again */ -+ if (eap_allowed_method(sm, m->vendor, m->method)) { -+ if (m->vendor != EAP_VENDOR_IETF) { -+ if (expanded_found) -+ continue; -+ expanded_found = 1; -+ wpabuf_put_u8(resp, EAP_TYPE_EXPANDED); -+ } else -+ wpabuf_put_u8(resp, m->method); -+ found++; -+ } -+ } -+ if (!found) -+ wpabuf_put_u8(resp, EAP_TYPE_NONE); -+ wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found); -+ -+ eap_update_len(resp); -+ -+ return resp; -+} -+ -+ -+static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req) -+{ -+ const struct eap_hdr *hdr = wpabuf_head(req); -+ const u8 *pos = (const u8 *) (hdr + 1); -+ pos++; -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED -+ "EAP authentication started"); -+ -+ /* -+ * RFC 3748 - 5.1: Identity -+ * Data field may contain a displayable message in UTF-8. If this -+ * includes NUL-character, only the data before that should be -+ * displayed. Some EAP implementasitons may piggy-back additional -+ * options after the NUL. -+ */ -+ /* TODO: could save displayable message so that it can be shown to the -+ * user in case of interaction is required */ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data", -+ pos, be_to_host16(hdr->length) - 5); -+} -+ -+ -+#ifdef PCSC_FUNCS -+static int eap_sm_imsi_identity(struct eap_sm *sm, -+ struct eap_peer_config *conf) -+{ -+ int aka = 0; -+ char imsi[100]; -+ size_t imsi_len; -+ struct eap_method_type *m = conf->eap_methods; -+ int i; -+ -+ imsi_len = sizeof(imsi); -+ if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) { -+ wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM"); -+ return -1; -+ } -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len); -+ -+ for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF || -+ m[i].method != EAP_TYPE_NONE); i++) { -+ if (m[i].vendor == EAP_VENDOR_IETF && -+ m[i].method == EAP_TYPE_AKA) { -+ aka = 1; -+ break; -+ } -+ } -+ -+ os_free(conf->identity); -+ conf->identity = os_malloc(1 + imsi_len); -+ if (conf->identity == NULL) { -+ wpa_printf(MSG_WARNING, "Failed to allocate buffer for " -+ "IMSI-based identity"); -+ return -1; -+ } -+ -+ conf->identity[0] = aka ? '0' : '1'; -+ os_memcpy(conf->identity + 1, imsi, imsi_len); -+ conf->identity_len = 1 + imsi_len; -+ -+ return 0; -+} -+#endif /* PCSC_FUNCS */ -+ -+ -+static int eap_sm_set_scard_pin(struct eap_sm *sm, -+ struct eap_peer_config *conf) -+{ -+#ifdef PCSC_FUNCS -+ if (scard_set_pin(sm->scard_ctx, conf->pin)) { -+ /* -+ * Make sure the same PIN is not tried again in order to avoid -+ * blocking SIM. -+ */ -+ os_free(conf->pin); -+ conf->pin = NULL; -+ -+ wpa_printf(MSG_WARNING, "PIN validation failed"); -+ eap_sm_request_pin(sm); -+ return -1; -+ } -+ return 0; -+#else /* PCSC_FUNCS */ -+ return -1; -+#endif /* PCSC_FUNCS */ -+} -+ -+static int eap_sm_get_scard_identity(struct eap_sm *sm, -+ struct eap_peer_config *conf) -+{ -+#ifdef PCSC_FUNCS -+ if (eap_sm_set_scard_pin(sm, conf)) -+ return -1; -+ -+ return eap_sm_imsi_identity(sm, conf); -+#else /* PCSC_FUNCS */ -+ return -1; -+#endif /* PCSC_FUNCS */ -+} -+ -+ -+/** -+ * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @id: EAP identifier for the packet -+ * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2) -+ * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on -+ * failure -+ * -+ * This function allocates and builds an EAP-Identity/Response packet for the -+ * current network. The caller is responsible for freeing the returned data. -+ */ -+struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ struct wpabuf *resp; -+ const u8 *identity; -+ size_t identity_len; -+ -+ if (config == NULL) { -+ wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration " -+ "was not available"); -+ return NULL; -+ } -+ -+ if (sm->m && sm->m->get_identity && -+ (identity = sm->m->get_identity(sm, sm->eap_method_priv, -+ &identity_len)) != NULL) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth " -+ "identity", identity, identity_len); -+ } else if (!encrypted && config->anonymous_identity) { -+ identity = config->anonymous_identity; -+ identity_len = config->anonymous_identity_len; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity", -+ identity, identity_len); -+ } else { -+ identity = config->identity; -+ identity_len = config->identity_len; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity", -+ identity, identity_len); -+ } -+ -+ if (identity == NULL) { -+ wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity " -+ "configuration was not available"); -+ if (config->pcsc) { -+ if (eap_sm_get_scard_identity(sm, config) < 0) -+ return NULL; -+ identity = config->identity; -+ identity_len = config->identity_len; -+ wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from " -+ "IMSI", identity, identity_len); -+ } else { -+ eap_sm_request_identity(sm); -+ return NULL; -+ } -+ } else if (config->pcsc) { -+ if (eap_sm_set_scard_pin(sm, config) < 0) -+ return NULL; -+ } -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_data(resp, identity, identity_len); -+ -+ return resp; -+} -+ -+ -+static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req) -+{ -+ const u8 *pos; -+ char *msg; -+ size_t i, msg_len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req, -+ &msg_len); -+ if (pos == NULL) -+ return; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data", -+ pos, msg_len); -+ -+ msg = os_malloc(msg_len + 1); -+ if (msg == NULL) -+ return; -+ for (i = 0; i < msg_len; i++) -+ msg[i] = isprint(pos[i]) ? (char) pos[i] : '_'; -+ msg[msg_len] = '\0'; -+ wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s", -+ WPA_EVENT_EAP_NOTIFICATION, msg); -+ os_free(msg); -+} -+ -+ -+static struct wpabuf * eap_sm_buildNotify(int id) -+{ -+ struct wpabuf *resp; -+ -+ wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification"); -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ return resp; -+} -+ -+ -+static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req) -+{ -+ const struct eap_hdr *hdr; -+ size_t plen; -+ const u8 *pos; -+ -+ sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE; -+ sm->reqId = 0; -+ sm->reqMethod = EAP_TYPE_NONE; -+ sm->reqVendor = EAP_VENDOR_IETF; -+ sm->reqVendorMethod = EAP_TYPE_NONE; -+ -+ if (req == NULL || wpabuf_len(req) < sizeof(*hdr)) -+ return; -+ -+ hdr = wpabuf_head(req); -+ plen = be_to_host16(hdr->length); -+ if (plen > wpabuf_len(req)) { -+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " -+ "(len=%lu plen=%lu)", -+ (unsigned long) wpabuf_len(req), -+ (unsigned long) plen); -+ return; -+ } -+ -+ sm->reqId = hdr->identifier; -+ -+ if (sm->workaround) { -+ const u8 *addr[1]; -+ addr[0] = wpabuf_head(req); -+ md5_vector(1, addr, &plen, sm->req_md5); -+ } -+ -+ switch (hdr->code) { -+ case EAP_CODE_REQUEST: -+ if (plen < sizeof(*hdr) + 1) { -+ wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - " -+ "no Type field"); -+ return; -+ } -+ sm->rxReq = TRUE; -+ pos = (const u8 *) (hdr + 1); -+ sm->reqMethod = *pos++; -+ if (sm->reqMethod == EAP_TYPE_EXPANDED) { -+ if (plen < sizeof(*hdr) + 8) { -+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " -+ "expanded EAP-Packet (plen=%lu)", -+ (unsigned long) plen); -+ return; -+ } -+ sm->reqVendor = WPA_GET_BE24(pos); -+ pos += 3; -+ sm->reqVendorMethod = WPA_GET_BE32(pos); -+ } -+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d " -+ "method=%u vendor=%u vendorMethod=%u", -+ sm->reqId, sm->reqMethod, sm->reqVendor, -+ sm->reqVendorMethod); -+ break; -+ case EAP_CODE_RESPONSE: -+ if (sm->selectedMethod == EAP_TYPE_LEAP) { -+ /* -+ * LEAP differs from RFC 4137 by using reversed roles -+ * for mutual authentication and because of this, we -+ * need to accept EAP-Response frames if LEAP is used. -+ */ -+ if (plen < sizeof(*hdr) + 1) { -+ wpa_printf(MSG_DEBUG, "EAP: Too short " -+ "EAP-Response - no Type field"); -+ return; -+ } -+ sm->rxResp = TRUE; -+ pos = (const u8 *) (hdr + 1); -+ sm->reqMethod = *pos; -+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for " -+ "LEAP method=%d id=%d", -+ sm->reqMethod, sm->reqId); -+ break; -+ } -+ wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response"); -+ break; -+ case EAP_CODE_SUCCESS: -+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success"); -+ sm->rxSuccess = TRUE; -+ break; -+ case EAP_CODE_FAILURE: -+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure"); -+ sm->rxFailure = TRUE; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown " -+ "code %d", hdr->code); -+ break; -+ } -+} -+ -+ -+static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, -+ union tls_event_data *data) -+{ -+ struct eap_sm *sm = ctx; -+ char *hash_hex = NULL; -+ char *cert_hex = NULL; -+ -+ switch (ev) { -+ case TLS_CERT_CHAIN_FAILURE: -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR -+ "reason=%d depth=%d subject='%s' err='%s'", -+ data->cert_fail.reason, -+ data->cert_fail.depth, -+ data->cert_fail.subject, -+ data->cert_fail.reason_txt); -+ break; -+ case TLS_PEER_CERTIFICATE: -+ if (data->peer_cert.hash) { -+ size_t len = data->peer_cert.hash_len * 2 + 1; -+ hash_hex = os_malloc(len); -+ if (hash_hex) { -+ wpa_snprintf_hex(hash_hex, len, -+ data->peer_cert.hash, -+ data->peer_cert.hash_len); -+ } -+ } -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT -+ "depth=%d subject='%s'%s%s", -+ data->peer_cert.depth, data->peer_cert.subject, -+ hash_hex ? " hash=" : "", hash_hex ? hash_hex : ""); -+ -+ if (data->peer_cert.cert) { -+ size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1; -+ cert_hex = os_malloc(len); -+ if (cert_hex == NULL) -+ break; -+ wpa_snprintf_hex(cert_hex, len, -+ wpabuf_head(data->peer_cert.cert), -+ wpabuf_len(data->peer_cert.cert)); -+ wpa_msg_ctrl(sm->msg_ctx, MSG_INFO, -+ WPA_EVENT_EAP_PEER_CERT -+ "depth=%d subject='%s' cert=%s", -+ data->peer_cert.depth, -+ data->peer_cert.subject, -+ cert_hex); -+ } -+ break; -+ } -+ -+ os_free(hash_hex); -+ os_free(cert_hex); -+} -+ -+ -+/** -+ * eap_peer_sm_init - Allocate and initialize EAP peer state machine -+ * @eapol_ctx: Context data to be used with eapol_cb calls -+ * @eapol_cb: Pointer to EAPOL callback functions -+ * @msg_ctx: Context data for wpa_msg() calls -+ * @conf: EAP configuration -+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure -+ * -+ * This function allocates and initializes an EAP state machine. In addition, -+ * this initializes TLS library for the new EAP state machine. eapol_cb pointer -+ * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP -+ * state machine. Consequently, the caller must make sure that this data -+ * structure remains alive while the EAP state machine is active. -+ */ -+struct eap_sm * eap_peer_sm_init(void *eapol_ctx, -+ struct eapol_callbacks *eapol_cb, -+ void *msg_ctx, struct eap_config *conf) -+{ -+ struct eap_sm *sm; -+ struct tls_config tlsconf; -+ -+ sm = os_zalloc(sizeof(*sm)); -+ if (sm == NULL) -+ return NULL; -+ sm->eapol_ctx = eapol_ctx; -+ sm->eapol_cb = eapol_cb; -+ sm->msg_ctx = msg_ctx; -+ sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT; -+ sm->wps = conf->wps; -+ -+ os_memset(&tlsconf, 0, sizeof(tlsconf)); -+ tlsconf.opensc_engine_path = conf->opensc_engine_path; -+ tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path; -+ tlsconf.pkcs11_module_path = conf->pkcs11_module_path; -+#ifdef CONFIG_FIPS -+ tlsconf.fips_mode = 1; -+#endif /* CONFIG_FIPS */ -+ tlsconf.event_cb = eap_peer_sm_tls_event; -+ tlsconf.cb_ctx = sm; -+ sm->ssl_ctx = tls_init(&tlsconf); -+ if (sm->ssl_ctx == NULL) { -+ wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS " -+ "context."); -+ os_free(sm); -+ return NULL; -+ } -+ -+ return sm; -+} -+ -+ -+/** -+ * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * This function deinitializes EAP state machine and frees all allocated -+ * resources. -+ */ -+void eap_peer_sm_deinit(struct eap_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ eap_deinit_prev_method(sm, "EAP deinit"); -+ eap_sm_abort(sm); -+ tls_deinit(sm->ssl_ctx); -+ os_free(sm); -+} -+ -+ -+/** -+ * eap_peer_sm_step - Step EAP peer state machine -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * Returns: 1 if EAP state was changed or 0 if not -+ * -+ * This function advances EAP state machine to a new state to match with the -+ * current variables. This should be called whenever variables used by the EAP -+ * state machine have changed. -+ */ -+int eap_peer_sm_step(struct eap_sm *sm) -+{ -+ int res = 0; -+ do { -+ sm->changed = FALSE; -+ SM_STEP_RUN(EAP); -+ if (sm->changed) -+ res = 1; -+ } while (sm->changed); -+ return res; -+} -+ -+ -+/** -+ * eap_sm_abort - Abort EAP authentication -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * Release system resources that have been allocated for the authentication -+ * session without fully deinitializing the EAP state machine. -+ */ -+void eap_sm_abort(struct eap_sm *sm) -+{ -+ wpabuf_free(sm->lastRespData); -+ sm->lastRespData = NULL; -+ wpabuf_free(sm->eapRespData); -+ sm->eapRespData = NULL; -+ os_free(sm->eapKeyData); -+ sm->eapKeyData = NULL; -+ -+ /* This is not clearly specified in the EAP statemachines draft, but -+ * it seems necessary to make sure that some of the EAPOL variables get -+ * cleared for the next authentication. */ -+ eapol_set_bool(sm, EAPOL_eapSuccess, FALSE); -+} -+ -+ -+#ifdef CONFIG_CTRL_IFACE -+static const char * eap_sm_state_txt(int state) -+{ -+ switch (state) { -+ case EAP_INITIALIZE: -+ return "INITIALIZE"; -+ case EAP_DISABLED: -+ return "DISABLED"; -+ case EAP_IDLE: -+ return "IDLE"; -+ case EAP_RECEIVED: -+ return "RECEIVED"; -+ case EAP_GET_METHOD: -+ return "GET_METHOD"; -+ case EAP_METHOD: -+ return "METHOD"; -+ case EAP_SEND_RESPONSE: -+ return "SEND_RESPONSE"; -+ case EAP_DISCARD: -+ return "DISCARD"; -+ case EAP_IDENTITY: -+ return "IDENTITY"; -+ case EAP_NOTIFICATION: -+ return "NOTIFICATION"; -+ case EAP_RETRANSMIT: -+ return "RETRANSMIT"; -+ case EAP_SUCCESS: -+ return "SUCCESS"; -+ case EAP_FAILURE: -+ return "FAILURE"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+#endif /* CONFIG_CTRL_IFACE */ -+ -+ -+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -+static const char * eap_sm_method_state_txt(EapMethodState state) -+{ -+ switch (state) { -+ case METHOD_NONE: -+ return "NONE"; -+ case METHOD_INIT: -+ return "INIT"; -+ case METHOD_CONT: -+ return "CONT"; -+ case METHOD_MAY_CONT: -+ return "MAY_CONT"; -+ case METHOD_DONE: -+ return "DONE"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+ -+static const char * eap_sm_decision_txt(EapDecision decision) -+{ -+ switch (decision) { -+ case DECISION_FAIL: -+ return "FAIL"; -+ case DECISION_COND_SUCC: -+ return "COND_SUCC"; -+ case DECISION_UNCOND_SUCC: -+ return "UNCOND_SUCC"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+#ifdef CONFIG_CTRL_IFACE -+ -+/** -+ * eap_sm_get_status - Get EAP state machine status -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @buf: Buffer for status information -+ * @buflen: Maximum buffer length -+ * @verbose: Whether to include verbose status information -+ * Returns: Number of bytes written to buf. -+ * -+ * Query EAP state machine for status information. This function fills in a -+ * text area with current status information from the EAPOL state machine. If -+ * the buffer (buf) is not large enough, status information will be truncated -+ * to fit the buffer. -+ */ -+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose) -+{ -+ int len, ret; -+ -+ if (sm == NULL) -+ return 0; -+ -+ len = os_snprintf(buf, buflen, -+ "EAP state=%s\n", -+ eap_sm_state_txt(sm->EAP_state)); -+ if (len < 0 || (size_t) len >= buflen) -+ return 0; -+ -+ if (sm->selectedMethod != EAP_TYPE_NONE) { -+ const char *name; -+ if (sm->m) { -+ name = sm->m->name; -+ } else { -+ const struct eap_method *m = -+ eap_peer_get_eap_method(EAP_VENDOR_IETF, -+ sm->selectedMethod); -+ if (m) -+ name = m->name; -+ else -+ name = "?"; -+ } -+ ret = os_snprintf(buf + len, buflen - len, -+ "selectedMethod=%d (EAP-%s)\n", -+ sm->selectedMethod, name); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ if (sm->m && sm->m->get_status) { -+ len += sm->m->get_status(sm, sm->eap_method_priv, -+ buf + len, buflen - len, -+ verbose); -+ } -+ } -+ -+ if (verbose) { -+ ret = os_snprintf(buf + len, buflen - len, -+ "reqMethod=%d\n" -+ "methodState=%s\n" -+ "decision=%s\n" -+ "ClientTimeout=%d\n", -+ sm->reqMethod, -+ eap_sm_method_state_txt(sm->methodState), -+ eap_sm_decision_txt(sm->decision), -+ sm->ClientTimeout); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ } -+ -+ return len; -+} -+#endif /* CONFIG_CTRL_IFACE */ -+ -+ -+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -+typedef enum { -+ TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD, -+ TYPE_PASSPHRASE -+} eap_ctrl_req_type; -+ -+static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type, -+ const char *msg, size_t msglen) -+{ -+ struct eap_peer_config *config; -+ char *field, *txt, *tmp; -+ -+ if (sm == NULL) -+ return; -+ config = eap_get_config(sm); -+ if (config == NULL) -+ return; -+ -+ switch (type) { -+ case TYPE_IDENTITY: -+ field = "IDENTITY"; -+ txt = "Identity"; -+ config->pending_req_identity++; -+ break; -+ case TYPE_PASSWORD: -+ field = "PASSWORD"; -+ txt = "Password"; -+ config->pending_req_password++; -+ break; -+ case TYPE_NEW_PASSWORD: -+ field = "NEW_PASSWORD"; -+ txt = "New Password"; -+ config->pending_req_new_password++; -+ break; -+ case TYPE_PIN: -+ field = "PIN"; -+ txt = "PIN"; -+ config->pending_req_pin++; -+ break; -+ case TYPE_OTP: -+ field = "OTP"; -+ if (msg) { -+ tmp = os_malloc(msglen + 3); -+ if (tmp == NULL) -+ return; -+ tmp[0] = '['; -+ os_memcpy(tmp + 1, msg, msglen); -+ tmp[msglen + 1] = ']'; -+ tmp[msglen + 2] = '\0'; -+ txt = tmp; -+ os_free(config->pending_req_otp); -+ config->pending_req_otp = tmp; -+ config->pending_req_otp_len = msglen + 3; -+ } else { -+ if (config->pending_req_otp == NULL) -+ return; -+ txt = config->pending_req_otp; -+ } -+ break; -+ case TYPE_PASSPHRASE: -+ field = "PASSPHRASE"; -+ txt = "Private key passphrase"; -+ config->pending_req_passphrase++; -+ break; -+ default: -+ return; -+ } -+ -+ if (sm->eapol_cb->eap_param_needed) -+ sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt); -+} -+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -+#define eap_sm_request(sm, type, msg, msglen) do { } while (0) -+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -+ -+const char * eap_sm_get_method_name(struct eap_sm *sm) -+{ -+ if (sm->m == NULL) -+ return "UNKNOWN"; -+ return sm->m->name; -+} -+ -+ -+/** -+ * eap_sm_request_identity - Request identity from user (ctrl_iface) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * EAP methods can call this function to request identity information for the -+ * current network. This is normally called when the identity is not included -+ * in the network configuration. The request will be sent to monitor programs -+ * through the control interface. -+ */ -+void eap_sm_request_identity(struct eap_sm *sm) -+{ -+ eap_sm_request(sm, TYPE_IDENTITY, NULL, 0); -+} -+ -+ -+/** -+ * eap_sm_request_password - Request password from user (ctrl_iface) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * EAP methods can call this function to request password information for the -+ * current network. This is normally called when the password is not included -+ * in the network configuration. The request will be sent to monitor programs -+ * through the control interface. -+ */ -+void eap_sm_request_password(struct eap_sm *sm) -+{ -+ eap_sm_request(sm, TYPE_PASSWORD, NULL, 0); -+} -+ -+ -+/** -+ * eap_sm_request_new_password - Request new password from user (ctrl_iface) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * EAP methods can call this function to request new password information for -+ * the current network. This is normally called when the EAP method indicates -+ * that the current password has expired and password change is required. The -+ * request will be sent to monitor programs through the control interface. -+ */ -+void eap_sm_request_new_password(struct eap_sm *sm) -+{ -+ eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0); -+} -+ -+ -+/** -+ * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * EAP methods can call this function to request SIM or smart card PIN -+ * information for the current network. This is normally called when the PIN is -+ * not included in the network configuration. The request will be sent to -+ * monitor programs through the control interface. -+ */ -+void eap_sm_request_pin(struct eap_sm *sm) -+{ -+ eap_sm_request(sm, TYPE_PIN, NULL, 0); -+} -+ -+ -+/** -+ * eap_sm_request_otp - Request one time password from user (ctrl_iface) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @msg: Message to be displayed to the user when asking for OTP -+ * @msg_len: Length of the user displayable message -+ * -+ * EAP methods can call this function to request open time password (OTP) for -+ * the current network. The request will be sent to monitor programs through -+ * the control interface. -+ */ -+void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len) -+{ -+ eap_sm_request(sm, TYPE_OTP, msg, msg_len); -+} -+ -+ -+/** -+ * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * EAP methods can call this function to request passphrase for a private key -+ * for the current network. This is normally called when the passphrase is not -+ * included in the network configuration. The request will be sent to monitor -+ * programs through the control interface. -+ */ -+void eap_sm_request_passphrase(struct eap_sm *sm) -+{ -+ eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0); -+} -+ -+ -+/** -+ * eap_sm_notify_ctrl_attached - Notification of attached monitor -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * Notify EAP state machines that a monitor was attached to the control -+ * interface to trigger re-sending of pending requests for user input. -+ */ -+void eap_sm_notify_ctrl_attached(struct eap_sm *sm) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ if (config == NULL) -+ return; -+ -+ /* Re-send any pending requests for user data since a new control -+ * interface was added. This handles cases where the EAP authentication -+ * starts immediately after system startup when the user interface is -+ * not yet running. */ -+ if (config->pending_req_identity) -+ eap_sm_request_identity(sm); -+ if (config->pending_req_password) -+ eap_sm_request_password(sm); -+ if (config->pending_req_new_password) -+ eap_sm_request_new_password(sm); -+ if (config->pending_req_otp) -+ eap_sm_request_otp(sm, NULL, 0); -+ if (config->pending_req_pin) -+ eap_sm_request_pin(sm); -+ if (config->pending_req_passphrase) -+ eap_sm_request_passphrase(sm); -+} -+ -+ -+static int eap_allowed_phase2_type(int vendor, int type) -+{ -+ if (vendor != EAP_VENDOR_IETF) -+ return 0; -+ return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS && -+ type != EAP_TYPE_FAST; -+} -+ -+ -+/** -+ * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name -+ * @name: EAP method name, e.g., MD5 -+ * @vendor: Buffer for returning EAP Vendor-Id -+ * Returns: EAP method type or %EAP_TYPE_NONE if not found -+ * -+ * This function maps EAP type names into EAP type numbers that are allowed for -+ * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with -+ * EAP-PEAP, EAP-TTLS, and EAP-FAST. -+ */ -+u32 eap_get_phase2_type(const char *name, int *vendor) -+{ -+ int v; -+ u8 type = eap_peer_get_type(name, &v); -+ if (eap_allowed_phase2_type(v, type)) { -+ *vendor = v; -+ return type; -+ } -+ *vendor = EAP_VENDOR_IETF; -+ return EAP_TYPE_NONE; -+} -+ -+ -+/** -+ * eap_get_phase2_types - Get list of allowed EAP phase 2 types -+ * @config: Pointer to a network configuration -+ * @count: Pointer to a variable to be filled with number of returned EAP types -+ * Returns: Pointer to allocated type list or %NULL on failure -+ * -+ * This function generates an array of allowed EAP phase 2 (tunneled) types for -+ * the given network configuration. -+ */ -+struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config, -+ size_t *count) -+{ -+ struct eap_method_type *buf; -+ u32 method; -+ int vendor; -+ size_t mcount; -+ const struct eap_method *methods, *m; -+ -+ methods = eap_peer_get_methods(&mcount); -+ if (methods == NULL) -+ return NULL; -+ *count = 0; -+ buf = os_malloc(mcount * sizeof(struct eap_method_type)); -+ if (buf == NULL) -+ return NULL; -+ -+ for (m = methods; m; m = m->next) { -+ vendor = m->vendor; -+ method = m->method; -+ if (eap_allowed_phase2_type(vendor, method)) { -+ if (vendor == EAP_VENDOR_IETF && -+ method == EAP_TYPE_TLS && config && -+ config->private_key2 == NULL) -+ continue; -+ buf[*count].vendor = vendor; -+ buf[*count].method = method; -+ (*count)++; -+ } -+ } -+ -+ return buf; -+} -+ -+ -+/** -+ * eap_set_fast_reauth - Update fast_reauth setting -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled -+ */ -+void eap_set_fast_reauth(struct eap_sm *sm, int enabled) -+{ -+ sm->fast_reauth = enabled; -+} -+ -+ -+/** -+ * eap_set_workaround - Update EAP workarounds setting -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds -+ */ -+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround) -+{ -+ sm->workaround = workaround; -+} -+ -+ -+/** -+ * eap_get_config - Get current network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * Returns: Pointer to the current network configuration or %NULL if not found -+ * -+ * EAP peer methods should avoid using this function if they can use other -+ * access functions, like eap_get_config_identity() and -+ * eap_get_config_password(), that do not require direct access to -+ * struct eap_peer_config. -+ */ -+struct eap_peer_config * eap_get_config(struct eap_sm *sm) -+{ -+ return sm->eapol_cb->get_config(sm->eapol_ctx); -+} -+ -+ -+/** -+ * eap_get_config_identity - Get identity from the network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @len: Buffer for the length of the identity -+ * Returns: Pointer to the identity or %NULL if not found -+ */ -+const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return NULL; -+ *len = config->identity_len; -+ return config->identity; -+} -+ -+ -+/** -+ * eap_get_config_password - Get password from the network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @len: Buffer for the length of the password -+ * Returns: Pointer to the password or %NULL if not found -+ */ -+const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return NULL; -+ *len = config->password_len; -+ return config->password; -+} -+ -+ -+/** -+ * eap_get_config_password2 - Get password from the network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @len: Buffer for the length of the password -+ * @hash: Buffer for returning whether the password is stored as a -+ * NtPasswordHash instead of plaintext password; can be %NULL if this -+ * information is not needed -+ * Returns: Pointer to the password or %NULL if not found -+ */ -+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return NULL; -+ *len = config->password_len; -+ if (hash) -+ *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH); -+ return config->password; -+} -+ -+ -+/** -+ * eap_get_config_new_password - Get new password from network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @len: Buffer for the length of the new password -+ * Returns: Pointer to the new password or %NULL if not found -+ */ -+const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return NULL; -+ *len = config->new_password_len; -+ return config->new_password; -+} -+ -+ -+/** -+ * eap_get_config_otp - Get one-time password from the network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @len: Buffer for the length of the one-time password -+ * Returns: Pointer to the one-time password or %NULL if not found -+ */ -+const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return NULL; -+ *len = config->otp_len; -+ return config->otp; -+} -+ -+ -+/** -+ * eap_clear_config_otp - Clear used one-time password -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * This function clears a used one-time password (OTP) from the current network -+ * configuration. This should be called when the OTP has been used and is not -+ * needed anymore. -+ */ -+void eap_clear_config_otp(struct eap_sm *sm) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return; -+ os_memset(config->otp, 0, config->otp_len); -+ os_free(config->otp); -+ config->otp = NULL; -+ config->otp_len = 0; -+} -+ -+ -+/** -+ * eap_get_config_phase1 - Get phase1 data from the network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * Returns: Pointer to the phase1 data or %NULL if not found -+ */ -+const char * eap_get_config_phase1(struct eap_sm *sm) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return NULL; -+ return config->phase1; -+} -+ -+ -+/** -+ * eap_get_config_phase2 - Get phase2 data from the network configuration -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * Returns: Pointer to the phase1 data or %NULL if not found -+ */ -+const char * eap_get_config_phase2(struct eap_sm *sm) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return NULL; -+ return config->phase2; -+} -+ -+ -+int eap_get_config_fragment_size(struct eap_sm *sm) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL) -+ return -1; -+ return config->fragment_size; -+} -+ -+ -+/** -+ * eap_key_available - Get key availability (eapKeyAvailable variable) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * Returns: 1 if EAP keying material is available, 0 if not -+ */ -+int eap_key_available(struct eap_sm *sm) -+{ -+ return sm ? sm->eapKeyAvailable : 0; -+} -+ -+ -+/** -+ * eap_notify_success - Notify EAP state machine about external success trigger -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * This function is called when external event, e.g., successful completion of -+ * WPA-PSK key handshake, is indicating that EAP state machine should move to -+ * success state. This is mainly used with security modes that do not use EAP -+ * state machine (e.g., WPA-PSK). -+ */ -+void eap_notify_success(struct eap_sm *sm) -+{ -+ if (sm) { -+ sm->decision = DECISION_COND_SUCC; -+ sm->EAP_state = EAP_SUCCESS; -+ } -+} -+ -+ -+/** -+ * eap_notify_lower_layer_success - Notification of lower layer success -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * Notify EAP state machines that a lower layer has detected a successful -+ * authentication. This is used to recover from dropped EAP-Success messages. -+ */ -+void eap_notify_lower_layer_success(struct eap_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ -+ if (eapol_get_bool(sm, EAPOL_eapSuccess) || -+ sm->decision == DECISION_FAIL || -+ (sm->methodState != METHOD_MAY_CONT && -+ sm->methodState != METHOD_DONE)) -+ return; -+ -+ if (sm->eapKeyData != NULL) -+ sm->eapKeyAvailable = TRUE; -+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE); -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS -+ "EAP authentication completed successfully (based on lower " -+ "layer success)"); -+} -+ -+ -+/** -+ * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @len: Pointer to variable that will be set to number of bytes in the key -+ * Returns: Pointer to the EAP keying data or %NULL on failure -+ * -+ * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The -+ * key is available only after a successful authentication. EAP state machine -+ * continues to manage the key data and the caller must not change or free the -+ * returned data. -+ */ -+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len) -+{ -+ if (sm == NULL || sm->eapKeyData == NULL) { -+ *len = 0; -+ return NULL; -+ } -+ -+ *len = sm->eapKeyDataLen; -+ return sm->eapKeyData; -+} -+ -+ -+/** -+ * eap_get_eapKeyData - Get EAP response data -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure -+ * -+ * Fetch EAP response (eapRespData) from the EAP state machine. This data is -+ * available when EAP state machine has processed an incoming EAP request. The -+ * EAP state machine does not maintain a reference to the response after this -+ * function is called and the caller is responsible for freeing the data. -+ */ -+struct wpabuf * eap_get_eapRespData(struct eap_sm *sm) -+{ -+ struct wpabuf *resp; -+ -+ if (sm == NULL || sm->eapRespData == NULL) -+ return NULL; -+ -+ resp = sm->eapRespData; -+ sm->eapRespData = NULL; -+ -+ return resp; -+} -+ -+ -+/** -+ * eap_sm_register_scard_ctx - Notification of smart card context -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @ctx: Context data for smart card operations -+ * -+ * Notify EAP state machines of context data for smart card operations. This -+ * context data will be used as a parameter for scard_*() functions. -+ */ -+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx) -+{ -+ if (sm) -+ sm->scard_ctx = ctx; -+} -+ -+ -+/** -+ * eap_set_config_blob - Set or add a named configuration blob -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @blob: New value for the blob -+ * -+ * Adds a new configuration blob or replaces the current value of an existing -+ * blob. -+ */ -+void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob) -+{ -+#ifndef CONFIG_NO_CONFIG_BLOBS -+ sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob); -+#endif /* CONFIG_NO_CONFIG_BLOBS */ -+} -+ -+ -+/** -+ * eap_get_config_blob - Get a named configuration blob -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @name: Name of the blob -+ * Returns: Pointer to blob data or %NULL if not found -+ */ -+const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, -+ const char *name) -+{ -+#ifndef CONFIG_NO_CONFIG_BLOBS -+ return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name); -+#else /* CONFIG_NO_CONFIG_BLOBS */ -+ return NULL; -+#endif /* CONFIG_NO_CONFIG_BLOBS */ -+} -+ -+ -+/** -+ * eap_set_force_disabled - Set force_disabled flag -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @disabled: 1 = EAP disabled, 0 = EAP enabled -+ * -+ * This function is used to force EAP state machine to be disabled when it is -+ * not in use (e.g., with WPA-PSK or plaintext connections). -+ */ -+void eap_set_force_disabled(struct eap_sm *sm, int disabled) -+{ -+ sm->force_disabled = disabled; -+} -+ -+ -+ /** -+ * eap_notify_pending - Notify that EAP method is ready to re-process a request -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * -+ * An EAP method can perform a pending operation (e.g., to get a response from -+ * an external process). Once the response is available, this function can be -+ * used to request EAPOL state machine to retry delivering the previously -+ * received (and still unanswered) EAP request to EAP state machine. -+ */ -+void eap_notify_pending(struct eap_sm *sm) -+{ -+ sm->eapol_cb->notify_pending(sm->eapol_ctx); -+} -+ -+ -+/** -+ * eap_invalidate_cached_session - Mark cached session data invalid -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ */ -+void eap_invalidate_cached_session(struct eap_sm *sm) -+{ -+ if (sm) -+ eap_deinit_prev_method(sm, "invalidate"); -+} -+ -+ -+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf) -+{ -+ if (conf->identity_len != WSC_ID_ENROLLEE_LEN || -+ os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)) -+ return 0; /* Not a WPS Enrollee */ -+ -+ if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL) -+ return 0; /* Not using PBC */ -+ -+ return 1; -+} -+ -+ -+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf) -+{ -+ if (conf->identity_len != WSC_ID_ENROLLEE_LEN || -+ os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)) -+ return 0; /* Not a WPS Enrollee */ -+ -+ if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL) -+ return 0; /* Not using PIN */ -+ -+ return 1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.h -new file mode 100644 -index 0000000000000..35509090c3656 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap.h -@@ -0,0 +1,292 @@ -+/* -+ * EAP peer state machine functions (RFC 4137) -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_H -+#define EAP_H -+ -+#include "common/defs.h" -+#include "eap_common/eap_defs.h" -+#include "eap_peer/eap_methods.h" -+ -+struct eap_sm; -+struct wpa_config_blob; -+struct wpabuf; -+ -+struct eap_method_type { -+ int vendor; -+ u32 method; -+}; -+ -+#ifdef IEEE8021X_EAPOL -+ -+/** -+ * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine -+ * -+ * These variables are used in the interface between EAP peer state machine and -+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is -+ * expected to maintain these variables and register a callback functions for -+ * EAP state machine to get and set the variables. -+ */ -+enum eapol_bool_var { -+ /** -+ * EAPOL_eapSuccess - EAP SUCCESS state reached -+ * -+ * EAP state machine reads and writes this value. -+ */ -+ EAPOL_eapSuccess, -+ -+ /** -+ * EAPOL_eapRestart - Lower layer request to restart authentication -+ * -+ * Set to TRUE in lower layer, FALSE in EAP state machine. -+ */ -+ EAPOL_eapRestart, -+ -+ /** -+ * EAPOL_eapFail - EAP FAILURE state reached -+ * -+ * EAP state machine writes this value. -+ */ -+ EAPOL_eapFail, -+ -+ /** -+ * EAPOL_eapResp - Response to send -+ * -+ * Set to TRUE in EAP state machine, FALSE in lower layer. -+ */ -+ EAPOL_eapResp, -+ -+ /** -+ * EAPOL_eapNoResp - Request has been process; no response to send -+ * -+ * Set to TRUE in EAP state machine, FALSE in lower layer. -+ */ -+ EAPOL_eapNoResp, -+ -+ /** -+ * EAPOL_eapReq - EAP request available from lower layer -+ * -+ * Set to TRUE in lower layer, FALSE in EAP state machine. -+ */ -+ EAPOL_eapReq, -+ -+ /** -+ * EAPOL_portEnabled - Lower layer is ready for communication -+ * -+ * EAP state machines reads this value. -+ */ -+ EAPOL_portEnabled, -+ -+ /** -+ * EAPOL_altAccept - Alternate indication of success (RFC3748) -+ * -+ * EAP state machines reads this value. -+ */ -+ EAPOL_altAccept, -+ -+ /** -+ * EAPOL_altReject - Alternate indication of failure (RFC3748) -+ * -+ * EAP state machines reads this value. -+ */ -+ EAPOL_altReject -+}; -+ -+/** -+ * enum eapol_int_var - EAPOL integer state variables for EAP state machine -+ * -+ * These variables are used in the interface between EAP peer state machine and -+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is -+ * expected to maintain these variables and register a callback functions for -+ * EAP state machine to get and set the variables. -+ */ -+enum eapol_int_var { -+ /** -+ * EAPOL_idleWhile - Outside time for EAP peer timeout -+ * -+ * This integer variable is used to provide an outside timer that the -+ * external (to EAP state machine) code must decrement by one every -+ * second until the value reaches zero. This is used in the same way as -+ * EAPOL state machine timers. EAP state machine reads and writes this -+ * value. -+ */ -+ EAPOL_idleWhile -+}; -+ -+/** -+ * struct eapol_callbacks - Callback functions from EAP to lower layer -+ * -+ * This structure defines the callback functions that EAP state machine -+ * requires from the lower layer (usually EAPOL state machine) for updating -+ * state variables and requesting information. eapol_ctx from -+ * eap_peer_sm_init() call will be used as the ctx parameter for these -+ * callback functions. -+ */ -+struct eapol_callbacks { -+ /** -+ * get_config - Get pointer to the current network configuration -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ */ -+ struct eap_peer_config * (*get_config)(void *ctx); -+ -+ /** -+ * get_bool - Get a boolean EAPOL state variable -+ * @variable: EAPOL boolean variable to get -+ * Returns: Value of the EAPOL variable -+ */ -+ Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable); -+ -+ /** -+ * set_bool - Set a boolean EAPOL state variable -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * @variable: EAPOL boolean variable to set -+ * @value: Value for the EAPOL variable -+ */ -+ void (*set_bool)(void *ctx, enum eapol_bool_var variable, -+ Boolean value); -+ -+ /** -+ * get_int - Get an integer EAPOL state variable -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * @variable: EAPOL integer variable to get -+ * Returns: Value of the EAPOL variable -+ */ -+ unsigned int (*get_int)(void *ctx, enum eapol_int_var variable); -+ -+ /** -+ * set_int - Set an integer EAPOL state variable -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * @variable: EAPOL integer variable to set -+ * @value: Value for the EAPOL variable -+ */ -+ void (*set_int)(void *ctx, enum eapol_int_var variable, -+ unsigned int value); -+ -+ /** -+ * get_eapReqData - Get EAP-Request data -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * @len: Pointer to variable that will be set to eapReqDataLen -+ * Returns: Reference to eapReqData (EAP state machine will not free -+ * this) or %NULL if eapReqData not available. -+ */ -+ struct wpabuf * (*get_eapReqData)(void *ctx); -+ -+ /** -+ * set_config_blob - Set named configuration blob -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * @blob: New value for the blob -+ * -+ * Adds a new configuration blob or replaces the current value of an -+ * existing blob. -+ */ -+ void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); -+ -+ /** -+ * get_config_blob - Get a named configuration blob -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * @name: Name of the blob -+ * Returns: Pointer to blob data or %NULL if not found -+ */ -+ const struct wpa_config_blob * (*get_config_blob)(void *ctx, -+ const char *name); -+ -+ /** -+ * notify_pending - Notify that a pending request can be retried -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * -+ * An EAP method can perform a pending operation (e.g., to get a -+ * response from an external process). Once the response is available, -+ * this callback function can be used to request EAPOL state machine to -+ * retry delivering the previously received (and still unanswered) EAP -+ * request to EAP state machine. -+ */ -+ void (*notify_pending)(void *ctx); -+ -+ /** -+ * eap_param_needed - Notify that EAP parameter is needed -+ * @ctx: eapol_ctx from eap_peer_sm_init() call -+ * @field: Field name (e.g., "IDENTITY") -+ * @txt: User readable text describing the required parameter -+ */ -+ void (*eap_param_needed)(void *ctx, const char *field, -+ const char *txt); -+}; -+ -+/** -+ * struct eap_config - Configuration for EAP state machine -+ */ -+struct eap_config { -+ /** -+ * opensc_engine_path - OpenSC engine for OpenSSL engine support -+ * -+ * Usually, path to engine_opensc.so. -+ */ -+ const char *opensc_engine_path; -+ /** -+ * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support -+ * -+ * Usually, path to engine_pkcs11.so. -+ */ -+ const char *pkcs11_engine_path; -+ /** -+ * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine -+ * -+ * Usually, path to opensc-pkcs11.so. -+ */ -+ const char *pkcs11_module_path; -+ /** -+ * wps - WPS context data -+ * -+ * This is only used by EAP-WSC and can be left %NULL if not available. -+ */ -+ struct wps_context *wps; -+}; -+ -+struct eap_sm * eap_peer_sm_init(void *eapol_ctx, -+ struct eapol_callbacks *eapol_cb, -+ void *msg_ctx, struct eap_config *conf); -+void eap_peer_sm_deinit(struct eap_sm *sm); -+int eap_peer_sm_step(struct eap_sm *sm); -+void eap_sm_abort(struct eap_sm *sm); -+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, -+ int verbose); -+const char * eap_sm_get_method_name(struct eap_sm *sm); -+struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted); -+void eap_sm_request_identity(struct eap_sm *sm); -+void eap_sm_request_password(struct eap_sm *sm); -+void eap_sm_request_new_password(struct eap_sm *sm); -+void eap_sm_request_pin(struct eap_sm *sm); -+void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len); -+void eap_sm_request_passphrase(struct eap_sm *sm); -+void eap_sm_notify_ctrl_attached(struct eap_sm *sm); -+u32 eap_get_phase2_type(const char *name, int *vendor); -+struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config, -+ size_t *count); -+void eap_set_fast_reauth(struct eap_sm *sm, int enabled); -+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround); -+void eap_set_force_disabled(struct eap_sm *sm, int disabled); -+int eap_key_available(struct eap_sm *sm); -+void eap_notify_success(struct eap_sm *sm); -+void eap_notify_lower_layer_success(struct eap_sm *sm); -+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); -+struct wpabuf * eap_get_eapRespData(struct eap_sm *sm); -+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx); -+void eap_invalidate_cached_session(struct eap_sm *sm); -+ -+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf); -+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf); -+ -+#endif /* IEEE8021X_EAPOL */ -+ -+#endif /* EAP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_aka.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_aka.c -new file mode 100644 -index 0000000000000..182f01a5e60ad ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_aka.c -@@ -0,0 +1,1389 @@ -+/* -+ * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "pcsc_funcs.h" -+#include "crypto/crypto.h" -+#include "crypto/sha1.h" -+#include "crypto/sha256.h" -+#include "crypto/milenage.h" -+#include "eap_common/eap_sim_common.h" -+#include "eap_config.h" -+#include "eap_i.h" -+ -+ -+struct eap_aka_data { -+ u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN]; -+ size_t res_len; -+ u8 nonce_s[EAP_SIM_NONCE_S_LEN]; -+ u8 mk[EAP_SIM_MK_LEN]; -+ u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; -+ u8 k_encr[EAP_SIM_K_ENCR_LEN]; -+ u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */ -+ u8 msk[EAP_SIM_KEYING_DATA_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN]; -+ u8 auts[EAP_AKA_AUTS_LEN]; -+ -+ int num_id_req, num_notification; -+ u8 *pseudonym; -+ size_t pseudonym_len; -+ u8 *reauth_id; -+ size_t reauth_id_len; -+ int reauth; -+ unsigned int counter, counter_too_small; -+ u8 *last_eap_identity; -+ size_t last_eap_identity_len; -+ enum { -+ CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE -+ } state; -+ -+ struct wpabuf *id_msgs; -+ int prev_id; -+ int result_ind, use_result_ind; -+ u8 eap_method; -+ u8 *network_name; -+ size_t network_name_len; -+ u16 kdf; -+ int kdf_negotiation; -+}; -+ -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+static const char * eap_aka_state_txt(int state) -+{ -+ switch (state) { -+ case CONTINUE: -+ return "CONTINUE"; -+ case RESULT_SUCCESS: -+ return "RESULT_SUCCESS"; -+ case RESULT_FAILURE: -+ return "RESULT_FAILURE"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "?"; -+ } -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+static void eap_aka_state(struct eap_aka_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", -+ eap_aka_state_txt(data->state), -+ eap_aka_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_aka_init(struct eap_sm *sm) -+{ -+ struct eap_aka_data *data; -+ const char *phase1 = eap_get_config_phase1(sm); -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ data->eap_method = EAP_TYPE_AKA; -+ -+ eap_aka_state(data, CONTINUE); -+ data->prev_id = -1; -+ -+ data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL; -+ -+ return data; -+} -+ -+ -+#ifdef EAP_AKA_PRIME -+static void * eap_aka_prime_init(struct eap_sm *sm) -+{ -+ struct eap_aka_data *data = eap_aka_init(sm); -+ if (data == NULL) -+ return NULL; -+ data->eap_method = EAP_TYPE_AKA_PRIME; -+ return data; -+} -+#endif /* EAP_AKA_PRIME */ -+ -+ -+static void eap_aka_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ if (data) { -+ os_free(data->pseudonym); -+ os_free(data->reauth_id); -+ os_free(data->last_eap_identity); -+ wpabuf_free(data->id_msgs); -+ os_free(data->network_name); -+ os_free(data); -+ } -+} -+ -+ -+static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data) -+{ -+ struct eap_peer_config *conf; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: UMTS authentication algorithm"); -+ -+ conf = eap_get_config(sm); -+ if (conf == NULL) -+ return -1; -+ if (conf->pcsc) { -+ return scard_umts_auth(sm->scard_ctx, data->rand, -+ data->autn, data->res, &data->res_len, -+ data->ik, data->ck, data->auts); -+ } -+ -+#ifdef CONFIG_USIM_SIMULATOR -+ if (conf->password) { -+ u8 opc[16], k[16], sqn[6]; -+ const char *pos; -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Use internal Milenage " -+ "implementation for UMTS authentication"); -+ if (conf->password_len < 78) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: invalid Milenage " -+ "password"); -+ return -1; -+ } -+ pos = (const char *) conf->password; -+ if (hexstr2bin(pos, k, 16)) -+ return -1; -+ pos += 32; -+ if (*pos != ':') -+ return -1; -+ pos++; -+ -+ if (hexstr2bin(pos, opc, 16)) -+ return -1; -+ pos += 32; -+ if (*pos != ':') -+ return -1; -+ pos++; -+ -+ if (hexstr2bin(pos, sqn, 6)) -+ return -1; -+ -+ return milenage_check(opc, k, sqn, data->rand, data->autn, -+ data->ik, data->ck, -+ data->res, &data->res_len, data->auts); -+ } -+#endif /* CONFIG_USIM_SIMULATOR */ -+ -+#ifdef CONFIG_USIM_HARDCODED -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Use hardcoded Kc and SRES values for " -+ "testing"); -+ -+ /* These hardcoded Kc and SRES values are used for testing. -+ * Could consider making them configurable. */ -+ os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN); -+ data->res_len = EAP_AKA_RES_MAX_LEN; -+ os_memset(data->ik, '3', EAP_AKA_IK_LEN); -+ os_memset(data->ck, '4', EAP_AKA_CK_LEN); -+ { -+ u8 autn[EAP_AKA_AUTN_LEN]; -+ os_memset(autn, '1', EAP_AKA_AUTN_LEN); -+ if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match " -+ "with expected value"); -+ return -1; -+ } -+ } -+#if 0 -+ { -+ static int test_resync = 1; -+ if (test_resync) { -+ /* Test Resynchronization */ -+ test_resync = 0; -+ return -2; -+ } -+ } -+#endif -+ return 0; -+ -+#else /* CONFIG_USIM_HARDCODED */ -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: No UMTS authentication algorith " -+ "enabled"); -+ return -1; -+ -+#endif /* CONFIG_USIM_HARDCODED */ -+} -+ -+ -+#define CLEAR_PSEUDONYM 0x01 -+#define CLEAR_REAUTH_ID 0x02 -+#define CLEAR_EAP_ID 0x04 -+ -+static void eap_aka_clear_identities(struct eap_aka_data *data, int id) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s", -+ id & CLEAR_PSEUDONYM ? " pseudonym" : "", -+ id & CLEAR_REAUTH_ID ? " reauth_id" : "", -+ id & CLEAR_EAP_ID ? " eap_id" : ""); -+ if (id & CLEAR_PSEUDONYM) { -+ os_free(data->pseudonym); -+ data->pseudonym = NULL; -+ data->pseudonym_len = 0; -+ } -+ if (id & CLEAR_REAUTH_ID) { -+ os_free(data->reauth_id); -+ data->reauth_id = NULL; -+ data->reauth_id_len = 0; -+ } -+ if (id & CLEAR_EAP_ID) { -+ os_free(data->last_eap_identity); -+ data->last_eap_identity = NULL; -+ data->last_eap_identity_len = 0; -+ } -+} -+ -+ -+static int eap_aka_learn_ids(struct eap_aka_data *data, -+ struct eap_sim_attrs *attr) -+{ -+ if (attr->next_pseudonym) { -+ os_free(data->pseudonym); -+ data->pseudonym = os_malloc(attr->next_pseudonym_len); -+ if (data->pseudonym == NULL) { -+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for " -+ "next pseudonym"); -+ return -1; -+ } -+ os_memcpy(data->pseudonym, attr->next_pseudonym, -+ attr->next_pseudonym_len); -+ data->pseudonym_len = attr->next_pseudonym_len; -+ wpa_hexdump_ascii(MSG_DEBUG, -+ "EAP-AKA: (encr) AT_NEXT_PSEUDONYM", -+ data->pseudonym, -+ data->pseudonym_len); -+ } -+ -+ if (attr->next_reauth_id) { -+ os_free(data->reauth_id); -+ data->reauth_id = os_malloc(attr->next_reauth_id_len); -+ if (data->reauth_id == NULL) { -+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for " -+ "next reauth_id"); -+ return -1; -+ } -+ os_memcpy(data->reauth_id, attr->next_reauth_id, -+ attr->next_reauth_id_len); -+ data->reauth_id_len = attr->next_reauth_id_len; -+ wpa_hexdump_ascii(MSG_DEBUG, -+ "EAP-AKA: (encr) AT_NEXT_REAUTH_ID", -+ data->reauth_id, -+ data->reauth_id_len); -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_aka_add_id_msg(struct eap_aka_data *data, -+ const struct wpabuf *msg) -+{ -+ if (msg == NULL) -+ return -1; -+ -+ if (data->id_msgs == NULL) { -+ data->id_msgs = wpabuf_dup(msg); -+ return data->id_msgs == NULL ? -1 : 0; -+ } -+ -+ if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) -+ return -1; -+ wpabuf_put_buf(data->id_msgs, msg); -+ -+ return 0; -+} -+ -+ -+static void eap_aka_add_checkcode(struct eap_aka_data *data, -+ struct eap_sim_msg *msg) -+{ -+ const u8 *addr; -+ size_t len; -+ u8 hash[SHA256_MAC_LEN]; -+ -+ wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); -+ -+ if (data->id_msgs == NULL) { -+ /* -+ * No EAP-AKA/Identity packets were exchanged - send empty -+ * checkcode. -+ */ -+ eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); -+ return; -+ } -+ -+ /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */ -+ addr = wpabuf_head(data->id_msgs); -+ len = wpabuf_len(data->id_msgs); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len); -+#ifdef EAP_AKA_PRIME -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) -+ sha256_vector(1, &addr, &len, hash); -+ else -+#endif /* EAP_AKA_PRIME */ -+ sha1_vector(1, &addr, &len, hash); -+ -+ eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash, -+ data->eap_method == EAP_TYPE_AKA_PRIME ? -+ EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN); -+} -+ -+ -+static int eap_aka_verify_checkcode(struct eap_aka_data *data, -+ const u8 *checkcode, size_t checkcode_len) -+{ -+ const u8 *addr; -+ size_t len; -+ u8 hash[SHA256_MAC_LEN]; -+ size_t hash_len; -+ -+ if (checkcode == NULL) -+ return -1; -+ -+ if (data->id_msgs == NULL) { -+ if (checkcode_len != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server " -+ "indicates that AKA/Identity messages were " -+ "used, but they were not"); -+ return -1; -+ } -+ return 0; -+ } -+ -+ hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ? -+ EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN; -+ -+ if (checkcode_len != hash_len) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server " -+ "indicates that AKA/Identity message were not " -+ "used, but they were"); -+ return -1; -+ } -+ -+ /* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */ -+ addr = wpabuf_head(data->id_msgs); -+ len = wpabuf_len(data->id_msgs); -+#ifdef EAP_AKA_PRIME -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) -+ sha256_vector(1, &addr, &len, hash); -+ else -+#endif /* EAP_AKA_PRIME */ -+ sha1_vector(1, &addr, &len, hash); -+ -+ if (os_memcmp(hash, checkcode, hash_len) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id, -+ int err) -+{ -+ struct eap_sim_msg *msg; -+ -+ eap_aka_state(data, FAILURE); -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_CLIENT_ERROR); -+ eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0); -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data, -+ u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ eap_aka_state(data, FAILURE); -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject " -+ "(id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT); -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_synchronization_failure( -+ struct eap_aka_data *data, u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure " -+ "(id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE); -+ wpa_printf(MSG_DEBUG, " AT_AUTS"); -+ eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, -+ EAP_AKA_AUTS_LEN); -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ u8 id, -+ enum eap_sim_id_req id_req) -+{ -+ const u8 *identity = NULL; -+ size_t identity_len = 0; -+ struct eap_sim_msg *msg; -+ -+ data->reauth = 0; -+ if (id_req == ANY_ID && data->reauth_id) { -+ identity = data->reauth_id; -+ identity_len = data->reauth_id_len; -+ data->reauth = 1; -+ } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) && -+ data->pseudonym) { -+ identity = data->pseudonym; -+ identity_len = data->pseudonym_len; -+ eap_aka_clear_identities(data, CLEAR_REAUTH_ID); -+ } else if (id_req != NO_ID_REQ) { -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity) { -+ eap_aka_clear_identities(data, CLEAR_PSEUDONYM | -+ CLEAR_REAUTH_ID); -+ } -+ } -+ if (id_req != NO_ID_REQ) -+ eap_aka_clear_identities(data, CLEAR_EAP_ID); -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_IDENTITY); -+ -+ if (identity) { -+ wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY", -+ identity, identity_len); -+ eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, -+ identity, identity_len); -+ } -+ -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data, -+ u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_CHALLENGE); -+ wpa_printf(MSG_DEBUG, " AT_RES"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8, -+ data->res, data->res_len); -+ eap_aka_add_checkcode(data, msg); -+ if (data->use_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0); -+} -+ -+ -+static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data, -+ u8 id, int counter_too_small, -+ const u8 *nonce_s) -+{ -+ struct eap_sim_msg *msg; -+ unsigned int counter; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)", -+ id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_REAUTHENTICATION); -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); -+ -+ if (counter_too_small) { -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0); -+ counter = data->counter_too_small; -+ } else -+ counter = data->counter; -+ -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); -+ -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " -+ "AT_ENCR_DATA"); -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ eap_aka_add_checkcode(data, msg); -+ if (data->use_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, nonce_s, -+ EAP_SIM_NONCE_S_LEN); -+} -+ -+ -+static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data, -+ u8 id, u16 notification) -+{ -+ struct eap_sim_msg *msg; -+ u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_NOTIFICATION); -+ if (k_aut && data->reauth) { -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, -+ EAP_SIM_AT_ENCR_DATA); -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, -+ NULL, 0); -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, -+ EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " -+ "AT_ENCR_DATA"); -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ } -+ if (k_aut) { -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ } -+ return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0); -+} -+ -+ -+static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ u8 id, -+ const struct wpabuf *reqData, -+ struct eap_sim_attrs *attr) -+{ -+ int id_error; -+ struct wpabuf *buf; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Identity"); -+ -+ id_error = 0; -+ switch (attr->id_req) { -+ case NO_ID_REQ: -+ break; -+ case ANY_ID: -+ if (data->num_id_req > 0) -+ id_error++; -+ data->num_id_req++; -+ break; -+ case FULLAUTH_ID: -+ if (data->num_id_req > 1) -+ id_error++; -+ data->num_id_req++; -+ break; -+ case PERMANENT_ID: -+ if (data->num_id_req > 2) -+ id_error++; -+ data->num_id_req++; -+ break; -+ } -+ if (id_error) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests " -+ "used within one authentication"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ buf = eap_aka_response_identity(sm, data, id, attr->id_req); -+ -+ if (data->prev_id != id) { -+ eap_aka_add_id_msg(data, reqData); -+ eap_aka_add_id_msg(data, buf); -+ data->prev_id = id; -+ } -+ -+ return buf; -+} -+ -+ -+static int eap_aka_verify_mac(struct eap_aka_data *data, -+ const struct wpabuf *req, -+ const u8 *mac, const u8 *extra, -+ size_t extra_len) -+{ -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) -+ return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, -+ extra_len); -+ return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); -+} -+ -+ -+#ifdef EAP_AKA_PRIME -+static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data, -+ u8 id, u16 kdf) -+{ -+ struct eap_sim_msg *msg; -+ -+ data->kdf_negotiation = 1; -+ data->kdf = kdf; -+ wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF " -+ "select)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, -+ EAP_AKA_SUBTYPE_CHALLENGE); -+ wpa_printf(MSG_DEBUG, " AT_KDF"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0); -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data, -+ u8 id, struct eap_sim_attrs *attr) -+{ -+ size_t i; -+ -+ for (i = 0; i < attr->kdf_count; i++) { -+ if (attr->kdf[i] == EAP_AKA_PRIME_KDF) -+ return eap_aka_prime_kdf_select(data, id, -+ EAP_AKA_PRIME_KDF); -+ } -+ -+ /* No matching KDF found - fail authentication as if AUTN had been -+ * incorrect */ -+ return eap_aka_authentication_reject(data, id); -+} -+ -+ -+static int eap_aka_prime_kdf_valid(struct eap_aka_data *data, -+ struct eap_sim_attrs *attr) -+{ -+ size_t i, j; -+ -+ if (attr->kdf_count == 0) -+ return 0; -+ -+ /* The only allowed (and required) duplication of a KDF is the addition -+ * of the selected KDF into the beginning of the list. */ -+ -+ if (data->kdf_negotiation) { -+ if (attr->kdf[0] != data->kdf) { -+ wpa_printf(MSG_WARNING, "EAP-AKA': The server did not " -+ "accept the selected KDF"); -+ return 0; -+ } -+ -+ for (i = 1; i < attr->kdf_count; i++) { -+ if (attr->kdf[i] == data->kdf) -+ break; -+ } -+ if (i == attr->kdf_count && -+ attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) { -+ wpa_printf(MSG_WARNING, "EAP-AKA': The server did not " -+ "duplicate the selected KDF"); -+ return 0; -+ } -+ -+ /* TODO: should check that the list is identical to the one -+ * used in the previous Challenge message apart from the added -+ * entry in the beginning. */ -+ } -+ -+ for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) { -+ for (j = i + 1; j < attr->kdf_count; j++) { -+ if (attr->kdf[i] == attr->kdf[j]) { -+ wpa_printf(MSG_WARNING, "EAP-AKA': The server " -+ "included a duplicated KDF"); -+ return 0; -+ } -+ } -+ } -+ -+ return 1; -+} -+#endif /* EAP_AKA_PRIME */ -+ -+ -+static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ u8 id, -+ const struct wpabuf *reqData, -+ struct eap_sim_attrs *attr) -+{ -+ const u8 *identity; -+ size_t identity_len; -+ int res; -+ struct eap_sim_attrs eattr; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Challenge"); -+ -+ if (attr->checkcode && -+ eap_aka_verify_checkcode(data, attr->checkcode, -+ attr->checkcode_len)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " -+ "message"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+#ifdef EAP_AKA_PRIME -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ if (!attr->kdf_input || attr->kdf_input_len == 0) { -+ wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message " -+ "did not include non-empty AT_KDF_INPUT"); -+ /* Fail authentication as if AUTN had been incorrect */ -+ return eap_aka_authentication_reject(data, id); -+ } -+ os_free(data->network_name); -+ data->network_name = os_malloc(attr->kdf_input_len); -+ if (data->network_name == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA': No memory for " -+ "storing Network Name"); -+ return eap_aka_authentication_reject(data, id); -+ } -+ os_memcpy(data->network_name, attr->kdf_input, -+ attr->kdf_input_len); -+ data->network_name_len = attr->kdf_input_len; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name " -+ "(AT_KDF_INPUT)", -+ data->network_name, data->network_name_len); -+ /* TODO: check Network Name per 3GPP.33.402 */ -+ -+ if (!eap_aka_prime_kdf_valid(data, attr)) -+ return eap_aka_authentication_reject(data, id); -+ -+ if (attr->kdf[0] != EAP_AKA_PRIME_KDF) -+ return eap_aka_prime_kdf_neg(data, id, attr); -+ -+ data->kdf = EAP_AKA_PRIME_KDF; -+ wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); -+ } -+ -+ if (data->eap_method == EAP_TYPE_AKA && attr->bidding) { -+ u16 flags = WPA_GET_BE16(attr->bidding); -+ if ((flags & EAP_AKA_BIDDING_FLAG_D) && -+ eap_allowed_method(sm, EAP_VENDOR_IETF, -+ EAP_TYPE_AKA_PRIME)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from " -+ "AKA' to AKA detected"); -+ /* Fail authentication as if AUTN had been incorrect */ -+ return eap_aka_authentication_reject(data, id); -+ } -+ } -+#endif /* EAP_AKA_PRIME */ -+ -+ data->reauth = 0; -+ if (!attr->mac || !attr->rand || !attr->autn) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " -+ "did not include%s%s%s", -+ !attr->mac ? " AT_MAC" : "", -+ !attr->rand ? " AT_RAND" : "", -+ !attr->autn ? " AT_AUTN" : ""); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN); -+ os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN); -+ -+ res = eap_aka_umts_auth(sm, data); -+ if (res == -1) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication " -+ "failed (AUTN)"); -+ return eap_aka_authentication_reject(data, id); -+ } else if (res == -2) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication " -+ "failed (AUTN seq# -> AUTS)"); -+ return eap_aka_synchronization_failure(data, id); -+ } else if (res) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+#ifdef EAP_AKA_PRIME -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the -+ * needed 6-octet SQN ^ AK for CK',IK' derivation */ -+ u16 amf = WPA_GET_BE16(data->autn + 6); -+ if (!(amf & 0x8000)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA': AMF separation bit " -+ "not set (AMF=0x%4x)", amf); -+ return eap_aka_authentication_reject(data, id); -+ } -+ eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, -+ data->autn, -+ data->network_name, -+ data->network_name_len); -+ } -+#endif /* EAP_AKA_PRIME */ -+ if (data->last_eap_identity) { -+ identity = data->last_eap_identity; -+ identity_len = data->last_eap_identity_len; -+ } else if (data->pseudonym) { -+ identity = data->pseudonym; -+ identity_len = data->pseudonym_len; -+ } else -+ identity = eap_get_config_identity(sm, &identity_len); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK " -+ "derivation", identity, identity_len); -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ eap_aka_prime_derive_keys(identity, identity_len, data->ik, -+ data->ck, data->k_encr, data->k_aut, -+ data->k_re, data->msk, data->emsk); -+ } else { -+ eap_aka_derive_mk(identity, identity_len, data->ik, data->ck, -+ data->mk); -+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, -+ data->msk, data->emsk); -+ } -+ if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " -+ "used invalid AT_MAC"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ /* Old reauthentication and pseudonym identities must not be used -+ * anymore. In other words, if no new identities are received, full -+ * authentication will be used on next reauthentication. */ -+ eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID | -+ CLEAR_EAP_ID); -+ -+ if (attr->encr_data) { -+ u8 *decrypted; -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, -+ &eattr, 0); -+ if (decrypted == NULL) { -+ return eap_aka_client_error( -+ data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ eap_aka_learn_ids(data, &eattr); -+ os_free(decrypted); -+ } -+ -+ if (data->result_ind && attr->result_ind) -+ data->use_result_ind = 1; -+ -+ if (data->state != FAILURE && data->state != RESULT_FAILURE) { -+ eap_aka_state(data, data->use_result_ind ? -+ RESULT_SUCCESS : SUCCESS); -+ } -+ -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ /* RFC 4187 specifies that counter is initialized to one after -+ * fullauth, but initializing it to zero makes it easier to implement -+ * reauth verification. */ -+ data->counter = 0; -+ return eap_aka_response_challenge(data, id); -+} -+ -+ -+static int eap_aka_process_notification_reauth(struct eap_aka_data *data, -+ struct eap_sim_attrs *attr) -+{ -+ struct eap_sim_attrs eattr; -+ u8 *decrypted; -+ -+ if (attr->encr_data == NULL || attr->iv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after " -+ "reauth did not include encrypted data"); -+ return -1; -+ } -+ -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, &eattr, -+ 0); -+ if (decrypted == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " -+ "data from notification message"); -+ return -1; -+ } -+ -+ if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification " -+ "message does not match with counter in reauth " -+ "message"); -+ os_free(decrypted); -+ return -1; -+ } -+ -+ os_free(decrypted); -+ return 0; -+} -+ -+ -+static int eap_aka_process_notification_auth(struct eap_aka_data *data, -+ const struct wpabuf *reqData, -+ struct eap_sim_attrs *attr) -+{ -+ if (attr->mac == NULL) { -+ wpa_printf(MSG_INFO, "EAP-AKA: no AT_MAC in after_auth " -+ "Notification message"); -+ return -1; -+ } -+ -+ if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Notification message " -+ "used invalid AT_MAC"); -+ return -1; -+ } -+ -+ if (data->reauth && -+ eap_aka_process_notification_reauth(data, attr)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification " -+ "message after reauth"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_aka_process_notification( -+ struct eap_sm *sm, struct eap_aka_data *data, u8 id, -+ const struct wpabuf *reqData, struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Notification"); -+ if (data->num_notification > 0) { -+ wpa_printf(MSG_INFO, "EAP-AKA: too many notification " -+ "rounds (only one allowed)"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ data->num_notification++; -+ if (attr->notification == -1) { -+ wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in " -+ "Notification message"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if ((attr->notification & 0x4000) == 0 && -+ eap_aka_process_notification_auth(data, reqData, attr)) { -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ eap_sim_report_notification(sm->msg_ctx, attr->notification, 1); -+ if (attr->notification >= 0 && attr->notification < 32768) { -+ eap_aka_state(data, FAILURE); -+ } else if (attr->notification == EAP_SIM_SUCCESS && -+ data->state == RESULT_SUCCESS) -+ eap_aka_state(data, SUCCESS); -+ return eap_aka_response_notification(data, id, attr->notification); -+} -+ -+ -+static struct wpabuf * eap_aka_process_reauthentication( -+ struct eap_sm *sm, struct eap_aka_data *data, u8 id, -+ const struct wpabuf *reqData, struct eap_sim_attrs *attr) -+{ -+ struct eap_sim_attrs eattr; -+ u8 *decrypted; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication"); -+ -+ if (attr->checkcode && -+ eap_aka_verify_checkcode(data, attr->checkcode, -+ attr->checkcode_len)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " -+ "message"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if (data->reauth_id == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying " -+ "reauthentication, but no reauth_id available"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ data->reauth = 1; -+ if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " -+ "did not have valid AT_MAC"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if (attr->encr_data == NULL || attr->iv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " -+ "message did not include encrypted data"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, &eattr, -+ 0); -+ if (decrypted == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " -+ "data from reauthentication message"); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if (eattr.nonce_s == NULL || eattr.counter < 0) { -+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet", -+ !eattr.nonce_s ? " AT_NONCE_S" : "", -+ eattr.counter < 0 ? " AT_COUNTER" : ""); -+ os_free(decrypted); -+ return eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { -+ struct wpabuf *res; -+ wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter " -+ "(%d <= %d)", eattr.counter, data->counter); -+ data->counter_too_small = eattr.counter; -+ -+ /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current -+ * reauth_id must not be used to start a new reauthentication. -+ * However, since it was used in the last EAP-Response-Identity -+ * packet, it has to saved for the following fullauth to be -+ * used in MK derivation. */ -+ os_free(data->last_eap_identity); -+ data->last_eap_identity = data->reauth_id; -+ data->last_eap_identity_len = data->reauth_id_len; -+ data->reauth_id = NULL; -+ data->reauth_id_len = 0; -+ -+ res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s); -+ os_free(decrypted); -+ -+ return res; -+ } -+ data->counter = eattr.counter; -+ -+ os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S", -+ data->nonce_s, EAP_SIM_NONCE_S_LEN); -+ -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, -+ data->reauth_id, -+ data->reauth_id_len, -+ data->nonce_s, -+ data->msk, data->emsk); -+ } else { -+ eap_sim_derive_keys_reauth(data->counter, data->reauth_id, -+ data->reauth_id_len, -+ data->nonce_s, data->mk, -+ data->msk, data->emsk); -+ } -+ eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); -+ eap_aka_learn_ids(data, &eattr); -+ -+ if (data->result_ind && attr->result_ind) -+ data->use_result_ind = 1; -+ -+ if (data->state != FAILURE && data->state != RESULT_FAILURE) { -+ eap_aka_state(data, data->use_result_ind ? -+ RESULT_SUCCESS : SUCCESS); -+ } -+ -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of " -+ "fast reauths performed - force fullauth"); -+ eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); -+ } -+ os_free(decrypted); -+ return eap_aka_response_reauth(data, id, 0, data->nonce_s); -+} -+ -+ -+static struct wpabuf * eap_aka_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_aka_data *data = priv; -+ const struct eap_hdr *req; -+ u8 subtype, id; -+ struct wpabuf *res; -+ const u8 *pos; -+ struct eap_sim_attrs attr; -+ size_t len; -+ -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-AKA: EAP data", reqData); -+ if (eap_get_config_identity(sm, &len) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured"); -+ eap_sm_request_identity(sm); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData, -+ &len); -+ if (pos == NULL || len < 1) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ req = wpabuf_head(reqData); -+ id = req->identifier; -+ len = be_to_host16(req->length); -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = TRUE; -+ -+ subtype = *pos++; -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype); -+ pos += 2; /* Reserved */ -+ -+ if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, -+ data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, -+ 0)) { -+ res = eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ goto done; -+ } -+ -+ switch (subtype) { -+ case EAP_AKA_SUBTYPE_IDENTITY: -+ res = eap_aka_process_identity(sm, data, id, reqData, &attr); -+ break; -+ case EAP_AKA_SUBTYPE_CHALLENGE: -+ res = eap_aka_process_challenge(sm, data, id, reqData, &attr); -+ break; -+ case EAP_AKA_SUBTYPE_NOTIFICATION: -+ res = eap_aka_process_notification(sm, data, id, reqData, -+ &attr); -+ break; -+ case EAP_AKA_SUBTYPE_REAUTHENTICATION: -+ res = eap_aka_process_reauthentication(sm, data, id, reqData, -+ &attr); -+ break; -+ case EAP_AKA_SUBTYPE_CLIENT_ERROR: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error"); -+ res = eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype); -+ res = eap_aka_client_error(data, id, -+ EAP_AKA_UNABLE_TO_PROCESS_PACKET); -+ break; -+ } -+ -+done: -+ if (data->state == FAILURE) { -+ ret->decision = DECISION_FAIL; -+ ret->methodState = METHOD_DONE; -+ } else if (data->state == SUCCESS) { -+ ret->decision = data->use_result_ind ? -+ DECISION_UNCOND_SUCC : DECISION_COND_SUCC; -+ /* -+ * It is possible for the server to reply with AKA -+ * Notification, so we must allow the method to continue and -+ * not only accept EAP-Success at this point. -+ */ -+ ret->methodState = data->use_result_ind ? -+ METHOD_DONE : METHOD_MAY_CONT; -+ } else if (data->state == RESULT_FAILURE) -+ ret->methodState = METHOD_CONT; -+ else if (data->state == RESULT_SUCCESS) -+ ret->methodState = METHOD_CONT; -+ -+ if (ret->methodState == METHOD_DONE) { -+ ret->allowNotifications = FALSE; -+ } -+ -+ return res; -+} -+ -+ -+static Boolean eap_aka_has_reauth_data(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ return data->pseudonym || data->reauth_id; -+} -+ -+ -+static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ eap_aka_clear_identities(data, CLEAR_EAP_ID); -+ data->prev_id = -1; -+ wpabuf_free(data->id_msgs); -+ data->id_msgs = NULL; -+ data->use_result_ind = 0; -+ data->kdf_negotiation = 0; -+} -+ -+ -+static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ eap_aka_state(data, CONTINUE); -+ return priv; -+} -+ -+ -+static const u8 * eap_aka_get_identity(struct eap_sm *sm, void *priv, -+ size_t *len) -+{ -+ struct eap_aka_data *data = priv; -+ -+ if (data->reauth_id) { -+ *len = data->reauth_id_len; -+ return data->reauth_id; -+ } -+ -+ if (data->pseudonym) { -+ *len = data->pseudonym_len; -+ return data->pseudonym; -+ } -+ -+ return NULL; -+} -+ -+ -+static Boolean eap_aka_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_aka_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_SIM_KEYING_DATA_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_SIM_KEYING_DATA_LEN; -+ os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); -+ -+ return key; -+} -+ -+ -+static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_aka_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_EMSK_LEN; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ -+ return key; -+} -+ -+ -+int eap_peer_aka_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_aka_init; -+ eap->deinit = eap_aka_deinit; -+ eap->process = eap_aka_process; -+ eap->isKeyAvailable = eap_aka_isKeyAvailable; -+ eap->getKey = eap_aka_getKey; -+ eap->has_reauth_data = eap_aka_has_reauth_data; -+ eap->deinit_for_reauth = eap_aka_deinit_for_reauth; -+ eap->init_for_reauth = eap_aka_init_for_reauth; -+ eap->get_identity = eap_aka_get_identity; -+ eap->get_emsk = eap_aka_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -+ -+ -+#ifdef EAP_AKA_PRIME -+int eap_peer_aka_prime_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, -+ "AKA'"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_aka_prime_init; -+ eap->deinit = eap_aka_deinit; -+ eap->process = eap_aka_process; -+ eap->isKeyAvailable = eap_aka_isKeyAvailable; -+ eap->getKey = eap_aka_getKey; -+ eap->has_reauth_data = eap_aka_has_reauth_data; -+ eap->deinit_for_reauth = eap_aka_deinit_for_reauth; -+ eap->init_for_reauth = eap_aka_init_for_reauth; -+ eap->get_identity = eap_aka_get_identity; -+ eap->get_emsk = eap_aka_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ -+ return ret; -+} -+#endif /* EAP_AKA_PRIME */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_config.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_config.h -new file mode 100644 -index 0000000000000..b64b68f4b76c2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_config.h -@@ -0,0 +1,669 @@ -+/* -+ * EAP peer configuration data -+ * Copyright (c) 2003-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_CONFIG_H -+#define EAP_CONFIG_H -+ -+/** -+ * struct eap_peer_config - EAP peer configuration/credentials -+ */ -+struct eap_peer_config { -+ /** -+ * identity - EAP Identity -+ * -+ * This field is used to set the real user identity or NAI (for -+ * EAP-PSK/PAX/SAKE/GPSK). -+ */ -+ u8 *identity; -+ -+ /** -+ * identity_len - EAP Identity length -+ */ -+ size_t identity_len; -+ -+ /** -+ * anonymous_identity - Anonymous EAP Identity -+ * -+ * This field is used for unencrypted use with EAP types that support -+ * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the -+ * real identity (identity field) only to the authentication server. -+ * -+ * If not set, the identity field will be used for both unencrypted and -+ * protected fields. -+ */ -+ u8 *anonymous_identity; -+ -+ /** -+ * anonymous_identity_len - Length of anonymous_identity -+ */ -+ size_t anonymous_identity_len; -+ -+ /** -+ * password - Password string for EAP -+ * -+ * This field can include either the plaintext password (default -+ * option) or a NtPasswordHash (16-byte MD4 hash of the unicode -+ * presentation of the password) if flags field has -+ * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can -+ * only be used with authentication mechanism that use this hash as the -+ * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2, -+ * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). -+ * -+ * In addition, this field is used to configure a pre-shared key for -+ * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK -+ * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length -+ * PSK. -+ */ -+ u8 *password; -+ -+ /** -+ * password_len - Length of password field -+ */ -+ size_t password_len; -+ -+ /** -+ * ca_cert - File path to CA certificate file (PEM/DER) -+ * -+ * This file can have one or more trusted CA certificates. If ca_cert -+ * and ca_path are not included, server certificate will not be -+ * verified. This is insecure and a trusted CA certificate should -+ * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the -+ * file should be used since working directory may change when -+ * wpa_supplicant is run in the background. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ * -+ * Alternatively, this can be used to only perform matching of the -+ * server certificate (SHA-256 hash of the DER encoded X.509 -+ * certificate). In this case, the possible CA certificates in the -+ * server certificate chain are ignored and only the server certificate -+ * is verified. This is configured with the following format: -+ * hash:://server/sha256/cert_hash_in_hex -+ * For example: "hash://server/sha256/ -+ * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" -+ * -+ * On Windows, trusted CA certificates can be loaded from the system -+ * certificate store by setting this to cert_store://name, e.g., -+ * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". -+ * Note that when running wpa_supplicant as an application, the user -+ * certificate store (My user account) is used, whereas computer store -+ * (Computer account) is used when running wpasvc as a service. -+ */ -+ u8 *ca_cert; -+ -+ /** -+ * ca_path - Directory path for CA certificate files (PEM) -+ * -+ * This path may contain multiple CA certificates in OpenSSL format. -+ * Common use for this is to point to system trusted CA list which is -+ * often installed into directory like /etc/ssl/certs. If configured, -+ * these certificates are added to the list of trusted CAs. ca_cert -+ * may also be included in that case, but it is not required. -+ */ -+ u8 *ca_path; -+ -+ /** -+ * client_cert - File path to client certificate file (PEM/DER) -+ * -+ * This field is used with EAP method that use TLS authentication. -+ * Usually, this is only configured for EAP-TLS, even though this could -+ * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the -+ * file should be used since working directory may change when -+ * wpa_supplicant is run in the background. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ u8 *client_cert; -+ -+ /** -+ * private_key - File path to client private key file (PEM/DER/PFX) -+ * -+ * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be -+ * commented out. Both the private key and certificate will be read -+ * from the PKCS#12 file in this case. Full path to the file should be -+ * used since working directory may change when wpa_supplicant is run -+ * in the background. -+ * -+ * Windows certificate store can be used by leaving client_cert out and -+ * configuring private_key in one of the following formats: -+ * -+ * cert://substring_to_match -+ * -+ * hash://certificate_thumbprint_in_hex -+ * -+ * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" -+ * -+ * Note that when running wpa_supplicant as an application, the user -+ * certificate store (My user account) is used, whereas computer store -+ * (Computer account) is used when running wpasvc as a service. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ u8 *private_key; -+ -+ /** -+ * private_key_passwd - Password for private key file -+ * -+ * If left out, this will be asked through control interface. -+ */ -+ u8 *private_key_passwd; -+ -+ /** -+ * dh_file - File path to DH/DSA parameters file (in PEM format) -+ * -+ * This is an optional configuration file for setting parameters for an -+ * ephemeral DH key exchange. In most cases, the default RSA -+ * authentication does not use this configuration. However, it is -+ * possible setup RSA to use ephemeral DH key exchange. In addition, -+ * ciphers with DSA keys always use ephemeral DH keys. This can be used -+ * to achieve forward secrecy. If the file is in DSA parameters format, -+ * it will be automatically converted into DH params. Full path to the -+ * file should be used since working directory may change when -+ * wpa_supplicant is run in the background. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ u8 *dh_file; -+ -+ /** -+ * subject_match - Constraint for server certificate subject -+ * -+ * This substring is matched against the subject of the authentication -+ * server certificate. If this string is set, the server sertificate is -+ * only accepted if it contains this string in the subject. The subject -+ * string is in following format: -+ * -+ * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com -+ */ -+ u8 *subject_match; -+ -+ /** -+ * altsubject_match - Constraint for server certificate alt. subject -+ * -+ * Semicolon separated string of entries to be matched against the -+ * alternative subject name of the authentication server certificate. -+ * If this string is set, the server sertificate is only accepted if it -+ * contains one of the entries in an alternative subject name -+ * extension. -+ * -+ * altSubjectName string is in following format: TYPE:VALUE -+ * -+ * Example: EMAIL:server@example.com -+ * Example: DNS:server.example.com;DNS:server2.example.com -+ * -+ * Following types are supported: EMAIL, DNS, URI -+ */ -+ u8 *altsubject_match; -+ -+ /** -+ * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2) -+ * -+ * This file can have one or more trusted CA certificates. If ca_cert2 -+ * and ca_path2 are not included, server certificate will not be -+ * verified. This is insecure and a trusted CA certificate should -+ * always be configured. Full path to the file should be used since -+ * working directory may change when wpa_supplicant is run in the -+ * background. -+ * -+ * This field is like ca_cert, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ u8 *ca_cert2; -+ -+ /** -+ * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2) -+ * -+ * This path may contain multiple CA certificates in OpenSSL format. -+ * Common use for this is to point to system trusted CA list which is -+ * often installed into directory like /etc/ssl/certs. If configured, -+ * these certificates are added to the list of trusted CAs. ca_cert -+ * may also be included in that case, but it is not required. -+ * -+ * This field is like ca_path, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ */ -+ u8 *ca_path2; -+ -+ /** -+ * client_cert2 - File path to client certificate file -+ * -+ * This field is like client_cert, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the -+ * file should be used since working directory may change when -+ * wpa_supplicant is run in the background. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ u8 *client_cert2; -+ -+ /** -+ * private_key2 - File path to client private key file -+ * -+ * This field is like private_key, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the -+ * file should be used since working directory may change when -+ * wpa_supplicant is run in the background. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ u8 *private_key2; -+ -+ /** -+ * private_key2_passwd - Password for private key file -+ * -+ * This field is like private_key_passwd, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ */ -+ u8 *private_key2_passwd; -+ -+ /** -+ * dh_file2 - File path to DH/DSA parameters file (in PEM format) -+ * -+ * This field is like dh_file, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the -+ * file should be used since working directory may change when -+ * wpa_supplicant is run in the background. -+ * -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ u8 *dh_file2; -+ -+ /** -+ * subject_match2 - Constraint for server certificate subject -+ * -+ * This field is like subject_match, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ */ -+ u8 *subject_match2; -+ -+ /** -+ * altsubject_match2 - Constraint for server certificate alt. subject -+ * -+ * This field is like altsubject_match, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ */ -+ u8 *altsubject_match2; -+ -+ /** -+ * eap_methods - Allowed EAP methods -+ * -+ * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of -+ * allowed EAP methods or %NULL if all methods are accepted. -+ */ -+ struct eap_method_type *eap_methods; -+ -+ /** -+ * phase1 - Phase 1 (outer authentication) parameters -+ * -+ * String with field-value pairs, e.g., "peapver=0" or -+ * "peapver=1 peaplabel=1". -+ * -+ * 'peapver' can be used to force which PEAP version (0 or 1) is used. -+ * -+ * 'peaplabel=1' can be used to force new label, "client PEAP -+ * encryption", to be used during key derivation when PEAPv1 or newer. -+ * -+ * Most existing PEAPv1 implementation seem to be using the old label, -+ * "client EAP encryption", and wpa_supplicant is now using that as the -+ * default value. -+ * -+ * Some servers, e.g., Radiator, may require peaplabel=1 configuration -+ * to interoperate with PEAPv1; see eap_testing.txt for more details. -+ * -+ * 'peap_outer_success=0' can be used to terminate PEAP authentication -+ * on tunneled EAP-Success. This is required with some RADIUS servers -+ * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g., -+ * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode). -+ * -+ * include_tls_length=1 can be used to force wpa_supplicant to include -+ * TLS Message Length field in all TLS messages even if they are not -+ * fragmented. -+ * -+ * sim_min_num_chal=3 can be used to configure EAP-SIM to require three -+ * challenges (by default, it accepts 2 or 3). -+ * -+ * result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use -+ * protected result indication. -+ * -+ * fast_provisioning option can be used to enable in-line provisioning -+ * of EAP-FAST credentials (PAC): -+ * 0 = disabled, -+ * 1 = allow unauthenticated provisioning, -+ * 2 = allow authenticated provisioning, -+ * 3 = allow both unauthenticated and authenticated provisioning -+ * -+ * fast_max_pac_list_len=num option can be used to set the maximum -+ * number of PAC entries to store in a PAC list (default: 10). -+ * -+ * fast_pac_format=binary option can be used to select binary format -+ * for storing PAC entries in order to save some space (the default -+ * text format uses about 2.5 times the size of minimal binary format). -+ * -+ * crypto_binding option can be used to control PEAPv0 cryptobinding -+ * behavior: -+ * 0 = do not use cryptobinding (default) -+ * 1 = use cryptobinding if server supports it -+ * 2 = require cryptobinding -+ * -+ * EAP-WSC (WPS) uses following options: pin=Device_Password and -+ * uuid=Device_UUID -+ */ -+ char *phase1; -+ -+ /** -+ * phase2 - Phase2 (inner authentication with TLS tunnel) parameters -+ * -+ * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or -+ * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. -+ */ -+ char *phase2; -+ -+ /** -+ * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM -+ * -+ * This field is used to configure PC/SC smartcard interface. -+ * Currently, the only configuration is whether this field is %NULL (do -+ * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC. -+ * -+ * This field is used for EAP-SIM and EAP-AKA. -+ */ -+ char *pcsc; -+ -+ /** -+ * pin - PIN for USIM, GSM SIM, and smartcards -+ * -+ * This field is used to configure PIN for SIM and smartcards for -+ * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a -+ * smartcard is used for private key operations. -+ * -+ * If left out, this will be asked through control interface. -+ */ -+ char *pin; -+ -+ /** -+ * engine - Enable OpenSSL engine (e.g., for smartcard access) -+ * -+ * This is used if private key operations for EAP-TLS are performed -+ * using a smartcard. -+ */ -+ int engine; -+ -+ /** -+ * engine_id - Engine ID for OpenSSL engine -+ * -+ * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 -+ * engine. -+ * -+ * This is used if private key operations for EAP-TLS are performed -+ * using a smartcard. -+ */ -+ char *engine_id; -+ -+ /** -+ * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2) -+ * -+ * This is used if private key operations for EAP-TLS are performed -+ * using a smartcard. -+ * -+ * This field is like engine, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ */ -+ int engine2; -+ -+ -+ /** -+ * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2) -+ * -+ * This field is used to configure PIN for SIM and smartcards for -+ * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a -+ * smartcard is used for private key operations. -+ * -+ * This field is like pin2, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ * -+ * If left out, this will be asked through control interface. -+ */ -+ char *pin2; -+ -+ /** -+ * engine2_id - Engine ID for OpenSSL engine (Phase 2) -+ * -+ * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 -+ * engine. -+ * -+ * This is used if private key operations for EAP-TLS are performed -+ * using a smartcard. -+ * -+ * This field is like engine_id, but used for phase 2 (inside -+ * EAP-TTLS/PEAP/FAST tunnel) authentication. -+ */ -+ char *engine2_id; -+ -+ -+ /** -+ * key_id - Key ID for OpenSSL engine -+ * -+ * This is used if private key operations for EAP-TLS are performed -+ * using a smartcard. -+ */ -+ char *key_id; -+ -+ /** -+ * cert_id - Cert ID for OpenSSL engine -+ * -+ * This is used if the certificate operations for EAP-TLS are performed -+ * using a smartcard. -+ */ -+ char *cert_id; -+ -+ /** -+ * ca_cert_id - CA Cert ID for OpenSSL engine -+ * -+ * This is used if the CA certificate for EAP-TLS is on a smartcard. -+ */ -+ char *ca_cert_id; -+ -+ /** -+ * key2_id - Key ID for OpenSSL engine (phase2) -+ * -+ * This is used if private key operations for EAP-TLS are performed -+ * using a smartcard. -+ */ -+ char *key2_id; -+ -+ /** -+ * cert2_id - Cert ID for OpenSSL engine (phase2) -+ * -+ * This is used if the certificate operations for EAP-TLS are performed -+ * using a smartcard. -+ */ -+ char *cert2_id; -+ -+ /** -+ * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2) -+ * -+ * This is used if the CA certificate for EAP-TLS is on a smartcard. -+ */ -+ char *ca_cert2_id; -+ -+ /** -+ * otp - One-time-password -+ * -+ * This field should not be set in configuration step. It is only used -+ * internally when OTP is entered through the control interface. -+ */ -+ u8 *otp; -+ -+ /** -+ * otp_len - Length of the otp field -+ */ -+ size_t otp_len; -+ -+ /** -+ * pending_req_identity - Whether there is a pending identity request -+ * -+ * This field should not be set in configuration step. It is only used -+ * internally when control interface is used to request needed -+ * information. -+ */ -+ int pending_req_identity; -+ -+ /** -+ * pending_req_password - Whether there is a pending password request -+ * -+ * This field should not be set in configuration step. It is only used -+ * internally when control interface is used to request needed -+ * information. -+ */ -+ int pending_req_password; -+ -+ /** -+ * pending_req_pin - Whether there is a pending PIN request -+ * -+ * This field should not be set in configuration step. It is only used -+ * internally when control interface is used to request needed -+ * information. -+ */ -+ int pending_req_pin; -+ -+ /** -+ * pending_req_new_password - Pending password update request -+ * -+ * This field should not be set in configuration step. It is only used -+ * internally when control interface is used to request needed -+ * information. -+ */ -+ int pending_req_new_password; -+ -+ /** -+ * pending_req_passphrase - Pending passphrase request -+ * -+ * This field should not be set in configuration step. It is only used -+ * internally when control interface is used to request needed -+ * information. -+ */ -+ int pending_req_passphrase; -+ -+ /** -+ * pending_req_otp - Whether there is a pending OTP request -+ * -+ * This field should not be set in configuration step. It is only used -+ * internally when control interface is used to request needed -+ * information. -+ */ -+ char *pending_req_otp; -+ -+ /** -+ * pending_req_otp_len - Length of the pending OTP request -+ */ -+ size_t pending_req_otp_len; -+ -+ /** -+ * pac_file - File path or blob name for the PAC entries (EAP-FAST) -+ * -+ * wpa_supplicant will need to be able to create this file and write -+ * updates to it when PAC is being provisioned or refreshed. Full path -+ * to the file should be used since working directory may change when -+ * wpa_supplicant is run in the background. -+ * Alternatively, a named configuration blob can be used by setting -+ * this to blob://blob_name. -+ */ -+ char *pac_file; -+ -+ /** -+ * mschapv2_retry - MSCHAPv2 retry in progress -+ * -+ * This field is used internally by EAP-MSCHAPv2 and should not be set -+ * as part of configuration. -+ */ -+ int mschapv2_retry; -+ -+ /** -+ * new_password - New password for password update -+ * -+ * This field is used during MSCHAPv2 password update. This is normally -+ * requested from the user through the control interface and not set -+ * from configuration. -+ */ -+ u8 *new_password; -+ -+ /** -+ * new_password_len - Length of new_password field -+ */ -+ size_t new_password_len; -+ -+ /** -+ * fragment_size - Maximum EAP fragment size in bytes (default 1398) -+ * -+ * This value limits the fragment size for EAP methods that support -+ * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set -+ * small enough to make the EAP messages fit in MTU of the network -+ * interface used for EAPOL. The default value is suitable for most -+ * cases. -+ */ -+ int fragment_size; -+ -+#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0) -+ /** -+ * flags - Network configuration flags (bitfield) -+ * -+ * This variable is used for internal flags to describe further details -+ * for the network parameters. -+ * bit 0 = password is represented as a 16-byte NtPasswordHash value -+ * instead of plaintext password -+ */ -+ u32 flags; -+}; -+ -+ -+/** -+ * struct wpa_config_blob - Named configuration blob -+ * -+ * This data structure is used to provide storage for binary objects to store -+ * abstract information like certificates and private keys inlined with the -+ * configuration data. -+ */ -+struct wpa_config_blob { -+ /** -+ * name - Blob name -+ */ -+ char *name; -+ -+ /** -+ * data - Pointer to binary data -+ */ -+ u8 *data; -+ -+ /** -+ * len - Length of binary data -+ */ -+ size_t len; -+ -+ /** -+ * next - Pointer to next blob in the configuration -+ */ -+ struct wpa_config_blob *next; -+}; -+ -+#endif /* EAP_CONFIG_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast.c -new file mode 100644 -index 0000000000000..5d3e69d3cdfe6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast.c -@@ -0,0 +1,1712 @@ -+/* -+ * EAP peer method: EAP-FAST (RFC 4851) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/tls.h" -+#include "crypto/sha1.h" -+#include "eap_common/eap_tlv_common.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+#include "eap_config.h" -+#include "eap_fast_pac.h" -+ -+#ifdef EAP_FAST_DYNAMIC -+#include "eap_fast_pac.c" -+#endif /* EAP_FAST_DYNAMIC */ -+ -+/* TODO: -+ * - test session resumption and enable it if it interoperates -+ * - password change (pending mschapv2 packet; replay decrypted packet) -+ */ -+ -+ -+static void eap_fast_deinit(struct eap_sm *sm, void *priv); -+ -+ -+struct eap_fast_data { -+ struct eap_ssl_data ssl; -+ -+ int fast_version; -+ -+ const struct eap_method *phase2_method; -+ void *phase2_priv; -+ int phase2_success; -+ -+ struct eap_method_type phase2_type; -+ struct eap_method_type *phase2_types; -+ size_t num_phase2_types; -+ int resuming; /* starting a resumed session */ -+ struct eap_fast_key_block_provisioning *key_block_p; -+#define EAP_FAST_PROV_UNAUTH 1 -+#define EAP_FAST_PROV_AUTH 2 -+ int provisioning_allowed; /* Allowed PAC provisioning modes */ -+ int provisioning; /* doing PAC provisioning (not the normal auth) */ -+ int anon_provisioning; /* doing anonymous (unauthenticated) -+ * provisioning */ -+ int session_ticket_used; -+ -+ u8 key_data[EAP_FAST_KEY_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ int success; -+ -+ struct eap_fast_pac *pac; -+ struct eap_fast_pac *current_pac; -+ size_t max_pac_list_len; -+ int use_pac_binary_format; -+ -+ u8 simck[EAP_FAST_SIMCK_LEN]; -+ int simck_idx; -+ -+ struct wpabuf *pending_phase2_req; -+}; -+ -+ -+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, -+ const u8 *client_random, -+ const u8 *server_random, -+ u8 *master_secret) -+{ -+ struct eap_fast_data *data = ctx; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback"); -+ -+ if (client_random == NULL || server_random == NULL || -+ master_secret == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall " -+ "back to full TLS handshake"); -+ data->session_ticket_used = 0; -+ if (data->provisioning_allowed) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a " -+ "new PAC-Key"); -+ data->provisioning = 1; -+ data->current_pac = NULL; -+ } -+ return 0; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len); -+ -+ if (data->current_pac == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for " -+ "using SessionTicket"); -+ data->session_ticket_used = 0; -+ return 0; -+ } -+ -+ eap_fast_derive_master_secret(data->current_pac->pac_key, -+ server_random, client_random, -+ master_secret); -+ -+ data->session_ticket_used = 1; -+ -+ return 1; -+} -+ -+ -+static int eap_fast_parse_phase1(struct eap_fast_data *data, -+ const char *phase1) -+{ -+ const char *pos; -+ -+ pos = os_strstr(phase1, "fast_provisioning="); -+ if (pos) { -+ data->provisioning_allowed = atoi(pos + 18); -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC provisioning " -+ "mode: %d", data->provisioning_allowed); -+ } -+ -+ pos = os_strstr(phase1, "fast_max_pac_list_len="); -+ if (pos) { -+ data->max_pac_list_len = atoi(pos + 22); -+ if (data->max_pac_list_len == 0) -+ data->max_pac_list_len = 1; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Maximum PAC list length: %lu", -+ (unsigned long) data->max_pac_list_len); -+ } -+ -+ pos = os_strstr(phase1, "fast_pac_format=binary"); -+ if (pos) { -+ data->use_pac_binary_format = 1; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC " -+ "list"); -+ } -+ -+ return 0; -+} -+ -+ -+static void * eap_fast_init(struct eap_sm *sm) -+{ -+ struct eap_fast_data *data; -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->fast_version = EAP_FAST_VERSION; -+ data->max_pac_list_len = 10; -+ -+ if (config && config->phase1 && -+ eap_fast_parse_phase1(data, config->phase1) < 0) { -+ eap_fast_deinit(sm, data); -+ return NULL; -+ } -+ -+ if (eap_peer_select_phase2_methods(config, "auth=", -+ &data->phase2_types, -+ &data->num_phase2_types) < 0) { -+ eap_fast_deinit(sm, data); -+ return NULL; -+ } -+ -+ data->phase2_type.vendor = EAP_VENDOR_IETF; -+ data->phase2_type.method = EAP_TYPE_NONE; -+ -+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL."); -+ eap_fast_deinit(sm, data); -+ return NULL; -+ } -+ -+ if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn, -+ eap_fast_session_ticket_cb, -+ data) < 0) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket " -+ "callback"); -+ eap_fast_deinit(sm, data); -+ return NULL; -+ } -+ -+ /* -+ * The local RADIUS server in a Cisco AP does not seem to like empty -+ * fragments before data, so disable that workaround for CBC. -+ * TODO: consider making this configurable -+ */ -+ if (tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn)) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to enable TLS " -+ "workarounds"); -+ } -+ -+ if (data->use_pac_binary_format && -+ eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) { -+ eap_fast_deinit(sm, data); -+ return NULL; -+ } -+ -+ if (!data->use_pac_binary_format && -+ eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) { -+ eap_fast_deinit(sm, data); -+ return NULL; -+ } -+ eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len); -+ -+ if (data->pac == NULL && !data->provisioning_allowed) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and " -+ "provisioning disabled"); -+ eap_fast_deinit(sm, data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_fast_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ struct eap_fast_pac *pac, *prev; -+ -+ if (data == NULL) -+ return; -+ if (data->phase2_priv && data->phase2_method) -+ data->phase2_method->deinit(sm, data->phase2_priv); -+ os_free(data->phase2_types); -+ os_free(data->key_block_p); -+ eap_peer_tls_ssl_deinit(sm, &data->ssl); -+ -+ pac = data->pac; -+ prev = NULL; -+ while (pac) { -+ prev = pac; -+ pac = pac->next; -+ eap_fast_free_pac(prev); -+ } -+ wpabuf_free(data->pending_phase2_req); -+ os_free(data); -+} -+ -+ -+static int eap_fast_derive_msk(struct eap_fast_data *data) -+{ -+ eap_fast_derive_eap_msk(data->simck, data->key_data); -+ eap_fast_derive_eap_emsk(data->simck, data->emsk); -+ data->success = 1; -+ return 0; -+} -+ -+ -+static void eap_fast_derive_key_auth(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ u8 *sks; -+ -+ /* RFC 4851, Section 5.1: -+ * Extra key material after TLS key_block: session_key_seed[40] -+ */ -+ -+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion", -+ EAP_FAST_SKS_LEN); -+ if (sks == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive " -+ "session_key_seed"); -+ return; -+ } -+ -+ /* -+ * RFC 4851, Section 5.2: -+ * S-IMCK[0] = session_key_seed -+ */ -+ wpa_hexdump_key(MSG_DEBUG, -+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", -+ sks, EAP_FAST_SKS_LEN); -+ data->simck_idx = 0; -+ os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN); -+ os_free(sks); -+} -+ -+ -+static void eap_fast_derive_key_provisioning(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ os_free(data->key_block_p); -+ data->key_block_p = (struct eap_fast_key_block_provisioning *) -+ eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, -+ "key expansion", -+ sizeof(*data->key_block_p)); -+ if (data->key_block_p == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block"); -+ return; -+ } -+ /* -+ * RFC 4851, Section 5.2: -+ * S-IMCK[0] = session_key_seed -+ */ -+ wpa_hexdump_key(MSG_DEBUG, -+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", -+ data->key_block_p->session_key_seed, -+ sizeof(data->key_block_p->session_key_seed)); -+ data->simck_idx = 0; -+ os_memcpy(data->simck, data->key_block_p->session_key_seed, -+ EAP_FAST_SIMCK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge", -+ data->key_block_p->server_challenge, -+ sizeof(data->key_block_p->server_challenge)); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge", -+ data->key_block_p->client_challenge, -+ sizeof(data->key_block_p->client_challenge)); -+} -+ -+ -+static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data) -+{ -+ if (data->anon_provisioning) -+ eap_fast_derive_key_provisioning(sm, data); -+ else -+ eap_fast_derive_key_auth(sm, data); -+} -+ -+ -+static int eap_fast_init_phase2_method(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ data->phase2_method = -+ eap_peer_get_eap_method(data->phase2_type.vendor, -+ data->phase2_type.method); -+ if (data->phase2_method == NULL) -+ return -1; -+ -+ if (data->key_block_p) { -+ sm->auth_challenge = data->key_block_p->server_challenge; -+ sm->peer_challenge = data->key_block_p->client_challenge; -+ } -+ sm->init_phase2 = 1; -+ data->phase2_priv = data->phase2_method->init(sm); -+ sm->init_phase2 = 0; -+ sm->auth_challenge = NULL; -+ sm->peer_challenge = NULL; -+ -+ return data->phase2_priv == NULL ? -1 : 0; -+} -+ -+ -+static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type) -+{ -+ size_t i; -+ -+ /* TODO: TNC with anonymous provisioning; need to require both -+ * completed MSCHAPv2 and TNC */ -+ -+ if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed " -+ "during unauthenticated provisioning; reject phase2" -+ " type %d", type); -+ return -1; -+ } -+ -+#ifdef EAP_TNC -+ if (type == EAP_TYPE_TNC) { -+ data->phase2_type.vendor = EAP_VENDOR_IETF; -+ data->phase2_type.method = EAP_TYPE_TNC; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP " -+ "vendor %d method %d for TNC", -+ data->phase2_type.vendor, -+ data->phase2_type.method); -+ return 0; -+ } -+#endif /* EAP_TNC */ -+ -+ for (i = 0; i < data->num_phase2_types; i++) { -+ if (data->phase2_types[i].vendor != EAP_VENDOR_IETF || -+ data->phase2_types[i].method != type) -+ continue; -+ -+ data->phase2_type.vendor = data->phase2_types[i].vendor; -+ data->phase2_type.method = data->phase2_types[i].method; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP " -+ "vendor %d method %d", -+ data->phase2_type.vendor, -+ data->phase2_type.method); -+ break; -+ } -+ -+ if (type != data->phase2_type.method || type == EAP_TYPE_NONE) -+ return -1; -+ -+ return 0; -+} -+ -+ -+static int eap_fast_phase2_request(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct eap_method_ret *ret, -+ struct eap_hdr *hdr, -+ struct wpabuf **resp) -+{ -+ size_t len = be_to_host16(hdr->length); -+ u8 *pos; -+ struct eap_method_ret iret; -+ struct eap_peer_config *config = eap_get_config(sm); -+ struct wpabuf msg; -+ -+ if (len <= sizeof(struct eap_hdr)) { -+ wpa_printf(MSG_INFO, "EAP-FAST: too short " -+ "Phase 2 request (len=%lu)", (unsigned long) len); -+ return -1; -+ } -+ pos = (u8 *) (hdr + 1); -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos); -+ if (*pos == EAP_TYPE_IDENTITY) { -+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); -+ return 0; -+ } -+ -+ if (data->phase2_priv && data->phase2_method && -+ *pos != data->phase2_type.method) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - " -+ "deinitialize previous method"); -+ data->phase2_method->deinit(sm, data->phase2_priv); -+ data->phase2_method = NULL; -+ data->phase2_priv = NULL; -+ data->phase2_type.vendor = EAP_VENDOR_IETF; -+ data->phase2_type.method = EAP_TYPE_NONE; -+ } -+ -+ if (data->phase2_type.vendor == EAP_VENDOR_IETF && -+ data->phase2_type.method == EAP_TYPE_NONE && -+ eap_fast_select_phase2_method(data, *pos) < 0) { -+ if (eap_peer_tls_phase2_nak(data->phase2_types, -+ data->num_phase2_types, -+ hdr, resp)) -+ return -1; -+ return 0; -+ } -+ -+ if (data->phase2_priv == NULL && -+ eap_fast_init_phase2_method(sm, data) < 0) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize " -+ "Phase 2 EAP method %d", *pos); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return -1; -+ } -+ -+ os_memset(&iret, 0, sizeof(iret)); -+ wpabuf_set(&msg, hdr, len); -+ *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, -+ &msg); -+ if (*resp == NULL || -+ (iret.methodState == METHOD_DONE && -+ iret.decision == DECISION_FAIL)) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ } else if ((iret.methodState == METHOD_DONE || -+ iret.methodState == METHOD_MAY_CONT) && -+ (iret.decision == DECISION_UNCOND_SUCC || -+ iret.decision == DECISION_COND_SUCC)) { -+ data->phase2_success = 1; -+ } -+ -+ if (*resp == NULL && config && -+ (config->pending_req_identity || config->pending_req_password || -+ config->pending_req_otp || config->pending_req_new_password)) { -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); -+ } else if (*resp == NULL) -+ return -1; -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_fast_tlv_nak(int vendor_id, int tlv_type) -+{ -+ struct wpabuf *buf; -+ struct eap_tlv_nak_tlv *nak; -+ buf = wpabuf_alloc(sizeof(*nak)); -+ if (buf == NULL) -+ return NULL; -+ nak = wpabuf_put(buf, sizeof(*nak)); -+ nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV); -+ nak->length = host_to_be16(6); -+ nak->vendor_id = host_to_be32(vendor_id); -+ nak->nak_type = host_to_be16(tlv_type); -+ return buf; -+} -+ -+ -+static struct wpabuf * eap_fast_tlv_result(int status, int intermediate) -+{ -+ struct wpabuf *buf; -+ struct eap_tlv_intermediate_result_tlv *result; -+ buf = wpabuf_alloc(sizeof(*result)); -+ if (buf == NULL) -+ return NULL; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add %sResult TLV(status=%d)", -+ intermediate ? "Intermediate " : "", status); -+ result = wpabuf_put(buf, sizeof(*result)); -+ result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | -+ (intermediate ? -+ EAP_TLV_INTERMEDIATE_RESULT_TLV : -+ EAP_TLV_RESULT_TLV)); -+ result->length = host_to_be16(2); -+ result->status = host_to_be16(status); -+ return buf; -+} -+ -+ -+static struct wpabuf * eap_fast_tlv_pac_ack(void) -+{ -+ struct wpabuf *buf; -+ struct eap_tlv_result_tlv *res; -+ struct eap_tlv_pac_ack_tlv *ack; -+ -+ buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack)); -+ if (buf == NULL) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV (ack)"); -+ ack = wpabuf_put(buf, sizeof(*ack)); -+ ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV | -+ EAP_TLV_TYPE_MANDATORY); -+ ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr)); -+ ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT); -+ ack->pac_len = host_to_be16(2); -+ ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS); -+ -+ return buf; -+} -+ -+ -+static struct wpabuf * eap_fast_process_eap_payload_tlv( -+ struct eap_sm *sm, struct eap_fast_data *data, -+ struct eap_method_ret *ret, const struct eap_hdr *req, -+ u8 *eap_payload_tlv, size_t eap_payload_tlv_len) -+{ -+ struct eap_hdr *hdr; -+ struct wpabuf *resp = NULL; -+ -+ if (eap_payload_tlv_len < sizeof(*hdr)) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP " -+ "Payload TLV (len=%lu)", -+ (unsigned long) eap_payload_tlv_len); -+ return NULL; -+ } -+ -+ hdr = (struct eap_hdr *) eap_payload_tlv; -+ if (be_to_host16(hdr->length) > eap_payload_tlv_len) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow in " -+ "EAP Payload TLV"); -+ return NULL; -+ } -+ -+ if (hdr->code != EAP_CODE_REQUEST) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in " -+ "Phase 2 EAP header", hdr->code); -+ return NULL; -+ } -+ -+ if (eap_fast_phase2_request(sm, data, ret, hdr, &resp)) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Phase2 Request processing " -+ "failed"); -+ return NULL; -+ } -+ -+ return eap_fast_tlv_eap_payload(resp); -+} -+ -+ -+static int eap_fast_validate_crypto_binding( -+ struct eap_tlv_crypto_binding_tlv *_bind) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d " -+ "Received Version %d SubType %d", -+ _bind->version, _bind->received_version, _bind->subtype); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", -+ _bind->nonce, sizeof(_bind->nonce)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", -+ _bind->compound_mac, sizeof(_bind->compound_mac)); -+ -+ if (_bind->version != EAP_FAST_VERSION || -+ _bind->received_version != EAP_FAST_VERSION || -+ _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in " -+ "Crypto-Binding TLV: Version %d " -+ "Received Version %d SubType %d", -+ _bind->version, _bind->received_version, -+ _bind->subtype); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_fast_write_crypto_binding( -+ struct eap_tlv_crypto_binding_tlv *rbind, -+ struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk) -+{ -+ rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | -+ EAP_TLV_CRYPTO_BINDING_TLV); -+ rbind->length = host_to_be16(sizeof(*rbind) - -+ sizeof(struct eap_tlv_hdr)); -+ rbind->version = EAP_FAST_VERSION; -+ rbind->received_version = _bind->version; -+ rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE; -+ os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce)); -+ inc_byte_array(rbind->nonce, sizeof(rbind->nonce)); -+ hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind), -+ rbind->compound_mac); -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d " -+ "Received Version %d SubType %d", -+ rbind->version, rbind->received_version, rbind->subtype); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", -+ rbind->nonce, sizeof(rbind->nonce)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", -+ rbind->compound_mac, sizeof(rbind->compound_mac)); -+} -+ -+ -+static int eap_fast_get_phase2_key(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ u8 *isk, size_t isk_len) -+{ -+ u8 *key; -+ size_t key_len; -+ -+ os_memset(isk, 0, isk_len); -+ -+ if (data->phase2_method == NULL || data->phase2_priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " -+ "available"); -+ return -1; -+ } -+ -+ if (data->phase2_method->isKeyAvailable == NULL || -+ data->phase2_method->getKey == NULL) -+ return 0; -+ -+ if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || -+ (key = data->phase2_method->getKey(sm, data->phase2_priv, -+ &key_len)) == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material " -+ "from Phase 2"); -+ return -1; -+ } -+ -+ if (key_len > isk_len) -+ key_len = isk_len; -+ if (key_len == 32 && -+ data->phase2_method->vendor == EAP_VENDOR_IETF && -+ data->phase2_method->method == EAP_TYPE_MSCHAPV2) { -+ /* -+ * EAP-FAST uses reverse order for MS-MPPE keys when deriving -+ * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct -+ * ISK for EAP-FAST cryptobinding. -+ */ -+ os_memcpy(isk, key + 16, 16); -+ os_memcpy(isk + 16, key, 16); -+ } else -+ os_memcpy(isk, key, key_len); -+ os_free(key); -+ -+ return 0; -+} -+ -+ -+static int eap_fast_get_cmk(struct eap_sm *sm, struct eap_fast_data *data, -+ u8 *cmk) -+{ -+ u8 isk[32], imck[60]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC " -+ "calculation", data->simck_idx + 1); -+ -+ /* -+ * RFC 4851, Section 5.2: -+ * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys", -+ * MSK[j], 60) -+ * S-IMCK[j] = first 40 octets of IMCK[j] -+ * CMK[j] = last 20 octets of IMCK[j] -+ */ -+ -+ if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0) -+ return -1; -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk)); -+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, -+ "Inner Methods Compound Keys", -+ isk, sizeof(isk), imck, sizeof(imck)); -+ data->simck_idx++; -+ os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]", -+ data->simck, EAP_FAST_SIMCK_LEN); -+ os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", -+ cmk, EAP_FAST_CMK_LEN); -+ -+ return 0; -+} -+ -+ -+static u8 * eap_fast_write_pac_request(u8 *pos, u16 pac_type) -+{ -+ struct eap_tlv_hdr *pac; -+ struct eap_tlv_request_action_tlv *act; -+ struct eap_tlv_pac_type_tlv *type; -+ -+ act = (struct eap_tlv_request_action_tlv *) pos; -+ act->tlv_type = host_to_be16(EAP_TLV_REQUEST_ACTION_TLV); -+ act->length = host_to_be16(2); -+ act->action = host_to_be16(EAP_TLV_ACTION_PROCESS_TLV); -+ -+ pac = (struct eap_tlv_hdr *) (act + 1); -+ pac->tlv_type = host_to_be16(EAP_TLV_PAC_TLV); -+ pac->length = host_to_be16(sizeof(*type)); -+ -+ type = (struct eap_tlv_pac_type_tlv *) (pac + 1); -+ type->tlv_type = host_to_be16(PAC_TYPE_PAC_TYPE); -+ type->length = host_to_be16(2); -+ type->pac_type = host_to_be16(pac_type); -+ -+ return (u8 *) (type + 1); -+} -+ -+ -+static struct wpabuf * eap_fast_process_crypto_binding( -+ struct eap_sm *sm, struct eap_fast_data *data, -+ struct eap_method_ret *ret, -+ struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len) -+{ -+ struct wpabuf *resp; -+ u8 *pos; -+ u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN]; -+ int res; -+ size_t len; -+ -+ if (eap_fast_validate_crypto_binding(_bind) < 0) -+ return NULL; -+ -+ if (eap_fast_get_cmk(sm, data, cmk) < 0) -+ return NULL; -+ -+ /* Validate received Compound MAC */ -+ os_memcpy(cmac, _bind->compound_mac, sizeof(cmac)); -+ os_memset(_bind->compound_mac, 0, sizeof(cmac)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound " -+ "MAC calculation", (u8 *) _bind, bind_len); -+ hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len, -+ _bind->compound_mac); -+ res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC", -+ cmac, sizeof(cmac)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC", -+ _bind->compound_mac, sizeof(cmac)); -+ if (res != 0) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match"); -+ os_memcpy(_bind->compound_mac, cmac, sizeof(cmac)); -+ return NULL; -+ } -+ -+ /* -+ * Compound MAC was valid, so authentication succeeded. Reply with -+ * crypto binding to allow server to complete authentication. -+ */ -+ -+ len = sizeof(struct eap_tlv_crypto_binding_tlv); -+ resp = wpabuf_alloc(len); -+ if (resp == NULL) -+ return NULL; -+ -+ if (!data->anon_provisioning && data->phase2_success && -+ eap_fast_derive_msk(data) < 0) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ data->phase2_success = 0; -+ wpabuf_free(resp); -+ return NULL; -+ } -+ -+ pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv)); -+ eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *) -+ pos, _bind, cmk); -+ -+ return resp; -+} -+ -+ -+static void eap_fast_parse_pac_tlv(struct eap_fast_pac *entry, int type, -+ u8 *pos, size_t len, int *pac_key_found) -+{ -+ switch (type & 0x7fff) { -+ case PAC_TYPE_PAC_KEY: -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key", pos, len); -+ if (len != EAP_FAST_PAC_KEY_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid PAC-Key " -+ "length %lu", (unsigned long) len); -+ break; -+ } -+ *pac_key_found = 1; -+ os_memcpy(entry->pac_key, pos, len); -+ break; -+ case PAC_TYPE_PAC_OPAQUE: -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", pos, len); -+ entry->pac_opaque = pos; -+ entry->pac_opaque_len = len; -+ break; -+ case PAC_TYPE_PAC_INFO: -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info", pos, len); -+ entry->pac_info = pos; -+ entry->pac_info_len = len; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC type %d", -+ type); -+ break; -+ } -+} -+ -+ -+static int eap_fast_process_pac_tlv(struct eap_fast_pac *entry, -+ u8 *pac, size_t pac_len) -+{ -+ struct pac_tlv_hdr *hdr; -+ u8 *pos; -+ size_t left, len; -+ int type, pac_key_found = 0; -+ -+ pos = pac; -+ left = pac_len; -+ -+ while (left > sizeof(*hdr)) { -+ hdr = (struct pac_tlv_hdr *) pos; -+ type = be_to_host16(hdr->type); -+ len = be_to_host16(hdr->len); -+ pos += sizeof(*hdr); -+ left -= sizeof(*hdr); -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV overrun " -+ "(type=%d len=%lu left=%lu)", -+ type, (unsigned long) len, -+ (unsigned long) left); -+ return -1; -+ } -+ -+ eap_fast_parse_pac_tlv(entry, type, pos, len, &pac_key_found); -+ -+ pos += len; -+ left -= len; -+ } -+ -+ if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV does not include " -+ "all the required fields"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type, -+ u8 *pos, size_t len) -+{ -+ u16 pac_type; -+ u32 lifetime; -+ struct os_time now; -+ -+ switch (type & 0x7fff) { -+ case PAC_TYPE_CRED_LIFETIME: -+ if (len != 4) { -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Info - " -+ "Invalid CRED_LIFETIME length - ignored", -+ pos, len); -+ return 0; -+ } -+ -+ /* -+ * This is not currently saved separately in PAC files since -+ * the server can automatically initiate PAC update when -+ * needed. Anyway, the information is available from PAC-Info -+ * dump if it is needed for something in the future. -+ */ -+ lifetime = WPA_GET_BE32(pos); -+ os_get_time(&now); -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - CRED_LIFETIME %d " -+ "(%d days)", -+ lifetime, (lifetime - (u32) now.sec) / 86400); -+ break; -+ case PAC_TYPE_A_ID: -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID", -+ pos, len); -+ entry->a_id = pos; -+ entry->a_id_len = len; -+ break; -+ case PAC_TYPE_I_ID: -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - I-ID", -+ pos, len); -+ entry->i_id = pos; -+ entry->i_id_len = len; -+ break; -+ case PAC_TYPE_A_ID_INFO: -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: PAC-Info - A-ID-Info", -+ pos, len); -+ entry->a_id_info = pos; -+ entry->a_id_info_len = len; -+ break; -+ case PAC_TYPE_PAC_TYPE: -+ /* RFC 5422, Section 4.2.6 - PAC-Type TLV */ -+ if (len != 2) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type " -+ "length %lu (expected 2)", -+ (unsigned long) len); -+ wpa_hexdump_ascii(MSG_DEBUG, -+ "EAP-FAST: PAC-Info - PAC-Type", -+ pos, len); -+ return -1; -+ } -+ pac_type = WPA_GET_BE16(pos); -+ if (pac_type != PAC_TYPE_TUNNEL_PAC && -+ pac_type != PAC_TYPE_USER_AUTHORIZATION && -+ pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Unsupported PAC Type " -+ "%d", pac_type); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info - PAC-Type %d", -+ pac_type); -+ entry->pac_type = pac_type; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored unknown PAC-Info " -+ "type %d", type); -+ break; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_process_pac_info(struct eap_fast_pac *entry) -+{ -+ struct pac_tlv_hdr *hdr; -+ u8 *pos; -+ size_t left, len; -+ int type; -+ -+ /* RFC 5422, Section 4.2.4 */ -+ -+ /* PAC-Type defaults to Tunnel PAC (Type 1) */ -+ entry->pac_type = PAC_TYPE_TUNNEL_PAC; -+ -+ pos = entry->pac_info; -+ left = entry->pac_info_len; -+ while (left > sizeof(*hdr)) { -+ hdr = (struct pac_tlv_hdr *) pos; -+ type = be_to_host16(hdr->type); -+ len = be_to_host16(hdr->len); -+ pos += sizeof(*hdr); -+ left -= sizeof(*hdr); -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info overrun " -+ "(type=%d len=%lu left=%lu)", -+ type, (unsigned long) len, -+ (unsigned long) left); -+ return -1; -+ } -+ -+ if (eap_fast_parse_pac_info(entry, type, pos, len) < 0) -+ return -1; -+ -+ pos += len; -+ left -= len; -+ } -+ -+ if (entry->a_id == NULL || entry->a_id_info == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Info does not include " -+ "all the required fields"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct eap_method_ret *ret, -+ u8 *pac, size_t pac_len) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ struct eap_fast_pac entry; -+ -+ os_memset(&entry, 0, sizeof(entry)); -+ if (eap_fast_process_pac_tlv(&entry, pac, pac_len) || -+ eap_fast_process_pac_info(&entry)) -+ return NULL; -+ -+ eap_fast_add_pac(&data->pac, &data->current_pac, &entry); -+ eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len); -+ if (data->use_pac_binary_format) -+ eap_fast_save_pac_bin(sm, data->pac, config->pac_file); -+ else -+ eap_fast_save_pac(sm, data->pac, config->pac_file); -+ -+ if (data->provisioning) { -+ if (data->anon_provisioning) { -+ /* -+ * Unauthenticated provisioning does not provide keying -+ * material and must end with an EAP-Failure. -+ * Authentication will be done separately after this. -+ */ -+ data->success = 0; -+ ret->decision = DECISION_FAIL; -+ } else { -+ /* -+ * Server may or may not allow authenticated -+ * provisioning also for key generation. -+ */ -+ ret->decision = DECISION_COND_SUCC; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV " -+ "- Provisioning completed successfully"); -+ } else { -+ /* -+ * This is PAC refreshing, i.e., normal authentication that is -+ * expected to be completed with an EAP-Success. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV " -+ "- PAC refreshing completed successfully"); -+ ret->decision = DECISION_UNCOND_SUCC; -+ } -+ ret->methodState = METHOD_DONE; -+ return eap_fast_tlv_pac_ack(); -+} -+ -+ -+static int eap_fast_parse_decrypted(struct wpabuf *decrypted, -+ struct eap_fast_tlv_parse *tlv, -+ struct wpabuf **resp) -+{ -+ int mandatory, tlv_type, len, res; -+ u8 *pos, *end; -+ -+ os_memset(tlv, 0, sizeof(*tlv)); -+ -+ /* Parse TLVs from the decrypted Phase 2 data */ -+ pos = wpabuf_mhead(decrypted); -+ end = pos + wpabuf_len(decrypted); -+ while (pos + 4 < end) { -+ mandatory = pos[0] & 0x80; -+ tlv_type = WPA_GET_BE16(pos) & 0x3fff; -+ pos += 2; -+ len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (pos + len > end) { -+ wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " -+ "TLV type %d length %d%s", -+ tlv_type, len, mandatory ? " (mandatory)" : ""); -+ -+ res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); -+ if (res == -2) -+ break; -+ if (res < 0) { -+ if (mandatory) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown " -+ "mandatory TLV type %d", tlv_type); -+ *resp = eap_fast_tlv_nak(0, tlv_type); -+ break; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: ignored " -+ "unknown optional TLV type %d", -+ tlv_type); -+ } -+ } -+ -+ pos += len; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_encrypt_response(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct wpabuf *resp, -+ u8 identifier, struct wpabuf **out_data) -+{ -+ if (resp == NULL) -+ return 0; -+ -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 data", -+ resp); -+ if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST, -+ data->fast_version, identifier, -+ resp, out_data)) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 " -+ "frame"); -+ } -+ wpabuf_free(resp); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_fast_pac_request(void) -+{ -+ struct wpabuf *tmp; -+ u8 *pos, *pos2; -+ -+ tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) + -+ sizeof(struct eap_tlv_request_action_tlv) + -+ sizeof(struct eap_tlv_pac_type_tlv)); -+ if (tmp == NULL) -+ return NULL; -+ -+ pos = wpabuf_put(tmp, 0); -+ pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC); -+ wpabuf_put(tmp, pos2 - pos); -+ return tmp; -+} -+ -+ -+static int eap_fast_process_decrypted(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct eap_method_ret *ret, -+ const struct eap_hdr *req, -+ struct wpabuf *decrypted, -+ struct wpabuf **out_data) -+{ -+ struct wpabuf *resp = NULL, *tmp; -+ struct eap_fast_tlv_parse tlv; -+ int failed = 0; -+ -+ if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0) -+ return 0; -+ if (resp) -+ return eap_fast_encrypt_response(sm, data, resp, -+ req->identifier, out_data); -+ -+ if (tlv.result == EAP_TLV_RESULT_FAILURE) { -+ resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0); -+ return eap_fast_encrypt_response(sm, data, resp, -+ req->identifier, out_data); -+ } -+ -+ if (tlv.iresult == EAP_TLV_RESULT_FAILURE) { -+ resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1); -+ return eap_fast_encrypt_response(sm, data, resp, -+ req->identifier, out_data); -+ } -+ -+ if (tlv.crypto_binding) { -+ tmp = eap_fast_process_crypto_binding(sm, data, ret, -+ tlv.crypto_binding, -+ tlv.crypto_binding_len); -+ if (tmp == NULL) -+ failed = 1; -+ else -+ resp = wpabuf_concat(resp, tmp); -+ } -+ -+ if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) { -+ tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE : -+ EAP_TLV_RESULT_SUCCESS, 1); -+ resp = wpabuf_concat(resp, tmp); -+ } -+ -+ if (tlv.eap_payload_tlv) { -+ tmp = eap_fast_process_eap_payload_tlv( -+ sm, data, ret, req, tlv.eap_payload_tlv, -+ tlv.eap_payload_tlv_len); -+ resp = wpabuf_concat(resp, tmp); -+ } -+ -+ if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV " -+ "acknowledging success"); -+ failed = 1; -+ } else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) { -+ tmp = eap_fast_process_pac(sm, data, ret, tlv.pac, -+ tlv.pac_len); -+ resp = wpabuf_concat(resp, tmp); -+ } -+ -+ if (data->current_pac == NULL && data->provisioning && -+ !data->anon_provisioning && !tlv.pac && -+ (tlv.iresult == EAP_TLV_RESULT_SUCCESS || -+ tlv.result == EAP_TLV_RESULT_SUCCESS)) { -+ /* -+ * Need to request Tunnel PAC when using authenticated -+ * provisioning. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC"); -+ tmp = eap_fast_pac_request(); -+ resp = wpabuf_concat(resp, tmp); -+ } -+ -+ if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) { -+ tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0); -+ resp = wpabuf_concat(tmp, resp); -+ } else if (failed) { -+ tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0); -+ resp = wpabuf_concat(tmp, resp); -+ } -+ -+ if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed && -+ tlv.crypto_binding && data->phase2_success) { -+ if (data->anon_provisioning) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated " -+ "provisioning completed successfully."); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " -+ "completed successfully."); -+ if (data->provisioning) -+ ret->methodState = METHOD_MAY_CONT; -+ else -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ } -+ } -+ -+ if (resp == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send " -+ "empty response packet"); -+ resp = wpabuf_alloc(1); -+ } -+ -+ return eap_fast_encrypt_response(sm, data, resp, req->identifier, -+ out_data); -+} -+ -+ -+static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data, -+ struct eap_method_ret *ret, -+ const struct eap_hdr *req, -+ const struct wpabuf *in_data, -+ struct wpabuf **out_data) -+{ -+ struct wpabuf *in_decrypted; -+ int res; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" -+ " Phase 2", (unsigned long) wpabuf_len(in_data)); -+ -+ if (data->pending_phase2_req) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Pending Phase 2 request - " -+ "skip decryption and use old data"); -+ /* Clear TLS reassembly state. */ -+ eap_peer_tls_reset_input(&data->ssl); -+ -+ in_decrypted = data->pending_phase2_req; -+ data->pending_phase2_req = NULL; -+ goto continue_req; -+ } -+ -+ if (wpabuf_len(in_data) == 0) { -+ /* Received TLS ACK - requesting more fragments */ -+ return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_FAST, -+ data->fast_version, -+ req->identifier, NULL, out_data); -+ } -+ -+ res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); -+ if (res) -+ return res; -+ -+continue_req: -+ wpa_hexdump_buf(MSG_MSGDUMP, "EAP-FAST: Decrypted Phase 2 TLV(s)", -+ in_decrypted); -+ -+ if (wpabuf_len(in_decrypted) < 4) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " -+ "TLV frame (len=%lu)", -+ (unsigned long) wpabuf_len(in_decrypted)); -+ wpabuf_free(in_decrypted); -+ return -1; -+ } -+ -+ res = eap_fast_process_decrypted(sm, data, ret, req, -+ in_decrypted, out_data); -+ -+ wpabuf_free(in_decrypted); -+ -+ return res; -+} -+ -+ -+static const u8 * eap_fast_get_a_id(const u8 *buf, size_t len, size_t *id_len) -+{ -+ const u8 *a_id; -+ struct pac_tlv_hdr *hdr; -+ -+ /* -+ * Parse authority identity (A-ID) from the EAP-FAST/Start. This -+ * supports both raw A-ID and one inside an A-ID TLV. -+ */ -+ a_id = buf; -+ *id_len = len; -+ if (len > sizeof(*hdr)) { -+ int tlen; -+ hdr = (struct pac_tlv_hdr *) buf; -+ tlen = be_to_host16(hdr->len); -+ if (be_to_host16(hdr->type) == PAC_TYPE_A_ID && -+ sizeof(*hdr) + tlen <= len) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: A-ID was in TLV " -+ "(Start)"); -+ a_id = (u8 *) (hdr + 1); -+ *id_len = tlen; -+ } -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: A-ID", a_id, *id_len); -+ -+ return a_id; -+} -+ -+ -+static void eap_fast_select_pac(struct eap_fast_data *data, -+ const u8 *a_id, size_t a_id_len) -+{ -+ data->current_pac = eap_fast_get_pac(data->pac, a_id, a_id_len, -+ PAC_TYPE_TUNNEL_PAC); -+ if (data->current_pac == NULL) { -+ /* -+ * Tunnel PAC was not available for this A-ID. Try to use -+ * Machine Authentication PAC, if one is available. -+ */ -+ data->current_pac = eap_fast_get_pac( -+ data->pac, a_id, a_id_len, -+ PAC_TYPE_MACHINE_AUTHENTICATION); -+ } -+ -+ if (data->current_pac) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC found for this A-ID " -+ "(PAC-Type %d)", data->current_pac->pac_type); -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-FAST: A-ID-Info", -+ data->current_pac->a_id_info, -+ data->current_pac->a_id_info_len); -+ } -+} -+ -+ -+static int eap_fast_use_pac_opaque(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct eap_fast_pac *pac) -+{ -+ u8 *tlv; -+ size_t tlv_len, olen; -+ struct eap_tlv_hdr *ehdr; -+ -+ olen = pac->pac_opaque_len; -+ tlv_len = sizeof(*ehdr) + olen; -+ tlv = os_malloc(tlv_len); -+ if (tlv) { -+ ehdr = (struct eap_tlv_hdr *) tlv; -+ ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE); -+ ehdr->length = host_to_be16(olen); -+ os_memcpy(ehdr + 1, pac->pac_opaque, olen); -+ } -+ if (tlv == NULL || -+ tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn, -+ TLS_EXT_PAC_OPAQUE, -+ tlv, tlv_len) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to add PAC-Opaque TLS " -+ "extension"); -+ os_free(tlv); -+ return -1; -+ } -+ os_free(tlv); -+ -+ return 0; -+} -+ -+ -+static int eap_fast_clear_pac_opaque_ext(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn, -+ TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to remove PAC-Opaque " -+ "TLS extension"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int eap_fast_set_provisioning_ciphers(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ u8 ciphers[5]; -+ int count = 0; -+ -+ if (data->provisioning_allowed & EAP_FAST_PROV_UNAUTH) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling unauthenticated " -+ "provisioning TLS cipher suites"); -+ ciphers[count++] = TLS_CIPHER_ANON_DH_AES128_SHA; -+ } -+ -+ if (data->provisioning_allowed & EAP_FAST_PROV_AUTH) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Enabling authenticated " -+ "provisioning TLS cipher suites"); -+ ciphers[count++] = TLS_CIPHER_RSA_DHE_AES128_SHA; -+ ciphers[count++] = TLS_CIPHER_AES128_SHA; -+ ciphers[count++] = TLS_CIPHER_RC4_SHA; -+ } -+ -+ ciphers[count++] = TLS_CIPHER_NONE; -+ -+ if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn, -+ ciphers)) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Could not configure TLS " -+ "cipher suites for provisioning"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_process_start(struct eap_sm *sm, -+ struct eap_fast_data *data, u8 flags, -+ const u8 *pos, size_t left) -+{ -+ const u8 *a_id; -+ size_t a_id_len; -+ -+ /* EAP-FAST Version negotiation (section 3.1) */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Start (server ver=%d, own ver=%d)", -+ flags & EAP_TLS_VERSION_MASK, data->fast_version); -+ if ((flags & EAP_TLS_VERSION_MASK) < data->fast_version) -+ data->fast_version = flags & EAP_TLS_VERSION_MASK; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Using FAST version %d", -+ data->fast_version); -+ -+ a_id = eap_fast_get_a_id(pos, left, &a_id_len); -+ eap_fast_select_pac(data, a_id, a_id_len); -+ -+ if (data->resuming && data->current_pac) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Trying to resume session - " -+ "do not add PAC-Opaque to TLS ClientHello"); -+ if (eap_fast_clear_pac_opaque_ext(sm, data) < 0) -+ return -1; -+ } else if (data->current_pac) { -+ /* -+ * PAC found for the A-ID and we are not resuming an old -+ * session, so add PAC-Opaque extension to ClientHello. -+ */ -+ if (eap_fast_use_pac_opaque(sm, data, data->current_pac) < 0) -+ return -1; -+ } else { -+ /* No PAC found, so we must provision one. */ -+ if (!data->provisioning_allowed) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found and " -+ "provisioning disabled"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - " -+ "starting provisioning"); -+ if (eap_fast_set_provisioning_ciphers(sm, data) < 0 || -+ eap_fast_clear_pac_opaque_ext(sm, data) < 0) -+ return -1; -+ data->provisioning = 1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ const struct eap_hdr *req; -+ size_t left; -+ int res; -+ u8 flags, id; -+ struct wpabuf *resp; -+ const u8 *pos; -+ struct eap_fast_data *data = priv; -+ -+ pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret, -+ reqData, &left, &flags); -+ if (pos == NULL) -+ return NULL; -+ -+ req = wpabuf_head(reqData); -+ id = req->identifier; -+ -+ if (flags & EAP_TLS_FLAGS_START) { -+ if (eap_fast_process_start(sm, data, flags, pos, left) < 0) -+ return NULL; -+ -+ left = 0; /* A-ID is not used in further packet processing */ -+ } -+ -+ resp = NULL; -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && -+ !data->resuming) { -+ /* Process tunneled (encrypted) phase 2 data. */ -+ struct wpabuf msg; -+ wpabuf_set(&msg, pos, left); -+ res = eap_fast_decrypt(sm, data, ret, req, &msg, &resp); -+ if (res < 0) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ /* -+ * Ack possible Alert that may have caused failure in -+ * decryption. -+ */ -+ res = 1; -+ } -+ } else { -+ /* Continue processing TLS handshake (phase 1). */ -+ res = eap_peer_tls_process_helper(sm, &data->ssl, -+ EAP_TYPE_FAST, -+ data->fast_version, id, pos, -+ left, &resp); -+ -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { -+ char cipher[80]; -+ wpa_printf(MSG_DEBUG, -+ "EAP-FAST: TLS done, proceed to Phase 2"); -+ if (data->provisioning && -+ (!(data->provisioning_allowed & -+ EAP_FAST_PROV_AUTH) || -+ tls_get_cipher(sm->ssl_ctx, data->ssl.conn, -+ cipher, sizeof(cipher)) < 0 || -+ os_strstr(cipher, "ADH-") || -+ os_strstr(cipher, "anon"))) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Using " -+ "anonymous (unauthenticated) " -+ "provisioning"); -+ data->anon_provisioning = 1; -+ } else -+ data->anon_provisioning = 0; -+ data->resuming = 0; -+ eap_fast_derive_keys(sm, data); -+ } -+ -+ if (res == 2) { -+ struct wpabuf msg; -+ /* -+ * Application data included in the handshake message. -+ */ -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = resp; -+ resp = NULL; -+ wpabuf_set(&msg, pos, left); -+ res = eap_fast_decrypt(sm, data, ret, req, &msg, -+ &resp); -+ } -+ } -+ -+ if (res == 1) { -+ wpabuf_free(resp); -+ return eap_peer_tls_build_ack(id, EAP_TYPE_FAST, -+ data->fast_version); -+ } -+ -+ return resp; -+} -+ -+ -+#if 0 /* FIX */ -+static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn); -+} -+ -+ -+static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ os_free(data->key_block_p); -+ data->key_block_p = NULL; -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = NULL; -+} -+ -+ -+static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ if (eap_peer_tls_reauth_init(sm, &data->ssl)) { -+ os_free(data); -+ return NULL; -+ } -+ if (data->phase2_priv && data->phase2_method && -+ data->phase2_method->init_for_reauth) -+ data->phase2_method->init_for_reauth(sm, data->phase2_priv); -+ data->phase2_success = 0; -+ data->resuming = 1; -+ data->provisioning = 0; -+ data->anon_provisioning = 0; -+ data->simck_idx = 0; -+ return priv; -+} -+#endif -+ -+ -+static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf, -+ size_t buflen, int verbose) -+{ -+ struct eap_fast_data *data = priv; -+ int len, ret; -+ -+ len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); -+ if (data->phase2_method) { -+ ret = os_snprintf(buf + len, buflen - len, -+ "EAP-FAST Phase2 method=%s\n", -+ data->phase2_method->name); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ } -+ return len; -+} -+ -+ -+static Boolean eap_fast_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ return data->success; -+} -+ -+ -+static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_fast_data *data = priv; -+ u8 *key; -+ -+ if (!data->success) -+ return NULL; -+ -+ key = os_malloc(EAP_FAST_KEY_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_FAST_KEY_LEN; -+ os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN); -+ -+ return key; -+} -+ -+ -+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_fast_data *data = priv; -+ u8 *key; -+ -+ if (!data->success) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_EMSK_LEN; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ -+ return key; -+} -+ -+ -+int eap_peer_fast_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_fast_init; -+ eap->deinit = eap_fast_deinit; -+ eap->process = eap_fast_process; -+ eap->isKeyAvailable = eap_fast_isKeyAvailable; -+ eap->getKey = eap_fast_getKey; -+ eap->get_status = eap_fast_get_status; -+#if 0 -+ eap->has_reauth_data = eap_fast_has_reauth_data; -+ eap->deinit_for_reauth = eap_fast_deinit_for_reauth; -+ eap->init_for_reauth = eap_fast_init_for_reauth; -+#endif -+ eap->get_emsk = eap_fast_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.c -new file mode 100644 -index 0000000000000..403728808abcf ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.c -@@ -0,0 +1,923 @@ -+/* -+ * EAP peer method: EAP-FAST PAC file processing -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_config.h" -+#include "eap_i.h" -+#include "eap_fast_pac.h" -+ -+/* TODO: encrypt PAC-Key in the PAC file */ -+ -+ -+/* Text data format */ -+static const char *pac_file_hdr = -+ "wpa_supplicant EAP-FAST PAC file - version 1"; -+ -+/* -+ * Binary data format -+ * 4-octet magic value: 6A E4 92 0C -+ * 2-octet version (big endian) -+ * -+ * -+ * version=0: -+ * Sequence of PAC entries: -+ * 2-octet PAC-Type (big endian) -+ * 32-octet PAC-Key -+ * 2-octet PAC-Opaque length (big endian) -+ * PAC-Opaque data (length bytes) -+ * 2-octet PAC-Info length (big endian) -+ * PAC-Info data (length bytes) -+ */ -+ -+#define EAP_FAST_PAC_BINARY_MAGIC 0x6ae4920c -+#define EAP_FAST_PAC_BINARY_FORMAT_VERSION 0 -+ -+ -+/** -+ * eap_fast_free_pac - Free PAC data -+ * @pac: Pointer to the PAC entry -+ * -+ * Note that the PAC entry must not be in a list since this function does not -+ * remove the list links. -+ */ -+void eap_fast_free_pac(struct eap_fast_pac *pac) -+{ -+ os_free(pac->pac_opaque); -+ os_free(pac->pac_info); -+ os_free(pac->a_id); -+ os_free(pac->i_id); -+ os_free(pac->a_id_info); -+ os_free(pac); -+} -+ -+ -+/** -+ * eap_fast_get_pac - Get a PAC entry based on A-ID -+ * @pac_root: Pointer to root of the PAC list -+ * @a_id: A-ID to search for -+ * @a_id_len: Length of A-ID -+ * @pac_type: PAC-Type to search for -+ * Returns: Pointer to the PAC entry, or %NULL if A-ID not found -+ */ -+struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root, -+ const u8 *a_id, size_t a_id_len, -+ u16 pac_type) -+{ -+ struct eap_fast_pac *pac = pac_root; -+ -+ while (pac) { -+ if (pac->pac_type == pac_type && pac->a_id_len == a_id_len && -+ os_memcmp(pac->a_id, a_id, a_id_len) == 0) { -+ return pac; -+ } -+ pac = pac->next; -+ } -+ return NULL; -+} -+ -+ -+static void eap_fast_remove_pac(struct eap_fast_pac **pac_root, -+ struct eap_fast_pac **pac_current, -+ const u8 *a_id, size_t a_id_len, u16 pac_type) -+{ -+ struct eap_fast_pac *pac, *prev; -+ -+ pac = *pac_root; -+ prev = NULL; -+ -+ while (pac) { -+ if (pac->pac_type == pac_type && pac->a_id_len == a_id_len && -+ os_memcmp(pac->a_id, a_id, a_id_len) == 0) { -+ if (prev == NULL) -+ *pac_root = pac->next; -+ else -+ prev->next = pac->next; -+ if (*pac_current == pac) -+ *pac_current = NULL; -+ eap_fast_free_pac(pac); -+ break; -+ } -+ prev = pac; -+ pac = pac->next; -+ } -+} -+ -+ -+static int eap_fast_copy_buf(u8 **dst, size_t *dst_len, -+ const u8 *src, size_t src_len) -+{ -+ if (src) { -+ *dst = os_malloc(src_len); -+ if (*dst == NULL) -+ return -1; -+ os_memcpy(*dst, src, src_len); -+ *dst_len = src_len; -+ } -+ return 0; -+} -+ -+ -+/** -+ * eap_fast_add_pac - Add a copy of a PAC entry to a list -+ * @pac_root: Pointer to PAC list root pointer -+ * @pac_current: Pointer to the current PAC pointer -+ * @entry: New entry to clone and add to the list -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function makes a clone of the given PAC entry and adds this copied -+ * entry to the list (pac_root). If an old entry for the same A-ID is found, -+ * it will be removed from the PAC list and in this case, pac_current entry -+ * is set to %NULL if it was the removed entry. -+ */ -+int eap_fast_add_pac(struct eap_fast_pac **pac_root, -+ struct eap_fast_pac **pac_current, -+ struct eap_fast_pac *entry) -+{ -+ struct eap_fast_pac *pac; -+ -+ if (entry == NULL || entry->a_id == NULL) -+ return -1; -+ -+ /* Remove a possible old entry for the matching A-ID. */ -+ eap_fast_remove_pac(pac_root, pac_current, -+ entry->a_id, entry->a_id_len, entry->pac_type); -+ -+ /* Allocate a new entry and add it to the list of PACs. */ -+ pac = os_zalloc(sizeof(*pac)); -+ if (pac == NULL) -+ return -1; -+ -+ pac->pac_type = entry->pac_type; -+ os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN); -+ if (eap_fast_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len, -+ entry->pac_opaque, entry->pac_opaque_len) < 0 || -+ eap_fast_copy_buf(&pac->pac_info, &pac->pac_info_len, -+ entry->pac_info, entry->pac_info_len) < 0 || -+ eap_fast_copy_buf(&pac->a_id, &pac->a_id_len, -+ entry->a_id, entry->a_id_len) < 0 || -+ eap_fast_copy_buf(&pac->i_id, &pac->i_id_len, -+ entry->i_id, entry->i_id_len) < 0 || -+ eap_fast_copy_buf(&pac->a_id_info, &pac->a_id_info_len, -+ entry->a_id_info, entry->a_id_info_len) < 0) { -+ eap_fast_free_pac(pac); -+ return -1; -+ } -+ -+ pac->next = *pac_root; -+ *pac_root = pac; -+ -+ return 0; -+} -+ -+ -+struct eap_fast_read_ctx { -+ FILE *f; -+ const char *pos; -+ const char *end; -+ int line; -+ char *buf; -+ size_t buf_len; -+}; -+ -+static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char **value) -+{ -+ char *pos; -+ -+ rc->line++; -+ if (rc->f) { -+ if (fgets(rc->buf, rc->buf_len, rc->f) == NULL) -+ return -1; -+ } else { -+ const char *l_end; -+ size_t len; -+ if (rc->pos >= rc->end) -+ return -1; -+ l_end = rc->pos; -+ while (l_end < rc->end && *l_end != '\n') -+ l_end++; -+ len = l_end - rc->pos; -+ if (len >= rc->buf_len) -+ len = rc->buf_len - 1; -+ os_memcpy(rc->buf, rc->pos, len); -+ rc->buf[len] = '\0'; -+ rc->pos = l_end + 1; -+ } -+ -+ rc->buf[rc->buf_len - 1] = '\0'; -+ pos = rc->buf; -+ while (*pos != '\0') { -+ if (*pos == '\n' || *pos == '\r') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+ -+ pos = os_strchr(rc->buf, '='); -+ if (pos) -+ *pos++ = '\0'; -+ *value = pos; -+ -+ return 0; -+} -+ -+ -+static u8 * eap_fast_parse_hex(const char *value, size_t *len) -+{ -+ int hlen; -+ u8 *buf; -+ -+ if (value == NULL) -+ return NULL; -+ hlen = os_strlen(value); -+ if (hlen & 1) -+ return NULL; -+ *len = hlen / 2; -+ buf = os_malloc(*len); -+ if (buf == NULL) -+ return NULL; -+ if (hexstr2bin(value, buf, *len)) { -+ os_free(buf); -+ return NULL; -+ } -+ return buf; -+} -+ -+ -+static int eap_fast_init_pac_data(struct eap_sm *sm, const char *pac_file, -+ struct eap_fast_read_ctx *rc) -+{ -+ os_memset(rc, 0, sizeof(*rc)); -+ -+ rc->buf_len = 2048; -+ rc->buf = os_malloc(rc->buf_len); -+ if (rc->buf == NULL) -+ return -1; -+ -+ if (os_strncmp(pac_file, "blob://", 7) == 0) { -+ const struct wpa_config_blob *blob; -+ blob = eap_get_config_blob(sm, pac_file + 7); -+ if (blob == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - " -+ "assume no PAC entries have been " -+ "provisioned", pac_file + 7); -+ os_free(rc->buf); -+ return -1; -+ } -+ rc->pos = (char *) blob->data; -+ rc->end = (char *) blob->data + blob->len; -+ } else { -+ rc->f = fopen(pac_file, "rb"); -+ if (rc->f == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - " -+ "assume no PAC entries have been " -+ "provisioned", pac_file); -+ os_free(rc->buf); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_fast_deinit_pac_data(struct eap_fast_read_ctx *rc) -+{ -+ os_free(rc->buf); -+ if (rc->f) -+ fclose(rc->f); -+} -+ -+ -+static const char * eap_fast_parse_start(struct eap_fast_pac **pac) -+{ -+ if (*pac) -+ return "START line without END"; -+ -+ *pac = os_zalloc(sizeof(struct eap_fast_pac)); -+ if (*pac == NULL) -+ return "No memory for PAC entry"; -+ (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC; -+ return NULL; -+} -+ -+ -+static const char * eap_fast_parse_end(struct eap_fast_pac **pac_root, -+ struct eap_fast_pac **pac) -+{ -+ if (*pac == NULL) -+ return "END line without START"; -+ if (*pac_root) { -+ struct eap_fast_pac *end = *pac_root; -+ while (end->next) -+ end = end->next; -+ end->next = *pac; -+ } else -+ *pac_root = *pac; -+ -+ *pac = NULL; -+ return NULL; -+} -+ -+ -+static const char * eap_fast_parse_pac_type(struct eap_fast_pac *pac, -+ char *pos) -+{ -+ pac->pac_type = atoi(pos); -+ if (pac->pac_type != PAC_TYPE_TUNNEL_PAC && -+ pac->pac_type != PAC_TYPE_USER_AUTHORIZATION && -+ pac->pac_type != PAC_TYPE_MACHINE_AUTHENTICATION) -+ return "Unrecognized PAC-Type"; -+ -+ return NULL; -+} -+ -+ -+static const char * eap_fast_parse_pac_key(struct eap_fast_pac *pac, char *pos) -+{ -+ u8 *key; -+ size_t key_len; -+ -+ key = eap_fast_parse_hex(pos, &key_len); -+ if (key == NULL || key_len != EAP_FAST_PAC_KEY_LEN) { -+ os_free(key); -+ return "Invalid PAC-Key"; -+ } -+ -+ os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN); -+ os_free(key); -+ -+ return NULL; -+} -+ -+ -+static const char * eap_fast_parse_pac_opaque(struct eap_fast_pac *pac, -+ char *pos) -+{ -+ os_free(pac->pac_opaque); -+ pac->pac_opaque = eap_fast_parse_hex(pos, &pac->pac_opaque_len); -+ if (pac->pac_opaque == NULL) -+ return "Invalid PAC-Opaque"; -+ return NULL; -+} -+ -+ -+static const char * eap_fast_parse_a_id(struct eap_fast_pac *pac, char *pos) -+{ -+ os_free(pac->a_id); -+ pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len); -+ if (pac->a_id == NULL) -+ return "Invalid A-ID"; -+ return NULL; -+} -+ -+ -+static const char * eap_fast_parse_i_id(struct eap_fast_pac *pac, char *pos) -+{ -+ os_free(pac->i_id); -+ pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len); -+ if (pac->i_id == NULL) -+ return "Invalid I-ID"; -+ return NULL; -+} -+ -+ -+static const char * eap_fast_parse_a_id_info(struct eap_fast_pac *pac, -+ char *pos) -+{ -+ os_free(pac->a_id_info); -+ pac->a_id_info = eap_fast_parse_hex(pos, &pac->a_id_info_len); -+ if (pac->a_id_info == NULL) -+ return "Invalid A-ID-Info"; -+ return NULL; -+} -+ -+ -+/** -+ * eap_fast_load_pac - Load PAC entries (text format) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @pac_root: Pointer to root of the PAC list (to be filled) -+ * @pac_file: Name of the PAC file/blob to load -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root, -+ const char *pac_file) -+{ -+ struct eap_fast_read_ctx rc; -+ struct eap_fast_pac *pac = NULL; -+ int count = 0; -+ char *pos; -+ const char *err = NULL; -+ -+ if (pac_file == NULL) -+ return -1; -+ -+ if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0) -+ return 0; -+ -+ if (eap_fast_read_line(&rc, &pos) < 0 || -+ os_strcmp(pac_file_hdr, rc.buf) != 0) -+ err = "Unrecognized header line"; -+ -+ while (!err && eap_fast_read_line(&rc, &pos) == 0) { -+ if (os_strcmp(rc.buf, "START") == 0) -+ err = eap_fast_parse_start(&pac); -+ else if (os_strcmp(rc.buf, "END") == 0) { -+ err = eap_fast_parse_end(pac_root, &pac); -+ count++; -+ } else if (!pac) -+ err = "Unexpected line outside START/END block"; -+ else if (os_strcmp(rc.buf, "PAC-Type") == 0) -+ err = eap_fast_parse_pac_type(pac, pos); -+ else if (os_strcmp(rc.buf, "PAC-Key") == 0) -+ err = eap_fast_parse_pac_key(pac, pos); -+ else if (os_strcmp(rc.buf, "PAC-Opaque") == 0) -+ err = eap_fast_parse_pac_opaque(pac, pos); -+ else if (os_strcmp(rc.buf, "A-ID") == 0) -+ err = eap_fast_parse_a_id(pac, pos); -+ else if (os_strcmp(rc.buf, "I-ID") == 0) -+ err = eap_fast_parse_i_id(pac, pos); -+ else if (os_strcmp(rc.buf, "A-ID-Info") == 0) -+ err = eap_fast_parse_a_id_info(pac, pos); -+ } -+ -+ if (pac) { -+ err = "PAC block not terminated with END"; -+ eap_fast_free_pac(pac); -+ } -+ -+ eap_fast_deinit_pac_data(&rc); -+ -+ if (err) { -+ wpa_printf(MSG_INFO, "EAP-FAST: %s in '%s:%d'", -+ err, pac_file, rc.line); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Read %d PAC entries from '%s'", -+ count, pac_file); -+ -+ return 0; -+} -+ -+ -+static void eap_fast_write(char **buf, char **pos, size_t *buf_len, -+ const char *field, const u8 *data, -+ size_t len, int txt) -+{ -+ size_t i, need; -+ int ret; -+ char *end; -+ -+ if (data == NULL || buf == NULL || *buf == NULL || -+ pos == NULL || *pos == NULL || *pos < *buf) -+ return; -+ -+ need = os_strlen(field) + len * 2 + 30; -+ if (txt) -+ need += os_strlen(field) + len + 20; -+ -+ if (*pos - *buf + need > *buf_len) { -+ char *nbuf = os_realloc(*buf, *buf_len + need); -+ if (nbuf == NULL) { -+ os_free(*buf); -+ *buf = NULL; -+ return; -+ } -+ *pos = nbuf + (*pos - *buf); -+ *buf = nbuf; -+ *buf_len += need; -+ } -+ end = *buf + *buf_len; -+ -+ ret = os_snprintf(*pos, end - *pos, "%s=", field); -+ if (ret < 0 || ret >= end - *pos) -+ return; -+ *pos += ret; -+ *pos += wpa_snprintf_hex(*pos, end - *pos, data, len); -+ ret = os_snprintf(*pos, end - *pos, "\n"); -+ if (ret < 0 || ret >= end - *pos) -+ return; -+ *pos += ret; -+ -+ if (txt) { -+ ret = os_snprintf(*pos, end - *pos, "%s-txt=", field); -+ if (ret < 0 || ret >= end - *pos) -+ return; -+ *pos += ret; -+ for (i = 0; i < len; i++) { -+ ret = os_snprintf(*pos, end - *pos, "%c", data[i]); -+ if (ret < 0 || ret >= end - *pos) -+ return; -+ *pos += ret; -+ } -+ ret = os_snprintf(*pos, end - *pos, "\n"); -+ if (ret < 0 || ret >= end - *pos) -+ return; -+ *pos += ret; -+ } -+} -+ -+ -+static int eap_fast_write_pac(struct eap_sm *sm, const char *pac_file, -+ char *buf, size_t len) -+{ -+ if (os_strncmp(pac_file, "blob://", 7) == 0) { -+ struct wpa_config_blob *blob; -+ blob = os_zalloc(sizeof(*blob)); -+ if (blob == NULL) -+ return -1; -+ blob->data = (u8 *) buf; -+ blob->len = len; -+ buf = NULL; -+ blob->name = os_strdup(pac_file + 7); -+ if (blob->name == NULL) { -+ os_free(blob); -+ return -1; -+ } -+ eap_set_config_blob(sm, blob); -+ } else { -+ FILE *f; -+ f = fopen(pac_file, "wb"); -+ if (f == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC " -+ "file '%s' for writing", pac_file); -+ return -1; -+ } -+ if (fwrite(buf, 1, len, f) != len) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to write all " -+ "PACs into '%s'", pac_file); -+ fclose(f); -+ return -1; -+ } -+ os_free(buf); -+ fclose(f); -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_add_pac_data(struct eap_fast_pac *pac, char **buf, -+ char **pos, size_t *buf_len) -+{ -+ int ret; -+ -+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, -+ "START\nPAC-Type=%d\n", pac->pac_type); -+ if (ret < 0 || ret >= *buf + *buf_len - *pos) -+ return -1; -+ -+ *pos += ret; -+ eap_fast_write(buf, pos, buf_len, "PAC-Key", -+ pac->pac_key, EAP_FAST_PAC_KEY_LEN, 0); -+ eap_fast_write(buf, pos, buf_len, "PAC-Opaque", -+ pac->pac_opaque, pac->pac_opaque_len, 0); -+ eap_fast_write(buf, pos, buf_len, "PAC-Info", -+ pac->pac_info, pac->pac_info_len, 0); -+ eap_fast_write(buf, pos, buf_len, "A-ID", -+ pac->a_id, pac->a_id_len, 0); -+ eap_fast_write(buf, pos, buf_len, "I-ID", -+ pac->i_id, pac->i_id_len, 1); -+ eap_fast_write(buf, pos, buf_len, "A-ID-Info", -+ pac->a_id_info, pac->a_id_info_len, 1); -+ if (*buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC " -+ "data"); -+ return -1; -+ } -+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n"); -+ if (ret < 0 || ret >= *buf + *buf_len - *pos) -+ return -1; -+ *pos += ret; -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_fast_save_pac - Save PAC entries (text format) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @pac_root: Root of the PAC list -+ * @pac_file: Name of the PAC file/blob -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root, -+ const char *pac_file) -+{ -+ struct eap_fast_pac *pac; -+ int ret, count = 0; -+ char *buf, *pos; -+ size_t buf_len; -+ -+ if (pac_file == NULL) -+ return -1; -+ -+ buf_len = 1024; -+ pos = buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return -1; -+ -+ ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr); -+ if (ret < 0 || ret >= buf + buf_len - pos) { -+ os_free(buf); -+ return -1; -+ } -+ pos += ret; -+ -+ pac = pac_root; -+ while (pac) { -+ if (eap_fast_add_pac_data(pac, &buf, &pos, &buf_len)) { -+ os_free(buf); -+ return -1; -+ } -+ count++; -+ pac = pac->next; -+ } -+ -+ if (eap_fast_write_pac(sm, pac_file, buf, pos - buf)) { -+ os_free(buf); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %d PAC entries into '%s'", -+ count, pac_file); -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_fast_pac_list_truncate - Truncate a PAC list to the given length -+ * @pac_root: Root of the PAC list -+ * @max_len: Maximum length of the list (>= 1) -+ * Returns: Number of PAC entries removed -+ */ -+size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root, -+ size_t max_len) -+{ -+ struct eap_fast_pac *pac, *prev; -+ size_t count; -+ -+ pac = pac_root; -+ prev = NULL; -+ count = 0; -+ -+ while (pac) { -+ count++; -+ if (count > max_len) -+ break; -+ prev = pac; -+ pac = pac->next; -+ } -+ -+ if (count <= max_len || prev == NULL) -+ return 0; -+ -+ count = 0; -+ prev->next = NULL; -+ -+ while (pac) { -+ prev = pac; -+ pac = pac->next; -+ eap_fast_free_pac(prev); -+ count++; -+ } -+ -+ return count; -+} -+ -+ -+static void eap_fast_pac_get_a_id(struct eap_fast_pac *pac) -+{ -+ u8 *pos, *end; -+ u16 type, len; -+ -+ pos = pac->pac_info; -+ end = pos + pac->pac_info_len; -+ -+ while (pos + 4 < end) { -+ type = WPA_GET_BE16(pos); -+ pos += 2; -+ len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (pos + len > end) -+ break; -+ -+ if (type == PAC_TYPE_A_ID) { -+ os_free(pac->a_id); -+ pac->a_id = os_malloc(len); -+ if (pac->a_id == NULL) -+ break; -+ os_memcpy(pac->a_id, pos, len); -+ pac->a_id_len = len; -+ } -+ -+ if (type == PAC_TYPE_A_ID_INFO) { -+ os_free(pac->a_id_info); -+ pac->a_id_info = os_malloc(len); -+ if (pac->a_id_info == NULL) -+ break; -+ os_memcpy(pac->a_id_info, pos, len); -+ pac->a_id_info_len = len; -+ } -+ -+ pos += len; -+ } -+} -+ -+ -+/** -+ * eap_fast_load_pac_bin - Load PAC entries (binary format) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @pac_root: Pointer to root of the PAC list (to be filled) -+ * @pac_file: Name of the PAC file/blob to load -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root, -+ const char *pac_file) -+{ -+ const struct wpa_config_blob *blob = NULL; -+ u8 *buf, *end, *pos; -+ size_t len, count = 0; -+ struct eap_fast_pac *pac, *prev; -+ -+ *pac_root = NULL; -+ -+ if (pac_file == NULL) -+ return -1; -+ -+ if (os_strncmp(pac_file, "blob://", 7) == 0) { -+ blob = eap_get_config_blob(sm, pac_file + 7); -+ if (blob == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - " -+ "assume no PAC entries have been " -+ "provisioned", pac_file + 7); -+ return 0; -+ } -+ buf = blob->data; -+ len = blob->len; -+ } else { -+ buf = (u8 *) os_readfile(pac_file, &len); -+ if (buf == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - " -+ "assume no PAC entries have been " -+ "provisioned", pac_file); -+ return 0; -+ } -+ } -+ -+ if (len == 0) { -+ if (blob == NULL) -+ os_free(buf); -+ return 0; -+ } -+ -+ if (len < 6 || WPA_GET_BE32(buf) != EAP_FAST_PAC_BINARY_MAGIC || -+ WPA_GET_BE16(buf + 4) != EAP_FAST_PAC_BINARY_FORMAT_VERSION) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC file '%s' (bin)", -+ pac_file); -+ if (blob == NULL) -+ os_free(buf); -+ return -1; -+ } -+ -+ pac = prev = NULL; -+ pos = buf + 6; -+ end = buf + len; -+ while (pos < end) { -+ if (end - pos < 2 + 32 + 2 + 2) -+ goto parse_fail; -+ -+ pac = os_zalloc(sizeof(*pac)); -+ if (pac == NULL) -+ goto parse_fail; -+ -+ pac->pac_type = WPA_GET_BE16(pos); -+ pos += 2; -+ os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN); -+ pos += EAP_FAST_PAC_KEY_LEN; -+ pac->pac_opaque_len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (pos + pac->pac_opaque_len + 2 > end) -+ goto parse_fail; -+ pac->pac_opaque = os_malloc(pac->pac_opaque_len); -+ if (pac->pac_opaque == NULL) -+ goto parse_fail; -+ os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len); -+ pos += pac->pac_opaque_len; -+ pac->pac_info_len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (pos + pac->pac_info_len > end) -+ goto parse_fail; -+ pac->pac_info = os_malloc(pac->pac_info_len); -+ if (pac->pac_info == NULL) -+ goto parse_fail; -+ os_memcpy(pac->pac_info, pos, pac->pac_info_len); -+ pos += pac->pac_info_len; -+ eap_fast_pac_get_a_id(pac); -+ -+ count++; -+ if (prev) -+ prev->next = pac; -+ else -+ *pac_root = pac; -+ prev = pac; -+ } -+ -+ if (blob == NULL) -+ os_free(buf); -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Read %lu PAC entries from '%s' (bin)", -+ (unsigned long) count, pac_file); -+ -+ return 0; -+ -+parse_fail: -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to parse PAC file '%s' (bin)", -+ pac_file); -+ if (blob == NULL) -+ os_free(buf); -+ if (pac) -+ eap_fast_free_pac(pac); -+ return -1; -+} -+ -+ -+/** -+ * eap_fast_save_pac_bin - Save PAC entries (binary format) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @pac_root: Root of the PAC list -+ * @pac_file: Name of the PAC file/blob -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root, -+ const char *pac_file) -+{ -+ size_t len, count = 0; -+ struct eap_fast_pac *pac; -+ u8 *buf, *pos; -+ -+ len = 6; -+ pac = pac_root; -+ while (pac) { -+ if (pac->pac_opaque_len > 65535 || -+ pac->pac_info_len > 65535) -+ return -1; -+ len += 2 + EAP_FAST_PAC_KEY_LEN + 2 + pac->pac_opaque_len + -+ 2 + pac->pac_info_len; -+ pac = pac->next; -+ } -+ -+ buf = os_malloc(len); -+ if (buf == NULL) -+ return -1; -+ -+ pos = buf; -+ WPA_PUT_BE32(pos, EAP_FAST_PAC_BINARY_MAGIC); -+ pos += 4; -+ WPA_PUT_BE16(pos, EAP_FAST_PAC_BINARY_FORMAT_VERSION); -+ pos += 2; -+ -+ pac = pac_root; -+ while (pac) { -+ WPA_PUT_BE16(pos, pac->pac_type); -+ pos += 2; -+ os_memcpy(pos, pac->pac_key, EAP_FAST_PAC_KEY_LEN); -+ pos += EAP_FAST_PAC_KEY_LEN; -+ WPA_PUT_BE16(pos, pac->pac_opaque_len); -+ pos += 2; -+ os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len); -+ pos += pac->pac_opaque_len; -+ WPA_PUT_BE16(pos, pac->pac_info_len); -+ pos += 2; -+ os_memcpy(pos, pac->pac_info, pac->pac_info_len); -+ pos += pac->pac_info_len; -+ -+ pac = pac->next; -+ count++; -+ } -+ -+ if (eap_fast_write_pac(sm, pac_file, (char *) buf, len)) { -+ os_free(buf); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Wrote %lu PAC entries into '%s' " -+ "(bin)", (unsigned long) count, pac_file); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.h -new file mode 100644 -index 0000000000000..9483f96852c65 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_fast_pac.h -@@ -0,0 +1,56 @@ -+/* -+ * EAP peer method: EAP-FAST PAC file processing -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_FAST_PAC_H -+#define EAP_FAST_PAC_H -+ -+#include "eap_common/eap_fast_common.h" -+ -+struct eap_fast_pac { -+ struct eap_fast_pac *next; -+ -+ u8 pac_key[EAP_FAST_PAC_KEY_LEN]; -+ u8 *pac_opaque; -+ size_t pac_opaque_len; -+ u8 *pac_info; -+ size_t pac_info_len; -+ u8 *a_id; -+ size_t a_id_len; -+ u8 *i_id; -+ size_t i_id_len; -+ u8 *a_id_info; -+ size_t a_id_info_len; -+ u16 pac_type; -+}; -+ -+ -+void eap_fast_free_pac(struct eap_fast_pac *pac); -+struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_pac *pac_root, -+ const u8 *a_id, size_t a_id_len, -+ u16 pac_type); -+int eap_fast_add_pac(struct eap_fast_pac **pac_root, -+ struct eap_fast_pac **pac_current, -+ struct eap_fast_pac *entry); -+int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root, -+ const char *pac_file); -+int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_pac *pac_root, -+ const char *pac_file); -+size_t eap_fast_pac_list_truncate(struct eap_fast_pac *pac_root, -+ size_t max_len); -+int eap_fast_load_pac_bin(struct eap_sm *sm, struct eap_fast_pac **pac_root, -+ const char *pac_file); -+int eap_fast_save_pac_bin(struct eap_sm *sm, struct eap_fast_pac *pac_root, -+ const char *pac_file); -+ -+#endif /* EAP_FAST_PAC_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gpsk.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gpsk.c -new file mode 100644 -index 0000000000000..5037c600acdfb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gpsk.c -@@ -0,0 +1,738 @@ -+/* -+ * EAP peer method: EAP-GPSK (RFC 5433) -+ * Copyright (c) 2006-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_peer/eap_i.h" -+#include "eap_common/eap_gpsk_common.h" -+ -+struct eap_gpsk_data { -+ enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; -+ u8 rand_server[EAP_GPSK_RAND_LEN]; -+ u8 rand_peer[EAP_GPSK_RAND_LEN]; -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 sk[EAP_GPSK_MAX_SK_LEN]; -+ size_t sk_len; -+ u8 pk[EAP_GPSK_MAX_PK_LEN]; -+ size_t pk_len; -+ u8 session_id; -+ int session_id_set; -+ u8 *id_peer; -+ size_t id_peer_len; -+ u8 *id_server; -+ size_t id_server_len; -+ int vendor; /* CSuite/Specifier */ -+ int specifier; /* CSuite/Specifier */ -+ u8 *psk; -+ size_t psk_len; -+}; -+ -+ -+static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, -+ u8 identifier, -+ const u8 *csuite_list, -+ size_t csuite_list_len); -+static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, -+ u8 identifier); -+ -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+static const char * eap_gpsk_state_txt(int state) -+{ -+ switch (state) { -+ case GPSK_1: -+ return "GPSK-1"; -+ case GPSK_3: -+ return "GPSK-3"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "?"; -+ } -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+static void eap_gpsk_state(struct eap_gpsk_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", -+ eap_gpsk_state_txt(data->state), -+ eap_gpsk_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void eap_gpsk_deinit(struct eap_sm *sm, void *priv); -+ -+ -+static void * eap_gpsk_init(struct eap_sm *sm) -+{ -+ struct eap_gpsk_data *data; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ password = eap_get_config_password(sm, &password_len); -+ if (password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = GPSK_1; -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity) { -+ data->id_peer = os_malloc(identity_len); -+ if (data->id_peer == NULL) { -+ eap_gpsk_deinit(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->id_peer, identity, identity_len); -+ data->id_peer_len = identity_len; -+ } -+ -+ data->psk = os_malloc(password_len); -+ if (data->psk == NULL) { -+ eap_gpsk_deinit(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->psk, password, password_len); -+ data->psk_len = password_len; -+ -+ return data; -+} -+ -+ -+static void eap_gpsk_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gpsk_data *data = priv; -+ os_free(data->id_server); -+ os_free(data->id_peer); -+ os_free(data->psk); -+ os_free(data); -+} -+ -+ -+static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data, -+ const u8 *pos, const u8 *end) -+{ -+ u16 alen; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); -+ return NULL; -+ } -+ alen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < alen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow"); -+ return NULL; -+ } -+ os_free(data->id_server); -+ data->id_server = os_malloc(alen); -+ if (data->id_server == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server"); -+ return NULL; -+ } -+ os_memcpy(data->id_server, pos, alen); -+ data->id_server_len = alen; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server", -+ data->id_server, data->id_server_len); -+ pos += alen; -+ -+ return pos; -+} -+ -+ -+static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data, -+ const u8 *pos, const u8 *end) -+{ -+ if (pos == NULL) -+ return NULL; -+ -+ if (end - pos < EAP_GPSK_RAND_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow"); -+ return NULL; -+ } -+ os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server", -+ data->rand_server, EAP_GPSK_RAND_LEN); -+ pos += EAP_GPSK_RAND_LEN; -+ -+ return pos; -+} -+ -+ -+static int eap_gpsk_select_csuite(struct eap_sm *sm, -+ struct eap_gpsk_data *data, -+ const u8 *csuite_list, -+ size_t csuite_list_len) -+{ -+ struct eap_gpsk_csuite *csuite; -+ int i, count; -+ -+ count = csuite_list_len / sizeof(struct eap_gpsk_csuite); -+ data->vendor = EAP_GPSK_VENDOR_IETF; -+ data->specifier = EAP_GPSK_CIPHER_RESERVED; -+ csuite = (struct eap_gpsk_csuite *) csuite_list; -+ for (i = 0; i < count; i++) { -+ int vendor, specifier; -+ vendor = WPA_GET_BE32(csuite->vendor); -+ specifier = WPA_GET_BE16(csuite->specifier); -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d", -+ i, vendor, specifier); -+ if (data->vendor == EAP_GPSK_VENDOR_IETF && -+ data->specifier == EAP_GPSK_CIPHER_RESERVED && -+ eap_gpsk_supported_ciphersuite(vendor, specifier)) { -+ data->vendor = vendor; -+ data->specifier = specifier; -+ } -+ csuite++; -+ } -+ if (data->vendor == EAP_GPSK_VENDOR_IETF && -+ data->specifier == EAP_GPSK_CIPHER_RESERVED) { -+ wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported " -+ "ciphersuite found"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d", -+ data->vendor, data->specifier); -+ -+ return 0; -+} -+ -+ -+static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm, -+ struct eap_gpsk_data *data, -+ const u8 **list, -+ size_t *list_len, -+ const u8 *pos, const u8 *end) -+{ -+ if (pos == NULL) -+ return NULL; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); -+ return NULL; -+ } -+ *list_len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < (int) *list_len) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow"); -+ return NULL; -+ } -+ if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu", -+ (unsigned long) *list_len); -+ return NULL; -+ } -+ *list = pos; -+ pos += *list_len; -+ -+ if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0) -+ return NULL; -+ -+ return pos; -+} -+ -+ -+static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm, -+ struct eap_gpsk_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, -+ size_t payload_len) -+{ -+ size_t csuite_list_len; -+ const u8 *csuite_list, *pos, *end; -+ struct wpabuf *resp; -+ -+ if (data->state != GPSK_1) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1"); -+ -+ end = payload + payload_len; -+ -+ pos = eap_gpsk_process_id_server(data, payload, end); -+ pos = eap_gpsk_process_rand_server(data, pos, end); -+ pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list, -+ &csuite_list_len, pos, end); -+ if (pos == NULL) { -+ eap_gpsk_state(data, FAILURE); -+ return NULL; -+ } -+ -+ resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData), -+ csuite_list, csuite_list_len); -+ if (resp == NULL) -+ return NULL; -+ -+ eap_gpsk_state(data, GPSK_3); -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, -+ u8 identifier, -+ const u8 *csuite_list, -+ size_t csuite_list_len) -+{ -+ struct wpabuf *resp; -+ size_t len, miclen; -+ u8 *rpos, *start; -+ struct eap_gpsk_csuite *csuite; -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2"); -+ -+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier); -+ len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len + -+ 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len + -+ sizeof(struct eap_gpsk_csuite) + 2 + miclen; -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, -+ EAP_CODE_RESPONSE, identifier); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2); -+ start = wpabuf_put(resp, 0); -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", -+ data->id_peer, data->id_peer_len); -+ wpabuf_put_be16(resp, data->id_peer_len); -+ wpabuf_put_data(resp, data->id_peer, data->id_peer_len); -+ -+ wpabuf_put_be16(resp, data->id_server_len); -+ wpabuf_put_data(resp, data->id_server, data->id_server_len); -+ -+ if (random_get_bytes(data->rand_peer, EAP_GPSK_RAND_LEN)) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data " -+ "for RAND_Peer"); -+ eap_gpsk_state(data, FAILURE); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", -+ data->rand_peer, EAP_GPSK_RAND_LEN); -+ wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN); -+ wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN); -+ -+ wpabuf_put_be16(resp, csuite_list_len); -+ wpabuf_put_data(resp, csuite_list, csuite_list_len); -+ -+ csuite = wpabuf_put(resp, sizeof(*csuite)); -+ WPA_PUT_BE32(csuite->vendor, data->vendor); -+ WPA_PUT_BE16(csuite->specifier, data->specifier); -+ -+ if (eap_gpsk_derive_keys(data->psk, data->psk_len, -+ data->vendor, data->specifier, -+ data->rand_peer, data->rand_server, -+ data->id_peer, data->id_peer_len, -+ data->id_server, data->id_server_len, -+ data->msk, data->emsk, -+ data->sk, &data->sk_len, -+ data->pk, &data->pk_len) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); -+ eap_gpsk_state(data, FAILURE); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ -+ /* No PD_Payload_1 */ -+ wpabuf_put_be16(resp, 0); -+ -+ rpos = wpabuf_put(resp, miclen); -+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, -+ data->specifier, start, rpos - start, rpos) < -+ 0) { -+ eap_gpsk_state(data, FAILURE); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ -+ return resp; -+} -+ -+ -+static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data, -+ const u8 *pos, const u8 *end) -+{ -+ if (end - pos < EAP_GPSK_RAND_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " -+ "RAND_Peer"); -+ return NULL; -+ } -+ if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and " -+ "GPSK-3 did not match"); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2", -+ data->rand_peer, EAP_GPSK_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3", -+ pos, EAP_GPSK_RAND_LEN); -+ return NULL; -+ } -+ pos += EAP_GPSK_RAND_LEN; -+ -+ if (end - pos < EAP_GPSK_RAND_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " -+ "RAND_Server"); -+ return NULL; -+ } -+ if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " -+ "GPSK-3 did not match"); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", -+ data->rand_server, EAP_GPSK_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3", -+ pos, EAP_GPSK_RAND_LEN); -+ return NULL; -+ } -+ pos += EAP_GPSK_RAND_LEN; -+ -+ return pos; -+} -+ -+ -+static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data, -+ const u8 *pos, const u8 *end) -+{ -+ size_t len; -+ -+ if (pos == NULL) -+ return NULL; -+ -+ if (end - pos < (int) 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " -+ "length(ID_Server)"); -+ return NULL; -+ } -+ -+ len = WPA_GET_BE16(pos); -+ pos += 2; -+ -+ if (end - pos < (int) len) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " -+ "ID_Server"); -+ return NULL; -+ } -+ -+ if (len != data->id_server_len || -+ os_memcmp(pos, data->id_server, len) != 0) { -+ wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with " -+ "the one used in GPSK-1"); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1", -+ data->id_server, data->id_server_len); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3", -+ pos, len); -+ return NULL; -+ } -+ -+ pos += len; -+ -+ return pos; -+} -+ -+ -+static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data, -+ const u8 *pos, const u8 *end) -+{ -+ int vendor, specifier; -+ const struct eap_gpsk_csuite *csuite; -+ -+ if (pos == NULL) -+ return NULL; -+ -+ if (end - pos < (int) sizeof(*csuite)) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " -+ "CSuite_Sel"); -+ return NULL; -+ } -+ csuite = (const struct eap_gpsk_csuite *) pos; -+ vendor = WPA_GET_BE32(csuite->vendor); -+ specifier = WPA_GET_BE16(csuite->specifier); -+ pos += sizeof(*csuite); -+ if (vendor != data->vendor || specifier != data->specifier) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not " -+ "match with the one sent in GPSK-2 (%d:%d)", -+ vendor, specifier, data->vendor, data->specifier); -+ return NULL; -+ } -+ -+ return pos; -+} -+ -+ -+static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data, -+ const u8 *pos, const u8 *end) -+{ -+ u16 alen; -+ -+ if (pos == NULL) -+ return NULL; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " -+ "PD_Payload_2 length"); -+ return NULL; -+ } -+ alen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < alen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " -+ "%d-octet PD_Payload_2", alen); -+ return NULL; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen); -+ pos += alen; -+ -+ return pos; -+} -+ -+ -+static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data, -+ const u8 *payload, -+ const u8 *pos, const u8 *end) -+{ -+ size_t miclen; -+ u8 mic[EAP_GPSK_MAX_MIC_LEN]; -+ -+ if (pos == NULL) -+ return NULL; -+ -+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier); -+ if (end - pos < (int) miclen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " -+ "(left=%lu miclen=%lu)", -+ (unsigned long) (end - pos), -+ (unsigned long) miclen); -+ return NULL; -+ } -+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, -+ data->specifier, payload, pos - payload, mic) -+ < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); -+ return NULL; -+ } -+ if (os_memcmp(mic, pos, miclen) != 0) { -+ wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3"); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); -+ return NULL; -+ } -+ pos += miclen; -+ -+ return pos; -+} -+ -+ -+static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm, -+ struct eap_gpsk_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, -+ size_t payload_len) -+{ -+ struct wpabuf *resp; -+ const u8 *pos, *end; -+ -+ if (data->state != GPSK_3) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3"); -+ -+ end = payload + payload_len; -+ -+ pos = eap_gpsk_validate_rand(data, payload, end); -+ pos = eap_gpsk_validate_id_server(data, pos, end); -+ pos = eap_gpsk_validate_csuite(data, pos, end); -+ pos = eap_gpsk_validate_pd_payload_2(data, pos, end); -+ pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end); -+ -+ if (pos == NULL) { -+ eap_gpsk_state(data, FAILURE); -+ return NULL; -+ } -+ if (pos != end) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " -+ "data in the end of GPSK-2", -+ (unsigned long) (end - pos)); -+ } -+ -+ resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ -+ eap_gpsk_state(data, SUCCESS); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, -+ u8 identifier) -+{ -+ struct wpabuf *resp; -+ u8 *rpos, *start; -+ size_t mlen; -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4"); -+ -+ mlen = eap_gpsk_mic_len(data->vendor, data->specifier); -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen, -+ EAP_CODE_RESPONSE, identifier); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4); -+ start = wpabuf_put(resp, 0); -+ -+ /* No PD_Payload_3 */ -+ wpabuf_put_be16(resp, 0); -+ -+ rpos = wpabuf_put(resp, mlen); -+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, -+ data->specifier, start, rpos - start, rpos) < -+ 0) { -+ eap_gpsk_state(data, FAILURE); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_gpsk_data *data = priv; -+ struct wpabuf *resp; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len); -+ if (pos == NULL || len < 1) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos); -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = FALSE; -+ -+ switch (*pos) { -+ case EAP_GPSK_OPCODE_GPSK_1: -+ resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData, -+ pos + 1, len - 1); -+ break; -+ case EAP_GPSK_OPCODE_GPSK_3: -+ resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData, -+ pos + 1, len - 1); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with " -+ "unknown opcode %d", *pos); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ return resp; -+} -+ -+ -+static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gpsk_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_gpsk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ -+ return key; -+} -+ -+ -+static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_gpsk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ -+ return key; -+} -+ -+ -+int eap_peer_gpsk_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_gpsk_init; -+ eap->deinit = eap_gpsk_deinit; -+ eap->process = eap_gpsk_process; -+ eap->isKeyAvailable = eap_gpsk_isKeyAvailable; -+ eap->getKey = eap_gpsk_getKey; -+ eap->get_emsk = eap_gpsk_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gtc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gtc.c -new file mode 100644 -index 0000000000000..b2b554b4478b6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_gtc.c -@@ -0,0 +1,151 @@ -+/* -+ * EAP peer method: EAP-GTC (RFC 3748) -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+ -+ -+struct eap_gtc_data { -+ int prefix; -+}; -+ -+ -+static void * eap_gtc_init(struct eap_sm *sm) -+{ -+ struct eap_gtc_data *data; -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && -+ sm->m->method == EAP_TYPE_FAST) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " -+ "with challenge/response"); -+ data->prefix = 1; -+ } -+ return data; -+} -+ -+ -+static void eap_gtc_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gtc_data *data = priv; -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_gtc_data *data = priv; -+ struct wpabuf *resp; -+ const u8 *pos, *password, *identity; -+ size_t password_len, identity_len, len, plen; -+ int otp; -+ u8 id; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len); -+ if (pos == NULL) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ id = eap_get_id(reqData); -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len); -+ if (data->prefix && -+ (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with " -+ "expected prefix"); -+ -+ /* Send an empty response in order to allow tunneled -+ * acknowledgement of the failure. This will also cover the -+ * error case which seems to use EAP-MSCHAPv2 like error -+ * reporting with EAP-GTC inside EAP-FAST tunnel. */ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, -+ 0, EAP_CODE_RESPONSE, id); -+ return resp; -+ } -+ -+ password = eap_get_config_otp(sm, &password_len); -+ if (password) -+ otp = 1; -+ else { -+ password = eap_get_config_password(sm, &password_len); -+ otp = 0; -+ } -+ -+ if (password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-GTC: Password not configured"); -+ eap_sm_request_otp(sm, (const char *) pos, len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ ret->ignore = FALSE; -+ -+ ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE; -+ ret->decision = DECISION_COND_SUCC; -+ ret->allowNotifications = FALSE; -+ -+ plen = password_len; -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity == NULL) -+ return NULL; -+ if (data->prefix) -+ plen += 9 + identity_len + 1; -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ if (data->prefix) { -+ wpabuf_put_data(resp, "RESPONSE=", 9); -+ wpabuf_put_data(resp, identity, identity_len); -+ wpabuf_put_u8(resp, '\0'); -+ } -+ wpabuf_put_data(resp, password, password_len); -+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", -+ wpabuf_head_u8(resp) + sizeof(struct eap_hdr) + -+ 1, plen); -+ -+ if (otp) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password"); -+ eap_clear_config_otp(sm); -+ } -+ -+ return resp; -+} -+ -+ -+int eap_peer_gtc_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_gtc_init; -+ eap->deinit = eap_gtc_deinit; -+ eap->process = eap_gtc_process; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_i.h -new file mode 100644 -index 0000000000000..afca6111eb871 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_i.h -@@ -0,0 +1,356 @@ -+/* -+ * EAP peer state machines internal structures (RFC 4137) -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_I_H -+#define EAP_I_H -+ -+#include "wpabuf.h" -+#include "eap_peer/eap.h" -+#include "eap_common/eap_common.h" -+ -+/* RFC 4137 - EAP Peer state machine */ -+ -+typedef enum { -+ DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC -+} EapDecision; -+ -+typedef enum { -+ METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE -+} EapMethodState; -+ -+/** -+ * struct eap_method_ret - EAP return values from struct eap_method::process() -+ * -+ * These structure contains OUT variables for the interface between peer state -+ * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as -+ * the return value of struct eap_method::process() so it is not included in -+ * this structure. -+ */ -+struct eap_method_ret { -+ /** -+ * ignore - Whether method decided to drop the current packed (OUT) -+ */ -+ Boolean ignore; -+ -+ /** -+ * methodState - Method-specific state (IN/OUT) -+ */ -+ EapMethodState methodState; -+ -+ /** -+ * decision - Authentication decision (OUT) -+ */ -+ EapDecision decision; -+ -+ /** -+ * allowNotifications - Whether method allows notifications (OUT) -+ */ -+ Boolean allowNotifications; -+}; -+ -+ -+/** -+ * struct eap_method - EAP method interface -+ * This structure defines the EAP method interface. Each method will need to -+ * register its own EAP type, EAP name, and set of function pointers for method -+ * specific operations. This interface is based on section 4.4 of RFC 4137. -+ */ -+struct eap_method { -+ /** -+ * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) -+ */ -+ int vendor; -+ -+ /** -+ * method - EAP type number (EAP_TYPE_*) -+ */ -+ EapType method; -+ -+ /** -+ * name - Name of the method (e.g., "TLS") -+ */ -+ const char *name; -+ -+ /** -+ * init - Initialize an EAP method -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * Returns: Pointer to allocated private data, or %NULL on failure -+ * -+ * This function is used to initialize the EAP method explicitly -+ * instead of using METHOD_INIT state as specific in RFC 4137. The -+ * method is expected to initialize it method-specific state and return -+ * a pointer that will be used as the priv argument to other calls. -+ */ -+ void * (*init)(struct eap_sm *sm); -+ -+ /** -+ * deinit - Deinitialize an EAP method -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * -+ * Deinitialize the EAP method and free any allocated private data. -+ */ -+ void (*deinit)(struct eap_sm *sm, void *priv); -+ -+ /** -+ * process - Process an EAP request -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * @ret: Return values from EAP request validation and processing -+ * @reqData: EAP request to be processed (eapReqData) -+ * Returns: Pointer to allocated EAP response packet (eapRespData) -+ * -+ * This function is a combination of m.check(), m.process(), and -+ * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other -+ * words, this function validates the incoming request, processes it, -+ * and build a response packet. m.check() and m.process() return values -+ * are returned through struct eap_method_ret *ret variable. Caller is -+ * responsible for freeing the returned EAP response packet. -+ */ -+ struct wpabuf * (*process)(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData); -+ -+ /** -+ * isKeyAvailable - Find out whether EAP method has keying material -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * Returns: %TRUE if key material (eapKeyData) is available -+ */ -+ Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv); -+ -+ /** -+ * getKey - Get EAP method specific keying material (eapKeyData) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * @len: Pointer to variable to store key length (eapKeyDataLen) -+ * Returns: Keying material (eapKeyData) or %NULL if not available -+ * -+ * This function can be used to get the keying material from the EAP -+ * method. The key may already be stored in the method-specific private -+ * data or this function may derive the key. -+ */ -+ u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len); -+ -+ /** -+ * get_status - Get EAP method status -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * @buf: Buffer for status information -+ * @buflen: Maximum buffer length -+ * @verbose: Whether to include verbose status information -+ * Returns: Number of bytes written to buf -+ * -+ * Query EAP method for status information. This function fills in a -+ * text area with current status information from the EAP method. If -+ * the buffer (buf) is not large enough, status information will be -+ * truncated to fit the buffer. -+ */ -+ int (*get_status)(struct eap_sm *sm, void *priv, char *buf, -+ size_t buflen, int verbose); -+ -+ /** -+ * has_reauth_data - Whether method is ready for fast reauthentication -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * Returns: %TRUE or %FALSE based on whether fast reauthentication is -+ * possible -+ * -+ * This function is an optional handler that only EAP methods -+ * supporting fast re-authentication need to implement. -+ */ -+ Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv); -+ -+ /** -+ * deinit_for_reauth - Release data that is not needed for fast re-auth -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * -+ * This function is an optional handler that only EAP methods -+ * supporting fast re-authentication need to implement. This is called -+ * when authentication has been completed and EAP state machine is -+ * requesting that enough state information is maintained for fast -+ * re-authentication -+ */ -+ void (*deinit_for_reauth)(struct eap_sm *sm, void *priv); -+ -+ /** -+ * init_for_reauth - Prepare for start of fast re-authentication -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * -+ * This function is an optional handler that only EAP methods -+ * supporting fast re-authentication need to implement. This is called -+ * when EAP authentication is started and EAP state machine is -+ * requesting fast re-authentication to be used. -+ */ -+ void * (*init_for_reauth)(struct eap_sm *sm, void *priv); -+ -+ /** -+ * get_identity - Get method specific identity for re-authentication -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * @len: Length of the returned identity -+ * Returns: Pointer to the method specific identity or %NULL if default -+ * identity is to be used -+ * -+ * This function is an optional handler that only EAP methods -+ * that use method specific identity need to implement. -+ */ -+ const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len); -+ -+ /** -+ * free - Free EAP method data -+ * @method: Pointer to the method data registered with -+ * eap_peer_method_register(). -+ * -+ * This function will be called when the EAP method is being -+ * unregistered. If the EAP method allocated resources during -+ * registration (e.g., allocated struct eap_method), they should be -+ * freed in this function. No other method functions will be called -+ * after this call. If this function is not defined (i.e., function -+ * pointer is %NULL), a default handler is used to release the method -+ * data with free(method). This is suitable for most cases. -+ */ -+ void (*free)(struct eap_method *method); -+ -+#define EAP_PEER_METHOD_INTERFACE_VERSION 1 -+ /** -+ * version - Version of the EAP peer method interface -+ * -+ * The EAP peer method implementation should set this variable to -+ * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the -+ * EAP method is using supported API version when using dynamically -+ * loadable EAP methods. -+ */ -+ int version; -+ -+ /** -+ * next - Pointer to the next EAP method -+ * -+ * This variable is used internally in the EAP method registration code -+ * to create a linked list of registered EAP methods. -+ */ -+ struct eap_method *next; -+ -+#ifdef CONFIG_DYNAMIC_EAP_METHODS -+ /** -+ * dl_handle - Handle for the dynamic library -+ * -+ * This variable is used internally in the EAP method registration code -+ * to store a handle for the dynamic library. If the method is linked -+ * in statically, this is %NULL. -+ */ -+ void *dl_handle; -+#endif /* CONFIG_DYNAMIC_EAP_METHODS */ -+ -+ /** -+ * get_emsk - Get EAP method specific keying extended material (EMSK) -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * @len: Pointer to a variable to store EMSK length -+ * Returns: EMSK or %NULL if not available -+ * -+ * This function can be used to get the extended keying material from -+ * the EAP method. The key may already be stored in the method-specific -+ * private data or this function may derive the key. -+ */ -+ u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); -+}; -+ -+ -+/** -+ * struct eap_sm - EAP state machine data -+ */ -+struct eap_sm { -+ enum { -+ EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED, -+ EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD, -+ EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS, -+ EAP_FAILURE -+ } EAP_state; -+ /* Long-term local variables */ -+ EapType selectedMethod; -+ EapMethodState methodState; -+ int lastId; -+ struct wpabuf *lastRespData; -+ EapDecision decision; -+ /* Short-term local variables */ -+ Boolean rxReq; -+ Boolean rxSuccess; -+ Boolean rxFailure; -+ int reqId; -+ EapType reqMethod; -+ int reqVendor; -+ u32 reqVendorMethod; -+ Boolean ignore; -+ /* Constants */ -+ int ClientTimeout; -+ -+ /* Miscellaneous variables */ -+ Boolean allowNotifications; /* peer state machine <-> methods */ -+ struct wpabuf *eapRespData; /* peer to lower layer */ -+ Boolean eapKeyAvailable; /* peer to lower layer */ -+ u8 *eapKeyData; /* peer to lower layer */ -+ size_t eapKeyDataLen; /* peer to lower layer */ -+ const struct eap_method *m; /* selected EAP method */ -+ /* not defined in RFC 4137 */ -+ Boolean changed; -+ void *eapol_ctx; -+ struct eapol_callbacks *eapol_cb; -+ void *eap_method_priv; -+ int init_phase2; -+ int fast_reauth; -+ -+ Boolean rxResp /* LEAP only */; -+ Boolean leap_done; -+ Boolean peap_done; -+ u8 req_md5[16]; /* MD5() of the current EAP packet */ -+ u8 last_md5[16]; /* MD5() of the previously received EAP packet; used -+ * in duplicate request detection. */ -+ -+ void *msg_ctx; -+ void *scard_ctx; -+ void *ssl_ctx; -+ -+ unsigned int workaround; -+ -+ /* Optional challenges generated in Phase 1 (EAP-FAST) */ -+ u8 *peer_challenge, *auth_challenge; -+ -+ int num_rounds; -+ int force_disabled; -+ -+ struct wps_context *wps; -+ -+ int prev_failure; -+}; -+ -+const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); -+const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len); -+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash); -+const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len); -+const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len); -+void eap_clear_config_otp(struct eap_sm *sm); -+const char * eap_get_config_phase1(struct eap_sm *sm); -+const char * eap_get_config_phase2(struct eap_sm *sm); -+int eap_get_config_fragment_size(struct eap_sm *sm); -+struct eap_peer_config * eap_get_config(struct eap_sm *sm); -+void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob); -+const struct wpa_config_blob * -+eap_get_config_blob(struct eap_sm *sm, const char *name); -+void eap_notify_pending(struct eap_sm *sm); -+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method); -+ -+#endif /* EAP_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ikev2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ikev2.c -new file mode 100644 -index 0000000000000..bb49a662d72d0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ikev2.c -@@ -0,0 +1,506 @@ -+/* -+ * EAP-IKEv2 peer (RFC 5106) -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+#include "eap_common/eap_ikev2_common.h" -+#include "ikev2.h" -+ -+ -+struct eap_ikev2_data { -+ struct ikev2_responder_data ikev2; -+ enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; -+ struct wpabuf *in_buf; -+ struct wpabuf *out_buf; -+ size_t out_used; -+ size_t fragment_size; -+ int keys_ready; -+ u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; -+ int keymat_ok; -+}; -+ -+ -+static const char * eap_ikev2_state_txt(int state) -+{ -+ switch (state) { -+ case WAIT_START: -+ return "WAIT_START"; -+ case PROC_MSG: -+ return "PROC_MSG"; -+ case WAIT_FRAG_ACK: -+ return "WAIT_FRAG_ACK"; -+ case DONE: -+ return "DONE"; -+ case FAIL: -+ return "FAIL"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+static void eap_ikev2_state(struct eap_ikev2_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", -+ eap_ikev2_state_txt(data->state), -+ eap_ikev2_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_ikev2_init(struct eap_sm *sm) -+{ -+ struct eap_ikev2_data *data; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity == NULL) { -+ wpa_printf(MSG_INFO, "EAP-IKEV2: No identity available"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = WAIT_START; -+ data->fragment_size = IKEV2_FRAGMENT_SIZE; -+ data->ikev2.state = SA_INIT; -+ data->ikev2.peer_auth = PEER_AUTH_SECRET; -+ data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); -+ if (data->ikev2.key_pad == NULL) -+ goto failed; -+ data->ikev2.key_pad_len = 21; -+ data->ikev2.IDr = os_malloc(identity_len); -+ if (data->ikev2.IDr == NULL) -+ goto failed; -+ os_memcpy(data->ikev2.IDr, identity, identity_len); -+ data->ikev2.IDr_len = identity_len; -+ -+ password = eap_get_config_password(sm, &password_len); -+ if (password) { -+ data->ikev2.shared_secret = os_malloc(password_len); -+ if (data->ikev2.shared_secret == NULL) -+ goto failed; -+ os_memcpy(data->ikev2.shared_secret, password, password_len); -+ data->ikev2.shared_secret_len = password_len; -+ } -+ -+ return data; -+ -+failed: -+ ikev2_responder_deinit(&data->ikev2); -+ os_free(data); -+ return NULL; -+} -+ -+ -+static void eap_ikev2_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ikev2_data *data = priv; -+ wpabuf_free(data->in_buf); -+ wpabuf_free(data->out_buf); -+ ikev2_responder_deinit(&data->ikev2); -+ os_free(data); -+} -+ -+ -+static int eap_ikev2_peer_keymat(struct eap_ikev2_data *data) -+{ -+ if (eap_ikev2_derive_keymat( -+ data->ikev2.proposal.prf, &data->ikev2.keys, -+ data->ikev2.i_nonce, data->ikev2.i_nonce_len, -+ data->ikev2.r_nonce, data->ikev2.r_nonce_len, -+ data->keymat) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " -+ "derive key material"); -+ return -1; -+ } -+ data->keymat_ok = 1; -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, -+ struct eap_method_ret *ret, u8 id) -+{ -+ struct wpabuf *resp; -+ u8 flags; -+ size_t send_len, plen, icv_len = 0; -+ -+ ret->ignore = FALSE; -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Response"); -+ ret->allowNotifications = TRUE; -+ -+ flags = 0; -+ send_len = wpabuf_len(data->out_buf) - data->out_used; -+ if (1 + send_len > data->fragment_size) { -+ send_len = data->fragment_size - 1; -+ flags |= IKEV2_FLAGS_MORE_FRAGMENTS; -+ if (data->out_used == 0) { -+ flags |= IKEV2_FLAGS_LENGTH_INCLUDED; -+ send_len -= 4; -+ } -+ } -+#ifdef CCNS_PL -+ /* Some issues figuring out the length of the message if Message Length -+ * field not included?! */ -+ if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) -+ flags |= IKEV2_FLAGS_LENGTH_INCLUDED; -+#endif /* CCNS_PL */ -+ -+ plen = 1 + send_len; -+ if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) -+ plen += 4; -+ if (data->keys_ready) { -+ const struct ikev2_integ_alg *integ; -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " -+ "Data"); -+ flags |= IKEV2_FLAGS_ICV_INCLUDED; -+ integ = ikev2_get_integ(data->ikev2.proposal.integ); -+ if (integ == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " -+ "transform / cannot generate ICV"); -+ return NULL; -+ } -+ icv_len = integ->hash_len; -+ -+ plen += icv_len; -+ } -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, flags); /* Flags */ -+ if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) -+ wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); -+ -+ wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, -+ send_len); -+ data->out_used += send_len; -+ -+ if (flags & IKEV2_FLAGS_ICV_INCLUDED) { -+ const u8 *msg = wpabuf_head(resp); -+ size_t len = wpabuf_len(resp); -+ ikev2_integ_hash(data->ikev2.proposal.integ, -+ data->ikev2.keys.SK_ar, -+ data->ikev2.keys.SK_integ_len, -+ msg, len, wpabuf_put(resp, icv_len)); -+ } -+ -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ -+ if (data->out_used == wpabuf_len(data->out_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " -+ "(message sent completely)", -+ (unsigned long) send_len); -+ wpabuf_free(data->out_buf); -+ data->out_buf = NULL; -+ data->out_used = 0; -+ switch (data->ikev2.state) { -+ case SA_AUTH: -+ /* SA_INIT was sent out, so message have to be -+ * integrity protected from now on. */ -+ data->keys_ready = 1; -+ break; -+ case IKEV2_DONE: -+ ret->methodState = METHOD_DONE; -+ if (data->state == FAIL) -+ break; -+ ret->decision = DECISION_COND_SUCC; -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " -+ "completed successfully"); -+ if (eap_ikev2_peer_keymat(data)) -+ break; -+ eap_ikev2_state(data, DONE); -+ break; -+ case IKEV2_FAILED: -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication " -+ "failed"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ break; -+ default: -+ break; -+ } -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " -+ "(%lu more to send)", (unsigned long) send_len, -+ (unsigned long) wpabuf_len(data->out_buf) - -+ data->out_used); -+ eap_ikev2_state(data, WAIT_FRAG_ACK); -+ } -+ -+ return resp; -+} -+ -+ -+static int eap_ikev2_process_icv(struct eap_ikev2_data *data, -+ const struct wpabuf *reqData, -+ u8 flags, const u8 *pos, const u8 **end) -+{ -+ if (flags & IKEV2_FLAGS_ICV_INCLUDED) { -+ int icv_len = eap_ikev2_validate_icv( -+ data->ikev2.proposal.integ, &data->ikev2.keys, 1, -+ reqData, pos, *end); -+ if (icv_len < 0) -+ return -1; -+ /* Hide Integrity Checksum Data from further processing */ -+ *end -= icv_len; -+ } else if (data->keys_ready) { -+ wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " -+ "included integrity checksum"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ikev2_process_cont(struct eap_ikev2_data *data, -+ const u8 *buf, size_t len) -+{ -+ /* Process continuation of a pending message */ -+ if (len > wpabuf_tailroom(data->in_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); -+ eap_ikev2_state(data, FAIL); -+ return -1; -+ } -+ -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting " -+ "for %lu bytes more", (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_ikev2_process_fragment(struct eap_ikev2_data *data, -+ struct eap_method_ret *ret, -+ u8 id, u8 flags, -+ u32 message_length, -+ const u8 *buf, size_t len) -+{ -+ /* Process a fragment that is not the last one of the message */ -+ if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " -+ "a fragmented packet"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* First fragment of the message */ -+ data->in_buf = wpabuf_alloc(message_length); -+ if (data->in_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " -+ "message"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " -+ "fragment, waiting for %lu bytes more", -+ (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ } -+ -+ return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE); -+} -+ -+ -+static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_ikev2_data *data = priv; -+ const u8 *start, *pos, *end; -+ size_t len; -+ u8 flags, id; -+ u32 message_length = 0; -+ struct wpabuf tmpbuf; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, reqData, &len); -+ if (pos == NULL) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ id = eap_get_id(reqData); -+ -+ start = pos; -+ end = start + len; -+ -+ if (len == 0) -+ flags = 0; /* fragment ack */ -+ else -+ flags = *pos++; -+ -+ if (eap_ikev2_process_icv(data, reqData, flags, pos, &end) < 0) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { -+ if (end - pos < 4) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ message_length = WPA_GET_BE32(pos); -+ pos += 4; -+ -+ if (message_length < (u32) (end - pos)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " -+ "Length (%d; %ld remaining in this msg)", -+ message_length, (long) (end - pos)); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " -+ "Message Length %u", flags, message_length); -+ -+ if (data->state == WAIT_FRAG_ACK) { -+#ifdef CCNS_PL -+ if (len > 1) /* Empty Flags field included in ACK */ -+#else /* CCNS_PL */ -+ if (len != 0) -+#endif /* CCNS_PL */ -+ { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " -+ "in WAIT_FRAG_ACK state"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); -+ eap_ikev2_state(data, PROC_MSG); -+ return eap_ikev2_build_msg(data, ret, id); -+ } -+ -+ if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { -+ return eap_ikev2_process_fragment(data, ret, id, flags, -+ message_length, pos, -+ end - pos); -+ } -+ -+ if (data->in_buf == NULL) { -+ /* Wrap unfragmented messages as wpabuf without extra copy */ -+ wpabuf_set(&tmpbuf, pos, end - pos); -+ data->in_buf = &tmpbuf; -+ } -+ -+ if (ikev2_responder_process(&data->ikev2, data->in_buf) < 0) { -+ if (data->in_buf == &tmpbuf) -+ data->in_buf = NULL; -+ eap_ikev2_state(data, FAIL); -+ return NULL; -+ } -+ -+ if (data->in_buf != &tmpbuf) -+ wpabuf_free(data->in_buf); -+ data->in_buf = NULL; -+ -+ if (data->out_buf == NULL) { -+ data->out_buf = ikev2_responder_build(&data->ikev2); -+ if (data->out_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to generate " -+ "IKEv2 message"); -+ return NULL; -+ } -+ data->out_used = 0; -+ } -+ -+ eap_ikev2_state(data, PROC_MSG); -+ return eap_ikev2_build_msg(data, ret, id); -+} -+ -+ -+static Boolean eap_ikev2_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ikev2_data *data = priv; -+ return data->state == DONE && data->keymat_ok; -+} -+ -+ -+static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_ikev2_data *data = priv; -+ u8 *key; -+ -+ if (data->state != DONE || !data->keymat_ok) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key) { -+ os_memcpy(key, data->keymat, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ } -+ -+ return key; -+} -+ -+ -+static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_ikev2_data *data = priv; -+ u8 *key; -+ -+ if (data->state != DONE || !data->keymat_ok) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key) { -+ os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ } -+ -+ return key; -+} -+ -+ -+int eap_peer_ikev2_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_IKEV2, -+ "IKEV2"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_ikev2_init; -+ eap->deinit = eap_ikev2_deinit; -+ eap->process = eap_ikev2_process; -+ eap->isKeyAvailable = eap_ikev2_isKeyAvailable; -+ eap->getKey = eap_ikev2_getKey; -+ eap->get_emsk = eap_ikev2_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_leap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_leap.c -new file mode 100644 -index 0000000000000..6a8efcd95f93d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_leap.c -@@ -0,0 +1,416 @@ -+/* -+ * EAP peer method: LEAP -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/ms_funcs.h" -+#include "crypto/crypto.h" -+#include "crypto/random.h" -+#include "eap_i.h" -+ -+#define LEAP_VERSION 1 -+#define LEAP_CHALLENGE_LEN 8 -+#define LEAP_RESPONSE_LEN 24 -+#define LEAP_KEY_LEN 16 -+ -+ -+struct eap_leap_data { -+ enum { -+ LEAP_WAIT_CHALLENGE, -+ LEAP_WAIT_SUCCESS, -+ LEAP_WAIT_RESPONSE, -+ LEAP_DONE -+ } state; -+ -+ u8 peer_challenge[LEAP_CHALLENGE_LEN]; -+ u8 peer_response[LEAP_RESPONSE_LEN]; -+ -+ u8 ap_challenge[LEAP_CHALLENGE_LEN]; -+ u8 ap_response[LEAP_RESPONSE_LEN]; -+}; -+ -+ -+static void * eap_leap_init(struct eap_sm *sm) -+{ -+ struct eap_leap_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = LEAP_WAIT_CHALLENGE; -+ -+ sm->leap_done = FALSE; -+ return data; -+} -+ -+ -+static void eap_leap_deinit(struct eap_sm *sm, void *priv) -+{ -+ os_free(priv); -+} -+ -+ -+static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_leap_data *data = priv; -+ struct wpabuf *resp; -+ const u8 *pos, *challenge, *identity, *password; -+ u8 challenge_len, *rpos; -+ size_t identity_len, password_len, len; -+ int pwhash; -+ -+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request"); -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ password = eap_get_config_password2(sm, &password_len, &pwhash); -+ if (identity == NULL || password == NULL) -+ return NULL; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); -+ if (pos == NULL || len < 3) { -+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (*pos != LEAP_VERSION) { -+ wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " -+ "%d", *pos); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ pos++; -+ -+ pos++; /* skip unused byte */ -+ -+ challenge_len = *pos++; -+ if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) { -+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge " -+ "(challenge_len=%d reqDataLen=%lu)", -+ challenge_len, (unsigned long) wpabuf_len(reqData)); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ challenge = pos; -+ os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP", -+ challenge, LEAP_CHALLENGE_LEN); -+ -+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response"); -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, -+ 3 + LEAP_RESPONSE_LEN + identity_len, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ wpabuf_put_u8(resp, LEAP_VERSION); -+ wpabuf_put_u8(resp, 0); /* unused */ -+ wpabuf_put_u8(resp, LEAP_RESPONSE_LEN); -+ rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN); -+ if (pwhash) -+ challenge_response(challenge, password, rpos); -+ else -+ nt_challenge_response(challenge, password, password_len, rpos); -+ os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", -+ rpos, LEAP_RESPONSE_LEN); -+ wpabuf_put_data(resp, identity, identity_len); -+ -+ data->state = LEAP_WAIT_SUCCESS; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_leap_data *data = priv; -+ struct wpabuf *resp; -+ u8 *pos; -+ const u8 *identity; -+ size_t identity_len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success"); -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity == NULL) -+ return NULL; -+ -+ if (data->state != LEAP_WAIT_SUCCESS) { -+ wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in " -+ "unexpected state (%d) - ignored", data->state); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, -+ 3 + LEAP_CHALLENGE_LEN + identity_len, -+ EAP_CODE_REQUEST, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ wpabuf_put_u8(resp, LEAP_VERSION); -+ wpabuf_put_u8(resp, 0); /* unused */ -+ wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN); -+ pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN); -+ if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) { -+ wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data " -+ "for challenge"); -+ wpabuf_free(resp); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos, -+ LEAP_CHALLENGE_LEN); -+ wpabuf_put_data(resp, identity, identity_len); -+ -+ data->state = LEAP_WAIT_RESPONSE; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_leap_data *data = priv; -+ const u8 *pos, *password; -+ u8 response_len, pw_hash[16], pw_hash_hash[16], -+ expected[LEAP_RESPONSE_LEN]; -+ size_t password_len, len; -+ int pwhash; -+ -+ wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); -+ -+ password = eap_get_config_password2(sm, &password_len, &pwhash); -+ if (password == NULL) -+ return NULL; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); -+ if (pos == NULL || len < 3) { -+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (*pos != LEAP_VERSION) { -+ wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " -+ "%d", *pos); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ pos++; -+ -+ pos++; /* skip unused byte */ -+ -+ response_len = *pos++; -+ if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) { -+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " -+ "(response_len=%d reqDataLen=%lu)", -+ response_len, (unsigned long) wpabuf_len(reqData)); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", -+ pos, LEAP_RESPONSE_LEN); -+ os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); -+ -+ if (pwhash) { -+ if (hash_nt_password_hash(password, pw_hash_hash)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ } else { -+ if (nt_password_hash(password, password_len, pw_hash) || -+ hash_nt_password_hash(pw_hash, pw_hash_hash)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ } -+ challenge_response(data->ap_challenge, pw_hash_hash, expected); -+ -+ ret->methodState = METHOD_DONE; -+ ret->allowNotifications = FALSE; -+ -+ if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) { -+ wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " -+ "response - authentication failed"); -+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", -+ expected, LEAP_RESPONSE_LEN); -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ -+ ret->decision = DECISION_UNCOND_SUCC; -+ -+ /* LEAP is somewhat odd method since it sends EAP-Success in the middle -+ * of the authentication. Use special variable to transit EAP state -+ * machine to SUCCESS state. */ -+ sm->leap_done = TRUE; -+ data->state = LEAP_DONE; -+ -+ /* No more authentication messages expected; AP will send EAPOL-Key -+ * frames if encryption is enabled. */ -+ return NULL; -+} -+ -+ -+static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ const struct eap_hdr *eap; -+ size_t password_len; -+ const u8 *password; -+ -+ password = eap_get_config_password(sm, &password_len); -+ if (password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured"); -+ eap_sm_request_password(sm); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ /* -+ * LEAP needs to be able to handle EAP-Success frame which does not -+ * include Type field. Consequently, eap_hdr_validate() cannot be used -+ * here. This validation will be done separately for EAP-Request and -+ * EAP-Response frames. -+ */ -+ eap = wpabuf_head(reqData); -+ if (wpabuf_len(reqData) < sizeof(*eap) || -+ be_to_host16(eap->length) > wpabuf_len(reqData)) { -+ wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ ret->ignore = FALSE; -+ ret->allowNotifications = TRUE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ -+ sm->leap_done = FALSE; -+ -+ switch (eap->code) { -+ case EAP_CODE_REQUEST: -+ return eap_leap_process_request(sm, priv, ret, reqData); -+ case EAP_CODE_SUCCESS: -+ return eap_leap_process_success(sm, priv, ret, reqData); -+ case EAP_CODE_RESPONSE: -+ return eap_leap_process_response(sm, priv, ret, reqData); -+ default: -+ wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - " -+ "ignored", eap->code); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+} -+ -+ -+static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_leap_data *data = priv; -+ return data->state == LEAP_DONE; -+} -+ -+ -+static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_leap_data *data = priv; -+ u8 *key, pw_hash_hash[16], pw_hash[16]; -+ const u8 *addr[5], *password; -+ size_t elen[5], password_len; -+ int pwhash; -+ -+ if (data->state != LEAP_DONE) -+ return NULL; -+ -+ password = eap_get_config_password2(sm, &password_len, &pwhash); -+ if (password == NULL) -+ return NULL; -+ -+ key = os_malloc(LEAP_KEY_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ if (pwhash) { -+ if (hash_nt_password_hash(password, pw_hash_hash)) { -+ os_free(key); -+ return NULL; -+ } -+ } else { -+ if (nt_password_hash(password, password_len, pw_hash) || -+ hash_nt_password_hash(pw_hash, pw_hash_hash)) { -+ os_free(key); -+ return NULL; -+ } -+ } -+ wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", -+ pw_hash_hash, 16); -+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", -+ data->peer_challenge, LEAP_CHALLENGE_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", -+ data->peer_response, LEAP_RESPONSE_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", -+ data->ap_challenge, LEAP_CHALLENGE_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", -+ data->ap_response, LEAP_RESPONSE_LEN); -+ -+ addr[0] = pw_hash_hash; -+ elen[0] = 16; -+ addr[1] = data->ap_challenge; -+ elen[1] = LEAP_CHALLENGE_LEN; -+ addr[2] = data->ap_response; -+ elen[2] = LEAP_RESPONSE_LEN; -+ addr[3] = data->peer_challenge; -+ elen[3] = LEAP_CHALLENGE_LEN; -+ addr[4] = data->peer_response; -+ elen[4] = LEAP_RESPONSE_LEN; -+ md5_vector(5, addr, elen, key); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); -+ *len = LEAP_KEY_LEN; -+ -+ return key; -+} -+ -+ -+int eap_peer_leap_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_leap_init; -+ eap->deinit = eap_leap_deinit; -+ eap->process = eap_leap_process; -+ eap->isKeyAvailable = eap_leap_isKeyAvailable; -+ eap->getKey = eap_leap_getKey; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_md5.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_md5.c -new file mode 100644 -index 0000000000000..0edbae8f74d37 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_md5.c -@@ -0,0 +1,120 @@ -+/* -+ * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994) -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+#include "eap_common/chap.h" -+ -+ -+static void * eap_md5_init(struct eap_sm *sm) -+{ -+ /* No need for private data. However, must return non-NULL to indicate -+ * success. */ -+ return (void *) 1; -+} -+ -+ -+static void eap_md5_deinit(struct eap_sm *sm, void *priv) -+{ -+} -+ -+ -+static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct wpabuf *resp; -+ const u8 *pos, *challenge, *password; -+ u8 *rpos, id; -+ size_t len, challenge_len, password_len; -+ -+ password = eap_get_config_password(sm, &password_len); -+ if (password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-MD5: Password not configured"); -+ eap_sm_request_password(sm); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len); -+ if (pos == NULL || len == 0) { -+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)", -+ pos, (unsigned long) len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ /* -+ * CHAP Challenge: -+ * Value-Size (1 octet) | Value(Challenge) | Name(optional) -+ */ -+ challenge_len = *pos++; -+ if (challenge_len == 0 || challenge_len > len - 1) { -+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge " -+ "(challenge_len=%lu len=%lu)", -+ (unsigned long) challenge_len, (unsigned long) len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ ret->ignore = FALSE; -+ challenge = pos; -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", -+ challenge, challenge_len); -+ -+ wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_COND_SUCC; -+ ret->allowNotifications = TRUE; -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ -+ /* -+ * CHAP Response: -+ * Value-Size (1 octet) | Value(Response) | Name(optional) -+ */ -+ wpabuf_put_u8(resp, CHAP_MD5_LEN); -+ -+ id = eap_get_id(resp); -+ rpos = wpabuf_put(resp, CHAP_MD5_LEN); -+ chap_md5(id, password, password_len, challenge, challenge_len, rpos); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN); -+ -+ return resp; -+} -+ -+ -+int eap_peer_md5_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_md5_init; -+ eap->deinit = eap_md5_deinit; -+ eap->process = eap_md5_process; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.c -new file mode 100644 -index 0000000000000..3b0af055b39c7 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.c -@@ -0,0 +1,373 @@ -+/* -+ * EAP peer: Method registration -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#ifdef CONFIG_DYNAMIC_EAP_METHODS -+#include -+#endif /* CONFIG_DYNAMIC_EAP_METHODS */ -+ -+#include "common.h" -+#include "eap_i.h" -+#include "eap_methods.h" -+ -+ -+static struct eap_method *eap_methods = NULL; -+ -+ -+/** -+ * eap_peer_get_eap_method - Get EAP method based on type number -+ * @vendor: EAP Vendor-Id (0 = IETF) -+ * @method: EAP type number -+ * Returns: Pointer to EAP method or %NULL if not found -+ */ -+const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method) -+{ -+ struct eap_method *m; -+ for (m = eap_methods; m; m = m->next) { -+ if (m->vendor == vendor && m->method == method) -+ return m; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * eap_peer_get_type - Get EAP type for the given EAP method name -+ * @name: EAP method name, e.g., TLS -+ * @vendor: Buffer for returning EAP Vendor-Id -+ * Returns: EAP method type or %EAP_TYPE_NONE if not found -+ * -+ * This function maps EAP type names into EAP type numbers based on the list of -+ * EAP methods included in the build. -+ */ -+EapType eap_peer_get_type(const char *name, int *vendor) -+{ -+ struct eap_method *m; -+ for (m = eap_methods; m; m = m->next) { -+ if (os_strcmp(m->name, name) == 0) { -+ *vendor = m->vendor; -+ return m->method; -+ } -+ } -+ *vendor = EAP_VENDOR_IETF; -+ return EAP_TYPE_NONE; -+} -+ -+ -+/** -+ * eap_get_name - Get EAP method name for the given EAP type -+ * @vendor: EAP Vendor-Id (0 = IETF) -+ * @type: EAP method type -+ * Returns: EAP method name, e.g., TLS, or %NULL if not found -+ * -+ * This function maps EAP type numbers into EAP type names based on the list of -+ * EAP methods included in the build. -+ */ -+const char * eap_get_name(int vendor, EapType type) -+{ -+ struct eap_method *m; -+ for (m = eap_methods; m; m = m->next) { -+ if (m->vendor == vendor && m->method == type) -+ return m->name; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * eap_get_names - Get space separated list of names for supported EAP methods -+ * @buf: Buffer for names -+ * @buflen: Buffer length -+ * Returns: Number of characters written into buf (not including nul -+ * termination) -+ */ -+size_t eap_get_names(char *buf, size_t buflen) -+{ -+ char *pos, *end; -+ struct eap_method *m; -+ int ret; -+ -+ if (buflen == 0) -+ return 0; -+ -+ pos = buf; -+ end = pos + buflen; -+ -+ for (m = eap_methods; m; m = m->next) { -+ ret = os_snprintf(pos, end - pos, "%s%s", -+ m == eap_methods ? "" : " ", m->name); -+ if (ret < 0 || ret >= end - pos) -+ break; -+ pos += ret; -+ } -+ buf[buflen - 1] = '\0'; -+ -+ return pos - buf; -+} -+ -+ -+/** -+ * eap_get_names_as_string_array - Get supported EAP methods as string array -+ * @num: Buffer for returning the number of items in array, not including %NULL -+ * terminator. This parameter can be %NULL if the length is not needed. -+ * Returns: A %NULL-terminated array of strings, or %NULL on error. -+ * -+ * This function returns the list of names for all supported EAP methods as an -+ * array of strings. The caller must free the returned array items and the -+ * array. -+ */ -+char ** eap_get_names_as_string_array(size_t *num) -+{ -+ struct eap_method *m; -+ size_t array_len = 0; -+ char **array; -+ int i = 0, j; -+ -+ for (m = eap_methods; m; m = m->next) -+ array_len++; -+ -+ array = os_zalloc(sizeof(char *) * (array_len + 1)); -+ if (array == NULL) -+ return NULL; -+ -+ for (m = eap_methods; m; m = m->next) { -+ array[i++] = os_strdup(m->name); -+ if (array[i - 1] == NULL) { -+ for (j = 0; j < i; j++) -+ os_free(array[j]); -+ os_free(array); -+ return NULL; -+ } -+ } -+ array[i] = NULL; -+ -+ if (num) -+ *num = array_len; -+ -+ return array; -+} -+ -+ -+/** -+ * eap_peer_get_methods - Get a list of enabled EAP peer methods -+ * @count: Set to number of available methods -+ * Returns: List of enabled EAP peer methods -+ */ -+const struct eap_method * eap_peer_get_methods(size_t *count) -+{ -+ int c = 0; -+ struct eap_method *m; -+ -+ for (m = eap_methods; m; m = m->next) -+ c++; -+ -+ *count = c; -+ return eap_methods; -+} -+ -+ -+#ifdef CONFIG_DYNAMIC_EAP_METHODS -+/** -+ * eap_peer_method_load - Load a dynamic EAP method library (shared object) -+ * @so: File path for the shared object file to load -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_peer_method_load(const char *so) -+{ -+ void *handle; -+ int (*dyn_init)(void); -+ int ret; -+ -+ handle = dlopen(so, RTLD_LAZY); -+ if (handle == NULL) { -+ wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method " -+ "'%s': %s", so, dlerror()); -+ return -1; -+ } -+ -+ dyn_init = dlsym(handle, "eap_peer_method_dynamic_init"); -+ if (dyn_init == NULL) { -+ dlclose(handle); -+ wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no " -+ "eap_peer_method_dynamic_init()", so); -+ return -1; -+ } -+ -+ ret = dyn_init(); -+ if (ret) { -+ dlclose(handle); -+ wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - " -+ "ret %d", so, ret); -+ return ret; -+ } -+ -+ /* Store the handle for this shared object. It will be freed with -+ * dlclose() when the EAP method is unregistered. */ -+ eap_methods->dl_handle = handle; -+ -+ wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so); -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_peer_method_unload - Unload a dynamic EAP method library (shared object) -+ * @method: Pointer to the dynamically loaded EAP method -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to unload EAP methods that have been previously -+ * loaded with eap_peer_method_load(). Before unloading the method, all -+ * references to the method must be removed to make sure that no dereferences -+ * of freed memory will occur after unloading. -+ */ -+int eap_peer_method_unload(struct eap_method *method) -+{ -+ struct eap_method *m, *prev; -+ void *handle; -+ -+ m = eap_methods; -+ prev = NULL; -+ while (m) { -+ if (m == method) -+ break; -+ prev = m; -+ m = m->next; -+ } -+ -+ if (m == NULL || m->dl_handle == NULL) -+ return -1; -+ -+ if (prev) -+ prev->next = m->next; -+ else -+ eap_methods = m->next; -+ -+ handle = m->dl_handle; -+ -+ if (m->free) -+ m->free(m); -+ else -+ eap_peer_method_free(m); -+ -+ dlclose(handle); -+ -+ return 0; -+} -+#endif /* CONFIG_DYNAMIC_EAP_METHODS */ -+ -+ -+/** -+ * eap_peer_method_alloc - Allocate EAP peer method structure -+ * @version: Version of the EAP peer method interface (set to -+ * EAP_PEER_METHOD_INTERFACE_VERSION) -+ * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) -+ * @method: EAP type number (EAP_TYPE_*) -+ * @name: Name of the method (e.g., "TLS") -+ * Returns: Allocated EAP method structure or %NULL on failure -+ * -+ * The returned structure should be freed with eap_peer_method_free() when it -+ * is not needed anymore. -+ */ -+struct eap_method * eap_peer_method_alloc(int version, int vendor, -+ EapType method, const char *name) -+{ -+ struct eap_method *eap; -+ eap = os_zalloc(sizeof(*eap)); -+ if (eap == NULL) -+ return NULL; -+ eap->version = version; -+ eap->vendor = vendor; -+ eap->method = method; -+ eap->name = name; -+ return eap; -+} -+ -+ -+/** -+ * eap_peer_method_free - Free EAP peer method structure -+ * @method: Method structure allocated with eap_peer_method_alloc() -+ */ -+void eap_peer_method_free(struct eap_method *method) -+{ -+ os_free(method); -+} -+ -+ -+/** -+ * eap_peer_method_register - Register an EAP peer method -+ * @method: EAP method to register -+ * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method -+ * has already been registered -+ * -+ * Each EAP peer method needs to call this function to register itself as a -+ * supported EAP method. -+ */ -+int eap_peer_method_register(struct eap_method *method) -+{ -+ struct eap_method *m, *last = NULL; -+ -+ if (method == NULL || method->name == NULL || -+ method->version != EAP_PEER_METHOD_INTERFACE_VERSION) -+ return -1; -+ -+ for (m = eap_methods; m; m = m->next) { -+ if ((m->vendor == method->vendor && -+ m->method == method->method) || -+ os_strcmp(m->name, method->name) == 0) -+ return -2; -+ last = m; -+ } -+ -+ if (last) -+ last->next = method; -+ else -+ eap_methods = method; -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_peer_unregister_methods - Unregister EAP peer methods -+ * -+ * This function is called at program termination to unregister all EAP peer -+ * methods. -+ */ -+void eap_peer_unregister_methods(void) -+{ -+ struct eap_method *m; -+#ifdef CONFIG_DYNAMIC_EAP_METHODS -+ void *handle; -+#endif /* CONFIG_DYNAMIC_EAP_METHODS */ -+ -+ while (eap_methods) { -+ m = eap_methods; -+ eap_methods = eap_methods->next; -+ -+#ifdef CONFIG_DYNAMIC_EAP_METHODS -+ handle = m->dl_handle; -+#endif /* CONFIG_DYNAMIC_EAP_METHODS */ -+ -+ if (m->free) -+ m->free(m); -+ else -+ eap_peer_method_free(m); -+ -+#ifdef CONFIG_DYNAMIC_EAP_METHODS -+ if (handle) -+ dlclose(handle); -+#endif /* CONFIG_DYNAMIC_EAP_METHODS */ -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.h -new file mode 100644 -index 0000000000000..4330b5748d324 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_methods.h -@@ -0,0 +1,114 @@ -+/* -+ * EAP peer: Method registration -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_METHODS_H -+#define EAP_METHODS_H -+ -+#include "eap_common/eap_defs.h" -+ -+const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method); -+const struct eap_method * eap_peer_get_methods(size_t *count); -+ -+struct eap_method * eap_peer_method_alloc(int version, int vendor, -+ EapType method, const char *name); -+void eap_peer_method_free(struct eap_method *method); -+int eap_peer_method_register(struct eap_method *method); -+ -+ -+#ifdef IEEE8021X_EAPOL -+ -+EapType eap_peer_get_type(const char *name, int *vendor); -+const char * eap_get_name(int vendor, EapType type); -+size_t eap_get_names(char *buf, size_t buflen); -+char ** eap_get_names_as_string_array(size_t *num); -+void eap_peer_unregister_methods(void); -+ -+#else /* IEEE8021X_EAPOL */ -+ -+static inline EapType eap_peer_get_type(const char *name, int *vendor) -+{ -+ *vendor = EAP_VENDOR_IETF; -+ return EAP_TYPE_NONE; -+} -+ -+static inline const char * eap_get_name(int vendor, EapType type) -+{ -+ return NULL; -+} -+ -+static inline size_t eap_get_names(char *buf, size_t buflen) -+{ -+ return 0; -+} -+ -+static inline int eap_peer_register_methods(void) -+{ -+ return 0; -+} -+ -+static inline void eap_peer_unregister_methods(void) -+{ -+} -+ -+static inline char ** eap_get_names_as_string_array(size_t *num) -+{ -+ return NULL; -+} -+ -+#endif /* IEEE8021X_EAPOL */ -+ -+ -+#ifdef CONFIG_DYNAMIC_EAP_METHODS -+ -+int eap_peer_method_load(const char *so); -+int eap_peer_method_unload(struct eap_method *method); -+ -+#else /* CONFIG_DYNAMIC_EAP_METHODS */ -+ -+static inline int eap_peer_method_load(const char *so) -+{ -+ return 0; -+} -+ -+static inline int eap_peer_method_unload(struct eap_method *method) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_DYNAMIC_EAP_METHODS */ -+ -+/* EAP peer method registration calls for statically linked in methods */ -+int eap_peer_md5_register(void); -+int eap_peer_tls_register(void); -+int eap_peer_mschapv2_register(void); -+int eap_peer_peap_register(void); -+int eap_peer_ttls_register(void); -+int eap_peer_gtc_register(void); -+int eap_peer_otp_register(void); -+int eap_peer_sim_register(void); -+int eap_peer_leap_register(void); -+int eap_peer_psk_register(void); -+int eap_peer_aka_register(void); -+int eap_peer_aka_prime_register(void); -+int eap_peer_fast_register(void); -+int eap_peer_pax_register(void); -+int eap_peer_sake_register(void); -+int eap_peer_gpsk_register(void); -+int eap_peer_wsc_register(void); -+int eap_peer_ikev2_register(void); -+int eap_peer_vendor_test_register(void); -+int eap_peer_tnc_register(void); -+int eap_peer_pwd_register(void); -+ -+#endif /* EAP_METHODS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_mschapv2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_mschapv2.c -new file mode 100644 -index 0000000000000..321e9f78ec091 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_mschapv2.c -@@ -0,0 +1,883 @@ -+/* -+ * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26). -+ * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP -+ * Extensions Protocol, Version 2, for mutual authentication and key -+ * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in -+ * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in -+ * RFC 3079. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/ms_funcs.h" -+#include "crypto/random.h" -+#include "common/wpa_ctrl.h" -+#include "mschapv2.h" -+#include "eap_i.h" -+#include "eap_config.h" -+ -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct eap_mschapv2_hdr { -+ u8 op_code; /* MSCHAPV2_OP_* */ -+ u8 mschapv2_id; /* usually same as EAP identifier; must be changed -+ * for challenges, but not for success/failure */ -+ u8 ms_length[2]; /* Note: misaligned; length - 5 */ -+ /* followed by data */ -+} STRUCT_PACKED; -+ -+/* Response Data field */ -+struct ms_response { -+ u8 peer_challenge[MSCHAPV2_CHAL_LEN]; -+ u8 reserved[8]; -+ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN]; -+ u8 flags; -+} STRUCT_PACKED; -+ -+/* Change-Password Data field */ -+struct ms_change_password { -+ u8 encr_password[516]; -+ u8 encr_hash[16]; -+ u8 peer_challenge[MSCHAPV2_CHAL_LEN]; -+ u8 reserved[8]; -+ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN]; -+ u8 flags[2]; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+#define MSCHAPV2_OP_CHALLENGE 1 -+#define MSCHAPV2_OP_RESPONSE 2 -+#define MSCHAPV2_OP_SUCCESS 3 -+#define MSCHAPV2_OP_FAILURE 4 -+#define MSCHAPV2_OP_CHANGE_PASSWORD 7 -+ -+#define ERROR_RESTRICTED_LOGON_HOURS 646 -+#define ERROR_ACCT_DISABLED 647 -+#define ERROR_PASSWD_EXPIRED 648 -+#define ERROR_NO_DIALIN_PERMISSION 649 -+#define ERROR_AUTHENTICATION_FAILURE 691 -+#define ERROR_CHANGING_PASSWORD 709 -+ -+#define PASSWD_CHANGE_CHAL_LEN 16 -+#define MSCHAPV2_KEY_LEN 16 -+ -+ -+struct eap_mschapv2_data { -+ u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; -+ int auth_response_valid; -+ -+ int prev_error; -+ u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN]; -+ int passwd_change_challenge_valid; -+ int passwd_change_version; -+ -+ /* Optional challenge values generated in EAP-FAST Phase 1 negotiation -+ */ -+ u8 *peer_challenge; -+ u8 *auth_challenge; -+ -+ int phase2; -+ u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; -+ int master_key_valid; -+ int success; -+ -+ struct wpabuf *prev_challenge; -+}; -+ -+ -+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv); -+ -+ -+static void * eap_mschapv2_init(struct eap_sm *sm) -+{ -+ struct eap_mschapv2_data *data; -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ if (sm->peer_challenge) { -+ data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN); -+ if (data->peer_challenge == NULL) { -+ eap_mschapv2_deinit(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->peer_challenge, sm->peer_challenge, -+ MSCHAPV2_CHAL_LEN); -+ } -+ -+ if (sm->auth_challenge) { -+ data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN); -+ if (data->auth_challenge == NULL) { -+ eap_mschapv2_deinit(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->auth_challenge, sm->auth_challenge, -+ MSCHAPV2_CHAL_LEN); -+ } -+ -+ data->phase2 = sm->init_phase2; -+ -+ return data; -+} -+ -+ -+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_mschapv2_data *data = priv; -+ os_free(data->peer_challenge); -+ os_free(data->auth_challenge); -+ wpabuf_free(data->prev_challenge); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_mschapv2_challenge_reply( -+ struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id, -+ u8 mschapv2_id, const u8 *auth_challenge) -+{ -+ struct wpabuf *resp; -+ struct eap_mschapv2_hdr *ms; -+ u8 *peer_challenge; -+ int ms_len; -+ struct ms_response *r; -+ size_t identity_len, password_len; -+ const u8 *identity, *password; -+ int pwhash; -+ -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response"); -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ password = eap_get_config_password2(sm, &password_len, &pwhash); -+ if (identity == NULL || password == NULL) -+ return NULL; -+ -+ ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len; -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ ms = wpabuf_put(resp, sizeof(*ms)); -+ ms->op_code = MSCHAPV2_OP_RESPONSE; -+ ms->mschapv2_id = mschapv2_id; -+ if (data->prev_error) { -+ /* -+ * TODO: this does not seem to be enough when processing two -+ * or more failure messages. IAS did not increment mschapv2_id -+ * in its own packets, but it seemed to expect the peer to -+ * increment this for all packets(?). -+ */ -+ ms->mschapv2_id++; -+ } -+ WPA_PUT_BE16(ms->ms_length, ms_len); -+ -+ wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */ -+ -+ /* Response */ -+ r = wpabuf_put(resp, sizeof(*r)); -+ peer_challenge = r->peer_challenge; -+ if (data->peer_challenge) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated " -+ "in Phase 1"); -+ peer_challenge = data->peer_challenge; -+ os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN); -+ } else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) { -+ wpabuf_free(resp); -+ return NULL; -+ } -+ os_memset(r->reserved, 0, 8); -+ if (data->auth_challenge) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated " -+ "in Phase 1"); -+ auth_challenge = data->auth_challenge; -+ } -+ if (mschapv2_derive_response(identity, identity_len, password, -+ password_len, pwhash, auth_challenge, -+ peer_challenge, r->nt_response, -+ data->auth_response, data->master_key)) { -+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive " -+ "response"); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ data->auth_response_valid = 1; -+ data->master_key_valid = 1; -+ -+ r->flags = 0; /* reserved, must be zero */ -+ -+ wpabuf_put_data(resp, identity, identity_len); -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " -+ "(response)", id, ms->mschapv2_id); -+ return resp; -+} -+ -+ -+/** -+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Pointer to private EAP method data from eap_mschapv2_init() -+ * @ret: Return values from EAP request validation and processing -+ * @req: Pointer to EAP-MSCHAPv2 header from the request -+ * @req_len: Length of the EAP-MSCHAPv2 data -+ * @id: EAP identifier used in the request -+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if -+ * no reply available -+ */ -+static struct wpabuf * eap_mschapv2_challenge( -+ struct eap_sm *sm, struct eap_mschapv2_data *data, -+ struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, -+ size_t req_len, u8 id) -+{ -+ size_t len, challenge_len; -+ const u8 *pos, *challenge; -+ -+ if (eap_get_config_identity(sm, &len) == NULL || -+ eap_get_config_password(sm, &len) == NULL) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge"); -+ if (req_len < sizeof(*req) + 1) { -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data " -+ "(len %lu)", (unsigned long) req_len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ pos = (const u8 *) (req + 1); -+ challenge_len = *pos++; -+ len = req_len - sizeof(*req) - 1; -+ if (challenge_len != MSCHAPV2_CHAL_LEN) { -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length " -+ "%lu", (unsigned long) challenge_len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (len < challenge_len) { -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge" -+ " packet: len=%lu challenge_len=%lu", -+ (unsigned long) len, (unsigned long) challenge_len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->passwd_change_challenge_valid) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the " -+ "failure message"); -+ challenge = data->passwd_change_challenge; -+ } else -+ challenge = pos; -+ pos += challenge_len; -+ len -= challenge_len; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername", -+ pos, len); -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = TRUE; -+ -+ return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id, -+ challenge); -+} -+ -+ -+static void eap_mschapv2_password_changed(struct eap_sm *sm, -+ struct eap_mschapv2_data *data) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config && config->new_password) { -+ wpa_msg(sm->msg_ctx, MSG_INFO, -+ WPA_EVENT_PASSWORD_CHANGED -+ "EAP-MSCHAPV2: Password changed successfully"); -+ data->prev_error = 0; -+ os_free(config->password); -+ if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { -+ config->password = os_malloc(16); -+ config->password_len = 16; -+ if (config->password) { -+ nt_password_hash(config->new_password, -+ config->new_password_len, -+ config->password); -+ } -+ os_free(config->new_password); -+ } else { -+ config->password = config->new_password; -+ config->password_len = config->new_password_len; -+ } -+ config->new_password = NULL; -+ config->new_password_len = 0; -+ } -+} -+ -+ -+/** -+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Pointer to private EAP method data from eap_mschapv2_init() -+ * @ret: Return values from EAP request validation and processing -+ * @req: Pointer to EAP-MSCHAPv2 header from the request -+ * @req_len: Length of the EAP-MSCHAPv2 data -+ * @id: EAP identifier used in th erequest -+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if -+ * no reply available -+ */ -+static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm, -+ struct eap_mschapv2_data *data, -+ struct eap_method_ret *ret, -+ const struct eap_mschapv2_hdr *req, -+ size_t req_len, u8 id) -+{ -+ struct wpabuf *resp; -+ const u8 *pos; -+ size_t len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success"); -+ len = req_len - sizeof(*req); -+ pos = (const u8 *) (req + 1); -+ if (!data->auth_response_valid || -+ mschapv2_verify_auth_response(data->auth_response, pos, len)) { -+ wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator " -+ "response in success request"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN; -+ len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN; -+ while (len > 0 && *pos == ' ') { -+ pos++; -+ len--; -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message", -+ pos, len); -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded"); -+ -+ /* Note: Only op_code of the EAP-MSCHAPV2 header is included in success -+ * message. */ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate " -+ "buffer for success response"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */ -+ -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ ret->allowNotifications = FALSE; -+ data->success = 1; -+ -+ if (data->prev_error == ERROR_PASSWD_EXPIRED) -+ eap_mschapv2_password_changed(sm, data); -+ -+ return resp; -+} -+ -+ -+static int eap_mschapv2_failure_txt(struct eap_sm *sm, -+ struct eap_mschapv2_data *data, char *txt) -+{ -+ char *pos, *msg = ""; -+ int retry = 1; -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ /* For example: -+ * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure -+ */ -+ -+ pos = txt; -+ -+ if (pos && os_strncmp(pos, "E=", 2) == 0) { -+ pos += 2; -+ data->prev_error = atoi(pos); -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d", -+ data->prev_error); -+ pos = os_strchr(pos, ' '); -+ if (pos) -+ pos++; -+ } -+ -+ if (pos && os_strncmp(pos, "R=", 2) == 0) { -+ pos += 2; -+ retry = atoi(pos); -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed", -+ retry == 1 ? "" : "not "); -+ pos = os_strchr(pos, ' '); -+ if (pos) -+ pos++; -+ } -+ -+ if (pos && os_strncmp(pos, "C=", 2) == 0) { -+ int hex_len; -+ pos += 2; -+ hex_len = os_strchr(pos, ' ') - (char *) pos; -+ if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) { -+ if (hexstr2bin(pos, data->passwd_change_challenge, -+ PASSWD_CHANGE_CHAL_LEN)) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid " -+ "failure challenge"); -+ } else { -+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure " -+ "challenge", -+ data->passwd_change_challenge, -+ PASSWD_CHANGE_CHAL_LEN); -+ data->passwd_change_challenge_valid = 1; -+ } -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure " -+ "challenge len %d", hex_len); -+ } -+ pos = os_strchr(pos, ' '); -+ if (pos) -+ pos++; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field " -+ "was not present in failure message"); -+ } -+ -+ if (pos && os_strncmp(pos, "V=", 2) == 0) { -+ pos += 2; -+ data->passwd_change_version = atoi(pos); -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing " -+ "protocol version %d", data->passwd_change_version); -+ pos = os_strchr(pos, ' '); -+ if (pos) -+ pos++; -+ } -+ -+ if (pos && os_strncmp(pos, "M=", 2) == 0) { -+ pos += 2; -+ msg = pos; -+ } -+ wpa_msg(sm->msg_ctx, MSG_WARNING, -+ "EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error " -+ "%d)", -+ msg, retry == 1 ? "" : "not ", data->prev_error); -+ if (data->prev_error == ERROR_PASSWD_EXPIRED && -+ data->passwd_change_version == 3 && config) { -+ if (config->new_password == NULL) { -+ wpa_msg(sm->msg_ctx, MSG_INFO, -+ "EAP-MSCHAPV2: Password expired - password " -+ "change required"); -+ eap_sm_request_new_password(sm); -+ } -+ } else if (retry == 1 && config) { -+ /* TODO: could prevent the current password from being used -+ * again at least for some period of time */ -+ if (!config->mschapv2_retry) -+ eap_sm_request_identity(sm); -+ eap_sm_request_password(sm); -+ config->mschapv2_retry = 1; -+ } else if (config) { -+ /* TODO: prevent retries using same username/password */ -+ config->mschapv2_retry = 0; -+ } -+ -+ return retry == 1; -+} -+ -+ -+static struct wpabuf * eap_mschapv2_change_password( -+ struct eap_sm *sm, struct eap_mschapv2_data *data, -+ struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id) -+{ -+ struct wpabuf *resp; -+ int ms_len; -+ const u8 *username, *password, *new_password; -+ size_t username_len, password_len, new_password_len; -+ struct eap_mschapv2_hdr *ms; -+ struct ms_change_password *cp; -+ u8 password_hash[16], password_hash_hash[16]; -+ int pwhash; -+ -+ username = eap_get_config_identity(sm, &username_len); -+ password = eap_get_config_password2(sm, &password_len, &pwhash); -+ new_password = eap_get_config_new_password(sm, &new_password_len); -+ if (username == NULL || password == NULL || new_password == NULL) -+ return NULL; -+ -+ username = mschapv2_remove_domain(username, &username_len); -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_COND_SUCC; -+ ret->allowNotifications = TRUE; -+ -+ ms_len = sizeof(*ms) + sizeof(*cp); -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ ms = wpabuf_put(resp, sizeof(*ms)); -+ ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD; -+ ms->mschapv2_id = req->mschapv2_id + 1; -+ WPA_PUT_BE16(ms->ms_length, ms_len); -+ cp = wpabuf_put(resp, sizeof(*cp)); -+ -+ /* Encrypted-Password */ -+ if (pwhash) { -+ if (encrypt_pw_block_with_password_hash( -+ new_password, new_password_len, -+ password, cp->encr_password)) -+ goto fail; -+ } else { -+ if (new_password_encrypted_with_old_nt_password_hash( -+ new_password, new_password_len, -+ password, password_len, cp->encr_password)) -+ goto fail; -+ } -+ -+ /* Encrypted-Hash */ -+ if (pwhash) { -+ u8 new_password_hash[16]; -+ nt_password_hash(new_password, new_password_len, -+ new_password_hash); -+ nt_password_hash_encrypted_with_block(password, -+ new_password_hash, -+ cp->encr_hash); -+ } else { -+ old_nt_password_hash_encrypted_with_new_nt_password_hash( -+ new_password, new_password_len, -+ password, password_len, cp->encr_hash); -+ } -+ -+ /* Peer-Challenge */ -+ if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN)) -+ goto fail; -+ -+ /* Reserved, must be zero */ -+ os_memset(cp->reserved, 0, 8); -+ -+ /* NT-Response */ -+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", -+ data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge", -+ cp->peer_challenge, MSCHAPV2_CHAL_LEN); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username", -+ username, username_len); -+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password", -+ new_password, new_password_len); -+ generate_nt_response(data->passwd_change_challenge, cp->peer_challenge, -+ username, username_len, -+ new_password, new_password_len, -+ cp->nt_response); -+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response", -+ cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN); -+ -+ /* Authenticator response is not really needed yet, but calculate it -+ * here so that challenges need not be saved. */ -+ generate_authenticator_response(new_password, new_password_len, -+ cp->peer_challenge, -+ data->passwd_change_challenge, -+ username, username_len, -+ cp->nt_response, data->auth_response); -+ data->auth_response_valid = 1; -+ -+ /* Likewise, generate master_key here since we have the needed data -+ * available. */ -+ nt_password_hash(new_password, new_password_len, password_hash); -+ hash_nt_password_hash(password_hash, password_hash_hash); -+ get_master_key(password_hash_hash, cp->nt_response, data->master_key); -+ data->master_key_valid = 1; -+ -+ /* Flags */ -+ os_memset(cp->flags, 0, 2); -+ -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d " -+ "(change pw)", id, ms->mschapv2_id); -+ -+ return resp; -+ -+fail: -+ wpabuf_free(resp); -+ return NULL; -+} -+ -+ -+/** -+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Pointer to private EAP method data from eap_mschapv2_init() -+ * @ret: Return values from EAP request validation and processing -+ * @req: Pointer to EAP-MSCHAPv2 header from the request -+ * @req_len: Length of the EAP-MSCHAPv2 data -+ * @id: EAP identifier used in th erequest -+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if -+ * no reply available -+ */ -+static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm, -+ struct eap_mschapv2_data *data, -+ struct eap_method_ret *ret, -+ const struct eap_mschapv2_hdr *req, -+ size_t req_len, u8 id) -+{ -+ struct wpabuf *resp; -+ const u8 *msdata = (const u8 *) (req + 1); -+ char *buf; -+ size_t len = req_len - sizeof(*req); -+ int retry = 0; -+ -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure"); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data", -+ msdata, len); -+ /* -+ * eap_mschapv2_failure_txt() expects a nul terminated string, so we -+ * must allocate a large enough temporary buffer to create that since -+ * the received message does not include nul termination. -+ */ -+ buf = os_malloc(len + 1); -+ if (buf) { -+ os_memcpy(buf, msdata, len); -+ buf[len] = '\0'; -+ retry = eap_mschapv2_failure_txt(sm, data, buf); -+ os_free(buf); -+ } -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = FALSE; -+ -+ if (data->prev_error == ERROR_PASSWD_EXPIRED && -+ data->passwd_change_version == 3) { -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config && config->new_password) -+ return eap_mschapv2_change_password(sm, data, ret, req, -+ id); -+ if (config && config->pending_req_new_password) -+ return NULL; -+ } else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) { -+ /* TODO: could try to retry authentication, e.g, after having -+ * changed the username/password. In this case, EAP MS-CHAP-v2 -+ * Failure Response would not be sent here. */ -+ return NULL; -+ } -+ -+ /* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure -+ * message. */ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */ -+ -+ return resp; -+} -+ -+ -+static int eap_mschapv2_check_config(struct eap_sm *sm) -+{ -+ size_t len; -+ -+ if (eap_get_config_identity(sm, &len) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured"); -+ eap_sm_request_identity(sm); -+ return -1; -+ } -+ -+ if (eap_get_config_password(sm, &len) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured"); -+ eap_sm_request_password(sm); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len, -+ const struct eap_mschapv2_hdr *ms) -+{ -+ size_t ms_len = WPA_GET_BE16(ms->ms_length); -+ -+ if (ms_len == len) -+ return 0; -+ -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu " -+ "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len); -+ if (sm->workaround) { -+ /* Some authentication servers use invalid ms_len, -+ * ignore it for interoperability. */ -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore" -+ " invalid ms_len %lu (len %lu)", -+ (unsigned long) ms_len, -+ (unsigned long) len); -+ return 0; -+ } -+ -+ return -1; -+} -+ -+ -+static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data, -+ const struct wpabuf *reqData) -+{ -+ /* -+ * Store a copy of the challenge message, so that it can be processed -+ * again in case retry is allowed after a possible failure. -+ */ -+ wpabuf_free(data->prev_challenge); -+ data->prev_challenge = wpabuf_dup(reqData); -+} -+ -+ -+/** -+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 request -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @priv: Pointer to private EAP method data from eap_mschapv2_init() -+ * @ret: Return values from EAP request validation and processing -+ * @reqData: EAP request to be processed (eapReqData) -+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if -+ * no reply available -+ */ -+static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_mschapv2_data *data = priv; -+ struct eap_peer_config *config = eap_get_config(sm); -+ const struct eap_mschapv2_hdr *ms; -+ int using_prev_challenge = 0; -+ const u8 *pos; -+ size_t len; -+ u8 id; -+ -+ if (eap_mschapv2_check_config(sm)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (config->mschapv2_retry && data->prev_challenge && -+ data->prev_error == ERROR_AUTHENTICATION_FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet " -+ "with the previous challenge"); -+ -+ reqData = data->prev_challenge; -+ using_prev_challenge = 1; -+ config->mschapv2_retry = 0; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData, -+ &len); -+ if (pos == NULL || len < sizeof(*ms) + 1) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ ms = (const struct eap_mschapv2_hdr *) pos; -+ if (eap_mschapv2_check_mslen(sm, len, ms)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ id = eap_get_id(reqData); -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d", -+ id, ms->mschapv2_id); -+ -+ switch (ms->op_code) { -+ case MSCHAPV2_OP_CHALLENGE: -+ if (!using_prev_challenge) -+ eap_mschapv2_copy_challenge(data, reqData); -+ return eap_mschapv2_challenge(sm, data, ret, ms, len, id); -+ case MSCHAPV2_OP_SUCCESS: -+ return eap_mschapv2_success(sm, data, ret, ms, len, id); -+ case MSCHAPV2_OP_FAILURE: -+ return eap_mschapv2_failure(sm, data, ret, ms, len, id); -+ default: -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored", -+ ms->op_code); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+} -+ -+ -+static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_mschapv2_data *data = priv; -+ return data->success && data->master_key_valid; -+} -+ -+ -+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_mschapv2_data *data = priv; -+ u8 *key; -+ int key_len; -+ -+ if (!data->master_key_valid || !data->success) -+ return NULL; -+ -+ key_len = 2 * MSCHAPV2_KEY_LEN; -+ -+ key = os_malloc(key_len); -+ if (key == NULL) -+ return NULL; -+ -+ /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e., -+ * peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */ -+ get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0); -+ get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, -+ MSCHAPV2_KEY_LEN, 0, 0); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", -+ key, key_len); -+ -+ *len = key_len; -+ return key; -+} -+ -+ -+/** -+ * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to register EAP-MSCHAPv2 peer method into the EAP -+ * method list. -+ */ -+int eap_peer_mschapv2_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, -+ "MSCHAPV2"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_mschapv2_init; -+ eap->deinit = eap_mschapv2_deinit; -+ eap->process = eap_mschapv2_process; -+ eap->isKeyAvailable = eap_mschapv2_isKeyAvailable; -+ eap->getKey = eap_mschapv2_getKey; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_otp.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_otp.c -new file mode 100644 -index 0000000000000..556c22f9e2d59 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_otp.c -@@ -0,0 +1,107 @@ -+/* -+ * EAP peer method: EAP-OTP (RFC 3748) -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+ -+ -+static void * eap_otp_init(struct eap_sm *sm) -+{ -+ /* No need for private data. However, must return non-NULL to indicate -+ * success. */ -+ return (void *) 1; -+} -+ -+ -+static void eap_otp_deinit(struct eap_sm *sm, void *priv) -+{ -+} -+ -+ -+static struct wpabuf * eap_otp_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct wpabuf *resp; -+ const u8 *pos, *password; -+ size_t password_len, len; -+ int otp; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP, reqData, &len); -+ if (pos == NULL) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message", -+ pos, len); -+ -+ password = eap_get_config_otp(sm, &password_len); -+ if (password) -+ otp = 1; -+ else { -+ password = eap_get_config_password(sm, &password_len); -+ otp = 0; -+ } -+ -+ if (password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-OTP: Password not configured"); -+ eap_sm_request_otp(sm, (const char *) pos, len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ ret->ignore = FALSE; -+ -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_COND_SUCC; -+ ret->allowNotifications = FALSE; -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, password_len, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ wpabuf_put_data(resp, password, password_len); -+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response", -+ password, password_len); -+ -+ if (otp) { -+ wpa_printf(MSG_DEBUG, "EAP-OTP: Forgetting used password"); -+ eap_clear_config_otp(sm); -+ } -+ -+ return resp; -+} -+ -+ -+int eap_peer_otp_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_OTP, "OTP"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_otp_init; -+ eap->deinit = eap_otp_deinit; -+ eap->process = eap_otp_process; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pax.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pax.c -new file mode 100644 -index 0000000000000..d42a7f869eb47 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pax.c -@@ -0,0 +1,531 @@ -+/* -+ * EAP peer method: EAP-PAX (RFC 4746) -+ * Copyright (c) 2005-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_common/eap_pax_common.h" -+#include "eap_i.h" -+ -+/* -+ * Note: only PAX_STD subprotocol is currently supported -+ * -+ * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite -+ * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and -+ * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits), -+ * RSAES-OAEP). -+ */ -+ -+struct eap_pax_data { -+ enum { PAX_INIT, PAX_STD_2_SENT, PAX_DONE } state; -+ u8 mac_id, dh_group_id, public_key_id; -+ union { -+ u8 e[2 * EAP_PAX_RAND_LEN]; -+ struct { -+ u8 x[EAP_PAX_RAND_LEN]; /* server rand */ -+ u8 y[EAP_PAX_RAND_LEN]; /* client rand */ -+ } r; -+ } rand; -+ char *cid; -+ size_t cid_len; -+ u8 ak[EAP_PAX_AK_LEN]; -+ u8 mk[EAP_PAX_MK_LEN]; -+ u8 ck[EAP_PAX_CK_LEN]; -+ u8 ick[EAP_PAX_ICK_LEN]; -+}; -+ -+ -+static void eap_pax_deinit(struct eap_sm *sm, void *priv); -+ -+ -+static void * eap_pax_init(struct eap_sm *sm) -+{ -+ struct eap_pax_data *data; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ password = eap_get_config_password(sm, &password_len); -+ if (!identity || !password) { -+ wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key (password) " -+ "not configured"); -+ return NULL; -+ } -+ -+ if (password_len != EAP_PAX_AK_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Invalid PSK length"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = PAX_INIT; -+ -+ data->cid = os_malloc(identity_len); -+ if (data->cid == NULL) { -+ eap_pax_deinit(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->cid, identity, identity_len); -+ data->cid_len = identity_len; -+ -+ os_memcpy(data->ak, password, EAP_PAX_AK_LEN); -+ -+ return data; -+} -+ -+ -+static void eap_pax_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pax_data *data = priv; -+ os_free(data->cid); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_pax_alloc_resp(const struct eap_pax_hdr *req, -+ u8 id, u8 op_code, size_t plen) -+{ -+ struct wpabuf *resp; -+ struct eap_pax_hdr *pax; -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX, -+ sizeof(*pax) + plen, EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ pax = wpabuf_put(resp, sizeof(*pax)); -+ pax->op_code = op_code; -+ pax->flags = 0; -+ pax->mac_id = req->mac_id; -+ pax->dh_group_id = req->dh_group_id; -+ pax->public_key_id = req->public_key_id; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_pax_process_std_1(struct eap_pax_data *data, -+ struct eap_method_ret *ret, u8 id, -+ const struct eap_pax_hdr *req, -+ size_t req_plen) -+{ -+ struct wpabuf *resp; -+ const u8 *pos; -+ u8 *rpos; -+ size_t left, plen; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (received)"); -+ -+ if (data->state != PAX_INIT) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in " -+ "unexpected state (%d) - ignored", data->state); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (req->flags & EAP_PAX_FLAGS_CE) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - " -+ "ignored"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ left = req_plen - sizeof(*req); -+ -+ if (left < 2 + EAP_PAX_RAND_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short " -+ "payload"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ pos = (const u8 *) (req + 1); -+ if (WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A " -+ "length %d (expected %d)", -+ WPA_GET_BE16(pos), EAP_PAX_RAND_LEN); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ pos += 2; -+ left -= 2; -+ os_memcpy(data->rand.r.x, pos, EAP_PAX_RAND_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: X (server rand)", -+ data->rand.r.x, EAP_PAX_RAND_LEN); -+ pos += EAP_PAX_RAND_LEN; -+ left -= EAP_PAX_RAND_LEN; -+ -+ if (left > 0) { -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", -+ pos, left); -+ } -+ -+ if (random_get_bytes(data->rand.r.y, EAP_PAX_RAND_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)", -+ data->rand.r.y, EAP_PAX_RAND_LEN); -+ -+ if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e, -+ data->mk, data->ck, data->ick) < 0) -+ { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-2 (sending)"); -+ -+ plen = 2 + EAP_PAX_RAND_LEN + 2 + data->cid_len + 2 + EAP_PAX_MAC_LEN + -+ EAP_PAX_ICV_LEN; -+ resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_STD_2, plen); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_be16(resp, EAP_PAX_RAND_LEN); -+ wpabuf_put_data(resp, data->rand.r.y, EAP_PAX_RAND_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: B = Y (client rand)", -+ data->rand.r.y, EAP_PAX_RAND_LEN); -+ -+ wpabuf_put_be16(resp, data->cid_len); -+ wpabuf_put_data(resp, data->cid, data->cid_len); -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", -+ (u8 *) data->cid, data->cid_len); -+ -+ wpabuf_put_be16(resp, EAP_PAX_MAC_LEN); -+ rpos = wpabuf_put(resp, EAP_PAX_MAC_LEN); -+ eap_pax_mac(req->mac_id, data->ck, EAP_PAX_CK_LEN, -+ data->rand.r.x, EAP_PAX_RAND_LEN, -+ data->rand.r.y, EAP_PAX_RAND_LEN, -+ (u8 *) data->cid, data->cid_len, rpos); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)", -+ rpos, EAP_PAX_MAC_LEN); -+ -+ /* Optional ADE could be added here, if needed */ -+ -+ rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN); -+ eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN, -+ wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN, -+ NULL, 0, NULL, 0, rpos); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN); -+ -+ data->state = PAX_STD_2_SENT; -+ data->mac_id = req->mac_id; -+ data->dh_group_id = req->dh_group_id; -+ data->public_key_id = req->public_key_id; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data, -+ struct eap_method_ret *ret, u8 id, -+ const struct eap_pax_hdr *req, -+ size_t req_plen) -+{ -+ struct wpabuf *resp; -+ u8 *rpos, mac[EAP_PAX_MAC_LEN]; -+ const u8 *pos; -+ size_t left; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (received)"); -+ -+ if (data->state != PAX_STD_2_SENT) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in " -+ "unexpected state (%d) - ignored", data->state); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (req->flags & EAP_PAX_FLAGS_CE) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - " -+ "ignored"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ left = req_plen - sizeof(*req); -+ -+ if (left < 2 + EAP_PAX_MAC_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short " -+ "payload"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ pos = (const u8 *) (req + 1); -+ if (WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect " -+ "MAC_CK length %d (expected %d)", -+ WPA_GET_BE16(pos), EAP_PAX_MAC_LEN); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ pos += 2; -+ left -= 2; -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)", -+ pos, EAP_PAX_MAC_LEN); -+ eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, -+ data->rand.r.y, EAP_PAX_RAND_LEN, -+ (u8 *) data->cid, data->cid_len, NULL, 0, mac); -+ if (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) " -+ "received"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)", -+ mac, EAP_PAX_MAC_LEN); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ -+ pos += EAP_PAX_MAC_LEN; -+ left -= EAP_PAX_MAC_LEN; -+ -+ if (left > 0) { -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", -+ pos, left); -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX-ACK (sending)"); -+ -+ resp = eap_pax_alloc_resp(req, id, EAP_PAX_OP_ACK, EAP_PAX_ICV_LEN); -+ if (resp == NULL) -+ return NULL; -+ -+ /* Optional ADE could be added here, if needed */ -+ -+ rpos = wpabuf_put(resp, EAP_PAX_ICV_LEN); -+ eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, -+ wpabuf_head(resp), wpabuf_len(resp) - EAP_PAX_ICV_LEN, -+ NULL, 0, NULL, 0, rpos); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN); -+ -+ data->state = PAX_DONE; -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ ret->allowNotifications = FALSE; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_pax_data *data = priv; -+ const struct eap_pax_hdr *req; -+ struct wpabuf *resp; -+ u8 icvbuf[EAP_PAX_ICV_LEN], id; -+ const u8 *icv, *pos; -+ size_t len; -+ u16 flen, mlen; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, reqData, &len); -+ if (pos == NULL || len < EAP_PAX_ICV_LEN) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ id = eap_get_id(reqData); -+ req = (const struct eap_pax_hdr *) pos; -+ flen = len - EAP_PAX_ICV_LEN; -+ mlen = wpabuf_len(reqData) - EAP_PAX_ICV_LEN; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x " -+ "flags 0x%x mac_id 0x%x dh_group_id 0x%x " -+ "public_key_id 0x%x", -+ req->op_code, req->flags, req->mac_id, req->dh_group_id, -+ req->public_key_id); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload", -+ pos, len - EAP_PAX_ICV_LEN); -+ -+ if (data->state != PAX_INIT && data->mac_id != req->mac_id) { -+ wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during " -+ "authentication (was 0x%d, is 0x%d)", -+ data->mac_id, req->mac_id); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->state != PAX_INIT && data->dh_group_id != req->dh_group_id) { -+ wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during " -+ "authentication (was 0x%d, is 0x%d)", -+ data->dh_group_id, req->dh_group_id); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->state != PAX_INIT && -+ data->public_key_id != req->public_key_id) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during " -+ "authentication (was 0x%d, is 0x%d)", -+ data->public_key_id, req->public_key_id); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ /* TODO: add support EAP_PAX_HMAC_SHA256_128 */ -+ if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x", -+ req->mac_id); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x", -+ req->dh_group_id); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x", -+ req->public_key_id); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (req->flags & EAP_PAX_FLAGS_MF) { -+ /* TODO: add support for reassembling fragments */ -+ wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - " -+ "ignored packet"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ icv = pos + len - EAP_PAX_ICV_LEN; -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN); -+ if (req->op_code == EAP_PAX_OP_STD_1) { -+ eap_pax_mac(req->mac_id, (u8 *) "", 0, -+ wpabuf_head(reqData), mlen, NULL, 0, NULL, 0, -+ icvbuf); -+ } else { -+ eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN, -+ wpabuf_head(reqData), mlen, NULL, 0, NULL, 0, -+ icvbuf); -+ } -+ if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the " -+ "message"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV", -+ icvbuf, EAP_PAX_ICV_LEN); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = TRUE; -+ -+ switch (req->op_code) { -+ case EAP_PAX_OP_STD_1: -+ resp = eap_pax_process_std_1(data, ret, id, req, flen); -+ break; -+ case EAP_PAX_OP_STD_3: -+ resp = eap_pax_process_std_3(data, ret, id, req, flen); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown " -+ "op_code %d", req->op_code); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (ret->methodState == METHOD_DONE) { -+ ret->allowNotifications = FALSE; -+ } -+ -+ return resp; -+} -+ -+ -+static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pax_data *data = priv; -+ return data->state == PAX_DONE; -+} -+ -+ -+static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pax_data *data = priv; -+ u8 *key; -+ -+ if (data->state != PAX_DONE) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_MSK_LEN; -+ eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, -+ "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN, -+ EAP_MSK_LEN, key); -+ -+ return key; -+} -+ -+ -+static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pax_data *data = priv; -+ u8 *key; -+ -+ if (data->state != PAX_DONE) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_EMSK_LEN; -+ eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, -+ "Extended Master Session Key", -+ data->rand.e, 2 * EAP_PAX_RAND_LEN, -+ EAP_EMSK_LEN, key); -+ -+ return key; -+} -+ -+ -+int eap_peer_pax_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_pax_init; -+ eap->deinit = eap_pax_deinit; -+ eap->process = eap_pax_process; -+ eap->isKeyAvailable = eap_pax_isKeyAvailable; -+ eap->getKey = eap_pax_getKey; -+ eap->get_emsk = eap_pax_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_peap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_peap.c -new file mode 100644 -index 0000000000000..2b72084e54337 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_peap.c -@@ -0,0 +1,1288 @@ -+/* -+ * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "eap_common/eap_tlv_common.h" -+#include "eap_common/eap_peap_common.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+#include "eap_config.h" -+#include "tncc.h" -+ -+ -+/* Maximum supported PEAP version -+ * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt -+ * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt -+ * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt -+ */ -+#define EAP_PEAP_VERSION 1 -+ -+ -+static void eap_peap_deinit(struct eap_sm *sm, void *priv); -+ -+ -+struct eap_peap_data { -+ struct eap_ssl_data ssl; -+ -+ int peap_version, force_peap_version, force_new_label; -+ -+ const struct eap_method *phase2_method; -+ void *phase2_priv; -+ int phase2_success; -+ int phase2_eap_success; -+ int phase2_eap_started; -+ -+ struct eap_method_type phase2_type; -+ struct eap_method_type *phase2_types; -+ size_t num_phase2_types; -+ -+ int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner -+ * EAP-Success -+ * 1 = reply with tunneled EAP-Success to inner -+ * EAP-Success and expect AS to send outer -+ * (unencrypted) EAP-Success after this -+ * 2 = reply with PEAP/TLS ACK to inner -+ * EAP-Success and expect AS to send outer -+ * (unencrypted) EAP-Success after this */ -+ int resuming; /* starting a resumed session */ -+ int reauth; /* reauthentication */ -+ u8 *key_data; -+ -+ struct wpabuf *pending_phase2_req; -+ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; -+ int crypto_binding_used; -+ u8 binding_nonce[32]; -+ u8 ipmk[40]; -+ u8 cmk[20]; -+ int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) -+ * is enabled. */ -+}; -+ -+ -+static int eap_peap_parse_phase1(struct eap_peap_data *data, -+ const char *phase1) -+{ -+ const char *pos; -+ -+ pos = os_strstr(phase1, "peapver="); -+ if (pos) { -+ data->force_peap_version = atoi(pos + 8); -+ data->peap_version = data->force_peap_version; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d", -+ data->force_peap_version); -+ } -+ -+ if (os_strstr(phase1, "peaplabel=1")) { -+ data->force_new_label = 1; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key " -+ "derivation"); -+ } -+ -+ if (os_strstr(phase1, "peap_outer_success=0")) { -+ data->peap_outer_success = 0; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on " -+ "tunneled EAP-Success"); -+ } else if (os_strstr(phase1, "peap_outer_success=1")) { -+ data->peap_outer_success = 1; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success " -+ "after receiving tunneled EAP-Success"); -+ } else if (os_strstr(phase1, "peap_outer_success=2")) { -+ data->peap_outer_success = 2; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after " -+ "receiving tunneled EAP-Success"); -+ } -+ -+ if (os_strstr(phase1, "crypto_binding=0")) { -+ data->crypto_binding = NO_BINDING; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding"); -+ } else if (os_strstr(phase1, "crypto_binding=1")) { -+ data->crypto_binding = OPTIONAL_BINDING; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding"); -+ } else if (os_strstr(phase1, "crypto_binding=2")) { -+ data->crypto_binding = REQUIRE_BINDING; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); -+ } -+ -+#ifdef EAP_TNC -+ if (os_strstr(phase1, "tnc=soh2")) { -+ data->soh = 2; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); -+ } else if (os_strstr(phase1, "tnc=soh1")) { -+ data->soh = 1; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled"); -+ } else if (os_strstr(phase1, "tnc=soh")) { -+ data->soh = 2; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); -+ } -+#endif /* EAP_TNC */ -+ -+ return 0; -+} -+ -+ -+static void * eap_peap_init(struct eap_sm *sm) -+{ -+ struct eap_peap_data *data; -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ sm->peap_done = FALSE; -+ data->peap_version = EAP_PEAP_VERSION; -+ data->force_peap_version = -1; -+ data->peap_outer_success = 2; -+ data->crypto_binding = OPTIONAL_BINDING; -+ -+ if (config && config->phase1 && -+ eap_peap_parse_phase1(data, config->phase1) < 0) { -+ eap_peap_deinit(sm, data); -+ return NULL; -+ } -+ -+ if (eap_peer_select_phase2_methods(config, "auth=", -+ &data->phase2_types, -+ &data->num_phase2_types) < 0) { -+ eap_peap_deinit(sm, data); -+ return NULL; -+ } -+ -+ data->phase2_type.vendor = EAP_VENDOR_IETF; -+ data->phase2_type.method = EAP_TYPE_NONE; -+ -+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); -+ eap_peap_deinit(sm, data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_peap_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ if (data == NULL) -+ return; -+ if (data->phase2_priv && data->phase2_method) -+ data->phase2_method->deinit(sm, data->phase2_priv); -+ os_free(data->phase2_types); -+ eap_peer_tls_ssl_deinit(sm, &data->ssl); -+ os_free(data->key_data); -+ wpabuf_free(data->pending_phase2_req); -+ os_free(data); -+} -+ -+ -+/** -+ * eap_tlv_build_nak - Build EAP-TLV NAK message -+ * @id: EAP identifier for the header -+ * @nak_type: TLV type (EAP_TLV_*) -+ * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure -+ * -+ * This funtion builds an EAP-TLV NAK message. The caller is responsible for -+ * freeing the returned buffer. -+ */ -+static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type) -+{ -+ struct wpabuf *msg; -+ -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10, -+ EAP_CODE_RESPONSE, id); -+ if (msg == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(msg, 0x80); /* Mandatory */ -+ wpabuf_put_u8(msg, EAP_TLV_NAK_TLV); -+ wpabuf_put_be16(msg, 6); /* Length */ -+ wpabuf_put_be32(msg, 0); /* Vendor-Id */ -+ wpabuf_put_be16(msg, nak_type); /* NAK-Type */ -+ -+ return msg; -+} -+ -+ -+static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data, -+ u8 *isk, size_t isk_len) -+{ -+ u8 *key; -+ size_t key_len; -+ -+ os_memset(isk, 0, isk_len); -+ if (data->phase2_method == NULL || data->phase2_priv == NULL || -+ data->phase2_method->isKeyAvailable == NULL || -+ data->phase2_method->getKey == NULL) -+ return 0; -+ -+ if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || -+ (key = data->phase2_method->getKey(sm, data->phase2_priv, -+ &key_len)) == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material " -+ "from Phase 2"); -+ return -1; -+ } -+ -+ if (key_len > isk_len) -+ key_len = isk_len; -+ os_memcpy(isk, key, key_len); -+ os_free(key); -+ -+ return 0; -+} -+ -+ -+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) -+{ -+ u8 *tk; -+ u8 isk[32], imck[60]; -+ -+ /* -+ * Tunnel key (TK) is the first 60 octets of the key generated by -+ * phase 1 of PEAP (based on TLS). -+ */ -+ tk = data->key_data; -+ if (tk == NULL) -+ return -1; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); -+ -+ if (data->reauth && -+ tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { -+ /* Fast-connect: IPMK|CMK = TK */ -+ os_memcpy(data->ipmk, tk, 40); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", -+ data->ipmk, 40); -+ os_memcpy(data->cmk, tk + 40, 20); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK", -+ data->cmk, 20); -+ return 0; -+ } -+ -+ if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0) -+ return -1; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); -+ -+ /* -+ * IPMK Seed = "Inner Methods Compound Keys" | ISK -+ * TempKey = First 40 octets of TK -+ * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) -+ * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space -+ * in the end of the label just before ISK; is that just a typo?) -+ */ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); -+ peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys", -+ isk, sizeof(isk), imck, sizeof(imck)); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", -+ imck, sizeof(imck)); -+ -+ os_memcpy(data->ipmk, imck, 40); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); -+ os_memcpy(data->cmk, imck + 40, 20); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); -+ -+ return 0; -+} -+ -+ -+static int eap_tlv_add_cryptobinding(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ struct wpabuf *buf) -+{ -+ u8 *mac; -+ u8 eap_type = EAP_TYPE_PEAP; -+ const u8 *addr[2]; -+ size_t len[2]; -+ u16 tlv_type; -+ -+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ -+ addr[0] = wpabuf_put(buf, 0); -+ len[0] = 60; -+ addr[1] = &eap_type; -+ len[1] = 1; -+ -+ tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; -+ if (data->peap_version >= 2) -+ tlv_type |= EAP_TLV_TYPE_MANDATORY; -+ wpabuf_put_be16(buf, tlv_type); -+ wpabuf_put_be16(buf, 56); -+ -+ wpabuf_put_u8(buf, 0); /* Reserved */ -+ wpabuf_put_u8(buf, data->peap_version); /* Version */ -+ wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */ -+ wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */ -+ wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ -+ mac = wpabuf_put(buf, 20); /* Compound_MAC */ -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", -+ addr[0], len[0]); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", -+ addr[1], len[1]); -+ hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); -+ data->crypto_binding_used = 1; -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_tlv_build_result - Build EAP-TLV Result message -+ * @id: EAP identifier for the header -+ * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE) -+ * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure -+ * -+ * This funtion builds an EAP-TLV Result message. The caller is responsible for -+ * freeing the returned buffer. -+ */ -+static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ int crypto_tlv_used, -+ int id, u16 status) -+{ -+ struct wpabuf *msg; -+ size_t len; -+ -+ if (data->crypto_binding == NO_BINDING) -+ crypto_tlv_used = 0; -+ -+ len = 6; -+ if (crypto_tlv_used) -+ len += 60; /* Cryptobinding TLV */ -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len, -+ EAP_CODE_RESPONSE, id); -+ if (msg == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(msg, 0x80); /* Mandatory */ -+ wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV); -+ wpabuf_put_be16(msg, 2); /* Length */ -+ wpabuf_put_be16(msg, status); /* Status */ -+ -+ if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ -+ return msg; -+} -+ -+ -+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ const u8 *crypto_tlv, -+ size_t crypto_tlv_len) -+{ -+ u8 buf[61], mac[SHA1_MAC_LEN]; -+ const u8 *pos; -+ -+ if (eap_peap_derive_cmk(sm, data) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK"); -+ return -1; -+ } -+ -+ if (crypto_tlv_len != 4 + 56) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " -+ "length %d", (int) crypto_tlv_len); -+ return -1; -+ } -+ -+ pos = crypto_tlv; -+ pos += 4; /* TLV header */ -+ if (pos[1] != data->peap_version) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " -+ "mismatch (was %d; expected %d)", -+ pos[1], data->peap_version); -+ return -1; -+ } -+ -+ if (pos[3] != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " -+ "SubType %d", pos[3]); -+ return -1; -+ } -+ pos += 4; -+ os_memcpy(data->binding_nonce, pos, 32); -+ pos += 32; /* Nonce */ -+ -+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ -+ os_memcpy(buf, crypto_tlv, 60); -+ os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ -+ buf[60] = EAP_TYPE_PEAP; -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data", -+ buf, sizeof(buf)); -+ hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); -+ -+ if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " -+ "cryptobinding TLV"); -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC", -+ pos, SHA1_MAC_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC", -+ mac, SHA1_MAC_LEN); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_tlv_process - Process a received EAP-TLV message and generate a response -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @ret: Return values from EAP request validation and processing -+ * @req: EAP-TLV request to be processed. The caller must have validated that -+ * the buffer is large enough to contain full request (hdr->length bytes) and -+ * that the EAP type is EAP_TYPE_TLV. -+ * @resp: Buffer to return a pointer to the allocated response message. This -+ * field should be initialized to %NULL before the call. The value will be -+ * updated if a response message is generated. The caller is responsible for -+ * freeing the allocated message. -+ * @force_failure: Force negotiation to fail -+ * Returns: 0 on success, -1 on failure -+ */ -+static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *req, struct wpabuf **resp, -+ int force_failure) -+{ -+ size_t left, tlv_len; -+ const u8 *pos; -+ const u8 *result_tlv = NULL, *crypto_tlv = NULL; -+ size_t result_tlv_len = 0, crypto_tlv_len = 0; -+ int tlv_type, mandatory; -+ -+ /* Parse TLVs */ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); -+ if (pos == NULL) -+ return -1; -+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); -+ while (left >= 4) { -+ mandatory = !!(pos[0] & 0x80); -+ tlv_type = WPA_GET_BE16(pos) & 0x3fff; -+ pos += 2; -+ tlv_len = WPA_GET_BE16(pos); -+ pos += 2; -+ left -= 4; -+ if (tlv_len > left) { -+ wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " -+ "(tlv_len=%lu left=%lu)", -+ (unsigned long) tlv_len, -+ (unsigned long) left); -+ return -1; -+ } -+ switch (tlv_type) { -+ case EAP_TLV_RESULT_TLV: -+ result_tlv = pos; -+ result_tlv_len = tlv_len; -+ break; -+ case EAP_TLV_CRYPTO_BINDING_TLV: -+ crypto_tlv = pos; -+ crypto_tlv_len = tlv_len; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " -+ "%d%s", tlv_type, -+ mandatory ? " (mandatory)" : ""); -+ if (mandatory) { -+ /* NAK TLV and ignore all TLVs in this packet. -+ */ -+ *resp = eap_tlv_build_nak(eap_get_id(req), -+ tlv_type); -+ return *resp == NULL ? -1 : 0; -+ } -+ /* Ignore this TLV, but process other TLVs */ -+ break; -+ } -+ -+ pos += tlv_len; -+ left -= tlv_len; -+ } -+ if (left) { -+ wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " -+ "Request (left=%lu)", (unsigned long) left); -+ return -1; -+ } -+ -+ /* Process supported TLVs */ -+ if (crypto_tlv && data->crypto_binding != NO_BINDING) { -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", -+ crypto_tlv, crypto_tlv_len); -+ if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, -+ crypto_tlv_len + 4) < 0) { -+ if (result_tlv == NULL) -+ return -1; -+ force_failure = 1; -+ crypto_tlv = NULL; /* do not include Cryptobinding TLV -+ * in response, if the received -+ * cryptobinding was invalid. */ -+ } -+ } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); -+ return -1; -+ } -+ -+ if (result_tlv) { -+ int status, resp_status; -+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", -+ result_tlv, result_tlv_len); -+ if (result_tlv_len < 2) { -+ wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " -+ "(len=%lu)", -+ (unsigned long) result_tlv_len); -+ return -1; -+ } -+ status = WPA_GET_BE16(result_tlv); -+ if (status == EAP_TLV_RESULT_SUCCESS) { -+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " -+ "- EAP-TLV/Phase2 Completed"); -+ if (force_failure) { -+ wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" -+ " - force failed Phase 2"); -+ resp_status = EAP_TLV_RESULT_FAILURE; -+ ret->decision = DECISION_FAIL; -+ } else { -+ resp_status = EAP_TLV_RESULT_SUCCESS; -+ ret->decision = DECISION_UNCOND_SUCC; -+ } -+ } else if (status == EAP_TLV_RESULT_FAILURE) { -+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); -+ resp_status = EAP_TLV_RESULT_FAILURE; -+ ret->decision = DECISION_FAIL; -+ } else { -+ wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " -+ "Status %d", status); -+ resp_status = EAP_TLV_RESULT_FAILURE; -+ ret->decision = DECISION_FAIL; -+ } -+ ret->methodState = METHOD_DONE; -+ -+ *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, -+ eap_get_id(req), resp_status); -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) -+{ -+ struct wpabuf *e; -+ struct eap_tlv_hdr *tlv; -+ -+ if (buf == NULL) -+ return NULL; -+ -+ /* Encapsulate EAP packet in EAP-Payload TLV */ -+ wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); -+ e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); -+ if (e == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " -+ "for TLV encapsulation"); -+ wpabuf_free(buf); -+ return NULL; -+ } -+ tlv = wpabuf_put(e, sizeof(*tlv)); -+ tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | -+ EAP_TLV_EAP_PAYLOAD_TLV); -+ tlv->length = host_to_be16(wpabuf_len(buf)); -+ wpabuf_put_buf(e, buf); -+ wpabuf_free(buf); -+ return e; -+} -+ -+ -+static int eap_peap_phase2_request(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ struct eap_method_ret *ret, -+ struct wpabuf *req, -+ struct wpabuf **resp) -+{ -+ struct eap_hdr *hdr = wpabuf_mhead(req); -+ size_t len = be_to_host16(hdr->length); -+ u8 *pos; -+ struct eap_method_ret iret; -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ if (len <= sizeof(struct eap_hdr)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: too short " -+ "Phase 2 request (len=%lu)", (unsigned long) len); -+ return -1; -+ } -+ pos = (u8 *) (hdr + 1); -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos); -+ switch (*pos) { -+ case EAP_TYPE_IDENTITY: -+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); -+ break; -+ case EAP_TYPE_TLV: -+ os_memset(&iret, 0, sizeof(iret)); -+ if (eap_tlv_process(sm, data, &iret, req, resp, -+ data->phase2_eap_started && -+ !data->phase2_eap_success)) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return -1; -+ } -+ if (iret.methodState == METHOD_DONE || -+ iret.methodState == METHOD_MAY_CONT) { -+ ret->methodState = iret.methodState; -+ ret->decision = iret.decision; -+ data->phase2_success = 1; -+ } -+ break; -+ case EAP_TYPE_EXPANDED: -+#ifdef EAP_TNC -+ if (data->soh) { -+ const u8 *epos; -+ size_t eleft; -+ -+ epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, -+ req, &eleft); -+ if (epos) { -+ struct wpabuf *buf; -+ wpa_printf(MSG_DEBUG, -+ "EAP-PEAP: SoH EAP Extensions"); -+ buf = tncc_process_soh_request(data->soh, -+ epos, eleft); -+ if (buf) { -+ *resp = eap_msg_alloc( -+ EAP_VENDOR_MICROSOFT, 0x21, -+ wpabuf_len(buf), -+ EAP_CODE_RESPONSE, -+ hdr->identifier); -+ if (*resp == NULL) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return -1; -+ } -+ wpabuf_put_buf(*resp, buf); -+ wpabuf_free(buf); -+ break; -+ } -+ } -+ } -+#endif /* EAP_TNC */ -+ /* fall through */ -+ default: -+ if (data->phase2_type.vendor == EAP_VENDOR_IETF && -+ data->phase2_type.method == EAP_TYPE_NONE) { -+ size_t i; -+ for (i = 0; i < data->num_phase2_types; i++) { -+ if (data->phase2_types[i].vendor != -+ EAP_VENDOR_IETF || -+ data->phase2_types[i].method != *pos) -+ continue; -+ -+ data->phase2_type.vendor = -+ data->phase2_types[i].vendor; -+ data->phase2_type.method = -+ data->phase2_types[i].method; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected " -+ "Phase 2 EAP vendor %d method %d", -+ data->phase2_type.vendor, -+ data->phase2_type.method); -+ break; -+ } -+ } -+ if (*pos != data->phase2_type.method || -+ *pos == EAP_TYPE_NONE) { -+ if (eap_peer_tls_phase2_nak(data->phase2_types, -+ data->num_phase2_types, -+ hdr, resp)) -+ return -1; -+ return 0; -+ } -+ -+ if (data->phase2_priv == NULL) { -+ data->phase2_method = eap_peer_get_eap_method( -+ data->phase2_type.vendor, -+ data->phase2_type.method); -+ if (data->phase2_method) { -+ sm->init_phase2 = 1; -+ data->phase2_priv = -+ data->phase2_method->init(sm); -+ sm->init_phase2 = 0; -+ } -+ } -+ if (data->phase2_priv == NULL || data->phase2_method == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize " -+ "Phase 2 EAP method %d", *pos); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return -1; -+ } -+ data->phase2_eap_started = 1; -+ os_memset(&iret, 0, sizeof(iret)); -+ *resp = data->phase2_method->process(sm, data->phase2_priv, -+ &iret, req); -+ if ((iret.methodState == METHOD_DONE || -+ iret.methodState == METHOD_MAY_CONT) && -+ (iret.decision == DECISION_UNCOND_SUCC || -+ iret.decision == DECISION_COND_SUCC)) { -+ data->phase2_eap_success = 1; -+ data->phase2_success = 1; -+ } -+ break; -+ } -+ -+ if (*resp == NULL && -+ (config->pending_req_identity || config->pending_req_password || -+ config->pending_req_otp || config->pending_req_new_password)) { -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data, -+ struct eap_method_ret *ret, -+ const struct eap_hdr *req, -+ const struct wpabuf *in_data, -+ struct wpabuf **out_data) -+{ -+ struct wpabuf *in_decrypted = NULL; -+ int res, skip_change = 0; -+ struct eap_hdr *hdr, *rhdr; -+ struct wpabuf *resp = NULL; -+ size_t len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" -+ " Phase 2", (unsigned long) wpabuf_len(in_data)); -+ -+ if (data->pending_phase2_req) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - " -+ "skip decryption and use old data"); -+ /* Clear TLS reassembly state. */ -+ eap_peer_tls_reset_input(&data->ssl); -+ in_decrypted = data->pending_phase2_req; -+ data->pending_phase2_req = NULL; -+ skip_change = 1; -+ goto continue_req; -+ } -+ -+ if (wpabuf_len(in_data) == 0 && sm->workaround && -+ data->phase2_success) { -+ /* -+ * Cisco ACS seems to be using TLS ACK to terminate -+ * EAP-PEAPv0/GTC. Try to reply with TLS ACK. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but " -+ "expected data - acknowledge with TLS ACK since " -+ "Phase 2 has been completed"); -+ ret->decision = DECISION_COND_SUCC; -+ ret->methodState = METHOD_DONE; -+ return 1; -+ } else if (wpabuf_len(in_data) == 0) { -+ /* Received TLS ACK - requesting more fragments */ -+ return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, -+ data->peap_version, -+ req->identifier, NULL, out_data); -+ } -+ -+ res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); -+ if (res) -+ return res; -+ -+continue_req: -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", -+ in_decrypted); -+ -+ hdr = wpabuf_mhead(in_decrypted); -+ if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST && -+ be_to_host16(hdr->length) == 5 && -+ eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) { -+ /* At least FreeRADIUS seems to send full EAP header with -+ * EAP Request Identity */ -+ skip_change = 1; -+ } -+ if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST && -+ eap_get_type(in_decrypted) == EAP_TYPE_TLV) { -+ skip_change = 1; -+ } -+ -+ if (data->peap_version == 0 && !skip_change) { -+ struct eap_hdr *nhdr; -+ struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) + -+ wpabuf_len(in_decrypted)); -+ if (nmsg == NULL) { -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ nhdr = wpabuf_put(nmsg, sizeof(*nhdr)); -+ wpabuf_put_buf(nmsg, in_decrypted); -+ nhdr->code = req->code; -+ nhdr->identifier = req->identifier; -+ nhdr->length = host_to_be16(sizeof(struct eap_hdr) + -+ wpabuf_len(in_decrypted)); -+ -+ wpabuf_free(in_decrypted); -+ in_decrypted = nmsg; -+ } -+ -+ if (data->peap_version >= 2) { -+ struct eap_tlv_hdr *tlv; -+ struct wpabuf *nmsg; -+ -+ if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " -+ "EAP TLV"); -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ tlv = wpabuf_mhead(in_decrypted); -+ if ((be_to_host16(tlv->tlv_type) & 0x3fff) != -+ EAP_TLV_EAP_PAYLOAD_TLV) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ if (sizeof(*tlv) + be_to_host16(tlv->length) > -+ wpabuf_len(in_decrypted)) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " -+ "length"); -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ hdr = (struct eap_hdr *) (tlv + 1); -+ if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " -+ "EAP packet in EAP TLV"); -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ -+ nmsg = wpabuf_alloc(be_to_host16(hdr->length)); -+ if (nmsg == NULL) { -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ -+ wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); -+ wpabuf_free(in_decrypted); -+ in_decrypted = nmsg; -+ } -+ -+ hdr = wpabuf_mhead(in_decrypted); -+ if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " -+ "EAP frame (len=%lu)", -+ (unsigned long) wpabuf_len(in_decrypted)); -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ len = be_to_host16(hdr->length); -+ if (len > wpabuf_len(in_decrypted)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " -+ "Phase 2 EAP frame (len=%lu hdr->length=%lu)", -+ (unsigned long) wpabuf_len(in_decrypted), -+ (unsigned long) len); -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ if (len < wpabuf_len(in_decrypted)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has " -+ "shorter length than full decrypted data " -+ "(%lu < %lu)", -+ (unsigned long) len, -+ (unsigned long) wpabuf_len(in_decrypted)); -+ } -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " -+ "identifier=%d length=%lu", hdr->code, hdr->identifier, -+ (unsigned long) len); -+ switch (hdr->code) { -+ case EAP_CODE_REQUEST: -+ if (eap_peap_phase2_request(sm, data, ret, in_decrypted, -+ &resp)) { -+ wpabuf_free(in_decrypted); -+ wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request " -+ "processing failed"); -+ return 0; -+ } -+ break; -+ case EAP_CODE_SUCCESS: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); -+ if (data->peap_version == 1) { -+ /* EAP-Success within TLS tunnel is used to indicate -+ * shutdown of the TLS channel. The authentication has -+ * been completed. */ -+ if (data->phase2_eap_started && -+ !data->phase2_eap_success) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " -+ "Success used to indicate success, " -+ "but Phase 2 EAP was not yet " -+ "completed successfully"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ wpabuf_free(in_decrypted); -+ return 0; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - " -+ "EAP-Success within TLS tunnel - " -+ "authentication completed"); -+ ret->decision = DECISION_UNCOND_SUCC; -+ ret->methodState = METHOD_DONE; -+ data->phase2_success = 1; -+ if (data->peap_outer_success == 2) { -+ wpabuf_free(in_decrypted); -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK " -+ "to finish authentication"); -+ return 1; -+ } else if (data->peap_outer_success == 1) { -+ /* Reply with EAP-Success within the TLS -+ * channel to complete the authentication. */ -+ resp = wpabuf_alloc(sizeof(struct eap_hdr)); -+ if (resp) { -+ rhdr = wpabuf_put(resp, sizeof(*rhdr)); -+ rhdr->code = EAP_CODE_SUCCESS; -+ rhdr->identifier = hdr->identifier; -+ rhdr->length = -+ host_to_be16(sizeof(*rhdr)); -+ } -+ } else { -+ /* No EAP-Success expected for Phase 1 (outer, -+ * unencrypted auth), so force EAP state -+ * machine to SUCCESS state. */ -+ sm->peap_done = TRUE; -+ } -+ } else { -+ /* FIX: ? */ -+ } -+ break; -+ case EAP_CODE_FAILURE: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); -+ ret->decision = DECISION_FAIL; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->allowNotifications = FALSE; -+ /* Reply with EAP-Failure within the TLS channel to complete -+ * failure reporting. */ -+ resp = wpabuf_alloc(sizeof(struct eap_hdr)); -+ if (resp) { -+ rhdr = wpabuf_put(resp, sizeof(*rhdr)); -+ rhdr->code = EAP_CODE_FAILURE; -+ rhdr->identifier = hdr->identifier; -+ rhdr->length = host_to_be16(sizeof(*rhdr)); -+ } -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " -+ "Phase 2 EAP header", hdr->code); -+ break; -+ } -+ -+ wpabuf_free(in_decrypted); -+ -+ if (resp) { -+ int skip_change2 = 0; -+ struct wpabuf *rmsg, buf; -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, -+ "EAP-PEAP: Encrypting Phase 2 data", resp); -+ /* PEAP version changes */ -+ if (data->peap_version >= 2) { -+ resp = eap_peapv2_tlv_eap_payload(resp); -+ if (resp == NULL) -+ return -1; -+ } -+ if (wpabuf_len(resp) >= 5 && -+ wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && -+ eap_get_type(resp) == EAP_TYPE_TLV) -+ skip_change2 = 1; -+ rmsg = resp; -+ if (data->peap_version == 0 && !skip_change2) { -+ wpabuf_set(&buf, wpabuf_head_u8(resp) + -+ sizeof(struct eap_hdr), -+ wpabuf_len(resp) - sizeof(struct eap_hdr)); -+ rmsg = &buf; -+ } -+ -+ if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, -+ data->peap_version, req->identifier, -+ rmsg, out_data)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt " -+ "a Phase 2 frame"); -+ } -+ wpabuf_free(resp); -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ const struct eap_hdr *req; -+ size_t left; -+ int res; -+ u8 flags, id; -+ struct wpabuf *resp; -+ const u8 *pos; -+ struct eap_peap_data *data = priv; -+ -+ pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret, -+ reqData, &left, &flags); -+ if (pos == NULL) -+ return NULL; -+ req = wpabuf_head(reqData); -+ id = req->identifier; -+ -+ if (flags & EAP_TLS_FLAGS_START) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own " -+ "ver=%d)", flags & EAP_TLS_VERSION_MASK, -+ data->peap_version); -+ if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version) -+ data->peap_version = flags & EAP_TLS_VERSION_MASK; -+ if (data->force_peap_version >= 0 && -+ data->force_peap_version != data->peap_version) { -+ wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select " -+ "forced PEAP version %d", -+ data->force_peap_version); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = FALSE; -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d", -+ data->peap_version); -+ left = 0; /* make sure that this frame is empty, even though it -+ * should always be, anyway */ -+ } -+ -+ resp = NULL; -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && -+ !data->resuming) { -+ struct wpabuf msg; -+ wpabuf_set(&msg, pos, left); -+ res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp); -+ } else { -+ res = eap_peer_tls_process_helper(sm, &data->ssl, -+ EAP_TYPE_PEAP, -+ data->peap_version, id, pos, -+ left, &resp); -+ -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { -+ char *label; -+ wpa_printf(MSG_DEBUG, -+ "EAP-PEAP: TLS done, proceed to Phase 2"); -+ os_free(data->key_data); -+ /* draft-josefsson-ppext-eap-tls-eap-05.txt -+ * specifies that PEAPv1 would use "client PEAP -+ * encryption" as the label. However, most existing -+ * PEAPv1 implementations seem to be using the old -+ * label, "client EAP encryption", instead. Use the old -+ * label by default, but allow it to be configured with -+ * phase1 parameter peaplabel=1. */ -+ if (data->peap_version > 1 || data->force_new_label) -+ label = "client PEAP encryption"; -+ else -+ label = "client EAP encryption"; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in " -+ "key derivation", label); -+ data->key_data = -+ eap_peer_tls_derive_key(sm, &data->ssl, label, -+ EAP_TLS_KEY_LEN); -+ if (data->key_data) { -+ wpa_hexdump_key(MSG_DEBUG, -+ "EAP-PEAP: Derived key", -+ data->key_data, -+ EAP_TLS_KEY_LEN); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to " -+ "derive key"); -+ } -+ -+ if (sm->workaround && data->resuming) { -+ /* -+ * At least few RADIUS servers (Aegis v1.1.6; -+ * but not v1.1.4; and Cisco ACS) seem to be -+ * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco -+ * ACS) session resumption with outer -+ * EAP-Success. This does not seem to follow -+ * draft-josefsson-pppext-eap-tls-eap-05.txt -+ * section 4.2, so only allow this if EAP -+ * workarounds are enabled. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - " -+ "allow outer EAP-Success to " -+ "terminate PEAP resumption"); -+ ret->decision = DECISION_COND_SUCC; -+ data->phase2_success = 1; -+ } -+ -+ data->resuming = 0; -+ } -+ -+ if (res == 2) { -+ struct wpabuf msg; -+ /* -+ * Application data included in the handshake message. -+ */ -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = resp; -+ resp = NULL; -+ wpabuf_set(&msg, pos, left); -+ res = eap_peap_decrypt(sm, data, ret, req, &msg, -+ &resp); -+ } -+ } -+ -+ if (ret->methodState == METHOD_DONE) { -+ ret->allowNotifications = FALSE; -+ } -+ -+ if (res == 1) { -+ wpabuf_free(resp); -+ return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP, -+ data->peap_version); -+ } -+ -+ return resp; -+} -+ -+ -+static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && -+ data->phase2_success; -+} -+ -+ -+static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = NULL; -+ data->crypto_binding_used = 0; -+} -+ -+ -+static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ os_free(data->key_data); -+ data->key_data = NULL; -+ if (eap_peer_tls_reauth_init(sm, &data->ssl)) { -+ os_free(data); -+ return NULL; -+ } -+ if (data->phase2_priv && data->phase2_method && -+ data->phase2_method->init_for_reauth) -+ data->phase2_method->init_for_reauth(sm, data->phase2_priv); -+ data->phase2_success = 0; -+ data->phase2_eap_success = 0; -+ data->phase2_eap_started = 0; -+ data->resuming = 1; -+ data->reauth = 1; -+ sm->peap_done = FALSE; -+ return priv; -+} -+ -+ -+static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf, -+ size_t buflen, int verbose) -+{ -+ struct eap_peap_data *data = priv; -+ int len, ret; -+ -+ len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); -+ if (data->phase2_method) { -+ ret = os_snprintf(buf + len, buflen - len, -+ "EAP-PEAPv%d Phase2 method=%s\n", -+ data->peap_version, -+ data->phase2_method->name); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ } -+ return len; -+} -+ -+ -+static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ return data->key_data != NULL && data->phase2_success; -+} -+ -+ -+static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_peap_data *data = priv; -+ u8 *key; -+ -+ if (data->key_data == NULL || !data->phase2_success) -+ return NULL; -+ -+ key = os_malloc(EAP_TLS_KEY_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_TLS_KEY_LEN; -+ -+ if (data->crypto_binding_used) { -+ u8 csk[128]; -+ /* -+ * Note: It looks like Microsoft implementation requires null -+ * termination for this label while the one used for deriving -+ * IPMK|CMK did not use null termination. -+ */ -+ peap_prfplus(data->peap_version, data->ipmk, 40, -+ "Session Key Generating Function", -+ (u8 *) "\00", 1, csk, sizeof(csk)); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); -+ os_memcpy(key, csk, EAP_TLS_KEY_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", -+ key, EAP_TLS_KEY_LEN); -+ } else -+ os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); -+ -+ return key; -+} -+ -+ -+int eap_peer_peap_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_peap_init; -+ eap->deinit = eap_peap_deinit; -+ eap->process = eap_peap_process; -+ eap->isKeyAvailable = eap_peap_isKeyAvailable; -+ eap->getKey = eap_peap_getKey; -+ eap->get_status = eap_peap_get_status; -+ eap->has_reauth_data = eap_peap_has_reauth_data; -+ eap->deinit_for_reauth = eap_peap_deinit_for_reauth; -+ eap->init_for_reauth = eap_peap_init_for_reauth; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_psk.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_psk.c -new file mode 100644 -index 0000000000000..592ef13003a44 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_psk.c -@@ -0,0 +1,483 @@ -+/* -+ * EAP peer method: EAP-PSK (RFC 4764) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * Note: EAP-PSK is an EAP authentication method and as such, completely -+ * different from WPA-PSK. This file is not needed for WPA-PSK functionality. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/random.h" -+#include "eap_common/eap_psk_common.h" -+#include "eap_i.h" -+ -+ -+struct eap_psk_data { -+ enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state; -+ u8 rand_p[EAP_PSK_RAND_LEN]; -+ u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; -+ u8 *id_s, *id_p; -+ size_t id_s_len, id_p_len; -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+}; -+ -+ -+static void * eap_psk_init(struct eap_sm *sm) -+{ -+ struct eap_psk_data *data; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ password = eap_get_config_password(sm, &password_len); -+ if (!password || password_len != 16) { -+ wpa_printf(MSG_INFO, "EAP-PSK: 16-octet pre-shared key not " -+ "configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ if (eap_psk_key_setup(password, data->ak, data->kdk)) { -+ os_free(data); -+ return NULL; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); -+ data->state = PSK_INIT; -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity) { -+ data->id_p = os_malloc(identity_len); -+ if (data->id_p) -+ os_memcpy(data->id_p, identity, identity_len); -+ data->id_p_len = identity_len; -+ } -+ if (data->id_p == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity"); -+ os_free(data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_psk_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_psk_data *data = priv; -+ os_free(data->id_s); -+ os_free(data->id_p); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ const struct eap_psk_hdr_1 *hdr1; -+ struct eap_psk_hdr_2 *hdr2; -+ struct wpabuf *resp; -+ u8 *buf, *pos; -+ size_t buflen, len; -+ const u8 *cpos; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); -+ -+ cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); -+ hdr1 = (const struct eap_psk_hdr_1 *) cpos; -+ if (cpos == NULL || len < sizeof(*hdr1)) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message " -+ "length (%lu; expected %lu or more)", -+ (unsigned long) len, -+ (unsigned long) sizeof(*hdr1)); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); -+ if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", -+ EAP_PSK_FLAGS_GET_T(hdr1->flags)); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, -+ EAP_PSK_RAND_LEN); -+ os_free(data->id_s); -+ data->id_s_len = len - sizeof(*hdr1); -+ data->id_s = os_malloc(data->id_s_len); -+ if (data->id_s == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " -+ "ID_S (len=%lu)", (unsigned long) data->id_s_len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", -+ data->id_s, data->id_s_len); -+ -+ if (random_get_bytes(data->rand_p, EAP_PSK_RAND_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, -+ sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, -+ eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ hdr2 = wpabuf_put(resp, sizeof(*hdr2)); -+ hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ -+ os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); -+ os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); -+ wpabuf_put_data(resp, data->id_p, data->id_p_len); -+ /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ -+ buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; -+ buf = os_malloc(buflen); -+ if (buf == NULL) { -+ wpabuf_free(resp); -+ return NULL; -+ } -+ os_memcpy(buf, data->id_p, data->id_p_len); -+ pos = buf + data->id_p_len; -+ os_memcpy(pos, data->id_s, data->id_s_len); -+ pos += data->id_s_len; -+ os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); -+ pos += EAP_PSK_RAND_LEN; -+ os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); -+ if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { -+ os_free(buf); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ os_free(buf); -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, -+ EAP_PSK_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", -+ data->id_p, data->id_p_len); -+ -+ data->state = PSK_MAC_SENT; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ const struct eap_psk_hdr_3 *hdr3; -+ struct eap_psk_hdr_4 *hdr4; -+ struct wpabuf *resp; -+ u8 *buf, *rpchannel, nonce[16], *decrypted; -+ const u8 *pchannel, *tag, *msg; -+ u8 mac[EAP_PSK_MAC_LEN]; -+ size_t buflen, left, data_len, len, plen; -+ int failed = 0; -+ const u8 *pos; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, -+ reqData, &len); -+ hdr3 = (const struct eap_psk_hdr_3 *) pos; -+ if (pos == NULL || len < sizeof(*hdr3)) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " -+ "length (%lu; expected %lu or more)", -+ (unsigned long) len, -+ (unsigned long) sizeof(*hdr3)); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ left = len - sizeof(*hdr3); -+ pchannel = (const u8 *) (hdr3 + 1); -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); -+ if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", -+ EAP_PSK_FLAGS_GET_T(hdr3->flags)); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, -+ EAP_PSK_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); -+ -+ if (left < 4 + 16 + 1) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " -+ "third message (len=%lu, expected 21)", -+ (unsigned long) left); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ -+ buflen = data->id_s_len + EAP_PSK_RAND_LEN; -+ buf = os_malloc(buflen); -+ if (buf == NULL) -+ return NULL; -+ os_memcpy(buf, data->id_s, data->id_s_len); -+ os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); -+ if (omac1_aes_128(data->ak, buf, buflen, mac)) { -+ os_free(buf); -+ return NULL; -+ } -+ os_free(buf); -+ if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { -+ wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " -+ "message"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); -+ -+ if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, -+ data->msk, data->emsk)) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); -+ -+ os_memset(nonce, 0, 12); -+ os_memcpy(nonce + 12, pchannel, 4); -+ pchannel += 4; -+ left -= 4; -+ -+ tag = pchannel; -+ pchannel += 16; -+ left -= 16; -+ -+ msg = pchannel; -+ -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", -+ nonce, sizeof(nonce)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", -+ wpabuf_head(reqData), 5); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); -+ -+ decrypted = os_malloc(left); -+ if (decrypted == NULL) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return NULL; -+ } -+ os_memcpy(decrypted, msg, left); -+ -+ if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), -+ wpabuf_head(reqData), -+ sizeof(struct eap_hdr) + 1 + -+ sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, -+ left, tag)) { -+ wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); -+ os_free(decrypted); -+ return NULL; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", -+ decrypted, left); -+ -+ /* Verify R flag */ -+ switch (decrypted[0] >> 6) { -+ case EAP_PSK_R_FLAG_CONT: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); -+ failed = 1; -+ break; -+ case EAP_PSK_R_FLAG_DONE_SUCCESS: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); -+ break; -+ case EAP_PSK_R_FLAG_DONE_FAILURE: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); -+ wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " -+ "authentication"); -+ failed = 1; -+ break; -+ } -+ -+ data_len = 1; -+ if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) -+ data_len++; -+ plen = sizeof(*hdr4) + 4 + 16 + data_len; -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) { -+ os_free(decrypted); -+ return NULL; -+ } -+ hdr4 = wpabuf_put(resp, sizeof(*hdr4)); -+ hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ -+ os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); -+ rpchannel = wpabuf_put(resp, 4 + 16 + data_len); -+ -+ /* nonce++ */ -+ inc_byte_array(nonce, sizeof(nonce)); -+ os_memcpy(rpchannel, nonce + 12, 4); -+ -+ if (decrypted[0] & EAP_PSK_E_FLAG) { -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); -+ failed = 1; -+ rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | -+ EAP_PSK_E_FLAG; -+ if (left > 1) { -+ /* Add empty EXT_Payload with same EXT_Type */ -+ rpchannel[4 + 16 + 1] = decrypted[1]; -+ } -+ } else if (failed) -+ rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; -+ else -+ rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", -+ rpchannel + 4 + 16, data_len); -+ if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), -+ wpabuf_head(resp), -+ sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), -+ rpchannel + 4 + 16, data_len, rpchannel + 4)) { -+ os_free(decrypted); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", -+ rpchannel, 4 + 16 + data_len); -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", -+ failed ? "un" : ""); -+ data->state = PSK_DONE; -+ ret->methodState = METHOD_DONE; -+ ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; -+ -+ os_free(decrypted); -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_psk_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_psk_data *data = priv; -+ const u8 *pos; -+ struct wpabuf *resp = NULL; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); -+ if (pos == NULL) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = TRUE; -+ -+ switch (data->state) { -+ case PSK_INIT: -+ resp = eap_psk_process_1(data, ret, reqData); -+ break; -+ case PSK_MAC_SENT: -+ resp = eap_psk_process_3(data, ret, reqData); -+ break; -+ case PSK_DONE: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " -+ "unexpected message"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (ret->methodState == METHOD_DONE) { -+ ret->allowNotifications = FALSE; -+ } -+ -+ return resp; -+} -+ -+ -+static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_psk_data *data = priv; -+ return data->state == PSK_DONE; -+} -+ -+ -+static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_psk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != PSK_DONE) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_MSK_LEN; -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ -+ return key; -+} -+ -+ -+static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_psk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != PSK_DONE) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_EMSK_LEN; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ -+ return key; -+} -+ -+ -+int eap_peer_psk_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_psk_init; -+ eap->deinit = eap_psk_deinit; -+ eap->process = eap_psk_process; -+ eap->isKeyAvailable = eap_psk_isKeyAvailable; -+ eap->getKey = eap_psk_getKey; -+ eap->get_emsk = eap_psk_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pwd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pwd.c -new file mode 100644 -index 0000000000000..e4705b7e4e74b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_pwd.c -@@ -0,0 +1,744 @@ -+/* -+ * EAP peer method: EAP-pwd (RFC 5931) -+ * Copyright (c) 2010, Dan Harkins -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the BSD license. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_peer/eap_i.h" -+#include "eap_common/eap_pwd_common.h" -+ -+ -+struct eap_pwd_data { -+ enum { -+ PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE -+ } state; -+ u8 *id_peer; -+ size_t id_peer_len; -+ u8 *id_server; -+ size_t id_server_len; -+ u8 *password; -+ size_t password_len; -+ u16 group_num; -+ EAP_PWD_group *grp; -+ -+ BIGNUM *k; -+ BIGNUM *private_value; -+ BIGNUM *server_scalar; -+ BIGNUM *my_scalar; -+ EC_POINT *my_element; -+ EC_POINT *server_element; -+ -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ -+ BN_CTX *bnctx; -+}; -+ -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+static const char * eap_pwd_state_txt(int state) -+{ -+ switch (state) { -+ case PWD_ID_Req: -+ return "PWD-ID-Req"; -+ case PWD_Commit_Req: -+ return "PWD-Commit-Req"; -+ case PWD_Confirm_Req: -+ return "PWD-Confirm-Req"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "PWD-UNK"; -+ } -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+static void eap_pwd_state(struct eap_pwd_data *data, int state) -+{ -+ wpa_printf(MSG_INFO, "EAP-PWD: %s -> %s", -+ eap_pwd_state_txt(data->state), eap_pwd_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_pwd_init(struct eap_sm *sm) -+{ -+ struct eap_pwd_data *data; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ password = eap_get_config_password(sm, &password_len); -+ if (password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: No password configured!"); -+ return NULL; -+ } -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: No identity configured!"); -+ return NULL; -+ } -+ -+ if ((data = os_zalloc(sizeof(*data))) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: memory allocation data fail"); -+ return NULL; -+ } -+ -+ if ((data->bnctx = BN_CTX_new()) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); -+ os_free(data); -+ return NULL; -+ } -+ -+ if ((data->id_peer = os_malloc(identity_len)) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); -+ BN_CTX_free(data->bnctx); -+ os_free(data); -+ return NULL; -+ } -+ -+ os_memcpy(data->id_peer, identity, identity_len); -+ data->id_peer_len = identity_len; -+ -+ if ((data->password = os_malloc(password_len)) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); -+ BN_CTX_free(data->bnctx); -+ os_free(data->id_peer); -+ os_free(data); -+ return NULL; -+ } -+ os_memcpy(data->password, password, password_len); -+ data->password_len = password_len; -+ -+ data->state = PWD_ID_Req; -+ -+ return data; -+} -+ -+ -+static void eap_pwd_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pwd_data *data = priv; -+ -+ BN_free(data->private_value); -+ BN_free(data->server_scalar); -+ BN_free(data->my_scalar); -+ BN_free(data->k); -+ BN_CTX_free(data->bnctx); -+ EC_POINT_free(data->my_element); -+ EC_POINT_free(data->server_element); -+ os_free(data->id_peer); -+ os_free(data->id_server); -+ os_free(data->password); -+ if (data->grp) { -+ EC_GROUP_free(data->grp->group); -+ EC_POINT_free(data->grp->pwe); -+ BN_free(data->grp->order); -+ BN_free(data->grp->prime); -+ os_free(data->grp); -+ } -+ os_free(data); -+} -+ -+ -+static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pwd_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ -+ return key; -+} -+ -+ -+static struct wpabuf * -+eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, size_t payload_len) -+{ -+ struct eap_pwd_id *id; -+ struct wpabuf *resp; -+ -+ if (data->state != PWD_ID_Req) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (payload_len < sizeof(struct eap_pwd_id)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ id = (struct eap_pwd_id *) payload; -+ data->group_num = be_to_host16(id->group_num); -+ if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || -+ (id->prf != EAP_PWD_DEFAULT_PRF)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-PWD (peer): server said group %d", -+ data->group_num); -+ -+ data->id_server = os_malloc(payload_len - sizeof(struct eap_pwd_id)); -+ if (data->id_server == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); -+ return NULL; -+ } -+ data->id_server_len = payload_len - sizeof(struct eap_pwd_id); -+ os_memcpy(data->id_server, id->identity, data->id_server_len); -+ wpa_hexdump_ascii(MSG_INFO, "EAP-PWD (peer): server sent id of", -+ data->id_server, data->id_server_len); -+ -+ if ((data->grp = (EAP_PWD_group *) os_malloc(sizeof(EAP_PWD_group))) == -+ NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " -+ "group"); -+ return NULL; -+ } -+ -+ /* compute PWE */ -+ if (compute_password_element(data->grp, data->group_num, -+ data->password, data->password_len, -+ data->id_server, data->id_server_len, -+ data->id_peer, data->id_peer_len, -+ id->token)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE"); -+ return NULL; -+ } -+ -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): computed %d bit PWE...", -+ BN_num_bits(data->grp->prime)); -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, -+ 1 + sizeof(struct eap_pwd_id) + data->id_peer_len, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, EAP_PWD_OPCODE_ID_EXCH); -+ wpabuf_put_be16(resp, data->group_num); -+ wpabuf_put_u8(resp, EAP_PWD_DEFAULT_RAND_FUNC); -+ wpabuf_put_u8(resp, EAP_PWD_DEFAULT_PRF); -+ wpabuf_put_data(resp, id->token, sizeof(id->token)); -+ wpabuf_put_u8(resp, EAP_PWD_PREP_NONE); -+ wpabuf_put_data(resp, data->id_peer, data->id_peer_len); -+ -+ eap_pwd_state(data, PWD_Commit_Req); -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * -+eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, size_t payload_len) -+{ -+ struct wpabuf *resp = NULL; -+ EC_POINT *K = NULL, *point = NULL; -+ BIGNUM *mask = NULL, *x = NULL, *y = NULL, *cofactor = NULL; -+ u16 offset; -+ u8 *ptr, *scalar = NULL, *element = NULL; -+ -+ if (((data->private_value = BN_new()) == NULL) || -+ ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || -+ ((cofactor = BN_new()) == NULL) || -+ ((data->my_scalar = BN_new()) == NULL) || -+ ((mask = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): scalar allocation fail"); -+ goto fin; -+ } -+ -+ if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-pwd (peer): unable to get cofactor " -+ "for curve"); -+ goto fin; -+ } -+ -+ BN_rand_range(data->private_value, data->grp->order); -+ BN_rand_range(mask, data->grp->order); -+ BN_add(data->my_scalar, data->private_value, mask); -+ BN_mod(data->my_scalar, data->my_scalar, data->grp->order, -+ data->bnctx); -+ -+ if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, -+ data->grp->pwe, mask, data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): element allocation " -+ "fail"); -+ eap_pwd_state(data, FAILURE); -+ goto fin; -+ } -+ -+ if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) -+ { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail"); -+ goto fin; -+ } -+ BN_free(mask); -+ -+ if (((x = BN_new()) == NULL) || -+ ((y = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): point allocation fail"); -+ goto fin; -+ } -+ -+ /* process the request */ -+ if (((data->server_scalar = BN_new()) == NULL) || -+ ((data->k = BN_new()) == NULL) || -+ ((K = EC_POINT_new(data->grp->group)) == NULL) || -+ ((point = EC_POINT_new(data->grp->group)) == NULL) || -+ ((data->server_element = EC_POINT_new(data->grp->group)) == NULL)) -+ { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): peer data allocation " -+ "fail"); -+ goto fin; -+ } -+ -+ /* element, x then y, followed by scalar */ -+ ptr = (u8 *) payload; -+ BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); -+ ptr += BN_num_bytes(data->grp->prime); -+ BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); -+ ptr += BN_num_bytes(data->grp->prime); -+ BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->server_scalar); -+ if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, -+ data->server_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): setting peer element " -+ "fail"); -+ goto fin; -+ } -+ -+ /* check to ensure server's element is not in a small sub-group */ -+ if (BN_cmp(cofactor, BN_value_one())) { -+ if (!EC_POINT_mul(data->grp->group, point, NULL, -+ data->server_element, cofactor, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " -+ "server element by order!\n"); -+ goto fin; -+ } -+ if (EC_POINT_is_at_infinity(data->grp->group, point)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): server element " -+ "is at infinity!\n"); -+ goto fin; -+ } -+ } -+ -+ /* compute the shared key, k */ -+ if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, -+ data->server_scalar, data->bnctx)) || -+ (!EC_POINT_add(data->grp->group, K, K, data->server_element, -+ data->bnctx)) || -+ (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, -+ data->bnctx))) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): computing shared key " -+ "fail"); -+ goto fin; -+ } -+ -+ /* ensure that the shared key isn't in a small sub-group */ -+ if (BN_cmp(cofactor, BN_value_one())) { -+ if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, -+ NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): cannot multiply " -+ "shared key point by order"); -+ goto fin; -+ } -+ } -+ -+ /* -+ * This check is strictly speaking just for the case above where -+ * co-factor > 1 but it was suggested that even though this is probably -+ * never going to happen it is a simple and safe check "just to be -+ * sure" so let's be safe. -+ */ -+ if (EC_POINT_is_at_infinity(data->grp->group, K)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): shared key point is at " -+ "infinity!\n"); -+ goto fin; -+ } -+ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, -+ NULL, data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to extract " -+ "shared secret from point"); -+ goto fin; -+ } -+ -+ /* now do the response */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->my_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); -+ goto fin; -+ } -+ -+ if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || -+ ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == -+ NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): data allocation fail"); -+ goto fin; -+ } -+ -+ /* -+ * bignums occupy as little memory as possible so one that is -+ * sufficiently smaller than the prime or order might need pre-pending -+ * with zeros. -+ */ -+ os_memset(scalar, 0, BN_num_bytes(data->grp->order)); -+ os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); -+ offset = BN_num_bytes(data->grp->order) - -+ BN_num_bytes(data->my_scalar); -+ BN_bn2bin(data->my_scalar, scalar + offset); -+ -+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); -+ BN_bn2bin(x, element + offset); -+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); -+ BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, -+ sizeof(struct eap_pwd_hdr) + -+ BN_num_bytes(data->grp->order) + -+ (2 * BN_num_bytes(data->grp->prime)), -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ goto fin; -+ -+ wpabuf_put_u8(resp, EAP_PWD_OPCODE_COMMIT_EXCH); -+ -+ /* we send the element as (x,y) follwed by the scalar */ -+ wpabuf_put_data(resp, element, (2 * BN_num_bytes(data->grp->prime))); -+ wpabuf_put_data(resp, scalar, BN_num_bytes(data->grp->order)); -+ -+fin: -+ os_free(scalar); -+ os_free(element); -+ BN_free(x); -+ BN_free(y); -+ BN_free(cofactor); -+ EC_POINT_free(K); -+ EC_POINT_free(point); -+ if (resp == NULL) -+ eap_pwd_state(data, FAILURE); -+ else -+ eap_pwd_state(data, PWD_Confirm_Req); -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * -+eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, size_t payload_len) -+{ -+ struct wpabuf *resp = NULL; -+ BIGNUM *x = NULL, *y = NULL; -+ HMAC_CTX ctx; -+ u32 cs; -+ u16 grp; -+ u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr; -+ -+ /* -+ * first build up the ciphersuite which is group | random_function | -+ * prf -+ */ -+ grp = htons(data->group_num); -+ ptr = (u8 *) &cs; -+ os_memcpy(ptr, &grp, sizeof(u16)); -+ ptr += sizeof(u16); -+ *ptr = EAP_PWD_DEFAULT_RAND_FUNC; -+ ptr += sizeof(u8); -+ *ptr = EAP_PWD_DEFAULT_PRF; -+ -+ /* each component of the cruft will be at most as big as the prime */ -+ if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || -+ ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation " -+ "fail"); -+ goto fin; -+ } -+ -+ /* -+ * server's commit is H(k | server_element | server_scalar | -+ * peer_element | peer_scalar | ciphersuite) -+ */ -+ H_Init(&ctx); -+ -+ /* -+ * zero the memory each time because this is mod prime math and some -+ * value may start with a few zeros and the previous one did not. -+ */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->k, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* server element: x, y */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->server_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* server scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->server_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* my element: x, y */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->my_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* my scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->my_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* the ciphersuite */ -+ H_Update(&ctx, (u8 *) &cs, sizeof(u32)); -+ -+ /* random function fin */ -+ H_Final(&ctx, conf); -+ -+ ptr = (u8 *) payload; -+ if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify"); -+ goto fin; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-pwd (peer): confirm verified"); -+ -+ /* -+ * compute confirm: -+ * H(k | peer_element | peer_scalar | server_element | server_scalar | -+ * ciphersuite) -+ */ -+ H_Init(&ctx); -+ -+ /* k */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->k, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* my element */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->my_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* my scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->my_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* server element: x, y */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->server_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* server scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->server_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* the ciphersuite */ -+ H_Update(&ctx, (u8 *) &cs, sizeof(u32)); -+ -+ /* all done */ -+ H_Final(&ctx, conf); -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, -+ sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ goto fin; -+ -+ wpabuf_put_u8(resp, EAP_PWD_OPCODE_CONFIRM_EXCH); -+ wpabuf_put_data(resp, conf, SHA256_DIGEST_LENGTH); -+ -+ if (compute_keys(data->grp, data->bnctx, data->k, -+ data->my_scalar, data->server_scalar, conf, ptr, -+ &cs, data->msk, data->emsk) < 0) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute MSK | " -+ "EMSK"); -+ goto fin; -+ } -+ -+fin: -+ os_free(cruft); -+ BN_free(x); -+ BN_free(y); -+ ret->methodState = METHOD_DONE; -+ if (resp == NULL) { -+ ret->decision = DECISION_FAIL; -+ eap_pwd_state(data, FAILURE); -+ } else { -+ ret->decision = DECISION_UNCOND_SUCC; -+ eap_pwd_state(data, SUCCESS); -+ } -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * -+eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_pwd_data *data = priv; -+ struct wpabuf *resp = NULL; -+ const u8 *pos; -+ size_t len; -+ u8 exch; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, reqData, &len); -+ if ((pos == NULL) || (len < 1)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_INFO, "EAP-pwd: Received frame: opcode %d", *pos); -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = FALSE; -+ -+ exch = *pos & 0x3f; -+ switch (exch) { -+ case EAP_PWD_OPCODE_ID_EXCH: -+ resp = eap_pwd_perform_id_exchange(sm, data, ret, reqData, -+ pos + 1, len - 1); -+ break; -+ case EAP_PWD_OPCODE_COMMIT_EXCH: -+ resp = eap_pwd_perform_commit_exchange(sm, data, ret, reqData, -+ pos + 1, len - 1); -+ break; -+ case EAP_PWD_OPCODE_CONFIRM_EXCH: -+ resp = eap_pwd_perform_confirm_exchange(sm, data, ret, reqData, -+ pos + 1, len - 1); -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-pwd: Ignoring message with unknown " -+ "opcode %d", exch); -+ break; -+ } -+ -+ return resp; -+} -+ -+ -+static Boolean eap_pwd_key_available(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pwd_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pwd_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ if ((key = os_malloc(EAP_EMSK_LEN)) == NULL) -+ return NULL; -+ -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ -+ return key; -+} -+ -+ -+int eap_peer_pwd_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ EVP_add_digest(EVP_sha256()); -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_pwd_init; -+ eap->deinit = eap_pwd_deinit; -+ eap->process = eap_pwd_process; -+ eap->isKeyAvailable = eap_pwd_key_available; -+ eap->getKey = eap_pwd_getkey; -+ eap->get_emsk = eap_pwd_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sake.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sake.c -new file mode 100644 -index 0000000000000..1474b7f072359 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sake.c -@@ -0,0 +1,500 @@ -+/* -+ * EAP peer method: EAP-SAKE (RFC 4763) -+ * Copyright (c) 2006-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_peer/eap_i.h" -+#include "eap_common/eap_sake_common.h" -+ -+struct eap_sake_data { -+ enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state; -+ u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN]; -+ u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN]; -+ u8 rand_s[EAP_SAKE_RAND_LEN]; -+ u8 rand_p[EAP_SAKE_RAND_LEN]; -+ struct { -+ u8 auth[EAP_SAKE_TEK_AUTH_LEN]; -+ u8 cipher[EAP_SAKE_TEK_CIPHER_LEN]; -+ } tek; -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 session_id; -+ int session_id_set; -+ u8 *peerid; -+ size_t peerid_len; -+ u8 *serverid; -+ size_t serverid_len; -+}; -+ -+ -+static const char * eap_sake_state_txt(int state) -+{ -+ switch (state) { -+ case IDENTITY: -+ return "IDENTITY"; -+ case CHALLENGE: -+ return "CHALLENGE"; -+ case CONFIRM: -+ return "CONFIRM"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+static void eap_sake_state(struct eap_sake_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s", -+ eap_sake_state_txt(data->state), -+ eap_sake_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void eap_sake_deinit(struct eap_sm *sm, void *priv); -+ -+ -+static void * eap_sake_init(struct eap_sm *sm) -+{ -+ struct eap_sake_data *data; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ password = eap_get_config_password(sm, &password_len); -+ if (!password || password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: No key of correct length " -+ "configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = IDENTITY; -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity) { -+ data->peerid = os_malloc(identity_len); -+ if (data->peerid == NULL) { -+ eap_sake_deinit(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->peerid, identity, identity_len); -+ data->peerid_len = identity_len; -+ } -+ -+ os_memcpy(data->root_secret_a, password, EAP_SAKE_ROOT_SECRET_LEN); -+ os_memcpy(data->root_secret_b, -+ password + EAP_SAKE_ROOT_SECRET_LEN, -+ EAP_SAKE_ROOT_SECRET_LEN); -+ -+ return data; -+} -+ -+ -+static void eap_sake_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sake_data *data = priv; -+ os_free(data->serverid); -+ os_free(data->peerid); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data, -+ int id, size_t length, u8 subtype) -+{ -+ struct eap_sake_hdr *sake; -+ struct wpabuf *msg; -+ size_t plen; -+ -+ plen = length + sizeof(struct eap_sake_hdr); -+ -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen, -+ EAP_CODE_RESPONSE, id); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory " -+ "request"); -+ return NULL; -+ } -+ -+ sake = wpabuf_put(msg, sizeof(*sake)); -+ sake->version = EAP_SAKE_VERSION; -+ sake->session_id = data->session_id; -+ sake->subtype = subtype; -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_sake_process_identity(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, -+ size_t payload_len) -+{ -+ struct eap_sake_parse_attr attr; -+ struct wpabuf *resp; -+ -+ if (data->state != IDENTITY) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity"); -+ -+ if (eap_sake_parse_attributes(payload, payload_len, &attr)) -+ return NULL; -+ -+ if (!attr.perm_id_req && !attr.any_id_req) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or " -+ "AT_ANY_ID_REQ in Request/Identity"); -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity"); -+ -+ resp = eap_sake_build_msg(data, eap_get_id(reqData), -+ 2 + data->peerid_len, -+ EAP_SAKE_SUBTYPE_IDENTITY); -+ if (resp == NULL) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); -+ eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, -+ data->peerid, data->peerid_len); -+ -+ eap_sake_state(data, CHALLENGE); -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_sake_process_challenge(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, -+ size_t payload_len) -+{ -+ struct eap_sake_parse_attr attr; -+ struct wpabuf *resp; -+ u8 *rpos; -+ size_t rlen; -+ -+ if (data->state != IDENTITY && data->state != CHALLENGE) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received " -+ "in unexpected state (%d)", data->state); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ if (data->state == IDENTITY) -+ eap_sake_state(data, CHALLENGE); -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge"); -+ -+ if (eap_sake_parse_attributes(payload, payload_len, &attr)) -+ return NULL; -+ -+ if (!attr.rand_s) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not " -+ "include AT_RAND_S"); -+ return NULL; -+ } -+ -+ os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)", -+ data->rand_s, EAP_SAKE_RAND_LEN); -+ -+ if (random_get_bytes(data->rand_p, EAP_SAKE_RAND_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); -+ return NULL; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)", -+ data->rand_p, EAP_SAKE_RAND_LEN); -+ -+ os_free(data->serverid); -+ data->serverid = NULL; -+ data->serverid_len = 0; -+ if (attr.serverid) { -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID", -+ attr.serverid, attr.serverid_len); -+ data->serverid = os_malloc(attr.serverid_len); -+ if (data->serverid == NULL) -+ return NULL; -+ os_memcpy(data->serverid, attr.serverid, attr.serverid_len); -+ data->serverid_len = attr.serverid_len; -+ } -+ -+ eap_sake_derive_keys(data->root_secret_a, data->root_secret_b, -+ data->rand_s, data->rand_p, -+ (u8 *) &data->tek, data->msk, data->emsk); -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge"); -+ -+ rlen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN; -+ if (data->peerid) -+ rlen += 2 + data->peerid_len; -+ resp = eap_sake_build_msg(data, eap_get_id(reqData), rlen, -+ EAP_SAKE_SUBTYPE_CHALLENGE); -+ if (resp == NULL) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P"); -+ eap_sake_add_attr(resp, EAP_SAKE_AT_RAND_P, -+ data->rand_p, EAP_SAKE_RAND_LEN); -+ -+ if (data->peerid) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID"); -+ eap_sake_add_attr(resp, EAP_SAKE_AT_PEERID, -+ data->peerid, data->peerid_len); -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); -+ wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); -+ wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); -+ rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); -+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, -+ data->serverid, data->serverid_len, -+ data->peerid, data->peerid_len, 1, -+ wpabuf_head(resp), wpabuf_len(resp), rpos, -+ rpos)) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ -+ eap_sake_state(data, CONFIRM); -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ const u8 *payload, -+ size_t payload_len) -+{ -+ struct eap_sake_parse_attr attr; -+ u8 mic_s[EAP_SAKE_MIC_LEN]; -+ struct wpabuf *resp; -+ u8 *rpos; -+ -+ if (data->state != CONFIRM) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm"); -+ -+ if (eap_sake_parse_attributes(payload, payload_len, &attr)) -+ return NULL; -+ -+ if (!attr.mic_s) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not " -+ "include AT_MIC_S"); -+ return NULL; -+ } -+ -+ eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, -+ data->serverid, data->serverid_len, -+ data->peerid, data->peerid_len, 0, -+ wpabuf_head(reqData), wpabuf_len(reqData), -+ attr.mic_s, mic_s); -+ if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S"); -+ eap_sake_state(data, FAILURE); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = FALSE; -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending " -+ "Response/Auth-Reject"); -+ return eap_sake_build_msg(data, eap_get_id(reqData), 0, -+ EAP_SAKE_SUBTYPE_AUTH_REJECT); -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm"); -+ -+ resp = eap_sake_build_msg(data, eap_get_id(reqData), -+ 2 + EAP_SAKE_MIC_LEN, -+ EAP_SAKE_SUBTYPE_CONFIRM); -+ if (resp == NULL) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P"); -+ wpabuf_put_u8(resp, EAP_SAKE_AT_MIC_P); -+ wpabuf_put_u8(resp, 2 + EAP_SAKE_MIC_LEN); -+ rpos = wpabuf_put(resp, EAP_SAKE_MIC_LEN); -+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, -+ data->serverid, data->serverid_len, -+ data->peerid, data->peerid_len, 1, -+ wpabuf_head(resp), wpabuf_len(resp), rpos, -+ rpos)) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); -+ wpabuf_free(resp); -+ return NULL; -+ } -+ -+ eap_sake_state(data, SUCCESS); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ ret->allowNotifications = FALSE; -+ -+ return resp; -+} -+ -+ -+static struct wpabuf * eap_sake_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_sake_data *data = priv; -+ const struct eap_sake_hdr *req; -+ struct wpabuf *resp; -+ const u8 *pos, *end; -+ size_t len; -+ u8 subtype, session_id; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, reqData, &len); -+ if (pos == NULL || len < sizeof(struct eap_sake_hdr)) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ req = (const struct eap_sake_hdr *) pos; -+ end = pos + len; -+ subtype = req->subtype; -+ session_id = req->session_id; -+ pos = (const u8 *) (req + 1); -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d " -+ "session_id %d", subtype, session_id); -+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", -+ pos, end - pos); -+ -+ if (data->session_id_set && data->session_id != session_id) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)", -+ session_id, data->session_id); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ data->session_id = session_id; -+ data->session_id_set = 1; -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = TRUE; -+ -+ switch (subtype) { -+ case EAP_SAKE_SUBTYPE_IDENTITY: -+ resp = eap_sake_process_identity(sm, data, ret, reqData, -+ pos, end - pos); -+ break; -+ case EAP_SAKE_SUBTYPE_CHALLENGE: -+ resp = eap_sake_process_challenge(sm, data, ret, reqData, -+ pos, end - pos); -+ break; -+ case EAP_SAKE_SUBTYPE_CONFIRM: -+ resp = eap_sake_process_confirm(sm, data, ret, reqData, -+ pos, end - pos); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with " -+ "unknown subtype %d", subtype); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (ret->methodState == METHOD_DONE) -+ ret->allowNotifications = FALSE; -+ -+ return resp; -+} -+ -+ -+static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sake_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sake_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ -+ return key; -+} -+ -+ -+static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sake_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ -+ return key; -+} -+ -+ -+int eap_peer_sake_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_sake_init; -+ eap->deinit = eap_sake_deinit; -+ eap->process = eap_sake_process; -+ eap->isKeyAvailable = eap_sake_isKeyAvailable; -+ eap->getKey = eap_sake_getKey; -+ eap->get_emsk = eap_sake_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sim.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sim.c -new file mode 100644 -index 0000000000000..6677063a7bea9 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_sim.c -@@ -0,0 +1,1101 @@ -+/* -+ * EAP peer method: EAP-SIM (RFC 4186) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "pcsc_funcs.h" -+#include "crypto/milenage.h" -+#include "crypto/random.h" -+#include "eap_peer/eap_i.h" -+#include "eap_config.h" -+#include "eap_common/eap_sim_common.h" -+ -+ -+struct eap_sim_data { -+ u8 *ver_list; -+ size_t ver_list_len; -+ int selected_version; -+ size_t min_num_chal, num_chal; -+ -+ u8 kc[3][EAP_SIM_KC_LEN]; -+ u8 sres[3][EAP_SIM_SRES_LEN]; -+ u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN]; -+ u8 mk[EAP_SIM_MK_LEN]; -+ u8 k_aut[EAP_SIM_K_AUT_LEN]; -+ u8 k_encr[EAP_SIM_K_ENCR_LEN]; -+ u8 msk[EAP_SIM_KEYING_DATA_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 rand[3][GSM_RAND_LEN]; -+ -+ int num_id_req, num_notification; -+ u8 *pseudonym; -+ size_t pseudonym_len; -+ u8 *reauth_id; -+ size_t reauth_id_len; -+ int reauth; -+ unsigned int counter, counter_too_small; -+ u8 *last_eap_identity; -+ size_t last_eap_identity_len; -+ enum { -+ CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE -+ } state; -+ int result_ind, use_result_ind; -+}; -+ -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+static const char * eap_sim_state_txt(int state) -+{ -+ switch (state) { -+ case CONTINUE: -+ return "CONTINUE"; -+ case RESULT_SUCCESS: -+ return "RESULT_SUCCESS"; -+ case RESULT_FAILURE: -+ return "RESULT_FAILURE"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "?"; -+ } -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+static void eap_sim_state(struct eap_sim_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s", -+ eap_sim_state_txt(data->state), -+ eap_sim_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_sim_init(struct eap_sm *sm) -+{ -+ struct eap_sim_data *data; -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data " -+ "for NONCE_MT"); -+ os_free(data); -+ return NULL; -+ } -+ -+ data->min_num_chal = 2; -+ if (config && config->phase1) { -+ char *pos = os_strstr(config->phase1, "sim_min_num_chal="); -+ if (pos) { -+ data->min_num_chal = atoi(pos + 17); -+ if (data->min_num_chal < 2 || data->min_num_chal > 3) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Invalid " -+ "sim_min_num_chal configuration " -+ "(%lu, expected 2 or 3)", -+ (unsigned long) data->min_num_chal); -+ os_free(data); -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of " -+ "challenges to %lu", -+ (unsigned long) data->min_num_chal); -+ } -+ -+ data->result_ind = os_strstr(config->phase1, "result_ind=1") != -+ NULL; -+ } -+ -+ eap_sim_state(data, CONTINUE); -+ -+ return data; -+} -+ -+ -+static void eap_sim_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ if (data) { -+ os_free(data->ver_list); -+ os_free(data->pseudonym); -+ os_free(data->reauth_id); -+ os_free(data->last_eap_identity); -+ os_free(data); -+ } -+} -+ -+ -+static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data) -+{ -+ struct eap_peer_config *conf; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication algorithm"); -+ -+ conf = eap_get_config(sm); -+ if (conf == NULL) -+ return -1; -+ if (conf->pcsc) { -+ if (scard_gsm_auth(sm->scard_ctx, data->rand[0], -+ data->sres[0], data->kc[0]) || -+ scard_gsm_auth(sm->scard_ctx, data->rand[1], -+ data->sres[1], data->kc[1]) || -+ (data->num_chal > 2 && -+ scard_gsm_auth(sm->scard_ctx, data->rand[2], -+ data->sres[2], data->kc[2]))) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: GSM SIM " -+ "authentication could not be completed"); -+ return -1; -+ } -+ return 0; -+ } -+ -+#ifdef CONFIG_SIM_SIMULATOR -+ if (conf->password) { -+ u8 opc[16], k[16]; -+ const char *pos; -+ size_t i; -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Use internal GSM-Milenage " -+ "implementation for authentication"); -+ if (conf->password_len < 65) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: invalid GSM-Milenage " -+ "password"); -+ return -1; -+ } -+ pos = (const char *) conf->password; -+ if (hexstr2bin(pos, k, 16)) -+ return -1; -+ pos += 32; -+ if (*pos != ':') -+ return -1; -+ pos++; -+ -+ if (hexstr2bin(pos, opc, 16)) -+ return -1; -+ -+ for (i = 0; i < data->num_chal; i++) { -+ if (gsm_milenage(opc, k, data->rand[i], -+ data->sres[i], data->kc[i])) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: " -+ "GSM-Milenage authentication " -+ "could not be completed"); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: RAND", -+ data->rand[i], GSM_RAND_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: SRES", -+ data->sres[i], EAP_SIM_SRES_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Kc", -+ data->kc[i], EAP_SIM_KC_LEN); -+ } -+ return 0; -+ } -+#endif /* CONFIG_SIM_SIMULATOR */ -+ -+#ifdef CONFIG_SIM_HARDCODED -+ /* These hardcoded Kc and SRES values are used for testing. RAND to -+ * KC/SREC mapping is very bogus as far as real authentication is -+ * concerned, but it is quite useful for cases where the AS is rotating -+ * the order of pre-configured values. */ -+ { -+ size_t i; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Use hardcoded Kc and SRES " -+ "values for testing"); -+ -+ for (i = 0; i < data->num_chal; i++) { -+ if (data->rand[i][0] == 0xaa) { -+ os_memcpy(data->kc[i], -+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7", -+ EAP_SIM_KC_LEN); -+ os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4", -+ EAP_SIM_SRES_LEN); -+ } else if (data->rand[i][0] == 0xbb) { -+ os_memcpy(data->kc[i], -+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7", -+ EAP_SIM_KC_LEN); -+ os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4", -+ EAP_SIM_SRES_LEN); -+ } else { -+ os_memcpy(data->kc[i], -+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7", -+ EAP_SIM_KC_LEN); -+ os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4", -+ EAP_SIM_SRES_LEN); -+ } -+ } -+ } -+ -+ return 0; -+ -+#else /* CONFIG_SIM_HARDCODED */ -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: No GSM authentication algorithm " -+ "enabled"); -+ return -1; -+ -+#endif /* CONFIG_SIM_HARDCODED */ -+} -+ -+ -+static int eap_sim_supported_ver(int version) -+{ -+ return version == EAP_SIM_VERSION; -+} -+ -+ -+#define CLEAR_PSEUDONYM 0x01 -+#define CLEAR_REAUTH_ID 0x02 -+#define CLEAR_EAP_ID 0x04 -+ -+static void eap_sim_clear_identities(struct eap_sim_data *data, int id) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s", -+ id & CLEAR_PSEUDONYM ? " pseudonym" : "", -+ id & CLEAR_REAUTH_ID ? " reauth_id" : "", -+ id & CLEAR_EAP_ID ? " eap_id" : ""); -+ if (id & CLEAR_PSEUDONYM) { -+ os_free(data->pseudonym); -+ data->pseudonym = NULL; -+ data->pseudonym_len = 0; -+ } -+ if (id & CLEAR_REAUTH_ID) { -+ os_free(data->reauth_id); -+ data->reauth_id = NULL; -+ data->reauth_id_len = 0; -+ } -+ if (id & CLEAR_EAP_ID) { -+ os_free(data->last_eap_identity); -+ data->last_eap_identity = NULL; -+ data->last_eap_identity_len = 0; -+ } -+} -+ -+ -+static int eap_sim_learn_ids(struct eap_sim_data *data, -+ struct eap_sim_attrs *attr) -+{ -+ if (attr->next_pseudonym) { -+ os_free(data->pseudonym); -+ data->pseudonym = os_malloc(attr->next_pseudonym_len); -+ if (data->pseudonym == NULL) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for " -+ "next pseudonym"); -+ return -1; -+ } -+ os_memcpy(data->pseudonym, attr->next_pseudonym, -+ attr->next_pseudonym_len); -+ data->pseudonym_len = attr->next_pseudonym_len; -+ wpa_hexdump_ascii(MSG_DEBUG, -+ "EAP-SIM: (encr) AT_NEXT_PSEUDONYM", -+ data->pseudonym, -+ data->pseudonym_len); -+ } -+ -+ if (attr->next_reauth_id) { -+ os_free(data->reauth_id); -+ data->reauth_id = os_malloc(attr->next_reauth_id_len); -+ if (data->reauth_id == NULL) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for " -+ "next reauth_id"); -+ return -1; -+ } -+ os_memcpy(data->reauth_id, attr->next_reauth_id, -+ attr->next_reauth_id_len); -+ data->reauth_id_len = attr->next_reauth_id_len; -+ wpa_hexdump_ascii(MSG_DEBUG, -+ "EAP-SIM: (encr) AT_NEXT_REAUTH_ID", -+ data->reauth_id, -+ data->reauth_id_len); -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id, -+ int err) -+{ -+ struct eap_sim_msg *msg; -+ -+ eap_sim_state(data, FAILURE); -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, -+ EAP_SIM_SUBTYPE_CLIENT_ERROR); -+ eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0); -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, -+ struct eap_sim_data *data, u8 id, -+ enum eap_sim_id_req id_req) -+{ -+ const u8 *identity = NULL; -+ size_t identity_len = 0; -+ struct eap_sim_msg *msg; -+ -+ data->reauth = 0; -+ if (id_req == ANY_ID && data->reauth_id) { -+ identity = data->reauth_id; -+ identity_len = data->reauth_id_len; -+ data->reauth = 1; -+ } else if ((id_req == ANY_ID || id_req == FULLAUTH_ID) && -+ data->pseudonym) { -+ identity = data->pseudonym; -+ identity_len = data->pseudonym_len; -+ eap_sim_clear_identities(data, CLEAR_REAUTH_ID); -+ } else if (id_req != NO_ID_REQ) { -+ identity = eap_get_config_identity(sm, &identity_len); -+ if (identity) { -+ eap_sim_clear_identities(data, CLEAR_PSEUDONYM | -+ CLEAR_REAUTH_ID); -+ } -+ } -+ if (id_req != NO_ID_REQ) -+ eap_sim_clear_identities(data, CLEAR_EAP_ID); -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, -+ EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START); -+ if (!data->reauth) { -+ wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT", -+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_MT, 0, -+ data->nonce_mt, EAP_SIM_NONCE_MT_LEN); -+ wpa_printf(MSG_DEBUG, " AT_SELECTED_VERSION %d", -+ data->selected_version); -+ eap_sim_msg_add(msg, EAP_SIM_AT_SELECTED_VERSION, -+ data->selected_version, NULL, 0); -+ } -+ -+ if (identity) { -+ wpa_hexdump_ascii(MSG_DEBUG, " AT_IDENTITY", -+ identity, identity_len); -+ eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, -+ identity, identity_len); -+ } -+ -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data, -+ u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, -+ EAP_SIM_SUBTYPE_CHALLENGE); -+ if (data->use_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres, -+ data->num_chal * EAP_SIM_SRES_LEN); -+} -+ -+ -+static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data, -+ u8 id, int counter_too_small) -+{ -+ struct eap_sim_msg *msg; -+ unsigned int counter; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Reauthentication (id=%d)", -+ id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, -+ EAP_SIM_SUBTYPE_REAUTHENTICATION); -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); -+ -+ if (counter_too_small) { -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER_TOO_SMALL"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER_TOO_SMALL, 0, NULL, 0); -+ counter = data->counter_too_small; -+ } else -+ counter = data->counter; -+ -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); -+ -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " -+ "AT_ENCR_DATA"); -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ if (data->use_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, data->nonce_s, -+ EAP_SIM_NONCE_S_LEN); -+} -+ -+ -+static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data, -+ u8 id, u16 notification) -+{ -+ struct eap_sim_msg *msg; -+ u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL; -+ -+ wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id); -+ msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, -+ EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION); -+ if (k_aut && data->reauth) { -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, -+ EAP_SIM_AT_ENCR_DATA); -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER %d", data->counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, -+ NULL, 0); -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, -+ EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " -+ "AT_ENCR_DATA"); -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ } -+ if (k_aut) { -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ } -+ return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0); -+} -+ -+ -+static struct wpabuf * eap_sim_process_start(struct eap_sm *sm, -+ struct eap_sim_data *data, u8 id, -+ struct eap_sim_attrs *attr) -+{ -+ int selected_version = -1, id_error; -+ size_t i; -+ u8 *pos; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start"); -+ if (attr->version_list == NULL) { -+ wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in " -+ "SIM/Start"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNSUPPORTED_VERSION); -+ } -+ -+ os_free(data->ver_list); -+ data->ver_list = os_malloc(attr->version_list_len); -+ if (data->ver_list == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate " -+ "memory for version list"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ os_memcpy(data->ver_list, attr->version_list, attr->version_list_len); -+ data->ver_list_len = attr->version_list_len; -+ pos = data->ver_list; -+ for (i = 0; i < data->ver_list_len / 2; i++) { -+ int ver = pos[0] * 256 + pos[1]; -+ pos += 2; -+ if (eap_sim_supported_ver(ver)) { -+ selected_version = ver; -+ break; -+ } -+ } -+ if (selected_version < 0) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported " -+ "version"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNSUPPORTED_VERSION); -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d", -+ selected_version); -+ data->selected_version = selected_version; -+ -+ id_error = 0; -+ switch (attr->id_req) { -+ case NO_ID_REQ: -+ break; -+ case ANY_ID: -+ if (data->num_id_req > 0) -+ id_error++; -+ data->num_id_req++; -+ break; -+ case FULLAUTH_ID: -+ if (data->num_id_req > 1) -+ id_error++; -+ data->num_id_req++; -+ break; -+ case PERMANENT_ID: -+ if (data->num_id_req > 2) -+ id_error++; -+ data->num_id_req++; -+ break; -+ } -+ if (id_error) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests " -+ "used within one authentication"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ return eap_sim_response_start(sm, data, id, attr->id_req); -+} -+ -+ -+static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ u8 id, -+ const struct wpabuf *reqData, -+ struct eap_sim_attrs *attr) -+{ -+ const u8 *identity; -+ size_t identity_len; -+ struct eap_sim_attrs eattr; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Challenge"); -+ data->reauth = 0; -+ if (!attr->mac || !attr->rand) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " -+ "did not include%s%s", -+ !attr->mac ? " AT_MAC" : "", -+ !attr->rand ? " AT_RAND" : ""); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: %lu challenges", -+ (unsigned long) attr->num_chal); -+ if (attr->num_chal < data->min_num_chal) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of " -+ "challenges (%lu)", (unsigned long) attr->num_chal); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_INSUFFICIENT_NUM_OF_CHAL); -+ } -+ if (attr->num_chal > 3) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges " -+ "(%lu)", (unsigned long) attr->num_chal); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ /* Verify that RANDs are different */ -+ if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN, -+ GSM_RAND_LEN) == 0 || -+ (attr->num_chal > 2 && -+ (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN, -+ GSM_RAND_LEN) == 0 || -+ os_memcmp(attr->rand + GSM_RAND_LEN, -+ attr->rand + 2 * GSM_RAND_LEN, -+ GSM_RAND_LEN) == 0))) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_RAND_NOT_FRESH); -+ } -+ -+ os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN); -+ data->num_chal = attr->num_chal; -+ -+ if (eap_sim_gsm_auth(sm, data)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ if (data->last_eap_identity) { -+ identity = data->last_eap_identity; -+ identity_len = data->last_eap_identity_len; -+ } else if (data->pseudonym) { -+ identity = data->pseudonym; -+ identity_len = data->pseudonym_len; -+ } else -+ identity = eap_get_config_identity(sm, &identity_len); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK " -+ "derivation", identity, identity_len); -+ eap_sim_derive_mk(identity, identity_len, data->nonce_mt, -+ data->selected_version, data->ver_list, -+ data->ver_list_len, data->num_chal, -+ (const u8 *) data->kc, data->mk); -+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, -+ data->emsk); -+ if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, data->nonce_mt, -+ EAP_SIM_NONCE_MT_LEN)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " -+ "used invalid AT_MAC"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ /* Old reauthentication and pseudonym identities must not be used -+ * anymore. In other words, if no new identities are received, full -+ * authentication will be used on next reauthentication. */ -+ eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID | -+ CLEAR_EAP_ID); -+ -+ if (attr->encr_data) { -+ u8 *decrypted; -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, -+ &eattr, 0); -+ if (decrypted == NULL) { -+ return eap_sim_client_error( -+ data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ eap_sim_learn_ids(data, &eattr); -+ os_free(decrypted); -+ } -+ -+ if (data->result_ind && attr->result_ind) -+ data->use_result_ind = 1; -+ -+ if (data->state != FAILURE && data->state != RESULT_FAILURE) { -+ eap_sim_state(data, data->use_result_ind ? -+ RESULT_SUCCESS : SUCCESS); -+ } -+ -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ /* RFC 4186 specifies that counter is initialized to one after -+ * fullauth, but initializing it to zero makes it easier to implement -+ * reauth verification. */ -+ data->counter = 0; -+ return eap_sim_response_challenge(data, id); -+} -+ -+ -+static int eap_sim_process_notification_reauth(struct eap_sim_data *data, -+ struct eap_sim_attrs *attr) -+{ -+ struct eap_sim_attrs eattr; -+ u8 *decrypted; -+ -+ if (attr->encr_data == NULL || attr->iv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after " -+ "reauth did not include encrypted data"); -+ return -1; -+ } -+ -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, &eattr, -+ 0); -+ if (decrypted == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " -+ "data from notification message"); -+ return -1; -+ } -+ -+ if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification " -+ "message does not match with counter in reauth " -+ "message"); -+ os_free(decrypted); -+ return -1; -+ } -+ -+ os_free(decrypted); -+ return 0; -+} -+ -+ -+static int eap_sim_process_notification_auth(struct eap_sim_data *data, -+ const struct wpabuf *reqData, -+ struct eap_sim_attrs *attr) -+{ -+ if (attr->mac == NULL) { -+ wpa_printf(MSG_INFO, "EAP-SIM: no AT_MAC in after_auth " -+ "Notification message"); -+ return -1; -+ } -+ -+ if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) -+ { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Notification message " -+ "used invalid AT_MAC"); -+ return -1; -+ } -+ -+ if (data->reauth && -+ eap_sim_process_notification_reauth(data, attr)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification " -+ "message after reauth"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_sim_process_notification( -+ struct eap_sm *sm, struct eap_sim_data *data, u8 id, -+ const struct wpabuf *reqData, struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Notification"); -+ if (data->num_notification > 0) { -+ wpa_printf(MSG_INFO, "EAP-SIM: too many notification " -+ "rounds (only one allowed)"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ data->num_notification++; -+ if (attr->notification == -1) { -+ wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in " -+ "Notification message"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if ((attr->notification & 0x4000) == 0 && -+ eap_sim_process_notification_auth(data, reqData, attr)) { -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ eap_sim_report_notification(sm->msg_ctx, attr->notification, 0); -+ if (attr->notification >= 0 && attr->notification < 32768) { -+ eap_sim_state(data, FAILURE); -+ } else if (attr->notification == EAP_SIM_SUCCESS && -+ data->state == RESULT_SUCCESS) -+ eap_sim_state(data, SUCCESS); -+ return eap_sim_response_notification(data, id, attr->notification); -+} -+ -+ -+static struct wpabuf * eap_sim_process_reauthentication( -+ struct eap_sm *sm, struct eap_sim_data *data, u8 id, -+ const struct wpabuf *reqData, struct eap_sim_attrs *attr) -+{ -+ struct eap_sim_attrs eattr; -+ u8 *decrypted; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication"); -+ -+ if (data->reauth_id == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying " -+ "reauthentication, but no reauth_id available"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ data->reauth = 1; -+ if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0)) -+ { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " -+ "did not have valid AT_MAC"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if (attr->encr_data == NULL || attr->iv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " -+ "message did not include encrypted data"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, &eattr, -+ 0); -+ if (decrypted == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " -+ "data from reauthentication message"); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if (eattr.nonce_s == NULL || eattr.counter < 0) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet", -+ !eattr.nonce_s ? " AT_NONCE_S" : "", -+ eattr.counter < 0 ? " AT_COUNTER" : ""); -+ os_free(decrypted); -+ return eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ } -+ -+ if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) { -+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter " -+ "(%d <= %d)", eattr.counter, data->counter); -+ data->counter_too_small = eattr.counter; -+ /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current -+ * reauth_id must not be used to start a new reauthentication. -+ * However, since it was used in the last EAP-Response-Identity -+ * packet, it has to saved for the following fullauth to be -+ * used in MK derivation. */ -+ os_free(data->last_eap_identity); -+ data->last_eap_identity = data->reauth_id; -+ data->last_eap_identity_len = data->reauth_id_len; -+ data->reauth_id = NULL; -+ data->reauth_id_len = 0; -+ os_free(decrypted); -+ return eap_sim_response_reauth(data, id, 1); -+ } -+ data->counter = eattr.counter; -+ -+ os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S", -+ data->nonce_s, EAP_SIM_NONCE_S_LEN); -+ -+ eap_sim_derive_keys_reauth(data->counter, -+ data->reauth_id, data->reauth_id_len, -+ data->nonce_s, data->mk, data->msk, -+ data->emsk); -+ eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); -+ eap_sim_learn_ids(data, &eattr); -+ -+ if (data->result_ind && attr->result_ind) -+ data->use_result_ind = 1; -+ -+ if (data->state != FAILURE && data->state != RESULT_FAILURE) { -+ eap_sim_state(data, data->use_result_ind ? -+ RESULT_SUCCESS : SUCCESS); -+ } -+ -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of " -+ "fast reauths performed - force fullauth"); -+ eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); -+ } -+ os_free(decrypted); -+ return eap_sim_response_reauth(data, id, 0); -+} -+ -+ -+static struct wpabuf * eap_sim_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_sim_data *data = priv; -+ const struct eap_hdr *req; -+ u8 subtype, id; -+ struct wpabuf *res; -+ const u8 *pos; -+ struct eap_sim_attrs attr; -+ size_t len; -+ -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-SIM: EAP data", reqData); -+ if (eap_get_config_identity(sm, &len) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured"); -+ eap_sm_request_identity(sm); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, reqData, &len); -+ if (pos == NULL || len < 1) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ req = wpabuf_head(reqData); -+ id = req->identifier; -+ len = be_to_host16(req->length); -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = TRUE; -+ -+ subtype = *pos++; -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype); -+ pos += 2; /* Reserved */ -+ -+ if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 0, -+ 0)) { -+ res = eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ goto done; -+ } -+ -+ switch (subtype) { -+ case EAP_SIM_SUBTYPE_START: -+ res = eap_sim_process_start(sm, data, id, &attr); -+ break; -+ case EAP_SIM_SUBTYPE_CHALLENGE: -+ res = eap_sim_process_challenge(sm, data, id, reqData, &attr); -+ break; -+ case EAP_SIM_SUBTYPE_NOTIFICATION: -+ res = eap_sim_process_notification(sm, data, id, reqData, -+ &attr); -+ break; -+ case EAP_SIM_SUBTYPE_REAUTHENTICATION: -+ res = eap_sim_process_reauthentication(sm, data, id, reqData, -+ &attr); -+ break; -+ case EAP_SIM_SUBTYPE_CLIENT_ERROR: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error"); -+ res = eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype); -+ res = eap_sim_client_error(data, id, -+ EAP_SIM_UNABLE_TO_PROCESS_PACKET); -+ break; -+ } -+ -+done: -+ if (data->state == FAILURE) { -+ ret->decision = DECISION_FAIL; -+ ret->methodState = METHOD_DONE; -+ } else if (data->state == SUCCESS) { -+ ret->decision = data->use_result_ind ? -+ DECISION_UNCOND_SUCC : DECISION_COND_SUCC; -+ ret->methodState = data->use_result_ind ? -+ METHOD_DONE : METHOD_MAY_CONT; -+ } else if (data->state == RESULT_FAILURE) -+ ret->methodState = METHOD_CONT; -+ else if (data->state == RESULT_SUCCESS) -+ ret->methodState = METHOD_CONT; -+ -+ if (ret->methodState == METHOD_DONE) { -+ ret->allowNotifications = FALSE; -+ } -+ -+ return res; -+} -+ -+ -+static Boolean eap_sim_has_reauth_data(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ return data->pseudonym || data->reauth_id; -+} -+ -+ -+static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ eap_sim_clear_identities(data, CLEAR_EAP_ID); -+ data->use_result_ind = 0; -+} -+ -+ -+static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ if (random_get_bytes(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data " -+ "for NONCE_MT"); -+ os_free(data); -+ return NULL; -+ } -+ data->num_id_req = 0; -+ data->num_notification = 0; -+ eap_sim_state(data, CONTINUE); -+ return priv; -+} -+ -+ -+static const u8 * eap_sim_get_identity(struct eap_sm *sm, void *priv, -+ size_t *len) -+{ -+ struct eap_sim_data *data = priv; -+ -+ if (data->reauth_id) { -+ *len = data->reauth_id_len; -+ return data->reauth_id; -+ } -+ -+ if (data->pseudonym) { -+ *len = data->pseudonym_len; -+ return data->pseudonym; -+ } -+ -+ return NULL; -+} -+ -+ -+static Boolean eap_sim_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sim_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_SIM_KEYING_DATA_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_SIM_KEYING_DATA_LEN; -+ os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); -+ -+ return key; -+} -+ -+ -+static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sim_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_EMSK_LEN; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ -+ return key; -+} -+ -+ -+int eap_peer_sim_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_sim_init; -+ eap->deinit = eap_sim_deinit; -+ eap->process = eap_sim_process; -+ eap->isKeyAvailable = eap_sim_isKeyAvailable; -+ eap->getKey = eap_sim_getKey; -+ eap->has_reauth_data = eap_sim_has_reauth_data; -+ eap->deinit_for_reauth = eap_sim_deinit_for_reauth; -+ eap->init_for_reauth = eap_sim_init_for_reauth; -+ eap->get_identity = eap_sim_get_identity; -+ eap->get_emsk = eap_sim_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls.c -new file mode 100644 -index 0000000000000..20b2212e1cdc4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls.c -@@ -0,0 +1,289 @@ -+/* -+ * EAP peer method: EAP-TLS (RFC 2716) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/tls.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+#include "eap_config.h" -+ -+ -+static void eap_tls_deinit(struct eap_sm *sm, void *priv); -+ -+ -+struct eap_tls_data { -+ struct eap_ssl_data ssl; -+ u8 *key_data; -+}; -+ -+ -+static void * eap_tls_init(struct eap_sm *sm) -+{ -+ struct eap_tls_data *data; -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config == NULL || -+ ((sm->init_phase2 ? config->private_key2 : config->private_key) -+ == NULL && -+ (sm->init_phase2 ? config->engine2 : config->engine) == 0)) { -+ wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) { -+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); -+ eap_tls_deinit(sm, data); -+ if (config->engine) { -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard " -+ "PIN"); -+ eap_sm_request_pin(sm); -+ sm->ignore = TRUE; -+ } else if (config->private_key && !config->private_key_passwd) -+ { -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private " -+ "key passphrase"); -+ eap_sm_request_passphrase(sm); -+ sm->ignore = TRUE; -+ } -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_tls_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tls_data *data = priv; -+ if (data == NULL) -+ return; -+ eap_peer_tls_ssl_deinit(sm, &data->ssl); -+ os_free(data->key_data); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_tls_failure(struct eap_sm *sm, -+ struct eap_tls_data *data, -+ struct eap_method_ret *ret, int res, -+ struct wpabuf *resp, u8 id) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed"); -+ -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ -+ if (res == -1) { -+ struct eap_peer_config *config = eap_get_config(sm); -+ if (config) { -+ /* -+ * The TLS handshake failed. So better forget the old -+ * PIN. It may be wrong, we cannot be sure but trying -+ * the wrong one again might block it on the card--so -+ * better ask the user again. -+ */ -+ os_free(config->pin); -+ config->pin = NULL; -+ } -+ } -+ -+ if (resp) { -+ /* -+ * This is likely an alert message, so send it instead of just -+ * ACKing the error. -+ */ -+ return resp; -+ } -+ -+ return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0); -+} -+ -+ -+static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, -+ struct eap_method_ret *ret) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); -+ -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ -+ os_free(data->key_data); -+ data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, -+ "client EAP encryption", -+ EAP_TLS_KEY_LEN + -+ EAP_EMSK_LEN); -+ if (data->key_data) { -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key", -+ data->key_data, EAP_TLS_KEY_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK", -+ data->key_data + EAP_TLS_KEY_LEN, -+ EAP_EMSK_LEN); -+ } else { -+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key"); -+ } -+} -+ -+ -+static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ size_t left; -+ int res; -+ struct wpabuf *resp; -+ u8 flags, id; -+ const u8 *pos; -+ struct eap_tls_data *data = priv; -+ -+ pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret, -+ reqData, &left, &flags); -+ if (pos == NULL) -+ return NULL; -+ id = eap_get_id(reqData); -+ -+ if (flags & EAP_TLS_FLAGS_START) { -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Start"); -+ left = 0; /* make sure that this frame is empty, even though it -+ * should always be, anyway */ -+ } -+ -+ resp = NULL; -+ res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id, -+ pos, left, &resp); -+ -+ if (res < 0) { -+ return eap_tls_failure(sm, data, ret, res, resp, id); -+ } -+ -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) -+ eap_tls_success(sm, data, ret); -+ -+ if (res == 1) { -+ wpabuf_free(resp); -+ return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0); -+ } -+ -+ return resp; -+} -+ -+ -+static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tls_data *data = priv; -+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn); -+} -+ -+ -+static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) -+{ -+} -+ -+ -+static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tls_data *data = priv; -+ os_free(data->key_data); -+ data->key_data = NULL; -+ if (eap_peer_tls_reauth_init(sm, &data->ssl)) { -+ os_free(data); -+ return NULL; -+ } -+ return priv; -+} -+ -+ -+static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf, -+ size_t buflen, int verbose) -+{ -+ struct eap_tls_data *data = priv; -+ return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); -+} -+ -+ -+static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tls_data *data = priv; -+ return data->key_data != NULL; -+} -+ -+ -+static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_tls_data *data = priv; -+ u8 *key; -+ -+ if (data->key_data == NULL) -+ return NULL; -+ -+ key = os_malloc(EAP_TLS_KEY_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_TLS_KEY_LEN; -+ os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); -+ -+ return key; -+} -+ -+ -+static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_tls_data *data = priv; -+ u8 *key; -+ -+ if (data->key_data == NULL) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_EMSK_LEN; -+ os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); -+ -+ return key; -+} -+ -+ -+int eap_peer_tls_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_tls_init; -+ eap->deinit = eap_tls_deinit; -+ eap->process = eap_tls_process; -+ eap->isKeyAvailable = eap_tls_isKeyAvailable; -+ eap->getKey = eap_tls_getKey; -+ eap->get_status = eap_tls_get_status; -+ eap->has_reauth_data = eap_tls_has_reauth_data; -+ eap->deinit_for_reauth = eap_tls_deinit_for_reauth; -+ eap->init_for_reauth = eap_tls_init_for_reauth; -+ eap->get_emsk = eap_tls_get_emsk; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.c -new file mode 100644 -index 0000000000000..d1567e9281da4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.c -@@ -0,0 +1,1021 @@ -+/* -+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+#include "eap_config.h" -+ -+ -+static int eap_tls_check_blob(struct eap_sm *sm, const char **name, -+ const u8 **data, size_t *data_len) -+{ -+ const struct wpa_config_blob *blob; -+ -+ if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) -+ return 0; -+ -+ blob = eap_get_config_blob(sm, *name + 7); -+ if (blob == NULL) { -+ wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " -+ "found", __func__, *name + 7); -+ return -1; -+ } -+ -+ *name = NULL; -+ *data = blob->data; -+ *data_len = blob->len; -+ -+ return 0; -+} -+ -+ -+static void eap_tls_params_flags(struct tls_connection_params *params, -+ const char *txt) -+{ -+ if (txt == NULL) -+ return; -+ if (os_strstr(txt, "tls_allow_md5=1")) -+ params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; -+ if (os_strstr(txt, "tls_disable_time_checks=1")) -+ params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; -+} -+ -+ -+static void eap_tls_params_from_conf1(struct tls_connection_params *params, -+ struct eap_peer_config *config) -+{ -+ params->ca_cert = (char *) config->ca_cert; -+ params->ca_path = (char *) config->ca_path; -+ params->client_cert = (char *) config->client_cert; -+ params->private_key = (char *) config->private_key; -+ params->private_key_passwd = (char *) config->private_key_passwd; -+ params->dh_file = (char *) config->dh_file; -+ params->subject_match = (char *) config->subject_match; -+ params->altsubject_match = (char *) config->altsubject_match; -+ params->engine = config->engine; -+ params->engine_id = config->engine_id; -+ params->pin = config->pin; -+ params->key_id = config->key_id; -+ params->cert_id = config->cert_id; -+ params->ca_cert_id = config->ca_cert_id; -+ eap_tls_params_flags(params, config->phase1); -+} -+ -+ -+static void eap_tls_params_from_conf2(struct tls_connection_params *params, -+ struct eap_peer_config *config) -+{ -+ params->ca_cert = (char *) config->ca_cert2; -+ params->ca_path = (char *) config->ca_path2; -+ params->client_cert = (char *) config->client_cert2; -+ params->private_key = (char *) config->private_key2; -+ params->private_key_passwd = (char *) config->private_key2_passwd; -+ params->dh_file = (char *) config->dh_file2; -+ params->subject_match = (char *) config->subject_match2; -+ params->altsubject_match = (char *) config->altsubject_match2; -+ params->engine = config->engine2; -+ params->engine_id = config->engine2_id; -+ params->pin = config->pin2; -+ params->key_id = config->key2_id; -+ params->cert_id = config->cert2_id; -+ params->ca_cert_id = config->ca_cert2_id; -+ eap_tls_params_flags(params, config->phase2); -+} -+ -+ -+static int eap_tls_params_from_conf(struct eap_sm *sm, -+ struct eap_ssl_data *data, -+ struct tls_connection_params *params, -+ struct eap_peer_config *config, int phase2) -+{ -+ os_memset(params, 0, sizeof(*params)); -+ if (phase2) { -+ wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); -+ eap_tls_params_from_conf2(params, config); -+ } else { -+ wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); -+ eap_tls_params_from_conf1(params, config); -+ } -+ params->tls_ia = data->tls_ia; -+ -+ /* -+ * Use blob data, if available. Otherwise, leave reference to external -+ * file as-is. -+ */ -+ if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, -+ ¶ms->ca_cert_blob_len) || -+ eap_tls_check_blob(sm, ¶ms->client_cert, -+ ¶ms->client_cert_blob, -+ ¶ms->client_cert_blob_len) || -+ eap_tls_check_blob(sm, ¶ms->private_key, -+ ¶ms->private_key_blob, -+ ¶ms->private_key_blob_len) || -+ eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, -+ ¶ms->dh_blob_len)) { -+ wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_tls_init_connection(struct eap_sm *sm, -+ struct eap_ssl_data *data, -+ struct eap_peer_config *config, -+ struct tls_connection_params *params) -+{ -+ int res; -+ -+ data->conn = tls_connection_init(sm->ssl_ctx); -+ if (data->conn == NULL) { -+ wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " -+ "connection"); -+ return -1; -+ } -+ -+ res = tls_connection_set_params(sm->ssl_ctx, data->conn, params); -+ if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { -+ /* -+ * At this point with the pkcs11 engine the PIN might be wrong. -+ * We reset the PIN in the configuration to be sure to not use -+ * it again and the calling function must request a new one. -+ */ -+ os_free(config->pin); -+ config->pin = NULL; -+ } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { -+ wpa_printf(MSG_INFO, "TLS: Failed to load private key"); -+ /* -+ * We do not know exactly but maybe the PIN was wrong, -+ * so ask for a new one. -+ */ -+ os_free(config->pin); -+ config->pin = NULL; -+ eap_sm_request_pin(sm); -+ sm->ignore = TRUE; -+ tls_connection_deinit(sm->ssl_ctx, data->conn); -+ data->conn = NULL; -+ return -1; -+ } else if (res) { -+ wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " -+ "parameters"); -+ tls_connection_deinit(sm->ssl_ctx, data->conn); -+ data->conn = NULL; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_peer_tls_ssl_init - Initialize shared TLS functionality -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @config: Pointer to the network configuration -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to initialize shared TLS functionality for EAP-TLS, -+ * EAP-PEAP, EAP-TTLS, and EAP-FAST. -+ */ -+int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, -+ struct eap_peer_config *config) -+{ -+ struct tls_connection_params params; -+ -+ if (config == NULL) -+ return -1; -+ -+ data->eap = sm; -+ data->phase2 = sm->init_phase2; -+ if (eap_tls_params_from_conf(sm, data, ¶ms, config, data->phase2) < -+ 0) -+ return -1; -+ -+ if (eap_tls_init_connection(sm, data, config, ¶ms) < 0) -+ return -1; -+ -+ data->tls_out_limit = config->fragment_size; -+ if (data->phase2) { -+ /* Limit the fragment size in the inner TLS authentication -+ * since the outer authentication with EAP-PEAP does not yet -+ * support fragmentation */ -+ if (data->tls_out_limit > 100) -+ data->tls_out_limit -= 100; -+ } -+ -+ if (config->phase1 && -+ os_strstr(config->phase1, "include_tls_length=1")) { -+ wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in " -+ "unfragmented packets"); -+ data->include_tls_length = 1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * -+ * This function deinitializes shared TLS functionality that was initialized -+ * with eap_peer_tls_ssl_init(). -+ */ -+void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) -+{ -+ tls_connection_deinit(sm->ssl_ctx, data->conn); -+ eap_peer_tls_reset_input(data); -+ eap_peer_tls_reset_output(data); -+} -+ -+ -+/** -+ * eap_peer_tls_derive_key - Derive a key based on TLS session data -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @label: Label string for deriving the keys, e.g., "client EAP encryption" -+ * @len: Length of the key material to generate (usually 64 for MSK) -+ * Returns: Pointer to allocated key on success or %NULL on failure -+ * -+ * This function uses TLS-PRF to generate pseudo-random data based on the TLS -+ * session data (client/server random and master key). Each key type may use a -+ * different label to bind the key usage into the generated material. -+ * -+ * The caller is responsible for freeing the returned buffer. -+ */ -+u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, -+ const char *label, size_t len) -+{ -+ struct tls_keys keys; -+ u8 *rnd = NULL, *out; -+ -+ out = os_malloc(len); -+ if (out == NULL) -+ return NULL; -+ -+ /* First, try to use TLS library function for PRF, if available. */ -+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == -+ 0) -+ return out; -+ -+ /* -+ * TLS library did not support key generation, so get the needed TLS -+ * session parameters and use an internal implementation of TLS PRF to -+ * derive the key. -+ */ -+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) -+ goto fail; -+ -+ if (keys.client_random == NULL || keys.server_random == NULL || -+ keys.master_key == NULL) -+ goto fail; -+ -+ rnd = os_malloc(keys.client_random_len + keys.server_random_len); -+ if (rnd == NULL) -+ goto fail; -+ os_memcpy(rnd, keys.client_random, keys.client_random_len); -+ os_memcpy(rnd + keys.client_random_len, keys.server_random, -+ keys.server_random_len); -+ -+ if (tls_prf(keys.master_key, keys.master_key_len, -+ label, rnd, keys.client_random_len + -+ keys.server_random_len, out, len)) -+ goto fail; -+ -+ os_free(rnd); -+ return out; -+ -+fail: -+ os_free(out); -+ os_free(rnd); -+ return NULL; -+} -+ -+ -+/** -+ * eap_peer_tls_reassemble_fragment - Reassemble a received fragment -+ * @data: Data for TLS processing -+ * @in_data: Next incoming TLS segment -+ * Returns: 0 on success, 1 if more data is needed for the full message, or -+ * -1 on error -+ */ -+static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, -+ const struct wpabuf *in_data) -+{ -+ size_t tls_in_len, in_len; -+ -+ tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; -+ in_len = in_data ? wpabuf_len(in_data) : 0; -+ -+ if (tls_in_len + in_len == 0) { -+ /* No message data received?! */ -+ wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " -+ "tls_in_left=%lu tls_in_len=%lu in_len=%lu", -+ (unsigned long) data->tls_in_left, -+ (unsigned long) tls_in_len, -+ (unsigned long) in_len); -+ eap_peer_tls_reset_input(data); -+ return -1; -+ } -+ -+ if (tls_in_len + in_len > 65536) { -+ /* -+ * Limit length to avoid rogue servers from causing large -+ * memory allocations. -+ */ -+ wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over " -+ "64 kB)"); -+ eap_peer_tls_reset_input(data); -+ return -1; -+ } -+ -+ if (in_len > data->tls_in_left) { -+ /* Sender is doing something odd - reject message */ -+ wpa_printf(MSG_INFO, "SSL: more data than TLS message length " -+ "indicated"); -+ eap_peer_tls_reset_input(data); -+ return -1; -+ } -+ -+ if (wpabuf_resize(&data->tls_in, in_len) < 0) { -+ wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " -+ "data"); -+ eap_peer_tls_reset_input(data); -+ return -1; -+ } -+ if (in_data) -+ wpabuf_put_buf(data->tls_in, in_data); -+ data->tls_in_left -= in_len; -+ -+ if (data->tls_in_left > 0) { -+ wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " -+ "data", (unsigned long) data->tls_in_left); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_peer_tls_data_reassemble - Reassemble TLS data -+ * @data: Data for TLS processing -+ * @in_data: Next incoming TLS segment -+ * @need_more_input: Variable for returning whether more input data is needed -+ * to reassemble this TLS packet -+ * Returns: Pointer to output data, %NULL on error or when more data is needed -+ * for the full message (in which case, *need_more_input is also set to 1). -+ * -+ * This function reassembles TLS fragments. Caller must not free the returned -+ * data buffer since an internal pointer to it is maintained. -+ */ -+static const struct wpabuf * eap_peer_tls_data_reassemble( -+ struct eap_ssl_data *data, const struct wpabuf *in_data, -+ int *need_more_input) -+{ -+ *need_more_input = 0; -+ -+ if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { -+ /* Message has fragments */ -+ int res = eap_peer_tls_reassemble_fragment(data, in_data); -+ if (res) { -+ if (res == 1) -+ *need_more_input = 1; -+ return NULL; -+ } -+ -+ /* Message is now fully reassembled. */ -+ } else { -+ /* No fragments in this message, so just make a copy of it. */ -+ data->tls_in_left = 0; -+ data->tls_in = wpabuf_dup(in_data); -+ if (data->tls_in == NULL) -+ return NULL; -+ } -+ -+ return data->tls_in; -+} -+ -+ -+/** -+ * eap_tls_process_input - Process incoming TLS message -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @in_data: Message received from the server -+ * @in_len: Length of in_data -+ * @out_data: Buffer for returning a pointer to application data (if available) -+ * Returns: 0 on success, 1 if more input data is needed, 2 if application data -+ * is available, -1 on failure -+ */ -+static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, -+ const u8 *in_data, size_t in_len, -+ struct wpabuf **out_data) -+{ -+ const struct wpabuf *msg; -+ int need_more_input; -+ struct wpabuf *appl_data; -+ struct wpabuf buf; -+ -+ wpabuf_set(&buf, in_data, in_len); -+ msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input); -+ if (msg == NULL) -+ return need_more_input ? 1 : -1; -+ -+ /* Full TLS message reassembled - continue handshake processing */ -+ if (data->tls_out) { -+ /* This should not happen.. */ -+ wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " -+ "tls_out data even though tls_out_len = 0"); -+ wpabuf_free(data->tls_out); -+ WPA_ASSERT(data->tls_out == NULL); -+ } -+ appl_data = NULL; -+ data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn, -+ msg, &appl_data); -+ -+ eap_peer_tls_reset_input(data); -+ -+ if (appl_data && -+ tls_connection_established(sm->ssl_ctx, data->conn) && -+ !tls_connection_get_failed(sm->ssl_ctx, data->conn)) { -+ wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", -+ appl_data); -+ *out_data = appl_data; -+ return 2; -+ } -+ -+ wpabuf_free(appl_data); -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_tls_process_output - Process outgoing TLS message -+ * @data: Data for TLS processing -+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) -+ * @peap_version: Version number for EAP-PEAP/TTLS -+ * @id: EAP identifier for the response -+ * @ret: Return value to use on success -+ * @out_data: Buffer for returning the allocated output buffer -+ * Returns: ret (0 or 1) on success, -1 on failure -+ */ -+static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, -+ int peap_version, u8 id, int ret, -+ struct wpabuf **out_data) -+{ -+ size_t len; -+ u8 *flags; -+ int more_fragments, length_included; -+ -+ if (data->tls_out == NULL) -+ return -1; -+ len = wpabuf_len(data->tls_out) - data->tls_out_pos; -+ wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " -+ "%lu bytes)", -+ (unsigned long) len, -+ (unsigned long) wpabuf_len(data->tls_out)); -+ -+ /* -+ * Limit outgoing message to the configured maximum size. Fragment -+ * message if needed. -+ */ -+ if (len > data->tls_out_limit) { -+ more_fragments = 1; -+ len = data->tls_out_limit; -+ wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments " -+ "will follow", (unsigned long) len); -+ } else -+ more_fragments = 0; -+ -+ length_included = data->tls_out_pos == 0 && -+ (wpabuf_len(data->tls_out) > data->tls_out_limit || -+ data->include_tls_length); -+ if (!length_included && -+ eap_type == EAP_TYPE_PEAP && peap_version == 0 && -+ !tls_connection_established(data->eap->ssl_ctx, data->conn)) { -+ /* -+ * Windows Server 2008 NPS really wants to have the TLS Message -+ * length included in phase 0 even for unfragmented frames or -+ * it will get very confused with Compound MAC calculation and -+ * Outer TLVs. -+ */ -+ length_included = 1; -+ } -+ -+ *out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, -+ 1 + length_included * 4 + len, -+ EAP_CODE_RESPONSE, id); -+ if (*out_data == NULL) -+ return -1; -+ -+ flags = wpabuf_put(*out_data, 1); -+ *flags = peap_version; -+ if (more_fragments) -+ *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; -+ if (length_included) { -+ *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; -+ wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); -+ } -+ -+ wpabuf_put_data(*out_data, -+ wpabuf_head_u8(data->tls_out) + data->tls_out_pos, -+ len); -+ data->tls_out_pos += len; -+ -+ if (!more_fragments) -+ eap_peer_tls_reset_output(data); -+ -+ return ret; -+} -+ -+ -+/** -+ * eap_peer_tls_process_helper - Process TLS handshake message -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) -+ * @peap_version: Version number for EAP-PEAP/TTLS -+ * @id: EAP identifier for the response -+ * @in_data: Message received from the server -+ * @in_len: Length of in_data -+ * @out_data: Buffer for returning a pointer to the response message -+ * Returns: 0 on success, 1 if more input data is needed, 2 if application data -+ * is available, or -1 on failure -+ * -+ * This function can be used to process TLS handshake messages. It reassembles -+ * the received fragments and uses a TLS library to process the messages. The -+ * response data from the TLS library is fragmented to suitable output messages -+ * that the caller can send out. -+ * -+ * out_data is used to return the response message if the return value of this -+ * function is 0, 2, or -1. In case of failure, the message is likely a TLS -+ * alarm message. The caller is responsible for freeing the allocated buffer if -+ * *out_data is not %NULL. -+ * -+ * This function is called for each received TLS message during the TLS -+ * handshake after eap_peer_tls_process_init() call and possible processing of -+ * TLS Flags field. Once the handshake has been completed, i.e., when -+ * tls_connection_established() returns 1, EAP method specific decrypting of -+ * the tunneled data is used. -+ */ -+int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, -+ EapType eap_type, int peap_version, -+ u8 id, const u8 *in_data, size_t in_len, -+ struct wpabuf **out_data) -+{ -+ int ret = 0; -+ -+ *out_data = NULL; -+ -+ if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) { -+ wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " -+ "fragments are waiting to be sent out"); -+ return -1; -+ } -+ -+ if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { -+ /* -+ * No more data to send out - expect to receive more data from -+ * the AS. -+ */ -+ int res = eap_tls_process_input(sm, data, in_data, in_len, -+ out_data); -+ if (res) { -+ /* -+ * Input processing failed (res = -1) or more data is -+ * needed (res = 1). -+ */ -+ return res; -+ } -+ -+ /* -+ * The incoming message has been reassembled and processed. The -+ * response was allocated into data->tls_out buffer. -+ */ -+ } -+ -+ if (data->tls_out == NULL) { -+ /* -+ * No outgoing fragments remaining from the previous message -+ * and no new message generated. This indicates an error in TLS -+ * processing. -+ */ -+ eap_peer_tls_reset_output(data); -+ return -1; -+ } -+ -+ if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { -+ /* TLS processing has failed - return error */ -+ wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " -+ "report error"); -+ ret = -1; -+ /* TODO: clean pin if engine used? */ -+ } -+ -+ if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { -+ /* -+ * TLS negotiation should now be complete since all other cases -+ * needing more data should have been caught above based on -+ * the TLS Message Length field. -+ */ -+ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); -+ wpabuf_free(data->tls_out); -+ data->tls_out = NULL; -+ return 1; -+ } -+ -+ /* Send the pending message (in fragments, if needed). */ -+ return eap_tls_process_output(data, eap_type, peap_version, id, ret, -+ out_data); -+} -+ -+ -+/** -+ * eap_peer_tls_build_ack - Build a TLS ACK frame -+ * @id: EAP identifier for the response -+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) -+ * @peap_version: Version number for EAP-PEAP/TTLS -+ * Returns: Pointer to the allocated ACK frame or %NULL on failure -+ */ -+struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, -+ int peap_version) -+{ -+ struct wpabuf *resp; -+ -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE, -+ id); -+ if (resp == NULL) -+ return NULL; -+ wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", -+ (int) eap_type, id, peap_version); -+ wpabuf_put_u8(resp, peap_version); /* Flags */ -+ return resp; -+} -+ -+ -+/** -+ * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data) -+{ -+ eap_peer_tls_reset_input(data); -+ eap_peer_tls_reset_output(data); -+ return tls_connection_shutdown(sm->ssl_ctx, data->conn); -+} -+ -+ -+/** -+ * eap_peer_tls_status - Get TLS status -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @buf: Buffer for status information -+ * @buflen: Maximum buffer length -+ * @verbose: Whether to include verbose status information -+ * Returns: Number of bytes written to buf. -+ */ -+int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, -+ char *buf, size_t buflen, int verbose) -+{ -+ char name[128]; -+ int len = 0, ret; -+ -+ if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) { -+ ret = os_snprintf(buf + len, buflen - len, -+ "EAP TLS cipher=%s\n", name); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ } -+ -+ return len; -+} -+ -+ -+/** -+ * eap_peer_tls_process_init - Initial validation/processing of EAP requests -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) -+ * @ret: Return values from EAP request validation and processing -+ * @reqData: EAP request to be processed (eapReqData) -+ * @len: Buffer for returning length of the remaining payload -+ * @flags: Buffer for returning TLS flags -+ * Returns: Pointer to payload after TLS flags and length or %NULL on failure -+ * -+ * This function validates the EAP header and processes the optional TLS -+ * Message Length field. If this is the first fragment of a TLS message, the -+ * TLS reassembly code is initialized to receive the indicated number of bytes. -+ * -+ * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this -+ * function as the first step in processing received messages. They will need -+ * to process the flags (apart from Message Length Included) that are returned -+ * through the flags pointer and the message payload that will be returned (and -+ * the length is returned through the len pointer). Return values (ret) are set -+ * for continuation of EAP method processing. The caller is responsible for -+ * setting these to indicate completion (either success or failure) based on -+ * the authentication result. -+ */ -+const u8 * eap_peer_tls_process_init(struct eap_sm *sm, -+ struct eap_ssl_data *data, -+ EapType eap_type, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ size_t *len, u8 *flags) -+{ -+ const u8 *pos; -+ size_t left; -+ unsigned int tls_msg_len; -+ -+ if (tls_get_errors(sm->ssl_ctx)) { -+ wpa_printf(MSG_INFO, "SSL: TLS errors detected"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left); -+ if (pos == NULL) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ if (left == 0) { -+ wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags " -+ "octet included"); -+ if (!sm->workaround) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags " -+ "indicates ACK frame"); -+ *flags = 0; -+ } else { -+ *flags = *pos++; -+ left--; -+ } -+ wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " -+ "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), -+ *flags); -+ if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { -+ if (left < 4) { -+ wpa_printf(MSG_INFO, "SSL: Short frame with TLS " -+ "length"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ tls_msg_len = WPA_GET_BE32(pos); -+ wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", -+ tls_msg_len); -+ if (data->tls_in_left == 0) { -+ data->tls_in_total = tls_msg_len; -+ data->tls_in_left = tls_msg_len; -+ wpabuf_free(data->tls_in); -+ data->tls_in = NULL; -+ } -+ pos += 4; -+ left -= 4; -+ } -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = TRUE; -+ -+ *len = left; -+ return pos; -+} -+ -+ -+/** -+ * eap_peer_tls_reset_input - Reset input buffers -+ * @data: Data for TLS processing -+ * -+ * This function frees any allocated memory for input buffers and resets input -+ * state. -+ */ -+void eap_peer_tls_reset_input(struct eap_ssl_data *data) -+{ -+ data->tls_in_left = data->tls_in_total = 0; -+ wpabuf_free(data->tls_in); -+ data->tls_in = NULL; -+} -+ -+ -+/** -+ * eap_peer_tls_reset_output - Reset output buffers -+ * @data: Data for TLS processing -+ * -+ * This function frees any allocated memory for output buffers and resets -+ * output state. -+ */ -+void eap_peer_tls_reset_output(struct eap_ssl_data *data) -+{ -+ data->tls_out_pos = 0; -+ wpabuf_free(data->tls_out); -+ data->tls_out = NULL; -+} -+ -+ -+/** -+ * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @in_data: Message received from the server -+ * @in_decrypted: Buffer for returning a pointer to the decrypted message -+ * Returns: 0 on success, 1 if more input data is needed, or -1 on failure -+ */ -+int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, -+ const struct wpabuf *in_data, -+ struct wpabuf **in_decrypted) -+{ -+ const struct wpabuf *msg; -+ int need_more_input; -+ -+ msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); -+ if (msg == NULL) -+ return need_more_input ? 1 : -1; -+ -+ *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg); -+ eap_peer_tls_reset_input(data); -+ if (*in_decrypted == NULL) { -+ wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * eap_peer_tls_encrypt - Encrypt phase 2 TLS message -+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() -+ * @data: Data for TLS processing -+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) -+ * @peap_version: Version number for EAP-PEAP/TTLS -+ * @id: EAP identifier for the response -+ * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments -+ * @out_data: Buffer for returning a pointer to the encrypted response message -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, -+ EapType eap_type, int peap_version, u8 id, -+ const struct wpabuf *in_data, -+ struct wpabuf **out_data) -+{ -+ if (in_data) { -+ eap_peer_tls_reset_output(data); -+ data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn, -+ in_data); -+ if (data->tls_out == NULL) { -+ wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " -+ "data (in_len=%lu)", -+ (unsigned long) wpabuf_len(in_data)); -+ eap_peer_tls_reset_output(data); -+ return -1; -+ } -+ } -+ -+ return eap_tls_process_output(data, eap_type, peap_version, id, 0, -+ out_data); -+} -+ -+ -+/** -+ * eap_peer_select_phase2_methods - Select phase 2 EAP method -+ * @config: Pointer to the network configuration -+ * @prefix: 'phase2' configuration prefix, e.g., "auth=" -+ * @types: Buffer for returning allocated list of allowed EAP methods -+ * @num_types: Buffer for returning number of allocated EAP methods -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to parse EAP method list and select allowed methods -+ * for Phase2 authentication. -+ */ -+int eap_peer_select_phase2_methods(struct eap_peer_config *config, -+ const char *prefix, -+ struct eap_method_type **types, -+ size_t *num_types) -+{ -+ char *start, *pos, *buf; -+ struct eap_method_type *methods = NULL, *_methods; -+ u8 method; -+ size_t num_methods = 0, prefix_len; -+ -+ if (config == NULL || config->phase2 == NULL) -+ goto get_defaults; -+ -+ start = buf = os_strdup(config->phase2); -+ if (buf == NULL) -+ return -1; -+ -+ prefix_len = os_strlen(prefix); -+ -+ while (start && *start != '\0') { -+ int vendor; -+ pos = os_strstr(start, prefix); -+ if (pos == NULL) -+ break; -+ if (start != pos && *(pos - 1) != ' ') { -+ start = pos + prefix_len; -+ continue; -+ } -+ -+ start = pos + prefix_len; -+ pos = os_strchr(start, ' '); -+ if (pos) -+ *pos++ = '\0'; -+ method = eap_get_phase2_type(start, &vendor); -+ if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { -+ wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " -+ "method '%s'", start); -+ } else { -+ num_methods++; -+ _methods = os_realloc(methods, -+ num_methods * sizeof(*methods)); -+ if (_methods == NULL) { -+ os_free(methods); -+ os_free(buf); -+ return -1; -+ } -+ methods = _methods; -+ methods[num_methods - 1].vendor = vendor; -+ methods[num_methods - 1].method = method; -+ } -+ -+ start = pos; -+ } -+ -+ os_free(buf); -+ -+get_defaults: -+ if (methods == NULL) -+ methods = eap_get_phase2_types(config, &num_methods); -+ -+ if (methods == NULL) { -+ wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", -+ (u8 *) methods, -+ num_methods * sizeof(struct eap_method_type)); -+ -+ *types = methods; -+ *num_types = num_methods; -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 -+ * @types: Buffer for returning allocated list of allowed EAP methods -+ * @num_types: Buffer for returning number of allocated EAP methods -+ * @hdr: EAP-Request header (and the following EAP type octet) -+ * @resp: Buffer for returning the EAP-Nak message -+ * Returns: 0 on success, -1 on failure -+ */ -+int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, -+ struct eap_hdr *hdr, struct wpabuf **resp) -+{ -+ u8 *pos = (u8 *) (hdr + 1); -+ size_t i; -+ -+ /* TODO: add support for expanded Nak */ -+ wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); -+ wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", -+ (u8 *) types, num_types * sizeof(struct eap_method_type)); -+ *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, -+ EAP_CODE_RESPONSE, hdr->identifier); -+ if (*resp == NULL) -+ return -1; -+ -+ for (i = 0; i < num_types; i++) { -+ if (types[i].vendor == EAP_VENDOR_IETF && -+ types[i].method < 256) -+ wpabuf_put_u8(*resp, types[i].method); -+ } -+ -+ eap_update_len(*resp); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.h -new file mode 100644 -index 0000000000000..e9e0998098ccb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tls_common.h -@@ -0,0 +1,126 @@ -+/* -+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_TLS_COMMON_H -+#define EAP_TLS_COMMON_H -+ -+/** -+ * struct eap_ssl_data - TLS data for EAP methods -+ */ -+struct eap_ssl_data { -+ /** -+ * conn - TLS connection context data from tls_connection_init() -+ */ -+ struct tls_connection *conn; -+ -+ /** -+ * tls_out - TLS message to be sent out in fragments -+ */ -+ struct wpabuf *tls_out; -+ -+ /** -+ * tls_out_pos - The current position in the outgoing TLS message -+ */ -+ size_t tls_out_pos; -+ -+ /** -+ * tls_out_limit - Maximum fragment size for outgoing TLS messages -+ */ -+ size_t tls_out_limit; -+ -+ /** -+ * tls_in - Received TLS message buffer for re-assembly -+ */ -+ struct wpabuf *tls_in; -+ -+ /** -+ * tls_in_left - Number of remaining bytes in the incoming TLS message -+ */ -+ size_t tls_in_left; -+ -+ /** -+ * tls_in_total - Total number of bytes in the incoming TLS message -+ */ -+ size_t tls_in_total; -+ -+ /** -+ * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) -+ */ -+ int phase2; -+ -+ /** -+ * include_tls_length - Whether the TLS length field is included even -+ * if the TLS data is not fragmented -+ */ -+ int include_tls_length; -+ -+ /** -+ * tls_ia - Whether TLS/IA is enabled for this TLS connection -+ */ -+ int tls_ia; -+ -+ /** -+ * eap - EAP state machine allocated with eap_peer_sm_init() -+ */ -+ struct eap_sm *eap; -+}; -+ -+ -+/* EAP TLS Flags */ -+#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 -+#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 -+#define EAP_TLS_FLAGS_START 0x20 -+#define EAP_TLS_VERSION_MASK 0x07 -+ -+ /* could be up to 128 bytes, but only the first 64 bytes are used */ -+#define EAP_TLS_KEY_LEN 64 -+ -+ -+int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, -+ struct eap_peer_config *config); -+void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); -+u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, -+ const char *label, size_t len); -+int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, -+ EapType eap_type, int peap_version, -+ u8 id, const u8 *in_data, size_t in_len, -+ struct wpabuf **out_data); -+struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, -+ int peap_version); -+int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data); -+int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, -+ char *buf, size_t buflen, int verbose); -+const u8 * eap_peer_tls_process_init(struct eap_sm *sm, -+ struct eap_ssl_data *data, -+ EapType eap_type, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData, -+ size_t *len, u8 *flags); -+void eap_peer_tls_reset_input(struct eap_ssl_data *data); -+void eap_peer_tls_reset_output(struct eap_ssl_data *data); -+int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, -+ const struct wpabuf *in_data, -+ struct wpabuf **in_decrypted); -+int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, -+ EapType eap_type, int peap_version, u8 id, -+ const struct wpabuf *in_data, -+ struct wpabuf **out_data); -+int eap_peer_select_phase2_methods(struct eap_peer_config *config, -+ const char *prefix, -+ struct eap_method_type **types, -+ size_t *num_types); -+int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, -+ struct eap_hdr *hdr, struct wpabuf **resp); -+ -+#endif /* EAP_TLS_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tnc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tnc.c -new file mode 100644 -index 0000000000000..6c95f72c15071 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_tnc.c -@@ -0,0 +1,434 @@ -+/* -+ * EAP peer method: EAP-TNC (Trusted Network Connect) -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "base64.h" -+#include "eap_i.h" -+#include "tncc.h" -+ -+ -+struct eap_tnc_data { -+ enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state; -+ struct tncc_data *tncc; -+ struct wpabuf *in_buf; -+ struct wpabuf *out_buf; -+ size_t out_used; -+ size_t fragment_size; -+}; -+ -+ -+/* EAP-TNC Flags */ -+#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80 -+#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40 -+#define EAP_TNC_FLAGS_START 0x20 -+#define EAP_TNC_VERSION_MASK 0x07 -+ -+#define EAP_TNC_VERSION 1 -+ -+ -+static void * eap_tnc_init(struct eap_sm *sm) -+{ -+ struct eap_tnc_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = WAIT_START; -+ data->fragment_size = 1300; -+ data->tncc = tncc_init(); -+ if (data->tncc == NULL) { -+ os_free(data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_tnc_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tnc_data *data = priv; -+ -+ wpabuf_free(data->in_buf); -+ wpabuf_free(data->out_buf); -+ tncc_deinit(data->tncc); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) -+{ -+ struct wpabuf *msg; -+ -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " -+ "for fragment ack"); -+ return NULL; -+ } -+ wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ -+ -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, -+ struct eap_method_ret *ret, u8 id) -+{ -+ struct wpabuf *resp; -+ u8 flags; -+ size_t send_len, plen; -+ -+ ret->ignore = FALSE; -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response"); -+ ret->allowNotifications = TRUE; -+ -+ flags = EAP_TNC_VERSION; -+ send_len = wpabuf_len(data->out_buf) - data->out_used; -+ if (1 + send_len > data->fragment_size) { -+ send_len = data->fragment_size - 1; -+ flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS; -+ if (data->out_used == 0) { -+ flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED; -+ send_len -= 4; -+ } -+ } -+ -+ plen = 1 + send_len; -+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) -+ plen += 4; -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, flags); /* Flags */ -+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) -+ wpabuf_put_be32(resp, wpabuf_len(data->out_buf)); -+ -+ wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, -+ send_len); -+ data->out_used += send_len; -+ -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ -+ if (data->out_used == wpabuf_len(data->out_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " -+ "(message sent completely)", -+ (unsigned long) send_len); -+ wpabuf_free(data->out_buf); -+ data->out_buf = NULL; -+ data->out_used = 0; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " -+ "(%lu more to send)", (unsigned long) send_len, -+ (unsigned long) wpabuf_len(data->out_buf) - -+ data->out_used); -+ data->state = WAIT_FRAG_ACK; -+ } -+ -+ return resp; -+} -+ -+ -+static int eap_tnc_process_cont(struct eap_tnc_data *data, -+ const u8 *buf, size_t len) -+{ -+ /* Process continuation of a pending message */ -+ if (len > wpabuf_tailroom(data->in_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); -+ data->state = FAIL; -+ return -1; -+ } -+ -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for " -+ "%lu bytes more", (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data, -+ struct eap_method_ret *ret, -+ u8 id, u8 flags, -+ u32 message_length, -+ const u8 *buf, size_t len) -+{ -+ /* Process a fragment that is not the last one of the message */ -+ if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a " -+ "fragmented packet"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* First fragment of the message */ -+ data->in_buf = wpabuf_alloc(message_length); -+ if (data->in_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for " -+ "message"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first " -+ "fragment, waiting for %lu bytes more", -+ (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ } -+ -+ return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE); -+} -+ -+ -+static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_tnc_data *data = priv; -+ struct wpabuf *resp; -+ const u8 *pos, *end; -+ u8 *rpos, *rpos1; -+ size_t len, rlen; -+ size_t imc_len; -+ char *start_buf, *end_buf; -+ size_t start_len, end_len; -+ int tncs_done = 0; -+ u8 flags, id; -+ u32 message_length = 0; -+ struct wpabuf tmpbuf; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len); -+ if (pos == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)", -+ pos, (unsigned long) len); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ id = eap_get_id(reqData); -+ -+ end = pos + len; -+ -+ if (len == 0) -+ flags = 0; /* fragment ack */ -+ else -+ flags = *pos++; -+ -+ if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", -+ flags & EAP_TNC_VERSION_MASK); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { -+ if (end - pos < 4) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ message_length = WPA_GET_BE32(pos); -+ pos += 4; -+ -+ if (message_length < (u32) (end - pos)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " -+ "Length (%d; %ld remaining in this msg)", -+ message_length, (long) (end - pos)); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " -+ "Message Length %u", flags, message_length); -+ -+ if (data->state == WAIT_FRAG_ACK) { -+ if (len > 1) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in " -+ "WAIT_FRAG_ACK state"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); -+ data->state = PROC_MSG; -+ return eap_tnc_build_msg(data, ret, id); -+ } -+ -+ if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { -+ return eap_tnc_process_fragment(data, ret, id, flags, -+ message_length, pos, -+ end - pos); -+ } -+ -+ if (data->in_buf == NULL) { -+ /* Wrap unfragmented messages as wpabuf without extra copy */ -+ wpabuf_set(&tmpbuf, pos, end - pos); -+ data->in_buf = &tmpbuf; -+ } -+ -+ if (data->state == WAIT_START) { -+ if (!(flags & EAP_TNC_FLAGS_START)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use " -+ "start flag in the first message"); -+ ret->ignore = TRUE; -+ goto fail; -+ } -+ -+ tncc_init_connection(data->tncc); -+ -+ data->state = PROC_MSG; -+ } else { -+ enum tncc_process_res res; -+ -+ if (flags & EAP_TNC_FLAGS_START) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start " -+ "flag again"); -+ ret->ignore = TRUE; -+ goto fail; -+ } -+ -+ res = tncc_process_if_tnccs(data->tncc, -+ wpabuf_head(data->in_buf), -+ wpabuf_len(data->in_buf)); -+ switch (res) { -+ case TNCCS_PROCESS_ERROR: -+ ret->ignore = TRUE; -+ goto fail; -+ case TNCCS_PROCESS_OK_NO_RECOMMENDATION: -+ case TNCCS_RECOMMENDATION_ERROR: -+ wpa_printf(MSG_DEBUG, "EAP-TNC: No " -+ "TNCCS-Recommendation received"); -+ break; -+ case TNCCS_RECOMMENDATION_ALLOW: -+ wpa_msg(sm->msg_ctx, MSG_INFO, -+ "TNC: Recommendation = allow"); -+ tncs_done = 1; -+ break; -+ case TNCCS_RECOMMENDATION_NONE: -+ wpa_msg(sm->msg_ctx, MSG_INFO, -+ "TNC: Recommendation = none"); -+ tncs_done = 1; -+ break; -+ case TNCCS_RECOMMENDATION_ISOLATE: -+ wpa_msg(sm->msg_ctx, MSG_INFO, -+ "TNC: Recommendation = isolate"); -+ tncs_done = 1; -+ break; -+ } -+ } -+ -+ if (data->in_buf != &tmpbuf) -+ wpabuf_free(data->in_buf); -+ data->in_buf = NULL; -+ -+ ret->ignore = FALSE; -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_UNCOND_SUCC; -+ ret->allowNotifications = TRUE; -+ -+ if (data->out_buf) { -+ data->state = PROC_MSG; -+ return eap_tnc_build_msg(data, ret, id); -+ } -+ -+ if (tncs_done) { -+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, EAP_TNC_VERSION); -+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an " -+ "empty ACK message"); -+ return resp; -+ } -+ -+ imc_len = tncc_total_send_len(data->tncc); -+ -+ start_buf = tncc_if_tnccs_start(data->tncc); -+ if (start_buf == NULL) -+ return NULL; -+ start_len = os_strlen(start_buf); -+ end_buf = tncc_if_tnccs_end(); -+ if (end_buf == NULL) { -+ os_free(start_buf); -+ return NULL; -+ } -+ end_len = os_strlen(end_buf); -+ -+ rlen = start_len + imc_len + end_len; -+ resp = wpabuf_alloc(rlen); -+ if (resp == NULL) { -+ os_free(start_buf); -+ os_free(end_buf); -+ return NULL; -+ } -+ -+ wpabuf_put_data(resp, start_buf, start_len); -+ os_free(start_buf); -+ -+ rpos1 = wpabuf_put(resp, 0); -+ rpos = tncc_copy_send_buf(data->tncc, rpos1); -+ wpabuf_put(resp, rpos - rpos1); -+ -+ wpabuf_put_data(resp, end_buf, end_len); -+ os_free(end_buf); -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response", -+ wpabuf_head(resp), wpabuf_len(resp)); -+ -+ data->out_buf = resp; -+ data->state = PROC_MSG; -+ return eap_tnc_build_msg(data, ret, id); -+ -+fail: -+ if (data->in_buf == &tmpbuf) -+ data->in_buf = NULL; -+ return NULL; -+} -+ -+ -+int eap_peer_tnc_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_tnc_init; -+ eap->deinit = eap_tnc_deinit; -+ eap->process = eap_tnc_process; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ttls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ttls.c -new file mode 100644 -index 0000000000000..e8f0f38f04538 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_ttls.c -@@ -0,0 +1,1986 @@ -+/* -+ * EAP peer method: EAP-TTLS (RFC 5281) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/ms_funcs.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "eap_common/chap.h" -+#include "eap_common/eap_ttls.h" -+#include "mschapv2.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+#include "eap_config.h" -+ -+ -+/* Maximum supported TTLS version -+ * 0 = RFC 5281 -+ * 1 = draft-funk-eap-ttls-v1-00.txt -+ */ -+#ifndef EAP_TTLS_VERSION -+#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ -+#endif /* EAP_TTLS_VERSION */ -+ -+ -+#define MSCHAPV2_KEY_LEN 16 -+#define MSCHAPV2_NT_RESPONSE_LEN 24 -+ -+ -+static void eap_ttls_deinit(struct eap_sm *sm, void *priv); -+ -+ -+struct eap_ttls_data { -+ struct eap_ssl_data ssl; -+ int ssl_initialized; -+ -+ int ttls_version, force_ttls_version; -+ -+ const struct eap_method *phase2_method; -+ void *phase2_priv; -+ int phase2_success; -+ int phase2_start; -+ -+ enum phase2_types { -+ EAP_TTLS_PHASE2_EAP, -+ EAP_TTLS_PHASE2_MSCHAPV2, -+ EAP_TTLS_PHASE2_MSCHAP, -+ EAP_TTLS_PHASE2_PAP, -+ EAP_TTLS_PHASE2_CHAP -+ } phase2_type; -+ struct eap_method_type phase2_eap_type; -+ struct eap_method_type *phase2_eap_types; -+ size_t num_phase2_eap_types; -+ -+ u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; -+ int auth_response_valid; -+ u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ -+ u8 ident; -+ int resuming; /* starting a resumed session */ -+ int reauth; /* reauthentication */ -+ u8 *key_data; -+ -+ struct wpabuf *pending_phase2_req; -+ -+#ifdef EAP_TNC -+ int ready_for_tnc; -+ int tnc_started; -+#endif /* EAP_TNC */ -+}; -+ -+ -+static void * eap_ttls_init(struct eap_sm *sm) -+{ -+ struct eap_ttls_data *data; -+ struct eap_peer_config *config = eap_get_config(sm); -+ char *selected; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->ttls_version = EAP_TTLS_VERSION; -+ data->force_ttls_version = -1; -+ selected = "EAP"; -+ data->phase2_type = EAP_TTLS_PHASE2_EAP; -+ -+#if EAP_TTLS_VERSION > 0 -+ if (config && config->phase1) { -+ const char *pos = os_strstr(config->phase1, "ttlsver="); -+ if (pos) { -+ data->force_ttls_version = atoi(pos + 8); -+ data->ttls_version = data->force_ttls_version; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version " -+ "%d", data->force_ttls_version); -+ } -+ } -+#endif /* EAP_TTLS_VERSION */ -+ -+ if (config && config->phase2) { -+ if (os_strstr(config->phase2, "autheap=")) { -+ selected = "EAP"; -+ data->phase2_type = EAP_TTLS_PHASE2_EAP; -+ } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { -+ selected = "MSCHAPV2"; -+ data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; -+ } else if (os_strstr(config->phase2, "auth=MSCHAP")) { -+ selected = "MSCHAP"; -+ data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; -+ } else if (os_strstr(config->phase2, "auth=PAP")) { -+ selected = "PAP"; -+ data->phase2_type = EAP_TTLS_PHASE2_PAP; -+ } else if (os_strstr(config->phase2, "auth=CHAP")) { -+ selected = "CHAP"; -+ data->phase2_type = EAP_TTLS_PHASE2_CHAP; -+ } -+ } -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); -+ -+ if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { -+ if (eap_peer_select_phase2_methods(config, "autheap=", -+ &data->phase2_eap_types, -+ &data->num_phase2_eap_types) -+ < 0) { -+ eap_ttls_deinit(sm, data); -+ return NULL; -+ } -+ -+ data->phase2_eap_type.vendor = EAP_VENDOR_IETF; -+ data->phase2_eap_type.method = EAP_TYPE_NONE; -+ } -+ -+#if EAP_TTLS_VERSION > 0 -+ if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && -+ data->ttls_version > 0) { -+ if (data->force_ttls_version > 0) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " -+ "TLS library does not support TLS/IA.", -+ data->force_ttls_version); -+ eap_ttls_deinit(sm, data); -+ return NULL; -+ } -+ data->ttls_version = 0; -+ } -+#endif /* EAP_TTLS_VERSION */ -+ -+ return data; -+} -+ -+ -+static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, -+ struct eap_ttls_data *data) -+{ -+ if (data->phase2_priv && data->phase2_method) { -+ data->phase2_method->deinit(sm, data->phase2_priv); -+ data->phase2_method = NULL; -+ data->phase2_priv = NULL; -+ } -+} -+ -+ -+static void eap_ttls_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ if (data == NULL) -+ return; -+ eap_ttls_phase2_eap_deinit(sm, data); -+ os_free(data->phase2_eap_types); -+ if (data->ssl_initialized) -+ eap_peer_tls_ssl_deinit(sm, &data->ssl); -+ os_free(data->key_data); -+ wpabuf_free(data->pending_phase2_req); -+ os_free(data); -+} -+ -+ -+static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, -+ int mandatory, size_t len) -+{ -+ struct ttls_avp_vendor *avp; -+ u8 flags; -+ size_t hdrlen; -+ -+ avp = (struct ttls_avp_vendor *) avphdr; -+ flags = mandatory ? AVP_FLAGS_MANDATORY : 0; -+ if (vendor_id) { -+ flags |= AVP_FLAGS_VENDOR; -+ hdrlen = sizeof(*avp); -+ avp->vendor_id = host_to_be32(vendor_id); -+ } else { -+ hdrlen = sizeof(struct ttls_avp); -+ } -+ -+ avp->avp_code = host_to_be32(avp_code); -+ avp->avp_length = host_to_be32((flags << 24) | (u32) (hdrlen + len)); -+ -+ return avphdr + hdrlen; -+} -+ -+ -+static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code, -+ u32 vendor_id, int mandatory, -+ const u8 *data, size_t len) -+{ -+ u8 *pos; -+ pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len); -+ os_memcpy(pos, data, len); -+ pos += len; -+ AVP_PAD(start, pos); -+ return pos; -+} -+ -+ -+static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, -+ int mandatory) -+{ -+ struct wpabuf *msg; -+ u8 *avp, *pos; -+ -+ msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4); -+ if (msg == NULL) { -+ wpabuf_free(*resp); -+ *resp = NULL; -+ return -1; -+ } -+ -+ avp = wpabuf_mhead(msg); -+ pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp)); -+ os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp)); -+ pos += wpabuf_len(*resp); -+ AVP_PAD(avp, pos); -+ wpabuf_free(*resp); -+ wpabuf_put(msg, pos - avp); -+ *resp = msg; -+ return 0; -+} -+ -+ -+#if EAP_TTLS_VERSION > 0 -+static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ const u8 *key, size_t key_len) -+{ -+ u8 *buf; -+ size_t buf_len; -+ int ret; -+ -+ if (key) { -+ buf_len = 2 + key_len; -+ buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return -1; -+ WPA_PUT_BE16(buf, key_len); -+ os_memcpy(buf + 2, key, key_len); -+ } else { -+ buf = NULL; -+ buf_len = 0; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " -+ "secret permutation", buf, buf_len); -+ ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, -+ data->ssl.conn, -+ buf, buf_len); -+ os_free(buf); -+ -+ return ret; -+} -+#endif /* EAP_TTLS_VERSION */ -+ -+ -+static int eap_ttls_v0_derive_key(struct eap_sm *sm, -+ struct eap_ttls_data *data) -+{ -+ os_free(data->key_data); -+ data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, -+ "ttls keying material", -+ EAP_TLS_KEY_LEN); -+ if (!data->key_data) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); -+ return -1; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", -+ data->key_data, EAP_TLS_KEY_LEN); -+ -+ return 0; -+} -+ -+ -+#if EAP_TTLS_VERSION > 0 -+static int eap_ttls_v1_derive_key(struct eap_sm *sm, -+ struct eap_ttls_data *data) -+{ -+ struct tls_keys keys; -+ u8 *rnd; -+ -+ os_free(data->key_data); -+ data->key_data = NULL; -+ -+ os_memset(&keys, 0, sizeof(keys)); -+ if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || -+ keys.client_random == NULL || keys.server_random == NULL || -+ keys.inner_secret == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " -+ "client random, or server random to derive keying " -+ "material"); -+ return -1; -+ } -+ -+ rnd = os_malloc(keys.client_random_len + keys.server_random_len); -+ data->key_data = os_malloc(EAP_TLS_KEY_LEN); -+ if (rnd == NULL || data->key_data == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); -+ os_free(rnd); -+ os_free(data->key_data); -+ data->key_data = NULL; -+ return -1; -+ } -+ os_memcpy(rnd, keys.client_random, keys.client_random_len); -+ os_memcpy(rnd + keys.client_random_len, keys.server_random, -+ keys.server_random_len); -+ -+ if (tls_prf(keys.inner_secret, keys.inner_secret_len, -+ "ttls v1 keying material", rnd, keys.client_random_len + -+ keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); -+ os_free(rnd); -+ os_free(data->key_data); -+ data->key_data = NULL; -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", -+ rnd, keys.client_random_len + keys.server_random_len); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", -+ keys.inner_secret, keys.inner_secret_len); -+ -+ os_free(rnd); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", -+ data->key_data, EAP_TLS_KEY_LEN); -+ -+ return 0; -+} -+#endif /* EAP_TTLS_VERSION */ -+ -+ -+static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, -+ struct eap_ttls_data *data, size_t len) -+{ -+#if EAP_TTLS_VERSION > 0 -+ struct tls_keys keys; -+ u8 *challenge, *rnd; -+#endif /* EAP_TTLS_VERSION */ -+ -+ if (data->ttls_version == 0) { -+ return eap_peer_tls_derive_key(sm, &data->ssl, -+ "ttls challenge", len); -+ } -+ -+#if EAP_TTLS_VERSION > 0 -+ -+ os_memset(&keys, 0, sizeof(keys)); -+ if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || -+ keys.client_random == NULL || keys.server_random == NULL || -+ keys.inner_secret == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " -+ "client random, or server random to derive " -+ "implicit challenge"); -+ return NULL; -+ } -+ -+ rnd = os_malloc(keys.client_random_len + keys.server_random_len); -+ challenge = os_malloc(len); -+ if (rnd == NULL || challenge == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " -+ "challenge derivation"); -+ os_free(rnd); -+ os_free(challenge); -+ return NULL; -+ } -+ os_memcpy(rnd, keys.server_random, keys.server_random_len); -+ os_memcpy(rnd + keys.server_random_len, keys.client_random, -+ keys.client_random_len); -+ -+ if (tls_prf(keys.inner_secret, keys.inner_secret_len, -+ "inner application challenge", rnd, -+ keys.client_random_len + keys.server_random_len, -+ challenge, len)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " -+ "challenge"); -+ os_free(rnd); -+ os_free(challenge); -+ return NULL; -+ } -+ -+ os_free(rnd); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", -+ challenge, len); -+ -+ return challenge; -+ -+#else /* EAP_TTLS_VERSION */ -+ -+ return NULL; -+ -+#endif /* EAP_TTLS_VERSION */ -+} -+ -+ -+static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret) -+{ -+#if EAP_TTLS_VERSION > 0 -+ if (data->ttls_version > 0) { -+ const struct eap_method *m = data->phase2_method; -+ void *priv = data->phase2_priv; -+ -+ /* TTLSv1 requires TLS/IA FinalPhaseFinished */ -+ if (ret->decision == DECISION_UNCOND_SUCC) -+ ret->decision = DECISION_COND_SUCC; -+ ret->methodState = METHOD_CONT; -+ -+ if (ret->decision == DECISION_COND_SUCC && -+ m->isKeyAvailable && m->getKey && -+ m->isKeyAvailable(sm, priv)) { -+ u8 *key; -+ size_t key_len; -+ key = m->getKey(sm, priv, &key_len); -+ if (key) { -+ eap_ttls_ia_permute_inner_secret( -+ sm, data, key, key_len); -+ os_free(key); -+ } -+ } -+ } -+#endif /* EAP_TTLS_VERSION */ -+} -+ -+ -+static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, -+ u8 method) -+{ -+ size_t i; -+ for (i = 0; i < data->num_phase2_eap_types; i++) { -+ if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF || -+ data->phase2_eap_types[i].method != method) -+ continue; -+ -+ data->phase2_eap_type.vendor = -+ data->phase2_eap_types[i].vendor; -+ data->phase2_eap_type.method = -+ data->phase2_eap_types[i].method; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " -+ "Phase 2 EAP vendor %d method %d", -+ data->phase2_eap_type.vendor, -+ data->phase2_eap_type.method); -+ break; -+ } -+} -+ -+ -+static int eap_ttls_phase2_eap_process(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct eap_hdr *hdr, size_t len, -+ struct wpabuf **resp) -+{ -+ struct wpabuf msg; -+ struct eap_method_ret iret; -+ -+ os_memset(&iret, 0, sizeof(iret)); -+ wpabuf_set(&msg, hdr, len); -+ *resp = data->phase2_method->process(sm, data->phase2_priv, &iret, -+ &msg); -+ if ((iret.methodState == METHOD_DONE || -+ iret.methodState == METHOD_MAY_CONT) && -+ (iret.decision == DECISION_UNCOND_SUCC || -+ iret.decision == DECISION_COND_SUCC || -+ iret.decision == DECISION_FAIL)) { -+ ret->methodState = iret.methodState; -+ ret->decision = iret.decision; -+ } -+ eap_ttlsv1_phase2_eap_finish(sm, data, ret); -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct eap_hdr *hdr, size_t len, -+ u8 method, struct wpabuf **resp) -+{ -+#ifdef EAP_TNC -+ if (data->tnc_started && data->phase2_method && -+ data->phase2_priv && method == EAP_TYPE_TNC && -+ data->phase2_eap_type.method == EAP_TYPE_TNC) -+ return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, -+ resp); -+ -+ if (data->ready_for_tnc && !data->tnc_started && -+ method == EAP_TYPE_TNC) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " -+ "EAP method"); -+ data->tnc_started = 1; -+ } -+ -+ if (data->tnc_started) { -+ if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF || -+ data->phase2_eap_type.method == EAP_TYPE_TNC) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP " -+ "type %d for TNC", method); -+ return -1; -+ } -+ -+ data->phase2_eap_type.vendor = EAP_VENDOR_IETF; -+ data->phase2_eap_type.method = method; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected " -+ "Phase 2 EAP vendor %d method %d (TNC)", -+ data->phase2_eap_type.vendor, -+ data->phase2_eap_type.method); -+ -+ if (data->phase2_type == EAP_TTLS_PHASE2_EAP) -+ eap_ttls_phase2_eap_deinit(sm, data); -+ } -+#endif /* EAP_TNC */ -+ -+ if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF && -+ data->phase2_eap_type.method == EAP_TYPE_NONE) -+ eap_ttls_phase2_select_eap_method(data, method); -+ -+ if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE) -+ { -+ if (eap_peer_tls_phase2_nak(data->phase2_eap_types, -+ data->num_phase2_eap_types, -+ hdr, resp)) -+ return -1; -+ return 0; -+ } -+ -+ if (data->phase2_priv == NULL) { -+ data->phase2_method = eap_peer_get_eap_method( -+ EAP_VENDOR_IETF, method); -+ if (data->phase2_method) { -+ sm->init_phase2 = 1; -+ data->phase2_priv = data->phase2_method->init(sm); -+ sm->init_phase2 = 0; -+ } -+ } -+ if (data->phase2_priv == NULL || data->phase2_method == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize " -+ "Phase 2 EAP method %d", method); -+ return -1; -+ } -+ -+ return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp); -+} -+ -+ -+static int eap_ttls_phase2_request_eap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct eap_hdr *hdr, -+ struct wpabuf **resp) -+{ -+ size_t len = be_to_host16(hdr->length); -+ u8 *pos; -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ if (len <= sizeof(struct eap_hdr)) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: too short " -+ "Phase 2 request (len=%lu)", (unsigned long) len); -+ return -1; -+ } -+ pos = (u8 *) (hdr + 1); -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos); -+ switch (*pos) { -+ case EAP_TYPE_IDENTITY: -+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); -+ break; -+ default: -+ if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len, -+ *pos, resp) < 0) -+ return -1; -+ break; -+ } -+ -+ if (*resp == NULL && -+ (config->pending_req_identity || config->pending_req_password || -+ config->pending_req_otp)) { -+ return 0; -+ } -+ -+ if (*resp == NULL) -+ return -1; -+ -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response", -+ *resp); -+ return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1); -+} -+ -+ -+static void eap_ttlsv1_permute_inner(struct eap_sm *sm, -+ struct eap_ttls_data *data) -+{ -+#if EAP_TTLS_VERSION > 0 -+ u8 session_key[2 * MSCHAPV2_KEY_LEN]; -+ -+ if (data->ttls_version == 0) -+ return; -+ -+ get_asymetric_start_key(data->master_key, session_key, -+ MSCHAPV2_KEY_LEN, 0, 0); -+ get_asymetric_start_key(data->master_key, -+ session_key + MSCHAPV2_KEY_LEN, -+ MSCHAPV2_KEY_LEN, 1, 0); -+ eap_ttls_ia_permute_inner_secret(sm, data, session_key, -+ sizeof(session_key)); -+#endif /* EAP_TTLS_VERSION */ -+} -+ -+ -+static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct wpabuf **resp) -+{ -+ struct wpabuf *msg; -+ u8 *buf, *pos, *challenge, *peer_challenge; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ int pwhash; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request"); -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ password = eap_get_config_password2(sm, &password_len, &pwhash); -+ if (identity == NULL || password == NULL) -+ return -1; -+ -+ msg = wpabuf_alloc(identity_len + 1000); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, -+ "EAP-TTLS/MSCHAPV2: Failed to allocate memory"); -+ return -1; -+ } -+ pos = buf = wpabuf_mhead(msg); -+ -+ /* User-Name */ -+ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, -+ identity, identity_len); -+ -+ /* MS-CHAP-Challenge */ -+ challenge = eap_ttls_implicit_challenge( -+ sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); -+ if (challenge == NULL) { -+ wpabuf_free(msg); -+ wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " -+ "implicit challenge"); -+ return -1; -+ } -+ peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; -+ -+ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, -+ RADIUS_VENDOR_ID_MICROSOFT, 1, -+ challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); -+ -+ /* MS-CHAP2-Response */ -+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE, -+ RADIUS_VENDOR_ID_MICROSOFT, 1, -+ EAP_TTLS_MSCHAPV2_RESPONSE_LEN); -+ data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]; -+ *pos++ = data->ident; -+ *pos++ = 0; /* Flags */ -+ os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); -+ pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; -+ os_memset(pos, 0, 8); /* Reserved, must be zero */ -+ pos += 8; -+ if (mschapv2_derive_response(identity, identity_len, password, -+ password_len, pwhash, challenge, -+ peer_challenge, pos, data->auth_response, -+ data->master_key)) { -+ wpabuf_free(msg); -+ wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive " -+ "response"); -+ return -1; -+ } -+ data->auth_response_valid = 1; -+ -+ eap_ttlsv1_permute_inner(sm, data); -+ -+ pos += 24; -+ os_free(challenge); -+ AVP_PAD(buf, pos); -+ -+ wpabuf_put(msg, pos - buf); -+ *resp = msg; -+ -+ if (sm->workaround && data->ttls_version == 0) { -+ /* At least FreeRADIUS seems to be terminating -+ * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success -+ * packet. */ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " -+ "allow success without tunneled response"); -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_COND_SUCC; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct wpabuf **resp) -+{ -+ struct wpabuf *msg; -+ u8 *buf, *pos, *challenge; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ int pwhash; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ password = eap_get_config_password2(sm, &password_len, &pwhash); -+ if (identity == NULL || password == NULL) -+ return -1; -+ -+ msg = wpabuf_alloc(identity_len + 1000); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, -+ "EAP-TTLS/MSCHAP: Failed to allocate memory"); -+ return -1; -+ } -+ pos = buf = wpabuf_mhead(msg); -+ -+ /* User-Name */ -+ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, -+ identity, identity_len); -+ -+ /* MS-CHAP-Challenge */ -+ challenge = eap_ttls_implicit_challenge( -+ sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); -+ if (challenge == NULL) { -+ wpabuf_free(msg); -+ wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " -+ "implicit challenge"); -+ return -1; -+ } -+ -+ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, -+ RADIUS_VENDOR_ID_MICROSOFT, 1, -+ challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); -+ -+ /* MS-CHAP-Response */ -+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, -+ RADIUS_VENDOR_ID_MICROSOFT, 1, -+ EAP_TTLS_MSCHAP_RESPONSE_LEN); -+ data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; -+ *pos++ = data->ident; -+ *pos++ = 1; /* Flags: Use NT style passwords */ -+ os_memset(pos, 0, 24); /* LM-Response */ -+ pos += 24; -+ if (pwhash) { -+ challenge_response(challenge, password, pos); /* NT-Response */ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", -+ password, 16); -+ } else { -+ nt_challenge_response(challenge, password, password_len, -+ pos); /* NT-Response */ -+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", -+ password, password_len); -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", -+ challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); -+ pos += 24; -+ os_free(challenge); -+ AVP_PAD(buf, pos); -+ -+ wpabuf_put(msg, pos - buf); -+ *resp = msg; -+ -+ if (data->ttls_version > 0) { -+ /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, -+ * so do not allow connection to be terminated yet. */ -+ ret->methodState = METHOD_CONT; -+ ret->decision = DECISION_COND_SUCC; -+ } else { -+ /* EAP-TTLS/MSCHAP does not provide tunneled success -+ * notification, so assume that Phase2 succeeds. */ -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_COND_SUCC; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_phase2_request_pap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct wpabuf **resp) -+{ -+ struct wpabuf *msg; -+ u8 *buf, *pos; -+ size_t pad; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ password = eap_get_config_password(sm, &password_len); -+ if (identity == NULL || password == NULL) -+ return -1; -+ -+ msg = wpabuf_alloc(identity_len + password_len + 100); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, -+ "EAP-TTLS/PAP: Failed to allocate memory"); -+ return -1; -+ } -+ pos = buf = wpabuf_mhead(msg); -+ -+ /* User-Name */ -+ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, -+ identity, identity_len); -+ -+ /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts -+ * the data, so no separate encryption is used in the AVP itself. -+ * However, the password is padded to obfuscate its length. */ -+ pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; -+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, -+ password_len + pad); -+ os_memcpy(pos, password, password_len); -+ pos += password_len; -+ os_memset(pos, 0, pad); -+ pos += pad; -+ AVP_PAD(buf, pos); -+ -+ wpabuf_put(msg, pos - buf); -+ *resp = msg; -+ -+ if (data->ttls_version > 0) { -+ /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, -+ * so do not allow connection to be terminated yet. */ -+ ret->methodState = METHOD_CONT; -+ ret->decision = DECISION_COND_SUCC; -+ } else { -+ /* EAP-TTLS/PAP does not provide tunneled success notification, -+ * so assume that Phase2 succeeds. */ -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_COND_SUCC; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_phase2_request_chap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct wpabuf **resp) -+{ -+ struct wpabuf *msg; -+ u8 *buf, *pos, *challenge; -+ const u8 *identity, *password; -+ size_t identity_len, password_len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ password = eap_get_config_password(sm, &password_len); -+ if (identity == NULL || password == NULL) -+ return -1; -+ -+ msg = wpabuf_alloc(identity_len + 1000); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, -+ "EAP-TTLS/CHAP: Failed to allocate memory"); -+ return -1; -+ } -+ pos = buf = wpabuf_mhead(msg); -+ -+ /* User-Name */ -+ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, -+ identity, identity_len); -+ -+ /* CHAP-Challenge */ -+ challenge = eap_ttls_implicit_challenge( -+ sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); -+ if (challenge == NULL) { -+ wpabuf_free(msg); -+ wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " -+ "implicit challenge"); -+ return -1; -+ } -+ -+ pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, -+ challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); -+ -+ /* CHAP-Password */ -+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, -+ 1 + EAP_TTLS_CHAP_PASSWORD_LEN); -+ data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; -+ *pos++ = data->ident; -+ -+ /* MD5(Ident + Password + Challenge) */ -+ chap_md5(data->ident, password, password_len, challenge, -+ EAP_TTLS_CHAP_CHALLENGE_LEN, pos); -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", -+ identity, identity_len); -+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", -+ password, password_len); -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", -+ challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", -+ pos, EAP_TTLS_CHAP_PASSWORD_LEN); -+ pos += EAP_TTLS_CHAP_PASSWORD_LEN; -+ os_free(challenge); -+ AVP_PAD(buf, pos); -+ -+ wpabuf_put(msg, pos - buf); -+ *resp = msg; -+ -+ if (data->ttls_version > 0) { -+ /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, -+ * so do not allow connection to be terminated yet. */ -+ ret->methodState = METHOD_CONT; -+ ret->decision = DECISION_COND_SUCC; -+ } else { -+ /* EAP-TTLS/CHAP does not provide tunneled success -+ * notification, so assume that Phase2 succeeds. */ -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_COND_SUCC; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_phase2_request(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct eap_hdr *hdr, -+ struct wpabuf **resp) -+{ -+ int res = 0; -+ size_t len; -+ enum phase2_types phase2_type = data->phase2_type; -+ -+#ifdef EAP_TNC -+ if (data->tnc_started) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); -+ phase2_type = EAP_TTLS_PHASE2_EAP; -+ } -+#endif /* EAP_TNC */ -+ -+ if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || -+ phase2_type == EAP_TTLS_PHASE2_MSCHAP || -+ phase2_type == EAP_TTLS_PHASE2_PAP || -+ phase2_type == EAP_TTLS_PHASE2_CHAP) { -+ if (eap_get_config_identity(sm, &len) == NULL) { -+ wpa_printf(MSG_INFO, -+ "EAP-TTLS: Identity not configured"); -+ eap_sm_request_identity(sm); -+ if (eap_get_config_password(sm, &len) == NULL) -+ eap_sm_request_password(sm); -+ return 0; -+ } -+ -+ if (eap_get_config_password(sm, &len) == NULL) { -+ wpa_printf(MSG_INFO, -+ "EAP-TTLS: Password not configured"); -+ eap_sm_request_password(sm); -+ return 0; -+ } -+ } -+ -+ switch (phase2_type) { -+ case EAP_TTLS_PHASE2_EAP: -+ res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); -+ break; -+ case EAP_TTLS_PHASE2_MSCHAPV2: -+ res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); -+ break; -+ case EAP_TTLS_PHASE2_MSCHAP: -+ res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); -+ break; -+ case EAP_TTLS_PHASE2_PAP: -+ res = eap_ttls_phase2_request_pap(sm, data, ret, resp); -+ break; -+ case EAP_TTLS_PHASE2_CHAP: -+ res = eap_ttls_phase2_request_chap(sm, data, ret, resp); -+ break; -+ default: -+ wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); -+ res = -1; -+ break; -+ } -+ -+ if (res < 0) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ } -+ -+ return res; -+} -+ -+ -+#if EAP_TTLS_VERSION > 0 -+static struct wpabuf * eap_ttls_build_phase_finished( -+ struct eap_sm *sm, struct eap_ttls_data *data, int id, int final) -+{ -+ struct wpabuf *req, *buf; -+ -+ buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx, -+ data->ssl.conn, -+ final); -+ if (buf == NULL) -+ return NULL; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, -+ 1 + wpabuf_len(buf), -+ EAP_CODE_RESPONSE, id); -+ if (req == NULL) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, data->ttls_version); -+ wpabuf_put_buf(req, buf); -+ wpabuf_free(buf); -+ eap_update_len(req); -+ -+ return req; -+} -+#endif /* EAP_TTLS_VERSION */ -+ -+ -+struct ttls_parse_avp { -+ u8 *mschapv2; -+ u8 *eapdata; -+ size_t eap_len; -+ int mschapv2_error; -+}; -+ -+ -+static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen, -+ struct ttls_parse_avp *parse) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); -+ if (parse->eapdata == NULL) { -+ parse->eapdata = os_malloc(dlen); -+ if (parse->eapdata == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " -+ "memory for Phase 2 EAP data"); -+ return -1; -+ } -+ os_memcpy(parse->eapdata, dpos, dlen); -+ parse->eap_len = dlen; -+ } else { -+ u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen); -+ if (neweap == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate " -+ "memory for Phase 2 EAP data"); -+ return -1; -+ } -+ os_memcpy(neweap + parse->eap_len, dpos, dlen); -+ parse->eapdata = neweap; -+ parse->eap_len += dlen; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_parse_avp(u8 *pos, size_t left, -+ struct ttls_parse_avp *parse) -+{ -+ struct ttls_avp *avp; -+ u32 avp_code, avp_length, vendor_id = 0; -+ u8 avp_flags, *dpos; -+ size_t dlen; -+ -+ avp = (struct ttls_avp *) pos; -+ avp_code = be_to_host32(avp->avp_code); -+ avp_length = be_to_host32(avp->avp_length); -+ avp_flags = (avp_length >> 24) & 0xff; -+ avp_length &= 0xffffff; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " -+ "length=%d", (int) avp_code, avp_flags, -+ (int) avp_length); -+ -+ if (avp_length > left) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " -+ "(len=%d, left=%lu) - dropped", -+ (int) avp_length, (unsigned long) left); -+ return -1; -+ } -+ -+ if (avp_length < sizeof(*avp)) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d", -+ avp_length); -+ return -1; -+ } -+ -+ dpos = (u8 *) (avp + 1); -+ dlen = avp_length - sizeof(*avp); -+ if (avp_flags & AVP_FLAGS_VENDOR) { -+ if (dlen < 4) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP " -+ "underflow"); -+ return -1; -+ } -+ vendor_id = WPA_GET_BE32(dpos); -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", -+ (int) vendor_id); -+ dpos += 4; -+ dlen -= 4; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); -+ -+ if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { -+ if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0) -+ return -1; -+ } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) { -+ /* This is an optional message that can be displayed to -+ * the user. */ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message", -+ dpos, dlen); -+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && -+ avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success", -+ dpos, dlen); -+ if (dlen != 43) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected " -+ "MS-CHAP2-Success length " -+ "(len=%lu, expected 43)", -+ (unsigned long) dlen); -+ return -1; -+ } -+ parse->mschapv2 = dpos; -+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && -+ avp_code == RADIUS_ATTR_MS_CHAP_ERROR) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error", -+ dpos, dlen); -+ parse->mschapv2_error = 1; -+ } else if (avp_flags & AVP_FLAGS_MANDATORY) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP " -+ "code %d vendor_id %d - dropped", -+ (int) avp_code, (int) vendor_id); -+ return -1; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP " -+ "code %d vendor_id %d", -+ (int) avp_code, (int) vendor_id); -+ } -+ -+ return avp_length; -+} -+ -+ -+static int eap_ttls_parse_avps(struct wpabuf *in_decrypted, -+ struct ttls_parse_avp *parse) -+{ -+ u8 *pos; -+ size_t left, pad; -+ int avp_length; -+ -+ pos = wpabuf_mhead(in_decrypted); -+ left = wpabuf_len(in_decrypted); -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left); -+ if (left < sizeof(struct ttls_avp)) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame" -+ " len=%lu expected %lu or more - dropped", -+ (unsigned long) left, -+ (unsigned long) sizeof(struct ttls_avp)); -+ return -1; -+ } -+ -+ /* Parse AVPs */ -+ os_memset(parse, 0, sizeof(*parse)); -+ -+ while (left > 0) { -+ avp_length = eap_ttls_parse_avp(pos, left, parse); -+ if (avp_length < 0) -+ return -1; -+ -+ pad = (4 - (avp_length & 3)) & 3; -+ pos += avp_length + pad; -+ if (left < avp_length + pad) -+ left = 0; -+ else -+ left -= avp_length + pad; -+ } -+ -+ return 0; -+} -+ -+ -+static u8 * eap_ttls_fake_identity_request(void) -+{ -+ struct eap_hdr *hdr; -+ u8 *buf; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of " -+ "Phase 2 - use fake EAP-Request Identity"); -+ buf = os_malloc(sizeof(*hdr) + 1); -+ if (buf == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate " -+ "memory for fake EAP-Identity Request"); -+ return NULL; -+ } -+ -+ hdr = (struct eap_hdr *) buf; -+ hdr->code = EAP_CODE_REQUEST; -+ hdr->identifier = 0; -+ hdr->length = host_to_be16(sizeof(*hdr) + 1); -+ buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY; -+ -+ return buf; -+} -+ -+ -+static int eap_ttls_encrypt_response(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct wpabuf *resp, u8 identifier, -+ struct wpabuf **out_data) -+{ -+ if (resp == NULL) -+ return 0; -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", -+ resp); -+ if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, -+ data->ttls_version, identifier, -+ resp, out_data)) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 " -+ "frame"); -+ return -1; -+ } -+ wpabuf_free(resp); -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_process_phase2_eap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct ttls_parse_avp *parse, -+ struct wpabuf **resp) -+{ -+ struct eap_hdr *hdr; -+ size_t len; -+ -+ if (parse->eapdata == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " -+ "packet - dropped"); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", -+ parse->eapdata, parse->eap_len); -+ hdr = (struct eap_hdr *) parse->eapdata; -+ -+ if (parse->eap_len < sizeof(*hdr)) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " -+ "frame (len=%lu, expected %lu or more) - dropped", -+ (unsigned long) parse->eap_len, -+ (unsigned long) sizeof(*hdr)); -+ return -1; -+ } -+ len = be_to_host16(hdr->length); -+ if (len > parse->eap_len) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " -+ "EAP frame (EAP hdr len=%lu, EAP data len in " -+ "AVP=%lu)", -+ (unsigned long) len, -+ (unsigned long) parse->eap_len); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " -+ "identifier=%d length=%lu", -+ hdr->code, hdr->identifier, (unsigned long) len); -+ switch (hdr->code) { -+ case EAP_CODE_REQUEST: -+ if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " -+ "processing failed"); -+ return -1; -+ } -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " -+ "Phase 2 EAP header", hdr->code); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct ttls_parse_avp *parse) -+{ -+ if (parse->mschapv2_error) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " -+ "MS-CHAP-Error - failed"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ /* Reply with empty data to ACK error */ -+ return 1; -+ } -+ -+ if (parse->mschapv2 == NULL) { -+#ifdef EAP_TNC -+ if (data->phase2_success && parse->eapdata) { -+ /* -+ * Allow EAP-TNC to be started after successfully -+ * completed MSCHAPV2. -+ */ -+ return 1; -+ } -+#endif /* EAP_TNC */ -+ wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " -+ "received for Phase2 MSCHAPV2"); -+ return -1; -+ } -+ if (parse->mschapv2[0] != data->ident) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " -+ "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", -+ parse->mschapv2[0], data->ident); -+ return -1; -+ } -+ if (!data->auth_response_valid || -+ mschapv2_verify_auth_response(data->auth_response, -+ parse->mschapv2 + 1, 42)) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " -+ "response in Phase 2 MSCHAPV2 success request"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " -+ "authentication succeeded"); -+ if (data->ttls_version > 0) { -+ /* -+ * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report -+ * success, so do not allow connection to be terminated -+ * yet. -+ */ -+ ret->methodState = METHOD_CONT; -+ ret->decision = DECISION_COND_SUCC; -+ } else { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ data->phase2_success = 1; -+ } -+ -+ /* -+ * Reply with empty data; authentication server will reply -+ * with EAP-Success after this. -+ */ -+ return 1; -+} -+ -+ -+#ifdef EAP_TNC -+static int eap_ttls_process_tnc_start(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ struct ttls_parse_avp *parse, -+ struct wpabuf **resp) -+{ -+ /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ -+ if (parse->eapdata == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " -+ "unexpected tunneled data (no EAP)"); -+ return -1; -+ } -+ -+ if (!data->ready_for_tnc) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " -+ "EAP after non-EAP, but not ready for TNC"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " -+ "non-EAP method"); -+ data->tnc_started = 1; -+ -+ if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) -+ return -1; -+ -+ return 0; -+} -+#endif /* EAP_TNC */ -+ -+ -+static int eap_ttls_process_decrypted(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ u8 identifier, -+ struct ttls_parse_avp *parse, -+ struct wpabuf *in_decrypted, -+ struct wpabuf **out_data) -+{ -+ struct wpabuf *resp = NULL; -+ struct eap_peer_config *config = eap_get_config(sm); -+ int res; -+ enum phase2_types phase2_type = data->phase2_type; -+ -+#ifdef EAP_TNC -+ if (data->tnc_started) -+ phase2_type = EAP_TTLS_PHASE2_EAP; -+#endif /* EAP_TNC */ -+ -+ switch (phase2_type) { -+ case EAP_TTLS_PHASE2_EAP: -+ if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < -+ 0) -+ return -1; -+ break; -+ case EAP_TTLS_PHASE2_MSCHAPV2: -+ res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); -+#ifdef EAP_TNC -+ if (res == 1 && parse->eapdata && data->phase2_success) { -+ /* -+ * TNC may be required as the next -+ * authentication method within the tunnel. -+ */ -+ ret->methodState = METHOD_MAY_CONT; -+ data->ready_for_tnc = 1; -+ if (eap_ttls_process_tnc_start(sm, data, ret, parse, -+ &resp) == 0) -+ break; -+ } -+#endif /* EAP_TNC */ -+ return res; -+ case EAP_TTLS_PHASE2_MSCHAP: -+ case EAP_TTLS_PHASE2_PAP: -+ case EAP_TTLS_PHASE2_CHAP: -+#ifdef EAP_TNC -+ if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < -+ 0) -+ return -1; -+ break; -+#else /* EAP_TNC */ -+ /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled -+ * requests to the supplicant */ -+ wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " -+ "tunneled data"); -+ return -1; -+#endif /* EAP_TNC */ -+ } -+ -+ if (resp) { -+ if (eap_ttls_encrypt_response(sm, data, resp, identifier, -+ out_data) < 0) -+ return -1; -+ } else if (config->pending_req_identity || -+ config->pending_req_password || -+ config->pending_req_otp || -+ config->pending_req_new_password) { -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = wpabuf_dup(in_decrypted); -+ } -+ -+ return 0; -+} -+ -+ -+#if EAP_TTLS_VERSION > 0 -+static void eap_ttls_final_phase_finished(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ u8 identifier, -+ struct wpabuf **out_data) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received"); -+ wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ data->phase2_success = 1; -+ *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1); -+ eap_ttls_v1_derive_key(sm, data); -+} -+#endif /* EAP_TTLS_VERSION */ -+ -+ -+static int eap_ttls_implicit_identity_request(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ u8 identifier, -+ struct wpabuf **out_data) -+{ -+ int retval = 0; -+ struct eap_hdr *hdr; -+ struct wpabuf *resp; -+ -+ hdr = (struct eap_hdr *) eap_ttls_fake_identity_request(); -+ if (hdr == NULL) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ return -1; -+ } -+ -+ resp = NULL; -+ if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " -+ "processing failed"); -+ retval = -1; -+ } else { -+ retval = eap_ttls_encrypt_response(sm, data, resp, identifier, -+ out_data); -+ } -+ -+ os_free(hdr); -+ -+ if (retval < 0) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ } -+ -+ return retval; -+} -+ -+ -+static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data, -+ struct eap_method_ret *ret, u8 identifier, -+ struct wpabuf **out_data) -+{ -+ data->phase2_start = 0; -+ -+ /* -+ * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only -+ * if TLS part was indeed resuming a previous session. Most -+ * Authentication Servers terminate EAP-TTLS before reaching this -+ * point, but some do not. Make wpa_supplicant stop phase 2 here, if -+ * needed. -+ */ -+ if (data->reauth && -+ tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - " -+ "skip phase 2"); -+ *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS, -+ data->ttls_version); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ data->phase2_success = 1; -+ return 0; -+ } -+ -+ return eap_ttls_implicit_identity_request(sm, data, ret, identifier, -+ out_data); -+} -+ -+ -+static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data, -+ struct eap_method_ret *ret, u8 identifier, -+ const struct wpabuf *in_data, -+ struct wpabuf **out_data) -+{ -+ struct wpabuf *in_decrypted = NULL; -+ int retval = 0; -+ struct ttls_parse_avp parse; -+ -+ os_memset(&parse, 0, sizeof(parse)); -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" -+ " Phase 2", -+ in_data ? (unsigned long) wpabuf_len(in_data) : 0); -+ -+ if (data->pending_phase2_req) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - " -+ "skip decryption and use old data"); -+ /* Clear TLS reassembly state. */ -+ eap_peer_tls_reset_input(&data->ssl); -+ -+ in_decrypted = data->pending_phase2_req; -+ data->pending_phase2_req = NULL; -+ if (wpabuf_len(in_decrypted) == 0) { -+ wpabuf_free(in_decrypted); -+ return eap_ttls_implicit_identity_request( -+ sm, data, ret, identifier, out_data); -+ } -+ goto continue_req; -+ } -+ -+ if ((in_data == NULL || wpabuf_len(in_data) == 0) && -+ data->phase2_start) { -+ return eap_ttls_phase2_start(sm, data, ret, identifier, -+ out_data); -+ } -+ -+ if (in_data == NULL || wpabuf_len(in_data) == 0) { -+ /* Received TLS ACK - requesting more fragments */ -+ return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, -+ data->ttls_version, -+ identifier, NULL, out_data); -+ } -+ -+ retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); -+ if (retval) -+ goto done; -+ -+#if EAP_TTLS_VERSION > 0 -+ if (data->ttls_version > 0 && -+ (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) && -+ tls_connection_ia_final_phase_finished(sm->ssl_ctx, -+ data->ssl.conn)) { -+ eap_ttls_final_phase_finished(sm, data, ret, identifier, -+ out_data); -+ goto done; -+ } -+#endif /* EAP_TTLS_VERSION */ -+ -+continue_req: -+ data->phase2_start = 0; -+ -+ if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) { -+ retval = -1; -+ goto done; -+ } -+ -+ retval = eap_ttls_process_decrypted(sm, data, ret, identifier, -+ &parse, in_decrypted, out_data); -+ -+done: -+ wpabuf_free(in_decrypted); -+ os_free(parse.eapdata); -+ -+ if (retval < 0) { -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ } -+ -+ return retval; -+} -+ -+ -+static int eap_ttls_process_start(struct eap_sm *sm, -+ struct eap_ttls_data *data, u8 flags, -+ struct eap_method_ret *ret) -+{ -+ struct eap_peer_config *config = eap_get_config(sm); -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)", -+ flags & EAP_TLS_VERSION_MASK, data->ttls_version); -+#if EAP_TTLS_VERSION > 0 -+ if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version) -+ data->ttls_version = flags & EAP_TLS_VERSION_MASK; -+ if (data->force_ttls_version >= 0 && -+ data->force_ttls_version != data->ttls_version) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select " -+ "forced TTLS version %d", -+ data->force_ttls_version); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = FALSE; -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d", -+ data->ttls_version); -+ -+ if (data->ttls_version > 0) -+ data->ssl.tls_ia = 1; -+#endif /* EAP_TTLS_VERSION */ -+ if (!data->ssl_initialized && -+ eap_peer_tls_ssl_init(sm, &data->ssl, config)) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); -+ return -1; -+ } -+ data->ssl_initialized = 1; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Start"); -+ -+ return 0; -+} -+ -+ -+static int eap_ttls_process_handshake(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret, -+ u8 identifier, -+ const u8 *in_data, size_t in_len, -+ struct wpabuf **out_data) -+{ -+ int res; -+ -+ res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, -+ data->ttls_version, identifier, -+ in_data, in_len, out_data); -+ -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to " -+ "Phase 2"); -+ if (data->resuming) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may " -+ "skip Phase 2"); -+ ret->decision = DECISION_COND_SUCC; -+ ret->methodState = METHOD_MAY_CONT; -+ } -+ data->phase2_start = 1; -+ if (data->ttls_version == 0) -+ eap_ttls_v0_derive_key(sm, data); -+ -+ if (*out_data == NULL || wpabuf_len(*out_data) == 0) { -+ if (eap_ttls_decrypt(sm, data, ret, identifier, -+ NULL, out_data)) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: " -+ "failed to process early " -+ "start for Phase 2"); -+ } -+ res = 0; -+ } -+ data->resuming = 0; -+ } -+ -+ if (res == 2) { -+ struct wpabuf msg; -+ /* -+ * Application data included in the handshake message. -+ */ -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = *out_data; -+ *out_data = NULL; -+ wpabuf_set(&msg, in_data, in_len); -+ res = eap_ttls_decrypt(sm, data, ret, identifier, &msg, -+ out_data); -+ } -+ -+ return res; -+} -+ -+ -+static void eap_ttls_check_auth_status(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct eap_method_ret *ret) -+{ -+ if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) { -+ ret->allowNotifications = FALSE; -+ if (ret->decision == DECISION_UNCOND_SUCC || -+ ret->decision == DECISION_COND_SUCC) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " -+ "completed successfully"); -+ data->phase2_success = 1; -+#ifdef EAP_TNC -+ if (!data->ready_for_tnc && !data->tnc_started) { -+ /* -+ * TNC may be required as the next -+ * authentication method within the tunnel. -+ */ -+ ret->methodState = METHOD_MAY_CONT; -+ data->ready_for_tnc = 1; -+ } -+#endif /* EAP_TNC */ -+ } -+ } else if (data->ttls_version == 0 && -+ ret->methodState == METHOD_MAY_CONT && -+ (ret->decision == DECISION_UNCOND_SUCC || -+ ret->decision == DECISION_COND_SUCC)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " -+ "completed successfully (MAY_CONT)"); -+ data->phase2_success = 1; -+ } -+} -+ -+ -+static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ size_t left; -+ int res; -+ u8 flags, id; -+ struct wpabuf *resp; -+ const u8 *pos; -+ struct eap_ttls_data *data = priv; -+ -+ pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret, -+ reqData, &left, &flags); -+ if (pos == NULL) -+ return NULL; -+ id = eap_get_id(reqData); -+ -+ if (flags & EAP_TLS_FLAGS_START) { -+ if (eap_ttls_process_start(sm, data, flags, ret) < 0) -+ return NULL; -+ -+ /* RFC 5281, Ch. 9.2: -+ * "This packet MAY contain additional information in the form -+ * of AVPs, which may provide useful hints to the client" -+ * For now, ignore any potential extra data. -+ */ -+ left = 0; -+ } else if (!data->ssl_initialized) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not " -+ "include Start flag"); -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_FAIL; -+ ret->allowNotifications = FALSE; -+ return NULL; -+ } -+ -+ resp = NULL; -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && -+ !data->resuming) { -+ struct wpabuf msg; -+ wpabuf_set(&msg, pos, left); -+ res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); -+ } else { -+ res = eap_ttls_process_handshake(sm, data, ret, id, -+ pos, left, &resp); -+ } -+ -+ eap_ttls_check_auth_status(sm, data, ret); -+ -+ /* FIX: what about res == -1? Could just move all error processing into -+ * the other functions and get rid of this res==1 case here. */ -+ if (res == 1) { -+ wpabuf_free(resp); -+ return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, -+ data->ttls_version); -+ } -+ return resp; -+} -+ -+ -+static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && -+ data->phase2_success; -+} -+ -+ -+static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ wpabuf_free(data->pending_phase2_req); -+ data->pending_phase2_req = NULL; -+#ifdef EAP_TNC -+ data->ready_for_tnc = 0; -+ data->tnc_started = 0; -+#endif /* EAP_TNC */ -+} -+ -+ -+static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ os_free(data->key_data); -+ data->key_data = NULL; -+ if (eap_peer_tls_reauth_init(sm, &data->ssl)) { -+ os_free(data); -+ return NULL; -+ } -+ if (data->phase2_priv && data->phase2_method && -+ data->phase2_method->init_for_reauth) -+ data->phase2_method->init_for_reauth(sm, data->phase2_priv); -+ data->phase2_start = 0; -+ data->phase2_success = 0; -+ data->resuming = 1; -+ data->reauth = 1; -+ return priv; -+} -+ -+ -+static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, -+ size_t buflen, int verbose) -+{ -+ struct eap_ttls_data *data = priv; -+ int len, ret; -+ -+ len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); -+ ret = os_snprintf(buf + len, buflen - len, -+ "EAP-TTLSv%d Phase2 method=", -+ data->ttls_version); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ switch (data->phase2_type) { -+ case EAP_TTLS_PHASE2_EAP: -+ ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", -+ data->phase2_method ? -+ data->phase2_method->name : "?"); -+ break; -+ case EAP_TTLS_PHASE2_MSCHAPV2: -+ ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); -+ break; -+ case EAP_TTLS_PHASE2_MSCHAP: -+ ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); -+ break; -+ case EAP_TTLS_PHASE2_PAP: -+ ret = os_snprintf(buf + len, buflen - len, "PAP\n"); -+ break; -+ case EAP_TTLS_PHASE2_CHAP: -+ ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); -+ break; -+ default: -+ ret = 0; -+ break; -+ } -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ return len; -+} -+ -+ -+static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ return data->key_data != NULL && data->phase2_success; -+} -+ -+ -+static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_ttls_data *data = priv; -+ u8 *key; -+ -+ if (data->key_data == NULL || !data->phase2_success) -+ return NULL; -+ -+ key = os_malloc(EAP_TLS_KEY_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_TLS_KEY_LEN; -+ os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); -+ -+ return key; -+} -+ -+ -+int eap_peer_ttls_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_ttls_init; -+ eap->deinit = eap_ttls_deinit; -+ eap->process = eap_ttls_process; -+ eap->isKeyAvailable = eap_ttls_isKeyAvailable; -+ eap->getKey = eap_ttls_getKey; -+ eap->get_status = eap_ttls_get_status; -+ eap->has_reauth_data = eap_ttls_has_reauth_data; -+ eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; -+ eap->init_for_reauth = eap_ttls_init_for_reauth; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_vendor_test.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_vendor_test.c -new file mode 100644 -index 0000000000000..3e114c142a428 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_vendor_test.c -@@ -0,0 +1,195 @@ -+/* -+ * EAP peer method: Test method for vendor specific (expanded) EAP type -+ * Copyright (c) 2005-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file implements a vendor specific test method using EAP expanded types. -+ * This is only for test use and must not be used for authentication since no -+ * security is provided. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+#ifdef TEST_PENDING_REQUEST -+#include "eloop.h" -+#endif /* TEST_PENDING_REQUEST */ -+ -+ -+#define EAP_VENDOR_ID 0xfffefd -+#define EAP_VENDOR_TYPE 0xfcfbfaf9 -+ -+ -+/* #define TEST_PENDING_REQUEST */ -+ -+struct eap_vendor_test_data { -+ enum { INIT, CONFIRM, SUCCESS } state; -+ int first_try; -+}; -+ -+ -+static void * eap_vendor_test_init(struct eap_sm *sm) -+{ -+ struct eap_vendor_test_data *data; -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = INIT; -+ data->first_try = 1; -+ return data; -+} -+ -+ -+static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_vendor_test_data *data = priv; -+ os_free(data); -+} -+ -+ -+#ifdef TEST_PENDING_REQUEST -+static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct eap_sm *sm = eloop_ctx; -+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending " -+ "request"); -+ eap_notify_pending(sm); -+} -+#endif /* TEST_PENDING_REQUEST */ -+ -+ -+static struct wpabuf * eap_vendor_test_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_vendor_test_data *data = priv; -+ struct wpabuf *resp; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, reqData, &len); -+ if (pos == NULL || len < 1) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->state == INIT && *pos != 1) { -+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " -+ "%d in INIT state", *pos); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->state == CONFIRM && *pos != 3) { -+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " -+ "%d in CONFIRM state", *pos); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->state == SUCCESS) { -+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message " -+ "in SUCCESS state"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->state == CONFIRM) { -+#ifdef TEST_PENDING_REQUEST -+ if (data->first_try) { -+ data->first_try = 0; -+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing " -+ "pending request"); -+ ret->ignore = TRUE; -+ eloop_register_timeout(1, 0, eap_vendor_ready, sm, -+ NULL); -+ return NULL; -+ } -+#endif /* TEST_PENDING_REQUEST */ -+ } -+ -+ ret->ignore = FALSE; -+ -+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response"); -+ ret->allowNotifications = TRUE; -+ -+ resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1, -+ EAP_CODE_RESPONSE, eap_get_id(reqData)); -+ if (resp == NULL) -+ return NULL; -+ -+ if (data->state == INIT) { -+ wpabuf_put_u8(resp, 2); -+ data->state = CONFIRM; -+ ret->methodState = METHOD_CONT; -+ ret->decision = DECISION_FAIL; -+ } else { -+ wpabuf_put_u8(resp, 4); -+ data->state = SUCCESS; -+ ret->methodState = METHOD_DONE; -+ ret->decision = DECISION_UNCOND_SUCC; -+ } -+ -+ return resp; -+} -+ -+ -+static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv) -+{ -+ struct eap_vendor_test_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_vendor_test_data *data = priv; -+ u8 *key; -+ const int key_len = 64; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(key_len); -+ if (key == NULL) -+ return NULL; -+ -+ os_memset(key, 0x11, key_len / 2); -+ os_memset(key + key_len / 2, 0x22, key_len / 2); -+ *len = key_len; -+ -+ return key; -+} -+ -+ -+int eap_peer_vendor_test_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_ID, EAP_VENDOR_TYPE, -+ "VENDOR-TEST"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_vendor_test_init; -+ eap->deinit = eap_vendor_test_deinit; -+ eap->process = eap_vendor_test_process; -+ eap->isKeyAvailable = eap_vendor_test_isKeyAvailable; -+ eap->getKey = eap_vendor_test_getKey; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_wsc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_wsc.c -new file mode 100644 -index 0000000000000..09d8a1c8a1b7b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/eap_wsc.c -@@ -0,0 +1,553 @@ -+/* -+ * EAP-WSC peer for Wi-Fi Protected Setup -+ * Copyright (c) 2007-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "uuid.h" -+#include "eap_i.h" -+#include "eap_common/eap_wsc_common.h" -+#include "wps/wps.h" -+#include "wps/wps_defs.h" -+ -+ -+struct eap_wsc_data { -+ enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; -+ int registrar; -+ struct wpabuf *in_buf; -+ struct wpabuf *out_buf; -+ enum wsc_op_code in_op_code, out_op_code; -+ size_t out_used; -+ size_t fragment_size; -+ struct wps_data *wps; -+ struct wps_context *wps_ctx; -+}; -+ -+ -+static const char * eap_wsc_state_txt(int state) -+{ -+ switch (state) { -+ case WAIT_START: -+ return "WAIT_START"; -+ case MESG: -+ return "MESG"; -+ case FRAG_ACK: -+ return "FRAG_ACK"; -+ case WAIT_FRAG_ACK: -+ return "WAIT_FRAG_ACK"; -+ case DONE: -+ return "DONE"; -+ case FAIL: -+ return "FAIL"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+static void eap_wsc_state(struct eap_wsc_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", -+ eap_wsc_state_txt(data->state), -+ eap_wsc_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static int eap_wsc_new_ap_settings(struct wps_credential *cred, -+ const char *params) -+{ -+ const char *pos, *end; -+ size_t len; -+ -+ os_memset(cred, 0, sizeof(*cred)); -+ -+ pos = os_strstr(params, "new_ssid="); -+ if (pos == NULL) -+ return 0; -+ pos += 9; -+ end = os_strchr(pos, ' '); -+ if (end == NULL) -+ len = os_strlen(pos); -+ else -+ len = end - pos; -+ if ((len & 1) || len > 2 * sizeof(cred->ssid) || -+ hexstr2bin(pos, cred->ssid, len / 2)) -+ return -1; -+ cred->ssid_len = len / 2; -+ -+ pos = os_strstr(params, "new_auth="); -+ if (pos == NULL) -+ return -1; -+ if (os_strncmp(pos + 9, "OPEN", 4) == 0) -+ cred->auth_type = WPS_AUTH_OPEN; -+ else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0) -+ cred->auth_type = WPS_AUTH_WPAPSK; -+ else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0) -+ cred->auth_type = WPS_AUTH_WPA2PSK; -+ else -+ return -1; -+ -+ pos = os_strstr(params, "new_encr="); -+ if (pos == NULL) -+ return -1; -+ if (os_strncmp(pos + 9, "NONE", 4) == 0) -+ cred->encr_type = WPS_ENCR_NONE; -+ else if (os_strncmp(pos + 9, "WEP", 3) == 0) -+ cred->encr_type = WPS_ENCR_WEP; -+ else if (os_strncmp(pos + 9, "TKIP", 4) == 0) -+ cred->encr_type = WPS_ENCR_TKIP; -+ else if (os_strncmp(pos + 9, "CCMP", 4) == 0) -+ cred->encr_type = WPS_ENCR_AES; -+ else -+ return -1; -+ -+ pos = os_strstr(params, "new_key="); -+ if (pos == NULL) -+ return 0; -+ pos += 8; -+ end = os_strchr(pos, ' '); -+ if (end == NULL) -+ len = os_strlen(pos); -+ else -+ len = end - pos; -+ if ((len & 1) || len > 2 * sizeof(cred->key) || -+ hexstr2bin(pos, cred->key, len / 2)) -+ return -1; -+ cred->key_len = len / 2; -+ -+ return 1; -+} -+ -+ -+static void * eap_wsc_init(struct eap_sm *sm) -+{ -+ struct eap_wsc_data *data; -+ const u8 *identity; -+ size_t identity_len; -+ int registrar; -+ struct wps_config cfg; -+ const char *pos; -+ const char *phase1; -+ struct wps_context *wps; -+ struct wps_credential new_ap_settings; -+ int res; -+ -+ wps = sm->wps; -+ if (wps == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); -+ return NULL; -+ } -+ -+ identity = eap_get_config_identity(sm, &identity_len); -+ -+ if (identity && identity_len == WSC_ID_REGISTRAR_LEN && -+ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) -+ registrar = 1; /* Supplicant is Registrar */ -+ else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && -+ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) -+ registrar = 0; /* Supplicant is Enrollee */ -+ else { -+ wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", -+ identity, identity_len); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = registrar ? MESG : WAIT_START; -+ data->registrar = registrar; -+ data->wps_ctx = wps; -+ -+ os_memset(&cfg, 0, sizeof(cfg)); -+ cfg.wps = wps; -+ cfg.registrar = registrar; -+ -+ phase1 = eap_get_config_phase1(sm); -+ if (phase1 == NULL) { -+ wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " -+ "set"); -+ os_free(data); -+ return NULL; -+ } -+ -+ pos = os_strstr(phase1, "pin="); -+ if (pos) { -+ pos += 4; -+ cfg.pin = (const u8 *) pos; -+ while (*pos != '\0' && *pos != ' ') -+ pos++; -+ cfg.pin_len = pos - (const char *) cfg.pin; -+ } else { -+ pos = os_strstr(phase1, "pbc=1"); -+ if (pos) -+ cfg.pbc = 1; -+ } -+ -+ if (cfg.pin == NULL && !cfg.pbc) { -+ wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " -+ "configuration data"); -+ os_free(data); -+ return NULL; -+ } -+ -+ pos = os_strstr(phase1, "dev_pw_id="); -+ if (pos && cfg.pin) -+ cfg.dev_pw_id = atoi(pos + 10); -+ -+ res = eap_wsc_new_ap_settings(&new_ap_settings, phase1); -+ if (res < 0) { -+ os_free(data); -+ return NULL; -+ } -+ if (res == 1) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for " -+ "WPS"); -+ cfg.new_ap_settings = &new_ap_settings; -+ } -+ -+ data->wps = wps_init(&cfg); -+ if (data->wps == NULL) { -+ os_free(data); -+ return NULL; -+ } -+ res = eap_get_config_fragment_size(sm); -+ if (res > 0) -+ data->fragment_size = res; -+ else -+ data->fragment_size = WSC_FRAGMENT_SIZE; -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u", -+ (unsigned int) data->fragment_size); -+ -+ if (registrar && cfg.pin) { -+ wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL, -+ cfg.pin, cfg.pin_len, 0); -+ } -+ -+ /* Use reduced client timeout for WPS to avoid long wait */ -+ if (sm->ClientTimeout > 30) -+ sm->ClientTimeout = 30; -+ -+ return data; -+} -+ -+ -+static void eap_wsc_deinit(struct eap_sm *sm, void *priv) -+{ -+ struct eap_wsc_data *data = priv; -+ wpabuf_free(data->in_buf); -+ wpabuf_free(data->out_buf); -+ wps_deinit(data->wps); -+ os_free(data->wps_ctx->network_key); -+ data->wps_ctx->network_key = NULL; -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, -+ struct eap_method_ret *ret, u8 id) -+{ -+ struct wpabuf *resp; -+ u8 flags; -+ size_t send_len, plen; -+ -+ ret->ignore = FALSE; -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); -+ ret->allowNotifications = TRUE; -+ -+ flags = 0; -+ send_len = wpabuf_len(data->out_buf) - data->out_used; -+ if (2 + send_len > data->fragment_size) { -+ send_len = data->fragment_size - 2; -+ flags |= WSC_FLAGS_MF; -+ if (data->out_used == 0) { -+ flags |= WSC_FLAGS_LF; -+ send_len -= 2; -+ } -+ } -+ plen = 2 + send_len; -+ if (flags & WSC_FLAGS_LF) -+ plen += 2; -+ resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, -+ EAP_CODE_RESPONSE, id); -+ if (resp == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ -+ wpabuf_put_u8(resp, flags); /* Flags */ -+ if (flags & WSC_FLAGS_LF) -+ wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); -+ -+ wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, -+ send_len); -+ data->out_used += send_len; -+ -+ ret->methodState = METHOD_MAY_CONT; -+ ret->decision = DECISION_FAIL; -+ -+ if (data->out_used == wpabuf_len(data->out_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " -+ "(message sent completely)", -+ (unsigned long) send_len); -+ wpabuf_free(data->out_buf); -+ data->out_buf = NULL; -+ data->out_used = 0; -+ if ((data->state == FAIL && data->out_op_code == WSC_ACK) || -+ data->out_op_code == WSC_NACK || -+ data->out_op_code == WSC_Done) { -+ eap_wsc_state(data, FAIL); -+ ret->methodState = METHOD_DONE; -+ } else -+ eap_wsc_state(data, MESG); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " -+ "(%lu more to send)", (unsigned long) send_len, -+ (unsigned long) wpabuf_len(data->out_buf) - -+ data->out_used); -+ eap_wsc_state(data, WAIT_FRAG_ACK); -+ } -+ -+ return resp; -+} -+ -+ -+static int eap_wsc_process_cont(struct eap_wsc_data *data, -+ const u8 *buf, size_t len, u8 op_code) -+{ -+ /* Process continuation of a pending message */ -+ if (op_code != data->in_op_code) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " -+ "fragment (expected %d)", -+ op_code, data->in_op_code); -+ return -1; -+ } -+ -+ if (len > wpabuf_tailroom(data->in_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); -+ eap_wsc_state(data, FAIL); -+ return -1; -+ } -+ -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " -+ "for %lu bytes more", (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, -+ struct eap_method_ret *ret, -+ u8 id, u8 flags, u8 op_code, -+ u16 message_length, -+ const u8 *buf, size_t len) -+{ -+ /* Process a fragment that is not the last one of the message */ -+ if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " -+ "fragmented packet"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* First fragment of the message */ -+ data->in_buf = wpabuf_alloc(message_length); -+ if (data->in_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " -+ "message"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ data->in_op_code = op_code; -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " -+ "fragment, waiting for %lu bytes more", -+ (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ } -+ -+ return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); -+} -+ -+ -+static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, -+ struct eap_method_ret *ret, -+ const struct wpabuf *reqData) -+{ -+ struct eap_wsc_data *data = priv; -+ const u8 *start, *pos, *end; -+ size_t len; -+ u8 op_code, flags, id; -+ u16 message_length = 0; -+ enum wps_process_res res; -+ struct wpabuf tmpbuf; -+ struct wpabuf *r; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, -+ &len); -+ if (pos == NULL || len < 2) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ id = eap_get_id(reqData); -+ -+ start = pos; -+ end = start + len; -+ -+ op_code = *pos++; -+ flags = *pos++; -+ if (flags & WSC_FLAGS_LF) { -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ message_length = WPA_GET_BE16(pos); -+ pos += 2; -+ -+ if (message_length < end - pos) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " -+ "Length"); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " -+ "Flags 0x%x Message Length %d", -+ op_code, flags, message_length); -+ -+ if (data->state == WAIT_FRAG_ACK) { -+ if (op_code != WSC_FRAG_ACK) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " -+ "in WAIT_FRAG_ACK state", op_code); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); -+ eap_wsc_state(data, MESG); -+ return eap_wsc_build_msg(data, ret, id); -+ } -+ -+ if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && -+ op_code != WSC_Done && op_code != WSC_Start) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", -+ op_code); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->state == WAIT_START) { -+ if (op_code != WSC_Start) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " -+ "in WAIT_START state", op_code); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); -+ eap_wsc_state(data, MESG); -+ /* Start message has empty payload, skip processing */ -+ goto send_msg; -+ } else if (op_code == WSC_Start) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", -+ op_code); -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (data->in_buf && -+ eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { -+ ret->ignore = TRUE; -+ return NULL; -+ } -+ -+ if (flags & WSC_FLAGS_MF) { -+ return eap_wsc_process_fragment(data, ret, id, flags, op_code, -+ message_length, pos, -+ end - pos); -+ } -+ -+ if (data->in_buf == NULL) { -+ /* Wrap unfragmented messages as wpabuf without extra copy */ -+ wpabuf_set(&tmpbuf, pos, end - pos); -+ data->in_buf = &tmpbuf; -+ } -+ -+ res = wps_process_msg(data->wps, op_code, data->in_buf); -+ switch (res) { -+ case WPS_DONE: -+ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " -+ "successfully - wait for EAP failure"); -+ eap_wsc_state(data, FAIL); -+ break; -+ case WPS_CONTINUE: -+ eap_wsc_state(data, MESG); -+ break; -+ case WPS_FAILURE: -+ case WPS_PENDING: -+ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); -+ eap_wsc_state(data, FAIL); -+ break; -+ } -+ -+ if (data->in_buf != &tmpbuf) -+ wpabuf_free(data->in_buf); -+ data->in_buf = NULL; -+ -+send_msg: -+ if (data->out_buf == NULL) { -+ data->out_buf = wps_get_msg(data->wps, &data->out_op_code); -+ if (data->out_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " -+ "message from WPS"); -+ return NULL; -+ } -+ data->out_used = 0; -+ } -+ -+ eap_wsc_state(data, MESG); -+ r = eap_wsc_build_msg(data, ret, id); -+ if (data->state == FAIL && ret->methodState == METHOD_DONE) { -+ /* Use reduced client timeout for WPS to avoid long wait */ -+ if (sm->ClientTimeout > 2) -+ sm->ClientTimeout = 2; -+ } -+ return r; -+} -+ -+ -+int eap_peer_wsc_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, -+ "WSC"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_wsc_init; -+ eap->deinit = eap_wsc_deinit; -+ eap->process = eap_wsc_process; -+ -+ ret = eap_peer_method_register(eap); -+ if (ret) -+ eap_peer_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.c -new file mode 100644 -index 0000000000000..1e169a070b6e9 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.c -@@ -0,0 +1,1304 @@ -+/* -+ * IKEv2 responder (RFC 4306) for EAP-IKEV2 -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/dh_groups.h" -+#include "crypto/random.h" -+#include "ikev2.h" -+ -+ -+void ikev2_responder_deinit(struct ikev2_responder_data *data) -+{ -+ ikev2_free_keys(&data->keys); -+ wpabuf_free(data->i_dh_public); -+ wpabuf_free(data->r_dh_private); -+ os_free(data->IDi); -+ os_free(data->IDr); -+ os_free(data->shared_secret); -+ wpabuf_free(data->i_sign_msg); -+ wpabuf_free(data->r_sign_msg); -+ os_free(data->key_pad); -+} -+ -+ -+static int ikev2_derive_keys(struct ikev2_responder_data *data) -+{ -+ u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN]; -+ size_t buf_len, pad_len; -+ struct wpabuf *shared; -+ const struct ikev2_integ_alg *integ; -+ const struct ikev2_prf_alg *prf; -+ const struct ikev2_encr_alg *encr; -+ int ret; -+ const u8 *addr[2]; -+ size_t len[2]; -+ -+ /* RFC 4306, Sect. 2.14 */ -+ -+ integ = ikev2_get_integ(data->proposal.integ); -+ prf = ikev2_get_prf(data->proposal.prf); -+ encr = ikev2_get_encr(data->proposal.encr); -+ if (integ == NULL || prf == NULL || encr == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal"); -+ return -1; -+ } -+ -+ shared = dh_derive_shared(data->i_dh_public, data->r_dh_private, -+ data->dh); -+ if (shared == NULL) -+ return -1; -+ -+ /* Construct Ni | Nr | SPIi | SPIr */ -+ -+ buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN; -+ buf = os_malloc(buf_len); -+ if (buf == NULL) { -+ wpabuf_free(shared); -+ return -1; -+ } -+ -+ pos = buf; -+ os_memcpy(pos, data->i_nonce, data->i_nonce_len); -+ pos += data->i_nonce_len; -+ os_memcpy(pos, data->r_nonce, data->r_nonce_len); -+ pos += data->r_nonce_len; -+ os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); -+ pos += IKEV2_SPI_LEN; -+ os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); -+#ifdef CCNS_PL -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+ { -+ int i; -+ u8 *tmp = pos - IKEV2_SPI_LEN; -+ /* Incorrect byte re-ordering on little endian hosts.. */ -+ for (i = 0; i < IKEV2_SPI_LEN; i++) -+ *tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i]; -+ for (i = 0; i < IKEV2_SPI_LEN; i++) -+ *tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i]; -+ } -+#endif -+#endif /* CCNS_PL */ -+ -+ /* SKEYSEED = prf(Ni | Nr, g^ir) */ -+ /* Use zero-padding per RFC 4306, Sect. 2.14 */ -+ pad_len = data->dh->prime_len - wpabuf_len(shared); -+#ifdef CCNS_PL -+ /* Shared secret is not zero-padded correctly */ -+ pad_len = 0; -+#endif /* CCNS_PL */ -+ pad = os_zalloc(pad_len ? pad_len : 1); -+ if (pad == NULL) { -+ wpabuf_free(shared); -+ os_free(buf); -+ return -1; -+ } -+ -+ addr[0] = pad; -+ len[0] = pad_len; -+ addr[1] = wpabuf_head(shared); -+ len[1] = wpabuf_len(shared); -+ if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len, -+ 2, addr, len, skeyseed) < 0) { -+ wpabuf_free(shared); -+ os_free(buf); -+ os_free(pad); -+ return -1; -+ } -+ os_free(pad); -+ wpabuf_free(shared); -+ -+ /* DH parameters are not needed anymore, so free them */ -+ wpabuf_free(data->i_dh_public); -+ data->i_dh_public = NULL; -+ wpabuf_free(data->r_dh_private); -+ data->r_dh_private = NULL; -+ -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED", -+ skeyseed, prf->hash_len); -+ -+ ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len, -+ &data->keys); -+ os_free(buf); -+ return ret; -+} -+ -+ -+static int ikev2_parse_transform(struct ikev2_proposal_data *prop, -+ const u8 *pos, const u8 *end) -+{ -+ int transform_len; -+ const struct ikev2_transform *t; -+ u16 transform_id; -+ const u8 *tend; -+ -+ if (end - pos < (int) sizeof(*t)) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short transform"); -+ return -1; -+ } -+ -+ t = (const struct ikev2_transform *) pos; -+ transform_len = WPA_GET_BE16(t->transform_length); -+ if (transform_len < (int) sizeof(*t) || pos + transform_len > end) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", -+ transform_len); -+ return -1; -+ } -+ tend = pos + transform_len; -+ -+ transform_id = WPA_GET_BE16(t->transform_id); -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); -+ wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " -+ "Transform Type: %d Transform ID: %d", -+ t->type, transform_len, t->transform_type, transform_id); -+ -+ if (t->type != 0 && t->type != 3) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); -+ return -1; -+ } -+ -+ pos = (const u8 *) (t + 1); -+ if (pos < tend) { -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", -+ pos, tend - pos); -+ } -+ -+ switch (t->transform_type) { -+ case IKEV2_TRANSFORM_ENCR: -+ if (ikev2_get_encr(transform_id)) { -+ if (transform_id == ENCR_AES_CBC) { -+ if (tend - pos != 4) { -+ wpa_printf(MSG_DEBUG, "IKEV2: No " -+ "Transform Attr for AES"); -+ break; -+ } -+#ifdef CCNS_PL -+ if (WPA_GET_BE16(pos) != 0x001d /* ?? */) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Not a " -+ "Key Size attribute for " -+ "AES"); -+ break; -+ } -+#else /* CCNS_PL */ -+ if (WPA_GET_BE16(pos) != 0x800e) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Not a " -+ "Key Size attribute for " -+ "AES"); -+ break; -+ } -+#endif /* CCNS_PL */ -+ if (WPA_GET_BE16(pos + 2) != 128) { -+ wpa_printf(MSG_DEBUG, "IKEV2: " -+ "Unsupported AES key size " -+ "%d bits", -+ WPA_GET_BE16(pos + 2)); -+ break; -+ } -+ } -+ prop->encr = transform_id; -+ } -+ break; -+ case IKEV2_TRANSFORM_PRF: -+ if (ikev2_get_prf(transform_id)) -+ prop->prf = transform_id; -+ break; -+ case IKEV2_TRANSFORM_INTEG: -+ if (ikev2_get_integ(transform_id)) -+ prop->integ = transform_id; -+ break; -+ case IKEV2_TRANSFORM_DH: -+ if (dh_groups_get(transform_id)) -+ prop->dh = transform_id; -+ break; -+ } -+ -+ return transform_len; -+} -+ -+ -+static int ikev2_parse_proposal(struct ikev2_proposal_data *prop, -+ const u8 *pos, const u8 *end) -+{ -+ const u8 *pend, *ppos; -+ int proposal_len, i; -+ const struct ikev2_proposal *p; -+ -+ if (end - pos < (int) sizeof(*p)) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short proposal"); -+ return -1; -+ } -+ -+ /* FIX: AND processing if multiple proposals use the same # */ -+ -+ p = (const struct ikev2_proposal *) pos; -+ proposal_len = WPA_GET_BE16(p->proposal_length); -+ if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d", -+ proposal_len); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d", -+ p->proposal_num); -+ wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Proposal Length: %d " -+ " Protocol ID: %d", -+ p->type, proposal_len, p->protocol_id); -+ wpa_printf(MSG_DEBUG, "IKEV2: SPI Size: %d Transforms: %d", -+ p->spi_size, p->num_transforms); -+ -+ if (p->type != 0 && p->type != 2) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type"); -+ return -1; -+ } -+ -+ if (p->protocol_id != IKEV2_PROTOCOL_IKE) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID " -+ "(only IKE allowed for EAP-IKEv2)"); -+ return -1; -+ } -+ -+ if (p->proposal_num != prop->proposal_num) { -+ if (p->proposal_num == prop->proposal_num + 1) -+ prop->proposal_num = p->proposal_num; -+ else { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #"); -+ return -1; -+ } -+ } -+ -+ ppos = (const u8 *) (p + 1); -+ pend = pos + proposal_len; -+ if (ppos + p->spi_size > pend) { -+ wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI " -+ "in proposal"); -+ return -1; -+ } -+ if (p->spi_size) { -+ wpa_hexdump(MSG_DEBUG, "IKEV2: SPI", -+ ppos, p->spi_size); -+ ppos += p->spi_size; -+ } -+ -+ /* -+ * For initial IKE_SA negotiation, SPI Size MUST be zero; for -+ * subsequent negotiations, it must be 8 for IKE. We only support -+ * initial case for now. -+ */ -+ if (p->spi_size != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size"); -+ return -1; -+ } -+ -+ if (p->num_transforms == 0) { -+ wpa_printf(MSG_INFO, "IKEV2: At least one transform required"); -+ return -1; -+ } -+ -+ for (i = 0; i < (int) p->num_transforms; i++) { -+ int tlen = ikev2_parse_transform(prop, ppos, pend); -+ if (tlen < 0) -+ return -1; -+ ppos += tlen; -+ } -+ -+ if (ppos != pend) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected data after " -+ "transforms"); -+ return -1; -+ } -+ -+ return proposal_len; -+} -+ -+ -+static int ikev2_process_sai1(struct ikev2_responder_data *data, -+ const u8 *sai1, size_t sai1_len) -+{ -+ struct ikev2_proposal_data prop; -+ const u8 *pos, *end; -+ int found = 0; -+ -+ /* Security Association Payloads: */ -+ -+ if (sai1 == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: SAi1 not received"); -+ return -1; -+ } -+ -+ os_memset(&prop, 0, sizeof(prop)); -+ prop.proposal_num = 1; -+ -+ pos = sai1; -+ end = sai1 + sai1_len; -+ -+ while (pos < end) { -+ int plen; -+ -+ prop.integ = -1; -+ prop.prf = -1; -+ prop.encr = -1; -+ prop.dh = -1; -+ plen = ikev2_parse_proposal(&prop, pos, end); -+ if (plen < 0) -+ return -1; -+ -+ if (!found && prop.integ != -1 && prop.prf != -1 && -+ prop.encr != -1 && prop.dh != -1) { -+ os_memcpy(&data->proposal, &prop, sizeof(prop)); -+ data->dh = dh_groups_get(prop.dh); -+ found = 1; -+ } -+ -+ pos += plen; -+ } -+ -+ if (pos != end) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals"); -+ return -1; -+ } -+ -+ if (!found) { -+ wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " -+ "INTEG:%d D-H:%d", data->proposal.proposal_num, -+ data->proposal.encr, data->proposal.prf, -+ data->proposal.integ, data->proposal.dh); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_kei(struct ikev2_responder_data *data, -+ const u8 *kei, size_t kei_len) -+{ -+ u16 group; -+ -+ /* -+ * Key Exchange Payload: -+ * DH Group # (16 bits) -+ * RESERVED (16 bits) -+ * Key Exchange Data (Diffie-Hellman public value) -+ */ -+ -+ if (kei == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: KEi not received"); -+ return -1; -+ } -+ -+ if (kei_len < 4 + 96) { -+ wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload"); -+ return -1; -+ } -+ -+ group = WPA_GET_BE16(kei); -+ wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group); -+ -+ if (group != data->proposal.dh) { -+ wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match " -+ "with the selected proposal (%u)", -+ group, data->proposal.dh); -+ /* Reject message with Notify payload of type -+ * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */ -+ data->error_type = INVALID_KE_PAYLOAD; -+ data->state = NOTIFY; -+ return -1; -+ } -+ -+ if (data->dh == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); -+ return -1; -+ } -+ -+ /* RFC 4306, Section 3.4: -+ * The length of DH public value MUST be equal to the lenght of the -+ * prime modulus. -+ */ -+ if (kei_len - 4 != data->dh->prime_len) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " -+ "%ld (expected %ld)", -+ (long) (kei_len - 4), (long) data->dh->prime_len); -+ return -1; -+ } -+ -+ wpabuf_free(data->i_dh_public); -+ data->i_dh_public = wpabuf_alloc(kei_len - 4); -+ if (data->i_dh_public == NULL) -+ return -1; -+ wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4); -+ -+ wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value", -+ data->i_dh_public); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_ni(struct ikev2_responder_data *data, -+ const u8 *ni, size_t ni_len) -+{ -+ if (ni == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Ni not received"); -+ return -1; -+ } -+ -+ if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld", -+ (long) ni_len); -+ return -1; -+ } -+ -+#ifdef CCNS_PL -+ /* Zeros are removed incorrectly from the beginning of the nonces */ -+ while (ni_len > 1 && *ni == 0) { -+ ni_len--; -+ ni++; -+ } -+#endif /* CCNS_PL */ -+ -+ data->i_nonce_len = ni_len; -+ os_memcpy(data->i_nonce, ni, ni_len); -+ wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni", -+ data->i_nonce, data->i_nonce_len); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_sa_init(struct ikev2_responder_data *data, -+ const struct ikev2_hdr *hdr, -+ struct ikev2_payloads *pl) -+{ -+ if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 || -+ ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 || -+ ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0) -+ return -1; -+ -+ os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_idi(struct ikev2_responder_data *data, -+ const u8 *idi, size_t idi_len) -+{ -+ u8 id_type; -+ -+ if (idi == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No IDi received"); -+ return -1; -+ } -+ -+ if (idi_len < 4) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload"); -+ return -1; -+ } -+ -+ id_type = idi[0]; -+ idi += 4; -+ idi_len -= 4; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type); -+ wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len); -+ os_free(data->IDi); -+ data->IDi = os_malloc(idi_len); -+ if (data->IDi == NULL) -+ return -1; -+ os_memcpy(data->IDi, idi, idi_len); -+ data->IDi_len = idi_len; -+ data->IDi_type = id_type; -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_cert(struct ikev2_responder_data *data, -+ const u8 *cert, size_t cert_len) -+{ -+ u8 cert_encoding; -+ -+ if (cert == NULL) { -+ if (data->peer_auth == PEER_AUTH_CERT) { -+ wpa_printf(MSG_INFO, "IKEV2: No Certificate received"); -+ return -1; -+ } -+ return 0; -+ } -+ -+ if (cert_len < 1) { -+ wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field"); -+ return -1; -+ } -+ -+ cert_encoding = cert[0]; -+ cert++; -+ cert_len--; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding); -+ wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len); -+ -+ /* TODO: validate certificate */ -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_auth_cert(struct ikev2_responder_data *data, -+ u8 method, const u8 *auth, size_t auth_len) -+{ -+ if (method != AUTH_RSA_SIGN) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " -+ "method %d", method); -+ return -1; -+ } -+ -+ /* TODO: validate AUTH */ -+ return 0; -+} -+ -+ -+static int ikev2_process_auth_secret(struct ikev2_responder_data *data, -+ u8 method, const u8 *auth, -+ size_t auth_len) -+{ -+ u8 auth_data[IKEV2_MAX_HASH_LEN]; -+ const struct ikev2_prf_alg *prf; -+ -+ if (method != AUTH_SHARED_KEY_MIC) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " -+ "method %d", method); -+ return -1; -+ } -+ -+ /* msg | Nr | prf(SK_pi,IDi') */ -+ if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, -+ data->IDi, data->IDi_len, data->IDi_type, -+ &data->keys, 1, data->shared_secret, -+ data->shared_secret_len, -+ data->r_nonce, data->r_nonce_len, -+ data->key_pad, data->key_pad_len, -+ auth_data) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); -+ return -1; -+ } -+ -+ wpabuf_free(data->i_sign_msg); -+ data->i_sign_msg = NULL; -+ -+ prf = ikev2_get_prf(data->proposal.prf); -+ if (prf == NULL) -+ return -1; -+ -+ if (auth_len != prf->hash_len || -+ os_memcmp(auth, auth_data, auth_len) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", -+ auth, auth_len); -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", -+ auth_data, prf->hash_len); -+ data->error_type = AUTHENTICATION_FAILED; -+ data->state = NOTIFY; -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully " -+ "using shared keys"); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_auth(struct ikev2_responder_data *data, -+ const u8 *auth, size_t auth_len) -+{ -+ u8 auth_method; -+ -+ if (auth == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); -+ return -1; -+ } -+ -+ if (auth_len < 4) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " -+ "Payload"); -+ return -1; -+ } -+ -+ auth_method = auth[0]; -+ auth += 4; -+ auth_len -= 4; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); -+ wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); -+ -+ switch (data->peer_auth) { -+ case PEER_AUTH_CERT: -+ return ikev2_process_auth_cert(data, auth_method, auth, -+ auth_len); -+ case PEER_AUTH_SECRET: -+ return ikev2_process_auth_secret(data, auth_method, auth, -+ auth_len); -+ } -+ -+ return -1; -+} -+ -+ -+static int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data, -+ u8 next_payload, -+ u8 *payload, size_t payload_len) -+{ -+ struct ikev2_payloads pl; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); -+ -+ if (ikev2_parse_payloads(&pl, next_payload, payload, payload + -+ payload_len) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " -+ "payloads"); -+ return -1; -+ } -+ -+ if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 || -+ ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || -+ ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) -+ return -1; -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_sa_auth(struct ikev2_responder_data *data, -+ const struct ikev2_hdr *hdr, -+ struct ikev2_payloads *pl) -+{ -+ u8 *decrypted; -+ size_t decrypted_len; -+ int ret; -+ -+ decrypted = ikev2_decrypt_payload(data->proposal.encr, -+ data->proposal.integ, -+ &data->keys, 1, hdr, pl->encrypted, -+ pl->encrypted_len, &decrypted_len); -+ if (decrypted == NULL) -+ return -1; -+ -+ ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, -+ decrypted, decrypted_len); -+ os_free(decrypted); -+ -+ return ret; -+} -+ -+ -+static int ikev2_validate_rx_state(struct ikev2_responder_data *data, -+ u8 exchange_type, u32 message_id) -+{ -+ switch (data->state) { -+ case SA_INIT: -+ /* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */ -+ if (exchange_type != IKE_SA_INIT) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " -+ "%u in SA_INIT state", exchange_type); -+ return -1; -+ } -+ if (message_id != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " -+ "in SA_INIT state", message_id); -+ return -1; -+ } -+ break; -+ case SA_AUTH: -+ /* Expect to receive IKE_SA_AUTH: -+ * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,] -+ * AUTH, SAi2, TSi, TSr} -+ */ -+ if (exchange_type != IKE_SA_AUTH) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " -+ "%u in SA_AUTH state", exchange_type); -+ return -1; -+ } -+ if (message_id != 1) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " -+ "in SA_AUTH state", message_id); -+ return -1; -+ } -+ break; -+ case CHILD_SA: -+ if (exchange_type != CREATE_CHILD_SA) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " -+ "%u in CHILD_SA state", exchange_type); -+ return -1; -+ } -+ if (message_id != 2) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " -+ "in CHILD_SA state", message_id); -+ return -1; -+ } -+ break; -+ case NOTIFY: -+ case IKEV2_DONE: -+ case IKEV2_FAILED: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int ikev2_responder_process(struct ikev2_responder_data *data, -+ const struct wpabuf *buf) -+{ -+ const struct ikev2_hdr *hdr; -+ u32 length, message_id; -+ const u8 *pos, *end; -+ struct ikev2_payloads pl; -+ -+ wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", -+ (unsigned long) wpabuf_len(buf)); -+ -+ if (wpabuf_len(buf) < sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); -+ return -1; -+ } -+ -+ data->error_type = 0; -+ hdr = (const struct ikev2_hdr *) wpabuf_head(buf); -+ end = wpabuf_head_u8(buf) + wpabuf_len(buf); -+ message_id = WPA_GET_BE32(hdr->message_id); -+ length = WPA_GET_BE32(hdr->length); -+ -+ wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", -+ hdr->i_spi, IKEV2_SPI_LEN); -+ wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", -+ hdr->r_spi, IKEV2_SPI_LEN); -+ wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " -+ "Exchange Type: %u", -+ hdr->next_payload, hdr->version, hdr->exchange_type); -+ wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", -+ message_id, length); -+ -+ if (hdr->version != IKEV2_VERSION) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " -+ "(expected 0x%x)", hdr->version, IKEV2_VERSION); -+ return -1; -+ } -+ -+ if (length != wpabuf_len(buf)) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " -+ "RX: %lu)", (unsigned long) length, -+ (unsigned long) wpabuf_len(buf)); -+ return -1; -+ } -+ -+ if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) -+ return -1; -+ -+ if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != -+ IKEV2_HDR_INITIATOR) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", -+ hdr->flags); -+ return -1; -+ } -+ -+ if (data->state != SA_INIT) { -+ if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " -+ "Initiator's SPI"); -+ return -1; -+ } -+ if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " -+ "Responder's SPI"); -+ return -1; -+ } -+ } -+ -+ pos = (const u8 *) (hdr + 1); -+ if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) -+ return -1; -+ -+ if (data->state == SA_INIT) { -+ data->last_msg = LAST_MSG_SA_INIT; -+ if (ikev2_process_sa_init(data, hdr, &pl) < 0) { -+ if (data->state == NOTIFY) -+ return 0; -+ return -1; -+ } -+ wpabuf_free(data->i_sign_msg); -+ data->i_sign_msg = wpabuf_dup(buf); -+ } -+ -+ if (data->state == SA_AUTH) { -+ data->last_msg = LAST_MSG_SA_AUTH; -+ if (ikev2_process_sa_auth(data, hdr, &pl) < 0) { -+ if (data->state == NOTIFY) -+ return 0; -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static void ikev2_build_hdr(struct ikev2_responder_data *data, -+ struct wpabuf *msg, u8 exchange_type, -+ u8 next_payload, u32 message_id) -+{ -+ struct ikev2_hdr *hdr; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); -+ -+ /* HDR - RFC 4306, Sect. 3.1 */ -+ hdr = wpabuf_put(msg, sizeof(*hdr)); -+ os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); -+ os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); -+ hdr->next_payload = next_payload; -+ hdr->version = IKEV2_VERSION; -+ hdr->exchange_type = exchange_type; -+ hdr->flags = IKEV2_HDR_RESPONSE; -+ WPA_PUT_BE32(hdr->message_id, message_id); -+} -+ -+ -+static int ikev2_build_sar1(struct ikev2_responder_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ struct ikev2_proposal *p; -+ struct ikev2_transform *t; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload"); -+ -+ /* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ -+ p = wpabuf_put(msg, sizeof(*p)); -+#ifdef CCNS_PL -+ /* Seems to require that the Proposal # is 1 even though RFC 4306 -+ * Sect 3.3.1 has following requirement "When a proposal is accepted, -+ * all of the proposal numbers in the SA payload MUST be the same and -+ * MUST match the number on the proposal sent that was accepted.". -+ */ -+ p->proposal_num = 1; -+#else /* CCNS_PL */ -+ p->proposal_num = data->proposal.proposal_num; -+#endif /* CCNS_PL */ -+ p->protocol_id = IKEV2_PROTOCOL_IKE; -+ p->num_transforms = 4; -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ t->type = 3; -+ t->transform_type = IKEV2_TRANSFORM_ENCR; -+ WPA_PUT_BE16(t->transform_id, data->proposal.encr); -+ if (data->proposal.encr == ENCR_AES_CBC) { -+ /* Transform Attribute: Key Len = 128 bits */ -+#ifdef CCNS_PL -+ wpabuf_put_be16(msg, 0x001d); /* ?? */ -+#else /* CCNS_PL */ -+ wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ -+#endif /* CCNS_PL */ -+ wpabuf_put_be16(msg, 128); /* 128-bit key */ -+ } -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; -+ WPA_PUT_BE16(t->transform_length, plen); -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ t->type = 3; -+ WPA_PUT_BE16(t->transform_length, sizeof(*t)); -+ t->transform_type = IKEV2_TRANSFORM_PRF; -+ WPA_PUT_BE16(t->transform_id, data->proposal.prf); -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ t->type = 3; -+ WPA_PUT_BE16(t->transform_length, sizeof(*t)); -+ t->transform_type = IKEV2_TRANSFORM_INTEG; -+ WPA_PUT_BE16(t->transform_id, data->proposal.integ); -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ WPA_PUT_BE16(t->transform_length, sizeof(*t)); -+ t->transform_type = IKEV2_TRANSFORM_DH; -+ WPA_PUT_BE16(t->transform_id, data->proposal.dh); -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; -+ WPA_PUT_BE16(p->proposal_length, plen); -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ -+ return 0; -+} -+ -+ -+static int ikev2_build_ker(struct ikev2_responder_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ struct wpabuf *pv; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload"); -+ -+ pv = dh_init(data->dh, &data->r_dh_private); -+ if (pv == NULL) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); -+ return -1; -+ } -+ -+ /* KEr - RFC 4306, Sect. 3.4 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ -+ wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ -+ wpabuf_put(msg, 2); /* RESERVED */ -+ /* -+ * RFC 4306, Sect. 3.4: possible zero padding for public value to -+ * match the length of the prime. -+ */ -+ wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); -+ wpabuf_put_buf(msg, pv); -+ wpabuf_free(pv); -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static int ikev2_build_nr(struct ikev2_responder_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload"); -+ -+ /* Nr - RFC 4306, Sect. 3.9 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len); -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static int ikev2_build_idr(struct ikev2_responder_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload"); -+ -+ if (data->IDr == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No IDr available"); -+ return -1; -+ } -+ -+ /* IDr - RFC 4306, Sect. 3.5 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ wpabuf_put_u8(msg, ID_KEY_ID); -+ wpabuf_put(msg, 3); /* RESERVED */ -+ wpabuf_put_data(msg, data->IDr, data->IDr_len); -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static int ikev2_build_auth(struct ikev2_responder_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ const struct ikev2_prf_alg *prf; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); -+ -+ prf = ikev2_get_prf(data->proposal.prf); -+ if (prf == NULL) -+ return -1; -+ -+ /* Authentication - RFC 4306, Sect. 3.8 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); -+ wpabuf_put(msg, 3); /* RESERVED */ -+ -+ /* msg | Ni | prf(SK_pr,IDr') */ -+ if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, -+ data->IDr, data->IDr_len, ID_KEY_ID, -+ &data->keys, 0, data->shared_secret, -+ data->shared_secret_len, -+ data->i_nonce, data->i_nonce_len, -+ data->key_pad, data->key_pad_len, -+ wpabuf_put(msg, prf->hash_len)) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); -+ return -1; -+ } -+ wpabuf_free(data->r_sign_msg); -+ data->r_sign_msg = NULL; -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static int ikev2_build_notification(struct ikev2_responder_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload"); -+ -+ if (data->error_type == 0) { -+ wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type " -+ "available"); -+ return -1; -+ } -+ -+ /* Notify - RFC 4306, Sect. 3.10 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+#ifdef CCNS_PL -+ wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */ -+#else /* CCNS_PL */ -+ wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */ -+#endif /* CCNS_PL */ -+ wpabuf_put_u8(msg, 0); /* SPI Size */ -+ wpabuf_put_be16(msg, data->error_type); -+ -+ switch (data->error_type) { -+ case INVALID_KE_PAYLOAD: -+ if (data->proposal.dh == -1) { -+ wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for " -+ "INVALID_KE_PAYLOAD notifications"); -+ return -1; -+ } -+ wpabuf_put_be16(msg, data->proposal.dh); -+ wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request " -+ "DH Group #%d", data->proposal.dh); -+ break; -+ case AUTHENTICATION_FAILED: -+ /* no associated data */ -+ break; -+ default: -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type " -+ "%d", data->error_type); -+ return -1; -+ } -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data) -+{ -+ struct wpabuf *msg; -+ -+ /* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */ -+ -+ if (os_get_random(data->r_spi, IKEV2_SPI_LEN)) -+ return NULL; -+ wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", -+ data->r_spi, IKEV2_SPI_LEN); -+ -+ data->r_nonce_len = IKEV2_NONCE_MIN_LEN; -+ if (random_get_bytes(data->r_nonce, data->r_nonce_len)) -+ return NULL; -+#ifdef CCNS_PL -+ /* Zeros are removed incorrectly from the beginning of the nonces in -+ * key derivation; as a workaround, make sure Nr does not start with -+ * zero.. */ -+ if (data->r_nonce[0] == 0) -+ data->r_nonce[0] = 1; -+#endif /* CCNS_PL */ -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len); -+ -+ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500); -+ if (msg == NULL) -+ return NULL; -+ -+ ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); -+ if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || -+ ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) || -+ ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ? -+ IKEV2_PAYLOAD_ENCRYPTED : -+ IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ -+ if (ikev2_derive_keys(data)) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ -+ if (data->peer_auth == PEER_AUTH_CERT) { -+ /* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info -+ * for trust agents */ -+ } -+ -+ if (data->peer_auth == PEER_AUTH_SECRET) { -+ struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000); -+ if (plain == NULL) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ if (ikev2_build_idr(data, plain, -+ IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || -+ ikev2_build_encrypted(data->proposal.encr, -+ data->proposal.integ, -+ &data->keys, 0, msg, plain, -+ IKEV2_PAYLOAD_IDr)) { -+ wpabuf_free(plain); -+ wpabuf_free(msg); -+ return NULL; -+ } -+ wpabuf_free(plain); -+ } -+ -+ ikev2_update_hdr(msg); -+ -+ wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); -+ -+ data->state = SA_AUTH; -+ -+ wpabuf_free(data->r_sign_msg); -+ data->r_sign_msg = wpabuf_dup(msg); -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data) -+{ -+ struct wpabuf *msg, *plain; -+ -+ /* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */ -+ -+ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); -+ if (msg == NULL) -+ return NULL; -+ ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); -+ -+ plain = wpabuf_alloc(data->IDr_len + 1000); -+ if (plain == NULL) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ -+ if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || -+ ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || -+ ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, -+ &data->keys, 0, msg, plain, -+ IKEV2_PAYLOAD_IDr)) { -+ wpabuf_free(plain); -+ wpabuf_free(msg); -+ return NULL; -+ } -+ wpabuf_free(plain); -+ -+ wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); -+ -+ data->state = IKEV2_DONE; -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) -+{ -+ struct wpabuf *msg; -+ -+ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); -+ if (msg == NULL) -+ return NULL; -+ if (data->last_msg == LAST_MSG_SA_AUTH) { -+ /* HDR, SK{N} */ -+ struct wpabuf *plain = wpabuf_alloc(100); -+ if (plain == NULL) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ ikev2_build_hdr(data, msg, IKE_SA_AUTH, -+ IKEV2_PAYLOAD_ENCRYPTED, 1); -+ if (ikev2_build_notification(data, plain, -+ IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || -+ ikev2_build_encrypted(data->proposal.encr, -+ data->proposal.integ, -+ &data->keys, 0, msg, plain, -+ IKEV2_PAYLOAD_NOTIFICATION)) { -+ wpabuf_free(plain); -+ wpabuf_free(msg); -+ return NULL; -+ } -+ data->state = IKEV2_FAILED; -+ } else { -+ /* HDR, N */ -+ ikev2_build_hdr(data, msg, IKE_SA_INIT, -+ IKEV2_PAYLOAD_NOTIFICATION, 0); -+ if (ikev2_build_notification(data, msg, -+ IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ data->state = SA_INIT; -+ } -+ -+ ikev2_update_hdr(msg); -+ -+ wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)", -+ msg); -+ -+ return msg; -+} -+ -+ -+struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data) -+{ -+ switch (data->state) { -+ case SA_INIT: -+ return ikev2_build_sa_init(data); -+ case SA_AUTH: -+ return ikev2_build_sa_auth(data); -+ case CHILD_SA: -+ return NULL; -+ case NOTIFY: -+ return ikev2_build_notify(data); -+ case IKEV2_DONE: -+ case IKEV2_FAILED: -+ return NULL; -+ } -+ return NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.h -new file mode 100644 -index 0000000000000..9ca0ca56959d1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/ikev2.h -@@ -0,0 +1,65 @@ -+/* -+ * IKEv2 responder (RFC 4306) for EAP-IKEV2 -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IKEV2_H -+#define IKEV2_H -+ -+#include "eap_common/ikev2_common.h" -+ -+struct ikev2_proposal_data { -+ u8 proposal_num; -+ int integ; -+ int prf; -+ int encr; -+ int dh; -+}; -+ -+ -+struct ikev2_responder_data { -+ enum { SA_INIT, SA_AUTH, CHILD_SA, NOTIFY, IKEV2_DONE, IKEV2_FAILED } -+ state; -+ u8 i_spi[IKEV2_SPI_LEN]; -+ u8 r_spi[IKEV2_SPI_LEN]; -+ u8 i_nonce[IKEV2_NONCE_MAX_LEN]; -+ size_t i_nonce_len; -+ u8 r_nonce[IKEV2_NONCE_MAX_LEN]; -+ size_t r_nonce_len; -+ struct wpabuf *i_dh_public; -+ struct wpabuf *r_dh_private; -+ struct ikev2_proposal_data proposal; -+ const struct dh_group *dh; -+ struct ikev2_keys keys; -+ u8 *IDi; -+ size_t IDi_len; -+ u8 IDi_type; -+ u8 *IDr; -+ size_t IDr_len; -+ struct wpabuf *r_sign_msg; -+ struct wpabuf *i_sign_msg; -+ u8 *shared_secret; -+ size_t shared_secret_len; -+ enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth; -+ u8 *key_pad; -+ size_t key_pad_len; -+ u16 error_type; -+ enum { LAST_MSG_SA_INIT, LAST_MSG_SA_AUTH } last_msg; -+}; -+ -+ -+void ikev2_responder_deinit(struct ikev2_responder_data *data); -+int ikev2_responder_process(struct ikev2_responder_data *data, -+ const struct wpabuf *buf); -+struct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data); -+ -+#endif /* IKEV2_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.c -new file mode 100644 -index 0000000000000..b8fb07502fd73 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.c -@@ -0,0 +1,123 @@ -+/* -+ * MSCHAPV2 (RFC 2759) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/ms_funcs.h" -+#include "mschapv2.h" -+ -+const u8 * mschapv2_remove_domain(const u8 *username, size_t *len) -+{ -+ size_t i; -+ -+ /* -+ * MSCHAPv2 does not include optional domain name in the -+ * challenge-response calculation, so remove domain prefix -+ * (if present). -+ */ -+ -+ for (i = 0; i < *len; i++) { -+ if (username[i] == '\\') { -+ *len -= i + 1; -+ return username + i + 1; -+ } -+ } -+ -+ return username; -+} -+ -+ -+int mschapv2_derive_response(const u8 *identity, size_t identity_len, -+ const u8 *password, size_t password_len, -+ int pwhash, -+ const u8 *auth_challenge, -+ const u8 *peer_challenge, -+ u8 *nt_response, u8 *auth_response, -+ u8 *master_key) -+{ -+ const u8 *username; -+ size_t username_len; -+ u8 password_hash[16], password_hash_hash[16]; -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity", -+ identity, identity_len); -+ username_len = identity_len; -+ username = mschapv2_remove_domain(identity, &username_len); -+ wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username", -+ username, username_len); -+ -+ wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge", -+ auth_challenge, MSCHAPV2_CHAL_LEN); -+ wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge", -+ peer_challenge, MSCHAPV2_CHAL_LEN); -+ wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username", -+ username, username_len); -+ /* Authenticator response is not really needed yet, but calculate it -+ * here so that challenges need not be saved. */ -+ if (pwhash) { -+ wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash", -+ password, password_len); -+ generate_nt_response_pwhash(auth_challenge, peer_challenge, -+ username, username_len, -+ password, nt_response); -+ generate_authenticator_response_pwhash( -+ password, peer_challenge, auth_challenge, -+ username, username_len, nt_response, auth_response); -+ } else { -+ wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password", -+ password, password_len); -+ generate_nt_response(auth_challenge, peer_challenge, -+ username, username_len, -+ password, password_len, nt_response); -+ generate_authenticator_response(password, password_len, -+ peer_challenge, auth_challenge, -+ username, username_len, -+ nt_response, auth_response); -+ } -+ wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response", -+ nt_response, MSCHAPV2_NT_RESPONSE_LEN); -+ wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response", -+ auth_response, MSCHAPV2_AUTH_RESPONSE_LEN); -+ -+ /* Generate master_key here since we have the needed data available. */ -+ if (pwhash) { -+ if (hash_nt_password_hash(password, password_hash_hash)) -+ return -1; -+ } else { -+ if (nt_password_hash(password, password_len, password_hash) || -+ hash_nt_password_hash(password_hash, password_hash_hash)) -+ return -1; -+ } -+ get_master_key(password_hash_hash, nt_response, master_key); -+ wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key", -+ master_key, MSCHAPV2_MASTER_KEY_LEN); -+ -+ return 0; -+} -+ -+ -+int mschapv2_verify_auth_response(const u8 *auth_response, -+ const u8 *buf, size_t buf_len) -+{ -+ u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN]; -+ if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN || -+ buf[0] != 'S' || buf[1] != '=' || -+ hexstr2bin((char *) (buf + 2), recv_response, -+ MSCHAPV2_AUTH_RESPONSE_LEN) || -+ os_memcmp(auth_response, recv_response, -+ MSCHAPV2_AUTH_RESPONSE_LEN) != 0) -+ return -1; -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.h -new file mode 100644 -index 0000000000000..90dad31ef72a4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/mschapv2.h -@@ -0,0 +1,34 @@ -+/* -+ * MSCHAPV2 (RFC 2759) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef MSCHAPV2_H -+#define MSCHAPV2_H -+ -+#define MSCHAPV2_CHAL_LEN 16 -+#define MSCHAPV2_NT_RESPONSE_LEN 24 -+#define MSCHAPV2_AUTH_RESPONSE_LEN 20 -+#define MSCHAPV2_MASTER_KEY_LEN 16 -+ -+const u8 * mschapv2_remove_domain(const u8 *username, size_t *len); -+int mschapv2_derive_response(const u8 *username, size_t username_len, -+ const u8 *password, size_t password_len, -+ int pwhash, -+ const u8 *auth_challenge, -+ const u8 *peer_challenge, -+ u8 *nt_response, u8 *auth_response, -+ u8 *master_key); -+int mschapv2_verify_auth_response(const u8 *auth_response, -+ const u8 *buf, size_t buf_len); -+ -+#endif /* MSCHAPV2_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.c -new file mode 100644 -index 0000000000000..a70d70ccd6a6d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.c -@@ -0,0 +1,1369 @@ -+/* -+ * EAP-TNC - TNCC (IF-IMC and IF-TNCCS) -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#ifndef CONFIG_NATIVE_WINDOWS -+#include -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+#include "common.h" -+#include "base64.h" -+#include "tncc.h" -+#include "eap_common/eap_tlv_common.h" -+#include "eap_common/eap_defs.h" -+ -+ -+#ifdef UNICODE -+#define TSTR "%S" -+#else /* UNICODE */ -+#define TSTR "%s" -+#endif /* UNICODE */ -+ -+ -+#define TNC_CONFIG_FILE "/etc/tnc_config" -+#define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs") -+#define IF_TNCCS_START \ -+"\n" \ -+"\n" -+#define IF_TNCCS_END "\n" -+ -+/* TNC IF-IMC */ -+ -+typedef unsigned long TNC_UInt32; -+typedef unsigned char *TNC_BufferReference; -+ -+typedef TNC_UInt32 TNC_IMCID; -+typedef TNC_UInt32 TNC_ConnectionID; -+typedef TNC_UInt32 TNC_ConnectionState; -+typedef TNC_UInt32 TNC_RetryReason; -+typedef TNC_UInt32 TNC_MessageType; -+typedef TNC_MessageType *TNC_MessageTypeList; -+typedef TNC_UInt32 TNC_VendorID; -+typedef TNC_UInt32 TNC_MessageSubtype; -+typedef TNC_UInt32 TNC_Version; -+typedef TNC_UInt32 TNC_Result; -+ -+typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)( -+ TNC_IMCID imcID, -+ char *functionName, -+ void **pOutfunctionPointer); -+ -+#define TNC_RESULT_SUCCESS 0 -+#define TNC_RESULT_NOT_INITIALIZED 1 -+#define TNC_RESULT_ALREADY_INITIALIZED 2 -+#define TNC_RESULT_NO_COMMON_VERSION 3 -+#define TNC_RESULT_CANT_RETRY 4 -+#define TNC_RESULT_WONT_RETRY 5 -+#define TNC_RESULT_INVALID_PARAMETER 6 -+#define TNC_RESULT_CANT_RESPOND 7 -+#define TNC_RESULT_ILLEGAL_OPERATION 8 -+#define TNC_RESULT_OTHER 9 -+#define TNC_RESULT_FATAL 10 -+ -+#define TNC_CONNECTION_STATE_CREATE 0 -+#define TNC_CONNECTION_STATE_HANDSHAKE 1 -+#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 -+#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3 -+#define TNC_CONNECTION_STATE_ACCESS_NONE 4 -+#define TNC_CONNECTION_STATE_DELETE 5 -+ -+#define TNC_IFIMC_VERSION_1 1 -+ -+#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) -+#define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff) -+ -+/* TNCC-TNCS Message Types */ -+#define TNC_TNCCS_RECOMMENDATION 0x00000001 -+#define TNC_TNCCS_ERROR 0x00000002 -+#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003 -+#define TNC_TNCCS_REASONSTRINGS 0x00000004 -+ -+ -+/* IF-TNCCS-SOH - SSoH and SSoHR Attributes */ -+enum { -+ SSOH_MS_MACHINE_INVENTORY = 1, -+ SSOH_MS_QUARANTINE_STATE = 2, -+ SSOH_MS_PACKET_INFO = 3, -+ SSOH_MS_SYSTEMGENERATED_IDS = 4, -+ SSOH_MS_MACHINENAME = 5, -+ SSOH_MS_CORRELATIONID = 6, -+ SSOH_MS_INSTALLED_SHVS = 7, -+ SSOH_MS_MACHINE_INVENTORY_EX = 8 -+}; -+ -+struct tnc_if_imc { -+ struct tnc_if_imc *next; -+ char *name; -+ char *path; -+ void *dlhandle; /* from dlopen() */ -+ TNC_IMCID imcID; -+ TNC_ConnectionID connectionID; -+ TNC_MessageTypeList supported_types; -+ size_t num_supported_types; -+ u8 *imc_send; -+ size_t imc_send_len; -+ -+ /* Functions implemented by IMCs (with TNC_IMC_ prefix) */ -+ TNC_Result (*Initialize)( -+ TNC_IMCID imcID, -+ TNC_Version minVersion, -+ TNC_Version maxVersion, -+ TNC_Version *pOutActualVersion); -+ TNC_Result (*NotifyConnectionChange)( -+ TNC_IMCID imcID, -+ TNC_ConnectionID connectionID, -+ TNC_ConnectionState newState); -+ TNC_Result (*BeginHandshake)( -+ TNC_IMCID imcID, -+ TNC_ConnectionID connectionID); -+ TNC_Result (*ReceiveMessage)( -+ TNC_IMCID imcID, -+ TNC_ConnectionID connectionID, -+ TNC_BufferReference messageBuffer, -+ TNC_UInt32 messageLength, -+ TNC_MessageType messageType); -+ TNC_Result (*BatchEnding)( -+ TNC_IMCID imcID, -+ TNC_ConnectionID connectionID); -+ TNC_Result (*Terminate)(TNC_IMCID imcID); -+ TNC_Result (*ProvideBindFunction)( -+ TNC_IMCID imcID, -+ TNC_TNCC_BindFunctionPointer bindFunction); -+}; -+ -+struct tncc_data { -+ struct tnc_if_imc *imc; -+ unsigned int last_batchid; -+}; -+ -+#define TNC_MAX_IMC_ID 10 -+static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL }; -+ -+ -+/* TNCC functions that IMCs can call */ -+ -+TNC_Result TNC_TNCC_ReportMessageTypes( -+ TNC_IMCID imcID, -+ TNC_MessageTypeList supportedTypes, -+ TNC_UInt32 typeCount) -+{ -+ TNC_UInt32 i; -+ struct tnc_if_imc *imc; -+ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu " -+ "typeCount=%lu)", -+ (unsigned long) imcID, (unsigned long) typeCount); -+ -+ for (i = 0; i < typeCount; i++) { -+ wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", -+ i, supportedTypes[i]); -+ } -+ -+ if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ imc = tnc_imc[imcID]; -+ os_free(imc->supported_types); -+ imc->supported_types = -+ os_malloc(typeCount * sizeof(TNC_MessageType)); -+ if (imc->supported_types == NULL) -+ return TNC_RESULT_FATAL; -+ os_memcpy(imc->supported_types, supportedTypes, -+ typeCount * sizeof(TNC_MessageType)); -+ imc->num_supported_types = typeCount; -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCC_SendMessage( -+ TNC_IMCID imcID, -+ TNC_ConnectionID connectionID, -+ TNC_BufferReference message, -+ TNC_UInt32 messageLength, -+ TNC_MessageType messageType) -+{ -+ struct tnc_if_imc *imc; -+ unsigned char *b64; -+ size_t b64len; -+ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu " -+ "connectionID=%lu messageType=%lu)", -+ imcID, connectionID, messageType); -+ wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage", -+ message, messageLength); -+ -+ if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ b64 = base64_encode(message, messageLength, &b64len); -+ if (b64 == NULL) -+ return TNC_RESULT_FATAL; -+ -+ imc = tnc_imc[imcID]; -+ os_free(imc->imc_send); -+ imc->imc_send_len = 0; -+ imc->imc_send = os_zalloc(b64len + 100); -+ if (imc->imc_send == NULL) { -+ os_free(b64); -+ return TNC_RESULT_OTHER; -+ } -+ -+ imc->imc_send_len = -+ os_snprintf((char *) imc->imc_send, b64len + 100, -+ "%08X" -+ "%s", -+ (unsigned int) messageType, b64); -+ -+ os_free(b64); -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCC_RequestHandshakeRetry( -+ TNC_IMCID imcID, -+ TNC_ConnectionID connectionID, -+ TNC_RetryReason reason) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry"); -+ -+ if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ /* -+ * TODO: trigger a call to eapol_sm_request_reauth(). This would -+ * require that the IMC continues to be loaded in memory afer -+ * authentication.. -+ */ -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity, -+ const char *message) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu " -+ "severity==%lu message='%s')", -+ imcID, severity, message); -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID, -+ const char *message) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu " -+ "connectionID==%lu message='%s')", -+ imcID, connectionID, message); -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCC_BindFunction( -+ TNC_IMCID imcID, -+ char *functionName, -+ void **pOutfunctionPointer) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, " -+ "functionName='%s')", (unsigned long) imcID, functionName); -+ -+ if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ if (pOutfunctionPointer == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0) -+ *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes; -+ else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0) -+ *pOutfunctionPointer = TNC_TNCC_SendMessage; -+ else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") == -+ 0) -+ *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry; -+ else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0) -+ *pOutfunctionPointer = TNC_9048_LogMessage; -+ else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0) -+ *pOutfunctionPointer = TNC_9048_UserMessage; -+ else -+ *pOutfunctionPointer = NULL; -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+static void * tncc_get_sym(void *handle, char *func) -+{ -+ void *fptr; -+ -+#ifdef CONFIG_NATIVE_WINDOWS -+#ifdef _WIN32_WCE -+ fptr = GetProcAddressA(handle, func); -+#else /* _WIN32_WCE */ -+ fptr = GetProcAddress(handle, func); -+#endif /* _WIN32_WCE */ -+#else /* CONFIG_NATIVE_WINDOWS */ -+ fptr = dlsym(handle, func); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ return fptr; -+} -+ -+ -+static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc) -+{ -+ void *handle = imc->dlhandle; -+ -+ /* Mandatory IMC functions */ -+ imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize"); -+ if (imc->Initialize == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: IMC does not export " -+ "TNC_IMC_Initialize"); -+ return -1; -+ } -+ -+ imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake"); -+ if (imc->BeginHandshake == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: IMC does not export " -+ "TNC_IMC_BeginHandshake"); -+ return -1; -+ } -+ -+ imc->ProvideBindFunction = -+ tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction"); -+ if (imc->ProvideBindFunction == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: IMC does not export " -+ "TNC_IMC_ProvideBindFunction"); -+ return -1; -+ } -+ -+ /* Optional IMC functions */ -+ imc->NotifyConnectionChange = -+ tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange"); -+ imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage"); -+ imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding"); -+ imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate"); -+ -+ return 0; -+} -+ -+ -+static int tncc_imc_initialize(struct tnc_if_imc *imc) -+{ -+ TNC_Result res; -+ TNC_Version imc_ver; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'", -+ imc->name); -+ res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1, -+ TNC_IFIMC_VERSION_1, &imc_ver); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu", -+ (unsigned long) res, (unsigned long) imc_ver); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncc_imc_terminate(struct tnc_if_imc *imc) -+{ -+ TNC_Result res; -+ -+ if (imc->Terminate == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'", -+ imc->name); -+ res = imc->Terminate(imc->imcID); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu", -+ (unsigned long) res); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc) -+{ -+ TNC_Result res; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for " -+ "IMC '%s'", imc->name); -+ res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu", -+ (unsigned long) res); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc, -+ TNC_ConnectionState state) -+{ -+ TNC_Result res; -+ -+ if (imc->NotifyConnectionChange == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)" -+ " for IMC '%s'", (int) state, imc->name); -+ res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID, -+ state); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", -+ (unsigned long) res); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncc_imc_begin_handshake(struct tnc_if_imc *imc) -+{ -+ TNC_Result res; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC " -+ "'%s'", imc->name); -+ res = imc->BeginHandshake(imc->imcID, imc->connectionID); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu", -+ (unsigned long) res); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncc_load_imc(struct tnc_if_imc *imc) -+{ -+ if (imc->path == NULL) { -+ wpa_printf(MSG_DEBUG, "TNC: No IMC configured"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)", -+ imc->name, imc->path); -+#ifdef CONFIG_NATIVE_WINDOWS -+#ifdef UNICODE -+ { -+ TCHAR *lib = wpa_strdup_tchar(imc->path); -+ if (lib == NULL) -+ return -1; -+ imc->dlhandle = LoadLibrary(lib); -+ os_free(lib); -+ } -+#else /* UNICODE */ -+ imc->dlhandle = LoadLibrary(imc->path); -+#endif /* UNICODE */ -+ if (imc->dlhandle == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d", -+ imc->name, imc->path, (int) GetLastError()); -+ return -1; -+ } -+#else /* CONFIG_NATIVE_WINDOWS */ -+ imc->dlhandle = dlopen(imc->path, RTLD_LAZY); -+ if (imc->dlhandle == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s", -+ imc->name, imc->path, dlerror()); -+ return -1; -+ } -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ if (tncc_imc_resolve_funcs(imc) < 0) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions"); -+ return -1; -+ } -+ -+ if (tncc_imc_initialize(imc) < 0 || -+ tncc_imc_provide_bind_function(imc) < 0) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void tncc_unload_imc(struct tnc_if_imc *imc) -+{ -+ tncc_imc_terminate(imc); -+ tnc_imc[imc->imcID] = NULL; -+ -+ if (imc->dlhandle) { -+#ifdef CONFIG_NATIVE_WINDOWS -+ FreeLibrary(imc->dlhandle); -+#else /* CONFIG_NATIVE_WINDOWS */ -+ dlclose(imc->dlhandle); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ } -+ os_free(imc->name); -+ os_free(imc->path); -+ os_free(imc->supported_types); -+ os_free(imc->imc_send); -+} -+ -+ -+static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type) -+{ -+ size_t i; -+ unsigned int vendor, subtype; -+ -+ if (imc == NULL || imc->supported_types == NULL) -+ return 0; -+ -+ vendor = type >> 8; -+ subtype = type & 0xff; -+ -+ for (i = 0; i < imc->num_supported_types; i++) { -+ unsigned int svendor, ssubtype; -+ svendor = imc->supported_types[i] >> 8; -+ ssubtype = imc->supported_types[i] & 0xff; -+ if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && -+ (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type, -+ const u8 *msg, size_t len) -+{ -+ struct tnc_if_imc *imc; -+ TNC_Result res; -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len); -+ -+ for (imc = tncc->imc; imc; imc = imc->next) { -+ if (imc->ReceiveMessage == NULL || -+ !tncc_supported_type(imc, type)) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'", -+ imc->name); -+ res = imc->ReceiveMessage(imc->imcID, imc->connectionID, -+ (TNC_BufferReference) msg, len, -+ type); -+ wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", -+ (unsigned long) res); -+ } -+} -+ -+ -+void tncc_init_connection(struct tncc_data *tncc) -+{ -+ struct tnc_if_imc *imc; -+ -+ for (imc = tncc->imc; imc; imc = imc->next) { -+ tncc_imc_notify_connection_change( -+ imc, TNC_CONNECTION_STATE_CREATE); -+ tncc_imc_notify_connection_change( -+ imc, TNC_CONNECTION_STATE_HANDSHAKE); -+ -+ os_free(imc->imc_send); -+ imc->imc_send = NULL; -+ imc->imc_send_len = 0; -+ -+ tncc_imc_begin_handshake(imc); -+ } -+} -+ -+ -+size_t tncc_total_send_len(struct tncc_data *tncc) -+{ -+ struct tnc_if_imc *imc; -+ -+ size_t len = 0; -+ for (imc = tncc->imc; imc; imc = imc->next) -+ len += imc->imc_send_len; -+ return len; -+} -+ -+ -+u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos) -+{ -+ struct tnc_if_imc *imc; -+ -+ for (imc = tncc->imc; imc; imc = imc->next) { -+ if (imc->imc_send == NULL) -+ continue; -+ -+ os_memcpy(pos, imc->imc_send, imc->imc_send_len); -+ pos += imc->imc_send_len; -+ os_free(imc->imc_send); -+ imc->imc_send = NULL; -+ imc->imc_send_len = 0; -+ } -+ -+ return pos; -+} -+ -+ -+char * tncc_if_tnccs_start(struct tncc_data *tncc) -+{ -+ char *buf = os_malloc(1000); -+ if (buf == NULL) -+ return NULL; -+ tncc->last_batchid++; -+ os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid); -+ return buf; -+} -+ -+ -+char * tncc_if_tnccs_end(void) -+{ -+ char *buf = os_malloc(100); -+ if (buf == NULL) -+ return NULL; -+ os_snprintf(buf, 100, IF_TNCCS_END); -+ return buf; -+} -+ -+ -+static void tncc_notify_recommendation(struct tncc_data *tncc, -+ enum tncc_process_res res) -+{ -+ TNC_ConnectionState state; -+ struct tnc_if_imc *imc; -+ -+ switch (res) { -+ case TNCCS_RECOMMENDATION_ALLOW: -+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; -+ break; -+ case TNCCS_RECOMMENDATION_NONE: -+ state = TNC_CONNECTION_STATE_ACCESS_NONE; -+ break; -+ case TNCCS_RECOMMENDATION_ISOLATE: -+ state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; -+ break; -+ default: -+ state = TNC_CONNECTION_STATE_ACCESS_NONE; -+ break; -+ } -+ -+ for (imc = tncc->imc; imc; imc = imc->next) -+ tncc_imc_notify_connection_change(imc, state); -+} -+ -+ -+static int tncc_get_type(char *start, unsigned int *type) -+{ -+ char *pos = os_strstr(start, ""); -+ if (pos == NULL) -+ return -1; -+ pos += 6; -+ *type = strtoul(pos, NULL, 16); -+ return 0; -+} -+ -+ -+static unsigned char * tncc_get_base64(char *start, size_t *decoded_len) -+{ -+ char *pos, *pos2; -+ unsigned char *decoded; -+ -+ pos = os_strstr(start, ""); -+ if (pos == NULL) -+ return NULL; -+ -+ pos += 8; -+ pos2 = os_strstr(pos, ""); -+ if (pos2 == NULL) -+ return NULL; -+ *pos2 = '\0'; -+ -+ decoded = base64_decode((unsigned char *) pos, os_strlen(pos), -+ decoded_len); -+ *pos2 = '<'; -+ if (decoded == NULL) { -+ wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); -+ } -+ -+ return decoded; -+} -+ -+ -+static enum tncc_process_res tncc_get_recommendation(char *start) -+{ -+ char *pos, *pos2, saved; -+ int recom; -+ -+ pos = os_strstr(start, ""); -+ if (start == NULL || end == NULL || start > end) { -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ -+ start += 13; -+ while (*start == ' ') -+ start++; -+ *end = '\0'; -+ -+ pos = os_strstr(start, "BatchId="); -+ if (pos == NULL) { -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ -+ pos += 8; -+ if (*pos == '"') -+ pos++; -+ batch_id = atoi(pos); -+ wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", -+ batch_id); -+ if (batch_id != tncc->last_batchid + 1) { -+ wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " -+ "%u (expected %u)", -+ batch_id, tncc->last_batchid + 1); -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ tncc->last_batchid = batch_id; -+ -+ while (*pos != '\0' && *pos != '>') -+ pos++; -+ if (*pos == '\0') { -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ pos++; -+ payload = start; -+ -+ /* -+ * -+ * 01234567 -+ * foo== -+ * -+ */ -+ -+ while (*start) { -+ char *endpos; -+ unsigned int type; -+ -+ pos = os_strstr(start, ""); -+ if (pos == NULL) -+ break; -+ start = pos + 17; -+ end = os_strstr(start, ""); -+ if (end == NULL) -+ break; -+ *end = '\0'; -+ endpos = end; -+ end += 18; -+ -+ if (tncc_get_type(start, &type) < 0) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); -+ -+ decoded = tncc_get_base64(start, &decoded_len); -+ if (decoded == NULL) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ -+ tncc_send_to_imcs(tncc, type, decoded, decoded_len); -+ -+ os_free(decoded); -+ -+ start = end; -+ } -+ -+ /* -+ * -+ * 01234567 -+ * -+ * foo== -+ * -+ */ -+ -+ start = payload; -+ while (*start) { -+ unsigned int type; -+ char *xml, *xmlend, *endpos; -+ -+ pos = os_strstr(start, ""); -+ if (pos == NULL) -+ break; -+ start = pos + 19; -+ end = os_strstr(start, ""); -+ if (end == NULL) -+ break; -+ *end = '\0'; -+ endpos = end; -+ end += 20; -+ -+ if (tncc_get_type(start, &type) < 0) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", -+ type); -+ -+ /* Base64 OR XML */ -+ decoded = NULL; -+ xml = NULL; -+ xmlend = NULL; -+ pos = os_strstr(start, ""); -+ if (pos) { -+ pos += 5; -+ pos2 = os_strstr(pos, ""); -+ if (pos2 == NULL) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ xmlend = pos2; -+ xml = pos; -+ } else { -+ decoded = tncc_get_base64(start, &decoded_len); -+ if (decoded == NULL) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ } -+ -+ if (decoded) { -+ wpa_hexdump_ascii(MSG_MSGDUMP, -+ "TNC: TNCC-TNCS-Message Base64", -+ decoded, decoded_len); -+ os_free(decoded); -+ } -+ -+ if (xml) { -+ wpa_hexdump_ascii(MSG_MSGDUMP, -+ "TNC: TNCC-TNCS-Message XML", -+ (unsigned char *) xml, -+ xmlend - xml); -+ } -+ -+ if (type == TNC_TNCCS_RECOMMENDATION && xml) { -+ /* -+ * -+ * -+ */ -+ *xmlend = '\0'; -+ res = tncc_get_recommendation(xml); -+ *xmlend = '<'; -+ recommendation_msg = 1; -+ } -+ -+ start = end; -+ } -+ -+ os_free(buf); -+ -+ if (recommendation_msg) -+ tncc_notify_recommendation(tncc, res); -+ -+ return res; -+} -+ -+ -+#ifdef CONFIG_NATIVE_WINDOWS -+static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive) -+{ -+ HKEY hk, hk2; -+ LONG ret; -+ DWORD i; -+ struct tnc_if_imc *imc, *last; -+ int j; -+ -+ last = tncc->imc; -+ while (last && last->next) -+ last = last->next; -+ -+ ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS, -+ &hk); -+ if (ret != ERROR_SUCCESS) -+ return 0; -+ -+ for (i = 0; ; i++) { -+ TCHAR name[255], *val; -+ DWORD namelen, buflen; -+ -+ namelen = 255; -+ ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, -+ NULL); -+ -+ if (ret == ERROR_NO_MORE_ITEMS) -+ break; -+ -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x", -+ (unsigned int) ret); -+ break; -+ } -+ -+ if (namelen >= 255) -+ namelen = 255 - 1; -+ name[namelen] = '\0'; -+ -+ wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name); -+ -+ ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2); -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR -+ "'", name); -+ continue; -+ } -+ -+ ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL, -+ &buflen); -+ if (ret != ERROR_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "TNC: Could not read Path from " -+ "IMC key '" TSTR "'", name); -+ RegCloseKey(hk2); -+ continue; -+ } -+ -+ val = os_malloc(buflen); -+ if (val == NULL) { -+ RegCloseKey(hk2); -+ continue; -+ } -+ -+ ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, -+ (LPBYTE) val, &buflen); -+ if (ret != ERROR_SUCCESS) { -+ os_free(val); -+ RegCloseKey(hk2); -+ continue; -+ } -+ -+ RegCloseKey(hk2); -+ -+ wpa_unicode2ascii_inplace(val); -+ wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val); -+ -+ for (j = 0; j < TNC_MAX_IMC_ID; j++) { -+ if (tnc_imc[j] == NULL) -+ break; -+ } -+ if (j >= TNC_MAX_IMC_ID) { -+ wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); -+ os_free(val); -+ continue; -+ } -+ -+ imc = os_zalloc(sizeof(*imc)); -+ if (imc == NULL) { -+ os_free(val); -+ break; -+ } -+ -+ imc->imcID = j; -+ -+ wpa_unicode2ascii_inplace(name); -+ imc->name = os_strdup((char *) name); -+ imc->path = os_strdup((char *) val); -+ -+ os_free(val); -+ -+ if (last == NULL) -+ tncc->imc = imc; -+ else -+ last->next = imc; -+ last = imc; -+ -+ tnc_imc[imc->imcID] = imc; -+ } -+ -+ RegCloseKey(hk); -+ -+ return 0; -+} -+ -+ -+static int tncc_read_config(struct tncc_data *tncc) -+{ -+ if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 || -+ tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0) -+ return -1; -+ return 0; -+} -+ -+#else /* CONFIG_NATIVE_WINDOWS */ -+ -+static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error) -+{ -+ struct tnc_if_imc *imc; -+ char *pos, *pos2; -+ int i; -+ -+ for (i = 0; i < TNC_MAX_IMC_ID; i++) { -+ if (tnc_imc[i] == NULL) -+ break; -+ } -+ if (i >= TNC_MAX_IMC_ID) { -+ wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); -+ return NULL; -+ } -+ -+ imc = os_zalloc(sizeof(*imc)); -+ if (imc == NULL) { -+ *error = 1; -+ return NULL; -+ } -+ -+ imc->imcID = i; -+ -+ pos = start; -+ wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos); -+ if (pos + 1 >= end || *pos != '"') { -+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " -+ "(no starting quotation mark)", start); -+ os_free(imc); -+ return NULL; -+ } -+ -+ pos++; -+ pos2 = pos; -+ while (pos2 < end && *pos2 != '"') -+ pos2++; -+ if (pos2 >= end) { -+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " -+ "(no ending quotation mark)", start); -+ os_free(imc); -+ return NULL; -+ } -+ *pos2 = '\0'; -+ wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); -+ imc->name = os_strdup(pos); -+ -+ pos = pos2 + 1; -+ if (pos >= end || *pos != ' ') { -+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " -+ "(no space after name)", start); -+ os_free(imc->name); -+ os_free(imc); -+ return NULL; -+ } -+ -+ pos++; -+ wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos); -+ imc->path = os_strdup(pos); -+ tnc_imc[imc->imcID] = imc; -+ -+ return imc; -+} -+ -+ -+static int tncc_read_config(struct tncc_data *tncc) -+{ -+ char *config, *end, *pos, *line_end; -+ size_t config_len; -+ struct tnc_if_imc *imc, *last; -+ -+ last = NULL; -+ -+ config = os_readfile(TNC_CONFIG_FILE, &config_len); -+ if (config == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " -+ "file '%s'", TNC_CONFIG_FILE); -+ return -1; -+ } -+ -+ end = config + config_len; -+ for (pos = config; pos < end; pos = line_end + 1) { -+ line_end = pos; -+ while (*line_end != '\n' && *line_end != '\r' && -+ line_end < end) -+ line_end++; -+ *line_end = '\0'; -+ -+ if (os_strncmp(pos, "IMC ", 4) == 0) { -+ int error = 0; -+ -+ imc = tncc_parse_imc(pos + 4, line_end, &error); -+ if (error) -+ return -1; -+ if (imc) { -+ if (last == NULL) -+ tncc->imc = imc; -+ else -+ last->next = imc; -+ last = imc; -+ } -+ } -+ } -+ -+ os_free(config); -+ -+ return 0; -+} -+ -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ -+struct tncc_data * tncc_init(void) -+{ -+ struct tncc_data *tncc; -+ struct tnc_if_imc *imc; -+ -+ tncc = os_zalloc(sizeof(*tncc)); -+ if (tncc == NULL) -+ return NULL; -+ -+ /* TODO: -+ * move loading and Initialize() to a location that is not -+ * re-initialized for every EAP-TNC session (?) -+ */ -+ -+ if (tncc_read_config(tncc) < 0) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); -+ goto failed; -+ } -+ -+ for (imc = tncc->imc; imc; imc = imc->next) { -+ if (tncc_load_imc(imc)) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'", -+ imc->name); -+ goto failed; -+ } -+ } -+ -+ return tncc; -+ -+failed: -+ tncc_deinit(tncc); -+ return NULL; -+} -+ -+ -+void tncc_deinit(struct tncc_data *tncc) -+{ -+ struct tnc_if_imc *imc, *prev; -+ -+ imc = tncc->imc; -+ while (imc) { -+ tncc_unload_imc(imc); -+ -+ prev = imc; -+ imc = imc->next; -+ os_free(prev); -+ } -+ -+ os_free(tncc); -+} -+ -+ -+static struct wpabuf * tncc_build_soh(int ver) -+{ -+ struct wpabuf *buf; -+ u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end; -+ u8 correlation_id[24]; -+ /* TODO: get correct name */ -+ char *machinename = "wpa_supplicant@w1.fi"; -+ -+ if (os_get_random(correlation_id, sizeof(correlation_id))) -+ return NULL; -+ wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID", -+ correlation_id, sizeof(correlation_id)); -+ -+ buf = wpabuf_alloc(200); -+ if (buf == NULL) -+ return NULL; -+ -+ /* Vendor-Specific TLV (Microsoft) - SoH */ -+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ -+ tlv_len = wpabuf_put(buf, 2); /* Length */ -+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ -+ wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */ -+ tlv_len2 = wpabuf_put(buf, 2); /* Length */ -+ -+ /* SoH Header */ -+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */ -+ outer_len = wpabuf_put(buf, 2); -+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ -+ wpabuf_put_be16(buf, ver); /* Inner Type */ -+ inner_len = wpabuf_put(buf, 2); -+ -+ if (ver == 2) { -+ /* SoH Mode Sub-Header */ -+ /* Outer Type */ -+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); -+ wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */ -+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ -+ /* Value: */ -+ wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); -+ wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */ -+ wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */ -+ } -+ -+ /* SSoH TLV */ -+ /* System-Health-Id */ -+ wpabuf_put_be16(buf, 0x0002); /* Type */ -+ wpabuf_put_be16(buf, 4); /* Length */ -+ wpabuf_put_be32(buf, 79616); -+ /* Vendor-Specific Attribute */ -+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); -+ ssoh_len = wpabuf_put(buf, 2); -+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ -+ -+ /* MS-Packet-Info */ -+ wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO); -+ /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be: -+ * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP -+ * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit -+ * would not be in the specified location. -+ * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits) -+ */ -+ wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */ -+ -+ /* MS-Machine-Inventory */ -+ /* TODO: get correct values; 0 = not applicable for OS */ -+ wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY); -+ wpabuf_put_be32(buf, 0); /* osVersionMajor */ -+ wpabuf_put_be32(buf, 0); /* osVersionMinor */ -+ wpabuf_put_be32(buf, 0); /* osVersionBuild */ -+ wpabuf_put_be16(buf, 0); /* spVersionMajor */ -+ wpabuf_put_be16(buf, 0); /* spVersionMinor */ -+ wpabuf_put_be16(buf, 0); /* procArch */ -+ -+ /* MS-MachineName */ -+ wpabuf_put_u8(buf, SSOH_MS_MACHINENAME); -+ wpabuf_put_be16(buf, os_strlen(machinename) + 1); -+ wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1); -+ -+ /* MS-CorrelationId */ -+ wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID); -+ wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); -+ -+ /* MS-Quarantine-State */ -+ wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE); -+ wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */ -+ wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */ -+ wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */ -+ wpabuf_put_be16(buf, 1); /* urlLenInBytes */ -+ wpabuf_put_u8(buf, 0); /* null termination for the url */ -+ -+ /* MS-Machine-Inventory-Ex */ -+ wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX); -+ wpabuf_put_be32(buf, 0); /* Reserved -+ * (note: Windows XP SP3 uses 0xdecafbad) */ -+ wpabuf_put_u8(buf, 1); /* ProductType: Client */ -+ -+ /* Update SSoH Length */ -+ end = wpabuf_put(buf, 0); -+ WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2); -+ -+ /* TODO: SoHReportEntry TLV (zero or more) */ -+ -+ /* Update length fields */ -+ end = wpabuf_put(buf, 0); -+ WPA_PUT_BE16(tlv_len, end - tlv_len - 2); -+ WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2); -+ WPA_PUT_BE16(outer_len, end - outer_len - 2); -+ WPA_PUT_BE16(inner_len, end - inner_len - 2); -+ -+ return buf; -+} -+ -+ -+struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len) -+{ -+ const u8 *pos; -+ -+ wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len); -+ -+ if (len < 12) -+ return NULL; -+ -+ /* SoH Request */ -+ pos = data; -+ -+ /* TLV Type */ -+ if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV) -+ return NULL; -+ pos += 2; -+ -+ /* Length */ -+ if (WPA_GET_BE16(pos) < 8) -+ return NULL; -+ pos += 2; -+ -+ /* Vendor_Id */ -+ if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT) -+ return NULL; -+ pos += 4; -+ -+ /* TLV Type */ -+ if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */) -+ return NULL; -+ -+ wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received"); -+ -+ return tncc_build_soh(2); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.h -new file mode 100644 -index 0000000000000..4d42a05b9a0e2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_peer/tncc.h -@@ -0,0 +1,42 @@ -+/* -+ * EAP-TNC - TNCC (IF-IMC and IF-TNCCS) -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TNCC_H -+#define TNCC_H -+ -+struct tncc_data; -+ -+struct tncc_data * tncc_init(void); -+void tncc_deinit(struct tncc_data *tncc); -+void tncc_init_connection(struct tncc_data *tncc); -+size_t tncc_total_send_len(struct tncc_data *tncc); -+u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos); -+char * tncc_if_tnccs_start(struct tncc_data *tncc); -+char * tncc_if_tnccs_end(void); -+ -+enum tncc_process_res { -+ TNCCS_PROCESS_ERROR = -1, -+ TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0, -+ TNCCS_RECOMMENDATION_ERROR, -+ TNCCS_RECOMMENDATION_ALLOW, -+ TNCCS_RECOMMENDATION_NONE, -+ TNCCS_RECOMMENDATION_ISOLATE -+}; -+ -+enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc, -+ const u8 *msg, size_t len); -+ -+struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len); -+ -+#endif /* TNCC_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap.h -new file mode 100644 -index 0000000000000..6b2907519e148 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap.h -@@ -0,0 +1,128 @@ -+/* -+ * hostapd / EAP Full Authenticator state machine (RFC 4137) -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_H -+#define EAP_H -+ -+#include "common/defs.h" -+#include "eap_common/eap_defs.h" -+#include "eap_server/eap_methods.h" -+#include "wpabuf.h" -+ -+struct eap_sm; -+ -+#define EAP_MAX_METHODS 8 -+ -+#define EAP_TTLS_AUTH_PAP 1 -+#define EAP_TTLS_AUTH_CHAP 2 -+#define EAP_TTLS_AUTH_MSCHAP 4 -+#define EAP_TTLS_AUTH_MSCHAPV2 8 -+ -+struct eap_user { -+ struct { -+ int vendor; -+ u32 method; -+ } methods[EAP_MAX_METHODS]; -+ u8 *password; -+ size_t password_len; -+ int password_hash; /* whether password is hashed with -+ * nt_password_hash() */ -+ int phase2; -+ int force_version; -+ int ttls_auth; /* bitfield of -+ * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */ -+}; -+ -+struct eap_eapol_interface { -+ /* Lower layer to full authenticator variables */ -+ Boolean eapResp; /* shared with EAPOL Backend Authentication */ -+ struct wpabuf *eapRespData; -+ Boolean portEnabled; -+ int retransWhile; -+ Boolean eapRestart; /* shared with EAPOL Authenticator PAE */ -+ int eapSRTT; -+ int eapRTTVAR; -+ -+ /* Full authenticator to lower layer variables */ -+ Boolean eapReq; /* shared with EAPOL Backend Authentication */ -+ Boolean eapNoReq; /* shared with EAPOL Backend Authentication */ -+ Boolean eapSuccess; -+ Boolean eapFail; -+ Boolean eapTimeout; -+ struct wpabuf *eapReqData; -+ u8 *eapKeyData; -+ size_t eapKeyDataLen; -+ Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */ -+ -+ /* AAA interface to full authenticator variables */ -+ Boolean aaaEapReq; -+ Boolean aaaEapNoReq; -+ Boolean aaaSuccess; -+ Boolean aaaFail; -+ struct wpabuf *aaaEapReqData; -+ u8 *aaaEapKeyData; -+ size_t aaaEapKeyDataLen; -+ Boolean aaaEapKeyAvailable; -+ int aaaMethodTimeout; -+ -+ /* Full authenticator to AAA interface variables */ -+ Boolean aaaEapResp; -+ struct wpabuf *aaaEapRespData; -+ /* aaaIdentity -> eap_get_identity() */ -+ Boolean aaaTimeout; -+}; -+ -+struct eapol_callbacks { -+ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, -+ int phase2, struct eap_user *user); -+ const char * (*get_eap_req_id_text)(void *ctx, size_t *len); -+}; -+ -+struct eap_config { -+ void *ssl_ctx; -+ void *msg_ctx; -+ void *eap_sim_db_priv; -+ Boolean backend_auth; -+ int eap_server; -+ u16 pwd_group; -+ u8 *pac_opaque_encr_key; -+ u8 *eap_fast_a_id; -+ size_t eap_fast_a_id_len; -+ char *eap_fast_a_id_info; -+ int eap_fast_prov; -+ int pac_key_lifetime; -+ int pac_key_refresh_time; -+ int eap_sim_aka_result_ind; -+ int tnc; -+ struct wps_context *wps; -+ const struct wpabuf *assoc_wps_ie; -+ const struct wpabuf *assoc_p2p_ie; -+ const u8 *peer_addr; -+ int fragment_size; -+}; -+ -+ -+struct eap_sm * eap_server_sm_init(void *eapol_ctx, -+ struct eapol_callbacks *eapol_cb, -+ struct eap_config *eap_conf); -+void eap_server_sm_deinit(struct eap_sm *sm); -+int eap_server_sm_step(struct eap_sm *sm); -+void eap_sm_notify_cached(struct eap_sm *sm); -+void eap_sm_pending_cb(struct eap_sm *sm); -+int eap_sm_method_pending(struct eap_sm *sm); -+const u8 * eap_get_identity(struct eap_sm *sm, size_t *len); -+struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm); -+void eap_server_clear_identity(struct eap_sm *sm); -+ -+#endif /* EAP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_i.h -new file mode 100644 -index 0000000000000..daac746dce126 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_i.h -@@ -0,0 +1,201 @@ -+/* -+ * hostapd / EAP Authenticator state machine internal structures (RFC 4137) -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_I_H -+#define EAP_I_H -+ -+#include "wpabuf.h" -+#include "eap_server/eap.h" -+#include "eap_common/eap_common.h" -+ -+/* RFC 4137 - EAP Standalone Authenticator */ -+ -+/** -+ * struct eap_method - EAP method interface -+ * This structure defines the EAP method interface. Each method will need to -+ * register its own EAP type, EAP name, and set of function pointers for method -+ * specific operations. This interface is based on section 5.4 of RFC 4137. -+ */ -+struct eap_method { -+ int vendor; -+ EapType method; -+ const char *name; -+ -+ void * (*init)(struct eap_sm *sm); -+ void * (*initPickUp)(struct eap_sm *sm); -+ void (*reset)(struct eap_sm *sm, void *priv); -+ -+ struct wpabuf * (*buildReq)(struct eap_sm *sm, void *priv, u8 id); -+ int (*getTimeout)(struct eap_sm *sm, void *priv); -+ Boolean (*check)(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData); -+ void (*process)(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData); -+ Boolean (*isDone)(struct eap_sm *sm, void *priv); -+ u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len); -+ /* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt, -+ * but it is useful in implementing Policy.getDecision() */ -+ Boolean (*isSuccess)(struct eap_sm *sm, void *priv); -+ -+ /** -+ * free - Free EAP method data -+ * @method: Pointer to the method data registered with -+ * eap_server_method_register(). -+ * -+ * This function will be called when the EAP method is being -+ * unregistered. If the EAP method allocated resources during -+ * registration (e.g., allocated struct eap_method), they should be -+ * freed in this function. No other method functions will be called -+ * after this call. If this function is not defined (i.e., function -+ * pointer is %NULL), a default handler is used to release the method -+ * data with free(method). This is suitable for most cases. -+ */ -+ void (*free)(struct eap_method *method); -+ -+#define EAP_SERVER_METHOD_INTERFACE_VERSION 1 -+ /** -+ * version - Version of the EAP server method interface -+ * -+ * The EAP server method implementation should set this variable to -+ * EAP_SERVER_METHOD_INTERFACE_VERSION. This is used to verify that the -+ * EAP method is using supported API version when using dynamically -+ * loadable EAP methods. -+ */ -+ int version; -+ -+ /** -+ * next - Pointer to the next EAP method -+ * -+ * This variable is used internally in the EAP method registration code -+ * to create a linked list of registered EAP methods. -+ */ -+ struct eap_method *next; -+ -+ /** -+ * get_emsk - Get EAP method specific keying extended material (EMSK) -+ * @sm: Pointer to EAP state machine allocated with eap_sm_init() -+ * @priv: Pointer to private EAP method data from eap_method::init() -+ * @len: Pointer to a variable to store EMSK length -+ * Returns: EMSK or %NULL if not available -+ * -+ * This function can be used to get the extended keying material from -+ * the EAP method. The key may already be stored in the method-specific -+ * private data or this function may derive the key. -+ */ -+ u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); -+}; -+ -+/** -+ * struct eap_sm - EAP server state machine data -+ */ -+struct eap_sm { -+ enum { -+ EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED, -+ EAP_INTEGRITY_CHECK, EAP_METHOD_RESPONSE, EAP_METHOD_REQUEST, -+ EAP_PROPOSE_METHOD, EAP_SELECT_ACTION, EAP_SEND_REQUEST, -+ EAP_DISCARD, EAP_NAK, EAP_RETRANSMIT, EAP_SUCCESS, EAP_FAILURE, -+ EAP_TIMEOUT_FAILURE, EAP_PICK_UP_METHOD, -+ EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2, -+ EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2, -+ EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE, -+ EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2 -+ } EAP_state; -+ -+ /* Constants */ -+ int MaxRetrans; -+ -+ struct eap_eapol_interface eap_if; -+ -+ /* Full authenticator state machine local variables */ -+ -+ /* Long-term (maintained betwen packets) */ -+ EapType currentMethod; -+ int currentId; -+ enum { -+ METHOD_PROPOSED, METHOD_CONTINUE, METHOD_END -+ } methodState; -+ int retransCount; -+ struct wpabuf *lastReqData; -+ int methodTimeout; -+ -+ /* Short-term (not maintained between packets) */ -+ Boolean rxResp; -+ int respId; -+ EapType respMethod; -+ int respVendor; -+ u32 respVendorMethod; -+ Boolean ignore; -+ enum { -+ DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE, -+ DECISION_PASSTHROUGH -+ } decision; -+ -+ /* Miscellaneous variables */ -+ const struct eap_method *m; /* selected EAP method */ -+ /* not defined in RFC 4137 */ -+ Boolean changed; -+ void *eapol_ctx, *msg_ctx; -+ struct eapol_callbacks *eapol_cb; -+ void *eap_method_priv; -+ u8 *identity; -+ size_t identity_len; -+ /* Whether Phase 2 method should validate identity match */ -+ int require_identity_match; -+ int lastId; /* Identifier used in the last EAP-Packet */ -+ struct eap_user *user; -+ int user_eap_method_index; -+ int init_phase2; -+ void *ssl_ctx; -+ void *eap_sim_db_priv; -+ Boolean backend_auth; -+ Boolean update_user; -+ int eap_server; -+ -+ int num_rounds; -+ enum { -+ METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT -+ } method_pending; -+ -+ u8 *auth_challenge; -+ u8 *peer_challenge; -+ -+ u8 *pac_opaque_encr_key; -+ u8 *eap_fast_a_id; -+ size_t eap_fast_a_id_len; -+ char *eap_fast_a_id_info; -+ enum { -+ NO_PROV, ANON_PROV, AUTH_PROV, BOTH_PROV -+ } eap_fast_prov; -+ int pac_key_lifetime; -+ int pac_key_refresh_time; -+ int eap_sim_aka_result_ind; -+ int tnc; -+ u16 pwd_group; -+ struct wps_context *wps; -+ struct wpabuf *assoc_wps_ie; -+ struct wpabuf *assoc_p2p_ie; -+ -+ Boolean start_reauth; -+ -+ u8 peer_addr[ETH_ALEN]; -+ -+ /* Fragmentation size for EAP method init() handler */ -+ int fragment_size; -+}; -+ -+int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, -+ int phase2); -+void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len); -+ -+#endif /* EAP_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_methods.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_methods.h -new file mode 100644 -index 0000000000000..4a5296e584b3c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_methods.h -@@ -0,0 +1,54 @@ -+/* -+ * EAP server method registration -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_SERVER_METHODS_H -+#define EAP_SERVER_METHODS_H -+ -+#include "eap_common/eap_defs.h" -+ -+const struct eap_method * eap_server_get_eap_method(int vendor, -+ EapType method); -+struct eap_method * eap_server_method_alloc(int version, int vendor, -+ EapType method, const char *name); -+void eap_server_method_free(struct eap_method *method); -+int eap_server_method_register(struct eap_method *method); -+ -+EapType eap_server_get_type(const char *name, int *vendor); -+void eap_server_unregister_methods(void); -+const char * eap_server_get_name(int vendor, EapType type); -+ -+/* EAP server method registration calls for statically linked in methods */ -+int eap_server_identity_register(void); -+int eap_server_md5_register(void); -+int eap_server_tls_register(void); -+int eap_server_mschapv2_register(void); -+int eap_server_peap_register(void); -+int eap_server_tlv_register(void); -+int eap_server_gtc_register(void); -+int eap_server_ttls_register(void); -+int eap_server_sim_register(void); -+int eap_server_aka_register(void); -+int eap_server_aka_prime_register(void); -+int eap_server_pax_register(void); -+int eap_server_psk_register(void); -+int eap_server_sake_register(void); -+int eap_server_gpsk_register(void); -+int eap_server_vendor_test_register(void); -+int eap_server_fast_register(void); -+int eap_server_wsc_register(void); -+int eap_server_ikev2_register(void); -+int eap_server_tnc_register(void); -+int eap_server_pwd_register(void); -+ -+#endif /* EAP_SERVER_METHODS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server.c -new file mode 100644 -index 0000000000000..41416b1de92c4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server.c -@@ -0,0 +1,1384 @@ -+/* -+ * hostapd / EAP Full Authenticator state machine (RFC 4137) -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This state machine is based on the full authenticator state machine defined -+ * in RFC 4137. However, to support backend authentication in RADIUS -+ * authentication server functionality, parts of backend authenticator (also -+ * from RFC 4137) are mixed in. This functionality is enabled by setting -+ * backend_auth configuration variable to TRUE. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+#include "state_machine.h" -+#include "common/wpa_ctrl.h" -+ -+#define STATE_MACHINE_DATA struct eap_sm -+#define STATE_MACHINE_DEBUG_PREFIX "EAP" -+ -+#define EAP_MAX_AUTH_ROUNDS 50 -+ -+static void eap_user_free(struct eap_user *user); -+ -+ -+/* EAP state machines are described in RFC 4137 */ -+ -+static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, -+ int eapSRTT, int eapRTTVAR, -+ int methodTimeout); -+static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp); -+static int eap_sm_getId(const struct wpabuf *data); -+static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id); -+static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id); -+static int eap_sm_nextId(struct eap_sm *sm, int id); -+static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, -+ size_t len); -+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor); -+static int eap_sm_Policy_getDecision(struct eap_sm *sm); -+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method); -+ -+ -+static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src) -+{ -+ if (src == NULL) -+ return -1; -+ -+ wpabuf_free(*dst); -+ *dst = wpabuf_dup(src); -+ return *dst ? 0 : -1; -+} -+ -+ -+static int eap_copy_data(u8 **dst, size_t *dst_len, -+ const u8 *src, size_t src_len) -+{ -+ if (src == NULL) -+ return -1; -+ -+ os_free(*dst); -+ *dst = os_malloc(src_len); -+ if (*dst) { -+ os_memcpy(*dst, src, src_len); -+ *dst_len = src_len; -+ return 0; -+ } else { -+ *dst_len = 0; -+ return -1; -+ } -+} -+ -+#define EAP_COPY(dst, src) \ -+ eap_copy_data((dst), (dst ## Len), (src), (src ## Len)) -+ -+ -+/** -+ * eap_user_get - Fetch user information from the database -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * @identity: Identity (User-Name) of the user -+ * @identity_len: Length of identity in bytes -+ * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user -+ * Returns: 0 on success, or -1 on failure -+ * -+ * This function is used to fetch user information for EAP. The user will be -+ * selected based on the specified identity. sm->user and -+ * sm->user_eap_method_index are updated for the new user when a matching user -+ * is found. sm->user can be used to get user information (e.g., password). -+ */ -+int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, -+ int phase2) -+{ -+ struct eap_user *user; -+ -+ if (sm == NULL || sm->eapol_cb == NULL || -+ sm->eapol_cb->get_eap_user == NULL) -+ return -1; -+ -+ eap_user_free(sm->user); -+ sm->user = NULL; -+ -+ user = os_zalloc(sizeof(*user)); -+ if (user == NULL) -+ return -1; -+ -+ if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, -+ identity_len, phase2, user) != 0) { -+ eap_user_free(user); -+ return -1; -+ } -+ -+ sm->user = user; -+ sm->user_eap_method_index = 0; -+ -+ return 0; -+} -+ -+ -+SM_STATE(EAP, DISABLED) -+{ -+ SM_ENTRY(EAP, DISABLED); -+ sm->num_rounds = 0; -+} -+ -+ -+SM_STATE(EAP, INITIALIZE) -+{ -+ SM_ENTRY(EAP, INITIALIZE); -+ -+ sm->currentId = -1; -+ sm->eap_if.eapSuccess = FALSE; -+ sm->eap_if.eapFail = FALSE; -+ sm->eap_if.eapTimeout = FALSE; -+ os_free(sm->eap_if.eapKeyData); -+ sm->eap_if.eapKeyData = NULL; -+ sm->eap_if.eapKeyDataLen = 0; -+ sm->eap_if.eapKeyAvailable = FALSE; -+ sm->eap_if.eapRestart = FALSE; -+ -+ /* -+ * This is not defined in RFC 4137, but method state needs to be -+ * reseted here so that it does not remain in success state when -+ * re-authentication starts. -+ */ -+ if (sm->m && sm->eap_method_priv) { -+ sm->m->reset(sm, sm->eap_method_priv); -+ sm->eap_method_priv = NULL; -+ } -+ sm->m = NULL; -+ sm->user_eap_method_index = 0; -+ -+ if (sm->backend_auth) { -+ sm->currentMethod = EAP_TYPE_NONE; -+ /* parse rxResp, respId, respMethod */ -+ eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); -+ if (sm->rxResp) { -+ sm->currentId = sm->respId; -+ } -+ } -+ sm->num_rounds = 0; -+ sm->method_pending = METHOD_PENDING_NONE; -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED -+ MACSTR, MAC2STR(sm->peer_addr)); -+} -+ -+ -+SM_STATE(EAP, PICK_UP_METHOD) -+{ -+ SM_ENTRY(EAP, PICK_UP_METHOD); -+ -+ if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { -+ sm->currentMethod = sm->respMethod; -+ if (sm->m && sm->eap_method_priv) { -+ sm->m->reset(sm, sm->eap_method_priv); -+ sm->eap_method_priv = NULL; -+ } -+ sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF, -+ sm->currentMethod); -+ if (sm->m && sm->m->initPickUp) { -+ sm->eap_method_priv = sm->m->initPickUp(sm); -+ if (sm->eap_method_priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP: Failed to " -+ "initialize EAP method %d", -+ sm->currentMethod); -+ sm->m = NULL; -+ sm->currentMethod = EAP_TYPE_NONE; -+ } -+ } else { -+ sm->m = NULL; -+ sm->currentMethod = EAP_TYPE_NONE; -+ } -+ } -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD -+ "method=%u", sm->currentMethod); -+} -+ -+ -+SM_STATE(EAP, IDLE) -+{ -+ SM_ENTRY(EAP, IDLE); -+ -+ sm->eap_if.retransWhile = eap_sm_calculateTimeout( -+ sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, -+ sm->methodTimeout); -+} -+ -+ -+SM_STATE(EAP, RETRANSMIT) -+{ -+ SM_ENTRY(EAP, RETRANSMIT); -+ -+ sm->retransCount++; -+ if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { -+ if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) -+ sm->eap_if.eapReq = TRUE; -+ } -+} -+ -+ -+SM_STATE(EAP, RECEIVED) -+{ -+ SM_ENTRY(EAP, RECEIVED); -+ -+ /* parse rxResp, respId, respMethod */ -+ eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); -+ sm->num_rounds++; -+} -+ -+ -+SM_STATE(EAP, DISCARD) -+{ -+ SM_ENTRY(EAP, DISCARD); -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapNoReq = TRUE; -+} -+ -+ -+SM_STATE(EAP, SEND_REQUEST) -+{ -+ SM_ENTRY(EAP, SEND_REQUEST); -+ -+ sm->retransCount = 0; -+ if (sm->eap_if.eapReqData) { -+ if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) -+ { -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapReq = TRUE; -+ } else { -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapReq = FALSE; -+ } -+ } else { -+ wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapReq = FALSE; -+ sm->eap_if.eapNoReq = TRUE; -+ } -+} -+ -+ -+SM_STATE(EAP, INTEGRITY_CHECK) -+{ -+ SM_ENTRY(EAP, INTEGRITY_CHECK); -+ -+ if (sm->m->check) { -+ sm->ignore = sm->m->check(sm, sm->eap_method_priv, -+ sm->eap_if.eapRespData); -+ } -+} -+ -+ -+SM_STATE(EAP, METHOD_REQUEST) -+{ -+ SM_ENTRY(EAP, METHOD_REQUEST); -+ -+ if (sm->m == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP: method not initialized"); -+ return; -+ } -+ -+ sm->currentId = eap_sm_nextId(sm, sm->currentId); -+ wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d", -+ sm->currentId); -+ sm->lastId = sm->currentId; -+ wpabuf_free(sm->eap_if.eapReqData); -+ sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, -+ sm->currentId); -+ if (sm->m->getTimeout) -+ sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv); -+ else -+ sm->methodTimeout = 0; -+} -+ -+ -+SM_STATE(EAP, METHOD_RESPONSE) -+{ -+ SM_ENTRY(EAP, METHOD_RESPONSE); -+ -+ sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); -+ if (sm->m->isDone(sm, sm->eap_method_priv)) { -+ eap_sm_Policy_update(sm, NULL, 0); -+ os_free(sm->eap_if.eapKeyData); -+ if (sm->m->getKey) { -+ sm->eap_if.eapKeyData = sm->m->getKey( -+ sm, sm->eap_method_priv, -+ &sm->eap_if.eapKeyDataLen); -+ } else { -+ sm->eap_if.eapKeyData = NULL; -+ sm->eap_if.eapKeyDataLen = 0; -+ } -+ sm->methodState = METHOD_END; -+ } else { -+ sm->methodState = METHOD_CONTINUE; -+ } -+} -+ -+ -+SM_STATE(EAP, PROPOSE_METHOD) -+{ -+ int vendor; -+ EapType type; -+ -+ SM_ENTRY(EAP, PROPOSE_METHOD); -+ -+ type = eap_sm_Policy_getNextMethod(sm, &vendor); -+ if (vendor == EAP_VENDOR_IETF) -+ sm->currentMethod = type; -+ else -+ sm->currentMethod = EAP_TYPE_EXPANDED; -+ if (sm->m && sm->eap_method_priv) { -+ sm->m->reset(sm, sm->eap_method_priv); -+ sm->eap_method_priv = NULL; -+ } -+ sm->m = eap_server_get_eap_method(vendor, type); -+ if (sm->m) { -+ sm->eap_method_priv = sm->m->init(sm); -+ if (sm->eap_method_priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " -+ "method %d", sm->currentMethod); -+ sm->m = NULL; -+ sm->currentMethod = EAP_TYPE_NONE; -+ } -+ } -+ if (sm->currentMethod == EAP_TYPE_IDENTITY || -+ sm->currentMethod == EAP_TYPE_NOTIFICATION) -+ sm->methodState = METHOD_CONTINUE; -+ else -+ sm->methodState = METHOD_PROPOSED; -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD -+ "vendor=%u method=%u", vendor, sm->currentMethod); -+} -+ -+ -+SM_STATE(EAP, NAK) -+{ -+ const struct eap_hdr *nak; -+ size_t len = 0; -+ const u8 *pos; -+ const u8 *nak_list = NULL; -+ -+ SM_ENTRY(EAP, NAK); -+ -+ if (sm->eap_method_priv) { -+ sm->m->reset(sm, sm->eap_method_priv); -+ sm->eap_method_priv = NULL; -+ } -+ sm->m = NULL; -+ -+ nak = wpabuf_head(sm->eap_if.eapRespData); -+ if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { -+ len = be_to_host16(nak->length); -+ if (len > wpabuf_len(sm->eap_if.eapRespData)) -+ len = wpabuf_len(sm->eap_if.eapRespData); -+ pos = (const u8 *) (nak + 1); -+ len -= sizeof(*nak); -+ if (*pos == EAP_TYPE_NAK) { -+ pos++; -+ len--; -+ nak_list = pos; -+ } -+ } -+ eap_sm_Policy_update(sm, nak_list, len); -+} -+ -+ -+SM_STATE(EAP, SELECT_ACTION) -+{ -+ SM_ENTRY(EAP, SELECT_ACTION); -+ -+ sm->decision = eap_sm_Policy_getDecision(sm); -+} -+ -+ -+SM_STATE(EAP, TIMEOUT_FAILURE) -+{ -+ SM_ENTRY(EAP, TIMEOUT_FAILURE); -+ -+ sm->eap_if.eapTimeout = TRUE; -+} -+ -+ -+SM_STATE(EAP, FAILURE) -+{ -+ SM_ENTRY(EAP, FAILURE); -+ -+ wpabuf_free(sm->eap_if.eapReqData); -+ sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId); -+ wpabuf_free(sm->lastReqData); -+ sm->lastReqData = NULL; -+ sm->eap_if.eapFail = TRUE; -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE -+ MACSTR, MAC2STR(sm->peer_addr)); -+} -+ -+ -+SM_STATE(EAP, SUCCESS) -+{ -+ SM_ENTRY(EAP, SUCCESS); -+ -+ wpabuf_free(sm->eap_if.eapReqData); -+ sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId); -+ wpabuf_free(sm->lastReqData); -+ sm->lastReqData = NULL; -+ if (sm->eap_if.eapKeyData) -+ sm->eap_if.eapKeyAvailable = TRUE; -+ sm->eap_if.eapSuccess = TRUE; -+ -+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS -+ MACSTR, MAC2STR(sm->peer_addr)); -+} -+ -+ -+SM_STATE(EAP, INITIALIZE_PASSTHROUGH) -+{ -+ SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); -+ -+ wpabuf_free(sm->eap_if.aaaEapRespData); -+ sm->eap_if.aaaEapRespData = NULL; -+} -+ -+ -+SM_STATE(EAP, IDLE2) -+{ -+ SM_ENTRY(EAP, IDLE2); -+ -+ sm->eap_if.retransWhile = eap_sm_calculateTimeout( -+ sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, -+ sm->methodTimeout); -+} -+ -+ -+SM_STATE(EAP, RETRANSMIT2) -+{ -+ SM_ENTRY(EAP, RETRANSMIT2); -+ -+ sm->retransCount++; -+ if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { -+ if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) -+ sm->eap_if.eapReq = TRUE; -+ } -+} -+ -+ -+SM_STATE(EAP, RECEIVED2) -+{ -+ SM_ENTRY(EAP, RECEIVED2); -+ -+ /* parse rxResp, respId, respMethod */ -+ eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); -+} -+ -+ -+SM_STATE(EAP, DISCARD2) -+{ -+ SM_ENTRY(EAP, DISCARD2); -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapNoReq = TRUE; -+} -+ -+ -+SM_STATE(EAP, SEND_REQUEST2) -+{ -+ SM_ENTRY(EAP, SEND_REQUEST2); -+ -+ sm->retransCount = 0; -+ if (sm->eap_if.eapReqData) { -+ if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) -+ { -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapReq = TRUE; -+ } else { -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapReq = FALSE; -+ } -+ } else { -+ wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData"); -+ sm->eap_if.eapResp = FALSE; -+ sm->eap_if.eapReq = FALSE; -+ sm->eap_if.eapNoReq = TRUE; -+ } -+} -+ -+ -+SM_STATE(EAP, AAA_REQUEST) -+{ -+ SM_ENTRY(EAP, AAA_REQUEST); -+ -+ if (sm->eap_if.eapRespData == NULL) { -+ wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData"); -+ return; -+ } -+ -+ /* -+ * if (respMethod == IDENTITY) -+ * aaaIdentity = eapRespData -+ * This is already taken care of by the EAP-Identity method which -+ * stores the identity into sm->identity. -+ */ -+ -+ eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData); -+} -+ -+ -+SM_STATE(EAP, AAA_RESPONSE) -+{ -+ SM_ENTRY(EAP, AAA_RESPONSE); -+ -+ eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); -+ sm->currentId = eap_sm_getId(sm->eap_if.eapReqData); -+ sm->methodTimeout = sm->eap_if.aaaMethodTimeout; -+} -+ -+ -+SM_STATE(EAP, AAA_IDLE) -+{ -+ SM_ENTRY(EAP, AAA_IDLE); -+ -+ sm->eap_if.aaaFail = FALSE; -+ sm->eap_if.aaaSuccess = FALSE; -+ sm->eap_if.aaaEapReq = FALSE; -+ sm->eap_if.aaaEapNoReq = FALSE; -+ sm->eap_if.aaaEapResp = TRUE; -+} -+ -+ -+SM_STATE(EAP, TIMEOUT_FAILURE2) -+{ -+ SM_ENTRY(EAP, TIMEOUT_FAILURE2); -+ -+ sm->eap_if.eapTimeout = TRUE; -+} -+ -+ -+SM_STATE(EAP, FAILURE2) -+{ -+ SM_ENTRY(EAP, FAILURE2); -+ -+ eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); -+ sm->eap_if.eapFail = TRUE; -+} -+ -+ -+SM_STATE(EAP, SUCCESS2) -+{ -+ SM_ENTRY(EAP, SUCCESS2); -+ -+ eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); -+ -+ sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable; -+ if (sm->eap_if.aaaEapKeyAvailable) { -+ EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData); -+ } else { -+ os_free(sm->eap_if.eapKeyData); -+ sm->eap_if.eapKeyData = NULL; -+ sm->eap_if.eapKeyDataLen = 0; -+ } -+ -+ sm->eap_if.eapSuccess = TRUE; -+ -+ /* -+ * Start reauthentication with identity request even though we know the -+ * previously used identity. This is needed to get reauthentication -+ * started properly. -+ */ -+ sm->start_reauth = TRUE; -+} -+ -+ -+SM_STEP(EAP) -+{ -+ if (sm->eap_if.eapRestart && sm->eap_if.portEnabled) -+ SM_ENTER_GLOBAL(EAP, INITIALIZE); -+ else if (!sm->eap_if.portEnabled) -+ SM_ENTER_GLOBAL(EAP, DISABLED); -+ else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { -+ if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { -+ wpa_printf(MSG_DEBUG, "EAP: more than %d " -+ "authentication rounds - abort", -+ EAP_MAX_AUTH_ROUNDS); -+ sm->num_rounds++; -+ SM_ENTER_GLOBAL(EAP, FAILURE); -+ } -+ } else switch (sm->EAP_state) { -+ case EAP_INITIALIZE: -+ if (sm->backend_auth) { -+ if (!sm->rxResp) -+ SM_ENTER(EAP, SELECT_ACTION); -+ else if (sm->rxResp && -+ (sm->respMethod == EAP_TYPE_NAK || -+ (sm->respMethod == EAP_TYPE_EXPANDED && -+ sm->respVendor == EAP_VENDOR_IETF && -+ sm->respVendorMethod == EAP_TYPE_NAK))) -+ SM_ENTER(EAP, NAK); -+ else -+ SM_ENTER(EAP, PICK_UP_METHOD); -+ } else { -+ SM_ENTER(EAP, SELECT_ACTION); -+ } -+ break; -+ case EAP_PICK_UP_METHOD: -+ if (sm->currentMethod == EAP_TYPE_NONE) { -+ SM_ENTER(EAP, SELECT_ACTION); -+ } else { -+ SM_ENTER(EAP, METHOD_RESPONSE); -+ } -+ break; -+ case EAP_DISABLED: -+ if (sm->eap_if.portEnabled) -+ SM_ENTER(EAP, INITIALIZE); -+ break; -+ case EAP_IDLE: -+ if (sm->eap_if.retransWhile == 0) -+ SM_ENTER(EAP, RETRANSMIT); -+ else if (sm->eap_if.eapResp) -+ SM_ENTER(EAP, RECEIVED); -+ break; -+ case EAP_RETRANSMIT: -+ if (sm->retransCount > sm->MaxRetrans) -+ SM_ENTER(EAP, TIMEOUT_FAILURE); -+ else -+ SM_ENTER(EAP, IDLE); -+ break; -+ case EAP_RECEIVED: -+ if (sm->rxResp && (sm->respId == sm->currentId) && -+ (sm->respMethod == EAP_TYPE_NAK || -+ (sm->respMethod == EAP_TYPE_EXPANDED && -+ sm->respVendor == EAP_VENDOR_IETF && -+ sm->respVendorMethod == EAP_TYPE_NAK)) -+ && (sm->methodState == METHOD_PROPOSED)) -+ SM_ENTER(EAP, NAK); -+ else if (sm->rxResp && (sm->respId == sm->currentId) && -+ ((sm->respMethod == sm->currentMethod) || -+ (sm->respMethod == EAP_TYPE_EXPANDED && -+ sm->respVendor == EAP_VENDOR_IETF && -+ sm->respVendorMethod == sm->currentMethod))) -+ SM_ENTER(EAP, INTEGRITY_CHECK); -+ else { -+ wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: " -+ "rxResp=%d respId=%d currentId=%d " -+ "respMethod=%d currentMethod=%d", -+ sm->rxResp, sm->respId, sm->currentId, -+ sm->respMethod, sm->currentMethod); -+ SM_ENTER(EAP, DISCARD); -+ } -+ break; -+ case EAP_DISCARD: -+ SM_ENTER(EAP, IDLE); -+ break; -+ case EAP_SEND_REQUEST: -+ SM_ENTER(EAP, IDLE); -+ break; -+ case EAP_INTEGRITY_CHECK: -+ if (sm->ignore) -+ SM_ENTER(EAP, DISCARD); -+ else -+ SM_ENTER(EAP, METHOD_RESPONSE); -+ break; -+ case EAP_METHOD_REQUEST: -+ SM_ENTER(EAP, SEND_REQUEST); -+ break; -+ case EAP_METHOD_RESPONSE: -+ /* -+ * Note: Mechanism to allow EAP methods to wait while going -+ * through pending processing is an extension to RFC 4137 -+ * which only defines the transits to SELECT_ACTION and -+ * METHOD_REQUEST from this METHOD_RESPONSE state. -+ */ -+ if (sm->methodState == METHOD_END) -+ SM_ENTER(EAP, SELECT_ACTION); -+ else if (sm->method_pending == METHOD_PENDING_WAIT) { -+ wpa_printf(MSG_DEBUG, "EAP: Method has pending " -+ "processing - wait before proceeding to " -+ "METHOD_REQUEST state"); -+ } else if (sm->method_pending == METHOD_PENDING_CONT) { -+ wpa_printf(MSG_DEBUG, "EAP: Method has completed " -+ "pending processing - reprocess pending " -+ "EAP message"); -+ sm->method_pending = METHOD_PENDING_NONE; -+ SM_ENTER(EAP, METHOD_RESPONSE); -+ } else -+ SM_ENTER(EAP, METHOD_REQUEST); -+ break; -+ case EAP_PROPOSE_METHOD: -+ /* -+ * Note: Mechanism to allow EAP methods to wait while going -+ * through pending processing is an extension to RFC 4137 -+ * which only defines the transit to METHOD_REQUEST from this -+ * PROPOSE_METHOD state. -+ */ -+ if (sm->method_pending == METHOD_PENDING_WAIT) { -+ wpa_printf(MSG_DEBUG, "EAP: Method has pending " -+ "processing - wait before proceeding to " -+ "METHOD_REQUEST state"); -+ if (sm->user_eap_method_index > 0) -+ sm->user_eap_method_index--; -+ } else if (sm->method_pending == METHOD_PENDING_CONT) { -+ wpa_printf(MSG_DEBUG, "EAP: Method has completed " -+ "pending processing - reprocess pending " -+ "EAP message"); -+ sm->method_pending = METHOD_PENDING_NONE; -+ SM_ENTER(EAP, PROPOSE_METHOD); -+ } else -+ SM_ENTER(EAP, METHOD_REQUEST); -+ break; -+ case EAP_NAK: -+ SM_ENTER(EAP, SELECT_ACTION); -+ break; -+ case EAP_SELECT_ACTION: -+ if (sm->decision == DECISION_FAILURE) -+ SM_ENTER(EAP, FAILURE); -+ else if (sm->decision == DECISION_SUCCESS) -+ SM_ENTER(EAP, SUCCESS); -+ else if (sm->decision == DECISION_PASSTHROUGH) -+ SM_ENTER(EAP, INITIALIZE_PASSTHROUGH); -+ else -+ SM_ENTER(EAP, PROPOSE_METHOD); -+ break; -+ case EAP_TIMEOUT_FAILURE: -+ break; -+ case EAP_FAILURE: -+ break; -+ case EAP_SUCCESS: -+ break; -+ -+ case EAP_INITIALIZE_PASSTHROUGH: -+ if (sm->currentId == -1) -+ SM_ENTER(EAP, AAA_IDLE); -+ else -+ SM_ENTER(EAP, AAA_REQUEST); -+ break; -+ case EAP_IDLE2: -+ if (sm->eap_if.eapResp) -+ SM_ENTER(EAP, RECEIVED2); -+ else if (sm->eap_if.retransWhile == 0) -+ SM_ENTER(EAP, RETRANSMIT2); -+ break; -+ case EAP_RETRANSMIT2: -+ if (sm->retransCount > sm->MaxRetrans) -+ SM_ENTER(EAP, TIMEOUT_FAILURE2); -+ else -+ SM_ENTER(EAP, IDLE2); -+ break; -+ case EAP_RECEIVED2: -+ if (sm->rxResp && (sm->respId == sm->currentId)) -+ SM_ENTER(EAP, AAA_REQUEST); -+ else -+ SM_ENTER(EAP, DISCARD2); -+ break; -+ case EAP_DISCARD2: -+ SM_ENTER(EAP, IDLE2); -+ break; -+ case EAP_SEND_REQUEST2: -+ SM_ENTER(EAP, IDLE2); -+ break; -+ case EAP_AAA_REQUEST: -+ SM_ENTER(EAP, AAA_IDLE); -+ break; -+ case EAP_AAA_RESPONSE: -+ SM_ENTER(EAP, SEND_REQUEST2); -+ break; -+ case EAP_AAA_IDLE: -+ if (sm->eap_if.aaaFail) -+ SM_ENTER(EAP, FAILURE2); -+ else if (sm->eap_if.aaaSuccess) -+ SM_ENTER(EAP, SUCCESS2); -+ else if (sm->eap_if.aaaEapReq) -+ SM_ENTER(EAP, AAA_RESPONSE); -+ else if (sm->eap_if.aaaTimeout) -+ SM_ENTER(EAP, TIMEOUT_FAILURE2); -+ break; -+ case EAP_TIMEOUT_FAILURE2: -+ break; -+ case EAP_FAILURE2: -+ break; -+ case EAP_SUCCESS2: -+ break; -+ } -+} -+ -+ -+static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, -+ int eapSRTT, int eapRTTVAR, -+ int methodTimeout) -+{ -+ int rto, i; -+ -+ if (methodTimeout) { -+ /* -+ * EAP method (either internal or through AAA server, provided -+ * timeout hint. Use that as-is as a timeout for retransmitting -+ * the EAP request if no response is received. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " -+ "(from EAP method hint)", methodTimeout); -+ return methodTimeout; -+ } -+ -+ /* -+ * RFC 3748 recommends algorithms described in RFC 2988 for estimation -+ * of the retransmission timeout. This should be implemented once -+ * round-trip time measurements are available. For nowm a simple -+ * backoff mechanism is used instead if there are no EAP method -+ * specific hints. -+ * -+ * SRTT = smoothed round-trip time -+ * RTTVAR = round-trip time variation -+ * RTO = retransmission timeout -+ */ -+ -+ /* -+ * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for -+ * initial retransmission and then double the RTO to provide back off -+ * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3 -+ * modified RTOmax. -+ */ -+ rto = 3; -+ for (i = 0; i < retransCount; i++) { -+ rto *= 2; -+ if (rto >= 20) { -+ rto = 20; -+ break; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " -+ "(from dynamic back off; retransCount=%d)", -+ rto, retransCount); -+ -+ return rto; -+} -+ -+ -+static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) -+{ -+ const struct eap_hdr *hdr; -+ size_t plen; -+ -+ /* parse rxResp, respId, respMethod */ -+ sm->rxResp = FALSE; -+ sm->respId = -1; -+ sm->respMethod = EAP_TYPE_NONE; -+ sm->respVendor = EAP_VENDOR_IETF; -+ sm->respVendorMethod = EAP_TYPE_NONE; -+ -+ if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) { -+ wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p " -+ "len=%lu", resp, -+ resp ? (unsigned long) wpabuf_len(resp) : 0); -+ return; -+ } -+ -+ hdr = wpabuf_head(resp); -+ plen = be_to_host16(hdr->length); -+ if (plen > wpabuf_len(resp)) { -+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " -+ "(len=%lu plen=%lu)", -+ (unsigned long) wpabuf_len(resp), -+ (unsigned long) plen); -+ return; -+ } -+ -+ sm->respId = hdr->identifier; -+ -+ if (hdr->code == EAP_CODE_RESPONSE) -+ sm->rxResp = TRUE; -+ -+ if (plen > sizeof(*hdr)) { -+ u8 *pos = (u8 *) (hdr + 1); -+ sm->respMethod = *pos++; -+ if (sm->respMethod == EAP_TYPE_EXPANDED) { -+ if (plen < sizeof(*hdr) + 8) { -+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " -+ "expanded EAP-Packet (plen=%lu)", -+ (unsigned long) plen); -+ return; -+ } -+ sm->respVendor = WPA_GET_BE24(pos); -+ pos += 3; -+ sm->respVendorMethod = WPA_GET_BE32(pos); -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " -+ "respMethod=%u respVendor=%u respVendorMethod=%u", -+ sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, -+ sm->respVendorMethod); -+} -+ -+ -+static int eap_sm_getId(const struct wpabuf *data) -+{ -+ const struct eap_hdr *hdr; -+ -+ if (data == NULL || wpabuf_len(data) < sizeof(*hdr)) -+ return -1; -+ -+ hdr = wpabuf_head(data); -+ wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier); -+ return hdr->identifier; -+} -+ -+ -+static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id) -+{ -+ struct wpabuf *msg; -+ struct eap_hdr *resp; -+ wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id); -+ -+ msg = wpabuf_alloc(sizeof(*resp)); -+ if (msg == NULL) -+ return NULL; -+ resp = wpabuf_put(msg, sizeof(*resp)); -+ resp->code = EAP_CODE_SUCCESS; -+ resp->identifier = id; -+ resp->length = host_to_be16(sizeof(*resp)); -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id) -+{ -+ struct wpabuf *msg; -+ struct eap_hdr *resp; -+ wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id); -+ -+ msg = wpabuf_alloc(sizeof(*resp)); -+ if (msg == NULL) -+ return NULL; -+ resp = wpabuf_put(msg, sizeof(*resp)); -+ resp->code = EAP_CODE_FAILURE; -+ resp->identifier = id; -+ resp->length = host_to_be16(sizeof(*resp)); -+ -+ return msg; -+} -+ -+ -+static int eap_sm_nextId(struct eap_sm *sm, int id) -+{ -+ if (id < 0) { -+ /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a -+ * random number */ -+ id = rand() & 0xff; -+ if (id != sm->lastId) -+ return id; -+ } -+ return (id + 1) & 0xff; -+} -+ -+ -+/** -+ * eap_sm_process_nak - Process EAP-Response/Nak -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * @nak_list: Nak list (allowed methods) from the supplicant -+ * @len: Length of nak_list in bytes -+ * -+ * This function is called when EAP-Response/Nak is received from the -+ * supplicant. This can happen for both phase 1 and phase 2 authentications. -+ */ -+void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) -+{ -+ int i; -+ size_t j; -+ -+ if (sm->user == NULL) -+ return; -+ -+ wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method " -+ "index %d)", sm->user_eap_method_index); -+ -+ wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods", -+ (u8 *) sm->user->methods, -+ EAP_MAX_METHODS * sizeof(sm->user->methods[0])); -+ wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer", -+ nak_list, len); -+ -+ i = sm->user_eap_method_index; -+ while (i < EAP_MAX_METHODS && -+ (sm->user->methods[i].vendor != EAP_VENDOR_IETF || -+ sm->user->methods[i].method != EAP_TYPE_NONE)) { -+ if (sm->user->methods[i].vendor != EAP_VENDOR_IETF) -+ goto not_found; -+ for (j = 0; j < len; j++) { -+ if (nak_list[j] == sm->user->methods[i].method) { -+ break; -+ } -+ } -+ -+ if (j < len) { -+ /* found */ -+ i++; -+ continue; -+ } -+ -+ not_found: -+ /* not found - remove from the list */ -+ os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1], -+ (EAP_MAX_METHODS - i - 1) * -+ sizeof(sm->user->methods[0])); -+ sm->user->methods[EAP_MAX_METHODS - 1].vendor = -+ EAP_VENDOR_IETF; -+ sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods", -+ (u8 *) sm->user->methods, EAP_MAX_METHODS * -+ sizeof(sm->user->methods[0])); -+} -+ -+ -+static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, -+ size_t len) -+{ -+ if (nak_list == NULL || sm == NULL || sm->user == NULL) -+ return; -+ -+ if (sm->user->phase2) { -+ wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user" -+ " info was selected - reject"); -+ sm->decision = DECISION_FAILURE; -+ return; -+ } -+ -+ eap_sm_process_nak(sm, nak_list, len); -+} -+ -+ -+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor) -+{ -+ EapType next; -+ int idx = sm->user_eap_method_index; -+ -+ /* In theory, there should be no problems with starting -+ * re-authentication with something else than EAP-Request/Identity and -+ * this does indeed work with wpa_supplicant. However, at least Funk -+ * Supplicant seemed to ignore re-auth if it skipped -+ * EAP-Request/Identity. -+ * Re-auth sets currentId == -1, so that can be used here to select -+ * whether Identity needs to be requested again. */ -+ if (sm->identity == NULL || sm->currentId == -1) { -+ *vendor = EAP_VENDOR_IETF; -+ next = EAP_TYPE_IDENTITY; -+ sm->update_user = TRUE; -+ } else if (sm->user && idx < EAP_MAX_METHODS && -+ (sm->user->methods[idx].vendor != EAP_VENDOR_IETF || -+ sm->user->methods[idx].method != EAP_TYPE_NONE)) { -+ *vendor = sm->user->methods[idx].vendor; -+ next = sm->user->methods[idx].method; -+ sm->user_eap_method_index++; -+ } else { -+ *vendor = EAP_VENDOR_IETF; -+ next = EAP_TYPE_NONE; -+ } -+ wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d", -+ *vendor, next); -+ return next; -+} -+ -+ -+static int eap_sm_Policy_getDecision(struct eap_sm *sm) -+{ -+ if (!sm->eap_server && sm->identity && !sm->start_reauth) { -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH"); -+ return DECISION_PASSTHROUGH; -+ } -+ -+ if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY && -+ sm->m->isSuccess(sm, sm->eap_method_priv)) { -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> " -+ "SUCCESS"); -+ sm->update_user = TRUE; -+ return DECISION_SUCCESS; -+ } -+ -+ if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) && -+ !sm->m->isSuccess(sm, sm->eap_method_priv)) { -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> " -+ "FAILURE"); -+ sm->update_user = TRUE; -+ return DECISION_FAILURE; -+ } -+ -+ if ((sm->user == NULL || sm->update_user) && sm->identity && -+ !sm->start_reauth) { -+ /* -+ * Allow Identity method to be started once to allow identity -+ * selection hint to be sent from the authentication server, -+ * but prevent a loop of Identity requests by only allowing -+ * this to happen once. -+ */ -+ int id_req = 0; -+ if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY && -+ sm->user->methods[0].vendor == EAP_VENDOR_IETF && -+ sm->user->methods[0].method == EAP_TYPE_IDENTITY) -+ id_req = 1; -+ if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " -+ "found from database -> FAILURE"); -+ return DECISION_FAILURE; -+ } -+ if (id_req && sm->user && -+ sm->user->methods[0].vendor == EAP_VENDOR_IETF && -+ sm->user->methods[0].method == EAP_TYPE_IDENTITY) { -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: stop " -+ "identity request loop -> FAILURE"); -+ sm->update_user = TRUE; -+ return DECISION_FAILURE; -+ } -+ sm->update_user = FALSE; -+ } -+ sm->start_reauth = FALSE; -+ -+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && -+ (sm->user->methods[sm->user_eap_method_index].vendor != -+ EAP_VENDOR_IETF || -+ sm->user->methods[sm->user_eap_method_index].method != -+ EAP_TYPE_NONE)) { -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: another method " -+ "available -> CONTINUE"); -+ return DECISION_CONTINUE; -+ } -+ -+ if (sm->identity == NULL || sm->currentId == -1) { -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known " -+ "yet -> CONTINUE"); -+ return DECISION_CONTINUE; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> " -+ "FAILURE"); -+ return DECISION_FAILURE; -+} -+ -+ -+static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method) -+{ -+ return method == EAP_TYPE_IDENTITY ? TRUE : FALSE; -+} -+ -+ -+/** -+ * eap_server_sm_step - Step EAP server state machine -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * Returns: 1 if EAP state was changed or 0 if not -+ * -+ * This function advances EAP state machine to a new state to match with the -+ * current variables. This should be called whenever variables used by the EAP -+ * state machine have changed. -+ */ -+int eap_server_sm_step(struct eap_sm *sm) -+{ -+ int res = 0; -+ do { -+ sm->changed = FALSE; -+ SM_STEP_RUN(EAP); -+ if (sm->changed) -+ res = 1; -+ } while (sm->changed); -+ return res; -+} -+ -+ -+static void eap_user_free(struct eap_user *user) -+{ -+ if (user == NULL) -+ return; -+ os_free(user->password); -+ user->password = NULL; -+ os_free(user); -+} -+ -+ -+/** -+ * eap_server_sm_init - Allocate and initialize EAP server state machine -+ * @eapol_ctx: Context data to be used with eapol_cb calls -+ * @eapol_cb: Pointer to EAPOL callback functions -+ * @conf: EAP configuration -+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure -+ * -+ * This function allocates and initializes an EAP state machine. -+ */ -+struct eap_sm * eap_server_sm_init(void *eapol_ctx, -+ struct eapol_callbacks *eapol_cb, -+ struct eap_config *conf) -+{ -+ struct eap_sm *sm; -+ -+ sm = os_zalloc(sizeof(*sm)); -+ if (sm == NULL) -+ return NULL; -+ sm->eapol_ctx = eapol_ctx; -+ sm->eapol_cb = eapol_cb; -+ sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ -+ sm->ssl_ctx = conf->ssl_ctx; -+ sm->msg_ctx = conf->msg_ctx; -+ sm->eap_sim_db_priv = conf->eap_sim_db_priv; -+ sm->backend_auth = conf->backend_auth; -+ sm->eap_server = conf->eap_server; -+ if (conf->pac_opaque_encr_key) { -+ sm->pac_opaque_encr_key = os_malloc(16); -+ if (sm->pac_opaque_encr_key) { -+ os_memcpy(sm->pac_opaque_encr_key, -+ conf->pac_opaque_encr_key, 16); -+ } -+ } -+ if (conf->eap_fast_a_id) { -+ sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); -+ if (sm->eap_fast_a_id) { -+ os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id, -+ conf->eap_fast_a_id_len); -+ sm->eap_fast_a_id_len = conf->eap_fast_a_id_len; -+ } -+ } -+ if (conf->eap_fast_a_id_info) -+ sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); -+ sm->eap_fast_prov = conf->eap_fast_prov; -+ sm->pac_key_lifetime = conf->pac_key_lifetime; -+ sm->pac_key_refresh_time = conf->pac_key_refresh_time; -+ sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; -+ sm->tnc = conf->tnc; -+ sm->wps = conf->wps; -+ if (conf->assoc_wps_ie) -+ sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); -+ if (conf->assoc_p2p_ie) -+ sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie); -+ if (conf->peer_addr) -+ os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); -+ sm->fragment_size = conf->fragment_size; -+ sm->pwd_group = conf->pwd_group; -+ -+ wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); -+ -+ return sm; -+} -+ -+ -+/** -+ * eap_server_sm_deinit - Deinitialize and free an EAP server state machine -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * -+ * This function deinitializes EAP state machine and frees all allocated -+ * resources. -+ */ -+void eap_server_sm_deinit(struct eap_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAP: Server state machine removed"); -+ if (sm->m && sm->eap_method_priv) -+ sm->m->reset(sm, sm->eap_method_priv); -+ wpabuf_free(sm->eap_if.eapReqData); -+ os_free(sm->eap_if.eapKeyData); -+ wpabuf_free(sm->lastReqData); -+ wpabuf_free(sm->eap_if.eapRespData); -+ os_free(sm->identity); -+ os_free(sm->pac_opaque_encr_key); -+ os_free(sm->eap_fast_a_id); -+ os_free(sm->eap_fast_a_id_info); -+ wpabuf_free(sm->eap_if.aaaEapReqData); -+ wpabuf_free(sm->eap_if.aaaEapRespData); -+ os_free(sm->eap_if.aaaEapKeyData); -+ eap_user_free(sm->user); -+ wpabuf_free(sm->assoc_wps_ie); -+ wpabuf_free(sm->assoc_p2p_ie); -+ os_free(sm); -+} -+ -+ -+/** -+ * eap_sm_notify_cached - Notify EAP state machine of cached PMK -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * -+ * This function is called when PMKSA caching is used to skip EAP -+ * authentication. -+ */ -+void eap_sm_notify_cached(struct eap_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ -+ sm->EAP_state = EAP_SUCCESS; -+} -+ -+ -+/** -+ * eap_sm_pending_cb - EAP state machine callback for a pending EAP request -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * -+ * This function is called when data for a pending EAP-Request is received. -+ */ -+void eap_sm_pending_cb(struct eap_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received"); -+ if (sm->method_pending == METHOD_PENDING_WAIT) -+ sm->method_pending = METHOD_PENDING_CONT; -+} -+ -+ -+/** -+ * eap_sm_method_pending - Query whether EAP method is waiting for pending data -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * Returns: 1 if method is waiting for pending data or 0 if not -+ */ -+int eap_sm_method_pending(struct eap_sm *sm) -+{ -+ if (sm == NULL) -+ return 0; -+ return sm->method_pending == METHOD_PENDING_WAIT; -+} -+ -+ -+/** -+ * eap_get_identity - Get the user identity (from EAP-Response/Identity) -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * @len: Buffer for returning identity length -+ * Returns: Pointer to the user identity or %NULL if not available -+ */ -+const u8 * eap_get_identity(struct eap_sm *sm, size_t *len) -+{ -+ *len = sm->identity_len; -+ return sm->identity; -+} -+ -+ -+/** -+ * eap_get_interface - Get pointer to EAP-EAPOL interface data -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * Returns: Pointer to the EAP-EAPOL interface data -+ */ -+struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm) -+{ -+ return &sm->eap_if; -+} -+ -+ -+/** -+ * eap_server_clear_identity - Clear EAP identity information -+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() -+ * -+ * This function can be used to clear the EAP identity information in the EAP -+ * server context. This allows the EAP/Identity method to be used again after -+ * EAPOL-Start or EAPOL-Logoff. -+ */ -+void eap_server_clear_identity(struct eap_sm *sm) -+{ -+ os_free(sm->identity); -+ sm->identity = NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_aka.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_aka.c -new file mode 100644 -index 0000000000000..42cbdce404a1b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_aka.c -@@ -0,0 +1,1278 @@ -+/* -+ * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf) -+ * Copyright (c) 2005-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha256.h" -+#include "crypto/crypto.h" -+#include "crypto/random.h" -+#include "eap_common/eap_sim_common.h" -+#include "eap_server/eap_i.h" -+#include "eap_server/eap_sim_db.h" -+ -+ -+struct eap_aka_data { -+ u8 mk[EAP_SIM_MK_LEN]; -+ u8 nonce_s[EAP_SIM_NONCE_S_LEN]; -+ u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; -+ u8 k_encr[EAP_SIM_K_ENCR_LEN]; -+ u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */ -+ u8 msk[EAP_SIM_KEYING_DATA_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 rand[EAP_AKA_RAND_LEN]; -+ u8 autn[EAP_AKA_AUTN_LEN]; -+ u8 ck[EAP_AKA_CK_LEN]; -+ u8 ik[EAP_AKA_IK_LEN]; -+ u8 res[EAP_AKA_RES_MAX_LEN]; -+ size_t res_len; -+ enum { -+ IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE -+ } state; -+ char *next_pseudonym; -+ char *next_reauth_id; -+ u16 counter; -+ struct eap_sim_reauth *reauth; -+ int auts_reported; /* whether the current AUTS has been reported to the -+ * eap_sim_db */ -+ u16 notification; -+ int use_result_ind; -+ -+ struct wpabuf *id_msgs; -+ int pending_id; -+ u8 eap_method; -+ u8 *network_name; -+ size_t network_name_len; -+ u16 kdf; -+}; -+ -+ -+static void eap_aka_determine_identity(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ int before_identity, int after_reauth); -+ -+ -+static const char * eap_aka_state_txt(int state) -+{ -+ switch (state) { -+ case IDENTITY: -+ return "IDENTITY"; -+ case CHALLENGE: -+ return "CHALLENGE"; -+ case REAUTH: -+ return "REAUTH"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ case NOTIFICATION: -+ return "NOTIFICATION"; -+ default: -+ return "Unknown?!"; -+ } -+} -+ -+ -+static void eap_aka_state(struct eap_aka_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s", -+ eap_aka_state_txt(data->state), -+ eap_aka_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_aka_init(struct eap_sm *sm) -+{ -+ struct eap_aka_data *data; -+ -+ if (sm->eap_sim_db_priv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ data->eap_method = EAP_TYPE_AKA; -+ -+ data->state = IDENTITY; -+ eap_aka_determine_identity(sm, data, 1, 0); -+ data->pending_id = -1; -+ -+ return data; -+} -+ -+ -+#ifdef EAP_SERVER_AKA_PRIME -+static void * eap_aka_prime_init(struct eap_sm *sm) -+{ -+ struct eap_aka_data *data; -+ /* TODO: make ANID configurable; see 3GPP TS 24.302 */ -+ char *network_name = "WLAN"; -+ -+ if (sm->eap_sim_db_priv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ data->eap_method = EAP_TYPE_AKA_PRIME; -+ data->network_name = os_malloc(os_strlen(network_name)); -+ if (data->network_name == NULL) { -+ os_free(data); -+ return NULL; -+ } -+ -+ data->network_name_len = os_strlen(network_name); -+ os_memcpy(data->network_name, network_name, data->network_name_len); -+ -+ data->state = IDENTITY; -+ eap_aka_determine_identity(sm, data, 1, 0); -+ data->pending_id = -1; -+ -+ return data; -+} -+#endif /* EAP_SERVER_AKA_PRIME */ -+ -+ -+static void eap_aka_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ os_free(data->next_pseudonym); -+ os_free(data->next_reauth_id); -+ wpabuf_free(data->id_msgs); -+ os_free(data->network_name); -+ os_free(data); -+} -+ -+ -+static int eap_aka_add_id_msg(struct eap_aka_data *data, -+ const struct wpabuf *msg) -+{ -+ if (msg == NULL) -+ return -1; -+ -+ if (data->id_msgs == NULL) { -+ data->id_msgs = wpabuf_dup(msg); -+ return data->id_msgs == NULL ? -1 : 0; -+ } -+ -+ if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0) -+ return -1; -+ wpabuf_put_buf(data->id_msgs, msg); -+ -+ return 0; -+} -+ -+ -+static void eap_aka_add_checkcode(struct eap_aka_data *data, -+ struct eap_sim_msg *msg) -+{ -+ const u8 *addr; -+ size_t len; -+ u8 hash[SHA256_MAC_LEN]; -+ -+ wpa_printf(MSG_DEBUG, " AT_CHECKCODE"); -+ -+ if (data->id_msgs == NULL) { -+ /* -+ * No EAP-AKA/Identity packets were exchanged - send empty -+ * checkcode. -+ */ -+ eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, NULL, 0); -+ return; -+ } -+ -+ /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ -+ addr = wpabuf_head(data->id_msgs); -+ len = wpabuf_len(data->id_msgs); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len); -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) -+ sha256_vector(1, &addr, &len, hash); -+ else -+ sha1_vector(1, &addr, &len, hash); -+ -+ eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash, -+ data->eap_method == EAP_TYPE_AKA_PRIME ? -+ EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN); -+} -+ -+ -+static int eap_aka_verify_checkcode(struct eap_aka_data *data, -+ const u8 *checkcode, size_t checkcode_len) -+{ -+ const u8 *addr; -+ size_t len; -+ u8 hash[SHA256_MAC_LEN]; -+ size_t hash_len; -+ -+ if (checkcode == NULL) -+ return -1; -+ -+ if (data->id_msgs == NULL) { -+ if (checkcode_len != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer " -+ "indicates that AKA/Identity messages were " -+ "used, but they were not"); -+ return -1; -+ } -+ return 0; -+ } -+ -+ hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ? -+ EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN; -+ -+ if (checkcode_len != hash_len) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates " -+ "that AKA/Identity message were not used, but they " -+ "were"); -+ return -1; -+ } -+ -+ /* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */ -+ addr = wpabuf_head(data->id_msgs); -+ len = wpabuf_len(data->id_msgs); -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) -+ sha256_vector(1, &addr, &len, hash); -+ else -+ sha1_vector(1, &addr, &len, hash); -+ -+ if (os_memcmp(hash, checkcode, hash_len) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, -+ struct eap_aka_data *data, u8 id) -+{ -+ struct eap_sim_msg *msg; -+ struct wpabuf *buf; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity"); -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, -+ EAP_AKA_SUBTYPE_IDENTITY); -+ if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len)) { -+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); -+ } else { -+ /* -+ * RFC 4187, Chap. 4.1.4 recommends that identity from EAP is -+ * ignored and the AKA/Identity is used to request the -+ * identity. -+ */ -+ wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); -+ } -+ buf = eap_sim_msg_finish(msg, NULL, NULL, 0); -+ if (eap_aka_add_id_msg(data, buf) < 0) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ data->pending_id = id; -+ return buf; -+} -+ -+ -+static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, -+ struct eap_sim_msg *msg, u16 counter, -+ const u8 *nonce_s) -+{ -+ os_free(data->next_pseudonym); -+ data->next_pseudonym = -+ eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1); -+ os_free(data->next_reauth_id); -+ if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { -+ data->next_reauth_id = -+ eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " -+ "count exceeded - force full authentication"); -+ data->next_reauth_id = NULL; -+ } -+ -+ if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && -+ counter == 0 && nonce_s == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); -+ -+ if (counter > 0) { -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); -+ } -+ -+ if (nonce_s) { -+ wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, -+ EAP_SIM_NONCE_S_LEN); -+ } -+ -+ if (data->next_pseudonym) { -+ wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", -+ data->next_pseudonym); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, -+ os_strlen(data->next_pseudonym), -+ (u8 *) data->next_pseudonym, -+ os_strlen(data->next_pseudonym)); -+ } -+ -+ if (data->next_reauth_id) { -+ wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", -+ data->next_reauth_id); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, -+ os_strlen(data->next_reauth_id), -+ (u8 *) data->next_reauth_id, -+ os_strlen(data->next_reauth_id)); -+ } -+ -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt " -+ "AT_ENCR_DATA"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge"); -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, -+ EAP_AKA_SUBTYPE_CHALLENGE); -+ wpa_printf(MSG_DEBUG, " AT_RAND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN); -+ wpa_printf(MSG_DEBUG, " AT_AUTN"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN); -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ if (data->kdf) { -+ /* Add the selected KDF into the beginning */ -+ wpa_printf(MSG_DEBUG, " AT_KDF"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf, -+ NULL, 0); -+ } -+ wpa_printf(MSG_DEBUG, " AT_KDF"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF, -+ NULL, 0); -+ wpa_printf(MSG_DEBUG, " AT_KDF_INPUT"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT, -+ data->network_name_len, -+ data->network_name, data->network_name_len); -+ } -+ -+ if (eap_aka_build_encr(sm, data, msg, 0, NULL)) { -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ -+ eap_aka_add_checkcode(data, msg); -+ -+ if (sm->eap_sim_aka_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ -+#ifdef EAP_SERVER_AKA_PRIME -+ if (data->eap_method == EAP_TYPE_AKA) { -+ u16 flags = 0; -+ int i; -+ int aka_prime_preferred = 0; -+ -+ i = 0; -+ while (sm->user && i < EAP_MAX_METHODS && -+ (sm->user->methods[i].vendor != EAP_VENDOR_IETF || -+ sm->user->methods[i].method != EAP_TYPE_NONE)) { -+ if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) { -+ if (sm->user->methods[i].method == -+ EAP_TYPE_AKA) -+ break; -+ if (sm->user->methods[i].method == -+ EAP_TYPE_AKA_PRIME) { -+ aka_prime_preferred = 1; -+ break; -+ } -+ } -+ i++; -+ } -+ -+ if (aka_prime_preferred) -+ flags |= EAP_AKA_BIDDING_FLAG_D; -+ eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); -+ } -+#endif /* EAP_SERVER_AKA_PRIME */ -+ -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, -+ struct eap_aka_data *data, u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication"); -+ -+ if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) -+ return NULL; -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S", -+ data->nonce_s, EAP_SIM_NONCE_S_LEN); -+ -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ eap_aka_prime_derive_keys_reauth(data->k_re, data->counter, -+ sm->identity, -+ sm->identity_len, -+ data->nonce_s, -+ data->msk, data->emsk); -+ } else { -+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, -+ data->msk, data->emsk); -+ eap_sim_derive_keys_reauth(data->counter, sm->identity, -+ sm->identity_len, data->nonce_s, -+ data->mk, data->msk, data->emsk); -+ } -+ -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, -+ EAP_AKA_SUBTYPE_REAUTHENTICATION); -+ -+ if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) { -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ -+ eap_aka_add_checkcode(data, msg); -+ -+ if (sm->eap_sim_aka_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification"); -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method, -+ EAP_AKA_SUBTYPE_NOTIFICATION); -+ wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, -+ NULL, 0); -+ if (data->use_result_ind) { -+ if (data->reauth) { -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, -+ EAP_SIM_AT_ENCR_DATA); -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", -+ data->counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, -+ NULL, 0); -+ -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, -+ EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to " -+ "encrypt AT_ENCR_DATA"); -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ } -+ return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_aka_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_aka_data *data = priv; -+ -+ data->auts_reported = 0; -+ switch (data->state) { -+ case IDENTITY: -+ return eap_aka_build_identity(sm, data, id); -+ case CHALLENGE: -+ return eap_aka_build_challenge(sm, data, id); -+ case REAUTH: -+ return eap_aka_build_reauth(sm, data, id); -+ case NOTIFICATION: -+ return eap_aka_build_notification(sm, data, id); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " -+ "buildReq", data->state); -+ break; -+ } -+ return NULL; -+} -+ -+ -+static Boolean eap_aka_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_aka_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, -+ &len); -+ if (pos == NULL || len < 3) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype) -+{ -+ if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR || -+ subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) -+ return FALSE; -+ -+ switch (data->state) { -+ case IDENTITY: -+ if (subtype != EAP_AKA_SUBTYPE_IDENTITY) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ case CHALLENGE: -+ if (subtype != EAP_AKA_SUBTYPE_CHALLENGE && -+ subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ case REAUTH: -+ if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ case NOTIFICATION: -+ if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for " -+ "processing a response", data->state); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_aka_determine_identity(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ int before_identity, int after_reauth) -+{ -+ const u8 *identity; -+ size_t identity_len; -+ int res; -+ -+ identity = NULL; -+ identity_len = 0; -+ -+ if (after_reauth && data->reauth) { -+ identity = data->reauth->identity; -+ identity_len = data->reauth->identity_len; -+ } else if (sm->identity && sm->identity_len > 0 && -+ sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) { -+ identity = sm->identity; -+ identity_len = sm->identity_len; -+ } else { -+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, -+ sm->identity, -+ sm->identity_len, -+ &identity_len); -+ if (identity == NULL) { -+ data->reauth = eap_sim_db_get_reauth_entry( -+ sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len); -+ if (data->reauth && -+ data->reauth->aka_prime != -+ (data->eap_method == EAP_TYPE_AKA_PRIME)) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data " -+ "was for different AKA version"); -+ data->reauth = NULL; -+ } -+ if (data->reauth) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast " -+ "re-authentication"); -+ identity = data->reauth->identity; -+ identity_len = data->reauth->identity_len; -+ data->counter = data->reauth->counter; -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ os_memcpy(data->k_encr, -+ data->reauth->k_encr, -+ EAP_SIM_K_ENCR_LEN); -+ os_memcpy(data->k_aut, -+ data->reauth->k_aut, -+ EAP_AKA_PRIME_K_AUT_LEN); -+ os_memcpy(data->k_re, -+ data->reauth->k_re, -+ EAP_AKA_PRIME_K_RE_LEN); -+ } else { -+ os_memcpy(data->mk, data->reauth->mk, -+ EAP_SIM_MK_LEN); -+ } -+ } -+ } -+ } -+ -+ if (identity == NULL || -+ eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len) < 0) { -+ if (before_identity) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name " -+ "not known - send AKA-Identity request"); -+ eap_aka_state(data, IDENTITY); -+ return; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the " -+ "permanent user name is known; try to use " -+ "it"); -+ /* eap_sim_db_get_aka_auth() will report failure, if -+ * this identity is not known. */ -+ } -+ } -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity", -+ identity, identity_len); -+ -+ if (!after_reauth && data->reauth) { -+ eap_aka_state(data, REAUTH); -+ return; -+ } -+ -+ res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity, -+ identity_len, data->rand, data->autn, -+ data->ik, data->ck, data->res, -+ &data->res_len, sm); -+ if (res == EAP_SIM_DB_PENDING) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " -+ "not yet available - pending request"); -+ sm->method_pending = METHOD_PENDING_WAIT; -+ return; -+ } -+ -+#ifdef EAP_SERVER_AKA_PRIME -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ /* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the -+ * needed 6-octet SQN ^AK for CK',IK' derivation */ -+ eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik, -+ data->autn, -+ data->network_name, -+ data->network_name_len); -+ } -+#endif /* EAP_SERVER_AKA_PRIME */ -+ -+ data->reauth = NULL; -+ data->counter = 0; /* reset re-auth counter since this is full auth */ -+ -+ if (res != 0) { -+ wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA " -+ "authentication data for the peer"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ if (sm->method_pending == METHOD_PENDING_WAIT) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data " -+ "available - abort pending wait"); -+ sm->method_pending = METHOD_PENDING_NONE; -+ } -+ -+ identity_len = sm->identity_len; -+ while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Workaround - drop last null " -+ "character from identity"); -+ identity_len--; -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation", -+ sm->identity, identity_len); -+ -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+ eap_aka_prime_derive_keys(identity, identity_len, data->ik, -+ data->ck, data->k_encr, data->k_aut, -+ data->k_re, data->msk, data->emsk); -+ } else { -+ eap_aka_derive_mk(sm->identity, identity_len, data->ik, -+ data->ck, data->mk); -+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, -+ data->msk, data->emsk); -+ } -+ -+ eap_aka_state(data, CHALLENGE); -+} -+ -+ -+static void eap_aka_process_identity(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity"); -+ -+ if (attr->mac || attr->iv || attr->encr_data) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute " -+ "received in EAP-Response/AKA-Identity"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ -+ if (attr->identity) { -+ os_free(sm->identity); -+ sm->identity = os_malloc(attr->identity_len); -+ if (sm->identity) { -+ os_memcpy(sm->identity, attr->identity, -+ attr->identity_len); -+ sm->identity_len = attr->identity_len; -+ } -+ } -+ -+ eap_aka_determine_identity(sm, data, 0, 0); -+ if (eap_get_id(respData) == data->pending_id) { -+ data->pending_id = -1; -+ eap_aka_add_id_msg(data, respData); -+ } -+} -+ -+ -+static int eap_aka_verify_mac(struct eap_aka_data *data, -+ const struct wpabuf *req, -+ const u8 *mac, const u8 *extra, -+ size_t extra_len) -+{ -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) -+ return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra, -+ extra_len); -+ return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len); -+} -+ -+ -+static void eap_aka_process_challenge(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ const u8 *identity; -+ size_t identity_len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge"); -+ -+#ifdef EAP_SERVER_AKA_PRIME -+#if 0 -+ /* KDF negotiation; to be enabled only after more than one KDF is -+ * supported */ -+ if (data->eap_method == EAP_TYPE_AKA_PRIME && -+ attr->kdf_count == 1 && attr->mac == NULL) { -+ if (attr->kdf[0] != EAP_AKA_PRIME_KDF) { -+ wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected " -+ "unknown KDF"); -+ data->notification = -+ EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ -+ data->kdf = attr->kdf[0]; -+ -+ /* Allow negotiation to continue with the selected KDF by -+ * sending another Challenge message */ -+ wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); -+ return; -+ } -+#endif -+#endif /* EAP_SERVER_AKA_PRIME */ -+ -+ if (attr->checkcode && -+ eap_aka_verify_checkcode(data, attr->checkcode, -+ attr->checkcode_len)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Invalid AT_CHECKCODE in the " -+ "message"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ if (attr->mac == NULL || -+ eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message " -+ "did not include valid AT_MAC"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ -+ /* -+ * AT_RES is padded, so verify that there is enough room for RES and -+ * that the RES length in bits matches with the expected RES. -+ */ -+ if (attr->res == NULL || attr->res_len < data->res_len || -+ attr->res_len_bits != data->res_len * 8 || -+ os_memcmp(attr->res, data->res, data->res_len) != 0) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " -+ "include valid AT_RES (attr len=%lu, res len=%lu " -+ "bits, expected %lu bits)", -+ (unsigned long) attr->res_len, -+ (unsigned long) attr->res_len_bits, -+ (unsigned long) data->res_len * 8); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the " -+ "correct AT_MAC"); -+ if (sm->eap_sim_aka_result_ind && attr->result_ind) { -+ data->use_result_ind = 1; -+ data->notification = EAP_SIM_SUCCESS; -+ eap_aka_state(data, NOTIFICATION); -+ } else -+ eap_aka_state(data, SUCCESS); -+ -+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len, &identity_len); -+ if (identity == NULL) { -+ identity = sm->identity; -+ identity_len = sm->identity_len; -+ } -+ -+ if (data->next_pseudonym) { -+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, -+ identity_len, -+ data->next_pseudonym); -+ data->next_pseudonym = NULL; -+ } -+ if (data->next_reauth_id) { -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+#ifdef EAP_SERVER_AKA_PRIME -+ eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, -+ identity, -+ identity_len, -+ data->next_reauth_id, -+ data->counter + 1, -+ data->k_encr, data->k_aut, -+ data->k_re); -+#endif /* EAP_SERVER_AKA_PRIME */ -+ } else { -+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, -+ identity_len, -+ data->next_reauth_id, -+ data->counter + 1, -+ data->mk); -+ } -+ data->next_reauth_id = NULL; -+ } -+} -+ -+ -+static void eap_aka_process_sync_failure(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure"); -+ -+ if (attr->auts == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure " -+ "message did not include valid AT_AUTS"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ -+ /* Avoid re-reporting AUTS when processing pending EAP packet by -+ * maintaining a local flag stating whether this AUTS has already been -+ * reported. */ -+ if (!data->auts_reported && -+ eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len, attr->auts, -+ data->rand)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ data->auts_reported = 1; -+ -+ /* Try again after resynchronization */ -+ eap_aka_determine_identity(sm, data, 0, 0); -+} -+ -+ -+static void eap_aka_process_reauth(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ struct eap_sim_attrs eattr; -+ u8 *decrypted = NULL; -+ const u8 *identity, *id2; -+ size_t identity_len, id2_len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication"); -+ -+ if (attr->mac == NULL || -+ eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s, -+ EAP_SIM_NONCE_S_LEN)) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " -+ "did not include valid AT_MAC"); -+ goto fail; -+ } -+ -+ if (attr->encr_data == NULL || attr->iv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication " -+ "message did not include encrypted data"); -+ goto fail; -+ } -+ -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, &eattr, -+ 0); -+ if (decrypted == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted " -+ "data from reauthentication message"); -+ goto fail; -+ } -+ -+ if (eattr.counter != data->counter) { -+ wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message " -+ "used incorrect counter %u, expected %u", -+ eattr.counter, data->counter); -+ goto fail; -+ } -+ os_free(decrypted); -+ decrypted = NULL; -+ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes " -+ "the correct AT_MAC"); -+ -+ if (eattr.counter_too_small) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response " -+ "included AT_COUNTER_TOO_SMALL - starting full " -+ "authentication"); -+ eap_aka_determine_identity(sm, data, 0, 1); -+ return; -+ } -+ -+ if (sm->eap_sim_aka_result_ind && attr->result_ind) { -+ data->use_result_ind = 1; -+ data->notification = EAP_SIM_SUCCESS; -+ eap_aka_state(data, NOTIFICATION); -+ } else -+ eap_aka_state(data, SUCCESS); -+ -+ if (data->reauth) { -+ identity = data->reauth->identity; -+ identity_len = data->reauth->identity_len; -+ } else { -+ identity = sm->identity; -+ identity_len = sm->identity_len; -+ } -+ -+ id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, -+ identity_len, &id2_len); -+ if (id2) { -+ identity = id2; -+ identity_len = id2_len; -+ } -+ -+ if (data->next_pseudonym) { -+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, -+ identity_len, data->next_pseudonym); -+ data->next_pseudonym = NULL; -+ } -+ if (data->next_reauth_id) { -+ if (data->eap_method == EAP_TYPE_AKA_PRIME) { -+#ifdef EAP_SERVER_AKA_PRIME -+ eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv, -+ identity, -+ identity_len, -+ data->next_reauth_id, -+ data->counter + 1, -+ data->k_encr, data->k_aut, -+ data->k_re); -+#endif /* EAP_SERVER_AKA_PRIME */ -+ } else { -+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, -+ identity_len, -+ data->next_reauth_id, -+ data->counter + 1, -+ data->mk); -+ } -+ data->next_reauth_id = NULL; -+ } else { -+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); -+ data->reauth = NULL; -+ } -+ -+ return; -+ -+fail: -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); -+ data->reauth = NULL; -+ os_free(decrypted); -+} -+ -+ -+static void eap_aka_process_client_error(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d", -+ attr->client_error_code); -+ if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) -+ eap_aka_state(data, SUCCESS); -+ else -+ eap_aka_state(data, FAILURE); -+} -+ -+ -+static void eap_aka_process_authentication_reject( -+ struct eap_sm *sm, struct eap_aka_data *data, -+ struct wpabuf *respData, struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication"); -+ eap_aka_state(data, FAILURE); -+} -+ -+ -+static void eap_aka_process_notification(struct eap_sm *sm, -+ struct eap_aka_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification"); -+ if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) -+ eap_aka_state(data, SUCCESS); -+ else -+ eap_aka_state(data, FAILURE); -+} -+ -+ -+static void eap_aka_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_aka_data *data = priv; -+ const u8 *pos, *end; -+ u8 subtype; -+ size_t len; -+ struct eap_sim_attrs attr; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData, -+ &len); -+ if (pos == NULL || len < 3) -+ return; -+ -+ end = pos + len; -+ subtype = *pos; -+ pos += 3; -+ -+ if (eap_aka_subtype_ok(data, subtype)) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected " -+ "EAP-AKA Subtype in EAP Response"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ -+ if (eap_sim_parse_attr(pos, end, &attr, -+ data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1, -+ 0)) { -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes"); -+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; -+ eap_aka_state(data, NOTIFICATION); -+ return; -+ } -+ -+ if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) { -+ eap_aka_process_client_error(sm, data, respData, &attr); -+ return; -+ } -+ -+ if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) { -+ eap_aka_process_authentication_reject(sm, data, respData, -+ &attr); -+ return; -+ } -+ -+ switch (data->state) { -+ case IDENTITY: -+ eap_aka_process_identity(sm, data, respData, &attr); -+ break; -+ case CHALLENGE: -+ if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) { -+ eap_aka_process_sync_failure(sm, data, respData, -+ &attr); -+ } else { -+ eap_aka_process_challenge(sm, data, respData, &attr); -+ } -+ break; -+ case REAUTH: -+ eap_aka_process_reauth(sm, data, respData, &attr); -+ break; -+ case NOTIFICATION: -+ eap_aka_process_notification(sm, data, respData, &attr); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in " -+ "process", data->state); -+ break; -+ } -+} -+ -+ -+static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_aka_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_SIM_KEYING_DATA_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); -+ *len = EAP_SIM_KEYING_DATA_LEN; -+ return key; -+} -+ -+ -+static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_aka_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ return key; -+} -+ -+ -+static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_aka_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_aka_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_aka_init; -+ eap->reset = eap_aka_reset; -+ eap->buildReq = eap_aka_buildReq; -+ eap->check = eap_aka_check; -+ eap->process = eap_aka_process; -+ eap->isDone = eap_aka_isDone; -+ eap->getKey = eap_aka_getKey; -+ eap->isSuccess = eap_aka_isSuccess; -+ eap->get_emsk = eap_aka_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -+ -+ -+#ifdef EAP_SERVER_AKA_PRIME -+int eap_server_aka_prime_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME, -+ "AKA'"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_aka_prime_init; -+ eap->reset = eap_aka_reset; -+ eap->buildReq = eap_aka_buildReq; -+ eap->check = eap_aka_check; -+ eap->process = eap_aka_process; -+ eap->isDone = eap_aka_isDone; -+ eap->getKey = eap_aka_getKey; -+ eap->isSuccess = eap_aka_isSuccess; -+ eap->get_emsk = eap_aka_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ -+ return ret; -+} -+#endif /* EAP_SERVER_AKA_PRIME */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_fast.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_fast.c -new file mode 100644 -index 0000000000000..ba17e98ec632a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_fast.c -@@ -0,0 +1,1620 @@ -+/* -+ * EAP-FAST server (RFC 4851) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "crypto/random.h" -+#include "eap_common/eap_tlv_common.h" -+#include "eap_common/eap_fast_common.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+ -+ -+static void eap_fast_reset(struct eap_sm *sm, void *priv); -+ -+ -+/* Private PAC-Opaque TLV types */ -+#define PAC_OPAQUE_TYPE_PAD 0 -+#define PAC_OPAQUE_TYPE_KEY 1 -+#define PAC_OPAQUE_TYPE_LIFETIME 2 -+#define PAC_OPAQUE_TYPE_IDENTITY 3 -+ -+struct eap_fast_data { -+ struct eap_ssl_data ssl; -+ enum { -+ START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD, -+ CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE -+ } state; -+ -+ int fast_version; -+ const struct eap_method *phase2_method; -+ void *phase2_priv; -+ int force_version; -+ int peer_version; -+ -+ u8 crypto_binding_nonce[32]; -+ int final_result; -+ -+ struct eap_fast_key_block_provisioning *key_block_p; -+ -+ u8 simck[EAP_FAST_SIMCK_LEN]; -+ u8 cmk[EAP_FAST_CMK_LEN]; -+ int simck_idx; -+ -+ u8 pac_opaque_encr[16]; -+ u8 *srv_id; -+ size_t srv_id_len; -+ char *srv_id_info; -+ -+ int anon_provisioning; -+ int send_new_pac; /* server triggered re-keying of Tunnel PAC */ -+ struct wpabuf *pending_phase2_resp; -+ u8 *identity; /* from PAC-Opaque */ -+ size_t identity_len; -+ int eap_seq; -+ int tnc_started; -+ -+ int pac_key_lifetime; -+ int pac_key_refresh_time; -+}; -+ -+ -+static int eap_fast_process_phase2_start(struct eap_sm *sm, -+ struct eap_fast_data *data); -+ -+ -+static const char * eap_fast_state_txt(int state) -+{ -+ switch (state) { -+ case START: -+ return "START"; -+ case PHASE1: -+ return "PHASE1"; -+ case PHASE2_START: -+ return "PHASE2_START"; -+ case PHASE2_ID: -+ return "PHASE2_ID"; -+ case PHASE2_METHOD: -+ return "PHASE2_METHOD"; -+ case CRYPTO_BINDING: -+ return "CRYPTO_BINDING"; -+ case REQUEST_PAC: -+ return "REQUEST_PAC"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "Unknown?!"; -+ } -+} -+ -+ -+static void eap_fast_state(struct eap_fast_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s", -+ eap_fast_state_txt(data->state), -+ eap_fast_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static EapType eap_fast_req_failure(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ /* TODO: send Result TLV(FAILURE) */ -+ eap_fast_state(data, FAILURE); -+ return EAP_TYPE_NONE; -+} -+ -+ -+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, -+ const u8 *client_random, -+ const u8 *server_random, -+ u8 *master_secret) -+{ -+ struct eap_fast_data *data = ctx; -+ const u8 *pac_opaque; -+ size_t pac_opaque_len; -+ u8 *buf, *pos, *end, *pac_key = NULL; -+ os_time_t lifetime = 0; -+ struct os_time now; -+ u8 *identity = NULL; -+ size_t identity_len = 0; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback"); -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)", -+ ticket, len); -+ -+ if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid " -+ "SessionTicket"); -+ return 0; -+ } -+ -+ pac_opaque_len = WPA_GET_BE16(ticket + 2); -+ pac_opaque = ticket + 4; -+ if (pac_opaque_len < 8 || pac_opaque_len % 8 || -+ pac_opaque_len > len - 4) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque " -+ "(len=%lu left=%lu)", -+ (unsigned long) pac_opaque_len, -+ (unsigned long) len); -+ return 0; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque", -+ pac_opaque, pac_opaque_len); -+ -+ buf = os_malloc(pac_opaque_len - 8); -+ if (buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory " -+ "for decrypting PAC-Opaque"); -+ return 0; -+ } -+ -+ if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8, -+ pac_opaque, buf) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt " -+ "PAC-Opaque"); -+ os_free(buf); -+ /* -+ * This may have been caused by server changing the PAC-Opaque -+ * encryption key, so just ignore this PAC-Opaque instead of -+ * failing the authentication completely. Provisioning can now -+ * be used to provision a new PAC. -+ */ -+ return 0; -+ } -+ -+ end = buf + pac_opaque_len - 8; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque", -+ buf, end - buf); -+ -+ pos = buf; -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ -+ switch (*pos) { -+ case PAC_OPAQUE_TYPE_PAD: -+ pos = end; -+ break; -+ case PAC_OPAQUE_TYPE_KEY: -+ if (pos[1] != EAP_FAST_PAC_KEY_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid " -+ "PAC-Key length %d", pos[1]); -+ os_free(buf); -+ return -1; -+ } -+ pac_key = pos + 2; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from " -+ "decrypted PAC-Opaque", -+ pac_key, EAP_FAST_PAC_KEY_LEN); -+ break; -+ case PAC_OPAQUE_TYPE_LIFETIME: -+ if (pos[1] != 4) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid " -+ "PAC-Key lifetime length %d", -+ pos[1]); -+ os_free(buf); -+ return -1; -+ } -+ lifetime = WPA_GET_BE32(pos + 2); -+ break; -+ case PAC_OPAQUE_TYPE_IDENTITY: -+ identity = pos + 2; -+ identity_len = pos[1]; -+ break; -+ } -+ -+ pos += 2 + pos[1]; -+ } -+ -+ if (pac_key == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in " -+ "PAC-Opaque"); -+ os_free(buf); -+ return -1; -+ } -+ -+ if (identity) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from " -+ "PAC-Opaque", identity, identity_len); -+ os_free(data->identity); -+ data->identity = os_malloc(identity_len); -+ if (data->identity) { -+ os_memcpy(data->identity, identity, identity_len); -+ data->identity_len = identity_len; -+ } -+ } -+ -+ if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore " -+ "(lifetime=%ld now=%ld)", lifetime, now.sec); -+ data->send_new_pac = 2; -+ /* -+ * Allow PAC to be used to allow a PAC update with some level -+ * of server authentication (i.e., do not fall back to full TLS -+ * handshake since we cannot be sure that the peer would be -+ * able to validate server certificate now). However, reject -+ * the authentication since the PAC was not valid anymore. Peer -+ * can connect again with the newly provisioned PAC after this. -+ */ -+ } else if (lifetime - now.sec < data->pac_key_refresh_time) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key soft timeout; send " -+ "an update if authentication succeeds"); -+ data->send_new_pac = 1; -+ } -+ -+ eap_fast_derive_master_secret(pac_key, server_random, client_random, -+ master_secret); -+ -+ os_free(buf); -+ -+ return 1; -+} -+ -+ -+static void eap_fast_derive_key_auth(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ u8 *sks; -+ -+ /* RFC 4851, Section 5.1: -+ * Extra key material after TLS key_block: session_key_seed[40] -+ */ -+ -+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion", -+ EAP_FAST_SKS_LEN); -+ if (sks == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive " -+ "session_key_seed"); -+ return; -+ } -+ -+ /* -+ * RFC 4851, Section 5.2: -+ * S-IMCK[0] = session_key_seed -+ */ -+ wpa_hexdump_key(MSG_DEBUG, -+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", -+ sks, EAP_FAST_SKS_LEN); -+ data->simck_idx = 0; -+ os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN); -+ os_free(sks); -+} -+ -+ -+static void eap_fast_derive_key_provisioning(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ os_free(data->key_block_p); -+ data->key_block_p = (struct eap_fast_key_block_provisioning *) -+ eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, -+ "key expansion", -+ sizeof(*data->key_block_p)); -+ if (data->key_block_p == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block"); -+ return; -+ } -+ /* -+ * RFC 4851, Section 5.2: -+ * S-IMCK[0] = session_key_seed -+ */ -+ wpa_hexdump_key(MSG_DEBUG, -+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", -+ data->key_block_p->session_key_seed, -+ sizeof(data->key_block_p->session_key_seed)); -+ data->simck_idx = 0; -+ os_memcpy(data->simck, data->key_block_p->session_key_seed, -+ EAP_FAST_SIMCK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge", -+ data->key_block_p->server_challenge, -+ sizeof(data->key_block_p->server_challenge)); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge", -+ data->key_block_p->client_challenge, -+ sizeof(data->key_block_p->client_challenge)); -+} -+ -+ -+static int eap_fast_get_phase2_key(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ u8 *isk, size_t isk_len) -+{ -+ u8 *key; -+ size_t key_len; -+ -+ os_memset(isk, 0, isk_len); -+ -+ if (data->phase2_method == NULL || data->phase2_priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " -+ "available"); -+ return -1; -+ } -+ -+ if (data->phase2_method->getKey == NULL) -+ return 0; -+ -+ if ((key = data->phase2_method->getKey(sm, data->phase2_priv, -+ &key_len)) == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material " -+ "from Phase 2"); -+ return -1; -+ } -+ -+ if (key_len > isk_len) -+ key_len = isk_len; -+ if (key_len == 32 && -+ data->phase2_method->vendor == EAP_VENDOR_IETF && -+ data->phase2_method->method == EAP_TYPE_MSCHAPV2) { -+ /* -+ * EAP-FAST uses reverse order for MS-MPPE keys when deriving -+ * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct -+ * ISK for EAP-FAST cryptobinding. -+ */ -+ os_memcpy(isk, key + 16, 16); -+ os_memcpy(isk + 16, key, 16); -+ } else -+ os_memcpy(isk, key, key_len); -+ os_free(key); -+ -+ return 0; -+} -+ -+ -+static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data) -+{ -+ u8 isk[32], imck[60]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)", -+ data->simck_idx + 1); -+ -+ /* -+ * RFC 4851, Section 5.2: -+ * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys", -+ * MSK[j], 60) -+ * S-IMCK[j] = first 40 octets of IMCK[j] -+ * CMK[j] = last 20 octets of IMCK[j] -+ */ -+ -+ if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0) -+ return -1; -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk)); -+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, -+ "Inner Methods Compound Keys", -+ isk, sizeof(isk), imck, sizeof(imck)); -+ data->simck_idx++; -+ os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]", -+ data->simck, EAP_FAST_SIMCK_LEN); -+ os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN); -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", -+ data->cmk, EAP_FAST_CMK_LEN); -+ -+ return 0; -+} -+ -+ -+static void * eap_fast_init(struct eap_sm *sm) -+{ -+ struct eap_fast_data *data; -+ u8 ciphers[5] = { -+ TLS_CIPHER_ANON_DH_AES128_SHA, -+ TLS_CIPHER_AES128_SHA, -+ TLS_CIPHER_RSA_DHE_AES128_SHA, -+ TLS_CIPHER_RC4_SHA, -+ TLS_CIPHER_NONE -+ }; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->fast_version = EAP_FAST_VERSION; -+ data->force_version = -1; -+ if (sm->user && sm->user->force_version >= 0) { -+ data->force_version = sm->user->force_version; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: forcing version %d", -+ data->force_version); -+ data->fast_version = data->force_version; -+ } -+ data->state = START; -+ -+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL."); -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ -+ if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn, -+ ciphers) < 0) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher " -+ "suites"); -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ -+ if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn, -+ eap_fast_session_ticket_cb, -+ data) < 0) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket " -+ "callback"); -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ -+ if (sm->pac_opaque_encr_key == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key " -+ "configured"); -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key, -+ sizeof(data->pac_opaque_encr)); -+ -+ if (sm->eap_fast_a_id == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured"); -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ data->srv_id = os_malloc(sm->eap_fast_a_id_len); -+ if (data->srv_id == NULL) { -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ os_memcpy(data->srv_id, sm->eap_fast_a_id, sm->eap_fast_a_id_len); -+ data->srv_id_len = sm->eap_fast_a_id_len; -+ -+ if (sm->eap_fast_a_id_info == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured"); -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ data->srv_id_info = os_strdup(sm->eap_fast_a_id_info); -+ if (data->srv_id_info == NULL) { -+ eap_fast_reset(sm, data); -+ return NULL; -+ } -+ -+ /* PAC-Key lifetime in seconds (hard limit) */ -+ data->pac_key_lifetime = sm->pac_key_lifetime; -+ -+ /* -+ * PAC-Key refresh time in seconds (soft limit on remaining hard -+ * limit). The server will generate a new PAC-Key when this number of -+ * seconds (or fewer) of the lifetime remains. -+ */ -+ data->pac_key_refresh_time = sm->pac_key_refresh_time; -+ -+ return data; -+} -+ -+ -+static void eap_fast_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ if (data == NULL) -+ return; -+ if (data->phase2_priv && data->phase2_method) -+ data->phase2_method->reset(sm, data->phase2_priv); -+ eap_server_tls_ssl_deinit(sm, &data->ssl); -+ os_free(data->srv_id); -+ os_free(data->srv_id_info); -+ os_free(data->key_block_p); -+ wpabuf_free(data->pending_phase2_resp); -+ os_free(data->identity); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_fast_build_start(struct eap_sm *sm, -+ struct eap_fast_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST, -+ 1 + sizeof(struct pac_tlv_hdr) + data->srv_id_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for" -+ " request"); -+ eap_fast_state(data, FAILURE); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version); -+ -+ /* RFC 4851, 4.1.1. Authority ID Data */ -+ eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); -+ -+ eap_fast_state(data, PHASE1); -+ -+ return req; -+} -+ -+ -+static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data) -+{ -+ char cipher[64]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2"); -+ -+ if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher)) -+ < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher " -+ "information"); -+ eap_fast_state(data, FAILURE); -+ return -1; -+ } -+ data->anon_provisioning = os_strstr(cipher, "ADH") != NULL; -+ -+ if (data->anon_provisioning) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning"); -+ eap_fast_derive_key_provisioning(sm, data); -+ } else -+ eap_fast_derive_key_auth(sm, data); -+ -+ eap_fast_state(data, PHASE2_START); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ u8 id) -+{ -+ struct wpabuf *req; -+ -+ if (data->phase2_priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " -+ "initialized"); -+ return NULL; -+ } -+ req = data->phase2_method->buildReq(sm, data->phase2_priv, id); -+ if (req == NULL) -+ return NULL; -+ -+ wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request", req); -+ return eap_fast_tlv_eap_payload(req); -+} -+ -+ -+static struct wpabuf * eap_fast_build_crypto_binding( -+ struct eap_sm *sm, struct eap_fast_data *data) -+{ -+ struct wpabuf *buf; -+ struct eap_tlv_result_tlv *result; -+ struct eap_tlv_crypto_binding_tlv *binding; -+ -+ buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding)); -+ if (buf == NULL) -+ return NULL; -+ -+ if (data->send_new_pac || data->anon_provisioning || -+ data->phase2_method) -+ data->final_result = 0; -+ else -+ data->final_result = 1; -+ -+ if (!data->final_result || data->eap_seq > 1) { -+ /* Intermediate-Result */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV " -+ "(status=SUCCESS)"); -+ result = wpabuf_put(buf, sizeof(*result)); -+ result->tlv_type = host_to_be16( -+ EAP_TLV_TYPE_MANDATORY | -+ EAP_TLV_INTERMEDIATE_RESULT_TLV); -+ result->length = host_to_be16(2); -+ result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); -+ } -+ -+ if (data->final_result) { -+ /* Result TLV */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV " -+ "(status=SUCCESS)"); -+ result = wpabuf_put(buf, sizeof(*result)); -+ result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | -+ EAP_TLV_RESULT_TLV); -+ result->length = host_to_be16(2); -+ result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); -+ } -+ -+ /* Crypto-Binding TLV */ -+ binding = wpabuf_put(buf, sizeof(*binding)); -+ binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | -+ EAP_TLV_CRYPTO_BINDING_TLV); -+ binding->length = host_to_be16(sizeof(*binding) - -+ sizeof(struct eap_tlv_hdr)); -+ binding->version = EAP_FAST_VERSION; -+ binding->received_version = data->peer_version; -+ binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST; -+ if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ -+ /* -+ * RFC 4851, Section 4.2.8: -+ * The nonce in a request MUST have its least significant bit set to 0. -+ */ -+ binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01; -+ -+ os_memcpy(data->crypto_binding_nonce, binding->nonce, -+ sizeof(binding->nonce)); -+ -+ /* -+ * RFC 4851, Section 5.3: -+ * CMK = CMK[j] -+ * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV ) -+ */ -+ -+ hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, -+ (u8 *) binding, sizeof(*binding), -+ binding->compound_mac); -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d " -+ "Received Version %d SubType %d", -+ binding->version, binding->received_version, -+ binding->subtype); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", -+ binding->nonce, sizeof(binding->nonce)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", -+ binding->compound_mac, sizeof(binding->compound_mac)); -+ -+ return buf; -+} -+ -+ -+static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ u8 pac_key[EAP_FAST_PAC_KEY_LEN]; -+ u8 *pac_buf, *pac_opaque; -+ struct wpabuf *buf; -+ u8 *pos; -+ size_t buf_len, srv_id_info_len, pac_len; -+ struct eap_tlv_hdr *pac_tlv; -+ struct pac_tlv_hdr *pac_info; -+ struct eap_tlv_result_tlv *result; -+ struct os_time now; -+ -+ if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 || -+ os_get_time(&now) < 0) -+ return NULL; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key", -+ pac_key, EAP_FAST_PAC_KEY_LEN); -+ -+ pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) + -+ (2 + sm->identity_len) + 8; -+ pac_buf = os_malloc(pac_len); -+ if (pac_buf == NULL) -+ return NULL; -+ -+ srv_id_info_len = os_strlen(data->srv_id_info); -+ -+ pos = pac_buf; -+ *pos++ = PAC_OPAQUE_TYPE_KEY; -+ *pos++ = EAP_FAST_PAC_KEY_LEN; -+ os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN); -+ pos += EAP_FAST_PAC_KEY_LEN; -+ -+ *pos++ = PAC_OPAQUE_TYPE_LIFETIME; -+ *pos++ = 4; -+ WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime); -+ pos += 4; -+ -+ if (sm->identity) { -+ *pos++ = PAC_OPAQUE_TYPE_IDENTITY; -+ *pos++ = sm->identity_len; -+ os_memcpy(pos, sm->identity, sm->identity_len); -+ pos += sm->identity_len; -+ } -+ -+ pac_len = pos - pac_buf; -+ while (pac_len % 8) { -+ *pos++ = PAC_OPAQUE_TYPE_PAD; -+ pac_len++; -+ } -+ -+ pac_opaque = os_malloc(pac_len + 8); -+ if (pac_opaque == NULL) { -+ os_free(pac_buf); -+ return NULL; -+ } -+ if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf, -+ pac_opaque) < 0) { -+ os_free(pac_buf); -+ os_free(pac_opaque); -+ return NULL; -+ } -+ os_free(pac_buf); -+ -+ pac_len += 8; -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", -+ pac_opaque, pac_len); -+ -+ buf_len = sizeof(*pac_tlv) + -+ sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN + -+ sizeof(struct pac_tlv_hdr) + pac_len + -+ data->srv_id_len + srv_id_info_len + 100 + sizeof(*result); -+ buf = wpabuf_alloc(buf_len); -+ if (buf == NULL) { -+ os_free(pac_opaque); -+ return NULL; -+ } -+ -+ /* Result TLV */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)"); -+ result = wpabuf_put(buf, sizeof(*result)); -+ WPA_PUT_BE16((u8 *) &result->tlv_type, -+ EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV); -+ WPA_PUT_BE16((u8 *) &result->length, 2); -+ WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS); -+ -+ /* PAC TLV */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV"); -+ pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv)); -+ pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | -+ EAP_TLV_PAC_TLV); -+ -+ /* PAC-Key */ -+ eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN); -+ -+ /* PAC-Opaque */ -+ eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len); -+ os_free(pac_opaque); -+ -+ /* PAC-Info */ -+ pac_info = wpabuf_put(buf, sizeof(*pac_info)); -+ pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO); -+ -+ /* PAC-Lifetime (inside PAC-Info) */ -+ eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4); -+ wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime); -+ -+ /* A-ID (inside PAC-Info) */ -+ eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); -+ -+ /* Note: headers may be misaligned after A-ID */ -+ -+ if (sm->identity) { -+ eap_fast_put_tlv(buf, PAC_TYPE_I_ID, sm->identity, -+ sm->identity_len); -+ } -+ -+ /* A-ID-Info (inside PAC-Info) */ -+ eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info, -+ srv_id_info_len); -+ -+ /* PAC-Type (inside PAC-Info) */ -+ eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2); -+ wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC); -+ -+ /* Update PAC-Info and PAC TLV Length fields */ -+ pos = wpabuf_put(buf, 0); -+ pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1)); -+ pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1)); -+ -+ return buf; -+} -+ -+ -+static int eap_fast_encrypt_phase2(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct wpabuf *plain, int piggyback) -+{ -+ struct wpabuf *encr; -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs", -+ plain); -+ encr = eap_server_tls_encrypt(sm, &data->ssl, plain); -+ wpabuf_free(plain); -+ -+ if (data->ssl.tls_out && piggyback) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data " -+ "(len=%d) with last Phase 1 Message (len=%d " -+ "used=%d)", -+ (int) wpabuf_len(encr), -+ (int) wpabuf_len(data->ssl.tls_out), -+ (int) data->ssl.tls_out_pos); -+ if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) { -+ wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize " -+ "output buffer"); -+ wpabuf_free(encr); -+ return -1; -+ } -+ wpabuf_put_buf(data->ssl.tls_out, encr); -+ wpabuf_free(encr); -+ } else { -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = encr; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_fast_data *data = priv; -+ struct wpabuf *req = NULL; -+ int piggyback = 0; -+ -+ if (data->ssl.state == FRAG_ACK) { -+ return eap_server_tls_build_ack(id, EAP_TYPE_FAST, -+ data->fast_version); -+ } -+ -+ if (data->ssl.state == WAIT_FRAG_ACK) { -+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, -+ data->fast_version, id); -+ } -+ -+ switch (data->state) { -+ case START: -+ return eap_fast_build_start(sm, data, id); -+ case PHASE1: -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { -+ if (eap_fast_phase1_done(sm, data) < 0) -+ return NULL; -+ if (data->state == PHASE2_START) { -+ /* -+ * Try to generate Phase 2 data to piggyback -+ * with the end of Phase 1 to avoid extra -+ * roundtrip. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Try to start " -+ "Phase 2"); -+ if (eap_fast_process_phase2_start(sm, data)) -+ break; -+ req = eap_fast_build_phase2_req(sm, data, id); -+ piggyback = 1; -+ } -+ } -+ break; -+ case PHASE2_ID: -+ case PHASE2_METHOD: -+ req = eap_fast_build_phase2_req(sm, data, id); -+ break; -+ case CRYPTO_BINDING: -+ req = eap_fast_build_crypto_binding(sm, data); -+ if (data->phase2_method) { -+ /* -+ * Include the start of the next EAP method in the -+ * sequence in the same message with Crypto-Binding to -+ * save a round-trip. -+ */ -+ struct wpabuf *eap; -+ eap = eap_fast_build_phase2_req(sm, data, id); -+ req = wpabuf_concat(req, eap); -+ eap_fast_state(data, PHASE2_METHOD); -+ } -+ break; -+ case REQUEST_PAC: -+ req = eap_fast_build_pac(sm, data); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", -+ __func__, data->state); -+ return NULL; -+ } -+ -+ if (req && -+ eap_fast_encrypt_phase2(sm, data, req, piggyback) < 0) -+ return NULL; -+ -+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, -+ data->fast_version, id); -+} -+ -+ -+static Boolean eap_fast_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data, -+ EapType eap_type) -+{ -+ if (data->phase2_priv && data->phase2_method) { -+ data->phase2_method->reset(sm, data->phase2_priv); -+ data->phase2_method = NULL; -+ data->phase2_priv = NULL; -+ } -+ data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, -+ eap_type); -+ if (!data->phase2_method) -+ return -1; -+ -+ if (data->key_block_p) { -+ sm->auth_challenge = data->key_block_p->server_challenge; -+ sm->peer_challenge = data->key_block_p->client_challenge; -+ } -+ sm->init_phase2 = 1; -+ data->phase2_priv = data->phase2_method->init(sm); -+ sm->init_phase2 = 0; -+ sm->auth_challenge = NULL; -+ sm->peer_challenge = NULL; -+ -+ return data->phase2_priv == NULL ? -1 : 0; -+} -+ -+ -+static void eap_fast_process_phase2_response(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ u8 *in_data, size_t in_len) -+{ -+ u8 next_type = EAP_TYPE_NONE; -+ struct eap_hdr *hdr; -+ u8 *pos; -+ size_t left; -+ struct wpabuf buf; -+ const struct eap_method *m = data->phase2_method; -+ void *priv = data->phase2_priv; -+ -+ if (priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not " -+ "initialized?!", __func__); -+ return; -+ } -+ -+ hdr = (struct eap_hdr *) in_data; -+ pos = (u8 *) (hdr + 1); -+ -+ if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { -+ left = in_len - sizeof(*hdr); -+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; " -+ "allowed types", pos + 1, left - 1); -+#ifdef EAP_SERVER_TNC -+ if (m && m->vendor == EAP_VENDOR_IETF && -+ m->method == EAP_TYPE_TNC) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required " -+ "TNC negotiation"); -+ next_type = eap_fast_req_failure(sm, data); -+ eap_fast_phase2_init(sm, data, next_type); -+ return; -+ } -+#endif /* EAP_SERVER_TNC */ -+ eap_sm_process_nak(sm, pos + 1, left - 1); -+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && -+ sm->user->methods[sm->user_eap_method_index].method != -+ EAP_TYPE_NONE) { -+ next_type = sm->user->methods[ -+ sm->user_eap_method_index++].method; -+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", -+ next_type); -+ } else { -+ next_type = eap_fast_req_failure(sm, data); -+ } -+ eap_fast_phase2_init(sm, data, next_type); -+ return; -+ } -+ -+ wpabuf_set(&buf, in_data, in_len); -+ -+ if (m->check(sm, priv, &buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to " -+ "ignore the packet"); -+ next_type = eap_fast_req_failure(sm, data); -+ return; -+ } -+ -+ m->process(sm, priv, &buf); -+ -+ if (!m->isDone(sm, priv)) -+ return; -+ -+ if (!m->isSuccess(sm, priv)) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed"); -+ next_type = eap_fast_req_failure(sm, data); -+ eap_fast_phase2_init(sm, data, next_type); -+ return; -+ } -+ -+ switch (data->state) { -+ case PHASE2_ID: -+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 " -+ "Identity not found in the user " -+ "database", -+ sm->identity, sm->identity_len); -+ next_type = eap_fast_req_failure(sm, data); -+ break; -+ } -+ -+ eap_fast_state(data, PHASE2_METHOD); -+ if (data->anon_provisioning) { -+ /* -+ * Only EAP-MSCHAPv2 is allowed for anonymous -+ * provisioning. -+ */ -+ next_type = EAP_TYPE_MSCHAPV2; -+ sm->user_eap_method_index = 0; -+ } else { -+ next_type = sm->user->methods[0].method; -+ sm->user_eap_method_index = 1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type); -+ break; -+ case PHASE2_METHOD: -+ case CRYPTO_BINDING: -+ eap_fast_update_icmk(sm, data); -+ eap_fast_state(data, CRYPTO_BINDING); -+ data->eap_seq++; -+ next_type = EAP_TYPE_NONE; -+#ifdef EAP_SERVER_TNC -+ if (sm->tnc && !data->tnc_started) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC"); -+ next_type = EAP_TYPE_TNC; -+ data->tnc_started = 1; -+ } -+#endif /* EAP_SERVER_TNC */ -+ break; -+ case FAILURE: -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", -+ __func__, data->state); -+ break; -+ } -+ -+ eap_fast_phase2_init(sm, data, next_type); -+} -+ -+ -+static void eap_fast_process_phase2_eap(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ u8 *in_data, size_t in_len) -+{ -+ struct eap_hdr *hdr; -+ size_t len; -+ -+ hdr = (struct eap_hdr *) in_data; -+ if (in_len < (int) sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " -+ "EAP frame (len=%lu)", (unsigned long) in_len); -+ eap_fast_req_failure(sm, data); -+ return; -+ } -+ len = be_to_host16(hdr->length); -+ if (len > in_len) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in " -+ "Phase 2 EAP frame (len=%lu hdr->length=%lu)", -+ (unsigned long) in_len, (unsigned long) len); -+ eap_fast_req_failure(sm, data); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d " -+ "identifier=%d length=%lu", hdr->code, hdr->identifier, -+ (unsigned long) len); -+ switch (hdr->code) { -+ case EAP_CODE_RESPONSE: -+ eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len); -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in " -+ "Phase 2 EAP header", hdr->code); -+ break; -+ } -+} -+ -+ -+static int eap_fast_parse_tlvs(struct wpabuf *data, -+ struct eap_fast_tlv_parse *tlv) -+{ -+ int mandatory, tlv_type, len, res; -+ u8 *pos, *end; -+ -+ os_memset(tlv, 0, sizeof(*tlv)); -+ -+ pos = wpabuf_mhead(data); -+ end = pos + wpabuf_len(data); -+ while (pos + 4 < end) { -+ mandatory = pos[0] & 0x80; -+ tlv_type = WPA_GET_BE16(pos) & 0x3fff; -+ pos += 2; -+ len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (pos + len > end) { -+ wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " -+ "TLV type %d length %d%s", -+ tlv_type, len, mandatory ? " (mandatory)" : ""); -+ -+ res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); -+ if (res == -2) -+ break; -+ if (res < 0) { -+ if (mandatory) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown " -+ "mandatory TLV type %d", tlv_type); -+ /* TODO: generate Nak TLV */ -+ break; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored " -+ "unknown optional TLV type %d", -+ tlv_type); -+ } -+ } -+ -+ pos += len; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_validate_crypto_binding( -+ struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b, -+ size_t bind_len) -+{ -+ u8 cmac[SHA1_MAC_LEN]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: " -+ "Version %d Received Version %d SubType %d", -+ b->version, b->received_version, b->subtype); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", -+ b->nonce, sizeof(b->nonce)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", -+ b->compound_mac, sizeof(b->compound_mac)); -+ -+ if (b->version != EAP_FAST_VERSION || -+ b->received_version != EAP_FAST_VERSION) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version " -+ "in Crypto-Binding: version %d " -+ "received_version %d", b->version, -+ b->received_version); -+ return -1; -+ } -+ -+ if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in " -+ "Crypto-Binding: %d", b->subtype); -+ return -1; -+ } -+ -+ if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 || -+ (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in " -+ "Crypto-Binding"); -+ return -1; -+ } -+ -+ os_memcpy(cmac, b->compound_mac, sizeof(cmac)); -+ os_memset(b->compound_mac, 0, sizeof(cmac)); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for " -+ "Compound MAC calculation", -+ (u8 *) b, bind_len); -+ hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len, -+ b->compound_mac); -+ if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) { -+ wpa_hexdump(MSG_MSGDUMP, -+ "EAP-FAST: Calculated Compound MAC", -+ b->compound_mac, sizeof(cmac)); -+ wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not " -+ "match"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_pac_type(u8 *pac, size_t len, u16 type) -+{ -+ struct eap_tlv_pac_type_tlv *tlv; -+ -+ if (pac == NULL || len != sizeof(*tlv)) -+ return 0; -+ -+ tlv = (struct eap_tlv_pac_type_tlv *) pac; -+ -+ return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE && -+ be_to_host16(tlv->length) == 2 && -+ be_to_host16(tlv->pac_type) == type; -+} -+ -+ -+static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct wpabuf *in_data) -+{ -+ struct eap_fast_tlv_parse tlv; -+ int check_crypto_binding = data->state == CRYPTO_BINDING; -+ -+ if (eap_fast_parse_tlvs(in_data, &tlv) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received " -+ "Phase 2 TLVs"); -+ return; -+ } -+ -+ if (tlv.result == EAP_TLV_RESULT_FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated " -+ "failure"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ if (data->state == REQUEST_PAC) { -+ u16 type, len, res; -+ if (tlv.pac == NULL || tlv.pac_len < 6) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC " -+ "Acknowledgement received"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ type = WPA_GET_BE16(tlv.pac); -+ len = WPA_GET_BE16(tlv.pac + 2); -+ res = WPA_GET_BE16(tlv.pac + 4); -+ -+ if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 || -+ res != EAP_TLV_RESULT_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not " -+ "contain acknowledgement"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received " -+ "- PAC provisioning succeeded"); -+ eap_fast_state(data, (data->anon_provisioning || -+ data->send_new_pac == 2) ? -+ FAILURE : SUCCESS); -+ return; -+ } -+ -+ if (check_crypto_binding) { -+ if (tlv.crypto_binding == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding " -+ "TLV received"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ if (data->final_result && -+ tlv.result != EAP_TLV_RESULT_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " -+ "without Success Result"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ if (!data->final_result && -+ tlv.iresult != EAP_TLV_RESULT_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " -+ "without intermediate Success Result"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding, -+ tlv.crypto_binding_len)) { -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV " -+ "received"); -+ if (data->final_result) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " -+ "completed successfully"); -+ } -+ -+ if (data->anon_provisioning && -+ sm->eap_fast_prov != ANON_PROV && -+ sm->eap_fast_prov != BOTH_PROV) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " -+ "use unauthenticated provisioning which is " -+ "disabled"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ if (sm->eap_fast_prov != AUTH_PROV && -+ sm->eap_fast_prov != BOTH_PROV && -+ tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && -+ eap_fast_pac_type(tlv.pac, tlv.pac_len, -+ PAC_TYPE_TUNNEL_PAC)) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " -+ "use authenticated provisioning which is " -+ "disabled"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ if (data->anon_provisioning || -+ (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && -+ eap_fast_pac_type(tlv.pac, tlv.pac_len, -+ PAC_TYPE_TUNNEL_PAC))) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new " -+ "Tunnel PAC"); -+ eap_fast_state(data, REQUEST_PAC); -+ } else if (data->send_new_pac) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered " -+ "re-keying of Tunnel PAC"); -+ eap_fast_state(data, REQUEST_PAC); -+ } else if (data->final_result) -+ eap_fast_state(data, SUCCESS); -+ } -+ -+ if (tlv.eap_payload_tlv) { -+ eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv, -+ tlv.eap_payload_tlv_len); -+ } -+} -+ -+ -+static void eap_fast_process_phase2(struct eap_sm *sm, -+ struct eap_fast_data *data, -+ struct wpabuf *in_buf) -+{ -+ struct wpabuf *in_decrypted; -+ -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" -+ " Phase 2", (unsigned long) wpabuf_len(in_buf)); -+ -+ if (data->pending_phase2_resp) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " -+ "skip decryption and use old data"); -+ eap_fast_process_phase2_tlvs(sm, data, -+ data->pending_phase2_resp); -+ wpabuf_free(data->pending_phase2_resp); -+ data->pending_phase2_resp = NULL; -+ return; -+ } -+ -+ in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, -+ in_buf); -+ if (in_decrypted == NULL) { -+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 " -+ "data"); -+ eap_fast_state(data, FAILURE); -+ return; -+ } -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", -+ in_decrypted); -+ -+ eap_fast_process_phase2_tlvs(sm, data, in_decrypted); -+ -+ if (sm->method_pending == METHOD_PENDING_WAIT) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in " -+ "pending wait state - save decrypted response"); -+ wpabuf_free(data->pending_phase2_resp); -+ data->pending_phase2_resp = in_decrypted; -+ return; -+ } -+ -+ wpabuf_free(in_decrypted); -+} -+ -+ -+static int eap_fast_process_version(struct eap_sm *sm, void *priv, -+ int peer_version) -+{ -+ struct eap_fast_data *data = priv; -+ -+ data->peer_version = peer_version; -+ -+ if (data->force_version >= 0 && peer_version != data->force_version) { -+ wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced" -+ " version (forced=%d peer=%d) - reject", -+ data->force_version, peer_version); -+ return -1; -+ } -+ -+ if (peer_version < data->fast_version) { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; " -+ "use version %d", -+ peer_version, data->fast_version, peer_version); -+ data->fast_version = peer_version; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_fast_process_phase1(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) { -+ wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed"); -+ eap_fast_state(data, FAILURE); -+ return -1; -+ } -+ -+ if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) || -+ wpabuf_len(data->ssl.tls_out) > 0) -+ return 1; -+ -+ /* -+ * Phase 1 was completed with the received message (e.g., when using -+ * abbreviated handshake), so Phase 2 can be started immediately -+ * without having to send through an empty message to the peer. -+ */ -+ -+ return eap_fast_phase1_done(sm, data); -+} -+ -+ -+static int eap_fast_process_phase2_start(struct eap_sm *sm, -+ struct eap_fast_data *data) -+{ -+ u8 next_type; -+ -+ if (data->identity) { -+ os_free(sm->identity); -+ sm->identity = data->identity; -+ data->identity = NULL; -+ sm->identity_len = data->identity_len; -+ data->identity_len = 0; -+ sm->require_identity_match = 1; -+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: " -+ "Phase2 Identity not found " -+ "in the user database", -+ sm->identity, sm->identity_len); -+ next_type = eap_fast_req_failure(sm, data); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already " -+ "known - skip Phase 2 Identity Request"); -+ next_type = sm->user->methods[0].method; -+ sm->user_eap_method_index = 1; -+ } -+ -+ eap_fast_state(data, PHASE2_METHOD); -+ } else { -+ eap_fast_state(data, PHASE2_ID); -+ next_type = EAP_TYPE_IDENTITY; -+ } -+ -+ return eap_fast_phase2_init(sm, data, next_type); -+} -+ -+ -+static void eap_fast_process_msg(struct eap_sm *sm, void *priv, -+ const struct wpabuf *respData) -+{ -+ struct eap_fast_data *data = priv; -+ -+ switch (data->state) { -+ case PHASE1: -+ if (eap_fast_process_phase1(sm, data)) -+ break; -+ -+ /* fall through to PHASE2_START */ -+ case PHASE2_START: -+ eap_fast_process_phase2_start(sm, data); -+ break; -+ case PHASE2_ID: -+ case PHASE2_METHOD: -+ case CRYPTO_BINDING: -+ case REQUEST_PAC: -+ eap_fast_process_phase2(sm, data, data->ssl.tls_in); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s", -+ data->state, __func__); -+ break; -+ } -+} -+ -+ -+static void eap_fast_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_fast_data *data = priv; -+ if (eap_server_tls_process(sm, &data->ssl, respData, data, -+ EAP_TYPE_FAST, eap_fast_process_version, -+ eap_fast_process_msg) < 0) -+ eap_fast_state(data, FAILURE); -+} -+ -+ -+static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_fast_data *data = priv; -+ u8 *eapKeyData; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ eapKeyData = os_malloc(EAP_FAST_KEY_LEN); -+ if (eapKeyData == NULL) -+ return NULL; -+ -+ eap_fast_derive_eap_msk(data->simck, eapKeyData); -+ *len = EAP_FAST_KEY_LEN; -+ -+ return eapKeyData; -+} -+ -+ -+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_fast_data *data = priv; -+ u8 *eapKeyData; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ eapKeyData = os_malloc(EAP_EMSK_LEN); -+ if (eapKeyData == NULL) -+ return NULL; -+ -+ eap_fast_derive_eap_emsk(data->simck, eapKeyData); -+ *len = EAP_EMSK_LEN; -+ -+ return eapKeyData; -+} -+ -+ -+static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_fast_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_fast_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_fast_init; -+ eap->reset = eap_fast_reset; -+ eap->buildReq = eap_fast_buildReq; -+ eap->check = eap_fast_check; -+ eap->process = eap_fast_process; -+ eap->isDone = eap_fast_isDone; -+ eap->getKey = eap_fast_getKey; -+ eap->get_emsk = eap_fast_get_emsk; -+ eap->isSuccess = eap_fast_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gpsk.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gpsk.c -new file mode 100644 -index 0000000000000..a79480682c54f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gpsk.c -@@ -0,0 +1,634 @@ -+/* -+ * hostapd / EAP-GPSK (RFC 5433) server -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_server/eap_i.h" -+#include "eap_common/eap_gpsk_common.h" -+ -+ -+struct eap_gpsk_data { -+ enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; -+ u8 rand_server[EAP_GPSK_RAND_LEN]; -+ u8 rand_peer[EAP_GPSK_RAND_LEN]; -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 sk[EAP_GPSK_MAX_SK_LEN]; -+ size_t sk_len; -+ u8 pk[EAP_GPSK_MAX_PK_LEN]; -+ size_t pk_len; -+ u8 *id_peer; -+ size_t id_peer_len; -+ u8 *id_server; -+ size_t id_server_len; -+#define MAX_NUM_CSUITES 2 -+ struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES]; -+ size_t csuite_count; -+ int vendor; /* CSuite/Vendor */ -+ int specifier; /* CSuite/Specifier */ -+}; -+ -+ -+static const char * eap_gpsk_state_txt(int state) -+{ -+ switch (state) { -+ case GPSK_1: -+ return "GPSK-1"; -+ case GPSK_3: -+ return "GPSK-3"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+static void eap_gpsk_state(struct eap_gpsk_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", -+ eap_gpsk_state_txt(data->state), -+ eap_gpsk_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_gpsk_init(struct eap_sm *sm) -+{ -+ struct eap_gpsk_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = GPSK_1; -+ -+ /* TODO: add support for configuring ID_Server */ -+ data->id_server = (u8 *) os_strdup("hostapd"); -+ if (data->id_server) -+ data->id_server_len = os_strlen((char *) data->id_server); -+ -+ data->csuite_count = 0; -+ if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, -+ EAP_GPSK_CIPHER_AES)) { -+ WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, -+ EAP_GPSK_VENDOR_IETF); -+ WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, -+ EAP_GPSK_CIPHER_AES); -+ data->csuite_count++; -+ } -+ if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, -+ EAP_GPSK_CIPHER_SHA256)) { -+ WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, -+ EAP_GPSK_VENDOR_IETF); -+ WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, -+ EAP_GPSK_CIPHER_SHA256); -+ data->csuite_count++; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_gpsk_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gpsk_data *data = priv; -+ os_free(data->id_server); -+ os_free(data->id_peer); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm, -+ struct eap_gpsk_data *data, u8 id) -+{ -+ size_t len; -+ struct wpabuf *req; -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1"); -+ -+ if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data"); -+ eap_gpsk_state(data, FAILURE); -+ return NULL; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server", -+ data->rand_server, EAP_GPSK_RAND_LEN); -+ -+ len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 + -+ data->csuite_count * sizeof(struct eap_gpsk_csuite); -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " -+ "for request/GPSK-1"); -+ eap_gpsk_state(data, FAILURE); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1); -+ wpabuf_put_be16(req, data->id_server_len); -+ wpabuf_put_data(req, data->id_server, data->id_server_len); -+ wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); -+ wpabuf_put_be16(req, -+ data->csuite_count * sizeof(struct eap_gpsk_csuite)); -+ wpabuf_put_data(req, data->csuite_list, -+ data->csuite_count * sizeof(struct eap_gpsk_csuite)); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm, -+ struct eap_gpsk_data *data, u8 id) -+{ -+ u8 *pos, *start; -+ size_t len, miclen; -+ struct eap_gpsk_csuite *csuite; -+ struct wpabuf *req; -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3"); -+ -+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier); -+ len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len + -+ sizeof(struct eap_gpsk_csuite) + 2 + miclen; -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " -+ "for request/GPSK-3"); -+ eap_gpsk_state(data, FAILURE); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3); -+ start = wpabuf_put(req, 0); -+ -+ wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN); -+ wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); -+ wpabuf_put_be16(req, data->id_server_len); -+ wpabuf_put_data(req, data->id_server, data->id_server_len); -+ csuite = wpabuf_put(req, sizeof(*csuite)); -+ WPA_PUT_BE32(csuite->vendor, data->vendor); -+ WPA_PUT_BE16(csuite->specifier, data->specifier); -+ -+ /* no PD_Payload_2 */ -+ wpabuf_put_be16(req, 0); -+ -+ pos = wpabuf_put(req, miclen); -+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, -+ data->specifier, start, pos - start, pos) < 0) -+ { -+ os_free(req); -+ eap_gpsk_state(data, FAILURE); -+ return NULL; -+ } -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_gpsk_data *data = priv; -+ -+ switch (data->state) { -+ case GPSK_1: -+ return eap_gpsk_build_gpsk_1(sm, data, id); -+ case GPSK_3: -+ return eap_gpsk_build_gpsk_3(sm, data, id); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq", -+ data->state); -+ break; -+ } -+ return NULL; -+} -+ -+ -+static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_gpsk_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame"); -+ return TRUE; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos); -+ -+ if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2) -+ return FALSE; -+ -+ if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4) -+ return FALSE; -+ -+ wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d", -+ *pos, data->state); -+ -+ return TRUE; -+} -+ -+ -+static void eap_gpsk_process_gpsk_2(struct eap_sm *sm, -+ struct eap_gpsk_data *data, -+ const u8 *payload, size_t payloadlen) -+{ -+ const u8 *pos, *end; -+ u16 alen; -+ const struct eap_gpsk_csuite *csuite; -+ size_t i, miclen; -+ u8 mic[EAP_GPSK_MAX_MIC_LEN]; -+ -+ if (data->state != GPSK_1) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2"); -+ -+ pos = payload; -+ end = payload + payloadlen; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "ID_Peer length"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ alen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < alen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "ID_Peer"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ os_free(data->id_peer); -+ data->id_peer = os_malloc(alen); -+ if (data->id_peer == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store " -+ "%d-octet ID_Peer", alen); -+ return; -+ } -+ os_memcpy(data->id_peer, pos, alen); -+ data->id_peer_len = alen; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", -+ data->id_peer, data->id_peer_len); -+ pos += alen; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "ID_Server length"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ alen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < alen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "ID_Server"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ if (alen != data->id_server_len || -+ os_memcmp(pos, data->id_server, alen) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and " -+ "GPSK-2 did not match"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ pos += alen; -+ -+ if (end - pos < EAP_GPSK_RAND_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "RAND_Peer"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", -+ data->rand_peer, EAP_GPSK_RAND_LEN); -+ pos += EAP_GPSK_RAND_LEN; -+ -+ if (end - pos < EAP_GPSK_RAND_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "RAND_Server"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " -+ "GPSK-2 did not match"); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", -+ data->rand_server, EAP_GPSK_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2", -+ pos, EAP_GPSK_RAND_LEN); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ pos += EAP_GPSK_RAND_LEN; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "CSuite_List length"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ alen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < alen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "CSuite_List"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) || -+ os_memcmp(pos, data->csuite_list, alen) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and " -+ "GPSK-2 did not match"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ pos += alen; -+ -+ if (end - pos < (int) sizeof(*csuite)) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "CSuite_Sel"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ csuite = (const struct eap_gpsk_csuite *) pos; -+ for (i = 0; i < data->csuite_count; i++) { -+ if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) -+ == 0) -+ break; -+ } -+ if (i == data->csuite_count) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported " -+ "ciphersuite %d:%d", -+ WPA_GET_BE32(csuite->vendor), -+ WPA_GET_BE16(csuite->specifier)); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ data->vendor = WPA_GET_BE32(csuite->vendor); -+ data->specifier = WPA_GET_BE16(csuite->specifier); -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d", -+ data->vendor, data->specifier); -+ pos += sizeof(*csuite); -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "PD_Payload_1 length"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ alen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < alen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "PD_Payload_1"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); -+ pos += alen; -+ -+ if (sm->user == NULL || sm->user->password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured " -+ "for the user"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ -+ if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len, -+ data->vendor, data->specifier, -+ data->rand_peer, data->rand_server, -+ data->id_peer, data->id_peer_len, -+ data->id_server, data->id_server_len, -+ data->msk, data->emsk, -+ data->sk, &data->sk_len, -+ data->pk, &data->pk_len) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ -+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier); -+ if (end - pos < (int) miclen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " -+ "(left=%lu miclen=%lu)", -+ (unsigned long) (end - pos), -+ (unsigned long) miclen); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, -+ data->specifier, payload, pos - payload, mic) -+ < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ if (os_memcmp(mic, pos, miclen) != 0) { -+ wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2"); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ pos += miclen; -+ -+ if (pos != end) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " -+ "data in the end of GPSK-2", -+ (unsigned long) (end - pos)); -+ } -+ -+ eap_gpsk_state(data, GPSK_3); -+} -+ -+ -+static void eap_gpsk_process_gpsk_4(struct eap_sm *sm, -+ struct eap_gpsk_data *data, -+ const u8 *payload, size_t payloadlen) -+{ -+ const u8 *pos, *end; -+ u16 alen; -+ size_t miclen; -+ u8 mic[EAP_GPSK_MAX_MIC_LEN]; -+ -+ if (data->state != GPSK_3) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4"); -+ -+ pos = payload; -+ end = payload + payloadlen; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "PD_Payload_1 length"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ alen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < alen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " -+ "PD_Payload_1"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); -+ pos += alen; -+ -+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier); -+ if (end - pos < (int) miclen) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " -+ "(left=%lu miclen=%lu)", -+ (unsigned long) (end - pos), -+ (unsigned long) miclen); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, -+ data->specifier, payload, pos - payload, mic) -+ < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ if (os_memcmp(mic, pos, miclen) != 0) { -+ wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4"); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); -+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); -+ eap_gpsk_state(data, FAILURE); -+ return; -+ } -+ pos += miclen; -+ -+ if (pos != end) { -+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " -+ "data in the end of GPSK-4", -+ (unsigned long) (end - pos)); -+ } -+ -+ eap_gpsk_state(data, SUCCESS); -+} -+ -+ -+static void eap_gpsk_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_gpsk_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); -+ if (pos == NULL || len < 1) -+ return; -+ -+ switch (*pos) { -+ case EAP_GPSK_OPCODE_GPSK_2: -+ eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1); -+ break; -+ case EAP_GPSK_OPCODE_GPSK_4: -+ eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1); -+ break; -+ } -+} -+ -+ -+static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gpsk_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_gpsk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ -+ return key; -+} -+ -+ -+static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_gpsk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ -+ return key; -+} -+ -+ -+static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gpsk_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_gpsk_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_gpsk_init; -+ eap->reset = eap_gpsk_reset; -+ eap->buildReq = eap_gpsk_buildReq; -+ eap->check = eap_gpsk_check; -+ eap->process = eap_gpsk_process; -+ eap->isDone = eap_gpsk_isDone; -+ eap->getKey = eap_gpsk_getKey; -+ eap->isSuccess = eap_gpsk_isSuccess; -+ eap->get_emsk = eap_gpsk_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gtc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gtc.c -new file mode 100644 -index 0000000000000..79b9696b2c953 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_gtc.c -@@ -0,0 +1,230 @@ -+/* -+ * hostapd / EAP-GTC (RFC 3748) -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+ -+ -+struct eap_gtc_data { -+ enum { CONTINUE, SUCCESS, FAILURE } state; -+ int prefix; -+}; -+ -+ -+static void * eap_gtc_init(struct eap_sm *sm) -+{ -+ struct eap_gtc_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = CONTINUE; -+ -+#ifdef EAP_SERVER_FAST -+ if (sm->m && sm->m->vendor == EAP_VENDOR_IETF && -+ sm->m->method == EAP_TYPE_FAST) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix " -+ "with challenge/response"); -+ data->prefix = 1; -+ } -+#endif /* EAP_SERVER_FAST */ -+ -+ return data; -+} -+ -+ -+static void eap_gtc_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gtc_data *data = priv; -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_gtc_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_gtc_data *data = priv; -+ struct wpabuf *req; -+ char *msg; -+ size_t msg_len; -+ -+ msg = data->prefix ? "CHALLENGE=Password" : "Password"; -+ -+ msg_len = os_strlen(msg); -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, msg_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for " -+ "request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ wpabuf_put_data(req, msg, msg_len); -+ -+ data->state = CONTINUE; -+ -+ return req; -+} -+ -+ -+static Boolean eap_gtc_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_gtc_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_gtc_data *data = priv; -+ const u8 *pos; -+ size_t rlen; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, respData, &rlen); -+ if (pos == NULL || rlen < 1) -+ return; /* Should not happen - frame already validated */ -+ -+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen); -+ -+#ifdef EAP_SERVER_FAST -+ if (data->prefix) { -+ const u8 *pos2, *end; -+ /* "RESPONSE=\0" */ -+ if (rlen < 10) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response " -+ "for EAP-FAST prefix"); -+ data->state = FAILURE; -+ return; -+ } -+ -+ end = pos + rlen; -+ pos += 9; -+ pos2 = pos; -+ while (pos2 < end && *pos2) -+ pos2++; -+ if (pos2 == end) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: No password in " -+ "response to EAP-FAST prefix"); -+ data->state = FAILURE; -+ return; -+ } -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user", -+ pos, pos2 - pos); -+ if (sm->identity && sm->require_identity_match && -+ (pos2 - pos != (int) sm->identity_len || -+ os_memcmp(pos, sm->identity, sm->identity_len))) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did " -+ "not match with required Identity"); -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected " -+ "identity", -+ sm->identity, sm->identity_len); -+ data->state = FAILURE; -+ return; -+ } else { -+ os_free(sm->identity); -+ sm->identity_len = pos2 - pos; -+ sm->identity = os_malloc(sm->identity_len); -+ if (sm->identity == NULL) { -+ data->state = FAILURE; -+ return; -+ } -+ os_memcpy(sm->identity, pos, sm->identity_len); -+ } -+ -+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 " -+ "Identity not found in the user " -+ "database", -+ sm->identity, sm->identity_len); -+ data->state = FAILURE; -+ return; -+ } -+ -+ pos = pos2 + 1; -+ rlen = end - pos; -+ wpa_hexdump_ascii_key(MSG_MSGDUMP, -+ "EAP-GTC: Response password", -+ pos, rlen); -+ } -+#endif /* EAP_SERVER_FAST */ -+ -+ if (sm->user == NULL || sm->user->password == NULL || -+ sm->user->password_hash) { -+ wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not " -+ "configured"); -+ data->state = FAILURE; -+ return; -+ } -+ -+ if (rlen != sm->user->password_len || -+ os_memcmp(pos, sm->user->password, rlen) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); -+ data->state = FAILURE; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Success"); -+ data->state = SUCCESS; -+ } -+} -+ -+ -+static Boolean eap_gtc_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gtc_data *data = priv; -+ return data->state != CONTINUE; -+} -+ -+ -+static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_gtc_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_gtc_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_gtc_init; -+ eap->reset = eap_gtc_reset; -+ eap->buildReq = eap_gtc_buildReq; -+ eap->check = eap_gtc_check; -+ eap->process = eap_gtc_process; -+ eap->isDone = eap_gtc_isDone; -+ eap->isSuccess = eap_gtc_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_identity.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_identity.c -new file mode 100644 -index 0000000000000..cd8da2a632b9b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_identity.c -@@ -0,0 +1,180 @@ -+/* -+ * hostapd / EAP-Identity -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+ -+ -+struct eap_identity_data { -+ enum { CONTINUE, SUCCESS, FAILURE } state; -+ int pick_up; -+}; -+ -+ -+static void * eap_identity_init(struct eap_sm *sm) -+{ -+ struct eap_identity_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = CONTINUE; -+ -+ return data; -+} -+ -+ -+static void * eap_identity_initPickUp(struct eap_sm *sm) -+{ -+ struct eap_identity_data *data; -+ data = eap_identity_init(sm); -+ if (data) { -+ data->pick_up = 1; -+ } -+ return data; -+} -+ -+ -+static void eap_identity_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_identity_data *data = priv; -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_identity_buildReq(struct eap_sm *sm, void *priv, -+ u8 id) -+{ -+ struct eap_identity_data *data = priv; -+ struct wpabuf *req; -+ const char *req_data; -+ size_t req_data_len; -+ -+ if (sm->eapol_cb->get_eap_req_id_text) { -+ req_data = sm->eapol_cb->get_eap_req_id_text(sm->eapol_ctx, -+ &req_data_len); -+ } else { -+ req_data = NULL; -+ req_data_len = 0; -+ } -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req_data_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate " -+ "memory for request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ wpabuf_put_data(req, req_data, req_data_len); -+ -+ return req; -+} -+ -+ -+static Boolean eap_identity_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, -+ respData, &len); -+ if (pos == NULL) { -+ wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_identity_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_identity_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ if (data->pick_up) { -+ if (eap_identity_check(sm, data, respData)) { -+ wpa_printf(MSG_DEBUG, "EAP-Identity: failed to pick " -+ "up already started negotiation"); -+ data->state = FAILURE; -+ return; -+ } -+ data->pick_up = 0; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, -+ respData, &len); -+ if (pos == NULL) -+ return; /* Should not happen - frame already validated */ -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len); -+ if (sm->identity) -+ sm->update_user = TRUE; -+ os_free(sm->identity); -+ sm->identity = os_malloc(len ? len : 1); -+ if (sm->identity == NULL) { -+ data->state = FAILURE; -+ } else { -+ os_memcpy(sm->identity, pos, len); -+ sm->identity_len = len; -+ data->state = SUCCESS; -+ } -+} -+ -+ -+static Boolean eap_identity_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_identity_data *data = priv; -+ return data->state != CONTINUE; -+} -+ -+ -+static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_identity_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_identity_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, -+ "Identity"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_identity_init; -+ eap->initPickUp = eap_identity_initPickUp; -+ eap->reset = eap_identity_reset; -+ eap->buildReq = eap_identity_buildReq; -+ eap->check = eap_identity_check; -+ eap->process = eap_identity_process; -+ eap->isDone = eap_identity_isDone; -+ eap->isSuccess = eap_identity_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ikev2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ikev2.c -new file mode 100644 -index 0000000000000..ec4fa8796fc65 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ikev2.c -@@ -0,0 +1,539 @@ -+/* -+ * EAP-IKEv2 server (RFC 5106) -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+#include "eap_common/eap_ikev2_common.h" -+#include "ikev2.h" -+ -+ -+struct eap_ikev2_data { -+ struct ikev2_initiator_data ikev2; -+ enum { MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; -+ struct wpabuf *in_buf; -+ struct wpabuf *out_buf; -+ size_t out_used; -+ size_t fragment_size; -+ int keys_ready; -+ u8 keymat[EAP_MSK_LEN + EAP_EMSK_LEN]; -+ int keymat_ok; -+}; -+ -+ -+static const u8 * eap_ikev2_get_shared_secret(void *ctx, const u8 *IDr, -+ size_t IDr_len, -+ size_t *secret_len) -+{ -+ struct eap_sm *sm = ctx; -+ -+ if (IDr == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: No IDr received - default " -+ "to user identity from EAP-Identity"); -+ IDr = sm->identity; -+ IDr_len = sm->identity_len; -+ } -+ -+ if (eap_user_get(sm, IDr, IDr_len, 0) < 0 || sm->user == NULL || -+ sm->user->password == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: No user entry found"); -+ return NULL; -+ } -+ -+ *secret_len = sm->user->password_len; -+ return sm->user->password; -+} -+ -+ -+static const char * eap_ikev2_state_txt(int state) -+{ -+ switch (state) { -+ case MSG: -+ return "MSG"; -+ case FRAG_ACK: -+ return "FRAG_ACK"; -+ case WAIT_FRAG_ACK: -+ return "WAIT_FRAG_ACK"; -+ case DONE: -+ return "DONE"; -+ case FAIL: -+ return "FAIL"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+static void eap_ikev2_state(struct eap_ikev2_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: %s -> %s", -+ eap_ikev2_state_txt(data->state), -+ eap_ikev2_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_ikev2_init(struct eap_sm *sm) -+{ -+ struct eap_ikev2_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = MSG; -+ data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : -+ IKEV2_FRAGMENT_SIZE; -+ data->ikev2.state = SA_INIT; -+ data->ikev2.peer_auth = PEER_AUTH_SECRET; -+ data->ikev2.key_pad = (u8 *) os_strdup("Key Pad for EAP-IKEv2"); -+ if (data->ikev2.key_pad == NULL) -+ goto failed; -+ data->ikev2.key_pad_len = 21; -+ -+ /* TODO: make proposals configurable */ -+ data->ikev2.proposal.proposal_num = 1; -+ data->ikev2.proposal.integ = AUTH_HMAC_SHA1_96; -+ data->ikev2.proposal.prf = PRF_HMAC_SHA1; -+ data->ikev2.proposal.encr = ENCR_AES_CBC; -+ data->ikev2.proposal.dh = DH_GROUP2_1024BIT_MODP; -+ -+ data->ikev2.IDi = (u8 *) os_strdup("hostapd"); -+ data->ikev2.IDi_len = 7; -+ -+ data->ikev2.get_shared_secret = eap_ikev2_get_shared_secret; -+ data->ikev2.cb_ctx = sm; -+ -+ return data; -+ -+failed: -+ ikev2_initiator_deinit(&data->ikev2); -+ os_free(data); -+ return NULL; -+} -+ -+ -+static void eap_ikev2_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ikev2_data *data = priv; -+ wpabuf_free(data->in_buf); -+ wpabuf_free(data->out_buf); -+ ikev2_initiator_deinit(&data->ikev2); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ u8 flags; -+ size_t send_len, plen, icv_len = 0; -+ -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Generating Request"); -+ -+ flags = 0; -+ send_len = wpabuf_len(data->out_buf) - data->out_used; -+ if (1 + send_len > data->fragment_size) { -+ send_len = data->fragment_size - 1; -+ flags |= IKEV2_FLAGS_MORE_FRAGMENTS; -+ if (data->out_used == 0) { -+ flags |= IKEV2_FLAGS_LENGTH_INCLUDED; -+ send_len -= 4; -+ } -+ } -+ -+ plen = 1 + send_len; -+ if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) -+ plen += 4; -+ if (data->keys_ready) { -+ const struct ikev2_integ_alg *integ; -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Add Integrity Checksum " -+ "Data"); -+ flags |= IKEV2_FLAGS_ICV_INCLUDED; -+ integ = ikev2_get_integ(data->ikev2.proposal.integ); -+ if (integ == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unknown INTEG " -+ "transform / cannot generate ICV"); -+ return NULL; -+ } -+ icv_len = integ->hash_len; -+ -+ plen += icv_len; -+ } -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, plen, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(req, flags); /* Flags */ -+ if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) -+ wpabuf_put_be32(req, wpabuf_len(data->out_buf)); -+ -+ wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, -+ send_len); -+ data->out_used += send_len; -+ -+ if (flags & IKEV2_FLAGS_ICV_INCLUDED) { -+ const u8 *msg = wpabuf_head(req); -+ size_t len = wpabuf_len(req); -+ ikev2_integ_hash(data->ikev2.proposal.integ, -+ data->ikev2.keys.SK_ai, -+ data->ikev2.keys.SK_integ_len, -+ msg, len, wpabuf_put(req, icv_len)); -+ } -+ -+ if (data->out_used == wpabuf_len(data->out_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " -+ "(message sent completely)", -+ (unsigned long) send_len); -+ wpabuf_free(data->out_buf); -+ data->out_buf = NULL; -+ data->out_used = 0; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Sending out %lu bytes " -+ "(%lu more to send)", (unsigned long) send_len, -+ (unsigned long) wpabuf_len(data->out_buf) - -+ data->out_used); -+ eap_ikev2_state(data, WAIT_FRAG_ACK); -+ } -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_ikev2_data *data = priv; -+ -+ switch (data->state) { -+ case MSG: -+ if (data->out_buf == NULL) { -+ data->out_buf = ikev2_initiator_build(&data->ikev2); -+ if (data->out_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to " -+ "generate IKEv2 message"); -+ return NULL; -+ } -+ data->out_used = 0; -+ } -+ /* pass through */ -+ case WAIT_FRAG_ACK: -+ return eap_ikev2_build_msg(data, id); -+ case FRAG_ACK: -+ return eap_ikev2_build_frag_ack(id, EAP_CODE_REQUEST); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected state %d in " -+ "buildReq", data->state); -+ return NULL; -+ } -+} -+ -+ -+static Boolean eap_ikev2_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, -+ &len); -+ if (pos == NULL) { -+ wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static int eap_ikev2_process_icv(struct eap_ikev2_data *data, -+ const struct wpabuf *respData, -+ u8 flags, const u8 *pos, const u8 **end) -+{ -+ if (flags & IKEV2_FLAGS_ICV_INCLUDED) { -+ int icv_len = eap_ikev2_validate_icv( -+ data->ikev2.proposal.integ, &data->ikev2.keys, 0, -+ respData, pos, *end); -+ if (icv_len < 0) -+ return -1; -+ /* Hide Integrity Checksum Data from further processing */ -+ *end -= icv_len; -+ } else if (data->keys_ready) { -+ wpa_printf(MSG_INFO, "EAP-IKEV2: The message should have " -+ "included integrity checksum"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ikev2_process_cont(struct eap_ikev2_data *data, -+ const u8 *buf, size_t len) -+{ -+ /* Process continuation of a pending message */ -+ if (len > wpabuf_tailroom(data->in_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment overflow"); -+ eap_ikev2_state(data, FAIL); -+ return -1; -+ } -+ -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes, waiting for %lu " -+ "bytes more", (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ -+ return 0; -+} -+ -+ -+static int eap_ikev2_process_fragment(struct eap_ikev2_data *data, -+ u8 flags, u32 message_length, -+ const u8 *buf, size_t len) -+{ -+ /* Process a fragment that is not the last one of the message */ -+ if (data->in_buf == NULL && !(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: No Message Length field in " -+ "a fragmented packet"); -+ return -1; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* First fragment of the message */ -+ data->in_buf = wpabuf_alloc(message_length); -+ if (data->in_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for " -+ "message"); -+ return -1; -+ } -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received %lu bytes in first " -+ "fragment, waiting for %lu bytes more", -+ (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_ikev2_server_keymat(struct eap_ikev2_data *data) -+{ -+ if (eap_ikev2_derive_keymat( -+ data->ikev2.proposal.prf, &data->ikev2.keys, -+ data->ikev2.i_nonce, data->ikev2.i_nonce_len, -+ data->ikev2.r_nonce, data->ikev2.r_nonce_len, -+ data->keymat) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Failed to derive " -+ "key material"); -+ return -1; -+ } -+ data->keymat_ok = 1; -+ return 0; -+} -+ -+ -+static void eap_ikev2_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_ikev2_data *data = priv; -+ const u8 *start, *pos, *end; -+ size_t len; -+ u8 flags; -+ u32 message_length = 0; -+ struct wpabuf tmpbuf; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, respData, -+ &len); -+ if (pos == NULL) -+ return; /* Should not happen; message already verified */ -+ -+ start = pos; -+ end = start + len; -+ -+ if (len == 0) { -+ /* fragment ack */ -+ flags = 0; -+ } else -+ flags = *pos++; -+ -+ if (eap_ikev2_process_icv(data, respData, flags, pos, &end) < 0) { -+ eap_ikev2_state(data, FAIL); -+ return; -+ } -+ -+ if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) { -+ if (end - pos < 4) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Message underflow"); -+ eap_ikev2_state(data, FAIL); -+ return; -+ } -+ message_length = WPA_GET_BE32(pos); -+ pos += 4; -+ -+ if (message_length < (u32) (end - pos)) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Invalid Message " -+ "Length (%d; %ld remaining in this msg)", -+ message_length, (long) (end - pos)); -+ eap_ikev2_state(data, FAIL); -+ return; -+ } -+ } -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Received packet: Flags 0x%x " -+ "Message Length %u", flags, message_length); -+ -+ if (data->state == WAIT_FRAG_ACK) { -+ if (len != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " -+ "in WAIT_FRAG_ACK state"); -+ eap_ikev2_state(data, FAIL); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Fragment acknowledged"); -+ eap_ikev2_state(data, MSG); -+ return; -+ } -+ -+ if (data->in_buf && eap_ikev2_process_cont(data, pos, end - pos) < 0) { -+ eap_ikev2_state(data, FAIL); -+ return; -+ } -+ -+ if (flags & IKEV2_FLAGS_MORE_FRAGMENTS) { -+ if (eap_ikev2_process_fragment(data, flags, message_length, -+ pos, end - pos) < 0) -+ eap_ikev2_state(data, FAIL); -+ else -+ eap_ikev2_state(data, FRAG_ACK); -+ return; -+ } else if (data->state == FRAG_ACK) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); -+ data->state = MSG; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* Wrap unfragmented messages as wpabuf without extra copy */ -+ wpabuf_set(&tmpbuf, pos, end - pos); -+ data->in_buf = &tmpbuf; -+ } -+ -+ if (ikev2_initiator_process(&data->ikev2, data->in_buf) < 0) { -+ if (data->in_buf == &tmpbuf) -+ data->in_buf = NULL; -+ eap_ikev2_state(data, FAIL); -+ return; -+ } -+ -+ switch (data->ikev2.state) { -+ case SA_AUTH: -+ /* SA_INIT was sent out, so message have to be -+ * integrity protected from now on. */ -+ data->keys_ready = 1; -+ break; -+ case IKEV2_DONE: -+ if (data->state == FAIL) -+ break; -+ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Authentication completed " -+ "successfully"); -+ if (eap_ikev2_server_keymat(data)) -+ break; -+ eap_ikev2_state(data, DONE); -+ break; -+ default: -+ break; -+ } -+ -+ if (data->in_buf != &tmpbuf) -+ wpabuf_free(data->in_buf); -+ data->in_buf = NULL; -+} -+ -+ -+static Boolean eap_ikev2_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ikev2_data *data = priv; -+ return data->state == DONE || data->state == FAIL; -+} -+ -+ -+static Boolean eap_ikev2_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ikev2_data *data = priv; -+ return data->state == DONE && data->ikev2.state == IKEV2_DONE && -+ data->keymat_ok; -+} -+ -+ -+static u8 * eap_ikev2_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_ikev2_data *data = priv; -+ u8 *key; -+ -+ if (data->state != DONE || !data->keymat_ok) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key) { -+ os_memcpy(key, data->keymat, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ } -+ -+ return key; -+} -+ -+ -+static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_ikev2_data *data = priv; -+ u8 *key; -+ -+ if (data->state != DONE || !data->keymat_ok) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key) { -+ os_memcpy(key, data->keymat + EAP_MSK_LEN, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ } -+ -+ return key; -+} -+ -+ -+int eap_server_ikev2_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_IKEV2, -+ "IKEV2"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_ikev2_init; -+ eap->reset = eap_ikev2_reset; -+ eap->buildReq = eap_ikev2_buildReq; -+ eap->check = eap_ikev2_check; -+ eap->process = eap_ikev2_process; -+ eap->isDone = eap_ikev2_isDone; -+ eap->getKey = eap_ikev2_getKey; -+ eap->isSuccess = eap_ikev2_isSuccess; -+ eap->get_emsk = eap_ikev2_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_md5.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_md5.c -new file mode 100644 -index 0000000000000..d03ec53b04701 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_md5.c -@@ -0,0 +1,177 @@ -+/* -+ * hostapd / EAP-MD5 server -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_i.h" -+#include "eap_common/chap.h" -+ -+ -+#define CHALLENGE_LEN 16 -+ -+struct eap_md5_data { -+ u8 challenge[CHALLENGE_LEN]; -+ enum { CONTINUE, SUCCESS, FAILURE } state; -+}; -+ -+ -+static void * eap_md5_init(struct eap_sm *sm) -+{ -+ struct eap_md5_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = CONTINUE; -+ -+ return data; -+} -+ -+ -+static void eap_md5_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_md5_data *data = priv; -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_md5_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_md5_data *data = priv; -+ struct wpabuf *req; -+ -+ if (random_get_bytes(data->challenge, CHALLENGE_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-MD5: Failed to get random data"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHALLENGE_LEN, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for " -+ "request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, CHALLENGE_LEN); -+ wpabuf_put_data(req, data->challenge, CHALLENGE_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", data->challenge, -+ CHALLENGE_LEN); -+ -+ data->state = CONTINUE; -+ -+ return req; -+} -+ -+ -+static Boolean eap_md5_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame"); -+ return TRUE; -+ } -+ if (*pos != CHAP_MD5_LEN || 1 + CHAP_MD5_LEN > len) { -+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid response " -+ "(response_len=%d payload_len=%lu", -+ *pos, (unsigned long) len); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_md5_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_md5_data *data = priv; -+ const u8 *pos; -+ size_t plen; -+ u8 hash[CHAP_MD5_LEN], id; -+ -+ if (sm->user == NULL || sm->user->password == NULL || -+ sm->user->password_hash) { -+ wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not " -+ "configured"); -+ data->state = FAILURE; -+ return; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, respData, &plen); -+ if (pos == NULL || *pos != CHAP_MD5_LEN || plen < 1 + CHAP_MD5_LEN) -+ return; /* Should not happen - frame already validated */ -+ -+ pos++; /* Skip response len */ -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN); -+ -+ id = eap_get_id(respData); -+ chap_md5(id, sm->user->password, sm->user->password_len, -+ data->challenge, CHALLENGE_LEN, hash); -+ -+ if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); -+ data->state = SUCCESS; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Failure"); -+ data->state = FAILURE; -+ } -+} -+ -+ -+static Boolean eap_md5_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_md5_data *data = priv; -+ return data->state != CONTINUE; -+} -+ -+ -+static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_md5_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_md5_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_md5_init; -+ eap->reset = eap_md5_reset; -+ eap->buildReq = eap_md5_buildReq; -+ eap->check = eap_md5_check; -+ eap->process = eap_md5_process; -+ eap->isDone = eap_md5_isDone; -+ eap->isSuccess = eap_md5_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_methods.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_methods.c -new file mode 100644 -index 0000000000000..900a5dd318105 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_methods.c -@@ -0,0 +1,175 @@ -+/* -+ * EAP server method registration -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+#include "eap_methods.h" -+ -+ -+static struct eap_method *eap_methods; -+ -+ -+/** -+ * eap_server_get_eap_method - Get EAP method based on type number -+ * @vendor: EAP Vendor-Id (0 = IETF) -+ * @method: EAP type number -+ * Returns: Pointer to EAP method or %NULL if not found -+ */ -+const struct eap_method * eap_server_get_eap_method(int vendor, EapType method) -+{ -+ struct eap_method *m; -+ for (m = eap_methods; m; m = m->next) { -+ if (m->vendor == vendor && m->method == method) -+ return m; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * eap_server_get_type - Get EAP type for the given EAP method name -+ * @name: EAP method name, e.g., TLS -+ * @vendor: Buffer for returning EAP Vendor-Id -+ * Returns: EAP method type or %EAP_TYPE_NONE if not found -+ * -+ * This function maps EAP type names into EAP type numbers based on the list of -+ * EAP methods included in the build. -+ */ -+EapType eap_server_get_type(const char *name, int *vendor) -+{ -+ struct eap_method *m; -+ for (m = eap_methods; m; m = m->next) { -+ if (os_strcmp(m->name, name) == 0) { -+ *vendor = m->vendor; -+ return m->method; -+ } -+ } -+ *vendor = EAP_VENDOR_IETF; -+ return EAP_TYPE_NONE; -+} -+ -+ -+/** -+ * eap_server_method_alloc - Allocate EAP server method structure -+ * @version: Version of the EAP server method interface (set to -+ * EAP_SERVER_METHOD_INTERFACE_VERSION) -+ * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) -+ * @method: EAP type number (EAP_TYPE_*) -+ * @name: Name of the method (e.g., "TLS") -+ * Returns: Allocated EAP method structure or %NULL on failure -+ * -+ * The returned structure should be freed with eap_server_method_free() when it -+ * is not needed anymore. -+ */ -+struct eap_method * eap_server_method_alloc(int version, int vendor, -+ EapType method, const char *name) -+{ -+ struct eap_method *eap; -+ eap = os_zalloc(sizeof(*eap)); -+ if (eap == NULL) -+ return NULL; -+ eap->version = version; -+ eap->vendor = vendor; -+ eap->method = method; -+ eap->name = name; -+ return eap; -+} -+ -+ -+/** -+ * eap_server_method_free - Free EAP server method structure -+ * @method: Method structure allocated with eap_server_method_alloc() -+ */ -+void eap_server_method_free(struct eap_method *method) -+{ -+ os_free(method); -+} -+ -+ -+/** -+ * eap_server_method_register - Register an EAP server method -+ * @method: EAP method to register -+ * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method -+ * has already been registered -+ * -+ * Each EAP server method needs to call this function to register itself as a -+ * supported EAP method. -+ */ -+int eap_server_method_register(struct eap_method *method) -+{ -+ struct eap_method *m, *last = NULL; -+ -+ if (method == NULL || method->name == NULL || -+ method->version != EAP_SERVER_METHOD_INTERFACE_VERSION) -+ return -1; -+ -+ for (m = eap_methods; m; m = m->next) { -+ if ((m->vendor == method->vendor && -+ m->method == method->method) || -+ os_strcmp(m->name, method->name) == 0) -+ return -2; -+ last = m; -+ } -+ -+ if (last) -+ last->next = method; -+ else -+ eap_methods = method; -+ -+ return 0; -+} -+ -+ -+/** -+ * eap_server_unregister_methods - Unregister EAP server methods -+ * -+ * This function is called at program termination to unregister all EAP server -+ * methods. -+ */ -+void eap_server_unregister_methods(void) -+{ -+ struct eap_method *m; -+ -+ while (eap_methods) { -+ m = eap_methods; -+ eap_methods = eap_methods->next; -+ -+ if (m->free) -+ m->free(m); -+ else -+ eap_server_method_free(m); -+ } -+} -+ -+ -+/** -+ * eap_server_get_name - Get EAP method name for the given EAP type -+ * @vendor: EAP Vendor-Id (0 = IETF) -+ * @type: EAP method type -+ * Returns: EAP method name, e.g., TLS, or %NULL if not found -+ * -+ * This function maps EAP type numbers into EAP type names based on the list of -+ * EAP methods included in the build. -+ */ -+const char * eap_server_get_name(int vendor, EapType type) -+{ -+ struct eap_method *m; -+ for (m = eap_methods; m; m = m->next) { -+ if (m->vendor == vendor && m->method == type) -+ return m->name; -+ } -+ return NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_mschapv2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_mschapv2.c -new file mode 100644 -index 0000000000000..64120a4f9b747 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_mschapv2.c -@@ -0,0 +1,575 @@ -+/* -+ * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/ms_funcs.h" -+#include "crypto/random.h" -+#include "eap_i.h" -+ -+ -+struct eap_mschapv2_hdr { -+ u8 op_code; /* MSCHAPV2_OP_* */ -+ u8 mschapv2_id; /* must be changed for challenges, but not for -+ * success/failure */ -+ u8 ms_length[2]; /* Note: misaligned; length - 5 */ -+ /* followed by data */ -+} STRUCT_PACKED; -+ -+#define MSCHAPV2_OP_CHALLENGE 1 -+#define MSCHAPV2_OP_RESPONSE 2 -+#define MSCHAPV2_OP_SUCCESS 3 -+#define MSCHAPV2_OP_FAILURE 4 -+#define MSCHAPV2_OP_CHANGE_PASSWORD 7 -+ -+#define MSCHAPV2_RESP_LEN 49 -+ -+#define ERROR_RESTRICTED_LOGON_HOURS 646 -+#define ERROR_ACCT_DISABLED 647 -+#define ERROR_PASSWD_EXPIRED 648 -+#define ERROR_NO_DIALIN_PERMISSION 649 -+#define ERROR_AUTHENTICATION_FAILURE 691 -+#define ERROR_CHANGING_PASSWORD 709 -+ -+#define PASSWD_CHANGE_CHAL_LEN 16 -+#define MSCHAPV2_KEY_LEN 16 -+ -+ -+#define CHALLENGE_LEN 16 -+ -+struct eap_mschapv2_data { -+ u8 auth_challenge[CHALLENGE_LEN]; -+ int auth_challenge_from_tls; -+ u8 *peer_challenge; -+ u8 auth_response[20]; -+ enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state; -+ u8 resp_mschapv2_id; -+ u8 master_key[16]; -+ int master_key_valid; -+}; -+ -+ -+static void * eap_mschapv2_init(struct eap_sm *sm) -+{ -+ struct eap_mschapv2_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = CHALLENGE; -+ -+ if (sm->auth_challenge) { -+ os_memcpy(data->auth_challenge, sm->auth_challenge, -+ CHALLENGE_LEN); -+ data->auth_challenge_from_tls = 1; -+ } -+ -+ if (sm->peer_challenge) { -+ data->peer_challenge = os_malloc(CHALLENGE_LEN); -+ if (data->peer_challenge == NULL) { -+ os_free(data); -+ return NULL; -+ } -+ os_memcpy(data->peer_challenge, sm->peer_challenge, -+ CHALLENGE_LEN); -+ } -+ -+ return data; -+} -+ -+ -+static void eap_mschapv2_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_mschapv2_data *data = priv; -+ if (data == NULL) -+ return; -+ -+ os_free(data->peer_challenge); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_mschapv2_build_challenge( -+ struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ struct eap_mschapv2_hdr *ms; -+ char *name = "hostapd"; /* TODO: make this configurable */ -+ size_t ms_len; -+ -+ if (!data->auth_challenge_from_tls && -+ random_get_bytes(data->auth_challenge, CHALLENGE_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random " -+ "data"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + os_strlen(name); -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" -+ " for request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ ms = wpabuf_put(req, sizeof(*ms)); -+ ms->op_code = MSCHAPV2_OP_CHALLENGE; -+ ms->mschapv2_id = id; -+ WPA_PUT_BE16(ms->ms_length, ms_len); -+ -+ wpabuf_put_u8(req, CHALLENGE_LEN); -+ if (!data->auth_challenge_from_tls) -+ wpabuf_put_data(req, data->auth_challenge, CHALLENGE_LEN); -+ else -+ wpabuf_put(req, CHALLENGE_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", -+ data->auth_challenge, CHALLENGE_LEN); -+ wpabuf_put_data(req, name, os_strlen(name)); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_mschapv2_build_success_req( -+ struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ struct eap_mschapv2_hdr *ms; -+ u8 *msg; -+ char *message = "OK"; -+ size_t ms_len; -+ -+ ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 + -+ os_strlen(message); -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" -+ " for request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ ms = wpabuf_put(req, sizeof(*ms)); -+ ms->op_code = MSCHAPV2_OP_SUCCESS; -+ ms->mschapv2_id = data->resp_mschapv2_id; -+ WPA_PUT_BE16(ms->ms_length, ms_len); -+ msg = (u8 *) (ms + 1); -+ -+ wpabuf_put_u8(req, 'S'); -+ wpabuf_put_u8(req, '='); -+ wpa_snprintf_hex_uppercase( -+ wpabuf_put(req, sizeof(data->auth_response) * 2), -+ sizeof(data->auth_response) * 2 + 1, -+ data->auth_response, sizeof(data->auth_response)); -+ wpabuf_put_u8(req, ' '); -+ wpabuf_put_u8(req, 'M'); -+ wpabuf_put_u8(req, '='); -+ wpabuf_put_data(req, message, os_strlen(message)); -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message", -+ msg, ms_len - sizeof(*ms)); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_mschapv2_build_failure_req( -+ struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ struct eap_mschapv2_hdr *ms; -+ char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 " -+ "M=FAILED"; -+ size_t ms_len; -+ -+ ms_len = sizeof(*ms) + os_strlen(message); -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory" -+ " for request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ ms = wpabuf_put(req, sizeof(*ms)); -+ ms->op_code = MSCHAPV2_OP_FAILURE; -+ ms->mschapv2_id = data->resp_mschapv2_id; -+ WPA_PUT_BE16(ms->ms_length, ms_len); -+ -+ wpabuf_put_data(req, message, os_strlen(message)); -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message", -+ (u8 *) message, os_strlen(message)); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_mschapv2_buildReq(struct eap_sm *sm, void *priv, -+ u8 id) -+{ -+ struct eap_mschapv2_data *data = priv; -+ -+ switch (data->state) { -+ case CHALLENGE: -+ return eap_mschapv2_build_challenge(sm, data, id); -+ case SUCCESS_REQ: -+ return eap_mschapv2_build_success_req(sm, data, id); -+ case FAILURE_REQ: -+ return eap_mschapv2_build_failure_req(sm, data, id); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in " -+ "buildReq", data->state); -+ break; -+ } -+ return NULL; -+} -+ -+ -+static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_mschapv2_data *data = priv; -+ struct eap_mschapv2_hdr *resp; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, -+ &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame"); -+ return TRUE; -+ } -+ -+ resp = (struct eap_mschapv2_hdr *) pos; -+ if (data->state == CHALLENGE && -+ resp->op_code != MSCHAPV2_OP_RESPONSE) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - " -+ "ignore op %d", resp->op_code); -+ return TRUE; -+ } -+ -+ if (data->state == SUCCESS_REQ && -+ resp->op_code != MSCHAPV2_OP_SUCCESS && -+ resp->op_code != MSCHAPV2_OP_FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Success or " -+ "Failure - ignore op %d", resp->op_code); -+ return TRUE; -+ } -+ -+ if (data->state == FAILURE_REQ && -+ resp->op_code != MSCHAPV2_OP_FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Failure " -+ "- ignore op %d", resp->op_code); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_mschapv2_process_response(struct eap_sm *sm, -+ struct eap_mschapv2_data *data, -+ struct wpabuf *respData) -+{ -+ struct eap_mschapv2_hdr *resp; -+ const u8 *pos, *end, *peer_challenge, *nt_response, *name; -+ u8 flags; -+ size_t len, name_len, i; -+ u8 expected[24]; -+ const u8 *username, *user; -+ size_t username_len, user_len; -+ int res; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, -+ &len); -+ if (pos == NULL || len < 1) -+ return; /* Should not happen - frame already validated */ -+ -+ end = pos + len; -+ resp = (struct eap_mschapv2_hdr *) pos; -+ pos = (u8 *) (resp + 1); -+ -+ if (len < sizeof(*resp) + 1 + 49 || -+ resp->op_code != MSCHAPV2_OP_RESPONSE || -+ pos[0] != 49) { -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response", -+ respData); -+ data->state = FAILURE; -+ return; -+ } -+ data->resp_mschapv2_id = resp->mschapv2_id; -+ pos++; -+ peer_challenge = pos; -+ pos += 16 + 8; -+ nt_response = pos; -+ pos += 24; -+ flags = *pos++; -+ name = pos; -+ name_len = end - name; -+ -+ if (data->peer_challenge) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured " -+ "Peer-Challenge"); -+ peer_challenge = data->peer_challenge; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge", -+ peer_challenge, 16); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24); -+ wpa_printf(MSG_MSGDUMP, "EAP-MSCHAPV2: Flags 0x%x", flags); -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Name", name, name_len); -+ -+ /* MSCHAPv2 does not include optional domain name in the -+ * challenge-response calculation, so remove domain prefix -+ * (if present). */ -+ username = sm->identity; -+ username_len = sm->identity_len; -+ for (i = 0; i < username_len; i++) { -+ if (username[i] == '\\') { -+ username_len -= i + 1; -+ username += i + 1; -+ break; -+ } -+ } -+ -+ user = name; -+ user_len = name_len; -+ for (i = 0; i < user_len; i++) { -+ if (user[i] == '\\') { -+ user_len -= i + 1; -+ user += i + 1; -+ break; -+ } -+ } -+ -+ if (username_len != user_len || -+ os_memcmp(username, user, username_len) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names"); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Expected user " -+ "name", username, username_len); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Received user " -+ "name", user, user_len); -+ data->state = FAILURE; -+ return; -+ } -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name", -+ username, username_len); -+ -+ if (sm->user->password_hash) { -+ res = generate_nt_response_pwhash(data->auth_challenge, -+ peer_challenge, -+ username, username_len, -+ sm->user->password, -+ expected); -+ } else { -+ res = generate_nt_response(data->auth_challenge, -+ peer_challenge, -+ username, username_len, -+ sm->user->password, -+ sm->user->password_len, -+ expected); -+ } -+ if (res) { -+ data->state = FAILURE; -+ return; -+ } -+ -+ if (os_memcmp(nt_response, expected, 24) == 0) { -+ const u8 *pw_hash; -+ u8 pw_hash_buf[16], pw_hash_hash[16]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response"); -+ data->state = SUCCESS_REQ; -+ -+ /* Authenticator response is not really needed yet, but -+ * calculate it here so that peer_challenge and username need -+ * not be saved. */ -+ if (sm->user->password_hash) { -+ pw_hash = sm->user->password; -+ } else { -+ nt_password_hash(sm->user->password, -+ sm->user->password_len, -+ pw_hash_buf); -+ pw_hash = pw_hash_buf; -+ } -+ generate_authenticator_response_pwhash( -+ pw_hash, peer_challenge, data->auth_challenge, -+ username, username_len, nt_response, -+ data->auth_response); -+ -+ hash_nt_password_hash(pw_hash, pw_hash_hash); -+ get_master_key(pw_hash_hash, nt_response, data->master_key); -+ data->master_key_valid = 1; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key", -+ data->master_key, MSCHAPV2_KEY_LEN); -+ } else { -+ wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response", -+ expected, 24); -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Invalid NT-Response"); -+ data->state = FAILURE_REQ; -+ } -+} -+ -+ -+static void eap_mschapv2_process_success_resp(struct eap_sm *sm, -+ struct eap_mschapv2_data *data, -+ struct wpabuf *respData) -+{ -+ struct eap_mschapv2_hdr *resp; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, -+ &len); -+ if (pos == NULL || len < 1) -+ return; /* Should not happen - frame already validated */ -+ -+ resp = (struct eap_mschapv2_hdr *) pos; -+ -+ if (resp->op_code == MSCHAPV2_OP_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response" -+ " - authentication completed successfully"); -+ data->state = SUCCESS; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Success " -+ "Response - peer rejected authentication"); -+ data->state = FAILURE; -+ } -+} -+ -+ -+static void eap_mschapv2_process_failure_resp(struct eap_sm *sm, -+ struct eap_mschapv2_data *data, -+ struct wpabuf *respData) -+{ -+ struct eap_mschapv2_hdr *resp; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respData, -+ &len); -+ if (pos == NULL || len < 1) -+ return; /* Should not happen - frame already validated */ -+ -+ resp = (struct eap_mschapv2_hdr *) pos; -+ -+ if (resp->op_code == MSCHAPV2_OP_FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response" -+ " - authentication failed"); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Did not receive Failure " -+ "Response - authentication failed"); -+ } -+ -+ data->state = FAILURE; -+} -+ -+ -+static void eap_mschapv2_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_mschapv2_data *data = priv; -+ -+ if (sm->user == NULL || sm->user->password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured"); -+ data->state = FAILURE; -+ return; -+ } -+ -+ switch (data->state) { -+ case CHALLENGE: -+ eap_mschapv2_process_response(sm, data, respData); -+ break; -+ case SUCCESS_REQ: -+ eap_mschapv2_process_success_resp(sm, data, respData); -+ break; -+ case FAILURE_REQ: -+ eap_mschapv2_process_failure_resp(sm, data, respData); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Unknown state %d in " -+ "process", data->state); -+ break; -+ } -+} -+ -+ -+static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_mschapv2_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_mschapv2_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS || !data->master_key_valid) -+ return NULL; -+ -+ *len = 2 * MSCHAPV2_KEY_LEN; -+ key = os_malloc(*len); -+ if (key == NULL) -+ return NULL; -+ /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */ -+ get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1); -+ get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, -+ MSCHAPV2_KEY_LEN, 1, 1); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len); -+ -+ return key; -+} -+ -+ -+static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_mschapv2_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_mschapv2_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, -+ "MSCHAPV2"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_mschapv2_init; -+ eap->reset = eap_mschapv2_reset; -+ eap->buildReq = eap_mschapv2_buildReq; -+ eap->check = eap_mschapv2_check; -+ eap->process = eap_mschapv2_process; -+ eap->isDone = eap_mschapv2_isDone; -+ eap->getKey = eap_mschapv2_getKey; -+ eap->isSuccess = eap_mschapv2_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pax.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pax.c -new file mode 100644 -index 0000000000000..4d64269a16d28 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pax.c -@@ -0,0 +1,570 @@ -+/* -+ * hostapd / EAP-PAX (RFC 4746) server -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_server/eap_i.h" -+#include "eap_common/eap_pax_common.h" -+ -+/* -+ * Note: only PAX_STD subprotocol is currently supported -+ * -+ * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite -+ * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and -+ * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits), -+ * RSAES-OAEP). -+ */ -+ -+struct eap_pax_data { -+ enum { PAX_STD_1, PAX_STD_3, SUCCESS, FAILURE } state; -+ u8 mac_id; -+ union { -+ u8 e[2 * EAP_PAX_RAND_LEN]; -+ struct { -+ u8 x[EAP_PAX_RAND_LEN]; /* server rand */ -+ u8 y[EAP_PAX_RAND_LEN]; /* client rand */ -+ } r; -+ } rand; -+ u8 ak[EAP_PAX_AK_LEN]; -+ u8 mk[EAP_PAX_MK_LEN]; -+ u8 ck[EAP_PAX_CK_LEN]; -+ u8 ick[EAP_PAX_ICK_LEN]; -+ int keys_set; -+ char *cid; -+ size_t cid_len; -+}; -+ -+ -+static void * eap_pax_init(struct eap_sm *sm) -+{ -+ struct eap_pax_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = PAX_STD_1; -+ /* -+ * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is -+ * supported -+ */ -+ data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128; -+ -+ return data; -+} -+ -+ -+static void eap_pax_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pax_data *data = priv; -+ os_free(data->cid); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_pax_build_std_1(struct eap_sm *sm, -+ struct eap_pax_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ struct eap_pax_hdr *pax; -+ u8 *pos; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (sending)"); -+ -+ if (random_get_bytes(data->rand.r.x, EAP_PAX_RAND_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX, -+ sizeof(*pax) + 2 + EAP_PAX_RAND_LEN + -+ EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory " -+ "request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ pax = wpabuf_put(req, sizeof(*pax)); -+ pax->op_code = EAP_PAX_OP_STD_1; -+ pax->flags = 0; -+ pax->mac_id = data->mac_id; -+ pax->dh_group_id = EAP_PAX_DH_GROUP_NONE; -+ pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE; -+ -+ wpabuf_put_be16(req, EAP_PAX_RAND_LEN); -+ wpabuf_put_data(req, data->rand.r.x, EAP_PAX_RAND_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: A = X (server rand)", -+ data->rand.r.x, EAP_PAX_RAND_LEN); -+ -+ pos = wpabuf_put(req, EAP_PAX_MAC_LEN); -+ eap_pax_mac(data->mac_id, (u8 *) "", 0, -+ wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN, -+ NULL, 0, NULL, 0, pos); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_pax_build_std_3(struct eap_sm *sm, -+ struct eap_pax_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ struct eap_pax_hdr *pax; -+ u8 *pos; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (sending)"); -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PAX, -+ sizeof(*pax) + 2 + EAP_PAX_MAC_LEN + -+ EAP_PAX_ICV_LEN, EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to allocate memory " -+ "request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ pax = wpabuf_put(req, sizeof(*pax)); -+ pax->op_code = EAP_PAX_OP_STD_3; -+ pax->flags = 0; -+ pax->mac_id = data->mac_id; -+ pax->dh_group_id = EAP_PAX_DH_GROUP_NONE; -+ pax->public_key_id = EAP_PAX_PUBLIC_KEY_NONE; -+ -+ wpabuf_put_be16(req, EAP_PAX_MAC_LEN); -+ pos = wpabuf_put(req, EAP_PAX_MAC_LEN); -+ eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, -+ data->rand.r.y, EAP_PAX_RAND_LEN, -+ (u8 *) data->cid, data->cid_len, NULL, 0, pos); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)", -+ pos, EAP_PAX_MAC_LEN); -+ pos += EAP_PAX_MAC_LEN; -+ -+ /* Optional ADE could be added here, if needed */ -+ -+ pos = wpabuf_put(req, EAP_PAX_MAC_LEN); -+ eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, -+ wpabuf_mhead(req), wpabuf_len(req) - EAP_PAX_ICV_LEN, -+ NULL, 0, NULL, 0, pos); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_pax_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_pax_data *data = priv; -+ -+ switch (data->state) { -+ case PAX_STD_1: -+ return eap_pax_build_std_1(sm, data, id); -+ case PAX_STD_3: -+ return eap_pax_build_std_3(sm, data, id); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown state %d in buildReq", -+ data->state); -+ break; -+ } -+ return NULL; -+} -+ -+ -+static Boolean eap_pax_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_pax_data *data = priv; -+ struct eap_pax_hdr *resp; -+ const u8 *pos; -+ size_t len, mlen; -+ u8 icvbuf[EAP_PAX_ICV_LEN], *icv; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); -+ if (pos == NULL || len < sizeof(*resp)) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Invalid frame"); -+ return TRUE; -+ } -+ -+ mlen = sizeof(struct eap_hdr) + 1 + len; -+ resp = (struct eap_pax_hdr *) pos; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x " -+ "flags 0x%x mac_id 0x%x dh_group_id 0x%x " -+ "public_key_id 0x%x", -+ resp->op_code, resp->flags, resp->mac_id, resp->dh_group_id, -+ resp->public_key_id); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload", -+ (u8 *) (resp + 1), len - sizeof(*resp) - EAP_PAX_ICV_LEN); -+ -+ if (data->state == PAX_STD_1 && -+ resp->op_code != EAP_PAX_OP_STD_2) { -+ wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX_STD-2 - " -+ "ignore op %d", resp->op_code); -+ return TRUE; -+ } -+ -+ if (data->state == PAX_STD_3 && -+ resp->op_code != EAP_PAX_OP_ACK) { -+ wpa_printf(MSG_DEBUG, "EAP-PAX: Expected PAX-ACK - " -+ "ignore op %d", resp->op_code); -+ return TRUE; -+ } -+ -+ if (resp->op_code != EAP_PAX_OP_STD_2 && -+ resp->op_code != EAP_PAX_OP_ACK) { -+ wpa_printf(MSG_DEBUG, "EAP-PAX: Unknown op_code 0x%x", -+ resp->op_code); -+ } -+ -+ if (data->mac_id != resp->mac_id) { -+ wpa_printf(MSG_DEBUG, "EAP-PAX: Expected MAC ID 0x%x, " -+ "received 0x%x", data->mac_id, resp->mac_id); -+ return TRUE; -+ } -+ -+ if (resp->dh_group_id != EAP_PAX_DH_GROUP_NONE) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Expected DH Group ID 0x%x, " -+ "received 0x%x", EAP_PAX_DH_GROUP_NONE, -+ resp->dh_group_id); -+ return TRUE; -+ } -+ -+ if (resp->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Expected Public Key ID 0x%x, " -+ "received 0x%x", EAP_PAX_PUBLIC_KEY_NONE, -+ resp->public_key_id); -+ return TRUE; -+ } -+ -+ if (resp->flags & EAP_PAX_FLAGS_MF) { -+ /* TODO: add support for reassembling fragments */ -+ wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported"); -+ return TRUE; -+ } -+ -+ if (resp->flags & EAP_PAX_FLAGS_CE) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Unexpected CE flag"); -+ return TRUE; -+ } -+ -+ if (data->keys_set) { -+ if (len - sizeof(*resp) < EAP_PAX_ICV_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: No ICV in the packet"); -+ return TRUE; -+ } -+ icv = wpabuf_mhead_u8(respData) + mlen - EAP_PAX_ICV_LEN; -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN); -+ eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, -+ wpabuf_mhead(respData), -+ wpabuf_len(respData) - EAP_PAX_ICV_LEN, -+ NULL, 0, NULL, 0, icvbuf); -+ if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", -+ icvbuf, EAP_PAX_ICV_LEN); -+ return TRUE; -+ } -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_pax_process_std_2(struct eap_sm *sm, -+ struct eap_pax_data *data, -+ struct wpabuf *respData) -+{ -+ struct eap_pax_hdr *resp; -+ u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN]; -+ const u8 *pos; -+ size_t len, left; -+ int i; -+ -+ if (data->state != PAX_STD_1) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX_STD-2"); -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); -+ if (pos == NULL || len < sizeof(*resp) + EAP_PAX_ICV_LEN) -+ return; -+ -+ resp = (struct eap_pax_hdr *) pos; -+ pos = (u8 *) (resp + 1); -+ left = len - sizeof(*resp); -+ -+ if (left < 2 + EAP_PAX_RAND_LEN || -+ WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (B)"); -+ return; -+ } -+ pos += 2; -+ left -= 2; -+ os_memcpy(data->rand.r.y, pos, EAP_PAX_RAND_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)", -+ data->rand.r.y, EAP_PAX_RAND_LEN); -+ pos += EAP_PAX_RAND_LEN; -+ left -= EAP_PAX_RAND_LEN; -+ -+ if (left < 2 || (size_t) 2 + WPA_GET_BE16(pos) > left) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)"); -+ return; -+ } -+ data->cid_len = WPA_GET_BE16(pos); -+ os_free(data->cid); -+ data->cid = os_malloc(data->cid_len); -+ if (data->cid == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Failed to allocate memory for " -+ "CID"); -+ return; -+ } -+ os_memcpy(data->cid, pos + 2, data->cid_len); -+ pos += 2 + data->cid_len; -+ left -= 2 + data->cid_len; -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", -+ (u8 *) data->cid, data->cid_len); -+ -+ if (left < 2 + EAP_PAX_MAC_LEN || -+ WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (MAC_CK)"); -+ return; -+ } -+ pos += 2; -+ left -= 2; -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)", -+ pos, EAP_PAX_MAC_LEN); -+ -+ if (eap_user_get(sm, (u8 *) data->cid, data->cid_len, 0) < 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: unknown CID", -+ (u8 *) data->cid, data->cid_len); -+ data->state = FAILURE; -+ return; -+ } -+ -+ for (i = 0; -+ i < EAP_MAX_METHODS && -+ (sm->user->methods[i].vendor != EAP_VENDOR_IETF || -+ sm->user->methods[i].method != EAP_TYPE_NONE); -+ i++) { -+ if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && -+ sm->user->methods[i].method == EAP_TYPE_PAX) -+ break; -+ } -+ -+ if (i >= EAP_MAX_METHODS || -+ sm->user->methods[i].vendor != EAP_VENDOR_IETF || -+ sm->user->methods[i].method != EAP_TYPE_PAX) { -+ wpa_hexdump_ascii(MSG_DEBUG, -+ "EAP-PAX: EAP-PAX not enabled for CID", -+ (u8 *) data->cid, data->cid_len); -+ data->state = FAILURE; -+ return; -+ } -+ -+ if (sm->user->password == NULL || -+ sm->user->password_len != EAP_PAX_AK_LEN) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PAX: invalid password in " -+ "user database for CID", -+ (u8 *) data->cid, data->cid_len); -+ data->state = FAILURE; -+ return; -+ } -+ os_memcpy(data->ak, sm->user->password, EAP_PAX_AK_LEN); -+ -+ if (eap_pax_initial_key_derivation(data->mac_id, data->ak, -+ data->rand.e, data->mk, data->ck, -+ data->ick) < 0) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial " -+ "key derivation"); -+ data->state = FAILURE; -+ return; -+ } -+ data->keys_set = 1; -+ -+ eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, -+ data->rand.r.x, EAP_PAX_RAND_LEN, -+ data->rand.r.y, EAP_PAX_RAND_LEN, -+ (u8 *) data->cid, data->cid_len, mac); -+ if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in " -+ "PAX_STD-2"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)", -+ mac, EAP_PAX_MAC_LEN); -+ data->state = FAILURE; -+ return; -+ } -+ -+ pos += EAP_PAX_MAC_LEN; -+ left -= EAP_PAX_MAC_LEN; -+ -+ if (left < EAP_PAX_ICV_LEN) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Too short ICV (%lu) in " -+ "PAX_STD-2", (unsigned long) left); -+ return; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", pos, EAP_PAX_ICV_LEN); -+ eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN, -+ wpabuf_head(respData), -+ wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, -+ icvbuf); -+ if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", -+ icvbuf, EAP_PAX_ICV_LEN); -+ return; -+ } -+ pos += EAP_PAX_ICV_LEN; -+ left -= EAP_PAX_ICV_LEN; -+ -+ if (left > 0) { -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload", -+ pos, left); -+ } -+ -+ data->state = PAX_STD_3; -+} -+ -+ -+static void eap_pax_process_ack(struct eap_sm *sm, -+ struct eap_pax_data *data, -+ struct wpabuf *respData) -+{ -+ if (data->state != PAX_STD_3) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PAX: Received PAX-ACK - authentication " -+ "completed successfully"); -+ data->state = SUCCESS; -+} -+ -+ -+static void eap_pax_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_pax_data *data = priv; -+ struct eap_pax_hdr *resp; -+ const u8 *pos; -+ size_t len; -+ -+ if (sm->user == NULL || sm->user->password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not " -+ "configured"); -+ data->state = FAILURE; -+ return; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX, respData, &len); -+ if (pos == NULL || len < sizeof(*resp)) -+ return; -+ -+ resp = (struct eap_pax_hdr *) pos; -+ -+ switch (resp->op_code) { -+ case EAP_PAX_OP_STD_2: -+ eap_pax_process_std_2(sm, data, respData); -+ break; -+ case EAP_PAX_OP_ACK: -+ eap_pax_process_ack(sm, data, respData); -+ break; -+ } -+} -+ -+ -+static Boolean eap_pax_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pax_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pax_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_MSK_LEN; -+ eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, -+ "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN, -+ EAP_MSK_LEN, key); -+ -+ return key; -+} -+ -+ -+static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pax_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ *len = EAP_EMSK_LEN; -+ eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN, -+ "Extended Master Session Key", -+ data->rand.e, 2 * EAP_PAX_RAND_LEN, -+ EAP_EMSK_LEN, key); -+ -+ return key; -+} -+ -+ -+static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pax_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_pax_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_pax_init; -+ eap->reset = eap_pax_reset; -+ eap->buildReq = eap_pax_buildReq; -+ eap->check = eap_pax_check; -+ eap->process = eap_pax_process; -+ eap->isDone = eap_pax_isDone; -+ eap->getKey = eap_pax_getKey; -+ eap->isSuccess = eap_pax_isSuccess; -+ eap->get_emsk = eap_pax_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_peap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_peap.c -new file mode 100644 -index 0000000000000..8a7d626a63a14 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_peap.c -@@ -0,0 +1,1387 @@ -+/* -+ * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "crypto/random.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+#include "eap_common/eap_tlv_common.h" -+#include "eap_common/eap_peap_common.h" -+#include "tncs.h" -+ -+ -+/* Maximum supported PEAP version -+ * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt -+ * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt -+ * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt -+ */ -+#define EAP_PEAP_VERSION 1 -+ -+ -+static void eap_peap_reset(struct eap_sm *sm, void *priv); -+ -+ -+struct eap_peap_data { -+ struct eap_ssl_data ssl; -+ enum { -+ START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID, -+ PHASE2_METHOD, PHASE2_SOH, -+ PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE -+ } state; -+ -+ int peap_version; -+ int recv_version; -+ const struct eap_method *phase2_method; -+ void *phase2_priv; -+ int force_version; -+ struct wpabuf *pending_phase2_resp; -+ enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request; -+ int crypto_binding_sent; -+ int crypto_binding_used; -+ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; -+ u8 binding_nonce[32]; -+ u8 ipmk[40]; -+ u8 cmk[20]; -+ u8 *phase2_key; -+ size_t phase2_key_len; -+ struct wpabuf *soh_response; -+}; -+ -+ -+static const char * eap_peap_state_txt(int state) -+{ -+ switch (state) { -+ case START: -+ return "START"; -+ case PHASE1: -+ return "PHASE1"; -+ case PHASE1_ID2: -+ return "PHASE1_ID2"; -+ case PHASE2_START: -+ return "PHASE2_START"; -+ case PHASE2_ID: -+ return "PHASE2_ID"; -+ case PHASE2_METHOD: -+ return "PHASE2_METHOD"; -+ case PHASE2_SOH: -+ return "PHASE2_SOH"; -+ case PHASE2_TLV: -+ return "PHASE2_TLV"; -+ case SUCCESS_REQ: -+ return "SUCCESS_REQ"; -+ case FAILURE_REQ: -+ return "FAILURE_REQ"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "Unknown?!"; -+ } -+} -+ -+ -+static void eap_peap_state(struct eap_peap_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s", -+ eap_peap_state_txt(data->state), -+ eap_peap_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) -+{ -+ struct wpabuf *e; -+ struct eap_tlv_hdr *tlv; -+ -+ if (buf == NULL) -+ return NULL; -+ -+ /* Encapsulate EAP packet in EAP-Payload TLV */ -+ wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); -+ e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); -+ if (e == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " -+ "for TLV encapsulation"); -+ wpabuf_free(buf); -+ return NULL; -+ } -+ tlv = wpabuf_put(e, sizeof(*tlv)); -+ tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | -+ EAP_TLV_EAP_PAYLOAD_TLV); -+ tlv->length = host_to_be16(wpabuf_len(buf)); -+ wpabuf_put_buf(e, buf); -+ wpabuf_free(buf); -+ return e; -+} -+ -+ -+static void eap_peap_req_success(struct eap_sm *sm, -+ struct eap_peap_data *data) -+{ -+ if (data->state == FAILURE || data->state == FAILURE_REQ) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ if (data->peap_version == 0) { -+ data->tlv_request = TLV_REQ_SUCCESS; -+ eap_peap_state(data, PHASE2_TLV); -+ } else { -+ eap_peap_state(data, SUCCESS_REQ); -+ } -+} -+ -+ -+static void eap_peap_req_failure(struct eap_sm *sm, -+ struct eap_peap_data *data) -+{ -+ if (data->state == FAILURE || data->state == FAILURE_REQ || -+ data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ if (data->peap_version == 0) { -+ data->tlv_request = TLV_REQ_FAILURE; -+ eap_peap_state(data, PHASE2_TLV); -+ } else { -+ eap_peap_state(data, FAILURE_REQ); -+ } -+} -+ -+ -+static void * eap_peap_init(struct eap_sm *sm) -+{ -+ struct eap_peap_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->peap_version = EAP_PEAP_VERSION; -+ data->force_version = -1; -+ if (sm->user && sm->user->force_version >= 0) { -+ data->force_version = sm->user->force_version; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d", -+ data->force_version); -+ data->peap_version = data->force_version; -+ } -+ data->state = START; -+ data->crypto_binding = OPTIONAL_BINDING; -+ -+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); -+ eap_peap_reset(sm, data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_peap_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ if (data == NULL) -+ return; -+ if (data->phase2_priv && data->phase2_method) -+ data->phase2_method->reset(sm, data->phase2_priv); -+ eap_server_tls_ssl_deinit(sm, &data->ssl); -+ wpabuf_free(data->pending_phase2_resp); -+ os_free(data->phase2_key); -+ wpabuf_free(data->soh_response); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_peap_build_start(struct eap_sm *sm, -+ struct eap_peap_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for" -+ " request"); -+ eap_peap_state(data, FAILURE); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version); -+ -+ eap_peap_state(data, PHASE1); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ u8 id) -+{ -+ struct wpabuf *buf, *encr_req, msgbuf; -+ const u8 *req; -+ size_t req_len; -+ -+ if (data->phase2_method == NULL || data->phase2_priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready"); -+ return NULL; -+ } -+ buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); -+ if (data->peap_version >= 2 && buf) -+ buf = eap_peapv2_tlv_eap_payload(buf); -+ if (buf == NULL) -+ return NULL; -+ -+ req = wpabuf_head(buf); -+ req_len = wpabuf_len(buf); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", -+ req, req_len); -+ -+ if (data->peap_version == 0 && -+ data->phase2_method->method != EAP_TYPE_TLV) { -+ req += sizeof(struct eap_hdr); -+ req_len -= sizeof(struct eap_hdr); -+ } -+ -+ wpabuf_set(&msgbuf, req, req_len); -+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); -+ wpabuf_free(buf); -+ -+ return encr_req; -+} -+ -+ -+#ifdef EAP_SERVER_TNC -+static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ u8 id) -+{ -+ struct wpabuf *buf1, *buf, *encr_req, msgbuf; -+ const u8 *req; -+ size_t req_len; -+ -+ buf1 = tncs_build_soh_request(); -+ if (buf1 == NULL) -+ return NULL; -+ -+ buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1), -+ EAP_CODE_REQUEST, id); -+ if (buf == NULL) { -+ wpabuf_free(buf1); -+ return NULL; -+ } -+ wpabuf_put_buf(buf, buf1); -+ wpabuf_free(buf1); -+ -+ req = wpabuf_head(buf); -+ req_len = wpabuf_len(buf); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data", -+ req, req_len); -+ -+ req += sizeof(struct eap_hdr); -+ req_len -= sizeof(struct eap_hdr); -+ wpabuf_set(&msgbuf, req, req_len); -+ -+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); -+ wpabuf_free(buf); -+ -+ return encr_req; -+} -+#endif /* EAP_SERVER_TNC */ -+ -+ -+static void eap_peap_get_isk(struct eap_peap_data *data, -+ u8 *isk, size_t isk_len) -+{ -+ size_t key_len; -+ -+ os_memset(isk, 0, isk_len); -+ if (data->phase2_key == NULL) -+ return; -+ -+ key_len = data->phase2_key_len; -+ if (key_len > isk_len) -+ key_len = isk_len; -+ os_memcpy(isk, data->phase2_key, key_len); -+} -+ -+ -+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) -+{ -+ u8 *tk; -+ u8 isk[32], imck[60]; -+ -+ /* -+ * Tunnel key (TK) is the first 60 octets of the key generated by -+ * phase 1 of PEAP (based on TLS). -+ */ -+ tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption", -+ EAP_TLS_KEY_LEN); -+ if (tk == NULL) -+ return -1; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); -+ -+ eap_peap_get_isk(data, isk, sizeof(isk)); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); -+ -+ /* -+ * IPMK Seed = "Inner Methods Compound Keys" | ISK -+ * TempKey = First 40 octets of TK -+ * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) -+ * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space -+ * in the end of the label just before ISK; is that just a typo?) -+ */ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); -+ peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys", -+ isk, sizeof(isk), imck, sizeof(imck)); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", -+ imck, sizeof(imck)); -+ -+ os_free(tk); -+ -+ /* TODO: fast-connect: IPMK|CMK = TK */ -+ os_memcpy(data->ipmk, imck, 40); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); -+ os_memcpy(data->cmk, imck + 40, 20); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ u8 id) -+{ -+ struct wpabuf *buf, *encr_req; -+ size_t mlen; -+ -+ mlen = 6; /* Result TLV */ -+ if (data->crypto_binding != NO_BINDING) -+ mlen += 60; /* Cryptobinding TLV */ -+#ifdef EAP_SERVER_TNC -+ if (data->soh_response) -+ mlen += wpabuf_len(data->soh_response); -+#endif /* EAP_SERVER_TNC */ -+ -+ buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen, -+ EAP_CODE_REQUEST, id); -+ if (buf == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(buf, 0x80); /* Mandatory */ -+ wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV); -+ /* Length */ -+ wpabuf_put_be16(buf, 2); -+ /* Status */ -+ wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ? -+ EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE); -+ -+ if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS && -+ data->crypto_binding != NO_BINDING) { -+ u8 *mac; -+ u8 eap_type = EAP_TYPE_PEAP; -+ const u8 *addr[2]; -+ size_t len[2]; -+ u16 tlv_type; -+ -+#ifdef EAP_SERVER_TNC -+ if (data->soh_response) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH " -+ "Response TLV"); -+ wpabuf_put_buf(buf, data->soh_response); -+ wpabuf_free(data->soh_response); -+ data->soh_response = NULL; -+ } -+#endif /* EAP_SERVER_TNC */ -+ -+ if (eap_peap_derive_cmk(sm, data) < 0 || -+ random_get_bytes(data->binding_nonce, 32)) { -+ wpabuf_free(buf); -+ return NULL; -+ } -+ -+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ -+ addr[0] = wpabuf_put(buf, 0); -+ len[0] = 60; -+ addr[1] = &eap_type; -+ len[1] = 1; -+ -+ tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; -+ if (data->peap_version >= 2) -+ tlv_type |= EAP_TLV_TYPE_MANDATORY; -+ wpabuf_put_be16(buf, tlv_type); -+ wpabuf_put_be16(buf, 56); -+ -+ wpabuf_put_u8(buf, 0); /* Reserved */ -+ wpabuf_put_u8(buf, data->peap_version); /* Version */ -+ wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */ -+ wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */ -+ wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ -+ mac = wpabuf_put(buf, 20); /* Compound_MAC */ -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", -+ data->cmk, 20); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", -+ addr[0], len[0]); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", -+ addr[1], len[1]); -+ hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", -+ mac, SHA1_MAC_LEN); -+ data->crypto_binding_sent = 1; -+ } -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", -+ buf); -+ -+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); -+ wpabuf_free(buf); -+ -+ return encr_req; -+} -+ -+ -+static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ u8 id, int success) -+{ -+ struct wpabuf *encr_req, msgbuf; -+ size_t req_len; -+ struct eap_hdr *hdr; -+ -+ req_len = sizeof(*hdr); -+ hdr = os_zalloc(req_len); -+ if (hdr == NULL) -+ return NULL; -+ -+ hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; -+ hdr->identifier = id; -+ hdr->length = host_to_be16(req_len); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", -+ (u8 *) hdr, req_len); -+ -+ wpabuf_set(&msgbuf, hdr, req_len); -+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); -+ os_free(hdr); -+ -+ return encr_req; -+} -+ -+ -+static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_peap_data *data = priv; -+ -+ if (data->ssl.state == FRAG_ACK) { -+ return eap_server_tls_build_ack(id, EAP_TYPE_PEAP, -+ data->peap_version); -+ } -+ -+ if (data->ssl.state == WAIT_FRAG_ACK) { -+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, -+ data->peap_version, id); -+ } -+ -+ switch (data->state) { -+ case START: -+ return eap_peap_build_start(sm, data, id); -+ case PHASE1: -+ case PHASE1_ID2: -+ if (data->peap_version < 2 && -+ tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " -+ "starting Phase2"); -+ eap_peap_state(data, PHASE2_START); -+ } -+ break; -+ case PHASE2_ID: -+ case PHASE2_METHOD: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id); -+ break; -+#ifdef EAP_SERVER_TNC -+ case PHASE2_SOH: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id); -+ break; -+#endif /* EAP_SERVER_TNC */ -+ case PHASE2_TLV: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id); -+ break; -+ case SUCCESS_REQ: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, -+ 1); -+ break; -+ case FAILURE_REQ: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, -+ 0); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", -+ __func__, data->state); -+ return NULL; -+ } -+ -+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, -+ data->peap_version, id); -+} -+ -+ -+static Boolean eap_peap_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, -+ EapType eap_type) -+{ -+ if (data->phase2_priv && data->phase2_method) { -+ data->phase2_method->reset(sm, data->phase2_priv); -+ data->phase2_method = NULL; -+ data->phase2_priv = NULL; -+ } -+ data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, -+ eap_type); -+ if (!data->phase2_method) -+ return -1; -+ -+ sm->init_phase2 = 1; -+ data->phase2_priv = data->phase2_method->init(sm); -+ sm->init_phase2 = 0; -+ return 0; -+} -+ -+ -+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ const u8 *crypto_tlv, -+ size_t crypto_tlv_len) -+{ -+ u8 buf[61], mac[SHA1_MAC_LEN]; -+ const u8 *pos; -+ -+ if (crypto_tlv_len != 4 + 56) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " -+ "length %d", (int) crypto_tlv_len); -+ return -1; -+ } -+ -+ pos = crypto_tlv; -+ pos += 4; /* TLV header */ -+ if (pos[1] != data->peap_version) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " -+ "mismatch (was %d; expected %d)", -+ pos[1], data->peap_version); -+ return -1; -+ } -+ -+ if (pos[3] != 1) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " -+ "SubType %d", pos[3]); -+ return -1; -+ } -+ pos += 4; -+ pos += 32; /* Nonce */ -+ -+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ -+ os_memcpy(buf, crypto_tlv, 60); -+ os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ -+ buf[60] = EAP_TYPE_PEAP; -+ hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); -+ -+ if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " -+ "cryptobinding TLV"); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20); -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data", -+ buf, 61); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); -+ -+ return 0; -+} -+ -+ -+static void eap_peap_process_phase2_tlv(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ struct wpabuf *in_data) -+{ -+ const u8 *pos; -+ size_t left; -+ const u8 *result_tlv = NULL, *crypto_tlv = NULL; -+ size_t result_tlv_len = 0, crypto_tlv_len = 0; -+ int tlv_type, mandatory, tlv_len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left); -+ if (pos == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header"); -+ return; -+ } -+ -+ /* Parse TLVs */ -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left); -+ while (left >= 4) { -+ mandatory = !!(pos[0] & 0x80); -+ tlv_type = pos[0] & 0x3f; -+ tlv_type = (tlv_type << 8) | pos[1]; -+ tlv_len = ((int) pos[2] << 8) | pos[3]; -+ pos += 4; -+ left -= 4; -+ if ((size_t) tlv_len > left) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " -+ "(tlv_len=%d left=%lu)", tlv_len, -+ (unsigned long) left); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ switch (tlv_type) { -+ case EAP_TLV_RESULT_TLV: -+ result_tlv = pos; -+ result_tlv_len = tlv_len; -+ break; -+ case EAP_TLV_CRYPTO_BINDING_TLV: -+ crypto_tlv = pos; -+ crypto_tlv_len = tlv_len; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " -+ "%d%s", tlv_type, -+ mandatory ? " (mandatory)" : ""); -+ if (mandatory) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ /* Ignore this TLV, but process other TLVs */ -+ break; -+ } -+ -+ pos += tlv_len; -+ left -= tlv_len; -+ } -+ if (left) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " -+ "Request (left=%lu)", (unsigned long) left); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ /* Process supported TLVs */ -+ if (crypto_tlv && data->crypto_binding_sent) { -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", -+ crypto_tlv, crypto_tlv_len); -+ if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, -+ crypto_tlv_len + 4) < 0) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ data->crypto_binding_used = 1; -+ } else if (!crypto_tlv && data->crypto_binding_sent && -+ data->crypto_binding == REQUIRE_BINDING) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ if (result_tlv) { -+ int status; -+ const char *requested; -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV", -+ result_tlv, result_tlv_len); -+ if (result_tlv_len < 2) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV " -+ "(len=%lu)", -+ (unsigned long) result_tlv_len); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" : -+ "Failure"; -+ status = WPA_GET_BE16(result_tlv); -+ if (status == EAP_TLV_RESULT_SUCCESS) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success " -+ "- requested %s", requested); -+ if (data->tlv_request == TLV_REQ_SUCCESS) -+ eap_peap_state(data, SUCCESS); -+ else -+ eap_peap_state(data, FAILURE); -+ -+ } else if (status == EAP_TLV_RESULT_FAILURE) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure " -+ "- requested %s", requested); -+ eap_peap_state(data, FAILURE); -+ } else { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result " -+ "Status %d", status); -+ eap_peap_state(data, FAILURE); -+ } -+ } -+} -+ -+ -+#ifdef EAP_SERVER_TNC -+static void eap_peap_process_phase2_soh(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ struct wpabuf *in_data) -+{ -+ const u8 *pos, *vpos; -+ size_t left; -+ const u8 *soh_tlv = NULL; -+ size_t soh_tlv_len = 0; -+ int tlv_type, mandatory, tlv_len, vtlv_len; -+ u8 next_type; -+ u32 vendor_id; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left); -+ if (pos == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP " -+ "Extensions Method header - skip TNC"); -+ goto auth_method; -+ } -+ -+ /* Parse TLVs */ -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left); -+ while (left >= 4) { -+ mandatory = !!(pos[0] & 0x80); -+ tlv_type = pos[0] & 0x3f; -+ tlv_type = (tlv_type << 8) | pos[1]; -+ tlv_len = ((int) pos[2] << 8) | pos[3]; -+ pos += 4; -+ left -= 4; -+ if ((size_t) tlv_len > left) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " -+ "(tlv_len=%d left=%lu)", tlv_len, -+ (unsigned long) left); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ switch (tlv_type) { -+ case EAP_TLV_VENDOR_SPECIFIC_TLV: -+ if (tlv_len < 4) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short " -+ "vendor specific TLV (len=%d)", -+ (int) tlv_len); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ vendor_id = WPA_GET_BE32(pos); -+ if (vendor_id != EAP_VENDOR_MICROSOFT) { -+ if (mandatory) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ break; -+ } -+ -+ vpos = pos + 4; -+ mandatory = !!(vpos[0] & 0x80); -+ tlv_type = vpos[0] & 0x3f; -+ tlv_type = (tlv_type << 8) | vpos[1]; -+ vtlv_len = ((int) vpos[2] << 8) | vpos[3]; -+ vpos += 4; -+ if (vpos + vtlv_len > pos + left) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV " -+ "underrun"); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ if (tlv_type == 1) { -+ soh_tlv = vpos; -+ soh_tlv_len = vtlv_len; -+ break; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV " -+ "Type %d%s", tlv_type, -+ mandatory ? " (mandatory)" : ""); -+ if (mandatory) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ /* Ignore this TLV, but process other TLVs */ -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " -+ "%d%s", tlv_type, -+ mandatory ? " (mandatory)" : ""); -+ if (mandatory) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ /* Ignore this TLV, but process other TLVs */ -+ break; -+ } -+ -+ pos += tlv_len; -+ left -= tlv_len; -+ } -+ if (left) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " -+ "Request (left=%lu)", (unsigned long) left); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ /* Process supported TLVs */ -+ if (soh_tlv) { -+ int failure = 0; -+ wpabuf_free(data->soh_response); -+ data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len, -+ &failure); -+ if (failure) { -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received"); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+auth_method: -+ eap_peap_state(data, PHASE2_METHOD); -+ next_type = sm->user->methods[0].method; -+ sm->user_eap_method_index = 1; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); -+ eap_peap_phase2_init(sm, data, next_type); -+} -+#endif /* EAP_SERVER_TNC */ -+ -+ -+static void eap_peap_process_phase2_response(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ struct wpabuf *in_data) -+{ -+ u8 next_type = EAP_TYPE_NONE; -+ const struct eap_hdr *hdr; -+ const u8 *pos; -+ size_t left; -+ -+ if (data->state == PHASE2_TLV) { -+ eap_peap_process_phase2_tlv(sm, data, in_data); -+ return; -+ } -+ -+#ifdef EAP_SERVER_TNC -+ if (data->state == PHASE2_SOH) { -+ eap_peap_process_phase2_soh(sm, data, in_data); -+ return; -+ } -+#endif /* EAP_SERVER_TNC */ -+ -+ if (data->phase2_priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " -+ "initialized?!", __func__); -+ return; -+ } -+ -+ hdr = wpabuf_head(in_data); -+ pos = (const u8 *) (hdr + 1); -+ -+ if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { -+ left = wpabuf_len(in_data) - sizeof(*hdr); -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; " -+ "allowed types", pos + 1, left - 1); -+ eap_sm_process_nak(sm, pos + 1, left - 1); -+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && -+ sm->user->methods[sm->user_eap_method_index].method != -+ EAP_TYPE_NONE) { -+ next_type = sm->user->methods[ -+ sm->user_eap_method_index++].method; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", -+ next_type); -+ } else { -+ eap_peap_req_failure(sm, data); -+ next_type = EAP_TYPE_NONE; -+ } -+ eap_peap_phase2_init(sm, data, next_type); -+ return; -+ } -+ -+ if (data->phase2_method->check(sm, data->phase2_priv, in_data)) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to " -+ "ignore the packet"); -+ return; -+ } -+ -+ data->phase2_method->process(sm, data->phase2_priv, in_data); -+ -+ if (sm->method_pending == METHOD_PENDING_WAIT) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in " -+ "pending wait state - save decrypted response"); -+ wpabuf_free(data->pending_phase2_resp); -+ data->pending_phase2_resp = wpabuf_dup(in_data); -+ } -+ -+ if (!data->phase2_method->isDone(sm, data->phase2_priv)) -+ return; -+ -+ if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); -+ eap_peap_req_failure(sm, data); -+ next_type = EAP_TYPE_NONE; -+ eap_peap_phase2_init(sm, data, next_type); -+ return; -+ } -+ -+ os_free(data->phase2_key); -+ if (data->phase2_method->getKey) { -+ data->phase2_key = data->phase2_method->getKey( -+ sm, data->phase2_priv, &data->phase2_key_len); -+ if (data->phase2_key == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey " -+ "failed"); -+ eap_peap_req_failure(sm, data); -+ eap_peap_phase2_init(sm, data, EAP_TYPE_NONE); -+ return; -+ } -+ } -+ -+ switch (data->state) { -+ case PHASE1_ID2: -+ case PHASE2_ID: -+ case PHASE2_SOH: -+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 " -+ "Identity not found in the user " -+ "database", -+ sm->identity, sm->identity_len); -+ eap_peap_req_failure(sm, data); -+ next_type = EAP_TYPE_NONE; -+ break; -+ } -+ -+#ifdef EAP_SERVER_TNC -+ if (data->state != PHASE2_SOH && sm->tnc && -+ data->peap_version == 0) { -+ eap_peap_state(data, PHASE2_SOH); -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize " -+ "TNC (NAP SOH)"); -+ next_type = EAP_TYPE_NONE; -+ break; -+ } -+#endif /* EAP_SERVER_TNC */ -+ -+ eap_peap_state(data, PHASE2_METHOD); -+ next_type = sm->user->methods[0].method; -+ sm->user_eap_method_index = 1; -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); -+ break; -+ case PHASE2_METHOD: -+ eap_peap_req_success(sm, data); -+ next_type = EAP_TYPE_NONE; -+ break; -+ case FAILURE: -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", -+ __func__, data->state); -+ break; -+ } -+ -+ eap_peap_phase2_init(sm, data, next_type); -+} -+ -+ -+static void eap_peap_process_phase2(struct eap_sm *sm, -+ struct eap_peap_data *data, -+ const struct wpabuf *respData, -+ struct wpabuf *in_buf) -+{ -+ struct wpabuf *in_decrypted; -+ const struct eap_hdr *hdr; -+ size_t len; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" -+ " Phase 2", (unsigned long) wpabuf_len(in_buf)); -+ -+ if (data->pending_phase2_resp) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " -+ "skip decryption and use old data"); -+ eap_peap_process_phase2_response(sm, data, -+ data->pending_phase2_resp); -+ wpabuf_free(data->pending_phase2_resp); -+ data->pending_phase2_resp = NULL; -+ return; -+ } -+ -+ in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, -+ in_buf); -+ if (in_decrypted == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " -+ "data"); -+ eap_peap_state(data, FAILURE); -+ return; -+ } -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", -+ in_decrypted); -+ -+ hdr = wpabuf_head(in_decrypted); -+ -+ if (data->peap_version == 0 && data->state != PHASE2_TLV) { -+ const struct eap_hdr *resp; -+ struct eap_hdr *nhdr; -+ struct wpabuf *nbuf = -+ wpabuf_alloc(sizeof(struct eap_hdr) + -+ wpabuf_len(in_decrypted)); -+ if (nbuf == NULL) { -+ wpabuf_free(in_decrypted); -+ return; -+ } -+ -+ resp = wpabuf_head(respData); -+ nhdr = wpabuf_put(nbuf, sizeof(*nhdr)); -+ nhdr->code = resp->code; -+ nhdr->identifier = resp->identifier; -+ nhdr->length = host_to_be16(sizeof(struct eap_hdr) + -+ wpabuf_len(in_decrypted)); -+ wpabuf_put_buf(nbuf, in_decrypted); -+ wpabuf_free(in_decrypted); -+ -+ in_decrypted = nbuf; -+ } else if (data->peap_version >= 2) { -+ struct eap_tlv_hdr *tlv; -+ struct wpabuf *nmsg; -+ -+ if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " -+ "EAP TLV"); -+ wpabuf_free(in_decrypted); -+ return; -+ } -+ tlv = wpabuf_mhead(in_decrypted); -+ if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) != -+ EAP_TLV_EAP_PAYLOAD_TLV) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); -+ wpabuf_free(in_decrypted); -+ return; -+ } -+ if (sizeof(*tlv) + be_to_host16(tlv->length) > -+ wpabuf_len(in_decrypted)) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " -+ "length"); -+ wpabuf_free(in_decrypted); -+ return; -+ } -+ hdr = (struct eap_hdr *) (tlv + 1); -+ if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " -+ "EAP packet in EAP TLV"); -+ wpabuf_free(in_decrypted); -+ return; -+ } -+ -+ nmsg = wpabuf_alloc(be_to_host16(hdr->length)); -+ if (nmsg == NULL) { -+ wpabuf_free(in_decrypted); -+ return; -+ } -+ -+ wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); -+ wpabuf_free(in_decrypted); -+ in_decrypted = nmsg; -+ } -+ -+ hdr = wpabuf_head(in_decrypted); -+ if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " -+ "EAP frame (len=%lu)", -+ (unsigned long) wpabuf_len(in_decrypted)); -+ wpabuf_free(in_decrypted); -+ eap_peap_req_failure(sm, data); -+ return; -+ } -+ len = be_to_host16(hdr->length); -+ if (len > wpabuf_len(in_decrypted)) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " -+ "Phase 2 EAP frame (len=%lu hdr->length=%lu)", -+ (unsigned long) wpabuf_len(in_decrypted), -+ (unsigned long) len); -+ wpabuf_free(in_decrypted); -+ eap_peap_req_failure(sm, data); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " -+ "identifier=%d length=%lu", hdr->code, hdr->identifier, -+ (unsigned long) len); -+ switch (hdr->code) { -+ case EAP_CODE_RESPONSE: -+ eap_peap_process_phase2_response(sm, data, in_decrypted); -+ break; -+ case EAP_CODE_SUCCESS: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); -+ if (data->state == SUCCESS_REQ) { -+ eap_peap_state(data, SUCCESS); -+ } -+ break; -+ case EAP_CODE_FAILURE: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); -+ eap_peap_state(data, FAILURE); -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " -+ "Phase 2 EAP header", hdr->code); -+ break; -+ } -+ -+ wpabuf_free(in_decrypted); -+} -+ -+ -+static int eap_peapv2_start_phase2(struct eap_sm *sm, -+ struct eap_peap_data *data) -+{ -+ struct wpabuf *buf, *buf2; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " -+ "payload in the same message"); -+ eap_peap_state(data, PHASE1_ID2); -+ if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY)) -+ return -1; -+ -+ /* TODO: which Id to use here? */ -+ buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6); -+ if (buf == NULL) -+ return -1; -+ -+ buf2 = eap_peapv2_tlv_eap_payload(buf); -+ if (buf2 == NULL) -+ return -1; -+ -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); -+ -+ buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, -+ buf2); -+ wpabuf_free(buf2); -+ -+ if (buf == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " -+ "data"); -+ return -1; -+ } -+ -+ wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", -+ buf); -+ -+ /* Append TLS data into the pending buffer after the Server Finished */ -+ if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) { -+ wpabuf_free(buf); -+ return -1; -+ } -+ wpabuf_put_buf(data->ssl.tls_out, buf); -+ wpabuf_free(buf); -+ -+ return 0; -+} -+ -+ -+static int eap_peap_process_version(struct eap_sm *sm, void *priv, -+ int peer_version) -+{ -+ struct eap_peap_data *data = priv; -+ -+ data->recv_version = peer_version; -+ if (data->force_version >= 0 && peer_version != data->force_version) { -+ wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced" -+ " version (forced=%d peer=%d) - reject", -+ data->force_version, peer_version); -+ return -1; -+ } -+ if (peer_version < data->peap_version) { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; " -+ "use version %d", -+ peer_version, data->peap_version, peer_version); -+ data->peap_version = peer_version; -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_peap_process_msg(struct eap_sm *sm, void *priv, -+ const struct wpabuf *respData) -+{ -+ struct eap_peap_data *data = priv; -+ -+ switch (data->state) { -+ case PHASE1: -+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) { -+ eap_peap_state(data, FAILURE); -+ break; -+ } -+ -+ if (data->peap_version >= 2 && -+ tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { -+ if (eap_peapv2_start_phase2(sm, data)) { -+ eap_peap_state(data, FAILURE); -+ break; -+ } -+ } -+ break; -+ case PHASE2_START: -+ eap_peap_state(data, PHASE2_ID); -+ eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY); -+ break; -+ case PHASE1_ID2: -+ case PHASE2_ID: -+ case PHASE2_METHOD: -+ case PHASE2_SOH: -+ case PHASE2_TLV: -+ eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in); -+ break; -+ case SUCCESS_REQ: -+ eap_peap_state(data, SUCCESS); -+ break; -+ case FAILURE_REQ: -+ eap_peap_state(data, FAILURE); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s", -+ data->state, __func__); -+ break; -+ } -+} -+ -+ -+static void eap_peap_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_peap_data *data = priv; -+ if (eap_server_tls_process(sm, &data->ssl, respData, data, -+ EAP_TYPE_PEAP, eap_peap_process_version, -+ eap_peap_process_msg) < 0) -+ eap_peap_state(data, FAILURE); -+} -+ -+ -+static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_peap_data *data = priv; -+ u8 *eapKeyData; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ if (data->crypto_binding_used) { -+ u8 csk[128]; -+ /* -+ * Note: It looks like Microsoft implementation requires null -+ * termination for this label while the one used for deriving -+ * IPMK|CMK did not use null termination. -+ */ -+ peap_prfplus(data->peap_version, data->ipmk, 40, -+ "Session Key Generating Function", -+ (u8 *) "\00", 1, csk, sizeof(csk)); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); -+ eapKeyData = os_malloc(EAP_TLS_KEY_LEN); -+ if (eapKeyData) { -+ os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN); -+ *len = EAP_TLS_KEY_LEN; -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", -+ eapKeyData, EAP_TLS_KEY_LEN); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive " -+ "key"); -+ } -+ -+ return eapKeyData; -+ } -+ -+ /* TODO: PEAPv1 - different label in some cases */ -+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, -+ "client EAP encryption", -+ EAP_TLS_KEY_LEN); -+ if (eapKeyData) { -+ *len = EAP_TLS_KEY_LEN; -+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", -+ eapKeyData, EAP_TLS_KEY_LEN); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key"); -+ } -+ -+ return eapKeyData; -+} -+ -+ -+static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_peap_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_peap_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_peap_init; -+ eap->reset = eap_peap_reset; -+ eap->buildReq = eap_peap_buildReq; -+ eap->check = eap_peap_check; -+ eap->process = eap_peap_process; -+ eap->isDone = eap_peap_isDone; -+ eap->getKey = eap_peap_getKey; -+ eap->isSuccess = eap_peap_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_psk.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_psk.c -new file mode 100644 -index 0000000000000..efc7a825c16aa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_psk.c -@@ -0,0 +1,518 @@ -+/* -+ * hostapd / EAP-PSK (RFC 4764) server -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * Note: EAP-PSK is an EAP authentication method and as such, completely -+ * different from WPA-PSK. This file is not needed for WPA-PSK functionality. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/random.h" -+#include "eap_common/eap_psk_common.h" -+#include "eap_server/eap_i.h" -+ -+ -+struct eap_psk_data { -+ enum { PSK_1, PSK_3, SUCCESS, FAILURE } state; -+ u8 rand_s[EAP_PSK_RAND_LEN]; -+ u8 rand_p[EAP_PSK_RAND_LEN]; -+ u8 *id_p, *id_s; -+ size_t id_p_len, id_s_len; -+ u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+}; -+ -+ -+static void * eap_psk_init(struct eap_sm *sm) -+{ -+ struct eap_psk_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = PSK_1; -+ data->id_s = (u8 *) "hostapd"; -+ data->id_s_len = 7; -+ -+ return data; -+} -+ -+ -+static void eap_psk_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_psk_data *data = priv; -+ os_free(data->id_p); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_psk_build_1(struct eap_sm *sm, -+ struct eap_psk_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ struct eap_psk_hdr_1 *psk; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-1 (sending)"); -+ -+ if (random_get_bytes(data->rand_s, EAP_PSK_RAND_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_S (server rand)", -+ data->rand_s, EAP_PSK_RAND_LEN); -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, -+ sizeof(*psk) + data->id_s_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory " -+ "request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ psk = wpabuf_put(req, sizeof(*psk)); -+ psk->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */ -+ os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN); -+ wpabuf_put_data(req, data->id_s, data->id_s_len); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_psk_build_3(struct eap_sm *sm, -+ struct eap_psk_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ struct eap_psk_hdr_3 *psk; -+ u8 *buf, *pchannel, nonce[16]; -+ size_t buflen; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)"); -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, -+ sizeof(*psk) + 4 + 16 + 1, EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory " -+ "request"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ psk = wpabuf_put(req, sizeof(*psk)); -+ psk->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */ -+ os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN); -+ -+ /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ -+ buflen = data->id_s_len + EAP_PSK_RAND_LEN; -+ buf = os_malloc(buflen); -+ if (buf == NULL) -+ goto fail; -+ -+ os_memcpy(buf, data->id_s, data->id_s_len); -+ os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); -+ if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) -+ goto fail; -+ os_free(buf); -+ -+ if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk, -+ data->emsk)) -+ goto fail; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); -+ -+ os_memset(nonce, 0, sizeof(nonce)); -+ pchannel = wpabuf_put(req, 4 + 16 + 1); -+ os_memcpy(pchannel, nonce + 12, 4); -+ os_memset(pchannel + 4, 0, 16); /* Tag */ -+ pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)", -+ pchannel, 4 + 16 + 1); -+ if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), -+ wpabuf_head(req), 22, -+ pchannel + 4 + 16, 1, pchannel + 4)) -+ goto fail; -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)", -+ pchannel, 4 + 16 + 1); -+ -+ return req; -+ -+fail: -+ wpabuf_free(req); -+ data->state = FAILURE; -+ return NULL; -+} -+ -+ -+static struct wpabuf * eap_psk_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_psk_data *data = priv; -+ -+ switch (data->state) { -+ case PSK_1: -+ return eap_psk_build_1(sm, data, id); -+ case PSK_3: -+ return eap_psk_build_3(sm, data, id); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Unknown state %d in buildReq", -+ data->state); -+ break; -+ } -+ return NULL; -+} -+ -+ -+static Boolean eap_psk_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_psk_data *data = priv; -+ size_t len; -+ u8 t; -+ const u8 *pos; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); -+ return TRUE; -+ } -+ t = EAP_PSK_FLAGS_GET_T(*pos); -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t); -+ -+ if (data->state == PSK_1 && t != 1) { -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-2 - " -+ "ignore T=%d", t); -+ return TRUE; -+ } -+ -+ if (data->state == PSK_3 && t != 3) { -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Expected PSK-4 - " -+ "ignore T=%d", t); -+ return TRUE; -+ } -+ -+ if ((t == 1 && len < sizeof(struct eap_psk_hdr_2)) || -+ (t == 3 && len < sizeof(struct eap_psk_hdr_4))) { -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Too short frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_psk_process_2(struct eap_sm *sm, -+ struct eap_psk_data *data, -+ struct wpabuf *respData) -+{ -+ const struct eap_psk_hdr_2 *resp; -+ u8 *pos, mac[EAP_PSK_MAC_LEN], *buf; -+ size_t left, buflen; -+ int i; -+ const u8 *cpos; -+ -+ if (data->state != PSK_1) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2"); -+ -+ cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, -+ &left); -+ if (cpos == NULL || left < sizeof(*resp)) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); -+ return; -+ } -+ resp = (const struct eap_psk_hdr_2 *) cpos; -+ cpos = (const u8 *) (resp + 1); -+ left -= sizeof(*resp); -+ -+ os_free(data->id_p); -+ data->id_p = os_malloc(left); -+ if (data->id_p == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for " -+ "ID_P"); -+ return; -+ } -+ os_memcpy(data->id_p, cpos, left); -+ data->id_p_len = left; -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P", -+ data->id_p, data->id_p_len); -+ -+ if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P", -+ data->id_p, data->id_p_len); -+ data->state = FAILURE; -+ return; -+ } -+ -+ for (i = 0; -+ i < EAP_MAX_METHODS && -+ (sm->user->methods[i].vendor != EAP_VENDOR_IETF || -+ sm->user->methods[i].method != EAP_TYPE_NONE); -+ i++) { -+ if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && -+ sm->user->methods[i].method == EAP_TYPE_PSK) -+ break; -+ } -+ -+ if (i >= EAP_MAX_METHODS || -+ sm->user->methods[i].vendor != EAP_VENDOR_IETF || -+ sm->user->methods[i].method != EAP_TYPE_PSK) { -+ wpa_hexdump_ascii(MSG_DEBUG, -+ "EAP-PSK: EAP-PSK not enabled for ID_P", -+ data->id_p, data->id_p_len); -+ data->state = FAILURE; -+ return; -+ } -+ -+ if (sm->user->password == NULL || -+ sm->user->password_len != EAP_PSK_PSK_LEN) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in " -+ "user database for ID_P", -+ data->id_p, data->id_p_len); -+ data->state = FAILURE; -+ return; -+ } -+ if (eap_psk_key_setup(sm->user->password, data->ak, data->kdk)) { -+ data->state = FAILURE; -+ return; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); -+ -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)", -+ resp->rand_p, EAP_PSK_RAND_LEN); -+ os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN); -+ -+ /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ -+ buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; -+ buf = os_malloc(buflen); -+ if (buf == NULL) { -+ data->state = FAILURE; -+ return; -+ } -+ os_memcpy(buf, data->id_p, data->id_p_len); -+ pos = buf + data->id_p_len; -+ os_memcpy(pos, data->id_s, data->id_s_len); -+ pos += data->id_s_len; -+ os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN); -+ pos += EAP_PSK_RAND_LEN; -+ os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); -+ if (omac1_aes_128(data->ak, buf, buflen, mac)) { -+ os_free(buf); -+ data->state = FAILURE; -+ return; -+ } -+ os_free(buf); -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN); -+ if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P", -+ mac, EAP_PSK_MAC_LEN); -+ data->state = FAILURE; -+ return; -+ } -+ -+ data->state = PSK_3; -+} -+ -+ -+static void eap_psk_process_4(struct eap_sm *sm, -+ struct eap_psk_data *data, -+ struct wpabuf *respData) -+{ -+ const struct eap_psk_hdr_4 *resp; -+ u8 *decrypted, nonce[16]; -+ size_t left; -+ const u8 *pos, *tag; -+ -+ if (data->state != PSK_3) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-4"); -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &left); -+ if (pos == NULL || left < sizeof(*resp)) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); -+ return; -+ } -+ resp = (const struct eap_psk_hdr_4 *) pos; -+ pos = (const u8 *) (resp + 1); -+ left -= sizeof(*resp); -+ -+ wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Encrypted PCHANNEL", pos, left); -+ -+ if (left < 4 + 16 + 1) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " -+ "PSK-4 (len=%lu, expected 21)", -+ (unsigned long) left); -+ return; -+ } -+ -+ if (pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-PSK: Nonce did not increase"); -+ return; -+ } -+ -+ os_memset(nonce, 0, 12); -+ os_memcpy(nonce + 12, pos, 4); -+ pos += 4; -+ left -= 4; -+ tag = pos; -+ pos += 16; -+ left -= 16; -+ -+ decrypted = os_malloc(left); -+ if (decrypted == NULL) -+ return; -+ os_memcpy(decrypted, pos, left); -+ -+ if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), -+ wpabuf_head(respData), 22, decrypted, left, -+ tag)) { -+ wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); -+ os_free(decrypted); -+ data->state = FAILURE; -+ return; -+ } -+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", -+ decrypted, left); -+ -+ /* Verify R flag */ -+ switch (decrypted[0] >> 6) { -+ case EAP_PSK_R_FLAG_CONT: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); -+ data->state = FAILURE; -+ break; -+ case EAP_PSK_R_FLAG_DONE_SUCCESS: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); -+ data->state = SUCCESS; -+ break; -+ case EAP_PSK_R_FLAG_DONE_FAILURE: -+ wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); -+ data->state = FAILURE; -+ break; -+ } -+ os_free(decrypted); -+} -+ -+ -+static void eap_psk_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_psk_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ if (sm->user == NULL || sm->user->password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not " -+ "configured"); -+ data->state = FAILURE; -+ return; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &len); -+ if (pos == NULL || len < 1) -+ return; -+ -+ switch (EAP_PSK_FLAGS_GET_T(*pos)) { -+ case 1: -+ eap_psk_process_2(sm, data, respData); -+ break; -+ case 3: -+ eap_psk_process_4(sm, data, respData); -+ break; -+ } -+} -+ -+ -+static Boolean eap_psk_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_psk_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_psk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ -+ return key; -+} -+ -+ -+static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_psk_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ -+ return key; -+} -+ -+ -+static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_psk_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_psk_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_psk_init; -+ eap->reset = eap_psk_reset; -+ eap->buildReq = eap_psk_buildReq; -+ eap->check = eap_psk_check; -+ eap->process = eap_psk_process; -+ eap->isDone = eap_psk_isDone; -+ eap->getKey = eap_psk_getKey; -+ eap->isSuccess = eap_psk_isSuccess; -+ eap->get_emsk = eap_psk_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pwd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pwd.c -new file mode 100644 -index 0000000000000..dd2557a83e235 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_pwd.c -@@ -0,0 +1,844 @@ -+/* -+ * hostapd / EAP-pwd (RFC 5931) server -+ * Copyright (c) 2010, Dan Harkins -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the BSD license. -+ * -+ * Alternatively, this software may be distributed under the terms of the -+ * GNU General Public License version 2 as published by the Free Software -+ * Foundation. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_server/eap_i.h" -+#include "eap_common/eap_pwd_common.h" -+ -+ -+struct eap_pwd_data { -+ enum { -+ PWD_ID_Req, PWD_Commit_Req, PWD_Confirm_Req, SUCCESS, FAILURE -+ } state; -+ u8 *id_peer; -+ size_t id_peer_len; -+ u8 *id_server; -+ size_t id_server_len; -+ u8 *password; -+ size_t password_len; -+ u32 token; -+ u16 group_num; -+ EAP_PWD_group *grp; -+ -+ BIGNUM *k; -+ BIGNUM *private_value; -+ BIGNUM *peer_scalar; -+ BIGNUM *my_scalar; -+ EC_POINT *my_element; -+ EC_POINT *peer_element; -+ -+ u8 my_confirm[SHA256_DIGEST_LENGTH]; -+ -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ -+ BN_CTX *bnctx; -+}; -+ -+ -+static const char * eap_pwd_state_txt(int state) -+{ -+ switch (state) { -+ case PWD_ID_Req: -+ return "PWD-ID-Req"; -+ case PWD_Commit_Req: -+ return "PWD-Commit-Req"; -+ case PWD_Confirm_Req: -+ return "PWD-Confirm-Req"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "PWD-Unk"; -+ } -+} -+ -+ -+static void eap_pwd_state(struct eap_pwd_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-pwd: %s -> %s", -+ eap_pwd_state_txt(data->state), eap_pwd_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_pwd_init(struct eap_sm *sm) -+{ -+ struct eap_pwd_data *data; -+ -+ if (sm->user == NULL || sm->user->password == NULL || -+ sm->user->password_len == 0) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): Password is not " -+ "configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ data->group_num = sm->pwd_group; -+ wpa_printf(MSG_DEBUG, "EAP-pwd: Selected group number %d", -+ data->group_num); -+ data->state = PWD_ID_Req; -+ -+ data->id_server = (u8 *) os_strdup("server"); -+ if (data->id_server) -+ data->id_server_len = os_strlen((char *) data->id_server); -+ -+ data->password = os_malloc(sm->user->password_len); -+ if (data->password == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password " -+ "fail"); -+ os_free(data->id_server); -+ os_free(data); -+ return NULL; -+ } -+ data->password_len = sm->user->password_len; -+ os_memcpy(data->password, sm->user->password, data->password_len); -+ -+ data->bnctx = BN_CTX_new(); -+ if (data->bnctx == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); -+ os_free(data->password); -+ os_free(data->id_server); -+ os_free(data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_pwd_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pwd_data *data = priv; -+ -+ BN_free(data->private_value); -+ BN_free(data->peer_scalar); -+ BN_free(data->my_scalar); -+ BN_free(data->k); -+ BN_CTX_free(data->bnctx); -+ EC_POINT_free(data->my_element); -+ EC_POINT_free(data->peer_element); -+ os_free(data->id_peer); -+ os_free(data->id_server); -+ os_free(data->password); -+ if (data->grp) { -+ EC_GROUP_free(data->grp->group); -+ EC_POINT_free(data->grp->pwe); -+ BN_free(data->grp->order); -+ BN_free(data->grp->prime); -+ os_free(data->grp); -+ } -+ os_free(data); -+} -+ -+ -+static struct wpabuf * -+eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ -+ wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request"); -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, -+ sizeof(struct eap_pwd_hdr) + -+ sizeof(struct eap_pwd_id) + data->id_server_len, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ eap_pwd_state(data, FAILURE); -+ return NULL; -+ } -+ -+ /* an lfsr is good enough to generate unpredictable tokens */ -+ data->token = os_random(); -+ wpabuf_put_u8(req, EAP_PWD_OPCODE_ID_EXCH); -+ wpabuf_put_be16(req, data->group_num); -+ wpabuf_put_u8(req, EAP_PWD_DEFAULT_RAND_FUNC); -+ wpabuf_put_u8(req, EAP_PWD_DEFAULT_PRF); -+ wpabuf_put_data(req, &data->token, sizeof(data->token)); -+ wpabuf_put_u8(req, EAP_PWD_PREP_NONE); -+ wpabuf_put_data(req, data->id_server, data->id_server_len); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * -+eap_pwd_build_commit_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) -+{ -+ struct wpabuf *req = NULL; -+ BIGNUM *mask = NULL, *x = NULL, *y = NULL; -+ u8 *scalar = NULL, *element = NULL; -+ u16 offset; -+ -+ wpa_printf(MSG_DEBUG, "EAP-pwd: Commit/Request"); -+ -+ if (((data->private_value = BN_new()) == NULL) || -+ ((data->my_element = EC_POINT_new(data->grp->group)) == NULL) || -+ ((data->my_scalar = BN_new()) == NULL) || -+ ((mask = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): scalar allocation " -+ "fail"); -+ goto fin; -+ } -+ -+ BN_rand_range(data->private_value, data->grp->order); -+ BN_rand_range(mask, data->grp->order); -+ BN_add(data->my_scalar, data->private_value, mask); -+ BN_mod(data->my_scalar, data->my_scalar, data->grp->order, -+ data->bnctx); -+ -+ if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, -+ data->grp->pwe, mask, data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): element allocation " -+ "fail"); -+ eap_pwd_state(data, FAILURE); -+ goto fin; -+ } -+ -+ if (!EC_POINT_invert(data->grp->group, data->my_element, data->bnctx)) -+ { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): element inversion " -+ "fail"); -+ goto fin; -+ } -+ BN_free(mask); -+ -+ if (((x = BN_new()) == NULL) || -+ ((y = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): point allocation " -+ "fail"); -+ goto fin; -+ } -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->my_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment " -+ "fail"); -+ goto fin; -+ } -+ -+ if (((scalar = os_malloc(BN_num_bytes(data->grp->order))) == NULL) || -+ ((element = os_malloc(BN_num_bytes(data->grp->prime) * 2)) == -+ NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): data allocation fail"); -+ goto fin; -+ } -+ -+ /* -+ * bignums occupy as little memory as possible so one that is -+ * sufficiently smaller than the prime or order might need pre-pending -+ * with zeros. -+ */ -+ os_memset(scalar, 0, BN_num_bytes(data->grp->order)); -+ os_memset(element, 0, BN_num_bytes(data->grp->prime) * 2); -+ offset = BN_num_bytes(data->grp->order) - -+ BN_num_bytes(data->my_scalar); -+ BN_bn2bin(data->my_scalar, scalar + offset); -+ -+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x); -+ BN_bn2bin(x, element + offset); -+ offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y); -+ BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset); -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, -+ sizeof(struct eap_pwd_hdr) + -+ (2 * BN_num_bytes(data->grp->prime)) + -+ BN_num_bytes(data->grp->order), -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) -+ goto fin; -+ wpabuf_put_u8(req, EAP_PWD_OPCODE_COMMIT_EXCH); -+ -+ /* We send the element as (x,y) followed by the scalar */ -+ wpabuf_put_data(req, element, (2 * BN_num_bytes(data->grp->prime))); -+ wpabuf_put_data(req, scalar, BN_num_bytes(data->grp->order)); -+ -+fin: -+ os_free(scalar); -+ os_free(element); -+ BN_free(x); -+ BN_free(y); -+ if (req == NULL) -+ eap_pwd_state(data, FAILURE); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * -+eap_pwd_build_confirm_req(struct eap_sm *sm, struct eap_pwd_data *data, u8 id) -+{ -+ struct wpabuf *req = NULL; -+ BIGNUM *x = NULL, *y = NULL; -+ HMAC_CTX ctx; -+ u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr; -+ u16 grp; -+ -+ wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request"); -+ -+ /* Each component of the cruft will be at most as big as the prime */ -+ if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || -+ ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): debug allocation " -+ "fail"); -+ goto fin; -+ } -+ -+ /* -+ * commit is H(k | server_element | server_scalar | peer_element | -+ * peer_scalar | ciphersuite) -+ */ -+ H_Init(&ctx); -+ -+ /* -+ * Zero the memory each time because this is mod prime math and some -+ * value may start with a few zeros and the previous one did not. -+ * -+ * First is k -+ */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->k, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* server element: x, y */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->my_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* server scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->my_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* peer element: x, y */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->peer_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* peer scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->peer_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* ciphersuite */ -+ grp = htons(data->group_num); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ ptr = cruft; -+ os_memcpy(ptr, &grp, sizeof(u16)); -+ ptr += sizeof(u16); -+ *ptr = EAP_PWD_DEFAULT_RAND_FUNC; -+ ptr += sizeof(u8); -+ *ptr = EAP_PWD_DEFAULT_PRF; -+ ptr += sizeof(u8); -+ H_Update(&ctx, cruft, ptr-cruft); -+ -+ /* all done with the random function */ -+ H_Final(&ctx, conf); -+ os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH); -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD, -+ sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) -+ goto fin; -+ -+ wpabuf_put_u8(req, EAP_PWD_OPCODE_CONFIRM_EXCH); -+ wpabuf_put_data(req, conf, SHA256_DIGEST_LENGTH); -+ -+fin: -+ os_free(cruft); -+ BN_free(x); -+ BN_free(y); -+ if (req == NULL) -+ eap_pwd_state(data, FAILURE); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * -+eap_pwd_build_req(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_pwd_data *data = priv; -+ -+ switch (data->state) { -+ case PWD_ID_Req: -+ return eap_pwd_build_id_req(sm, data, id); -+ case PWD_Commit_Req: -+ return eap_pwd_build_commit_req(sm, data, id); -+ case PWD_Confirm_Req: -+ return eap_pwd_build_confirm_req(sm, data, id); -+ default: -+ wpa_printf(MSG_INFO, "EAP-pwd: Unknown state %d in build_req", -+ data->state); -+ break; -+ } -+ -+ return NULL; -+} -+ -+ -+static Boolean eap_pwd_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_pwd_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-pwd: Invalid frame"); -+ return TRUE; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-pwd: Received frame: opcode=%d", *pos); -+ -+ if (data->state == PWD_ID_Req && *pos == EAP_PWD_OPCODE_ID_EXCH) -+ return FALSE; -+ -+ if (data->state == PWD_Commit_Req && -+ *pos == EAP_PWD_OPCODE_COMMIT_EXCH) -+ return FALSE; -+ -+ if (data->state == PWD_Confirm_Req && -+ *pos == EAP_PWD_OPCODE_CONFIRM_EXCH) -+ return FALSE; -+ -+ wpa_printf(MSG_INFO, "EAP-pwd: Unexpected opcode=%d in state=%d", -+ *pos, data->state); -+ -+ return TRUE; -+} -+ -+ -+static void eap_pwd_process_id_resp(struct eap_sm *sm, -+ struct eap_pwd_data *data, -+ const u8 *payload, size_t payload_len) -+{ -+ struct eap_pwd_id *id; -+ -+ if (payload_len < sizeof(struct eap_pwd_id)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response"); -+ return; -+ } -+ -+ id = (struct eap_pwd_id *) payload; -+ if ((data->group_num != be_to_host16(id->group_num)) || -+ (id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || -+ (os_memcmp(id->token, (u8 *)&data->token, sizeof(data->token))) || -+ (id->prf != EAP_PWD_DEFAULT_PRF)) { -+ wpa_printf(MSG_INFO, "EAP-pwd: peer changed parameters"); -+ eap_pwd_state(data, FAILURE); -+ return; -+ } -+ data->id_peer = os_malloc(payload_len - sizeof(struct eap_pwd_id)); -+ if (data->id_peer == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: memory allocation id fail"); -+ return; -+ } -+ data->id_peer_len = payload_len - sizeof(struct eap_pwd_id); -+ os_memcpy(data->id_peer, id->identity, data->id_peer_len); -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-PWD (server): peer sent id of", -+ data->id_peer, data->id_peer_len); -+ -+ if ((data->grp = os_malloc(sizeof(EAP_PWD_group))) == NULL) { -+ wpa_printf(MSG_INFO, "EAP-PWD: failed to allocate memory for " -+ "group"); -+ return; -+ } -+ if (compute_password_element(data->grp, data->group_num, -+ data->password, data->password_len, -+ data->id_server, data->id_server_len, -+ data->id_peer, data->id_peer_len, -+ (u8 *) &data->token)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute " -+ "PWE"); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-PWD (server): computed %d bit PWE...", -+ BN_num_bits(data->grp->prime)); -+ -+ eap_pwd_state(data, PWD_Commit_Req); -+} -+ -+ -+static void -+eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, -+ const u8 *payload, size_t payload_len) -+{ -+ u8 *ptr; -+ BIGNUM *x = NULL, *y = NULL, *cofactor = NULL; -+ EC_POINT *K = NULL, *point = NULL; -+ int res = 0; -+ -+ wpa_printf(MSG_DEBUG, "EAP-pwd: Received commit response"); -+ -+ if (((data->peer_scalar = BN_new()) == NULL) || -+ ((data->k = BN_new()) == NULL) || -+ ((cofactor = BN_new()) == NULL) || -+ ((x = BN_new()) == NULL) || -+ ((y = BN_new()) == NULL) || -+ ((point = EC_POINT_new(data->grp->group)) == NULL) || -+ ((K = EC_POINT_new(data->grp->group)) == NULL) || -+ ((data->peer_element = EC_POINT_new(data->grp->group)) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer data allocation " -+ "fail"); -+ goto fin; -+ } -+ -+ if (!EC_GROUP_get_cofactor(data->grp->group, cofactor, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): unable to get " -+ "cofactor for curve"); -+ goto fin; -+ } -+ -+ /* element, x then y, followed by scalar */ -+ ptr = (u8 *) payload; -+ BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), x); -+ ptr += BN_num_bytes(data->grp->prime); -+ BN_bin2bn(ptr, BN_num_bytes(data->grp->prime), y); -+ ptr += BN_num_bytes(data->grp->prime); -+ BN_bin2bn(ptr, BN_num_bytes(data->grp->order), data->peer_scalar); -+ if (!EC_POINT_set_affine_coordinates_GFp(data->grp->group, -+ data->peer_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): setting peer element " -+ "fail"); -+ goto fin; -+ } -+ -+ /* check to ensure peer's element is not in a small sub-group */ -+ if (BN_cmp(cofactor, BN_value_one())) { -+ if (!EC_POINT_mul(data->grp->group, point, NULL, -+ data->peer_element, cofactor, NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " -+ "multiply peer element by order"); -+ goto fin; -+ } -+ if (EC_POINT_is_at_infinity(data->grp->group, point)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): peer element " -+ "is at infinity!\n"); -+ goto fin; -+ } -+ } -+ -+ /* compute the shared key, k */ -+ if ((!EC_POINT_mul(data->grp->group, K, NULL, data->grp->pwe, -+ data->peer_scalar, data->bnctx)) || -+ (!EC_POINT_add(data->grp->group, K, K, data->peer_element, -+ data->bnctx)) || -+ (!EC_POINT_mul(data->grp->group, K, NULL, K, data->private_value, -+ data->bnctx))) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): computing shared key " -+ "fail"); -+ goto fin; -+ } -+ -+ /* ensure that the shared key isn't in a small sub-group */ -+ if (BN_cmp(cofactor, BN_value_one())) { -+ if (!EC_POINT_mul(data->grp->group, K, NULL, K, cofactor, -+ NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): cannot " -+ "multiply shared key point by order!\n"); -+ goto fin; -+ } -+ } -+ -+ /* -+ * This check is strictly speaking just for the case above where -+ * co-factor > 1 but it was suggested that even though this is probably -+ * never going to happen it is a simple and safe check "just to be -+ * sure" so let's be safe. -+ */ -+ if (EC_POINT_is_at_infinity(data->grp->group, K)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): shared key point is " -+ "at infinity"); -+ goto fin; -+ } -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, K, data->k, -+ NULL, data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): unable to extract " -+ "shared secret from secret point"); -+ goto fin; -+ } -+ res = 1; -+ -+fin: -+ EC_POINT_free(K); -+ EC_POINT_free(point); -+ BN_free(cofactor); -+ BN_free(x); -+ BN_free(y); -+ -+ if (res) -+ eap_pwd_state(data, PWD_Confirm_Req); -+ else -+ eap_pwd_state(data, FAILURE); -+} -+ -+ -+static void -+eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, -+ const u8 *payload, size_t payload_len) -+{ -+ BIGNUM *x = NULL, *y = NULL; -+ HMAC_CTX ctx; -+ u32 cs; -+ u16 grp; -+ u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr; -+ -+ /* build up the ciphersuite: group | random_function | prf */ -+ grp = htons(data->group_num); -+ ptr = (u8 *) &cs; -+ os_memcpy(ptr, &grp, sizeof(u16)); -+ ptr += sizeof(u16); -+ *ptr = EAP_PWD_DEFAULT_RAND_FUNC; -+ ptr += sizeof(u8); -+ *ptr = EAP_PWD_DEFAULT_PRF; -+ -+ /* each component of the cruft will be at most as big as the prime */ -+ if (((cruft = os_malloc(BN_num_bytes(data->grp->prime))) == NULL) || -+ ((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (peer): allocation fail"); -+ goto fin; -+ } -+ -+ /* -+ * commit is H(k | peer_element | peer_scalar | server_element | -+ * server_scalar | ciphersuite) -+ */ -+ H_Init(&ctx); -+ -+ /* k */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->k, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* peer element: x, y */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->peer_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* peer scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->peer_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* server element: x, y */ -+ if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group, -+ data->my_element, x, y, -+ data->bnctx)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm point " -+ "assignment fail"); -+ goto fin; -+ } -+ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(x, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(y, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime)); -+ -+ /* server scalar */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ BN_bn2bin(data->my_scalar, cruft); -+ H_Update(&ctx, cruft, BN_num_bytes(data->grp->order)); -+ -+ /* ciphersuite */ -+ os_memset(cruft, 0, BN_num_bytes(data->grp->prime)); -+ H_Update(&ctx, (u8 *)&cs, sizeof(u32)); -+ -+ /* all done */ -+ H_Final(&ctx, conf); -+ -+ ptr = (u8 *) payload; -+ if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) { -+ wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not " -+ "verify"); -+ goto fin; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-pwd (server): confirm verified"); -+ if (compute_keys(data->grp, data->bnctx, data->k, -+ data->peer_scalar, data->my_scalar, conf, -+ data->my_confirm, &cs, data->msk, data->emsk) < 0) -+ eap_pwd_state(data, FAILURE); -+ else -+ eap_pwd_state(data, SUCCESS); -+ -+fin: -+ os_free(cruft); -+ BN_free(x); -+ BN_free(y); -+} -+ -+ -+static void eap_pwd_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_pwd_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ u8 exch; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PWD, respData, &len); -+ if ((pos == NULL) || (len < 1)) { -+ wpa_printf(MSG_INFO, "Bad EAP header! pos %s and len = %d", -+ (pos == NULL) ? "is NULL" : "is not NULL", -+ (int) len); -+ return; -+ } -+ -+ exch = *pos & 0x3f; -+ switch (exch) { -+ case EAP_PWD_OPCODE_ID_EXCH: -+ eap_pwd_process_id_resp(sm, data, pos + 1, len - 1); -+ break; -+ case EAP_PWD_OPCODE_COMMIT_EXCH: -+ eap_pwd_process_commit_resp(sm, data, pos + 1, len - 1); -+ break; -+ case EAP_PWD_OPCODE_CONFIRM_EXCH: -+ eap_pwd_process_confirm_resp(sm, data, pos + 1, len - 1); -+ break; -+ } -+} -+ -+ -+static u8 * eap_pwd_getkey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pwd_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ -+ return key; -+} -+ -+ -+static u8 * eap_pwd_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_pwd_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ -+ return key; -+} -+ -+ -+static Boolean eap_pwd_is_success(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pwd_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static Boolean eap_pwd_is_done(struct eap_sm *sm, void *priv) -+{ -+ struct eap_pwd_data *data = priv; -+ return (data->state == SUCCESS) || (data->state == FAILURE); -+} -+ -+ -+int eap_server_pwd_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ struct timeval tp; -+ struct timezone tz; -+ u32 sr; -+ -+ EVP_add_digest(EVP_sha256()); -+ -+ sr = 0xdeaddada; -+ (void) gettimeofday(&tp, &tz); -+ sr ^= (tp.tv_sec ^ tp.tv_usec); -+ srandom(sr); -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_PWD, -+ "PWD"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_pwd_init; -+ eap->reset = eap_pwd_reset; -+ eap->buildReq = eap_pwd_build_req; -+ eap->check = eap_pwd_check; -+ eap->process = eap_pwd_process; -+ eap->isDone = eap_pwd_is_done; -+ eap->getKey = eap_pwd_getkey; -+ eap->get_emsk = eap_pwd_get_emsk; -+ eap->isSuccess = eap_pwd_is_success; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -+ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sake.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sake.c -new file mode 100644 -index 0000000000000..a9b515f99904c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sake.c -@@ -0,0 +1,543 @@ -+/* -+ * hostapd / EAP-SAKE (RFC 4763) server -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_server/eap_i.h" -+#include "eap_common/eap_sake_common.h" -+ -+ -+struct eap_sake_data { -+ enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state; -+ u8 rand_s[EAP_SAKE_RAND_LEN]; -+ u8 rand_p[EAP_SAKE_RAND_LEN]; -+ struct { -+ u8 auth[EAP_SAKE_TEK_AUTH_LEN]; -+ u8 cipher[EAP_SAKE_TEK_CIPHER_LEN]; -+ } tek; -+ u8 msk[EAP_MSK_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 session_id; -+ u8 *peerid; -+ size_t peerid_len; -+ u8 *serverid; -+ size_t serverid_len; -+}; -+ -+ -+static const char * eap_sake_state_txt(int state) -+{ -+ switch (state) { -+ case IDENTITY: -+ return "IDENTITY"; -+ case CHALLENGE: -+ return "CHALLENGE"; -+ case CONFIRM: -+ return "CONFIRM"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+static void eap_sake_state(struct eap_sake_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s", -+ eap_sake_state_txt(data->state), -+ eap_sake_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_sake_init(struct eap_sm *sm) -+{ -+ struct eap_sake_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = CHALLENGE; -+ -+ if (os_get_random(&data->session_id, 1)) { -+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); -+ os_free(data); -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d", -+ data->session_id); -+ -+ /* TODO: add support for configuring SERVERID */ -+ data->serverid = (u8 *) os_strdup("hostapd"); -+ if (data->serverid) -+ data->serverid_len = os_strlen((char *) data->serverid); -+ -+ return data; -+} -+ -+ -+static void eap_sake_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sake_data *data = priv; -+ os_free(data->serverid); -+ os_free(data->peerid); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_sake_build_msg(struct eap_sake_data *data, -+ u8 id, size_t length, u8 subtype) -+{ -+ struct eap_sake_hdr *sake; -+ struct wpabuf *msg; -+ size_t plen; -+ -+ plen = sizeof(struct eap_sake_hdr) + length; -+ -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_SAKE, plen, -+ EAP_CODE_REQUEST, id); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory " -+ "request"); -+ return NULL; -+ } -+ -+ sake = wpabuf_put(msg, sizeof(*sake)); -+ sake->version = EAP_SAKE_VERSION; -+ sake->session_id = data->session_id; -+ sake->subtype = subtype; -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_sake_build_identity(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ u8 id) -+{ -+ struct wpabuf *msg; -+ size_t plen; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity"); -+ -+ plen = 4; -+ if (data->serverid) -+ plen += 2 + data->serverid_len; -+ msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_IDENTITY); -+ if (msg == NULL) { -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ"); -+ eap_sake_add_attr(msg, EAP_SAKE_AT_PERM_ID_REQ, NULL, 2); -+ -+ if (data->serverid) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID"); -+ eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID, -+ data->serverid, data->serverid_len); -+ } -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_sake_build_challenge(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ u8 id) -+{ -+ struct wpabuf *msg; -+ size_t plen; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge"); -+ -+ if (random_get_bytes(data->rand_s, EAP_SAKE_RAND_LEN)) { -+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data"); -+ data->state = FAILURE; -+ return NULL; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)", -+ data->rand_s, EAP_SAKE_RAND_LEN); -+ -+ plen = 2 + EAP_SAKE_RAND_LEN; -+ if (data->serverid) -+ plen += 2 + data->serverid_len; -+ msg = eap_sake_build_msg(data, id, plen, EAP_SAKE_SUBTYPE_CHALLENGE); -+ if (msg == NULL) { -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S"); -+ eap_sake_add_attr(msg, EAP_SAKE_AT_RAND_S, -+ data->rand_s, EAP_SAKE_RAND_LEN); -+ -+ if (data->serverid) { -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID"); -+ eap_sake_add_attr(msg, EAP_SAKE_AT_SERVERID, -+ data->serverid, data->serverid_len); -+ } -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_sake_build_confirm(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ u8 id) -+{ -+ struct wpabuf *msg; -+ u8 *mic; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm"); -+ -+ msg = eap_sake_build_msg(data, id, 2 + EAP_SAKE_MIC_LEN, -+ EAP_SAKE_SUBTYPE_CONFIRM); -+ if (msg == NULL) { -+ data->state = FAILURE; -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S"); -+ wpabuf_put_u8(msg, EAP_SAKE_AT_MIC_S); -+ wpabuf_put_u8(msg, 2 + EAP_SAKE_MIC_LEN); -+ mic = wpabuf_put(msg, EAP_SAKE_MIC_LEN); -+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, -+ data->serverid, data->serverid_len, -+ data->peerid, data->peerid_len, 0, -+ wpabuf_head(msg), wpabuf_len(msg), mic, mic)) -+ { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC"); -+ data->state = FAILURE; -+ os_free(msg); -+ return NULL; -+ } -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_sake_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_sake_data *data = priv; -+ -+ switch (data->state) { -+ case IDENTITY: -+ return eap_sake_build_identity(sm, data, id); -+ case CHALLENGE: -+ return eap_sake_build_challenge(sm, data, id); -+ case CONFIRM: -+ return eap_sake_build_confirm(sm, data, id); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq", -+ data->state); -+ break; -+ } -+ return NULL; -+} -+ -+ -+static Boolean eap_sake_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_sake_data *data = priv; -+ struct eap_sake_hdr *resp; -+ size_t len; -+ u8 version, session_id, subtype; -+ const u8 *pos; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len); -+ if (pos == NULL || len < sizeof(struct eap_sake_hdr)) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame"); -+ return TRUE; -+ } -+ -+ resp = (struct eap_sake_hdr *) pos; -+ version = resp->version; -+ session_id = resp->session_id; -+ subtype = resp->subtype; -+ -+ if (version != EAP_SAKE_VERSION) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version); -+ return TRUE; -+ } -+ -+ if (session_id != data->session_id) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)", -+ session_id, data->session_id); -+ return TRUE; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype); -+ -+ if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY) -+ return FALSE; -+ -+ if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE) -+ return FALSE; -+ -+ if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM) -+ return FALSE; -+ -+ if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT) -+ return FALSE; -+ -+ wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d", -+ subtype, data->state); -+ -+ return TRUE; -+} -+ -+ -+static void eap_sake_process_identity(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ const struct wpabuf *respData, -+ const u8 *payload, size_t payloadlen) -+{ -+ if (data->state != IDENTITY) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity"); -+ /* TODO: update identity and select new user data */ -+ eap_sake_state(data, CHALLENGE); -+} -+ -+ -+static void eap_sake_process_challenge(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ const struct wpabuf *respData, -+ const u8 *payload, size_t payloadlen) -+{ -+ struct eap_sake_parse_attr attr; -+ u8 mic_p[EAP_SAKE_MIC_LEN]; -+ -+ if (data->state != CHALLENGE) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge"); -+ -+ if (eap_sake_parse_attributes(payload, payloadlen, &attr)) -+ return; -+ -+ if (!attr.rand_p || !attr.mic_p) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not " -+ "include AT_RAND_P or AT_MIC_P"); -+ return; -+ } -+ -+ os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN); -+ -+ os_free(data->peerid); -+ data->peerid = NULL; -+ data->peerid_len = 0; -+ if (attr.peerid) { -+ data->peerid = os_malloc(attr.peerid_len); -+ if (data->peerid == NULL) -+ return; -+ os_memcpy(data->peerid, attr.peerid, attr.peerid_len); -+ data->peerid_len = attr.peerid_len; -+ } -+ -+ if (sm->user == NULL || sm->user->password == NULL || -+ sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with " -+ "%d-byte key not configured", -+ 2 * EAP_SAKE_ROOT_SECRET_LEN); -+ data->state = FAILURE; -+ return; -+ } -+ eap_sake_derive_keys(sm->user->password, -+ sm->user->password + EAP_SAKE_ROOT_SECRET_LEN, -+ data->rand_s, data->rand_p, -+ (u8 *) &data->tek, data->msk, data->emsk); -+ -+ eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, -+ data->serverid, data->serverid_len, -+ data->peerid, data->peerid_len, 1, -+ wpabuf_head(respData), wpabuf_len(respData), -+ attr.mic_p, mic_p); -+ if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P"); -+ eap_sake_state(data, FAILURE); -+ return; -+ } -+ -+ eap_sake_state(data, CONFIRM); -+} -+ -+ -+static void eap_sake_process_confirm(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ const struct wpabuf *respData, -+ const u8 *payload, size_t payloadlen) -+{ -+ struct eap_sake_parse_attr attr; -+ u8 mic_p[EAP_SAKE_MIC_LEN]; -+ -+ if (data->state != CONFIRM) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm"); -+ -+ if (eap_sake_parse_attributes(payload, payloadlen, &attr)) -+ return; -+ -+ if (!attr.mic_p) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not " -+ "include AT_MIC_P"); -+ return; -+ } -+ -+ eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p, -+ data->serverid, data->serverid_len, -+ data->peerid, data->peerid_len, 1, -+ wpabuf_head(respData), wpabuf_len(respData), -+ attr.mic_p, mic_p); -+ if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { -+ wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P"); -+ eap_sake_state(data, FAILURE); -+ } else -+ eap_sake_state(data, SUCCESS); -+} -+ -+ -+static void eap_sake_process_auth_reject(struct eap_sm *sm, -+ struct eap_sake_data *data, -+ const struct wpabuf *respData, -+ const u8 *payload, size_t payloadlen) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject"); -+ eap_sake_state(data, FAILURE); -+} -+ -+ -+static void eap_sake_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_sake_data *data = priv; -+ struct eap_sake_hdr *resp; -+ u8 subtype; -+ size_t len; -+ const u8 *pos, *end; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE, respData, &len); -+ if (pos == NULL || len < sizeof(struct eap_sake_hdr)) -+ return; -+ -+ resp = (struct eap_sake_hdr *) pos; -+ end = pos + len; -+ subtype = resp->subtype; -+ pos = (u8 *) (resp + 1); -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes", -+ pos, end - pos); -+ -+ switch (subtype) { -+ case EAP_SAKE_SUBTYPE_IDENTITY: -+ eap_sake_process_identity(sm, data, respData, pos, end - pos); -+ break; -+ case EAP_SAKE_SUBTYPE_CHALLENGE: -+ eap_sake_process_challenge(sm, data, respData, pos, end - pos); -+ break; -+ case EAP_SAKE_SUBTYPE_CONFIRM: -+ eap_sake_process_confirm(sm, data, respData, pos, end - pos); -+ break; -+ case EAP_SAKE_SUBTYPE_AUTH_REJECT: -+ eap_sake_process_auth_reject(sm, data, respData, pos, -+ end - pos); -+ break; -+ } -+} -+ -+ -+static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sake_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sake_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_MSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->msk, EAP_MSK_LEN); -+ *len = EAP_MSK_LEN; -+ -+ return key; -+} -+ -+ -+static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sake_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ -+ return key; -+} -+ -+ -+static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sake_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_sake_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_sake_init; -+ eap->reset = eap_sake_reset; -+ eap->buildReq = eap_sake_buildReq; -+ eap->check = eap_sake_check; -+ eap->process = eap_sake_process; -+ eap->isDone = eap_sake_isDone; -+ eap->getKey = eap_sake_getKey; -+ eap->isSuccess = eap_sake_isSuccess; -+ eap->get_emsk = eap_sake_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sim.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sim.c -new file mode 100644 -index 0000000000000..29df2ff718aa1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_sim.c -@@ -0,0 +1,798 @@ -+/* -+ * hostapd / EAP-SIM (RFC 4186) -+ * Copyright (c) 2005-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_server/eap_i.h" -+#include "eap_common/eap_sim_common.h" -+#include "eap_server/eap_sim_db.h" -+ -+ -+struct eap_sim_data { -+ u8 mk[EAP_SIM_MK_LEN]; -+ u8 nonce_mt[EAP_SIM_NONCE_MT_LEN]; -+ u8 nonce_s[EAP_SIM_NONCE_S_LEN]; -+ u8 k_aut[EAP_SIM_K_AUT_LEN]; -+ u8 k_encr[EAP_SIM_K_ENCR_LEN]; -+ u8 msk[EAP_SIM_KEYING_DATA_LEN]; -+ u8 emsk[EAP_EMSK_LEN]; -+ u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; -+ u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; -+ u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; -+ int num_chal; -+ enum { -+ START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE -+ } state; -+ char *next_pseudonym; -+ char *next_reauth_id; -+ u16 counter; -+ struct eap_sim_reauth *reauth; -+ u16 notification; -+ int use_result_ind; -+}; -+ -+ -+static const char * eap_sim_state_txt(int state) -+{ -+ switch (state) { -+ case START: -+ return "START"; -+ case CHALLENGE: -+ return "CHALLENGE"; -+ case REAUTH: -+ return "REAUTH"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ case NOTIFICATION: -+ return "NOTIFICATION"; -+ default: -+ return "Unknown?!"; -+ } -+} -+ -+ -+static void eap_sim_state(struct eap_sim_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s", -+ eap_sim_state_txt(data->state), -+ eap_sim_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_sim_init(struct eap_sm *sm) -+{ -+ struct eap_sim_data *data; -+ -+ if (sm->eap_sim_db_priv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured"); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = START; -+ -+ return data; -+} -+ -+ -+static void eap_sim_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ os_free(data->next_pseudonym); -+ os_free(data->next_reauth_id); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_sim_build_start(struct eap_sm *sm, -+ struct eap_sim_data *data, u8 id) -+{ -+ struct eap_sim_msg *msg; -+ u8 ver[2]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start"); -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, -+ EAP_SIM_SUBTYPE_START); -+ if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len)) { -+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); -+ } else { -+ /* -+ * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is -+ * ignored and the SIM/Start is used to request the identity. -+ */ -+ wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); -+ } -+ wpa_printf(MSG_DEBUG, " AT_VERSION_LIST"); -+ ver[0] = 0; -+ ver[1] = EAP_SIM_VERSION; -+ eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver), -+ ver, sizeof(ver)); -+ return eap_sim_msg_finish(msg, NULL, NULL, 0); -+} -+ -+ -+static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data, -+ struct eap_sim_msg *msg, u16 counter, -+ const u8 *nonce_s) -+{ -+ os_free(data->next_pseudonym); -+ data->next_pseudonym = -+ eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0); -+ os_free(data->next_reauth_id); -+ if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) { -+ data->next_reauth_id = -+ eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication " -+ "count exceeded - force full authentication"); -+ data->next_reauth_id = NULL; -+ } -+ -+ if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && -+ counter == 0 && nonce_s == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); -+ -+ if (counter > 0) { -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); -+ } -+ -+ if (nonce_s) { -+ wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, -+ EAP_SIM_NONCE_S_LEN); -+ } -+ -+ if (data->next_pseudonym) { -+ wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", -+ data->next_pseudonym); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, -+ os_strlen(data->next_pseudonym), -+ (u8 *) data->next_pseudonym, -+ os_strlen(data->next_pseudonym)); -+ } -+ -+ if (data->next_reauth_id) { -+ wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", -+ data->next_reauth_id); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, -+ os_strlen(data->next_reauth_id), -+ (u8 *) data->next_reauth_id, -+ os_strlen(data->next_reauth_id)); -+ } -+ -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " -+ "AT_ENCR_DATA"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge"); -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, -+ EAP_SIM_SUBTYPE_CHALLENGE); -+ wpa_printf(MSG_DEBUG, " AT_RAND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand, -+ data->num_chal * GSM_RAND_LEN); -+ -+ if (eap_sim_build_encr(sm, data, msg, 0, NULL)) { -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ -+ if (sm->eap_sim_aka_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt, -+ EAP_SIM_NONCE_MT_LEN); -+} -+ -+ -+static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm, -+ struct eap_sim_data *data, u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication"); -+ -+ if (random_get_bytes(data->nonce_s, EAP_SIM_NONCE_S_LEN)) -+ return NULL; -+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S", -+ data->nonce_s, EAP_SIM_NONCE_S_LEN); -+ -+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, -+ data->emsk); -+ eap_sim_derive_keys_reauth(data->counter, sm->identity, -+ sm->identity_len, data->nonce_s, data->mk, -+ data->msk, data->emsk); -+ -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, -+ EAP_SIM_SUBTYPE_REAUTHENTICATION); -+ -+ if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) { -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ -+ if (sm->eap_sim_aka_result_ind) { -+ wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); -+ eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); -+ } -+ -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ u8 id) -+{ -+ struct eap_sim_msg *msg; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification"); -+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, -+ EAP_SIM_SUBTYPE_NOTIFICATION); -+ wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); -+ eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, -+ NULL, 0); -+ if (data->use_result_ind) { -+ if (data->reauth) { -+ wpa_printf(MSG_DEBUG, " AT_IV"); -+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); -+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, -+ EAP_SIM_AT_ENCR_DATA); -+ wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", -+ data->counter); -+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, -+ NULL, 0); -+ -+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, -+ EAP_SIM_AT_PADDING)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to " -+ "encrypt AT_ENCR_DATA"); -+ eap_sim_msg_free(msg); -+ return NULL; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, " AT_MAC"); -+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); -+ } -+ return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); -+} -+ -+ -+static struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_sim_data *data = priv; -+ -+ switch (data->state) { -+ case START: -+ return eap_sim_build_start(sm, data, id); -+ case CHALLENGE: -+ return eap_sim_build_challenge(sm, data, id); -+ case REAUTH: -+ return eap_sim_build_reauth(sm, data, id); -+ case NOTIFICATION: -+ return eap_sim_build_notification(sm, data, id); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " -+ "buildReq", data->state); -+ break; -+ } -+ return NULL; -+} -+ -+ -+static Boolean eap_sim_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_sim_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ u8 subtype; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); -+ if (pos == NULL || len < 3) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame"); -+ return TRUE; -+ } -+ subtype = *pos; -+ -+ if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) -+ return FALSE; -+ -+ switch (data->state) { -+ case START: -+ if (subtype != EAP_SIM_SUBTYPE_START) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ case CHALLENGE: -+ if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ case REAUTH: -+ if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ case NOTIFICATION: -+ if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " -+ "subtype %d", subtype); -+ return TRUE; -+ } -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for " -+ "processing a response", data->state); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static int eap_sim_supported_ver(struct eap_sim_data *data, int version) -+{ -+ return version == EAP_SIM_VERSION; -+} -+ -+ -+static void eap_sim_process_start(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ const u8 *identity; -+ size_t identity_len; -+ u8 ver_list[2]; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); -+ -+ if (attr->identity) { -+ os_free(sm->identity); -+ sm->identity = os_malloc(attr->identity_len); -+ if (sm->identity) { -+ os_memcpy(sm->identity, attr->identity, -+ attr->identity_len); -+ sm->identity_len = attr->identity_len; -+ } -+ } -+ -+ identity = NULL; -+ identity_len = 0; -+ -+ if (sm->identity && sm->identity_len > 0 && -+ sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) { -+ identity = sm->identity; -+ identity_len = sm->identity_len; -+ } else { -+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, -+ sm->identity, -+ sm->identity_len, -+ &identity_len); -+ if (identity == NULL) { -+ data->reauth = eap_sim_db_get_reauth_entry( -+ sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len); -+ if (data->reauth) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast " -+ "re-authentication"); -+ identity = data->reauth->identity; -+ identity_len = data->reauth->identity_len; -+ data->counter = data->reauth->counter; -+ os_memcpy(data->mk, data->reauth->mk, -+ EAP_SIM_MK_LEN); -+ } -+ } -+ } -+ -+ if (identity == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent" -+ " user name"); -+ eap_sim_state(data, FAILURE); -+ return; -+ } -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", -+ identity, identity_len); -+ -+ if (data->reauth) { -+ eap_sim_state(data, REAUTH); -+ return; -+ } -+ -+ if (attr->nonce_mt == NULL || attr->selected_version < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " -+ "required attributes"); -+ eap_sim_state(data, FAILURE); -+ return; -+ } -+ -+ if (!eap_sim_supported_ver(data, attr->selected_version)) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " -+ "version %d", attr->selected_version); -+ eap_sim_state(data, FAILURE); -+ return; -+ } -+ -+ data->counter = 0; /* reset re-auth counter since this is full auth */ -+ data->reauth = NULL; -+ -+ data->num_chal = eap_sim_db_get_gsm_triplets( -+ sm->eap_sim_db_priv, identity, identity_len, -+ EAP_SIM_MAX_CHAL, -+ (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); -+ if (data->num_chal == EAP_SIM_DB_PENDING) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " -+ "not yet available - pending request"); -+ sm->method_pending = METHOD_PENDING_WAIT; -+ return; -+ } -+ if (data->num_chal < 2) { -+ wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " -+ "authentication triplets for the peer"); -+ eap_sim_state(data, FAILURE); -+ return; -+ } -+ -+ identity_len = sm->identity_len; -+ while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " -+ "character from identity"); -+ identity_len--; -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", -+ sm->identity, identity_len); -+ -+ os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); -+ WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); -+ eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, -+ attr->selected_version, ver_list, sizeof(ver_list), -+ data->num_chal, (const u8 *) data->kc, data->mk); -+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, -+ data->emsk); -+ -+ eap_sim_state(data, CHALLENGE); -+} -+ -+ -+static void eap_sim_process_challenge(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ const u8 *identity; -+ size_t identity_len; -+ -+ if (attr->mac == NULL || -+ eap_sim_verify_mac(data->k_aut, respData, attr->mac, -+ (u8 *) data->sres, -+ data->num_chal * EAP_SIM_SRES_LEN)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " -+ "did not include valid AT_MAC"); -+ eap_sim_state(data, FAILURE); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the " -+ "correct AT_MAC"); -+ if (sm->eap_sim_aka_result_ind && attr->result_ind) { -+ data->use_result_ind = 1; -+ data->notification = EAP_SIM_SUCCESS; -+ eap_sim_state(data, NOTIFICATION); -+ } else -+ eap_sim_state(data, SUCCESS); -+ -+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, -+ sm->identity_len, &identity_len); -+ if (identity == NULL) { -+ identity = sm->identity; -+ identity_len = sm->identity_len; -+ } -+ -+ if (data->next_pseudonym) { -+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, -+ identity_len, -+ data->next_pseudonym); -+ data->next_pseudonym = NULL; -+ } -+ if (data->next_reauth_id) { -+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, -+ identity_len, -+ data->next_reauth_id, data->counter + 1, -+ data->mk); -+ data->next_reauth_id = NULL; -+ } -+} -+ -+ -+static void eap_sim_process_reauth(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ struct eap_sim_attrs eattr; -+ u8 *decrypted = NULL; -+ const u8 *identity, *id2; -+ size_t identity_len, id2_len; -+ -+ if (attr->mac == NULL || -+ eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, -+ EAP_SIM_NONCE_S_LEN)) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " -+ "did not include valid AT_MAC"); -+ goto fail; -+ } -+ -+ if (attr->encr_data == NULL || attr->iv == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " -+ "message did not include encrypted data"); -+ goto fail; -+ } -+ -+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, -+ attr->encr_data_len, attr->iv, &eattr, -+ 0); -+ if (decrypted == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " -+ "data from reauthentication message"); -+ goto fail; -+ } -+ -+ if (eattr.counter != data->counter) { -+ wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " -+ "used incorrect counter %u, expected %u", -+ eattr.counter, data->counter); -+ goto fail; -+ } -+ os_free(decrypted); -+ decrypted = NULL; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " -+ "the correct AT_MAC"); -+ if (sm->eap_sim_aka_result_ind && attr->result_ind) { -+ data->use_result_ind = 1; -+ data->notification = EAP_SIM_SUCCESS; -+ eap_sim_state(data, NOTIFICATION); -+ } else -+ eap_sim_state(data, SUCCESS); -+ -+ if (data->reauth) { -+ identity = data->reauth->identity; -+ identity_len = data->reauth->identity_len; -+ } else { -+ identity = sm->identity; -+ identity_len = sm->identity_len; -+ } -+ -+ id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, -+ identity_len, &id2_len); -+ if (id2) { -+ identity = id2; -+ identity_len = id2_len; -+ } -+ -+ if (data->next_pseudonym) { -+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, -+ identity_len, data->next_pseudonym); -+ data->next_pseudonym = NULL; -+ } -+ if (data->next_reauth_id) { -+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, -+ identity_len, data->next_reauth_id, -+ data->counter + 1, data->mk); -+ data->next_reauth_id = NULL; -+ } else { -+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); -+ data->reauth = NULL; -+ } -+ -+ return; -+ -+fail: -+ eap_sim_state(data, FAILURE); -+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); -+ data->reauth = NULL; -+ os_free(decrypted); -+} -+ -+ -+static void eap_sim_process_client_error(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d", -+ attr->client_error_code); -+ if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) -+ eap_sim_state(data, SUCCESS); -+ else -+ eap_sim_state(data, FAILURE); -+} -+ -+ -+static void eap_sim_process_notification(struct eap_sm *sm, -+ struct eap_sim_data *data, -+ struct wpabuf *respData, -+ struct eap_sim_attrs *attr) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification"); -+ if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) -+ eap_sim_state(data, SUCCESS); -+ else -+ eap_sim_state(data, FAILURE); -+} -+ -+ -+static void eap_sim_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_sim_data *data = priv; -+ const u8 *pos, *end; -+ u8 subtype; -+ size_t len; -+ struct eap_sim_attrs attr; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); -+ if (pos == NULL || len < 3) -+ return; -+ -+ end = pos + len; -+ subtype = *pos; -+ pos += 3; -+ -+ if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); -+ eap_sim_state(data, FAILURE); -+ return; -+ } -+ -+ if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { -+ eap_sim_process_client_error(sm, data, respData, &attr); -+ return; -+ } -+ -+ switch (data->state) { -+ case START: -+ eap_sim_process_start(sm, data, respData, &attr); -+ break; -+ case CHALLENGE: -+ eap_sim_process_challenge(sm, data, respData, &attr); -+ break; -+ case REAUTH: -+ eap_sim_process_reauth(sm, data, respData, &attr); -+ break; -+ case NOTIFICATION: -+ eap_sim_process_notification(sm, data, respData, &attr); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " -+ "process", data->state); -+ break; -+ } -+} -+ -+ -+static Boolean eap_sim_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sim_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_SIM_KEYING_DATA_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); -+ *len = EAP_SIM_KEYING_DATA_LEN; -+ return key; -+} -+ -+ -+static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_sim_data *data = priv; -+ u8 *key; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(EAP_EMSK_LEN); -+ if (key == NULL) -+ return NULL; -+ os_memcpy(key, data->emsk, EAP_EMSK_LEN); -+ *len = EAP_EMSK_LEN; -+ return key; -+} -+ -+ -+static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_sim_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_sim_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_sim_init; -+ eap->reset = eap_sim_reset; -+ eap->buildReq = eap_sim_buildReq; -+ eap->check = eap_sim_check; -+ eap->process = eap_sim_process; -+ eap->isDone = eap_sim_isDone; -+ eap->getKey = eap_sim_getKey; -+ eap->isSuccess = eap_sim_isSuccess; -+ eap->get_emsk = eap_sim_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls.c -new file mode 100644 -index 0000000000000..c98fa185bb5df ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls.c -@@ -0,0 +1,286 @@ -+/* -+ * hostapd / EAP-TLS (RFC 2716) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+#include "crypto/tls.h" -+ -+ -+static void eap_tls_reset(struct eap_sm *sm, void *priv); -+ -+ -+struct eap_tls_data { -+ struct eap_ssl_data ssl; -+ enum { START, CONTINUE, SUCCESS, FAILURE } state; -+ int established; -+}; -+ -+ -+static const char * eap_tls_state_txt(int state) -+{ -+ switch (state) { -+ case START: -+ return "START"; -+ case CONTINUE: -+ return "CONTINUE"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "Unknown?!"; -+ } -+} -+ -+ -+static void eap_tls_state(struct eap_tls_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s", -+ eap_tls_state_txt(data->state), -+ eap_tls_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_tls_init(struct eap_sm *sm) -+{ -+ struct eap_tls_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = START; -+ -+ if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) { -+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); -+ eap_tls_reset(sm, data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_tls_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tls_data *data = priv; -+ if (data == NULL) -+ return; -+ eap_server_tls_ssl_deinit(sm, &data->ssl); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_tls_build_start(struct eap_sm *sm, -+ struct eap_tls_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST, -+ id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " -+ "request"); -+ eap_tls_state(data, FAILURE); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, EAP_TLS_FLAGS_START); -+ -+ eap_tls_state(data, CONTINUE); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_tls_data *data = priv; -+ struct wpabuf *res; -+ -+ if (data->ssl.state == FRAG_ACK) { -+ return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0); -+ } -+ -+ if (data->ssl.state == WAIT_FRAG_ACK) { -+ res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, -+ id); -+ goto check_established; -+ } -+ -+ switch (data->state) { -+ case START: -+ return eap_tls_build_start(sm, data, id); -+ case CONTINUE: -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) -+ data->established = 1; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d", -+ __func__, data->state); -+ return NULL; -+ } -+ -+ res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id); -+ -+check_established: -+ if (data->established && data->ssl.state != WAIT_FRAG_ACK) { -+ /* TLS handshake has been completed and there are no more -+ * fragments waiting to be sent out. */ -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); -+ eap_tls_state(data, SUCCESS); -+ } -+ -+ return res; -+} -+ -+ -+static Boolean eap_tls_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_tls_process_msg(struct eap_sm *sm, void *priv, -+ const struct wpabuf *respData) -+{ -+ struct eap_tls_data *data = priv; -+ if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " -+ "handshake message"); -+ return; -+ } -+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) -+ eap_tls_state(data, FAILURE); -+} -+ -+ -+static void eap_tls_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_tls_data *data = priv; -+ if (eap_server_tls_process(sm, &data->ssl, respData, data, -+ EAP_TYPE_TLS, NULL, eap_tls_process_msg) < -+ 0) -+ eap_tls_state(data, FAILURE); -+} -+ -+ -+static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tls_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_tls_data *data = priv; -+ u8 *eapKeyData; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, -+ "client EAP encryption", -+ EAP_TLS_KEY_LEN); -+ if (eapKeyData) { -+ *len = EAP_TLS_KEY_LEN; -+ wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", -+ eapKeyData, EAP_TLS_KEY_LEN); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); -+ } -+ -+ return eapKeyData; -+} -+ -+ -+static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_tls_data *data = priv; -+ u8 *eapKeyData, *emsk; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, -+ "client EAP encryption", -+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN); -+ if (eapKeyData) { -+ emsk = os_malloc(EAP_EMSK_LEN); -+ if (emsk) -+ os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, -+ EAP_EMSK_LEN); -+ os_free(eapKeyData); -+ } else -+ emsk = NULL; -+ -+ if (emsk) { -+ *len = EAP_EMSK_LEN; -+ wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", -+ emsk, EAP_EMSK_LEN); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); -+ } -+ -+ return emsk; -+} -+ -+ -+static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tls_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_tls_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_tls_init; -+ eap->reset = eap_tls_reset; -+ eap->buildReq = eap_tls_buildReq; -+ eap->check = eap_tls_check; -+ eap->process = eap_tls_process; -+ eap->isDone = eap_tls_isDone; -+ eap->getKey = eap_tls_getKey; -+ eap->isSuccess = eap_tls_isSuccess; -+ eap->get_emsk = eap_tls_get_emsk; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls_common.c -new file mode 100644 -index 0000000000000..e149ee3e47021 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tls_common.c -@@ -0,0 +1,400 @@ -+/* -+ * EAP-TLS/PEAP/TTLS/FAST server common functions -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "eap_i.h" -+#include "eap_tls_common.h" -+ -+ -+static void eap_server_tls_free_in_buf(struct eap_ssl_data *data); -+ -+ -+int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, -+ int verify_peer) -+{ -+ data->eap = sm; -+ data->phase2 = sm->init_phase2; -+ -+ data->conn = tls_connection_init(sm->ssl_ctx); -+ if (data->conn == NULL) { -+ wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " -+ "connection"); -+ return -1; -+ } -+ -+ if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) { -+ wpa_printf(MSG_INFO, "SSL: Failed to configure verification " -+ "of TLS peer certificate"); -+ tls_connection_deinit(sm->ssl_ctx, data->conn); -+ data->conn = NULL; -+ return -1; -+ } -+ -+ data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398; -+ if (data->phase2) { -+ /* Limit the fragment size in the inner TLS authentication -+ * since the outer authentication with EAP-PEAP does not yet -+ * support fragmentation */ -+ if (data->tls_out_limit > 100) -+ data->tls_out_limit -= 100; -+ } -+ return 0; -+} -+ -+ -+void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) -+{ -+ tls_connection_deinit(sm->ssl_ctx, data->conn); -+ eap_server_tls_free_in_buf(data); -+ wpabuf_free(data->tls_out); -+ data->tls_out = NULL; -+} -+ -+ -+u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, -+ char *label, size_t len) -+{ -+ struct tls_keys keys; -+ u8 *rnd = NULL, *out; -+ -+ out = os_malloc(len); -+ if (out == NULL) -+ return NULL; -+ -+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == -+ 0) -+ return out; -+ -+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) -+ goto fail; -+ -+ if (keys.client_random == NULL || keys.server_random == NULL || -+ keys.master_key == NULL) -+ goto fail; -+ -+ rnd = os_malloc(keys.client_random_len + keys.server_random_len); -+ if (rnd == NULL) -+ goto fail; -+ os_memcpy(rnd, keys.client_random, keys.client_random_len); -+ os_memcpy(rnd + keys.client_random_len, keys.server_random, -+ keys.server_random_len); -+ -+ if (tls_prf(keys.master_key, keys.master_key_len, -+ label, rnd, keys.client_random_len + -+ keys.server_random_len, out, len)) -+ goto fail; -+ -+ os_free(rnd); -+ return out; -+ -+fail: -+ os_free(out); -+ os_free(rnd); -+ return NULL; -+} -+ -+ -+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, -+ int eap_type, int version, u8 id) -+{ -+ struct wpabuf *req; -+ u8 flags; -+ size_t send_len, plen; -+ -+ wpa_printf(MSG_DEBUG, "SSL: Generating Request"); -+ if (data->tls_out == NULL) { -+ wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__); -+ return NULL; -+ } -+ -+ flags = version; -+ send_len = wpabuf_len(data->tls_out) - data->tls_out_pos; -+ if (1 + send_len > data->tls_out_limit) { -+ send_len = data->tls_out_limit - 1; -+ flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; -+ if (data->tls_out_pos == 0) { -+ flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; -+ send_len -= 4; -+ } -+ } -+ -+ plen = 1 + send_len; -+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) -+ plen += 4; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(req, flags); /* Flags */ -+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) -+ wpabuf_put_be32(req, wpabuf_len(data->tls_out)); -+ -+ wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos, -+ send_len); -+ data->tls_out_pos += send_len; -+ -+ if (data->tls_out_pos == wpabuf_len(data->tls_out)) { -+ wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " -+ "(message sent completely)", -+ (unsigned long) send_len); -+ wpabuf_free(data->tls_out); -+ data->tls_out = NULL; -+ data->tls_out_pos = 0; -+ data->state = MSG; -+ } else { -+ wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes " -+ "(%lu more to send)", (unsigned long) send_len, -+ (unsigned long) wpabuf_len(data->tls_out) - -+ data->tls_out_pos); -+ data->state = WAIT_FRAG_ACK; -+ } -+ -+ return req; -+} -+ -+ -+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version) -+{ -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST, -+ id); -+ if (req == NULL) -+ return NULL; -+ wpa_printf(MSG_DEBUG, "SSL: Building ACK"); -+ wpabuf_put_u8(req, version); /* Flags */ -+ return req; -+} -+ -+ -+static int eap_server_tls_process_cont(struct eap_ssl_data *data, -+ const u8 *buf, size_t len) -+{ -+ /* Process continuation of a pending message */ -+ if (len > wpabuf_tailroom(data->tls_in)) { -+ wpa_printf(MSG_DEBUG, "SSL: Fragment overflow"); -+ return -1; -+ } -+ -+ wpabuf_put_data(data->tls_in, buf, len); -+ wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu " -+ "bytes more", (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->tls_in)); -+ -+ return 0; -+} -+ -+ -+static int eap_server_tls_process_fragment(struct eap_ssl_data *data, -+ u8 flags, u32 message_length, -+ const u8 *buf, size_t len) -+{ -+ /* Process a fragment that is not the last one of the message */ -+ if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) { -+ wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a " -+ "fragmented packet"); -+ return -1; -+ } -+ -+ if (data->tls_in == NULL) { -+ /* First fragment of the message */ -+ -+ /* Limit length to avoid rogue peers from causing large -+ * memory allocations. */ -+ if (message_length > 65536) { -+ wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size" -+ " over 64 kB)"); -+ return -1; -+ } -+ -+ data->tls_in = wpabuf_alloc(message_length); -+ if (data->tls_in == NULL) { -+ wpa_printf(MSG_DEBUG, "SSL: No memory for message"); -+ return -1; -+ } -+ wpabuf_put_data(data->tls_in, buf, len); -+ wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first " -+ "fragment, waiting for %lu bytes more", -+ (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->tls_in)); -+ } -+ -+ return 0; -+} -+ -+ -+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) -+{ -+ if (data->tls_out) { -+ /* This should not happen.. */ -+ wpa_printf(MSG_INFO, "SSL: pending tls_out data when " -+ "processing new message"); -+ wpabuf_free(data->tls_out); -+ WPA_ASSERT(data->tls_out == NULL); -+ } -+ -+ data->tls_out = tls_connection_server_handshake(sm->ssl_ctx, -+ data->conn, -+ data->tls_in, NULL); -+ if (data->tls_out == NULL) { -+ wpa_printf(MSG_INFO, "SSL: TLS processing failed"); -+ return -1; -+ } -+ if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { -+ /* TLS processing has failed - return error */ -+ wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " -+ "report error"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags, -+ const u8 **pos, size_t *left) -+{ -+ unsigned int tls_msg_len = 0; -+ const u8 *end = *pos + *left; -+ -+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { -+ if (*left < 4) { -+ wpa_printf(MSG_INFO, "SSL: Short frame with TLS " -+ "length"); -+ return -1; -+ } -+ tls_msg_len = WPA_GET_BE32(*pos); -+ wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", -+ tls_msg_len); -+ *pos += 4; -+ *left -= 4; -+ } -+ -+ wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x " -+ "Message Length %u", flags, tls_msg_len); -+ -+ if (data->state == WAIT_FRAG_ACK) { -+ if (*left != 0) { -+ wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in " -+ "WAIT_FRAG_ACK state"); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged"); -+ return 1; -+ } -+ -+ if (data->tls_in && -+ eap_server_tls_process_cont(data, *pos, end - *pos) < 0) -+ return -1; -+ -+ if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) { -+ if (eap_server_tls_process_fragment(data, flags, tls_msg_len, -+ *pos, end - *pos) < 0) -+ return -1; -+ -+ data->state = FRAG_ACK; -+ return 1; -+ } -+ -+ if (data->state == FRAG_ACK) { -+ wpa_printf(MSG_DEBUG, "SSL: All fragments received"); -+ data->state = MSG; -+ } -+ -+ if (data->tls_in == NULL) { -+ /* Wrap unfragmented messages as wpabuf without extra copy */ -+ wpabuf_set(&data->tmpbuf, *pos, end - *pos); -+ data->tls_in = &data->tmpbuf; -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_server_tls_free_in_buf(struct eap_ssl_data *data) -+{ -+ if (data->tls_in != &data->tmpbuf) -+ wpabuf_free(data->tls_in); -+ data->tls_in = NULL; -+} -+ -+ -+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, -+ struct eap_ssl_data *data, -+ const struct wpabuf *plain) -+{ -+ struct wpabuf *buf; -+ -+ buf = tls_connection_encrypt(sm->ssl_ctx, data->conn, -+ plain); -+ if (buf == NULL) { -+ wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); -+ return NULL; -+ } -+ -+ return buf; -+} -+ -+ -+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, -+ struct wpabuf *respData, void *priv, int eap_type, -+ int (*proc_version)(struct eap_sm *sm, void *priv, -+ int peer_version), -+ void (*proc_msg)(struct eap_sm *sm, void *priv, -+ const struct wpabuf *respData)) -+{ -+ const u8 *pos; -+ u8 flags; -+ size_t left; -+ int ret, res = 0; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left); -+ if (pos == NULL || left < 1) -+ return 0; /* Should not happen - frame already validated */ -+ flags = *pos++; -+ left--; -+ wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x", -+ (unsigned long) wpabuf_len(respData), flags); -+ -+ if (proc_version && -+ proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0) -+ return -1; -+ -+ ret = eap_server_tls_reassemble(data, flags, &pos, &left); -+ if (ret < 0) { -+ res = -1; -+ goto done; -+ } else if (ret == 1) -+ return 0; -+ -+ if (proc_msg) -+ proc_msg(sm, priv, respData); -+ -+ if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) { -+ wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in " -+ "TLS processing"); -+ res = -1; -+ } -+ -+done: -+ eap_server_tls_free_in_buf(data); -+ -+ return res; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tnc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tnc.c -new file mode 100644 -index 0000000000000..a2d6f17088383 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_tnc.c -@@ -0,0 +1,582 @@ -+/* -+ * EAP server method: EAP-TNC (Trusted Network Connect) -+ * Copyright (c) 2007-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "base64.h" -+#include "eap_i.h" -+#include "tncs.h" -+ -+ -+struct eap_tnc_data { -+ enum eap_tnc_state { -+ START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE, -+ FAIL -+ } state; -+ enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation; -+ struct tncs_data *tncs; -+ struct wpabuf *in_buf; -+ struct wpabuf *out_buf; -+ size_t out_used; -+ size_t fragment_size; -+ unsigned int was_done:1; -+ unsigned int was_fail:1; -+}; -+ -+ -+/* EAP-TNC Flags */ -+#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80 -+#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40 -+#define EAP_TNC_FLAGS_START 0x20 -+#define EAP_TNC_VERSION_MASK 0x07 -+ -+#define EAP_TNC_VERSION 1 -+ -+ -+static const char * eap_tnc_state_txt(enum eap_tnc_state state) -+{ -+ switch (state) { -+ case START: -+ return "START"; -+ case CONTINUE: -+ return "CONTINUE"; -+ case RECOMMENDATION: -+ return "RECOMMENDATION"; -+ case FRAG_ACK: -+ return "FRAG_ACK"; -+ case WAIT_FRAG_ACK: -+ return "WAIT_FRAG_ACK"; -+ case DONE: -+ return "DONE"; -+ case FAIL: -+ return "FAIL"; -+ } -+ return "??"; -+} -+ -+ -+static void eap_tnc_set_state(struct eap_tnc_data *data, -+ enum eap_tnc_state new_state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-TNC: %s -> %s", -+ eap_tnc_state_txt(data->state), -+ eap_tnc_state_txt(new_state)); -+ data->state = new_state; -+} -+ -+ -+static void * eap_tnc_init(struct eap_sm *sm) -+{ -+ struct eap_tnc_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ eap_tnc_set_state(data, START); -+ data->tncs = tncs_init(); -+ if (data->tncs == NULL) { -+ os_free(data); -+ return NULL; -+ } -+ -+ data->fragment_size = sm->fragment_size > 100 ? -+ sm->fragment_size - 98 : 1300; -+ -+ return data; -+} -+ -+ -+static void eap_tnc_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tnc_data *data = priv; -+ wpabuf_free(data->in_buf); -+ wpabuf_free(data->out_buf); -+ tncs_deinit(data->tncs); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm, -+ struct eap_tnc_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST, -+ id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for " -+ "request"); -+ eap_tnc_set_state(data, FAIL); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION); -+ -+ eap_tnc_set_state(data, CONTINUE); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_tnc_build(struct eap_sm *sm, -+ struct eap_tnc_data *data) -+{ -+ struct wpabuf *req; -+ u8 *rpos, *rpos1; -+ size_t rlen; -+ char *start_buf, *end_buf; -+ size_t start_len, end_len; -+ size_t imv_len; -+ -+ imv_len = tncs_total_send_len(data->tncs); -+ -+ start_buf = tncs_if_tnccs_start(data->tncs); -+ if (start_buf == NULL) -+ return NULL; -+ start_len = os_strlen(start_buf); -+ end_buf = tncs_if_tnccs_end(); -+ if (end_buf == NULL) { -+ os_free(start_buf); -+ return NULL; -+ } -+ end_len = os_strlen(end_buf); -+ -+ rlen = start_len + imv_len + end_len; -+ req = wpabuf_alloc(rlen); -+ if (req == NULL) { -+ os_free(start_buf); -+ os_free(end_buf); -+ return NULL; -+ } -+ -+ wpabuf_put_data(req, start_buf, start_len); -+ os_free(start_buf); -+ -+ rpos1 = wpabuf_put(req, 0); -+ rpos = tncs_copy_send_buf(data->tncs, rpos1); -+ wpabuf_put(req, rpos - rpos1); -+ -+ wpabuf_put_data(req, end_buf, end_len); -+ os_free(end_buf); -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request", -+ wpabuf_head(req), wpabuf_len(req)); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm, -+ struct eap_tnc_data *data) -+{ -+ switch (data->recommendation) { -+ case ALLOW: -+ eap_tnc_set_state(data, DONE); -+ break; -+ case ISOLATE: -+ eap_tnc_set_state(data, FAIL); -+ /* TODO: support assignment to a different VLAN */ -+ break; -+ case NO_ACCESS: -+ eap_tnc_set_state(data, FAIL); -+ break; -+ case NO_RECOMMENDATION: -+ eap_tnc_set_state(data, DONE); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation"); -+ return NULL; -+ } -+ -+ return eap_tnc_build(sm, data); -+} -+ -+ -+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code) -+{ -+ struct wpabuf *msg; -+ -+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id); -+ if (msg == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory " -+ "for fragment ack"); -+ return NULL; -+ } -+ wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */ -+ -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack"); -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ u8 flags; -+ size_t send_len, plen; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request"); -+ -+ flags = EAP_TNC_VERSION; -+ send_len = wpabuf_len(data->out_buf) - data->out_used; -+ if (1 + send_len > data->fragment_size) { -+ send_len = data->fragment_size - 1; -+ flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS; -+ if (data->out_used == 0) { -+ flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED; -+ send_len -= 4; -+ } -+ } -+ -+ plen = 1 + send_len; -+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) -+ plen += 4; -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(req, flags); /* Flags */ -+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) -+ wpabuf_put_be32(req, wpabuf_len(data->out_buf)); -+ -+ wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, -+ send_len); -+ data->out_used += send_len; -+ -+ if (data->out_used == wpabuf_len(data->out_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " -+ "(message sent completely)", -+ (unsigned long) send_len); -+ wpabuf_free(data->out_buf); -+ data->out_buf = NULL; -+ data->out_used = 0; -+ if (data->was_fail) -+ eap_tnc_set_state(data, FAIL); -+ else if (data->was_done) -+ eap_tnc_set_state(data, DONE); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " -+ "(%lu more to send)", (unsigned long) send_len, -+ (unsigned long) wpabuf_len(data->out_buf) - -+ data->out_used); -+ if (data->state == FAIL) -+ data->was_fail = 1; -+ else if (data->state == DONE) -+ data->was_done = 1; -+ eap_tnc_set_state(data, WAIT_FRAG_ACK); -+ } -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_tnc_data *data = priv; -+ -+ switch (data->state) { -+ case START: -+ tncs_init_connection(data->tncs); -+ return eap_tnc_build_start(sm, data, id); -+ case CONTINUE: -+ if (data->out_buf == NULL) { -+ data->out_buf = eap_tnc_build(sm, data); -+ if (data->out_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " -+ "generate message"); -+ return NULL; -+ } -+ data->out_used = 0; -+ } -+ return eap_tnc_build_msg(data, id); -+ case RECOMMENDATION: -+ if (data->out_buf == NULL) { -+ data->out_buf = eap_tnc_build_recommendation(sm, data); -+ if (data->out_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to " -+ "generate recommendation message"); -+ return NULL; -+ } -+ data->out_used = 0; -+ } -+ return eap_tnc_build_msg(data, id); -+ case WAIT_FRAG_ACK: -+ return eap_tnc_build_msg(data, id); -+ case FRAG_ACK: -+ return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST); -+ case DONE: -+ case FAIL: -+ return NULL; -+ } -+ -+ return NULL; -+} -+ -+ -+static Boolean eap_tnc_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_tnc_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, -+ &len); -+ if (pos == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame"); -+ return TRUE; -+ } -+ -+ if (len == 0 && data->state != WAIT_FRAG_ACK) { -+ wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)"); -+ return TRUE; -+ } -+ -+ if (len == 0) -+ return FALSE; /* Fragment ACK does not include flags */ -+ -+ if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d", -+ *pos & EAP_TNC_VERSION_MASK); -+ return TRUE; -+ } -+ -+ if (*pos & EAP_TNC_FLAGS_START) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf) -+{ -+ enum tncs_process_res res; -+ -+ res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf), -+ wpabuf_len(inbuf)); -+ switch (res) { -+ case TNCCS_RECOMMENDATION_ALLOW: -+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access"); -+ eap_tnc_set_state(data, RECOMMENDATION); -+ data->recommendation = ALLOW; -+ break; -+ case TNCCS_RECOMMENDATION_NO_RECOMMENDATION: -+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation"); -+ eap_tnc_set_state(data, RECOMMENDATION); -+ data->recommendation = NO_RECOMMENDATION; -+ break; -+ case TNCCS_RECOMMENDATION_ISOLATE: -+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation"); -+ eap_tnc_set_state(data, RECOMMENDATION); -+ data->recommendation = ISOLATE; -+ break; -+ case TNCCS_RECOMMENDATION_NO_ACCESS: -+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access"); -+ eap_tnc_set_state(data, RECOMMENDATION); -+ data->recommendation = NO_ACCESS; -+ break; -+ case TNCCS_PROCESS_ERROR: -+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error"); -+ eap_tnc_set_state(data, FAIL); -+ break; -+ default: -+ break; -+ } -+} -+ -+ -+static int eap_tnc_process_cont(struct eap_tnc_data *data, -+ const u8 *buf, size_t len) -+{ -+ /* Process continuation of a pending message */ -+ if (len > wpabuf_tailroom(data->in_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); -+ eap_tnc_set_state(data, FAIL); -+ return -1; -+ } -+ -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu " -+ "bytes more", (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ -+ return 0; -+} -+ -+ -+static int eap_tnc_process_fragment(struct eap_tnc_data *data, -+ u8 flags, u32 message_length, -+ const u8 *buf, size_t len) -+{ -+ /* Process a fragment that is not the last one of the message */ -+ if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a " -+ "fragmented packet"); -+ return -1; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* First fragment of the message */ -+ data->in_buf = wpabuf_alloc(message_length); -+ if (data->in_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for " -+ "message"); -+ return -1; -+ } -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first " -+ "fragment, waiting for %lu bytes more", -+ (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_tnc_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_tnc_data *data = priv; -+ const u8 *pos, *end; -+ size_t len; -+ u8 flags; -+ u32 message_length = 0; -+ struct wpabuf tmpbuf; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len); -+ if (pos == NULL) -+ return; /* Should not happen; message already verified */ -+ -+ end = pos + len; -+ -+ if (len == 1 && (data->state == DONE || data->state == FAIL)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last " -+ "message"); -+ return; -+ } -+ -+ if (len == 0) { -+ /* fragment ack */ -+ flags = 0; -+ } else -+ flags = *pos++; -+ -+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { -+ if (end - pos < 4) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); -+ eap_tnc_set_state(data, FAIL); -+ return; -+ } -+ message_length = WPA_GET_BE32(pos); -+ pos += 4; -+ -+ if (message_length < (u32) (end - pos)) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " -+ "Length (%d; %ld remaining in this msg)", -+ message_length, (long) (end - pos)); -+ eap_tnc_set_state(data, FAIL); -+ return; -+ } -+ } -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " -+ "Message Length %u", flags, message_length); -+ -+ if (data->state == WAIT_FRAG_ACK) { -+ if (len > 1) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload " -+ "in WAIT_FRAG_ACK state"); -+ eap_tnc_set_state(data, FAIL); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); -+ eap_tnc_set_state(data, CONTINUE); -+ return; -+ } -+ -+ if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { -+ eap_tnc_set_state(data, FAIL); -+ return; -+ } -+ -+ if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { -+ if (eap_tnc_process_fragment(data, flags, message_length, -+ pos, end - pos) < 0) -+ eap_tnc_set_state(data, FAIL); -+ else -+ eap_tnc_set_state(data, FRAG_ACK); -+ return; -+ } else if (data->state == FRAG_ACK) { -+ wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); -+ eap_tnc_set_state(data, CONTINUE); -+ } -+ -+ if (data->in_buf == NULL) { -+ /* Wrap unfragmented messages as wpabuf without extra copy */ -+ wpabuf_set(&tmpbuf, pos, end - pos); -+ data->in_buf = &tmpbuf; -+ } -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", -+ wpabuf_head(data->in_buf), wpabuf_len(data->in_buf)); -+ tncs_process(data, data->in_buf); -+ -+ if (data->in_buf != &tmpbuf) -+ wpabuf_free(data->in_buf); -+ data->in_buf = NULL; -+} -+ -+ -+static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tnc_data *data = priv; -+ return data->state == DONE || data->state == FAIL; -+} -+ -+ -+static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_tnc_data *data = priv; -+ return data->state == DONE; -+} -+ -+ -+int eap_server_tnc_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_tnc_init; -+ eap->reset = eap_tnc_reset; -+ eap->buildReq = eap_tnc_buildReq; -+ eap->check = eap_tnc_check; -+ eap->process = eap_tnc_process; -+ eap->isDone = eap_tnc_isDone; -+ eap->isSuccess = eap_tnc_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ttls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ttls.c -new file mode 100644 -index 0000000000000..702c50c3566e4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_ttls.c -@@ -0,0 +1,1430 @@ -+/* -+ * hostapd / EAP-TTLS (RFC 5281) -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/ms_funcs.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "eap_server/eap_i.h" -+#include "eap_server/eap_tls_common.h" -+#include "eap_common/chap.h" -+#include "eap_common/eap_ttls.h" -+ -+ -+/* Maximum supported TTLS version -+ * 0 = RFC 5281 -+ * 1 = draft-funk-eap-ttls-v1-00.txt -+ */ -+#ifndef EAP_TTLS_VERSION -+#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ -+#endif /* EAP_TTLS_VERSION */ -+ -+ -+#define MSCHAPV2_KEY_LEN 16 -+ -+ -+static void eap_ttls_reset(struct eap_sm *sm, void *priv); -+ -+ -+struct eap_ttls_data { -+ struct eap_ssl_data ssl; -+ enum { -+ START, PHASE1, PHASE2_START, PHASE2_METHOD, -+ PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE -+ } state; -+ -+ int ttls_version; -+ int force_version; -+ const struct eap_method *phase2_method; -+ void *phase2_priv; -+ int mschapv2_resp_ok; -+ u8 mschapv2_auth_response[20]; -+ u8 mschapv2_ident; -+ int tls_ia_configured; -+ struct wpabuf *pending_phase2_eap_resp; -+ int tnc_started; -+}; -+ -+ -+static const char * eap_ttls_state_txt(int state) -+{ -+ switch (state) { -+ case START: -+ return "START"; -+ case PHASE1: -+ return "PHASE1"; -+ case PHASE2_START: -+ return "PHASE2_START"; -+ case PHASE2_METHOD: -+ return "PHASE2_METHOD"; -+ case PHASE2_MSCHAPV2_RESP: -+ return "PHASE2_MSCHAPV2_RESP"; -+ case PHASE_FINISHED: -+ return "PHASE_FINISHED"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "Unknown?!"; -+ } -+} -+ -+ -+static void eap_ttls_state(struct eap_ttls_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: %s -> %s", -+ eap_ttls_state_txt(data->state), -+ eap_ttls_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id, -+ int mandatory, size_t len) -+{ -+ struct ttls_avp_vendor *avp; -+ u8 flags; -+ size_t hdrlen; -+ -+ avp = (struct ttls_avp_vendor *) avphdr; -+ flags = mandatory ? AVP_FLAGS_MANDATORY : 0; -+ if (vendor_id) { -+ flags |= AVP_FLAGS_VENDOR; -+ hdrlen = sizeof(*avp); -+ avp->vendor_id = host_to_be32(vendor_id); -+ } else { -+ hdrlen = sizeof(struct ttls_avp); -+ } -+ -+ avp->avp_code = host_to_be32(avp_code); -+ avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len)); -+ -+ return avphdr + hdrlen; -+} -+ -+ -+static struct wpabuf * eap_ttls_avp_encapsulate(struct wpabuf *resp, -+ u32 avp_code, int mandatory) -+{ -+ struct wpabuf *avp; -+ u8 *pos; -+ -+ avp = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(resp) + 4); -+ if (avp == NULL) { -+ wpabuf_free(resp); -+ return NULL; -+ } -+ -+ pos = eap_ttls_avp_hdr(wpabuf_mhead(avp), avp_code, 0, mandatory, -+ wpabuf_len(resp)); -+ os_memcpy(pos, wpabuf_head(resp), wpabuf_len(resp)); -+ pos += wpabuf_len(resp); -+ AVP_PAD((const u8 *) wpabuf_head(avp), pos); -+ wpabuf_free(resp); -+ wpabuf_put(avp, pos - (u8 *) wpabuf_head(avp)); -+ return avp; -+} -+ -+ -+struct eap_ttls_avp { -+ /* Note: eap is allocated memory; caller is responsible for freeing -+ * it. All the other pointers are pointing to the packet data, i.e., -+ * they must not be freed separately. */ -+ u8 *eap; -+ size_t eap_len; -+ u8 *user_name; -+ size_t user_name_len; -+ u8 *user_password; -+ size_t user_password_len; -+ u8 *chap_challenge; -+ size_t chap_challenge_len; -+ u8 *chap_password; -+ size_t chap_password_len; -+ u8 *mschap_challenge; -+ size_t mschap_challenge_len; -+ u8 *mschap_response; -+ size_t mschap_response_len; -+ u8 *mschap2_response; -+ size_t mschap2_response_len; -+}; -+ -+ -+static int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse) -+{ -+ struct ttls_avp *avp; -+ u8 *pos; -+ int left; -+ -+ pos = wpabuf_mhead(buf); -+ left = wpabuf_len(buf); -+ os_memset(parse, 0, sizeof(*parse)); -+ -+ while (left > 0) { -+ u32 avp_code, avp_length, vendor_id = 0; -+ u8 avp_flags, *dpos; -+ size_t pad, dlen; -+ avp = (struct ttls_avp *) pos; -+ avp_code = be_to_host32(avp->avp_code); -+ avp_length = be_to_host32(avp->avp_length); -+ avp_flags = (avp_length >> 24) & 0xff; -+ avp_length &= 0xffffff; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x " -+ "length=%d", (int) avp_code, avp_flags, -+ (int) avp_length); -+ if ((int) avp_length > left) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow " -+ "(len=%d, left=%d) - dropped", -+ (int) avp_length, left); -+ goto fail; -+ } -+ if (avp_length < sizeof(*avp)) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length " -+ "%d", avp_length); -+ goto fail; -+ } -+ dpos = (u8 *) (avp + 1); -+ dlen = avp_length - sizeof(*avp); -+ if (avp_flags & AVP_FLAGS_VENDOR) { -+ if (dlen < 4) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: vendor AVP " -+ "underflow"); -+ goto fail; -+ } -+ vendor_id = be_to_host32(* (be32 *) dpos); -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d", -+ (int) vendor_id); -+ dpos += 4; -+ dlen -= 4; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen); -+ -+ if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message"); -+ if (parse->eap == NULL) { -+ parse->eap = os_malloc(dlen); -+ if (parse->eap == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: " -+ "failed to allocate memory " -+ "for Phase 2 EAP data"); -+ goto fail; -+ } -+ os_memcpy(parse->eap, dpos, dlen); -+ parse->eap_len = dlen; -+ } else { -+ u8 *neweap = os_realloc(parse->eap, -+ parse->eap_len + dlen); -+ if (neweap == NULL) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: " -+ "failed to allocate memory " -+ "for Phase 2 EAP data"); -+ goto fail; -+ } -+ os_memcpy(neweap + parse->eap_len, dpos, dlen); -+ parse->eap = neweap; -+ parse->eap_len += dlen; -+ } -+ } else if (vendor_id == 0 && -+ avp_code == RADIUS_ATTR_USER_NAME) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: User-Name", -+ dpos, dlen); -+ parse->user_name = dpos; -+ parse->user_name_len = dlen; -+ } else if (vendor_id == 0 && -+ avp_code == RADIUS_ATTR_USER_PASSWORD) { -+ u8 *password = dpos; -+ size_t password_len = dlen; -+ while (password_len > 0 && -+ password[password_len - 1] == '\0') { -+ password_len--; -+ } -+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: " -+ "User-Password (PAP)", -+ password, password_len); -+ parse->user_password = password; -+ parse->user_password_len = password_len; -+ } else if (vendor_id == 0 && -+ avp_code == RADIUS_ATTR_CHAP_CHALLENGE) { -+ wpa_hexdump(MSG_DEBUG, -+ "EAP-TTLS: CHAP-Challenge (CHAP)", -+ dpos, dlen); -+ parse->chap_challenge = dpos; -+ parse->chap_challenge_len = dlen; -+ } else if (vendor_id == 0 && -+ avp_code == RADIUS_ATTR_CHAP_PASSWORD) { -+ wpa_hexdump(MSG_DEBUG, -+ "EAP-TTLS: CHAP-Password (CHAP)", -+ dpos, dlen); -+ parse->chap_password = dpos; -+ parse->chap_password_len = dlen; -+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && -+ avp_code == RADIUS_ATTR_MS_CHAP_CHALLENGE) { -+ wpa_hexdump(MSG_DEBUG, -+ "EAP-TTLS: MS-CHAP-Challenge", -+ dpos, dlen); -+ parse->mschap_challenge = dpos; -+ parse->mschap_challenge_len = dlen; -+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && -+ avp_code == RADIUS_ATTR_MS_CHAP_RESPONSE) { -+ wpa_hexdump(MSG_DEBUG, -+ "EAP-TTLS: MS-CHAP-Response (MSCHAP)", -+ dpos, dlen); -+ parse->mschap_response = dpos; -+ parse->mschap_response_len = dlen; -+ } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT && -+ avp_code == RADIUS_ATTR_MS_CHAP2_RESPONSE) { -+ wpa_hexdump(MSG_DEBUG, -+ "EAP-TTLS: MS-CHAP2-Response (MSCHAPV2)", -+ dpos, dlen); -+ parse->mschap2_response = dpos; -+ parse->mschap2_response_len = dlen; -+ } else if (avp_flags & AVP_FLAGS_MANDATORY) { -+ wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported " -+ "mandatory AVP code %d vendor_id %d - " -+ "dropped", (int) avp_code, (int) vendor_id); -+ goto fail; -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported " -+ "AVP code %d vendor_id %d", -+ (int) avp_code, (int) vendor_id); -+ } -+ -+ pad = (4 - (avp_length & 3)) & 3; -+ pos += avp_length + pad; -+ left -= avp_length + pad; -+ } -+ -+ return 0; -+ -+fail: -+ os_free(parse->eap); -+ parse->eap = NULL; -+ return -1; -+} -+ -+ -+static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, -+ struct eap_ttls_data *data, size_t len) -+{ -+ struct tls_keys keys; -+ u8 *challenge, *rnd; -+ -+ if (data->ttls_version == 0) { -+ return eap_server_tls_derive_key(sm, &data->ssl, -+ "ttls challenge", len); -+ } -+ -+ os_memset(&keys, 0, sizeof(keys)); -+ if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || -+ keys.client_random == NULL || keys.server_random == NULL || -+ keys.inner_secret == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " -+ "client random, or server random to derive " -+ "implicit challenge"); -+ return NULL; -+ } -+ -+ rnd = os_malloc(keys.client_random_len + keys.server_random_len); -+ challenge = os_malloc(len); -+ if (rnd == NULL || challenge == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " -+ "challenge derivation"); -+ os_free(rnd); -+ os_free(challenge); -+ return NULL; -+ } -+ os_memcpy(rnd, keys.server_random, keys.server_random_len); -+ os_memcpy(rnd + keys.server_random_len, keys.client_random, -+ keys.client_random_len); -+ -+ if (tls_prf(keys.inner_secret, keys.inner_secret_len, -+ "inner application challenge", rnd, -+ keys.client_random_len + keys.server_random_len, -+ challenge, len)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " -+ "challenge"); -+ os_free(rnd); -+ os_free(challenge); -+ return NULL; -+ } -+ -+ os_free(rnd); -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", -+ challenge, len); -+ -+ return challenge; -+} -+ -+ -+static void * eap_ttls_init(struct eap_sm *sm) -+{ -+ struct eap_ttls_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->ttls_version = EAP_TTLS_VERSION; -+ data->force_version = -1; -+ if (sm->user && sm->user->force_version >= 0) { -+ data->force_version = sm->user->force_version; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d", -+ data->force_version); -+ data->ttls_version = data->force_version; -+ } -+ data->state = START; -+ -+ if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && -+ data->ttls_version > 0) { -+ if (data->force_version > 0) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " -+ "TLS library does not support TLS/IA.", -+ data->force_version); -+ eap_ttls_reset(sm, data); -+ return NULL; -+ } -+ data->ttls_version = 0; -+ } -+ -+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); -+ eap_ttls_reset(sm, data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+static void eap_ttls_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ if (data == NULL) -+ return; -+ if (data->phase2_priv && data->phase2_method) -+ data->phase2_method->reset(sm, data->phase2_priv); -+ eap_server_tls_ssl_deinit(sm, &data->ssl); -+ wpabuf_free(data->pending_phase2_eap_resp); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_ttls_build_start(struct eap_sm *sm, -+ struct eap_ttls_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, 1, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to allocate memory for" -+ " request"); -+ eap_ttls_state(data, FAILURE); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->ttls_version); -+ -+ eap_ttls_state(data, PHASE1); -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_ttls_build_phase2_eap_req( -+ struct eap_sm *sm, struct eap_ttls_data *data, u8 id) -+{ -+ struct wpabuf *buf, *encr_req; -+ -+ -+ buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); -+ if (buf == NULL) -+ return NULL; -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, -+ "EAP-TTLS/EAP: Encapsulate Phase 2 data", buf); -+ -+ buf = eap_ttls_avp_encapsulate(buf, RADIUS_ATTR_EAP_MESSAGE, 1); -+ if (buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Failed to encapsulate " -+ "packet"); -+ return NULL; -+ } -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated " -+ "Phase 2 data", buf); -+ -+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); -+ wpabuf_free(buf); -+ -+ return encr_req; -+} -+ -+ -+static struct wpabuf * eap_ttls_build_phase2_mschapv2( -+ struct eap_sm *sm, struct eap_ttls_data *data) -+{ -+ struct wpabuf *encr_req, msgbuf; -+ u8 *req, *pos, *end; -+ int ret; -+ -+ pos = req = os_malloc(100); -+ if (req == NULL) -+ return NULL; -+ end = req + 100; -+ -+ if (data->mschapv2_resp_ok) { -+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS, -+ RADIUS_VENDOR_ID_MICROSOFT, 1, 43); -+ *pos++ = data->mschapv2_ident; -+ ret = os_snprintf((char *) pos, end - pos, "S="); -+ if (ret >= 0 && ret < end - pos) -+ pos += ret; -+ pos += wpa_snprintf_hex_uppercase( -+ (char *) pos, end - pos, data->mschapv2_auth_response, -+ sizeof(data->mschapv2_auth_response)); -+ } else { -+ pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR, -+ RADIUS_VENDOR_ID_MICROSOFT, 1, 6); -+ os_memcpy(pos, "Failed", 6); -+ pos += 6; -+ AVP_PAD(req, pos); -+ } -+ -+ wpabuf_set(&msgbuf, req, pos - req); -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " -+ "data", &msgbuf); -+ -+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); -+ os_free(req); -+ -+ return encr_req; -+} -+ -+ -+static struct wpabuf * eap_ttls_build_phase_finished( -+ struct eap_sm *sm, struct eap_ttls_data *data, int final) -+{ -+ return tls_connection_ia_send_phase_finished(sm->ssl_ctx, -+ data->ssl.conn, final); -+} -+ -+ -+static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_ttls_data *data = priv; -+ -+ if (data->ssl.state == FRAG_ACK) { -+ return eap_server_tls_build_ack(id, EAP_TYPE_TTLS, -+ data->ttls_version); -+ } -+ -+ if (data->ssl.state == WAIT_FRAG_ACK) { -+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, -+ data->ttls_version, id); -+ } -+ -+ switch (data->state) { -+ case START: -+ return eap_ttls_build_start(sm, data, id); -+ case PHASE1: -+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, " -+ "starting Phase2"); -+ eap_ttls_state(data, PHASE2_START); -+ } -+ break; -+ case PHASE2_METHOD: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_ttls_build_phase2_eap_req(sm, data, -+ id); -+ break; -+ case PHASE2_MSCHAPV2_RESP: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data); -+ break; -+ case PHASE_FINISHED: -+ wpabuf_free(data->ssl.tls_out); -+ data->ssl.tls_out_pos = 0; -+ data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", -+ __func__, data->state); -+ return NULL; -+ } -+ -+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS, -+ data->ttls_version, id); -+} -+ -+ -+static Boolean eap_ttls_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ const u8 *key, size_t key_len) -+{ -+ u8 *buf; -+ size_t buf_len; -+ int ret; -+ -+ if (key) { -+ buf_len = 2 + key_len; -+ buf = os_malloc(buf_len); -+ if (buf == NULL) -+ return -1; -+ WPA_PUT_BE16(buf, key_len); -+ os_memcpy(buf + 2, key, key_len); -+ } else { -+ buf = NULL; -+ buf_len = 0; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " -+ "secret permutation", buf, buf_len); -+ ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, -+ data->ssl.conn, -+ buf, buf_len); -+ os_free(buf); -+ -+ return ret; -+} -+ -+ -+static void eap_ttls_process_phase2_pap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ const u8 *user_password, -+ size_t user_password_len) -+{ -+ if (!sm->user || !sm->user->password || sm->user->password_hash || -+ !(sm->user->ttls_auth & EAP_TTLS_AUTH_PAP)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No plaintext user " -+ "password configured"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (sm->user->password_len != user_password_len || -+ os_memcmp(sm->user->password, user_password, user_password_len) != -+ 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password"); -+ eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : -+ SUCCESS); -+} -+ -+ -+static void eap_ttls_process_phase2_chap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ const u8 *challenge, -+ size_t challenge_len, -+ const u8 *password, -+ size_t password_len) -+{ -+ u8 *chal, hash[CHAP_MD5_LEN]; -+ -+ if (challenge == NULL || password == NULL || -+ challenge_len != EAP_TTLS_CHAP_CHALLENGE_LEN || -+ password_len != 1 + EAP_TTLS_CHAP_PASSWORD_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid CHAP attributes " -+ "(challenge len %lu password len %lu)", -+ (unsigned long) challenge_len, -+ (unsigned long) password_len); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (!sm->user || !sm->user->password || sm->user->password_hash || -+ !(sm->user->ttls_auth & EAP_TTLS_AUTH_CHAP)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No plaintext user " -+ "password configured"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ chal = eap_ttls_implicit_challenge(sm, data, -+ EAP_TTLS_CHAP_CHALLENGE_LEN + 1); -+ if (chal == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate " -+ "challenge from TLS data"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 || -+ password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch"); -+ os_free(chal); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ os_free(chal); -+ -+ /* MD5(Ident + Password + Challenge) */ -+ chap_md5(password[0], sm->user->password, sm->user->password_len, -+ challenge, challenge_len, hash); -+ -+ if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password"); -+ eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : -+ SUCCESS); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password"); -+ eap_ttls_state(data, FAILURE); -+ } -+} -+ -+ -+static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ u8 *challenge, size_t challenge_len, -+ u8 *response, size_t response_len) -+{ -+ u8 *chal, nt_response[24]; -+ -+ if (challenge == NULL || response == NULL || -+ challenge_len != EAP_TTLS_MSCHAP_CHALLENGE_LEN || -+ response_len != EAP_TTLS_MSCHAP_RESPONSE_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid MS-CHAP " -+ "attributes (challenge len %lu response len %lu)", -+ (unsigned long) challenge_len, -+ (unsigned long) response_len); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (!sm->user || !sm->user->password || -+ !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAP)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: No user password " -+ "configured"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ chal = eap_ttls_implicit_challenge(sm, data, -+ EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); -+ if (chal == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate " -+ "challenge from TLS data"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 || -+ response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch"); -+ os_free(chal); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ os_free(chal); -+ -+ if (sm->user->password_hash) -+ challenge_response(challenge, sm->user->password, nt_response); -+ else -+ nt_challenge_response(challenge, sm->user->password, -+ sm->user->password_len, nt_response); -+ -+ if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response"); -+ eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED : -+ SUCCESS); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received", -+ response + 2 + 24, 24); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Expected", -+ nt_response, 24); -+ eap_ttls_state(data, FAILURE); -+ } -+} -+ -+ -+static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ u8 *challenge, -+ size_t challenge_len, -+ u8 *response, size_t response_len) -+{ -+ u8 *chal, *username, nt_response[24], *rx_resp, *peer_challenge, -+ *auth_challenge; -+ size_t username_len, i; -+ -+ if (challenge == NULL || response == NULL || -+ challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN || -+ response_len != EAP_TTLS_MSCHAPV2_RESPONSE_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid MS-CHAP2 " -+ "attributes (challenge len %lu response len %lu)", -+ (unsigned long) challenge_len, -+ (unsigned long) response_len); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (!sm->user || !sm->user->password || -+ !(sm->user->ttls_auth & EAP_TTLS_AUTH_MSCHAPV2)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user password " -+ "configured"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ /* MSCHAPv2 does not include optional domain name in the -+ * challenge-response calculation, so remove domain prefix -+ * (if present). */ -+ username = sm->identity; -+ username_len = sm->identity_len; -+ for (i = 0; i < username_len; i++) { -+ if (username[i] == '\\') { -+ username_len -= i + 1; -+ username += i + 1; -+ break; -+ } -+ } -+ -+ chal = eap_ttls_implicit_challenge( -+ sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1); -+ if (chal == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate " -+ "challenge from TLS data"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 || -+ response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch"); -+ os_free(chal); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ os_free(chal); -+ -+ auth_challenge = challenge; -+ peer_challenge = response + 2; -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: User", -+ username, username_len); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: auth_challenge", -+ auth_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge", -+ peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); -+ -+ if (sm->user->password_hash) { -+ generate_nt_response_pwhash(auth_challenge, peer_challenge, -+ username, username_len, -+ sm->user->password, -+ nt_response); -+ } else { -+ generate_nt_response(auth_challenge, peer_challenge, -+ username, username_len, -+ sm->user->password, -+ sm->user->password_len, -+ nt_response); -+ } -+ -+ rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8; -+ if (os_memcmp(nt_response, rx_resp, 24) == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct " -+ "NT-Response"); -+ data->mschapv2_resp_ok = 1; -+ if (data->ttls_version > 0) { -+ const u8 *pw_hash; -+ u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16]; -+ u8 session_key[2 * MSCHAPV2_KEY_LEN]; -+ -+ if (sm->user->password_hash) -+ pw_hash = sm->user->password; -+ else { -+ nt_password_hash(sm->user->password, -+ sm->user->password_len, -+ pw_hash_buf); -+ pw_hash = pw_hash_buf; -+ } -+ hash_nt_password_hash(pw_hash, pw_hash_hash); -+ get_master_key(pw_hash_hash, nt_response, master_key); -+ get_asymetric_start_key(master_key, session_key, -+ MSCHAPV2_KEY_LEN, 0, 0); -+ get_asymetric_start_key(master_key, -+ session_key + MSCHAPV2_KEY_LEN, -+ MSCHAPV2_KEY_LEN, 1, 0); -+ eap_ttls_ia_permute_inner_secret(sm, data, -+ session_key, -+ sizeof(session_key)); -+ } -+ -+ if (sm->user->password_hash) { -+ generate_authenticator_response_pwhash( -+ sm->user->password, -+ peer_challenge, auth_challenge, -+ username, username_len, nt_response, -+ data->mschapv2_auth_response); -+ } else { -+ generate_authenticator_response( -+ sm->user->password, sm->user->password_len, -+ peer_challenge, auth_challenge, -+ username, username_len, nt_response, -+ data->mschapv2_auth_response); -+ } -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid " -+ "NT-Response"); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Received", -+ rx_resp, 24); -+ wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: Expected", -+ nt_response, 24); -+ data->mschapv2_resp_ok = 0; -+ } -+ eap_ttls_state(data, PHASE2_MSCHAPV2_RESP); -+ data->mschapv2_ident = response[0]; -+} -+ -+ -+static int eap_ttls_phase2_eap_init(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ EapType eap_type) -+{ -+ if (data->phase2_priv && data->phase2_method) { -+ data->phase2_method->reset(sm, data->phase2_priv); -+ data->phase2_method = NULL; -+ data->phase2_priv = NULL; -+ } -+ data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, -+ eap_type); -+ if (!data->phase2_method) -+ return -1; -+ -+ sm->init_phase2 = 1; -+ data->phase2_priv = data->phase2_method->init(sm); -+ sm->init_phase2 = 0; -+ return data->phase2_priv == NULL ? -1 : 0; -+} -+ -+ -+static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ u8 *in_data, size_t in_len) -+{ -+ u8 next_type = EAP_TYPE_NONE; -+ struct eap_hdr *hdr; -+ u8 *pos; -+ size_t left; -+ struct wpabuf buf; -+ const struct eap_method *m = data->phase2_method; -+ void *priv = data->phase2_priv; -+ -+ if (priv == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not " -+ "initialized?!", __func__); -+ return; -+ } -+ -+ hdr = (struct eap_hdr *) in_data; -+ pos = (u8 *) (hdr + 1); -+ -+ if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { -+ left = in_len - sizeof(*hdr); -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; " -+ "allowed types", pos + 1, left - 1); -+ eap_sm_process_nak(sm, pos + 1, left - 1); -+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && -+ sm->user->methods[sm->user_eap_method_index].method != -+ EAP_TYPE_NONE) { -+ next_type = sm->user->methods[ -+ sm->user_eap_method_index++].method; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", -+ next_type); -+ if (eap_ttls_phase2_eap_init(sm, data, next_type)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to " -+ "initialize EAP type %d", -+ next_type); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ } else { -+ eap_ttls_state(data, FAILURE); -+ } -+ return; -+ } -+ -+ wpabuf_set(&buf, in_data, in_len); -+ -+ if (m->check(sm, priv, &buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to " -+ "ignore the packet"); -+ return; -+ } -+ -+ m->process(sm, priv, &buf); -+ -+ if (sm->method_pending == METHOD_PENDING_WAIT) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method is in " -+ "pending wait state - save decrypted response"); -+ wpabuf_free(data->pending_phase2_eap_resp); -+ data->pending_phase2_eap_resp = wpabuf_dup(&buf); -+ } -+ -+ if (!m->isDone(sm, priv)) -+ return; -+ -+ if (!m->isSuccess(sm, priv)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ switch (data->state) { -+ case PHASE2_START: -+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP_TTLS: Phase2 " -+ "Identity not found in the user " -+ "database", -+ sm->identity, sm->identity_len); -+ eap_ttls_state(data, FAILURE); -+ break; -+ } -+ -+ eap_ttls_state(data, PHASE2_METHOD); -+ next_type = sm->user->methods[0].method; -+ sm->user_eap_method_index = 1; -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type); -+ if (eap_ttls_phase2_eap_init(sm, data, next_type)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize " -+ "EAP type %d", next_type); -+ eap_ttls_state(data, FAILURE); -+ } -+ break; -+ case PHASE2_METHOD: -+ if (data->ttls_version > 0) { -+ if (m->getKey) { -+ u8 *key; -+ size_t key_len; -+ key = m->getKey(sm, priv, &key_len); -+ eap_ttls_ia_permute_inner_secret(sm, data, -+ key, key_len); -+ } -+ eap_ttls_state(data, PHASE_FINISHED); -+ } else -+ eap_ttls_state(data, SUCCESS); -+ break; -+ case FAILURE: -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d", -+ __func__, data->state); -+ break; -+ } -+} -+ -+ -+static void eap_ttls_process_phase2_eap(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ const u8 *eap, size_t eap_len) -+{ -+ struct eap_hdr *hdr; -+ size_t len; -+ -+ if (data->state == PHASE2_START) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: initializing Phase 2"); -+ if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_IDENTITY) < 0) -+ { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: failed to " -+ "initialize EAP-Identity"); -+ return; -+ } -+ } -+ -+ if (eap_len < sizeof(*hdr)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: too short Phase 2 EAP " -+ "packet (len=%lu)", (unsigned long) eap_len); -+ return; -+ } -+ -+ hdr = (struct eap_hdr *) eap; -+ len = be_to_host16(hdr->length); -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: received Phase 2 EAP: code=%d " -+ "identifier=%d length=%lu", hdr->code, hdr->identifier, -+ (unsigned long) len); -+ if (len > eap_len) { -+ wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Length mismatch in Phase 2" -+ " EAP frame (hdr len=%lu, data len in AVP=%lu)", -+ (unsigned long) len, (unsigned long) eap_len); -+ return; -+ } -+ -+ switch (hdr->code) { -+ case EAP_CODE_RESPONSE: -+ eap_ttls_process_phase2_eap_response(sm, data, (u8 *) hdr, -+ len); -+ break; -+ default: -+ wpa_printf(MSG_INFO, "EAP-TTLS/EAP: Unexpected code=%d in " -+ "Phase 2 EAP header", hdr->code); -+ break; -+ } -+} -+ -+ -+static void eap_ttls_process_phase2(struct eap_sm *sm, -+ struct eap_ttls_data *data, -+ struct wpabuf *in_buf) -+{ -+ struct wpabuf *in_decrypted; -+ struct eap_ttls_avp parse; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" -+ " Phase 2", (unsigned long) wpabuf_len(in_buf)); -+ -+ if (data->pending_phase2_eap_resp) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response " -+ "- skip decryption and use old data"); -+ eap_ttls_process_phase2_eap( -+ sm, data, wpabuf_head(data->pending_phase2_eap_resp), -+ wpabuf_len(data->pending_phase2_eap_resp)); -+ wpabuf_free(data->pending_phase2_eap_resp); -+ data->pending_phase2_eap_resp = NULL; -+ return; -+ } -+ -+ in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, -+ in_buf); -+ if (in_decrypted == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " -+ "data"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (data->state == PHASE_FINISHED) { -+ if (wpabuf_len(in_decrypted) == 0 && -+ tls_connection_ia_final_phase_finished(sm->ssl_ctx, -+ data->ssl.conn)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished " -+ "received"); -+ eap_ttls_state(data, SUCCESS); -+ } else { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid " -+ "FinalPhaseFinished"); -+ eap_ttls_state(data, FAILURE); -+ } -+ -+ wpabuf_free(in_decrypted); -+ return; -+ } -+ -+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", -+ in_decrypted); -+ -+ if (eap_ttls_avp_parse(in_decrypted, &parse) < 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs"); -+ wpabuf_free(in_decrypted); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ if (parse.user_name) { -+ os_free(sm->identity); -+ sm->identity = os_malloc(parse.user_name_len); -+ if (sm->identity) { -+ os_memcpy(sm->identity, parse.user_name, -+ parse.user_name_len); -+ sm->identity_len = parse.user_name_len; -+ } -+ if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1) -+ != 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not " -+ "found in the user database"); -+ eap_ttls_state(data, FAILURE); -+ goto done; -+ } -+ } -+ -+#ifdef EAP_SERVER_TNC -+ if (data->tnc_started && parse.eap == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP " -+ "response from peer"); -+ eap_ttls_state(data, FAILURE); -+ goto done; -+ } -+#endif /* EAP_SERVER_TNC */ -+ -+ if (parse.eap) { -+ eap_ttls_process_phase2_eap(sm, data, parse.eap, -+ parse.eap_len); -+ } else if (parse.user_password) { -+ eap_ttls_process_phase2_pap(sm, data, parse.user_password, -+ parse.user_password_len); -+ } else if (parse.chap_password) { -+ eap_ttls_process_phase2_chap(sm, data, -+ parse.chap_challenge, -+ parse.chap_challenge_len, -+ parse.chap_password, -+ parse.chap_password_len); -+ } else if (parse.mschap_response) { -+ eap_ttls_process_phase2_mschap(sm, data, -+ parse.mschap_challenge, -+ parse.mschap_challenge_len, -+ parse.mschap_response, -+ parse.mschap_response_len); -+ } else if (parse.mschap2_response) { -+ eap_ttls_process_phase2_mschapv2(sm, data, -+ parse.mschap_challenge, -+ parse.mschap_challenge_len, -+ parse.mschap2_response, -+ parse.mschap2_response_len); -+ } -+ -+done: -+ wpabuf_free(in_decrypted); -+ os_free(parse.eap); -+} -+ -+ -+static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data) -+{ -+#ifdef EAP_SERVER_TNC -+ if (!sm->tnc || data->state != SUCCESS || data->tnc_started) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC"); -+ if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC"); -+ eap_ttls_state(data, FAILURE); -+ return; -+ } -+ -+ data->tnc_started = 1; -+ eap_ttls_state(data, PHASE2_METHOD); -+#endif /* EAP_SERVER_TNC */ -+} -+ -+ -+static int eap_ttls_process_version(struct eap_sm *sm, void *priv, -+ int peer_version) -+{ -+ struct eap_ttls_data *data = priv; -+ if (peer_version < data->ttls_version) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; " -+ "use version %d", -+ peer_version, data->ttls_version, peer_version); -+ data->ttls_version = peer_version; -+ } -+ -+ if (data->ttls_version > 0 && !data->tls_ia_configured) { -+ if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable " -+ "TLS/IA"); -+ return -1; -+ } -+ data->tls_ia_configured = 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_ttls_process_msg(struct eap_sm *sm, void *priv, -+ const struct wpabuf *respData) -+{ -+ struct eap_ttls_data *data = priv; -+ -+ switch (data->state) { -+ case PHASE1: -+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) -+ eap_ttls_state(data, FAILURE); -+ break; -+ case PHASE2_START: -+ case PHASE2_METHOD: -+ case PHASE_FINISHED: -+ eap_ttls_process_phase2(sm, data, data->ssl.tls_in); -+ eap_ttls_start_tnc(sm, data); -+ break; -+ case PHASE2_MSCHAPV2_RESP: -+ if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.tls_in) == -+ 0) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " -+ "acknowledged response"); -+ eap_ttls_state(data, data->ttls_version > 0 ? -+ PHASE_FINISHED : SUCCESS); -+ } else if (!data->mschapv2_resp_ok) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer " -+ "acknowledged error"); -+ eap_ttls_state(data, FAILURE); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected " -+ "frame from peer (payload len %lu, " -+ "expected empty frame)", -+ (unsigned long) -+ wpabuf_len(data->ssl.tls_in)); -+ eap_ttls_state(data, FAILURE); -+ } -+ eap_ttls_start_tnc(sm, data); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s", -+ data->state, __func__); -+ break; -+ } -+} -+ -+ -+static void eap_ttls_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_ttls_data *data = priv; -+ if (eap_server_tls_process(sm, &data->ssl, respData, data, -+ EAP_TYPE_TTLS, eap_ttls_process_version, -+ eap_ttls_process_msg) < 0) -+ eap_ttls_state(data, FAILURE); -+} -+ -+ -+static Boolean eap_ttls_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ return data->state == SUCCESS || data->state == FAILURE; -+} -+ -+ -+static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm, -+ struct eap_ttls_data *data) -+{ -+ struct tls_keys keys; -+ u8 *rnd, *key; -+ -+ os_memset(&keys, 0, sizeof(keys)); -+ if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || -+ keys.client_random == NULL || keys.server_random == NULL || -+ keys.inner_secret == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " -+ "client random, or server random to derive keying " -+ "material"); -+ return NULL; -+ } -+ -+ rnd = os_malloc(keys.client_random_len + keys.server_random_len); -+ key = os_malloc(EAP_TLS_KEY_LEN); -+ if (rnd == NULL || key == NULL) { -+ wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); -+ os_free(rnd); -+ os_free(key); -+ return NULL; -+ } -+ os_memcpy(rnd, keys.client_random, keys.client_random_len); -+ os_memcpy(rnd + keys.client_random_len, keys.server_random, -+ keys.server_random_len); -+ -+ if (tls_prf(keys.inner_secret, keys.inner_secret_len, -+ "ttls v1 keying material", rnd, keys.client_random_len + -+ keys.server_random_len, key, EAP_TLS_KEY_LEN)) { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); -+ os_free(rnd); -+ os_free(key); -+ return NULL; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", -+ rnd, keys.client_random_len + keys.server_random_len); -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", -+ keys.inner_secret, keys.inner_secret_len); -+ -+ os_free(rnd); -+ -+ return key; -+} -+ -+ -+static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_ttls_data *data = priv; -+ u8 *eapKeyData; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ if (data->ttls_version == 0) { -+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, -+ "ttls keying material", -+ EAP_TLS_KEY_LEN); -+ } else { -+ eapKeyData = eap_ttls_v1_derive_key(sm, data); -+ } -+ -+ if (eapKeyData) { -+ *len = EAP_TLS_KEY_LEN; -+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", -+ eapKeyData, EAP_TLS_KEY_LEN); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); -+ } -+ -+ return eapKeyData; -+} -+ -+ -+static Boolean eap_ttls_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_ttls_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_ttls_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_ttls_init; -+ eap->reset = eap_ttls_reset; -+ eap->buildReq = eap_ttls_buildReq; -+ eap->check = eap_ttls_check; -+ eap->process = eap_ttls_process; -+ eap->isDone = eap_ttls_isDone; -+ eap->getKey = eap_ttls_getKey; -+ eap->isSuccess = eap_ttls_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_vendor_test.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_vendor_test.c -new file mode 100644 -index 0000000000000..0dd0aca911b4d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_vendor_test.c -@@ -0,0 +1,198 @@ -+/* -+ * hostapd / Test method for vendor specific (expanded) EAP type -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_i.h" -+ -+ -+#define EAP_VENDOR_ID 0xfffefd -+#define EAP_VENDOR_TYPE 0xfcfbfaf9 -+ -+ -+struct eap_vendor_test_data { -+ enum { INIT, CONFIRM, SUCCESS, FAILURE } state; -+}; -+ -+ -+static const char * eap_vendor_test_state_txt(int state) -+{ -+ switch (state) { -+ case INIT: -+ return "INIT"; -+ case CONFIRM: -+ return "CONFIRM"; -+ case SUCCESS: -+ return "SUCCESS"; -+ case FAILURE: -+ return "FAILURE"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+static void eap_vendor_test_state(struct eap_vendor_test_data *data, -+ int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: %s -> %s", -+ eap_vendor_test_state_txt(data->state), -+ eap_vendor_test_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void * eap_vendor_test_init(struct eap_sm *sm) -+{ -+ struct eap_vendor_test_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = INIT; -+ -+ return data; -+} -+ -+ -+static void eap_vendor_test_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_vendor_test_data *data = priv; -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv, -+ u8 id) -+{ -+ struct eap_vendor_test_data *data = priv; -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, 1, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-VENDOR-TEST: Failed to allocate " -+ "memory for request"); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, data->state == INIT ? 1 : 3); -+ -+ return req; -+} -+ -+ -+static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len); -+ if (pos == NULL || len < 1) { -+ wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static void eap_vendor_test_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_vendor_test_data *data = priv; -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respData, &len); -+ if (pos == NULL || len < 1) -+ return; -+ -+ if (data->state == INIT) { -+ if (*pos == 2) -+ eap_vendor_test_state(data, CONFIRM); -+ else -+ eap_vendor_test_state(data, FAILURE); -+ } else if (data->state == CONFIRM) { -+ if (*pos == 4) -+ eap_vendor_test_state(data, SUCCESS); -+ else -+ eap_vendor_test_state(data, FAILURE); -+ } else -+ eap_vendor_test_state(data, FAILURE); -+} -+ -+ -+static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_vendor_test_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len) -+{ -+ struct eap_vendor_test_data *data = priv; -+ u8 *key; -+ const int key_len = 64; -+ -+ if (data->state != SUCCESS) -+ return NULL; -+ -+ key = os_malloc(key_len); -+ if (key == NULL) -+ return NULL; -+ -+ os_memset(key, 0x11, key_len / 2); -+ os_memset(key + key_len / 2, 0x22, key_len / 2); -+ *len = key_len; -+ -+ return key; -+} -+ -+ -+static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ struct eap_vendor_test_data *data = priv; -+ return data->state == SUCCESS; -+} -+ -+ -+int eap_server_vendor_test_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_ID, EAP_VENDOR_TYPE, -+ "VENDOR-TEST"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_vendor_test_init; -+ eap->reset = eap_vendor_test_reset; -+ eap->buildReq = eap_vendor_test_buildReq; -+ eap->check = eap_vendor_test_check; -+ eap->process = eap_vendor_test_process; -+ eap->isDone = eap_vendor_test_isDone; -+ eap->getKey = eap_vendor_test_getKey; -+ eap->isSuccess = eap_vendor_test_isSuccess; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_wsc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_wsc.c -new file mode 100644 -index 0000000000000..e944a4d437273 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_server_wsc.c -@@ -0,0 +1,517 @@ -+/* -+ * EAP-WSC server for Wi-Fi Protected Setup -+ * Copyright (c) 2007-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "eap_i.h" -+#include "eap_common/eap_wsc_common.h" -+#include "p2p/p2p.h" -+#include "wps/wps.h" -+ -+ -+struct eap_wsc_data { -+ enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; -+ int registrar; -+ struct wpabuf *in_buf; -+ struct wpabuf *out_buf; -+ enum wsc_op_code in_op_code, out_op_code; -+ size_t out_used; -+ size_t fragment_size; -+ struct wps_data *wps; -+ int ext_reg_timeout; -+}; -+ -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+static const char * eap_wsc_state_txt(int state) -+{ -+ switch (state) { -+ case START: -+ return "START"; -+ case MESG: -+ return "MESG"; -+ case FRAG_ACK: -+ return "FRAG_ACK"; -+ case WAIT_FRAG_ACK: -+ return "WAIT_FRAG_ACK"; -+ case DONE: -+ return "DONE"; -+ case FAIL: -+ return "FAIL"; -+ default: -+ return "?"; -+ } -+} -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+static void eap_wsc_state(struct eap_wsc_data *data, int state) -+{ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", -+ eap_wsc_state_txt(data->state), -+ eap_wsc_state_txt(state)); -+ data->state = state; -+} -+ -+ -+static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct eap_sm *sm = eloop_ctx; -+ struct eap_wsc_data *data = timeout_ctx; -+ -+ if (sm->method_pending != METHOD_PENDING_WAIT) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External " -+ "Registrar"); -+ data->ext_reg_timeout = 1; -+ eap_sm_pending_cb(sm); -+} -+ -+ -+static void * eap_wsc_init(struct eap_sm *sm) -+{ -+ struct eap_wsc_data *data; -+ int registrar; -+ struct wps_config cfg; -+ -+ if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN && -+ os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == -+ 0) -+ registrar = 0; /* Supplicant is Registrar */ -+ else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN && -+ os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) -+ == 0) -+ registrar = 1; /* Supplicant is Enrollee */ -+ else { -+ wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", -+ sm->identity, sm->identity_len); -+ return NULL; -+ } -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ data->state = registrar ? START : MESG; -+ data->registrar = registrar; -+ -+ os_memset(&cfg, 0, sizeof(cfg)); -+ cfg.wps = sm->wps; -+ cfg.registrar = registrar; -+ if (registrar) { -+ if (sm->wps == NULL || sm->wps->registrar == NULL) { -+ wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not " -+ "initialized"); -+ os_free(data); -+ return NULL; -+ } -+ } else { -+ if (sm->user == NULL || sm->user->password == NULL) { -+ /* -+ * In theory, this should not really be needed, but -+ * Windows 7 uses Registrar mode to probe AP's WPS -+ * capabilities before trying to use Enrollee and fails -+ * if the AP does not allow that probing to happen.. -+ */ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) " -+ "configured for Enrollee functionality - " -+ "allow for probing capabilities (M1)"); -+ } else { -+ cfg.pin = sm->user->password; -+ cfg.pin_len = sm->user->password_len; -+ } -+ } -+ cfg.assoc_wps_ie = sm->assoc_wps_ie; -+ cfg.peer_addr = sm->peer_addr; -+#ifdef CONFIG_P2P -+ if (sm->assoc_p2p_ie) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P " -+ "client"); -+ cfg.use_psk_key = 1; -+ cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); -+ } -+#endif /* CONFIG_P2P */ -+ data->wps = wps_init(&cfg); -+ if (data->wps == NULL) { -+ os_free(data); -+ return NULL; -+ } -+ data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : -+ WSC_FRAGMENT_SIZE; -+ -+ return data; -+} -+ -+ -+static void eap_wsc_reset(struct eap_sm *sm, void *priv) -+{ -+ struct eap_wsc_data *data = priv; -+ eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); -+ wpabuf_free(data->in_buf); -+ wpabuf_free(data->out_buf); -+ wps_deinit(data->wps); -+ os_free(data); -+} -+ -+ -+static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm, -+ struct eap_wsc_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ -+ req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " -+ "request"); -+ return NULL; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start"); -+ wpabuf_put_u8(req, WSC_Start); /* Op-Code */ -+ wpabuf_put_u8(req, 0); /* Flags */ -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id) -+{ -+ struct wpabuf *req; -+ u8 flags; -+ size_t send_len, plen; -+ -+ flags = 0; -+ send_len = wpabuf_len(data->out_buf) - data->out_used; -+ if (2 + send_len > data->fragment_size) { -+ send_len = data->fragment_size - 2; -+ flags |= WSC_FLAGS_MF; -+ if (data->out_used == 0) { -+ flags |= WSC_FLAGS_LF; -+ send_len -= 2; -+ } -+ } -+ plen = 2 + send_len; -+ if (flags & WSC_FLAGS_LF) -+ plen += 2; -+ req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, -+ EAP_CODE_REQUEST, id); -+ if (req == NULL) { -+ wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " -+ "request"); -+ return NULL; -+ } -+ -+ wpabuf_put_u8(req, data->out_op_code); /* Op-Code */ -+ wpabuf_put_u8(req, flags); /* Flags */ -+ if (flags & WSC_FLAGS_LF) -+ wpabuf_put_be16(req, wpabuf_len(data->out_buf)); -+ -+ wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, -+ send_len); -+ data->out_used += send_len; -+ -+ if (data->out_used == wpabuf_len(data->out_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " -+ "(message sent completely)", -+ (unsigned long) send_len); -+ wpabuf_free(data->out_buf); -+ data->out_buf = NULL; -+ data->out_used = 0; -+ eap_wsc_state(data, MESG); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " -+ "(%lu more to send)", (unsigned long) send_len, -+ (unsigned long) wpabuf_len(data->out_buf) - -+ data->out_used); -+ eap_wsc_state(data, WAIT_FRAG_ACK); -+ } -+ -+ return req; -+} -+ -+ -+static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id) -+{ -+ struct eap_wsc_data *data = priv; -+ -+ switch (data->state) { -+ case START: -+ return eap_wsc_build_start(sm, data, id); -+ case MESG: -+ if (data->out_buf == NULL) { -+ data->out_buf = wps_get_msg(data->wps, -+ &data->out_op_code); -+ if (data->out_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to " -+ "receive message from WPS"); -+ return NULL; -+ } -+ data->out_used = 0; -+ } -+ /* pass through */ -+ case WAIT_FRAG_ACK: -+ return eap_wsc_build_msg(data, id); -+ case FRAG_ACK: -+ return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST); -+ default: -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in " -+ "buildReq", data->state); -+ return NULL; -+ } -+} -+ -+ -+static Boolean eap_wsc_check(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ const u8 *pos; -+ size_t len; -+ -+ pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, -+ respData, &len); -+ if (pos == NULL || len < 2) { -+ wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame"); -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+ -+static int eap_wsc_process_cont(struct eap_wsc_data *data, -+ const u8 *buf, size_t len, u8 op_code) -+{ -+ /* Process continuation of a pending message */ -+ if (op_code != data->in_op_code) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " -+ "fragment (expected %d)", -+ op_code, data->in_op_code); -+ eap_wsc_state(data, FAIL); -+ return -1; -+ } -+ -+ if (len > wpabuf_tailroom(data->in_buf)) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); -+ eap_wsc_state(data, FAIL); -+ return -1; -+ } -+ -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu " -+ "bytes more", (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ -+ return 0; -+} -+ -+ -+static int eap_wsc_process_fragment(struct eap_wsc_data *data, -+ u8 flags, u8 op_code, u16 message_length, -+ const u8 *buf, size_t len) -+{ -+ /* Process a fragment that is not the last one of the message */ -+ if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length " -+ "field in a fragmented packet"); -+ return -1; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* First fragment of the message */ -+ data->in_buf = wpabuf_alloc(message_length); -+ if (data->in_buf == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " -+ "message"); -+ return -1; -+ } -+ data->in_op_code = op_code; -+ wpabuf_put_data(data->in_buf, buf, len); -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in " -+ "first fragment, waiting for %lu bytes more", -+ (unsigned long) len, -+ (unsigned long) wpabuf_tailroom(data->in_buf)); -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_wsc_process(struct eap_sm *sm, void *priv, -+ struct wpabuf *respData) -+{ -+ struct eap_wsc_data *data = priv; -+ const u8 *start, *pos, *end; -+ size_t len; -+ u8 op_code, flags; -+ u16 message_length = 0; -+ enum wps_process_res res; -+ struct wpabuf tmpbuf; -+ -+ eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); -+ if (data->ext_reg_timeout) { -+ eap_wsc_state(data, FAIL); -+ return; -+ } -+ -+ pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, -+ respData, &len); -+ if (pos == NULL || len < 2) -+ return; /* Should not happen; message already verified */ -+ -+ start = pos; -+ end = start + len; -+ -+ op_code = *pos++; -+ flags = *pos++; -+ if (flags & WSC_FLAGS_LF) { -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); -+ return; -+ } -+ message_length = WPA_GET_BE16(pos); -+ pos += 2; -+ -+ if (message_length < end - pos) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " -+ "Length"); -+ return; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " -+ "Flags 0x%x Message Length %d", -+ op_code, flags, message_length); -+ -+ if (data->state == WAIT_FRAG_ACK) { -+ if (op_code != WSC_FRAG_ACK) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " -+ "in WAIT_FRAG_ACK state", op_code); -+ eap_wsc_state(data, FAIL); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); -+ eap_wsc_state(data, MESG); -+ return; -+ } -+ -+ if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && -+ op_code != WSC_Done) { -+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", -+ op_code); -+ eap_wsc_state(data, FAIL); -+ return; -+ } -+ -+ if (data->in_buf && -+ eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { -+ eap_wsc_state(data, FAIL); -+ return; -+ } -+ -+ if (flags & WSC_FLAGS_MF) { -+ if (eap_wsc_process_fragment(data, flags, op_code, -+ message_length, pos, end - pos) < -+ 0) -+ eap_wsc_state(data, FAIL); -+ else -+ eap_wsc_state(data, FRAG_ACK); -+ return; -+ } -+ -+ if (data->in_buf == NULL) { -+ /* Wrap unfragmented messages as wpabuf without extra copy */ -+ wpabuf_set(&tmpbuf, pos, end - pos); -+ data->in_buf = &tmpbuf; -+ } -+ -+ res = wps_process_msg(data->wps, op_code, data->in_buf); -+ switch (res) { -+ case WPS_DONE: -+ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " -+ "successfully - report EAP failure"); -+ eap_wsc_state(data, FAIL); -+ break; -+ case WPS_CONTINUE: -+ eap_wsc_state(data, MESG); -+ break; -+ case WPS_FAILURE: -+ wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); -+ eap_wsc_state(data, FAIL); -+ break; -+ case WPS_PENDING: -+ eap_wsc_state(data, MESG); -+ sm->method_pending = METHOD_PENDING_WAIT; -+ eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); -+ eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, -+ sm, data); -+ break; -+ } -+ -+ if (data->in_buf != &tmpbuf) -+ wpabuf_free(data->in_buf); -+ data->in_buf = NULL; -+} -+ -+ -+static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv) -+{ -+ struct eap_wsc_data *data = priv; -+ return data->state == FAIL; -+} -+ -+ -+static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv) -+{ -+ /* EAP-WSC will always result in EAP-Failure */ -+ return FALSE; -+} -+ -+ -+static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv) -+{ -+ /* Recommended retransmit times: retransmit timeout 5 seconds, -+ * per-message timeout 15 seconds, i.e., 3 tries. */ -+ sm->MaxRetrans = 2; /* total 3 attempts */ -+ return 5; -+} -+ -+ -+int eap_server_wsc_register(void) -+{ -+ struct eap_method *eap; -+ int ret; -+ -+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, -+ EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, -+ "WSC"); -+ if (eap == NULL) -+ return -1; -+ -+ eap->init = eap_wsc_init; -+ eap->reset = eap_wsc_reset; -+ eap->buildReq = eap_wsc_buildReq; -+ eap->check = eap_wsc_check; -+ eap->process = eap_wsc_process; -+ eap->isDone = eap_wsc_isDone; -+ eap->isSuccess = eap_wsc_isSuccess; -+ eap->getTimeout = eap_wsc_getTimeout; -+ -+ ret = eap_server_method_register(eap); -+ if (ret) -+ eap_server_method_free(eap); -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.c -new file mode 100644 -index 0000000000000..248b21630cfbb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.c -@@ -0,0 +1,1338 @@ -+/* -+ * hostapd / EAP-SIM database/authenticator gateway -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This is an example implementation of the EAP-SIM/AKA database/authentication -+ * gateway interface that is using an external program as an SS7 gateway to -+ * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example -+ * implementation of such a gateway program. This eap_sim_db.c takes care of -+ * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different -+ * gateway implementations for HLR/AuC access. Alternatively, it can also be -+ * completely replaced if the in-memory database of pseudonyms/re-auth -+ * identities is not suitable for some cases. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "crypto/random.h" -+#include "eap_common/eap_sim_common.h" -+#include "eap_server/eap_sim_db.h" -+#include "eloop.h" -+ -+struct eap_sim_pseudonym { -+ struct eap_sim_pseudonym *next; -+ u8 *identity; -+ size_t identity_len; -+ char *pseudonym; -+}; -+ -+struct eap_sim_db_pending { -+ struct eap_sim_db_pending *next; -+ u8 imsi[20]; -+ size_t imsi_len; -+ enum { PENDING, SUCCESS, FAILURE } state; -+ void *cb_session_ctx; -+ struct os_time timestamp; -+ int aka; -+ union { -+ struct { -+ u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; -+ u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; -+ u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; -+ int num_chal; -+ } sim; -+ struct { -+ u8 rand[EAP_AKA_RAND_LEN]; -+ u8 autn[EAP_AKA_AUTN_LEN]; -+ u8 ik[EAP_AKA_IK_LEN]; -+ u8 ck[EAP_AKA_CK_LEN]; -+ u8 res[EAP_AKA_RES_MAX_LEN]; -+ size_t res_len; -+ } aka; -+ } u; -+}; -+ -+struct eap_sim_db_data { -+ int sock; -+ char *fname; -+ char *local_sock; -+ void (*get_complete_cb)(void *ctx, void *session_ctx); -+ void *ctx; -+ struct eap_sim_pseudonym *pseudonyms; -+ struct eap_sim_reauth *reauths; -+ struct eap_sim_db_pending *pending; -+}; -+ -+ -+static struct eap_sim_db_pending * -+eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi, -+ size_t imsi_len, int aka) -+{ -+ struct eap_sim_db_pending *entry, *prev = NULL; -+ -+ entry = data->pending; -+ while (entry) { -+ if (entry->aka == aka && entry->imsi_len == imsi_len && -+ os_memcmp(entry->imsi, imsi, imsi_len) == 0) { -+ if (prev) -+ prev->next = entry->next; -+ else -+ data->pending = entry->next; -+ break; -+ } -+ prev = entry; -+ entry = entry->next; -+ } -+ return entry; -+} -+ -+ -+static void eap_sim_db_add_pending(struct eap_sim_db_data *data, -+ struct eap_sim_db_pending *entry) -+{ -+ entry->next = data->pending; -+ data->pending = entry; -+} -+ -+ -+static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data, -+ const char *imsi, char *buf) -+{ -+ char *start, *end, *pos; -+ struct eap_sim_db_pending *entry; -+ int num_chal; -+ -+ /* -+ * SIM-RESP-AUTH Kc(i):SRES(i):RAND(i) ... -+ * SIM-RESP-AUTH FAILURE -+ * (IMSI = ASCII string, Kc/SRES/RAND = hex string) -+ */ -+ -+ entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0); -+ if (entry == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " -+ "received message found"); -+ return; -+ } -+ -+ start = buf; -+ if (os_strncmp(start, "FAILURE", 7) == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " -+ "failure"); -+ entry->state = FAILURE; -+ eap_sim_db_add_pending(data, entry); -+ data->get_complete_cb(data->ctx, entry->cb_session_ctx); -+ return; -+ } -+ -+ num_chal = 0; -+ while (num_chal < EAP_SIM_MAX_CHAL) { -+ end = os_strchr(start, ' '); -+ if (end) -+ *end = '\0'; -+ -+ pos = os_strchr(start, ':'); -+ if (pos == NULL) -+ goto parse_fail; -+ *pos = '\0'; -+ if (hexstr2bin(start, entry->u.sim.kc[num_chal], -+ EAP_SIM_KC_LEN)) -+ goto parse_fail; -+ -+ start = pos + 1; -+ pos = os_strchr(start, ':'); -+ if (pos == NULL) -+ goto parse_fail; -+ *pos = '\0'; -+ if (hexstr2bin(start, entry->u.sim.sres[num_chal], -+ EAP_SIM_SRES_LEN)) -+ goto parse_fail; -+ -+ start = pos + 1; -+ if (hexstr2bin(start, entry->u.sim.rand[num_chal], -+ GSM_RAND_LEN)) -+ goto parse_fail; -+ -+ num_chal++; -+ if (end == NULL) -+ break; -+ else -+ start = end + 1; -+ } -+ entry->u.sim.num_chal = num_chal; -+ -+ entry->state = SUCCESS; -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " -+ "successfully - callback"); -+ eap_sim_db_add_pending(data, entry); -+ data->get_complete_cb(data->ctx, entry->cb_session_ctx); -+ return; -+ -+parse_fail: -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); -+ os_free(entry); -+} -+ -+ -+static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data, -+ const char *imsi, char *buf) -+{ -+ char *start, *end; -+ struct eap_sim_db_pending *entry; -+ -+ /* -+ * AKA-RESP-AUTH -+ * AKA-RESP-AUTH FAILURE -+ * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string) -+ */ -+ -+ entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1); -+ if (entry == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " -+ "received message found"); -+ return; -+ } -+ -+ start = buf; -+ if (os_strncmp(start, "FAILURE", 7) == 0) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " -+ "failure"); -+ entry->state = FAILURE; -+ eap_sim_db_add_pending(data, entry); -+ data->get_complete_cb(data->ctx, entry->cb_session_ctx); -+ return; -+ } -+ -+ end = os_strchr(start, ' '); -+ if (end == NULL) -+ goto parse_fail; -+ *end = '\0'; -+ if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN)) -+ goto parse_fail; -+ -+ start = end + 1; -+ end = os_strchr(start, ' '); -+ if (end == NULL) -+ goto parse_fail; -+ *end = '\0'; -+ if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN)) -+ goto parse_fail; -+ -+ start = end + 1; -+ end = os_strchr(start, ' '); -+ if (end == NULL) -+ goto parse_fail; -+ *end = '\0'; -+ if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN)) -+ goto parse_fail; -+ -+ start = end + 1; -+ end = os_strchr(start, ' '); -+ if (end == NULL) -+ goto parse_fail; -+ *end = '\0'; -+ if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN)) -+ goto parse_fail; -+ -+ start = end + 1; -+ end = os_strchr(start, ' '); -+ if (end) -+ *end = '\0'; -+ else { -+ end = start; -+ while (*end) -+ end++; -+ } -+ entry->u.aka.res_len = (end - start) / 2; -+ if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES"); -+ entry->u.aka.res_len = 0; -+ goto parse_fail; -+ } -+ if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len)) -+ goto parse_fail; -+ -+ entry->state = SUCCESS; -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " -+ "successfully - callback"); -+ eap_sim_db_add_pending(data, entry); -+ data->get_complete_cb(data->ctx, entry->cb_session_ctx); -+ return; -+ -+parse_fail: -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); -+ os_free(entry); -+} -+ -+ -+static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct eap_sim_db_data *data = eloop_ctx; -+ char buf[1000], *pos, *cmd, *imsi; -+ int res; -+ -+ res = recv(sock, buf, sizeof(buf), 0); -+ if (res < 0) -+ return; -+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an " -+ "external source", (u8 *) buf, res); -+ if (res == 0) -+ return; -+ if (res >= (int) sizeof(buf)) -+ res = sizeof(buf) - 1; -+ buf[res] = '\0'; -+ -+ if (data->get_complete_cb == NULL) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb " -+ "registered"); -+ return; -+ } -+ -+ /* ... */ -+ -+ cmd = buf; -+ pos = os_strchr(cmd, ' '); -+ if (pos == NULL) -+ goto parse_fail; -+ *pos = '\0'; -+ imsi = pos + 1; -+ pos = os_strchr(imsi, ' '); -+ if (pos == NULL) -+ goto parse_fail; -+ *pos = '\0'; -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s", -+ cmd, imsi); -+ -+ if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0) -+ eap_sim_db_sim_resp_auth(data, imsi, pos + 1); -+ else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0) -+ eap_sim_db_aka_resp_auth(data, imsi, pos + 1); -+ else -+ wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response " -+ "'%s'", cmd); -+ return; -+ -+parse_fail: -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); -+} -+ -+ -+static int eap_sim_db_open_socket(struct eap_sim_db_data *data) -+{ -+ struct sockaddr_un addr; -+ static int counter = 0; -+ -+ if (os_strncmp(data->fname, "unix:", 5) != 0) -+ return -1; -+ -+ data->sock = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (data->sock < 0) { -+ perror("socket(eap_sim_db)"); -+ return -1; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), -+ "/tmp/eap_sim_db_%d-%d", getpid(), counter++); -+ data->local_sock = os_strdup(addr.sun_path); -+ if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind(eap_sim_db)"); -+ close(data->sock); -+ data->sock = -1; -+ return -1; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path)); -+ if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("connect(eap_sim_db)"); -+ wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket", -+ (u8 *) addr.sun_path, -+ os_strlen(addr.sun_path)); -+ close(data->sock); -+ data->sock = -1; -+ return -1; -+ } -+ -+ eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL); -+ -+ return 0; -+} -+ -+ -+static void eap_sim_db_close_socket(struct eap_sim_db_data *data) -+{ -+ if (data->sock >= 0) { -+ eloop_unregister_read_sock(data->sock); -+ close(data->sock); -+ data->sock = -1; -+ } -+ if (data->local_sock) { -+ unlink(data->local_sock); -+ os_free(data->local_sock); -+ data->local_sock = NULL; -+ } -+} -+ -+ -+/** -+ * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface -+ * @config: Configuration data (e.g., file name) -+ * @get_complete_cb: Callback function for reporting availability of triplets -+ * @ctx: Context pointer for get_complete_cb -+ * Returns: Pointer to a private data structure or %NULL on failure -+ */ -+void * eap_sim_db_init(const char *config, -+ void (*get_complete_cb)(void *ctx, void *session_ctx), -+ void *ctx) -+{ -+ struct eap_sim_db_data *data; -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ data->sock = -1; -+ data->get_complete_cb = get_complete_cb; -+ data->ctx = ctx; -+ data->fname = os_strdup(config); -+ if (data->fname == NULL) -+ goto fail; -+ -+ if (os_strncmp(data->fname, "unix:", 5) == 0) { -+ if (eap_sim_db_open_socket(data)) -+ goto fail; -+ } -+ -+ return data; -+ -+fail: -+ eap_sim_db_close_socket(data); -+ os_free(data->fname); -+ os_free(data); -+ return NULL; -+} -+ -+ -+static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p) -+{ -+ os_free(p->identity); -+ os_free(p->pseudonym); -+ os_free(p); -+} -+ -+ -+static void eap_sim_db_free_reauth(struct eap_sim_reauth *r) -+{ -+ os_free(r->identity); -+ os_free(r->reauth_id); -+ os_free(r); -+} -+ -+ -+/** -+ * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface -+ * @priv: Private data pointer from eap_sim_db_init() -+ */ -+void eap_sim_db_deinit(void *priv) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_pseudonym *p, *prev; -+ struct eap_sim_reauth *r, *prevr; -+ struct eap_sim_db_pending *pending, *prev_pending; -+ -+ eap_sim_db_close_socket(data); -+ os_free(data->fname); -+ -+ p = data->pseudonyms; -+ while (p) { -+ prev = p; -+ p = p->next; -+ eap_sim_db_free_pseudonym(prev); -+ } -+ -+ r = data->reauths; -+ while (r) { -+ prevr = r; -+ r = r->next; -+ eap_sim_db_free_reauth(prevr); -+ } -+ -+ pending = data->pending; -+ while (pending) { -+ prev_pending = pending; -+ pending = pending->next; -+ os_free(prev_pending); -+ } -+ -+ os_free(data); -+} -+ -+ -+static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg, -+ size_t len) -+{ -+ int _errno = 0; -+ -+ if (send(data->sock, msg, len, 0) < 0) { -+ _errno = errno; -+ perror("send[EAP-SIM DB UNIX]"); -+ } -+ -+ if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || -+ _errno == ECONNREFUSED) { -+ /* Try to reconnect */ -+ eap_sim_db_close_socket(data); -+ if (eap_sim_db_open_socket(data) < 0) -+ return -1; -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the " -+ "external server"); -+ if (send(data->sock, msg, len, 0) < 0) { -+ perror("send[EAP-SIM DB UNIX]"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static void eap_sim_db_expire_pending(struct eap_sim_db_data *data) -+{ -+ /* TODO: add limit for maximum length for pending list; remove latest -+ * (i.e., last) entry from the list if the limit is reached; could also -+ * use timeout to expire pending entries */ -+} -+ -+ -+/** -+ * eap_sim_db_get_gsm_triplets - Get GSM triplets -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: User name identity -+ * @identity_len: Length of identity in bytes -+ * @max_chal: Maximum number of triplets -+ * @_rand: Buffer for RAND values -+ * @kc: Buffer for Kc values -+ * @sres: Buffer for SRES values -+ * @cb_session_ctx: Session callback context for get_complete_cb() -+ * Returns: Number of triplets received (has to be less than or equal to -+ * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or -+ * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the -+ * callback function registered with eap_sim_db_init() will be called once the -+ * results become available. -+ * -+ * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in -+ * ASCII format. -+ * -+ * When using an external server for GSM triplets, this function can always -+ * start a request and return EAP_SIM_DB_PENDING immediately if authentication -+ * triplets are not available. Once the triplets are received, callback -+ * function registered with eap_sim_db_init() is called to notify EAP state -+ * machine to reprocess the message. This eap_sim_db_get_gsm_triplets() -+ * function will then be called again and the newly received triplets will then -+ * be given to the caller. -+ */ -+int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, -+ size_t identity_len, int max_chal, -+ u8 *_rand, u8 *kc, u8 *sres, -+ void *cb_session_ctx) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_db_pending *entry; -+ int len, ret; -+ size_t i; -+ char msg[40]; -+ -+ if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", -+ identity, identity_len); -+ return EAP_SIM_DB_FAILURE; -+ } -+ identity++; -+ identity_len--; -+ for (i = 0; i < identity_len; i++) { -+ if (identity[i] == '@') { -+ identity_len = i; -+ break; -+ } -+ } -+ if (identity_len + 1 > sizeof(entry->imsi)) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", -+ identity, identity_len); -+ return EAP_SIM_DB_FAILURE; -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI", -+ identity, identity_len); -+ -+ entry = eap_sim_db_get_pending(data, identity, identity_len, 0); -+ if (entry) { -+ int num_chal; -+ if (entry->state == FAILURE) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " -+ "failure"); -+ os_free(entry); -+ return EAP_SIM_DB_FAILURE; -+ } -+ -+ if (entry->state == PENDING) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " -+ "still pending"); -+ eap_sim_db_add_pending(data, entry); -+ return EAP_SIM_DB_PENDING; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " -+ "%d challenges", entry->u.sim.num_chal); -+ num_chal = entry->u.sim.num_chal; -+ if (num_chal > max_chal) -+ num_chal = max_chal; -+ os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN); -+ os_memcpy(sres, entry->u.sim.sres, -+ num_chal * EAP_SIM_SRES_LEN); -+ os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN); -+ os_free(entry); -+ return num_chal; -+ } -+ -+ if (data->sock < 0) { -+ if (eap_sim_db_open_socket(data) < 0) -+ return EAP_SIM_DB_FAILURE; -+ } -+ -+ len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH "); -+ if (len < 0 || len + identity_len >= sizeof(msg)) -+ return EAP_SIM_DB_FAILURE; -+ os_memcpy(msg + len, identity, identity_len); -+ len += identity_len; -+ ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal); -+ if (ret < 0 || (size_t) ret >= sizeof(msg) - len) -+ return EAP_SIM_DB_FAILURE; -+ len += ret; -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication " -+ "data for IMSI", identity, identity_len); -+ if (eap_sim_db_send(data, msg, len) < 0) -+ return EAP_SIM_DB_FAILURE; -+ -+ entry = os_zalloc(sizeof(*entry)); -+ if (entry == NULL) -+ return EAP_SIM_DB_FAILURE; -+ -+ os_get_time(&entry->timestamp); -+ os_memcpy(entry->imsi, identity, identity_len); -+ entry->imsi_len = identity_len; -+ entry->cb_session_ctx = cb_session_ctx; -+ entry->state = PENDING; -+ eap_sim_db_add_pending(data, entry); -+ eap_sim_db_expire_pending(data); -+ -+ return EAP_SIM_DB_PENDING; -+} -+ -+ -+static struct eap_sim_pseudonym * -+eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity, -+ size_t identity_len) -+{ -+ char *pseudonym; -+ size_t len; -+ struct eap_sim_pseudonym *p; -+ -+ if (identity_len == 0 || -+ (identity[0] != EAP_SIM_PSEUDONYM_PREFIX && -+ identity[0] != EAP_AKA_PSEUDONYM_PREFIX)) -+ return NULL; -+ -+ /* Remove possible realm from identity */ -+ len = 0; -+ while (len < identity_len) { -+ if (identity[len] == '@') -+ break; -+ len++; -+ } -+ -+ pseudonym = os_malloc(len + 1); -+ if (pseudonym == NULL) -+ return NULL; -+ os_memcpy(pseudonym, identity, len); -+ pseudonym[len] = '\0'; -+ -+ p = data->pseudonyms; -+ while (p) { -+ if (os_strcmp(p->pseudonym, pseudonym) == 0) -+ break; -+ p = p->next; -+ } -+ -+ os_free(pseudonym); -+ -+ return p; -+} -+ -+ -+static struct eap_sim_pseudonym * -+eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity, -+ size_t identity_len) -+{ -+ struct eap_sim_pseudonym *p; -+ -+ if (identity_len == 0 || -+ (identity[0] != EAP_SIM_PERMANENT_PREFIX && -+ identity[0] != EAP_AKA_PERMANENT_PREFIX)) -+ return NULL; -+ -+ p = data->pseudonyms; -+ while (p) { -+ if (identity_len == p->identity_len && -+ os_memcmp(p->identity, identity, identity_len) == 0) -+ break; -+ p = p->next; -+ } -+ -+ return p; -+} -+ -+ -+static struct eap_sim_reauth * -+eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity, -+ size_t identity_len) -+{ -+ char *reauth_id; -+ size_t len; -+ struct eap_sim_reauth *r; -+ -+ if (identity_len == 0 || -+ (identity[0] != EAP_SIM_REAUTH_ID_PREFIX && -+ identity[0] != EAP_AKA_REAUTH_ID_PREFIX)) -+ return NULL; -+ -+ /* Remove possible realm from identity */ -+ len = 0; -+ while (len < identity_len) { -+ if (identity[len] == '@') -+ break; -+ len++; -+ } -+ -+ reauth_id = os_malloc(len + 1); -+ if (reauth_id == NULL) -+ return NULL; -+ os_memcpy(reauth_id, identity, len); -+ reauth_id[len] = '\0'; -+ -+ r = data->reauths; -+ while (r) { -+ if (os_strcmp(r->reauth_id, reauth_id) == 0) -+ break; -+ r = r->next; -+ } -+ -+ os_free(reauth_id); -+ -+ return r; -+} -+ -+ -+static struct eap_sim_reauth * -+eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity, -+ size_t identity_len) -+{ -+ struct eap_sim_pseudonym *p; -+ struct eap_sim_reauth *r; -+ -+ if (identity_len == 0) -+ return NULL; -+ -+ p = eap_sim_db_get_pseudonym(data, identity, identity_len); -+ if (p == NULL) -+ p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); -+ if (p) { -+ identity = p->identity; -+ identity_len = p->identity_len; -+ } -+ -+ r = data->reauths; -+ while (r) { -+ if (identity_len == r->identity_len && -+ os_memcmp(r->identity, identity, identity_len) == 0) -+ break; -+ r = r->next; -+ } -+ -+ return r; -+} -+ -+ -+/** -+ * eap_sim_db_identity_known - Verify whether the given identity is known -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: User name identity -+ * @identity_len: Length of identity in bytes -+ * Returns: 0 if the user is found or -1 on failure -+ * -+ * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the -+ * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id. -+ */ -+int eap_sim_db_identity_known(void *priv, const u8 *identity, -+ size_t identity_len) -+{ -+ struct eap_sim_db_data *data = priv; -+ -+ if (identity == NULL || identity_len < 2) -+ return -1; -+ -+ if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX || -+ identity[0] == EAP_AKA_PSEUDONYM_PREFIX) { -+ struct eap_sim_pseudonym *p = -+ eap_sim_db_get_pseudonym(data, identity, identity_len); -+ return p ? 0 : -1; -+ } -+ -+ if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX || -+ identity[0] == EAP_AKA_REAUTH_ID_PREFIX) { -+ struct eap_sim_reauth *r = -+ eap_sim_db_get_reauth(data, identity, identity_len); -+ return r ? 0 : -1; -+ } -+ -+ if (identity[0] != EAP_SIM_PERMANENT_PREFIX && -+ identity[0] != EAP_AKA_PERMANENT_PREFIX) { -+ /* Unknown identity prefix */ -+ return -1; -+ } -+ -+ /* TODO: Should consider asking HLR/AuC gateway whether this permanent -+ * identity is known. If it is, EAP-SIM/AKA can skip identity request. -+ * In case of EAP-AKA, this would reduce number of needed round-trips. -+ * Ideally, this would be done with one wait, i.e., just request -+ * authentication data and store it for the next use. This would then -+ * need to use similar pending-request functionality as the normal -+ * request for authentication data at later phase. -+ */ -+ return -1; -+} -+ -+ -+static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) -+{ -+ char *id, *pos, *end; -+ u8 buf[10]; -+ -+ if (random_get_bytes(buf, sizeof(buf))) -+ return NULL; -+ id = os_malloc(sizeof(buf) * 2 + 2); -+ if (id == NULL) -+ return NULL; -+ -+ pos = id; -+ end = id + sizeof(buf) * 2 + 2; -+ *pos++ = prefix; -+ pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf)); -+ -+ return id; -+} -+ -+ -+/** -+ * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @aka: Using EAP-AKA instead of EAP-SIM -+ * Returns: Next pseudonym (allocated string) or %NULL on failure -+ * -+ * This function is used to generate a pseudonym for EAP-SIM. The returned -+ * pseudonym is not added to database at this point; it will need to be added -+ * with eap_sim_db_add_pseudonym() once the authentication has been completed -+ * successfully. Caller is responsible for freeing the returned buffer. -+ */ -+char * eap_sim_db_get_next_pseudonym(void *priv, int aka) -+{ -+ struct eap_sim_db_data *data = priv; -+ return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX : -+ EAP_SIM_PSEUDONYM_PREFIX); -+} -+ -+ -+/** -+ * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @aka: Using EAP-AKA instead of EAP-SIM -+ * Returns: Next reauth_id (allocated string) or %NULL on failure -+ * -+ * This function is used to generate a fast re-authentication identity for -+ * EAP-SIM. The returned reauth_id is not added to database at this point; it -+ * will need to be added with eap_sim_db_add_reauth() once the authentication -+ * has been completed successfully. Caller is responsible for freeing the -+ * returned buffer. -+ */ -+char * eap_sim_db_get_next_reauth_id(void *priv, int aka) -+{ -+ struct eap_sim_db_data *data = priv; -+ return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX : -+ EAP_SIM_REAUTH_ID_PREFIX); -+} -+ -+ -+/** -+ * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: Identity of the user (may be permanent identity or pseudonym) -+ * @identity_len: Length of identity -+ * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer, -+ * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not -+ * free it. -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is -+ * responsible of freeing pseudonym buffer once it is not needed anymore. -+ */ -+int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, -+ size_t identity_len, char *pseudonym) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_pseudonym *p; -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity", -+ identity, identity_len); -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym); -+ -+ /* TODO: could store last two pseudonyms */ -+ p = eap_sim_db_get_pseudonym(data, identity, identity_len); -+ if (p == NULL) -+ p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); -+ -+ if (p) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " -+ "pseudonym: %s", p->pseudonym); -+ os_free(p->pseudonym); -+ p->pseudonym = pseudonym; -+ return 0; -+ } -+ -+ p = os_zalloc(sizeof(*p)); -+ if (p == NULL) { -+ os_free(pseudonym); -+ return -1; -+ } -+ -+ p->next = data->pseudonyms; -+ p->identity = os_malloc(identity_len); -+ if (p->identity == NULL) { -+ os_free(p); -+ os_free(pseudonym); -+ return -1; -+ } -+ os_memcpy(p->identity, identity, identity_len); -+ p->identity_len = identity_len; -+ p->pseudonym = pseudonym; -+ data->pseudonyms = p; -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry"); -+ return 0; -+} -+ -+ -+static struct eap_sim_reauth * -+eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity, -+ size_t identity_len, char *reauth_id, u16 counter) -+{ -+ struct eap_sim_reauth *r; -+ -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity", -+ identity, identity_len); -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id); -+ -+ r = eap_sim_db_get_reauth(data, identity, identity_len); -+ if (r == NULL) -+ r = eap_sim_db_get_reauth_id(data, identity, identity_len); -+ -+ if (r) { -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " -+ "reauth_id: %s", r->reauth_id); -+ os_free(r->reauth_id); -+ r->reauth_id = reauth_id; -+ } else { -+ r = os_zalloc(sizeof(*r)); -+ if (r == NULL) { -+ os_free(reauth_id); -+ return NULL; -+ } -+ -+ r->next = data->reauths; -+ r->identity = os_malloc(identity_len); -+ if (r->identity == NULL) { -+ os_free(r); -+ os_free(reauth_id); -+ return NULL; -+ } -+ os_memcpy(r->identity, identity, identity_len); -+ r->identity_len = identity_len; -+ r->reauth_id = reauth_id; -+ data->reauths = r; -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry"); -+ } -+ -+ r->counter = counter; -+ -+ return r; -+} -+ -+ -+/** -+ * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: Identity of the user (may be permanent identity or pseudonym) -+ * @identity_len: Length of identity -+ * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, -+ * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not -+ * free it. -+ * @counter: AT_COUNTER value for fast re-authentication -+ * @mk: 16-byte MK from the previous full authentication or %NULL -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function adds a new re-authentication entry for an EAP-SIM user. -+ * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed -+ * anymore. -+ */ -+int eap_sim_db_add_reauth(void *priv, const u8 *identity, -+ size_t identity_len, char *reauth_id, u16 counter, -+ const u8 *mk) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_reauth *r; -+ -+ r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, -+ counter); -+ if (r == NULL) -+ return -1; -+ -+ os_memcpy(r->mk, mk, EAP_SIM_MK_LEN); -+ r->aka_prime = 0; -+ -+ return 0; -+} -+ -+ -+#ifdef EAP_SERVER_AKA_PRIME -+/** -+ * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: Identity of the user (may be permanent identity or pseudonym) -+ * @identity_len: Length of identity -+ * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, -+ * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not -+ * free it. -+ * @counter: AT_COUNTER value for fast re-authentication -+ * @k_encr: K_encr from the previous full authentication -+ * @k_aut: K_aut from the previous full authentication -+ * @k_re: 32-byte K_re from the previous full authentication -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function adds a new re-authentication entry for an EAP-AKA' user. -+ * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed -+ * anymore. -+ */ -+int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, -+ size_t identity_len, char *reauth_id, -+ u16 counter, const u8 *k_encr, const u8 *k_aut, -+ const u8 *k_re) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_reauth *r; -+ -+ r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, -+ counter); -+ if (r == NULL) -+ return -1; -+ -+ r->aka_prime = 1; -+ os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN); -+ os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN); -+ os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN); -+ -+ return 0; -+} -+#endif /* EAP_SERVER_AKA_PRIME */ -+ -+ -+/** -+ * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: Identity of the user (may be permanent identity or pseudonym) -+ * @identity_len: Length of identity -+ * @len: Buffer for length of the returned permanent identity -+ * Returns: Pointer to the permanent identity, or %NULL if not found -+ */ -+const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity, -+ size_t identity_len, size_t *len) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_pseudonym *p; -+ -+ if (identity == NULL) -+ return NULL; -+ -+ p = eap_sim_db_get_pseudonym(data, identity, identity_len); -+ if (p == NULL) -+ p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); -+ if (p == NULL) -+ return NULL; -+ -+ *len = p->identity_len; -+ return p->identity; -+} -+ -+ -+/** -+ * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: Identity of the user (may be permanent identity, pseudonym, or -+ * reauth_id) -+ * @identity_len: Length of identity -+ * Returns: Pointer to the re-auth entry, or %NULL if not found -+ */ -+struct eap_sim_reauth * -+eap_sim_db_get_reauth_entry(void *priv, const u8 *identity, -+ size_t identity_len) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_reauth *r; -+ -+ if (identity == NULL) -+ return NULL; -+ r = eap_sim_db_get_reauth(data, identity, identity_len); -+ if (r == NULL) -+ r = eap_sim_db_get_reauth_id(data, identity, identity_len); -+ return r; -+} -+ -+ -+/** -+ * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @reauth: Pointer to re-authentication entry from -+ * eap_sim_db_get_reauth_entry() -+ */ -+void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_reauth *r, *prev = NULL; -+ r = data->reauths; -+ while (r) { -+ if (r == reauth) { -+ if (prev) -+ prev->next = r->next; -+ else -+ data->reauths = r->next; -+ eap_sim_db_free_reauth(r); -+ return; -+ } -+ prev = r; -+ r = r->next; -+ } -+} -+ -+ -+/** -+ * eap_sim_db_get_aka_auth - Get AKA authentication values -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: User name identity -+ * @identity_len: Length of identity in bytes -+ * @_rand: Buffer for RAND value -+ * @autn: Buffer for AUTN value -+ * @ik: Buffer for IK value -+ * @ck: Buffer for CK value -+ * @res: Buffer for RES value -+ * @res_len: Buffer for RES length -+ * @cb_session_ctx: Session callback context for get_complete_cb() -+ * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not -+ * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this -+ * case, the callback function registered with eap_sim_db_init() will be -+ * called once the results become available. -+ * -+ * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in -+ * ASCII format. -+ * -+ * When using an external server for AKA authentication, this function can -+ * always start a request and return EAP_SIM_DB_PENDING immediately if -+ * authentication triplets are not available. Once the authentication data are -+ * received, callback function registered with eap_sim_db_init() is called to -+ * notify EAP state machine to reprocess the message. This -+ * eap_sim_db_get_aka_auth() function will then be called again and the newly -+ * received triplets will then be given to the caller. -+ */ -+int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, -+ size_t identity_len, u8 *_rand, u8 *autn, u8 *ik, -+ u8 *ck, u8 *res, size_t *res_len, -+ void *cb_session_ctx) -+{ -+ struct eap_sim_db_data *data = priv; -+ struct eap_sim_db_pending *entry; -+ int len; -+ size_t i; -+ char msg[40]; -+ -+ if (identity_len < 2 || identity == NULL || -+ identity[0] != EAP_AKA_PERMANENT_PREFIX) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", -+ identity, identity_len); -+ return EAP_SIM_DB_FAILURE; -+ } -+ identity++; -+ identity_len--; -+ for (i = 0; i < identity_len; i++) { -+ if (identity[i] == '@') { -+ identity_len = i; -+ break; -+ } -+ } -+ if (identity_len + 1 > sizeof(entry->imsi)) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", -+ identity, identity_len); -+ return EAP_SIM_DB_FAILURE; -+ } -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI", -+ identity, identity_len); -+ -+ entry = eap_sim_db_get_pending(data, identity, identity_len, 1); -+ if (entry) { -+ if (entry->state == FAILURE) { -+ os_free(entry); -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure"); -+ return EAP_SIM_DB_FAILURE; -+ } -+ -+ if (entry->state == PENDING) { -+ eap_sim_db_add_pending(data, entry); -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending"); -+ return EAP_SIM_DB_PENDING; -+ } -+ -+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully " -+ "received authentication data"); -+ os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN); -+ os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN); -+ os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN); -+ os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN); -+ os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN); -+ *res_len = entry->u.aka.res_len; -+ os_free(entry); -+ return 0; -+ } -+ -+ if (data->sock < 0) { -+ if (eap_sim_db_open_socket(data) < 0) -+ return EAP_SIM_DB_FAILURE; -+ } -+ -+ len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH "); -+ if (len < 0 || len + identity_len >= sizeof(msg)) -+ return EAP_SIM_DB_FAILURE; -+ os_memcpy(msg + len, identity, identity_len); -+ len += identity_len; -+ -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication " -+ "data for IMSI", identity, identity_len); -+ if (eap_sim_db_send(data, msg, len) < 0) -+ return EAP_SIM_DB_FAILURE; -+ -+ entry = os_zalloc(sizeof(*entry)); -+ if (entry == NULL) -+ return EAP_SIM_DB_FAILURE; -+ -+ os_get_time(&entry->timestamp); -+ entry->aka = 1; -+ os_memcpy(entry->imsi, identity, identity_len); -+ entry->imsi_len = identity_len; -+ entry->cb_session_ctx = cb_session_ctx; -+ entry->state = PENDING; -+ eap_sim_db_add_pending(data, entry); -+ eap_sim_db_expire_pending(data); -+ -+ return EAP_SIM_DB_PENDING; -+} -+ -+ -+/** -+ * eap_sim_db_resynchronize - Resynchronize AKA AUTN -+ * @priv: Private data pointer from eap_sim_db_init() -+ * @identity: User name identity -+ * @identity_len: Length of identity in bytes -+ * @auts: AUTS value from the peer -+ * @_rand: RAND value used in the rejected message -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is called when the peer reports synchronization failure in the -+ * AUTN value by sending AUTS. The AUTS and RAND values should be sent to -+ * HLR/AuC to allow it to resynchronize with the peer. After this, -+ * eap_sim_db_get_aka_auth() will be called again to to fetch updated -+ * RAND/AUTN values for the next challenge. -+ */ -+int eap_sim_db_resynchronize(void *priv, const u8 *identity, -+ size_t identity_len, const u8 *auts, -+ const u8 *_rand) -+{ -+ struct eap_sim_db_data *data = priv; -+ size_t i; -+ -+ if (identity_len < 2 || identity == NULL || -+ identity[0] != EAP_AKA_PERMANENT_PREFIX) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", -+ identity, identity_len); -+ return -1; -+ } -+ identity++; -+ identity_len--; -+ for (i = 0; i < identity_len; i++) { -+ if (identity[i] == '@') { -+ identity_len = i; -+ break; -+ } -+ } -+ if (identity_len > 20) { -+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", -+ identity, identity_len); -+ return -1; -+ } -+ -+ if (data->sock >= 0) { -+ char msg[100]; -+ int len, ret; -+ -+ len = os_snprintf(msg, sizeof(msg), "AKA-AUTS "); -+ if (len < 0 || len + identity_len >= sizeof(msg)) -+ return -1; -+ os_memcpy(msg + len, identity, identity_len); -+ len += identity_len; -+ -+ ret = os_snprintf(msg + len, sizeof(msg) - len, " "); -+ if (ret < 0 || (size_t) ret >= sizeof(msg) - len) -+ return -1; -+ len += ret; -+ len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, -+ auts, EAP_AKA_AUTS_LEN); -+ ret = os_snprintf(msg + len, sizeof(msg) - len, " "); -+ if (ret < 0 || (size_t) ret >= sizeof(msg) - len) -+ return -1; -+ len += ret; -+ len += wpa_snprintf_hex(msg + len, sizeof(msg) - len, -+ _rand, EAP_AKA_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for " -+ "IMSI", identity, identity_len); -+ if (eap_sim_db_send(data, msg, len) < 0) -+ return -1; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.h -new file mode 100644 -index 0000000000000..ab89ae97d5a0f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_sim_db.h -@@ -0,0 +1,91 @@ -+/* -+ * hostapd / EAP-SIM database/authenticator gateway -+ * Copyright (c) 2005-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_SIM_DB_H -+#define EAP_SIM_DB_H -+ -+#include "eap_common/eap_sim_common.h" -+ -+/* Identity prefixes */ -+#define EAP_SIM_PERMANENT_PREFIX '1' -+#define EAP_SIM_PSEUDONYM_PREFIX '3' -+#define EAP_SIM_REAUTH_ID_PREFIX '5' -+#define EAP_AKA_PERMANENT_PREFIX '0' -+#define EAP_AKA_PSEUDONYM_PREFIX '2' -+#define EAP_AKA_REAUTH_ID_PREFIX '4' -+ -+void * eap_sim_db_init(const char *config, -+ void (*get_complete_cb)(void *ctx, void *session_ctx), -+ void *ctx); -+ -+void eap_sim_db_deinit(void *priv); -+ -+int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, -+ size_t identity_len, int max_chal, -+ u8 *_rand, u8 *kc, u8 *sres, -+ void *cb_session_ctx); -+ -+#define EAP_SIM_DB_FAILURE -1 -+#define EAP_SIM_DB_PENDING -2 -+ -+int eap_sim_db_identity_known(void *priv, const u8 *identity, -+ size_t identity_len); -+ -+char * eap_sim_db_get_next_pseudonym(void *priv, int aka); -+ -+char * eap_sim_db_get_next_reauth_id(void *priv, int aka); -+ -+int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, -+ size_t identity_len, char *pseudonym); -+ -+int eap_sim_db_add_reauth(void *priv, const u8 *identity, -+ size_t identity_len, char *reauth_id, u16 counter, -+ const u8 *mk); -+int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, -+ size_t identity_len, char *reauth_id, -+ u16 counter, const u8 *k_encr, const u8 *k_aut, -+ const u8 *k_re); -+ -+const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity, -+ size_t identity_len, size_t *len); -+ -+struct eap_sim_reauth { -+ struct eap_sim_reauth *next; -+ u8 *identity; -+ size_t identity_len; -+ char *reauth_id; -+ u16 counter; -+ int aka_prime; -+ u8 mk[EAP_SIM_MK_LEN]; -+ u8 k_encr[EAP_SIM_K_ENCR_LEN]; -+ u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN]; -+ u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; -+}; -+ -+struct eap_sim_reauth * -+eap_sim_db_get_reauth_entry(void *priv, const u8 *identity, -+ size_t identity_len); -+ -+void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth); -+ -+int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, -+ size_t identity_len, u8 *_rand, u8 *autn, u8 *ik, -+ u8 *ck, u8 *res, size_t *res_len, -+ void *cb_session_ctx); -+ -+int eap_sim_db_resynchronize(void *priv, const u8 *identity, -+ size_t identity_len, const u8 *auts, -+ const u8 *_rand); -+ -+#endif /* EAP_SIM_DB_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_tls_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_tls_common.h -new file mode 100644 -index 0000000000000..c34c40108b24e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/eap_tls_common.h -@@ -0,0 +1,91 @@ -+/* -+ * EAP-TLS/PEAP/TTLS/FAST server common functions -+ * Copyright (c) 2004-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAP_TLS_COMMON_H -+#define EAP_TLS_COMMON_H -+ -+/** -+ * struct eap_ssl_data - TLS data for EAP methods -+ */ -+struct eap_ssl_data { -+ /** -+ * conn - TLS connection context data from tls_connection_init() -+ */ -+ struct tls_connection *conn; -+ -+ /** -+ * tls_out - TLS message to be sent out in fragments -+ */ -+ struct wpabuf *tls_out; -+ -+ /** -+ * tls_out_pos - The current position in the outgoing TLS message -+ */ -+ size_t tls_out_pos; -+ -+ /** -+ * tls_out_limit - Maximum fragment size for outgoing TLS messages -+ */ -+ size_t tls_out_limit; -+ -+ /** -+ * tls_in - Received TLS message buffer for re-assembly -+ */ -+ struct wpabuf *tls_in; -+ -+ /** -+ * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) -+ */ -+ int phase2; -+ -+ /** -+ * eap - EAP state machine allocated with eap_server_sm_init() -+ */ -+ struct eap_sm *eap; -+ -+ enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state; -+ struct wpabuf tmpbuf; -+}; -+ -+ -+/* EAP TLS Flags */ -+#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 -+#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 -+#define EAP_TLS_FLAGS_START 0x20 -+#define EAP_TLS_VERSION_MASK 0x07 -+ -+ /* could be up to 128 bytes, but only the first 64 bytes are used */ -+#define EAP_TLS_KEY_LEN 64 -+ -+ -+int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, -+ int verify_peer); -+void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); -+u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, -+ char *label, size_t len); -+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data, -+ int eap_type, int version, u8 id); -+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version); -+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data); -+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, -+ struct eap_ssl_data *data, -+ const struct wpabuf *plain); -+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, -+ struct wpabuf *respData, void *priv, int eap_type, -+ int (*proc_version)(struct eap_sm *sm, void *priv, -+ int peer_version), -+ void (*proc_msg)(struct eap_sm *sm, void *priv, -+ const struct wpabuf *respData)); -+ -+#endif /* EAP_TLS_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.c -new file mode 100644 -index 0000000000000..9624d53af36cd ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.c -@@ -0,0 +1,1206 @@ -+/* -+ * IKEv2 initiator (RFC 4306) for EAP-IKEV2 -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/dh_groups.h" -+#include "crypto/random.h" -+#include "ikev2.h" -+ -+ -+static int ikev2_process_idr(struct ikev2_initiator_data *data, -+ const u8 *idr, size_t idr_len); -+ -+ -+void ikev2_initiator_deinit(struct ikev2_initiator_data *data) -+{ -+ ikev2_free_keys(&data->keys); -+ wpabuf_free(data->r_dh_public); -+ wpabuf_free(data->i_dh_private); -+ os_free(data->IDi); -+ os_free(data->IDr); -+ os_free(data->shared_secret); -+ wpabuf_free(data->i_sign_msg); -+ wpabuf_free(data->r_sign_msg); -+ os_free(data->key_pad); -+} -+ -+ -+static int ikev2_derive_keys(struct ikev2_initiator_data *data) -+{ -+ u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN]; -+ size_t buf_len, pad_len; -+ struct wpabuf *shared; -+ const struct ikev2_integ_alg *integ; -+ const struct ikev2_prf_alg *prf; -+ const struct ikev2_encr_alg *encr; -+ int ret; -+ const u8 *addr[2]; -+ size_t len[2]; -+ -+ /* RFC 4306, Sect. 2.14 */ -+ -+ integ = ikev2_get_integ(data->proposal.integ); -+ prf = ikev2_get_prf(data->proposal.prf); -+ encr = ikev2_get_encr(data->proposal.encr); -+ if (integ == NULL || prf == NULL || encr == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal"); -+ return -1; -+ } -+ -+ shared = dh_derive_shared(data->r_dh_public, data->i_dh_private, -+ data->dh); -+ if (shared == NULL) -+ return -1; -+ -+ /* Construct Ni | Nr | SPIi | SPIr */ -+ -+ buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN; -+ buf = os_malloc(buf_len); -+ if (buf == NULL) { -+ wpabuf_free(shared); -+ return -1; -+ } -+ -+ pos = buf; -+ os_memcpy(pos, data->i_nonce, data->i_nonce_len); -+ pos += data->i_nonce_len; -+ os_memcpy(pos, data->r_nonce, data->r_nonce_len); -+ pos += data->r_nonce_len; -+ os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); -+ pos += IKEV2_SPI_LEN; -+ os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); -+ -+ /* SKEYSEED = prf(Ni | Nr, g^ir) */ -+ -+ /* Use zero-padding per RFC 4306, Sect. 2.14 */ -+ pad_len = data->dh->prime_len - wpabuf_len(shared); -+ pad = os_zalloc(pad_len ? pad_len : 1); -+ if (pad == NULL) { -+ wpabuf_free(shared); -+ os_free(buf); -+ return -1; -+ } -+ addr[0] = pad; -+ len[0] = pad_len; -+ addr[1] = wpabuf_head(shared); -+ len[1] = wpabuf_len(shared); -+ if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len, -+ 2, addr, len, skeyseed) < 0) { -+ wpabuf_free(shared); -+ os_free(buf); -+ os_free(pad); -+ return -1; -+ } -+ os_free(pad); -+ wpabuf_free(shared); -+ -+ /* DH parameters are not needed anymore, so free them */ -+ wpabuf_free(data->r_dh_public); -+ data->r_dh_public = NULL; -+ wpabuf_free(data->i_dh_private); -+ data->i_dh_private = NULL; -+ -+ wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED", -+ skeyseed, prf->hash_len); -+ -+ ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len, -+ &data->keys); -+ os_free(buf); -+ return ret; -+} -+ -+ -+static int ikev2_parse_transform(struct ikev2_initiator_data *data, -+ struct ikev2_proposal_data *prop, -+ const u8 *pos, const u8 *end) -+{ -+ int transform_len; -+ const struct ikev2_transform *t; -+ u16 transform_id; -+ const u8 *tend; -+ -+ if (end - pos < (int) sizeof(*t)) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short transform"); -+ return -1; -+ } -+ -+ t = (const struct ikev2_transform *) pos; -+ transform_len = WPA_GET_BE16(t->transform_length); -+ if (transform_len < (int) sizeof(*t) || pos + transform_len > end) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", -+ transform_len); -+ return -1; -+ } -+ tend = pos + transform_len; -+ -+ transform_id = WPA_GET_BE16(t->transform_id); -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); -+ wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " -+ "Transform Type: %d Transform ID: %d", -+ t->type, transform_len, t->transform_type, transform_id); -+ -+ if (t->type != 0 && t->type != 3) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); -+ return -1; -+ } -+ -+ pos = (const u8 *) (t + 1); -+ if (pos < tend) { -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", -+ pos, tend - pos); -+ } -+ -+ switch (t->transform_type) { -+ case IKEV2_TRANSFORM_ENCR: -+ if (ikev2_get_encr(transform_id) && -+ transform_id == data->proposal.encr) { -+ if (transform_id == ENCR_AES_CBC) { -+ if (tend - pos != 4) { -+ wpa_printf(MSG_DEBUG, "IKEV2: No " -+ "Transform Attr for AES"); -+ break; -+ } -+ if (WPA_GET_BE16(pos) != 0x800e) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Not a " -+ "Key Size attribute for " -+ "AES"); -+ break; -+ } -+ if (WPA_GET_BE16(pos + 2) != 128) { -+ wpa_printf(MSG_DEBUG, "IKEV2: " -+ "Unsupported AES key size " -+ "%d bits", -+ WPA_GET_BE16(pos + 2)); -+ break; -+ } -+ } -+ prop->encr = transform_id; -+ } -+ break; -+ case IKEV2_TRANSFORM_PRF: -+ if (ikev2_get_prf(transform_id) && -+ transform_id == data->proposal.prf) -+ prop->prf = transform_id; -+ break; -+ case IKEV2_TRANSFORM_INTEG: -+ if (ikev2_get_integ(transform_id) && -+ transform_id == data->proposal.integ) -+ prop->integ = transform_id; -+ break; -+ case IKEV2_TRANSFORM_DH: -+ if (dh_groups_get(transform_id) && -+ transform_id == data->proposal.dh) -+ prop->dh = transform_id; -+ break; -+ } -+ -+ return transform_len; -+} -+ -+ -+static int ikev2_parse_proposal(struct ikev2_initiator_data *data, -+ struct ikev2_proposal_data *prop, -+ const u8 *pos, const u8 *end) -+{ -+ const u8 *pend, *ppos; -+ int proposal_len, i; -+ const struct ikev2_proposal *p; -+ -+ if (end - pos < (int) sizeof(*p)) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short proposal"); -+ return -1; -+ } -+ -+ p = (const struct ikev2_proposal *) pos; -+ proposal_len = WPA_GET_BE16(p->proposal_length); -+ if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d", -+ proposal_len); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d", -+ p->proposal_num); -+ wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Proposal Length: %d " -+ " Protocol ID: %d", -+ p->type, proposal_len, p->protocol_id); -+ wpa_printf(MSG_DEBUG, "IKEV2: SPI Size: %d Transforms: %d", -+ p->spi_size, p->num_transforms); -+ -+ if (p->type != 0 && p->type != 2) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type"); -+ return -1; -+ } -+ -+ if (p->protocol_id != IKEV2_PROTOCOL_IKE) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID " -+ "(only IKE allowed for EAP-IKEv2)"); -+ return -1; -+ } -+ -+ if (p->proposal_num != prop->proposal_num) { -+ if (p->proposal_num == prop->proposal_num + 1) -+ prop->proposal_num = p->proposal_num; -+ else { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #"); -+ return -1; -+ } -+ } -+ -+ ppos = (const u8 *) (p + 1); -+ pend = pos + proposal_len; -+ if (ppos + p->spi_size > pend) { -+ wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI " -+ "in proposal"); -+ return -1; -+ } -+ if (p->spi_size) { -+ wpa_hexdump(MSG_DEBUG, "IKEV2: SPI", -+ ppos, p->spi_size); -+ ppos += p->spi_size; -+ } -+ -+ /* -+ * For initial IKE_SA negotiation, SPI Size MUST be zero; for -+ * subsequent negotiations, it must be 8 for IKE. We only support -+ * initial case for now. -+ */ -+ if (p->spi_size != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size"); -+ return -1; -+ } -+ -+ if (p->num_transforms == 0) { -+ wpa_printf(MSG_INFO, "IKEV2: At least one transform required"); -+ return -1; -+ } -+ -+ for (i = 0; i < (int) p->num_transforms; i++) { -+ int tlen = ikev2_parse_transform(data, prop, ppos, pend); -+ if (tlen < 0) -+ return -1; -+ ppos += tlen; -+ } -+ -+ if (ppos != pend) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected data after " -+ "transforms"); -+ return -1; -+ } -+ -+ return proposal_len; -+} -+ -+ -+static int ikev2_process_sar1(struct ikev2_initiator_data *data, -+ const u8 *sar1, size_t sar1_len) -+{ -+ struct ikev2_proposal_data prop; -+ const u8 *pos, *end; -+ int found = 0; -+ -+ /* Security Association Payloads: */ -+ -+ if (sar1 == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: SAr1 not received"); -+ return -1; -+ } -+ -+ os_memset(&prop, 0, sizeof(prop)); -+ prop.proposal_num = 1; -+ -+ pos = sar1; -+ end = sar1 + sar1_len; -+ -+ while (pos < end) { -+ int plen; -+ -+ prop.integ = -1; -+ prop.prf = -1; -+ prop.encr = -1; -+ prop.dh = -1; -+ plen = ikev2_parse_proposal(data, &prop, pos, end); -+ if (plen < 0) -+ return -1; -+ -+ if (!found && prop.integ != -1 && prop.prf != -1 && -+ prop.encr != -1 && prop.dh != -1) { -+ found = 1; -+ } -+ -+ pos += plen; -+ -+ /* Only one proposal expected in SAr */ -+ break; -+ } -+ -+ if (pos != end) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposal"); -+ return -1; -+ } -+ -+ if (!found) { -+ wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " -+ "INTEG:%d D-H:%d", data->proposal.proposal_num, -+ data->proposal.encr, data->proposal.prf, -+ data->proposal.integ, data->proposal.dh); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_ker(struct ikev2_initiator_data *data, -+ const u8 *ker, size_t ker_len) -+{ -+ u16 group; -+ -+ /* -+ * Key Exchange Payload: -+ * DH Group # (16 bits) -+ * RESERVED (16 bits) -+ * Key Exchange Data (Diffie-Hellman public value) -+ */ -+ -+ if (ker == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: KEr not received"); -+ return -1; -+ } -+ -+ if (ker_len < 4 + 96) { -+ wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload"); -+ return -1; -+ } -+ -+ group = WPA_GET_BE16(ker); -+ wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u", group); -+ -+ if (group != data->proposal.dh) { -+ wpa_printf(MSG_DEBUG, "IKEV2: KEr DH Group #%u does not match " -+ "with the selected proposal (%u)", -+ group, data->proposal.dh); -+ return -1; -+ } -+ -+ if (data->dh == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); -+ return -1; -+ } -+ -+ /* RFC 4306, Section 3.4: -+ * The length of DH public value MUST be equal to the lenght of the -+ * prime modulus. -+ */ -+ if (ker_len - 4 != data->dh->prime_len) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " -+ "%ld (expected %ld)", -+ (long) (ker_len - 4), (long) data->dh->prime_len); -+ return -1; -+ } -+ -+ wpabuf_free(data->r_dh_public); -+ data->r_dh_public = wpabuf_alloc_copy(ker + 4, ker_len - 4); -+ if (data->r_dh_public == NULL) -+ return -1; -+ -+ wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEr Diffie-Hellman Public Value", -+ data->r_dh_public); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_nr(struct ikev2_initiator_data *data, -+ const u8 *nr, size_t nr_len) -+{ -+ if (nr == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Nr not received"); -+ return -1; -+ } -+ -+ if (nr_len < IKEV2_NONCE_MIN_LEN || nr_len > IKEV2_NONCE_MAX_LEN) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid Nr length %ld", -+ (long) nr_len); -+ return -1; -+ } -+ -+ data->r_nonce_len = nr_len; -+ os_memcpy(data->r_nonce, nr, nr_len); -+ wpa_hexdump(MSG_MSGDUMP, "IKEV2: Nr", -+ data->r_nonce, data->r_nonce_len); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_sa_init_encr(struct ikev2_initiator_data *data, -+ const struct ikev2_hdr *hdr, -+ const u8 *encrypted, -+ size_t encrypted_len, u8 next_payload) -+{ -+ u8 *decrypted; -+ size_t decrypted_len; -+ struct ikev2_payloads pl; -+ int ret = 0; -+ -+ decrypted = ikev2_decrypt_payload(data->proposal.encr, -+ data->proposal.integ, &data->keys, 0, -+ hdr, encrypted, encrypted_len, -+ &decrypted_len); -+ if (decrypted == NULL) -+ return -1; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); -+ -+ if (ikev2_parse_payloads(&pl, next_payload, decrypted, -+ decrypted + decrypted_len) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " -+ "payloads"); -+ return -1; -+ } -+ -+ if (pl.idr) -+ ret = ikev2_process_idr(data, pl.idr, pl.idr_len); -+ -+ os_free(decrypted); -+ -+ return ret; -+} -+ -+ -+static int ikev2_process_sa_init(struct ikev2_initiator_data *data, -+ const struct ikev2_hdr *hdr, -+ struct ikev2_payloads *pl) -+{ -+ if (ikev2_process_sar1(data, pl->sa, pl->sa_len) < 0 || -+ ikev2_process_ker(data, pl->ke, pl->ke_len) < 0 || -+ ikev2_process_nr(data, pl->nonce, pl->nonce_len) < 0) -+ return -1; -+ -+ os_memcpy(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN); -+ -+ if (ikev2_derive_keys(data) < 0) -+ return -1; -+ -+ if (pl->encrypted) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Encrypted payload in SA_INIT - " -+ "try to get IDr from it"); -+ if (ikev2_process_sa_init_encr(data, hdr, pl->encrypted, -+ pl->encrypted_len, -+ pl->encr_next_payload) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Failed to process " -+ "encrypted payload"); -+ return -1; -+ } -+ } -+ -+ data->state = SA_AUTH; -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_idr(struct ikev2_initiator_data *data, -+ const u8 *idr, size_t idr_len) -+{ -+ u8 id_type; -+ -+ if (idr == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No IDr received"); -+ return -1; -+ } -+ -+ if (idr_len < 4) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short IDr payload"); -+ return -1; -+ } -+ -+ id_type = idr[0]; -+ idr += 4; -+ idr_len -= 4; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: IDr ID Type %d", id_type); -+ wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDr", idr, idr_len); -+ if (data->IDr) { -+ if (id_type != data->IDr_type || idr_len != data->IDr_len || -+ os_memcmp(idr, data->IDr, idr_len) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: IDr differs from the one " -+ "received earlier"); -+ wpa_printf(MSG_DEBUG, "IKEV2: Previous IDr ID Type %d", -+ id_type); -+ wpa_hexdump_ascii(MSG_DEBUG, "Previous IKEV2: IDr", -+ data->IDr, data->IDr_len); -+ return -1; -+ } -+ os_free(data->IDr); -+ } -+ data->IDr = os_malloc(idr_len); -+ if (data->IDr == NULL) -+ return -1; -+ os_memcpy(data->IDr, idr, idr_len); -+ data->IDr_len = idr_len; -+ data->IDr_type = id_type; -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_cert(struct ikev2_initiator_data *data, -+ const u8 *cert, size_t cert_len) -+{ -+ u8 cert_encoding; -+ -+ if (cert == NULL) { -+ if (data->peer_auth == PEER_AUTH_CERT) { -+ wpa_printf(MSG_INFO, "IKEV2: No Certificate received"); -+ return -1; -+ } -+ return 0; -+ } -+ -+ if (cert_len < 1) { -+ wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field"); -+ return -1; -+ } -+ -+ cert_encoding = cert[0]; -+ cert++; -+ cert_len--; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding); -+ wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len); -+ -+ /* TODO: validate certificate */ -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_auth_cert(struct ikev2_initiator_data *data, -+ u8 method, const u8 *auth, size_t auth_len) -+{ -+ if (method != AUTH_RSA_SIGN) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " -+ "method %d", method); -+ return -1; -+ } -+ -+ /* TODO: validate AUTH */ -+ return 0; -+} -+ -+ -+static int ikev2_process_auth_secret(struct ikev2_initiator_data *data, -+ u8 method, const u8 *auth, -+ size_t auth_len) -+{ -+ u8 auth_data[IKEV2_MAX_HASH_LEN]; -+ const struct ikev2_prf_alg *prf; -+ -+ if (method != AUTH_SHARED_KEY_MIC) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " -+ "method %d", method); -+ return -1; -+ } -+ -+ /* msg | Ni | prf(SK_pr,IDr') */ -+ if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, -+ data->IDr, data->IDr_len, data->IDr_type, -+ &data->keys, 0, data->shared_secret, -+ data->shared_secret_len, -+ data->i_nonce, data->i_nonce_len, -+ data->key_pad, data->key_pad_len, -+ auth_data) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); -+ return -1; -+ } -+ -+ wpabuf_free(data->r_sign_msg); -+ data->r_sign_msg = NULL; -+ -+ prf = ikev2_get_prf(data->proposal.prf); -+ if (prf == NULL) -+ return -1; -+ -+ if (auth_len != prf->hash_len || -+ os_memcmp(auth, auth_data, auth_len) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", -+ auth, auth_len); -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", -+ auth_data, prf->hash_len); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Peer authenticated successfully " -+ "using shared keys"); -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_auth(struct ikev2_initiator_data *data, -+ const u8 *auth, size_t auth_len) -+{ -+ u8 auth_method; -+ -+ if (auth == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); -+ return -1; -+ } -+ -+ if (auth_len < 4) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " -+ "Payload"); -+ return -1; -+ } -+ -+ auth_method = auth[0]; -+ auth += 4; -+ auth_len -= 4; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); -+ wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); -+ -+ switch (data->peer_auth) { -+ case PEER_AUTH_CERT: -+ return ikev2_process_auth_cert(data, auth_method, auth, -+ auth_len); -+ case PEER_AUTH_SECRET: -+ return ikev2_process_auth_secret(data, auth_method, auth, -+ auth_len); -+ } -+ -+ return -1; -+} -+ -+ -+static int ikev2_process_sa_auth_decrypted(struct ikev2_initiator_data *data, -+ u8 next_payload, -+ u8 *payload, size_t payload_len) -+{ -+ struct ikev2_payloads pl; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); -+ -+ if (ikev2_parse_payloads(&pl, next_payload, payload, payload + -+ payload_len) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " -+ "payloads"); -+ return -1; -+ } -+ -+ if (ikev2_process_idr(data, pl.idr, pl.idr_len) < 0 || -+ ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || -+ ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) -+ return -1; -+ -+ return 0; -+} -+ -+ -+static int ikev2_process_sa_auth(struct ikev2_initiator_data *data, -+ const struct ikev2_hdr *hdr, -+ struct ikev2_payloads *pl) -+{ -+ u8 *decrypted; -+ size_t decrypted_len; -+ int ret; -+ -+ decrypted = ikev2_decrypt_payload(data->proposal.encr, -+ data->proposal.integ, -+ &data->keys, 0, hdr, pl->encrypted, -+ pl->encrypted_len, &decrypted_len); -+ if (decrypted == NULL) -+ return -1; -+ -+ ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, -+ decrypted, decrypted_len); -+ os_free(decrypted); -+ -+ if (ret == 0 && !data->unknown_user) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Authentication completed"); -+ data->state = IKEV2_DONE; -+ } -+ -+ return ret; -+} -+ -+ -+static int ikev2_validate_rx_state(struct ikev2_initiator_data *data, -+ u8 exchange_type, u32 message_id) -+{ -+ switch (data->state) { -+ case SA_INIT: -+ /* Expect to receive IKE_SA_INIT: HDR, SAr, KEr, Nr, [CERTREQ], -+ * [SK{IDr}] */ -+ if (exchange_type != IKE_SA_INIT) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " -+ "%u in SA_INIT state", exchange_type); -+ return -1; -+ } -+ if (message_id != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " -+ "in SA_INIT state", message_id); -+ return -1; -+ } -+ break; -+ case SA_AUTH: -+ /* Expect to receive IKE_SA_AUTH: -+ * HDR, SK {IDr, [CERT,] [CERTREQ,] [NFID,] AUTH} -+ */ -+ if (exchange_type != IKE_SA_AUTH) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " -+ "%u in SA_AUTH state", exchange_type); -+ return -1; -+ } -+ if (message_id != 1) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " -+ "in SA_AUTH state", message_id); -+ return -1; -+ } -+ break; -+ case CHILD_SA: -+ if (exchange_type != CREATE_CHILD_SA) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " -+ "%u in CHILD_SA state", exchange_type); -+ return -1; -+ } -+ if (message_id != 2) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " -+ "in CHILD_SA state", message_id); -+ return -1; -+ } -+ break; -+ case IKEV2_DONE: -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int ikev2_initiator_process(struct ikev2_initiator_data *data, -+ const struct wpabuf *buf) -+{ -+ const struct ikev2_hdr *hdr; -+ u32 length, message_id; -+ const u8 *pos, *end; -+ struct ikev2_payloads pl; -+ -+ wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", -+ (unsigned long) wpabuf_len(buf)); -+ -+ if (wpabuf_len(buf) < sizeof(*hdr)) { -+ wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); -+ return -1; -+ } -+ -+ hdr = (const struct ikev2_hdr *) wpabuf_head(buf); -+ end = wpabuf_head_u8(buf) + wpabuf_len(buf); -+ message_id = WPA_GET_BE32(hdr->message_id); -+ length = WPA_GET_BE32(hdr->length); -+ -+ wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", -+ hdr->i_spi, IKEV2_SPI_LEN); -+ wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", -+ hdr->r_spi, IKEV2_SPI_LEN); -+ wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " -+ "Exchange Type: %u", -+ hdr->next_payload, hdr->version, hdr->exchange_type); -+ wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", -+ message_id, length); -+ -+ if (hdr->version != IKEV2_VERSION) { -+ wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " -+ "(expected 0x%x)", hdr->version, IKEV2_VERSION); -+ return -1; -+ } -+ -+ if (length != wpabuf_len(buf)) { -+ wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " -+ "RX: %lu)", (unsigned long) length, -+ (unsigned long) wpabuf_len(buf)); -+ return -1; -+ } -+ -+ if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) -+ return -1; -+ -+ if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != -+ IKEV2_HDR_RESPONSE) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", -+ hdr->flags); -+ return -1; -+ } -+ -+ if (data->state != SA_INIT) { -+ if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " -+ "Initiator's SPI"); -+ return -1; -+ } -+ if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " -+ "Responder's SPI"); -+ return -1; -+ } -+ } -+ -+ pos = (const u8 *) (hdr + 1); -+ if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) -+ return -1; -+ -+ switch (data->state) { -+ case SA_INIT: -+ if (ikev2_process_sa_init(data, hdr, &pl) < 0) -+ return -1; -+ wpabuf_free(data->r_sign_msg); -+ data->r_sign_msg = wpabuf_dup(buf); -+ break; -+ case SA_AUTH: -+ if (ikev2_process_sa_auth(data, hdr, &pl) < 0) -+ return -1; -+ break; -+ case CHILD_SA: -+ case IKEV2_DONE: -+ break; -+ } -+ -+ return 0; -+} -+ -+ -+static void ikev2_build_hdr(struct ikev2_initiator_data *data, -+ struct wpabuf *msg, u8 exchange_type, -+ u8 next_payload, u32 message_id) -+{ -+ struct ikev2_hdr *hdr; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); -+ -+ /* HDR - RFC 4306, Sect. 3.1 */ -+ hdr = wpabuf_put(msg, sizeof(*hdr)); -+ os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); -+ os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); -+ hdr->next_payload = next_payload; -+ hdr->version = IKEV2_VERSION; -+ hdr->exchange_type = exchange_type; -+ hdr->flags = IKEV2_HDR_INITIATOR; -+ WPA_PUT_BE32(hdr->message_id, message_id); -+} -+ -+ -+static int ikev2_build_sai(struct ikev2_initiator_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ struct ikev2_proposal *p; -+ struct ikev2_transform *t; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding SAi payload"); -+ -+ /* SAi1 - RFC 4306, Sect. 2.7 and 3.3 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ -+ /* TODO: support for multiple proposals */ -+ p = wpabuf_put(msg, sizeof(*p)); -+ p->proposal_num = data->proposal.proposal_num; -+ p->protocol_id = IKEV2_PROTOCOL_IKE; -+ p->num_transforms = 4; -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ t->type = 3; -+ t->transform_type = IKEV2_TRANSFORM_ENCR; -+ WPA_PUT_BE16(t->transform_id, data->proposal.encr); -+ if (data->proposal.encr == ENCR_AES_CBC) { -+ /* Transform Attribute: Key Len = 128 bits */ -+ wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ -+ wpabuf_put_be16(msg, 128); /* 128-bit key */ -+ } -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; -+ WPA_PUT_BE16(t->transform_length, plen); -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ t->type = 3; -+ WPA_PUT_BE16(t->transform_length, sizeof(*t)); -+ t->transform_type = IKEV2_TRANSFORM_PRF; -+ WPA_PUT_BE16(t->transform_id, data->proposal.prf); -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ t->type = 3; -+ WPA_PUT_BE16(t->transform_length, sizeof(*t)); -+ t->transform_type = IKEV2_TRANSFORM_INTEG; -+ WPA_PUT_BE16(t->transform_id, data->proposal.integ); -+ -+ t = wpabuf_put(msg, sizeof(*t)); -+ WPA_PUT_BE16(t->transform_length, sizeof(*t)); -+ t->transform_type = IKEV2_TRANSFORM_DH; -+ WPA_PUT_BE16(t->transform_id, data->proposal.dh); -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; -+ WPA_PUT_BE16(p->proposal_length, plen); -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ -+ return 0; -+} -+ -+ -+static int ikev2_build_kei(struct ikev2_initiator_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ struct wpabuf *pv; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding KEi payload"); -+ -+ data->dh = dh_groups_get(data->proposal.dh); -+ pv = dh_init(data->dh, &data->i_dh_private); -+ if (pv == NULL) { -+ wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); -+ return -1; -+ } -+ -+ /* KEi - RFC 4306, Sect. 3.4 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ -+ wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ -+ wpabuf_put(msg, 2); /* RESERVED */ -+ /* -+ * RFC 4306, Sect. 3.4: possible zero padding for public value to -+ * match the length of the prime. -+ */ -+ wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); -+ wpabuf_put_buf(msg, pv); -+ os_free(pv); -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static int ikev2_build_ni(struct ikev2_initiator_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding Ni payload"); -+ -+ /* Ni - RFC 4306, Sect. 3.9 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ wpabuf_put_data(msg, data->i_nonce, data->i_nonce_len); -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static int ikev2_build_idi(struct ikev2_initiator_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding IDi payload"); -+ -+ if (data->IDi == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: No IDi available"); -+ return -1; -+ } -+ -+ /* IDi - RFC 4306, Sect. 3.5 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ wpabuf_put_u8(msg, ID_KEY_ID); -+ wpabuf_put(msg, 3); /* RESERVED */ -+ wpabuf_put_data(msg, data->IDi, data->IDi_len); -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static int ikev2_build_auth(struct ikev2_initiator_data *data, -+ struct wpabuf *msg, u8 next_payload) -+{ -+ struct ikev2_payload_hdr *phdr; -+ size_t plen; -+ const struct ikev2_prf_alg *prf; -+ -+ wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); -+ -+ prf = ikev2_get_prf(data->proposal.prf); -+ if (prf == NULL) -+ return -1; -+ -+ /* Authentication - RFC 4306, Sect. 3.8 */ -+ phdr = wpabuf_put(msg, sizeof(*phdr)); -+ phdr->next_payload = next_payload; -+ phdr->flags = 0; -+ wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); -+ wpabuf_put(msg, 3); /* RESERVED */ -+ -+ /* msg | Nr | prf(SK_pi,IDi') */ -+ if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, -+ data->IDi, data->IDi_len, ID_KEY_ID, -+ &data->keys, 1, data->shared_secret, -+ data->shared_secret_len, -+ data->r_nonce, data->r_nonce_len, -+ data->key_pad, data->key_pad_len, -+ wpabuf_put(msg, prf->hash_len)) < 0) { -+ wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); -+ return -1; -+ } -+ wpabuf_free(data->i_sign_msg); -+ data->i_sign_msg = NULL; -+ -+ plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; -+ WPA_PUT_BE16(phdr->payload_length, plen); -+ return 0; -+} -+ -+ -+static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data) -+{ -+ struct wpabuf *msg; -+ -+ /* build IKE_SA_INIT: HDR, SAi, KEi, Ni */ -+ -+ if (os_get_random(data->i_spi, IKEV2_SPI_LEN)) -+ return NULL; -+ wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", -+ data->i_spi, IKEV2_SPI_LEN); -+ -+ data->i_nonce_len = IKEV2_NONCE_MIN_LEN; -+ if (random_get_bytes(data->i_nonce, data->i_nonce_len)) -+ return NULL; -+ wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len); -+ -+ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); -+ if (msg == NULL) -+ return NULL; -+ -+ ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); -+ if (ikev2_build_sai(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || -+ ikev2_build_kei(data, msg, IKEV2_PAYLOAD_NONCE) || -+ ikev2_build_ni(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ -+ ikev2_update_hdr(msg); -+ -+ wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); -+ -+ wpabuf_free(data->i_sign_msg); -+ data->i_sign_msg = wpabuf_dup(msg); -+ -+ return msg; -+} -+ -+ -+static struct wpabuf * ikev2_build_sa_auth(struct ikev2_initiator_data *data) -+{ -+ struct wpabuf *msg, *plain; -+ const u8 *secret; -+ size_t secret_len; -+ -+ secret = data->get_shared_secret(data->cb_ctx, data->IDr, -+ data->IDr_len, &secret_len); -+ if (secret == NULL) { -+ wpa_printf(MSG_INFO, "IKEV2: Could not get shared secret - " -+ "use fake value"); -+ /* RFC 5106, Sect. 7: -+ * Use a random key to fake AUTH generation in order to prevent -+ * probing of user identities. -+ */ -+ data->unknown_user = 1; -+ os_free(data->shared_secret); -+ data->shared_secret = os_malloc(16); -+ if (data->shared_secret == NULL) -+ return NULL; -+ data->shared_secret_len = 16; -+ if (random_get_bytes(data->shared_secret, 16)) -+ return NULL; -+ } else { -+ os_free(data->shared_secret); -+ data->shared_secret = os_malloc(secret_len); -+ if (data->shared_secret == NULL) -+ return NULL; -+ os_memcpy(data->shared_secret, secret, secret_len); -+ data->shared_secret_len = secret_len; -+ } -+ -+ /* build IKE_SA_AUTH: HDR, SK {IDi, [CERT,] [CERTREQ,] AUTH} */ -+ -+ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); -+ if (msg == NULL) -+ return NULL; -+ ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); -+ -+ plain = wpabuf_alloc(data->IDr_len + 1000); -+ if (plain == NULL) { -+ wpabuf_free(msg); -+ return NULL; -+ } -+ -+ if (ikev2_build_idi(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || -+ ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || -+ ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, -+ &data->keys, 1, msg, plain, -+ IKEV2_PAYLOAD_IDi)) { -+ wpabuf_free(plain); -+ wpabuf_free(msg); -+ return NULL; -+ } -+ wpabuf_free(plain); -+ -+ wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); -+ -+ return msg; -+} -+ -+ -+struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data) -+{ -+ switch (data->state) { -+ case SA_INIT: -+ return ikev2_build_sa_init(data); -+ case SA_AUTH: -+ return ikev2_build_sa_auth(data); -+ case CHILD_SA: -+ return NULL; -+ case IKEV2_DONE: -+ return NULL; -+ } -+ return NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.h -new file mode 100644 -index 0000000000000..8349fbe62de60 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/ikev2.h -@@ -0,0 +1,67 @@ -+/* -+ * IKEv2 initiator (RFC 4306) for EAP-IKEV2 -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IKEV2_H -+#define IKEV2_H -+ -+#include "eap_common/ikev2_common.h" -+ -+struct ikev2_proposal_data { -+ u8 proposal_num; -+ int integ; -+ int prf; -+ int encr; -+ int dh; -+}; -+ -+ -+struct ikev2_initiator_data { -+ enum { SA_INIT, SA_AUTH, CHILD_SA, IKEV2_DONE } state; -+ u8 i_spi[IKEV2_SPI_LEN]; -+ u8 r_spi[IKEV2_SPI_LEN]; -+ u8 i_nonce[IKEV2_NONCE_MAX_LEN]; -+ size_t i_nonce_len; -+ u8 r_nonce[IKEV2_NONCE_MAX_LEN]; -+ size_t r_nonce_len; -+ struct wpabuf *r_dh_public; -+ struct wpabuf *i_dh_private; -+ struct ikev2_proposal_data proposal; -+ const struct dh_group *dh; -+ struct ikev2_keys keys; -+ u8 *IDi; -+ size_t IDi_len; -+ u8 *IDr; -+ size_t IDr_len; -+ u8 IDr_type; -+ struct wpabuf *r_sign_msg; -+ struct wpabuf *i_sign_msg; -+ u8 *shared_secret; -+ size_t shared_secret_len; -+ enum { PEER_AUTH_CERT, PEER_AUTH_SECRET } peer_auth; -+ u8 *key_pad; -+ size_t key_pad_len; -+ -+ const u8 * (*get_shared_secret)(void *ctx, const u8 *IDr, -+ size_t IDr_len, size_t *secret_len); -+ void *cb_ctx; -+ int unknown_user; -+}; -+ -+ -+void ikev2_initiator_deinit(struct ikev2_initiator_data *data); -+int ikev2_initiator_process(struct ikev2_initiator_data *data, -+ const struct wpabuf *buf); -+struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data); -+ -+#endif /* IKEV2_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.c -new file mode 100644 -index 0000000000000..637b6f88de427 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.c -@@ -0,0 +1,1273 @@ -+/* -+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) -+ * Copyright (c) 2007-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "base64.h" -+#include "tncs.h" -+#include "eap_common/eap_tlv_common.h" -+#include "eap_common/eap_defs.h" -+ -+ -+/* TODO: TNCS must be thread-safe; review the code and add locking etc. if -+ * needed.. */ -+ -+#define TNC_CONFIG_FILE "/etc/tnc_config" -+#define IF_TNCCS_START \ -+"\n" \ -+"\n" -+#define IF_TNCCS_END "\n" -+ -+/* TNC IF-IMV */ -+ -+typedef unsigned long TNC_UInt32; -+typedef unsigned char *TNC_BufferReference; -+ -+typedef TNC_UInt32 TNC_IMVID; -+typedef TNC_UInt32 TNC_ConnectionID; -+typedef TNC_UInt32 TNC_ConnectionState; -+typedef TNC_UInt32 TNC_RetryReason; -+typedef TNC_UInt32 TNC_IMV_Action_Recommendation; -+typedef TNC_UInt32 TNC_IMV_Evaluation_Result; -+typedef TNC_UInt32 TNC_MessageType; -+typedef TNC_MessageType *TNC_MessageTypeList; -+typedef TNC_UInt32 TNC_VendorID; -+typedef TNC_UInt32 TNC_Subtype; -+typedef TNC_UInt32 TNC_Version; -+typedef TNC_UInt32 TNC_Result; -+typedef TNC_UInt32 TNC_AttributeID; -+ -+typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)( -+ TNC_IMVID imvID, -+ char *functionName, -+ void **pOutfunctionPointer); -+ -+#define TNC_RESULT_SUCCESS 0 -+#define TNC_RESULT_NOT_INITIALIZED 1 -+#define TNC_RESULT_ALREADY_INITIALIZED 2 -+#define TNC_RESULT_NO_COMMON_VERSION 3 -+#define TNC_RESULT_CANT_RETRY 4 -+#define TNC_RESULT_WONT_RETRY 5 -+#define TNC_RESULT_INVALID_PARAMETER 6 -+#define TNC_RESULT_CANT_RESPOND 7 -+#define TNC_RESULT_ILLEGAL_OPERATION 8 -+#define TNC_RESULT_OTHER 9 -+#define TNC_RESULT_FATAL 10 -+ -+#define TNC_CONNECTION_STATE_CREATE 0 -+#define TNC_CONNECTION_STATE_HANDSHAKE 1 -+#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 -+#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3 -+#define TNC_CONNECTION_STATE_ACCESS_NONE 4 -+#define TNC_CONNECTION_STATE_DELETE 5 -+ -+#define TNC_IFIMV_VERSION_1 1 -+ -+#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) -+#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff) -+ -+/* TNCC-TNCS Message Types */ -+#define TNC_TNCCS_RECOMMENDATION 0x00000001 -+#define TNC_TNCCS_ERROR 0x00000002 -+#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003 -+#define TNC_TNCCS_REASONSTRINGS 0x00000004 -+ -+/* Possible TNC_IMV_Action_Recommendation values: */ -+enum IMV_Action_Recommendation { -+ TNC_IMV_ACTION_RECOMMENDATION_ALLOW, -+ TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, -+ TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, -+ TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION -+}; -+ -+/* Possible TNC_IMV_Evaluation_Result values: */ -+enum IMV_Evaluation_Result { -+ TNC_IMV_EVALUATION_RESULT_COMPLIANT, -+ TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR, -+ TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR, -+ TNC_IMV_EVALUATION_RESULT_ERROR, -+ TNC_IMV_EVALUATION_RESULT_DONT_KNOW -+}; -+ -+struct tnc_if_imv { -+ struct tnc_if_imv *next; -+ char *name; -+ char *path; -+ void *dlhandle; /* from dlopen() */ -+ TNC_IMVID imvID; -+ TNC_MessageTypeList supported_types; -+ size_t num_supported_types; -+ -+ /* Functions implemented by IMVs (with TNC_IMV_ prefix) */ -+ TNC_Result (*Initialize)( -+ TNC_IMVID imvID, -+ TNC_Version minVersion, -+ TNC_Version maxVersion, -+ TNC_Version *pOutActualVersion); -+ TNC_Result (*NotifyConnectionChange)( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID, -+ TNC_ConnectionState newState); -+ TNC_Result (*ReceiveMessage)( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID, -+ TNC_BufferReference message, -+ TNC_UInt32 messageLength, -+ TNC_MessageType messageType); -+ TNC_Result (*SolicitRecommendation)( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID); -+ TNC_Result (*BatchEnding)( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID); -+ TNC_Result (*Terminate)(TNC_IMVID imvID); -+ TNC_Result (*ProvideBindFunction)( -+ TNC_IMVID imvID, -+ TNC_TNCS_BindFunctionPointer bindFunction); -+}; -+ -+ -+#define TNC_MAX_IMV_ID 10 -+ -+struct tncs_data { -+ struct tncs_data *next; -+ struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */ -+ TNC_ConnectionID connectionID; -+ unsigned int last_batchid; -+ enum IMV_Action_Recommendation recommendation; -+ int done; -+ -+ struct conn_imv { -+ u8 *imv_send; -+ size_t imv_send_len; -+ enum IMV_Action_Recommendation recommendation; -+ int recommendation_set; -+ } imv_data[TNC_MAX_IMV_ID]; -+ -+ char *tncs_message; -+}; -+ -+ -+struct tncs_global { -+ struct tnc_if_imv *imv; -+ TNC_ConnectionID next_conn_id; -+ struct tncs_data *connections; -+}; -+ -+static struct tncs_global *tncs_global_data = NULL; -+ -+ -+static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID) -+{ -+ struct tnc_if_imv *imv; -+ -+ if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL) -+ return NULL; -+ imv = tncs_global_data->imv; -+ while (imv) { -+ if (imv->imvID == imvID) -+ return imv; -+ imv = imv->next; -+ } -+ return NULL; -+} -+ -+ -+static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID) -+{ -+ struct tncs_data *tncs; -+ -+ if (tncs_global_data == NULL) -+ return NULL; -+ -+ tncs = tncs_global_data->connections; -+ while (tncs) { -+ if (tncs->connectionID == connectionID) -+ return tncs; -+ tncs = tncs->next; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found", -+ (unsigned long) connectionID); -+ -+ return NULL; -+} -+ -+ -+/* TNCS functions that IMVs can call */ -+TNC_Result TNC_TNCS_ReportMessageTypes( -+ TNC_IMVID imvID, -+ TNC_MessageTypeList supportedTypes, -+ TNC_UInt32 typeCount) -+{ -+ TNC_UInt32 i; -+ struct tnc_if_imv *imv; -+ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu " -+ "typeCount=%lu)", -+ (unsigned long) imvID, (unsigned long) typeCount); -+ -+ for (i = 0; i < typeCount; i++) { -+ wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", -+ i, supportedTypes[i]); -+ } -+ -+ imv = tncs_get_imv(imvID); -+ if (imv == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ os_free(imv->supported_types); -+ imv->supported_types = -+ os_malloc(typeCount * sizeof(TNC_MessageType)); -+ if (imv->supported_types == NULL) -+ return TNC_RESULT_FATAL; -+ os_memcpy(imv->supported_types, supportedTypes, -+ typeCount * sizeof(TNC_MessageType)); -+ imv->num_supported_types = typeCount; -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCS_SendMessage( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID, -+ TNC_BufferReference message, -+ TNC_UInt32 messageLength, -+ TNC_MessageType messageType) -+{ -+ struct tncs_data *tncs; -+ unsigned char *b64; -+ size_t b64len; -+ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu " -+ "connectionID=%lu messageType=%lu)", -+ imvID, connectionID, messageType); -+ wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage", -+ message, messageLength); -+ -+ if (tncs_get_imv(imvID) == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ tncs = tncs_get_conn(connectionID); -+ if (tncs == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ b64 = base64_encode(message, messageLength, &b64len); -+ if (b64 == NULL) -+ return TNC_RESULT_FATAL; -+ -+ os_free(tncs->imv_data[imvID].imv_send); -+ tncs->imv_data[imvID].imv_send_len = 0; -+ tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100); -+ if (tncs->imv_data[imvID].imv_send == NULL) { -+ os_free(b64); -+ return TNC_RESULT_OTHER; -+ } -+ -+ tncs->imv_data[imvID].imv_send_len = -+ os_snprintf((char *) tncs->imv_data[imvID].imv_send, -+ b64len + 100, -+ "%08X" -+ "%s", -+ (unsigned int) messageType, b64); -+ -+ os_free(b64); -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCS_RequestHandshakeRetry( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID, -+ TNC_RetryReason reason) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry"); -+ /* TODO */ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCS_ProvideRecommendation( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID, -+ TNC_IMV_Action_Recommendation recommendation, -+ TNC_IMV_Evaluation_Result evaluation) -+{ -+ struct tncs_data *tncs; -+ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu " -+ "connectionID=%lu recommendation=%lu evaluation=%lu)", -+ (unsigned long) imvID, (unsigned long) connectionID, -+ (unsigned long) recommendation, (unsigned long) evaluation); -+ -+ if (tncs_get_imv(imvID) == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ tncs = tncs_get_conn(connectionID); -+ if (tncs == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ tncs->imv_data[imvID].recommendation = recommendation; -+ tncs->imv_data[imvID].recommendation_set = 1; -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCS_GetAttribute( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID, -+ TNC_AttributeID attribureID, -+ TNC_UInt32 bufferLength, -+ TNC_BufferReference buffer, -+ TNC_UInt32 *pOutValueLength) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute"); -+ /* TODO */ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCS_SetAttribute( -+ TNC_IMVID imvID, -+ TNC_ConnectionID connectionID, -+ TNC_AttributeID attribureID, -+ TNC_UInt32 bufferLength, -+ TNC_BufferReference buffer) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute"); -+ /* TODO */ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+TNC_Result TNC_TNCS_BindFunction( -+ TNC_IMVID imvID, -+ char *functionName, -+ void **pOutFunctionPointer) -+{ -+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, " -+ "functionName='%s')", (unsigned long) imvID, functionName); -+ -+ if (tncs_get_imv(imvID) == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ if (pOutFunctionPointer == NULL) -+ return TNC_RESULT_INVALID_PARAMETER; -+ -+ if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0) -+ *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes; -+ else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0) -+ *pOutFunctionPointer = TNC_TNCS_SendMessage; -+ else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") == -+ 0) -+ *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry; -+ else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") == -+ 0) -+ *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation; -+ else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0) -+ *pOutFunctionPointer = TNC_TNCS_GetAttribute; -+ else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0) -+ *pOutFunctionPointer = TNC_TNCS_SetAttribute; -+ else -+ *pOutFunctionPointer = NULL; -+ -+ return TNC_RESULT_SUCCESS; -+} -+ -+ -+static void * tncs_get_sym(void *handle, char *func) -+{ -+ void *fptr; -+ -+ fptr = dlsym(handle, func); -+ -+ return fptr; -+} -+ -+ -+static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv) -+{ -+ void *handle = imv->dlhandle; -+ -+ /* Mandatory IMV functions */ -+ imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize"); -+ if (imv->Initialize == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: IMV does not export " -+ "TNC_IMV_Initialize"); -+ return -1; -+ } -+ -+ imv->SolicitRecommendation = tncs_get_sym( -+ handle, "TNC_IMV_SolicitRecommendation"); -+ if (imv->SolicitRecommendation == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: IMV does not export " -+ "TNC_IMV_SolicitRecommendation"); -+ return -1; -+ } -+ -+ imv->ProvideBindFunction = -+ tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction"); -+ if (imv->ProvideBindFunction == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: IMV does not export " -+ "TNC_IMV_ProvideBindFunction"); -+ return -1; -+ } -+ -+ /* Optional IMV functions */ -+ imv->NotifyConnectionChange = -+ tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange"); -+ imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage"); -+ imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding"); -+ imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate"); -+ -+ return 0; -+} -+ -+ -+static int tncs_imv_initialize(struct tnc_if_imv *imv) -+{ -+ TNC_Result res; -+ TNC_Version imv_ver; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'", -+ imv->name); -+ res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1, -+ TNC_IFIMV_VERSION_1, &imv_ver); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu", -+ (unsigned long) res, (unsigned long) imv_ver); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncs_imv_terminate(struct tnc_if_imv *imv) -+{ -+ TNC_Result res; -+ -+ if (imv->Terminate == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'", -+ imv->name); -+ res = imv->Terminate(imv->imvID); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu", -+ (unsigned long) res); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv) -+{ -+ TNC_Result res; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for " -+ "IMV '%s'", imv->name); -+ res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu", -+ (unsigned long) res); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv, -+ TNC_ConnectionID conn, -+ TNC_ConnectionState state) -+{ -+ TNC_Result res; -+ -+ if (imv->NotifyConnectionChange == NULL) -+ return 0; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)" -+ " for IMV '%s'", (int) state, imv->name); -+ res = imv->NotifyConnectionChange(imv->imvID, conn, state); -+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", -+ (unsigned long) res); -+ -+ return res == TNC_RESULT_SUCCESS ? 0 : -1; -+} -+ -+ -+static int tncs_load_imv(struct tnc_if_imv *imv) -+{ -+ if (imv->path == NULL) { -+ wpa_printf(MSG_DEBUG, "TNC: No IMV configured"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)", -+ imv->name, imv->path); -+ imv->dlhandle = dlopen(imv->path, RTLD_LAZY); -+ if (imv->dlhandle == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s", -+ imv->name, imv->path, dlerror()); -+ return -1; -+ } -+ -+ if (tncs_imv_resolve_funcs(imv) < 0) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions"); -+ return -1; -+ } -+ -+ if (tncs_imv_initialize(imv) < 0 || -+ tncs_imv_provide_bind_function(imv) < 0) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void tncs_free_imv(struct tnc_if_imv *imv) -+{ -+ os_free(imv->name); -+ os_free(imv->path); -+ os_free(imv->supported_types); -+} -+ -+static void tncs_unload_imv(struct tnc_if_imv *imv) -+{ -+ tncs_imv_terminate(imv); -+ -+ if (imv->dlhandle) -+ dlclose(imv->dlhandle); -+ -+ tncs_free_imv(imv); -+} -+ -+ -+static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type) -+{ -+ size_t i; -+ unsigned int vendor, subtype; -+ -+ if (imv == NULL || imv->supported_types == NULL) -+ return 0; -+ -+ vendor = type >> 8; -+ subtype = type & 0xff; -+ -+ for (i = 0; i < imv->num_supported_types; i++) { -+ unsigned int svendor, ssubtype; -+ svendor = imv->supported_types[i] >> 8; -+ ssubtype = imv->supported_types[i] & 0xff; -+ if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && -+ (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type, -+ const u8 *msg, size_t len) -+{ -+ struct tnc_if_imv *imv; -+ TNC_Result res; -+ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len); -+ -+ for (imv = tncs->imv; imv; imv = imv->next) { -+ if (imv->ReceiveMessage == NULL || -+ !tncs_supported_type(imv, type)) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'", -+ imv->name); -+ res = imv->ReceiveMessage(imv->imvID, tncs->connectionID, -+ (TNC_BufferReference) msg, len, -+ type); -+ wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", -+ (unsigned long) res); -+ } -+} -+ -+ -+static void tncs_batch_ending(struct tncs_data *tncs) -+{ -+ struct tnc_if_imv *imv; -+ TNC_Result res; -+ -+ for (imv = tncs->imv; imv; imv = imv->next) { -+ if (imv->BatchEnding == NULL) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'", -+ imv->name); -+ res = imv->BatchEnding(imv->imvID, tncs->connectionID); -+ wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu", -+ (unsigned long) res); -+ } -+} -+ -+ -+static void tncs_solicit_recommendation(struct tncs_data *tncs) -+{ -+ struct tnc_if_imv *imv; -+ TNC_Result res; -+ -+ for (imv = tncs->imv; imv; imv = imv->next) { -+ if (tncs->imv_data[imv->imvID].recommendation_set) -+ continue; -+ -+ wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for " -+ "IMV '%s'", imv->name); -+ res = imv->SolicitRecommendation(imv->imvID, -+ tncs->connectionID); -+ wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu", -+ (unsigned long) res); -+ } -+} -+ -+ -+void tncs_init_connection(struct tncs_data *tncs) -+{ -+ struct tnc_if_imv *imv; -+ int i; -+ -+ for (imv = tncs->imv; imv; imv = imv->next) { -+ tncs_imv_notify_connection_change( -+ imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE); -+ tncs_imv_notify_connection_change( -+ imv, tncs->connectionID, -+ TNC_CONNECTION_STATE_HANDSHAKE); -+ } -+ -+ for (i = 0; i < TNC_MAX_IMV_ID; i++) { -+ os_free(tncs->imv_data[i].imv_send); -+ tncs->imv_data[i].imv_send = NULL; -+ tncs->imv_data[i].imv_send_len = 0; -+ } -+} -+ -+ -+size_t tncs_total_send_len(struct tncs_data *tncs) -+{ -+ int i; -+ size_t len = 0; -+ -+ for (i = 0; i < TNC_MAX_IMV_ID; i++) -+ len += tncs->imv_data[i].imv_send_len; -+ if (tncs->tncs_message) -+ len += os_strlen(tncs->tncs_message); -+ return len; -+} -+ -+ -+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos) -+{ -+ int i; -+ -+ for (i = 0; i < TNC_MAX_IMV_ID; i++) { -+ if (tncs->imv_data[i].imv_send == NULL) -+ continue; -+ -+ os_memcpy(pos, tncs->imv_data[i].imv_send, -+ tncs->imv_data[i].imv_send_len); -+ pos += tncs->imv_data[i].imv_send_len; -+ os_free(tncs->imv_data[i].imv_send); -+ tncs->imv_data[i].imv_send = NULL; -+ tncs->imv_data[i].imv_send_len = 0; -+ } -+ -+ if (tncs->tncs_message) { -+ size_t len = os_strlen(tncs->tncs_message); -+ os_memcpy(pos, tncs->tncs_message, len); -+ pos += len; -+ os_free(tncs->tncs_message); -+ tncs->tncs_message = NULL; -+ } -+ -+ return pos; -+} -+ -+ -+char * tncs_if_tnccs_start(struct tncs_data *tncs) -+{ -+ char *buf = os_malloc(1000); -+ if (buf == NULL) -+ return NULL; -+ tncs->last_batchid++; -+ os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid); -+ return buf; -+} -+ -+ -+char * tncs_if_tnccs_end(void) -+{ -+ char *buf = os_malloc(100); -+ if (buf == NULL) -+ return NULL; -+ os_snprintf(buf, 100, IF_TNCCS_END); -+ return buf; -+} -+ -+ -+static int tncs_get_type(char *start, unsigned int *type) -+{ -+ char *pos = os_strstr(start, ""); -+ if (pos == NULL) -+ return -1; -+ pos += 6; -+ *type = strtoul(pos, NULL, 16); -+ return 0; -+} -+ -+ -+static unsigned char * tncs_get_base64(char *start, size_t *decoded_len) -+{ -+ char *pos, *pos2; -+ unsigned char *decoded; -+ -+ pos = os_strstr(start, ""); -+ if (pos == NULL) -+ return NULL; -+ -+ pos += 8; -+ pos2 = os_strstr(pos, ""); -+ if (pos2 == NULL) -+ return NULL; -+ *pos2 = '\0'; -+ -+ decoded = base64_decode((unsigned char *) pos, os_strlen(pos), -+ decoded_len); -+ *pos2 = '<'; -+ if (decoded == NULL) { -+ wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); -+ } -+ -+ return decoded; -+} -+ -+ -+static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs) -+{ -+ enum IMV_Action_Recommendation rec; -+ struct tnc_if_imv *imv; -+ TNC_ConnectionState state; -+ char *txt; -+ -+ wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs"); -+ -+ if (tncs->done) -+ return TNCCS_PROCESS_OK_NO_RECOMMENDATION; -+ -+ tncs_solicit_recommendation(tncs); -+ -+ /* Select the most restrictive recommendation */ -+ rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; -+ for (imv = tncs->imv; imv; imv = imv->next) { -+ TNC_IMV_Action_Recommendation irec; -+ irec = tncs->imv_data[imv->imvID].recommendation; -+ if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) -+ rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS; -+ if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE && -+ rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) -+ rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE; -+ if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW && -+ rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION) -+ rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec); -+ tncs->recommendation = rec; -+ tncs->done = 1; -+ -+ txt = NULL; -+ switch (rec) { -+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: -+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: -+ txt = "allow"; -+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; -+ break; -+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: -+ txt = "isolate"; -+ state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; -+ break; -+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: -+ txt = "none"; -+ state = TNC_CONNECTION_STATE_ACCESS_NONE; -+ break; -+ default: -+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; -+ break; -+ } -+ -+ if (txt) { -+ os_free(tncs->tncs_message); -+ tncs->tncs_message = os_zalloc(200); -+ if (tncs->tncs_message) { -+ os_snprintf(tncs->tncs_message, 199, -+ "%08X" -+ "" -+ "" -+ "", -+ TNC_TNCCS_RECOMMENDATION, txt); -+ } -+ } -+ -+ for (imv = tncs->imv; imv; imv = imv->next) { -+ tncs_imv_notify_connection_change(imv, tncs->connectionID, -+ state); -+ } -+ -+ switch (rec) { -+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: -+ return TNCCS_RECOMMENDATION_ALLOW; -+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: -+ return TNCCS_RECOMMENDATION_NO_ACCESS; -+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: -+ return TNCCS_RECOMMENDATION_ISOLATE; -+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: -+ return TNCCS_RECOMMENDATION_NO_RECOMMENDATION; -+ default: -+ return TNCCS_PROCESS_ERROR; -+ } -+} -+ -+ -+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs, -+ const u8 *msg, size_t len) -+{ -+ char *buf, *start, *end, *pos, *pos2, *payload; -+ unsigned int batch_id; -+ unsigned char *decoded; -+ size_t decoded_len; -+ -+ buf = os_malloc(len + 1); -+ if (buf == NULL) -+ return TNCCS_PROCESS_ERROR; -+ -+ os_memcpy(buf, msg, len); -+ buf[len] = '\0'; -+ start = os_strstr(buf, ""); -+ if (start == NULL || end == NULL || start > end) { -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ -+ start += 13; -+ while (*start == ' ') -+ start++; -+ *end = '\0'; -+ -+ pos = os_strstr(start, "BatchId="); -+ if (pos == NULL) { -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ -+ pos += 8; -+ if (*pos == '"') -+ pos++; -+ batch_id = atoi(pos); -+ wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", -+ batch_id); -+ if (batch_id != tncs->last_batchid + 1) { -+ wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " -+ "%u (expected %u)", -+ batch_id, tncs->last_batchid + 1); -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ tncs->last_batchid = batch_id; -+ -+ while (*pos != '\0' && *pos != '>') -+ pos++; -+ if (*pos == '\0') { -+ os_free(buf); -+ return TNCCS_PROCESS_ERROR; -+ } -+ pos++; -+ payload = start; -+ -+ /* -+ * -+ * 01234567 -+ * foo== -+ * -+ */ -+ -+ while (*start) { -+ char *endpos; -+ unsigned int type; -+ -+ pos = os_strstr(start, ""); -+ if (pos == NULL) -+ break; -+ start = pos + 17; -+ end = os_strstr(start, ""); -+ if (end == NULL) -+ break; -+ *end = '\0'; -+ endpos = end; -+ end += 18; -+ -+ if (tncs_get_type(start, &type) < 0) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); -+ -+ decoded = tncs_get_base64(start, &decoded_len); -+ if (decoded == NULL) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ -+ tncs_send_to_imvs(tncs, type, decoded, decoded_len); -+ -+ os_free(decoded); -+ -+ start = end; -+ } -+ -+ /* -+ * -+ * 01234567 -+ * -+ * foo== -+ * -+ */ -+ -+ start = payload; -+ while (*start) { -+ unsigned int type; -+ char *xml, *xmlend, *endpos; -+ -+ pos = os_strstr(start, ""); -+ if (pos == NULL) -+ break; -+ start = pos + 19; -+ end = os_strstr(start, ""); -+ if (end == NULL) -+ break; -+ *end = '\0'; -+ endpos = end; -+ end += 20; -+ -+ if (tncs_get_type(start, &type) < 0) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", -+ type); -+ -+ /* Base64 OR XML */ -+ decoded = NULL; -+ xml = NULL; -+ xmlend = NULL; -+ pos = os_strstr(start, ""); -+ if (pos) { -+ pos += 5; -+ pos2 = os_strstr(pos, ""); -+ if (pos2 == NULL) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ xmlend = pos2; -+ xml = pos; -+ } else { -+ decoded = tncs_get_base64(start, &decoded_len); -+ if (decoded == NULL) { -+ *endpos = '<'; -+ start = end; -+ continue; -+ } -+ } -+ -+ if (decoded) { -+ wpa_hexdump_ascii(MSG_MSGDUMP, -+ "TNC: TNCC-TNCS-Message Base64", -+ decoded, decoded_len); -+ os_free(decoded); -+ } -+ -+ if (xml) { -+ wpa_hexdump_ascii(MSG_MSGDUMP, -+ "TNC: TNCC-TNCS-Message XML", -+ (unsigned char *) xml, -+ xmlend - xml); -+ } -+ -+ start = end; -+ } -+ -+ os_free(buf); -+ -+ tncs_batch_ending(tncs); -+ -+ if (tncs_total_send_len(tncs) == 0) -+ return tncs_derive_recommendation(tncs); -+ -+ return TNCCS_PROCESS_OK_NO_RECOMMENDATION; -+} -+ -+ -+static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end, -+ int *error) -+{ -+ struct tnc_if_imv *imv; -+ char *pos, *pos2; -+ -+ if (id >= TNC_MAX_IMV_ID) { -+ wpa_printf(MSG_DEBUG, "TNC: Too many IMVs"); -+ return NULL; -+ } -+ -+ imv = os_zalloc(sizeof(*imv)); -+ if (imv == NULL) { -+ *error = 1; -+ return NULL; -+ } -+ -+ imv->imvID = id; -+ -+ pos = start; -+ wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos); -+ if (pos + 1 >= end || *pos != '"') { -+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " -+ "(no starting quotation mark)", start); -+ os_free(imv); -+ return NULL; -+ } -+ -+ pos++; -+ pos2 = pos; -+ while (pos2 < end && *pos2 != '"') -+ pos2++; -+ if (pos2 >= end) { -+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " -+ "(no ending quotation mark)", start); -+ os_free(imv); -+ return NULL; -+ } -+ *pos2 = '\0'; -+ wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); -+ imv->name = os_strdup(pos); -+ -+ pos = pos2 + 1; -+ if (pos >= end || *pos != ' ') { -+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " -+ "(no space after name)", start); -+ os_free(imv); -+ return NULL; -+ } -+ -+ pos++; -+ wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos); -+ imv->path = os_strdup(pos); -+ -+ return imv; -+} -+ -+ -+static int tncs_read_config(struct tncs_global *global) -+{ -+ char *config, *end, *pos, *line_end; -+ size_t config_len; -+ struct tnc_if_imv *imv, *last; -+ int id = 0; -+ -+ last = NULL; -+ -+ config = os_readfile(TNC_CONFIG_FILE, &config_len); -+ if (config == NULL) { -+ wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " -+ "file '%s'", TNC_CONFIG_FILE); -+ return -1; -+ } -+ -+ end = config + config_len; -+ for (pos = config; pos < end; pos = line_end + 1) { -+ line_end = pos; -+ while (*line_end != '\n' && *line_end != '\r' && -+ line_end < end) -+ line_end++; -+ *line_end = '\0'; -+ -+ if (os_strncmp(pos, "IMV ", 4) == 0) { -+ int error = 0; -+ -+ imv = tncs_parse_imv(id++, pos + 4, line_end, &error); -+ if (error) -+ return -1; -+ if (imv) { -+ if (last == NULL) -+ global->imv = imv; -+ else -+ last->next = imv; -+ last = imv; -+ } -+ } -+ } -+ -+ os_free(config); -+ -+ return 0; -+} -+ -+ -+struct tncs_data * tncs_init(void) -+{ -+ struct tncs_data *tncs; -+ -+ if (tncs_global_data == NULL) -+ return NULL; -+ -+ tncs = os_zalloc(sizeof(*tncs)); -+ if (tncs == NULL) -+ return NULL; -+ tncs->imv = tncs_global_data->imv; -+ tncs->connectionID = tncs_global_data->next_conn_id++; -+ tncs->next = tncs_global_data->connections; -+ tncs_global_data->connections = tncs; -+ -+ return tncs; -+} -+ -+ -+void tncs_deinit(struct tncs_data *tncs) -+{ -+ int i; -+ struct tncs_data *prev, *conn; -+ -+ if (tncs == NULL) -+ return; -+ -+ for (i = 0; i < TNC_MAX_IMV_ID; i++) -+ os_free(tncs->imv_data[i].imv_send); -+ -+ prev = NULL; -+ conn = tncs_global_data->connections; -+ while (conn) { -+ if (conn == tncs) { -+ if (prev) -+ prev->next = tncs->next; -+ else -+ tncs_global_data->connections = tncs->next; -+ break; -+ } -+ prev = conn; -+ conn = conn->next; -+ } -+ -+ os_free(tncs->tncs_message); -+ os_free(tncs); -+} -+ -+ -+int tncs_global_init(void) -+{ -+ struct tnc_if_imv *imv; -+ -+ tncs_global_data = os_zalloc(sizeof(*tncs_global_data)); -+ if (tncs_global_data == NULL) -+ return -1; -+ -+ if (tncs_read_config(tncs_global_data) < 0) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); -+ goto failed; -+ } -+ -+ for (imv = tncs_global_data->imv; imv; imv = imv->next) { -+ if (tncs_load_imv(imv)) { -+ wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'", -+ imv->name); -+ goto failed; -+ } -+ } -+ -+ return 0; -+ -+failed: -+ tncs_global_deinit(); -+ return -1; -+} -+ -+ -+void tncs_global_deinit(void) -+{ -+ struct tnc_if_imv *imv, *prev; -+ -+ if (tncs_global_data == NULL) -+ return; -+ -+ imv = tncs_global_data->imv; -+ while (imv) { -+ tncs_unload_imv(imv); -+ -+ prev = imv; -+ imv = imv->next; -+ os_free(prev); -+ } -+ -+ os_free(tncs_global_data); -+ tncs_global_data = NULL; -+} -+ -+ -+struct wpabuf * tncs_build_soh_request(void) -+{ -+ struct wpabuf *buf; -+ -+ /* -+ * Build a SoH Request TLV (to be used inside SoH EAP Extensions -+ * Method) -+ */ -+ -+ buf = wpabuf_alloc(8 + 4); -+ if (buf == NULL) -+ return NULL; -+ -+ /* Vendor-Specific TLV (Microsoft) - SoH Request */ -+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ -+ wpabuf_put_be16(buf, 8); /* Length */ -+ -+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ -+ -+ wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */ -+ wpabuf_put_be16(buf, 0); /* Length */ -+ -+ return buf; -+} -+ -+ -+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len, -+ int *failure) -+{ -+ wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len); -+ *failure = 0; -+ -+ /* TODO: return MS-SoH Response TLV */ -+ -+ return NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.h -new file mode 100644 -index 0000000000000..18a3a1fa3c474 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eap_server/tncs.h -@@ -0,0 +1,49 @@ -+/* -+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) -+ * Copyright (c) 2007-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TNCS_H -+#define TNCS_H -+ -+struct tncs_data; -+ -+struct tncs_data * tncs_init(void); -+void tncs_deinit(struct tncs_data *tncs); -+void tncs_init_connection(struct tncs_data *tncs); -+size_t tncs_total_send_len(struct tncs_data *tncs); -+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos); -+char * tncs_if_tnccs_start(struct tncs_data *tncs); -+char * tncs_if_tnccs_end(void); -+ -+enum tncs_process_res { -+ TNCCS_PROCESS_ERROR = -1, -+ TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0, -+ TNCCS_RECOMMENDATION_ERROR, -+ TNCCS_RECOMMENDATION_ALLOW, -+ TNCCS_RECOMMENDATION_NONE, -+ TNCCS_RECOMMENDATION_ISOLATE, -+ TNCCS_RECOMMENDATION_NO_ACCESS, -+ TNCCS_RECOMMENDATION_NO_RECOMMENDATION -+}; -+ -+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs, -+ const u8 *msg, size_t len); -+ -+int tncs_global_init(void); -+void tncs_global_deinit(void); -+ -+struct wpabuf * tncs_build_soh_request(void); -+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len, -+ int *failure); -+ -+#endif /* TNCS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_dump.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_dump.c -new file mode 100644 -index 0000000000000..a0f0e8d616691 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_dump.c -@@ -0,0 +1,231 @@ -+/* -+ * IEEE 802.1X-2004 Authenticator - State dump -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eap_server/eap.h" -+#include "eapol_auth_sm.h" -+#include "eapol_auth_sm_i.h" -+ -+static inline const char * port_type_txt(PortTypes pt) -+{ -+ switch (pt) { -+ case ForceUnauthorized: return "ForceUnauthorized"; -+ case ForceAuthorized: return "ForceAuthorized"; -+ case Auto: return "Auto"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * port_state_txt(PortState ps) -+{ -+ switch (ps) { -+ case Unauthorized: return "Unauthorized"; -+ case Authorized: return "Authorized"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * ctrl_dir_txt(ControlledDirection dir) -+{ -+ switch (dir) { -+ case Both: return "Both"; -+ case In: return "In"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * auth_pae_state_txt(int s) -+{ -+ switch (s) { -+ case AUTH_PAE_INITIALIZE: return "INITIALIZE"; -+ case AUTH_PAE_DISCONNECTED: return "DISCONNECTED"; -+ case AUTH_PAE_CONNECTING: return "CONNECTING"; -+ case AUTH_PAE_AUTHENTICATING: return "AUTHENTICATING"; -+ case AUTH_PAE_AUTHENTICATED: return "AUTHENTICATED"; -+ case AUTH_PAE_ABORTING: return "ABORTING"; -+ case AUTH_PAE_HELD: return "HELD"; -+ case AUTH_PAE_FORCE_AUTH: return "FORCE_AUTH"; -+ case AUTH_PAE_FORCE_UNAUTH: return "FORCE_UNAUTH"; -+ case AUTH_PAE_RESTART: return "RESTART"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * be_auth_state_txt(int s) -+{ -+ switch (s) { -+ case BE_AUTH_REQUEST: return "REQUEST"; -+ case BE_AUTH_RESPONSE: return "RESPONSE"; -+ case BE_AUTH_SUCCESS: return "SUCCESS"; -+ case BE_AUTH_FAIL: return "FAIL"; -+ case BE_AUTH_TIMEOUT: return "TIMEOUT"; -+ case BE_AUTH_IDLE: return "IDLE"; -+ case BE_AUTH_INITIALIZE: return "INITIALIZE"; -+ case BE_AUTH_IGNORE: return "IGNORE"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * reauth_timer_state_txt(int s) -+{ -+ switch (s) { -+ case REAUTH_TIMER_INITIALIZE: return "INITIALIZE"; -+ case REAUTH_TIMER_REAUTHENTICATE: return "REAUTHENTICATE"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * auth_key_tx_state_txt(int s) -+{ -+ switch (s) { -+ case AUTH_KEY_TX_NO_KEY_TRANSMIT: return "NO_KEY_TRANSMIT"; -+ case AUTH_KEY_TX_KEY_TRANSMIT: return "KEY_TRANSMIT"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * key_rx_state_txt(int s) -+{ -+ switch (s) { -+ case KEY_RX_NO_KEY_RECEIVE: return "NO_KEY_RECEIVE"; -+ case KEY_RX_KEY_RECEIVE: return "KEY_RECEIVE"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+static inline const char * ctrl_dir_state_txt(int s) -+{ -+ switch (s) { -+ case CTRL_DIR_FORCE_BOTH: return "FORCE_BOTH"; -+ case CTRL_DIR_IN_OR_BOTH: return "IN_OR_BOTH"; -+ default: return "Unknown"; -+ } -+} -+ -+ -+void eapol_auth_dump_state(FILE *f, const char *prefix, -+ struct eapol_state_machine *sm) -+{ -+ fprintf(f, "%sEAPOL state machine:\n", prefix); -+ fprintf(f, "%s aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix, -+ sm->aWhile, sm->quietWhile, sm->reAuthWhen); -+#define _SB(b) ((b) ? "TRUE" : "FALSE") -+ fprintf(f, -+ "%s authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n" -+ "%s authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n" -+ "%s eapSuccess=%s eapTimeout=%s initialize=%s " -+ "keyAvailable=%s\n" -+ "%s keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n" -+ "%s portEnabled=%s portValid=%s reAuthenticate=%s\n", -+ prefix, _SB(sm->authAbort), _SB(sm->authFail), -+ port_state_txt(sm->authPortStatus), _SB(sm->authStart), -+ prefix, _SB(sm->authTimeout), _SB(sm->authSuccess), -+ _SB(sm->eap_if->eapFail), _SB(sm->eapolEap), -+ prefix, _SB(sm->eap_if->eapSuccess), -+ _SB(sm->eap_if->eapTimeout), -+ _SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable), -+ prefix, _SB(sm->keyDone), _SB(sm->keyRun), -+ _SB(sm->keyTxEnabled), port_type_txt(sm->portControl), -+ prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid), -+ _SB(sm->reAuthenticate)); -+ -+ fprintf(f, "%s Authenticator PAE:\n" -+ "%s state=%s\n" -+ "%s eapolLogoff=%s eapolStart=%s eapRestart=%s\n" -+ "%s portMode=%s reAuthCount=%d\n" -+ "%s quietPeriod=%d reAuthMax=%d\n" -+ "%s authEntersConnecting=%d\n" -+ "%s authEapLogoffsWhileConnecting=%d\n" -+ "%s authEntersAuthenticating=%d\n" -+ "%s authAuthSuccessesWhileAuthenticating=%d\n" -+ "%s authAuthTimeoutsWhileAuthenticating=%d\n" -+ "%s authAuthFailWhileAuthenticating=%d\n" -+ "%s authAuthEapStartsWhileAuthenticating=%d\n" -+ "%s authAuthEapLogoffWhileAuthenticating=%d\n" -+ "%s authAuthReauthsWhileAuthenticated=%d\n" -+ "%s authAuthEapStartsWhileAuthenticated=%d\n" -+ "%s authAuthEapLogoffWhileAuthenticated=%d\n", -+ prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix, -+ _SB(sm->eapolLogoff), _SB(sm->eapolStart), -+ _SB(sm->eap_if->eapRestart), -+ prefix, port_type_txt(sm->portMode), sm->reAuthCount, -+ prefix, sm->quietPeriod, sm->reAuthMax, -+ prefix, sm->authEntersConnecting, -+ prefix, sm->authEapLogoffsWhileConnecting, -+ prefix, sm->authEntersAuthenticating, -+ prefix, sm->authAuthSuccessesWhileAuthenticating, -+ prefix, sm->authAuthTimeoutsWhileAuthenticating, -+ prefix, sm->authAuthFailWhileAuthenticating, -+ prefix, sm->authAuthEapStartsWhileAuthenticating, -+ prefix, sm->authAuthEapLogoffWhileAuthenticating, -+ prefix, sm->authAuthReauthsWhileAuthenticated, -+ prefix, sm->authAuthEapStartsWhileAuthenticated, -+ prefix, sm->authAuthEapLogoffWhileAuthenticated); -+ -+ fprintf(f, "%s Backend Authentication:\n" -+ "%s state=%s\n" -+ "%s eapNoReq=%s eapReq=%s eapResp=%s\n" -+ "%s serverTimeout=%d\n" -+ "%s backendResponses=%d\n" -+ "%s backendAccessChallenges=%d\n" -+ "%s backendOtherRequestsToSupplicant=%d\n" -+ "%s backendAuthSuccesses=%d\n" -+ "%s backendAuthFails=%d\n", -+ prefix, prefix, -+ be_auth_state_txt(sm->be_auth_state), -+ prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq), -+ _SB(sm->eap_if->eapResp), -+ prefix, sm->serverTimeout, -+ prefix, sm->backendResponses, -+ prefix, sm->backendAccessChallenges, -+ prefix, sm->backendOtherRequestsToSupplicant, -+ prefix, sm->backendAuthSuccesses, -+ prefix, sm->backendAuthFails); -+ -+ fprintf(f, "%s Reauthentication Timer:\n" -+ "%s state=%s\n" -+ "%s reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix, -+ reauth_timer_state_txt(sm->reauth_timer_state), prefix, -+ sm->reAuthPeriod, _SB(sm->reAuthEnabled)); -+ -+ fprintf(f, "%s Authenticator Key Transmit:\n" -+ "%s state=%s\n", prefix, prefix, -+ auth_key_tx_state_txt(sm->auth_key_tx_state)); -+ -+ fprintf(f, "%s Key Receive:\n" -+ "%s state=%s\n" -+ "%s rxKey=%s\n", prefix, prefix, -+ key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey)); -+ -+ fprintf(f, "%s Controlled Directions:\n" -+ "%s state=%s\n" -+ "%s adminControlledDirections=%s " -+ "operControlledDirections=%s\n" -+ "%s operEdge=%s\n", prefix, prefix, -+ ctrl_dir_state_txt(sm->ctrl_dir_state), -+ prefix, ctrl_dir_txt(sm->adminControlledDirections), -+ ctrl_dir_txt(sm->operControlledDirections), -+ prefix, _SB(sm->operEdge)); -+#undef _SB -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.c -new file mode 100644 -index 0000000000000..841a1c515e9dd ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.c -@@ -0,0 +1,1145 @@ -+/* -+ * IEEE 802.1X-2004 Authenticator - EAPOL state machine -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "state_machine.h" -+#include "common/eapol_common.h" -+#include "eap_common/eap_defs.h" -+#include "eap_common/eap_common.h" -+#include "eap_server/eap.h" -+#include "eapol_auth_sm.h" -+#include "eapol_auth_sm_i.h" -+ -+#define STATE_MACHINE_DATA struct eapol_state_machine -+#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X" -+#define STATE_MACHINE_ADDR sm->addr -+ -+static struct eapol_callbacks eapol_cb; -+ -+/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */ -+ -+#define setPortAuthorized() \ -+sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1) -+#define setPortUnauthorized() \ -+sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0) -+ -+/* procedures */ -+#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0) -+#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1) -+#define txReq() eapol_auth_tx_req(sm) -+#define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta) -+#define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta) -+#define processKey() do { } while (0) -+ -+ -+static void eapol_sm_step_run(struct eapol_state_machine *sm); -+static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx); -+static void eapol_auth_initialize(struct eapol_state_machine *sm); -+ -+ -+static void eapol_auth_logger(struct eapol_authenticator *eapol, -+ const u8 *addr, eapol_logger_level level, -+ const char *txt) -+{ -+ if (eapol->cb.logger == NULL) -+ return; -+ eapol->cb.logger(eapol->conf.ctx, addr, level, txt); -+} -+ -+ -+static void eapol_auth_vlogger(struct eapol_authenticator *eapol, -+ const u8 *addr, eapol_logger_level level, -+ const char *fmt, ...) -+{ -+ char *format; -+ int maxlen; -+ va_list ap; -+ -+ if (eapol->cb.logger == NULL) -+ return; -+ -+ maxlen = os_strlen(fmt) + 100; -+ format = os_malloc(maxlen); -+ if (!format) -+ return; -+ -+ va_start(ap, fmt); -+ vsnprintf(format, maxlen, fmt, ap); -+ va_end(ap); -+ -+ eapol_auth_logger(eapol, addr, level, format); -+ -+ os_free(format); -+} -+ -+ -+static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm, -+ int success) -+{ -+ struct eap_hdr eap; -+ -+ os_memset(&eap, 0, sizeof(eap)); -+ -+ eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; -+ eap.identifier = ++sm->last_eap_id; -+ eap.length = host_to_be16(sizeof(eap)); -+ -+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG, -+ "Sending canned EAP packet %s (identifier %d)", -+ success ? "SUCCESS" : "FAILURE", eap.identifier); -+ sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta, -+ IEEE802_1X_TYPE_EAP_PACKET, -+ (u8 *) &eap, sizeof(eap)); -+ sm->dot1xAuthEapolFramesTx++; -+} -+ -+ -+static void eapol_auth_tx_req(struct eapol_state_machine *sm) -+{ -+ if (sm->eap_if->eapReqData == NULL || -+ wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) { -+ eapol_auth_logger(sm->eapol, sm->addr, -+ EAPOL_LOGGER_DEBUG, -+ "TxReq called, but there is no EAP request " -+ "from authentication server"); -+ return; -+ } -+ -+ if (sm->flags & EAPOL_SM_WAIT_START) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR -+ " while waiting for EAPOL-Start", -+ MAC2STR(sm->addr)); -+ return; -+ } -+ -+ sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData); -+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG, -+ "Sending EAP Packet (identifier %d)", -+ sm->last_eap_id); -+ sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta, -+ IEEE802_1X_TYPE_EAP_PACKET, -+ wpabuf_head(sm->eap_if->eapReqData), -+ wpabuf_len(sm->eap_if->eapReqData)); -+ sm->dot1xAuthEapolFramesTx++; -+ if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY) -+ sm->dot1xAuthEapolReqIdFramesTx++; -+ else -+ sm->dot1xAuthEapolReqFramesTx++; -+} -+ -+ -+/** -+ * eapol_port_timers_tick - Port Timers state machine -+ * @eloop_ctx: struct eapol_state_machine * -+ * @timeout_ctx: Not used -+ * -+ * This statemachine is implemented as a function that will be called -+ * once a second as a registered event loop timeout. -+ */ -+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct eapol_state_machine *state = timeout_ctx; -+ -+ if (state->aWhile > 0) { -+ state->aWhile--; -+ if (state->aWhile == 0) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR -+ " - aWhile --> 0", -+ MAC2STR(state->addr)); -+ } -+ } -+ -+ if (state->quietWhile > 0) { -+ state->quietWhile--; -+ if (state->quietWhile == 0) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR -+ " - quietWhile --> 0", -+ MAC2STR(state->addr)); -+ } -+ } -+ -+ if (state->reAuthWhen > 0) { -+ state->reAuthWhen--; -+ if (state->reAuthWhen == 0) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR -+ " - reAuthWhen --> 0", -+ MAC2STR(state->addr)); -+ } -+ } -+ -+ if (state->eap_if->retransWhile > 0) { -+ state->eap_if->retransWhile--; -+ if (state->eap_if->retransWhile == 0) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR -+ " - (EAP) retransWhile --> 0", -+ MAC2STR(state->addr)); -+ } -+ } -+ -+ eapol_sm_step_run(state); -+ -+ eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state); -+} -+ -+ -+ -+/* Authenticator PAE state machine */ -+ -+SM_STATE(AUTH_PAE, INITIALIZE) -+{ -+ SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae); -+ sm->portMode = Auto; -+} -+ -+ -+SM_STATE(AUTH_PAE, DISCONNECTED) -+{ -+ int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE; -+ -+ if (sm->eapolLogoff) { -+ if (sm->auth_pae_state == AUTH_PAE_CONNECTING) -+ sm->authEapLogoffsWhileConnecting++; -+ else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) -+ sm->authAuthEapLogoffWhileAuthenticated++; -+ } -+ -+ SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae); -+ -+ sm->authPortStatus = Unauthorized; -+ setPortUnauthorized(); -+ sm->reAuthCount = 0; -+ sm->eapolLogoff = FALSE; -+ if (!from_initialize) { -+ sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, -+ sm->flags & EAPOL_SM_PREAUTH); -+ } -+} -+ -+ -+SM_STATE(AUTH_PAE, RESTART) -+{ -+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) { -+ if (sm->reAuthenticate) -+ sm->authAuthReauthsWhileAuthenticated++; -+ if (sm->eapolStart) -+ sm->authAuthEapStartsWhileAuthenticated++; -+ if (sm->eapolLogoff) -+ sm->authAuthEapLogoffWhileAuthenticated++; -+ } -+ -+ SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae); -+ -+ sm->eap_if->eapRestart = TRUE; -+} -+ -+ -+SM_STATE(AUTH_PAE, CONNECTING) -+{ -+ if (sm->auth_pae_state != AUTH_PAE_CONNECTING) -+ sm->authEntersConnecting++; -+ -+ SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae); -+ -+ sm->reAuthenticate = FALSE; -+ sm->reAuthCount++; -+} -+ -+ -+SM_STATE(AUTH_PAE, HELD) -+{ -+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail) -+ sm->authAuthFailWhileAuthenticating++; -+ -+ SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae); -+ -+ sm->authPortStatus = Unauthorized; -+ setPortUnauthorized(); -+ sm->quietWhile = sm->quietPeriod; -+ sm->eapolLogoff = FALSE; -+ -+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING, -+ "authentication failed - EAP type: %d (%s)", -+ sm->eap_type_authsrv, -+ eap_server_get_name(0, sm->eap_type_authsrv)); -+ if (sm->eap_type_authsrv != sm->eap_type_supp) { -+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO, -+ "Supplicant used different EAP type: " -+ "%d (%s)", sm->eap_type_supp, -+ eap_server_get_name(0, sm->eap_type_supp)); -+ } -+ sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, -+ sm->flags & EAPOL_SM_PREAUTH); -+} -+ -+ -+SM_STATE(AUTH_PAE, AUTHENTICATED) -+{ -+ char *extra = ""; -+ -+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess) -+ sm->authAuthSuccessesWhileAuthenticating++; -+ -+ SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae); -+ -+ sm->authPortStatus = Authorized; -+ setPortAuthorized(); -+ sm->reAuthCount = 0; -+ if (sm->flags & EAPOL_SM_PREAUTH) -+ extra = " (pre-authentication)"; -+ else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE) -+ extra = " (PMKSA cache)"; -+ eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO, -+ "authenticated - EAP type: %d (%s)%s", -+ sm->eap_type_authsrv, -+ eap_server_get_name(0, sm->eap_type_authsrv), -+ extra); -+ sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1, -+ sm->flags & EAPOL_SM_PREAUTH); -+} -+ -+ -+SM_STATE(AUTH_PAE, AUTHENTICATING) -+{ -+ SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae); -+ -+ sm->eapolStart = FALSE; -+ sm->authSuccess = FALSE; -+ sm->authFail = FALSE; -+ sm->authTimeout = FALSE; -+ sm->authStart = TRUE; -+ sm->keyRun = FALSE; -+ sm->keyDone = FALSE; -+} -+ -+ -+SM_STATE(AUTH_PAE, ABORTING) -+{ -+ if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) { -+ if (sm->authTimeout) -+ sm->authAuthTimeoutsWhileAuthenticating++; -+ if (sm->eapolStart) -+ sm->authAuthEapStartsWhileAuthenticating++; -+ if (sm->eapolLogoff) -+ sm->authAuthEapLogoffWhileAuthenticating++; -+ } -+ -+ SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae); -+ -+ sm->authAbort = TRUE; -+ sm->keyRun = FALSE; -+ sm->keyDone = FALSE; -+} -+ -+ -+SM_STATE(AUTH_PAE, FORCE_AUTH) -+{ -+ SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae); -+ -+ sm->authPortStatus = Authorized; -+ setPortAuthorized(); -+ sm->portMode = ForceAuthorized; -+ sm->eapolStart = FALSE; -+ txCannedSuccess(); -+} -+ -+ -+SM_STATE(AUTH_PAE, FORCE_UNAUTH) -+{ -+ SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae); -+ -+ sm->authPortStatus = Unauthorized; -+ setPortUnauthorized(); -+ sm->portMode = ForceUnauthorized; -+ sm->eapolStart = FALSE; -+ txCannedFail(); -+} -+ -+ -+SM_STEP(AUTH_PAE) -+{ -+ if ((sm->portControl == Auto && sm->portMode != sm->portControl) || -+ sm->initialize || !sm->eap_if->portEnabled) -+ SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE); -+ else if (sm->portControl == ForceAuthorized && -+ sm->portMode != sm->portControl && -+ !(sm->initialize || !sm->eap_if->portEnabled)) -+ SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH); -+ else if (sm->portControl == ForceUnauthorized && -+ sm->portMode != sm->portControl && -+ !(sm->initialize || !sm->eap_if->portEnabled)) -+ SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH); -+ else { -+ switch (sm->auth_pae_state) { -+ case AUTH_PAE_INITIALIZE: -+ SM_ENTER(AUTH_PAE, DISCONNECTED); -+ break; -+ case AUTH_PAE_DISCONNECTED: -+ SM_ENTER(AUTH_PAE, RESTART); -+ break; -+ case AUTH_PAE_RESTART: -+ if (!sm->eap_if->eapRestart) -+ SM_ENTER(AUTH_PAE, CONNECTING); -+ break; -+ case AUTH_PAE_HELD: -+ if (sm->quietWhile == 0) -+ SM_ENTER(AUTH_PAE, RESTART); -+ break; -+ case AUTH_PAE_CONNECTING: -+ if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax) -+ SM_ENTER(AUTH_PAE, DISCONNECTED); -+ else if ((sm->eap_if->eapReq && -+ sm->reAuthCount <= sm->reAuthMax) || -+ sm->eap_if->eapSuccess || sm->eap_if->eapFail) -+ SM_ENTER(AUTH_PAE, AUTHENTICATING); -+ break; -+ case AUTH_PAE_AUTHENTICATED: -+ if (sm->eapolStart || sm->reAuthenticate) -+ SM_ENTER(AUTH_PAE, RESTART); -+ else if (sm->eapolLogoff || !sm->portValid) -+ SM_ENTER(AUTH_PAE, DISCONNECTED); -+ break; -+ case AUTH_PAE_AUTHENTICATING: -+ if (sm->authSuccess && sm->portValid) -+ SM_ENTER(AUTH_PAE, AUTHENTICATED); -+ else if (sm->authFail || -+ (sm->keyDone && !sm->portValid)) -+ SM_ENTER(AUTH_PAE, HELD); -+ else if (sm->eapolStart || sm->eapolLogoff || -+ sm->authTimeout) -+ SM_ENTER(AUTH_PAE, ABORTING); -+ break; -+ case AUTH_PAE_ABORTING: -+ if (sm->eapolLogoff && !sm->authAbort) -+ SM_ENTER(AUTH_PAE, DISCONNECTED); -+ else if (!sm->eapolLogoff && !sm->authAbort) -+ SM_ENTER(AUTH_PAE, RESTART); -+ break; -+ case AUTH_PAE_FORCE_AUTH: -+ if (sm->eapolStart) -+ SM_ENTER(AUTH_PAE, FORCE_AUTH); -+ break; -+ case AUTH_PAE_FORCE_UNAUTH: -+ if (sm->eapolStart) -+ SM_ENTER(AUTH_PAE, FORCE_UNAUTH); -+ break; -+ } -+ } -+} -+ -+ -+ -+/* Backend Authentication state machine */ -+ -+SM_STATE(BE_AUTH, INITIALIZE) -+{ -+ SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth); -+ -+ abortAuth(); -+ sm->eap_if->eapNoReq = FALSE; -+ sm->authAbort = FALSE; -+} -+ -+ -+SM_STATE(BE_AUTH, REQUEST) -+{ -+ SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth); -+ -+ txReq(); -+ sm->eap_if->eapReq = FALSE; -+ sm->backendOtherRequestsToSupplicant++; -+ -+ /* -+ * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but -+ * it looks like this would be logical thing to do there since the old -+ * EAP response would not be valid anymore after the new EAP request -+ * was sent out. -+ * -+ * A race condition has been reported, in which hostapd ended up -+ * sending out EAP-Response/Identity as a response to the first -+ * EAP-Request from the main EAP method. This can be avoided by -+ * clearing eapolEap here. -+ */ -+ sm->eapolEap = FALSE; -+} -+ -+ -+SM_STATE(BE_AUTH, RESPONSE) -+{ -+ SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth); -+ -+ sm->authTimeout = FALSE; -+ sm->eapolEap = FALSE; -+ sm->eap_if->eapNoReq = FALSE; -+ sm->aWhile = sm->serverTimeout; -+ sm->eap_if->eapResp = TRUE; -+ /* sendRespToServer(); */ -+ sm->backendResponses++; -+} -+ -+ -+SM_STATE(BE_AUTH, SUCCESS) -+{ -+ SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth); -+ -+ txReq(); -+ sm->authSuccess = TRUE; -+ sm->keyRun = TRUE; -+} -+ -+ -+SM_STATE(BE_AUTH, FAIL) -+{ -+ SM_ENTRY_MA(BE_AUTH, FAIL, be_auth); -+ -+ txReq(); -+ sm->authFail = TRUE; -+} -+ -+ -+SM_STATE(BE_AUTH, TIMEOUT) -+{ -+ SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth); -+ -+ sm->authTimeout = TRUE; -+} -+ -+ -+SM_STATE(BE_AUTH, IDLE) -+{ -+ SM_ENTRY_MA(BE_AUTH, IDLE, be_auth); -+ -+ sm->authStart = FALSE; -+} -+ -+ -+SM_STATE(BE_AUTH, IGNORE) -+{ -+ SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth); -+ -+ sm->eap_if->eapNoReq = FALSE; -+} -+ -+ -+SM_STEP(BE_AUTH) -+{ -+ if (sm->portControl != Auto || sm->initialize || sm->authAbort) { -+ SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE); -+ return; -+ } -+ -+ switch (sm->be_auth_state) { -+ case BE_AUTH_INITIALIZE: -+ SM_ENTER(BE_AUTH, IDLE); -+ break; -+ case BE_AUTH_REQUEST: -+ if (sm->eapolEap) -+ SM_ENTER(BE_AUTH, RESPONSE); -+ else if (sm->eap_if->eapReq) -+ SM_ENTER(BE_AUTH, REQUEST); -+ else if (sm->eap_if->eapTimeout) -+ SM_ENTER(BE_AUTH, TIMEOUT); -+ break; -+ case BE_AUTH_RESPONSE: -+ if (sm->eap_if->eapNoReq) -+ SM_ENTER(BE_AUTH, IGNORE); -+ if (sm->eap_if->eapReq) { -+ sm->backendAccessChallenges++; -+ SM_ENTER(BE_AUTH, REQUEST); -+ } else if (sm->aWhile == 0) -+ SM_ENTER(BE_AUTH, TIMEOUT); -+ else if (sm->eap_if->eapFail) { -+ sm->backendAuthFails++; -+ SM_ENTER(BE_AUTH, FAIL); -+ } else if (sm->eap_if->eapSuccess) { -+ sm->backendAuthSuccesses++; -+ SM_ENTER(BE_AUTH, SUCCESS); -+ } -+ break; -+ case BE_AUTH_SUCCESS: -+ SM_ENTER(BE_AUTH, IDLE); -+ break; -+ case BE_AUTH_FAIL: -+ SM_ENTER(BE_AUTH, IDLE); -+ break; -+ case BE_AUTH_TIMEOUT: -+ SM_ENTER(BE_AUTH, IDLE); -+ break; -+ case BE_AUTH_IDLE: -+ if (sm->eap_if->eapFail && sm->authStart) -+ SM_ENTER(BE_AUTH, FAIL); -+ else if (sm->eap_if->eapReq && sm->authStart) -+ SM_ENTER(BE_AUTH, REQUEST); -+ else if (sm->eap_if->eapSuccess && sm->authStart) -+ SM_ENTER(BE_AUTH, SUCCESS); -+ break; -+ case BE_AUTH_IGNORE: -+ if (sm->eapolEap) -+ SM_ENTER(BE_AUTH, RESPONSE); -+ else if (sm->eap_if->eapReq) -+ SM_ENTER(BE_AUTH, REQUEST); -+ else if (sm->eap_if->eapTimeout) -+ SM_ENTER(BE_AUTH, TIMEOUT); -+ break; -+ } -+} -+ -+ -+ -+/* Reauthentication Timer state machine */ -+ -+SM_STATE(REAUTH_TIMER, INITIALIZE) -+{ -+ SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer); -+ -+ sm->reAuthWhen = sm->reAuthPeriod; -+} -+ -+ -+SM_STATE(REAUTH_TIMER, REAUTHENTICATE) -+{ -+ SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer); -+ -+ sm->reAuthenticate = TRUE; -+ sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta, -+ EAPOL_AUTH_REAUTHENTICATE); -+} -+ -+ -+SM_STEP(REAUTH_TIMER) -+{ -+ if (sm->portControl != Auto || sm->initialize || -+ sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) { -+ SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE); -+ return; -+ } -+ -+ switch (sm->reauth_timer_state) { -+ case REAUTH_TIMER_INITIALIZE: -+ if (sm->reAuthWhen == 0) -+ SM_ENTER(REAUTH_TIMER, REAUTHENTICATE); -+ break; -+ case REAUTH_TIMER_REAUTHENTICATE: -+ SM_ENTER(REAUTH_TIMER, INITIALIZE); -+ break; -+ } -+} -+ -+ -+ -+/* Authenticator Key Transmit state machine */ -+ -+SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT) -+{ -+ SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx); -+} -+ -+ -+SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT) -+{ -+ SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx); -+ -+ txKey(); -+ sm->eap_if->eapKeyAvailable = FALSE; -+ sm->keyDone = TRUE; -+} -+ -+ -+SM_STEP(AUTH_KEY_TX) -+{ -+ if (sm->initialize || sm->portControl != Auto) { -+ SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT); -+ return; -+ } -+ -+ switch (sm->auth_key_tx_state) { -+ case AUTH_KEY_TX_NO_KEY_TRANSMIT: -+ if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable && -+ sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA)) -+ SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT); -+ break; -+ case AUTH_KEY_TX_KEY_TRANSMIT: -+ if (!sm->keyTxEnabled || !sm->keyRun) -+ SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT); -+ else if (sm->eap_if->eapKeyAvailable) -+ SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT); -+ break; -+ } -+} -+ -+ -+ -+/* Key Receive state machine */ -+ -+SM_STATE(KEY_RX, NO_KEY_RECEIVE) -+{ -+ SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx); -+} -+ -+ -+SM_STATE(KEY_RX, KEY_RECEIVE) -+{ -+ SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx); -+ -+ processKey(); -+ sm->rxKey = FALSE; -+} -+ -+ -+SM_STEP(KEY_RX) -+{ -+ if (sm->initialize || !sm->eap_if->portEnabled) { -+ SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE); -+ return; -+ } -+ -+ switch (sm->key_rx_state) { -+ case KEY_RX_NO_KEY_RECEIVE: -+ if (sm->rxKey) -+ SM_ENTER(KEY_RX, KEY_RECEIVE); -+ break; -+ case KEY_RX_KEY_RECEIVE: -+ if (sm->rxKey) -+ SM_ENTER(KEY_RX, KEY_RECEIVE); -+ break; -+ } -+} -+ -+ -+ -+/* Controlled Directions state machine */ -+ -+SM_STATE(CTRL_DIR, FORCE_BOTH) -+{ -+ SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir); -+ sm->operControlledDirections = Both; -+} -+ -+ -+SM_STATE(CTRL_DIR, IN_OR_BOTH) -+{ -+ SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir); -+ sm->operControlledDirections = sm->adminControlledDirections; -+} -+ -+ -+SM_STEP(CTRL_DIR) -+{ -+ if (sm->initialize) { -+ SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH); -+ return; -+ } -+ -+ switch (sm->ctrl_dir_state) { -+ case CTRL_DIR_FORCE_BOTH: -+ if (sm->eap_if->portEnabled && sm->operEdge) -+ SM_ENTER(CTRL_DIR, IN_OR_BOTH); -+ break; -+ case CTRL_DIR_IN_OR_BOTH: -+ if (sm->operControlledDirections != -+ sm->adminControlledDirections) -+ SM_ENTER(CTRL_DIR, IN_OR_BOTH); -+ if (!sm->eap_if->portEnabled || !sm->operEdge) -+ SM_ENTER(CTRL_DIR, FORCE_BOTH); -+ break; -+ } -+} -+ -+ -+ -+struct eapol_state_machine * -+eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, -+ int flags, const struct wpabuf *assoc_wps_ie, -+ const struct wpabuf *assoc_p2p_ie, void *sta_ctx) -+{ -+ struct eapol_state_machine *sm; -+ struct eap_config eap_conf; -+ -+ if (eapol == NULL) -+ return NULL; -+ -+ sm = os_zalloc(sizeof(*sm)); -+ if (sm == NULL) { -+ wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation " -+ "failed"); -+ return NULL; -+ } -+ sm->radius_identifier = -1; -+ os_memcpy(sm->addr, addr, ETH_ALEN); -+ sm->flags = flags; -+ -+ sm->eapol = eapol; -+ sm->sta = sta_ctx; -+ -+ /* Set default values for state machine constants */ -+ sm->auth_pae_state = AUTH_PAE_INITIALIZE; -+ sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod; -+ sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax; -+ -+ sm->be_auth_state = BE_AUTH_INITIALIZE; -+ sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout; -+ -+ sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE; -+ sm->reAuthPeriod = eapol->conf.eap_reauth_period; -+ sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE; -+ -+ sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT; -+ -+ sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE; -+ -+ sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH; -+ -+ sm->portControl = Auto; -+ -+ if (!eapol->conf.wpa && -+ (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0)) -+ sm->keyTxEnabled = TRUE; -+ else -+ sm->keyTxEnabled = FALSE; -+ if (eapol->conf.wpa) -+ sm->portValid = FALSE; -+ else -+ sm->portValid = TRUE; -+ -+ os_memset(&eap_conf, 0, sizeof(eap_conf)); -+ eap_conf.eap_server = eapol->conf.eap_server; -+ eap_conf.ssl_ctx = eapol->conf.ssl_ctx; -+ eap_conf.msg_ctx = eapol->conf.msg_ctx; -+ eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv; -+ eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key; -+ eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id; -+ eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len; -+ eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info; -+ eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov; -+ eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime; -+ eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time; -+ eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind; -+ eap_conf.tnc = eapol->conf.tnc; -+ eap_conf.wps = eapol->conf.wps; -+ eap_conf.assoc_wps_ie = assoc_wps_ie; -+ eap_conf.assoc_p2p_ie = assoc_p2p_ie; -+ eap_conf.peer_addr = addr; -+ eap_conf.fragment_size = eapol->conf.fragment_size; -+ eap_conf.pwd_group = eapol->conf.pwd_group; -+ sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf); -+ if (sm->eap == NULL) { -+ eapol_auth_free(sm); -+ return NULL; -+ } -+ sm->eap_if = eap_get_interface(sm->eap); -+ -+ eapol_auth_initialize(sm); -+ -+ return sm; -+} -+ -+ -+void eapol_auth_free(struct eapol_state_machine *sm) -+{ -+ if (sm == NULL) -+ return; -+ -+ eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); -+ eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL); -+ if (sm->eap) -+ eap_server_sm_deinit(sm->eap); -+ os_free(sm); -+} -+ -+ -+static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol, -+ const u8 *addr) -+{ -+ return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr); -+} -+ -+ -+static void eapol_sm_step_run(struct eapol_state_machine *sm) -+{ -+ struct eapol_authenticator *eapol = sm->eapol; -+ u8 addr[ETH_ALEN]; -+ unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer, -+ prev_auth_key_tx, prev_key_rx, prev_ctrl_dir; -+ int max_steps = 100; -+ -+ os_memcpy(addr, sm->addr, ETH_ALEN); -+ -+ /* -+ * Allow EAPOL state machines to run as long as there are state -+ * changes, but exit and return here through event loop if more than -+ * 100 steps is needed as a precaution against infinite loops inside -+ * eloop callback. -+ */ -+restart: -+ prev_auth_pae = sm->auth_pae_state; -+ prev_be_auth = sm->be_auth_state; -+ prev_reauth_timer = sm->reauth_timer_state; -+ prev_auth_key_tx = sm->auth_key_tx_state; -+ prev_key_rx = sm->key_rx_state; -+ prev_ctrl_dir = sm->ctrl_dir_state; -+ -+ SM_STEP_RUN(AUTH_PAE); -+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) -+ SM_STEP_RUN(BE_AUTH); -+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) -+ SM_STEP_RUN(REAUTH_TIMER); -+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) -+ SM_STEP_RUN(AUTH_KEY_TX); -+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) -+ SM_STEP_RUN(KEY_RX); -+ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) -+ SM_STEP_RUN(CTRL_DIR); -+ -+ if (prev_auth_pae != sm->auth_pae_state || -+ prev_be_auth != sm->be_auth_state || -+ prev_reauth_timer != sm->reauth_timer_state || -+ prev_auth_key_tx != sm->auth_key_tx_state || -+ prev_key_rx != sm->key_rx_state || -+ prev_ctrl_dir != sm->ctrl_dir_state) { -+ if (--max_steps > 0) -+ goto restart; -+ /* Re-run from eloop timeout */ -+ eapol_auth_step(sm); -+ return; -+ } -+ -+ if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) { -+ if (eap_server_sm_step(sm->eap)) { -+ if (--max_steps > 0) -+ goto restart; -+ /* Re-run from eloop timeout */ -+ eapol_auth_step(sm); -+ return; -+ } -+ -+ /* TODO: find a better location for this */ -+ if (sm->eap_if->aaaEapResp) { -+ sm->eap_if->aaaEapResp = FALSE; -+ if (sm->eap_if->aaaEapRespData == NULL) { -+ wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, " -+ "but no aaaEapRespData available"); -+ return; -+ } -+ sm->eapol->cb.aaa_send( -+ sm->eapol->conf.ctx, sm->sta, -+ wpabuf_head(sm->eap_if->aaaEapRespData), -+ wpabuf_len(sm->eap_if->aaaEapRespData)); -+ } -+ } -+ -+ if (eapol_sm_sta_entry_alive(eapol, addr)) -+ sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta, -+ EAPOL_AUTH_SM_CHANGE); -+} -+ -+ -+static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct eapol_state_machine *sm = eloop_ctx; -+ eapol_sm_step_run(sm); -+} -+ -+ -+/** -+ * eapol_auth_step - Advance EAPOL state machines -+ * @sm: EAPOL state machine -+ * -+ * This function is called to advance EAPOL state machines after any change -+ * that could affect their state. -+ */ -+void eapol_auth_step(struct eapol_state_machine *sm) -+{ -+ /* -+ * Run eapol_sm_step_run from a registered timeout to make sure that -+ * other possible timeouts/events are processed and to avoid long -+ * function call chains. -+ */ -+ -+ eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL); -+} -+ -+ -+static void eapol_auth_initialize(struct eapol_state_machine *sm) -+{ -+ sm->initializing = TRUE; -+ /* Initialize the state machines by asserting initialize and then -+ * deasserting it after one step */ -+ sm->initialize = TRUE; -+ eapol_sm_step_run(sm); -+ sm->initialize = FALSE; -+ eapol_sm_step_run(sm); -+ sm->initializing = FALSE; -+ -+ /* Start one second tick for port timers state machine */ -+ eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); -+ eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); -+} -+ -+ -+static int eapol_sm_get_eap_user(void *ctx, const u8 *identity, -+ size_t identity_len, int phase2, -+ struct eap_user *user) -+{ -+ struct eapol_state_machine *sm = ctx; -+ return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity, -+ identity_len, phase2, user); -+} -+ -+ -+static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len) -+{ -+ struct eapol_state_machine *sm = ctx; -+ *len = sm->eapol->conf.eap_req_id_text_len; -+ return sm->eapol->conf.eap_req_id_text; -+} -+ -+ -+static struct eapol_callbacks eapol_cb = -+{ -+ eapol_sm_get_eap_user, -+ eapol_sm_get_eap_req_id_text -+}; -+ -+ -+int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx) -+{ -+ if (sm == NULL || ctx != sm->eap) -+ return -1; -+ -+ eap_sm_pending_cb(sm->eap); -+ eapol_auth_step(sm); -+ -+ return 0; -+} -+ -+ -+static int eapol_auth_conf_clone(struct eapol_auth_config *dst, -+ struct eapol_auth_config *src) -+{ -+ dst->ctx = src->ctx; -+ dst->eap_reauth_period = src->eap_reauth_period; -+ dst->wpa = src->wpa; -+ dst->individual_wep_key_len = src->individual_wep_key_len; -+ dst->eap_server = src->eap_server; -+ dst->ssl_ctx = src->ssl_ctx; -+ dst->msg_ctx = src->msg_ctx; -+ dst->eap_sim_db_priv = src->eap_sim_db_priv; -+ os_free(dst->eap_req_id_text); -+ dst->pwd_group = src->pwd_group; -+ if (src->eap_req_id_text) { -+ dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len); -+ if (dst->eap_req_id_text == NULL) -+ return -1; -+ os_memcpy(dst->eap_req_id_text, src->eap_req_id_text, -+ src->eap_req_id_text_len); -+ dst->eap_req_id_text_len = src->eap_req_id_text_len; -+ } else { -+ dst->eap_req_id_text = NULL; -+ dst->eap_req_id_text_len = 0; -+ } -+ if (src->pac_opaque_encr_key) { -+ dst->pac_opaque_encr_key = os_malloc(16); -+ os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key, -+ 16); -+ } else -+ dst->pac_opaque_encr_key = NULL; -+ if (src->eap_fast_a_id) { -+ dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len); -+ if (dst->eap_fast_a_id == NULL) { -+ os_free(dst->eap_req_id_text); -+ return -1; -+ } -+ os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id, -+ src->eap_fast_a_id_len); -+ dst->eap_fast_a_id_len = src->eap_fast_a_id_len; -+ } else -+ dst->eap_fast_a_id = NULL; -+ if (src->eap_fast_a_id_info) { -+ dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info); -+ if (dst->eap_fast_a_id_info == NULL) { -+ os_free(dst->eap_req_id_text); -+ os_free(dst->eap_fast_a_id); -+ return -1; -+ } -+ } else -+ dst->eap_fast_a_id_info = NULL; -+ dst->eap_fast_prov = src->eap_fast_prov; -+ dst->pac_key_lifetime = src->pac_key_lifetime; -+ dst->pac_key_refresh_time = src->pac_key_refresh_time; -+ dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind; -+ dst->tnc = src->tnc; -+ dst->wps = src->wps; -+ dst->fragment_size = src->fragment_size; -+ return 0; -+} -+ -+ -+static void eapol_auth_conf_free(struct eapol_auth_config *conf) -+{ -+ os_free(conf->eap_req_id_text); -+ conf->eap_req_id_text = NULL; -+ os_free(conf->pac_opaque_encr_key); -+ conf->pac_opaque_encr_key = NULL; -+ os_free(conf->eap_fast_a_id); -+ conf->eap_fast_a_id = NULL; -+ os_free(conf->eap_fast_a_id_info); -+ conf->eap_fast_a_id_info = NULL; -+} -+ -+ -+struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf, -+ struct eapol_auth_cb *cb) -+{ -+ struct eapol_authenticator *eapol; -+ -+ eapol = os_zalloc(sizeof(*eapol)); -+ if (eapol == NULL) -+ return NULL; -+ -+ if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) { -+ os_free(eapol); -+ return NULL; -+ } -+ -+ if (conf->individual_wep_key_len > 0) { -+ /* use key0 in individual key and key1 in broadcast key */ -+ eapol->default_wep_key_idx = 1; -+ } -+ -+ eapol->cb.eapol_send = cb->eapol_send; -+ eapol->cb.aaa_send = cb->aaa_send; -+ eapol->cb.finished = cb->finished; -+ eapol->cb.get_eap_user = cb->get_eap_user; -+ eapol->cb.sta_entry_alive = cb->sta_entry_alive; -+ eapol->cb.logger = cb->logger; -+ eapol->cb.set_port_authorized = cb->set_port_authorized; -+ eapol->cb.abort_auth = cb->abort_auth; -+ eapol->cb.tx_key = cb->tx_key; -+ eapol->cb.eapol_event = cb->eapol_event; -+ -+ return eapol; -+} -+ -+ -+void eapol_auth_deinit(struct eapol_authenticator *eapol) -+{ -+ if (eapol == NULL) -+ return; -+ -+ eapol_auth_conf_free(&eapol->conf); -+ os_free(eapol->default_wep_key); -+ os_free(eapol); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.h -new file mode 100644 -index 0000000000000..59a10b45b2c31 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm.h -@@ -0,0 +1,92 @@ -+/* -+ * IEEE 802.1X-2004 Authenticator - EAPOL state machine -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAPOL_AUTH_SM_H -+#define EAPOL_AUTH_SM_H -+ -+#define EAPOL_SM_PREAUTH BIT(0) -+#define EAPOL_SM_WAIT_START BIT(1) -+#define EAPOL_SM_USES_WPA BIT(2) -+#define EAPOL_SM_FROM_PMKSA_CACHE BIT(3) -+ -+struct eapol_auth_config { -+ int eap_reauth_period; -+ int wpa; -+ int individual_wep_key_len; -+ int eap_server; -+ void *ssl_ctx; -+ void *msg_ctx; -+ void *eap_sim_db_priv; -+ char *eap_req_id_text; /* a copy of this will be allocated */ -+ size_t eap_req_id_text_len; -+ u8 *pac_opaque_encr_key; -+ u8 *eap_fast_a_id; -+ size_t eap_fast_a_id_len; -+ char *eap_fast_a_id_info; -+ int eap_fast_prov; -+ int pac_key_lifetime; -+ int pac_key_refresh_time; -+ int eap_sim_aka_result_ind; -+ int tnc; -+ struct wps_context *wps; -+ int fragment_size; -+ u16 pwd_group; -+ -+ /* Opaque context pointer to owner data for callback functions */ -+ void *ctx; -+}; -+ -+struct eap_user; -+ -+typedef enum { -+ EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING -+} eapol_logger_level; -+ -+enum eapol_event { -+ EAPOL_AUTH_SM_CHANGE, -+ EAPOL_AUTH_REAUTHENTICATE -+}; -+ -+struct eapol_auth_cb { -+ void (*eapol_send)(void *ctx, void *sta_ctx, u8 type, const u8 *data, -+ size_t datalen); -+ void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data, -+ size_t datalen); -+ void (*finished)(void *ctx, void *sta_ctx, int success, int preauth); -+ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, -+ int phase2, struct eap_user *user); -+ int (*sta_entry_alive)(void *ctx, const u8 *addr); -+ void (*logger)(void *ctx, const u8 *addr, eapol_logger_level level, -+ const char *txt); -+ void (*set_port_authorized)(void *ctx, void *sta_ctx, int authorized); -+ void (*abort_auth)(void *ctx, void *sta_ctx); -+ void (*tx_key)(void *ctx, void *sta_ctx); -+ void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type); -+}; -+ -+ -+struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf, -+ struct eapol_auth_cb *cb); -+void eapol_auth_deinit(struct eapol_authenticator *eapol); -+struct eapol_state_machine * -+eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, -+ int flags, const struct wpabuf *assoc_wps_ie, -+ const struct wpabuf *assoc_p2p_ie, void *sta_ctx); -+void eapol_auth_free(struct eapol_state_machine *sm); -+void eapol_auth_step(struct eapol_state_machine *sm); -+void eapol_auth_dump_state(FILE *f, const char *prefix, -+ struct eapol_state_machine *sm); -+int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx); -+ -+#endif /* EAPOL_AUTH_SM_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm_i.h -new file mode 100644 -index 0000000000000..1000da4df148c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_auth/eapol_auth_sm_i.h -@@ -0,0 +1,183 @@ -+/* -+ * IEEE 802.1X-2004 Authenticator - EAPOL state machine (internal definitions) -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAPOL_AUTH_SM_I_H -+#define EAPOL_AUTH_SM_I_H -+ -+#include "common/defs.h" -+#include "radius/radius.h" -+ -+/* IEEE Std 802.1X-2004, Ch. 8.2 */ -+ -+typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 } -+ PortTypes; -+typedef enum { Unauthorized = 2, Authorized = 1 } PortState; -+typedef enum { Both = 0, In = 1 } ControlledDirection; -+typedef unsigned int Counter; -+ -+ -+/** -+ * struct eapol_authenticator - Global EAPOL authenticator data -+ */ -+struct eapol_authenticator { -+ struct eapol_auth_config conf; -+ struct eapol_auth_cb cb; -+ -+ u8 *default_wep_key; -+ u8 default_wep_key_idx; -+}; -+ -+ -+/** -+ * struct eapol_state_machine - Per-Supplicant Authenticator state machines -+ */ -+struct eapol_state_machine { -+ /* timers */ -+ int aWhile; -+ int quietWhile; -+ int reAuthWhen; -+ -+ /* global variables */ -+ Boolean authAbort; -+ Boolean authFail; -+ PortState authPortStatus; -+ Boolean authStart; -+ Boolean authTimeout; -+ Boolean authSuccess; -+ Boolean eapolEap; -+ Boolean initialize; -+ Boolean keyDone; -+ Boolean keyRun; -+ Boolean keyTxEnabled; -+ PortTypes portControl; -+ Boolean portValid; -+ Boolean reAuthenticate; -+ -+ /* Port Timers state machine */ -+ /* 'Boolean tick' implicitly handled as registered timeout */ -+ -+ /* Authenticator PAE state machine */ -+ enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING, -+ AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED, -+ AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH, -+ AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state; -+ /* variables */ -+ Boolean eapolLogoff; -+ Boolean eapolStart; -+ PortTypes portMode; -+ unsigned int reAuthCount; -+ /* constants */ -+ unsigned int quietPeriod; /* default 60; 0..65535 */ -+#define AUTH_PAE_DEFAULT_quietPeriod 60 -+ unsigned int reAuthMax; /* default 2 */ -+#define AUTH_PAE_DEFAULT_reAuthMax 2 -+ /* counters */ -+ Counter authEntersConnecting; -+ Counter authEapLogoffsWhileConnecting; -+ Counter authEntersAuthenticating; -+ Counter authAuthSuccessesWhileAuthenticating; -+ Counter authAuthTimeoutsWhileAuthenticating; -+ Counter authAuthFailWhileAuthenticating; -+ Counter authAuthEapStartsWhileAuthenticating; -+ Counter authAuthEapLogoffWhileAuthenticating; -+ Counter authAuthReauthsWhileAuthenticated; -+ Counter authAuthEapStartsWhileAuthenticated; -+ Counter authAuthEapLogoffWhileAuthenticated; -+ -+ /* Backend Authentication state machine */ -+ enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS, -+ BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE, -+ BE_AUTH_IGNORE -+ } be_auth_state; -+ /* constants */ -+ unsigned int serverTimeout; /* default 30; 1..X */ -+#define BE_AUTH_DEFAULT_serverTimeout 30 -+ /* counters */ -+ Counter backendResponses; -+ Counter backendAccessChallenges; -+ Counter backendOtherRequestsToSupplicant; -+ Counter backendAuthSuccesses; -+ Counter backendAuthFails; -+ -+ /* Reauthentication Timer state machine */ -+ enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE -+ } reauth_timer_state; -+ /* constants */ -+ unsigned int reAuthPeriod; /* default 3600 s */ -+ Boolean reAuthEnabled; -+ -+ /* Authenticator Key Transmit state machine */ -+ enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT -+ } auth_key_tx_state; -+ -+ /* Key Receive state machine */ -+ enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state; -+ /* variables */ -+ Boolean rxKey; -+ -+ /* Controlled Directions state machine */ -+ enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state; -+ /* variables */ -+ ControlledDirection adminControlledDirections; -+ ControlledDirection operControlledDirections; -+ Boolean operEdge; -+ -+ /* Authenticator Statistics Table */ -+ Counter dot1xAuthEapolFramesRx; -+ Counter dot1xAuthEapolFramesTx; -+ Counter dot1xAuthEapolStartFramesRx; -+ Counter dot1xAuthEapolLogoffFramesRx; -+ Counter dot1xAuthEapolRespIdFramesRx; -+ Counter dot1xAuthEapolRespFramesRx; -+ Counter dot1xAuthEapolReqIdFramesTx; -+ Counter dot1xAuthEapolReqFramesTx; -+ Counter dot1xAuthInvalidEapolFramesRx; -+ Counter dot1xAuthEapLengthErrorFramesRx; -+ Counter dot1xAuthLastEapolFrameVersion; -+ -+ /* Other variables - not defined in IEEE 802.1X */ -+ u8 addr[ETH_ALEN]; /* Supplicant address */ -+ int flags; /* EAPOL_SM_* */ -+ -+ /* EAPOL/AAA <-> EAP full authenticator interface */ -+ struct eap_eapol_interface *eap_if; -+ -+ int radius_identifier; -+ /* TODO: check when the last messages can be released */ -+ struct radius_msg *last_recv_radius; -+ u8 last_eap_id; /* last used EAP Identifier */ -+ u8 *identity; -+ size_t identity_len; -+ u8 eap_type_authsrv; /* EAP type of the last EAP packet from -+ * Authentication server */ -+ u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */ -+ struct radius_class_data radius_class; -+ -+ /* Keys for encrypting and signing EAPOL-Key frames */ -+ u8 *eapol_key_sign; -+ size_t eapol_key_sign_len; -+ u8 *eapol_key_crypt; -+ size_t eapol_key_crypt_len; -+ -+ struct eap_sm *eap; -+ -+ Boolean initializing; /* in process of initializing state machines */ -+ Boolean changed; -+ -+ struct eapol_authenticator *eapol; -+ -+ void *sta; /* station context pointer to use in callbacks */ -+}; -+ -+#endif /* EAPOL_AUTH_SM_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.c -new file mode 100644 -index 0000000000000..18abb4e3c4173 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.c -@@ -0,0 +1,1913 @@ -+/* -+ * EAPOL supplicant state machines -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "state_machine.h" -+#include "wpabuf.h" -+#include "eloop.h" -+#include "crypto/crypto.h" -+#include "crypto/md5.h" -+#include "common/eapol_common.h" -+#include "eap_peer/eap.h" -+#include "eapol_supp_sm.h" -+ -+#define STATE_MACHINE_DATA struct eapol_sm -+#define STATE_MACHINE_DEBUG_PREFIX "EAPOL" -+ -+ -+/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */ -+ -+/** -+ * struct eapol_sm - Internal data for EAPOL state machines -+ */ -+struct eapol_sm { -+ /* Timers */ -+ unsigned int authWhile; -+ unsigned int heldWhile; -+ unsigned int startWhen; -+ unsigned int idleWhile; /* for EAP state machine */ -+ int timer_tick_enabled; -+ -+ /* Global variables */ -+ Boolean eapFail; -+ Boolean eapolEap; -+ Boolean eapSuccess; -+ Boolean initialize; -+ Boolean keyDone; -+ Boolean keyRun; -+ PortControl portControl; -+ Boolean portEnabled; -+ PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */ -+ Boolean portValid; -+ Boolean suppAbort; -+ Boolean suppFail; -+ Boolean suppStart; -+ Boolean suppSuccess; -+ Boolean suppTimeout; -+ -+ /* Supplicant PAE state machine */ -+ enum { -+ SUPP_PAE_UNKNOWN = 0, -+ SUPP_PAE_DISCONNECTED = 1, -+ SUPP_PAE_LOGOFF = 2, -+ SUPP_PAE_CONNECTING = 3, -+ SUPP_PAE_AUTHENTICATING = 4, -+ SUPP_PAE_AUTHENTICATED = 5, -+ /* unused(6) */ -+ SUPP_PAE_HELD = 7, -+ SUPP_PAE_RESTART = 8, -+ SUPP_PAE_S_FORCE_AUTH = 9, -+ SUPP_PAE_S_FORCE_UNAUTH = 10 -+ } SUPP_PAE_state; /* dot1xSuppPaeState */ -+ /* Variables */ -+ Boolean userLogoff; -+ Boolean logoffSent; -+ unsigned int startCount; -+ Boolean eapRestart; -+ PortControl sPortMode; -+ /* Constants */ -+ unsigned int heldPeriod; /* dot1xSuppHeldPeriod */ -+ unsigned int startPeriod; /* dot1xSuppStartPeriod */ -+ unsigned int maxStart; /* dot1xSuppMaxStart */ -+ -+ /* Key Receive state machine */ -+ enum { -+ KEY_RX_UNKNOWN = 0, -+ KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE -+ } KEY_RX_state; -+ /* Variables */ -+ Boolean rxKey; -+ -+ /* Supplicant Backend state machine */ -+ enum { -+ SUPP_BE_UNKNOWN = 0, -+ SUPP_BE_INITIALIZE = 1, -+ SUPP_BE_IDLE = 2, -+ SUPP_BE_REQUEST = 3, -+ SUPP_BE_RECEIVE = 4, -+ SUPP_BE_RESPONSE = 5, -+ SUPP_BE_FAIL = 6, -+ SUPP_BE_TIMEOUT = 7, -+ SUPP_BE_SUCCESS = 8 -+ } SUPP_BE_state; /* dot1xSuppBackendPaeState */ -+ /* Variables */ -+ Boolean eapNoResp; -+ Boolean eapReq; -+ Boolean eapResp; -+ /* Constants */ -+ unsigned int authPeriod; /* dot1xSuppAuthPeriod */ -+ -+ /* Statistics */ -+ unsigned int dot1xSuppEapolFramesRx; -+ unsigned int dot1xSuppEapolFramesTx; -+ unsigned int dot1xSuppEapolStartFramesTx; -+ unsigned int dot1xSuppEapolLogoffFramesTx; -+ unsigned int dot1xSuppEapolRespFramesTx; -+ unsigned int dot1xSuppEapolReqIdFramesRx; -+ unsigned int dot1xSuppEapolReqFramesRx; -+ unsigned int dot1xSuppInvalidEapolFramesRx; -+ unsigned int dot1xSuppEapLengthErrorFramesRx; -+ unsigned int dot1xSuppLastEapolFrameVersion; -+ unsigned char dot1xSuppLastEapolFrameSource[6]; -+ -+ /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */ -+ Boolean changed; -+ struct eap_sm *eap; -+ struct eap_peer_config *config; -+ Boolean initial_req; -+ u8 *last_rx_key; -+ size_t last_rx_key_len; -+ struct wpabuf *eapReqData; /* for EAP */ -+ Boolean altAccept; /* for EAP */ -+ Boolean altReject; /* for EAP */ -+ Boolean replay_counter_valid; -+ u8 last_replay_counter[16]; -+ struct eapol_config conf; -+ struct eapol_ctx *ctx; -+ enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE } -+ cb_status; -+ Boolean cached_pmk; -+ -+ Boolean unicast_key_received, broadcast_key_received; -+}; -+ -+ -+#define IEEE8021X_REPLAY_COUNTER_LEN 8 -+#define IEEE8021X_KEY_SIGN_LEN 16 -+#define IEEE8021X_KEY_IV_LEN 16 -+ -+#define IEEE8021X_KEY_INDEX_FLAG 0x80 -+#define IEEE8021X_KEY_INDEX_MASK 0x03 -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct ieee802_1x_eapol_key { -+ u8 type; -+ /* Note: key_length is unaligned */ -+ u8 key_length[2]; -+ /* does not repeat within the life of the keying material used to -+ * encrypt the Key field; 64-bit NTP timestamp MAY be used here */ -+ u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN]; -+ u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */ -+ u8 key_index; /* key flag in the most significant bit: -+ * 0 = broadcast (default key), -+ * 1 = unicast (key mapping key); key index is in the -+ * 7 least significant bits */ -+ /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as -+ * the key */ -+ u8 key_signature[IEEE8021X_KEY_SIGN_LEN]; -+ -+ /* followed by key: if packet body length = 44 + key length, then the -+ * key field (of key_length bytes) contains the key in encrypted form; -+ * if packet body length = 44, key field is absent and key_length -+ * represents the number of least significant octets from -+ * MS-MPPE-Send-Key attribute to be used as the keying material; -+ * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */ -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+ -+static void eapol_sm_txLogoff(struct eapol_sm *sm); -+static void eapol_sm_txStart(struct eapol_sm *sm); -+static void eapol_sm_processKey(struct eapol_sm *sm); -+static void eapol_sm_getSuppRsp(struct eapol_sm *sm); -+static void eapol_sm_txSuppRsp(struct eapol_sm *sm); -+static void eapol_sm_abortSupp(struct eapol_sm *sm); -+static void eapol_sm_abort_cached(struct eapol_sm *sm); -+static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx); -+static void eapol_sm_set_port_authorized(struct eapol_sm *sm); -+static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm); -+ -+ -+/* Port Timers state machine - implemented as a function that will be called -+ * once a second as a registered event loop timeout */ -+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct eapol_sm *sm = timeout_ctx; -+ -+ if (sm->authWhile > 0) { -+ sm->authWhile--; -+ if (sm->authWhile == 0) -+ wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0"); -+ } -+ if (sm->heldWhile > 0) { -+ sm->heldWhile--; -+ if (sm->heldWhile == 0) -+ wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0"); -+ } -+ if (sm->startWhen > 0) { -+ sm->startWhen--; -+ if (sm->startWhen == 0) -+ wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0"); -+ } -+ if (sm->idleWhile > 0) { -+ sm->idleWhile--; -+ if (sm->idleWhile == 0) -+ wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0"); -+ } -+ -+ if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) { -+ eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, -+ sm); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick"); -+ sm->timer_tick_enabled = 0; -+ } -+ eapol_sm_step(sm); -+} -+ -+ -+static void eapol_enable_timer_tick(struct eapol_sm *sm) -+{ -+ if (sm->timer_tick_enabled) -+ return; -+ wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick"); -+ sm->timer_tick_enabled = 1; -+ eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); -+ eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); -+} -+ -+ -+SM_STATE(SUPP_PAE, LOGOFF) -+{ -+ SM_ENTRY(SUPP_PAE, LOGOFF); -+ eapol_sm_txLogoff(sm); -+ sm->logoffSent = TRUE; -+ sm->suppPortStatus = Unauthorized; -+ eapol_sm_set_port_unauthorized(sm); -+} -+ -+ -+SM_STATE(SUPP_PAE, DISCONNECTED) -+{ -+ SM_ENTRY(SUPP_PAE, DISCONNECTED); -+ sm->sPortMode = Auto; -+ sm->startCount = 0; -+ sm->logoffSent = FALSE; -+ sm->suppPortStatus = Unauthorized; -+ eapol_sm_set_port_unauthorized(sm); -+ sm->suppAbort = TRUE; -+ -+ sm->unicast_key_received = FALSE; -+ sm->broadcast_key_received = FALSE; -+} -+ -+ -+SM_STATE(SUPP_PAE, CONNECTING) -+{ -+ int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING; -+ SM_ENTRY(SUPP_PAE, CONNECTING); -+ if (send_start) { -+ sm->startWhen = sm->startPeriod; -+ sm->startCount++; -+ } else { -+ /* -+ * Do not send EAPOL-Start immediately since in most cases, -+ * Authenticator is going to start authentication immediately -+ * after association and an extra EAPOL-Start is just going to -+ * delay authentication. Use a short timeout to send the first -+ * EAPOL-Start if Authenticator does not start authentication. -+ */ -+#ifdef CONFIG_WPS -+ /* Reduce latency on starting WPS negotiation. */ -+ sm->startWhen = 1; -+#else /* CONFIG_WPS */ -+ sm->startWhen = 3; -+#endif /* CONFIG_WPS */ -+ } -+ eapol_enable_timer_tick(sm); -+ sm->eapolEap = FALSE; -+ if (send_start) -+ eapol_sm_txStart(sm); -+} -+ -+ -+SM_STATE(SUPP_PAE, AUTHENTICATING) -+{ -+ SM_ENTRY(SUPP_PAE, AUTHENTICATING); -+ sm->startCount = 0; -+ sm->suppSuccess = FALSE; -+ sm->suppFail = FALSE; -+ sm->suppTimeout = FALSE; -+ sm->keyRun = FALSE; -+ sm->keyDone = FALSE; -+ sm->suppStart = TRUE; -+} -+ -+ -+SM_STATE(SUPP_PAE, HELD) -+{ -+ SM_ENTRY(SUPP_PAE, HELD); -+ sm->heldWhile = sm->heldPeriod; -+ eapol_enable_timer_tick(sm); -+ sm->suppPortStatus = Unauthorized; -+ eapol_sm_set_port_unauthorized(sm); -+ sm->cb_status = EAPOL_CB_FAILURE; -+} -+ -+ -+SM_STATE(SUPP_PAE, AUTHENTICATED) -+{ -+ SM_ENTRY(SUPP_PAE, AUTHENTICATED); -+ sm->suppPortStatus = Authorized; -+ eapol_sm_set_port_authorized(sm); -+ sm->cb_status = EAPOL_CB_SUCCESS; -+} -+ -+ -+SM_STATE(SUPP_PAE, RESTART) -+{ -+ SM_ENTRY(SUPP_PAE, RESTART); -+ sm->eapRestart = TRUE; -+} -+ -+ -+SM_STATE(SUPP_PAE, S_FORCE_AUTH) -+{ -+ SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); -+ sm->suppPortStatus = Authorized; -+ eapol_sm_set_port_authorized(sm); -+ sm->sPortMode = ForceAuthorized; -+} -+ -+ -+SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) -+{ -+ SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); -+ sm->suppPortStatus = Unauthorized; -+ eapol_sm_set_port_unauthorized(sm); -+ sm->sPortMode = ForceUnauthorized; -+ eapol_sm_txLogoff(sm); -+} -+ -+ -+SM_STEP(SUPP_PAE) -+{ -+ if ((sm->userLogoff && !sm->logoffSent) && -+ !(sm->initialize || !sm->portEnabled)) -+ SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF); -+ else if (((sm->portControl == Auto) && -+ (sm->sPortMode != sm->portControl)) || -+ sm->initialize || !sm->portEnabled) -+ SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED); -+ else if ((sm->portControl == ForceAuthorized) && -+ (sm->sPortMode != sm->portControl) && -+ !(sm->initialize || !sm->portEnabled)) -+ SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH); -+ else if ((sm->portControl == ForceUnauthorized) && -+ (sm->sPortMode != sm->portControl) && -+ !(sm->initialize || !sm->portEnabled)) -+ SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH); -+ else switch (sm->SUPP_PAE_state) { -+ case SUPP_PAE_UNKNOWN: -+ break; -+ case SUPP_PAE_LOGOFF: -+ if (!sm->userLogoff) -+ SM_ENTER(SUPP_PAE, DISCONNECTED); -+ break; -+ case SUPP_PAE_DISCONNECTED: -+ SM_ENTER(SUPP_PAE, CONNECTING); -+ break; -+ case SUPP_PAE_CONNECTING: -+ if (sm->startWhen == 0 && sm->startCount < sm->maxStart) -+ SM_ENTER(SUPP_PAE, CONNECTING); -+ else if (sm->startWhen == 0 && -+ sm->startCount >= sm->maxStart && -+ sm->portValid) -+ SM_ENTER(SUPP_PAE, AUTHENTICATED); -+ else if (sm->eapSuccess || sm->eapFail) -+ SM_ENTER(SUPP_PAE, AUTHENTICATING); -+ else if (sm->eapolEap) -+ SM_ENTER(SUPP_PAE, RESTART); -+ else if (sm->startWhen == 0 && -+ sm->startCount >= sm->maxStart && -+ !sm->portValid) -+ SM_ENTER(SUPP_PAE, HELD); -+ break; -+ case SUPP_PAE_AUTHENTICATING: -+ if (sm->eapSuccess && !sm->portValid && -+ sm->conf.accept_802_1x_keys && -+ sm->conf.required_keys == 0) { -+ wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for " -+ "plaintext connection; no EAPOL-Key frames " -+ "required"); -+ sm->portValid = TRUE; -+ if (sm->ctx->eapol_done_cb) -+ sm->ctx->eapol_done_cb(sm->ctx->ctx); -+ } -+ if (sm->eapSuccess && sm->portValid) -+ SM_ENTER(SUPP_PAE, AUTHENTICATED); -+ else if (sm->eapFail || (sm->keyDone && !sm->portValid)) -+ SM_ENTER(SUPP_PAE, HELD); -+ else if (sm->suppTimeout) -+ SM_ENTER(SUPP_PAE, CONNECTING); -+ break; -+ case SUPP_PAE_HELD: -+ if (sm->heldWhile == 0) -+ SM_ENTER(SUPP_PAE, CONNECTING); -+ else if (sm->eapolEap) -+ SM_ENTER(SUPP_PAE, RESTART); -+ break; -+ case SUPP_PAE_AUTHENTICATED: -+ if (sm->eapolEap && sm->portValid) -+ SM_ENTER(SUPP_PAE, RESTART); -+ else if (!sm->portValid) -+ SM_ENTER(SUPP_PAE, DISCONNECTED); -+ break; -+ case SUPP_PAE_RESTART: -+ if (!sm->eapRestart) -+ SM_ENTER(SUPP_PAE, AUTHENTICATING); -+ break; -+ case SUPP_PAE_S_FORCE_AUTH: -+ break; -+ case SUPP_PAE_S_FORCE_UNAUTH: -+ break; -+ } -+} -+ -+ -+SM_STATE(KEY_RX, NO_KEY_RECEIVE) -+{ -+ SM_ENTRY(KEY_RX, NO_KEY_RECEIVE); -+} -+ -+ -+SM_STATE(KEY_RX, KEY_RECEIVE) -+{ -+ SM_ENTRY(KEY_RX, KEY_RECEIVE); -+ eapol_sm_processKey(sm); -+ sm->rxKey = FALSE; -+} -+ -+ -+SM_STEP(KEY_RX) -+{ -+ if (sm->initialize || !sm->portEnabled) -+ SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE); -+ switch (sm->KEY_RX_state) { -+ case KEY_RX_UNKNOWN: -+ break; -+ case KEY_RX_NO_KEY_RECEIVE: -+ if (sm->rxKey) -+ SM_ENTER(KEY_RX, KEY_RECEIVE); -+ break; -+ case KEY_RX_KEY_RECEIVE: -+ if (sm->rxKey) -+ SM_ENTER(KEY_RX, KEY_RECEIVE); -+ break; -+ } -+} -+ -+ -+SM_STATE(SUPP_BE, REQUEST) -+{ -+ SM_ENTRY(SUPP_BE, REQUEST); -+ sm->authWhile = 0; -+ sm->eapReq = TRUE; -+ eapol_sm_getSuppRsp(sm); -+} -+ -+ -+SM_STATE(SUPP_BE, RESPONSE) -+{ -+ SM_ENTRY(SUPP_BE, RESPONSE); -+ eapol_sm_txSuppRsp(sm); -+ sm->eapResp = FALSE; -+} -+ -+ -+SM_STATE(SUPP_BE, SUCCESS) -+{ -+ SM_ENTRY(SUPP_BE, SUCCESS); -+ sm->keyRun = TRUE; -+ sm->suppSuccess = TRUE; -+ -+ if (eap_key_available(sm->eap)) { -+ /* New key received - clear IEEE 802.1X EAPOL-Key replay -+ * counter */ -+ sm->replay_counter_valid = FALSE; -+ } -+} -+ -+ -+SM_STATE(SUPP_BE, FAIL) -+{ -+ SM_ENTRY(SUPP_BE, FAIL); -+ sm->suppFail = TRUE; -+} -+ -+ -+SM_STATE(SUPP_BE, TIMEOUT) -+{ -+ SM_ENTRY(SUPP_BE, TIMEOUT); -+ sm->suppTimeout = TRUE; -+} -+ -+ -+SM_STATE(SUPP_BE, IDLE) -+{ -+ SM_ENTRY(SUPP_BE, IDLE); -+ sm->suppStart = FALSE; -+ sm->initial_req = TRUE; -+} -+ -+ -+SM_STATE(SUPP_BE, INITIALIZE) -+{ -+ SM_ENTRY(SUPP_BE, INITIALIZE); -+ eapol_sm_abortSupp(sm); -+ sm->suppAbort = FALSE; -+} -+ -+ -+SM_STATE(SUPP_BE, RECEIVE) -+{ -+ SM_ENTRY(SUPP_BE, RECEIVE); -+ sm->authWhile = sm->authPeriod; -+ eapol_enable_timer_tick(sm); -+ sm->eapolEap = FALSE; -+ sm->eapNoResp = FALSE; -+ sm->initial_req = FALSE; -+} -+ -+ -+SM_STEP(SUPP_BE) -+{ -+ if (sm->initialize || sm->suppAbort) -+ SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE); -+ else switch (sm->SUPP_BE_state) { -+ case SUPP_BE_UNKNOWN: -+ break; -+ case SUPP_BE_REQUEST: -+ /* -+ * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL -+ * and SUCCESS based on eapFail and eapSuccess, respectively. -+ * However, IEEE Std 802.1X-2004 is also specifying that -+ * eapNoResp should be set in conjuction with eapSuccess and -+ * eapFail which would mean that more than one of the -+ * transitions here would be activated at the same time. -+ * Skipping RESPONSE and/or RECEIVE states in these cases can -+ * cause problems and the direct transitions to do not seem -+ * correct. Because of this, the conditions for these -+ * transitions are verified only after eapNoResp. They are -+ * unlikely to be used since eapNoResp should always be set if -+ * either of eapSuccess or eapFail is set. -+ */ -+ if (sm->eapResp && sm->eapNoResp) { -+ wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both " -+ "eapResp and eapNoResp set?!"); -+ } -+ if (sm->eapResp) -+ SM_ENTER(SUPP_BE, RESPONSE); -+ else if (sm->eapNoResp) -+ SM_ENTER(SUPP_BE, RECEIVE); -+ else if (sm->eapFail) -+ SM_ENTER(SUPP_BE, FAIL); -+ else if (sm->eapSuccess) -+ SM_ENTER(SUPP_BE, SUCCESS); -+ break; -+ case SUPP_BE_RESPONSE: -+ SM_ENTER(SUPP_BE, RECEIVE); -+ break; -+ case SUPP_BE_SUCCESS: -+ SM_ENTER(SUPP_BE, IDLE); -+ break; -+ case SUPP_BE_FAIL: -+ SM_ENTER(SUPP_BE, IDLE); -+ break; -+ case SUPP_BE_TIMEOUT: -+ SM_ENTER(SUPP_BE, IDLE); -+ break; -+ case SUPP_BE_IDLE: -+ if (sm->eapFail && sm->suppStart) -+ SM_ENTER(SUPP_BE, FAIL); -+ else if (sm->eapolEap && sm->suppStart) -+ SM_ENTER(SUPP_BE, REQUEST); -+ else if (sm->eapSuccess && sm->suppStart) -+ SM_ENTER(SUPP_BE, SUCCESS); -+ break; -+ case SUPP_BE_INITIALIZE: -+ SM_ENTER(SUPP_BE, IDLE); -+ break; -+ case SUPP_BE_RECEIVE: -+ if (sm->eapolEap) -+ SM_ENTER(SUPP_BE, REQUEST); -+ else if (sm->eapFail) -+ SM_ENTER(SUPP_BE, FAIL); -+ else if (sm->authWhile == 0) -+ SM_ENTER(SUPP_BE, TIMEOUT); -+ else if (sm->eapSuccess) -+ SM_ENTER(SUPP_BE, SUCCESS); -+ break; -+ } -+} -+ -+ -+static void eapol_sm_txLogoff(struct eapol_sm *sm) -+{ -+ wpa_printf(MSG_DEBUG, "EAPOL: txLogoff"); -+ sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, -+ IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0); -+ sm->dot1xSuppEapolLogoffFramesTx++; -+ sm->dot1xSuppEapolFramesTx++; -+} -+ -+ -+static void eapol_sm_txStart(struct eapol_sm *sm) -+{ -+ wpa_printf(MSG_DEBUG, "EAPOL: txStart"); -+ sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, -+ IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0); -+ sm->dot1xSuppEapolStartFramesTx++; -+ sm->dot1xSuppEapolFramesTx++; -+} -+ -+ -+#define IEEE8021X_ENCR_KEY_LEN 32 -+#define IEEE8021X_SIGN_KEY_LEN 32 -+ -+struct eap_key_data { -+ u8 encr_key[IEEE8021X_ENCR_KEY_LEN]; -+ u8 sign_key[IEEE8021X_SIGN_KEY_LEN]; -+}; -+ -+ -+static void eapol_sm_processKey(struct eapol_sm *sm) -+{ -+ struct ieee802_1x_hdr *hdr; -+ struct ieee802_1x_eapol_key *key; -+ struct eap_key_data keydata; -+ u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32]; -+ u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN]; -+ int key_len, res, sign_key_len, encr_key_len; -+ u16 rx_key_length; -+ -+ wpa_printf(MSG_DEBUG, "EAPOL: processKey"); -+ if (sm->last_rx_key == NULL) -+ return; -+ -+ if (!sm->conf.accept_802_1x_keys) { -+ wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key" -+ " even though this was not accepted - " -+ "ignoring this packet"); -+ return; -+ } -+ -+ hdr = (struct ieee802_1x_hdr *) sm->last_rx_key; -+ key = (struct ieee802_1x_eapol_key *) (hdr + 1); -+ if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) { -+ wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame"); -+ return; -+ } -+ rx_key_length = WPA_GET_BE16(key->key_length); -+ wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d " -+ "EAPOL-Key: type=%d key_length=%d key_index=0x%x", -+ hdr->version, hdr->type, be_to_host16(hdr->length), -+ key->type, rx_key_length, key->key_index); -+ -+ eapol_sm_notify_lower_layer_success(sm, 1); -+ sign_key_len = IEEE8021X_SIGN_KEY_LEN; -+ encr_key_len = IEEE8021X_ENCR_KEY_LEN; -+ res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata)); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " -+ "decrypting EAPOL-Key keys"); -+ return; -+ } -+ if (res == 16) { -+ /* LEAP derives only 16 bytes of keying material. */ -+ res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); -+ if (res) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " -+ "master key for decrypting EAPOL-Key keys"); -+ return; -+ } -+ sign_key_len = 16; -+ encr_key_len = 16; -+ os_memcpy(keydata.sign_key, keydata.encr_key, 16); -+ } else if (res) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " -+ "data for decrypting EAPOL-Key keys (res=%d)", res); -+ return; -+ } -+ -+ /* The key replay_counter must increase when same master key */ -+ if (sm->replay_counter_valid && -+ os_memcmp(sm->last_replay_counter, key->replay_counter, -+ IEEE8021X_REPLAY_COUNTER_LEN) >= 0) { -+ wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did " -+ "not increase - ignoring key"); -+ wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter", -+ sm->last_replay_counter, -+ IEEE8021X_REPLAY_COUNTER_LEN); -+ wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter", -+ key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); -+ return; -+ } -+ -+ /* Verify key signature (HMAC-MD5) */ -+ os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); -+ os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN); -+ hmac_md5(keydata.sign_key, sign_key_len, -+ sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), -+ key->key_signature); -+ if (os_memcmp(orig_key_sign, key->key_signature, -+ IEEE8021X_KEY_SIGN_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " -+ "EAPOL-Key packet"); -+ os_memcpy(key->key_signature, orig_key_sign, -+ IEEE8021X_KEY_SIGN_LEN); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); -+ -+ key_len = be_to_host16(hdr->length) - sizeof(*key); -+ if (key_len > 32 || rx_key_length > 32) { -+ wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d", -+ key_len ? key_len : rx_key_length); -+ return; -+ } -+ if (key_len == rx_key_length) { -+ os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); -+ os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, -+ encr_key_len); -+ os_memcpy(datakey, key + 1, key_len); -+ rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0, -+ datakey, key_len); -+ wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key", -+ datakey, key_len); -+ } else if (key_len == 0) { -+ /* -+ * IEEE 802.1X-2004 specifies that least significant Key Length -+ * octets from MS-MPPE-Send-Key are used as the key if the key -+ * data is not present. This seems to be meaning the beginning -+ * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in -+ * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator. -+ * Anyway, taking the beginning of the keying material from EAP -+ * seems to interoperate with Authenticators. -+ */ -+ key_len = rx_key_length; -+ os_memcpy(datakey, keydata.encr_key, key_len); -+ wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying " -+ "material data encryption key", -+ datakey, key_len); -+ } else { -+ wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " -+ "(key_length=%d)", key_len, rx_key_length); -+ return; -+ } -+ -+ sm->replay_counter_valid = TRUE; -+ os_memcpy(sm->last_replay_counter, key->replay_counter, -+ IEEE8021X_REPLAY_COUNTER_LEN); -+ -+ wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " -+ "len %d", -+ key->key_index & IEEE8021X_KEY_INDEX_FLAG ? -+ "unicast" : "broadcast", -+ key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); -+ -+ if (sm->ctx->set_wep_key && -+ sm->ctx->set_wep_key(sm->ctx->ctx, -+ key->key_index & IEEE8021X_KEY_INDEX_FLAG, -+ key->key_index & IEEE8021X_KEY_INDEX_MASK, -+ datakey, key_len) < 0) { -+ wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " -+ " driver."); -+ } else { -+ if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) -+ sm->unicast_key_received = TRUE; -+ else -+ sm->broadcast_key_received = TRUE; -+ -+ if ((sm->unicast_key_received || -+ !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) && -+ (sm->broadcast_key_received || -+ !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST))) -+ { -+ wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " -+ "frames received"); -+ sm->portValid = TRUE; -+ if (sm->ctx->eapol_done_cb) -+ sm->ctx->eapol_done_cb(sm->ctx->ctx); -+ } -+ } -+} -+ -+ -+static void eapol_sm_getSuppRsp(struct eapol_sm *sm) -+{ -+ wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp"); -+ /* EAP layer processing; no special code is needed, since Supplicant -+ * Backend state machine is waiting for eapNoResp or eapResp to be set -+ * and these are only set in the EAP state machine when the processing -+ * has finished. */ -+} -+ -+ -+static void eapol_sm_txSuppRsp(struct eapol_sm *sm) -+{ -+ struct wpabuf *resp; -+ -+ wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp"); -+ resp = eap_get_eapRespData(sm->eap); -+ if (resp == NULL) { -+ wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data " -+ "not available"); -+ return; -+ } -+ -+ /* Send EAP-Packet from the EAP layer to the Authenticator */ -+ sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, -+ IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp), -+ wpabuf_len(resp)); -+ -+ /* eapRespData is not used anymore, so free it here */ -+ wpabuf_free(resp); -+ -+ if (sm->initial_req) -+ sm->dot1xSuppEapolReqIdFramesRx++; -+ else -+ sm->dot1xSuppEapolReqFramesRx++; -+ sm->dot1xSuppEapolRespFramesTx++; -+ sm->dot1xSuppEapolFramesTx++; -+} -+ -+ -+static void eapol_sm_abortSupp(struct eapol_sm *sm) -+{ -+ /* release system resources that may have been allocated for the -+ * authentication session */ -+ os_free(sm->last_rx_key); -+ sm->last_rx_key = NULL; -+ wpabuf_free(sm->eapReqData); -+ sm->eapReqData = NULL; -+ eap_sm_abort(sm->eap); -+} -+ -+ -+static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ eapol_sm_step(timeout_ctx); -+} -+ -+ -+static void eapol_sm_set_port_authorized(struct eapol_sm *sm) -+{ -+ if (sm->ctx->port_cb) -+ sm->ctx->port_cb(sm->ctx->ctx, 1); -+} -+ -+ -+static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm) -+{ -+ if (sm->ctx->port_cb) -+ sm->ctx->port_cb(sm->ctx->ctx, 0); -+} -+ -+ -+/** -+ * eapol_sm_step - EAPOL state machine step function -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * -+ * This function is called to notify the state machine about changed external -+ * variables. It will step through the EAPOL state machines in loop to process -+ * all triggered state changes. -+ */ -+void eapol_sm_step(struct eapol_sm *sm) -+{ -+ int i; -+ -+ /* In theory, it should be ok to run this in loop until !changed. -+ * However, it is better to use a limit on number of iterations to -+ * allow events (e.g., SIGTERM) to stop the program cleanly if the -+ * state machine were to generate a busy loop. */ -+ for (i = 0; i < 100; i++) { -+ sm->changed = FALSE; -+ SM_STEP_RUN(SUPP_PAE); -+ SM_STEP_RUN(KEY_RX); -+ SM_STEP_RUN(SUPP_BE); -+ if (eap_peer_sm_step(sm->eap)) -+ sm->changed = TRUE; -+ if (!sm->changed) -+ break; -+ } -+ -+ if (sm->changed) { -+ /* restart EAPOL state machine step from timeout call in order -+ * to allow other events to be processed. */ -+ eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); -+ eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm); -+ } -+ -+ if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) { -+ int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0; -+ sm->cb_status = EAPOL_CB_IN_PROGRESS; -+ sm->ctx->cb(sm, success, sm->ctx->cb_ctx); -+ } -+} -+ -+ -+#ifdef CONFIG_CTRL_IFACE -+static const char *eapol_supp_pae_state(int state) -+{ -+ switch (state) { -+ case SUPP_PAE_LOGOFF: -+ return "LOGOFF"; -+ case SUPP_PAE_DISCONNECTED: -+ return "DISCONNECTED"; -+ case SUPP_PAE_CONNECTING: -+ return "CONNECTING"; -+ case SUPP_PAE_AUTHENTICATING: -+ return "AUTHENTICATING"; -+ case SUPP_PAE_HELD: -+ return "HELD"; -+ case SUPP_PAE_AUTHENTICATED: -+ return "AUTHENTICATED"; -+ case SUPP_PAE_RESTART: -+ return "RESTART"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+ -+static const char *eapol_supp_be_state(int state) -+{ -+ switch (state) { -+ case SUPP_BE_REQUEST: -+ return "REQUEST"; -+ case SUPP_BE_RESPONSE: -+ return "RESPONSE"; -+ case SUPP_BE_SUCCESS: -+ return "SUCCESS"; -+ case SUPP_BE_FAIL: -+ return "FAIL"; -+ case SUPP_BE_TIMEOUT: -+ return "TIMEOUT"; -+ case SUPP_BE_IDLE: -+ return "IDLE"; -+ case SUPP_BE_INITIALIZE: -+ return "INITIALIZE"; -+ case SUPP_BE_RECEIVE: -+ return "RECEIVE"; -+ default: -+ return "UNKNOWN"; -+ } -+} -+ -+ -+static const char * eapol_port_status(PortStatus status) -+{ -+ if (status == Authorized) -+ return "Authorized"; -+ else -+ return "Unauthorized"; -+} -+#endif /* CONFIG_CTRL_IFACE */ -+ -+ -+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -+static const char * eapol_port_control(PortControl ctrl) -+{ -+ switch (ctrl) { -+ case Auto: -+ return "Auto"; -+ case ForceUnauthorized: -+ return "ForceUnauthorized"; -+ case ForceAuthorized: -+ return "ForceAuthorized"; -+ default: -+ return "Unknown"; -+ } -+} -+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+/** -+ * eapol_sm_configure - Set EAPOL variables -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @heldPeriod: dot1xSuppHeldPeriod -+ * @authPeriod: dot1xSuppAuthPeriod -+ * @startPeriod: dot1xSuppStartPeriod -+ * @maxStart: dot1xSuppMaxStart -+ * -+ * Set configurable EAPOL state machine variables. Each variable can be set to -+ * the given value or ignored if set to -1 (to set only some of the variables). -+ */ -+void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, -+ int startPeriod, int maxStart) -+{ -+ if (sm == NULL) -+ return; -+ if (heldPeriod >= 0) -+ sm->heldPeriod = heldPeriod; -+ if (authPeriod >= 0) -+ sm->authPeriod = authPeriod; -+ if (startPeriod >= 0) -+ sm->startPeriod = startPeriod; -+ if (maxStart >= 0) -+ sm->maxStart = maxStart; -+} -+ -+ -+/** -+ * eapol_sm_get_method_name - Get EAPOL method name -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * Returns: Static string containing name of current eap method or NULL -+ */ -+const char * eapol_sm_get_method_name(struct eapol_sm *sm) -+{ -+ if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED || -+ sm->suppPortStatus != Authorized) -+ return NULL; -+ -+ return eap_sm_get_method_name(sm->eap); -+} -+ -+ -+#ifdef CONFIG_CTRL_IFACE -+/** -+ * eapol_sm_get_status - Get EAPOL state machine status -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @buf: Buffer for status information -+ * @buflen: Maximum buffer length -+ * @verbose: Whether to include verbose status information -+ * Returns: Number of bytes written to buf. -+ * -+ * Query EAPOL state machine for status information. This function fills in a -+ * text area with current status information from the EAPOL state machine. If -+ * the buffer (buf) is not large enough, status information will be truncated -+ * to fit the buffer. -+ */ -+int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, -+ int verbose) -+{ -+ int len, ret; -+ if (sm == NULL) -+ return 0; -+ -+ len = os_snprintf(buf, buflen, -+ "Supplicant PAE state=%s\n" -+ "suppPortStatus=%s\n", -+ eapol_supp_pae_state(sm->SUPP_PAE_state), -+ eapol_port_status(sm->suppPortStatus)); -+ if (len < 0 || (size_t) len >= buflen) -+ return 0; -+ -+ if (verbose) { -+ ret = os_snprintf(buf + len, buflen - len, -+ "heldPeriod=%u\n" -+ "authPeriod=%u\n" -+ "startPeriod=%u\n" -+ "maxStart=%u\n" -+ "portControl=%s\n" -+ "Supplicant Backend state=%s\n", -+ sm->heldPeriod, -+ sm->authPeriod, -+ sm->startPeriod, -+ sm->maxStart, -+ eapol_port_control(sm->portControl), -+ eapol_supp_be_state(sm->SUPP_BE_state)); -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ } -+ -+ len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose); -+ -+ return len; -+} -+ -+ -+/** -+ * eapol_sm_get_mib - Get EAPOL state machine MIBs -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @buf: Buffer for MIB information -+ * @buflen: Maximum buffer length -+ * Returns: Number of bytes written to buf. -+ * -+ * Query EAPOL state machine for MIB information. This function fills in a -+ * text area with current MIB information from the EAPOL state machine. If -+ * the buffer (buf) is not large enough, MIB information will be truncated to -+ * fit the buffer. -+ */ -+int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen) -+{ -+ size_t len; -+ int ret; -+ -+ if (sm == NULL) -+ return 0; -+ ret = os_snprintf(buf, buflen, -+ "dot1xSuppPaeState=%d\n" -+ "dot1xSuppHeldPeriod=%u\n" -+ "dot1xSuppAuthPeriod=%u\n" -+ "dot1xSuppStartPeriod=%u\n" -+ "dot1xSuppMaxStart=%u\n" -+ "dot1xSuppSuppControlledPortStatus=%s\n" -+ "dot1xSuppBackendPaeState=%d\n", -+ sm->SUPP_PAE_state, -+ sm->heldPeriod, -+ sm->authPeriod, -+ sm->startPeriod, -+ sm->maxStart, -+ sm->suppPortStatus == Authorized ? -+ "Authorized" : "Unauthorized", -+ sm->SUPP_BE_state); -+ -+ if (ret < 0 || (size_t) ret >= buflen) -+ return 0; -+ len = ret; -+ -+ ret = os_snprintf(buf + len, buflen - len, -+ "dot1xSuppEapolFramesRx=%u\n" -+ "dot1xSuppEapolFramesTx=%u\n" -+ "dot1xSuppEapolStartFramesTx=%u\n" -+ "dot1xSuppEapolLogoffFramesTx=%u\n" -+ "dot1xSuppEapolRespFramesTx=%u\n" -+ "dot1xSuppEapolReqIdFramesRx=%u\n" -+ "dot1xSuppEapolReqFramesRx=%u\n" -+ "dot1xSuppInvalidEapolFramesRx=%u\n" -+ "dot1xSuppEapLengthErrorFramesRx=%u\n" -+ "dot1xSuppLastEapolFrameVersion=%u\n" -+ "dot1xSuppLastEapolFrameSource=" MACSTR "\n", -+ sm->dot1xSuppEapolFramesRx, -+ sm->dot1xSuppEapolFramesTx, -+ sm->dot1xSuppEapolStartFramesTx, -+ sm->dot1xSuppEapolLogoffFramesTx, -+ sm->dot1xSuppEapolRespFramesTx, -+ sm->dot1xSuppEapolReqIdFramesRx, -+ sm->dot1xSuppEapolReqFramesRx, -+ sm->dot1xSuppInvalidEapolFramesRx, -+ sm->dot1xSuppEapLengthErrorFramesRx, -+ sm->dot1xSuppLastEapolFrameVersion, -+ MAC2STR(sm->dot1xSuppLastEapolFrameSource)); -+ -+ if (ret < 0 || (size_t) ret >= buflen - len) -+ return len; -+ len += ret; -+ -+ return len; -+} -+#endif /* CONFIG_CTRL_IFACE */ -+ -+ -+/** -+ * eapol_sm_rx_eapol - Process received EAPOL frames -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @src: Source MAC address of the EAPOL packet -+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) -+ * @len: Length of the EAPOL frame -+ * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine, -+ * -1 failure -+ */ -+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, -+ size_t len) -+{ -+ const struct ieee802_1x_hdr *hdr; -+ const struct ieee802_1x_eapol_key *key; -+ int data_len; -+ int res = 1; -+ size_t plen; -+ -+ if (sm == NULL) -+ return 0; -+ sm->dot1xSuppEapolFramesRx++; -+ if (len < sizeof(*hdr)) { -+ sm->dot1xSuppInvalidEapolFramesRx++; -+ return 0; -+ } -+ hdr = (const struct ieee802_1x_hdr *) buf; -+ sm->dot1xSuppLastEapolFrameVersion = hdr->version; -+ os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN); -+ if (hdr->version < EAPOL_VERSION) { -+ /* TODO: backwards compatibility */ -+ } -+ plen = be_to_host16(hdr->length); -+ if (plen > len - sizeof(*hdr)) { -+ sm->dot1xSuppEapLengthErrorFramesRx++; -+ return 0; -+ } -+#ifdef CONFIG_WPS -+ if (sm->conf.workaround && -+ plen < len - sizeof(*hdr) && -+ hdr->type == IEEE802_1X_TYPE_EAP_PACKET && -+ len - sizeof(*hdr) > sizeof(struct eap_hdr)) { -+ const struct eap_hdr *ehdr = -+ (const struct eap_hdr *) (hdr + 1); -+ u16 elen; -+ -+ elen = be_to_host16(ehdr->length); -+ if (elen > plen && elen <= len - sizeof(*hdr)) { -+ /* -+ * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS -+ * packets with too short EAPOL header length field -+ * (14 octets). This is fixed in firmware Ver.1.49. -+ * As a workaround, fix the EAPOL header based on the -+ * correct length in the EAP packet. -+ */ -+ wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL " -+ "payload length based on EAP header: " -+ "%d -> %d", (int) plen, elen); -+ plen = elen; -+ } -+ } -+#endif /* CONFIG_WPS */ -+ data_len = plen + sizeof(*hdr); -+ -+ switch (hdr->type) { -+ case IEEE802_1X_TYPE_EAP_PACKET: -+ if (sm->cached_pmk) { -+ /* Trying to use PMKSA caching, but Authenticator did -+ * not seem to have a matching entry. Need to restart -+ * EAPOL state machines. -+ */ -+ eapol_sm_abort_cached(sm); -+ } -+ wpabuf_free(sm->eapReqData); -+ sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen); -+ if (sm->eapReqData) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet " -+ "frame"); -+ sm->eapolEap = TRUE; -+ eapol_sm_step(sm); -+ } -+ break; -+ case IEEE802_1X_TYPE_EAPOL_KEY: -+ if (plen < sizeof(*key)) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key " -+ "frame received"); -+ break; -+ } -+ key = (const struct ieee802_1x_eapol_key *) (hdr + 1); -+ if (key->type == EAPOL_KEY_TYPE_WPA || -+ key->type == EAPOL_KEY_TYPE_RSN) { -+ /* WPA Supplicant takes care of this frame. */ -+ wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key " -+ "frame in EAPOL state machines"); -+ res = 0; -+ break; -+ } -+ if (key->type != EAPOL_KEY_TYPE_RC4) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown " -+ "EAPOL-Key type %d", key->type); -+ break; -+ } -+ os_free(sm->last_rx_key); -+ sm->last_rx_key = os_malloc(data_len); -+ if (sm->last_rx_key) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key " -+ "frame"); -+ os_memcpy(sm->last_rx_key, buf, data_len); -+ sm->last_rx_key_len = data_len; -+ sm->rxKey = TRUE; -+ eapol_sm_step(sm); -+ } -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d", -+ hdr->type); -+ sm->dot1xSuppInvalidEapolFramesRx++; -+ break; -+ } -+ -+ return res; -+} -+ -+ -+/** -+ * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * -+ * Notify EAPOL state machine about transmitted EAPOL packet from an external -+ * component, e.g., WPA. This will update the statistics. -+ */ -+void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm) -+{ -+ if (sm) -+ sm->dot1xSuppEapolFramesTx++; -+} -+ -+ -+/** -+ * eapol_sm_notify_portEnabled - Notification about portEnabled change -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @enabled: New portEnabled value -+ * -+ * Notify EAPOL state machine about new portEnabled value. -+ */ -+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAPOL: External notification - " -+ "portEnabled=%d", enabled); -+ sm->portEnabled = enabled; -+ eapol_sm_step(sm); -+} -+ -+ -+/** -+ * eapol_sm_notify_portValid - Notification about portValid change -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @valid: New portValid value -+ * -+ * Notify EAPOL state machine about new portValid value. -+ */ -+void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAPOL: External notification - " -+ "portValid=%d", valid); -+ sm->portValid = valid; -+ eapol_sm_step(sm); -+} -+ -+ -+/** -+ * eapol_sm_notify_eap_success - Notification of external EAP success trigger -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @success: %TRUE = set success, %FALSE = clear success -+ * -+ * Notify the EAPOL state machine that external event has forced EAP state to -+ * success (success = %TRUE). This can be cleared by setting success = %FALSE. -+ * -+ * This function is called to update EAP state when WPA-PSK key handshake has -+ * been completed successfully since WPA-PSK does not use EAP state machine. -+ */ -+void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAPOL: External notification - " -+ "EAP success=%d", success); -+ sm->eapSuccess = success; -+ sm->altAccept = success; -+ if (success) -+ eap_notify_success(sm->eap); -+ eapol_sm_step(sm); -+} -+ -+ -+/** -+ * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @fail: %TRUE = set failure, %FALSE = clear failure -+ * -+ * Notify EAPOL state machine that external event has forced EAP state to -+ * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE. -+ */ -+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAPOL: External notification - " -+ "EAP fail=%d", fail); -+ sm->eapFail = fail; -+ sm->altReject = fail; -+ eapol_sm_step(sm); -+} -+ -+ -+/** -+ * eapol_sm_notify_config - Notification of EAPOL configuration change -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @config: Pointer to current network EAP configuration -+ * @conf: Pointer to EAPOL configuration data -+ * -+ * Notify EAPOL state machine that configuration has changed. config will be -+ * stored as a backpointer to network configuration. This can be %NULL to clear -+ * the stored pointed. conf will be copied to local EAPOL/EAP configuration -+ * data. If conf is %NULL, this part of the configuration change will be -+ * skipped. -+ */ -+void eapol_sm_notify_config(struct eapol_sm *sm, -+ struct eap_peer_config *config, -+ const struct eapol_config *conf) -+{ -+ if (sm == NULL) -+ return; -+ -+ sm->config = config; -+ -+ if (conf == NULL) -+ return; -+ -+ sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys; -+ sm->conf.required_keys = conf->required_keys; -+ sm->conf.fast_reauth = conf->fast_reauth; -+ sm->conf.workaround = conf->workaround; -+ if (sm->eap) { -+ eap_set_fast_reauth(sm->eap, conf->fast_reauth); -+ eap_set_workaround(sm->eap, conf->workaround); -+ eap_set_force_disabled(sm->eap, conf->eap_disabled); -+ } -+} -+ -+ -+/** -+ * eapol_sm_get_key - Get master session key (MSK) from EAP -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @key: Pointer for key buffer -+ * @len: Number of bytes to copy to key -+ * Returns: 0 on success (len of key available), maximum available key len -+ * (>0) if key is available but it is shorter than len, or -1 on failure. -+ * -+ * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key -+ * is available only after a successful authentication. -+ */ -+int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) -+{ -+ const u8 *eap_key; -+ size_t eap_len; -+ -+ if (sm == NULL || !eap_key_available(sm->eap)) { -+ wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available"); -+ return -1; -+ } -+ eap_key = eap_get_eapKeyData(sm->eap, &eap_len); -+ if (eap_key == NULL) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData"); -+ return -1; -+ } -+ if (len > eap_len) { -+ wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not " -+ "available (len=%lu)", -+ (unsigned long) len, (unsigned long) eap_len); -+ return eap_len; -+ } -+ os_memcpy(key, eap_key, len); -+ wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)", -+ (unsigned long) len); -+ return 0; -+} -+ -+ -+/** -+ * eapol_sm_notify_logoff - Notification of logon/logoff commands -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @logoff: Whether command was logoff -+ * -+ * Notify EAPOL state machines that user requested logon/logoff. -+ */ -+void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff) -+{ -+ if (sm) { -+ sm->userLogoff = logoff; -+ eapol_sm_step(sm); -+ } -+} -+ -+ -+/** -+ * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * -+ * Notify EAPOL state machines that PMKSA caching was successful. This is used -+ * to move EAPOL and EAP state machines into authenticated/successful state. -+ */ -+void eapol_sm_notify_cached(struct eapol_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL"); -+ sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED; -+ sm->suppPortStatus = Authorized; -+ eapol_sm_set_port_authorized(sm); -+ sm->portValid = TRUE; -+ eap_notify_success(sm->eap); -+ eapol_sm_step(sm); -+} -+ -+ -+/** -+ * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @attempt: Whether PMKSA caching is tried -+ * -+ * Notify EAPOL state machines whether PMKSA caching is used. -+ */ -+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt) -+{ -+ if (sm == NULL) -+ return; -+ if (attempt) { -+ wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA"); -+ sm->cached_pmk = TRUE; -+ } else { -+ wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA"); -+ sm->cached_pmk = FALSE; -+ } -+} -+ -+ -+static void eapol_sm_abort_cached(struct eapol_sm *sm) -+{ -+ wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, " -+ "doing full EAP authentication"); -+ if (sm == NULL) -+ return; -+ sm->cached_pmk = FALSE; -+ sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; -+ sm->suppPortStatus = Unauthorized; -+ eapol_sm_set_port_unauthorized(sm); -+ -+ /* Make sure we do not start sending EAPOL-Start frames first, but -+ * instead move to RESTART state to start EAPOL authentication. */ -+ sm->startWhen = 3; -+ eapol_enable_timer_tick(sm); -+ -+ if (sm->ctx->aborted_cached) -+ sm->ctx->aborted_cached(sm->ctx->ctx); -+} -+ -+ -+/** -+ * eapol_sm_register_scard_ctx - Notification of smart card context -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @ctx: Context data for smart card operations -+ * -+ * Notify EAPOL state machines of context data for smart card operations. This -+ * context data will be used as a parameter for scard_*() functions. -+ */ -+void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx) -+{ -+ if (sm) { -+ sm->ctx->scard_ctx = ctx; -+ eap_register_scard_ctx(sm->eap, ctx); -+ } -+} -+ -+ -+/** -+ * eapol_sm_notify_portControl - Notification of portControl changes -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @portControl: New value for portControl variable -+ * -+ * Notify EAPOL state machines that portControl variable has changed. -+ */ -+void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl) -+{ -+ if (sm == NULL) -+ return; -+ wpa_printf(MSG_DEBUG, "EAPOL: External notification - " -+ "portControl=%s", eapol_port_control(portControl)); -+ sm->portControl = portControl; -+ eapol_sm_step(sm); -+} -+ -+ -+/** -+ * eapol_sm_notify_ctrl_attached - Notification of attached monitor -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * -+ * Notify EAPOL state machines that a monitor was attached to the control -+ * interface to trigger re-sending of pending requests for user input. -+ */ -+void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ eap_sm_notify_ctrl_attached(sm->eap); -+} -+ -+ -+/** -+ * eapol_sm_notify_ctrl_response - Notification of received user input -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * -+ * Notify EAPOL state machines that a control response, i.e., user -+ * input, was received in order to trigger retrying of a pending EAP request. -+ */ -+void eapol_sm_notify_ctrl_response(struct eapol_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ if (sm->eapReqData && !sm->eapReq) { -+ wpa_printf(MSG_DEBUG, "EAPOL: received control response (user " -+ "input) notification - retrying pending EAP " -+ "Request"); -+ sm->eapolEap = TRUE; -+ sm->eapReq = TRUE; -+ eapol_sm_step(sm); -+ } -+} -+ -+ -+/** -+ * eapol_sm_request_reauth - Request reauthentication -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * -+ * This function can be used to request EAPOL reauthentication, e.g., when the -+ * current PMKSA entry is nearing expiration. -+ */ -+void eapol_sm_request_reauth(struct eapol_sm *sm) -+{ -+ if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED) -+ return; -+ eapol_sm_txStart(sm); -+} -+ -+ -+/** -+ * eapol_sm_notify_lower_layer_success - Notification of lower layer success -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * @in_eapol_sm: Whether the caller is already running inside EAPOL state -+ * machine loop (eapol_sm_step()) -+ * -+ * Notify EAPOL (and EAP) state machines that a lower layer has detected a -+ * successful authentication. This is used to recover from dropped EAP-Success -+ * messages. -+ */ -+void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm) -+{ -+ if (sm == NULL) -+ return; -+ eap_notify_lower_layer_success(sm->eap); -+ if (!in_eapol_sm) -+ eapol_sm_step(sm); -+} -+ -+ -+/** -+ * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ */ -+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm) -+{ -+ if (sm) -+ eap_invalidate_cached_session(sm->eap); -+} -+ -+ -+static struct eap_peer_config * eapol_sm_get_config(void *ctx) -+{ -+ struct eapol_sm *sm = ctx; -+ return sm ? sm->config : NULL; -+} -+ -+ -+static struct wpabuf * eapol_sm_get_eapReqData(void *ctx) -+{ -+ struct eapol_sm *sm = ctx; -+ if (sm == NULL || sm->eapReqData == NULL) -+ return NULL; -+ -+ return sm->eapReqData; -+} -+ -+ -+static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable) -+{ -+ struct eapol_sm *sm = ctx; -+ if (sm == NULL) -+ return FALSE; -+ switch (variable) { -+ case EAPOL_eapSuccess: -+ return sm->eapSuccess; -+ case EAPOL_eapRestart: -+ return sm->eapRestart; -+ case EAPOL_eapFail: -+ return sm->eapFail; -+ case EAPOL_eapResp: -+ return sm->eapResp; -+ case EAPOL_eapNoResp: -+ return sm->eapNoResp; -+ case EAPOL_eapReq: -+ return sm->eapReq; -+ case EAPOL_portEnabled: -+ return sm->portEnabled; -+ case EAPOL_altAccept: -+ return sm->altAccept; -+ case EAPOL_altReject: -+ return sm->altReject; -+ } -+ return FALSE; -+} -+ -+ -+static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable, -+ Boolean value) -+{ -+ struct eapol_sm *sm = ctx; -+ if (sm == NULL) -+ return; -+ switch (variable) { -+ case EAPOL_eapSuccess: -+ sm->eapSuccess = value; -+ break; -+ case EAPOL_eapRestart: -+ sm->eapRestart = value; -+ break; -+ case EAPOL_eapFail: -+ sm->eapFail = value; -+ break; -+ case EAPOL_eapResp: -+ sm->eapResp = value; -+ break; -+ case EAPOL_eapNoResp: -+ sm->eapNoResp = value; -+ break; -+ case EAPOL_eapReq: -+ sm->eapReq = value; -+ break; -+ case EAPOL_portEnabled: -+ sm->portEnabled = value; -+ break; -+ case EAPOL_altAccept: -+ sm->altAccept = value; -+ break; -+ case EAPOL_altReject: -+ sm->altReject = value; -+ break; -+ } -+} -+ -+ -+static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable) -+{ -+ struct eapol_sm *sm = ctx; -+ if (sm == NULL) -+ return 0; -+ switch (variable) { -+ case EAPOL_idleWhile: -+ return sm->idleWhile; -+ } -+ return 0; -+} -+ -+ -+static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable, -+ unsigned int value) -+{ -+ struct eapol_sm *sm = ctx; -+ if (sm == NULL) -+ return; -+ switch (variable) { -+ case EAPOL_idleWhile: -+ sm->idleWhile = value; -+ eapol_enable_timer_tick(sm); -+ break; -+ } -+} -+ -+ -+static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob) -+{ -+#ifndef CONFIG_NO_CONFIG_BLOBS -+ struct eapol_sm *sm = ctx; -+ if (sm && sm->ctx && sm->ctx->set_config_blob) -+ sm->ctx->set_config_blob(sm->ctx->ctx, blob); -+#endif /* CONFIG_NO_CONFIG_BLOBS */ -+} -+ -+ -+static const struct wpa_config_blob * -+eapol_sm_get_config_blob(void *ctx, const char *name) -+{ -+#ifndef CONFIG_NO_CONFIG_BLOBS -+ struct eapol_sm *sm = ctx; -+ if (sm && sm->ctx && sm->ctx->get_config_blob) -+ return sm->ctx->get_config_blob(sm->ctx->ctx, name); -+ else -+ return NULL; -+#else /* CONFIG_NO_CONFIG_BLOBS */ -+ return NULL; -+#endif /* CONFIG_NO_CONFIG_BLOBS */ -+} -+ -+ -+static void eapol_sm_notify_pending(void *ctx) -+{ -+ struct eapol_sm *sm = ctx; -+ if (sm == NULL) -+ return; -+ if (sm->eapReqData && !sm->eapReq) { -+ wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP " -+ "state machine - retrying pending EAP Request"); -+ sm->eapolEap = TRUE; -+ sm->eapReq = TRUE; -+ eapol_sm_step(sm); -+ } -+} -+ -+ -+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) -+static void eapol_sm_eap_param_needed(void *ctx, const char *field, -+ const char *txt) -+{ -+ struct eapol_sm *sm = ctx; -+ wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed"); -+ if (sm->ctx->eap_param_needed) -+ sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt); -+} -+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -+#define eapol_sm_eap_param_needed NULL -+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ -+ -+ -+static struct eapol_callbacks eapol_cb = -+{ -+ eapol_sm_get_config, -+ eapol_sm_get_bool, -+ eapol_sm_set_bool, -+ eapol_sm_get_int, -+ eapol_sm_set_int, -+ eapol_sm_get_eapReqData, -+ eapol_sm_set_config_blob, -+ eapol_sm_get_config_blob, -+ eapol_sm_notify_pending, -+ eapol_sm_eap_param_needed -+}; -+ -+ -+/** -+ * eapol_sm_init - Initialize EAPOL state machine -+ * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer -+ * and EAPOL state machine will free it in eapol_sm_deinit() -+ * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure -+ * -+ * Allocate and initialize an EAPOL state machine. -+ */ -+struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) -+{ -+ struct eapol_sm *sm; -+ struct eap_config conf; -+ sm = os_zalloc(sizeof(*sm)); -+ if (sm == NULL) -+ return NULL; -+ sm->ctx = ctx; -+ -+ sm->portControl = Auto; -+ -+ /* Supplicant PAE state machine */ -+ sm->heldPeriod = 60; -+ sm->startPeriod = 30; -+ sm->maxStart = 3; -+ -+ /* Supplicant Backend state machine */ -+ sm->authPeriod = 30; -+ -+ os_memset(&conf, 0, sizeof(conf)); -+ conf.opensc_engine_path = ctx->opensc_engine_path; -+ conf.pkcs11_engine_path = ctx->pkcs11_engine_path; -+ conf.pkcs11_module_path = ctx->pkcs11_module_path; -+ conf.wps = ctx->wps; -+ -+ sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf); -+ if (sm->eap == NULL) { -+ os_free(sm); -+ return NULL; -+ } -+ -+ /* Initialize EAPOL state machines */ -+ sm->initialize = TRUE; -+ eapol_sm_step(sm); -+ sm->initialize = FALSE; -+ eapol_sm_step(sm); -+ -+ sm->timer_tick_enabled = 1; -+ eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); -+ -+ return sm; -+} -+ -+ -+/** -+ * eapol_sm_deinit - Deinitialize EAPOL state machine -+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ * -+ * Deinitialize and free EAPOL state machine. -+ */ -+void eapol_sm_deinit(struct eapol_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); -+ eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); -+ eap_peer_sm_deinit(sm->eap); -+ os_free(sm->last_rx_key); -+ wpabuf_free(sm->eapReqData); -+ os_free(sm->ctx); -+ os_free(sm); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.h -new file mode 100644 -index 0000000000000..1bdf8cdd4f119 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/eapol_supp/eapol_supp_sm.h -@@ -0,0 +1,352 @@ -+/* -+ * EAPOL supplicant state machines -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EAPOL_SUPP_SM_H -+#define EAPOL_SUPP_SM_H -+ -+#include "common/defs.h" -+ -+typedef enum { Unauthorized, Authorized } PortStatus; -+typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl; -+ -+/** -+ * struct eapol_config - Per network configuration for EAPOL state machines -+ */ -+struct eapol_config { -+ /** -+ * accept_802_1x_keys - Accept IEEE 802.1X (non-WPA) EAPOL-Key frames -+ * -+ * This variable should be set to 1 when using EAPOL state machines -+ * with non-WPA security policy to generate dynamic WEP keys. When -+ * using WPA, this should be set to 0 so that WPA state machine can -+ * process the EAPOL-Key frames. -+ */ -+ int accept_802_1x_keys; -+ -+#define EAPOL_REQUIRE_KEY_UNICAST BIT(0) -+#define EAPOL_REQUIRE_KEY_BROADCAST BIT(1) -+ /** -+ * required_keys - Which EAPOL-Key packets are required -+ * -+ * This variable determines which EAPOL-Key packets are required before -+ * marking connection authenticated. This is a bit field of -+ * EAPOL_REQUIRE_KEY_UNICAST and EAPOL_REQUIRE_KEY_BROADCAST flags. -+ */ -+ int required_keys; -+ -+ /** -+ * fast_reauth - Whether fast EAP reauthentication is enabled -+ */ -+ int fast_reauth; -+ -+ /** -+ * workaround - Whether EAP workarounds are enabled -+ */ -+ unsigned int workaround; -+ -+ /** -+ * eap_disabled - Whether EAP is disabled -+ */ -+ int eap_disabled; -+}; -+ -+struct eapol_sm; -+struct wpa_config_blob; -+ -+/** -+ * struct eapol_ctx - Global (for all networks) EAPOL state machine context -+ */ -+struct eapol_ctx { -+ /** -+ * ctx - Pointer to arbitrary upper level context -+ */ -+ void *ctx; -+ -+ /** -+ * preauth - IEEE 802.11i/RSN pre-authentication -+ * -+ * This EAPOL state machine is used for IEEE 802.11i/RSN -+ * pre-authentication -+ */ -+ int preauth; -+ -+ /** -+ * cb - Function to be called when EAPOL negotiation has been completed -+ * @eapol: Pointer to EAPOL state machine data -+ * @success: Whether the authentication was completed successfully -+ * @ctx: Pointer to context data (cb_ctx) -+ * -+ * This optional callback function will be called when the EAPOL -+ * authentication has been completed. This allows the owner of the -+ * EAPOL state machine to process the key and terminate the EAPOL state -+ * machine. Currently, this is used only in RSN pre-authentication. -+ */ -+ void (*cb)(struct eapol_sm *eapol, int success, void *ctx); -+ -+ /** -+ * cb_ctx - Callback context for cb() -+ */ -+ void *cb_ctx; -+ -+ /** -+ * msg_ctx - Callback context for wpa_msg() calls -+ */ -+ void *msg_ctx; -+ -+ /** -+ * scard_ctx - Callback context for PC/SC scard_*() function calls -+ * -+ * This context can be updated with eapol_sm_register_scard_ctx(). -+ */ -+ void *scard_ctx; -+ -+ /** -+ * eapol_send_ctx - Callback context for eapol_send() calls -+ */ -+ void *eapol_send_ctx; -+ -+ /** -+ * eapol_done_cb - Function to be called at successful completion -+ * @ctx: Callback context (ctx) -+ * -+ * This function is called at the successful completion of EAPOL -+ * authentication. If dynamic WEP keys are used, this is called only -+ * after all the expected keys have been received. -+ */ -+ void (*eapol_done_cb)(void *ctx); -+ -+ /** -+ * eapol_send - Send EAPOL packets -+ * @ctx: Callback context (eapol_send_ctx) -+ * @type: EAPOL type (IEEE802_1X_TYPE_*) -+ * @buf: Pointer to EAPOL payload -+ * @len: Length of the EAPOL payload -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*eapol_send)(void *ctx, int type, const u8 *buf, size_t len); -+ -+ /** -+ * set_wep_key - Configure WEP keys -+ * @ctx: Callback context (ctx) -+ * @unicast: Non-zero = unicast, 0 = multicast/broadcast key -+ * @keyidx: Key index (0..3) -+ * @key: WEP key -+ * @keylen: Length of the WEP key -+ * Returns: 0 on success, -1 on failure -+ */ -+ int (*set_wep_key)(void *ctx, int unicast, int keyidx, -+ const u8 *key, size_t keylen); -+ -+ /** -+ * set_config_blob - Set or add a named configuration blob -+ * @ctx: Callback context (ctx) -+ * @blob: New value for the blob -+ * -+ * Adds a new configuration blob or replaces the current value of an -+ * existing blob. -+ */ -+ void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); -+ -+ /** -+ * get_config_blob - Get a named configuration blob -+ * @ctx: Callback context (ctx) -+ * @name: Name of the blob -+ * Returns: Pointer to blob data or %NULL if not found -+ */ -+ const struct wpa_config_blob * (*get_config_blob)(void *ctx, -+ const char *name); -+ -+ /** -+ * aborted_cached - Notify that cached PMK attempt was aborted -+ * @ctx: Callback context (ctx) -+ */ -+ void (*aborted_cached)(void *ctx); -+ -+ /** -+ * opensc_engine_path - Path to the OpenSSL engine for opensc -+ * -+ * This is an OpenSSL specific configuration option for loading OpenSC -+ * engine (engine_opensc.so); if %NULL, this engine is not loaded. -+ */ -+ const char *opensc_engine_path; -+ -+ /** -+ * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11 -+ * -+ * This is an OpenSSL specific configuration option for loading PKCS#11 -+ * engine (engine_pkcs11.so); if %NULL, this engine is not loaded. -+ */ -+ const char *pkcs11_engine_path; -+ -+ /** -+ * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module -+ * -+ * This is an OpenSSL specific configuration option for configuring -+ * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this -+ * module is not loaded. -+ */ -+ const char *pkcs11_module_path; -+ -+ /** -+ * wps - WPS context data -+ * -+ * This is only used by EAP-WSC and can be left %NULL if not available. -+ */ -+ struct wps_context *wps; -+ -+ /** -+ * eap_param_needed - Notify that EAP parameter is needed -+ * @ctx: Callback context (ctx) -+ * @field: Field name (e.g., "IDENTITY") -+ * @txt: User readable text describing the required parameter -+ */ -+ void (*eap_param_needed)(void *ctx, const char *field, -+ const char *txt); -+ -+ /** -+ * port_cb - Set port authorized/unauthorized callback (optional) -+ * @ctx: Callback context (ctx) -+ * @authorized: Whether the supplicant port is now in authorized state -+ */ -+ void (*port_cb)(void *ctx, int authorized); -+}; -+ -+ -+struct eap_peer_config; -+ -+#ifdef IEEE8021X_EAPOL -+struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx); -+void eapol_sm_deinit(struct eapol_sm *sm); -+void eapol_sm_step(struct eapol_sm *sm); -+int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, -+ int verbose); -+int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen); -+void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, -+ int startPeriod, int maxStart); -+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, -+ size_t len); -+void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm); -+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled); -+void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid); -+void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success); -+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail); -+void eapol_sm_notify_config(struct eapol_sm *sm, -+ struct eap_peer_config *config, -+ const struct eapol_config *conf); -+int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len); -+void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff); -+void eapol_sm_notify_cached(struct eapol_sm *sm); -+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt); -+void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx); -+void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl); -+void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm); -+void eapol_sm_notify_ctrl_response(struct eapol_sm *sm); -+void eapol_sm_request_reauth(struct eapol_sm *sm); -+void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm); -+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm); -+const char * eapol_sm_get_method_name(struct eapol_sm *sm); -+#else /* IEEE8021X_EAPOL */ -+static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) -+{ -+ free(ctx); -+ return (struct eapol_sm *) 1; -+} -+static inline void eapol_sm_deinit(struct eapol_sm *sm) -+{ -+} -+static inline void eapol_sm_step(struct eapol_sm *sm) -+{ -+} -+static inline int eapol_sm_get_status(struct eapol_sm *sm, char *buf, -+ size_t buflen, int verbose) -+{ -+ return 0; -+} -+static inline int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, -+ size_t buflen) -+{ -+ return 0; -+} -+static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, -+ int authPeriod, int startPeriod, -+ int maxStart) -+{ -+} -+static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, -+ const u8 *buf, size_t len) -+{ -+ return 0; -+} -+static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm) -+{ -+} -+static inline void eapol_sm_notify_portEnabled(struct eapol_sm *sm, -+ Boolean enabled) -+{ -+} -+static inline void eapol_sm_notify_portValid(struct eapol_sm *sm, -+ Boolean valid) -+{ -+} -+static inline void eapol_sm_notify_eap_success(struct eapol_sm *sm, -+ Boolean success) -+{ -+} -+static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail) -+{ -+} -+static inline void eapol_sm_notify_config(struct eapol_sm *sm, -+ struct eap_peer_config *config, -+ struct eapol_config *conf) -+{ -+} -+static inline int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) -+{ -+ return -1; -+} -+static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff) -+{ -+} -+static inline void eapol_sm_notify_cached(struct eapol_sm *sm) -+{ -+} -+#define eapol_sm_notify_pmkid_attempt(sm, attempt) do { } while (0) -+#define eapol_sm_register_scard_ctx(sm, ctx) do { } while (0) -+static inline void eapol_sm_notify_portControl(struct eapol_sm *sm, -+ PortControl portControl) -+{ -+} -+static inline void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm) -+{ -+} -+static inline void eapol_sm_notify_ctrl_response(struct eapol_sm *sm) -+{ -+} -+static inline void eapol_sm_request_reauth(struct eapol_sm *sm) -+{ -+} -+static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, -+ int in_eapol_sm) -+{ -+} -+static inline void eapol_sm_invalidate_cached_session(struct eapol_sm *sm) -+{ -+} -+static inline const char * eapol_sm_get_method_name(struct eapol_sm *sm) -+{ -+ return NULL; -+} -+#endif /* IEEE8021X_EAPOL */ -+ -+#endif /* EAPOL_SUPP_SM_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet.h -new file mode 100644 -index 0000000000000..c7b50141e9c37 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet.h -@@ -0,0 +1,130 @@ -+/* -+ * WPA Supplicant - Layer2 packet interface definition -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file defines an interface for layer 2 (link layer) packet sending and -+ * receiving. l2_packet_linux.c is one implementation for such a layer 2 -+ * implementation using Linux packet sockets and l2_packet_pcap.c another one -+ * using libpcap and libdnet. When porting %wpa_supplicant to other operating -+ * systems, a new l2_packet implementation may need to be added. -+ */ -+ -+#ifndef L2_PACKET_H -+#define L2_PACKET_H -+ -+/** -+ * struct l2_packet_data - Internal l2_packet data structure -+ * -+ * This structure is used by the l2_packet implementation to store its private -+ * data. Other files use a pointer to this data when calling the l2_packet -+ * functions, but the contents of this structure should not be used directly -+ * outside l2_packet implementation. -+ */ -+struct l2_packet_data; -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct l2_ethhdr { -+ u8 h_dest[ETH_ALEN]; -+ u8 h_source[ETH_ALEN]; -+ be16 h_proto; -+} STRUCT_PACKED; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+/** -+ * l2_packet_init - Initialize l2_packet interface -+ * @ifname: Interface name -+ * @own_addr: Optional own MAC address if available from driver interface or -+ * %NULL if not available -+ * @protocol: Ethernet protocol number in host byte order -+ * @rx_callback: Callback function that will be called for each received packet -+ * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback() -+ * @l2_hdr: 1 = include layer 2 header, 0 = do not include header -+ * Returns: Pointer to internal data or %NULL on failure -+ * -+ * rx_callback function will be called with src_addr pointing to the source -+ * address (MAC address) of the the packet. If l2_hdr is set to 0, buf -+ * points to len bytes of the payload after the layer 2 header and similarly, -+ * TX buffers start with payload. This behavior can be changed by setting -+ * l2_hdr=1 to include the layer 2 header in the data buffer. -+ */ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr); -+ -+/** -+ * l2_packet_deinit - Deinitialize l2_packet interface -+ * @l2: Pointer to internal l2_packet data from l2_packet_init() -+ */ -+void l2_packet_deinit(struct l2_packet_data *l2); -+ -+/** -+ * l2_packet_get_own_addr - Get own layer 2 address -+ * @l2: Pointer to internal l2_packet data from l2_packet_init() -+ * @addr: Buffer for the own address (6 bytes) -+ * Returns: 0 on success, -1 on failure -+ */ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr); -+ -+/** -+ * l2_packet_send - Send a packet -+ * @l2: Pointer to internal l2_packet data from l2_packet_init() -+ * @dst_addr: Destination address for the packet (only used if l2_hdr == 0) -+ * @proto: Protocol/ethertype for the packet in host byte order (only used if -+ * l2_hdr == 0) -+ * @buf: Packet contents to be sent; including layer 2 header if l2_hdr was -+ * set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet -+ * is included. -+ * @len: Length of the buffer (including l2 header only if l2_hdr == 1) -+ * Returns: >=0 on success, <0 on failure -+ */ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len); -+ -+/** -+ * l2_packet_get_ip_addr - Get the current IP address from the interface -+ * @l2: Pointer to internal l2_packet data from l2_packet_init() -+ * @buf: Buffer for the IP address in text format -+ * @len: Maximum buffer length -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to get the current IP address from the interface -+ * bound to the l2_packet. This is mainly for status information and the IP -+ * address will be stored as an ASCII string. This function is not essential -+ * for %wpa_supplicant operation, so full implementation is not required. -+ * l2_packet implementation will need to define the function, but it can return -+ * -1 if the IP address information is not available. -+ */ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len); -+ -+ -+/** -+ * l2_packet_notify_auth_start - Notify l2_packet about start of authentication -+ * @l2: Pointer to internal l2_packet data from l2_packet_init() -+ * -+ * This function is called when authentication is expected to start, e.g., when -+ * association has been completed, in order to prepare l2_packet implementation -+ * for EAPOL frames. This function is used mainly if the l2_packet code needs -+ * to do polling in which case it can increasing polling frequency. This can -+ * also be an empty function if the l2_packet implementation does not benefit -+ * from knowing about the starting authentication. -+ */ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2); -+ -+#endif /* L2_PACKET_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_freebsd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_freebsd.c -new file mode 100644 -index 0000000000000..e24277c29f608 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_freebsd.c -@@ -0,0 +1,316 @@ -+/* -+ * WPA Supplicant - Layer2 packet handling with FreeBSD -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * Copyright (c) 2005, Sam Leffler -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#if defined(__APPLE__) || defined(__GLIBC__) -+#include -+#endif /* __APPLE__ */ -+#include -+ -+#include -+#ifdef __sun__ -+#include -+#else /* __sun__ */ -+#include -+#endif /* __sun__ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "l2_packet.h" -+ -+ -+static const u8 pae_group_addr[ETH_ALEN] = -+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; -+ -+struct l2_packet_data { -+ pcap_t *pcap; -+ char ifname[100]; -+ u8 own_addr[ETH_ALEN]; -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len); -+ void *rx_callback_ctx; -+ int l2_hdr; /* whether to include layer 2 (Ethernet) header data -+ * buffers */ -+}; -+ -+ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -+{ -+ os_memcpy(addr, l2->own_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len) -+{ -+ if (!l2->l2_hdr) { -+ int ret; -+ struct l2_ethhdr *eth = os_malloc(sizeof(*eth) + len); -+ if (eth == NULL) -+ return -1; -+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); -+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); -+ eth->h_proto = htons(proto); -+ os_memcpy(eth + 1, buf, len); -+ ret = pcap_inject(l2->pcap, (u8 *) eth, len + sizeof(*eth)); -+ os_free(eth); -+ return ret; -+ } else -+ return pcap_inject(l2->pcap, buf, len); -+} -+ -+ -+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct l2_packet_data *l2 = eloop_ctx; -+ pcap_t *pcap = sock_ctx; -+ struct pcap_pkthdr hdr; -+ const u_char *packet; -+ struct l2_ethhdr *ethhdr; -+ unsigned char *buf; -+ size_t len; -+ -+ packet = pcap_next(pcap, &hdr); -+ -+ if (packet == NULL || hdr.caplen < sizeof(*ethhdr)) -+ return; -+ -+ ethhdr = (struct l2_ethhdr *) packet; -+ if (l2->l2_hdr) { -+ buf = (unsigned char *) ethhdr; -+ len = hdr.caplen; -+ } else { -+ buf = (unsigned char *) (ethhdr + 1); -+ len = hdr.caplen - sizeof(*ethhdr); -+ } -+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); -+} -+ -+ -+static int l2_packet_init_libpcap(struct l2_packet_data *l2, -+ unsigned short protocol) -+{ -+ bpf_u_int32 pcap_maskp, pcap_netp; -+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE]; -+ struct bpf_program pcap_fp; -+ -+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err); -+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err); -+ if (l2->pcap == NULL) { -+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err); -+ fprintf(stderr, "ifname='%s'\n", l2->ifname); -+ return -1; -+ } -+ if (pcap_datalink(l2->pcap) != DLT_EN10MB && -+ pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) { -+ fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n", -+ pcap_geterr(l2->pcap)); -+ return -1; -+ } -+ os_snprintf(pcap_filter, sizeof(pcap_filter), -+ "not ether src " MACSTR " and " -+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and " -+ "ether proto 0x%x", -+ MAC2STR(l2->own_addr), /* do not receive own packets */ -+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), -+ protocol); -+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { -+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); -+ return -1; -+ } -+ -+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) { -+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap)); -+ return -1; -+ } -+ -+ pcap_freecode(&pcap_fp); -+#ifndef __sun__ -+ /* -+ * When libpcap uses BPF we must enable "immediate mode" to -+ * receive frames right away; otherwise the system may -+ * buffer them for us. -+ */ -+ { -+ unsigned int on = 1; -+ if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) { -+ fprintf(stderr, "%s: cannot enable immediate mode on " -+ "interface %s: %s\n", -+ __func__, l2->ifname, strerror(errno)); -+ /* XXX should we fail? */ -+ } -+ } -+#endif /* __sun__ */ -+ -+ eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap), -+ l2_packet_receive, l2, l2->pcap); -+ -+ return 0; -+} -+ -+ -+static int eth_get(const char *device, u8 ea[ETH_ALEN]) -+{ -+#ifdef __sun__ -+ dlpi_handle_t dh; -+ u32 physaddrlen = DLPI_PHYSADDR_MAX; -+ u8 physaddr[DLPI_PHYSADDR_MAX]; -+ int retval; -+ -+ retval = dlpi_open(device, &dh, 0); -+ if (retval != DLPI_SUCCESS) { -+ wpa_printf(MSG_ERROR, "dlpi_open error: %s", -+ dlpi_strerror(retval)); -+ return -1; -+ } -+ -+ retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, -+ &physaddrlen); -+ if (retval != DLPI_SUCCESS) { -+ wpa_printf(MSG_ERROR, "dlpi_get_physaddr error: %s", -+ dlpi_strerror(retval)); -+ dlpi_close(dh); -+ return -1; -+ } -+ os_memcpy(ea, physaddr, ETH_ALEN); -+ dlpi_close(dh); -+#else /* __sun__ */ -+ struct if_msghdr *ifm; -+ struct sockaddr_dl *sdl; -+ u_char *p, *buf; -+ size_t len; -+ int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; -+ -+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) -+ return -1; -+ if ((buf = os_malloc(len)) == NULL) -+ return -1; -+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { -+ os_free(buf); -+ return -1; -+ } -+ for (p = buf; p < buf + len; p += ifm->ifm_msglen) { -+ ifm = (struct if_msghdr *)p; -+ sdl = (struct sockaddr_dl *)(ifm + 1); -+ if (ifm->ifm_type != RTM_IFINFO || -+ (ifm->ifm_addrs & RTA_IFP) == 0) -+ continue; -+ if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 || -+ os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0) -+ continue; -+ os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen); -+ break; -+ } -+ os_free(buf); -+ -+ if (p >= buf + len) { -+ errno = ESRCH; -+ return -1; -+ } -+#endif /* __sun__ */ -+ return 0; -+} -+ -+ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr) -+{ -+ struct l2_packet_data *l2; -+ -+ l2 = os_zalloc(sizeof(struct l2_packet_data)); -+ if (l2 == NULL) -+ return NULL; -+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); -+ l2->rx_callback = rx_callback; -+ l2->rx_callback_ctx = rx_callback_ctx; -+ l2->l2_hdr = l2_hdr; -+ -+ if (eth_get(l2->ifname, l2->own_addr) < 0) { -+ fprintf(stderr, "Failed to get link-level address for " -+ "interface '%s'.\n", l2->ifname); -+ os_free(l2); -+ return NULL; -+ } -+ -+ if (l2_packet_init_libpcap(l2, protocol)) { -+ os_free(l2); -+ return NULL; -+ } -+ -+ return l2; -+} -+ -+ -+void l2_packet_deinit(struct l2_packet_data *l2) -+{ -+ if (l2 != NULL) { -+ if (l2->pcap) { -+ eloop_unregister_read_sock( -+ pcap_get_selectable_fd(l2->pcap)); -+ pcap_close(l2->pcap); -+ } -+ os_free(l2); -+ } -+} -+ -+ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -+{ -+ pcap_if_t *devs, *dev; -+ struct pcap_addr *addr; -+ struct sockaddr_in *saddr; -+ int found = 0; -+ char err[PCAP_ERRBUF_SIZE + 1]; -+ -+ if (pcap_findalldevs(&devs, err) < 0) { -+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err); -+ return -1; -+ } -+ -+ for (dev = devs; dev && !found; dev = dev->next) { -+ if (os_strcmp(dev->name, l2->ifname) != 0) -+ continue; -+ -+ addr = dev->addresses; -+ while (addr) { -+ saddr = (struct sockaddr_in *) addr->addr; -+ if (saddr && saddr->sin_family == AF_INET) { -+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr), -+ len); -+ found = 1; -+ break; -+ } -+ addr = addr->next; -+ } -+ } -+ -+ pcap_freealldevs(devs); -+ -+ return found ? 0 : -1; -+} -+ -+ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_linux.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_linux.c -new file mode 100644 -index 0000000000000..93e15eb7c5b01 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_linux.c -@@ -0,0 +1,210 @@ -+/* -+ * WPA Supplicant - Layer2 packet handling with Linux packet sockets -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "l2_packet.h" -+ -+ -+struct l2_packet_data { -+ int fd; /* packet socket for EAPOL frames */ -+ char ifname[IFNAMSIZ + 1]; -+ int ifindex; -+ u8 own_addr[ETH_ALEN]; -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len); -+ void *rx_callback_ctx; -+ int l2_hdr; /* whether to include layer 2 (Ethernet) header data -+ * buffers */ -+}; -+ -+ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -+{ -+ os_memcpy(addr, l2->own_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len) -+{ -+ int ret; -+ if (l2 == NULL) -+ return -1; -+ if (l2->l2_hdr) { -+ ret = send(l2->fd, buf, len, 0); -+ if (ret < 0) -+ wpa_printf(MSG_ERROR, "l2_packet_send - send: %s", -+ strerror(errno)); -+ } else { -+ struct sockaddr_ll ll; -+ os_memset(&ll, 0, sizeof(ll)); -+ ll.sll_family = AF_PACKET; -+ ll.sll_ifindex = l2->ifindex; -+ ll.sll_protocol = htons(proto); -+ ll.sll_halen = ETH_ALEN; -+ os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN); -+ ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll, -+ sizeof(ll)); -+ if (ret < 0) { -+ wpa_printf(MSG_ERROR, "l2_packet_send - sendto: %s", -+ strerror(errno)); -+ } -+ } -+ return ret; -+} -+ -+ -+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct l2_packet_data *l2 = eloop_ctx; -+ u8 buf[2300]; -+ int res; -+ struct sockaddr_ll ll; -+ socklen_t fromlen; -+ -+ os_memset(&ll, 0, sizeof(ll)); -+ fromlen = sizeof(ll); -+ res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, -+ &fromlen); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "l2_packet_receive - recvfrom: %s", -+ strerror(errno)); -+ return; -+ } -+ -+ l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); -+} -+ -+ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr) -+{ -+ struct l2_packet_data *l2; -+ struct ifreq ifr; -+ struct sockaddr_ll ll; -+ -+ l2 = os_zalloc(sizeof(struct l2_packet_data)); -+ if (l2 == NULL) -+ return NULL; -+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); -+ l2->rx_callback = rx_callback; -+ l2->rx_callback_ctx = rx_callback_ctx; -+ l2->l2_hdr = l2_hdr; -+ -+ l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, -+ htons(protocol)); -+ if (l2->fd < 0) { -+ wpa_printf(MSG_ERROR, "%s: socket(PF_PACKET): %s", -+ __func__, strerror(errno)); -+ os_free(l2); -+ return NULL; -+ } -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); -+ if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) { -+ wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFINDEX]: %s", -+ __func__, strerror(errno)); -+ close(l2->fd); -+ os_free(l2); -+ return NULL; -+ } -+ l2->ifindex = ifr.ifr_ifindex; -+ -+ os_memset(&ll, 0, sizeof(ll)); -+ ll.sll_family = PF_PACKET; -+ ll.sll_ifindex = ifr.ifr_ifindex; -+ ll.sll_protocol = htons(protocol); -+ if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) { -+ wpa_printf(MSG_ERROR, "%s: bind[PF_PACKET]: %s", -+ __func__, strerror(errno)); -+ close(l2->fd); -+ os_free(l2); -+ return NULL; -+ } -+ -+ if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) { -+ wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFHWADDR]: %s", -+ __func__, strerror(errno)); -+ close(l2->fd); -+ os_free(l2); -+ return NULL; -+ } -+ os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); -+ -+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); -+ -+ return l2; -+} -+ -+ -+void l2_packet_deinit(struct l2_packet_data *l2) -+{ -+ if (l2 == NULL) -+ return; -+ -+ if (l2->fd >= 0) { -+ eloop_unregister_read_sock(l2->fd); -+ close(l2->fd); -+ } -+ -+ os_free(l2); -+} -+ -+ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -+{ -+ int s; -+ struct ifreq ifr; -+ struct sockaddr_in *saddr; -+ size_t res; -+ -+ s = socket(PF_INET, SOCK_DGRAM, 0); -+ if (s < 0) { -+ wpa_printf(MSG_ERROR, "%s: socket: %s", -+ __func__, strerror(errno)); -+ return -1; -+ } -+ os_memset(&ifr, 0, sizeof(ifr)); -+ os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); -+ if (ioctl(s, SIOCGIFADDR, &ifr) < 0) { -+ if (errno != EADDRNOTAVAIL) -+ wpa_printf(MSG_ERROR, "%s: ioctl[SIOCGIFADDR]: %s", -+ __func__, strerror(errno)); -+ close(s); -+ return -1; -+ } -+ close(s); -+ saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in); -+ if (saddr->sin_family != AF_INET) -+ return -1; -+ res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len); -+ if (res >= len) -+ return -1; -+ return 0; -+} -+ -+ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_ndis.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_ndis.c -new file mode 100644 -index 0000000000000..6ce29aa20ec93 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_ndis.c -@@ -0,0 +1,522 @@ -+/* -+ * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This implementation requires Windows specific event loop implementation, -+ * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with -+ * driver_ndis.c, so only that driver interface can be used and -+ * CONFIG_USE_NDISUIO must be defined. -+ * -+ * WinXP version of the code uses overlapped I/O and a single threaded design -+ * with callback functions from I/O code. WinCE version uses a separate RX -+ * thread that blocks on ReadFile() whenever the media status is connected. -+ */ -+ -+#include "includes.h" -+#include -+#include -+ -+#ifdef _WIN32_WCE -+#include -+#include -+#endif /* _WIN32_WCE */ -+ -+#include "common.h" -+#include "eloop.h" -+#include "l2_packet.h" -+ -+#ifndef _WIN32_WCE -+/* from nuiouser.h */ -+#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK -+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \ -+ CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access) -+#define IOCTL_NDISUIO_SET_ETHER_TYPE \ -+ _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \ -+ FILE_READ_ACCESS | FILE_WRITE_ACCESS) -+#endif /* _WIN32_WCE */ -+ -+/* From driver_ndis.c to shared the handle to NDISUIO */ -+HANDLE driver_ndis_get_ndisuio_handle(void); -+ -+/* -+ * NDISUIO supports filtering of only one ethertype at the time, so we must -+ * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth -+ * whenever wpa_supplicant is trying to pre-authenticate and then switching -+ * back to EAPOL when pre-authentication has been completed. -+ */ -+ -+struct l2_packet_data; -+ -+struct l2_packet_ndisuio_global { -+ int refcount; -+ unsigned short first_proto; -+ struct l2_packet_data *l2[2]; -+#ifdef _WIN32_WCE -+ HANDLE rx_thread; -+ HANDLE stop_request; -+ HANDLE ready_for_read; -+ HANDLE rx_processed; -+#endif /* _WIN32_WCE */ -+}; -+ -+static struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL; -+ -+struct l2_packet_data { -+ char ifname[100]; -+ u8 own_addr[ETH_ALEN]; -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len); -+ void *rx_callback_ctx; -+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to -+ * rx_callback and l2_packet_send() */ -+ HANDLE rx_avail; -+#ifndef _WIN32_WCE -+ OVERLAPPED rx_overlapped; -+#endif /* _WIN32_WCE */ -+ u8 rx_buf[1514]; -+ DWORD rx_written; -+}; -+ -+ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -+{ -+ os_memcpy(addr, l2->own_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len) -+{ -+ BOOL res; -+ DWORD written; -+ struct l2_ethhdr *eth; -+#ifndef _WIN32_WCE -+ OVERLAPPED overlapped; -+#endif /* _WIN32_WCE */ -+ OVERLAPPED *o; -+ -+ if (l2 == NULL) -+ return -1; -+ -+#ifdef _WIN32_WCE -+ o = NULL; -+#else /* _WIN32_WCE */ -+ os_memset(&overlapped, 0, sizeof(overlapped)); -+ o = &overlapped; -+#endif /* _WIN32_WCE */ -+ -+ if (l2->l2_hdr) { -+ res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len, -+ &written, o); -+ } else { -+ size_t mlen = sizeof(*eth) + len; -+ eth = os_malloc(mlen); -+ if (eth == NULL) -+ return -1; -+ -+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); -+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); -+ eth->h_proto = htons(proto); -+ os_memcpy(eth + 1, buf, len); -+ res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen, -+ &written, o); -+ os_free(eth); -+ } -+ -+ if (!res) { -+ DWORD err = GetLastError(); -+#ifndef _WIN32_WCE -+ if (err == ERROR_IO_PENDING) { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): Wait for pending " -+ "write to complete"); -+ res = GetOverlappedResult( -+ driver_ndis_get_ndisuio_handle(), &overlapped, -+ &written, TRUE); -+ if (!res) { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): " -+ "GetOverlappedResult failed: %d", -+ (int) GetLastError()); -+ return -1; -+ } -+ return 0; -+ } -+#endif /* _WIN32_WCE */ -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d", -+ (int) GetLastError()); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void l2_packet_callback(struct l2_packet_data *l2); -+ -+#ifdef _WIN32_WCE -+static void l2_packet_rx_thread_try_read(struct l2_packet_data *l2) -+{ -+ HANDLE handles[2]; -+ -+ wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile"); -+ if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf, -+ sizeof(l2->rx_buf), &l2->rx_written, NULL)) { -+ DWORD err = GetLastError(); -+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: " -+ "%d", (int) err); -+ /* -+ * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED -+ * error whenever the connection is not up. Yield the thread to -+ * avoid triggering a busy loop. Connection event should stop -+ * us from looping for long, but we need to allow enough CPU -+ * for the main thread to process the media disconnection. -+ */ -+ Sleep(100); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet", -+ (int) l2->rx_written); -+ -+ /* -+ * Notify the main thread about the availability of a frame and wait -+ * for the frame to be processed. -+ */ -+ SetEvent(l2->rx_avail); -+ handles[0] = l2_ndisuio_global->stop_request; -+ handles[1] = l2_ndisuio_global->rx_processed; -+ WaitForMultipleObjects(2, handles, FALSE, INFINITE); -+ ResetEvent(l2_ndisuio_global->rx_processed); -+} -+ -+ -+static DWORD WINAPI l2_packet_rx_thread(LPVOID arg) -+{ -+ struct l2_packet_data *l2 = arg; -+ DWORD res; -+ HANDLE handles[2]; -+ int run = 1; -+ -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started"); -+ handles[0] = l2_ndisuio_global->stop_request; -+ handles[1] = l2_ndisuio_global->ready_for_read; -+ -+ /* -+ * Unfortunately, NDISUIO on WinCE does not seem to support waiting -+ * on the handle. There do not seem to be anything else that we could -+ * wait for either. If one were to modify NDISUIO to set a named event -+ * whenever packets are available, this event could be used here to -+ * avoid having to poll for new packets or we could even move to use a -+ * single threaded design. -+ * -+ * In addition, NDISUIO on WinCE is returning -+ * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while -+ * the adapter is not in connected state. For now, we are just using a -+ * local event to allow ReadFile calls only after having received NDIS -+ * media connect event. This event could be easily converted to handle -+ * another event if the protocol driver is replaced with somewhat more -+ * useful design. -+ */ -+ -+ while (l2_ndisuio_global && run) { -+ res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); -+ switch (res) { -+ case WAIT_OBJECT_0: -+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received " -+ "request to stop RX thread"); -+ run = 0; -+ break; -+ case WAIT_OBJECT_0 + 1: -+ l2_packet_rx_thread_try_read(l2); -+ break; -+ case WAIT_FAILED: -+ default: -+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: " -+ "WaitForMultipleObjects failed: %d", -+ (int) GetLastError()); -+ run = 0; -+ break; -+ } -+ } -+ -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped"); -+ -+ return 0; -+} -+#else /* _WIN32_WCE */ -+static int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive) -+{ -+ os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped)); -+ l2->rx_overlapped.hEvent = l2->rx_avail; -+ if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf, -+ sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped)) -+ { -+ DWORD err = GetLastError(); -+ if (err != ERROR_IO_PENDING) { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: " -+ "%d", (int) err); -+ return -1; -+ } -+ /* -+ * Once read is completed, l2_packet_rx_event() will be -+ * called. -+ */ -+ } else { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data " -+ "without wait for completion"); -+ if (!recursive) -+ l2_packet_callback(l2); -+ } -+ -+ return 0; -+} -+#endif /* _WIN32_WCE */ -+ -+ -+static void l2_packet_callback(struct l2_packet_data *l2) -+{ -+ const u8 *rx_buf, *rx_src; -+ size_t rx_len; -+ struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf; -+ -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes", -+ (int) l2->rx_written); -+ -+ if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) { -+ rx_buf = (u8 *) ethhdr; -+ rx_len = l2->rx_written; -+ } else { -+ rx_buf = (u8 *) (ethhdr + 1); -+ rx_len = l2->rx_written - sizeof(*ethhdr); -+ } -+ rx_src = ethhdr->h_source; -+ -+ l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len); -+#ifndef _WIN32_WCE -+ l2_ndisuio_start_read(l2, 1); -+#endif /* _WIN32_WCE */ -+} -+ -+ -+static void l2_packet_rx_event(void *eloop_data, void *user_data) -+{ -+ struct l2_packet_data *l2 = eloop_data; -+ -+ if (l2_ndisuio_global) -+ l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1]; -+ -+ ResetEvent(l2->rx_avail); -+ -+#ifndef _WIN32_WCE -+ if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(), -+ &l2->rx_overlapped, &l2->rx_written, FALSE)) { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult " -+ "failed: %d", (int) GetLastError()); -+ return; -+ } -+#endif /* _WIN32_WCE */ -+ -+ l2_packet_callback(l2); -+ -+#ifdef _WIN32_WCE -+ SetEvent(l2_ndisuio_global->rx_processed); -+#endif /* _WIN32_WCE */ -+} -+ -+ -+static int l2_ndisuio_set_ether_type(unsigned short protocol) -+{ -+ USHORT proto = htons(protocol); -+ DWORD written; -+ -+ if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(), -+ IOCTL_NDISUIO_SET_ETHER_TYPE, &proto, -+ sizeof(proto), NULL, 0, &written, NULL)) { -+ wpa_printf(MSG_ERROR, "L2(NDISUIO): " -+ "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d", -+ (int) GetLastError()); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr) -+{ -+ struct l2_packet_data *l2; -+ -+ if (l2_ndisuio_global == NULL) { -+ l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global)); -+ if (l2_ndisuio_global == NULL) -+ return NULL; -+ l2_ndisuio_global->first_proto = protocol; -+ } -+ if (l2_ndisuio_global->refcount >= 2) { -+ wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two " -+ "simultaneous connections allowed"); -+ return NULL; -+ } -+ l2_ndisuio_global->refcount++; -+ -+ l2 = os_zalloc(sizeof(struct l2_packet_data)); -+ if (l2 == NULL) -+ return NULL; -+ l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2; -+ -+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); -+ l2->rx_callback = rx_callback; -+ l2->rx_callback_ctx = rx_callback_ctx; -+ l2->l2_hdr = l2_hdr; -+ -+ if (own_addr) -+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN); -+ -+ if (l2_ndisuio_set_ether_type(protocol) < 0) { -+ os_free(l2); -+ return NULL; -+ } -+ -+ if (l2_ndisuio_global->refcount > 1) { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting " -+ "filtering ethertype to %04x", protocol); -+ if (l2_ndisuio_global->l2[0]) -+ l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail; -+ return l2; -+ } -+ -+ l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL); -+ if (l2->rx_avail == NULL) { -+ os_free(l2); -+ return NULL; -+ } -+ -+ eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail), -+ l2_packet_rx_event, l2, NULL); -+ -+#ifdef _WIN32_WCE -+ l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL); -+ /* -+ * This event is being set based on media connect/disconnect -+ * notifications in driver_ndis.c. -+ */ -+ l2_ndisuio_global->ready_for_read = -+ CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected")); -+ l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL); -+ if (l2_ndisuio_global->stop_request == NULL || -+ l2_ndisuio_global->ready_for_read == NULL || -+ l2_ndisuio_global->rx_processed == NULL) { -+ if (l2_ndisuio_global->stop_request) { -+ CloseHandle(l2_ndisuio_global->stop_request); -+ l2_ndisuio_global->stop_request = NULL; -+ } -+ if (l2_ndisuio_global->ready_for_read) { -+ CloseHandle(l2_ndisuio_global->ready_for_read); -+ l2_ndisuio_global->ready_for_read = NULL; -+ } -+ if (l2_ndisuio_global->rx_processed) { -+ CloseHandle(l2_ndisuio_global->rx_processed); -+ l2_ndisuio_global->rx_processed = NULL; -+ } -+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); -+ os_free(l2); -+ return NULL; -+ } -+ -+ l2_ndisuio_global->rx_thread = CreateThread(NULL, 0, -+ l2_packet_rx_thread, l2, 0, -+ NULL); -+ if (l2_ndisuio_global->rx_thread == NULL) { -+ wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX " -+ "thread: %d", (int) GetLastError()); -+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); -+ CloseHandle(l2_ndisuio_global->stop_request); -+ l2_ndisuio_global->stop_request = NULL; -+ os_free(l2); -+ return NULL; -+ } -+#else /* _WIN32_WCE */ -+ l2_ndisuio_start_read(l2, 0); -+#endif /* _WIN32_WCE */ -+ -+ return l2; -+} -+ -+ -+void l2_packet_deinit(struct l2_packet_data *l2) -+{ -+ if (l2 == NULL) -+ return; -+ -+ if (l2_ndisuio_global) { -+ l2_ndisuio_global->refcount--; -+ l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL; -+ if (l2_ndisuio_global->refcount) { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering " -+ "ethertype to %04x", -+ l2_ndisuio_global->first_proto); -+ l2_ndisuio_set_ether_type( -+ l2_ndisuio_global->first_proto); -+ return; -+ } -+ -+#ifdef _WIN32_WCE -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to " -+ "stop"); -+ SetEvent(l2_ndisuio_global->stop_request); -+ /* -+ * Cancel pending ReadFile() in the RX thread (if we were still -+ * connected at this point). -+ */ -+ if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(), -+ IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL, -+ NULL)) { -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ " -+ "failed: %d", (int) GetLastError()); -+ /* RX thread will exit blocking ReadFile once NDISUIO -+ * notices that the adapter is disconnected. */ -+ } -+ WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE); -+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited"); -+ CloseHandle(l2_ndisuio_global->rx_thread); -+ CloseHandle(l2_ndisuio_global->stop_request); -+ CloseHandle(l2_ndisuio_global->ready_for_read); -+ CloseHandle(l2_ndisuio_global->rx_processed); -+#endif /* _WIN32_WCE */ -+ -+ os_free(l2_ndisuio_global); -+ l2_ndisuio_global = NULL; -+ } -+ -+#ifndef _WIN32_WCE -+ CancelIo(driver_ndis_get_ndisuio_handle()); -+#endif /* _WIN32_WCE */ -+ -+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); -+ CloseHandle(l2->rx_avail); -+ os_free(l2); -+} -+ -+ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -+{ -+ return -1; -+} -+ -+ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2) -+{ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_none.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_none.c -new file mode 100644 -index 0000000000000..5e3f6e972384f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_none.c -@@ -0,0 +1,123 @@ -+/* -+ * WPA Supplicant - Layer2 packet handling example with dummy functions -+ * Copyright (c) 2003-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file can be used as a starting point for layer2 packet implementation. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "l2_packet.h" -+ -+ -+struct l2_packet_data { -+ char ifname[17]; -+ u8 own_addr[ETH_ALEN]; -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len); -+ void *rx_callback_ctx; -+ int l2_hdr; /* whether to include layer 2 (Ethernet) header data -+ * buffers */ -+ int fd; -+}; -+ -+ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -+{ -+ os_memcpy(addr, l2->own_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len) -+{ -+ if (l2 == NULL) -+ return -1; -+ -+ /* -+ * TODO: Send frame (may need different implementation depending on -+ * whether l2->l2_hdr is set). -+ */ -+ -+ return 0; -+} -+ -+ -+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct l2_packet_data *l2 = eloop_ctx; -+ u8 buf[2300]; -+ int res; -+ -+ /* TODO: receive frame (e.g., recv() using sock */ -+ buf[0] = 0; -+ res = 0; -+ -+ l2->rx_callback(l2->rx_callback_ctx, NULL /* TODO: src addr */, -+ buf, res); -+} -+ -+ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr) -+{ -+ struct l2_packet_data *l2; -+ -+ l2 = os_zalloc(sizeof(struct l2_packet_data)); -+ if (l2 == NULL) -+ return NULL; -+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); -+ l2->rx_callback = rx_callback; -+ l2->rx_callback_ctx = rx_callback_ctx; -+ l2->l2_hdr = l2_hdr; -+ -+ /* -+ * TODO: open connection for receiving frames -+ */ -+ l2->fd = -1; -+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); -+ -+ return l2; -+} -+ -+ -+void l2_packet_deinit(struct l2_packet_data *l2) -+{ -+ if (l2 == NULL) -+ return; -+ -+ if (l2->fd >= 0) { -+ eloop_unregister_read_sock(l2->fd); -+ /* TODO: close connection */ -+ } -+ -+ os_free(l2); -+} -+ -+ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -+{ -+ /* TODO: get interface IP address */ -+ return -1; -+} -+ -+ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2) -+{ -+ /* This function can be left empty */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_pcap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_pcap.c -new file mode 100644 -index 0000000000000..8156e294b1bb2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_pcap.c -@@ -0,0 +1,386 @@ -+/* -+ * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#ifndef CONFIG_NATIVE_WINDOWS -+#include -+#endif /* CONFIG_NATIVE_WINDOWS */ -+#include -+#ifndef CONFIG_WINPCAP -+#include -+#endif /* CONFIG_WINPCAP */ -+ -+#include "common.h" -+#include "eloop.h" -+#include "l2_packet.h" -+ -+ -+static const u8 pae_group_addr[ETH_ALEN] = -+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; -+ -+struct l2_packet_data { -+ pcap_t *pcap; -+#ifdef CONFIG_WINPCAP -+ unsigned int num_fast_poll; -+#else /* CONFIG_WINPCAP */ -+ eth_t *eth; -+#endif /* CONFIG_WINPCAP */ -+ char ifname[100]; -+ u8 own_addr[ETH_ALEN]; -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len); -+ void *rx_callback_ctx; -+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls -+ * to rx_callback */ -+}; -+ -+ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -+{ -+ os_memcpy(addr, l2->own_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+#ifndef CONFIG_WINPCAP -+static int l2_packet_init_libdnet(struct l2_packet_data *l2) -+{ -+ eth_addr_t own_addr; -+ -+ l2->eth = eth_open(l2->ifname); -+ if (!l2->eth) { -+ printf("Failed to open interface '%s'.\n", l2->ifname); -+ perror("eth_open"); -+ return -1; -+ } -+ -+ if (eth_get(l2->eth, &own_addr) < 0) { -+ printf("Failed to get own hw address from interface '%s'.\n", -+ l2->ifname); -+ perror("eth_get"); -+ eth_close(l2->eth); -+ l2->eth = NULL; -+ return -1; -+ } -+ os_memcpy(l2->own_addr, own_addr.data, ETH_ALEN); -+ -+ return 0; -+} -+#endif /* CONFIG_WINPCAP */ -+ -+ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len) -+{ -+ int ret; -+ struct l2_ethhdr *eth; -+ -+ if (l2 == NULL) -+ return -1; -+ -+ if (l2->l2_hdr) { -+#ifdef CONFIG_WINPCAP -+ ret = pcap_sendpacket(l2->pcap, buf, len); -+#else /* CONFIG_WINPCAP */ -+ ret = eth_send(l2->eth, buf, len); -+#endif /* CONFIG_WINPCAP */ -+ } else { -+ size_t mlen = sizeof(*eth) + len; -+ eth = os_malloc(mlen); -+ if (eth == NULL) -+ return -1; -+ -+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); -+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); -+ eth->h_proto = htons(proto); -+ os_memcpy(eth + 1, buf, len); -+ -+#ifdef CONFIG_WINPCAP -+ ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen); -+#else /* CONFIG_WINPCAP */ -+ ret = eth_send(l2->eth, (u8 *) eth, mlen); -+#endif /* CONFIG_WINPCAP */ -+ -+ os_free(eth); -+ } -+ -+ return ret; -+} -+ -+ -+#ifndef CONFIG_WINPCAP -+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct l2_packet_data *l2 = eloop_ctx; -+ pcap_t *pcap = sock_ctx; -+ struct pcap_pkthdr hdr; -+ const u_char *packet; -+ struct l2_ethhdr *ethhdr; -+ unsigned char *buf; -+ size_t len; -+ -+ packet = pcap_next(pcap, &hdr); -+ -+ if (packet == NULL || hdr.caplen < sizeof(*ethhdr)) -+ return; -+ -+ ethhdr = (struct l2_ethhdr *) packet; -+ if (l2->l2_hdr) { -+ buf = (unsigned char *) ethhdr; -+ len = hdr.caplen; -+ } else { -+ buf = (unsigned char *) (ethhdr + 1); -+ len = hdr.caplen - sizeof(*ethhdr); -+ } -+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); -+} -+#endif /* CONFIG_WINPCAP */ -+ -+ -+#ifdef CONFIG_WINPCAP -+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr, -+ const u_char *pkt_data) -+{ -+ struct l2_packet_data *l2 = (struct l2_packet_data *) user; -+ struct l2_ethhdr *ethhdr; -+ unsigned char *buf; -+ size_t len; -+ -+ if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr)) -+ return; -+ -+ ethhdr = (struct l2_ethhdr *) pkt_data; -+ if (l2->l2_hdr) { -+ buf = (unsigned char *) ethhdr; -+ len = hdr->caplen; -+ } else { -+ buf = (unsigned char *) (ethhdr + 1); -+ len = hdr->caplen - sizeof(*ethhdr); -+ } -+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); -+ /* -+ * Use shorter poll interval for 3 seconds to reduce latency during key -+ * handshake. -+ */ -+ l2->num_fast_poll = 3 * 50; -+} -+ -+ -+static void l2_packet_receive_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct l2_packet_data *l2 = eloop_ctx; -+ pcap_t *pcap = timeout_ctx; -+ int timeout; -+ -+ if (l2->num_fast_poll > 0) { -+ timeout = 20000; -+ l2->num_fast_poll--; -+ } else -+ timeout = 100000; -+ -+ /* Register new timeout before calling l2_packet_receive() since -+ * receive handler may free this l2_packet instance (which will -+ * cancel this timeout). */ -+ eloop_register_timeout(0, timeout, l2_packet_receive_timeout, -+ l2, pcap); -+ pcap_dispatch(pcap, 10, l2_packet_receive_cb, (u_char *) l2); -+} -+#endif /* CONFIG_WINPCAP */ -+ -+ -+static int l2_packet_init_libpcap(struct l2_packet_data *l2, -+ unsigned short protocol) -+{ -+ bpf_u_int32 pcap_maskp, pcap_netp; -+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE]; -+ struct bpf_program pcap_fp; -+ -+#ifdef CONFIG_WINPCAP -+ char ifname[128]; -+ os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", l2->ifname); -+ pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err); -+ l2->pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err); -+ if (l2->pcap == NULL) { -+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err); -+ fprintf(stderr, "ifname='%s'\n", ifname); -+ return -1; -+ } -+ if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0) -+ fprintf(stderr, "pcap_setnonblock: %s\n", -+ pcap_geterr(l2->pcap)); -+#else /* CONFIG_WINPCAP */ -+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err); -+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err); -+ if (l2->pcap == NULL) { -+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err); -+ fprintf(stderr, "ifname='%s'\n", l2->ifname); -+ return -1; -+ } -+ if (pcap_datalink(l2->pcap) != DLT_EN10MB && -+ pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) { -+ fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n", -+ pcap_geterr(l2->pcap)); -+ return -1; -+ } -+#endif /* CONFIG_WINPCAP */ -+ os_snprintf(pcap_filter, sizeof(pcap_filter), -+ "not ether src " MACSTR " and " -+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and " -+ "ether proto 0x%x", -+ MAC2STR(l2->own_addr), /* do not receive own packets */ -+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), -+ protocol); -+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { -+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); -+ return -1; -+ } -+ -+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) { -+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap)); -+ return -1; -+ } -+ -+ pcap_freecode(&pcap_fp); -+#ifdef BIOCIMMEDIATE -+ /* -+ * When libpcap uses BPF we must enable "immediate mode" to -+ * receive frames right away; otherwise the system may -+ * buffer them for us. -+ */ -+ { -+ unsigned int on = 1; -+ if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) { -+ fprintf(stderr, "%s: cannot enable immediate mode on " -+ "interface %s: %s\n", -+ __func__, l2->ifname, strerror(errno)); -+ /* XXX should we fail? */ -+ } -+ } -+#endif /* BIOCIMMEDIATE */ -+ -+#ifdef CONFIG_WINPCAP -+ eloop_register_timeout(0, 100000, l2_packet_receive_timeout, -+ l2, l2->pcap); -+#else /* CONFIG_WINPCAP */ -+ eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap), -+ l2_packet_receive, l2, l2->pcap); -+#endif /* CONFIG_WINPCAP */ -+ -+ return 0; -+} -+ -+ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr) -+{ -+ struct l2_packet_data *l2; -+ -+ l2 = os_zalloc(sizeof(struct l2_packet_data)); -+ if (l2 == NULL) -+ return NULL; -+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); -+ l2->rx_callback = rx_callback; -+ l2->rx_callback_ctx = rx_callback_ctx; -+ l2->l2_hdr = l2_hdr; -+ -+#ifdef CONFIG_WINPCAP -+ if (own_addr) -+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN); -+#else /* CONFIG_WINPCAP */ -+ if (l2_packet_init_libdnet(l2)) -+ return NULL; -+#endif /* CONFIG_WINPCAP */ -+ -+ if (l2_packet_init_libpcap(l2, protocol)) { -+#ifndef CONFIG_WINPCAP -+ eth_close(l2->eth); -+#endif /* CONFIG_WINPCAP */ -+ os_free(l2); -+ return NULL; -+ } -+ -+ return l2; -+} -+ -+ -+void l2_packet_deinit(struct l2_packet_data *l2) -+{ -+ if (l2 == NULL) -+ return; -+ -+#ifdef CONFIG_WINPCAP -+ eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap); -+#else /* CONFIG_WINPCAP */ -+ if (l2->eth) -+ eth_close(l2->eth); -+ eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap)); -+#endif /* CONFIG_WINPCAP */ -+ if (l2->pcap) -+ pcap_close(l2->pcap); -+ os_free(l2); -+} -+ -+ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -+{ -+ pcap_if_t *devs, *dev; -+ struct pcap_addr *addr; -+ struct sockaddr_in *saddr; -+ int found = 0; -+ char err[PCAP_ERRBUF_SIZE + 1]; -+ -+ if (pcap_findalldevs(&devs, err) < 0) { -+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err); -+ return -1; -+ } -+ -+ for (dev = devs; dev && !found; dev = dev->next) { -+ if (os_strcmp(dev->name, l2->ifname) != 0) -+ continue; -+ -+ addr = dev->addresses; -+ while (addr) { -+ saddr = (struct sockaddr_in *) addr->addr; -+ if (saddr && saddr->sin_family == AF_INET) { -+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr), -+ len); -+ found = 1; -+ break; -+ } -+ addr = addr->next; -+ } -+ } -+ -+ pcap_freealldevs(devs); -+ -+ return found ? 0 : -1; -+} -+ -+ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2) -+{ -+#ifdef CONFIG_WINPCAP -+ /* -+ * Use shorter poll interval for 3 seconds to reduce latency during key -+ * handshake. -+ */ -+ l2->num_fast_poll = 3 * 50; -+ eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap); -+ eloop_register_timeout(0, 10000, l2_packet_receive_timeout, -+ l2, l2->pcap); -+#endif /* CONFIG_WINPCAP */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_privsep.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_privsep.c -new file mode 100644 -index 0000000000000..79d29681565a1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_privsep.c -@@ -0,0 +1,267 @@ -+/* -+ * WPA Supplicant - Layer2 packet handling with privilege separation -+ * Copyright (c) 2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "l2_packet.h" -+#include "common/privsep_commands.h" -+ -+ -+struct l2_packet_data { -+ int fd; /* UNIX domain socket for privsep access */ -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len); -+ void *rx_callback_ctx; -+ u8 own_addr[ETH_ALEN]; -+ char *own_socket_path; -+ struct sockaddr_un priv_addr; -+}; -+ -+ -+static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd, -+ const void *data, size_t data_len) -+{ -+ struct msghdr msg; -+ struct iovec io[2]; -+ -+ io[0].iov_base = &cmd; -+ io[0].iov_len = sizeof(cmd); -+ io[1].iov_base = (u8 *) data; -+ io[1].iov_len = data_len; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ msg.msg_iov = io; -+ msg.msg_iovlen = data ? 2 : 1; -+ msg.msg_name = &l2->priv_addr; -+ msg.msg_namelen = sizeof(l2->priv_addr); -+ -+ if (sendmsg(l2->fd, &msg, 0) < 0) { -+ perror("L2: sendmsg(cmd)"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -+{ -+ os_memcpy(addr, l2->own_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len) -+{ -+ struct msghdr msg; -+ struct iovec io[4]; -+ int cmd = PRIVSEP_CMD_L2_SEND; -+ -+ io[0].iov_base = &cmd; -+ io[0].iov_len = sizeof(cmd); -+ io[1].iov_base = &dst_addr; -+ io[1].iov_len = ETH_ALEN; -+ io[2].iov_base = &proto; -+ io[2].iov_len = 2; -+ io[3].iov_base = (u8 *) buf; -+ io[3].iov_len = len; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ msg.msg_iov = io; -+ msg.msg_iovlen = 4; -+ msg.msg_name = &l2->priv_addr; -+ msg.msg_namelen = sizeof(l2->priv_addr); -+ -+ if (sendmsg(l2->fd, &msg, 0) < 0) { -+ perror("L2: sendmsg(packet_send)"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct l2_packet_data *l2 = eloop_ctx; -+ u8 buf[2300]; -+ int res; -+ struct sockaddr_un from; -+ socklen_t fromlen = sizeof(from); -+ -+ os_memset(&from, 0, sizeof(from)); -+ res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from, -+ &fromlen); -+ if (res < 0) { -+ perror("l2_packet_receive - recvfrom"); -+ return; -+ } -+ if (res < ETH_ALEN) { -+ wpa_printf(MSG_DEBUG, "L2: Too show packet received"); -+ return; -+ } -+ -+ if (from.sun_family != AF_UNIX || -+ os_strncmp(from.sun_path, l2->priv_addr.sun_path, -+ sizeof(from.sun_path)) != 0) { -+ wpa_printf(MSG_DEBUG, "L2: Received message from unexpected " -+ "source"); -+ return; -+ } -+ -+ l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN, -+ res - ETH_ALEN); -+} -+ -+ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr) -+{ -+ struct l2_packet_data *l2; -+ char *own_dir = "/tmp"; -+ char *priv_dir = "/var/run/wpa_priv"; -+ size_t len; -+ static unsigned int counter = 0; -+ struct sockaddr_un addr; -+ fd_set rfds; -+ struct timeval tv; -+ int res; -+ u8 reply[ETH_ALEN + 1]; -+ int reg_cmd[2]; -+ -+ l2 = os_zalloc(sizeof(struct l2_packet_data)); -+ if (l2 == NULL) -+ return NULL; -+ l2->rx_callback = rx_callback; -+ l2->rx_callback_ctx = rx_callback_ctx; -+ -+ len = os_strlen(own_dir) + 50; -+ l2->own_socket_path = os_malloc(len); -+ if (l2->own_socket_path == NULL) { -+ os_free(l2); -+ return NULL; -+ } -+ os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d", -+ own_dir, getpid(), counter++); -+ -+ l2->priv_addr.sun_family = AF_UNIX; -+ os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path), -+ "%s/%s", priv_dir, ifname); -+ -+ l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0); -+ if (l2->fd < 0) { -+ perror("socket(PF_UNIX)"); -+ os_free(l2->own_socket_path); -+ l2->own_socket_path = NULL; -+ os_free(l2); -+ return NULL; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sun_family = AF_UNIX; -+ os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path)); -+ if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind(PF_UNIX)"); -+ goto fail; -+ } -+ -+ reg_cmd[0] = protocol; -+ reg_cmd[1] = l2_hdr; -+ if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd)) -+ < 0) { -+ wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv"); -+ goto fail; -+ } -+ -+ FD_ZERO(&rfds); -+ FD_SET(l2->fd, &rfds); -+ tv.tv_sec = 5; -+ tv.tv_usec = 0; -+ res = select(l2->fd + 1, &rfds, NULL, NULL, &tv); -+ if (res < 0 && errno != EINTR) { -+ perror("select"); -+ goto fail; -+ } -+ -+ if (FD_ISSET(l2->fd, &rfds)) { -+ res = recv(l2->fd, reply, sizeof(reply), 0); -+ if (res < 0) { -+ perror("recv"); -+ goto fail; -+ } -+ } else { -+ wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for " -+ "registration reply"); -+ goto fail; -+ } -+ -+ if (res != ETH_ALEN) { -+ wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply " -+ "(len=%d)", res); -+ } -+ os_memcpy(l2->own_addr, reply, ETH_ALEN); -+ -+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); -+ -+ return l2; -+ -+fail: -+ close(l2->fd); -+ l2->fd = -1; -+ unlink(l2->own_socket_path); -+ os_free(l2->own_socket_path); -+ l2->own_socket_path = NULL; -+ os_free(l2); -+ return NULL; -+} -+ -+ -+void l2_packet_deinit(struct l2_packet_data *l2) -+{ -+ if (l2 == NULL) -+ return; -+ -+ if (l2->fd >= 0) { -+ wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0); -+ eloop_unregister_read_sock(l2->fd); -+ close(l2->fd); -+ } -+ -+ if (l2->own_socket_path) { -+ unlink(l2->own_socket_path); -+ os_free(l2->own_socket_path); -+ } -+ -+ os_free(l2); -+} -+ -+ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -+{ -+ /* TODO */ -+ return -1; -+} -+ -+ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2) -+{ -+ wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_winpcap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_winpcap.c -new file mode 100644 -index 0000000000000..f76b386fc033a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/l2_packet/l2_packet_winpcap.c -@@ -0,0 +1,341 @@ -+/* -+ * WPA Supplicant - Layer2 packet handling with WinPcap RX thread -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This l2_packet implementation is explicitly for WinPcap and Windows events. -+ * l2_packet_pcap.c has support for WinPcap, but it requires polling to receive -+ * frames which means relatively long latency for EAPOL RX processing. The -+ * implementation here uses a separate thread to allow WinPcap to be receiving -+ * all the time to reduce latency for EAPOL receiving from about 100 ms to 3 ms -+ * when comparing l2_packet_pcap.c to l2_packet_winpcap.c. Extra sleep of 50 ms -+ * is added in to receive thread whenever no EAPOL frames has been received for -+ * a while. Whenever an EAPOL handshake is expected, this sleep is removed. -+ * -+ * The RX thread receives a frame and signals main thread through Windows event -+ * about the availability of a new frame. Processing the received frame is -+ * synchronized with pair of Windows events so that no extra buffer or queuing -+ * mechanism is needed. This implementation requires Windows specific event -+ * loop implementation, i.e., eloop_win.c. -+ * -+ * WinPcap has pcap_getevent() that could, in theory at least, be used to -+ * implement this kind of waiting with a simpler single-thread design. However, -+ * that event handle is not really signaled immediately when receiving each -+ * frame, so it does not really work for this kind of use. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "l2_packet.h" -+ -+ -+static const u8 pae_group_addr[ETH_ALEN] = -+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; -+ -+/* -+ * Number of pcap_dispatch() iterations to do without extra wait after each -+ * received EAPOL packet or authentication notification. This is used to reduce -+ * latency for EAPOL receive. -+ */ -+static const size_t no_wait_count = 750; -+ -+struct l2_packet_data { -+ pcap_t *pcap; -+ unsigned int num_fast_poll; -+ char ifname[100]; -+ u8 own_addr[ETH_ALEN]; -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len); -+ void *rx_callback_ctx; -+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to -+ * rx_callback and l2_packet_send() */ -+ int running; -+ HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify; -+ u8 *rx_buf, *rx_src; -+ size_t rx_len; -+ size_t rx_no_wait; -+}; -+ -+ -+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr) -+{ -+ os_memcpy(addr, l2->own_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, -+ const u8 *buf, size_t len) -+{ -+ int ret; -+ struct l2_ethhdr *eth; -+ -+ if (l2 == NULL) -+ return -1; -+ -+ if (l2->l2_hdr) { -+ ret = pcap_sendpacket(l2->pcap, buf, len); -+ } else { -+ size_t mlen = sizeof(*eth) + len; -+ eth = os_malloc(mlen); -+ if (eth == NULL) -+ return -1; -+ -+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN); -+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN); -+ eth->h_proto = htons(proto); -+ os_memcpy(eth + 1, buf, len); -+ ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen); -+ os_free(eth); -+ } -+ -+ return ret; -+} -+ -+ -+/* pcap_dispatch() callback for the RX thread */ -+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr, -+ const u_char *pkt_data) -+{ -+ struct l2_packet_data *l2 = (struct l2_packet_data *) user; -+ struct l2_ethhdr *ethhdr; -+ -+ if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr)) -+ return; -+ -+ ethhdr = (struct l2_ethhdr *) pkt_data; -+ if (l2->l2_hdr) { -+ l2->rx_buf = (u8 *) ethhdr; -+ l2->rx_len = hdr->caplen; -+ } else { -+ l2->rx_buf = (u8 *) (ethhdr + 1); -+ l2->rx_len = hdr->caplen - sizeof(*ethhdr); -+ } -+ l2->rx_src = ethhdr->h_source; -+ SetEvent(l2->rx_avail); -+ WaitForSingleObject(l2->rx_done, INFINITE); -+ ResetEvent(l2->rx_done); -+ l2->rx_no_wait = no_wait_count; -+} -+ -+ -+/* main RX loop that is running in a separate thread */ -+static DWORD WINAPI l2_packet_receive_thread(LPVOID arg) -+{ -+ struct l2_packet_data *l2 = arg; -+ -+ while (l2->running) { -+ pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb, -+ (u_char *) l2); -+ if (l2->rx_no_wait > 0) -+ l2->rx_no_wait--; -+ if (WaitForSingleObject(l2->rx_notify, -+ l2->rx_no_wait ? 0 : 50) == -+ WAIT_OBJECT_0) { -+ l2->rx_no_wait = no_wait_count; -+ ResetEvent(l2->rx_notify); -+ } -+ } -+ SetEvent(l2->rx_thread_done); -+ ExitThread(0); -+ return 0; -+} -+ -+ -+/* main thread RX event handler */ -+static void l2_packet_rx_event(void *eloop_data, void *user_data) -+{ -+ struct l2_packet_data *l2 = eloop_data; -+ l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf, -+ l2->rx_len); -+ ResetEvent(l2->rx_avail); -+ SetEvent(l2->rx_done); -+} -+ -+ -+static int l2_packet_init_libpcap(struct l2_packet_data *l2, -+ unsigned short protocol) -+{ -+ bpf_u_int32 pcap_maskp, pcap_netp; -+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE]; -+ struct bpf_program pcap_fp; -+ -+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err); -+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err); -+ if (l2->pcap == NULL) { -+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err); -+ fprintf(stderr, "ifname='%s'\n", l2->ifname); -+ return -1; -+ } -+ os_snprintf(pcap_filter, sizeof(pcap_filter), -+ "not ether src " MACSTR " and " -+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and " -+ "ether proto 0x%x", -+ MAC2STR(l2->own_addr), /* do not receive own packets */ -+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), -+ protocol); -+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { -+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); -+ return -1; -+ } -+ -+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) { -+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap)); -+ return -1; -+ } -+ -+ pcap_freecode(&pcap_fp); -+ -+ return 0; -+} -+ -+ -+struct l2_packet_data * l2_packet_init( -+ const char *ifname, const u8 *own_addr, unsigned short protocol, -+ void (*rx_callback)(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len), -+ void *rx_callback_ctx, int l2_hdr) -+{ -+ struct l2_packet_data *l2; -+ DWORD thread_id; -+ -+ l2 = os_zalloc(sizeof(struct l2_packet_data)); -+ if (l2 == NULL) -+ return NULL; -+ if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0) -+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname)); -+ else -+ os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s", -+ ifname); -+ l2->rx_callback = rx_callback; -+ l2->rx_callback_ctx = rx_callback_ctx; -+ l2->l2_hdr = l2_hdr; -+ -+ if (own_addr) -+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN); -+ -+ if (l2_packet_init_libpcap(l2, protocol)) { -+ os_free(l2); -+ return NULL; -+ } -+ -+ l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL); -+ l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL); -+ l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL); -+ if (l2->rx_avail == NULL || l2->rx_done == NULL || -+ l2->rx_notify == NULL) { -+ CloseHandle(l2->rx_avail); -+ CloseHandle(l2->rx_done); -+ CloseHandle(l2->rx_notify); -+ pcap_close(l2->pcap); -+ os_free(l2); -+ return NULL; -+ } -+ -+ eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail), -+ l2_packet_rx_event, l2, NULL); -+ -+ l2->running = 1; -+ l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0, -+ &thread_id); -+ -+ return l2; -+} -+ -+ -+static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct l2_packet_data *l2 = eloop_ctx; -+ -+ if (l2->rx_thread_done && -+ WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) { -+ wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not " -+ "exit - kill it\n"); -+ TerminateThread(l2->rx_thread, 0); -+ } -+ CloseHandle(l2->rx_thread_done); -+ CloseHandle(l2->rx_thread); -+ if (l2->pcap) -+ pcap_close(l2->pcap); -+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail)); -+ CloseHandle(l2->rx_avail); -+ CloseHandle(l2->rx_done); -+ CloseHandle(l2->rx_notify); -+ os_free(l2); -+} -+ -+ -+void l2_packet_deinit(struct l2_packet_data *l2) -+{ -+ if (l2 == NULL) -+ return; -+ -+ l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL); -+ -+ l2->running = 0; -+ pcap_breakloop(l2->pcap); -+ -+ /* -+ * RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done -+ * event and this event is set in l2_packet_rx_event(). However, -+ * l2_packet_deinit() may end up being called from l2->rx_callback(), -+ * so we need to return from here and complete deinitialization in -+ * a registered timeout to avoid having to forcefully kill the RX -+ * thread. -+ */ -+ eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL); -+} -+ -+ -+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -+{ -+ pcap_if_t *devs, *dev; -+ struct pcap_addr *addr; -+ struct sockaddr_in *saddr; -+ int found = 0; -+ char err[PCAP_ERRBUF_SIZE + 1]; -+ -+ if (pcap_findalldevs(&devs, err) < 0) { -+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err); -+ return -1; -+ } -+ -+ for (dev = devs; dev && !found; dev = dev->next) { -+ if (os_strcmp(dev->name, l2->ifname) != 0) -+ continue; -+ -+ addr = dev->addresses; -+ while (addr) { -+ saddr = (struct sockaddr_in *) addr->addr; -+ if (saddr && saddr->sin_family == AF_INET) { -+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr), -+ len); -+ found = 1; -+ break; -+ } -+ addr = addr->next; -+ } -+ } -+ -+ pcap_freealldevs(devs); -+ -+ return found ? 0 : -1; -+} -+ -+ -+void l2_packet_notify_auth_start(struct l2_packet_data *l2) -+{ -+ if (l2) -+ SetEvent(l2->rx_notify); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/lib.rules b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/lib.rules -new file mode 100644 -index 0000000000000..b260d25a050cb ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/lib.rules -@@ -0,0 +1,21 @@ -+ifndef CC -+CC=gcc -+endif -+ -+ifndef CFLAGS -+CFLAGS = -MMD -O2 -Wall -g -+endif -+ -+CFLAGS += -I.. -I../utils -+ -+ -+Q=@ -+E=echo -+ifeq ($(V), 1) -+Q= -+E=true -+endif -+ -+%.o: %.c -+ $(Q)$(CC) -c -o $@ $(CFLAGS) $< -+ @$(E) " CC " $< -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/Makefile -new file mode 100644 -index 0000000000000..cffba620da04f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/Makefile -@@ -0,0 +1,9 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ for d in $(SUBDIRS); do make -C $$d clean; done -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.c -new file mode 100644 -index 0000000000000..653609e335a5a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.c -@@ -0,0 +1,3490 @@ -+/* -+ * Wi-Fi Direct - P2P module -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "wps/wps_i.h" -+#include "p2p_i.h" -+#include "p2p.h" -+ -+ -+static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx); -+static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev); -+static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da, -+ const u8 *sa, const u8 *data, size_t len, -+ int rx_freq); -+static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da, -+ const u8 *sa, const u8 *data, -+ size_t len); -+static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx); -+static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx); -+ -+ -+/* -+ * p2p_scan recovery timeout -+ * -+ * Many drivers are using 30 second timeout on scan results. Allow a bit larger -+ * timeout for this to avoid hitting P2P timeout unnecessarily. -+ */ -+#define P2P_SCAN_TIMEOUT 35 -+ -+/** -+ * P2P_PEER_EXPIRATION_AGE - Number of seconds after which inactive peer -+ * entries will be removed -+ */ -+#define P2P_PEER_EXPIRATION_AGE 300 -+ -+#define P2P_PEER_EXPIRATION_INTERVAL (P2P_PEER_EXPIRATION_AGE / 2) -+ -+static void p2p_expire_peers(struct p2p_data *p2p) -+{ -+ struct p2p_device *dev, *n; -+ struct os_time now; -+ -+ os_get_time(&now); -+ dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) { -+ if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec) -+ continue; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Expiring old peer " -+ "entry " MACSTR, MAC2STR(dev->info.p2p_device_addr)); -+ dl_list_del(&dev->list); -+ p2p_device_free(p2p, dev); -+ } -+} -+ -+ -+static void p2p_expiration_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct p2p_data *p2p = eloop_ctx; -+ p2p_expire_peers(p2p); -+ eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0, -+ p2p_expiration_timeout, p2p, NULL); -+} -+ -+ -+static const char * p2p_state_txt(int state) -+{ -+ switch (state) { -+ case P2P_IDLE: -+ return "IDLE"; -+ case P2P_SEARCH: -+ return "SEARCH"; -+ case P2P_CONNECT: -+ return "CONNECT"; -+ case P2P_CONNECT_LISTEN: -+ return "CONNECT_LISTEN"; -+ case P2P_GO_NEG: -+ return "GO_NEG"; -+ case P2P_LISTEN_ONLY: -+ return "LISTEN_ONLY"; -+ case P2P_WAIT_PEER_CONNECT: -+ return "WAIT_PEER_CONNECT"; -+ case P2P_WAIT_PEER_IDLE: -+ return "WAIT_PEER_IDLE"; -+ case P2P_SD_DURING_FIND: -+ return "SD_DURING_FIND"; -+ case P2P_PROVISIONING: -+ return "PROVISIONING"; -+ case P2P_PD_DURING_FIND: -+ return "PD_DURING_FIND"; -+ case P2P_INVITE: -+ return "INVITE"; -+ case P2P_INVITE_LISTEN: -+ return "INVITE_LISTEN"; -+ default: -+ return "?"; -+ } -+} -+ -+ -+void p2p_set_state(struct p2p_data *p2p, int new_state) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s", -+ p2p_state_txt(p2p->state), p2p_state_txt(new_state)); -+ p2p->state = new_state; -+} -+ -+ -+void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Set timeout (state=%s): %u.%06u sec", -+ p2p_state_txt(p2p->state), sec, usec); -+ eloop_cancel_timeout(p2p_state_timeout, p2p, NULL); -+ eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL); -+} -+ -+ -+void p2p_clear_timeout(struct p2p_data *p2p) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear timeout (state=%s)", -+ p2p_state_txt(p2p->state)); -+ eloop_cancel_timeout(p2p_state_timeout, p2p, NULL); -+} -+ -+ -+void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer, -+ int status) -+{ -+ struct p2p_go_neg_results res; -+ p2p_clear_timeout(p2p); -+ p2p_set_state(p2p, P2P_IDLE); -+ p2p->go_neg_peer = NULL; -+ -+ os_memset(&res, 0, sizeof(res)); -+ res.status = status; -+ if (peer) { -+ os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, -+ ETH_ALEN); -+ os_memcpy(res.peer_interface_addr, peer->intended_addr, -+ ETH_ALEN); -+ } -+ p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); -+} -+ -+ -+static void p2p_listen_in_find(struct p2p_data *p2p) -+{ -+ unsigned int r, tu; -+ int freq; -+ struct wpabuf *ies; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Starting short listen state (state=%s)", -+ p2p_state_txt(p2p->state)); -+ -+ freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (freq < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown regulatory class/channel"); -+ return; -+ } -+ -+ os_get_random((u8 *) &r, sizeof(r)); -+ tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) + -+ p2p->min_disc_int) * 100; -+ -+ p2p->pending_listen_freq = freq; -+ p2p->pending_listen_sec = 0; -+ p2p->pending_listen_usec = 1024 * tu; -+ -+ ies = p2p_build_probe_resp_ies(p2p); -+ if (ies == NULL) -+ return; -+ -+ if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000, -+ ies) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to start listen mode"); -+ p2p->pending_listen_freq = 0; -+ } -+ wpabuf_free(ies); -+} -+ -+ -+int p2p_listen(struct p2p_data *p2p, unsigned int timeout) -+{ -+ int freq; -+ struct wpabuf *ies; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Going to listen(only) state"); -+ -+ freq = p2p_channel_to_freq(p2p->cfg->country, p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (freq < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown regulatory class/channel"); -+ return -1; -+ } -+ -+ p2p->pending_listen_freq = freq; -+ p2p->pending_listen_sec = timeout / 1000; -+ p2p->pending_listen_usec = (timeout % 1000) * 1000; -+ -+ if (p2p->p2p_scan_running) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: p2p_scan running - delay start of listen state"); -+ p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN; -+ return 0; -+ } -+ -+ ies = p2p_build_probe_resp_ies(p2p); -+ if (ies == NULL) -+ return -1; -+ -+ if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, timeout, ies) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to start listen mode"); -+ p2p->pending_listen_freq = 0; -+ wpabuf_free(ies); -+ return -1; -+ } -+ wpabuf_free(ies); -+ -+ p2p_set_state(p2p, P2P_LISTEN_ONLY); -+ -+ return 0; -+} -+ -+ -+static void p2p_device_clear_reported(struct p2p_data *p2p) -+{ -+ struct p2p_device *dev; -+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) -+ dev->flags &= ~P2P_DEV_REPORTED; -+} -+ -+ -+/** -+ * p2p_get_device - Fetch a peer entry -+ * @p2p: P2P module context from p2p_init() -+ * @addr: P2P Device Address of the peer -+ * Returns: Pointer to the device entry or %NULL if not found -+ */ -+struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr) -+{ -+ struct p2p_device *dev; -+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { -+ if (os_memcmp(dev->info.p2p_device_addr, addr, ETH_ALEN) == 0) -+ return dev; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * p2p_get_device_interface - Fetch a peer entry based on P2P Interface Address -+ * @p2p: P2P module context from p2p_init() -+ * @addr: P2P Interface Address of the peer -+ * Returns: Pointer to the device entry or %NULL if not found -+ */ -+struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, -+ const u8 *addr) -+{ -+ struct p2p_device *dev; -+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { -+ if (os_memcmp(dev->interface_addr, addr, ETH_ALEN) == 0) -+ return dev; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * p2p_create_device - Create a peer entry -+ * @p2p: P2P module context from p2p_init() -+ * @addr: P2P Device Address of the peer -+ * Returns: Pointer to the device entry or %NULL on failure -+ * -+ * If there is already an entry for the peer, it will be returned instead of -+ * creating a new one. -+ */ -+static struct p2p_device * p2p_create_device(struct p2p_data *p2p, -+ const u8 *addr) -+{ -+ struct p2p_device *dev, *oldest = NULL; -+ size_t count = 0; -+ -+ dev = p2p_get_device(p2p, addr); -+ if (dev) -+ return dev; -+ -+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { -+ count++; -+ if (oldest == NULL || -+ os_time_before(&dev->last_seen, &oldest->last_seen)) -+ oldest = dev; -+ } -+ if (count + 1 > p2p->cfg->max_peers && oldest) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Remove oldest peer entry to make room for a new " -+ "peer"); -+ dl_list_del(&oldest->list); -+ p2p_device_free(p2p, oldest); -+ } -+ -+ dev = os_zalloc(sizeof(*dev)); -+ if (dev == NULL) -+ return NULL; -+ dl_list_add(&p2p->devices, &dev->list); -+ os_memcpy(dev->info.p2p_device_addr, addr, ETH_ALEN); -+ -+ return dev; -+} -+ -+ -+static void p2p_copy_client_info(struct p2p_device *dev, -+ struct p2p_client_info *cli) -+{ -+ os_memcpy(dev->info.device_name, cli->dev_name, cli->dev_name_len); -+ dev->info.device_name[cli->dev_name_len] = '\0'; -+ dev->info.dev_capab = cli->dev_capab; -+ dev->info.config_methods = cli->config_methods; -+ os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8); -+ dev->info.wps_sec_dev_type_list_len = 8 * cli->num_sec_dev_types; -+ os_memcpy(dev->info.wps_sec_dev_type_list, cli->sec_dev_types, -+ dev->info.wps_sec_dev_type_list_len); -+} -+ -+ -+static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, -+ const u8 *go_interface_addr, int freq, -+ const u8 *gi, size_t gi_len) -+{ -+ struct p2p_group_info info; -+ size_t c; -+ struct p2p_device *dev; -+ -+ if (gi == NULL) -+ return 0; -+ -+ if (p2p_group_info_parse(gi, gi_len, &info) < 0) -+ return -1; -+ -+ /* -+ * Clear old data for this group; if the devices are still in the -+ * group, the information will be restored in the loop following this. -+ */ -+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { -+ if (os_memcpy(dev->member_in_go_iface, go_interface_addr, -+ ETH_ALEN) == 0) { -+ os_memset(dev->member_in_go_iface, 0, ETH_ALEN); -+ os_memset(dev->member_in_go_dev, 0, ETH_ALEN); -+ } -+ } -+ -+ for (c = 0; c < info.num_clients; c++) { -+ struct p2p_client_info *cli = &info.client[c]; -+ dev = p2p_get_device(p2p, cli->p2p_device_addr); -+ if (dev) { -+ /* -+ * Update information only if we have not received this -+ * directly from the client. -+ */ -+ if (dev->flags & (P2P_DEV_GROUP_CLIENT_ONLY | -+ P2P_DEV_PROBE_REQ_ONLY)) -+ p2p_copy_client_info(dev, cli); -+ if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) { -+ dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY; -+ } -+ } else { -+ dev = p2p_create_device(p2p, cli->p2p_device_addr); -+ if (dev == NULL) -+ continue; -+ dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY; -+ p2p_copy_client_info(dev, cli); -+ dev->oper_freq = freq; -+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, -+ dev->info.p2p_device_addr, -+ &dev->info, 1); -+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; -+ } -+ -+ os_memcpy(dev->interface_addr, cli->p2p_interface_addr, -+ ETH_ALEN); -+ os_get_time(&dev->last_seen); -+ os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN); -+ os_memcpy(dev->member_in_go_iface, go_interface_addr, -+ ETH_ALEN); -+ } -+ -+ return 0; -+} -+ -+ -+static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req, -+ const struct p2p_message *msg) -+{ -+ os_memcpy(dev->info.device_name, msg->device_name, -+ sizeof(dev->info.device_name)); -+ -+ if (msg->manufacturer && -+ msg->manufacturer_len < sizeof(dev->info.manufacturer)) { -+ os_memset(dev->info.manufacturer, 0, -+ sizeof(dev->info.manufacturer)); -+ os_memcpy(dev->info.manufacturer, msg->manufacturer, -+ msg->manufacturer_len); -+ } -+ -+ if (msg->model_name && -+ msg->model_name_len < sizeof(dev->info.model_name)) { -+ os_memset(dev->info.model_name, 0, -+ sizeof(dev->info.model_name)); -+ os_memcpy(dev->info.model_name, msg->model_name, -+ msg->model_name_len); -+ } -+ -+ if (msg->model_number && -+ msg->model_number_len < sizeof(dev->info.model_number)) { -+ os_memset(dev->info.model_number, 0, -+ sizeof(dev->info.model_number)); -+ os_memcpy(dev->info.model_number, msg->model_number, -+ msg->model_number_len); -+ } -+ -+ if (msg->serial_number && -+ msg->serial_number_len < sizeof(dev->info.serial_number)) { -+ os_memset(dev->info.serial_number, 0, -+ sizeof(dev->info.serial_number)); -+ os_memcpy(dev->info.serial_number, msg->serial_number, -+ msg->serial_number_len); -+ } -+ -+ if (msg->pri_dev_type) -+ os_memcpy(dev->info.pri_dev_type, msg->pri_dev_type, -+ sizeof(dev->info.pri_dev_type)); -+ else if (msg->wps_pri_dev_type) -+ os_memcpy(dev->info.pri_dev_type, msg->wps_pri_dev_type, -+ sizeof(dev->info.pri_dev_type)); -+ -+ if (msg->wps_sec_dev_type_list) { -+ os_memcpy(dev->info.wps_sec_dev_type_list, -+ msg->wps_sec_dev_type_list, -+ msg->wps_sec_dev_type_list_len); -+ dev->info.wps_sec_dev_type_list_len = -+ msg->wps_sec_dev_type_list_len; -+ } -+ -+ if (msg->capability) { -+ dev->info.dev_capab = msg->capability[0]; -+ dev->info.group_capab = msg->capability[1]; -+ } -+ -+ if (msg->ext_listen_timing) { -+ dev->ext_listen_period = WPA_GET_LE16(msg->ext_listen_timing); -+ dev->ext_listen_interval = -+ WPA_GET_LE16(msg->ext_listen_timing + 2); -+ } -+ -+ if (!probe_req) { -+ dev->info.config_methods = msg->config_methods ? -+ msg->config_methods : msg->wps_config_methods; -+ } -+} -+ -+ -+/** -+ * p2p_add_device - Add peer entries based on scan results -+ * @p2p: P2P module context from p2p_init() -+ * @addr: Source address of Beacon or Probe Response frame (may be either -+ * P2P Device Address or P2P Interface Address) -+ * @level: Signal level (signal strength of the received frame from the peer) -+ * @freq: Frequency on which the Beacon or Probe Response frame was received -+ * @ies: IEs from the Beacon or Probe Response frame -+ * @ies_len: Length of ies buffer in octets -+ * Returns: 0 on success, -1 on failure -+ * -+ * If the scan result is for a GO, the clients in the group will also be added -+ * to the peer table. This function can also be used with some other frames -+ * like Provision Discovery Request that contains P2P Capability and P2P Device -+ * Info attributes. -+ */ -+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, -+ const u8 *ies, size_t ies_len) -+{ -+ struct p2p_device *dev; -+ struct p2p_message msg; -+ const u8 *p2p_dev_addr; -+ int i; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_ies(ies, ies_len, &msg)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to parse P2P IE for a device entry"); -+ p2p_parse_free(&msg); -+ return -1; -+ } -+ -+ if (msg.p2p_device_addr) -+ p2p_dev_addr = msg.p2p_device_addr; -+ else if (msg.device_id) -+ p2p_dev_addr = msg.device_id; -+ else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore scan data without P2P Device Info or " -+ "P2P Device Id"); -+ p2p_parse_free(&msg); -+ return -1; -+ } -+ -+ if (!is_zero_ether_addr(p2p->peer_filter) && -+ os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer " -+ "filter for " MACSTR " due to peer filter", -+ MAC2STR(p2p_dev_addr)); -+ return 0; -+ } -+ -+ dev = p2p_create_device(p2p, p2p_dev_addr); -+ if (dev == NULL) { -+ p2p_parse_free(&msg); -+ return -1; -+ } -+ os_get_time(&dev->last_seen); -+ dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY); -+ -+ if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0) -+ os_memcpy(dev->interface_addr, addr, ETH_ALEN); -+ if (msg.ssid && -+ (msg.ssid[1] != P2P_WILDCARD_SSID_LEN || -+ os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) -+ != 0)) { -+ os_memcpy(dev->oper_ssid, msg.ssid + 2, msg.ssid[1]); -+ dev->oper_ssid_len = msg.ssid[1]; -+ } -+ -+ if (freq >= 2412 && freq <= 2484 && msg.ds_params && -+ *msg.ds_params >= 1 && *msg.ds_params <= 14) { -+ int ds_freq; -+ if (*msg.ds_params == 14) -+ ds_freq = 2484; -+ else -+ ds_freq = 2407 + *msg.ds_params * 5; -+ if (freq != ds_freq) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Update Listen frequency based on DS " -+ "Parameter Set IE: %d -> %d MHz", -+ freq, ds_freq); -+ freq = ds_freq; -+ } -+ } -+ -+ if (dev->listen_freq && dev->listen_freq != freq) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Update Listen frequency based on scan " -+ "results (" MACSTR " %d -> %d MHz (DS param %d)", -+ MAC2STR(dev->info.p2p_device_addr), dev->listen_freq, -+ freq, msg.ds_params ? *msg.ds_params : -1); -+ } -+ dev->listen_freq = freq; -+ if (msg.group_info) -+ dev->oper_freq = freq; -+ dev->level = level; -+ -+ p2p_copy_wps_info(dev, 0, &msg); -+ -+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { -+ wpabuf_free(dev->info.wps_vendor_ext[i]); -+ dev->info.wps_vendor_ext[i] = NULL; -+ } -+ -+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { -+ if (msg.wps_vendor_ext[i] == NULL) -+ break; -+ dev->info.wps_vendor_ext[i] = wpabuf_alloc_copy( -+ msg.wps_vendor_ext[i], msg.wps_vendor_ext_len[i]); -+ if (dev->info.wps_vendor_ext[i] == NULL) -+ break; -+ } -+ -+ p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq, msg.group_info, -+ msg.group_info_len); -+ -+ p2p_parse_free(&msg); -+ -+ if (p2p_pending_sd_req(p2p, dev)) -+ dev->flags |= P2P_DEV_SD_SCHEDULE; -+ -+ if (dev->flags & P2P_DEV_REPORTED) -+ return 0; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Peer found with Listen frequency %d MHz", freq); -+ if (dev->flags & P2P_DEV_USER_REJECTED) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Do not report rejected device"); -+ return 0; -+ } -+ -+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info, -+ !(dev->flags & P2P_DEV_REPORTED_ONCE)); -+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; -+ -+ return 0; -+} -+ -+ -+static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) -+{ -+ int i; -+ -+ if (p2p->go_neg_peer == dev) -+ p2p->go_neg_peer = NULL; -+ if (p2p->invite_peer == dev) -+ p2p->invite_peer = NULL; -+ if (p2p->sd_peer == dev) -+ p2p->sd_peer = NULL; -+ if (p2p->pending_client_disc_go == dev) -+ p2p->pending_client_disc_go = NULL; -+ -+ p2p->cfg->dev_lost(p2p->cfg->cb_ctx, dev->info.p2p_device_addr); -+ -+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { -+ wpabuf_free(dev->info.wps_vendor_ext[i]); -+ dev->info.wps_vendor_ext[i] = NULL; -+ } -+ -+ os_free(dev); -+} -+ -+ -+static int p2p_get_next_prog_freq(struct p2p_data *p2p) -+{ -+ struct p2p_channels *c; -+ struct p2p_reg_class *cla; -+ size_t cl, ch; -+ int found = 0; -+ u8 reg_class; -+ u8 channel; -+ int freq; -+ -+ c = &p2p->cfg->channels; -+ for (cl = 0; cl < c->reg_classes; cl++) { -+ cla = &c->reg_class[cl]; -+ if (cla->reg_class != p2p->last_prog_scan_class) -+ continue; -+ for (ch = 0; ch < cla->channels; ch++) { -+ if (cla->channel[ch] == p2p->last_prog_scan_chan) { -+ found = 1; -+ break; -+ } -+ } -+ if (found) -+ break; -+ } -+ -+ if (!found) { -+ /* Start from beginning */ -+ reg_class = c->reg_class[0].reg_class; -+ channel = c->reg_class[0].channel[0]; -+ } else { -+ /* Pick the next channel */ -+ ch++; -+ if (ch == cla->channels) { -+ cl++; -+ if (cl == c->reg_classes) -+ cl = 0; -+ ch = 0; -+ } -+ reg_class = c->reg_class[cl].reg_class; -+ channel = c->reg_class[cl].channel[ch]; -+ } -+ -+ freq = p2p_channel_to_freq(p2p->cfg->country, reg_class, channel); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Next progressive search " -+ "channel: reg_class %u channel %u -> %d MHz", -+ reg_class, channel, freq); -+ p2p->last_prog_scan_class = reg_class; -+ p2p->last_prog_scan_chan = channel; -+ -+ if (freq == 2412 || freq == 2437 || freq == 2462) -+ return 0; /* No need to add social channels */ -+ return freq; -+} -+ -+ -+static void p2p_search(struct p2p_data *p2p) -+{ -+ int freq = 0; -+ enum p2p_scan_type type; -+ -+ if (p2p->drv_in_listen) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still " -+ "in Listen state - wait for it to end before " -+ "continuing"); -+ return; -+ } -+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx); -+ -+ if (p2p->go_neg_peer) { -+ /* -+ * Only scan the known listen frequency of the peer -+ * during GO Negotiation start. -+ */ -+ freq = p2p->go_neg_peer->listen_freq; -+ if (freq <= 0) -+ freq = p2p->go_neg_peer->oper_freq; -+ type = P2P_SCAN_SPECIFIC; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search " -+ "for freq %u (GO Neg)", freq); -+ } else if (p2p->invite_peer) { -+ /* -+ * Only scan the known listen frequency of the peer -+ * during Invite start. -+ */ -+ freq = p2p->invite_peer->listen_freq; -+ if (freq <= 0) -+ freq = p2p->invite_peer->oper_freq; -+ type = P2P_SCAN_SPECIFIC; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search " -+ "for freq %u (Invite)", freq); -+ } else if (p2p->find_type == P2P_FIND_PROGRESSIVE && -+ (freq = p2p_get_next_prog_freq(p2p)) > 0) { -+ type = P2P_SCAN_SOCIAL_PLUS_ONE; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search " -+ "(+ freq %u)", freq); -+ } else { -+ type = P2P_SCAN_SOCIAL; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search"); -+ } -+ -+ if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, -+ p2p->num_req_dev_types, p2p->req_dev_types) < 0) -+ { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Scan request failed"); -+ p2p_continue_find(p2p); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan"); -+ p2p->p2p_scan_running = 1; -+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); -+ eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout, -+ p2p, NULL); -+ } -+} -+ -+ -+static void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct p2p_data *p2p = eloop_ctx; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Find timeout -> stop"); -+ p2p_stop_find(p2p); -+} -+ -+ -+static int p2p_run_after_scan(struct p2p_data *p2p) -+{ -+ struct p2p_device *dev; -+ enum p2p_after_scan op; -+ -+ if (p2p->after_scan_tx) { -+ int ret; -+ /* TODO: schedule p2p_run_after_scan to be called from TX -+ * status callback(?) */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending " -+ "Action frame at p2p_scan completion"); -+ ret = p2p->cfg->send_action(p2p->cfg->cb_ctx, -+ p2p->after_scan_tx->freq, -+ p2p->after_scan_tx->dst, -+ p2p->after_scan_tx->src, -+ p2p->after_scan_tx->bssid, -+ (u8 *) (p2p->after_scan_tx + 1), -+ p2p->after_scan_tx->len, -+ p2p->after_scan_tx->wait_time); -+ os_free(p2p->after_scan_tx); -+ p2p->after_scan_tx = NULL; -+ return 1; -+ } -+ -+ op = p2p->start_after_scan; -+ p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; -+ switch (op) { -+ case P2P_AFTER_SCAN_NOTHING: -+ break; -+ case P2P_AFTER_SCAN_LISTEN: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously " -+ "requested Listen state"); -+ p2p_listen(p2p, p2p->pending_listen_sec * 1000 + -+ p2p->pending_listen_usec / 1000); -+ return 1; -+ case P2P_AFTER_SCAN_CONNECT: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Start previously " -+ "requested connect with " MACSTR, -+ MAC2STR(p2p->after_scan_peer)); -+ dev = p2p_get_device(p2p, p2p->after_scan_peer); -+ if (dev == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer not " -+ "known anymore"); -+ break; -+ } -+ p2p_connect_send(p2p, dev); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct p2p_data *p2p = eloop_ctx; -+ int running; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan timeout " -+ "(running=%d)", p2p->p2p_scan_running); -+ running = p2p->p2p_scan_running; -+ /* Make sure we recover from missed scan results callback */ -+ p2p->p2p_scan_running = 0; -+ -+ if (running) -+ p2p_run_after_scan(p2p); -+} -+ -+ -+static void p2p_free_req_dev_types(struct p2p_data *p2p) -+{ -+ p2p->num_req_dev_types = 0; -+ os_free(p2p->req_dev_types); -+ p2p->req_dev_types = NULL; -+} -+ -+ -+int p2p_find(struct p2p_data *p2p, unsigned int timeout, -+ enum p2p_discovery_type type, -+ unsigned int num_req_dev_types, const u8 *req_dev_types) -+{ -+ int res; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)", -+ type); -+ if (p2p->p2p_scan_running) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is " -+ "already running"); -+ } -+ -+ p2p_free_req_dev_types(p2p); -+ if (req_dev_types && num_req_dev_types) { -+ p2p->req_dev_types = os_malloc(num_req_dev_types * -+ WPS_DEV_TYPE_LEN); -+ if (p2p->req_dev_types == NULL) -+ return -1; -+ os_memcpy(p2p->req_dev_types, req_dev_types, -+ num_req_dev_types * WPS_DEV_TYPE_LEN); -+ p2p->num_req_dev_types = num_req_dev_types; -+ } -+ -+ p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; -+ p2p_clear_timeout(p2p); -+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx); -+ p2p->find_type = type; -+ p2p_device_clear_reported(p2p); -+ p2p_set_state(p2p, P2P_SEARCH); -+ eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); -+ if (timeout) -+ eloop_register_timeout(timeout, 0, p2p_find_timeout, -+ p2p, NULL); -+ switch (type) { -+ case P2P_FIND_START_WITH_FULL: -+ case P2P_FIND_PROGRESSIVE: -+ res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0, -+ p2p->num_req_dev_types, -+ p2p->req_dev_types); -+ break; -+ case P2P_FIND_ONLY_SOCIAL: -+ res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0, -+ p2p->num_req_dev_types, -+ p2p->req_dev_types); -+ break; -+ default: -+ return -1; -+ } -+ -+ if (res == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan"); -+ p2p->p2p_scan_running = 1; -+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); -+ eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout, -+ p2p, NULL); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start " -+ "p2p_scan"); -+ } -+ -+ return res; -+} -+ -+ -+void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find"); -+ eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); -+ p2p_clear_timeout(p2p); -+ p2p_set_state(p2p, P2P_IDLE); -+ p2p_free_req_dev_types(p2p); -+ p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; -+ p2p->go_neg_peer = NULL; -+ p2p->sd_peer = NULL; -+ p2p->invite_peer = NULL; -+ if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip stop_listen " -+ "since we are on correct channel for response"); -+ return; -+ } -+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx); -+} -+ -+ -+void p2p_stop_find(struct p2p_data *p2p) -+{ -+ p2p_stop_find_for_freq(p2p, 0); -+} -+ -+ -+static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq) -+{ -+ if (force_freq) { -+ u8 op_reg_class, op_channel; -+ if (p2p_freq_to_channel(p2p->cfg->country, force_freq, -+ &op_reg_class, &op_channel) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported frequency %u MHz", -+ force_freq); -+ return -1; -+ } -+ if (!p2p_channels_includes(&p2p->cfg->channels, op_reg_class, -+ op_channel)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Frequency %u MHz (oper_class %u " -+ "channel %u) not allowed for P2P", -+ force_freq, op_reg_class, op_channel); -+ return -1; -+ } -+ p2p->op_reg_class = op_reg_class; -+ p2p->op_channel = op_channel; -+ p2p->channels.reg_classes = 1; -+ p2p->channels.reg_class[0].channels = 1; -+ p2p->channels.reg_class[0].reg_class = p2p->op_reg_class; -+ p2p->channels.reg_class[0].channel[0] = p2p->op_channel; -+ } else { -+ u8 op_reg_class, op_channel; -+ -+ if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 && -+ p2p_supported_freq(p2p, p2p->best_freq_overall) && -+ p2p_freq_to_channel(p2p->cfg->country, -+ p2p->best_freq_overall, -+ &op_reg_class, &op_channel) == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Select best overall channel as " -+ "operating channel preference"); -+ p2p->op_reg_class = op_reg_class; -+ p2p->op_channel = op_channel; -+ } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 && -+ p2p_supported_freq(p2p, p2p->best_freq_5) && -+ p2p_freq_to_channel(p2p->cfg->country, -+ p2p->best_freq_5, -+ &op_reg_class, &op_channel) == -+ 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Select best 5 GHz channel as " -+ "operating channel preference"); -+ p2p->op_reg_class = op_reg_class; -+ p2p->op_channel = op_channel; -+ } else if (!p2p->cfg->cfg_op_channel && -+ p2p->best_freq_24 > 0 && -+ p2p_supported_freq(p2p, p2p->best_freq_24) && -+ p2p_freq_to_channel(p2p->cfg->country, -+ p2p->best_freq_24, -+ &op_reg_class, &op_channel) == -+ 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Select best 2.4 GHz channel as " -+ "operating channel preference"); -+ p2p->op_reg_class = op_reg_class; -+ p2p->op_channel = op_channel; -+ } else { -+ p2p->op_reg_class = p2p->cfg->op_reg_class; -+ p2p->op_channel = p2p->cfg->op_channel; -+ } -+ -+ os_memcpy(&p2p->channels, &p2p->cfg->channels, -+ sizeof(struct p2p_channels)); -+ } -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Own preference for operation channel: " -+ "Operating Class %u Channel %u%s", -+ p2p->op_reg_class, p2p->op_channel, -+ force_freq ? " (forced)" : ""); -+ -+ return 0; -+} -+ -+ -+int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, -+ enum p2p_wps_method wps_method, -+ int go_intent, const u8 *own_interface_addr, -+ unsigned int force_freq, int persistent_group) -+{ -+ struct p2p_device *dev; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Request to start group negotiation - peer=" MACSTR -+ " GO Intent=%d Intended Interface Address=" MACSTR -+ " wps_method=%d persistent_group=%d", -+ MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr), -+ wps_method, persistent_group); -+ -+ if (p2p_prepare_channel(p2p, force_freq) < 0) -+ return -1; -+ -+ dev = p2p_get_device(p2p, peer_addr); -+ if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cannot connect to unknown P2P Device " MACSTR, -+ MAC2STR(peer_addr)); -+ return -1; -+ } -+ -+ if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { -+ if (!(dev->info.dev_capab & -+ P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cannot connect to P2P Device " MACSTR -+ " that is in a group and is not discoverable", -+ MAC2STR(peer_addr)); -+ return -1; -+ } -+ if (dev->oper_freq <= 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cannot connect to P2P Device " MACSTR -+ " with incomplete information", -+ MAC2STR(peer_addr)); -+ return -1; -+ } -+ -+ /* -+ * First, try to connect directly. If the peer does not -+ * acknowledge frames, assume it is sleeping and use device -+ * discoverability via the GO at that point. -+ */ -+ } -+ -+ dev->flags &= ~P2P_DEV_NOT_YET_READY; -+ dev->flags &= ~P2P_DEV_USER_REJECTED; -+ dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; -+ dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; -+ dev->connect_reqs = 0; -+ dev->go_neg_req_sent = 0; -+ dev->go_state = UNKNOWN_GO; -+ if (persistent_group) -+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; -+ else -+ dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP; -+ p2p->go_intent = go_intent; -+ os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); -+ -+ if (p2p->state != P2P_IDLE) -+ p2p_stop_find(p2p); -+ -+ if (p2p->after_scan_tx) { -+ /* -+ * We need to drop the pending frame to avoid issues with the -+ * new GO Negotiation, e.g., when the pending frame was from a -+ * previous attempt at starting a GO Negotiation. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped " -+ "previous pending Action frame TX that was waiting " -+ "for p2p_scan completion"); -+ os_free(p2p->after_scan_tx); -+ p2p->after_scan_tx = NULL; -+ } -+ -+ dev->wps_method = wps_method; -+ dev->status = P2P_SC_SUCCESS; -+ -+ if (force_freq) -+ dev->flags |= P2P_DEV_FORCE_FREQ; -+ else -+ dev->flags &= ~P2P_DEV_FORCE_FREQ; -+ -+ if (p2p->p2p_scan_running) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: p2p_scan running - delay connect send"); -+ p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT; -+ os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN); -+ return 0; -+ } -+ p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; -+ -+ return p2p_connect_send(p2p, dev); -+} -+ -+ -+int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, -+ enum p2p_wps_method wps_method, -+ int go_intent, const u8 *own_interface_addr, -+ unsigned int force_freq, int persistent_group) -+{ -+ struct p2p_device *dev; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Request to authorize group negotiation - peer=" MACSTR -+ " GO Intent=%d Intended Interface Address=" MACSTR -+ " wps_method=%d persistent_group=%d", -+ MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr), -+ wps_method, persistent_group); -+ -+ if (p2p_prepare_channel(p2p, force_freq) < 0) -+ return -1; -+ -+ dev = p2p_get_device(p2p, peer_addr); -+ if (dev == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cannot authorize unknown P2P Device " MACSTR, -+ MAC2STR(peer_addr)); -+ return -1; -+ } -+ -+ dev->flags &= ~P2P_DEV_NOT_YET_READY; -+ dev->flags &= ~P2P_DEV_USER_REJECTED; -+ dev->go_neg_req_sent = 0; -+ dev->go_state = UNKNOWN_GO; -+ if (persistent_group) -+ dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP; -+ else -+ dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP; -+ p2p->go_intent = go_intent; -+ os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN); -+ -+ dev->wps_method = wps_method; -+ dev->status = P2P_SC_SUCCESS; -+ -+ if (force_freq) -+ dev->flags |= P2P_DEV_FORCE_FREQ; -+ else -+ dev->flags &= ~P2P_DEV_FORCE_FREQ; -+ -+ return 0; -+} -+ -+ -+void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, -+ struct p2p_device *dev, struct p2p_message *msg) -+{ -+ os_get_time(&dev->last_seen); -+ -+ p2p_copy_wps_info(dev, 0, msg); -+ -+ if (msg->listen_channel) { -+ int freq; -+ freq = p2p_channel_to_freq((char *) msg->listen_channel, -+ msg->listen_channel[3], -+ msg->listen_channel[4]); -+ if (freq < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown peer Listen channel: " -+ "country=%c%c(0x%02x) reg_class=%u channel=%u", -+ msg->listen_channel[0], -+ msg->listen_channel[1], -+ msg->listen_channel[2], -+ msg->listen_channel[3], -+ msg->listen_channel[4]); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update " -+ "peer " MACSTR " Listen channel: %u -> %u MHz", -+ MAC2STR(dev->info.p2p_device_addr), -+ dev->listen_freq, freq); -+ dev->listen_freq = freq; -+ } -+ } -+ -+ if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) { -+ dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Completed device entry based on data from " -+ "GO Negotiation Request"); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Created device entry based on GO Neg Req: " -+ MACSTR " dev_capab=0x%x group_capab=0x%x name='%s' " -+ "listen_freq=%d", -+ MAC2STR(dev->info.p2p_device_addr), -+ dev->info.dev_capab, dev->info.group_capab, -+ dev->info.device_name, dev->listen_freq); -+ } -+ -+ dev->flags &= ~P2P_DEV_GROUP_CLIENT_ONLY; -+ -+ if (dev->flags & P2P_DEV_USER_REJECTED) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Do not report rejected device"); -+ return; -+ } -+ -+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info, -+ !(dev->flags & P2P_DEV_REPORTED_ONCE)); -+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE; -+} -+ -+ -+void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len) -+{ -+ os_memcpy(ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN); -+ p2p_random((char *) &ssid[P2P_WILDCARD_SSID_LEN], 2); -+ os_memcpy(&ssid[P2P_WILDCARD_SSID_LEN + 2], -+ p2p->cfg->ssid_postfix, p2p->cfg->ssid_postfix_len); -+ *ssid_len = P2P_WILDCARD_SSID_LEN + 2 + p2p->cfg->ssid_postfix_len; -+} -+ -+ -+int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params) -+{ -+ p2p_build_ssid(p2p, params->ssid, ¶ms->ssid_len); -+ p2p_random(params->passphrase, 8); -+ return 0; -+} -+ -+ -+void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) -+{ -+ struct p2p_go_neg_results res; -+ int go = peer->go_state == LOCAL_GO; -+ struct p2p_channels intersection; -+ int freqs; -+ size_t i, j; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation with " MACSTR " completed (%s will be " -+ "GO)", MAC2STR(peer->info.p2p_device_addr), -+ go ? "local end" : "peer"); -+ -+ os_memset(&res, 0, sizeof(res)); -+ res.role_go = go; -+ os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN); -+ os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN); -+ res.wps_method = peer->wps_method; -+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) -+ res.persistent_group = 1; -+ -+ if (go) { -+ /* Setup AP mode for WPS provisioning */ -+ res.freq = p2p_channel_to_freq(p2p->cfg->country, -+ p2p->op_reg_class, -+ p2p->op_channel); -+ os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len); -+ res.ssid_len = p2p->ssid_len; -+ p2p_random(res.passphrase, 8); -+ } else { -+ res.freq = peer->oper_freq; -+ if (p2p->ssid_len) { -+ os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len); -+ res.ssid_len = p2p->ssid_len; -+ } -+ } -+ -+ p2p_channels_intersect(&p2p->channels, &peer->channels, -+ &intersection); -+ freqs = 0; -+ for (i = 0; i < intersection.reg_classes; i++) { -+ struct p2p_reg_class *c = &intersection.reg_class[i]; -+ if (freqs + 1 == P2P_MAX_CHANNELS) -+ break; -+ for (j = 0; j < c->channels; j++) { -+ int freq; -+ if (freqs + 1 == P2P_MAX_CHANNELS) -+ break; -+ freq = p2p_channel_to_freq(peer->country, c->reg_class, -+ c->channel[j]); -+ if (freq < 0) -+ continue; -+ res.freq_list[freqs++] = freq; -+ } -+ } -+ -+ res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout; -+ -+ p2p_clear_timeout(p2p); -+ peer->go_neg_req_sent = 0; -+ peer->wps_method = WPS_NOT_READY; -+ -+ p2p_set_state(p2p, P2P_PROVISIONING); -+ p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res); -+} -+ -+ -+static void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: RX P2P Public Action from " MACSTR, MAC2STR(sa)); -+ wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len); -+ -+ if (len < 1) -+ return; -+ -+ switch (data[0]) { -+ case P2P_GO_NEG_REQ: -+ p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq); -+ break; -+ case P2P_GO_NEG_RESP: -+ p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq); -+ break; -+ case P2P_GO_NEG_CONF: -+ p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1); -+ break; -+ case P2P_INVITATION_REQ: -+ p2p_process_invitation_req(p2p, sa, data + 1, len - 1, -+ rx_freq); -+ break; -+ case P2P_INVITATION_RESP: -+ p2p_process_invitation_resp(p2p, sa, data + 1, len - 1); -+ break; -+ case P2P_PROV_DISC_REQ: -+ p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq); -+ break; -+ case P2P_PROV_DISC_RESP: -+ p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1); -+ break; -+ case P2P_DEV_DISC_REQ: -+ p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq); -+ break; -+ case P2P_DEV_DISC_RESP: -+ p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1); -+ break; -+ default: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported P2P Public Action frame type %d", -+ data[0]); -+ break; -+ } -+} -+ -+ -+void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa, -+ const u8 *bssid, const u8 *data, size_t len, -+ int freq) -+{ -+ if (len < 1) -+ return; -+ -+ switch (data[0]) { -+ case WLAN_PA_VENDOR_SPECIFIC: -+ data++; -+ len--; -+ if (len < 3) -+ return; -+ if (WPA_GET_BE24(data) != OUI_WFA) -+ return; -+ -+ data += 3; -+ len -= 3; -+ if (len < 1) -+ return; -+ -+ if (*data != P2P_OUI_TYPE) -+ return; -+ -+ p2p_rx_p2p_action(p2p, sa, data + 1, len - 1, freq); -+ break; -+ case WLAN_PA_GAS_INITIAL_REQ: -+ p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq); -+ break; -+ case WLAN_PA_GAS_INITIAL_RESP: -+ p2p_rx_gas_initial_resp(p2p, sa, data + 1, len - 1, freq); -+ break; -+ case WLAN_PA_GAS_COMEBACK_REQ: -+ p2p_rx_gas_comeback_req(p2p, sa, data + 1, len - 1, freq); -+ break; -+ case WLAN_PA_GAS_COMEBACK_RESP: -+ p2p_rx_gas_comeback_resp(p2p, sa, data + 1, len - 1, freq); -+ break; -+ } -+} -+ -+ -+void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, -+ const u8 *bssid, u8 category, -+ const u8 *data, size_t len, int freq) -+{ -+ if (category == WLAN_ACTION_PUBLIC) { -+ p2p_rx_action_public(p2p, da, sa, bssid, data, len, freq); -+ return; -+ } -+ -+ if (category != WLAN_ACTION_VENDOR_SPECIFIC) -+ return; -+ -+ if (len < 4) -+ return; -+ -+ if (WPA_GET_BE24(data) != OUI_WFA) -+ return; -+ data += 3; -+ len -= 3; -+ -+ if (*data != P2P_OUI_TYPE) -+ return; -+ data++; -+ len--; -+ -+ /* P2P action frame */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: RX P2P Action from " MACSTR, MAC2STR(sa)); -+ wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Action contents", data, len); -+ -+ if (len < 1) -+ return; -+ switch (data[0]) { -+ case P2P_NOA: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received P2P Action - Notice of Absence"); -+ /* TODO */ -+ break; -+ case P2P_PRESENCE_REQ: -+ p2p_process_presence_req(p2p, da, sa, data + 1, len - 1, freq); -+ break; -+ case P2P_PRESENCE_RESP: -+ p2p_process_presence_resp(p2p, da, sa, data + 1, len - 1); -+ break; -+ case P2P_GO_DISC_REQ: -+ p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq); -+ break; -+ default: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received P2P Action - unknown type %u", data[0]); -+ break; -+ } -+} -+ -+ -+static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct p2p_data *p2p = eloop_ctx; -+ if (p2p->go_neg_peer == NULL) -+ return; -+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx); -+ p2p->go_neg_peer->status = P2P_SC_SUCCESS; -+ p2p_connect_send(p2p, p2p->go_neg_peer); -+} -+ -+ -+static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct p2p_data *p2p = eloop_ctx; -+ if (p2p->invite_peer == NULL) -+ return; -+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx); -+ p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr); -+} -+ -+ -+static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, -+ const u8 *ie, size_t ie_len) -+{ -+ struct p2p_message msg; -+ struct p2p_device *dev; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_ies(ie, ie_len, &msg) < 0 || msg.p2p_attributes == NULL) -+ { -+ p2p_parse_free(&msg); -+ return; /* not a P2P probe */ -+ } -+ -+ if (msg.ssid == NULL || msg.ssid[1] != P2P_WILDCARD_SSID_LEN || -+ os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) -+ != 0) { -+ /* The Probe Request is not part of P2P Device Discovery. It is -+ * not known whether the source address of the frame is the P2P -+ * Device Address or P2P Interface Address. Do not add a new -+ * peer entry based on this frames. -+ */ -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ dev = p2p_get_device(p2p, addr); -+ if (dev) { -+ if (dev->country[0] == 0 && msg.listen_channel) -+ os_memcpy(dev->country, msg.listen_channel, 3); -+ p2p_parse_free(&msg); -+ return; /* already known */ -+ } -+ -+ dev = p2p_create_device(p2p, addr); -+ if (dev == NULL) { -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ os_get_time(&dev->last_seen); -+ dev->flags |= P2P_DEV_PROBE_REQ_ONLY; -+ -+ if (msg.listen_channel) { -+ os_memcpy(dev->country, msg.listen_channel, 3); -+ dev->listen_freq = p2p_channel_to_freq(dev->country, -+ msg.listen_channel[3], -+ msg.listen_channel[4]); -+ } -+ -+ p2p_copy_wps_info(dev, 1, &msg); -+ -+ p2p_parse_free(&msg); -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Created device entry based on Probe Req: " MACSTR -+ " dev_capab=0x%x group_capab=0x%x name='%s' listen_freq=%d", -+ MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab, -+ dev->info.group_capab, dev->info.device_name, -+ dev->listen_freq); -+} -+ -+ -+struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, -+ const u8 *addr, -+ struct p2p_message *msg) -+{ -+ struct p2p_device *dev; -+ -+ dev = p2p_get_device(p2p, addr); -+ if (dev) { -+ os_get_time(&dev->last_seen); -+ return dev; /* already known */ -+ } -+ -+ dev = p2p_create_device(p2p, addr); -+ if (dev == NULL) -+ return NULL; -+ -+ p2p_add_dev_info(p2p, addr, dev, msg); -+ -+ return dev; -+} -+ -+ -+static int dev_type_match(const u8 *dev_type, const u8 *req_dev_type) -+{ -+ if (os_memcmp(dev_type, req_dev_type, WPS_DEV_TYPE_LEN) == 0) -+ return 1; -+ if (os_memcmp(dev_type, req_dev_type, 2) == 0 && -+ WPA_GET_BE32(&req_dev_type[2]) == 0 && -+ WPA_GET_BE16(&req_dev_type[6]) == 0) -+ return 1; /* Category match with wildcard OUI/sub-category */ -+ return 0; -+} -+ -+ -+int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[], -+ size_t num_req_dev_type) -+{ -+ size_t i; -+ for (i = 0; i < num_req_dev_type; i++) { -+ if (dev_type_match(dev_type, req_dev_type[i])) -+ return 1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * p2p_match_dev_type - Match local device type with requested type -+ * @p2p: P2P module context from p2p_init() -+ * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs) -+ * Returns: 1 on match, 0 on mismatch -+ * -+ * This function can be used to match the Requested Device Type attribute in -+ * WPS IE with the local device types for deciding whether to reply to a Probe -+ * Request frame. -+ */ -+int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps) -+{ -+ struct wps_parse_attr attr; -+ size_t i; -+ -+ if (wps_parse_msg(wps, &attr)) -+ return 1; /* assume no Requested Device Type attributes */ -+ -+ if (attr.num_req_dev_type == 0) -+ return 1; /* no Requested Device Type attributes -> match */ -+ -+ if (dev_type_list_match(p2p->cfg->pri_dev_type, attr.req_dev_type, -+ attr.num_req_dev_type)) -+ return 1; /* Own Primary Device Type matches */ -+ -+ for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) -+ if (dev_type_list_match(p2p->cfg->sec_dev_type[i], -+ attr.req_dev_type, -+ attr.num_req_dev_type)) -+ return 1; /* Own Secondary Device Type matches */ -+ -+ /* No matching device type found */ -+ return 0; -+} -+ -+ -+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ -+ buf = wpabuf_alloc(1000); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_build_wps_ie(p2p, buf, DEV_PW_DEFAULT, 1); -+ -+ /* P2P IE */ -+ len = p2p_buf_add_ie_hdr(buf); -+ p2p_buf_add_capability(buf, p2p->dev_capab, 0); -+ if (p2p->ext_listen_interval) -+ p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period, -+ p2p->ext_listen_interval); -+ p2p_buf_add_device_info(buf, p2p, NULL); -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ return buf; -+} -+ -+ -+static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie, -+ size_t ie_len) -+{ -+ struct ieee802_11_elems elems; -+ struct wpabuf *buf; -+ struct ieee80211_mgmt *resp; -+ struct wpabuf *wps; -+ struct wpabuf *ies; -+ -+ if (!p2p->in_listen || !p2p->drv_in_listen) { -+ /* not in Listen state - ignore Probe Request */ -+ return; -+ } -+ -+ if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) == -+ ParseFailed) { -+ /* Ignore invalid Probe Request frames */ -+ return; -+ } -+ -+ if (elems.p2p == NULL) { -+ /* not a P2P probe - ignore it */ -+ return; -+ } -+ -+ if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN || -+ os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) != -+ 0) { -+ /* not using P2P Wildcard SSID - ignore */ -+ return; -+ } -+ -+ /* Check Requested Device Type match */ -+ wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA); -+ if (wps && !p2p_match_dev_type(p2p, wps)) { -+ wpabuf_free(wps); -+ /* No match with Requested Device Type */ -+ return; -+ } -+ wpabuf_free(wps); -+ -+ if (!p2p->cfg->send_probe_resp) -+ return; /* Response generated elsewhere */ -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Reply to P2P Probe Request in Listen state"); -+ -+ /* -+ * We do not really have a specific BSS that this frame is advertising, -+ * so build a frame that has some information in valid format. This is -+ * really only used for discovery purposes, not to learn exact BSS -+ * parameters. -+ */ -+ ies = p2p_build_probe_resp_ies(p2p); -+ if (ies == NULL) -+ return; -+ -+ buf = wpabuf_alloc(200 + wpabuf_len(ies)); -+ if (buf == NULL) { -+ wpabuf_free(ies); -+ return; -+ } -+ -+ resp = NULL; -+ resp = wpabuf_put(buf, resp->u.probe_resp.variable - (u8 *) resp); -+ -+ resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) | -+ (WLAN_FC_STYPE_PROBE_RESP << 4)); -+ os_memcpy(resp->da, addr, ETH_ALEN); -+ os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN); -+ os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN); -+ resp->u.probe_resp.beacon_int = host_to_le16(100); -+ /* hardware or low-level driver will setup seq_ctrl and timestamp */ -+ resp->u.probe_resp.capab_info = -+ host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE | -+ WLAN_CAPABILITY_PRIVACY | -+ WLAN_CAPABILITY_SHORT_SLOT_TIME); -+ -+ wpabuf_put_u8(buf, WLAN_EID_SSID); -+ wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN); -+ wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN); -+ -+ wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES); -+ wpabuf_put_u8(buf, 8); -+ wpabuf_put_u8(buf, (60 / 5) | 0x80); -+ wpabuf_put_u8(buf, 90 / 5); -+ wpabuf_put_u8(buf, (120 / 5) | 0x80); -+ wpabuf_put_u8(buf, 180 / 5); -+ wpabuf_put_u8(buf, (240 / 5) | 0x80); -+ wpabuf_put_u8(buf, 360 / 5); -+ wpabuf_put_u8(buf, 480 / 5); -+ wpabuf_put_u8(buf, 540 / 5); -+ -+ wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS); -+ wpabuf_put_u8(buf, 1); -+ wpabuf_put_u8(buf, p2p->cfg->channel); -+ -+ wpabuf_put_buf(buf, ies); -+ wpabuf_free(ies); -+ -+ p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf); -+ -+ wpabuf_free(buf); -+} -+ -+ -+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie, -+ size_t ie_len) -+{ -+ p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len); -+ -+ p2p_reply_probe(p2p, addr, ie, ie_len); -+ -+ if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) && -+ p2p->go_neg_peer && -+ os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) -+ == 0) { -+ /* Received a Probe Request from GO Negotiation peer */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Found GO Negotiation peer - try to start GO " -+ "negotiation from timeout"); -+ eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL); -+ return 1; -+ } -+ -+ if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) && -+ p2p->invite_peer && -+ os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN) -+ == 0) { -+ /* Received a Probe Request from Invite peer */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Found Invite peer - try to start Invite from " -+ "timeout"); -+ eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static int p2p_assoc_req_ie_wlan_ap(struct p2p_data *p2p, const u8 *bssid, -+ u8 *buf, size_t len, struct wpabuf *p2p_ie) -+{ -+ struct wpabuf *tmp; -+ u8 *lpos; -+ size_t tmplen; -+ int res; -+ u8 group_capab; -+ -+ if (p2p_ie == NULL) -+ return 0; /* WLAN AP is not a P2P manager */ -+ -+ /* -+ * (Re)Association Request - P2P IE -+ * P2P Capability attribute (shall be present) -+ * P2P Interface attribute (present if concurrent device and -+ * P2P Management is enabled) -+ */ -+ tmp = wpabuf_alloc(200); -+ if (tmp == NULL) -+ return -1; -+ -+ lpos = p2p_buf_add_ie_hdr(tmp); -+ group_capab = 0; -+ if (p2p->num_groups > 0) { -+ group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; -+ if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && -+ (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) && -+ p2p->cross_connect) -+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; -+ } -+ p2p_buf_add_capability(tmp, p2p->dev_capab, group_capab); -+ if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) && -+ (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED)) -+ p2p_buf_add_p2p_interface(tmp, p2p); -+ p2p_buf_update_ie_hdr(tmp, lpos); -+ -+ tmplen = wpabuf_len(tmp); -+ if (tmplen > len) -+ res = -1; -+ else { -+ os_memcpy(buf, wpabuf_head(tmp), tmplen); -+ res = tmplen; -+ } -+ wpabuf_free(tmp); -+ -+ return res; -+} -+ -+ -+int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, -+ size_t len, int p2p_group, struct wpabuf *p2p_ie) -+{ -+ struct wpabuf *tmp; -+ u8 *lpos; -+ struct p2p_device *peer; -+ size_t tmplen; -+ int res; -+ -+ if (!p2p_group) -+ return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie); -+ -+ /* -+ * (Re)Association Request - P2P IE -+ * P2P Capability attribute (shall be present) -+ * Extended Listen Timing (may be present) -+ * P2P Device Info attribute (shall be present) -+ */ -+ tmp = wpabuf_alloc(200); -+ if (tmp == NULL) -+ return -1; -+ -+ peer = bssid ? p2p_get_device(p2p, bssid) : NULL; -+ -+ lpos = p2p_buf_add_ie_hdr(tmp); -+ p2p_buf_add_capability(tmp, p2p->dev_capab, 0); -+ if (p2p->ext_listen_interval) -+ p2p_buf_add_ext_listen_timing(tmp, p2p->ext_listen_period, -+ p2p->ext_listen_interval); -+ p2p_buf_add_device_info(tmp, p2p, peer); -+ p2p_buf_update_ie_hdr(tmp, lpos); -+ -+ tmplen = wpabuf_len(tmp); -+ if (tmplen > len) -+ res = -1; -+ else { -+ os_memcpy(buf, wpabuf_head(tmp), tmplen); -+ res = tmplen; -+ } -+ wpabuf_free(tmp); -+ -+ return res; -+} -+ -+ -+int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end) -+{ -+ struct wpabuf *p2p_ie; -+ int ret; -+ -+ p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, P2P_IE_VENDOR_TYPE); -+ if (p2p_ie == NULL) -+ return 0; -+ -+ ret = p2p_attr_text(p2p_ie, buf, end); -+ wpabuf_free(p2p_ie); -+ return ret; -+} -+ -+ -+static void p2p_clear_go_neg(struct p2p_data *p2p) -+{ -+ p2p->go_neg_peer = NULL; -+ p2p_clear_timeout(p2p); -+ p2p_set_state(p2p, P2P_IDLE); -+} -+ -+ -+void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr) -+{ -+ if (p2p->go_neg_peer == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No pending Group Formation - " -+ "ignore WPS registration success notification"); -+ return; /* No pending Group Formation */ -+ } -+ -+ if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) != -+ 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore WPS registration success notification " -+ "for " MACSTR " (GO Negotiation peer " MACSTR ")", -+ MAC2STR(mac_addr), -+ MAC2STR(p2p->go_neg_peer->intended_addr)); -+ return; /* Ignore unexpected peer address */ -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Group Formation completed successfully with " MACSTR, -+ MAC2STR(mac_addr)); -+ -+ p2p_clear_go_neg(p2p); -+} -+ -+ -+void p2p_group_formation_failed(struct p2p_data *p2p) -+{ -+ if (p2p->go_neg_peer == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No pending Group Formation - " -+ "ignore group formation failure notification"); -+ return; /* No pending Group Formation */ -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Group Formation failed with " MACSTR, -+ MAC2STR(p2p->go_neg_peer->intended_addr)); -+ -+ p2p_clear_go_neg(p2p); -+} -+ -+ -+struct p2p_data * p2p_init(const struct p2p_config *cfg) -+{ -+ struct p2p_data *p2p; -+ -+ if (cfg->max_peers < 1) -+ return NULL; -+ -+ p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg)); -+ if (p2p == NULL) -+ return NULL; -+ p2p->cfg = (struct p2p_config *) (p2p + 1); -+ os_memcpy(p2p->cfg, cfg, sizeof(*cfg)); -+ if (cfg->dev_name) -+ p2p->cfg->dev_name = os_strdup(cfg->dev_name); -+ if (cfg->manufacturer) -+ p2p->cfg->manufacturer = os_strdup(cfg->manufacturer); -+ if (cfg->model_name) -+ p2p->cfg->model_name = os_strdup(cfg->model_name); -+ if (cfg->model_number) -+ p2p->cfg->model_number = os_strdup(cfg->model_number); -+ if (cfg->serial_number) -+ p2p->cfg->serial_number = os_strdup(cfg->serial_number); -+ -+ p2p->min_disc_int = 1; -+ p2p->max_disc_int = 3; -+ -+ os_get_random(&p2p->next_tie_breaker, 1); -+ p2p->next_tie_breaker &= 0x01; -+ if (cfg->sd_request) -+ p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY; -+ p2p->dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE; -+ if (cfg->concurrent_operations) -+ p2p->dev_capab |= P2P_DEV_CAPAB_CONCURRENT_OPER; -+ p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; -+ -+ dl_list_init(&p2p->devices); -+ -+ eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0, -+ p2p_expiration_timeout, p2p, NULL); -+ -+ return p2p; -+} -+ -+ -+void p2p_deinit(struct p2p_data *p2p) -+{ -+ eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL); -+ eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL); -+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); -+ p2p_flush(p2p); -+ p2p_free_req_dev_types(p2p); -+ os_free(p2p->cfg->dev_name); -+ os_free(p2p->cfg->manufacturer); -+ os_free(p2p->cfg->model_name); -+ os_free(p2p->cfg->model_number); -+ os_free(p2p->cfg->serial_number); -+ os_free(p2p->groups); -+ wpabuf_free(p2p->sd_resp); -+ os_free(p2p->after_scan_tx); -+ p2p_remove_wps_vendor_extensions(p2p); -+ os_free(p2p); -+} -+ -+ -+void p2p_flush(struct p2p_data *p2p) -+{ -+ struct p2p_device *dev, *prev; -+ p2p_clear_timeout(p2p); -+ p2p_set_state(p2p, P2P_IDLE); -+ p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; -+ p2p->go_neg_peer = NULL; -+ eloop_cancel_timeout(p2p_find_timeout, p2p, NULL); -+ dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device, -+ list) { -+ dl_list_del(&dev->list); -+ p2p_device_free(p2p, dev); -+ } -+ p2p_free_sd_queries(p2p); -+ os_free(p2p->after_scan_tx); -+ p2p->after_scan_tx = NULL; -+} -+ -+ -+int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr) -+{ -+ struct p2p_device *dev; -+ -+ dev = p2p_get_device(p2p, addr); -+ if (dev == NULL) -+ return -1; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unauthorizing " MACSTR, -+ MAC2STR(addr)); -+ -+ if (p2p->go_neg_peer == dev) -+ p2p->go_neg_peer = NULL; -+ -+ dev->wps_method = WPS_NOT_READY; -+ dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; -+ dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; -+ -+ /* Check if after_scan_tx is for this peer. If so free it */ -+ if (p2p->after_scan_tx && -+ os_memcmp(addr, p2p->after_scan_tx->dst, ETH_ALEN) == 0) { -+ os_free(p2p->after_scan_tx); -+ p2p->after_scan_tx = NULL; -+ } -+ -+ return 0; -+} -+ -+ -+int p2p_set_dev_name(struct p2p_data *p2p, const char *dev_name) -+{ -+ os_free(p2p->cfg->dev_name); -+ if (dev_name) { -+ p2p->cfg->dev_name = os_strdup(dev_name); -+ if (p2p->cfg->dev_name == NULL) -+ return -1; -+ } else -+ p2p->cfg->dev_name = NULL; -+ return 0; -+} -+ -+ -+int p2p_set_manufacturer(struct p2p_data *p2p, const char *manufacturer) -+{ -+ os_free(p2p->cfg->manufacturer); -+ p2p->cfg->manufacturer = NULL; -+ if (manufacturer) { -+ p2p->cfg->manufacturer = os_strdup(manufacturer); -+ if (p2p->cfg->manufacturer == NULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int p2p_set_model_name(struct p2p_data *p2p, const char *model_name) -+{ -+ os_free(p2p->cfg->model_name); -+ p2p->cfg->model_name = NULL; -+ if (model_name) { -+ p2p->cfg->model_name = os_strdup(model_name); -+ if (p2p->cfg->model_name == NULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int p2p_set_model_number(struct p2p_data *p2p, const char *model_number) -+{ -+ os_free(p2p->cfg->model_number); -+ p2p->cfg->model_number = NULL; -+ if (model_number) { -+ p2p->cfg->model_number = os_strdup(model_number); -+ if (p2p->cfg->model_number == NULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int p2p_set_serial_number(struct p2p_data *p2p, const char *serial_number) -+{ -+ os_free(p2p->cfg->serial_number); -+ p2p->cfg->serial_number = NULL; -+ if (serial_number) { -+ p2p->cfg->serial_number = os_strdup(serial_number); -+ if (p2p->cfg->serial_number == NULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+void p2p_set_config_methods(struct p2p_data *p2p, u16 config_methods) -+{ -+ p2p->cfg->config_methods = config_methods; -+} -+ -+ -+void p2p_set_uuid(struct p2p_data *p2p, const u8 *uuid) -+{ -+ os_memcpy(p2p->cfg->uuid, uuid, 16); -+} -+ -+ -+int p2p_set_pri_dev_type(struct p2p_data *p2p, const u8 *pri_dev_type) -+{ -+ os_memcpy(p2p->cfg->pri_dev_type, pri_dev_type, 8); -+ return 0; -+} -+ -+ -+int p2p_set_sec_dev_types(struct p2p_data *p2p, const u8 dev_types[][8], -+ size_t num_dev_types) -+{ -+ if (num_dev_types > P2P_SEC_DEVICE_TYPES) -+ num_dev_types = P2P_SEC_DEVICE_TYPES; -+ p2p->cfg->num_sec_dev_types = num_dev_types; -+ os_memcpy(p2p->cfg->sec_dev_type, dev_types, num_dev_types * 8); -+ return 0; -+} -+ -+ -+void p2p_remove_wps_vendor_extensions(struct p2p_data *p2p) -+{ -+ int i; -+ -+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { -+ wpabuf_free(p2p->wps_vendor_ext[i]); -+ p2p->wps_vendor_ext[i] = NULL; -+ } -+} -+ -+ -+int p2p_add_wps_vendor_extension(struct p2p_data *p2p, -+ const struct wpabuf *vendor_ext) -+{ -+ int i; -+ -+ if (vendor_ext == NULL) -+ return -1; -+ -+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { -+ if (p2p->wps_vendor_ext[i] == NULL) -+ break; -+ } -+ if (i >= P2P_MAX_WPS_VENDOR_EXT) -+ return -1; -+ -+ p2p->wps_vendor_ext[i] = wpabuf_dup(vendor_ext); -+ if (p2p->wps_vendor_ext[i] == NULL) -+ return -1; -+ -+ return 0; -+} -+ -+ -+int p2p_set_country(struct p2p_data *p2p, const char *country) -+{ -+ os_memcpy(p2p->cfg->country, country, 3); -+ return 0; -+} -+ -+ -+void p2p_continue_find(struct p2p_data *p2p) -+{ -+ struct p2p_device *dev; -+ p2p_set_state(p2p, P2P_SEARCH); -+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { -+ if (dev->flags & P2P_DEV_SD_SCHEDULE) { -+ if (p2p_start_sd(p2p, dev) == 0) -+ return; -+ else -+ break; -+ } else if (dev->req_config_methods && -+ !(dev->flags & P2P_DEV_PD_FOR_JOIN)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send " -+ "pending Provisioning Discovery Request to " -+ MACSTR " (config methods 0x%x)", -+ MAC2STR(dev->info.p2p_device_addr), -+ dev->req_config_methods); -+ if (p2p_send_prov_disc_req(p2p, dev, 0) == 0) -+ return; -+ } -+ } -+ -+ p2p_listen_in_find(p2p); -+} -+ -+ -+static void p2p_sd_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Service Discovery Query TX callback: success=%d", -+ success); -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ -+ if (!success) { -+ if (p2p->sd_peer) { -+ p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; -+ p2p->sd_peer = NULL; -+ } -+ p2p_continue_find(p2p); -+ return; -+ } -+ -+ if (p2p->sd_peer == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No SD peer entry known"); -+ p2p_continue_find(p2p); -+ return; -+ } -+ -+ /* Wait for response from the peer */ -+ p2p_set_state(p2p, P2P_SD_DURING_FIND); -+ p2p_set_timeout(p2p, 0, 200000); -+} -+ -+static void p2p_prov_disc_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Provision Discovery Request TX callback: success=%d", -+ success); -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ -+ if (!success) { -+ if (p2p->state != P2P_IDLE) -+ p2p_continue_find(p2p); -+ return; -+ } -+ -+ /* Wait for response from the peer */ -+ if (p2p->state == P2P_SEARCH) -+ p2p_set_state(p2p, P2P_PD_DURING_FIND); -+ p2p_set_timeout(p2p, 0, 200000); -+} -+ -+ -+int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, -+ int level, const u8 *ies, size_t ies_len) -+{ -+ p2p_add_device(p2p, bssid, freq, level, ies, ies_len); -+ -+ if (p2p->go_neg_peer && p2p->state == P2P_SEARCH && -+ os_memcmp(p2p->go_neg_peer->info.p2p_device_addr, bssid, ETH_ALEN) -+ == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Found GO Negotiation peer - try to start GO " -+ "negotiation"); -+ p2p_connect_send(p2p, p2p->go_neg_peer); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+void p2p_scan_res_handled(struct p2p_data *p2p) -+{ -+ if (!p2p->p2p_scan_running) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan was not " -+ "running, but scan results received"); -+ } -+ p2p->p2p_scan_running = 0; -+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL); -+ -+ if (p2p_run_after_scan(p2p)) -+ return; -+ if (p2p->state == P2P_SEARCH) -+ p2p_continue_find(p2p); -+} -+ -+ -+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies) -+{ -+ u8 *len = p2p_buf_add_ie_hdr(ies); -+ p2p_buf_add_capability(ies, p2p->dev_capab, 0); -+ if (p2p->cfg->reg_class && p2p->cfg->channel) -+ p2p_buf_add_listen_channel(ies, p2p->cfg->country, -+ p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (p2p->ext_listen_interval) -+ p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period, -+ p2p->ext_listen_interval); -+ /* TODO: p2p_buf_add_operating_channel() if GO */ -+ p2p_buf_update_ie_hdr(ies, len); -+} -+ -+ -+int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end) -+{ -+ return p2p_attr_text(p2p_ie, buf, end); -+} -+ -+ -+static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success) -+{ -+ struct p2p_device *dev = p2p->go_neg_peer; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation Request TX callback: success=%d", -+ success); -+ -+ if (dev == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No pending GO Negotiation"); -+ return; -+ } -+ -+ if (success) { -+ dev->go_neg_req_sent++; -+ if (dev->flags & P2P_DEV_USER_REJECTED) { -+ p2p_set_state(p2p, P2P_IDLE); -+ return; -+ } -+ } -+ -+ if (!success && -+ (dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) && -+ !is_zero_ether_addr(dev->member_in_go_dev)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Peer " MACSTR " did not acknowledge request - " -+ "try to use device discoverability through its GO", -+ MAC2STR(dev->info.p2p_device_addr)); -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p_send_dev_disc_req(p2p, dev); -+ return; -+ } -+ -+ /* -+ * Use P2P find, if needed, to find the other device from its listen -+ * channel. -+ */ -+ p2p_set_state(p2p, P2P_CONNECT); -+ p2p_set_timeout(p2p, 0, 100000); -+} -+ -+ -+static void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation Response TX callback: success=%d", -+ success); -+ if (!p2p->go_neg_peer && p2p->state == P2P_PROVISIONING) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore TX callback event - GO Negotiation is " -+ "not running anymore"); -+ return; -+ } -+ p2p_set_state(p2p, P2P_CONNECT); -+ p2p_set_timeout(p2p, 0, 100000); -+} -+ -+ -+static void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation Response (failure) TX callback: " -+ "success=%d", success); -+ if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) { -+ p2p_go_neg_failed(p2p, p2p->go_neg_peer, -+ p2p->go_neg_peer->status); -+ } -+} -+ -+ -+static void p2p_go_neg_conf_cb(struct p2p_data *p2p, -+ enum p2p_send_action_result result) -+{ -+ struct p2p_device *dev; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation Confirm TX callback: result=%d", -+ result); -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ if (result == P2P_SEND_ACTION_FAILED) { -+ p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); -+ return; -+ } -+ if (result == P2P_SEND_ACTION_NO_ACK) { -+ /* -+ * It looks like the TX status for GO Negotiation Confirm is -+ * often showing failure even when the peer has actually -+ * received the frame. Since the peer may change channels -+ * immediately after having received the frame, we may not see -+ * an Ack for retries, so just dropping a single frame may -+ * trigger this. To allow the group formation to succeed if the -+ * peer did indeed receive the frame, continue regardless of -+ * the TX status. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Assume GO Negotiation Confirm TX was actually " -+ "received by the peer even though Ack was not " -+ "reported"); -+ } -+ -+ dev = p2p->go_neg_peer; -+ if (dev == NULL) -+ return; -+ -+ p2p_go_complete(p2p, dev); -+} -+ -+ -+void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst, -+ const u8 *src, const u8 *bssid, -+ enum p2p_send_action_result result) -+{ -+ enum p2p_pending_action_state state; -+ int success; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Action frame TX callback (state=%d freq=%u dst=" MACSTR -+ " src=" MACSTR " bssid=" MACSTR " result=%d", -+ p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src), -+ MAC2STR(bssid), result); -+ success = result == P2P_SEND_ACTION_SUCCESS; -+ state = p2p->pending_action_state; -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ switch (state) { -+ case P2P_NO_PENDING_ACTION: -+ break; -+ case P2P_PENDING_GO_NEG_REQUEST: -+ p2p_go_neg_req_cb(p2p, success); -+ break; -+ case P2P_PENDING_GO_NEG_RESPONSE: -+ p2p_go_neg_resp_cb(p2p, success); -+ break; -+ case P2P_PENDING_GO_NEG_RESPONSE_FAILURE: -+ p2p_go_neg_resp_failure_cb(p2p, success); -+ break; -+ case P2P_PENDING_GO_NEG_CONFIRM: -+ p2p_go_neg_conf_cb(p2p, result); -+ break; -+ case P2P_PENDING_SD: -+ p2p_sd_cb(p2p, success); -+ break; -+ case P2P_PENDING_PD: -+ p2p_prov_disc_cb(p2p, success); -+ break; -+ case P2P_PENDING_INVITATION_REQUEST: -+ p2p_invitation_req_cb(p2p, success); -+ break; -+ case P2P_PENDING_INVITATION_RESPONSE: -+ p2p_invitation_resp_cb(p2p, success); -+ break; -+ case P2P_PENDING_DEV_DISC_REQUEST: -+ p2p_dev_disc_req_cb(p2p, success); -+ break; -+ case P2P_PENDING_DEV_DISC_RESPONSE: -+ p2p_dev_disc_resp_cb(p2p, success); -+ break; -+ case P2P_PENDING_GO_DISC_REQ: -+ p2p_go_disc_req_cb(p2p, success); -+ break; -+ } -+} -+ -+ -+void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq, -+ unsigned int duration) -+{ -+ if (freq == p2p->pending_client_disc_freq) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Client discoverability remain-awake completed"); -+ p2p->pending_client_disc_freq = 0; -+ return; -+ } -+ -+ if (freq != p2p->pending_listen_freq) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected listen callback for freq=%u " -+ "duration=%u (pending_listen_freq=%u)", -+ freq, duration, p2p->pending_listen_freq); -+ return; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Starting Listen timeout(%u,%u) on freq=%u based on " -+ "callback", -+ p2p->pending_listen_sec, p2p->pending_listen_usec, -+ p2p->pending_listen_freq); -+ p2p->in_listen = 1; -+ p2p->drv_in_listen = freq; -+ if (p2p->pending_listen_sec || p2p->pending_listen_usec) { -+ /* -+ * Add 20 msec extra wait to avoid race condition with driver -+ * remain-on-channel end event, i.e., give driver more time to -+ * complete the operation before our timeout expires. -+ */ -+ p2p_set_timeout(p2p, p2p->pending_listen_sec, -+ p2p->pending_listen_usec + 20000); -+ } -+ -+ p2p->pending_listen_freq = 0; -+} -+ -+ -+int p2p_listen_end(struct p2p_data *p2p, unsigned int freq) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver ended Listen " -+ "state (freq=%u)", freq); -+ p2p->drv_in_listen = 0; -+ if (p2p->in_listen) -+ return 0; /* Internal timeout will trigger the next step */ -+ -+ if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) { -+ if (p2p->go_neg_peer->connect_reqs >= 120) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Timeout on sending GO Negotiation " -+ "Request without getting response"); -+ p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); -+ return 0; -+ } -+ -+ p2p_set_state(p2p, P2P_CONNECT); -+ p2p_connect_send(p2p, p2p->go_neg_peer); -+ return 1; -+ } else if (p2p->state == P2P_SEARCH) { -+ p2p_search(p2p); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void p2p_timeout_connect(struct p2p_data *p2p) -+{ -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p_set_state(p2p, P2P_CONNECT_LISTEN); -+ p2p_listen_in_find(p2p); -+} -+ -+ -+static void p2p_timeout_connect_listen(struct p2p_data *p2p) -+{ -+ if (p2p->go_neg_peer) { -+ if (p2p->drv_in_listen) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is " -+ "still in Listen state; wait for it to " -+ "complete"); -+ return; -+ } -+ -+ if (p2p->go_neg_peer->connect_reqs >= 120) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Timeout on sending GO Negotiation " -+ "Request without getting response"); -+ p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); -+ return; -+ } -+ -+ p2p_set_state(p2p, P2P_CONNECT); -+ p2p_connect_send(p2p, p2p->go_neg_peer); -+ } else -+ p2p_set_state(p2p, P2P_IDLE); -+} -+ -+ -+static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p) -+{ -+ /* -+ * TODO: could remain constantly in Listen state for some time if there -+ * are no other concurrent uses for the radio. For now, go to listen -+ * state once per second to give other uses a chance to use the radio. -+ */ -+ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); -+ p2p_set_timeout(p2p, 1, 0); -+} -+ -+ -+static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p) -+{ -+ struct p2p_device *dev = p2p->go_neg_peer; -+ -+ if (dev == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown GO Neg peer - stop GO Neg wait"); -+ return; -+ } -+ -+ dev->wait_count++; -+ if (dev->wait_count >= 120) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Timeout on waiting peer to become ready for GO " -+ "Negotiation"); -+ p2p_go_neg_failed(p2p, dev, -1); -+ return; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Go to Listen state while waiting for the peer to become " -+ "ready for GO Negotiation"); -+ p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT); -+ p2p_listen_in_find(p2p); -+} -+ -+ -+static void p2p_timeout_sd_during_find(struct p2p_data *p2p) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Service Discovery Query timeout"); -+ if (p2p->sd_peer) { -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; -+ p2p->sd_peer = NULL; -+ } -+ p2p_continue_find(p2p); -+} -+ -+ -+static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Provision Discovery Request timeout"); -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p_continue_find(p2p); -+} -+ -+ -+static void p2p_timeout_invite(struct p2p_data *p2p) -+{ -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p_set_state(p2p, P2P_INVITE_LISTEN); -+ if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) { -+ /* -+ * Better remain on operating channel instead of listen channel -+ * when running a group. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Inviting in " -+ "active GO role - wait on operating channel"); -+ p2p_set_timeout(p2p, 0, 100000); -+ return; -+ } -+ p2p_listen_in_find(p2p); -+} -+ -+ -+static void p2p_timeout_invite_listen(struct p2p_data *p2p) -+{ -+ if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) { -+ p2p_set_state(p2p, P2P_INVITE); -+ p2p_invite_send(p2p, p2p->invite_peer, -+ p2p->invite_go_dev_addr); -+ } else { -+ if (p2p->invite_peer) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invitation Request retry limit reached"); -+ if (p2p->cfg->invitation_result) -+ p2p->cfg->invitation_result( -+ p2p->cfg->cb_ctx, -1, NULL); -+ } -+ p2p_set_state(p2p, P2P_IDLE); -+ } -+} -+ -+ -+static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct p2p_data *p2p = eloop_ctx; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Timeout (state=%s)", -+ p2p_state_txt(p2p->state)); -+ -+ p2p->in_listen = 0; -+ -+ switch (p2p->state) { -+ case P2P_IDLE: -+ break; -+ case P2P_SEARCH: -+ p2p_search(p2p); -+ break; -+ case P2P_CONNECT: -+ p2p_timeout_connect(p2p); -+ break; -+ case P2P_CONNECT_LISTEN: -+ p2p_timeout_connect_listen(p2p); -+ break; -+ case P2P_GO_NEG: -+ break; -+ case P2P_LISTEN_ONLY: -+ if (p2p->ext_listen_only) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Extended Listen Timing - Listen State " -+ "completed"); -+ p2p->ext_listen_only = 0; -+ p2p_set_state(p2p, P2P_IDLE); -+ } -+ break; -+ case P2P_WAIT_PEER_CONNECT: -+ p2p_timeout_wait_peer_connect(p2p); -+ break; -+ case P2P_WAIT_PEER_IDLE: -+ p2p_timeout_wait_peer_idle(p2p); -+ break; -+ case P2P_SD_DURING_FIND: -+ p2p_timeout_sd_during_find(p2p); -+ break; -+ case P2P_PROVISIONING: -+ break; -+ case P2P_PD_DURING_FIND: -+ p2p_timeout_prov_disc_during_find(p2p); -+ break; -+ case P2P_INVITE: -+ p2p_timeout_invite(p2p); -+ break; -+ case P2P_INVITE_LISTEN: -+ p2p_timeout_invite_listen(p2p); -+ break; -+ } -+} -+ -+ -+int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr) -+{ -+ struct p2p_device *dev; -+ -+ dev = p2p_get_device(p2p, peer_addr); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Local request to reject " -+ "connection attempts by peer " MACSTR, MAC2STR(peer_addr)); -+ if (dev == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR -+ " unknown", MAC2STR(peer_addr)); -+ return -1; -+ } -+ dev->status = P2P_SC_FAIL_REJECTED_BY_USER; -+ dev->flags |= P2P_DEV_USER_REJECTED; -+ return 0; -+} -+ -+ -+static const char * p2p_wps_method_text(enum p2p_wps_method method) -+{ -+ switch (method) { -+ case WPS_NOT_READY: -+ return "not-ready"; -+ case WPS_PIN_LABEL: -+ return "Label"; -+ case WPS_PIN_DISPLAY: -+ return "Display"; -+ case WPS_PIN_KEYPAD: -+ return "Keypad"; -+ case WPS_PBC: -+ return "PBC"; -+ } -+ -+ return "??"; -+} -+ -+ -+static const char * p2p_go_state_text(enum p2p_go_state go_state) -+{ -+ switch (go_state) { -+ case UNKNOWN_GO: -+ return "unknown"; -+ case LOCAL_GO: -+ return "local"; -+ case REMOTE_GO: -+ return "remote"; -+ } -+ -+ return "??"; -+} -+ -+ -+int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, -+ char *buf, size_t buflen) -+{ -+ struct p2p_device *dev; -+ int res; -+ char *pos, *end; -+ struct os_time now; -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ -+ if (addr) -+ dev = p2p_get_device(p2p, addr); -+ else -+ dev = dl_list_first(&p2p->devices, struct p2p_device, list); -+ -+ if (dev && next) { -+ dev = dl_list_first(&dev->list, struct p2p_device, list); -+ if (&dev->list == &p2p->devices) -+ dev = NULL; -+ } -+ -+ if (dev == NULL) -+ return -1; -+ -+ pos = buf; -+ end = buf + buflen; -+ -+ res = os_snprintf(pos, end - pos, MACSTR "\n", -+ MAC2STR(dev->info.p2p_device_addr)); -+ if (res < 0 || res >= end - pos) -+ return pos - buf; -+ pos += res; -+ -+ os_get_time(&now); -+ res = os_snprintf(pos, end - pos, -+ "age=%d\n" -+ "listen_freq=%d\n" -+ "level=%d\n" -+ "wps_method=%s\n" -+ "interface_addr=" MACSTR "\n" -+ "member_in_go_dev=" MACSTR "\n" -+ "member_in_go_iface=" MACSTR "\n" -+ "pri_dev_type=%s\n" -+ "device_name=%s\n" -+ "manufacturer=%s\n" -+ "model_name=%s\n" -+ "model_number=%s\n" -+ "serial_number=%s\n" -+ "config_methods=0x%x\n" -+ "dev_capab=0x%x\n" -+ "group_capab=0x%x\n" -+ "go_neg_req_sent=%d\n" -+ "go_state=%s\n" -+ "dialog_token=%u\n" -+ "intended_addr=" MACSTR "\n" -+ "country=%c%c\n" -+ "oper_freq=%d\n" -+ "req_config_methods=0x%x\n" -+ "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n" -+ "status=%d\n" -+ "wait_count=%u\n" -+ "invitation_reqs=%u\n", -+ (int) (now.sec - dev->last_seen.sec), -+ dev->listen_freq, -+ dev->level, -+ p2p_wps_method_text(dev->wps_method), -+ MAC2STR(dev->interface_addr), -+ MAC2STR(dev->member_in_go_dev), -+ MAC2STR(dev->member_in_go_iface), -+ wps_dev_type_bin2str(dev->info.pri_dev_type, -+ devtype, sizeof(devtype)), -+ dev->info.device_name, -+ dev->info.manufacturer, -+ dev->info.model_name, -+ dev->info.model_number, -+ dev->info.serial_number, -+ dev->info.config_methods, -+ dev->info.dev_capab, -+ dev->info.group_capab, -+ dev->go_neg_req_sent, -+ p2p_go_state_text(dev->go_state), -+ dev->dialog_token, -+ MAC2STR(dev->intended_addr), -+ dev->country[0] ? dev->country[0] : '_', -+ dev->country[1] ? dev->country[1] : '_', -+ dev->oper_freq, -+ dev->req_config_methods, -+ dev->flags & P2P_DEV_PROBE_REQ_ONLY ? -+ "[PROBE_REQ_ONLY]" : "", -+ dev->flags & P2P_DEV_REPORTED ? "[REPORTED]" : "", -+ dev->flags & P2P_DEV_NOT_YET_READY ? -+ "[NOT_YET_READY]" : "", -+ dev->flags & P2P_DEV_SD_INFO ? "[SD_INFO]" : "", -+ dev->flags & P2P_DEV_SD_SCHEDULE ? "[SD_SCHEDULE]" : -+ "", -+ dev->flags & P2P_DEV_PD_PEER_DISPLAY ? -+ "[PD_PEER_DISPLAY]" : "", -+ dev->flags & P2P_DEV_PD_PEER_KEYPAD ? -+ "[PD_PEER_KEYPAD]" : "", -+ dev->flags & P2P_DEV_USER_REJECTED ? -+ "[USER_REJECTED]" : "", -+ dev->flags & P2P_DEV_PEER_WAITING_RESPONSE ? -+ "[PEER_WAITING_RESPONSE]" : "", -+ dev->flags & P2P_DEV_PREFER_PERSISTENT_GROUP ? -+ "[PREFER_PERSISTENT_GROUP]" : "", -+ dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE ? -+ "[WAIT_GO_NEG_RESPONSE]" : "", -+ dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM ? -+ "[WAIT_GO_NEG_CONFIRM]" : "", -+ dev->flags & P2P_DEV_GROUP_CLIENT_ONLY ? -+ "[GROUP_CLIENT_ONLY]" : "", -+ dev->flags & P2P_DEV_FORCE_FREQ ? -+ "[FORCE_FREQ]" : "", -+ dev->flags & P2P_DEV_PD_FOR_JOIN ? -+ "[PD_FOR_JOIN]" : "", -+ dev->status, -+ dev->wait_count, -+ dev->invitation_reqs); -+ if (res < 0 || res >= end - pos) -+ return pos - buf; -+ pos += res; -+ -+ if (dev->ext_listen_period) { -+ res = os_snprintf(pos, end - pos, -+ "ext_listen_period=%u\n" -+ "ext_listen_interval=%u\n", -+ dev->ext_listen_period, -+ dev->ext_listen_interval); -+ if (res < 0 || res >= end - pos) -+ return pos - buf; -+ pos += res; -+ } -+ -+ if (dev->oper_ssid_len) { -+ res = os_snprintf(pos, end - pos, -+ "oper_ssid=%s\n", -+ wpa_ssid_txt(dev->oper_ssid, -+ dev->oper_ssid_len)); -+ if (res < 0 || res >= end - pos) -+ return pos - buf; -+ pos += res; -+ } -+ -+ return pos - buf; -+} -+ -+ -+void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled) -+{ -+ if (enabled) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client " -+ "discoverability enabled"); -+ p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Client " -+ "discoverability disabled"); -+ p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY; -+ } -+} -+ -+ -+static struct wpabuf * p2p_build_presence_req(u32 duration1, u32 interval1, -+ u32 duration2, u32 interval2) -+{ -+ struct wpabuf *req; -+ struct p2p_noa_desc desc1, desc2, *ptr1 = NULL, *ptr2 = NULL; -+ u8 *len; -+ -+ req = wpabuf_alloc(100); -+ if (req == NULL) -+ return NULL; -+ -+ if (duration1 || interval1) { -+ os_memset(&desc1, 0, sizeof(desc1)); -+ desc1.count_type = 1; -+ desc1.duration = duration1; -+ desc1.interval = interval1; -+ ptr1 = &desc1; -+ -+ if (duration2 || interval2) { -+ os_memset(&desc2, 0, sizeof(desc2)); -+ desc2.count_type = 2; -+ desc2.duration = duration2; -+ desc2.interval = interval2; -+ ptr2 = &desc2; -+ } -+ } -+ -+ p2p_buf_add_action_hdr(req, P2P_PRESENCE_REQ, 1); -+ len = p2p_buf_add_ie_hdr(req); -+ p2p_buf_add_noa(req, 0, 0, 0, ptr1, ptr2); -+ p2p_buf_update_ie_hdr(req, len); -+ -+ return req; -+} -+ -+ -+int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr, -+ const u8 *own_interface_addr, unsigned int freq, -+ u32 duration1, u32 interval1, u32 duration2, -+ u32 interval2) -+{ -+ struct wpabuf *req; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send Presence Request to " -+ "GO " MACSTR " (own interface " MACSTR ") freq=%u dur1=%u " -+ "int1=%u dur2=%u int2=%u", -+ MAC2STR(go_interface_addr), MAC2STR(own_interface_addr), -+ freq, duration1, interval1, duration2, interval2); -+ -+ req = p2p_build_presence_req(duration1, interval1, duration2, -+ interval2); -+ if (req == NULL) -+ return -1; -+ -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ if (p2p_send_action(p2p, freq, go_interface_addr, own_interface_addr, -+ go_interface_addr, -+ wpabuf_head(req), wpabuf_len(req), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ } -+ wpabuf_free(req); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * p2p_build_presence_resp(u8 status, const u8 *noa, -+ size_t noa_len, u8 dialog_token) -+{ -+ struct wpabuf *resp; -+ u8 *len; -+ -+ resp = wpabuf_alloc(100 + noa_len); -+ if (resp == NULL) -+ return NULL; -+ -+ p2p_buf_add_action_hdr(resp, P2P_PRESENCE_RESP, dialog_token); -+ len = p2p_buf_add_ie_hdr(resp); -+ p2p_buf_add_status(resp, status); -+ if (noa) { -+ wpabuf_put_u8(resp, P2P_ATTR_NOTICE_OF_ABSENCE); -+ wpabuf_put_le16(resp, noa_len); -+ wpabuf_put_data(resp, noa, noa_len); -+ } else -+ p2p_buf_add_noa(resp, 0, 0, 0, NULL, NULL); -+ p2p_buf_update_ie_hdr(resp, len); -+ -+ return resp; -+} -+ -+ -+static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da, -+ const u8 *sa, const u8 *data, size_t len, -+ int rx_freq) -+{ -+ struct p2p_message msg; -+ u8 status; -+ struct wpabuf *resp; -+ size_t g; -+ struct p2p_group *group = NULL; -+ int parsed = 0; -+ u8 noa[50]; -+ int noa_len; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received P2P Action - P2P Presence Request"); -+ -+ for (g = 0; g < p2p->num_groups; g++) { -+ if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]), -+ ETH_ALEN) == 0) { -+ group = p2p->groups[g]; -+ break; -+ } -+ } -+ if (group == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore P2P Presence Request for unknown group " -+ MACSTR, MAC2STR(da)); -+ return; -+ } -+ -+ if (p2p_parse(data, len, &msg) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to parse P2P Presence Request"); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ parsed = 1; -+ -+ if (msg.noa == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No NoA attribute in P2P Presence Request"); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ -+ status = p2p_group_presence_req(group, sa, msg.noa, msg.noa_len); -+ -+fail: -+ if (p2p->cfg->get_noa) -+ noa_len = p2p->cfg->get_noa(p2p->cfg->cb_ctx, da, noa, -+ sizeof(noa)); -+ else -+ noa_len = -1; -+ resp = p2p_build_presence_resp(status, noa_len > 0 ? noa : NULL, -+ noa_len > 0 ? noa_len : 0, -+ msg.dialog_token); -+ if (parsed) -+ p2p_parse_free(&msg); -+ if (resp == NULL) -+ return; -+ -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ if (p2p_send_action(p2p, rx_freq, sa, da, da, -+ wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ } -+ wpabuf_free(resp); -+} -+ -+ -+static void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da, -+ const u8 *sa, const u8 *data, size_t len) -+{ -+ struct p2p_message msg; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received P2P Action - P2P Presence Response"); -+ -+ if (p2p_parse(data, len, &msg) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to parse P2P Presence Response"); -+ return; -+ } -+ -+ if (msg.status == NULL || msg.noa == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Status or NoA attribute in P2P Presence " -+ "Response"); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (*msg.status) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: P2P Presence Request was rejected: status %u", -+ *msg.status); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: P2P Presence Request was accepted"); -+ wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA", -+ msg.noa, msg.noa_len); -+ /* TODO: process NoA */ -+ p2p_parse_free(&msg); -+} -+ -+ -+static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct p2p_data *p2p = eloop_ctx; -+ -+ if (p2p->ext_listen_interval) { -+ /* Schedule next extended listen timeout */ -+ eloop_register_timeout(p2p->ext_listen_interval_sec, -+ p2p->ext_listen_interval_usec, -+ p2p_ext_listen_timeout, p2p, NULL); -+ } -+ -+ if (p2p->state == P2P_LISTEN_ONLY && p2p->ext_listen_only) { -+ /* -+ * This should not really happen, but it looks like the Listen -+ * command may fail is something else (e.g., a scan) was -+ * running at an inconvenient time. As a workaround, allow new -+ * Extended Listen operation to be started. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Previous " -+ "Extended Listen operation had not been completed - " -+ "try again"); -+ p2p->ext_listen_only = 0; -+ p2p_set_state(p2p, P2P_IDLE); -+ } -+ -+ if (p2p->state != P2P_IDLE) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip Extended " -+ "Listen timeout in active state (%s)", -+ p2p_state_txt(p2p->state)); -+ return; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Extended Listen timeout"); -+ p2p->ext_listen_only = 1; -+ if (p2p_listen(p2p, p2p->ext_listen_period) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start " -+ "Listen state for Extended Listen Timing"); -+ p2p->ext_listen_only = 0; -+ } -+} -+ -+ -+int p2p_ext_listen(struct p2p_data *p2p, unsigned int period, -+ unsigned int interval) -+{ -+ if (period > 65535 || interval > 65535 || period > interval || -+ (period == 0 && interval > 0) || (period > 0 && interval == 0)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid Extended Listen Timing request: " -+ "period=%u interval=%u", period, interval); -+ return -1; -+ } -+ -+ eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL); -+ -+ if (interval == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Disabling Extended Listen Timing"); -+ p2p->ext_listen_period = 0; -+ p2p->ext_listen_interval = 0; -+ return 0; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Enabling Extended Listen Timing: period %u msec, " -+ "interval %u msec", period, interval); -+ p2p->ext_listen_period = period; -+ p2p->ext_listen_interval = interval; -+ p2p->ext_listen_interval_sec = interval / 1000; -+ p2p->ext_listen_interval_usec = (interval % 1000) * 1000; -+ -+ eloop_register_timeout(p2p->ext_listen_interval_sec, -+ p2p->ext_listen_interval_usec, -+ p2p_ext_listen_timeout, p2p, NULL); -+ -+ return 0; -+} -+ -+ -+void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, -+ const u8 *ie, size_t ie_len) -+{ -+ struct p2p_message msg; -+ -+ if (bssid == NULL || ie == NULL) -+ return; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_ies(ie, ie_len, &msg)) -+ return; -+ if (msg.minor_reason_code == NULL) -+ return; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, -+ "P2P: Deauthentication notification BSSID " MACSTR -+ " reason_code=%u minor_reason_code=%u", -+ MAC2STR(bssid), reason_code, *msg.minor_reason_code); -+ -+ p2p_parse_free(&msg); -+} -+ -+ -+void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, -+ const u8 *ie, size_t ie_len) -+{ -+ struct p2p_message msg; -+ -+ if (bssid == NULL || ie == NULL) -+ return; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_ies(ie, ie_len, &msg)) -+ return; -+ if (msg.minor_reason_code == NULL) -+ return; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, -+ "P2P: Disassociation notification BSSID " MACSTR -+ " reason_code=%u minor_reason_code=%u", -+ MAC2STR(bssid), reason_code, *msg.minor_reason_code); -+ -+ p2p_parse_free(&msg); -+} -+ -+ -+void p2p_set_managed_oper(struct p2p_data *p2p, int enabled) -+{ -+ if (enabled) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P " -+ "Device operations enabled"); -+ p2p->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED; -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Managed P2P " -+ "Device operations disabled"); -+ p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED; -+ } -+} -+ -+ -+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel) -+{ -+ if (p2p_channel_to_freq(p2p->cfg->country, reg_class, channel) < 0) -+ return -1; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set Listen channel: " -+ "reg_class %u channel %u", reg_class, channel); -+ p2p->cfg->reg_class = reg_class; -+ p2p->cfg->channel = channel; -+ -+ return 0; -+} -+ -+ -+int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len) -+{ -+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: New SSID postfix", postfix, len); -+ if (postfix == NULL) { -+ p2p->cfg->ssid_postfix_len = 0; -+ return 0; -+ } -+ if (len > sizeof(p2p->cfg->ssid_postfix)) -+ return -1; -+ os_memcpy(p2p->cfg->ssid_postfix, postfix, len); -+ p2p->cfg->ssid_postfix_len = len; -+ return 0; -+} -+ -+ -+int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, -+ u8 *iface_addr) -+{ -+ struct p2p_device *dev = p2p_get_device(p2p, dev_addr); -+ if (dev == NULL || is_zero_ether_addr(dev->interface_addr)) -+ return -1; -+ os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, -+ u8 *dev_addr) -+{ -+ struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr); -+ if (dev == NULL) -+ return -1; -+ os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN); -+ return 0; -+} -+ -+ -+void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr) -+{ -+ os_memcpy(p2p->peer_filter, addr, ETH_ALEN); -+ if (is_zero_ether_addr(p2p->peer_filter)) -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Disable peer " -+ "filter"); -+ else -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Enable peer " -+ "filter for " MACSTR, MAC2STR(p2p->peer_filter)); -+} -+ -+ -+void p2p_set_cross_connect(struct p2p_data *p2p, int enabled) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Cross connection %s", -+ enabled ? "enabled" : "disabled"); -+ if (p2p->cross_connect == enabled) -+ return; -+ p2p->cross_connect = enabled; -+ /* TODO: may need to tear down any action group where we are GO(?) */ -+} -+ -+ -+int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr) -+{ -+ struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr); -+ if (dev == NULL) -+ return -1; -+ if (dev->oper_freq <= 0) -+ return -1; -+ return dev->oper_freq; -+} -+ -+ -+void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Intra BSS distribution %s", -+ enabled ? "enabled" : "disabled"); -+ p2p->cfg->p2p_intra_bss = enabled; -+} -+ -+ -+void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Update channel list"); -+ os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels)); -+} -+ -+ -+int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, -+ const u8 *src, const u8 *bssid, const u8 *buf, -+ size_t len, unsigned int wait_time) -+{ -+ if (p2p->p2p_scan_running) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay Action " -+ "frame TX until p2p_scan completes"); -+ if (p2p->after_scan_tx) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dropped " -+ "previous pending Action frame TX"); -+ os_free(p2p->after_scan_tx); -+ } -+ p2p->after_scan_tx = os_malloc(sizeof(*p2p->after_scan_tx) + -+ len); -+ if (p2p->after_scan_tx == NULL) -+ return -1; -+ p2p->after_scan_tx->freq = freq; -+ os_memcpy(p2p->after_scan_tx->dst, dst, ETH_ALEN); -+ os_memcpy(p2p->after_scan_tx->src, src, ETH_ALEN); -+ os_memcpy(p2p->after_scan_tx->bssid, bssid, ETH_ALEN); -+ p2p->after_scan_tx->len = len; -+ p2p->after_scan_tx->wait_time = wait_time; -+ os_memcpy(p2p->after_scan_tx + 1, buf, len); -+ return 0; -+ } -+ -+ return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid, -+ buf, len, wait_time); -+} -+ -+ -+void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, -+ int freq_overall) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Best channel: 2.4 GHz: %d," -+ " 5 GHz: %d, overall: %d", freq_24, freq_5, freq_overall); -+ p2p->best_freq_24 = freq_24; -+ p2p->best_freq_5 = freq_5; -+ p2p->best_freq_overall = freq_overall; -+} -+ -+ -+const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p) -+{ -+ if (p2p == NULL || p2p->go_neg_peer == NULL) -+ return NULL; -+ return p2p->go_neg_peer->info.p2p_device_addr; -+} -+ -+ -+const struct p2p_peer_info * -+p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next) -+{ -+ struct p2p_device *dev; -+ -+ if (addr) { -+ dev = p2p_get_device(p2p, addr); -+ if (!dev) -+ return NULL; -+ -+ if (!next) { -+ if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) -+ return NULL; -+ -+ return &dev->info; -+ } else { -+ do { -+ dev = dl_list_first(&dev->list, -+ struct p2p_device, -+ list); -+ if (&dev->list == &p2p->devices) -+ return NULL; -+ } while (dev->flags & P2P_DEV_PROBE_REQ_ONLY); -+ } -+ } else { -+ dev = dl_list_first(&p2p->devices, struct p2p_device, list); -+ if (!dev) -+ return NULL; -+ while (dev->flags & P2P_DEV_PROBE_REQ_ONLY) { -+ dev = dl_list_first(&dev->list, -+ struct p2p_device, -+ list); -+ if (&dev->list == &p2p->devices) -+ return NULL; -+ } -+ } -+ -+ return &dev->info; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.h -new file mode 100644 -index 0000000000000..954f562bf1ec2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p.h -@@ -0,0 +1,1473 @@ -+/* -+ * Wi-Fi Direct - P2P module -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef P2P_H -+#define P2P_H -+ -+/** -+ * P2P_MAX_REG_CLASSES - Maximum number of regulatory classes -+ */ -+#define P2P_MAX_REG_CLASSES 10 -+ -+/** -+ * P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class -+ */ -+#define P2P_MAX_REG_CLASS_CHANNELS 20 -+ -+/** -+ * struct p2p_channels - List of supported channels -+ */ -+struct p2p_channels { -+ /** -+ * struct p2p_reg_class - Supported regulatory class -+ */ -+ struct p2p_reg_class { -+ /** -+ * reg_class - Regulatory class (IEEE 802.11-2007, Annex J) -+ */ -+ u8 reg_class; -+ -+ /** -+ * channel - Supported channels -+ */ -+ u8 channel[P2P_MAX_REG_CLASS_CHANNELS]; -+ -+ /** -+ * channels - Number of channel entries in use -+ */ -+ size_t channels; -+ } reg_class[P2P_MAX_REG_CLASSES]; -+ -+ /** -+ * reg_classes - Number of reg_class entries in use -+ */ -+ size_t reg_classes; -+}; -+ -+enum p2p_wps_method { -+ WPS_NOT_READY, WPS_PIN_LABEL, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC -+}; -+ -+/** -+ * struct p2p_go_neg_results - P2P Group Owner Negotiation results -+ */ -+struct p2p_go_neg_results { -+ /** -+ * status - Negotiation result (Status Code) -+ * -+ * 0 (P2P_SC_SUCCESS) indicates success. Non-zero values indicate -+ * failed negotiation. -+ */ -+ int status; -+ -+ /** -+ * role_go - Whether local end is Group Owner -+ */ -+ int role_go; -+ -+ /** -+ * freq - Frequency of the group operational channel in MHz -+ */ -+ int freq; -+ -+ /** -+ * ssid - SSID of the group -+ */ -+ u8 ssid[32]; -+ -+ /** -+ * ssid_len - Length of SSID in octets -+ */ -+ size_t ssid_len; -+ -+ /** -+ * passphrase - WPA2-Personal passphrase for the group (GO only) -+ */ -+ char passphrase[64]; -+ -+ /** -+ * peer_device_addr - P2P Device Address of the peer -+ */ -+ u8 peer_device_addr[ETH_ALEN]; -+ -+ /** -+ * peer_interface_addr - P2P Interface Address of the peer -+ */ -+ u8 peer_interface_addr[ETH_ALEN]; -+ -+ /** -+ * wps_method - WPS method to be used during provisioning -+ */ -+ enum p2p_wps_method wps_method; -+ -+#define P2P_MAX_CHANNELS 50 -+ -+ /** -+ * freq_list - Zero-terminated list of possible operational channels -+ */ -+ int freq_list[P2P_MAX_CHANNELS]; -+ -+ /** -+ * persistent_group - Whether the group should be made persistent -+ */ -+ int persistent_group; -+ -+ /** -+ * peer_config_timeout - Peer configuration timeout (in 10 msec units) -+ */ -+ unsigned int peer_config_timeout; -+}; -+ -+struct p2p_data; -+ -+enum p2p_scan_type { -+ P2P_SCAN_SOCIAL, -+ P2P_SCAN_FULL, -+ P2P_SCAN_SPECIFIC, -+ P2P_SCAN_SOCIAL_PLUS_ONE -+}; -+ -+#define P2P_MAX_WPS_VENDOR_EXT 10 -+ -+/** -+ * struct p2p_peer_info - P2P peer information -+ */ -+struct p2p_peer_info { -+ /** -+ * p2p_device_addr - P2P Device Address of the peer -+ */ -+ u8 p2p_device_addr[ETH_ALEN]; -+ -+ /** -+ * pri_dev_type - Primary Device Type -+ */ -+ u8 pri_dev_type[8]; -+ -+ /** -+ * device_name - Device Name (0..32 octets encoded in UTF-8) -+ */ -+ char device_name[33]; -+ -+ /** -+ * manufacturer - Manufacturer (0..64 octets encoded in UTF-8) -+ */ -+ char manufacturer[65]; -+ -+ /** -+ * model_name - Model Name (0..32 octets encoded in UTF-8) -+ */ -+ char model_name[33]; -+ -+ /** -+ * model_number - Model Number (0..32 octets encoded in UTF-8) -+ */ -+ char model_number[33]; -+ -+ /** -+ * serial_number - Serial Number (0..32 octets encoded in UTF-8) -+ */ -+ char serial_number[33]; -+ -+ /** -+ * config_methods - WPS Configuration Methods -+ */ -+ u16 config_methods; -+ -+ /** -+ * dev_capab - Device Capabilities -+ */ -+ u8 dev_capab; -+ -+ /** -+ * group_capab - Group Capabilities -+ */ -+ u8 group_capab; -+ -+ /** -+ * wps_sec_dev_type_list - WPS secondary device type list -+ * -+ * This list includes from 0 to 16 Secondary Device Types as indicated -+ * by wps_sec_dev_type_list_len (8 * number of types). -+ */ -+ u8 wps_sec_dev_type_list[128]; -+ -+ /** -+ * wps_sec_dev_type_list_len - Length of secondary device type list -+ */ -+ size_t wps_sec_dev_type_list_len; -+ -+ struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; -+}; -+ -+/** -+ * struct p2p_config - P2P configuration -+ * -+ * This configuration is provided to the P2P module during initialization with -+ * p2p_init(). -+ */ -+struct p2p_config { -+ /** -+ * country - Country code to use in P2P operations -+ */ -+ char country[3]; -+ -+ /** -+ * reg_class - Regulatory class for own listen channel -+ */ -+ u8 reg_class; -+ -+ /** -+ * channel - Own listen channel -+ */ -+ u8 channel; -+ -+ /** -+ * Regulatory class for own operational channel -+ */ -+ u8 op_reg_class; -+ -+ /** -+ * op_channel - Own operational channel -+ */ -+ u8 op_channel; -+ -+ /** -+ * cfg_op_channel - Whether op_channel is hardcoded in configuration -+ */ -+ u8 cfg_op_channel; -+ -+ /** -+ * channels - Own supported regulatory classes and channels -+ * -+ * List of supposerted channels per regulatory class. The regulatory -+ * classes are defined in IEEE Std 802.11-2007 Annex J and the -+ * numbering of the clases depends on the configured country code. -+ */ -+ struct p2p_channels channels; -+ -+ /** -+ * pri_dev_type - Primary Device Type (see WPS) -+ */ -+ u8 pri_dev_type[8]; -+ -+ /** -+ * P2P_SEC_DEVICE_TYPES - Maximum number of secondary device types -+ */ -+#define P2P_SEC_DEVICE_TYPES 5 -+ -+ /** -+ * sec_dev_type - Optional secondary device types -+ */ -+ u8 sec_dev_type[P2P_SEC_DEVICE_TYPES][8]; -+ -+ /** -+ * num_sec_dev_types - Number of sec_dev_type entries -+ */ -+ size_t num_sec_dev_types; -+ -+ /** -+ * dev_addr - P2P Device Address -+ */ -+ u8 dev_addr[ETH_ALEN]; -+ -+ /** -+ * dev_name - Device Name -+ */ -+ char *dev_name; -+ -+ char *manufacturer; -+ char *model_name; -+ char *model_number; -+ char *serial_number; -+ -+ u8 uuid[16]; -+ u16 config_methods; -+ -+ /** -+ * concurrent_operations - Whether concurrent operations are supported -+ */ -+ int concurrent_operations; -+ -+ /** -+ * max_peers - Maximum number of discovered peers to remember -+ * -+ * If more peers are discovered, older entries will be removed to make -+ * room for the new ones. -+ */ -+ size_t max_peers; -+ -+ /** -+ * p2p_intra_bss - Intra BSS communication is supported -+ */ -+ int p2p_intra_bss; -+ -+ /** -+ * ssid_postfix - Postfix data to add to the SSID -+ * -+ * This data will be added to the end of the SSID after the -+ * DIRECT- prefix. -+ */ -+ u8 ssid_postfix[32 - 9]; -+ -+ /** -+ * ssid_postfix_len - Length of the ssid_postfix data -+ */ -+ size_t ssid_postfix_len; -+ -+ /** -+ * msg_ctx - Context to use with wpa_msg() calls -+ */ -+ void *msg_ctx; -+ -+ /** -+ * cb_ctx - Context to use with callback functions -+ */ -+ void *cb_ctx; -+ -+ -+ /* Callbacks to request lower layer driver operations */ -+ -+ /** -+ * p2p_scan - Request a P2P scan/search -+ * @ctx: Callback context from cb_ctx -+ * @type: Scan type -+ * @freq: Specific frequency (MHz) to scan or 0 for no restriction -+ * @num_req_dev_types: Number of requested device types -+ * @req_dev_types: Array containing requested device types -+ * Returns: 0 on success, -1 on failure -+ * -+ * This callback function is used to request a P2P scan or search -+ * operation to be completed. Type type argument specifies which type -+ * of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the -+ * social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL -+ * indicates that all channels are to be scanned. @P2P_SCAN_SPECIFIC -+ * request a scan of a single channel specified by freq. -+ * @P2P_SCAN_SOCIAL_PLUS_ONE request scan of all the social channels -+ * plus one extra channel specified by freq. -+ * -+ * The full scan is used for the initial scan to find group owners from -+ * all. The other types are used during search phase scan of the social -+ * channels (with potential variation if the Listen channel of the -+ * target peer is known or if other channels are scanned in steps). -+ * -+ * The scan results are returned after this call by calling -+ * p2p_scan_res_handler() for each scan result that has a P2P IE and -+ * then calling p2p_scan_res_handled() to indicate that all scan -+ * results have been indicated. -+ */ -+ int (*p2p_scan)(void *ctx, enum p2p_scan_type type, int freq, -+ unsigned int num_req_dev_types, -+ const u8 *req_dev_types); -+ -+ /** -+ * send_probe_resp - Transmit a Probe Response frame -+ * @ctx: Callback context from cb_ctx -+ * @buf: Probe Response frame (including the header and body) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to reply to Probe Request frames that were -+ * indicated with a call to p2p_probe_req_rx(). The response is to be -+ * sent on the same channel or to be dropped if the driver is not -+ * anymore listening to Probe Request frames. -+ * -+ * Alternatively, the responsibility for building the Probe Response -+ * frames in Listen state may be in another system component in which -+ * case this function need to be implemented (i.e., the function -+ * pointer can be %NULL). The WPS and P2P IEs to be added for Probe -+ * Response frames in such a case are available from the -+ * start_listen() callback. It should be noted that the received Probe -+ * Request frames must be indicated by calling p2p_probe_req_rx() even -+ * if this send_probe_resp() is not used. -+ */ -+ int (*send_probe_resp)(void *ctx, const struct wpabuf *buf); -+ -+ /** -+ * send_action - Transmit an Action frame -+ * @ctx: Callback context from cb_ctx -+ * @freq: Frequency in MHz for the channel on which to transmit -+ * @dst: Destination MAC address (Address 1) -+ * @src: Source MAC address (Address 2) -+ * @bssid: BSSID (Address 3) -+ * @buf: Frame body (starting from Category field) -+ * @len: Length of buf in octets -+ * @wait_time: How many msec to wait for a response frame -+ * Returns: 0 on success, -1 on failure -+ * -+ * The Action frame may not be transmitted immediately and the status -+ * of the transmission must be reported by calling -+ * p2p_send_action_cb() once the frame has either been transmitted or -+ * it has been dropped due to excessive retries or other failure to -+ * transmit. -+ */ -+ int (*send_action)(void *ctx, unsigned int freq, const u8 *dst, -+ const u8 *src, const u8 *bssid, const u8 *buf, -+ size_t len, unsigned int wait_time); -+ -+ /** -+ * send_action_done - Notify that Action frame sequence was completed -+ * @ctx: Callback context from cb_ctx -+ * -+ * This function is called when the Action frame sequence that was -+ * started with send_action() has been completed, i.e., when there is -+ * no need to wait for a response from the destination peer anymore. -+ */ -+ void (*send_action_done)(void *ctx); -+ -+ /** -+ * start_listen - Start Listen state -+ * @ctx: Callback context from cb_ctx -+ * @freq: Frequency of the listen channel in MHz -+ * @duration: Duration for the Listen state in milliseconds -+ * @probe_resp_ie: IE(s) to be added to Probe Response frames -+ * Returns: 0 on success, -1 on failure -+ * -+ * This Listen state may not start immediately since the driver may -+ * have other pending operations to complete first. Once the Listen -+ * state has started, p2p_listen_cb() must be called to notify the P2P -+ * module. Once the Listen state is stopped, p2p_listen_end() must be -+ * called to notify the P2P module that the driver is not in the Listen -+ * state anymore. -+ * -+ * If the send_probe_resp() is not used for generating the response, -+ * the IEs from probe_resp_ie need to be added to the end of the Probe -+ * Response frame body. If send_probe_resp() is used, the probe_resp_ie -+ * information can be ignored. -+ */ -+ int (*start_listen)(void *ctx, unsigned int freq, -+ unsigned int duration, -+ const struct wpabuf *probe_resp_ie); -+ /** -+ * stop_listen - Stop Listen state -+ * @ctx: Callback context from cb_ctx -+ * -+ * This callback can be used to stop a Listen state operation that was -+ * previously requested with start_listen(). -+ */ -+ void (*stop_listen)(void *ctx); -+ -+ /** -+ * get_noa - Get current Notice of Absence attribute payload -+ * @ctx: Callback context from cb_ctx -+ * @interface_addr: P2P Interface Address of the GO -+ * @buf: Buffer for returning NoA -+ * @buf_len: Buffer length in octets -+ * Returns: Number of octets used in buf, 0 to indicate no NoA is being -+ * advertized, or -1 on failure -+ * -+ * This function is used to fetch the current Notice of Absence -+ * attribute value from GO. -+ */ -+ int (*get_noa)(void *ctx, const u8 *interface_addr, u8 *buf, -+ size_t buf_len); -+ -+ /* Callbacks to notify events to upper layer management entity */ -+ -+ /** -+ * dev_found - Notification of a found P2P Device -+ * @ctx: Callback context from cb_ctx -+ * @addr: Source address of the message triggering this notification -+ * @info: P2P peer information -+ * @new_device: Inform if the peer is newly found -+ * -+ * This callback is used to notify that a new P2P Device has been -+ * found. This may happen, e.g., during Search state based on scan -+ * results or during Listen state based on receive Probe Request and -+ * Group Owner Negotiation Request. -+ */ -+ void (*dev_found)(void *ctx, const u8 *addr, -+ const struct p2p_peer_info *info, -+ int new_device); -+ -+ /** -+ * dev_lost - Notification of a lost P2P Device -+ * @ctx: Callback context from cb_ctx -+ * @dev_addr: P2P Device Address of the lost P2P Device -+ * -+ * This callback is used to notify that a P2P Device has been deleted. -+ */ -+ void (*dev_lost)(void *ctx, const u8 *dev_addr); -+ -+ /** -+ * go_neg_req_rx - Notification of a receive GO Negotiation Request -+ * @ctx: Callback context from cb_ctx -+ * @src: Source address of the message triggering this notification -+ * @dev_passwd_id: WPS Device Password ID -+ * -+ * This callback is used to notify that a P2P Device is requesting -+ * group owner negotiation with us, but we do not have all the -+ * necessary information to start GO Negotiation. This indicates that -+ * the local user has not authorized the connection yet by providing a -+ * PIN or PBC button press. This information can be provided with a -+ * call to p2p_connect(). -+ */ -+ void (*go_neg_req_rx)(void *ctx, const u8 *src, u16 dev_passwd_id); -+ -+ /** -+ * go_neg_completed - Notification of GO Negotiation results -+ * @ctx: Callback context from cb_ctx -+ * @res: GO Negotiation results -+ * -+ * This callback is used to notify that Group Owner Negotiation has -+ * been completed. Non-zero struct p2p_go_neg_results::status indicates -+ * failed negotiation. In case of success, this function is responsible -+ * for creating a new group interface (or using the existing interface -+ * depending on driver features), setting up the group interface in -+ * proper mode based on struct p2p_go_neg_results::role_go and -+ * initializing WPS provisioning either as a Registrar (if GO) or as an -+ * Enrollee. Successful WPS provisioning must be indicated by calling -+ * p2p_wps_success_cb(). The callee is responsible for timing out group -+ * formation if WPS provisioning cannot be completed successfully -+ * within 15 seconds. -+ */ -+ void (*go_neg_completed)(void *ctx, struct p2p_go_neg_results *res); -+ -+ /** -+ * sd_request - Callback on Service Discovery Request -+ * @ctx: Callback context from cb_ctx -+ * @freq: Frequency (in MHz) of the channel -+ * @sa: Source address of the request -+ * @dialog_token: Dialog token -+ * @update_indic: Service Update Indicator from the source of request -+ * @tlvs: P2P Service Request TLV(s) -+ * @tlvs_len: Length of tlvs buffer in octets -+ * -+ * This callback is used to indicate reception of a service discovery -+ * request. Response to the query must be indicated by calling -+ * p2p_sd_response() with the context information from the arguments to -+ * this callback function. -+ * -+ * This callback handler can be set to %NULL to indicate that service -+ * discovery is not supported. -+ */ -+ void (*sd_request)(void *ctx, int freq, const u8 *sa, u8 dialog_token, -+ u16 update_indic, const u8 *tlvs, size_t tlvs_len); -+ -+ /** -+ * sd_response - Callback on Service Discovery Response -+ * @ctx: Callback context from cb_ctx -+ * @sa: Source address of the request -+ * @update_indic: Service Update Indicator from the source of response -+ * @tlvs: P2P Service Response TLV(s) -+ * @tlvs_len: Length of tlvs buffer in octets -+ * -+ * This callback is used to indicate reception of a service discovery -+ * response. This callback handler can be set to %NULL if no service -+ * discovery requests are used. The information provided with this call -+ * is replies to the queries scheduled with p2p_sd_request(). -+ */ -+ void (*sd_response)(void *ctx, const u8 *sa, u16 update_indic, -+ const u8 *tlvs, size_t tlvs_len); -+ -+ /** -+ * prov_disc_req - Callback on Provisiong Discovery Request -+ * @ctx: Callback context from cb_ctx -+ * @peer: Source address of the request -+ * @config_methods: Requested WPS Config Method -+ * @dev_addr: P2P Device Address of the found P2P Device -+ * @pri_dev_type: Primary Device Type -+ * @dev_name: Device Name -+ * @supp_config_methods: Supported configuration Methods -+ * @dev_capab: Device Capabilities -+ * @group_capab: Group Capabilities -+ * -+ * This callback is used to indicate reception of a Provision Discovery -+ * Request frame that the P2P module accepted. -+ */ -+ void (*prov_disc_req)(void *ctx, const u8 *peer, u16 config_methods, -+ const u8 *dev_addr, const u8 *pri_dev_type, -+ const char *dev_name, u16 supp_config_methods, -+ u8 dev_capab, u8 group_capab); -+ -+ /** -+ * prov_disc_resp - Callback on Provisiong Discovery Response -+ * @ctx: Callback context from cb_ctx -+ * @peer: Source address of the response -+ * @config_methods: Value from p2p_prov_disc_req() or 0 on failure -+ * -+ * This callback is used to indicate reception of a Provision Discovery -+ * Response frame for a pending request scheduled with -+ * p2p_prov_disc_req(). This callback handler can be set to %NULL if -+ * provision discovery is not used. -+ */ -+ void (*prov_disc_resp)(void *ctx, const u8 *peer, u16 config_methods); -+ -+ /** -+ * invitation_process - Optional callback for processing Invitations -+ * @ctx: Callback context from cb_ctx -+ * @sa: Source address of the Invitation Request -+ * @bssid: P2P Group BSSID from the request or %NULL if not included -+ * @go_dev_addr: GO Device Address from P2P Group ID -+ * @ssid: SSID from P2P Group ID -+ * @ssid_len: Length of ssid buffer in octets -+ * @go: Variable for returning whether the local end is GO in the group -+ * @group_bssid: Buffer for returning P2P Group BSSID (if local end GO) -+ * @force_freq: Variable for returning forced frequency for the group -+ * @persistent_group: Whether this is an invitation to reinvoke a -+ * persistent group (instead of invitation to join an active -+ * group) -+ * Returns: Status code (P2P_SC_*) -+ * -+ * This optional callback can be used to implement persistent reconnect -+ * by allowing automatic restarting of persistent groups without user -+ * interaction. If this callback is not implemented (i.e., is %NULL), -+ * the received Invitation Request frames are replied with -+ * %P2P_SC_REQ_RECEIVED status and indicated to upper layer with the -+ * invitation_result() callback. -+ * -+ * If the requested parameters are acceptable and the group is known, -+ * %P2P_SC_SUCCESS may be returned. If the requested group is unknown, -+ * %P2P_SC_FAIL_UNKNOWN_GROUP should be returned. %P2P_SC_REQ_RECEIVED -+ * can be returned if there is not enough data to provide immediate -+ * response, i.e., if some sort of user interaction is needed. The -+ * invitation_received() callback will be called in that case -+ * immediately after this call. -+ */ -+ u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid, -+ const u8 *go_dev_addr, const u8 *ssid, -+ size_t ssid_len, int *go, u8 *group_bssid, -+ int *force_freq, int persistent_group); -+ -+ /** -+ * invitation_received - Callback on Invitation Request RX -+ * @ctx: Callback context from cb_ctx -+ * @sa: Source address of the Invitation Request -+ * @bssid: P2P Group BSSID or %NULL if not received -+ * @ssid: SSID of the group -+ * @ssid_len: Length of ssid in octets -+ * @go_dev_addr: GO Device Address -+ * @status: Response Status -+ * @op_freq: Operational frequency for the group -+ * -+ * This callback is used to indicate sending of an Invitation Response -+ * for a received Invitation Request. If status == 0 (success), the -+ * upper layer code is responsible for starting the group. status == 1 -+ * indicates need to get user authorization for the group. Other status -+ * values indicate that the invitation request was rejected. -+ */ -+ void (*invitation_received)(void *ctx, const u8 *sa, const u8 *bssid, -+ const u8 *ssid, size_t ssid_len, -+ const u8 *go_dev_addr, u8 status, -+ int op_freq); -+ -+ /** -+ * invitation_result - Callback on Invitation result -+ * @ctx: Callback context from cb_ctx -+ * @status: Negotiation result (Status Code) -+ * @bssid: P2P Group BSSID or %NULL if not received -+ * -+ * This callback is used to indicate result of an Invitation procedure -+ * started with a call to p2p_invite(). The indicated status code is -+ * the value received from the peer in Invitation Response with 0 -+ * (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a -+ * local failure in transmitting the Invitation Request. -+ */ -+ void (*invitation_result)(void *ctx, int status, const u8 *bssid); -+}; -+ -+ -+/* P2P module initialization/deinitialization */ -+ -+/** -+ * p2p_init - Initialize P2P module -+ * @cfg: P2P module configuration -+ * Returns: Pointer to private data or %NULL on failure -+ * -+ * This function is used to initialize global P2P module context (one per -+ * device). The P2P module will keep a copy of the configuration data, so the -+ * caller does not need to maintain this structure. However, the callback -+ * functions and the context parameters to them must be kept available until -+ * the P2P module is deinitialized with p2p_deinit(). -+ */ -+struct p2p_data * p2p_init(const struct p2p_config *cfg); -+ -+/** -+ * p2p_deinit - Deinitialize P2P module -+ * @p2p: P2P module context from p2p_init() -+ */ -+void p2p_deinit(struct p2p_data *p2p); -+ -+/** -+ * p2p_flush - Flush P2P module state -+ * @p2p: P2P module context from p2p_init() -+ * -+ * This command removes the P2P module state like peer device entries. -+ */ -+void p2p_flush(struct p2p_data *p2p); -+ -+/** -+ * p2p_unauthorize - Unauthorize the specified peer device -+ * @p2p: P2P module context from p2p_init() -+ * @addr: P2P peer entry to be unauthorized -+ * Returns: 0 on success, -1 on failure -+ * -+ * This command removes any connection authorization from the specified P2P -+ * peer device address. This can be used, e.g., to cancel effect of a previous -+ * p2p_authorize() or p2p_connect() call that has not yet resulted in completed -+ * GO Negotiation. -+ */ -+int p2p_unauthorize(struct p2p_data *p2p, const u8 *addr); -+ -+/** -+ * p2p_set_dev_name - Set device name -+ * @p2p: P2P module context from p2p_init() -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to update the P2P module configuration with -+ * information that was not available at the time of the p2p_init() call. -+ */ -+int p2p_set_dev_name(struct p2p_data *p2p, const char *dev_name); -+ -+int p2p_set_manufacturer(struct p2p_data *p2p, const char *manufacturer); -+int p2p_set_model_name(struct p2p_data *p2p, const char *model_name); -+int p2p_set_model_number(struct p2p_data *p2p, const char *model_number); -+int p2p_set_serial_number(struct p2p_data *p2p, const char *serial_number); -+ -+void p2p_set_config_methods(struct p2p_data *p2p, u16 config_methods); -+void p2p_set_uuid(struct p2p_data *p2p, const u8 *uuid); -+ -+/** -+ * p2p_set_pri_dev_type - Set primary device type -+ * @p2p: P2P module context from p2p_init() -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to update the P2P module configuration with -+ * information that was not available at the time of the p2p_init() call. -+ */ -+int p2p_set_pri_dev_type(struct p2p_data *p2p, const u8 *pri_dev_type); -+ -+/** -+ * p2p_set_sec_dev_types - Set secondary device types -+ * @p2p: P2P module context from p2p_init() -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to update the P2P module configuration with -+ * information that was not available at the time of the p2p_init() call. -+ */ -+int p2p_set_sec_dev_types(struct p2p_data *p2p, const u8 dev_types[][8], -+ size_t num_dev_types); -+ -+int p2p_set_country(struct p2p_data *p2p, const char *country); -+ -+ -+/* Commands from upper layer management entity */ -+ -+enum p2p_discovery_type { -+ P2P_FIND_START_WITH_FULL, -+ P2P_FIND_ONLY_SOCIAL, -+ P2P_FIND_PROGRESSIVE -+}; -+ -+/** -+ * p2p_find - Start P2P Find (Device Discovery) -+ * @p2p: P2P module context from p2p_init() -+ * @timeout: Timeout for find operation in seconds or 0 for no timeout -+ * @type: Device Discovery type -+ * @num_req_dev_types: Number of requested device types -+ * @req_dev_types: Requested device types array, must be an array -+ * containing num_req_dev_types * WPS_DEV_TYPE_LEN bytes; %NULL if no -+ * requested device types. -+ * Returns: 0 on success, -1 on failure -+ */ -+int p2p_find(struct p2p_data *p2p, unsigned int timeout, -+ enum p2p_discovery_type type, -+ unsigned int num_req_dev_types, const u8 *req_dev_types); -+ -+/** -+ * p2p_stop_find - Stop P2P Find (Device Discovery) -+ * @p2p: P2P module context from p2p_init() -+ */ -+void p2p_stop_find(struct p2p_data *p2p); -+ -+/** -+ * p2p_stop_find_for_freq - Stop P2P Find for next oper on specific freq -+ * @p2p: P2P module context from p2p_init() -+ * @freq: Frequency in MHz for next operation -+ * -+ * This is like p2p_stop_find(), but Listen state is not stopped if we are -+ * already on the same frequency. -+ */ -+void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq); -+ -+/** -+ * p2p_listen - Start P2P Listen state for specified duration -+ * @p2p: P2P module context from p2p_init() -+ * @timeout: Listen state duration in milliseconds -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to request the P2P module to keep the device -+ * discoverable on the listen channel for an extended set of time. At least in -+ * its current form, this is mainly used for testing purposes and may not be of -+ * much use for normal P2P operations. -+ */ -+int p2p_listen(struct p2p_data *p2p, unsigned int timeout); -+ -+/** -+ * p2p_connect - Start P2P group formation (GO negotiation) -+ * @p2p: P2P module context from p2p_init() -+ * @peer_addr: MAC address of the peer P2P client -+ * @wps_method: WPS method to be used in provisioning -+ * @go_intent: Local GO intent value (1..15) -+ * @own_interface_addr: Intended interface address to use with the group -+ * @force_freq: The only allowed channel frequency in MHz or 0 -+ * @persistent_group: Whether to create a persistent group -+ * Returns: 0 on success, -1 on failure -+ */ -+int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, -+ enum p2p_wps_method wps_method, -+ int go_intent, const u8 *own_interface_addr, -+ unsigned int force_freq, int persistent_group); -+ -+/** -+ * p2p_authorize - Authorize P2P group formation (GO negotiation) -+ * @p2p: P2P module context from p2p_init() -+ * @peer_addr: MAC address of the peer P2P client -+ * @wps_method: WPS method to be used in provisioning -+ * @go_intent: Local GO intent value (1..15) -+ * @own_interface_addr: Intended interface address to use with the group -+ * @force_freq: The only allowed channel frequency in MHz or 0 -+ * @persistent_group: Whether to create a persistent group -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is like p2p_connect(), but the actual group negotiation is not -+ * initiated automatically, i.e., the other end is expected to do that. -+ */ -+int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, -+ enum p2p_wps_method wps_method, -+ int go_intent, const u8 *own_interface_addr, -+ unsigned int force_freq, int persistent_group); -+ -+/** -+ * p2p_reject - Reject peer device (explicitly block connection attempts) -+ * @p2p: P2P module context from p2p_init() -+ * @peer_addr: MAC address of the peer P2P client -+ * Returns: 0 on success, -1 on failure -+ */ -+int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr); -+ -+/** -+ * p2p_prov_disc_req - Send Provision Discovery Request -+ * @p2p: P2P module context from p2p_init() -+ * @peer_addr: MAC address of the peer P2P client -+ * @config_methods: WPS Config Methods value (only one bit set) -+ * @join: Whether this is used by a client joining an active group -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to request a discovered P2P peer to display a PIN -+ * (config_methods = WPS_CONFIG_DISPLAY) or be prepared to enter a PIN from us -+ * (config_methods = WPS_CONFIG_KEYPAD). The Provision Discovery Request frame -+ * is transmitted once immediately and if no response is received, the frame -+ * will be sent again whenever the target device is discovered during device -+ * dsicovery (start with a p2p_find() call). Response from the peer is -+ * indicated with the p2p_config::prov_disc_resp() callback. -+ */ -+int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, -+ u16 config_methods, int join); -+ -+/** -+ * p2p_sd_request - Schedule a service discovery query -+ * @p2p: P2P module context from p2p_init() -+ * @dst: Destination peer or %NULL to apply for all peers -+ * @tlvs: P2P Service Query TLV(s) -+ * Returns: Reference to the query or %NULL on failure -+ * -+ * Response to the query is indicated with the p2p_config::sd_response() -+ * callback. -+ */ -+void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst, -+ const struct wpabuf *tlvs); -+ -+/** -+ * p2p_sd_cancel_request - Cancel a pending service discovery query -+ * @p2p: P2P module context from p2p_init() -+ * @req: Query reference from p2p_sd_request() -+ * Returns: 0 if request for cancelled; -1 if not found -+ */ -+int p2p_sd_cancel_request(struct p2p_data *p2p, void *req); -+ -+/** -+ * p2p_sd_response - Send response to a service discovery query -+ * @p2p: P2P module context from p2p_init() -+ * @freq: Frequency from p2p_config::sd_request() callback -+ * @dst: Destination address from p2p_config::sd_request() callback -+ * @dialog_token: Dialog token from p2p_config::sd_request() callback -+ * @resp_tlvs: P2P Service Response TLV(s) -+ * -+ * This function is called as a response to the request indicated with -+ * p2p_config::sd_request() callback. -+ */ -+void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst, -+ u8 dialog_token, const struct wpabuf *resp_tlvs); -+ -+/** -+ * p2p_sd_service_update - Indicate a change in local services -+ * @p2p: P2P module context from p2p_init() -+ * -+ * This function needs to be called whenever there is a change in availability -+ * of the local services. This will increment the Service Update Indicator -+ * value which will be used in SD Request and Response frames. -+ */ -+void p2p_sd_service_update(struct p2p_data *p2p); -+ -+ -+enum p2p_invite_role { -+ P2P_INVITE_ROLE_GO, -+ P2P_INVITE_ROLE_ACTIVE_GO, -+ P2P_INVITE_ROLE_CLIENT -+}; -+ -+/** -+ * p2p_invite - Invite a P2P Device into a group -+ * @p2p: P2P module context from p2p_init() -+ * @peer: Device Address of the peer P2P Device -+ * @role: Local role in the group -+ * @bssid: Group BSSID or %NULL if not known -+ * @ssid: Group SSID -+ * @ssid_len: Length of ssid in octets -+ * @force_freq: The only allowed channel frequency in MHz or 0 -+ * @go_dev_addr: Forced GO Device Address or %NULL if none -+ * @persistent_group: Whether this is to reinvoke a persistent group -+ * Returns: 0 on success, -1 on failure -+ */ -+int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, -+ const u8 *bssid, const u8 *ssid, size_t ssid_len, -+ unsigned int force_freq, const u8 *go_dev_addr, -+ int persistent_group); -+ -+/** -+ * p2p_presence_req - Request GO presence -+ * @p2p: P2P module context from p2p_init() -+ * @go_interface_addr: GO P2P Interface Address -+ * @own_interface_addr: Own P2P Interface Address for this group -+ * @freq: Group operating frequence (in MHz) -+ * @duration1: Preferred presence duration in microseconds -+ * @interval1: Preferred presence interval in microseconds -+ * @duration2: Acceptable presence duration in microseconds -+ * @interval2: Acceptable presence interval in microseconds -+ * Returns: 0 on success, -1 on failure -+ * -+ * If both duration and interval values are zero, the parameter pair is not -+ * specified (i.e., to remove Presence Request, use duration1 = interval1 = 0). -+ */ -+int p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr, -+ const u8 *own_interface_addr, unsigned int freq, -+ u32 duration1, u32 interval1, u32 duration2, -+ u32 interval2); -+ -+/** -+ * p2p_ext_listen - Set Extended Listen Timing -+ * @p2p: P2P module context from p2p_init() -+ * @freq: Group operating frequence (in MHz) -+ * @period: Availability period in milliseconds (1-65535; 0 to disable) -+ * @interval: Availability interval in milliseconds (1-65535; 0 to disable) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function can be used to enable or disable (period = interval = 0) -+ * Extended Listen Timing. When enabled, the P2P Device will become -+ * discoverable (go into Listen State) every @interval milliseconds for at -+ * least @period milliseconds. -+ */ -+int p2p_ext_listen(struct p2p_data *p2p, unsigned int period, -+ unsigned int interval); -+ -+/* Event notifications from upper layer management operations */ -+ -+/** -+ * p2p_wps_success_cb - Report successfully completed WPS provisioning -+ * @p2p: P2P module context from p2p_init() -+ * @mac_addr: Peer address -+ * -+ * This function is used to report successfully completed WPS provisioning -+ * during group formation in both GO/Registrar and client/Enrollee roles. -+ */ -+void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr); -+ -+/** -+ * p2p_group_formation_failed - Report failed WPS provisioning -+ * @p2p: P2P module context from p2p_init() -+ * -+ * This function is used to report failed group formation. This can happen -+ * either due to failed WPS provisioning or due to 15 second timeout during -+ * the provisioning phase. -+ */ -+void p2p_group_formation_failed(struct p2p_data *p2p); -+ -+ -+/* Event notifications from lower layer driver operations */ -+ -+/** -+ * p2p_probe_req_rx - Report reception of a Probe Request frame -+ * @p2p: P2P module context from p2p_init() -+ * @addr: Source MAC address -+ * @ie: Information elements from the Probe Request frame body -+ * @ie_len: Length of ie buffer in octets -+ * Returns: 0 to indicate the frame was not processed or 1 if it was -+ */ -+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie, -+ size_t ie_len); -+ -+/** -+ * p2p_rx_action - Report received Action frame -+ * @p2p: P2P module context from p2p_init() -+ * @da: Destination address of the received Action frame -+ * @sa: Source address of the received Action frame -+ * @bssid: Address 3 of the received Action frame -+ * @category: Category of the received Action frame -+ * @data: Action frame body after the Category field -+ * @len: Length of the data buffer in octets -+ * @freq: Frequency (in MHz) on which the frame was received -+ */ -+void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, -+ const u8 *bssid, u8 category, -+ const u8 *data, size_t len, int freq); -+ -+/** -+ * p2p_scan_res_handler - Indicate a P2P scan results -+ * @p2p: P2P module context from p2p_init() -+ * @bssid: BSSID of the scan result -+ * @freq: Frequency of the channel on which the device was found in MHz -+ * @level: Signal level (signal strength of the received Beacon/Probe Response -+ * frame) -+ * @ies: Pointer to IEs from the scan result -+ * @ies_len: Length of the ies buffer -+ * Returns: 0 to continue or 1 to stop scan result indication -+ * -+ * This function is called to indicate a scan result entry with P2P IE from a -+ * scan requested with struct p2p_config::p2p_scan(). This can be called during -+ * the actual scan process (i.e., whenever a new device is found) or as a -+ * sequence of calls after the full scan has been completed. The former option -+ * can result in optimized operations, but may not be supported by all -+ * driver/firmware designs. The ies buffer need to include at least the P2P IE, -+ * but it is recommended to include all IEs received from the device. The -+ * caller does not need to check that the IEs contain a P2P IE before calling -+ * this function since frames will be filtered internally if needed. -+ * -+ * This function will return 1 if it wants to stop scan result iteration (and -+ * scan in general if it is still in progress). This is used to allow faster -+ * start of a pending operation, e.g., to start a pending GO negotiation. -+ */ -+int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq, -+ int level, const u8 *ies, size_t ies_len); -+ -+/** -+ * p2p_scan_res_handled - Indicate end of scan results -+ * @p2p: P2P module context from p2p_init() -+ * -+ * This function is called to indicate that all P2P scan results from a scan -+ * have been reported with zero or more calls to p2p_scan_res_handler(). This -+ * function must be called as a response to successful -+ * struct p2p_config::p2p_scan() call if none of the p2p_scan_res_handler() -+ * calls stopped iteration. -+ */ -+void p2p_scan_res_handled(struct p2p_data *p2p); -+ -+enum p2p_send_action_result { -+ P2P_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */, -+ P2P_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged */, -+ P2P_SEND_ACTION_FAILED /* Frame was not sent due to a failure */ -+}; -+ -+/** -+ * p2p_send_action_cb - Notify TX status of an Action frame -+ * @p2p: P2P module context from p2p_init() -+ * @freq: Channel frequency in MHz -+ * @dst: Destination MAC address (Address 1) -+ * @src: Source MAC address (Address 2) -+ * @bssid: BSSID (Address 3) -+ * @result: Result of the transmission attempt -+ * -+ * This function is used to indicate the result of an Action frame transmission -+ * that was requested with struct p2p_config::send_action() callback. -+ */ -+void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst, -+ const u8 *src, const u8 *bssid, -+ enum p2p_send_action_result result); -+ -+/** -+ * p2p_listen_cb - Indicate the start of a requested Listen state -+ * @p2p: P2P module context from p2p_init() -+ * @freq: Listen channel frequency in MHz -+ * @duration: Duration for the Listen state in milliseconds -+ * -+ * This function is used to indicate that a Listen state requested with -+ * struct p2p_config::start_listen() callback has started. -+ */ -+void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq, -+ unsigned int duration); -+ -+/** -+ * p2p_listen_end - Indicate the end of a requested Listen state -+ * @p2p: P2P module context from p2p_init() -+ * @freq: Listen channel frequency in MHz -+ * Returns: 0 if no operations were started, 1 if an operation was started -+ * -+ * This function is used to indicate that a Listen state requested with -+ * struct p2p_config::start_listen() callback has ended. -+ */ -+int p2p_listen_end(struct p2p_data *p2p, unsigned int freq); -+ -+void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, -+ const u8 *ie, size_t ie_len); -+ -+void p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code, -+ const u8 *ie, size_t ie_len); -+ -+ -+/* Per-group P2P state for GO */ -+ -+struct p2p_group; -+ -+/** -+ * struct p2p_group_config - P2P group configuration -+ * -+ * This configuration is provided to the P2P module during initialization of -+ * the per-group information with p2p_group_init(). -+ */ -+struct p2p_group_config { -+ /** -+ * persistent_group - Whether the group is persistent -+ */ -+ int persistent_group; -+ -+ /** -+ * interface_addr - P2P Interface Address of the group -+ */ -+ u8 interface_addr[ETH_ALEN]; -+ -+ /** -+ * max_clients - Maximum number of clients in the group -+ */ -+ unsigned int max_clients; -+ -+ /** -+ * cb_ctx - Context to use with callback functions -+ */ -+ void *cb_ctx; -+ -+ /** -+ * ie_update - Notification of IE update -+ * @ctx: Callback context from cb_ctx -+ * @beacon_ies: P2P IE for Beacon frames or %NULL if no change -+ * @proberesp_ies: P2P Ie for Probe Response frames -+ * -+ * P2P module uses this callback function to notify whenever the P2P IE -+ * in Beacon or Probe Response frames should be updated based on group -+ * events. -+ * -+ * The callee is responsible for freeing the returned buffer(s) with -+ * wpabuf_free(). -+ */ -+ void (*ie_update)(void *ctx, struct wpabuf *beacon_ies, -+ struct wpabuf *proberesp_ies); -+ -+ /** -+ * idle_update - Notification of changes in group idle state -+ * @ctx: Callback context from cb_ctx -+ * @idle: Whether the group is idle (no associated stations) -+ */ -+ void (*idle_update)(void *ctx, int idle); -+}; -+ -+/** -+ * p2p_group_init - Initialize P2P group -+ * @p2p: P2P module context from p2p_init() -+ * @config: P2P group configuration (will be freed by p2p_group_deinit()) -+ * Returns: Pointer to private data or %NULL on failure -+ * -+ * This function is used to initialize per-group P2P module context. Currently, -+ * this is only used to manage GO functionality and P2P clients do not need to -+ * create an instance of this per-group information. -+ */ -+struct p2p_group * p2p_group_init(struct p2p_data *p2p, -+ struct p2p_group_config *config); -+ -+/** -+ * p2p_group_deinit - Deinitialize P2P group -+ * @group: P2P group context from p2p_group_init() -+ */ -+void p2p_group_deinit(struct p2p_group *group); -+ -+/** -+ * p2p_group_notif_assoc - Notification of P2P client association with GO -+ * @group: P2P group context from p2p_group_init() -+ * @addr: Interface address of the P2P client -+ * @ie: IEs from the (Re)association Request frame -+ * @len: Length of the ie buffer in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, -+ const u8 *ie, size_t len); -+ -+/** -+ * p2p_group_assoc_resp_ie - Build P2P IE for (re)association response -+ * @group: P2P group context from p2p_group_init() -+ * @status: Status value (P2P_SC_SUCCESS if association succeeded) -+ * Returns: P2P IE for (Re)association Response or %NULL on failure -+ * -+ * The caller is responsible for freeing the returned buffer with -+ * wpabuf_free(). -+ */ -+struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status); -+ -+/** -+ * p2p_group_notif_disassoc - Notification of P2P client disassociation from GO -+ * @group: P2P group context from p2p_group_init() -+ * @addr: Interface address of the P2P client -+ */ -+void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr); -+ -+/** -+ * p2p_group_notif_formation_done - Notification of completed group formation -+ * @group: P2P group context from p2p_group_init() -+ */ -+void p2p_group_notif_formation_done(struct p2p_group *group); -+ -+/** -+ * p2p_group_notif_noa - Notification of NoA change -+ * @group: P2P group context from p2p_group_init() -+ * @noa: Notice of Absence attribute payload, %NULL if none -+ * @noa_len: Length of noa buffer in octets -+ * Returns: 0 on success, -1 on failure -+ * -+ * Notify the P2P group management about a new NoA contents. This will be -+ * inserted into the P2P IEs in Beacon and Probe Response frames with rest of -+ * the group information. -+ */ -+int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, -+ size_t noa_len); -+ -+/** -+ * p2p_group_match_dev_type - Match device types in group with requested type -+ * @group: P2P group context from p2p_group_init() -+ * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs) -+ * Returns: 1 on match, 0 on mismatch -+ * -+ * This function can be used to match the Requested Device Type attribute in -+ * WPS IE with the device types of a group member for deciding whether a GO -+ * should reply to a Probe Request frame. Match will be reported if the WPS IE -+ * is not requested any specific device type. -+ */ -+int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps); -+ -+/** -+ * p2p_group_go_discover - Send GO Discoverability Request to a group client -+ * @group: P2P group context from p2p_group_init() -+ * Returns: 0 on success (frame scheduled); -1 if client was not found -+ */ -+int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, -+ const u8 *searching_dev, int rx_freq); -+ -+ -+/* Generic helper functions */ -+ -+/** -+ * p2p_ie_text - Build text format description of P2P IE -+ * @p2p_ie: P2P IE -+ * @buf: Buffer for returning text -+ * @end: Pointer to the end of the buf area -+ * Returns: Number of octets written to the buffer or -1 on failure -+ * -+ * This function can be used to parse P2P IE contents into text format -+ * field=value lines. -+ */ -+int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end); -+ -+/** -+ * p2p_scan_result_text - Build text format description of P2P IE -+ * @ies: Information elements from scan results -+ * @ies_len: ies buffer length in octets -+ * @buf: Buffer for returning text -+ * @end: Pointer to the end of the buf area -+ * Returns: Number of octets written to the buffer or -1 on failure -+ * -+ * This function can be used to parse P2P IE contents into text format -+ * field=value lines. -+ */ -+int p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end); -+ -+/** -+ * p2p_assoc_req_ie - Build P2P IE for (Re)Association Request frame -+ * @p2p: P2P module context from p2p_init() -+ * @bssid: BSSID -+ * @buf: Buffer for writing the P2P IE -+ * @len: Maximum buf length in octets -+ * @p2p_group: Whether this is for association with a P2P GO -+ * @p2p_ie: Reassembled P2P IE data from scan results or %NULL if none -+ * Returns: Number of octets written into buf or -1 on failure -+ */ -+int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, -+ size_t len, int p2p_group, struct wpabuf *p2p_ie); -+ -+/** -+ * p2p_scan_ie - Build P2P IE for Probe Request -+ * @p2p: P2P module context from p2p_init() -+ * @ies: Buffer for writing P2P IE -+ */ -+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies); -+ -+/** -+ * p2p_go_params - Generate random P2P group parameters -+ * @p2p: P2P module context from p2p_init() -+ * @params: Buffer for parameters -+ * Returns: 0 on success, -1 on failure -+ */ -+int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params); -+ -+/** -+ * p2p_get_group_capab - Get Group Capability from P2P IE data -+ * @p2p_ie: P2P IE(s) contents -+ * Returns: Group Capability -+ */ -+u8 p2p_get_group_capab(const struct wpabuf *p2p_ie); -+ -+/** -+ * p2p_get_cross_connect_disallowed - Does WLAN AP disallows cross connection -+ * @p2p_ie: P2P IE(s) contents -+ * Returns: 0 if cross connection is allow, 1 if not -+ */ -+int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie); -+ -+/** -+ * p2p_get_go_dev_addr - Get P2P Device Address from P2P IE data -+ * @p2p_ie: P2P IE(s) contents -+ * Returns: Pointer to P2P Device Address or %NULL if not included -+ */ -+const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie); -+ -+/** -+ * p2p_get_peer_info - Get P2P peer information in text format -+ * @p2p: P2P module context from p2p_init() -+ * @addr: P2P Device Address of the peer or %NULL to indicate the first peer -+ * @next: Whether to select the peer entry following the one indicated by addr -+ * @buf: Buffer for returning text -+ * @buflen: Maximum buffer length -+ * Returns: Number of octets written to the buffer or -1 on failure -+ */ -+int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next, -+ char *buf, size_t buflen); -+ -+/** -+ * p2p_set_client_discoverability - Set client discoverability capability -+ * @p2p: P2P module context from p2p_init() -+ * @enabled: Whether client discoverability will be enabled -+ * -+ * This function can be used to disable (and re-enable) client discoverability. -+ * This capability is enabled by default and should not be disabled in normal -+ * use cases, i.e., this is mainly for testing purposes. -+ */ -+void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled); -+ -+/** -+ * p2p_set_manageD_oper - Set managed P2P Device operations capability -+ * @p2p: P2P module context from p2p_init() -+ * @enabled: Whether managed P2P Device operations will be enabled -+ */ -+void p2p_set_managed_oper(struct p2p_data *p2p, int enabled); -+ -+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel); -+ -+int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len); -+ -+int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, -+ u8 *iface_addr); -+int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, -+ u8 *dev_addr); -+ -+void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr); -+ -+/** -+ * p2p_set_cross_connect - Set cross connection capability -+ * @p2p: P2P module context from p2p_init() -+ * @enabled: Whether cross connection will be enabled -+ */ -+void p2p_set_cross_connect(struct p2p_data *p2p, int enabled); -+ -+int p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr); -+ -+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, -+ const u8 *ies, size_t ies_len); -+ -+/** -+ * p2p_set_intra_bss_dist - Set intra BSS distribution -+ * @p2p: P2P module context from p2p_init() -+ * @enabled: Whether intra BSS distribution will be enabled -+ */ -+void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled); -+ -+/** -+ * p2p_supported_freq - Check whether channel is supported for P2P -+ * @p2p: P2P module context from p2p_init() -+ * @freq: Channel frequency in MHz -+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P -+ */ -+int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq); -+ -+void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan); -+ -+/** -+ * p2p_set_best_channels - Update best channel information -+ * @p2p: P2P module context from p2p_init() -+ * @freq_24: Frequency (MHz) of best channel in 2.4 GHz band -+ * @freq_5: Frequency (MHz) of best channel in 5 GHz band -+ * @freq_overall: Frequency (MHz) of best channel overall -+ */ -+void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, -+ int freq_overall); -+ -+const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p); -+ -+/** -+ * p2p_get_group_num_members - Get number of members in group -+ * @group: P2P group context from p2p_group_init() -+ * Returns: Number of members in the group -+ */ -+unsigned int p2p_get_group_num_members(struct p2p_group *group); -+ -+/** -+ * p2p_iterate_group_members - Iterate group members -+ * @group: P2P group context from p2p_group_init() -+ * @next: iteration pointer, must be a pointer to a void * that is set to %NULL -+ * on the first call and not modified later -+ * Returns: A P2P Interface Address for each call and %NULL for no more members -+ */ -+const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next); -+ -+/** -+ * p2p_get_peer_found - Get P2P peer info structure of a found peer -+ * @p2p: P2P module context from p2p_init() -+ * @addr: P2P Device Address of the peer or %NULL to indicate the first peer -+ * @next: Whether to select the peer entry following the one indicated by addr -+ * Returns: The first P2P peer info available or %NULL if no such peer exists -+ */ -+const struct p2p_peer_info * -+p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next); -+ -+/** -+ * p2p_remove_wps_vendor_extensions - Remove WPS vendor extensions -+ * @p2p: P2P module context from p2p_init() -+ */ -+void p2p_remove_wps_vendor_extensions(struct p2p_data *p2p); -+ -+/** -+ * p2p_add_wps_vendor_extension - Add a WPS vendor extension -+ * @p2p: P2P module context from p2p_init() -+ * @vendor_ext: The vendor extensions to add -+ * Returns: 0 on success, -1 on failure -+ * -+ * The wpabuf structures in the array are owned by the P2P -+ * module after this call. -+ */ -+int p2p_add_wps_vendor_extension(struct p2p_data *p2p, -+ const struct wpabuf *vendor_ext); -+ -+#endif /* P2P_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_build.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_build.c -new file mode 100644 -index 0000000000000..c34db91521625 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_build.c -@@ -0,0 +1,431 @@ -+/* -+ * P2P - IE builder -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "wps/wps_i.h" -+#include "p2p_i.h" -+ -+ -+void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token) -+{ -+ wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC); -+ wpabuf_put_be24(buf, OUI_WFA); -+ wpabuf_put_u8(buf, P2P_OUI_TYPE); -+ -+ wpabuf_put_u8(buf, subtype); /* OUI Subtype */ -+ wpabuf_put_u8(buf, dialog_token); -+ wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); -+} -+ -+ -+void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, -+ u8 dialog_token) -+{ -+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); -+ wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC); -+ wpabuf_put_be24(buf, OUI_WFA); -+ wpabuf_put_u8(buf, P2P_OUI_TYPE); -+ -+ wpabuf_put_u8(buf, subtype); /* OUI Subtype */ -+ wpabuf_put_u8(buf, dialog_token); -+ wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token); -+} -+ -+ -+u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf) -+{ -+ u8 *len; -+ -+ /* P2P IE header */ -+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); -+ len = wpabuf_put(buf, 1); /* IE length to be filled */ -+ wpabuf_put_be24(buf, OUI_WFA); -+ wpabuf_put_u8(buf, P2P_OUI_TYPE); -+ wpa_printf(MSG_DEBUG, "P2P: * P2P IE header"); -+ return len; -+} -+ -+ -+void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len) -+{ -+ /* Update P2P IE Length */ -+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1; -+} -+ -+ -+void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab) -+{ -+ /* P2P Capability */ -+ wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY); -+ wpabuf_put_le16(buf, 2); -+ wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */ -+ wpabuf_put_u8(buf, group_capab); /* Group Capabilities */ -+ wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x", -+ dev_capab, group_capab); -+} -+ -+ -+void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent) -+{ -+ /* Group Owner Intent */ -+ wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT); -+ wpabuf_put_le16(buf, 1); -+ wpabuf_put_u8(buf, go_intent); -+ wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u", -+ go_intent >> 1, go_intent & 0x01); -+} -+ -+ -+void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, -+ u8 reg_class, u8 channel) -+{ -+ /* Listen Channel */ -+ wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL); -+ wpabuf_put_le16(buf, 5); -+ wpabuf_put_data(buf, country, 3); -+ wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ -+ wpabuf_put_u8(buf, channel); /* Channel Number */ -+ wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u " -+ "Channel %u", reg_class, channel); -+} -+ -+ -+void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, -+ u8 reg_class, u8 channel) -+{ -+ /* Operating Channel */ -+ wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL); -+ wpabuf_put_le16(buf, 5); -+ wpabuf_put_data(buf, country, 3); -+ wpabuf_put_u8(buf, reg_class); /* Regulatory Class */ -+ wpabuf_put_u8(buf, channel); /* Channel Number */ -+ wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u " -+ "Channel %u", reg_class, channel); -+} -+ -+ -+void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, -+ struct p2p_channels *chan) -+{ -+ u8 *len; -+ size_t i; -+ -+ /* Channel List */ -+ wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST); -+ len = wpabuf_put(buf, 2); /* IE length to be filled */ -+ wpabuf_put_data(buf, country, 3); /* Country String */ -+ -+ for (i = 0; i < chan->reg_classes; i++) { -+ struct p2p_reg_class *c = &chan->reg_class[i]; -+ wpabuf_put_u8(buf, c->reg_class); -+ wpabuf_put_u8(buf, c->channels); -+ wpabuf_put_data(buf, c->channel, c->channels); -+ } -+ -+ /* Update attribute length */ -+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); -+ wpa_printf(MSG_DEBUG, "P2P: * Channel List"); -+} -+ -+ -+void p2p_buf_add_status(struct wpabuf *buf, u8 status) -+{ -+ /* Status */ -+ wpabuf_put_u8(buf, P2P_ATTR_STATUS); -+ wpabuf_put_le16(buf, 1); -+ wpabuf_put_u8(buf, status); -+ wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status); -+} -+ -+ -+void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, -+ struct p2p_device *peer) -+{ -+ u8 *len; -+ u16 methods; -+ size_t nlen, i; -+ -+ /* P2P Device Info */ -+ wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO); -+ len = wpabuf_put(buf, 2); /* IE length to be filled */ -+ -+ /* P2P Device address */ -+ wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); -+ -+ /* Config Methods */ -+ methods = 0; -+ if (peer && peer->wps_method != WPS_NOT_READY) { -+ if (peer->wps_method == WPS_PBC) -+ methods |= WPS_CONFIG_PUSHBUTTON; -+ else if (peer->wps_method == WPS_PIN_LABEL) -+ methods |= WPS_CONFIG_LABEL; -+ else if (peer->wps_method == WPS_PIN_DISPLAY || -+ peer->wps_method == WPS_PIN_KEYPAD) -+ methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; -+ } else { -+ methods |= WPS_CONFIG_PUSHBUTTON; -+ methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; -+ } -+ wpabuf_put_be16(buf, methods); -+ -+ /* Primary Device Type */ -+ wpabuf_put_data(buf, p2p->cfg->pri_dev_type, -+ sizeof(p2p->cfg->pri_dev_type)); -+ -+ /* Number of Secondary Device Types */ -+ wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types); -+ -+ /* Secondary Device Type List */ -+ for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) -+ wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i], -+ WPS_DEV_TYPE_LEN); -+ -+ /* Device Name */ -+ nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0; -+ wpabuf_put_be16(buf, ATTR_DEV_NAME); -+ wpabuf_put_be16(buf, nlen); -+ wpabuf_put_data(buf, p2p->cfg->dev_name, nlen); -+ -+ /* Update attribute length */ -+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); -+ wpa_printf(MSG_DEBUG, "P2P: * Device Info"); -+} -+ -+ -+void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr) -+{ -+ /* P2P Device ID */ -+ wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID); -+ wpabuf_put_le16(buf, ETH_ALEN); -+ wpabuf_put_data(buf, dev_addr, ETH_ALEN); -+ wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr)); -+} -+ -+ -+void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, -+ u8 client_timeout) -+{ -+ /* Configuration Timeout */ -+ wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT); -+ wpabuf_put_le16(buf, 2); -+ wpabuf_put_u8(buf, go_timeout); -+ wpabuf_put_u8(buf, client_timeout); -+ wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms) " -+ "client %d (*10ms)", go_timeout, client_timeout); -+} -+ -+ -+void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr) -+{ -+ /* Intended P2P Interface Address */ -+ wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR); -+ wpabuf_put_le16(buf, ETH_ALEN); -+ wpabuf_put_data(buf, interface_addr, ETH_ALEN); -+ wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR, -+ MAC2STR(interface_addr)); -+} -+ -+ -+void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid) -+{ -+ /* P2P Group BSSID */ -+ wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID); -+ wpabuf_put_le16(buf, ETH_ALEN); -+ wpabuf_put_data(buf, bssid, ETH_ALEN); -+ wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR, -+ MAC2STR(bssid)); -+} -+ -+ -+void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr, -+ const u8 *ssid, size_t ssid_len) -+{ -+ /* P2P Group ID */ -+ wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID); -+ wpabuf_put_le16(buf, ETH_ALEN + ssid_len); -+ wpabuf_put_data(buf, dev_addr, ETH_ALEN); -+ wpabuf_put_data(buf, ssid, ssid_len); -+ wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR, -+ MAC2STR(dev_addr)); -+} -+ -+ -+void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags) -+{ -+ /* Invitation Flags */ -+ wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS); -+ wpabuf_put_le16(buf, 1); -+ wpabuf_put_u8(buf, flags); -+ wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags); -+} -+ -+ -+static void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc) -+{ -+ if (desc == NULL) -+ return; -+ -+ wpabuf_put_u8(buf, desc->count_type); -+ wpabuf_put_le32(buf, desc->duration); -+ wpabuf_put_le32(buf, desc->interval); -+ wpabuf_put_le32(buf, desc->start_time); -+} -+ -+ -+void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow, -+ struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2) -+{ -+ /* Notice of Absence */ -+ wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE); -+ wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0)); -+ wpabuf_put_u8(buf, noa_index); -+ wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f)); -+ p2p_buf_add_noa_desc(buf, desc1); -+ p2p_buf_add_noa_desc(buf, desc2); -+ wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); -+} -+ -+ -+void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period, -+ u16 interval) -+{ -+ /* Extended Listen Timing */ -+ wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING); -+ wpabuf_put_le16(buf, 4); -+ wpabuf_put_le16(buf, period); -+ wpabuf_put_le16(buf, interval); -+ wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec " -+ "interval %u msec)", period, interval); -+} -+ -+ -+void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p) -+{ -+ /* P2P Interface */ -+ wpabuf_put_u8(buf, P2P_ATTR_INTERFACE); -+ wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN); -+ /* P2P Device address */ -+ wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); -+ /* -+ * FIX: Fetch interface address list from driver. Do not include -+ * the P2P Device address if it is never used as interface address. -+ */ -+ /* P2P Interface Address Count */ -+ wpabuf_put_u8(buf, 1); -+ wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN); -+} -+ -+ -+static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr, -+ const char *val) -+{ -+ size_t len; -+ -+ wpabuf_put_be16(buf, attr); -+ len = val ? os_strlen(val) : 0; -+#ifndef CONFIG_WPS_STRICT -+ if (len == 0) { -+ /* -+ * Some deployed WPS implementations fail to parse zeor-length -+ * attributes. As a workaround, send a space character if the -+ * device attribute string is empty. -+ */ -+ wpabuf_put_be16(buf, 1); -+ wpabuf_put_u8(buf, ' '); -+ return; -+ } -+#endif /* CONFIG_WPS_STRICT */ -+ wpabuf_put_be16(buf, len); -+ if (val) -+ wpabuf_put_data(buf, val, len); -+} -+ -+ -+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id, -+ int all_attr) -+{ -+ u8 *len; -+ int i; -+ -+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); -+ len = wpabuf_put(buf, 1); -+ wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); -+ -+ wps_build_version(buf); -+ -+ if (all_attr) { -+ wpabuf_put_be16(buf, ATTR_WPS_STATE); -+ wpabuf_put_be16(buf, 1); -+ wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED); -+ } -+ -+ /* Device Password ID */ -+ wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID); -+ wpabuf_put_be16(buf, 2); -+ wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d", pw_id); -+ wpabuf_put_be16(buf, pw_id); -+ -+ if (all_attr) { -+ wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE); -+ wpabuf_put_be16(buf, 1); -+ wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO); -+ -+ wps_build_uuid_e(buf, p2p->cfg->uuid); -+ p2p_add_wps_string(buf, ATTR_MANUFACTURER, -+ p2p->cfg->manufacturer); -+ p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name); -+ p2p_add_wps_string(buf, ATTR_MODEL_NUMBER, -+ p2p->cfg->model_number); -+ p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER, -+ p2p->cfg->serial_number); -+ -+ wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE); -+ wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN); -+ wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN); -+ -+ p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name); -+ -+ wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); -+ wpabuf_put_be16(buf, 2); -+ wpabuf_put_be16(buf, p2p->cfg->config_methods); -+ } -+ -+ wps_build_wfa_ext(buf, 0, NULL, 0); -+ -+ if (all_attr && p2p->cfg->num_sec_dev_types) { -+ wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST); -+ wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN * -+ p2p->cfg->num_sec_dev_types); -+ wpabuf_put_data(buf, p2p->cfg->sec_dev_type, -+ WPS_DEV_TYPE_LEN * -+ p2p->cfg->num_sec_dev_types); -+ } -+ -+ /* Add the WPS vendor extensions */ -+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { -+ if (p2p->wps_vendor_ext[i] == NULL) -+ break; -+ if (wpabuf_tailroom(buf) < -+ 4 + wpabuf_len(p2p->wps_vendor_ext[i])) -+ continue; -+ wpabuf_put_be16(buf, ATTR_VENDOR_EXT); -+ wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i])); -+ wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]); -+ } -+ -+ p2p_buf_update_ie_hdr(buf, len); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_dev_disc.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_dev_disc.c -new file mode 100644 -index 0000000000000..47cc0fdff1d3e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_dev_disc.c -@@ -0,0 +1,365 @@ -+/* -+ * Wi-Fi Direct - P2P Device Discoverability procedure -+ * Copyright (c) 2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "p2p_i.h" -+#include "p2p.h" -+ -+ -+static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p, -+ struct p2p_device *go, -+ const u8 *dev_id) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ -+ buf = wpabuf_alloc(100); -+ if (buf == NULL) -+ return NULL; -+ -+ go->dialog_token++; -+ if (go->dialog_token == 0) -+ go->dialog_token = 1; -+ p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_REQ, go->dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ p2p_buf_add_device_id(buf, dev_id); -+ p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid, -+ go->oper_ssid_len); -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ return buf; -+} -+ -+ -+void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Device Discoverability Request TX callback: success=%d", -+ success); -+ -+ if (!success) { -+ /* -+ * Use P2P find, if needed, to find the other device or to -+ * retry device discoverability. -+ */ -+ p2p_set_state(p2p, P2P_CONNECT); -+ p2p_set_timeout(p2p, 0, 100000); -+ return; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO acknowledged Device Discoverability Request - wait " -+ "for response"); -+ /* -+ * TODO: is the remain-on-channel from Action frame TX long enough for -+ * most cases or should we try to increase its duration and/or start -+ * another remain-on-channel if needed once the previous one expires? -+ */ -+} -+ -+ -+int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev) -+{ -+ struct p2p_device *go; -+ struct wpabuf *req; -+ -+ go = p2p_get_device(p2p, dev->member_in_go_dev); -+ if (go == NULL || dev->oper_freq <= 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Could not find peer entry for GO and frequency " -+ "to send Device Discoverability Request"); -+ return -1; -+ } -+ -+ req = p2p_build_dev_disc_req(p2p, go, dev->info.p2p_device_addr); -+ if (req == NULL) -+ return -1; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Sending Device Discoverability Request to GO " MACSTR -+ " for client " MACSTR, -+ MAC2STR(go->info.p2p_device_addr), -+ MAC2STR(dev->info.p2p_device_addr)); -+ -+ p2p->pending_client_disc_go = go; -+ os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr, -+ ETH_ALEN); -+ p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST; -+ if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr, -+ p2p->cfg->dev_addr, go->info.p2p_device_addr, -+ wpabuf_head(req), wpabuf_len(req), 1000) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ wpabuf_free(req); -+ /* TODO: how to recover from failure? */ -+ return -1; -+ } -+ -+ wpabuf_free(req); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ -+ buf = wpabuf_alloc(100); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_RESP, dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ p2p_buf_add_status(buf, status); -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ return buf; -+} -+ -+ -+void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Device Discoverability Response TX callback: success=%d", -+ success); -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+} -+ -+ -+static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token, -+ const u8 *addr, int freq, u8 status) -+{ -+ struct wpabuf *resp; -+ -+ resp = p2p_build_dev_disc_resp(dialog_token, status); -+ if (resp == NULL) -+ return; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Sending Device Discoverability Response to " MACSTR -+ " (status %u freq %d)", -+ MAC2STR(addr), status, freq); -+ -+ p2p->pending_action_state = P2P_PENDING_DEV_DISC_RESPONSE; -+ if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr, -+ p2p->cfg->dev_addr, -+ wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ } -+ -+ wpabuf_free(resp); -+} -+ -+ -+void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ struct p2p_message msg; -+ size_t g; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received Device Discoverability Request from " MACSTR -+ " (freq=%d)", MAC2STR(sa), rx_freq); -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ if (msg.dialog_token == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid Dialog Token 0 (must be nonzero) in " -+ "Device Discoverability Request"); -+ p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, -+ P2P_SC_FAIL_INVALID_PARAMS); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (msg.device_id == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: P2P Device ID attribute missing from Device " -+ "Discoverability Request"); -+ p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, -+ P2P_SC_FAIL_INVALID_PARAMS); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ for (g = 0; g < p2p->num_groups; g++) { -+ if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa, -+ rx_freq) == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled " -+ "GO Discoverability Request for the target " -+ "device"); -+ /* -+ * P2P group code will use a callback to indicate TX -+ * status, so that we can reply to the request once the -+ * target client has acknowledged the request or it has -+ * timed out. -+ */ -+ p2p->pending_dev_disc_dialog_token = msg.dialog_token; -+ os_memcpy(p2p->pending_dev_disc_addr, sa, ETH_ALEN); -+ p2p->pending_dev_disc_freq = rx_freq; -+ p2p_parse_free(&msg); -+ return; -+ } -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client " -+ "was not found in any group or did not support client " -+ "discoverability"); -+ p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, -+ P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE); -+ p2p_parse_free(&msg); -+} -+ -+ -+void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len) -+{ -+ struct p2p_message msg; -+ struct p2p_device *go; -+ u8 status; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received Device Discoverability Response from " MACSTR, -+ MAC2STR(sa)); -+ -+ go = p2p->pending_client_disc_go; -+ if (go == NULL || -+ os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected " -+ "Device Discoverability Response"); -+ return; -+ } -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ if (msg.status == NULL) { -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (msg.dialog_token != go->dialog_token) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device " -+ "Discoverability Response with unexpected dialog " -+ "token %u (expected %u)", -+ msg.dialog_token, go->dialog_token); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ status = *msg.status; -+ p2p_parse_free(&msg); -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Device Discoverability Response status %u", status); -+ -+ if (p2p->go_neg_peer == NULL || -+ os_memcmp(p2p->pending_client_disc_addr, -+ p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 || -+ os_memcmp(p2p->go_neg_peer->member_in_go_dev, -+ go->info.p2p_device_addr, ETH_ALEN) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending " -+ "operation with the client discoverability peer " -+ "anymore"); -+ return; -+ } -+ -+ if (status == 0) { -+ /* -+ * Peer is expected to be awake for at least 100 TU; try to -+ * connect immediately. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Client discoverability request succeeded"); -+ if (p2p->state == P2P_CONNECT) { -+ /* -+ * Change state to force the timeout to start in -+ * P2P_CONNECT again without going through the short -+ * Listen state. -+ */ -+ p2p_set_state(p2p, P2P_CONNECT_LISTEN); -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ } -+ p2p_set_timeout(p2p, 0, 0); -+ } else { -+ /* -+ * Client discoverability request failed; try to connect from -+ * timeout. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Client discoverability request failed"); -+ p2p_set_timeout(p2p, 0, 500000); -+ } -+ -+} -+ -+ -+void p2p_go_disc_req_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Discoverability Request TX callback: success=%d", -+ success); -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ -+ if (p2p->pending_dev_disc_dialog_token == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device " -+ "Discoverability Request"); -+ return; -+ } -+ -+ p2p_send_dev_disc_resp(p2p, p2p->pending_dev_disc_dialog_token, -+ p2p->pending_dev_disc_addr, -+ p2p->pending_dev_disc_freq, -+ success ? P2P_SC_SUCCESS : -+ P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE); -+ -+ p2p->pending_dev_disc_dialog_token = 0; -+} -+ -+ -+void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ unsigned int tu; -+ struct wpabuf *ies; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received GO Discoverability Request - remain awake for " -+ "100 TU"); -+ -+ ies = p2p_build_probe_resp_ies(p2p); -+ if (ies == NULL) -+ return; -+ -+ /* Remain awake 100 TU on operating channel */ -+ p2p->pending_client_disc_freq = rx_freq; -+ tu = 100; -+ if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000, -+ ies) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to start listen mode for client " -+ "discoverability"); -+ } -+ wpabuf_free(ies); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_go_neg.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_go_neg.c -new file mode 100644 -index 0000000000000..1c96486a4ed59 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_go_neg.c -@@ -0,0 +1,1127 @@ -+/* -+ * Wi-Fi Direct - P2P Group Owner Negotiation -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "wps/wps_defs.h" -+#include "p2p_i.h" -+#include "p2p.h" -+ -+ -+static int p2p_go_det(u8 own_intent, u8 peer_value) -+{ -+ u8 peer_intent = peer_value >> 1; -+ if (own_intent == peer_intent) { -+ if (own_intent == P2P_MAX_GO_INTENT) -+ return -1; /* both devices want to become GO */ -+ -+ /* Use tie breaker bit to determine GO */ -+ return (peer_value & 0x01) ? 0 : 1; -+ } -+ -+ return own_intent > peer_intent; -+} -+ -+ -+int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own, -+ struct p2p_device *dev, -+ const u8 *channel_list, size_t channel_list_len) -+{ -+ const u8 *pos, *end; -+ struct p2p_channels *ch; -+ size_t channels; -+ struct p2p_channels intersection; -+ -+ ch = &dev->channels; -+ os_memset(ch, 0, sizeof(*ch)); -+ pos = channel_list; -+ end = channel_list + channel_list_len; -+ -+ if (end - pos < 3) -+ return -1; -+ os_memcpy(dev->country, pos, 3); -+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Peer country", pos, 3); -+ if (pos[2] != 0x04 && os_memcmp(pos, p2p->cfg->country, 2) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, -+ "P2P: Mismatching country (ours=%c%c peer's=%c%c)", -+ p2p->cfg->country[0], p2p->cfg->country[1], -+ pos[0], pos[1]); -+ return -1; -+ } -+ pos += 3; -+ -+ while (pos + 2 < end) { -+ struct p2p_reg_class *cl = &ch->reg_class[ch->reg_classes]; -+ cl->reg_class = *pos++; -+ if (pos + 1 + pos[0] > end) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, -+ "P2P: Invalid peer Channel List"); -+ return -1; -+ } -+ channels = *pos++; -+ cl->channels = channels > P2P_MAX_REG_CLASS_CHANNELS ? -+ P2P_MAX_REG_CLASS_CHANNELS : channels; -+ os_memcpy(cl->channel, pos, cl->channels); -+ pos += channels; -+ ch->reg_classes++; -+ if (ch->reg_classes == P2P_MAX_REG_CLASSES) -+ break; -+ } -+ -+ p2p_channels_intersect(own, &dev->channels, &intersection); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own reg_classes %d " -+ "peer reg_classes %d intersection reg_classes %d", -+ (int) own->reg_classes, -+ (int) dev->channels.reg_classes, -+ (int) intersection.reg_classes); -+ if (intersection.reg_classes == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, -+ "P2P: No common channels found"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int p2p_peer_channels(struct p2p_data *p2p, struct p2p_device *dev, -+ const u8 *channel_list, size_t channel_list_len) -+{ -+ return p2p_peer_channels_check(p2p, &p2p->channels, dev, -+ channel_list, channel_list_len); -+} -+ -+ -+static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method) -+{ -+ switch (wps_method) { -+ case WPS_PIN_LABEL: -+ return DEV_PW_DEFAULT; -+ case WPS_PIN_DISPLAY: -+ return DEV_PW_REGISTRAR_SPECIFIED; -+ case WPS_PIN_KEYPAD: -+ return DEV_PW_USER_SPECIFIED; -+ case WPS_PBC: -+ return DEV_PW_PUSHBUTTON; -+ default: -+ return DEV_PW_DEFAULT; -+ } -+} -+ -+ -+static const char * p2p_wps_method_str(enum p2p_wps_method wps_method) -+{ -+ switch (wps_method) { -+ case WPS_PIN_LABEL: -+ return "Label"; -+ case WPS_PIN_DISPLAY: -+ return "Display"; -+ case WPS_PIN_KEYPAD: -+ return "Keypad"; -+ case WPS_PBC: -+ return "PBC"; -+ default: -+ return "??"; -+ } -+} -+ -+ -+static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, -+ struct p2p_device *peer) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ u8 group_capab; -+ -+ buf = wpabuf_alloc(1000); -+ if (buf == NULL) -+ return NULL; -+ -+ peer->dialog_token++; -+ if (peer->dialog_token == 0) -+ peer->dialog_token = 1; -+ p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ group_capab = 0; -+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) -+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; -+ if (p2p->cross_connect) -+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; -+ if (p2p->cfg->p2p_intra_bss) -+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; -+ p2p_buf_add_capability(buf, p2p->dev_capab, group_capab); -+ p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | -+ p2p->next_tie_breaker); -+ p2p->next_tie_breaker = !p2p->next_tie_breaker; -+ p2p_buf_add_config_timeout(buf, 100, 20); -+ p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (p2p->ext_listen_interval) -+ p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period, -+ p2p->ext_listen_interval); -+ p2p_buf_add_intended_addr(buf, p2p->intended_addr); -+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); -+ p2p_buf_add_device_info(buf, p2p, peer); -+ p2p_buf_add_operating_channel(buf, p2p->cfg->country, -+ p2p->op_reg_class, p2p->op_channel); -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ /* WPS IE with Device Password ID attribute */ -+ p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0); -+ -+ return buf; -+} -+ -+ -+int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev) -+{ -+ struct wpabuf *req; -+ int freq; -+ -+ freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; -+ if (freq <= 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Listen/Operating frequency known for the " -+ "peer " MACSTR " to send GO Negotiation Request", -+ MAC2STR(dev->info.p2p_device_addr)); -+ return -1; -+ } -+ -+ req = p2p_build_go_neg_req(p2p, dev); -+ if (req == NULL) -+ return -1; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Sending GO Negotiation Request"); -+ p2p_set_state(p2p, P2P_CONNECT); -+ p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST; -+ p2p->go_neg_peer = dev; -+ dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE; -+ dev->connect_reqs++; -+ if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, -+ p2p->cfg->dev_addr, dev->info.p2p_device_addr, -+ wpabuf_head(req), wpabuf_len(req), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ /* Use P2P find to recover and retry */ -+ p2p_set_timeout(p2p, 0, 0); -+ } -+ -+ wpabuf_free(req); -+ -+ return 0; -+} -+ -+ -+static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, -+ struct p2p_device *peer, -+ u8 dialog_token, u8 status, -+ u8 tie_breaker) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ u8 group_capab; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Building GO Negotiation Response"); -+ buf = wpabuf_alloc(1000); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_RESP, dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ p2p_buf_add_status(buf, status); -+ group_capab = 0; -+ if (peer && peer->go_state == LOCAL_GO) { -+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) -+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; -+ if (p2p->cross_connect) -+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; -+ if (p2p->cfg->p2p_intra_bss) -+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; -+ } -+ p2p_buf_add_capability(buf, p2p->dev_capab, group_capab); -+ p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker); -+ p2p_buf_add_config_timeout(buf, 100, 20); -+ if (peer && peer->go_state == REMOTE_GO) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating " -+ "Channel attribute"); -+ } else { -+ p2p_buf_add_operating_channel(buf, p2p->cfg->country, -+ p2p->op_reg_class, -+ p2p->op_channel); -+ } -+ p2p_buf_add_intended_addr(buf, p2p->intended_addr); -+ if (status || peer == NULL) { -+ p2p_buf_add_channel_list(buf, p2p->cfg->country, -+ &p2p->channels); -+ } else if (peer->go_state == REMOTE_GO) { -+ p2p_buf_add_channel_list(buf, p2p->cfg->country, -+ &p2p->channels); -+ } else { -+ struct p2p_channels res; -+ p2p_channels_intersect(&p2p->channels, &peer->channels, -+ &res); -+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &res); -+ } -+ p2p_buf_add_device_info(buf, p2p, peer); -+ if (peer && peer->go_state == LOCAL_GO) { -+ p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid, -+ p2p->ssid_len); -+ } -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ /* WPS IE with Device Password ID attribute */ -+ p2p_build_wps_ie(p2p, buf, -+ p2p_wps_method_pw_id(peer ? peer->wps_method : -+ WPS_NOT_READY), 0); -+ -+ return buf; -+} -+ -+ -+static void p2p_reselect_channel(struct p2p_data *p2p, -+ struct p2p_channels *intersection) -+{ -+ struct p2p_reg_class *cl; -+ int freq; -+ u8 op_reg_class, op_channel; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating " -+ "channel (reg_class %u channel %u) not acceptable to the " -+ "peer", p2p->op_reg_class, p2p->op_channel); -+ -+ /* First, try to pick the best channel from another band */ -+ freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class, -+ p2p->op_channel); -+ if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 && -+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5, -+ &op_reg_class, &op_channel) == 0 && -+ p2p_channels_includes(intersection, op_reg_class, op_channel)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 5 GHz " -+ "channel (reg_class %u channel %u) from intersection", -+ op_reg_class, op_channel); -+ p2p->op_reg_class = op_reg_class; -+ p2p->op_channel = op_channel; -+ return; -+ } -+ -+ if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 && -+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24, -+ &op_reg_class, &op_channel) == 0 && -+ p2p_channels_includes(intersection, op_reg_class, op_channel)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best 2.4 GHz " -+ "channel (reg_class %u channel %u) from intersection", -+ op_reg_class, op_channel); -+ p2p->op_reg_class = op_reg_class; -+ p2p->op_channel = op_channel; -+ return; -+ } -+ -+ /* -+ * Fall back to whatever is included in the channel intersection since -+ * no better options seems to be available. -+ */ -+ cl = &intersection->reg_class[0]; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick another channel " -+ "(reg_class %u channel %u) from intersection", -+ cl->reg_class, cl->channel[0]); -+ p2p->op_reg_class = cl->reg_class; -+ p2p->op_channel = cl->channel[0]; -+} -+ -+ -+void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ struct p2p_device *dev = NULL; -+ struct wpabuf *resp; -+ struct p2p_message msg; -+ u8 status = P2P_SC_FAIL_INVALID_PARAMS; -+ int tie_breaker = 0; -+ int freq; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received GO Negotiation Request from " MACSTR -+ "(freq=%d)", MAC2STR(sa), rx_freq); -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ if (!msg.capability) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory Capability attribute missing from GO " -+ "Negotiation Request"); -+#ifdef CONFIG_P2P_STRICT -+ goto fail; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (msg.go_intent) -+ tie_breaker = *msg.go_intent & 0x01; -+ else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory GO Intent attribute missing from GO " -+ "Negotiation Request"); -+#ifdef CONFIG_P2P_STRICT -+ goto fail; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (!msg.config_timeout) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory Configuration Timeout attribute " -+ "missing from GO Negotiation Request"); -+#ifdef CONFIG_P2P_STRICT -+ goto fail; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (!msg.listen_channel) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Listen Channel attribute received"); -+ goto fail; -+ } -+ if (!msg.operating_channel) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Operating Channel attribute received"); -+ goto fail; -+ } -+ if (!msg.channel_list) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Channel List attribute received"); -+ goto fail; -+ } -+ if (!msg.intended_addr) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Intended P2P Interface Address attribute " -+ "received"); -+ goto fail; -+ } -+ if (!msg.p2p_device_info) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No P2P Device Info attribute received"); -+ goto fail; -+ } -+ -+ if (os_memcmp(msg.p2p_device_addr, sa, ETH_ALEN) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected GO Negotiation Request SA=" MACSTR -+ " != dev_addr=" MACSTR, -+ MAC2STR(sa), MAC2STR(msg.p2p_device_addr)); -+ goto fail; -+ } -+ -+ dev = p2p_get_device(p2p, sa); -+ -+ if (msg.status && *msg.status) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected Status attribute (%d) in GO " -+ "Negotiation Request", *msg.status); -+ goto fail; -+ } -+ -+ if (dev == NULL) -+ dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg); -+ else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) -+ p2p_add_dev_info(p2p, sa, dev, &msg); -+ if (dev && dev->flags & P2P_DEV_USER_REJECTED) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: User has rejected this peer"); -+ status = P2P_SC_FAIL_REJECTED_BY_USER; -+ } else if (dev == NULL || dev->wps_method == WPS_NOT_READY) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Not ready for GO negotiation with " MACSTR, -+ MAC2STR(sa)); -+ status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; -+ if (dev) -+ dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE; -+ p2p->cfg->go_neg_req_rx(p2p->cfg->cb_ctx, sa, -+ msg.dev_password_id); -+ } else if (p2p->go_neg_peer && p2p->go_neg_peer != dev) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Already in Group Formation with another peer"); -+ status = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; -+ } else { -+ int go; -+ -+ if (!p2p->go_neg_peer) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting " -+ "GO Negotiation with previously authorized " -+ "peer"); -+ if (!(dev->flags & P2P_DEV_FORCE_FREQ)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Use default channel settings"); -+ p2p->op_reg_class = p2p->cfg->op_reg_class; -+ p2p->op_channel = p2p->cfg->op_channel; -+ os_memcpy(&p2p->channels, &p2p->cfg->channels, -+ sizeof(struct p2p_channels)); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Use previously configured " -+ "forced channel settings"); -+ } -+ } -+ -+ dev->flags &= ~P2P_DEV_NOT_YET_READY; -+ -+ if (!msg.go_intent) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No GO Intent attribute received"); -+ goto fail; -+ } -+ if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid GO Intent value (%u) received", -+ *msg.go_intent >> 1); -+ goto fail; -+ } -+ -+ if (dev->go_neg_req_sent && -+ os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Do not reply since peer has higher " -+ "address and GO Neg Request already sent"); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ go = p2p_go_det(p2p->go_intent, *msg.go_intent); -+ if (go < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Incompatible GO Intent"); -+ status = P2P_SC_FAIL_BOTH_GO_INTENT_15; -+ goto fail; -+ } -+ -+ if (p2p_peer_channels(p2p, dev, msg.channel_list, -+ msg.channel_list_len) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No common channels found"); -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ goto fail; -+ } -+ -+ switch (msg.dev_password_id) { -+ case DEV_PW_DEFAULT: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: PIN from peer Label"); -+ if (dev->wps_method != WPS_PIN_KEYPAD) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ case DEV_PW_REGISTRAR_SPECIFIED: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: PIN from peer Display"); -+ if (dev->wps_method != WPS_PIN_KEYPAD) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ case DEV_PW_USER_SPECIFIED: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Peer entered PIN on Keypad"); -+ if (dev->wps_method != WPS_PIN_LABEL && -+ dev->wps_method != WPS_PIN_DISPLAY) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ case DEV_PW_PUSHBUTTON: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Peer using pushbutton"); -+ if (dev->wps_method != WPS_PBC) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ default: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported Device Password ID %d", -+ msg.dev_password_id); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ -+ if (go) { -+ struct p2p_channels intersection; -+ size_t i; -+ p2p_channels_intersect(&p2p->channels, &dev->channels, -+ &intersection); -+ if (intersection.reg_classes == 0 || -+ intersection.reg_class[0].channels == 0) { -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No common channels found"); -+ goto fail; -+ } -+ for (i = 0; i < intersection.reg_classes; i++) { -+ struct p2p_reg_class *c; -+ c = &intersection.reg_class[i]; -+ wpa_printf(MSG_DEBUG, "P2P: reg_class %u", -+ c->reg_class); -+ wpa_hexdump(MSG_DEBUG, "P2P: channels", -+ c->channel, c->channels); -+ } -+ if (!p2p_channels_includes(&intersection, -+ p2p->op_reg_class, -+ p2p->op_channel)) -+ p2p_reselect_channel(p2p, &intersection); -+ -+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); -+ } -+ -+ dev->go_state = go ? LOCAL_GO : REMOTE_GO; -+ dev->oper_freq = p2p_channel_to_freq((const char *) -+ msg.operating_channel, -+ msg.operating_channel[3], -+ msg.operating_channel[4]); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating " -+ "channel preference: %d MHz", dev->oper_freq); -+ -+ if (msg.config_timeout) { -+ dev->go_timeout = msg.config_timeout[0]; -+ dev->client_timeout = msg.config_timeout[1]; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation with " MACSTR, MAC2STR(sa)); -+ if (p2p->state != P2P_IDLE) -+ p2p_stop_find_for_freq(p2p, rx_freq); -+ p2p_set_state(p2p, P2P_GO_NEG); -+ p2p_clear_timeout(p2p); -+ dev->dialog_token = msg.dialog_token; -+ os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); -+ p2p->go_neg_peer = dev; -+ status = P2P_SC_SUCCESS; -+ } -+ -+fail: -+ if (dev) -+ dev->status = status; -+ resp = p2p_build_go_neg_resp(p2p, dev, msg.dialog_token, status, -+ !tie_breaker); -+ p2p_parse_free(&msg); -+ if (resp == NULL) -+ return; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Sending GO Negotiation Response"); -+ if (rx_freq > 0) -+ freq = rx_freq; -+ else -+ freq = p2p_channel_to_freq(p2p->cfg->country, -+ p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (freq < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown regulatory class/channel"); -+ wpabuf_free(resp); -+ return; -+ } -+ if (status == P2P_SC_SUCCESS) { -+ p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE; -+ dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM; -+ } else -+ p2p->pending_action_state = -+ P2P_PENDING_GO_NEG_RESPONSE_FAILURE; -+ if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, -+ p2p->cfg->dev_addr, -+ wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ } -+ -+ wpabuf_free(resp); -+} -+ -+ -+static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, -+ struct p2p_device *peer, -+ u8 dialog_token, u8 status, -+ const u8 *resp_chan, int go) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ struct p2p_channels res; -+ u8 group_capab; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Building GO Negotiation Confirm"); -+ buf = wpabuf_alloc(1000); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_CONF, dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ p2p_buf_add_status(buf, status); -+ group_capab = 0; -+ if (peer->go_state == LOCAL_GO) { -+ if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) -+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; -+ if (p2p->cross_connect) -+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; -+ if (p2p->cfg->p2p_intra_bss) -+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; -+ } -+ p2p_buf_add_capability(buf, p2p->dev_capab, group_capab); -+ if (go || resp_chan == NULL) -+ p2p_buf_add_operating_channel(buf, p2p->cfg->country, -+ p2p->op_reg_class, -+ p2p->op_channel); -+ else -+ p2p_buf_add_operating_channel(buf, (const char *) resp_chan, -+ resp_chan[3], resp_chan[4]); -+ p2p_channels_intersect(&p2p->channels, &peer->channels, &res); -+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &res); -+ if (go) { -+ p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid, -+ p2p->ssid_len); -+ } -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ return buf; -+} -+ -+ -+void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ struct p2p_device *dev; -+ struct wpabuf *conf; -+ int go = -1; -+ struct p2p_message msg; -+ u8 status = P2P_SC_SUCCESS; -+ int freq; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received GO Negotiation Response from " MACSTR -+ " (freq=%d)", MAC2STR(sa), rx_freq); -+ dev = p2p_get_device(p2p, sa); -+ if (dev == NULL || dev->wps_method == WPS_NOT_READY || -+ dev != p2p->go_neg_peer) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Not ready for GO negotiation with " MACSTR, -+ MAC2STR(sa)); -+ return; -+ } -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Was not expecting GO Negotiation Response - " -+ "ignore"); -+ p2p_parse_free(&msg); -+ return; -+ } -+ dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; -+ -+ if (msg.dialog_token != dev->dialog_token) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected Dialog Token %u (expected %u)", -+ msg.dialog_token, dev->dialog_token); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (!msg.status) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Status attribute received"); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ if (*msg.status) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation rejected: status %d", -+ *msg.status); -+ dev->go_neg_req_sent = 0; -+ if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Wait for the peer to become ready for " -+ "GO Negotiation"); -+ dev->flags |= P2P_DEV_NOT_YET_READY; -+ dev->wait_count = 0; -+ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); -+ p2p_set_timeout(p2p, 0, 0); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Stop GO Negotiation attempt"); -+ p2p_go_neg_failed(p2p, dev, *msg.status); -+ } -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (!msg.capability) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory Capability attribute missing from GO " -+ "Negotiation Response"); -+#ifdef CONFIG_P2P_STRICT -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (!msg.p2p_device_info) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory P2P Device Info attribute missing " -+ "from GO Negotiation Response"); -+#ifdef CONFIG_P2P_STRICT -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (!msg.intended_addr) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Intended P2P Interface Address attribute " -+ "received"); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ -+ if (!msg.go_intent) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No GO Intent attribute received"); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ if ((*msg.go_intent >> 1) > P2P_MAX_GO_INTENT) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid GO Intent value (%u) received", -+ *msg.go_intent >> 1); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ -+ go = p2p_go_det(p2p->go_intent, *msg.go_intent); -+ if (go < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Incompatible GO Intent"); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; -+ goto fail; -+ } -+ -+ if (!go && msg.group_id) { -+ /* Store SSID for Provisioning step */ -+ p2p->ssid_len = msg.group_id_len - ETH_ALEN; -+ os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len); -+ } else if (!go) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory P2P Group ID attribute missing from " -+ "GO Negotiation Response"); -+ p2p->ssid_len = 0; -+#ifdef CONFIG_P2P_STRICT -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (!msg.config_timeout) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory Configuration Timeout attribute " -+ "missing from GO Negotiation Response"); -+#ifdef CONFIG_P2P_STRICT -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+#endif /* CONFIG_P2P_STRICT */ -+ } else { -+ dev->go_timeout = msg.config_timeout[0]; -+ dev->client_timeout = msg.config_timeout[1]; -+ } -+ -+ if (!msg.operating_channel && !go) { -+ /* -+ * Note: P2P Client may omit Operating Channel attribute to -+ * indicate it does not have a preference. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Operating Channel attribute received"); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ if (!msg.channel_list) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Channel List attribute received"); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ -+ if (p2p_peer_channels(p2p, dev, msg.channel_list, -+ msg.channel_list_len) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No common channels found"); -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ goto fail; -+ } -+ -+ if (msg.operating_channel) { -+ dev->oper_freq = p2p_channel_to_freq((const char *) -+ msg.operating_channel, -+ msg.operating_channel[3], -+ msg.operating_channel[4]); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating " -+ "channel preference: %d MHz", dev->oper_freq); -+ } else -+ dev->oper_freq = 0; -+ -+ switch (msg.dev_password_id) { -+ case DEV_PW_DEFAULT: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: PIN from peer Label"); -+ if (dev->wps_method != WPS_PIN_KEYPAD) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ case DEV_PW_REGISTRAR_SPECIFIED: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: PIN from peer Display"); -+ if (dev->wps_method != WPS_PIN_KEYPAD) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ case DEV_PW_USER_SPECIFIED: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Peer entered PIN on Keypad"); -+ if (dev->wps_method != WPS_PIN_LABEL && -+ dev->wps_method != WPS_PIN_DISPLAY) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ case DEV_PW_PUSHBUTTON: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Peer using pushbutton"); -+ if (dev->wps_method != WPS_PBC) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: We have wps_method=%s -> " -+ "incompatible", -+ p2p_wps_method_str(dev->wps_method)); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ break; -+ default: -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported Device Password ID %d", -+ msg.dev_password_id); -+ status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD; -+ goto fail; -+ } -+ -+ if (go) { -+ struct p2p_channels intersection; -+ size_t i; -+ p2p_channels_intersect(&p2p->channels, &dev->channels, -+ &intersection); -+ if (intersection.reg_classes == 0 || -+ intersection.reg_class[0].channels == 0) { -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No common channels found"); -+ goto fail; -+ } -+ for (i = 0; i < intersection.reg_classes; i++) { -+ struct p2p_reg_class *c; -+ c = &intersection.reg_class[i]; -+ wpa_printf(MSG_DEBUG, "P2P: reg_class %u", -+ c->reg_class); -+ wpa_hexdump(MSG_DEBUG, "P2P: channels", -+ c->channel, c->channels); -+ } -+ if (!p2p_channels_includes(&intersection, p2p->op_reg_class, -+ p2p->op_channel)) -+ p2p_reselect_channel(p2p, &intersection); -+ -+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); -+ } -+ -+ p2p_set_state(p2p, P2P_GO_NEG); -+ p2p_clear_timeout(p2p); -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation with " MACSTR, MAC2STR(sa)); -+ os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN); -+ -+fail: -+ conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status, -+ msg.operating_channel, go); -+ p2p_parse_free(&msg); -+ if (conf == NULL) -+ return; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Sending GO Negotiation Confirm"); -+ if (status == P2P_SC_SUCCESS) { -+ p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM; -+ dev->go_state = go ? LOCAL_GO : REMOTE_GO; -+ } else -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ if (rx_freq > 0) -+ freq = rx_freq; -+ else -+ freq = dev->listen_freq; -+ if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa, -+ wpabuf_head(conf), wpabuf_len(conf), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ p2p_go_neg_failed(p2p, dev, -1); -+ } -+ wpabuf_free(conf); -+} -+ -+ -+void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len) -+{ -+ struct p2p_device *dev; -+ struct p2p_message msg; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received GO Negotiation Confirm from " MACSTR, -+ MAC2STR(sa)); -+ dev = p2p_get_device(p2p, sa); -+ if (dev == NULL || dev->wps_method == WPS_NOT_READY || -+ dev != p2p->go_neg_peer) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Not ready for GO negotiation with " MACSTR, -+ MAC2STR(sa)); -+ return; -+ } -+ -+ if (p2p->pending_action_state == P2P_PENDING_GO_NEG_RESPONSE) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopped waiting " -+ "for TX status on GO Negotiation Response since we " -+ "already received Confirmation"); -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ } -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Was not expecting GO Negotiation Confirm - " -+ "ignore"); -+ return; -+ } -+ dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; -+ -+ if (msg.dialog_token != dev->dialog_token) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected Dialog Token %u (expected %u)", -+ msg.dialog_token, dev->dialog_token); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (!msg.status) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Status attribute received"); -+ p2p_parse_free(&msg); -+ return; -+ } -+ if (*msg.status) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GO Negotiation rejected: status %d", -+ *msg.status); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (dev->go_state == REMOTE_GO && msg.group_id) { -+ /* Store SSID for Provisioning step */ -+ p2p->ssid_len = msg.group_id_len - ETH_ALEN; -+ os_memcpy(p2p->ssid, msg.group_id + ETH_ALEN, p2p->ssid_len); -+ } else if (dev->go_state == REMOTE_GO) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory P2P Group ID attribute missing from " -+ "GO Negotiation Confirmation"); -+ p2p->ssid_len = 0; -+#ifdef CONFIG_P2P_STRICT -+ p2p_parse_free(&msg); -+ return; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (!msg.operating_channel) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory Operating Channel attribute missing " -+ "from GO Negotiation Confirmation"); -+#ifdef CONFIG_P2P_STRICT -+ p2p_parse_free(&msg); -+ return; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ if (!msg.channel_list) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory Operating Channel attribute missing " -+ "from GO Negotiation Confirmation"); -+#ifdef CONFIG_P2P_STRICT -+ p2p_parse_free(&msg); -+ return; -+#endif /* CONFIG_P2P_STRICT */ -+ } -+ -+ p2p_parse_free(&msg); -+ -+ if (dev->go_state == UNKNOWN_GO) { -+ /* -+ * This should not happen since GO negotiation has already -+ * been completed. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected GO Neg state - do not know which end " -+ "becomes GO"); -+ return; -+ } -+ -+ p2p_go_complete(p2p, dev); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_group.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_group.c -new file mode 100644 -index 0000000000000..14a475d01908c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_group.c -@@ -0,0 +1,673 @@ -+/* -+ * Wi-Fi Direct - P2P group operations -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "wps/wps_defs.h" -+#include "wps/wps_i.h" -+#include "p2p_i.h" -+#include "p2p.h" -+ -+ -+struct p2p_group_member { -+ struct p2p_group_member *next; -+ u8 addr[ETH_ALEN]; /* P2P Interface Address */ -+ u8 dev_addr[ETH_ALEN]; /* P2P Device Address */ -+ struct wpabuf *p2p_ie; -+ struct wpabuf *client_info; -+ u8 dev_capab; -+}; -+ -+/** -+ * struct p2p_group - Internal P2P module per-group data -+ */ -+struct p2p_group { -+ struct p2p_data *p2p; -+ struct p2p_group_config *cfg; -+ struct p2p_group_member *members; -+ unsigned int num_members; -+ int group_formation; -+ int beacon_update; -+ struct wpabuf *noa; -+}; -+ -+ -+static void p2p_group_update_ies(struct p2p_group *group); -+ -+ -+struct p2p_group * p2p_group_init(struct p2p_data *p2p, -+ struct p2p_group_config *config) -+{ -+ struct p2p_group *group, **groups; -+ -+ group = os_zalloc(sizeof(*group)); -+ if (group == NULL) -+ return NULL; -+ -+ groups = os_realloc(p2p->groups, (p2p->num_groups + 1) * -+ sizeof(struct p2p_group *)); -+ if (groups == NULL) { -+ os_free(group); -+ return NULL; -+ } -+ groups[p2p->num_groups++] = group; -+ p2p->groups = groups; -+ -+ group->p2p = p2p; -+ group->cfg = config; -+ group->group_formation = 1; -+ group->beacon_update = 1; -+ p2p_group_update_ies(group); -+ group->cfg->idle_update(group->cfg->cb_ctx, 1); -+ -+ return group; -+} -+ -+ -+static void p2p_group_free_member(struct p2p_group_member *m) -+{ -+ wpabuf_free(m->p2p_ie); -+ wpabuf_free(m->client_info); -+ os_free(m); -+} -+ -+ -+static void p2p_group_free_members(struct p2p_group *group) -+{ -+ struct p2p_group_member *m, *prev; -+ m = group->members; -+ group->members = NULL; -+ group->num_members = 0; -+ while (m) { -+ prev = m; -+ m = m->next; -+ p2p_group_free_member(prev); -+ } -+} -+ -+ -+void p2p_group_deinit(struct p2p_group *group) -+{ -+ size_t g; -+ struct p2p_data *p2p; -+ -+ if (group == NULL) -+ return; -+ -+ p2p = group->p2p; -+ -+ for (g = 0; g < p2p->num_groups; g++) { -+ if (p2p->groups[g] == group) { -+ while (g + 1 < p2p->num_groups) { -+ p2p->groups[g] = p2p->groups[g + 1]; -+ g++; -+ } -+ p2p->num_groups--; -+ break; -+ } -+ } -+ -+ p2p_group_free_members(group); -+ os_free(group->cfg); -+ wpabuf_free(group->noa); -+ os_free(group); -+} -+ -+ -+static void p2p_client_info(struct wpabuf *ie, struct p2p_group_member *m) -+{ -+ if (m->client_info == NULL) -+ return; -+ if (wpabuf_tailroom(ie) < wpabuf_len(m->client_info) + 1) -+ return; -+ wpabuf_put_buf(ie, m->client_info); -+} -+ -+ -+static void p2p_group_add_common_ies(struct p2p_group *group, -+ struct wpabuf *ie) -+{ -+ u8 dev_capab = 0, group_capab = 0; -+ -+ /* P2P Capability */ -+ dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY; -+ dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE; -+ group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER; -+ if (group->cfg->persistent_group) -+ group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; -+ if (group->p2p->cfg->p2p_intra_bss) -+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; -+ if (group->group_formation) -+ group_capab |= P2P_GROUP_CAPAB_GROUP_FORMATION; -+ if (group->p2p->cross_connect) -+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; -+ if (group->num_members >= group->cfg->max_clients) -+ group_capab |= P2P_GROUP_CAPAB_GROUP_LIMIT; -+ p2p_buf_add_capability(ie, dev_capab, group_capab); -+} -+ -+ -+static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa) -+{ -+ if (noa == NULL) -+ return; -+ /* Notice of Absence */ -+ wpabuf_put_u8(ie, P2P_ATTR_NOTICE_OF_ABSENCE); -+ wpabuf_put_le16(ie, wpabuf_len(noa)); -+ wpabuf_put_buf(ie, noa); -+} -+ -+ -+static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) -+{ -+ struct wpabuf *ie; -+ u8 *len; -+ -+ ie = wpabuf_alloc(257); -+ if (ie == NULL) -+ return NULL; -+ -+ len = p2p_buf_add_ie_hdr(ie); -+ p2p_group_add_common_ies(group, ie); -+ p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); -+ p2p_group_add_noa(ie, group->noa); -+ p2p_buf_update_ie_hdr(ie, len); -+ -+ return ie; -+} -+ -+ -+static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) -+{ -+ u8 *group_info; -+ struct wpabuf *ie; -+ struct p2p_group_member *m; -+ u8 *len; -+ -+ ie = wpabuf_alloc(257); -+ if (ie == NULL) -+ return NULL; -+ -+ len = p2p_buf_add_ie_hdr(ie); -+ -+ p2p_group_add_common_ies(group, ie); -+ p2p_group_add_noa(ie, group->noa); -+ -+ /* P2P Device Info */ -+ p2p_buf_add_device_info(ie, group->p2p, NULL); -+ -+ /* P2P Group Info */ -+ group_info = wpabuf_put(ie, 0); -+ wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO); -+ wpabuf_put_le16(ie, 0); /* Length to be filled */ -+ for (m = group->members; m; m = m->next) -+ p2p_client_info(ie, m); -+ WPA_PUT_LE16(group_info + 1, -+ (u8 *) wpabuf_put(ie, 0) - group_info - 3); -+ -+ p2p_buf_update_ie_hdr(ie, len); -+ return ie; -+} -+ -+ -+static void p2p_group_update_ies(struct p2p_group *group) -+{ -+ struct wpabuf *beacon_ie; -+ struct wpabuf *probe_resp_ie; -+ -+ probe_resp_ie = p2p_group_build_probe_resp_ie(group); -+ if (probe_resp_ie == NULL) -+ return; -+ wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Probe Response P2P IE", -+ probe_resp_ie); -+ -+ if (group->beacon_update) { -+ beacon_ie = p2p_group_build_beacon_ie(group); -+ if (beacon_ie) -+ group->beacon_update = 0; -+ wpa_hexdump_buf(MSG_MSGDUMP, "P2P: Update GO Beacon P2P IE", -+ beacon_ie); -+ } else -+ beacon_ie = NULL; -+ -+ group->cfg->ie_update(group->cfg->cb_ctx, beacon_ie, probe_resp_ie); -+} -+ -+ -+/** -+ * p2p_build_client_info - Build P2P Client Info Descriptor -+ * @addr: MAC address of the peer device -+ * @p2p_ie: P2P IE from (Re)Association Request -+ * @dev_capab: Buffer for returning Device Capability -+ * @dev_addr: Buffer for returning P2P Device Address -+ * Returns: P2P Client Info Descriptor or %NULL on failure -+ * -+ * This function builds P2P Client Info Descriptor based on the information -+ * available from (Re)Association Request frame. Group owner can use this to -+ * build the P2P Group Info attribute for Probe Response frames. -+ */ -+static struct wpabuf * p2p_build_client_info(const u8 *addr, -+ struct wpabuf *p2p_ie, -+ u8 *dev_capab, u8 *dev_addr) -+{ -+ const u8 *spos; -+ struct p2p_message msg; -+ u8 *len_pos; -+ struct wpabuf *buf; -+ -+ if (p2p_ie == NULL) -+ return NULL; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_p2p_ie(p2p_ie, &msg) || -+ msg.capability == NULL || msg.p2p_device_info == NULL) -+ return NULL; -+ -+ buf = wpabuf_alloc(ETH_ALEN + 1 + 1 + msg.p2p_device_info_len); -+ if (buf == NULL) -+ return NULL; -+ -+ *dev_capab = msg.capability[0]; -+ os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN); -+ -+ spos = msg.p2p_device_info; /* P2P Device address */ -+ -+ /* P2P Client Info Descriptor */ -+ /* Length to be set */ -+ len_pos = wpabuf_put(buf, 1); -+ /* P2P Device address */ -+ wpabuf_put_data(buf, spos, ETH_ALEN); -+ /* P2P Interface address */ -+ wpabuf_put_data(buf, addr, ETH_ALEN); -+ /* Device Capability Bitmap */ -+ wpabuf_put_u8(buf, msg.capability[0]); -+ /* -+ * Config Methods, Primary Device Type, Number of Secondary Device -+ * Types, Secondary Device Type List, Device Name copied from -+ * Device Info -+ */ -+ wpabuf_put_data(buf, spos + ETH_ALEN, -+ msg.p2p_device_info_len - ETH_ALEN); -+ -+ *len_pos = wpabuf_len(buf) - 1; -+ -+ -+ return buf; -+} -+ -+ -+int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr, -+ const u8 *ie, size_t len) -+{ -+ struct p2p_group_member *m; -+ -+ if (group == NULL) -+ return -1; -+ -+ m = os_zalloc(sizeof(*m)); -+ if (m == NULL) -+ return -1; -+ os_memcpy(m->addr, addr, ETH_ALEN); -+ m->p2p_ie = ieee802_11_vendor_ie_concat(ie, len, P2P_IE_VENDOR_TYPE); -+ if (m->p2p_ie) { -+ m->client_info = p2p_build_client_info(addr, m->p2p_ie, -+ &m->dev_capab, -+ m->dev_addr); -+ } -+ -+ m->next = group->members; -+ group->members = m; -+ group->num_members++; -+ wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR -+ " to group (p2p=%d client_info=%d); num_members=%u/%u", -+ MAC2STR(addr), m->p2p_ie ? 1 : 0, m->client_info ? 1 : 0, -+ group->num_members, group->cfg->max_clients); -+ if (group->num_members == group->cfg->max_clients) -+ group->beacon_update = 1; -+ p2p_group_update_ies(group); -+ if (group->num_members == 1) -+ group->cfg->idle_update(group->cfg->cb_ctx, 0); -+ -+ return 0; -+} -+ -+ -+struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) -+{ -+ struct wpabuf *resp; -+ u8 *rlen; -+ -+ /* -+ * (Re)Association Response - P2P IE -+ * Status attribute (shall be present when association request is -+ * denied) -+ * Extended Listen Timing (may be present) -+ */ -+ resp = wpabuf_alloc(20); -+ if (resp == NULL) -+ return NULL; -+ rlen = p2p_buf_add_ie_hdr(resp); -+ if (status != P2P_SC_SUCCESS) -+ p2p_buf_add_status(resp, status); -+ p2p_buf_update_ie_hdr(resp, rlen); -+ -+ return resp; -+} -+ -+ -+void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr) -+{ -+ struct p2p_group_member *m, *prev; -+ -+ if (group == NULL) -+ return; -+ -+ m = group->members; -+ prev = NULL; -+ while (m) { -+ if (os_memcmp(m->addr, addr, ETH_ALEN) == 0) -+ break; -+ prev = m; -+ m = m->next; -+ } -+ -+ if (m) { -+ if (prev) -+ prev->next = m->next; -+ else -+ group->members = m->next; -+ p2p_group_free_member(m); -+ group->num_members--; -+ wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove " -+ "client " MACSTR " from group; num_members=%u/%u", -+ MAC2STR(addr), group->num_members, -+ group->cfg->max_clients); -+ if (group->num_members == group->cfg->max_clients - 1) -+ group->beacon_update = 1; -+ p2p_group_update_ies(group); -+ if (group->num_members == 0) -+ group->cfg->idle_update(group->cfg->cb_ctx, 1); -+ } -+} -+ -+ -+/** -+ * p2p_match_dev_type_member - Match client device type with requested type -+ * @m: Group member -+ * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs) -+ * Returns: 1 on match, 0 on mismatch -+ * -+ * This function can be used to match the Requested Device Type attribute in -+ * WPS IE with the device types of a group member for deciding whether a GO -+ * should reply to a Probe Request frame. -+ */ -+static int p2p_match_dev_type_member(struct p2p_group_member *m, -+ struct wpabuf *wps) -+{ -+ const u8 *pos, *end; -+ struct wps_parse_attr attr; -+ u8 num_sec; -+ -+ if (m->client_info == NULL || wps == NULL) -+ return 0; -+ -+ pos = wpabuf_head(m->client_info); -+ end = pos + wpabuf_len(m->client_info); -+ -+ pos += 1 + 2 * ETH_ALEN + 1 + 2; -+ if (end - pos < WPS_DEV_TYPE_LEN + 1) -+ return 0; -+ -+ if (wps_parse_msg(wps, &attr)) -+ return 1; /* assume no Requested Device Type attributes */ -+ -+ if (attr.num_req_dev_type == 0) -+ return 1; /* no Requested Device Type attributes -> match */ -+ -+ if (dev_type_list_match(pos, attr.req_dev_type, attr.num_req_dev_type)) -+ return 1; /* Match with client Primary Device Type */ -+ -+ pos += WPS_DEV_TYPE_LEN; -+ num_sec = *pos++; -+ if (end - pos < num_sec * WPS_DEV_TYPE_LEN) -+ return 0; -+ while (num_sec > 0) { -+ num_sec--; -+ if (dev_type_list_match(pos, attr.req_dev_type, -+ attr.num_req_dev_type)) -+ return 1; /* Match with client Secondary Device Type */ -+ pos += WPS_DEV_TYPE_LEN; -+ } -+ -+ /* No matching device type found */ -+ return 0; -+} -+ -+ -+int p2p_group_match_dev_type(struct p2p_group *group, struct wpabuf *wps) -+{ -+ struct p2p_group_member *m; -+ -+ if (p2p_match_dev_type(group->p2p, wps)) -+ return 1; /* Match with own device type */ -+ -+ for (m = group->members; m; m = m->next) { -+ if (p2p_match_dev_type_member(m, wps)) -+ return 1; /* Match with group client device type */ -+ } -+ -+ /* No match with Requested Device Type */ -+ return 0; -+} -+ -+ -+void p2p_group_notif_formation_done(struct p2p_group *group) -+{ -+ if (group == NULL) -+ return; -+ group->group_formation = 0; -+ group->beacon_update = 1; -+ p2p_group_update_ies(group); -+} -+ -+ -+int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa, -+ size_t noa_len) -+{ -+ if (noa == NULL) { -+ wpabuf_free(group->noa); -+ group->noa = NULL; -+ } else { -+ if (group->noa) { -+ if (wpabuf_size(group->noa) >= noa_len) { -+ group->noa->size = 0; -+ wpabuf_put_data(group->noa, noa, noa_len); -+ } else { -+ wpabuf_free(group->noa); -+ group->noa = NULL; -+ } -+ } -+ -+ if (!group->noa) { -+ group->noa = wpabuf_alloc_copy(noa, noa_len); -+ if (group->noa == NULL) -+ return -1; -+ } -+ } -+ -+ group->beacon_update = 1; -+ p2p_group_update_ies(group); -+ return 0; -+} -+ -+ -+static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group, -+ const u8 *dev_id) -+{ -+ struct p2p_group_member *m; -+ -+ for (m = group->members; m; m = m->next) { -+ if (os_memcmp(dev_id, m->dev_addr, ETH_ALEN) == 0) -+ return m; -+ } -+ -+ return NULL; -+} -+ -+ -+static struct p2p_group_member * p2p_group_get_client_iface( -+ struct p2p_group *group, const u8 *interface_addr) -+{ -+ struct p2p_group_member *m; -+ -+ for (m = group->members; m; m = m->next) { -+ if (os_memcmp(interface_addr, m->addr, ETH_ALEN) == 0) -+ return m; -+ } -+ -+ return NULL; -+} -+ -+ -+static struct wpabuf * p2p_build_go_disc_req(void) -+{ -+ struct wpabuf *buf; -+ -+ buf = wpabuf_alloc(100); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_buf_add_action_hdr(buf, P2P_GO_DISC_REQ, 0); -+ -+ return buf; -+} -+ -+ -+int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, -+ const u8 *searching_dev, int rx_freq) -+{ -+ struct p2p_group_member *m; -+ struct wpabuf *req; -+ struct p2p_data *p2p = group->p2p; -+ int freq; -+ -+ m = p2p_group_get_client(group, dev_id); -+ if (m == NULL || m->client_info == NULL) { -+ wpa_printf(MSG_DEBUG, "P2P: Requested client was not in this " -+ "group " MACSTR, -+ MAC2STR(group->cfg->interface_addr)); -+ return -1; -+ } -+ -+ if (!(m->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { -+ wpa_printf(MSG_DEBUG, "P2P: Requested client does not support " -+ "client discoverability"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "P2P: Schedule GO Discoverability Request to be " -+ "sent to " MACSTR, MAC2STR(dev_id)); -+ -+ req = p2p_build_go_disc_req(); -+ if (req == NULL) -+ return -1; -+ -+ /* TODO: Should really use group operating frequency here */ -+ freq = rx_freq; -+ -+ p2p->pending_action_state = P2P_PENDING_GO_DISC_REQ; -+ if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr, -+ group->cfg->interface_addr, -+ group->cfg->interface_addr, -+ wpabuf_head(req), wpabuf_len(req), 200) < 0) -+ { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ } -+ -+ wpabuf_free(req); -+ -+ return 0; -+} -+ -+ -+const u8 * p2p_group_get_interface_addr(struct p2p_group *group) -+{ -+ return group->cfg->interface_addr; -+} -+ -+ -+u8 p2p_group_presence_req(struct p2p_group *group, -+ const u8 *client_interface_addr, -+ const u8 *noa, size_t noa_len) -+{ -+ struct p2p_group_member *m; -+ u8 curr_noa[50]; -+ int curr_noa_len; -+ -+ m = p2p_group_get_client_iface(group, client_interface_addr); -+ if (m == NULL || m->client_info == NULL) { -+ wpa_printf(MSG_DEBUG, "P2P: Client was not in this group"); -+ return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "P2P: Presence Request NoA", noa, noa_len); -+ -+ if (group->p2p->cfg->get_noa) -+ curr_noa_len = group->p2p->cfg->get_noa( -+ group->p2p->cfg->cb_ctx, group->cfg->interface_addr, -+ curr_noa, sizeof(curr_noa)); -+ else -+ curr_noa_len = -1; -+ if (curr_noa_len < 0) -+ wpa_printf(MSG_DEBUG, "P2P: Failed to fetch current NoA"); -+ else if (curr_noa_len == 0) -+ wpa_printf(MSG_DEBUG, "P2P: No NoA being advertized"); -+ else -+ wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa, -+ curr_noa_len); -+ -+ /* TODO: properly process request and store copy */ -+ if (curr_noa_len > 0) -+ return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; -+ -+ return P2P_SC_SUCCESS; -+} -+ -+ -+unsigned int p2p_get_group_num_members(struct p2p_group *group) -+{ -+ return group->num_members; -+} -+ -+ -+const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next) -+{ -+ struct p2p_group_member *iter = *next; -+ -+ if (!iter) -+ iter = group->members; -+ else -+ iter = iter->next; -+ -+ *next = iter; -+ -+ if (!iter) -+ return NULL; -+ -+ return iter->addr; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_i.h -new file mode 100644 -index 0000000000000..68b1194062db0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_i.h -@@ -0,0 +1,638 @@ -+/* -+ * P2P - Internal definitions for P2P module -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef P2P_I_H -+#define P2P_I_H -+ -+#include "utils/list.h" -+#include "p2p.h" -+ -+/* TODO: add removal of expired P2P device entries */ -+ -+enum p2p_go_state { -+ UNKNOWN_GO, -+ LOCAL_GO, -+ REMOTE_GO -+}; -+ -+/** -+ * struct p2p_device - P2P Device data (internal to P2P module) -+ */ -+struct p2p_device { -+ struct dl_list list; -+ struct os_time last_seen; -+ int listen_freq; -+ int level; -+ enum p2p_wps_method wps_method; -+ -+ struct p2p_peer_info info; -+ -+ /* -+ * If the peer was discovered based on an interface address (e.g., GO -+ * from Beacon/Probe Response), the interface address is stored here. -+ * p2p_device_addr must still be set in such a case to the unique -+ * identifier for the P2P Device. -+ */ -+ u8 interface_addr[ETH_ALEN]; -+ -+ /* -+ * P2P Device Address of the GO in whose group this P2P Device is a -+ * client. -+ */ -+ u8 member_in_go_dev[ETH_ALEN]; -+ -+ /* -+ * P2P Interface Address of the GO in whose group this P2P Device is a -+ * client. -+ */ -+ u8 member_in_go_iface[ETH_ALEN]; -+ -+ int go_neg_req_sent; -+ enum p2p_go_state go_state; -+ u8 dialog_token; -+ u8 intended_addr[ETH_ALEN]; -+ -+ char country[3]; -+ struct p2p_channels channels; -+ int oper_freq; -+ u8 oper_ssid[32]; -+ size_t oper_ssid_len; -+ -+ /** -+ * req_config_methods - Pending provisioning discovery methods -+ */ -+ u16 req_config_methods; -+ -+#define P2P_DEV_PROBE_REQ_ONLY BIT(0) -+#define P2P_DEV_REPORTED BIT(1) -+#define P2P_DEV_NOT_YET_READY BIT(2) -+#define P2P_DEV_SD_INFO BIT(3) -+#define P2P_DEV_SD_SCHEDULE BIT(4) -+#define P2P_DEV_PD_PEER_DISPLAY BIT(5) -+#define P2P_DEV_PD_PEER_KEYPAD BIT(6) -+#define P2P_DEV_USER_REJECTED BIT(7) -+#define P2P_DEV_PEER_WAITING_RESPONSE BIT(8) -+#define P2P_DEV_PREFER_PERSISTENT_GROUP BIT(9) -+#define P2P_DEV_WAIT_GO_NEG_RESPONSE BIT(10) -+#define P2P_DEV_WAIT_GO_NEG_CONFIRM BIT(11) -+#define P2P_DEV_GROUP_CLIENT_ONLY BIT(12) -+#define P2P_DEV_FORCE_FREQ BIT(13) -+#define P2P_DEV_PD_FOR_JOIN BIT(14) -+#define P2P_DEV_REPORTED_ONCE BIT(15) -+ unsigned int flags; -+ -+ int status; /* enum p2p_status_code */ -+ unsigned int wait_count; -+ unsigned int connect_reqs; -+ unsigned int invitation_reqs; -+ -+ u16 ext_listen_period; -+ u16 ext_listen_interval; -+ -+ u8 go_timeout; -+ u8 client_timeout; -+}; -+ -+struct p2p_sd_query { -+ struct p2p_sd_query *next; -+ u8 peer[ETH_ALEN]; -+ int for_all_peers; -+ struct wpabuf *tlvs; -+}; -+ -+struct p2p_pending_action_tx { -+ unsigned int freq; -+ u8 dst[ETH_ALEN]; -+ u8 src[ETH_ALEN]; -+ u8 bssid[ETH_ALEN]; -+ size_t len; -+ unsigned int wait_time; -+ /* Followed by len octets of the frame */ -+}; -+ -+/** -+ * struct p2p_data - P2P module data (internal to P2P module) -+ */ -+struct p2p_data { -+ /** -+ * cfg - P2P module configuration -+ * -+ * This is included in the same memory allocation with the -+ * struct p2p_data and as such, must not be freed separately. -+ */ -+ struct p2p_config *cfg; -+ -+ /** -+ * state - The current P2P state -+ */ -+ enum p2p_state { -+ /** -+ * P2P_IDLE - Idle -+ */ -+ P2P_IDLE, -+ -+ /** -+ * P2P_SEARCH - Search (Device Discovery) -+ */ -+ P2P_SEARCH, -+ -+ /** -+ * P2P_CONNECT - Trying to start GO Negotiation -+ */ -+ P2P_CONNECT, -+ -+ /** -+ * P2P_CONNECT_LISTEN - Listen during GO Negotiation start -+ */ -+ P2P_CONNECT_LISTEN, -+ -+ /** -+ * P2P_GO_NEG - In GO Negotiation -+ */ -+ P2P_GO_NEG, -+ -+ /** -+ * P2P_LISTEN_ONLY - Listen only -+ */ -+ P2P_LISTEN_ONLY, -+ -+ /** -+ * P2P_WAIT_PEER_CONNECT - Waiting peer in List for GO Neg -+ */ -+ P2P_WAIT_PEER_CONNECT, -+ -+ /** -+ * P2P_WAIT_PEER_IDLE - Waiting peer idle for GO Neg -+ */ -+ P2P_WAIT_PEER_IDLE, -+ -+ /** -+ * P2P_SD_DURING_FIND - Service Discovery during find -+ */ -+ P2P_SD_DURING_FIND, -+ -+ /** -+ * P2P_PROVISIONING - Provisioning (during group formation) -+ */ -+ P2P_PROVISIONING, -+ -+ /** -+ * P2P_PD_DURING_FIND - Provision Discovery during find -+ */ -+ P2P_PD_DURING_FIND, -+ -+ /** -+ * P2P_INVITE - Trying to start Invite -+ */ -+ P2P_INVITE, -+ -+ /** -+ * P2P_INVITE_LISTEN - Listen during Invite -+ */ -+ P2P_INVITE_LISTEN, -+ } state; -+ -+ /** -+ * min_disc_int - minDiscoverableInterval -+ */ -+ int min_disc_int; -+ -+ /** -+ * max_disc_int - maxDiscoverableInterval -+ */ -+ int max_disc_int; -+ -+ /** -+ * devices - List of known P2P Device peers -+ */ -+ struct dl_list devices; -+ -+ /** -+ * go_neg_peer - Pointer to GO Negotiation peer -+ */ -+ struct p2p_device *go_neg_peer; -+ -+ /** -+ * invite_peer - Pointer to Invite peer -+ */ -+ struct p2p_device *invite_peer; -+ -+ const u8 *invite_go_dev_addr; -+ u8 invite_go_dev_addr_buf[ETH_ALEN]; -+ -+ /** -+ * sd_peer - Pointer to Service Discovery peer -+ */ -+ struct p2p_device *sd_peer; -+ -+ /** -+ * sd_query - Pointer to Service Discovery query -+ */ -+ struct p2p_sd_query *sd_query; -+ -+ /* GO Negotiation data */ -+ -+ /** -+ * intended_addr - Local Intended P2P Interface Address -+ * -+ * This address is used during group owner negotiation as the Intended -+ * P2P Interface Address and the group interface will be created with -+ * address as the local address in case of successfully completed -+ * negotiation. -+ */ -+ u8 intended_addr[ETH_ALEN]; -+ -+ /** -+ * go_intent - Local GO Intent to be used during GO Negotiation -+ */ -+ u8 go_intent; -+ -+ /** -+ * next_tie_breaker - Next tie-breaker value to use in GO Negotiation -+ */ -+ u8 next_tie_breaker; -+ -+ /** -+ * ssid - Selected SSID for GO Negotiation (if local end will be GO) -+ */ -+ u8 ssid[32]; -+ -+ /** -+ * ssid_len - ssid length in octets -+ */ -+ size_t ssid_len; -+ -+ /** -+ * Regulatory class for own operational channel -+ */ -+ u8 op_reg_class; -+ -+ /** -+ * op_channel - Own operational channel -+ */ -+ u8 op_channel; -+ -+ /** -+ * channels - Own supported regulatory classes and channels -+ * -+ * List of supposerted channels per regulatory class. The regulatory -+ * classes are defined in IEEE Std 802.11-2007 Annex J and the -+ * numbering of the clases depends on the configured country code. -+ */ -+ struct p2p_channels channels; -+ -+ enum p2p_pending_action_state { -+ P2P_NO_PENDING_ACTION, -+ P2P_PENDING_GO_NEG_REQUEST, -+ P2P_PENDING_GO_NEG_RESPONSE, -+ P2P_PENDING_GO_NEG_RESPONSE_FAILURE, -+ P2P_PENDING_GO_NEG_CONFIRM, -+ P2P_PENDING_SD, -+ P2P_PENDING_PD, -+ P2P_PENDING_INVITATION_REQUEST, -+ P2P_PENDING_INVITATION_RESPONSE, -+ P2P_PENDING_DEV_DISC_REQUEST, -+ P2P_PENDING_DEV_DISC_RESPONSE, -+ P2P_PENDING_GO_DISC_REQ -+ } pending_action_state; -+ -+ unsigned int pending_listen_freq; -+ unsigned int pending_listen_sec; -+ unsigned int pending_listen_usec; -+ -+ u8 dev_capab; -+ -+ int in_listen; -+ int drv_in_listen; -+ -+ /** -+ * sd_queries - Pending service discovery queries -+ */ -+ struct p2p_sd_query *sd_queries; -+ -+ /** -+ * srv_update_indic - Service Update Indicator for local services -+ */ -+ u16 srv_update_indic; -+ -+ struct wpabuf *sd_resp; /* Fragmented SD response */ -+ u8 sd_resp_addr[ETH_ALEN]; -+ u8 sd_resp_dialog_token; -+ size_t sd_resp_pos; /* Offset in sd_resp */ -+ u8 sd_frag_id; -+ -+ struct wpabuf *sd_rx_resp; /* Reassembled SD response */ -+ u16 sd_rx_update_indic; -+ -+ /* P2P Invitation data */ -+ enum p2p_invite_role inv_role; -+ u8 inv_bssid[ETH_ALEN]; -+ int inv_bssid_set; -+ u8 inv_ssid[32]; -+ size_t inv_ssid_len; -+ u8 inv_sa[ETH_ALEN]; -+ u8 inv_group_bssid[ETH_ALEN]; -+ u8 *inv_group_bssid_ptr; -+ u8 inv_go_dev_addr[ETH_ALEN]; -+ u8 inv_status; -+ int inv_op_freq; -+ int inv_persistent; -+ -+ enum p2p_discovery_type find_type; -+ u8 last_prog_scan_class; -+ u8 last_prog_scan_chan; -+ int p2p_scan_running; -+ enum p2p_after_scan { -+ P2P_AFTER_SCAN_NOTHING, -+ P2P_AFTER_SCAN_LISTEN, -+ P2P_AFTER_SCAN_CONNECT -+ } start_after_scan; -+ u8 after_scan_peer[ETH_ALEN]; -+ struct p2p_pending_action_tx *after_scan_tx; -+ -+ /* Requested device types for find/search */ -+ unsigned int num_req_dev_types; -+ u8 *req_dev_types; -+ -+ struct p2p_group **groups; -+ size_t num_groups; -+ -+ struct p2p_device *pending_client_disc_go; -+ u8 pending_client_disc_addr[ETH_ALEN]; -+ u8 pending_dev_disc_dialog_token; -+ u8 pending_dev_disc_addr[ETH_ALEN]; -+ int pending_dev_disc_freq; -+ unsigned int pending_client_disc_freq; -+ -+ int ext_listen_only; -+ unsigned int ext_listen_period; -+ unsigned int ext_listen_interval; -+ unsigned int ext_listen_interval_sec; -+ unsigned int ext_listen_interval_usec; -+ -+ u8 peer_filter[ETH_ALEN]; -+ -+ int cross_connect; -+ -+ int best_freq_24; -+ int best_freq_5; -+ int best_freq_overall; -+ -+ /** -+ * wps_vendor_ext - WPS Vendor Extensions to add -+ */ -+ struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; -+}; -+ -+/** -+ * struct p2p_message - Parsed P2P message (or P2P IE) -+ */ -+struct p2p_message { -+ struct wpabuf *p2p_attributes; -+ struct wpabuf *wps_attributes; -+ -+ u8 dialog_token; -+ -+ const u8 *capability; -+ const u8 *go_intent; -+ const u8 *status; -+ const u8 *listen_channel; -+ const u8 *operating_channel; -+ const u8 *channel_list; -+ u8 channel_list_len; -+ const u8 *config_timeout; -+ const u8 *intended_addr; -+ const u8 *group_bssid; -+ const u8 *invitation_flags; -+ -+ const u8 *group_info; -+ size_t group_info_len; -+ -+ const u8 *group_id; -+ size_t group_id_len; -+ -+ const u8 *device_id; -+ -+ const u8 *manageability; -+ -+ const u8 *noa; -+ size_t noa_len; -+ -+ const u8 *ext_listen_timing; -+ -+ const u8 *minor_reason_code; -+ -+ /* P2P Device Info */ -+ const u8 *p2p_device_info; -+ size_t p2p_device_info_len; -+ const u8 *p2p_device_addr; -+ const u8 *pri_dev_type; -+ u8 num_sec_dev_types; -+ char device_name[33]; -+ u16 config_methods; -+ -+ /* WPS IE */ -+ u16 dev_password_id; -+ u16 wps_config_methods; -+ const u8 *wps_pri_dev_type; -+ const u8 *wps_sec_dev_type_list; -+ size_t wps_sec_dev_type_list_len; -+ const u8 *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; -+ size_t wps_vendor_ext_len[P2P_MAX_WPS_VENDOR_EXT]; -+ const u8 *manufacturer; -+ size_t manufacturer_len; -+ const u8 *model_name; -+ size_t model_name_len; -+ const u8 *model_number; -+ size_t model_number_len; -+ const u8 *serial_number; -+ size_t serial_number_len; -+ -+ /* DS Parameter Set IE */ -+ const u8 *ds_params; -+ -+ /* SSID IE */ -+ const u8 *ssid; -+}; -+ -+ -+#define P2P_MAX_GROUP_ENTRIES 50 -+ -+struct p2p_group_info { -+ unsigned int num_clients; -+ struct p2p_client_info { -+ const u8 *p2p_device_addr; -+ const u8 *p2p_interface_addr; -+ u8 dev_capab; -+ u16 config_methods; -+ const u8 *pri_dev_type; -+ u8 num_sec_dev_types; -+ const u8 *sec_dev_types; -+ const char *dev_name; -+ size_t dev_name_len; -+ } client[P2P_MAX_GROUP_ENTRIES]; -+}; -+ -+ -+/* p2p_utils.c */ -+int p2p_random(char *buf, size_t len); -+int p2p_channel_to_freq(const char *country, int reg_class, int channel); -+int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class, -+ u8 *channel); -+void p2p_channels_intersect(const struct p2p_channels *a, -+ const struct p2p_channels *b, -+ struct p2p_channels *res); -+int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class, -+ u8 channel); -+ -+/* p2p_parse.c */ -+int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg); -+int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg); -+int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg); -+void p2p_parse_free(struct p2p_message *msg); -+int p2p_attr_text(struct wpabuf *data, char *buf, char *end); -+int p2p_group_info_parse(const u8 *gi, size_t gi_len, -+ struct p2p_group_info *info); -+ -+/* p2p_build.c */ -+ -+struct p2p_noa_desc { -+ u8 count_type; -+ u32 duration; -+ u32 interval; -+ u32 start_time; -+}; -+ -+/* p2p_group.c */ -+const u8 * p2p_group_get_interface_addr(struct p2p_group *group); -+u8 p2p_group_presence_req(struct p2p_group *group, -+ const u8 *client_interface_addr, -+ const u8 *noa, size_t noa_len); -+ -+ -+void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token); -+void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype, -+ u8 dialog_token); -+u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf); -+void p2p_buf_add_status(struct wpabuf *buf, u8 status); -+void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p, -+ struct p2p_device *peer); -+void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr); -+void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len); -+void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab); -+void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent); -+void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, -+ u8 reg_class, u8 channel); -+void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, -+ u8 reg_class, u8 channel); -+void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, -+ struct p2p_channels *chan); -+void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, -+ u8 client_timeout); -+void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr); -+void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid); -+void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr, -+ const u8 *ssid, size_t ssid_len); -+void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags); -+void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow, -+ struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2); -+void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period, -+ u16 interval); -+void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p); -+void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, u16 pw_id, -+ int all_attr); -+ -+/* p2p_sd.c */ -+struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, -+ struct p2p_device *dev); -+void p2p_free_sd_queries(struct p2p_data *p2p); -+void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev); -+ -+/* p2p_go_neg.c */ -+int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own, -+ struct p2p_device *dev, -+ const u8 *channel_list, size_t channel_list_len); -+void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len); -+int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev); -+ -+/* p2p_pd.c */ -+void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len); -+int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, -+ int join); -+ -+/* p2p_invitation.c */ -+void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len); -+int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, -+ const u8 *go_dev_addr); -+void p2p_invitation_req_cb(struct p2p_data *p2p, int success); -+void p2p_invitation_resp_cb(struct p2p_data *p2p, int success); -+ -+/* p2p_dev_disc.c */ -+void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success); -+int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev); -+void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success); -+void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len); -+void p2p_go_disc_req_cb(struct p2p_data *p2p, int success); -+void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq); -+ -+/* p2p.c */ -+void p2p_set_state(struct p2p_data *p2p, int new_state); -+void p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, -+ unsigned int usec); -+void p2p_clear_timeout(struct p2p_data *p2p); -+void p2p_continue_find(struct p2p_data *p2p); -+struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, -+ const u8 *addr, -+ struct p2p_message *msg); -+void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, -+ struct p2p_device *dev, struct p2p_message *msg); -+struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr); -+struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, -+ const u8 *addr); -+void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer, -+ int status); -+void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer); -+int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps); -+int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[], -+ size_t num_req_dev_type); -+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p); -+void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len); -+int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, -+ const u8 *src, const u8 *bssid, const u8 *buf, -+ size_t len, unsigned int wait_time); -+ -+#endif /* P2P_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_invitation.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_invitation.c -new file mode 100644 -index 0000000000000..bb2767d107365 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_invitation.c -@@ -0,0 +1,489 @@ -+/* -+ * Wi-Fi Direct - P2P Invitation procedure -+ * Copyright (c) 2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "p2p_i.h" -+#include "p2p.h" -+ -+ -+static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, -+ struct p2p_device *peer, -+ const u8 *go_dev_addr) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ const u8 *dev_addr; -+ -+ buf = wpabuf_alloc(1000); -+ if (buf == NULL) -+ return NULL; -+ -+ peer->dialog_token++; -+ if (peer->dialog_token == 0) -+ peer->dialog_token = 1; -+ p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_REQ, -+ peer->dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent) -+ p2p_buf_add_config_timeout(buf, 0, 0); -+ else -+ p2p_buf_add_config_timeout(buf, 100, 20); -+ p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ? -+ P2P_INVITATION_FLAGS_TYPE : 0); -+ p2p_buf_add_operating_channel(buf, p2p->cfg->country, -+ p2p->op_reg_class, p2p->op_channel); -+ if (p2p->inv_bssid_set) -+ p2p_buf_add_group_bssid(buf, p2p->inv_bssid); -+ p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); -+ if (go_dev_addr) -+ dev_addr = go_dev_addr; -+ else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) -+ dev_addr = peer->info.p2p_device_addr; -+ else -+ dev_addr = p2p->cfg->dev_addr; -+ p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len); -+ p2p_buf_add_device_info(buf, p2p, peer); -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ return buf; -+} -+ -+ -+static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, -+ struct p2p_device *peer, -+ u8 dialog_token, u8 status, -+ const u8 *group_bssid, -+ u8 reg_class, u8 channel, -+ struct p2p_channels *channels) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ -+ buf = wpabuf_alloc(1000); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_RESP, -+ dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ p2p_buf_add_status(buf, status); -+ p2p_buf_add_config_timeout(buf, 0, 0); /* FIX */ -+ if (reg_class && channel) -+ p2p_buf_add_operating_channel(buf, p2p->cfg->country, -+ reg_class, channel); -+ if (group_bssid) -+ p2p_buf_add_group_bssid(buf, group_bssid); -+ if (channels) -+ p2p_buf_add_channel_list(buf, p2p->cfg->country, channels); -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ return buf; -+} -+ -+ -+void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ struct p2p_device *dev; -+ struct p2p_message msg; -+ struct wpabuf *resp = NULL; -+ u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; -+ int freq; -+ int go = 0; -+ u8 group_bssid[ETH_ALEN], *bssid; -+ int op_freq = 0; -+ u8 reg_class = 0, channel = 0; -+ struct p2p_channels intersection, *channels = NULL; -+ int persistent; -+ -+ os_memset(group_bssid, 0, sizeof(group_bssid)); -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received Invitation Request from " MACSTR " (freq=%d)", -+ MAC2STR(sa), rx_freq); -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ dev = p2p_get_device(p2p, sa); -+ if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invitation Request from unknown peer " -+ MACSTR, MAC2STR(sa)); -+ -+ if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invitation Request add device failed " -+ MACSTR, MAC2STR(sa)); -+ status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; -+ goto fail; -+ } -+ -+ dev = p2p_get_device(p2p, sa); -+ if (dev == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Reject Invitation Request from unknown " -+ "peer " MACSTR, MAC2STR(sa)); -+ status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; -+ goto fail; -+ } -+ } -+ -+ if (!msg.group_id || !msg.channel_list) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory attribute missing in Invitation " -+ "Request from " MACSTR, MAC2STR(sa)); -+ status = P2P_SC_FAIL_INVALID_PARAMS; -+ goto fail; -+ } -+ -+ if (msg.invitation_flags) -+ persistent = *msg.invitation_flags & P2P_INVITATION_FLAGS_TYPE; -+ else { -+ /* Invitation Flags is a mandatory attribute starting from P2P -+ * spec 1.06. As a backwards compatibility mechanism, assume -+ * the request was for a persistent group if the attribute is -+ * missing. -+ */ -+ wpa_printf(MSG_DEBUG, "P2P: Mandatory Invitation Flags " -+ "attribute missing from Invitation Request"); -+ persistent = 1; -+ } -+ -+ if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev, -+ msg.channel_list, msg.channel_list_len) < -+ 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No common channels found"); -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ goto fail; -+ } -+ -+ if (p2p->cfg->invitation_process) { -+ status = p2p->cfg->invitation_process( -+ p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id, -+ msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN, -+ &go, group_bssid, &op_freq, persistent); -+ } -+ -+ if (op_freq) { -+ if (p2p_freq_to_channel(p2p->cfg->country, op_freq, -+ ®_class, &channel) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown forced freq %d MHz from " -+ "invitation_process()", op_freq); -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ goto fail; -+ } -+ -+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels, -+ &intersection); -+ if (!p2p_channels_includes(&intersection, reg_class, channel)) -+ { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: forced freq %d MHz not in the supported " -+ "channels interaction", op_freq); -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ goto fail; -+ } -+ -+ if (status == P2P_SC_SUCCESS) -+ channels = &intersection; -+ } else { -+ op_freq = p2p_channel_to_freq(p2p->cfg->country, -+ p2p->cfg->op_reg_class, -+ p2p->cfg->op_channel); -+ if (op_freq < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown operational channel " -+ "(country=%c%c reg_class=%u channel=%u)", -+ p2p->cfg->country[0], p2p->cfg->country[1], -+ p2p->cfg->op_reg_class, p2p->cfg->op_channel); -+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS; -+ goto fail; -+ } -+ -+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels, -+ &intersection); -+ if (status == P2P_SC_SUCCESS) { -+ reg_class = p2p->cfg->op_reg_class; -+ channel = p2p->cfg->op_channel; -+ channels = &intersection; -+ } -+ } -+ -+fail: -+ if (go && status == P2P_SC_SUCCESS && !is_zero_ether_addr(group_bssid)) -+ bssid = group_bssid; -+ else -+ bssid = NULL; -+ resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status, -+ bssid, reg_class, channel, channels); -+ -+ if (resp == NULL) -+ goto out; -+ -+ if (rx_freq > 0) -+ freq = rx_freq; -+ else -+ freq = p2p_channel_to_freq(p2p->cfg->country, -+ p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (freq < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown regulatory class/channel"); -+ goto out; -+ } -+ -+ /* -+ * Store copy of invitation data to be used when processing TX status -+ * callback for the Acton frame. -+ */ -+ os_memcpy(p2p->inv_sa, sa, ETH_ALEN); -+ if (msg.group_bssid) { -+ os_memcpy(p2p->inv_group_bssid, msg.group_bssid, ETH_ALEN); -+ p2p->inv_group_bssid_ptr = p2p->inv_group_bssid; -+ } else -+ p2p->inv_group_bssid_ptr = NULL; -+ if (msg.group_id_len - ETH_ALEN <= 32) { -+ os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN, -+ msg.group_id_len - ETH_ALEN); -+ p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN; -+ } -+ os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN); -+ p2p->inv_status = status; -+ p2p->inv_op_freq = op_freq; -+ -+ p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE; -+ if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, -+ p2p->cfg->dev_addr, -+ wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ } -+ -+out: -+ wpabuf_free(resp); -+ p2p_parse_free(&msg); -+} -+ -+ -+void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len) -+{ -+ struct p2p_device *dev; -+ struct p2p_message msg; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received Invitation Response from " MACSTR, -+ MAC2STR(sa)); -+ -+ dev = p2p_get_device(p2p, sa); -+ if (dev == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore Invitation Response from unknown peer " -+ MACSTR, MAC2STR(sa)); -+ return; -+ } -+ -+ if (dev != p2p->invite_peer) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore unexpected Invitation Response from peer " -+ MACSTR, MAC2STR(sa)); -+ return; -+ } -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ if (!msg.status) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Mandatory Status attribute missing in " -+ "Invitation Response from " MACSTR, MAC2STR(sa)); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (p2p->cfg->invitation_result) -+ p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status, -+ msg.group_bssid); -+ -+ p2p_parse_free(&msg); -+ -+ p2p_clear_timeout(p2p); -+ p2p_set_state(p2p, P2P_IDLE); -+ p2p->invite_peer = NULL; -+} -+ -+ -+int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, -+ const u8 *go_dev_addr) -+{ -+ struct wpabuf *req; -+ int freq; -+ -+ freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; -+ if (freq <= 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Listen/Operating frequency known for the " -+ "peer " MACSTR " to send Invitation Request", -+ MAC2STR(dev->info.p2p_device_addr)); -+ return -1; -+ } -+ -+ req = p2p_build_invitation_req(p2p, dev, go_dev_addr); -+ if (req == NULL) -+ return -1; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Sending Invitation Request"); -+ p2p_set_state(p2p, P2P_INVITE); -+ p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST; -+ p2p->invite_peer = dev; -+ dev->invitation_reqs++; -+ if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, -+ p2p->cfg->dev_addr, dev->info.p2p_device_addr, -+ wpabuf_head(req), wpabuf_len(req), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ /* Use P2P find to recover and retry */ -+ p2p_set_timeout(p2p, 0, 0); -+ } -+ -+ wpabuf_free(req); -+ -+ return 0; -+} -+ -+ -+void p2p_invitation_req_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invitation Request TX callback: success=%d", success); -+ -+ if (p2p->invite_peer == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No pending Invite"); -+ return; -+ } -+ -+ /* -+ * Use P2P find, if needed, to find the other device from its listen -+ * channel. -+ */ -+ p2p_set_state(p2p, P2P_INVITE); -+ p2p_set_timeout(p2p, 0, 100000); -+} -+ -+ -+void p2p_invitation_resp_cb(struct p2p_data *p2p, int success) -+{ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invitation Response TX callback: success=%d", success); -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ -+ if (success && p2p->cfg->invitation_received) { -+ p2p->cfg->invitation_received(p2p->cfg->cb_ctx, -+ p2p->inv_sa, -+ p2p->inv_group_bssid_ptr, -+ p2p->inv_ssid, p2p->inv_ssid_len, -+ p2p->inv_go_dev_addr, -+ p2p->inv_status, -+ p2p->inv_op_freq); -+ } -+} -+ -+ -+int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, -+ const u8 *bssid, const u8 *ssid, size_t ssid_len, -+ unsigned int force_freq, const u8 *go_dev_addr, -+ int persistent_group) -+{ -+ struct p2p_device *dev; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Request to invite peer " MACSTR " role=%d persistent=%d " -+ "force_freq=%u", -+ MAC2STR(peer), role, persistent_group, force_freq); -+ if (bssid) -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invitation for BSSID " MACSTR, MAC2STR(bssid)); -+ if (go_dev_addr) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invitation for GO Device Address " MACSTR, -+ MAC2STR(go_dev_addr)); -+ os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN); -+ p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf; -+ } else -+ p2p->invite_go_dev_addr = NULL; -+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Invitation for SSID", -+ ssid, ssid_len); -+ -+ dev = p2p_get_device(p2p, peer); -+ if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cannot invite unknown P2P Device " MACSTR, -+ MAC2STR(peer)); -+ return -1; -+ } -+ -+ if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { -+ if (!(dev->info.dev_capab & -+ P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cannot invite a P2P Device " MACSTR -+ " that is in a group and is not discoverable", -+ MAC2STR(peer)); -+ } -+ /* TODO: use device discoverability request through GO */ -+ } -+ -+ dev->invitation_reqs = 0; -+ -+ if (force_freq) { -+ if (p2p_freq_to_channel(p2p->cfg->country, force_freq, -+ &p2p->op_reg_class, &p2p->op_channel) < -+ 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported frequency %u MHz", -+ force_freq); -+ return -1; -+ } -+ p2p->channels.reg_classes = 1; -+ p2p->channels.reg_class[0].channels = 1; -+ p2p->channels.reg_class[0].reg_class = p2p->op_reg_class; -+ p2p->channels.reg_class[0].channel[0] = p2p->op_channel; -+ } else { -+ p2p->op_reg_class = p2p->cfg->op_reg_class; -+ p2p->op_channel = p2p->cfg->op_channel; -+ os_memcpy(&p2p->channels, &p2p->cfg->channels, -+ sizeof(struct p2p_channels)); -+ } -+ -+ if (p2p->state != P2P_IDLE) -+ p2p_stop_find(p2p); -+ -+ p2p->inv_role = role; -+ p2p->inv_bssid_set = bssid != NULL; -+ if (bssid) -+ os_memcpy(p2p->inv_bssid, bssid, ETH_ALEN); -+ os_memcpy(p2p->inv_ssid, ssid, ssid_len); -+ p2p->inv_ssid_len = ssid_len; -+ p2p->inv_persistent = persistent_group; -+ return p2p_invite_send(p2p, dev, go_dev_addr); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_parse.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_parse.c -new file mode 100644 -index 0000000000000..5c5445a5a145b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_parse.c -@@ -0,0 +1,718 @@ -+/* -+ * P2P - IE parser -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "wps/wps_i.h" -+#include "p2p_i.h" -+ -+ -+static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, -+ struct p2p_message *msg) -+{ -+ const u8 *pos; -+ size_t i, nlen; -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ -+ switch (id) { -+ case P2P_ATTR_CAPABILITY: -+ if (len < 2) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Capability " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->capability = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x " -+ "Group Capability %02x", -+ data[0], data[1]); -+ break; -+ case P2P_ATTR_DEVICE_ID: -+ if (len < ETH_ALEN) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Device ID " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->device_id = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR, -+ MAC2STR(msg->device_id)); -+ break; -+ case P2P_ATTR_GROUP_OWNER_INTENT: -+ if (len < 1) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->go_intent = data; -+ wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u " -+ "Tie breaker %u", data[0] >> 1, data[0] & 0x01); -+ break; -+ case P2P_ATTR_STATUS: -+ if (len < 1) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Status " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->status = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]); -+ break; -+ case P2P_ATTR_LISTEN_CHANNEL: -+ if (len == 0) { -+ wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore " -+ "null channel"); -+ break; -+ } -+ if (len < 5) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->listen_channel = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: " -+ "Country %c%c(0x%02x) Regulatory " -+ "Class %d Channel Number %d", data[0], data[1], -+ data[2], data[3], data[4]); -+ break; -+ case P2P_ATTR_OPERATING_CHANNEL: -+ if (len == 0) { -+ wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " -+ "Ignore null channel"); -+ break; -+ } -+ if (len < 5) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Operating " -+ "Channel attribute (length %d)", len); -+ return -1; -+ } -+ msg->operating_channel = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " -+ "Country %c%c(0x%02x) Regulatory " -+ "Class %d Channel Number %d", data[0], data[1], -+ data[2], data[3], data[4]); -+ break; -+ case P2P_ATTR_CHANNEL_LIST: -+ if (len < 3) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Channel List " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->channel_list = data; -+ msg->channel_list_len = len; -+ wpa_printf(MSG_DEBUG, "P2P: * Channel List: Country String " -+ "'%c%c(0x%02x)'", data[0], data[1], data[2]); -+ wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List", -+ msg->channel_list, msg->channel_list_len); -+ break; -+ case P2P_ATTR_GROUP_INFO: -+ msg->group_info = data; -+ msg->group_info_len = len; -+ wpa_printf(MSG_DEBUG, "P2P: * Group Info"); -+ break; -+ case P2P_ATTR_DEVICE_INFO: -+ if (len < ETH_ALEN + 2 + 8 + 1) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Device Info " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->p2p_device_info = data; -+ msg->p2p_device_info_len = len; -+ pos = data; -+ msg->p2p_device_addr = pos; -+ pos += ETH_ALEN; -+ msg->config_methods = WPA_GET_BE16(pos); -+ pos += 2; -+ msg->pri_dev_type = pos; -+ pos += 8; -+ msg->num_sec_dev_types = *pos++; -+ if (msg->num_sec_dev_types * 8 > data + len - pos) { -+ wpa_printf(MSG_DEBUG, "P2P: Device Info underflow"); -+ return -1; -+ } -+ pos += msg->num_sec_dev_types * 8; -+ if (data + len - pos < 4) { -+ wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " -+ "length %d", (int) (data + len - pos)); -+ return -1; -+ } -+ if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) { -+ wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name " -+ "header", pos, 4); -+ return -1; -+ } -+ pos += 2; -+ nlen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (data + len - pos < (int) nlen || nlen > 32) { -+ wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " -+ "length %d (buf len %d)", (int) nlen, -+ (int) (data + len - pos)); -+ return -1; -+ } -+ os_memcpy(msg->device_name, pos, nlen); -+ msg->device_name[nlen] = '\0'; -+ for (i = 0; i < nlen; i++) { -+ if (msg->device_name[i] == '\0') -+ break; -+ if (msg->device_name[i] > 0 && -+ msg->device_name[i] < 32) -+ msg->device_name[i] = '_'; -+ } -+ wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR -+ " primary device type %s device name '%s' " -+ "config methods 0x%x", -+ MAC2STR(msg->p2p_device_addr), -+ wps_dev_type_bin2str(msg->pri_dev_type, devtype, -+ sizeof(devtype)), -+ msg->device_name, msg->config_methods); -+ break; -+ case P2P_ATTR_CONFIGURATION_TIMEOUT: -+ if (len < 2) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Configuration " -+ "Timeout attribute (length %d)", len); -+ return -1; -+ } -+ msg->config_timeout = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout"); -+ break; -+ case P2P_ATTR_INTENDED_INTERFACE_ADDR: -+ if (len < ETH_ALEN) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P " -+ "Interface Address attribute (length %d)", -+ len); -+ return -1; -+ } -+ msg->intended_addr = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: " -+ MACSTR, MAC2STR(msg->intended_addr)); -+ break; -+ case P2P_ATTR_GROUP_BSSID: -+ if (len < ETH_ALEN) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->group_bssid = data; -+ wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR, -+ MAC2STR(msg->group_bssid)); -+ break; -+ case P2P_ATTR_GROUP_ID: -+ if (len < ETH_ALEN || len > ETH_ALEN + 32) { -+ wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID " -+ "attribute length %d", len); -+ return -1; -+ } -+ msg->group_id = data; -+ msg->group_id_len = len; -+ wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address " -+ MACSTR, MAC2STR(msg->group_id)); -+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID", -+ msg->group_id + ETH_ALEN, -+ msg->group_id_len - ETH_ALEN); -+ break; -+ case P2P_ATTR_INVITATION_FLAGS: -+ if (len < 1) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Invitation " -+ "Flag attribute (length %d)", len); -+ return -1; -+ } -+ msg->invitation_flags = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", -+ data[0]); -+ break; -+ case P2P_ATTR_MANAGEABILITY: -+ if (len < 1) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Manageability " -+ "attribute (length %d)", len); -+ return -1; -+ } -+ msg->manageability = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x", -+ data[0]); -+ break; -+ case P2P_ATTR_NOTICE_OF_ABSENCE: -+ if (len < 2) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Notice of " -+ "Absence attribute (length %d)", len); -+ return -1; -+ } -+ msg->noa = data; -+ msg->noa_len = len; -+ wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); -+ break; -+ case P2P_ATTR_EXT_LISTEN_TIMING: -+ if (len < 4) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen " -+ "Timing attribute (length %d)", len); -+ return -1; -+ } -+ msg->ext_listen_timing = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing " -+ "(period %u msec interval %u msec)", -+ WPA_GET_LE16(msg->ext_listen_timing), -+ WPA_GET_LE16(msg->ext_listen_timing + 2)); -+ break; -+ case P2P_ATTR_MINOR_REASON_CODE: -+ if (len < 1) { -+ wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason " -+ "Code attribute (length %d)", len); -+ return -1; -+ } -+ msg->minor_reason_code = data; -+ wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u", -+ *msg->minor_reason_code); -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " -+ "(length %d)", id, len); -+ break; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * p2p_parse_p2p_ie - Parse P2P IE -+ * @buf: Concatenated P2P IE(s) payload -+ * @msg: Buffer for returning parsed attributes -+ * Returns: 0 on success, -1 on failure -+ * -+ * Note: Caller is responsible for clearing the msg data structure before -+ * calling this function. -+ */ -+int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg) -+{ -+ const u8 *pos = wpabuf_head_u8(buf); -+ const u8 *end = pos + wpabuf_len(buf); -+ -+ wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE"); -+ -+ while (pos < end) { -+ u16 attr_len; -+ if (pos + 2 >= end) { -+ wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute"); -+ return -1; -+ } -+ attr_len = WPA_GET_LE16(pos + 1); -+ wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u", -+ pos[0], attr_len); -+ if (pos + 3 + attr_len > end) { -+ wpa_printf(MSG_DEBUG, "P2P: Attribute underflow " -+ "(len=%u left=%d)", -+ attr_len, (int) (end - pos - 3)); -+ wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos); -+ return -1; -+ } -+ if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg)) -+ return -1; -+ pos += 3 + attr_len; -+ } -+ -+ return 0; -+} -+ -+ -+static int p2p_parse_wps_ie(const struct wpabuf *buf, struct p2p_message *msg) -+{ -+ struct wps_parse_attr attr; -+ int i; -+ -+ wpa_printf(MSG_DEBUG, "P2P: Parsing WPS IE"); -+ if (wps_parse_msg(buf, &attr)) -+ return -1; -+ if (attr.dev_name && attr.dev_name_len < sizeof(msg->device_name) && -+ !msg->device_name[0]) -+ os_memcpy(msg->device_name, attr.dev_name, attr.dev_name_len); -+ if (attr.config_methods) { -+ msg->wps_config_methods = -+ WPA_GET_BE16(attr.config_methods); -+ wpa_printf(MSG_DEBUG, "P2P: Config Methods (WPS): 0x%x", -+ msg->wps_config_methods); -+ } -+ if (attr.dev_password_id) { -+ msg->dev_password_id = WPA_GET_BE16(attr.dev_password_id); -+ wpa_printf(MSG_DEBUG, "P2P: Device Password ID: %d", -+ msg->dev_password_id); -+ } -+ if (attr.primary_dev_type) { -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ msg->wps_pri_dev_type = attr.primary_dev_type; -+ wpa_printf(MSG_DEBUG, "P2P: Primary Device Type (WPS): %s", -+ wps_dev_type_bin2str(msg->wps_pri_dev_type, devtype, -+ sizeof(devtype))); -+ } -+ if (attr.sec_dev_type_list) { -+ msg->wps_sec_dev_type_list = attr.sec_dev_type_list; -+ msg->wps_sec_dev_type_list_len = attr.sec_dev_type_list_len; -+ } -+ -+ for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { -+ msg->wps_vendor_ext[i] = attr.vendor_ext[i]; -+ msg->wps_vendor_ext_len[i] = attr.vendor_ext_len[i]; -+ } -+ -+ msg->manufacturer = attr.manufacturer; -+ msg->manufacturer_len = attr.manufacturer_len; -+ msg->model_name = attr.model_name; -+ msg->model_name_len = attr.model_name_len; -+ msg->model_number = attr.model_number; -+ msg->model_number_len = attr.model_number_len; -+ msg->serial_number = attr.serial_number; -+ msg->serial_number_len = attr.serial_number_len; -+ -+ return 0; -+} -+ -+ -+/** -+ * p2p_parse_ies - Parse P2P message IEs (both WPS and P2P IE) -+ * @data: IEs from the message -+ * @len: Length of data buffer in octets -+ * @msg: Buffer for returning parsed attributes -+ * Returns: 0 on success, -1 on failure -+ * -+ * Note: Caller is responsible for clearing the msg data structure before -+ * calling this function. -+ * -+ * Note: Caller must free temporary memory allocations by calling -+ * p2p_parse_free() when the parsed data is not needed anymore. -+ */ -+int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) -+{ -+ struct ieee802_11_elems elems; -+ -+ ieee802_11_parse_elems(data, len, &elems, 0); -+ if (elems.ds_params && elems.ds_params_len >= 1) -+ msg->ds_params = elems.ds_params; -+ if (elems.ssid) -+ msg->ssid = elems.ssid - 2; -+ -+ msg->wps_attributes = ieee802_11_vendor_ie_concat(data, len, -+ WPS_DEV_OUI_WFA); -+ if (msg->wps_attributes && -+ p2p_parse_wps_ie(msg->wps_attributes, msg)) { -+ p2p_parse_free(msg); -+ return -1; -+ } -+ -+ msg->p2p_attributes = ieee802_11_vendor_ie_concat(data, len, -+ P2P_IE_VENDOR_TYPE); -+ if (msg->p2p_attributes && -+ p2p_parse_p2p_ie(msg->p2p_attributes, msg)) { -+ wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data"); -+ if (msg->p2p_attributes) -+ wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data", -+ msg->p2p_attributes); -+ p2p_parse_free(msg); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * p2p_parse - Parse a P2P Action frame contents -+ * @data: Action frame payload after Category and Code fields -+ * @len: Length of data buffer in octets -+ * @msg: Buffer for returning parsed attributes -+ * Returns: 0 on success, -1 on failure -+ * -+ * Note: Caller must free temporary memory allocations by calling -+ * p2p_parse_free() when the parsed data is not needed anymore. -+ */ -+int p2p_parse(const u8 *data, size_t len, struct p2p_message *msg) -+{ -+ os_memset(msg, 0, sizeof(*msg)); -+ wpa_printf(MSG_DEBUG, "P2P: Parsing the received message"); -+ if (len < 1) { -+ wpa_printf(MSG_DEBUG, "P2P: No Dialog Token in the message"); -+ return -1; -+ } -+ msg->dialog_token = data[0]; -+ wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", msg->dialog_token); -+ -+ return p2p_parse_ies(data + 1, len - 1, msg); -+} -+ -+ -+/** -+ * p2p_parse_free - Free temporary data from P2P parsing -+ * @msg: Parsed attributes -+ */ -+void p2p_parse_free(struct p2p_message *msg) -+{ -+ wpabuf_free(msg->p2p_attributes); -+ msg->p2p_attributes = NULL; -+ wpabuf_free(msg->wps_attributes); -+ msg->wps_attributes = NULL; -+} -+ -+ -+int p2p_group_info_parse(const u8 *gi, size_t gi_len, -+ struct p2p_group_info *info) -+{ -+ const u8 *g, *gend; -+ -+ os_memset(info, 0, sizeof(*info)); -+ if (gi == NULL) -+ return 0; -+ -+ g = gi; -+ gend = gi + gi_len; -+ while (g < gend) { -+ struct p2p_client_info *cli; -+ const u8 *t, *cend; -+ int count; -+ -+ cli = &info->client[info->num_clients]; -+ cend = g + 1 + g[0]; -+ if (cend > gend) -+ return -1; /* invalid data */ -+ /* g at start of P2P Client Info Descriptor */ -+ /* t at Device Capability Bitmap */ -+ t = g + 1 + 2 * ETH_ALEN; -+ if (t > cend) -+ return -1; /* invalid data */ -+ cli->p2p_device_addr = g + 1; -+ cli->p2p_interface_addr = g + 1 + ETH_ALEN; -+ cli->dev_capab = t[0]; -+ -+ if (t + 1 + 2 + 8 + 1 > cend) -+ return -1; /* invalid data */ -+ -+ cli->config_methods = WPA_GET_BE16(&t[1]); -+ cli->pri_dev_type = &t[3]; -+ -+ t += 1 + 2 + 8; -+ /* t at Number of Secondary Device Types */ -+ cli->num_sec_dev_types = *t++; -+ if (t + 8 * cli->num_sec_dev_types > cend) -+ return -1; /* invalid data */ -+ cli->sec_dev_types = t; -+ t += 8 * cli->num_sec_dev_types; -+ -+ /* t at Device Name in WPS TLV format */ -+ if (t + 2 + 2 > cend) -+ return -1; /* invalid data */ -+ if (WPA_GET_BE16(t) != ATTR_DEV_NAME) -+ return -1; /* invalid Device Name TLV */ -+ t += 2; -+ count = WPA_GET_BE16(t); -+ t += 2; -+ if (count > cend - t) -+ return -1; /* invalid Device Name TLV */ -+ if (count >= 32) -+ count = 32; -+ cli->dev_name = (const char *) t; -+ cli->dev_name_len = count; -+ -+ g = cend; -+ -+ info->num_clients++; -+ if (info->num_clients == P2P_MAX_GROUP_ENTRIES) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int p2p_group_info_text(const u8 *gi, size_t gi_len, char *buf, -+ char *end) -+{ -+ char *pos = buf; -+ int ret; -+ struct p2p_group_info info; -+ unsigned int i; -+ -+ if (p2p_group_info_parse(gi, gi_len, &info) < 0) -+ return 0; -+ -+ for (i = 0; i < info.num_clients; i++) { -+ struct p2p_client_info *cli; -+ char name[33]; -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ u8 s; -+ int count; -+ -+ cli = &info.client[i]; -+ ret = os_snprintf(pos, end - pos, "p2p_group_client: " -+ "dev=" MACSTR " iface=" MACSTR, -+ MAC2STR(cli->p2p_device_addr), -+ MAC2STR(cli->p2p_interface_addr)); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ ret = os_snprintf(pos, end - pos, -+ " dev_capab=0x%x config_methods=0x%x " -+ "dev_type=%s", -+ cli->dev_capab, cli->config_methods, -+ wps_dev_type_bin2str(cli->pri_dev_type, -+ devtype, -+ sizeof(devtype))); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ for (s = 0; s < cli->num_sec_dev_types; s++) { -+ ret = os_snprintf(pos, end - pos, " dev_type=%s", -+ wps_dev_type_bin2str( -+ &cli->sec_dev_types[s * 8], -+ devtype, sizeof(devtype))); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ os_memcpy(name, cli->dev_name, cli->dev_name_len); -+ name[cli->dev_name_len] = '\0'; -+ count = (int) cli->dev_name_len - 1; -+ while (count >= 0) { -+ if (name[count] > 0 && name[count] < 32) -+ name[count] = '_'; -+ count--; -+ } -+ -+ ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ return pos - buf; -+} -+ -+ -+/** -+ * p2p_attr_text - Build text format description of P2P IE attributes -+ * @data: P2P IE contents -+ * @buf: Buffer for returning text -+ * @end: Pointer to the end of the buf area -+ * Returns: Number of octets written to the buffer or -1 on faikure -+ * -+ * This function can be used to parse P2P IE contents into text format -+ * field=value lines. -+ */ -+int p2p_attr_text(struct wpabuf *data, char *buf, char *end) -+{ -+ struct p2p_message msg; -+ char *pos = buf; -+ int ret; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_p2p_ie(data, &msg)) -+ return -1; -+ -+ if (msg.capability) { -+ ret = os_snprintf(pos, end - pos, -+ "p2p_dev_capab=0x%x\n" -+ "p2p_group_capab=0x%x\n", -+ msg.capability[0], msg.capability[1]); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ if (msg.pri_dev_type) { -+ char devtype[WPS_DEV_TYPE_BUFSIZE]; -+ ret = os_snprintf(pos, end - pos, -+ "p2p_primary_device_type=%s\n", -+ wps_dev_type_bin2str(msg.pri_dev_type, -+ devtype, -+ sizeof(devtype))); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n", -+ msg.device_name); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ if (msg.p2p_device_addr) { -+ ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR -+ "\n", -+ MAC2STR(msg.p2p_device_addr)); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ } -+ -+ ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n", -+ msg.config_methods); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ -+ ret = p2p_group_info_text(msg.group_info, msg.group_info_len, -+ pos, end); -+ if (ret < 0) -+ return pos - buf; -+ pos += ret; -+ -+ return pos - buf; -+} -+ -+ -+int p2p_get_cross_connect_disallowed(const struct wpabuf *p2p_ie) -+{ -+ struct p2p_message msg; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_p2p_ie(p2p_ie, &msg)) -+ return 0; -+ -+ if (!msg.manageability) -+ return 0; -+ -+ return !(msg.manageability[0] & P2P_MAN_CROSS_CONNECTION_PERMITTED); -+} -+ -+ -+u8 p2p_get_group_capab(const struct wpabuf *p2p_ie) -+{ -+ struct p2p_message msg; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_p2p_ie(p2p_ie, &msg)) -+ return 0; -+ -+ if (!msg.capability) -+ return 0; -+ -+ return msg.capability[1]; -+} -+ -+ -+const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie) -+{ -+ struct p2p_message msg; -+ -+ os_memset(&msg, 0, sizeof(msg)); -+ if (p2p_parse_p2p_ie(p2p_ie, &msg)) -+ return NULL; -+ -+ if (msg.p2p_device_addr) -+ return msg.p2p_device_addr; -+ if (msg.device_id) -+ return msg.device_id; -+ -+ return NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_pd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_pd.c -new file mode 100644 -index 0000000000000..e0642168f9229 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_pd.c -@@ -0,0 +1,347 @@ -+/* -+ * Wi-Fi Direct - P2P provision discovery -+ * Copyright (c) 2009-2010, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "wps/wps_defs.h" -+#include "p2p_i.h" -+#include "p2p.h" -+ -+ -+static void p2p_build_wps_ie_config_methods(struct wpabuf *buf, -+ u16 config_methods) -+{ -+ u8 *len; -+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); -+ len = wpabuf_put(buf, 1); -+ wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); -+ -+ /* Config Methods */ -+ wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); -+ wpabuf_put_be16(buf, 2); -+ wpabuf_put_be16(buf, config_methods); -+ -+ p2p_buf_update_ie_hdr(buf, len); -+} -+ -+ -+static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, -+ u8 dialog_token, -+ u16 config_methods, -+ struct p2p_device *go) -+{ -+ struct wpabuf *buf; -+ u8 *len; -+ -+ buf = wpabuf_alloc(1000); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); -+ -+ len = p2p_buf_add_ie_hdr(buf); -+ p2p_buf_add_capability(buf, p2p->dev_capab, 0); -+ p2p_buf_add_device_info(buf, p2p, NULL); -+ if (go) { -+ p2p_buf_add_group_id(buf, go->info.p2p_device_addr, -+ go->oper_ssid, go->oper_ssid_len); -+ } -+ p2p_buf_update_ie_hdr(buf, len); -+ -+ /* WPS IE with Config Methods attribute */ -+ p2p_build_wps_ie_config_methods(buf, config_methods); -+ -+ return buf; -+} -+ -+ -+static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, -+ u8 dialog_token, -+ u16 config_methods) -+{ -+ struct wpabuf *buf; -+ -+ buf = wpabuf_alloc(100); -+ if (buf == NULL) -+ return NULL; -+ -+ p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token); -+ -+ /* WPS IE with Config Methods attribute */ -+ p2p_build_wps_ie_config_methods(buf, config_methods); -+ -+ return buf; -+} -+ -+ -+void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ struct p2p_message msg; -+ struct p2p_device *dev; -+ int freq; -+ int reject = 1; -+ struct wpabuf *resp; -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received Provision Discovery Request from " MACSTR -+ " with config methods 0x%x (freq=%d)", -+ MAC2STR(sa), msg.wps_config_methods, rx_freq); -+ -+ dev = p2p_get_device(p2p, sa); -+ if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Provision Discovery Request from " -+ "unknown peer " MACSTR, MAC2STR(sa)); -+ if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Provision Discovery Request add device " -+ "failed " MACSTR, MAC2STR(sa)); -+ } -+ } -+ -+ if (!(msg.wps_config_methods & -+ (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | -+ WPS_CONFIG_PUSHBUTTON))) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported " -+ "Config Methods in Provision Discovery Request"); -+ goto out; -+ } -+ -+ if (dev) -+ dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | -+ P2P_DEV_PD_PEER_KEYPAD); -+ if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR -+ " requested us to show a PIN on display", MAC2STR(sa)); -+ if (dev) -+ dev->flags |= P2P_DEV_PD_PEER_KEYPAD; -+ } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR -+ " requested us to write its PIN using keypad", -+ MAC2STR(sa)); -+ if (dev) -+ dev->flags |= P2P_DEV_PD_PEER_DISPLAY; -+ } -+ -+ reject = 0; -+ -+out: -+ resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token, -+ reject ? 0 : msg.wps_config_methods); -+ if (resp == NULL) { -+ p2p_parse_free(&msg); -+ return; -+ } -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Sending Provision Discovery Response"); -+ if (rx_freq > 0) -+ freq = rx_freq; -+ else -+ freq = p2p_channel_to_freq(p2p->cfg->country, -+ p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (freq < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unknown regulatory class/channel"); -+ wpabuf_free(resp); -+ p2p_parse_free(&msg); -+ return; -+ } -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, -+ p2p->cfg->dev_addr, -+ wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ } -+ -+ wpabuf_free(resp); -+ -+ if (!reject && p2p->cfg->prov_disc_req) { -+ const u8 *dev_addr = sa; -+ if (msg.p2p_device_addr) -+ dev_addr = msg.p2p_device_addr; -+ p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, -+ msg.wps_config_methods, -+ dev_addr, msg.pri_dev_type, -+ msg.device_name, msg.config_methods, -+ msg.capability ? msg.capability[0] : 0, -+ msg.capability ? msg.capability[1] : -+ 0); -+ -+ } -+ p2p_parse_free(&msg); -+} -+ -+ -+void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len) -+{ -+ struct p2p_message msg; -+ struct p2p_device *dev; -+ u16 report_config_methods = 0; -+ -+ if (p2p_parse(data, len, &msg)) -+ return; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received Provisioning Discovery Response from " MACSTR -+ " with config methods 0x%x", -+ MAC2STR(sa), msg.wps_config_methods); -+ -+ dev = p2p_get_device(p2p, sa); -+ if (dev == NULL || !dev->req_config_methods) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore Provisioning Discovery Response from " -+ MACSTR " with no pending request", MAC2STR(sa)); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (dev->dialog_token != msg.dialog_token) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore Provisioning Discovery Response with " -+ "unexpected Dialog Token %u (expected %u)", -+ msg.dialog_token, dev->dialog_token); -+ p2p_parse_free(&msg); -+ return; -+ } -+ -+ if (msg.wps_config_methods != dev->req_config_methods) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected " -+ "our Provisioning Discovery Request"); -+ p2p_parse_free(&msg); -+ goto out; -+ } -+ -+ report_config_methods = dev->req_config_methods; -+ dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | -+ P2P_DEV_PD_PEER_KEYPAD); -+ if (dev->req_config_methods & WPS_CONFIG_DISPLAY) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR -+ " accepted to show a PIN on display", MAC2STR(sa)); -+ dev->flags |= P2P_DEV_PD_PEER_DISPLAY; -+ } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR -+ " accepted to write our PIN using keypad", -+ MAC2STR(sa)); -+ dev->flags |= P2P_DEV_PD_PEER_KEYPAD; -+ } -+ p2p_parse_free(&msg); -+ -+out: -+ dev->req_config_methods = 0; -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ if (p2p->cfg->prov_disc_resp) -+ p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa, -+ report_config_methods); -+} -+ -+ -+int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, -+ int join) -+{ -+ struct wpabuf *req; -+ int freq; -+ -+ freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; -+ if (freq <= 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Listen/Operating frequency known for the " -+ "peer " MACSTR " to send Provision Discovery Request", -+ MAC2STR(dev->info.p2p_device_addr)); -+ return -1; -+ } -+ -+ if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { -+ if (!(dev->info.dev_capab & -+ P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cannot use PD with P2P Device " MACSTR -+ " that is in a group and is not discoverable", -+ MAC2STR(dev->info.p2p_device_addr)); -+ return -1; -+ } -+ /* TODO: use device discoverability request through GO */ -+ } -+ -+ dev->dialog_token++; -+ if (dev->dialog_token == 0) -+ dev->dialog_token = 1; -+ req = p2p_build_prov_disc_req(p2p, dev->dialog_token, -+ dev->req_config_methods, -+ join ? dev : NULL); -+ if (req == NULL) -+ return -1; -+ -+ p2p->pending_action_state = P2P_PENDING_PD; -+ if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, -+ p2p->cfg->dev_addr, dev->info.p2p_device_addr, -+ wpabuf_head(req), wpabuf_len(req), 200) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ wpabuf_free(req); -+ return -1; -+ } -+ -+ wpabuf_free(req); -+ return 0; -+} -+ -+ -+int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, -+ u16 config_methods, int join) -+{ -+ struct p2p_device *dev; -+ -+ dev = p2p_get_device(p2p, peer_addr); -+ if (dev == NULL) -+ dev = p2p_get_device_interface(p2p, peer_addr); -+ if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision " -+ "Discovery Request destination " MACSTR -+ " not yet known", MAC2STR(peer_addr)); -+ return -1; -+ } -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery " -+ "Request with " MACSTR " (config methods 0x%x)", -+ MAC2STR(peer_addr), config_methods); -+ if (config_methods == 0) -+ return -1; -+ -+ dev->req_config_methods = config_methods; -+ if (join) -+ dev->flags |= P2P_DEV_PD_FOR_JOIN; -+ else -+ dev->flags &= ~P2P_DEV_PD_FOR_JOIN; -+ -+ if (p2p->go_neg_peer || -+ (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH && -+ p2p->state != P2P_LISTEN_ONLY)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other " -+ "operations; postpone Provision Discovery Request " -+ "with " MACSTR " (config methods 0x%x)", -+ MAC2STR(peer_addr), config_methods); -+ return 0; -+ } -+ -+ return p2p_send_prov_disc_req(p2p, dev, join); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_sd.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_sd.c -new file mode 100644 -index 0000000000000..926fc03e7b902 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_sd.c -@@ -0,0 +1,951 @@ -+/* -+ * Wi-Fi Direct - P2P service discovery -+ * Copyright (c) 2009, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "common/ieee802_11_defs.h" -+#include "p2p_i.h" -+#include "p2p.h" -+ -+ -+struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, -+ struct p2p_device *dev) -+{ -+ struct p2p_sd_query *q; -+ -+ if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY)) -+ return 0; /* peer does not support SD */ -+ -+ for (q = p2p->sd_queries; q; q = q->next) { -+ if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO)) -+ return q; -+ if (!q->for_all_peers && -+ os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) == -+ 0) -+ return q; -+ } -+ -+ return NULL; -+} -+ -+ -+static int p2p_unlink_sd_query(struct p2p_data *p2p, -+ struct p2p_sd_query *query) -+{ -+ struct p2p_sd_query *q, *prev; -+ q = p2p->sd_queries; -+ prev = NULL; -+ while (q) { -+ if (q == query) { -+ if (prev) -+ prev->next = q->next; -+ else -+ p2p->sd_queries = q->next; -+ if (p2p->sd_query == query) -+ p2p->sd_query = NULL; -+ return 1; -+ } -+ prev = q; -+ q = q->next; -+ } -+ return 0; -+} -+ -+ -+static void p2p_free_sd_query(struct p2p_sd_query *q) -+{ -+ if (q == NULL) -+ return; -+ wpabuf_free(q->tlvs); -+ os_free(q); -+} -+ -+ -+void p2p_free_sd_queries(struct p2p_data *p2p) -+{ -+ struct p2p_sd_query *q, *prev; -+ q = p2p->sd_queries; -+ p2p->sd_queries = NULL; -+ while (q) { -+ prev = q; -+ q = q->next; -+ p2p_free_sd_query(prev); -+ } -+} -+ -+ -+static struct wpabuf * p2p_build_sd_query(u16 update_indic, -+ struct wpabuf *tlvs) -+{ -+ struct wpabuf *buf; -+ u8 *len_pos, *len_pos2; -+ -+ buf = wpabuf_alloc(1000 + wpabuf_len(tlvs)); -+ if (buf == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); -+ wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ); -+ wpabuf_put_u8(buf, 0); /* Dialog Token */ -+ -+ /* Advertisement Protocol IE */ -+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); -+ wpabuf_put_u8(buf, 2); /* Length */ -+ wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */ -+ wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ -+ -+ /* Query Request */ -+ len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ -+ -+ /* NQP Query Request Frame */ -+ wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ -+ len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */ -+ wpabuf_put_be24(buf, OUI_WFA); -+ wpabuf_put_u8(buf, P2P_OUI_TYPE); -+ wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */ -+ wpabuf_put_buf(buf, tlvs); -+ -+ WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2); -+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); -+ -+ return buf; -+} -+ -+ -+static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token) -+{ -+ struct wpabuf *buf; -+ -+ buf = wpabuf_alloc(3); -+ if (buf == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); -+ wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ); -+ wpabuf_put_u8(buf, dialog_token); -+ -+ return buf; -+} -+ -+ -+static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst, -+ u8 dialog_token, int freq) -+{ -+ struct wpabuf *req; -+ -+ req = p2p_build_gas_comeback_req(dialog_token); -+ if (req == NULL) -+ return; -+ -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst, -+ wpabuf_head(req), wpabuf_len(req), 200) < 0) -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ -+ wpabuf_free(req); -+} -+ -+ -+static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code, -+ u16 comeback_delay, -+ u16 update_indic, -+ const struct wpabuf *tlvs) -+{ -+ struct wpabuf *buf; -+ u8 *len_pos, *len_pos2; -+ -+ buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0)); -+ if (buf == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); -+ wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP); -+ wpabuf_put_u8(buf, dialog_token); -+ wpabuf_put_le16(buf, status_code); -+ wpabuf_put_le16(buf, comeback_delay); -+ -+ /* Advertisement Protocol IE */ -+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); -+ wpabuf_put_u8(buf, 2); /* Length */ -+ wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */ -+ wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ -+ -+ /* Query Response */ -+ len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ -+ -+ if (tlvs) { -+ /* NQP Query Response Frame */ -+ wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ -+ len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */ -+ wpabuf_put_be24(buf, OUI_WFA); -+ wpabuf_put_u8(buf, P2P_OUI_TYPE); -+ /* Service Update Indicator */ -+ wpabuf_put_le16(buf, update_indic); -+ wpabuf_put_buf(buf, tlvs); -+ -+ WPA_PUT_LE16(len_pos2, -+ (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2); -+ } -+ -+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); -+ -+ return buf; -+} -+ -+ -+static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token, -+ u16 status_code, -+ u16 update_indic, -+ const u8 *data, size_t len, -+ u8 frag_id, u8 more, -+ u16 total_len) -+{ -+ struct wpabuf *buf; -+ u8 *len_pos; -+ -+ buf = wpabuf_alloc(1000 + len); -+ if (buf == NULL) -+ return NULL; -+ -+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); -+ wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP); -+ wpabuf_put_u8(buf, dialog_token); -+ wpabuf_put_le16(buf, status_code); -+ wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0)); -+ wpabuf_put_le16(buf, 0); /* Comeback Delay */ -+ -+ /* Advertisement Protocol IE */ -+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO); -+ wpabuf_put_u8(buf, 2); /* Length */ -+ wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */ -+ wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */ -+ -+ /* Query Response */ -+ len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */ -+ -+ if (frag_id == 0) { -+ /* NQP Query Response Frame */ -+ wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */ -+ wpabuf_put_le16(buf, 3 + 1 + 2 + total_len); -+ wpabuf_put_be24(buf, OUI_WFA); -+ wpabuf_put_u8(buf, P2P_OUI_TYPE); -+ /* Service Update Indicator */ -+ wpabuf_put_le16(buf, update_indic); -+ } -+ -+ wpabuf_put_data(buf, data, len); -+ -+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2); -+ -+ return buf; -+} -+ -+ -+int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev) -+{ -+ struct wpabuf *req; -+ int ret = 0; -+ struct p2p_sd_query *query; -+ int freq; -+ -+ freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; -+ if (freq <= 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: No Listen/Operating frequency known for the " -+ "peer " MACSTR " to send SD Request", -+ MAC2STR(dev->info.p2p_device_addr)); -+ return -1; -+ } -+ -+ query = p2p_pending_sd_req(p2p, dev); -+ if (query == NULL) -+ return -1; -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Start Service Discovery with " MACSTR, -+ MAC2STR(dev->info.p2p_device_addr)); -+ -+ req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs); -+ if (req == NULL) -+ return -1; -+ -+ p2p->sd_peer = dev; -+ p2p->sd_query = query; -+ p2p->pending_action_state = P2P_PENDING_SD; -+ -+ if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, -+ p2p->cfg->dev_addr, dev->info.p2p_device_addr, -+ wpabuf_head(req), wpabuf_len(req), 5000) < 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ ret = -1; -+ } -+ -+ wpabuf_free(req); -+ -+ return ret; -+} -+ -+ -+void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ const u8 *pos = data; -+ const u8 *end = data + len; -+ const u8 *next; -+ u8 dialog_token; -+ u16 slen; -+ int freq; -+ u16 update_indic; -+ -+ -+ if (p2p->cfg->sd_request == NULL) -+ return; -+ -+ if (rx_freq > 0) -+ freq = rx_freq; -+ else -+ freq = p2p_channel_to_freq(p2p->cfg->country, -+ p2p->cfg->reg_class, -+ p2p->cfg->channel); -+ if (freq < 0) -+ return; -+ -+ if (len < 1 + 2) -+ return; -+ -+ dialog_token = *pos++; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: GAS Initial Request from " MACSTR " (dialog token %u, " -+ "freq %d)", -+ MAC2STR(sa), dialog_token, rx_freq); -+ -+ if (*pos != WLAN_EID_ADV_PROTO) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected IE in GAS Initial Request: %u", *pos); -+ return; -+ } -+ pos++; -+ -+ slen = *pos++; -+ next = pos + slen; -+ if (next > end || slen < 2) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid IE in GAS Initial Request"); -+ return; -+ } -+ pos++; /* skip QueryRespLenLimit and PAME-BI */ -+ -+ if (*pos != NATIVE_QUERY_PROTOCOL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported GAS advertisement protocol id %u", -+ *pos); -+ return; -+ } -+ -+ pos = next; -+ /* Query Request */ -+ if (pos + 2 > end) -+ return; -+ slen = WPA_GET_LE16(pos); -+ pos += 2; -+ if (pos + slen > end) -+ return; -+ end = pos + slen; -+ -+ /* NQP Query Request */ -+ if (pos + 4 > end) -+ return; -+ if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); -+ return; -+ } -+ pos += 2; -+ -+ slen = WPA_GET_LE16(pos); -+ pos += 2; -+ if (pos + slen > end || slen < 3 + 1) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid NQP Query Request length"); -+ return; -+ } -+ -+ if (WPA_GET_BE24(pos) != OUI_WFA) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); -+ return; -+ } -+ pos += 3; -+ -+ if (*pos != P2P_OUI_TYPE) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP vendor type %u", *pos); -+ return; -+ } -+ pos++; -+ -+ if (pos + 2 > end) -+ return; -+ update_indic = WPA_GET_LE16(pos); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Service Update Indicator: %u", update_indic); -+ pos += 2; -+ -+ p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token, -+ update_indic, pos, end - pos); -+ /* the response will be indicated with a call to p2p_sd_response() */ -+} -+ -+ -+void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst, -+ u8 dialog_token, const struct wpabuf *resp_tlvs) -+{ -+ struct wpabuf *resp; -+ -+ /* TODO: fix the length limit to match with the maximum frame length */ -+ if (wpabuf_len(resp_tlvs) > 1400) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response long " -+ "enough to require fragmentation"); -+ if (p2p->sd_resp) { -+ /* -+ * TODO: Could consider storing the fragmented response -+ * separately for each peer to avoid having to drop old -+ * one if there is more than one pending SD query. -+ * Though, that would eat more memory, so there are -+ * also benefits to just using a single buffer. -+ */ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop " -+ "previous SD response"); -+ wpabuf_free(p2p->sd_resp); -+ } -+ os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN); -+ p2p->sd_resp_dialog_token = dialog_token; -+ p2p->sd_resp = wpabuf_dup(resp_tlvs); -+ p2p->sd_resp_pos = 0; -+ p2p->sd_frag_id = 0; -+ resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS, -+ 1, p2p->srv_update_indic, NULL); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: SD response fits " -+ "in initial response"); -+ resp = p2p_build_sd_response(dialog_token, -+ WLAN_STATUS_SUCCESS, 0, -+ p2p->srv_update_indic, resp_tlvs); -+ } -+ if (resp == NULL) -+ return; -+ -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, -+ p2p->cfg->dev_addr, -+ wpabuf_head(resp), wpabuf_len(resp), 200) < 0) -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ -+ wpabuf_free(resp); -+} -+ -+ -+void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ const u8 *pos = data; -+ const u8 *end = data + len; -+ const u8 *next; -+ u8 dialog_token; -+ u16 status_code; -+ u16 comeback_delay; -+ u16 slen; -+ u16 update_indic; -+ -+ if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || -+ os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore unexpected GAS Initial Response from " -+ MACSTR, MAC2STR(sa)); -+ return; -+ } -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p_clear_timeout(p2p); -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received GAS Initial Response from " MACSTR " (len=%d)", -+ MAC2STR(sa), (int) len); -+ -+ if (len < 5 + 2) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Too short GAS Initial Response frame"); -+ return; -+ } -+ -+ dialog_token = *pos++; -+ /* TODO: check dialog_token match */ -+ status_code = WPA_GET_LE16(pos); -+ pos += 2; -+ comeback_delay = WPA_GET_LE16(pos); -+ pos += 2; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: dialog_token=%u status_code=%u comeback_delay=%u", -+ dialog_token, status_code, comeback_delay); -+ if (status_code) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Service Discovery failed: status code %u", -+ status_code); -+ return; -+ } -+ -+ if (*pos != WLAN_EID_ADV_PROTO) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected IE in GAS Initial Response: %u", -+ *pos); -+ return; -+ } -+ pos++; -+ -+ slen = *pos++; -+ next = pos + slen; -+ if (next > end || slen < 2) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid IE in GAS Initial Response"); -+ return; -+ } -+ pos++; /* skip QueryRespLenLimit and PAME-BI */ -+ -+ if (*pos != NATIVE_QUERY_PROTOCOL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported GAS advertisement protocol id %u", -+ *pos); -+ return; -+ } -+ -+ pos = next; -+ /* Query Response */ -+ if (pos + 2 > end) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query " -+ "Response"); -+ return; -+ } -+ slen = WPA_GET_LE16(pos); -+ pos += 2; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d", -+ slen); -+ if (pos + slen > end) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query " -+ "Response data"); -+ return; -+ } -+ end = pos + slen; -+ -+ if (comeback_delay) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Fragmented " -+ "response - request fragments"); -+ if (p2p->sd_rx_resp) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Drop " -+ "old SD reassembly buffer"); -+ wpabuf_free(p2p->sd_rx_resp); -+ p2p->sd_rx_resp = NULL; -+ } -+ p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); -+ return; -+ } -+ -+ /* NQP Query Response */ -+ if (pos + 4 > end) -+ return; -+ if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); -+ return; -+ } -+ pos += 2; -+ -+ slen = WPA_GET_LE16(pos); -+ pos += 2; -+ if (pos + slen > end || slen < 3 + 1) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid NQP Query Response length"); -+ return; -+ } -+ -+ if (WPA_GET_BE24(pos) != OUI_WFA) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); -+ return; -+ } -+ pos += 3; -+ -+ if (*pos != P2P_OUI_TYPE) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP vendor type %u", *pos); -+ return; -+ } -+ pos++; -+ -+ if (pos + 2 > end) -+ return; -+ update_indic = WPA_GET_LE16(pos); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Service Update Indicator: %u", update_indic); -+ pos += 2; -+ -+ p2p->sd_peer->flags |= P2P_DEV_SD_INFO; -+ p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; -+ p2p->sd_peer = NULL; -+ -+ if (p2p->sd_query) { -+ if (!p2p->sd_query->for_all_peers) { -+ struct p2p_sd_query *q; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Remove completed SD query %p", -+ p2p->sd_query); -+ q = p2p->sd_query; -+ p2p_unlink_sd_query(p2p, p2p->sd_query); -+ p2p_free_sd_query(q); -+ } -+ p2p->sd_query = NULL; -+ } -+ -+ if (p2p->cfg->sd_response) -+ p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic, -+ pos, end - pos); -+ p2p_continue_find(p2p); -+} -+ -+ -+void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ struct wpabuf *resp; -+ u8 dialog_token; -+ size_t frag_len; -+ int more = 0; -+ -+ wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len); -+ if (len < 1) -+ return; -+ dialog_token = *data; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Dialog Token: %u", -+ dialog_token); -+ if (dialog_token != p2p->sd_resp_dialog_token) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD " -+ "response fragment for dialog token %u", dialog_token); -+ return; -+ } -+ -+ if (p2p->sd_resp == NULL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD " -+ "response fragment available"); -+ return; -+ } -+ if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending SD " -+ "response fragment for " MACSTR, MAC2STR(sa)); -+ return; -+ } -+ -+ frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos; -+ if (frag_len > 1400) { -+ frag_len = 1400; -+ more = 1; -+ } -+ resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS, -+ p2p->srv_update_indic, -+ wpabuf_head_u8(p2p->sd_resp) + -+ p2p->sd_resp_pos, frag_len, -+ p2p->sd_frag_id, more, -+ wpabuf_len(p2p->sd_resp)); -+ if (resp == NULL) -+ return; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send GAS Comeback " -+ "Response (frag_id %d more=%d frag_len=%d)", -+ p2p->sd_frag_id, more, (int) frag_len); -+ p2p->sd_frag_id++; -+ p2p->sd_resp_pos += frag_len; -+ -+ if (more) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: %d more bytes " -+ "remain to be sent", -+ (int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos)); -+ } else { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: All fragments of " -+ "SD response sent"); -+ wpabuf_free(p2p->sd_resp); -+ p2p->sd_resp = NULL; -+ } -+ -+ p2p->pending_action_state = P2P_NO_PENDING_ACTION; -+ if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr, -+ p2p->cfg->dev_addr, -+ wpabuf_head(resp), wpabuf_len(resp), 200) < 0) -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Failed to send Action frame"); -+ -+ wpabuf_free(resp); -+} -+ -+ -+void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, -+ const u8 *data, size_t len, int rx_freq) -+{ -+ const u8 *pos = data; -+ const u8 *end = data + len; -+ const u8 *next; -+ u8 dialog_token; -+ u16 status_code; -+ u8 frag_id; -+ u8 more_frags; -+ u16 comeback_delay; -+ u16 slen; -+ -+ wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len); -+ -+ if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || -+ os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Ignore unexpected GAS Comeback Response from " -+ MACSTR, MAC2STR(sa)); -+ return; -+ } -+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx); -+ p2p_clear_timeout(p2p); -+ -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Received GAS Comeback Response from " MACSTR " (len=%d)", -+ MAC2STR(sa), (int) len); -+ -+ if (len < 6 + 2) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Too short GAS Comeback Response frame"); -+ return; -+ } -+ -+ dialog_token = *pos++; -+ /* TODO: check dialog_token match */ -+ status_code = WPA_GET_LE16(pos); -+ pos += 2; -+ frag_id = *pos & 0x7f; -+ more_frags = (*pos & 0x80) >> 7; -+ pos++; -+ comeback_delay = WPA_GET_LE16(pos); -+ pos += 2; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: dialog_token=%u status_code=%u frag_id=%d more_frags=%d " -+ "comeback_delay=%u", -+ dialog_token, status_code, frag_id, more_frags, -+ comeback_delay); -+ /* TODO: check frag_id match */ -+ if (status_code) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Service Discovery failed: status code %u", -+ status_code); -+ return; -+ } -+ -+ if (*pos != WLAN_EID_ADV_PROTO) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unexpected IE in GAS Comeback Response: %u", -+ *pos); -+ return; -+ } -+ pos++; -+ -+ slen = *pos++; -+ next = pos + slen; -+ if (next > end || slen < 2) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid IE in GAS Comeback Response"); -+ return; -+ } -+ pos++; /* skip QueryRespLenLimit and PAME-BI */ -+ -+ if (*pos != NATIVE_QUERY_PROTOCOL) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported GAS advertisement protocol id %u", -+ *pos); -+ return; -+ } -+ -+ pos = next; -+ /* Query Response */ -+ if (pos + 2 > end) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too short Query " -+ "Response"); -+ return; -+ } -+ slen = WPA_GET_LE16(pos); -+ pos += 2; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Query Response Length: %d", -+ slen); -+ if (pos + slen > end) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Not enough Query " -+ "Response data"); -+ return; -+ } -+ if (slen == 0) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No Query Response " -+ "data"); -+ return; -+ } -+ end = pos + slen; -+ -+ if (p2p->sd_rx_resp) { -+ /* -+ * NQP header is only included in the first fragment; rest of -+ * the fragments start with continue TLVs. -+ */ -+ goto skip_nqp_header; -+ } -+ -+ /* NQP Query Response */ -+ if (pos + 4 > end) -+ return; -+ if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos)); -+ return; -+ } -+ pos += 2; -+ -+ slen = WPA_GET_LE16(pos); -+ pos += 2; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: NQP Query Response " -+ "length: %u", slen); -+ if (slen < 3 + 1) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Invalid NQP Query Response length"); -+ return; -+ } -+ if (pos + 4 > end) -+ return; -+ -+ if (WPA_GET_BE24(pos) != OUI_WFA) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos)); -+ return; -+ } -+ pos += 3; -+ -+ if (*pos != P2P_OUI_TYPE) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Unsupported NQP vendor type %u", *pos); -+ return; -+ } -+ pos++; -+ -+ if (pos + 2 > end) -+ return; -+ p2p->sd_rx_update_indic = WPA_GET_LE16(pos); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Service Update Indicator: %u", p2p->sd_rx_update_indic); -+ pos += 2; -+ -+skip_nqp_header: -+ if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0) -+ return; -+ wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos); -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Current SD reassembly " -+ "buffer length: %u", -+ (unsigned int) wpabuf_len(p2p->sd_rx_resp)); -+ -+ if (more_frags) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: More fragments " -+ "remains"); -+ /* TODO: what would be a good size limit? */ -+ if (wpabuf_len(p2p->sd_rx_resp) > 64000) { -+ wpabuf_free(p2p->sd_rx_resp); -+ p2p->sd_rx_resp = NULL; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Too long " -+ "SD response - drop it"); -+ return; -+ } -+ p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); -+ return; -+ } -+ -+ p2p->sd_peer->flags |= P2P_DEV_SD_INFO; -+ p2p->sd_peer->flags &= ~P2P_DEV_SD_SCHEDULE; -+ p2p->sd_peer = NULL; -+ -+ if (p2p->sd_query) { -+ if (!p2p->sd_query->for_all_peers) { -+ struct p2p_sd_query *q; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Remove completed SD query %p", -+ p2p->sd_query); -+ q = p2p->sd_query; -+ p2p_unlink_sd_query(p2p, p2p->sd_query); -+ p2p_free_sd_query(q); -+ } -+ p2p->sd_query = NULL; -+ } -+ -+ if (p2p->cfg->sd_response) -+ p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, -+ p2p->sd_rx_update_indic, -+ wpabuf_head(p2p->sd_rx_resp), -+ wpabuf_len(p2p->sd_rx_resp)); -+ wpabuf_free(p2p->sd_rx_resp); -+ p2p->sd_rx_resp = NULL; -+ -+ p2p_continue_find(p2p); -+} -+ -+ -+void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst, -+ const struct wpabuf *tlvs) -+{ -+ struct p2p_sd_query *q; -+ -+ q = os_zalloc(sizeof(*q)); -+ if (q == NULL) -+ return NULL; -+ -+ if (dst) -+ os_memcpy(q->peer, dst, ETH_ALEN); -+ else -+ q->for_all_peers = 1; -+ -+ q->tlvs = wpabuf_dup(tlvs); -+ if (q->tlvs == NULL) { -+ p2p_free_sd_query(q); -+ return NULL; -+ } -+ -+ q->next = p2p->sd_queries; -+ p2p->sd_queries = q; -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Added SD Query %p", q); -+ -+ return q; -+} -+ -+ -+void p2p_sd_service_update(struct p2p_data *p2p) -+{ -+ p2p->srv_update_indic++; -+} -+ -+ -+int p2p_sd_cancel_request(struct p2p_data *p2p, void *req) -+{ -+ if (p2p_unlink_sd_query(p2p, req)) { -+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, -+ "P2P: Cancel pending SD query %p", req); -+ p2p_free_sd_query(req); -+ return 0; -+ } -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_utils.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_utils.c -new file mode 100644 -index 0000000000000..da4b6edd40fe6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/p2p/p2p_utils.c -@@ -0,0 +1,271 @@ -+/* -+ * P2P - generic helper functions -+ * Copyright (c) 2009, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "p2p_i.h" -+ -+ -+/** -+ * p2p_random - Generate random string for SSID and passphrase -+ * @buf: Buffer for returning the result -+ * @len: Number of octets to write to the buffer -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function generates a random string using the following character set: -+ * 'A'-'Z', 'a'-'z', '0'-'9'. -+ */ -+int p2p_random(char *buf, size_t len) -+{ -+ u8 val; -+ size_t i; -+ u8 letters = 'Z' - 'A' + 1; -+ u8 numbers = 10; -+ -+ if (os_get_random((unsigned char *) buf, len)) -+ return -1; -+ /* Character set: 'A'-'Z', 'a'-'z', '0'-'9' */ -+ for (i = 0; i < len; i++) { -+ val = buf[i]; -+ val %= 2 * letters + numbers; -+ if (val < letters) -+ buf[i] = 'A' + val; -+ else if (val < 2 * letters) -+ buf[i] = 'a' + (val - letters); -+ else -+ buf[i] = '0' + (val - 2 * letters); -+ } -+ -+ return 0; -+} -+ -+ -+static int p2p_channel_to_freq_j4(int reg_class, int channel) -+{ -+ /* Table J-4 in P802.11REVmb/D4.0 - Global operating classes */ -+ /* TODO: more regulatory classes */ -+ switch (reg_class) { -+ case 81: -+ /* channels 1..13 */ -+ if (channel < 1 || channel > 13) -+ return -1; -+ return 2407 + 5 * channel; -+ case 82: -+ /* channel 14 */ -+ if (channel != 14) -+ return -1; -+ return 2414 + 5 * channel; -+ case 83: /* channels 1..9; 40 MHz */ -+ case 84: /* channels 5..13; 40 MHz */ -+ if (channel < 1 || channel > 13) -+ return -1; -+ return 2407 + 5 * channel; -+ case 115: /* channels 36,40,44,48; indoor only */ -+ case 118: /* channels 52,56,60,64; dfs */ -+ if (channel < 36 || channel > 64) -+ return -1; -+ return 5000 + 5 * channel; -+ case 124: /* channels 149,153,157,161 */ -+ case 125: /* channels 149,153,157,161,165,169 */ -+ if (channel < 149 || channel > 161) -+ return -1; -+ return 5000 + 5 * channel; -+ case 116: /* channels 36,44; 40 MHz; indoor only */ -+ case 117: /* channels 40,48; 40 MHz; indoor only */ -+ case 119: /* channels 52,60; 40 MHz; dfs */ -+ case 120: /* channels 56,64; 40 MHz; dfs */ -+ if (channel < 36 || channel > 64) -+ return -1; -+ return 5000 + 5 * channel; -+ case 126: /* channels 149,157; 40 MHz */ -+ case 127: /* channels 153,161; 40 MHz */ -+ if (channel < 149 || channel > 161) -+ return -1; -+ return 5000 + 5 * channel; -+ } -+ return -1; -+} -+ -+ -+/** -+ * p2p_channel_to_freq - Convert channel info to frequency -+ * @country: Country code -+ * @reg_class: Regulatory class -+ * @channel: Channel number -+ * Returns: Frequency in MHz or -1 if the specified channel is unknown -+ */ -+int p2p_channel_to_freq(const char *country, int reg_class, int channel) -+{ -+ if (country[2] == 0x04) -+ return p2p_channel_to_freq_j4(reg_class, channel); -+ -+ /* These are mainly for backwards compatibility; to be removed */ -+ switch (reg_class) { -+ case 1: /* US/1, EU/1, JP/1 = 5 GHz, channels 36,40,44,48 */ -+ if (channel < 36 || channel > 48) -+ return -1; -+ return 5000 + 5 * channel; -+ case 3: /* US/3 = 5 GHz, channels 149,153,157,161 */ -+ case 5: /* US/5 = 5 GHz, channels 149,153,157,161 */ -+ if (channel < 149 || channel > 161) -+ return -1; -+ return 5000 + 5 * channel; -+ case 4: /* EU/4 = 2.407 GHz, channels 1..13 */ -+ case 12: /* US/12 = 2.407 GHz, channels 1..11 */ -+ case 30: /* JP/30 = 2.407 GHz, channels 1..13 */ -+ if (channel < 1 || channel > 13) -+ return -1; -+ return 2407 + 5 * channel; -+ case 31: /* JP/31 = 2.414 GHz, channel 14 */ -+ if (channel != 14) -+ return -1; -+ return 2414 + 5 * channel; -+ } -+ -+ return -1; -+} -+ -+ -+/** -+ * p2p_freq_to_channel - Convert frequency into channel info -+ * @country: Country code -+ * @reg_class: Buffer for returning regulatory class -+ * @channel: Buffer for returning channel number -+ * Returns: 0 on success, -1 if the specified frequency is unknown -+ */ -+int p2p_freq_to_channel(const char *country, unsigned int freq, u8 *reg_class, -+ u8 *channel) -+{ -+ /* TODO: more operating classes */ -+ if (freq >= 2412 && freq <= 2472) { -+ *reg_class = 81; /* 2.407 GHz, channels 1..13 */ -+ *channel = (freq - 2407) / 5; -+ return 0; -+ } -+ -+ if (freq == 2484) { -+ *reg_class = 82; /* channel 14 */ -+ *channel = 14; -+ return 0; -+ } -+ -+ if (freq >= 5180 && freq <= 5240) { -+ *reg_class = 115; /* 5 GHz, channels 36..48 */ -+ *channel = (freq - 5000) / 5; -+ return 0; -+ } -+ -+ if (freq >= 5745 && freq <= 5805) { -+ *reg_class = 124; /* 5 GHz, channels 149..161 */ -+ *channel = (freq - 5000) / 5; -+ return 0; -+ } -+ -+ return -1; -+} -+ -+ -+static void p2p_reg_class_intersect(const struct p2p_reg_class *a, -+ const struct p2p_reg_class *b, -+ struct p2p_reg_class *res) -+{ -+ size_t i, j; -+ -+ res->reg_class = a->reg_class; -+ -+ for (i = 0; i < a->channels; i++) { -+ for (j = 0; j < b->channels; j++) { -+ if (a->channel[i] != b->channel[j]) -+ continue; -+ res->channel[res->channels] = a->channel[i]; -+ res->channels++; -+ if (res->channels == P2P_MAX_REG_CLASS_CHANNELS) -+ return; -+ } -+ } -+} -+ -+ -+/** -+ * p2p_channels_intersect - Intersection of supported channel lists -+ * @a: First set of supported channels -+ * @b: Second set of supported channels -+ * @res: Data structure for returning the intersection of support channels -+ * -+ * This function can be used to find a common set of supported channels. Both -+ * input channels sets are assumed to use the same country code. If different -+ * country codes are used, the regulatory class numbers may not be matched -+ * correctly and results are undefined. -+ */ -+void p2p_channels_intersect(const struct p2p_channels *a, -+ const struct p2p_channels *b, -+ struct p2p_channels *res) -+{ -+ size_t i, j; -+ -+ os_memset(res, 0, sizeof(*res)); -+ -+ for (i = 0; i < a->reg_classes; i++) { -+ const struct p2p_reg_class *a_reg = &a->reg_class[i]; -+ for (j = 0; j < b->reg_classes; j++) { -+ const struct p2p_reg_class *b_reg = &b->reg_class[j]; -+ if (a_reg->reg_class != b_reg->reg_class) -+ continue; -+ p2p_reg_class_intersect( -+ a_reg, b_reg, -+ &res->reg_class[res->reg_classes]); -+ if (res->reg_class[res->reg_classes].channels) { -+ res->reg_classes++; -+ if (res->reg_classes == P2P_MAX_REG_CLASSES) -+ return; -+ } -+ } -+ } -+} -+ -+ -+/** -+ * p2p_channels_includes - Check whether a channel is included in the list -+ * @channels: List of supported channels -+ * @reg_class: Regulatory class of the channel to search -+ * @channel: Channel number of the channel to search -+ * Returns: 1 if channel was found or 0 if not -+ */ -+int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class, -+ u8 channel) -+{ -+ size_t i, j; -+ for (i = 0; i < channels->reg_classes; i++) { -+ const struct p2p_reg_class *reg = &channels->reg_class[i]; -+ if (reg->reg_class != reg_class) -+ continue; -+ for (j = 0; j < reg->channels; j++) { -+ if (reg->channel[j] == channel) -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+ -+int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq) -+{ -+ u8 op_reg_class, op_channel; -+ if (p2p_freq_to_channel(p2p->cfg->country, freq, -+ &op_reg_class, &op_channel) < 0) -+ return 0; -+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class, -+ op_channel); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/.gitignore b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/.gitignore -new file mode 100644 -index 0000000000000..a89a1f92753d5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/.gitignore -@@ -0,0 +1 @@ -+libradius.a -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/Makefile -new file mode 100644 -index 0000000000000..b199be8b19703 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/Makefile -@@ -0,0 +1,22 @@ -+all: libradius.a -+ -+clean: -+ rm -f *~ *.o *.d libradius.a -+ -+install: -+ @echo Nothing to be made. -+ -+ -+include ../lib.rules -+ -+CFLAGS += -DCONFIG_IPV6 -+ -+LIB_OBJS= \ -+ radius.o \ -+ radius_client.o \ -+ radius_server.o -+ -+libradius.a: $(LIB_OBJS) -+ $(AR) crT $@ $? -+ -+-include $(OBJS:%.o=%.d) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.c -new file mode 100644 -index 0000000000000..70754ef5dd725 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.c -@@ -0,0 +1,1317 @@ -+/* -+ * RADIUS message processing -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/wpabuf.h" -+#include "crypto/md5.h" -+#include "crypto/crypto.h" -+#include "radius.h" -+ -+ -+/** -+ * struct radius_msg - RADIUS message structure for new and parsed messages -+ */ -+struct radius_msg { -+ /** -+ * buf - Allocated buffer for RADIUS message -+ */ -+ struct wpabuf *buf; -+ -+ /** -+ * hdr - Pointer to the RADIUS header in buf -+ */ -+ struct radius_hdr *hdr; -+ -+ /** -+ * attr_pos - Array of indexes to attributes -+ * -+ * The values are number of bytes from buf to the beginning of -+ * struct radius_attr_hdr. -+ */ -+ size_t *attr_pos; -+ -+ /** -+ * attr_size - Total size of the attribute pointer array -+ */ -+ size_t attr_size; -+ -+ /** -+ * attr_used - Total number of attributes in the array -+ */ -+ size_t attr_used; -+}; -+ -+ -+struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg) -+{ -+ return msg->hdr; -+} -+ -+ -+struct wpabuf * radius_msg_get_buf(struct radius_msg *msg) -+{ -+ return msg->buf; -+} -+ -+ -+static struct radius_attr_hdr * -+radius_get_attr_hdr(struct radius_msg *msg, int idx) -+{ -+ return (struct radius_attr_hdr *) -+ (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]); -+} -+ -+ -+static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier) -+{ -+ msg->hdr->code = code; -+ msg->hdr->identifier = identifier; -+} -+ -+ -+static int radius_msg_initialize(struct radius_msg *msg) -+{ -+ msg->attr_pos = -+ os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos)); -+ if (msg->attr_pos == NULL) -+ return -1; -+ -+ msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT; -+ msg->attr_used = 0; -+ -+ return 0; -+} -+ -+ -+/** -+ * radius_msg_new - Create a new RADIUS message -+ * @code: Code for RADIUS header -+ * @identifier: Identifier for RADIUS header -+ * Returns: Context for RADIUS message or %NULL on failure -+ * -+ * The caller is responsible for freeing the returned data with -+ * radius_msg_free(). -+ */ -+struct radius_msg * radius_msg_new(u8 code, u8 identifier) -+{ -+ struct radius_msg *msg; -+ -+ msg = os_zalloc(sizeof(*msg)); -+ if (msg == NULL) -+ return NULL; -+ -+ msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE); -+ if (msg->buf == NULL || radius_msg_initialize(msg)) { -+ radius_msg_free(msg); -+ return NULL; -+ } -+ msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr)); -+ -+ radius_msg_set_hdr(msg, code, identifier); -+ -+ return msg; -+} -+ -+ -+/** -+ * radius_msg_free - Free a RADIUS message -+ * @msg: RADIUS message from radius_msg_new() or radius_msg_parse() -+ */ -+void radius_msg_free(struct radius_msg *msg) -+{ -+ if (msg == NULL) -+ return; -+ -+ wpabuf_free(msg->buf); -+ os_free(msg->attr_pos); -+ os_free(msg); -+} -+ -+ -+static const char *radius_code_string(u8 code) -+{ -+ switch (code) { -+ case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; -+ case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; -+ case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; -+ case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; -+ case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; -+ case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; -+ case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; -+ case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; -+ case RADIUS_CODE_RESERVED: return "Reserved"; -+ default: return "?Unknown?"; -+ } -+} -+ -+ -+struct radius_attr_type { -+ u8 type; -+ char *name; -+ enum { -+ RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, -+ RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6 -+ } data_type; -+}; -+ -+static struct radius_attr_type radius_attrs[] = -+{ -+ { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST }, -+ { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP }, -+ { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, -+ { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST }, -+ { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST }, -+ { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id", -+ RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id", -+ RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST }, -+ { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id", -+ RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP }, -+ { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type", -+ RADIUS_ATTR_HEXDUMP }, -+ { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST }, -+ { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", -+ RADIUS_ATTR_UNDIST }, -+ { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id", -+ RADIUS_ATTR_HEXDUMP }, -+ { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", -+ RADIUS_ATTR_INT32 }, -+ { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity", -+ RADIUS_ATTR_TEXT }, -+ { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, -+}; -+#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0])) -+ -+ -+static struct radius_attr_type *radius_get_attr_type(u8 type) -+{ -+ size_t i; -+ -+ for (i = 0; i < RADIUS_ATTRS; i++) { -+ if (type == radius_attrs[i].type) -+ return &radius_attrs[i]; -+ } -+ -+ return NULL; -+} -+ -+ -+static void print_char(char c) -+{ -+ if (c >= 32 && c < 127) -+ printf("%c", c); -+ else -+ printf("<%02x>", c); -+} -+ -+ -+static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) -+{ -+ struct radius_attr_type *attr; -+ int i, len; -+ unsigned char *pos; -+ -+ attr = radius_get_attr_type(hdr->type); -+ -+ printf(" Attribute %d (%s) length=%d\n", -+ hdr->type, attr ? attr->name : "?Unknown?", hdr->length); -+ -+ if (attr == NULL) -+ return; -+ -+ len = hdr->length - sizeof(struct radius_attr_hdr); -+ pos = (unsigned char *) (hdr + 1); -+ -+ switch (attr->data_type) { -+ case RADIUS_ATTR_TEXT: -+ printf(" Value: '"); -+ for (i = 0; i < len; i++) -+ print_char(pos[i]); -+ printf("'\n"); -+ break; -+ -+ case RADIUS_ATTR_IP: -+ if (len == 4) { -+ struct in_addr addr; -+ os_memcpy(&addr, pos, 4); -+ printf(" Value: %s\n", inet_ntoa(addr)); -+ } else -+ printf(" Invalid IP address length %d\n", len); -+ break; -+ -+#ifdef CONFIG_IPV6 -+ case RADIUS_ATTR_IPV6: -+ if (len == 16) { -+ char buf[128]; -+ const char *atxt; -+ struct in6_addr *addr = (struct in6_addr *) pos; -+ atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); -+ printf(" Value: %s\n", atxt ? atxt : "?"); -+ } else -+ printf(" Invalid IPv6 address length %d\n", len); -+ break; -+#endif /* CONFIG_IPV6 */ -+ -+ case RADIUS_ATTR_HEXDUMP: -+ case RADIUS_ATTR_UNDIST: -+ printf(" Value:"); -+ for (i = 0; i < len; i++) -+ printf(" %02x", pos[i]); -+ printf("\n"); -+ break; -+ -+ case RADIUS_ATTR_INT32: -+ if (len == 4) -+ printf(" Value: %u\n", WPA_GET_BE32(pos)); -+ else -+ printf(" Invalid INT32 length %d\n", len); -+ break; -+ -+ default: -+ break; -+ } -+} -+ -+ -+void radius_msg_dump(struct radius_msg *msg) -+{ -+ size_t i; -+ -+ printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", -+ msg->hdr->code, radius_code_string(msg->hdr->code), -+ msg->hdr->identifier, ntohs(msg->hdr->length)); -+ -+ for (i = 0; i < msg->attr_used; i++) { -+ struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); -+ radius_msg_dump_attr(attr); -+ } -+} -+ -+ -+int radius_msg_finish(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len) -+{ -+ if (secret) { -+ u8 auth[MD5_MAC_LEN]; -+ struct radius_attr_hdr *attr; -+ -+ os_memset(auth, 0, MD5_MAC_LEN); -+ attr = radius_msg_add_attr(msg, -+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, -+ auth, MD5_MAC_LEN); -+ if (attr == NULL) { -+ wpa_printf(MSG_WARNING, "RADIUS: Could not add " -+ "Message-Authenticator"); -+ return -1; -+ } -+ msg->hdr->length = htons(wpabuf_len(msg->buf)); -+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf), -+ wpabuf_len(msg->buf), (u8 *) (attr + 1)); -+ } else -+ msg->hdr->length = htons(wpabuf_len(msg->buf)); -+ -+ if (wpabuf_len(msg->buf) > 0xffff) { -+ wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", -+ (unsigned long) wpabuf_len(msg->buf)); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len, const u8 *req_authenticator) -+{ -+ u8 auth[MD5_MAC_LEN]; -+ struct radius_attr_hdr *attr; -+ const u8 *addr[4]; -+ size_t len[4]; -+ -+ os_memset(auth, 0, MD5_MAC_LEN); -+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, -+ auth, MD5_MAC_LEN); -+ if (attr == NULL) { -+ printf("WARNING: Could not add Message-Authenticator\n"); -+ return -1; -+ } -+ msg->hdr->length = htons(wpabuf_len(msg->buf)); -+ os_memcpy(msg->hdr->authenticator, req_authenticator, -+ sizeof(msg->hdr->authenticator)); -+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf), -+ wpabuf_len(msg->buf), (u8 *) (attr + 1)); -+ -+ /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ -+ addr[0] = (u8 *) msg->hdr; -+ len[0] = 1 + 1 + 2; -+ addr[1] = req_authenticator; -+ len[1] = MD5_MAC_LEN; -+ addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); -+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); -+ addr[3] = secret; -+ len[3] = secret_len; -+ md5_vector(4, addr, len, msg->hdr->authenticator); -+ -+ if (wpabuf_len(msg->buf) > 0xffff) { -+ wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", -+ (unsigned long) wpabuf_len(msg->buf)); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len) -+{ -+ const u8 *addr[2]; -+ size_t len[2]; -+ -+ msg->hdr->length = htons(wpabuf_len(msg->buf)); -+ os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); -+ addr[0] = wpabuf_head(msg->buf); -+ len[0] = wpabuf_len(msg->buf); -+ addr[1] = secret; -+ len[1] = secret_len; -+ md5_vector(2, addr, len, msg->hdr->authenticator); -+ -+ if (wpabuf_len(msg->buf) > 0xffff) { -+ wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)", -+ (unsigned long) wpabuf_len(msg->buf)); -+ } -+} -+ -+ -+static int radius_msg_add_attr_to_array(struct radius_msg *msg, -+ struct radius_attr_hdr *attr) -+{ -+ if (msg->attr_used >= msg->attr_size) { -+ size_t *nattr_pos; -+ int nlen = msg->attr_size * 2; -+ -+ nattr_pos = os_realloc(msg->attr_pos, -+ nlen * sizeof(*msg->attr_pos)); -+ if (nattr_pos == NULL) -+ return -1; -+ -+ msg->attr_pos = nattr_pos; -+ msg->attr_size = nlen; -+ } -+ -+ msg->attr_pos[msg->attr_used++] = -+ (unsigned char *) attr - wpabuf_head_u8(msg->buf); -+ -+ return 0; -+} -+ -+ -+struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, -+ const u8 *data, size_t data_len) -+{ -+ size_t buf_needed; -+ struct radius_attr_hdr *attr; -+ -+ if (data_len > RADIUS_MAX_ATTR_LEN) { -+ printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", -+ (unsigned long) data_len); -+ return NULL; -+ } -+ -+ buf_needed = sizeof(*attr) + data_len; -+ -+ if (wpabuf_tailroom(msg->buf) < buf_needed) { -+ /* allocate more space for message buffer */ -+ if (wpabuf_resize(&msg->buf, buf_needed) < 0) -+ return NULL; -+ msg->hdr = wpabuf_mhead(msg->buf); -+ } -+ -+ attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); -+ attr->type = type; -+ attr->length = sizeof(*attr) + data_len; -+ wpabuf_put_data(msg->buf, data, data_len); -+ -+ if (radius_msg_add_attr_to_array(msg, attr)) -+ return NULL; -+ -+ return attr; -+} -+ -+ -+/** -+ * radius_msg_parse - Parse a RADIUS message -+ * @data: RADIUS message to be parsed -+ * @len: Length of data buffer in octets -+ * Returns: Parsed RADIUS message or %NULL on failure -+ * -+ * This parses a RADIUS message and makes a copy of its data. The caller is -+ * responsible for freeing the returned data with radius_msg_free(). -+ */ -+struct radius_msg * radius_msg_parse(const u8 *data, size_t len) -+{ -+ struct radius_msg *msg; -+ struct radius_hdr *hdr; -+ struct radius_attr_hdr *attr; -+ size_t msg_len; -+ unsigned char *pos, *end; -+ -+ if (data == NULL || len < sizeof(*hdr)) -+ return NULL; -+ -+ hdr = (struct radius_hdr *) data; -+ -+ msg_len = ntohs(hdr->length); -+ if (msg_len < sizeof(*hdr) || msg_len > len) { -+ wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); -+ return NULL; -+ } -+ -+ if (msg_len < len) { -+ wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " -+ "RADIUS message", (unsigned long) len - msg_len); -+ } -+ -+ msg = os_zalloc(sizeof(*msg)); -+ if (msg == NULL) -+ return NULL; -+ -+ msg->buf = wpabuf_alloc_copy(data, msg_len); -+ if (msg->buf == NULL || radius_msg_initialize(msg)) { -+ radius_msg_free(msg); -+ return NULL; -+ } -+ msg->hdr = wpabuf_mhead(msg->buf); -+ -+ /* parse attributes */ -+ pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); -+ end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); -+ while (pos < end) { -+ if ((size_t) (end - pos) < sizeof(*attr)) -+ goto fail; -+ -+ attr = (struct radius_attr_hdr *) pos; -+ -+ if (pos + attr->length > end || attr->length < sizeof(*attr)) -+ goto fail; -+ -+ /* TODO: check that attr->length is suitable for attr->type */ -+ -+ if (radius_msg_add_attr_to_array(msg, attr)) -+ goto fail; -+ -+ pos += attr->length; -+ } -+ -+ return msg; -+ -+ fail: -+ radius_msg_free(msg); -+ return NULL; -+} -+ -+ -+int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) -+{ -+ const u8 *pos = data; -+ size_t left = data_len; -+ -+ while (left > 0) { -+ int len; -+ if (left > RADIUS_MAX_ATTR_LEN) -+ len = RADIUS_MAX_ATTR_LEN; -+ else -+ len = left; -+ -+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, -+ pos, len)) -+ return 0; -+ -+ pos += len; -+ left -= len; -+ } -+ -+ return 1; -+} -+ -+ -+u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len) -+{ -+ u8 *eap, *pos; -+ size_t len, i; -+ struct radius_attr_hdr *attr; -+ -+ if (msg == NULL) -+ return NULL; -+ -+ len = 0; -+ for (i = 0; i < msg->attr_used; i++) { -+ attr = radius_get_attr_hdr(msg, i); -+ if (attr->type == RADIUS_ATTR_EAP_MESSAGE) -+ len += attr->length - sizeof(struct radius_attr_hdr); -+ } -+ -+ if (len == 0) -+ return NULL; -+ -+ eap = os_malloc(len); -+ if (eap == NULL) -+ return NULL; -+ -+ pos = eap; -+ for (i = 0; i < msg->attr_used; i++) { -+ attr = radius_get_attr_hdr(msg, i); -+ if (attr->type == RADIUS_ATTR_EAP_MESSAGE) { -+ int flen = attr->length - sizeof(*attr); -+ os_memcpy(pos, attr + 1, flen); -+ pos += flen; -+ } -+ } -+ -+ if (eap_len) -+ *eap_len = len; -+ -+ return eap; -+} -+ -+ -+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len, const u8 *req_auth) -+{ -+ u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN]; -+ u8 orig_authenticator[16]; -+ struct radius_attr_hdr *attr = NULL, *tmp; -+ size_t i; -+ -+ for (i = 0; i < msg->attr_used; i++) { -+ tmp = radius_get_attr_hdr(msg, i); -+ if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { -+ if (attr != NULL) { -+ printf("Multiple Message-Authenticator " -+ "attributes in RADIUS message\n"); -+ return 1; -+ } -+ attr = tmp; -+ } -+ } -+ -+ if (attr == NULL) { -+ printf("No Message-Authenticator attribute found\n"); -+ return 1; -+ } -+ -+ os_memcpy(orig, attr + 1, MD5_MAC_LEN); -+ os_memset(attr + 1, 0, MD5_MAC_LEN); -+ if (req_auth) { -+ os_memcpy(orig_authenticator, msg->hdr->authenticator, -+ sizeof(orig_authenticator)); -+ os_memcpy(msg->hdr->authenticator, req_auth, -+ sizeof(msg->hdr->authenticator)); -+ } -+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf), -+ wpabuf_len(msg->buf), auth); -+ os_memcpy(attr + 1, orig, MD5_MAC_LEN); -+ if (req_auth) { -+ os_memcpy(msg->hdr->authenticator, orig_authenticator, -+ sizeof(orig_authenticator)); -+ } -+ -+ if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { -+ printf("Invalid Message-Authenticator!\n"); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+int radius_msg_verify(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len, struct radius_msg *sent_msg, int auth) -+{ -+ const u8 *addr[4]; -+ size_t len[4]; -+ u8 hash[MD5_MAC_LEN]; -+ -+ if (sent_msg == NULL) { -+ printf("No matching Access-Request message found\n"); -+ return 1; -+ } -+ -+ if (auth && -+ radius_msg_verify_msg_auth(msg, secret, secret_len, -+ sent_msg->hdr->authenticator)) { -+ return 1; -+ } -+ -+ /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ -+ addr[0] = (u8 *) msg->hdr; -+ len[0] = 1 + 1 + 2; -+ addr[1] = sent_msg->hdr->authenticator; -+ len[1] = MD5_MAC_LEN; -+ addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); -+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); -+ addr[3] = secret; -+ len[3] = secret_len; -+ md5_vector(4, addr, len, hash); -+ if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { -+ printf("Response Authenticator invalid!\n"); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, -+ u8 type) -+{ -+ struct radius_attr_hdr *attr; -+ size_t i; -+ int count = 0; -+ -+ for (i = 0; i < src->attr_used; i++) { -+ attr = radius_get_attr_hdr(src, i); -+ if (attr->type == type) { -+ if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), -+ attr->length - sizeof(*attr))) -+ return -1; -+ count++; -+ } -+ } -+ -+ return count; -+} -+ -+ -+/* Create Request Authenticator. The value should be unique over the lifetime -+ * of the shared secret between authenticator and authentication server. -+ * Use one-way MD5 hash calculated from current timestamp and some data given -+ * by the caller. */ -+void radius_msg_make_authenticator(struct radius_msg *msg, -+ const u8 *data, size_t len) -+{ -+ struct os_time tv; -+ long int l; -+ const u8 *addr[3]; -+ size_t elen[3]; -+ -+ os_get_time(&tv); -+ l = os_random(); -+ addr[0] = (u8 *) &tv; -+ elen[0] = sizeof(tv); -+ addr[1] = data; -+ elen[1] = len; -+ addr[2] = (u8 *) &l; -+ elen[2] = sizeof(l); -+ md5_vector(3, addr, elen, msg->hdr->authenticator); -+} -+ -+ -+/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. -+ * Returns the Attribute payload and sets alen to indicate the length of the -+ * payload if a vendor attribute with subtype is found, otherwise returns NULL. -+ * The returned payload is allocated with os_malloc() and caller must free it -+ * by calling os_free(). -+ */ -+static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, -+ u8 subtype, size_t *alen) -+{ -+ u8 *data, *pos; -+ size_t i, len; -+ -+ if (msg == NULL) -+ return NULL; -+ -+ for (i = 0; i < msg->attr_used; i++) { -+ struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); -+ size_t left; -+ u32 vendor_id; -+ struct radius_attr_vendor *vhdr; -+ -+ if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC) -+ continue; -+ -+ left = attr->length - sizeof(*attr); -+ if (left < 4) -+ continue; -+ -+ pos = (u8 *) (attr + 1); -+ -+ os_memcpy(&vendor_id, pos, 4); -+ pos += 4; -+ left -= 4; -+ -+ if (ntohl(vendor_id) != vendor) -+ continue; -+ -+ while (left >= sizeof(*vhdr)) { -+ vhdr = (struct radius_attr_vendor *) pos; -+ if (vhdr->vendor_length > left || -+ vhdr->vendor_length < sizeof(*vhdr)) { -+ left = 0; -+ break; -+ } -+ if (vhdr->vendor_type != subtype) { -+ pos += vhdr->vendor_length; -+ left -= vhdr->vendor_length; -+ continue; -+ } -+ -+ len = vhdr->vendor_length - sizeof(*vhdr); -+ data = os_malloc(len); -+ if (data == NULL) -+ return NULL; -+ os_memcpy(data, pos + sizeof(*vhdr), len); -+ if (alen) -+ *alen = len; -+ return data; -+ } -+ } -+ -+ return NULL; -+} -+ -+ -+static u8 * decrypt_ms_key(const u8 *key, size_t len, -+ const u8 *req_authenticator, -+ const u8 *secret, size_t secret_len, size_t *reslen) -+{ -+ u8 *plain, *ppos, *res; -+ const u8 *pos; -+ size_t left, plen; -+ u8 hash[MD5_MAC_LEN]; -+ int i, first = 1; -+ const u8 *addr[3]; -+ size_t elen[3]; -+ -+ /* key: 16-bit salt followed by encrypted key info */ -+ -+ if (len < 2 + 16) -+ return NULL; -+ -+ pos = key + 2; -+ left = len - 2; -+ if (left % 16) { -+ printf("Invalid ms key len %lu\n", (unsigned long) left); -+ return NULL; -+ } -+ -+ plen = left; -+ ppos = plain = os_malloc(plen); -+ if (plain == NULL) -+ return NULL; -+ plain[0] = 0; -+ -+ while (left > 0) { -+ /* b(1) = MD5(Secret + Request-Authenticator + Salt) -+ * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ -+ -+ addr[0] = secret; -+ elen[0] = secret_len; -+ if (first) { -+ addr[1] = req_authenticator; -+ elen[1] = MD5_MAC_LEN; -+ addr[2] = key; -+ elen[2] = 2; /* Salt */ -+ } else { -+ addr[1] = pos - MD5_MAC_LEN; -+ elen[1] = MD5_MAC_LEN; -+ } -+ md5_vector(first ? 3 : 2, addr, elen, hash); -+ first = 0; -+ -+ for (i = 0; i < MD5_MAC_LEN; i++) -+ *ppos++ = *pos++ ^ hash[i]; -+ left -= MD5_MAC_LEN; -+ } -+ -+ if (plain[0] == 0 || plain[0] > plen - 1) { -+ printf("Failed to decrypt MPPE key\n"); -+ os_free(plain); -+ return NULL; -+ } -+ -+ res = os_malloc(plain[0]); -+ if (res == NULL) { -+ os_free(plain); -+ return NULL; -+ } -+ os_memcpy(res, plain + 1, plain[0]); -+ if (reslen) -+ *reslen = plain[0]; -+ os_free(plain); -+ return res; -+} -+ -+ -+static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, -+ const u8 *req_authenticator, -+ const u8 *secret, size_t secret_len, -+ u8 *ebuf, size_t *elen) -+{ -+ int i, len, first = 1; -+ u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; -+ const u8 *addr[3]; -+ size_t _len[3]; -+ -+ WPA_PUT_BE16(saltbuf, salt); -+ -+ len = 1 + key_len; -+ if (len & 0x0f) { -+ len = (len & 0xf0) + 16; -+ } -+ os_memset(ebuf, 0, len); -+ ebuf[0] = key_len; -+ os_memcpy(ebuf + 1, key, key_len); -+ -+ *elen = len; -+ -+ pos = ebuf; -+ while (len > 0) { -+ /* b(1) = MD5(Secret + Request-Authenticator + Salt) -+ * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ -+ addr[0] = secret; -+ _len[0] = secret_len; -+ if (first) { -+ addr[1] = req_authenticator; -+ _len[1] = MD5_MAC_LEN; -+ addr[2] = saltbuf; -+ _len[2] = sizeof(saltbuf); -+ } else { -+ addr[1] = pos - MD5_MAC_LEN; -+ _len[1] = MD5_MAC_LEN; -+ } -+ md5_vector(first ? 3 : 2, addr, _len, hash); -+ first = 0; -+ -+ for (i = 0; i < MD5_MAC_LEN; i++) -+ *pos++ ^= hash[i]; -+ -+ len -= MD5_MAC_LEN; -+ } -+} -+ -+ -+struct radius_ms_mppe_keys * -+radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, -+ const u8 *secret, size_t secret_len) -+{ -+ u8 *key; -+ size_t keylen; -+ struct radius_ms_mppe_keys *keys; -+ -+ if (msg == NULL || sent_msg == NULL) -+ return NULL; -+ -+ keys = os_zalloc(sizeof(*keys)); -+ if (keys == NULL) -+ return NULL; -+ -+ key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, -+ RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, -+ &keylen); -+ if (key) { -+ keys->send = decrypt_ms_key(key, keylen, -+ sent_msg->hdr->authenticator, -+ secret, secret_len, -+ &keys->send_len); -+ os_free(key); -+ } -+ -+ key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, -+ RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, -+ &keylen); -+ if (key) { -+ keys->recv = decrypt_ms_key(key, keylen, -+ sent_msg->hdr->authenticator, -+ secret, secret_len, -+ &keys->recv_len); -+ os_free(key); -+ } -+ -+ return keys; -+} -+ -+ -+struct radius_ms_mppe_keys * -+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, -+ const u8 *secret, size_t secret_len) -+{ -+ u8 *key; -+ size_t keylen; -+ struct radius_ms_mppe_keys *keys; -+ -+ if (msg == NULL || sent_msg == NULL) -+ return NULL; -+ -+ keys = os_zalloc(sizeof(*keys)); -+ if (keys == NULL) -+ return NULL; -+ -+ key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, -+ RADIUS_CISCO_AV_PAIR, &keylen); -+ if (key && keylen == 51 && -+ os_memcmp(key, "leap:session-key=", 17) == 0) { -+ keys->recv = decrypt_ms_key(key + 17, keylen - 17, -+ sent_msg->hdr->authenticator, -+ secret, secret_len, -+ &keys->recv_len); -+ } -+ os_free(key); -+ -+ return keys; -+} -+ -+ -+int radius_msg_add_mppe_keys(struct radius_msg *msg, -+ const u8 *req_authenticator, -+ const u8 *secret, size_t secret_len, -+ const u8 *send_key, size_t send_key_len, -+ const u8 *recv_key, size_t recv_key_len) -+{ -+ struct radius_attr_hdr *attr; -+ u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); -+ u8 *buf; -+ struct radius_attr_vendor *vhdr; -+ u8 *pos; -+ size_t elen; -+ int hlen; -+ u16 salt; -+ -+ hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; -+ -+ /* MS-MPPE-Send-Key */ -+ buf = os_malloc(hlen + send_key_len + 16); -+ if (buf == NULL) { -+ return 0; -+ } -+ pos = buf; -+ os_memcpy(pos, &vendor_id, sizeof(vendor_id)); -+ pos += sizeof(vendor_id); -+ vhdr = (struct radius_attr_vendor *) pos; -+ vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; -+ pos = (u8 *) (vhdr + 1); -+ salt = os_random() | 0x8000; -+ WPA_PUT_BE16(pos, salt); -+ pos += 2; -+ encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, -+ secret_len, pos, &elen); -+ vhdr->vendor_length = hlen + elen - sizeof(vendor_id); -+ -+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, -+ buf, hlen + elen); -+ os_free(buf); -+ if (attr == NULL) { -+ return 0; -+ } -+ -+ /* MS-MPPE-Recv-Key */ -+ buf = os_malloc(hlen + send_key_len + 16); -+ if (buf == NULL) { -+ return 0; -+ } -+ pos = buf; -+ os_memcpy(pos, &vendor_id, sizeof(vendor_id)); -+ pos += sizeof(vendor_id); -+ vhdr = (struct radius_attr_vendor *) pos; -+ vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; -+ pos = (u8 *) (vhdr + 1); -+ salt ^= 1; -+ WPA_PUT_BE16(pos, salt); -+ pos += 2; -+ encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, -+ secret_len, pos, &elen); -+ vhdr->vendor_length = hlen + elen - sizeof(vendor_id); -+ -+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, -+ buf, hlen + elen); -+ os_free(buf); -+ if (attr == NULL) { -+ return 0; -+ } -+ -+ return 1; -+} -+ -+ -+/* Add User-Password attribute to a RADIUS message and encrypt it as specified -+ * in RFC 2865, Chap. 5.2 */ -+struct radius_attr_hdr * -+radius_msg_add_attr_user_password(struct radius_msg *msg, -+ const u8 *data, size_t data_len, -+ const u8 *secret, size_t secret_len) -+{ -+ u8 buf[128]; -+ int padlen, i; -+ size_t buf_len, pos; -+ const u8 *addr[2]; -+ size_t len[2]; -+ u8 hash[16]; -+ -+ if (data_len > 128) -+ return NULL; -+ -+ os_memcpy(buf, data, data_len); -+ buf_len = data_len; -+ -+ padlen = data_len % 16; -+ if (padlen) { -+ padlen = 16 - padlen; -+ os_memset(buf + data_len, 0, padlen); -+ buf_len += padlen; -+ } -+ -+ addr[0] = secret; -+ len[0] = secret_len; -+ addr[1] = msg->hdr->authenticator; -+ len[1] = 16; -+ md5_vector(2, addr, len, hash); -+ -+ for (i = 0; i < 16; i++) -+ buf[i] ^= hash[i]; -+ pos = 16; -+ -+ while (pos < buf_len) { -+ addr[0] = secret; -+ len[0] = secret_len; -+ addr[1] = &buf[pos - 16]; -+ len[1] = 16; -+ md5_vector(2, addr, len, hash); -+ -+ for (i = 0; i < 16; i++) -+ buf[pos + i] ^= hash[i]; -+ -+ pos += 16; -+ } -+ -+ return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, -+ buf, buf_len); -+} -+ -+ -+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) -+{ -+ struct radius_attr_hdr *attr = NULL, *tmp; -+ size_t i, dlen; -+ -+ for (i = 0; i < msg->attr_used; i++) { -+ tmp = radius_get_attr_hdr(msg, i); -+ if (tmp->type == type) { -+ attr = tmp; -+ break; -+ } -+ } -+ -+ if (!attr) -+ return -1; -+ -+ dlen = attr->length - sizeof(*attr); -+ if (buf) -+ os_memcpy(buf, (attr + 1), dlen > len ? len : dlen); -+ return dlen; -+} -+ -+ -+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, -+ size_t *len, const u8 *start) -+{ -+ size_t i; -+ struct radius_attr_hdr *attr = NULL, *tmp; -+ -+ for (i = 0; i < msg->attr_used; i++) { -+ tmp = radius_get_attr_hdr(msg, i); -+ if (tmp->type == type && -+ (start == NULL || (u8 *) tmp > start)) { -+ attr = tmp; -+ break; -+ } -+ } -+ -+ if (!attr) -+ return -1; -+ -+ *buf = (u8 *) (attr + 1); -+ *len = attr->length - sizeof(*attr); -+ return 0; -+} -+ -+ -+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) -+{ -+ size_t i; -+ int count; -+ -+ for (count = 0, i = 0; i < msg->attr_used; i++) { -+ struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); -+ if (attr->type == type && -+ attr->length >= sizeof(struct radius_attr_hdr) + min_len) -+ count++; -+ } -+ -+ return count; -+} -+ -+ -+struct radius_tunnel_attrs { -+ int tag_used; -+ int type; /* Tunnel-Type */ -+ int medium_type; /* Tunnel-Medium-Type */ -+ int vlanid; -+}; -+ -+ -+/** -+ * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information -+ * @msg: RADIUS message -+ * Returns: VLAN ID for the first tunnel configuration of -1 if none is found -+ */ -+int radius_msg_get_vlanid(struct radius_msg *msg) -+{ -+ struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun; -+ size_t i; -+ struct radius_attr_hdr *attr = NULL; -+ const u8 *data; -+ char buf[10]; -+ size_t dlen; -+ -+ os_memset(&tunnel, 0, sizeof(tunnel)); -+ -+ for (i = 0; i < msg->attr_used; i++) { -+ attr = radius_get_attr_hdr(msg, i); -+ data = (const u8 *) (attr + 1); -+ dlen = attr->length - sizeof(*attr); -+ if (attr->length < 3) -+ continue; -+ if (data[0] >= RADIUS_TUNNEL_TAGS) -+ tun = &tunnel[0]; -+ else -+ tun = &tunnel[data[0]]; -+ -+ switch (attr->type) { -+ case RADIUS_ATTR_TUNNEL_TYPE: -+ if (attr->length != 6) -+ break; -+ tun->tag_used++; -+ tun->type = WPA_GET_BE24(data + 1); -+ break; -+ case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE: -+ if (attr->length != 6) -+ break; -+ tun->tag_used++; -+ tun->medium_type = WPA_GET_BE24(data + 1); -+ break; -+ case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID: -+ if (data[0] < RADIUS_TUNNEL_TAGS) { -+ data++; -+ dlen--; -+ } -+ if (dlen >= sizeof(buf)) -+ break; -+ os_memcpy(buf, data, dlen); -+ buf[dlen] = '\0'; -+ tun->tag_used++; -+ tun->vlanid = atoi(buf); -+ break; -+ } -+ } -+ -+ for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) { -+ tun = &tunnel[i]; -+ if (tun->tag_used && -+ tun->type == RADIUS_TUNNEL_TYPE_VLAN && -+ tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 && -+ tun->vlanid > 0) -+ return tun->vlanid; -+ } -+ -+ return -1; -+} -+ -+ -+void radius_free_class(struct radius_class_data *c) -+{ -+ size_t i; -+ if (c == NULL) -+ return; -+ for (i = 0; i < c->count; i++) -+ os_free(c->attr[i].data); -+ os_free(c->attr); -+ c->attr = NULL; -+ c->count = 0; -+} -+ -+ -+int radius_copy_class(struct radius_class_data *dst, -+ const struct radius_class_data *src) -+{ -+ size_t i; -+ -+ if (src->attr == NULL) -+ return 0; -+ -+ dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data)); -+ if (dst->attr == NULL) -+ return -1; -+ -+ dst->count = 0; -+ -+ for (i = 0; i < src->count; i++) { -+ dst->attr[i].data = os_malloc(src->attr[i].len); -+ if (dst->attr[i].data == NULL) -+ break; -+ dst->count++; -+ os_memcpy(dst->attr[i].data, src->attr[i].data, -+ src->attr[i].len); -+ dst->attr[i].len = src->attr[i].len; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.h -new file mode 100644 -index 0000000000000..a3cdac0dac0aa ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius.h -@@ -0,0 +1,273 @@ -+/* -+ * RADIUS message processing -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef RADIUS_H -+#define RADIUS_H -+ -+/* RFC 2865 - RADIUS */ -+ -+#ifdef _MSC_VER -+#pragma pack(push, 1) -+#endif /* _MSC_VER */ -+ -+struct radius_hdr { -+ u8 code; -+ u8 identifier; -+ u16 length; /* including this header */ -+ u8 authenticator[16]; -+ /* followed by length-20 octets of attributes */ -+} STRUCT_PACKED; -+ -+enum { RADIUS_CODE_ACCESS_REQUEST = 1, -+ RADIUS_CODE_ACCESS_ACCEPT = 2, -+ RADIUS_CODE_ACCESS_REJECT = 3, -+ RADIUS_CODE_ACCOUNTING_REQUEST = 4, -+ RADIUS_CODE_ACCOUNTING_RESPONSE = 5, -+ RADIUS_CODE_ACCESS_CHALLENGE = 11, -+ RADIUS_CODE_STATUS_SERVER = 12, -+ RADIUS_CODE_STATUS_CLIENT = 13, -+ RADIUS_CODE_RESERVED = 255 -+}; -+ -+struct radius_attr_hdr { -+ u8 type; -+ u8 length; /* including this header */ -+ /* followed by length-2 octets of attribute value */ -+} STRUCT_PACKED; -+ -+#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr)) -+ -+enum { RADIUS_ATTR_USER_NAME = 1, -+ RADIUS_ATTR_USER_PASSWORD = 2, -+ RADIUS_ATTR_NAS_IP_ADDRESS = 4, -+ RADIUS_ATTR_NAS_PORT = 5, -+ RADIUS_ATTR_FRAMED_MTU = 12, -+ RADIUS_ATTR_REPLY_MESSAGE = 18, -+ RADIUS_ATTR_STATE = 24, -+ RADIUS_ATTR_CLASS = 25, -+ RADIUS_ATTR_VENDOR_SPECIFIC = 26, -+ RADIUS_ATTR_SESSION_TIMEOUT = 27, -+ RADIUS_ATTR_IDLE_TIMEOUT = 28, -+ RADIUS_ATTR_TERMINATION_ACTION = 29, -+ RADIUS_ATTR_CALLED_STATION_ID = 30, -+ RADIUS_ATTR_CALLING_STATION_ID = 31, -+ RADIUS_ATTR_NAS_IDENTIFIER = 32, -+ RADIUS_ATTR_PROXY_STATE = 33, -+ RADIUS_ATTR_ACCT_STATUS_TYPE = 40, -+ RADIUS_ATTR_ACCT_DELAY_TIME = 41, -+ RADIUS_ATTR_ACCT_INPUT_OCTETS = 42, -+ RADIUS_ATTR_ACCT_OUTPUT_OCTETS = 43, -+ RADIUS_ATTR_ACCT_SESSION_ID = 44, -+ RADIUS_ATTR_ACCT_AUTHENTIC = 45, -+ RADIUS_ATTR_ACCT_SESSION_TIME = 46, -+ RADIUS_ATTR_ACCT_INPUT_PACKETS = 47, -+ RADIUS_ATTR_ACCT_OUTPUT_PACKETS = 48, -+ RADIUS_ATTR_ACCT_TERMINATE_CAUSE = 49, -+ RADIUS_ATTR_ACCT_MULTI_SESSION_ID = 50, -+ RADIUS_ATTR_ACCT_LINK_COUNT = 51, -+ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52, -+ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53, -+ RADIUS_ATTR_EVENT_TIMESTAMP = 55, -+ RADIUS_ATTR_NAS_PORT_TYPE = 61, -+ RADIUS_ATTR_TUNNEL_TYPE = 64, -+ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65, -+ RADIUS_ATTR_CONNECT_INFO = 77, -+ RADIUS_ATTR_EAP_MESSAGE = 79, -+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80, -+ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81, -+ RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85, -+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89, -+ RADIUS_ATTR_NAS_IPV6_ADDRESS = 95 -+}; -+ -+ -+/* Termination-Action */ -+#define RADIUS_TERMINATION_ACTION_DEFAULT 0 -+#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1 -+ -+/* NAS-Port-Type */ -+#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19 -+ -+/* Acct-Status-Type */ -+#define RADIUS_ACCT_STATUS_TYPE_START 1 -+#define RADIUS_ACCT_STATUS_TYPE_STOP 2 -+#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3 -+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON 7 -+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF 8 -+ -+/* Acct-Authentic */ -+#define RADIUS_ACCT_AUTHENTIC_RADIUS 1 -+#define RADIUS_ACCT_AUTHENTIC_LOCAL 2 -+#define RADIUS_ACCT_AUTHENTIC_REMOTE 3 -+ -+/* Acct-Terminate-Cause */ -+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST 1 -+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_CARRIER 2 -+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE 3 -+#define RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT 4 -+#define RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT 5 -+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET 6 -+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT 7 -+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_ERROR 8 -+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_ERROR 9 -+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REQUEST 10 -+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT 11 -+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_UNNEEDED 12 -+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_PREEMPTED 13 -+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_SUSPENDED 14 -+#define RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAILABLE 15 -+#define RADIUS_ACCT_TERMINATE_CAUSE_CALLBACK 16 -+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17 -+#define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18 -+ -+#define RADIUS_TUNNEL_TAGS 32 -+ -+/* Tunnel-Type */ -+#define RADIUS_TUNNEL_TYPE_PPTP 1 -+#define RADIUS_TUNNEL_TYPE_L2TP 3 -+#define RADIUS_TUNNEL_TYPE_IPIP 7 -+#define RADIUS_TUNNEL_TYPE_GRE 10 -+#define RADIUS_TUNNEL_TYPE_VLAN 13 -+ -+/* Tunnel-Medium-Type */ -+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1 -+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2 -+#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6 -+ -+ -+struct radius_attr_vendor { -+ u8 vendor_type; -+ u8 vendor_length; -+} STRUCT_PACKED; -+ -+#define RADIUS_VENDOR_ID_CISCO 9 -+#define RADIUS_CISCO_AV_PAIR 1 -+ -+/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */ -+#define RADIUS_VENDOR_ID_MICROSOFT 311 -+ -+enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16, -+ RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17 -+}; -+ -+#ifdef _MSC_VER -+#pragma pack(pop) -+#endif /* _MSC_VER */ -+ -+struct radius_ms_mppe_keys { -+ u8 *send; -+ size_t send_len; -+ u8 *recv; -+ size_t recv_len; -+}; -+ -+ -+struct radius_msg; -+ -+/* Default size to be allocated for new RADIUS messages */ -+#define RADIUS_DEFAULT_MSG_SIZE 1024 -+ -+/* Default size to be allocated for attribute array */ -+#define RADIUS_DEFAULT_ATTR_COUNT 16 -+ -+ -+/* MAC address ASCII format for IEEE 802.1X use -+ * (draft-congdon-radius-8021x-20.txt) */ -+#define RADIUS_802_1X_ADDR_FORMAT "%02X-%02X-%02X-%02X-%02X-%02X" -+/* MAC address ASCII format for non-802.1X use */ -+#define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x" -+ -+struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg); -+struct wpabuf * radius_msg_get_buf(struct radius_msg *msg); -+struct radius_msg * radius_msg_new(u8 code, u8 identifier); -+void radius_msg_free(struct radius_msg *msg); -+void radius_msg_dump(struct radius_msg *msg); -+int radius_msg_finish(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len); -+int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len, const u8 *req_authenticator); -+void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len); -+struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type, -+ const u8 *data, size_t data_len); -+struct radius_msg * radius_msg_parse(const u8 *data, size_t len); -+int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, -+ size_t data_len); -+u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len); -+int radius_msg_verify(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len, struct radius_msg *sent_msg, -+ int auth); -+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, -+ size_t secret_len, const u8 *req_auth); -+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, -+ u8 type); -+void radius_msg_make_authenticator(struct radius_msg *msg, -+ const u8 *data, size_t len); -+struct radius_ms_mppe_keys * -+radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, -+ const u8 *secret, size_t secret_len); -+struct radius_ms_mppe_keys * -+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, -+ const u8 *secret, size_t secret_len); -+int radius_msg_add_mppe_keys(struct radius_msg *msg, -+ const u8 *req_authenticator, -+ const u8 *secret, size_t secret_len, -+ const u8 *send_key, size_t send_key_len, -+ const u8 *recv_key, size_t recv_key_len); -+struct radius_attr_hdr * -+radius_msg_add_attr_user_password(struct radius_msg *msg, -+ const u8 *data, size_t data_len, -+ const u8 *secret, size_t secret_len); -+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len); -+int radius_msg_get_vlanid(struct radius_msg *msg); -+ -+static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type, -+ u32 value) -+{ -+ u32 val = htonl(value); -+ return radius_msg_add_attr(msg, type, (u8 *) &val, 4) != NULL; -+} -+ -+static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type, -+ u32 *value) -+{ -+ u32 val; -+ int res; -+ res = radius_msg_get_attr(msg, type, (u8 *) &val, 4); -+ if (res != 4) -+ return -1; -+ -+ *value = ntohl(val); -+ return 0; -+} -+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, -+ size_t *len, const u8 *start); -+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len); -+ -+ -+struct radius_attr_data { -+ u8 *data; -+ size_t len; -+}; -+ -+struct radius_class_data { -+ struct radius_attr_data *attr; -+ size_t count; -+}; -+ -+void radius_free_class(struct radius_class_data *c); -+int radius_copy_class(struct radius_class_data *dst, -+ const struct radius_class_data *src); -+ -+#endif /* RADIUS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.c -new file mode 100644 -index 0000000000000..691f77a5e53e8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.c -@@ -0,0 +1,1499 @@ -+/* -+ * RADIUS client -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "radius.h" -+#include "radius_client.h" -+#include "eloop.h" -+ -+/* Defaults for RADIUS retransmit values (exponential backoff) */ -+ -+/** -+ * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds -+ */ -+#define RADIUS_CLIENT_FIRST_WAIT 3 -+ -+/** -+ * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds -+ */ -+#define RADIUS_CLIENT_MAX_WAIT 120 -+ -+/** -+ * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries -+ * -+ * Maximum number of retransmit attempts before the entry is removed from -+ * retransmit list. -+ */ -+#define RADIUS_CLIENT_MAX_RETRIES 10 -+ -+/** -+ * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages -+ * -+ * Maximum number of entries in retransmit list (oldest entries will be -+ * removed, if this limit is exceeded). -+ */ -+#define RADIUS_CLIENT_MAX_ENTRIES 30 -+ -+/** -+ * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point -+ * -+ * The number of failed retry attempts after which the RADIUS server will be -+ * changed (if one of more backup servers are configured). -+ */ -+#define RADIUS_CLIENT_NUM_FAILOVER 4 -+ -+ -+/** -+ * struct radius_rx_handler - RADIUS client RX handler -+ * -+ * This data structure is used internally inside the RADIUS client module to -+ * store registered RX handlers. These handlers are registered by calls to -+ * radius_client_register() and unregistered when the RADIUS client is -+ * deinitialized with a call to radius_client_deinit(). -+ */ -+struct radius_rx_handler { -+ /** -+ * handler - Received RADIUS message handler -+ */ -+ RadiusRxResult (*handler)(struct radius_msg *msg, -+ struct radius_msg *req, -+ const u8 *shared_secret, -+ size_t shared_secret_len, -+ void *data); -+ -+ /** -+ * data - Context data for the handler -+ */ -+ void *data; -+}; -+ -+ -+/** -+ * struct radius_msg_list - RADIUS client message retransmit list -+ * -+ * This data structure is used internally inside the RADIUS client module to -+ * store pending RADIUS requests that may still need to be retransmitted. -+ */ -+struct radius_msg_list { -+ /** -+ * addr - STA/client address -+ * -+ * This is used to find RADIUS messages for the same STA. -+ */ -+ u8 addr[ETH_ALEN]; -+ -+ /** -+ * msg - RADIUS message -+ */ -+ struct radius_msg *msg; -+ -+ /** -+ * msg_type - Message type -+ */ -+ RadiusType msg_type; -+ -+ /** -+ * first_try - Time of the first transmission attempt -+ */ -+ os_time_t first_try; -+ -+ /** -+ * next_try - Time for the next transmission attempt -+ */ -+ os_time_t next_try; -+ -+ /** -+ * attempts - Number of transmission attempts -+ */ -+ int attempts; -+ -+ /** -+ * next_wait - Next retransmission wait time in seconds -+ */ -+ int next_wait; -+ -+ /** -+ * last_attempt - Time of the last transmission attempt -+ */ -+ struct os_time last_attempt; -+ -+ /** -+ * shared_secret - Shared secret with the target RADIUS server -+ */ -+ const u8 *shared_secret; -+ -+ /** -+ * shared_secret_len - shared_secret length in octets -+ */ -+ size_t shared_secret_len; -+ -+ /* TODO: server config with failover to backup server(s) */ -+ -+ /** -+ * next - Next message in the list -+ */ -+ struct radius_msg_list *next; -+}; -+ -+ -+/** -+ * struct radius_client_data - Internal RADIUS client data -+ * -+ * This data structure is used internally inside the RADIUS client module. -+ * External users allocate this by calling radius_client_init() and free it by -+ * calling radius_client_deinit(). The pointer to this opaque data is used in -+ * calls to other functions as an identifier for the RADIUS client instance. -+ */ -+struct radius_client_data { -+ /** -+ * ctx - Context pointer for hostapd_logger() callbacks -+ */ -+ void *ctx; -+ -+ /** -+ * conf - RADIUS client configuration (list of RADIUS servers to use) -+ */ -+ struct hostapd_radius_servers *conf; -+ -+ /** -+ * auth_serv_sock - IPv4 socket for RADIUS authentication messages -+ */ -+ int auth_serv_sock; -+ -+ /** -+ * acct_serv_sock - IPv4 socket for RADIUS accounting messages -+ */ -+ int acct_serv_sock; -+ -+ /** -+ * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages -+ */ -+ int auth_serv_sock6; -+ -+ /** -+ * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages -+ */ -+ int acct_serv_sock6; -+ -+ /** -+ * auth_sock - Currently used socket for RADIUS authentication server -+ */ -+ int auth_sock; -+ -+ /** -+ * acct_sock - Currently used socket for RADIUS accounting server -+ */ -+ int acct_sock; -+ -+ /** -+ * auth_handlers - Authentication message handlers -+ */ -+ struct radius_rx_handler *auth_handlers; -+ -+ /** -+ * num_auth_handlers - Number of handlers in auth_handlers -+ */ -+ size_t num_auth_handlers; -+ -+ /** -+ * acct_handlers - Accounting message handlers -+ */ -+ struct radius_rx_handler *acct_handlers; -+ -+ /** -+ * num_acct_handlers - Number of handlers in acct_handlers -+ */ -+ size_t num_acct_handlers; -+ -+ /** -+ * msgs - Pending outgoing RADIUS messages -+ */ -+ struct radius_msg_list *msgs; -+ -+ /** -+ * num_msgs - Number of pending messages in the msgs list -+ */ -+ size_t num_msgs; -+ -+ /** -+ * next_radius_identifier - Next RADIUS message identifier to use -+ */ -+ u8 next_radius_identifier; -+}; -+ -+ -+static int -+radius_change_server(struct radius_client_data *radius, -+ struct hostapd_radius_server *nserv, -+ struct hostapd_radius_server *oserv, -+ int sock, int sock6, int auth); -+static int radius_client_init_acct(struct radius_client_data *radius); -+static int radius_client_init_auth(struct radius_client_data *radius); -+ -+ -+static void radius_client_msg_free(struct radius_msg_list *req) -+{ -+ radius_msg_free(req->msg); -+ os_free(req); -+} -+ -+ -+/** -+ * radius_client_register - Register a RADIUS client RX handler -+ * @radius: RADIUS client context from radius_client_init() -+ * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT) -+ * @handler: Handler for received RADIUS messages -+ * @data: Context pointer for handler callbacks -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to register a handler for processing received RADIUS -+ * authentication and accounting messages. The handler() callback function will -+ * be called whenever a RADIUS message is received from the active server. -+ * -+ * There can be multiple registered RADIUS message handlers. The handlers will -+ * be called in order until one of them indicates that it has processed or -+ * queued the message. -+ */ -+int radius_client_register(struct radius_client_data *radius, -+ RadiusType msg_type, -+ RadiusRxResult (*handler)(struct radius_msg *msg, -+ struct radius_msg *req, -+ const u8 *shared_secret, -+ size_t shared_secret_len, -+ void *data), -+ void *data) -+{ -+ struct radius_rx_handler **handlers, *newh; -+ size_t *num; -+ -+ if (msg_type == RADIUS_ACCT) { -+ handlers = &radius->acct_handlers; -+ num = &radius->num_acct_handlers; -+ } else { -+ handlers = &radius->auth_handlers; -+ num = &radius->num_auth_handlers; -+ } -+ -+ newh = os_realloc(*handlers, -+ (*num + 1) * sizeof(struct radius_rx_handler)); -+ if (newh == NULL) -+ return -1; -+ -+ newh[*num].handler = handler; -+ newh[*num].data = data; -+ (*num)++; -+ *handlers = newh; -+ -+ return 0; -+} -+ -+ -+static void radius_client_handle_send_error(struct radius_client_data *radius, -+ int s, RadiusType msg_type) -+{ -+#ifndef CONFIG_NATIVE_WINDOWS -+ int _errno = errno; -+ perror("send[RADIUS]"); -+ if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || -+ _errno == EBADF) { -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, -+ "Send failed - maybe interface status changed -" -+ " try to connect again"); -+ eloop_unregister_read_sock(s); -+ close(s); -+ if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) -+ radius_client_init_acct(radius); -+ else -+ radius_client_init_auth(radius); -+ } -+#endif /* CONFIG_NATIVE_WINDOWS */ -+} -+ -+ -+static int radius_client_retransmit(struct radius_client_data *radius, -+ struct radius_msg_list *entry, -+ os_time_t now) -+{ -+ struct hostapd_radius_servers *conf = radius->conf; -+ int s; -+ struct wpabuf *buf; -+ -+ if (entry->msg_type == RADIUS_ACCT || -+ entry->msg_type == RADIUS_ACCT_INTERIM) { -+ s = radius->acct_sock; -+ if (entry->attempts == 0) -+ conf->acct_server->requests++; -+ else { -+ conf->acct_server->timeouts++; -+ conf->acct_server->retransmissions++; -+ } -+ } else { -+ s = radius->auth_sock; -+ if (entry->attempts == 0) -+ conf->auth_server->requests++; -+ else { -+ conf->auth_server->timeouts++; -+ conf->auth_server->retransmissions++; -+ } -+ } -+ -+ /* retransmit; remove entry if too many attempts */ -+ entry->attempts++; -+ hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", -+ radius_msg_get_hdr(entry->msg)->identifier); -+ -+ os_get_time(&entry->last_attempt); -+ buf = radius_msg_get_buf(entry->msg); -+ if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) -+ radius_client_handle_send_error(radius, s, entry->msg_type); -+ -+ entry->next_try = now + entry->next_wait; -+ entry->next_wait *= 2; -+ if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) -+ entry->next_wait = RADIUS_CLIENT_MAX_WAIT; -+ if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { -+ printf("Removing un-ACKed RADIUS message due to too many " -+ "failed retransmit attempts\n"); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct radius_client_data *radius = eloop_ctx; -+ struct hostapd_radius_servers *conf = radius->conf; -+ struct os_time now; -+ os_time_t first; -+ struct radius_msg_list *entry, *prev, *tmp; -+ int auth_failover = 0, acct_failover = 0; -+ char abuf[50]; -+ -+ entry = radius->msgs; -+ if (!entry) -+ return; -+ -+ os_get_time(&now); -+ first = 0; -+ -+ prev = NULL; -+ while (entry) { -+ if (now.sec >= entry->next_try && -+ radius_client_retransmit(radius, entry, now.sec)) { -+ if (prev) -+ prev->next = entry->next; -+ else -+ radius->msgs = entry->next; -+ -+ tmp = entry; -+ entry = entry->next; -+ radius_client_msg_free(tmp); -+ radius->num_msgs--; -+ continue; -+ } -+ -+ if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) { -+ if (entry->msg_type == RADIUS_ACCT || -+ entry->msg_type == RADIUS_ACCT_INTERIM) -+ acct_failover++; -+ else -+ auth_failover++; -+ } -+ -+ if (first == 0 || entry->next_try < first) -+ first = entry->next_try; -+ -+ prev = entry; -+ entry = entry->next; -+ } -+ -+ if (radius->msgs) { -+ if (first < now.sec) -+ first = now.sec; -+ eloop_register_timeout(first - now.sec, 0, -+ radius_client_timer, radius, NULL); -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "Next RADIUS client " -+ "retransmit in %ld seconds", -+ (long int) (first - now.sec)); -+ } -+ -+ if (auth_failover && conf->num_auth_servers > 1) { -+ struct hostapd_radius_server *next, *old; -+ old = conf->auth_server; -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_NOTICE, -+ "No response from Authentication server " -+ "%s:%d - failover", -+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), -+ old->port); -+ -+ for (entry = radius->msgs; entry; entry = entry->next) { -+ if (entry->msg_type == RADIUS_AUTH) -+ old->timeouts++; -+ } -+ -+ next = old + 1; -+ if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) -+ next = conf->auth_servers; -+ conf->auth_server = next; -+ radius_change_server(radius, next, old, -+ radius->auth_serv_sock, -+ radius->auth_serv_sock6, 1); -+ } -+ -+ if (acct_failover && conf->num_acct_servers > 1) { -+ struct hostapd_radius_server *next, *old; -+ old = conf->acct_server; -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_NOTICE, -+ "No response from Accounting server " -+ "%s:%d - failover", -+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), -+ old->port); -+ -+ for (entry = radius->msgs; entry; entry = entry->next) { -+ if (entry->msg_type == RADIUS_ACCT || -+ entry->msg_type == RADIUS_ACCT_INTERIM) -+ old->timeouts++; -+ } -+ -+ next = old + 1; -+ if (next > &conf->acct_servers[conf->num_acct_servers - 1]) -+ next = conf->acct_servers; -+ conf->acct_server = next; -+ radius_change_server(radius, next, old, -+ radius->acct_serv_sock, -+ radius->acct_serv_sock6, 0); -+ } -+} -+ -+ -+static void radius_client_update_timeout(struct radius_client_data *radius) -+{ -+ struct os_time now; -+ os_time_t first; -+ struct radius_msg_list *entry; -+ -+ eloop_cancel_timeout(radius_client_timer, radius, NULL); -+ -+ if (radius->msgs == NULL) { -+ return; -+ } -+ -+ first = 0; -+ for (entry = radius->msgs; entry; entry = entry->next) { -+ if (first == 0 || entry->next_try < first) -+ first = entry->next_try; -+ } -+ -+ os_get_time(&now); -+ if (first < now.sec) -+ first = now.sec; -+ eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius, -+ NULL); -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in" -+ " %ld seconds\n", (long int) (first - now.sec)); -+} -+ -+ -+static void radius_client_list_add(struct radius_client_data *radius, -+ struct radius_msg *msg, -+ RadiusType msg_type, -+ const u8 *shared_secret, -+ size_t shared_secret_len, const u8 *addr) -+{ -+ struct radius_msg_list *entry, *prev; -+ -+ if (eloop_terminated()) { -+ /* No point in adding entries to retransmit queue since event -+ * loop has already been terminated. */ -+ radius_msg_free(msg); -+ return; -+ } -+ -+ entry = os_zalloc(sizeof(*entry)); -+ if (entry == NULL) { -+ printf("Failed to add RADIUS packet into retransmit list\n"); -+ radius_msg_free(msg); -+ return; -+ } -+ -+ if (addr) -+ os_memcpy(entry->addr, addr, ETH_ALEN); -+ entry->msg = msg; -+ entry->msg_type = msg_type; -+ entry->shared_secret = shared_secret; -+ entry->shared_secret_len = shared_secret_len; -+ os_get_time(&entry->last_attempt); -+ entry->first_try = entry->last_attempt.sec; -+ entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; -+ entry->attempts = 1; -+ entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; -+ entry->next = radius->msgs; -+ radius->msgs = entry; -+ radius_client_update_timeout(radius); -+ -+ if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) { -+ printf("Removing the oldest un-ACKed RADIUS packet due to " -+ "retransmit list limits.\n"); -+ prev = NULL; -+ while (entry->next) { -+ prev = entry; -+ entry = entry->next; -+ } -+ if (prev) { -+ prev->next = NULL; -+ radius_client_msg_free(entry); -+ } -+ } else -+ radius->num_msgs++; -+} -+ -+ -+static void radius_client_list_del(struct radius_client_data *radius, -+ RadiusType msg_type, const u8 *addr) -+{ -+ struct radius_msg_list *entry, *prev, *tmp; -+ -+ if (addr == NULL) -+ return; -+ -+ entry = radius->msgs; -+ prev = NULL; -+ while (entry) { -+ if (entry->msg_type == msg_type && -+ os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { -+ if (prev) -+ prev->next = entry->next; -+ else -+ radius->msgs = entry->next; -+ tmp = entry; -+ entry = entry->next; -+ hostapd_logger(radius->ctx, addr, -+ HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, -+ "Removing matching RADIUS message"); -+ radius_client_msg_free(tmp); -+ radius->num_msgs--; -+ continue; -+ } -+ prev = entry; -+ entry = entry->next; -+ } -+} -+ -+ -+/** -+ * radius_client_send - Send a RADIUS request -+ * @radius: RADIUS client context from radius_client_init() -+ * @msg: RADIUS message to be sent -+ * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM) -+ * @addr: MAC address of the device related to this message or %NULL -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or -+ * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference -+ * between accounting and interim accounting messages is that the interim -+ * message will override any pending interim accounting updates while a new -+ * accounting message does not remove any pending messages. -+ * -+ * The message is added on the retransmission queue and will be retransmitted -+ * automatically until a response is received or maximum number of retries -+ * (RADIUS_CLIENT_MAX_RETRIES) is reached. -+ * -+ * The related device MAC address can be used to identify pending messages that -+ * can be removed with radius_client_flush_auth() or with interim accounting -+ * updates. -+ */ -+int radius_client_send(struct radius_client_data *radius, -+ struct radius_msg *msg, RadiusType msg_type, -+ const u8 *addr) -+{ -+ struct hostapd_radius_servers *conf = radius->conf; -+ const u8 *shared_secret; -+ size_t shared_secret_len; -+ char *name; -+ int s, res; -+ struct wpabuf *buf; -+ -+ if (msg_type == RADIUS_ACCT_INTERIM) { -+ /* Remove any pending interim acct update for the same STA. */ -+ radius_client_list_del(radius, msg_type, addr); -+ } -+ -+ if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { -+ if (conf->acct_server == NULL) { -+ hostapd_logger(radius->ctx, NULL, -+ HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, -+ "No accounting server configured"); -+ return -1; -+ } -+ shared_secret = conf->acct_server->shared_secret; -+ shared_secret_len = conf->acct_server->shared_secret_len; -+ radius_msg_finish_acct(msg, shared_secret, shared_secret_len); -+ name = "accounting"; -+ s = radius->acct_sock; -+ conf->acct_server->requests++; -+ } else { -+ if (conf->auth_server == NULL) { -+ hostapd_logger(radius->ctx, NULL, -+ HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, -+ "No authentication server configured"); -+ return -1; -+ } -+ shared_secret = conf->auth_server->shared_secret; -+ shared_secret_len = conf->auth_server->shared_secret_len; -+ radius_msg_finish(msg, shared_secret, shared_secret_len); -+ name = "authentication"; -+ s = radius->auth_sock; -+ conf->auth_server->requests++; -+ } -+ -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s " -+ "server", name); -+ if (conf->msg_dumps) -+ radius_msg_dump(msg); -+ -+ buf = radius_msg_get_buf(msg); -+ res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0); -+ if (res < 0) -+ radius_client_handle_send_error(radius, s, msg_type); -+ -+ radius_client_list_add(radius, msg, msg_type, shared_secret, -+ shared_secret_len, addr); -+ -+ return res; -+} -+ -+ -+static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct radius_client_data *radius = eloop_ctx; -+ struct hostapd_radius_servers *conf = radius->conf; -+ RadiusType msg_type = (RadiusType) sock_ctx; -+ int len, roundtrip; -+ unsigned char buf[3000]; -+ struct radius_msg *msg; -+ struct radius_hdr *hdr; -+ struct radius_rx_handler *handlers; -+ size_t num_handlers, i; -+ struct radius_msg_list *req, *prev_req; -+ struct os_time now; -+ struct hostapd_radius_server *rconf; -+ int invalid_authenticator = 0; -+ -+ if (msg_type == RADIUS_ACCT) { -+ handlers = radius->acct_handlers; -+ num_handlers = radius->num_acct_handlers; -+ rconf = conf->acct_server; -+ } else { -+ handlers = radius->auth_handlers; -+ num_handlers = radius->num_auth_handlers; -+ rconf = conf->auth_server; -+ } -+ -+ len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT); -+ if (len < 0) { -+ perror("recv[RADIUS]"); -+ return; -+ } -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS " -+ "server", len); -+ if (len == sizeof(buf)) { -+ printf("Possibly too long UDP frame for our buffer - " -+ "dropping it\n"); -+ return; -+ } -+ -+ msg = radius_msg_parse(buf, len); -+ if (msg == NULL) { -+ printf("Parsing incoming RADIUS frame failed\n"); -+ rconf->malformed_responses++; -+ return; -+ } -+ hdr = radius_msg_get_hdr(msg); -+ -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "Received RADIUS message"); -+ if (conf->msg_dumps) -+ radius_msg_dump(msg); -+ -+ switch (hdr->code) { -+ case RADIUS_CODE_ACCESS_ACCEPT: -+ rconf->access_accepts++; -+ break; -+ case RADIUS_CODE_ACCESS_REJECT: -+ rconf->access_rejects++; -+ break; -+ case RADIUS_CODE_ACCESS_CHALLENGE: -+ rconf->access_challenges++; -+ break; -+ case RADIUS_CODE_ACCOUNTING_RESPONSE: -+ rconf->responses++; -+ break; -+ } -+ -+ prev_req = NULL; -+ req = radius->msgs; -+ while (req) { -+ /* TODO: also match by src addr:port of the packet when using -+ * alternative RADIUS servers (?) */ -+ if ((req->msg_type == msg_type || -+ (req->msg_type == RADIUS_ACCT_INTERIM && -+ msg_type == RADIUS_ACCT)) && -+ radius_msg_get_hdr(req->msg)->identifier == -+ hdr->identifier) -+ break; -+ -+ prev_req = req; -+ req = req->next; -+ } -+ -+ if (req == NULL) { -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, -+ "No matching RADIUS request found (type=%d " -+ "id=%d) - dropping packet", -+ msg_type, hdr->identifier); -+ goto fail; -+ } -+ -+ os_get_time(&now); -+ roundtrip = (now.sec - req->last_attempt.sec) * 100 + -+ (now.usec - req->last_attempt.usec) / 10000; -+ hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, -+ "Received RADIUS packet matched with a pending " -+ "request, round trip time %d.%02d sec", -+ roundtrip / 100, roundtrip % 100); -+ rconf->round_trip_time = roundtrip; -+ -+ /* Remove ACKed RADIUS packet from retransmit list */ -+ if (prev_req) -+ prev_req->next = req->next; -+ else -+ radius->msgs = req->next; -+ radius->num_msgs--; -+ -+ for (i = 0; i < num_handlers; i++) { -+ RadiusRxResult res; -+ res = handlers[i].handler(msg, req->msg, req->shared_secret, -+ req->shared_secret_len, -+ handlers[i].data); -+ switch (res) { -+ case RADIUS_RX_PROCESSED: -+ radius_msg_free(msg); -+ /* continue */ -+ case RADIUS_RX_QUEUED: -+ radius_client_msg_free(req); -+ return; -+ case RADIUS_RX_INVALID_AUTHENTICATOR: -+ invalid_authenticator++; -+ /* continue */ -+ case RADIUS_RX_UNKNOWN: -+ /* continue with next handler */ -+ break; -+ } -+ } -+ -+ if (invalid_authenticator) -+ rconf->bad_authenticators++; -+ else -+ rconf->unknown_types++; -+ hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " -+ "(type=%d code=%d id=%d)%s - dropping packet", -+ msg_type, hdr->code, hdr->identifier, -+ invalid_authenticator ? " [INVALID AUTHENTICATOR]" : -+ ""); -+ radius_client_msg_free(req); -+ -+ fail: -+ radius_msg_free(msg); -+} -+ -+ -+/** -+ * radius_client_get_id - Get an identifier for a new RADIUS message -+ * @radius: RADIUS client context from radius_client_init() -+ * Returns: Allocated identifier -+ * -+ * This function is used to fetch a unique (among pending requests) identifier -+ * for a new RADIUS message. -+ */ -+u8 radius_client_get_id(struct radius_client_data *radius) -+{ -+ struct radius_msg_list *entry, *prev, *_remove; -+ u8 id = radius->next_radius_identifier++; -+ -+ /* remove entries with matching id from retransmit list to avoid -+ * using new reply from the RADIUS server with an old request */ -+ entry = radius->msgs; -+ prev = NULL; -+ while (entry) { -+ if (radius_msg_get_hdr(entry->msg)->identifier == id) { -+ hostapd_logger(radius->ctx, entry->addr, -+ HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, -+ "Removing pending RADIUS message, " -+ "since its id (%d) is reused", id); -+ if (prev) -+ prev->next = entry->next; -+ else -+ radius->msgs = entry->next; -+ _remove = entry; -+ } else { -+ _remove = NULL; -+ prev = entry; -+ } -+ entry = entry->next; -+ -+ if (_remove) -+ radius_client_msg_free(_remove); -+ } -+ -+ return id; -+} -+ -+ -+/** -+ * radius_client_flush - Flush all pending RADIUS client messages -+ * @radius: RADIUS client context from radius_client_init() -+ * @only_auth: Whether only authentication messages are removed -+ */ -+void radius_client_flush(struct radius_client_data *radius, int only_auth) -+{ -+ struct radius_msg_list *entry, *prev, *tmp; -+ -+ if (!radius) -+ return; -+ -+ prev = NULL; -+ entry = radius->msgs; -+ -+ while (entry) { -+ if (!only_auth || entry->msg_type == RADIUS_AUTH) { -+ if (prev) -+ prev->next = entry->next; -+ else -+ radius->msgs = entry->next; -+ -+ tmp = entry; -+ entry = entry->next; -+ radius_client_msg_free(tmp); -+ radius->num_msgs--; -+ } else { -+ prev = entry; -+ entry = entry->next; -+ } -+ } -+ -+ if (radius->msgs == NULL) -+ eloop_cancel_timeout(radius_client_timer, radius, NULL); -+} -+ -+ -+static void radius_client_update_acct_msgs(struct radius_client_data *radius, -+ const u8 *shared_secret, -+ size_t shared_secret_len) -+{ -+ struct radius_msg_list *entry; -+ -+ if (!radius) -+ return; -+ -+ for (entry = radius->msgs; entry; entry = entry->next) { -+ if (entry->msg_type == RADIUS_ACCT) { -+ entry->shared_secret = shared_secret; -+ entry->shared_secret_len = shared_secret_len; -+ radius_msg_finish_acct(entry->msg, shared_secret, -+ shared_secret_len); -+ } -+ } -+} -+ -+ -+static int -+radius_change_server(struct radius_client_data *radius, -+ struct hostapd_radius_server *nserv, -+ struct hostapd_radius_server *oserv, -+ int sock, int sock6, int auth) -+{ -+ struct sockaddr_in serv, claddr; -+#ifdef CONFIG_IPV6 -+ struct sockaddr_in6 serv6, claddr6; -+#endif /* CONFIG_IPV6 */ -+ struct sockaddr *addr, *cl_addr; -+ socklen_t addrlen, claddrlen; -+ char abuf[50]; -+ int sel_sock; -+ struct radius_msg_list *entry; -+ struct hostapd_radius_servers *conf = radius->conf; -+ -+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_INFO, -+ "%s server %s:%d", -+ auth ? "Authentication" : "Accounting", -+ hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), -+ nserv->port); -+ -+ if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || -+ os_memcmp(nserv->shared_secret, oserv->shared_secret, -+ nserv->shared_secret_len) != 0) { -+ /* Pending RADIUS packets used different shared secret, so -+ * they need to be modified. Update accounting message -+ * authenticators here. Authentication messages are removed -+ * since they would require more changes and the new RADIUS -+ * server may not be prepared to receive them anyway due to -+ * missing state information. Client will likely retry -+ * authentication, so this should not be an issue. */ -+ if (auth) -+ radius_client_flush(radius, 1); -+ else { -+ radius_client_update_acct_msgs( -+ radius, nserv->shared_secret, -+ nserv->shared_secret_len); -+ } -+ } -+ -+ /* Reset retry counters for the new server */ -+ for (entry = radius->msgs; entry; entry = entry->next) { -+ if ((auth && entry->msg_type != RADIUS_AUTH) || -+ (!auth && entry->msg_type != RADIUS_ACCT)) -+ continue; -+ entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; -+ entry->attempts = 0; -+ entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; -+ } -+ -+ if (radius->msgs) { -+ eloop_cancel_timeout(radius_client_timer, radius, NULL); -+ eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, -+ radius_client_timer, radius, NULL); -+ } -+ -+ switch (nserv->addr.af) { -+ case AF_INET: -+ os_memset(&serv, 0, sizeof(serv)); -+ serv.sin_family = AF_INET; -+ serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; -+ serv.sin_port = htons(nserv->port); -+ addr = (struct sockaddr *) &serv; -+ addrlen = sizeof(serv); -+ sel_sock = sock; -+ break; -+#ifdef CONFIG_IPV6 -+ case AF_INET6: -+ os_memset(&serv6, 0, sizeof(serv6)); -+ serv6.sin6_family = AF_INET6; -+ os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, -+ sizeof(struct in6_addr)); -+ serv6.sin6_port = htons(nserv->port); -+ addr = (struct sockaddr *) &serv6; -+ addrlen = sizeof(serv6); -+ sel_sock = sock6; -+ break; -+#endif /* CONFIG_IPV6 */ -+ default: -+ return -1; -+ } -+ -+ if (conf->force_client_addr) { -+ switch (conf->client_addr.af) { -+ case AF_INET: -+ os_memset(&claddr, 0, sizeof(claddr)); -+ claddr.sin_family = AF_INET; -+ claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr; -+ claddr.sin_port = htons(0); -+ cl_addr = (struct sockaddr *) &claddr; -+ claddrlen = sizeof(claddr); -+ break; -+#ifdef CONFIG_IPV6 -+ case AF_INET6: -+ os_memset(&claddr6, 0, sizeof(claddr6)); -+ claddr6.sin6_family = AF_INET6; -+ os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6, -+ sizeof(struct in6_addr)); -+ claddr6.sin6_port = htons(0); -+ cl_addr = (struct sockaddr *) &claddr6; -+ claddrlen = sizeof(claddr6); -+ break; -+#endif /* CONFIG_IPV6 */ -+ default: -+ return -1; -+ } -+ -+ if (bind(sel_sock, cl_addr, claddrlen) < 0) { -+ perror("bind[radius]"); -+ return -1; -+ } -+ } -+ -+ if (connect(sel_sock, addr, addrlen) < 0) { -+ perror("connect[radius]"); -+ return -1; -+ } -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ switch (nserv->addr.af) { -+ case AF_INET: -+ claddrlen = sizeof(claddr); -+ getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen); -+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", -+ inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port)); -+ break; -+#ifdef CONFIG_IPV6 -+ case AF_INET6: { -+ claddrlen = sizeof(claddr6); -+ getsockname(sel_sock, (struct sockaddr *) &claddr6, -+ &claddrlen); -+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", -+ inet_ntop(AF_INET6, &claddr6.sin6_addr, -+ abuf, sizeof(abuf)), -+ ntohs(claddr6.sin6_port)); -+ break; -+ } -+#endif /* CONFIG_IPV6 */ -+ } -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ if (auth) -+ radius->auth_sock = sel_sock; -+ else -+ radius->acct_sock = sel_sock; -+ -+ return 0; -+} -+ -+ -+static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct radius_client_data *radius = eloop_ctx; -+ struct hostapd_radius_servers *conf = radius->conf; -+ struct hostapd_radius_server *oserv; -+ -+ if (radius->auth_sock >= 0 && conf->auth_servers && -+ conf->auth_server != conf->auth_servers) { -+ oserv = conf->auth_server; -+ conf->auth_server = conf->auth_servers; -+ radius_change_server(radius, conf->auth_server, oserv, -+ radius->auth_serv_sock, -+ radius->auth_serv_sock6, 1); -+ } -+ -+ if (radius->acct_sock >= 0 && conf->acct_servers && -+ conf->acct_server != conf->acct_servers) { -+ oserv = conf->acct_server; -+ conf->acct_server = conf->acct_servers; -+ radius_change_server(radius, conf->acct_server, oserv, -+ radius->acct_serv_sock, -+ radius->acct_serv_sock6, 0); -+ } -+ -+ if (conf->retry_primary_interval) -+ eloop_register_timeout(conf->retry_primary_interval, 0, -+ radius_retry_primary_timer, radius, -+ NULL); -+} -+ -+ -+static int radius_client_disable_pmtu_discovery(int s) -+{ -+ int r = -1; -+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) -+ /* Turn off Path MTU discovery on IPv4/UDP sockets. */ -+ int action = IP_PMTUDISC_DONT; -+ r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, -+ sizeof(action)); -+ if (r == -1) -+ wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " -+ "%s", strerror(errno)); -+#endif -+ return r; -+} -+ -+ -+static int radius_client_init_auth(struct radius_client_data *radius) -+{ -+ struct hostapd_radius_servers *conf = radius->conf; -+ int ok = 0; -+ -+ radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (radius->auth_serv_sock < 0) -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ else { -+ radius_client_disable_pmtu_discovery(radius->auth_serv_sock); -+ ok++; -+ } -+ -+#ifdef CONFIG_IPV6 -+ radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); -+ if (radius->auth_serv_sock6 < 0) -+ perror("socket[PF_INET6,SOCK_DGRAM]"); -+ else -+ ok++; -+#endif /* CONFIG_IPV6 */ -+ -+ if (ok == 0) -+ return -1; -+ -+ radius_change_server(radius, conf->auth_server, NULL, -+ radius->auth_serv_sock, radius->auth_serv_sock6, -+ 1); -+ -+ if (radius->auth_serv_sock >= 0 && -+ eloop_register_read_sock(radius->auth_serv_sock, -+ radius_client_receive, radius, -+ (void *) RADIUS_AUTH)) { -+ printf("Could not register read socket for authentication " -+ "server\n"); -+ return -1; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (radius->auth_serv_sock6 >= 0 && -+ eloop_register_read_sock(radius->auth_serv_sock6, -+ radius_client_receive, radius, -+ (void *) RADIUS_AUTH)) { -+ printf("Could not register read socket for authentication " -+ "server\n"); -+ return -1; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ return 0; -+} -+ -+ -+static int radius_client_init_acct(struct radius_client_data *radius) -+{ -+ struct hostapd_radius_servers *conf = radius->conf; -+ int ok = 0; -+ -+ radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); -+ if (radius->acct_serv_sock < 0) -+ perror("socket[PF_INET,SOCK_DGRAM]"); -+ else { -+ radius_client_disable_pmtu_discovery(radius->acct_serv_sock); -+ ok++; -+ } -+ -+#ifdef CONFIG_IPV6 -+ radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); -+ if (radius->acct_serv_sock6 < 0) -+ perror("socket[PF_INET6,SOCK_DGRAM]"); -+ else -+ ok++; -+#endif /* CONFIG_IPV6 */ -+ -+ if (ok == 0) -+ return -1; -+ -+ radius_change_server(radius, conf->acct_server, NULL, -+ radius->acct_serv_sock, radius->acct_serv_sock6, -+ 0); -+ -+ if (radius->acct_serv_sock >= 0 && -+ eloop_register_read_sock(radius->acct_serv_sock, -+ radius_client_receive, radius, -+ (void *) RADIUS_ACCT)) { -+ printf("Could not register read socket for accounting " -+ "server\n"); -+ return -1; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (radius->acct_serv_sock6 >= 0 && -+ eloop_register_read_sock(radius->acct_serv_sock6, -+ radius_client_receive, radius, -+ (void *) RADIUS_ACCT)) { -+ printf("Could not register read socket for accounting " -+ "server\n"); -+ return -1; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ return 0; -+} -+ -+ -+/** -+ * radius_client_init - Initialize RADIUS client -+ * @ctx: Callback context to be used in hostapd_logger() calls -+ * @conf: RADIUS client configuration (RADIUS servers) -+ * Returns: Pointer to private RADIUS client context or %NULL on failure -+ * -+ * The caller is responsible for keeping the configuration data available for -+ * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is -+ * called for the returned context pointer. -+ */ -+struct radius_client_data * -+radius_client_init(void *ctx, struct hostapd_radius_servers *conf) -+{ -+ struct radius_client_data *radius; -+ -+ radius = os_zalloc(sizeof(struct radius_client_data)); -+ if (radius == NULL) -+ return NULL; -+ -+ radius->ctx = ctx; -+ radius->conf = conf; -+ radius->auth_serv_sock = radius->acct_serv_sock = -+ radius->auth_serv_sock6 = radius->acct_serv_sock6 = -+ radius->auth_sock = radius->acct_sock = -1; -+ -+ if (conf->auth_server && radius_client_init_auth(radius)) { -+ radius_client_deinit(radius); -+ return NULL; -+ } -+ -+ if (conf->acct_server && radius_client_init_acct(radius)) { -+ radius_client_deinit(radius); -+ return NULL; -+ } -+ -+ if (conf->retry_primary_interval) -+ eloop_register_timeout(conf->retry_primary_interval, 0, -+ radius_retry_primary_timer, radius, -+ NULL); -+ -+ return radius; -+} -+ -+ -+/** -+ * radius_client_deinit - Deinitialize RADIUS client -+ * @radius: RADIUS client context from radius_client_init() -+ */ -+void radius_client_deinit(struct radius_client_data *radius) -+{ -+ if (!radius) -+ return; -+ -+ if (radius->auth_serv_sock >= 0) -+ eloop_unregister_read_sock(radius->auth_serv_sock); -+ if (radius->acct_serv_sock >= 0) -+ eloop_unregister_read_sock(radius->acct_serv_sock); -+#ifdef CONFIG_IPV6 -+ if (radius->auth_serv_sock6 >= 0) -+ eloop_unregister_read_sock(radius->auth_serv_sock6); -+ if (radius->acct_serv_sock6 >= 0) -+ eloop_unregister_read_sock(radius->acct_serv_sock6); -+#endif /* CONFIG_IPV6 */ -+ -+ eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); -+ -+ radius_client_flush(radius, 0); -+ os_free(radius->auth_handlers); -+ os_free(radius->acct_handlers); -+ os_free(radius); -+} -+ -+ -+/** -+ * radius_client_flush_auth - Flush pending RADIUS messages for an address -+ * @radius: RADIUS client context from radius_client_init() -+ * @addr: MAC address of the related device -+ * -+ * This function can be used to remove pending RADIUS authentication messages -+ * that are related to a specific device. The addr parameter is matched with -+ * the one used in radius_client_send() call that was used to transmit the -+ * authentication request. -+ */ -+void radius_client_flush_auth(struct radius_client_data *radius, -+ const u8 *addr) -+{ -+ struct radius_msg_list *entry, *prev, *tmp; -+ -+ prev = NULL; -+ entry = radius->msgs; -+ while (entry) { -+ if (entry->msg_type == RADIUS_AUTH && -+ os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { -+ hostapd_logger(radius->ctx, addr, -+ HOSTAPD_MODULE_RADIUS, -+ HOSTAPD_LEVEL_DEBUG, -+ "Removing pending RADIUS authentication" -+ " message for removed client"); -+ -+ if (prev) -+ prev->next = entry->next; -+ else -+ radius->msgs = entry->next; -+ -+ tmp = entry; -+ entry = entry->next; -+ radius_client_msg_free(tmp); -+ radius->num_msgs--; -+ continue; -+ } -+ -+ prev = entry; -+ entry = entry->next; -+ } -+} -+ -+ -+static int radius_client_dump_auth_server(char *buf, size_t buflen, -+ struct hostapd_radius_server *serv, -+ struct radius_client_data *cli) -+{ -+ int pending = 0; -+ struct radius_msg_list *msg; -+ char abuf[50]; -+ -+ if (cli) { -+ for (msg = cli->msgs; msg; msg = msg->next) { -+ if (msg->msg_type == RADIUS_AUTH) -+ pending++; -+ } -+ } -+ -+ return os_snprintf(buf, buflen, -+ "radiusAuthServerIndex=%d\n" -+ "radiusAuthServerAddress=%s\n" -+ "radiusAuthClientServerPortNumber=%d\n" -+ "radiusAuthClientRoundTripTime=%d\n" -+ "radiusAuthClientAccessRequests=%u\n" -+ "radiusAuthClientAccessRetransmissions=%u\n" -+ "radiusAuthClientAccessAccepts=%u\n" -+ "radiusAuthClientAccessRejects=%u\n" -+ "radiusAuthClientAccessChallenges=%u\n" -+ "radiusAuthClientMalformedAccessResponses=%u\n" -+ "radiusAuthClientBadAuthenticators=%u\n" -+ "radiusAuthClientPendingRequests=%u\n" -+ "radiusAuthClientTimeouts=%u\n" -+ "radiusAuthClientUnknownTypes=%u\n" -+ "radiusAuthClientPacketsDropped=%u\n", -+ serv->index, -+ hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), -+ serv->port, -+ serv->round_trip_time, -+ serv->requests, -+ serv->retransmissions, -+ serv->access_accepts, -+ serv->access_rejects, -+ serv->access_challenges, -+ serv->malformed_responses, -+ serv->bad_authenticators, -+ pending, -+ serv->timeouts, -+ serv->unknown_types, -+ serv->packets_dropped); -+} -+ -+ -+static int radius_client_dump_acct_server(char *buf, size_t buflen, -+ struct hostapd_radius_server *serv, -+ struct radius_client_data *cli) -+{ -+ int pending = 0; -+ struct radius_msg_list *msg; -+ char abuf[50]; -+ -+ if (cli) { -+ for (msg = cli->msgs; msg; msg = msg->next) { -+ if (msg->msg_type == RADIUS_ACCT || -+ msg->msg_type == RADIUS_ACCT_INTERIM) -+ pending++; -+ } -+ } -+ -+ return os_snprintf(buf, buflen, -+ "radiusAccServerIndex=%d\n" -+ "radiusAccServerAddress=%s\n" -+ "radiusAccClientServerPortNumber=%d\n" -+ "radiusAccClientRoundTripTime=%d\n" -+ "radiusAccClientRequests=%u\n" -+ "radiusAccClientRetransmissions=%u\n" -+ "radiusAccClientResponses=%u\n" -+ "radiusAccClientMalformedResponses=%u\n" -+ "radiusAccClientBadAuthenticators=%u\n" -+ "radiusAccClientPendingRequests=%u\n" -+ "radiusAccClientTimeouts=%u\n" -+ "radiusAccClientUnknownTypes=%u\n" -+ "radiusAccClientPacketsDropped=%u\n", -+ serv->index, -+ hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), -+ serv->port, -+ serv->round_trip_time, -+ serv->requests, -+ serv->retransmissions, -+ serv->responses, -+ serv->malformed_responses, -+ serv->bad_authenticators, -+ pending, -+ serv->timeouts, -+ serv->unknown_types, -+ serv->packets_dropped); -+} -+ -+ -+/** -+ * radius_client_get_mib - Get RADIUS client MIB information -+ * @radius: RADIUS client context from radius_client_init() -+ * @buf: Buffer for returning MIB data in text format -+ * @buflen: Maximum buf length in octets -+ * Returns: Number of octets written into the buffer -+ */ -+int radius_client_get_mib(struct radius_client_data *radius, char *buf, -+ size_t buflen) -+{ -+ struct hostapd_radius_servers *conf = radius->conf; -+ int i; -+ struct hostapd_radius_server *serv; -+ int count = 0; -+ -+ if (conf->auth_servers) { -+ for (i = 0; i < conf->num_auth_servers; i++) { -+ serv = &conf->auth_servers[i]; -+ count += radius_client_dump_auth_server( -+ buf + count, buflen - count, serv, -+ serv == conf->auth_server ? -+ radius : NULL); -+ } -+ } -+ -+ if (conf->acct_servers) { -+ for (i = 0; i < conf->num_acct_servers; i++) { -+ serv = &conf->acct_servers[i]; -+ count += radius_client_dump_acct_server( -+ buf + count, buflen - count, serv, -+ serv == conf->acct_server ? -+ radius : NULL); -+ } -+ } -+ -+ return count; -+} -+ -+ -+void radius_client_reconfig(struct radius_client_data *radius, -+ struct hostapd_radius_servers *conf) -+{ -+ if (radius) -+ radius->conf = conf; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.h -new file mode 100644 -index 0000000000000..18e729041b30d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_client.h -@@ -0,0 +1,265 @@ -+/* -+ * RADIUS client -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef RADIUS_CLIENT_H -+#define RADIUS_CLIENT_H -+ -+#include "ip_addr.h" -+ -+struct radius_msg; -+ -+/** -+ * struct hostapd_radius_server - RADIUS server information for RADIUS client -+ * -+ * This structure contains information about a RADIUS server. The values are -+ * mainly for MIB information. The MIB variable prefix (radiusAuth or -+ * radiusAcc) depends on whether this is an authentication or accounting -+ * server. -+ * -+ * radiusAuthClientPendingRequests (or radiusAccClientPendingRequests) is the -+ * number struct radius_client_data::msgs for matching msg_type. -+ */ -+struct hostapd_radius_server { -+ /** -+ * addr - radiusAuthServerAddress or radiusAccServerAddress -+ */ -+ struct hostapd_ip_addr addr; -+ -+ /** -+ * port - radiusAuthClientServerPortNumber or radiusAccClientServerPortNumber -+ */ -+ int port; -+ -+ /** -+ * shared_secret - Shared secret for authenticating RADIUS messages -+ */ -+ u8 *shared_secret; -+ -+ /** -+ * shared_secret_len - Length of shared_secret in octets -+ */ -+ size_t shared_secret_len; -+ -+ /* Dynamic (not from configuration file) MIB data */ -+ -+ /** -+ * index - radiusAuthServerIndex or radiusAccServerIndex -+ */ -+ int index; -+ -+ /** -+ * round_trip_time - radiusAuthClientRoundTripTime or radiusAccClientRoundTripTime -+ * Round-trip time in hundredths of a second. -+ */ -+ int round_trip_time; -+ -+ /** -+ * requests - radiusAuthClientAccessRequests or radiusAccClientRequests -+ */ -+ u32 requests; -+ -+ /** -+ * retransmissions - radiusAuthClientAccessRetransmissions or radiusAccClientRetransmissions -+ */ -+ u32 retransmissions; -+ -+ /** -+ * access_accepts - radiusAuthClientAccessAccepts -+ */ -+ u32 access_accepts; -+ -+ /** -+ * access_rejects - radiusAuthClientAccessRejects -+ */ -+ u32 access_rejects; -+ -+ /** -+ * access_challenges - radiusAuthClientAccessChallenges -+ */ -+ u32 access_challenges; -+ -+ /** -+ * responses - radiusAccClientResponses -+ */ -+ u32 responses; -+ -+ /** -+ * malformed_responses - radiusAuthClientMalformedAccessResponses or radiusAccClientMalformedResponses -+ */ -+ u32 malformed_responses; -+ -+ /** -+ * bad_authenticators - radiusAuthClientBadAuthenticators or radiusAccClientBadAuthenticators -+ */ -+ u32 bad_authenticators; -+ -+ /** -+ * timeouts - radiusAuthClientTimeouts or radiusAccClientTimeouts -+ */ -+ u32 timeouts; -+ -+ /** -+ * unknown_types - radiusAuthClientUnknownTypes or radiusAccClientUnknownTypes -+ */ -+ u32 unknown_types; -+ -+ /** -+ * packets_dropped - radiusAuthClientPacketsDropped or radiusAccClientPacketsDropped -+ */ -+ u32 packets_dropped; -+}; -+ -+/** -+ * struct hostapd_radius_servers - RADIUS servers for RADIUS client -+ */ -+struct hostapd_radius_servers { -+ /** -+ * auth_servers - RADIUS Authentication servers in priority order -+ */ -+ struct hostapd_radius_server *auth_servers; -+ -+ /** -+ * num_auth_servers - Number of auth_servers entries -+ */ -+ int num_auth_servers; -+ -+ /** -+ * auth_server - The current Authentication server -+ */ -+ struct hostapd_radius_server *auth_server; -+ -+ /** -+ * acct_servers - RADIUS Accounting servers in priority order -+ */ -+ struct hostapd_radius_server *acct_servers; -+ -+ /** -+ * num_acct_servers - Number of acct_servers entries -+ */ -+ int num_acct_servers; -+ -+ /** -+ * acct_server - The current Accounting server -+ */ -+ struct hostapd_radius_server *acct_server; -+ -+ /** -+ * retry_primary_interval - Retry interval for trying primary server -+ * -+ * This specifies a retry interval in sexconds for trying to return to -+ * the primary RADIUS server. RADIUS client code will automatically try -+ * to use the next server when the current server is not replying to -+ * requests. If this interval is set (non-zero), the primary server -+ * will be retried after the specified number of seconds has passed -+ * even if the current used secondary server is still working. -+ */ -+ int retry_primary_interval; -+ -+ /** -+ * msg_dumps - Whether RADIUS message details are shown in stdout -+ */ -+ int msg_dumps; -+ -+ /** -+ * client_addr - Client (local) address to use if force_client_addr -+ */ -+ struct hostapd_ip_addr client_addr; -+ -+ /** -+ * force_client_addr - Whether to force client (local) address -+ */ -+ int force_client_addr; -+}; -+ -+ -+/** -+ * RadiusType - RADIUS server type for RADIUS client -+ */ -+typedef enum { -+ /** -+ * RADIUS authentication -+ */ -+ RADIUS_AUTH, -+ -+ /** -+ * RADIUS_ACCT - RADIUS accounting -+ */ -+ RADIUS_ACCT, -+ -+ /** -+ * RADIUS_ACCT_INTERIM - RADIUS interim accounting message -+ * -+ * Used only with radius_client_send(). This behaves just like -+ * RADIUS_ACCT, but removes any pending interim RADIUS Accounting -+ * messages for the same STA before sending the new interim update. -+ */ -+ RADIUS_ACCT_INTERIM -+} RadiusType; -+ -+/** -+ * RadiusRxResult - RADIUS client RX handler result -+ */ -+typedef enum { -+ /** -+ * RADIUS_RX_PROCESSED - Message processed -+ * -+ * This stops handler calls and frees the message. -+ */ -+ RADIUS_RX_PROCESSED, -+ -+ /** -+ * RADIUS_RX_QUEUED - Message has been queued -+ * -+ * This stops handler calls, but does not free the message; the handler -+ * that returned this is responsible for eventually freeing the -+ * message. -+ */ -+ RADIUS_RX_QUEUED, -+ -+ /** -+ * RADIUS_RX_UNKNOWN - Message is not for this handler -+ */ -+ RADIUS_RX_UNKNOWN, -+ -+ /** -+ * RADIUS_RX_INVALID_AUTHENTICATOR - Message has invalid Authenticator -+ */ -+ RADIUS_RX_INVALID_AUTHENTICATOR -+} RadiusRxResult; -+ -+struct radius_client_data; -+ -+int radius_client_register(struct radius_client_data *radius, -+ RadiusType msg_type, -+ RadiusRxResult (*handler) -+ (struct radius_msg *msg, struct radius_msg *req, -+ const u8 *shared_secret, size_t shared_secret_len, -+ void *data), -+ void *data); -+int radius_client_send(struct radius_client_data *radius, -+ struct radius_msg *msg, -+ RadiusType msg_type, const u8 *addr); -+u8 radius_client_get_id(struct radius_client_data *radius); -+void radius_client_flush(struct radius_client_data *radius, int only_auth); -+struct radius_client_data * -+radius_client_init(void *ctx, struct hostapd_radius_servers *conf); -+void radius_client_deinit(struct radius_client_data *radius); -+void radius_client_flush_auth(struct radius_client_data *radius, -+ const u8 *addr); -+int radius_client_get_mib(struct radius_client_data *radius, char *buf, -+ size_t buflen); -+void radius_client_reconfig(struct radius_client_data *radius, -+ struct hostapd_radius_servers *conf); -+ -+#endif /* RADIUS_CLIENT_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.c -new file mode 100644 -index 0000000000000..6f1c3a50be873 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.c -@@ -0,0 +1,1527 @@ -+/* -+ * RADIUS authentication server -+ * Copyright (c) 2005-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "radius.h" -+#include "eloop.h" -+#include "eap_server/eap.h" -+#include "radius_server.h" -+ -+/** -+ * RADIUS_SESSION_TIMEOUT - Session timeout in seconds -+ */ -+#define RADIUS_SESSION_TIMEOUT 60 -+ -+/** -+ * RADIUS_MAX_SESSION - Maximum number of active sessions -+ */ -+#define RADIUS_MAX_SESSION 100 -+ -+/** -+ * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages -+ */ -+#define RADIUS_MAX_MSG_LEN 3000 -+ -+static struct eapol_callbacks radius_server_eapol_cb; -+ -+struct radius_client; -+struct radius_server_data; -+ -+/** -+ * struct radius_server_counters - RADIUS server statistics counters -+ */ -+struct radius_server_counters { -+ u32 access_requests; -+ u32 invalid_requests; -+ u32 dup_access_requests; -+ u32 access_accepts; -+ u32 access_rejects; -+ u32 access_challenges; -+ u32 malformed_access_requests; -+ u32 bad_authenticators; -+ u32 packets_dropped; -+ u32 unknown_types; -+}; -+ -+/** -+ * struct radius_session - Internal RADIUS server data for a session -+ */ -+struct radius_session { -+ struct radius_session *next; -+ struct radius_client *client; -+ struct radius_server_data *server; -+ unsigned int sess_id; -+ struct eap_sm *eap; -+ struct eap_eapol_interface *eap_if; -+ -+ struct radius_msg *last_msg; -+ char *last_from_addr; -+ int last_from_port; -+ struct sockaddr_storage last_from; -+ socklen_t last_fromlen; -+ u8 last_identifier; -+ struct radius_msg *last_reply; -+ u8 last_authenticator[16]; -+}; -+ -+/** -+ * struct radius_client - Internal RADIUS server data for a client -+ */ -+struct radius_client { -+ struct radius_client *next; -+ struct in_addr addr; -+ struct in_addr mask; -+#ifdef CONFIG_IPV6 -+ struct in6_addr addr6; -+ struct in6_addr mask6; -+#endif /* CONFIG_IPV6 */ -+ char *shared_secret; -+ int shared_secret_len; -+ struct radius_session *sessions; -+ struct radius_server_counters counters; -+}; -+ -+/** -+ * struct radius_server_data - Internal RADIUS server data -+ */ -+struct radius_server_data { -+ /** -+ * auth_sock - Socket for RADIUS authentication messages -+ */ -+ int auth_sock; -+ -+ /** -+ * clients - List of authorized RADIUS clients -+ */ -+ struct radius_client *clients; -+ -+ /** -+ * next_sess_id - Next session identifier -+ */ -+ unsigned int next_sess_id; -+ -+ /** -+ * conf_ctx - Context pointer for callbacks -+ * -+ * This is used as the ctx argument in get_eap_user() calls. -+ */ -+ void *conf_ctx; -+ -+ /** -+ * num_sess - Number of active sessions -+ */ -+ int num_sess; -+ -+ /** -+ * eap_sim_db_priv - EAP-SIM/AKA database context -+ * -+ * This is passed to the EAP-SIM/AKA server implementation as a -+ * callback context. -+ */ -+ void *eap_sim_db_priv; -+ -+ /** -+ * ssl_ctx - TLS context -+ * -+ * This is passed to the EAP server implementation as a callback -+ * context for TLS operations. -+ */ -+ void *ssl_ctx; -+ -+ /** -+ * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST -+ * -+ * This parameter is used to set a key for EAP-FAST to encrypt the -+ * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If -+ * set, must point to a 16-octet key. -+ */ -+ u8 *pac_opaque_encr_key; -+ -+ /** -+ * eap_fast_a_id - EAP-FAST authority identity (A-ID) -+ * -+ * If EAP-FAST is not used, this can be set to %NULL. In theory, this -+ * is a variable length field, but due to some existing implementations -+ * requiring A-ID to be 16 octets in length, it is recommended to use -+ * that length for the field to provide interoperability with deployed -+ * peer implementations. -+ */ -+ u8 *eap_fast_a_id; -+ -+ /** -+ * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets -+ */ -+ size_t eap_fast_a_id_len; -+ -+ /** -+ * eap_fast_a_id_info - EAP-FAST authority identifier information -+ * -+ * This A-ID-Info contains a user-friendly name for the A-ID. For -+ * example, this could be the enterprise and server names in -+ * human-readable format. This field is encoded as UTF-8. If EAP-FAST -+ * is not used, this can be set to %NULL. -+ */ -+ char *eap_fast_a_id_info; -+ -+ /** -+ * eap_fast_prov - EAP-FAST provisioning modes -+ * -+ * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, -+ * 2 = only authenticated provisioning allowed, 3 = both provisioning -+ * modes allowed. -+ */ -+ int eap_fast_prov; -+ -+ /** -+ * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds -+ * -+ * This is the hard limit on how long a provisioned PAC-Key can be -+ * used. -+ */ -+ int pac_key_lifetime; -+ -+ /** -+ * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds -+ * -+ * This is a soft limit on the PAC-Key. The server will automatically -+ * generate a new PAC-Key when this number of seconds (or fewer) of the -+ * lifetime remains. -+ */ -+ int pac_key_refresh_time; -+ -+ /** -+ * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication -+ * -+ * This controls whether the protected success/failure indication -+ * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. -+ */ -+ int eap_sim_aka_result_ind; -+ -+ /** -+ * tnc - Trusted Network Connect (TNC) -+ * -+ * This controls whether TNC is enabled and will be required before the -+ * peer is allowed to connect. Note: This is only used with EAP-TTLS -+ * and EAP-FAST. If any other EAP method is enabled, the peer will be -+ * allowed to connect without TNC. -+ */ -+ int tnc; -+ -+ /** -+ * pwd_group - The D-H group assigned for EAP-pwd -+ * -+ * If EAP-pwd is not used it can be set to zero. -+ */ -+ u16 pwd_group; -+ -+ /** -+ * wps - Wi-Fi Protected Setup context -+ * -+ * If WPS is used with an external RADIUS server (which is quite -+ * unlikely configuration), this is used to provide a pointer to WPS -+ * context data. Normally, this can be set to %NULL. -+ */ -+ struct wps_context *wps; -+ -+ /** -+ * ipv6 - Whether to enable IPv6 support in the RADIUS server -+ */ -+ int ipv6; -+ -+ /** -+ * start_time - Timestamp of server start -+ */ -+ struct os_time start_time; -+ -+ /** -+ * counters - Statistics counters for server operations -+ * -+ * These counters are the sum over all clients. -+ */ -+ struct radius_server_counters counters; -+ -+ /** -+ * get_eap_user - Callback for fetching EAP user information -+ * @ctx: Context data from conf_ctx -+ * @identity: User identity -+ * @identity_len: identity buffer length in octets -+ * @phase2: Whether this is for Phase 2 identity -+ * @user: Data structure for filling in the user information -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is used to fetch information from user database. The callback -+ * will fill in information about allowed EAP methods and the user -+ * password. The password field will be an allocated copy of the -+ * password data and RADIUS server will free it after use. -+ */ -+ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, -+ int phase2, struct eap_user *user); -+ -+ /** -+ * eap_req_id_text - Optional data for EAP-Request/Identity -+ * -+ * This can be used to configure an optional, displayable message that -+ * will be sent in EAP-Request/Identity. This string can contain an -+ * ASCII-0 character (nul) to separate network infromation per RFC -+ * 4284. The actual string length is explicit provided in -+ * eap_req_id_text_len since nul character will not be used as a string -+ * terminator. -+ */ -+ char *eap_req_id_text; -+ -+ /** -+ * eap_req_id_text_len - Length of eap_req_id_text buffer in octets -+ */ -+ size_t eap_req_id_text_len; -+ -+ /* -+ * msg_ctx - Context data for wpa_msg() calls -+ */ -+ void *msg_ctx; -+}; -+ -+ -+extern int wpa_debug_level; -+ -+#define RADIUS_DEBUG(args...) \ -+wpa_printf(MSG_DEBUG, "RADIUS SRV: " args) -+#define RADIUS_ERROR(args...) \ -+wpa_printf(MSG_ERROR, "RADIUS SRV: " args) -+#define RADIUS_DUMP(args...) \ -+wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args) -+#define RADIUS_DUMP_ASCII(args...) \ -+wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args) -+ -+ -+static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx); -+static void radius_server_session_remove_timeout(void *eloop_ctx, -+ void *timeout_ctx); -+ -+ -+static struct radius_client * -+radius_server_get_client(struct radius_server_data *data, struct in_addr *addr, -+ int ipv6) -+{ -+ struct radius_client *client = data->clients; -+ -+ while (client) { -+#ifdef CONFIG_IPV6 -+ if (ipv6) { -+ struct in6_addr *addr6; -+ int i; -+ -+ addr6 = (struct in6_addr *) addr; -+ for (i = 0; i < 16; i++) { -+ if ((addr6->s6_addr[i] & -+ client->mask6.s6_addr[i]) != -+ (client->addr6.s6_addr[i] & -+ client->mask6.s6_addr[i])) { -+ i = 17; -+ break; -+ } -+ } -+ if (i == 16) { -+ break; -+ } -+ } -+#endif /* CONFIG_IPV6 */ -+ if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) == -+ (addr->s_addr & client->mask.s_addr)) { -+ break; -+ } -+ -+ client = client->next; -+ } -+ -+ return client; -+} -+ -+ -+static struct radius_session * -+radius_server_get_session(struct radius_client *client, unsigned int sess_id) -+{ -+ struct radius_session *sess = client->sessions; -+ -+ while (sess) { -+ if (sess->sess_id == sess_id) { -+ break; -+ } -+ sess = sess->next; -+ } -+ -+ return sess; -+} -+ -+ -+static void radius_server_session_free(struct radius_server_data *data, -+ struct radius_session *sess) -+{ -+ eloop_cancel_timeout(radius_server_session_timeout, data, sess); -+ eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); -+ eap_server_sm_deinit(sess->eap); -+ radius_msg_free(sess->last_msg); -+ os_free(sess->last_from_addr); -+ radius_msg_free(sess->last_reply); -+ os_free(sess); -+ data->num_sess--; -+} -+ -+ -+static void radius_server_session_remove(struct radius_server_data *data, -+ struct radius_session *sess) -+{ -+ struct radius_client *client = sess->client; -+ struct radius_session *session, *prev; -+ -+ eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); -+ -+ prev = NULL; -+ session = client->sessions; -+ while (session) { -+ if (session == sess) { -+ if (prev == NULL) { -+ client->sessions = sess->next; -+ } else { -+ prev->next = sess->next; -+ } -+ radius_server_session_free(data, sess); -+ break; -+ } -+ prev = session; -+ session = session->next; -+ } -+} -+ -+ -+static void radius_server_session_remove_timeout(void *eloop_ctx, -+ void *timeout_ctx) -+{ -+ struct radius_server_data *data = eloop_ctx; -+ struct radius_session *sess = timeout_ctx; -+ RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id); -+ radius_server_session_remove(data, sess); -+} -+ -+ -+static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct radius_server_data *data = eloop_ctx; -+ struct radius_session *sess = timeout_ctx; -+ -+ RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id); -+ radius_server_session_remove(data, sess); -+} -+ -+ -+static struct radius_session * -+radius_server_new_session(struct radius_server_data *data, -+ struct radius_client *client) -+{ -+ struct radius_session *sess; -+ -+ if (data->num_sess >= RADIUS_MAX_SESSION) { -+ RADIUS_DEBUG("Maximum number of existing session - no room " -+ "for a new session"); -+ return NULL; -+ } -+ -+ sess = os_zalloc(sizeof(*sess)); -+ if (sess == NULL) -+ return NULL; -+ -+ sess->server = data; -+ sess->client = client; -+ sess->sess_id = data->next_sess_id++; -+ sess->next = client->sessions; -+ client->sessions = sess; -+ eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0, -+ radius_server_session_timeout, data, sess); -+ data->num_sess++; -+ return sess; -+} -+ -+ -+static struct radius_session * -+radius_server_get_new_session(struct radius_server_data *data, -+ struct radius_client *client, -+ struct radius_msg *msg) -+{ -+ u8 *user; -+ size_t user_len; -+ int res; -+ struct radius_session *sess; -+ struct eap_config eap_conf; -+ -+ RADIUS_DEBUG("Creating a new session"); -+ -+ user = os_malloc(256); -+ if (user == NULL) { -+ return NULL; -+ } -+ res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256); -+ if (res < 0 || res > 256) { -+ RADIUS_DEBUG("Could not get User-Name"); -+ os_free(user); -+ return NULL; -+ } -+ user_len = res; -+ RADIUS_DUMP_ASCII("User-Name", user, user_len); -+ -+ res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL); -+ os_free(user); -+ -+ if (res == 0) { -+ RADIUS_DEBUG("Matching user entry found"); -+ sess = radius_server_new_session(data, client); -+ if (sess == NULL) { -+ RADIUS_DEBUG("Failed to create a new session"); -+ return NULL; -+ } -+ } else { -+ RADIUS_DEBUG("User-Name not found from user database"); -+ return NULL; -+ } -+ -+ os_memset(&eap_conf, 0, sizeof(eap_conf)); -+ eap_conf.ssl_ctx = data->ssl_ctx; -+ eap_conf.msg_ctx = data->msg_ctx; -+ eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; -+ eap_conf.backend_auth = TRUE; -+ eap_conf.eap_server = 1; -+ eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key; -+ eap_conf.eap_fast_a_id = data->eap_fast_a_id; -+ eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len; -+ eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info; -+ eap_conf.eap_fast_prov = data->eap_fast_prov; -+ eap_conf.pac_key_lifetime = data->pac_key_lifetime; -+ eap_conf.pac_key_refresh_time = data->pac_key_refresh_time; -+ eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind; -+ eap_conf.tnc = data->tnc; -+ eap_conf.wps = data->wps; -+ eap_conf.pwd_group = data->pwd_group; -+ sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb, -+ &eap_conf); -+ if (sess->eap == NULL) { -+ RADIUS_DEBUG("Failed to initialize EAP state machine for the " -+ "new session"); -+ radius_server_session_free(data, sess); -+ return NULL; -+ } -+ sess->eap_if = eap_get_interface(sess->eap); -+ sess->eap_if->eapRestart = TRUE; -+ sess->eap_if->portEnabled = TRUE; -+ -+ RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id); -+ -+ return sess; -+} -+ -+ -+static struct radius_msg * -+radius_server_encapsulate_eap(struct radius_server_data *data, -+ struct radius_client *client, -+ struct radius_session *sess, -+ struct radius_msg *request) -+{ -+ struct radius_msg *msg; -+ int code; -+ unsigned int sess_id; -+ struct radius_hdr *hdr = radius_msg_get_hdr(request); -+ -+ if (sess->eap_if->eapFail) { -+ sess->eap_if->eapFail = FALSE; -+ code = RADIUS_CODE_ACCESS_REJECT; -+ } else if (sess->eap_if->eapSuccess) { -+ sess->eap_if->eapSuccess = FALSE; -+ code = RADIUS_CODE_ACCESS_ACCEPT; -+ } else { -+ sess->eap_if->eapReq = FALSE; -+ code = RADIUS_CODE_ACCESS_CHALLENGE; -+ } -+ -+ msg = radius_msg_new(code, hdr->identifier); -+ if (msg == NULL) { -+ RADIUS_DEBUG("Failed to allocate reply message"); -+ return NULL; -+ } -+ -+ sess_id = htonl(sess->sess_id); -+ if (code == RADIUS_CODE_ACCESS_CHALLENGE && -+ !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, -+ (u8 *) &sess_id, sizeof(sess_id))) { -+ RADIUS_DEBUG("Failed to add State attribute"); -+ } -+ -+ if (sess->eap_if->eapReqData && -+ !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData), -+ wpabuf_len(sess->eap_if->eapReqData))) { -+ RADIUS_DEBUG("Failed to add EAP-Message attribute"); -+ } -+ -+ if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) { -+ int len; -+ if (sess->eap_if->eapKeyDataLen > 64) { -+ len = 32; -+ } else { -+ len = sess->eap_if->eapKeyDataLen / 2; -+ } -+ if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, -+ (u8 *) client->shared_secret, -+ client->shared_secret_len, -+ sess->eap_if->eapKeyData + len, -+ len, sess->eap_if->eapKeyData, -+ len)) { -+ RADIUS_DEBUG("Failed to add MPPE key attributes"); -+ } -+ } -+ -+ if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { -+ RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); -+ radius_msg_free(msg); -+ return NULL; -+ } -+ -+ if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, -+ client->shared_secret_len, -+ hdr->authenticator) < 0) { -+ RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); -+ } -+ -+ return msg; -+} -+ -+ -+static int radius_server_reject(struct radius_server_data *data, -+ struct radius_client *client, -+ struct radius_msg *request, -+ struct sockaddr *from, socklen_t fromlen, -+ const char *from_addr, int from_port) -+{ -+ struct radius_msg *msg; -+ int ret = 0; -+ struct eap_hdr eapfail; -+ struct wpabuf *buf; -+ struct radius_hdr *hdr = radius_msg_get_hdr(request); -+ -+ RADIUS_DEBUG("Reject invalid request from %s:%d", -+ from_addr, from_port); -+ -+ msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier); -+ if (msg == NULL) { -+ return -1; -+ } -+ -+ os_memset(&eapfail, 0, sizeof(eapfail)); -+ eapfail.code = EAP_CODE_FAILURE; -+ eapfail.identifier = 0; -+ eapfail.length = host_to_be16(sizeof(eapfail)); -+ -+ if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) { -+ RADIUS_DEBUG("Failed to add EAP-Message attribute"); -+ } -+ -+ if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { -+ RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); -+ radius_msg_free(msg); -+ return -1; -+ } -+ -+ if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, -+ client->shared_secret_len, -+ hdr->authenticator) < -+ 0) { -+ RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); -+ } -+ -+ if (wpa_debug_level <= MSG_MSGDUMP) { -+ radius_msg_dump(msg); -+ } -+ -+ data->counters.access_rejects++; -+ client->counters.access_rejects++; -+ buf = radius_msg_get_buf(msg); -+ if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, -+ (struct sockaddr *) from, sizeof(*from)) < 0) { -+ perror("sendto[RADIUS SRV]"); -+ ret = -1; -+ } -+ -+ radius_msg_free(msg); -+ -+ return ret; -+} -+ -+ -+static int radius_server_request(struct radius_server_data *data, -+ struct radius_msg *msg, -+ struct sockaddr *from, socklen_t fromlen, -+ struct radius_client *client, -+ const char *from_addr, int from_port, -+ struct radius_session *force_sess) -+{ -+ u8 *eap = NULL; -+ size_t eap_len; -+ int res, state_included = 0; -+ u8 statebuf[4]; -+ unsigned int state; -+ struct radius_session *sess; -+ struct radius_msg *reply; -+ int is_complete = 0; -+ -+ if (force_sess) -+ sess = force_sess; -+ else { -+ res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, -+ sizeof(statebuf)); -+ state_included = res >= 0; -+ if (res == sizeof(statebuf)) { -+ state = WPA_GET_BE32(statebuf); -+ sess = radius_server_get_session(client, state); -+ } else { -+ sess = NULL; -+ } -+ } -+ -+ if (sess) { -+ RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); -+ } else if (state_included) { -+ RADIUS_DEBUG("State attribute included but no session found"); -+ radius_server_reject(data, client, msg, from, fromlen, -+ from_addr, from_port); -+ return -1; -+ } else { -+ sess = radius_server_get_new_session(data, client, msg); -+ if (sess == NULL) { -+ RADIUS_DEBUG("Could not create a new session"); -+ radius_server_reject(data, client, msg, from, fromlen, -+ from_addr, from_port); -+ return -1; -+ } -+ } -+ -+ if (sess->last_from_port == from_port && -+ sess->last_identifier == radius_msg_get_hdr(msg)->identifier && -+ os_memcmp(sess->last_authenticator, -+ radius_msg_get_hdr(msg)->authenticator, 16) == 0) { -+ RADIUS_DEBUG("Duplicate message from %s", from_addr); -+ data->counters.dup_access_requests++; -+ client->counters.dup_access_requests++; -+ -+ if (sess->last_reply) { -+ struct wpabuf *buf; -+ buf = radius_msg_get_buf(sess->last_reply); -+ res = sendto(data->auth_sock, wpabuf_head(buf), -+ wpabuf_len(buf), 0, -+ (struct sockaddr *) from, fromlen); -+ if (res < 0) { -+ perror("sendto[RADIUS SRV]"); -+ } -+ return 0; -+ } -+ -+ RADIUS_DEBUG("No previous reply available for duplicate " -+ "message"); -+ return -1; -+ } -+ -+ eap = radius_msg_get_eap(msg, &eap_len); -+ if (eap == NULL) { -+ RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", -+ from_addr); -+ data->counters.packets_dropped++; -+ client->counters.packets_dropped++; -+ return -1; -+ } -+ -+ RADIUS_DUMP("Received EAP data", eap, eap_len); -+ -+ /* FIX: if Code is Request, Success, or Failure, send Access-Reject; -+ * RFC3579 Sect. 2.6.2. -+ * Include EAP-Response/Nak with no preferred method if -+ * code == request. -+ * If code is not 1-4, discard the packet silently. -+ * Or is this already done by the EAP state machine? */ -+ -+ wpabuf_free(sess->eap_if->eapRespData); -+ sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len); -+ if (sess->eap_if->eapRespData == NULL) -+ os_free(eap); -+ eap = NULL; -+ sess->eap_if->eapResp = TRUE; -+ eap_server_sm_step(sess->eap); -+ -+ if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess || -+ sess->eap_if->eapFail) && sess->eap_if->eapReqData) { -+ RADIUS_DUMP("EAP data from the state machine", -+ wpabuf_head(sess->eap_if->eapReqData), -+ wpabuf_len(sess->eap_if->eapReqData)); -+ } else if (sess->eap_if->eapFail) { -+ RADIUS_DEBUG("No EAP data from the state machine, but eapFail " -+ "set"); -+ } else if (eap_sm_method_pending(sess->eap)) { -+ radius_msg_free(sess->last_msg); -+ sess->last_msg = msg; -+ sess->last_from_port = from_port; -+ os_free(sess->last_from_addr); -+ sess->last_from_addr = os_strdup(from_addr); -+ sess->last_fromlen = fromlen; -+ os_memcpy(&sess->last_from, from, fromlen); -+ return -2; -+ } else { -+ RADIUS_DEBUG("No EAP data from the state machine - ignore this" -+ " Access-Request silently (assuming it was a " -+ "duplicate)"); -+ data->counters.packets_dropped++; -+ client->counters.packets_dropped++; -+ return -1; -+ } -+ -+ if (sess->eap_if->eapSuccess || sess->eap_if->eapFail) -+ is_complete = 1; -+ -+ reply = radius_server_encapsulate_eap(data, client, sess, msg); -+ -+ if (reply) { -+ struct wpabuf *buf; -+ struct radius_hdr *hdr; -+ -+ RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); -+ if (wpa_debug_level <= MSG_MSGDUMP) { -+ radius_msg_dump(reply); -+ } -+ -+ switch (radius_msg_get_hdr(reply)->code) { -+ case RADIUS_CODE_ACCESS_ACCEPT: -+ data->counters.access_accepts++; -+ client->counters.access_accepts++; -+ break; -+ case RADIUS_CODE_ACCESS_REJECT: -+ data->counters.access_rejects++; -+ client->counters.access_rejects++; -+ break; -+ case RADIUS_CODE_ACCESS_CHALLENGE: -+ data->counters.access_challenges++; -+ client->counters.access_challenges++; -+ break; -+ } -+ buf = radius_msg_get_buf(reply); -+ res = sendto(data->auth_sock, wpabuf_head(buf), -+ wpabuf_len(buf), 0, -+ (struct sockaddr *) from, fromlen); -+ if (res < 0) { -+ perror("sendto[RADIUS SRV]"); -+ } -+ radius_msg_free(sess->last_reply); -+ sess->last_reply = reply; -+ sess->last_from_port = from_port; -+ hdr = radius_msg_get_hdr(msg); -+ sess->last_identifier = hdr->identifier; -+ os_memcpy(sess->last_authenticator, hdr->authenticator, 16); -+ } else { -+ data->counters.packets_dropped++; -+ client->counters.packets_dropped++; -+ } -+ -+ if (is_complete) { -+ RADIUS_DEBUG("Removing completed session 0x%x after timeout", -+ sess->sess_id); -+ eloop_cancel_timeout(radius_server_session_remove_timeout, -+ data, sess); -+ eloop_register_timeout(10, 0, -+ radius_server_session_remove_timeout, -+ data, sess); -+ } -+ -+ return 0; -+} -+ -+ -+static void radius_server_receive_auth(int sock, void *eloop_ctx, -+ void *sock_ctx) -+{ -+ struct radius_server_data *data = eloop_ctx; -+ u8 *buf = NULL; -+ union { -+ struct sockaddr_storage ss; -+ struct sockaddr_in sin; -+#ifdef CONFIG_IPV6 -+ struct sockaddr_in6 sin6; -+#endif /* CONFIG_IPV6 */ -+ } from; -+ socklen_t fromlen; -+ int len; -+ struct radius_client *client = NULL; -+ struct radius_msg *msg = NULL; -+ char abuf[50]; -+ int from_port = 0; -+ -+ buf = os_malloc(RADIUS_MAX_MSG_LEN); -+ if (buf == NULL) { -+ goto fail; -+ } -+ -+ fromlen = sizeof(from); -+ len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, -+ (struct sockaddr *) &from.ss, &fromlen); -+ if (len < 0) { -+ perror("recvfrom[radius_server]"); -+ goto fail; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (data->ipv6) { -+ if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, -+ sizeof(abuf)) == NULL) -+ abuf[0] = '\0'; -+ from_port = ntohs(from.sin6.sin6_port); -+ RADIUS_DEBUG("Received %d bytes from %s:%d", -+ len, abuf, from_port); -+ -+ client = radius_server_get_client(data, -+ (struct in_addr *) -+ &from.sin6.sin6_addr, 1); -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ if (!data->ipv6) { -+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); -+ from_port = ntohs(from.sin.sin_port); -+ RADIUS_DEBUG("Received %d bytes from %s:%d", -+ len, abuf, from_port); -+ -+ client = radius_server_get_client(data, &from.sin.sin_addr, 0); -+ } -+ -+ RADIUS_DUMP("Received data", buf, len); -+ -+ if (client == NULL) { -+ RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); -+ data->counters.invalid_requests++; -+ goto fail; -+ } -+ -+ msg = radius_msg_parse(buf, len); -+ if (msg == NULL) { -+ RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); -+ data->counters.malformed_access_requests++; -+ client->counters.malformed_access_requests++; -+ goto fail; -+ } -+ -+ os_free(buf); -+ buf = NULL; -+ -+ if (wpa_debug_level <= MSG_MSGDUMP) { -+ radius_msg_dump(msg); -+ } -+ -+ if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) { -+ RADIUS_DEBUG("Unexpected RADIUS code %d", -+ radius_msg_get_hdr(msg)->code); -+ data->counters.unknown_types++; -+ client->counters.unknown_types++; -+ goto fail; -+ } -+ -+ data->counters.access_requests++; -+ client->counters.access_requests++; -+ -+ if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, -+ client->shared_secret_len, NULL)) { -+ RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf); -+ data->counters.bad_authenticators++; -+ client->counters.bad_authenticators++; -+ goto fail; -+ } -+ -+ if (radius_server_request(data, msg, (struct sockaddr *) &from, -+ fromlen, client, abuf, from_port, NULL) == -+ -2) -+ return; /* msg was stored with the session */ -+ -+fail: -+ radius_msg_free(msg); -+ os_free(buf); -+} -+ -+ -+static int radius_server_disable_pmtu_discovery(int s) -+{ -+ int r = -1; -+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) -+ /* Turn off Path MTU discovery on IPv4/UDP sockets. */ -+ int action = IP_PMTUDISC_DONT; -+ r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, -+ sizeof(action)); -+ if (r == -1) -+ wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " -+ "%s", strerror(errno)); -+#endif -+ return r; -+} -+ -+ -+static int radius_server_open_socket(int port) -+{ -+ int s; -+ struct sockaddr_in addr; -+ -+ s = socket(PF_INET, SOCK_DGRAM, 0); -+ if (s < 0) { -+ perror("socket"); -+ return -1; -+ } -+ -+ radius_server_disable_pmtu_discovery(s); -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sin_family = AF_INET; -+ addr.sin_port = htons(port); -+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind"); -+ close(s); -+ return -1; -+ } -+ -+ return s; -+} -+ -+ -+#ifdef CONFIG_IPV6 -+static int radius_server_open_socket6(int port) -+{ -+ int s; -+ struct sockaddr_in6 addr; -+ -+ s = socket(PF_INET6, SOCK_DGRAM, 0); -+ if (s < 0) { -+ perror("socket[IPv6]"); -+ return -1; -+ } -+ -+ os_memset(&addr, 0, sizeof(addr)); -+ addr.sin6_family = AF_INET6; -+ os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); -+ addr.sin6_port = htons(port); -+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { -+ perror("bind"); -+ close(s); -+ return -1; -+ } -+ -+ return s; -+} -+#endif /* CONFIG_IPV6 */ -+ -+ -+static void radius_server_free_sessions(struct radius_server_data *data, -+ struct radius_session *sessions) -+{ -+ struct radius_session *session, *prev; -+ -+ session = sessions; -+ while (session) { -+ prev = session; -+ session = session->next; -+ radius_server_session_free(data, prev); -+ } -+} -+ -+ -+static void radius_server_free_clients(struct radius_server_data *data, -+ struct radius_client *clients) -+{ -+ struct radius_client *client, *prev; -+ -+ client = clients; -+ while (client) { -+ prev = client; -+ client = client->next; -+ -+ radius_server_free_sessions(data, prev->sessions); -+ os_free(prev->shared_secret); -+ os_free(prev); -+ } -+} -+ -+ -+static struct radius_client * -+radius_server_read_clients(const char *client_file, int ipv6) -+{ -+ FILE *f; -+ const int buf_size = 1024; -+ char *buf, *pos; -+ struct radius_client *clients, *tail, *entry; -+ int line = 0, mask, failed = 0, i; -+ struct in_addr addr; -+#ifdef CONFIG_IPV6 -+ struct in6_addr addr6; -+#endif /* CONFIG_IPV6 */ -+ unsigned int val; -+ -+ f = fopen(client_file, "r"); -+ if (f == NULL) { -+ RADIUS_ERROR("Could not open client file '%s'", client_file); -+ return NULL; -+ } -+ -+ buf = os_malloc(buf_size); -+ if (buf == NULL) { -+ fclose(f); -+ return NULL; -+ } -+ -+ clients = tail = NULL; -+ while (fgets(buf, buf_size, f)) { -+ /* Configuration file format: -+ * 192.168.1.0/24 secret -+ * 192.168.1.2 secret -+ * fe80::211:22ff:fe33:4455/64 secretipv6 -+ */ -+ line++; -+ buf[buf_size - 1] = '\0'; -+ pos = buf; -+ while (*pos != '\0' && *pos != '\n') -+ pos++; -+ if (*pos == '\n') -+ *pos = '\0'; -+ if (*buf == '\0' || *buf == '#') -+ continue; -+ -+ pos = buf; -+ while ((*pos >= '0' && *pos <= '9') || *pos == '.' || -+ (*pos >= 'a' && *pos <= 'f') || *pos == ':' || -+ (*pos >= 'A' && *pos <= 'F')) { -+ pos++; -+ } -+ -+ if (*pos == '\0') { -+ failed = 1; -+ break; -+ } -+ -+ if (*pos == '/') { -+ char *end; -+ *pos++ = '\0'; -+ mask = strtol(pos, &end, 10); -+ if ((pos == end) || -+ (mask < 0 || mask > (ipv6 ? 128 : 32))) { -+ failed = 1; -+ break; -+ } -+ pos = end; -+ } else { -+ mask = ipv6 ? 128 : 32; -+ *pos++ = '\0'; -+ } -+ -+ if (!ipv6 && inet_aton(buf, &addr) == 0) { -+ failed = 1; -+ break; -+ } -+#ifdef CONFIG_IPV6 -+ if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) { -+ if (inet_pton(AF_INET, buf, &addr) <= 0) { -+ failed = 1; -+ break; -+ } -+ /* Convert IPv4 address to IPv6 */ -+ if (mask <= 32) -+ mask += (128 - 32); -+ os_memset(addr6.s6_addr, 0, 10); -+ addr6.s6_addr[10] = 0xff; -+ addr6.s6_addr[11] = 0xff; -+ os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, -+ 4); -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ while (*pos == ' ' || *pos == '\t') { -+ pos++; -+ } -+ -+ if (*pos == '\0') { -+ failed = 1; -+ break; -+ } -+ -+ entry = os_zalloc(sizeof(*entry)); -+ if (entry == NULL) { -+ failed = 1; -+ break; -+ } -+ entry->shared_secret = os_strdup(pos); -+ if (entry->shared_secret == NULL) { -+ failed = 1; -+ os_free(entry); -+ break; -+ } -+ entry->shared_secret_len = os_strlen(entry->shared_secret); -+ entry->addr.s_addr = addr.s_addr; -+ if (!ipv6) { -+ val = 0; -+ for (i = 0; i < mask; i++) -+ val |= 1 << (31 - i); -+ entry->mask.s_addr = htonl(val); -+ } -+#ifdef CONFIG_IPV6 -+ if (ipv6) { -+ int offset = mask / 8; -+ -+ os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16); -+ os_memset(entry->mask6.s6_addr, 0xff, offset); -+ val = 0; -+ for (i = 0; i < (mask % 8); i++) -+ val |= 1 << (7 - i); -+ if (offset < 16) -+ entry->mask6.s6_addr[offset] = val; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ if (tail == NULL) { -+ clients = tail = entry; -+ } else { -+ tail->next = entry; -+ tail = entry; -+ } -+ } -+ -+ if (failed) { -+ RADIUS_ERROR("Invalid line %d in '%s'", line, client_file); -+ radius_server_free_clients(NULL, clients); -+ clients = NULL; -+ } -+ -+ os_free(buf); -+ fclose(f); -+ -+ return clients; -+} -+ -+ -+/** -+ * radius_server_init - Initialize RADIUS server -+ * @conf: Configuration for the RADIUS server -+ * Returns: Pointer to private RADIUS server context or %NULL on failure -+ * -+ * This initializes a RADIUS server instance and returns a context pointer that -+ * will be used in other calls to the RADIUS server module. The server can be -+ * deinitialize by calling radius_server_deinit(). -+ */ -+struct radius_server_data * -+radius_server_init(struct radius_server_conf *conf) -+{ -+ struct radius_server_data *data; -+ -+#ifndef CONFIG_IPV6 -+ if (conf->ipv6) { -+ fprintf(stderr, "RADIUS server compiled without IPv6 " -+ "support.\n"); -+ return NULL; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ data = os_zalloc(sizeof(*data)); -+ if (data == NULL) -+ return NULL; -+ -+ os_get_time(&data->start_time); -+ data->conf_ctx = conf->conf_ctx; -+ data->eap_sim_db_priv = conf->eap_sim_db_priv; -+ data->ssl_ctx = conf->ssl_ctx; -+ data->msg_ctx = conf->msg_ctx; -+ data->ipv6 = conf->ipv6; -+ if (conf->pac_opaque_encr_key) { -+ data->pac_opaque_encr_key = os_malloc(16); -+ os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key, -+ 16); -+ } -+ if (conf->eap_fast_a_id) { -+ data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); -+ if (data->eap_fast_a_id) { -+ os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id, -+ conf->eap_fast_a_id_len); -+ data->eap_fast_a_id_len = conf->eap_fast_a_id_len; -+ } -+ } -+ if (conf->eap_fast_a_id_info) -+ data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); -+ data->eap_fast_prov = conf->eap_fast_prov; -+ data->pac_key_lifetime = conf->pac_key_lifetime; -+ data->pac_key_refresh_time = conf->pac_key_refresh_time; -+ data->get_eap_user = conf->get_eap_user; -+ data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; -+ data->tnc = conf->tnc; -+ data->wps = conf->wps; -+ data->pwd_group = conf->pwd_group; -+ if (conf->eap_req_id_text) { -+ data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len); -+ if (data->eap_req_id_text) { -+ os_memcpy(data->eap_req_id_text, conf->eap_req_id_text, -+ conf->eap_req_id_text_len); -+ data->eap_req_id_text_len = conf->eap_req_id_text_len; -+ } -+ } -+ -+ data->clients = radius_server_read_clients(conf->client_file, -+ conf->ipv6); -+ if (data->clients == NULL) { -+ printf("No RADIUS clients configured.\n"); -+ radius_server_deinit(data); -+ return NULL; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (conf->ipv6) -+ data->auth_sock = radius_server_open_socket6(conf->auth_port); -+ else -+#endif /* CONFIG_IPV6 */ -+ data->auth_sock = radius_server_open_socket(conf->auth_port); -+ if (data->auth_sock < 0) { -+ printf("Failed to open UDP socket for RADIUS authentication " -+ "server\n"); -+ radius_server_deinit(data); -+ return NULL; -+ } -+ if (eloop_register_read_sock(data->auth_sock, -+ radius_server_receive_auth, -+ data, NULL)) { -+ radius_server_deinit(data); -+ return NULL; -+ } -+ -+ return data; -+} -+ -+ -+/** -+ * radius_server_deinit - Deinitialize RADIUS server -+ * @data: RADIUS server context from radius_server_init() -+ */ -+void radius_server_deinit(struct radius_server_data *data) -+{ -+ if (data == NULL) -+ return; -+ -+ if (data->auth_sock >= 0) { -+ eloop_unregister_read_sock(data->auth_sock); -+ close(data->auth_sock); -+ } -+ -+ radius_server_free_clients(data, data->clients); -+ -+ os_free(data->pac_opaque_encr_key); -+ os_free(data->eap_fast_a_id); -+ os_free(data->eap_fast_a_id_info); -+ os_free(data->eap_req_id_text); -+ os_free(data); -+} -+ -+ -+/** -+ * radius_server_get_mib - Get RADIUS server MIB information -+ * @data: RADIUS server context from radius_server_init() -+ * @buf: Buffer for returning the MIB data in text format -+ * @buflen: buf length in octets -+ * Returns: Number of octets written into buf -+ */ -+int radius_server_get_mib(struct radius_server_data *data, char *buf, -+ size_t buflen) -+{ -+ int ret, uptime; -+ unsigned int idx; -+ char *end, *pos; -+ struct os_time now; -+ struct radius_client *cli; -+ -+ /* RFC 2619 - RADIUS Authentication Server MIB */ -+ -+ if (data == NULL || buflen == 0) -+ return 0; -+ -+ pos = buf; -+ end = buf + buflen; -+ -+ os_get_time(&now); -+ uptime = (now.sec - data->start_time.sec) * 100 + -+ ((now.usec - data->start_time.usec) / 10000) % 100; -+ ret = os_snprintf(pos, end - pos, -+ "RADIUS-AUTH-SERVER-MIB\n" -+ "radiusAuthServIdent=hostapd\n" -+ "radiusAuthServUpTime=%d\n" -+ "radiusAuthServResetTime=0\n" -+ "radiusAuthServConfigReset=4\n", -+ uptime); -+ if (ret < 0 || ret >= end - pos) { -+ *pos = '\0'; -+ return pos - buf; -+ } -+ pos += ret; -+ -+ ret = os_snprintf(pos, end - pos, -+ "radiusAuthServTotalAccessRequests=%u\n" -+ "radiusAuthServTotalInvalidRequests=%u\n" -+ "radiusAuthServTotalDupAccessRequests=%u\n" -+ "radiusAuthServTotalAccessAccepts=%u\n" -+ "radiusAuthServTotalAccessRejects=%u\n" -+ "radiusAuthServTotalAccessChallenges=%u\n" -+ "radiusAuthServTotalMalformedAccessRequests=%u\n" -+ "radiusAuthServTotalBadAuthenticators=%u\n" -+ "radiusAuthServTotalPacketsDropped=%u\n" -+ "radiusAuthServTotalUnknownTypes=%u\n", -+ data->counters.access_requests, -+ data->counters.invalid_requests, -+ data->counters.dup_access_requests, -+ data->counters.access_accepts, -+ data->counters.access_rejects, -+ data->counters.access_challenges, -+ data->counters.malformed_access_requests, -+ data->counters.bad_authenticators, -+ data->counters.packets_dropped, -+ data->counters.unknown_types); -+ if (ret < 0 || ret >= end - pos) { -+ *pos = '\0'; -+ return pos - buf; -+ } -+ pos += ret; -+ -+ for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) { -+ char abuf[50], mbuf[50]; -+#ifdef CONFIG_IPV6 -+ if (data->ipv6) { -+ if (inet_ntop(AF_INET6, &cli->addr6, abuf, -+ sizeof(abuf)) == NULL) -+ abuf[0] = '\0'; -+ if (inet_ntop(AF_INET6, &cli->mask6, abuf, -+ sizeof(mbuf)) == NULL) -+ mbuf[0] = '\0'; -+ } -+#endif /* CONFIG_IPV6 */ -+ if (!data->ipv6) { -+ os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf)); -+ os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf)); -+ } -+ -+ ret = os_snprintf(pos, end - pos, -+ "radiusAuthClientIndex=%u\n" -+ "radiusAuthClientAddress=%s/%s\n" -+ "radiusAuthServAccessRequests=%u\n" -+ "radiusAuthServDupAccessRequests=%u\n" -+ "radiusAuthServAccessAccepts=%u\n" -+ "radiusAuthServAccessRejects=%u\n" -+ "radiusAuthServAccessChallenges=%u\n" -+ "radiusAuthServMalformedAccessRequests=%u\n" -+ "radiusAuthServBadAuthenticators=%u\n" -+ "radiusAuthServPacketsDropped=%u\n" -+ "radiusAuthServUnknownTypes=%u\n", -+ idx, -+ abuf, mbuf, -+ cli->counters.access_requests, -+ cli->counters.dup_access_requests, -+ cli->counters.access_accepts, -+ cli->counters.access_rejects, -+ cli->counters.access_challenges, -+ cli->counters.malformed_access_requests, -+ cli->counters.bad_authenticators, -+ cli->counters.packets_dropped, -+ cli->counters.unknown_types); -+ if (ret < 0 || ret >= end - pos) { -+ *pos = '\0'; -+ return pos - buf; -+ } -+ pos += ret; -+ } -+ -+ return pos - buf; -+} -+ -+ -+static int radius_server_get_eap_user(void *ctx, const u8 *identity, -+ size_t identity_len, int phase2, -+ struct eap_user *user) -+{ -+ struct radius_session *sess = ctx; -+ struct radius_server_data *data = sess->server; -+ -+ return data->get_eap_user(data->conf_ctx, identity, identity_len, -+ phase2, user); -+} -+ -+ -+static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len) -+{ -+ struct radius_session *sess = ctx; -+ struct radius_server_data *data = sess->server; -+ *len = data->eap_req_id_text_len; -+ return data->eap_req_id_text; -+} -+ -+ -+static struct eapol_callbacks radius_server_eapol_cb = -+{ -+ .get_eap_user = radius_server_get_eap_user, -+ .get_eap_req_id_text = radius_server_get_eap_req_id_text, -+}; -+ -+ -+/** -+ * radius_server_eap_pending_cb - Pending EAP data notification -+ * @data: RADIUS server context from radius_server_init() -+ * @ctx: Pending EAP context pointer -+ * -+ * This function is used to notify EAP server module that a pending operation -+ * has been completed and processing of the EAP session can proceed. -+ */ -+void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) -+{ -+ struct radius_client *cli; -+ struct radius_session *s, *sess = NULL; -+ struct radius_msg *msg; -+ -+ if (data == NULL) -+ return; -+ -+ for (cli = data->clients; cli; cli = cli->next) { -+ for (s = cli->sessions; s; s = s->next) { -+ if (s->eap == ctx && s->last_msg) { -+ sess = s; -+ break; -+ } -+ if (sess) -+ break; -+ } -+ if (sess) -+ break; -+ } -+ -+ if (sess == NULL) { -+ RADIUS_DEBUG("No session matched callback ctx"); -+ return; -+ } -+ -+ msg = sess->last_msg; -+ sess->last_msg = NULL; -+ eap_sm_pending_cb(sess->eap); -+ if (radius_server_request(data, msg, -+ (struct sockaddr *) &sess->last_from, -+ sess->last_fromlen, cli, -+ sess->last_from_addr, -+ sess->last_from_port, sess) == -2) -+ return; /* msg was stored with the session */ -+ -+ radius_msg_free(msg); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.h -new file mode 100644 -index 0000000000000..126e31446af8e ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/radius/radius_server.h -@@ -0,0 +1,217 @@ -+/* -+ * RADIUS authentication server -+ * Copyright (c) 2005-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef RADIUS_SERVER_H -+#define RADIUS_SERVER_H -+ -+struct radius_server_data; -+struct eap_user; -+ -+/** -+ * struct radius_server_conf - RADIUS server configuration -+ */ -+struct radius_server_conf { -+ /** -+ * auth_port - UDP port to listen to as an authentication server -+ */ -+ int auth_port; -+ -+ /** -+ * client_file - RADIUS client configuration file -+ * -+ * This file contains the RADIUS clients and the shared secret to be -+ * used with them in a format where each client is on its own line. The -+ * first item on the line is the IPv4 or IPv6 address of the client -+ * with an optional address mask to allow full network to be specified -+ * (e.g., 192.168.1.2 or 192.168.1.0/24). This is followed by white -+ * space (space or tabulator) and the shared secret. Lines starting -+ * with '#' are skipped and can be used as comments. -+ */ -+ char *client_file; -+ -+ /** -+ * conf_ctx - Context pointer for callbacks -+ * -+ * This is used as the ctx argument in get_eap_user() calls. -+ */ -+ void *conf_ctx; -+ -+ /** -+ * eap_sim_db_priv - EAP-SIM/AKA database context -+ * -+ * This is passed to the EAP-SIM/AKA server implementation as a -+ * callback context. -+ */ -+ void *eap_sim_db_priv; -+ -+ /** -+ * ssl_ctx - TLS context -+ * -+ * This is passed to the EAP server implementation as a callback -+ * context for TLS operations. -+ */ -+ void *ssl_ctx; -+ -+ /** -+ * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST -+ * -+ * This parameter is used to set a key for EAP-FAST to encrypt the -+ * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If -+ * set, must point to a 16-octet key. -+ */ -+ u8 *pac_opaque_encr_key; -+ -+ /** -+ * eap_fast_a_id - EAP-FAST authority identity (A-ID) -+ * -+ * If EAP-FAST is not used, this can be set to %NULL. In theory, this -+ * is a variable length field, but due to some existing implementations -+ * requiring A-ID to be 16 octets in length, it is recommended to use -+ * that length for the field to provide interoperability with deployed -+ * peer implementations. -+ */ -+ u8 *eap_fast_a_id; -+ -+ /** -+ * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets -+ */ -+ size_t eap_fast_a_id_len; -+ -+ /** -+ * eap_fast_a_id_info - EAP-FAST authority identifier information -+ * -+ * This A-ID-Info contains a user-friendly name for the A-ID. For -+ * example, this could be the enterprise and server names in -+ * human-readable format. This field is encoded as UTF-8. If EAP-FAST -+ * is not used, this can be set to %NULL. -+ */ -+ char *eap_fast_a_id_info; -+ -+ /** -+ * eap_fast_prov - EAP-FAST provisioning modes -+ * -+ * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, -+ * 2 = only authenticated provisioning allowed, 3 = both provisioning -+ * modes allowed. -+ */ -+ int eap_fast_prov; -+ -+ /** -+ * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds -+ * -+ * This is the hard limit on how long a provisioned PAC-Key can be -+ * used. -+ */ -+ int pac_key_lifetime; -+ -+ /** -+ * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds -+ * -+ * This is a soft limit on the PAC-Key. The server will automatically -+ * generate a new PAC-Key when this number of seconds (or fewer) of the -+ * lifetime remains. -+ */ -+ int pac_key_refresh_time; -+ -+ /** -+ * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication -+ * -+ * This controls whether the protected success/failure indication -+ * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. -+ */ -+ int eap_sim_aka_result_ind; -+ -+ /** -+ * tnc - Trusted Network Connect (TNC) -+ * -+ * This controls whether TNC is enabled and will be required before the -+ * peer is allowed to connect. Note: This is only used with EAP-TTLS -+ * and EAP-FAST. If any other EAP method is enabled, the peer will be -+ * allowed to connect without TNC. -+ */ -+ int tnc; -+ -+ /** -+ * pwd_group - EAP-pwd D-H group -+ * -+ * This is used to select which D-H group to use with EAP-pwd. -+ */ -+ u16 pwd_group; -+ -+ /** -+ * wps - Wi-Fi Protected Setup context -+ * -+ * If WPS is used with an external RADIUS server (which is quite -+ * unlikely configuration), this is used to provide a pointer to WPS -+ * context data. Normally, this can be set to %NULL. -+ */ -+ struct wps_context *wps; -+ -+ /** -+ * ipv6 - Whether to enable IPv6 support in the RADIUS server -+ */ -+ int ipv6; -+ -+ /** -+ * get_eap_user - Callback for fetching EAP user information -+ * @ctx: Context data from conf_ctx -+ * @identity: User identity -+ * @identity_len: identity buffer length in octets -+ * @phase2: Whether this is for Phase 2 identity -+ * @user: Data structure for filling in the user information -+ * Returns: 0 on success, -1 on failure -+ * -+ * This is used to fetch information from user database. The callback -+ * will fill in information about allowed EAP methods and the user -+ * password. The password field will be an allocated copy of the -+ * password data and RADIUS server will free it after use. -+ */ -+ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, -+ int phase2, struct eap_user *user); -+ -+ /** -+ * eap_req_id_text - Optional data for EAP-Request/Identity -+ * -+ * This can be used to configure an optional, displayable message that -+ * will be sent in EAP-Request/Identity. This string can contain an -+ * ASCII-0 character (nul) to separate network infromation per RFC -+ * 4284. The actual string length is explicit provided in -+ * eap_req_id_text_len since nul character will not be used as a string -+ * terminator. -+ */ -+ const char *eap_req_id_text; -+ -+ /** -+ * eap_req_id_text_len - Length of eap_req_id_text buffer in octets -+ */ -+ size_t eap_req_id_text_len; -+ -+ /* -+ * msg_ctx - Context data for wpa_msg() calls -+ */ -+ void *msg_ctx; -+}; -+ -+ -+struct radius_server_data * -+radius_server_init(struct radius_server_conf *conf); -+ -+void radius_server_deinit(struct radius_server_data *data); -+ -+int radius_server_get_mib(struct radius_server_data *data, char *buf, -+ size_t buflen); -+ -+void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx); -+ -+#endif /* RADIUS_SERVER_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.c -new file mode 100644 -index 0000000000000..2b3332ea36bff ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.c -@@ -0,0 +1,1186 @@ -+/* -+ * WPA Supplicant - PeerKey for Direct Link Setup (DLS) -+ * Copyright (c) 2006-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#ifdef CONFIG_PEERKEY -+ -+#include "common.h" -+#include "eloop.h" -+#include "crypto/sha1.h" -+#include "crypto/sha256.h" -+#include "crypto/random.h" -+#include "common/ieee802_11_defs.h" -+#include "wpa.h" -+#include "wpa_i.h" -+#include "wpa_ie.h" -+#include "peerkey.h" -+ -+ -+static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) -+{ -+ os_memcpy(pos, ie, ie_len); -+ return pos + ie_len; -+} -+ -+ -+static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len) -+{ -+ *pos++ = WLAN_EID_VENDOR_SPECIFIC; -+ *pos++ = RSN_SELECTOR_LEN + data_len; -+ RSN_SELECTOR_PUT(pos, kde); -+ pos += RSN_SELECTOR_LEN; -+ os_memcpy(pos, data, data_len); -+ pos += data_len; -+ return pos; -+} -+ -+ -+static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+#if 0 -+ struct wpa_sm *sm = eloop_ctx; -+ struct wpa_peerkey *peerkey = timeout_ctx; -+#endif -+ /* TODO: time out SMK and any STK that was generated using this SMK */ -+} -+ -+ -+static void wpa_supplicant_peerkey_free(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey) -+{ -+ eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); -+ os_free(peerkey); -+} -+ -+ -+static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, -+ const u8 *peer, -+ u16 mui, u16 error_type, int ver) -+{ -+ size_t rlen; -+ struct wpa_eapol_key *err; -+ struct rsn_error_kde error; -+ u8 *rbuf, *pos; -+ size_t kde_len; -+ u16 key_info; -+ -+ kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error); -+ if (peer) -+ kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN; -+ -+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, -+ NULL, sizeof(*err) + kde_len, &rlen, -+ (void *) &err); -+ if (rbuf == NULL) -+ return -1; -+ -+ err->type = EAPOL_KEY_TYPE_RSN; -+ key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR | -+ WPA_KEY_INFO_REQUEST; -+ WPA_PUT_BE16(err->key_info, key_info); -+ WPA_PUT_BE16(err->key_length, 0); -+ os_memcpy(err->replay_counter, sm->request_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); -+ -+ WPA_PUT_BE16(err->key_data_length, (u16) kde_len); -+ pos = (u8 *) (err + 1); -+ -+ if (peer) { -+ /* Peer MAC Address KDE */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); -+ } -+ -+ /* Error KDE */ -+ error.mui = host_to_be16(mui); -+ error.error_type = host_to_be16(error_type); -+ wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error)); -+ -+ if (peer) { -+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer " -+ MACSTR " mui %d error_type %d)", -+ MAC2STR(peer), mui, error_type); -+ } else { -+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error " -+ "(mui %d error_type %d)", mui, error_type); -+ } -+ -+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL, -+ rbuf, rlen, err->key_mic); -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, -+ int ver, struct wpa_peerkey *peerkey) -+{ -+ size_t rlen; -+ struct wpa_eapol_key *reply; -+ u8 *rbuf, *pos; -+ size_t kde_len; -+ u16 key_info; -+ -+ /* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */ -+ kde_len = peerkey->rsnie_p_len + -+ 2 + RSN_SELECTOR_LEN + ETH_ALEN + -+ 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN; -+ -+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, -+ NULL, sizeof(*reply) + kde_len, &rlen, -+ (void *) &reply); -+ if (rbuf == NULL) -+ return -1; -+ -+ reply->type = EAPOL_KEY_TYPE_RSN; -+ key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_SECURE; -+ WPA_PUT_BE16(reply->key_info, key_info); -+ WPA_PUT_BE16(reply->key_length, 0); -+ os_memcpy(reply->replay_counter, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ -+ os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN); -+ -+ WPA_PUT_BE16(reply->key_data_length, (u16) kde_len); -+ pos = (u8 *) (reply + 1); -+ -+ /* Peer RSN IE */ -+ pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len); -+ -+ /* Initiator MAC Address KDE */ -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN); -+ -+ /* Initiator Nonce */ -+ wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN); -+ -+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3"); -+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL, -+ rbuf, rlen, reply->key_mic); -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_process_smk_m2( -+ struct wpa_sm *sm, const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, size_t extra_len, int ver) -+{ -+ struct wpa_peerkey *peerkey; -+ struct wpa_eapol_ie_parse kde; -+ struct wpa_ie_data ie; -+ int cipher; -+ struct rsn_ie_hdr *hdr; -+ u8 *pos; -+ -+ wpa_printf(MSG_DEBUG, "RSN: Received SMK M2"); -+ -+ if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { -+ wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for " -+ "the current network"); -+ return -1; -+ } -+ -+ if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < -+ 0) { -+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2"); -+ return -1; -+ } -+ -+ if (kde.rsn_ie == NULL || kde.mac_addr == NULL || -+ kde.mac_addr_len < ETH_ALEN) { -+ wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " -+ "SMK M2"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR, -+ MAC2STR(kde.mac_addr)); -+ -+ if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) { -+ wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK " -+ "M2"); -+ return -1; -+ } -+ -+ if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { -+ wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2"); -+ return -1; -+ } -+ -+ cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; -+ if (cipher & WPA_CIPHER_CCMP) { -+ wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); -+ cipher = WPA_CIPHER_CCMP; -+ } else if (cipher & WPA_CIPHER_TKIP) { -+ wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); -+ cipher = WPA_CIPHER_TKIP; -+ } else { -+ wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2"); -+ wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr, -+ STK_MUI_SMK, STK_ERR_CPHR_NS, -+ ver); -+ return -1; -+ } -+ -+ /* TODO: find existing entry and if found, use that instead of adding -+ * a new one; how to handle the case where both ends initiate at the -+ * same time? */ -+ peerkey = os_zalloc(sizeof(*peerkey)); -+ if (peerkey == NULL) -+ return -1; -+ os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN); -+ os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); -+ os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); -+ peerkey->rsnie_i_len = kde.rsn_ie_len; -+ peerkey->cipher = cipher; -+#ifdef CONFIG_IEEE80211W -+ if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 | -+ WPA_KEY_MGMT_PSK_SHA256)) -+ peerkey->use_sha256 = 1; -+#endif /* CONFIG_IEEE80211W */ -+ -+ if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to get random data for PNonce"); -+ wpa_supplicant_peerkey_free(sm, peerkey); -+ return -1; -+ } -+ -+ hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p; -+ hdr->elem_id = WLAN_EID_RSN; -+ WPA_PUT_LE16(hdr->version, RSN_VERSION); -+ pos = (u8 *) (hdr + 1); -+ /* Group Suite can be anything for SMK RSN IE; receiver will just -+ * ignore it. */ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ pos += RSN_SELECTOR_LEN; -+ /* Include only the selected cipher in pairwise cipher suite */ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ if (cipher == WPA_CIPHER_CCMP) -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ else if (cipher == WPA_CIPHER_TKIP) -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ pos += RSN_SELECTOR_LEN; -+ -+ hdr->len = (pos - peerkey->rsnie_p) - 2; -+ peerkey->rsnie_p_len = pos - peerkey->rsnie_p; -+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", -+ peerkey->rsnie_p, peerkey->rsnie_p_len); -+ -+ wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey); -+ -+ peerkey->next = sm->peerkey; -+ sm->peerkey = peerkey; -+ -+ return 0; -+} -+ -+ -+/** -+ * rsn_smkid - Derive SMK identifier -+ * @smk: Station master key (32 bytes) -+ * @pnonce: Peer Nonce -+ * @mac_p: Peer MAC address -+ * @inonce: Initiator Nonce -+ * @mac_i: Initiator MAC address -+ * @use_sha256: Whether to use SHA256-based KDF -+ * -+ * 8.5.1.4 Station to station (STK) key hierarchy -+ * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I) -+ */ -+static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p, -+ const u8 *inonce, const u8 *mac_i, u8 *smkid, -+ int use_sha256) -+{ -+ char *title = "SMK Name"; -+ const u8 *addr[5]; -+ const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN, -+ ETH_ALEN }; -+ unsigned char hash[SHA256_MAC_LEN]; -+ -+ addr[0] = (u8 *) title; -+ addr[1] = pnonce; -+ addr[2] = mac_p; -+ addr[3] = inonce; -+ addr[4] = mac_i; -+ -+#ifdef CONFIG_IEEE80211W -+ if (use_sha256) -+ hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash); -+ else -+#endif /* CONFIG_IEEE80211W */ -+ hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash); -+ os_memcpy(smkid, hash, PMKID_LEN); -+} -+ -+ -+static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey) -+{ -+ size_t mlen; -+ struct wpa_eapol_key *msg; -+ u8 *mbuf; -+ size_t kde_len; -+ u16 key_info, ver; -+ -+ kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; -+ -+ mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, -+ sizeof(*msg) + kde_len, &mlen, -+ (void *) &msg); -+ if (mbuf == NULL) -+ return; -+ -+ msg->type = EAPOL_KEY_TYPE_RSN; -+ -+ if (peerkey->cipher == WPA_CIPHER_CCMP) -+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; -+ else -+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; -+ -+ key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK; -+ WPA_PUT_BE16(msg->key_info, key_info); -+ -+ if (peerkey->cipher == WPA_CIPHER_CCMP) -+ WPA_PUT_BE16(msg->key_length, 16); -+ else -+ WPA_PUT_BE16(msg->key_length, 32); -+ -+ os_memcpy(msg->replay_counter, peerkey->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); -+ -+ WPA_PUT_BE16(msg->key_data_length, kde_len); -+ wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID, -+ peerkey->smkid, PMKID_LEN); -+ -+ if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "RSN: Failed to get random data for INonce (STK)"); -+ os_free(mbuf); -+ return; -+ } -+ wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake", -+ peerkey->inonce, WPA_NONCE_LEN); -+ os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN); -+ -+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR, -+ MAC2STR(peerkey->addr)); -+ wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL, -+ mbuf, mlen, NULL); -+} -+ -+ -+static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey) -+{ -+ size_t mlen; -+ struct wpa_eapol_key *msg; -+ u8 *mbuf, *pos; -+ size_t kde_len; -+ u16 key_info, ver; -+ be32 lifetime; -+ -+ kde_len = peerkey->rsnie_i_len + -+ 2 + RSN_SELECTOR_LEN + sizeof(lifetime); -+ -+ mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, -+ sizeof(*msg) + kde_len, &mlen, -+ (void *) &msg); -+ if (mbuf == NULL) -+ return; -+ -+ msg->type = EAPOL_KEY_TYPE_RSN; -+ -+ if (peerkey->cipher == WPA_CIPHER_CCMP) -+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; -+ else -+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; -+ -+ key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK | -+ WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; -+ WPA_PUT_BE16(msg->key_info, key_info); -+ -+ if (peerkey->cipher == WPA_CIPHER_CCMP) -+ WPA_PUT_BE16(msg->key_length, 16); -+ else -+ WPA_PUT_BE16(msg->key_length, 32); -+ -+ os_memcpy(msg->replay_counter, peerkey->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); -+ -+ WPA_PUT_BE16(msg->key_data_length, kde_len); -+ pos = (u8 *) (msg + 1); -+ pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); -+ lifetime = host_to_be32(peerkey->lifetime); -+ wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, -+ (u8 *) &lifetime, sizeof(lifetime)); -+ -+ os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN); -+ -+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR, -+ MAC2STR(peerkey->addr)); -+ wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr, -+ ETH_P_EAPOL, mbuf, mlen, msg->key_mic); -+} -+ -+ -+static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey, -+ struct wpa_eapol_ie_parse *kde) -+{ -+ wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")", -+ MAC2STR(kde->mac_addr)); -+ -+ if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0) -+ { -+ wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not " -+ "match with the one used in SMK M3"); -+ return -1; -+ } -+ -+ if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not " -+ "match with the one received in SMK M2"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, -+ int ver, -+ struct wpa_peerkey *peerkey, -+ struct wpa_eapol_ie_parse *kde) -+{ -+ int cipher; -+ struct wpa_ie_data ie; -+ -+ wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")", -+ MAC2STR(kde->mac_addr)); -+ if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN || -+ wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) { -+ wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5"); -+ /* TODO: abort negotiation */ -+ return -1; -+ } -+ -+ if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does " -+ "not match with INonce used in SMK M1"); -+ return -1; -+ } -+ -+ if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0) -+ { -+ wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not " -+ "match with the one used in SMK M1"); -+ return -1; -+ } -+ -+ os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len); -+ peerkey->rsnie_p_len = kde->rsn_ie_len; -+ os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN); -+ -+ cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; -+ if (cipher & WPA_CIPHER_CCMP) { -+ wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); -+ peerkey->cipher = WPA_CIPHER_CCMP; -+ } else if (cipher & WPA_CIPHER_TKIP) { -+ wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); -+ peerkey->cipher = WPA_CIPHER_TKIP; -+ } else { -+ wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected " -+ "unacceptable cipher", MAC2STR(kde->mac_addr)); -+ wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr, -+ STK_MUI_SMK, STK_ERR_CPHR_NS, -+ ver); -+ /* TODO: abort negotiation */ -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_process_smk_m45( -+ struct wpa_sm *sm, const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, size_t extra_len, int ver) -+{ -+ struct wpa_peerkey *peerkey; -+ struct wpa_eapol_ie_parse kde; -+ u32 lifetime; -+ struct os_time now; -+ -+ if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { -+ wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " -+ "the current network"); -+ return -1; -+ } -+ -+ if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < -+ 0) { -+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5"); -+ return -1; -+ } -+ -+ if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || -+ kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN || -+ kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN || -+ kde.lifetime == NULL || kde.lifetime_len < 4) { -+ wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or " -+ "Lifetime KDE in SMK M4/M5"); -+ return -1; -+ } -+ -+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { -+ if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 && -+ os_memcmp(peerkey->initiator ? peerkey->inonce : -+ peerkey->pnonce, -+ key->key_nonce, WPA_NONCE_LEN) == 0) -+ break; -+ } -+ if (peerkey == NULL) { -+ wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found " -+ "for SMK M4/M5: peer " MACSTR, -+ MAC2STR(kde.mac_addr)); -+ return -1; -+ } -+ -+ if (peerkey->initiator) { -+ if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver, -+ peerkey, &kde) < 0) -+ return -1; -+ } else { -+ if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0) -+ return -1; -+ } -+ -+ os_memcpy(peerkey->smk, kde.smk, PMK_LEN); -+ peerkey->smk_complete = 1; -+ wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN); -+ lifetime = WPA_GET_BE32(kde.lifetime); -+ wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime); -+ if (lifetime > 1000000000) -+ lifetime = 1000000000; /* avoid overflowing expiration time */ -+ peerkey->lifetime = lifetime; -+ os_get_time(&now); -+ peerkey->expiration = now.sec + lifetime; -+ eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, -+ sm, peerkey); -+ -+ if (peerkey->initiator) { -+ rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr, -+ peerkey->inonce, sm->own_addr, peerkey->smkid, -+ peerkey->use_sha256); -+ wpa_supplicant_send_stk_1_of_4(sm, peerkey); -+ } else { -+ rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr, -+ peerkey->inonce, peerkey->addr, peerkey->smkid, -+ peerkey->use_sha256); -+ } -+ wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN); -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_process_smk_error( -+ struct wpa_sm *sm, const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, size_t extra_len) -+{ -+ struct wpa_eapol_ie_parse kde; -+ struct rsn_error_kde error; -+ u8 peer[ETH_ALEN]; -+ u16 error_type; -+ -+ wpa_printf(MSG_DEBUG, "RSN: Received SMK Error"); -+ -+ if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { -+ wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " -+ "the current network"); -+ return -1; -+ } -+ -+ if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < -+ 0) { -+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error"); -+ return -1; -+ } -+ -+ if (kde.error == NULL || kde.error_len < sizeof(error)) { -+ wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error"); -+ return -1; -+ } -+ -+ if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN) -+ os_memcpy(peer, kde.mac_addr, ETH_ALEN); -+ else -+ os_memset(peer, 0, ETH_ALEN); -+ os_memcpy(&error, kde.error, sizeof(error)); -+ error_type = be_to_host16(error.error_type); -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "RSN: SMK Error KDE received: MUI %d error_type %d peer " -+ MACSTR, -+ be_to_host16(error.mui), error_type, -+ MAC2STR(peer)); -+ -+ if (kde.mac_addr && -+ (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN || -+ error_type == STK_ERR_CPHR_NS)) { -+ struct wpa_peerkey *peerkey; -+ -+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { -+ if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == -+ 0) -+ break; -+ } -+ if (peerkey == NULL) { -+ wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake " -+ "found for SMK Error"); -+ return -1; -+ } -+ /* TODO: abort SMK/STK handshake and remove all related keys */ -+ } -+ -+ return 0; -+} -+ -+ -+static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ const struct wpa_eapol_key *key, -+ u16 ver) -+{ -+ struct wpa_eapol_ie_parse ie; -+ const u8 *kde; -+ size_t len, kde_buf_len; -+ struct wpa_ptk *stk; -+ u8 buf[8], *kde_buf, *pos; -+ be32 lifetime; -+ -+ wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from " -+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); -+ -+ os_memset(&ie, 0, sizeof(ie)); -+ -+ /* RSN: msg 1/4 should contain SMKID for the selected SMK */ -+ kde = (const u8 *) (key + 1); -+ len = WPA_GET_BE16(key->key_data_length); -+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len); -+ if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) { -+ wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4"); -+ return; -+ } -+ if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) { -+ wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4", -+ ie.pmkid, PMKID_LEN); -+ return; -+ } -+ -+ if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "RSN: Failed to get random data for PNonce"); -+ return; -+ } -+ wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce", -+ peerkey->pnonce, WPA_NONCE_LEN); -+ -+ /* Calculate STK which will be stored as a temporary STK until it has -+ * been verified when processing message 3/4. */ -+ stk = &peerkey->tstk; -+ wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion", -+ sm->own_addr, peerkey->addr, -+ peerkey->pnonce, key->key_nonce, -+ (u8 *) stk, sizeof(*stk), -+ peerkey->use_sha256); -+ /* Supplicant: swap tx/rx Mic keys */ -+ os_memcpy(buf, stk->u.auth.tx_mic_key, 8); -+ os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8); -+ os_memcpy(stk->u.auth.rx_mic_key, buf, 8); -+ peerkey->tstk_set = 1; -+ -+ kde_buf_len = peerkey->rsnie_p_len + -+ 2 + RSN_SELECTOR_LEN + sizeof(lifetime) + -+ 2 + RSN_SELECTOR_LEN + PMKID_LEN; -+ kde_buf = os_malloc(kde_buf_len); -+ if (kde_buf == NULL) -+ return; -+ pos = kde_buf; -+ pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len); -+ lifetime = host_to_be32(peerkey->lifetime); -+ pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, -+ (u8 *) &lifetime, sizeof(lifetime)); -+ wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN); -+ -+ if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver, -+ peerkey->pnonce, kde_buf, kde_buf_len, -+ stk)) { -+ os_free(kde_buf); -+ return; -+ } -+ os_free(kde_buf); -+ -+ os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); -+} -+ -+ -+static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ struct wpa_eapol_ie_parse *kde) -+{ -+ u32 lifetime; -+ struct os_time now; -+ -+ if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime)) -+ return; -+ -+ lifetime = WPA_GET_BE32(kde->lifetime); -+ -+ if (lifetime >= peerkey->lifetime) { -+ wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds " -+ "which is larger than or equal to own value %u " -+ "seconds - ignored", lifetime, peerkey->lifetime); -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds " -+ "(own was %u seconds) - updated", -+ lifetime, peerkey->lifetime); -+ peerkey->lifetime = lifetime; -+ -+ os_get_time(&now); -+ peerkey->expiration = now.sec + lifetime; -+ eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); -+ eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, -+ sm, peerkey); -+} -+ -+ -+static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ const struct wpa_eapol_key *key, -+ u16 ver) -+{ -+ struct wpa_eapol_ie_parse kde; -+ const u8 *keydata; -+ size_t len; -+ -+ wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from " -+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); -+ -+ os_memset(&kde, 0, sizeof(kde)); -+ -+ /* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE -+ * from the peer. It may also include Lifetime KDE. */ -+ keydata = (const u8 *) (key + 1); -+ len = WPA_GET_BE16(key->key_data_length); -+ wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len); -+ if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 || -+ kde.pmkid == NULL || kde.rsn_ie == NULL) { -+ wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4"); -+ return; -+ } -+ -+ if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) { -+ wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4", -+ kde.pmkid, PMKID_LEN); -+ return; -+ } -+ -+ if (kde.rsn_ie_len != peerkey->rsnie_p_len || -+ os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) { -+ wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK " -+ "handshakes did not match"); -+ wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake", -+ peerkey->rsnie_p, peerkey->rsnie_p_len); -+ wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake", -+ kde.rsn_ie, kde.rsn_ie_len); -+ return; -+ } -+ -+ wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde); -+ -+ wpa_supplicant_send_stk_3_of_4(sm, peerkey); -+ os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN); -+} -+ -+ -+static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ const struct wpa_eapol_key *key, -+ u16 ver) -+{ -+ struct wpa_eapol_ie_parse kde; -+ const u8 *keydata; -+ size_t len, key_len; -+ const u8 *_key; -+ u8 key_buf[32], rsc[6]; -+ -+ wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from " -+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); -+ -+ os_memset(&kde, 0, sizeof(kde)); -+ -+ /* RSN: msg 3/4 should contain Initiator RSN IE. It may also include -+ * Lifetime KDE. */ -+ keydata = (const u8 *) (key + 1); -+ len = WPA_GET_BE16(key->key_data_length); -+ wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len); -+ if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) { -+ wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in " -+ "STK 3/4"); -+ return; -+ } -+ -+ if (kde.rsn_ie_len != peerkey->rsnie_i_len || -+ os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) { -+ wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK " -+ "handshakes did not match"); -+ wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK " -+ "handshake", -+ peerkey->rsnie_i, peerkey->rsnie_i_len); -+ wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK " -+ "handshake", -+ kde.rsn_ie, kde.rsn_ie_len); -+ return; -+ } -+ -+ if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK " -+ "4-Way Handshake differs from 3 of STK 4-Way " -+ "Handshake - drop packet (src=" MACSTR ")", -+ MAC2STR(peerkey->addr)); -+ return; -+ } -+ -+ wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde); -+ -+ if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver, -+ WPA_GET_BE16(key->key_info), -+ NULL, 0, &peerkey->stk)) -+ return; -+ -+ _key = (u8 *) peerkey->stk.tk1; -+ if (peerkey->cipher == WPA_CIPHER_TKIP) { -+ /* Swap Tx/Rx keys for Michael MIC */ -+ os_memcpy(key_buf, _key, 16); -+ os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8); -+ os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8); -+ _key = key_buf; -+ key_len = 32; -+ } else -+ key_len = 16; -+ -+ os_memset(rsc, 0, 6); -+ if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1, -+ rsc, sizeof(rsc), _key, key_len) < 0) { -+ wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the " -+ "driver."); -+ return; -+ } -+} -+ -+ -+static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ const struct wpa_eapol_key *key, -+ u16 ver) -+{ -+ u8 rsc[6]; -+ -+ wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from " -+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); -+ -+ os_memset(rsc, 0, 6); -+ if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1, -+ rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1, -+ peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) { -+ wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the " -+ "driver."); -+ return; -+ } -+} -+ -+ -+/** -+ * peerkey_verify_eapol_key_mic - Verify PeerKey MIC -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @peerkey: Pointer to the PeerKey data for the peer -+ * @key: Pointer to the EAPOL-Key frame header -+ * @ver: Version bits from EAPOL-Key Key Info -+ * @buf: Pointer to the beginning of EAPOL-Key frame -+ * @len: Length of the EAPOL-Key frame -+ * Returns: 0 on success, -1 on failure -+ */ -+int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ struct wpa_eapol_key *key, u16 ver, -+ const u8 *buf, size_t len) -+{ -+ u8 mic[16]; -+ int ok = 0; -+ -+ if (peerkey->initiator && !peerkey->stk_set) { -+ wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion", -+ sm->own_addr, peerkey->addr, -+ peerkey->inonce, key->key_nonce, -+ (u8 *) &peerkey->stk, sizeof(peerkey->stk), -+ peerkey->use_sha256); -+ peerkey->stk_set = 1; -+ } -+ -+ os_memcpy(mic, key->key_mic, 16); -+ if (peerkey->tstk_set) { -+ os_memset(key->key_mic, 0, 16); -+ wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len, -+ key->key_mic); -+ if (os_memcmp(mic, key->key_mic, 16) != 0) { -+ wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " -+ "when using TSTK - ignoring TSTK"); -+ } else { -+ ok = 1; -+ peerkey->tstk_set = 0; -+ peerkey->stk_set = 1; -+ os_memcpy(&peerkey->stk, &peerkey->tstk, -+ sizeof(peerkey->stk)); -+ } -+ } -+ -+ if (!ok && peerkey->stk_set) { -+ os_memset(key->key_mic, 0, 16); -+ wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len, -+ key->key_mic); -+ if (os_memcmp(mic, key->key_mic, 16) != 0) { -+ wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " -+ "- dropping packet"); -+ return -1; -+ } -+ ok = 1; -+ } -+ -+ if (!ok) { -+ wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC " -+ "- dropping packet"); -+ return -1; -+ } -+ -+ os_memcpy(peerkey->replay_counter, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ peerkey->replay_counter_set = 1; -+ return 0; -+} -+ -+ -+/** -+ * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1) -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @peer: MAC address of the peer STA -+ * Returns: 0 on success, or -1 on failure -+ * -+ * Send an EAPOL-Key Request to the current authenticator to start STK -+ * handshake with the peer. -+ */ -+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) -+{ -+ size_t rlen, kde_len; -+ struct wpa_eapol_key *req; -+ int key_info, ver; -+ u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos; -+ u16 count; -+ struct rsn_ie_hdr *hdr; -+ struct wpa_peerkey *peerkey; -+ struct wpa_ie_data ie; -+ -+ if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled) -+ return -1; -+ -+ if (sm->ap_rsn_ie && -+ wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 && -+ !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) { -+ wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK"); -+ return -1; -+ } -+ -+ if (sm->pairwise_cipher == WPA_CIPHER_CCMP) -+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; -+ else -+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; -+ -+ if (wpa_sm_get_bssid(sm, bssid) < 0) { -+ wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " -+ "SMK M1"); -+ return -1; -+ } -+ -+ /* TODO: find existing entry and if found, use that instead of adding -+ * a new one */ -+ peerkey = os_zalloc(sizeof(*peerkey)); -+ if (peerkey == NULL) -+ return -1; -+ peerkey->initiator = 1; -+ os_memcpy(peerkey->addr, peer, ETH_ALEN); -+#ifdef CONFIG_IEEE80211W -+ if (wpa_key_mgmt_sha256(sm->key_mgmt)) -+ peerkey->use_sha256 = 1; -+#endif /* CONFIG_IEEE80211W */ -+ -+ /* SMK M1: -+ * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, -+ * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE)) -+ */ -+ -+ hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i; -+ hdr->elem_id = WLAN_EID_RSN; -+ WPA_PUT_LE16(hdr->version, RSN_VERSION); -+ pos = (u8 *) (hdr + 1); -+ /* Group Suite can be anything for SMK RSN IE; receiver will just -+ * ignore it. */ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ pos += RSN_SELECTOR_LEN; -+ count_pos = pos; -+ pos += 2; -+ -+ count = 0; -+ if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ pos += RSN_SELECTOR_LEN; -+ count++; -+ } -+ if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ pos += RSN_SELECTOR_LEN; -+ count++; -+ } -+ WPA_PUT_LE16(count_pos, count); -+ -+ hdr->len = (pos - peerkey->rsnie_i) - 2; -+ peerkey->rsnie_i_len = pos - peerkey->rsnie_i; -+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", -+ peerkey->rsnie_i, peerkey->rsnie_i_len); -+ -+ kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; -+ -+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, -+ sizeof(*req) + kde_len, &rlen, -+ (void *) &req); -+ if (rbuf == NULL) { -+ wpa_supplicant_peerkey_free(sm, peerkey); -+ return -1; -+ } -+ -+ req->type = EAPOL_KEY_TYPE_RSN; -+ key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | -+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver; -+ WPA_PUT_BE16(req->key_info, key_info); -+ WPA_PUT_BE16(req->key_length, 0); -+ os_memcpy(req->replay_counter, sm->request_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); -+ -+ if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to get random data for INonce"); -+ os_free(rbuf); -+ wpa_supplicant_peerkey_free(sm, peerkey); -+ return -1; -+ } -+ os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake", -+ req->key_nonce, WPA_NONCE_LEN); -+ -+ WPA_PUT_BE16(req->key_data_length, (u16) kde_len); -+ pos = (u8 *) (req + 1); -+ -+ /* Initiator RSN IE */ -+ pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); -+ /* Peer MAC address KDE */ -+ wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); -+ -+ wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer " -+ MACSTR ")", MAC2STR(peer)); -+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, -+ rbuf, rlen, req->key_mic); -+ -+ peerkey->next = sm->peerkey; -+ sm->peerkey = peerkey; -+ -+ return 0; -+} -+ -+ -+/** -+ * peerkey_deinit - Free PeerKey values -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ */ -+void peerkey_deinit(struct wpa_sm *sm) -+{ -+ struct wpa_peerkey *prev, *peerkey = sm->peerkey; -+ while (peerkey) { -+ prev = peerkey; -+ peerkey = peerkey->next; -+ os_free(prev); -+ } -+ sm->peerkey = NULL; -+} -+ -+ -+void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, -+ struct wpa_eapol_key *key, u16 key_info, u16 ver) -+{ -+ if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) == -+ (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) { -+ /* 3/4 STK 4-Way Handshake */ -+ wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver); -+ } else if (key_info & WPA_KEY_INFO_ACK) { -+ /* 1/4 STK 4-Way Handshake */ -+ wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver); -+ } else if (key_info & WPA_KEY_INFO_SECURE) { -+ /* 4/4 STK 4-Way Handshake */ -+ wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver); -+ } else { -+ /* 2/4 STK 4-Way Handshake */ -+ wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver); -+ } -+} -+ -+ -+void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, -+ struct wpa_eapol_key *key, size_t extra_len, -+ u16 key_info, u16 ver) -+{ -+ if (key_info & WPA_KEY_INFO_ERROR) { -+ /* SMK Error */ -+ wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len); -+ } else if (key_info & WPA_KEY_INFO_ACK) { -+ /* SMK M2 */ -+ wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len, -+ ver); -+ } else { -+ /* SMK M4 or M5 */ -+ wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len, -+ ver); -+ } -+} -+ -+#endif /* CONFIG_PEERKEY */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.h -new file mode 100644 -index 0000000000000..2613127c3ea48 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/peerkey.h -@@ -0,0 +1,87 @@ -+/* -+ * WPA Supplicant - PeerKey for Direct Link Setup (DLS) -+ * Copyright (c) 2006-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PEERKEY_H -+#define PEERKEY_H -+ -+#define PEERKEY_MAX_IE_LEN 80 -+struct wpa_peerkey { -+ struct wpa_peerkey *next; -+ int initiator; /* whether this end was initator for SMK handshake */ -+ u8 addr[ETH_ALEN]; /* other end MAC address */ -+ u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */ -+ u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */ -+ u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */ -+ size_t rsnie_i_len; -+ u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */ -+ size_t rsnie_p_len; -+ u8 smk[PMK_LEN]; -+ int smk_complete; -+ u8 smkid[PMKID_LEN]; -+ u32 lifetime; -+ os_time_t expiration; -+ int cipher; /* Selected cipher (WPA_CIPHER_*) */ -+ u8 replay_counter[WPA_REPLAY_COUNTER_LEN]; -+ int replay_counter_set; -+ int use_sha256; /* whether AKMP indicate SHA256-based derivations */ -+ -+ struct wpa_ptk stk, tstk; -+ int stk_set, tstk_set; -+}; -+ -+ -+#ifdef CONFIG_PEERKEY -+ -+int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ struct wpa_eapol_key *key, u16 ver, -+ const u8 *buf, size_t len); -+void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, -+ struct wpa_eapol_key *key, u16 key_info, u16 ver); -+void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, -+ struct wpa_eapol_key *key, size_t extra_len, -+ u16 key_info, u16 ver); -+void peerkey_deinit(struct wpa_sm *sm); -+ -+#else /* CONFIG_PEERKEY */ -+ -+static inline int -+peerkey_verify_eapol_key_mic(struct wpa_sm *sm, -+ struct wpa_peerkey *peerkey, -+ struct wpa_eapol_key *key, u16 ver, -+ const u8 *buf, size_t len) -+{ -+ return -1; -+} -+ -+static inline void -+peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, -+ struct wpa_eapol_key *key, u16 key_info, u16 ver) -+{ -+} -+ -+static inline void -+peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, -+ struct wpa_eapol_key *key, size_t extra_len, -+ u16 key_info, u16 ver) -+{ -+} -+ -+static inline void peerkey_deinit(struct wpa_sm *sm) -+{ -+} -+ -+#endif /* CONFIG_PEERKEY */ -+ -+#endif /* PEERKEY_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.c -new file mode 100644 -index 0000000000000..cac8c83e6eeb4 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.c -@@ -0,0 +1,476 @@ -+/* -+ * WPA Supplicant - RSN PMKSA cache -+ * Copyright (c) 2004-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "eapol_supp/eapol_supp_sm.h" -+#include "wpa.h" -+#include "wpa_i.h" -+#include "pmksa_cache.h" -+ -+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) -+ -+static const int pmksa_cache_max_entries = 32; -+ -+struct rsn_pmksa_cache { -+ struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ -+ int pmksa_count; /* number of entries in PMKSA cache */ -+ struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ -+ -+ void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, -+ int replace); -+ void *ctx; -+}; -+ -+ -+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); -+ -+ -+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) -+{ -+ os_free(entry); -+} -+ -+ -+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, -+ struct rsn_pmksa_cache_entry *entry, -+ int replace) -+{ -+ pmksa->pmksa_count--; -+ pmksa->free_cb(entry, pmksa->ctx, replace); -+ _pmksa_cache_free_entry(entry); -+} -+ -+ -+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct rsn_pmksa_cache *pmksa = eloop_ctx; -+ struct os_time now; -+ -+ os_get_time(&now); -+ while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { -+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; -+ pmksa->pmksa = entry->next; -+ wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " -+ MACSTR, MAC2STR(entry->aa)); -+ pmksa_cache_free_entry(pmksa, entry, 0); -+ } -+ -+ pmksa_cache_set_expiration(pmksa); -+} -+ -+ -+static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct rsn_pmksa_cache *pmksa = eloop_ctx; -+ pmksa->sm->cur_pmksa = NULL; -+ eapol_sm_request_reauth(pmksa->sm->eapol); -+} -+ -+ -+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) -+{ -+ int sec; -+ struct rsn_pmksa_cache_entry *entry; -+ struct os_time now; -+ -+ eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); -+ eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); -+ if (pmksa->pmksa == NULL) -+ return; -+ os_get_time(&now); -+ sec = pmksa->pmksa->expiration - now.sec; -+ if (sec < 0) -+ sec = 0; -+ eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); -+ -+ entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : -+ pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL); -+ if (entry) { -+ sec = pmksa->pmksa->reauth_time - now.sec; -+ if (sec < 0) -+ sec = 0; -+ eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, -+ NULL); -+ } -+} -+ -+ -+/** -+ * pmksa_cache_add - Add a PMKSA cache entry -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() -+ * @pmk: The new pairwise master key -+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32) -+ * @aa: Authenticator address -+ * @spa: Supplicant address -+ * @network_ctx: Network configuration context for this PMK -+ * @akmp: WPA_KEY_MGMT_* used in key derivation -+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error -+ * -+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA -+ * cache. If an old entry is already in the cache for the same Authenticator, -+ * this entry will be replaced with the new entry. PMKID will be calculated -+ * based on the PMK and the driver interface is notified of the new PMKID. -+ */ -+struct rsn_pmksa_cache_entry * -+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, -+ const u8 *aa, const u8 *spa, void *network_ctx, int akmp) -+{ -+ struct rsn_pmksa_cache_entry *entry, *pos, *prev; -+ struct os_time now; -+ -+ if (pmk_len > PMK_LEN) -+ return NULL; -+ -+ entry = os_zalloc(sizeof(*entry)); -+ if (entry == NULL) -+ return NULL; -+ os_memcpy(entry->pmk, pmk, pmk_len); -+ entry->pmk_len = pmk_len; -+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, -+ wpa_key_mgmt_sha256(akmp)); -+ os_get_time(&now); -+ entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; -+ entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * -+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; -+ entry->akmp = akmp; -+ os_memcpy(entry->aa, aa, ETH_ALEN); -+ entry->network_ctx = network_ctx; -+ -+ /* Replace an old entry for the same Authenticator (if found) with the -+ * new entry */ -+ pos = pmksa->pmksa; -+ prev = NULL; -+ while (pos) { -+ if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { -+ if (pos->pmk_len == pmk_len && -+ os_memcmp(pos->pmk, pmk, pmk_len) == 0 && -+ os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == -+ 0) { -+ wpa_printf(MSG_DEBUG, "WPA: reusing previous " -+ "PMKSA entry"); -+ os_free(entry); -+ return pos; -+ } -+ if (prev == NULL) -+ pmksa->pmksa = pos->next; -+ else -+ prev->next = pos->next; -+ if (pos == pmksa->sm->cur_pmksa) { -+ /* We are about to replace the current PMKSA -+ * cache entry. This happens when the PMKSA -+ * caching attempt fails, so we don't want to -+ * force pmksa_cache_free_entry() to disconnect -+ * at this point. Let's just make sure the old -+ * PMKSA cache entry will not be used in the -+ * future. -+ */ -+ wpa_printf(MSG_DEBUG, "RSN: replacing current " -+ "PMKSA entry"); -+ pmksa->sm->cur_pmksa = NULL; -+ } -+ wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " -+ "the current AP"); -+ pmksa_cache_free_entry(pmksa, pos, 1); -+ break; -+ } -+ prev = pos; -+ pos = pos->next; -+ } -+ -+ if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { -+ /* Remove the oldest entry to make room for the new entry */ -+ pos = pmksa->pmksa; -+ pmksa->pmksa = pos->next; -+ wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " -+ "entry (for " MACSTR ") to make room for new one", -+ MAC2STR(pos->aa)); -+ wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid); -+ pmksa_cache_free_entry(pmksa, pos, 0); -+ } -+ -+ /* Add the new entry; order by expiration time */ -+ pos = pmksa->pmksa; -+ prev = NULL; -+ while (pos) { -+ if (pos->expiration > entry->expiration) -+ break; -+ prev = pos; -+ pos = pos->next; -+ } -+ if (prev == NULL) { -+ entry->next = pmksa->pmksa; -+ pmksa->pmksa = entry; -+ pmksa_cache_set_expiration(pmksa); -+ } else { -+ entry->next = prev->next; -+ prev->next = entry; -+ } -+ pmksa->pmksa_count++; -+ wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR, -+ MAC2STR(entry->aa)); -+ wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid); -+ -+ return entry; -+} -+ -+ -+/** -+ * pmksa_cache_deinit - Free all entries in PMKSA cache -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() -+ */ -+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) -+{ -+ struct rsn_pmksa_cache_entry *entry, *prev; -+ -+ if (pmksa == NULL) -+ return; -+ -+ entry = pmksa->pmksa; -+ pmksa->pmksa = NULL; -+ while (entry) { -+ prev = entry; -+ entry = entry->next; -+ os_free(prev); -+ } -+ pmksa_cache_set_expiration(pmksa); -+ os_free(pmksa); -+} -+ -+ -+/** -+ * pmksa_cache_get - Fetch a PMKSA cache entry -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() -+ * @aa: Authenticator address or %NULL to match any -+ * @pmkid: PMKID or %NULL to match any -+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found -+ */ -+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, -+ const u8 *aa, const u8 *pmkid) -+{ -+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; -+ while (entry) { -+ if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && -+ (pmkid == NULL || -+ os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) -+ return entry; -+ entry = entry->next; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() -+ * -+ * Clear references to old data structures when wpa_supplicant is reconfigured. -+ */ -+void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) -+{ -+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; -+ while (entry) { -+ entry->network_ctx = NULL; -+ entry = entry->next; -+ } -+} -+ -+ -+static struct rsn_pmksa_cache_entry * -+pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, -+ const struct rsn_pmksa_cache_entry *old_entry, -+ const u8 *aa) -+{ -+ struct rsn_pmksa_cache_entry *new_entry; -+ -+ new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, -+ aa, pmksa->sm->own_addr, -+ old_entry->network_ctx, old_entry->akmp); -+ if (new_entry == NULL) -+ return NULL; -+ -+ /* TODO: reorder entries based on expiration time? */ -+ new_entry->expiration = old_entry->expiration; -+ new_entry->opportunistic = 1; -+ -+ return new_entry; -+} -+ -+ -+/** -+ * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() -+ * @network_ctx: Network configuration context -+ * @aa: Authenticator address for the new AP -+ * Returns: Pointer to a new PMKSA cache entry or %NULL if not available -+ * -+ * Try to create a new PMKSA cache entry opportunistically by guessing that the -+ * new AP is sharing the same PMK as another AP that has the same SSID and has -+ * already an entry in PMKSA cache. -+ */ -+struct rsn_pmksa_cache_entry * -+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, -+ const u8 *aa) -+{ -+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; -+ -+ if (network_ctx == NULL) -+ return NULL; -+ while (entry) { -+ if (entry->network_ctx == network_ctx) { -+ entry = pmksa_cache_clone_entry(pmksa, entry, aa); -+ if (entry) { -+ wpa_printf(MSG_DEBUG, "RSN: added " -+ "opportunistic PMKSA cache entry " -+ "for " MACSTR, MAC2STR(aa)); -+ } -+ return entry; -+ } -+ entry = entry->next; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * pmksa_cache_get_current - Get the current used PMKSA entry -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * Returns: Pointer to the current PMKSA cache entry or %NULL if not available -+ */ -+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return NULL; -+ return sm->cur_pmksa; -+} -+ -+ -+/** -+ * pmksa_cache_clear_current - Clear the current PMKSA entry selection -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ */ -+void pmksa_cache_clear_current(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ sm->cur_pmksa = NULL; -+} -+ -+ -+/** -+ * pmksa_cache_set_current - Set the current PMKSA entry selection -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @pmkid: PMKID for selecting PMKSA or %NULL if not used -+ * @bssid: BSSID for PMKSA or %NULL if not used -+ * @network_ctx: Network configuration context -+ * @try_opportunistic: Whether to allow opportunistic PMKSA caching -+ * Returns: 0 if PMKSA was found or -1 if no matching entry was found -+ */ -+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, -+ const u8 *bssid, void *network_ctx, -+ int try_opportunistic) -+{ -+ struct rsn_pmksa_cache *pmksa = sm->pmksa; -+ sm->cur_pmksa = NULL; -+ if (pmkid) -+ sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid); -+ if (sm->cur_pmksa == NULL && bssid) -+ sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL); -+ if (sm->cur_pmksa == NULL && try_opportunistic && bssid) -+ sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, -+ network_ctx, -+ bssid); -+ if (sm->cur_pmksa) { -+ wpa_hexdump(MSG_DEBUG, "RSN: PMKID", -+ sm->cur_pmksa->pmkid, PMKID_LEN); -+ return 0; -+ } -+ return -1; -+} -+ -+ -+/** -+ * pmksa_cache_list - Dump text list of entries in PMKSA cache -+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() -+ * @buf: Buffer for the list -+ * @len: Length of the buffer -+ * Returns: number of bytes written to buffer -+ * -+ * This function is used to generate a text format representation of the -+ * current PMKSA cache contents for the ctrl_iface PMKSA command. -+ */ -+int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) -+{ -+ int i, ret; -+ char *pos = buf; -+ struct rsn_pmksa_cache_entry *entry; -+ struct os_time now; -+ -+ os_get_time(&now); -+ ret = os_snprintf(pos, buf + len - pos, -+ "Index / AA / PMKID / expiration (in seconds) / " -+ "opportunistic\n"); -+ if (ret < 0 || ret >= buf + len - pos) -+ return pos - buf; -+ pos += ret; -+ i = 0; -+ entry = pmksa->pmksa; -+ while (entry) { -+ i++; -+ ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", -+ i, MAC2STR(entry->aa)); -+ if (ret < 0 || ret >= buf + len - pos) -+ return pos - buf; -+ pos += ret; -+ pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, -+ PMKID_LEN); -+ ret = os_snprintf(pos, buf + len - pos, " %d %d\n", -+ (int) (entry->expiration - now.sec), -+ entry->opportunistic); -+ if (ret < 0 || ret >= buf + len - pos) -+ return pos - buf; -+ pos += ret; -+ entry = entry->next; -+ } -+ return pos - buf; -+} -+ -+ -+/** -+ * pmksa_cache_init - Initialize PMKSA cache -+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed -+ * @ctx: Context pointer for free_cb function -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * Returns: Pointer to PMKSA cache data or %NULL on failure -+ */ -+struct rsn_pmksa_cache * -+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, -+ void *ctx, int replace), -+ void *ctx, struct wpa_sm *sm) -+{ -+ struct rsn_pmksa_cache *pmksa; -+ -+ pmksa = os_zalloc(sizeof(*pmksa)); -+ if (pmksa) { -+ pmksa->free_cb = free_cb; -+ pmksa->ctx = ctx; -+ pmksa->sm = sm; -+ } -+ -+ return pmksa; -+} -+ -+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.h -new file mode 100644 -index 0000000000000..a1447e526d5bc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/pmksa_cache.h -@@ -0,0 +1,127 @@ -+/* -+ * wpa_supplicant - WPA2/RSN PMKSA cache functions -+ * Copyright (c) 2003-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PMKSA_CACHE_H -+#define PMKSA_CACHE_H -+ -+/** -+ * struct rsn_pmksa_cache_entry - PMKSA cache entry -+ */ -+struct rsn_pmksa_cache_entry { -+ struct rsn_pmksa_cache_entry *next; -+ u8 pmkid[PMKID_LEN]; -+ u8 pmk[PMK_LEN]; -+ size_t pmk_len; -+ os_time_t expiration; -+ int akmp; /* WPA_KEY_MGMT_* */ -+ u8 aa[ETH_ALEN]; -+ -+ os_time_t reauth_time; -+ -+ /** -+ * network_ctx - Network configuration context -+ * -+ * This field is only used to match PMKSA cache entries to a specific -+ * network configuration (e.g., a specific SSID and security policy). -+ * This can be a pointer to the configuration entry, but PMKSA caching -+ * code does not dereference the value and this could be any kind of -+ * identifier. -+ */ -+ void *network_ctx; -+ int opportunistic; -+}; -+ -+struct rsn_pmksa_cache; -+ -+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) -+ -+struct rsn_pmksa_cache * -+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, -+ void *ctx, int replace), -+ void *ctx, struct wpa_sm *sm); -+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); -+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, -+ const u8 *aa, const u8 *pmkid); -+int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); -+struct rsn_pmksa_cache_entry * -+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, -+ const u8 *aa, const u8 *spa, void *network_ctx, int akmp); -+void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa); -+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); -+void pmksa_cache_clear_current(struct wpa_sm *sm); -+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, -+ const u8 *bssid, void *network_ctx, -+ int try_opportunistic); -+struct rsn_pmksa_cache_entry * -+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, -+ void *network_ctx, const u8 *aa); -+ -+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ -+ -+static inline struct rsn_pmksa_cache * -+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, -+ void *ctx, int replace), -+ void *ctx, struct wpa_sm *sm) -+{ -+ return (void *) -1; -+} -+ -+static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) -+{ -+} -+ -+static inline struct rsn_pmksa_cache_entry * -+pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid) -+{ -+ return NULL; -+} -+ -+static inline struct rsn_pmksa_cache_entry * -+pmksa_cache_get_current(struct wpa_sm *sm) -+{ -+ return NULL; -+} -+ -+static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, -+ size_t len) -+{ -+ return -1; -+} -+ -+static inline struct rsn_pmksa_cache_entry * -+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, -+ const u8 *aa, const u8 *spa, void *network_ctx, int akmp) -+{ -+ return NULL; -+} -+ -+static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) -+{ -+} -+ -+static inline void pmksa_cache_clear_current(struct wpa_sm *sm) -+{ -+} -+ -+static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, -+ const u8 *bssid, -+ void *network_ctx, -+ int try_opportunistic) -+{ -+ return -1; -+} -+ -+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ -+ -+#endif /* PMKSA_CACHE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.c -new file mode 100644 -index 0000000000000..6109f5e9f8734 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.c -@@ -0,0 +1,518 @@ -+/* -+ * RSN pre-authentication (supplicant) -+ * Copyright (c) 2003-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "wpa.h" -+#include "eloop.h" -+#include "l2_packet/l2_packet.h" -+#include "eapol_supp/eapol_supp_sm.h" -+#include "preauth.h" -+#include "pmksa_cache.h" -+#include "wpa_i.h" -+#include "common/ieee802_11_defs.h" -+ -+ -+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) -+ -+#define PMKID_CANDIDATE_PRIO_SCAN 1000 -+ -+ -+struct rsn_pmksa_candidate { -+ struct dl_list list; -+ u8 bssid[ETH_ALEN]; -+ int priority; -+}; -+ -+ -+/** -+ * pmksa_candidate_free - Free all entries in PMKSA candidate list -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ */ -+void pmksa_candidate_free(struct wpa_sm *sm) -+{ -+ struct rsn_pmksa_candidate *entry, *n; -+ -+ if (sm == NULL) -+ return; -+ -+ dl_list_for_each_safe(entry, n, &sm->pmksa_candidates, -+ struct rsn_pmksa_candidate, list) { -+ dl_list_del(&entry->list); -+ os_free(entry); -+ } -+} -+ -+ -+static void rsn_preauth_receive(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct wpa_sm *sm = ctx; -+ -+ wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr)); -+ wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len); -+ -+ if (sm->preauth_eapol == NULL || -+ is_zero_ether_addr(sm->preauth_bssid) || -+ os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) { -+ wpa_printf(MSG_WARNING, "RSN pre-auth frame received from " -+ "unexpected source " MACSTR " - dropped", -+ MAC2STR(src_addr)); -+ return; -+ } -+ -+ eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len); -+} -+ -+ -+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success, -+ void *ctx) -+{ -+ struct wpa_sm *sm = ctx; -+ u8 pmk[PMK_LEN]; -+ -+ if (success) { -+ int res, pmk_len; -+ pmk_len = PMK_LEN; -+ res = eapol_sm_get_key(eapol, pmk, PMK_LEN); -+ if (res) { -+ /* -+ * EAP-LEAP is an exception from other EAP methods: it -+ * uses only 16-byte PMK. -+ */ -+ res = eapol_sm_get_key(eapol, pmk, 16); -+ pmk_len = 16; -+ } -+ if (res == 0) { -+ wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth", -+ pmk, pmk_len); -+ sm->pmk_len = pmk_len; -+ pmksa_cache_add(sm->pmksa, pmk, pmk_len, -+ sm->preauth_bssid, sm->own_addr, -+ sm->network_ctx, -+ WPA_KEY_MGMT_IEEE8021X); -+ } else { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "RSN: failed to get master session key from " -+ "pre-auth EAPOL state machines"); -+ success = 0; -+ } -+ } -+ -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " -+ MACSTR " %s", MAC2STR(sm->preauth_bssid), -+ success ? "completed successfully" : "failed"); -+ -+ rsn_preauth_deinit(sm); -+ rsn_preauth_candidate_process(sm); -+} -+ -+ -+static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_sm *sm = eloop_ctx; -+ -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with " -+ MACSTR " timed out", MAC2STR(sm->preauth_bssid)); -+ rsn_preauth_deinit(sm); -+ rsn_preauth_candidate_process(sm); -+} -+ -+ -+static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf, -+ size_t len) -+{ -+ struct wpa_sm *sm = ctx; -+ u8 *msg; -+ size_t msglen; -+ int res; -+ -+ /* TODO: could add l2_packet_sendmsg that allows fragments to avoid -+ * extra copy here */ -+ -+ if (sm->l2_preauth == NULL) -+ return -1; -+ -+ msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL); -+ if (msg == NULL) -+ return -1; -+ -+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen); -+ res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid, -+ ETH_P_RSN_PREAUTH, msg, msglen); -+ os_free(msg); -+ return res; -+} -+ -+ -+/** -+ * rsn_preauth_init - Start new RSN pre-authentication -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @dst: Authenticator address (BSSID) with which to preauthenticate -+ * @eap_conf: Current EAP configuration -+ * Returns: 0 on success, -1 on another pre-authentication is in progress, -+ * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine -+ * initialization failure, -4 on memory allocation failure -+ * -+ * This function request an RSN pre-authentication with a given destination -+ * address. This is usually called for PMKSA candidates found from scan results -+ * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger -+ * pre-authentication. -+ */ -+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, -+ struct eap_peer_config *eap_conf) -+{ -+ struct eapol_config eapol_conf; -+ struct eapol_ctx *ctx; -+ -+ if (sm->preauth_eapol) -+ return -1; -+ -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: starting pre-authentication with " MACSTR, MAC2STR(dst)); -+ -+ sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr, -+ ETH_P_RSN_PREAUTH, -+ rsn_preauth_receive, sm, 0); -+ if (sm->l2_preauth == NULL) { -+ wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet " -+ "processing for pre-authentication"); -+ return -2; -+ } -+ -+ if (sm->bridge_ifname) { -+ sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname, -+ sm->own_addr, -+ ETH_P_RSN_PREAUTH, -+ rsn_preauth_receive, sm, 0); -+ if (sm->l2_preauth_br == NULL) { -+ wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 " -+ "packet processing (bridge) for " -+ "pre-authentication"); -+ return -2; -+ } -+ } -+ -+ ctx = os_zalloc(sizeof(*ctx)); -+ if (ctx == NULL) { -+ wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context."); -+ return -4; -+ } -+ ctx->ctx = sm->ctx->ctx; -+ ctx->msg_ctx = sm->ctx->ctx; -+ ctx->preauth = 1; -+ ctx->cb = rsn_preauth_eapol_cb; -+ ctx->cb_ctx = sm; -+ ctx->scard_ctx = sm->scard_ctx; -+ ctx->eapol_send = rsn_preauth_eapol_send; -+ ctx->eapol_send_ctx = sm; -+ ctx->set_config_blob = sm->ctx->set_config_blob; -+ ctx->get_config_blob = sm->ctx->get_config_blob; -+ -+ sm->preauth_eapol = eapol_sm_init(ctx); -+ if (sm->preauth_eapol == NULL) { -+ os_free(ctx); -+ wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL " -+ "state machines for pre-authentication"); -+ return -3; -+ } -+ os_memset(&eapol_conf, 0, sizeof(eapol_conf)); -+ eapol_conf.accept_802_1x_keys = 0; -+ eapol_conf.required_keys = 0; -+ eapol_conf.fast_reauth = sm->fast_reauth; -+ eapol_conf.workaround = sm->eap_workaround; -+ eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf); -+ /* -+ * Use a shorter startPeriod with preauthentication since the first -+ * preauth EAPOL-Start frame may end up being dropped due to race -+ * condition in the AP between the data receive and key configuration -+ * after the 4-Way Handshake. -+ */ -+ eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6); -+ os_memcpy(sm->preauth_bssid, dst, ETH_ALEN); -+ -+ eapol_sm_notify_portValid(sm->preauth_eapol, TRUE); -+ /* 802.1X::portControl = Auto */ -+ eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE); -+ -+ eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0, -+ rsn_preauth_timeout, sm, NULL); -+ -+ return 0; -+} -+ -+ -+/** -+ * rsn_preauth_deinit - Abort RSN pre-authentication -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * -+ * This function aborts the current RSN pre-authentication (if one is started) -+ * and frees resources allocated for it. -+ */ -+void rsn_preauth_deinit(struct wpa_sm *sm) -+{ -+ if (sm == NULL || !sm->preauth_eapol) -+ return; -+ -+ eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL); -+ eapol_sm_deinit(sm->preauth_eapol); -+ sm->preauth_eapol = NULL; -+ os_memset(sm->preauth_bssid, 0, ETH_ALEN); -+ -+ l2_packet_deinit(sm->l2_preauth); -+ sm->l2_preauth = NULL; -+ if (sm->l2_preauth_br) { -+ l2_packet_deinit(sm->l2_preauth_br); -+ sm->l2_preauth_br = NULL; -+ } -+} -+ -+ -+/** -+ * rsn_preauth_candidate_process - Process PMKSA candidates -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * -+ * Go through the PMKSA candidates and start pre-authentication if a candidate -+ * without an existing PMKSA cache entry is found. Processed candidates will be -+ * removed from the list. -+ */ -+void rsn_preauth_candidate_process(struct wpa_sm *sm) -+{ -+ struct rsn_pmksa_candidate *candidate, *n; -+ -+ if (dl_list_empty(&sm->pmksa_candidates)) -+ return; -+ -+ /* TODO: drop priority for old candidate entries */ -+ -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate " -+ "list"); -+ if (sm->preauth_eapol || -+ sm->proto != WPA_PROTO_RSN || -+ wpa_sm_get_state(sm) != WPA_COMPLETED || -+ (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X && -+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable " -+ "state for new pre-authentication"); -+ return; /* invalid state for new pre-auth */ -+ } -+ -+ dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates, -+ struct rsn_pmksa_candidate, list) { -+ struct rsn_pmksa_cache_entry *p = NULL; -+ p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL); -+ if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 && -+ (p == NULL || p->opportunistic)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA " -+ "candidate " MACSTR -+ " selected for pre-authentication", -+ MAC2STR(candidate->bssid)); -+ dl_list_del(&candidate->list); -+ rsn_preauth_init(sm, candidate->bssid, -+ sm->eap_conf_ctx); -+ os_free(candidate); -+ return; -+ } -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate " -+ MACSTR " does not need pre-authentication anymore", -+ MAC2STR(candidate->bssid)); -+ /* Some drivers (e.g., NDIS) expect to get notified about the -+ * PMKIDs again, so report the existing data now. */ -+ if (p) { -+ wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid); -+ } -+ -+ dl_list_del(&candidate->list); -+ os_free(candidate); -+ } -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA " -+ "candidates"); -+} -+ -+ -+/** -+ * pmksa_candidate_add - Add a new PMKSA candidate -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @bssid: BSSID (authenticator address) of the candidate -+ * @prio: Priority (the smaller number, the higher priority) -+ * @preauth: Whether the candidate AP advertises support for pre-authentication -+ * -+ * This function is used to add PMKSA candidates for RSN pre-authentication. It -+ * is called from scan result processing and from driver events for PMKSA -+ * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event(). -+ */ -+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, -+ int prio, int preauth) -+{ -+ struct rsn_pmksa_candidate *cand, *pos; -+ -+ if (sm->network_ctx && sm->proactive_key_caching) -+ pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx, -+ bssid); -+ -+ if (!preauth) { -+ wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without " -+ "preauth flag"); -+ return; -+ } -+ -+ /* If BSSID already on candidate list, update the priority of the old -+ * entry. Do not override priority based on normal scan results. */ -+ cand = NULL; -+ dl_list_for_each(pos, &sm->pmksa_candidates, -+ struct rsn_pmksa_candidate, list) { -+ if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) { -+ cand = pos; -+ break; -+ } -+ } -+ -+ if (cand) { -+ dl_list_del(&cand->list); -+ if (prio < PMKID_CANDIDATE_PRIO_SCAN) -+ cand->priority = prio; -+ } else { -+ cand = os_zalloc(sizeof(*cand)); -+ if (cand == NULL) -+ return; -+ os_memcpy(cand->bssid, bssid, ETH_ALEN); -+ cand->priority = prio; -+ } -+ -+ /* Add candidate to the list; order by increasing priority value. i.e., -+ * highest priority (smallest value) first. */ -+ dl_list_for_each(pos, &sm->pmksa_candidates, -+ struct rsn_pmksa_candidate, list) { -+ if (cand->priority <= pos->priority) { -+ dl_list_add(pos->list.prev, &cand->list); -+ cand = NULL; -+ break; -+ } -+ } -+ if (cand) -+ dl_list_add_tail(&sm->pmksa_candidates, &cand->list); -+ -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache " -+ "candidate " MACSTR " prio %d", MAC2STR(bssid), prio); -+ rsn_preauth_candidate_process(sm); -+} -+ -+ -+/* TODO: schedule periodic scans if current AP supports preauth */ -+ -+/** -+ * rsn_preauth_scan_results - Start processing scan results for canditates -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * Returns: 0 if ready to process results or -1 to skip processing -+ * -+ * This functions is used to notify RSN code about start of new scan results -+ * processing. The actual scan results will be provided by calling -+ * rsn_preauth_scan_result() for each BSS if this function returned 0. -+ */ -+int rsn_preauth_scan_results(struct wpa_sm *sm) -+{ -+ if (sm->ssid_len == 0) -+ return -1; -+ -+ /* -+ * TODO: is it ok to free all candidates? What about the entries -+ * received from EVENT_PMKID_CANDIDATE? -+ */ -+ pmksa_candidate_free(sm); -+ -+ return 0; -+} -+ -+ -+/** -+ * rsn_preauth_scan_result - Processing scan result for PMKSA canditates -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * -+ * Add all suitable APs (Authenticators) from scan results into PMKSA -+ * candidate list. -+ */ -+void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, -+ const u8 *ssid, const u8 *rsn) -+{ -+ struct wpa_ie_data ie; -+ struct rsn_pmksa_cache_entry *pmksa; -+ -+ if (ssid[1] != sm->ssid_len || -+ os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0) -+ return; /* Not for the current SSID */ -+ -+ if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0) -+ return; /* Ignore current AP */ -+ -+ if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) -+ return; -+ -+ pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL); -+ if (pmksa && (!pmksa->opportunistic || -+ !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) -+ return; -+ -+ /* Give less priority to candidates found from normal scan results. */ -+ pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN, -+ ie.capabilities & WPA_CAPABILITY_PREAUTH); -+} -+ -+ -+#ifdef CONFIG_CTRL_IFACE -+/** -+ * rsn_preauth_get_status - Get pre-authentication status -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @buf: Buffer for status information -+ * @buflen: Maximum buffer length -+ * @verbose: Whether to include verbose status information -+ * Returns: Number of bytes written to buf. -+ * -+ * Query WPA2 pre-authentication for status information. This function fills in -+ * a text area with current status information. If the buffer (buf) is not -+ * large enough, status information will be truncated to fit the buffer. -+ */ -+int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen, -+ int verbose) -+{ -+ char *pos = buf, *end = buf + buflen; -+ int res, ret; -+ -+ if (sm->preauth_eapol) { -+ ret = os_snprintf(pos, end - pos, "Pre-authentication " -+ "EAPOL state machines:\n"); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ res = eapol_sm_get_status(sm->preauth_eapol, -+ pos, end - pos, verbose); -+ if (res >= 0) -+ pos += res; -+ } -+ -+ return pos - buf; -+} -+#endif /* CONFIG_CTRL_IFACE */ -+ -+ -+/** -+ * rsn_preauth_in_progress - Verify whether pre-authentication is in progress -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ */ -+int rsn_preauth_in_progress(struct wpa_sm *sm) -+{ -+ return sm->preauth_eapol != NULL; -+} -+ -+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.h -new file mode 100644 -index 0000000000000..f8240abef6df8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/preauth.h -@@ -0,0 +1,85 @@ -+/* -+ * wpa_supplicant - WPA2/RSN pre-authentication functions -+ * Copyright (c) 2003-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PREAUTH_H -+#define PREAUTH_H -+ -+struct wpa_scan_results; -+ -+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) -+ -+void pmksa_candidate_free(struct wpa_sm *sm); -+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, -+ struct eap_peer_config *eap_conf); -+void rsn_preauth_deinit(struct wpa_sm *sm); -+int rsn_preauth_scan_results(struct wpa_sm *sm); -+void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, -+ const u8 *ssid, const u8 *rsn); -+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, -+ int prio, int preauth); -+void rsn_preauth_candidate_process(struct wpa_sm *sm); -+int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen, -+ int verbose); -+int rsn_preauth_in_progress(struct wpa_sm *sm); -+ -+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ -+ -+static inline void pmksa_candidate_free(struct wpa_sm *sm) -+{ -+} -+ -+static inline void rsn_preauth_candidate_process(struct wpa_sm *sm) -+{ -+} -+ -+static inline int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, -+ struct eap_peer_config *eap_conf) -+{ -+ return -1; -+} -+ -+static inline void rsn_preauth_deinit(struct wpa_sm *sm) -+{ -+} -+ -+static inline int rsn_preauth_scan_results(struct wpa_sm *sm) -+{ -+ return -1; -+} -+ -+static inline void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, -+ const u8 *ssid, const u8 *rsn) -+{ -+} -+ -+static inline void pmksa_candidate_add(struct wpa_sm *sm, -+ const u8 *bssid, -+ int prio, int preauth) -+{ -+} -+ -+static inline int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, -+ size_t buflen, int verbose) -+{ -+ return 0; -+} -+ -+static inline int rsn_preauth_in_progress(struct wpa_sm *sm) -+{ -+ return 0; -+} -+ -+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ -+ -+#endif /* PREAUTH_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/tdls.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/tdls.c -new file mode 100644 -index 0000000000000..e75186798230b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/tdls.c -@@ -0,0 +1,2069 @@ -+/* -+ * wpa_supplicant - TDLS -+ * Copyright (c) 2010-2011, Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "utils/includes.h" -+ -+#include "utils/common.h" -+#include "utils/eloop.h" -+#include "utils/os.h" -+#include "common/ieee802_11_defs.h" -+#include "crypto/sha256.h" -+#include "crypto/crypto.h" -+#include "crypto/aes_wrap.h" -+#include "rsn_supp/wpa.h" -+#include "rsn_supp/wpa_ie.h" -+#include "rsn_supp/wpa_i.h" -+#include "drivers/driver.h" -+#include "l2_packet/l2_packet.h" -+ -+#ifdef CONFIG_TDLS_TESTING -+#define TDLS_TESTING_LONG_FRAME BIT(0) -+#define TDLS_TESTING_ALT_RSN_IE BIT(1) -+#define TDLS_TESTING_DIFF_BSSID BIT(2) -+#define TDLS_TESTING_SHORT_LIFETIME BIT(3) -+#define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4) -+#define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5) -+#define TDLS_TESTING_LONG_LIFETIME BIT(6) -+#define TDLS_TESTING_CONCURRENT_INIT BIT(7) -+#define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8) -+#define TDLS_TESTING_DECLINE_RESP BIT(9) -+#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10) -+unsigned int tdls_testing = 0; -+#endif /* CONFIG_TDLS_TESTING */ -+ -+#define TPK_LIFETIME 43200 /* 12 hours */ -+#define TPK_RETRY_COUNT 3 -+#define TPK_TIMEOUT 5000 /* in milliseconds */ -+ -+#define TDLS_MIC_LEN 16 -+ -+#define TDLS_TIMEOUT_LEN 4 -+ -+struct wpa_tdls_ftie { -+ u8 ie_type; /* FTIE */ -+ u8 ie_len; -+ u8 mic_ctrl[2]; -+ u8 mic[TDLS_MIC_LEN]; -+ u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ -+ u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */ -+ /* followed by optional elements */ -+} STRUCT_PACKED; -+ -+struct wpa_tdls_timeoutie { -+ u8 ie_type; /* Timeout IE */ -+ u8 ie_len; -+ u8 interval_type; -+ u8 value[TDLS_TIMEOUT_LEN]; -+} STRUCT_PACKED; -+ -+struct wpa_tdls_lnkid { -+ u8 ie_type; /* Link Identifier IE */ -+ u8 ie_len; -+ u8 bssid[ETH_ALEN]; -+ u8 init_sta[ETH_ALEN]; -+ u8 resp_sta[ETH_ALEN]; -+} STRUCT_PACKED; -+ -+/* TDLS frame headers as per IEEE Std 802.11z-2010 */ -+struct wpa_tdls_frame { -+ u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */ -+ u8 category; /* Category */ -+ u8 action; /* Action (enum tdls_frame_type) */ -+} STRUCT_PACKED; -+ -+static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs); -+static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx); -+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer); -+ -+ -+#define TDLS_MAX_IE_LEN 80 -+struct wpa_tdls_peer { -+ struct wpa_tdls_peer *next; -+ int initiator; /* whether this end was initiator for TDLS setup */ -+ u8 addr[ETH_ALEN]; /* other end MAC address */ -+ u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */ -+ u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */ -+ u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */ -+ size_t rsnie_i_len; -+ u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */ -+ size_t rsnie_p_len; -+ u32 lifetime; -+ int cipher; /* Selected cipher (WPA_CIPHER_*) */ -+ u8 dtoken; -+ -+ struct tpk { -+ u8 kck[16]; /* TPK-KCK */ -+ u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */ -+ } tpk; -+ int tpk_set; -+ int tpk_success; -+ -+ struct tpk_timer { -+ u8 dest[ETH_ALEN]; -+ int count; /* Retry Count */ -+ int timer; /* Timeout in milliseconds */ -+ u8 action_code; /* TDLS frame type */ -+ u8 dialog_token; -+ u16 status_code; -+ int buf_len; /* length of TPK message for retransmission */ -+ u8 *buf; /* buffer for TPK message */ -+ } sm_tmr; -+}; -+ -+ -+static int wpa_tdls_get_privacy(struct wpa_sm *sm) -+{ -+ /* -+ * Get info needed from supplicant to check if the current BSS supports -+ * security. Other than OPEN mode, rest are considered secured -+ * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake. -+ */ -+ return sm->pairwise_cipher != WPA_CIPHER_NONE; -+} -+ -+ -+static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) -+{ -+ os_memcpy(pos, ie, ie_len); -+ return pos + ie_len; -+} -+ -+ -+static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -+{ -+ if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, -+ 0, 0, NULL, 0, NULL, 0) < 0) { -+ wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " -+ "the driver"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -+{ -+ u8 key_len; -+ u8 rsc[6]; -+ enum wpa_alg alg; -+ -+ os_memset(rsc, 0, 6); -+ -+ switch (peer->cipher) { -+ case WPA_CIPHER_CCMP: -+ alg = WPA_ALG_CCMP; -+ key_len = 16; -+ break; -+ case WPA_CIPHER_NONE: -+ wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: " -+ "NONE - do not use pairwise keys"); -+ return -1; -+ default: -+ wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d", -+ sm->pairwise_cipher); -+ return -1; -+ } -+ -+ if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, -+ rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { -+ wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " -+ "driver"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, -+ u8 action_code, u8 dialog_token, -+ u16 status_code, const u8 *buf, size_t len) -+{ -+ return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, -+ status_code, buf, len); -+} -+ -+ -+static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, -+ u8 dialog_token, u16 status_code, -+ const u8 *msg, size_t msg_len) -+{ -+ struct wpa_tdls_peer *peer; -+ -+ wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u " -+ "dialog_token=%u status_code=%u msg_len=%u", -+ MAC2STR(dest), action_code, dialog_token, status_code, -+ (unsigned int) msg_len); -+ -+ if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, -+ status_code, msg, msg_len)) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to send message " -+ "(action_code=%u)", action_code); -+ return -1; -+ } -+ -+ if (action_code == WLAN_TDLS_SETUP_CONFIRM || -+ action_code == WLAN_TDLS_TEARDOWN) -+ return 0; /* No retries */ -+ -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0) -+ break; -+ } -+ -+ if (peer == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No matching entry found for " -+ "retry " MACSTR, MAC2STR(dest)); -+ return 0; -+ } -+ -+ eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); -+ -+ peer->sm_tmr.count = TPK_RETRY_COUNT; -+ peer->sm_tmr.timer = TPK_TIMEOUT; -+ -+ /* Copy message to resend on timeout */ -+ os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN); -+ peer->sm_tmr.action_code = action_code; -+ peer->sm_tmr.dialog_token = dialog_token; -+ peer->sm_tmr.status_code = status_code; -+ peer->sm_tmr.buf_len = msg_len; -+ os_free(peer->sm_tmr.buf); -+ peer->sm_tmr.buf = os_malloc(msg_len); -+ if (peer->sm_tmr.buf == NULL) -+ return -1; -+ os_memcpy(peer->sm_tmr.buf, msg, msg_len); -+ -+ wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered " -+ "(action_code=%u)", action_code); -+ eloop_register_timeout(peer->sm_tmr.timer / 1000, 0, -+ wpa_tdls_tpk_retry_timeout, sm, peer); -+ return 0; -+} -+ -+ -+static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ -+ struct wpa_sm *sm = eloop_ctx; -+ struct wpa_tdls_peer *peer = timeout_ctx; -+ -+ if (peer->sm_tmr.count) { -+ peer->sm_tmr.count--; -+ peer->sm_tmr.timer = TPK_TIMEOUT; -+ -+ wpa_printf(MSG_INFO, "TDLS: Retrying sending of message " -+ "(action_code=%u)", -+ peer->sm_tmr.action_code); -+ -+ if (peer->sm_tmr.buf == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No retry buffer available " -+ "for action_code=%u", -+ peer->sm_tmr.action_code); -+ eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, -+ peer); -+ return; -+ } -+ -+ /* resend TPK Handshake Message to Peer */ -+ if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest, -+ peer->sm_tmr.action_code, -+ peer->sm_tmr.dialog_token, -+ peer->sm_tmr.status_code, -+ peer->sm_tmr.buf, -+ peer->sm_tmr.buf_len)) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to retry " -+ "transmission"); -+ } -+ -+ eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); -+ eloop_register_timeout(peer->sm_tmr.timer / 1000, 0, -+ wpa_tdls_tpk_retry_timeout, sm, peer); -+ } else { -+ wpa_printf(MSG_INFO, "Sending Tear_Down Request"); -+ wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); -+ -+ wpa_printf(MSG_INFO, "Clearing SM: Peerkey(" MACSTR ")", -+ MAC2STR(peer->addr)); -+ eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); -+ -+ /* clear the Peerkey statemachine */ -+ wpa_tdls_peer_free(sm, peer); -+ } -+} -+ -+ -+static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm, -+ struct wpa_tdls_peer *peer, -+ u8 action_code) -+{ -+ if (action_code == peer->sm_tmr.action_code) { -+ wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for " -+ "action_code=%u", action_code); -+ -+ /* Cancel Timeout registered */ -+ eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); -+ -+ /* free all resources meant for retry */ -+ os_free(peer->sm_tmr.buf); -+ peer->sm_tmr.buf = NULL; -+ -+ peer->sm_tmr.count = 0; -+ peer->sm_tmr.timer = 0; -+ peer->sm_tmr.buf_len = 0; -+ peer->sm_tmr.action_code = 0xff; -+ } else { -+ wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout " -+ "(Unknown action_code=%u)", action_code); -+ } -+} -+ -+ -+static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer, -+ const u8 *own_addr, const u8 *bssid) -+{ -+ u8 key_input[SHA256_MAC_LEN]; -+ const u8 *nonce[2]; -+ size_t len[2]; -+ u8 data[3 * ETH_ALEN]; -+ -+ /* IEEE Std 802.11z-2010 8.5.9.1: -+ * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) -+ */ -+ len[0] = WPA_NONCE_LEN; -+ len[1] = WPA_NONCE_LEN; -+ if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) { -+ nonce[0] = peer->inonce; -+ nonce[1] = peer->rnonce; -+ } else { -+ nonce[0] = peer->rnonce; -+ nonce[1] = peer->inonce; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN); -+ sha256_vector(2, nonce, len, key_input); -+ wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input", -+ key_input, SHA256_MAC_LEN); -+ -+ /* -+ * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", -+ * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) -+ * TODO: is N_KEY really included in KDF Context and if so, in which -+ * presentation format (little endian 16-bit?) is it used? It gets -+ * added by the KDF anyway.. -+ */ -+ -+ if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) { -+ os_memcpy(data, own_addr, ETH_ALEN); -+ os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN); -+ } else { -+ os_memcpy(data, peer->addr, ETH_ALEN); -+ os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN); -+ } -+ os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN); -+ wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data)); -+ -+ sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), -+ (u8 *) &peer->tpk, sizeof(peer->tpk)); -+ wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK", -+ peer->tpk.kck, sizeof(peer->tpk.kck)); -+ wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK", -+ peer->tpk.tk, sizeof(peer->tpk.tk)); -+ peer->tpk_set = 1; -+} -+ -+ -+/** -+ * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC -+ * @kck: TPK-KCK -+ * @lnkid: Pointer to the beginning of Link Identifier IE -+ * @rsnie: Pointer to the beginning of RSN IE used for handshake -+ * @timeoutie: Pointer to the beginning of Timeout IE used for handshake -+ * @ftie: Pointer to the beginning of FT IE -+ * @mic: Pointer for writing MIC -+ * -+ * Calculate MIC for TDLS frame. -+ */ -+static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, -+ const u8 *rsnie, const u8 *timeoutie, -+ const u8 *ftie, u8 *mic) -+{ -+ u8 *buf, *pos; -+ struct wpa_tdls_ftie *_ftie; -+ const struct wpa_tdls_lnkid *_lnkid; -+ int ret; -+ int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + -+ 2 + timeoutie[1] + 2 + ftie[1]; -+ buf = os_zalloc(len); -+ if (!buf) { -+ wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); -+ return -1; -+ } -+ -+ pos = buf; -+ _lnkid = (const struct wpa_tdls_lnkid *) lnkid; -+ /* 1) TDLS initiator STA MAC address */ -+ os_memcpy(pos, _lnkid->init_sta, ETH_ALEN); -+ pos += ETH_ALEN; -+ /* 2) TDLS responder STA MAC address */ -+ os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); -+ pos += ETH_ALEN; -+ /* 3) Transaction Sequence number */ -+ *pos++ = trans_seq; -+ /* 4) Link Identifier IE */ -+ os_memcpy(pos, lnkid, 2 + lnkid[1]); -+ pos += 2 + lnkid[1]; -+ /* 5) RSN IE */ -+ os_memcpy(pos, rsnie, 2 + rsnie[1]); -+ pos += 2 + rsnie[1]; -+ /* 6) Timeout Interval IE */ -+ os_memcpy(pos, timeoutie, 2 + timeoutie[1]); -+ pos += 2 + timeoutie[1]; -+ /* 7) FTIE, with the MIC field of the FTIE set to 0 */ -+ os_memcpy(pos, ftie, 2 + ftie[1]); -+ _ftie = (struct wpa_tdls_ftie *) pos; -+ os_memset(_ftie->mic, 0, TDLS_MIC_LEN); -+ pos += 2 + ftie[1]; -+ -+ wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); -+ wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); -+ ret = omac1_aes_128(kck, buf, pos - buf, mic); -+ os_free(buf); -+ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); -+ return ret; -+} -+ -+ -+/** -+ * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame -+ * @kck: TPK-KCK -+ * @trans_seq: Transaction Sequence Number (4 - Teardown) -+ * @rcode: Reason code for Teardown -+ * @dtoken: Dialog Token used for that particular link -+ * @lnkid: Pointer to the beginning of Link Identifier IE -+ * @ftie: Pointer to the beginning of FT IE -+ * @mic: Pointer for writing MIC -+ * -+ * Calculate MIC for TDLS frame. -+ */ -+static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, -+ u8 dtoken, const u8 *lnkid, -+ const u8 *ftie, u8 *mic) -+{ -+ u8 *buf, *pos; -+ struct wpa_tdls_ftie *_ftie; -+ int ret; -+ int len; -+ -+ if (lnkid == NULL) -+ return -1; -+ -+ len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) + -+ sizeof(trans_seq) + 2 + ftie[1]; -+ -+ buf = os_zalloc(len); -+ if (!buf) { -+ wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); -+ return -1; -+ } -+ -+ pos = buf; -+ /* 1) Link Identifier IE */ -+ os_memcpy(pos, lnkid, 2 + lnkid[1]); -+ pos += 2 + lnkid[1]; -+ /* 2) Reason Code */ -+ WPA_PUT_LE16(pos, rcode); -+ pos += sizeof(rcode); -+ /* 3) Dialog token */ -+ *pos++ = dtoken; -+ /* 4) Transaction Sequence number */ -+ *pos++ = trans_seq; -+ /* 7) FTIE, with the MIC field of the FTIE set to 0 */ -+ os_memcpy(pos, ftie, 2 + ftie[1]); -+ _ftie = (struct wpa_tdls_ftie *) pos; -+ os_memset(_ftie->mic, 0, TDLS_MIC_LEN); -+ pos += 2 + ftie[1]; -+ -+ wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); -+ wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); -+ ret = omac1_aes_128(kck, buf, pos - buf, mic); -+ os_free(buf); -+ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); -+ return ret; -+} -+ -+ -+static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, -+ struct wpa_tdls_peer *peer, -+ const u8 *lnkid, const u8 *timeoutie, -+ const struct wpa_tdls_ftie *ftie) -+{ -+ u8 mic[16]; -+ -+ if (peer->tpk_set) { -+ wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, -+ peer->rsnie_p, timeoutie, (u8 *) ftie, -+ mic); -+ if (os_memcmp(mic, ftie->mic, 16) != 0) { -+ wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - " -+ "dropping packet"); -+ wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC", -+ ftie->mic, 16); -+ wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC", -+ mic, 16); -+ return -1; -+ } -+ } else { -+ wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, " -+ "TPK not set - dropping packet"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int wpa_supplicant_verify_tdls_mic_teardown( -+ u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer, -+ const u8 *lnkid, const struct wpa_tdls_ftie *ftie) -+{ -+ u8 mic[16]; -+ -+ if (peer->tpk_set) { -+ wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, -+ dtoken, lnkid, (u8 *) ftie, mic); -+ if (os_memcmp(mic, ftie->mic, 16) != 0) { -+ wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " -+ "dropping packet"); -+ return -1; -+ } -+ } else { -+ wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown " -+ "MIC, TPK not set - dropping packet"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_sm *sm = eloop_ctx; -+ struct wpa_tdls_peer *peer = timeout_ctx; -+ -+ /* -+ * On TPK lifetime expiration, we have an option of either tearing down -+ * the direct link or trying to re-initiate it. The selection of what -+ * to do is not strictly speaking controlled by our role in the expired -+ * link, but for now, use that to select whether to renew or tear down -+ * the link. -+ */ -+ -+ if (peer->initiator) { -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR -+ " - try to renew", MAC2STR(peer->addr)); -+ wpa_tdls_start(sm, peer->addr); -+ } else { -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR -+ " - tear down", MAC2STR(peer->addr)); -+ wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); -+ } -+} -+ -+ -+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -+{ -+ wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR, -+ MAC2STR(peer->addr)); -+ eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); -+ eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); -+ peer->initiator = 0; -+ os_free(peer->sm_tmr.buf); -+ peer->sm_tmr.buf = NULL; -+ peer->rsnie_i_len = peer->rsnie_p_len = 0; -+ peer->cipher = 0; -+ peer->tpk_set = peer->tpk_success = 0; -+ os_memset(&peer->tpk, 0, sizeof(peer->tpk)); -+ os_memset(peer->inonce, 0, WPA_NONCE_LEN); -+ os_memset(peer->rnonce, 0, WPA_NONCE_LEN); -+} -+ -+ -+static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, -+ struct wpa_tdls_lnkid *lnkid) -+{ -+ lnkid->ie_type = WLAN_EID_LINK_ID; -+ lnkid->ie_len = 3 * ETH_ALEN; -+ os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN); -+ if (peer->initiator) { -+ os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN); -+ os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN); -+ } else { -+ os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN); -+ os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN); -+ } -+} -+ -+ -+int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, -+ u16 reason_code) -+{ -+ struct wpa_tdls_peer *peer; -+ struct wpa_tdls_ftie *ftie; -+ struct wpa_tdls_lnkid lnkid; -+ u8 dialog_token; -+ u8 *rbuf, *pos; -+ int ielen; -+ -+ if (sm->tdls_disabled) -+ return -1; -+ -+ /* Find the node and free from the list */ -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) -+ break; -+ } -+ -+ if (peer == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No matching entry found for " -+ "Teardown " MACSTR, MAC2STR(addr)); -+ return 0; -+ } -+ -+ dialog_token = peer->dtoken; -+ -+ wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR, -+ MAC2STR(addr)); -+ -+ ielen = 0; -+ if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) { -+ /* To add FTIE for Teardown request and compute MIC */ -+ ielen += sizeof(*ftie); -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_LONG_FRAME) -+ ielen += 170; -+#endif /* CONFIG_TDLS_TESTING */ -+ } -+ -+ rbuf = os_zalloc(ielen + 1); -+ if (rbuf == NULL) -+ return -1; -+ pos = rbuf; -+ -+ if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) -+ goto skip_ies; -+ -+ ftie = (struct wpa_tdls_ftie *) pos; -+ ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; -+ /* Using the recent nonce which should be for CONFIRM frame */ -+ os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); -+ os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); -+ ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; -+ pos = (u8 *) (ftie + 1); -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_LONG_FRAME) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " -+ "FTIE"); -+ ftie->ie_len += 170; -+ *pos++ = 255; /* FTIE subelem */ -+ *pos++ = 168; /* FTIE subelem length */ -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake", -+ (u8 *) ftie, sizeof(*ftie)); -+ -+ /* compute MIC before sending */ -+ wpa_tdls_linkid(sm, peer, &lnkid); -+ wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code, -+ dialog_token, (u8 *) &lnkid, (u8 *) ftie, -+ ftie->mic); -+ -+skip_ies: -+ /* TODO: register for a Timeout handler, if Teardown is not received at -+ * the other end, then try again another time */ -+ -+ /* request driver to send Teardown using this FTIE */ -+ wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, -+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf, -+ pos - rbuf); -+ os_free(rbuf); -+ -+ /* clear the Peerkey statemachine */ -+ wpa_tdls_peer_free(sm, peer); -+ -+ return 0; -+} -+ -+ -+static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct wpa_tdls_peer *peer = NULL; -+ struct wpa_tdls_ftie *ftie; -+ struct wpa_tdls_lnkid *lnkid; -+ struct wpa_eapol_ie_parse kde; -+ u16 reason_code; -+ const u8 *pos; -+ int ielen; -+ -+ /* Find the node and free from the list */ -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ } -+ -+ if (peer == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No matching entry found for " -+ "Teardown " MACSTR, MAC2STR(src_addr)); -+ return 0; -+ } -+ -+ pos = buf; -+ pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; -+ -+ reason_code = WPA_GET_LE16(pos); -+ pos += 2; -+ -+ wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR -+ " (reason code %u)", MAC2STR(src_addr), reason_code); -+ -+ ielen = len - (pos - buf); /* start of IE in buf */ -+ if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown"); -+ return -1; -+ } -+ -+ if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { -+ wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS " -+ "Teardown"); -+ return -1; -+ } -+ lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; -+ -+ if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) -+ goto skip_ftie; -+ -+ if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { -+ wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown"); -+ return -1; -+ } -+ -+ ftie = (struct wpa_tdls_ftie *) kde.ftie; -+ -+ /* Process MIC check to see if TDLS Teardown is right */ -+ if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code, -+ peer->dtoken, peer, -+ (u8 *) lnkid, ftie) < 0) { -+ wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS " -+ "Teardown Request from " MACSTR, MAC2STR(src_addr)); -+ return -1; -+ } -+ -+skip_ftie: -+ /* -+ * Request the driver to disable the direct link and clear associated -+ * keys. -+ */ -+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); -+ -+ /* clear the Peerkey statemachine */ -+ wpa_tdls_peer_free(sm, peer); -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_tdls_send_error - To send suitable TDLS status response with -+ * appropriate status code mentioning reason for error/failure. -+ * @dst - MAC addr of Peer station -+ * @tdls_action - TDLS frame type for which error code is sent -+ * @status - status code mentioning reason -+ */ -+ -+static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, -+ u8 tdls_action, u8 dialog_token, u16 status) -+{ -+ wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR -+ " (action=%u status=%u)", -+ MAC2STR(dst), tdls_action, status); -+ return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, -+ NULL, 0); -+} -+ -+ -+static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm, -+ struct wpa_tdls_peer *peer) -+{ -+ size_t buf_len; -+ struct wpa_tdls_timeoutie timeoutie; -+ u16 rsn_capab; -+ struct wpa_tdls_ftie *ftie; -+ u8 *rbuf, *pos, *count_pos; -+ u16 count; -+ struct rsn_ie_hdr *hdr; -+ -+ if (!wpa_tdls_get_privacy(sm)) { -+ wpa_printf(MSG_DEBUG, "TDLS: No security used on the link"); -+ peer->rsnie_i_len = 0; -+ goto skip_rsnie; -+ } -+ -+ /* -+ * TPK Handshake Message 1: -+ * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I, -+ * Timeout Interval IE)) -+ */ -+ -+ /* Filling RSN IE */ -+ hdr = (struct rsn_ie_hdr *) peer->rsnie_i; -+ hdr->elem_id = WLAN_EID_RSN; -+ WPA_PUT_LE16(hdr->version, RSN_VERSION); -+ -+ pos = (u8 *) (hdr + 1); -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); -+ pos += RSN_SELECTOR_LEN; -+ count_pos = pos; -+ pos += 2; -+ -+ count = 0; -+ -+ /* -+ * AES-CCMP is the default Encryption preferred for TDLS, so -+ * RSN IE is filled only with CCMP CIPHER -+ * Note: TKIP is not used to encrypt TDLS link. -+ * -+ * Regardless of the cipher used on the AP connection, select CCMP -+ * here. -+ */ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ pos += RSN_SELECTOR_LEN; -+ count++; -+ -+ WPA_PUT_LE16(count_pos, count); -+ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); -+ pos += RSN_SELECTOR_LEN; -+ -+ rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; -+ rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { -+ wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for " -+ "testing"); -+ rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ WPA_PUT_LE16(pos, rsn_capab); -+ pos += 2; -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { -+ /* Number of PMKIDs */ -+ *pos++ = 0x00; -+ *pos++ = 0x00; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ hdr->len = (pos - peer->rsnie_i) - 2; -+ peer->rsnie_i_len = pos - peer->rsnie_i; -+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", -+ peer->rsnie_i, peer->rsnie_i_len); -+ -+skip_rsnie: -+ buf_len = 0; -+ if (wpa_tdls_get_privacy(sm)) -+ buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + -+ sizeof(struct wpa_tdls_timeoutie); -+#ifdef CONFIG_TDLS_TESTING -+ if (wpa_tdls_get_privacy(sm) && -+ (tdls_testing & TDLS_TESTING_LONG_FRAME)) -+ buf_len += 170; -+ if (tdls_testing & TDLS_TESTING_DIFF_BSSID) -+ buf_len += sizeof(struct wpa_tdls_lnkid); -+#endif /* CONFIG_TDLS_TESTING */ -+ rbuf = os_zalloc(buf_len + 1); -+ if (rbuf == NULL) { -+ wpa_tdls_peer_free(sm, peer); -+ return -1; -+ } -+ pos = rbuf; -+ -+ if (!wpa_tdls_get_privacy(sm)) -+ goto skip_ies; -+ -+ /* Initiator RSN IE */ -+ pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); -+ -+ ftie = (struct wpa_tdls_ftie *) pos; -+ ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; -+ ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; -+ -+ if (os_get_random(peer->inonce, WPA_NONCE_LEN)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "TDLS: Failed to get random data for initiator Nonce"); -+ os_free(rbuf); -+ wpa_tdls_peer_free(sm, peer); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", -+ peer->inonce, WPA_NONCE_LEN); -+ os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); -+ -+ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1", -+ (u8 *) ftie, sizeof(struct wpa_tdls_ftie)); -+ -+ pos = (u8 *) (ftie + 1); -+ -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_LONG_FRAME) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " -+ "FTIE"); -+ ftie->ie_len += 170; -+ *pos++ = 255; /* FTIE subelem */ -+ *pos++ = 168; /* FTIE subelem length */ -+ pos += 168; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ /* Lifetime */ -+ peer->lifetime = TPK_LIFETIME; -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK " -+ "lifetime"); -+ peer->lifetime = 301; -+ } -+ if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK " -+ "lifetime"); -+ peer->lifetime = 0xffffffff; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, -+ sizeof(timeoutie), peer->lifetime); -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); -+ -+skip_ies: -+ -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_DIFF_BSSID) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in " -+ "Link Identifier"); -+ struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos; -+ wpa_tdls_linkid(sm, peer, l); -+ l->bssid[5] ^= 0x01; -+ pos += sizeof(*l); -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK " -+ "Handshake Message 1 (peer " MACSTR ")", -+ MAC2STR(peer->addr)); -+ -+ wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 0, 0, -+ rbuf, pos - rbuf); -+ os_free(rbuf); -+ -+ return 0; -+} -+ -+ -+static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, -+ const unsigned char *src_addr, u8 dtoken, -+ struct wpa_tdls_lnkid *lnkid, -+ const struct wpa_tdls_peer *peer) -+{ -+ u8 *rbuf, *pos; -+ size_t buf_len; -+ u32 lifetime; -+ struct wpa_tdls_timeoutie timeoutie; -+ struct wpa_tdls_ftie *ftie; -+ -+ buf_len = 0; -+ if (wpa_tdls_get_privacy(sm)) { -+ /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), -+ * Lifetime */ -+ buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + -+ sizeof(struct wpa_tdls_timeoutie); -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_LONG_FRAME) -+ buf_len += 170; -+#endif /* CONFIG_TDLS_TESTING */ -+ } -+ -+ rbuf = os_zalloc(buf_len + 1); -+ if (rbuf == NULL) -+ return -1; -+ pos = rbuf; -+ -+ if (!wpa_tdls_get_privacy(sm)) -+ goto skip_ies; -+ -+ /* Peer RSN IE */ -+ pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); -+ -+ ftie = (struct wpa_tdls_ftie *) pos; -+ ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; -+ /* TODO: ftie->mic_control to set 2-RESPONSE */ -+ os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); -+ os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); -+ ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; -+ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2", -+ (u8 *) ftie, sizeof(*ftie)); -+ -+ pos = (u8 *) (ftie + 1); -+ -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_LONG_FRAME) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " -+ "FTIE"); -+ ftie->ie_len += 170; -+ *pos++ = 255; /* FTIE subelem */ -+ *pos++ = 168; /* FTIE subelem length */ -+ pos += 168; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ /* Lifetime */ -+ lifetime = peer->lifetime; -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " -+ "lifetime in response"); -+ lifetime++; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, -+ sizeof(timeoutie), lifetime); -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator", -+ lifetime); -+ -+ /* compute MIC before sending */ -+ wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p, -+ (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); -+ -+skip_ies: -+ wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0, -+ rbuf, pos - rbuf); -+ os_free(rbuf); -+ -+ return 0; -+} -+ -+ -+static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, -+ const unsigned char *src_addr, u8 dtoken, -+ struct wpa_tdls_lnkid *lnkid, -+ const struct wpa_tdls_peer *peer) -+{ -+ u8 *rbuf, *pos; -+ size_t buf_len; -+ struct wpa_tdls_ftie *ftie; -+ struct wpa_tdls_timeoutie timeoutie; -+ u32 lifetime; -+ -+ buf_len = 0; -+ if (wpa_tdls_get_privacy(sm)) { -+ /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), -+ * Lifetime */ -+ buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + -+ sizeof(struct wpa_tdls_timeoutie); -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_LONG_FRAME) -+ buf_len += 170; -+#endif /* CONFIG_TDLS_TESTING */ -+ } -+ -+ rbuf = os_zalloc(buf_len + 1); -+ if (rbuf == NULL) -+ return -1; -+ pos = rbuf; -+ -+ if (!wpa_tdls_get_privacy(sm)) -+ goto skip_ies; -+ -+ /* Peer RSN IE */ -+ pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); -+ -+ ftie = (struct wpa_tdls_ftie *) pos; -+ ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; -+ /*TODO: ftie->mic_control to set 3-CONFIRM */ -+ os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); -+ os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); -+ ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; -+ -+ pos = (u8 *) (ftie + 1); -+ -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_LONG_FRAME) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " -+ "FTIE"); -+ ftie->ie_len += 170; -+ *pos++ = 255; /* FTIE subelem */ -+ *pos++ = 168; /* FTIE subelem length */ -+ pos += 168; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ /* Lifetime */ -+ lifetime = peer->lifetime; -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " -+ "lifetime in confirm"); -+ lifetime++; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, -+ sizeof(timeoutie), lifetime); -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", -+ lifetime); -+ -+ /* compute MIC before sending */ -+ wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p, -+ (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); -+ -+skip_ies: -+ wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0, -+ rbuf, pos - rbuf); -+ os_free(rbuf); -+ -+ return 0; -+} -+ -+ -+static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct wpa_tdls_peer *peer; -+ struct wpa_eapol_ie_parse kde; -+ struct wpa_ie_data ie; -+ int cipher; -+ const u8 *cpos; -+ struct wpa_tdls_ftie *ftie = NULL; -+ struct wpa_tdls_timeoutie *timeoutie; -+ struct wpa_tdls_lnkid *lnkid; -+ u32 lifetime = 0; -+#if 0 -+ struct rsn_ie_hdr *hdr; -+ u8 *pos; -+ u16 rsn_capab; -+ u16 rsn_ver; -+#endif -+ u8 dtoken; -+ u16 ielen; -+ u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; -+ int tdls_prohibited = sm->tdls_prohibited; -+ -+ if (len < 3 + 3) -+ return -1; -+ -+ cpos = buf; -+ cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; -+ -+ /* driver had already verified the frame format */ -+ dtoken = *cpos++; /* dialog token */ -+ -+ wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken); -+ -+ cpos += 2; /* capability information */ -+ -+ ielen = len - (cpos - buf); /* start of IE in buf */ -+ if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1"); -+ goto error; -+ } -+ -+ if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { -+ wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " -+ "TPK M1"); -+ goto error; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1", -+ kde.lnkid, kde.lnkid_len); -+ lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; -+ if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { -+ wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS"); -+ status = WLAN_STATUS_NOT_IN_SAME_BSS; -+ goto error; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR, -+ MAC2STR(src_addr)); -+ -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ } -+ if (peer == NULL) { -+ peer = os_zalloc(sizeof(*peer)); -+ if (peer == NULL) -+ goto error; -+ os_memcpy(peer->addr, src_addr, ETH_ALEN); -+ peer->next = sm->tdls; -+ sm->tdls = peer; -+ } -+ wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of " -+ "TDLS setup - send own request"); -+ peer->initiator = 1; -+ wpa_tdls_send_tpk_m1(sm, peer); -+ } -+ -+ if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && -+ tdls_prohibited) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " -+ "on TDLS"); -+ tdls_prohibited = 0; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ if (tdls_prohibited) { -+ wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS"); -+ status = WLAN_STATUS_REQUEST_DECLINED; -+ goto error; -+ } -+ -+ if (!wpa_tdls_get_privacy(sm)) { -+ if (kde.rsn_ie) { -+ wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while " -+ "security is disabled"); -+ status = WLAN_STATUS_SECURITY_DISABLED; -+ goto error; -+ } -+ goto skip_rsn; -+ } -+ -+ if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || -+ kde.rsn_ie == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1"); -+ status = WLAN_STATUS_INVALID_PARAMETERS; -+ goto error; -+ } -+ -+ if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { -+ wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in " -+ "TPK M1"); -+ status = WLAN_STATUS_INVALID_RSNIE; -+ goto error; -+ } -+ -+ if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1"); -+ status = WLAN_STATUS_INVALID_RSNIE; -+ goto error; -+ } -+ -+ cipher = ie.pairwise_cipher; -+ if (cipher & WPA_CIPHER_CCMP) { -+ wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); -+ cipher = WPA_CIPHER_CCMP; -+ } else { -+ wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1"); -+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; -+ goto error; -+ } -+ -+ if ((ie.capabilities & -+ (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) != -+ WPA_CAPABILITY_PEERKEY_ENABLED) { -+ wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in " -+ "TPK M1"); -+ status = WLAN_STATUS_INVALID_RSN_IE_CAPAB; -+ goto error; -+ } -+ -+ /* Lifetime */ -+ if (kde.key_lifetime == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1"); -+ status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; -+ goto error; -+ } -+ timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; -+ lifetime = WPA_GET_LE32(timeoutie->value); -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime); -+ if (lifetime < 300) { -+ wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime"); -+ status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; -+ goto error; -+ } -+ -+skip_rsn: -+ /* Find existing entry and if found, use that instead of adding -+ * a new one; how to handle the case where both ends initiate at the -+ * same time? */ -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ } -+ -+ if (peer == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No matching entry found for " -+ "peer, creating one for " MACSTR, -+ MAC2STR(src_addr)); -+ peer = os_malloc(sizeof(*peer)); -+ if (peer == NULL) -+ goto error; -+ os_memset(peer, 0, sizeof(*peer)); -+ os_memcpy(peer->addr, src_addr, ETH_ALEN); -+ peer->next = sm->tdls; -+ sm->tdls = peer; -+ } else { -+ if (peer->tpk_success) { -+ wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while " -+ "direct link is enabled - tear down the " -+ "old link first"); -+#if 0 -+ /* TODO: Disabling the link would be more proper -+ * operation here, but it seems to trigger a race with -+ * some drivers handling the new request frame. */ -+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); -+#else -+ wpa_tdls_del_key(sm, peer); -+#endif -+ wpa_tdls_peer_free(sm, peer); -+ } -+ -+ /* -+ * An entry is already present, so check if we already sent a -+ * TDLS Setup Request. If so, compare MAC addresses and let the -+ * STA with the lower MAC address continue as the initiator. -+ * The other negotiation is terminated. -+ */ -+ if (peer->initiator) { -+ if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) { -+ wpa_printf(MSG_DEBUG, "TDLS: Discard request " -+ "from peer with higher address " -+ MACSTR, MAC2STR(src_addr)); -+ return -1; -+ } else { -+ wpa_printf(MSG_DEBUG, "TDLS: Accept request " -+ "from peer with lower address " -+ MACSTR " (terminate previously " -+ "initiated negotiation", -+ MAC2STR(src_addr)); -+ wpa_tdls_peer_free(sm, peer); -+ } -+ } -+ } -+ -+ peer->initiator = 0; /* Need to check */ -+ peer->dtoken = dtoken; -+ -+ if (!wpa_tdls_get_privacy(sm)) { -+ peer->rsnie_i_len = 0; -+ peer->rsnie_p_len = 0; -+ peer->cipher = WPA_CIPHER_NONE; -+ goto skip_rsn_check; -+ } -+ -+ ftie = (struct wpa_tdls_ftie *) kde.ftie; -+ os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN); -+ os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); -+ peer->rsnie_i_len = kde.rsn_ie_len; -+ peer->cipher = cipher; -+ -+ if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) { -+ wpa_msg(sm->ctx->ctx, MSG_WARNING, -+ "TDLS: Failed to get random data for responder nonce"); -+ wpa_tdls_peer_free(sm, peer); -+ goto error; -+ } -+ -+#if 0 -+ /* get version info from RSNIE received from Peer */ -+ hdr = (struct rsn_ie_hdr *) kde.rsn_ie; -+ rsn_ver = WPA_GET_LE16(hdr->version); -+ -+ /* use min(peer's version, out version) */ -+ if (rsn_ver > RSN_VERSION) -+ rsn_ver = RSN_VERSION; -+ -+ hdr = (struct rsn_ie_hdr *) peer->rsnie_p; -+ -+ hdr->elem_id = WLAN_EID_RSN; -+ WPA_PUT_LE16(hdr->version, rsn_ver); -+ pos = (u8 *) (hdr + 1); -+ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); -+ pos += RSN_SELECTOR_LEN; -+ /* Include only the selected cipher in pairwise cipher suite */ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ if (cipher == WPA_CIPHER_CCMP) -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ pos += RSN_SELECTOR_LEN; -+ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); -+ pos += RSN_SELECTOR_LEN; -+ -+ rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; -+ rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; -+ WPA_PUT_LE16(pos, rsn_capab); -+ pos += 2; -+ -+ hdr->len = (pos - peer->rsnie_p) - 2; -+ peer->rsnie_p_len = pos - peer->rsnie_p; -+#endif -+ -+ /* temp fix: validation of RSNIE later */ -+ os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len); -+ peer->rsnie_p_len = peer->rsnie_i_len; -+ -+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", -+ peer->rsnie_p, peer->rsnie_p_len); -+ -+ peer->lifetime = lifetime; -+ -+ wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); -+ -+skip_rsn_check: -+ wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); -+ wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer); -+ -+ return 0; -+ -+error: -+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, -+ status); -+ return -1; -+} -+ -+ -+static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -+{ -+ peer->tpk_success = 1; -+ eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); -+ if (wpa_tdls_get_privacy(sm)) { -+ u32 lifetime = peer->lifetime; -+ /* -+ * Start the initiator process a bit earlier to avoid race -+ * condition with the responder sending teardown request. -+ */ -+ if (lifetime > 3 && peer->initiator) -+ lifetime -= 3; -+ eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout, -+ sm, peer); -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK " -+ "expiration"); -+ eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ } -+ wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr); -+} -+ -+ -+static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct wpa_tdls_peer *peer; -+ struct wpa_eapol_ie_parse kde; -+ struct wpa_ie_data ie; -+ int cipher; -+ struct wpa_tdls_ftie *ftie; -+ struct wpa_tdls_timeoutie *timeoutie; -+ struct wpa_tdls_lnkid *lnkid; -+ u32 lifetime; -+ u8 dtoken; -+ int ielen; -+ u16 status; -+ const u8 *pos; -+ -+ wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 " -+ "(Peer " MACSTR ")", MAC2STR(src_addr)); -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ } -+ if (peer == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No matching peer found for " -+ "TPK M2: " MACSTR, MAC2STR(src_addr)); -+ return -1; -+ } -+ wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST); -+ -+ if (len < 3 + 2 + 1) -+ return -1; -+ pos = buf; -+ pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; -+ status = WPA_GET_LE16(pos); -+ pos += 2 /* status code */; -+ -+ if (status != WLAN_STATUS_SUCCESS) { -+ wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u", -+ status); -+ return -1; -+ } -+ -+ status = WLAN_STATUS_UNSPECIFIED_FAILURE; -+ -+ /* TODO: need to verify dialog token matches here or in kernel */ -+ dtoken = *pos++; /* dialog token */ -+ -+ wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken); -+ -+ if (len < 3 + 2 + 1 + 2) -+ return -1; -+ pos += 2; /* capability information */ -+ -+ ielen = len - (pos - buf); /* start of IE in buf */ -+ if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2"); -+ goto error; -+ } -+ -+#ifdef CONFIG_TDLS_TESTING -+ if (tdls_testing & TDLS_TESTING_DECLINE_RESP) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response"); -+ status = WLAN_STATUS_REQUEST_DECLINED; -+ goto error; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { -+ wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " -+ "TPK M2"); -+ goto error; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2", -+ kde.lnkid, kde.lnkid_len); -+ lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; -+ -+ if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { -+ wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS"); -+ status = WLAN_STATUS_NOT_IN_SAME_BSS; -+ goto error; -+ } -+ -+ if (!wpa_tdls_get_privacy(sm)) { -+ peer->rsnie_p_len = 0; -+ peer->cipher = WPA_CIPHER_NONE; -+ goto skip_rsn; -+ } -+ -+ if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || -+ kde.rsn_ie == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2"); -+ status = WLAN_STATUS_INVALID_PARAMETERS; -+ goto error; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", -+ kde.rsn_ie, kde.rsn_ie_len); -+ -+ /* -+ * FIX: bitwise comparison of RSN IE is not the correct way of -+ * validation this. It can be different, but certain fields must -+ * match. Since we list only a single pairwise cipher in TPK M1, the -+ * memcmp is likely to work in most cases, though. -+ */ -+ if (kde.rsn_ie_len != peer->rsnie_i_len || -+ os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) { -+ wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does " -+ "not match with RSN IE used in TPK M1"); -+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1", -+ peer->rsnie_i, peer->rsnie_i_len); -+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", -+ kde.rsn_ie, kde.rsn_ie_len); -+ status = WLAN_STATUS_INVALID_RSNIE; -+ goto error; -+ } -+ -+ if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2"); -+ status = WLAN_STATUS_INVALID_RSNIE; -+ goto error; -+ } -+ -+ cipher = ie.pairwise_cipher; -+ if (cipher == WPA_CIPHER_CCMP) { -+ wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); -+ cipher = WPA_CIPHER_CCMP; -+ } else { -+ wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2"); -+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; -+ goto error; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2", -+ kde.ftie, sizeof(*ftie)); -+ ftie = (struct wpa_tdls_ftie *) kde.ftie; -+ -+ if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { -+ wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does " -+ "not match with FTIE SNonce used in TPK M1"); -+ /* Silently discard the frame */ -+ return -1; -+ } -+ -+ /* Responder Nonce and RSN IE */ -+ os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN); -+ os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len); -+ peer->rsnie_p_len = kde.rsn_ie_len; -+ peer->cipher = cipher; -+ -+ /* Lifetime */ -+ if (kde.key_lifetime == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2"); -+ status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; -+ goto error; -+ } -+ timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; -+ lifetime = WPA_GET_LE32(timeoutie->value); -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2", -+ lifetime); -+ if (lifetime != peer->lifetime) { -+ wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " -+ "TPK M2 (expected %u)", lifetime, peer->lifetime); -+ status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; -+ goto error; -+ } -+ -+ wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); -+ -+ /* Process MIC check to see if TPK M2 is right */ -+ if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid, -+ (u8 *) timeoutie, ftie) < 0) { -+ /* Discard the frame */ -+ wpa_tdls_del_key(sm, peer); -+ wpa_tdls_peer_free(sm, peer); -+ return -1; -+ } -+ -+ wpa_tdls_set_key(sm, peer); -+ -+skip_rsn: -+ peer->dtoken = dtoken; -+ -+ wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / " -+ "TPK Handshake Message 3"); -+ wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer); -+ -+ wpa_tdls_enable_link(sm, peer); -+ -+ return 0; -+ -+error: -+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, -+ status); -+ return -1; -+} -+ -+ -+static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct wpa_tdls_peer *peer; -+ struct wpa_eapol_ie_parse kde; -+ struct wpa_tdls_ftie *ftie; -+ struct wpa_tdls_timeoutie *timeoutie; -+ struct wpa_tdls_lnkid *lnkid; -+ int ielen; -+ u16 status; -+ const u8 *pos; -+ u32 lifetime; -+ -+ wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 " -+ "(Peer " MACSTR ")", MAC2STR(src_addr)); -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ } -+ if (peer == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No matching peer found for " -+ "TPK M3: " MACSTR, MAC2STR(src_addr)); -+ return -1; -+ } -+ wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE); -+ -+ if (len < 3 + 3) -+ return -1; -+ pos = buf; -+ pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; -+ -+ status = WPA_GET_LE16(pos); -+ -+ if (status != 0) { -+ wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u", -+ status); -+ return -1; -+ } -+ pos += 2 /* status code */ + 1 /* dialog token */; -+ -+ ielen = len - (pos - buf); /* start of IE in buf */ -+ if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { -+ wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3"); -+ return -1; -+ } -+ -+ if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { -+ wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3"); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3", -+ (u8 *) kde.lnkid, kde.lnkid_len); -+ lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; -+ -+ if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { -+ wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS"); -+ return -1; -+ } -+ -+ if (!wpa_tdls_get_privacy(sm)) -+ goto skip_rsn; -+ -+ if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { -+ wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3"); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3", -+ kde.ftie, sizeof(*ftie)); -+ ftie = (struct wpa_tdls_ftie *) kde.ftie; -+ -+ if (kde.rsn_ie == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3"); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3", -+ kde.rsn_ie, kde.rsn_ie_len); -+ if (kde.rsn_ie_len != peer->rsnie_p_len || -+ os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) { -+ wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match " -+ "with the one sent in TPK M2"); -+ return -1; -+ } -+ -+ if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) { -+ wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does " -+ "not match with FTIE ANonce used in TPK M2"); -+ return -1; -+ } -+ -+ if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { -+ wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not " -+ "match with FTIE SNonce used in TPK M1"); -+ return -1; -+ } -+ -+ if (kde.key_lifetime == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3"); -+ return -1; -+ } -+ timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; -+ wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3", -+ (u8 *) timeoutie, sizeof(*timeoutie)); -+ lifetime = WPA_GET_LE32(timeoutie->value); -+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3", -+ lifetime); -+ if (lifetime != peer->lifetime) { -+ wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " -+ "TPK M3 (expected %u)", lifetime, peer->lifetime); -+ return -1; -+ } -+ -+ if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid, -+ (u8 *) timeoutie, ftie) < 0) { -+ wpa_tdls_del_key(sm, peer); -+ wpa_tdls_peer_free(sm, peer); -+ return -1; -+ } -+ -+ if (wpa_tdls_set_key(sm, peer) < 0) -+ return -1; -+ -+skip_rsn: -+ wpa_tdls_enable_link(sm, peer); -+ -+ return 0; -+} -+ -+ -+static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs) -+{ -+ struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie; -+ -+ os_memset(lifetime, 0, ie_len); -+ lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL; -+ lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2; -+ lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME; -+ WPA_PUT_LE32(lifetime->value, tsecs); -+ os_memcpy(pos, ie, ie_len); -+ return pos + ie_len; -+} -+ -+ -+/** -+ * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1) -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @peer: MAC address of the peer STA -+ * Returns: 0 on success, or -1 on failure -+ * -+ * Send TPK Handshake Message 1 info to driver to start TDLS -+ * handshake with the peer. -+ */ -+int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) -+{ -+ struct wpa_tdls_peer *peer; -+ int tdls_prohibited = sm->tdls_prohibited; -+ -+ if (sm->tdls_disabled) -+ return -1; -+ -+#ifdef CONFIG_TDLS_TESTING -+ if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && -+ tdls_prohibited) { -+ wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " -+ "on TDLS"); -+ tdls_prohibited = 0; -+ } -+#endif /* CONFIG_TDLS_TESTING */ -+ -+ if (tdls_prohibited) { -+ wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - " -+ "reject request to start setup"); -+ return -1; -+ } -+ -+ /* Find existing entry and if found, use that instead of adding -+ * a new one */ -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) -+ break; -+ } -+ -+ if (peer == NULL) { -+ wpa_printf(MSG_INFO, "TDLS: No matching entry found for " -+ "peer, creating one for " MACSTR, MAC2STR(addr)); -+ peer = os_malloc(sizeof(*peer)); -+ if (peer == NULL) -+ return -1; -+ os_memset(peer, 0, sizeof(*peer)); -+ os_memcpy(peer->addr, addr, ETH_ALEN); -+ peer->next = sm->tdls; -+ sm->tdls = peer; -+ } -+ -+ peer->initiator = 1; -+ -+ return wpa_tdls_send_tpk_m1(sm, peer); -+} -+ -+ -+int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr) -+{ -+ struct wpa_tdls_peer *peer; -+ -+ if (sm->tdls_disabled) -+ return -1; -+ -+ for (peer = sm->tdls; peer; peer = peer->next) { -+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) -+ break; -+ } -+ -+ if (peer == NULL || !peer->tpk_success) -+ return -1; -+ -+ return wpa_tdls_start(sm, addr); -+} -+ -+ -+/** -+ * wpa_supplicant_rx_tdls - Receive TDLS data frame -+ * -+ * This function is called to receive TDLS (ethertype = 0x890d) data frames. -+ */ -+static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ struct wpa_sm *sm = ctx; -+ struct wpa_tdls_frame *tf; -+ -+ wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", -+ buf, len); -+ -+ if (sm->tdls_disabled) { -+ wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled"); -+ return; -+ } -+ -+ if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) { -+ wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message"); -+ return; -+ } -+ -+ if (len < sizeof(*tf)) { -+ wpa_printf(MSG_INFO, "TDLS: Drop too short frame"); -+ return; -+ } -+ -+ /* Check to make sure its a valid encapsulated TDLS frame */ -+ tf = (struct wpa_tdls_frame *) buf; -+ if (tf->payloadtype != 2 /* TDLS_RFTYPE */ || -+ tf->category != WLAN_ACTION_TDLS) { -+ wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u " -+ "category=%u action=%u", -+ tf->payloadtype, tf->category, tf->action); -+ return; -+ } -+ -+ switch (tf->action) { -+ case WLAN_TDLS_SETUP_REQUEST: -+ wpa_tdls_process_tpk_m1(sm, src_addr, buf, len); -+ break; -+ case WLAN_TDLS_SETUP_RESPONSE: -+ wpa_tdls_process_tpk_m2(sm, src_addr, buf, len); -+ break; -+ case WLAN_TDLS_SETUP_CONFIRM: -+ wpa_tdls_process_tpk_m3(sm, src_addr, buf, len); -+ break; -+ case WLAN_TDLS_TEARDOWN: -+ wpa_tdls_recv_teardown(sm, src_addr, buf, len); -+ break; -+ default: -+ /* Kernel code will process remaining frames */ -+ wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u", -+ tf->action); -+ break; -+ } -+} -+ -+ -+/** -+ * wpa_tdls_init - Initialize driver interface parameters for TDLS -+ * @wpa_s: Pointer to wpa_supplicant data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is called to initialize driver interface parameters for TDLS. -+ * wpa_drv_init() must have been called before this function to initialize the -+ * driver interface. -+ */ -+int wpa_tdls_init(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return -1; -+ -+ sm->l2_tdls = l2_packet_init(sm->ifname, sm->own_addr, -+ ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls, -+ sm, 0); -+ if (sm->l2_tdls == NULL) { -+ wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet " -+ "connection"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static void wpa_tdls_remove_peers(struct wpa_sm *sm) -+{ -+ struct wpa_tdls_peer *peer, *tmp; -+ -+ peer = sm->tdls; -+ sm->tdls = NULL; -+ -+ while (peer) { -+ int res; -+ tmp = peer->next; -+ res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); -+ wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)", -+ MAC2STR(peer->addr), res); -+ wpa_tdls_peer_free(sm, peer); -+ os_free(peer); -+ peer = tmp; -+ } -+} -+ -+ -+/** -+ * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS -+ * -+ * This function is called to recover driver interface parameters for TDLS -+ * and frees resources allocated for it. -+ */ -+void wpa_tdls_deinit(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ -+ if (sm->l2_tdls) -+ l2_packet_deinit(sm->l2_tdls); -+ sm->l2_tdls = NULL; -+ -+ wpa_tdls_remove_peers(sm); -+} -+ -+ -+void wpa_tdls_assoc(struct wpa_sm *sm) -+{ -+ wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association"); -+ wpa_tdls_remove_peers(sm); -+} -+ -+ -+void wpa_tdls_disassoc(struct wpa_sm *sm) -+{ -+ wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation"); -+ wpa_tdls_remove_peers(sm); -+} -+ -+ -+static int wpa_tdls_prohibited(const u8 *ies, size_t len) -+{ -+ struct wpa_eapol_ie_parse elems; -+ -+ if (ies == NULL) -+ return 0; -+ -+ if (wpa_supplicant_parse_ies(ies, len, &elems) < 0) -+ return 0; -+ -+ if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) -+ return 0; -+ -+ /* bit 38 - TDLS Prohibited */ -+ return !!(elems.ext_capab[2 + 4] & 0x40); -+} -+ -+ -+void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len) -+{ -+ sm->tdls_prohibited = wpa_tdls_prohibited(ies, len); -+ wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS", -+ sm->tdls_prohibited ? "prohibited" : "allowed"); -+} -+ -+ -+void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len) -+{ -+ if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) { -+ wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on " -+ "(Re)Association Response IEs"); -+ sm->tdls_prohibited = 1; -+ } -+} -+ -+ -+void wpa_tdls_enable(struct wpa_sm *sm, int enabled) -+{ -+ wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled"); -+ sm->tdls_disabled = !enabled; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.c -new file mode 100644 -index 0000000000000..01a46dc9a95f2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.c -@@ -0,0 +1,2644 @@ -+/* -+ * WPA Supplicant - WPA state machine and EAPOL-Key processing -+ * Copyright (c) 2003-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/crypto.h" -+#include "crypto/random.h" -+#include "common/ieee802_11_defs.h" -+#include "eapol_supp/eapol_supp_sm.h" -+#include "wpa.h" -+#include "eloop.h" -+#include "preauth.h" -+#include "pmksa_cache.h" -+#include "wpa_i.h" -+#include "wpa_ie.h" -+#include "peerkey.h" -+ -+ -+/** -+ * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @kck: Key Confirmation Key (KCK, part of PTK) -+ * @ver: Version field from Key Info -+ * @dest: Destination address for the frame -+ * @proto: Ethertype (usually ETH_P_EAPOL) -+ * @msg: EAPOL-Key message -+ * @msg_len: Length of message -+ * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written -+ */ -+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, -+ int ver, const u8 *dest, u16 proto, -+ u8 *msg, size_t msg_len, u8 *key_mic) -+{ -+ if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { -+ /* -+ * Association event was not yet received; try to fetch -+ * BSSID from the driver. -+ */ -+ if (wpa_sm_get_bssid(sm, sm->bssid) < 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: Failed to read BSSID for " -+ "EAPOL-Key destination address"); -+ } else { -+ dest = sm->bssid; -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: Use BSSID (" MACSTR -+ ") as the destination for EAPOL-Key", -+ MAC2STR(dest)); -+ } -+ } -+ if (key_mic && -+ wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, -+ "WPA: Failed to generate EAPOL-Key " -+ "version %d MIC", ver); -+ goto out; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16); -+ wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16); -+ wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len); -+ wpa_sm_ether_send(sm, dest, proto, msg, msg_len); -+ eapol_sm_notify_tx_eapol_key(sm->eapol); -+out: -+ os_free(msg); -+} -+ -+ -+/** -+ * wpa_sm_key_request - Send EAPOL-Key Request -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @error: Indicate whether this is an Michael MIC error report -+ * @pairwise: 1 = error report for pairwise packet, 0 = for group packet -+ * -+ * Send an EAPOL-Key Request to the current authenticator. This function is -+ * used to request rekeying and it is usually called when a local Michael MIC -+ * failure is detected. -+ */ -+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) -+{ -+ size_t rlen; -+ struct wpa_eapol_key *reply; -+ int key_info, ver; -+ u8 bssid[ETH_ALEN], *rbuf; -+ -+ if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt)) -+ ver = WPA_KEY_INFO_TYPE_AES_128_CMAC; -+ else if (sm->pairwise_cipher == WPA_CIPHER_CCMP) -+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; -+ else -+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; -+ -+ if (wpa_sm_get_bssid(sm, bssid) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "Failed to read BSSID for EAPOL-Key request"); -+ return; -+ } -+ -+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, -+ sizeof(*reply), &rlen, (void *) &reply); -+ if (rbuf == NULL) -+ return; -+ -+ reply->type = sm->proto == WPA_PROTO_RSN ? -+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; -+ key_info = WPA_KEY_INFO_REQUEST | ver; -+ if (sm->ptk_set) -+ key_info |= WPA_KEY_INFO_MIC; -+ if (error) -+ key_info |= WPA_KEY_INFO_ERROR; -+ if (pairwise) -+ key_info |= WPA_KEY_INFO_KEY_TYPE; -+ WPA_PUT_BE16(reply->key_info, key_info); -+ WPA_PUT_BE16(reply->key_length, 0); -+ os_memcpy(reply->replay_counter, sm->request_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); -+ -+ WPA_PUT_BE16(reply->key_data_length, 0); -+ -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: Sending EAPOL-Key Request (error=%d " -+ "pairwise=%d ptk_set=%d len=%lu)", -+ error, pairwise, sm->ptk_set, (unsigned long) rlen); -+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, -+ rbuf, rlen, key_info & WPA_KEY_INFO_MIC ? -+ reply->key_mic : NULL); -+} -+ -+ -+static int wpa_supplicant_get_pmk(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ const u8 *pmkid) -+{ -+ int abort_cached = 0; -+ -+ if (pmkid && !sm->cur_pmksa) { -+ /* When using drivers that generate RSN IE, wpa_supplicant may -+ * not have enough time to get the association information -+ * event before receiving this 1/4 message, so try to find a -+ * matching PMKSA cache entry here. */ -+ sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid); -+ if (sm->cur_pmksa) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: found matching PMKID from PMKSA cache"); -+ } else { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: no matching PMKID found"); -+ abort_cached = 1; -+ } -+ } -+ -+ if (pmkid && sm->cur_pmksa && -+ os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) { -+ wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN); -+ wpa_sm_set_pmk_from_pmksa(sm); -+ wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache", -+ sm->pmk, sm->pmk_len); -+ eapol_sm_notify_cached(sm->eapol); -+#ifdef CONFIG_IEEE80211R -+ sm->xxkey_len = 0; -+#endif /* CONFIG_IEEE80211R */ -+ } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) { -+ int res, pmk_len; -+ pmk_len = PMK_LEN; -+ res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN); -+ if (res) { -+ /* -+ * EAP-LEAP is an exception from other EAP methods: it -+ * uses only 16-byte PMK. -+ */ -+ res = eapol_sm_get_key(sm->eapol, sm->pmk, 16); -+ pmk_len = 16; -+ } else { -+#ifdef CONFIG_IEEE80211R -+ u8 buf[2 * PMK_LEN]; -+ if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0) -+ { -+ os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN); -+ sm->xxkey_len = PMK_LEN; -+ os_memset(buf, 0, sizeof(buf)); -+ } -+#endif /* CONFIG_IEEE80211R */ -+ } -+ if (res == 0) { -+ wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state " -+ "machines", sm->pmk, pmk_len); -+ sm->pmk_len = pmk_len; -+ if (sm->proto == WPA_PROTO_RSN) { -+ pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, -+ src_addr, sm->own_addr, -+ sm->network_ctx, sm->key_mgmt); -+ } -+ if (!sm->cur_pmksa && pmkid && -+ pmksa_cache_get(sm->pmksa, src_addr, pmkid)) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: the new PMK matches with the " -+ "PMKID"); -+ abort_cached = 0; -+ } -+ } else { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to get master session key from " -+ "EAPOL state machines - key handshake " -+ "aborted"); -+ if (sm->cur_pmksa) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: Cancelled PMKSA caching " -+ "attempt"); -+ sm->cur_pmksa = NULL; -+ abort_cached = 1; -+ } else if (!abort_cached) { -+ return -1; -+ } -+ } -+ } -+ -+ if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) { -+ /* Send EAPOL-Start to trigger full EAP authentication. */ -+ u8 *buf; -+ size_t buflen; -+ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: no PMKSA entry found - trigger " -+ "full EAP authentication"); -+ buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START, -+ NULL, 0, &buflen, NULL); -+ if (buf) { -+ wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL, -+ buf, buflen); -+ os_free(buf); -+ return -2; -+ } -+ -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @dst: Destination address for the frame -+ * @key: Pointer to the EAPOL-Key frame header -+ * @ver: Version bits from EAPOL-Key Key Info -+ * @nonce: Nonce value for the EAPOL-Key frame -+ * @wpa_ie: WPA/RSN IE -+ * @wpa_ie_len: Length of the WPA/RSN IE -+ * @ptk: PTK to use for keyed hash and encryption -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, -+ const struct wpa_eapol_key *key, -+ int ver, const u8 *nonce, -+ const u8 *wpa_ie, size_t wpa_ie_len, -+ struct wpa_ptk *ptk) -+{ -+ size_t rlen; -+ struct wpa_eapol_key *reply; -+ u8 *rbuf; -+ u8 *rsn_ie_buf = NULL; -+ -+ if (wpa_ie == NULL) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - " -+ "cannot generate msg 2/4"); -+ return -1; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->key_mgmt)) { -+ int res; -+ -+ /* -+ * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and -+ * FTIE from (Re)Association Response. -+ */ -+ rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN + -+ sm->assoc_resp_ies_len); -+ if (rsn_ie_buf == NULL) -+ return -1; -+ os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); -+ res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len, -+ sm->pmk_r1_name); -+ if (res < 0) { -+ os_free(rsn_ie_buf); -+ return -1; -+ } -+ wpa_ie_len += res; -+ -+ if (sm->assoc_resp_ies) { -+ os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies, -+ sm->assoc_resp_ies_len); -+ wpa_ie_len += sm->assoc_resp_ies_len; -+ } -+ -+ wpa_ie = rsn_ie_buf; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); -+ -+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, -+ NULL, sizeof(*reply) + wpa_ie_len, -+ &rlen, (void *) &reply); -+ if (rbuf == NULL) { -+ os_free(rsn_ie_buf); -+ return -1; -+ } -+ -+ reply->type = sm->proto == WPA_PROTO_RSN ? -+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; -+ WPA_PUT_BE16(reply->key_info, -+ ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC); -+ if (sm->proto == WPA_PROTO_RSN) -+ WPA_PUT_BE16(reply->key_length, 0); -+ else -+ os_memcpy(reply->key_length, key->key_length, 2); -+ os_memcpy(reply->replay_counter, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ -+ WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); -+ os_memcpy(reply + 1, wpa_ie, wpa_ie_len); -+ os_free(rsn_ie_buf); -+ -+ os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); -+ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4"); -+ wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, -+ rbuf, rlen, reply->key_mic); -+ -+ return 0; -+} -+ -+ -+static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, -+ struct wpa_ptk *ptk) -+{ -+ size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64; -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->key_mgmt)) -+ return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len); -+#endif /* CONFIG_IEEE80211R */ -+ -+ wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", -+ sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, -+ (u8 *) ptk, ptk_len, -+ wpa_key_mgmt_sha256(sm->key_mgmt)); -+ return 0; -+} -+ -+ -+static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, -+ u16 ver) -+{ -+ struct wpa_eapol_ie_parse ie; -+ struct wpa_ptk *ptk; -+ u8 buf[8]; -+ int res; -+ -+ if (wpa_sm_get_network_ctx(sm) == NULL) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info " -+ "found (msg 1 of 4)"); -+ return; -+ } -+ -+ wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way " -+ "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); -+ -+ os_memset(&ie, 0, sizeof(ie)); -+ -+#ifndef CONFIG_NO_WPA2 -+ if (sm->proto == WPA_PROTO_RSN) { -+ /* RSN: msg 1/4 should contain PMKID for the selected PMK */ -+ const u8 *_buf = (const u8 *) (key + 1); -+ size_t len = WPA_GET_BE16(key->key_data_length); -+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len); -+ wpa_supplicant_parse_ies(_buf, len, &ie); -+ if (ie.pmkid) { -+ wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " -+ "Authenticator", ie.pmkid, PMKID_LEN); -+ } -+ } -+#endif /* CONFIG_NO_WPA2 */ -+ -+ res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid); -+ if (res == -2) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to " -+ "msg 1/4 - requesting full EAP authentication"); -+ return; -+ } -+ if (res) -+ goto failed; -+ -+ if (sm->renew_snonce) { -+ if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to get random data for SNonce"); -+ goto failed; -+ } -+ sm->renew_snonce = 0; -+ wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", -+ sm->snonce, WPA_NONCE_LEN); -+ } -+ -+ /* Calculate PTK which will be stored as a temporary PTK until it has -+ * been verified when processing message 3/4. */ -+ ptk = &sm->tptk; -+ wpa_derive_ptk(sm, src_addr, key, ptk); -+ /* Supplicant: swap tx/rx Mic keys */ -+ os_memcpy(buf, ptk->u.auth.tx_mic_key, 8); -+ os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8); -+ os_memcpy(ptk->u.auth.rx_mic_key, buf, 8); -+ sm->tptk_set = 1; -+ -+ if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, -+ sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, -+ ptk)) -+ goto failed; -+ -+ os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN); -+ return; -+ -+failed: -+ wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -+} -+ -+ -+static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_sm *sm = eloop_ctx; -+ rsn_preauth_candidate_process(sm); -+} -+ -+ -+static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm, -+ const u8 *addr, int secure) -+{ -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: Key negotiation completed with " -+ MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr), -+ wpa_cipher_txt(sm->pairwise_cipher), -+ wpa_cipher_txt(sm->group_cipher)); -+ wpa_sm_cancel_auth_timeout(sm); -+ wpa_sm_set_state(sm, WPA_COMPLETED); -+ -+ if (secure) { -+ wpa_sm_mlme_setprotection( -+ sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX, -+ MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); -+ eapol_sm_notify_portValid(sm->eapol, TRUE); -+ if (wpa_key_mgmt_wpa_psk(sm->key_mgmt)) -+ eapol_sm_notify_eap_success(sm->eapol, TRUE); -+ /* -+ * Start preauthentication after a short wait to avoid a -+ * possible race condition between the data receive and key -+ * configuration after the 4-Way Handshake. This increases the -+ * likelyhood of the first preauth EAPOL-Start frame getting to -+ * the target AP. -+ */ -+ eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL); -+ } -+ -+ if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: Authenticator accepted " -+ "opportunistic PMKSA entry - marking it valid"); -+ sm->cur_pmksa->opportunistic = 0; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->key_mgmt)) { -+ /* Prepare for the next transition */ -+ wpa_ft_prepare_auth_request(sm, NULL); -+ } -+#endif /* CONFIG_IEEE80211R */ -+} -+ -+ -+static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx) -+{ -+ struct wpa_sm *sm = eloop_ctx; -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Request PTK rekeying"); -+ wpa_sm_key_request(sm, 0, 1); -+} -+ -+ -+static int wpa_supplicant_install_ptk(struct wpa_sm *sm, -+ const struct wpa_eapol_key *key) -+{ -+ int keylen, rsclen; -+ enum wpa_alg alg; -+ const u8 *key_rsc; -+ u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -+ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: Installing PTK to the driver"); -+ -+ switch (sm->pairwise_cipher) { -+ case WPA_CIPHER_CCMP: -+ alg = WPA_ALG_CCMP; -+ keylen = 16; -+ rsclen = 6; -+ break; -+ case WPA_CIPHER_TKIP: -+ alg = WPA_ALG_TKIP; -+ keylen = 32; -+ rsclen = 6; -+ break; -+ case WPA_CIPHER_NONE: -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher " -+ "Suite: NONE - do not use pairwise keys"); -+ return 0; -+ default: -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Unsupported pairwise cipher %d", -+ sm->pairwise_cipher); -+ return -1; -+ } -+ -+ if (sm->proto == WPA_PROTO_RSN) { -+ key_rsc = null_rsc; -+ } else { -+ key_rsc = key->key_rsc; -+ wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen); -+ } -+ -+ if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen, -+ (u8 *) sm->ptk.tk1, keylen) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to set PTK to the " -+ "driver (alg=%d keylen=%d bssid=" MACSTR ")", -+ alg, keylen, MAC2STR(sm->bssid)); -+ return -1; -+ } -+ -+ if (sm->wpa_ptk_rekey) { -+ eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); -+ eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, -+ sm, NULL); -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm, -+ int group_cipher, -+ int keylen, int maxkeylen, -+ int *key_rsc_len, -+ enum wpa_alg *alg) -+{ -+ int ret = 0; -+ -+ switch (group_cipher) { -+ case WPA_CIPHER_CCMP: -+ if (keylen != 16 || maxkeylen < 16) { -+ ret = -1; -+ break; -+ } -+ *key_rsc_len = 6; -+ *alg = WPA_ALG_CCMP; -+ break; -+ case WPA_CIPHER_TKIP: -+ if (keylen != 32 || maxkeylen < 32) { -+ ret = -1; -+ break; -+ } -+ *key_rsc_len = 6; -+ *alg = WPA_ALG_TKIP; -+ break; -+ case WPA_CIPHER_WEP104: -+ if (keylen != 13 || maxkeylen < 13) { -+ ret = -1; -+ break; -+ } -+ *key_rsc_len = 0; -+ *alg = WPA_ALG_WEP; -+ break; -+ case WPA_CIPHER_WEP40: -+ if (keylen != 5 || maxkeylen < 5) { -+ ret = -1; -+ break; -+ } -+ *key_rsc_len = 0; -+ *alg = WPA_ALG_WEP; -+ break; -+ default: -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Unsupported Group Cipher %d", -+ group_cipher); -+ return -1; -+ } -+ -+ if (ret < 0 ) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Unsupported %s Group Cipher key length %d (%d)", -+ wpa_cipher_txt(group_cipher), keylen, maxkeylen); -+ } -+ -+ return ret; -+} -+ -+ -+struct wpa_gtk_data { -+ enum wpa_alg alg; -+ int tx, key_rsc_len, keyidx; -+ u8 gtk[32]; -+ int gtk_len; -+}; -+ -+ -+static int wpa_supplicant_install_gtk(struct wpa_sm *sm, -+ const struct wpa_gtk_data *gd, -+ const u8 *key_rsc) -+{ -+ const u8 *_gtk = gd->gtk; -+ u8 gtk_buf[32]; -+ -+ wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len); -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)", -+ gd->keyidx, gd->tx, gd->gtk_len); -+ wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len); -+ if (sm->group_cipher == WPA_CIPHER_TKIP) { -+ /* Swap Tx/Rx keys for Michael MIC */ -+ os_memcpy(gtk_buf, gd->gtk, 16); -+ os_memcpy(gtk_buf + 16, gd->gtk + 24, 8); -+ os_memcpy(gtk_buf + 24, gd->gtk + 16, 8); -+ _gtk = gtk_buf; -+ } -+ if (sm->pairwise_cipher == WPA_CIPHER_NONE) { -+ if (wpa_sm_set_key(sm, gd->alg, NULL, -+ gd->keyidx, 1, key_rsc, gd->key_rsc_len, -+ _gtk, gd->gtk_len) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to set GTK to the driver " -+ "(Group only)"); -+ return -1; -+ } -+ } else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr, -+ gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, -+ _gtk, gd->gtk_len) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to set GTK to " -+ "the driver (alg=%d keylen=%d keyidx=%d)", -+ gd->alg, gd->gtk_len, gd->keyidx); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, -+ int tx) -+{ -+ if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) { -+ /* Ignore Tx bit for GTK if a pairwise key is used. One AP -+ * seemed to set this bit (incorrectly, since Tx is only when -+ * doing Group Key only APs) and without this workaround, the -+ * data connection does not work because wpa_supplicant -+ * configured non-zero keyidx to be used for unicast. */ -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: Tx bit set for GTK, but pairwise " -+ "keys are used - ignore Tx bit"); -+ return 0; -+ } -+ return tx; -+} -+ -+ -+static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, -+ const struct wpa_eapol_key *key, -+ const u8 *gtk, size_t gtk_len, -+ int key_info) -+{ -+#ifndef CONFIG_NO_WPA2 -+ struct wpa_gtk_data gd; -+ -+ /* -+ * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x -+ * GTK KDE format: -+ * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7] -+ * Reserved [bits 0-7] -+ * GTK -+ */ -+ -+ os_memset(&gd, 0, sizeof(gd)); -+ wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake", -+ gtk, gtk_len); -+ -+ if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk)) -+ return -1; -+ -+ gd.keyidx = gtk[0] & 0x3; -+ gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm, -+ !!(gtk[0] & BIT(2))); -+ gtk += 2; -+ gtk_len -= 2; -+ -+ os_memcpy(gd.gtk, gtk, gtk_len); -+ gd.gtk_len = gtk_len; -+ -+ if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, -+ gtk_len, gtk_len, -+ &gd.key_rsc_len, &gd.alg) || -+ wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: Failed to install GTK"); -+ return -1; -+ } -+ -+ wpa_supplicant_key_neg_complete(sm, sm->bssid, -+ key_info & WPA_KEY_INFO_SECURE); -+ return 0; -+#else /* CONFIG_NO_WPA2 */ -+ return -1; -+#endif /* CONFIG_NO_WPA2 */ -+} -+ -+ -+static int ieee80211w_set_keys(struct wpa_sm *sm, -+ struct wpa_eapol_ie_parse *ie) -+{ -+#ifdef CONFIG_IEEE80211W -+ if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) -+ return 0; -+ -+ if (ie->igtk) { -+ const struct wpa_igtk_kde *igtk; -+ u16 keyidx; -+ if (ie->igtk_len != sizeof(*igtk)) -+ return -1; -+ igtk = (const struct wpa_igtk_kde *) ie->igtk; -+ keyidx = WPA_GET_LE16(igtk->keyid); -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d " -+ "pn %02x%02x%02x%02x%02x%02x", -+ keyidx, MAC2STR(igtk->pn)); -+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", -+ igtk->igtk, WPA_IGTK_LEN); -+ if (keyidx > 4095) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Invalid IGTK KeyID %d", keyidx); -+ return -1; -+ } -+ if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, -+ keyidx, 0, igtk->pn, sizeof(igtk->pn), -+ igtk->igtk, WPA_IGTK_LEN) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Failed to configure IGTK to the driver"); -+ return -1; -+ } -+ } -+ -+ return 0; -+#else /* CONFIG_IEEE80211W */ -+ return 0; -+#endif /* CONFIG_IEEE80211W */ -+} -+ -+ -+static void wpa_report_ie_mismatch(struct wpa_sm *sm, -+ const char *reason, const u8 *src_addr, -+ const u8 *wpa_ie, size_t wpa_ie_len, -+ const u8 *rsn_ie, size_t rsn_ie_len) -+{ -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")", -+ reason, MAC2STR(src_addr)); -+ -+ if (sm->ap_wpa_ie) { -+ wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp", -+ sm->ap_wpa_ie, sm->ap_wpa_ie_len); -+ } -+ if (wpa_ie) { -+ if (!sm->ap_wpa_ie) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: No WPA IE in Beacon/ProbeResp"); -+ } -+ wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg", -+ wpa_ie, wpa_ie_len); -+ } -+ -+ if (sm->ap_rsn_ie) { -+ wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp", -+ sm->ap_rsn_ie, sm->ap_rsn_ie_len); -+ } -+ if (rsn_ie) { -+ if (!sm->ap_rsn_ie) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: No RSN IE in Beacon/ProbeResp"); -+ } -+ wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg", -+ rsn_ie, rsn_ie_len); -+ } -+ -+ wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS); -+} -+ -+ -+#ifdef CONFIG_IEEE80211R -+ -+static int ft_validate_mdie(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ struct wpa_eapol_ie_parse *ie, -+ const u8 *assoc_resp_mdie) -+{ -+ struct rsn_mdie *mdie; -+ -+ mdie = (struct rsn_mdie *) (ie->mdie + 2); -+ if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) || -+ os_memcmp(mdie->mobility_domain, sm->mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE in msg 3/4 did " -+ "not match with the current mobility domain"); -+ return -1; -+ } -+ -+ if (assoc_resp_mdie && -+ (assoc_resp_mdie[1] != ie->mdie[1] || -+ os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE mismatch"); -+ wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4", -+ ie->mdie, 2 + ie->mdie[1]); -+ wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response", -+ assoc_resp_mdie, 2 + assoc_resp_mdie[1]); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int ft_validate_ftie(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ struct wpa_eapol_ie_parse *ie, -+ const u8 *assoc_resp_ftie) -+{ -+ if (ie->ftie == NULL) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "FT: No FTIE in EAPOL-Key msg 3/4"); -+ return -1; -+ } -+ -+ if (assoc_resp_ftie == NULL) -+ return 0; -+ -+ if (assoc_resp_ftie[1] != ie->ftie[1] || -+ os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: FTIE mismatch"); -+ wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4", -+ ie->ftie, 2 + ie->ftie[1]); -+ wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response", -+ assoc_resp_ftie, 2 + assoc_resp_ftie[1]); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int ft_validate_rsnie(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ struct wpa_eapol_ie_parse *ie) -+{ -+ struct wpa_ie_data rsn; -+ -+ if (!ie->rsn_ie) -+ return 0; -+ -+ /* -+ * Verify that PMKR1Name from EAPOL-Key message 3/4 -+ * matches with the value we derived. -+ */ -+ if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 || -+ rsn.num_pmkid != 1 || rsn.pmkid == NULL) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: No PMKR1Name in " -+ "FT 4-way handshake message 3/4"); -+ return -1; -+ } -+ -+ if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "FT: PMKR1Name mismatch in " -+ "FT 4-way handshake message 3/4"); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator", -+ rsn.pmkid, WPA_PMK_NAME_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", -+ sm->pmk_r1_name, WPA_PMK_NAME_LEN); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ struct wpa_eapol_ie_parse *ie) -+{ -+ const u8 *pos, *end, *mdie = NULL, *ftie = NULL; -+ -+ if (sm->assoc_resp_ies) { -+ pos = sm->assoc_resp_ies; -+ end = pos + sm->assoc_resp_ies_len; -+ while (pos + 2 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ switch (*pos) { -+ case WLAN_EID_MOBILITY_DOMAIN: -+ mdie = pos; -+ break; -+ case WLAN_EID_FAST_BSS_TRANSITION: -+ ftie = pos; -+ break; -+ } -+ pos += 2 + pos[1]; -+ } -+ } -+ -+ if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 || -+ ft_validate_ftie(sm, src_addr, ie, ftie) < 0 || -+ ft_validate_rsnie(sm, src_addr, ie) < 0) -+ return -1; -+ -+ return 0; -+} -+ -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+static int wpa_supplicant_validate_ie(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ struct wpa_eapol_ie_parse *ie) -+{ -+ if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: No WPA/RSN IE for this AP known. " -+ "Trying to get from scan results"); -+ if (wpa_sm_get_beacon_ie(sm) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Could not find AP from " -+ "the scan results"); -+ } else { -+ wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: Found the current AP from " -+ "updated scan results"); -+ } -+ } -+ -+ if (ie->wpa_ie == NULL && ie->rsn_ie == NULL && -+ (sm->ap_wpa_ie || sm->ap_rsn_ie)) { -+ wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " -+ "with IE in Beacon/ProbeResp (no IE?)", -+ src_addr, ie->wpa_ie, ie->wpa_ie_len, -+ ie->rsn_ie, ie->rsn_ie_len); -+ return -1; -+ } -+ -+ if ((ie->wpa_ie && sm->ap_wpa_ie && -+ (ie->wpa_ie_len != sm->ap_wpa_ie_len || -+ os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) || -+ (ie->rsn_ie && sm->ap_rsn_ie && -+ wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt), -+ sm->ap_rsn_ie, sm->ap_rsn_ie_len, -+ ie->rsn_ie, ie->rsn_ie_len))) { -+ wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match " -+ "with IE in Beacon/ProbeResp", -+ src_addr, ie->wpa_ie, ie->wpa_ie_len, -+ ie->rsn_ie, ie->rsn_ie_len); -+ return -1; -+ } -+ -+ if (sm->proto == WPA_PROTO_WPA && -+ ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) { -+ wpa_report_ie_mismatch(sm, "Possible downgrade attack " -+ "detected - RSN was enabled and RSN IE " -+ "was in msg 3/4, but not in " -+ "Beacon/ProbeResp", -+ src_addr, ie->wpa_ie, ie->wpa_ie_len, -+ ie->rsn_ie, ie->rsn_ie_len); -+ return -1; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->key_mgmt) && -+ wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0) -+ return -1; -+#endif /* CONFIG_IEEE80211R */ -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @dst: Destination address for the frame -+ * @key: Pointer to the EAPOL-Key frame header -+ * @ver: Version bits from EAPOL-Key Key Info -+ * @key_info: Key Info -+ * @kde: KDEs to include the EAPOL-Key frame -+ * @kde_len: Length of KDEs -+ * @ptk: PTK to use for keyed hash and encryption -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, -+ const struct wpa_eapol_key *key, -+ u16 ver, u16 key_info, -+ const u8 *kde, size_t kde_len, -+ struct wpa_ptk *ptk) -+{ -+ size_t rlen; -+ struct wpa_eapol_key *reply; -+ u8 *rbuf; -+ -+ if (kde) -+ wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len); -+ -+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, -+ sizeof(*reply) + kde_len, -+ &rlen, (void *) &reply); -+ if (rbuf == NULL) -+ return -1; -+ -+ reply->type = sm->proto == WPA_PROTO_RSN ? -+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; -+ key_info &= WPA_KEY_INFO_SECURE; -+ key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC; -+ WPA_PUT_BE16(reply->key_info, key_info); -+ if (sm->proto == WPA_PROTO_RSN) -+ WPA_PUT_BE16(reply->key_length, 0); -+ else -+ os_memcpy(reply->key_length, key->key_length, 2); -+ os_memcpy(reply->replay_counter, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ -+ WPA_PUT_BE16(reply->key_data_length, kde_len); -+ if (kde) -+ os_memcpy(reply + 1, kde, kde_len); -+ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); -+ wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, -+ rbuf, rlen, reply->key_mic); -+ -+ return 0; -+} -+ -+ -+static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, -+ const struct wpa_eapol_key *key, -+ u16 ver) -+{ -+ u16 key_info, keylen, len; -+ const u8 *pos; -+ struct wpa_eapol_ie_parse ie; -+ -+ wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way " -+ "Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver); -+ -+ key_info = WPA_GET_BE16(key->key_info); -+ -+ pos = (const u8 *) (key + 1); -+ len = WPA_GET_BE16(key->key_data_length); -+ wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len); -+ wpa_supplicant_parse_ies(pos, len, &ie); -+ if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: GTK IE in unencrypted key data"); -+ goto failed; -+ } -+#ifdef CONFIG_IEEE80211W -+ if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: IGTK KDE in unencrypted key data"); -+ goto failed; -+ } -+ -+ if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Invalid IGTK KDE length %lu", -+ (unsigned long) ie.igtk_len); -+ goto failed; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) -+ goto failed; -+ -+ if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: ANonce from message 1 of 4-Way Handshake " -+ "differs from 3 of 4-Way Handshake - drop packet (src=" -+ MACSTR ")", MAC2STR(sm->bssid)); -+ goto failed; -+ } -+ -+ keylen = WPA_GET_BE16(key->key_length); -+ switch (sm->pairwise_cipher) { -+ case WPA_CIPHER_CCMP: -+ if (keylen != 16) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Invalid CCMP key length %d (src=" MACSTR -+ ")", keylen, MAC2STR(sm->bssid)); -+ goto failed; -+ } -+ break; -+ case WPA_CIPHER_TKIP: -+ if (keylen != 32) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Invalid TKIP key length %d (src=" MACSTR -+ ")", keylen, MAC2STR(sm->bssid)); -+ goto failed; -+ } -+ break; -+ } -+ -+ if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, -+ NULL, 0, &sm->ptk)) { -+ goto failed; -+ } -+ -+ /* SNonce was successfully used in msg 3/4, so mark it to be renewed -+ * for the next 4-Way Handshake. If msg 3 is received again, the old -+ * SNonce will still be used to avoid changing PTK. */ -+ sm->renew_snonce = 1; -+ -+ if (key_info & WPA_KEY_INFO_INSTALL) { -+ if (wpa_supplicant_install_ptk(sm, key)) -+ goto failed; -+ } -+ -+ if (key_info & WPA_KEY_INFO_SECURE) { -+ wpa_sm_mlme_setprotection( -+ sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, -+ MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); -+ eapol_sm_notify_portValid(sm->eapol, TRUE); -+ } -+ wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); -+ -+ if (ie.gtk && -+ wpa_supplicant_pairwise_gtk(sm, key, -+ ie.gtk, ie.gtk_len, key_info) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "RSN: Failed to configure GTK"); -+ goto failed; -+ } -+ -+ if (ieee80211w_set_keys(sm, &ie) < 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "RSN: Failed to configure IGTK"); -+ goto failed; -+ } -+ -+ return; -+ -+failed: -+ wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -+} -+ -+ -+static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, -+ const u8 *keydata, -+ size_t keydatalen, -+ u16 key_info, -+ struct wpa_gtk_data *gd) -+{ -+ int maxkeylen; -+ struct wpa_eapol_ie_parse ie; -+ -+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen); -+ wpa_supplicant_parse_ies(keydata, keydatalen, &ie); -+ if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: GTK IE in unencrypted key data"); -+ return -1; -+ } -+ if (ie.gtk == NULL) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: No GTK IE in Group Key msg 1/2"); -+ return -1; -+ } -+ maxkeylen = gd->gtk_len = ie.gtk_len - 2; -+ -+ if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, -+ gd->gtk_len, maxkeylen, -+ &gd->key_rsc_len, &gd->alg)) -+ return -1; -+ -+ wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake", -+ ie.gtk, ie.gtk_len); -+ gd->keyidx = ie.gtk[0] & 0x3; -+ gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, -+ !!(ie.gtk[0] & BIT(2))); -+ if (ie.gtk_len - 2 > sizeof(gd->gtk)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "RSN: Too long GTK in GTK IE (len=%lu)", -+ (unsigned long) ie.gtk_len - 2); -+ return -1; -+ } -+ os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2); -+ -+ if (ieee80211w_set_keys(sm, &ie) < 0) -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "RSN: Failed to configure IGTK"); -+ -+ return 0; -+} -+ -+ -+static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, -+ const struct wpa_eapol_key *key, -+ size_t keydatalen, int key_info, -+ size_t extra_len, u16 ver, -+ struct wpa_gtk_data *gd) -+{ -+ size_t maxkeylen; -+ u8 ek[32]; -+ -+ gd->gtk_len = WPA_GET_BE16(key->key_length); -+ maxkeylen = keydatalen; -+ if (keydatalen > extra_len) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: Truncated EAPOL-Key packet: " -+ "key_data_length=%lu > extra_len=%lu", -+ (unsigned long) keydatalen, (unsigned long) extra_len); -+ return -1; -+ } -+ if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { -+ if (maxkeylen < 8) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: Too short maxkeylen (%lu)", -+ (unsigned long) maxkeylen); -+ return -1; -+ } -+ maxkeylen -= 8; -+ } -+ -+ if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, -+ gd->gtk_len, maxkeylen, -+ &gd->key_rsc_len, &gd->alg)) -+ return -1; -+ -+ gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> -+ WPA_KEY_INFO_KEY_INDEX_SHIFT; -+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { -+ os_memcpy(ek, key->key_iv, 16); -+ os_memcpy(ek + 16, sm->ptk.kek, 16); -+ if (keydatalen > sizeof(gd->gtk)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: RC4 key data too long (%lu)", -+ (unsigned long) keydatalen); -+ return -1; -+ } -+ os_memcpy(gd->gtk, key + 1, keydatalen); -+ if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, -+ "WPA: RC4 failed"); -+ return -1; -+ } -+ } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { -+ if (keydatalen % 8) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Unsupported AES-WRAP len %lu", -+ (unsigned long) keydatalen); -+ return -1; -+ } -+ if (maxkeylen > sizeof(gd->gtk)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: AES-WRAP key data " -+ "too long (keydatalen=%lu maxkeylen=%lu)", -+ (unsigned long) keydatalen, -+ (unsigned long) maxkeylen); -+ return -1; -+ } -+ if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, -+ (const u8 *) (key + 1), gd->gtk)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: AES unwrap failed - could not decrypt " -+ "GTK"); -+ return -1; -+ } -+ } else { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Unsupported key_info type %d", ver); -+ return -1; -+ } -+ gd->tx = wpa_supplicant_gtk_tx_bit_workaround( -+ sm, !!(key_info & WPA_KEY_INFO_TXRX)); -+ return 0; -+} -+ -+ -+static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, -+ const struct wpa_eapol_key *key, -+ int ver, u16 key_info) -+{ -+ size_t rlen; -+ struct wpa_eapol_key *reply; -+ u8 *rbuf; -+ -+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, -+ sizeof(*reply), &rlen, (void *) &reply); -+ if (rbuf == NULL) -+ return -1; -+ -+ reply->type = sm->proto == WPA_PROTO_RSN ? -+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; -+ key_info &= WPA_KEY_INFO_KEY_INDEX_MASK; -+ key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; -+ WPA_PUT_BE16(reply->key_info, key_info); -+ if (sm->proto == WPA_PROTO_RSN) -+ WPA_PUT_BE16(reply->key_length, 0); -+ else -+ os_memcpy(reply->key_length, key->key_length, 2); -+ os_memcpy(reply->replay_counter, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ -+ WPA_PUT_BE16(reply->key_data_length, 0); -+ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2"); -+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL, -+ rbuf, rlen, reply->key_mic); -+ -+ return 0; -+} -+ -+ -+static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, -+ const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, -+ int extra_len, u16 ver) -+{ -+ u16 key_info, keydatalen; -+ int rekey, ret; -+ struct wpa_gtk_data gd; -+ -+ os_memset(&gd, 0, sizeof(gd)); -+ -+ rekey = wpa_sm_get_state(sm) == WPA_COMPLETED; -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key " -+ "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); -+ -+ key_info = WPA_GET_BE16(key->key_info); -+ keydatalen = WPA_GET_BE16(key->key_data_length); -+ -+ if (sm->proto == WPA_PROTO_RSN) { -+ ret = wpa_supplicant_process_1_of_2_rsn(sm, -+ (const u8 *) (key + 1), -+ keydatalen, key_info, -+ &gd); -+ } else { -+ ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen, -+ key_info, extra_len, -+ ver, &gd); -+ } -+ -+ wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); -+ -+ if (ret) -+ goto failed; -+ -+ if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) || -+ wpa_supplicant_send_2_of_2(sm, key, ver, key_info)) -+ goto failed; -+ -+ if (rekey) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying " -+ "completed with " MACSTR " [GTK=%s]", -+ MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); -+ wpa_sm_cancel_auth_timeout(sm); -+ wpa_sm_set_state(sm, WPA_COMPLETED); -+ } else { -+ wpa_supplicant_key_neg_complete(sm, sm->bssid, -+ key_info & -+ WPA_KEY_INFO_SECURE); -+ } -+ return; -+ -+failed: -+ wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -+} -+ -+ -+static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, -+ struct wpa_eapol_key *key, -+ u16 ver, -+ const u8 *buf, size_t len) -+{ -+ u8 mic[16]; -+ int ok = 0; -+ -+ os_memcpy(mic, key->key_mic, 16); -+ if (sm->tptk_set) { -+ os_memset(key->key_mic, 0, 16); -+ wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len, -+ key->key_mic); -+ if (os_memcmp(mic, key->key_mic, 16) != 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Invalid EAPOL-Key MIC " -+ "when using TPTK - ignoring TPTK"); -+ } else { -+ ok = 1; -+ sm->tptk_set = 0; -+ sm->ptk_set = 1; -+ os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk)); -+ } -+ } -+ -+ if (!ok && sm->ptk_set) { -+ os_memset(key->key_mic, 0, 16); -+ wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len, -+ key->key_mic); -+ if (os_memcmp(mic, key->key_mic, 16) != 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Invalid EAPOL-Key MIC - " -+ "dropping packet"); -+ return -1; -+ } -+ ok = 1; -+ } -+ -+ if (!ok) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Could not verify EAPOL-Key MIC - " -+ "dropping packet"); -+ return -1; -+ } -+ -+ os_memcpy(sm->rx_replay_counter, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ sm->rx_replay_counter_set = 1; -+ return 0; -+} -+ -+ -+/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ -+static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, -+ struct wpa_eapol_key *key, u16 ver) -+{ -+ u16 keydatalen = WPA_GET_BE16(key->key_data_length); -+ -+ wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", -+ (u8 *) (key + 1), keydatalen); -+ if (!sm->ptk_set) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: PTK not available, cannot decrypt EAPOL-Key Key " -+ "Data"); -+ return -1; -+ } -+ -+ /* Decrypt key data here so that this operation does not need -+ * to be implemented separately for each message type. */ -+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { -+ u8 ek[32]; -+ os_memcpy(ek, key->key_iv, 16); -+ os_memcpy(ek + 16, sm->ptk.kek, 16); -+ if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, -+ "WPA: RC4 failed"); -+ return -1; -+ } -+ } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || -+ ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { -+ u8 *buf; -+ if (keydatalen % 8) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Unsupported AES-WRAP len %d", -+ keydatalen); -+ return -1; -+ } -+ keydatalen -= 8; /* AES-WRAP adds 8 bytes */ -+ buf = os_malloc(keydatalen); -+ if (buf == NULL) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: No memory for AES-UNWRAP buffer"); -+ return -1; -+ } -+ if (aes_unwrap(sm->ptk.kek, keydatalen / 8, -+ (u8 *) (key + 1), buf)) { -+ os_free(buf); -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: AES unwrap failed - " -+ "could not decrypt EAPOL-Key key data"); -+ return -1; -+ } -+ os_memcpy(key + 1, buf, keydatalen); -+ os_free(buf); -+ WPA_PUT_BE16(key->key_data_length, keydatalen); -+ } else { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Unsupported key_info type %d", ver); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", -+ (u8 *) (key + 1), keydatalen); -+ return 0; -+} -+ -+ -+/** -+ * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ */ -+void wpa_sm_aborted_cached(struct wpa_sm *sm) -+{ -+ if (sm && sm->cur_pmksa) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: Cancelling PMKSA caching attempt"); -+ sm->cur_pmksa = NULL; -+ } -+} -+ -+ -+static void wpa_eapol_key_dump(struct wpa_sm *sm, -+ const struct wpa_eapol_key *key) -+{ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+ u16 key_info = WPA_GET_BE16(key->key_info); -+ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, " EAPOL-Key type=%d", key->type); -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ " key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)", -+ key_info, key_info & WPA_KEY_INFO_TYPE_MASK, -+ (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> -+ WPA_KEY_INFO_KEY_INDEX_SHIFT, -+ (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13, -+ key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group", -+ key_info & WPA_KEY_INFO_INSTALL ? " Install" : "", -+ key_info & WPA_KEY_INFO_ACK ? " Ack" : "", -+ key_info & WPA_KEY_INFO_MIC ? " MIC" : "", -+ key_info & WPA_KEY_INFO_SECURE ? " Secure" : "", -+ key_info & WPA_KEY_INFO_ERROR ? " Error" : "", -+ key_info & WPA_KEY_INFO_REQUEST ? " Request" : "", -+ key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : ""); -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ " key_length=%u key_data_length=%u", -+ WPA_GET_BE16(key->key_length), -+ WPA_GET_BE16(key->key_data_length)); -+ wpa_hexdump(MSG_DEBUG, " replay_counter", -+ key->replay_counter, WPA_REPLAY_COUNTER_LEN); -+ wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16); -+ wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8); -+ wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8); -+ wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16); -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+} -+ -+ -+/** -+ * wpa_sm_rx_eapol - Process received WPA EAPOL frames -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @src_addr: Source MAC address of the EAPOL packet -+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) -+ * @len: Length of the EAPOL frame -+ * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure -+ * -+ * This function is called for each received EAPOL frame. Other than EAPOL-Key -+ * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is -+ * only processing WPA and WPA2 EAPOL-Key frames. -+ * -+ * The received EAPOL-Key packets are validated and valid packets are replied -+ * to. In addition, key material (PTK, GTK) is configured at the end of a -+ * successful key handshake. -+ */ -+int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ size_t plen, data_len, extra_len; -+ struct ieee802_1x_hdr *hdr; -+ struct wpa_eapol_key *key; -+ u16 key_info, ver; -+ u8 *tmp; -+ int ret = -1; -+ struct wpa_peerkey *peerkey = NULL; -+ -+#ifdef CONFIG_IEEE80211R -+ sm->ft_completed = 0; -+#endif /* CONFIG_IEEE80211R */ -+ -+ if (len < sizeof(*hdr) + sizeof(*key)) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: EAPOL frame too short to be a WPA " -+ "EAPOL-Key (len %lu, expecting at least %lu)", -+ (unsigned long) len, -+ (unsigned long) sizeof(*hdr) + sizeof(*key)); -+ return 0; -+ } -+ -+ tmp = os_malloc(len); -+ if (tmp == NULL) -+ return -1; -+ os_memcpy(tmp, buf, len); -+ -+ hdr = (struct ieee802_1x_hdr *) tmp; -+ key = (struct wpa_eapol_key *) (hdr + 1); -+ plen = be_to_host16(hdr->length); -+ data_len = plen + sizeof(*hdr); -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "IEEE 802.1X RX: version=%d type=%d length=%lu", -+ hdr->version, hdr->type, (unsigned long) plen); -+ -+ if (hdr->version < EAPOL_VERSION) { -+ /* TODO: backwards compatibility */ -+ } -+ if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: EAPOL frame (type %u) discarded, " -+ "not a Key frame", hdr->type); -+ ret = 0; -+ goto out; -+ } -+ if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: EAPOL frame payload size %lu " -+ "invalid (frame size %lu)", -+ (unsigned long) plen, (unsigned long) len); -+ ret = 0; -+ goto out; -+ } -+ -+ if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN) -+ { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: EAPOL-Key type (%d) unknown, discarded", -+ key->type); -+ ret = 0; -+ goto out; -+ } -+ wpa_eapol_key_dump(sm, key); -+ -+ eapol_sm_notify_lower_layer_success(sm->eapol, 0); -+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len); -+ if (data_len < len) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: ignoring %lu bytes after the IEEE 802.1X data", -+ (unsigned long) len - data_len); -+ } -+ key_info = WPA_GET_BE16(key->key_info); -+ ver = key_info & WPA_KEY_INFO_TYPE_MASK; -+ if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && -+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) -+ ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && -+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ -+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: Unsupported EAPOL-Key descriptor version %d", -+ ver); -+ goto out; -+ } -+ -+#ifdef CONFIG_IEEE80211R -+ if (wpa_key_mgmt_ft(sm->key_mgmt)) { -+ /* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */ -+ if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "FT: AP did not use AES-128-CMAC"); -+ goto out; -+ } -+ } else -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ if (wpa_key_mgmt_sha256(sm->key_mgmt)) { -+ if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: AP did not use the " -+ "negotiated AES-128-CMAC"); -+ goto out; -+ } -+ } else -+#endif /* CONFIG_IEEE80211W */ -+ if (sm->pairwise_cipher == WPA_CIPHER_CCMP && -+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: CCMP is used, but EAPOL-Key " -+ "descriptor version (%d) is not 2", ver); -+ if (sm->group_cipher != WPA_CIPHER_CCMP && -+ !(key_info & WPA_KEY_INFO_KEY_TYPE)) { -+ /* Earlier versions of IEEE 802.11i did not explicitly -+ * require version 2 descriptor for all EAPOL-Key -+ * packets, so allow group keys to use version 1 if -+ * CCMP is not used for them. */ -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: Backwards compatibility: allow invalid " -+ "version for non-CCMP group keys"); -+ } else -+ goto out; -+ } -+ -+#ifdef CONFIG_PEERKEY -+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { -+ if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0) -+ break; -+ } -+ -+ if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) { -+ if (!peerkey->initiator && peerkey->replay_counter_set && -+ os_memcmp(key->replay_counter, peerkey->replay_counter, -+ WPA_REPLAY_COUNTER_LEN) <= 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "RSN: EAPOL-Key Replay Counter did not " -+ "increase (STK) - dropping packet"); -+ goto out; -+ } else if (peerkey->initiator) { -+ u8 _tmp[WPA_REPLAY_COUNTER_LEN]; -+ os_memcpy(_tmp, key->replay_counter, -+ WPA_REPLAY_COUNTER_LEN); -+ inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN); -+ if (os_memcmp(_tmp, peerkey->replay_counter, -+ WPA_REPLAY_COUNTER_LEN) != 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: EAPOL-Key Replay " -+ "Counter did not match (STK) - " -+ "dropping packet"); -+ goto out; -+ } -+ } -+ } -+ -+ if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "RSN: Ack bit in key_info from STK peer"); -+ goto out; -+ } -+#endif /* CONFIG_PEERKEY */ -+ -+ if (!peerkey && sm->rx_replay_counter_set && -+ os_memcmp(key->replay_counter, sm->rx_replay_counter, -+ WPA_REPLAY_COUNTER_LEN) <= 0) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: EAPOL-Key Replay Counter did not increase - " -+ "dropping packet"); -+ goto out; -+ } -+ -+ if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE)) -+#ifdef CONFIG_PEERKEY -+ && (peerkey == NULL || !peerkey->initiator) -+#endif /* CONFIG_PEERKEY */ -+ ) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: No Ack bit in key_info"); -+ goto out; -+ } -+ -+ if (key_info & WPA_KEY_INFO_REQUEST) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, -+ "WPA: EAPOL-Key with Request bit - dropped"); -+ goto out; -+ } -+ -+ if ((key_info & WPA_KEY_INFO_MIC) && !peerkey && -+ wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len)) -+ goto out; -+ -+#ifdef CONFIG_PEERKEY -+ if ((key_info & WPA_KEY_INFO_MIC) && peerkey && -+ peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len)) -+ goto out; -+#endif /* CONFIG_PEERKEY */ -+ -+ extra_len = data_len - sizeof(*hdr) - sizeof(*key); -+ -+ if (WPA_GET_BE16(key->key_data_length) > extra_len) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " -+ "frame - key_data overflow (%d > %lu)", -+ WPA_GET_BE16(key->key_data_length), -+ (unsigned long) extra_len); -+ goto out; -+ } -+ extra_len = WPA_GET_BE16(key->key_data_length); -+ -+ if (sm->proto == WPA_PROTO_RSN && -+ (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { -+ if (wpa_supplicant_decrypt_key_data(sm, key, ver)) -+ goto out; -+ extra_len = WPA_GET_BE16(key->key_data_length); -+ } -+ -+ if (key_info & WPA_KEY_INFO_KEY_TYPE) { -+ if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: Ignored EAPOL-Key (Pairwise) with " -+ "non-zero key index"); -+ goto out; -+ } -+ if (peerkey) { -+ /* PeerKey 4-Way Handshake */ -+ peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver); -+ } else if (key_info & WPA_KEY_INFO_MIC) { -+ /* 3/4 4-Way Handshake */ -+ wpa_supplicant_process_3_of_4(sm, key, ver); -+ } else { -+ /* 1/4 4-Way Handshake */ -+ wpa_supplicant_process_1_of_4(sm, src_addr, key, -+ ver); -+ } -+ } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { -+ /* PeerKey SMK Handshake */ -+ peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info, -+ ver); -+ } else { -+ if (key_info & WPA_KEY_INFO_MIC) { -+ /* 1/2 Group Key Handshake */ -+ wpa_supplicant_process_1_of_2(sm, src_addr, key, -+ extra_len, ver); -+ } else { -+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, -+ "WPA: EAPOL-Key (Group) without Mic bit - " -+ "dropped"); -+ } -+ } -+ -+ ret = 1; -+ -+out: -+ os_free(tmp); -+ return ret; -+} -+ -+ -+#ifdef CONFIG_CTRL_IFACE -+static int wpa_cipher_bits(int cipher) -+{ -+ switch (cipher) { -+ case WPA_CIPHER_CCMP: -+ return 128; -+ case WPA_CIPHER_TKIP: -+ return 256; -+ case WPA_CIPHER_WEP104: -+ return 104; -+ case WPA_CIPHER_WEP40: -+ return 40; -+ default: -+ return 0; -+ } -+} -+ -+ -+static u32 wpa_key_mgmt_suite(struct wpa_sm *sm) -+{ -+ switch (sm->key_mgmt) { -+ case WPA_KEY_MGMT_IEEE8021X: -+ return (sm->proto == WPA_PROTO_RSN ? -+ RSN_AUTH_KEY_MGMT_UNSPEC_802_1X : -+ WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); -+ case WPA_KEY_MGMT_PSK: -+ return (sm->proto == WPA_PROTO_RSN ? -+ RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X : -+ WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); -+#ifdef CONFIG_IEEE80211R -+ case WPA_KEY_MGMT_FT_IEEE8021X: -+ return RSN_AUTH_KEY_MGMT_FT_802_1X; -+ case WPA_KEY_MGMT_FT_PSK: -+ return RSN_AUTH_KEY_MGMT_FT_PSK; -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ case WPA_KEY_MGMT_IEEE8021X_SHA256: -+ return RSN_AUTH_KEY_MGMT_802_1X_SHA256; -+ case WPA_KEY_MGMT_PSK_SHA256: -+ return RSN_AUTH_KEY_MGMT_PSK_SHA256; -+#endif /* CONFIG_IEEE80211W */ -+ case WPA_KEY_MGMT_WPA_NONE: -+ return WPA_AUTH_KEY_MGMT_NONE; -+ default: -+ return 0; -+ } -+} -+ -+ -+static u32 wpa_cipher_suite(struct wpa_sm *sm, int cipher) -+{ -+ switch (cipher) { -+ case WPA_CIPHER_CCMP: -+ return (sm->proto == WPA_PROTO_RSN ? -+ RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP); -+ case WPA_CIPHER_TKIP: -+ return (sm->proto == WPA_PROTO_RSN ? -+ RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP); -+ case WPA_CIPHER_WEP104: -+ return (sm->proto == WPA_PROTO_RSN ? -+ RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104); -+ case WPA_CIPHER_WEP40: -+ return (sm->proto == WPA_PROTO_RSN ? -+ RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40); -+ case WPA_CIPHER_NONE: -+ return (sm->proto == WPA_PROTO_RSN ? -+ RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); -+ default: -+ return 0; -+ } -+} -+ -+ -+#define RSN_SUITE "%02x-%02x-%02x-%d" -+#define RSN_SUITE_ARG(s) \ -+((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff -+ -+/** -+ * wpa_sm_get_mib - Dump text list of MIB entries -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @buf: Buffer for the list -+ * @buflen: Length of the buffer -+ * Returns: Number of bytes written to buffer -+ * -+ * This function is used fetch dot11 MIB variables. -+ */ -+int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen) -+{ -+ char pmkid_txt[PMKID_LEN * 2 + 1]; -+ int rsna, ret; -+ size_t len; -+ -+ if (sm->cur_pmksa) { -+ wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt), -+ sm->cur_pmksa->pmkid, PMKID_LEN); -+ } else -+ pmkid_txt[0] = '\0'; -+ -+ if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) || -+ wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) && -+ sm->proto == WPA_PROTO_RSN) -+ rsna = 1; -+ else -+ rsna = 0; -+ -+ ret = os_snprintf(buf, buflen, -+ "dot11RSNAOptionImplemented=TRUE\n" -+ "dot11RSNAPreauthenticationImplemented=TRUE\n" -+ "dot11RSNAEnabled=%s\n" -+ "dot11RSNAPreauthenticationEnabled=%s\n" -+ "dot11RSNAConfigVersion=%d\n" -+ "dot11RSNAConfigPairwiseKeysSupported=5\n" -+ "dot11RSNAConfigGroupCipherSize=%d\n" -+ "dot11RSNAConfigPMKLifetime=%d\n" -+ "dot11RSNAConfigPMKReauthThreshold=%d\n" -+ "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n" -+ "dot11RSNAConfigSATimeout=%d\n", -+ rsna ? "TRUE" : "FALSE", -+ rsna ? "TRUE" : "FALSE", -+ RSN_VERSION, -+ wpa_cipher_bits(sm->group_cipher), -+ sm->dot11RSNAConfigPMKLifetime, -+ sm->dot11RSNAConfigPMKReauthThreshold, -+ sm->dot11RSNAConfigSATimeout); -+ if (ret < 0 || (size_t) ret >= buflen) -+ return 0; -+ len = ret; -+ -+ ret = os_snprintf( -+ buf + len, buflen - len, -+ "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n" -+ "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n" -+ "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n" -+ "dot11RSNAPMKIDUsed=%s\n" -+ "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n" -+ "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n" -+ "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n" -+ "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n" -+ "dot11RSNA4WayHandshakeFailures=%u\n", -+ RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), -+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)), -+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)), -+ pmkid_txt, -+ RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)), -+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)), -+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)), -+ sm->dot11RSNA4WayHandshakeFailures); -+ if (ret >= 0 && (size_t) ret < buflen) -+ len += ret; -+ -+ return (int) len; -+} -+#endif /* CONFIG_CTRL_IFACE */ -+ -+ -+static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, -+ void *ctx, int replace) -+{ -+ struct wpa_sm *sm = ctx; -+ -+ if (sm->cur_pmksa == entry || -+ (sm->pmk_len == entry->pmk_len && -+ os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "RSN: removed current PMKSA entry"); -+ sm->cur_pmksa = NULL; -+ -+ if (replace) { -+ /* A new entry is being added, so no need to -+ * deauthenticate in this case. This happens when EAP -+ * authentication is completed again (reauth or failed -+ * PMKSA caching attempt). */ -+ return; -+ } -+ -+ os_memset(sm->pmk, 0, sizeof(sm->pmk)); -+ wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -+ } -+} -+ -+ -+/** -+ * wpa_sm_init - Initialize WPA state machine -+ * @ctx: Context pointer for callbacks; this needs to be an allocated buffer -+ * Returns: Pointer to the allocated WPA state machine data -+ * -+ * This function is used to allocate a new WPA state machine and the returned -+ * value is passed to all WPA state machine calls. -+ */ -+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) -+{ -+ struct wpa_sm *sm; -+ -+ sm = os_zalloc(sizeof(*sm)); -+ if (sm == NULL) -+ return NULL; -+ dl_list_init(&sm->pmksa_candidates); -+ sm->renew_snonce = 1; -+ sm->ctx = ctx; -+ -+ sm->dot11RSNAConfigPMKLifetime = 43200; -+ sm->dot11RSNAConfigPMKReauthThreshold = 70; -+ sm->dot11RSNAConfigSATimeout = 60; -+ -+ sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm); -+ if (sm->pmksa == NULL) { -+ wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, -+ "RSN: PMKSA cache initialization failed"); -+ os_free(sm); -+ return NULL; -+ } -+ -+ return sm; -+} -+ -+ -+/** -+ * wpa_sm_deinit - Deinitialize WPA state machine -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ */ -+void wpa_sm_deinit(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ pmksa_cache_deinit(sm->pmksa); -+ eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL); -+ eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); -+ os_free(sm->assoc_wpa_ie); -+ os_free(sm->ap_wpa_ie); -+ os_free(sm->ap_rsn_ie); -+ os_free(sm->ctx); -+ peerkey_deinit(sm); -+#ifdef CONFIG_IEEE80211R -+ os_free(sm->assoc_resp_ies); -+#endif /* CONFIG_IEEE80211R */ -+ os_free(sm); -+} -+ -+ -+/** -+ * wpa_sm_notify_assoc - Notify WPA state machine about association -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @bssid: The BSSID of the new association -+ * -+ * This function is called to let WPA state machine know that the connection -+ * was established. -+ */ -+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) -+{ -+ int clear_ptk = 1; -+ -+ if (sm == NULL) -+ return; -+ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: Association event - clear replay counter"); -+ os_memcpy(sm->bssid, bssid, ETH_ALEN); -+ os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN); -+ sm->rx_replay_counter_set = 0; -+ sm->renew_snonce = 1; -+ if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0) -+ rsn_preauth_deinit(sm); -+ -+#ifdef CONFIG_IEEE80211R -+ if (wpa_ft_is_completed(sm)) { -+ /* -+ * Clear portValid to kick EAPOL state machine to re-enter -+ * AUTHENTICATED state to get the EAPOL port Authorized. -+ */ -+ eapol_sm_notify_portValid(sm->eapol, FALSE); -+ wpa_supplicant_key_neg_complete(sm, sm->bssid, 1); -+ -+ /* Prepare for the next transition */ -+ wpa_ft_prepare_auth_request(sm, NULL); -+ -+ clear_ptk = 0; -+ } -+#endif /* CONFIG_IEEE80211R */ -+ -+ if (clear_ptk) { -+ /* -+ * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if -+ * this is not part of a Fast BSS Transition. -+ */ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK"); -+ sm->ptk_set = 0; -+ sm->tptk_set = 0; -+ } -+ -+#ifdef CONFIG_TDLS -+ wpa_tdls_assoc(sm); -+#endif /* CONFIG_TDLS */ -+} -+ -+ -+/** -+ * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * -+ * This function is called to let WPA state machine know that the connection -+ * was lost. This will abort any existing pre-authentication session. -+ */ -+void wpa_sm_notify_disassoc(struct wpa_sm *sm) -+{ -+ rsn_preauth_deinit(sm); -+ if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE) -+ sm->dot11RSNA4WayHandshakeFailures++; -+#ifdef CONFIG_TDLS -+ wpa_tdls_disassoc(sm); -+#endif /* CONFIG_TDLS */ -+} -+ -+ -+/** -+ * wpa_sm_set_pmk - Set PMK -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @pmk: The new PMK -+ * @pmk_len: The length of the new PMK in bytes -+ * -+ * Configure the PMK for WPA state machine. -+ */ -+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len) -+{ -+ if (sm == NULL) -+ return; -+ -+ sm->pmk_len = pmk_len; -+ os_memcpy(sm->pmk, pmk, pmk_len); -+ -+#ifdef CONFIG_IEEE80211R -+ /* Set XXKey to be PSK for FT key derivation */ -+ sm->xxkey_len = pmk_len; -+ os_memcpy(sm->xxkey, pmk, pmk_len); -+#endif /* CONFIG_IEEE80211R */ -+} -+ -+ -+/** -+ * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * -+ * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK -+ * will be cleared. -+ */ -+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return; -+ -+ if (sm->cur_pmksa) { -+ sm->pmk_len = sm->cur_pmksa->pmk_len; -+ os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len); -+ } else { -+ sm->pmk_len = PMK_LEN; -+ os_memset(sm->pmk, 0, PMK_LEN); -+ } -+} -+ -+ -+/** -+ * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @fast_reauth: Whether fast reauthentication (EAP) is allowed -+ */ -+void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth) -+{ -+ if (sm) -+ sm->fast_reauth = fast_reauth; -+} -+ -+ -+/** -+ * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @scard_ctx: Context pointer for smartcard related callback functions -+ */ -+void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx) -+{ -+ if (sm == NULL) -+ return; -+ sm->scard_ctx = scard_ctx; -+ if (sm->preauth_eapol) -+ eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx); -+} -+ -+ -+/** -+ * wpa_sm_set_config - Notification of current configration change -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @config: Pointer to current network configuration -+ * -+ * Notify WPA state machine that configuration has changed. config will be -+ * stored as a backpointer to network configuration. This can be %NULL to clear -+ * the stored pointed. -+ */ -+void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) -+{ -+ if (!sm) -+ return; -+ -+ if (config) { -+ sm->network_ctx = config->network_ctx; -+ sm->peerkey_enabled = config->peerkey_enabled; -+ sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher; -+ sm->proactive_key_caching = config->proactive_key_caching; -+ sm->eap_workaround = config->eap_workaround; -+ sm->eap_conf_ctx = config->eap_conf_ctx; -+ if (config->ssid) { -+ os_memcpy(sm->ssid, config->ssid, config->ssid_len); -+ sm->ssid_len = config->ssid_len; -+ } else -+ sm->ssid_len = 0; -+ sm->wpa_ptk_rekey = config->wpa_ptk_rekey; -+ } else { -+ sm->network_ctx = NULL; -+ sm->peerkey_enabled = 0; -+ sm->allowed_pairwise_cipher = 0; -+ sm->proactive_key_caching = 0; -+ sm->eap_workaround = 0; -+ sm->eap_conf_ctx = NULL; -+ sm->ssid_len = 0; -+ sm->wpa_ptk_rekey = 0; -+ } -+ if (config == NULL || config->network_ctx != sm->network_ctx) -+ pmksa_cache_notify_reconfig(sm->pmksa); -+} -+ -+ -+/** -+ * wpa_sm_set_own_addr - Set own MAC address -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @addr: Own MAC address -+ */ -+void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr) -+{ -+ if (sm) -+ os_memcpy(sm->own_addr, addr, ETH_ALEN); -+} -+ -+ -+/** -+ * wpa_sm_set_ifname - Set network interface name -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @ifname: Interface name -+ * @bridge_ifname: Optional bridge interface name (for pre-auth) -+ */ -+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, -+ const char *bridge_ifname) -+{ -+ if (sm) { -+ sm->ifname = ifname; -+ sm->bridge_ifname = bridge_ifname; -+ } -+} -+ -+ -+/** -+ * wpa_sm_set_eapol - Set EAPOL state machine pointer -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init() -+ */ -+void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol) -+{ -+ if (sm) -+ sm->eapol = eapol; -+} -+ -+ -+/** -+ * wpa_sm_set_param - Set WPA state machine parameters -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @param: Parameter field -+ * @value: Parameter value -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, -+ unsigned int value) -+{ -+ int ret = 0; -+ -+ if (sm == NULL) -+ return -1; -+ -+ switch (param) { -+ case RSNA_PMK_LIFETIME: -+ if (value > 0) -+ sm->dot11RSNAConfigPMKLifetime = value; -+ else -+ ret = -1; -+ break; -+ case RSNA_PMK_REAUTH_THRESHOLD: -+ if (value > 0 && value <= 100) -+ sm->dot11RSNAConfigPMKReauthThreshold = value; -+ else -+ ret = -1; -+ break; -+ case RSNA_SA_TIMEOUT: -+ if (value > 0) -+ sm->dot11RSNAConfigSATimeout = value; -+ else -+ ret = -1; -+ break; -+ case WPA_PARAM_PROTO: -+ sm->proto = value; -+ break; -+ case WPA_PARAM_PAIRWISE: -+ sm->pairwise_cipher = value; -+ break; -+ case WPA_PARAM_GROUP: -+ sm->group_cipher = value; -+ break; -+ case WPA_PARAM_KEY_MGMT: -+ sm->key_mgmt = value; -+ break; -+#ifdef CONFIG_IEEE80211W -+ case WPA_PARAM_MGMT_GROUP: -+ sm->mgmt_group_cipher = value; -+ break; -+#endif /* CONFIG_IEEE80211W */ -+ case WPA_PARAM_RSN_ENABLED: -+ sm->rsn_enabled = value; -+ break; -+ case WPA_PARAM_MFP: -+ sm->mfp = value; -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+ -+/** -+ * wpa_sm_get_param - Get WPA state machine parameters -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @param: Parameter field -+ * Returns: Parameter value -+ */ -+unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param) -+{ -+ if (sm == NULL) -+ return 0; -+ -+ switch (param) { -+ case RSNA_PMK_LIFETIME: -+ return sm->dot11RSNAConfigPMKLifetime; -+ case RSNA_PMK_REAUTH_THRESHOLD: -+ return sm->dot11RSNAConfigPMKReauthThreshold; -+ case RSNA_SA_TIMEOUT: -+ return sm->dot11RSNAConfigSATimeout; -+ case WPA_PARAM_PROTO: -+ return sm->proto; -+ case WPA_PARAM_PAIRWISE: -+ return sm->pairwise_cipher; -+ case WPA_PARAM_GROUP: -+ return sm->group_cipher; -+ case WPA_PARAM_KEY_MGMT: -+ return sm->key_mgmt; -+#ifdef CONFIG_IEEE80211W -+ case WPA_PARAM_MGMT_GROUP: -+ return sm->mgmt_group_cipher; -+#endif /* CONFIG_IEEE80211W */ -+ case WPA_PARAM_RSN_ENABLED: -+ return sm->rsn_enabled; -+ default: -+ return 0; -+ } -+} -+ -+ -+/** -+ * wpa_sm_get_status - Get WPA state machine -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @buf: Buffer for status information -+ * @buflen: Maximum buffer length -+ * @verbose: Whether to include verbose status information -+ * Returns: Number of bytes written to buf. -+ * -+ * Query WPA state machine for status information. This function fills in -+ * a text area with current status information. If the buffer (buf) is not -+ * large enough, status information will be truncated to fit the buffer. -+ */ -+int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, -+ int verbose) -+{ -+ char *pos = buf, *end = buf + buflen; -+ int ret; -+ -+ ret = os_snprintf(pos, end - pos, -+ "pairwise_cipher=%s\n" -+ "group_cipher=%s\n" -+ "key_mgmt=%s\n", -+ wpa_cipher_txt(sm->pairwise_cipher), -+ wpa_cipher_txt(sm->group_cipher), -+ wpa_key_mgmt_txt(sm->key_mgmt, sm->proto)); -+ if (ret < 0 || ret >= end - pos) -+ return pos - buf; -+ pos += ret; -+ return pos - buf; -+} -+ -+ -+/** -+ * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @wpa_ie: Pointer to buffer for WPA/RSN IE -+ * @wpa_ie_len: Pointer to the length of the wpa_ie buffer -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie, -+ size_t *wpa_ie_len) -+{ -+ int res; -+ -+ if (sm == NULL) -+ return -1; -+ -+ res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len); -+ if (res < 0) -+ return -1; -+ *wpa_ie_len = res; -+ -+ wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default", -+ wpa_ie, *wpa_ie_len); -+ -+ if (sm->assoc_wpa_ie == NULL) { -+ /* -+ * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets -+ * the correct version of the IE even if PMKSA caching is -+ * aborted (which would remove PMKID from IE generation). -+ */ -+ sm->assoc_wpa_ie = os_malloc(*wpa_ie_len); -+ if (sm->assoc_wpa_ie == NULL) -+ return -1; -+ -+ os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len); -+ sm->assoc_wpa_ie_len = *wpa_ie_len; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @ie: Pointer to IE data (starting from id) -+ * @len: IE length -+ * Returns: 0 on success, -1 on failure -+ * -+ * Inform WPA state machine about the WPA/RSN IE used in (Re)Association -+ * Request frame. The IE will be used to override the default value generated -+ * with wpa_sm_set_assoc_wpa_ie_default(). -+ */ -+int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len) -+{ -+ if (sm == NULL) -+ return -1; -+ -+ os_free(sm->assoc_wpa_ie); -+ if (ie == NULL || len == 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: clearing own WPA/RSN IE"); -+ sm->assoc_wpa_ie = NULL; -+ sm->assoc_wpa_ie_len = 0; -+ } else { -+ wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len); -+ sm->assoc_wpa_ie = os_malloc(len); -+ if (sm->assoc_wpa_ie == NULL) -+ return -1; -+ -+ os_memcpy(sm->assoc_wpa_ie, ie, len); -+ sm->assoc_wpa_ie_len = len; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @ie: Pointer to IE data (starting from id) -+ * @len: IE length -+ * Returns: 0 on success, -1 on failure -+ * -+ * Inform WPA state machine about the WPA IE used in Beacon / Probe Response -+ * frame. -+ */ -+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len) -+{ -+ if (sm == NULL) -+ return -1; -+ -+ os_free(sm->ap_wpa_ie); -+ if (ie == NULL || len == 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: clearing AP WPA IE"); -+ sm->ap_wpa_ie = NULL; -+ sm->ap_wpa_ie_len = 0; -+ } else { -+ wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len); -+ sm->ap_wpa_ie = os_malloc(len); -+ if (sm->ap_wpa_ie == NULL) -+ return -1; -+ -+ os_memcpy(sm->ap_wpa_ie, ie, len); -+ sm->ap_wpa_ie_len = len; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @ie: Pointer to IE data (starting from id) -+ * @len: IE length -+ * Returns: 0 on success, -1 on failure -+ * -+ * Inform WPA state machine about the RSN IE used in Beacon / Probe Response -+ * frame. -+ */ -+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len) -+{ -+ if (sm == NULL) -+ return -1; -+ -+ os_free(sm->ap_rsn_ie); -+ if (ie == NULL || len == 0) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: clearing AP RSN IE"); -+ sm->ap_rsn_ie = NULL; -+ sm->ap_rsn_ie_len = 0; -+ } else { -+ wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len); -+ sm->ap_rsn_ie = os_malloc(len); -+ if (sm->ap_rsn_ie == NULL) -+ return -1; -+ -+ os_memcpy(sm->ap_rsn_ie, ie, len); -+ sm->ap_rsn_ie_len = len; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @data: Pointer to data area for parsing results -+ * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure -+ * -+ * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the -+ * parsed data into data. -+ */ -+int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data) -+{ -+ if (sm == NULL) -+ return -1; -+ -+ if (sm->assoc_wpa_ie == NULL) { -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, -+ "WPA: No WPA/RSN IE available from association info"); -+ return -1; -+ } -+ if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data)) -+ return -2; -+ return 0; -+} -+ -+ -+int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) -+{ -+#ifndef CONFIG_NO_WPA2 -+ return pmksa_cache_list(sm->pmksa, buf, len); -+#else /* CONFIG_NO_WPA2 */ -+ return -1; -+#endif /* CONFIG_NO_WPA2 */ -+} -+ -+ -+void wpa_sm_drop_sa(struct wpa_sm *sm) -+{ -+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK"); -+ sm->ptk_set = 0; -+ sm->tptk_set = 0; -+ os_memset(sm->pmk, 0, sizeof(sm->pmk)); -+ os_memset(&sm->ptk, 0, sizeof(sm->ptk)); -+ os_memset(&sm->tptk, 0, sizeof(sm->tptk)); -+} -+ -+ -+int wpa_sm_has_ptk(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return 0; -+ return sm->ptk_set; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.h -new file mode 100644 -index 0000000000000..111597ca4a760 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa.h -@@ -0,0 +1,351 @@ -+/* -+ * wpa_supplicant - WPA definitions -+ * Copyright (c) 2003-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_H -+#define WPA_H -+ -+#include "common/defs.h" -+#include "common/eapol_common.h" -+#include "common/wpa_common.h" -+ -+struct wpa_sm; -+struct eapol_sm; -+struct wpa_config_blob; -+ -+struct wpa_sm_ctx { -+ void *ctx; /* pointer to arbitrary upper level context */ -+ void *msg_ctx; /* upper level context for wpa_msg() calls */ -+ -+ void (*set_state)(void *ctx, enum wpa_states state); -+ enum wpa_states (*get_state)(void *ctx); -+ void (*deauthenticate)(void * ctx, int reason_code); -+ void (*disassociate)(void *ctx, int reason_code); -+ int (*set_key)(void *ctx, enum wpa_alg alg, -+ const u8 *addr, int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len); -+ void * (*get_network_ctx)(void *ctx); -+ int (*get_bssid)(void *ctx, u8 *bssid); -+ int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf, -+ size_t len); -+ int (*get_beacon_ie)(void *ctx); -+ void (*cancel_auth_timeout)(void *ctx); -+ u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len, -+ size_t *msg_len, void **data_pos); -+ int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid); -+ int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid); -+ void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); -+ const struct wpa_config_blob * (*get_config_blob)(void *ctx, -+ const char *name); -+ int (*mlme_setprotection)(void *ctx, const u8 *addr, -+ int protection_type, int key_type); -+ int (*update_ft_ies)(void *ctx, const u8 *md, const u8 *ies, -+ size_t ies_len); -+ int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap, -+ const u8 *ies, size_t ies_len); -+ int (*mark_authenticated)(void *ctx, const u8 *target_ap); -+#ifdef CONFIG_TDLS -+ int (*send_tdls_mgmt)(void *ctx, const u8 *dst, -+ u8 action_code, u8 dialog_token, -+ u16 status_code, const u8 *buf, size_t len); -+ int (*tdls_oper)(void *ctx, int oper, const u8 *peer); -+#endif /* CONFIG_TDLS */ -+}; -+ -+ -+enum wpa_sm_conf_params { -+ RSNA_PMK_LIFETIME /* dot11RSNAConfigPMKLifetime */, -+ RSNA_PMK_REAUTH_THRESHOLD /* dot11RSNAConfigPMKReauthThreshold */, -+ RSNA_SA_TIMEOUT /* dot11RSNAConfigSATimeout */, -+ WPA_PARAM_PROTO, -+ WPA_PARAM_PAIRWISE, -+ WPA_PARAM_GROUP, -+ WPA_PARAM_KEY_MGMT, -+ WPA_PARAM_MGMT_GROUP, -+ WPA_PARAM_RSN_ENABLED, -+ WPA_PARAM_MFP -+}; -+ -+struct rsn_supp_config { -+ void *network_ctx; -+ int peerkey_enabled; -+ int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */ -+ int proactive_key_caching; -+ int eap_workaround; -+ void *eap_conf_ctx; -+ const u8 *ssid; -+ size_t ssid_len; -+ int wpa_ptk_rekey; -+}; -+ -+#ifndef CONFIG_NO_WPA -+ -+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx); -+void wpa_sm_deinit(struct wpa_sm *sm); -+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid); -+void wpa_sm_notify_disassoc(struct wpa_sm *sm); -+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len); -+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm); -+void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth); -+void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx); -+void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config); -+void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr); -+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, -+ const char *bridge_ifname); -+void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol); -+int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len); -+int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie, -+ size_t *wpa_ie_len); -+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len); -+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len); -+int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen); -+ -+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, -+ unsigned int value); -+unsigned int wpa_sm_get_param(struct wpa_sm *sm, -+ enum wpa_sm_conf_params param); -+ -+int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, -+ int verbose); -+ -+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise); -+ -+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, -+ struct wpa_ie_data *data); -+ -+void wpa_sm_aborted_cached(struct wpa_sm *sm); -+int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, -+ const u8 *buf, size_t len); -+int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data); -+int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len); -+void wpa_sm_drop_sa(struct wpa_sm *sm); -+int wpa_sm_has_ptk(struct wpa_sm *sm); -+ -+#else /* CONFIG_NO_WPA */ -+ -+static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) -+{ -+ return (struct wpa_sm *) 1; -+} -+ -+static inline void wpa_sm_deinit(struct wpa_sm *sm) -+{ -+} -+ -+static inline void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) -+{ -+} -+ -+static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm) -+{ -+} -+ -+static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, -+ size_t pmk_len) -+{ -+} -+ -+static inline void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm) -+{ -+} -+ -+static inline void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth) -+{ -+} -+ -+static inline void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx) -+{ -+} -+ -+static inline void wpa_sm_set_config(struct wpa_sm *sm, -+ struct rsn_supp_config *config) -+{ -+} -+ -+static inline void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr) -+{ -+} -+ -+static inline void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, -+ const char *bridge_ifname) -+{ -+} -+ -+static inline void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol) -+{ -+} -+ -+static inline int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, -+ size_t len) -+{ -+ return -1; -+} -+ -+static inline int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, -+ u8 *wpa_ie, -+ size_t *wpa_ie_len) -+{ -+ return -1; -+} -+ -+static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, -+ size_t len) -+{ -+ return -1; -+} -+ -+static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, -+ size_t len) -+{ -+ return -1; -+} -+ -+static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen) -+{ -+ return 0; -+} -+ -+static inline int wpa_sm_set_param(struct wpa_sm *sm, -+ enum wpa_sm_conf_params param, -+ unsigned int value) -+{ -+ return -1; -+} -+ -+static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm, -+ enum wpa_sm_conf_params param) -+{ -+ return 0; -+} -+ -+static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf, -+ size_t buflen, int verbose) -+{ -+ return 0; -+} -+ -+static inline void wpa_sm_key_request(struct wpa_sm *sm, int error, -+ int pairwise) -+{ -+} -+ -+static inline int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, -+ struct wpa_ie_data *data) -+{ -+ return -1; -+} -+ -+static inline void wpa_sm_aborted_cached(struct wpa_sm *sm) -+{ -+} -+ -+static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, -+ const u8 *buf, size_t len) -+{ -+ return -1; -+} -+ -+static inline int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, -+ struct wpa_ie_data *data) -+{ -+ return -1; -+} -+ -+static inline int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, -+ size_t len) -+{ -+ return -1; -+} -+ -+static inline void wpa_sm_drop_sa(struct wpa_sm *sm) -+{ -+} -+ -+static inline int wpa_sm_has_ptk(struct wpa_sm *sm) -+{ -+ return 0; -+} -+ -+#endif /* CONFIG_NO_WPA */ -+ -+#ifdef CONFIG_PEERKEY -+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer); -+#else /* CONFIG_PEERKEY */ -+static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) -+{ -+ return -1; -+} -+#endif /* CONFIG_PEERKEY */ -+ -+#ifdef CONFIG_IEEE80211R -+ -+int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len); -+int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie); -+int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, -+ int ft_action, const u8 *target_ap, -+ const u8 *ric_ies, size_t ric_ies_len); -+int wpa_ft_is_completed(struct wpa_sm *sm); -+int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, -+ size_t ies_len, const u8 *src_addr); -+int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, -+ const u8 *mdie); -+ -+#else /* CONFIG_IEEE80211R */ -+ -+static inline int -+wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) -+{ -+ return 0; -+} -+ -+static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm, -+ const u8 *mdie) -+{ -+ return 0; -+} -+ -+static inline int -+wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, -+ int ft_action, const u8 *target_ap) -+{ -+ return 0; -+} -+ -+static inline int wpa_ft_is_completed(struct wpa_sm *sm) -+{ -+ return 0; -+} -+ -+static inline int -+wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len, -+ const u8 *src_addr) -+{ -+ return -1; -+} -+ -+#endif /* CONFIG_IEEE80211R */ -+ -+ -+/* tdls.c */ -+void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len); -+void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len); -+int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr); -+int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr); -+int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr, -+ u16 reason_code); -+int wpa_tdls_init(struct wpa_sm *sm); -+void wpa_tdls_deinit(struct wpa_sm *sm); -+void wpa_tdls_enable(struct wpa_sm *sm, int enabled); -+ -+#endif /* WPA_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ft.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ft.c -new file mode 100644 -index 0000000000000..da6e966f653d8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ft.c -@@ -0,0 +1,1039 @@ -+/* -+ * WPA Supplicant - IEEE 802.11r - Fast BSS Transition -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/aes_wrap.h" -+#include "crypto/random.h" -+#include "common/ieee802_11_defs.h" -+#include "common/ieee802_11_common.h" -+#include "wpa.h" -+#include "wpa_i.h" -+#include "wpa_ie.h" -+ -+#ifdef CONFIG_IEEE80211R -+ -+struct wpa_ft_ies { -+ const u8 *mdie; -+ size_t mdie_len; -+ const u8 *ftie; -+ size_t ftie_len; -+ const u8 *r1kh_id; -+ const u8 *gtk; -+ size_t gtk_len; -+ const u8 *r0kh_id; -+ size_t r0kh_id_len; -+ const u8 *rsn; -+ size_t rsn_len; -+ const u8 *rsn_pmkid; -+ const u8 *tie; -+ size_t tie_len; -+ const u8 *igtk; -+ size_t igtk_len; -+ const u8 *ric; -+ size_t ric_len; -+}; -+ -+static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, -+ struct wpa_ft_ies *parse); -+ -+ -+int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, -+ struct wpa_ptk *ptk, size_t ptk_len) -+{ -+ u8 ptk_name[WPA_PMK_NAME_LEN]; -+ const u8 *anonce = key->key_nonce; -+ -+ if (sm->xxkey_len == 0) { -+ wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " -+ "derivation"); -+ return -1; -+ } -+ -+ wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid, -+ sm->ssid_len, sm->mobility_domain, -+ sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, -+ sm->pmk_r0, sm->pmk_r0_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", -+ sm->pmk_r0_name, WPA_PMK_NAME_LEN); -+ wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, -+ sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name, -+ WPA_PMK_NAME_LEN); -+ wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, -+ sm->bssid, sm->pmk_r1_name, -+ (u8 *) ptk, ptk_len, ptk_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len); -+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @ies: Association Response IEs or %NULL to clear FT parameters -+ * @ies_len: Length of ies buffer in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) -+{ -+ struct wpa_ft_ies ft; -+ -+ if (sm == NULL) -+ return 0; -+ -+ if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0) -+ return -1; -+ -+ if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) -+ return -1; -+ -+ if (ft.mdie) { -+ wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", -+ ft.mdie, MOBILITY_DOMAIN_ID_LEN); -+ os_memcpy(sm->mobility_domain, ft.mdie, -+ MOBILITY_DOMAIN_ID_LEN); -+ sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; -+ wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", -+ sm->mdie_ft_capab); -+ } else -+ os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); -+ -+ if (ft.r0kh_id) { -+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", -+ ft.r0kh_id, ft.r0kh_id_len); -+ os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len); -+ sm->r0kh_id_len = ft.r0kh_id_len; -+ } else { -+ /* FIX: When should R0KH-ID be cleared? We need to keep the -+ * old R0KH-ID in order to be able to use this during FT. */ -+ /* -+ * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN); -+ * sm->r0kh_id_len = 0; -+ */ -+ } -+ -+ if (ft.r1kh_id) { -+ wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", -+ ft.r1kh_id, FT_R1KH_ID_LEN); -+ os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN); -+ } else -+ os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); -+ -+ os_free(sm->assoc_resp_ies); -+ sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2); -+ if (sm->assoc_resp_ies) { -+ u8 *pos = sm->assoc_resp_ies; -+ if (ft.mdie) { -+ os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); -+ pos += ft.mdie_len + 2; -+ } -+ if (ft.ftie) { -+ os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2); -+ pos += ft.ftie_len + 2; -+ } -+ sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies; -+ wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from " -+ "(Re)Association Response", -+ sm->assoc_resp_ies, sm->assoc_resp_ies_len); -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @len: Buffer for returning the length of the IEs -+ * @anonce: ANonce or %NULL if not yet available -+ * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List -+ * @kck: 128-bit KCK for MIC or %NULL if no MIC is used -+ * @target_ap: Target AP address -+ * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL -+ * @ric_ies_len: Length of ric_ies buffer in octets -+ * @ap_mdie: Mobility Domain IE from the target AP -+ * Returns: Pointer to buffer with IEs or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned buffer with os_free(); -+ */ -+static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, -+ const u8 *anonce, const u8 *pmk_name, -+ const u8 *kck, const u8 *target_ap, -+ const u8 *ric_ies, size_t ric_ies_len, -+ const u8 *ap_mdie) -+{ -+ size_t buf_len; -+ u8 *buf, *pos, *ftie_len, *ftie_pos; -+ struct rsn_mdie *mdie; -+ struct rsn_ftie *ftie; -+ struct rsn_ie_hdr *rsnie; -+ u16 capab; -+ -+ sm->ft_completed = 0; -+ -+ buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) + -+ 2 + sm->r0kh_id_len + ric_ies_len + 100; -+ buf = os_zalloc(buf_len); -+ if (buf == NULL) -+ return NULL; -+ pos = buf; -+ -+ /* RSNIE[PMKR0Name/PMKR1Name] */ -+ rsnie = (struct rsn_ie_hdr *) pos; -+ rsnie->elem_id = WLAN_EID_RSN; -+ WPA_PUT_LE16(rsnie->version, RSN_VERSION); -+ pos = (u8 *) (rsnie + 1); -+ -+ /* Group Suite Selector */ -+ if (sm->group_cipher == WPA_CIPHER_CCMP) -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ else if (sm->group_cipher == WPA_CIPHER_TKIP) -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ else { -+ wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)", -+ sm->group_cipher); -+ os_free(buf); -+ return NULL; -+ } -+ pos += RSN_SELECTOR_LEN; -+ -+ /* Pairwise Suite Count */ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ -+ /* Pairwise Suite List */ -+ if (sm->pairwise_cipher == WPA_CIPHER_CCMP) -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ else if (sm->pairwise_cipher == WPA_CIPHER_TKIP) -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ else { -+ wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)", -+ sm->pairwise_cipher); -+ os_free(buf); -+ return NULL; -+ } -+ pos += RSN_SELECTOR_LEN; -+ -+ /* Authenticated Key Management Suite Count */ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ -+ /* Authenticated Key Management Suite List */ -+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); -+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); -+ else { -+ wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)", -+ sm->key_mgmt); -+ os_free(buf); -+ return NULL; -+ } -+ pos += RSN_SELECTOR_LEN; -+ -+ /* RSN Capabilities */ -+ capab = 0; -+#ifdef CONFIG_IEEE80211W -+ if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) -+ capab |= WPA_CAPABILITY_MFPC; -+#endif /* CONFIG_IEEE80211W */ -+ WPA_PUT_LE16(pos, capab); -+ pos += 2; -+ -+ /* PMKID Count */ -+ WPA_PUT_LE16(pos, 1); -+ pos += 2; -+ -+ /* PMKID List [PMKR0Name/PMKR1Name] */ -+ os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN); -+ pos += WPA_PMK_NAME_LEN; -+ -+#ifdef CONFIG_IEEE80211W -+ if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { -+ /* Management Group Cipher Suite */ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); -+ pos += RSN_SELECTOR_LEN; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ rsnie->len = (pos - (u8 *) rsnie) - 2; -+ -+ /* MDIE */ -+ *pos++ = WLAN_EID_MOBILITY_DOMAIN; -+ *pos++ = sizeof(*mdie); -+ mdie = (struct rsn_mdie *) pos; -+ pos += sizeof(*mdie); -+ os_memcpy(mdie->mobility_domain, sm->mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN); -+ mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] : -+ sm->mdie_ft_capab; -+ -+ /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */ -+ ftie_pos = pos; -+ *pos++ = WLAN_EID_FAST_BSS_TRANSITION; -+ ftie_len = pos++; -+ ftie = (struct rsn_ftie *) pos; -+ pos += sizeof(*ftie); -+ os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); -+ if (anonce) -+ os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); -+ if (kck) { -+ /* R1KH-ID sub-element in third FT message */ -+ *pos++ = FTIE_SUBELEM_R1KH_ID; -+ *pos++ = FT_R1KH_ID_LEN; -+ os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN); -+ pos += FT_R1KH_ID_LEN; -+ } -+ /* R0KH-ID sub-element */ -+ *pos++ = FTIE_SUBELEM_R0KH_ID; -+ *pos++ = sm->r0kh_id_len; -+ os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len); -+ pos += sm->r0kh_id_len; -+ *ftie_len = pos - ftie_len - 1; -+ -+ if (ric_ies) { -+ /* RIC Request */ -+ os_memcpy(pos, ric_ies, ric_ies_len); -+ pos += ric_ies_len; -+ } -+ -+ if (kck) { -+ /* -+ * IEEE Std 802.11r-2008, 11A.8.4 -+ * MIC shall be calculated over: -+ * non-AP STA MAC address -+ * Target AP MAC address -+ * Transaction seq number (5 for ReassocReq, 3 otherwise) -+ * RSN IE -+ * MDIE -+ * FTIE (with MIC field set to 0) -+ * RIC-Request (if present) -+ */ -+ /* Information element count */ -+ ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies, -+ ric_ies_len); -+ if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5, -+ ((u8 *) mdie) - 2, 2 + sizeof(*mdie), -+ ftie_pos, 2 + *ftie_len, -+ (u8 *) rsnie, 2 + rsnie->len, ric_ies, -+ ric_ies_len, ftie->mic) < 0) { -+ wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); -+ os_free(buf); -+ return NULL; -+ } -+ } -+ -+ *len = pos - buf; -+ -+ return buf; -+} -+ -+ -+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, -+ struct wpa_ft_ies *parse) -+{ -+ const u8 *end, *pos; -+ -+ parse->ftie = ie; -+ parse->ftie_len = ie_len; -+ -+ pos = ie + sizeof(struct rsn_ftie); -+ end = ie + ie_len; -+ -+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) { -+ switch (pos[0]) { -+ case FTIE_SUBELEM_R1KH_ID: -+ if (pos[1] != FT_R1KH_ID_LEN) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID " -+ "length in FTIE: %d", pos[1]); -+ return -1; -+ } -+ parse->r1kh_id = pos + 2; -+ break; -+ case FTIE_SUBELEM_GTK: -+ parse->gtk = pos + 2; -+ parse->gtk_len = pos[1]; -+ break; -+ case FTIE_SUBELEM_R0KH_ID: -+ if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID " -+ "length in FTIE: %d", pos[1]); -+ return -1; -+ } -+ parse->r0kh_id = pos + 2; -+ parse->r0kh_id_len = pos[1]; -+ break; -+#ifdef CONFIG_IEEE80211W -+ case FTIE_SUBELEM_IGTK: -+ parse->igtk = pos + 2; -+ parse->igtk_len = pos[1]; -+ break; -+#endif /* CONFIG_IEEE80211W */ -+ } -+ -+ pos += 2 + pos[1]; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, -+ struct wpa_ft_ies *parse) -+{ -+ const u8 *end, *pos; -+ struct wpa_ie_data data; -+ int ret; -+ const struct rsn_ftie *ftie; -+ int prot_ie_count = 0; -+ -+ os_memset(parse, 0, sizeof(*parse)); -+ if (ies == NULL) -+ return 0; -+ -+ pos = ies; -+ end = ies + ies_len; -+ while (pos + 2 <= end && pos + 2 + pos[1] <= end) { -+ switch (pos[0]) { -+ case WLAN_EID_RSN: -+ parse->rsn = pos + 2; -+ parse->rsn_len = pos[1]; -+ ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2, -+ parse->rsn_len + 2, -+ &data); -+ if (ret < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to parse " -+ "RSN IE: %d", ret); -+ return -1; -+ } -+ if (data.num_pmkid == 1 && data.pmkid) -+ parse->rsn_pmkid = data.pmkid; -+ break; -+ case WLAN_EID_MOBILITY_DOMAIN: -+ parse->mdie = pos + 2; -+ parse->mdie_len = pos[1]; -+ break; -+ case WLAN_EID_FAST_BSS_TRANSITION: -+ if (pos[1] < sizeof(*ftie)) -+ return -1; -+ ftie = (const struct rsn_ftie *) (pos + 2); -+ prot_ie_count = ftie->mic_control[1]; -+ if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) -+ return -1; -+ break; -+ case WLAN_EID_TIMEOUT_INTERVAL: -+ parse->tie = pos + 2; -+ parse->tie_len = pos[1]; -+ break; -+ case WLAN_EID_RIC_DATA: -+ if (parse->ric == NULL) -+ parse->ric = pos; -+ } -+ -+ pos += 2 + pos[1]; -+ } -+ -+ if (prot_ie_count == 0) -+ return 0; /* no MIC */ -+ -+ /* -+ * Check that the protected IE count matches with IEs included in the -+ * frame. -+ */ -+ if (parse->rsn) -+ prot_ie_count--; -+ if (parse->mdie) -+ prot_ie_count--; -+ if (parse->ftie) -+ prot_ie_count--; -+ if (parse->tie) -+ prot_ie_count--; -+ if (prot_ie_count < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " -+ "the protected IE count"); -+ return -1; -+ } -+ -+ if (prot_ie_count == 0 && parse->ric) { -+ wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " -+ "included in protected IE count"); -+ return -1; -+ } -+ -+ /* Determine the end of the RIC IE(s) */ -+ pos = parse->ric; -+ while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && -+ prot_ie_count) { -+ prot_ie_count--; -+ pos += 2 + pos[1]; -+ } -+ parse->ric_len = pos - parse->ric; -+ if (prot_ie_count) { -+ wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " -+ "frame", (int) prot_ie_count); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) -+{ -+ int keylen; -+ enum wpa_alg alg; -+ u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 }; -+ -+ wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver."); -+ -+ switch (sm->pairwise_cipher) { -+ case WPA_CIPHER_CCMP: -+ alg = WPA_ALG_CCMP; -+ keylen = 16; -+ break; -+ case WPA_CIPHER_TKIP: -+ alg = WPA_ALG_TKIP; -+ keylen = 32; -+ break; -+ default: -+ wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d", -+ sm->pairwise_cipher); -+ return -1; -+ } -+ -+ if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, -+ sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) { -+ wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_ft_prepare_auth_request - Generate over-the-air auth request -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @mdie: Target AP MDIE -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) -+{ -+ u8 *ft_ies; -+ size_t ft_ies_len; -+ -+ /* Generate a new SNonce */ -+ if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { -+ wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); -+ return -1; -+ } -+ -+ ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, -+ NULL, sm->bssid, NULL, 0, mdie); -+ if (ft_ies) { -+ wpa_sm_update_ft_ies(sm, sm->mobility_domain, -+ ft_ies, ft_ies_len); -+ os_free(ft_ies); -+ } -+ -+ return 0; -+} -+ -+ -+int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, -+ int ft_action, const u8 *target_ap, -+ const u8 *ric_ies, size_t ric_ies_len) -+{ -+ u8 *ft_ies; -+ size_t ft_ies_len, ptk_len; -+ struct wpa_ft_ies parse; -+ struct rsn_mdie *mdie; -+ struct rsn_ftie *ftie; -+ u8 ptk_name[WPA_PMK_NAME_LEN]; -+ int ret; -+ const u8 *bssid; -+ -+ wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); -+ wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); -+ -+ if (ft_action) { -+ if (!sm->over_the_ds_in_progress) { -+ wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " -+ "- drop FT Action Response"); -+ return -1; -+ } -+ -+ if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " -+ "with this Target AP - drop FT Action " -+ "Response"); -+ return -1; -+ } -+ } -+ -+ if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && -+ sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { -+ wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " -+ "enabled for this connection"); -+ return -1; -+ } -+ -+ if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); -+ return -1; -+ } -+ -+ mdie = (struct rsn_mdie *) parse.mdie; -+ if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || -+ os_memcmp(mdie->mobility_domain, sm->mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); -+ return -1; -+ } -+ -+ ftie = (struct rsn_ftie *) parse.ftie; -+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); -+ return -1; -+ } -+ -+ if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); -+ wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", -+ ftie->snonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", -+ sm->snonce, WPA_NONCE_LEN); -+ return -1; -+ } -+ -+ if (parse.r0kh_id == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); -+ return -1; -+ } -+ -+ if (parse.r0kh_id_len != sm->r0kh_id_len || -+ os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " -+ "the current R0KH-ID"); -+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", -+ parse.r0kh_id, parse.r0kh_id_len); -+ wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", -+ sm->r0kh_id, sm->r0kh_id_len); -+ return -1; -+ } -+ -+ if (parse.r1kh_id == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); -+ return -1; -+ } -+ -+ if (parse.rsn_pmkid == NULL || -+ os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) { -+ wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in " -+ "RSNIE"); -+ return -1; -+ } -+ -+ os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN); -+ os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN); -+ wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id, -+ sm->own_addr, sm->pmk_r1, sm->pmk_r1_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", -+ sm->pmk_r1_name, WPA_PMK_NAME_LEN); -+ -+ bssid = target_ap; -+ ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64; -+ wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr, -+ bssid, sm->pmk_r1_name, -+ (u8 *) &sm->ptk, ptk_len, ptk_name); -+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", -+ (u8 *) &sm->ptk, ptk_len); -+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); -+ -+ ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, -+ sm->pmk_r1_name, sm->ptk.kck, bssid, -+ ric_ies, ric_ies_len, -+ parse.mdie ? parse.mdie - 2 : NULL); -+ if (ft_ies) { -+ wpa_sm_update_ft_ies(sm, sm->mobility_domain, -+ ft_ies, ft_ies_len); -+ os_free(ft_ies); -+ } -+ -+ wpa_sm_mark_authenticated(sm, bssid); -+ ret = wpa_ft_install_ptk(sm, bssid); -+ if (ret) { -+ /* -+ * Some drivers do not support key configuration when we are -+ * not associated with the target AP. Work around this by -+ * trying again after the following reassociation gets -+ * completed. -+ */ -+ wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to " -+ "association - try again after reassociation"); -+ sm->set_ptk_after_assoc = 1; -+ } else -+ sm->set_ptk_after_assoc = 0; -+ -+ sm->ft_completed = 1; -+ if (ft_action) { -+ /* -+ * The caller is expected trigger re-association with the -+ * Target AP. -+ */ -+ os_memcpy(sm->bssid, target_ap, ETH_ALEN); -+ } -+ -+ return 0; -+} -+ -+ -+int wpa_ft_is_completed(struct wpa_sm *sm) -+{ -+ if (sm == NULL) -+ return 0; -+ -+ if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && -+ sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) -+ return 0; -+ -+ return sm->ft_completed; -+} -+ -+ -+static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, -+ size_t gtk_elem_len) -+{ -+ u8 gtk[32]; -+ int keyidx; -+ enum wpa_alg alg; -+ size_t gtk_len, keylen, rsc_len; -+ -+ if (gtk_elem == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE"); -+ return 0; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp", -+ gtk_elem, gtk_elem_len); -+ -+ if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 || -+ gtk_elem_len - 19 > sizeof(gtk)) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem " -+ "length %lu", (unsigned long) gtk_elem_len); -+ return -1; -+ } -+ gtk_len = gtk_elem_len - 19; -+ if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) { -+ wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " -+ "decrypt GTK"); -+ return -1; -+ } -+ -+ switch (sm->group_cipher) { -+ case WPA_CIPHER_CCMP: -+ keylen = 16; -+ rsc_len = 6; -+ alg = WPA_ALG_CCMP; -+ break; -+ case WPA_CIPHER_TKIP: -+ keylen = 32; -+ rsc_len = 6; -+ alg = WPA_ALG_TKIP; -+ break; -+ case WPA_CIPHER_WEP104: -+ keylen = 13; -+ rsc_len = 0; -+ alg = WPA_ALG_WEP; -+ break; -+ case WPA_CIPHER_WEP40: -+ keylen = 5; -+ rsc_len = 0; -+ alg = WPA_ALG_WEP; -+ break; -+ default: -+ wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d", -+ sm->group_cipher); -+ return -1; -+ } -+ -+ if (gtk_len < keylen) { -+ wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE"); -+ return -1; -+ } -+ -+ /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */ -+ -+ keyidx = WPA_GET_LE16(gtk_elem) & 0x03; -+ -+ if (gtk_elem[2] != keylen) { -+ wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d " -+ "negotiated %lu", -+ gtk_elem[2], (unsigned long) keylen); -+ return -1; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen); -+ if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0, -+ gtk_elem + 3, rsc_len, gtk, keylen) < 0) { -+ wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " -+ "driver."); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_IEEE80211W -+static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, -+ size_t igtk_elem_len) -+{ -+ u8 igtk[WPA_IGTK_LEN]; -+ u16 keyidx; -+ -+ if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) -+ return 0; -+ -+ if (igtk_elem == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE"); -+ return 0; -+ } -+ -+ wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp", -+ igtk_elem, igtk_elem_len); -+ -+ if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem " -+ "length %lu", (unsigned long) igtk_elem_len); -+ return -1; -+ } -+ if (igtk_elem[8] != WPA_IGTK_LEN) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length " -+ "%d", igtk_elem[8]); -+ return -1; -+ } -+ -+ if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) { -+ wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " -+ "decrypt IGTK"); -+ return -1; -+ } -+ -+ /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */ -+ -+ keyidx = WPA_GET_LE16(igtk_elem); -+ -+ wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk, -+ WPA_IGTK_LEN); -+ if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0, -+ igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) { -+ wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the " -+ "driver."); -+ return -1; -+ } -+ -+ return 0; -+} -+#endif /* CONFIG_IEEE80211W */ -+ -+ -+int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, -+ size_t ies_len, const u8 *src_addr) -+{ -+ struct wpa_ft_ies parse; -+ struct rsn_mdie *mdie; -+ struct rsn_ftie *ftie; -+ unsigned int count; -+ u8 mic[16]; -+ -+ wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); -+ -+ if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X && -+ sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) { -+ wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " -+ "enabled for this connection"); -+ return -1; -+ } -+ -+ if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); -+ return -1; -+ } -+ -+ mdie = (struct rsn_mdie *) parse.mdie; -+ if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || -+ os_memcmp(mdie->mobility_domain, sm->mobility_domain, -+ MOBILITY_DOMAIN_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); -+ return -1; -+ } -+ -+ ftie = (struct rsn_ftie *) parse.ftie; -+ if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); -+ return -1; -+ } -+ -+ if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); -+ wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", -+ ftie->snonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", -+ sm->snonce, WPA_NONCE_LEN); -+ return -1; -+ } -+ -+ if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); -+ wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", -+ ftie->anonce, WPA_NONCE_LEN); -+ wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", -+ sm->anonce, WPA_NONCE_LEN); -+ return -1; -+ } -+ -+ if (parse.r0kh_id == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); -+ return -1; -+ } -+ -+ if (parse.r0kh_id_len != sm->r0kh_id_len || -+ os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " -+ "the current R0KH-ID"); -+ wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", -+ parse.r0kh_id, parse.r0kh_id_len); -+ wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", -+ sm->r0kh_id, sm->r0kh_id_len); -+ return -1; -+ } -+ -+ if (parse.r1kh_id == NULL) { -+ wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); -+ return -1; -+ } -+ -+ if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " -+ "ReassocResp"); -+ return -1; -+ } -+ -+ if (parse.rsn_pmkid == NULL || -+ os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { -+ wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " -+ "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); -+ return -1; -+ } -+ -+ count = 3; -+ if (parse.tie) -+ count++; -+ if (ftie->mic_control[1] != count) { -+ wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " -+ "Control: received %u expected %u", -+ ftie->mic_control[1], count); -+ return -1; -+ } -+ -+ if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6, -+ parse.mdie - 2, parse.mdie_len + 2, -+ parse.ftie - 2, parse.ftie_len + 2, -+ parse.rsn - 2, parse.rsn_len + 2, -+ parse.ric, parse.ric_len, -+ mic) < 0) { -+ wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); -+ return -1; -+ } -+ -+ if (os_memcmp(mic, ftie->mic, 16) != 0) { -+ wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); -+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); -+ wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); -+ return -1; -+ } -+ -+ if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) -+ return -1; -+ -+#ifdef CONFIG_IEEE80211W -+ if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0) -+ return -1; -+#endif /* CONFIG_IEEE80211W */ -+ -+ if (sm->set_ptk_after_assoc) { -+ wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we " -+ "are associated"); -+ if (wpa_ft_install_ptk(sm, src_addr) < 0) -+ return -1; -+ sm->set_ptk_after_assoc = 0; -+ } -+ -+ if (parse.ric) { -+ wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response", -+ parse.ric, parse.ric_len); -+ /* TODO: parse response and inform driver about results */ -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_ft_start_over_ds - Generate over-the-DS auth request -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @target_ap: Target AP Address -+ * @mdie: Mobility Domain IE from the target AP -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, -+ const u8 *mdie) -+{ -+ u8 *ft_ies; -+ size_t ft_ies_len; -+ -+ wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR, -+ MAC2STR(target_ap)); -+ -+ /* Generate a new SNonce */ -+ if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { -+ wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce"); -+ return -1; -+ } -+ -+ ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, -+ NULL, target_ap, NULL, 0, mdie); -+ if (ft_ies) { -+ sm->over_the_ds_in_progress = 1; -+ os_memcpy(sm->target_ap, target_ap, ETH_ALEN); -+ wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len); -+ os_free(ft_ies); -+ } -+ -+ return 0; -+} -+ -+#endif /* CONFIG_IEEE80211R */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_i.h -new file mode 100644 -index 0000000000000..09a2e4ff5a508 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_i.h -@@ -0,0 +1,290 @@ -+/* -+ * Internal WPA/RSN supplicant state machine definitions -+ * Copyright (c) 2004-2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_I_H -+#define WPA_I_H -+ -+#include "utils/list.h" -+ -+struct wpa_peerkey; -+struct wpa_tdls_peer; -+struct wpa_eapol_key; -+ -+/** -+ * struct wpa_sm - Internal WPA state machine data -+ */ -+struct wpa_sm { -+ u8 pmk[PMK_LEN]; -+ size_t pmk_len; -+ struct wpa_ptk ptk, tptk; -+ int ptk_set, tptk_set; -+ u8 snonce[WPA_NONCE_LEN]; -+ u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */ -+ int renew_snonce; -+ u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN]; -+ int rx_replay_counter_set; -+ u8 request_counter[WPA_REPLAY_COUNTER_LEN]; -+ -+ struct eapol_sm *eapol; /* EAPOL state machine from upper level code */ -+ -+ struct rsn_pmksa_cache *pmksa; /* PMKSA cache */ -+ struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */ -+ struct dl_list pmksa_candidates; -+ -+ struct l2_packet_data *l2_preauth; -+ struct l2_packet_data *l2_preauth_br; -+ struct l2_packet_data *l2_tdls; -+ u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or -+ * 00:00:00:00:00:00 if no pre-auth is -+ * in progress */ -+ struct eapol_sm *preauth_eapol; -+ -+ struct wpa_sm_ctx *ctx; -+ -+ void *scard_ctx; /* context for smartcard callbacks */ -+ int fast_reauth; /* whether EAP fast re-authentication is enabled */ -+ -+ void *network_ctx; -+ int peerkey_enabled; -+ int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */ -+ int proactive_key_caching; -+ int eap_workaround; -+ void *eap_conf_ctx; -+ u8 ssid[32]; -+ size_t ssid_len; -+ int wpa_ptk_rekey; -+ -+ u8 own_addr[ETH_ALEN]; -+ const char *ifname; -+ const char *bridge_ifname; -+ u8 bssid[ETH_ALEN]; -+ -+ unsigned int dot11RSNAConfigPMKLifetime; -+ unsigned int dot11RSNAConfigPMKReauthThreshold; -+ unsigned int dot11RSNAConfigSATimeout; -+ -+ unsigned int dot11RSNA4WayHandshakeFailures; -+ -+ /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ -+ unsigned int proto; -+ unsigned int pairwise_cipher; -+ unsigned int group_cipher; -+ unsigned int key_mgmt; -+ unsigned int mgmt_group_cipher; -+ -+ int rsn_enabled; /* Whether RSN is enabled in configuration */ -+ int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */ -+ -+ u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ -+ size_t assoc_wpa_ie_len; -+ u8 *ap_wpa_ie, *ap_rsn_ie; -+ size_t ap_wpa_ie_len, ap_rsn_ie_len; -+ -+#ifdef CONFIG_PEERKEY -+ struct wpa_peerkey *peerkey; -+#endif /* CONFIG_PEERKEY */ -+#ifdef CONFIG_TDLS -+ struct wpa_tdls_peer *tdls; -+ int tdls_prohibited; -+ int tdls_disabled; -+#endif /* CONFIG_TDLS */ -+ -+#ifdef CONFIG_IEEE80211R -+ u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */ -+ size_t xxkey_len; -+ u8 pmk_r0[PMK_LEN]; -+ u8 pmk_r0_name[WPA_PMK_NAME_LEN]; -+ u8 pmk_r1[PMK_LEN]; -+ u8 pmk_r1_name[WPA_PMK_NAME_LEN]; -+ u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; -+ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; -+ size_t r0kh_id_len; -+ u8 r1kh_id[FT_R1KH_ID_LEN]; -+ int ft_completed; -+ int over_the_ds_in_progress; -+ u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */ -+ int set_ptk_after_assoc; -+ u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */ -+ u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */ -+ size_t assoc_resp_ies_len; -+#endif /* CONFIG_IEEE80211R */ -+}; -+ -+ -+static inline void wpa_sm_set_state(struct wpa_sm *sm, enum wpa_states state) -+{ -+ WPA_ASSERT(sm->ctx->set_state); -+ sm->ctx->set_state(sm->ctx->ctx, state); -+} -+ -+static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm) -+{ -+ WPA_ASSERT(sm->ctx->get_state); -+ return sm->ctx->get_state(sm->ctx->ctx); -+} -+ -+static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code) -+{ -+ WPA_ASSERT(sm->ctx->deauthenticate); -+ sm->ctx->deauthenticate(sm->ctx->ctx, reason_code); -+} -+ -+static inline void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code) -+{ -+ WPA_ASSERT(sm->ctx->disassociate); -+ sm->ctx->disassociate(sm->ctx->ctx, reason_code); -+} -+ -+static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg, -+ const u8 *addr, int key_idx, int set_tx, -+ const u8 *seq, size_t seq_len, -+ const u8 *key, size_t key_len) -+{ -+ WPA_ASSERT(sm->ctx->set_key); -+ return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx, -+ seq, seq_len, key, key_len); -+} -+ -+static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm) -+{ -+ WPA_ASSERT(sm->ctx->get_network_ctx); -+ return sm->ctx->get_network_ctx(sm->ctx->ctx); -+} -+ -+static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid) -+{ -+ WPA_ASSERT(sm->ctx->get_bssid); -+ return sm->ctx->get_bssid(sm->ctx->ctx, bssid); -+} -+ -+static inline int wpa_sm_ether_send(struct wpa_sm *sm, const u8 *dest, -+ u16 proto, const u8 *buf, size_t len) -+{ -+ WPA_ASSERT(sm->ctx->ether_send); -+ return sm->ctx->ether_send(sm->ctx->ctx, dest, proto, buf, len); -+} -+ -+static inline int wpa_sm_get_beacon_ie(struct wpa_sm *sm) -+{ -+ WPA_ASSERT(sm->ctx->get_beacon_ie); -+ return sm->ctx->get_beacon_ie(sm->ctx->ctx); -+} -+ -+static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm) -+{ -+ WPA_ASSERT(sm->ctx->cancel_auth_timeout); -+ sm->ctx->cancel_auth_timeout(sm->ctx->ctx); -+} -+ -+static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, -+ const void *data, u16 data_len, -+ size_t *msg_len, void **data_pos) -+{ -+ WPA_ASSERT(sm->ctx->alloc_eapol); -+ return sm->ctx->alloc_eapol(sm->ctx->ctx, type, data, data_len, -+ msg_len, data_pos); -+} -+ -+static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ WPA_ASSERT(sm->ctx->add_pmkid); -+ return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid); -+} -+ -+static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid, -+ const u8 *pmkid) -+{ -+ WPA_ASSERT(sm->ctx->remove_pmkid); -+ return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid); -+} -+ -+static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr, -+ int protect_type, int key_type) -+{ -+ WPA_ASSERT(sm->ctx->mlme_setprotection); -+ return sm->ctx->mlme_setprotection(sm->ctx->ctx, addr, protect_type, -+ key_type); -+} -+ -+static inline int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md, -+ const u8 *ies, size_t ies_len) -+{ -+ if (sm->ctx->update_ft_ies) -+ return sm->ctx->update_ft_ies(sm->ctx->ctx, md, ies, ies_len); -+ return -1; -+} -+ -+static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action, -+ const u8 *target_ap, -+ const u8 *ies, size_t ies_len) -+{ -+ if (sm->ctx->send_ft_action) -+ return sm->ctx->send_ft_action(sm->ctx->ctx, action, target_ap, -+ ies, ies_len); -+ return -1; -+} -+ -+static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm, -+ const u8 *target_ap) -+{ -+ if (sm->ctx->mark_authenticated) -+ return sm->ctx->mark_authenticated(sm->ctx->ctx, target_ap); -+ return -1; -+} -+ -+#ifdef CONFIG_TDLS -+static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst, -+ u8 action_code, u8 dialog_token, -+ u16 status_code, const u8 *buf, -+ size_t len) -+{ -+ if (sm->ctx->send_tdls_mgmt) -+ return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code, -+ dialog_token, status_code, -+ buf, len); -+ return -1; -+} -+ -+static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper, -+ const u8 *peer) -+{ -+ if (sm->ctx->tdls_oper) -+ return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer); -+ return -1; -+} -+#endif /* CONFIG_TDLS */ -+ -+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, -+ int ver, const u8 *dest, u16 proto, -+ u8 *msg, size_t msg_len, u8 *key_mic); -+int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, -+ const struct wpa_eapol_key *key, -+ int ver, const u8 *nonce, -+ const u8 *wpa_ie, size_t wpa_ie_len, -+ struct wpa_ptk *ptk); -+int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, -+ const struct wpa_eapol_key *key, -+ u16 ver, u16 key_info, -+ const u8 *kde, size_t kde_len, -+ struct wpa_ptk *ptk); -+ -+int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, -+ const struct wpa_eapol_key *key, -+ struct wpa_ptk *ptk, size_t ptk_len); -+ -+void wpa_tdls_assoc(struct wpa_sm *sm); -+void wpa_tdls_disassoc(struct wpa_sm *sm); -+ -+#endif /* WPA_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.c -new file mode 100644 -index 0000000000000..654cc1f153409 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.c -@@ -0,0 +1,447 @@ -+/* -+ * wpa_supplicant - WPA/RSN IE and KDE processing -+ * Copyright (c) 2003-2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "wpa.h" -+#include "pmksa_cache.h" -+#include "common/ieee802_11_defs.h" -+#include "wpa_i.h" -+#include "wpa_ie.h" -+ -+ -+/** -+ * wpa_parse_wpa_ie - Parse WPA/RSN IE -+ * @wpa_ie: Pointer to WPA or RSN IE -+ * @wpa_ie_len: Length of the WPA/RSN IE -+ * @data: Pointer to data area for parsing results -+ * Returns: 0 on success, -1 on failure -+ * -+ * Parse the contents of WPA or RSN IE and write the parsed data into data. -+ */ -+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, -+ struct wpa_ie_data *data) -+{ -+ if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) -+ return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); -+ else -+ return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); -+} -+ -+ -+static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, -+ int pairwise_cipher, int group_cipher, -+ int key_mgmt) -+{ -+ u8 *pos; -+ struct wpa_ie_hdr *hdr; -+ -+ if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + -+ 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) -+ return -1; -+ -+ hdr = (struct wpa_ie_hdr *) wpa_ie; -+ hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; -+ RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); -+ WPA_PUT_LE16(hdr->version, WPA_VERSION); -+ pos = (u8 *) (hdr + 1); -+ -+ if (group_cipher == WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); -+ } else if (group_cipher == WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); -+ } else if (group_cipher == WPA_CIPHER_WEP104) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104); -+ } else if (group_cipher == WPA_CIPHER_WEP40) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40); -+ } else { -+ wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", -+ group_cipher); -+ return -1; -+ } -+ pos += WPA_SELECTOR_LEN; -+ -+ *pos++ = 1; -+ *pos++ = 0; -+ if (pairwise_cipher == WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP); -+ } else if (pairwise_cipher == WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP); -+ } else if (pairwise_cipher == WPA_CIPHER_NONE) { -+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE); -+ } else { -+ wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", -+ pairwise_cipher); -+ return -1; -+ } -+ pos += WPA_SELECTOR_LEN; -+ -+ *pos++ = 1; -+ *pos++ = 0; -+ if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { -+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); -+ } else if (key_mgmt == WPA_KEY_MGMT_PSK) { -+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); -+ } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { -+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); -+ } else { -+ wpa_printf(MSG_WARNING, "Invalid key management type (%d).", -+ key_mgmt); -+ return -1; -+ } -+ pos += WPA_SELECTOR_LEN; -+ -+ /* WPA Capabilities; use defaults, so no need to include it */ -+ -+ hdr->len = (pos - wpa_ie) - 2; -+ -+ WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); -+ -+ return pos - wpa_ie; -+} -+ -+ -+static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, -+ int pairwise_cipher, int group_cipher, -+ int key_mgmt, int mgmt_group_cipher, -+ struct wpa_sm *sm) -+{ -+#ifndef CONFIG_NO_WPA2 -+ u8 *pos; -+ struct rsn_ie_hdr *hdr; -+ u16 capab; -+ -+ if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + -+ 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + -+ (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { -+ wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", -+ (unsigned long) rsn_ie_len); -+ return -1; -+ } -+ -+ hdr = (struct rsn_ie_hdr *) rsn_ie; -+ hdr->elem_id = WLAN_EID_RSN; -+ WPA_PUT_LE16(hdr->version, RSN_VERSION); -+ pos = (u8 *) (hdr + 1); -+ -+ if (group_cipher == WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ } else if (group_cipher == WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ } else if (group_cipher == WPA_CIPHER_WEP104) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104); -+ } else if (group_cipher == WPA_CIPHER_WEP40) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40); -+ } else { -+ wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", -+ group_cipher); -+ return -1; -+ } -+ pos += RSN_SELECTOR_LEN; -+ -+ *pos++ = 1; -+ *pos++ = 0; -+ if (pairwise_cipher == WPA_CIPHER_CCMP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); -+ } else if (pairwise_cipher == WPA_CIPHER_TKIP) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP); -+ } else if (pairwise_cipher == WPA_CIPHER_NONE) { -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE); -+ } else { -+ wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", -+ pairwise_cipher); -+ return -1; -+ } -+ pos += RSN_SELECTOR_LEN; -+ -+ *pos++ = 1; -+ *pos++ = 0; -+ if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); -+ } else if (key_mgmt == WPA_KEY_MGMT_PSK) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); -+#ifdef CONFIG_IEEE80211R -+ } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); -+ } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); -+#endif /* CONFIG_IEEE80211R */ -+#ifdef CONFIG_IEEE80211W -+ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); -+ } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { -+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); -+#endif /* CONFIG_IEEE80211W */ -+ } else { -+ wpa_printf(MSG_WARNING, "Invalid key management type (%d).", -+ key_mgmt); -+ return -1; -+ } -+ pos += RSN_SELECTOR_LEN; -+ -+ /* RSN Capabilities */ -+ capab = 0; -+#ifdef CONFIG_IEEE80211W -+ if (sm->mfp) -+ capab |= WPA_CAPABILITY_MFPC; -+ if (sm->mfp == 2) -+ capab |= WPA_CAPABILITY_MFPR; -+#endif /* CONFIG_IEEE80211W */ -+ WPA_PUT_LE16(pos, capab); -+ pos += 2; -+ -+ if (sm->cur_pmksa) { -+ /* PMKID Count (2 octets, little endian) */ -+ *pos++ = 1; -+ *pos++ = 0; -+ /* PMKID */ -+ os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); -+ pos += PMKID_LEN; -+ } -+ -+#ifdef CONFIG_IEEE80211W -+ if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { -+ if (!sm->cur_pmksa) { -+ /* PMKID Count */ -+ WPA_PUT_LE16(pos, 0); -+ pos += 2; -+ } -+ -+ /* Management Group Cipher Suite */ -+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); -+ pos += RSN_SELECTOR_LEN; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ hdr->len = (pos - rsn_ie) - 2; -+ -+ WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); -+ -+ return pos - rsn_ie; -+#else /* CONFIG_NO_WPA2 */ -+ return -1; -+#endif /* CONFIG_NO_WPA2 */ -+} -+ -+ -+/** -+ * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy -+ * @sm: Pointer to WPA state machine data from wpa_sm_init() -+ * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE -+ * @wpa_ie_len: Maximum length of the generated WPA/RSN IE -+ * Returns: Length of the generated WPA/RSN IE or -1 on failure -+ */ -+int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) -+{ -+ if (sm->proto == WPA_PROTO_RSN) -+ return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, -+ sm->pairwise_cipher, -+ sm->group_cipher, -+ sm->key_mgmt, sm->mgmt_group_cipher, -+ sm); -+ else -+ return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, -+ sm->pairwise_cipher, -+ sm->group_cipher, -+ sm->key_mgmt); -+} -+ -+ -+/** -+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs -+ * @pos: Pointer to the IE header -+ * @end: Pointer to the end of the Key Data buffer -+ * @ie: Pointer to parsed IE data -+ * Returns: 0 on success, 1 if end mark is found, -1 on failure -+ */ -+static int wpa_parse_generic(const u8 *pos, const u8 *end, -+ struct wpa_eapol_ie_parse *ie) -+{ -+ if (pos[1] == 0) -+ return 1; -+ -+ if (pos[1] >= 6 && -+ RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && -+ pos[2 + WPA_SELECTOR_LEN] == 1 && -+ pos[2 + WPA_SELECTOR_LEN + 1] == 0) { -+ ie->wpa_ie = pos; -+ ie->wpa_ie_len = pos[1] + 2; -+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", -+ ie->wpa_ie, ie->wpa_ie_len); -+ return 0; -+ } -+ -+ if (pos + 1 + RSN_SELECTOR_LEN < end && -+ pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { -+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; -+ wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { -+ ie->gtk = pos + 2 + RSN_SELECTOR_LEN; -+ ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; -+ wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { -+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; -+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; -+ wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+ -+#ifdef CONFIG_PEERKEY -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { -+ ie->smk = pos + 2 + RSN_SELECTOR_LEN; -+ ie->smk_len = pos[1] - RSN_SELECTOR_LEN; -+ wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { -+ ie->nonce = pos + 2 + RSN_SELECTOR_LEN; -+ ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; -+ wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { -+ ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; -+ ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; -+ wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+ -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { -+ ie->error = pos + 2 + RSN_SELECTOR_LEN; -+ ie->error_len = pos[1] - RSN_SELECTOR_LEN; -+ wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+#endif /* CONFIG_PEERKEY */ -+ -+#ifdef CONFIG_IEEE80211W -+ if (pos[1] > RSN_SELECTOR_LEN + 2 && -+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { -+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN; -+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; -+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", -+ pos, pos[1] + 2); -+ return 0; -+ } -+#endif /* CONFIG_IEEE80211W */ -+ -+ return 0; -+} -+ -+ -+/** -+ * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs -+ * @buf: Pointer to the Key Data buffer -+ * @len: Key Data Length -+ * @ie: Pointer to parsed IE data -+ * Returns: 0 on success, -1 on failure -+ */ -+int wpa_supplicant_parse_ies(const u8 *buf, size_t len, -+ struct wpa_eapol_ie_parse *ie) -+{ -+ const u8 *pos, *end; -+ int ret = 0; -+ -+ os_memset(ie, 0, sizeof(*ie)); -+ for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { -+ if (pos[0] == 0xdd && -+ ((pos == buf + len - 1) || pos[1] == 0)) { -+ /* Ignore padding */ -+ break; -+ } -+ if (pos + 2 + pos[1] > end) { -+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " -+ "underflow (ie=%d len=%d pos=%d)", -+ pos[0], pos[1], (int) (pos - buf)); -+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", -+ buf, len); -+ ret = -1; -+ break; -+ } -+ if (*pos == WLAN_EID_RSN) { -+ ie->rsn_ie = pos; -+ ie->rsn_ie_len = pos[1] + 2; -+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", -+ ie->rsn_ie, ie->rsn_ie_len); -+ } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { -+ ie->mdie = pos; -+ ie->mdie_len = pos[1] + 2; -+ wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", -+ ie->mdie, ie->mdie_len); -+ } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { -+ ie->ftie = pos; -+ ie->ftie_len = pos[1] + 2; -+ wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", -+ ie->ftie, ie->ftie_len); -+ } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { -+ if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { -+ ie->reassoc_deadline = pos; -+ wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " -+ "in EAPOL-Key", -+ ie->reassoc_deadline, pos[1] + 2); -+ } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { -+ ie->key_lifetime = pos; -+ wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " -+ "in EAPOL-Key", -+ ie->key_lifetime, pos[1] + 2); -+ } else { -+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " -+ "EAPOL-Key Key Data IE", -+ pos, 2 + pos[1]); -+ } -+ } else if (*pos == WLAN_EID_LINK_ID) { -+ ie->lnkid = pos; -+ ie->lnkid_len = pos[1] + 2; -+ } else if (*pos == WLAN_EID_EXT_CAPAB) { -+ ie->ext_capab = pos; -+ ie->ext_capab_len = pos[1] + 2; -+ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { -+ ret = wpa_parse_generic(pos, end, ie); -+ if (ret < 0) -+ break; -+ if (ret > 0) { -+ ret = 0; -+ break; -+ } -+ } else { -+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " -+ "Key Data IE", pos, 2 + pos[1]); -+ } -+ } -+ -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.h -new file mode 100644 -index 0000000000000..f939b13d1e743 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/rsn_supp/wpa_ie.h -@@ -0,0 +1,60 @@ -+/* -+ * wpa_supplicant - WPA/RSN IE and KDE definitions -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_IE_H -+#define WPA_IE_H -+ -+struct wpa_sm; -+ -+struct wpa_eapol_ie_parse { -+ const u8 *wpa_ie; -+ size_t wpa_ie_len; -+ const u8 *rsn_ie; -+ size_t rsn_ie_len; -+ const u8 *pmkid; -+ const u8 *gtk; -+ size_t gtk_len; -+ const u8 *mac_addr; -+ size_t mac_addr_len; -+#ifdef CONFIG_PEERKEY -+ const u8 *smk; -+ size_t smk_len; -+ const u8 *nonce; -+ size_t nonce_len; -+ const u8 *lifetime; -+ size_t lifetime_len; -+ const u8 *error; -+ size_t error_len; -+#endif /* CONFIG_PEERKEY */ -+#ifdef CONFIG_IEEE80211W -+ const u8 *igtk; -+ size_t igtk_len; -+#endif /* CONFIG_IEEE80211W */ -+ const u8 *mdie; -+ size_t mdie_len; -+ const u8 *ftie; -+ size_t ftie_len; -+ const u8 *reassoc_deadline; -+ const u8 *key_lifetime; -+ const u8 *lnkid; -+ size_t lnkid_len; -+ const u8 *ext_capab; -+ size_t ext_capab_len; -+}; -+ -+int wpa_supplicant_parse_ies(const u8 *buf, size_t len, -+ struct wpa_eapol_ie_parse *ie); -+int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); -+ -+#endif /* WPA_IE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/.gitignore b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/.gitignore -new file mode 100644 -index 0000000000000..d43242d73390b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/.gitignore -@@ -0,0 +1 @@ -+libtls.a -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/Makefile -new file mode 100644 -index 0000000000000..a2da0965a5f9d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/Makefile -@@ -0,0 +1,37 @@ -+all: libtls.a -+ -+clean: -+ rm -f *~ *.o *.d libtls.a -+ -+install: -+ @echo Nothing to be made. -+ -+ -+include ../lib.rules -+ -+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH -+CFLAGS += -DCONFIG_CRYPTO_INTERNAL -+ -+LIB_OBJS= \ -+ asn1.o \ -+ bignum.o \ -+ pkcs1.o \ -+ pkcs5.o \ -+ pkcs8.o \ -+ rsa.o \ -+ tlsv1_client.o \ -+ tlsv1_client_read.o \ -+ tlsv1_client_write.o \ -+ tlsv1_common.o \ -+ tlsv1_cred.o \ -+ tlsv1_record.o \ -+ tlsv1_server.o \ -+ tlsv1_server_read.o \ -+ tlsv1_server_write.o \ -+ x509v3.o -+ -+ -+libtls.a: $(LIB_OBJS) -+ $(AR) crT $@ $? -+ -+-include $(OBJS:%.o=%.d) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.c -new file mode 100644 -index 0000000000000..3391245fe3cd2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.c -@@ -0,0 +1,212 @@ -+/* -+ * ASN.1 DER parsing -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "asn1.h" -+ -+int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) -+{ -+ const u8 *pos, *end; -+ u8 tmp; -+ -+ os_memset(hdr, 0, sizeof(*hdr)); -+ pos = buf; -+ end = buf + len; -+ -+ hdr->identifier = *pos++; -+ hdr->class = hdr->identifier >> 6; -+ hdr->constructed = !!(hdr->identifier & (1 << 5)); -+ -+ if ((hdr->identifier & 0x1f) == 0x1f) { -+ hdr->tag = 0; -+ do { -+ if (pos >= end) { -+ wpa_printf(MSG_DEBUG, "ASN.1: Identifier " -+ "underflow"); -+ return -1; -+ } -+ tmp = *pos++; -+ wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " -+ "0x%02x", tmp); -+ hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); -+ } while (tmp & 0x80); -+ } else -+ hdr->tag = hdr->identifier & 0x1f; -+ -+ tmp = *pos++; -+ if (tmp & 0x80) { -+ if (tmp == 0xff) { -+ wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " -+ "value 0xff used"); -+ return -1; -+ } -+ tmp &= 0x7f; /* number of subsequent octets */ -+ hdr->length = 0; -+ if (tmp > 4) { -+ wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); -+ return -1; -+ } -+ while (tmp--) { -+ if (pos >= end) { -+ wpa_printf(MSG_DEBUG, "ASN.1: Length " -+ "underflow"); -+ return -1; -+ } -+ hdr->length = (hdr->length << 8) | *pos++; -+ } -+ } else { -+ /* Short form - length 0..127 in one octet */ -+ hdr->length = tmp; -+ } -+ -+ if (end < pos || hdr->length > (unsigned int) (end - pos)) { -+ wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); -+ return -1; -+ } -+ -+ hdr->payload = pos; -+ return 0; -+} -+ -+ -+int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) -+{ -+ const u8 *pos, *end; -+ unsigned long val; -+ u8 tmp; -+ -+ os_memset(oid, 0, sizeof(*oid)); -+ -+ pos = buf; -+ end = buf + len; -+ -+ while (pos < end) { -+ val = 0; -+ -+ do { -+ if (pos >= end) -+ return -1; -+ tmp = *pos++; -+ val = (val << 7) | (tmp & 0x7f); -+ } while (tmp & 0x80); -+ -+ if (oid->len >= ASN1_MAX_OID_LEN) { -+ wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); -+ return -1; -+ } -+ if (oid->len == 0) { -+ /* -+ * The first octet encodes the first two object -+ * identifier components in (X*40) + Y formula. -+ * X = 0..2. -+ */ -+ oid->oid[0] = val / 40; -+ if (oid->oid[0] > 2) -+ oid->oid[0] = 2; -+ oid->oid[1] = val - oid->oid[0] * 40; -+ oid->len = 2; -+ } else -+ oid->oid[oid->len++] = val; -+ } -+ -+ return 0; -+} -+ -+ -+int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, -+ const u8 **next) -+{ -+ struct asn1_hdr hdr; -+ -+ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) -+ return -1; -+ -+ if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { -+ wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " -+ "tag 0x%x", hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ *next = hdr.payload + hdr.length; -+ -+ return asn1_parse_oid(hdr.payload, hdr.length, oid); -+} -+ -+ -+void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) -+{ -+ char *pos = buf; -+ size_t i; -+ int ret; -+ -+ if (len == 0) -+ return; -+ -+ buf[0] = '\0'; -+ -+ for (i = 0; i < oid->len; i++) { -+ ret = os_snprintf(pos, buf + len - pos, -+ "%s%lu", -+ i == 0 ? "" : ".", oid->oid[i]); -+ if (ret < 0 || ret >= buf + len - pos) -+ break; -+ pos += ret; -+ } -+ buf[len - 1] = '\0'; -+} -+ -+ -+static u8 rotate_bits(u8 octet) -+{ -+ int i; -+ u8 res; -+ -+ res = 0; -+ for (i = 0; i < 8; i++) { -+ res <<= 1; -+ if (octet & 1) -+ res |= 1; -+ octet >>= 1; -+ } -+ -+ return res; -+} -+ -+ -+unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) -+{ -+ unsigned long val = 0; -+ const u8 *pos = buf; -+ -+ /* BER requires that unused bits are zero, so we can ignore the number -+ * of unused bits */ -+ pos++; -+ -+ if (len >= 2) -+ val |= rotate_bits(*pos++); -+ if (len >= 3) -+ val |= ((unsigned long) rotate_bits(*pos++)) << 8; -+ if (len >= 4) -+ val |= ((unsigned long) rotate_bits(*pos++)) << 16; -+ if (len >= 5) -+ val |= ((unsigned long) rotate_bits(*pos++)) << 24; -+ if (len >= 6) -+ wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " -+ "(BIT STRING length %lu)", -+ __func__, (unsigned long) len); -+ -+ return val; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.h -new file mode 100644 -index 0000000000000..2ff571ea909d3 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/asn1.h -@@ -0,0 +1,72 @@ -+/* -+ * ASN.1 DER parsing -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef ASN1_H -+#define ASN1_H -+ -+#define ASN1_TAG_EOC 0x00 /* not used with DER */ -+#define ASN1_TAG_BOOLEAN 0x01 -+#define ASN1_TAG_INTEGER 0x02 -+#define ASN1_TAG_BITSTRING 0x03 -+#define ASN1_TAG_OCTETSTRING 0x04 -+#define ASN1_TAG_NULL 0x05 -+#define ASN1_TAG_OID 0x06 -+#define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */ -+#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */ -+#define ASN1_TAG_REAL 0x09 /* not yet parsed */ -+#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */ -+#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */ -+#define ANS1_TAG_RELATIVE_OID 0x0D -+#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */ -+#define ASN1_TAG_SET 0x11 -+#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */ -+#define ASN1_TAG_PRINTABLESTRING 0x13 -+#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */ -+#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */ -+#define ASN1_TAG_IA5STRING 0x16 -+#define ASN1_TAG_UTCTIME 0x17 -+#define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */ -+#define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */ -+#define ASN1_TAG_VISIBLESTRING 0x1A -+#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */ -+#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */ -+#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */ -+ -+#define ASN1_CLASS_UNIVERSAL 0 -+#define ASN1_CLASS_APPLICATION 1 -+#define ASN1_CLASS_CONTEXT_SPECIFIC 2 -+#define ASN1_CLASS_PRIVATE 3 -+ -+ -+struct asn1_hdr { -+ const u8 *payload; -+ u8 identifier, class, constructed; -+ unsigned int tag, length; -+}; -+ -+#define ASN1_MAX_OID_LEN 20 -+struct asn1_oid { -+ unsigned long oid[ASN1_MAX_OID_LEN]; -+ size_t len; -+}; -+ -+ -+int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); -+int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid); -+int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, -+ const u8 **next); -+void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); -+unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); -+ -+#endif /* ASN1_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.c -new file mode 100644 -index 0000000000000..5c0fc62edeb59 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.c -@@ -0,0 +1,230 @@ -+/* -+ * Big number math -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "bignum.h" -+ -+#ifdef CONFIG_INTERNAL_LIBTOMMATH -+#include "libtommath.c" -+#else /* CONFIG_INTERNAL_LIBTOMMATH */ -+#include -+#endif /* CONFIG_INTERNAL_LIBTOMMATH */ -+ -+ -+/* -+ * The current version is just a wrapper for LibTomMath library, so -+ * struct bignum is just typecast to mp_int. -+ */ -+ -+/** -+ * bignum_init - Allocate memory for bignum -+ * Returns: Pointer to allocated bignum or %NULL on failure -+ */ -+struct bignum * bignum_init(void) -+{ -+ struct bignum *n = os_zalloc(sizeof(mp_int)); -+ if (n == NULL) -+ return NULL; -+ if (mp_init((mp_int *) n) != MP_OKAY) { -+ os_free(n); -+ n = NULL; -+ } -+ return n; -+} -+ -+ -+/** -+ * bignum_deinit - Free bignum -+ * @n: Bignum from bignum_init() -+ */ -+void bignum_deinit(struct bignum *n) -+{ -+ if (n) { -+ mp_clear((mp_int *) n); -+ os_free(n); -+ } -+} -+ -+ -+/** -+ * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer -+ * @n: Bignum from bignum_init() -+ * Returns: Length of n if written to a binary buffer -+ */ -+size_t bignum_get_unsigned_bin_len(struct bignum *n) -+{ -+ return mp_unsigned_bin_size((mp_int *) n); -+} -+ -+ -+/** -+ * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum -+ * @n: Bignum from bignum_init() -+ * @buf: Buffer for the binary number -+ * @len: Length of the buffer, can be %NULL if buffer is known to be long -+ * enough. Set to used buffer length on success if not %NULL. -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len) -+{ -+ size_t need = mp_unsigned_bin_size((mp_int *) n); -+ if (len && need > *len) { -+ *len = need; -+ return -1; -+ } -+ if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) { -+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); -+ return -1; -+ } -+ if (len) -+ *len = need; -+ return 0; -+} -+ -+ -+/** -+ * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer -+ * @n: Bignum from bignum_init(); to be set to the given value -+ * @buf: Buffer with unsigned binary value -+ * @len: Length of buf in octets -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len) -+{ -+ if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) { -+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * bignum_cmp - Signed comparison -+ * @a: Bignum from bignum_init() -+ * @b: Bignum from bignum_init() -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_cmp(const struct bignum *a, const struct bignum *b) -+{ -+ return mp_cmp((mp_int *) a, (mp_int *) b); -+} -+ -+ -+/** -+ * bignum_cmd_d - Compare bignum to standard integer -+ * @a: Bignum from bignum_init() -+ * @b: Small integer -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_cmp_d(const struct bignum *a, unsigned long b) -+{ -+ return mp_cmp_d((mp_int *) a, b); -+} -+ -+ -+/** -+ * bignum_add - c = a + b -+ * @a: Bignum from bignum_init() -+ * @b: Bignum from bignum_init() -+ * @c: Bignum from bignum_init(); used to store the result of a + b -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_add(const struct bignum *a, const struct bignum *b, -+ struct bignum *c) -+{ -+ if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { -+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * bignum_sub - c = a - b -+ * @a: Bignum from bignum_init() -+ * @b: Bignum from bignum_init() -+ * @c: Bignum from bignum_init(); used to store the result of a - b -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_sub(const struct bignum *a, const struct bignum *b, -+ struct bignum *c) -+{ -+ if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { -+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * bignum_mul - c = a * b -+ * @a: Bignum from bignum_init() -+ * @b: Bignum from bignum_init() -+ * @c: Bignum from bignum_init(); used to store the result of a * b -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_mul(const struct bignum *a, const struct bignum *b, -+ struct bignum *c) -+{ -+ if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { -+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * bignum_mulmod - d = a * b (mod c) -+ * @a: Bignum from bignum_init() -+ * @b: Bignum from bignum_init() -+ * @c: Bignum from bignum_init(); modulus -+ * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_mulmod(const struct bignum *a, const struct bignum *b, -+ const struct bignum *c, struct bignum *d) -+{ -+ if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) -+ != MP_OKAY) { -+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * bignum_exptmod - Modular exponentiation: d = a^b (mod c) -+ * @a: Bignum from bignum_init(); base -+ * @b: Bignum from bignum_init(); exponent -+ * @c: Bignum from bignum_init(); modulus -+ * @d: Bignum from bignum_init(); used to store the result of a^b (mod c) -+ * Returns: 0 on success, -1 on failure -+ */ -+int bignum_exptmod(const struct bignum *a, const struct bignum *b, -+ const struct bignum *c, struct bignum *d) -+{ -+ if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) -+ != MP_OKAY) { -+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); -+ return -1; -+ } -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.h -new file mode 100644 -index 0000000000000..f25e26783a0ab ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/bignum.h -@@ -0,0 +1,38 @@ -+/* -+ * Big number math -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef BIGNUM_H -+#define BIGNUM_H -+ -+struct bignum; -+ -+struct bignum * bignum_init(void); -+void bignum_deinit(struct bignum *n); -+size_t bignum_get_unsigned_bin_len(struct bignum *n); -+int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); -+int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); -+int bignum_cmp(const struct bignum *a, const struct bignum *b); -+int bignum_cmp_d(const struct bignum *a, unsigned long b); -+int bignum_add(const struct bignum *a, const struct bignum *b, -+ struct bignum *c); -+int bignum_sub(const struct bignum *a, const struct bignum *b, -+ struct bignum *c); -+int bignum_mul(const struct bignum *a, const struct bignum *b, -+ struct bignum *c); -+int bignum_mulmod(const struct bignum *a, const struct bignum *b, -+ const struct bignum *c, struct bignum *d); -+int bignum_exptmod(const struct bignum *a, const struct bignum *b, -+ const struct bignum *c, struct bignum *d); -+ -+#endif /* BIGNUM_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/libtommath.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/libtommath.c -new file mode 100644 -index 0000000000000..2b23f308acb93 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/libtommath.c -@@ -0,0 +1,3381 @@ -+/* -+ * Minimal code for RSA support from LibTomMath 0.41 -+ * http://libtom.org/ -+ * http://libtom.org/files/ltm-0.41.tar.bz2 -+ * This library was released in public domain by Tom St Denis. -+ * -+ * The combination in this file may not use all of the optimized algorithms -+ * from LibTomMath and may be considerable slower than the LibTomMath with its -+ * default settings. The main purpose of having this version here is to make it -+ * easier to build bignum.c wrapper without having to install and build an -+ * external library. -+ * -+ * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this -+ * libtommath.c file instead of using the external LibTomMath library. -+ */ -+ -+#ifndef CHAR_BIT -+#define CHAR_BIT 8 -+#endif -+ -+#define BN_MP_INVMOD_C -+#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would -+ * require BN_MP_EXPTMOD_FAST_C instead */ -+#define BN_S_MP_MUL_DIGS_C -+#define BN_MP_INVMOD_SLOW_C -+#define BN_S_MP_SQR_C -+#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this -+ * would require other than mp_reduce */ -+ -+#ifdef LTM_FAST -+ -+/* Use faster div at the cost of about 1 kB */ -+#define BN_MP_MUL_D_C -+ -+/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */ -+#define BN_MP_EXPTMOD_FAST_C -+#define BN_MP_MONTGOMERY_SETUP_C -+#define BN_FAST_MP_MONTGOMERY_REDUCE_C -+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C -+#define BN_MP_MUL_2_C -+ -+/* Include faster sqr at the cost of about 0.5 kB in code */ -+#define BN_FAST_S_MP_SQR_C -+ -+#else /* LTM_FAST */ -+ -+#define BN_MP_DIV_SMALL -+#define BN_MP_INIT_MULTI_C -+#define BN_MP_CLEAR_MULTI_C -+#define BN_MP_ABS_C -+#endif /* LTM_FAST */ -+ -+/* Current uses do not require support for negative exponent in exptmod, so we -+ * can save about 1.5 kB in leaving out invmod. */ -+#define LTM_NO_NEG_EXP -+ -+/* from tommath.h */ -+ -+#ifndef MIN -+ #define MIN(x,y) ((x)<(y)?(x):(y)) -+#endif -+ -+#ifndef MAX -+ #define MAX(x,y) ((x)>(y)?(x):(y)) -+#endif -+ -+#define OPT_CAST(x) -+ -+typedef unsigned long mp_digit; -+typedef u64 mp_word; -+ -+#define DIGIT_BIT 28 -+#define MP_28BIT -+ -+ -+#define XMALLOC os_malloc -+#define XFREE os_free -+#define XREALLOC os_realloc -+ -+ -+#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) -+ -+#define MP_LT -1 /* less than */ -+#define MP_EQ 0 /* equal to */ -+#define MP_GT 1 /* greater than */ -+ -+#define MP_ZPOS 0 /* positive integer */ -+#define MP_NEG 1 /* negative */ -+ -+#define MP_OKAY 0 /* ok result */ -+#define MP_MEM -2 /* out of mem */ -+#define MP_VAL -3 /* invalid input */ -+ -+#define MP_YES 1 /* yes response */ -+#define MP_NO 0 /* no response */ -+ -+typedef int mp_err; -+ -+/* define this to use lower memory usage routines (exptmods mostly) */ -+#define MP_LOW_MEM -+ -+/* default precision */ -+#ifndef MP_PREC -+ #ifndef MP_LOW_MEM -+ #define MP_PREC 32 /* default digits of precision */ -+ #else -+ #define MP_PREC 8 /* default digits of precision */ -+ #endif -+#endif -+ -+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ -+#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) -+ -+/* the infamous mp_int structure */ -+typedef struct { -+ int used, alloc, sign; -+ mp_digit *dp; -+} mp_int; -+ -+ -+/* ---> Basic Manipulations <--- */ -+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) -+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) -+#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) -+ -+ -+/* prototypes for copied functions */ -+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) -+static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); -+static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); -+static int s_mp_sqr(mp_int * a, mp_int * b); -+static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs); -+ -+static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); -+ -+#ifdef BN_MP_INIT_MULTI_C -+static int mp_init_multi(mp_int *mp, ...); -+#endif -+#ifdef BN_MP_CLEAR_MULTI_C -+static void mp_clear_multi(mp_int *mp, ...); -+#endif -+static int mp_lshd(mp_int * a, int b); -+static void mp_set(mp_int * a, mp_digit b); -+static void mp_clamp(mp_int * a); -+static void mp_exch(mp_int * a, mp_int * b); -+static void mp_rshd(mp_int * a, int b); -+static void mp_zero(mp_int * a); -+static int mp_mod_2d(mp_int * a, int b, mp_int * c); -+static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d); -+static int mp_init_copy(mp_int * a, mp_int * b); -+static int mp_mul_2d(mp_int * a, int b, mp_int * c); -+#ifndef LTM_NO_NEG_EXP -+static int mp_div_2(mp_int * a, mp_int * b); -+static int mp_invmod(mp_int * a, mp_int * b, mp_int * c); -+static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c); -+#endif /* LTM_NO_NEG_EXP */ -+static int mp_copy(mp_int * a, mp_int * b); -+static int mp_count_bits(mp_int * a); -+static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); -+static int mp_mod(mp_int * a, mp_int * b, mp_int * c); -+static int mp_grow(mp_int * a, int size); -+static int mp_cmp_mag(mp_int * a, mp_int * b); -+#ifdef BN_MP_ABS_C -+static int mp_abs(mp_int * a, mp_int * b); -+#endif -+static int mp_sqr(mp_int * a, mp_int * b); -+static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); -+static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); -+static int mp_2expt(mp_int * a, int b); -+static int mp_reduce_setup(mp_int * a, mp_int * b); -+static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu); -+static int mp_init_size(mp_int * a, int size); -+#ifdef BN_MP_EXPTMOD_FAST_C -+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); -+#endif /* BN_MP_EXPTMOD_FAST_C */ -+#ifdef BN_FAST_S_MP_SQR_C -+static int fast_s_mp_sqr (mp_int * a, mp_int * b); -+#endif /* BN_FAST_S_MP_SQR_C */ -+#ifdef BN_MP_MUL_D_C -+static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); -+#endif /* BN_MP_MUL_D_C */ -+ -+ -+ -+/* functions from bn_.c */ -+ -+ -+/* reverse an array, used for radix code */ -+static void bn_reverse (unsigned char *s, int len) -+{ -+ int ix, iy; -+ unsigned char t; -+ -+ ix = 0; -+ iy = len - 1; -+ while (ix < iy) { -+ t = s[ix]; -+ s[ix] = s[iy]; -+ s[iy] = t; -+ ++ix; -+ --iy; -+ } -+} -+ -+ -+/* low level addition, based on HAC pp.594, Algorithm 14.7 */ -+static int s_mp_add (mp_int * a, mp_int * b, mp_int * c) -+{ -+ mp_int *x; -+ int olduse, res, min, max; -+ -+ /* find sizes, we let |a| <= |b| which means we have to sort -+ * them. "x" will point to the input with the most digits -+ */ -+ if (a->used > b->used) { -+ min = b->used; -+ max = a->used; -+ x = a; -+ } else { -+ min = a->used; -+ max = b->used; -+ x = b; -+ } -+ -+ /* init result */ -+ if (c->alloc < max + 1) { -+ if ((res = mp_grow (c, max + 1)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* get old used digit count and set new one */ -+ olduse = c->used; -+ c->used = max + 1; -+ -+ { -+ register mp_digit u, *tmpa, *tmpb, *tmpc; -+ register int i; -+ -+ /* alias for digit pointers */ -+ -+ /* first input */ -+ tmpa = a->dp; -+ -+ /* second input */ -+ tmpb = b->dp; -+ -+ /* destination */ -+ tmpc = c->dp; -+ -+ /* zero the carry */ -+ u = 0; -+ for (i = 0; i < min; i++) { -+ /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ -+ *tmpc = *tmpa++ + *tmpb++ + u; -+ -+ /* U = carry bit of T[i] */ -+ u = *tmpc >> ((mp_digit)DIGIT_BIT); -+ -+ /* take away carry bit from T[i] */ -+ *tmpc++ &= MP_MASK; -+ } -+ -+ /* now copy higher words if any, that is in A+B -+ * if A or B has more digits add those in -+ */ -+ if (min != max) { -+ for (; i < max; i++) { -+ /* T[i] = X[i] + U */ -+ *tmpc = x->dp[i] + u; -+ -+ /* U = carry bit of T[i] */ -+ u = *tmpc >> ((mp_digit)DIGIT_BIT); -+ -+ /* take away carry bit from T[i] */ -+ *tmpc++ &= MP_MASK; -+ } -+ } -+ -+ /* add carry */ -+ *tmpc++ = u; -+ -+ /* clear digits above oldused */ -+ for (i = c->used; i < olduse; i++) { -+ *tmpc++ = 0; -+ } -+ } -+ -+ mp_clamp (c); -+ return MP_OKAY; -+} -+ -+ -+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ -+static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c) -+{ -+ int olduse, res, min, max; -+ -+ /* find sizes */ -+ min = b->used; -+ max = a->used; -+ -+ /* init result */ -+ if (c->alloc < max) { -+ if ((res = mp_grow (c, max)) != MP_OKAY) { -+ return res; -+ } -+ } -+ olduse = c->used; -+ c->used = max; -+ -+ { -+ register mp_digit u, *tmpa, *tmpb, *tmpc; -+ register int i; -+ -+ /* alias for digit pointers */ -+ tmpa = a->dp; -+ tmpb = b->dp; -+ tmpc = c->dp; -+ -+ /* set carry to zero */ -+ u = 0; -+ for (i = 0; i < min; i++) { -+ /* T[i] = A[i] - B[i] - U */ -+ *tmpc = *tmpa++ - *tmpb++ - u; -+ -+ /* U = carry bit of T[i] -+ * Note this saves performing an AND operation since -+ * if a carry does occur it will propagate all the way to the -+ * MSB. As a result a single shift is enough to get the carry -+ */ -+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); -+ -+ /* Clear carry from T[i] */ -+ *tmpc++ &= MP_MASK; -+ } -+ -+ /* now copy higher words if any, e.g. if A has more digits than B */ -+ for (; i < max; i++) { -+ /* T[i] = A[i] - U */ -+ *tmpc = *tmpa++ - u; -+ -+ /* U = carry bit of T[i] */ -+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); -+ -+ /* Clear carry from T[i] */ -+ *tmpc++ &= MP_MASK; -+ } -+ -+ /* clear digits above used (since we may not have grown result above) */ -+ for (i = c->used; i < olduse; i++) { -+ *tmpc++ = 0; -+ } -+ } -+ -+ mp_clamp (c); -+ return MP_OKAY; -+} -+ -+ -+/* init a new mp_int */ -+static int mp_init (mp_int * a) -+{ -+ int i; -+ -+ /* allocate memory required and clear it */ -+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); -+ if (a->dp == NULL) { -+ return MP_MEM; -+ } -+ -+ /* set the digits to zero */ -+ for (i = 0; i < MP_PREC; i++) { -+ a->dp[i] = 0; -+ } -+ -+ /* set the used to zero, allocated digits to the default precision -+ * and sign to positive */ -+ a->used = 0; -+ a->alloc = MP_PREC; -+ a->sign = MP_ZPOS; -+ -+ return MP_OKAY; -+} -+ -+ -+/* clear one (frees) */ -+static void mp_clear (mp_int * a) -+{ -+ int i; -+ -+ /* only do anything if a hasn't been freed previously */ -+ if (a->dp != NULL) { -+ /* first zero the digits */ -+ for (i = 0; i < a->used; i++) { -+ a->dp[i] = 0; -+ } -+ -+ /* free ram */ -+ XFREE(a->dp); -+ -+ /* reset members to make debugging easier */ -+ a->dp = NULL; -+ a->alloc = a->used = 0; -+ a->sign = MP_ZPOS; -+ } -+} -+ -+ -+/* high level addition (handles signs) */ -+static int mp_add (mp_int * a, mp_int * b, mp_int * c) -+{ -+ int sa, sb, res; -+ -+ /* get sign of both inputs */ -+ sa = a->sign; -+ sb = b->sign; -+ -+ /* handle two cases, not four */ -+ if (sa == sb) { -+ /* both positive or both negative */ -+ /* add their magnitudes, copy the sign */ -+ c->sign = sa; -+ res = s_mp_add (a, b, c); -+ } else { -+ /* one positive, the other negative */ -+ /* subtract the one with the greater magnitude from */ -+ /* the one of the lesser magnitude. The result gets */ -+ /* the sign of the one with the greater magnitude. */ -+ if (mp_cmp_mag (a, b) == MP_LT) { -+ c->sign = sb; -+ res = s_mp_sub (b, a, c); -+ } else { -+ c->sign = sa; -+ res = s_mp_sub (a, b, c); -+ } -+ } -+ return res; -+} -+ -+ -+/* high level subtraction (handles signs) */ -+static int mp_sub (mp_int * a, mp_int * b, mp_int * c) -+{ -+ int sa, sb, res; -+ -+ sa = a->sign; -+ sb = b->sign; -+ -+ if (sa != sb) { -+ /* subtract a negative from a positive, OR */ -+ /* subtract a positive from a negative. */ -+ /* In either case, ADD their magnitudes, */ -+ /* and use the sign of the first number. */ -+ c->sign = sa; -+ res = s_mp_add (a, b, c); -+ } else { -+ /* subtract a positive from a positive, OR */ -+ /* subtract a negative from a negative. */ -+ /* First, take the difference between their */ -+ /* magnitudes, then... */ -+ if (mp_cmp_mag (a, b) != MP_LT) { -+ /* Copy the sign from the first */ -+ c->sign = sa; -+ /* The first has a larger or equal magnitude */ -+ res = s_mp_sub (a, b, c); -+ } else { -+ /* The result has the *opposite* sign from */ -+ /* the first number. */ -+ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; -+ /* The second has a larger magnitude */ -+ res = s_mp_sub (b, a, c); -+ } -+ } -+ return res; -+} -+ -+ -+/* high level multiplication (handles sign) */ -+static int mp_mul (mp_int * a, mp_int * b, mp_int * c) -+{ -+ int res, neg; -+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; -+ -+ /* use Toom-Cook? */ -+#ifdef BN_MP_TOOM_MUL_C -+ if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { -+ res = mp_toom_mul(a, b, c); -+ } else -+#endif -+#ifdef BN_MP_KARATSUBA_MUL_C -+ /* use Karatsuba? */ -+ if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { -+ res = mp_karatsuba_mul (a, b, c); -+ } else -+#endif -+ { -+ /* can we use the fast multiplier? -+ * -+ * The fast multiplier can be used if the output will -+ * have less than MP_WARRAY digits and the number of -+ * digits won't affect carry propagation -+ */ -+#ifdef BN_FAST_S_MP_MUL_DIGS_C -+ int digs = a->used + b->used + 1; -+ -+ if ((digs < MP_WARRAY) && -+ MIN(a->used, b->used) <= -+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { -+ res = fast_s_mp_mul_digs (a, b, c, digs); -+ } else -+#endif -+#ifdef BN_S_MP_MUL_DIGS_C -+ res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ -+#else -+#error mp_mul could fail -+ res = MP_VAL; -+#endif -+ -+ } -+ c->sign = (c->used > 0) ? neg : MP_ZPOS; -+ return res; -+} -+ -+ -+/* d = a * b (mod c) */ -+static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -+{ -+ int res; -+ mp_int t; -+ -+ if ((res = mp_init (&t)) != MP_OKAY) { -+ return res; -+ } -+ -+ if ((res = mp_mul (a, b, &t)) != MP_OKAY) { -+ mp_clear (&t); -+ return res; -+ } -+ res = mp_mod (&t, c, d); -+ mp_clear (&t); -+ return res; -+} -+ -+ -+/* c = a mod b, 0 <= c < b */ -+static int mp_mod (mp_int * a, mp_int * b, mp_int * c) -+{ -+ mp_int t; -+ int res; -+ -+ if ((res = mp_init (&t)) != MP_OKAY) { -+ return res; -+ } -+ -+ if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { -+ mp_clear (&t); -+ return res; -+ } -+ -+ if (t.sign != b->sign) { -+ res = mp_add (b, &t, c); -+ } else { -+ res = MP_OKAY; -+ mp_exch (&t, c); -+ } -+ -+ mp_clear (&t); -+ return res; -+} -+ -+ -+/* this is a shell function that calls either the normal or Montgomery -+ * exptmod functions. Originally the call to the montgomery code was -+ * embedded in the normal function but that wasted alot of stack space -+ * for nothing (since 99% of the time the Montgomery code would be called) -+ */ -+static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -+{ -+ int dr = 0; -+ -+ /* modulus P must be positive */ -+ if (P->sign == MP_NEG) { -+ return MP_VAL; -+ } -+ -+ /* if exponent X is negative we have to recurse */ -+ if (X->sign == MP_NEG) { -+#ifdef LTM_NO_NEG_EXP -+ return MP_VAL; -+#else /* LTM_NO_NEG_EXP */ -+#ifdef BN_MP_INVMOD_C -+ mp_int tmpG, tmpX; -+ int err; -+ -+ /* first compute 1/G mod P */ -+ if ((err = mp_init(&tmpG)) != MP_OKAY) { -+ return err; -+ } -+ if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { -+ mp_clear(&tmpG); -+ return err; -+ } -+ -+ /* now get |X| */ -+ if ((err = mp_init(&tmpX)) != MP_OKAY) { -+ mp_clear(&tmpG); -+ return err; -+ } -+ if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { -+ mp_clear_multi(&tmpG, &tmpX, NULL); -+ return err; -+ } -+ -+ /* and now compute (1/G)**|X| instead of G**X [X < 0] */ -+ err = mp_exptmod(&tmpG, &tmpX, P, Y); -+ mp_clear_multi(&tmpG, &tmpX, NULL); -+ return err; -+#else -+#error mp_exptmod would always fail -+ /* no invmod */ -+ return MP_VAL; -+#endif -+#endif /* LTM_NO_NEG_EXP */ -+ } -+ -+/* modified diminished radix reduction */ -+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) -+ if (mp_reduce_is_2k_l(P) == MP_YES) { -+ return s_mp_exptmod(G, X, P, Y, 1); -+ } -+#endif -+ -+#ifdef BN_MP_DR_IS_MODULUS_C -+ /* is it a DR modulus? */ -+ dr = mp_dr_is_modulus(P); -+#else -+ /* default to no */ -+ dr = 0; -+#endif -+ -+#ifdef BN_MP_REDUCE_IS_2K_C -+ /* if not, is it a unrestricted DR modulus? */ -+ if (dr == 0) { -+ mp_reduce_is_2k(P) << 1; -+ } -+#endif -+ -+ /* if the modulus is odd or dr != 0 use the montgomery method */ -+#ifdef BN_MP_EXPTMOD_FAST_C -+ if (mp_isodd (P) == 1 || dr != 0) { -+ return mp_exptmod_fast (G, X, P, Y, dr); -+ } else { -+#endif -+#ifdef BN_S_MP_EXPTMOD_C -+ /* otherwise use the generic Barrett reduction technique */ -+ return s_mp_exptmod (G, X, P, Y, 0); -+#else -+#error mp_exptmod could fail -+ /* no exptmod for evens */ -+ return MP_VAL; -+#endif -+#ifdef BN_MP_EXPTMOD_FAST_C -+ } -+#endif -+} -+ -+ -+/* compare two ints (signed)*/ -+static int mp_cmp (mp_int * a, mp_int * b) -+{ -+ /* compare based on sign */ -+ if (a->sign != b->sign) { -+ if (a->sign == MP_NEG) { -+ return MP_LT; -+ } else { -+ return MP_GT; -+ } -+ } -+ -+ /* compare digits */ -+ if (a->sign == MP_NEG) { -+ /* if negative compare opposite direction */ -+ return mp_cmp_mag(b, a); -+ } else { -+ return mp_cmp_mag(a, b); -+ } -+} -+ -+ -+/* compare a digit */ -+static int mp_cmp_d(mp_int * a, mp_digit b) -+{ -+ /* compare based on sign */ -+ if (a->sign == MP_NEG) { -+ return MP_LT; -+ } -+ -+ /* compare based on magnitude */ -+ if (a->used > 1) { -+ return MP_GT; -+ } -+ -+ /* compare the only digit of a to b */ -+ if (a->dp[0] > b) { -+ return MP_GT; -+ } else if (a->dp[0] < b) { -+ return MP_LT; -+ } else { -+ return MP_EQ; -+ } -+} -+ -+ -+#ifndef LTM_NO_NEG_EXP -+/* hac 14.61, pp608 */ -+static int mp_invmod (mp_int * a, mp_int * b, mp_int * c) -+{ -+ /* b cannot be negative */ -+ if (b->sign == MP_NEG || mp_iszero(b) == 1) { -+ return MP_VAL; -+ } -+ -+#ifdef BN_FAST_MP_INVMOD_C -+ /* if the modulus is odd we can use a faster routine instead */ -+ if (mp_isodd (b) == 1) { -+ return fast_mp_invmod (a, b, c); -+ } -+#endif -+ -+#ifdef BN_MP_INVMOD_SLOW_C -+ return mp_invmod_slow(a, b, c); -+#endif -+ -+#ifndef BN_FAST_MP_INVMOD_C -+#ifndef BN_MP_INVMOD_SLOW_C -+#error mp_invmod would always fail -+#endif -+#endif -+ return MP_VAL; -+} -+#endif /* LTM_NO_NEG_EXP */ -+ -+ -+/* get the size for an unsigned equivalent */ -+static int mp_unsigned_bin_size (mp_int * a) -+{ -+ int size = mp_count_bits (a); -+ return (size / 8 + ((size & 7) != 0 ? 1 : 0)); -+} -+ -+ -+#ifndef LTM_NO_NEG_EXP -+/* hac 14.61, pp608 */ -+static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) -+{ -+ mp_int x, y, u, v, A, B, C, D; -+ int res; -+ -+ /* b cannot be negative */ -+ if (b->sign == MP_NEG || mp_iszero(b) == 1) { -+ return MP_VAL; -+ } -+ -+ /* init temps */ -+ if ((res = mp_init_multi(&x, &y, &u, &v, -+ &A, &B, &C, &D, NULL)) != MP_OKAY) { -+ return res; -+ } -+ -+ /* x = a, y = b */ -+ if ((res = mp_mod(a, b, &x)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ if ((res = mp_copy (b, &y)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ -+ /* 2. [modified] if x,y are both even then return an error! */ -+ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { -+ res = MP_VAL; -+ goto LBL_ERR; -+ } -+ -+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ -+ if ((res = mp_copy (&x, &u)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ if ((res = mp_copy (&y, &v)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ mp_set (&A, 1); -+ mp_set (&D, 1); -+ -+top: -+ /* 4. while u is even do */ -+ while (mp_iseven (&u) == 1) { -+ /* 4.1 u = u/2 */ -+ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ /* 4.2 if A or B is odd then */ -+ if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { -+ /* A = (A+y)/2, B = (B-x)/2 */ -+ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } -+ /* A = A/2, B = B/2 */ -+ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } -+ -+ /* 5. while v is even do */ -+ while (mp_iseven (&v) == 1) { -+ /* 5.1 v = v/2 */ -+ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ /* 5.2 if C or D is odd then */ -+ if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { -+ /* C = (C+y)/2, D = (D-x)/2 */ -+ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } -+ /* C = C/2, D = D/2 */ -+ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } -+ -+ /* 6. if u >= v then */ -+ if (mp_cmp (&u, &v) != MP_LT) { -+ /* u = u - v, A = A - C, B = B - D */ -+ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ -+ if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ -+ if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } else { -+ /* v - v - u, C = C - A, D = D - B */ -+ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ -+ if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ -+ if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } -+ -+ /* if not zero goto step 4 */ -+ if (mp_iszero (&u) == 0) -+ goto top; -+ -+ /* now a = C, b = D, gcd == g*v */ -+ -+ /* if v != 1 then there is no inverse */ -+ if (mp_cmp_d (&v, 1) != MP_EQ) { -+ res = MP_VAL; -+ goto LBL_ERR; -+ } -+ -+ /* if its too low */ -+ while (mp_cmp_d(&C, 0) == MP_LT) { -+ if ((res = mp_add(&C, b, &C)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } -+ -+ /* too big */ -+ while (mp_cmp_mag(&C, b) != MP_LT) { -+ if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { -+ goto LBL_ERR; -+ } -+ } -+ -+ /* C is now the inverse */ -+ mp_exch (&C, c); -+ res = MP_OKAY; -+LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); -+ return res; -+} -+#endif /* LTM_NO_NEG_EXP */ -+ -+ -+/* compare maginitude of two ints (unsigned) */ -+static int mp_cmp_mag (mp_int * a, mp_int * b) -+{ -+ int n; -+ mp_digit *tmpa, *tmpb; -+ -+ /* compare based on # of non-zero digits */ -+ if (a->used > b->used) { -+ return MP_GT; -+ } -+ -+ if (a->used < b->used) { -+ return MP_LT; -+ } -+ -+ /* alias for a */ -+ tmpa = a->dp + (a->used - 1); -+ -+ /* alias for b */ -+ tmpb = b->dp + (a->used - 1); -+ -+ /* compare based on digits */ -+ for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { -+ if (*tmpa > *tmpb) { -+ return MP_GT; -+ } -+ -+ if (*tmpa < *tmpb) { -+ return MP_LT; -+ } -+ } -+ return MP_EQ; -+} -+ -+ -+/* reads a unsigned char array, assumes the msb is stored first [big endian] */ -+static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) -+{ -+ int res; -+ -+ /* make sure there are at least two digits */ -+ if (a->alloc < 2) { -+ if ((res = mp_grow(a, 2)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* zero the int */ -+ mp_zero (a); -+ -+ /* read the bytes in */ -+ while (c-- > 0) { -+ if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { -+ return res; -+ } -+ -+#ifndef MP_8BIT -+ a->dp[0] |= *b++; -+ a->used += 1; -+#else -+ a->dp[0] = (*b & MP_MASK); -+ a->dp[1] |= ((*b++ >> 7U) & 1); -+ a->used += 2; -+#endif -+ } -+ mp_clamp (a); -+ return MP_OKAY; -+} -+ -+ -+/* store in unsigned [big endian] format */ -+static int mp_to_unsigned_bin (mp_int * a, unsigned char *b) -+{ -+ int x, res; -+ mp_int t; -+ -+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) { -+ return res; -+ } -+ -+ x = 0; -+ while (mp_iszero (&t) == 0) { -+#ifndef MP_8BIT -+ b[x++] = (unsigned char) (t.dp[0] & 255); -+#else -+ b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); -+#endif -+ if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { -+ mp_clear (&t); -+ return res; -+ } -+ } -+ bn_reverse (b, x); -+ mp_clear (&t); -+ return MP_OKAY; -+} -+ -+ -+/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ -+static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) -+{ -+ mp_digit D, r, rr; -+ int x, res; -+ mp_int t; -+ -+ -+ /* if the shift count is <= 0 then we do no work */ -+ if (b <= 0) { -+ res = mp_copy (a, c); -+ if (d != NULL) { -+ mp_zero (d); -+ } -+ return res; -+ } -+ -+ if ((res = mp_init (&t)) != MP_OKAY) { -+ return res; -+ } -+ -+ /* get the remainder */ -+ if (d != NULL) { -+ if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { -+ mp_clear (&t); -+ return res; -+ } -+ } -+ -+ /* copy */ -+ if ((res = mp_copy (a, c)) != MP_OKAY) { -+ mp_clear (&t); -+ return res; -+ } -+ -+ /* shift by as many digits in the bit count */ -+ if (b >= (int)DIGIT_BIT) { -+ mp_rshd (c, b / DIGIT_BIT); -+ } -+ -+ /* shift any bit count < DIGIT_BIT */ -+ D = (mp_digit) (b % DIGIT_BIT); -+ if (D != 0) { -+ register mp_digit *tmpc, mask, shift; -+ -+ /* mask */ -+ mask = (((mp_digit)1) << D) - 1; -+ -+ /* shift for lsb */ -+ shift = DIGIT_BIT - D; -+ -+ /* alias */ -+ tmpc = c->dp + (c->used - 1); -+ -+ /* carry */ -+ r = 0; -+ for (x = c->used - 1; x >= 0; x--) { -+ /* get the lower bits of this word in a temp */ -+ rr = *tmpc & mask; -+ -+ /* shift the current word and mix in the carry bits from the previous word */ -+ *tmpc = (*tmpc >> D) | (r << shift); -+ --tmpc; -+ -+ /* set the carry to the carry bits of the current word found above */ -+ r = rr; -+ } -+ } -+ mp_clamp (c); -+ if (d != NULL) { -+ mp_exch (&t, d); -+ } -+ mp_clear (&t); -+ return MP_OKAY; -+} -+ -+ -+static int mp_init_copy (mp_int * a, mp_int * b) -+{ -+ int res; -+ -+ if ((res = mp_init (a)) != MP_OKAY) { -+ return res; -+ } -+ return mp_copy (b, a); -+} -+ -+ -+/* set to zero */ -+static void mp_zero (mp_int * a) -+{ -+ int n; -+ mp_digit *tmp; -+ -+ a->sign = MP_ZPOS; -+ a->used = 0; -+ -+ tmp = a->dp; -+ for (n = 0; n < a->alloc; n++) { -+ *tmp++ = 0; -+ } -+} -+ -+ -+/* copy, b = a */ -+static int mp_copy (mp_int * a, mp_int * b) -+{ -+ int res, n; -+ -+ /* if dst == src do nothing */ -+ if (a == b) { -+ return MP_OKAY; -+ } -+ -+ /* grow dest */ -+ if (b->alloc < a->used) { -+ if ((res = mp_grow (b, a->used)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* zero b and copy the parameters over */ -+ { -+ register mp_digit *tmpa, *tmpb; -+ -+ /* pointer aliases */ -+ -+ /* source */ -+ tmpa = a->dp; -+ -+ /* destination */ -+ tmpb = b->dp; -+ -+ /* copy all the digits */ -+ for (n = 0; n < a->used; n++) { -+ *tmpb++ = *tmpa++; -+ } -+ -+ /* clear high digits */ -+ for (; n < b->used; n++) { -+ *tmpb++ = 0; -+ } -+ } -+ -+ /* copy used count and sign */ -+ b->used = a->used; -+ b->sign = a->sign; -+ return MP_OKAY; -+} -+ -+ -+/* shift right a certain amount of digits */ -+static void mp_rshd (mp_int * a, int b) -+{ -+ int x; -+ -+ /* if b <= 0 then ignore it */ -+ if (b <= 0) { -+ return; -+ } -+ -+ /* if b > used then simply zero it and return */ -+ if (a->used <= b) { -+ mp_zero (a); -+ return; -+ } -+ -+ { -+ register mp_digit *bottom, *top; -+ -+ /* shift the digits down */ -+ -+ /* bottom */ -+ bottom = a->dp; -+ -+ /* top [offset into digits] */ -+ top = a->dp + b; -+ -+ /* this is implemented as a sliding window where -+ * the window is b-digits long and digits from -+ * the top of the window are copied to the bottom -+ * -+ * e.g. -+ -+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> -+ /\ | ----> -+ \-------------------/ ----> -+ */ -+ for (x = 0; x < (a->used - b); x++) { -+ *bottom++ = *top++; -+ } -+ -+ /* zero the top digits */ -+ for (; x < a->used; x++) { -+ *bottom++ = 0; -+ } -+ } -+ -+ /* remove excess digits */ -+ a->used -= b; -+} -+ -+ -+/* swap the elements of two integers, for cases where you can't simply swap the -+ * mp_int pointers around -+ */ -+static void mp_exch (mp_int * a, mp_int * b) -+{ -+ mp_int t; -+ -+ t = *a; -+ *a = *b; -+ *b = t; -+} -+ -+ -+/* trim unused digits -+ * -+ * This is used to ensure that leading zero digits are -+ * trimed and the leading "used" digit will be non-zero -+ * Typically very fast. Also fixes the sign if there -+ * are no more leading digits -+ */ -+static void mp_clamp (mp_int * a) -+{ -+ /* decrease used while the most significant digit is -+ * zero. -+ */ -+ while (a->used > 0 && a->dp[a->used - 1] == 0) { -+ --(a->used); -+ } -+ -+ /* reset the sign flag if used == 0 */ -+ if (a->used == 0) { -+ a->sign = MP_ZPOS; -+ } -+} -+ -+ -+/* grow as required */ -+static int mp_grow (mp_int * a, int size) -+{ -+ int i; -+ mp_digit *tmp; -+ -+ /* if the alloc size is smaller alloc more ram */ -+ if (a->alloc < size) { -+ /* ensure there are always at least MP_PREC digits extra on top */ -+ size += (MP_PREC * 2) - (size % MP_PREC); -+ -+ /* reallocate the array a->dp -+ * -+ * We store the return in a temporary variable -+ * in case the operation failed we don't want -+ * to overwrite the dp member of a. -+ */ -+ tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); -+ if (tmp == NULL) { -+ /* reallocation failed but "a" is still valid [can be freed] */ -+ return MP_MEM; -+ } -+ -+ /* reallocation succeeded so set a->dp */ -+ a->dp = tmp; -+ -+ /* zero excess digits */ -+ i = a->alloc; -+ a->alloc = size; -+ for (; i < a->alloc; i++) { -+ a->dp[i] = 0; -+ } -+ } -+ return MP_OKAY; -+} -+ -+ -+#ifdef BN_MP_ABS_C -+/* b = |a| -+ * -+ * Simple function copies the input and fixes the sign to positive -+ */ -+static int mp_abs (mp_int * a, mp_int * b) -+{ -+ int res; -+ -+ /* copy a to b */ -+ if (a != b) { -+ if ((res = mp_copy (a, b)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* force the sign of b to positive */ -+ b->sign = MP_ZPOS; -+ -+ return MP_OKAY; -+} -+#endif -+ -+ -+/* set to a digit */ -+static void mp_set (mp_int * a, mp_digit b) -+{ -+ mp_zero (a); -+ a->dp[0] = b & MP_MASK; -+ a->used = (a->dp[0] != 0) ? 1 : 0; -+} -+ -+ -+#ifndef LTM_NO_NEG_EXP -+/* b = a/2 */ -+static int mp_div_2(mp_int * a, mp_int * b) -+{ -+ int x, res, oldused; -+ -+ /* copy */ -+ if (b->alloc < a->used) { -+ if ((res = mp_grow (b, a->used)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ oldused = b->used; -+ b->used = a->used; -+ { -+ register mp_digit r, rr, *tmpa, *tmpb; -+ -+ /* source alias */ -+ tmpa = a->dp + b->used - 1; -+ -+ /* dest alias */ -+ tmpb = b->dp + b->used - 1; -+ -+ /* carry */ -+ r = 0; -+ for (x = b->used - 1; x >= 0; x--) { -+ /* get the carry for the next iteration */ -+ rr = *tmpa & 1; -+ -+ /* shift the current digit, add in carry and store */ -+ *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); -+ -+ /* forward carry to next iteration */ -+ r = rr; -+ } -+ -+ /* zero excess digits */ -+ tmpb = b->dp + b->used; -+ for (x = b->used; x < oldused; x++) { -+ *tmpb++ = 0; -+ } -+ } -+ b->sign = a->sign; -+ mp_clamp (b); -+ return MP_OKAY; -+} -+#endif /* LTM_NO_NEG_EXP */ -+ -+ -+/* shift left by a certain bit count */ -+static int mp_mul_2d (mp_int * a, int b, mp_int * c) -+{ -+ mp_digit d; -+ int res; -+ -+ /* copy */ -+ if (a != c) { -+ if ((res = mp_copy (a, c)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { -+ if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* shift by as many digits in the bit count */ -+ if (b >= (int)DIGIT_BIT) { -+ if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* shift any bit count < DIGIT_BIT */ -+ d = (mp_digit) (b % DIGIT_BIT); -+ if (d != 0) { -+ register mp_digit *tmpc, shift, mask, r, rr; -+ register int x; -+ -+ /* bitmask for carries */ -+ mask = (((mp_digit)1) << d) - 1; -+ -+ /* shift for msbs */ -+ shift = DIGIT_BIT - d; -+ -+ /* alias */ -+ tmpc = c->dp; -+ -+ /* carry */ -+ r = 0; -+ for (x = 0; x < c->used; x++) { -+ /* get the higher bits of the current word */ -+ rr = (*tmpc >> shift) & mask; -+ -+ /* shift the current word and OR in the carry */ -+ *tmpc = ((*tmpc << d) | r) & MP_MASK; -+ ++tmpc; -+ -+ /* set the carry to the carry bits of the current word */ -+ r = rr; -+ } -+ -+ /* set final carry */ -+ if (r != 0) { -+ c->dp[(c->used)++] = r; -+ } -+ } -+ mp_clamp (c); -+ return MP_OKAY; -+} -+ -+ -+#ifdef BN_MP_INIT_MULTI_C -+static int mp_init_multi(mp_int *mp, ...) -+{ -+ mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ -+ int n = 0; /* Number of ok inits */ -+ mp_int* cur_arg = mp; -+ va_list args; -+ -+ va_start(args, mp); /* init args to next argument from caller */ -+ while (cur_arg != NULL) { -+ if (mp_init(cur_arg) != MP_OKAY) { -+ /* Oops - error! Back-track and mp_clear what we already -+ succeeded in init-ing, then return error. -+ */ -+ va_list clean_args; -+ -+ /* end the current list */ -+ va_end(args); -+ -+ /* now start cleaning up */ -+ cur_arg = mp; -+ va_start(clean_args, mp); -+ while (n--) { -+ mp_clear(cur_arg); -+ cur_arg = va_arg(clean_args, mp_int*); -+ } -+ va_end(clean_args); -+ res = MP_MEM; -+ break; -+ } -+ n++; -+ cur_arg = va_arg(args, mp_int*); -+ } -+ va_end(args); -+ return res; /* Assumed ok, if error flagged above. */ -+} -+#endif -+ -+ -+#ifdef BN_MP_CLEAR_MULTI_C -+static void mp_clear_multi(mp_int *mp, ...) -+{ -+ mp_int* next_mp = mp; -+ va_list args; -+ va_start(args, mp); -+ while (next_mp != NULL) { -+ mp_clear(next_mp); -+ next_mp = va_arg(args, mp_int*); -+ } -+ va_end(args); -+} -+#endif -+ -+ -+/* shift left a certain amount of digits */ -+static int mp_lshd (mp_int * a, int b) -+{ -+ int x, res; -+ -+ /* if its less than zero return */ -+ if (b <= 0) { -+ return MP_OKAY; -+ } -+ -+ /* grow to fit the new digits */ -+ if (a->alloc < a->used + b) { -+ if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ { -+ register mp_digit *top, *bottom; -+ -+ /* increment the used by the shift amount then copy upwards */ -+ a->used += b; -+ -+ /* top */ -+ top = a->dp + a->used - 1; -+ -+ /* base */ -+ bottom = a->dp + a->used - 1 - b; -+ -+ /* much like mp_rshd this is implemented using a sliding window -+ * except the window goes the otherway around. Copying from -+ * the bottom to the top. see bn_mp_rshd.c for more info. -+ */ -+ for (x = a->used - 1; x >= b; x--) { -+ *top-- = *bottom--; -+ } -+ -+ /* zero the lower digits */ -+ top = a->dp; -+ for (x = 0; x < b; x++) { -+ *top++ = 0; -+ } -+ } -+ return MP_OKAY; -+} -+ -+ -+/* returns the number of bits in an int */ -+static int mp_count_bits (mp_int * a) -+{ -+ int r; -+ mp_digit q; -+ -+ /* shortcut */ -+ if (a->used == 0) { -+ return 0; -+ } -+ -+ /* get number of digits and add that */ -+ r = (a->used - 1) * DIGIT_BIT; -+ -+ /* take the last digit and count the bits in it */ -+ q = a->dp[a->used - 1]; -+ while (q > ((mp_digit) 0)) { -+ ++r; -+ q >>= ((mp_digit) 1); -+ } -+ return r; -+} -+ -+ -+/* calc a value mod 2**b */ -+static int mp_mod_2d (mp_int * a, int b, mp_int * c) -+{ -+ int x, res; -+ -+ /* if b is <= 0 then zero the int */ -+ if (b <= 0) { -+ mp_zero (c); -+ return MP_OKAY; -+ } -+ -+ /* if the modulus is larger than the value than return */ -+ if (b >= (int) (a->used * DIGIT_BIT)) { -+ res = mp_copy (a, c); -+ return res; -+ } -+ -+ /* copy */ -+ if ((res = mp_copy (a, c)) != MP_OKAY) { -+ return res; -+ } -+ -+ /* zero digits above the last digit of the modulus */ -+ for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { -+ c->dp[x] = 0; -+ } -+ /* clear the digit that is not completely outside/inside the modulus */ -+ c->dp[b / DIGIT_BIT] &= -+ (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); -+ mp_clamp (c); -+ return MP_OKAY; -+} -+ -+ -+#ifdef BN_MP_DIV_SMALL -+ -+/* slower bit-bang division... also smaller */ -+static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) -+{ -+ mp_int ta, tb, tq, q; -+ int res, n, n2; -+ -+ /* is divisor zero ? */ -+ if (mp_iszero (b) == 1) { -+ return MP_VAL; -+ } -+ -+ /* if a < b then q=0, r = a */ -+ if (mp_cmp_mag (a, b) == MP_LT) { -+ if (d != NULL) { -+ res = mp_copy (a, d); -+ } else { -+ res = MP_OKAY; -+ } -+ if (c != NULL) { -+ mp_zero (c); -+ } -+ return res; -+ } -+ -+ /* init our temps */ -+ if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { -+ return res; -+ } -+ -+ -+ mp_set(&tq, 1); -+ n = mp_count_bits(a) - mp_count_bits(b); -+ if (((res = mp_abs(a, &ta)) != MP_OKAY) || -+ ((res = mp_abs(b, &tb)) != MP_OKAY) || -+ ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || -+ ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { -+ goto LBL_ERR; -+ } -+ -+ while (n-- >= 0) { -+ if (mp_cmp(&tb, &ta) != MP_GT) { -+ if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || -+ ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { -+ goto LBL_ERR; -+ } -+ } -+ if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || -+ ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { -+ goto LBL_ERR; -+ } -+ } -+ -+ /* now q == quotient and ta == remainder */ -+ n = a->sign; -+ n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); -+ if (c != NULL) { -+ mp_exch(c, &q); -+ c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; -+ } -+ if (d != NULL) { -+ mp_exch(d, &ta); -+ d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; -+ } -+LBL_ERR: -+ mp_clear_multi(&ta, &tb, &tq, &q, NULL); -+ return res; -+} -+ -+#else -+ -+/* integer signed division. -+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder] -+ * HAC pp.598 Algorithm 14.20 -+ * -+ * Note that the description in HAC is horribly -+ * incomplete. For example, it doesn't consider -+ * the case where digits are removed from 'x' in -+ * the inner loop. It also doesn't consider the -+ * case that y has fewer than three digits, etc.. -+ * -+ * The overall algorithm is as described as -+ * 14.20 from HAC but fixed to treat these cases. -+*/ -+static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) -+{ -+ mp_int q, x, y, t1, t2; -+ int res, n, t, i, norm, neg; -+ -+ /* is divisor zero ? */ -+ if (mp_iszero (b) == 1) { -+ return MP_VAL; -+ } -+ -+ /* if a < b then q=0, r = a */ -+ if (mp_cmp_mag (a, b) == MP_LT) { -+ if (d != NULL) { -+ res = mp_copy (a, d); -+ } else { -+ res = MP_OKAY; -+ } -+ if (c != NULL) { -+ mp_zero (c); -+ } -+ return res; -+ } -+ -+ if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { -+ return res; -+ } -+ q.used = a->used + 2; -+ -+ if ((res = mp_init (&t1)) != MP_OKAY) { -+ goto LBL_Q; -+ } -+ -+ if ((res = mp_init (&t2)) != MP_OKAY) { -+ goto LBL_T1; -+ } -+ -+ if ((res = mp_init_copy (&x, a)) != MP_OKAY) { -+ goto LBL_T2; -+ } -+ -+ if ((res = mp_init_copy (&y, b)) != MP_OKAY) { -+ goto LBL_X; -+ } -+ -+ /* fix the sign */ -+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; -+ x.sign = y.sign = MP_ZPOS; -+ -+ /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ -+ norm = mp_count_bits(&y) % DIGIT_BIT; -+ if (norm < (int)(DIGIT_BIT-1)) { -+ norm = (DIGIT_BIT-1) - norm; -+ if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ } else { -+ norm = 0; -+ } -+ -+ /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ -+ n = x.used - 1; -+ t = y.used - 1; -+ -+ /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ -+ if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ -+ goto LBL_Y; -+ } -+ -+ while (mp_cmp (&x, &y) != MP_LT) { -+ ++(q.dp[n - t]); -+ if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ } -+ -+ /* reset y by shifting it back down */ -+ mp_rshd (&y, n - t); -+ -+ /* step 3. for i from n down to (t + 1) */ -+ for (i = n; i >= (t + 1); i--) { -+ if (i > x.used) { -+ continue; -+ } -+ -+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1, -+ * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ -+ if (x.dp[i] == y.dp[t]) { -+ q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); -+ } else { -+ mp_word tmp; -+ tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); -+ tmp |= ((mp_word) x.dp[i - 1]); -+ tmp /= ((mp_word) y.dp[t]); -+ if (tmp > (mp_word) MP_MASK) -+ tmp = MP_MASK; -+ q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); -+ } -+ -+ /* while (q{i-t-1} * (yt * b + y{t-1})) > -+ xi * b**2 + xi-1 * b + xi-2 -+ -+ do q{i-t-1} -= 1; -+ */ -+ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; -+ do { -+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; -+ -+ /* find left hand */ -+ mp_zero (&t1); -+ t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; -+ t1.dp[1] = y.dp[t]; -+ t1.used = 2; -+ if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ -+ /* find right hand */ -+ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; -+ t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; -+ t2.dp[2] = x.dp[i]; -+ t2.used = 3; -+ } while (mp_cmp_mag(&t1, &t2) == MP_GT); -+ -+ /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ -+ if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ -+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ -+ if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ -+ /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ -+ if (x.sign == MP_NEG) { -+ if ((res = mp_copy (&y, &t1)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { -+ goto LBL_Y; -+ } -+ -+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; -+ } -+ } -+ -+ /* now q is the quotient and x is the remainder -+ * [which we have to normalize] -+ */ -+ -+ /* get sign before writing to c */ -+ x.sign = x.used == 0 ? MP_ZPOS : a->sign; -+ -+ if (c != NULL) { -+ mp_clamp (&q); -+ mp_exch (&q, c); -+ c->sign = neg; -+ } -+ -+ if (d != NULL) { -+ mp_div_2d (&x, norm, &x, NULL); -+ mp_exch (&x, d); -+ } -+ -+ res = MP_OKAY; -+ -+LBL_Y:mp_clear (&y); -+LBL_X:mp_clear (&x); -+LBL_T2:mp_clear (&t2); -+LBL_T1:mp_clear (&t1); -+LBL_Q:mp_clear (&q); -+ return res; -+} -+ -+#endif -+ -+ -+#ifdef MP_LOW_MEM -+ #define TAB_SIZE 32 -+#else -+ #define TAB_SIZE 256 -+#endif -+ -+static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) -+{ -+ mp_int M[TAB_SIZE], res, mu; -+ mp_digit buf; -+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; -+ int (*redux)(mp_int*,mp_int*,mp_int*); -+ -+ /* find window size */ -+ x = mp_count_bits (X); -+ if (x <= 7) { -+ winsize = 2; -+ } else if (x <= 36) { -+ winsize = 3; -+ } else if (x <= 140) { -+ winsize = 4; -+ } else if (x <= 450) { -+ winsize = 5; -+ } else if (x <= 1303) { -+ winsize = 6; -+ } else if (x <= 3529) { -+ winsize = 7; -+ } else { -+ winsize = 8; -+ } -+ -+#ifdef MP_LOW_MEM -+ if (winsize > 5) { -+ winsize = 5; -+ } -+#endif -+ -+ /* init M array */ -+ /* init first cell */ -+ if ((err = mp_init(&M[1])) != MP_OKAY) { -+ return err; -+ } -+ -+ /* now init the second half of the array */ -+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { -+ if ((err = mp_init(&M[x])) != MP_OKAY) { -+ for (y = 1<<(winsize-1); y < x; y++) { -+ mp_clear (&M[y]); -+ } -+ mp_clear(&M[1]); -+ return err; -+ } -+ } -+ -+ /* create mu, used for Barrett reduction */ -+ if ((err = mp_init (&mu)) != MP_OKAY) { -+ goto LBL_M; -+ } -+ -+ if (redmode == 0) { -+ if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ redux = mp_reduce; -+ } else { -+ if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ redux = mp_reduce_2k_l; -+ } -+ -+ /* create M table -+ * -+ * The M table contains powers of the base, -+ * e.g. M[x] = G**x mod P -+ * -+ * The first half of the table is not -+ * computed though accept for M[0] and M[1] -+ */ -+ if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ -+ /* compute the value at M[1<<(winsize-1)] by squaring -+ * M[1] (winsize-1) times -+ */ -+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ -+ for (x = 0; x < (winsize - 1); x++) { -+ /* square it */ -+ if ((err = mp_sqr (&M[1 << (winsize - 1)], -+ &M[1 << (winsize - 1)])) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ -+ /* reduce modulo P */ -+ if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ } -+ -+ /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) -+ * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) -+ */ -+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { -+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ } -+ -+ /* setup result */ -+ if ((err = mp_init (&res)) != MP_OKAY) { -+ goto LBL_MU; -+ } -+ mp_set (&res, 1); -+ -+ /* set initial mode and bit cnt */ -+ mode = 0; -+ bitcnt = 1; -+ buf = 0; -+ digidx = X->used - 1; -+ bitcpy = 0; -+ bitbuf = 0; -+ -+ for (;;) { -+ /* grab next digit as required */ -+ if (--bitcnt == 0) { -+ /* if digidx == -1 we are out of digits */ -+ if (digidx == -1) { -+ break; -+ } -+ /* read next digit and reset the bitcnt */ -+ buf = X->dp[digidx--]; -+ bitcnt = (int) DIGIT_BIT; -+ } -+ -+ /* grab the next msb from the exponent */ -+ y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; -+ buf <<= (mp_digit)1; -+ -+ /* if the bit is zero and mode == 0 then we ignore it -+ * These represent the leading zero bits before the first 1 bit -+ * in the exponent. Technically this opt is not required but it -+ * does lower the # of trivial squaring/reductions used -+ */ -+ if (mode == 0 && y == 0) { -+ continue; -+ } -+ -+ /* if the bit is zero and mode == 1 then we square */ -+ if (mode == 1 && y == 0) { -+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, &mu)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ continue; -+ } -+ -+ /* else we add it to the window */ -+ bitbuf |= (y << (winsize - ++bitcpy)); -+ mode = 2; -+ -+ if (bitcpy == winsize) { -+ /* ok window is filled so square as required and multiply */ -+ /* square first */ -+ for (x = 0; x < winsize; x++) { -+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, &mu)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ -+ /* then multiply */ -+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, &mu)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ -+ /* empty window and reset */ -+ bitcpy = 0; -+ bitbuf = 0; -+ mode = 1; -+ } -+ } -+ -+ /* if bits remain then square/multiply */ -+ if (mode == 2 && bitcpy > 0) { -+ /* square then multiply if the bit is set */ -+ for (x = 0; x < bitcpy; x++) { -+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, &mu)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ -+ bitbuf <<= 1; -+ if ((bitbuf & (1 << winsize)) != 0) { -+ /* then multiply */ -+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, &mu)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ } -+ } -+ -+ mp_exch (&res, Y); -+ err = MP_OKAY; -+LBL_RES:mp_clear (&res); -+LBL_MU:mp_clear (&mu); -+LBL_M: -+ mp_clear(&M[1]); -+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { -+ mp_clear (&M[x]); -+ } -+ return err; -+} -+ -+ -+/* computes b = a*a */ -+static int mp_sqr (mp_int * a, mp_int * b) -+{ -+ int res; -+ -+#ifdef BN_MP_TOOM_SQR_C -+ /* use Toom-Cook? */ -+ if (a->used >= TOOM_SQR_CUTOFF) { -+ res = mp_toom_sqr(a, b); -+ /* Karatsuba? */ -+ } else -+#endif -+#ifdef BN_MP_KARATSUBA_SQR_C -+if (a->used >= KARATSUBA_SQR_CUTOFF) { -+ res = mp_karatsuba_sqr (a, b); -+ } else -+#endif -+ { -+#ifdef BN_FAST_S_MP_SQR_C -+ /* can we use the fast comba multiplier? */ -+ if ((a->used * 2 + 1) < MP_WARRAY && -+ a->used < -+ (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { -+ res = fast_s_mp_sqr (a, b); -+ } else -+#endif -+#ifdef BN_S_MP_SQR_C -+ res = s_mp_sqr (a, b); -+#else -+#error mp_sqr could fail -+ res = MP_VAL; -+#endif -+ } -+ b->sign = MP_ZPOS; -+ return res; -+} -+ -+ -+/* reduces a modulo n where n is of the form 2**p - d -+ This differs from reduce_2k since "d" can be larger -+ than a single digit. -+*/ -+static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) -+{ -+ mp_int q; -+ int p, res; -+ -+ if ((res = mp_init(&q)) != MP_OKAY) { -+ return res; -+ } -+ -+ p = mp_count_bits(n); -+top: -+ /* q = a/2**p, a = a mod 2**p */ -+ if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { -+ goto ERR; -+ } -+ -+ /* q = q * d */ -+ if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { -+ goto ERR; -+ } -+ -+ /* a = a + q */ -+ if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { -+ goto ERR; -+ } -+ -+ if (mp_cmp_mag(a, n) != MP_LT) { -+ s_mp_sub(a, n, a); -+ goto top; -+ } -+ -+ERR: -+ mp_clear(&q); -+ return res; -+} -+ -+ -+/* determines the setup value */ -+static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) -+{ -+ int res; -+ mp_int tmp; -+ -+ if ((res = mp_init(&tmp)) != MP_OKAY) { -+ return res; -+ } -+ -+ if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { -+ goto ERR; -+ } -+ -+ if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { -+ goto ERR; -+ } -+ -+ERR: -+ mp_clear(&tmp); -+ return res; -+} -+ -+ -+/* computes a = 2**b -+ * -+ * Simple algorithm which zeroes the int, grows it then just sets one bit -+ * as required. -+ */ -+static int mp_2expt (mp_int * a, int b) -+{ -+ int res; -+ -+ /* zero a as per default */ -+ mp_zero (a); -+ -+ /* grow a to accomodate the single bit */ -+ if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { -+ return res; -+ } -+ -+ /* set the used count of where the bit will go */ -+ a->used = b / DIGIT_BIT + 1; -+ -+ /* put the single bit in its place */ -+ a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); -+ -+ return MP_OKAY; -+} -+ -+ -+/* pre-calculate the value required for Barrett reduction -+ * For a given modulus "b" it calulates the value required in "a" -+ */ -+static int mp_reduce_setup (mp_int * a, mp_int * b) -+{ -+ int res; -+ -+ if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { -+ return res; -+ } -+ return mp_div (a, b, a, NULL); -+} -+ -+ -+/* reduces x mod m, assumes 0 < x < m**2, mu is -+ * precomputed via mp_reduce_setup. -+ * From HAC pp.604 Algorithm 14.42 -+ */ -+static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) -+{ -+ mp_int q; -+ int res, um = m->used; -+ -+ /* q = x */ -+ if ((res = mp_init_copy (&q, x)) != MP_OKAY) { -+ return res; -+ } -+ -+ /* q1 = x / b**(k-1) */ -+ mp_rshd (&q, um - 1); -+ -+ /* according to HAC this optimization is ok */ -+ if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { -+ if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+ } else { -+#ifdef BN_S_MP_MUL_HIGH_DIGS_C -+ if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) -+ if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+#else -+ { -+#error mp_reduce would always fail -+ res = MP_VAL; -+ goto CLEANUP; -+ } -+#endif -+ } -+ -+ /* q3 = q2 / b**(k+1) */ -+ mp_rshd (&q, um + 1); -+ -+ /* x = x mod b**(k+1), quick (no division) */ -+ if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+ -+ /* q = q * m mod b**(k+1), quick (no division) */ -+ if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+ -+ /* x = x - q */ -+ if ((res = mp_sub (x, &q, x)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+ -+ /* If x < 0, add b**(k+1) to it */ -+ if (mp_cmp_d (x, 0) == MP_LT) { -+ mp_set (&q, 1); -+ if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+ if ((res = mp_add (x, &q, x)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+ } -+ -+ /* Back off if it's too big */ -+ while (mp_cmp (x, m) != MP_LT) { -+ if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { -+ goto CLEANUP; -+ } -+ } -+ -+CLEANUP: -+ mp_clear (&q); -+ -+ return res; -+} -+ -+ -+/* multiplies |a| * |b| and only computes upto digs digits of result -+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how -+ * many digits of output are created. -+ */ -+static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -+{ -+ mp_int t; -+ int res, pa, pb, ix, iy; -+ mp_digit u; -+ mp_word r; -+ mp_digit tmpx, *tmpt, *tmpy; -+ -+ /* can we use the fast multiplier? */ -+ if (((digs) < MP_WARRAY) && -+ MIN (a->used, b->used) < -+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { -+ return fast_s_mp_mul_digs (a, b, c, digs); -+ } -+ -+ if ((res = mp_init_size (&t, digs)) != MP_OKAY) { -+ return res; -+ } -+ t.used = digs; -+ -+ /* compute the digits of the product directly */ -+ pa = a->used; -+ for (ix = 0; ix < pa; ix++) { -+ /* set the carry to zero */ -+ u = 0; -+ -+ /* limit ourselves to making digs digits of output */ -+ pb = MIN (b->used, digs - ix); -+ -+ /* setup some aliases */ -+ /* copy of the digit from a used within the nested loop */ -+ tmpx = a->dp[ix]; -+ -+ /* an alias for the destination shifted ix places */ -+ tmpt = t.dp + ix; -+ -+ /* an alias for the digits of b */ -+ tmpy = b->dp; -+ -+ /* compute the columns of the output and propagate the carry */ -+ for (iy = 0; iy < pb; iy++) { -+ /* compute the column as a mp_word */ -+ r = ((mp_word)*tmpt) + -+ ((mp_word)tmpx) * ((mp_word)*tmpy++) + -+ ((mp_word) u); -+ -+ /* the new column is the lower part of the result */ -+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); -+ -+ /* get the carry word from the result */ -+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); -+ } -+ /* set carry if it is placed below digs */ -+ if (ix + iy < digs) { -+ *tmpt = u; -+ } -+ } -+ -+ mp_clamp (&t); -+ mp_exch (&t, c); -+ -+ mp_clear (&t); -+ return MP_OKAY; -+} -+ -+ -+/* Fast (comba) multiplier -+ * -+ * This is the fast column-array [comba] multiplier. It is -+ * designed to compute the columns of the product first -+ * then handle the carries afterwards. This has the effect -+ * of making the nested loops that compute the columns very -+ * simple and schedulable on super-scalar processors. -+ * -+ * This has been modified to produce a variable number of -+ * digits of output so if say only a half-product is required -+ * you don't have to compute the upper half (a feature -+ * required for fast Barrett reduction). -+ * -+ * Based on Algorithm 14.12 on pp.595 of HAC. -+ * -+ */ -+static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -+{ -+ int olduse, res, pa, ix, iz; -+ mp_digit W[MP_WARRAY]; -+ register mp_word _W; -+ -+ /* grow the destination as required */ -+ if (c->alloc < digs) { -+ if ((res = mp_grow (c, digs)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* number of output digits to produce */ -+ pa = MIN(digs, a->used + b->used); -+ -+ /* clear the carry */ -+ _W = 0; -+ for (ix = 0; ix < pa; ix++) { -+ int tx, ty; -+ int iy; -+ mp_digit *tmpx, *tmpy; -+ -+ /* get offsets into the two bignums */ -+ ty = MIN(b->used-1, ix); -+ tx = ix - ty; -+ -+ /* setup temp aliases */ -+ tmpx = a->dp + tx; -+ tmpy = b->dp + ty; -+ -+ /* this is the number of times the loop will iterrate, essentially -+ while (tx++ < a->used && ty-- >= 0) { ... } -+ */ -+ iy = MIN(a->used-tx, ty+1); -+ -+ /* execute loop */ -+ for (iz = 0; iz < iy; ++iz) { -+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); -+ -+ } -+ -+ /* store term */ -+ W[ix] = ((mp_digit)_W) & MP_MASK; -+ -+ /* make next carry */ -+ _W = _W >> ((mp_word)DIGIT_BIT); -+ } -+ -+ /* setup dest */ -+ olduse = c->used; -+ c->used = pa; -+ -+ { -+ register mp_digit *tmpc; -+ tmpc = c->dp; -+ for (ix = 0; ix < pa+1; ix++) { -+ /* now extract the previous digit [below the carry] */ -+ *tmpc++ = W[ix]; -+ } -+ -+ /* clear unused digits [that existed in the old copy of c] */ -+ for (; ix < olduse; ix++) { -+ *tmpc++ = 0; -+ } -+ } -+ mp_clamp (c); -+ return MP_OKAY; -+} -+ -+ -+/* init an mp_init for a given size */ -+static int mp_init_size (mp_int * a, int size) -+{ -+ int x; -+ -+ /* pad size so there are always extra digits */ -+ size += (MP_PREC * 2) - (size % MP_PREC); -+ -+ /* alloc mem */ -+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); -+ if (a->dp == NULL) { -+ return MP_MEM; -+ } -+ -+ /* set the members */ -+ a->used = 0; -+ a->alloc = size; -+ a->sign = MP_ZPOS; -+ -+ /* zero the digits */ -+ for (x = 0; x < size; x++) { -+ a->dp[x] = 0; -+ } -+ -+ return MP_OKAY; -+} -+ -+ -+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ -+static int s_mp_sqr (mp_int * a, mp_int * b) -+{ -+ mp_int t; -+ int res, ix, iy, pa; -+ mp_word r; -+ mp_digit u, tmpx, *tmpt; -+ -+ pa = a->used; -+ if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { -+ return res; -+ } -+ -+ /* default used is maximum possible size */ -+ t.used = 2*pa + 1; -+ -+ for (ix = 0; ix < pa; ix++) { -+ /* first calculate the digit at 2*ix */ -+ /* calculate double precision result */ -+ r = ((mp_word) t.dp[2*ix]) + -+ ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); -+ -+ /* store lower part in result */ -+ t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); -+ -+ /* get the carry */ -+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); -+ -+ /* left hand side of A[ix] * A[iy] */ -+ tmpx = a->dp[ix]; -+ -+ /* alias for where to store the results */ -+ tmpt = t.dp + (2*ix + 1); -+ -+ for (iy = ix + 1; iy < pa; iy++) { -+ /* first calculate the product */ -+ r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); -+ -+ /* now calculate the double precision result, note we use -+ * addition instead of *2 since it's easier to optimize -+ */ -+ r = ((mp_word) *tmpt) + r + r + ((mp_word) u); -+ -+ /* store lower part */ -+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); -+ -+ /* get carry */ -+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); -+ } -+ /* propagate upwards */ -+ while (u != ((mp_digit) 0)) { -+ r = ((mp_word) *tmpt) + ((mp_word) u); -+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); -+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); -+ } -+ } -+ -+ mp_clamp (&t); -+ mp_exch (&t, b); -+ mp_clear (&t); -+ return MP_OKAY; -+} -+ -+ -+/* multiplies |a| * |b| and does not compute the lower digs digits -+ * [meant to get the higher part of the product] -+ */ -+static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -+{ -+ mp_int t; -+ int res, pa, pb, ix, iy; -+ mp_digit u; -+ mp_word r; -+ mp_digit tmpx, *tmpt, *tmpy; -+ -+ /* can we use the fast multiplier? */ -+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C -+ if (((a->used + b->used + 1) < MP_WARRAY) -+ && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { -+ return fast_s_mp_mul_high_digs (a, b, c, digs); -+ } -+#endif -+ -+ if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { -+ return res; -+ } -+ t.used = a->used + b->used + 1; -+ -+ pa = a->used; -+ pb = b->used; -+ for (ix = 0; ix < pa; ix++) { -+ /* clear the carry */ -+ u = 0; -+ -+ /* left hand side of A[ix] * B[iy] */ -+ tmpx = a->dp[ix]; -+ -+ /* alias to the address of where the digits will be stored */ -+ tmpt = &(t.dp[digs]); -+ -+ /* alias for where to read the right hand side from */ -+ tmpy = b->dp + (digs - ix); -+ -+ for (iy = digs - ix; iy < pb; iy++) { -+ /* calculate the double precision result */ -+ r = ((mp_word)*tmpt) + -+ ((mp_word)tmpx) * ((mp_word)*tmpy++) + -+ ((mp_word) u); -+ -+ /* get the lower part */ -+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); -+ -+ /* carry the carry */ -+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); -+ } -+ *tmpt = u; -+ } -+ mp_clamp (&t); -+ mp_exch (&t, c); -+ mp_clear (&t); -+ return MP_OKAY; -+} -+ -+ -+#ifdef BN_MP_MONTGOMERY_SETUP_C -+/* setups the montgomery reduction stuff */ -+static int -+mp_montgomery_setup (mp_int * n, mp_digit * rho) -+{ -+ mp_digit x, b; -+ -+/* fast inversion mod 2**k -+ * -+ * Based on the fact that -+ * -+ * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) -+ * => 2*X*A - X*X*A*A = 1 -+ * => 2*(1) - (1) = 1 -+ */ -+ b = n->dp[0]; -+ -+ if ((b & 1) == 0) { -+ return MP_VAL; -+ } -+ -+ x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ -+ x *= 2 - b * x; /* here x*a==1 mod 2**8 */ -+#if !defined(MP_8BIT) -+ x *= 2 - b * x; /* here x*a==1 mod 2**16 */ -+#endif -+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) -+ x *= 2 - b * x; /* here x*a==1 mod 2**32 */ -+#endif -+#ifdef MP_64BIT -+ x *= 2 - b * x; /* here x*a==1 mod 2**64 */ -+#endif -+ -+ /* rho = -1/m mod b */ -+ *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; -+ -+ return MP_OKAY; -+} -+#endif -+ -+ -+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C -+/* computes xR**-1 == x (mod N) via Montgomery Reduction -+ * -+ * This is an optimized implementation of montgomery_reduce -+ * which uses the comba method to quickly calculate the columns of the -+ * reduction. -+ * -+ * Based on Algorithm 14.32 on pp.601 of HAC. -+*/ -+int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) -+{ -+ int ix, res, olduse; -+ mp_word W[MP_WARRAY]; -+ -+ /* get old used count */ -+ olduse = x->used; -+ -+ /* grow a as required */ -+ if (x->alloc < n->used + 1) { -+ if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* first we have to get the digits of the input into -+ * an array of double precision words W[...] -+ */ -+ { -+ register mp_word *_W; -+ register mp_digit *tmpx; -+ -+ /* alias for the W[] array */ -+ _W = W; -+ -+ /* alias for the digits of x*/ -+ tmpx = x->dp; -+ -+ /* copy the digits of a into W[0..a->used-1] */ -+ for (ix = 0; ix < x->used; ix++) { -+ *_W++ = *tmpx++; -+ } -+ -+ /* zero the high words of W[a->used..m->used*2] */ -+ for (; ix < n->used * 2 + 1; ix++) { -+ *_W++ = 0; -+ } -+ } -+ -+ /* now we proceed to zero successive digits -+ * from the least significant upwards -+ */ -+ for (ix = 0; ix < n->used; ix++) { -+ /* mu = ai * m' mod b -+ * -+ * We avoid a double precision multiplication (which isn't required) -+ * by casting the value down to a mp_digit. Note this requires -+ * that W[ix-1] have the carry cleared (see after the inner loop) -+ */ -+ register mp_digit mu; -+ mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); -+ -+ /* a = a + mu * m * b**i -+ * -+ * This is computed in place and on the fly. The multiplication -+ * by b**i is handled by offseting which columns the results -+ * are added to. -+ * -+ * Note the comba method normally doesn't handle carries in the -+ * inner loop In this case we fix the carry from the previous -+ * column since the Montgomery reduction requires digits of the -+ * result (so far) [see above] to work. This is -+ * handled by fixing up one carry after the inner loop. The -+ * carry fixups are done in order so after these loops the -+ * first m->used words of W[] have the carries fixed -+ */ -+ { -+ register int iy; -+ register mp_digit *tmpn; -+ register mp_word *_W; -+ -+ /* alias for the digits of the modulus */ -+ tmpn = n->dp; -+ -+ /* Alias for the columns set by an offset of ix */ -+ _W = W + ix; -+ -+ /* inner loop */ -+ for (iy = 0; iy < n->used; iy++) { -+ *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); -+ } -+ } -+ -+ /* now fix carry for next digit, W[ix+1] */ -+ W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); -+ } -+ -+ /* now we have to propagate the carries and -+ * shift the words downward [all those least -+ * significant digits we zeroed]. -+ */ -+ { -+ register mp_digit *tmpx; -+ register mp_word *_W, *_W1; -+ -+ /* nox fix rest of carries */ -+ -+ /* alias for current word */ -+ _W1 = W + ix; -+ -+ /* alias for next word, where the carry goes */ -+ _W = W + ++ix; -+ -+ for (; ix <= n->used * 2 + 1; ix++) { -+ *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); -+ } -+ -+ /* copy out, A = A/b**n -+ * -+ * The result is A/b**n but instead of converting from an -+ * array of mp_word to mp_digit than calling mp_rshd -+ * we just copy them in the right order -+ */ -+ -+ /* alias for destination word */ -+ tmpx = x->dp; -+ -+ /* alias for shifted double precision result */ -+ _W = W + n->used; -+ -+ for (ix = 0; ix < n->used + 1; ix++) { -+ *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); -+ } -+ -+ /* zero oldused digits, if the input a was larger than -+ * m->used+1 we'll have to clear the digits -+ */ -+ for (; ix < olduse; ix++) { -+ *tmpx++ = 0; -+ } -+ } -+ -+ /* set the max used and clamp */ -+ x->used = n->used + 1; -+ mp_clamp (x); -+ -+ /* if A >= m then A = A - m */ -+ if (mp_cmp_mag (x, n) != MP_LT) { -+ return s_mp_sub (x, n, x); -+ } -+ return MP_OKAY; -+} -+#endif -+ -+ -+#ifdef BN_MP_MUL_2_C -+/* b = a*2 */ -+static int mp_mul_2(mp_int * a, mp_int * b) -+{ -+ int x, res, oldused; -+ -+ /* grow to accomodate result */ -+ if (b->alloc < a->used + 1) { -+ if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ oldused = b->used; -+ b->used = a->used; -+ -+ { -+ register mp_digit r, rr, *tmpa, *tmpb; -+ -+ /* alias for source */ -+ tmpa = a->dp; -+ -+ /* alias for dest */ -+ tmpb = b->dp; -+ -+ /* carry */ -+ r = 0; -+ for (x = 0; x < a->used; x++) { -+ -+ /* get what will be the *next* carry bit from the -+ * MSB of the current digit -+ */ -+ rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); -+ -+ /* now shift up this digit, add in the carry [from the previous] */ -+ *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; -+ -+ /* copy the carry that would be from the source -+ * digit into the next iteration -+ */ -+ r = rr; -+ } -+ -+ /* new leading digit? */ -+ if (r != 0) { -+ /* add a MSB which is always 1 at this point */ -+ *tmpb = 1; -+ ++(b->used); -+ } -+ -+ /* now zero any excess digits on the destination -+ * that we didn't write to -+ */ -+ tmpb = b->dp + b->used; -+ for (x = b->used; x < oldused; x++) { -+ *tmpb++ = 0; -+ } -+ } -+ b->sign = a->sign; -+ return MP_OKAY; -+} -+#endif -+ -+ -+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C -+/* -+ * shifts with subtractions when the result is greater than b. -+ * -+ * The method is slightly modified to shift B unconditionally upto just under -+ * the leading bit of b. This saves alot of multiple precision shifting. -+ */ -+static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) -+{ -+ int x, bits, res; -+ -+ /* how many bits of last digit does b use */ -+ bits = mp_count_bits (b) % DIGIT_BIT; -+ -+ if (b->used > 1) { -+ if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { -+ return res; -+ } -+ } else { -+ mp_set(a, 1); -+ bits = 1; -+ } -+ -+ -+ /* now compute C = A * B mod b */ -+ for (x = bits - 1; x < (int)DIGIT_BIT; x++) { -+ if ((res = mp_mul_2 (a, a)) != MP_OKAY) { -+ return res; -+ } -+ if (mp_cmp_mag (a, b) != MP_LT) { -+ if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { -+ return res; -+ } -+ } -+ } -+ -+ return MP_OKAY; -+} -+#endif -+ -+ -+#ifdef BN_MP_EXPTMOD_FAST_C -+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 -+ * -+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. -+ * The value of k changes based on the size of the exponent. -+ * -+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate] -+ */ -+ -+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) -+{ -+ mp_int M[TAB_SIZE], res; -+ mp_digit buf, mp; -+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; -+ -+ /* use a pointer to the reduction algorithm. This allows us to use -+ * one of many reduction algorithms without modding the guts of -+ * the code with if statements everywhere. -+ */ -+ int (*redux)(mp_int*,mp_int*,mp_digit); -+ -+ /* find window size */ -+ x = mp_count_bits (X); -+ if (x <= 7) { -+ winsize = 2; -+ } else if (x <= 36) { -+ winsize = 3; -+ } else if (x <= 140) { -+ winsize = 4; -+ } else if (x <= 450) { -+ winsize = 5; -+ } else if (x <= 1303) { -+ winsize = 6; -+ } else if (x <= 3529) { -+ winsize = 7; -+ } else { -+ winsize = 8; -+ } -+ -+#ifdef MP_LOW_MEM -+ if (winsize > 5) { -+ winsize = 5; -+ } -+#endif -+ -+ /* init M array */ -+ /* init first cell */ -+ if ((err = mp_init(&M[1])) != MP_OKAY) { -+ return err; -+ } -+ -+ /* now init the second half of the array */ -+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { -+ if ((err = mp_init(&M[x])) != MP_OKAY) { -+ for (y = 1<<(winsize-1); y < x; y++) { -+ mp_clear (&M[y]); -+ } -+ mp_clear(&M[1]); -+ return err; -+ } -+ } -+ -+ /* determine and setup reduction code */ -+ if (redmode == 0) { -+#ifdef BN_MP_MONTGOMERY_SETUP_C -+ /* now setup montgomery */ -+ if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { -+ goto LBL_M; -+ } -+#else -+ err = MP_VAL; -+ goto LBL_M; -+#endif -+ -+ /* automatically pick the comba one if available (saves quite a few calls/ifs) */ -+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C -+ if (((P->used * 2 + 1) < MP_WARRAY) && -+ P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { -+ redux = fast_mp_montgomery_reduce; -+ } else -+#endif -+ { -+#ifdef BN_MP_MONTGOMERY_REDUCE_C -+ /* use slower baseline Montgomery method */ -+ redux = mp_montgomery_reduce; -+#else -+ err = MP_VAL; -+ goto LBL_M; -+#endif -+ } -+ } else if (redmode == 1) { -+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) -+ /* setup DR reduction for moduli of the form B**k - b */ -+ mp_dr_setup(P, &mp); -+ redux = mp_dr_reduce; -+#else -+ err = MP_VAL; -+ goto LBL_M; -+#endif -+ } else { -+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) -+ /* setup DR reduction for moduli of the form 2**k - b */ -+ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { -+ goto LBL_M; -+ } -+ redux = mp_reduce_2k; -+#else -+ err = MP_VAL; -+ goto LBL_M; -+#endif -+ } -+ -+ /* setup result */ -+ if ((err = mp_init (&res)) != MP_OKAY) { -+ goto LBL_M; -+ } -+ -+ /* create M table -+ * -+ -+ * -+ * The first half of the table is not computed though accept for M[0] and M[1] -+ */ -+ -+ if (redmode == 0) { -+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C -+ /* now we need R mod m */ -+ if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+#else -+ err = MP_VAL; -+ goto LBL_RES; -+#endif -+ -+ /* now set M[1] to G * R mod m */ -+ if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } else { -+ mp_set(&res, 1); -+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ -+ /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ -+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ -+ for (x = 0; x < (winsize - 1); x++) { -+ if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ -+ /* create upper table */ -+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { -+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&M[x], P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ -+ /* set initial mode and bit cnt */ -+ mode = 0; -+ bitcnt = 1; -+ buf = 0; -+ digidx = X->used - 1; -+ bitcpy = 0; -+ bitbuf = 0; -+ -+ for (;;) { -+ /* grab next digit as required */ -+ if (--bitcnt == 0) { -+ /* if digidx == -1 we are out of digits so break */ -+ if (digidx == -1) { -+ break; -+ } -+ /* read next digit and reset bitcnt */ -+ buf = X->dp[digidx--]; -+ bitcnt = (int)DIGIT_BIT; -+ } -+ -+ /* grab the next msb from the exponent */ -+ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; -+ buf <<= (mp_digit)1; -+ -+ /* if the bit is zero and mode == 0 then we ignore it -+ * These represent the leading zero bits before the first 1 bit -+ * in the exponent. Technically this opt is not required but it -+ * does lower the # of trivial squaring/reductions used -+ */ -+ if (mode == 0 && y == 0) { -+ continue; -+ } -+ -+ /* if the bit is zero and mode == 1 then we square */ -+ if (mode == 1 && y == 0) { -+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ continue; -+ } -+ -+ /* else we add it to the window */ -+ bitbuf |= (y << (winsize - ++bitcpy)); -+ mode = 2; -+ -+ if (bitcpy == winsize) { -+ /* ok window is filled so square as required and multiply */ -+ /* square first */ -+ for (x = 0; x < winsize; x++) { -+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ -+ /* then multiply */ -+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ -+ /* empty window and reset */ -+ bitcpy = 0; -+ bitbuf = 0; -+ mode = 1; -+ } -+ } -+ -+ /* if bits remain then square/multiply */ -+ if (mode == 2 && bitcpy > 0) { -+ /* square then multiply if the bit is set */ -+ for (x = 0; x < bitcpy; x++) { -+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ -+ /* get next bit of the window */ -+ bitbuf <<= 1; -+ if ((bitbuf & (1 << winsize)) != 0) { -+ /* then multiply */ -+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ if ((err = redux (&res, P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ } -+ } -+ -+ if (redmode == 0) { -+ /* fixup result if Montgomery reduction is used -+ * recall that any value in a Montgomery system is -+ * actually multiplied by R mod n. So we have -+ * to reduce one more time to cancel out the factor -+ * of R. -+ */ -+ if ((err = redux(&res, P, mp)) != MP_OKAY) { -+ goto LBL_RES; -+ } -+ } -+ -+ /* swap res with Y */ -+ mp_exch (&res, Y); -+ err = MP_OKAY; -+LBL_RES:mp_clear (&res); -+LBL_M: -+ mp_clear(&M[1]); -+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { -+ mp_clear (&M[x]); -+ } -+ return err; -+} -+#endif -+ -+ -+#ifdef BN_FAST_S_MP_SQR_C -+/* the jist of squaring... -+ * you do like mult except the offset of the tmpx [one that -+ * starts closer to zero] can't equal the offset of tmpy. -+ * So basically you set up iy like before then you min it with -+ * (ty-tx) so that it never happens. You double all those -+ * you add in the inner loop -+ -+After that loop you do the squares and add them in. -+*/ -+ -+static int fast_s_mp_sqr (mp_int * a, mp_int * b) -+{ -+ int olduse, res, pa, ix, iz; -+ mp_digit W[MP_WARRAY], *tmpx; -+ mp_word W1; -+ -+ /* grow the destination as required */ -+ pa = a->used + a->used; -+ if (b->alloc < pa) { -+ if ((res = mp_grow (b, pa)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* number of output digits to produce */ -+ W1 = 0; -+ for (ix = 0; ix < pa; ix++) { -+ int tx, ty, iy; -+ mp_word _W; -+ mp_digit *tmpy; -+ -+ /* clear counter */ -+ _W = 0; -+ -+ /* get offsets into the two bignums */ -+ ty = MIN(a->used-1, ix); -+ tx = ix - ty; -+ -+ /* setup temp aliases */ -+ tmpx = a->dp + tx; -+ tmpy = a->dp + ty; -+ -+ /* this is the number of times the loop will iterrate, essentially -+ while (tx++ < a->used && ty-- >= 0) { ... } -+ */ -+ iy = MIN(a->used-tx, ty+1); -+ -+ /* now for squaring tx can never equal ty -+ * we halve the distance since they approach at a rate of 2x -+ * and we have to round because odd cases need to be executed -+ */ -+ iy = MIN(iy, (ty-tx+1)>>1); -+ -+ /* execute loop */ -+ for (iz = 0; iz < iy; iz++) { -+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); -+ } -+ -+ /* double the inner product and add carry */ -+ _W = _W + _W + W1; -+ -+ /* even columns have the square term in them */ -+ if ((ix&1) == 0) { -+ _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); -+ } -+ -+ /* store it */ -+ W[ix] = (mp_digit)(_W & MP_MASK); -+ -+ /* make next carry */ -+ W1 = _W >> ((mp_word)DIGIT_BIT); -+ } -+ -+ /* setup dest */ -+ olduse = b->used; -+ b->used = a->used+a->used; -+ -+ { -+ mp_digit *tmpb; -+ tmpb = b->dp; -+ for (ix = 0; ix < pa; ix++) { -+ *tmpb++ = W[ix] & MP_MASK; -+ } -+ -+ /* clear unused digits [that existed in the old copy of c] */ -+ for (; ix < olduse; ix++) { -+ *tmpb++ = 0; -+ } -+ } -+ mp_clamp (b); -+ return MP_OKAY; -+} -+#endif -+ -+ -+#ifdef BN_MP_MUL_D_C -+/* multiply by a digit */ -+static int -+mp_mul_d (mp_int * a, mp_digit b, mp_int * c) -+{ -+ mp_digit u, *tmpa, *tmpc; -+ mp_word r; -+ int ix, res, olduse; -+ -+ /* make sure c is big enough to hold a*b */ -+ if (c->alloc < a->used + 1) { -+ if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { -+ return res; -+ } -+ } -+ -+ /* get the original destinations used count */ -+ olduse = c->used; -+ -+ /* set the sign */ -+ c->sign = a->sign; -+ -+ /* alias for a->dp [source] */ -+ tmpa = a->dp; -+ -+ /* alias for c->dp [dest] */ -+ tmpc = c->dp; -+ -+ /* zero carry */ -+ u = 0; -+ -+ /* compute columns */ -+ for (ix = 0; ix < a->used; ix++) { -+ /* compute product and carry sum for this term */ -+ r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); -+ -+ /* mask off higher bits to get a single digit */ -+ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); -+ -+ /* send carry into next iteration */ -+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); -+ } -+ -+ /* store final carry [if any] and increment ix offset */ -+ *tmpc++ = u; -+ ++ix; -+ -+ /* now zero digits above the top */ -+ while (ix++ < olduse) { -+ *tmpc++ = 0; -+ } -+ -+ /* set used count */ -+ c->used = a->used + 1; -+ mp_clamp(c); -+ -+ return MP_OKAY; -+} -+#endif -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.c -new file mode 100644 -index 0000000000000..72ebd87648576 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.c -@@ -0,0 +1,201 @@ -+/* -+ * PKCS #1 (RSA Encryption) -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "rsa.h" -+#include "pkcs1.h" -+ -+ -+static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ size_t ps_len; -+ u8 *pos; -+ -+ /* -+ * PKCS #1 v1.5, 8.1: -+ * -+ * EB = 00 || BT || PS || 00 || D -+ * BT = 00 or 01 for private-key operation; 02 for public-key operation -+ * PS = k-3-||D||; at least eight octets -+ * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero) -+ * k = length of modulus in octets (modlen) -+ */ -+ -+ if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) { -+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer " -+ "lengths (modlen=%lu outlen=%lu inlen=%lu)", -+ __func__, (unsigned long) modlen, -+ (unsigned long) *outlen, -+ (unsigned long) inlen); -+ return -1; -+ } -+ -+ pos = out; -+ *pos++ = 0x00; -+ *pos++ = block_type; /* BT */ -+ ps_len = modlen - inlen - 3; -+ switch (block_type) { -+ case 0: -+ os_memset(pos, 0x00, ps_len); -+ pos += ps_len; -+ break; -+ case 1: -+ os_memset(pos, 0xff, ps_len); -+ pos += ps_len; -+ break; -+ case 2: -+ if (os_get_random(pos, ps_len) < 0) { -+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get " -+ "random data for PS", __func__); -+ return -1; -+ } -+ while (ps_len--) { -+ if (*pos == 0x00) -+ *pos = 0x01; -+ pos++; -+ } -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type " -+ "%d", __func__, block_type); -+ return -1; -+ } -+ *pos++ = 0x00; -+ os_memcpy(pos, in, inlen); /* D */ -+ -+ return 0; -+} -+ -+ -+int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, -+ int use_private, const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ size_t modlen; -+ -+ modlen = crypto_rsa_get_modulus_len(key); -+ -+ if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen, -+ out, outlen) < 0) -+ return -1; -+ -+ return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private); -+} -+ -+ -+int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen) -+{ -+ int res; -+ u8 *pos, *end; -+ -+ res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1); -+ if (res) -+ return res; -+ -+ if (*outlen < 2 || out[0] != 0 || out[1] != 2) -+ return -1; -+ -+ /* Skip PS (pseudorandom non-zero octets) */ -+ pos = out + 2; -+ end = out + *outlen; -+ while (*pos && pos < end) -+ pos++; -+ if (pos == end) -+ return -1; -+ pos++; -+ -+ *outlen -= pos - out; -+ -+ /* Strip PKCS #1 header */ -+ os_memmove(out, pos, *outlen); -+ -+ return 0; -+} -+ -+ -+int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, -+ const u8 *crypt, size_t crypt_len, -+ u8 *plain, size_t *plain_len) -+{ -+ size_t len; -+ u8 *pos; -+ -+ len = *plain_len; -+ if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0) -+ return -1; -+ -+ /* -+ * PKCS #1 v1.5, 8.1: -+ * -+ * EB = 00 || BT || PS || 00 || D -+ * BT = 00 or 01 -+ * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) -+ * k = length of modulus in octets -+ */ -+ -+ if (len < 3 + 8 + 16 /* min hash len */ || -+ plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) { -+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " -+ "structure"); -+ return -1; -+ } -+ -+ pos = plain + 3; -+ if (plain[1] == 0x00) { -+ /* BT = 00 */ -+ if (plain[2] != 0x00) { -+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " -+ "PS (BT=00)"); -+ return -1; -+ } -+ while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00) -+ pos++; -+ } else { -+ /* BT = 01 */ -+ if (plain[2] != 0xff) { -+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " -+ "PS (BT=01)"); -+ return -1; -+ } -+ while (pos < plain + len && *pos == 0xff) -+ pos++; -+ } -+ -+ if (pos - plain - 2 < 8) { -+ /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ -+ wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature " -+ "padding"); -+ return -1; -+ } -+ -+ if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) { -+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " -+ "structure (2)"); -+ return -1; -+ } -+ pos++; -+ len -= pos - plain; -+ -+ /* Strip PKCS #1 header */ -+ os_memmove(plain, pos, len); -+ *plain_len = len; -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.h -new file mode 100644 -index 0000000000000..68872b1502edf ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs1.h -@@ -0,0 +1,28 @@ -+/* -+ * PKCS #1 (RSA Encryption) -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PKCS1_H -+#define PKCS1_H -+ -+int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, -+ int use_private, const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen); -+int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, -+ const u8 *in, size_t inlen, -+ u8 *out, size_t *outlen); -+int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, -+ const u8 *crypt, size_t crypt_len, -+ u8 *plain, size_t *plain_len); -+ -+#endif /* PKCS1_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.c -new file mode 100644 -index 0000000000000..4291b84f16d7f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.c -@@ -0,0 +1,238 @@ -+/* -+ * PKCS #5 (Password-based Encryption) -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/crypto.h" -+#include "crypto/md5.h" -+#include "asn1.h" -+#include "pkcs5.h" -+ -+ -+struct pkcs5_params { -+ enum pkcs5_alg { -+ PKCS5_ALG_UNKNOWN, -+ PKCS5_ALG_MD5_DES_CBC -+ } alg; -+ u8 salt[8]; -+ size_t salt_len; -+ unsigned int iter_count; -+}; -+ -+ -+enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid) -+{ -+ if (oid->len == 7 && -+ oid->oid[0] == 1 /* iso */ && -+ oid->oid[1] == 2 /* member-body */ && -+ oid->oid[2] == 840 /* us */ && -+ oid->oid[3] == 113549 /* rsadsi */ && -+ oid->oid[4] == 1 /* pkcs */ && -+ oid->oid[5] == 5 /* pkcs-5 */ && -+ oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */) -+ return PKCS5_ALG_MD5_DES_CBC; -+ -+ return PKCS5_ALG_UNKNOWN; -+} -+ -+ -+static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len, -+ struct pkcs5_params *params) -+{ -+ struct asn1_hdr hdr; -+ const u8 *enc_alg_end, *pos, *end; -+ struct asn1_oid oid; -+ char obuf[80]; -+ -+ /* AlgorithmIdentifier */ -+ -+ enc_alg_end = enc_alg + enc_alg_len; -+ -+ os_memset(params, 0, sizeof(*params)); -+ -+ if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) { -+ wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID " -+ "(algorithm)"); -+ return -1; -+ } -+ -+ asn1_oid_to_str(&oid, obuf, sizeof(obuf)); -+ wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf); -+ params->alg = pkcs5_get_alg(&oid); -+ if (params->alg == PKCS5_ALG_UNKNOWN) { -+ wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption " -+ "algorithm %s", obuf); -+ return -1; -+ } -+ -+ /* -+ * PKCS#5, Section 8 -+ * PBEParameter ::= SEQUENCE { -+ * salt OCTET STRING SIZE(8), -+ * iterationCount INTEGER } -+ */ -+ -+ if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE " -+ "(PBEParameter) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ end = hdr.payload + hdr.length; -+ -+ /* salt OCTET STRING SIZE(8) */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_OCTETSTRING || -+ hdr.length != 8) { -+ wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) " -+ "(salt) - found class %d tag 0x%x size %d", -+ hdr.class, hdr.tag, hdr.length); -+ return -1; -+ } -+ pos = hdr.payload + hdr.length; -+ os_memcpy(params->salt, hdr.payload, hdr.length); -+ params->salt_len = hdr.length; -+ wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", -+ params->salt, params->salt_len); -+ -+ /* iterationCount INTEGER */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found " -+ "class %d tag 0x%x", hdr.class, hdr.tag); -+ return -1; -+ } -+ if (hdr.length == 1) -+ params->iter_count = *hdr.payload; -+ else if (hdr.length == 2) -+ params->iter_count = WPA_GET_BE16(hdr.payload); -+ else if (hdr.length == 4) -+ params->iter_count = WPA_GET_BE32(hdr.payload); -+ else { -+ wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value " -+ " (iterationCount)", -+ hdr.payload, hdr.length); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x", -+ params->iter_count); -+ if (params->iter_count == 0 || params->iter_count > 0xffff) { -+ wpa_printf(MSG_INFO, "PKCS #5: Unsupported " -+ "iterationCount=0x%x", params->iter_count); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params, -+ const char *passwd) -+{ -+ unsigned int i; -+ u8 hash[MD5_MAC_LEN]; -+ const u8 *addr[2]; -+ size_t len[2]; -+ -+ if (params->alg != PKCS5_ALG_MD5_DES_CBC) -+ return NULL; -+ -+ addr[0] = (const u8 *) passwd; -+ len[0] = os_strlen(passwd); -+ addr[1] = params->salt; -+ len[1] = params->salt_len; -+ if (md5_vector(2, addr, len, hash) < 0) -+ return NULL; -+ addr[0] = hash; -+ len[0] = MD5_MAC_LEN; -+ for (i = 1; i < params->iter_count; i++) { -+ if (md5_vector(1, addr, len, hash) < 0) -+ return NULL; -+ } -+ /* TODO: DES key parity bits(?) */ -+ wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8); -+ wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8); -+ -+ return crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8); -+} -+ -+ -+u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, -+ const u8 *enc_data, size_t enc_data_len, -+ const char *passwd, size_t *data_len) -+{ -+ struct crypto_cipher *ctx; -+ u8 *eb, pad; -+ struct pkcs5_params params; -+ unsigned int i; -+ -+ if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) { -+ wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters"); -+ return NULL; -+ } -+ -+ ctx = pkcs5_crypto_init(¶ms, passwd); -+ if (ctx == NULL) { -+ wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto"); -+ return NULL; -+ } -+ -+ /* PKCS #5, Section 7 - Decryption process */ -+ if (enc_data_len < 16 || enc_data_len % 8) { -+ wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext " -+ "%d", (int) enc_data_len); -+ crypto_cipher_deinit(ctx); -+ return NULL; -+ } -+ -+ eb = os_malloc(enc_data_len); -+ if (eb == NULL) { -+ crypto_cipher_deinit(ctx); -+ return NULL; -+ } -+ -+ if (crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) { -+ wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB"); -+ crypto_cipher_deinit(ctx); -+ os_free(eb); -+ return NULL; -+ } -+ crypto_cipher_deinit(ctx); -+ -+ pad = eb[enc_data_len - 1]; -+ if (pad > 8) { -+ wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad); -+ os_free(eb); -+ return NULL; -+ } -+ for (i = enc_data_len - pad; i < enc_data_len; i++) { -+ if (eb[i] != pad) { -+ wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS", -+ eb + enc_data_len - pad, pad); -+ os_free(eb); -+ return NULL; -+ } -+ } -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)", -+ eb, enc_data_len - pad); -+ -+ *data_len = enc_data_len - pad; -+ return eb; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.h -new file mode 100644 -index 0000000000000..6ed39230b5332 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs5.h -@@ -0,0 +1,22 @@ -+/* -+ * PKCS #5 (Password-based Encryption) -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PKCS5_H -+#define PKCS5_H -+ -+u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len, -+ const u8 *enc_data, size_t enc_data_len, -+ const char *passwd, size_t *data_len); -+ -+#endif /* PKCS5_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.c -new file mode 100644 -index 0000000000000..69ab262e5ebed ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.c -@@ -0,0 +1,193 @@ -+/* -+ * PKCS #8 (Private-key information syntax) -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "asn1.h" -+#include "bignum.h" -+#include "rsa.h" -+#include "pkcs5.h" -+#include "pkcs8.h" -+ -+ -+struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end; -+ struct bignum *zero; -+ struct asn1_oid oid; -+ char obuf[80]; -+ -+ /* PKCS #8, Chapter 6 */ -+ -+ /* PrivateKeyInfo ::= SEQUENCE */ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " -+ "header (SEQUENCE); assume PKCS #8 not used"); -+ return NULL; -+ } -+ pos = hdr.payload; -+ end = pos + hdr.length; -+ -+ /* version Version (Version ::= INTEGER) */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found " -+ "class %d tag 0x%x; assume PKCS #8 not used", -+ hdr.class, hdr.tag); -+ return NULL; -+ } -+ -+ zero = bignum_init(); -+ if (zero == NULL) -+ return NULL; -+ -+ if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER"); -+ bignum_deinit(zero); -+ return NULL; -+ } -+ pos = hdr.payload + hdr.length; -+ -+ if (bignum_cmp_d(zero, 0) != 0) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the " -+ "beginning of private key; not found; assume " -+ "PKCS #8 not used"); -+ bignum_deinit(zero); -+ return NULL; -+ } -+ bignum_deinit(zero); -+ -+ /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier -+ * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " -+ "(AlgorithmIdentifier) - found class %d tag 0x%x; " -+ "assume PKCS #8 not used", -+ hdr.class, hdr.tag); -+ return NULL; -+ } -+ -+ if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID " -+ "(algorithm); assume PKCS #8 not used"); -+ return NULL; -+ } -+ -+ asn1_oid_to_str(&oid, obuf, sizeof(obuf)); -+ wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf); -+ -+ if (oid.len != 7 || -+ oid.oid[0] != 1 /* iso */ || -+ oid.oid[1] != 2 /* member-body */ || -+ oid.oid[2] != 840 /* us */ || -+ oid.oid[3] != 113549 /* rsadsi */ || -+ oid.oid[4] != 1 /* pkcs */ || -+ oid.oid[5] != 1 /* pkcs-1 */ || -+ oid.oid[6] != 1 /* rsaEncryption */) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key " -+ "algorithm %s", obuf); -+ return NULL; -+ } -+ -+ pos = hdr.payload + hdr.length; -+ -+ /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_OCTETSTRING) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " -+ "(privateKey) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey"); -+ -+ return (struct crypto_private_key *) -+ crypto_rsa_import_private_key(hdr.payload, hdr.length); -+} -+ -+ -+struct crypto_private_key * -+pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end, *enc_alg; -+ size_t enc_alg_len; -+ u8 *data; -+ size_t data_len; -+ -+ if (passwd == NULL) -+ return NULL; -+ -+ /* -+ * PKCS #8, Chapter 7 -+ * EncryptedPrivateKeyInfo ::= SEQUENCE { -+ * encryptionAlgorithm EncryptionAlgorithmIdentifier, -+ * encryptedData EncryptedData } -+ * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier -+ * EncryptedData ::= OCTET STRING -+ */ -+ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 " -+ "header (SEQUENCE); assume encrypted PKCS #8 not " -+ "used"); -+ return NULL; -+ } -+ pos = hdr.payload; -+ end = pos + hdr.length; -+ -+ /* encryptionAlgorithm EncryptionAlgorithmIdentifier */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE " -+ "(AlgorithmIdentifier) - found class %d tag 0x%x; " -+ "assume encrypted PKCS #8 not used", -+ hdr.class, hdr.tag); -+ return NULL; -+ } -+ enc_alg = hdr.payload; -+ enc_alg_len = hdr.length; -+ pos = hdr.payload + hdr.length; -+ -+ /* encryptedData EncryptedData */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_OCTETSTRING) { -+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING " -+ "(encryptedData) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return NULL; -+ } -+ -+ data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length, -+ passwd, &data_len); -+ if (data) { -+ struct crypto_private_key *key; -+ key = pkcs8_key_import(data, data_len); -+ os_free(data); -+ return key; -+ } -+ -+ return NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.h -new file mode 100644 -index 0000000000000..dac517c91ac94 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/pkcs8.h -@@ -0,0 +1,22 @@ -+/* -+ * PKCS #8 (Private-key information syntax) -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PKCS8_H -+#define PKCS8_H -+ -+struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len); -+struct crypto_private_key * -+pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd); -+ -+#endif /* PKCS8_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.c -new file mode 100644 -index 0000000000000..3084adc17579a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.c -@@ -0,0 +1,358 @@ -+/* -+ * RSA -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "asn1.h" -+#include "bignum.h" -+#include "rsa.h" -+ -+ -+struct crypto_rsa_key { -+ int private_key; /* whether private key is set */ -+ struct bignum *n; /* modulus (p * q) */ -+ struct bignum *e; /* public exponent */ -+ /* The following parameters are available only if private_key is set */ -+ struct bignum *d; /* private exponent */ -+ struct bignum *p; /* prime p (factor of n) */ -+ struct bignum *q; /* prime q (factor of n) */ -+ struct bignum *dmp1; /* d mod (p - 1); CRT exponent */ -+ struct bignum *dmq1; /* d mod (q - 1); CRT exponent */ -+ struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */ -+}; -+ -+ -+static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end, -+ struct bignum *num) -+{ -+ struct asn1_hdr hdr; -+ -+ if (pos == NULL) -+ return NULL; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d " -+ "tag 0x%x", hdr.class, hdr.tag); -+ return NULL; -+ } -+ -+ if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) { -+ wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER"); -+ return NULL; -+ } -+ -+ return hdr.payload + hdr.length; -+} -+ -+ -+/** -+ * crypto_rsa_import_public_key - Import an RSA public key -+ * @buf: Key buffer (DER encoded RSA public key) -+ * @len: Key buffer length in bytes -+ * Returns: Pointer to the public key or %NULL on failure -+ */ -+struct crypto_rsa_key * -+crypto_rsa_import_public_key(const u8 *buf, size_t len) -+{ -+ struct crypto_rsa_key *key; -+ struct asn1_hdr hdr; -+ const u8 *pos, *end; -+ -+ key = os_zalloc(sizeof(*key)); -+ if (key == NULL) -+ return NULL; -+ -+ key->n = bignum_init(); -+ key->e = bignum_init(); -+ if (key->n == NULL || key->e == NULL) { -+ crypto_rsa_free(key); -+ return NULL; -+ } -+ -+ /* -+ * PKCS #1, 7.1: -+ * RSAPublicKey ::= SEQUENCE { -+ * modulus INTEGER, -- n -+ * publicExponent INTEGER -- e -+ * } -+ */ -+ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " -+ "(public key) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ goto error; -+ } -+ pos = hdr.payload; -+ end = pos + hdr.length; -+ -+ pos = crypto_rsa_parse_integer(pos, end, key->n); -+ pos = crypto_rsa_parse_integer(pos, end, key->e); -+ -+ if (pos == NULL) -+ goto error; -+ -+ if (pos != end) { -+ wpa_hexdump(MSG_DEBUG, -+ "RSA: Extra data in public key SEQUENCE", -+ pos, end - pos); -+ goto error; -+ } -+ -+ return key; -+ -+error: -+ crypto_rsa_free(key); -+ return NULL; -+} -+ -+ -+/** -+ * crypto_rsa_import_private_key - Import an RSA private key -+ * @buf: Key buffer (DER encoded RSA private key) -+ * @len: Key buffer length in bytes -+ * Returns: Pointer to the private key or %NULL on failure -+ */ -+struct crypto_rsa_key * -+crypto_rsa_import_private_key(const u8 *buf, size_t len) -+{ -+ struct crypto_rsa_key *key; -+ struct bignum *zero; -+ struct asn1_hdr hdr; -+ const u8 *pos, *end; -+ -+ key = os_zalloc(sizeof(*key)); -+ if (key == NULL) -+ return NULL; -+ -+ key->private_key = 1; -+ -+ key->n = bignum_init(); -+ key->e = bignum_init(); -+ key->d = bignum_init(); -+ key->p = bignum_init(); -+ key->q = bignum_init(); -+ key->dmp1 = bignum_init(); -+ key->dmq1 = bignum_init(); -+ key->iqmp = bignum_init(); -+ -+ if (key->n == NULL || key->e == NULL || key->d == NULL || -+ key->p == NULL || key->q == NULL || key->dmp1 == NULL || -+ key->dmq1 == NULL || key->iqmp == NULL) { -+ crypto_rsa_free(key); -+ return NULL; -+ } -+ -+ /* -+ * PKCS #1, 7.2: -+ * RSAPrivateKey ::= SEQUENCE { -+ * version Version, -+ * modulus INTEGER, -- n -+ * publicExponent INTEGER, -- e -+ * privateExponent INTEGER, -- d -+ * prime1 INTEGER, -- p -+ * prime2 INTEGER, -- q -+ * exponent1 INTEGER, -- d mod (p-1) -+ * exponent2 INTEGER, -- d mod (q-1) -+ * coefficient INTEGER -- (inverse of q) mod p -+ * } -+ * -+ * Version ::= INTEGER -- shall be 0 for this version of the standard -+ */ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE " -+ "(public key) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ goto error; -+ } -+ pos = hdr.payload; -+ end = pos + hdr.length; -+ -+ zero = bignum_init(); -+ if (zero == NULL) -+ goto error; -+ pos = crypto_rsa_parse_integer(pos, end, zero); -+ if (pos == NULL || bignum_cmp_d(zero, 0) != 0) { -+ wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the " -+ "beginning of private key; not found"); -+ bignum_deinit(zero); -+ goto error; -+ } -+ bignum_deinit(zero); -+ -+ pos = crypto_rsa_parse_integer(pos, end, key->n); -+ pos = crypto_rsa_parse_integer(pos, end, key->e); -+ pos = crypto_rsa_parse_integer(pos, end, key->d); -+ pos = crypto_rsa_parse_integer(pos, end, key->p); -+ pos = crypto_rsa_parse_integer(pos, end, key->q); -+ pos = crypto_rsa_parse_integer(pos, end, key->dmp1); -+ pos = crypto_rsa_parse_integer(pos, end, key->dmq1); -+ pos = crypto_rsa_parse_integer(pos, end, key->iqmp); -+ -+ if (pos == NULL) -+ goto error; -+ -+ if (pos != end) { -+ wpa_hexdump(MSG_DEBUG, -+ "RSA: Extra data in public key SEQUENCE", -+ pos, end - pos); -+ goto error; -+ } -+ -+ return key; -+ -+error: -+ crypto_rsa_free(key); -+ return NULL; -+} -+ -+ -+/** -+ * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key -+ * @key: RSA key -+ * Returns: Modulus length of the key -+ */ -+size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key) -+{ -+ return bignum_get_unsigned_bin_len(key->n); -+} -+ -+ -+/** -+ * crypto_rsa_exptmod - RSA modular exponentiation -+ * @in: Input data -+ * @inlen: Input data length -+ * @out: Buffer for output data -+ * @outlen: Maximum size of the output buffer and used size on success -+ * @key: RSA key -+ * @use_private: 1 = Use RSA private key, 0 = Use RSA public key -+ * Returns: 0 on success, -1 on failure -+ */ -+int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, -+ struct crypto_rsa_key *key, int use_private) -+{ -+ struct bignum *tmp, *a = NULL, *b = NULL; -+ int ret = -1; -+ size_t modlen; -+ -+ if (use_private && !key->private_key) -+ return -1; -+ -+ tmp = bignum_init(); -+ if (tmp == NULL) -+ return -1; -+ -+ if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) -+ goto error; -+ if (bignum_cmp(key->n, tmp) < 0) { -+ /* Too large input value for the RSA key modulus */ -+ goto error; -+ } -+ -+ if (use_private) { -+ /* -+ * Decrypt (or sign) using Chinese remainer theorem to speed -+ * up calculation. This is equivalent to tmp = tmp^d mod n -+ * (which would require more CPU to calculate directly). -+ * -+ * dmp1 = (1/e) mod (p-1) -+ * dmq1 = (1/e) mod (q-1) -+ * iqmp = (1/q) mod p, where p > q -+ * m1 = c^dmp1 mod p -+ * m2 = c^dmq1 mod q -+ * h = q^-1 (m1 - m2) mod p -+ * m = m2 + hq -+ */ -+ a = bignum_init(); -+ b = bignum_init(); -+ if (a == NULL || b == NULL) -+ goto error; -+ -+ /* a = tmp^dmp1 mod p */ -+ if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) -+ goto error; -+ -+ /* b = tmp^dmq1 mod q */ -+ if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) -+ goto error; -+ -+ /* tmp = (a - b) * (1/q mod p) (mod p) */ -+ if (bignum_sub(a, b, tmp) < 0 || -+ bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) -+ goto error; -+ -+ /* tmp = b + q * tmp */ -+ if (bignum_mul(tmp, key->q, tmp) < 0 || -+ bignum_add(tmp, b, tmp) < 0) -+ goto error; -+ } else { -+ /* Encrypt (or verify signature) */ -+ /* tmp = tmp^e mod N */ -+ if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) -+ goto error; -+ } -+ -+ modlen = crypto_rsa_get_modulus_len(key); -+ if (modlen > *outlen) { -+ *outlen = modlen; -+ goto error; -+ } -+ -+ if (bignum_get_unsigned_bin_len(tmp) > modlen) -+ goto error; /* should never happen */ -+ -+ *outlen = modlen; -+ os_memset(out, 0, modlen); -+ if (bignum_get_unsigned_bin( -+ tmp, out + -+ (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) -+ goto error; -+ -+ ret = 0; -+ -+error: -+ bignum_deinit(tmp); -+ bignum_deinit(a); -+ bignum_deinit(b); -+ return ret; -+} -+ -+ -+/** -+ * crypto_rsa_free - Free RSA key -+ * @key: RSA key to be freed -+ * -+ * This function frees an RSA key imported with either -+ * crypto_rsa_import_public_key() or crypto_rsa_import_private_key(). -+ */ -+void crypto_rsa_free(struct crypto_rsa_key *key) -+{ -+ if (key) { -+ bignum_deinit(key->n); -+ bignum_deinit(key->e); -+ bignum_deinit(key->d); -+ bignum_deinit(key->p); -+ bignum_deinit(key->q); -+ bignum_deinit(key->dmp1); -+ bignum_deinit(key->dmq1); -+ bignum_deinit(key->iqmp); -+ os_free(key); -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.h -new file mode 100644 -index 0000000000000..ac50dfd69d3e6 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/rsa.h -@@ -0,0 +1,29 @@ -+/* -+ * RSA -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef RSA_H -+#define RSA_H -+ -+struct crypto_rsa_key; -+ -+struct crypto_rsa_key * -+crypto_rsa_import_public_key(const u8 *buf, size_t len); -+struct crypto_rsa_key * -+crypto_rsa_import_private_key(const u8 *buf, size_t len); -+size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key); -+int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, -+ struct crypto_rsa_key *key, int use_private); -+void crypto_rsa_free(struct crypto_rsa_key *key); -+ -+#endif /* RSA_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.c -new file mode 100644 -index 0000000000000..afb603175a11a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.c -@@ -0,0 +1,667 @@ -+/* -+ * TLSv1 client (RFC 2246) -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "tlsv1_common.h" -+#include "tlsv1_record.h" -+#include "tlsv1_client.h" -+#include "tlsv1_client_i.h" -+ -+/* TODO: -+ * Support for a message fragmented across several records (RFC 2246, 6.2.1) -+ */ -+ -+ -+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description) -+{ -+ conn->alert_level = level; -+ conn->alert_description = description; -+} -+ -+ -+void tlsv1_client_free_dh(struct tlsv1_client *conn) -+{ -+ os_free(conn->dh_p); -+ os_free(conn->dh_g); -+ os_free(conn->dh_ys); -+ conn->dh_p = conn->dh_g = conn->dh_ys = NULL; -+} -+ -+ -+int tls_derive_pre_master_secret(u8 *pre_master_secret) -+{ -+ WPA_PUT_BE16(pre_master_secret, TLS_VERSION); -+ if (os_get_random(pre_master_secret + 2, -+ TLS_PRE_MASTER_SECRET_LEN - 2)) -+ return -1; -+ return 0; -+} -+ -+ -+int tls_derive_keys(struct tlsv1_client *conn, -+ const u8 *pre_master_secret, size_t pre_master_secret_len) -+{ -+ u8 seed[2 * TLS_RANDOM_LEN]; -+ u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; -+ u8 *pos; -+ size_t key_block_len; -+ -+ if (pre_master_secret) { -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", -+ pre_master_secret, pre_master_secret_len); -+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, -+ TLS_RANDOM_LEN); -+ if (tls_prf(pre_master_secret, pre_master_secret_len, -+ "master secret", seed, 2 * TLS_RANDOM_LEN, -+ conn->master_secret, TLS_MASTER_SECRET_LEN)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " -+ "master_secret"); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", -+ conn->master_secret, TLS_MASTER_SECRET_LEN); -+ } -+ -+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); -+ key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len + -+ conn->rl.iv_size); -+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ "key expansion", seed, 2 * TLS_RANDOM_LEN, -+ key_block, key_block_len)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", -+ key_block, key_block_len); -+ -+ pos = key_block; -+ -+ /* client_write_MAC_secret */ -+ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); -+ pos += conn->rl.hash_size; -+ /* server_write_MAC_secret */ -+ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); -+ pos += conn->rl.hash_size; -+ -+ /* client_write_key */ -+ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); -+ pos += conn->rl.key_material_len; -+ /* server_write_key */ -+ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); -+ pos += conn->rl.key_material_len; -+ -+ /* client_write_IV */ -+ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); -+ pos += conn->rl.iv_size; -+ /* server_write_IV */ -+ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); -+ pos += conn->rl.iv_size; -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_client_handshake - Process TLS handshake -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @in_data: Input data from TLS peer -+ * @in_len: Input data length -+ * @out_len: Length of the output buffer. -+ * @appl_data: Pointer to application data pointer, or %NULL if dropped -+ * @appl_data_len: Pointer to variable that is set to appl_data length -+ * Returns: Pointer to output data, %NULL on failure -+ */ -+u8 * tlsv1_client_handshake(struct tlsv1_client *conn, -+ const u8 *in_data, size_t in_len, -+ size_t *out_len, u8 **appl_data, -+ size_t *appl_data_len) -+{ -+ const u8 *pos, *end; -+ u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct; -+ size_t in_msg_len; -+ int no_appl_data; -+ -+ if (conn->state == CLIENT_HELLO) { -+ if (in_len) -+ return NULL; -+ return tls_send_client_hello(conn, out_len); -+ } -+ -+ if (in_data == NULL || in_len == 0) -+ return NULL; -+ -+ pos = in_data; -+ end = in_data + in_len; -+ in_msg = os_malloc(in_len); -+ if (in_msg == NULL) -+ return NULL; -+ -+ /* Each received packet may include multiple records */ -+ while (pos < end) { -+ in_msg_len = in_len; -+ if (tlsv1_record_receive(&conn->rl, pos, end - pos, -+ in_msg, &in_msg_len, &alert)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Processing received " -+ "record failed"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); -+ goto failed; -+ } -+ ct = pos[0]; -+ -+ in_pos = in_msg; -+ in_end = in_msg + in_msg_len; -+ -+ /* Each received record may include multiple messages of the -+ * same ContentType. */ -+ while (in_pos < in_end) { -+ in_msg_len = in_end - in_pos; -+ if (tlsv1_client_process_handshake(conn, ct, in_pos, -+ &in_msg_len, -+ appl_data, -+ appl_data_len) < 0) -+ goto failed; -+ in_pos += in_msg_len; -+ } -+ -+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); -+ } -+ -+ os_free(in_msg); -+ in_msg = NULL; -+ -+ no_appl_data = appl_data == NULL || *appl_data == NULL; -+ msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data); -+ -+failed: -+ os_free(in_msg); -+ if (conn->alert_level) { -+ conn->state = FAILED; -+ os_free(msg); -+ msg = tlsv1_client_send_alert(conn, conn->alert_level, -+ conn->alert_description, -+ out_len); -+ } else if (msg == NULL) { -+ msg = os_zalloc(1); -+ *out_len = 0; -+ } -+ -+ return msg; -+} -+ -+ -+/** -+ * tlsv1_client_encrypt - Encrypt data into TLS tunnel -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @in_data: Pointer to plaintext data to be encrypted -+ * @in_len: Input buffer length -+ * @out_data: Pointer to output buffer (encrypted TLS data) -+ * @out_len: Maximum out_data length -+ * Returns: Number of bytes written to out_data, -1 on failure -+ * -+ * This function is used after TLS handshake has been completed successfully to -+ * send data in the encrypted tunnel. -+ */ -+int tlsv1_client_encrypt(struct tlsv1_client *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len) -+{ -+ size_t rlen; -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", -+ in_data, in_len); -+ -+ os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, -+ out_data, out_len, in_len, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ return rlen; -+} -+ -+ -+/** -+ * tlsv1_client_decrypt - Decrypt data from TLS tunnel -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @in_data: Pointer to input buffer (encrypted TLS data) -+ * @in_len: Input buffer length -+ * @out_data: Pointer to output buffer (decrypted data from TLS tunnel) -+ * @out_len: Maximum out_data length -+ * Returns: Number of bytes written to out_data, -1 on failure -+ * -+ * This function is used after TLS handshake has been completed successfully to -+ * receive data from the encrypted tunnel. -+ */ -+int tlsv1_client_decrypt(struct tlsv1_client *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len) -+{ -+ const u8 *in_end, *pos; -+ int res; -+ u8 alert, *out_end, *out_pos; -+ size_t olen; -+ -+ pos = in_data; -+ in_end = in_data + in_len; -+ out_pos = out_data; -+ out_end = out_data + out_len; -+ -+ while (pos < in_end) { -+ if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " -+ "0x%x", pos[0]); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ olen = out_end - out_pos; -+ res = tlsv1_record_receive(&conn->rl, pos, in_end - pos, -+ out_pos, &olen, &alert); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " -+ "failed"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); -+ return -1; -+ } -+ out_pos += olen; -+ if (out_pos > out_end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough " -+ "for processing the received record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); -+ } -+ -+ return out_pos - out_data; -+} -+ -+ -+/** -+ * tlsv1_client_global_init - Initialize TLSv1 client -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function must be called before using any other TLSv1 client functions. -+ */ -+int tlsv1_client_global_init(void) -+{ -+ return crypto_global_init(); -+} -+ -+ -+/** -+ * tlsv1_client_global_deinit - Deinitialize TLSv1 client -+ * -+ * This function can be used to deinitialize the TLSv1 client that was -+ * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions -+ * can be called after this before calling tlsv1_client_global_init() again. -+ */ -+void tlsv1_client_global_deinit(void) -+{ -+ crypto_global_deinit(); -+} -+ -+ -+/** -+ * tlsv1_client_init - Initialize TLSv1 client connection -+ * Returns: Pointer to TLSv1 client connection data or %NULL on failure -+ */ -+struct tlsv1_client * tlsv1_client_init(void) -+{ -+ struct tlsv1_client *conn; -+ size_t count; -+ u16 *suites; -+ -+ conn = os_zalloc(sizeof(*conn)); -+ if (conn == NULL) -+ return NULL; -+ -+ conn->state = CLIENT_HELLO; -+ -+ if (tls_verify_hash_init(&conn->verify) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify " -+ "hash"); -+ os_free(conn); -+ return NULL; -+ } -+ -+ count = 0; -+ suites = conn->cipher_suites; -+#ifndef CONFIG_CRYPTO_INTERNAL -+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; -+#endif /* CONFIG_CRYPTO_INTERNAL */ -+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; -+ suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; -+ suites[count++] = TLS_RSA_WITH_RC4_128_SHA; -+ suites[count++] = TLS_RSA_WITH_RC4_128_MD5; -+ conn->num_cipher_suites = count; -+ -+ return conn; -+} -+ -+ -+/** -+ * tlsv1_client_deinit - Deinitialize TLSv1 client connection -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ */ -+void tlsv1_client_deinit(struct tlsv1_client *conn) -+{ -+ crypto_public_key_free(conn->server_rsa_key); -+ tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); -+ tlsv1_record_change_write_cipher(&conn->rl); -+ tlsv1_record_change_read_cipher(&conn->rl); -+ tls_verify_hash_free(&conn->verify); -+ os_free(conn->client_hello_ext); -+ tlsv1_client_free_dh(conn); -+ tlsv1_cred_free(conn->cred); -+ os_free(conn); -+} -+ -+ -+/** -+ * tlsv1_client_established - Check whether connection has been established -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * Returns: 1 if connection is established, 0 if not -+ */ -+int tlsv1_client_established(struct tlsv1_client *conn) -+{ -+ return conn->state == ESTABLISHED; -+} -+ -+ -+/** -+ * tlsv1_client_prf - Use TLS-PRF to derive keying material -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @label: Label (e.g., description of the key) for PRF -+ * @server_random_first: seed is 0 = client_random|server_random, -+ * 1 = server_random|client_random -+ * @out: Buffer for output data from TLS-PRF -+ * @out_len: Length of the output buffer -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, -+ int server_random_first, u8 *out, size_t out_len) -+{ -+ u8 seed[2 * TLS_RANDOM_LEN]; -+ -+ if (conn->state != ESTABLISHED) -+ return -1; -+ -+ if (server_random_first) { -+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, -+ TLS_RANDOM_LEN); -+ } else { -+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, -+ TLS_RANDOM_LEN); -+ } -+ -+ return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ label, seed, 2 * TLS_RANDOM_LEN, out, out_len); -+} -+ -+ -+/** -+ * tlsv1_client_get_cipher - Get current cipher name -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @buf: Buffer for the cipher name -+ * @buflen: buf size -+ * Returns: 0 on success, -1 on failure -+ * -+ * Get the name of the currently used cipher. -+ */ -+int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, -+ size_t buflen) -+{ -+ char *cipher; -+ -+ switch (conn->rl.cipher_suite) { -+ case TLS_RSA_WITH_RC4_128_MD5: -+ cipher = "RC4-MD5"; -+ break; -+ case TLS_RSA_WITH_RC4_128_SHA: -+ cipher = "RC4-SHA"; -+ break; -+ case TLS_RSA_WITH_DES_CBC_SHA: -+ cipher = "DES-CBC-SHA"; -+ break; -+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA: -+ cipher = "DES-CBC3-SHA"; -+ break; -+ case TLS_DH_anon_WITH_AES_128_CBC_SHA: -+ cipher = "ADH-AES-128-SHA"; -+ break; -+ case TLS_RSA_WITH_AES_256_CBC_SHA: -+ cipher = "AES-256-SHA"; -+ break; -+ case TLS_RSA_WITH_AES_128_CBC_SHA: -+ cipher = "AES-128-SHA"; -+ break; -+ default: -+ return -1; -+ } -+ -+ if (os_strlcpy(buf, cipher, buflen) >= buflen) -+ return -1; -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_client_shutdown - Shutdown TLS connection -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_client_shutdown(struct tlsv1_client *conn) -+{ -+ conn->state = CLIENT_HELLO; -+ -+ if (tls_verify_hash_init(&conn->verify) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify " -+ "hash"); -+ return -1; -+ } -+ -+ tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); -+ tlsv1_record_change_write_cipher(&conn->rl); -+ tlsv1_record_change_read_cipher(&conn->rl); -+ -+ conn->certificate_requested = 0; -+ crypto_public_key_free(conn->server_rsa_key); -+ conn->server_rsa_key = NULL; -+ conn->session_resumed = 0; -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_client_resumed - Was session resumption used -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * Returns: 1 if current session used session resumption, 0 if not -+ */ -+int tlsv1_client_resumed(struct tlsv1_client *conn) -+{ -+ return !!conn->session_resumed; -+} -+ -+ -+/** -+ * tlsv1_client_hello_ext - Set TLS extension for ClientHello -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @ext_type: Extension type -+ * @data: Extension payload (%NULL to remove extension) -+ * @data_len: Extension payload length -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type, -+ const u8 *data, size_t data_len) -+{ -+ u8 *pos; -+ -+ conn->session_ticket_included = 0; -+ os_free(conn->client_hello_ext); -+ conn->client_hello_ext = NULL; -+ conn->client_hello_ext_len = 0; -+ -+ if (data == NULL || data_len == 0) -+ return 0; -+ -+ pos = conn->client_hello_ext = os_malloc(6 + data_len); -+ if (pos == NULL) -+ return -1; -+ -+ WPA_PUT_BE16(pos, 4 + data_len); -+ pos += 2; -+ WPA_PUT_BE16(pos, ext_type); -+ pos += 2; -+ WPA_PUT_BE16(pos, data_len); -+ pos += 2; -+ os_memcpy(pos, data, data_len); -+ conn->client_hello_ext_len = 6 + data_len; -+ -+ if (ext_type == TLS_EXT_PAC_OPAQUE) { -+ conn->session_ticket_included = 1; -+ wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket"); -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_client_get_keys - Get master key and random data from TLS connection -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @keys: Structure of key/random data (filled on success) -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys) -+{ -+ os_memset(keys, 0, sizeof(*keys)); -+ if (conn->state == CLIENT_HELLO) -+ return -1; -+ -+ keys->client_random = conn->client_random; -+ keys->client_random_len = TLS_RANDOM_LEN; -+ -+ if (conn->state != SERVER_HELLO) { -+ keys->server_random = conn->server_random; -+ keys->server_random_len = TLS_RANDOM_LEN; -+ keys->master_key = conn->master_secret; -+ keys->master_key_len = TLS_MASTER_SECRET_LEN; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_client_get_keyblock_size - Get TLS key_block size -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on -+ * failure -+ */ -+int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn) -+{ -+ if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO) -+ return -1; -+ -+ return 2 * (conn->rl.hash_size + conn->rl.key_material_len + -+ conn->rl.iv_size); -+} -+ -+ -+/** -+ * tlsv1_client_set_cipher_list - Configure acceptable cipher suites -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers -+ * (TLS_CIPHER_*). -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers) -+{ -+ size_t count; -+ u16 *suites; -+ -+ /* TODO: implement proper configuration of cipher suites */ -+ if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) { -+ count = 0; -+ suites = conn->cipher_suites; -+#ifndef CONFIG_CRYPTO_INTERNAL -+ suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA; -+#endif /* CONFIG_CRYPTO_INTERNAL */ -+ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; -+ suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; -+ suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5; -+ suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA; -+ -+ /* -+ * Cisco AP (at least 350 and 1200 series) local authentication -+ * server does not know how to search cipher suites from the -+ * list and seem to require that the last entry in the list is -+ * the one that it wants to use. However, TLS specification -+ * requires the list to be in the client preference order. As a -+ * workaround, add anon-DH AES-128-SHA1 again at the end of the -+ * list to allow the Cisco code to find it. -+ */ -+ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; -+ conn->num_cipher_suites = count; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_client_set_cred - Set client credentials -+ * @conn: TLSv1 client connection data from tlsv1_client_init() -+ * @cred: Credentials from tlsv1_cred_alloc() -+ * Returns: 0 on success, -1 on failure -+ * -+ * On success, the client takes ownership of the credentials block and caller -+ * must not free it. On failure, caller is responsible for freeing the -+ * credential block. -+ */ -+int tlsv1_client_set_cred(struct tlsv1_client *conn, -+ struct tlsv1_credentials *cred) -+{ -+ tlsv1_cred_free(conn->cred); -+ conn->cred = cred; -+ return 0; -+} -+ -+ -+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, -+ tlsv1_client_session_ticket_cb cb, -+ void *ctx) -+{ -+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)", -+ cb, ctx); -+ conn->session_ticket_cb = cb; -+ conn->session_ticket_cb_ctx = ctx; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.h -new file mode 100644 -index 0000000000000..16ad57d4007fe ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client.h -@@ -0,0 +1,59 @@ -+/* -+ * TLSv1 client (RFC 2246) -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLSV1_CLIENT_H -+#define TLSV1_CLIENT_H -+ -+#include "tlsv1_cred.h" -+ -+struct tlsv1_client; -+ -+int tlsv1_client_global_init(void); -+void tlsv1_client_global_deinit(void); -+struct tlsv1_client * tlsv1_client_init(void); -+void tlsv1_client_deinit(struct tlsv1_client *conn); -+int tlsv1_client_established(struct tlsv1_client *conn); -+int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, -+ int server_random_first, u8 *out, size_t out_len); -+u8 * tlsv1_client_handshake(struct tlsv1_client *conn, -+ const u8 *in_data, size_t in_len, -+ size_t *out_len, u8 **appl_data, -+ size_t *appl_data_len); -+int tlsv1_client_encrypt(struct tlsv1_client *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len); -+int tlsv1_client_decrypt(struct tlsv1_client *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len); -+int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, -+ size_t buflen); -+int tlsv1_client_shutdown(struct tlsv1_client *conn); -+int tlsv1_client_resumed(struct tlsv1_client *conn); -+int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type, -+ const u8 *data, size_t data_len); -+int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys); -+int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn); -+int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers); -+int tlsv1_client_set_cred(struct tlsv1_client *conn, -+ struct tlsv1_credentials *cred); -+ -+typedef int (*tlsv1_client_session_ticket_cb) -+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, -+ const u8 *server_random, u8 *master_secret); -+ -+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn, -+ tlsv1_client_session_ticket_cb cb, -+ void *ctx); -+ -+#endif /* TLSV1_CLIENT_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_i.h -new file mode 100644 -index 0000000000000..7fe179f10c63b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_i.h -@@ -0,0 +1,87 @@ -+/* -+ * TLSv1 client - internal structures -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLSV1_CLIENT_I_H -+#define TLSV1_CLIENT_I_H -+ -+struct tlsv1_client { -+ enum { -+ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, -+ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, -+ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC, -+ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED, -+ ESTABLISHED, FAILED -+ } state; -+ -+ struct tlsv1_record_layer rl; -+ -+ u8 session_id[TLS_SESSION_ID_MAX_LEN]; -+ size_t session_id_len; -+ u8 client_random[TLS_RANDOM_LEN]; -+ u8 server_random[TLS_RANDOM_LEN]; -+ u8 master_secret[TLS_MASTER_SECRET_LEN]; -+ -+ u8 alert_level; -+ u8 alert_description; -+ -+ unsigned int certificate_requested:1; -+ unsigned int session_resumed:1; -+ unsigned int session_ticket_included:1; -+ unsigned int use_session_ticket:1; -+ -+ struct crypto_public_key *server_rsa_key; -+ -+ struct tls_verify_hash verify; -+ -+#define MAX_CIPHER_COUNT 30 -+ u16 cipher_suites[MAX_CIPHER_COUNT]; -+ size_t num_cipher_suites; -+ -+ u16 prev_cipher_suite; -+ -+ u8 *client_hello_ext; -+ size_t client_hello_ext_len; -+ -+ /* The prime modulus used for Diffie-Hellman */ -+ u8 *dh_p; -+ size_t dh_p_len; -+ /* The generator used for Diffie-Hellman */ -+ u8 *dh_g; -+ size_t dh_g_len; -+ /* The server's Diffie-Hellman public value */ -+ u8 *dh_ys; -+ size_t dh_ys_len; -+ -+ struct tlsv1_credentials *cred; -+ -+ tlsv1_client_session_ticket_cb session_ticket_cb; -+ void *session_ticket_cb_ctx; -+}; -+ -+ -+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description); -+void tlsv1_client_free_dh(struct tlsv1_client *conn); -+int tls_derive_pre_master_secret(u8 *pre_master_secret); -+int tls_derive_keys(struct tlsv1_client *conn, -+ const u8 *pre_master_secret, size_t pre_master_secret_len); -+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len); -+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, -+ u8 description, size_t *out_len); -+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, -+ int no_appl_data); -+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, -+ const u8 *buf, size_t *len, -+ u8 **out_data, size_t *out_len); -+ -+#endif /* TLSV1_CLIENT_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_read.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_read.c -new file mode 100644 -index 0000000000000..ed3f2606c8cc2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_read.c -@@ -0,0 +1,976 @@ -+/* -+ * TLSv1 client - read handshake message -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/md5.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "x509v3.h" -+#include "tlsv1_common.h" -+#include "tlsv1_record.h" -+#include "tlsv1_client.h" -+#include "tlsv1_client_i.h" -+ -+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len); -+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len); -+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len); -+ -+ -+static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len, i; -+ u16 cipher_suite; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) -+ goto decode_error; -+ -+ /* HandshakeType msg_type */ -+ if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected ServerHello)", *pos); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello"); -+ pos++; -+ /* uint24 length */ -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) -+ goto decode_error; -+ -+ /* body - ServerHello */ -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len); -+ end = pos + len; -+ -+ /* ProtocolVersion server_version */ -+ if (end - pos < 2) -+ goto decode_error; -+ if (WPA_GET_BE16(pos) != TLS_VERSION) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " -+ "ServerHello"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_PROTOCOL_VERSION); -+ return -1; -+ } -+ pos += 2; -+ -+ /* Random random */ -+ if (end - pos < TLS_RANDOM_LEN) -+ goto decode_error; -+ -+ os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN); -+ pos += TLS_RANDOM_LEN; -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", -+ conn->server_random, TLS_RANDOM_LEN); -+ -+ /* SessionID session_id */ -+ if (end - pos < 1) -+ goto decode_error; -+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) -+ goto decode_error; -+ if (conn->session_id_len && conn->session_id_len == *pos && -+ os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) { -+ pos += 1 + conn->session_id_len; -+ wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session"); -+ conn->session_resumed = 1; -+ } else { -+ conn->session_id_len = *pos; -+ pos++; -+ os_memcpy(conn->session_id, pos, conn->session_id_len); -+ pos += conn->session_id_len; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", -+ conn->session_id, conn->session_id_len); -+ -+ /* CipherSuite cipher_suite */ -+ if (end - pos < 2) -+ goto decode_error; -+ cipher_suite = WPA_GET_BE16(pos); -+ pos += 2; -+ for (i = 0; i < conn->num_cipher_suites; i++) { -+ if (cipher_suite == conn->cipher_suites[i]) -+ break; -+ } -+ if (i == conn->num_cipher_suites) { -+ wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " -+ "cipher suite 0x%04x", cipher_suite); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_ILLEGAL_PARAMETER); -+ return -1; -+ } -+ -+ if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different " -+ "cipher suite for a resumed connection (0x%04x != " -+ "0x%04x)", cipher_suite, conn->prev_cipher_suite); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_ILLEGAL_PARAMETER); -+ return -1; -+ } -+ -+ if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " -+ "record layer"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ conn->prev_cipher_suite = cipher_suite; -+ -+ /* CompressionMethod compression_method */ -+ if (end - pos < 1) -+ goto decode_error; -+ if (*pos != TLS_COMPRESSION_NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected " -+ "compression 0x%02x", *pos); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_ILLEGAL_PARAMETER); -+ return -1; -+ } -+ pos++; -+ -+ if (end != pos) { -+ /* TODO: ServerHello extensions */ -+ wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the " -+ "end of ServerHello", pos, end - pos); -+ goto decode_error; -+ } -+ -+ if (conn->session_ticket_included && conn->session_ticket_cb) { -+ /* TODO: include SessionTicket extension if one was included in -+ * ServerHello */ -+ int res = conn->session_ticket_cb( -+ conn->session_ticket_cb_ctx, NULL, 0, -+ conn->client_random, conn->server_random, -+ conn->master_secret); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " -+ "indicated failure"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_HANDSHAKE_FAILURE); -+ return -1; -+ } -+ conn->use_session_ticket = !!res; -+ } -+ -+ if ((conn->session_resumed || conn->use_session_ticket) && -+ tls_derive_keys(conn, NULL, 0)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ *in_len = end - in_data; -+ -+ conn->state = (conn->session_resumed || conn->use_session_ticket) ? -+ SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE; -+ -+ return 0; -+ -+decode_error: -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+} -+ -+ -+static int tls_process_certificate(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len, list_len, cert_len, idx; -+ u8 type; -+ struct x509_certificate *chain = NULL, *last = NULL, *cert; -+ int reason; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " -+ "(len=%lu)", (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ type = *pos++; -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " -+ "length (len=%lu != left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) -+ return tls_process_server_key_exchange(conn, ct, in_data, -+ in_len); -+ if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) -+ return tls_process_certificate_request(conn, ct, in_data, -+ in_len); -+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) -+ return tls_process_server_hello_done(conn, ct, in_data, -+ in_len); -+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected Certificate/" -+ "ServerKeyExchange/CertificateRequest/" -+ "ServerHelloDone)", type); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, -+ "TLSv1: Received Certificate (certificate_list len %lu)", -+ (unsigned long) len); -+ -+ /* -+ * opaque ASN.1Cert<2^24-1>; -+ * -+ * struct { -+ * ASN.1Cert certificate_list<1..2^24-1>; -+ * } Certificate; -+ */ -+ -+ end = pos + len; -+ -+ if (end - pos < 3) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " -+ "(left=%lu)", (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ list_len = WPA_GET_BE24(pos); -+ pos += 3; -+ -+ if ((size_t) (end - pos) != list_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " -+ "length (len=%lu left=%lu)", -+ (unsigned long) list_len, -+ (unsigned long) (end - pos)); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ idx = 0; -+ while (pos < end) { -+ if (end - pos < 3) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " -+ "certificate_list"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ cert_len = WPA_GET_BE24(pos); -+ pos += 3; -+ -+ if ((size_t) (end - pos) < cert_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " -+ "length (len=%lu left=%lu)", -+ (unsigned long) cert_len, -+ (unsigned long) (end - pos)); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", -+ (unsigned long) idx, (unsigned long) cert_len); -+ -+ if (idx == 0) { -+ crypto_public_key_free(conn->server_rsa_key); -+ if (tls_parse_cert(pos, cert_len, -+ &conn->server_rsa_key)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " -+ "the certificate"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_BAD_CERTIFICATE); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ } -+ -+ cert = x509_certificate_parse(pos, cert_len); -+ if (cert == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " -+ "the certificate"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_BAD_CERTIFICATE); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ if (last == NULL) -+ chain = cert; -+ else -+ last->next = cert; -+ last = cert; -+ -+ idx++; -+ pos += cert_len; -+ } -+ -+ if (conn->cred && -+ x509_certificate_chain_validate(conn->cred->trusted_certs, chain, -+ &reason) < 0) { -+ int tls_reason; -+ wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " -+ "validation failed (reason=%d)", reason); -+ switch (reason) { -+ case X509_VALIDATE_BAD_CERTIFICATE: -+ tls_reason = TLS_ALERT_BAD_CERTIFICATE; -+ break; -+ case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: -+ tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; -+ break; -+ case X509_VALIDATE_CERTIFICATE_REVOKED: -+ tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; -+ break; -+ case X509_VALIDATE_CERTIFICATE_EXPIRED: -+ tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; -+ break; -+ case X509_VALIDATE_CERTIFICATE_UNKNOWN: -+ tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; -+ break; -+ case X509_VALIDATE_UNKNOWN_CA: -+ tls_reason = TLS_ALERT_UNKNOWN_CA; -+ break; -+ default: -+ tls_reason = TLS_ALERT_BAD_CERTIFICATE; -+ break; -+ } -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ x509_certificate_chain_free(chain); -+ -+ *in_len = end - in_data; -+ -+ conn->state = SERVER_KEY_EXCHANGE; -+ -+ return 0; -+} -+ -+ -+static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, -+ const u8 *buf, size_t len) -+{ -+ const u8 *pos, *end; -+ -+ tlsv1_client_free_dh(conn); -+ -+ pos = buf; -+ end = buf + len; -+ -+ if (end - pos < 3) -+ goto fail; -+ conn->dh_p_len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu", -+ (unsigned long) conn->dh_p_len); -+ goto fail; -+ } -+ conn->dh_p = os_malloc(conn->dh_p_len); -+ if (conn->dh_p == NULL) -+ goto fail; -+ os_memcpy(conn->dh_p, pos, conn->dh_p_len); -+ pos += conn->dh_p_len; -+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)", -+ conn->dh_p, conn->dh_p_len); -+ -+ if (end - pos < 3) -+ goto fail; -+ conn->dh_g_len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len) -+ goto fail; -+ conn->dh_g = os_malloc(conn->dh_g_len); -+ if (conn->dh_g == NULL) -+ goto fail; -+ os_memcpy(conn->dh_g, pos, conn->dh_g_len); -+ pos += conn->dh_g_len; -+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)", -+ conn->dh_g, conn->dh_g_len); -+ if (conn->dh_g_len == 1 && conn->dh_g[0] < 2) -+ goto fail; -+ -+ if (end - pos < 3) -+ goto fail; -+ conn->dh_ys_len = WPA_GET_BE16(pos); -+ pos += 2; -+ if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len) -+ goto fail; -+ conn->dh_ys = os_malloc(conn->dh_ys_len); -+ if (conn->dh_ys == NULL) -+ goto fail; -+ os_memcpy(conn->dh_ys, pos, conn->dh_ys_len); -+ pos += conn->dh_ys_len; -+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", -+ conn->dh_ys, conn->dh_ys_len); -+ -+ return 0; -+ -+fail: -+ wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed"); -+ tlsv1_client_free_dh(conn); -+ return -1; -+} -+ -+ -+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len; -+ u8 type; -+ const struct tls_cipher_suite *suite; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange " -+ "(Left=%lu)", (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ type = *pos++; -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange " -+ "length (len=%lu != left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ end = pos + len; -+ -+ if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) -+ return tls_process_certificate_request(conn, ct, in_data, -+ in_len); -+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) -+ return tls_process_server_hello_done(conn, ct, in_data, -+ in_len); -+ if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected ServerKeyExchange/" -+ "CertificateRequest/ServerHelloDone)", type); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange"); -+ -+ if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed " -+ "with the selected cipher suite"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len); -+ suite = tls_get_cipher_suite(conn->rl.cipher_suite); -+ if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { -+ if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) { -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ } else { -+ wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ *in_len = end - in_data; -+ -+ conn->state = SERVER_CERTIFICATE_REQUEST; -+ -+ return 0; -+} -+ -+ -+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len; -+ u8 type; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest " -+ "(left=%lu)", (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ type = *pos++; -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest " -+ "length (len=%lu != left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ end = pos + len; -+ -+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) -+ return tls_process_server_hello_done(conn, ct, in_data, -+ in_len); -+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected CertificateRequest/" -+ "ServerHelloDone)", type); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest"); -+ -+ conn->certificate_requested = 1; -+ -+ *in_len = end - in_data; -+ -+ conn->state = SERVER_HELLO_DONE; -+ -+ return 0; -+} -+ -+ -+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len; -+ u8 type; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone " -+ "(left=%lu)", (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ type = *pos++; -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone " -+ "length (len=%lu != left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ end = pos + len; -+ -+ if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected ServerHelloDone)", type); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone"); -+ -+ *in_len = end - in_data; -+ -+ conn->state = CLIENT_KEY_EXCHANGE; -+ -+ return 0; -+} -+ -+ -+static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn, -+ u8 ct, const u8 *in_data, -+ size_t *in_len) -+{ -+ const u8 *pos; -+ size_t left; -+ -+ if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " -+ "received content type 0x%x", ct); -+ if (conn->use_session_ticket) { -+ int res; -+ wpa_printf(MSG_DEBUG, "TLSv1: Server may have " -+ "rejected SessionTicket"); -+ conn->use_session_ticket = 0; -+ -+ /* Notify upper layers that SessionTicket failed */ -+ res = conn->session_ticket_cb( -+ conn->session_ticket_cb_ctx, NULL, 0, NULL, -+ NULL, NULL); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket " -+ "callback indicated failure"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_HANDSHAKE_FAILURE); -+ return -1; -+ } -+ -+ conn->state = SERVER_CERTIFICATE; -+ return tls_process_certificate(conn, ct, in_data, -+ in_len); -+ } -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 1) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ if (*pos != TLS_CHANGE_CIPHER_SPEC) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " -+ "received data 0x%x", *pos); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); -+ if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " -+ "for record layer"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ *in_len = pos + 1 - in_data; -+ -+ conn->state = SERVER_FINISHED; -+ -+ return 0; -+} -+ -+ -+static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len, hlen; -+ u8 verify_data[TLS_VERIFY_DATA_LEN]; -+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " -+ "received content type 0x%x", ct); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " -+ "Finished", -+ (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " -+ "type 0x%x", pos[0]); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ len = WPA_GET_BE24(pos + 1); -+ -+ pos += 4; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " -+ "(len=%lu > left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ end = pos + len; -+ if (len != TLS_VERIFY_DATA_LEN) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " -+ "in Finished: %lu (expected %d)", -+ (unsigned long) len, TLS_VERIFY_DATA_LEN); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", -+ pos, TLS_VERIFY_DATA_LEN); -+ -+ hlen = MD5_MAC_LEN; -+ if (conn->verify.md5_server == NULL || -+ crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ conn->verify.md5_server = NULL; -+ crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); -+ conn->verify.sha1_server = NULL; -+ return -1; -+ } -+ conn->verify.md5_server = NULL; -+ hlen = SHA1_MAC_LEN; -+ if (conn->verify.sha1_server == NULL || -+ crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, -+ &hlen) < 0) { -+ conn->verify.sha1_server = NULL; -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ conn->verify.sha1_server = NULL; -+ -+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, -+ verify_data, TLS_VERIFY_DATA_LEN)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECRYPT_ERROR); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", -+ verify_data, TLS_VERIFY_DATA_LEN); -+ -+ if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { -+ wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); -+ -+ *in_len = end - in_data; -+ -+ conn->state = (conn->session_resumed || conn->use_session_ticket) ? -+ CHANGE_CIPHER_SPEC : ACK_FINISHED; -+ -+ return 0; -+} -+ -+ -+static int tls_process_application_data(struct tlsv1_client *conn, u8 ct, -+ const u8 *in_data, size_t *in_len, -+ u8 **out_data, size_t *out_len) -+{ -+ const u8 *pos; -+ size_t left; -+ -+ if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; " -+ "received content type 0x%x", ct); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake", -+ pos, left); -+ -+ *out_data = os_malloc(left); -+ if (*out_data) { -+ os_memcpy(*out_data, pos, left); -+ *out_len = left; -+ } -+ -+ return 0; -+} -+ -+ -+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, -+ const u8 *buf, size_t *len, -+ u8 **out_data, size_t *out_len) -+{ -+ if (ct == TLS_CONTENT_TYPE_ALERT) { -+ if (*len < 2) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", -+ buf[0], buf[1]); -+ *len = 2; -+ conn->state = FAILED; -+ return -1; -+ } -+ -+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 && -+ buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) { -+ size_t hr_len = WPA_GET_BE24(buf + 1); -+ if (hr_len > *len - 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest"); -+ *len = 4 + hr_len; -+ return 0; -+ } -+ -+ switch (conn->state) { -+ case SERVER_HELLO: -+ if (tls_process_server_hello(conn, ct, buf, len)) -+ return -1; -+ break; -+ case SERVER_CERTIFICATE: -+ if (tls_process_certificate(conn, ct, buf, len)) -+ return -1; -+ break; -+ case SERVER_KEY_EXCHANGE: -+ if (tls_process_server_key_exchange(conn, ct, buf, len)) -+ return -1; -+ break; -+ case SERVER_CERTIFICATE_REQUEST: -+ if (tls_process_certificate_request(conn, ct, buf, len)) -+ return -1; -+ break; -+ case SERVER_HELLO_DONE: -+ if (tls_process_server_hello_done(conn, ct, buf, len)) -+ return -1; -+ break; -+ case SERVER_CHANGE_CIPHER_SPEC: -+ if (tls_process_server_change_cipher_spec(conn, ct, buf, len)) -+ return -1; -+ break; -+ case SERVER_FINISHED: -+ if (tls_process_server_finished(conn, ct, buf, len)) -+ return -1; -+ break; -+ case ACK_FINISHED: -+ if (out_data && -+ tls_process_application_data(conn, ct, buf, len, out_data, -+ out_len)) -+ return -1; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " -+ "while processing received message", -+ conn->state); -+ return -1; -+ } -+ -+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE) -+ tls_verify_hash_add(&conn->verify, buf, *len); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_write.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_write.c -new file mode 100644 -index 0000000000000..0898df9a02b45 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_client_write.c -@@ -0,0 +1,798 @@ -+/* -+ * TLSv1 client - write handshake message -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/md5.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "crypto/random.h" -+#include "x509v3.h" -+#include "tlsv1_common.h" -+#include "tlsv1_record.h" -+#include "tlsv1_client.h" -+#include "tlsv1_client_i.h" -+ -+ -+static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn) -+{ -+ size_t len = 0; -+ struct x509_certificate *cert; -+ -+ if (conn->cred == NULL) -+ return 0; -+ -+ cert = conn->cred->cert; -+ while (cert) { -+ len += 3 + cert->cert_len; -+ if (x509_certificate_self_signed(cert)) -+ break; -+ cert = x509_certificate_get_subject(conn->cred->trusted_certs, -+ &cert->issuer); -+ } -+ -+ return len; -+} -+ -+ -+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len) -+{ -+ u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr; -+ struct os_time now; -+ size_t len, i; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello"); -+ *out_len = 0; -+ -+ os_get_time(&now); -+ WPA_PUT_BE32(conn->client_random, now.sec); -+ if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) { -+ wpa_printf(MSG_ERROR, "TLSv1: Could not generate " -+ "client_random"); -+ return NULL; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", -+ conn->client_random, TLS_RANDOM_LEN); -+ -+ len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len; -+ hello = os_malloc(len); -+ if (hello == NULL) -+ return NULL; -+ end = hello + len; -+ -+ rhdr = hello; -+ pos = rhdr + TLS_RECORD_HEADER_LEN; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ /* body - ClientHello */ -+ /* ProtocolVersion client_version */ -+ WPA_PUT_BE16(pos, TLS_VERSION); -+ pos += 2; -+ /* Random random: uint32 gmt_unix_time, opaque random_bytes */ -+ os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN); -+ pos += TLS_RANDOM_LEN; -+ /* SessionID session_id */ -+ *pos++ = conn->session_id_len; -+ os_memcpy(pos, conn->session_id, conn->session_id_len); -+ pos += conn->session_id_len; -+ /* CipherSuite cipher_suites<2..2^16-1> */ -+ WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites); -+ pos += 2; -+ for (i = 0; i < conn->num_cipher_suites; i++) { -+ WPA_PUT_BE16(pos, conn->cipher_suites[i]); -+ pos += 2; -+ } -+ /* CompressionMethod compression_methods<1..2^8-1> */ -+ *pos++ = 1; -+ *pos++ = TLS_COMPRESSION_NULL; -+ -+ if (conn->client_hello_ext) { -+ os_memcpy(pos, conn->client_hello_ext, -+ conn->client_hello_ext_len); -+ pos += conn->client_hello_ext_len; -+ } -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, out_len) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(hello); -+ return NULL; -+ } -+ -+ conn->state = SERVER_HELLO; -+ -+ return hello; -+} -+ -+ -+static int tls_write_client_certificate(struct tlsv1_client *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; -+ size_t rlen; -+ struct x509_certificate *cert; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ /* body - Certificate */ -+ /* uint24 length (to be filled) */ -+ cert_start = pos; -+ pos += 3; -+ cert = conn->cred ? conn->cred->cert : NULL; -+ while (cert) { -+ if (pos + 3 + cert->cert_len > end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " -+ "for Certificate (cert_len=%lu left=%lu)", -+ (unsigned long) cert->cert_len, -+ (unsigned long) (end - pos)); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ WPA_PUT_BE24(pos, cert->cert_len); -+ pos += 3; -+ os_memcpy(pos, cert->cert_start, cert->cert_len); -+ pos += cert->cert_len; -+ -+ if (x509_certificate_self_signed(cert)) -+ break; -+ cert = x509_certificate_get_subject(conn->cred->trusted_certs, -+ &cert->issuer); -+ } -+ if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) { -+ /* -+ * Client was not configured with all the needed certificates -+ * to form a full certificate chain. The server may fail to -+ * validate the chain unless it is configured with all the -+ * missing CA certificates. -+ */ -+ wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain " -+ "not configured - validation may fail"); -+ } -+ WPA_PUT_BE24(cert_start, pos - cert_start - 3); -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end) -+{ -+ /* ClientDiffieHellmanPublic */ -+ u8 *csecret, *csecret_start, *dh_yc, *shared; -+ size_t csecret_len, dh_yc_len, shared_len; -+ -+ csecret_len = conn->dh_p_len; -+ csecret = os_malloc(csecret_len); -+ if (csecret == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " -+ "memory for Yc (Diffie-Hellman)"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ if (random_get_bytes(csecret, csecret_len)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " -+ "data for Diffie-Hellman"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(csecret); -+ return -1; -+ } -+ -+ if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0) -+ csecret[0] = 0; /* make sure Yc < p */ -+ -+ csecret_start = csecret; -+ while (csecret_len > 1 && *csecret_start == 0) { -+ csecret_start++; -+ csecret_len--; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value", -+ csecret_start, csecret_len); -+ -+ /* Yc = g^csecret mod p */ -+ dh_yc_len = conn->dh_p_len; -+ dh_yc = os_malloc(dh_yc_len); -+ if (dh_yc == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " -+ "memory for Diffie-Hellman"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(csecret); -+ return -1; -+ } -+ if (crypto_mod_exp(conn->dh_g, conn->dh_g_len, -+ csecret_start, csecret_len, -+ conn->dh_p, conn->dh_p_len, -+ dh_yc, &dh_yc_len)) { -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(csecret); -+ os_free(dh_yc); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", -+ dh_yc, dh_yc_len); -+ -+ WPA_PUT_BE16(*pos, dh_yc_len); -+ *pos += 2; -+ if (*pos + dh_yc_len > end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the " -+ "message buffer for Yc"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(csecret); -+ os_free(dh_yc); -+ return -1; -+ } -+ os_memcpy(*pos, dh_yc, dh_yc_len); -+ *pos += dh_yc_len; -+ os_free(dh_yc); -+ -+ shared_len = conn->dh_p_len; -+ shared = os_malloc(shared_len); -+ if (shared == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " -+ "DH"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(csecret); -+ return -1; -+ } -+ -+ /* shared = Ys^csecret mod p */ -+ if (crypto_mod_exp(conn->dh_ys, conn->dh_ys_len, -+ csecret_start, csecret_len, -+ conn->dh_p, conn->dh_p_len, -+ shared, &shared_len)) { -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(csecret); -+ os_free(shared); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", -+ shared, shared_len); -+ -+ os_memset(csecret_start, 0, csecret_len); -+ os_free(csecret); -+ if (tls_derive_keys(conn, shared, shared_len)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(shared); -+ return -1; -+ } -+ os_memset(shared, 0, shared_len); -+ os_free(shared); -+ tlsv1_client_free_dh(conn); -+ return 0; -+} -+ -+ -+static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end) -+{ -+ u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN]; -+ size_t clen; -+ int res; -+ -+ if (tls_derive_pre_master_secret(pre_master_secret) < 0 || -+ tls_derive_keys(conn, pre_master_secret, -+ TLS_PRE_MASTER_SECRET_LEN)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ /* EncryptedPreMasterSecret */ -+ if (conn->server_rsa_key == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to " -+ "use for encrypting pre-master secret"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */ -+ *pos += 2; -+ clen = end - *pos; -+ res = crypto_public_key_encrypt_pkcs1_v15( -+ conn->server_rsa_key, -+ pre_master_secret, TLS_PRE_MASTER_SECRET_LEN, -+ *pos, &clen); -+ os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ WPA_PUT_BE16(*pos - 2, clen); -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret", -+ *pos, clen); -+ *pos += clen; -+ -+ return 0; -+} -+ -+ -+static int tls_write_client_key_exchange(struct tlsv1_client *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length; -+ size_t rlen; -+ tls_key_exchange keyx; -+ const struct tls_cipher_suite *suite; -+ -+ suite = tls_get_cipher_suite(conn->rl.cipher_suite); -+ if (suite == NULL) -+ keyx = TLS_KEY_X_NULL; -+ else -+ keyx = suite->key_exchange; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange"); -+ -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ /* body - ClientKeyExchange */ -+ if (keyx == TLS_KEY_X_DH_anon) { -+ if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0) -+ return -1; -+ } else { -+ if (tlsv1_key_x_rsa(conn, &pos, end) < 0) -+ return -1; -+ } -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tls_write_client_certificate_verify(struct tlsv1_client *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start; -+ size_t rlen, hlen, clen; -+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos; -+ enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ -+ /* -+ * RFC 2246: 7.4.3 and 7.4.8: -+ * Signature signature -+ * -+ * RSA: -+ * digitally-signed struct { -+ * opaque md5_hash[16]; -+ * opaque sha_hash[20]; -+ * }; -+ * -+ * DSA: -+ * digitally-signed struct { -+ * opaque sha_hash[20]; -+ * }; -+ * -+ * The hash values are calculated over all handshake messages sent or -+ * received starting at ClientHello up to, but not including, this -+ * CertificateVerify message, including the type and length fields of -+ * the handshake messages. -+ */ -+ -+ hpos = hash; -+ -+ if (alg == SIGN_ALG_RSA) { -+ hlen = MD5_MAC_LEN; -+ if (conn->verify.md5_cert == NULL || -+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) -+ { -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ conn->verify.md5_cert = NULL; -+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); -+ conn->verify.sha1_cert = NULL; -+ return -1; -+ } -+ hpos += MD5_MAC_LEN; -+ } else -+ crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); -+ -+ conn->verify.md5_cert = NULL; -+ hlen = SHA1_MAC_LEN; -+ if (conn->verify.sha1_cert == NULL || -+ crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { -+ conn->verify.sha1_cert = NULL; -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ conn->verify.sha1_cert = NULL; -+ -+ if (alg == SIGN_ALG_RSA) -+ hlen += MD5_MAC_LEN; -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); -+ -+ /* -+ * RFC 2246, 4.7: -+ * In digital signing, one-way hash functions are used as input for a -+ * signing algorithm. A digitally-signed element is encoded as an -+ * opaque vector <0..2^16-1>, where the length is specified by the -+ * signing algorithm and key. -+ * -+ * In RSA signing, a 36-byte structure of two hashes (one SHA and one -+ * MD5) is signed (encrypted with the private key). It is encoded with -+ * PKCS #1 block type 0 or type 1 as described in [PKCS1]. -+ */ -+ signed_start = pos; /* length to be filled */ -+ pos += 2; -+ clen = end - pos; -+ if (conn->cred == NULL || -+ crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen, -+ pos, &clen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ WPA_PUT_BE16(signed_start, clen); -+ -+ pos += clen; -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr; -+ size_t rlen; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ *pos = TLS_CHANGE_CIPHER_SPEC; -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, -+ rhdr, end - rhdr, 1, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " -+ "record layer"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ *msgpos = rhdr + rlen; -+ -+ return 0; -+} -+ -+ -+static int tls_write_client_finished(struct tlsv1_client *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length; -+ size_t rlen, hlen; -+ u8 verify_data[TLS_VERIFY_DATA_LEN]; -+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); -+ -+ /* Encrypted Handshake Message: Finished */ -+ -+ hlen = MD5_MAC_LEN; -+ if (conn->verify.md5_client == NULL || -+ crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ conn->verify.md5_client = NULL; -+ crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); -+ conn->verify.sha1_client = NULL; -+ return -1; -+ } -+ conn->verify.md5_client = NULL; -+ hlen = SHA1_MAC_LEN; -+ if (conn->verify.sha1_client == NULL || -+ crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, -+ &hlen) < 0) { -+ conn->verify.sha1_client = NULL; -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ conn->verify.sha1_client = NULL; -+ -+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, -+ verify_data, TLS_VERIFY_DATA_LEN)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", -+ verify_data, TLS_VERIFY_DATA_LEN); -+ -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); -+ pos += TLS_VERIFY_DATA_LEN; -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); -+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ pos = rhdr + rlen; -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn, -+ size_t *out_len) -+{ -+ u8 *msg, *end, *pos; -+ size_t msglen; -+ -+ *out_len = 0; -+ -+ msglen = 2000; -+ if (conn->certificate_requested) -+ msglen += tls_client_cert_chain_der_len(conn); -+ -+ msg = os_malloc(msglen); -+ if (msg == NULL) -+ return NULL; -+ -+ pos = msg; -+ end = msg + msglen; -+ -+ if (conn->certificate_requested) { -+ if (tls_write_client_certificate(conn, &pos, end) < 0) { -+ os_free(msg); -+ return NULL; -+ } -+ } -+ -+ if (tls_write_client_key_exchange(conn, &pos, end) < 0 || -+ (conn->certificate_requested && conn->cred && conn->cred->key && -+ tls_write_client_certificate_verify(conn, &pos, end) < 0) || -+ tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || -+ tls_write_client_finished(conn, &pos, end) < 0) { -+ os_free(msg); -+ return NULL; -+ } -+ -+ *out_len = pos - msg; -+ -+ conn->state = SERVER_CHANGE_CIPHER_SPEC; -+ -+ return msg; -+} -+ -+ -+static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn, -+ size_t *out_len) -+{ -+ u8 *msg, *end, *pos; -+ -+ *out_len = 0; -+ -+ msg = os_malloc(1000); -+ if (msg == NULL) -+ return NULL; -+ -+ pos = msg; -+ end = msg + 1000; -+ -+ if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 || -+ tls_write_client_finished(conn, &pos, end) < 0) { -+ os_free(msg); -+ return NULL; -+ } -+ -+ *out_len = pos - msg; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed " -+ "successfully"); -+ conn->state = ESTABLISHED; -+ -+ return msg; -+} -+ -+ -+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len, -+ int no_appl_data) -+{ -+ switch (conn->state) { -+ case CLIENT_KEY_EXCHANGE: -+ return tls_send_client_key_exchange(conn, out_len); -+ case CHANGE_CIPHER_SPEC: -+ return tls_send_change_cipher_spec(conn, out_len); -+ case ACK_FINISHED: -+ wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed " -+ "successfully"); -+ conn->state = ESTABLISHED; -+ *out_len = 0; -+ if (no_appl_data) { -+ /* Need to return something to get final TLS ACK. */ -+ return os_malloc(1); -+ } -+ return NULL; -+ default: -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " -+ "generating reply", conn->state); -+ return NULL; -+ } -+} -+ -+ -+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level, -+ u8 description, size_t *out_len) -+{ -+ u8 *alert, *pos, *length; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); -+ *out_len = 0; -+ -+ alert = os_malloc(10); -+ if (alert == NULL) -+ return NULL; -+ -+ pos = alert; -+ -+ /* TLSPlaintext */ -+ /* ContentType type */ -+ *pos++ = TLS_CONTENT_TYPE_ALERT; -+ /* ProtocolVersion version */ -+ WPA_PUT_BE16(pos, TLS_VERSION); -+ pos += 2; -+ /* uint16 length (to be filled) */ -+ length = pos; -+ pos += 2; -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Alert */ -+ /* AlertLevel level */ -+ *pos++ = level; -+ /* AlertDescription description */ -+ *pos++ = description; -+ -+ WPA_PUT_BE16(length, pos - length - 2); -+ *out_len = pos - alert; -+ -+ return alert; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.c -new file mode 100644 -index 0000000000000..2f9dd0fa887d1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.c -@@ -0,0 +1,241 @@ -+/* -+ * TLSv1 common routines -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "x509v3.h" -+#include "tlsv1_common.h" -+ -+ -+/* -+ * TODO: -+ * RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA -+ * Add support for commonly used cipher suites; don't bother with exportable -+ * suites. -+ */ -+ -+static const struct tls_cipher_suite tls_cipher_suites[] = { -+ { TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL, -+ TLS_HASH_NULL }, -+ { TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128, -+ TLS_HASH_MD5 }, -+ { TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128, -+ TLS_HASH_SHA }, -+ { TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC, -+ TLS_HASH_SHA }, -+ { TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA, -+ TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, -+ { TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon, -+ TLS_CIPHER_RC4_128, TLS_HASH_MD5 }, -+ { TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon, -+ TLS_CIPHER_DES_CBC, TLS_HASH_SHA }, -+ { TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon, -+ TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA }, -+ { TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC, -+ TLS_HASH_SHA }, -+ { TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon, -+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA }, -+ { TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC, -+ TLS_HASH_SHA }, -+ { TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon, -+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA } -+}; -+ -+#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0])) -+#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites) -+ -+ -+static const struct tls_cipher_data tls_ciphers[] = { -+ { TLS_CIPHER_NULL, TLS_CIPHER_STREAM, 0, 0, 0, -+ CRYPTO_CIPHER_NULL }, -+ { TLS_CIPHER_IDEA_CBC, TLS_CIPHER_BLOCK, 16, 16, 8, -+ CRYPTO_CIPHER_NULL }, -+ { TLS_CIPHER_RC2_CBC_40, TLS_CIPHER_BLOCK, 5, 16, 0, -+ CRYPTO_CIPHER_ALG_RC2 }, -+ { TLS_CIPHER_RC4_40, TLS_CIPHER_STREAM, 5, 16, 0, -+ CRYPTO_CIPHER_ALG_RC4 }, -+ { TLS_CIPHER_RC4_128, TLS_CIPHER_STREAM, 16, 16, 0, -+ CRYPTO_CIPHER_ALG_RC4 }, -+ { TLS_CIPHER_DES40_CBC, TLS_CIPHER_BLOCK, 5, 8, 8, -+ CRYPTO_CIPHER_ALG_DES }, -+ { TLS_CIPHER_DES_CBC, TLS_CIPHER_BLOCK, 8, 8, 8, -+ CRYPTO_CIPHER_ALG_DES }, -+ { TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK, 24, 24, 8, -+ CRYPTO_CIPHER_ALG_3DES }, -+ { TLS_CIPHER_AES_128_CBC, TLS_CIPHER_BLOCK, 16, 16, 16, -+ CRYPTO_CIPHER_ALG_AES }, -+ { TLS_CIPHER_AES_256_CBC, TLS_CIPHER_BLOCK, 32, 32, 16, -+ CRYPTO_CIPHER_ALG_AES } -+}; -+ -+#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers) -+ -+ -+/** -+ * tls_get_cipher_suite - Get TLS cipher suite -+ * @suite: Cipher suite identifier -+ * Returns: Pointer to the cipher data or %NULL if not found -+ */ -+const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite) -+{ -+ size_t i; -+ for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++) -+ if (tls_cipher_suites[i].suite == suite) -+ return &tls_cipher_suites[i]; -+ return NULL; -+} -+ -+ -+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher) -+{ -+ size_t i; -+ for (i = 0; i < NUM_TLS_CIPHER_DATA; i++) -+ if (tls_ciphers[i].cipher == cipher) -+ return &tls_ciphers[i]; -+ return NULL; -+} -+ -+ -+int tls_server_key_exchange_allowed(tls_cipher cipher) -+{ -+ const struct tls_cipher_suite *suite; -+ -+ /* RFC 2246, Section 7.4.3 */ -+ suite = tls_get_cipher_suite(cipher); -+ if (suite == NULL) -+ return 0; -+ -+ switch (suite->key_exchange) { -+ case TLS_KEY_X_DHE_DSS: -+ case TLS_KEY_X_DHE_DSS_EXPORT: -+ case TLS_KEY_X_DHE_RSA: -+ case TLS_KEY_X_DHE_RSA_EXPORT: -+ case TLS_KEY_X_DH_anon_EXPORT: -+ case TLS_KEY_X_DH_anon: -+ return 1; -+ case TLS_KEY_X_RSA_EXPORT: -+ return 1 /* FIX: public key len > 512 bits */; -+ default: -+ return 0; -+ } -+} -+ -+ -+/** -+ * tls_parse_cert - Parse DER encoded X.509 certificate and get public key -+ * @buf: ASN.1 DER encoded certificate -+ * @len: Length of the buffer -+ * @pk: Buffer for returning the allocated public key -+ * Returns: 0 on success, -1 on failure -+ * -+ * This functions parses an ASN.1 DER encoded X.509 certificate and retrieves -+ * the public key from it. The caller is responsible for freeing the public key -+ * by calling crypto_public_key_free(). -+ */ -+int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk) -+{ -+ struct x509_certificate *cert; -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate", -+ buf, len); -+ -+ *pk = crypto_public_key_from_cert(buf, len); -+ if (*pk) -+ return 0; -+ -+ cert = x509_certificate_parse(buf, len); -+ if (cert == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 " -+ "certificate"); -+ return -1; -+ } -+ -+ /* TODO -+ * verify key usage (must allow encryption) -+ * -+ * All certificate profiles, key and cryptographic formats are -+ * defined by the IETF PKIX working group [PKIX]. When a key -+ * usage extension is present, the digitalSignature bit must be -+ * set for the key to be eligible for signing, as described -+ * above, and the keyEncipherment bit must be present to allow -+ * encryption, as described above. The keyAgreement bit must be -+ * set on Diffie-Hellman certificates. (PKIX: RFC 3280) -+ */ -+ -+ *pk = crypto_public_key_import(cert->public_key, cert->public_key_len); -+ x509_certificate_free(cert); -+ -+ if (*pk == NULL) { -+ wpa_printf(MSG_ERROR, "TLSv1: Failed to import " -+ "server public key"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+int tls_verify_hash_init(struct tls_verify_hash *verify) -+{ -+ tls_verify_hash_free(verify); -+ verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); -+ verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); -+ verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0); -+ verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); -+ verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); -+ verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0); -+ if (verify->md5_client == NULL || verify->md5_server == NULL || -+ verify->md5_cert == NULL || verify->sha1_client == NULL || -+ verify->sha1_server == NULL || verify->sha1_cert == NULL) { -+ tls_verify_hash_free(verify); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, -+ size_t len) -+{ -+ if (verify->md5_client && verify->sha1_client) { -+ crypto_hash_update(verify->md5_client, buf, len); -+ crypto_hash_update(verify->sha1_client, buf, len); -+ } -+ if (verify->md5_server && verify->sha1_server) { -+ crypto_hash_update(verify->md5_server, buf, len); -+ crypto_hash_update(verify->sha1_server, buf, len); -+ } -+ if (verify->md5_cert && verify->sha1_cert) { -+ crypto_hash_update(verify->md5_cert, buf, len); -+ crypto_hash_update(verify->sha1_cert, buf, len); -+ } -+} -+ -+ -+void tls_verify_hash_free(struct tls_verify_hash *verify) -+{ -+ crypto_hash_finish(verify->md5_client, NULL, NULL); -+ crypto_hash_finish(verify->md5_server, NULL, NULL); -+ crypto_hash_finish(verify->md5_cert, NULL, NULL); -+ crypto_hash_finish(verify->sha1_client, NULL, NULL); -+ crypto_hash_finish(verify->sha1_server, NULL, NULL); -+ crypto_hash_finish(verify->sha1_cert, NULL, NULL); -+ verify->md5_client = NULL; -+ verify->md5_server = NULL; -+ verify->md5_cert = NULL; -+ verify->sha1_client = NULL; -+ verify->sha1_server = NULL; -+ verify->sha1_cert = NULL; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.h -new file mode 100644 -index 0000000000000..763a4af3d5611 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_common.h -@@ -0,0 +1,216 @@ -+/* -+ * TLSv1 common definitions -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLSV1_COMMON_H -+#define TLSV1_COMMON_H -+ -+#include "crypto/crypto.h" -+ -+#define TLS_VERSION 0x0301 /* TLSv1 */ -+#define TLS_RANDOM_LEN 32 -+#define TLS_PRE_MASTER_SECRET_LEN 48 -+#define TLS_MASTER_SECRET_LEN 48 -+#define TLS_SESSION_ID_MAX_LEN 32 -+#define TLS_VERIFY_DATA_LEN 12 -+ -+/* HandshakeType */ -+enum { -+ TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0, -+ TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1, -+ TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2, -+ TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */, -+ TLS_HANDSHAKE_TYPE_CERTIFICATE = 11, -+ TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12, -+ TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13, -+ TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14, -+ TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15, -+ TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16, -+ TLS_HANDSHAKE_TYPE_FINISHED = 20, -+ TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */, -+ TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */ -+}; -+ -+/* CipherSuite */ -+#define TLS_NULL_WITH_NULL_NULL 0x0000 /* RFC 2246 */ -+#define TLS_RSA_WITH_NULL_MD5 0x0001 /* RFC 2246 */ -+#define TLS_RSA_WITH_NULL_SHA 0x0002 /* RFC 2246 */ -+#define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 /* RFC 2246 */ -+#define TLS_RSA_WITH_RC4_128_MD5 0x0004 /* RFC 2246 */ -+#define TLS_RSA_WITH_RC4_128_SHA 0x0005 /* RFC 2246 */ -+#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006 /* RFC 2246 */ -+#define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* RFC 2246 */ -+#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008 /* RFC 2246 */ -+#define TLS_RSA_WITH_DES_CBC_SHA 0x0009 /* RFC 2246 */ -+#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* RFC 2246 */ -+#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000B /* RFC 2246 */ -+#define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000C /* RFC 2246 */ -+#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D /* RFC 2246 */ -+#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000E /* RFC 2246 */ -+#define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000F /* RFC 2246 */ -+#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 /* RFC 2246 */ -+#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011 /* RFC 2246 */ -+#define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012 /* RFC 2246 */ -+#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 /* RFC 2246 */ -+#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014 /* RFC 2246 */ -+#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015 /* RFC 2246 */ -+#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* RFC 2246 */ -+#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017 /* RFC 2246 */ -+#define TLS_DH_anon_WITH_RC4_128_MD5 0x0018 /* RFC 2246 */ -+#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019 /* RFC 2246 */ -+#define TLS_DH_anon_WITH_DES_CBC_SHA 0x001A /* RFC 2246 */ -+#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* RFC 2246 */ -+#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /* RFC 3268 */ -+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 /* RFC 3268 */ -+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 /* RFC 3268 */ -+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 /* RFC 3268 */ -+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* RFC 3268 */ -+#define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* RFC 3268 */ -+#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* RFC 3268 */ -+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 /* RFC 3268 */ -+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 /* RFC 3268 */ -+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 /* RFC 3268 */ -+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* RFC 3268 */ -+#define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* RFC 3268 */ -+ -+/* CompressionMethod */ -+#define TLS_COMPRESSION_NULL 0 -+ -+/* AlertLevel */ -+#define TLS_ALERT_LEVEL_WARNING 1 -+#define TLS_ALERT_LEVEL_FATAL 2 -+ -+/* AlertDescription */ -+#define TLS_ALERT_CLOSE_NOTIFY 0 -+#define TLS_ALERT_UNEXPECTED_MESSAGE 10 -+#define TLS_ALERT_BAD_RECORD_MAC 20 -+#define TLS_ALERT_DECRYPTION_FAILED 21 -+#define TLS_ALERT_RECORD_OVERFLOW 22 -+#define TLS_ALERT_DECOMPRESSION_FAILURE 30 -+#define TLS_ALERT_HANDSHAKE_FAILURE 40 -+#define TLS_ALERT_BAD_CERTIFICATE 42 -+#define TLS_ALERT_UNSUPPORTED_CERTIFICATE 43 -+#define TLS_ALERT_CERTIFICATE_REVOKED 44 -+#define TLS_ALERT_CERTIFICATE_EXPIRED 45 -+#define TLS_ALERT_CERTIFICATE_UNKNOWN 46 -+#define TLS_ALERT_ILLEGAL_PARAMETER 47 -+#define TLS_ALERT_UNKNOWN_CA 48 -+#define TLS_ALERT_ACCESS_DENIED 49 -+#define TLS_ALERT_DECODE_ERROR 50 -+#define TLS_ALERT_DECRYPT_ERROR 51 -+#define TLS_ALERT_EXPORT_RESTRICTION 60 -+#define TLS_ALERT_PROTOCOL_VERSION 70 -+#define TLS_ALERT_INSUFFICIENT_SECURITY 71 -+#define TLS_ALERT_INTERNAL_ERROR 80 -+#define TLS_ALERT_USER_CANCELED 90 -+#define TLS_ALERT_NO_RENEGOTIATION 100 -+#define TLS_ALERT_UNSUPPORTED_EXTENSION 110 /* RFC 4366 */ -+#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE 111 /* RFC 4366 */ -+#define TLS_ALERT_UNRECOGNIZED_NAME 112 /* RFC 4366 */ -+#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE 113 /* RFC 4366 */ -+#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE 114 /* RFC 4366 */ -+ -+/* ChangeCipherSpec */ -+enum { -+ TLS_CHANGE_CIPHER_SPEC = 1 -+}; -+ -+/* TLS Extensions */ -+#define TLS_EXT_SERVER_NAME 0 /* RFC 4366 */ -+#define TLS_EXT_MAX_FRAGMENT_LENGTH 1 /* RFC 4366 */ -+#define TLS_EXT_CLIENT_CERTIFICATE_URL 2 /* RFC 4366 */ -+#define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */ -+#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */ -+#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */ -+#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */ -+ -+#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */ -+ -+ -+typedef enum { -+ TLS_KEY_X_NULL, -+ TLS_KEY_X_RSA, -+ TLS_KEY_X_RSA_EXPORT, -+ TLS_KEY_X_DH_DSS_EXPORT, -+ TLS_KEY_X_DH_DSS, -+ TLS_KEY_X_DH_RSA_EXPORT, -+ TLS_KEY_X_DH_RSA, -+ TLS_KEY_X_DHE_DSS_EXPORT, -+ TLS_KEY_X_DHE_DSS, -+ TLS_KEY_X_DHE_RSA_EXPORT, -+ TLS_KEY_X_DHE_RSA, -+ TLS_KEY_X_DH_anon_EXPORT, -+ TLS_KEY_X_DH_anon -+} tls_key_exchange; -+ -+typedef enum { -+ TLS_CIPHER_NULL, -+ TLS_CIPHER_RC4_40, -+ TLS_CIPHER_RC4_128, -+ TLS_CIPHER_RC2_CBC_40, -+ TLS_CIPHER_IDEA_CBC, -+ TLS_CIPHER_DES40_CBC, -+ TLS_CIPHER_DES_CBC, -+ TLS_CIPHER_3DES_EDE_CBC, -+ TLS_CIPHER_AES_128_CBC, -+ TLS_CIPHER_AES_256_CBC -+} tls_cipher; -+ -+typedef enum { -+ TLS_HASH_NULL, -+ TLS_HASH_MD5, -+ TLS_HASH_SHA -+} tls_hash; -+ -+struct tls_cipher_suite { -+ u16 suite; -+ tls_key_exchange key_exchange; -+ tls_cipher cipher; -+ tls_hash hash; -+}; -+ -+typedef enum { -+ TLS_CIPHER_STREAM, -+ TLS_CIPHER_BLOCK -+} tls_cipher_type; -+ -+struct tls_cipher_data { -+ tls_cipher cipher; -+ tls_cipher_type type; -+ size_t key_material; -+ size_t expanded_key_material; -+ size_t block_size; /* also iv_size */ -+ enum crypto_cipher_alg alg; -+}; -+ -+ -+struct tls_verify_hash { -+ struct crypto_hash *md5_client; -+ struct crypto_hash *sha1_client; -+ struct crypto_hash *md5_server; -+ struct crypto_hash *sha1_server; -+ struct crypto_hash *md5_cert; -+ struct crypto_hash *sha1_cert; -+}; -+ -+ -+const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite); -+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher); -+int tls_server_key_exchange_allowed(tls_cipher cipher); -+int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk); -+int tls_verify_hash_init(struct tls_verify_hash *verify); -+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf, -+ size_t len); -+void tls_verify_hash_free(struct tls_verify_hash *verify); -+ -+#endif /* TLSV1_COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.c -new file mode 100644 -index 0000000000000..aa467efc8c3c2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.c -@@ -0,0 +1,493 @@ -+/* -+ * TLSv1 credentials -+ * Copyright (c) 2006-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "base64.h" -+#include "crypto/crypto.h" -+#include "x509v3.h" -+#include "tlsv1_cred.h" -+ -+ -+struct tlsv1_credentials * tlsv1_cred_alloc(void) -+{ -+ struct tlsv1_credentials *cred; -+ cred = os_zalloc(sizeof(*cred)); -+ return cred; -+} -+ -+ -+void tlsv1_cred_free(struct tlsv1_credentials *cred) -+{ -+ if (cred == NULL) -+ return; -+ -+ x509_certificate_chain_free(cred->trusted_certs); -+ x509_certificate_chain_free(cred->cert); -+ crypto_private_key_free(cred->key); -+ os_free(cred->dh_p); -+ os_free(cred->dh_g); -+ os_free(cred); -+} -+ -+ -+static int tlsv1_add_cert_der(struct x509_certificate **chain, -+ const u8 *buf, size_t len) -+{ -+ struct x509_certificate *cert; -+ char name[128]; -+ -+ cert = x509_certificate_parse(buf, len); -+ if (cert == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate", -+ __func__); -+ return -1; -+ } -+ -+ cert->next = *chain; -+ *chain = cert; -+ -+ x509_name_string(&cert->subject, name, sizeof(name)); -+ wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name); -+ -+ return 0; -+} -+ -+ -+static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----"; -+static const char *pem_cert_end = "-----END CERTIFICATE-----"; -+static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----"; -+static const char *pem_key_end = "-----END RSA PRIVATE KEY-----"; -+static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----"; -+static const char *pem_key2_end = "-----END PRIVATE KEY-----"; -+static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; -+static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----"; -+ -+ -+static const u8 * search_tag(const char *tag, const u8 *buf, size_t len) -+{ -+ size_t i, plen; -+ -+ plen = os_strlen(tag); -+ if (len < plen) -+ return NULL; -+ -+ for (i = 0; i < len - plen; i++) { -+ if (os_memcmp(buf + i, tag, plen) == 0) -+ return buf + i; -+ } -+ -+ return NULL; -+} -+ -+ -+static int tlsv1_add_cert(struct x509_certificate **chain, -+ const u8 *buf, size_t len) -+{ -+ const u8 *pos, *end; -+ unsigned char *der; -+ size_t der_len; -+ -+ pos = search_tag(pem_cert_begin, buf, len); -+ if (!pos) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - " -+ "assume DER format"); -+ return tlsv1_add_cert_der(chain, buf, len); -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into " -+ "DER format"); -+ -+ while (pos) { -+ pos += os_strlen(pem_cert_begin); -+ end = search_tag(pem_cert_end, pos, buf + len - pos); -+ if (end == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Could not find PEM " -+ "certificate end tag (%s)", pem_cert_end); -+ return -1; -+ } -+ -+ der = base64_decode(pos, end - pos, &der_len); -+ if (der == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM " -+ "certificate"); -+ return -1; -+ } -+ -+ if (tlsv1_add_cert_der(chain, der, der_len) < 0) { -+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM " -+ "certificate after DER conversion"); -+ os_free(der); -+ return -1; -+ } -+ -+ os_free(der); -+ -+ end += os_strlen(pem_cert_end); -+ pos = search_tag(pem_cert_begin, end, buf + len - end); -+ } -+ -+ return 0; -+} -+ -+ -+static int tlsv1_set_cert_chain(struct x509_certificate **chain, -+ const char *cert, const u8 *cert_blob, -+ size_t cert_blob_len) -+{ -+ if (cert_blob) -+ return tlsv1_add_cert(chain, cert_blob, cert_blob_len); -+ -+ if (cert) { -+ u8 *buf; -+ size_t len; -+ int ret; -+ -+ buf = (u8 *) os_readfile(cert, &len); -+ if (buf == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", -+ cert); -+ return -1; -+ } -+ -+ ret = tlsv1_add_cert(chain, buf, len); -+ os_free(buf); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_set_ca_cert - Set trusted CA certificate(s) -+ * @cred: TLSv1 credentials from tlsv1_cred_alloc() -+ * @cert: File or reference name for X.509 certificate in PEM or DER format -+ * @cert_blob: cert as inlined data or %NULL if not used -+ * @cert_blob_len: ca_cert_blob length -+ * @path: Path to CA certificates (not yet supported) -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, -+ const u8 *cert_blob, size_t cert_blob_len, -+ const char *path) -+{ -+ if (tlsv1_set_cert_chain(&cred->trusted_certs, cert, -+ cert_blob, cert_blob_len) < 0) -+ return -1; -+ -+ if (path) { -+ /* TODO: add support for reading number of certificate files */ -+ wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory " -+ "not yet supported"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_set_cert - Set certificate -+ * @cred: TLSv1 credentials from tlsv1_cred_alloc() -+ * @cert: File or reference name for X.509 certificate in PEM or DER format -+ * @cert_blob: cert as inlined data or %NULL if not used -+ * @cert_blob_len: cert_blob length -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, -+ const u8 *cert_blob, size_t cert_blob_len) -+{ -+ return tlsv1_set_cert_chain(&cred->cert, cert, -+ cert_blob, cert_blob_len); -+} -+ -+ -+static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len) -+{ -+ const u8 *pos, *end; -+ unsigned char *der; -+ size_t der_len; -+ struct crypto_private_key *pkey; -+ -+ pos = search_tag(pem_key_begin, key, len); -+ if (!pos) { -+ pos = search_tag(pem_key2_begin, key, len); -+ if (!pos) -+ return NULL; -+ pos += os_strlen(pem_key2_begin); -+ end = search_tag(pem_key2_end, pos, key + len - pos); -+ if (!end) -+ return NULL; -+ } else { -+ pos += os_strlen(pem_key_begin); -+ end = search_tag(pem_key_end, pos, key + len - pos); -+ if (!end) -+ return NULL; -+ } -+ -+ der = base64_decode(pos, end - pos, &der_len); -+ if (!der) -+ return NULL; -+ pkey = crypto_private_key_import(der, der_len, NULL); -+ os_free(der); -+ return pkey; -+} -+ -+ -+static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key, -+ size_t len, -+ const char *passwd) -+{ -+ const u8 *pos, *end; -+ unsigned char *der; -+ size_t der_len; -+ struct crypto_private_key *pkey; -+ -+ if (passwd == NULL) -+ return NULL; -+ pos = search_tag(pem_key_enc_begin, key, len); -+ if (!pos) -+ return NULL; -+ pos += os_strlen(pem_key_enc_begin); -+ end = search_tag(pem_key_enc_end, pos, key + len - pos); -+ if (!end) -+ return NULL; -+ -+ der = base64_decode(pos, end - pos, &der_len); -+ if (!der) -+ return NULL; -+ pkey = crypto_private_key_import(der, der_len, passwd); -+ os_free(der); -+ return pkey; -+} -+ -+ -+static int tlsv1_set_key(struct tlsv1_credentials *cred, -+ const u8 *key, size_t len, const char *passwd) -+{ -+ cred->key = crypto_private_key_import(key, len, passwd); -+ if (cred->key == NULL) -+ cred->key = tlsv1_set_key_pem(key, len); -+ if (cred->key == NULL) -+ cred->key = tlsv1_set_key_enc_pem(key, len, passwd); -+ if (cred->key == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key"); -+ return -1; -+ } -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_set_private_key - Set private key -+ * @cred: TLSv1 credentials from tlsv1_cred_alloc() -+ * @private_key: File or reference name for the key in PEM or DER format -+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no -+ * passphrase is used. -+ * @private_key_blob: private_key as inlined data or %NULL if not used -+ * @private_key_blob_len: private_key_blob length -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_set_private_key(struct tlsv1_credentials *cred, -+ const char *private_key, -+ const char *private_key_passwd, -+ const u8 *private_key_blob, -+ size_t private_key_blob_len) -+{ -+ crypto_private_key_free(cred->key); -+ cred->key = NULL; -+ -+ if (private_key_blob) -+ return tlsv1_set_key(cred, private_key_blob, -+ private_key_blob_len, -+ private_key_passwd); -+ -+ if (private_key) { -+ u8 *buf; -+ size_t len; -+ int ret; -+ -+ buf = (u8 *) os_readfile(private_key, &len); -+ if (buf == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", -+ private_key); -+ return -1; -+ } -+ -+ ret = tlsv1_set_key(cred, buf, len, private_key_passwd); -+ os_free(buf); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+ -+static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred, -+ const u8 *dh, size_t len) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end; -+ -+ pos = dh; -+ end = dh + len; -+ -+ /* -+ * DHParameter ::= SEQUENCE { -+ * prime INTEGER, -- p -+ * base INTEGER, -- g -+ * privateValueLength INTEGER OPTIONAL } -+ */ -+ -+ /* DHParamer ::= SEQUENCE */ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a " -+ "valid SEQUENCE - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ -+ /* prime INTEGER */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0) -+ return -1; -+ -+ if (hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; " -+ "class=%d tag=0x%x", hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length); -+ if (hdr.length == 0) -+ return -1; -+ os_free(cred->dh_p); -+ cred->dh_p = os_malloc(hdr.length); -+ if (cred->dh_p == NULL) -+ return -1; -+ os_memcpy(cred->dh_p, hdr.payload, hdr.length); -+ cred->dh_p_len = hdr.length; -+ pos = hdr.payload + hdr.length; -+ -+ /* base INTEGER */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0) -+ return -1; -+ -+ if (hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; " -+ "class=%d tag=0x%x", hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length); -+ if (hdr.length == 0) -+ return -1; -+ os_free(cred->dh_g); -+ cred->dh_g = os_malloc(hdr.length); -+ if (cred->dh_g == NULL) -+ return -1; -+ os_memcpy(cred->dh_g, hdr.payload, hdr.length); -+ cred->dh_g_len = hdr.length; -+ -+ return 0; -+} -+ -+ -+static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----"; -+static const char *pem_dhparams_end = "-----END DH PARAMETERS-----"; -+ -+ -+static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred, -+ const u8 *buf, size_t len) -+{ -+ const u8 *pos, *end; -+ unsigned char *der; -+ size_t der_len; -+ -+ pos = search_tag(pem_dhparams_begin, buf, len); -+ if (!pos) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - " -+ "assume DER format"); -+ return tlsv1_set_dhparams_der(cred, buf, len); -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER " -+ "format"); -+ -+ pos += os_strlen(pem_dhparams_begin); -+ end = search_tag(pem_dhparams_end, pos, buf + len - pos); -+ if (end == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end " -+ "tag (%s)", pem_dhparams_end); -+ return -1; -+ } -+ -+ der = base64_decode(pos, end - pos, &der_len); -+ if (der == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams"); -+ return -1; -+ } -+ -+ if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) { -+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams " -+ "DER conversion"); -+ os_free(der); -+ return -1; -+ } -+ -+ os_free(der); -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_set_dhparams - Set Diffie-Hellman parameters -+ * @cred: TLSv1 credentials from tlsv1_cred_alloc() -+ * @dh_file: File or reference name for the DH params in PEM or DER format -+ * @dh_blob: DH params as inlined data or %NULL if not used -+ * @dh_blob_len: dh_blob length -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, -+ const u8 *dh_blob, size_t dh_blob_len) -+{ -+ if (dh_blob) -+ return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len); -+ -+ if (dh_file) { -+ u8 *buf; -+ size_t len; -+ int ret; -+ -+ buf = (u8 *) os_readfile(dh_file, &len); -+ if (buf == NULL) { -+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'", -+ dh_file); -+ return -1; -+ } -+ -+ ret = tlsv1_set_dhparams_blob(cred, buf, len); -+ os_free(buf); -+ return ret; -+ } -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.h -new file mode 100644 -index 0000000000000..8425fe4541266 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_cred.h -@@ -0,0 +1,46 @@ -+/* -+ * TLSv1 credentials -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLSV1_CRED_H -+#define TLSV1_CRED_H -+ -+struct tlsv1_credentials { -+ struct x509_certificate *trusted_certs; -+ struct x509_certificate *cert; -+ struct crypto_private_key *key; -+ -+ /* Diffie-Hellman parameters */ -+ u8 *dh_p; /* prime */ -+ size_t dh_p_len; -+ u8 *dh_g; /* generator */ -+ size_t dh_g_len; -+}; -+ -+ -+struct tlsv1_credentials * tlsv1_cred_alloc(void); -+void tlsv1_cred_free(struct tlsv1_credentials *cred); -+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert, -+ const u8 *cert_blob, size_t cert_blob_len, -+ const char *path); -+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert, -+ const u8 *cert_blob, size_t cert_blob_len); -+int tlsv1_set_private_key(struct tlsv1_credentials *cred, -+ const char *private_key, -+ const char *private_key_passwd, -+ const u8 *private_key_blob, -+ size_t private_key_blob_len); -+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file, -+ const u8 *dh_blob, size_t dh_blob_len); -+ -+#endif /* TLSV1_CRED_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.c -new file mode 100644 -index 0000000000000..e811f0e33b440 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.c -@@ -0,0 +1,409 @@ -+/* -+ * TLSv1 Record Protocol -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/md5.h" -+#include "crypto/sha1.h" -+#include "tlsv1_common.h" -+#include "tlsv1_record.h" -+ -+ -+/** -+ * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite -+ * @rl: Pointer to TLS record layer data -+ * @cipher_suite: New cipher suite -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is used to prepare TLS record layer for cipher suite change. -+ * tlsv1_record_change_write_cipher() and -+ * tlsv1_record_change_read_cipher() functions can then be used to change the -+ * currently used ciphers. -+ */ -+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, -+ u16 cipher_suite) -+{ -+ const struct tls_cipher_suite *suite; -+ const struct tls_cipher_data *data; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x", -+ cipher_suite); -+ rl->cipher_suite = cipher_suite; -+ -+ suite = tls_get_cipher_suite(cipher_suite); -+ if (suite == NULL) -+ return -1; -+ -+ if (suite->hash == TLS_HASH_MD5) { -+ rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5; -+ rl->hash_size = MD5_MAC_LEN; -+ } else if (suite->hash == TLS_HASH_SHA) { -+ rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1; -+ rl->hash_size = SHA1_MAC_LEN; -+ } -+ -+ data = tls_get_cipher_data(suite->cipher); -+ if (data == NULL) -+ return -1; -+ -+ rl->key_material_len = data->key_material; -+ rl->iv_size = data->block_size; -+ rl->cipher_alg = data->alg; -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher -+ * @rl: Pointer to TLS record layer data -+ * Returns: 0 on success (cipher changed), -1 on failure -+ * -+ * This function changes TLS record layer to use the new cipher suite -+ * configured with tlsv1_record_set_cipher_suite() for writing. -+ */ -+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl) -+{ -+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite " -+ "0x%04x", rl->cipher_suite); -+ rl->write_cipher_suite = rl->cipher_suite; -+ os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN); -+ -+ if (rl->write_cbc) { -+ crypto_cipher_deinit(rl->write_cbc); -+ rl->write_cbc = NULL; -+ } -+ if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { -+ rl->write_cbc = crypto_cipher_init(rl->cipher_alg, -+ rl->write_iv, rl->write_key, -+ rl->key_material_len); -+ if (rl->write_cbc == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " -+ "cipher"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher -+ * @rl: Pointer to TLS record layer data -+ * Returns: 0 on success (cipher changed), -1 on failure -+ * -+ * This function changes TLS record layer to use the new cipher suite -+ * configured with tlsv1_record_set_cipher_suite() for reading. -+ */ -+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl) -+{ -+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite " -+ "0x%04x", rl->cipher_suite); -+ rl->read_cipher_suite = rl->cipher_suite; -+ os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN); -+ -+ if (rl->read_cbc) { -+ crypto_cipher_deinit(rl->read_cbc); -+ rl->read_cbc = NULL; -+ } -+ if (rl->cipher_alg != CRYPTO_CIPHER_NULL) { -+ rl->read_cbc = crypto_cipher_init(rl->cipher_alg, -+ rl->read_iv, rl->read_key, -+ rl->key_material_len); -+ if (rl->read_cbc == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize " -+ "cipher"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_record_send - TLS record layer: Send a message -+ * @rl: Pointer to TLS record layer data -+ * @content_type: Content type (TLS_CONTENT_TYPE_*) -+ * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the -+ * beginning for record layer to fill in; payload filled in after this and -+ * extra space in the end for HMAC). -+ * @buf_size: Maximum buf size -+ * @payload_len: Length of the payload -+ * @out_len: Buffer for returning the used buf length -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function fills in the TLS record layer header, adds HMAC, and encrypts -+ * the data using the current write cipher. -+ */ -+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, -+ size_t buf_size, size_t payload_len, size_t *out_len) -+{ -+ u8 *pos, *ct_start, *length, *payload; -+ struct crypto_hash *hmac; -+ size_t clen; -+ -+ pos = buf; -+ /* ContentType type */ -+ ct_start = pos; -+ *pos++ = content_type; -+ /* ProtocolVersion version */ -+ WPA_PUT_BE16(pos, TLS_VERSION); -+ pos += 2; -+ /* uint16 length */ -+ length = pos; -+ WPA_PUT_BE16(length, payload_len); -+ pos += 2; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ payload = pos; -+ pos += payload_len; -+ -+ if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) { -+ hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret, -+ rl->hash_size); -+ if (hmac == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " -+ "to initialize HMAC"); -+ return -1; -+ } -+ crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN); -+ /* type + version + length + fragment */ -+ crypto_hash_update(hmac, ct_start, pos - ct_start); -+ clen = buf + buf_size - pos; -+ if (clen < rl->hash_size) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not " -+ "enough room for MAC"); -+ crypto_hash_finish(hmac, NULL, NULL); -+ return -1; -+ } -+ -+ if (crypto_hash_finish(hmac, pos, &clen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " -+ "to calculate HMAC"); -+ return -1; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC", -+ pos, clen); -+ pos += clen; -+ if (rl->iv_size) { -+ size_t len = pos - payload; -+ size_t pad; -+ pad = (len + 1) % rl->iv_size; -+ if (pad) -+ pad = rl->iv_size - pad; -+ if (pos + pad + 1 > buf + buf_size) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No room for " -+ "block cipher padding"); -+ return -1; -+ } -+ os_memset(pos, pad, pad + 1); -+ pos += pad + 1; -+ } -+ -+ if (crypto_cipher_encrypt(rl->write_cbc, payload, -+ payload, pos - payload) < 0) -+ return -1; -+ } -+ -+ WPA_PUT_BE16(length, pos - length - 2); -+ inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN); -+ -+ *out_len = pos - buf; -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_record_receive - TLS record layer: Process a received message -+ * @rl: Pointer to TLS record layer data -+ * @in_data: Received data -+ * @in_len: Length of the received data -+ * @out_data: Buffer for output data (must be at least as long as in_data) -+ * @out_len: Set to maximum out_data length by caller; used to return the -+ * length of the used data -+ * @alert: Buffer for returning an alert value on failure -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function decrypts the received message, verifies HMAC and TLS record -+ * layer header. -+ */ -+int tlsv1_record_receive(struct tlsv1_record_layer *rl, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t *out_len, u8 *alert) -+{ -+ size_t i, rlen, hlen; -+ u8 padlen; -+ struct crypto_hash *hmac; -+ u8 len[2], hash[100]; -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", -+ in_data, in_len); -+ -+ if (in_len < TLS_RECORD_HEADER_LEN) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)", -+ (unsigned long) in_len); -+ *alert = TLS_ALERT_DECODE_ERROR; -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d " -+ "length %d", in_data[0], in_data[1], in_data[2], -+ WPA_GET_BE16(in_data + 3)); -+ -+ if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE && -+ in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC && -+ in_data[0] != TLS_CONTENT_TYPE_ALERT && -+ in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x", -+ in_data[0]); -+ *alert = TLS_ALERT_UNEXPECTED_MESSAGE; -+ return -1; -+ } -+ -+ if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version " -+ "%d.%d", in_data[1], in_data[2]); -+ *alert = TLS_ALERT_PROTOCOL_VERSION; -+ return -1; -+ } -+ -+ rlen = WPA_GET_BE16(in_data + 3); -+ -+ /* TLSCiphertext must not be more than 2^14+2048 bytes */ -+ if (TLS_RECORD_HEADER_LEN + rlen > 18432) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", -+ (unsigned long) (TLS_RECORD_HEADER_LEN + rlen)); -+ *alert = TLS_ALERT_RECORD_OVERFLOW; -+ return -1; -+ } -+ -+ in_data += TLS_RECORD_HEADER_LEN; -+ in_len -= TLS_RECORD_HEADER_LEN; -+ -+ if (rlen > in_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included " -+ "(rlen=%lu > in_len=%lu)", -+ (unsigned long) rlen, (unsigned long) in_len); -+ *alert = TLS_ALERT_DECODE_ERROR; -+ return -1; -+ } -+ -+ in_len = rlen; -+ -+ if (*out_len < in_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for " -+ "processing received record"); -+ *alert = TLS_ALERT_INTERNAL_ERROR; -+ return -1; -+ } -+ -+ os_memcpy(out_data, in_data, in_len); -+ *out_len = in_len; -+ -+ if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) { -+ if (crypto_cipher_decrypt(rl->read_cbc, out_data, -+ out_data, in_len) < 0) { -+ *alert = TLS_ALERT_DECRYPTION_FAILED; -+ return -1; -+ } -+ if (rl->iv_size) { -+ if (in_len == 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record" -+ " (no pad)"); -+ *alert = TLS_ALERT_DECODE_ERROR; -+ return -1; -+ } -+ padlen = out_data[in_len - 1]; -+ if (padlen >= in_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad " -+ "length (%u, in_len=%lu) in " -+ "received record", -+ padlen, (unsigned long) in_len); -+ *alert = TLS_ALERT_DECRYPTION_FAILED; -+ return -1; -+ } -+ for (i = in_len - padlen; i < in_len; i++) { -+ if (out_data[i] != padlen) { -+ wpa_hexdump(MSG_DEBUG, -+ "TLSv1: Invalid pad in " -+ "received record", -+ out_data + in_len - padlen, -+ padlen); -+ *alert = TLS_ALERT_DECRYPTION_FAILED; -+ return -1; -+ } -+ } -+ -+ *out_len -= padlen + 1; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, -+ "TLSv1: Record Layer - Decrypted data", -+ out_data, in_len); -+ -+ if (*out_len < rl->hash_size) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " -+ "hash value"); -+ *alert = TLS_ALERT_INTERNAL_ERROR; -+ return -1; -+ } -+ -+ *out_len -= rl->hash_size; -+ -+ hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret, -+ rl->hash_size); -+ if (hmac == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " -+ "to initialize HMAC"); -+ *alert = TLS_ALERT_INTERNAL_ERROR; -+ return -1; -+ } -+ -+ crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN); -+ /* type + version + length + fragment */ -+ crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3); -+ WPA_PUT_BE16(len, *out_len); -+ crypto_hash_update(hmac, len, 2); -+ crypto_hash_update(hmac, out_data, *out_len); -+ hlen = sizeof(hash); -+ if (crypto_hash_finish(hmac, hash, &hlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " -+ "to calculate HMAC"); -+ return -1; -+ } -+ if (hlen != rl->hash_size || -+ os_memcmp(hash, out_data + *out_len, hlen) != 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " -+ "received message"); -+ *alert = TLS_ALERT_BAD_RECORD_MAC; -+ return -1; -+ } -+ } -+ -+ /* TLSCompressed must not be more than 2^14+1024 bytes */ -+ if (TLS_RECORD_HEADER_LEN + *out_len > 17408) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)", -+ (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len)); -+ *alert = TLS_ALERT_RECORD_OVERFLOW; -+ return -1; -+ } -+ -+ inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.h -new file mode 100644 -index 0000000000000..9c7c0a4e644e2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_record.h -@@ -0,0 +1,74 @@ -+/* -+ * TLSv1 Record Protocol -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLSV1_RECORD_H -+#define TLSV1_RECORD_H -+ -+#include "crypto/crypto.h" -+ -+#define TLS_MAX_WRITE_MAC_SECRET_LEN 20 -+#define TLS_MAX_WRITE_KEY_LEN 32 -+#define TLS_MAX_IV_LEN 16 -+#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \ -+ TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN)) -+ -+#define TLS_SEQ_NUM_LEN 8 -+#define TLS_RECORD_HEADER_LEN 5 -+ -+/* ContentType */ -+enum { -+ TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20, -+ TLS_CONTENT_TYPE_ALERT = 21, -+ TLS_CONTENT_TYPE_HANDSHAKE = 22, -+ TLS_CONTENT_TYPE_APPLICATION_DATA = 23 -+}; -+ -+struct tlsv1_record_layer { -+ u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; -+ u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN]; -+ u8 write_key[TLS_MAX_WRITE_KEY_LEN]; -+ u8 read_key[TLS_MAX_WRITE_KEY_LEN]; -+ u8 write_iv[TLS_MAX_IV_LEN]; -+ u8 read_iv[TLS_MAX_IV_LEN]; -+ -+ size_t hash_size; -+ size_t key_material_len; -+ size_t iv_size; /* also block_size */ -+ -+ enum crypto_hash_alg hash_alg; -+ enum crypto_cipher_alg cipher_alg; -+ -+ u8 write_seq_num[TLS_SEQ_NUM_LEN]; -+ u8 read_seq_num[TLS_SEQ_NUM_LEN]; -+ -+ u16 cipher_suite; -+ u16 write_cipher_suite; -+ u16 read_cipher_suite; -+ -+ struct crypto_cipher *write_cbc; -+ struct crypto_cipher *read_cbc; -+}; -+ -+ -+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl, -+ u16 cipher_suite); -+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl); -+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl); -+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf, -+ size_t buf_size, size_t payload_len, size_t *out_len); -+int tlsv1_record_receive(struct tlsv1_record_layer *rl, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t *out_len, u8 *alert); -+ -+#endif /* TLSV1_RECORD_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.c -new file mode 100644 -index 0000000000000..6a6123564553c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.c -@@ -0,0 +1,592 @@ -+/* -+ * TLSv1 server (RFC 2246) -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "tlsv1_common.h" -+#include "tlsv1_record.h" -+#include "tlsv1_server.h" -+#include "tlsv1_server_i.h" -+ -+/* TODO: -+ * Support for a message fragmented across several records (RFC 2246, 6.2.1) -+ */ -+ -+ -+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description) -+{ -+ conn->alert_level = level; -+ conn->alert_description = description; -+} -+ -+ -+int tlsv1_server_derive_keys(struct tlsv1_server *conn, -+ const u8 *pre_master_secret, -+ size_t pre_master_secret_len) -+{ -+ u8 seed[2 * TLS_RANDOM_LEN]; -+ u8 key_block[TLS_MAX_KEY_BLOCK_LEN]; -+ u8 *pos; -+ size_t key_block_len; -+ -+ if (pre_master_secret) { -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret", -+ pre_master_secret, pre_master_secret_len); -+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, -+ TLS_RANDOM_LEN); -+ if (tls_prf(pre_master_secret, pre_master_secret_len, -+ "master secret", seed, 2 * TLS_RANDOM_LEN, -+ conn->master_secret, TLS_MASTER_SECRET_LEN)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive " -+ "master_secret"); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret", -+ conn->master_secret, TLS_MASTER_SECRET_LEN); -+ } -+ -+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN); -+ key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len + -+ conn->rl.iv_size); -+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ "key expansion", seed, 2 * TLS_RANDOM_LEN, -+ key_block, key_block_len)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block"); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block", -+ key_block, key_block_len); -+ -+ pos = key_block; -+ -+ /* client_write_MAC_secret */ -+ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size); -+ pos += conn->rl.hash_size; -+ /* server_write_MAC_secret */ -+ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size); -+ pos += conn->rl.hash_size; -+ -+ /* client_write_key */ -+ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len); -+ pos += conn->rl.key_material_len; -+ /* server_write_key */ -+ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len); -+ pos += conn->rl.key_material_len; -+ -+ /* client_write_IV */ -+ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size); -+ pos += conn->rl.iv_size; -+ /* server_write_IV */ -+ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size); -+ pos += conn->rl.iv_size; -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_server_handshake - Process TLS handshake -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * @in_data: Input data from TLS peer -+ * @in_len: Input data length -+ * @out_len: Length of the output buffer. -+ * Returns: Pointer to output data, %NULL on failure -+ */ -+u8 * tlsv1_server_handshake(struct tlsv1_server *conn, -+ const u8 *in_data, size_t in_len, -+ size_t *out_len) -+{ -+ const u8 *pos, *end; -+ u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct; -+ size_t in_msg_len; -+ -+ if (in_data == NULL || in_len == 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No input data to server"); -+ return NULL; -+ } -+ -+ pos = in_data; -+ end = in_data + in_len; -+ in_msg = os_malloc(in_len); -+ if (in_msg == NULL) -+ return NULL; -+ -+ /* Each received packet may include multiple records */ -+ while (pos < end) { -+ in_msg_len = in_len; -+ if (tlsv1_record_receive(&conn->rl, pos, end - pos, -+ in_msg, &in_msg_len, &alert)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Processing received " -+ "record failed"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); -+ goto failed; -+ } -+ ct = pos[0]; -+ -+ in_pos = in_msg; -+ in_end = in_msg + in_msg_len; -+ -+ /* Each received record may include multiple messages of the -+ * same ContentType. */ -+ while (in_pos < in_end) { -+ in_msg_len = in_end - in_pos; -+ if (tlsv1_server_process_handshake(conn, ct, in_pos, -+ &in_msg_len) < 0) -+ goto failed; -+ in_pos += in_msg_len; -+ } -+ -+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); -+ } -+ -+ os_free(in_msg); -+ in_msg = NULL; -+ -+ msg = tlsv1_server_handshake_write(conn, out_len); -+ -+failed: -+ os_free(in_msg); -+ if (conn->alert_level) { -+ if (conn->state == FAILED) { -+ /* Avoid alert loops */ -+ wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop"); -+ os_free(msg); -+ return NULL; -+ } -+ conn->state = FAILED; -+ os_free(msg); -+ msg = tlsv1_server_send_alert(conn, conn->alert_level, -+ conn->alert_description, -+ out_len); -+ } -+ -+ return msg; -+} -+ -+ -+/** -+ * tlsv1_server_encrypt - Encrypt data into TLS tunnel -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * @in_data: Pointer to plaintext data to be encrypted -+ * @in_len: Input buffer length -+ * @out_data: Pointer to output buffer (encrypted TLS data) -+ * @out_len: Maximum out_data length -+ * Returns: Number of bytes written to out_data, -1 on failure -+ * -+ * This function is used after TLS handshake has been completed successfully to -+ * send data in the encrypted tunnel. -+ */ -+int tlsv1_server_encrypt(struct tlsv1_server *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len) -+{ -+ size_t rlen; -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData", -+ in_data, in_len); -+ -+ os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA, -+ out_data, out_len, in_len, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ return rlen; -+} -+ -+ -+/** -+ * tlsv1_server_decrypt - Decrypt data from TLS tunnel -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * @in_data: Pointer to input buffer (encrypted TLS data) -+ * @in_len: Input buffer length -+ * @out_data: Pointer to output buffer (decrypted data from TLS tunnel) -+ * @out_len: Maximum out_data length -+ * Returns: Number of bytes written to out_data, -1 on failure -+ * -+ * This function is used after TLS handshake has been completed successfully to -+ * receive data from the encrypted tunnel. -+ */ -+int tlsv1_server_decrypt(struct tlsv1_server *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len) -+{ -+ const u8 *in_end, *pos; -+ int res; -+ u8 alert, *out_end, *out_pos; -+ size_t olen; -+ -+ pos = in_data; -+ in_end = in_data + in_len; -+ out_pos = out_data; -+ out_end = out_data + out_len; -+ -+ while (pos < in_end) { -+ if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type " -+ "0x%x", pos[0]); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ olen = out_end - out_pos; -+ res = tlsv1_record_receive(&conn->rl, pos, in_end - pos, -+ out_pos, &olen, &alert); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing " -+ "failed"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert); -+ return -1; -+ } -+ out_pos += olen; -+ if (out_pos > out_end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough " -+ "for processing the received record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3); -+ } -+ -+ return out_pos - out_data; -+} -+ -+ -+/** -+ * tlsv1_server_global_init - Initialize TLSv1 server -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function must be called before using any other TLSv1 server functions. -+ */ -+int tlsv1_server_global_init(void) -+{ -+ return crypto_global_init(); -+} -+ -+ -+/** -+ * tlsv1_server_global_deinit - Deinitialize TLSv1 server -+ * -+ * This function can be used to deinitialize the TLSv1 server that was -+ * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions -+ * can be called after this before calling tlsv1_server_global_init() again. -+ */ -+void tlsv1_server_global_deinit(void) -+{ -+ crypto_global_deinit(); -+} -+ -+ -+/** -+ * tlsv1_server_init - Initialize TLSv1 server connection -+ * @cred: Pointer to server credentials from tlsv1_server_cred_alloc() -+ * Returns: Pointer to TLSv1 server connection data or %NULL on failure -+ */ -+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred) -+{ -+ struct tlsv1_server *conn; -+ size_t count; -+ u16 *suites; -+ -+ conn = os_zalloc(sizeof(*conn)); -+ if (conn == NULL) -+ return NULL; -+ -+ conn->cred = cred; -+ -+ conn->state = CLIENT_HELLO; -+ -+ if (tls_verify_hash_init(&conn->verify) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify " -+ "hash"); -+ os_free(conn); -+ return NULL; -+ } -+ -+ count = 0; -+ suites = conn->cipher_suites; -+#ifndef CONFIG_CRYPTO_INTERNAL -+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; -+#endif /* CONFIG_CRYPTO_INTERNAL */ -+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; -+ suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; -+ suites[count++] = TLS_RSA_WITH_RC4_128_SHA; -+ suites[count++] = TLS_RSA_WITH_RC4_128_MD5; -+ conn->num_cipher_suites = count; -+ -+ return conn; -+} -+ -+ -+static void tlsv1_server_clear_data(struct tlsv1_server *conn) -+{ -+ tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL); -+ tlsv1_record_change_write_cipher(&conn->rl); -+ tlsv1_record_change_read_cipher(&conn->rl); -+ tls_verify_hash_free(&conn->verify); -+ -+ crypto_public_key_free(conn->client_rsa_key); -+ conn->client_rsa_key = NULL; -+ -+ os_free(conn->session_ticket); -+ conn->session_ticket = NULL; -+ conn->session_ticket_len = 0; -+ conn->use_session_ticket = 0; -+ -+ os_free(conn->dh_secret); -+ conn->dh_secret = NULL; -+ conn->dh_secret_len = 0; -+} -+ -+ -+/** -+ * tlsv1_server_deinit - Deinitialize TLSv1 server connection -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ */ -+void tlsv1_server_deinit(struct tlsv1_server *conn) -+{ -+ tlsv1_server_clear_data(conn); -+ os_free(conn); -+} -+ -+ -+/** -+ * tlsv1_server_established - Check whether connection has been established -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * Returns: 1 if connection is established, 0 if not -+ */ -+int tlsv1_server_established(struct tlsv1_server *conn) -+{ -+ return conn->state == ESTABLISHED; -+} -+ -+ -+/** -+ * tlsv1_server_prf - Use TLS-PRF to derive keying material -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * @label: Label (e.g., description of the key) for PRF -+ * @server_random_first: seed is 0 = client_random|server_random, -+ * 1 = server_random|client_random -+ * @out: Buffer for output data from TLS-PRF -+ * @out_len: Length of the output buffer -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, -+ int server_random_first, u8 *out, size_t out_len) -+{ -+ u8 seed[2 * TLS_RANDOM_LEN]; -+ -+ if (conn->state != ESTABLISHED) -+ return -1; -+ -+ if (server_random_first) { -+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, -+ TLS_RANDOM_LEN); -+ } else { -+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN); -+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random, -+ TLS_RANDOM_LEN); -+ } -+ -+ return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ label, seed, 2 * TLS_RANDOM_LEN, out, out_len); -+} -+ -+ -+/** -+ * tlsv1_server_get_cipher - Get current cipher name -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * @buf: Buffer for the cipher name -+ * @buflen: buf size -+ * Returns: 0 on success, -1 on failure -+ * -+ * Get the name of the currently used cipher. -+ */ -+int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf, -+ size_t buflen) -+{ -+ char *cipher; -+ -+ switch (conn->rl.cipher_suite) { -+ case TLS_RSA_WITH_RC4_128_MD5: -+ cipher = "RC4-MD5"; -+ break; -+ case TLS_RSA_WITH_RC4_128_SHA: -+ cipher = "RC4-SHA"; -+ break; -+ case TLS_RSA_WITH_DES_CBC_SHA: -+ cipher = "DES-CBC-SHA"; -+ break; -+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA: -+ cipher = "DES-CBC3-SHA"; -+ break; -+ case TLS_DH_anon_WITH_AES_128_CBC_SHA: -+ cipher = "ADH-AES-128-SHA"; -+ break; -+ case TLS_RSA_WITH_AES_256_CBC_SHA: -+ cipher = "AES-256-SHA"; -+ break; -+ case TLS_RSA_WITH_AES_128_CBC_SHA: -+ cipher = "AES-128-SHA"; -+ break; -+ default: -+ return -1; -+ } -+ -+ if (os_strlcpy(buf, cipher, buflen) >= buflen) -+ return -1; -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_server_shutdown - Shutdown TLS connection -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_server_shutdown(struct tlsv1_server *conn) -+{ -+ conn->state = CLIENT_HELLO; -+ -+ if (tls_verify_hash_init(&conn->verify) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify " -+ "hash"); -+ return -1; -+ } -+ -+ tlsv1_server_clear_data(conn); -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_server_resumed - Was session resumption used -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * Returns: 1 if current session used session resumption, 0 if not -+ */ -+int tlsv1_server_resumed(struct tlsv1_server *conn) -+{ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_server_get_keys - Get master key and random data from TLS connection -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * @keys: Structure of key/random data (filled on success) -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys) -+{ -+ os_memset(keys, 0, sizeof(*keys)); -+ if (conn->state == CLIENT_HELLO) -+ return -1; -+ -+ keys->client_random = conn->client_random; -+ keys->client_random_len = TLS_RANDOM_LEN; -+ -+ if (conn->state != SERVER_HELLO) { -+ keys->server_random = conn->server_random; -+ keys->server_random_len = TLS_RANDOM_LEN; -+ keys->master_key = conn->master_secret; -+ keys->master_key_len = TLS_MASTER_SECRET_LEN; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * tlsv1_server_get_keyblock_size - Get TLS key_block size -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on -+ * failure -+ */ -+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn) -+{ -+ if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO) -+ return -1; -+ -+ return 2 * (conn->rl.hash_size + conn->rl.key_material_len + -+ conn->rl.iv_size); -+} -+ -+ -+/** -+ * tlsv1_server_set_cipher_list - Configure acceptable cipher suites -+ * @conn: TLSv1 server connection data from tlsv1_server_init() -+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers -+ * (TLS_CIPHER_*). -+ * Returns: 0 on success, -1 on failure -+ */ -+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers) -+{ -+ size_t count; -+ u16 *suites; -+ -+ /* TODO: implement proper configuration of cipher suites */ -+ if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) { -+ count = 0; -+ suites = conn->cipher_suites; -+#ifndef CONFIG_CRYPTO_INTERNAL -+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA; -+#endif /* CONFIG_CRYPTO_INTERNAL */ -+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA; -+ suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA; -+ suites[count++] = TLS_RSA_WITH_RC4_128_SHA; -+ suites[count++] = TLS_RSA_WITH_RC4_128_MD5; -+#ifndef CONFIG_CRYPTO_INTERNAL -+ suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA; -+#endif /* CONFIG_CRYPTO_INTERNAL */ -+ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA; -+ suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA; -+ suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5; -+ suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA; -+ conn->num_cipher_suites = count; -+ } -+ -+ return 0; -+} -+ -+ -+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer) -+{ -+ conn->verify_peer = verify_peer; -+ return 0; -+} -+ -+ -+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn, -+ tlsv1_server_session_ticket_cb cb, -+ void *ctx) -+{ -+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)", -+ cb, ctx); -+ conn->session_ticket_cb = cb; -+ conn->session_ticket_cb_ctx = ctx; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.h -new file mode 100644 -index 0000000000000..00c536c3ee2b8 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server.h -@@ -0,0 +1,54 @@ -+/* -+ * TLSv1 server (RFC 2246) -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLSV1_SERVER_H -+#define TLSV1_SERVER_H -+ -+#include "tlsv1_cred.h" -+ -+struct tlsv1_server; -+ -+int tlsv1_server_global_init(void); -+void tlsv1_server_global_deinit(void); -+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred); -+void tlsv1_server_deinit(struct tlsv1_server *conn); -+int tlsv1_server_established(struct tlsv1_server *conn); -+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label, -+ int server_random_first, u8 *out, size_t out_len); -+u8 * tlsv1_server_handshake(struct tlsv1_server *conn, -+ const u8 *in_data, size_t in_len, size_t *out_len); -+int tlsv1_server_encrypt(struct tlsv1_server *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len); -+int tlsv1_server_decrypt(struct tlsv1_server *conn, -+ const u8 *in_data, size_t in_len, -+ u8 *out_data, size_t out_len); -+int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf, -+ size_t buflen); -+int tlsv1_server_shutdown(struct tlsv1_server *conn); -+int tlsv1_server_resumed(struct tlsv1_server *conn); -+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys); -+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn); -+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers); -+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer); -+ -+typedef int (*tlsv1_server_session_ticket_cb) -+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random, -+ const u8 *server_random, u8 *master_secret); -+ -+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn, -+ tlsv1_server_session_ticket_cb cb, -+ void *ctx); -+ -+#endif /* TLSV1_SERVER_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_i.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_i.h -new file mode 100644 -index 0000000000000..d11ea7559f3fe ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_i.h -@@ -0,0 +1,77 @@ -+/* -+ * TLSv1 server - internal structures -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TLSV1_SERVER_I_H -+#define TLSV1_SERVER_I_H -+ -+struct tlsv1_server { -+ enum { -+ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE, -+ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST, -+ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE, -+ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED, -+ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, -+ ESTABLISHED, FAILED -+ } state; -+ -+ struct tlsv1_record_layer rl; -+ -+ u8 session_id[TLS_SESSION_ID_MAX_LEN]; -+ size_t session_id_len; -+ u8 client_random[TLS_RANDOM_LEN]; -+ u8 server_random[TLS_RANDOM_LEN]; -+ u8 master_secret[TLS_MASTER_SECRET_LEN]; -+ -+ u8 alert_level; -+ u8 alert_description; -+ -+ struct crypto_public_key *client_rsa_key; -+ -+ struct tls_verify_hash verify; -+ -+#define MAX_CIPHER_COUNT 30 -+ u16 cipher_suites[MAX_CIPHER_COUNT]; -+ size_t num_cipher_suites; -+ -+ u16 cipher_suite; -+ -+ struct tlsv1_credentials *cred; -+ -+ int verify_peer; -+ u16 client_version; -+ -+ u8 *session_ticket; -+ size_t session_ticket_len; -+ -+ tlsv1_server_session_ticket_cb session_ticket_cb; -+ void *session_ticket_cb_ctx; -+ -+ int use_session_ticket; -+ -+ u8 *dh_secret; -+ size_t dh_secret_len; -+}; -+ -+ -+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description); -+int tlsv1_server_derive_keys(struct tlsv1_server *conn, -+ const u8 *pre_master_secret, -+ size_t pre_master_secret_len); -+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len); -+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, -+ u8 description, size_t *out_len); -+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, -+ const u8 *buf, size_t *len); -+ -+#endif /* TLSV1_SERVER_I_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_read.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_read.c -new file mode 100644 -index 0000000000000..49e811ffcff51 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_read.c -@@ -0,0 +1,1134 @@ -+/* -+ * TLSv1 server - read handshake message -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/md5.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "x509v3.h" -+#include "tlsv1_common.h" -+#include "tlsv1_record.h" -+#include "tlsv1_server.h" -+#include "tlsv1_server_i.h" -+ -+ -+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, -+ const u8 *in_data, size_t *in_len); -+static int tls_process_change_cipher_spec(struct tlsv1_server *conn, -+ u8 ct, const u8 *in_data, -+ size_t *in_len); -+ -+ -+static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end, *c; -+ size_t left, len, i, j; -+ u16 cipher_suite; -+ u16 num_suites; -+ int compr_null_found; -+ u16 ext_type, ext_len; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) -+ goto decode_error; -+ -+ /* HandshakeType msg_type */ -+ if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected ClientHello)", *pos); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello"); -+ pos++; -+ /* uint24 length */ -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) -+ goto decode_error; -+ -+ /* body - ClientHello */ -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len); -+ end = pos + len; -+ -+ /* ProtocolVersion client_version */ -+ if (end - pos < 2) -+ goto decode_error; -+ conn->client_version = WPA_GET_BE16(pos); -+ wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d", -+ conn->client_version >> 8, conn->client_version & 0xff); -+ if (conn->client_version < TLS_VERSION) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in " -+ "ClientHello"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_PROTOCOL_VERSION); -+ return -1; -+ } -+ pos += 2; -+ -+ /* Random random */ -+ if (end - pos < TLS_RANDOM_LEN) -+ goto decode_error; -+ -+ os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN); -+ pos += TLS_RANDOM_LEN; -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random", -+ conn->client_random, TLS_RANDOM_LEN); -+ -+ /* SessionID session_id */ -+ if (end - pos < 1) -+ goto decode_error; -+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN) -+ goto decode_error; -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos); -+ pos += 1 + *pos; -+ /* TODO: add support for session resumption */ -+ -+ /* CipherSuite cipher_suites<2..2^16-1> */ -+ if (end - pos < 2) -+ goto decode_error; -+ num_suites = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < num_suites) -+ goto decode_error; -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites", -+ pos, num_suites); -+ if (num_suites & 1) -+ goto decode_error; -+ num_suites /= 2; -+ -+ cipher_suite = 0; -+ for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) { -+ c = pos; -+ for (j = 0; j < num_suites; j++) { -+ u16 tmp = WPA_GET_BE16(c); -+ c += 2; -+ if (!cipher_suite && tmp == conn->cipher_suites[i]) { -+ cipher_suite = tmp; -+ break; -+ } -+ } -+ } -+ pos += num_suites * 2; -+ if (!cipher_suite) { -+ wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite " -+ "available"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_ILLEGAL_PARAMETER); -+ return -1; -+ } -+ -+ if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for " -+ "record layer"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ conn->cipher_suite = cipher_suite; -+ -+ /* CompressionMethod compression_methods<1..2^8-1> */ -+ if (end - pos < 1) -+ goto decode_error; -+ num_suites = *pos++; -+ if (end - pos < num_suites) -+ goto decode_error; -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods", -+ pos, num_suites); -+ compr_null_found = 0; -+ for (i = 0; i < num_suites; i++) { -+ if (*pos++ == TLS_COMPRESSION_NULL) -+ compr_null_found = 1; -+ } -+ if (!compr_null_found) { -+ wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL " -+ "compression"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_ILLEGAL_PARAMETER); -+ return -1; -+ } -+ -+ if (end - pos == 1) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the " -+ "end of ClientHello: 0x%02x", *pos); -+ goto decode_error; -+ } -+ -+ if (end - pos >= 2) { -+ /* Extension client_hello_extension_list<0..2^16-1> */ -+ ext_len = WPA_GET_BE16(pos); -+ pos += 2; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello " -+ "extensions", ext_len); -+ if (end - pos != ext_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello " -+ "extension list length %u (expected %u)", -+ ext_len, (unsigned int) (end - pos)); -+ goto decode_error; -+ } -+ -+ /* -+ * struct { -+ * ExtensionType extension_type (0..65535) -+ * opaque extension_data<0..2^16-1> -+ * } Extension; -+ */ -+ -+ while (pos < end) { -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid " -+ "extension_type field"); -+ goto decode_error; -+ } -+ -+ ext_type = WPA_GET_BE16(pos); -+ pos += 2; -+ -+ if (end - pos < 2) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid " -+ "extension_data length field"); -+ goto decode_error; -+ } -+ -+ ext_len = WPA_GET_BE16(pos); -+ pos += 2; -+ -+ if (end - pos < ext_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid " -+ "extension_data field"); -+ goto decode_error; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension " -+ "type %u", ext_type); -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello " -+ "Extension data", pos, ext_len); -+ -+ if (ext_type == TLS_EXT_SESSION_TICKET) { -+ os_free(conn->session_ticket); -+ conn->session_ticket = os_malloc(ext_len); -+ if (conn->session_ticket) { -+ os_memcpy(conn->session_ticket, pos, -+ ext_len); -+ conn->session_ticket_len = ext_len; -+ } -+ } -+ -+ pos += ext_len; -+ } -+ } -+ -+ *in_len = end - in_data; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to " -+ "ServerHello"); -+ conn->state = SERVER_HELLO; -+ -+ return 0; -+ -+decode_error: -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+} -+ -+ -+static int tls_process_certificate(struct tlsv1_server *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len, list_len, cert_len, idx; -+ u8 type; -+ struct x509_certificate *chain = NULL, *last = NULL, *cert; -+ int reason; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message " -+ "(len=%lu)", (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ type = *pos++; -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message " -+ "length (len=%lu != left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { -+ if (conn->verify_peer) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " -+ "Certificate"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ return tls_process_client_key_exchange(conn, ct, in_data, -+ in_len); -+ } -+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected Certificate/" -+ "ClientKeyExchange)", type); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, -+ "TLSv1: Received Certificate (certificate_list len %lu)", -+ (unsigned long) len); -+ -+ /* -+ * opaque ASN.1Cert<2^24-1>; -+ * -+ * struct { -+ * ASN.1Cert certificate_list<1..2^24-1>; -+ * } Certificate; -+ */ -+ -+ end = pos + len; -+ -+ if (end - pos < 3) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate " -+ "(left=%lu)", (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ list_len = WPA_GET_BE24(pos); -+ pos += 3; -+ -+ if ((size_t) (end - pos) != list_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list " -+ "length (len=%lu left=%lu)", -+ (unsigned long) list_len, -+ (unsigned long) (end - pos)); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ idx = 0; -+ while (pos < end) { -+ if (end - pos < 3) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " -+ "certificate_list"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ cert_len = WPA_GET_BE24(pos); -+ pos += 3; -+ -+ if ((size_t) (end - pos) < cert_len) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate " -+ "length (len=%lu left=%lu)", -+ (unsigned long) cert_len, -+ (unsigned long) (end - pos)); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)", -+ (unsigned long) idx, (unsigned long) cert_len); -+ -+ if (idx == 0) { -+ crypto_public_key_free(conn->client_rsa_key); -+ if (tls_parse_cert(pos, cert_len, -+ &conn->client_rsa_key)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " -+ "the certificate"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_BAD_CERTIFICATE); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ } -+ -+ cert = x509_certificate_parse(pos, cert_len); -+ if (cert == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse " -+ "the certificate"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_BAD_CERTIFICATE); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ if (last == NULL) -+ chain = cert; -+ else -+ last->next = cert; -+ last = cert; -+ -+ idx++; -+ pos += cert_len; -+ } -+ -+ if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain, -+ &reason) < 0) { -+ int tls_reason; -+ wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain " -+ "validation failed (reason=%d)", reason); -+ switch (reason) { -+ case X509_VALIDATE_BAD_CERTIFICATE: -+ tls_reason = TLS_ALERT_BAD_CERTIFICATE; -+ break; -+ case X509_VALIDATE_UNSUPPORTED_CERTIFICATE: -+ tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE; -+ break; -+ case X509_VALIDATE_CERTIFICATE_REVOKED: -+ tls_reason = TLS_ALERT_CERTIFICATE_REVOKED; -+ break; -+ case X509_VALIDATE_CERTIFICATE_EXPIRED: -+ tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED; -+ break; -+ case X509_VALIDATE_CERTIFICATE_UNKNOWN: -+ tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN; -+ break; -+ case X509_VALIDATE_UNKNOWN_CA: -+ tls_reason = TLS_ALERT_UNKNOWN_CA; -+ break; -+ default: -+ tls_reason = TLS_ALERT_BAD_CERTIFICATE; -+ break; -+ } -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason); -+ x509_certificate_chain_free(chain); -+ return -1; -+ } -+ -+ x509_certificate_chain_free(chain); -+ -+ *in_len = end - in_data; -+ -+ conn->state = CLIENT_KEY_EXCHANGE; -+ -+ return 0; -+} -+ -+ -+static int tls_process_client_key_exchange_rsa( -+ struct tlsv1_server *conn, const u8 *pos, const u8 *end) -+{ -+ u8 *out; -+ size_t outlen, outbuflen; -+ u16 encr_len; -+ int res; -+ int use_random = 0; -+ -+ if (end - pos < 2) { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ encr_len = WPA_GET_BE16(pos); -+ pos += 2; -+ -+ outbuflen = outlen = end - pos; -+ out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ? -+ outlen : TLS_PRE_MASTER_SECRET_LEN); -+ if (out == NULL) { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ /* -+ * struct { -+ * ProtocolVersion client_version; -+ * opaque random[46]; -+ * } PreMasterSecret; -+ * -+ * struct { -+ * public-key-encrypted PreMasterSecret pre_master_secret; -+ * } EncryptedPreMasterSecret; -+ */ -+ -+ /* -+ * Note: To avoid Bleichenbacher attack, we do not report decryption or -+ * parsing errors from EncryptedPreMasterSecret processing to the -+ * client. Instead, a random pre-master secret is used to force the -+ * handshake to fail. -+ */ -+ -+ if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key, -+ pos, end - pos, -+ out, &outlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt " -+ "PreMasterSecret (encr_len=%d outlen=%lu)", -+ (int) (end - pos), (unsigned long) outlen); -+ use_random = 1; -+ } -+ -+ if (outlen != TLS_PRE_MASTER_SECRET_LEN) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret " -+ "length %lu", (unsigned long) outlen); -+ use_random = 1; -+ } -+ -+ if (WPA_GET_BE16(out) != conn->client_version) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Client version in " -+ "ClientKeyExchange does not match with version in " -+ "ClientHello"); -+ use_random = 1; -+ } -+ -+ if (use_random) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret " -+ "to avoid revealing information about private key"); -+ outlen = TLS_PRE_MASTER_SECRET_LEN; -+ if (os_get_random(out, outlen)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " -+ "data"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(out); -+ return -1; -+ } -+ } -+ -+ res = tlsv1_server_derive_keys(conn, out, outlen); -+ -+ /* Clear the pre-master secret since it is not needed anymore */ -+ os_memset(out, 0, outbuflen); -+ os_free(out); -+ -+ if (res) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int tls_process_client_key_exchange_dh_anon( -+ struct tlsv1_server *conn, const u8 *pos, const u8 *end) -+{ -+ const u8 *dh_yc; -+ u16 dh_yc_len; -+ u8 *shared; -+ size_t shared_len; -+ int res; -+ -+ /* -+ * struct { -+ * select (PublicValueEncoding) { -+ * case implicit: struct { }; -+ * case explicit: opaque dh_Yc<1..2^16-1>; -+ * } dh_public; -+ * } ClientDiffieHellmanPublic; -+ */ -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic", -+ pos, end - pos); -+ -+ if (end == pos) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding " -+ "not supported"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ if (end - pos < 3) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value " -+ "length"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ dh_yc_len = WPA_GET_BE16(pos); -+ dh_yc = pos + 2; -+ -+ if (dh_yc + dh_yc_len > end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow " -+ "(length %d)", dh_yc_len); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)", -+ dh_yc, dh_yc_len); -+ -+ if (conn->cred == NULL || conn->cred->dh_p == NULL || -+ conn->dh_secret == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ shared_len = conn->cred->dh_p_len; -+ shared = os_malloc(shared_len); -+ if (shared == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " -+ "DH"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ /* shared = Yc^secret mod p */ -+ if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, -+ conn->dh_secret_len, -+ conn->cred->dh_p, conn->cred->dh_p_len, -+ shared, &shared_len)) { -+ os_free(shared); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange", -+ shared, shared_len); -+ -+ os_memset(conn->dh_secret, 0, conn->dh_secret_len); -+ os_free(conn->dh_secret); -+ conn->dh_secret = NULL; -+ -+ res = tlsv1_server_derive_keys(conn, shared, shared_len); -+ -+ /* Clear the pre-master secret since it is not needed anymore */ -+ os_memset(shared, 0, shared_len); -+ os_free(shared); -+ -+ if (res) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len; -+ u8 type; -+ tls_key_exchange keyx; -+ const struct tls_cipher_suite *suite; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange " -+ "(Left=%lu)", (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ type = *pos++; -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange " -+ "length (len=%lu != left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ end = pos + len; -+ -+ if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected ClientKeyExchange)", type); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange"); -+ -+ wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len); -+ -+ suite = tls_get_cipher_suite(conn->rl.cipher_suite); -+ if (suite == NULL) -+ keyx = TLS_KEY_X_NULL; -+ else -+ keyx = suite->key_exchange; -+ -+ if (keyx == TLS_KEY_X_DH_anon && -+ tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0) -+ return -1; -+ -+ if (keyx != TLS_KEY_X_DH_anon && -+ tls_process_client_key_exchange_rsa(conn, pos, end) < 0) -+ return -1; -+ -+ *in_len = end - in_data; -+ -+ conn->state = CERTIFICATE_VERIFY; -+ -+ return 0; -+} -+ -+ -+static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len; -+ u8 type; -+ size_t hlen, buflen; -+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf; -+ enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA; -+ u16 slen; -+ -+ if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { -+ if (conn->verify_peer) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Client did not include " -+ "CertificateVerify"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ return tls_process_change_cipher_spec(conn, ct, in_data, -+ in_len); -+ } -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; " -+ "received content type 0x%x", ct); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify " -+ "message (len=%lu)", (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ type = *pos++; -+ len = WPA_GET_BE24(pos); -+ pos += 3; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify " -+ "message length (len=%lu != left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ end = pos + len; -+ -+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake " -+ "message %d (expected CertificateVerify)", type); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify"); -+ -+ /* -+ * struct { -+ * Signature signature; -+ * } CertificateVerify; -+ */ -+ -+ hpos = hash; -+ -+ if (alg == SIGN_ALG_RSA) { -+ hlen = MD5_MAC_LEN; -+ if (conn->verify.md5_cert == NULL || -+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0) -+ { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ conn->verify.md5_cert = NULL; -+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL); -+ conn->verify.sha1_cert = NULL; -+ return -1; -+ } -+ hpos += MD5_MAC_LEN; -+ } else -+ crypto_hash_finish(conn->verify.md5_cert, NULL, NULL); -+ -+ conn->verify.md5_cert = NULL; -+ hlen = SHA1_MAC_LEN; -+ if (conn->verify.sha1_cert == NULL || -+ crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) { -+ conn->verify.sha1_cert = NULL; -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ conn->verify.sha1_cert = NULL; -+ -+ if (alg == SIGN_ALG_RSA) -+ hlen += MD5_MAC_LEN; -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen); -+ -+ if (end - pos < 2) { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ slen = WPA_GET_BE16(pos); -+ pos += 2; -+ if (end - pos < slen) { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos); -+ if (conn->client_rsa_key == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify " -+ "signature"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ buflen = end - pos; -+ buf = os_malloc(end - pos); -+ if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key, -+ pos, end - pos, buf, &buflen) < 0) -+ { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature"); -+ os_free(buf); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECRYPT_ERROR); -+ return -1; -+ } -+ -+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature", -+ buf, buflen); -+ -+ if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in " -+ "CertificateVerify - did not match with calculated " -+ "hash"); -+ os_free(buf); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECRYPT_ERROR); -+ return -1; -+ } -+ -+ os_free(buf); -+ -+ *in_len = end - in_data; -+ -+ conn->state = CHANGE_CIPHER_SPEC; -+ -+ return 0; -+} -+ -+ -+static int tls_process_change_cipher_spec(struct tlsv1_server *conn, -+ u8 ct, const u8 *in_data, -+ size_t *in_len) -+{ -+ const u8 *pos; -+ size_t left; -+ -+ if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " -+ "received content type 0x%x", ct); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 1) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ if (*pos != TLS_CHANGE_CIPHER_SPEC) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; " -+ "received data 0x%x", *pos); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec"); -+ if (tlsv1_record_change_read_cipher(&conn->rl) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher " -+ "for record layer"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ *in_len = pos + 1 - in_data; -+ -+ conn->state = CLIENT_FINISHED; -+ -+ return 0; -+} -+ -+ -+static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, -+ const u8 *in_data, size_t *in_len) -+{ -+ const u8 *pos, *end; -+ size_t left, len, hlen; -+ u8 verify_data[TLS_VERIFY_DATA_LEN]; -+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; -+ -+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; " -+ "received content type 0x%x", ct); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ pos = in_data; -+ left = *in_len; -+ -+ if (left < 4) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for " -+ "Finished", -+ (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ -+ if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received " -+ "type 0x%x", pos[0]); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_UNEXPECTED_MESSAGE); -+ return -1; -+ } -+ -+ len = WPA_GET_BE24(pos + 1); -+ -+ pos += 4; -+ left -= 4; -+ -+ if (len > left) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished " -+ "(len=%lu > left=%lu)", -+ (unsigned long) len, (unsigned long) left); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ end = pos + len; -+ if (len != TLS_VERIFY_DATA_LEN) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length " -+ "in Finished: %lu (expected %d)", -+ (unsigned long) len, TLS_VERIFY_DATA_LEN); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished", -+ pos, TLS_VERIFY_DATA_LEN); -+ -+ hlen = MD5_MAC_LEN; -+ if (conn->verify.md5_client == NULL || -+ crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ conn->verify.md5_client = NULL; -+ crypto_hash_finish(conn->verify.sha1_client, NULL, NULL); -+ conn->verify.sha1_client = NULL; -+ return -1; -+ } -+ conn->verify.md5_client = NULL; -+ hlen = SHA1_MAC_LEN; -+ if (conn->verify.sha1_client == NULL || -+ crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN, -+ &hlen) < 0) { -+ conn->verify.sha1_client = NULL; -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ conn->verify.sha1_client = NULL; -+ -+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, -+ verify_data, TLS_VERIFY_DATA_LEN)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECRYPT_ERROR); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", -+ verify_data, TLS_VERIFY_DATA_LEN); -+ -+ if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { -+ wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Received Finished"); -+ -+ *in_len = end - in_data; -+ -+ if (conn->use_session_ticket) { -+ /* Abbreviated handshake using session ticket; RFC 4507 */ -+ wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed " -+ "successfully"); -+ conn->state = ESTABLISHED; -+ } else { -+ /* Full handshake */ -+ conn->state = SERVER_CHANGE_CIPHER_SPEC; -+ } -+ -+ return 0; -+} -+ -+ -+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, -+ const u8 *buf, size_t *len) -+{ -+ if (ct == TLS_CONTENT_TYPE_ALERT) { -+ if (*len < 2) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_DECODE_ERROR); -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d", -+ buf[0], buf[1]); -+ *len = 2; -+ conn->state = FAILED; -+ return -1; -+ } -+ -+ switch (conn->state) { -+ case CLIENT_HELLO: -+ if (tls_process_client_hello(conn, ct, buf, len)) -+ return -1; -+ break; -+ case CLIENT_CERTIFICATE: -+ if (tls_process_certificate(conn, ct, buf, len)) -+ return -1; -+ break; -+ case CLIENT_KEY_EXCHANGE: -+ if (tls_process_client_key_exchange(conn, ct, buf, len)) -+ return -1; -+ break; -+ case CERTIFICATE_VERIFY: -+ if (tls_process_certificate_verify(conn, ct, buf, len)) -+ return -1; -+ break; -+ case CHANGE_CIPHER_SPEC: -+ if (tls_process_change_cipher_spec(conn, ct, buf, len)) -+ return -1; -+ break; -+ case CLIENT_FINISHED: -+ if (tls_process_client_finished(conn, ct, buf, len)) -+ return -1; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d " -+ "while processing received message", -+ conn->state); -+ return -1; -+ } -+ -+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE) -+ tls_verify_hash_add(&conn->verify, buf, *len); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_write.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_write.c -new file mode 100644 -index 0000000000000..e89e52ec00036 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/tlsv1_server_write.c -@@ -0,0 +1,791 @@ -+/* -+ * TLSv1 server - write handshake message -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/md5.h" -+#include "crypto/sha1.h" -+#include "crypto/tls.h" -+#include "crypto/random.h" -+#include "x509v3.h" -+#include "tlsv1_common.h" -+#include "tlsv1_record.h" -+#include "tlsv1_server.h" -+#include "tlsv1_server_i.h" -+ -+ -+static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn) -+{ -+ size_t len = 0; -+ struct x509_certificate *cert; -+ -+ cert = conn->cred->cert; -+ while (cert) { -+ len += 3 + cert->cert_len; -+ if (x509_certificate_self_signed(cert)) -+ break; -+ cert = x509_certificate_get_subject(conn->cred->trusted_certs, -+ &cert->issuer); -+ } -+ -+ return len; -+} -+ -+ -+static int tls_write_server_hello(struct tlsv1_server *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length; -+ struct os_time now; -+ size_t rlen; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ os_get_time(&now); -+ WPA_PUT_BE32(conn->server_random, now.sec); -+ if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) { -+ wpa_printf(MSG_ERROR, "TLSv1: Could not generate " -+ "server_random"); -+ return -1; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random", -+ conn->server_random, TLS_RANDOM_LEN); -+ -+ conn->session_id_len = TLS_SESSION_ID_MAX_LEN; -+ if (random_get_bytes(conn->session_id, conn->session_id_len)) { -+ wpa_printf(MSG_ERROR, "TLSv1: Could not generate " -+ "session_id"); -+ return -1; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id", -+ conn->session_id, conn->session_id_len); -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ /* body - ServerHello */ -+ /* ProtocolVersion server_version */ -+ WPA_PUT_BE16(pos, TLS_VERSION); -+ pos += 2; -+ /* Random random: uint32 gmt_unix_time, opaque random_bytes */ -+ os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN); -+ pos += TLS_RANDOM_LEN; -+ /* SessionID session_id */ -+ *pos++ = conn->session_id_len; -+ os_memcpy(pos, conn->session_id, conn->session_id_len); -+ pos += conn->session_id_len; -+ /* CipherSuite cipher_suite */ -+ WPA_PUT_BE16(pos, conn->cipher_suite); -+ pos += 2; -+ /* CompressionMethod compression_method */ -+ *pos++ = TLS_COMPRESSION_NULL; -+ -+ if (conn->session_ticket && conn->session_ticket_cb) { -+ int res = conn->session_ticket_cb( -+ conn->session_ticket_cb_ctx, -+ conn->session_ticket, conn->session_ticket_len, -+ conn->client_random, conn->server_random, -+ conn->master_secret); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback " -+ "indicated failure"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_HANDSHAKE_FAILURE); -+ return -1; -+ } -+ conn->use_session_ticket = res; -+ -+ if (conn->use_session_ticket) { -+ if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to " -+ "derive keys"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ } -+ -+ /* -+ * RFC 4507 specifies that server would include an empty -+ * SessionTicket extension in ServerHello and a -+ * NewSessionTicket message after the ServerHello. However, -+ * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket -+ * extension at the moment, does not use such extensions. -+ * -+ * TODO: Add support for configuring RFC 4507 behavior and make -+ * EAP-FAST disable it. -+ */ -+ } -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tls_write_server_certificate(struct tlsv1_server *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start; -+ size_t rlen; -+ struct x509_certificate *cert; -+ const struct tls_cipher_suite *suite; -+ -+ suite = tls_get_cipher_suite(conn->rl.cipher_suite); -+ if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when " -+ "using anonymous DH"); -+ return 0; -+ } -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ /* body - Certificate */ -+ /* uint24 length (to be filled) */ -+ cert_start = pos; -+ pos += 3; -+ cert = conn->cred->cert; -+ while (cert) { -+ if (pos + 3 + cert->cert_len > end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space " -+ "for Certificate (cert_len=%lu left=%lu)", -+ (unsigned long) cert->cert_len, -+ (unsigned long) (end - pos)); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ WPA_PUT_BE24(pos, cert->cert_len); -+ pos += 3; -+ os_memcpy(pos, cert->cert_start, cert->cert_len); -+ pos += cert->cert_len; -+ -+ if (x509_certificate_self_signed(cert)) -+ break; -+ cert = x509_certificate_get_subject(conn->cred->trusted_certs, -+ &cert->issuer); -+ } -+ if (cert == conn->cred->cert || cert == NULL) { -+ /* -+ * Server was not configured with all the needed certificates -+ * to form a full certificate chain. The client may fail to -+ * validate the chain unless it is configured with all the -+ * missing CA certificates. -+ */ -+ wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain " -+ "not configured - validation may fail"); -+ } -+ WPA_PUT_BE24(cert_start, pos - cert_start - 3); -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tls_write_server_key_exchange(struct tlsv1_server *conn, -+ u8 **msgpos, u8 *end) -+{ -+ tls_key_exchange keyx; -+ const struct tls_cipher_suite *suite; -+ u8 *pos, *rhdr, *hs_start, *hs_length; -+ size_t rlen; -+ u8 *dh_ys; -+ size_t dh_ys_len; -+ -+ suite = tls_get_cipher_suite(conn->rl.cipher_suite); -+ if (suite == NULL) -+ keyx = TLS_KEY_X_NULL; -+ else -+ keyx = suite->key_exchange; -+ -+ if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed"); -+ return 0; -+ } -+ -+ if (keyx != TLS_KEY_X_DH_anon) { -+ /* TODO? */ -+ wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet " -+ "supported with key exchange type %d", keyx); -+ return -1; -+ } -+ -+ if (conn->cred == NULL || conn->cred->dh_p == NULL || -+ conn->cred->dh_g == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for " -+ "ServerKeyExhcange"); -+ return -1; -+ } -+ -+ os_free(conn->dh_secret); -+ conn->dh_secret_len = conn->cred->dh_p_len; -+ conn->dh_secret = os_malloc(conn->dh_secret_len); -+ if (conn->dh_secret == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " -+ "memory for secret (Diffie-Hellman)"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random " -+ "data for Diffie-Hellman"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(conn->dh_secret); -+ conn->dh_secret = NULL; -+ return -1; -+ } -+ -+ if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > -+ 0) -+ conn->dh_secret[0] = 0; /* make sure secret < p */ -+ -+ pos = conn->dh_secret; -+ while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0) -+ pos++; -+ if (pos != conn->dh_secret) { -+ os_memmove(conn->dh_secret, pos, -+ conn->dh_secret_len - (pos - conn->dh_secret)); -+ conn->dh_secret_len -= pos - conn->dh_secret; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value", -+ conn->dh_secret, conn->dh_secret_len); -+ -+ /* Ys = g^secret mod p */ -+ dh_ys_len = conn->cred->dh_p_len; -+ dh_ys = os_malloc(dh_ys_len); -+ if (dh_ys == NULL) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for " -+ "Diffie-Hellman"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, -+ conn->dh_secret, conn->dh_secret_len, -+ conn->cred->dh_p, conn->cred->dh_p_len, -+ dh_ys, &dh_ys_len)) { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(dh_ys); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)", -+ dh_ys, dh_ys_len); -+ -+ /* -+ * struct { -+ * select (KeyExchangeAlgorithm) { -+ * case diffie_hellman: -+ * ServerDHParams params; -+ * Signature signed_params; -+ * case rsa: -+ * ServerRSAParams params; -+ * Signature signed_params; -+ * }; -+ * } ServerKeyExchange; -+ * -+ * struct { -+ * opaque dh_p<1..2^16-1>; -+ * opaque dh_g<1..2^16-1>; -+ * opaque dh_Ys<1..2^16-1>; -+ * } ServerDHParams; -+ */ -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ -+ /* body - ServerDHParams */ -+ /* dh_p */ -+ if (pos + 2 + conn->cred->dh_p_len > end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " -+ "dh_p"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(dh_ys); -+ return -1; -+ } -+ WPA_PUT_BE16(pos, conn->cred->dh_p_len); -+ pos += 2; -+ os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); -+ pos += conn->cred->dh_p_len; -+ -+ /* dh_g */ -+ if (pos + 2 + conn->cred->dh_g_len > end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " -+ "dh_g"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(dh_ys); -+ return -1; -+ } -+ WPA_PUT_BE16(pos, conn->cred->dh_g_len); -+ pos += 2; -+ os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len); -+ pos += conn->cred->dh_g_len; -+ -+ /* dh_Ys */ -+ if (pos + 2 + dh_ys_len > end) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " -+ "dh_Ys"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ os_free(dh_ys); -+ return -1; -+ } -+ WPA_PUT_BE16(pos, dh_ys_len); -+ pos += 2; -+ os_memcpy(pos, dh_ys, dh_ys_len); -+ pos += dh_ys_len; -+ os_free(dh_ys); -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tls_write_server_certificate_request(struct tlsv1_server *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length; -+ size_t rlen; -+ -+ if (!conn->verify_peer) { -+ wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed"); -+ return 0; -+ } -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ /* body - CertificateRequest */ -+ -+ /* -+ * enum { -+ * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), -+ * (255) -+ * } ClientCertificateType; -+ * ClientCertificateType certificate_types<1..2^8-1> -+ */ -+ *pos++ = 1; -+ *pos++ = 1; /* rsa_sign */ -+ -+ /* -+ * opaque DistinguishedName<1..2^16-1> -+ * DistinguishedName certificate_authorities<3..2^16-1> -+ */ -+ /* TODO: add support for listing DNs for trusted CAs */ -+ WPA_PUT_BE16(pos, 0); -+ pos += 2; -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tls_write_server_hello_done(struct tlsv1_server *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length; -+ size_t rlen; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ /* body - ServerHelloDone (empty) */ -+ -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ pos = rhdr + rlen; -+ -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr; -+ size_t rlen; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec"); -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ *pos = TLS_CHANGE_CIPHER_SPEC; -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC, -+ rhdr, end - rhdr, 1, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ if (tlsv1_record_change_write_cipher(&conn->rl) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for " -+ "record layer"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ *msgpos = rhdr + rlen; -+ -+ return 0; -+} -+ -+ -+static int tls_write_server_finished(struct tlsv1_server *conn, -+ u8 **msgpos, u8 *end) -+{ -+ u8 *pos, *rhdr, *hs_start, *hs_length; -+ size_t rlen, hlen; -+ u8 verify_data[TLS_VERIFY_DATA_LEN]; -+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN]; -+ -+ pos = *msgpos; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send Finished"); -+ -+ /* Encrypted Handshake Message: Finished */ -+ -+ hlen = MD5_MAC_LEN; -+ if (conn->verify.md5_server == NULL || -+ crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) { -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ conn->verify.md5_server = NULL; -+ crypto_hash_finish(conn->verify.sha1_server, NULL, NULL); -+ conn->verify.sha1_server = NULL; -+ return -1; -+ } -+ conn->verify.md5_server = NULL; -+ hlen = SHA1_MAC_LEN; -+ if (conn->verify.sha1_server == NULL || -+ crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN, -+ &hlen) < 0) { -+ conn->verify.sha1_server = NULL; -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ conn->verify.sha1_server = NULL; -+ -+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN, -+ "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN, -+ verify_data, TLS_VERIFY_DATA_LEN)) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", -+ verify_data, TLS_VERIFY_DATA_LEN); -+ -+ rhdr = pos; -+ pos += TLS_RECORD_HEADER_LEN; -+ /* Handshake */ -+ hs_start = pos; -+ /* HandshakeType msg_type */ -+ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED; -+ /* uint24 length (to be filled) */ -+ hs_length = pos; -+ pos += 3; -+ os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN); -+ pos += TLS_VERIFY_DATA_LEN; -+ WPA_PUT_BE24(hs_length, pos - hs_length - 3); -+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start); -+ -+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE, -+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) { -+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record"); -+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, -+ TLS_ALERT_INTERNAL_ERROR); -+ return -1; -+ } -+ -+ pos = rhdr + rlen; -+ -+ *msgpos = pos; -+ -+ return 0; -+} -+ -+ -+static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len) -+{ -+ u8 *msg, *end, *pos; -+ size_t msglen; -+ -+ *out_len = 0; -+ -+ msglen = 1000 + tls_server_cert_chain_der_len(conn); -+ -+ msg = os_malloc(msglen); -+ if (msg == NULL) -+ return NULL; -+ -+ pos = msg; -+ end = msg + msglen; -+ -+ if (tls_write_server_hello(conn, &pos, end) < 0) { -+ os_free(msg); -+ return NULL; -+ } -+ -+ if (conn->use_session_ticket) { -+ /* Abbreviated handshake using session ticket; RFC 4507 */ -+ if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || -+ tls_write_server_finished(conn, &pos, end) < 0) { -+ os_free(msg); -+ return NULL; -+ } -+ -+ *out_len = pos - msg; -+ -+ conn->state = CHANGE_CIPHER_SPEC; -+ -+ return msg; -+ } -+ -+ /* Full handshake */ -+ if (tls_write_server_certificate(conn, &pos, end) < 0 || -+ tls_write_server_key_exchange(conn, &pos, end) < 0 || -+ tls_write_server_certificate_request(conn, &pos, end) < 0 || -+ tls_write_server_hello_done(conn, &pos, end) < 0) { -+ os_free(msg); -+ return NULL; -+ } -+ -+ *out_len = pos - msg; -+ -+ conn->state = CLIENT_CERTIFICATE; -+ -+ return msg; -+} -+ -+ -+static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn, -+ size_t *out_len) -+{ -+ u8 *msg, *end, *pos; -+ -+ *out_len = 0; -+ -+ msg = os_malloc(1000); -+ if (msg == NULL) -+ return NULL; -+ -+ pos = msg; -+ end = msg + 1000; -+ -+ if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 || -+ tls_write_server_finished(conn, &pos, end) < 0) { -+ os_free(msg); -+ return NULL; -+ } -+ -+ *out_len = pos - msg; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully"); -+ conn->state = ESTABLISHED; -+ -+ return msg; -+} -+ -+ -+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len) -+{ -+ switch (conn->state) { -+ case SERVER_HELLO: -+ return tls_send_server_hello(conn, out_len); -+ case SERVER_CHANGE_CIPHER_SPEC: -+ return tls_send_change_cipher_spec(conn, out_len); -+ default: -+ if (conn->state == ESTABLISHED && conn->use_session_ticket) { -+ /* Abbreviated handshake was already completed. */ -+ return NULL; -+ } -+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while " -+ "generating reply", conn->state); -+ return NULL; -+ } -+} -+ -+ -+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, -+ u8 description, size_t *out_len) -+{ -+ u8 *alert, *pos, *length; -+ -+ wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description); -+ *out_len = 0; -+ -+ alert = os_malloc(10); -+ if (alert == NULL) -+ return NULL; -+ -+ pos = alert; -+ -+ /* TLSPlaintext */ -+ /* ContentType type */ -+ *pos++ = TLS_CONTENT_TYPE_ALERT; -+ /* ProtocolVersion version */ -+ WPA_PUT_BE16(pos, TLS_VERSION); -+ pos += 2; -+ /* uint16 length (to be filled) */ -+ length = pos; -+ pos += 2; -+ /* opaque fragment[TLSPlaintext.length] */ -+ -+ /* Alert */ -+ /* AlertLevel level */ -+ *pos++ = level; -+ /* AlertDescription description */ -+ *pos++ = description; -+ -+ WPA_PUT_BE16(length, pos - length - 2); -+ *out_len = pos - alert; -+ -+ return alert; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.c -new file mode 100644 -index 0000000000000..bc93df6837873 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.c -@@ -0,0 +1,1985 @@ -+/* -+ * X.509v3 certificate parsing and processing (RFC 3280 profile) -+ * Copyright (c) 2006-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "crypto/crypto.h" -+#include "asn1.h" -+#include "x509v3.h" -+ -+ -+static void x509_free_name(struct x509_name *name) -+{ -+ size_t i; -+ -+ for (i = 0; i < name->num_attr; i++) { -+ os_free(name->attr[i].value); -+ name->attr[i].value = NULL; -+ name->attr[i].type = X509_NAME_ATTR_NOT_USED; -+ } -+ name->num_attr = 0; -+ os_free(name->email); -+ name->email = NULL; -+ -+ os_free(name->alt_email); -+ os_free(name->dns); -+ os_free(name->uri); -+ os_free(name->ip); -+ name->alt_email = name->dns = name->uri = NULL; -+ name->ip = NULL; -+ name->ip_len = 0; -+ os_memset(&name->rid, 0, sizeof(name->rid)); -+} -+ -+ -+/** -+ * x509_certificate_free - Free an X.509 certificate -+ * @cert: Certificate to be freed -+ */ -+void x509_certificate_free(struct x509_certificate *cert) -+{ -+ if (cert == NULL) -+ return; -+ if (cert->next) { -+ wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p " -+ "was still on a list (next=%p)\n", -+ cert, cert->next); -+ } -+ x509_free_name(&cert->issuer); -+ x509_free_name(&cert->subject); -+ os_free(cert->public_key); -+ os_free(cert->sign_value); -+ os_free(cert); -+} -+ -+ -+/** -+ * x509_certificate_free - Free an X.509 certificate chain -+ * @cert: Pointer to the first certificate in the chain -+ */ -+void x509_certificate_chain_free(struct x509_certificate *cert) -+{ -+ struct x509_certificate *next; -+ -+ while (cert) { -+ next = cert->next; -+ cert->next = NULL; -+ x509_certificate_free(cert); -+ cert = next; -+ } -+} -+ -+ -+static int x509_whitespace(char c) -+{ -+ return c == ' ' || c == '\t'; -+} -+ -+ -+static void x509_str_strip_whitespace(char *a) -+{ -+ char *ipos, *opos; -+ int remove_whitespace = 1; -+ -+ ipos = opos = a; -+ -+ while (*ipos) { -+ if (remove_whitespace && x509_whitespace(*ipos)) -+ ipos++; -+ else { -+ remove_whitespace = x509_whitespace(*ipos); -+ *opos++ = *ipos++; -+ } -+ } -+ -+ *opos-- = '\0'; -+ if (opos > a && x509_whitespace(*opos)) -+ *opos = '\0'; -+} -+ -+ -+static int x509_str_compare(const char *a, const char *b) -+{ -+ char *aa, *bb; -+ int ret; -+ -+ if (!a && b) -+ return -1; -+ if (a && !b) -+ return 1; -+ if (!a && !b) -+ return 0; -+ -+ aa = os_strdup(a); -+ bb = os_strdup(b); -+ -+ if (aa == NULL || bb == NULL) { -+ os_free(aa); -+ os_free(bb); -+ return os_strcasecmp(a, b); -+ } -+ -+ x509_str_strip_whitespace(aa); -+ x509_str_strip_whitespace(bb); -+ -+ ret = os_strcasecmp(aa, bb); -+ -+ os_free(aa); -+ os_free(bb); -+ -+ return ret; -+} -+ -+ -+/** -+ * x509_name_compare - Compare X.509 certificate names -+ * @a: Certificate name -+ * @b: Certificate name -+ * Returns: <0, 0, or >0 based on whether a is less than, equal to, or -+ * greater than b -+ */ -+int x509_name_compare(struct x509_name *a, struct x509_name *b) -+{ -+ int res; -+ size_t i; -+ -+ if (!a && b) -+ return -1; -+ if (a && !b) -+ return 1; -+ if (!a && !b) -+ return 0; -+ if (a->num_attr < b->num_attr) -+ return -1; -+ if (a->num_attr > b->num_attr) -+ return 1; -+ -+ for (i = 0; i < a->num_attr; i++) { -+ if (a->attr[i].type < b->attr[i].type) -+ return -1; -+ if (a->attr[i].type > b->attr[i].type) -+ return -1; -+ res = x509_str_compare(a->attr[i].value, b->attr[i].value); -+ if (res) -+ return res; -+ } -+ res = x509_str_compare(a->email, b->email); -+ if (res) -+ return res; -+ -+ return 0; -+} -+ -+ -+static int x509_parse_algorithm_identifier( -+ const u8 *buf, size_t len, -+ struct x509_algorithm_identifier *id, const u8 **next) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end; -+ -+ /* -+ * AlgorithmIdentifier ::= SEQUENCE { -+ * algorithm OBJECT IDENTIFIER, -+ * parameters ANY DEFINED BY algorithm OPTIONAL -+ * } -+ */ -+ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " -+ "(AlgorithmIdentifier) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ end = pos + hdr.length; -+ -+ if (end > buf + len) -+ return -1; -+ -+ *next = end; -+ -+ if (asn1_get_oid(pos, end - pos, &id->oid, &pos)) -+ return -1; -+ -+ /* TODO: optional parameters */ -+ -+ return 0; -+} -+ -+ -+static int x509_parse_public_key(const u8 *buf, size_t len, -+ struct x509_certificate *cert, -+ const u8 **next) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end; -+ -+ /* -+ * SubjectPublicKeyInfo ::= SEQUENCE { -+ * algorithm AlgorithmIdentifier, -+ * subjectPublicKey BIT STRING -+ * } -+ */ -+ -+ pos = buf; -+ end = buf + len; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " -+ "(SubjectPublicKeyInfo) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ -+ if (pos + hdr.length > end) -+ return -1; -+ end = pos + hdr.length; -+ *next = end; -+ -+ if (x509_parse_algorithm_identifier(pos, end - pos, -+ &cert->public_key_alg, &pos)) -+ return -1; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_BITSTRING) { -+ wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " -+ "(subjectPublicKey) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ if (hdr.length < 1) -+ return -1; -+ pos = hdr.payload; -+ if (*pos) { -+ wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", -+ *pos); -+ /* -+ * TODO: should this be rejected? X.509 certificates are -+ * unlikely to use such a construction. Now we would end up -+ * including the extra bits in the buffer which may also be -+ * ok. -+ */ -+ } -+ os_free(cert->public_key); -+ cert->public_key = os_malloc(hdr.length - 1); -+ if (cert->public_key == NULL) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " -+ "public key"); -+ return -1; -+ } -+ os_memcpy(cert->public_key, pos + 1, hdr.length - 1); -+ cert->public_key_len = hdr.length - 1; -+ wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey", -+ cert->public_key, cert->public_key_len); -+ -+ return 0; -+} -+ -+ -+static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, -+ const u8 **next) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; -+ struct asn1_oid oid; -+ char *val; -+ -+ /* -+ * Name ::= CHOICE { RDNSequence } -+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName -+ * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue -+ * AttributeTypeAndValue ::= SEQUENCE { -+ * type AttributeType, -+ * value AttributeValue -+ * } -+ * AttributeType ::= OBJECT IDENTIFIER -+ * AttributeValue ::= ANY DEFINED BY AttributeType -+ */ -+ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " -+ "(Name / RDNSequencer) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ -+ if (pos + hdr.length > buf + len) -+ return -1; -+ -+ end = *next = pos + hdr.length; -+ -+ while (pos < end) { -+ enum x509_name_attr_type type; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SET) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SET " -+ "(RelativeDistinguishedName) - found class " -+ "%d tag 0x%x", hdr.class, hdr.tag); -+ x509_free_name(name); -+ return -1; -+ } -+ -+ set_pos = hdr.payload; -+ pos = set_end = hdr.payload + hdr.length; -+ -+ if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " -+ "(AttributeTypeAndValue) - found class %d " -+ "tag 0x%x", hdr.class, hdr.tag); -+ x509_free_name(name); -+ return -1; -+ } -+ -+ seq_pos = hdr.payload; -+ seq_end = hdr.payload + hdr.length; -+ -+ if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) { -+ x509_free_name(name); -+ return -1; -+ } -+ -+ if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to parse " -+ "AttributeValue"); -+ x509_free_name(name); -+ return -1; -+ } -+ -+ /* RFC 3280: -+ * MUST: country, organization, organizational-unit, -+ * distinguished name qualifier, state or province name, -+ * common name, serial number. -+ * SHOULD: locality, title, surname, given name, initials, -+ * pseudonym, generation qualifier. -+ * MUST: domainComponent (RFC 2247). -+ */ -+ type = X509_NAME_ATTR_NOT_USED; -+ if (oid.len == 4 && -+ oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) { -+ /* id-at ::= 2.5.4 */ -+ switch (oid.oid[3]) { -+ case 3: -+ /* commonName */ -+ type = X509_NAME_ATTR_CN; -+ break; -+ case 6: -+ /* countryName */ -+ type = X509_NAME_ATTR_C; -+ break; -+ case 7: -+ /* localityName */ -+ type = X509_NAME_ATTR_L; -+ break; -+ case 8: -+ /* stateOrProvinceName */ -+ type = X509_NAME_ATTR_ST; -+ break; -+ case 10: -+ /* organizationName */ -+ type = X509_NAME_ATTR_O; -+ break; -+ case 11: -+ /* organizationalUnitName */ -+ type = X509_NAME_ATTR_OU; -+ break; -+ } -+ } else if (oid.len == 7 && -+ oid.oid[0] == 1 && oid.oid[1] == 2 && -+ oid.oid[2] == 840 && oid.oid[3] == 113549 && -+ oid.oid[4] == 1 && oid.oid[5] == 9 && -+ oid.oid[6] == 1) { -+ /* 1.2.840.113549.1.9.1 - e-mailAddress */ -+ os_free(name->email); -+ name->email = os_malloc(hdr.length + 1); -+ if (name->email == NULL) { -+ x509_free_name(name); -+ return -1; -+ } -+ os_memcpy(name->email, hdr.payload, hdr.length); -+ name->email[hdr.length] = '\0'; -+ continue; -+ } else if (oid.len == 7 && -+ oid.oid[0] == 0 && oid.oid[1] == 9 && -+ oid.oid[2] == 2342 && oid.oid[3] == 19200300 && -+ oid.oid[4] == 100 && oid.oid[5] == 1 && -+ oid.oid[6] == 25) { -+ /* 0.9.2342.19200300.100.1.25 - domainComponent */ -+ type = X509_NAME_ATTR_DC; -+ } -+ -+ if (type == X509_NAME_ATTR_NOT_USED) { -+ wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID", -+ (u8 *) oid.oid, -+ oid.len * sizeof(oid.oid[0])); -+ wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data", -+ hdr.payload, hdr.length); -+ continue; -+ } -+ -+ if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) { -+ wpa_printf(MSG_INFO, "X509: Too many Name attributes"); -+ x509_free_name(name); -+ return -1; -+ } -+ -+ val = os_malloc(hdr.length + 1); -+ if (val == NULL) { -+ x509_free_name(name); -+ return -1; -+ } -+ os_memcpy(val, hdr.payload, hdr.length); -+ val[hdr.length] = '\0'; -+ if (os_strlen(val) != hdr.length) { -+ wpa_printf(MSG_INFO, "X509: Reject certificate with " -+ "embedded NUL byte in a string (%s[NUL])", -+ val); -+ x509_free_name(name); -+ return -1; -+ } -+ -+ name->attr[name->num_attr].type = type; -+ name->attr[name->num_attr].value = val; -+ name->num_attr++; -+ } -+ -+ return 0; -+} -+ -+ -+static char * x509_name_attr_str(enum x509_name_attr_type type) -+{ -+ switch (type) { -+ case X509_NAME_ATTR_NOT_USED: -+ return "[N/A]"; -+ case X509_NAME_ATTR_DC: -+ return "DC"; -+ case X509_NAME_ATTR_CN: -+ return "CN"; -+ case X509_NAME_ATTR_C: -+ return "C"; -+ case X509_NAME_ATTR_L: -+ return "L"; -+ case X509_NAME_ATTR_ST: -+ return "ST"; -+ case X509_NAME_ATTR_O: -+ return "O"; -+ case X509_NAME_ATTR_OU: -+ return "OU"; -+ } -+ return "?"; -+} -+ -+ -+/** -+ * x509_name_string - Convert an X.509 certificate name into a string -+ * @name: Name to convert -+ * @buf: Buffer for the string -+ * @len: Maximum buffer length -+ */ -+void x509_name_string(struct x509_name *name, char *buf, size_t len) -+{ -+ char *pos, *end; -+ int ret; -+ size_t i; -+ -+ if (len == 0) -+ return; -+ -+ pos = buf; -+ end = buf + len; -+ -+ for (i = 0; i < name->num_attr; i++) { -+ ret = os_snprintf(pos, end - pos, "%s=%s, ", -+ x509_name_attr_str(name->attr[i].type), -+ name->attr[i].value); -+ if (ret < 0 || ret >= end - pos) -+ goto done; -+ pos += ret; -+ } -+ -+ if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') { -+ pos--; -+ *pos = '\0'; -+ pos--; -+ *pos = '\0'; -+ } -+ -+ if (name->email) { -+ ret = os_snprintf(pos, end - pos, "/emailAddress=%s", -+ name->email); -+ if (ret < 0 || ret >= end - pos) -+ goto done; -+ pos += ret; -+ } -+ -+done: -+ end[-1] = '\0'; -+} -+ -+ -+static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, -+ os_time_t *val) -+{ -+ const char *pos; -+ int year, month, day, hour, min, sec; -+ -+ /* -+ * Time ::= CHOICE { -+ * utcTime UTCTime, -+ * generalTime GeneralizedTime -+ * } -+ * -+ * UTCTime: YYMMDDHHMMSSZ -+ * GeneralizedTime: YYYYMMDDHHMMSSZ -+ */ -+ -+ pos = (const char *) buf; -+ -+ switch (asn1_tag) { -+ case ASN1_TAG_UTCTIME: -+ if (len != 13 || buf[12] != 'Z') { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " -+ "UTCTime format", buf, len); -+ return -1; -+ } -+ if (sscanf(pos, "%02d", &year) != 1) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " -+ "UTCTime year", buf, len); -+ return -1; -+ } -+ if (year < 50) -+ year += 2000; -+ else -+ year += 1900; -+ pos += 2; -+ break; -+ case ASN1_TAG_GENERALIZEDTIME: -+ if (len != 15 || buf[14] != 'Z') { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " -+ "GeneralizedTime format", buf, len); -+ return -1; -+ } -+ if (sscanf(pos, "%04d", &year) != 1) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " -+ "GeneralizedTime year", buf, len); -+ return -1; -+ } -+ pos += 4; -+ break; -+ default: -+ wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or " -+ "GeneralizedTime - found tag 0x%x", asn1_tag); -+ return -1; -+ } -+ -+ if (sscanf(pos, "%02d", &month) != 1) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " -+ "(month)", buf, len); -+ return -1; -+ } -+ pos += 2; -+ -+ if (sscanf(pos, "%02d", &day) != 1) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " -+ "(day)", buf, len); -+ return -1; -+ } -+ pos += 2; -+ -+ if (sscanf(pos, "%02d", &hour) != 1) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " -+ "(hour)", buf, len); -+ return -1; -+ } -+ pos += 2; -+ -+ if (sscanf(pos, "%02d", &min) != 1) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " -+ "(min)", buf, len); -+ return -1; -+ } -+ pos += 2; -+ -+ if (sscanf(pos, "%02d", &sec) != 1) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " -+ "(sec)", buf, len); -+ return -1; -+ } -+ -+ if (os_mktime(year, month, day, hour, min, sec, val) < 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time", -+ buf, len); -+ if (year < 1970) { -+ /* -+ * At least some test certificates have been configured -+ * to use dates prior to 1970. Set the date to -+ * beginning of 1970 to handle these case. -+ */ -+ wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - " -+ "assume epoch as the time", year); -+ *val = 0; -+ return 0; -+ } -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int x509_parse_validity(const u8 *buf, size_t len, -+ struct x509_certificate *cert, const u8 **next) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos; -+ size_t plen; -+ -+ /* -+ * Validity ::= SEQUENCE { -+ * notBefore Time, -+ * notAfter Time -+ * } -+ * -+ * RFC 3280, 4.1.2.5: -+ * CAs conforming to this profile MUST always encode certificate -+ * validity dates through the year 2049 as UTCTime; certificate -+ * validity dates in 2050 or later MUST be encoded as GeneralizedTime. -+ */ -+ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " -+ "(Validity) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ plen = hdr.length; -+ -+ if (pos + plen > buf + len) -+ return -1; -+ -+ *next = pos + plen; -+ -+ if (asn1_get_next(pos, plen, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ x509_parse_time(hdr.payload, hdr.length, hdr.tag, -+ &cert->not_before) < 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore " -+ "Time", hdr.payload, hdr.length); -+ return -1; -+ } -+ -+ pos = hdr.payload + hdr.length; -+ plen = *next - pos; -+ -+ if (asn1_get_next(pos, plen, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ x509_parse_time(hdr.payload, hdr.length, hdr.tag, -+ &cert->not_after) < 0) { -+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter " -+ "Time", hdr.payload, hdr.length); -+ return -1; -+ } -+ -+ wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu", -+ (unsigned long) cert->not_before, -+ (unsigned long) cert->not_after); -+ -+ return 0; -+} -+ -+ -+static int x509_id_ce_oid(struct asn1_oid *oid) -+{ -+ /* id-ce arc from X.509 for standard X.509v3 extensions */ -+ return oid->len >= 4 && -+ oid->oid[0] == 2 /* joint-iso-ccitt */ && -+ oid->oid[1] == 5 /* ds */ && -+ oid->oid[2] == 29 /* id-ce */; -+} -+ -+ -+static int x509_parse_ext_key_usage(struct x509_certificate *cert, -+ const u8 *pos, size_t len) -+{ -+ struct asn1_hdr hdr; -+ -+ /* -+ * KeyUsage ::= BIT STRING { -+ * digitalSignature (0), -+ * nonRepudiation (1), -+ * keyEncipherment (2), -+ * dataEncipherment (3), -+ * keyAgreement (4), -+ * keyCertSign (5), -+ * cRLSign (6), -+ * encipherOnly (7), -+ * decipherOnly (8) } -+ */ -+ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_BITSTRING || -+ hdr.length < 1) { -+ wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in " -+ "KeyUsage; found %d tag 0x%x len %d", -+ hdr.class, hdr.tag, hdr.length); -+ return -1; -+ } -+ -+ cert->extensions_present |= X509_EXT_KEY_USAGE; -+ cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length); -+ -+ wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage); -+ -+ return 0; -+} -+ -+ -+static int x509_parse_ext_basic_constraints(struct x509_certificate *cert, -+ const u8 *pos, size_t len) -+{ -+ struct asn1_hdr hdr; -+ unsigned long value; -+ size_t left; -+ -+ /* -+ * BasicConstraints ::= SEQUENCE { -+ * cA BOOLEAN DEFAULT FALSE, -+ * pathLenConstraint INTEGER (0..MAX) OPTIONAL } -+ */ -+ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " -+ "BasicConstraints; found %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS; -+ -+ if (hdr.length == 0) -+ return 0; -+ -+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to parse " -+ "BasicConstraints"); -+ return -1; -+ } -+ -+ if (hdr.tag == ASN1_TAG_BOOLEAN) { -+ if (hdr.length != 1) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected " -+ "Boolean length (%u) in BasicConstraints", -+ hdr.length); -+ return -1; -+ } -+ cert->ca = hdr.payload[0]; -+ -+ if (hdr.payload + hdr.length == pos + len) { -+ wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d", -+ cert->ca); -+ return 0; -+ } -+ -+ if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length, -+ &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to parse " -+ "BasicConstraints"); -+ return -1; -+ } -+ } -+ -+ if (hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in " -+ "BasicConstraints; found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ pos = hdr.payload; -+ left = hdr.length; -+ value = 0; -+ while (left) { -+ value <<= 8; -+ value |= *pos++; -+ left--; -+ } -+ -+ cert->path_len_constraint = value; -+ cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT; -+ -+ wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d " -+ "pathLenConstraint=%lu", -+ cert->ca, cert->path_len_constraint); -+ -+ return 0; -+} -+ -+ -+static int x509_parse_alt_name_rfc8222(struct x509_name *name, -+ const u8 *pos, size_t len) -+{ -+ /* rfc822Name IA5String */ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len); -+ os_free(name->alt_email); -+ name->alt_email = os_zalloc(len + 1); -+ if (name->alt_email == NULL) -+ return -1; -+ os_memcpy(name->alt_email, pos, len); -+ if (os_strlen(name->alt_email) != len) { -+ wpa_printf(MSG_INFO, "X509: Reject certificate with " -+ "embedded NUL byte in rfc822Name (%s[NUL])", -+ name->alt_email); -+ os_free(name->alt_email); -+ name->alt_email = NULL; -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int x509_parse_alt_name_dns(struct x509_name *name, -+ const u8 *pos, size_t len) -+{ -+ /* dNSName IA5String */ -+ wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len); -+ os_free(name->dns); -+ name->dns = os_zalloc(len + 1); -+ if (name->dns == NULL) -+ return -1; -+ os_memcpy(name->dns, pos, len); -+ if (os_strlen(name->dns) != len) { -+ wpa_printf(MSG_INFO, "X509: Reject certificate with " -+ "embedded NUL byte in dNSName (%s[NUL])", -+ name->dns); -+ os_free(name->dns); -+ name->dns = NULL; -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int x509_parse_alt_name_uri(struct x509_name *name, -+ const u8 *pos, size_t len) -+{ -+ /* uniformResourceIdentifier IA5String */ -+ wpa_hexdump_ascii(MSG_MSGDUMP, -+ "X509: altName - uniformResourceIdentifier", -+ pos, len); -+ os_free(name->uri); -+ name->uri = os_zalloc(len + 1); -+ if (name->uri == NULL) -+ return -1; -+ os_memcpy(name->uri, pos, len); -+ if (os_strlen(name->uri) != len) { -+ wpa_printf(MSG_INFO, "X509: Reject certificate with " -+ "embedded NUL byte in uniformResourceIdentifier " -+ "(%s[NUL])", name->uri); -+ os_free(name->uri); -+ name->uri = NULL; -+ return -1; -+ } -+ return 0; -+} -+ -+ -+static int x509_parse_alt_name_ip(struct x509_name *name, -+ const u8 *pos, size_t len) -+{ -+ /* iPAddress OCTET STRING */ -+ wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len); -+ os_free(name->ip); -+ name->ip = os_malloc(len); -+ if (name->ip == NULL) -+ return -1; -+ os_memcpy(name->ip, pos, len); -+ name->ip_len = len; -+ return 0; -+} -+ -+ -+static int x509_parse_alt_name_rid(struct x509_name *name, -+ const u8 *pos, size_t len) -+{ -+ char buf[80]; -+ -+ /* registeredID OBJECT IDENTIFIER */ -+ if (asn1_parse_oid(pos, len, &name->rid) < 0) -+ return -1; -+ -+ asn1_oid_to_str(&name->rid, buf, sizeof(buf)); -+ wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf); -+ -+ return 0; -+} -+ -+ -+static int x509_parse_ext_alt_name(struct x509_name *name, -+ const u8 *pos, size_t len) -+{ -+ struct asn1_hdr hdr; -+ const u8 *p, *end; -+ -+ /* -+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName -+ * -+ * GeneralName ::= CHOICE { -+ * otherName [0] OtherName, -+ * rfc822Name [1] IA5String, -+ * dNSName [2] IA5String, -+ * x400Address [3] ORAddress, -+ * directoryName [4] Name, -+ * ediPartyName [5] EDIPartyName, -+ * uniformResourceIdentifier [6] IA5String, -+ * iPAddress [7] OCTET STRING, -+ * registeredID [8] OBJECT IDENTIFIER } -+ * -+ * OtherName ::= SEQUENCE { -+ * type-id OBJECT IDENTIFIER, -+ * value [0] EXPLICIT ANY DEFINED BY type-id } -+ * -+ * EDIPartyName ::= SEQUENCE { -+ * nameAssigner [0] DirectoryString OPTIONAL, -+ * partyName [1] DirectoryString } -+ */ -+ -+ for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) { -+ int res; -+ -+ if (asn1_get_next(p, end - p, &hdr) < 0) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to parse " -+ "SubjectAltName item"); -+ return -1; -+ } -+ -+ if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) -+ continue; -+ -+ switch (hdr.tag) { -+ case 1: -+ res = x509_parse_alt_name_rfc8222(name, hdr.payload, -+ hdr.length); -+ break; -+ case 2: -+ res = x509_parse_alt_name_dns(name, hdr.payload, -+ hdr.length); -+ break; -+ case 6: -+ res = x509_parse_alt_name_uri(name, hdr.payload, -+ hdr.length); -+ break; -+ case 7: -+ res = x509_parse_alt_name_ip(name, hdr.payload, -+ hdr.length); -+ break; -+ case 8: -+ res = x509_parse_alt_name_rid(name, hdr.payload, -+ hdr.length); -+ break; -+ case 0: /* TODO: otherName */ -+ case 3: /* TODO: x500Address */ -+ case 4: /* TODO: directoryName */ -+ case 5: /* TODO: ediPartyName */ -+ default: -+ res = 0; -+ break; -+ } -+ if (res < 0) -+ return res; -+ } -+ -+ return 0; -+} -+ -+ -+static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert, -+ const u8 *pos, size_t len) -+{ -+ struct asn1_hdr hdr; -+ -+ /* SubjectAltName ::= GeneralNames */ -+ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " -+ "SubjectAltName; found %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "X509: SubjectAltName"); -+ cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME; -+ -+ if (hdr.length == 0) -+ return 0; -+ -+ return x509_parse_ext_alt_name(&cert->subject, hdr.payload, -+ hdr.length); -+} -+ -+ -+static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert, -+ const u8 *pos, size_t len) -+{ -+ struct asn1_hdr hdr; -+ -+ /* IssuerAltName ::= GeneralNames */ -+ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " -+ "IssuerAltName; found %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "X509: IssuerAltName"); -+ cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME; -+ -+ if (hdr.length == 0) -+ return 0; -+ -+ return x509_parse_ext_alt_name(&cert->issuer, hdr.payload, -+ hdr.length); -+} -+ -+ -+static int x509_parse_extension_data(struct x509_certificate *cert, -+ struct asn1_oid *oid, -+ const u8 *pos, size_t len) -+{ -+ if (!x509_id_ce_oid(oid)) -+ return 1; -+ -+ /* TODO: add other extensions required by RFC 3280, Ch 4.2: -+ * certificate policies (section 4.2.1.5) -+ * name constraints (section 4.2.1.11) -+ * policy constraints (section 4.2.1.12) -+ * extended key usage (section 4.2.1.13) -+ * inhibit any-policy (section 4.2.1.15) -+ */ -+ switch (oid->oid[3]) { -+ case 15: /* id-ce-keyUsage */ -+ return x509_parse_ext_key_usage(cert, pos, len); -+ case 17: /* id-ce-subjectAltName */ -+ return x509_parse_ext_subject_alt_name(cert, pos, len); -+ case 18: /* id-ce-issuerAltName */ -+ return x509_parse_ext_issuer_alt_name(cert, pos, len); -+ case 19: /* id-ce-basicConstraints */ -+ return x509_parse_ext_basic_constraints(cert, pos, len); -+ default: -+ return 1; -+ } -+} -+ -+ -+static int x509_parse_extension(struct x509_certificate *cert, -+ const u8 *pos, size_t len, const u8 **next) -+{ -+ const u8 *end; -+ struct asn1_hdr hdr; -+ struct asn1_oid oid; -+ int critical_ext = 0, res; -+ char buf[80]; -+ -+ /* -+ * Extension ::= SEQUENCE { -+ * extnID OBJECT IDENTIFIER, -+ * critical BOOLEAN DEFAULT FALSE, -+ * extnValue OCTET STRING -+ * } -+ */ -+ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " -+ "Extensions: class %d tag 0x%x; expected SEQUENCE", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ *next = end = pos + hdr.length; -+ -+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for " -+ "Extension (expected OID)"); -+ return -1; -+ } -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ (hdr.tag != ASN1_TAG_BOOLEAN && -+ hdr.tag != ASN1_TAG_OCTETSTRING)) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " -+ "Extensions: class %d tag 0x%x; expected BOOLEAN " -+ "or OCTET STRING", hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ if (hdr.tag == ASN1_TAG_BOOLEAN) { -+ if (hdr.length != 1) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected " -+ "Boolean length (%u)", hdr.length); -+ return -1; -+ } -+ critical_ext = hdr.payload[0]; -+ pos = hdr.payload; -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ (hdr.class != ASN1_CLASS_UNIVERSAL && -+ hdr.class != ASN1_CLASS_PRIVATE) || -+ hdr.tag != ASN1_TAG_OCTETSTRING) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header " -+ "in Extensions: class %d tag 0x%x; " -+ "expected OCTET STRING", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ } -+ -+ asn1_oid_to_str(&oid, buf, sizeof(buf)); -+ wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d", -+ buf, critical_ext); -+ wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length); -+ -+ res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length); -+ if (res < 0) -+ return res; -+ if (res == 1 && critical_ext) { -+ wpa_printf(MSG_INFO, "X509: Unknown critical extension %s", -+ buf); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int x509_parse_extensions(struct x509_certificate *cert, -+ const u8 *pos, size_t len) -+{ -+ const u8 *end; -+ struct asn1_hdr hdr; -+ -+ /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */ -+ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data " -+ "for Extensions: class %d tag 0x%x; " -+ "expected SEQUENCE", hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ pos = hdr.payload; -+ end = pos + hdr.length; -+ -+ while (pos < end) { -+ if (x509_parse_extension(cert, pos, end - pos, &pos) -+ < 0) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int x509_parse_tbs_certificate(const u8 *buf, size_t len, -+ struct x509_certificate *cert, -+ const u8 **next) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end; -+ size_t left; -+ char sbuf[128]; -+ unsigned long value; -+ -+ /* tbsCertificate TBSCertificate ::= SEQUENCE */ -+ if (asn1_get_next(buf, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start " -+ "with a valid SEQUENCE - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ pos = hdr.payload; -+ end = *next = pos + hdr.length; -+ -+ /* -+ * version [0] EXPLICIT Version DEFAULT v1 -+ * Version ::= INTEGER { v1(0), v2(1), v3(2) } -+ */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0) -+ return -1; -+ pos = hdr.payload; -+ -+ if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) { -+ if (asn1_get_next(pos, end - pos, &hdr) < 0) -+ return -1; -+ -+ if (hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " -+ "version field - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ if (hdr.length != 1) { -+ wpa_printf(MSG_DEBUG, "X509: Unexpected version field " -+ "length %u (expected 1)", hdr.length); -+ return -1; -+ } -+ pos = hdr.payload; -+ left = hdr.length; -+ value = 0; -+ while (left) { -+ value <<= 8; -+ value |= *pos++; -+ left--; -+ } -+ -+ cert->version = value; -+ if (cert->version != X509_CERT_V1 && -+ cert->version != X509_CERT_V2 && -+ cert->version != X509_CERT_V3) { -+ wpa_printf(MSG_DEBUG, "X509: Unsupported version %d", -+ cert->version + 1); -+ return -1; -+ } -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0) -+ return -1; -+ } else -+ cert->version = X509_CERT_V1; -+ wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1); -+ -+ /* serialNumber CertificateSerialNumber ::= INTEGER */ -+ if (hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_INTEGER) { -+ wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " -+ "serialNumber; class=%d tag=0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ pos = hdr.payload; -+ left = hdr.length; -+ while (left) { -+ cert->serial_number <<= 8; -+ cert->serial_number |= *pos++; -+ left--; -+ } -+ wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number); -+ -+ /* signature AlgorithmIdentifier */ -+ if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature, -+ &pos)) -+ return -1; -+ -+ /* issuer Name */ -+ if (x509_parse_name(pos, end - pos, &cert->issuer, &pos)) -+ return -1; -+ x509_name_string(&cert->issuer, sbuf, sizeof(sbuf)); -+ wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf); -+ -+ /* validity Validity */ -+ if (x509_parse_validity(pos, end - pos, cert, &pos)) -+ return -1; -+ -+ /* subject Name */ -+ if (x509_parse_name(pos, end - pos, &cert->subject, &pos)) -+ return -1; -+ x509_name_string(&cert->subject, sbuf, sizeof(sbuf)); -+ wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf); -+ -+ /* subjectPublicKeyInfo SubjectPublicKeyInfo */ -+ if (x509_parse_public_key(pos, end - pos, cert, &pos)) -+ return -1; -+ -+ if (pos == end) -+ return 0; -+ -+ if (cert->version == X509_CERT_V1) -+ return 0; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { -+ wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" -+ " tag to parse optional tbsCertificate " -+ "field(s); parsed class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ -+ if (hdr.tag == 1) { -+ /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */ -+ wpa_printf(MSG_DEBUG, "X509: issuerUniqueID"); -+ /* TODO: parse UniqueIdentifier ::= BIT STRING */ -+ -+ if (hdr.payload + hdr.length == end) -+ return 0; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { -+ wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" -+ " tag to parse optional tbsCertificate " -+ "field(s); parsed class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ } -+ -+ if (hdr.tag == 2) { -+ /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */ -+ wpa_printf(MSG_DEBUG, "X509: subjectUniqueID"); -+ /* TODO: parse UniqueIdentifier ::= BIT STRING */ -+ -+ if (hdr.payload + hdr.length == end) -+ return 0; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { -+ wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" -+ " tag to parse optional tbsCertificate " -+ "field(s); parsed class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ return -1; -+ } -+ } -+ -+ if (hdr.tag != 3) { -+ wpa_printf(MSG_DEBUG, "X509: Ignored unexpected " -+ "Context-Specific tag %d in optional " -+ "tbsCertificate fields", hdr.tag); -+ return 0; -+ } -+ -+ /* extensions [3] EXPLICIT Extensions OPTIONAL */ -+ -+ if (cert->version != X509_CERT_V3) { -+ wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and " -+ "Extensions data which are only allowed for " -+ "version 3", cert->version + 1); -+ return -1; -+ } -+ -+ if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0) -+ return -1; -+ -+ pos = hdr.payload + hdr.length; -+ if (pos < end) { -+ wpa_hexdump(MSG_DEBUG, -+ "X509: Ignored extra tbsCertificate data", -+ pos, end - pos); -+ } -+ -+ return 0; -+} -+ -+ -+static int x509_rsadsi_oid(struct asn1_oid *oid) -+{ -+ return oid->len >= 4 && -+ oid->oid[0] == 1 /* iso */ && -+ oid->oid[1] == 2 /* member-body */ && -+ oid->oid[2] == 840 /* us */ && -+ oid->oid[3] == 113549 /* rsadsi */; -+} -+ -+ -+static int x509_pkcs_oid(struct asn1_oid *oid) -+{ -+ return oid->len >= 5 && -+ x509_rsadsi_oid(oid) && -+ oid->oid[4] == 1 /* pkcs */; -+} -+ -+ -+static int x509_digest_oid(struct asn1_oid *oid) -+{ -+ return oid->len >= 5 && -+ x509_rsadsi_oid(oid) && -+ oid->oid[4] == 2 /* digestAlgorithm */; -+} -+ -+ -+static int x509_sha1_oid(struct asn1_oid *oid) -+{ -+ return oid->len == 6 && -+ oid->oid[0] == 1 /* iso */ && -+ oid->oid[1] == 3 /* identified-organization */ && -+ oid->oid[2] == 14 /* oiw */ && -+ oid->oid[3] == 3 /* secsig */ && -+ oid->oid[4] == 2 /* algorithms */ && -+ oid->oid[5] == 26 /* id-sha1 */; -+} -+ -+ -+static int x509_sha256_oid(struct asn1_oid *oid) -+{ -+ return oid->len == 9 && -+ oid->oid[0] == 2 /* joint-iso-itu-t */ && -+ oid->oid[1] == 16 /* country */ && -+ oid->oid[2] == 840 /* us */ && -+ oid->oid[3] == 1 /* organization */ && -+ oid->oid[4] == 101 /* gov */ && -+ oid->oid[5] == 3 /* csor */ && -+ oid->oid[6] == 4 /* nistAlgorithm */ && -+ oid->oid[7] == 2 /* hashAlgs */ && -+ oid->oid[8] == 1 /* sha256 */; -+} -+ -+ -+/** -+ * x509_certificate_parse - Parse a X.509 certificate in DER format -+ * @buf: Pointer to the X.509 certificate in DER format -+ * @len: Buffer length -+ * Returns: Pointer to the parsed certificate or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned certificate by calling -+ * x509_certificate_free(). -+ */ -+struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len) -+{ -+ struct asn1_hdr hdr; -+ const u8 *pos, *end, *hash_start; -+ struct x509_certificate *cert; -+ -+ cert = os_zalloc(sizeof(*cert) + len); -+ if (cert == NULL) -+ return NULL; -+ os_memcpy(cert + 1, buf, len); -+ cert->cert_start = (u8 *) (cert + 1); -+ cert->cert_len = len; -+ -+ pos = buf; -+ end = buf + len; -+ -+ /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */ -+ -+ /* Certificate ::= SEQUENCE */ -+ if (asn1_get_next(pos, len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Certificate did not start with " -+ "a valid SEQUENCE - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ pos = hdr.payload; -+ -+ if (pos + hdr.length > end) { -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ -+ if (pos + hdr.length < end) { -+ wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER " -+ "encoded certificate", -+ pos + hdr.length, end - pos + hdr.length); -+ end = pos + hdr.length; -+ } -+ -+ hash_start = pos; -+ cert->tbs_cert_start = cert->cert_start + (hash_start - buf); -+ if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) { -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ cert->tbs_cert_len = pos - hash_start; -+ -+ /* signatureAlgorithm AlgorithmIdentifier */ -+ if (x509_parse_algorithm_identifier(pos, end - pos, -+ &cert->signature_alg, &pos)) { -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ -+ /* signatureValue BIT STRING */ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_BITSTRING) { -+ wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " -+ "(signatureValue) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ if (hdr.length < 1) { -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ pos = hdr.payload; -+ if (*pos) { -+ wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", -+ *pos); -+ /* PKCS #1 v1.5 10.2.1: -+ * It is an error if the length in bits of the signature S is -+ * not a multiple of eight. -+ */ -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ os_free(cert->sign_value); -+ cert->sign_value = os_malloc(hdr.length - 1); -+ if (cert->sign_value == NULL) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " -+ "signatureValue"); -+ x509_certificate_free(cert); -+ return NULL; -+ } -+ os_memcpy(cert->sign_value, pos + 1, hdr.length - 1); -+ cert->sign_value_len = hdr.length - 1; -+ wpa_hexdump(MSG_MSGDUMP, "X509: signature", -+ cert->sign_value, cert->sign_value_len); -+ -+ return cert; -+} -+ -+ -+/** -+ * x509_certificate_check_signature - Verify certificate signature -+ * @issuer: Issuer certificate -+ * @cert: Certificate to be verified -+ * Returns: 0 if cert has a valid signature that was signed by the issuer, -+ * -1 if not -+ */ -+int x509_certificate_check_signature(struct x509_certificate *issuer, -+ struct x509_certificate *cert) -+{ -+ struct crypto_public_key *pk; -+ u8 *data; -+ const u8 *pos, *end, *next, *da_end; -+ size_t data_len; -+ struct asn1_hdr hdr; -+ struct asn1_oid oid; -+ u8 hash[32]; -+ size_t hash_len; -+ -+ if (!x509_pkcs_oid(&cert->signature.oid) || -+ cert->signature.oid.len != 7 || -+ cert->signature.oid.oid[5] != 1 /* pkcs-1 */) { -+ wpa_printf(MSG_DEBUG, "X509: Unrecognized signature " -+ "algorithm"); -+ return -1; -+ } -+ -+ pk = crypto_public_key_import(issuer->public_key, -+ issuer->public_key_len); -+ if (pk == NULL) -+ return -1; -+ -+ data_len = cert->sign_value_len; -+ data = os_malloc(data_len); -+ if (data == NULL) { -+ crypto_public_key_free(pk); -+ return -1; -+ } -+ -+ if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value, -+ cert->sign_value_len, data, -+ &data_len) < 0) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature"); -+ crypto_public_key_free(pk); -+ os_free(data); -+ return -1; -+ } -+ crypto_public_key_free(pk); -+ -+ wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len); -+ -+ /* -+ * PKCS #1 v1.5, 10.1.2: -+ * -+ * DigestInfo ::= SEQUENCE { -+ * digestAlgorithm DigestAlgorithmIdentifier, -+ * digest Digest -+ * } -+ * -+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier -+ * -+ * Digest ::= OCTET STRING -+ * -+ */ -+ if (asn1_get_next(data, data_len, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " -+ "(DigestInfo) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ os_free(data); -+ return -1; -+ } -+ -+ pos = hdr.payload; -+ end = pos + hdr.length; -+ -+ /* -+ * X.509: -+ * AlgorithmIdentifier ::= SEQUENCE { -+ * algorithm OBJECT IDENTIFIER, -+ * parameters ANY DEFINED BY algorithm OPTIONAL -+ * } -+ */ -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_SEQUENCE) { -+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " -+ "(AlgorithmIdentifier) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ os_free(data); -+ return -1; -+ } -+ da_end = hdr.payload + hdr.length; -+ -+ if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { -+ wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm"); -+ os_free(data); -+ return -1; -+ } -+ -+ if (x509_sha1_oid(&oid)) { -+ if (cert->signature.oid.oid[6] != -+ 5 /* sha-1WithRSAEncryption */) { -+ wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 " -+ "does not match with certificate " -+ "signatureAlgorithm (%lu)", -+ cert->signature.oid.oid[6]); -+ os_free(data); -+ return -1; -+ } -+ goto skip_digest_oid; -+ } -+ -+ if (x509_sha256_oid(&oid)) { -+ if (cert->signature.oid.oid[6] != -+ 11 /* sha2561WithRSAEncryption */) { -+ wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 " -+ "does not match with certificate " -+ "signatureAlgorithm (%lu)", -+ cert->signature.oid.oid[6]); -+ os_free(data); -+ return -1; -+ } -+ goto skip_digest_oid; -+ } -+ -+ if (!x509_digest_oid(&oid)) { -+ wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm"); -+ os_free(data); -+ return -1; -+ } -+ switch (oid.oid[5]) { -+ case 5: /* md5 */ -+ if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */) -+ { -+ wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does " -+ "not match with certificate " -+ "signatureAlgorithm (%lu)", -+ cert->signature.oid.oid[6]); -+ os_free(data); -+ return -1; -+ } -+ break; -+ case 2: /* md2 */ -+ case 4: /* md4 */ -+ default: -+ wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm " -+ "(%lu)", oid.oid[5]); -+ os_free(data); -+ return -1; -+ } -+ -+skip_digest_oid: -+ /* Digest ::= OCTET STRING */ -+ pos = da_end; -+ end = data + data_len; -+ -+ if (asn1_get_next(pos, end - pos, &hdr) < 0 || -+ hdr.class != ASN1_CLASS_UNIVERSAL || -+ hdr.tag != ASN1_TAG_OCTETSTRING) { -+ wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING " -+ "(Digest) - found class %d tag 0x%x", -+ hdr.class, hdr.tag); -+ os_free(data); -+ return -1; -+ } -+ wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest", -+ hdr.payload, hdr.length); -+ -+ switch (cert->signature.oid.oid[6]) { -+ case 4: /* md5WithRSAEncryption */ -+ md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, -+ hash); -+ hash_len = 16; -+ wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)", -+ hash, hash_len); -+ break; -+ case 5: /* sha-1WithRSAEncryption */ -+ sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, -+ hash); -+ hash_len = 20; -+ wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)", -+ hash, hash_len); -+ break; -+ case 11: /* sha256WithRSAEncryption */ -+ sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, -+ hash); -+ hash_len = 32; -+ wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", -+ hash, hash_len); -+ break; -+ case 2: /* md2WithRSAEncryption */ -+ case 12: /* sha384WithRSAEncryption */ -+ case 13: /* sha512WithRSAEncryption */ -+ default: -+ wpa_printf(MSG_INFO, "X509: Unsupported certificate signature " -+ "algorithm (%lu)", cert->signature.oid.oid[6]); -+ os_free(data); -+ return -1; -+ } -+ -+ if (hdr.length != hash_len || -+ os_memcmp(hdr.payload, hash, hdr.length) != 0) { -+ wpa_printf(MSG_INFO, "X509: Certificate Digest does not match " -+ "with calculated tbsCertificate hash"); -+ os_free(data); -+ return -1; -+ } -+ -+ os_free(data); -+ -+ wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with " -+ "calculated tbsCertificate hash"); -+ -+ return 0; -+} -+ -+ -+static int x509_valid_issuer(const struct x509_certificate *cert) -+{ -+ if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) && -+ !cert->ca) { -+ wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an " -+ "issuer"); -+ return -1; -+ } -+ -+ if (cert->version == X509_CERT_V3 && -+ !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) { -+ wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not " -+ "include BasicConstraints extension"); -+ return -1; -+ } -+ -+ if ((cert->extensions_present & X509_EXT_KEY_USAGE) && -+ !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) { -+ wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have " -+ "keyCertSign bit in Key Usage"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * x509_certificate_chain_validate - Validate X.509 certificate chain -+ * @trusted: List of trusted certificates -+ * @chain: Certificate chain to be validated (first chain must be issued by -+ * signed by the second certificate in the chain and so on) -+ * @reason: Buffer for returning failure reason (X509_VALIDATE_*) -+ * Returns: 0 if chain is valid, -1 if not -+ */ -+int x509_certificate_chain_validate(struct x509_certificate *trusted, -+ struct x509_certificate *chain, -+ int *reason) -+{ -+ long unsigned idx; -+ int chain_trusted = 0; -+ struct x509_certificate *cert, *trust; -+ char buf[128]; -+ struct os_time now; -+ -+ *reason = X509_VALIDATE_OK; -+ -+ wpa_printf(MSG_DEBUG, "X509: Validate certificate chain"); -+ os_get_time(&now); -+ -+ for (cert = chain, idx = 0; cert; cert = cert->next, idx++) { -+ x509_name_string(&cert->subject, buf, sizeof(buf)); -+ wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf); -+ -+ if (chain_trusted) -+ continue; -+ -+ if ((unsigned long) now.sec < -+ (unsigned long) cert->not_before || -+ (unsigned long) now.sec > -+ (unsigned long) cert->not_after) { -+ wpa_printf(MSG_INFO, "X509: Certificate not valid " -+ "(now=%lu not_before=%lu not_after=%lu)", -+ now.sec, cert->not_before, cert->not_after); -+ *reason = X509_VALIDATE_CERTIFICATE_EXPIRED; -+ return -1; -+ } -+ -+ if (cert->next) { -+ if (x509_name_compare(&cert->issuer, -+ &cert->next->subject) != 0) { -+ wpa_printf(MSG_DEBUG, "X509: Certificate " -+ "chain issuer name mismatch"); -+ x509_name_string(&cert->issuer, buf, -+ sizeof(buf)); -+ wpa_printf(MSG_DEBUG, "X509: cert issuer: %s", -+ buf); -+ x509_name_string(&cert->next->subject, buf, -+ sizeof(buf)); -+ wpa_printf(MSG_DEBUG, "X509: next cert " -+ "subject: %s", buf); -+ *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN; -+ return -1; -+ } -+ -+ if (x509_valid_issuer(cert->next) < 0) { -+ *reason = X509_VALIDATE_BAD_CERTIFICATE; -+ return -1; -+ } -+ -+ if ((cert->next->extensions_present & -+ X509_EXT_PATH_LEN_CONSTRAINT) && -+ idx > cert->next->path_len_constraint) { -+ wpa_printf(MSG_DEBUG, "X509: pathLenConstraint" -+ " not met (idx=%lu issuer " -+ "pathLenConstraint=%lu)", idx, -+ cert->next->path_len_constraint); -+ *reason = X509_VALIDATE_BAD_CERTIFICATE; -+ return -1; -+ } -+ -+ if (x509_certificate_check_signature(cert->next, cert) -+ < 0) { -+ wpa_printf(MSG_DEBUG, "X509: Invalid " -+ "certificate signature within " -+ "chain"); -+ *reason = X509_VALIDATE_BAD_CERTIFICATE; -+ return -1; -+ } -+ } -+ -+ for (trust = trusted; trust; trust = trust->next) { -+ if (x509_name_compare(&cert->issuer, &trust->subject) -+ == 0) -+ break; -+ } -+ -+ if (trust) { -+ wpa_printf(MSG_DEBUG, "X509: Found issuer from the " -+ "list of trusted certificates"); -+ if (x509_valid_issuer(trust) < 0) { -+ *reason = X509_VALIDATE_BAD_CERTIFICATE; -+ return -1; -+ } -+ -+ if (x509_certificate_check_signature(trust, cert) < 0) -+ { -+ wpa_printf(MSG_DEBUG, "X509: Invalid " -+ "certificate signature"); -+ *reason = X509_VALIDATE_BAD_CERTIFICATE; -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "X509: Trusted certificate " -+ "found to complete the chain"); -+ chain_trusted = 1; -+ } -+ } -+ -+ if (!chain_trusted) { -+ wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers " -+ "from the list of trusted certificates"); -+ if (trusted) { -+ *reason = X509_VALIDATE_UNKNOWN_CA; -+ return -1; -+ } -+ wpa_printf(MSG_DEBUG, "X509: Certificate chain validation " -+ "disabled - ignore unknown CA issue"); -+ } -+ -+ wpa_printf(MSG_DEBUG, "X509: Certificate chain valid"); -+ -+ return 0; -+} -+ -+ -+/** -+ * x509_certificate_get_subject - Get a certificate based on Subject name -+ * @chain: Certificate chain to search through -+ * @name: Subject name to search for -+ * Returns: Pointer to the certificate with the given Subject name or -+ * %NULL on failure -+ */ -+struct x509_certificate * -+x509_certificate_get_subject(struct x509_certificate *chain, -+ struct x509_name *name) -+{ -+ struct x509_certificate *cert; -+ -+ for (cert = chain; cert; cert = cert->next) { -+ if (x509_name_compare(&cert->subject, name) == 0) -+ return cert; -+ } -+ return NULL; -+} -+ -+ -+/** -+ * x509_certificate_self_signed - Is the certificate self-signed? -+ * @cert: Certificate -+ * Returns: 1 if certificate is self-signed, 0 if not -+ */ -+int x509_certificate_self_signed(struct x509_certificate *cert) -+{ -+ return x509_name_compare(&cert->issuer, &cert->subject) == 0; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.h -new file mode 100644 -index 0000000000000..37292d7e7dec9 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/tls/x509v3.h -@@ -0,0 +1,129 @@ -+/* -+ * X.509v3 certificate parsing and processing -+ * Copyright (c) 2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef X509V3_H -+#define X509V3_H -+ -+#include "asn1.h" -+ -+struct x509_algorithm_identifier { -+ struct asn1_oid oid; -+}; -+ -+struct x509_name_attr { -+ enum x509_name_attr_type { -+ X509_NAME_ATTR_NOT_USED, -+ X509_NAME_ATTR_DC, -+ X509_NAME_ATTR_CN, -+ X509_NAME_ATTR_C, -+ X509_NAME_ATTR_L, -+ X509_NAME_ATTR_ST, -+ X509_NAME_ATTR_O, -+ X509_NAME_ATTR_OU -+ } type; -+ char *value; -+}; -+ -+#define X509_MAX_NAME_ATTRIBUTES 20 -+ -+struct x509_name { -+ struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES]; -+ size_t num_attr; -+ char *email; /* emailAddress */ -+ -+ /* from alternative name extension */ -+ char *alt_email; /* rfc822Name */ -+ char *dns; /* dNSName */ -+ char *uri; /* uniformResourceIdentifier */ -+ u8 *ip; /* iPAddress */ -+ size_t ip_len; /* IPv4: 4, IPv6: 16 */ -+ struct asn1_oid rid; /* registeredID */ -+}; -+ -+struct x509_certificate { -+ struct x509_certificate *next; -+ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version; -+ unsigned long serial_number; -+ struct x509_algorithm_identifier signature; -+ struct x509_name issuer; -+ struct x509_name subject; -+ os_time_t not_before; -+ os_time_t not_after; -+ struct x509_algorithm_identifier public_key_alg; -+ u8 *public_key; -+ size_t public_key_len; -+ struct x509_algorithm_identifier signature_alg; -+ u8 *sign_value; -+ size_t sign_value_len; -+ -+ /* Extensions */ -+ unsigned int extensions_present; -+#define X509_EXT_BASIC_CONSTRAINTS (1 << 0) -+#define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1) -+#define X509_EXT_KEY_USAGE (1 << 2) -+#define X509_EXT_SUBJECT_ALT_NAME (1 << 3) -+#define X509_EXT_ISSUER_ALT_NAME (1 << 4) -+ -+ /* BasicConstraints */ -+ int ca; /* cA */ -+ unsigned long path_len_constraint; /* pathLenConstraint */ -+ -+ /* KeyUsage */ -+ unsigned long key_usage; -+#define X509_KEY_USAGE_DIGITAL_SIGNATURE (1 << 0) -+#define X509_KEY_USAGE_NON_REPUDIATION (1 << 1) -+#define X509_KEY_USAGE_KEY_ENCIPHERMENT (1 << 2) -+#define X509_KEY_USAGE_DATA_ENCIPHERMENT (1 << 3) -+#define X509_KEY_USAGE_KEY_AGREEMENT (1 << 4) -+#define X509_KEY_USAGE_KEY_CERT_SIGN (1 << 5) -+#define X509_KEY_USAGE_CRL_SIGN (1 << 6) -+#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7) -+#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8) -+ -+ /* -+ * The DER format certificate follows struct x509_certificate. These -+ * pointers point to that buffer. -+ */ -+ const u8 *cert_start; -+ size_t cert_len; -+ const u8 *tbs_cert_start; -+ size_t tbs_cert_len; -+}; -+ -+enum { -+ X509_VALIDATE_OK, -+ X509_VALIDATE_BAD_CERTIFICATE, -+ X509_VALIDATE_UNSUPPORTED_CERTIFICATE, -+ X509_VALIDATE_CERTIFICATE_REVOKED, -+ X509_VALIDATE_CERTIFICATE_EXPIRED, -+ X509_VALIDATE_CERTIFICATE_UNKNOWN, -+ X509_VALIDATE_UNKNOWN_CA -+}; -+ -+void x509_certificate_free(struct x509_certificate *cert); -+struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len); -+void x509_name_string(struct x509_name *name, char *buf, size_t len); -+int x509_name_compare(struct x509_name *a, struct x509_name *b); -+void x509_certificate_chain_free(struct x509_certificate *cert); -+int x509_certificate_check_signature(struct x509_certificate *issuer, -+ struct x509_certificate *cert); -+int x509_certificate_chain_validate(struct x509_certificate *trusted, -+ struct x509_certificate *chain, -+ int *reason); -+struct x509_certificate * -+x509_certificate_get_subject(struct x509_certificate *chain, -+ struct x509_name *name); -+int x509_certificate_self_signed(struct x509_certificate *cert); -+ -+#endif /* X509V3_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/.gitignore b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/.gitignore -new file mode 100644 -index 0000000000000..833734f887ac2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/.gitignore -@@ -0,0 +1 @@ -+libutils.a -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/Makefile -new file mode 100644 -index 0000000000000..0f1f191099953 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/Makefile -@@ -0,0 +1,39 @@ -+all: libutils.a -+ -+clean: -+ rm -f *~ *.o *.d libutils.a -+ -+install: -+ @echo Nothing to be made. -+ -+ -+include ../lib.rules -+ -+#CFLAGS += -DWPA_TRACE -+CFLAGS += -DCONFIG_IPV6 -+ -+LIB_OBJS= \ -+ base64.o \ -+ common.o \ -+ ip_addr.o \ -+ radiotap.o \ -+ trace.o \ -+ uuid.o \ -+ wpa_debug.o \ -+ wpabuf.o -+ -+# Pick correct OS wrapper implementation -+LIB_OBJS += os_unix.o -+ -+# Pick correct event loop implementation -+LIB_OBJS += eloop.o -+ -+# Pick correct edit implementation -+LIB_OBJS += edit.o -+ -+#LIB_OBJS += pcsc_funcs.o -+ -+libutils.a: $(LIB_OBJS) -+ $(AR) crT $@ $? -+ -+-include $(OBJS:%.o=%.d) -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.c -new file mode 100644 -index 0000000000000..155bfce83aa57 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.c -@@ -0,0 +1,154 @@ -+/* -+ * Base64 encoding/decoding (RFC1341) -+ * Copyright (c) 2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "os.h" -+#include "base64.h" -+ -+static const unsigned char base64_table[65] = -+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -+ -+/** -+ * base64_encode - Base64 encode -+ * @src: Data to be encoded -+ * @len: Length of the data to be encoded -+ * @out_len: Pointer to output length variable, or %NULL if not used -+ * Returns: Allocated buffer of out_len bytes of encoded data, -+ * or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned buffer. Returned buffer is -+ * nul terminated to make it easier to use as a C string. The nul terminator is -+ * not included in out_len. -+ */ -+unsigned char * base64_encode(const unsigned char *src, size_t len, -+ size_t *out_len) -+{ -+ unsigned char *out, *pos; -+ const unsigned char *end, *in; -+ size_t olen; -+ int line_len; -+ -+ olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ -+ olen += olen / 72; /* line feeds */ -+ olen++; /* nul termination */ -+ if (olen < len) -+ return NULL; /* integer overflow */ -+ out = os_malloc(olen); -+ if (out == NULL) -+ return NULL; -+ -+ end = src + len; -+ in = src; -+ pos = out; -+ line_len = 0; -+ while (end - in >= 3) { -+ *pos++ = base64_table[in[0] >> 2]; -+ *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; -+ *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; -+ *pos++ = base64_table[in[2] & 0x3f]; -+ in += 3; -+ line_len += 4; -+ if (line_len >= 72) { -+ *pos++ = '\n'; -+ line_len = 0; -+ } -+ } -+ -+ if (end - in) { -+ *pos++ = base64_table[in[0] >> 2]; -+ if (end - in == 1) { -+ *pos++ = base64_table[(in[0] & 0x03) << 4]; -+ *pos++ = '='; -+ } else { -+ *pos++ = base64_table[((in[0] & 0x03) << 4) | -+ (in[1] >> 4)]; -+ *pos++ = base64_table[(in[1] & 0x0f) << 2]; -+ } -+ *pos++ = '='; -+ line_len += 4; -+ } -+ -+ if (line_len) -+ *pos++ = '\n'; -+ -+ *pos = '\0'; -+ if (out_len) -+ *out_len = pos - out; -+ return out; -+} -+ -+ -+/** -+ * base64_decode - Base64 decode -+ * @src: Data to be decoded -+ * @len: Length of the data to be decoded -+ * @out_len: Pointer to output length variable -+ * Returns: Allocated buffer of out_len bytes of decoded data, -+ * or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned buffer. -+ */ -+unsigned char * base64_decode(const unsigned char *src, size_t len, -+ size_t *out_len) -+{ -+ unsigned char dtable[256], *out, *pos, in[4], block[4], tmp; -+ size_t i, count, olen; -+ -+ os_memset(dtable, 0x80, 256); -+ for (i = 0; i < sizeof(base64_table) - 1; i++) -+ dtable[base64_table[i]] = (unsigned char) i; -+ dtable['='] = 0; -+ -+ count = 0; -+ for (i = 0; i < len; i++) { -+ if (dtable[src[i]] != 0x80) -+ count++; -+ } -+ -+ if (count == 0 || count % 4) -+ return NULL; -+ -+ olen = count / 4 * 3; -+ pos = out = os_malloc(olen); -+ if (out == NULL) -+ return NULL; -+ -+ count = 0; -+ for (i = 0; i < len; i++) { -+ tmp = dtable[src[i]]; -+ if (tmp == 0x80) -+ continue; -+ -+ in[count] = src[i]; -+ block[count] = tmp; -+ count++; -+ if (count == 4) { -+ *pos++ = (block[0] << 2) | (block[1] >> 4); -+ *pos++ = (block[1] << 4) | (block[2] >> 2); -+ *pos++ = (block[2] << 6) | block[3]; -+ count = 0; -+ } -+ } -+ -+ if (pos > out) { -+ if (in[2] == '=') -+ pos -= 2; -+ else if (in[3] == '=') -+ pos--; -+ } -+ -+ *out_len = pos - out; -+ return out; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.h -new file mode 100644 -index 0000000000000..b87a1682f8ddf ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/base64.h -@@ -0,0 +1,23 @@ -+/* -+ * Base64 encoding/decoding (RFC1341) -+ * Copyright (c) 2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef BASE64_H -+#define BASE64_H -+ -+unsigned char * base64_encode(const unsigned char *src, size_t len, -+ size_t *out_len); -+unsigned char * base64_decode(const unsigned char *src, size_t len, -+ size_t *out_len); -+ -+#endif /* BASE64_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/build_config.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/build_config.h -new file mode 100644 -index 0000000000000..366677849231f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/build_config.h -@@ -0,0 +1,105 @@ -+/* -+ * wpa_supplicant/hostapd - Build time configuration defines -+ * Copyright (c) 2005-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This header file can be used to define configuration defines that were -+ * originally defined in Makefile. This is mainly meant for IDE use or for -+ * systems that do not have suitable 'make' tool. In these cases, it may be -+ * easier to have a single place for defining all the needed C pre-processor -+ * defines. -+ */ -+ -+#ifndef BUILD_CONFIG_H -+#define BUILD_CONFIG_H -+ -+/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */ -+ -+#ifdef CONFIG_WIN32_DEFAULTS -+#define CONFIG_NATIVE_WINDOWS -+#define CONFIG_ANSI_C_EXTRA -+#define CONFIG_WINPCAP -+#define IEEE8021X_EAPOL -+#define PKCS12_FUNCS -+#define PCSC_FUNCS -+#define CONFIG_CTRL_IFACE -+#define CONFIG_CTRL_IFACE_NAMED_PIPE -+#define CONFIG_DRIVER_NDIS -+#define CONFIG_NDIS_EVENTS_INTEGRATED -+#define CONFIG_DEBUG_FILE -+#define EAP_MD5 -+#define EAP_TLS -+#define EAP_MSCHAPv2 -+#define EAP_PEAP -+#define EAP_TTLS -+#define EAP_GTC -+#define EAP_OTP -+#define EAP_LEAP -+#define EAP_TNC -+#define _CRT_SECURE_NO_DEPRECATE -+ -+#ifdef USE_INTERNAL_CRYPTO -+#define CONFIG_TLS_INTERNAL_CLIENT -+#define CONFIG_INTERNAL_LIBTOMMATH -+#define CONFIG_CRYPTO_INTERNAL -+#endif /* USE_INTERNAL_CRYPTO */ -+#endif /* CONFIG_WIN32_DEFAULTS */ -+ -+#ifdef __SYMBIAN32__ -+#define OS_NO_C_LIB_DEFINES -+#define CONFIG_ANSI_C_EXTRA -+#define CONFIG_NO_WPA_MSG -+#define CONFIG_NO_HOSTAPD_LOGGER -+#define CONFIG_NO_STDOUT_DEBUG -+#define CONFIG_BACKEND_FILE -+#define CONFIG_INTERNAL_LIBTOMMATH -+#define CONFIG_CRYPTO_INTERNAL -+#define IEEE8021X_EAPOL -+#define PKCS12_FUNCS -+#define EAP_MD5 -+#define EAP_TLS -+#define EAP_MSCHAPv2 -+#define EAP_PEAP -+#define EAP_TTLS -+#define EAP_GTC -+#define EAP_OTP -+#define EAP_LEAP -+#define EAP_FAST -+#endif /* __SYMBIAN32__ */ -+ -+#ifdef CONFIG_XCODE_DEFAULTS -+#define CONFIG_DRIVER_OSX -+#define CONFIG_BACKEND_FILE -+#define IEEE8021X_EAPOL -+#define PKCS12_FUNCS -+#define CONFIG_CTRL_IFACE -+#define CONFIG_CTRL_IFACE_UNIX -+#define CONFIG_DEBUG_FILE -+#define EAP_MD5 -+#define EAP_TLS -+#define EAP_MSCHAPv2 -+#define EAP_PEAP -+#define EAP_TTLS -+#define EAP_GTC -+#define EAP_OTP -+#define EAP_LEAP -+#define EAP_TNC -+#define CONFIG_WPS -+#define EAP_WSC -+ -+#ifdef USE_INTERNAL_CRYPTO -+#define CONFIG_TLS_INTERNAL_CLIENT -+#define CONFIG_INTERNAL_LIBTOMMATH -+#define CONFIG_CRYPTO_INTERNAL -+#endif /* USE_INTERNAL_CRYPTO */ -+#endif /* CONFIG_XCODE_DEFAULTS */ -+ -+#endif /* BUILD_CONFIG_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.c -new file mode 100644 -index 0000000000000..89eca1c1b6695 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.c -@@ -0,0 +1,387 @@ -+/* -+ * wpa_supplicant/hostapd / common helper functions, etc. -+ * Copyright (c) 2002-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+ -+ -+static int hex2num(char c) -+{ -+ if (c >= '0' && c <= '9') -+ return c - '0'; -+ if (c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ if (c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ return -1; -+} -+ -+ -+int hex2byte(const char *hex) -+{ -+ int a, b; -+ a = hex2num(*hex++); -+ if (a < 0) -+ return -1; -+ b = hex2num(*hex++); -+ if (b < 0) -+ return -1; -+ return (a << 4) | b; -+} -+ -+ -+/** -+ * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format) -+ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55") -+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) -+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) -+ */ -+int hwaddr_aton(const char *txt, u8 *addr) -+{ -+ int i; -+ -+ for (i = 0; i < 6; i++) { -+ int a, b; -+ -+ a = hex2num(*txt++); -+ if (a < 0) -+ return -1; -+ b = hex2num(*txt++); -+ if (b < 0) -+ return -1; -+ *addr++ = (a << 4) | b; -+ if (i < 5 && *txt++ != ':') -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/** -+ * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format) -+ * @txt: MAC address as a string (e.g., "001122334455") -+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) -+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address) -+ */ -+int hwaddr_compact_aton(const char *txt, u8 *addr) -+{ -+ int i; -+ -+ for (i = 0; i < 6; i++) { -+ int a, b; -+ -+ a = hex2num(*txt++); -+ if (a < 0) -+ return -1; -+ b = hex2num(*txt++); -+ if (b < 0) -+ return -1; -+ *addr++ = (a << 4) | b; -+ } -+ -+ return 0; -+} -+ -+/** -+ * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format) -+ * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455) -+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes) -+ * Returns: Characters used (> 0) on success, -1 on failure -+ */ -+int hwaddr_aton2(const char *txt, u8 *addr) -+{ -+ int i; -+ const char *pos = txt; -+ -+ for (i = 0; i < 6; i++) { -+ int a, b; -+ -+ while (*pos == ':' || *pos == '.' || *pos == '-') -+ pos++; -+ -+ a = hex2num(*pos++); -+ if (a < 0) -+ return -1; -+ b = hex2num(*pos++); -+ if (b < 0) -+ return -1; -+ *addr++ = (a << 4) | b; -+ } -+ -+ return pos - txt; -+} -+ -+ -+/** -+ * hexstr2bin - Convert ASCII hex string into binary data -+ * @hex: ASCII hex string (e.g., "01ab") -+ * @buf: Buffer for the binary data -+ * @len: Length of the text to convert in bytes (of buf); hex will be double -+ * this size -+ * Returns: 0 on success, -1 on failure (invalid hex string) -+ */ -+int hexstr2bin(const char *hex, u8 *buf, size_t len) -+{ -+ size_t i; -+ int a; -+ const char *ipos = hex; -+ u8 *opos = buf; -+ -+ for (i = 0; i < len; i++) { -+ a = hex2byte(ipos); -+ if (a < 0) -+ return -1; -+ *opos++ = a; -+ ipos += 2; -+ } -+ return 0; -+} -+ -+ -+/** -+ * inc_byte_array - Increment arbitrary length byte array by one -+ * @counter: Pointer to byte array -+ * @len: Length of the counter in bytes -+ * -+ * This function increments the last byte of the counter by one and continues -+ * rolling over to more significant bytes if the byte was incremented from -+ * 0xff to 0x00. -+ */ -+void inc_byte_array(u8 *counter, size_t len) -+{ -+ int pos = len - 1; -+ while (pos >= 0) { -+ counter[pos]++; -+ if (counter[pos] != 0) -+ break; -+ pos--; -+ } -+} -+ -+ -+void wpa_get_ntp_timestamp(u8 *buf) -+{ -+ struct os_time now; -+ u32 sec, usec; -+ be32 tmp; -+ -+ /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ -+ os_get_time(&now); -+ sec = now.sec + 2208988800U; /* Epoch to 1900 */ -+ /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ -+ usec = now.usec; -+ usec = 4295 * usec - (usec >> 5) - (usec >> 9); -+ tmp = host_to_be32(sec); -+ os_memcpy(buf, (u8 *) &tmp, 4); -+ tmp = host_to_be32(usec); -+ os_memcpy(buf + 4, (u8 *) &tmp, 4); -+} -+ -+ -+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, -+ size_t len, int uppercase) -+{ -+ size_t i; -+ char *pos = buf, *end = buf + buf_size; -+ int ret; -+ if (buf_size == 0) -+ return 0; -+ for (i = 0; i < len; i++) { -+ ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x", -+ data[i]); -+ if (ret < 0 || ret >= end - pos) { -+ end[-1] = '\0'; -+ return pos - buf; -+ } -+ pos += ret; -+ } -+ end[-1] = '\0'; -+ return pos - buf; -+} -+ -+/** -+ * wpa_snprintf_hex - Print data as a hex string into a buffer -+ * @buf: Memory area to use as the output buffer -+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) -+ * @data: Data to be printed -+ * @len: Length of data in bytes -+ * Returns: Number of bytes written -+ */ -+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len) -+{ -+ return _wpa_snprintf_hex(buf, buf_size, data, len, 0); -+} -+ -+ -+/** -+ * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf -+ * @buf: Memory area to use as the output buffer -+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1) -+ * @data: Data to be printed -+ * @len: Length of data in bytes -+ * Returns: Number of bytes written -+ */ -+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, -+ size_t len) -+{ -+ return _wpa_snprintf_hex(buf, buf_size, data, len, 1); -+} -+ -+ -+#ifdef CONFIG_ANSI_C_EXTRA -+ -+#ifdef _WIN32_WCE -+void perror(const char *s) -+{ -+ wpa_printf(MSG_ERROR, "%s: GetLastError: %d", -+ s, (int) GetLastError()); -+} -+#endif /* _WIN32_WCE */ -+ -+ -+int optind = 1; -+int optopt; -+char *optarg; -+ -+int getopt(int argc, char *const argv[], const char *optstring) -+{ -+ static int optchr = 1; -+ char *cp; -+ -+ if (optchr == 1) { -+ if (optind >= argc) { -+ /* all arguments processed */ -+ return EOF; -+ } -+ -+ if (argv[optind][0] != '-' || argv[optind][1] == '\0') { -+ /* no option characters */ -+ return EOF; -+ } -+ } -+ -+ if (os_strcmp(argv[optind], "--") == 0) { -+ /* no more options */ -+ optind++; -+ return EOF; -+ } -+ -+ optopt = argv[optind][optchr]; -+ cp = os_strchr(optstring, optopt); -+ if (cp == NULL || optopt == ':') { -+ if (argv[optind][++optchr] == '\0') { -+ optchr = 1; -+ optind++; -+ } -+ return '?'; -+ } -+ -+ if (cp[1] == ':') { -+ /* Argument required */ -+ optchr = 1; -+ if (argv[optind][optchr + 1]) { -+ /* No space between option and argument */ -+ optarg = &argv[optind++][optchr + 1]; -+ } else if (++optind >= argc) { -+ /* option requires an argument */ -+ return '?'; -+ } else { -+ /* Argument in the next argv */ -+ optarg = argv[optind++]; -+ } -+ } else { -+ /* No argument */ -+ if (argv[optind][++optchr] == '\0') { -+ optchr = 1; -+ optind++; -+ } -+ optarg = NULL; -+ } -+ return *cp; -+} -+#endif /* CONFIG_ANSI_C_EXTRA */ -+ -+ -+#ifdef CONFIG_NATIVE_WINDOWS -+/** -+ * wpa_unicode2ascii_inplace - Convert unicode string into ASCII -+ * @str: Pointer to string to convert -+ * -+ * This function converts a unicode string to ASCII using the same -+ * buffer for output. If UNICODE is not set, the buffer is not -+ * modified. -+ */ -+void wpa_unicode2ascii_inplace(TCHAR *str) -+{ -+#ifdef UNICODE -+ char *dst = (char *) str; -+ while (*str) -+ *dst++ = (char) *str++; -+ *dst = '\0'; -+#endif /* UNICODE */ -+} -+ -+ -+TCHAR * wpa_strdup_tchar(const char *str) -+{ -+#ifdef UNICODE -+ TCHAR *buf; -+ buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR)); -+ if (buf == NULL) -+ return NULL; -+ wsprintf(buf, L"%S", str); -+ return buf; -+#else /* UNICODE */ -+ return os_strdup(str); -+#endif /* UNICODE */ -+} -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ -+/** -+ * wpa_ssid_txt - Convert SSID to a printable string -+ * @ssid: SSID (32-octet string) -+ * @ssid_len: Length of ssid in octets -+ * Returns: Pointer to a printable string -+ * -+ * This function can be used to convert SSIDs into printable form. In most -+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard -+ * does not limit the used character set, so anything could be used in an SSID. -+ * -+ * This function uses a static buffer, so only one call can be used at the -+ * time, i.e., this is not re-entrant and the returned buffer must be used -+ * before calling this again. -+ */ -+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len) -+{ -+ static char ssid_txt[33]; -+ char *pos; -+ -+ if (ssid_len > 32) -+ ssid_len = 32; -+ os_memcpy(ssid_txt, ssid, ssid_len); -+ ssid_txt[ssid_len] = '\0'; -+ for (pos = ssid_txt; *pos != '\0'; pos++) { -+ if ((u8) *pos < 32 || (u8) *pos >= 127) -+ *pos = '_'; -+ } -+ return ssid_txt; -+} -+ -+ -+void * __hide_aliasing_typecast(void *foo) -+{ -+ return foo; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.h -new file mode 100644 -index 0000000000000..14ab297f2f6ad ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/common.h -@@ -0,0 +1,502 @@ -+/* -+ * wpa_supplicant/hostapd / common helper functions, etc. -+ * Copyright (c) 2002-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef COMMON_H -+#define COMMON_H -+ -+#include "os.h" -+ -+#if defined(__linux__) || defined(__GLIBC__) -+#include -+#include -+#endif /* __linux__ */ -+ -+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ -+ defined(__OpenBSD__) -+#include -+#include -+#define __BYTE_ORDER _BYTE_ORDER -+#define __LITTLE_ENDIAN _LITTLE_ENDIAN -+#define __BIG_ENDIAN _BIG_ENDIAN -+#ifdef __OpenBSD__ -+#define bswap_16 swap16 -+#define bswap_32 swap32 -+#define bswap_64 swap64 -+#else /* __OpenBSD__ */ -+#define bswap_16 bswap16 -+#define bswap_32 bswap32 -+#define bswap_64 bswap64 -+#endif /* __OpenBSD__ */ -+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || -+ * defined(__DragonFly__) || defined(__OpenBSD__) */ -+ -+#ifdef __APPLE__ -+#include -+#include -+#define __BYTE_ORDER _BYTE_ORDER -+#define __LITTLE_ENDIAN _LITTLE_ENDIAN -+#define __BIG_ENDIAN _BIG_ENDIAN -+static inline unsigned short bswap_16(unsigned short v) -+{ -+ return ((v & 0xff) << 8) | (v >> 8); -+} -+ -+static inline unsigned int bswap_32(unsigned int v) -+{ -+ return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | -+ ((v & 0xff0000) >> 8) | (v >> 24); -+} -+#endif /* __APPLE__ */ -+ -+#ifdef CONFIG_TI_COMPILER -+#define __BIG_ENDIAN 4321 -+#define __LITTLE_ENDIAN 1234 -+#ifdef __big_endian__ -+#define __BYTE_ORDER __BIG_ENDIAN -+#else -+#define __BYTE_ORDER __LITTLE_ENDIAN -+#endif -+#endif /* CONFIG_TI_COMPILER */ -+ -+#ifdef __SYMBIAN32__ -+#define __BIG_ENDIAN 4321 -+#define __LITTLE_ENDIAN 1234 -+#define __BYTE_ORDER __LITTLE_ENDIAN -+#endif /* __SYMBIAN32__ */ -+ -+#ifdef CONFIG_NATIVE_WINDOWS -+#include -+ -+typedef int socklen_t; -+ -+#ifndef MSG_DONTWAIT -+#define MSG_DONTWAIT 0 /* not supported */ -+#endif -+ -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+#ifdef _MSC_VER -+#define inline __inline -+ -+#undef vsnprintf -+#define vsnprintf _vsnprintf -+#undef close -+#define close closesocket -+#endif /* _MSC_VER */ -+ -+ -+/* Define platform specific integer types */ -+ -+#ifdef _MSC_VER -+typedef UINT64 u64; -+typedef UINT32 u32; -+typedef UINT16 u16; -+typedef UINT8 u8; -+typedef INT64 s64; -+typedef INT32 s32; -+typedef INT16 s16; -+typedef INT8 s8; -+#define WPA_TYPES_DEFINED -+#endif /* _MSC_VER */ -+ -+#ifdef __vxworks -+typedef unsigned long long u64; -+typedef UINT32 u32; -+typedef UINT16 u16; -+typedef UINT8 u8; -+typedef long long s64; -+typedef INT32 s32; -+typedef INT16 s16; -+typedef INT8 s8; -+#define WPA_TYPES_DEFINED -+#endif /* __vxworks */ -+ -+#ifdef CONFIG_TI_COMPILER -+#ifdef _LLONG_AVAILABLE -+typedef unsigned long long u64; -+#else -+/* -+ * TODO: 64-bit variable not available. Using long as a workaround to test the -+ * build, but this will likely not work for all operations. -+ */ -+typedef unsigned long u64; -+#endif -+typedef unsigned int u32; -+typedef unsigned short u16; -+typedef unsigned char u8; -+#define WPA_TYPES_DEFINED -+#endif /* CONFIG_TI_COMPILER */ -+ -+#ifdef __SYMBIAN32__ -+#define __REMOVE_PLATSEC_DIAGNOSTICS__ -+#include -+typedef TUint64 u64; -+typedef TUint32 u32; -+typedef TUint16 u16; -+typedef TUint8 u8; -+#define WPA_TYPES_DEFINED -+#endif /* __SYMBIAN32__ */ -+ -+#ifndef WPA_TYPES_DEFINED -+#ifdef CONFIG_USE_INTTYPES_H -+#include -+#else -+#include -+#endif -+typedef uint64_t u64; -+typedef uint32_t u32; -+typedef uint16_t u16; -+typedef uint8_t u8; -+typedef int64_t s64; -+typedef int32_t s32; -+typedef int16_t s16; -+typedef int8_t s8; -+#define WPA_TYPES_DEFINED -+#endif /* !WPA_TYPES_DEFINED */ -+ -+ -+/* Define platform specific byte swapping macros */ -+ -+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) -+ -+static inline unsigned short wpa_swap_16(unsigned short v) -+{ -+ return ((v & 0xff) << 8) | (v >> 8); -+} -+ -+static inline unsigned int wpa_swap_32(unsigned int v) -+{ -+ return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | -+ ((v & 0xff0000) >> 8) | (v >> 24); -+} -+ -+#define le_to_host16(n) (n) -+#define host_to_le16(n) (n) -+#define be_to_host16(n) wpa_swap_16(n) -+#define host_to_be16(n) wpa_swap_16(n) -+#define le_to_host32(n) (n) -+#define be_to_host32(n) wpa_swap_32(n) -+#define host_to_be32(n) wpa_swap_32(n) -+ -+#define WPA_BYTE_SWAP_DEFINED -+ -+#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ -+ -+ -+#ifndef WPA_BYTE_SWAP_DEFINED -+ -+#ifndef __BYTE_ORDER -+#ifndef __LITTLE_ENDIAN -+#ifndef __BIG_ENDIAN -+#define __LITTLE_ENDIAN 1234 -+#define __BIG_ENDIAN 4321 -+#if defined(sparc) -+#define __BYTE_ORDER __BIG_ENDIAN -+#endif -+#endif /* __BIG_ENDIAN */ -+#endif /* __LITTLE_ENDIAN */ -+#endif /* __BYTE_ORDER */ -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+#define le_to_host16(n) ((__force u16) (le16) (n)) -+#define host_to_le16(n) ((__force le16) (u16) (n)) -+#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) -+#define host_to_be16(n) ((__force be16) bswap_16((n))) -+#define le_to_host32(n) ((__force u32) (le32) (n)) -+#define host_to_le32(n) ((__force le32) (u32) (n)) -+#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) -+#define host_to_be32(n) ((__force be32) bswap_32((n))) -+#define le_to_host64(n) ((__force u64) (le64) (n)) -+#define host_to_le64(n) ((__force le64) (u64) (n)) -+#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) -+#define host_to_be64(n) ((__force be64) bswap_64((n))) -+#elif __BYTE_ORDER == __BIG_ENDIAN -+#define le_to_host16(n) bswap_16(n) -+#define host_to_le16(n) bswap_16(n) -+#define be_to_host16(n) (n) -+#define host_to_be16(n) (n) -+#define le_to_host32(n) bswap_32(n) -+#define be_to_host32(n) (n) -+#define host_to_be32(n) (n) -+#define le_to_host64(n) bswap_64(n) -+#define host_to_le64(n) bswap_64(n) -+#define be_to_host64(n) (n) -+#define host_to_be64(n) (n) -+#ifndef WORDS_BIGENDIAN -+#define WORDS_BIGENDIAN -+#endif -+#else -+#error Could not determine CPU byte order -+#endif -+ -+#define WPA_BYTE_SWAP_DEFINED -+#endif /* !WPA_BYTE_SWAP_DEFINED */ -+ -+ -+/* Macros for handling unaligned memory accesses */ -+ -+#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) -+#define WPA_PUT_BE16(a, val) \ -+ do { \ -+ (a)[0] = ((u16) (val)) >> 8; \ -+ (a)[1] = ((u16) (val)) & 0xff; \ -+ } while (0) -+ -+#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) -+#define WPA_PUT_LE16(a, val) \ -+ do { \ -+ (a)[1] = ((u16) (val)) >> 8; \ -+ (a)[0] = ((u16) (val)) & 0xff; \ -+ } while (0) -+ -+#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ -+ ((u32) (a)[2])) -+#define WPA_PUT_BE24(a, val) \ -+ do { \ -+ (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ -+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ -+ (a)[2] = (u8) (((u32) (val)) & 0xff); \ -+ } while (0) -+ -+#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ -+ (((u32) (a)[2]) << 8) | ((u32) (a)[3])) -+#define WPA_PUT_BE32(a, val) \ -+ do { \ -+ (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ -+ (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ -+ (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ -+ (a)[3] = (u8) (((u32) (val)) & 0xff); \ -+ } while (0) -+ -+#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ -+ (((u32) (a)[1]) << 8) | ((u32) (a)[0])) -+#define WPA_PUT_LE32(a, val) \ -+ do { \ -+ (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ -+ (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ -+ (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ -+ (a)[0] = (u8) (((u32) (val)) & 0xff); \ -+ } while (0) -+ -+#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ -+ (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ -+ (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ -+ (((u64) (a)[6]) << 8) | ((u64) (a)[7])) -+#define WPA_PUT_BE64(a, val) \ -+ do { \ -+ (a)[0] = (u8) (((u64) (val)) >> 56); \ -+ (a)[1] = (u8) (((u64) (val)) >> 48); \ -+ (a)[2] = (u8) (((u64) (val)) >> 40); \ -+ (a)[3] = (u8) (((u64) (val)) >> 32); \ -+ (a)[4] = (u8) (((u64) (val)) >> 24); \ -+ (a)[5] = (u8) (((u64) (val)) >> 16); \ -+ (a)[6] = (u8) (((u64) (val)) >> 8); \ -+ (a)[7] = (u8) (((u64) (val)) & 0xff); \ -+ } while (0) -+ -+#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ -+ (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ -+ (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ -+ (((u64) (a)[1]) << 8) | ((u64) (a)[0])) -+ -+ -+#ifndef ETH_ALEN -+#define ETH_ALEN 6 -+#endif -+#ifndef IFNAMSIZ -+#define IFNAMSIZ 16 -+#endif -+#ifndef ETH_P_ALL -+#define ETH_P_ALL 0x0003 -+#endif -+#ifndef ETH_P_80211_ENCAP -+#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ -+#endif -+#ifndef ETH_P_PAE -+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -+#endif /* ETH_P_PAE */ -+#ifndef ETH_P_EAPOL -+#define ETH_P_EAPOL ETH_P_PAE -+#endif /* ETH_P_EAPOL */ -+#ifndef ETH_P_RSN_PREAUTH -+#define ETH_P_RSN_PREAUTH 0x88c7 -+#endif /* ETH_P_RSN_PREAUTH */ -+#ifndef ETH_P_RRB -+#define ETH_P_RRB 0x890D -+#endif /* ETH_P_RRB */ -+ -+ -+#ifdef __GNUC__ -+#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) -+#define STRUCT_PACKED __attribute__ ((packed)) -+#else -+#define PRINTF_FORMAT(a,b) -+#define STRUCT_PACKED -+#endif -+ -+ -+#ifdef CONFIG_ANSI_C_EXTRA -+ -+#if !defined(_MSC_VER) || _MSC_VER < 1400 -+/* snprintf - used in number of places; sprintf() is _not_ a good replacement -+ * due to possible buffer overflow; see, e.g., -+ * http://www.ijs.si/software/snprintf/ for portable implementation of -+ * snprintf. */ -+int snprintf(char *str, size_t size, const char *format, ...); -+ -+/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ -+int vsnprintf(char *str, size_t size, const char *format, va_list ap); -+#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ -+ -+/* getopt - only used in main.c */ -+int getopt(int argc, char *const argv[], const char *optstring); -+extern char *optarg; -+extern int optind; -+ -+#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF -+#ifndef __socklen_t_defined -+typedef int socklen_t; -+#endif -+#endif -+ -+/* inline - define as __inline or just define it to be empty, if needed */ -+#ifdef CONFIG_NO_INLINE -+#define inline -+#else -+#define inline __inline -+#endif -+ -+#ifndef __func__ -+#define __func__ "__func__ not defined" -+#endif -+ -+#ifndef bswap_16 -+#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) -+#endif -+ -+#ifndef bswap_32 -+#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ -+ (((u32) (a) << 8) & 0xff0000) | \ -+ (((u32) (a) >> 8) & 0xff00) | \ -+ (((u32) (a) >> 24) & 0xff)) -+#endif -+ -+#ifndef MSG_DONTWAIT -+#define MSG_DONTWAIT 0 -+#endif -+ -+#ifdef _WIN32_WCE -+void perror(const char *s); -+#endif /* _WIN32_WCE */ -+ -+#endif /* CONFIG_ANSI_C_EXTRA */ -+ -+#ifndef MAC2STR -+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -+ -+/* -+ * Compact form for string representation of MAC address -+ * To be used, e.g., for constructing dbus paths for P2P Devices -+ */ -+#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x" -+#endif -+ -+#ifndef BIT -+#define BIT(x) (1 << (x)) -+#endif -+ -+/* -+ * Definitions for sparse validation -+ * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) -+ */ -+#ifdef __CHECKER__ -+#define __force __attribute__((force)) -+#define __bitwise __attribute__((bitwise)) -+#else -+#define __force -+#define __bitwise -+#endif -+ -+typedef u16 __bitwise be16; -+typedef u16 __bitwise le16; -+typedef u32 __bitwise be32; -+typedef u32 __bitwise le32; -+typedef u64 __bitwise be64; -+typedef u64 __bitwise le64; -+ -+#ifndef __must_check -+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -+#define __must_check __attribute__((__warn_unused_result__)) -+#else -+#define __must_check -+#endif /* __GNUC__ */ -+#endif /* __must_check */ -+ -+int hwaddr_aton(const char *txt, u8 *addr); -+int hwaddr_compact_aton(const char *txt, u8 *addr); -+int hwaddr_aton2(const char *txt, u8 *addr); -+int hex2byte(const char *hex); -+int hexstr2bin(const char *hex, u8 *buf, size_t len); -+void inc_byte_array(u8 *counter, size_t len); -+void wpa_get_ntp_timestamp(u8 *buf); -+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); -+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, -+ size_t len); -+ -+#ifdef CONFIG_NATIVE_WINDOWS -+void wpa_unicode2ascii_inplace(TCHAR *str); -+TCHAR * wpa_strdup_tchar(const char *str); -+#else /* CONFIG_NATIVE_WINDOWS */ -+#define wpa_unicode2ascii_inplace(s) do { } while (0) -+#define wpa_strdup_tchar(s) strdup((s)) -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); -+ -+static inline int is_zero_ether_addr(const u8 *a) -+{ -+ return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); -+} -+ -+static inline int is_broadcast_ether_addr(const u8 *a) -+{ -+ return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; -+} -+ -+#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" -+ -+#include "wpa_debug.h" -+ -+ -+/* -+ * gcc 4.4 ends up generating strict-aliasing warnings about some very common -+ * networking socket uses that do not really result in a real problem and -+ * cannot be easily avoided with union-based type-punning due to struct -+ * definitions including another struct in system header files. To avoid having -+ * to fully disable strict-aliasing warnings, provide a mechanism to hide the -+ * typecast from aliasing for now. A cleaner solution will hopefully be found -+ * in the future to handle these cases. -+ */ -+void * __hide_aliasing_typecast(void *foo); -+#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) -+ -+#ifdef CONFIG_VALGRIND -+#include -+#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len)) -+#else /* CONFIG_VALGRIND */ -+#define WPA_MEM_DEFINED(ptr, len) do { } while (0) -+#endif /* CONFIG_VALGRIND */ -+ -+#endif /* COMMON_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.c -new file mode 100644 -index 0000000000000..8f9e4ede8660b ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.c -@@ -0,0 +1,1161 @@ -+/* -+ * Command line editing and history -+ * Copyright (c) 2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "list.h" -+#include "edit.h" -+ -+#define CMD_BUF_LEN 256 -+static char cmdbuf[CMD_BUF_LEN]; -+static int cmdbuf_pos = 0; -+static int cmdbuf_len = 0; -+ -+#define HISTORY_MAX 100 -+ -+struct edit_history { -+ struct dl_list list; -+ char str[1]; -+}; -+ -+static struct dl_list history_list; -+static struct edit_history *history_curr; -+ -+static void *edit_cb_ctx; -+static void (*edit_cmd_cb)(void *ctx, char *cmd); -+static void (*edit_eof_cb)(void *ctx); -+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) = -+ NULL; -+ -+static struct termios prevt, newt; -+ -+ -+#define CLEAR_END_LINE "\e[K" -+ -+ -+void edit_clear_line(void) -+{ -+ int i; -+ putchar('\r'); -+ for (i = 0; i < cmdbuf_len + 2; i++) -+ putchar(' '); -+} -+ -+ -+static void move_start(void) -+{ -+ cmdbuf_pos = 0; -+ edit_redraw(); -+} -+ -+ -+static void move_end(void) -+{ -+ cmdbuf_pos = cmdbuf_len; -+ edit_redraw(); -+} -+ -+ -+static void move_left(void) -+{ -+ if (cmdbuf_pos > 0) { -+ cmdbuf_pos--; -+ edit_redraw(); -+ } -+} -+ -+ -+static void move_right(void) -+{ -+ if (cmdbuf_pos < cmdbuf_len) { -+ cmdbuf_pos++; -+ edit_redraw(); -+ } -+} -+ -+ -+static void move_word_left(void) -+{ -+ while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] == ' ') -+ cmdbuf_pos--; -+ while (cmdbuf_pos > 0 && cmdbuf[cmdbuf_pos - 1] != ' ') -+ cmdbuf_pos--; -+ edit_redraw(); -+} -+ -+ -+static void move_word_right(void) -+{ -+ while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] == ' ') -+ cmdbuf_pos++; -+ while (cmdbuf_pos < cmdbuf_len && cmdbuf[cmdbuf_pos] != ' ') -+ cmdbuf_pos++; -+ edit_redraw(); -+} -+ -+ -+static void delete_left(void) -+{ -+ if (cmdbuf_pos == 0) -+ return; -+ -+ edit_clear_line(); -+ os_memmove(cmdbuf + cmdbuf_pos - 1, cmdbuf + cmdbuf_pos, -+ cmdbuf_len - cmdbuf_pos); -+ cmdbuf_pos--; -+ cmdbuf_len--; -+ edit_redraw(); -+} -+ -+ -+static void delete_current(void) -+{ -+ if (cmdbuf_pos == cmdbuf_len) -+ return; -+ -+ edit_clear_line(); -+ os_memmove(cmdbuf + cmdbuf_pos, cmdbuf + cmdbuf_pos + 1, -+ cmdbuf_len - cmdbuf_pos); -+ cmdbuf_len--; -+ edit_redraw(); -+} -+ -+ -+static void delete_word(void) -+{ -+ int pos; -+ -+ edit_clear_line(); -+ pos = cmdbuf_pos; -+ while (pos > 0 && cmdbuf[pos - 1] == ' ') -+ pos--; -+ while (pos > 0 && cmdbuf[pos - 1] != ' ') -+ pos--; -+ os_memmove(cmdbuf + pos, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos); -+ cmdbuf_len -= cmdbuf_pos - pos; -+ cmdbuf_pos = pos; -+ edit_redraw(); -+} -+ -+ -+static void clear_left(void) -+{ -+ if (cmdbuf_pos == 0) -+ return; -+ -+ edit_clear_line(); -+ os_memmove(cmdbuf, cmdbuf + cmdbuf_pos, cmdbuf_len - cmdbuf_pos); -+ cmdbuf_len -= cmdbuf_pos; -+ cmdbuf_pos = 0; -+ edit_redraw(); -+} -+ -+ -+static void clear_right(void) -+{ -+ if (cmdbuf_pos == cmdbuf_len) -+ return; -+ -+ edit_clear_line(); -+ cmdbuf_len = cmdbuf_pos; -+ edit_redraw(); -+} -+ -+ -+static void history_add(const char *str) -+{ -+ struct edit_history *h, *match = NULL, *last = NULL; -+ size_t len, count = 0; -+ -+ if (str[0] == '\0') -+ return; -+ -+ dl_list_for_each(h, &history_list, struct edit_history, list) { -+ if (os_strcmp(str, h->str) == 0) { -+ match = h; -+ break; -+ } -+ last = h; -+ count++; -+ } -+ -+ if (match) { -+ dl_list_del(&h->list); -+ dl_list_add(&history_list, &h->list); -+ history_curr = h; -+ return; -+ } -+ -+ if (count >= HISTORY_MAX && last) { -+ dl_list_del(&last->list); -+ os_free(last); -+ } -+ -+ len = os_strlen(str); -+ h = os_zalloc(sizeof(*h) + len); -+ if (h == NULL) -+ return; -+ dl_list_add(&history_list, &h->list); -+ os_strlcpy(h->str, str, len + 1); -+ history_curr = h; -+} -+ -+ -+static void history_use(void) -+{ -+ edit_clear_line(); -+ cmdbuf_len = cmdbuf_pos = os_strlen(history_curr->str); -+ os_memcpy(cmdbuf, history_curr->str, cmdbuf_len); -+ edit_redraw(); -+} -+ -+ -+static void history_prev(void) -+{ -+ if (history_curr == NULL) -+ return; -+ -+ if (history_curr == -+ dl_list_first(&history_list, struct edit_history, list)) { -+ cmdbuf[cmdbuf_len] = '\0'; -+ history_add(cmdbuf); -+ } -+ -+ history_use(); -+ -+ if (history_curr == -+ dl_list_last(&history_list, struct edit_history, list)) -+ return; -+ -+ history_curr = dl_list_entry(history_curr->list.next, -+ struct edit_history, list); -+} -+ -+ -+static void history_next(void) -+{ -+ if (history_curr == NULL || -+ history_curr == -+ dl_list_first(&history_list, struct edit_history, list)) -+ return; -+ -+ history_curr = dl_list_entry(history_curr->list.prev, -+ struct edit_history, list); -+ history_use(); -+} -+ -+ -+static void history_read(const char *fname) -+{ -+ FILE *f; -+ char buf[CMD_BUF_LEN], *pos; -+ -+ f = fopen(fname, "r"); -+ if (f == NULL) -+ return; -+ -+ while (fgets(buf, CMD_BUF_LEN, f)) { -+ for (pos = buf; *pos; pos++) { -+ if (*pos == '\r' || *pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ } -+ history_add(buf); -+ } -+ -+ fclose(f); -+} -+ -+ -+static void history_write(const char *fname, -+ int (*filter_cb)(void *ctx, const char *cmd)) -+{ -+ FILE *f; -+ struct edit_history *h; -+ -+ f = fopen(fname, "w"); -+ if (f == NULL) -+ return; -+ -+ dl_list_for_each_reverse(h, &history_list, struct edit_history, list) { -+ if (filter_cb && filter_cb(edit_cb_ctx, h->str)) -+ continue; -+ fprintf(f, "%s\n", h->str); -+ } -+ -+ fclose(f); -+} -+ -+ -+static void history_debug_dump(void) -+{ -+ struct edit_history *h; -+ edit_clear_line(); -+ printf("\r"); -+ dl_list_for_each_reverse(h, &history_list, struct edit_history, list) -+ printf("%s%s\n", h == history_curr ? "[C]" : "", h->str); -+ edit_redraw(); -+} -+ -+ -+static void insert_char(int c) -+{ -+ if (cmdbuf_len >= (int) sizeof(cmdbuf) - 1) -+ return; -+ if (cmdbuf_len == cmdbuf_pos) { -+ cmdbuf[cmdbuf_pos++] = c; -+ cmdbuf_len++; -+ putchar(c); -+ fflush(stdout); -+ } else { -+ os_memmove(cmdbuf + cmdbuf_pos + 1, cmdbuf + cmdbuf_pos, -+ cmdbuf_len - cmdbuf_pos); -+ cmdbuf[cmdbuf_pos++] = c; -+ cmdbuf_len++; -+ edit_redraw(); -+ } -+} -+ -+ -+static void process_cmd(void) -+{ -+ -+ if (cmdbuf_len == 0) { -+ printf("\n> "); -+ fflush(stdout); -+ return; -+ } -+ printf("\n"); -+ cmdbuf[cmdbuf_len] = '\0'; -+ history_add(cmdbuf); -+ cmdbuf_pos = 0; -+ cmdbuf_len = 0; -+ edit_cmd_cb(edit_cb_ctx, cmdbuf); -+ printf("> "); -+ fflush(stdout); -+} -+ -+ -+static void free_completions(char **c) -+{ -+ int i; -+ if (c == NULL) -+ return; -+ for (i = 0; c[i]; i++) -+ os_free(c[i]); -+ os_free(c); -+} -+ -+ -+static int filter_strings(char **c, char *str, size_t len) -+{ -+ int i, j; -+ -+ for (i = 0, j = 0; c[j]; j++) { -+ if (os_strncasecmp(c[j], str, len) == 0) { -+ if (i != j) { -+ c[i] = c[j]; -+ c[j] = NULL; -+ } -+ i++; -+ } else { -+ os_free(c[j]); -+ c[j] = NULL; -+ } -+ } -+ c[i] = NULL; -+ return i; -+} -+ -+ -+static int common_len(const char *a, const char *b) -+{ -+ int len = 0; -+ while (a[len] && a[len] == b[len]) -+ len++; -+ return len; -+} -+ -+ -+static int max_common_length(char **c) -+{ -+ int len, i; -+ -+ len = os_strlen(c[0]); -+ for (i = 1; c[i]; i++) { -+ int same = common_len(c[0], c[i]); -+ if (same < len) -+ len = same; -+ } -+ -+ return len; -+} -+ -+ -+static int cmp_str(const void *a, const void *b) -+{ -+ return os_strcmp(* (const char **) a, * (const char **) b); -+} -+ -+static void complete(int list) -+{ -+ char **c; -+ int i, len, count; -+ int start, end; -+ int room, plen, add_space; -+ -+ if (edit_completion_cb == NULL) -+ return; -+ -+ cmdbuf[cmdbuf_len] = '\0'; -+ c = edit_completion_cb(edit_cb_ctx, cmdbuf, cmdbuf_pos); -+ if (c == NULL) -+ return; -+ -+ end = cmdbuf_pos; -+ start = end; -+ while (start > 0 && cmdbuf[start - 1] != ' ') -+ start--; -+ plen = end - start; -+ -+ count = filter_strings(c, &cmdbuf[start], plen); -+ if (count == 0) { -+ free_completions(c); -+ return; -+ } -+ -+ len = max_common_length(c); -+ if (len <= plen && count > 1) { -+ if (list) { -+ qsort(c, count, sizeof(char *), cmp_str); -+ edit_clear_line(); -+ printf("\r"); -+ for (i = 0; c[i]; i++) -+ printf("%s%s", i > 0 ? " " : "", c[i]); -+ printf("\n"); -+ edit_redraw(); -+ } -+ free_completions(c); -+ return; -+ } -+ len -= plen; -+ -+ room = sizeof(cmdbuf) - 1 - cmdbuf_len; -+ if (room < len) -+ len = room; -+ add_space = count == 1 && len < room; -+ -+ os_memmove(cmdbuf + cmdbuf_pos + len + add_space, cmdbuf + cmdbuf_pos, -+ cmdbuf_len - cmdbuf_pos); -+ os_memcpy(&cmdbuf[cmdbuf_pos - plen], c[0], plen + len); -+ if (add_space) -+ cmdbuf[cmdbuf_pos + len] = ' '; -+ -+ cmdbuf_pos += len + add_space; -+ cmdbuf_len += len + add_space; -+ -+ edit_redraw(); -+ -+ free_completions(c); -+} -+ -+ -+enum edit_key_code { -+ EDIT_KEY_NONE = 256, -+ EDIT_KEY_TAB, -+ EDIT_KEY_UP, -+ EDIT_KEY_DOWN, -+ EDIT_KEY_RIGHT, -+ EDIT_KEY_LEFT, -+ EDIT_KEY_ENTER, -+ EDIT_KEY_BACKSPACE, -+ EDIT_KEY_INSERT, -+ EDIT_KEY_DELETE, -+ EDIT_KEY_HOME, -+ EDIT_KEY_END, -+ EDIT_KEY_PAGE_UP, -+ EDIT_KEY_PAGE_DOWN, -+ EDIT_KEY_F1, -+ EDIT_KEY_F2, -+ EDIT_KEY_F3, -+ EDIT_KEY_F4, -+ EDIT_KEY_F5, -+ EDIT_KEY_F6, -+ EDIT_KEY_F7, -+ EDIT_KEY_F8, -+ EDIT_KEY_F9, -+ EDIT_KEY_F10, -+ EDIT_KEY_F11, -+ EDIT_KEY_F12, -+ EDIT_KEY_CTRL_UP, -+ EDIT_KEY_CTRL_DOWN, -+ EDIT_KEY_CTRL_RIGHT, -+ EDIT_KEY_CTRL_LEFT, -+ EDIT_KEY_CTRL_A, -+ EDIT_KEY_CTRL_B, -+ EDIT_KEY_CTRL_D, -+ EDIT_KEY_CTRL_E, -+ EDIT_KEY_CTRL_F, -+ EDIT_KEY_CTRL_G, -+ EDIT_KEY_CTRL_H, -+ EDIT_KEY_CTRL_J, -+ EDIT_KEY_CTRL_K, -+ EDIT_KEY_CTRL_L, -+ EDIT_KEY_CTRL_N, -+ EDIT_KEY_CTRL_O, -+ EDIT_KEY_CTRL_P, -+ EDIT_KEY_CTRL_R, -+ EDIT_KEY_CTRL_T, -+ EDIT_KEY_CTRL_U, -+ EDIT_KEY_CTRL_V, -+ EDIT_KEY_CTRL_W, -+ EDIT_KEY_ALT_UP, -+ EDIT_KEY_ALT_DOWN, -+ EDIT_KEY_ALT_RIGHT, -+ EDIT_KEY_ALT_LEFT, -+ EDIT_KEY_SHIFT_UP, -+ EDIT_KEY_SHIFT_DOWN, -+ EDIT_KEY_SHIFT_RIGHT, -+ EDIT_KEY_SHIFT_LEFT, -+ EDIT_KEY_ALT_SHIFT_UP, -+ EDIT_KEY_ALT_SHIFT_DOWN, -+ EDIT_KEY_ALT_SHIFT_RIGHT, -+ EDIT_KEY_ALT_SHIFT_LEFT, -+ EDIT_KEY_EOF -+}; -+ -+static void show_esc_buf(const char *esc_buf, char c, int i) -+{ -+ edit_clear_line(); -+ printf("\rESC buffer '%s' c='%c' [%d]\n", esc_buf, c, i); -+ edit_redraw(); -+} -+ -+ -+static enum edit_key_code esc_seq_to_key1_no(char last) -+{ -+ switch (last) { -+ case 'A': -+ return EDIT_KEY_UP; -+ case 'B': -+ return EDIT_KEY_DOWN; -+ case 'C': -+ return EDIT_KEY_RIGHT; -+ case 'D': -+ return EDIT_KEY_LEFT; -+ default: -+ return EDIT_KEY_NONE; -+ } -+} -+ -+ -+static enum edit_key_code esc_seq_to_key1_shift(char last) -+{ -+ switch (last) { -+ case 'A': -+ return EDIT_KEY_SHIFT_UP; -+ case 'B': -+ return EDIT_KEY_SHIFT_DOWN; -+ case 'C': -+ return EDIT_KEY_SHIFT_RIGHT; -+ case 'D': -+ return EDIT_KEY_SHIFT_LEFT; -+ default: -+ return EDIT_KEY_NONE; -+ } -+} -+ -+ -+static enum edit_key_code esc_seq_to_key1_alt(char last) -+{ -+ switch (last) { -+ case 'A': -+ return EDIT_KEY_ALT_UP; -+ case 'B': -+ return EDIT_KEY_ALT_DOWN; -+ case 'C': -+ return EDIT_KEY_ALT_RIGHT; -+ case 'D': -+ return EDIT_KEY_ALT_LEFT; -+ default: -+ return EDIT_KEY_NONE; -+ } -+} -+ -+ -+static enum edit_key_code esc_seq_to_key1_alt_shift(char last) -+{ -+ switch (last) { -+ case 'A': -+ return EDIT_KEY_ALT_SHIFT_UP; -+ case 'B': -+ return EDIT_KEY_ALT_SHIFT_DOWN; -+ case 'C': -+ return EDIT_KEY_ALT_SHIFT_RIGHT; -+ case 'D': -+ return EDIT_KEY_ALT_SHIFT_LEFT; -+ default: -+ return EDIT_KEY_NONE; -+ } -+} -+ -+ -+static enum edit_key_code esc_seq_to_key1_ctrl(char last) -+{ -+ switch (last) { -+ case 'A': -+ return EDIT_KEY_CTRL_UP; -+ case 'B': -+ return EDIT_KEY_CTRL_DOWN; -+ case 'C': -+ return EDIT_KEY_CTRL_RIGHT; -+ case 'D': -+ return EDIT_KEY_CTRL_LEFT; -+ default: -+ return EDIT_KEY_NONE; -+ } -+} -+ -+ -+static enum edit_key_code esc_seq_to_key1(int param1, int param2, char last) -+{ -+ /* ESC-[; */ -+ -+ if (param1 < 0 && param2 < 0) -+ return esc_seq_to_key1_no(last); -+ -+ if (param1 == 1 && param2 == 2) -+ return esc_seq_to_key1_shift(last); -+ -+ if (param1 == 1 && param2 == 3) -+ return esc_seq_to_key1_alt(last); -+ -+ if (param1 == 1 && param2 == 4) -+ return esc_seq_to_key1_alt_shift(last); -+ -+ if (param1 == 1 && param2 == 5) -+ return esc_seq_to_key1_ctrl(last); -+ -+ if (param2 < 0) { -+ if (last != '~') -+ return EDIT_KEY_NONE; -+ switch (param1) { -+ case 2: -+ return EDIT_KEY_INSERT; -+ case 3: -+ return EDIT_KEY_DELETE; -+ case 5: -+ return EDIT_KEY_PAGE_UP; -+ case 6: -+ return EDIT_KEY_PAGE_DOWN; -+ case 15: -+ return EDIT_KEY_F5; -+ case 17: -+ return EDIT_KEY_F6; -+ case 18: -+ return EDIT_KEY_F7; -+ case 19: -+ return EDIT_KEY_F8; -+ case 20: -+ return EDIT_KEY_F9; -+ case 21: -+ return EDIT_KEY_F10; -+ case 23: -+ return EDIT_KEY_F11; -+ case 24: -+ return EDIT_KEY_F12; -+ } -+ } -+ -+ return EDIT_KEY_NONE; -+} -+ -+ -+static enum edit_key_code esc_seq_to_key2(int param1, int param2, char last) -+{ -+ /* ESC-O; */ -+ -+ if (param1 >= 0 || param2 >= 0) -+ return EDIT_KEY_NONE; -+ -+ switch (last) { -+ case 'F': -+ return EDIT_KEY_END; -+ case 'H': -+ return EDIT_KEY_HOME; -+ case 'P': -+ return EDIT_KEY_F1; -+ case 'Q': -+ return EDIT_KEY_F2; -+ case 'R': -+ return EDIT_KEY_F3; -+ case 'S': -+ return EDIT_KEY_F4; -+ default: -+ return EDIT_KEY_NONE; -+ } -+} -+ -+ -+static enum edit_key_code esc_seq_to_key(char *seq) -+{ -+ char last, *pos; -+ int param1 = -1, param2 = -1; -+ enum edit_key_code ret = EDIT_KEY_NONE; -+ -+ last = '\0'; -+ for (pos = seq; *pos; pos++) -+ last = *pos; -+ -+ if (seq[1] >= '0' && seq[1] <= '9') { -+ param1 = atoi(&seq[1]); -+ pos = os_strchr(seq, ';'); -+ if (pos) -+ param2 = atoi(pos + 1); -+ } -+ -+ if (seq[0] == '[') -+ ret = esc_seq_to_key1(param1, param2, last); -+ else if (seq[0] == 'O') -+ ret = esc_seq_to_key2(param1, param2, last); -+ -+ if (ret != EDIT_KEY_NONE) -+ return ret; -+ -+ edit_clear_line(); -+ printf("\rUnknown escape sequence '%s'\n", seq); -+ edit_redraw(); -+ return EDIT_KEY_NONE; -+} -+ -+ -+static enum edit_key_code edit_read_key(int sock) -+{ -+ int c; -+ unsigned char buf[1]; -+ int res; -+ static int esc = -1; -+ static char esc_buf[7]; -+ -+ res = read(sock, buf, 1); -+ if (res < 0) -+ perror("read"); -+ if (res <= 0) -+ return EDIT_KEY_EOF; -+ -+ c = buf[0]; -+ -+ if (esc >= 0) { -+ if (c == 27 /* ESC */) { -+ esc = 0; -+ return EDIT_KEY_NONE; -+ } -+ -+ if (esc == 6) { -+ show_esc_buf(esc_buf, c, 0); -+ esc = -1; -+ } else { -+ esc_buf[esc++] = c; -+ esc_buf[esc] = '\0'; -+ } -+ } -+ -+ if (esc == 1) { -+ if (esc_buf[0] != '[' && esc_buf[0] != 'O') { -+ show_esc_buf(esc_buf, c, 1); -+ esc = -1; -+ return EDIT_KEY_NONE; -+ } else -+ return EDIT_KEY_NONE; /* Escape sequence continues */ -+ } -+ -+ if (esc > 1) { -+ if ((c >= '0' && c <= '9') || c == ';') -+ return EDIT_KEY_NONE; /* Escape sequence continues */ -+ -+ if (c == '~' || (c >= 'A' && c <= 'Z')) { -+ esc = -1; -+ return esc_seq_to_key(esc_buf); -+ } -+ -+ show_esc_buf(esc_buf, c, 2); -+ esc = -1; -+ return EDIT_KEY_NONE; -+ } -+ -+ switch (c) { -+ case 1: -+ return EDIT_KEY_CTRL_A; -+ case 2: -+ return EDIT_KEY_CTRL_B; -+ case 4: -+ return EDIT_KEY_CTRL_D; -+ case 5: -+ return EDIT_KEY_CTRL_E; -+ case 6: -+ return EDIT_KEY_CTRL_F; -+ case 7: -+ return EDIT_KEY_CTRL_G; -+ case 8: -+ return EDIT_KEY_CTRL_H; -+ case 9: -+ return EDIT_KEY_TAB; -+ case 10: -+ return EDIT_KEY_CTRL_J; -+ case 13: /* CR */ -+ return EDIT_KEY_ENTER; -+ case 11: -+ return EDIT_KEY_CTRL_K; -+ case 12: -+ return EDIT_KEY_CTRL_L; -+ case 14: -+ return EDIT_KEY_CTRL_N; -+ case 15: -+ return EDIT_KEY_CTRL_O; -+ case 16: -+ return EDIT_KEY_CTRL_P; -+ case 18: -+ return EDIT_KEY_CTRL_R; -+ case 20: -+ return EDIT_KEY_CTRL_T; -+ case 21: -+ return EDIT_KEY_CTRL_U; -+ case 22: -+ return EDIT_KEY_CTRL_V; -+ case 23: -+ return EDIT_KEY_CTRL_W; -+ case 27: /* ESC */ -+ esc = 0; -+ return EDIT_KEY_NONE; -+ case 127: -+ return EDIT_KEY_BACKSPACE; -+ default: -+ return c; -+ } -+} -+ -+ -+static char search_buf[21]; -+static int search_skip; -+ -+static char * search_find(void) -+{ -+ struct edit_history *h; -+ size_t len = os_strlen(search_buf); -+ int skip = search_skip; -+ -+ if (len == 0) -+ return NULL; -+ -+ dl_list_for_each(h, &history_list, struct edit_history, list) { -+ if (os_strstr(h->str, search_buf)) { -+ if (skip == 0) -+ return h->str; -+ skip--; -+ } -+ } -+ -+ search_skip = 0; -+ return NULL; -+} -+ -+ -+static void search_redraw(void) -+{ -+ char *match = search_find(); -+ printf("\rsearch '%s': %s" CLEAR_END_LINE, -+ search_buf, match ? match : ""); -+ printf("\rsearch '%s", search_buf); -+ fflush(stdout); -+} -+ -+ -+static void search_start(void) -+{ -+ edit_clear_line(); -+ search_buf[0] = '\0'; -+ search_skip = 0; -+ search_redraw(); -+} -+ -+ -+static void search_clear(void) -+{ -+ search_redraw(); -+ printf("\r" CLEAR_END_LINE); -+} -+ -+ -+static void search_stop(void) -+{ -+ char *match = search_find(); -+ search_buf[0] = '\0'; -+ search_clear(); -+ if (match) { -+ os_strlcpy(cmdbuf, match, CMD_BUF_LEN); -+ cmdbuf_len = os_strlen(cmdbuf); -+ cmdbuf_pos = cmdbuf_len; -+ } -+ edit_redraw(); -+} -+ -+ -+static void search_cancel(void) -+{ -+ search_buf[0] = '\0'; -+ search_clear(); -+ edit_redraw(); -+} -+ -+ -+static void search_backspace(void) -+{ -+ size_t len; -+ len = os_strlen(search_buf); -+ if (len == 0) -+ return; -+ search_buf[len - 1] = '\0'; -+ search_skip = 0; -+ search_redraw(); -+} -+ -+ -+static void search_next(void) -+{ -+ search_skip++; -+ search_find(); -+ search_redraw(); -+} -+ -+ -+static void search_char(char c) -+{ -+ size_t len; -+ len = os_strlen(search_buf); -+ if (len == sizeof(search_buf) - 1) -+ return; -+ search_buf[len] = c; -+ search_buf[len + 1] = '\0'; -+ search_skip = 0; -+ search_redraw(); -+} -+ -+ -+static enum edit_key_code search_key(enum edit_key_code c) -+{ -+ switch (c) { -+ case EDIT_KEY_ENTER: -+ case EDIT_KEY_CTRL_J: -+ case EDIT_KEY_LEFT: -+ case EDIT_KEY_RIGHT: -+ case EDIT_KEY_HOME: -+ case EDIT_KEY_END: -+ case EDIT_KEY_CTRL_A: -+ case EDIT_KEY_CTRL_E: -+ search_stop(); -+ return c; -+ case EDIT_KEY_DOWN: -+ case EDIT_KEY_UP: -+ search_cancel(); -+ return EDIT_KEY_EOF; -+ case EDIT_KEY_CTRL_H: -+ case EDIT_KEY_BACKSPACE: -+ search_backspace(); -+ break; -+ case EDIT_KEY_CTRL_R: -+ search_next(); -+ break; -+ default: -+ if (c >= 32 && c <= 255) -+ search_char(c); -+ break; -+ } -+ -+ return EDIT_KEY_NONE; -+} -+ -+ -+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ static int last_tab = 0; -+ static int search = 0; -+ enum edit_key_code c; -+ -+ c = edit_read_key(sock); -+ -+ if (search) { -+ c = search_key(c); -+ if (c == EDIT_KEY_NONE) -+ return; -+ search = 0; -+ if (c == EDIT_KEY_EOF) -+ return; -+ } -+ -+ if (c != EDIT_KEY_TAB && c != EDIT_KEY_NONE) -+ last_tab = 0; -+ -+ switch (c) { -+ case EDIT_KEY_NONE: -+ break; -+ case EDIT_KEY_EOF: -+ edit_eof_cb(edit_cb_ctx); -+ break; -+ case EDIT_KEY_TAB: -+ complete(last_tab); -+ last_tab = 1; -+ break; -+ case EDIT_KEY_UP: -+ case EDIT_KEY_CTRL_P: -+ history_prev(); -+ break; -+ case EDIT_KEY_DOWN: -+ case EDIT_KEY_CTRL_N: -+ history_next(); -+ break; -+ case EDIT_KEY_RIGHT: -+ case EDIT_KEY_CTRL_F: -+ move_right(); -+ break; -+ case EDIT_KEY_LEFT: -+ case EDIT_KEY_CTRL_B: -+ move_left(); -+ break; -+ case EDIT_KEY_CTRL_RIGHT: -+ move_word_right(); -+ break; -+ case EDIT_KEY_CTRL_LEFT: -+ move_word_left(); -+ break; -+ case EDIT_KEY_DELETE: -+ delete_current(); -+ break; -+ case EDIT_KEY_END: -+ move_end(); -+ break; -+ case EDIT_KEY_HOME: -+ case EDIT_KEY_CTRL_A: -+ move_start(); -+ break; -+ case EDIT_KEY_F2: -+ history_debug_dump(); -+ break; -+ case EDIT_KEY_CTRL_D: -+ if (cmdbuf_len > 0) { -+ delete_current(); -+ return; -+ } -+ printf("\n"); -+ edit_eof_cb(edit_cb_ctx); -+ break; -+ case EDIT_KEY_CTRL_E: -+ move_end(); -+ break; -+ case EDIT_KEY_CTRL_H: -+ case EDIT_KEY_BACKSPACE: -+ delete_left(); -+ break; -+ case EDIT_KEY_ENTER: -+ case EDIT_KEY_CTRL_J: -+ process_cmd(); -+ break; -+ case EDIT_KEY_CTRL_K: -+ clear_right(); -+ break; -+ case EDIT_KEY_CTRL_L: -+ edit_clear_line(); -+ edit_redraw(); -+ break; -+ case EDIT_KEY_CTRL_R: -+ search = 1; -+ search_start(); -+ break; -+ case EDIT_KEY_CTRL_U: -+ clear_left(); -+ break; -+ case EDIT_KEY_CTRL_W: -+ delete_word(); -+ break; -+ default: -+ if (c >= 32 && c <= 255) -+ insert_char(c); -+ break; -+ } -+} -+ -+ -+int edit_init(void (*cmd_cb)(void *ctx, char *cmd), -+ void (*eof_cb)(void *ctx), -+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos), -+ void *ctx, const char *history_file) -+{ -+ dl_list_init(&history_list); -+ history_curr = NULL; -+ if (history_file) -+ history_read(history_file); -+ -+ edit_cb_ctx = ctx; -+ edit_cmd_cb = cmd_cb; -+ edit_eof_cb = eof_cb; -+ edit_completion_cb = completion_cb; -+ -+ tcgetattr(STDIN_FILENO, &prevt); -+ newt = prevt; -+ newt.c_lflag &= ~(ICANON | ECHO); -+ tcsetattr(STDIN_FILENO, TCSANOW, &newt); -+ -+ eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); -+ -+ printf("> "); -+ fflush(stdout); -+ -+ return 0; -+} -+ -+ -+void edit_deinit(const char *history_file, -+ int (*filter_cb)(void *ctx, const char *cmd)) -+{ -+ struct edit_history *h; -+ if (history_file) -+ history_write(history_file, filter_cb); -+ while ((h = dl_list_first(&history_list, struct edit_history, list))) { -+ dl_list_del(&h->list); -+ os_free(h); -+ } -+ edit_clear_line(); -+ putchar('\r'); -+ fflush(stdout); -+ eloop_unregister_read_sock(STDIN_FILENO); -+ tcsetattr(STDIN_FILENO, TCSANOW, &prevt); -+} -+ -+ -+void edit_redraw(void) -+{ -+ char tmp; -+ cmdbuf[cmdbuf_len] = '\0'; -+ printf("\r> %s", cmdbuf); -+ if (cmdbuf_pos != cmdbuf_len) { -+ tmp = cmdbuf[cmdbuf_pos]; -+ cmdbuf[cmdbuf_pos] = '\0'; -+ printf("\r> %s", cmdbuf); -+ cmdbuf[cmdbuf_pos] = tmp; -+ } -+ fflush(stdout); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.h -new file mode 100644 -index 0000000000000..fc4474bd6ece7 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit.h -@@ -0,0 +1,27 @@ -+/* -+ * Command line editing and history -+ * Copyright (c) 2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef EDIT_H -+#define EDIT_H -+ -+int edit_init(void (*cmd_cb)(void *ctx, char *cmd), -+ void (*eof_cb)(void *ctx), -+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos), -+ void *ctx, const char *history_file); -+void edit_deinit(const char *history_file, -+ int (*filter_cb)(void *ctx, const char *cmd)); -+void edit_clear_line(void); -+void edit_redraw(void); -+ -+#endif /* EDIT_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_readline.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_readline.c -new file mode 100644 -index 0000000000000..1fef7b9c0e62c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_readline.c -@@ -0,0 +1,184 @@ -+/* -+ * Command line editing and history wrapper for readline -+ * Copyright (c) 2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "edit.h" -+ -+ -+static void *edit_cb_ctx; -+static void (*edit_cmd_cb)(void *ctx, char *cmd); -+static void (*edit_eof_cb)(void *ctx); -+static char ** (*edit_completion_cb)(void *ctx, const char *cmd, int pos) = -+ NULL; -+ -+static char **pending_completions = NULL; -+ -+ -+static void readline_free_completions(void) -+{ -+ int i; -+ if (pending_completions == NULL) -+ return; -+ for (i = 0; pending_completions[i]; i++) -+ os_free(pending_completions[i]); -+ os_free(pending_completions); -+ pending_completions = NULL; -+} -+ -+ -+static char * readline_completion_func(const char *text, int state) -+{ -+ static int pos = 0; -+ static size_t len = 0; -+ -+ if (pending_completions == NULL) { -+ rl_attempted_completion_over = 1; -+ return NULL; -+ } -+ -+ if (state == 0) { -+ pos = 0; -+ len = os_strlen(text); -+ } -+ for (; pending_completions[pos]; pos++) { -+ if (strncmp(pending_completions[pos], text, len) == 0) -+ return strdup(pending_completions[pos++]); -+ } -+ -+ rl_attempted_completion_over = 1; -+ return NULL; -+} -+ -+ -+static char ** readline_completion(const char *text, int start, int end) -+{ -+ readline_free_completions(); -+ if (edit_completion_cb) -+ pending_completions = edit_completion_cb(edit_cb_ctx, -+ rl_line_buffer, end); -+ return rl_completion_matches(text, readline_completion_func); -+} -+ -+ -+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ rl_callback_read_char(); -+} -+ -+ -+static void trunc_nl(char *str) -+{ -+ char *pos = str; -+ while (*pos != '\0') { -+ if (*pos == '\n') { -+ *pos = '\0'; -+ break; -+ } -+ pos++; -+ } -+} -+ -+ -+static void readline_cmd_handler(char *cmd) -+{ -+ if (cmd && *cmd) { -+ HIST_ENTRY *h; -+ while (next_history()) -+ ; -+ h = previous_history(); -+ if (h == NULL || os_strcmp(cmd, h->line) != 0) -+ add_history(cmd); -+ next_history(); -+ } -+ if (cmd == NULL) { -+ edit_eof_cb(edit_cb_ctx); -+ return; -+ } -+ trunc_nl(cmd); -+ edit_cmd_cb(edit_cb_ctx, cmd); -+} -+ -+ -+int edit_init(void (*cmd_cb)(void *ctx, char *cmd), -+ void (*eof_cb)(void *ctx), -+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos), -+ void *ctx, const char *history_file) -+{ -+ edit_cb_ctx = ctx; -+ edit_cmd_cb = cmd_cb; -+ edit_eof_cb = eof_cb; -+ edit_completion_cb = completion_cb; -+ -+ rl_attempted_completion_function = readline_completion; -+ if (history_file) { -+ read_history(history_file); -+ stifle_history(100); -+ } -+ -+ eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); -+ -+ rl_callback_handler_install("> ", readline_cmd_handler); -+ -+ return 0; -+} -+ -+ -+void edit_deinit(const char *history_file, -+ int (*filter_cb)(void *ctx, const char *cmd)) -+{ -+ rl_callback_handler_remove(); -+ readline_free_completions(); -+ -+ eloop_unregister_read_sock(STDIN_FILENO); -+ -+ if (history_file) { -+ /* Save command history, excluding lines that may contain -+ * passwords. */ -+ HIST_ENTRY *h; -+ history_set_pos(0); -+ while ((h = current_history())) { -+ char *p = h->line; -+ while (*p == ' ' || *p == '\t') -+ p++; -+ if (filter_cb && filter_cb(edit_cb_ctx, p)) { -+ h = remove_history(where_history()); -+ if (h) { -+ os_free(h->line); -+ free(h->data); -+ os_free(h); -+ } else -+ next_history(); -+ } else -+ next_history(); -+ } -+ write_history(history_file); -+ } -+} -+ -+ -+void edit_clear_line(void) -+{ -+} -+ -+ -+void edit_redraw(void) -+{ -+ rl_on_new_line(); -+ rl_redisplay(); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_simple.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_simple.c -new file mode 100644 -index 0000000000000..61fb24e23d55f ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/edit_simple.c -@@ -0,0 +1,96 @@ -+/* -+ * Minimal command line editing -+ * Copyright (c) 2010, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "edit.h" -+ -+ -+#define CMD_BUF_LEN 256 -+static char cmdbuf[CMD_BUF_LEN]; -+static int cmdbuf_pos = 0; -+ -+static void *edit_cb_ctx; -+static void (*edit_cmd_cb)(void *ctx, char *cmd); -+static void (*edit_eof_cb)(void *ctx); -+ -+ -+static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ int c; -+ unsigned char buf[1]; -+ int res; -+ -+ res = read(sock, buf, 1); -+ if (res < 0) -+ perror("read"); -+ if (res <= 0) { -+ edit_eof_cb(edit_cb_ctx); -+ return; -+ } -+ c = buf[0]; -+ -+ if (c == '\r' || c == '\n') { -+ cmdbuf[cmdbuf_pos] = '\0'; -+ cmdbuf_pos = 0; -+ edit_cmd_cb(edit_cb_ctx, cmdbuf); -+ printf("> "); -+ fflush(stdout); -+ return; -+ } -+ -+ if (c >= 32 && c <= 255) { -+ if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) { -+ cmdbuf[cmdbuf_pos++] = c; -+ } -+ } -+} -+ -+ -+int edit_init(void (*cmd_cb)(void *ctx, char *cmd), -+ void (*eof_cb)(void *ctx), -+ char ** (*completion_cb)(void *ctx, const char *cmd, int pos), -+ void *ctx, const char *history_file) -+{ -+ edit_cb_ctx = ctx; -+ edit_cmd_cb = cmd_cb; -+ edit_eof_cb = eof_cb; -+ eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL); -+ -+ printf("> "); -+ fflush(stdout); -+ -+ return 0; -+} -+ -+ -+void edit_deinit(const char *history_file, -+ int (*filter_cb)(void *ctx, const char *cmd)) -+{ -+ eloop_unregister_read_sock(STDIN_FILENO); -+} -+ -+ -+void edit_clear_line(void) -+{ -+} -+ -+ -+void edit_redraw(void) -+{ -+ cmdbuf[cmdbuf_pos] = '\0'; -+ printf("\r> %s", cmdbuf); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.c -new file mode 100644 -index 0000000000000..b550c6323d600 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.c -@@ -0,0 +1,627 @@ -+/* -+ * Event loop based on select() loop -+ * Copyright (c) 2002-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "trace.h" -+#include "list.h" -+#include "eloop.h" -+ -+ -+struct eloop_sock { -+ int sock; -+ void *eloop_data; -+ void *user_data; -+ eloop_sock_handler handler; -+ WPA_TRACE_REF(eloop); -+ WPA_TRACE_REF(user); -+ WPA_TRACE_INFO -+}; -+ -+struct eloop_timeout { -+ struct dl_list list; -+ struct os_time time; -+ void *eloop_data; -+ void *user_data; -+ eloop_timeout_handler handler; -+ WPA_TRACE_REF(eloop); -+ WPA_TRACE_REF(user); -+ WPA_TRACE_INFO -+}; -+ -+struct eloop_signal { -+ int sig; -+ void *user_data; -+ eloop_signal_handler handler; -+ int signaled; -+}; -+ -+struct eloop_sock_table { -+ int count; -+ struct eloop_sock *table; -+ int changed; -+}; -+ -+struct eloop_data { -+ int max_sock; -+ -+ struct eloop_sock_table readers; -+ struct eloop_sock_table writers; -+ struct eloop_sock_table exceptions; -+ -+ struct dl_list timeout; -+ -+ int signal_count; -+ struct eloop_signal *signals; -+ int signaled; -+ int pending_terminate; -+ -+ int terminate; -+ int reader_table_changed; -+}; -+ -+static struct eloop_data eloop; -+ -+ -+#ifdef WPA_TRACE -+ -+static void eloop_sigsegv_handler(int sig) -+{ -+ wpa_trace_show("eloop SIGSEGV"); -+ abort(); -+} -+ -+static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) -+{ -+ int i; -+ if (table == NULL || table->table == NULL) -+ return; -+ for (i = 0; i < table->count; i++) { -+ wpa_trace_add_ref(&table->table[i], eloop, -+ table->table[i].eloop_data); -+ wpa_trace_add_ref(&table->table[i], user, -+ table->table[i].user_data); -+ } -+} -+ -+ -+static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) -+{ -+ int i; -+ if (table == NULL || table->table == NULL) -+ return; -+ for (i = 0; i < table->count; i++) { -+ wpa_trace_remove_ref(&table->table[i], eloop, -+ table->table[i].eloop_data); -+ wpa_trace_remove_ref(&table->table[i], user, -+ table->table[i].user_data); -+ } -+} -+ -+#else /* WPA_TRACE */ -+ -+#define eloop_trace_sock_add_ref(table) do { } while (0) -+#define eloop_trace_sock_remove_ref(table) do { } while (0) -+ -+#endif /* WPA_TRACE */ -+ -+ -+int eloop_init(void) -+{ -+ os_memset(&eloop, 0, sizeof(eloop)); -+ dl_list_init(&eloop.timeout); -+#ifdef WPA_TRACE -+ signal(SIGSEGV, eloop_sigsegv_handler); -+#endif /* WPA_TRACE */ -+ return 0; -+} -+ -+ -+static int eloop_sock_table_add_sock(struct eloop_sock_table *table, -+ int sock, eloop_sock_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_sock *tmp; -+ -+ if (table == NULL) -+ return -1; -+ -+ eloop_trace_sock_remove_ref(table); -+ tmp = (struct eloop_sock *) -+ os_realloc(table->table, -+ (table->count + 1) * sizeof(struct eloop_sock)); -+ if (tmp == NULL) -+ return -1; -+ -+ tmp[table->count].sock = sock; -+ tmp[table->count].eloop_data = eloop_data; -+ tmp[table->count].user_data = user_data; -+ tmp[table->count].handler = handler; -+ wpa_trace_record(&tmp[table->count]); -+ table->count++; -+ table->table = tmp; -+ if (sock > eloop.max_sock) -+ eloop.max_sock = sock; -+ table->changed = 1; -+ eloop_trace_sock_add_ref(table); -+ -+ return 0; -+} -+ -+ -+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, -+ int sock) -+{ -+ int i; -+ -+ if (table == NULL || table->table == NULL || table->count == 0) -+ return; -+ -+ for (i = 0; i < table->count; i++) { -+ if (table->table[i].sock == sock) -+ break; -+ } -+ if (i == table->count) -+ return; -+ eloop_trace_sock_remove_ref(table); -+ if (i != table->count - 1) { -+ os_memmove(&table->table[i], &table->table[i + 1], -+ (table->count - i - 1) * -+ sizeof(struct eloop_sock)); -+ } -+ table->count--; -+ table->changed = 1; -+ eloop_trace_sock_add_ref(table); -+} -+ -+ -+static void eloop_sock_table_set_fds(struct eloop_sock_table *table, -+ fd_set *fds) -+{ -+ int i; -+ -+ FD_ZERO(fds); -+ -+ if (table->table == NULL) -+ return; -+ -+ for (i = 0; i < table->count; i++) -+ FD_SET(table->table[i].sock, fds); -+} -+ -+ -+static void eloop_sock_table_dispatch(struct eloop_sock_table *table, -+ fd_set *fds) -+{ -+ int i; -+ -+ if (table == NULL || table->table == NULL) -+ return; -+ -+ table->changed = 0; -+ for (i = 0; i < table->count; i++) { -+ if (FD_ISSET(table->table[i].sock, fds)) { -+ table->table[i].handler(table->table[i].sock, -+ table->table[i].eloop_data, -+ table->table[i].user_data); -+ if (table->changed) -+ break; -+ } -+ } -+} -+ -+ -+static void eloop_sock_table_destroy(struct eloop_sock_table *table) -+{ -+ if (table) { -+ int i; -+ for (i = 0; i < table->count && table->table; i++) { -+ wpa_printf(MSG_INFO, "ELOOP: remaining socket: " -+ "sock=%d eloop_data=%p user_data=%p " -+ "handler=%p", -+ table->table[i].sock, -+ table->table[i].eloop_data, -+ table->table[i].user_data, -+ table->table[i].handler); -+ wpa_trace_dump_funcname("eloop unregistered socket " -+ "handler", -+ table->table[i].handler); -+ wpa_trace_dump("eloop sock", &table->table[i]); -+ } -+ os_free(table->table); -+ } -+} -+ -+ -+int eloop_register_read_sock(int sock, eloop_sock_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ return eloop_register_sock(sock, EVENT_TYPE_READ, handler, -+ eloop_data, user_data); -+} -+ -+ -+void eloop_unregister_read_sock(int sock) -+{ -+ eloop_unregister_sock(sock, EVENT_TYPE_READ); -+} -+ -+ -+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type) -+{ -+ switch (type) { -+ case EVENT_TYPE_READ: -+ return &eloop.readers; -+ case EVENT_TYPE_WRITE: -+ return &eloop.writers; -+ case EVENT_TYPE_EXCEPTION: -+ return &eloop.exceptions; -+ } -+ -+ return NULL; -+} -+ -+ -+int eloop_register_sock(int sock, eloop_event_type type, -+ eloop_sock_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_sock_table *table; -+ -+ table = eloop_get_sock_table(type); -+ return eloop_sock_table_add_sock(table, sock, handler, -+ eloop_data, user_data); -+} -+ -+ -+void eloop_unregister_sock(int sock, eloop_event_type type) -+{ -+ struct eloop_sock_table *table; -+ -+ table = eloop_get_sock_table(type); -+ eloop_sock_table_remove_sock(table, sock); -+} -+ -+ -+int eloop_register_timeout(unsigned int secs, unsigned int usecs, -+ eloop_timeout_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *timeout, *tmp; -+ os_time_t now_sec; -+ -+ timeout = os_zalloc(sizeof(*timeout)); -+ if (timeout == NULL) -+ return -1; -+ if (os_get_time(&timeout->time) < 0) { -+ os_free(timeout); -+ return -1; -+ } -+ now_sec = timeout->time.sec; -+ timeout->time.sec += secs; -+ if (timeout->time.sec < now_sec) { -+ /* -+ * Integer overflow - assume long enough timeout to be assumed -+ * to be infinite, i.e., the timeout would never happen. -+ */ -+ wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to " -+ "ever happen - ignore it", secs); -+ os_free(timeout); -+ return 0; -+ } -+ timeout->time.usec += usecs; -+ while (timeout->time.usec >= 1000000) { -+ timeout->time.sec++; -+ timeout->time.usec -= 1000000; -+ } -+ timeout->eloop_data = eloop_data; -+ timeout->user_data = user_data; -+ timeout->handler = handler; -+ wpa_trace_add_ref(timeout, eloop, eloop_data); -+ wpa_trace_add_ref(timeout, user, user_data); -+ wpa_trace_record(timeout); -+ -+ /* Maintain timeouts in order of increasing time */ -+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { -+ if (os_time_before(&timeout->time, &tmp->time)) { -+ dl_list_add(tmp->list.prev, &timeout->list); -+ return 0; -+ } -+ } -+ dl_list_add_tail(&eloop.timeout, &timeout->list); -+ -+ return 0; -+} -+ -+ -+static void eloop_remove_timeout(struct eloop_timeout *timeout) -+{ -+ dl_list_del(&timeout->list); -+ wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); -+ wpa_trace_remove_ref(timeout, user, timeout->user_data); -+ os_free(timeout); -+} -+ -+ -+int eloop_cancel_timeout(eloop_timeout_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *timeout, *prev; -+ int removed = 0; -+ -+ dl_list_for_each_safe(timeout, prev, &eloop.timeout, -+ struct eloop_timeout, list) { -+ if (timeout->handler == handler && -+ (timeout->eloop_data == eloop_data || -+ eloop_data == ELOOP_ALL_CTX) && -+ (timeout->user_data == user_data || -+ user_data == ELOOP_ALL_CTX)) { -+ eloop_remove_timeout(timeout); -+ removed++; -+ } -+ } -+ -+ return removed; -+} -+ -+ -+int eloop_is_timeout_registered(eloop_timeout_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *tmp; -+ -+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) { -+ if (tmp->handler == handler && -+ tmp->eloop_data == eloop_data && -+ tmp->user_data == user_data) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+static void eloop_handle_alarm(int sig) -+{ -+ wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in " -+ "two seconds. Looks like there\n" -+ "is a bug that ends up in a busy loop that " -+ "prevents clean shutdown.\n" -+ "Killing program forcefully.\n"); -+ exit(1); -+} -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ -+static void eloop_handle_signal(int sig) -+{ -+ int i; -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+ if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { -+ /* Use SIGALRM to break out from potential busy loops that -+ * would not allow the program to be killed. */ -+ eloop.pending_terminate = 1; -+ signal(SIGALRM, eloop_handle_alarm); -+ alarm(2); -+ } -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ eloop.signaled++; -+ for (i = 0; i < eloop.signal_count; i++) { -+ if (eloop.signals[i].sig == sig) { -+ eloop.signals[i].signaled++; -+ break; -+ } -+ } -+} -+ -+ -+static void eloop_process_pending_signals(void) -+{ -+ int i; -+ -+ if (eloop.signaled == 0) -+ return; -+ eloop.signaled = 0; -+ -+ if (eloop.pending_terminate) { -+#ifndef CONFIG_NATIVE_WINDOWS -+ alarm(0); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ eloop.pending_terminate = 0; -+ } -+ -+ for (i = 0; i < eloop.signal_count; i++) { -+ if (eloop.signals[i].signaled) { -+ eloop.signals[i].signaled = 0; -+ eloop.signals[i].handler(eloop.signals[i].sig, -+ eloop.signals[i].user_data); -+ } -+ } -+} -+ -+ -+int eloop_register_signal(int sig, eloop_signal_handler handler, -+ void *user_data) -+{ -+ struct eloop_signal *tmp; -+ -+ tmp = (struct eloop_signal *) -+ os_realloc(eloop.signals, -+ (eloop.signal_count + 1) * -+ sizeof(struct eloop_signal)); -+ if (tmp == NULL) -+ return -1; -+ -+ tmp[eloop.signal_count].sig = sig; -+ tmp[eloop.signal_count].user_data = user_data; -+ tmp[eloop.signal_count].handler = handler; -+ tmp[eloop.signal_count].signaled = 0; -+ eloop.signal_count++; -+ eloop.signals = tmp; -+ signal(sig, eloop_handle_signal); -+ -+ return 0; -+} -+ -+ -+int eloop_register_signal_terminate(eloop_signal_handler handler, -+ void *user_data) -+{ -+ int ret = eloop_register_signal(SIGINT, handler, user_data); -+ if (ret == 0) -+ ret = eloop_register_signal(SIGTERM, handler, user_data); -+ return ret; -+} -+ -+ -+int eloop_register_signal_reconfig(eloop_signal_handler handler, -+ void *user_data) -+{ -+#ifdef CONFIG_NATIVE_WINDOWS -+ return 0; -+#else /* CONFIG_NATIVE_WINDOWS */ -+ return eloop_register_signal(SIGHUP, handler, user_data); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+} -+ -+ -+void eloop_run(void) -+{ -+ fd_set *rfds, *wfds, *efds; -+ int res; -+ struct timeval _tv; -+ struct os_time tv, now; -+ -+ rfds = os_malloc(sizeof(*rfds)); -+ wfds = os_malloc(sizeof(*wfds)); -+ efds = os_malloc(sizeof(*efds)); -+ if (rfds == NULL || wfds == NULL || efds == NULL) -+ goto out; -+ -+ while (!eloop.terminate && -+ (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || -+ eloop.writers.count > 0 || eloop.exceptions.count > 0)) { -+ struct eloop_timeout *timeout; -+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, -+ list); -+ if (timeout) { -+ os_get_time(&now); -+ if (os_time_before(&now, &timeout->time)) -+ os_time_sub(&timeout->time, &now, &tv); -+ else -+ tv.sec = tv.usec = 0; -+ _tv.tv_sec = tv.sec; -+ _tv.tv_usec = tv.usec; -+ } -+ -+ eloop_sock_table_set_fds(&eloop.readers, rfds); -+ eloop_sock_table_set_fds(&eloop.writers, wfds); -+ eloop_sock_table_set_fds(&eloop.exceptions, efds); -+ res = select(eloop.max_sock + 1, rfds, wfds, efds, -+ timeout ? &_tv : NULL); -+ if (res < 0 && errno != EINTR && errno != 0) { -+ perror("select"); -+ goto out; -+ } -+ eloop_process_pending_signals(); -+ -+ /* check if some registered timeouts have occurred */ -+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, -+ list); -+ if (timeout) { -+ os_get_time(&now); -+ if (!os_time_before(&now, &timeout->time)) { -+ void *eloop_data = timeout->eloop_data; -+ void *user_data = timeout->user_data; -+ eloop_timeout_handler handler = -+ timeout->handler; -+ eloop_remove_timeout(timeout); -+ handler(eloop_data, user_data); -+ } -+ -+ } -+ -+ if (res <= 0) -+ continue; -+ -+ eloop_sock_table_dispatch(&eloop.readers, rfds); -+ eloop_sock_table_dispatch(&eloop.writers, wfds); -+ eloop_sock_table_dispatch(&eloop.exceptions, efds); -+ } -+ -+out: -+ os_free(rfds); -+ os_free(wfds); -+ os_free(efds); -+} -+ -+ -+void eloop_terminate(void) -+{ -+ eloop.terminate = 1; -+} -+ -+ -+void eloop_destroy(void) -+{ -+ struct eloop_timeout *timeout, *prev; -+ struct os_time now; -+ -+ os_get_time(&now); -+ dl_list_for_each_safe(timeout, prev, &eloop.timeout, -+ struct eloop_timeout, list) { -+ int sec, usec; -+ sec = timeout->time.sec - now.sec; -+ usec = timeout->time.usec - now.usec; -+ if (timeout->time.usec < now.usec) { -+ sec--; -+ usec += 1000000; -+ } -+ wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d " -+ "eloop_data=%p user_data=%p handler=%p", -+ sec, usec, timeout->eloop_data, timeout->user_data, -+ timeout->handler); -+ wpa_trace_dump_funcname("eloop unregistered timeout handler", -+ timeout->handler); -+ wpa_trace_dump("eloop timeout", timeout); -+ eloop_remove_timeout(timeout); -+ } -+ eloop_sock_table_destroy(&eloop.readers); -+ eloop_sock_table_destroy(&eloop.writers); -+ eloop_sock_table_destroy(&eloop.exceptions); -+ os_free(eloop.signals); -+} -+ -+ -+int eloop_terminated(void) -+{ -+ return eloop.terminate; -+} -+ -+ -+void eloop_wait_for_read_sock(int sock) -+{ -+ fd_set rfds; -+ -+ if (sock < 0) -+ return; -+ -+ FD_ZERO(&rfds); -+ FD_SET(sock, &rfds); -+ select(sock + 1, &rfds, NULL, NULL, NULL); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.h -new file mode 100644 -index 0000000000000..1228f24d22c8c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop.h -@@ -0,0 +1,316 @@ -+/* -+ * Event loop -+ * Copyright (c) 2002-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file defines an event loop interface that supports processing events -+ * from registered timeouts (i.e., do something after N seconds), sockets -+ * (e.g., a new packet available for reading), and signals. eloop.c is an -+ * implementation of this interface using select() and sockets. This is -+ * suitable for most UNIX/POSIX systems. When porting to other operating -+ * systems, it may be necessary to replace that implementation with OS specific -+ * mechanisms. -+ */ -+ -+#ifndef ELOOP_H -+#define ELOOP_H -+ -+/** -+ * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts -+ */ -+#define ELOOP_ALL_CTX (void *) -1 -+ -+/** -+ * eloop_event_type - eloop socket event type for eloop_register_sock() -+ * @EVENT_TYPE_READ: Socket has data available for reading -+ * @EVENT_TYPE_WRITE: Socket has room for new data to be written -+ * @EVENT_TYPE_EXCEPTION: An exception has been reported -+ */ -+typedef enum { -+ EVENT_TYPE_READ = 0, -+ EVENT_TYPE_WRITE, -+ EVENT_TYPE_EXCEPTION -+} eloop_event_type; -+ -+/** -+ * eloop_sock_handler - eloop socket event callback type -+ * @sock: File descriptor number for the socket -+ * @eloop_ctx: Registered callback context data (eloop_data) -+ * @sock_ctx: Registered callback context data (user_data) -+ */ -+typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx); -+ -+/** -+ * eloop_event_handler - eloop generic event callback type -+ * @eloop_ctx: Registered callback context data (eloop_data) -+ * @sock_ctx: Registered callback context data (user_data) -+ */ -+typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx); -+ -+/** -+ * eloop_timeout_handler - eloop timeout event callback type -+ * @eloop_ctx: Registered callback context data (eloop_data) -+ * @sock_ctx: Registered callback context data (user_data) -+ */ -+typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx); -+ -+/** -+ * eloop_signal_handler - eloop signal event callback type -+ * @sig: Signal number -+ * @signal_ctx: Registered callback context data (user_data from -+ * eloop_register_signal(), eloop_register_signal_terminate(), or -+ * eloop_register_signal_reconfig() call) -+ */ -+typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); -+ -+/** -+ * eloop_init() - Initialize global event loop data -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function must be called before any other eloop_* function. -+ */ -+int eloop_init(void); -+ -+/** -+ * eloop_register_read_sock - Register handler for read events -+ * @sock: File descriptor number for the socket -+ * @handler: Callback function to be called when data is available for reading -+ * @eloop_data: Callback context data (eloop_ctx) -+ * @user_data: Callback context data (sock_ctx) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Register a read socket notifier for the given file descriptor. The handler -+ * function will be called whenever data is available for reading from the -+ * socket. The handler function is responsible for clearing the event after -+ * having processed it in order to avoid eloop from calling the handler again -+ * for the same event. -+ */ -+int eloop_register_read_sock(int sock, eloop_sock_handler handler, -+ void *eloop_data, void *user_data); -+ -+/** -+ * eloop_unregister_read_sock - Unregister handler for read events -+ * @sock: File descriptor number for the socket -+ * -+ * Unregister a read socket notifier that was previously registered with -+ * eloop_register_read_sock(). -+ */ -+void eloop_unregister_read_sock(int sock); -+ -+/** -+ * eloop_register_sock - Register handler for socket events -+ * @sock: File descriptor number for the socket -+ * @type: Type of event to wait for -+ * @handler: Callback function to be called when the event is triggered -+ * @eloop_data: Callback context data (eloop_ctx) -+ * @user_data: Callback context data (sock_ctx) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Register an event notifier for the given socket's file descriptor. The -+ * handler function will be called whenever the that event is triggered for the -+ * socket. The handler function is responsible for clearing the event after -+ * having processed it in order to avoid eloop from calling the handler again -+ * for the same event. -+ */ -+int eloop_register_sock(int sock, eloop_event_type type, -+ eloop_sock_handler handler, -+ void *eloop_data, void *user_data); -+ -+/** -+ * eloop_unregister_sock - Unregister handler for socket events -+ * @sock: File descriptor number for the socket -+ * @type: Type of event for which sock was registered -+ * -+ * Unregister a socket event notifier that was previously registered with -+ * eloop_register_sock(). -+ */ -+void eloop_unregister_sock(int sock, eloop_event_type type); -+ -+/** -+ * eloop_register_event - Register handler for generic events -+ * @event: Event to wait (eloop implementation specific) -+ * @event_size: Size of event data -+ * @handler: Callback function to be called when event is triggered -+ * @eloop_data: Callback context data (eloop_data) -+ * @user_data: Callback context data (user_data) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Register an event handler for the given event. This function is used to -+ * register eloop implementation specific events which are mainly targetted for -+ * operating system specific code (driver interface and l2_packet) since the -+ * portable code will not be able to use such an OS-specific call. The handler -+ * function will be called whenever the event is triggered. The handler -+ * function is responsible for clearing the event after having processed it in -+ * order to avoid eloop from calling the handler again for the same event. -+ * -+ * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE -+ * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable, -+ * and they would call this function with eloop_register_event(h, sizeof(h), -+ * ...). -+ */ -+int eloop_register_event(void *event, size_t event_size, -+ eloop_event_handler handler, -+ void *eloop_data, void *user_data); -+ -+/** -+ * eloop_unregister_event - Unregister handler for a generic event -+ * @event: Event to cancel (eloop implementation specific) -+ * @event_size: Size of event data -+ * -+ * Unregister a generic event notifier that was previously registered with -+ * eloop_register_event(). -+ */ -+void eloop_unregister_event(void *event, size_t event_size); -+ -+/** -+ * eloop_register_timeout - Register timeout -+ * @secs: Number of seconds to the timeout -+ * @usecs: Number of microseconds to the timeout -+ * @handler: Callback function to be called when timeout occurs -+ * @eloop_data: Callback context data (eloop_ctx) -+ * @user_data: Callback context data (sock_ctx) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Register a timeout that will cause the handler function to be called after -+ * given time. -+ */ -+int eloop_register_timeout(unsigned int secs, unsigned int usecs, -+ eloop_timeout_handler handler, -+ void *eloop_data, void *user_data); -+ -+/** -+ * eloop_cancel_timeout - Cancel timeouts -+ * @handler: Matching callback function -+ * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all -+ * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all -+ * Returns: Number of cancelled timeouts -+ * -+ * Cancel matching timeouts registered with -+ * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for -+ * cancelling all timeouts regardless of eloop_data/user_data. -+ */ -+int eloop_cancel_timeout(eloop_timeout_handler handler, -+ void *eloop_data, void *user_data); -+ -+/** -+ * eloop_is_timeout_registered - Check if a timeout is already registered -+ * @handler: Matching callback function -+ * @eloop_data: Matching eloop_data -+ * @user_data: Matching user_data -+ * Returns: 1 if the timeout is registered, 0 if the timeout is not registered -+ * -+ * Determine if a matching timeout is registered -+ * with eloop_register_timeout(). -+ */ -+int eloop_is_timeout_registered(eloop_timeout_handler handler, -+ void *eloop_data, void *user_data); -+ -+/** -+ * eloop_register_signal - Register handler for signals -+ * @sig: Signal number (e.g., SIGHUP) -+ * @handler: Callback function to be called when the signal is received -+ * @user_data: Callback context data (signal_ctx) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Register a callback function that will be called when a signal is received. -+ * The callback function is actually called only after the system signal -+ * handler has returned. This means that the normal limits for sighandlers -+ * (i.e., only "safe functions" allowed) do not apply for the registered -+ * callback. -+ */ -+int eloop_register_signal(int sig, eloop_signal_handler handler, -+ void *user_data); -+ -+/** -+ * eloop_register_signal_terminate - Register handler for terminate signals -+ * @handler: Callback function to be called when the signal is received -+ * @user_data: Callback context data (signal_ctx) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Register a callback function that will be called when a process termination -+ * signal is received. The callback function is actually called only after the -+ * system signal handler has returned. This means that the normal limits for -+ * sighandlers (i.e., only "safe functions" allowed) do not apply for the -+ * registered callback. -+ * -+ * This function is a more portable version of eloop_register_signal() since -+ * the knowledge of exact details of the signals is hidden in eloop -+ * implementation. In case of operating systems using signal(), this function -+ * registers handlers for SIGINT and SIGTERM. -+ */ -+int eloop_register_signal_terminate(eloop_signal_handler handler, -+ void *user_data); -+ -+/** -+ * eloop_register_signal_reconfig - Register handler for reconfig signals -+ * @handler: Callback function to be called when the signal is received -+ * @user_data: Callback context data (signal_ctx) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Register a callback function that will be called when a reconfiguration / -+ * hangup signal is received. The callback function is actually called only -+ * after the system signal handler has returned. This means that the normal -+ * limits for sighandlers (i.e., only "safe functions" allowed) do not apply -+ * for the registered callback. -+ * -+ * This function is a more portable version of eloop_register_signal() since -+ * the knowledge of exact details of the signals is hidden in eloop -+ * implementation. In case of operating systems using signal(), this function -+ * registers a handler for SIGHUP. -+ */ -+int eloop_register_signal_reconfig(eloop_signal_handler handler, -+ void *user_data); -+ -+/** -+ * eloop_run - Start the event loop -+ * -+ * Start the event loop and continue running as long as there are any -+ * registered event handlers. This function is run after event loop has been -+ * initialized with event_init() and one or more events have been registered. -+ */ -+void eloop_run(void); -+ -+/** -+ * eloop_terminate - Terminate event loop -+ * -+ * Terminate event loop even if there are registered events. This can be used -+ * to request the program to be terminated cleanly. -+ */ -+void eloop_terminate(void); -+ -+/** -+ * eloop_destroy - Free any resources allocated for the event loop -+ * -+ * After calling eloop_destroy(), other eloop_* functions must not be called -+ * before re-running eloop_init(). -+ */ -+void eloop_destroy(void); -+ -+/** -+ * eloop_terminated - Check whether event loop has been terminated -+ * Returns: 1 = event loop terminate, 0 = event loop still running -+ * -+ * This function can be used to check whether eloop_terminate() has been called -+ * to request termination of the event loop. This is normally used to abort -+ * operations that may still be queued to be run when eloop_terminate() was -+ * called. -+ */ -+int eloop_terminated(void); -+ -+/** -+ * eloop_wait_for_read_sock - Wait for a single reader -+ * @sock: File descriptor number for the socket -+ * -+ * Do a blocking wait for a single read socket. -+ */ -+void eloop_wait_for_read_sock(int sock); -+ -+#endif /* ELOOP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_none.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_none.c -new file mode 100644 -index 0000000000000..18eae4e5a7788 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_none.c -@@ -0,0 +1,401 @@ -+/* -+ * Event loop - empty template (basic structure, but no OS specific operations) -+ * Copyright (c) 2002-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+ -+ -+struct eloop_sock { -+ int sock; -+ void *eloop_data; -+ void *user_data; -+ void (*handler)(int sock, void *eloop_ctx, void *sock_ctx); -+}; -+ -+struct eloop_timeout { -+ struct os_time time; -+ void *eloop_data; -+ void *user_data; -+ void (*handler)(void *eloop_ctx, void *sock_ctx); -+ struct eloop_timeout *next; -+}; -+ -+struct eloop_signal { -+ int sig; -+ void *user_data; -+ void (*handler)(int sig, void *eloop_ctx, void *signal_ctx); -+ int signaled; -+}; -+ -+struct eloop_data { -+ int max_sock, reader_count; -+ struct eloop_sock *readers; -+ -+ struct eloop_timeout *timeout; -+ -+ int signal_count; -+ struct eloop_signal *signals; -+ int signaled; -+ int pending_terminate; -+ -+ int terminate; -+ int reader_table_changed; -+}; -+ -+static struct eloop_data eloop; -+ -+ -+int eloop_init(void) -+{ -+ memset(&eloop, 0, sizeof(eloop)); -+ return 0; -+} -+ -+ -+int eloop_register_read_sock(int sock, -+ void (*handler)(int sock, void *eloop_ctx, -+ void *sock_ctx), -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_sock *tmp; -+ -+ tmp = (struct eloop_sock *) -+ realloc(eloop.readers, -+ (eloop.reader_count + 1) * sizeof(struct eloop_sock)); -+ if (tmp == NULL) -+ return -1; -+ -+ tmp[eloop.reader_count].sock = sock; -+ tmp[eloop.reader_count].eloop_data = eloop_data; -+ tmp[eloop.reader_count].user_data = user_data; -+ tmp[eloop.reader_count].handler = handler; -+ eloop.reader_count++; -+ eloop.readers = tmp; -+ if (sock > eloop.max_sock) -+ eloop.max_sock = sock; -+ eloop.reader_table_changed = 1; -+ -+ return 0; -+} -+ -+ -+void eloop_unregister_read_sock(int sock) -+{ -+ int i; -+ -+ if (eloop.readers == NULL || eloop.reader_count == 0) -+ return; -+ -+ for (i = 0; i < eloop.reader_count; i++) { -+ if (eloop.readers[i].sock == sock) -+ break; -+ } -+ if (i == eloop.reader_count) -+ return; -+ if (i != eloop.reader_count - 1) { -+ memmove(&eloop.readers[i], &eloop.readers[i + 1], -+ (eloop.reader_count - i - 1) * -+ sizeof(struct eloop_sock)); -+ } -+ eloop.reader_count--; -+ eloop.reader_table_changed = 1; -+} -+ -+ -+int eloop_register_timeout(unsigned int secs, unsigned int usecs, -+ void (*handler)(void *eloop_ctx, void *timeout_ctx), -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *timeout, *tmp, *prev; -+ -+ timeout = (struct eloop_timeout *) malloc(sizeof(*timeout)); -+ if (timeout == NULL) -+ return -1; -+ os_get_time(&timeout->time); -+ timeout->time.sec += secs; -+ timeout->time.usec += usecs; -+ while (timeout->time.usec >= 1000000) { -+ timeout->time.sec++; -+ timeout->time.usec -= 1000000; -+ } -+ timeout->eloop_data = eloop_data; -+ timeout->user_data = user_data; -+ timeout->handler = handler; -+ timeout->next = NULL; -+ -+ if (eloop.timeout == NULL) { -+ eloop.timeout = timeout; -+ return 0; -+ } -+ -+ prev = NULL; -+ tmp = eloop.timeout; -+ while (tmp != NULL) { -+ if (os_time_before(&timeout->time, &tmp->time)) -+ break; -+ prev = tmp; -+ tmp = tmp->next; -+ } -+ -+ if (prev == NULL) { -+ timeout->next = eloop.timeout; -+ eloop.timeout = timeout; -+ } else { -+ timeout->next = prev->next; -+ prev->next = timeout; -+ } -+ -+ return 0; -+} -+ -+ -+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx), -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *timeout, *prev, *next; -+ int removed = 0; -+ -+ prev = NULL; -+ timeout = eloop.timeout; -+ while (timeout != NULL) { -+ next = timeout->next; -+ -+ if (timeout->handler == handler && -+ (timeout->eloop_data == eloop_data || -+ eloop_data == ELOOP_ALL_CTX) && -+ (timeout->user_data == user_data || -+ user_data == ELOOP_ALL_CTX)) { -+ if (prev == NULL) -+ eloop.timeout = next; -+ else -+ prev->next = next; -+ free(timeout); -+ removed++; -+ } else -+ prev = timeout; -+ -+ timeout = next; -+ } -+ -+ return removed; -+} -+ -+ -+int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx, -+ void *timeout_ctx), -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *tmp; -+ -+ tmp = eloop.timeout; -+ while (tmp != NULL) { -+ if (tmp->handler == handler && -+ tmp->eloop_data == eloop_data && -+ tmp->user_data == user_data) -+ return 1; -+ -+ tmp = tmp->next; -+ } -+ -+ return 0; -+} -+ -+ -+/* TODO: replace with suitable signal handler */ -+#if 0 -+static void eloop_handle_signal(int sig) -+{ -+ int i; -+ -+ eloop.signaled++; -+ for (i = 0; i < eloop.signal_count; i++) { -+ if (eloop.signals[i].sig == sig) { -+ eloop.signals[i].signaled++; -+ break; -+ } -+ } -+} -+#endif -+ -+ -+static void eloop_process_pending_signals(void) -+{ -+ int i; -+ -+ if (eloop.signaled == 0) -+ return; -+ eloop.signaled = 0; -+ -+ if (eloop.pending_terminate) { -+ eloop.pending_terminate = 0; -+ } -+ -+ for (i = 0; i < eloop.signal_count; i++) { -+ if (eloop.signals[i].signaled) { -+ eloop.signals[i].signaled = 0; -+ eloop.signals[i].handler(eloop.signals[i].sig, -+ eloop.user_data, -+ eloop.signals[i].user_data); -+ } -+ } -+} -+ -+ -+int eloop_register_signal(int sig, -+ void (*handler)(int sig, void *eloop_ctx, -+ void *signal_ctx), -+ void *user_data) -+{ -+ struct eloop_signal *tmp; -+ -+ tmp = (struct eloop_signal *) -+ realloc(eloop.signals, -+ (eloop.signal_count + 1) * -+ sizeof(struct eloop_signal)); -+ if (tmp == NULL) -+ return -1; -+ -+ tmp[eloop.signal_count].sig = sig; -+ tmp[eloop.signal_count].user_data = user_data; -+ tmp[eloop.signal_count].handler = handler; -+ tmp[eloop.signal_count].signaled = 0; -+ eloop.signal_count++; -+ eloop.signals = tmp; -+ -+ /* TODO: register signal handler */ -+ -+ return 0; -+} -+ -+ -+int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx, -+ void *signal_ctx), -+ void *user_data) -+{ -+#if 0 -+ /* TODO: for example */ -+ int ret = eloop_register_signal(SIGINT, handler, user_data); -+ if (ret == 0) -+ ret = eloop_register_signal(SIGTERM, handler, user_data); -+ return ret; -+#endif -+ return 0; -+} -+ -+ -+int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx, -+ void *signal_ctx), -+ void *user_data) -+{ -+#if 0 -+ /* TODO: for example */ -+ return eloop_register_signal(SIGHUP, handler, user_data); -+#endif -+ return 0; -+} -+ -+ -+void eloop_run(void) -+{ -+ int i; -+ struct os_time tv, now; -+ -+ while (!eloop.terminate && -+ (eloop.timeout || eloop.reader_count > 0)) { -+ if (eloop.timeout) { -+ os_get_time(&now); -+ if (os_time_before(&now, &eloop.timeout->time)) -+ os_time_sub(&eloop.timeout->time, &now, &tv); -+ else -+ tv.sec = tv.usec = 0; -+ } -+ -+ /* -+ * TODO: wait for any event (read socket ready, timeout (tv), -+ * signal -+ */ -+ os_sleep(1, 0); /* just a dummy wait for testing */ -+ -+ eloop_process_pending_signals(); -+ -+ /* check if some registered timeouts have occurred */ -+ if (eloop.timeout) { -+ struct eloop_timeout *tmp; -+ -+ os_get_time(&now); -+ if (!os_time_before(&now, &eloop.timeout->time)) { -+ tmp = eloop.timeout; -+ eloop.timeout = eloop.timeout->next; -+ tmp->handler(tmp->eloop_data, -+ tmp->user_data); -+ free(tmp); -+ } -+ -+ } -+ -+ eloop.reader_table_changed = 0; -+ for (i = 0; i < eloop.reader_count; i++) { -+ /* -+ * TODO: call each handler that has pending data to -+ * read -+ */ -+ if (0 /* TODO: eloop.readers[i].sock ready */) { -+ eloop.readers[i].handler( -+ eloop.readers[i].sock, -+ eloop.readers[i].eloop_data, -+ eloop.readers[i].user_data); -+ if (eloop.reader_table_changed) -+ break; -+ } -+ } -+ } -+} -+ -+ -+void eloop_terminate(void) -+{ -+ eloop.terminate = 1; -+} -+ -+ -+void eloop_destroy(void) -+{ -+ struct eloop_timeout *timeout, *prev; -+ -+ timeout = eloop.timeout; -+ while (timeout != NULL) { -+ prev = timeout; -+ timeout = timeout->next; -+ free(prev); -+ } -+ free(eloop.readers); -+ free(eloop.signals); -+} -+ -+ -+int eloop_terminated(void) -+{ -+ return eloop.terminate; -+} -+ -+ -+void eloop_wait_for_read_sock(int sock) -+{ -+ /* -+ * TODO: wait for the file descriptor to have something available for -+ * reading -+ */ -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_win.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_win.c -new file mode 100644 -index 0000000000000..c726ece25de23 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/eloop_win.c -@@ -0,0 +1,623 @@ -+/* -+ * Event loop based on Windows events and WaitForMultipleObjects -+ * Copyright (c) 2002-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "eloop.h" -+ -+ -+struct eloop_sock { -+ int sock; -+ void *eloop_data; -+ void *user_data; -+ eloop_sock_handler handler; -+ WSAEVENT event; -+}; -+ -+struct eloop_event { -+ void *eloop_data; -+ void *user_data; -+ eloop_event_handler handler; -+ HANDLE event; -+}; -+ -+struct eloop_timeout { -+ struct os_time time; -+ void *eloop_data; -+ void *user_data; -+ eloop_timeout_handler handler; -+ struct eloop_timeout *next; -+}; -+ -+struct eloop_signal { -+ int sig; -+ void *user_data; -+ eloop_signal_handler handler; -+ int signaled; -+}; -+ -+struct eloop_data { -+ int max_sock; -+ size_t reader_count; -+ struct eloop_sock *readers; -+ -+ size_t event_count; -+ struct eloop_event *events; -+ -+ struct eloop_timeout *timeout; -+ -+ int signal_count; -+ struct eloop_signal *signals; -+ int signaled; -+ int pending_terminate; -+ -+ int terminate; -+ int reader_table_changed; -+ -+ struct eloop_signal term_signal; -+ HANDLE term_event; -+ -+ HANDLE *handles; -+ size_t num_handles; -+}; -+ -+static struct eloop_data eloop; -+ -+ -+int eloop_init(void) -+{ -+ os_memset(&eloop, 0, sizeof(eloop)); -+ eloop.num_handles = 1; -+ eloop.handles = os_malloc(eloop.num_handles * -+ sizeof(eloop.handles[0])); -+ if (eloop.handles == NULL) -+ return -1; -+ -+ eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL); -+ if (eloop.term_event == NULL) { -+ printf("CreateEvent() failed: %d\n", -+ (int) GetLastError()); -+ os_free(eloop.handles); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+static int eloop_prepare_handles(void) -+{ -+ HANDLE *n; -+ -+ if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8) -+ return 0; -+ n = os_realloc(eloop.handles, -+ eloop.num_handles * 2 * sizeof(eloop.handles[0])); -+ if (n == NULL) -+ return -1; -+ eloop.handles = n; -+ eloop.num_handles *= 2; -+ return 0; -+} -+ -+ -+int eloop_register_read_sock(int sock, eloop_sock_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ WSAEVENT event; -+ struct eloop_sock *tmp; -+ -+ if (eloop_prepare_handles()) -+ return -1; -+ -+ event = WSACreateEvent(); -+ if (event == WSA_INVALID_EVENT) { -+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError()); -+ return -1; -+ } -+ -+ if (WSAEventSelect(sock, event, FD_READ)) { -+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError()); -+ WSACloseEvent(event); -+ return -1; -+ } -+ tmp = os_realloc(eloop.readers, -+ (eloop.reader_count + 1) * sizeof(struct eloop_sock)); -+ if (tmp == NULL) { -+ WSAEventSelect(sock, event, 0); -+ WSACloseEvent(event); -+ return -1; -+ } -+ -+ tmp[eloop.reader_count].sock = sock; -+ tmp[eloop.reader_count].eloop_data = eloop_data; -+ tmp[eloop.reader_count].user_data = user_data; -+ tmp[eloop.reader_count].handler = handler; -+ tmp[eloop.reader_count].event = event; -+ eloop.reader_count++; -+ eloop.readers = tmp; -+ if (sock > eloop.max_sock) -+ eloop.max_sock = sock; -+ eloop.reader_table_changed = 1; -+ -+ return 0; -+} -+ -+ -+void eloop_unregister_read_sock(int sock) -+{ -+ size_t i; -+ -+ if (eloop.readers == NULL || eloop.reader_count == 0) -+ return; -+ -+ for (i = 0; i < eloop.reader_count; i++) { -+ if (eloop.readers[i].sock == sock) -+ break; -+ } -+ if (i == eloop.reader_count) -+ return; -+ -+ WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0); -+ WSACloseEvent(eloop.readers[i].event); -+ -+ if (i != eloop.reader_count - 1) { -+ os_memmove(&eloop.readers[i], &eloop.readers[i + 1], -+ (eloop.reader_count - i - 1) * -+ sizeof(struct eloop_sock)); -+ } -+ eloop.reader_count--; -+ eloop.reader_table_changed = 1; -+} -+ -+ -+int eloop_register_event(void *event, size_t event_size, -+ eloop_event_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_event *tmp; -+ HANDLE h = event; -+ -+ if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE) -+ return -1; -+ -+ if (eloop_prepare_handles()) -+ return -1; -+ -+ tmp = os_realloc(eloop.events, -+ (eloop.event_count + 1) * sizeof(struct eloop_event)); -+ if (tmp == NULL) -+ return -1; -+ -+ tmp[eloop.event_count].eloop_data = eloop_data; -+ tmp[eloop.event_count].user_data = user_data; -+ tmp[eloop.event_count].handler = handler; -+ tmp[eloop.event_count].event = h; -+ eloop.event_count++; -+ eloop.events = tmp; -+ -+ return 0; -+} -+ -+ -+void eloop_unregister_event(void *event, size_t event_size) -+{ -+ size_t i; -+ HANDLE h = event; -+ -+ if (eloop.events == NULL || eloop.event_count == 0 || -+ event_size != sizeof(HANDLE)) -+ return; -+ -+ for (i = 0; i < eloop.event_count; i++) { -+ if (eloop.events[i].event == h) -+ break; -+ } -+ if (i == eloop.event_count) -+ return; -+ -+ if (i != eloop.event_count - 1) { -+ os_memmove(&eloop.events[i], &eloop.events[i + 1], -+ (eloop.event_count - i - 1) * -+ sizeof(struct eloop_event)); -+ } -+ eloop.event_count--; -+} -+ -+ -+int eloop_register_timeout(unsigned int secs, unsigned int usecs, -+ eloop_timeout_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *timeout, *tmp, *prev; -+ os_time_t now_sec; -+ -+ timeout = os_malloc(sizeof(*timeout)); -+ if (timeout == NULL) -+ return -1; -+ os_get_time(&timeout->time); -+ now_sec = timeout->time.sec; -+ timeout->time.sec += secs; -+ if (timeout->time.sec < now_sec) { -+ /* -+ * Integer overflow - assume long enough timeout to be assumed -+ * to be infinite, i.e., the timeout would never happen. -+ */ -+ wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to " -+ "ever happen - ignore it", secs); -+ os_free(timeout); -+ return 0; -+ } -+ timeout->time.usec += usecs; -+ while (timeout->time.usec >= 1000000) { -+ timeout->time.sec++; -+ timeout->time.usec -= 1000000; -+ } -+ timeout->eloop_data = eloop_data; -+ timeout->user_data = user_data; -+ timeout->handler = handler; -+ timeout->next = NULL; -+ -+ if (eloop.timeout == NULL) { -+ eloop.timeout = timeout; -+ return 0; -+ } -+ -+ prev = NULL; -+ tmp = eloop.timeout; -+ while (tmp != NULL) { -+ if (os_time_before(&timeout->time, &tmp->time)) -+ break; -+ prev = tmp; -+ tmp = tmp->next; -+ } -+ -+ if (prev == NULL) { -+ timeout->next = eloop.timeout; -+ eloop.timeout = timeout; -+ } else { -+ timeout->next = prev->next; -+ prev->next = timeout; -+ } -+ -+ return 0; -+} -+ -+ -+int eloop_cancel_timeout(eloop_timeout_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *timeout, *prev, *next; -+ int removed = 0; -+ -+ prev = NULL; -+ timeout = eloop.timeout; -+ while (timeout != NULL) { -+ next = timeout->next; -+ -+ if (timeout->handler == handler && -+ (timeout->eloop_data == eloop_data || -+ eloop_data == ELOOP_ALL_CTX) && -+ (timeout->user_data == user_data || -+ user_data == ELOOP_ALL_CTX)) { -+ if (prev == NULL) -+ eloop.timeout = next; -+ else -+ prev->next = next; -+ os_free(timeout); -+ removed++; -+ } else -+ prev = timeout; -+ -+ timeout = next; -+ } -+ -+ return removed; -+} -+ -+ -+int eloop_is_timeout_registered(eloop_timeout_handler handler, -+ void *eloop_data, void *user_data) -+{ -+ struct eloop_timeout *tmp; -+ -+ tmp = eloop.timeout; -+ while (tmp != NULL) { -+ if (tmp->handler == handler && -+ tmp->eloop_data == eloop_data && -+ tmp->user_data == user_data) -+ return 1; -+ -+ tmp = tmp->next; -+ } -+ -+ return 0; -+} -+ -+ -+/* TODO: replace with suitable signal handler */ -+#if 0 -+static void eloop_handle_signal(int sig) -+{ -+ int i; -+ -+ eloop.signaled++; -+ for (i = 0; i < eloop.signal_count; i++) { -+ if (eloop.signals[i].sig == sig) { -+ eloop.signals[i].signaled++; -+ break; -+ } -+ } -+} -+#endif -+ -+ -+static void eloop_process_pending_signals(void) -+{ -+ int i; -+ -+ if (eloop.signaled == 0) -+ return; -+ eloop.signaled = 0; -+ -+ if (eloop.pending_terminate) { -+ eloop.pending_terminate = 0; -+ } -+ -+ for (i = 0; i < eloop.signal_count; i++) { -+ if (eloop.signals[i].signaled) { -+ eloop.signals[i].signaled = 0; -+ eloop.signals[i].handler(eloop.signals[i].sig, -+ eloop.signals[i].user_data); -+ } -+ } -+ -+ if (eloop.term_signal.signaled) { -+ eloop.term_signal.signaled = 0; -+ eloop.term_signal.handler(eloop.term_signal.sig, -+ eloop.term_signal.user_data); -+ } -+} -+ -+ -+int eloop_register_signal(int sig, eloop_signal_handler handler, -+ void *user_data) -+{ -+ struct eloop_signal *tmp; -+ -+ tmp = os_realloc(eloop.signals, -+ (eloop.signal_count + 1) * -+ sizeof(struct eloop_signal)); -+ if (tmp == NULL) -+ return -1; -+ -+ tmp[eloop.signal_count].sig = sig; -+ tmp[eloop.signal_count].user_data = user_data; -+ tmp[eloop.signal_count].handler = handler; -+ tmp[eloop.signal_count].signaled = 0; -+ eloop.signal_count++; -+ eloop.signals = tmp; -+ -+ /* TODO: register signal handler */ -+ -+ return 0; -+} -+ -+ -+#ifndef _WIN32_WCE -+static BOOL eloop_handle_console_ctrl(DWORD type) -+{ -+ switch (type) { -+ case CTRL_C_EVENT: -+ case CTRL_BREAK_EVENT: -+ eloop.signaled++; -+ eloop.term_signal.signaled++; -+ SetEvent(eloop.term_event); -+ return TRUE; -+ default: -+ return FALSE; -+ } -+} -+#endif /* _WIN32_WCE */ -+ -+ -+int eloop_register_signal_terminate(eloop_signal_handler handler, -+ void *user_data) -+{ -+#ifndef _WIN32_WCE -+ if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl, -+ TRUE) == 0) { -+ printf("SetConsoleCtrlHandler() failed: %d\n", -+ (int) GetLastError()); -+ return -1; -+ } -+#endif /* _WIN32_WCE */ -+ -+ eloop.term_signal.handler = handler; -+ eloop.term_signal.user_data = user_data; -+ -+ return 0; -+} -+ -+ -+int eloop_register_signal_reconfig(eloop_signal_handler handler, -+ void *user_data) -+{ -+ /* TODO */ -+ return 0; -+} -+ -+ -+void eloop_run(void) -+{ -+ struct os_time tv, now; -+ DWORD count, ret, timeout, err; -+ size_t i; -+ -+ while (!eloop.terminate && -+ (eloop.timeout || eloop.reader_count > 0 || -+ eloop.event_count > 0)) { -+ tv.sec = tv.usec = 0; -+ if (eloop.timeout) { -+ os_get_time(&now); -+ if (os_time_before(&now, &eloop.timeout->time)) -+ os_time_sub(&eloop.timeout->time, &now, &tv); -+ } -+ -+ count = 0; -+ for (i = 0; i < eloop.event_count; i++) -+ eloop.handles[count++] = eloop.events[i].event; -+ -+ for (i = 0; i < eloop.reader_count; i++) -+ eloop.handles[count++] = eloop.readers[i].event; -+ -+ if (eloop.term_event) -+ eloop.handles[count++] = eloop.term_event; -+ -+ if (eloop.timeout) -+ timeout = tv.sec * 1000 + tv.usec / 1000; -+ else -+ timeout = INFINITE; -+ -+ if (count > MAXIMUM_WAIT_OBJECTS) { -+ printf("WaitForMultipleObjects: Too many events: " -+ "%d > %d (ignoring extra events)\n", -+ (int) count, MAXIMUM_WAIT_OBJECTS); -+ count = MAXIMUM_WAIT_OBJECTS; -+ } -+#ifdef _WIN32_WCE -+ ret = WaitForMultipleObjects(count, eloop.handles, FALSE, -+ timeout); -+#else /* _WIN32_WCE */ -+ ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE, -+ timeout, TRUE); -+#endif /* _WIN32_WCE */ -+ err = GetLastError(); -+ -+ eloop_process_pending_signals(); -+ -+ /* check if some registered timeouts have occurred */ -+ if (eloop.timeout) { -+ struct eloop_timeout *tmp; -+ -+ os_get_time(&now); -+ if (!os_time_before(&now, &eloop.timeout->time)) { -+ tmp = eloop.timeout; -+ eloop.timeout = eloop.timeout->next; -+ tmp->handler(tmp->eloop_data, -+ tmp->user_data); -+ os_free(tmp); -+ } -+ -+ } -+ -+ if (ret == WAIT_FAILED) { -+ printf("WaitForMultipleObjects(count=%d) failed: %d\n", -+ (int) count, (int) err); -+ os_sleep(1, 0); -+ continue; -+ } -+ -+#ifndef _WIN32_WCE -+ if (ret == WAIT_IO_COMPLETION) -+ continue; -+#endif /* _WIN32_WCE */ -+ -+ if (ret == WAIT_TIMEOUT) -+ continue; -+ -+ while (ret >= WAIT_OBJECT_0 && -+ ret < WAIT_OBJECT_0 + eloop.event_count) { -+ eloop.events[ret].handler( -+ eloop.events[ret].eloop_data, -+ eloop.events[ret].user_data); -+ ret = WaitForMultipleObjects(eloop.event_count, -+ eloop.handles, FALSE, 0); -+ } -+ -+ eloop.reader_table_changed = 0; -+ for (i = 0; i < eloop.reader_count; i++) { -+ WSANETWORKEVENTS events; -+ if (WSAEnumNetworkEvents(eloop.readers[i].sock, -+ eloop.readers[i].event, -+ &events) == 0 && -+ (events.lNetworkEvents & FD_READ)) { -+ eloop.readers[i].handler( -+ eloop.readers[i].sock, -+ eloop.readers[i].eloop_data, -+ eloop.readers[i].user_data); -+ if (eloop.reader_table_changed) -+ break; -+ } -+ } -+ } -+} -+ -+ -+void eloop_terminate(void) -+{ -+ eloop.terminate = 1; -+ SetEvent(eloop.term_event); -+} -+ -+ -+void eloop_destroy(void) -+{ -+ struct eloop_timeout *timeout, *prev; -+ -+ timeout = eloop.timeout; -+ while (timeout != NULL) { -+ prev = timeout; -+ timeout = timeout->next; -+ os_free(prev); -+ } -+ os_free(eloop.readers); -+ os_free(eloop.signals); -+ if (eloop.term_event) -+ CloseHandle(eloop.term_event); -+ os_free(eloop.handles); -+ eloop.handles = NULL; -+ os_free(eloop.events); -+ eloop.events = NULL; -+} -+ -+ -+int eloop_terminated(void) -+{ -+ return eloop.terminate; -+} -+ -+ -+void eloop_wait_for_read_sock(int sock) -+{ -+ WSAEVENT event; -+ -+ event = WSACreateEvent(); -+ if (event == WSA_INVALID_EVENT) { -+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError()); -+ return; -+ } -+ -+ if (WSAEventSelect(sock, event, FD_READ)) { -+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError()); -+ WSACloseEvent(event); -+ return ; -+ } -+ -+ WaitForSingleObject(event, INFINITE); -+ WSAEventSelect(sock, event, 0); -+ WSACloseEvent(event); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/includes.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/includes.h -new file mode 100644 -index 0000000000000..63b5c23d84907 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/includes.h -@@ -0,0 +1,59 @@ -+/* -+ * wpa_supplicant/hostapd - Default include files -+ * Copyright (c) 2005-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This header file is included into all C files so that commonly used header -+ * files can be selected with OS specific ifdef blocks in one place instead of -+ * having to have OS/C library specific selection in many files. -+ */ -+ -+#ifndef INCLUDES_H -+#define INCLUDES_H -+ -+/* Include possible build time configuration before including anything else */ -+#include "build_config.h" -+ -+#include -+#include -+#include -+#include -+#ifndef _WIN32_WCE -+#ifndef CONFIG_TI_COMPILER -+#include -+#include -+#endif /* CONFIG_TI_COMPILER */ -+#include -+#endif /* _WIN32_WCE */ -+#include -+#include -+ -+#ifndef CONFIG_TI_COMPILER -+#ifndef _MSC_VER -+#include -+#endif /* _MSC_VER */ -+#endif /* CONFIG_TI_COMPILER */ -+ -+#ifndef CONFIG_NATIVE_WINDOWS -+#ifndef CONFIG_TI_COMPILER -+#include -+#include -+#include -+#ifndef __vxworks -+#ifndef __SYMBIAN32__ -+#include -+#endif /* __SYMBIAN32__ */ -+#include -+#endif /* __vxworks */ -+#endif /* CONFIG_TI_COMPILER */ -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+#endif /* INCLUDES_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.c -new file mode 100644 -index 0000000000000..158fd57ed0170 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.c -@@ -0,0 +1,83 @@ -+/* -+ * IP address processing -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "ip_addr.h" -+ -+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, -+ size_t buflen) -+{ -+ if (buflen == 0 || addr == NULL) -+ return NULL; -+ -+ if (addr->af == AF_INET) { -+ os_strlcpy(buf, inet_ntoa(addr->u.v4), buflen); -+ } else { -+ buf[0] = '\0'; -+ } -+#ifdef CONFIG_IPV6 -+ if (addr->af == AF_INET6) { -+ if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL) -+ buf[0] = '\0'; -+ } -+#endif /* CONFIG_IPV6 */ -+ -+ return buf; -+} -+ -+ -+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b) -+{ -+ if (a == NULL && b == NULL) -+ return 0; -+ if (a == NULL || b == NULL) -+ return 1; -+ -+ switch (a->af) { -+ case AF_INET: -+ if (a->u.v4.s_addr != b->u.v4.s_addr) -+ return 1; -+ break; -+#ifdef CONFIG_IPV6 -+ case AF_INET6: -+ if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0) -+ return 1; -+ break; -+#endif /* CONFIG_IPV6 */ -+ } -+ -+ return 0; -+} -+ -+ -+int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr) -+{ -+#ifndef CONFIG_NATIVE_WINDOWS -+ if (inet_aton(txt, &addr->u.v4)) { -+ addr->af = AF_INET; -+ return 0; -+ } -+ -+#ifdef CONFIG_IPV6 -+ if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) { -+ addr->af = AF_INET6; -+ return 0; -+ } -+#endif /* CONFIG_IPV6 */ -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.h -new file mode 100644 -index 0000000000000..28ccaefdea2bc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/ip_addr.h -@@ -0,0 +1,34 @@ -+/* -+ * IP address processing -+ * Copyright (c) 2003-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef IP_ADDR_H -+#define IP_ADDR_H -+ -+struct hostapd_ip_addr { -+ int af; /* AF_INET / AF_INET6 */ -+ union { -+ struct in_addr v4; -+#ifdef CONFIG_IPV6 -+ struct in6_addr v6; -+#endif /* CONFIG_IPV6 */ -+ u8 max_len[16]; -+ } u; -+}; -+ -+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, -+ size_t buflen); -+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b); -+int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr); -+ -+#endif /* IP_ADDR_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/list.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/list.h -new file mode 100644 -index 0000000000000..ded78464ab424 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/list.h -@@ -0,0 +1,98 @@ -+/* -+ * Doubly-linked list -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef LIST_H -+#define LIST_H -+ -+/** -+ * struct dl_list - Doubly-linked list -+ */ -+struct dl_list { -+ struct dl_list *next; -+ struct dl_list *prev; -+}; -+ -+static inline void dl_list_init(struct dl_list *list) -+{ -+ list->next = list; -+ list->prev = list; -+} -+ -+static inline void dl_list_add(struct dl_list *list, struct dl_list *item) -+{ -+ item->next = list->next; -+ item->prev = list; -+ list->next->prev = item; -+ list->next = item; -+} -+ -+static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item) -+{ -+ dl_list_add(list->prev, item); -+} -+ -+static inline void dl_list_del(struct dl_list *item) -+{ -+ item->next->prev = item->prev; -+ item->prev->next = item->next; -+ item->next = NULL; -+ item->prev = NULL; -+} -+ -+static inline int dl_list_empty(struct dl_list *list) -+{ -+ return list->next == list; -+} -+ -+static inline unsigned int dl_list_len(struct dl_list *list) -+{ -+ struct dl_list *item; -+ int count = 0; -+ for (item = list->next; item != list; item = item->next) -+ count++; -+ return count; -+} -+ -+#ifndef offsetof -+#define offsetof(type, member) ((long) &((type *) 0)->member) -+#endif -+ -+#define dl_list_entry(item, type, member) \ -+ ((type *) ((char *) item - offsetof(type, member))) -+ -+#define dl_list_first(list, type, member) \ -+ (dl_list_empty((list)) ? NULL : \ -+ dl_list_entry((list)->next, type, member)) -+ -+#define dl_list_last(list, type, member) \ -+ (dl_list_empty((list)) ? NULL : \ -+ dl_list_entry((list)->prev, type, member)) -+ -+#define dl_list_for_each(item, list, type, member) \ -+ for (item = dl_list_entry((list)->next, type, member); \ -+ &item->member != (list); \ -+ item = dl_list_entry(item->member.next, type, member)) -+ -+#define dl_list_for_each_safe(item, n, list, type, member) \ -+ for (item = dl_list_entry((list)->next, type, member), \ -+ n = dl_list_entry(item->member.next, type, member); \ -+ &item->member != (list); \ -+ item = n, n = dl_list_entry(n->member.next, type, member)) -+ -+#define dl_list_for_each_reverse(item, list, type, member) \ -+ for (item = dl_list_entry((list)->prev, type, member); \ -+ &item->member != (list); \ -+ item = dl_list_entry(item->member.prev, type, member)) -+ -+#endif /* LIST_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os.h -new file mode 100644 -index 0000000000000..f4723d87525d7 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os.h -@@ -0,0 +1,508 @@ -+/* -+ * OS specific functions -+ * Copyright (c) 2005-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef OS_H -+#define OS_H -+ -+typedef long os_time_t; -+ -+/** -+ * os_sleep - Sleep (sec, usec) -+ * @sec: Number of seconds to sleep -+ * @usec: Number of microseconds to sleep -+ */ -+void os_sleep(os_time_t sec, os_time_t usec); -+ -+struct os_time { -+ os_time_t sec; -+ os_time_t usec; -+}; -+ -+/** -+ * os_get_time - Get current time (sec, usec) -+ * @t: Pointer to buffer for the time -+ * Returns: 0 on success, -1 on failure -+ */ -+int os_get_time(struct os_time *t); -+ -+ -+/* Helper macros for handling struct os_time */ -+ -+#define os_time_before(a, b) \ -+ ((a)->sec < (b)->sec || \ -+ ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) -+ -+#define os_time_sub(a, b, res) do { \ -+ (res)->sec = (a)->sec - (b)->sec; \ -+ (res)->usec = (a)->usec - (b)->usec; \ -+ if ((res)->usec < 0) { \ -+ (res)->sec--; \ -+ (res)->usec += 1000000; \ -+ } \ -+} while (0) -+ -+/** -+ * os_mktime - Convert broken-down time into seconds since 1970-01-01 -+ * @year: Four digit year -+ * @month: Month (1 .. 12) -+ * @day: Day of month (1 .. 31) -+ * @hour: Hour (0 .. 23) -+ * @min: Minute (0 .. 59) -+ * @sec: Second (0 .. 60) -+ * @t: Buffer for returning calendar time representation (seconds since -+ * 1970-01-01 00:00:00) -+ * Returns: 0 on success, -1 on failure -+ * -+ * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time -+ * which is used by POSIX mktime(). -+ */ -+int os_mktime(int year, int month, int day, int hour, int min, int sec, -+ os_time_t *t); -+ -+ -+/** -+ * os_daemonize - Run in the background (detach from the controlling terminal) -+ * @pid_file: File name to write the process ID to or %NULL to skip this -+ * Returns: 0 on success, -1 on failure -+ */ -+int os_daemonize(const char *pid_file); -+ -+/** -+ * os_daemonize_terminate - Stop running in the background (remove pid file) -+ * @pid_file: File name to write the process ID to or %NULL to skip this -+ */ -+void os_daemonize_terminate(const char *pid_file); -+ -+/** -+ * os_get_random - Get cryptographically strong pseudo random data -+ * @buf: Buffer for pseudo random data -+ * @len: Length of the buffer -+ * Returns: 0 on success, -1 on failure -+ */ -+int os_get_random(unsigned char *buf, size_t len); -+ -+/** -+ * os_random - Get pseudo random value (not necessarily very strong) -+ * Returns: Pseudo random value -+ */ -+unsigned long os_random(void); -+ -+/** -+ * os_rel2abs_path - Get an absolute path for a file -+ * @rel_path: Relative path to a file -+ * Returns: Absolute path for the file or %NULL on failure -+ * -+ * This function tries to convert a relative path of a file to an absolute path -+ * in order for the file to be found even if current working directory has -+ * changed. The returned value is allocated and caller is responsible for -+ * freeing it. It is acceptable to just return the same path in an allocated -+ * buffer, e.g., return strdup(rel_path). This function is only used to find -+ * configuration files when os_daemonize() may have changed the current working -+ * directory and relative path would be pointing to a different location. -+ */ -+char * os_rel2abs_path(const char *rel_path); -+ -+/** -+ * os_program_init - Program initialization (called at start) -+ * Returns: 0 on success, -1 on failure -+ * -+ * This function is called when a programs starts. If there are any OS specific -+ * processing that is needed, it can be placed here. It is also acceptable to -+ * just return 0 if not special processing is needed. -+ */ -+int os_program_init(void); -+ -+/** -+ * os_program_deinit - Program deinitialization (called just before exit) -+ * -+ * This function is called just before a program exists. If there are any OS -+ * specific processing, e.g., freeing resourced allocated in os_program_init(), -+ * it should be done here. It is also acceptable for this function to do -+ * nothing. -+ */ -+void os_program_deinit(void); -+ -+/** -+ * os_setenv - Set environment variable -+ * @name: Name of the variable -+ * @value: Value to set to the variable -+ * @overwrite: Whether existing variable should be overwritten -+ * Returns: 0 on success, -1 on error -+ * -+ * This function is only used for wpa_cli action scripts. OS wrapper does not -+ * need to implement this if such functionality is not needed. -+ */ -+int os_setenv(const char *name, const char *value, int overwrite); -+ -+/** -+ * os_unsetenv - Delete environent variable -+ * @name: Name of the variable -+ * Returns: 0 on success, -1 on error -+ * -+ * This function is only used for wpa_cli action scripts. OS wrapper does not -+ * need to implement this if such functionality is not needed. -+ */ -+int os_unsetenv(const char *name); -+ -+/** -+ * os_readfile - Read a file to an allocated memory buffer -+ * @name: Name of the file to read -+ * @len: For returning the length of the allocated buffer -+ * Returns: Pointer to the allocated buffer or %NULL on failure -+ * -+ * This function allocates memory and reads the given file to this buffer. Both -+ * binary and text files can be read with this function. The caller is -+ * responsible for freeing the returned buffer with os_free(). -+ */ -+char * os_readfile(const char *name, size_t *len); -+ -+/** -+ * os_zalloc - Allocate and zero memory -+ * @size: Number of bytes to allocate -+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned buffer with os_free(). -+ */ -+void * os_zalloc(size_t size); -+ -+ -+/* -+ * The following functions are wrapper for standard ANSI C or POSIX functions. -+ * By default, they are just defined to use the standard function name and no -+ * os_*.c implementation is needed for them. This avoids extra function calls -+ * by allowing the C pre-processor take care of the function name mapping. -+ * -+ * If the target system uses a C library that does not provide these functions, -+ * build_config.h can be used to define the wrappers to use a different -+ * function name. This can be done on function-by-function basis since the -+ * defines here are only used if build_config.h does not define the os_* name. -+ * If needed, os_*.c file can be used to implement the functions that are not -+ * included in the C library on the target system. Alternatively, -+ * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case -+ * these functions need to be implemented in os_*.c file for the target system. -+ */ -+ -+#ifdef OS_NO_C_LIB_DEFINES -+ -+/** -+ * os_malloc - Allocate dynamic memory -+ * @size: Size of the buffer to allocate -+ * Returns: Allocated buffer or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned buffer with os_free(). -+ */ -+void * os_malloc(size_t size); -+ -+/** -+ * os_realloc - Re-allocate dynamic memory -+ * @ptr: Old buffer from os_malloc() or os_realloc() -+ * @size: Size of the new buffer -+ * Returns: Allocated buffer or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned buffer with os_free(). -+ * If re-allocation fails, %NULL is returned and the original buffer (ptr) is -+ * not freed and caller is still responsible for freeing it. -+ */ -+void * os_realloc(void *ptr, size_t size); -+ -+/** -+ * os_free - Free dynamic memory -+ * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL -+ */ -+void os_free(void *ptr); -+ -+/** -+ * os_memcpy - Copy memory area -+ * @dest: Destination -+ * @src: Source -+ * @n: Number of bytes to copy -+ * Returns: dest -+ * -+ * The memory areas src and dst must not overlap. os_memmove() can be used with -+ * overlapping memory. -+ */ -+void * os_memcpy(void *dest, const void *src, size_t n); -+ -+/** -+ * os_memmove - Copy memory area -+ * @dest: Destination -+ * @src: Source -+ * @n: Number of bytes to copy -+ * Returns: dest -+ * -+ * The memory areas src and dst may overlap. -+ */ -+void * os_memmove(void *dest, const void *src, size_t n); -+ -+/** -+ * os_memset - Fill memory with a constant byte -+ * @s: Memory area to be filled -+ * @c: Constant byte -+ * @n: Number of bytes started from s to fill with c -+ * Returns: s -+ */ -+void * os_memset(void *s, int c, size_t n); -+ -+/** -+ * os_memcmp - Compare memory areas -+ * @s1: First buffer -+ * @s2: Second buffer -+ * @n: Maximum numbers of octets to compare -+ * Returns: An integer less than, equal to, or greater than zero if s1 is -+ * found to be less than, to match, or be greater than s2. Only first n -+ * characters will be compared. -+ */ -+int os_memcmp(const void *s1, const void *s2, size_t n); -+ -+/** -+ * os_strdup - Duplicate a string -+ * @s: Source string -+ * Returns: Allocated buffer with the string copied into it or %NULL on failure -+ * -+ * Caller is responsible for freeing the returned buffer with os_free(). -+ */ -+char * os_strdup(const char *s); -+ -+/** -+ * os_strlen - Calculate the length of a string -+ * @s: '\0' terminated string -+ * Returns: Number of characters in s (not counting the '\0' terminator) -+ */ -+size_t os_strlen(const char *s); -+ -+/** -+ * os_strcasecmp - Compare two strings ignoring case -+ * @s1: First string -+ * @s2: Second string -+ * Returns: An integer less than, equal to, or greater than zero if s1 is -+ * found to be less than, to match, or be greatred than s2 -+ */ -+int os_strcasecmp(const char *s1, const char *s2); -+ -+/** -+ * os_strncasecmp - Compare two strings ignoring case -+ * @s1: First string -+ * @s2: Second string -+ * @n: Maximum numbers of characters to compare -+ * Returns: An integer less than, equal to, or greater than zero if s1 is -+ * found to be less than, to match, or be greater than s2. Only first n -+ * characters will be compared. -+ */ -+int os_strncasecmp(const char *s1, const char *s2, size_t n); -+ -+/** -+ * os_strchr - Locate the first occurrence of a character in string -+ * @s: String -+ * @c: Character to search for -+ * Returns: Pointer to the matched character or %NULL if not found -+ */ -+char * os_strchr(const char *s, int c); -+ -+/** -+ * os_strrchr - Locate the last occurrence of a character in string -+ * @s: String -+ * @c: Character to search for -+ * Returns: Pointer to the matched character or %NULL if not found -+ */ -+char * os_strrchr(const char *s, int c); -+ -+/** -+ * os_strcmp - Compare two strings -+ * @s1: First string -+ * @s2: Second string -+ * Returns: An integer less than, equal to, or greater than zero if s1 is -+ * found to be less than, to match, or be greatred than s2 -+ */ -+int os_strcmp(const char *s1, const char *s2); -+ -+/** -+ * os_strncmp - Compare two strings -+ * @s1: First string -+ * @s2: Second string -+ * @n: Maximum numbers of characters to compare -+ * Returns: An integer less than, equal to, or greater than zero if s1 is -+ * found to be less than, to match, or be greater than s2. Only first n -+ * characters will be compared. -+ */ -+int os_strncmp(const char *s1, const char *s2, size_t n); -+ -+/** -+ * os_strncpy - Copy a string -+ * @dest: Destination -+ * @src: Source -+ * @n: Maximum number of characters to copy -+ * Returns: dest -+ */ -+char * os_strncpy(char *dest, const char *src, size_t n); -+ -+/** -+ * os_strstr - Locate a substring -+ * @haystack: String (haystack) to search from -+ * @needle: Needle to search from haystack -+ * Returns: Pointer to the beginning of the substring or %NULL if not found -+ */ -+char * os_strstr(const char *haystack, const char *needle); -+ -+/** -+ * os_snprintf - Print to a memory buffer -+ * @str: Memory buffer to print into -+ * @size: Maximum length of the str buffer -+ * @format: printf format -+ * Returns: Number of characters printed (not including trailing '\0'). -+ * -+ * If the output buffer is truncated, number of characters which would have -+ * been written is returned. Since some C libraries return -1 in such a case, -+ * the caller must be prepared on that value, too, to indicate truncation. -+ * -+ * Note: Some C library implementations of snprintf() may not guarantee null -+ * termination in case the output is truncated. The OS wrapper function of -+ * os_snprintf() should provide this guarantee, i.e., to null terminate the -+ * output buffer if a C library version of the function is used and if that -+ * function does not guarantee null termination. -+ * -+ * If the target system does not include snprintf(), see, e.g., -+ * http://www.ijs.si/software/snprintf/ for an example of a portable -+ * implementation of snprintf. -+ */ -+int os_snprintf(char *str, size_t size, const char *format, ...); -+ -+#else /* OS_NO_C_LIB_DEFINES */ -+ -+#ifdef WPA_TRACE -+void * os_malloc(size_t size); -+void * os_realloc(void *ptr, size_t size); -+void os_free(void *ptr); -+char * os_strdup(const char *s); -+#else /* WPA_TRACE */ -+#ifndef os_malloc -+#define os_malloc(s) malloc((s)) -+#endif -+#ifndef os_realloc -+#define os_realloc(p, s) realloc((p), (s)) -+#endif -+#ifndef os_free -+#define os_free(p) free((p)) -+#endif -+#ifndef os_strdup -+#ifdef _MSC_VER -+#define os_strdup(s) _strdup(s) -+#else -+#define os_strdup(s) strdup(s) -+#endif -+#endif -+#endif /* WPA_TRACE */ -+ -+#ifndef os_memcpy -+#define os_memcpy(d, s, n) memcpy((d), (s), (n)) -+#endif -+#ifndef os_memmove -+#define os_memmove(d, s, n) memmove((d), (s), (n)) -+#endif -+#ifndef os_memset -+#define os_memset(s, c, n) memset(s, c, n) -+#endif -+#ifndef os_memcmp -+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) -+#endif -+ -+#ifndef os_strlen -+#define os_strlen(s) strlen(s) -+#endif -+#ifndef os_strcasecmp -+#ifdef _MSC_VER -+#define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) -+#else -+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) -+#endif -+#endif -+#ifndef os_strncasecmp -+#ifdef _MSC_VER -+#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) -+#else -+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) -+#endif -+#endif -+#ifndef os_strchr -+#define os_strchr(s, c) strchr((s), (c)) -+#endif -+#ifndef os_strcmp -+#define os_strcmp(s1, s2) strcmp((s1), (s2)) -+#endif -+#ifndef os_strncmp -+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n)) -+#endif -+#ifndef os_strncpy -+#define os_strncpy(d, s, n) strncpy((d), (s), (n)) -+#endif -+#ifndef os_strrchr -+#define os_strrchr(s, c) strrchr((s), (c)) -+#endif -+#ifndef os_strstr -+#define os_strstr(h, n) strstr((h), (n)) -+#endif -+ -+#ifndef os_snprintf -+#ifdef _MSC_VER -+#define os_snprintf _snprintf -+#else -+#define os_snprintf snprintf -+#endif -+#endif -+ -+#endif /* OS_NO_C_LIB_DEFINES */ -+ -+ -+/** -+ * os_strlcpy - Copy a string with size bound and NUL-termination -+ * @dest: Destination -+ * @src: Source -+ * @siz: Size of the target buffer -+ * Returns: Total length of the target string (length of src) (not including -+ * NUL-termination) -+ * -+ * This function matches in behavior with the strlcpy(3) function in OpenBSD. -+ */ -+size_t os_strlcpy(char *dest, const char *src, size_t siz); -+ -+ -+#ifdef OS_REJECT_C_LIB_FUNCTIONS -+#define malloc OS_DO_NOT_USE_malloc -+#define realloc OS_DO_NOT_USE_realloc -+#define free OS_DO_NOT_USE_free -+#define memcpy OS_DO_NOT_USE_memcpy -+#define memmove OS_DO_NOT_USE_memmove -+#define memset OS_DO_NOT_USE_memset -+#define memcmp OS_DO_NOT_USE_memcmp -+#undef strdup -+#define strdup OS_DO_NOT_USE_strdup -+#define strlen OS_DO_NOT_USE_strlen -+#define strcasecmp OS_DO_NOT_USE_strcasecmp -+#define strncasecmp OS_DO_NOT_USE_strncasecmp -+#undef strchr -+#define strchr OS_DO_NOT_USE_strchr -+#undef strcmp -+#define strcmp OS_DO_NOT_USE_strcmp -+#undef strncmp -+#define strncmp OS_DO_NOT_USE_strncmp -+#undef strncpy -+#define strncpy OS_DO_NOT_USE_strncpy -+#define strrchr OS_DO_NOT_USE_strrchr -+#define strstr OS_DO_NOT_USE_strstr -+#undef snprintf -+#define snprintf OS_DO_NOT_USE_snprintf -+ -+#define strcpy OS_DO_NOT_USE_strcpy -+#endif /* OS_REJECT_C_LIB_FUNCTIONS */ -+ -+#endif /* OS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_internal.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_internal.c -new file mode 100644 -index 0000000000000..5260e232101f2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_internal.c -@@ -0,0 +1,471 @@ -+/* -+ * wpa_supplicant/hostapd / Internal implementation of OS specific functions -+ * Copyright (c) 2005-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file is an example of operating system specific wrapper functions. -+ * This version implements many of the functions internally, so it can be used -+ * to fill in missing functions from the target system C libraries. -+ * -+ * Some of the functions are using standard C library calls in order to keep -+ * this file in working condition to allow the functions to be tested on a -+ * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for -+ * this file to work correctly. Note that these implementations are only -+ * examples and are not optimized for speed. -+ */ -+ -+#include "includes.h" -+ -+#undef OS_REJECT_C_LIB_FUNCTIONS -+#include "os.h" -+ -+void os_sleep(os_time_t sec, os_time_t usec) -+{ -+ if (sec) -+ sleep(sec); -+ if (usec) -+ usleep(usec); -+} -+ -+ -+int os_get_time(struct os_time *t) -+{ -+ int res; -+ struct timeval tv; -+ res = gettimeofday(&tv, NULL); -+ t->sec = tv.tv_sec; -+ t->usec = tv.tv_usec; -+ return res; -+} -+ -+ -+int os_mktime(int year, int month, int day, int hour, int min, int sec, -+ os_time_t *t) -+{ -+ struct tm tm; -+ -+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || -+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || -+ sec > 60) -+ return -1; -+ -+ os_memset(&tm, 0, sizeof(tm)); -+ tm.tm_year = year - 1900; -+ tm.tm_mon = month - 1; -+ tm.tm_mday = day; -+ tm.tm_hour = hour; -+ tm.tm_min = min; -+ tm.tm_sec = sec; -+ -+ *t = (os_time_t) mktime(&tm); -+ return 0; -+} -+ -+ -+int os_daemonize(const char *pid_file) -+{ -+ if (daemon(0, 0)) { -+ perror("daemon"); -+ return -1; -+ } -+ -+ if (pid_file) { -+ FILE *f = fopen(pid_file, "w"); -+ if (f) { -+ fprintf(f, "%u\n", getpid()); -+ fclose(f); -+ } -+ } -+ -+ return -0; -+} -+ -+ -+void os_daemonize_terminate(const char *pid_file) -+{ -+ if (pid_file) -+ unlink(pid_file); -+} -+ -+ -+int os_get_random(unsigned char *buf, size_t len) -+{ -+ FILE *f; -+ size_t rc; -+ -+ f = fopen("/dev/urandom", "rb"); -+ if (f == NULL) { -+ printf("Could not open /dev/urandom.\n"); -+ return -1; -+ } -+ -+ rc = fread(buf, 1, len, f); -+ fclose(f); -+ -+ return rc != len ? -1 : 0; -+} -+ -+ -+unsigned long os_random(void) -+{ -+ return random(); -+} -+ -+ -+char * os_rel2abs_path(const char *rel_path) -+{ -+ char *buf = NULL, *cwd, *ret; -+ size_t len = 128, cwd_len, rel_len, ret_len; -+ -+ if (rel_path[0] == '/') -+ return os_strdup(rel_path); -+ -+ for (;;) { -+ buf = os_malloc(len); -+ if (buf == NULL) -+ return NULL; -+ cwd = getcwd(buf, len); -+ if (cwd == NULL) { -+ os_free(buf); -+ if (errno != ERANGE) { -+ return NULL; -+ } -+ len *= 2; -+ } else { -+ break; -+ } -+ } -+ -+ cwd_len = strlen(cwd); -+ rel_len = strlen(rel_path); -+ ret_len = cwd_len + 1 + rel_len + 1; -+ ret = os_malloc(ret_len); -+ if (ret) { -+ os_memcpy(ret, cwd, cwd_len); -+ ret[cwd_len] = '/'; -+ os_memcpy(ret + cwd_len + 1, rel_path, rel_len); -+ ret[ret_len - 1] = '\0'; -+ } -+ os_free(buf); -+ return ret; -+} -+ -+ -+int os_program_init(void) -+{ -+ return 0; -+} -+ -+ -+void os_program_deinit(void) -+{ -+} -+ -+ -+int os_setenv(const char *name, const char *value, int overwrite) -+{ -+ return setenv(name, value, overwrite); -+} -+ -+ -+int os_unsetenv(const char *name) -+{ -+#if defined(__FreeBSD__) || defined(__NetBSD__) -+ unsetenv(name); -+ return 0; -+#else -+ return unsetenv(name); -+#endif -+} -+ -+ -+char * os_readfile(const char *name, size_t *len) -+{ -+ FILE *f; -+ char *buf; -+ -+ f = fopen(name, "rb"); -+ if (f == NULL) -+ return NULL; -+ -+ fseek(f, 0, SEEK_END); -+ *len = ftell(f); -+ fseek(f, 0, SEEK_SET); -+ -+ buf = os_malloc(*len); -+ if (buf == NULL) { -+ fclose(f); -+ return NULL; -+ } -+ -+ if (fread(buf, 1, *len, f) != *len) { -+ fclose(f); -+ os_free(buf); -+ return NULL; -+ } -+ -+ fclose(f); -+ -+ return buf; -+} -+ -+ -+void * os_zalloc(size_t size) -+{ -+ void *n = os_malloc(size); -+ if (n) -+ os_memset(n, 0, size); -+ return n; -+} -+ -+ -+void * os_malloc(size_t size) -+{ -+ return malloc(size); -+} -+ -+ -+void * os_realloc(void *ptr, size_t size) -+{ -+ return realloc(ptr, size); -+} -+ -+ -+void os_free(void *ptr) -+{ -+ free(ptr); -+} -+ -+ -+void * os_memcpy(void *dest, const void *src, size_t n) -+{ -+ char *d = dest; -+ const char *s = src; -+ while (n--) -+ *d++ = *s++; -+ return dest; -+} -+ -+ -+void * os_memmove(void *dest, const void *src, size_t n) -+{ -+ if (dest < src) -+ os_memcpy(dest, src, n); -+ else { -+ /* overlapping areas */ -+ char *d = (char *) dest + n; -+ const char *s = (const char *) src + n; -+ while (n--) -+ *--d = *--s; -+ } -+ return dest; -+} -+ -+ -+void * os_memset(void *s, int c, size_t n) -+{ -+ char *p = s; -+ while (n--) -+ *p++ = c; -+ return s; -+} -+ -+ -+int os_memcmp(const void *s1, const void *s2, size_t n) -+{ -+ const unsigned char *p1 = s1, *p2 = s2; -+ -+ if (n == 0) -+ return 0; -+ -+ while (*p1 == *p2) { -+ p1++; -+ p2++; -+ n--; -+ if (n == 0) -+ return 0; -+ } -+ -+ return *p1 - *p2; -+} -+ -+ -+char * os_strdup(const char *s) -+{ -+ char *res; -+ size_t len; -+ if (s == NULL) -+ return NULL; -+ len = os_strlen(s); -+ res = os_malloc(len + 1); -+ if (res) -+ os_memcpy(res, s, len + 1); -+ return res; -+} -+ -+ -+size_t os_strlen(const char *s) -+{ -+ const char *p = s; -+ while (*p) -+ p++; -+ return p - s; -+} -+ -+ -+int os_strcasecmp(const char *s1, const char *s2) -+{ -+ /* -+ * Ignoring case is not required for main functionality, so just use -+ * the case sensitive version of the function. -+ */ -+ return os_strcmp(s1, s2); -+} -+ -+ -+int os_strncasecmp(const char *s1, const char *s2, size_t n) -+{ -+ /* -+ * Ignoring case is not required for main functionality, so just use -+ * the case sensitive version of the function. -+ */ -+ return os_strncmp(s1, s2, n); -+} -+ -+ -+char * os_strchr(const char *s, int c) -+{ -+ while (*s) { -+ if (*s == c) -+ return (char *) s; -+ s++; -+ } -+ return NULL; -+} -+ -+ -+char * os_strrchr(const char *s, int c) -+{ -+ const char *p = s; -+ while (*p) -+ p++; -+ p--; -+ while (p >= s) { -+ if (*p == c) -+ return (char *) p; -+ p--; -+ } -+ return NULL; -+} -+ -+ -+int os_strcmp(const char *s1, const char *s2) -+{ -+ while (*s1 == *s2) { -+ if (*s1 == '\0') -+ break; -+ s1++; -+ s2++; -+ } -+ -+ return *s1 - *s2; -+} -+ -+ -+int os_strncmp(const char *s1, const char *s2, size_t n) -+{ -+ if (n == 0) -+ return 0; -+ -+ while (*s1 == *s2) { -+ if (*s1 == '\0') -+ break; -+ s1++; -+ s2++; -+ n--; -+ if (n == 0) -+ return 0; -+ } -+ -+ return *s1 - *s2; -+} -+ -+ -+char * os_strncpy(char *dest, const char *src, size_t n) -+{ -+ char *d = dest; -+ -+ while (n--) { -+ *d = *src; -+ if (*src == '\0') -+ break; -+ d++; -+ src++; -+ } -+ -+ return dest; -+} -+ -+ -+size_t os_strlcpy(char *dest, const char *src, size_t siz) -+{ -+ const char *s = src; -+ size_t left = siz; -+ -+ if (left) { -+ /* Copy string up to the maximum size of the dest buffer */ -+ while (--left != 0) { -+ if ((*dest++ = *s++) == '\0') -+ break; -+ } -+ } -+ -+ if (left == 0) { -+ /* Not enough room for the string; force NUL-termination */ -+ if (siz != 0) -+ *dest = '\0'; -+ while (*s++) -+ ; /* determine total src string length */ -+ } -+ -+ return s - src - 1; -+} -+ -+ -+char * os_strstr(const char *haystack, const char *needle) -+{ -+ size_t len = os_strlen(needle); -+ while (*haystack) { -+ if (os_strncmp(haystack, needle, len) == 0) -+ return (char *) haystack; -+ haystack++; -+ } -+ -+ return NULL; -+} -+ -+ -+int os_snprintf(char *str, size_t size, const char *format, ...) -+{ -+ va_list ap; -+ int ret; -+ -+ /* See http://www.ijs.si/software/snprintf/ for portable -+ * implementation of snprintf. -+ */ -+ -+ va_start(ap, format); -+ ret = vsnprintf(str, size, format, ap); -+ va_end(ap); -+ if (size > 0) -+ str[size - 1] = '\0'; -+ return ret; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_none.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_none.c -new file mode 100644 -index 0000000000000..bab8f178c05af ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_none.c -@@ -0,0 +1,226 @@ -+/* -+ * wpa_supplicant/hostapd / Empty OS specific functions -+ * Copyright (c) 2005-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file can be used as a starting point when adding a new OS target. The -+ * functions here do not really work as-is since they are just empty or only -+ * return an error value. os_internal.c can be used as another starting point -+ * or reference since it has example implementation of many of these functions. -+ */ -+ -+#include "includes.h" -+ -+#include "os.h" -+ -+void os_sleep(os_time_t sec, os_time_t usec) -+{ -+} -+ -+ -+int os_get_time(struct os_time *t) -+{ -+ return -1; -+} -+ -+ -+int os_mktime(int year, int month, int day, int hour, int min, int sec, -+ os_time_t *t) -+{ -+ return -1; -+} -+ -+ -+int os_daemonize(const char *pid_file) -+{ -+ return -1; -+} -+ -+ -+void os_daemonize_terminate(const char *pid_file) -+{ -+} -+ -+ -+int os_get_random(unsigned char *buf, size_t len) -+{ -+ return -1; -+} -+ -+ -+unsigned long os_random(void) -+{ -+ return 0; -+} -+ -+ -+char * os_rel2abs_path(const char *rel_path) -+{ -+ return NULL; /* strdup(rel_path) can be used here */ -+} -+ -+ -+int os_program_init(void) -+{ -+ return 0; -+} -+ -+ -+void os_program_deinit(void) -+{ -+} -+ -+ -+int os_setenv(const char *name, const char *value, int overwrite) -+{ -+ return -1; -+} -+ -+ -+int os_unsetenv(const char *name) -+{ -+ return -1; -+} -+ -+ -+char * os_readfile(const char *name, size_t *len) -+{ -+ return NULL; -+} -+ -+ -+void * os_zalloc(size_t size) -+{ -+ return NULL; -+} -+ -+ -+#ifdef OS_NO_C_LIB_DEFINES -+void * os_malloc(size_t size) -+{ -+ return NULL; -+} -+ -+ -+void * os_realloc(void *ptr, size_t size) -+{ -+ return NULL; -+} -+ -+ -+void os_free(void *ptr) -+{ -+} -+ -+ -+void * os_memcpy(void *dest, const void *src, size_t n) -+{ -+ return dest; -+} -+ -+ -+void * os_memmove(void *dest, const void *src, size_t n) -+{ -+ return dest; -+} -+ -+ -+void * os_memset(void *s, int c, size_t n) -+{ -+ return s; -+} -+ -+ -+int os_memcmp(const void *s1, const void *s2, size_t n) -+{ -+ return 0; -+} -+ -+ -+char * os_strdup(const char *s) -+{ -+ return NULL; -+} -+ -+ -+size_t os_strlen(const char *s) -+{ -+ return 0; -+} -+ -+ -+int os_strcasecmp(const char *s1, const char *s2) -+{ -+ /* -+ * Ignoring case is not required for main functionality, so just use -+ * the case sensitive version of the function. -+ */ -+ return os_strcmp(s1, s2); -+} -+ -+ -+int os_strncasecmp(const char *s1, const char *s2, size_t n) -+{ -+ /* -+ * Ignoring case is not required for main functionality, so just use -+ * the case sensitive version of the function. -+ */ -+ return os_strncmp(s1, s2, n); -+} -+ -+ -+char * os_strchr(const char *s, int c) -+{ -+ return NULL; -+} -+ -+ -+char * os_strrchr(const char *s, int c) -+{ -+ return NULL; -+} -+ -+ -+int os_strcmp(const char *s1, const char *s2) -+{ -+ return 0; -+} -+ -+ -+int os_strncmp(const char *s1, const char *s2, size_t n) -+{ -+ return 0; -+} -+ -+ -+char * os_strncpy(char *dest, const char *src, size_t n) -+{ -+ return dest; -+} -+ -+ -+size_t os_strlcpy(char *dest, const char *src, size_t size) -+{ -+ return 0; -+} -+ -+ -+char * os_strstr(const char *haystack, const char *needle) -+{ -+ return NULL; -+} -+ -+ -+int os_snprintf(char *str, size_t size, const char *format, ...) -+{ -+ return 0; -+} -+#endif /* OS_NO_C_LIB_DEFINES */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_unix.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_unix.c -new file mode 100644 -index 0000000000000..4e117585b0501 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_unix.c -@@ -0,0 +1,474 @@ -+/* -+ * OS specific functions for UNIX/POSIX systems -+ * Copyright (c) 2005-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#ifdef ANDROID -+#include -+#include -+#include -+#endif /* ANDROID */ -+ -+#include "os.h" -+ -+#ifdef WPA_TRACE -+ -+#include "common.h" -+#include "list.h" -+#include "wpa_debug.h" -+#include "trace.h" -+ -+static struct dl_list alloc_list; -+ -+#define ALLOC_MAGIC 0xa84ef1b2 -+#define FREED_MAGIC 0x67fd487a -+ -+struct os_alloc_trace { -+ unsigned int magic; -+ struct dl_list list; -+ size_t len; -+ WPA_TRACE_INFO -+}; -+ -+#endif /* WPA_TRACE */ -+ -+ -+void os_sleep(os_time_t sec, os_time_t usec) -+{ -+ if (sec) -+ sleep(sec); -+ if (usec) -+ usleep(usec); -+} -+ -+ -+int os_get_time(struct os_time *t) -+{ -+ int res; -+ struct timeval tv; -+ res = gettimeofday(&tv, NULL); -+ t->sec = tv.tv_sec; -+ t->usec = tv.tv_usec; -+ return res; -+} -+ -+ -+int os_mktime(int year, int month, int day, int hour, int min, int sec, -+ os_time_t *t) -+{ -+ struct tm tm, *tm1; -+ time_t t_local, t1, t2; -+ os_time_t tz_offset; -+ -+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || -+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || -+ sec > 60) -+ return -1; -+ -+ memset(&tm, 0, sizeof(tm)); -+ tm.tm_year = year - 1900; -+ tm.tm_mon = month - 1; -+ tm.tm_mday = day; -+ tm.tm_hour = hour; -+ tm.tm_min = min; -+ tm.tm_sec = sec; -+ -+ t_local = mktime(&tm); -+ -+ /* figure out offset to UTC */ -+ tm1 = localtime(&t_local); -+ if (tm1) { -+ t1 = mktime(tm1); -+ tm1 = gmtime(&t_local); -+ if (tm1) { -+ t2 = mktime(tm1); -+ tz_offset = t2 - t1; -+ } else -+ tz_offset = 0; -+ } else -+ tz_offset = 0; -+ -+ *t = (os_time_t) t_local - tz_offset; -+ return 0; -+} -+ -+ -+#ifdef __APPLE__ -+#include -+static int os_daemon(int nochdir, int noclose) -+{ -+ int devnull; -+ -+ if (chdir("/") < 0) -+ return -1; -+ -+ devnull = open("/dev/null", O_RDWR); -+ if (devnull < 0) -+ return -1; -+ -+ if (dup2(devnull, STDIN_FILENO) < 0) { -+ close(devnull); -+ return -1; -+ } -+ -+ if (dup2(devnull, STDOUT_FILENO) < 0) { -+ close(devnull); -+ return -1; -+ } -+ -+ if (dup2(devnull, STDERR_FILENO) < 0) { -+ close(devnull); -+ return -1; -+ } -+ -+ return 0; -+} -+#else /* __APPLE__ */ -+#define os_daemon daemon -+#endif /* __APPLE__ */ -+ -+ -+int os_daemonize(const char *pid_file) -+{ -+#if defined(__uClinux__) || defined(__sun__) -+ return -1; -+#else /* defined(__uClinux__) || defined(__sun__) */ -+ if (os_daemon(0, 0)) { -+ perror("daemon"); -+ return -1; -+ } -+ -+ if (pid_file) { -+ FILE *f = fopen(pid_file, "w"); -+ if (f) { -+ fprintf(f, "%u\n", getpid()); -+ fclose(f); -+ } -+ } -+ -+ return -0; -+#endif /* defined(__uClinux__) || defined(__sun__) */ -+} -+ -+ -+void os_daemonize_terminate(const char *pid_file) -+{ -+ if (pid_file) -+ unlink(pid_file); -+} -+ -+ -+int os_get_random(unsigned char *buf, size_t len) -+{ -+ FILE *f; -+ size_t rc; -+ -+ f = fopen("/dev/urandom", "rb"); -+ if (f == NULL) { -+ printf("Could not open /dev/urandom.\n"); -+ return -1; -+ } -+ -+ rc = fread(buf, 1, len, f); -+ fclose(f); -+ -+ return rc != len ? -1 : 0; -+} -+ -+ -+unsigned long os_random(void) -+{ -+ return random(); -+} -+ -+ -+char * os_rel2abs_path(const char *rel_path) -+{ -+ char *buf = NULL, *cwd, *ret; -+ size_t len = 128, cwd_len, rel_len, ret_len; -+ int last_errno; -+ -+ if (rel_path[0] == '/') -+ return os_strdup(rel_path); -+ -+ for (;;) { -+ buf = os_malloc(len); -+ if (buf == NULL) -+ return NULL; -+ cwd = getcwd(buf, len); -+ if (cwd == NULL) { -+ last_errno = errno; -+ os_free(buf); -+ if (last_errno != ERANGE) -+ return NULL; -+ len *= 2; -+ if (len > 2000) -+ return NULL; -+ } else { -+ buf[len - 1] = '\0'; -+ break; -+ } -+ } -+ -+ cwd_len = os_strlen(cwd); -+ rel_len = os_strlen(rel_path); -+ ret_len = cwd_len + 1 + rel_len + 1; -+ ret = os_malloc(ret_len); -+ if (ret) { -+ os_memcpy(ret, cwd, cwd_len); -+ ret[cwd_len] = '/'; -+ os_memcpy(ret + cwd_len + 1, rel_path, rel_len); -+ ret[ret_len - 1] = '\0'; -+ } -+ os_free(buf); -+ return ret; -+} -+ -+ -+int os_program_init(void) -+{ -+#ifdef ANDROID -+ /* -+ * We ignore errors here since errors are normal if we -+ * are already running as non-root. -+ */ -+ gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; -+ struct __user_cap_header_struct header; -+ struct __user_cap_data_struct cap; -+ -+ setgroups(sizeof(groups)/sizeof(groups[0]), groups); -+ -+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); -+ -+ setgid(AID_WIFI); -+ setuid(AID_WIFI); -+ -+ header.version = _LINUX_CAPABILITY_VERSION; -+ header.pid = 0; -+ cap.effective = cap.permitted = -+ (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); -+ cap.inheritable = 0; -+ capset(&header, &cap); -+#endif /* ANDROID */ -+ -+#ifdef WPA_TRACE -+ dl_list_init(&alloc_list); -+#endif /* WPA_TRACE */ -+ return 0; -+} -+ -+ -+void os_program_deinit(void) -+{ -+#ifdef WPA_TRACE -+ struct os_alloc_trace *a; -+ unsigned long total = 0; -+ dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { -+ total += a->len; -+ if (a->magic != ALLOC_MAGIC) { -+ wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " -+ "len %lu", -+ a, a->magic, (unsigned long) a->len); -+ continue; -+ } -+ wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", -+ a, (unsigned long) a->len); -+ wpa_trace_dump("memleak", a); -+ } -+ if (total) -+ wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", -+ (unsigned long) total); -+#endif /* WPA_TRACE */ -+} -+ -+ -+int os_setenv(const char *name, const char *value, int overwrite) -+{ -+ return setenv(name, value, overwrite); -+} -+ -+ -+int os_unsetenv(const char *name) -+{ -+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ -+ defined(__OpenBSD__) -+ unsetenv(name); -+ return 0; -+#else -+ return unsetenv(name); -+#endif -+} -+ -+ -+char * os_readfile(const char *name, size_t *len) -+{ -+ FILE *f; -+ char *buf; -+ long pos; -+ -+ f = fopen(name, "rb"); -+ if (f == NULL) -+ return NULL; -+ -+ if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) { -+ fclose(f); -+ return NULL; -+ } -+ *len = pos; -+ if (fseek(f, 0, SEEK_SET) < 0) { -+ fclose(f); -+ return NULL; -+ } -+ -+ buf = os_malloc(*len); -+ if (buf == NULL) { -+ fclose(f); -+ return NULL; -+ } -+ -+ if (fread(buf, 1, *len, f) != *len) { -+ fclose(f); -+ os_free(buf); -+ return NULL; -+ } -+ -+ fclose(f); -+ -+ return buf; -+} -+ -+ -+#ifndef WPA_TRACE -+void * os_zalloc(size_t size) -+{ -+ return calloc(1, size); -+} -+#endif /* WPA_TRACE */ -+ -+ -+size_t os_strlcpy(char *dest, const char *src, size_t siz) -+{ -+ const char *s = src; -+ size_t left = siz; -+ -+ if (left) { -+ /* Copy string up to the maximum size of the dest buffer */ -+ while (--left != 0) { -+ if ((*dest++ = *s++) == '\0') -+ break; -+ } -+ } -+ -+ if (left == 0) { -+ /* Not enough room for the string; force NUL-termination */ -+ if (siz != 0) -+ *dest = '\0'; -+ while (*s++) -+ ; /* determine total src string length */ -+ } -+ -+ return s - src - 1; -+} -+ -+ -+#ifdef WPA_TRACE -+ -+void * os_malloc(size_t size) -+{ -+ struct os_alloc_trace *a; -+ a = malloc(sizeof(*a) + size); -+ if (a == NULL) -+ return NULL; -+ a->magic = ALLOC_MAGIC; -+ dl_list_add(&alloc_list, &a->list); -+ a->len = size; -+ wpa_trace_record(a); -+ return a + 1; -+} -+ -+ -+void * os_realloc(void *ptr, size_t size) -+{ -+ struct os_alloc_trace *a; -+ size_t copy_len; -+ void *n; -+ -+ if (ptr == NULL) -+ return os_malloc(size); -+ -+ a = (struct os_alloc_trace *) ptr - 1; -+ if (a->magic != ALLOC_MAGIC) { -+ wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", -+ a, a->magic, -+ a->magic == FREED_MAGIC ? " (already freed)" : ""); -+ wpa_trace_show("Invalid os_realloc() call"); -+ abort(); -+ } -+ n = os_malloc(size); -+ if (n == NULL) -+ return NULL; -+ copy_len = a->len; -+ if (copy_len > size) -+ copy_len = size; -+ os_memcpy(n, a + 1, copy_len); -+ os_free(ptr); -+ return n; -+} -+ -+ -+void os_free(void *ptr) -+{ -+ struct os_alloc_trace *a; -+ -+ if (ptr == NULL) -+ return; -+ a = (struct os_alloc_trace *) ptr - 1; -+ if (a->magic != ALLOC_MAGIC) { -+ wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", -+ a, a->magic, -+ a->magic == FREED_MAGIC ? " (already freed)" : ""); -+ wpa_trace_show("Invalid os_free() call"); -+ abort(); -+ } -+ dl_list_del(&a->list); -+ a->magic = FREED_MAGIC; -+ -+ wpa_trace_check_ref(ptr); -+ free(a); -+} -+ -+ -+void * os_zalloc(size_t size) -+{ -+ void *ptr = os_malloc(size); -+ if (ptr) -+ os_memset(ptr, 0, size); -+ return ptr; -+} -+ -+ -+char * os_strdup(const char *s) -+{ -+ size_t len; -+ char *d; -+ len = os_strlen(s); -+ d = os_malloc(len + 1); -+ if (d == NULL) -+ return NULL; -+ os_memcpy(d, s, len); -+ d[len] = '\0'; -+ return d; -+} -+ -+#endif /* WPA_TRACE */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_win32.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_win32.c -new file mode 100644 -index 0000000000000..074096480a405 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/os_win32.c -@@ -0,0 +1,222 @@ -+/* -+ * wpa_supplicant/hostapd / OS specific functions for Win32 systems -+ * Copyright (c) 2005-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+#include -+ -+#include "os.h" -+ -+void os_sleep(os_time_t sec, os_time_t usec) -+{ -+ if (sec) -+ Sleep(sec * 1000); -+ if (usec) -+ Sleep(usec / 1000); -+} -+ -+ -+int os_get_time(struct os_time *t) -+{ -+#define EPOCHFILETIME (116444736000000000ULL) -+ FILETIME ft; -+ LARGE_INTEGER li; -+ ULONGLONG tt; -+ -+#ifdef _WIN32_WCE -+ SYSTEMTIME st; -+ -+ GetSystemTime(&st); -+ SystemTimeToFileTime(&st, &ft); -+#else /* _WIN32_WCE */ -+ GetSystemTimeAsFileTime(&ft); -+#endif /* _WIN32_WCE */ -+ li.LowPart = ft.dwLowDateTime; -+ li.HighPart = ft.dwHighDateTime; -+ tt = (li.QuadPart - EPOCHFILETIME) / 10; -+ t->sec = (os_time_t) (tt / 1000000); -+ t->usec = (os_time_t) (tt % 1000000); -+ -+ return 0; -+} -+ -+ -+int os_mktime(int year, int month, int day, int hour, int min, int sec, -+ os_time_t *t) -+{ -+ struct tm tm, *tm1; -+ time_t t_local, t1, t2; -+ os_time_t tz_offset; -+ -+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || -+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || -+ sec > 60) -+ return -1; -+ -+ memset(&tm, 0, sizeof(tm)); -+ tm.tm_year = year - 1900; -+ tm.tm_mon = month - 1; -+ tm.tm_mday = day; -+ tm.tm_hour = hour; -+ tm.tm_min = min; -+ tm.tm_sec = sec; -+ -+ t_local = mktime(&tm); -+ -+ /* figure out offset to UTC */ -+ tm1 = localtime(&t_local); -+ if (tm1) { -+ t1 = mktime(tm1); -+ tm1 = gmtime(&t_local); -+ if (tm1) { -+ t2 = mktime(tm1); -+ tz_offset = t2 - t1; -+ } else -+ tz_offset = 0; -+ } else -+ tz_offset = 0; -+ -+ *t = (os_time_t) t_local - tz_offset; -+ return 0; -+} -+ -+ -+int os_daemonize(const char *pid_file) -+{ -+ /* TODO */ -+ return -1; -+} -+ -+ -+void os_daemonize_terminate(const char *pid_file) -+{ -+} -+ -+ -+int os_get_random(unsigned char *buf, size_t len) -+{ -+ HCRYPTPROV prov; -+ BOOL ret; -+ -+ if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, -+ CRYPT_VERIFYCONTEXT)) -+ return -1; -+ -+ ret = CryptGenRandom(prov, len, buf); -+ CryptReleaseContext(prov, 0); -+ -+ return ret ? 0 : -1; -+} -+ -+ -+unsigned long os_random(void) -+{ -+ return rand(); -+} -+ -+ -+char * os_rel2abs_path(const char *rel_path) -+{ -+ return _strdup(rel_path); -+} -+ -+ -+int os_program_init(void) -+{ -+#ifdef CONFIG_NATIVE_WINDOWS -+ WSADATA wsaData; -+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { -+ printf("Could not find a usable WinSock.dll\n"); -+ return -1; -+ } -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ return 0; -+} -+ -+ -+void os_program_deinit(void) -+{ -+#ifdef CONFIG_NATIVE_WINDOWS -+ WSACleanup(); -+#endif /* CONFIG_NATIVE_WINDOWS */ -+} -+ -+ -+int os_setenv(const char *name, const char *value, int overwrite) -+{ -+ return -1; -+} -+ -+ -+int os_unsetenv(const char *name) -+{ -+ return -1; -+} -+ -+ -+char * os_readfile(const char *name, size_t *len) -+{ -+ FILE *f; -+ char *buf; -+ -+ f = fopen(name, "rb"); -+ if (f == NULL) -+ return NULL; -+ -+ fseek(f, 0, SEEK_END); -+ *len = ftell(f); -+ fseek(f, 0, SEEK_SET); -+ -+ buf = malloc(*len); -+ if (buf == NULL) { -+ fclose(f); -+ return NULL; -+ } -+ -+ fread(buf, 1, *len, f); -+ fclose(f); -+ -+ return buf; -+} -+ -+ -+void * os_zalloc(size_t size) -+{ -+ return calloc(1, size); -+} -+ -+ -+size_t os_strlcpy(char *dest, const char *src, size_t siz) -+{ -+ const char *s = src; -+ size_t left = siz; -+ -+ if (left) { -+ /* Copy string up to the maximum size of the dest buffer */ -+ while (--left != 0) { -+ if ((*dest++ = *s++) == '\0') -+ break; -+ } -+ } -+ -+ if (left == 0) { -+ /* Not enough room for the string; force NUL-termination */ -+ if (siz != 0) -+ *dest = '\0'; -+ while (*s++) -+ ; /* determine total src string length */ -+ } -+ -+ return s - src - 1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.c -new file mode 100644 -index 0000000000000..bf9f04a719b1d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.c -@@ -0,0 +1,1238 @@ -+/* -+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM -+ * Copyright (c) 2004-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM -+ * cards through PC/SC smartcard library. These functions are used to implement -+ * authentication routines for EAP-SIM and EAP-AKA. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "pcsc_funcs.h" -+ -+ -+/* See ETSI GSM 11.11 and ETSI TS 102 221 for details. -+ * SIM commands: -+ * Command APDU: CLA INS P1 P2 P3 Data -+ * CLA (class of instruction): A0 for GSM, 00 for USIM -+ * INS (instruction) -+ * P1 P2 P3 (parameters, P3 = length of Data) -+ * Response APDU: Data SW1 SW2 -+ * SW1 SW2 (Status words) -+ * Commands (INS P1 P2 P3): -+ * SELECT: A4 00 00 02 -+ * GET RESPONSE: C0 00 00 -+ * RUN GSM ALG: 88 00 00 00 -+ * RUN UMTS ALG: 88 00 81 data: 0x10 | RAND | 0x10 | AUTN -+ * P1 = ID of alg in card -+ * P2 = ID of secret key -+ * READ BINARY: B0 -+ * READ RECORD: B2 -+ * P2 (mode) = '02' (next record), '03' (previous record), -+ * '04' (absolute mode) -+ * VERIFY CHV: 20 00 08 -+ * CHANGE CHV: 24 00 10 -+ * DISABLE CHV: 26 00 01 08 -+ * ENABLE CHV: 28 00 01 08 -+ * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10 -+ * SLEEP: FA 00 00 00 -+ */ -+ -+/* GSM SIM commands */ -+#define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02 -+#define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10 -+#define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00 -+#define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00 -+#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00 -+#define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08 -+ -+/* USIM commands */ -+#define USIM_CLA 0x00 -+#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22 -+#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00 -+ -+#define SIM_RECORD_MODE_ABSOLUTE 0x04 -+ -+#define USIM_FSP_TEMPL_TAG 0x62 -+ -+#define USIM_TLV_FILE_DESC 0x82 -+#define USIM_TLV_FILE_ID 0x83 -+#define USIM_TLV_DF_NAME 0x84 -+#define USIM_TLV_PROPR_INFO 0xA5 -+#define USIM_TLV_LIFE_CYCLE_STATUS 0x8A -+#define USIM_TLV_FILE_SIZE 0x80 -+#define USIM_TLV_TOTAL_FILE_SIZE 0x81 -+#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6 -+#define USIM_TLV_SHORT_FILE_ID 0x88 -+ -+#define USIM_PS_DO_TAG 0x90 -+ -+#define AKA_RAND_LEN 16 -+#define AKA_AUTN_LEN 16 -+#define AKA_AUTS_LEN 14 -+#define RES_MAX_LEN 16 -+#define IK_LEN 16 -+#define CK_LEN 16 -+ -+ -+typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; -+ -+struct scard_data { -+ SCARDCONTEXT ctx; -+ SCARDHANDLE card; -+ DWORD protocol; -+ sim_types sim_type; -+ int pin1_required; -+}; -+ -+#ifdef __MINGW32_VERSION -+/* MinGW does not yet support WinScard, so load the needed functions -+ * dynamically from winscard.dll for now. */ -+ -+static HINSTANCE dll = NULL; /* winscard.dll */ -+ -+static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci; -+#undef SCARD_PCI_T0 -+#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci) -+#undef SCARD_PCI_T1 -+#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci) -+ -+ -+static WINSCARDAPI LONG WINAPI -+(*dll_SCardEstablishContext)(IN DWORD dwScope, -+ IN LPCVOID pvReserved1, -+ IN LPCVOID pvReserved2, -+ OUT LPSCARDCONTEXT phContext); -+#define SCardEstablishContext dll_SCardEstablishContext -+ -+static long (*dll_SCardReleaseContext)(long hContext); -+#define SCardReleaseContext dll_SCardReleaseContext -+ -+static WINSCARDAPI LONG WINAPI -+(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext, -+ IN LPCSTR mszGroups, -+ OUT LPSTR mszReaders, -+ IN OUT LPDWORD pcchReaders); -+#undef SCardListReaders -+#define SCardListReaders dll_SCardListReadersA -+ -+static WINSCARDAPI LONG WINAPI -+(*dll_SCardConnectA)(IN SCARDCONTEXT hContext, -+ IN LPCSTR szReader, -+ IN DWORD dwShareMode, -+ IN DWORD dwPreferredProtocols, -+ OUT LPSCARDHANDLE phCard, -+ OUT LPDWORD pdwActiveProtocol); -+#undef SCardConnect -+#define SCardConnect dll_SCardConnectA -+ -+static WINSCARDAPI LONG WINAPI -+(*dll_SCardDisconnect)(IN SCARDHANDLE hCard, -+ IN DWORD dwDisposition); -+#define SCardDisconnect dll_SCardDisconnect -+ -+static WINSCARDAPI LONG WINAPI -+(*dll_SCardTransmit)(IN SCARDHANDLE hCard, -+ IN LPCSCARD_IO_REQUEST pioSendPci, -+ IN LPCBYTE pbSendBuffer, -+ IN DWORD cbSendLength, -+ IN OUT LPSCARD_IO_REQUEST pioRecvPci, -+ OUT LPBYTE pbRecvBuffer, -+ IN OUT LPDWORD pcbRecvLength); -+#define SCardTransmit dll_SCardTransmit -+ -+static WINSCARDAPI LONG WINAPI -+(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard); -+#define SCardBeginTransaction dll_SCardBeginTransaction -+ -+static WINSCARDAPI LONG WINAPI -+(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); -+#define SCardEndTransaction dll_SCardEndTransaction -+ -+ -+static int mingw_load_symbols(void) -+{ -+ char *sym; -+ -+ if (dll) -+ return 0; -+ -+ dll = LoadLibrary("winscard"); -+ if (dll == NULL) { -+ wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll " -+ "library"); -+ return -1; -+ } -+ -+#define LOADSYM(s) \ -+ sym = #s; \ -+ dll_ ## s = (void *) GetProcAddress(dll, sym); \ -+ if (dll_ ## s == NULL) \ -+ goto fail; -+ -+ LOADSYM(SCardEstablishContext); -+ LOADSYM(SCardReleaseContext); -+ LOADSYM(SCardListReadersA); -+ LOADSYM(SCardConnectA); -+ LOADSYM(SCardDisconnect); -+ LOADSYM(SCardTransmit); -+ LOADSYM(SCardBeginTransaction); -+ LOADSYM(SCardEndTransaction); -+ LOADSYM(g_rgSCardT0Pci); -+ LOADSYM(g_rgSCardT1Pci); -+ -+#undef LOADSYM -+ -+ return 0; -+ -+fail: -+ wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from " -+ "winscard.dll", sym); -+ FreeLibrary(dll); -+ dll = NULL; -+ return -1; -+} -+ -+ -+static void mingw_unload_symbols(void) -+{ -+ if (dll == NULL) -+ return; -+ -+ FreeLibrary(dll); -+ dll = NULL; -+} -+ -+#else /* __MINGW32_VERSION */ -+ -+#define mingw_load_symbols() 0 -+#define mingw_unload_symbols() do { } while (0) -+ -+#endif /* __MINGW32_VERSION */ -+ -+ -+static int _scard_select_file(struct scard_data *scard, unsigned short file_id, -+ unsigned char *buf, size_t *buf_len, -+ sim_types sim_type, unsigned char *aid, -+ size_t aidlen); -+static int scard_select_file(struct scard_data *scard, unsigned short file_id, -+ unsigned char *buf, size_t *buf_len); -+static int scard_verify_pin(struct scard_data *scard, const char *pin); -+static int scard_get_record_len(struct scard_data *scard, -+ unsigned char recnum, unsigned char mode); -+static int scard_read_record(struct scard_data *scard, -+ unsigned char *data, size_t len, -+ unsigned char recnum, unsigned char mode); -+ -+ -+static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, -+ int *ps_do, int *file_len) -+{ -+ unsigned char *pos, *end; -+ -+ if (ps_do) -+ *ps_do = -1; -+ if (file_len) -+ *file_len = -1; -+ -+ pos = buf; -+ end = pos + buf_len; -+ if (*pos != USIM_FSP_TEMPL_TAG) { -+ wpa_printf(MSG_DEBUG, "SCARD: file header did not " -+ "start with FSP template tag"); -+ return -1; -+ } -+ pos++; -+ if (pos >= end) -+ return -1; -+ if ((pos + pos[0]) < end) -+ end = pos + 1 + pos[0]; -+ pos++; -+ wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template", -+ pos, end - pos); -+ -+ while (pos + 1 < end) { -+ wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV " -+ "0x%02x len=%d", pos[0], pos[1]); -+ if (pos + 2 + pos[1] > end) -+ break; -+ -+ if (pos[0] == USIM_TLV_FILE_SIZE && -+ (pos[1] == 1 || pos[1] == 2) && file_len) { -+ if (pos[1] == 1) -+ *file_len = (int) pos[2]; -+ else -+ *file_len = ((int) pos[2] << 8) | -+ (int) pos[3]; -+ wpa_printf(MSG_DEBUG, "SCARD: file_size=%d", -+ *file_len); -+ } -+ -+ if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE && -+ pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG && -+ pos[3] >= 1 && ps_do) { -+ wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x", -+ pos[4]); -+ *ps_do = (int) pos[4]; -+ } -+ -+ pos += 2 + pos[1]; -+ -+ if (pos == end) -+ return 0; -+ } -+ return -1; -+} -+ -+ -+static int scard_pin_needed(struct scard_data *scard, -+ unsigned char *hdr, size_t hlen) -+{ -+ if (scard->sim_type == SCARD_GSM_SIM) { -+ if (hlen > SCARD_CHV1_OFFSET && -+ !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG)) -+ return 1; -+ return 0; -+ } -+ -+ if (scard->sim_type == SCARD_USIM) { -+ int ps_do; -+ if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL)) -+ return -1; -+ /* TODO: there could be more than one PS_DO entry because of -+ * multiple PINs in key reference.. */ -+ if (ps_do > 0 && (ps_do & 0x80)) -+ return 1; -+ return 0; -+ } -+ -+ return -1; -+} -+ -+ -+static int scard_get_aid(struct scard_data *scard, unsigned char *aid, -+ size_t maxlen) -+{ -+ int rlen, rec; -+ struct efdir { -+ unsigned char appl_template_tag; /* 0x61 */ -+ unsigned char appl_template_len; -+ unsigned char appl_id_tag; /* 0x4f */ -+ unsigned char aid_len; -+ unsigned char rid[5]; -+ unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ -+ } *efdir; -+ unsigned char buf[100]; -+ size_t blen; -+ -+ efdir = (struct efdir *) buf; -+ blen = sizeof(buf); -+ if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR"); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen); -+ -+ for (rec = 1; rec < 10; rec++) { -+ rlen = scard_get_record_len(scard, rec, -+ SIM_RECORD_MODE_ABSOLUTE); -+ if (rlen < 0) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR " -+ "record length"); -+ return -1; -+ } -+ blen = sizeof(buf); -+ if (rlen > (int) blen) { -+ wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record"); -+ return -1; -+ } -+ if (scard_read_record(scard, buf, rlen, rec, -+ SIM_RECORD_MODE_ABSOLUTE) < 0) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read " -+ "EF_DIR record %d", rec); -+ return -1; -+ } -+ wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen); -+ -+ if (efdir->appl_template_tag != 0x61) { -+ wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " -+ "template tag 0x%x", -+ efdir->appl_template_tag); -+ continue; -+ } -+ -+ if (efdir->appl_template_len > rlen - 2) { -+ wpa_printf(MSG_DEBUG, "SCARD: Too long application " -+ "template (len=%d rlen=%d)", -+ efdir->appl_template_len, rlen); -+ continue; -+ } -+ -+ if (efdir->appl_id_tag != 0x4f) { -+ wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " -+ "identifier tag 0x%x", efdir->appl_id_tag); -+ continue; -+ } -+ -+ if (efdir->aid_len < 1 || efdir->aid_len > 16) { -+ wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d", -+ efdir->aid_len); -+ continue; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record", -+ efdir->rid, efdir->aid_len); -+ -+ if (efdir->appl_code[0] == 0x10 && -+ efdir->appl_code[1] == 0x02) { -+ wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from " -+ "EF_DIR record %d", rec); -+ break; -+ } -+ } -+ -+ if (rec >= 10) { -+ wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found " -+ "from EF_DIR records"); -+ return -1; -+ } -+ -+ if (efdir->aid_len > maxlen) { -+ wpa_printf(MSG_DEBUG, "SCARD: Too long AID"); -+ return -1; -+ } -+ -+ os_memcpy(aid, efdir->rid, efdir->aid_len); -+ -+ return efdir->aid_len; -+} -+ -+ -+/** -+ * scard_init - Initialize SIM/USIM connection using PC/SC -+ * @sim_type: Allowed SIM types (SIM, USIM, or both) -+ * Returns: Pointer to private data structure, or %NULL on failure -+ * -+ * This function is used to initialize SIM/USIM connection. PC/SC is used to -+ * open connection to the SIM/USIM card and the card is verified to support the -+ * selected sim_type. In addition, local flag is set if a PIN is needed to -+ * access some of the card functions. Once the connection is not needed -+ * anymore, scard_deinit() can be used to close it. -+ */ -+struct scard_data * scard_init(scard_sim_type sim_type) -+{ -+ long ret; -+ unsigned long len; -+ struct scard_data *scard; -+#ifdef CONFIG_NATIVE_WINDOWS -+ TCHAR *readers = NULL; -+#else /* CONFIG_NATIVE_WINDOWS */ -+ char *readers = NULL; -+#endif /* CONFIG_NATIVE_WINDOWS */ -+ unsigned char buf[100]; -+ size_t blen; -+ int transaction = 0; -+ int pin_needed; -+ -+ wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface"); -+ if (mingw_load_symbols()) -+ return NULL; -+ scard = os_zalloc(sizeof(*scard)); -+ if (scard == NULL) -+ return NULL; -+ -+ ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, -+ &scard->ctx); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card " -+ "context (err=%ld)", ret); -+ goto failed; -+ } -+ -+ ret = SCardListReaders(scard->ctx, NULL, NULL, &len); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed " -+ "(err=%ld)", ret); -+ goto failed; -+ } -+ -+#ifdef UNICODE -+ len *= 2; -+#endif /* UNICODE */ -+ readers = os_malloc(len); -+ if (readers == NULL) { -+ wpa_printf(MSG_INFO, "SCARD: malloc failed\n"); -+ goto failed; -+ } -+ -+ ret = SCardListReaders(scard->ctx, NULL, readers, &len); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) " -+ "(err=%ld)", ret); -+ goto failed; -+ } -+ if (len < 3) { -+ wpa_printf(MSG_WARNING, "SCARD: No smart card readers " -+ "available."); -+ goto failed; -+ } -+ /* readers is a list of available reader. Last entry is terminated with -+ * double NUL. -+ * TODO: add support for selecting the reader; now just use the first -+ * one.. */ -+#ifdef UNICODE -+ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); -+#else /* UNICODE */ -+ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); -+#endif /* UNICODE */ -+ -+ ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED, -+ SCARD_PROTOCOL_T0, &scard->card, &scard->protocol); -+ if (ret != SCARD_S_SUCCESS) { -+ if (ret == (long) SCARD_E_NO_SMARTCARD) -+ wpa_printf(MSG_INFO, "No smart card inserted."); -+ else -+ wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret); -+ goto failed; -+ } -+ -+ os_free(readers); -+ readers = NULL; -+ -+ wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", -+ (unsigned int) scard->card, scard->protocol, -+ scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); -+ -+ ret = SCardBeginTransaction(scard->card); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: " -+ "0x%x", (unsigned int) ret); -+ goto failed; -+ } -+ transaction = 1; -+ -+ blen = sizeof(buf); -+ -+ scard->sim_type = SCARD_GSM_SIM; -+ if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) { -+ wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support"); -+ if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen, -+ SCARD_USIM, NULL, 0)) { -+ wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported"); -+ if (sim_type == SCARD_USIM_ONLY) -+ goto failed; -+ wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM"); -+ scard->sim_type = SCARD_GSM_SIM; -+ } else { -+ wpa_printf(MSG_DEBUG, "SCARD: USIM is supported"); -+ scard->sim_type = SCARD_USIM; -+ } -+ } -+ -+ if (scard->sim_type == SCARD_GSM_SIM) { -+ blen = sizeof(buf); -+ if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF"); -+ goto failed; -+ } -+ -+ blen = sizeof(buf); -+ if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF"); -+ goto failed; -+ } -+ } else { -+ unsigned char aid[32]; -+ int aid_len; -+ -+ aid_len = scard_get_aid(scard, aid, sizeof(aid)); -+ if (aid_len < 0) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for " -+ "3G USIM app - try to use standard 3G RID"); -+ os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5); -+ aid_len = 5; -+ } -+ wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len); -+ -+ /* Select based on AID = 3G RID from EF_DIR. This is usually -+ * starting with A0 00 00 00 87. */ -+ blen = sizeof(buf); -+ if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type, -+ aid, aid_len)) { -+ wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM " -+ "app"); -+ wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID", -+ aid, aid_len); -+ goto failed; -+ } -+ } -+ -+ /* Verify whether CHV1 (PIN1) is needed to access the card. */ -+ pin_needed = scard_pin_needed(scard, buf, blen); -+ if (pin_needed < 0) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN " -+ "is needed"); -+ goto failed; -+ } -+ if (pin_needed) { -+ scard->pin1_required = 1; -+ wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access"); -+ } -+ -+ ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: " -+ "0x%x", (unsigned int) ret); -+ } -+ -+ return scard; -+ -+failed: -+ if (transaction) -+ SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); -+ os_free(readers); -+ scard_deinit(scard); -+ return NULL; -+} -+ -+ -+/** -+ * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands -+ * @scard: Pointer to private data from scard_init() -+ * @pin: PIN code as an ASCII string (e.g., "1234") -+ * Returns: 0 on success, -1 on failure -+ */ -+int scard_set_pin(struct scard_data *scard, const char *pin) -+{ -+ if (scard == NULL) -+ return -1; -+ -+ /* Verify whether CHV1 (PIN1) is needed to access the card. */ -+ if (scard->pin1_required) { -+ if (pin == NULL) { -+ wpa_printf(MSG_DEBUG, "No PIN configured for SIM " -+ "access"); -+ return -1; -+ } -+ if (scard_verify_pin(scard, pin)) { -+ wpa_printf(MSG_INFO, "PIN verification failed for " -+ "SIM access"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * scard_deinit - Deinitialize SIM/USIM connection -+ * @scard: Pointer to private data from scard_init() -+ * -+ * This function closes the SIM/USIM connect opened with scard_init(). -+ */ -+void scard_deinit(struct scard_data *scard) -+{ -+ long ret; -+ -+ if (scard == NULL) -+ return; -+ -+ wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface"); -+ if (scard->card) { -+ ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect " -+ "smart card (err=%ld)", ret); -+ } -+ } -+ -+ if (scard->ctx) { -+ ret = SCardReleaseContext(scard->ctx); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "Failed to release smart card " -+ "context (err=%ld)", ret); -+ } -+ } -+ os_free(scard); -+ mingw_unload_symbols(); -+} -+ -+ -+static long scard_transmit(struct scard_data *scard, -+ unsigned char *_send, size_t send_len, -+ unsigned char *_recv, size_t *recv_len) -+{ -+ long ret; -+ unsigned long rlen; -+ -+ wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", -+ _send, send_len); -+ rlen = *recv_len; -+ ret = SCardTransmit(scard->card, -+ scard->protocol == SCARD_PROTOCOL_T1 ? -+ SCARD_PCI_T1 : SCARD_PCI_T0, -+ _send, (unsigned long) send_len, -+ NULL, _recv, &rlen); -+ *recv_len = rlen; -+ if (ret == SCARD_S_SUCCESS) { -+ wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv", -+ _recv, rlen); -+ } else { -+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " -+ "(err=0x%lx)", ret); -+ } -+ return ret; -+} -+ -+ -+static int _scard_select_file(struct scard_data *scard, unsigned short file_id, -+ unsigned char *buf, size_t *buf_len, -+ sim_types sim_type, unsigned char *aid, -+ size_t aidlen) -+{ -+ long ret; -+ unsigned char resp[3]; -+ unsigned char cmd[50] = { SIM_CMD_SELECT }; -+ int cmdlen; -+ unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; -+ size_t len, rlen; -+ -+ if (sim_type == SCARD_USIM) { -+ cmd[0] = USIM_CLA; -+ cmd[3] = 0x04; -+ get_resp[0] = USIM_CLA; -+ } -+ -+ wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id); -+ if (aid) { -+ wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID", -+ aid, aidlen); -+ if (5 + aidlen > sizeof(cmd)) -+ return -1; -+ cmd[2] = 0x04; /* Select by AID */ -+ cmd[4] = aidlen; /* len */ -+ os_memcpy(cmd + 5, aid, aidlen); -+ cmdlen = 5 + aidlen; -+ } else { -+ cmd[5] = file_id >> 8; -+ cmd[6] = file_id & 0xff; -+ cmdlen = 7; -+ } -+ len = sizeof(resp); -+ ret = scard_transmit(scard, cmd, cmdlen, resp, &len); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " -+ "(err=0x%lx)", ret); -+ return -1; -+ } -+ -+ if (len != 2) { -+ wpa_printf(MSG_WARNING, "SCARD: unexpected resp len " -+ "%d (expected 2)", (int) len); -+ return -1; -+ } -+ -+ if (resp[0] == 0x98 && resp[1] == 0x04) { -+ /* Security status not satisfied (PIN_WLAN) */ -+ wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied " -+ "(PIN_WLAN)"); -+ return -1; -+ } -+ -+ if (resp[0] == 0x6e) { -+ wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported"); -+ return -1; -+ } -+ -+ if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) { -+ wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x " -+ "(expected 0x61, 0x6c, or 0x9f)", resp[0]); -+ return -1; -+ } -+ /* Normal ending of command; resp[1] bytes available */ -+ get_resp[4] = resp[1]; -+ wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)", -+ resp[1]); -+ -+ rlen = *buf_len; -+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen); -+ if (ret == SCARD_S_SUCCESS) { -+ *buf_len = resp[1] < rlen ? resp[1] : rlen; -+ return 0; -+ } -+ -+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret); -+ return -1; -+} -+ -+ -+static int scard_select_file(struct scard_data *scard, unsigned short file_id, -+ unsigned char *buf, size_t *buf_len) -+{ -+ return _scard_select_file(scard, file_id, buf, buf_len, -+ scard->sim_type, NULL, 0); -+} -+ -+ -+static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, -+ unsigned char mode) -+{ -+ unsigned char buf[255]; -+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; -+ size_t blen; -+ long ret; -+ -+ if (scard->sim_type == SCARD_USIM) -+ cmd[0] = USIM_CLA; -+ cmd[2] = recnum; -+ cmd[3] = mode; -+ cmd[4] = sizeof(buf); -+ -+ blen = sizeof(buf); -+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); -+ if (ret != SCARD_S_SUCCESS) { -+ wpa_printf(MSG_DEBUG, "SCARD: failed to determine file " -+ "length for record %d", recnum); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", -+ buf, blen); -+ -+ if (blen < 2 || buf[0] != 0x6c) { -+ wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " -+ "length determination"); -+ return -1; -+ } -+ -+ return buf[1]; -+} -+ -+ -+static int scard_read_record(struct scard_data *scard, -+ unsigned char *data, size_t len, -+ unsigned char recnum, unsigned char mode) -+{ -+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; -+ size_t blen = len + 3; -+ unsigned char *buf; -+ long ret; -+ -+ if (scard->sim_type == SCARD_USIM) -+ cmd[0] = USIM_CLA; -+ cmd[2] = recnum; -+ cmd[3] = mode; -+ cmd[4] = len; -+ -+ buf = os_malloc(blen); -+ if (buf == NULL) -+ return -1; -+ -+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); -+ if (ret != SCARD_S_SUCCESS) { -+ os_free(buf); -+ return -2; -+ } -+ if (blen != len + 2) { -+ wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " -+ "length %ld (expected %ld)", -+ (long) blen, (long) len + 2); -+ os_free(buf); -+ return -3; -+ } -+ -+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) { -+ wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " -+ "status %02x %02x (expected 90 00)", -+ buf[len], buf[len + 1]); -+ os_free(buf); -+ return -4; -+ } -+ -+ os_memcpy(data, buf, len); -+ os_free(buf); -+ -+ return 0; -+} -+ -+ -+static int scard_read_file(struct scard_data *scard, -+ unsigned char *data, size_t len) -+{ -+ unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ }; -+ size_t blen = len + 3; -+ unsigned char *buf; -+ long ret; -+ -+ cmd[4] = len; -+ -+ buf = os_malloc(blen); -+ if (buf == NULL) -+ return -1; -+ -+ if (scard->sim_type == SCARD_USIM) -+ cmd[0] = USIM_CLA; -+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); -+ if (ret != SCARD_S_SUCCESS) { -+ os_free(buf); -+ return -2; -+ } -+ if (blen != len + 2) { -+ wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " -+ "length %ld (expected %ld)", -+ (long) blen, (long) len + 2); -+ os_free(buf); -+ return -3; -+ } -+ -+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) { -+ wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " -+ "status %02x %02x (expected 90 00)", -+ buf[len], buf[len + 1]); -+ os_free(buf); -+ return -4; -+ } -+ -+ os_memcpy(data, buf, len); -+ os_free(buf); -+ -+ return 0; -+} -+ -+ -+static int scard_verify_pin(struct scard_data *scard, const char *pin) -+{ -+ long ret; -+ unsigned char resp[3]; -+ unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; -+ size_t len; -+ -+ wpa_printf(MSG_DEBUG, "SCARD: verifying PIN"); -+ -+ if (pin == NULL || os_strlen(pin) > 8) -+ return -1; -+ -+ if (scard->sim_type == SCARD_USIM) -+ cmd[0] = USIM_CLA; -+ os_memcpy(cmd + 5, pin, os_strlen(pin)); -+ os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin)); -+ -+ len = sizeof(resp); -+ ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); -+ if (ret != SCARD_S_SUCCESS) -+ return -2; -+ -+ if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) { -+ wpa_printf(MSG_WARNING, "SCARD: PIN verification failed"); -+ return -1; -+ } -+ -+ wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully"); -+ return 0; -+} -+ -+ -+/** -+ * scard_get_imsi - Read IMSI from SIM/USIM card -+ * @scard: Pointer to private data from scard_init() -+ * @imsi: Buffer for IMSI -+ * @len: Length of imsi buffer; set to IMSI length on success -+ * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file -+ * selection returns invalid result code, -3 if parsing FSP template file fails -+ * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set -+ * to needed length), -5 if reading IMSI file fails. -+ * -+ * This function can be used to read IMSI from the SIM/USIM card. If the IMSI -+ * file is PIN protected, scard_set_pin() must have been used to set the -+ * correct PIN code before calling scard_get_imsi(). -+ */ -+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) -+{ -+ unsigned char buf[100]; -+ size_t blen, imsilen, i; -+ char *pos; -+ -+ wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI"); -+ blen = sizeof(buf); -+ if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen)) -+ return -1; -+ if (blen < 4) { -+ wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI " -+ "header (len=%ld)", (long) blen); -+ return -2; -+ } -+ -+ if (scard->sim_type == SCARD_GSM_SIM) { -+ blen = (buf[2] << 8) | buf[3]; -+ } else { -+ int file_size; -+ if (scard_parse_fsp_templ(buf, blen, NULL, &file_size)) -+ return -3; -+ blen = file_size; -+ } -+ if (blen < 2 || blen > sizeof(buf)) { -+ wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld", -+ (long) blen); -+ return -3; -+ } -+ -+ imsilen = (blen - 2) * 2 + 1; -+ wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld", -+ (long) blen, (long) imsilen); -+ if (blen < 2 || imsilen > *len) { -+ *len = imsilen; -+ return -4; -+ } -+ -+ if (scard_read_file(scard, buf, blen)) -+ return -5; -+ -+ pos = imsi; -+ *pos++ = '0' + (buf[1] >> 4 & 0x0f); -+ for (i = 2; i < blen; i++) { -+ unsigned char digit; -+ -+ digit = buf[i] & 0x0f; -+ if (digit < 10) -+ *pos++ = '0' + digit; -+ else -+ imsilen--; -+ -+ digit = buf[i] >> 4 & 0x0f; -+ if (digit < 10) -+ *pos++ = '0' + digit; -+ else -+ imsilen--; -+ } -+ *len = imsilen; -+ -+ return 0; -+} -+ -+ -+/** -+ * scard_gsm_auth - Run GSM authentication command on SIM card -+ * @scard: Pointer to private data from scard_init() -+ * @_rand: 16-byte RAND value from HLR/AuC -+ * @sres: 4-byte buffer for SRES -+ * @kc: 8-byte buffer for Kc -+ * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized, -+ * -2 if authentication command execution fails, -3 if unknown response code -+ * for authentication command is received, -4 if reading of response fails, -+ * -5 if if response data is of unexpected length -+ * -+ * This function performs GSM authentication using SIM/USIM card and the -+ * provided RAND value from HLR/AuC. If authentication command can be completed -+ * successfully, SRES and Kc values will be written into sres and kc buffers. -+ */ -+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, -+ unsigned char *sres, unsigned char *kc) -+{ -+ unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG }; -+ int cmdlen; -+ unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; -+ unsigned char resp[3], buf[12 + 3 + 2]; -+ size_t len; -+ long ret; -+ -+ if (scard == NULL) -+ return -1; -+ -+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16); -+ if (scard->sim_type == SCARD_GSM_SIM) { -+ cmdlen = 5 + 16; -+ os_memcpy(cmd + 5, _rand, 16); -+ } else { -+ cmdlen = 5 + 1 + 16; -+ cmd[0] = USIM_CLA; -+ cmd[3] = 0x80; -+ cmd[4] = 17; -+ cmd[5] = 16; -+ os_memcpy(cmd + 6, _rand, 16); -+ } -+ len = sizeof(resp); -+ ret = scard_transmit(scard, cmd, cmdlen, resp, &len); -+ if (ret != SCARD_S_SUCCESS) -+ return -2; -+ -+ if ((scard->sim_type == SCARD_GSM_SIM && -+ (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) || -+ (scard->sim_type == SCARD_USIM && -+ (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) { -+ wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM " -+ "auth request (len=%ld resp=%02x %02x)", -+ (long) len, resp[0], resp[1]); -+ return -3; -+ } -+ get_resp[4] = resp[1]; -+ -+ len = sizeof(buf); -+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); -+ if (ret != SCARD_S_SUCCESS) -+ return -4; -+ -+ if (scard->sim_type == SCARD_GSM_SIM) { -+ if (len != 4 + 8 + 2) { -+ wpa_printf(MSG_WARNING, "SCARD: unexpected data " -+ "length for GSM auth (len=%ld, expected 14)", -+ (long) len); -+ return -5; -+ } -+ os_memcpy(sres, buf, 4); -+ os_memcpy(kc, buf + 4, 8); -+ } else { -+ if (len != 1 + 4 + 1 + 8 + 2) { -+ wpa_printf(MSG_WARNING, "SCARD: unexpected data " -+ "length for USIM auth (len=%ld, " -+ "expected 16)", (long) len); -+ return -5; -+ } -+ if (buf[0] != 4 || buf[5] != 8) { -+ wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc " -+ "length (%d %d, expected 4 8)", -+ buf[0], buf[5]); -+ } -+ os_memcpy(sres, buf + 1, 4); -+ os_memcpy(kc, buf + 6, 8); -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4); -+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8); -+ -+ return 0; -+} -+ -+ -+/** -+ * scard_umts_auth - Run UMTS authentication command on USIM card -+ * @scard: Pointer to private data from scard_init() -+ * @_rand: 16-byte RAND value from HLR/AuC -+ * @autn: 16-byte AUTN value from HLR/AuC -+ * @res: 16-byte buffer for RES -+ * @res_len: Variable that will be set to RES length -+ * @ik: 16-byte buffer for IK -+ * @ck: 16-byte buffer for CK -+ * @auts: 14-byte buffer for AUTS -+ * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization -+ * failure -+ * -+ * This function performs AKA authentication using USIM card and the provided -+ * RAND and AUTN values from HLR/AuC. If authentication command can be -+ * completed successfully, RES, IK, and CK values will be written into provided -+ * buffers and res_len is set to length of received RES value. If USIM reports -+ * synchronization failure, the received AUTS value will be written into auts -+ * buffer. In this case, RES, IK, and CK are not valid. -+ */ -+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, -+ const unsigned char *autn, -+ unsigned char *res, size_t *res_len, -+ unsigned char *ik, unsigned char *ck, unsigned char *auts) -+{ -+ unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = -+ { USIM_CMD_RUN_UMTS_ALG }; -+ unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE }; -+ unsigned char resp[3], buf[64], *pos, *end; -+ size_t len; -+ long ret; -+ -+ if (scard == NULL) -+ return -1; -+ -+ if (scard->sim_type == SCARD_GSM_SIM) { -+ wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS " -+ "auth"); -+ return -1; -+ } -+ -+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN); -+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN); -+ cmd[5] = AKA_RAND_LEN; -+ os_memcpy(cmd + 6, _rand, AKA_RAND_LEN); -+ cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN; -+ os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); -+ -+ len = sizeof(resp); -+ ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); -+ if (ret != SCARD_S_SUCCESS) -+ return -1; -+ -+ if (len <= sizeof(resp)) -+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len); -+ -+ if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) { -+ wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - " -+ "MAC != XMAC"); -+ return -1; -+ } else if (len != 2 || resp[0] != 0x61) { -+ wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS " -+ "auth request (len=%ld resp=%02x %02x)", -+ (long) len, resp[0], resp[1]); -+ return -1; -+ } -+ get_resp[4] = resp[1]; -+ -+ len = sizeof(buf); -+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); -+ if (ret != SCARD_S_SUCCESS || len > sizeof(buf)) -+ return -1; -+ -+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len); -+ if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && -+ buf[1] == AKA_AUTS_LEN) { -+ wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure"); -+ os_memcpy(auts, buf + 2, AKA_AUTS_LEN); -+ wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN); -+ return -2; -+ } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { -+ pos = buf + 1; -+ end = buf + len; -+ -+ /* RES */ -+ if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) { -+ wpa_printf(MSG_DEBUG, "SCARD: Invalid RES"); -+ return -1; -+ } -+ *res_len = *pos++; -+ os_memcpy(res, pos, *res_len); -+ pos += *res_len; -+ wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); -+ -+ /* CK */ -+ if (pos[0] != CK_LEN || pos + CK_LEN > end) { -+ wpa_printf(MSG_DEBUG, "SCARD: Invalid CK"); -+ return -1; -+ } -+ pos++; -+ os_memcpy(ck, pos, CK_LEN); -+ pos += CK_LEN; -+ wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); -+ -+ /* IK */ -+ if (pos[0] != IK_LEN || pos + IK_LEN > end) { -+ wpa_printf(MSG_DEBUG, "SCARD: Invalid IK"); -+ return -1; -+ } -+ pos++; -+ os_memcpy(ik, pos, IK_LEN); -+ pos += IK_LEN; -+ wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); -+ -+ return 0; -+ } -+ -+ wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response"); -+ return -1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.h -new file mode 100644 -index 0000000000000..543f7c598419a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/pcsc_funcs.h -@@ -0,0 +1,68 @@ -+/* -+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM -+ * Copyright (c) 2004-2006, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef PCSC_FUNCS_H -+#define PCSC_FUNCS_H -+ -+/* GSM files -+ * File type in first octet: -+ * 3F = Master File -+ * 7F = Dedicated File -+ * 2F = Elementary File under the Master File -+ * 6F = Elementary File under a Dedicated File -+ */ -+#define SCARD_FILE_MF 0x3F00 -+#define SCARD_FILE_GSM_DF 0x7F20 -+#define SCARD_FILE_UMTS_DF 0x7F50 -+#define SCARD_FILE_GSM_EF_IMSI 0x6F07 -+#define SCARD_FILE_EF_DIR 0x2F00 -+#define SCARD_FILE_EF_ICCID 0x2FE2 -+#define SCARD_FILE_EF_CK 0x6FE1 -+#define SCARD_FILE_EF_IK 0x6FE2 -+ -+#define SCARD_CHV1_OFFSET 13 -+#define SCARD_CHV1_FLAG 0x80 -+ -+typedef enum { -+ SCARD_GSM_SIM_ONLY, -+ SCARD_USIM_ONLY, -+ SCARD_TRY_BOTH -+} scard_sim_type; -+ -+ -+#ifdef PCSC_FUNCS -+struct scard_data * scard_init(scard_sim_type sim_type); -+void scard_deinit(struct scard_data *scard); -+ -+int scard_set_pin(struct scard_data *scard, const char *pin); -+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len); -+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, -+ unsigned char *sres, unsigned char *kc); -+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, -+ const unsigned char *autn, -+ unsigned char *res, size_t *res_len, -+ unsigned char *ik, unsigned char *ck, unsigned char *auts); -+ -+#else /* PCSC_FUNCS */ -+ -+#define scard_init(s) NULL -+#define scard_deinit(s) do { } while (0) -+#define scard_set_pin(s, p) -1 -+#define scard_get_imsi(s, i, l) -1 -+#define scard_gsm_auth(s, r, s2, k) -1 -+#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1 -+ -+#endif /* PCSC_FUNCS */ -+ -+#endif /* PCSC_FUNCS_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.c -new file mode 100644 -index 0000000000000..804473fa4bfb9 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.c -@@ -0,0 +1,287 @@ -+/* -+ * Radiotap parser -+ * -+ * Copyright 2007 Andy Green -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * -+ * Modified for userspace by Johannes Berg -+ * I only modified some things on top to ease syncing should bugs be found. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "radiotap_iter.h" -+ -+#define le16_to_cpu le_to_host16 -+#define le32_to_cpu le_to_host32 -+#define __le32 uint32_t -+#define ulong unsigned long -+#define unlikely(cond) (cond) -+#define get_unaligned(p) \ -+({ \ -+ struct packed_dummy_struct { \ -+ typeof(*(p)) __val; \ -+ } __attribute__((packed)) *__ptr = (void *) (p); \ -+ \ -+ __ptr->__val; \ -+}) -+ -+/* function prototypes and related defs are in radiotap_iter.h */ -+ -+/** -+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization -+ * @iterator: radiotap_iterator to initialize -+ * @radiotap_header: radiotap header to parse -+ * @max_length: total length we can parse into (eg, whole packet length) -+ * -+ * Returns: 0 or a negative error code if there is a problem. -+ * -+ * This function initializes an opaque iterator struct which can then -+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap -+ * argument which is present in the header. It knows about extended -+ * present headers and handles them. -+ * -+ * How to use: -+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator -+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) -+ * checking for a good 0 return code. Then loop calling -+ * __ieee80211_radiotap_iterator_next()... it returns either 0, -+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. -+ * The iterator's @this_arg member points to the start of the argument -+ * associated with the current argument index that is present, which can be -+ * found in the iterator's @this_arg_index member. This arg index corresponds -+ * to the IEEE80211_RADIOTAP_... defines. -+ * -+ * Radiotap header length: -+ * You can find the CPU-endian total radiotap header length in -+ * iterator->max_length after executing ieee80211_radiotap_iterator_init() -+ * successfully. -+ * -+ * Alignment Gotcha: -+ * You must take care when dereferencing iterator.this_arg -+ * for multibyte types... the pointer is not aligned. Use -+ * get_unaligned((type *)iterator.this_arg) to dereference -+ * iterator.this_arg for type "type" safely on all arches. -+ * -+ * Example code: -+ * See Documentation/networking/radiotap-headers.txt -+ */ -+ -+int ieee80211_radiotap_iterator_init( -+ struct ieee80211_radiotap_iterator *iterator, -+ struct ieee80211_radiotap_header *radiotap_header, -+ int max_length) -+{ -+ /* Linux only supports version 0 radiotap format */ -+ if (radiotap_header->it_version) -+ return -EINVAL; -+ -+ /* sanity check for allowed length and radiotap length field */ -+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len))) -+ return -EINVAL; -+ -+ iterator->rtheader = radiotap_header; -+ iterator->max_length = le16_to_cpu(get_unaligned( -+ &radiotap_header->it_len)); -+ iterator->arg_index = 0; -+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned( -+ &radiotap_header->it_present)); -+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); -+ iterator->this_arg = NULL; -+ -+ /* find payload start allowing for extended bitmap(s) */ -+ -+ if (unlikely(iterator->bitmap_shifter & (1<arg)) & -+ (1<arg += sizeof(u32); -+ -+ /* -+ * check for insanity where the present bitmaps -+ * keep claiming to extend up to or even beyond the -+ * stated radiotap header length -+ */ -+ -+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) -+ > (ulong)iterator->max_length) -+ return -EINVAL; -+ } -+ -+ iterator->arg += sizeof(u32); -+ -+ /* -+ * no need to check again for blowing past stated radiotap -+ * header length, because ieee80211_radiotap_iterator_next -+ * checks it before it is dereferenced -+ */ -+ } -+ -+ /* we are all initialized happily */ -+ -+ return 0; -+} -+ -+ -+/** -+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg -+ * @iterator: radiotap_iterator to move to next arg (if any) -+ * -+ * Returns: 0 if there is an argument to handle, -+ * -ENOENT if there are no more args or -EINVAL -+ * if there is something else wrong. -+ * -+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) -+ * in @this_arg_index and sets @this_arg to point to the -+ * payload for the field. It takes care of alignment handling and extended -+ * present fields. @this_arg can be changed by the caller (eg, -+ * incremented to move inside a compound argument like -+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in -+ * little-endian format whatever the endianess of your CPU. -+ * -+ * Alignment Gotcha: -+ * You must take care when dereferencing iterator.this_arg -+ * for multibyte types... the pointer is not aligned. Use -+ * get_unaligned((type *)iterator.this_arg) to dereference -+ * iterator.this_arg for type "type" safely on all arches. -+ */ -+ -+int ieee80211_radiotap_iterator_next( -+ struct ieee80211_radiotap_iterator *iterator) -+{ -+ -+ /* -+ * small length lookup table for all radiotap types we heard of -+ * starting from b0 in the bitmap, so we can walk the payload -+ * area of the radiotap header -+ * -+ * There is a requirement to pad args, so that args -+ * of a given length must begin at a boundary of that length -+ * -- but note that compound args are allowed (eg, 2 x u16 -+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not -+ * a reliable indicator of alignment requirement. -+ * -+ * upper nybble: content alignment for arg -+ * lower nybble: content length for arg -+ */ -+ -+ static const u8 rt_sizes[] = { -+ [IEEE80211_RADIOTAP_TSFT] = 0x88, -+ [IEEE80211_RADIOTAP_FLAGS] = 0x11, -+ [IEEE80211_RADIOTAP_RATE] = 0x11, -+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24, -+ [IEEE80211_RADIOTAP_FHSS] = 0x22, -+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, -+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, -+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, -+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, -+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, -+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, -+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11, -+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, -+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, -+ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, -+ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, -+ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, -+ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, -+ /* -+ * add more here as they are defined in -+ * include/net/ieee80211_radiotap.h -+ */ -+ }; -+ -+ /* -+ * for every radiotap entry we can at -+ * least skip (by knowing the length)... -+ */ -+ -+ while (iterator->arg_index < (int) sizeof(rt_sizes)) { -+ int hit = 0; -+ int pad; -+ -+ if (!(iterator->bitmap_shifter & 1)) -+ goto next_entry; /* arg not present */ -+ -+ /* -+ * arg is present, account for alignment padding -+ * 8-bit args can be at any alignment -+ * 16-bit args must start on 16-bit boundary -+ * 32-bit args must start on 32-bit boundary -+ * 64-bit args must start on 64-bit boundary -+ * -+ * note that total arg size can differ from alignment of -+ * elements inside arg, so we use upper nybble of length -+ * table to base alignment on -+ * -+ * also note: these alignments are ** relative to the -+ * start of the radiotap header **. There is no guarantee -+ * that the radiotap header itself is aligned on any -+ * kind of boundary. -+ * -+ * the above is why get_unaligned() is used to dereference -+ * multibyte elements from the radiotap area -+ */ -+ -+ pad = (((ulong)iterator->arg) - -+ ((ulong)iterator->rtheader)) & -+ ((rt_sizes[iterator->arg_index] >> 4) - 1); -+ -+ if (pad) -+ iterator->arg += -+ (rt_sizes[iterator->arg_index] >> 4) - pad; -+ -+ /* -+ * this is what we will return to user, but we need to -+ * move on first so next call has something fresh to test -+ */ -+ iterator->this_arg_index = iterator->arg_index; -+ iterator->this_arg = iterator->arg; -+ hit = 1; -+ -+ /* internally move on the size of this arg */ -+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; -+ -+ /* -+ * check for insanity where we are given a bitmap that -+ * claims to have more arg content than the length of the -+ * radiotap section. We will normally end up equalling this -+ * max_length on the last arg, never exceeding it. -+ */ -+ -+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) > -+ (ulong) iterator->max_length) -+ return -EINVAL; -+ -+ next_entry: -+ iterator->arg_index++; -+ if (unlikely((iterator->arg_index & 31) == 0)) { -+ /* completed current u32 bitmap */ -+ if (iterator->bitmap_shifter & 1) { -+ /* b31 was set, there is more */ -+ /* move to next u32 bitmap */ -+ iterator->bitmap_shifter = le32_to_cpu( -+ get_unaligned(iterator->next_bitmap)); -+ iterator->next_bitmap++; -+ } else -+ /* no more bitmaps: end */ -+ iterator->arg_index = sizeof(rt_sizes); -+ } else /* just try the next bit */ -+ iterator->bitmap_shifter >>= 1; -+ -+ /* if we found a valid arg earlier, return it now */ -+ if (hit) -+ return 0; -+ } -+ -+ /* we don't know how to handle any more args, we're done */ -+ return -ENOENT; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.h -new file mode 100644 -index 0000000000000..508264c4cf333 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap.h -@@ -0,0 +1,242 @@ -+/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ -+/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 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. -+ * 3. The name of David Young may not be used to endorse or promote -+ * products derived from this software without specific prior -+ * written permission. -+ * -+ * 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. -+ */ -+ -+/* -+ * Modifications to fit into the linux IEEE 802.11 stack, -+ * Mike Kershaw (dragorn@kismetwireless.net) -+ */ -+ -+#ifndef IEEE80211RADIOTAP_H -+#define IEEE80211RADIOTAP_H -+ -+#include -+ -+/* Base version of the radiotap packet header data */ -+#define PKTHDR_RADIOTAP_VERSION 0 -+ -+/* 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. -+ */ -+ -+/* The radio capture header precedes the 802.11 header. -+ * All data in the header is little endian on all platforms. -+ */ -+struct ieee80211_radiotap_header { -+ uint8_t it_version; /* Version 0. Only increases -+ * for drastic changes, -+ * introduction of compatible -+ * new fields does not count. -+ */ -+ uint8_t it_pad; -+ uint16_t it_len; /* length of the whole -+ * header in bytes, including -+ * it_version, it_pad, -+ * it_len, and data fields. -+ */ -+ uint32_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. -+ */ -+}; -+ -+/* Name Data type Units -+ * ---- --------- ----- -+ * -+ * IEEE80211_RADIOTAP_TSFT __le64 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 uint16_t MHz, bitmap -+ * -+ * Tx/Rx frequency in MHz, followed by flags (see below). -+ * -+ * IEEE80211_RADIOTAP_FHSS uint16_t see below -+ * -+ * For frequency-hopping radios, the hop set (first byte) -+ * and pattern (second byte). -+ * -+ * IEEE80211_RADIOTAP_RATE u8 500kb/s -+ * -+ * Tx/Rx data rate -+ * -+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from -+ * one milliwatt (dBm) -+ * -+ * RF signal power at the antenna, decibel difference from -+ * one milliwatt. -+ * -+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from -+ * one milliwatt (dBm) -+ * -+ * RF noise power at the antenna, decibel difference from one -+ * milliwatt. -+ * -+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) -+ * -+ * RF signal power at the antenna, decibel difference from an -+ * arbitrary, fixed reference. -+ * -+ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) -+ * -+ * RF noise power at the antenna, decibel difference from an -+ * arbitrary, fixed reference point. -+ * -+ * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_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 uint16_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 uint16_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 s8 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 u8 bitmap -+ * -+ * Properties of transmitted and received frames. See flags -+ * defined below. -+ * -+ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index -+ * -+ * Unitless indication of the Rx/Tx antenna for this packet. -+ * The first antenna is antenna 0. -+ * -+ * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap -+ * -+ * Properties of received frames. See flags defined below. -+ * -+ * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap -+ * -+ * Properties of transmitted frames. See flags defined below. -+ * -+ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data -+ * -+ * Number of rts retries a transmitted frame used. -+ * -+ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data -+ * -+ * Number of unicast retries a transmitted frame used. -+ * -+ */ -+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_RX_FLAGS = 14, -+ IEEE80211_RADIOTAP_TX_FLAGS = 15, -+ IEEE80211_RADIOTAP_RTS_RETRIES = 16, -+ IEEE80211_RADIOTAP_DATA_RETRIES = 17, -+ IEEE80211_RADIOTAP_EXT = 31 -+}; -+ -+/* Channel flags. */ -+#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo 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) */ -+ -+/* 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 */ -+#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between -+ * 802.11 header and payload -+ * (to 32-bit boundary) -+ */ -+/* For IEEE80211_RADIOTAP_RX_FLAGS */ -+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ -+ -+/* For IEEE80211_RADIOTAP_TX_FLAGS */ -+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive -+ * retries */ -+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ -+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ -+ -+#endif /* IEEE80211_RADIOTAP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap_iter.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap_iter.h -new file mode 100644 -index 0000000000000..92a798a67023a ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/radiotap_iter.h -@@ -0,0 +1,41 @@ -+#ifndef __RADIOTAP_ITER_H -+#define __RADIOTAP_ITER_H -+ -+#include "radiotap.h" -+ -+/* Radiotap header iteration -+ * implemented in radiotap.c -+ */ -+/** -+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args -+ * @rtheader: pointer to the radiotap header we are walking through -+ * @max_length: length of radiotap header in cpu byte ordering -+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg -+ * @this_arg: pointer to current radiotap arg -+ * @arg_index: internal next argument index -+ * @arg: internal next argument pointer -+ * @next_bitmap: internal pointer to next present u32 -+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present -+ */ -+ -+struct ieee80211_radiotap_iterator { -+ struct ieee80211_radiotap_header *rtheader; -+ int max_length; -+ int this_arg_index; -+ unsigned char *this_arg; -+ -+ int arg_index; -+ unsigned char *arg; -+ uint32_t *next_bitmap; -+ uint32_t bitmap_shifter; -+}; -+ -+extern int ieee80211_radiotap_iterator_init( -+ struct ieee80211_radiotap_iterator *iterator, -+ struct ieee80211_radiotap_header *radiotap_header, -+ int max_length); -+ -+extern int ieee80211_radiotap_iterator_next( -+ struct ieee80211_radiotap_iterator *iterator); -+ -+#endif /* __RADIOTAP_ITER_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/state_machine.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/state_machine.h -new file mode 100644 -index 0000000000000..31f667217f1ac ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/state_machine.h -@@ -0,0 +1,144 @@ -+/* -+ * wpa_supplicant/hostapd - State machine definitions -+ * Copyright (c) 2002-2005, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * This file includes a set of pre-processor macros that can be used to -+ * implement a state machine. In addition to including this header file, each -+ * file implementing a state machine must define STATE_MACHINE_DATA to be the -+ * data structure including state variables (enum machine_state, -+ * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used -+ * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define -+ * a group of state machines with shared data structure, STATE_MACHINE_ADDR -+ * needs to be defined to point to the MAC address used in debug output. -+ * SM_ENTRY_M macro can be used to define similar group of state machines -+ * without this additional debug info. -+ */ -+ -+#ifndef STATE_MACHINE_H -+#define STATE_MACHINE_H -+ -+/** -+ * SM_STATE - Declaration of a state machine function -+ * @machine: State machine name -+ * @state: State machine state -+ * -+ * This macro is used to declare a state machine function. It is used in place -+ * of a C function definition to declare functions to be run when the state is -+ * entered by calling SM_ENTER or SM_ENTER_GLOBAL. -+ */ -+#define SM_STATE(machine, state) \ -+static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \ -+ int global) -+ -+/** -+ * SM_ENTRY - State machine function entry point -+ * @machine: State machine name -+ * @state: State machine state -+ * -+ * This macro is used inside each state machine function declared with -+ * SM_STATE. SM_ENTRY should be in the beginning of the function body, but -+ * after declaration of possible local variables. This macro prints debug -+ * information about state transition and update the state machine state. -+ */ -+#define SM_ENTRY(machine, state) \ -+if (!global || sm->machine ## _state != machine ## _ ## state) { \ -+ sm->changed = TRUE; \ -+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \ -+ " entering state " #state); \ -+} \ -+sm->machine ## _state = machine ## _ ## state; -+ -+/** -+ * SM_ENTRY_M - State machine function entry point for state machine group -+ * @machine: State machine name -+ * @_state: State machine state -+ * @data: State variable prefix (full variable: prefix_state) -+ * -+ * This macro is like SM_ENTRY, but for state machine groups that use a shared -+ * data structure for more than one state machine. Both machine and prefix -+ * parameters are set to "sub-state machine" name. prefix is used to allow more -+ * than one state variable to be stored in the same data structure. -+ */ -+#define SM_ENTRY_M(machine, _state, data) \ -+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ -+ sm->changed = TRUE; \ -+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \ -+ #machine " entering state " #_state); \ -+} \ -+sm->data ## _ ## state = machine ## _ ## _state; -+ -+/** -+ * SM_ENTRY_MA - State machine function entry point for state machine group -+ * @machine: State machine name -+ * @_state: State machine state -+ * @data: State variable prefix (full variable: prefix_state) -+ * -+ * This macro is like SM_ENTRY_M, but a MAC address is included in debug -+ * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to -+ * be included in debug. -+ */ -+#define SM_ENTRY_MA(machine, _state, data) \ -+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \ -+ sm->changed = TRUE; \ -+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \ -+ #machine " entering state " #_state, \ -+ MAC2STR(STATE_MACHINE_ADDR)); \ -+} \ -+sm->data ## _ ## state = machine ## _ ## _state; -+ -+/** -+ * SM_ENTER - Enter a new state machine state -+ * @machine: State machine name -+ * @state: State machine state -+ * -+ * This macro expands to a function call to a state machine function defined -+ * with SM_STATE macro. SM_ENTER is used in a state machine step function to -+ * move the state machine to a new state. -+ */ -+#define SM_ENTER(machine, state) \ -+sm_ ## machine ## _ ## state ## _Enter(sm, 0) -+ -+/** -+ * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule -+ * @machine: State machine name -+ * @state: State machine state -+ * -+ * This macro is like SM_ENTER, but this is used when entering a new state -+ * based on a global (not specific to any particular state) rule. A separate -+ * macro is used to avoid unwanted debug message floods when the same global -+ * rule is forcing a state machine to remain in on state. -+ */ -+#define SM_ENTER_GLOBAL(machine, state) \ -+sm_ ## machine ## _ ## state ## _Enter(sm, 1) -+ -+/** -+ * SM_STEP - Declaration of a state machine step function -+ * @machine: State machine name -+ * -+ * This macro is used to declare a state machine step function. It is used in -+ * place of a C function definition to declare a function that is used to move -+ * state machine to a new state based on state variables. This function uses -+ * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state. -+ */ -+#define SM_STEP(machine) \ -+static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) -+ -+/** -+ * SM_STEP_RUN - Call the state machine step function -+ * @machine: State machine name -+ * -+ * This macro expands to a function call to a state machine step function -+ * defined with SM_STEP macro. -+ */ -+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm) -+ -+#endif /* STATE_MACHINE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.c -new file mode 100644 -index 0000000000000..bb3eb24d4c01c ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.c -@@ -0,0 +1,329 @@ -+/* -+ * Backtrace debugging -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "trace.h" -+ -+#ifdef WPA_TRACE -+ -+static struct dl_list active_references = -+{ &active_references, &active_references }; -+ -+#ifdef WPA_TRACE_BFD -+#include -+#ifdef __linux__ -+#include -+#else /* __linux__ */ -+#include -+#endif /* __linux__ */ -+ -+static char *prg_fname = NULL; -+static bfd *cached_abfd = NULL; -+static asymbol **syms = NULL; -+ -+static void get_prg_fname(void) -+{ -+ char exe[50], fname[512]; -+ int len; -+ os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid()); -+ len = readlink(exe, fname, sizeof(fname) - 1); -+ if (len < 0 || len >= (int) sizeof(fname)) { -+ perror("readlink"); -+ return; -+ } -+ fname[len] = '\0'; -+ prg_fname = strdup(fname); -+} -+ -+ -+static bfd * open_bfd(const char *fname) -+{ -+ bfd *abfd; -+ char **matching; -+ -+ abfd = bfd_openr(prg_fname, NULL); -+ if (abfd == NULL) { -+ wpa_printf(MSG_INFO, "bfd_openr failed"); -+ return NULL; -+ } -+ -+ if (bfd_check_format(abfd, bfd_archive)) { -+ wpa_printf(MSG_INFO, "bfd_check_format failed"); -+ bfd_close(abfd); -+ return NULL; -+ } -+ -+ if (!bfd_check_format_matches(abfd, bfd_object, &matching)) { -+ wpa_printf(MSG_INFO, "bfd_check_format_matches failed"); -+ free(matching); -+ bfd_close(abfd); -+ return NULL; -+ } -+ -+ return abfd; -+} -+ -+ -+static void read_syms(bfd *abfd) -+{ -+ long storage, symcount; -+ bfd_boolean dynamic = FALSE; -+ -+ if (syms) -+ return; -+ -+ if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) { -+ wpa_printf(MSG_INFO, "No symbols"); -+ return; -+ } -+ -+ storage = bfd_get_symtab_upper_bound(abfd); -+ if (storage == 0) { -+ storage = bfd_get_dynamic_symtab_upper_bound(abfd); -+ dynamic = TRUE; -+ } -+ if (storage < 0) { -+ wpa_printf(MSG_INFO, "Unknown symtab upper bound"); -+ return; -+ } -+ -+ syms = malloc(storage); -+ if (syms == NULL) { -+ wpa_printf(MSG_INFO, "Failed to allocate memory for symtab " -+ "(%ld bytes)", storage); -+ return; -+ } -+ if (dynamic) -+ symcount = bfd_canonicalize_dynamic_symtab(abfd, syms); -+ else -+ symcount = bfd_canonicalize_symtab(abfd, syms); -+ if (symcount < 0) { -+ wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab", -+ dynamic ? "dynamic " : ""); -+ free(syms); -+ syms = NULL; -+ return; -+ } -+} -+ -+ -+struct bfd_data { -+ bfd_vma pc; -+ bfd_boolean found; -+ const char *filename; -+ const char *function; -+ unsigned int line; -+}; -+ -+ -+static void find_addr_sect(bfd *abfd, asection *section, void *obj) -+{ -+ struct bfd_data *data = obj; -+ bfd_vma vma; -+ bfd_size_type size; -+ -+ if (data->found) -+ return; -+ -+ if (!(bfd_get_section_vma(abfd, section))) -+ return; -+ -+ vma = bfd_get_section_vma(abfd, section); -+ if (data->pc < vma) -+ return; -+ -+ size = bfd_get_section_size(section); -+ if (data->pc >= vma + size) -+ return; -+ -+ data->found = bfd_find_nearest_line(abfd, section, syms, -+ data->pc - vma, -+ &data->filename, -+ &data->function, -+ &data->line); -+} -+ -+ -+static void wpa_trace_bfd_addr(void *pc) -+{ -+ bfd *abfd = cached_abfd; -+ struct bfd_data data; -+ const char *name; -+ char *aname = NULL; -+ const char *filename; -+ -+ if (abfd == NULL) -+ return; -+ -+ data.pc = (bfd_vma) pc; -+ data.found = FALSE; -+ bfd_map_over_sections(abfd, find_addr_sect, &data); -+ -+ if (!data.found) -+ return; -+ -+ do { -+ if (data.function) -+ aname = bfd_demangle(abfd, data.function, -+ DMGL_ANSI | DMGL_PARAMS); -+ name = aname ? aname : data.function; -+ filename = data.filename; -+ if (filename) { -+ char *end = os_strrchr(filename, '/'); -+ int i = 0; -+ while (*filename && *filename == prg_fname[i] && -+ filename <= end) { -+ filename++; -+ i++; -+ } -+ } -+ wpa_printf(MSG_INFO, " %s() %s:%u", -+ name, filename, data.line); -+ free(aname); -+ -+ data.found = bfd_find_inliner_info(abfd, &data.filename, -+ &data.function, &data.line); -+ } while (data.found); -+} -+ -+ -+static const char * wpa_trace_bfd_addr2func(void *pc) -+{ -+ bfd *abfd = cached_abfd; -+ struct bfd_data data; -+ -+ if (abfd == NULL) -+ return NULL; -+ -+ data.pc = (bfd_vma) pc; -+ data.found = FALSE; -+ bfd_map_over_sections(abfd, find_addr_sect, &data); -+ -+ if (!data.found) -+ return NULL; -+ -+ return data.function; -+} -+ -+ -+static void wpa_trace_bfd_init(void) -+{ -+ if (!prg_fname) { -+ get_prg_fname(); -+ if (!prg_fname) -+ return; -+ } -+ -+ if (!cached_abfd) { -+ cached_abfd = open_bfd(prg_fname); -+ if (!cached_abfd) { -+ wpa_printf(MSG_INFO, "Failed to open bfd"); -+ return; -+ } -+ } -+ -+ read_syms(cached_abfd); -+ if (!syms) { -+ wpa_printf(MSG_INFO, "Failed to read symbols"); -+ return; -+ } -+} -+ -+ -+void wpa_trace_dump_funcname(const char *title, void *pc) -+{ -+ wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc); -+ wpa_trace_bfd_init(); -+ wpa_trace_bfd_addr(pc); -+} -+ -+#else /* WPA_TRACE_BFD */ -+ -+#define wpa_trace_bfd_init() do { } while (0) -+#define wpa_trace_bfd_addr(pc) do { } while (0) -+#define wpa_trace_bfd_addr2func(pc) NULL -+ -+#endif /* WPA_TRACE_BFD */ -+ -+void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num) -+{ -+ char **sym; -+ int i; -+ enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state; -+ -+ wpa_trace_bfd_init(); -+ wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title); -+ sym = backtrace_symbols(btrace, btrace_num); -+ state = TRACE_HEAD; -+ for (i = 0; i < btrace_num; i++) { -+ const char *func = wpa_trace_bfd_addr2func(btrace[i]); -+ if (state == TRACE_HEAD && func && -+ (os_strcmp(func, "wpa_trace_add_ref_func") == 0 || -+ os_strcmp(func, "wpa_trace_check_ref") == 0 || -+ os_strcmp(func, "wpa_trace_show") == 0)) -+ continue; -+ if (state == TRACE_TAIL && sym && sym[i] && -+ os_strstr(sym[i], "__libc_start_main")) -+ break; -+ if (state == TRACE_HEAD) -+ state = TRACE_RELEVANT; -+ if (sym) -+ wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]); -+ else -+ wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]); -+ wpa_trace_bfd_addr(btrace[i]); -+ if (state == TRACE_RELEVANT && func && -+ os_strcmp(func, "main") == 0) -+ state = TRACE_TAIL; -+ } -+ free(sym); -+ wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title); -+} -+ -+ -+void wpa_trace_show(const char *title) -+{ -+ struct info { -+ WPA_TRACE_INFO -+ } info; -+ wpa_trace_record(&info); -+ wpa_trace_dump(title, &info); -+} -+ -+ -+void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr) -+{ -+ if (addr == NULL) -+ return; -+ ref->addr = addr; -+ wpa_trace_record(ref); -+ dl_list_add(&active_references, &ref->list); -+} -+ -+ -+void wpa_trace_check_ref(const void *addr) -+{ -+ struct wpa_trace_ref *ref; -+ dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) { -+ if (addr != ref->addr) -+ continue; -+ wpa_trace_show("Freeing referenced memory"); -+ wpa_trace_dump("Reference registration", ref); -+ abort(); -+ } -+} -+ -+#endif /* WPA_TRACE */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.h -new file mode 100644 -index 0000000000000..22d3de035acb1 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/trace.h -@@ -0,0 +1,74 @@ -+/* -+ * Backtrace debugging -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef TRACE_H -+#define TRACE_H -+ -+#define WPA_TRACE_LEN 16 -+ -+#ifdef WPA_TRACE -+#include -+ -+#include "list.h" -+ -+#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num; -+ -+struct wpa_trace_ref { -+ struct dl_list list; -+ const void *addr; -+ WPA_TRACE_INFO -+}; -+#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name -+ -+#define wpa_trace_dump(title, ptr) \ -+ wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num) -+void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num); -+#define wpa_trace_record(ptr) \ -+ (ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN) -+void wpa_trace_show(const char *title); -+#define wpa_trace_add_ref(ptr, name, addr) \ -+ wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr)) -+void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr); -+#define wpa_trace_remove_ref(ptr, name, addr) \ -+ do { \ -+ if ((addr)) \ -+ dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \ -+ } while (0) -+void wpa_trace_check_ref(const void *addr); -+ -+#else /* WPA_TRACE */ -+ -+#define WPA_TRACE_INFO -+#define WPA_TRACE_REF(n) -+#define wpa_trace_dump(title, ptr) do { } while (0) -+#define wpa_trace_record(ptr) do { } while (0) -+#define wpa_trace_show(title) do { } while (0) -+#define wpa_trace_add_ref(ptr, name, addr) do { } while (0) -+#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0) -+#define wpa_trace_check_ref(addr) do { } while (0) -+ -+#endif /* WPA_TRACE */ -+ -+ -+#ifdef WPA_TRACE_BFD -+ -+void wpa_trace_dump_funcname(const char *title, void *pc); -+ -+#else /* WPA_TRACE_BFD */ -+ -+#define wpa_trace_dump_funcname(title, pc) do { } while (0) -+ -+#endif /* WPA_TRACE_BFD */ -+ -+#endif /* TRACE_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.c -new file mode 100644 -index 0000000000000..d8cc26754b39d ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.c -@@ -0,0 +1,77 @@ -+/* -+ * Universally Unique IDentifier (UUID) -+ * Copyright (c) 2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "uuid.h" -+ -+int uuid_str2bin(const char *str, u8 *bin) -+{ -+ const char *pos; -+ u8 *opos; -+ -+ pos = str; -+ opos = bin; -+ -+ if (hexstr2bin(pos, opos, 4)) -+ return -1; -+ pos += 8; -+ opos += 4; -+ -+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) -+ return -1; -+ pos += 4; -+ opos += 2; -+ -+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) -+ return -1; -+ pos += 4; -+ opos += 2; -+ -+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2)) -+ return -1; -+ pos += 4; -+ opos += 2; -+ -+ if (*pos++ != '-' || hexstr2bin(pos, opos, 6)) -+ return -1; -+ -+ return 0; -+} -+ -+ -+int uuid_bin2str(const u8 *bin, char *str, size_t max_len) -+{ -+ int len; -+ len = os_snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" -+ "%02x%02x-%02x%02x%02x%02x%02x%02x", -+ bin[0], bin[1], bin[2], bin[3], -+ bin[4], bin[5], bin[6], bin[7], -+ bin[8], bin[9], bin[10], bin[11], -+ bin[12], bin[13], bin[14], bin[15]); -+ if (len < 0 || (size_t) len >= max_len) -+ return -1; -+ return 0; -+} -+ -+ -+int is_nil_uuid(const u8 *uuid) -+{ -+ int i; -+ for (i = 0; i < UUID_LEN; i++) -+ if (uuid[i]) -+ return 0; -+ return 1; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.h -new file mode 100644 -index 0000000000000..0759165253578 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/uuid.h -@@ -0,0 +1,24 @@ -+/* -+ * Universally Unique IDentifier (UUID) -+ * Copyright (c) 2008, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef UUID_H -+#define UUID_H -+ -+#define UUID_LEN 16 -+ -+int uuid_str2bin(const char *str, u8 *bin); -+int uuid_bin2str(const u8 *bin, char *str, size_t max_len); -+int is_nil_uuid(const u8 *uuid); -+ -+#endif /* UUID_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.c -new file mode 100644 -index 0000000000000..b8c5e2fe495fc ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.c -@@ -0,0 +1,484 @@ -+/* -+ * wpa_supplicant/hostapd / Debug prints -+ * Copyright (c) 2002-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+ -+#ifdef CONFIG_DEBUG_SYSLOG -+#include -+ -+static int wpa_debug_syslog = 0; -+#endif /* CONFIG_DEBUG_SYSLOG */ -+ -+ -+int wpa_debug_level = MSG_INFO; -+int wpa_debug_show_keys = 0; -+int wpa_debug_timestamp = 0; -+ -+ -+#ifdef CONFIG_ANDROID_LOG -+ -+#include -+ -+void android_printf(int level, char *format, ...) -+{ -+ if (level >= wpa_debug_level) { -+ va_list ap; -+ if (level == MSG_ERROR) -+ level = ANDROID_LOG_ERROR; -+ else if (level == MSG_WARNING) -+ level = ANDROID_LOG_WARN; -+ else if (level == MSG_INFO) -+ level = ANDROID_LOG_INFO; -+ else -+ level = ANDROID_LOG_DEBUG; -+ va_start(ap, format); -+ __android_log_vprint(level, "wpa_supplicant", format, ap); -+ va_end(ap); -+ } -+} -+ -+#else /* CONFIG_ANDROID_LOG */ -+ -+#ifndef CONFIG_NO_STDOUT_DEBUG -+ -+#ifdef CONFIG_DEBUG_FILE -+static FILE *out_file = NULL; -+#endif /* CONFIG_DEBUG_FILE */ -+ -+ -+void wpa_debug_print_timestamp(void) -+{ -+ struct os_time tv; -+ -+ if (!wpa_debug_timestamp) -+ return; -+ -+ os_get_time(&tv); -+#ifdef CONFIG_DEBUG_FILE -+ if (out_file) { -+ fprintf(out_file, "%ld.%06u: ", (long) tv.sec, -+ (unsigned int) tv.usec); -+ } else -+#endif /* CONFIG_DEBUG_FILE */ -+ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); -+} -+ -+ -+#ifdef CONFIG_DEBUG_SYSLOG -+#ifndef LOG_HOSTAPD -+#define LOG_HOSTAPD LOG_DAEMON -+#endif /* LOG_HOSTAPD */ -+ -+void wpa_debug_open_syslog(void) -+{ -+ openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD); -+ wpa_debug_syslog++; -+} -+ -+ -+void wpa_debug_close_syslog(void) -+{ -+ if (wpa_debug_syslog) -+ closelog(); -+} -+ -+ -+static int syslog_priority(int level) -+{ -+ switch (level) { -+ case MSG_MSGDUMP: -+ case MSG_DEBUG: -+ return LOG_DEBUG; -+ case MSG_INFO: -+ return LOG_NOTICE; -+ case MSG_WARNING: -+ return LOG_WARNING; -+ case MSG_ERROR: -+ return LOG_ERR; -+ } -+ return LOG_INFO; -+} -+#endif /* CONFIG_DEBUG_SYSLOG */ -+ -+ -+/** -+ * wpa_printf - conditional printf -+ * @level: priority level (MSG_*) of the message -+ * @fmt: printf format string, followed by optional arguments -+ * -+ * This function is used to print conditional debugging and error messages. The -+ * output may be directed to stdout, stderr, and/or syslog based on -+ * configuration. -+ * -+ * Note: New line '\n' is added to the end of the text when printing to stdout. -+ */ -+void wpa_printf(int level, const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ if (level >= wpa_debug_level) { -+#ifdef CONFIG_DEBUG_SYSLOG -+ if (wpa_debug_syslog) { -+ vsyslog(syslog_priority(level), fmt, ap); -+ } else { -+#endif /* CONFIG_DEBUG_SYSLOG */ -+ wpa_debug_print_timestamp(); -+#ifdef CONFIG_DEBUG_FILE -+ if (out_file) { -+ vfprintf(out_file, fmt, ap); -+ fprintf(out_file, "\n"); -+ } else { -+#endif /* CONFIG_DEBUG_FILE */ -+ vprintf(fmt, ap); -+ printf("\n"); -+#ifdef CONFIG_DEBUG_FILE -+ } -+#endif /* CONFIG_DEBUG_FILE */ -+#ifdef CONFIG_DEBUG_SYSLOG -+ } -+#endif /* CONFIG_DEBUG_SYSLOG */ -+ } -+ va_end(ap); -+} -+ -+ -+static void _wpa_hexdump(int level, const char *title, const u8 *buf, -+ size_t len, int show) -+{ -+ size_t i; -+ if (level < wpa_debug_level) -+ return; -+ wpa_debug_print_timestamp(); -+#ifdef CONFIG_DEBUG_FILE -+ if (out_file) { -+ fprintf(out_file, "%s - hexdump(len=%lu):", -+ title, (unsigned long) len); -+ if (buf == NULL) { -+ fprintf(out_file, " [NULL]"); -+ } else if (show) { -+ for (i = 0; i < len; i++) -+ fprintf(out_file, " %02x", buf[i]); -+ } else { -+ fprintf(out_file, " [REMOVED]"); -+ } -+ fprintf(out_file, "\n"); -+ } else { -+#endif /* CONFIG_DEBUG_FILE */ -+ printf("%s - hexdump(len=%lu):", title, (unsigned long) len); -+ if (buf == NULL) { -+ printf(" [NULL]"); -+ } else if (show) { -+ for (i = 0; i < len; i++) -+ printf(" %02x", buf[i]); -+ } else { -+ printf(" [REMOVED]"); -+ } -+ printf("\n"); -+#ifdef CONFIG_DEBUG_FILE -+ } -+#endif /* CONFIG_DEBUG_FILE */ -+} -+ -+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len) -+{ -+ _wpa_hexdump(level, title, buf, len, 1); -+} -+ -+ -+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len) -+{ -+ _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); -+} -+ -+ -+static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf, -+ size_t len, int show) -+{ -+ size_t i, llen; -+ const u8 *pos = buf; -+ const size_t line_len = 16; -+ -+ if (level < wpa_debug_level) -+ return; -+ wpa_debug_print_timestamp(); -+#ifdef CONFIG_DEBUG_FILE -+ if (out_file) { -+ if (!show) { -+ fprintf(out_file, -+ "%s - hexdump_ascii(len=%lu): [REMOVED]\n", -+ title, (unsigned long) len); -+ return; -+ } -+ if (buf == NULL) { -+ fprintf(out_file, -+ "%s - hexdump_ascii(len=%lu): [NULL]\n", -+ title, (unsigned long) len); -+ return; -+ } -+ fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", -+ title, (unsigned long) len); -+ while (len) { -+ llen = len > line_len ? line_len : len; -+ fprintf(out_file, " "); -+ for (i = 0; i < llen; i++) -+ fprintf(out_file, " %02x", pos[i]); -+ for (i = llen; i < line_len; i++) -+ fprintf(out_file, " "); -+ fprintf(out_file, " "); -+ for (i = 0; i < llen; i++) { -+ if (isprint(pos[i])) -+ fprintf(out_file, "%c", pos[i]); -+ else -+ fprintf(out_file, "_"); -+ } -+ for (i = llen; i < line_len; i++) -+ fprintf(out_file, " "); -+ fprintf(out_file, "\n"); -+ pos += llen; -+ len -= llen; -+ } -+ } else { -+#endif /* CONFIG_DEBUG_FILE */ -+ if (!show) { -+ printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", -+ title, (unsigned long) len); -+ return; -+ } -+ if (buf == NULL) { -+ printf("%s - hexdump_ascii(len=%lu): [NULL]\n", -+ title, (unsigned long) len); -+ return; -+ } -+ printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); -+ while (len) { -+ llen = len > line_len ? line_len : len; -+ printf(" "); -+ for (i = 0; i < llen; i++) -+ printf(" %02x", pos[i]); -+ for (i = llen; i < line_len; i++) -+ printf(" "); -+ printf(" "); -+ for (i = 0; i < llen; i++) { -+ if (isprint(pos[i])) -+ printf("%c", pos[i]); -+ else -+ printf("_"); -+ } -+ for (i = llen; i < line_len; i++) -+ printf(" "); -+ printf("\n"); -+ pos += llen; -+ len -= llen; -+ } -+#ifdef CONFIG_DEBUG_FILE -+ } -+#endif /* CONFIG_DEBUG_FILE */ -+} -+ -+ -+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len) -+{ -+ _wpa_hexdump_ascii(level, title, buf, len, 1); -+} -+ -+ -+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, -+ size_t len) -+{ -+ _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys); -+} -+ -+ -+#ifdef CONFIG_DEBUG_FILE -+static char *last_path = NULL; -+#endif /* CONFIG_DEBUG_FILE */ -+ -+int wpa_debug_reopen_file(void) -+{ -+#ifdef CONFIG_DEBUG_FILE -+ int rv; -+ if (last_path) { -+ char *tmp = os_strdup(last_path); -+ wpa_debug_close_file(); -+ rv = wpa_debug_open_file(tmp); -+ os_free(tmp); -+ } else { -+ wpa_printf(MSG_ERROR, "Last-path was not set, cannot " -+ "re-open log file."); -+ rv = -1; -+ } -+ return rv; -+#else /* CONFIG_DEBUG_FILE */ -+ return 0; -+#endif /* CONFIG_DEBUG_FILE */ -+} -+ -+ -+int wpa_debug_open_file(const char *path) -+{ -+#ifdef CONFIG_DEBUG_FILE -+ if (!path) -+ return 0; -+ -+ if (last_path == NULL || os_strcmp(last_path, path) != 0) { -+ /* Save our path to enable re-open */ -+ os_free(last_path); -+ last_path = os_strdup(path); -+ } -+ -+ out_file = fopen(path, "a"); -+ if (out_file == NULL) { -+ wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " -+ "output file, using standard output"); -+ return -1; -+ } -+#ifndef _WIN32 -+ setvbuf(out_file, NULL, _IOLBF, 0); -+#endif /* _WIN32 */ -+#endif /* CONFIG_DEBUG_FILE */ -+ return 0; -+} -+ -+ -+void wpa_debug_close_file(void) -+{ -+#ifdef CONFIG_DEBUG_FILE -+ if (!out_file) -+ return; -+ fclose(out_file); -+ out_file = NULL; -+ os_free(last_path); -+ last_path = NULL; -+#endif /* CONFIG_DEBUG_FILE */ -+} -+ -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+#endif /* CONFIG_ANDROID_LOG */ -+ -+#ifndef CONFIG_NO_WPA_MSG -+static wpa_msg_cb_func wpa_msg_cb = NULL; -+ -+void wpa_msg_register_cb(wpa_msg_cb_func func) -+{ -+ wpa_msg_cb = func; -+} -+ -+ -+static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL; -+ -+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func) -+{ -+ wpa_msg_ifname_cb = func; -+} -+ -+ -+void wpa_msg(void *ctx, int level, const char *fmt, ...) -+{ -+ va_list ap; -+ char *buf; -+ const int buflen = 2048; -+ int len; -+ char prefix[130]; -+ -+ buf = os_malloc(buflen); -+ if (buf == NULL) { -+ wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message " -+ "buffer"); -+ return; -+ } -+ va_start(ap, fmt); -+ prefix[0] = '\0'; -+ if (wpa_msg_ifname_cb) { -+ const char *ifname = wpa_msg_ifname_cb(ctx); -+ if (ifname) { -+ int res = os_snprintf(prefix, sizeof(prefix), "%s: ", -+ ifname); -+ if (res < 0 || res >= (int) sizeof(prefix)) -+ prefix[0] = '\0'; -+ } -+ } -+ len = vsnprintf(buf, buflen, fmt, ap); -+ va_end(ap); -+ wpa_printf(level, "%s%s", prefix, buf); -+ if (wpa_msg_cb) -+ wpa_msg_cb(ctx, level, buf, len); -+ os_free(buf); -+} -+ -+ -+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) -+{ -+ va_list ap; -+ char *buf; -+ const int buflen = 2048; -+ int len; -+ -+ if (!wpa_msg_cb) -+ return; -+ -+ buf = os_malloc(buflen); -+ if (buf == NULL) { -+ wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate " -+ "message buffer"); -+ return; -+ } -+ va_start(ap, fmt); -+ len = vsnprintf(buf, buflen, fmt, ap); -+ va_end(ap); -+ wpa_msg_cb(ctx, level, buf, len); -+ os_free(buf); -+} -+#endif /* CONFIG_NO_WPA_MSG */ -+ -+ -+#ifndef CONFIG_NO_HOSTAPD_LOGGER -+static hostapd_logger_cb_func hostapd_logger_cb = NULL; -+ -+void hostapd_logger_register_cb(hostapd_logger_cb_func func) -+{ -+ hostapd_logger_cb = func; -+} -+ -+ -+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, -+ const char *fmt, ...) -+{ -+ va_list ap; -+ char *buf; -+ const int buflen = 2048; -+ int len; -+ -+ buf = os_malloc(buflen); -+ if (buf == NULL) { -+ wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate " -+ "message buffer"); -+ return; -+ } -+ va_start(ap, fmt); -+ len = vsnprintf(buf, buflen, fmt, ap); -+ va_end(ap); -+ if (hostapd_logger_cb) -+ hostapd_logger_cb(ctx, addr, module, level, buf, len); -+ else if (addr) -+ wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s", -+ MAC2STR(addr), buf); -+ else -+ wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf); -+ os_free(buf); -+} -+#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.h -new file mode 100644 -index 0000000000000..ae36afec50d06 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpa_debug.h -@@ -0,0 +1,307 @@ -+/* -+ * wpa_supplicant/hostapd / Debug prints -+ * Copyright (c) 2002-2007, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPA_DEBUG_H -+#define WPA_DEBUG_H -+ -+#include "wpabuf.h" -+ -+/* Debugging function - conditional printf and hex dump. Driver wrappers can -+ * use these for debugging purposes. */ -+ -+enum { -+ MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR -+}; -+ -+#ifdef CONFIG_ANDROID_LOG -+ -+#define wpa_debug_print_timestamp() do {} while (0) -+#define wpa_hexdump(...) do {} while (0) -+#define wpa_hexdump_key(...) do {} while (0) -+#define wpa_hexdump_buf(l,t,b) do {} while (0) -+#define wpa_hexdump_buf_key(l,t,b) do {} while (0) -+#define wpa_hexdump_ascii(...) do {} while (0) -+#define wpa_hexdump_ascii_key(...) do {} while (0) -+#define wpa_debug_open_file(...) do {} while (0) -+#define wpa_debug_close_file() do {} while (0) -+#define wpa_dbg(...) do {} while (0) -+ -+static inline int wpa_debug_reopen_file(void) -+{ -+ return 0; -+} -+ -+ -+void android_printf(int level, char *format, ...) -+PRINTF_FORMAT(2, 3); -+ -+#define wpa_printf android_printf -+ -+#else /* CONFIG_ANDROID_LOG */ -+ -+#ifdef CONFIG_NO_STDOUT_DEBUG -+ -+#define wpa_debug_print_timestamp() do { } while (0) -+#define wpa_printf(args...) do { } while (0) -+#define wpa_hexdump(l,t,b,le) do { } while (0) -+#define wpa_hexdump_buf(l,t,b) do { } while (0) -+#define wpa_hexdump_key(l,t,b,le) do { } while (0) -+#define wpa_hexdump_buf_key(l,t,b) do { } while (0) -+#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) -+#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) -+#define wpa_debug_open_file(p) do { } while (0) -+#define wpa_debug_close_file() do { } while (0) -+#define wpa_dbg(args...) do { } while (0) -+ -+static inline int wpa_debug_reopen_file(void) -+{ -+ return 0; -+} -+ -+#else /* CONFIG_NO_STDOUT_DEBUG */ -+ -+int wpa_debug_open_file(const char *path); -+int wpa_debug_reopen_file(void); -+void wpa_debug_close_file(void); -+ -+/** -+ * wpa_debug_printf_timestamp - Print timestamp for debug output -+ * -+ * This function prints a timestamp in seconds_from_1970.microsoconds -+ * format if debug output has been configured to include timestamps in debug -+ * messages. -+ */ -+void wpa_debug_print_timestamp(void); -+ -+/** -+ * wpa_printf - conditional printf -+ * @level: priority level (MSG_*) of the message -+ * @fmt: printf format string, followed by optional arguments -+ * -+ * This function is used to print conditional debugging and error messages. The -+ * output may be directed to stdout, stderr, and/or syslog based on -+ * configuration. -+ * -+ * Note: New line '\n' is added to the end of the text when printing to stdout. -+ */ -+void wpa_printf(int level, const char *fmt, ...) -+PRINTF_FORMAT(2, 3); -+ -+/** -+ * wpa_hexdump - conditional hex dump -+ * @level: priority level (MSG_*) of the message -+ * @title: title of for the message -+ * @buf: data buffer to be dumped -+ * @len: length of the buf -+ * -+ * This function is used to print conditional debugging and error messages. The -+ * output may be directed to stdout, stderr, and/or syslog based on -+ * configuration. The contents of buf is printed out has hex dump. -+ */ -+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); -+ -+static inline void wpa_hexdump_buf(int level, const char *title, -+ const struct wpabuf *buf) -+{ -+ wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL, -+ buf ? wpabuf_len(buf) : 0); -+} -+ -+/** -+ * wpa_hexdump_key - conditional hex dump, hide keys -+ * @level: priority level (MSG_*) of the message -+ * @title: title of for the message -+ * @buf: data buffer to be dumped -+ * @len: length of the buf -+ * -+ * This function is used to print conditional debugging and error messages. The -+ * output may be directed to stdout, stderr, and/or syslog based on -+ * configuration. The contents of buf is printed out has hex dump. This works -+ * like wpa_hexdump(), but by default, does not include secret keys (passwords, -+ * etc.) in debug output. -+ */ -+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); -+ -+static inline void wpa_hexdump_buf_key(int level, const char *title, -+ const struct wpabuf *buf) -+{ -+ wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : 0, -+ buf ? wpabuf_len(buf) : 0); -+} -+ -+/** -+ * wpa_hexdump_ascii - conditional hex dump -+ * @level: priority level (MSG_*) of the message -+ * @title: title of for the message -+ * @buf: data buffer to be dumped -+ * @len: length of the buf -+ * -+ * This function is used to print conditional debugging and error messages. The -+ * output may be directed to stdout, stderr, and/or syslog based on -+ * configuration. The contents of buf is printed out has hex dump with both -+ * the hex numbers and ASCII characters (for printable range) are shown. 16 -+ * bytes per line will be shown. -+ */ -+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, -+ size_t len); -+ -+/** -+ * wpa_hexdump_ascii_key - conditional hex dump, hide keys -+ * @level: priority level (MSG_*) of the message -+ * @title: title of for the message -+ * @buf: data buffer to be dumped -+ * @len: length of the buf -+ * -+ * This function is used to print conditional debugging and error messages. The -+ * output may be directed to stdout, stderr, and/or syslog based on -+ * configuration. The contents of buf is printed out has hex dump with both -+ * the hex numbers and ASCII characters (for printable range) are shown. 16 -+ * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by -+ * default, does not include secret keys (passwords, etc.) in debug output. -+ */ -+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, -+ size_t len); -+ -+/* -+ * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce -+ * binary size. As such, it should be used with debugging messages that are not -+ * needed in the control interface while wpa_msg() has to be used for anything -+ * that needs to shown to control interface monitors. -+ */ -+#define wpa_dbg(args...) wpa_msg(args) -+ -+#endif /* CONFIG_NO_STDOUT_DEBUG */ -+ -+#endif /* CONFIG_ANDROID_LOG */ -+ -+ -+#ifdef CONFIG_NO_WPA_MSG -+#define wpa_msg(args...) do { } while (0) -+#define wpa_msg_ctrl(args...) do { } while (0) -+#define wpa_msg_register_cb(f) do { } while (0) -+#define wpa_msg_register_ifname_cb(f) do { } while (0) -+#else /* CONFIG_NO_WPA_MSG */ -+/** -+ * wpa_msg - Conditional printf for default target and ctrl_iface monitors -+ * @ctx: Pointer to context data; this is the ctx variable registered -+ * with struct wpa_driver_ops::init() -+ * @level: priority level (MSG_*) of the message -+ * @fmt: printf format string, followed by optional arguments -+ * -+ * This function is used to print conditional debugging and error messages. The -+ * output may be directed to stdout, stderr, and/or syslog based on -+ * configuration. This function is like wpa_printf(), but it also sends the -+ * same message to all attached ctrl_iface monitors. -+ * -+ * Note: New line '\n' is added to the end of the text when printing to stdout. -+ */ -+void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); -+ -+/** -+ * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors -+ * @ctx: Pointer to context data; this is the ctx variable registered -+ * with struct wpa_driver_ops::init() -+ * @level: priority level (MSG_*) of the message -+ * @fmt: printf format string, followed by optional arguments -+ * -+ * This function is used to print conditional debugging and error messages. -+ * This function is like wpa_msg(), but it sends the output only to the -+ * attached ctrl_iface monitors. In other words, it can be used for frequent -+ * events that do not need to be sent to syslog. -+ */ -+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) -+PRINTF_FORMAT(3, 4); -+ -+typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, -+ size_t len); -+ -+/** -+ * wpa_msg_register_cb - Register callback function for wpa_msg() messages -+ * @func: Callback function (%NULL to unregister) -+ */ -+void wpa_msg_register_cb(wpa_msg_cb_func func); -+ -+typedef const char * (*wpa_msg_get_ifname_func)(void *ctx); -+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func); -+ -+#endif /* CONFIG_NO_WPA_MSG */ -+ -+#ifdef CONFIG_NO_HOSTAPD_LOGGER -+#define hostapd_logger(args...) do { } while (0) -+#define hostapd_logger_register_cb(f) do { } while (0) -+#else /* CONFIG_NO_HOSTAPD_LOGGER */ -+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, -+ const char *fmt, ...) PRINTF_FORMAT(5, 6); -+ -+typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, -+ unsigned int module, int level, -+ const char *txt, size_t len); -+ -+/** -+ * hostapd_logger_register_cb - Register callback function for hostapd_logger() -+ * @func: Callback function (%NULL to unregister) -+ */ -+void hostapd_logger_register_cb(hostapd_logger_cb_func func); -+#endif /* CONFIG_NO_HOSTAPD_LOGGER */ -+ -+#define HOSTAPD_MODULE_IEEE80211 0x00000001 -+#define HOSTAPD_MODULE_IEEE8021X 0x00000002 -+#define HOSTAPD_MODULE_RADIUS 0x00000004 -+#define HOSTAPD_MODULE_WPA 0x00000008 -+#define HOSTAPD_MODULE_DRIVER 0x00000010 -+#define HOSTAPD_MODULE_IAPP 0x00000020 -+#define HOSTAPD_MODULE_MLME 0x00000040 -+ -+enum hostapd_logger_level { -+ HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, -+ HOSTAPD_LEVEL_DEBUG = 1, -+ HOSTAPD_LEVEL_INFO = 2, -+ HOSTAPD_LEVEL_NOTICE = 3, -+ HOSTAPD_LEVEL_WARNING = 4 -+}; -+ -+ -+#ifdef CONFIG_DEBUG_SYSLOG -+ -+void wpa_debug_open_syslog(void); -+void wpa_debug_close_syslog(void); -+ -+#else /* CONFIG_DEBUG_SYSLOG */ -+ -+static inline void wpa_debug_open_syslog(void) -+{ -+} -+ -+static inline void wpa_debug_close_syslog(void) -+{ -+} -+ -+#endif /* CONFIG_DEBUG_SYSLOG */ -+ -+ -+#ifdef EAPOL_TEST -+#define WPA_ASSERT(a) \ -+ do { \ -+ if (!(a)) { \ -+ printf("WPA_ASSERT FAILED '" #a "' " \ -+ "%s %s:%d\n", \ -+ __FUNCTION__, __FILE__, __LINE__); \ -+ exit(1); \ -+ } \ -+ } while (0) -+#else -+#define WPA_ASSERT(a) do { } while (0) -+#endif -+ -+#endif /* WPA_DEBUG_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.c -new file mode 100644 -index 0000000000000..eda779eaff4fd ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.c -@@ -0,0 +1,304 @@ -+/* -+ * Dynamic data buffer -+ * Copyright (c) 2007-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "trace.h" -+#include "wpabuf.h" -+ -+#ifdef WPA_TRACE -+#define WPABUF_MAGIC 0x51a974e3 -+ -+struct wpabuf_trace { -+ unsigned int magic; -+}; -+ -+static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf) -+{ -+ return (struct wpabuf_trace *) -+ ((const u8 *) buf - sizeof(struct wpabuf_trace)); -+} -+#endif /* WPA_TRACE */ -+ -+ -+static void wpabuf_overflow(const struct wpabuf *buf, size_t len) -+{ -+#ifdef WPA_TRACE -+ struct wpabuf_trace *trace = wpabuf_get_trace(buf); -+ if (trace->magic != WPABUF_MAGIC) { -+ wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", -+ trace->magic); -+ } -+#endif /* WPA_TRACE */ -+ wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu", -+ buf, (unsigned long) buf->size, (unsigned long) buf->used, -+ (unsigned long) len); -+ wpa_trace_show("wpabuf overflow"); -+ abort(); -+} -+ -+ -+int wpabuf_resize(struct wpabuf **_buf, size_t add_len) -+{ -+ struct wpabuf *buf = *_buf; -+#ifdef WPA_TRACE -+ struct wpabuf_trace *trace; -+#endif /* WPA_TRACE */ -+ -+ if (buf == NULL) { -+ *_buf = wpabuf_alloc(add_len); -+ return *_buf == NULL ? -1 : 0; -+ } -+ -+#ifdef WPA_TRACE -+ trace = wpabuf_get_trace(buf); -+ if (trace->magic != WPABUF_MAGIC) { -+ wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x", -+ trace->magic); -+ wpa_trace_show("wpabuf_resize invalid magic"); -+ abort(); -+ } -+#endif /* WPA_TRACE */ -+ -+ if (buf->used + add_len > buf->size) { -+ unsigned char *nbuf; -+ if (buf->ext_data) { -+ nbuf = os_realloc(buf->ext_data, buf->used + add_len); -+ if (nbuf == NULL) -+ return -1; -+ os_memset(nbuf + buf->used, 0, add_len); -+ buf->ext_data = nbuf; -+ } else { -+#ifdef WPA_TRACE -+ nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) + -+ sizeof(struct wpabuf) + -+ buf->used + add_len); -+ if (nbuf == NULL) -+ return -1; -+ trace = (struct wpabuf_trace *) nbuf; -+ buf = (struct wpabuf *) (trace + 1); -+ os_memset(nbuf + sizeof(struct wpabuf_trace) + -+ sizeof(struct wpabuf) + buf->used, 0, -+ add_len); -+#else /* WPA_TRACE */ -+ nbuf = os_realloc(buf, sizeof(struct wpabuf) + -+ buf->used + add_len); -+ if (nbuf == NULL) -+ return -1; -+ buf = (struct wpabuf *) nbuf; -+ os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0, -+ add_len); -+#endif /* WPA_TRACE */ -+ *_buf = buf; -+ } -+ buf->size = buf->used + add_len; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * wpabuf_alloc - Allocate a wpabuf of the given size -+ * @len: Length for the allocated buffer -+ * Returns: Buffer to the allocated wpabuf or %NULL on failure -+ */ -+struct wpabuf * wpabuf_alloc(size_t len) -+{ -+#ifdef WPA_TRACE -+ struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + -+ sizeof(struct wpabuf) + len); -+ struct wpabuf *buf; -+ if (trace == NULL) -+ return NULL; -+ trace->magic = WPABUF_MAGIC; -+ buf = (struct wpabuf *) (trace + 1); -+#else /* WPA_TRACE */ -+ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len); -+ if (buf == NULL) -+ return NULL; -+#endif /* WPA_TRACE */ -+ -+ buf->size = len; -+ return buf; -+} -+ -+ -+struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len) -+{ -+#ifdef WPA_TRACE -+ struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) + -+ sizeof(struct wpabuf)); -+ struct wpabuf *buf; -+ if (trace == NULL) -+ return NULL; -+ trace->magic = WPABUF_MAGIC; -+ buf = (struct wpabuf *) (trace + 1); -+#else /* WPA_TRACE */ -+ struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf)); -+ if (buf == NULL) -+ return NULL; -+#endif /* WPA_TRACE */ -+ -+ buf->size = len; -+ buf->used = len; -+ buf->ext_data = data; -+ -+ return buf; -+} -+ -+ -+struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len) -+{ -+ struct wpabuf *buf = wpabuf_alloc(len); -+ if (buf) -+ wpabuf_put_data(buf, data, len); -+ return buf; -+} -+ -+ -+struct wpabuf * wpabuf_dup(const struct wpabuf *src) -+{ -+ struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src)); -+ if (buf) -+ wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src)); -+ return buf; -+} -+ -+ -+/** -+ * wpabuf_free - Free a wpabuf -+ * @buf: wpabuf buffer -+ */ -+void wpabuf_free(struct wpabuf *buf) -+{ -+#ifdef WPA_TRACE -+ struct wpabuf_trace *trace; -+ if (buf == NULL) -+ return; -+ trace = wpabuf_get_trace(buf); -+ if (trace->magic != WPABUF_MAGIC) { -+ wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x", -+ trace->magic); -+ wpa_trace_show("wpabuf_free magic mismatch"); -+ abort(); -+ } -+ os_free(buf->ext_data); -+ os_free(trace); -+#else /* WPA_TRACE */ -+ if (buf == NULL) -+ return; -+ os_free(buf->ext_data); -+ os_free(buf); -+#endif /* WPA_TRACE */ -+} -+ -+ -+void * wpabuf_put(struct wpabuf *buf, size_t len) -+{ -+ void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); -+ buf->used += len; -+ if (buf->used > buf->size) { -+ wpabuf_overflow(buf, len); -+ } -+ return tmp; -+} -+ -+ -+/** -+ * wpabuf_concat - Concatenate two buffers into a newly allocated one -+ * @a: First buffer -+ * @b: Second buffer -+ * Returns: wpabuf with concatenated a + b data or %NULL on failure -+ * -+ * Both buffers a and b will be freed regardless of the return value. Input -+ * buffers can be %NULL which is interpreted as an empty buffer. -+ */ -+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) -+{ -+ struct wpabuf *n = NULL; -+ size_t len = 0; -+ -+ if (b == NULL) -+ return a; -+ -+ if (a) -+ len += wpabuf_len(a); -+ if (b) -+ len += wpabuf_len(b); -+ -+ n = wpabuf_alloc(len); -+ if (n) { -+ if (a) -+ wpabuf_put_buf(n, a); -+ if (b) -+ wpabuf_put_buf(n, b); -+ } -+ -+ wpabuf_free(a); -+ wpabuf_free(b); -+ -+ return n; -+} -+ -+ -+/** -+ * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length -+ * @buf: Buffer to be padded -+ * @len: Length for the padded buffer -+ * Returns: wpabuf padded to len octets or %NULL on failure -+ * -+ * If buf is longer than len octets or of same size, it will be returned as-is. -+ * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed -+ * by the source data. The source buffer will be freed on error, i.e., caller -+ * will only be responsible on freeing the returned buffer. If buf is %NULL, -+ * %NULL will be returned. -+ */ -+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) -+{ -+ struct wpabuf *ret; -+ size_t blen; -+ -+ if (buf == NULL) -+ return NULL; -+ -+ blen = wpabuf_len(buf); -+ if (blen >= len) -+ return buf; -+ -+ ret = wpabuf_alloc(len); -+ if (ret) { -+ os_memset(wpabuf_put(ret, len - blen), 0, len - blen); -+ wpabuf_put_buf(ret, buf); -+ } -+ wpabuf_free(buf); -+ -+ return ret; -+} -+ -+ -+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) -+{ -+ va_list ap; -+ void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf); -+ int res; -+ -+ va_start(ap, fmt); -+ res = vsnprintf(tmp, buf->size - buf->used, fmt, ap); -+ va_end(ap); -+ if (res < 0 || (size_t) res >= buf->size - buf->used) -+ wpabuf_overflow(buf, res); -+ buf->used += res; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.h -new file mode 100644 -index 0000000000000..cccfcc80ef1a9 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/utils/wpabuf.h -@@ -0,0 +1,168 @@ -+/* -+ * Dynamic data buffer -+ * Copyright (c) 2007-2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef WPABUF_H -+#define WPABUF_H -+ -+/* -+ * Internal data structure for wpabuf. Please do not touch this directly from -+ * elsewhere. This is only defined in header file to allow inline functions -+ * from this file to access data. -+ */ -+struct wpabuf { -+ size_t size; /* total size of the allocated buffer */ -+ size_t used; /* length of data in the buffer */ -+ u8 *ext_data; /* pointer to external data; NULL if data follows -+ * struct wpabuf */ -+ /* optionally followed by the allocated buffer */ -+}; -+ -+ -+int wpabuf_resize(struct wpabuf **buf, size_t add_len); -+struct wpabuf * wpabuf_alloc(size_t len); -+struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); -+struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); -+struct wpabuf * wpabuf_dup(const struct wpabuf *src); -+void wpabuf_free(struct wpabuf *buf); -+void * wpabuf_put(struct wpabuf *buf, size_t len); -+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); -+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); -+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); -+ -+ -+/** -+ * wpabuf_size - Get the currently allocated size of a wpabuf buffer -+ * @buf: wpabuf buffer -+ * Returns: Currently allocated size of the buffer -+ */ -+static inline size_t wpabuf_size(const struct wpabuf *buf) -+{ -+ return buf->size; -+} -+ -+/** -+ * wpabuf_len - Get the current length of a wpabuf buffer data -+ * @buf: wpabuf buffer -+ * Returns: Currently used length of the buffer -+ */ -+static inline size_t wpabuf_len(const struct wpabuf *buf) -+{ -+ return buf->used; -+} -+ -+/** -+ * wpabuf_tailroom - Get size of available tail room in the end of the buffer -+ * @buf: wpabuf buffer -+ * Returns: Tail room (in bytes) of available space in the end of the buffer -+ */ -+static inline size_t wpabuf_tailroom(const struct wpabuf *buf) -+{ -+ return buf->size - buf->used; -+} -+ -+/** -+ * wpabuf_head - Get pointer to the head of the buffer data -+ * @buf: wpabuf buffer -+ * Returns: Pointer to the head of the buffer data -+ */ -+static inline const void * wpabuf_head(const struct wpabuf *buf) -+{ -+ if (buf->ext_data) -+ return buf->ext_data; -+ return buf + 1; -+} -+ -+static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) -+{ -+ return wpabuf_head(buf); -+} -+ -+/** -+ * wpabuf_mhead - Get modifiable pointer to the head of the buffer data -+ * @buf: wpabuf buffer -+ * Returns: Pointer to the head of the buffer data -+ */ -+static inline void * wpabuf_mhead(struct wpabuf *buf) -+{ -+ if (buf->ext_data) -+ return buf->ext_data; -+ return buf + 1; -+} -+ -+static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) -+{ -+ return wpabuf_mhead(buf); -+} -+ -+static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) -+{ -+ u8 *pos = wpabuf_put(buf, 1); -+ *pos = data; -+} -+ -+static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) -+{ -+ u8 *pos = wpabuf_put(buf, 2); -+ WPA_PUT_LE16(pos, data); -+} -+ -+static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) -+{ -+ u8 *pos = wpabuf_put(buf, 4); -+ WPA_PUT_LE32(pos, data); -+} -+ -+static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) -+{ -+ u8 *pos = wpabuf_put(buf, 2); -+ WPA_PUT_BE16(pos, data); -+} -+ -+static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) -+{ -+ u8 *pos = wpabuf_put(buf, 3); -+ WPA_PUT_BE24(pos, data); -+} -+ -+static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) -+{ -+ u8 *pos = wpabuf_put(buf, 4); -+ WPA_PUT_BE32(pos, data); -+} -+ -+static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, -+ size_t len) -+{ -+ if (data) -+ os_memcpy(wpabuf_put(buf, len), data, len); -+} -+ -+static inline void wpabuf_put_buf(struct wpabuf *dst, -+ const struct wpabuf *src) -+{ -+ wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); -+} -+ -+static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) -+{ -+ buf->ext_data = (u8 *) data; -+ buf->size = buf->used = len; -+} -+ -+static inline void wpabuf_put_str(struct wpabuf *dst, const char *str) -+{ -+ wpabuf_put_data(dst, str, os_strlen(str)); -+} -+ -+#endif /* WPABUF_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/Makefile b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/Makefile -new file mode 100644 -index 0000000000000..9c41962fd7e16 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/Makefile -@@ -0,0 +1,8 @@ -+all: -+ @echo Nothing to be made. -+ -+clean: -+ rm -f *~ *.o *.d -+ -+install: -+ @echo Nothing to be made. -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http.h -new file mode 100644 -index 0000000000000..2fee3a8f87a63 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http.h -@@ -0,0 +1,29 @@ -+/* -+ * HTTP for WPS -+ * Copyright (c) 2000-2003 Intel Corporation -+ * Copyright (c) 2006-2007 Sony Corporation -+ * Copyright (c) 2008-2009 Atheros Communications -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * See wps_upnp.c for more details on licensing and code history. -+ */ -+ -+#ifndef HTTP_H -+#define HTTP_H -+ -+enum http_reply_code { -+ HTTP_OK = 200, -+ HTTP_BAD_REQUEST = 400, -+ UPNP_INVALID_ACTION = 401, -+ UPNP_INVALID_ARGS = 402, -+ HTTP_NOT_FOUND = 404, -+ HTTP_PRECONDITION_FAILED = 412, -+ HTTP_INTERNAL_SERVER_ERROR = 500, -+ HTTP_UNIMPLEMENTED = 501, -+ UPNP_ACTION_FAILED = 501, -+ UPNP_ARG_VALUE_INVALID = 600, -+ UPNP_ARG_VALUE_OUT_OF_RANGE = 601, -+ UPNP_OUT_OF_MEMORY = 603 -+}; -+ -+#endif /* HTTP_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.c -new file mode 100644 -index 0000000000000..9b53b80681490 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.c -@@ -0,0 +1,374 @@ -+/* -+ * http_client - HTTP client -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "httpread.h" -+#include "http_client.h" -+ -+ -+#define HTTP_CLIENT_TIMEOUT_SEC 30 -+ -+ -+struct http_client { -+ struct sockaddr_in dst; -+ int sd; -+ struct wpabuf *req; -+ size_t req_pos; -+ size_t max_response; -+ -+ void (*cb)(void *ctx, struct http_client *c, -+ enum http_client_event event); -+ void *cb_ctx; -+ struct httpread *hread; -+ struct wpabuf body; -+}; -+ -+ -+static void http_client_timeout(void *eloop_data, void *user_ctx) -+{ -+ struct http_client *c = eloop_data; -+ wpa_printf(MSG_DEBUG, "HTTP: Timeout (c=%p)", c); -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); -+} -+ -+ -+static void http_client_got_response(struct httpread *handle, void *cookie, -+ enum httpread_event e) -+{ -+ struct http_client *c = cookie; -+ -+ wpa_printf(MSG_DEBUG, "HTTP: httpread callback: handle=%p cookie=%p " -+ "e=%d", handle, cookie, e); -+ -+ eloop_cancel_timeout(http_client_timeout, c, NULL); -+ switch (e) { -+ case HTTPREAD_EVENT_FILE_READY: -+ if (httpread_hdr_type_get(c->hread) == HTTPREAD_HDR_TYPE_REPLY) -+ { -+ int reply_code = httpread_reply_code_get(c->hread); -+ if (reply_code == 200 /* OK */) { -+ wpa_printf(MSG_DEBUG, "HTTP: Response OK from " -+ "%s:%d", -+ inet_ntoa(c->dst.sin_addr), -+ ntohs(c->dst.sin_port)); -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_OK); -+ } else { -+ wpa_printf(MSG_DEBUG, "HTTP: Error %d from " -+ "%s:%d", reply_code, -+ inet_ntoa(c->dst.sin_addr), -+ ntohs(c->dst.sin_port)); -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); -+ } -+ } else -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_INVALID_REPLY); -+ break; -+ case HTTPREAD_EVENT_TIMEOUT: -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_TIMEOUT); -+ break; -+ case HTTPREAD_EVENT_ERROR: -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); -+ break; -+ } -+} -+ -+ -+static void http_client_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) -+{ -+ struct http_client *c = eloop_ctx; -+ int res; -+ -+ wpa_printf(MSG_DEBUG, "HTTP: Send client request to %s:%d (%lu of %lu " -+ "bytes remaining)", -+ inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port), -+ (unsigned long) wpabuf_len(c->req), -+ (unsigned long) wpabuf_len(c->req) - c->req_pos); -+ -+ res = send(c->sd, wpabuf_head(c->req) + c->req_pos, -+ wpabuf_len(c->req) - c->req_pos, 0); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "HTTP: Failed to send buffer: %s", -+ strerror(errno)); -+ eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); -+ return; -+ } -+ -+ if ((size_t) res < wpabuf_len(c->req) - c->req_pos) { -+ wpa_printf(MSG_DEBUG, "HTTP: Sent %d of %lu bytes; %lu bytes " -+ "remaining", -+ res, (unsigned long) wpabuf_len(c->req), -+ (unsigned long) wpabuf_len(c->req) - c->req_pos - -+ res); -+ c->req_pos += res; -+ return; -+ } -+ -+ wpa_printf(MSG_DEBUG, "HTTP: Full client request sent to %s:%d", -+ inet_ntoa(c->dst.sin_addr), ntohs(c->dst.sin_port)); -+ eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); -+ wpabuf_free(c->req); -+ c->req = NULL; -+ -+ c->hread = httpread_create(c->sd, http_client_got_response, c, -+ c->max_response, HTTP_CLIENT_TIMEOUT_SEC); -+ if (c->hread == NULL) { -+ c->cb(c->cb_ctx, c, HTTP_CLIENT_FAILED); -+ return; -+ } -+} -+ -+ -+struct http_client * http_client_addr(struct sockaddr_in *dst, -+ struct wpabuf *req, size_t max_response, -+ void (*cb)(void *ctx, -+ struct http_client *c, -+ enum http_client_event event), -+ void *cb_ctx) -+{ -+ struct http_client *c; -+ -+ c = os_zalloc(sizeof(*c)); -+ if (c == NULL) -+ return NULL; -+ c->sd = -1; -+ c->dst = *dst; -+ c->max_response = max_response; -+ c->cb = cb; -+ c->cb_ctx = cb_ctx; -+ -+ c->sd = socket(AF_INET, SOCK_STREAM, 0); -+ if (c->sd < 0) { -+ http_client_free(c); -+ return NULL; -+ } -+ -+ if (fcntl(c->sd, F_SETFL, O_NONBLOCK) != 0) { -+ wpa_printf(MSG_DEBUG, "HTTP: fnctl(O_NONBLOCK) failed: %s", -+ strerror(errno)); -+ http_client_free(c); -+ return NULL; -+ } -+ -+ if (connect(c->sd, (struct sockaddr *) dst, sizeof(*dst))) { -+ if (errno != EINPROGRESS) { -+ wpa_printf(MSG_DEBUG, "HTTP: Failed to connect: %s", -+ strerror(errno)); -+ http_client_free(c); -+ return NULL; -+ } -+ -+ /* -+ * Continue connecting in the background; eloop will call us -+ * once the connection is ready (or failed). -+ */ -+ } -+ -+ if (eloop_register_sock(c->sd, EVENT_TYPE_WRITE, http_client_tx_ready, -+ c, NULL)) { -+ http_client_free(c); -+ return NULL; -+ } -+ -+ if (eloop_register_timeout(HTTP_CLIENT_TIMEOUT_SEC, 0, -+ http_client_timeout, c, NULL)) { -+ http_client_free(c); -+ return NULL; -+ } -+ -+ c->req = req; -+ -+ return c; -+} -+ -+ -+char * http_client_url_parse(const char *url, struct sockaddr_in *dst, -+ char **ret_path) -+{ -+ char *u, *addr, *port, *path; -+ -+ u = os_strdup(url); -+ if (u == NULL) -+ return NULL; -+ -+ os_memset(dst, 0, sizeof(*dst)); -+ dst->sin_family = AF_INET; -+ addr = u + 7; -+ path = os_strchr(addr, '/'); -+ port = os_strchr(addr, ':'); -+ if (path == NULL) { -+ path = "/"; -+ } else { -+ *path = '\0'; /* temporary nul termination for address */ -+ if (port > path) -+ port = NULL; -+ } -+ if (port) -+ *port++ = '\0'; -+ -+ if (inet_aton(addr, &dst->sin_addr) == 0) { -+ /* TODO: name lookup */ -+ wpa_printf(MSG_DEBUG, "HTTP: Unsupported address in URL '%s' " -+ "(addr='%s' port='%s')", -+ url, addr, port); -+ os_free(u); -+ return NULL; -+ } -+ -+ if (port) -+ dst->sin_port = htons(atoi(port)); -+ else -+ dst->sin_port = htons(80); -+ -+ if (*path == '\0') { -+ /* remove temporary nul termination for address */ -+ *path = '/'; -+ } -+ -+ *ret_path = path; -+ -+ return u; -+} -+ -+ -+struct http_client * http_client_url(const char *url, -+ struct wpabuf *req, size_t max_response, -+ void (*cb)(void *ctx, -+ struct http_client *c, -+ enum http_client_event event), -+ void *cb_ctx) -+{ -+ struct sockaddr_in dst; -+ struct http_client *c; -+ char *u, *path; -+ struct wpabuf *req_buf = NULL; -+ -+ if (os_strncmp(url, "http://", 7) != 0) -+ return NULL; -+ u = http_client_url_parse(url, &dst, &path); -+ if (u == NULL) -+ return NULL; -+ -+ if (req == NULL) { -+ req_buf = wpabuf_alloc(os_strlen(url) + 1000); -+ if (req_buf == NULL) { -+ os_free(u); -+ return NULL; -+ } -+ req = req_buf; -+ wpabuf_printf(req, -+ "GET %s HTTP/1.1\r\n" -+ "Cache-Control: no-cache\r\n" -+ "Pragma: no-cache\r\n" -+ "Accept: text/xml, application/xml\r\n" -+ "User-Agent: wpa_supplicant\r\n" -+ "Host: %s:%d\r\n" -+ "\r\n", -+ path, inet_ntoa(dst.sin_addr), -+ ntohs(dst.sin_port)); -+ } -+ os_free(u); -+ -+ c = http_client_addr(&dst, req, max_response, cb, cb_ctx); -+ if (c == NULL) { -+ wpabuf_free(req_buf); -+ return NULL; -+ } -+ -+ return c; -+} -+ -+ -+void http_client_free(struct http_client *c) -+{ -+ if (c == NULL) -+ return; -+ httpread_destroy(c->hread); -+ wpabuf_free(c->req); -+ if (c->sd >= 0) { -+ eloop_unregister_sock(c->sd, EVENT_TYPE_WRITE); -+ close(c->sd); -+ } -+ eloop_cancel_timeout(http_client_timeout, c, NULL); -+ os_free(c); -+} -+ -+ -+struct wpabuf * http_client_get_body(struct http_client *c) -+{ -+ if (c->hread == NULL) -+ return NULL; -+ wpabuf_set(&c->body, httpread_data_get(c->hread), -+ httpread_length_get(c->hread)); -+ return &c->body; -+} -+ -+ -+char * http_client_get_hdr_line(struct http_client *c, const char *tag) -+{ -+ if (c->hread == NULL) -+ return NULL; -+ return httpread_hdr_line_get(c->hread, tag); -+} -+ -+ -+char * http_link_update(char *url, const char *base) -+{ -+ char *n; -+ size_t len; -+ const char *pos; -+ -+ /* RFC 2396, Chapter 5.2 */ -+ /* TODO: consider adding all cases described in RFC 2396 */ -+ -+ if (url == NULL) -+ return NULL; -+ -+ if (os_strncmp(url, "http://", 7) == 0) -+ return url; /* absolute link */ -+ -+ if (os_strncmp(base, "http://", 7) != 0) -+ return url; /* unable to handle base URL */ -+ -+ len = os_strlen(url) + 1 + os_strlen(base) + 1; -+ n = os_malloc(len); -+ if (n == NULL) -+ return url; /* failed */ -+ -+ if (url[0] == '/') { -+ pos = os_strchr(base + 7, '/'); -+ if (pos == NULL) { -+ os_snprintf(n, len, "%s%s", base, url); -+ } else { -+ os_memcpy(n, base, pos - base); -+ os_memcpy(n + (pos - base), url, os_strlen(url) + 1); -+ } -+ } else { -+ pos = os_strrchr(base + 7, '/'); -+ if (pos == NULL) { -+ os_snprintf(n, len, "%s/%s", base, url); -+ } else { -+ os_memcpy(n, base, pos - base + 1); -+ os_memcpy(n + (pos - base) + 1, url, os_strlen(url) + -+ 1); -+ } -+ } -+ -+ os_free(url); -+ -+ return n; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.h -new file mode 100644 -index 0000000000000..924d6ab4a2a46 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_client.h -@@ -0,0 +1,46 @@ -+/* -+ * http_client - HTTP client -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef HTTP_CLIENT_H -+#define HTTP_CLIENT_H -+ -+struct http_client; -+ -+enum http_client_event { -+ HTTP_CLIENT_FAILED, -+ HTTP_CLIENT_TIMEOUT, -+ HTTP_CLIENT_OK, -+ HTTP_CLIENT_INVALID_REPLY, -+}; -+ -+char * http_client_url_parse(const char *url, struct sockaddr_in *dst, -+ char **path); -+struct http_client * http_client_addr(struct sockaddr_in *dst, -+ struct wpabuf *req, size_t max_response, -+ void (*cb)(void *ctx, -+ struct http_client *c, -+ enum http_client_event event), -+ void *cb_ctx); -+struct http_client * http_client_url(const char *url, -+ struct wpabuf *req, size_t max_response, -+ void (*cb)(void *ctx, -+ struct http_client *c, -+ enum http_client_event event), -+ void *cb_ctx); -+void http_client_free(struct http_client *c); -+struct wpabuf * http_client_get_body(struct http_client *c); -+char * http_client_get_hdr_line(struct http_client *c, const char *tag); -+char * http_link_update(char *url, const char *base); -+ -+#endif /* HTTP_CLIENT_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.c -new file mode 100644 -index 0000000000000..356f599abe059 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.c -@@ -0,0 +1,312 @@ -+/* -+ * http_server - HTTP server -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include -+ -+#include "common.h" -+#include "eloop.h" -+#include "httpread.h" -+#include "http_server.h" -+ -+#define HTTP_SERVER_TIMEOUT 30 -+#define HTTP_SERVER_MAX_REQ_LEN 8000 -+#define HTTP_SERVER_MAX_CONNECTIONS 10 -+ -+struct http_request { -+ struct http_request *next; -+ struct http_server *srv; -+ int fd; -+ struct sockaddr_in cli; -+ struct httpread *hread; -+}; -+ -+struct http_server { -+ void (*cb)(void *ctx, struct http_request *req); -+ void *cb_ctx; -+ -+ int fd; -+ int port; -+ -+ struct http_request *requests; -+ unsigned int request_count; -+}; -+ -+ -+static void http_request_cb(struct httpread *handle, void *cookie, -+ enum httpread_event en) -+{ -+ struct http_request *req = cookie; -+ struct http_server *srv = req->srv; -+ -+ if (en == HTTPREAD_EVENT_FILE_READY) { -+ wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received", -+ inet_ntoa(req->cli.sin_addr), -+ ntohs(req->cli.sin_port)); -+ srv->cb(srv->cb_ctx, req); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received " -+ "completely", inet_ntoa(req->cli.sin_addr), -+ ntohs(req->cli.sin_port)); -+ http_request_deinit(req); -+} -+ -+ -+static struct http_request * http_request_init(struct http_server *srv, int fd, -+ struct sockaddr_in *cli) -+{ -+ struct http_request *req; -+ -+ if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) { -+ wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests"); -+ return NULL; -+ } -+ -+ req = os_zalloc(sizeof(*req)); -+ if (req == NULL) -+ return NULL; -+ -+ req->srv = srv; -+ req->fd = fd; -+ req->cli = *cli; -+ -+ req->hread = httpread_create(req->fd, http_request_cb, req, -+ HTTP_SERVER_MAX_REQ_LEN, -+ HTTP_SERVER_TIMEOUT); -+ if (req->hread == NULL) { -+ http_request_deinit(req); -+ return NULL; -+ } -+ -+ return req; -+} -+ -+ -+void http_request_deinit(struct http_request *req) -+{ -+ struct http_request *r, *p; -+ struct http_server *srv; -+ -+ if (req == NULL) -+ return; -+ -+ srv = req->srv; -+ p = NULL; -+ r = srv->requests; -+ while (r) { -+ if (r == req) { -+ if (p) -+ p->next = r->next; -+ else -+ srv->requests = r->next; -+ srv->request_count--; -+ break; -+ } -+ p = r; -+ r = r->next; -+ } -+ -+ httpread_destroy(req->hread); -+ close(req->fd); -+ os_free(req); -+} -+ -+ -+static void http_request_free_all(struct http_request *req) -+{ -+ struct http_request *prev; -+ while (req) { -+ prev = req; -+ req = req->next; -+ http_request_deinit(prev); -+ } -+} -+ -+ -+void http_request_send(struct http_request *req, struct wpabuf *resp) -+{ -+ int res; -+ -+ wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d", -+ (unsigned long) wpabuf_len(resp), -+ inet_ntoa(req->cli.sin_addr), -+ ntohs(req->cli.sin_port)); -+ -+ res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0); -+ if (res < 0) { -+ wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s", -+ strerror(errno)); -+ } else if ((size_t) res < wpabuf_len(resp)) { -+ wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes", -+ res, (unsigned long) wpabuf_len(resp)); -+ /* TODO: add eloop handler for sending rest of the data */ -+ } -+ -+ wpabuf_free(resp); -+} -+ -+ -+void http_request_send_and_deinit(struct http_request *req, -+ struct wpabuf *resp) -+{ -+ http_request_send(req, resp); -+ http_request_deinit(req); -+} -+ -+ -+enum httpread_hdr_type http_request_get_type(struct http_request *req) -+{ -+ return httpread_hdr_type_get(req->hread); -+} -+ -+ -+char * http_request_get_uri(struct http_request *req) -+{ -+ return httpread_uri_get(req->hread); -+} -+ -+ -+char * http_request_get_hdr(struct http_request *req) -+{ -+ return httpread_hdr_get(req->hread); -+} -+ -+ -+char * http_request_get_data(struct http_request *req) -+{ -+ return httpread_data_get(req->hread); -+} -+ -+ -+char * http_request_get_hdr_line(struct http_request *req, const char *tag) -+{ -+ return httpread_hdr_line_get(req->hread, tag); -+} -+ -+ -+struct sockaddr_in * http_request_get_cli_addr(struct http_request *req) -+{ -+ return &req->cli; -+} -+ -+ -+static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx) -+{ -+ struct sockaddr_in addr; -+ socklen_t addr_len = sizeof(addr); -+ struct http_server *srv = eloop_ctx; -+ int conn; -+ struct http_request *req; -+ -+ conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len); -+ if (conn < 0) { -+ wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: " -+ "%s", strerror(errno)); -+ return; -+ } -+ wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d", -+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); -+ -+ req = http_request_init(srv, conn, &addr); -+ if (req == NULL) { -+ close(conn); -+ return; -+ } -+ -+ req->next = srv->requests; -+ srv->requests = req; -+ srv->request_count++; -+} -+ -+ -+struct http_server * http_server_init(struct in_addr *addr, int port, -+ void (*cb)(void *ctx, -+ struct http_request *req), -+ void *cb_ctx) -+{ -+ struct sockaddr_in sin; -+ struct http_server *srv; -+ -+ srv = os_zalloc(sizeof(*srv)); -+ if (srv == NULL) -+ return NULL; -+ srv->cb = cb; -+ srv->cb_ctx = cb_ctx; -+ -+ srv->fd = socket(AF_INET, SOCK_STREAM, 0); -+ if (srv->fd < 0) -+ goto fail; -+ if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) -+ goto fail; -+ if (port < 0) -+ srv->port = 49152; -+ else -+ srv->port = port; -+ -+ os_memset(&sin, 0, sizeof(sin)); -+ sin.sin_family = AF_INET; -+ sin.sin_addr.s_addr = addr->s_addr; -+ -+ for (;;) { -+ sin.sin_port = htons(srv->port); -+ if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0) -+ break; -+ if (errno == EADDRINUSE) { -+ /* search for unused port */ -+ if (++srv->port == 65535 || port >= 0) -+ goto fail; -+ continue; -+ } -+ wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: " -+ "%s", srv->port, strerror(errno)); -+ goto fail; -+ } -+ if (listen(srv->fd, 10 /* max backlog */) < 0) -+ goto fail; -+ if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0) -+ goto fail; -+ if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb, -+ srv, NULL)) -+ goto fail; -+ -+ wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d", -+ inet_ntoa(*addr), srv->port); -+ -+ return srv; -+ -+fail: -+ http_server_deinit(srv); -+ return NULL; -+} -+ -+ -+void http_server_deinit(struct http_server *srv) -+{ -+ if (srv == NULL) -+ return; -+ if (srv->fd >= 0) { -+ eloop_unregister_sock(srv->fd, EVENT_TYPE_READ); -+ close(srv->fd); -+ } -+ http_request_free_all(srv->requests); -+ -+ os_free(srv); -+} -+ -+ -+int http_server_get_port(struct http_server *srv) -+{ -+ return srv->port; -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.h -new file mode 100644 -index 0000000000000..219941c5ab5a5 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/http_server.h -@@ -0,0 +1,39 @@ -+/* -+ * http_server - HTTP server -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef HTTP_SERVER_H -+#define HTTP_SERVER_H -+ -+struct http_server; -+struct http_request; -+ -+void http_request_deinit(struct http_request *req); -+void http_request_send(struct http_request *req, struct wpabuf *resp); -+void http_request_send_and_deinit(struct http_request *req, -+ struct wpabuf *resp); -+enum httpread_hdr_type http_request_get_type(struct http_request *req); -+char * http_request_get_uri(struct http_request *req); -+char * http_request_get_hdr(struct http_request *req); -+char * http_request_get_data(struct http_request *req); -+char * http_request_get_hdr_line(struct http_request *req, const char *tag); -+struct sockaddr_in * http_request_get_cli_addr(struct http_request *req); -+ -+struct http_server * http_server_init(struct in_addr *addr, int port, -+ void (*cb)(void *ctx, -+ struct http_request *req), -+ void *cb_ctx); -+void http_server_deinit(struct http_server *srv); -+int http_server_get_port(struct http_server *srv); -+ -+#endif /* HTTP_SERVER_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.c -new file mode 100644 -index 0000000000000..40422e4651d35 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.c -@@ -0,0 +1,861 @@ -+/* -+ * httpread - Manage reading file(s) from HTTP/TCP socket -+ * Author: Ted Merrill -+ * Copyright 2008 Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ * -+ * The files are buffered via internal callbacks from eloop, then presented to -+ * an application callback routine when completely read into memory. May also -+ * be used if no file is expected but just to get the header, including HTTP -+ * replies (e.g. HTTP/1.1 200 OK etc.). -+ * -+ * This does not attempt to be an optimally efficient implementation, but does -+ * attempt to be of reasonably small size and memory consumption; assuming that -+ * only small files are to be read. A maximum file size is provided by -+ * application and enforced. -+ * -+ * It is assumed that the application does not expect any of the following: -+ * -- transfer encoding other than chunked -+ * -- trailer fields -+ * It is assumed that, even if the other side requested that the connection be -+ * kept open, that we will close it (thus HTTP messages sent by application -+ * should have the connection closed field); this is allowed by HTTP/1.1 and -+ * simplifies things for us. -+ * -+ * Other limitations: -+ * -- HTTP header may not exceed a hard-coded size. -+ * -+ * Notes: -+ * This code would be massively simpler without some of the new features of -+ * HTTP/1.1, especially chunked data. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "eloop.h" -+#include "httpread.h" -+ -+ -+/* Tunable parameters */ -+#define HTTPREAD_READBUF_SIZE 1024 /* read in chunks of this size */ -+#define HTTPREAD_HEADER_MAX_SIZE 4096 /* max allowed for headers */ -+#define HTTPREAD_BODYBUF_DELTA 4096 /* increase allocation by this */ -+ -+#if 0 -+/* httpread_debug -- set this global variable > 0 e.g. from debugger -+ * to enable debugs (larger numbers for more debugs) -+ * Make this a #define of 0 to eliminate the debugging code. -+ */ -+int httpread_debug = 99; -+#else -+#define httpread_debug 0 /* eliminates even the debugging code */ -+#endif -+ -+ -+/* control instance -- actual definition (opaque to application) -+ */ -+struct httpread { -+ /* information from creation */ -+ int sd; /* descriptor of TCP socket to read from */ -+ void (*cb)(struct httpread *handle, void *cookie, -+ enum httpread_event e); /* call on event */ -+ void *cookie; /* pass to callback */ -+ int max_bytes; /* maximum file size else abort it */ -+ int timeout_seconds; /* 0 or total duration timeout period */ -+ -+ /* dynamically used information follows */ -+ int sd_registered; /* nonzero if we need to unregister socket */ -+ int to_registered; /* nonzero if we need to unregister timeout */ -+ -+ int got_hdr; /* nonzero when header is finalized */ -+ char hdr[HTTPREAD_HEADER_MAX_SIZE+1]; /* headers stored here */ -+ int hdr_nbytes; -+ -+ enum httpread_hdr_type hdr_type; -+ int version; /* 1 if we've seen 1.1 */ -+ int reply_code; /* for type REPLY, e.g. 200 for HTTP/1.1 200 OK */ -+ int got_content_length; /* true if we know content length for sure */ -+ int content_length; /* body length, iff got_content_length */ -+ int chunked; /* nonzero for chunked data */ -+ char *uri; -+ -+ int got_body; /* nonzero when body is finalized */ -+ char *body; -+ int body_nbytes; -+ int body_alloc_nbytes; /* amount allocated */ -+ -+ int got_file; /* here when we are done */ -+ -+ /* The following apply if data is chunked: */ -+ int in_chunk_data; /* 0=in/at header, 1=in the data or tail*/ -+ int chunk_start; /* offset in body of chunk hdr or data */ -+ int chunk_size; /* data of chunk (not hdr or ending CRLF)*/ -+ int in_trailer; /* in header fields after data (chunked only)*/ -+ enum trailer_state { -+ trailer_line_begin = 0, -+ trailer_empty_cr, /* empty line + CR */ -+ trailer_nonempty, -+ trailer_nonempty_cr, -+ } trailer_state; -+}; -+ -+ -+/* Check words for equality, where words consist of graphical characters -+ * delimited by whitespace -+ * Returns nonzero if "equal" doing case insensitive comparison. -+ */ -+static int word_eq(char *s1, char *s2) -+{ -+ int c1; -+ int c2; -+ int end1 = 0; -+ int end2 = 0; -+ for (;;) { -+ c1 = *s1++; -+ c2 = *s2++; -+ if (isalpha(c1) && isupper(c1)) -+ c1 = tolower(c1); -+ if (isalpha(c2) && isupper(c2)) -+ c2 = tolower(c2); -+ end1 = !isgraph(c1); -+ end2 = !isgraph(c2); -+ if (end1 || end2 || c1 != c2) -+ break; -+ } -+ return end1 && end2; /* reached end of both words? */ -+} -+ -+ -+/* convert hex to binary -+ * Requires that c have been previously tested true with isxdigit(). -+ */ -+static int hex_value(int c) -+{ -+ if (isdigit(c)) -+ return c - '0'; -+ if (islower(c)) -+ return 10 + c - 'a'; -+ return 10 + c - 'A'; -+} -+ -+ -+static void httpread_timeout_handler(void *eloop_data, void *user_ctx); -+ -+/* httpread_destroy -- if h is non-NULL, clean up -+ * This must eventually be called by the application following -+ * call of the application's callback and may be called -+ * earlier if desired. -+ */ -+void httpread_destroy(struct httpread *h) -+{ -+ if (httpread_debug >= 10) -+ wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h); -+ if (!h) -+ return; -+ -+ if (h->to_registered) -+ eloop_cancel_timeout(httpread_timeout_handler, NULL, h); -+ h->to_registered = 0; -+ if (h->sd_registered) -+ eloop_unregister_sock(h->sd, EVENT_TYPE_READ); -+ h->sd_registered = 0; -+ os_free(h->body); -+ os_free(h->uri); -+ os_memset(h, 0, sizeof(*h)); /* aid debugging */ -+ h->sd = -1; /* aid debugging */ -+ os_free(h); -+} -+ -+ -+/* httpread_timeout_handler -- called on excessive total duration -+ */ -+static void httpread_timeout_handler(void *eloop_data, void *user_ctx) -+{ -+ struct httpread *h = user_ctx; -+ wpa_printf(MSG_DEBUG, "httpread timeout (%p)", h); -+ h->to_registered = 0; /* is self-cancelling */ -+ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_TIMEOUT); -+} -+ -+ -+/* Analyze options only so far as is needed to correctly obtain the file. -+ * The application can look at the raw header to find other options. -+ */ -+static int httpread_hdr_option_analyze( -+ struct httpread *h, -+ char *hbp /* pointer to current line in header buffer */ -+ ) -+{ -+ if (word_eq(hbp, "CONTENT-LENGTH:")) { -+ while (isgraph(*hbp)) -+ hbp++; -+ while (*hbp == ' ' || *hbp == '\t') -+ hbp++; -+ if (!isdigit(*hbp)) -+ return -1; -+ h->content_length = atol(hbp); -+ h->got_content_length = 1; -+ return 0; -+ } -+ if (word_eq(hbp, "TRANSFER_ENCODING:") || -+ word_eq(hbp, "TRANSFER-ENCODING:")) { -+ while (isgraph(*hbp)) -+ hbp++; -+ while (*hbp == ' ' || *hbp == '\t') -+ hbp++; -+ /* There should (?) be no encodings of interest -+ * other than chunked... -+ */ -+ if (word_eq(hbp, "CHUNKED")) { -+ h->chunked = 1; -+ h->in_chunk_data = 0; -+ /* ignore possible ; */ -+ } -+ return 0; -+ } -+ /* skip anything we don't know, which is a lot */ -+ return 0; -+} -+ -+ -+static int httpread_hdr_analyze(struct httpread *h) -+{ -+ char *hbp = h->hdr; /* pointer into h->hdr */ -+ int standard_first_line = 1; -+ -+ /* First line is special */ -+ h->hdr_type = HTTPREAD_HDR_TYPE_UNKNOWN; -+ if (!isgraph(*hbp)) -+ goto bad; -+ if (os_strncmp(hbp, "HTTP/", 5) == 0) { -+ h->hdr_type = HTTPREAD_HDR_TYPE_REPLY; -+ standard_first_line = 0; -+ hbp += 5; -+ if (hbp[0] == '1' && hbp[1] == '.' && -+ isdigit(hbp[2]) && hbp[2] != '0') -+ h->version = 1; -+ while (isgraph(*hbp)) -+ hbp++; -+ while (*hbp == ' ' || *hbp == '\t') -+ hbp++; -+ if (!isdigit(*hbp)) -+ goto bad; -+ h->reply_code = atol(hbp); -+ } else if (word_eq(hbp, "GET")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_GET; -+ else if (word_eq(hbp, "HEAD")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_HEAD; -+ else if (word_eq(hbp, "POST")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_POST; -+ else if (word_eq(hbp, "PUT")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_PUT; -+ else if (word_eq(hbp, "DELETE")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_DELETE; -+ else if (word_eq(hbp, "TRACE")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_TRACE; -+ else if (word_eq(hbp, "CONNECT")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_CONNECT; -+ else if (word_eq(hbp, "NOTIFY")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_NOTIFY; -+ else if (word_eq(hbp, "M-SEARCH")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_M_SEARCH; -+ else if (word_eq(hbp, "M-POST")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_M_POST; -+ else if (word_eq(hbp, "SUBSCRIBE")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_SUBSCRIBE; -+ else if (word_eq(hbp, "UNSUBSCRIBE")) -+ h->hdr_type = HTTPREAD_HDR_TYPE_UNSUBSCRIBE; -+ else { -+ } -+ -+ if (standard_first_line) { -+ char *rawuri; -+ char *uri; -+ /* skip type */ -+ while (isgraph(*hbp)) -+ hbp++; -+ while (*hbp == ' ' || *hbp == '\t') -+ hbp++; -+ /* parse uri. -+ * Find length, allocate memory for translated -+ * copy, then translate by changing % -+ * into represented value. -+ */ -+ rawuri = hbp; -+ while (isgraph(*hbp)) -+ hbp++; -+ h->uri = os_malloc((hbp - rawuri) + 1); -+ if (h->uri == NULL) -+ goto bad; -+ uri = h->uri; -+ while (rawuri < hbp) { -+ int c = *rawuri; -+ if (c == '%' && -+ isxdigit(rawuri[1]) && isxdigit(rawuri[2])) { -+ *uri++ = (hex_value(rawuri[1]) << 4) | -+ hex_value(rawuri[2]); -+ rawuri += 3; -+ } else { -+ *uri++ = c; -+ rawuri++; -+ } -+ } -+ *uri = 0; /* null terminate */ -+ while (isgraph(*hbp)) -+ hbp++; -+ while (*hbp == ' ' || *hbp == '\t') -+ hbp++; -+ /* get version */ -+ if (0 == strncmp(hbp, "HTTP/", 5)) { -+ hbp += 5; -+ if (hbp[0] == '1' && hbp[1] == '.' && -+ isdigit(hbp[2]) && hbp[2] != '0') -+ h->version = 1; -+ } -+ } -+ /* skip rest of line */ -+ while (*hbp) -+ if (*hbp++ == '\n') -+ break; -+ -+ /* Remainder of lines are options, in any order; -+ * or empty line to terminate -+ */ -+ for (;;) { -+ /* Empty line to terminate */ -+ if (hbp[0] == '\n' || -+ (hbp[0] == '\r' && hbp[1] == '\n')) -+ break; -+ if (!isgraph(*hbp)) -+ goto bad; -+ if (httpread_hdr_option_analyze(h, hbp)) -+ goto bad; -+ /* skip line */ -+ while (*hbp) -+ if (*hbp++ == '\n') -+ break; -+ } -+ -+ /* chunked overrides content-length always */ -+ if (h->chunked) -+ h->got_content_length = 0; -+ -+ /* For some types, we should not try to read a body -+ * This is in addition to the application determining -+ * that we should not read a body. -+ */ -+ switch (h->hdr_type) { -+ case HTTPREAD_HDR_TYPE_REPLY: -+ /* Some codes can have a body and some not. -+ * For now, just assume that any other than 200 -+ * do not... -+ */ -+ if (h->reply_code != 200) -+ h->max_bytes = 0; -+ break; -+ case HTTPREAD_HDR_TYPE_GET: -+ case HTTPREAD_HDR_TYPE_HEAD: -+ /* in practice it appears that it is assumed -+ * that GETs have a body length of 0... ? -+ */ -+ if (h->chunked == 0 && h->got_content_length == 0) -+ h->max_bytes = 0; -+ break; -+ case HTTPREAD_HDR_TYPE_POST: -+ case HTTPREAD_HDR_TYPE_PUT: -+ case HTTPREAD_HDR_TYPE_DELETE: -+ case HTTPREAD_HDR_TYPE_TRACE: -+ case HTTPREAD_HDR_TYPE_CONNECT: -+ case HTTPREAD_HDR_TYPE_NOTIFY: -+ case HTTPREAD_HDR_TYPE_M_SEARCH: -+ case HTTPREAD_HDR_TYPE_M_POST: -+ case HTTPREAD_HDR_TYPE_SUBSCRIBE: -+ case HTTPREAD_HDR_TYPE_UNSUBSCRIBE: -+ default: -+ break; -+ } -+ -+ return 0; -+ -+bad: -+ /* Error */ -+ return -1; -+} -+ -+ -+/* httpread_read_handler -- called when socket ready to read -+ * -+ * Note: any extra data we read past end of transmitted file is ignored; -+ * if we were to support keeping connections open for multiple files then -+ * this would have to be addressed. -+ */ -+static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx) -+{ -+ struct httpread *h = sock_ctx; -+ int nread; -+ char *rbp; /* pointer into read buffer */ -+ char *hbp; /* pointer into header buffer */ -+ char *bbp; /* pointer into body buffer */ -+ char readbuf[HTTPREAD_READBUF_SIZE]; /* temp use to read into */ -+ -+ if (httpread_debug >= 20) -+ wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h); -+ -+ /* read some at a time, then search for the interal -+ * boundaries between header and data and etc. -+ */ -+ nread = read(h->sd, readbuf, sizeof(readbuf)); -+ if (nread < 0) -+ goto bad; -+ if (nread == 0) { -+ /* end of transmission... this may be normal -+ * or may be an error... in some cases we can't -+ * tell which so we must assume it is normal then. -+ */ -+ if (!h->got_hdr) { -+ /* Must at least have completed header */ -+ wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h); -+ goto bad; -+ } -+ if (h->chunked || h->got_content_length) { -+ /* Premature EOF; e.g. dropped connection */ -+ wpa_printf(MSG_DEBUG, -+ "httpread premature eof(%p) %d/%d", -+ h, h->body_nbytes, -+ h->content_length); -+ goto bad; -+ } -+ /* No explicit length, hopefully we have all the data -+ * although dropped connections can cause false -+ * end -+ */ -+ if (httpread_debug >= 10) -+ wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h); -+ h->got_body = 1; -+ goto got_file; -+ } -+ rbp = readbuf; -+ -+ /* Header consists of text lines (terminated by both CR and LF) -+ * and an empty line (CR LF only). -+ */ -+ if (!h->got_hdr) { -+ hbp = h->hdr + h->hdr_nbytes; -+ /* add to headers until: -+ * -- we run out of data in read buffer -+ * -- or, we run out of header buffer room -+ * -- or, we get double CRLF in headers -+ */ -+ for (;;) { -+ if (nread == 0) -+ goto get_more; -+ if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) { -+ goto bad; -+ } -+ *hbp++ = *rbp++; -+ nread--; -+ h->hdr_nbytes++; -+ if (h->hdr_nbytes >= 4 && -+ hbp[-1] == '\n' && -+ hbp[-2] == '\r' && -+ hbp[-3] == '\n' && -+ hbp[-4] == '\r' ) { -+ h->got_hdr = 1; -+ *hbp = 0; /* null terminate */ -+ break; -+ } -+ } -+ /* here we've just finished reading the header */ -+ if (httpread_hdr_analyze(h)) { -+ wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h); -+ goto bad; -+ } -+ if (h->max_bytes == 0) { -+ if (httpread_debug >= 10) -+ wpa_printf(MSG_DEBUG, -+ "httpread no body hdr end(%p)", h); -+ goto got_file; -+ } -+ if (h->got_content_length && h->content_length == 0) { -+ if (httpread_debug >= 10) -+ wpa_printf(MSG_DEBUG, -+ "httpread zero content length(%p)", -+ h); -+ goto got_file; -+ } -+ } -+ -+ /* Certain types of requests never have data and so -+ * must be specially recognized. -+ */ -+ if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) || -+ !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) || -+ !os_strncasecmp(h->hdr, "HEAD", 4) || -+ !os_strncasecmp(h->hdr, "GET", 3)) { -+ if (!h->got_body) { -+ if (httpread_debug >= 10) -+ wpa_printf(MSG_DEBUG, -+ "httpread NO BODY for sp. type"); -+ } -+ h->got_body = 1; -+ goto got_file; -+ } -+ -+ /* Data can be just plain binary data, or if "chunked" -+ * consists of chunks each with a header, ending with -+ * an ending header. -+ */ -+ if (nread == 0) -+ goto get_more; -+ if (!h->got_body) { -+ /* Here to get (more of) body */ -+ /* ensure we have enough room for worst case for body -+ * plus a null termination character -+ */ -+ if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) { -+ char *new_body; -+ int new_alloc_nbytes; -+ -+ if (h->body_nbytes >= h->max_bytes) -+ goto bad; -+ new_alloc_nbytes = h->body_alloc_nbytes + -+ HTTPREAD_BODYBUF_DELTA; -+ /* For content-length case, the first time -+ * through we allocate the whole amount -+ * we need. -+ */ -+ if (h->got_content_length && -+ new_alloc_nbytes < (h->content_length + 1)) -+ new_alloc_nbytes = h->content_length + 1; -+ if ((new_body = os_realloc(h->body, new_alloc_nbytes)) -+ == NULL) -+ goto bad; -+ -+ h->body = new_body; -+ h->body_alloc_nbytes = new_alloc_nbytes; -+ } -+ /* add bytes */ -+ bbp = h->body + h->body_nbytes; -+ for (;;) { -+ int ncopy; -+ /* See if we need to stop */ -+ if (h->chunked && h->in_chunk_data == 0) { -+ /* in chunk header */ -+ char *cbp = h->body + h->chunk_start; -+ if (bbp-cbp >= 2 && bbp[-2] == '\r' && -+ bbp[-1] == '\n') { -+ /* end of chunk hdr line */ -+ /* hdr line consists solely -+ * of a hex numeral and CFLF -+ */ -+ if (!isxdigit(*cbp)) -+ goto bad; -+ h->chunk_size = strtoul(cbp, NULL, 16); -+ /* throw away chunk header -+ * so we have only real data -+ */ -+ h->body_nbytes = h->chunk_start; -+ bbp = cbp; -+ if (h->chunk_size == 0) { -+ /* end of chunking */ -+ /* trailer follows */ -+ h->in_trailer = 1; -+ if (httpread_debug >= 20) -+ wpa_printf( -+ MSG_DEBUG, -+ "httpread end chunks(%p)", h); -+ break; -+ } -+ h->in_chunk_data = 1; -+ /* leave chunk_start alone */ -+ } -+ } else if (h->chunked) { -+ /* in chunk data */ -+ if ((h->body_nbytes - h->chunk_start) == -+ (h->chunk_size + 2)) { -+ /* end of chunk reached, -+ * new chunk starts -+ */ -+ /* check chunk ended w/ CRLF -+ * which we'll throw away -+ */ -+ if (bbp[-1] == '\n' && -+ bbp[-2] == '\r') { -+ } else -+ goto bad; -+ h->body_nbytes -= 2; -+ bbp -= 2; -+ h->chunk_start = h->body_nbytes; -+ h->in_chunk_data = 0; -+ h->chunk_size = 0; /* just in case */ -+ } -+ } else if (h->got_content_length && -+ h->body_nbytes >= h->content_length) { -+ h->got_body = 1; -+ if (httpread_debug >= 10) -+ wpa_printf( -+ MSG_DEBUG, -+ "httpread got content(%p)", h); -+ goto got_file; -+ } -+ if (nread <= 0) -+ break; -+ /* Now transfer. Optimize using memcpy where we can. */ -+ if (h->chunked && h->in_chunk_data) { -+ /* copy up to remainder of chunk data -+ * plus the required CR+LF at end -+ */ -+ ncopy = (h->chunk_start + h->chunk_size + 2) - -+ h->body_nbytes; -+ } else if (h->chunked) { -+ /*in chunk header -- don't optimize */ -+ *bbp++ = *rbp++; -+ nread--; -+ h->body_nbytes++; -+ continue; -+ } else if (h->got_content_length) { -+ ncopy = h->content_length - h->body_nbytes; -+ } else { -+ ncopy = nread; -+ } -+ /* Note: should never be 0 */ -+ if (ncopy > nread) -+ ncopy = nread; -+ os_memcpy(bbp, rbp, ncopy); -+ bbp += ncopy; -+ h->body_nbytes += ncopy; -+ rbp += ncopy; -+ nread -= ncopy; -+ } /* body copy loop */ -+ } /* !got_body */ -+ if (h->chunked && h->in_trailer) { -+ /* If "chunked" then there is always a trailer, -+ * consisting of zero or more non-empty lines -+ * ending with CR LF and then an empty line w/ CR LF. -+ * We do NOT support trailers except to skip them -- -+ * this is supported (generally) by the http spec. -+ */ -+ bbp = h->body + h->body_nbytes; -+ for (;;) { -+ int c; -+ if (nread <= 0) -+ break; -+ c = *rbp++; -+ nread--; -+ switch (h->trailer_state) { -+ case trailer_line_begin: -+ if (c == '\r') -+ h->trailer_state = trailer_empty_cr; -+ else -+ h->trailer_state = trailer_nonempty; -+ break; -+ case trailer_empty_cr: -+ /* end empty line */ -+ if (c == '\n') { -+ h->trailer_state = trailer_line_begin; -+ h->in_trailer = 0; -+ if (httpread_debug >= 10) -+ wpa_printf( -+ MSG_DEBUG, -+ "httpread got content(%p)", h); -+ h->got_body = 1; -+ goto got_file; -+ } -+ h->trailer_state = trailer_nonempty; -+ break; -+ case trailer_nonempty: -+ if (c == '\r') -+ h->trailer_state = trailer_nonempty_cr; -+ break; -+ case trailer_nonempty_cr: -+ if (c == '\n') -+ h->trailer_state = trailer_line_begin; -+ else -+ h->trailer_state = trailer_nonempty; -+ break; -+ } -+ } -+ } -+ goto get_more; -+ -+bad: -+ /* Error */ -+ wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h); -+ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR); -+ return; -+ -+get_more: -+ return; -+ -+got_file: -+ if (httpread_debug >= 10) -+ wpa_printf(MSG_DEBUG, -+ "httpread got file %d bytes type %d", -+ h->body_nbytes, h->hdr_type); -+ /* Null terminate for convenience of some applications */ -+ if (h->body) -+ h->body[h->body_nbytes] = 0; /* null terminate */ -+ h->got_file = 1; -+ /* Assume that we do NOT support keeping connection alive, -+ * and just in case somehow we don't get destroyed right away, -+ * unregister now. -+ */ -+ if (h->sd_registered) -+ eloop_unregister_sock(h->sd, EVENT_TYPE_READ); -+ h->sd_registered = 0; -+ /* The application can destroy us whenever they feel like... -+ * cancel timeout. -+ */ -+ if (h->to_registered) -+ eloop_cancel_timeout(httpread_timeout_handler, NULL, h); -+ h->to_registered = 0; -+ (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY); -+} -+ -+ -+/* httpread_create -- start a new reading session making use of eloop. -+ * The new instance will use the socket descriptor for reading (until -+ * it gets a file and not after) but will not close the socket, even -+ * when the instance is destroyed (the application must do that). -+ * Return NULL on error. -+ * -+ * Provided that httpread_create successfully returns a handle, -+ * the callback fnc is called to handle httpread_event events. -+ * The caller should do destroy on any errors or unknown events. -+ * -+ * Pass max_bytes == 0 to not read body at all (required for e.g. -+ * reply to HEAD request). -+ */ -+struct httpread * httpread_create( -+ int sd, /* descriptor of TCP socket to read from */ -+ void (*cb)(struct httpread *handle, void *cookie, -+ enum httpread_event e), /* call on event */ -+ void *cookie, /* pass to callback */ -+ int max_bytes, /* maximum body size else abort it */ -+ int timeout_seconds /* 0; or total duration timeout period */ -+ ) -+{ -+ struct httpread *h = NULL; -+ -+ h = os_zalloc(sizeof(*h)); -+ if (h == NULL) -+ goto fail; -+ h->sd = sd; -+ h->cb = cb; -+ h->cookie = cookie; -+ h->max_bytes = max_bytes; -+ h->timeout_seconds = timeout_seconds; -+ -+ if (timeout_seconds > 0) { -+ if (eloop_register_timeout(timeout_seconds, 0, -+ httpread_timeout_handler, -+ NULL, h)) { -+ /* No way to recover (from malloc failure) */ -+ goto fail; -+ } -+ h->to_registered = 1; -+ } -+ if (eloop_register_sock(sd, EVENT_TYPE_READ, httpread_read_handler, -+ NULL, h)) { -+ /* No way to recover (from malloc failure) */ -+ goto fail; -+ } -+ h->sd_registered = 1; -+ return h; -+ -+fail: -+ -+ /* Error */ -+ httpread_destroy(h); -+ return NULL; -+} -+ -+ -+/* httpread_hdr_type_get -- When file is ready, returns header type. */ -+enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h) -+{ -+ return h->hdr_type; -+} -+ -+ -+/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI -+ * or possibly NULL (which would be an error). -+ */ -+char * httpread_uri_get(struct httpread *h) -+{ -+ return h->uri; -+} -+ -+ -+/* httpread_reply_code_get -- When reply is ready, returns reply code */ -+int httpread_reply_code_get(struct httpread *h) -+{ -+ return h->reply_code; -+} -+ -+ -+/* httpread_length_get -- When file is ready, returns file length. */ -+int httpread_length_get(struct httpread *h) -+{ -+ return h->body_nbytes; -+} -+ -+ -+/* httpread_data_get -- When file is ready, returns file content -+ * with null byte appened. -+ * Might return NULL in some error condition. -+ */ -+void * httpread_data_get(struct httpread *h) -+{ -+ return h->body ? h->body : ""; -+} -+ -+ -+/* httpread_hdr_get -- When file is ready, returns header content -+ * with null byte appended. -+ * Might return NULL in some error condition. -+ */ -+char * httpread_hdr_get(struct httpread *h) -+{ -+ return h->hdr; -+} -+ -+ -+/* httpread_hdr_line_get -- When file is ready, returns pointer -+ * to line within header content matching the given tag -+ * (after the tag itself and any spaces/tabs). -+ * -+ * The tag should end with a colon for reliable matching. -+ * -+ * If not found, returns NULL; -+ */ -+char * httpread_hdr_line_get(struct httpread *h, const char *tag) -+{ -+ int tag_len = os_strlen(tag); -+ char *hdr = h->hdr; -+ hdr = os_strchr(hdr, '\n'); -+ if (hdr == NULL) -+ return NULL; -+ hdr++; -+ for (;;) { -+ if (!os_strncasecmp(hdr, tag, tag_len)) { -+ hdr += tag_len; -+ while (*hdr == ' ' || *hdr == '\t') -+ hdr++; -+ return hdr; -+ } -+ hdr = os_strchr(hdr, '\n'); -+ if (hdr == NULL) -+ return NULL; -+ hdr++; -+ } -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.h b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.h -new file mode 100644 -index 0000000000000..51aa214946659 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/httpread.h -@@ -0,0 +1,123 @@ -+/* -+ * httpread - Manage reading file(s) from HTTP/TCP socket -+ * Author: Ted Merrill -+ * Copyright 2008 Atheros Communications -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#ifndef HTTPREAD_H -+#define HTTPREAD_H -+ -+/* event types (passed to callback) */ -+enum httpread_event { -+ HTTPREAD_EVENT_FILE_READY = 1, /* including reply ready */ -+ HTTPREAD_EVENT_TIMEOUT = 2, -+ HTTPREAD_EVENT_ERROR = 3 /* misc. error, esp malloc error */ -+}; -+ -+ -+/* header type detected -+ * available to callback via call to httpread_reply_code_get() -+ */ -+enum httpread_hdr_type { -+ HTTPREAD_HDR_TYPE_UNKNOWN = 0, /* none of the following */ -+ HTTPREAD_HDR_TYPE_REPLY = 1, /* hdr begins w/ HTTP/ */ -+ HTTPREAD_HDR_TYPE_GET = 2, /* hdr begins with GET */ -+ HTTPREAD_HDR_TYPE_HEAD = 3, /* hdr begins with HEAD */ -+ HTTPREAD_HDR_TYPE_POST = 4, /* hdr begins with POST */ -+ HTTPREAD_HDR_TYPE_PUT = 5, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_DELETE = 6, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_TRACE = 7, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_CONNECT = 8, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_NOTIFY = 9, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_M_SEARCH = 10, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_M_POST = 11, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_SUBSCRIBE = 12, /* hdr begins with ... */ -+ HTTPREAD_HDR_TYPE_UNSUBSCRIBE = 13, /* hdr begins with ... */ -+ -+ HTTPREAD_N_HDR_TYPES /* keep last */ -+}; -+ -+ -+/* control instance -- opaque struct declaration -+ */ -+struct httpread; -+ -+ -+/* httpread_destroy -- if h is non-NULL, clean up -+ * This must eventually be called by the application following -+ * call of the application's callback and may be called -+ * earlier if desired. -+ */ -+void httpread_destroy(struct httpread *h); -+ -+/* httpread_create -- start a new reading session making use of eloop. -+ * The new instance will use the socket descriptor for reading (until -+ * it gets a file and not after) but will not close the socket, even -+ * when the instance is destroyed (the application must do that). -+ * Return NULL on error. -+ * -+ * Provided that httpread_create successfully returns a handle, -+ * the callback fnc is called to handle httpread_event events. -+ * The caller should do destroy on any errors or unknown events. -+ * -+ * Pass max_bytes == 0 to not read body at all (required for e.g. -+ * reply to HEAD request). -+ */ -+struct httpread * httpread_create( -+ int sd, /* descriptor of TCP socket to read from */ -+ void (*cb)(struct httpread *handle, void *cookie, -+ enum httpread_event e), /* call on event */ -+ void *cookie, /* pass to callback */ -+ int max_bytes, /* maximum file size else abort it */ -+ int timeout_seconds /* 0; or total duration timeout period */ -+ ); -+ -+/* httpread_hdr_type_get -- When file is ready, returns header type. -+ */ -+enum httpread_hdr_type httpread_hdr_type_get(struct httpread *h); -+ -+ -+/* httpread_uri_get -- When file is ready, uri_get returns (translated) URI -+ * or possibly NULL (which would be an error). -+ */ -+char *httpread_uri_get(struct httpread *h); -+ -+/* httpread_reply_code_get -- When reply is ready, returns reply code */ -+int httpread_reply_code_get(struct httpread *h); -+ -+ -+/* httpread_length_get -- When file is ready, returns file length. */ -+int httpread_length_get(struct httpread *h); -+ -+/* httpread_data_get -- When file is ready, returns file content -+ * with null byte appened. -+ * Might return NULL in some error condition. -+ */ -+void * httpread_data_get(struct httpread *h); -+ -+/* httpread_hdr_get -- When file is ready, returns header content -+ * with null byte appended. -+ * Might return NULL in some error condition. -+ */ -+char * httpread_hdr_get(struct httpread *h); -+ -+/* httpread_hdr_line_get -- When file is ready, returns pointer -+ * to line within header content matching the given tag -+ * (after the tag itself and any spaces/tabs). -+ * -+ * The tag should end with a colon for reliable matching. -+ * -+ * If not found, returns NULL; -+ */ -+char * httpread_hdr_line_get(struct httpread *h, const char *tag); -+ -+#endif /* HTTPREAD_H */ -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/ndef.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/ndef.c -new file mode 100644 -index 0000000000000..9baec7f4b27c2 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/ndef.c -@@ -0,0 +1,175 @@ -+/* -+ * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup -+ * Reference is "NFCForum-TS-NDEF_1.0 2006-07-24". -+ * Copyright (c) 2009, Masashi Honma -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Alternatively, this software may be distributed under the terms of BSD -+ * license. -+ * -+ * See README and COPYING for more details. -+ */ -+ -+#include "includes.h" -+#include "common.h" -+#include "wps/wps.h" -+#include "wps/wps_i.h" -+ -+#define FLAG_MESSAGE_BEGIN (1 << 7) -+#define FLAG_MESSAGE_END (1 << 6) -+#define FLAG_CHUNK (1 << 5) -+#define FLAG_SHORT_RECORD (1 << 4) -+#define FLAG_ID_LENGTH_PRESENT (1 << 3) -+#define FLAG_TNF_RFC2046 (0x02) -+ -+struct ndef_record { -+ u8 *type; -+ u8 *id; -+ u8 *payload; -+ u8 type_length; -+ u8 id_length; -+ u32 payload_length; -+ u32 total_length; -+}; -+ -+static char wifi_handover_type[] = "application/vnd.wfa.wsc"; -+ -+static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record) -+{ -+ u8 *pos = data + 1; -+ -+ if (size < 2) -+ return -1; -+ record->type_length = *pos++; -+ if (data[0] & FLAG_SHORT_RECORD) { -+ if (size < 3) -+ return -1; -+ record->payload_length = *pos++; -+ } else { -+ if (size < 6) -+ return -1; -+ record->payload_length = ntohl(*(u32 *)pos); -+ pos += sizeof(u32); -+ } -+ -+ if (data[0] & FLAG_ID_LENGTH_PRESENT) { -+ if ((int) size < pos - data + 1) -+ return -1; -+ record->id_length = *pos++; -+ } else -+ record->id_length = 0; -+ -+ record->type = record->type_length == 0 ? NULL : pos; -+ pos += record->type_length; -+ -+ record->id = record->id_length == 0 ? NULL : pos; -+ pos += record->id_length; -+ -+ record->payload = record->payload_length == 0 ? NULL : pos; -+ pos += record->payload_length; -+ -+ record->total_length = pos - data; -+ if (record->total_length > size) -+ return -1; -+ return 0; -+} -+ -+ -+static struct wpabuf * ndef_parse_records(struct wpabuf *buf, -+ int (*filter)(struct ndef_record *)) -+{ -+ struct ndef_record record; -+ int len = wpabuf_len(buf); -+ u8 *data = wpabuf_mhead(buf); -+ -+ while (len > 0) { -+ if (ndef_parse_record(data, len, &record) < 0) { -+ wpa_printf(MSG_ERROR, "NDEF : Failed to parse"); -+ return NULL; -+ } -+ if (filter == NULL || filter(&record)) -+ return wpabuf_alloc_copy(record.payload, -+ record.payload_length); -+ data += record.total_length; -+ len -= record.total_length; -+ } -+ wpa_printf(MSG_ERROR, "NDEF : Record not found"); -+ return NULL; -+} -+ -+ -+static struct wpabuf * ndef_build_record(u8 flags, void *type, -+ u8 type_length, void *id, -+ u8 id_length, void *payload, -+ u32 payload_length) -+{ -+ struct wpabuf *record; -+ size_t total_len; -+ int short_record; -+ u8 local_flag; -+ -+ short_record = payload_length < 256 ? 1 : 0; -+ -+ total_len = 2; /* flag + type length */ -+ /* payload length */ -+ total_len += short_record ? sizeof(u8) : sizeof(u32); -+ if (id_length > 0) -+ total_len += 1; -+ total_len += type_length + id_length + payload_length; -+ record = wpabuf_alloc(total_len); -+ if (record == NULL) { -+ wpa_printf(MSG_ERROR, "NDEF : Failed to allocate " -+ "record for build"); -+ return NULL; -+ } -+ -+ local_flag = flags; -+ if (id_length > 0) -+ local_flag |= FLAG_ID_LENGTH_PRESENT; -+ if (short_record) -+ local_flag |= FLAG_SHORT_RECORD; -+ wpabuf_put_u8(record, local_flag); -+ -+ wpabuf_put_u8(record, type_length); -+ -+ if (short_record) -+ wpabuf_put_u8(record, payload_length); -+ else -+ wpabuf_put_be32(record, payload_length); -+ -+ if (id_length > 0) -+ wpabuf_put_u8(record, id_length); -+ wpabuf_put_data(record, type, type_length); -+ wpabuf_put_data(record, id, id_length); -+ wpabuf_put_data(record, payload, payload_length); -+ return record; -+} -+ -+ -+static int wifi_filter(struct ndef_record *record) -+{ -+ if (record->type_length != os_strlen(wifi_handover_type)) -+ return 0; -+ if (os_memcmp(record->type, wifi_handover_type, -+ os_strlen(wifi_handover_type)) != 0) -+ return 0; -+ return 1; -+} -+ -+ -+struct wpabuf * ndef_parse_wifi(struct wpabuf *buf) -+{ -+ return ndef_parse_records(buf, wifi_filter); -+} -+ -+ -+struct wpabuf * ndef_build_wifi(struct wpabuf *buf) -+{ -+ return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END | -+ FLAG_TNF_RFC2046, wifi_handover_type, -+ os_strlen(wifi_handover_type), NULL, 0, -+ wpabuf_mhead(buf), wpabuf_len(buf)); -+} -diff --git a/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/upnp_xml.c b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/upnp_xml.c -new file mode 100644 -index 0000000000000..b1b1e2b165dd0 ---- /dev/null -+++ b/drivers/net/wireless/rtl8188eu/hostapd-0.8/src/wps/upnp_xml.c -@@ -0,0 +1,252 @@ -+/* -+ * UPnP XML helper routines -+ * Copyright (c) 2000-2003 Intel Corporation -+ * Copyright (c) 2006-2007 Sony Corporation -+ * Copyright (c) 2008-2009 Atheros Communications -+ * Copyright (c) 2009, Jouni Malinen -+ * -+ * See wps_upnp.c for more details on licensing and code history. -+ */ -+ -+#include "includes.h" -+ -+#include "common.h" -+#include "base64.h" -+#include "http.h" -+#include "upnp_xml.h" -+ -+ -+/* -+ * XML parsing and formatting -+ * -+ * XML is a markup language based on unicode; usually (and in our case, -+ * always!) based on utf-8. utf-8 uses a variable number of bytes per -+ * character. utf-8 has the advantage that all non-ASCII unicode characters are -+ * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII -+ * characters are single ascii bytes, thus we can use typical text processing. -+ * -+ * (One other interesting thing about utf-8 is that it is possible to look at -+ * any random byte and determine if it is the first byte of a character as -+ * versus a continuation byte). -+ * -+ * The base syntax of XML uses a few ASCII punctionation characters; any -+ * characters that would appear in the payload data are rewritten using -+ * sequences, e.g., & for ampersand(&) and < for left angle bracket (<). -+ * Five such escapes total (more can be defined but that does not apply to our -+ * case). Thus we can safely parse for angle brackets etc. -+ * -+ * XML describes tree structures of tagged data, with each element beginning -+ * with an opening tag with -+ * matching label. (There is also a self-closing tag